282 lines
6.0 KiB
C#
282 lines
6.0 KiB
C#
using System;
|
|
using System.IO;
|
|
using System.Text;
|
|
|
|
using BizHawk.Common;
|
|
|
|
namespace BizHawk.Client.Common
|
|
{
|
|
public partial class BkmMovie
|
|
{
|
|
private int _preloadFramecount; // Not a a reliable number, used for preloading (when no log has yet been loaded), this is only for quick stat compilation for dialogs such as play movie
|
|
|
|
public void SaveAs(string path)
|
|
{
|
|
Filename = path;
|
|
if (!Loaded)
|
|
{
|
|
return;
|
|
}
|
|
|
|
var directoryInfo = new FileInfo(Filename).Directory;
|
|
if (directoryInfo != null)
|
|
{
|
|
Directory.CreateDirectory(directoryInfo.FullName);
|
|
}
|
|
|
|
Write(Filename);
|
|
}
|
|
|
|
public void Save()
|
|
{
|
|
if (!Loaded || string.IsNullOrWhiteSpace(Filename))
|
|
{
|
|
return;
|
|
}
|
|
|
|
SaveAs(Filename);
|
|
_changes = false;
|
|
}
|
|
|
|
public void SaveBackup()
|
|
{
|
|
if (!Loaded || string.IsNullOrWhiteSpace(Filename))
|
|
{
|
|
return;
|
|
}
|
|
|
|
var backupName = Filename;
|
|
backupName = backupName.Insert(Filename.LastIndexOf("."), $".{DateTime.Now:yyyy-MM-dd HH.mm.ss}");
|
|
backupName = Path.Combine(Global.Config.PathEntries["Global", "Movie backups"].Path, Path.GetFileName(backupName));
|
|
|
|
var directoryInfo = new FileInfo(backupName).Directory;
|
|
if (directoryInfo != null)
|
|
{
|
|
Directory.CreateDirectory(directoryInfo.FullName);
|
|
}
|
|
|
|
Write(backupName);
|
|
}
|
|
|
|
public bool Load(bool preload)
|
|
{
|
|
var file = new FileInfo(Filename);
|
|
|
|
if (file.Exists == false)
|
|
{
|
|
Loaded = false;
|
|
return false;
|
|
}
|
|
|
|
Header.Clear();
|
|
_log.Clear();
|
|
|
|
using (var sr = file.OpenText())
|
|
{
|
|
string line;
|
|
|
|
while ((line = sr.ReadLine()) != null)
|
|
{
|
|
if (line == "")
|
|
{
|
|
continue;
|
|
}
|
|
|
|
if (line.Contains("LoopOffset"))
|
|
{
|
|
try
|
|
{
|
|
_loopOffset = int.Parse(line.Split(new[] { ' ' }, 2)[1]);
|
|
}
|
|
catch (Exception)
|
|
{
|
|
continue;
|
|
}
|
|
}
|
|
else if (Header.ParseLineFromFile(line))
|
|
{
|
|
continue;
|
|
}
|
|
else if (line.StartsWith("|"))
|
|
{
|
|
_log.Add(line);
|
|
}
|
|
else
|
|
{
|
|
Header.Comments.Add(line);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (Header.SavestateBinaryBase64Blob != null)
|
|
{
|
|
BinarySavestate = Convert.FromBase64String(Header.SavestateBinaryBase64Blob);
|
|
}
|
|
|
|
Loaded = true;
|
|
_changes = false;
|
|
return true;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Load Header information only for displaying file information in dialogs such as play movie
|
|
/// TODO - consider not loading the SavestateBinaryBase64Blob key?
|
|
/// </summary>
|
|
public bool PreLoadHeaderAndLength(HawkFile hawkFile)
|
|
{
|
|
Loaded = false;
|
|
var file = new FileInfo(hawkFile.CanonicalFullPath);
|
|
|
|
if (file.Exists == false)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
Header.Clear();
|
|
_log.Clear();
|
|
|
|
var origStreamPosn = hawkFile.GetStream().Position;
|
|
hawkFile.GetStream().Position = 0; // Reset to start
|
|
|
|
// No using block because we're sharing the stream and need to give it back undisposed.
|
|
var sr = new StreamReader(hawkFile.GetStream());
|
|
|
|
for (;;)
|
|
{
|
|
// read to first space (key/value delimeter), or pipe, or EOF
|
|
int first = sr.Read();
|
|
|
|
if (first == -1)
|
|
{
|
|
break;
|
|
} // EOF
|
|
|
|
if (first == '|') // pipe: begin input log
|
|
{
|
|
// NOTE - this code is a bit convoluted due to its predating the basic outline of the parser which was upgraded in may 2014
|
|
var line = '|' + sr.ReadLine();
|
|
|
|
// how many bytes are left, total?
|
|
long remain = sr.BaseStream.Length - sr.BaseStream.Position;
|
|
|
|
// try to find out whether we use \r\n or \n
|
|
// but only look for 1K characters.
|
|
bool usesR = false;
|
|
for (int i = 0; i < 1024; i++)
|
|
{
|
|
int c = sr.Read();
|
|
if (c == -1)
|
|
{
|
|
break;
|
|
}
|
|
|
|
if (c == '\r')
|
|
{
|
|
usesR = true;
|
|
break;
|
|
}
|
|
|
|
if (c == '\n')
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
int lineLen = line.Length + 1; // account for \n
|
|
if (usesR)
|
|
{
|
|
lineLen++; // account for \r
|
|
}
|
|
|
|
_preloadFramecount = (int)(remain / lineLen); // length is remaining bytes / length per line
|
|
_preloadFramecount++; // account for the current line
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
// a header line. finish reading key token, to make sure it isn't one of the FORBIDDEN keys
|
|
var sbLine = new StringBuilder();
|
|
sbLine.Append((char)first);
|
|
for (;;)
|
|
{
|
|
int c = sr.Read();
|
|
if (c == -1 || c == '\n' || c == ' ')
|
|
{
|
|
break;
|
|
}
|
|
|
|
sbLine.Append((char)c);
|
|
}
|
|
|
|
var line = sbLine.ToString();
|
|
|
|
// ignore these suckers, theyre way too big for preloading. seriously, we will get out of memory errors.
|
|
var skip = line == HeaderKeys.SAVESTATEBINARYBASE64BLOB;
|
|
|
|
if (skip)
|
|
{
|
|
// skip remainder of the line
|
|
sr.DiscardBufferedData();
|
|
var stream = sr.BaseStream;
|
|
for (;;)
|
|
{
|
|
int c = stream.ReadByte();
|
|
if (c == -1 || c == '\n')
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
// proceed to next line
|
|
continue;
|
|
}
|
|
|
|
var remainder = sr.ReadLine();
|
|
sbLine.Append(' ');
|
|
sbLine.Append(remainder);
|
|
line = sbLine.ToString();
|
|
|
|
if (string.IsNullOrWhiteSpace(line) || Header.ParseLineFromFile(line))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
Header.Comments.Add(line);
|
|
}
|
|
}
|
|
|
|
hawkFile.GetStream().Position = origStreamPosn;
|
|
|
|
return true;
|
|
}
|
|
|
|
private void Write(string fn)
|
|
{
|
|
Header.SavestateBinaryBase64Blob = BinarySavestate != null
|
|
? Convert.ToBase64String(BinarySavestate)
|
|
: null;
|
|
|
|
using (var fs = new FileStream(fn, FileMode.Create, FileAccess.Write, FileShare.Read))
|
|
{
|
|
using (var sw = new StreamWriter(fs))
|
|
{
|
|
sw.Write(Header.ToString());
|
|
|
|
// TODO: clean this up
|
|
if (_loopOffset.HasValue)
|
|
{
|
|
sw.WriteLine("LoopOffset " + _loopOffset);
|
|
}
|
|
|
|
foreach (var input in _log)
|
|
{
|
|
sw.WriteLine(input);
|
|
}
|
|
}
|
|
}
|
|
|
|
_changes = false;
|
|
}
|
|
}
|
|
}
|