Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
alexbevi
GitHub Repository: alexbevi/BizHawk
Path: blob/master/BizHawk.Client.Common/movie/bk2/StringLogs.cs
2 views
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
	{
		public static bool DefaultToDisk;
		public static bool DefaultToAWE;
		public static IStringLog MakeStringLog()
		{
			if (DefaultToDisk)
				return new StreamStringLog(true);
			else if(DefaultToAWE)
				return new StreamStringLog(false);
			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>
	class StreamStringLog : IStringLog
	{
		List<long> Offsets = new List<long>();
		long cursor = 0;
		BinaryWriter bw;
		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();
			}
			bw = new BinaryWriter(stream);
			br = new BinaryReader(stream);
		}

		public IStringLog Clone()
		{
			StreamStringLog ret = new StreamStringLog(mDisk); //doesnt necessarily make sense to copy the mDisk value, they could be designated for different targets...
			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>
		{
			public StreamStringLog log;
			int index = -1;
			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;
			}
			void System.Collections.IEnumerator.Reset() { index = -1; }
			
			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];
		}
	}
}