From 2e872af6c2fef25c87c4752042c3018bdb43e8fc Mon Sep 17 00:00:00 2001 From: Paul Date: Wed, 3 Jan 2001 15:55:10 +0000 Subject: [PATCH] --- source/memcard/md5.cpp | 315 ++++++++ source/memcard/md5.h | 49 ++ source/memcard/md5global.h | 37 + source/memcard/memcard.cpp | 1401 +++++++++++++++++++++++++++++++++++ source/memcard/memcard.h | 266 +++++++ source/memcard/saveload.cpp | 537 ++++++++++++++ source/memcard/saveload.h | 131 ++++ 7 files changed, 2736 insertions(+) create mode 100644 source/memcard/md5.cpp create mode 100644 source/memcard/md5.h create mode 100644 source/memcard/md5global.h create mode 100644 source/memcard/memcard.cpp create mode 100644 source/memcard/memcard.h create mode 100644 source/memcard/saveload.cpp create mode 100644 source/memcard/saveload.h diff --git a/source/memcard/md5.cpp b/source/memcard/md5.cpp new file mode 100644 index 000000000..f95f8cb24 --- /dev/null +++ b/source/memcard/md5.cpp @@ -0,0 +1,315 @@ +// PKG - PROTO_LIST stuff removed and function headers re-written inna +// C++ style + + + +/* MD5C.C - RSA Data Security, Inc., MD5 message-digest algorithm + */ + +/* Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All +rights reserved. + +License to copy and use this software is granted provided that it +is identified as the "RSA Data Security, Inc. MD5 Message-Digest +Algorithm" in all material mentioning or referencing this software +or this function. + +License is also granted to make and use derivative works provided +that such works are identified as "derived from the RSA Data +Security, Inc. MD5 Message-Digest Algorithm" in all material +mentioning or referencing the derived work. + +RSA Data Security, Inc. makes no representations concerning either +the merchantability of this software or the suitability of this +software for any particular purpose. It is provided "as is" +without express or implied warranty of any kind. + +These notices must be retained in any copies of any part of this +documentation and/or software. + */ + +#include "md5.h" + +/* Constants for MD5Transform routine. + */ +#define S11 7 +#define S12 12 +#define S13 17 +#define S14 22 +#define S21 5 +#define S22 9 +#define S23 14 +#define S24 20 +#define S31 4 +#define S32 11 +#define S33 16 +#define S34 23 +#define S41 6 +#define S42 10 +#define S43 15 +#define S44 21 + +static void MD5Transform (UINT4 [4], unsigned char [64]); +static void Encode (unsigned char *, UINT4 *, unsigned int); +static void Decode (UINT4 *, unsigned char *, unsigned int); +static void MD5_memcpy (POINTER, POINTER, unsigned int); +static void MD5_memset (POINTER, int, unsigned int); + +static unsigned char PADDING[64] = { + 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; + +/* F, G, H and I are basic MD5 functions. + */ +#define F(x, y, z) (((x) & (y)) | ((~x) & (z))) +#define G(x, y, z) (((x) & (z)) | ((y) & (~z))) +#define H(x, y, z) ((x) ^ (y) ^ (z)) +#define I(x, y, z) ((y) ^ ((x) | (~z))) + +/* ROTATE_LEFT rotates x left n bits. + */ +#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n)))) + +/* FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4. +Rotation is separate from addition to prevent recomputation. + */ +#define FF(a, b, c, d, x, s, ac) { \ + (a) += F ((b), (c), (d)) + (x) + (UINT4)(ac); \ + (a) = ROTATE_LEFT ((a), (s)); \ + (a) += (b); \ + } +#define GG(a, b, c, d, x, s, ac) { \ + (a) += G ((b), (c), (d)) + (x) + (UINT4)(ac); \ + (a) = ROTATE_LEFT ((a), (s)); \ + (a) += (b); \ + } +#define HH(a, b, c, d, x, s, ac) { \ + (a) += H ((b), (c), (d)) + (x) + (UINT4)(ac); \ + (a) = ROTATE_LEFT ((a), (s)); \ + (a) += (b); \ + } +#define II(a, b, c, d, x, s, ac) { \ + (a) += I ((b), (c), (d)) + (x) + (UINT4)(ac); \ + (a) = ROTATE_LEFT ((a), (s)); \ + (a) += (b); \ + } + +/* MD5 initialization. Begins an MD5 operation, writing a new context. + */ +void MD5Init (MD5_CTX *context) +{ + context->count[0] = context->count[1] = 0; + /* Load magic initialization constants. +*/ + context->state[0] = 0x67452301; + context->state[1] = 0xefcdab89; + context->state[2] = 0x98badcfe; + context->state[3] = 0x10325476; +} + +/* MD5 block update operation. Continues an MD5 message-digest + operation, processing another message block, and updating the + context. + */ +void MD5Update (MD5_CTX *context, unsigned char *input, unsigned int inputLen) +{ + unsigned int i, index, partLen; + + /* Compute number of bytes mod 64 */ + index = (unsigned int)((context->count[0] >> 3) & 0x3F); + + /* Update number of bits */ + if ((context->count[0] += ((UINT4)inputLen << 3)) + < ((UINT4)inputLen << 3)) + context->count[1]++; + context->count[1] += ((UINT4)inputLen >> 29); + + partLen = 64 - index; + + /* Transform as many times as possible. +*/ + if (inputLen >= partLen) { + MD5_memcpy + ((POINTER)&context->buffer[index], (POINTER)input, partLen); + MD5Transform (context->state, context->buffer); + + for (i = partLen; i + 63 < inputLen; i += 64) + MD5Transform (context->state, &input[i]); + + index = 0; + } + else + i = 0; + + /* Buffer remaining input */ + MD5_memcpy + ((POINTER)&context->buffer[index], (POINTER)&input[i], + inputLen-i); +} + +/* MD5 finalization. Ends an MD5 message-digest operation, writing the + the message digest and zeroizing the context. + */ +void MD5Final (unsigned char digest[16], MD5_CTX *context) +{ + unsigned char bits[8]; + unsigned int index, padLen; + + /* Save number of bits */ + Encode (bits, context->count, 8); + + /* Pad out to 56 mod 64. +*/ + index = (unsigned int)((context->count[0] >> 3) & 0x3f); + padLen = (index < 56) ? (56 - index) : (120 - index); + MD5Update (context, PADDING, padLen); + + /* Append length (before padding) */ + MD5Update (context, bits, 8); + /* Store state in digest */ + Encode (digest, context->state, 16); + + /* Zeroize sensitive information. +*/ + MD5_memset ((POINTER)context, 0, sizeof (*context)); +} + +/* MD5 basic transformation. Transforms state based on block. + */ +static void MD5Transform (UINT4 state[4], unsigned char block[64]) +{ + UINT4 a = state[0], b = state[1], c = state[2], d = state[3], x[16]; + + Decode (x, block, 64); + + /* Round 1 */ + FF (a, b, c, d, x[ 0], S11, 0xd76aa478); /* 1 */ + FF (d, a, b, c, x[ 1], S12, 0xe8c7b756); /* 2 */ + FF (c, d, a, b, x[ 2], S13, 0x242070db); /* 3 */ + FF (b, c, d, a, x[ 3], S14, 0xc1bdceee); /* 4 */ + FF (a, b, c, d, x[ 4], S11, 0xf57c0faf); /* 5 */ + FF (d, a, b, c, x[ 5], S12, 0x4787c62a); /* 6 */ + FF (c, d, a, b, x[ 6], S13, 0xa8304613); /* 7 */ + FF (b, c, d, a, x[ 7], S14, 0xfd469501); /* 8 */ + FF (a, b, c, d, x[ 8], S11, 0x698098d8); /* 9 */ + FF (d, a, b, c, x[ 9], S12, 0x8b44f7af); /* 10 */ + FF (c, d, a, b, x[10], S13, 0xffff5bb1); /* 11 */ + FF (b, c, d, a, x[11], S14, 0x895cd7be); /* 12 */ + FF (a, b, c, d, x[12], S11, 0x6b901122); /* 13 */ + FF (d, a, b, c, x[13], S12, 0xfd987193); /* 14 */ + FF (c, d, a, b, x[14], S13, 0xa679438e); /* 15 */ + FF (b, c, d, a, x[15], S14, 0x49b40821); /* 16 */ + + /* Round 2 */ + GG (a, b, c, d, x[ 1], S21, 0xf61e2562); /* 17 */ + GG (d, a, b, c, x[ 6], S22, 0xc040b340); /* 18 */ + GG (c, d, a, b, x[11], S23, 0x265e5a51); /* 19 */ + GG (b, c, d, a, x[ 0], S24, 0xe9b6c7aa); /* 20 */ + GG (a, b, c, d, x[ 5], S21, 0xd62f105d); /* 21 */ + GG (d, a, b, c, x[10], S22, 0x2441453); /* 22 */ + GG (c, d, a, b, x[15], S23, 0xd8a1e681); /* 23 */ + GG (b, c, d, a, x[ 4], S24, 0xe7d3fbc8); /* 24 */ + GG (a, b, c, d, x[ 9], S21, 0x21e1cde6); /* 25 */ + GG (d, a, b, c, x[14], S22, 0xc33707d6); /* 26 */ + GG (c, d, a, b, x[ 3], S23, 0xf4d50d87); /* 27 */ + GG (b, c, d, a, x[ 8], S24, 0x455a14ed); /* 28 */ + GG (a, b, c, d, x[13], S21, 0xa9e3e905); /* 29 */ + GG (d, a, b, c, x[ 2], S22, 0xfcefa3f8); /* 30 */ + GG (c, d, a, b, x[ 7], S23, 0x676f02d9); /* 31 */ + GG (b, c, d, a, x[12], S24, 0x8d2a4c8a); /* 32 */ + + /* Round 3 */ + HH (a, b, c, d, x[ 5], S31, 0xfffa3942); /* 33 */ + HH (d, a, b, c, x[ 8], S32, 0x8771f681); /* 34 */ + HH (c, d, a, b, x[11], S33, 0x6d9d6122); /* 35 */ + HH (b, c, d, a, x[14], S34, 0xfde5380c); /* 36 */ + HH (a, b, c, d, x[ 1], S31, 0xa4beea44); /* 37 */ + HH (d, a, b, c, x[ 4], S32, 0x4bdecfa9); /* 38 */ + HH (c, d, a, b, x[ 7], S33, 0xf6bb4b60); /* 39 */ + HH (b, c, d, a, x[10], S34, 0xbebfbc70); /* 40 */ + HH (a, b, c, d, x[13], S31, 0x289b7ec6); /* 41 */ + HH (d, a, b, c, x[ 0], S32, 0xeaa127fa); /* 42 */ + HH (c, d, a, b, x[ 3], S33, 0xd4ef3085); /* 43 */ + HH (b, c, d, a, x[ 6], S34, 0x4881d05); /* 44 */ + HH (a, b, c, d, x[ 9], S31, 0xd9d4d039); /* 45 */ + HH (d, a, b, c, x[12], S32, 0xe6db99e5); /* 46 */ + HH (c, d, a, b, x[15], S33, 0x1fa27cf8); /* 47 */ + HH (b, c, d, a, x[ 2], S34, 0xc4ac5665); /* 48 */ + + /* Round 4 */ + II (a, b, c, d, x[ 0], S41, 0xf4292244); /* 49 */ + II (d, a, b, c, x[ 7], S42, 0x432aff97); /* 50 */ + II (c, d, a, b, x[14], S43, 0xab9423a7); /* 51 */ + II (b, c, d, a, x[ 5], S44, 0xfc93a039); /* 52 */ + II (a, b, c, d, x[12], S41, 0x655b59c3); /* 53 */ + II (d, a, b, c, x[ 3], S42, 0x8f0ccc92); /* 54 */ + II (c, d, a, b, x[10], S43, 0xffeff47d); /* 55 */ + II (b, c, d, a, x[ 1], S44, 0x85845dd1); /* 56 */ + II (a, b, c, d, x[ 8], S41, 0x6fa87e4f); /* 57 */ + II (d, a, b, c, x[15], S42, 0xfe2ce6e0); /* 58 */ + II (c, d, a, b, x[ 6], S43, 0xa3014314); /* 59 */ + II (b, c, d, a, x[13], S44, 0x4e0811a1); /* 60 */ + II (a, b, c, d, x[ 4], S41, 0xf7537e82); /* 61 */ + II (d, a, b, c, x[11], S42, 0xbd3af235); /* 62 */ + II (c, d, a, b, x[ 2], S43, 0x2ad7d2bb); /* 63 */ + II (b, c, d, a, x[ 9], S44, 0xeb86d391); /* 64 */ + + state[0] += a; + state[1] += b; + state[2] += c; + state[3] += d; + + /* Zeroize sensitive information. +*/ + MD5_memset ((POINTER)x, 0, sizeof (x)); +} + +/* Encodes input (UINT4) into output (unsigned char). Assumes len is + a multiple of 4. + */ +static void Encode (unsigned char *output, UINT4 *input, unsigned int len) +{ + unsigned int i, j; + + for (i = 0, j = 0; j < len; i++, j += 4) { + output[j] = (unsigned char)(input[i] & 0xff); + output[j+1] = (unsigned char)((input[i] >> 8) & 0xff); + output[j+2] = (unsigned char)((input[i] >> 16) & 0xff); + output[j+3] = (unsigned char)((input[i] >> 24) & 0xff); + } +} + +/* Decodes input (unsigned char) into output (UINT4). Assumes len is + a multiple of 4. + */ +static void Decode (UINT4 *output, unsigned char *input, unsigned int len) +{ + unsigned int i, j; + + for (i = 0, j = 0; j < len; i++, j += 4) + output[i] = ((UINT4)input[j]) | (((UINT4)input[j+1]) << 8) | + (((UINT4)input[j+2]) << 16) | (((UINT4)input[j+3]) << 24); +} + +/* Note: Replace "for loop" with standard memcpy if possible. + */ + +static void MD5_memcpy (POINTER output, POINTER input, unsigned int len) +{ + unsigned int i; + + for (i = 0; i < len; i++) + output[i] = input[i]; +} + +/* Note: Replace "for loop" with standard memset if possible. + */ +static void MD5_memset (POINTER output, int value, unsigned int len) +{ + unsigned int i; + + for (i = 0; i < len; i++) + ((char *)output)[i] = (char)value; +} diff --git a/source/memcard/md5.h b/source/memcard/md5.h new file mode 100644 index 000000000..e6aa51a66 --- /dev/null +++ b/source/memcard/md5.h @@ -0,0 +1,49 @@ +#ifndef __MEMCARD_MD5_H__ +#define __MEMCARD_MD5_H__ + + +#ifndef __MEMCARD_MD5GLOBAL_H__ +#include "memcard\md5global.h" +#endif + +#define MD5_CHECKSUM_SIZE 16 + + +/* MD5.H - header file for MD5C.C + */ + +/* Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All +rights reserved. + +License to copy and use this software is granted provided that it +is identified as the "RSA Data Security, Inc. MD5 Message-Digest +Algorithm" in all material mentioning or referencing this software +or this function. + +License is also granted to make and use derivative works provided +that such works are identified as "derived from the RSA Data +Security, Inc. MD5 Message-Digest Algorithm" in all material +mentioning or referencing the derived work. + +RSA Data Security, Inc. makes no representations concerning either +the merchantability of this software or the suitability of this +software for any particular purpose. It is provided "as is" +without express or implied warranty of any kind. + +These notices must be retained in any copies of any part of this +documentation and/or software. + */ + +/* MD5 context. */ +typedef struct { + UINT4 state[4]; /* state (ABCD) */ + UINT4 count[2]; /* number of bits, modulo 2^64 (lsb first) */ + unsigned char buffer[64]; /* input buffer */ +} MD5_CTX; + +void MD5Init (MD5_CTX *); +void MD5Update (MD5_CTX *, unsigned char *, unsigned int); +void MD5Final (unsigned char [16], MD5_CTX *); + + +#endif /* __MEMCARD_MD5_H__ */ \ No newline at end of file diff --git a/source/memcard/md5global.h b/source/memcard/md5global.h new file mode 100644 index 000000000..ceb771324 --- /dev/null +++ b/source/memcard/md5global.h @@ -0,0 +1,37 @@ +#ifndef __MEMCARD_MD5GLOBAL_H__ +#define __MEMCARD_MD5GLOBAL_H__ + + +/* GLOBAL.H - RSAREF types and constants +*/ + +///* PROTOTYPES should be set to one if and only if the compiler supports +//function argument prototyping. +//The following makes PROTOTYPES default to 0 if it has not already +//been defined with C compiler flags. +//*/ +//#ifndef PROTOTYPES +//#define PROTOTYPES 0 +//#endif + +/* POINTER defines a generic pointer type */ +typedef unsigned char *POINTER; + +/* UINT2 defines a two byte word */ +typedef unsigned short int UINT2; + +/* UINT4 defines a four byte word */ +typedef unsigned long int UINT4; + +///* PROTO_LIST is defined depending on how PROTOTYPES is defined above. +//If using PROTOTYPES, then PROTO_LIST returns the list, otherwise it +//returns an empty list. +//*/ +//#if PROTOTYPES +//#define PROTO_LIST(list) list +//#else +//#define PROTO_LIST(list) () +//#endif + + +#endif /* __MEMCARD_MD5GLOBAL_H__ */ \ No newline at end of file diff --git a/source/memcard/memcard.cpp b/source/memcard/memcard.cpp new file mode 100644 index 000000000..56ea992d3 --- /dev/null +++ b/source/memcard/memcard.cpp @@ -0,0 +1,1401 @@ +/*========================================================================= + + memcard.cpp + + Author: Paul Grenfell @ Climax + Created: Febuary 1999 + Project: Theme Park 2 + Purpose: Memory card access + + Copyright (c) 1999 Climax Development Ltd + +===========================================================================*/ + +/*---------------------------------------------------------------------- + Includes + -------- */ + +#include "memcard/memcard.h" + +#ifndef __SYSTEM_DBG_H__ +#include "system\dbg.h" +#endif + + +/* Std Lib + ------- */ + +#include +#include + +/*---------------------------------------------------------------------- + Tyepdefs && Defines + ------------------- */ + +#define SAVENAMEHEADER "PRLSR: " + +// for prlsr - use slot 1 only +#define USE_SLOT_ONE_ONLY + + + + +/*---------------------------------------------------------------------- + Structure defintions + -------------------- */ + +/*---------------------------------------------------------------------- + Positional Vars + --------------- */ + +/*---------------------------------------------------------------------- + Function Prototypes + ------------------- */ + + +/*---------------------------------------------------------------------- + Vars + ---- */ + + +int MemCard::s_active=false; + +int MemCard::s_currentChannel; +int MemCard::m_nextChannel; +MemCard::CMDTYPE MemCard::s_currentCommand; +MemCard::CMDTYPE MemCard::m_nextCommand; + +int MemCard::s_activeSlot=-1; + +MemCard::CARDDEF MemCard::s_cardData[MemCard::CARDSLOTSTOCHECK]; + +int MemCard::s_file; +int MemCard::s_blockCount; +char MemCard::s_tempFileInfoBuffer[128]; + +long int MemCard::s_syncStatus,MemCard::s_syncCmds,MemCard::s_syncResults; + +void *MemCard::s_bufPtr; + +char MemCard::s_userFileName[8+1]; +char MemCard::s_fname[20+1]; +char MemCard::s_fnameBase[40]; + +FileCallbackDef MemCard::s_callbackFunction; + + + + + +/*****************************************************************************/ +/*** SJIS Conversion Stuff ***************************************************/ +/*****************************************************************************/ +struct SjisS +{ + char Ascii; + unsigned char Num; + unsigned short Sjis; +}; + +static struct SjisS SjisTable[]= +{ + {'0',10, 0x824f },{'A',26, 0x8260 },{'a',26, 0x8281 }, + + {' ', 1,0x8140},{'!', 1,0x8149},{'"', 1,0x8168},{'#', 1,0x8194},{'$', 1,0x8190}, + {'%', 1,0x8193},{'&', 1,0x8195},{'\'',1,0x8166},{'(', 1,0x8169},{')', 1,0x816a}, + {'*', 1,0x8196},{'+', 1,0x817b},{',', 1,0x8143},{'-', 1,0x817c},{'.', 1,0x8144}, + {'/', 1,0x815e},{':', 1,0x8146},{';', 1,0x8147},{'<', 1,0x8171},{'=', 1,0x8181}, + {'>', 1,0x8172},{'?', 1,0x8148},{'@', 1,0x8197},{'[', 1,0x816d},{'\\',1,0x818f}, + {']', 1,0x816e},{'^', 1,0x814f},{'_', 1,0x8151},{'`', 1,0x8165},{'{', 1,0x816f}, + {'|', 1,0x8162},{'}', 1,0x8170},{'~', 1,0x8150},{0,0,0} +}; + +/*****************************************************************************/ +char MCToAscii(unsigned short Sjis) +{ + struct SjisS *Ptr = SjisTable; + + while( Ptr->Ascii ) + { + if( ( Sjis >= Ptr->Sjis ) && ( Sjis < ( Ptr->Sjis + Ptr->Num ) ) ) + { + /* Found SJIS code, return ASCII equivalent */ + return( Ptr->Ascii + ( Sjis - Ptr->Sjis ) ); + } + Ptr++; + } + + return '?'; // Unknown SJIS code +} +/*****************************************************************************/ +unsigned short MCToSjis(char Ascii) +{ + struct SjisS *Ptr=SjisTable; + + while (Ptr->Ascii) + { + if ((Ascii>=Ptr->Ascii) && (Ascii<(Ptr->Ascii+Ptr->Num))) + { + /* Found ASCII char, return SJIS equivalent */ + return (Ptr->Sjis+(Ascii-Ptr->Ascii)); + } + Ptr++; + } + + return( 0x8148 ); // Unknow char, return '?' +} + +/*****************************************************************************/ +// Returns: Pointer to a non-persistant containing ascii test +static char *JIStoASCII( unsigned short *Sjis ) +{ + unsigned short SwappedSjis[ 32+1 ]; + unsigned short *Src, *Dst; + char *CDst; + static char Ascii[ 64+1 ]; + + + Ascii[ 0 ] = '\0'; + + if( Sjis[ 0 ] & 0x0080 ) + { + Src = Sjis; + Dst = SwappedSjis; + while( *Src ) + { + *Dst = ( ( *Src & 0xff ) << 8 ) + ( *Src >> 8 ); + Src++; + Dst++; + } + *Dst++ = 0; + + // Convert to ASCII + Src = SwappedSjis; + CDst = Ascii; + while( *Src ) + { + *CDst++ = MCToAscii( *Src++ ); + } + *CDst++ = 0; + } + else + { + // Old style ASCII string - Just copy it across +// strcpy( (char *)sjis, ascii ); + return( "ASCII" ); + } + + return( Ascii ); +} +/*****************************************************************************/ +static unsigned short *ASCIItoJIS( char *Str ) +{ + static unsigned short SjisText[ 32+1 ]; + unsigned short *Sjis = SjisText; + + while( *Str ) + { + if( ( Str[ 0 ] ) & 0x80 ) + { + *Sjis++ = ( Str[ 0 ] << 8 ) | Str[ 1 ]; + Str += 2; + } + else + { + *Sjis++ = MCToSjis( *Str++ ); + } + } + + // Byte swap + unsigned short temp; + for( int i = 0; i < 32; i++ ) + { + temp = SjisText[ i ]; + SjisText[ i ] = ( ( temp & 0x00ff ) << 8 ) + ( ( temp & 0xff00 ) >> 8 ); + } + + + *Sjis++=0; *Sjis++=0; + return( SjisText ); +} +/*****************************************************************************/ +/*** SJIS Conversion Stuff ***************************************************/ +/*****************************************************************************/ + + + + + + +/*---------------------------------------------------------------------- + Function: Start + Purpose: Starts up memory card services. MemCardInit() should have already been called. + Params: None + Returns: Success + ---------------------------------------------------------------------- */ +bool MemCard::Start( void ) +{ + long int Dummy; + + + // Don't allow the sytem to be activated twice! + if( s_active == true ) + { + return( false ); + } + + // Startup system memcard services + MemCardStart(); + + // Make sure that the system memcard interface is idle + MemCardSync( 0, &Dummy, &Dummy ); + + // Initialisation + s_currentCommand=CmdNone; + m_nextCommand=CmdNone; + m_nextChannel=-1; + + InvalidateCard( 0 ); + InvalidateCard( 1 ); + s_currentChannel = 1; + s_activeSlot = -1; + CreateFName("\0"); + + // It's alive! + s_active = true; +// MEMCARD_DBGMSG( "[PMC] PMC started" ); + return( true ); +} + + + +/*---------------------------------------------------------------------- + Function: Stop + Purpose: Closes down memcard services. Call MemCardEnd() afterwards if you _really_ want to + shut the sytem memcard services down. + Params: None + Returns: Success + ---------------------------------------------------------------------- */ +bool MemCard::Stop( void ) +{ + long int Dummy; + + + // Check that the system is active + if( s_active != true ) + { + return( false ); + } + s_active = false; + + // Make sure that the system memcard interface is idle + MemCardSync( 0, &Dummy, &Dummy ); + + // Close down PSX memory card services + MemCardStop(); + + // Invalidate all data + InvalidateCard( 0 ); + InvalidateCard( 1 ); + + // Finished! +// MEMCARD_DBGMSG( "[PMC] PMC ended" ); + return( true ); +} + + + +/*---------------------------------------------------------------------- + Function: InvalidateCard + Purpose: Invalidates a card by clearing internal flags, also frees its memory + Params: Channel of card to invalidate + Returns: None + ---------------------------------------------------------------------- */ +void MemCard::InvalidateCard( int Channel ) +{ + // Clear data on the card + s_cardData[ Channel ].m_cardStatus = CS_NoCard; + s_cardData[ Channel ].m_slotStatus = SS_Idle; + s_cardData[ Channel ].m_totalFileCount = 0; + s_cardData[ Channel ].m_totalFreeBlocks = 0; + s_cardData[ Channel ].m_nativeFileCount = 0; + +MemCardClose(); + + // Stop whatever command was in operation and set the system to idle, the existance + // checks will then re-find this card if it is ok + if( Channel == m_nextChannel/*PKGm_nextCommand*/ ) + { + m_nextCommand = CmdNone; + m_nextChannel = -1; + } + s_currentCommand = CmdNone; + s_currentChannel = Channel; + + MEMCARD_DBGMSG( "[PMC] Invalidate card %d", Channel ); +} + + + +/*---------------------------------------------------------------------- + Function: GetErrorString + Purpose: Returns a pointer to a string which describes a memcard error code + Params: Error code + Returns: Pointer to error string + ---------------------------------------------------------------------- */ +static const char *GetErrorString( int ErrorCode ) +{ + switch( ErrorCode ) + { + case McErrNone: + return( "No error(!?)" ); + break; + + case McErrCardNotExist: + return( "Not connected" ); + + case McErrCardInvalid: + return( "Bad card" ); + + case McErrNewCard: + return( "New card ( card was replaced )" ); + + case McErrNotFormat: + return( "Not formatted" ); + + case McErrFileNotExist: + return( "File not found" ); + + case McErrAlreadyExist: + return( "File already exists" ); + + case McErrBlockFull: + return( "Not enough memory blocks" ); + + default: + return( "UNKNOWN MEMCARD ERROR CODE!" ); + } +} + + + +/*---------------------------------------------------------------------- + Function: GetCardStatus + Purpose: Access function to a cards status + Params: Channel of card + Returns: Status + ---------------------------------------------------------------------- */ +MemCard::CARDSTATUS MemCard::GetCardStatus( int Channel ) +{ + return( s_cardData[ Channel ].m_cardStatus ); +} + + + +/*---------------------------------------------------------------------- + Function: GetSlotStatus + Purpose: Access function to a slots status + Params: Channel of slot + Returns: Status + ---------------------------------------------------------------------- */ +MemCard::SLOTSTATUS MemCard::GetSlotStatus( int Channel ) +{ + return( s_cardData[ Channel ].m_slotStatus ); +} + + + +/*---------------------------------------------------------------------- + Function: GetFileCountOnCard + Purpose: Access function that gives the number of files on a cardthat belong to this app + Params: Channel of card + Returns: Number of files on card + ---------------------------------------------------------------------- */ +int MemCard::GetFileCountOnCard( int Channel ) +{ + if( s_cardData[ Channel ].m_cardStatus == CS_ValidCard ) + { + return( s_cardData[ Channel ].m_nativeFileCount ); + } + else + { + // If the card is not valid then return a file count of 0 + return( 0 ); + } +} + + + +/*---------------------------------------------------------------------- + Function: GetFreeBlocksOnCard + Purpose: Access function that gives the number of free blocks on a card + Params: Channel of card + Returns: Free block count + ---------------------------------------------------------------------- */ +int MemCard::GetFreeBlocksOnCard( int Channel ) +{ + if( s_cardData[ Channel ].m_cardStatus == CS_ValidCard ) + { + return( s_cardData[ Channel ].m_totalFreeBlocks ); + } + else + { + // If the card is not valid then return a free block count of 0 + return( 0 ); + } +} + + + +/*---------------------------------------------------------------------- + Function: GetFileName + Purpose: Access function to return a files name + Params: Channel of card and native file number + Returns: A non-persistant pointer to ASCII filename or NULL on error + ---------------------------------------------------------------------- */ +const char *MemCard::GetFileName( int Channel, int File ) +{ + if( File >= s_cardData[ Channel ].m_nativeFileCount ) + { + // Woah, we don't have this many files + return( NULL ); + } + else + { + // Convert name from SJIS and return + return( &JIStoASCII( s_cardData[ Channel ].m_nativeFileInfo[ File ].m_sjisName )[strlen(SAVENAMEHEADER)] ); + } +} + + + +/*---------------------------------------------------------------------- + Function: GetFileSizeInBlocks + Purpose: Access function to return the number of 8k blocks in a file + Params: Channel of card and file number + Returns: Number of blocks in file + ---------------------------------------------------------------------- */ +int MemCard::GetFileSizeInBlocks( int Channel, int File ) +{ + if( File >= s_cardData[ Channel ].m_nativeFileCount ) + { + // Woah, we don't have this many files + return( 0 ); + } + else + { + return( s_cardData[ Channel ].m_nativeFileInfo[ File ].m_blocks ); + } +} + + + +/*---------------------------------------------------------------------- + Function: FillHeaderDetails + Purpose: Takes a pointer to a file header and fills in filename and block count. This assumes + that you have used Sonys PDATool.exe to generate the header + Params: Number of blocks to save + ASCII filename ( max 32 chars ) + Returns: None + ---------------------------------------------------------------------- */ +void MemCard::FillHeaderDetails( unsigned char *HeaderBase, int FileLength, char *Filename ) +{ + int BlockCount=((FileLength-1)/BLOCKSIZE)+1; + char realFilename[32+1]; + + if( HeaderBase == NULL || + BlockCount < 1 || BlockCount > 15 || + strlen( Filename ) > 32-8 || + Filename[ 0 ] == '\0' ) + { + // Damn fool! + return; + } + sprintf(realFilename,"%s%s",SAVENAMEHEADER,Filename); + + // Fill in the details + HeaderBase[ 3 ] = (char)BlockCount; + memcpy( &HeaderBase[ 4 ], ASCIItoJIS( realFilename ), 64 ); + + return; +} + + +/*---------------------------------------------------------------------- + Function: ReadFile + Purpose: Starts file reading. + Params: Channel of card and file number + Callback gets called when the file reading has finsihed + Returns: Success + ---------------------------------------------------------------------- */ +bool MemCard::ReadFile( int Channel, int File, void *Dest, FileCallbackDef Callback ) +{ + // Check for valid input and that the card is idle etc... + if( s_cardData[ Channel ].m_cardStatus != CS_ValidCard || + File < 0 || File >= s_cardData[ Channel ].m_nativeFileCount || + Callback == NULL ) + { + return( false ); + } + + // Setup the load + m_nextChannel = Channel; + m_nextCommand = CmdReadFile; + s_file = File;//s_cardData[ Channel ].NativeFileInfo[ File ].DirEntry; + s_callbackFunction = Callback; + s_bufPtr = Dest; + + VSync( 0 ); + +// MEMCARD_DBGMSG( "[PMC] File read registered for card %d file %d", Channel, File ); + return( true ); +} + + +/*---------------------------------------------------------------------- + Function: WriteFile + Purpose: Starts file writing. If file supplied does not exist then a new one will be created first + Params: Channel of card and file number ( pass -1 as file number for new file ) + Source points to the source data + Blocks says how many blocks to wirte ( 1 block = 8k ) + Callback gets called when the file writing has finsihed + Returns: Success + ---------------------------------------------------------------------- */ +bool MemCard::WriteFile( int Channel, int File, u8 *FName, void *Source, int FileLength, FileCallbackDef Callback ) +{ + int Blocks=((FileLength-1)/BLOCKSIZE)+1; + + // Check for valid input and that the card is idle etc... +MEMCARD_DBGMSG("s: %d",s_cardData[ Channel ].m_cardStatus); + if( s_cardData[ Channel ].m_cardStatus != CS_ValidCard || + File < -1 || File >= s_cardData[ Channel ].m_nativeFileCount || + Blocks < 1 ||// Blocks > s_cardData[ Channel ].TotalFreeBlocks || + Callback == NULL ) + { + return( false ); + } + + // Setup the write as the next command + if( FName ) + strncpy( s_userFileName, (char*)FName, 8 ); + else + s_userFileName[0]='\0'; + m_nextChannel = Channel; + m_nextCommand = CmdWriteFile; + s_file = File; + s_callbackFunction = Callback; + s_blockCount = Blocks; + s_bufPtr = Source; + + VSync( 0 ); + +// MEMCARD_DBGMSG( "[PMC] File write registered" ); + return( true ); +} + + + +/*---------------------------------------------------------------------- + Function: FormatCard + Purpose: Starts file formatting. This will fail is the requested card is not unformatted + Params: Channel of card to format + Callback gets called when the format has finsihed + Returns: Success + ---------------------------------------------------------------------- */ +bool MemCard::FormatCard( int Channel, FileCallbackDef Callback ) +{ + // Check for valid input and that the card is idle etc... + if( s_cardData[ Channel ].m_cardStatus != CS_UnformattedCard || + Callback == NULL ) + { +// MEMCARD_DBGMSG( "[PMC] Card format not registered" ); + return( false ); + } + + + // Setup the format as the next command + m_nextChannel = Channel; + m_nextCommand = CmdFormatCard; + s_callbackFunction = Callback; + s_cardData[ Channel ].m_slotStatus = SS_Formatting; + +// MEMCARD_DBGMSG( "[PMC] Card format registered" ); + return( true ); +} + + + +/*---------------------------------------------------------------------- + Function: DeleteFile + Purpose: Starts file delete. + Params: Channel of card and file number + Callback gets called when the file writing has finsihed + Returns: Success + ---------------------------------------------------------------------- */ +bool MemCard::DeleteFile( int Channel, int File, FileCallbackDef Callback ) +{ + // Check for valid input etc... + if( s_cardData[ Channel ].m_cardStatus != CS_ValidCard || + File < 0 || File >= s_cardData[ Channel ].m_nativeFileCount || + Callback == NULL ) + { + return( false ); + } + + // Setup the load as the next command + m_nextChannel = Channel; + m_nextCommand = CmdDeleteFile; + strcpy( s_fname, s_cardData[ Channel ].m_totalDirEntry[ s_cardData[ Channel ].m_nativeFileInfo[ File ].m_dirEntry ].name ); + s_callbackFunction = Callback; + s_cardData[ s_currentChannel ].m_slotStatus = SS_Writing; + +// MEMCARD_DBGMSG( "[PMC] File delete registered for card %d file %d", Channel, File ); + return( true ); +} + + + +/*---------------------------------------------------------------------- + Function: HandleCmd_None + Purpose: Card command handler for CmdNone + In idle moments ( like these ) the memcard system checks both cards to + see if they have been inserted/removed. + Params: None ( Uses global PMC variables :) + Returns: None + ---------------------------------------------------------------------- */ +void MemCard::HandleCmd_None( void ) +{ + // System is idle? + if( s_syncStatus != -1 ) + { +// MEMCARD_DBGMSG( "[PMC] Not quite idle...!" ); + return; + } + +// MEMCARD_DBGMSG( "[PMC] ..HandleCmd_None()" ); + + if( m_nextCommand != CmdNone && + s_currentChannel == m_nextChannel ) + { + // Execute buffered command +// MEMCARD_DBGMSG( "[PMC] Set next command.. ss:%d ch:%d", (int)s_syncStatus, s_currentChannel ); + + s_currentCommand = m_nextCommand; + s_currentChannel = m_nextChannel; + m_nextCommand = CmdNone; + m_nextChannel = -1; + } + else +#ifdef USE_SLOT_ONE_ONLY + { + s_currentChannel=0; + s_currentCommand = CmdExist; + } +#else + { + // Do checks that the cards are still there +// MEMCARD_DBGMSG( "[PMC] check existance of other card.." ); + switch( s_activeSlot ) + { + case 1: + s_currentChannel=0; + break; + case 2: + s_currentChannel=1; + break; + default: + s_currentChannel^=1; + break; + } + s_currentCommand = CmdExist; + } +#endif +} + + + +/*---------------------------------------------------------------------- + Function: HandleCmd_Exist + Purpose: Card command handler for CmdExist + If a valid card is found then it is left ( it has already been accepted ). + If a new card is found then acceptance is started next frame. + Params: None ( Uses global PMC variables :) + Returns: None + ---------------------------------------------------------------------- */ +void MemCard::HandleCmd_Exist( void ) +{ + if( s_syncStatus == -1 ) + { + // No process active + MemCardExist( s_currentChannel << 4 ); + s_cardData[ s_currentChannel ].m_slotStatus = SS_Scanning; +// MEMCARD_DBGMSG( "[PMC] called MemCardExist()" ); + } + else + { +// MEMCARD_DBGMSG( "[PMC] returned from MemCardExist()" ); + // Process just ended + switch( s_syncResults ) + { + // Card exists + case McErrNone: + case McErrNewCard: + if( s_cardData[ s_currentChannel ].m_cardStatus == CS_ValidCard ) + { + // Lovely, the old valid card is still there + s_currentCommand = CmdNone; + s_cardData[ s_currentChannel ].m_slotStatus = SS_Idle; + } + else if( s_cardData[ s_currentChannel ].m_cardStatus == CS_UnformattedCard ) + { + // Found a card that has previously been marked as un-formatted + s_cardData[ s_currentChannel ].m_slotStatus = SS_Idle; + s_currentCommand = CmdNone; + } + else + { + // A card that hasn't yet been validated is there + //MEMCARD_DBGMSG( "[PMC] PMCmdExist says card exists but not yet valid" ); + s_cardData[ s_currentChannel ].m_cardStatus = CS_CardInserted; + s_currentCommand = CmdAccept; + } + break; + + // Error - Invalidate the card and go back to scanning + default: +// MEMCARD_DBGMSG( "[PMC] PMCmdExist returned error '%s'", GetErrorString( s_syncResults ) ); + InvalidateCard( s_currentChannel ); + break; + } + } +} + + + +/*---------------------------------------------------------------------- + Function: HandleCmd_Accept + Purpose: Card command handler for CmdAccept + If a card is accepted then start reading the directories next frame. + Params: None ( Uses global PMC variables :) + Returns: None + ---------------------------------------------------------------------- */ +void MemCard::HandleCmd_Accept( void ) +{ + if( s_syncStatus == -1 ) + { + // No process active + MemCardAccept( s_currentChannel << 4 ); + s_cardData[ s_currentChannel ].m_slotStatus = SS_Scanning; +// MEMCARD_DBGMSG( "[PMC] called MemCardAccept()" ); + } + else + { +// MEMCARD_DBGMSG( "[PMC] returned from MemCardAccept()" ); + // Process just ended + switch( s_syncResults ) + { + // Accepted ok + case McErrNone: + case McErrNewCard: + { + //MEMCARD_DBGMSG( "[PMC] PMCmdAccept says card ok but not yet valid" ); + s_currentCommand = CmdReadDir; + } + break; + + // Wa-hey, an unformatted card! + case McErrNotFormat: + s_cardData[ s_currentChannel ].m_cardStatus = CS_UnformattedCard; + s_cardData[ s_currentChannel ].m_slotStatus = SS_Idle; + s_currentCommand = CmdNone; + break; + + // Other error - Invalidate the card and continue searching + default: + //MEMCARD_DBGMSG( "[PMC] PMCmdAccept returned error '%s'", GetErrorString( s_syncResults ) ); + InvalidateCard( s_currentChannel ); + break; + } + } +} + + + +/*---------------------------------------------------------------------- + Function: HandleCmd_ReadDir + Purpose: Card command handler for CmdReadDir + NB: This function contains blocking calls to the system memcard library and _will_ slow down game code. + Params: None ( Uses global PMC variables :) + Returns: None + ---------------------------------------------------------------------- */ +void MemCard::HandleCmd_ReadDir( void ) +{ + int i, + BlockCount = 0; + + + // memCardGetDirectory() is blocking and returns after it has finsihed + switch( MemCardGetDirentry( s_currentChannel << 4, "*", + s_cardData[ s_currentChannel ].m_totalDirEntry, + (long int *)&s_cardData[ s_currentChannel ].m_totalFileCount, + 0, MAXFILES ) ) + { + // OK, now we have the cards file details + case McErrNone: + //MEMCARD_DBGMSG( "[PMC] PMCmdReadDir is valid" ); + + if( s_cardData[ s_currentChannel ].m_totalFileCount == 0 ) + { + // Card has no files - Accept the card now I guess... + s_cardData[ s_currentChannel ].m_totalFileCount = 0; + s_cardData[ s_currentChannel ].m_totalFreeBlocks = MAXBLOCKS; + s_cardData[ s_currentChannel ].m_nativeFileCount = 0; + s_file = 0; + s_currentCommand = CmdNone; + s_cardData[ s_currentChannel ].m_cardStatus = CS_ValidCard; + s_cardData[ s_currentChannel ].m_slotStatus = SS_Idle; + } + else + { + // Calculate number of blocks free on this card + for( i = 0; i < s_cardData[ s_currentChannel ].m_totalFileCount; i++ ) + { + BlockCount += s_cardData[ s_currentChannel ].m_totalDirEntry[ i ].size / BLOCKSIZE; + } + s_cardData[ s_currentChannel ].m_totalFreeBlocks = MAXBLOCKS - BlockCount; + + // Start getting the file details from file 0 + s_file = 0; + s_currentCommand = CmdReadFileInfo; + s_cardData[ s_currentChannel ].m_nativeFileCount = 0; + } + break; + + // Error! + default: + //MEMCARD_DBGMSG( "[PMC] PMCmdReadDir is not valid!" ); + InvalidateCard( s_currentChannel ); + break; + } +} + + + +/*---------------------------------------------------------------------- + Function: HandleCmd_ReadFileInfo + Purpose: Card command handler for Cmd + Params: None ( Uses global PMC variables :) + Returns: None + ---------------------------------------------------------------------- */ +void MemCard::HandleCmd_ReadFileInfo( void ) +{ + if( s_syncStatus == -1 ) + { + // No process active - Start reading file info + if( MemCardReadFile( s_currentChannel << 4, + s_cardData[ s_currentChannel ].m_totalDirEntry[ s_file ].name, + (long unsigned int *)s_tempFileInfoBuffer, 0, 128 ) == 0 ) + { + MEMCARD_DBGMSG( "[PMC] Reading file info for file %d", s_file ); + } + } + else + { + // Must have just finished a MemCardReadFile() + switch( s_syncResults ) + { + // File read ok + case McErrNone: + // Does the file we have just read look like a valid native file? + if( strncmp( s_fnameBase, s_cardData[ s_currentChannel ].m_totalDirEntry[ s_file ].name, 12 ) == 0 && + (char)s_tempFileInfoBuffer[ 0 ] == 'S' & (char)s_tempFileInfoBuffer[ 1 ] == 'C' /*&& // Magic 'SC' + (char)s_tempFileInfoBuffer[ 68 ] == 0 && // Pad area all 0s + memcmp( (char *)&s_tempFileInfoBuffer[ 68 ], (char *)&s_tempFileInfoBuffer[ 68 + 1 ], 27 ) == 0 */ ) + // Pad area check removed since some save files ( RidgeRacerR4 f'rinstance ) have crap in there :( + // Actually... This turns out to be PDA data :) + { + // Yup + int FileNumber = s_cardData[ s_currentChannel ].m_nativeFileCount++; + memcpy( s_cardData[ s_currentChannel ].m_nativeFileInfo[ FileNumber ].m_sjisName, &s_tempFileInfoBuffer[ 4 ], COMPRESSEDNAMESIZE ); + s_cardData[ s_currentChannel ].m_nativeFileInfo[ FileNumber ].m_blocks = (char)s_tempFileInfoBuffer[ 3 ]; + s_cardData[ s_currentChannel ].m_nativeFileInfo[ FileNumber ].m_dirEntry = s_file; + } + else + { + // Nope, ignore this file! + } + + // Have we read all of the files yet? + if( s_file < s_cardData[ s_currentChannel ].m_totalFileCount - 1 ) + { + // Nope - Check the next one + s_file++; + } + else + { + // Yes - Finished reading file info of all files on this card so it is now, at last, valid ( Huzzah! ) + s_file = 0; + s_currentCommand = CmdNone; + s_cardData[ s_currentChannel ].m_cardStatus = CS_ValidCard; + s_cardData[ s_currentChannel ].m_slotStatus = SS_Idle; + } + break; + + // Error - Invalidate the card and go back to scanning + default: + //MEMCARD_DBGMSG( "[PMC] PMCmdReadFileInfo returned error '%s'", GetErrorString( s_syncResults ) ); + InvalidateCard( s_currentChannel ); + break; + } + } +} + + + +/*---------------------------------------------------------------------- + Function: HandleCmd_ReadFile + Purpose: Card command handler for CmdReadFile + Starts file loading, which is done in one big go. + When file reading is finished, a callback function is executed + Params: None ( Uses global PMC variables :) + Returns: None + ---------------------------------------------------------------------- */ +void MemCard::HandleCmd_ReadFile( void ) +{ + if( s_syncStatus == -1 ) + { + // No process active - Start the load + int FileNumber = s_cardData[ s_currentChannel ].m_nativeFileInfo[ s_file ].m_dirEntry; + if( MemCardReadFile( s_currentChannel << 4, s_cardData[ s_currentChannel ].m_totalDirEntry[ FileNumber ].name, + (unsigned long *)s_bufPtr, + 0, GetFileSizeInBlocks( s_currentChannel, s_file ) * BLOCKSIZE ) == 0 ) + { +// MEMCARD_DBGMSG( "[PMC] Couldn't register MemCardReadFile!" ); + s_currentCommand = CmdNone; + s_cardData[ s_currentChannel ].m_slotStatus = SS_Idle; + } + else + { +// MEMCARD_DBGMSG( "[PMC] Called MemCardReadFile ( %d %d )", s_currentChannel, s_file ); + s_cardData[ s_currentChannel ].m_slotStatus = SS_Reading; + } + } + else + { + // Must have just finished reading a file in + switch( s_syncResults ) + { + case McErrNone: +// MEMCARD_DBGMSG( "[PMC] File read ok for card %d file %d", s_currentChannel, s_file ); + s_file = 0; + s_currentCommand = CmdNone; + s_cardData[ s_currentChannel ].m_slotStatus = SS_Idle; + + // Call the callback + s_callbackFunction( CCS_ReadFileOK ); + s_callbackFunction = NULL; + break; + + default: +// MEMCARD_DBGMSG( "[PMC] PMCmdReadFile returned error '%s'", GetErrorString( s_syncResults ) ); +// InvalidateCard( s_currentChannel ); + + // Call the callback + s_currentCommand = CmdExist; + s_callbackFunction( CCS_ReadFileFail ); + s_callbackFunction = NULL; + break; + } + } +} + + + +/*---------------------------------------------------------------------- + Function: HandleCmd_WriteFile + Purpose: Card command handler for CmdWriteFile + Starts file writing, which is done in one big go. + When file writing is finished, a callback function is executed + Params: None ( Uses global PMC variables :) + Returns: None + ---------------------------------------------------------------------- */ +void MemCard::HandleCmd_WriteFile( void ) +{ +// MEMCARD_DBGMSG( "[PMC] HandleCmd_WriteFile sync=%d", s_syncStatus ); + if( s_syncStatus == -1 ) + { + // No process active + int CRes; +// bool NameValid = false; + + // Does the specified file exist? + if( s_file == -1 ) + { + // Nope, need to create it +// do + { + // Create filename + char NewFName[ 20 + 1 ] = "\0"; + CreateFName(s_fname); + strcat( NewFName, s_fnameBase ); // Base filename + strcpy( s_fname, NewFName ); + + // The creation ( blocking function ) + CRes = MemCardCreateFile( s_currentChannel << 4, s_fname, s_blockCount ); + switch( CRes ) + { + case McErrNone: + MEMCARD_DBGMSG( "[PMC] Created new file '%s'", s_fname ); + s_currentCommand = CmdWriteFile; + s_cardData[ s_currentChannel ].m_slotStatus = SS_Writing; +// NameValid = true; + break; + +// case McErrAlreadyExist: +// // File already exists, try next +// CreateFName(); +// break; + + default: + MEMCARD_DBGMSG( "[PMC] Couldn't MemCardCreateFile due to '%s'", GetErrorString( CRes ) ); + s_currentCommand = CmdNone; + s_cardData[ s_currentChannel ].m_slotStatus = SS_Idle; + s_callbackFunction( CCS_WriteFileFail ); + s_callbackFunction = NULL; + return; + } + } +// while( NameValid == false ); + } + else + { + strcpy( s_fname, s_cardData[ s_currentChannel ].m_totalDirEntry[ s_cardData[ s_currentChannel ].m_nativeFileInfo[ s_file ].m_dirEntry ].name ); + } + + // Start the write + if( MemCardWriteFile( s_currentChannel << 4, s_fname, (unsigned long *)s_bufPtr, + 0, s_blockCount * BLOCKSIZE ) == 0 ) + { + MEMCARD_DBGMSG( "[PMC] Couldn't register MemCardWriteFile due to '%s'", GetErrorString( s_syncResults ) ); + s_currentCommand = CmdNone; + s_cardData[ s_currentChannel ].m_slotStatus = SS_Idle; + } + else + { + MEMCARD_DBGMSG( "[PMC] Called MemCardWriteFile" ); + s_cardData[ s_currentChannel ].m_slotStatus = SS_Writing; + } + } + else + { + // Must have just finished writing a file + switch( s_syncResults ) + { + case McErrNone: + MEMCARD_DBGMSG( "[PMC] File write completed!" ); + // Call the callback + s_currentCommand = CmdReadDir; + s_callbackFunction( CCS_WriteFileOK ); + s_callbackFunction = NULL; + break; + + default: + MEMCARD_DBGMSG( "[PMC] PMCmdWriteFile returned error '%s'", GetErrorString( s_syncResults ) ); + // Call the callback + s_currentCommand = CmdReadDir; + s_callbackFunction( CCS_WriteFileFail ); + s_callbackFunction = NULL; + break; + } + } +} + + + +/*---------------------------------------------------------------------- + Function: HandleCmd_FormatCard + Purpose: Card command handler for CmdFormatCard + Starts card formatting, which is done in one big go and _is_ a blocking function! + When card formatting is finished, a callback function is executed + Params: None ( Uses global PMC variables :) + Returns: None + ---------------------------------------------------------------------- */ +void MemCard::HandleCmd_FormatCard( void ) +{ + int FRes; + + + long int Dummy; + MemCardSync( 0, &Dummy, &Dummy ); + + // Format is a blocking function + MemCardClose(); + MemCardUnformat( s_currentChannel << 4 ); + MemCardClose(); + FRes = MemCardFormat( s_currentChannel << 4 ); +// MEMCARD_DBGMSG( "[PMC] FRes = %d", FRes ); + switch( FRes ) + { + case McErrNone: + //MEMCARD_DBGMSG( "[PMC] Format OK!" ); + s_callbackFunction( CCS_FormatCardOK ); + break; + + default: + //MEMCARD_DBGMSG( "[PMC] Format not ok - Returned error '%s'", GetErrorString( FRes ) ); + s_callbackFunction( CCS_FormatCardFail ); + break; + } + + MemCardClose(); + s_callbackFunction = NULL; + s_currentCommand = CmdExist; +} + + + +/*---------------------------------------------------------------------- + Function: HandleCmd_DeleteFile + Purpose: Card command handler for CmdDeleteFile + Starts file deletion, which is done in one big go and _is_ a blocking function! + When file deletion is finished, a callback function is executed + Params: None ( Uses global PMC variables :) + Returns: None + ---------------------------------------------------------------------- */ +void MemCard::HandleCmd_DeleteFile( void ) +{ + int DRes; + + + // Delete is a blocking function + DRes = MemCardDeleteFile( s_currentChannel << 4, s_fname ); + switch( DRes ) + { + case McErrNone: + //MEMCARD_DBGMSG( "[PMC] Delete OK!" ); + s_callbackFunction( CCS_DeleteFileOK ); + s_callbackFunction = NULL; + + // Force a re-scan of the directories + s_currentCommand = CmdReadDir; + break; + + default: + //MEMCARD_DBGMSG( "[PMC] Delete not ok - Returned error '%s'", GetErrorString( DRes ) ); + s_callbackFunction( CCS_DeleteFileFail ); + s_callbackFunction = NULL; + + // Force a re-scan of the directories + s_currentCommand = CmdReadDir; + break; + } +} + + + +/*---------------------------------------------------------------------- + Function: Handler + Purpose: Main memory card handler. Call from main loop somewhere once every vsync ( or less if you dare :) + Params: None + Returns: None + ---------------------------------------------------------------------- */ +//#define DEBUG_MEMCARD_STATUS + +#ifdef DEBUG_MEMCARD_STATUS +static int dinfo=true; +static char *cardtext[]= { "nocard", "cardinserted", "validcard", "unformattedcard" }; +//static char *slottext[]= { "idle", "scanning", "reading", "writing", "formatting" }; +static MemCard::CARDSTATUS lastCardStatus[2]={MemCard::CS_UnformattedCard,MemCard::CS_UnformattedCard}; +static MemCard::SLOTSTATUS lastSlotStatus[2]={MemCard::SS_Formatting,MemCard::SS_Formatting}; +#endif + +void MemCard::Handler( void ) +{ + // Ensure that memory cards are active + if( s_active ) + { + +// debug info +#ifdef DEBUG_MEMCARD_STATUS + if(dinfo) +{ + for(int i=0;i<2;i++) + { + if( lastCardStatus[i] != s_cardData[i].m_cardStatus ) + { + MEMCARD_DBGMSG("card %d status changed to %s", i, cardtext[s_cardData[i].m_cardStatus] ); + lastCardStatus[i] = s_cardData[i].m_cardStatus; + } +/* + if( lastSlotStatus[i] != s_cardData[i].SlotStatus ) + { + MEMCARD_DBGMSG("slot %d status changed to %s", i, slottext[s_cardData[i].SlotStatus] ); + lastSlotStatus[i] = s_cardData[i].SlotStatus; + } +*/ + } +} +#endif + + // See what the system is doing + s_syncStatus = MemCardSync( 1, &s_syncCmds, &s_syncResults ); + + // Don't bother calling the command function if status is 0 ( still processing ) + if( s_syncStatus != 0 ) + { + //MEMCARD_DBGMSG( "[PMC] run command (syn:%c%d com:%d)", s_syncStatus<0?'-':'+', s_syncStatus, s_currentCommand ); + switch(s_currentCommand) + { + case CmdNone: + HandleCmd_None(); + break; + case CmdExist: + HandleCmd_Exist(); + break; + case CmdAccept: + HandleCmd_Accept(); + break; + case CmdReadDir: + HandleCmd_ReadDir(); + break; + case CmdReadFileInfo: + HandleCmd_ReadFileInfo(); + break; + case CmdReadFile: + HandleCmd_ReadFile(); + break; + case CmdWriteFile: + HandleCmd_WriteFile(); + break; + case CmdFormatCard: + HandleCmd_FormatCard(); + break; + case CmdDeleteFile: + HandleCmd_DeleteFile(); + break; + } + } + } +} + + + +void MemCard::SetActiveCardSlot( int Channel ) +{ + s_activeSlot = Channel; +} + + + +/*---------------------------------------------------------------------- + Function: + Purpose: + Params: *result should point to a 16byte buffer + Returns: + ---------------------------------------------------------------------- */ +void MemCard::GiveCheckSum(unsigned char *_result,unsigned char *_data,u32 _size) +{ + MD5_CTX ctx; + MD5Init(&ctx); + MD5Update(&ctx,_data,_size); + MD5Final(_result,&ctx); +} + + +/*---------------------------------------------------------------------- + Function: + Purpose: + Params: *result is the checksum generated when the data was saved + Returns: + ---------------------------------------------------------------------- */ +int MemCard::TestCheckSum(unsigned char *_result,unsigned char *_data,u32 _size) +{ + MD5_CTX ctx; + unsigned char calcedResult[MD5_CHECKSUM_SIZE]; + int i; + + MD5Init(&ctx); + MD5Update(&ctx,_data,_size); + MD5Final(calcedResult,&ctx); + + for(i=0;im_nativeFileCount;i++) + { + if(strncmp(GetFileName(_slot,i),_name,8)==0) + return false; + } + return true; +} + +// returns -1 on error +int MemCard::FindFilenumberFromFilename(int _slot,char *_name) +{ + int i; + CARDDEF *cdata=&s_cardData[_slot]; + + if(_name==NULL||_name[0]=='\0') + return -1; + + for(i=0;im_nativeFileCount;i++) + { + if(strncmp(GetFileName(_slot,i),_name,8)==0) + return i; + } + return -1; +} + + + +/*=========================================================================== + end */ \ No newline at end of file diff --git a/source/memcard/memcard.h b/source/memcard/memcard.h new file mode 100644 index 000000000..3933cf309 --- /dev/null +++ b/source/memcard/memcard.h @@ -0,0 +1,266 @@ +/*========================================================================= + + memcard.h + + Author: Paul Grenfell @ Climax + Created: Febuary 1999 + Project: Theme Park 2 + Purpose: Memory card access + + Copyright (c) 1999 Climax Development Ltd + +===========================================================================*/ + +#ifndef __MEMCARD_MEMCARD_H__ +#define __MEMCARD_MEMCARD_H__ + + + +/*---------------------------------------------------------------------- + Includes + -------- */ + +#ifndef _GLOBAL_HEADER_ +#include "system\global.h" +#endif + +#ifndef __MEMCARD_MD5_H__ +#include "memcard\md5.h" +#endif + + +/* Std Lib + ------- */ + +/* Glib + ---- */ + +/* Local + ----- */ + +/*---------------------------------------------------------------------- + Tyepdefs && Defines + ------------------- */ + + + + +/*---------------------------------------------------------------------- + Structure defintions + -------------------- */ + +/*---------------------------------------------------------------------- + Globals + ------- */ + +/* Class + ----- */ + +/* Vars + ---- */ + +/* Data + ---- */ + +/* Functions + --------- */ + +// Definition of a memcard file callback +typedef void (* FileCallbackDef)( int _status ); + + +class MemCard +{ +public: + /* + Filenames created will be of something like "BEXXXX-00000SAVE000A". The last four characters are generated + automatically by the file create function. All files on a card need unique names so if we can't save the file + "BEXXXX-00000SAVE000A" we try and save "BEXXXX-00000SAVE000B" and so on until we succeed. If we create the filename + this way then we won't be able to copy between cards ( the first save on each card will always be called + "BEXXXX-00000SAVE000A" ). To solve this we put a random number ( or a frame count... ) into the last three + digits of the name when we save. This should at least limit the chances of files with identical names being saved + onto different cards. + */ + // PKG - Changed this now.. savegame names are fixed to "B?XXXX-00000xxxxxxxx" where + // xxxxxxxx is the users save name + + // Describe the filename for this product +/* What utter tosh + #define FNAME_MAGIC "B" // Always B, 'cos it's magic + #define FNAME_PCODE_US "ASLUS-00000" + #define FNAME_PCODE_EURO "ESLES-00000" +*/ +// Memcard filenames (not using else, to make sure its correct) +#if defined(__TERRITORY_USA__) +#define MEMCARD_BASE_FILENAME "BASLUS-01114" +#endif +#if defined(__TERRITORY_UK__) +#define MEMCARD_BASE_FILENAME "BESLES-03253" +#endif +#if defined(__TERRITORY_EUR__) +#define MEMCARD_BASE_FILENAME "BESLES-03286" +#endif + + + + + + // Describes the status of the card in a slot + typedef enum + { + CS_NoCard, // No card in slot + CS_CardInserted, // Card in slot ( busy scanning it ) + CS_ValidCard, // Totally valid, formatted and happy card + CS_UnformattedCard, // Card is valid but not formatted + } CARDSTATUS; + + // Describes what a card slot is doing + typedef enum _pmcstatus + { + SS_Idle, // Slot is idle + SS_Scanning, // Slot is scanning ( card existance checks ) + SS_Reading, // Slot is reading card + SS_Writing, // Slot is writing to card + SS_Formatting, // Slot is formatting card + } SLOTSTATUS; + + // Memcard callbacks return one of these: + typedef enum _pmccallbackstatus + { + CCS_ReadFileOK, + CCS_ReadFileFail, + CCS_WriteFileOK, + CCS_WriteFileFail, + CCS_FormatCardOK, + CCS_FormatCardFail, + CCS_DeleteFileOK, + CCS_DeleteFileFail, + CCS_GeneralFailure, + } CALLBACKSTATUS; + + + + + MemCard() {;} + ~MemCard() {;} + + static bool Start( void ); + static bool Stop( void ); + static void InvalidateCard( int Channel ); + static void Handler( void ); + + static CARDSTATUS GetCardStatus( int Channel ); + static SLOTSTATUS GetSlotStatus( int Channel ); + static int GetFileCountOnCard( int Channel ); + static int GetFreeBlocksOnCard( int Channel ); + static const char *GetFileName( int Channel, int File ); + static int GetFileSizeInBlocks( int Channel, int File ); + + static void FillHeaderDetails( unsigned char *HeaderBase, int FileLength, char *Filename ); + + static bool ReadFile( int Channel, int File, void *Dest, FileCallbackDef Callback ); + static bool WriteFile( int Channel, int File, u8 *FName, void *Source, int FileLength, FileCallbackDef Callback ); + static bool FormatCard( int Channel, FileCallbackDef Callback ); + static bool DeleteFile( int Channel, int File, FileCallbackDef Callback ); + + static void SetActiveCardSlot( int Channel ); + + static void GiveCheckSum(unsigned char *_result,unsigned char *_data,u32 _size); + static int TestCheckSum(unsigned char *_result,unsigned char *_data,u32 _size); + + static bool IsValidSavename(int _slot,char *_name); + static int FindFilenumberFromFilename(int _slot,char *_name); + + enum { + BLOCKSIZE =8192, // 8k per file block + + }; +private: + enum + { + MAXBLOCKS =15, // Max of 15 blocks per card + MAXFILES =15, // Max of 15 files per card + COMPRESSEDNAMESIZE =64, // Length of Shift-JIS filename + CARDSLOTSTOCHECK =2, // Number of card slots available + }; + + // Available command types + typedef enum + { + CmdNone, // No command + CmdExist, // Check that card exists + CmdAccept, // Accept card after cheking that it exists + CmdReadDir, // Read directory of card + CmdReadFileInfo, // Reading info of each file + CmdReadFile, // Reading a file from card to memory + CmdWriteFile, // Writing data to a file + CmdFormatCard, // Formatting card + CmdDeleteFile, // Delete a file + } CMDTYPE; + + // Definition of a card slot + typedef struct _pmccarddef + { + CARDSTATUS m_cardStatus; // Status of the crad ( 'in'/'out'/'maybe' sort of thing ) + SLOTSTATUS m_slotStatus; // Status of the slot ( 'Idle'/'Scan'/'Read'/'Write'/'Format' ) + + // General data on all files on card + int m_totalFileCount; // Number of files on this card + int m_totalFreeBlocks; // Number of free blocks on this card + struct DIRENTRY m_totalDirEntry[ MAXFILES ]; // Basic file info ( internal use mainly ) + + // Data on app specific files + int m_nativeFileCount; // Number of files on this card that belong to this app + struct _fileinfo // File info on files that belong to this app + { + unsigned short m_sjisName[ 64 ]; // Shift-JIS name of file + int m_blocks; // Number of blocks this file uses + int m_dirEntry; // Number of file in TotalDirEntry array + } m_nativeFileInfo[ MAXFILES ]; + } CARDDEF; + + + // Command handler functions + static void HandleCmd_None( void ); + static void HandleCmd_Exist( void ); + static void HandleCmd_Accept( void ); + static void HandleCmd_ReadDir( void ); + static void HandleCmd_ReadFileInfo( void ); + static void HandleCmd_ReadFile( void ); + static void HandleCmd_WriteFile( void ); + static void HandleCmd_FormatCard( void ); + static void HandleCmd_DeleteFile( void ); + + static void CreateFName(char *fname); + + + static int s_active; + + static int s_currentChannel,m_nextChannel; + static CMDTYPE s_currentCommand,m_nextCommand; + static int s_activeSlot; + static CARDDEF s_cardData[CARDSLOTSTOCHECK]; + + static int s_file; + static int s_blockCount; + static char s_tempFileInfoBuffer[128]; + + static long int s_syncStatus,s_syncCmds,s_syncResults; + + static void *s_bufPtr; + + static char s_userFileName[8+1]; + static char s_fname[20+1]; + static char s_fnameBase[40]; + + static FileCallbackDef s_callbackFunction; + +}; + + +/*---------------------------------------------------------------------- */ + +#endif /* __MEMCARD_H__ */ + +/*=========================================================================== + end */ \ No newline at end of file diff --git a/source/memcard/saveload.cpp b/source/memcard/saveload.cpp new file mode 100644 index 000000000..45a162a2d --- /dev/null +++ b/source/memcard/saveload.cpp @@ -0,0 +1,537 @@ +/*========================================================================= + + saveload.cpp + + Author: PKG + Created: + Project: SBSP + Purpose: + + Copyright (c) 2000 Climax Development Ltd + +===========================================================================*/ + + +/*---------------------------------------------------------------------- + Includes + -------- */ + +#include "memcard\saveload.h" + +#ifndef __MEMORY_HEADER__ +#include "mem\memory.h" +#endif + +#ifndef __MEMCARD_MEMCARD_H__ +#include "memcard\memcard.h" +#endif + +#ifndef _FILEIO_HEADER_ +#include "fileio\fileio.h" +#endif + +#ifndef __VID_HEADER_ +#include "system\vid.h" +#endif + +#ifndef __LOCALE_TEXTDBASE_H__ +#include "locale\textdbase.h" +#endif + +#ifndef __FILE_EQUATES_H__ +#include +#endif + + +/* Std Lib + ------- */ + +/* Gfx + --- */ + +/*---------------------------------------------------------------------- + Tyepdefs && Defines + ------------------- */ + +/*---------------------------------------------------------------------- + Structure defintions + -------------------- */ + +/*---------------------------------------------------------------------- + Positional Vars + --------------- */ + +/*---------------------------------------------------------------------- + Function Prototypes + ------------------- */ + +static void callback(int _status); + + +/*---------------------------------------------------------------------- + Vars + ---- */ + +static int s_callbackEnded=false; +static int s_callbackStatus=0; + + + + +/*---------------------------------------------------------------------- + Function: + Purpose: + Params: + Returns: + ---------------------------------------------------------------------- */ +SaveLoadDatabase::SaveLoadDatabase() +{ + m_saving=false; + m_loading=false; + m_formatting=false; + m_loading=false; + m_autoloading=false; + m_tempBuffer=NULL; + + gatherData(); +} + + +/*---------------------------------------------------------------------- + Function: + Purpose: + Params: + Returns: + ---------------------------------------------------------------------- */ +SaveLoadDatabase::~SaveLoadDatabase() +{ +} + + +/*---------------------------------------------------------------------- + Function: + Purpose: + Params: + Returns: + ---------------------------------------------------------------------- */ +void SaveLoadDatabase::think() +{ + MemCard::Handler(); +} + + +/*---------------------------------------------------------------------- + Function: + Purpose: + Params: + Returns: + ---------------------------------------------------------------------- */ +void SaveLoadDatabase::gatherData() +{ + ASSERT(!m_saving); + ASSERT(!m_loading); + ASSERT(!m_formatting); + ASSERT(!m_autoloading); + + createData(); +} + + +/*---------------------------------------------------------------------- + Function: + Purpose: + Params: + Returns: + ---------------------------------------------------------------------- */ +bool SaveLoadDatabase::startSave(char *_filename,int _fileNum=-1) +{ + char nameBuf[9]="\0"; + u8 *hdr; + + ASSERT(!m_saving); + ASSERT(!m_loading); + ASSERT(!m_formatting); + ASSERT(!m_autoloading); + + if(_fileNum!=-1) + { + strncat(nameBuf,MemCard::GetFileName(0,_fileNum),8); + _filename=nameBuf; + } + + // Alloc a buffer and copy everything to it + allocateBuffer(); + hdr=CFileIO::loadFile(MEMCARD_MEMHEAD_BIN); + memcpy((char*)&m_tempBuffer[0],hdr,256); // Memcard header + MemCard::FillHeaderDetails(m_tempBuffer,m_bufferSize,_filename); // Setup header + memcpy((char*)&m_tempBuffer[256],(char*)&m_dataBuffer,sizeof(m_dataBuffer)); // Data + MemCard::GiveCheckSum(&m_tempBuffer[m_bufferSize-MD5_CHECKSUM_SIZE], // Chksum + m_tempBuffer,m_bufferSize-MD5_CHECKSUM_SIZE); + + + // Start write to memcard + if(!MemCard::WriteFile(0,_fileNum,(u8*)_filename,(void*)m_tempBuffer,m_bufferSize,&callback)) + { + MEMCARD_DBGMSG("write error"); + freeBuffer(); + return false; + } + + s_callbackEnded=false; + m_saving=true; + return true; +} + + +/*---------------------------------------------------------------------- + Function: + Purpose: + Params: + Returns: + ---------------------------------------------------------------------- */ +int SaveLoadDatabase::getSaveStatus() +{ + int ret=INACTIVE; + + if(m_saving) + { + if(MemCard::GetCardStatus(0)==MemCard::CS_NoCard) + { +MEMCARD_DBGMSG("======= weird card removal - bonus 50 points"); + // Card removed at weird time.. + ret=FAILED; + s_callbackEnded=false; + m_saving=false; + freeBuffer(); + } + else if(s_callbackEnded) + { + ASSERT(m_tempBuffer); + + if(s_callbackStatus==MemCard::CCS_WriteFileOK) ret=FINISHED_OK; + else ret=FAILED; + freeBuffer(); + + s_callbackEnded=false; + m_saving=false; + } + else + { + ret=IN_PROGRESS; + } + } + + return ret; +} + + +/*---------------------------------------------------------------------- + Function: + Purpose: + Params: + Returns: + ---------------------------------------------------------------------- */ +bool SaveLoadDatabase::startLoad(int _file) +{ + ASSERT(!m_saving); + ASSERT(!m_loading); + ASSERT(!m_formatting); + + // Alloc a buffer to load to + allocateBuffer(); + + // Start read from memcard + if(!MemCard::ReadFile(0,_file,(void*)m_tempBuffer,&callback)) + { + MEMCARD_DBGMSG("read error"); + freeBuffer(); + return false; + } + + s_callbackEnded=false; + m_loading=true; + return true; +} + + +/*---------------------------------------------------------------------- + Function: + Purpose: + Params: + Returns: + ---------------------------------------------------------------------- */ +int SaveLoadDatabase::getLoadStatus() +{ + int ret=INACTIVE; + + if(m_loading) + { + if(MemCard::GetCardStatus(0)==MemCard::CS_NoCard) + { + MEMCARD_DBGMSG("======= weird card removal - bonus 50 points"); + // Card removed at weird time.. + freeBuffer(); + + m_loading=false; + m_autoloading=false; + s_callbackEnded=false; + ret=FAILED; + } + else if(s_callbackEnded) + { + ASSERT(m_tempBuffer); + + // Load ok? + if(s_callbackStatus==MemCard::CCS_ReadFileOK&& + MemCard::TestCheckSum(&m_tempBuffer[m_bufferSize-MD5_CHECKSUM_SIZE],m_tempBuffer,m_bufferSize-MD5_CHECKSUM_SIZE)) + { + memcpy(&m_dataBuffer,&m_tempBuffer[256],sizeof(m_dataBuffer)); + if(m_dataBuffer.m_headerId!=SAVELOAD_HEADERID) + { + ASSERT(!"YOUR MEMCARD SAVE IS OUT OF DATE! PLEASE DELETE IT!"); + } + + // Loaded ok - Copy the data in + restoreData(); + ret=FINISHED_OK; + MEMCARD_DBGMSG("load ok :)"); + } + else + { + MEMCARD_DBGMSG("load failed!!!"); + ret=FAILED; + } + freeBuffer(); + + m_loading=false; + m_autoloading=false; + s_callbackEnded=false; + } + else + { + ret=IN_PROGRESS; + } + } + + return ret; +} + + +/*---------------------------------------------------------------------- + Function: + Purpose: + Params: + Returns: + ---------------------------------------------------------------------- */ +bool SaveLoadDatabase::startFormat() +{ + ASSERT(!m_saving); + ASSERT(!m_loading); + ASSERT(!m_formatting); + ASSERT(!m_autoloading); + + if(!MemCard::FormatCard(0,&callback)) + { + MEMCARD_DBGMSG("format error"); + return false; + } + +MEMCARD_DBGMSG("======= m_formatting=true"); + s_callbackEnded=false; + m_formatting=true; + return true; +} + + +/*---------------------------------------------------------------------- + Function: + Purpose: + Params: + Returns: + ---------------------------------------------------------------------- */ +int SaveLoadDatabase::getFormatStatus() +{ + int ret=INACTIVE; + + if(m_formatting) + { + if(MemCard::GetCardStatus(0)==MemCard::CS_NoCard) + { +MEMCARD_DBGMSG("======= weird card removal - bonus 50 points"); + // Card removed at weird time.. + ret=FAILED; + s_callbackEnded=false; + m_formatting=false; + } + else if(s_callbackEnded) + { + if(s_callbackStatus==MemCard::CCS_FormatCardOK) ret=FINISHED_OK; + else ret=FAILED; + +MEMCARD_DBGMSG("======= m_formatting=false"); + s_callbackEnded=false; + m_formatting=false; + } + else + { +MEMCARD_DBGMSG("======= still formatting..."); + ret=IN_PROGRESS; + } + } + return ret; +} + + + +/*---------------------------------------------------------------------- + Function: + Purpose: + Params: + Returns: + ---------------------------------------------------------------------- */ +void SaveLoadDatabase::startAutoload() +{ + MEMCARD_DBGMSG("Trying autoload.."); + m_autoloadFrameCounter=0; + m_autoloading=true; +} + + +/*---------------------------------------------------------------------- + Function: + Purpose: + Params: + Returns: + ---------------------------------------------------------------------- */ +bool SaveLoadDatabase::monitorAutoload() +{ + if(m_autoloading) + { + if(m_loading) + { + getLoadStatus(); + } + else if(m_autoloading&& + m_autoloadFrameCounter>(60*2)&& + MemCard::GetCardStatus(0)!=MemCard::CS_CardInserted) + { + if(MemCard::GetFileCountOnCard(0)) + { + startLoad(0); + } + else + { + m_autoloading=false; + } + } + m_autoloadFrameCounter++; + } + else + { + return false; + } + + return true; +} + + +/*---------------------------------------------------------------------- + Function: + Purpose: + Params: + Returns: + ---------------------------------------------------------------------- */ +void SaveLoadDatabase::createData() +{ + int i; + + // Header + m_dataBuffer.m_headerId=SAVELOAD_HEADERID; + + // System details + m_dataBuffer.m_systemDetails.m_screenOffX=VidGetXOfs(); + m_dataBuffer.m_systemDetails.m_screenOffY=VidGetYOfs(); + for(i=0;i