2017-04-14 19:59:01 +00:00
using System ;
using System.Collections.Generic ;
using System.IO ;
using BizHawk.Common ;
namespace BizHawk.Client.Common
{
public static class StringLogUtil
{
2017-05-19 18:17:07 +00:00
public static bool DefaultToDisk { get ; set ; }
public static bool DefaultToAWE { get ; set ; }
2017-04-14 19:59:01 +00:00
public static IStringLog MakeStringLog ( )
{
if ( DefaultToDisk )
{
return new StreamStringLog ( true ) ;
}
if ( DefaultToAWE )
{
return new StreamStringLog ( false ) ;
}
return new ListStringLog ( ) ;
}
}
public interface IStringLog : IDisposable , IEnumerable < string >
{
void RemoveAt ( int index ) ;
int Count { get ; }
void Clear ( ) ;
void Add ( string str ) ;
string this [ int index ] { get ; set ; }
void Insert ( int index , string val ) ;
void InsertRange ( int index , IEnumerable < string > collection ) ;
void AddRange ( IEnumerable < string > collection ) ;
void RemoveRange ( int index , int count ) ;
IStringLog Clone ( ) ;
void CopyTo ( string [ ] array ) ;
void CopyTo ( int index , string [ ] array , int arrayIndex , int count ) ;
}
2017-05-17 16:53:42 +00:00
internal class ListStringLog : List < string > , IStringLog
2017-04-14 19:59:01 +00:00
{
public IStringLog Clone ( )
{
ListStringLog ret = new ListStringLog ( ) ;
ret . AddRange ( this ) ;
return ret ;
}
public void Dispose ( ) { }
}
/// <summary>
2017-05-19 18:17:07 +00:00
/// A dumb IStringLog with storage on disk with no provision for recovering lost space, except upon Clear()
/// The purpose here is to avoid having too complicated buggy logic or a dependency on SQLite or such.
2017-04-14 19:59:01 +00:00
/// It should be faster than those alternatives, but wasteful of disk space.
2017-05-18 16:36:38 +00:00
/// It should also be easier to add new IList<string>-like methods than dealing with a database
2017-04-14 19:59:01 +00:00
/// </summary>
2017-05-17 16:53:42 +00:00
internal class StreamStringLog : IStringLog
2017-04-14 19:59:01 +00:00
{
2017-05-19 18:17:07 +00:00
private readonly Stream stream ;
private readonly List < long > _offsets = new List < long > ( ) ;
private readonly BinaryWriter _bw ;
private readonly BinaryReader _br ;
private readonly bool _mDisk ;
private long _cursor ;
2017-04-14 19:59:01 +00:00
public StreamStringLog ( bool disk )
{
2017-05-19 18:17:07 +00:00
_mDisk = disk ;
2017-04-14 19:59:01 +00:00
if ( disk )
{
var path = TempFileCleaner . GetTempFilename ( "movieOnDisk" ) ;
stream = new FileStream ( path , FileMode . Create , System . Security . AccessControl . FileSystemRights . FullControl , FileShare . None , 4 * 1024 , FileOptions . DeleteOnClose ) ;
}
else
{
stream = new AWEMemoryStream ( ) ;
}
2017-05-19 18:17:07 +00:00
_bw = new BinaryWriter ( stream ) ;
_br = new BinaryReader ( stream ) ;
2017-04-14 19:59:01 +00:00
}
public IStringLog Clone ( )
{
2017-05-19 18:17:07 +00:00
StreamStringLog ret = new StreamStringLog ( _mDisk ) ; // doesnt necessarily make sense to copy the mDisk value, they could be designated for different targets...
2017-04-14 19:59:01 +00:00
for ( int i = 0 ; i < Count ; i + + )
{
ret . Add ( this [ i ] ) ;
}
return ret ;
}
public void Dispose ( )
{
stream . Dispose ( ) ;
}
2017-05-19 18:17:07 +00:00
public int Count = > _offsets . Count ;
2017-04-14 19:59:01 +00:00
2017-04-15 20:37:30 +00:00
public void Clear ( )
2017-04-14 19:59:01 +00:00
{
stream . SetLength ( 0 ) ;
2017-05-19 18:17:07 +00:00
_offsets . Clear ( ) ;
_cursor = 0 ;
2017-04-14 19:59:01 +00:00
}
public void Add ( string str )
{
stream . Position = stream . Length ;
2017-05-19 18:17:07 +00:00
_offsets . Add ( stream . Position ) ;
_bw . Write ( str ) ;
_bw . Flush ( ) ;
2017-04-14 19:59:01 +00:00
}
public void RemoveAt ( int index )
{
// no garbage collection in the disk file... oh well.
2017-05-19 18:17:07 +00:00
_offsets . RemoveAt ( index ) ;
2017-04-14 19:59:01 +00:00
}
public string this [ int index ]
{
get
{
2017-05-19 18:17:07 +00:00
stream . Position = _offsets [ index ] ;
return _br . ReadString ( ) ;
2017-04-14 19:59:01 +00:00
}
2017-05-18 16:36:38 +00:00
2017-04-14 19:59:01 +00:00
set
{
stream . Position = stream . Length ;
2017-05-19 18:17:07 +00:00
_offsets [ index ] = stream . Position ;
_bw . Write ( value ) ;
_bw . Flush ( ) ;
2017-04-14 19:59:01 +00:00
}
}
public void Insert ( int index , string val )
{
stream . Position = stream . Length ;
2017-05-19 18:17:07 +00:00
_offsets . Insert ( index , stream . Position ) ;
_bw . Write ( val ) ;
_bw . Flush ( ) ;
2017-04-14 19:59:01 +00:00
}
public void InsertRange ( int index , IEnumerable < string > collection )
{
foreach ( var item in collection )
{
2017-05-09 18:19:55 +00:00
Insert ( index + + , item ) ;
2017-04-14 19:59:01 +00:00
}
}
public void AddRange ( IEnumerable < string > collection )
{
foreach ( var item in collection )
{
Add ( item ) ;
}
}
2017-05-17 16:53:42 +00:00
private class Enumerator : IEnumerator < string >
2017-04-14 19:59:01 +00:00
{
2017-05-19 18:17:07 +00:00
public StreamStringLog Log { get ; set ; }
private int _index = - 1 ;
public string Current = > Log [ _index ] ;
object System . Collections . IEnumerator . Current = > Log [ _index ] ;
2017-04-14 19:59:01 +00:00
bool System . Collections . IEnumerator . MoveNext ( )
{
2017-05-19 18:17:07 +00:00
_index + + ;
if ( _index > = Log . Count )
2017-04-14 19:59:01 +00:00
{
2017-05-19 18:17:07 +00:00
_index = Log . Count ;
2017-04-14 19:59:01 +00:00
return false ;
}
2017-05-18 16:36:38 +00:00
2017-04-14 19:59:01 +00:00
return true ;
}
2017-05-18 16:36:38 +00:00
2017-05-19 18:17:07 +00:00
void System . Collections . IEnumerator . Reset ( ) { _index = - 1 ; }
2017-04-14 19:59:01 +00:00
public void Dispose ( ) { }
}
IEnumerator < string > IEnumerable < string > . GetEnumerator ( )
{
2017-05-19 18:17:07 +00:00
return new Enumerator { Log = this } ;
2017-04-14 19:59:01 +00:00
}
System . Collections . IEnumerator System . Collections . IEnumerable . GetEnumerator ( )
{
2017-05-19 18:17:07 +00:00
return new Enumerator { Log = this } ;
2017-04-14 19:59:01 +00:00
}
public void RemoveRange ( int index , int count )
{
int end = index + count - 1 ;
for ( int i = 0 ; i < count ; i + + )
{
RemoveAt ( end ) ;
end - - ;
}
}
public void CopyTo ( string [ ] array )
{
for ( int i = 0 ; i < Count ; i + + )
{
array [ i ] = this [ i ] ;
}
}
public void CopyTo ( int index , string [ ] array , int arrayIndex , int count )
{
for ( int i = 0 ; i < count ; i + + )
{
array [ i + arrayIndex ] = this [ index + i ] ;
}
}
}
}