PageRenderTime 59ms CodeModel.GetById 24ms RepoModel.GetById 1ms app.codeStats 0ms

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

https://bitbucket.org/VahidN/interlace
C# | 527 lines | 405 code | 94 blank | 28 comment | 47 complexity | 08066354e049e02f31ce7683b21015bf 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.Diagnostics;
  29. using System.IO;
  30. using System.Text;
  31. #endregion
  32. namespace Interlace.Pinch.Implementation
  33. {
  34. public class PinchEncoder : IPinchEncoder
  35. {
  36. Stream _stream;
  37. byte[] _streamBuffer;
  38. byte[] _decimalBuffer;
  39. public PinchEncoder(Stream stream)
  40. {
  41. _stream = stream;
  42. _streamBuffer = new byte[8];
  43. _decimalBuffer = null;
  44. }
  45. #region Encoding Utilities
  46. void WriteUnsignedTag(uint tag)
  47. {
  48. uint remaining = tag;
  49. while (remaining > 0x7f)
  50. {
  51. _stream.WriteByte((byte)(remaining | 0x80));
  52. remaining >>= 7;
  53. }
  54. _stream.WriteByte((byte)remaining);
  55. }
  56. void WriteSignedTag(int tag)
  57. {
  58. uint remaining = ((uint)tag << 1) ^ (uint)(tag >> 31);
  59. while (remaining > 0x7f)
  60. {
  61. _stream.WriteByte((byte)(remaining | 0x80));
  62. remaining >>= 7;
  63. }
  64. _stream.WriteByte((byte)remaining);
  65. }
  66. void WriteSignedLongTag(long tag)
  67. {
  68. ulong remaining = ((ulong)tag << 1) ^ (ulong)(tag >> 63);
  69. while (remaining > 0x7f)
  70. {
  71. _stream.WriteByte((byte)(remaining | 0x80));
  72. remaining >>= 7;
  73. }
  74. _stream.WriteByte((byte)remaining);
  75. }
  76. #endregion
  77. #region Encoding Primatives
  78. void WriteSequenceMarker(int count)
  79. {
  80. if (count < 64)
  81. {
  82. _stream.WriteByte((byte)(PinchAssignedNumbers.PackedSequenceByte | count));
  83. }
  84. else
  85. {
  86. _stream.WriteByte(PinchAssignedNumbers.TaggedSequenceByte);
  87. WriteUnsignedTag((uint)count);
  88. }
  89. }
  90. void WritePrimativeBuffer(byte[] buffer, int offset, int length)
  91. {
  92. if (length < 64)
  93. {
  94. _stream.WriteByte((byte)(PinchAssignedNumbers.PackedPrimativeBufferByte | length));
  95. }
  96. else
  97. {
  98. _stream.WriteByte(PinchAssignedNumbers.TaggedPrimativeBufferByte);
  99. WriteUnsignedTag((uint)length);
  100. }
  101. _stream.Write(buffer, offset, length);
  102. }
  103. void WritePrimativeSignedOrdinal(int ordinal)
  104. {
  105. if (0 <= ordinal && ordinal < 64)
  106. {
  107. _stream.WriteByte((byte)(PinchAssignedNumbers.PackedPrimativeOrdinalByte | ordinal));
  108. }
  109. else
  110. {
  111. _stream.WriteByte(PinchAssignedNumbers.TaggedPrimativeOrdinalByte);
  112. WriteSignedTag(ordinal);
  113. }
  114. }
  115. void WritePrimativeUnsignedOrdinal(uint ordinal)
  116. {
  117. if (0 <= ordinal && ordinal < 64)
  118. {
  119. _stream.WriteByte((byte)(PinchAssignedNumbers.PackedPrimativeOrdinalByte | ordinal));
  120. }
  121. else
  122. {
  123. _stream.WriteByte(PinchAssignedNumbers.TaggedPrimativeOrdinalByte);
  124. WriteUnsignedTag(ordinal);
  125. }
  126. }
  127. void WritePrimativeLongOrdinal(long ordinal)
  128. {
  129. if (0 <= ordinal && ordinal < 64)
  130. {
  131. _stream.WriteByte((byte)(PinchAssignedNumbers.PackedPrimativeOrdinalByte | ordinal));
  132. }
  133. else
  134. {
  135. _stream.WriteByte(PinchAssignedNumbers.TaggedPrimativeOrdinalByte);
  136. WriteSignedLongTag(ordinal);
  137. }
  138. }
  139. void WriteNull()
  140. {
  141. _stream.WriteByte(PinchAssignedNumbers.Null);
  142. }
  143. public void EncodeChoiceMarker(int valueKind)
  144. {
  145. _stream.WriteByte(PinchAssignedNumbers.TaggedChoiceByte);
  146. WriteUnsignedTag((uint)valueKind);
  147. }
  148. public void EncodeRemoved()
  149. {
  150. _stream.WriteByte(PinchAssignedNumbers.Null);
  151. }
  152. #endregion
  153. #region Scaler Writing
  154. void WriteFloat(float value)
  155. {
  156. byte[] intelOrder = BitConverter.GetBytes(value);
  157. _streamBuffer[0] = intelOrder[3];
  158. _streamBuffer[1] = intelOrder[2];
  159. _streamBuffer[2] = intelOrder[1];
  160. _streamBuffer[3] = intelOrder[0];
  161. WritePrimativeBuffer(_streamBuffer, 0, 4);
  162. }
  163. void WriteDouble(double value)
  164. {
  165. byte[] intelOrder = BitConverter.GetBytes(value);
  166. _streamBuffer[0] = intelOrder[7];
  167. _streamBuffer[1] = intelOrder[6];
  168. _streamBuffer[2] = intelOrder[5];
  169. _streamBuffer[3] = intelOrder[4];
  170. _streamBuffer[4] = intelOrder[3];
  171. _streamBuffer[5] = intelOrder[2];
  172. _streamBuffer[6] = intelOrder[1];
  173. _streamBuffer[7] = intelOrder[0];
  174. WritePrimativeBuffer(_streamBuffer, 0, 8);
  175. }
  176. void WriteDecimal(decimal value)
  177. {
  178. if (_decimalBuffer == null) _decimalBuffer = new byte[14];
  179. int[] bits = decimal.GetBits(value);
  180. // Write the two scale bytes in full:
  181. _decimalBuffer[0] = (byte)((bits[3] & 0x00ff0000) >> 16);
  182. _decimalBuffer[1] = (byte)((bits[3] & 0xff000000) >> 24);
  183. int decimalBufferUsed = 2;
  184. // Encode the mantissa:
  185. ulong low = ((ulong)(uint)bits[0]) | (((ulong)(uint)bits[1]) << 32);
  186. uint high = (uint)bits[2];
  187. if (high == 0)
  188. {
  189. ulong remaining = low;
  190. while (remaining > 0)
  191. {
  192. _decimalBuffer[decimalBufferUsed++] = (byte)remaining;
  193. remaining >>= 8;
  194. }
  195. }
  196. else
  197. {
  198. ulong lowRemaining = low;
  199. int remainingOctets = 8;
  200. while (remainingOctets > 0)
  201. {
  202. _decimalBuffer[decimalBufferUsed++] = (byte)lowRemaining;
  203. lowRemaining >>= 8;
  204. remainingOctets--;
  205. }
  206. // Write the high word:
  207. uint highRemaining = high;
  208. while (highRemaining > 0)
  209. {
  210. _decimalBuffer[decimalBufferUsed++] = (byte)highRemaining;
  211. highRemaining >>= 8;
  212. }
  213. }
  214. WritePrimativeBuffer(_decimalBuffer, 0, decimalBufferUsed);
  215. }
  216. #endregion
  217. #region IPinchDecoder Members
  218. public void OpenSequence(int count)
  219. {
  220. if (count < 0) throw new ArgumentException("count");
  221. WriteSequenceMarker(count);
  222. }
  223. public void EncodeRequiredFloat32(float value, PinchFieldProperties properties)
  224. {
  225. WriteFloat(value);
  226. }
  227. public void EncodeRequiredFloat64(double value, PinchFieldProperties properties)
  228. {
  229. WriteDouble(value);
  230. }
  231. public void EncodeRequiredInt8(byte value, PinchFieldProperties properties)
  232. {
  233. WritePrimativeUnsignedOrdinal((uint)value);
  234. }
  235. public void EncodeRequiredInt16(short value, PinchFieldProperties properties)
  236. {
  237. WritePrimativeSignedOrdinal((int)value);
  238. }
  239. public void EncodeRequiredInt32(int value, PinchFieldProperties properties)
  240. {
  241. WritePrimativeSignedOrdinal(value);
  242. }
  243. public void EncodeRequiredInt64(long value, PinchFieldProperties properties)
  244. {
  245. WritePrimativeLongOrdinal(value);
  246. }
  247. public void EncodeRequiredDecimal(decimal value, PinchFieldProperties properties)
  248. {
  249. WriteDecimal(value);
  250. }
  251. public void EncodeRequiredBool(bool value, PinchFieldProperties properties)
  252. {
  253. WritePrimativeUnsignedOrdinal(value ? 1u : 0u);
  254. }
  255. public void EncodeRequiredString(string value, PinchFieldProperties properties)
  256. {
  257. if (value == null) throw new PinchNullRequiredFieldException();
  258. byte[] bytes = Encoding.UTF8.GetBytes(value);
  259. WritePrimativeBuffer(bytes, 0, bytes.Length);
  260. }
  261. public void EncodeRequiredBytes(byte[] value, PinchFieldProperties properties)
  262. {
  263. if (value == null) throw new PinchNullRequiredFieldException();
  264. WritePrimativeBuffer(value, 0, value.Length);
  265. }
  266. public void EncodeRequiredEnumeration(object value, PinchFieldProperties properties)
  267. {
  268. if (value == null) throw new PinchNullRequiredFieldException();
  269. WritePrimativeUnsignedOrdinal((uint)(int)value);
  270. }
  271. public void EncodeRequiredStructure(object value, PinchFieldProperties properties)
  272. {
  273. if (value == null) throw new PinchNullRequiredFieldException();
  274. EncodeStructure(this, value, false);
  275. }
  276. public void EncodeOptionalFloat32(float? value, PinchFieldProperties properties)
  277. {
  278. if (value.HasValue)
  279. {
  280. WriteFloat(value.Value);
  281. }
  282. else
  283. {
  284. WriteNull();
  285. }
  286. }
  287. public void EncodeOptionalFloat64(double? value, PinchFieldProperties properties)
  288. {
  289. if (value.HasValue)
  290. {
  291. WriteDouble(value.Value);
  292. }
  293. else
  294. {
  295. WriteNull();
  296. }
  297. }
  298. public void EncodeOptionalInt8(byte? value, PinchFieldProperties properties)
  299. {
  300. if (value.HasValue)
  301. {
  302. WritePrimativeUnsignedOrdinal((uint)value.Value);
  303. }
  304. else
  305. {
  306. WriteNull();
  307. }
  308. }
  309. public void EncodeOptionalInt16(short? value, PinchFieldProperties properties)
  310. {
  311. if (value.HasValue)
  312. {
  313. WritePrimativeSignedOrdinal((int)value.Value);
  314. }
  315. else
  316. {
  317. WriteNull();
  318. }
  319. }
  320. public void EncodeOptionalInt32(int? value, PinchFieldProperties properties)
  321. {
  322. if (value.HasValue)
  323. {
  324. WritePrimativeSignedOrdinal(value.Value);
  325. }
  326. else
  327. {
  328. WriteNull();
  329. }
  330. }
  331. public void EncodeOptionalInt64(long? value, PinchFieldProperties properties)
  332. {
  333. if (value.HasValue)
  334. {
  335. WritePrimativeLongOrdinal(value.Value);
  336. }
  337. else
  338. {
  339. WriteNull();
  340. }
  341. }
  342. public void EncodeOptionalDecimal(decimal? value, PinchFieldProperties properties)
  343. {
  344. if (value.HasValue)
  345. {
  346. WriteDecimal(value.Value);
  347. }
  348. else
  349. {
  350. WriteNull();
  351. }
  352. }
  353. public void EncodeOptionalBool(bool? value, PinchFieldProperties properties)
  354. {
  355. if (value.HasValue)
  356. {
  357. WritePrimativeUnsignedOrdinal(value.Value ? 1u : 0u);
  358. }
  359. else
  360. {
  361. WriteNull();
  362. }
  363. }
  364. public void EncodeOptionalString(string value, PinchFieldProperties properties)
  365. {
  366. if (value != null)
  367. {
  368. byte[] bytes = Encoding.UTF8.GetBytes(value);
  369. WritePrimativeBuffer(bytes, 0, bytes.Length);
  370. }
  371. else
  372. {
  373. WriteNull();
  374. }
  375. }
  376. public void EncodeOptionalBytes(byte[] value, PinchFieldProperties properties)
  377. {
  378. if (value != null)
  379. {
  380. WritePrimativeBuffer(value, 0, value.Length);
  381. }
  382. else
  383. {
  384. WriteNull();
  385. }
  386. }
  387. public void EncodeOptionalEnumeration(object value, PinchFieldProperties properties)
  388. {
  389. if (value != null)
  390. {
  391. WritePrimativeUnsignedOrdinal((uint)(int)value);
  392. }
  393. else
  394. {
  395. WriteNull();
  396. }
  397. }
  398. public void EncodeOptionalStructure(object value, PinchFieldProperties properties)
  399. {
  400. if (value != null)
  401. {
  402. EncodeStructure(this, value, false);
  403. }
  404. else
  405. {
  406. WriteNull();
  407. }
  408. }
  409. public void CloseSequence()
  410. {
  411. }
  412. #endregion
  413. #region Structure Encoding
  414. internal static void EncodeStructure(PinchEncoder encoder, object value, bool encodeHeader)
  415. {
  416. if (value == null) throw new ArgumentNullException("value");
  417. if (value is IPinchable)
  418. {
  419. IPinchable pinchable = value as IPinchable;
  420. if (encodeHeader) encoder.EncodeHeader(pinchable.ProtocolVersion);
  421. pinchable.Encode(encoder);
  422. }
  423. else
  424. {
  425. throw new InvalidOperationException("An object that could not be encoded by this library has been passed in.");
  426. }
  427. }
  428. internal void EncodeHeader(int protocolVersion)
  429. {
  430. }
  431. #endregion
  432. }
  433. }