Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Sign in
Toggle navigation
Menu
Open sidebar
Libretro
fbalpha
Commits
434a58aa
Commit
434a58aa
authored
Oct 11, 2020
by
Libretro-Admin
Browse files
Update
parent
6cf2796b
Pipeline
#1062
failed with stages
in 1 minute and 54 seconds
Changes
1
Pipelines
1
Hide whitespace changes
Inline
Side-by-side
src/burner/state.cpp
deleted
100644 → 0
View file @
6cf2796b
// Driver Save State module
#include "burner.h"
// from dynhuff.cpp
INT32
FreezeDecode
(
UINT8
**
buffer
,
INT32
*
size
);
INT32
UnfreezeDecode
(
const
UINT8
*
buffer
,
INT32
size
);
INT32
FreezeEncode
(
UINT8
**
buffer
,
INT32
*
size
);
INT32
UnfreezeEncode
(
const
UINT8
*
buffer
,
INT32
size
);
// from replay.cpp
INT32
FreezeInput
(
UINT8
**
buf
,
int
*
size
);
INT32
UnfreezeInput
(
const
UINT8
*
buf
,
INT32
size
);
extern
INT32
nReplayStatus
;
extern
bool
bReplayReadOnly
;
extern
INT32
nReplayUndoCount
;
extern
UINT32
nReplayCurrentFrame
;
extern
UINT32
nStartFrame
;
// If bAll=0 save/load all non-volatile ram to .fs
// If bAll=1 save/load all ram to .fs
// ------------ State len --------------------
static
INT32
nTotalLen
=
0
;
static
INT32
__cdecl
StateLenAcb
(
struct
BurnArea
*
pba
)
{
nTotalLen
+=
pba
->
nLen
;
return
0
;
}
static
INT32
StateInfo
(
int
*
pnLen
,
int
*
pnMinVer
,
INT32
bAll
)
{
INT32
nMin
=
0
;
nTotalLen
=
0
;
BurnAcb
=
StateLenAcb
;
BurnAreaScan
(
ACB_NVRAM
,
&
nMin
);
// Scan nvram
if
(
bAll
)
{
INT32
m
;
BurnAreaScan
(
ACB_MEMCARD
,
&
m
);
// Scan memory card
if
(
m
>
nMin
)
{
// Up the minimum, if needed
nMin
=
m
;
}
BurnAreaScan
(
ACB_VOLATILE
,
&
m
);
// Scan volatile ram
if
(
m
>
nMin
)
{
// Up the minimum, if needed
nMin
=
m
;
}
}
*
pnLen
=
nTotalLen
;
*
pnMinVer
=
nMin
;
return
0
;
}
// State load
INT32
BurnStateLoadEmbed
(
FILE
*
fp
,
INT32
nOffset
,
INT32
bAll
,
INT32
(
*
pLoadGame
)())
{
const
char
*
szHeader
=
"FS1 "
;
// Chunk identifier
INT32
nLen
=
0
;
INT32
nMin
=
0
,
nFileVer
=
0
,
nFileMin
=
0
;
INT32
t1
=
0
,
t2
=
0
;
char
ReadHeader
[
4
];
char
szForName
[
33
];
INT32
nChunkSize
=
0
;
UINT8
*
Def
=
NULL
;
INT32
nDefLen
=
0
;
// Deflated version
INT32
nRet
=
0
;
if
(
nOffset
>=
0
)
{
fseek
(
fp
,
nOffset
,
SEEK_SET
);
}
else
{
if
(
nOffset
==
-
2
)
{
fseek
(
fp
,
0
,
SEEK_END
);
}
else
{
fseek
(
fp
,
0
,
SEEK_CUR
);
}
}
memset
(
ReadHeader
,
0
,
4
);
fread
(
ReadHeader
,
1
,
4
,
fp
);
// Read identifier
if
(
memcmp
(
ReadHeader
,
szHeader
,
4
))
{
// Not the right file type
return
-
2
;
}
fread
(
&
nChunkSize
,
1
,
4
,
fp
);
if
(
nChunkSize
<=
0x40
)
{
// Not big enough
return
-
1
;
}
INT32
nChunkData
=
ftell
(
fp
);
fread
(
&
nFileVer
,
1
,
4
,
fp
);
// Version of FB that this file was saved from
fread
(
&
t1
,
1
,
4
,
fp
);
// Min version of FB that NV data will work with
fread
(
&
t2
,
1
,
4
,
fp
);
// Min version of FB that All data will work with
if
(
bAll
)
{
// Get the min version number which applies to us
nFileMin
=
t2
;
}
else
{
nFileMin
=
t1
;
}
fread
(
&
nDefLen
,
1
,
4
,
fp
);
// Get the size of the compressed data block
memset
(
szForName
,
0
,
sizeof
(
szForName
));
fread
(
szForName
,
1
,
32
,
fp
);
if
(
nBurnVer
<
nFileMin
)
{
// Error - emulator is too old to load this state
return
-
5
;
}
// Check the game the savestate is for, and load it if needed.
{
bool
bLoadGame
=
false
;
if
(
nBurnDrvActive
<
nBurnDrvCount
)
{
if
(
strcmp
(
szForName
,
BurnDrvGetTextA
(
DRV_NAME
)))
{
// The save state is for the wrong game
bLoadGame
=
true
;
}
}
else
{
// No game loaded
bLoadGame
=
true
;
}
if
(
bLoadGame
)
{
UINT32
nCurrentGame
=
nBurnDrvActive
;
UINT32
i
;
for
(
i
=
0
;
i
<
nBurnDrvCount
;
i
++
)
{
nBurnDrvActive
=
i
;
if
(
strcmp
(
szForName
,
BurnDrvGetTextA
(
DRV_NAME
))
==
0
)
{
break
;
}
}
if
(
i
==
nBurnDrvCount
)
{
nBurnDrvActive
=
nCurrentGame
;
return
-
3
;
}
else
{
if
(
nCurrentGame
!=
nBurnDrvActive
)
{
INT32
nOldActive
=
nBurnDrvActive
;
// Exit current game if loading a state from another game
nBurnDrvActive
=
nCurrentGame
;
DrvExit
();
nBurnDrvActive
=
nOldActive
;
}
if
(
pLoadGame
==
NULL
)
{
return
-
1
;
}
if
(
pLoadGame
())
{
return
-
1
;
}
}
}
}
StateInfo
(
&
nLen
,
&
nMin
,
bAll
);
if
(
nLen
<=
0
)
{
// No memory to load
return
-
1
;
}
// Check if the save state is okay
if
(
nFileVer
<
nMin
)
{
// Error - this state is too old and cannot be loaded.
return
-
4
;
}
fseek
(
fp
,
nChunkData
+
0x30
,
SEEK_SET
);
// Read current frame
fread
(
&
nReplayCurrentFrame
,
1
,
4
,
fp
);
nCurrentFrame
=
nStartFrame
+
nReplayCurrentFrame
;
fseek
(
fp
,
0x0C
,
SEEK_CUR
);
// Move file pointer to the start of the compressed block
Def
=
(
UINT8
*
)
malloc
(
nDefLen
);
if
(
Def
==
NULL
)
{
return
-
1
;
}
memset
(
Def
,
0
,
nDefLen
);
fread
(
Def
,
1
,
nDefLen
,
fp
);
// Read in deflated block
nRet
=
BurnStateDecompress
(
Def
,
nDefLen
,
bAll
);
// Decompress block into driver
free
(
Def
);
// free deflated block
fseek
(
fp
,
nChunkData
+
nChunkSize
,
SEEK_SET
);
if
(
nRet
==
0
)
{
// Force the palette to recalculate on state load
BurnRecalcPal
();
}
if
(
nRet
)
{
return
-
1
;
}
else
{
return
0
;
}
}
// State load
INT32
BurnStateLoad
(
TCHAR
*
szName
,
INT32
bAll
,
INT32
(
*
pLoadGame
)())
{
const
char
szHeader
[]
=
"FB1 "
;
// File identifier
char
szReadHeader
[
4
]
=
""
;
INT32
nRet
=
0
;
FILE
*
fp
=
_tfopen
(
szName
,
_T
(
"rb"
));
if
(
fp
==
NULL
)
{
return
1
;
}
fread
(
szReadHeader
,
1
,
4
,
fp
);
// Read identifier
if
(
memcmp
(
szReadHeader
,
szHeader
,
4
)
==
0
)
{
// Check filetype
nRet
=
BurnStateLoadEmbed
(
fp
,
-
1
,
bAll
,
pLoadGame
);
}
// load movie extra info
if
(
nReplayStatus
)
{
const
char
szMovieExtra
[]
=
"MOV "
;
const
char
szDecodeChunk
[]
=
"HUFF"
;
const
char
szInputChunk
[]
=
"INP "
;
INT32
nChunkSize
;
UINT8
*
buf
=
NULL
;
do
{
fread
(
szReadHeader
,
1
,
4
,
fp
);
if
(
memcmp
(
szReadHeader
,
szMovieExtra
,
4
))
{
nRet
=
-
1
;
break
;
}
fread
(
&
nChunkSize
,
1
,
4
,
fp
);
fread
(
szReadHeader
,
1
,
4
,
fp
);
if
(
memcmp
(
szReadHeader
,
szDecodeChunk
,
4
))
{
nRet
=
-
1
;
break
;
}
fread
(
&
nChunkSize
,
1
,
4
,
fp
);
if
((
buf
=
(
UINT8
*
)
malloc
(
nChunkSize
))
==
NULL
)
{
nRet
=
-
1
;
break
;
}
fread
(
buf
,
1
,
nChunkSize
,
fp
);
INT32
ret
=-
1
;
if
(
nReplayStatus
==
1
)
{
ret
=
UnfreezeEncode
(
buf
,
nChunkSize
);
++
nReplayUndoCount
;
}
else
if
(
nReplayStatus
==
2
)
{
ret
=
UnfreezeDecode
(
buf
,
nChunkSize
);
}
if
(
ret
)
{
nRet
=
-
1
;
break
;
}
free
(
buf
);
buf
=
NULL
;
fread
(
szReadHeader
,
1
,
4
,
fp
);
if
(
memcmp
(
szReadHeader
,
szInputChunk
,
4
))
{
nRet
=
-
1
;
break
;
}
fread
(
&
nChunkSize
,
1
,
4
,
fp
);
if
((
buf
=
(
UINT8
*
)
malloc
(
nChunkSize
))
==
NULL
)
{
nRet
=
-
1
;
break
;
}
fread
(
buf
,
1
,
nChunkSize
,
fp
);
if
(
UnfreezeInput
(
buf
,
nChunkSize
))
{
nRet
=
-
1
;
break
;
}
free
(
buf
);
buf
=
NULL
;
}
while
(
false
);
if
(
buf
)
free
(
buf
);
}
fclose
(
fp
);
if
(
nRet
<
0
)
{
return
-
nRet
;
}
else
{
return
0
;
}
}
// Write a savestate as a chunk of an "FB1 " file
// nOffset is the absolute offset from the beginning of the file
// -1: Append at current position
// -2: Append at EOF
INT32
BurnStateSaveEmbed
(
FILE
*
fp
,
INT32
nOffset
,
INT32
bAll
)
{
const
char
*
szHeader
=
"FS1 "
;
// Chunk identifier
INT32
nLen
=
0
;
INT32
nNvMin
=
0
,
nAMin
=
0
;
INT32
nZero
=
0
;
char
szGame
[
33
];
UINT8
*
Def
=
NULL
;
INT32
nDefLen
=
0
;
// Deflated version
INT32
nRet
=
0
;
if
(
fp
==
NULL
)
{
return
-
1
;
}
StateInfo
(
&
nLen
,
&
nNvMin
,
0
);
// Get minimum version for NV part
nAMin
=
nNvMin
;
if
(
bAll
)
{
// Get minimum version for All data
StateInfo
(
&
nLen
,
&
nAMin
,
1
);
}
if
(
nLen
<=
0
)
{
// No memory to save
return
-
1
;
}
if
(
nOffset
>=
0
)
{
fseek
(
fp
,
nOffset
,
SEEK_SET
);
}
else
{
if
(
nOffset
==
-
2
)
{
fseek
(
fp
,
0
,
SEEK_END
);
}
else
{
fseek
(
fp
,
0
,
SEEK_CUR
);
}
}
fwrite
(
szHeader
,
1
,
4
,
fp
);
// Chunk identifier
INT32
nSizeOffset
=
ftell
(
fp
);
// Reserve space to write the size of this chunk
fwrite
(
&
nZero
,
1
,
4
,
fp
);
//
fwrite
(
&
nBurnVer
,
1
,
4
,
fp
);
// Version of FB this was saved from
fwrite
(
&
nNvMin
,
1
,
4
,
fp
);
// Min version of FB NV data will work with
fwrite
(
&
nAMin
,
1
,
4
,
fp
);
// Min version of FB All data will work with
fwrite
(
&
nZero
,
1
,
4
,
fp
);
// Reserve space to write the compressed data size
memset
(
szGame
,
0
,
sizeof
(
szGame
));
// Game name
sprintf
(
szGame
,
"%.32s"
,
BurnDrvGetTextA
(
DRV_NAME
));
//
fwrite
(
szGame
,
1
,
32
,
fp
);
//
nReplayCurrentFrame
=
GetCurrentFrame
()
-
nStartFrame
;
fwrite
(
&
nReplayCurrentFrame
,
1
,
4
,
fp
);
// Current frame
fwrite
(
&
nZero
,
1
,
4
,
fp
);
// Reserved
fwrite
(
&
nZero
,
1
,
4
,
fp
);
//
fwrite
(
&
nZero
,
1
,
4
,
fp
);
//
nRet
=
BurnStateCompress
(
&
Def
,
&
nDefLen
,
bAll
);
// Compress block from driver and return deflated buffer
if
(
Def
==
NULL
)
{
return
-
1
;
}
nRet
=
fwrite
(
Def
,
1
,
nDefLen
,
fp
);
// Write block to disk
free
(
Def
);
// free deflated block and close file
if
(
nRet
!=
nDefLen
)
{
// error writing block to disk
return
-
1
;
}
if
(
nDefLen
&
3
)
{
// Chunk size must be a multiple of 4
fwrite
(
&
nZero
,
1
,
4
-
(
nDefLen
&
3
),
fp
);
// Pad chunk if needed
}
fseek
(
fp
,
nSizeOffset
+
0x10
,
SEEK_SET
);
// Write size of the compressed data
fwrite
(
&
nDefLen
,
1
,
4
,
fp
);
//
nDefLen
=
(
nDefLen
+
0x43
)
&
~
3
;
// Add for header size and align
fseek
(
fp
,
nSizeOffset
,
SEEK_SET
);
// Write size of the chunk
fwrite
(
&
nDefLen
,
1
,
4
,
fp
);
//
fseek
(
fp
,
0
,
SEEK_END
);
// Set file pointer to the end of the chunk
return
nDefLen
;
}
#ifdef BUILD_WIN32
INT32
FileExists
(
const
TCHAR
*
fileName
)
{
DWORD
dwAttrib
=
GetFileAttributes
(
fileName
);
return
(
dwAttrib
!=
INVALID_FILE_ATTRIBUTES
&&
!
(
dwAttrib
&
FILE_ATTRIBUTE_DIRECTORY
));
}
#endif
#define MAX_STATEBACKUPS 10
// SaveState Undo - restores the last savestate backup file. Windows-only at the moment.
INT32
BurnStateUNDO
(
TCHAR
*
szName
)
{
#ifdef BUILD_WIN32
/*
Savestate Undo
derp.fs.backup0 -> derp.fs
derp.fs.backup1 -> derp.fs.backup0
derp.fs.backup2 -> derpfs.backup1
derp.fs.backup3 -> derpfs.backup2
*/
INT32
cantundo
=
0
;
for
(
INT32
i
=
0
;
i
<=
MAX_STATEBACKUPS
;
i
++
)
{
TCHAR
szBackupNameTo
[
1024
]
=
_T
(
""
);
TCHAR
szBackupNameFrom
[
1024
]
=
_T
(
""
);
TCHAR
szBackupNamePrev
[
1024
]
=
_T
(
""
);
if
(
i
==
0
)
{
_stprintf
(
szBackupNameTo
,
_T
(
"%s.UNDO"
),
szName
);
// game.fs -> game.fs.UNDO
_stprintf
(
szBackupNamePrev
,
_T
(
"%s.backup0"
),
szName
);
if
(
FileExists
(
szName
)
&&
FileExists
(
szBackupNamePrev
))
{
DeleteFileW
(
szBackupNameTo
);
MoveFileW
(
szName
,
szBackupNameTo
);
}
else
{
cantundo
=
1
;
}
_stprintf
(
szBackupNameTo
,
_T
(
"%s"
),
szName
);
// game.fs
}
else
{
_stprintf
(
szBackupNameTo
,
_T
(
"%s.backup%d"
),
szName
,
i
-
1
);
//game.fs.backup0
}
_stprintf
(
szBackupNameFrom
,
_T
(
"%s.backup%d"
),
szName
,
i
);
//game.fs.backup1
//bprintf(0, _T("%d: %s -> %s\n"), i, szBackupNameFrom, szBackupNameTo);
MoveFileW
(
szBackupNameFrom
,
szBackupNameTo
);
}
return
cantundo
;
#else
return
0
;
#endif
}
// State save
INT32
BurnStateSave
(
TCHAR
*
szName
,
INT32
bAll
)
{
const
char
szHeader
[]
=
"FB1 "
;
// File identifier
INT32
nLen
=
0
,
nVer
=
0
;
INT32
nRet
=
0
;
if
(
bAll
)
{
// Get amount of data
StateInfo
(
&
nLen
,
&
nVer
,
1
);
}
else
{
StateInfo
(
&
nLen
,
&
nVer
,
0
);
}
if
(
nLen
<=
0
)
{
// No data, so exit without creating a savestate
return
0
;
// Don't return an error code
}
#ifdef BUILD_WIN32
/*
Save State backups - used in conjunction with BurnStateUNDO();
derp.fs -> derp.fs.backup
derp.fs.backup -> derp.fs.backup1
derp.fs.backup1 -> derpfs.backup2
derp.fs.backup3 -> derpfs.backup4
*/
if
(
_tcsstr
(
szName
,
_T
(
" slot "
)))
{
for
(
INT32
i
=
MAX_STATEBACKUPS
;
i
>=
0
;
i
--
)
{
TCHAR
szBackupNameTo
[
1024
]
=
_T
(
""
);
TCHAR
szBackupNameFrom
[
1024
]
=
_T
(
""
);
_stprintf
(
szBackupNameTo
,
_T
(
"%s.backup%d"
),
szName
,
i
+
1
);
_stprintf
(
szBackupNameFrom
,
_T
(
"%s.backup%d"
),
szName
,
i
);
if
(
i
==
MAX_STATEBACKUPS
)
{
DeleteFileW
(
szBackupNameFrom
);
// make sure there is only MAX_STATEBACKUPS :)
}
else
{
MoveFileW
(
szBackupNameFrom
,
szBackupNameTo
);
//derp.fs.backup0 -> derp.fs.backup1
if
(
i
==
0
)
{
MoveFileW
(
szName
,
szBackupNameFrom
);
//derp.fs -> derp.fs.backup0
}
}
}
}
#endif
FILE
*
fp
=
_tfopen
(
szName
,
_T
(
"wb"
));
if
(
fp
==
NULL
)
{
return
1
;
}
fwrite
(
&
szHeader
,
1
,
4
,
fp
);
nRet
=
BurnStateSaveEmbed
(
fp
,
-
1
,
bAll
);
// save movie extra info
if
(
nReplayStatus
)
{
UINT8
*
huff_buf
=
NULL
;
INT32
huff_size
;
UINT8
*
input_buf
=
NULL
;
INT32
input_size
;
INT32
ret
=-
1
;
if
(
nReplayStatus
==
1
)
{
ret
=
FreezeEncode
(
&
huff_buf
,
&
huff_size
);
}
else
if
(
nReplayStatus
==
2
)
{
ret
=
FreezeDecode
(
&
huff_buf
,
&
huff_size
);
}
if
(
!
ret
&&
!
FreezeInput
(
&
input_buf
,
&
input_size
))
{
const
char
szMovieExtra
[]
=
"MOV "
;
const
char
szDecodeChunk
[]
=
"HUFF"
;
const
char
szInputChunk
[]
=
"INP "
;
INT32
nZero
=
0
;
INT32
nAlign
=
0
;
INT32
nChkLen
=
0
;
INT32
nMovChunkLen
=
0
;
fwrite
(
szMovieExtra
,
1
,
4
,
fp
);
INT32
nSizeOffset
=
ftell
(
fp
);
fwrite
(
&
nZero
,
1
,
4
,
fp
);
// Leave room for the chunk size
nMovChunkLen
=
0
;
// write Decode block
nAlign
=
(
huff_size
&
3
)
?
(
4
-
(
huff_size
&
3
))
:
0
;
nChkLen
=
huff_size
+
nAlign
;
fwrite
(
szDecodeChunk
,
1
,
4
,
fp
);
fwrite
(
&
nChkLen
,
1
,
4
,
fp
);
fwrite
(
huff_buf
,
1
,
huff_size
,
fp
);
if
(
nAlign
)
{
fwrite
(
&
nZero
,
1
,
nAlign
,
fp
);
}
nMovChunkLen
+=
nChkLen
+
8
;
// write Input block
nAlign
=
(
input_size
&
3
)
?
(
4
-
(
input_size
&
3
))
:
0
;
nChkLen
=
input_size
+
nAlign
;
fwrite
(
szInputChunk
,
1
,
4
,
fp
);
fwrite
(
&
nChkLen
,
1
,
4
,
fp
);
fwrite
(
input_buf
,
1
,
input_size
,
fp
);
if
(
nAlign
)
{
fwrite
(
&
nZero
,
1
,
nAlign
,
fp
);
}
nMovChunkLen
+=
nChkLen
+
8
;
fseek
(
fp
,
nSizeOffset
,
SEEK_SET
);
fwrite
(
&
nMovChunkLen
,
1
,
4
,
fp
);
fseek
(
fp
,
nMovChunkLen
,
SEEK_CUR
);
}
if
(
huff_buf
)
free
(
huff_buf
);
if
(
input_buf
)
free
(
input_buf
);
}
fclose
(
fp
);
if
(
nRet
<
0
)
{
return
1
;
}
else
{
return
0
;
}
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment