1using System;
2using System.IO;
3namespace SevenZip
4{
5	using CommandLineParser;
6
7	public class CDoubleStream: Stream
8	{
9		public System.IO.Stream s1;
10		public System.IO.Stream s2;
11		public int fileIndex;
12		public long skipSize;
13
14		public override bool CanRead { get { return true; }}
15		public override bool CanWrite { get { return false; }}
16		public override bool CanSeek { get { return false; }}
17		public override long Length { get { return s1.Length + s2.Length - skipSize; } }
18		public override long Position
19		{
20			get { return 0;	}
21			set { }
22		}
23		public override void Flush() { }
24		public override int Read(byte[] buffer, int offset, int count)
25		{
26			int numTotal = 0;
27			while (count > 0)
28			{
29				if (fileIndex == 0)
30				{
31					int num = s1.Read(buffer, offset, count);
32					offset += num;
33					count -= num;
34					numTotal += num;
35					if (num == 0)
36						fileIndex++;
37				}
38				if (fileIndex == 1)
39				{
40					numTotal += s2.Read(buffer, offset, count);
41					return numTotal;
42				}
43			}
44			return numTotal;
45		}
46		public override void Write(byte[] buffer, int offset, int count)
47		{
48			throw (new Exception("can't Write"));
49		}
50		public override long Seek(long offset, System.IO.SeekOrigin origin)
51		{
52			throw (new Exception("can't Seek"));
53		}
54		public override void SetLength(long value)
55		{
56			throw (new Exception("can't SetLength"));
57		}
58	}
59
60	class LzmaAlone
61	{
62		enum Key
63		{
64			Help1 = 0,
65			Help2,
66			Mode,
67			Dictionary,
68			FastBytes,
69			LitContext,
70			LitPos,
71			PosBits,
72			MatchFinder,
73			EOS,
74			StdIn,
75			StdOut,
76			Train
77		};
78
79		static void PrintHelp()
80		{
81			System.Console.WriteLine("\nUsage:  LZMA <e|d> [<switches>...] inputFile outputFile\n" +
82				"  e: encode file\n" +
83				"  d: decode file\n" +
84				"  b: Benchmark\n" +
85				"<Switches>\n" +
86				// "  -a{N}:  set compression mode - [0, 1], default: 1 (max)\n" +
87				"  -d{N}:  set dictionary - [0, 29], default: 23 (8MB)\n" +
88				"  -fb{N}: set number of fast bytes - [5, 273], default: 128\n" +
89				"  -lc{N}: set number of literal context bits - [0, 8], default: 3\n" +
90				"  -lp{N}: set number of literal pos bits - [0, 4], default: 0\n" +
91				"  -pb{N}: set number of pos bits - [0, 4], default: 2\n" +
92				"  -mf{MF_ID}: set Match Finder: [bt2, bt4], default: bt4\n" +
93				"  -eos:   write End Of Stream marker\n"
94				// + "  -si:    read data from stdin\n"
95				// + "  -so:    write data to stdout\n"
96				);
97		}
98
99		static bool GetNumber(string s, out Int32 v)
100		{
101			v = 0;
102			for (int i = 0; i < s.Length; i++)
103			{
104				char c = s[i];
105				if (c < '0' || c > '9')
106					return false;
107				v *= 10;
108				v += (Int32)(c - '0');
109			}
110			return true;
111		}
112
113		static int IncorrectCommand()
114		{
115			throw (new Exception("Command line error"));
116			// System.Console.WriteLine("\nCommand line error\n");
117			// return 1;
118		}
119		static int Main2(string[] args)
120		{
121			System.Console.WriteLine("\nLZMA# 4.61  2008-11-23\n");
122
123			if (args.Length == 0)
124			{
125				PrintHelp();
126				return 0;
127			}
128
129			SwitchForm[] kSwitchForms = new SwitchForm[13];
130			int sw = 0;
131			kSwitchForms[sw++] = new SwitchForm("?", SwitchType.Simple, false);
132			kSwitchForms[sw++] = new SwitchForm("H", SwitchType.Simple, false);
133			kSwitchForms[sw++] = new SwitchForm("A", SwitchType.UnLimitedPostString, false, 1);
134			kSwitchForms[sw++] = new SwitchForm("D", SwitchType.UnLimitedPostString, false, 1);
135			kSwitchForms[sw++] = new SwitchForm("FB", SwitchType.UnLimitedPostString, false, 1);
136			kSwitchForms[sw++] = new SwitchForm("LC", SwitchType.UnLimitedPostString, false, 1);
137			kSwitchForms[sw++] = new SwitchForm("LP", SwitchType.UnLimitedPostString, false, 1);
138			kSwitchForms[sw++] = new SwitchForm("PB", SwitchType.UnLimitedPostString, false, 1);
139			kSwitchForms[sw++] = new SwitchForm("MF", SwitchType.UnLimitedPostString, false, 1);
140			kSwitchForms[sw++] = new SwitchForm("EOS", SwitchType.Simple, false);
141			kSwitchForms[sw++] = new SwitchForm("SI", SwitchType.Simple, false);
142			kSwitchForms[sw++] = new SwitchForm("SO", SwitchType.Simple, false);
143			kSwitchForms[sw++] = new SwitchForm("T", SwitchType.UnLimitedPostString, false, 1);
144
145
146			Parser parser = new Parser(sw);
147			try
148			{
149				parser.ParseStrings(kSwitchForms, args);
150			}
151			catch
152			{
153				return IncorrectCommand();
154			}
155
156			if (parser[(int)Key.Help1].ThereIs || parser[(int)Key.Help2].ThereIs)
157			{
158				PrintHelp();
159				return 0;
160			}
161
162			System.Collections.ArrayList nonSwitchStrings = parser.NonSwitchStrings;
163
164			int paramIndex = 0;
165			if (paramIndex >= nonSwitchStrings.Count)
166				return IncorrectCommand();
167			string command = (string)nonSwitchStrings[paramIndex++];
168			command = command.ToLower();
169
170			bool dictionaryIsDefined = false;
171			Int32 dictionary = 1 << 21;
172			if (parser[(int)Key.Dictionary].ThereIs)
173			{
174				Int32 dicLog;
175				if (!GetNumber((string)parser[(int)Key.Dictionary].PostStrings[0], out dicLog))
176					IncorrectCommand();
177				dictionary = (Int32)1 << dicLog;
178				dictionaryIsDefined = true;
179			}
180			string mf = "bt4";
181			if (parser[(int)Key.MatchFinder].ThereIs)
182				mf = (string)parser[(int)Key.MatchFinder].PostStrings[0];
183			mf = mf.ToLower();
184
185			if (command == "b")
186			{
187				const Int32 kNumDefaultItereations = 10;
188				Int32 numIterations = kNumDefaultItereations;
189				if (paramIndex < nonSwitchStrings.Count)
190					if (!GetNumber((string)nonSwitchStrings[paramIndex++], out numIterations))
191						numIterations = kNumDefaultItereations;
192				return LzmaBench.LzmaBenchmark(numIterations, (UInt32)dictionary);
193			}
194
195			string train = "";
196			if (parser[(int)Key.Train].ThereIs)
197				train = (string)parser[(int)Key.Train].PostStrings[0];
198
199			bool encodeMode = false;
200			if (command == "e")
201				encodeMode = true;
202			else if (command == "d")
203				encodeMode = false;
204			else
205				IncorrectCommand();
206
207			bool stdInMode = parser[(int)Key.StdIn].ThereIs;
208			bool stdOutMode = parser[(int)Key.StdOut].ThereIs;
209
210			Stream inStream = null;
211			if (stdInMode)
212			{
213				throw (new Exception("Not implemeted"));
214			}
215			else
216			{
217				if (paramIndex >= nonSwitchStrings.Count)
218					IncorrectCommand();
219				string inputName = (string)nonSwitchStrings[paramIndex++];
220				inStream = new FileStream(inputName, FileMode.Open, FileAccess.Read);
221			}
222
223			FileStream outStream = null;
224			if (stdOutMode)
225			{
226				throw (new Exception("Not implemeted"));
227			}
228			else
229			{
230				if (paramIndex >= nonSwitchStrings.Count)
231					IncorrectCommand();
232				string outputName = (string)nonSwitchStrings[paramIndex++];
233				outStream = new FileStream(outputName, FileMode.Create, FileAccess.Write);
234			}
235
236			FileStream trainStream = null;
237			if (train.Length != 0)
238				trainStream = new FileStream(train, FileMode.Open, FileAccess.Read);
239
240			if (encodeMode)
241			{
242				if (!dictionaryIsDefined)
243					dictionary = 1 << 23;
244
245				Int32 posStateBits = 2;
246				Int32 litContextBits = 3; // for normal files
247				// UInt32 litContextBits = 0; // for 32-bit data
248				Int32 litPosBits = 0;
249				// UInt32 litPosBits = 2; // for 32-bit data
250				Int32 algorithm = 2;
251				Int32 numFastBytes = 128;
252
253				bool eos = parser[(int)Key.EOS].ThereIs || stdInMode;
254
255				if (parser[(int)Key.Mode].ThereIs)
256					if (!GetNumber((string)parser[(int)Key.Mode].PostStrings[0], out algorithm))
257						IncorrectCommand();
258
259				if (parser[(int)Key.FastBytes].ThereIs)
260					if (!GetNumber((string)parser[(int)Key.FastBytes].PostStrings[0], out numFastBytes))
261						IncorrectCommand();
262				if (parser[(int)Key.LitContext].ThereIs)
263					if (!GetNumber((string)parser[(int)Key.LitContext].PostStrings[0], out litContextBits))
264						IncorrectCommand();
265				if (parser[(int)Key.LitPos].ThereIs)
266					if (!GetNumber((string)parser[(int)Key.LitPos].PostStrings[0], out litPosBits))
267						IncorrectCommand();
268				if (parser[(int)Key.PosBits].ThereIs)
269					if (!GetNumber((string)parser[(int)Key.PosBits].PostStrings[0], out posStateBits))
270						IncorrectCommand();
271
272				CoderPropID[] propIDs =
273				{
274					CoderPropID.DictionarySize,
275					CoderPropID.PosStateBits,
276					CoderPropID.LitContextBits,
277					CoderPropID.LitPosBits,
278					CoderPropID.Algorithm,
279					CoderPropID.NumFastBytes,
280					CoderPropID.MatchFinder,
281					CoderPropID.EndMarker
282				};
283				object[] properties =
284				{
285					(Int32)(dictionary),
286					(Int32)(posStateBits),
287					(Int32)(litContextBits),
288					(Int32)(litPosBits),
289					(Int32)(algorithm),
290					(Int32)(numFastBytes),
291					mf,
292					eos
293				};
294
295				Compression.LZMA.Encoder encoder = new Compression.LZMA.Encoder();
296				encoder.SetCoderProperties(propIDs, properties);
297				encoder.WriteCoderProperties(outStream);
298				Int64 fileSize;
299				if (eos || stdInMode)
300					fileSize = -1;
301				else
302					fileSize = inStream.Length;
303				for (int i = 0; i < 8; i++)
304					outStream.WriteByte((Byte)(fileSize >> (8 * i)));
305				if (trainStream != null)
306				{
307					CDoubleStream doubleStream = new CDoubleStream();
308					doubleStream.s1 = trainStream;
309					doubleStream.s2 = inStream;
310					doubleStream.fileIndex = 0;
311					inStream = doubleStream;
312					long trainFileSize = trainStream.Length;
313					doubleStream.skipSize = 0;
314					if (trainFileSize > dictionary)
315						doubleStream.skipSize = trainFileSize - dictionary;
316					trainStream.Seek(doubleStream.skipSize, SeekOrigin.Begin);
317					encoder.SetTrainSize((uint)(trainFileSize - doubleStream.skipSize));
318				}
319				encoder.Code(inStream, outStream, -1, -1, null);
320			}
321			else if (command == "d")
322			{
323				byte[] properties = new byte[5];
324				if (inStream.Read(properties, 0, 5) != 5)
325					throw (new Exception("input .lzma is too short"));
326				Compression.LZMA.Decoder decoder = new Compression.LZMA.Decoder();
327				decoder.SetDecoderProperties(properties);
328				if (trainStream != null)
329				{
330					if (!decoder.Train(trainStream))
331						throw (new Exception("can't train"));
332				}
333				long outSize = 0;
334				for (int i = 0; i < 8; i++)
335				{
336					int v = inStream.ReadByte();
337					if (v < 0)
338						throw (new Exception("Can't Read 1"));
339					outSize |= ((long)(byte)v) << (8 * i);
340				}
341				long compressedSize = inStream.Length - inStream.Position;
342				decoder.Code(inStream, outStream, compressedSize, outSize, null);
343			}
344			else
345				throw (new Exception("Command Error"));
346			return 0;
347		}
348
349		[STAThread]
350		static int Main(string[] args)
351		{
352			try
353			{
354				return Main2(args);
355			}
356			catch (Exception e)
357			{
358				Console.WriteLine("{0} Caught exception #1.", e);
359				// throw e;
360				return 1;
361			}
362		}
363	}
364}
365