private static MethodInfo GetDecompressLZF(ModuleBuilder modBldr, GeneratorOptions config)
		{
			CreateTb(modBldr, config);
			if (decompress_LZF == null)
				decompress_LZF = EmitDecompressLZF(mTb);
			return decompress_LZF;
		}
		private static void Main(string[] args)
		{
			var options = new GeneratorOptions();
			if (!Configurator.Configure(options, args))
			    return;
			var gen = new Generator(options);
			gen.Generate();
		}
		public static MethodInfo GetDecompress(ModuleBuilder modBldr, GeneratorOptions config, CompressionAlgorithm alg)
		{
			switch (alg)
			{
				case CompressionAlgorithm.LZF:
					return GetDecompressLZF(modBldr, config);
				default:
					throw new Exception("Unknown CompressionAlgorithm!");
			}
		}
		private static void CreateTb(ModuleBuilder modBldr, GeneratorOptions config)
		{
			if (mTb == null)
				mTb = modBldr.DefineType(config.TargetNamespace + ".Decompression", TypeAttributes.NotPublic | TypeAttributes.Class | TypeAttributes.Abstract | TypeAttributes.Sealed);
		}
			private static long AddFile(FileStream strm, FileInfo file, GeneratorOptions config, FileDescriptor desc)
			{
				if (!config.Optimizations.MergeDuplicateFiles)
				{
					long off = strm.Position;
					using (var fs = file.OpenRead())
					{
						Stream ifs = fs;
						if (config.Optimizations.Minify)
						{
							if (SerializedMinifiable(file))
								ifs = NeoAxisSerializedFileMinifier.Minify(ifs);
							else if (CStyleMinifiable(file))
								ifs = CStyleMinifier.Minify(ifs);
						}
						byte[] buf = new byte[(int)ifs.Length];
						ifs.Read(buf, 0, buf.Length);
						strm.Write(buf, 0, buf.Length);
						desc.InternalSize = buf.Length;
                    }
                    WriteEndAddingFile(false);
					return off;
				}
				else
				{
					byte[] buf;
					long off = strm.Position;
					using (var fs = file.OpenRead())
					{
						Stream ifs = fs;
						if (config.Optimizations.Minify)
						{
							if (SerializedMinifiable(file))// && file.Name == "PhysicsSystem.config")
								ifs = NeoAxisSerializedFileMinifier.Minify(ifs);
							else if (CStyleMinifiable(file))// && file.Name == "Fxaa3_9.cg_hlsl")
								ifs = CStyleMinifier.Minify(ifs);
						}
						buf = new byte[(int)ifs.Length];
						ifs.Read(buf, 0, buf.Length);
						//if (file.Name == "PhysicsSystem.config")
						//{
						//    using (var ofs = new FileStream("Definitions/PhysicsSystem.minified.config", FileMode.Create))
						//    {
						//        ofs.Write(buf, 0, buf.Length);
						//    }
						//}
						//if (file.Name == "Fxaa3_9.cg_hlsl")
						//{
						//    using (var ofs = new FileStream("Materials/PostEffects/FXAA/Fxaa3_9.minified.cg_hlsl", FileMode.Create))
						//    {
						//        ofs.Write(buf, 0, buf.Length);
						//    }
						//}
						if (config.Optimizations.CompressText)
						{
							buf = DoCompress(desc, buf);
						}
					}
					desc.InternalSize = buf.Length;
					int hash = HashProvider.ComputeIntHash(buf);
					Tuple<FileInfo, long> kf;
					if (!KnownFiles.TryGetValue(hash, out kf))
					{
						KnownFiles.Add(hash, new Tuple<FileInfo, long>(file, off));
                        strm.Write(buf, 0, buf.Length);
                        WriteEndAddingFile(false);
					}
					else if (!FileDataEqual(kf.ValA, file))
                    {
                        WriteEndAddingFile(false);
						Console.WriteLine("Warning: Hash collision!");
                        strm.Write(buf, 0, buf.Length);
					}
					else
					{
                        off = kf.ValB;
                        WriteEndAddingFile(true);
					}
					return off;
				}
			}
            private static void TreeCreationInit(GeneratorOptions config)
            {
                if (config.Optimizations.MergeDuplicateFiles)
                    KnownFiles = new Dictionary<int, Tuple<FileInfo, long>>();
                HashProvider = new SHA512Managed();
                CurFileNum = 0;
                TotalFileCountWidth = TotalFileCount.ToString().Length;
                FileExtensionPriorities = new Dictionary<string, int>(config.Optimizations.EmitOrder.Length);
                for (int i = 0, i2 = 0; i < config.Optimizations.EmitOrder.Length; i++, i2++)
                {
					string fe = config.Optimizations.EmitOrder[i].ToLower();
                    FileExtensionPriorities[fe] = i2;
					if (fe == ".dds")
						i2 += 30;
                }
            }
		public Generator(GeneratorOptions options)
		{
			config = options;
		}
			private static void CreateArchive(FileTreeDescriptor tree, GeneratorOptions config)
			{
				string oFNme = config.TargetArchiveFileName + "." + config.TargetFileExtension;
				if (File.Exists(oFNme))
					File.Delete(oFNme);
                Console.WriteLine("Creating '" + oFNme + "' with " + tree.Files.Count + " files");
                TotalFileCount = tree.Files.Count;
				using (var strm = new FileStream(oFNme, FileMode.Create, FileAccess.Write))
				{
					TreeCreationInit(config);

					tree.Files.Sort(
					(a, b) =>
					{
						int ap = GetFilePriority(a.SourceFile);
						int bp = GetFilePriority(b.SourceFile);
						if (ap > bp)
							return 1;
						if (ap < bp)
							return -1;
						int c = StringComparer.CurrentCultureIgnoreCase.Compare(a.SourceFile.Name, b.SourceFile.Name);
						if (c == 0)
							return StringComparer.CurrentCultureIgnoreCase.Compare(a.FullName, b.FullName);
						return c;
					});

					foreach (var v in tree.Files)
					{
                        WriteStartAddingFile(v);
						v.FileOffset = AddFile(strm, v.SourceFile, config, v);
					}

					TreeCreationFinish();
				}
			}
            private static void FillTree(FileTreeDescriptor desc, string curDirectory, GeneratorOptions config)
            {
                if (config.UseWindowsDirectorySeperator)
                    desc.Directories.Add(curDirectory + "\\");
                else
                    desc.Directories.Add(curDirectory + "/");

                DirectoryInfo d = new DirectoryInfo(curDirectory);
                foreach (var f in d.GetFiles())
                {
                    if (config.UseWindowsDirectorySeperator)
                        desc.Files.Add(new FileDescriptor(curDirectory + "\\" + f.Name, f.Length, f));
                    else
                        desc.Files.Add(new FileDescriptor(curDirectory + "/" + f.Name, f.Length, f));
                }
                foreach (var sd in d.GetDirectories())
                {
                    if (config.UseWindowsDirectorySeperator)
                        FillTree(desc, curDirectory + "\\" + sd.Name, config);
                    else
                        FillTree(desc, curDirectory + "/" + sd.Name, config);
                }
            }
			public static FileTreeDescriptor GetTree(GeneratorOptions config)
			{
				var desc = new FileTreeDescriptor();
				Directory.SetCurrentDirectory("Data");
				DirectoryInfo d = new DirectoryInfo("./");
				foreach (var sd in d.GetDirectories())
				{
					FillTree(desc, sd.Name, config);
				}
				CreateArchive(desc, config);
				Directory.SetCurrentDirectory("../");
				return desc;
			}