Turn ByteQueue into MemoryStream wrapper, use MemoryStream for serialization of COutP...
[NovacoinLibrary.git] / Novacoin / VarInt.cs
1 \feff/**
2  *  Novacoin classes library
3  *  Copyright (C) 2015 Alex D. (balthazar.ad@gmail.com)
4
5  *  This program is free software: you can redistribute it and/or modify
6  *  it under the terms of the GNU Affero General Public License as
7  *  published by the Free Software Foundation, either version 3 of the
8  *  License, or (at your option) any later version.
9
10  *  This program is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  *  GNU Affero General Public License for more details.
14
15  *  You should have received a copy of the GNU Affero General Public License
16  *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
17  */
18
19 using System;
20 using System.Collections.Generic;
21 using System.IO;
22
23 namespace Novacoin
24 {
25     public class VarInt
26     {
27         /// <summary>
28         /// Encodes unsigned integer value into compact representation.
29         /// 
30         /// See https://bitcoin.org/en/developer-reference#compactsize-unsigned-integers for additional information.
31         /// </summary>
32         /// <param name="n">Unsigned integer value</param>
33         /// <returns>Byte sequence</returns>
34         public static byte[] EncodeVarInt(ulong n)
35         {
36             var resultBytes = new List<byte>();
37
38             if (n <= 0xfc)
39             {
40                 // Values up to 0xfc are stored directly without any prefix
41                 resultBytes.Add((byte)n);
42             }
43             else
44             {
45                 byte prefix;
46                 byte[] valueBytes;
47
48                 if (n <= ushort.MaxValue)
49                 {
50                     // ushort flag
51                     prefix = 0xfd;
52                     valueBytes = BitConverter.GetBytes((ushort)n);
53                 }
54                 else if (n <= uint.MaxValue)
55                 {
56                     // uint flag
57                     prefix = 0xfe;
58                     valueBytes = BitConverter.GetBytes((uint)n);
59                 }
60                 else
61                 {
62                     // ulong flag
63                     prefix = 0xff;
64                     valueBytes = BitConverter.GetBytes(n);
65                 }
66
67                 resultBytes.Add(prefix);
68                 resultBytes.AddRange(valueBytes);
69             }
70
71             return resultBytes.ToArray();
72         }
73
74         /// <summary>
75         /// Encodes integer value into compact representation.
76         /// 
77         /// See https://bitcoin.org/en/developer-reference#compactsize-unsigned-integers for additional information.
78         /// </summary>
79         /// <param name="n">Integer value</param>
80         /// <returns>Byte sequence</returns>
81         public static byte[] EncodeVarInt(long n)
82         {
83             return EncodeVarInt((ulong)n);
84         }
85
86         public static int GetEncodedSize(long n)
87         {
88             if (n <= 0xfc)
89             {
90                 return 1;
91             }
92             else if (n <= ushort.MaxValue)
93             {
94                 return 3;
95             }
96             else if (n <= uint.MaxValue)
97             {
98                 return 5;
99             }
100             else
101             {
102                 return 9;
103             }
104         }
105
106         /// <summary>
107         /// Decodes integer value from compact representation
108         /// 
109         /// See https://bitcoin.org/en/developer-reference#compactsize-unsigned-integers for additional information.
110         /// </summary>
111         /// <param name="bytes">Byte sequence</param>
112         /// <returns>Integer value</returns>
113         public static ulong DecodeVarInt(byte[] bytes)
114         {
115             var prefix = bytes[0];
116             var bytesArray = new byte[bytes.Length - 1];
117
118             bytes.CopyTo(bytesArray, 1);  // Get rid of prefix
119
120             switch (prefix)
121             {
122                 case 0xfd: // ushort flag
123                     return BitConverter.ToUInt16(bytesArray, 0);
124                 case 0xfe: // uint flag
125                     return BitConverter.ToUInt32(bytesArray, 0);
126                 case 0xff: // ulong flag
127                     return BitConverter.ToUInt64(bytesArray, 0);
128                 default:
129                     return prefix;
130             }
131         }
132
133         public static ulong ReadVarInt(ref BinaryReader reader)
134         {
135             byte prefix = reader.ReadByte();
136
137             switch (prefix)
138             {
139                 case 0xfd: // ushort
140                     return reader.ReadUInt16();
141                 case 0xfe: // uint
142                     return reader.ReadUInt32();
143                 case 0xff: // ulong
144                     return reader.ReadUInt64();
145                 default:
146                     return prefix;
147             }
148         }
149
150     }
151 }