You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1033 lines
38 KiB

  1. using Apewer.Internals;
  2. using Externals.Compression.Checksums;
  3. using Externals.Compression.Zip;
  4. using System;
  5. using System.Collections.Generic;
  6. using System.Diagnostics;
  7. using System.IO;
  8. using System.IO.Compression;
  9. using System.Security.Cryptography;
  10. using System.Text;
  11. namespace Apewer
  12. {
  13. /// <summary>二进制。</summary>
  14. public class BinaryUtility
  15. {
  16. /// <summary>空字节数组,每次获取都将创建新的引用。</summary>
  17. public static byte[] EmptyBytes { get => new byte[0]; }
  18. #region ASCII
  19. /// <summary>CRLF。</summary>
  20. public static byte[] CRLF { get => new byte[] { 13, 10 }; }
  21. /// <summary>0x00 空字符。</summary>
  22. public static byte[] NULL { get => new byte[] { 0x00 }; }
  23. #endregion
  24. #region Bytes Array
  25. /// <summary>克隆字节数组。当源为 NULL 时获取零元素字节数组。</summary>
  26. public static byte[] Clone(byte[] bytes)
  27. {
  28. if (bytes == null || bytes.LongLength < 0L) return EmptyBytes;
  29. var result = new byte[bytes.LongLength];
  30. bytes.CopyTo(result, 0L);
  31. return result;
  32. }
  33. /// <summary>创建数组,元素值为零。</summary>
  34. public static byte[] ZeroArray(int length = 0)
  35. {
  36. if (length < 1) return new byte[0];
  37. var array = new byte[length];
  38. for (int i = 0; i < length; i++) array[i] = 0;
  39. return array;
  40. }
  41. /// <summary>所有字节取反。</summary>
  42. public static byte[] Adverse(byte[] bytes)
  43. {
  44. if (bytes == null || bytes.LongLength < 1L) return EmptyBytes;
  45. var adverse = new byte[bytes.LongLength];
  46. for (var i = 0L; i < bytes.LongLength; i++) adverse[i] = Convert.ToByte(255 - bytes[i]);
  47. return adverse;
  48. }
  49. /// <summary>确定此字节数组实例的开头是否与指定的字节数组匹配。</summary>
  50. public static bool StartsWith(byte[] bytes, params byte[] head)
  51. {
  52. var data = bytes;
  53. if (data == null) return false;
  54. if (head == null) return false;
  55. var datalength = data.LongLength;
  56. var headlength = head.LongLength;
  57. if (datalength < headlength) return false;
  58. if (headlength < 1L) return true;
  59. for (long i = 0; i < head.LongLength; i++)
  60. {
  61. if (data[i] != head[i]) return false;
  62. }
  63. return true;
  64. }
  65. /// <summary>确定此字节数组实例的结尾是否与指定的字节数组匹配。</summary>
  66. public static bool EndsWith(byte[] bytes, params byte[] end)
  67. {
  68. if (bytes == null) return false;
  69. if (end == null) return false;
  70. var dataLength = bytes.LongLength;
  71. var endLength = end.LongLength;
  72. if (dataLength < endLength) return false;
  73. if (endLength < 1L) return true;
  74. for (long i = 0; i < endLength; i++)
  75. {
  76. var dataindex = dataLength - i - 1;
  77. var headindex = endLength - i - 1;
  78. if (bytes[dataindex] != end[headindex]) return false;
  79. }
  80. return true;
  81. }
  82. /// <summary>合并字节数组。</summary>
  83. public static byte[] Merge(IEnumerable<byte[]> array)
  84. {
  85. if (array == null) return EmptyBytes;
  86. var total = 0L;
  87. foreach (var bytes in array)
  88. {
  89. if (bytes == null) continue;
  90. total += bytes.LongLength;
  91. }
  92. var result = new byte[total];
  93. var offset = 0L;
  94. if (total > 0)
  95. {
  96. foreach (var bytes in array)
  97. {
  98. if (bytes == null) continue;
  99. var length = bytes.LongLength;
  100. if (length < 1L) continue;
  101. Array.Copy(bytes, 0L, result, offset, length);
  102. offset += length;
  103. }
  104. }
  105. return result;
  106. }
  107. /// <summary>合并字节数组。</summary>
  108. public static byte[] Merge(params byte[][] array) => Merge(array as IEnumerable<byte[]>);
  109. /// <summary>为字节数组增加字节。</summary>
  110. public static byte[] Append(byte[] head, params byte[] bytes) => Merge(head, bytes);
  111. /// <summary>为文本数据添加 BOM 字节,若已存在则忽略。</summary>
  112. public static byte[] AddTextBom(params byte[] bytes)
  113. {
  114. var bom = new byte[] { 0xEF, 0xBB, 0xBF };
  115. if (bytes == null || bytes.LongLength < 1L) return bom;
  116. var hasBom = (bytes.Length >= 3) && (bytes[0] == 0xEF) && (bytes[1] == 0xBB) && (bytes[2] == 0xBF);
  117. return hasBom ? Merge(bytes) : Merge(bom, bytes);
  118. }
  119. /// <summary>去除文本数据的 BOM 字节,若不存在则忽略。</summary>
  120. public static byte[] WipeTextBom(byte[] bytes)
  121. {
  122. if (bytes == null) return EmptyBytes;
  123. var hasBom = (bytes.Length >= 3) && (bytes[0] == 0xEF) && (bytes[1] == 0xBB) && (bytes[2] == 0xBF);
  124. var offset = hasBom ? 3 : 0;
  125. var length = bytes.Length - offset;
  126. var wiped = new byte[length];
  127. if (length > 0) Array.Copy(bytes, offset, wiped, 0, length);
  128. return wiped;
  129. }
  130. /// <summary>生成新的 GUID 数据。</summary>
  131. public static byte[] NewGuid() => Guid.NewGuid().ToByteArray();
  132. #endregion
  133. #region Text
  134. /// <summary>将字节数组转换为十六进制文本。</summary>
  135. public static string ToHex(params byte[] bytes)
  136. {
  137. int length = bytes.Length;
  138. if (length > 0)
  139. {
  140. var sb = new StringBuilder();
  141. for (int i = 0; i < length; i++)
  142. {
  143. sb.Append(Constant.HexCollection[bytes[i] / 16]);
  144. sb.Append(Constant.HexCollection[bytes[i] % 16]);
  145. }
  146. return sb.ToString();
  147. }
  148. return "";
  149. }
  150. /// <summary>将十六进制文本转换为字节数组。</summary>
  151. public static byte[] FromHex(string hex)
  152. {
  153. if (string.IsNullOrEmpty(hex) || hex.Length < 2) return EmptyBytes;
  154. if (hex.Length % 2 != 0) return EmptyBytes;
  155. var lower = hex.ToLower().ToCharArray();
  156. var half = lower.Length / 2;
  157. var bytes = new byte[half];
  158. for (var i = 0; i < half; i++)
  159. {
  160. var offset = i * 2;
  161. var h = Constant.HexCollection.IndexOf(lower[offset]);
  162. var l = Constant.HexCollection.IndexOf(lower[offset + 1]);
  163. if (h < 0 || l < 0) return EmptyBytes;
  164. bytes[i] = Convert.ToByte((h * 16) + l);
  165. }
  166. return bytes;
  167. }
  168. /// <summary>将字节数组格式化为大写十六进制字符串。</summary>
  169. public static string ToX2(params byte[] bytes)
  170. {
  171. if (bytes == null) return "";
  172. var sb = new StringBuilder();
  173. for (int i = 0; i < bytes.Length; i++)
  174. {
  175. sb.Append(bytes[i].ToString("X2"));
  176. }
  177. return sb.ToString();
  178. }
  179. /// <summary>Byte[] -> Base64</summary>
  180. public static string ToBase64(params byte[] bytes)
  181. {
  182. if (bytes.Length < 1) return Constant.EmptyString;
  183. try { return Convert.ToBase64String(bytes); }
  184. catch { return Constant.EmptyString; }
  185. }
  186. /// <summary>Base64 -> Byte[]</summary>
  187. public static byte[] FromBase64(string base64)
  188. {
  189. if (string.IsNullOrEmpty(base64)) return EmptyBytes;
  190. try { return Convert.FromBase64String(base64); }
  191. catch { return EmptyBytes; }
  192. }
  193. /// <summary>转换字节数组为文本,默认使用 UTF-8 代码页。</summary>
  194. public static string ToText(byte[] bytes, Encoding encoding = null)
  195. {
  196. if (bytes.Length < 1) return Constant.EmptyString;
  197. try { return (encoding ?? Encoding.UTF8).GetString(bytes); }
  198. catch { return Constant.EmptyString; }
  199. }
  200. /// <summary>转换文本为字节数组,默认使用 UTF-8 代码页。</summary>
  201. public static byte[] FromText(string text, Encoding encoding = null)
  202. {
  203. if (string.IsNullOrEmpty(text)) return EmptyBytes;
  204. try { return (encoding ?? Encoding.UTF8).GetBytes(text); }
  205. catch { return EmptyBytes; }
  206. }
  207. /// <summary>检查字节数组包含 UTF-8 BOM 头。</summary>
  208. public static bool ContainsBOM(byte[] bytes)
  209. {
  210. if (bytes == null) return false;
  211. if (bytes.LongLength < 3L) return false;
  212. return bytes[0L] == 0xEF && bytes[1L] == 0xBB && bytes[2L] == 0xBF;
  213. }
  214. /// <summary>检查字节数组是 UTF-8 文本。可指定检查的最大字节长度。</summary>
  215. /// <param name="bytes">要检查的字节数组。</param>
  216. /// <param name="offset">已检查的偏移量。</param>
  217. /// <param name="checkLength">检查的最大字节长度。</param>
  218. public static bool IsUTF8(byte[] bytes, Class<int> offset, int checkLength = 1048576)
  219. {
  220. return IsUTF8(bytes, offset, checkLength);
  221. }
  222. /// <summary>检查字节数组是 UTF-8 文本,默认最多检测 1MB 数据。</summary>
  223. /// <param name="bytes">要检查的字节数组。</param>
  224. /// <param name="checkLength">检查的最大字节长度,指定为 0 将不限制检查长度。</param>
  225. /// <param name="offset">已检查的偏移量,用于调试。</param>
  226. public static bool IsUTF8(byte[] bytes, int checkLength = 1048576, Class<int> offset = null)
  227. {
  228. // UTF8在Unicode的基础上制定了这样一套规则:
  229. // 1.对于单字节字符,比特位的最高位为0;
  230. // 2.对于多字节字符,第一个字节的比特位中,最高位有n个1,剩下的n - 1个字节的比特位中,最高位都是10。
  231. // 好了,我知道你一定看不懂,那就先来看看下面例子后,再去看上面定义吧。
  232. // 比如一个字符(“A”),它在UTF8中的编码为(用二进制表示):01000001。由于比特位的最高位是0,表示它是单字节,它只需要1个字节就可以表示。
  233. // 再比如一个字符(“判”),它在UTF8中的编码为(用二进制表示):11100101 10001000 10100100。由于在第一个字节中,比特位最高位有3个1,说明这个字符总共需要3个字节来表示,且后3 - 1 = 2位字节中,比特位的最高位为10。
  234. if (bytes == null) return false;
  235. var length = bytes.LongLength;
  236. // 检查 BOM 头。
  237. if (ContainsBOM(bytes)) return true;
  238. var hasOffset = offset != null;
  239. var append = 0;
  240. if (hasOffset) offset.Value = 0;
  241. for (int i = 0; i < length; i++)
  242. {
  243. if (checkLength > 0 && i >= checkLength) break;
  244. var b = bytes[i];
  245. if (hasOffset) offset.Value = i;
  246. // 追加字节最高位为 0。
  247. if (append > 0)
  248. {
  249. if (b >> 6 != 2) return false;
  250. append -= 1;
  251. continue;
  252. }
  253. // ASCII 字符。
  254. if (b < 128) continue;
  255. // 2 字节 UTF-8。
  256. if (b >= 0xC0 && b <= 0xDF)
  257. {
  258. append = 1;
  259. continue;
  260. }
  261. // 3 字节 UTF-8 字符。
  262. if (b >= 0xE0 && b <= 0xEF)
  263. {
  264. append = 2;
  265. continue;
  266. }
  267. // 4 字节 UTF-8 字符。
  268. if (b >= 0xF0 && b <= 0xF7)
  269. {
  270. append = 3;
  271. continue;
  272. }
  273. // 5 字节 UTF-8 字符。
  274. if (b >= 0xF8 && b <= 0xFB)
  275. {
  276. append = 4;
  277. continue;
  278. }
  279. // 6 字节 UTF-8 字符。
  280. if (b >= 0xFC && b <= 0xFD)
  281. {
  282. append = 5;
  283. continue;
  284. }
  285. // 未知字节,非 UTF-8 定义。
  286. return false;
  287. }
  288. return true;
  289. }
  290. #endregion
  291. #region 压缩、解压。
  292. /// <summary>对数据进行 GZip 压缩。</summary>
  293. public static byte[] ToGzip(byte[] plain)
  294. {
  295. if (plain == null || plain.Length == 0) return EmptyBytes;
  296. byte[] result;
  297. using (var output = new MemoryStream())
  298. {
  299. using (var zip = new GZipStream(output, CompressionMode.Compress, true))
  300. {
  301. zip.Write(plain, 0, plain.Length);
  302. }
  303. result = output.ToArray();
  304. }
  305. return result;
  306. }
  307. /// <summary>对数据进行 GZip 解压。</summary>
  308. public static byte[] FromGzip(byte[] gzip)
  309. {
  310. if (gzip == null || gzip.Length == 0) return EmptyBytes;
  311. byte[] result;
  312. using (var input = new MemoryStream(gzip))
  313. {
  314. input.Position = 0;
  315. using (var output = new MemoryStream())
  316. {
  317. using (var zip = new GZipStream(input, CompressionMode.Decompress, true))
  318. {
  319. Read(zip, output, null, 8192);
  320. result = output.ToArray();
  321. }
  322. }
  323. }
  324. return result;
  325. }
  326. /// <summary>压缩字典为 ZIP 文件。</summary>
  327. /// <param name="files">由文件名和文件内容组成的字典。</param>
  328. /// <param name="target">要输出的 ZIP 流。</param>
  329. public static Exception ToZip(Dictionary<string, byte[]> files, Stream target)
  330. {
  331. var zip = null as ZipOutputStream;
  332. try
  333. {
  334. if (files == null) return new ArgumentNullException();
  335. if (target == null) return new ArgumentNullException();
  336. if (!target.CanWrite) return new NotSupportedException();
  337. zip = new ZipOutputStream(target);
  338. zip.SetLevel(1);
  339. foreach (var file in files)
  340. {
  341. var crc = new Crc32();
  342. crc.Reset();
  343. crc.Update(file.Value);
  344. var zipentry = new ZipEntry(file.Key);
  345. zipentry.CompressionMethod = CompressionMethod.Deflated;
  346. //vzipentry.Size = vfile.Value.LongLength;
  347. zipentry.Crc = crc.Value;
  348. zipentry.IsUnicodeText = true;
  349. zip.PutNextEntry(zipentry);
  350. zip.Write(file.Value, 0, file.Value.Length);
  351. zip.CloseEntry();
  352. }
  353. zip.IsStreamOwner = false;
  354. zip.Finish();
  355. zip.Flush();
  356. zip.Close();
  357. return null;
  358. }
  359. catch (Exception ex)
  360. {
  361. RuntimeUtility.Dispose(zip);
  362. return ex;
  363. }
  364. }
  365. /// <summary>压缩到 ZIP 流。</summary>
  366. /// <param name="names">ZIP 内的文件名。</param>
  367. /// <param name="target">要输出的 ZIP 流。</param>
  368. /// <param name="modifildGetter">获取文件的修改时间。</param>
  369. /// <param name="disposeFiles">释放已写入 ZIP 的输入流。</param>
  370. public static Exception ToZip(IEnumerable<string> names, Stream target, Func<string, Stream> inputGetter, Func<string, DateTime> modifildGetter = null, bool disposeFiles = false)
  371. {
  372. var zip = null as ZipOutputStream;
  373. try
  374. {
  375. if (names == null) return new ArgumentNullException("names");
  376. if (target == null) return new ArgumentNullException("target");
  377. if (!target.CanWrite) return new ArgumentNullException("target");
  378. zip = new ZipOutputStream(target);
  379. zip.SetLevel(1);
  380. foreach (var name in names)
  381. {
  382. if (string.IsNullOrEmpty(name)) continue;
  383. // stream
  384. var capacity = 1024;
  385. var input = inputGetter == null ? null : inputGetter(name);
  386. if (input != null)
  387. {
  388. if (!input.CanSeek || !input.CanRead)
  389. {
  390. if (disposeFiles) RuntimeUtility.Dispose(input);
  391. return new NotSupportedException("获取到的输入流不支持 Seek 或 Read。");
  392. }
  393. }
  394. var crc = new Crc32();
  395. crc.Reset();
  396. if (input != null)
  397. {
  398. input.ResetPosition();
  399. while (true)
  400. {
  401. var count = 0;
  402. var buffer = new byte[capacity];
  403. count = input.Read(buffer, 0, buffer.Length);
  404. if (count == 0) break;
  405. crc.Update(buffer, 0, count);
  406. }
  407. }
  408. var entry = new ZipEntry(name);
  409. entry.CompressionMethod = CompressionMethod.Deflated;
  410. //vzipentry.Size = vfile.Value.LongLength;
  411. entry.Crc = crc.Value;
  412. entry.IsUnicodeText = true;
  413. if (modifildGetter != null) entry.DateTime = modifildGetter(name);
  414. zip.PutNextEntry(entry);
  415. if (input != null)
  416. {
  417. input.ResetPosition();
  418. while (true)
  419. {
  420. var count = 0;
  421. var buffer = new byte[capacity];
  422. count = input.Read(buffer, 0, buffer.Length);
  423. if (count == 0) break;
  424. zip.Write(buffer, 0, count);
  425. }
  426. }
  427. zip.CloseEntry();
  428. if (disposeFiles) RuntimeUtility.Dispose(input);
  429. }
  430. zip.IsStreamOwner = false;
  431. zip.Finish();
  432. zip.Flush();
  433. zip.Close();
  434. return null;
  435. }
  436. catch (Exception ex)
  437. {
  438. RuntimeUtility.Dispose(zip);
  439. return ex;
  440. }
  441. }
  442. /// <summary>压缩字典为 ZIP 包。</summary>
  443. /// <param name="files">由文件名和文件内容组成的字典。</param>
  444. public static byte[] ToZip(Dictionary<string, byte[]> files)
  445. {
  446. if (files == null) return null;
  447. var output = new MemoryStream();
  448. var input = null as Stream;
  449. var ex = ToZip(files.Keys, output, (name) =>
  450. {
  451. RuntimeUtility.Dispose(input);
  452. if (name.IsEmpty()) return null;
  453. var bytes = files[name];
  454. if (bytes == null || bytes.LongLength < 1L) return null;
  455. input = new MemoryStream();
  456. Write(input, bytes);
  457. return input;
  458. }, null, true);
  459. RuntimeUtility.Dispose(input);
  460. var result = output.ToArray();
  461. RuntimeUtility.Dispose(result);
  462. return result;
  463. }
  464. /// <summary>解压 ZIP 文件。</summary>
  465. public static Exception FromZip(Stream input, ZipOnFile onFile, ZipOnDirectory onDirectory = null, bool disposeOutput = false)
  466. {
  467. const int BufferCapacity = 1024;
  468. var zip = null as ZipInputStream;
  469. try
  470. {
  471. if (input == null) return new ArgumentNullException("input");
  472. if (!input.CanRead) return new NotSupportedException();
  473. if (onFile == null) return new ArgumentNullException("extraction");
  474. zip = new ZipInputStream(input);
  475. while (true)
  476. {
  477. var entry = zip.GetNextEntry();
  478. if (entry == null) break;
  479. var name = entry.Name;
  480. var size = entry.Size;
  481. var modified = entry.DateTime;
  482. if (entry.IsFile)
  483. {
  484. var output = null as Stream;
  485. try
  486. {
  487. output = onFile(name, size, modified);
  488. if (output == null) continue;
  489. if (!output.CanWrite)
  490. {
  491. RuntimeUtility.Dispose(output);
  492. continue;
  493. }
  494. var writed = 0L;
  495. while (true)
  496. {
  497. var buffer = new byte[BufferCapacity];
  498. var count = zip.Read(buffer, 0, BufferCapacity);
  499. writed += count;
  500. if (count < 1) break;
  501. output.Write(buffer, 0, count);
  502. }
  503. if (disposeOutput) RuntimeUtility.Dispose(output, true);
  504. }
  505. catch (Exception ex)
  506. {
  507. if (disposeOutput) RuntimeUtility.Dispose(output, true);
  508. RuntimeUtility.Dispose(zip);
  509. return ex;
  510. }
  511. }
  512. if (onDirectory != null && entry.IsDirectory)
  513. {
  514. try
  515. {
  516. onDirectory(name, modified);
  517. }
  518. catch (Exception ex)
  519. {
  520. RuntimeUtility.Dispose(zip);
  521. return ex;
  522. }
  523. }
  524. }
  525. zip.Dispose();
  526. return null;
  527. }
  528. catch (Exception ex)
  529. {
  530. RuntimeUtility.Dispose(zip);
  531. return ex;
  532. }
  533. }
  534. /// <summary>解压 .ZIP 文件为字典。</summary>
  535. public static Dictionary<string, byte[]> FromZip(byte[] zip)
  536. {
  537. var result = new Dictionary<string, byte[]>();
  538. if (zip == null) return result;
  539. if (zip.LongLength < 1) return result;
  540. var packagememory = new System.IO.MemoryStream(zip);
  541. try
  542. {
  543. var zipstream = new ZipInputStream(packagememory);
  544. while (true)
  545. {
  546. var entry = zipstream.GetNextEntry();
  547. if (entry == null) break;
  548. if (entry.IsFile)
  549. {
  550. var cellname = entry.Name;
  551. var celldata = new byte[0];
  552. {
  553. var cellstream = new System.IO.MemoryStream();
  554. while (true)
  555. {
  556. var blockdata = new byte[1024];
  557. var blockread = zipstream.Read(blockdata, 0, 1024);
  558. if (blockread < 1) break;
  559. cellstream.Write(blockdata, 0, blockread);
  560. }
  561. celldata = cellstream.ToArray();
  562. cellstream.Dispose();
  563. }
  564. if (result.ContainsKey(cellname)) result[cellname] = celldata;
  565. else result.Add(cellname, celldata);
  566. }
  567. }
  568. zipstream.Dispose();
  569. }
  570. catch (Exception ex)
  571. {
  572. Debug.WriteLine(ex.ToString());
  573. }
  574. packagememory.Dispose();
  575. return result;
  576. }
  577. #endregion
  578. #region Stream
  579. /// <summary>关闭,并释放流。</summary>
  580. public static void Dispose(Stream stream, bool flush = false, bool close = true)
  581. {
  582. if (stream != null)
  583. {
  584. try { if (flush) stream.Flush(); } catch { }
  585. try { if (close) stream.Close(); } catch { }
  586. try { stream.Dispose(); } catch { }
  587. }
  588. }
  589. /// <summary>关闭,并释放流。</summary>
  590. public static void Dispose(IEnumerable<Stream> streams, bool flush = false, bool close = true)
  591. {
  592. if (streams != null)
  593. {
  594. foreach (var stream in streams) Dispose(stream, flush, close);
  595. }
  596. }
  597. /// <summary>重置流的位置到开始位置。</summary>
  598. public static bool ResetPosition(Stream stream)
  599. {
  600. if (stream == null) return false;
  601. try
  602. {
  603. stream.Position = 0;
  604. if (stream.CanSeek) stream.Seek(0, SeekOrigin.Begin);
  605. return true;
  606. }
  607. catch
  608. {
  609. return false;
  610. }
  611. }
  612. /// <summary>读取源流中的数据,并将数据写入目标流,获取写入的总字节数。</summary>
  613. /// <param name="source">要读取的源流。</param>
  614. /// <param name="destination">要写入的目标流。</param>
  615. /// <param name="progress">已写入的字节数,返回 TRUE 继续读取,返回 FALSE 中断读取。</param>
  616. /// <param name="buffer">缓冲区大小,最小值为 1。</param>
  617. /// <returns>已写入的字节数。</returns>
  618. public static long Read(Stream source, Stream destination, Func<long, bool> progress = null, int buffer = 4096)
  619. {
  620. if (source == null || !source.CanRead) return 0;
  621. if (destination == null || !destination.CanWrite) return 0;
  622. var limit = buffer < 1 ? 1 : buffer;
  623. var total = 0L;
  624. var count = 0;
  625. var callback = progress == null ? false : true;
  626. while (true)
  627. {
  628. count = 0;
  629. var temp = new byte[limit];
  630. try
  631. {
  632. count = source.Read(temp, 0, limit);
  633. if (count < 1) break;
  634. }
  635. catch { break; }
  636. try
  637. {
  638. destination.Write(temp, 0, count);
  639. }
  640. catch { break; }
  641. total += count;
  642. if (callback)
  643. {
  644. var @continue = progress(total);
  645. if (!@continue) break;
  646. }
  647. }
  648. return total;
  649. }
  650. /// <summary>读取源流中的数据,并将数据写入目标流,获取写入的总字节数。</summary>
  651. /// <param name="source">要读取的源流。</param>
  652. /// <param name="destination">要写入的目标流。</param>
  653. /// <param name="progress">已写入的字节数,返回 TRUE 继续读取,返回 FALSE 中断读取。</param>
  654. /// <param name="buffer">缓冲区大小,最小值为 1。</param>
  655. /// <returns>已写入的字节数。</returns>
  656. public static long Read(Stream source, Stream destination, Action<long> progress, int buffer = 1024)
  657. {
  658. return Read(source, destination, (x) => { progress?.Invoke(x); return true; }, buffer);
  659. }
  660. /// <summary>读取源流中的数据。</summary>
  661. /// <param name="source">源流。</param>
  662. /// <param name="buffer">缓冲区大小,最小值为 1。</param>
  663. /// <param name="dispose">读取结束后释放源流。</param>
  664. public static byte[] Read(Stream source, int buffer = 1024, bool dispose = false)
  665. {
  666. var result = null as byte[];
  667. using (var memory = new MemoryStream())
  668. {
  669. Read(source, memory, null, buffer);
  670. result = memory.ToArray();
  671. }
  672. if (dispose) Dispose(source);
  673. return result;
  674. }
  675. /// <summary>读取源流中的数据。</summary>
  676. /// <param name="source">源流。</param>
  677. /// <param name="dispose">读取结束后释放源流。</param>
  678. public static byte[] Read(Stream source, bool dispose) => Read(source, 1024, dispose);
  679. /// <summary>读取源流中的数据,并将数据写入目标流,获取写入的总字节数。</summary>
  680. /// <param name="source">要读取的源流。</param>
  681. /// <param name="destination">要写入的目标流。</param>
  682. /// <param name="writed">已写入的字节数,返回 TRUE 继续读取,返回 FALSE 中断读取。</param>
  683. /// <param name="buffer">缓冲区大小,最小值为 1。</param>
  684. /// <returns>已写入的字节数。</returns>
  685. public static long Read(IEnumerable<Stream> sources, Stream destination, Func<long, bool> writed = null, int buffer = 1024)
  686. {
  687. var total = 0L;
  688. if (sources != null)
  689. {
  690. if (writed == null)
  691. {
  692. foreach (var source in sources) total += Read(source, destination, null, buffer);
  693. }
  694. else
  695. {
  696. foreach (var source in sources)
  697. {
  698. Read(source, destination, (x) =>
  699. {
  700. total += x;
  701. return writed(total);
  702. }, buffer);
  703. }
  704. }
  705. }
  706. return total;
  707. }
  708. /// <summary>读取源流中的数据,并将数据写入目标流,获取写入的总字节数。</summary>
  709. /// <param name="source">要读取的源流。</param>
  710. /// <param name="destination">要写入的目标流。</param>
  711. /// <param name="writed">已写入的字节数,返回 TRUE 继续读取,返回 FALSE 中断读取。</param>
  712. /// <param name="buffer">缓冲区大小,最小值为 1。</param>
  713. /// <returns>已写入的字节数。</returns>
  714. public static long Read(IEnumerable<Stream> sources, Stream destination, Action<long> writed, int buffer = 1024)
  715. {
  716. return Read(sources, destination, (x) => { writed?.Invoke(x); return true; }, buffer);
  717. }
  718. /// <summary>向目标流写入数据,最多可写入 2147483648 字节。</summary>
  719. public static int Write(Stream destination, byte[] bytes, Action<int> writed, int buffer = 1048576)
  720. {
  721. if (destination == null || !destination.CanWrite) return 0;
  722. if (bytes == null || bytes.Length < 1 || bytes.LongLength > int.MaxValue) return 0;
  723. var limit = buffer < 1 ? 1 : buffer;
  724. var total = 0;
  725. try
  726. {
  727. var length = bytes.Length;
  728. while (total < length)
  729. {
  730. var block = length - total;
  731. if (block > limit) block = limit;
  732. destination.Write(bytes, total, block);
  733. total += block;
  734. writed?.Invoke(total);
  735. }
  736. }
  737. catch (Exception ex)
  738. {
  739. Logger.Internals.Exception($"{nameof(BinaryUtility)}.{nameof(Write)}", ex);
  740. }
  741. return total;
  742. }
  743. /// <summary>向目标流写入数据,最多可写入 2147483647 字节(> 20 GB)。</summary>
  744. public static int Write(Stream destination, params byte[] bytes) => Write(destination, bytes, null);
  745. #endregion
  746. #region AES
  747. private static RijndaelManaged Aes256Provider(byte[] key)
  748. {
  749. var k = key ?? EmptyBytes; // AesFill(key);
  750. var p = new RijndaelManaged();
  751. p.Key = k;
  752. p.Mode = CipherMode.ECB;
  753. p.Padding = PaddingMode.PKCS7;
  754. return p;
  755. }
  756. /// <summary>对数据进行 AES 加密。</summary>
  757. public static byte[] Aes256Encrypt(byte[] bytes, byte[] key = null)
  758. {
  759. if (bytes == null) return EmptyBytes;
  760. if (bytes.Length == 0) return EmptyBytes;
  761. var rm = Aes256Provider(key);
  762. var result = new byte[0];
  763. var ct = rm.CreateEncryptor();
  764. try
  765. {
  766. result = ct.TransformFinalBlock(bytes, 0, bytes.Length);
  767. }
  768. catch { }
  769. return result;
  770. }
  771. /// <summary>对数据进行 AES 解密。</summary>
  772. public static byte[] Aes256Decrypt(byte[] cipher, byte[] key = null)
  773. {
  774. if (cipher == null) return EmptyBytes;
  775. if (cipher.Length == 0) return EmptyBytes;
  776. var rm = Aes256Provider(key);
  777. var result = new byte[0];
  778. var ct = rm.CreateDecryptor();
  779. try
  780. {
  781. result = ct.TransformFinalBlock(cipher, 0, cipher.Length);
  782. }
  783. catch { }
  784. ct.Dispose();
  785. return result;
  786. }
  787. #endregion
  788. #region Hash
  789. private static byte[] ComputeHash<T>(byte[] bytes) where T : HashAlgorithm, new()
  790. {
  791. if (bytes != null)
  792. {
  793. try
  794. {
  795. var algorithm = new T();
  796. var result = algorithm.ComputeHash(bytes);
  797. algorithm.Clear();
  798. #if !NET20
  799. algorithm.Dispose();
  800. #endif
  801. return result;
  802. }
  803. catch { }
  804. }
  805. return EmptyBytes;
  806. }
  807. private static byte[] ComputeHash<T>(Stream stream, bool dispose, Action<long> progress) where T : HashAlgorithm, new()
  808. {
  809. if (progress == null)
  810. {
  811. if (stream != null)
  812. {
  813. var result = EmptyBytes;
  814. try
  815. {
  816. var algorithm = new T();
  817. result = algorithm.ComputeHash(stream);
  818. algorithm.Clear();
  819. #if !NET20
  820. algorithm.Dispose();
  821. #endif
  822. }
  823. catch { }
  824. if (dispose) stream.Dispose();
  825. return result;
  826. }
  827. return EmptyBytes;
  828. }
  829. else
  830. {
  831. if (stream == null) return EmptyBytes;
  832. // 初始化。
  833. var validcallback = progress != null;
  834. var capacity = Constant.DefaultBufferCapacity;
  835. var buffer = new byte[capacity];
  836. var algorithm = new T();
  837. algorithm.Initialize();
  838. // 读取。
  839. var failed = false;
  840. while (true)
  841. {
  842. var read = 0;
  843. try { read = stream.Read(buffer, 0, capacity); }
  844. catch { failed = true; }
  845. if (read < capacity)
  846. {
  847. if (read < 1)
  848. {
  849. algorithm.TransformFinalBlock(new byte[0], 0, 0);
  850. }
  851. else
  852. {
  853. algorithm.TransformFinalBlock(buffer, 0, Convert.ToInt32(read));
  854. }
  855. break;
  856. }
  857. else
  858. {
  859. algorithm.TransformBlock(buffer, 0, Convert.ToInt32(read), buffer, 0);
  860. }
  861. }
  862. if (failed)
  863. {
  864. algorithm.Clear();
  865. #if !NET20
  866. algorithm.Dispose();
  867. #endif
  868. if (dispose) stream.Dispose();
  869. return EmptyBytes;
  870. }
  871. else
  872. {
  873. var result = algorithm.Hash;
  874. algorithm.Clear();
  875. #if !NET20
  876. algorithm.Dispose();
  877. #endif
  878. if (dispose) stream.Dispose();
  879. return result;
  880. }
  881. }
  882. }
  883. /// <summary>获取 MD5 值。</summary>
  884. public static byte[] MD5(params byte[] bytes) => ComputeHash<MD5CryptoServiceProvider>(bytes);
  885. /// <summary>获取 MD5 值。</summary>
  886. public static byte[] MD5(Stream stream, Action<long> progress = null) => ComputeHash<MD5CryptoServiceProvider>(stream, false, progress);
  887. /// <summary>获取 SHA1 值。</summary>
  888. public static byte[] SHA1(params byte[] bytes) => ComputeHash<SHA1CryptoServiceProvider>(bytes);
  889. /// <summary>获取 SHA1 值。</summary>
  890. public static byte[] SHA1(Stream stream, Action<long> progress = null) => ComputeHash<SHA1CryptoServiceProvider>(stream, false, progress);
  891. /// <summary>获取 SHA256 值。</summary>
  892. public static byte[] SHA256(params byte[] bytes) => ComputeHash<SHA256CryptoServiceProvider>(bytes);
  893. /// <summary>获取 SHA256 值。</summary>
  894. public static byte[] SHA256(Stream stream, Action<long> progress = null) => ComputeHash<SHA256CryptoServiceProvider>(stream, false, progress);
  895. /// <summary>获取 SHA512 值。</summary>
  896. public static byte[] SHA512(params byte[] bytes) => ComputeHash<SHA512CryptoServiceProvider>(bytes);
  897. /// <summary>获取 SHA512 值。</summary>
  898. public static byte[] SHA512(Stream stream, Action<long> progress = null) => ComputeHash<SHA512CryptoServiceProvider>(stream, false, progress);
  899. #endregion
  900. }
  901. }