PageRenderTime 73ms CodeModel.GetById 23ms RepoModel.GetById 0ms app.codeStats 0ms

/source/library/Interlace.Pinch/Interlace.Pinch.Implementation/PinchDecoder.cs

https://bitbucket.org/VahidN/interlace
C# | 831 lines | 605 code | 177 blank | 49 comment | 106 complexity | 574a627ebbc176f7b21417194973eec5 MD5 | raw file
  1. #region Using Directives and Copyright Notice
  2. // Copyright (c) 2007-2010, Computer Consultancy Pty Ltd
  3. // All rights reserved.
  4. //
  5. // Redistribution and use in source and binary forms, with or without
  6. // modification, are permitted provided that the following conditions are met:
  7. // * Redistributions of source code must retain the above copyright
  8. // notice, this list of conditions and the following disclaimer.
  9. // * Redistributions in binary form must reproduce the above copyright
  10. // notice, this list of conditions and the following disclaimer in the
  11. // documentation and/or other materials provided with the distribution.
  12. // * Neither the name of the Computer Consultancy Pty Ltd nor the
  13. // names of its contributors may be used to endorse or promote products
  14. // derived from this software without specific prior written permission.
  15. //
  16. // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  17. // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  18. // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  19. // ARE DISCLAIMED. IN NO EVENT SHALL COMPUTER CONSULTANCY PTY LTD BE LIABLE
  20. // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  21. // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
  22. // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
  23. // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  24. // LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  25. // OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
  26. // DAMAGE.
  27. using System;
  28. using System.Collections.Generic;
  29. using System.Diagnostics;
  30. using System.IO;
  31. using System.Text;
  32. #endregion
  33. namespace Interlace.Pinch.Implementation
  34. {
  35. public class PinchDecoder : IPinchDecoder
  36. {
  37. Stream _stream;
  38. byte[] _streamBuffer;
  39. byte[] _intelOrderBuffer;
  40. public PinchDecoder(Stream stream)
  41. {
  42. _stream = stream;
  43. _streamBuffer = new byte[8];
  44. _intelOrderBuffer = new byte[8];
  45. }
  46. #region Decoding Primitives
  47. enum TokenKind
  48. {
  49. Sequence, // (The argument is the number of tokens in the sequence, which must then be read.)
  50. PrimitiveBuffer, // (The argument is the number of bytes that follow in the buffer.)
  51. PrimitivePackedOrdinal, // (The argument is the ordinal value; nothing needs to be read.)
  52. PrimitiveTaggedOrdinal, // (No argument; the ordinal value must be read.)
  53. Choice, // (The value kind is the argument; the structure follows.)
  54. Null // (No argument and nothing to read after.)
  55. }
  56. bool _readRequired = true;
  57. TokenKind _readTokenKind;
  58. int _readTokenArgument;
  59. void ReadTokenInternal()
  60. {
  61. int readByte = _stream.ReadByte();
  62. if (readByte == -1) throw new PinchEndOfStreamException();
  63. byte tokenByte = (byte)readByte;
  64. byte maskedTokenByte = (byte)(tokenByte & PinchAssignedNumbers.PackedByteKindMask);
  65. switch (maskedTokenByte)
  66. {
  67. case PinchAssignedNumbers.PackedPrimativeOrdinalByte:
  68. _readTokenKind = TokenKind.PrimitivePackedOrdinal;
  69. _readTokenArgument = tokenByte & PinchAssignedNumbers.PackedByteValueMask;
  70. break;
  71. case PinchAssignedNumbers.PackedPrimativeBufferByte:
  72. _readTokenKind = TokenKind.PrimitiveBuffer;
  73. _readTokenArgument = tokenByte & PinchAssignedNumbers.PackedByteValueMask;
  74. break;
  75. case PinchAssignedNumbers.PackedSequenceByte:
  76. _readTokenKind = TokenKind.Sequence;
  77. _readTokenArgument = tokenByte & PinchAssignedNumbers.PackedByteValueMask;
  78. break;
  79. default:
  80. switch (tokenByte)
  81. {
  82. case PinchAssignedNumbers.Null:
  83. _readTokenKind = TokenKind.Null;
  84. break;
  85. case PinchAssignedNumbers.TaggedPrimativeOrdinalByte:
  86. _readTokenKind = TokenKind.PrimitiveTaggedOrdinal;
  87. break;
  88. case PinchAssignedNumbers.TaggedPrimativeBufferByte:
  89. _readTokenKind = TokenKind.PrimitiveBuffer;
  90. _readTokenArgument = (int)ReadUnsignedTag();
  91. break;
  92. case PinchAssignedNumbers.TaggedSequenceByte:
  93. _readTokenArgument = (int)ReadUnsignedTag();
  94. _readTokenKind = TokenKind.Sequence;
  95. break;
  96. case PinchAssignedNumbers.TaggedChoiceByte:
  97. _readTokenKind = TokenKind.Choice;
  98. _readTokenArgument = (int)ReadUnsignedTag();
  99. break;
  100. }
  101. break;
  102. }
  103. }
  104. TokenKind PeekToken()
  105. {
  106. if (_readRequired) ReadTokenInternal();
  107. _readRequired = false;
  108. return _readTokenKind;
  109. }
  110. TokenKind ReadToken()
  111. {
  112. if (_readRequired) ReadTokenInternal();
  113. _readRequired = true;
  114. return _readTokenKind;
  115. }
  116. #endregion
  117. #region Decoding Utilities
  118. void BufferBytes(int count)
  119. {
  120. int totalRead = 0;
  121. while (totalRead < count)
  122. {
  123. int read = _stream.Read(_streamBuffer, totalRead, count - totalRead);
  124. if (read == 0) throw new PinchEndOfStreamException();
  125. totalRead += read;
  126. }
  127. }
  128. byte[] ReadBytes(int count)
  129. {
  130. byte[] bytes = new byte[count];
  131. int totalRead = 0;
  132. while (totalRead < count)
  133. {
  134. int read = _stream.Read(bytes, totalRead, count - totalRead);
  135. if (read == 0) throw new PinchEndOfStreamException();
  136. totalRead += read;
  137. }
  138. return bytes;
  139. }
  140. void SkipBytes(int count)
  141. {
  142. if (_stream.CanSeek && count > 32)
  143. {
  144. // (Seeking may be more expensive than a small read in some situations.)
  145. _stream.Seek(count, SeekOrigin.Current);
  146. }
  147. else
  148. {
  149. byte[] bytes = new byte[Math.Min(count, 1024)];
  150. int totalRead = 0;
  151. while (totalRead < count)
  152. {
  153. int read = _stream.Read(bytes, totalRead, Math.Min(count - totalRead, 1024));
  154. if (read == 0) throw new PinchEndOfStreamException();
  155. totalRead += read;
  156. }
  157. }
  158. }
  159. uint ReadUnsignedTag()
  160. {
  161. int shift = 0;
  162. uint tag = 0;
  163. int readByte;
  164. do
  165. {
  166. readByte = _stream.ReadByte();
  167. if (readByte == -1) throw new PinchEndOfStreamException();
  168. if (shift >= 31) throw new PinchInvalidCodingException();
  169. tag |= (uint)(readByte & 0x7f) << shift;
  170. shift += 7;
  171. }
  172. while ((readByte & 0x80) != 0);
  173. return tag;
  174. }
  175. int ReadSignedTag()
  176. {
  177. int shift = 0;
  178. uint tag = 0;
  179. int readByte;
  180. do
  181. {
  182. readByte = _stream.ReadByte();
  183. if (readByte == -1) throw new PinchEndOfStreamException();
  184. if (shift >= 32) throw new PinchInvalidCodingException();
  185. tag |= (uint)(readByte & 0x7f) << shift;
  186. shift += 7;
  187. }
  188. while ((readByte & 0x80) != 0);
  189. return (int)(tag >> 1) ^ ((int)tag << 31 >> 31);
  190. }
  191. long ReadSignedLongTag()
  192. {
  193. int shift = 0;
  194. ulong tag = 0;
  195. int readByte;
  196. do
  197. {
  198. readByte = _stream.ReadByte();
  199. if (readByte == -1) throw new PinchEndOfStreamException();
  200. if (shift >= 64) throw new PinchInvalidCodingException();
  201. tag |= (ulong)(readByte & 0x7f) << shift;
  202. shift += 7;
  203. }
  204. while ((readByte & 0x80) != 0);
  205. return (long)(tag >> 1) ^ ((long)tag << 63 >> 63);
  206. }
  207. void SkipTag()
  208. {
  209. int readByte;
  210. do
  211. {
  212. readByte = _stream.ReadByte();
  213. if (readByte == -1) throw new PinchEndOfStreamException();
  214. }
  215. while ((readByte & 0x80) != 0);
  216. }
  217. decimal ReadDecimal()
  218. {
  219. // Read the buffer token and length, ensuring it has enough bytes to be valid:
  220. TokenKind token = ReadToken();
  221. if (token != TokenKind.PrimitiveBuffer || _readTokenArgument < 2) throw new PinchInvalidCodingException();
  222. BufferBytes(2);
  223. byte scale = _streamBuffer[0];
  224. bool isNegative = (_streamBuffer[1] & 0x80) != 0;
  225. int bufferLength = _readTokenArgument;
  226. int bufferUsed = 2;
  227. // Read the low bits:
  228. int lowShift = 0;
  229. int lowReadByte;
  230. ulong low = 0;
  231. while (lowShift != 64 && bufferUsed != bufferLength)
  232. {
  233. lowReadByte = _stream.ReadByte();
  234. bufferUsed++;
  235. if (lowReadByte == -1) throw new PinchEndOfStreamException();
  236. low |= (ulong)((byte)lowReadByte) << lowShift;
  237. lowShift += 8;
  238. }
  239. // If the last low octet had a continuation bit, continue reading into high:
  240. int highShift = 0;
  241. int highReadByte;
  242. uint high = 0;
  243. while (bufferUsed != bufferLength)
  244. {
  245. highReadByte = _stream.ReadByte();
  246. bufferUsed++;
  247. if (highReadByte == -1) throw new PinchEndOfStreamException();
  248. if (highShift == 32) throw new PinchInvalidCodingException();
  249. high |= (uint)((byte)highReadByte) << highShift;
  250. highShift += 8;
  251. }
  252. int intLow = (int)(uint)low;
  253. int intMiddle = (int)(uint)(low >> 32);
  254. int intHigh = (int)high;
  255. return new decimal(intLow, intMiddle, intHigh, isNegative, scale);
  256. }
  257. #endregion
  258. #region Decoding Assistants
  259. void BufferPrimitiveBuffer(int expectedLength)
  260. {
  261. if (expectedLength > _streamBuffer.Length) throw new InvalidOperationException();
  262. TokenKind token = ReadToken();
  263. if (token != TokenKind.PrimitiveBuffer) throw new PinchInvalidCodingException();
  264. if (_readTokenArgument != expectedLength) throw new PinchInvalidCodingException();
  265. BufferBytes(expectedLength);
  266. }
  267. byte[] ReadPrimitiveBuffer()
  268. {
  269. TokenKind token = ReadToken();
  270. if (token != TokenKind.PrimitiveBuffer) throw new PinchInvalidCodingException();
  271. return ReadBytes(_readTokenArgument);
  272. }
  273. int ReadPrimitiveSignedOrdinal()
  274. {
  275. TokenKind token = ReadToken();
  276. if (token == TokenKind.PrimitivePackedOrdinal)
  277. {
  278. return _readTokenArgument;
  279. }
  280. else if (token == TokenKind.PrimitiveTaggedOrdinal)
  281. {
  282. return ReadSignedTag();
  283. }
  284. else
  285. {
  286. throw new PinchInvalidCodingException();
  287. }
  288. }
  289. uint ReadPrimitiveUnsignedOrdinal()
  290. {
  291. TokenKind token = ReadToken();
  292. if (token == TokenKind.PrimitivePackedOrdinal)
  293. {
  294. return (uint)_readTokenArgument;
  295. }
  296. else if (token == TokenKind.PrimitiveTaggedOrdinal)
  297. {
  298. return ReadUnsignedTag();
  299. }
  300. else
  301. {
  302. throw new PinchInvalidCodingException();
  303. }
  304. }
  305. long ReadPrimitiveLongOrdinal()
  306. {
  307. TokenKind token = ReadToken();
  308. if (token == TokenKind.PrimitivePackedOrdinal)
  309. {
  310. return _readTokenArgument;
  311. }
  312. else if (token == TokenKind.PrimitiveTaggedOrdinal)
  313. {
  314. return ReadSignedLongTag();
  315. }
  316. else
  317. {
  318. throw new PinchInvalidCodingException();
  319. }
  320. }
  321. #endregion
  322. #region IPinchDecoder Implementation
  323. public int OpenSequence()
  324. {
  325. TokenKind token = ReadToken();
  326. if (token != TokenKind.Sequence) throw new PinchInvalidCodingException();
  327. return _readTokenArgument;
  328. }
  329. public int? OpenOptionalSequence()
  330. {
  331. TokenKind token = ReadToken();
  332. if (token == TokenKind.Null) return null;
  333. if (token != TokenKind.Sequence) throw new PinchInvalidCodingException();
  334. return _readTokenArgument;
  335. }
  336. public int DecodeChoiceMarker()
  337. {
  338. TokenKind token = ReadToken();
  339. if (token != TokenKind.Choice) throw new PinchInvalidCodingException();
  340. return _readTokenArgument;
  341. }
  342. public int? DecodeOptionalChoiceMarker()
  343. {
  344. TokenKind token = ReadToken();
  345. if (token == TokenKind.Null) return null;
  346. if (token != TokenKind.Choice) throw new PinchInvalidCodingException();
  347. return _readTokenArgument;
  348. }
  349. public float DecodeRequiredFloat32(PinchFieldProperties properties)
  350. {
  351. BufferPrimitiveBuffer(4);
  352. _intelOrderBuffer[0] = _streamBuffer[3];
  353. _intelOrderBuffer[1] = _streamBuffer[2];
  354. _intelOrderBuffer[2] = _streamBuffer[1];
  355. _intelOrderBuffer[3] = _streamBuffer[0];
  356. return BitConverter.ToSingle(_intelOrderBuffer, 0);
  357. }
  358. public double DecodeRequiredFloat64(PinchFieldProperties properties)
  359. {
  360. BufferPrimitiveBuffer(8);
  361. _intelOrderBuffer[0] = _streamBuffer[7];
  362. _intelOrderBuffer[1] = _streamBuffer[6];
  363. _intelOrderBuffer[2] = _streamBuffer[5];
  364. _intelOrderBuffer[3] = _streamBuffer[4];
  365. _intelOrderBuffer[4] = _streamBuffer[3];
  366. _intelOrderBuffer[5] = _streamBuffer[2];
  367. _intelOrderBuffer[6] = _streamBuffer[1];
  368. _intelOrderBuffer[7] = _streamBuffer[0];
  369. return BitConverter.ToDouble(_intelOrderBuffer, 0);
  370. }
  371. public byte DecodeRequiredInt8(PinchFieldProperties properties)
  372. {
  373. return (byte)ReadPrimitiveUnsignedOrdinal();
  374. }
  375. public short DecodeRequiredInt16(PinchFieldProperties properties)
  376. {
  377. return (short)ReadPrimitiveSignedOrdinal();
  378. }
  379. public int DecodeRequiredInt32(PinchFieldProperties properties)
  380. {
  381. return ReadPrimitiveSignedOrdinal();
  382. }
  383. public long DecodeRequiredInt64(PinchFieldProperties properties)
  384. {
  385. return ReadPrimitiveLongOrdinal();
  386. }
  387. public decimal DecodeRequiredDecimal(PinchFieldProperties properties)
  388. {
  389. return ReadDecimal();
  390. }
  391. public bool DecodeRequiredBool(PinchFieldProperties properties)
  392. {
  393. return ReadPrimitiveUnsignedOrdinal() == 1;
  394. }
  395. public string DecodeRequiredString(PinchFieldProperties properties)
  396. {
  397. byte[] bytes = ReadPrimitiveBuffer();
  398. return Encoding.UTF8.GetString(bytes);
  399. }
  400. public byte[] DecodeRequiredBytes(PinchFieldProperties properties)
  401. {
  402. return ReadPrimitiveBuffer();
  403. }
  404. public int DecodeRequiredEnumeration(PinchFieldProperties properties)
  405. {
  406. return (int)ReadPrimitiveUnsignedOrdinal();
  407. }
  408. public object DecodeRequiredStructure(IPinchableFactory factory, PinchFieldProperties properties)
  409. {
  410. return PinchDecoder.DecodeStructure(this, factory, false);
  411. }
  412. bool IsOptionalFieldPresent()
  413. {
  414. return PeekToken() != TokenKind.Null;
  415. }
  416. void ReadNull()
  417. {
  418. TokenKind token = ReadToken();
  419. if (token != TokenKind.Null) throw new InvalidOperationException();
  420. }
  421. public float? DecodeOptionalFloat32(PinchFieldProperties properties)
  422. {
  423. if (IsOptionalFieldPresent())
  424. {
  425. BufferPrimitiveBuffer(4);
  426. _intelOrderBuffer[0] = _streamBuffer[3];
  427. _intelOrderBuffer[1] = _streamBuffer[2];
  428. _intelOrderBuffer[2] = _streamBuffer[1];
  429. _intelOrderBuffer[3] = _streamBuffer[0];
  430. return BitConverter.ToSingle(_intelOrderBuffer, 0);
  431. }
  432. else
  433. {
  434. ReadNull();
  435. return null;
  436. }
  437. }
  438. public double? DecodeOptionalFloat64(PinchFieldProperties properties)
  439. {
  440. if (IsOptionalFieldPresent())
  441. {
  442. BufferPrimitiveBuffer(8);
  443. _intelOrderBuffer[0] = _streamBuffer[7];
  444. _intelOrderBuffer[1] = _streamBuffer[6];
  445. _intelOrderBuffer[2] = _streamBuffer[5];
  446. _intelOrderBuffer[3] = _streamBuffer[4];
  447. _intelOrderBuffer[4] = _streamBuffer[3];
  448. _intelOrderBuffer[5] = _streamBuffer[2];
  449. _intelOrderBuffer[6] = _streamBuffer[1];
  450. _intelOrderBuffer[7] = _streamBuffer[0];
  451. return BitConverter.ToDouble(_intelOrderBuffer, 0);
  452. }
  453. else
  454. {
  455. ReadNull();
  456. return null;
  457. }
  458. }
  459. public byte? DecodeOptionalInt8(PinchFieldProperties properties)
  460. {
  461. if (IsOptionalFieldPresent())
  462. {
  463. return (byte)ReadPrimitiveUnsignedOrdinal();
  464. }
  465. else
  466. {
  467. ReadNull();
  468. return null;
  469. }
  470. }
  471. public short? DecodeOptionalInt16(PinchFieldProperties properties)
  472. {
  473. if (IsOptionalFieldPresent())
  474. {
  475. return (short)ReadPrimitiveSignedOrdinal();
  476. }
  477. else
  478. {
  479. ReadNull();
  480. return null;
  481. }
  482. }
  483. public int? DecodeOptionalInt32(PinchFieldProperties properties)
  484. {
  485. if (IsOptionalFieldPresent())
  486. {
  487. return ReadPrimitiveSignedOrdinal();
  488. }
  489. else
  490. {
  491. ReadNull();
  492. return null;
  493. }
  494. }
  495. public long? DecodeOptionalInt64(PinchFieldProperties properties)
  496. {
  497. if (IsOptionalFieldPresent())
  498. {
  499. return ReadPrimitiveLongOrdinal();
  500. }
  501. else
  502. {
  503. ReadNull();
  504. return null;
  505. }
  506. }
  507. public decimal? DecodeOptionalDecimal(PinchFieldProperties properties)
  508. {
  509. if (IsOptionalFieldPresent())
  510. {
  511. return ReadDecimal();
  512. }
  513. else
  514. {
  515. ReadNull();
  516. return null;
  517. }
  518. }
  519. public bool? DecodeOptionalBool(PinchFieldProperties properties)
  520. {
  521. if (IsOptionalFieldPresent())
  522. {
  523. return ReadPrimitiveUnsignedOrdinal() == 1;
  524. }
  525. else
  526. {
  527. ReadNull();
  528. return null;
  529. }
  530. }
  531. public string DecodeOptionalString(PinchFieldProperties properties)
  532. {
  533. if (IsOptionalFieldPresent())
  534. {
  535. byte[] bytes = ReadPrimitiveBuffer();
  536. return Encoding.UTF8.GetString(bytes);
  537. }
  538. else
  539. {
  540. ReadNull();
  541. return null;
  542. }
  543. }
  544. public byte[] DecodeOptionalBytes(PinchFieldProperties properties)
  545. {
  546. if (IsOptionalFieldPresent())
  547. {
  548. return ReadPrimitiveBuffer();
  549. }
  550. else
  551. {
  552. ReadNull();
  553. return null;
  554. }
  555. }
  556. public int? DecodeOptionalEnumeration(PinchFieldProperties properties)
  557. {
  558. if (IsOptionalFieldPresent())
  559. {
  560. return (int)ReadPrimitiveUnsignedOrdinal();
  561. }
  562. else
  563. {
  564. ReadNull();
  565. return null;
  566. }
  567. }
  568. public object DecodeOptionalStructure(IPinchableFactory factory, PinchFieldProperties properties)
  569. {
  570. if (IsOptionalFieldPresent())
  571. {
  572. return PinchDecoder.DecodeStructure(this, factory, false);
  573. }
  574. else
  575. {
  576. ReadNull();
  577. return null;
  578. }
  579. }
  580. public void SkipFields(int remainingFields)
  581. {
  582. for (int i = 0; i < remainingFields; i++)
  583. {
  584. TokenKind token = ReadToken();
  585. switch (token)
  586. {
  587. case TokenKind.Sequence:
  588. SkipFields(_readTokenArgument);
  589. break;
  590. case TokenKind.PrimitiveBuffer:
  591. SkipBytes(_readTokenArgument);
  592. break;
  593. case TokenKind.PrimitivePackedOrdinal:
  594. break;
  595. case TokenKind.PrimitiveTaggedOrdinal:
  596. SkipTag();
  597. break;
  598. case TokenKind.Choice:
  599. SkipTag();
  600. SkipFields(1);
  601. break;
  602. case TokenKind.Null:
  603. break;
  604. }
  605. }
  606. }
  607. public void SkipRemoved()
  608. {
  609. SkipFields(1);
  610. }
  611. public void CloseSequence()
  612. {
  613. }
  614. #endregion
  615. internal static object DecodeStructure(PinchDecoder pinchDecoder, IPinchableFactory factory, bool expectHeader)
  616. {
  617. object value = factory.Create(null);
  618. if (value is IPinchable)
  619. {
  620. IPinchable pinchable = value as IPinchable;
  621. /*
  622. if (expectHeader)
  623. {
  624. int protocolVersion;
  625. pinchDecoder.DecodeHeader(out protocolVersion);
  626. if (protocolVersion == 0)
  627. {
  628. throw new NotImplementedException("Protocol identifier tagging is not yet implemented in this reader.");
  629. }
  630. if (protocolVersion != pinchable.ProtocolVersion)
  631. {
  632. throw new NotImplementedException(string.Format(
  633. "Versioning is not yet implemented; version {0} is supported by this " +
  634. "reader, but the encoded data was version {1}.", pinchable.ProtocolVersion, protocolVersion));
  635. }
  636. }
  637. */
  638. pinchable.Decode(pinchDecoder);
  639. }
  640. else
  641. {
  642. throw new InvalidOperationException();
  643. }
  644. return value;
  645. }
  646. internal void DecodeHeader(out int protocolVersion)
  647. {
  648. protocolVersion = 0;
  649. }
  650. }
  651. }