Utility.cs 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443
  1. using System;
  2. using System.Collections.Generic;
  3. using System.IO;
  4. using System.Linq;
  5. using System.Reflection;
  6. using System.Reflection.Emit;
  7. using System.Runtime.InteropServices;
  8. #if NETCORE
  9. using SharpCompress.Buffers;
  10. #endif
  11. using SharpCompress.Readers;
  12. namespace SharpCompress
  13. {
  14. internal static class Utility
  15. {
  16. public static ReadOnlyCollection<T> ToReadOnly<T>(this IEnumerable<T> items)
  17. {
  18. return new ReadOnlyCollection<T>(items.ToList());
  19. }
  20. /// <summary>
  21. /// Performs an unsigned bitwise right shift with the specified number
  22. /// </summary>
  23. /// <param name="number">Number to operate on</param>
  24. /// <param name="bits">Ammount of bits to shift</param>
  25. /// <returns>The resulting number from the shift operation</returns>
  26. public static int URShift(int number, int bits)
  27. {
  28. if (number >= 0)
  29. {
  30. return number >> bits;
  31. }
  32. return (number >> bits) + (2 << ~bits);
  33. }
  34. /// <summary>
  35. /// Performs an unsigned bitwise right shift with the specified number
  36. /// </summary>
  37. /// <param name="number">Number to operate on</param>
  38. /// <param name="bits">Ammount of bits to shift</param>
  39. /// <returns>The resulting number from the shift operation</returns>
  40. public static long URShift(long number, int bits)
  41. {
  42. if (number >= 0)
  43. {
  44. return number >> bits;
  45. }
  46. return (number >> bits) + (2L << ~bits);
  47. }
  48. /// <summary>
  49. /// Fills the array with an specific value from an specific index to an specific index.
  50. /// </summary>
  51. /// <param name="array">The array to be filled.</param>
  52. /// <param name="fromindex">The first index to be filled.</param>
  53. /// <param name="toindex">The last index to be filled.</param>
  54. /// <param name="val">The value to fill the array with.</param>
  55. public static void Fill<T>(T[] array, int fromindex, int toindex, T val) where T : struct
  56. {
  57. if (array.Length == 0)
  58. {
  59. throw new NullReferenceException();
  60. }
  61. if (fromindex > toindex)
  62. {
  63. throw new ArgumentException();
  64. }
  65. if ((fromindex < 0) || array.Length < toindex)
  66. {
  67. throw new IndexOutOfRangeException();
  68. }
  69. for (int index = (fromindex > 0) ? fromindex-- : fromindex; index < toindex; index++)
  70. {
  71. array[index] = val;
  72. }
  73. }
  74. #if NET45
  75. // super fast memset, up to 40x faster than for loop on large arrays
  76. // see https://stackoverflow.com/questions/1897555/what-is-the-equivalent-of-memset-in-c
  77. private static readonly Action<IntPtr, byte, uint> MemsetDelegate = CreateMemsetDelegate();
  78. private static Action<IntPtr, byte, uint> CreateMemsetDelegate() {
  79. var dynamicMethod = new DynamicMethod(
  80. "Memset",
  81. MethodAttributes.Public | MethodAttributes.Static,
  82. CallingConventions.Standard,
  83. null,
  84. new[] { typeof(IntPtr), typeof(byte), typeof(uint) },
  85. typeof(Utility),
  86. true);
  87. var generator = dynamicMethod.GetILGenerator();
  88. generator.Emit(OpCodes.Ldarg_0);
  89. generator.Emit(OpCodes.Ldarg_1);
  90. generator.Emit(OpCodes.Ldarg_2);
  91. generator.Emit(OpCodes.Initblk);
  92. generator.Emit(OpCodes.Ret);
  93. return (Action<IntPtr, byte, uint>)dynamicMethod.CreateDelegate(typeof(Action<IntPtr, byte, uint>));
  94. }
  95. public static void Memset(byte[] array, byte what, int length)
  96. {
  97. var gcHandle = GCHandle.Alloc(array, GCHandleType.Pinned);
  98. MemsetDelegate(gcHandle.AddrOfPinnedObject(), what, (uint)length);
  99. gcHandle.Free();
  100. }
  101. #else
  102. public static void Memset(byte[] array, byte what, int length)
  103. {
  104. for(var i = 0; i < length; i++)
  105. {
  106. array[i] = what;
  107. }
  108. }
  109. #endif
  110. public static void Memset<T>(T[] array, T what, int length)
  111. {
  112. for(var i = 0; i < length; i++)
  113. {
  114. array[i] = what;
  115. }
  116. }
  117. public static void FillFast<T>(T[] array, T val) where T : struct
  118. {
  119. for (int i = 0; i < array.Length; i++)
  120. {
  121. array[i] = val;
  122. }
  123. }
  124. public static void FillFast<T>(T[] array, int start, int length, T val) where T : struct
  125. {
  126. int toIndex = start + length;
  127. for (int i = start; i < toIndex; i++)
  128. {
  129. array[i] = val;
  130. }
  131. }
  132. /// <summary>
  133. /// Fills the array with an specific value.
  134. /// </summary>
  135. /// <param name="array">The array to be filled.</param>
  136. /// <param name="val">The value to fill the array with.</param>
  137. public static void Fill<T>(T[] array, T val) where T : struct
  138. {
  139. Fill(array, 0, array.Length, val);
  140. }
  141. public static void SetSize(this List<byte> list, int count)
  142. {
  143. if (count > list.Count)
  144. {
  145. for (int i = list.Count; i < count; i++)
  146. {
  147. list.Add(0x0);
  148. }
  149. }
  150. else
  151. {
  152. byte[] temp = new byte[count];
  153. list.CopyTo(temp, 0);
  154. list.Clear();
  155. list.AddRange(temp);
  156. }
  157. }
  158. public static void AddRange<T>(this ICollection<T> destination, IEnumerable<T> source)
  159. {
  160. foreach (T item in source)
  161. {
  162. destination.Add(item);
  163. }
  164. }
  165. public static void ForEach<T>(this IEnumerable<T> items, Action<T> action)
  166. {
  167. foreach (T item in items)
  168. {
  169. action(item);
  170. }
  171. }
  172. public static void Copy(Array sourceArray, long sourceIndex, Array destinationArray, long destinationIndex, long length)
  173. {
  174. if (sourceIndex > Int32.MaxValue || sourceIndex < Int32.MinValue)
  175. throw new ArgumentOutOfRangeException();
  176. if (destinationIndex > Int32.MaxValue || destinationIndex < Int32.MinValue)
  177. throw new ArgumentOutOfRangeException();
  178. if (length > Int32.MaxValue || length < Int32.MinValue)
  179. throw new ArgumentOutOfRangeException();
  180. Array.Copy(sourceArray, (int)sourceIndex, destinationArray, (int)destinationIndex, (int)length);
  181. }
  182. public static IEnumerable<T> AsEnumerable<T>(this T item)
  183. {
  184. yield return item;
  185. }
  186. public static void CheckNotNull(this object obj, string name)
  187. {
  188. if (obj == null)
  189. {
  190. throw new ArgumentNullException(name);
  191. }
  192. }
  193. public static void CheckNotNullOrEmpty(this string obj, string name)
  194. {
  195. obj.CheckNotNull(name);
  196. if (obj.Length == 0)
  197. {
  198. throw new ArgumentException("String is empty.");
  199. }
  200. }
  201. public static void Skip(this Stream source, long advanceAmount)
  202. {
  203. if (source.CanSeek)
  204. {
  205. source.Position += advanceAmount;
  206. return;
  207. }
  208. byte[] buffer = GetTransferByteArray();
  209. try
  210. {
  211. int read = 0;
  212. int readCount = 0;
  213. do
  214. {
  215. readCount = buffer.Length;
  216. if (readCount > advanceAmount)
  217. {
  218. readCount = (int)advanceAmount;
  219. }
  220. read = source.Read(buffer, 0, readCount);
  221. if (read <= 0)
  222. {
  223. break;
  224. }
  225. advanceAmount -= read;
  226. if (advanceAmount == 0)
  227. {
  228. break;
  229. }
  230. }
  231. while (true);
  232. }
  233. finally
  234. {
  235. #if NETCORE
  236. ArrayPool<byte>.Shared.Return(buffer);
  237. #endif
  238. }
  239. }
  240. public static void Skip(this Stream source)
  241. {
  242. byte[] buffer = GetTransferByteArray();
  243. try
  244. {
  245. do
  246. {
  247. }
  248. while (source.Read(buffer, 0, buffer.Length) == buffer.Length);
  249. }
  250. finally
  251. {
  252. #if NETCORE
  253. ArrayPool<byte>.Shared.Return(buffer);
  254. #endif
  255. }
  256. }
  257. public static DateTime DosDateToDateTime(UInt16 iDate, UInt16 iTime)
  258. {
  259. int year = iDate / 512 + 1980;
  260. int month = iDate % 512 / 32;
  261. int day = iDate % 512 % 32;
  262. int hour = iTime / 2048;
  263. int minute = iTime % 2048 / 32;
  264. int second = iTime % 2048 % 32 * 2;
  265. if (iDate == UInt16.MaxValue || month == 0 || day == 0)
  266. {
  267. year = 1980;
  268. month = 1;
  269. day = 1;
  270. }
  271. if (iTime == UInt16.MaxValue)
  272. {
  273. hour = minute = second = 0;
  274. }
  275. DateTime dt;
  276. try
  277. {
  278. dt = new DateTime(year, month, day, hour, minute, second, DateTimeKind.Local);
  279. }
  280. catch
  281. {
  282. dt = new DateTime();
  283. }
  284. return dt;
  285. }
  286. public static uint DateTimeToDosTime(this DateTime? dateTime)
  287. {
  288. if (dateTime == null)
  289. {
  290. return 0;
  291. }
  292. var localDateTime = dateTime.Value.ToLocalTime();
  293. return (uint)(
  294. (localDateTime.Second / 2) | (localDateTime.Minute << 5) | (localDateTime.Hour << 11) |
  295. (localDateTime.Day << 16) | (localDateTime.Month << 21) |
  296. ((localDateTime.Year - 1980) << 25));
  297. }
  298. public static DateTime DosDateToDateTime(UInt32 iTime)
  299. {
  300. return DosDateToDateTime((UInt16)(iTime / 65536),
  301. (UInt16)(iTime % 65536));
  302. }
  303. /// <summary>
  304. /// Convert Unix time value to a DateTime object.
  305. /// </summary>
  306. /// <param name="unixtime">The Unix time stamp you want to convert to DateTime.</param>
  307. /// <returns>Returns a DateTime object that represents value of the Unix time.</returns>
  308. public static DateTime UnixTimeToDateTime(long unixtime)
  309. {
  310. DateTime sTime = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
  311. return sTime.AddSeconds(unixtime);
  312. }
  313. public static long TransferTo(this Stream source, Stream destination)
  314. {
  315. byte[] array = GetTransferByteArray();
  316. try
  317. {
  318. int count;
  319. long total = 0;
  320. while (ReadTransferBlock(source, array, out count))
  321. {
  322. total += count;
  323. destination.Write(array, 0, count);
  324. }
  325. return total;
  326. }
  327. finally
  328. {
  329. #if NETCORE
  330. ArrayPool<byte>.Shared.Return(array);
  331. #endif
  332. }
  333. }
  334. public static long TransferTo(this Stream source, Stream destination, Common.Entry entry, IReaderExtractionListener readerExtractionListener)
  335. {
  336. byte[] array = GetTransferByteArray();
  337. try
  338. {
  339. int count;
  340. var iterations = 0;
  341. long total = 0;
  342. while (ReadTransferBlock(source, array, out count))
  343. {
  344. total += count;
  345. destination.Write(array, 0, count);
  346. iterations++;
  347. readerExtractionListener.FireEntryExtractionProgress(entry, total, iterations);
  348. }
  349. return total;
  350. }
  351. finally
  352. {
  353. #if NETCORE
  354. ArrayPool<byte>.Shared.Return(array);
  355. #endif
  356. }
  357. }
  358. private static bool ReadTransferBlock(Stream source, byte[] array, out int count)
  359. {
  360. return (count = source.Read(array, 0, array.Length)) != 0;
  361. }
  362. private static byte[] GetTransferByteArray()
  363. {
  364. #if NETCORE
  365. return ArrayPool<byte>.Shared.Rent(81920);
  366. #else
  367. return new byte[81920];
  368. #endif
  369. }
  370. public static bool ReadFully(this Stream stream, byte[] buffer)
  371. {
  372. int total = 0;
  373. int read;
  374. while ((read = stream.Read(buffer, total, buffer.Length - total)) > 0)
  375. {
  376. total += read;
  377. if (total >= buffer.Length)
  378. {
  379. return true;
  380. }
  381. }
  382. return (total >= buffer.Length);
  383. }
  384. public static string TrimNulls(this string source)
  385. {
  386. return source.Replace('\0', ' ').Trim();
  387. }
  388. public static bool BinaryEquals(this byte[] source, byte[] target)
  389. {
  390. if (source.Length != target.Length)
  391. {
  392. return false;
  393. }
  394. for (int i = 0; i < source.Length; ++i)
  395. {
  396. if (source[i] != target[i])
  397. {
  398. return false;
  399. }
  400. }
  401. return true;
  402. }
  403. }
  404. }