1 // CoreUtil
2 //
3 // Copyright (C) 2012-2014 Daiyuu Nobori. All Rights Reserved.
4 // Copyright (C) 2012-2014 SoftEther VPN Project at University of Tsukuba. All Rights Reserved.
5 //
6 // License: The Apache License, Version 2.0
7 // https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // DISCLAIMER
10 // ==========
11 //
12 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
13 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
14 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
15 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
16 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
17 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
18 // SOFTWARE.
19 //
20 // THIS SOFTWARE IS DEVELOPED IN JAPAN, AND DISTRIBUTED FROM JAPAN, UNDER
21 // JAPANESE LAWS. YOU MUST AGREE IN ADVANCE TO USE, COPY, MODIFY, MERGE, PUBLISH,
22 // DISTRIBUTE, SUBLICENSE, AND/OR SELL COPIES OF THIS SOFTWARE, THAT ANY
23 // JURIDICAL DISPUTES WHICH ARE CONCERNED TO THIS SOFTWARE OR ITS CONTENTS,
24 // AGAINST US (SOFTETHER PROJECT, SOFTETHER CORPORATION, DAIYUU NOBORI OR OTHER
25 // SUPPLIERS), OR ANY JURIDICAL DISPUTES AGAINST US WHICH ARE CAUSED BY ANY KIND
26 // OF USING, COPYING, MODIFYING, MERGING, PUBLISHING, DISTRIBUTING, SUBLICENSING,
27 // AND/OR SELLING COPIES OF THIS SOFTWARE SHALL BE REGARDED AS BE CONSTRUED AND
28 // CONTROLLED BY JAPANESE LAWS, AND YOU MUST FURTHER CONSENT TO EXCLUSIVE
29 // JURISDICTION AND VENUE IN THE COURTS SITTING IN TOKYO, JAPAN. YOU MUST WAIVE
30 // ALL DEFENSES OF LACK OF PERSONAL JURISDICTION AND FORUM NON CONVENIENS.
31 // PROCESS MAY BE SERVED ON EITHER PARTY IN THE MANNER AUTHORIZED BY APPLICABLE
32 // LAW OR COURT RULE.
33 //
34 // USE ONLY IN JAPAN. DO NOT USE THIS SOFTWARE IN ANOTHER COUNTRY UNLESS YOU HAVE
35 // A CONFIRMATION THAT THIS SOFTWARE DOES NOT VIOLATE ANY CRIMINAL LAWS OR CIVIL
36 // RIGHTS IN THAT PARTICULAR COUNTRY. USING THIS SOFTWARE IN OTHER COUNTRIES IS
37 // COMPLETELY AT YOUR OWN RISK. THE SOFTETHER VPN PROJECT HAS DEVELOPED AND
38 // DISTRIBUTED THIS SOFTWARE TO COMPLY ONLY WITH THE JAPANESE LAWS AND EXISTING
39 // CIVIL RIGHTS INCLUDING PATENTS WHICH ARE SUBJECTS APPLY IN JAPAN. OTHER
40 // COUNTRIES' LAWS OR CIVIL RIGHTS ARE NONE OF OUR CONCERNS NOR RESPONSIBILITIES.
41 // WE HAVE NEVER INVESTIGATED ANY CRIMINAL REGULATIONS, CIVIL LAWS OR
42 // INTELLECTUAL PROPERTY RIGHTS INCLUDING PATENTS IN ANY OF OTHER 200+ COUNTRIES
43 // AND TERRITORIES. BY NATURE, THERE ARE 200+ REGIONS IN THE WORLD, WITH
44 // DIFFERENT LAWS. IT IS IMPOSSIBLE TO VERIFY EVERY COUNTRIES' LAWS, REGULATIONS
45 // AND CIVIL RIGHTS TO MAKE THE SOFTWARE COMPLY WITH ALL COUNTRIES' LAWS BY THE
46 // PROJECT. EVEN IF YOU WILL BE SUED BY A PRIVATE ENTITY OR BE DAMAGED BY A
47 // PUBLIC SERVANT IN YOUR COUNTRY, THE DEVELOPERS OF THIS SOFTWARE WILL NEVER BE
48 // LIABLE TO RECOVER OR COMPENSATE SUCH DAMAGES, CRIMINAL OR CIVIL
49 // RESPONSIBILITIES. NOTE THAT THIS LINE IS NOT LICENSE RESTRICTION BUT JUST A
50 // STATEMENT FOR WARNING AND DISCLAIMER.
51 //
52 // READ AND UNDERSTAND THE 'WARNING.TXT' FILE BEFORE USING THIS SOFTWARE.
53 // SOME SOFTWARE PROGRAMS FROM THIRD PARTIES ARE INCLUDED ON THIS SOFTWARE WITH
54 // LICENSE CONDITIONS WHICH ARE DESCRIBED ON THE 'THIRD_PARTY.TXT' FILE.
55 //
56 //
57 // SOURCE CODE CONTRIBUTION
58 // ------------------------
59 //
60 // Your contribution to SoftEther VPN Project is much appreciated.
61 // Please send patches to us through GitHub.
62 // Read the SoftEther VPN Patch Acceptance Policy in advance:
63 // http://www.softether.org/5-download/src/9.patch
64 //
65 //
66 // DEAR SECURITY EXPERTS
67 // ---------------------
68 //
69 // If you find a bug or a security vulnerability please kindly inform us
70 // about the problem immediately so that we can fix the security problem
71 // to protect a lot of users around the world as soon as possible.
72 //
73 // Our e-mail address for security reports is:
74 // softether-vpn-security [at] softether.org
75 //
76 // Please note that the above e-mail address is not a technical support
77 // inquiry address. If you need technical assistance, please visit
78 // http://www.softether.org/ and ask your question on the users forum.
79 //
80 // Thank you for your cooperation.
81 //
82 //
83 // NO MEMORY OR RESOURCE LEAKS
84 // ---------------------------
85 //
86 // The memory-leaks and resource-leaks verification under the stress
87 // test has been passed before release this source code.
88 
89 
90 using System;
91 using System.Threading;
92 using System.Data;
93 using System.Data.Sql;
94 using System.Data.SqlClient;
95 using System.Data.SqlTypes;
96 using System.Text;
97 using System.Configuration;
98 using System.Collections;
99 using System.Collections.Generic;
100 using System.Security.Cryptography;
101 using System.Web;
102 using System.Web.Security;
103 using System.Web.UI;
104 using System.Web.UI.WebControls;
105 using System.Web.UI.WebControls.WebParts;
106 using System.Web.UI.HtmlControls;
107 using System.IO;
108 using System.Drawing;
109 using System.Drawing.Imaging;
110 using System.Drawing.Drawing2D;
111 using System.Web.Mail;
112 
113 namespace CoreUtil
114 {
115 	internal class HamCoreEntry : IComparable
116 	{
117 		public string FileName = "";
118 		public uint Size = 0;
119 		public uint SizeCompressed = 0;
120 		public uint Offset = 0;
121 		public byte[] Buffer = null;
122 		public long LastAccess = 0;
123 
CompareTo(object obj)124 		public int CompareTo(object obj)
125 		{
126 			HamCoreEntry hc1, hc2;
127 			hc1 = this;
128 			hc2 = (HamCoreEntry)obj;
129 
130 			return Str.StrCmpiRetInt(hc1.FileName, hc2.FileName);
131 		}
132 	}
133 
134 	public class HamCoreBuilderFileEntry : IComparable<HamCoreBuilderFileEntry>
135 	{
136 		public string Name;
137 		public Buf RawData;
138 		public Buf CompressedData;
139 		public int Offset = 0;
140 
CompareTo(HamCoreBuilderFileEntry other)141 		int IComparable<HamCoreBuilderFileEntry>.CompareTo(HamCoreBuilderFileEntry other)
142 		{
143 			return this.Name.CompareTo(other.Name);
144 		}
145 	}
146 
147 	public class HamCoreBuilder
148 	{
149 		List<HamCoreBuilderFileEntry> fileList;
150 		public List<HamCoreBuilderFileEntry> FileList
151 		{
152 			get { return fileList; }
153 		}
154 
IsFile(string name)155 		public bool IsFile(string name)
156 		{
157 			foreach (HamCoreBuilderFileEntry f in fileList)
158 			{
159 				if (f.Name.Equals(name, StringComparison.InvariantCultureIgnoreCase))
160 				{
161 					return true;
162 				}
163 			}
164 
165 			return false;
166 		}
167 
DeleteFile(string name)168 		public bool DeleteFile(string name)
169 		{
170 			foreach (HamCoreBuilderFileEntry f in fileList)
171 			{
172 				if (f.Name.Equals(name, StringComparison.InvariantCultureIgnoreCase))
173 				{
174 					fileList.Remove(f);
175 					return true;
176 				}
177 			}
178 
179 			return false;
180 		}
181 
HamCoreBuilder()182 		public HamCoreBuilder()
183 		{
184 			fileList = new List<HamCoreBuilderFileEntry>();
185 		}
186 
AddDir(string dirName)187 		public void AddDir(string dirName)
188 		{
189 			dirName = IO.RemoteLastEnMark(dirName);
190 
191 			DirEntry[] ee = IO.EnumDirEx(dirName);
192 
193 			foreach (DirEntry e in ee)
194 			{
195 				if (e.IsFolder == false)
196 				{
197 					AddFile(e.FullPath, dirName);
198 				}
199 			}
200 		}
201 
AddFile(string fileName, string baseDirFileName)202 		public void AddFile(string fileName, string baseDirFileName)
203 		{
204 			string name = IO.GetRelativeFileName(fileName, baseDirFileName);
205 
206 			AddFile(name, File.ReadAllBytes(fileName));
207 		}
208 
AddFile(string name, byte[] data)209 		public void AddFile(string name, byte[] data)
210 		{
211 			if (IsFile(name))
212 			{
213 				throw new InvalidOperationException("fileName");
214 			}
215 
216 			HamCoreBuilderFileEntry f = new HamCoreBuilderFileEntry();
217 
218 			Console.Write("{0}: ", name);
219 
220 			f.Name = name;
221 			f.RawData = new Buf(Util.CloneByteArray(data));
222 			Console.Write("{0} -> ", f.RawData.Size);
223 			f.CompressedData = new Buf(ZLib.Compress(f.RawData.ByteData));
224 			Console.WriteLine("{0}", f.CompressedData.Size);
225 
226 			this.fileList.Add(f);
227 		}
228 
Build(string dstFileName)229 		public void Build(string dstFileName)
230 		{
231 			Buf b = Build();
232 
233 			IO.SaveFile(dstFileName, b.ByteData);
234 		}
235 
Build()236 		public Buf Build()
237 		{
238 			int z;
239 			Buf b;
240 
241 			this.fileList.Sort();
242 
243 			z = 0;
244 
245 			z += HamCore.HamcoreHeaderSize;
246 
247 			z += sizeof(int);
248 
249 			foreach (HamCoreBuilderFileEntry f in this.fileList)
250 			{
251 				z += Str.ShiftJisEncoding.GetByteCount(f.Name) + sizeof(int);
252 				z += sizeof(int);
253 				z += sizeof(int);
254 				z += sizeof(int);
255 			}
256 			foreach (HamCoreBuilderFileEntry f in this.fileList)
257 			{
258 				f.Offset = z;
259 				z += (int)f.CompressedData.Size;
260 			}
261 
262 			b = new Buf();
263 			b.Write(Str.ShiftJisEncoding.GetBytes(HamCore.HamcoreHeaderData));
264 			b.WriteInt((uint)this.fileList.Count);
265 			foreach (HamCoreBuilderFileEntry f in this.fileList)
266 			{
267 				b.WriteStr(f.Name, true);
268 				b.WriteInt(f.RawData.Size);
269 				b.WriteInt(f.CompressedData.Size);
270 				b.WriteInt((uint)f.Offset);
271 			}
272 			foreach (HamCoreBuilderFileEntry f in this.fileList)
273 			{
274 				b.Write(f.CompressedData.ByteData);
275 			}
276 
277 			b.SeekToBegin();
278 
279 			return b;
280 		}
281 	}
282 
283 	public class HamCore
284 	{
285 		public const string HamcoreDirName = "@hamcore";
286 		public const string HamcoreHeaderData = "HamCore";
287 		public const int HamcoreHeaderSize = 7;
288 		public const long HamcoreCacheExpires = 5 * 60 * 1000;
289 		bool disableReadRawFile = false;
290 		public bool DisableReadRawFile
291 		{
292 			get { return disableReadRawFile; }
293 			set { disableReadRawFile = value; }
294 		}
295 
296 		Dictionary<string, HamCoreEntry> list;
297 
298 		IO hamcore_io;
299 
HamCore(string filename)300 		public HamCore(string filename)
301 		{
302 			init(filename);
303 		}
304 
GetFileNames()305 		public string[] GetFileNames()
306 		{
307 			List<string> ret = new List<string>();
308 
309 			foreach (HamCoreEntry e in list.Values)
310 			{
311 				ret.Add(e.FileName);
312 			}
313 
314 			return ret.ToArray();
315 		}
316 
init(string filename)317 		void init(string filename)
318 		{
319 			filename = IO.InnerFilePath(filename);
320 			string filenameOnly = Path.GetFileName(filename);
321 			string filenameAlt = Path.Combine(Path.GetDirectoryName(filename), "_" + filenameOnly);
322 
323 			try
324 			{
325 				IO.FileReplaceRename(filenameAlt, filename);
326 			}
327 			catch
328 			{
329 			}
330 
331 			list = new Dictionary<string, HamCoreEntry>();
332 
333 			try
334 			{
335 				hamcore_io = IO.FileOpen(filename);
336 			}
337 			catch
338 			{
339 				return;
340 			}
341 
342 			try
343 			{
344 				byte[] header = hamcore_io.Read(HamcoreHeaderSize);
345 				byte[] header2 = Str.AsciiEncoding.GetBytes(HamcoreHeaderData);
346 				if (header == null || Util.CompareByte(header, header2) == false)
347 				{
348 					throw new SystemException();
349 				}
350 
351 				uint num = 0;
352 				byte[] buf = hamcore_io.Read(Util.SizeOfInt32);
353 				num = Util.ByteToUInt(buf);
354 				uint i;
355 				for (i = 0; i < num; i++)
356 				{
357 					uint str_size;
358 
359 					buf = hamcore_io.Read(Util.SizeOfInt32);
360 					str_size = Util.ByteToUInt(buf);
361 					if (str_size >= 1)
362 					{
363 						str_size--;
364 					}
365 
366 					byte[] str_data = hamcore_io.Read((int)str_size);
367 					string tmp = Str.ShiftJisEncoding.GetString(str_data);
368 
369 					HamCoreEntry c = new HamCoreEntry();
370 					c.FileName = tmp;
371 
372 					buf = hamcore_io.Read(Util.SizeOfInt32);
373 					c.Size = Util.ByteToUInt(buf);
374 
375 					buf = hamcore_io.Read(Util.SizeOfInt32);
376 					c.SizeCompressed = Util.ByteToUInt(buf);
377 
378 					buf = hamcore_io.Read(Util.SizeOfInt32);
379 					c.Offset = Util.ByteToUInt(buf);
380 
381 					list.Add(c.FileName.ToUpper(), c);
382 				}
383 			}
384 			catch
385 			{
386 				hamcore_io.Close();
387 			}
388 		}
389 
ReadHamcore(string name)390 		public Buf ReadHamcore(string name)
391 		{
392 			if (name[0] == '|')
393 			{
394 				name = name.Substring(1);
395 			}
396 			if (name[0] == '/' || name[0] == '\\')
397 			{
398 				name = name.Substring(1);
399 			}
400 
401 			string filename = name;
402 
403 			filename = filename.Replace("/", "\\");
404 
405 			Buf b;
406 
407 			if (this.disableReadRawFile == false)
408 			{
409 				try
410 				{
411 					b = Buf.ReadFromFile(HamcoreDirName + "\\" + filename);
412 
413 					return b;
414 				}
415 				catch
416 				{
417 				}
418 			}
419 
420 			lock (list)
421 			{
422 				HamCoreEntry c;
423 				string key = filename.ToUpper();
424 
425 				b = null;
426 
427 				if (list.ContainsKey(key))
428 				{
429 					c = list[key];
430 
431 					if (c.Buffer != null)
432 					{
433 						b = new Buf(c.Buffer);
434 						b.SeekToBegin();
435 						c.LastAccess = Time.Tick64;
436 					}
437 					else
438 					{
439 						if (hamcore_io.Seek(SeekOrigin.Begin, (int)c.Offset))
440 						{
441 							byte[] data = hamcore_io.Read((int)c.SizeCompressed);
442 
443 							int dstSize = (int)c.Size;
444 							byte[] buffer = ZLib.Uncompress(data, dstSize);
445 
446 							c.Buffer = buffer;
447 							b = new Buf(buffer);
448 							b.SeekToBegin();
449 							c.LastAccess = Time.Tick64;
450 						}
451 					}
452 				}
453 
454 				long now = Time.Tick64;
455 				foreach (HamCoreEntry cc in list.Values)
456 				{
457 					if (cc.Buffer != null)
458 					{
459 						if (((cc.LastAccess + HamcoreCacheExpires) < now) ||
460 							cc.FileName.StartsWith("Li", StringComparison.CurrentCultureIgnoreCase))
461 						{
462 							cc.Buffer = null;
463 						}
464 					}
465 				}
466 			}
467 
468 			return b;
469 		}
470 	}
471 
472 	public class DirEntry : IComparable<DirEntry>
473 	{
474 		internal bool folder;
475 		public bool IsFolder
476 		{
477 			get { return folder; }
478 		}
479 		internal string fileName;
480 		public string FileName
481 		{
482 			get { return fileName; }
483 		}
484 		internal string fullPath;
485 		public string FullPath
486 		{
487 			get { return fullPath; }
488 		}
489 		internal string relativePath;
490 		public string RelativePath
491 		{
492 			get { return relativePath; }
493 		}
494 		internal long fileSize;
495 		public long FileSize
496 		{
497 			get { return fileSize; }
498 		}
499 		internal DateTime createDate;
500 		public DateTime CreateDate
501 		{
502 			get { return createDate; }
503 		}
504 		internal DateTime updateDate;
505 		public DateTime UpdateDate
506 		{
507 			get { return updateDate; }
508 		}
509 
CompareTo(DirEntry other)510 		public int CompareTo(DirEntry other)
511 		{
512 			int i;
513 			i = Str.StrCmpiRetInt(this.fileName, other.fileName);
514 			if (i == 0)
515 			{
516 				i = Str.StrCmpRetInt(this.fileName, other.fileName);
517 			}
518 
519 			return i;
520 		}
521 
ToString()522 		public override string ToString()
523 		{
524 			return FileName;
525 		}
526 	};
527 
528 	public class IO
529 	{
CopyDirPreCopyDelegate(FileInfo srcFileInfo)530 		public delegate bool CopyDirPreCopyDelegate(FileInfo srcFileInfo);
CopyDir(string srcDirName, string destDirName, CopyDirPreCopyDelegate preCopy, bool ignoreError, bool printStatus)531 		public static void CopyDir(string srcDirName, string destDirName, CopyDirPreCopyDelegate preCopy, bool ignoreError, bool printStatus)
532 		{
533 			CopyDir(srcDirName, destDirName, preCopy, ignoreError, printStatus, false, false, false);
534 		}
CopyDir(string srcDirName, string destDirName, CopyDirPreCopyDelegate preCopy, bool ignoreError, bool printStatus, bool skipIfNoChange, bool deleteBom)535 		public static void CopyDir(string srcDirName, string destDirName, CopyDirPreCopyDelegate preCopy, bool ignoreError, bool printStatus,
536 			bool skipIfNoChange, bool deleteBom)
537 		{
538 			CopyDir(srcDirName, destDirName, preCopy, ignoreError, printStatus, skipIfNoChange, deleteBom, false);
539 		}
CopyDir(string srcDirName, string destDirName, CopyDirPreCopyDelegate preCopy, bool ignoreError, bool printStatus, bool skipIfNoChange, bool deleteBom, bool useTimeStampToCheckNoChange)540 		public static void CopyDir(string srcDirName, string destDirName, CopyDirPreCopyDelegate preCopy, bool ignoreError, bool printStatus,
541 			bool skipIfNoChange, bool deleteBom, bool useTimeStampToCheckNoChange)
542 		{
543 			string[] files = Directory.GetFiles(srcDirName, "*", SearchOption.AllDirectories);
544 
545 			foreach (string srcFile in files)
546 			{
547 				FileInfo info = new FileInfo(srcFile);
548 
549 				string relativeFileName = IO.GetRelativeFileName(srcFile, srcDirName);
550 				string destFileName = Path.Combine(destDirName, relativeFileName);
551 				string destFileDirName = Path.GetDirectoryName(destFileName);
552 
553 				if (preCopy != null)
554 				{
555 					if (preCopy(info) == false)
556 					{
557 						continue;
558 					}
559 				}
560 
561 				try
562 				{
563 					if (Directory.Exists(destFileDirName) == false)
564 					{
565 						Directory.CreateDirectory(destFileDirName);
566 					}
567 
568 					FileCopy(srcFile, destFileName, skipIfNoChange, deleteBom, useTimeStampToCheckNoChange);
569 				}
570 				catch
571 				{
572 					if (ignoreError == false)
573 					{
574 						throw;
575 					}
576 				}
577 
578 				if (printStatus)
579 				{
580 					Con.WriteLine(relativeFileName);
581 				}
582 			}
583 		}
584 
585 		public const string DefaultHamcoreFileName = "@hamcore.se2";
586 
587 		static string hamcoreFileName = DefaultHamcoreFileName;
588 		public static string HamcoreFileName
589 		{
590 			get { return IO.hamcoreFileName; }
591 			set
592 			{
593 				lock (hamLockObj)
594 				{
595 					if (hamCore != null)
596 					{
597 						throw new ApplicationException();
598 					}
599 
600 					IO.hamcoreFileName = value;
601 					tryToUseHamcore = false;
602 				}
603 			}
604 		}
605 
606 		static bool tryToUseHamcore = true;
607 		static HamCore hamCore = null;
608 		static object hamLockObj = new object();
609 		public static HamCore HamCore
610 		{
611 			get
612 			{
613 				HamCore ret = null;
614 
615 				lock (hamLockObj)
616 				{
617 					if (hamCore == null)
618 					{
619 						if (tryToUseHamcore)
620 						{
621 							if (hamCore == null)
622 							{
623 								try
624 								{
625 									ret = hamCore = new HamCore(hamcoreFileName);
626 								}
627 								catch
628 								{
629 									tryToUseHamcore = false;
630 								}
631 							}
632 						}
633 					}
634 				}
635 
636 				return ret;
637 			}
638 		}
639 
640 		string name;
641 		public string Name
642 		{
643 			get { return name; }
644 		}
645 		FileStream p;
646 		public FileStream InnerFileStream
647 		{
648 			get { return p; }
649 		}
650 		bool writeMode;
651 		public bool WriteMode
652 		{
653 			get { return writeMode; }
654 		}
655 		bool hamMode;
656 		public bool HamMode
657 		{
658 			get { return hamMode; }
659 		}
660 		Buf hamBuf;
661 
662 		object lockObj;
663 
IO()664 		private IO()
665 		{
666 			name = "";
667 			p = null;
668 			writeMode = hamMode = false;
669 			lockObj = new object();
670 			hamBuf = null;
671 		}
672 
~IO()673 		~IO()
674 		{
675 			Close();
676 		}
677 
WriteAllTextWithEncoding(string fileName, string str, Encoding encoding)678 		public static void WriteAllTextWithEncoding(string fileName, string str, Encoding encoding)
679 		{
680 			WriteAllTextWithEncoding(fileName, str, encoding, false);
681 		}
WriteAllTextWithEncoding(string fileName, string str, Encoding encoding, bool appendBom)682 		public static void WriteAllTextWithEncoding(string fileName, string str, Encoding encoding, bool appendBom)
683 		{
684 			fileName = InnerFilePath(fileName);
685 
686 			byte[] data = encoding.GetBytes(str);
687 			byte[] bom = null;
688 			if (appendBom)
689 			{
690 				bom = Str.GetBOM(encoding);
691 			}
692 
693 			data = Util.CombineByteArray(bom, data);
694 
695 			File.WriteAllBytes(fileName, data);
696 		}
697 
ReadAllTextWithAutoGetEncoding(string fileName)698 		public static string ReadAllTextWithAutoGetEncoding(string fileName)
699 		{
700 			fileName = InnerFilePath(fileName);
701 
702 			byte[] data = File.ReadAllBytes(fileName);
703 
704 			int bomSize;
705 			Encoding enc = Str.GetEncoding(data, out bomSize);
706 			if (enc == null)
707 			{
708 				enc = Encoding.Default;
709 			}
710 
711 			data = Util.RemoveStartByteArray(data, bomSize);
712 
713 			return enc.GetString(data);
714 		}
715 
CreateTempFileByExt(string ext)716 		public static IO CreateTempFileByExt(string ext)
717 		{
718 			return IO.FileCreate(CreateTempFileNameByExt(ext));
719 		}
720 
CreateTempFileNameByExt(string ext)721 		public static string CreateTempFileNameByExt(string ext)
722 		{
723 			if (Str.IsEmptyStr(ext))
724 			{
725 				ext = "tmp";
726 			}
727 			if (ext[0] == '.')
728 			{
729 				ext = ext.Substring(1);
730 			}
731 
732 			while (true)
733 			{
734 				string newFilename;
735 				string fullPath;
736 				string randStr;
737 
738 				randStr = Str.GenRandStr();
739 				newFilename = "__" + randStr + "." + ext;
740 
741 				fullPath = CreateTempFileName(newFilename);
742 
743 				if (IO.IsFileExists(fullPath) == false)
744 				{
745 					return fullPath;
746 				}
747 			}
748 		}
749 
CreateTempFile(string name)750 		public static IO CreateTempFile(string name)
751 		{
752 			return IO.FileCreate(CreateTempFileName(name));
753 		}
754 
CreateTempFileName(string name)755 		public static string CreateTempFileName(string name)
756 		{
757 			return Path.Combine(Env.MyTempDir, name);
758 		}
759 
EnumDirEx(string dirName)760 		public static DirEntry[] EnumDirEx(string dirName)
761 		{
762 			List<DirEntry> list = new List<DirEntry>();
763 
764 			enumDirEx(dirName, dirName, list);
765 
766 			return list.ToArray();
767 		}
enumDirEx(string dirName, string baseDirName, List<DirEntry> list)768 		static void enumDirEx(string dirName, string baseDirName, List<DirEntry> list)
769 		{
770 			string tmp = IO.InnerFilePath(dirName);
771 
772 			string[] dirs = Directory.GetDirectories(tmp);
773 			foreach (string name in dirs)
774 			{
775 				string fullPath = name;
776 				DirectoryInfo info = new DirectoryInfo(fullPath);
777 
778 				DirEntry e = new DirEntry();
779 
780 				e.fileName = Path.GetFileName(name);
781 				e.fileSize = 0;
782 				e.createDate = info.CreationTimeUtc;
783 				e.folder = true;
784 				e.updateDate = info.LastWriteTimeUtc;
785 				e.fullPath = fullPath;
786 				e.relativePath = GetRelativeFileName(fullPath, baseDirName);
787 
788 				list.Add(e);
789 
790 				enumDirEx(fullPath, baseDirName, list);
791 			}
792 
793 			string[] files = Directory.GetFiles(tmp);
794 			foreach (string name in files)
795 			{
796 				string fullPath = name;
797 				FileInfo info = new FileInfo(fullPath);
798 
799 				DirEntry e = new DirEntry();
800 
801 				e.fileName = Path.GetFileName(name);
802 				e.fileSize = info.Length;
803 				e.createDate = info.CreationTimeUtc;
804 				e.folder = false;
805 				e.updateDate = info.LastWriteTimeUtc;
806 				e.fullPath = fullPath;
807 				e.relativePath = GetRelativeFileName(fullPath, baseDirName);
808 
809 				list.Add(e);
810 			}
811 		}
812 
EnumDir(string dirName)813 		public static DirEntry[] EnumDir(string dirName)
814 		{
815 			List<DirEntry> list = new List<DirEntry>();
816 			string tmp = IO.InnerFilePath(dirName);
817 
818 			string[] dirs = Directory.GetDirectories(tmp);
819 			foreach (string name in dirs)
820 			{
821 				string fullPath = name;
822 				DirectoryInfo info = new DirectoryInfo(fullPath);
823 
824 				DirEntry e = new DirEntry();
825 
826 				e.fileName = Path.GetFileName(name);
827 				e.fileSize = 0;
828 				e.createDate = info.CreationTimeUtc;
829 				e.folder = true;
830 				e.updateDate = info.LastWriteTimeUtc;
831 				e.fullPath = fullPath;
832 				e.relativePath = GetRelativeFileName(fullPath, dirName);
833 
834 				list.Add(e);
835 			}
836 
837 			string[] files = Directory.GetFiles(tmp);
838 			foreach (string name in files)
839 			{
840 				string fullPath = name;
841 				FileInfo info = new FileInfo(fullPath);
842 
843 				DirEntry e = new DirEntry();
844 
845 				e.fileName = Path.GetFileName(name);
846 				e.fileSize = info.Length;
847 				e.createDate = info.CreationTimeUtc;
848 				e.folder = false;
849 				e.updateDate = info.LastWriteTimeUtc;
850 				e.fullPath = fullPath;
851 				e.relativePath = GetRelativeFileName(fullPath, dirName);
852 
853 				list.Add(e);
854 			}
855 
856 			list.Sort();
857 
858 			return list.ToArray();
859 		}
860 
FileReplaceRename(string oldName, string newName)861 		public static void FileReplaceRename(string oldName, string newName)
862 		{
863 			try
864 			{
865 				FileCopy(oldName, newName);
866 				FileDelete(oldName);
867 			}
868 			catch (Exception e)
869 			{
870 				throw e;
871 			}
872 		}
873 
FileCopy(string oldName, string newName)874 		public static void FileCopy(string oldName, string newName)
875 		{
876 			FileCopy(oldName, newName, false, false);
877 		}
FileCopy(string oldName, string newName, bool skipIfNoChange, bool deleteBom)878 		public static void FileCopy(string oldName, string newName, bool skipIfNoChange, bool deleteBom)
879 		{
880 			FileCopy(oldName, newName, skipIfNoChange, deleteBom, false);
881 		}
FileCopy(string oldName, string newName, bool skipIfNoChange, bool deleteBom, bool useTimeStampToCheckNoChange)882 		public static void FileCopy(string oldName, string newName, bool skipIfNoChange, bool deleteBom, bool useTimeStampToCheckNoChange)
883 		{
884 			string tmp1 = InnerFilePath(oldName);
885 			string tmp2 = InnerFilePath(newName);
886 
887 			if (useTimeStampToCheckNoChange && skipIfNoChange)
888 			{
889 				DateTime dt1, dt2;
890 
891 				try
892 				{
893 					dt1 = Directory.GetLastWriteTimeUtc(tmp1);
894 					dt2 = Directory.GetLastWriteTimeUtc(tmp2);
895 
896 					TimeSpan ts = dt2 - dt1;
897 					if (ts.TotalSeconds >= -5.0)
898 					{
899 						return;
900 					}
901 				}
902 				catch
903 				{
904 				}
905 			}
906 
907 			if (skipIfNoChange || deleteBom)
908 			{
909 				byte[] srcData = File.ReadAllBytes(tmp1);
910 				byte[] destData = new byte[0];
911 				bool changed = true;
912 				int bomSize;
913 
914 				Str.GetEncoding(srcData, out bomSize);
915 				if (bomSize >= 1)
916 				{
917 					srcData = Util.ExtractByteArray(srcData, bomSize, srcData.Length - bomSize);
918 				}
919 
920 				if (skipIfNoChange)
921 				{
922 					try
923 					{
924 						FileStream fs = File.OpenRead(tmp2);
925 						long size = 0xffffffff;
926 						try
927 						{
928 							size = fs.Length;
929 						}
930 						finally
931 						{
932 							fs.Close();
933 						}
934 
935 						if (size == srcData.Length || srcData.Length == 0)
936 						{
937 							destData = File.ReadAllBytes(tmp2);
938 						}
939 					}
940 					catch
941 					{
942 					}
943 
944 					if (Util.CompareByte(srcData, destData))
945 					{
946 						changed = false;
947 					}
948 				}
949 
950 				if (changed)
951 				{
952 					File.WriteAllBytes(tmp2, srcData);
953 					CopyFileTimestamp(tmp2, tmp1);
954 				}
955 			}
956 			else
957 			{
958 				File.Copy(tmp1, tmp2, true);
959 			}
960 		}
961 
CopyFileTimestamp(string dstFileName, string srcFileName)962 		public static void CopyFileTimestamp(string dstFileName, string srcFileName)
963 		{
964 			DateTime dt1 = File.GetCreationTimeUtc(srcFileName);
965 			DateTime dt2 = File.GetLastAccessTimeUtc(srcFileName);
966 			DateTime dt3 = File.GetLastWriteTimeUtc(srcFileName);
967 
968 			File.SetCreationTimeUtc(dstFileName, dt1);
969 			File.SetLastAccessTimeUtc(dstFileName, dt2);
970 			File.SetLastWriteTimeUtc(dstFileName, dt3);
971 		}
972 
SetFileTimestamp(string dstFileName, FileInfo fi)973 		public static void SetFileTimestamp(string dstFileName, FileInfo fi)
974 		{
975 			File.SetCreationTimeUtc(dstFileName, fi.CreationTimeUtc);
976 			File.SetLastAccessTimeUtc(dstFileName, fi.LastAccessTimeUtc);
977 			File.SetLastWriteTimeUtc(dstFileName, fi.LastWriteTimeUtc);
978 		}
979 
ReadFile(string name)980 		static public byte[] ReadFile(string name)
981 		{
982 			IO io = FileOpen(name);
983 			try
984 			{
985 				int size = io.FileSize;
986 				byte[] ret = io.Read(size);
987 				return ret;
988 			}
989 			finally
990 			{
991 				io.Close();
992 			}
993 		}
994 
SaveFile(string name, byte[] data)995 		static public void SaveFile(string name, byte[] data)
996 		{
997 			SaveFile(name, data, 0, data.Length);
998 		}
SaveFile(string name, byte[] data, int offset, int size)999 		static public void SaveFile(string name, byte[] data, int offset, int size)
1000 		{
1001 			IO io = FileCreate(name);
1002 			try
1003 			{
1004 				io.Write(data, offset, size);
1005 			}
1006 			finally
1007 			{
1008 				io.Close();
1009 			}
1010 		}
1011 
MakeSafeFileName(string src)1012 		static public string MakeSafeFileName(string src)
1013 		{
1014 			return src
1015 				.Replace("..", "__")
1016 				.Replace("/", "_")
1017 				.Replace("\\", "_")
1018 				.Replace("@", "_")
1019 				.Replace("|", "_");
1020 		}
1021 
IsDirExists(string name)1022 		public static bool IsDirExists(string name)
1023 		{
1024 			string tmp = InnerFilePath(name);
1025 
1026 			return Directory.Exists(tmp);
1027 		}
1028 
IsFileExists(string name)1029 		public static bool IsFileExists(string name)
1030 		{
1031 			string tmp = InnerFilePath(name);
1032 
1033 			return File.Exists(tmp);
1034 		}
1035 
fileDeleteInner(string name)1036 		static void fileDeleteInner(string name)
1037 		{
1038 			string name2 = ConvertPath(name);
1039 
1040 			File.Delete(name2);
1041 		}
FileDelete(string name)1042 		public static void FileDelete(string name)
1043 		{
1044 			string tmp = InnerFilePath(name);
1045 
1046 			fileDeleteInner(tmp);
1047 		}
1048 
Seek(SeekOrigin mode, int offset)1049 		public bool Seek(SeekOrigin mode, int offset)
1050 		{
1051 			lock (lockObj)
1052 			{
1053 				if (p != null)
1054 				{
1055 					try
1056 					{
1057 						p.Seek(offset, mode);
1058 
1059 						return true;
1060 					}
1061 					catch
1062 					{
1063 						return false;
1064 					}
1065 				}
1066 				else
1067 				{
1068 					return false;
1069 				}
1070 			}
1071 		}
1072 
1073 		public long FileSize64
1074 		{
1075 			get
1076 			{
1077 				lock (lockObj)
1078 				{
1079 					if (p != null)
1080 					{
1081 						return p.Length;
1082 					}
1083 					else
1084 					{
1085 						if (hamMode)
1086 						{
1087 							return (long)hamBuf.Size;
1088 						}
1089 					}
1090 
1091 					return 0;
1092 				}
1093 			}
1094 		}
1095 		public int FileSize
1096 		{
1097 			get
1098 			{
1099 				long size64 = this.FileSize64;
1100 
1101 				if (size64 >= 2147483647)
1102 				{
1103 					size64 = 2147483647;
1104 				}
1105 
1106 				return (int)size64;
1107 			}
1108 		}
GetFileSize(string name)1109 		public static int GetFileSize(string name)
1110 		{
1111 			IO io = IO.FileOpen(name, false);
1112 			try
1113 			{
1114 				return io.FileSize;
1115 			}
1116 			finally
1117 			{
1118 				io.Close();
1119 			}
1120 		}
1121 
ReadAll()1122 		public byte[] ReadAll()
1123 		{
1124 			this.Seek(SeekOrigin.Begin, 0);
1125 			int size = this.FileSize;
1126 
1127 			byte[] data = new byte[size];
1128 			this.Read(data, 0, size);
1129 
1130 			this.Seek(SeekOrigin.Begin, 0);
1131 
1132 			return data;
1133 		}
1134 
Read(int size)1135 		public byte[] Read(int size)
1136 		{
1137 			byte[] buf = new byte[size];
1138 			bool ret = Read(buf, size);
1139 			if (ret == false)
1140 			{
1141 				return null;
1142 			}
1143 			return buf;
1144 		}
Read(byte[] buf, int size)1145 		public bool Read(byte[] buf, int size)
1146 		{
1147 			return Read(buf, 0, size);
1148 		}
Read(byte[] buf, int offset, int size)1149 		public bool Read(byte[] buf, int offset, int size)
1150 		{
1151 			if (size == 0)
1152 			{
1153 				return true;
1154 			}
1155 
1156 			lock (lockObj)
1157 			{
1158 				if (this.HamMode)
1159 				{
1160 					byte[] ret = hamBuf.Read((uint)size);
1161 
1162 					if (ret.Length != size)
1163 					{
1164 						return false;
1165 					}
1166 
1167 					Util.CopyByte(buf, offset, ret, 0, size);
1168 
1169 					return true;
1170 				}
1171 
1172 				if (p != null)
1173 				{
1174 					try
1175 					{
1176 						int ret = p.Read(buf, offset, size);
1177 						if (ret == size)
1178 						{
1179 							return true;
1180 						}
1181 						else
1182 						{
1183 							return false;
1184 						}
1185 					}
1186 					catch
1187 					{
1188 						return false;
1189 					}
1190 				}
1191 				else
1192 				{
1193 					return false;
1194 				}
1195 			}
1196 		}
1197 
Write(byte[] buf)1198 		public bool Write(byte[] buf)
1199 		{
1200 			return Write(buf, 0, buf.Length);
1201 		}
Write(byte[] buf, int size)1202 		public bool Write(byte[] buf, int size)
1203 		{
1204 			return Write(buf, 0, size);
1205 		}
Write(byte[] buf, int offset, int size)1206 		public bool Write(byte[] buf, int offset, int size)
1207 		{
1208 			if (writeMode == false)
1209 			{
1210 				return false;
1211 			}
1212 			if (size == 0)
1213 			{
1214 				return true;
1215 			}
1216 
1217 			lock (lockObj)
1218 			{
1219 				if (p != null)
1220 				{
1221 					try
1222 					{
1223 						p.Write(buf, offset, size);
1224 
1225 						return true;
1226 					}
1227 					catch
1228 					{
1229 						return false;
1230 					}
1231 				}
1232 				else
1233 				{
1234 					return false;
1235 				}
1236 			}
1237 		}
1238 
CloseAndDelete()1239 		public bool CloseAndDelete()
1240 		{
1241 			string name = this.Name;
1242 
1243 			Close();
1244 
1245 			try
1246 			{
1247 				FileDelete(name);
1248 				return true;
1249 			}
1250 			catch
1251 			{
1252 				return false;
1253 			}
1254 		}
1255 
Close()1256 		public void Close()
1257 		{
1258 			Close(false);
1259 		}
Close(bool noFlush)1260 		public void Close(bool noFlush)
1261 		{
1262 			lock (this.lockObj)
1263 			{
1264 				if (this.hamMode == false)
1265 				{
1266 					if (this.p != null)
1267 					{
1268 						if (this.writeMode && noFlush == false)
1269 						{
1270 							Flush();
1271 						}
1272 
1273 						this.p.Close();
1274 					}
1275 
1276 					this.p = null;
1277 				}
1278 			}
1279 		}
1280 
Flush()1281 		public void Flush()
1282 		{
1283 			try
1284 			{
1285 				lock (this.lockObj)
1286 				{
1287 					if (this.p != null)
1288 					{
1289 						this.p.Flush();
1290 					}
1291 				}
1292 			}
1293 			catch
1294 			{
1295 			}
1296 		}
1297 
fileCreateInner(string name)1298 		static IO fileCreateInner(string name)
1299 		{
1300 			IO o = new IO();
1301 
1302 			string name2 = ConvertPath(name);
1303 
1304 			lock (o.lockObj)
1305 			{
1306 				o.p = File.Open(name2, FileMode.Create, FileAccess.ReadWrite, FileShare.Read);
1307 				o.name = name2;
1308 				o.writeMode = true;
1309 			}
1310 
1311 			return o;
1312 		}
1313 
FileCreate(string name)1314 		public static IO FileCreate(string name)
1315 		{
1316 			name = InnerFilePath(name);
1317 
1318 			return fileCreateInner(name);
1319 		}
1320 
fileOpenInner(string name, bool writeMode, bool readLock)1321 		static IO fileOpenInner(string name, bool writeMode, bool readLock)
1322 		{
1323 			IO o = new IO();
1324 
1325 			string name2 = ConvertPath(name);
1326 
1327 			lock (o.lockObj)
1328 			{
1329 				o.p = File.Open(name2, FileMode.Open, (writeMode ? FileAccess.ReadWrite : FileAccess.Read),
1330 					(readLock ? FileShare.None : FileShare.Read));
1331 
1332 				o.name = name2;
1333 				o.writeMode = writeMode;
1334 			}
1335 
1336 			return o;
1337 		}
1338 
FileOpen(string name)1339 		public static IO FileOpen(string name)
1340 		{
1341 			return FileOpen(name, false);
1342 		}
FileOpen(string name, bool writeMode)1343 		public static IO FileOpen(string name, bool writeMode)
1344 		{
1345 			return FileOpen(name, writeMode, false);
1346 		}
FileOpen(string name, bool writeMode, bool readLock)1347 		public static IO FileOpen(string name, bool writeMode, bool readLock)
1348 		{
1349 			name = InnerFilePath(name);
1350 
1351 			if (name[0] == '|')
1352 			{
1353 				HamCore hc = IO.HamCore;
1354 
1355 				Buf b = hc.ReadHamcore(name);
1356 				if (b == null)
1357 				{
1358 					throw new FileNotFoundException();
1359 				}
1360 
1361 				IO o = new IO();
1362 				o.name = name.Substring(1);
1363 				o.hamMode = true;
1364 				o.hamBuf = b;
1365 
1366 				return o;
1367 			}
1368 			else
1369 			{
1370 				return fileOpenInner(name, writeMode, readLock);
1371 			}
1372 		}
1373 
FileCreateOrAppendOpen(string name)1374 		public static IO FileCreateOrAppendOpen(string name)
1375 		{
1376 			if (IsFileExists(name))
1377 			{
1378 				IO io = FileOpen(name, true);
1379 				io.Seek(SeekOrigin.End, 0);
1380 				return io;
1381 			}
1382 			else
1383 			{
1384 				return FileCreate(name);
1385 			}
1386 		}
1387 
GetRelativeFileName(string fileName, string baseDirName)1388 		public static string GetRelativeFileName(string fileName, string baseDirName)
1389 		{
1390 			baseDirName = RemoteLastEnMark(baseDirName).Trim() + "\\";
1391 			fileName = fileName.Trim();
1392 
1393 			if (fileName.Length <= baseDirName.Length)
1394 			{
1395 				throw new ArgumentException("fileName, baseDirName");
1396 			}
1397 
1398 			if (fileName.StartsWith(baseDirName, StringComparison.InvariantCultureIgnoreCase) == false)
1399 			{
1400 				throw new ArgumentException("fileName, baseDirName");
1401 			}
1402 
1403 			return fileName.Substring(baseDirName.Length);
1404 		}
1405 
RemoteLastEnMark(string path)1406 		public static string RemoteLastEnMark(string path)
1407 		{
1408 			if (path == null)
1409 			{
1410 				path = "";
1411 			}
1412 			if (path.EndsWith("\\"))
1413 			{
1414 				path = path.Substring(0, path.Length - 1);
1415 			}
1416 			return path;
1417 		}
1418 
FileRename(string oldName, string newName)1419 		public static void FileRename(string oldName, string newName)
1420 		{
1421 			string tmp1 = InnerFilePath(oldName);
1422 			string tmp2 = InnerFilePath(newName);
1423 
1424 			File.Move(tmp1, tmp2);
1425 		}
1426 
DeleteFilesAndSubDirsInDir(string dirName)1427 		public static void DeleteFilesAndSubDirsInDir(string dirName)
1428 		{
1429 			dirName = InnerFilePath(dirName);
1430 
1431 			if (Directory.Exists(dirName) == false)
1432 			{
1433 				Directory.CreateDirectory(dirName);
1434 				return;
1435 			}
1436 
1437 			string[] files = Directory.GetFiles(dirName);
1438 			string[] dirs = Directory.GetDirectories(dirName);
1439 
1440 			foreach (string file in files)
1441 			{
1442 				File.SetAttributes(file, FileAttributes.Normal);
1443 				File.Delete(file);
1444 			}
1445 
1446 			foreach (string dir in dirs)
1447 			{
1448 				Directory.Delete(dir, true);
1449 			}
1450 		}
1451 
DeleteDir(string dirName)1452 		public static bool DeleteDir(string dirName)
1453 		{
1454 			return DeleteDir(dirName, false);
1455 		}
DeleteDir(string dirName, bool deleteSubDirs)1456 		public static bool DeleteDir(string dirName, bool deleteSubDirs)
1457 		{
1458 			try
1459 			{
1460 				Directory.Delete(InnerFilePath(dirName), deleteSubDirs);
1461 				return true;
1462 			}
1463 			catch
1464 			{
1465 				return false;
1466 			}
1467 		}
1468 
MakeDir(string dirName)1469 		public static bool MakeDir(string dirName)
1470 		{
1471 			try
1472 			{
1473 				Directory.CreateDirectory(InnerFilePath(dirName));
1474 				return true;
1475 			}
1476 			catch
1477 			{
1478 				return false;
1479 			}
1480 		}
MakeDirIfNotExists(string dirName)1481 		public static bool MakeDirIfNotExists(string dirName)
1482 		{
1483 			string path = InnerFilePath(dirName);
1484 
1485 			if (Directory.Exists(path) == false)
1486 			{
1487 				Directory.CreateDirectory(path);
1488 
1489 				return true;
1490 			}
1491 
1492 			return false;
1493 		}
1494 
NormalizePath(string src)1495 		public static string NormalizePath(string src)
1496 		{
1497 			bool first_double_slash = false;
1498 			bool first_single_slash = false;
1499 			string win32_drive_char = "";
1500 			int i;
1501 			string tmp;
1502 
1503 			tmp = ConvertPath(src).Trim();
1504 
1505 			if (tmp.StartsWith(".\\") || tmp.StartsWith("..\\") || tmp.StartsWith(".") || tmp.StartsWith(".."))
1506 			{
1507 				if (tmp.StartsWith(".."))
1508 				{
1509 					tmp = Env.CurrentDir + "/../" + tmp.Substring(2);
1510 				}
1511 				else
1512 				{
1513 					tmp = Env.CurrentDir + "/" + tmp;
1514 				}
1515 			}
1516 
1517 			if (tmp.StartsWith("~/") || tmp.StartsWith("~\\"))
1518 			{
1519 				tmp = Env.HomeDir + "/" + tmp.Substring(2);
1520 			}
1521 
1522 			if (tmp.StartsWith("//") || tmp.StartsWith("\\\\"))
1523 			{
1524 				first_double_slash = true;
1525 			}
1526 			else
1527 			{
1528 				if (tmp.StartsWith("/") || tmp.StartsWith("\\"))
1529 				{
1530 					first_single_slash = true;
1531 				}
1532 			}
1533 
1534 			if (tmp.Length >= 2)
1535 			{
1536 				if (tmp[1] == ':')
1537 				{
1538 					win32_drive_char = "" + tmp[0];
1539 					tmp = tmp.Substring(2);
1540 				}
1541 			}
1542 
1543 			if (tmp == "/" || tmp == "\\")
1544 			{
1545 				tmp = "";
1546 			}
1547 
1548 			char[] splitChars = { '/', '\\' };
1549 			string[] t = tmp.Split(splitChars, StringSplitOptions.RemoveEmptyEntries);
1550 
1551 			Stack<string> sk = new Stack<string>();
1552 
1553 			for (i = 0; i < t.Length; i++)
1554 			{
1555 				string s = t[i];
1556 
1557 				if (Str.StrCmpi(s, "."))
1558 				{
1559 					continue;
1560 				}
1561 				else if (Str.StrCmpi(s, ".."))
1562 				{
1563 					if (sk.Count >= 1 && (first_double_slash == false || sk.Count >= 2))
1564 					{
1565 						sk.Pop();
1566 					}
1567 				}
1568 				else
1569 				{
1570 					sk.Push(s);
1571 				}
1572 			}
1573 
1574 			tmp = "";
1575 
1576 			if (first_double_slash)
1577 			{
1578 				tmp += "//";
1579 			}
1580 			else if (first_single_slash)
1581 			{
1582 				tmp += "/";
1583 			}
1584 
1585 			if (Str.IsEmptyStr(win32_drive_char) == false)
1586 			{
1587 				tmp = win32_drive_char + ":/" + tmp;
1588 			}
1589 
1590 			string[] sks = sk.ToArray();
1591 			Array.Reverse(sks);
1592 			for (i = 0; i < sks.Length; i++)
1593 			{
1594 				tmp += sks[i];
1595 				if (i != (sks.Length - 1))
1596 				{
1597 					tmp += "/";
1598 				}
1599 			}
1600 
1601 			tmp = ConvertPath(tmp);
1602 
1603 			return tmp;
1604 		}
1605 
ConvertPath(string path)1606 		public static string ConvertPath(string path)
1607 		{
1608 			return path.Replace('/', '\\');
1609 		}
1610 
ConbinePath(string dirname, string filename)1611 		public static string ConbinePath(string dirname, string filename)
1612 		{
1613 			return CombinePath(dirname, filename);
1614 		}
CombinePath(string dirname, string filename)1615 		public static string CombinePath(string dirname, string filename)
1616 		{
1617 			bool is_full_path;
1618 			string filename_ident = NormalizePath(filename);
1619 
1620 			is_full_path = false;
1621 
1622 			if (filename_ident.StartsWith("\\") || filename_ident.StartsWith("/"))
1623 			{
1624 				is_full_path = true;
1625 			}
1626 
1627 			filename = filename_ident;
1628 
1629 			if (filename.Length >= 2)
1630 			{
1631 				char c = filename[0];
1632 				if (('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z'))
1633 				{
1634 					if (filename[1] == ':')
1635 					{
1636 						is_full_path = true;
1637 					}
1638 				}
1639 			}
1640 
1641 			string tmp;
1642 
1643 			if (is_full_path == false)
1644 			{
1645 				tmp = dirname;
1646 				if (tmp.EndsWith("/") == false && tmp.EndsWith("\\") == false)
1647 				{
1648 					tmp += "/";
1649 				}
1650 
1651 				tmp += filename;
1652 			}
1653 			else
1654 			{
1655 				tmp = filename;
1656 			}
1657 
1658 			return NormalizePath(tmp);
1659 		}
1660 
InnerFilePath(string src)1661 		public static string InnerFilePath(string src)
1662 		{
1663 			if (src[0] != '@')
1664 			{
1665 				return NormalizePath(src);
1666 			}
1667 			else
1668 			{
1669 				return CombinePath(Env.ExeFileDir, src.Substring(1));
1670 			}
1671 		}
1672 
GetCreationTimeUtc(string filename)1673 		public static DateTime GetCreationTimeUtc(string filename)
1674 		{
1675 			return File.GetCreationTimeUtc(InnerFilePath(filename));
1676 		}
GetCreationTimeLocal(string filename)1677 		public static DateTime GetCreationTimeLocal(string filename)
1678 		{
1679 			return File.GetCreationTime(InnerFilePath(filename));
1680 		}
1681 
GetLastWriteTimeUtc(string filename)1682 		public static DateTime GetLastWriteTimeUtc(string filename)
1683 		{
1684 			return File.GetLastWriteTimeUtc(InnerFilePath(filename));
1685 		}
GetLastWriteTimeLocal(string filename)1686 		public static DateTime GetLastWriteTimeLocal(string filename)
1687 		{
1688 			return File.GetLastWriteTime(InnerFilePath(filename));
1689 		}
1690 
GetLastAccessTimeUtc(string filename)1691 		public static DateTime GetLastAccessTimeUtc(string filename)
1692 		{
1693 			return File.GetLastAccessTimeUtc(InnerFilePath(filename));
1694 		}
GetLastAccessTimeLocal(string filename)1695 		public static DateTime GetLastAccessTimeLocal(string filename)
1696 		{
1697 			return File.GetLastAccessTime(InnerFilePath(filename));
1698 		}
1699 
ReadFileData(string filename)1700 		public static byte[] ReadFileData(string filename)
1701 		{
1702 			FileStream fs = new FileStream(filename, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
1703 			try
1704 			{
1705 				long size = fs.Length;
1706 				int size2 = (int)Math.Min(size, int.MaxValue);
1707 				byte[] ret = new byte[size2];
1708 				fs.Read(ret, 0, size2);
1709 				return ret;
1710 			}
1711 			finally
1712 			{
1713 				fs.Close();
1714 			}
1715 		}
1716 	}
1717 }
1718