1 using System;
2 using System.IO;
3 namespace 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 		}
Flush()23 		public override void Flush() { }
Read(byte[] buffer, int offset, int count)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 		}
Write(byte[] buffer, int offset, int count)46 		public override void Write(byte[] buffer, int offset, int count)
47 		{
48 			throw (new Exception("can't Write"));
49 		}
Seek(long offset, System.IO.SeekOrigin origin)50 		public override long Seek(long offset, System.IO.SeekOrigin origin)
51 		{
52 			throw (new Exception("can't Seek"));
53 		}
SetLength(long value)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 
PrintHelp()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 
GetNumber(string s, out Int32 v)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 
IncorrectCommand()113 		static int IncorrectCommand()
114 		{
115 			throw (new Exception("Command line error"));
116 			// System.Console.WriteLine("\nCommand line error\n");
117 			// return 1;
118 		}
Main2(string[] args)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]
Main(string[] args)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