22
22
#include < sys/stat.h>
23
23
24
24
#include < algorithm>
25
+ #include < bitset>
25
26
#include < stdexcept>
26
27
27
28
#include " core/misc.h"
@@ -729,6 +730,7 @@ void PCSX::SIO::getMcdBlockInfo(int mcd, int block, McdBlock &info) {
729
730
730
731
info.reset ();
731
732
info.number = block;
733
+ info.mcd = mcd;
732
734
733
735
char *data = getMcdData (mcd);
734
736
uint8_t *ptr = reinterpret_cast <uint8_t *>(data) + block * MCD_BLOCK_SIZE + 2 ;
@@ -837,11 +839,12 @@ void PCSX::SIO::getMcdBlockInfo(int mcd, int block, McdBlock &info) {
837
839
uint16_t nextBlock = 0 ;
838
840
nextBlock |= directoryFrame[8 ];
839
841
nextBlock |= directoryFrame[9 ] << 8 ;
840
- info.nextBlock = nextBlock;
842
+ info.nextBlock = nextBlock == 0xffff ? - 1 : (nextBlock + 1 ) ;
841
843
842
844
// Check if the block is marked as free in the directory frame and adjust the name/filename if so
843
845
if (info.isErased ()) {
844
846
info.reset ();
847
+ info.allocState = 0xa0 ;
845
848
info.titleAscii = " Free Block" ;
846
849
info.titleSjis = " Free Block" ;
847
850
info.titleUtf8 = " Free Block" ;
@@ -862,8 +865,8 @@ char *PCSX::SIO::getMcdData(int mcd) {
862
865
863
866
// Erase a memory card block by clearing it with 0s
864
867
// mcd: The memory card we want to use (1 or 2)
865
- void PCSX::SIO::eraseMcdBlock ( int mcd, const McdBlock &block) {
866
- char *data = getMcdData (mcd);
868
+ void PCSX::SIO::eraseMcdFile ( const McdBlock &block) {
869
+ char *data = getMcdData (block. mcd );
867
870
868
871
// Set the block data to 0
869
872
const size_t offset = block.number * MCD_BLOCK_SIZE;
@@ -881,8 +884,83 @@ void PCSX::SIO::eraseMcdBlock(int mcd, const McdBlock &block) {
881
884
auto nextBlock = block.nextBlock ;
882
885
if ((nextBlock >= 1 ) && (nextBlock <= 15 )) {
883
886
McdBlock next;
884
- getMcdBlockInfo (mcd, nextBlock, next);
885
- eraseMcdBlock (mcd, next);
887
+ getMcdBlockInfo (block.mcd , nextBlock, next);
888
+ eraseMcdFile (next);
889
+ }
890
+ }
891
+
892
+ unsigned PCSX::SIO::getFreeSpace (int mcd) {
893
+ unsigned count = 0 ;
894
+ for (int i = 1 ; i < 16 ; i++) {
895
+ McdBlock block;
896
+ getMcdBlockInfo (mcd, i, block);
897
+ if (block.isErased ()) count++;
898
+ }
899
+
900
+ return count;
901
+ }
902
+
903
+ unsigned PCSX::SIO::getFileBlockCount (McdBlock block) {
904
+ if (block.isErased ()) return 0 ;
905
+
906
+ std::bitset<16 > walked;
907
+ unsigned count = 1 ;
908
+
909
+ while (true ) {
910
+ if ((block.nextBlock < 1 ) || (block.nextBlock > 15 )) return count;
911
+ if (walked.test (block.nextBlock )) return count;
912
+ walked.set (block.nextBlock );
913
+ getMcdBlockInfo (block.mcd , block.nextBlock , block);
914
+ count++;
915
+ }
916
+ }
917
+
918
+ int PCSX::SIO::findFirstFree (int mcd) {
919
+ McdBlock block;
920
+ for (int i = 1 ; i < 16 ; i++) {
921
+ getMcdBlockInfo (mcd, i, block);
922
+ if (block.isErased ()) return i;
923
+ }
924
+
925
+ return -1 ;
926
+ }
927
+
928
+ bool PCSX::SIO::copyMcdFile (McdBlock block) {
929
+ auto other = otherMcd (block);
930
+ if (getFreeSpace (other) < getFileBlockCount (block)) return false ;
931
+ const auto const data = getMcdData (block);
932
+ const auto otherData = getMcdData (other);
933
+
934
+ std::bitset<16 > walked;
935
+ int prevBlock = -1 ;
936
+
937
+ while (true ) {
938
+ int dstBlock = findFirstFree (other);
939
+ if (dstBlock < 1 || dstBlock > 16 ) throw std::runtime_error (" Inconsistent memory card state" );
940
+
941
+ // copy block data
942
+ size_t srcOffset = block.number * MCD_BLOCK_SIZE;
943
+ size_t dstOffset = dstBlock * MCD_BLOCK_SIZE;
944
+ std::memcpy (otherData + dstOffset, data + srcOffset, MCD_BLOCK_SIZE);
945
+
946
+ // copy directory entry
947
+ srcOffset = block.number * MCD_SECT_SIZE;
948
+ dstOffset = dstBlock * MCD_SECT_SIZE;
949
+ std::memcpy (otherData + dstOffset, data + srcOffset, MCD_SECT_SIZE);
950
+
951
+ // Fix up the corresponding directory frame in block 0.
952
+ if (prevBlock != -1 ) {
953
+ const auto frame = reinterpret_cast <uint8_t *>(otherData) + prevBlock * MCD_SECT_SIZE;
954
+ uint8_t crcFix = frame[8 ] ^ (dstBlock - 1 );
955
+ frame[8 ] = dstBlock - 1 ;
956
+ frame[0x7f ] ^= crcFix;
957
+ }
958
+ prevBlock = dstBlock;
959
+ if (block.nextBlock == -1 ) return true ;
960
+ if ((block.nextBlock < 1 ) || (block.nextBlock > 15 )) return false ;
961
+ if (walked.test (block.nextBlock )) return false ;
962
+ walked.set (block.nextBlock );
963
+ getMcdBlockInfo (block.mcd , block.nextBlock , block);
886
964
}
887
965
}
888
966
0 commit comments