PageRenderTime 74ms CodeModel.GetById 22ms RepoModel.GetById 0ms app.codeStats 1ms

/Languages/Ruby/Libraries/Zlib/zlib.cs

http://github.com/IronLanguages/main
C# | 1284 lines | 1019 code | 219 blank | 46 comment | 149 complexity | c90a442b2d84c7be94b5f92af0c602e9 MD5 | raw file
Possible License(s): CPL-1.0, BSD-3-Clause, ISC, GPL-2.0, MPL-2.0-no-copyleft-exception

Large files files are truncated, but you can click here to view the full file

  1. /* ****************************************************************************
  2. *
  3. * Copyright (c) Microsoft Corporation.
  4. *
  5. * This source code is subject to terms and conditions of the Apache License, Version 2.0. A
  6. * copy of the license can be found in the License.html file at the root of this distribution. If
  7. * you cannot locate the Apache License, Version 2.0, please send an email to
  8. * ironruby@microsoft.com. By using this source code in any fashion, you are agreeing to be bound
  9. * by the terms of the Apache License, Version 2.0.
  10. *
  11. * You must not remove this notice, or any other, from this software.
  12. *
  13. *
  14. * ***************************************************************************/
  15. #if !SILVERLIGHT
  16. using System.IO.Compression;
  17. #endif
  18. using System;
  19. using System.Collections.Generic;
  20. using System.IO;
  21. using System.Runtime.CompilerServices;
  22. using IronRuby.Builtins;
  23. using IronRuby.Runtime;
  24. using Microsoft.Scripting.Runtime;
  25. using Microsoft.Scripting.Generation;
  26. using System.Diagnostics;
  27. using System.Text;
  28. using System.Runtime.InteropServices;
  29. namespace IronRuby.StandardLibrary.Zlib {
  30. [RubyModule("Zlib")]
  31. public static class Zlib {
  32. #region Constants
  33. [RubyConstant("NO_FLUSH")]
  34. public const int NO_FLUSH = 0;
  35. [RubyConstant("SYNC_FLUSH")]
  36. public const int SYNC_FLUSH = 2;
  37. [RubyConstant("FULL_FLUSH")]
  38. public const int FULL_FLUSH = 3;
  39. [RubyConstant("FINISH")]
  40. public const int FINISH = 4;
  41. [RubyConstant("ZLIB_VERSION")]
  42. public static string ZLIB_VERSION = "1.2.3";
  43. [RubyConstant("VERSION")]
  44. public static string VERSION = "0.6.0";
  45. [RubyConstant("MAXBITS")]
  46. public const int MAXBITS = 15;
  47. [RubyConstant("MAXLCODES")]
  48. public const int MAXLCODES = 286;
  49. [RubyConstant("MAXDCODES")]
  50. public const int MAXDCODES = 30;
  51. [RubyConstant("MAXCODES")]
  52. public const int MAXCODES = (MAXLCODES + MAXDCODES);
  53. [RubyConstant("FIXLCODES")]
  54. public const int FIXLCODES = 288;
  55. [RubyConstant("MAX_WBITS")]
  56. public const int MAX_WBITS = 15;
  57. [RubyConstant("Z_DEFLATED")]
  58. public const int Z_DEFLATED = 8;
  59. [RubyConstant("BINARY")]
  60. public const int BINARY = 0;
  61. [RubyConstant("ASCII")]
  62. public const int ASCII = 1;
  63. [RubyConstant("UNKNOWN")]
  64. public const int UNKNOWN = 2;
  65. [RubyConstant("NO_COMPRESSION")]
  66. public const int NO_COMPRESSION = 0;
  67. [RubyConstant("BEST_SPEED")]
  68. public const int BEST_SPEED = 1;
  69. [RubyConstant("BEST_COMPRESSION")]
  70. public const int BEST_COMPRESSION = 9;
  71. [RubyConstant("DEFAULT_COMPRESSION")]
  72. public const int DEFAULT_COMPRESSION = -1;
  73. [RubyConstant("FILTERED")]
  74. public const int FILTERED = 1;
  75. [RubyConstant("HUFFMAN_ONLY")]
  76. public const int HUFFMAN_ONLY = 2;
  77. [RubyConstant("DEFAULT_STRATEGY")]
  78. public const int DEFAULT_STRATEGY = 0;
  79. #endregion
  80. #if !SILVERLIGHT
  81. [RubyMethod("crc32", RubyMethodAttributes.PublicSingleton, BuildConfig = "!SILVERLIGHT")]
  82. public static int GetCrc(RubyModule/*!*/ self) {
  83. return 0;
  84. }
  85. [RubyMethod("crc32", RubyMethodAttributes.PublicSingleton, BuildConfig = "!SILVERLIGHT")]
  86. public static object GetCrc(RubyModule/*!*/ self, [Optional, DefaultProtocol]MutableString str, [Optional]int initialCrc) {
  87. byte[] bytes;
  88. if (str == null) {
  89. bytes = new byte[0];
  90. } else {
  91. bytes = str.ToByteArray();
  92. }
  93. uint result = Deflate.ZDeflateStream.UpdateCrc(unchecked((uint)initialCrc), bytes, 0, bytes.Length);
  94. return Protocols.Normalize(result);
  95. }
  96. #endif
  97. #region ZStream class
  98. [RubyClass("ZStream")]
  99. public class ZStream {
  100. protected readonly List<byte>/*!*/ _inputBuffer;
  101. protected readonly List<byte>/*!*/ _outputBuffer;
  102. protected int _outPos = -1;
  103. protected int _inPos = -1;
  104. protected byte _bitBucket = 0;
  105. protected byte _bitCount = 0;
  106. protected bool _closed = false;
  107. public ZStream() {
  108. _outPos = -1;
  109. _inPos = -1;
  110. _bitBucket = 0;
  111. _bitCount = 0;
  112. _inputBuffer = new List<byte>();
  113. _outputBuffer = new List<byte>();
  114. }
  115. #region instance methods
  116. public bool Close() {
  117. _closed = true;
  118. return _closed;
  119. }
  120. #endregion
  121. [RubyMethod("adler")]
  122. public static int Adler(ZStream/*!*/ self) {
  123. throw new NotImplementedError();
  124. }
  125. [RubyMethod("avail_in")]
  126. public static int AvailIn(ZStream/*!*/ self) {
  127. return self._inputBuffer.Count - self._inPos;
  128. }
  129. [RubyMethod("avail_out")]
  130. public static int GetAvailOut(ZStream/*!*/ self) {
  131. return self._outputBuffer.Count - self._outPos;
  132. }
  133. [RubyMethod("avail_out=")]
  134. public static int SetAvailOut(ZStream/*!*/ self, int size) {
  135. self._outputBuffer.Capacity = size;
  136. return self._outputBuffer.Count;
  137. }
  138. [RubyMethod("finish")]
  139. [RubyMethod("close")]
  140. public static bool Close(ZStream/*!*/ self) {
  141. return self.Close();
  142. }
  143. [RubyMethod("stream_end?")]
  144. [RubyMethod("finished?")]
  145. [RubyMethod("closed?")]
  146. public static bool IsClosed(ZStream/*!*/ self) {
  147. return self._closed;
  148. }
  149. [RubyMethod("data_type")]
  150. public static void DataType(ZStream/*!*/ self) {
  151. throw new NotImplementedException();
  152. }
  153. [RubyMethod("flush_next_in")]
  154. public static List<byte> FlushNextIn(ZStream/*!*/ self) {
  155. self._inPos = self._inputBuffer.Count;
  156. return self._inputBuffer;
  157. }
  158. [RubyMethod("flush_next_out")]
  159. public static List<byte> FlushNextOut(ZStream/*!*/ self) {
  160. self._outPos = self._outputBuffer.Count;
  161. return self._outputBuffer;
  162. }
  163. [RubyMethod("reset")]
  164. public static void Reset(ZStream/*!*/ self) {
  165. self._outPos = -1;
  166. self._inPos = -1;
  167. self._inputBuffer.Clear();
  168. self._outputBuffer.Clear();
  169. }
  170. [RubyMethod("total_in")]
  171. public static int TotalIn(ZStream/*!*/ self) {
  172. return self._inputBuffer.Count;
  173. }
  174. [RubyMethod("total_out")]
  175. public static int TotalOut(ZStream/*!*/ self) {
  176. return self._outputBuffer.Count;
  177. }
  178. protected int GetBits(int need) {
  179. int val = _bitBucket;
  180. while (_bitCount < need) {
  181. val |= (int)(_inputBuffer[++_inPos] << _bitCount);
  182. _bitCount += 8;
  183. }
  184. _bitBucket = (byte)(val >> need);
  185. _bitCount -= (byte)need;
  186. return (val & ((1 << need) - 1));
  187. }
  188. }
  189. #endregion
  190. #region Inflate class
  191. [RubyClass("Inflate")]
  192. public class Inflate : ZStream {
  193. private int _wBits;
  194. private bool _rawDeflate;
  195. private HuffmanTree _fixedLengthCodes;
  196. private HuffmanTree _fixedDistanceCodes;
  197. private HuffmanTree _dynamicLengthCodes;
  198. private HuffmanTree _dynamicDistanceCodes;
  199. public Inflate()
  200. : this(MAX_WBITS) {
  201. }
  202. public Inflate(int windowBits) {
  203. _wBits = windowBits;
  204. if (_wBits < 0) {
  205. _rawDeflate = true;
  206. _wBits *= -1;
  207. }
  208. }
  209. #region Private Implementation Details
  210. private sealed class HuffmanTree {
  211. internal readonly List<int>/*!*/ Count;
  212. internal readonly List<int>/*!*/ Symbol;
  213. internal HuffmanTree() {
  214. Count = new List<int>();
  215. Symbol = new List<int>();
  216. }
  217. }
  218. private void DynamicCodes() {
  219. byte[] order = { 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 };
  220. int nlen = (int)GetBits(5) + 257;
  221. int ndist = (int)GetBits(5) + 1;
  222. int ncode = (int)GetBits(4) + 4;
  223. List<int> lengths = new List<int>();
  224. _dynamicLengthCodes = new HuffmanTree();
  225. _dynamicDistanceCodes = new HuffmanTree();
  226. if (nlen > MAXLCODES || ndist > MAXDCODES) {
  227. throw new DataError("too many length or distance codes");
  228. }
  229. int idx = 0;
  230. while (idx < ncode) {
  231. SetOrExpand(lengths, order[idx], GetBits(3));
  232. idx++;
  233. }
  234. while (idx < 19) {
  235. SetOrExpand(lengths, order[idx], 0);
  236. idx++;
  237. }
  238. int err = ConstructTree(_dynamicLengthCodes, lengths, 18);
  239. if (err != 0) {
  240. throw new DataError("code lengths codes incomplete");
  241. }
  242. idx = 0;
  243. while (idx < (nlen + ndist)) {
  244. int symbol = Decode(_dynamicLengthCodes);
  245. if (symbol < 16) {
  246. SetOrExpand(lengths, idx, symbol);
  247. idx++;
  248. } else {
  249. int len = 0;
  250. if (symbol == 16) {
  251. if (idx == 0) {
  252. throw new DataError("repeat lengths with no first length");
  253. }
  254. len = lengths[idx - 1];
  255. symbol = 3 + (int)GetBits(2);
  256. } else if (symbol == 17) {
  257. symbol = 3 + (int)GetBits(3);
  258. } else if (symbol == 18) {
  259. symbol = 11 + (int)GetBits(7);
  260. } else {
  261. throw new DataError("invalid repeat length code");
  262. }
  263. if ((idx + symbol) > (nlen + ndist)) {
  264. throw new DataError("repeat more than specified lengths");
  265. }
  266. while (symbol != 0) {
  267. SetOrExpand(lengths, idx, len);
  268. idx++;
  269. symbol--;
  270. }
  271. }
  272. }
  273. err = ConstructTree(_dynamicLengthCodes, lengths, nlen - 1);
  274. if (err < 0 || (err > 0 && (nlen - _dynamicLengthCodes.Count[0] != 1))) {
  275. throw new DataError("invalid literal/length code lengths");
  276. }
  277. lengths.RemoveRange(0, nlen);
  278. err = ConstructTree(_dynamicDistanceCodes, lengths, ndist - 1);
  279. if (err < 0 || (err > 0 && (ndist - _dynamicDistanceCodes.Count[0] != 1))) {
  280. throw new DataError("invalid distance code lengths");
  281. }
  282. Codes(_dynamicLengthCodes, _dynamicDistanceCodes);
  283. }
  284. private void NoCompression() {
  285. _bitBucket = 0;
  286. _bitCount = 0;
  287. if (_inPos + 4 > _inputBuffer.Count) {
  288. throw new DataError("not enough input to read length code");
  289. }
  290. int length = (int)(_inputBuffer[++_inPos] | (_inputBuffer[++_inPos] << 8));
  291. int lengthComplement = (int)(_inputBuffer[++_inPos] | (_inputBuffer[++_inPos] << 8));
  292. if (unchecked((ushort)length) != unchecked((ushort)(~lengthComplement))) {
  293. throw new DataError("invalid stored block lengths");
  294. }
  295. if (_inPos + length > _inputBuffer.Count) {
  296. throw new DataError("ran out of input");
  297. }
  298. _outputBuffer.AddRange(_inputBuffer.GetRange(_inPos + 1, length));
  299. _inPos += length;
  300. _outPos += length;
  301. }
  302. private void FixedCodes() {
  303. if (_fixedLengthCodes == null && _fixedDistanceCodes == null) {
  304. GenerateHuffmans();
  305. }
  306. Codes(_fixedLengthCodes, _fixedDistanceCodes);
  307. }
  308. private void GenerateHuffmans() {
  309. List<int> lengths = new List<int>(300);
  310. int x = 0;
  311. for (; x < 144; x++) {
  312. lengths.Add(8);
  313. }
  314. for (; x < 256; x++) {
  315. lengths.Add(9);
  316. }
  317. for (; x < 280; x++) {
  318. lengths.Add(7);
  319. }
  320. for (; x < 288; x++) {
  321. lengths.Add(8);
  322. }
  323. _fixedLengthCodes = new HuffmanTree();
  324. ConstructTree(_fixedLengthCodes, lengths, 287);
  325. lengths.Clear();
  326. for (int y = 0; y < 30; y++) {
  327. lengths.Add(5);
  328. }
  329. _fixedDistanceCodes = new HuffmanTree();
  330. ConstructTree(_fixedDistanceCodes, lengths, 29);
  331. }
  332. private int ConstructTree(HuffmanTree/*!*/ tree, List<int>/*!*/ lengths, int symbols) {
  333. List<int> offs = new List<int>();
  334. for (int x = 0; x <= MAXBITS; x++) {
  335. SetOrExpand(tree.Count, x, 0);
  336. }
  337. for (int y = 0; y <= symbols; y++) {
  338. (tree.Count[lengths[y]])++;
  339. }
  340. if (tree.Count[0] == symbols) {
  341. return 0;
  342. }
  343. int left = 1;
  344. for (int y = 1; y <= MAXBITS; y++) {
  345. left <<= 1;
  346. left -= tree.Count[y];
  347. if (left < 0) {
  348. return left;
  349. }
  350. }
  351. offs.Add(0);
  352. offs.Add(0);
  353. for (int len = 1; len <= MAXBITS - 1; len++) {
  354. offs.Add(0);
  355. offs[len + 1] = offs[len] + tree.Count[len];
  356. }
  357. for (int symbol = 0; symbol <= symbols; symbol++) {
  358. if (lengths[symbol] != 0) {
  359. SetOrExpand(tree.Symbol, offs[lengths[symbol]], symbol);
  360. offs[lengths[symbol]]++;
  361. }
  362. }
  363. return left;
  364. }
  365. private void SetOrExpand<T>(List<T>/*!*/ list, int index, T item) {
  366. int minCount = index + 1;
  367. int expand = minCount - list.Count;
  368. while (expand > 0) {
  369. list.Add(default(T));
  370. expand--;
  371. }
  372. list[index] = item;
  373. }
  374. private int Codes(HuffmanTree/*!*/ lengthCodes, HuffmanTree/*!*/ distanceCodes) {
  375. int[] lens = { 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258 };
  376. int[] lext = { 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0 };
  377. int[] dists = { 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, 8193, 12289, 16385, 24577 };
  378. int[] dext = { 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13 };
  379. int symbol = 0;
  380. while (symbol != 256) {
  381. symbol = Decode(lengthCodes);
  382. if (symbol < 0) {
  383. return symbol;
  384. }
  385. if (symbol < 256) {
  386. SetOrExpand(_outputBuffer, ++_outPos, (byte)symbol);
  387. }
  388. if (symbol > 256) {
  389. symbol -= 257;
  390. if (symbol >= 29) {
  391. throw new DataError("invalid literal/length or distance code in fixed or dynamic block");
  392. }
  393. int len = lens[symbol] + GetBits((byte)lext[symbol]);
  394. symbol = Decode(distanceCodes);
  395. if (symbol < 0) {
  396. return symbol;
  397. }
  398. int dist = dists[symbol] + GetBits((byte)dext[symbol]);
  399. if (dist > _outputBuffer.Count) {
  400. throw new DataError("distance is too far back in fixed or dynamic block");
  401. }
  402. while (len > 0) {
  403. SetOrExpand(_outputBuffer, ++_outPos, _outputBuffer[_outPos - dist]);
  404. len--;
  405. }
  406. }
  407. }
  408. return 0;
  409. }
  410. private int Decode(HuffmanTree/*!*/ tree) {
  411. int code = 0;
  412. int first = 0;
  413. int index = 0;
  414. for (int len = 1; len <= 15; len++) {
  415. code |= GetBits(1);
  416. int count = tree.Count[len];
  417. if (code < (first + count)) {
  418. return tree.Symbol[index + (code - first)];
  419. }
  420. index += count;
  421. first += count;
  422. first <<= 1;
  423. code <<= 1;
  424. }
  425. return -9;
  426. }
  427. #endregion
  428. [RubyMethod("inflate")]
  429. public static MutableString/*!*/ InflateString(Inflate/*!*/ self, [DefaultProtocol, NotNull]MutableString/*!*/ zstring) {
  430. if (zstring.IsEmpty) {
  431. throw new BufError("buffer error");
  432. }
  433. // TODO: hack
  434. if (zstring.GetByteCount() == 6 && zstring.GetByte(0) == (byte)'X' && zstring.GetByte(1) == 0x85 &&
  435. zstring.GetByte(2) == 0 && zstring.GetByte(3) == 0 && zstring.GetByte(4) == 0 && zstring.GetByte(5) == 0) {
  436. return MutableString.CreateEmpty();
  437. }
  438. self._inputBuffer.AddRange(zstring.ConvertToBytes());
  439. if (self._rawDeflate == false) {
  440. byte compression_method_and_flags = self._inputBuffer[++(self._inPos)];
  441. byte flags = self._inputBuffer[++(self._inPos)];
  442. if (((compression_method_and_flags << (byte)0x08) + flags) % (byte)31 != 0) {
  443. throw new DataError("incorrect header check");
  444. }
  445. byte compression_method = (byte)(compression_method_and_flags & (byte)0x0F);
  446. if (compression_method != Z_DEFLATED) {
  447. throw new DataError("unknown compression method");
  448. }
  449. byte compression_info = (byte)(compression_method_and_flags >> (byte)0x04);
  450. if ((compression_info + 8) > self._wBits) {
  451. throw new DataError("invalid window size");
  452. }
  453. bool preset_dictionary_flag = ((flags & 0x20) >> 0x05 == 1);
  454. // TODO: ???
  455. // byte compression_level = (byte)((flags & 0xC0) >> (byte)0x06);
  456. //TODO: Add Preset Dictionary Support
  457. if (preset_dictionary_flag) {
  458. self._inPos += 4;
  459. }
  460. }
  461. bool last_block = false;
  462. while (!last_block) {
  463. last_block = (self.GetBits(1) == 1);
  464. byte block_type = (byte)self.GetBits(2);
  465. switch (block_type) {
  466. case 0:
  467. self.NoCompression();
  468. break;
  469. case 1:
  470. self.FixedCodes();
  471. break;
  472. case 2:
  473. self.DynamicCodes();
  474. break;
  475. case 3:
  476. throw new DataError("invalid block type");
  477. }
  478. }
  479. return Inflate.Close(self);
  480. }
  481. [RubyMethod("inflate", RubyMethodAttributes.PublicSingleton)]
  482. public static MutableString/*!*/ InflateString(RubyClass/*!*/ self, [DefaultProtocol, NotNull]MutableString/*!*/ zstring) {
  483. return InflateString(new Inflate(), zstring);
  484. }
  485. [RubyMethod("close")]
  486. public static MutableString/*!*/ Close(Inflate/*!*/ self) {
  487. return MutableString.CreateBinary(self._outputBuffer, RubyEncoding.Binary);
  488. }
  489. }
  490. #endregion
  491. #region GzipFile class
  492. [RubyClass("GzipFile")]
  493. public class GZipFile {
  494. protected IOWrapper/*!*/ _ioWrapper;
  495. protected List<byte>/*!*/ _inputBuffer;
  496. protected List<byte>/*!*/ _outputBuffer;
  497. protected int _outPos;
  498. protected int _inPos;
  499. protected bool _isClosed;
  500. protected MutableString _originalName;
  501. protected MutableString _comment;
  502. public GZipFile(IOWrapper/*!*/ ioWrapper) {
  503. Debug.Assert(ioWrapper != null);
  504. _ioWrapper = ioWrapper;
  505. _inputBuffer = new List<byte>();
  506. _outputBuffer = new List<byte>();
  507. _outPos = -1;
  508. _inPos = -1;
  509. }
  510. [RubyClass("Error")]
  511. public class Error : RuntimeError {
  512. public Error(string message)
  513. : base(message) {
  514. }
  515. }
  516. // TODO: missing NoFooter, LengthError, CRCError constants
  517. [RubyMethod("wrap", RubyMethodAttributes.PublicSingleton)]
  518. public static object Wrap(BinaryOpStorage/*!*/ newStorage, UnaryOpStorage/*!*/ closedStorage, UnaryOpStorage/*!*/ closeStorage,
  519. BlockParam block, RubyClass/*!*/ self, object io) {
  520. var newSite = newStorage.GetCallSite("new");
  521. GZipFile gzipFile = (GZipFile)newSite.Target(newSite, self, io);
  522. if (block == null) {
  523. return gzipFile;
  524. }
  525. try {
  526. object blockResult;
  527. block.Yield(gzipFile, out blockResult);
  528. return blockResult;
  529. } finally {
  530. CloseFile(closedStorage, closeStorage, self, gzipFile);
  531. }
  532. }
  533. private static void CloseFile(UnaryOpStorage/*!*/ closedStorage, UnaryOpStorage/*!*/ closeStorage, RubyClass self, GZipFile gzipFile) {
  534. var closedSite = closedStorage.GetCallSite("closed?");
  535. bool isClosed = Protocols.IsTrue(closedSite.Target(closedSite, gzipFile));
  536. if (!isClosed) {
  537. var closeSite = closeStorage.GetCallSite("close");
  538. closeSite.Target(closeSite, gzipFile);
  539. }
  540. }
  541. internal static void Close(UnaryOpStorage/*!*/ closeStorage, GZipFile/*!*/ self, bool closeIO) {
  542. if (self._isClosed) {
  543. throw new Error("closed gzip stream");
  544. }
  545. if (closeIO && self._ioWrapper.CanBeClosed) {
  546. var site = closeStorage.GetCallSite("close");
  547. site.Target(site, self._ioWrapper.UnderlyingObject);
  548. }
  549. self._isClosed = true;
  550. }
  551. [RubyMethod("closed?")]
  552. public static bool IsClosed(GZipFile/*!*/ self) {
  553. return self._isClosed;
  554. }
  555. [RubyMethod("comment")]
  556. public static MutableString Comment(GZipFile/*!*/ self) {
  557. if (self._isClosed) {
  558. throw new Error("closed gzip stream");
  559. }
  560. return self._comment;
  561. }
  562. // crc()
  563. // level()
  564. // mtime()
  565. [RubyMethod("orig_name")]
  566. [RubyMethod("original_name")]
  567. public static MutableString OriginalName(GZipFile/*!*/ self) {
  568. if (self._isClosed) {
  569. throw new Error("closed gzip stream");
  570. }
  571. return self._originalName;
  572. }
  573. // os_code()
  574. // sync()
  575. // sync = flag
  576. // to_io
  577. }
  578. #endregion
  579. #region GzipReader class
  580. /* [RubyClass("GzipReader"), Includes(typeof(Enumerable))] */
  581. [RubyClass("GzipReader")]
  582. public class GZipReader : GZipFile {
  583. protected MutableString _xtraField;
  584. protected MutableString/*!*/ _contents;
  585. protected ushort _headerCrc;
  586. [RubyMethod("xtra_field")]
  587. public static MutableString ExtraField(GZipReader/*!*/ self) {
  588. return self._xtraField;
  589. }
  590. [RubyConstant("OSES")]
  591. public static string[] OSES = {
  592. "FAT filesystem",
  593. "Amiga",
  594. "VMS (or OpenVMS)",
  595. "Unix",
  596. "VM/CMS",
  597. "Atari TOS",
  598. "HPFS fileystem (OS/2, NT)",
  599. "Macintosh",
  600. "Z-System",
  601. "CP/M",
  602. "TOPS-20",
  603. "NTFS filesystem (NT)",
  604. "QDOS",
  605. "Acorn RISCOS",
  606. "unknown"
  607. };
  608. private bool IsBitSet(byte b, byte bit) {
  609. return ((b & (1 << bit)) == (1 << bit));
  610. }
  611. [RubyConstructor]
  612. public static GZipReader/*!*/ Create(RespondToStorage/*!*/ respondToStorage, RubyClass/*!*/ self, object io) {
  613. IOWrapper stream = null;
  614. if (io != null) {
  615. stream = RubyIOOps.CreateIOWrapper(respondToStorage, io, FileAccess.Read);
  616. }
  617. if (stream == null || !stream.CanRead) {
  618. throw RubyExceptions.CreateMethodMissing(self.Context, io, "read");
  619. }
  620. using (BinaryReader reader = new BinaryReader(stream)) {
  621. return new GZipReader(stream, reader);
  622. }
  623. }
  624. private static ushort ReadUInt16LE(BinaryReader/*!*/ reader) {
  625. return (ushort)(
  626. (ushort)(reader.ReadByte()) |
  627. (((ushort)(reader.ReadByte())) << 8)
  628. );
  629. }
  630. private static uint ReadUInt32LE(BinaryReader/*!*/ reader) {
  631. return (uint)(
  632. (uint)(reader.ReadByte()) |
  633. (((uint)(reader.ReadByte())) << 8) |
  634. (((uint)(reader.ReadByte())) << 16) |
  635. (((uint)(reader.ReadByte())) << 24)
  636. );
  637. }
  638. private static MutableString/*!*/ ReadStringZ(BinaryReader/*!*/ reader) {
  639. List<byte> result = new List<byte>();
  640. byte c;
  641. while ((c = reader.ReadByte()) != 0) {
  642. result.Add(c);
  643. }
  644. return MutableString.CreateBinary(result, RubyEncoding.Binary);
  645. }
  646. private static MutableString/*!*/ ReadToEnd(BinaryReader/*!*/ reader) {
  647. List<byte> result = new List<byte>();
  648. try {
  649. while (true) {
  650. result.Add(reader.ReadByte());
  651. }
  652. } catch (EndOfStreamException) {
  653. }
  654. return MutableString.CreateBinary(result, RubyEncoding.Binary);
  655. }
  656. private GZipReader(IOWrapper/*!*/ ioWrapper, BinaryReader/*!*/ reader)
  657. : base(ioWrapper) {
  658. // TODO: should all of this code be moved to open()?
  659. if (ReadUInt16LE(reader) != 0x8b1f) {
  660. throw new Error("not in gzip format");
  661. }
  662. if (reader.ReadByte() != 0x08) {
  663. throw new Error("unknown compression method");
  664. }
  665. #pragma warning disable 168,219 // TODO: mcs: unused locals
  666. byte flg = reader.ReadByte();
  667. bool ftext = IsBitSet(flg, 0);
  668. bool fhcrc = IsBitSet(flg, 1);
  669. bool fextra = IsBitSet(flg, 2);
  670. bool fname = IsBitSet(flg, 3);
  671. bool fcomment = IsBitSet(flg, 4);
  672. uint secondsSince1970 = ReadUInt32LE(reader);
  673. DateTime mtime = RubyTime.Epoch.AddSeconds((double)secondsSince1970);
  674. byte xfl = reader.ReadByte();
  675. string os = GZipReader.OSES[reader.ReadByte()];
  676. if (fextra) {
  677. int xlen = ReadUInt16LE(reader);
  678. _xtraField = MutableString.CreateBinary(reader.ReadBytes(xlen));
  679. }
  680. #pragma warning restore 168,219
  681. if (fname) {
  682. _originalName = ReadStringZ(reader);
  683. } else {
  684. _originalName = MutableString.CreateBinary();
  685. }
  686. if (fcomment) {
  687. _comment = ReadStringZ(reader);
  688. } else {
  689. _comment = MutableString.CreateBinary();
  690. }
  691. if (fhcrc) {
  692. _headerCrc = ReadUInt16LE(reader);
  693. }
  694. _contents = ReadToEnd(reader);
  695. }
  696. [RubyMethod("read")]
  697. public static MutableString/*!*/ Read(GZipReader/*!*/ self) {
  698. Inflate z = new Inflate(-MAX_WBITS);
  699. return Inflate.InflateString(z, self._contents);
  700. }
  701. [RubyMethod("open", RubyMethodAttributes.PrivateInstance)]
  702. public static GZipReader/*!*/ Open(GZipReader/*!*/ self) {
  703. // TODO: Open as an private instance method probably doesn't create a new GzipReader, right?
  704. // it probably returns nothing and is used internally to do all initialization
  705. return self;
  706. }
  707. [RubyMethod("open", RubyMethodAttributes.PublicSingleton)]
  708. public static GZipReader/*!*/ Open(RespondToStorage/*!*/ respondToStorage, RubyClass/*!*/ self, [DefaultProtocol, NotNull]MutableString/*!*/ path) {
  709. return Create(respondToStorage, self, new RubyFile(self.Context, path.ConvertToString(), IOMode.ReadOnly));
  710. }
  711. [RubyMethod("open", RubyMethodAttributes.PublicSingleton)]
  712. public static object Open(RespondToStorage/*!*/ respondToStorage, [NotNull]BlockParam/*!*/ block, RubyClass/*!*/ self, [DefaultProtocol, NotNull]MutableString/*!*/ path) {
  713. GZipReader reader = Open(respondToStorage, self, path);
  714. object blockResult;
  715. block.Yield(reader, out blockResult);
  716. return blockResult;
  717. }
  718. // pos()
  719. [RubyMethod("close")]
  720. public static object/*!*/ Close(UnaryOpStorage/*!*/ closeStorage, RubyContext/*!*/ context, GZipReader/*!*/ self) {
  721. GZipFile.Close(closeStorage, self, true);
  722. return self._ioWrapper.UnderlyingObject;
  723. }
  724. [RubyMethod("finish")]
  725. public static object/*!*/ Finish(UnaryOpStorage/*!*/ closeStorage, RubyContext/*!*/ context, GZipReader/*!*/ self) {
  726. GZipFile.Close(closeStorage, self, false);
  727. return self._ioWrapper.UnderlyingObject;
  728. }
  729. }
  730. #endregion
  731. #region Exceptions
  732. [RubyException("Error"), Serializable]
  733. public class Error : SystemException {
  734. public Error() : this(null, null) { }
  735. public Error(string message) : this(message, null) { }
  736. public Error(string message, Exception inner) : base(message ?? "Error", inner) { }
  737. #if !SILVERLIGHT
  738. protected Error(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context)
  739. : base(info, context) { }
  740. #endif
  741. }
  742. [RubyException("DataError"), Serializable]
  743. public class DataError : Error {
  744. public DataError() : this(null, null) { }
  745. public DataError(string message) : this(message, null) { }
  746. public DataError(string message, Exception inner) : base(message ?? "DataError", inner) { }
  747. #if !SILVERLIGHT
  748. protected DataError(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context)
  749. : base(info, context) { }
  750. #endif
  751. }
  752. [RubyException("BufError"), Serializable]
  753. public class BufError : Error {
  754. public BufError() : this(null, null) { }
  755. public BufError(string message) : this(message, null) { }
  756. public BufError(string message, Exception inner) : base(message ?? "BufError", inner) { }
  757. #if !SILVERLIGHT
  758. protected BufError(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context)
  759. : base(info, context) { }
  760. #endif
  761. }
  762. [RubyException("StreamError"), Serializable]
  763. public class StreamError : Error {
  764. public StreamError() : this(null, null) { }
  765. public StreamError(string message) : this(message, null) { }
  766. public StreamError(string message, Exception inner) : base(message ?? "StreamError", inner) { }
  767. #if !SILVERLIGHT
  768. protected StreamError(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context)
  769. : base(info, context) { }
  770. #endif
  771. }
  772. #endregion
  773. #region Deflate class
  774. #if !SILVERLIGHT
  775. [RubyClass("Deflate", BuildConfig="!SILVERLIGHT")]
  776. public class Deflate : ZStream {
  777. /// <summary>
  778. /// Adds a 2 byte header, and a 4 byte adler checksum footer.
  779. /// </summary>
  780. internal class ZDeflateStream : DeflateStream {
  781. private long _size;
  782. private uint _crc;
  783. private bool _leaveOpen;
  784. private Stream _output;
  785. public ZDeflateStream(Stream output, bool leaveOpen)
  786. : base(output, CompressionMode.Compress, true) {
  787. _output = output;
  788. _leaveOpen = leaveOpen;
  789. // System.IO.Compression.DeflateStream uses a window size of 8K and FLEVEL is 2 (default algorithm).
  790. byte[] header = { 0x58, 0x85 };
  791. _output.Write(header, 0, header.Length);
  792. }
  793. public override IAsyncResult BeginWrite(byte[] array, int offset, int count, AsyncCallback asyncCallback, object asyncState) {
  794. IAsyncResult result = base.BeginWrite(array, offset, count, asyncCallback, asyncState);
  795. _size += count;
  796. _crc = UpdateCrc(_crc, array, offset, count);
  797. return result;
  798. }
  799. public override void Write(byte[] array, int offset, int count) {
  800. base.Write(array, offset, count);
  801. _size += count;
  802. _crc = UpdateCrc(_crc, array, offset, count);
  803. }
  804. protected override void Dispose(bool disposing) {
  805. base.Dispose(disposing);
  806. if (disposing && _output != null) {
  807. _output.WriteByte((byte)(_crc & 0xff));
  808. _output.WriteByte((byte)((_crc >> 8) & 0xff));
  809. _output.WriteByte((byte)((_crc >> 16) & 0xff));
  810. _output.WriteByte((byte)((_crc >> 24) & 0xff));
  811. if (!_leaveOpen) _output.Close();
  812. _output = null;
  813. }
  814. }
  815. // See RFC1950 for details. http://www.faqs.org/rfcs/rfc1950.html
  816. internal static uint UpdateCrc(uint crc, byte[] buffer, int offset, int length) {
  817. crc ^= 0xffffffffU;
  818. while (--length >= 0) {
  819. crc = crcTable[(crc ^ buffer[offset++]) & 0xFF] ^ (crc >> 8);
  820. }
  821. crc ^= 0xffffffffU;
  822. return crc;
  823. }
  824. private static readonly uint[] crcTable = new uint[] {
  825. 0x00000000u, 0x77073096u, 0xee0e612cu, 0x990951bau, 0x076dc419u,
  826. 0x706af48fu, 0xe963a535u, 0x9e6495a3u, 0x0edb8832u, 0x79dcb8a4u,
  827. 0xe0d5e91eu, 0x97d2d988u, 0x09b64c2bu, 0x7eb17cbdu, 0xe7b82d07u,
  828. 0x90bf1d91u, 0x1db71064u, 0x6ab020f2u, 0xf3b97148u, 0x84be41deu,
  829. 0x1adad47du, 0x6ddde4ebu, 0xf4d4b551u, 0x83d385c7u, 0x136c9856u,
  830. 0x646ba8c0u, 0xfd62f97au, 0x8a65c9ecu, 0x14015c4fu, 0x63066cd9u,
  831. 0xfa0f3d63u, 0x8d080df5u, 0x3b6e20c8u, 0x4c69105eu, 0xd56041e4u,
  832. 0xa2677172u, 0x3c03e4d1u, 0x4b04d447u, 0xd20d85fdu, 0xa50ab56bu,
  833. 0x35b5a8fau, 0x42b2986cu, 0xdbbbc9d6u, 0xacbcf940u, 0x32d86ce3u,
  834. 0x45df5c75u, 0xdcd60dcfu, 0xabd13d59u, 0x26d930acu, 0x51de003au,
  835. 0xc8d75180u, 0xbfd06116u, 0x21b4f4b5u, 0x56b3c423u, 0xcfba9599u,
  836. 0xb8bda50fu, 0x2802b89eu, 0x5f058808u, 0xc60cd9b2u, 0xb10be924u,
  837. 0x2f6f7c87u, 0x58684c11u, 0xc1611dabu, 0xb6662d3du, 0x76dc4190u,
  838. 0x01db7106u, 0x98d220bcu, 0xefd5102au, 0x71b18589u, 0x06b6b51fu,
  839. 0x9fbfe4a5u, 0xe8b8d433u, 0x7807c9a2u, 0x0f00f934u, 0x9609a88eu,
  840. 0xe10e9818u, 0x7f6a0dbbu, 0x086d3d2du, 0x91646c97u, 0xe6635c01u,
  841. 0x6b6b51f4u, 0x1c6c6162u, 0x856530d8u, 0xf262004eu, 0x6c0695edu,
  842. 0x1b01a57bu, 0x8208f4c1u, 0xf50fc457u, 0x65b0d9c6u, 0x12b7e950u,
  843. 0x8bbeb8eau, 0xfcb9887cu, 0x62dd1ddfu, 0x15da2d49u, 0x8cd37cf3u,
  844. 0xfbd44c65u, 0x4db26158u, 0x3ab551ceu, 0xa3bc0074u, 0xd4bb30e2u,
  845. 0x4adfa541u, 0x3dd895d7u, 0xa4d1c46du, 0xd3d6f4fbu, 0x4369e96au,
  846. 0x346ed9fcu, 0xad678846u, 0xda60b8d0u, 0x44042d73u, 0x33031de5u,
  847. 0xaa0a4c5fu, 0xdd0d7cc9u, 0x5005713cu, 0x270241aau, 0xbe0b1010u,
  848. 0xc90c2086u, 0x5768b525u, 0x206f85b3u, 0xb966d409u, 0xce61e49fu,
  849. 0x5edef90eu, 0x29d9c998u, 0xb0d09822u, 0xc7d7a8b4u, 0x59b33d17u,
  850. 0x2eb40d81u, 0xb7bd5c3bu, 0xc0ba6cadu, 0xedb88320u, 0x9abfb3b6u,
  851. 0x03b6e20cu, 0x74b1d29au, 0xead54739u, 0x9dd277afu, 0x04db2615u,
  852. 0x73dc1683u, 0xe3630b12u, 0x94643b84u, 0x0d6d6a3eu, 0x7a6a5aa8u,
  853. 0xe40ecf0bu, 0x9309ff9du, 0x0a00ae27u, 0x7d079eb1u, 0xf00f9344u,
  854. 0x8708a3d2u, 0x1e01f268u, 0x6906c2feu, 0xf762575du, 0x806567cbu,
  855. 0x196c3671u, 0x6e6b06e7u, 0xfed41b76u, 0x89d32be0u, 0x10da7a5au,
  856. 0x67dd4accu, 0xf9b9df6fu, 0x8ebeeff9u, 0x17b7be43u, 0x60b08ed5u,
  857. 0xd6d6a3e8u, 0xa1d1937eu, 0x38d8c2c4u, 0x4fdff252u, 0xd1bb67f1u,
  858. 0xa6bc5767u, 0x3fb506ddu, 0x48b2364bu, 0xd80d2bdau, 0xaf0a1b4cu,
  859. 0x36034af6u, 0x41047a60u, 0xdf60efc3u, 0xa867df55u, 0x316e8eefu,
  860. 0x4669be79u, 0xcb61b38cu, 0xbc66831au, 0x256fd2a0u, 0x5268e236u,
  861. 0xcc0c7795u, 0xbb0b4703u, 0x220216b9u, 0x5505262fu, 0xc5ba3bbeu,
  862. 0xb2bd0b28u, 0x2bb45a92u, 0x5cb36a04u, 0xc2d7ffa7u, 0xb5d0cf31u,
  863. 0x2cd99e8bu, 0x5bdeae1du, 0x9b64c2b0u, 0xec63f226u, 0x756aa39cu,
  864. 0x026d930au, 0x9c0906a9u, 0xeb0e363fu, 0x72076785u, 0x05005713u,
  865. 0x95bf4a82u, 0xe2b87a14u, 0x7bb12baeu, 0x0cb61b38u, 0x92d28e9bu,
  866. 0xe5d5be0du, 0x7cdcefb7u, 0x0bdbdf21u, 0x86d3d2d4u, 0xf1d4e242u,
  867. 0x68ddb3f8u, 0x1fda836eu, 0x81be16cdu, 0xf6b9265bu, 0x6fb077e1u,
  868. 0x18b74777u, 0x88085ae6u, 0xff0f6a70u, 0x66063bcau, 0x11010b5cu,
  869. 0x8f659effu, 0xf862ae69u, 0x616bffd3u, 0x166ccf45u, 0xa00ae278u,
  870. 0xd70dd2eeu, 0x4e048354u, 0x3903b3c2u, 0xa7672661u, 0xd06016f7u,
  871. 0x4969474du, 0x3e6e77dbu, 0xaed16a4au, 0xd9d65adcu, 0x40df0b66u,
  872. 0x37d83bf0u, 0xa9bcae53u, 0xdebb9ec5u, 0x47b2cf7fu, 0x30b5ffe9u,
  873. 0xbdbdf21cu, 0xcabac28au, 0x53b39330u, 0x24b4a3a6u, 0xbad03605u,
  874. 0xcdd70693u, 0x54de5729u, 0x23d967bfu, 0xb3667a2eu, 0xc4614ab8u,
  875. 0x5d681b02u, 0x2a6f2b94u, 0xb40bbe37u, 0xc30c8ea1u, 0x5a05df1bu,
  876. 0x2d02ef8du
  877. };
  878. }
  879. public Deflate()
  880. : this(-1, -1, -1, -1) {
  881. }
  882. public Deflate(int level)
  883. : this(level, -1, -1, -1) {
  884. }
  885. public Deflate(int level, int windowBits)
  886. : this(level, windowBits, -1, -1) {
  887. }
  888. public Deflate(int level, int windowBits, int memlevel)
  889. : this(level, windowBits, memlevel, -1) {
  890. }
  891. public Deflate(int level, int windowBits, int memlevel, int strategy) {
  892. // TODO: use parameters
  893. }
  894. [RubyMethod("deflate")]
  895. public static MutableString/*!*/ DeflateString(Deflate/*!*/ self, [DefaultProtocol, NotNull]MutableString/*!*/ str, int flush) {
  896. if (flush != FINISH) {
  897. throw new NotImplementedError("flush can only be FINISH");
  898. }
  899. MutableStringStream inputStream = new MutableStringStream(str);
  900. MutableStringStream outputStream = new MutableStringStream();
  901. ZDeflateStream compressedZipStream = new ZDeflateStream(outputStream, false);
  902. int remainingInputSize = str.Length;
  903. byte[] inputDataBlock = new byte[Math.Min(0x1000, remainingInputSize)];
  904. while (remainingInputSize > 0) {
  905. int count = inputStream.Read(inputDataBlock, 0, inputDataBlock.Length);
  906. compressedZipStream.Write(inputDataBlock, 0, count);
  907. remainingInputSize -= count;
  908. }
  909. compressedZipStream.Close();
  910. return outputStream.String;
  911. }
  912. [RubyMethod("deflate", RubyMethodAttributes.PublicSingleton)]
  913. public static MutableString/*!*/ DeflateString(RubyClass/*!*/ self, [DefaultProtocol, NotNull]MutableString/*!*/ str) {
  914. return DeflateString(new Deflate(), str, FINISH);
  915. }
  916. }
  917. #endif
  918. #endregion
  919. #region GzipWriter class
  920. #if !SILVERLIGHT
  921. [RubyClass("GzipWriter", BuildConfig="!SILVERLIGHT")]
  922. public class GzipWriter : GZipFile {
  923. private readonly GZipStream/*!*/ _gzipStream;
  924. // TODO:
  925. #pragma warning disable 414 // mcs: unused field
  926. [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")]
  927. private int _level, _strategy;
  928. #pragma warning restore 414
  929. private GzipWriter(RespondToStorage/*!*/ respondToStorage, RubyContext/*!*/ context, IOWrapper/*!*/ ioWrapper, int level, int strategy)
  930. : base(ioWrapper) {
  931. _level = level;
  932. _strategy = strategy;
  933. _gzipStream = new GZipStream(ioWrapper, CompressionMode.Compress, true);
  934. }
  935. [RubyConstructor]
  936. public static GzipWriter/*!*/ Create(
  937. RespondToStorage/*!*/ respondToStorage,
  938. RubyClass/*!*/ self,
  939. object io,
  940. [DefaultParameterValue(0)]int level,
  941. [DefaultParameterValue(DEFAULT_STRATEGY)]int strategy) {
  942. IOWrapper ioWrapper = RubyIOOps.CreateIOWrapper(respondToStorage, io, FileAccess.Write);
  943. if (ioWrapper == null || !ioWrapper.CanWrite) {
  944. throw RubyExceptions.CreateMethodMissing(self.Context, io, "write");
  945. }
  946. return new GzipWriter(respondToStorage, self.Context, ioWrapper, level, strategy);
  947. }
  948. // Zlib::GzipWriter.open(filename, level=nil, strategy=nil) { |gz| ... }
  949. [RubyMethod("<<")]
  950. public static GzipWriter Output(ConversionStorage<MutableString>/*!*/ tosConversion, RubyContext/*!*/ context, GzipWriter/*!*/ self, [DefaultProtocol, NotNull]MutableString/*!*/ str) {
  951. Write(tosConversion, context, self, str);
  952. return self;
  953. }
  954. [RubyMethod("close")]
  955. public static object/*!*/ Close(UnaryOpStorage/*!*/ closeStorage, RubyContext/*!*/ context, GzipWriter/*!*/ self) {
  956. if (self._isClosed) {
  957. throw new Error("closed gzip stream");
  958. }
  959. self._gzipStream.Close();
  960. self._ioWrapper.Flush();
  961. GZipFile.Close(closeStorage, self, true);
  962. return self._ioWrapper.UnderlyingObject;
  963. }
  964. [RubyMethod("finish")]
  965. public static object/*!*/ Finish(UnaryOpStorage/*!*/ closeStorage, RubyContext/*!*/ context, GzipWriter/*!*/ self) {
  966. self._gzipStream.Close();
  967. self._ioWrapper.Flush(closeStorage, context);
  968. GZipFile.Close(closeStorage, self, false);
  969. return self._ioWrapper.UnderlyingObject;
  970. }
  971. [RubyMethod("comment=")]
  972. public static MutableString/*!*/ Comment(GzipWriter/*!*/ self, [NotNull]MutableString/*!*/ comment) {
  973. if (self._isClosed) {
  974. throw new Error("closed gzip stream");
  975. }
  976. self._comment = comment;
  977. return comment;
  978. }
  979. [RubyMethod("flush")]
  980. public static GzipWriter Flush(UnaryOpStorage/*!*/ flushStorage, RubyContext/*!*/ context, GzipWriter/*!*/ self, object flush) {
  981. if (flush != null) {
  982. throw RubyExceptions.CreateUnexpectedTypeError(context, flush, "Fixnum");
  983. }
  984. return Flush(flushStorage, context, self, SYNC_FLUSH);
  985. }
  986. [RubyMethod("flush")]
  987. public static GzipWriter Flush(UnaryOpStorage/*!*/ flushStorage, RubyContext/*!*/ context, GzipWriter/*!*/ self, [DefaultParameterValue(SYNC_FLUSH)]int flush) {
  988. switch (flush) {
  989. case NO_FLUSH:
  990. case SYNC_FLUSH:
  991. case FULL_FLUSH:
  992. case FINISH:
  993. self._gzipStream.Flush();
  994. self._ioWrapper.Flush(flushStorage, context);
  995. break;
  996. default:
  997. throw new StreamError("stream error");
  998. }
  999. return self;
  1000. }
  1001. // mtime=(p1)
  1002. [RubyMethod("open", RubyMethodAttributes.PublicSingleton)]
  1003. public static object Open(
  1004. RespondToStorage/*!*/ respondToStorage,
  1005. UnaryOpStorage/*!*/ closeStorage,
  1006. BlockParam block,
  1007. RubyClass/*!*/ self,
  1008. [NotNull]MutableString filename,
  1009. [DefaultParameterValue(0)]int level,
  1010. [DefaultParameterValue(DEFAULT_STRATEGY)]int strategy) {
  1011. RubyFile file = new RubyFile(self.Context, filename.ConvertToString(), IOMode.CreateIfNotExists | IOMode.Truncate | IOMode.WriteOnly | IOMode.PreserveEndOfLines);
  1012. GzipWriter gzipFile = Create(respondToStorage, self, file, level, strategy);
  1013. if (block == null) {
  1014. return gzipFile;
  1015. }
  1016. try {
  1017. object blockResult;
  1018. block.Yield(gzipFile, out blockResult);
  1019. return blockResult;
  1020. } finally {
  1021. Close(closeStorage, self.Context, gzipFile);
  1022. }
  1023. }
  1024. [RubyMethod("open", RubyMethodAttributes.PublicSingleton)]
  1025. public static object Open(
  1026. RespondToStorage/*!*/ respondToStorage,
  1027. UnaryOpStorage/*!*/ closeStorage,
  1028. BlockParam block,
  1029. RubyClass/*!*/ self,
  1030. [NotNull]MutableString filename,
  1031. object level,
  1032. object strategy) {
  1033. if (level != null) {
  1034. throw RubyExceptions.CreateUnexpectedTypeError(self.Context, level, "Fixnum");
  1035. }
  1036. if (strategy != null) {

Large files files are truncated, but you can click here to view the full file