misc/libphysfs/lzma/CS/7zip/Compress/LzmaAlone/LzmaAlone.cs
author nemo
Mon, 10 Apr 2017 12:06:43 -0400
changeset 12213 bb5522e88ab2
permissions -rw-r--r--
bulk copy of latest physfs to our misc/libphysfs since this seems to fix an off-by-1 error reliably hit in readln read of 1 byte probably introduced in the addition of the buffered read. Whether this is excessive or whether libphysfs should even be maintained by us is another matter. But at least we shouldn't crash

using System;
using System.IO;
namespace SevenZip
{
	using CommandLineParser;
	
	public class CDoubleStream: Stream
	{
		public System.IO.Stream s1;
		public System.IO.Stream s2;
		public int fileIndex;
		public long skipSize;
		
		public override bool CanRead { get { return true; }}
		public override bool CanWrite { get { return false; }}
		public override bool CanSeek { get { return false; }}
		public override long Length { get { return s1.Length + s2.Length - skipSize; } }
		public override long Position
		{
			get { return 0;	}
			set { }
		}
		public override void Flush() { }
		public override int Read(byte[] buffer, int offset, int count) 
		{
			int numTotal = 0;
			while (count > 0)
			{
				if (fileIndex == 0)
				{
					int num = s1.Read(buffer, offset, count);
					offset += num;
					count -= num;
					numTotal += num;
					if (num == 0)
						fileIndex++;
				}
				if (fileIndex == 1)
				{
					numTotal += s2.Read(buffer, offset, count);
					return numTotal;
				}
			}
			return numTotal;
		}
		public override void Write(byte[] buffer, int offset, int count)
		{
			throw (new Exception("can't Write"));
		}
		public override long Seek(long offset, System.IO.SeekOrigin origin)
		{
			throw (new Exception("can't Seek"));
		}
		public override void SetLength(long value)
		{
			throw (new Exception("can't SetLength"));
		}
	}
	
	class LzmaAlone
	{
		enum Key
		{
			Help1 = 0,
			Help2,
			Mode,
			Dictionary,
			FastBytes,
			LitContext,
			LitPos,
			PosBits,
			MatchFinder,
			EOS,
			StdIn,
			StdOut,
			Train
		};

		static void PrintHelp()
		{
			System.Console.WriteLine("\nUsage:  LZMA <e|d> [<switches>...] inputFile outputFile\n" +
				"  e: encode file\n" +
				"  d: decode file\n" +
				"  b: Benchmark\n" +
				"<Switches>\n" +
				// "  -a{N}:  set compression mode - [0, 1], default: 1 (max)\n" +
				"  -d{N}:  set dictionary - [0, 29], default: 23 (8MB)\n" +
				"  -fb{N}: set number of fast bytes - [5, 273], default: 128\n" +
				"  -lc{N}: set number of literal context bits - [0, 8], default: 3\n" +
				"  -lp{N}: set number of literal pos bits - [0, 4], default: 0\n" +
				"  -pb{N}: set number of pos bits - [0, 4], default: 2\n" +
				"  -mf{MF_ID}: set Match Finder: [bt2, bt4], default: bt4\n" +
				"  -eos:   write End Of Stream marker\n"
				// + "  -si:    read data from stdin\n"
				// + "  -so:    write data to stdout\n"
				);
		}

		static bool GetNumber(string s, out Int32 v)
		{
			v = 0;
			for (int i = 0; i < s.Length; i++)
			{
				char c = s[i];
				if (c < '0' || c > '9')
					return false;
				v *= 10;
				v += (Int32)(c - '0');
			}
			return true;
		}

		static int IncorrectCommand()
		{
			throw (new Exception("Command line error"));
			// System.Console.WriteLine("\nCommand line error\n");
			// return 1;
		}
		static int Main2(string[] args)
		{
			System.Console.WriteLine("\nLZMA# 4.49 Copyright (c) 1999-2007 Igor Pavlov  2006-07-05\n");

			if (args.Length == 0)
			{
				PrintHelp();
				return 0;
			}

			SwitchForm[] kSwitchForms = new SwitchForm[13];
			int sw = 0;
			kSwitchForms[sw++] = new SwitchForm("?", SwitchType.Simple, false);
			kSwitchForms[sw++] = new SwitchForm("H", SwitchType.Simple, false);
			kSwitchForms[sw++] = new SwitchForm("A", SwitchType.UnLimitedPostString, false, 1);
			kSwitchForms[sw++] = new SwitchForm("D", SwitchType.UnLimitedPostString, false, 1);
			kSwitchForms[sw++] = new SwitchForm("FB", SwitchType.UnLimitedPostString, false, 1);
			kSwitchForms[sw++] = new SwitchForm("LC", SwitchType.UnLimitedPostString, false, 1);
			kSwitchForms[sw++] = new SwitchForm("LP", SwitchType.UnLimitedPostString, false, 1);
			kSwitchForms[sw++] = new SwitchForm("PB", SwitchType.UnLimitedPostString, false, 1);
			kSwitchForms[sw++] = new SwitchForm("MF", SwitchType.UnLimitedPostString, false, 1);
			kSwitchForms[sw++] = new SwitchForm("EOS", SwitchType.Simple, false);
			kSwitchForms[sw++] = new SwitchForm("SI", SwitchType.Simple, false);
			kSwitchForms[sw++] = new SwitchForm("SO", SwitchType.Simple, false);
			kSwitchForms[sw++] = new SwitchForm("T", SwitchType.UnLimitedPostString, false, 1);


			Parser parser = new Parser(sw);
			try
			{
				parser.ParseStrings(kSwitchForms, args);
			}
			catch
			{
				return IncorrectCommand();
			}

			if (parser[(int)Key.Help1].ThereIs || parser[(int)Key.Help2].ThereIs)
			{
				PrintHelp();
				return 0;
			}

			System.Collections.ArrayList nonSwitchStrings = parser.NonSwitchStrings;

			int paramIndex = 0;
			if (paramIndex >= nonSwitchStrings.Count)
				return IncorrectCommand();
			string command = (string)nonSwitchStrings[paramIndex++];
			command = command.ToLower();

			bool dictionaryIsDefined = false;
			Int32 dictionary = 1 << 21;
			if (parser[(int)Key.Dictionary].ThereIs)
			{
				Int32 dicLog;
				if (!GetNumber((string)parser[(int)Key.Dictionary].PostStrings[0], out dicLog))
					IncorrectCommand();
				dictionary = (Int32)1 << dicLog;
				dictionaryIsDefined = true;
			}
			string mf = "bt4";
			if (parser[(int)Key.MatchFinder].ThereIs)
				mf = (string)parser[(int)Key.MatchFinder].PostStrings[0];
			mf = mf.ToLower();

			if (command == "b")
			{
				const Int32 kNumDefaultItereations = 10;
				Int32 numIterations = kNumDefaultItereations;
				if (paramIndex < nonSwitchStrings.Count)
					if (!GetNumber((string)nonSwitchStrings[paramIndex++], out numIterations))
						numIterations = kNumDefaultItereations;
				return LzmaBench.LzmaBenchmark(numIterations, (UInt32)dictionary);
			}

			string train = "";
			if (parser[(int)Key.Train].ThereIs)
				train = (string)parser[(int)Key.Train].PostStrings[0];

			bool encodeMode = false;
			if (command == "e")
				encodeMode = true;
			else if (command == "d")
				encodeMode = false;
			else
				IncorrectCommand();

			bool stdInMode = parser[(int)Key.StdIn].ThereIs;
			bool stdOutMode = parser[(int)Key.StdOut].ThereIs;

			Stream inStream = null;
			if (stdInMode)
			{
				throw (new Exception("Not implemeted"));
			}
			else
			{
				if (paramIndex >= nonSwitchStrings.Count)
					IncorrectCommand();
				string inputName = (string)nonSwitchStrings[paramIndex++];
				inStream = new FileStream(inputName, FileMode.Open, FileAccess.Read);
			}

			FileStream outStream = null;
			if (stdOutMode)
			{
				throw (new Exception("Not implemeted"));
			}
			else
			{
				if (paramIndex >= nonSwitchStrings.Count)
					IncorrectCommand();
				string outputName = (string)nonSwitchStrings[paramIndex++];
				outStream = new FileStream(outputName, FileMode.Create, FileAccess.Write);
			}

			FileStream trainStream = null;
			if (train.Length != 0)
				trainStream = new FileStream(train, FileMode.Open, FileAccess.Read);

			if (encodeMode)
			{
				if (!dictionaryIsDefined)
					dictionary = 1 << 23;

				Int32 posStateBits = 2;
				Int32 litContextBits = 3; // for normal files
				// UInt32 litContextBits = 0; // for 32-bit data
				Int32 litPosBits = 0;
				// UInt32 litPosBits = 2; // for 32-bit data
				Int32 algorithm = 2;
				Int32 numFastBytes = 128;

				bool eos = parser[(int)Key.EOS].ThereIs || stdInMode;

				if (parser[(int)Key.Mode].ThereIs)
					if (!GetNumber((string)parser[(int)Key.Mode].PostStrings[0], out algorithm))
						IncorrectCommand();

				if (parser[(int)Key.FastBytes].ThereIs)
					if (!GetNumber((string)parser[(int)Key.FastBytes].PostStrings[0], out numFastBytes))
						IncorrectCommand();
				if (parser[(int)Key.LitContext].ThereIs)
					if (!GetNumber((string)parser[(int)Key.LitContext].PostStrings[0], out litContextBits))
						IncorrectCommand();
				if (parser[(int)Key.LitPos].ThereIs)
					if (!GetNumber((string)parser[(int)Key.LitPos].PostStrings[0], out litPosBits))
						IncorrectCommand();
				if (parser[(int)Key.PosBits].ThereIs)
					if (!GetNumber((string)parser[(int)Key.PosBits].PostStrings[0], out posStateBits))
						IncorrectCommand();

				CoderPropID[] propIDs = 
				{
					CoderPropID.DictionarySize,
					CoderPropID.PosStateBits,
					CoderPropID.LitContextBits,
					CoderPropID.LitPosBits,
					CoderPropID.Algorithm,
					CoderPropID.NumFastBytes,
					CoderPropID.MatchFinder,
					CoderPropID.EndMarker
				};
				object[] properties = 
				{
					(Int32)(dictionary),
					(Int32)(posStateBits),
					(Int32)(litContextBits),
					(Int32)(litPosBits),
					(Int32)(algorithm),
					(Int32)(numFastBytes),
					mf,
					eos
				};

				Compression.LZMA.Encoder encoder = new Compression.LZMA.Encoder();
				encoder.SetCoderProperties(propIDs, properties);
				encoder.WriteCoderProperties(outStream);
				Int64 fileSize;
				if (eos || stdInMode)
					fileSize = -1;
				else
					fileSize = inStream.Length;
				for (int i = 0; i < 8; i++)
					outStream.WriteByte((Byte)(fileSize >> (8 * i)));
				if (trainStream != null)
				{
					CDoubleStream doubleStream = new CDoubleStream();
					doubleStream.s1 = trainStream;
					doubleStream.s2 = inStream;
					doubleStream.fileIndex = 0;
					inStream = doubleStream;
					long trainFileSize = trainStream.Length;
					doubleStream.skipSize = 0;
					if (trainFileSize > dictionary)
						doubleStream.skipSize = trainFileSize - dictionary;
					trainStream.Seek(doubleStream.skipSize, SeekOrigin.Begin);
					encoder.SetTrainSize((uint)(trainFileSize - doubleStream.skipSize));
				}
				encoder.Code(inStream, outStream, -1, -1, null);
			}
			else if (command == "d")
			{
				byte[] properties = new byte[5];
				if (inStream.Read(properties, 0, 5) != 5)
					throw (new Exception("input .lzma is too short"));
				Compression.LZMA.Decoder decoder = new Compression.LZMA.Decoder();
				decoder.SetDecoderProperties(properties);
				if (trainStream != null)
				{
					if (!decoder.Train(trainStream))
						throw (new Exception("can't train"));
				}
				long outSize = 0;
				for (int i = 0; i < 8; i++)
				{
					int v = inStream.ReadByte();
					if (v < 0)
						throw (new Exception("Can't Read 1"));
					outSize |= ((long)(byte)v) << (8 * i);
				}
				long compressedSize = inStream.Length - inStream.Position;
				decoder.Code(inStream, outStream, compressedSize, outSize, null);
			}
			else
				throw (new Exception("Command Error"));
			return 0;
		}

		[STAThread]
		static int Main(string[] args)
		{
			try
			{
				return Main2(args);
			}
			catch (Exception e)
			{
				Console.WriteLine("{0} Caught exception #1.", e);
				// throw e;
				return 1;
			}
		}
	}
}