2015-11-15 10:27:00 +00:00
using System ;
using System.Collections.Generic ;
using System.Globalization ;
using System.IO ;
using System.Linq ;
using System.Text ;
using BizHawk.Common ;
namespace BizHawk.Client.Common
{
public static class StringLogUtil
{
2016-02-10 07:09:43 +00:00
public static bool DefaultToDisk ;
public static bool DefaultToAWE ;
2015-11-15 10:27:00 +00:00
public static IStringLog MakeStringLog ( )
{
if ( DefaultToDisk )
2016-02-10 07:09:43 +00:00
return new StreamStringLog ( true ) ;
else if ( DefaultToAWE )
return new StreamStringLog ( false ) ;
2015-11-15 10:27:00 +00:00
else 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 ) ;
}
class ListStringLog : List < string > , IStringLog
{
public IStringLog Clone ( )
{
ListStringLog ret = new ListStringLog ( ) ;
ret . AddRange ( this ) ;
return ret ;
}
public void Dispose ( ) { }
}
/// <summary>
/// A dumb-ish 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.
/// It should be faster than those alternatives, but wasteful of disk space.
/// It should also be easier to add new IList<string>-like methods than dealing with a database
/// </summary>
2016-02-10 07:09:43 +00:00
class StreamStringLog : IStringLog
2015-11-15 10:27:00 +00:00
{
List < long > Offsets = new List < long > ( ) ;
long cursor = 0 ;
BinaryWriter bw ;
2016-02-10 07:09:43 +00:00
BinaryReader br ;
bool mDisk ;
Stream stream ;
public StreamStringLog ( bool disk )
{
mDisk = disk ;
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 ( ) ;
}
2015-11-15 10:27:00 +00:00
bw = new BinaryWriter ( stream ) ;
br = new BinaryReader ( stream ) ;
}
public IStringLog Clone ( )
2016-02-10 07:09:43 +00:00
{
StreamStringLog ret = new StreamStringLog ( mDisk ) ; //doesnt necessarily make sense to copy the mDisk value, they could be designated for different targets...
2015-11-15 10:27:00 +00:00
for ( int i = 0 ; i < Count ; i + + )
ret . Add ( this [ i ] ) ;
return ret ;
}
public void Dispose ( )
{
stream . Dispose ( ) ;
}
public int Count { get { return Offsets . Count ; } }
public void Clear ( )
{
stream . SetLength ( 0 ) ;
Offsets . Clear ( ) ;
cursor = 0 ;
}
public void Add ( string str )
{
Offsets . Add ( stream . Position ) ;
bw . Write ( str ) ;
bw . Flush ( ) ;
}
public void RemoveAt ( int index )
{
Offsets . RemoveAt ( index ) ;
//no garbage collection in the disk file... oh well.
}
public string this [ int index ]
{
get
{
stream . Position = Offsets [ index ] ;
return br . ReadString ( ) ;
}
set
{
stream . Position = stream . Length ;
Offsets [ index ] = stream . Position ;
bw . Write ( value ) ;
bw . Flush ( ) ;
}
}
public void Insert ( int index , string val )
{
Offsets . Insert ( index , stream . Position ) ;
bw . Write ( val ) ;
bw . Flush ( ) ;
}
public void InsertRange ( int index , IEnumerable < string > collection )
{
foreach ( var item in collection )
Insert ( index + + , item ) ;
}
public void AddRange ( IEnumerable < string > collection )
{
foreach ( var item in collection )
Add ( item ) ;
}
class Enumerator : IEnumerator < string >
{
2016-02-10 07:09:43 +00:00
public StreamStringLog log ;
2016-01-11 04:45:43 +00:00
int index = - 1 ;
2015-11-15 10:27:00 +00:00
public string Current { get { return log [ index ] ; } }
object System . Collections . IEnumerator . Current { get { return log [ index ] ; } }
bool System . Collections . IEnumerator . MoveNext ( )
{
index + + ;
if ( index > = log . Count )
{
index = log . Count ;
return false ;
}
return true ;
}
2016-01-11 04:45:43 +00:00
void System . Collections . IEnumerator . Reset ( ) { index = - 1 ; }
2015-11-15 10:27:00 +00:00
public void Dispose ( ) { }
}
IEnumerator < string > IEnumerable < string > . GetEnumerator ( )
{
return new Enumerator ( ) { log = this } ;
}
System . Collections . IEnumerator System . Collections . IEnumerable . GetEnumerator ( )
{
return new Enumerator ( ) { log = this } ;
}
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 ] ;
}
}
}