Generic class was a bit excessive for our purposes
[NovacoinLibrary.git] / Novacoin / VarInt.cs
1 \feffusing System;
2 using System.Collections.Generic;
3 using System.Linq;
4 using System.Text;
5 using System.Threading.Tasks;
6
7 namespace Novacoin
8 {
9     public class VarInt
10     {
11         /// <summary>
12         /// Encodes unsigned integer value into compact representation.
13         /// 
14         /// See https://bitcoin.org/en/developer-reference#compactsize-unsigned-integers for additional information.
15         /// </summary>
16         /// <param name="n">Unsigned integer value</param>
17         /// <returns>Byte sequence</returns>
18         public static IList<byte> EncodeVarInt(ulong n)
19         {
20             List<byte> resultBytes = new List<byte>();
21
22             if (n <= 0xfc)
23             {
24                 // Values up to 0xfc are stored directly without any prefix
25                 resultBytes.Add((byte)n);
26             }
27             else
28             {
29                 byte prefix;
30                 byte[] valueBytes;
31
32                 if (n <= ushort.MaxValue)
33                 {
34                     // ushort flag
35                     prefix = 0xfd;
36                     valueBytes = BitConverter.GetBytes((ushort)n);
37                 }
38                 else if (n <= uint.MaxValue)
39                 {
40                     // uint flag
41                     prefix = 0xfe;
42                     valueBytes = BitConverter.GetBytes((uint)n);
43                 }
44                 else
45                 {
46                     // ulong flag
47                     prefix = 0xff;
48                     valueBytes = BitConverter.GetBytes(n);
49                 }
50
51                 resultBytes.Add(prefix);
52                 resultBytes.AddRange(valueBytes);
53             }
54
55             return resultBytes;
56         }
57
58         /// <summary>
59         /// Encodes integer value into compact representation.
60         /// 
61         /// See https://bitcoin.org/en/developer-reference#compactsize-unsigned-integers for additional information.
62         /// </summary>
63         /// <param name="n">Integer value</param>
64         /// <returns>Byte sequence</returns>
65         public static IList<byte> EncodeVarInt(long n)
66         {
67             return EncodeVarInt((ulong)n);
68         }
69
70         /// <summary>
71         /// Decodes integer value from compact representation
72         /// 
73         /// See https://bitcoin.org/en/developer-reference#compactsize-unsigned-integers for additional information.
74         /// </summary>
75         /// <param name="bytes">Byte sequence</param>
76         /// <returns>Integer value</returns>
77         public static ulong DecodeVarInt(IList<byte> bytes)
78         {
79             byte prefix = bytes[0];
80
81             bytes.RemoveAt(0); // Remove prefix
82
83             byte[] bytesArray = bytes.ToArray();
84
85             switch (prefix)
86             {
87                 case 0xfd: // ushort flag
88                     return BitConverter.ToUInt16(bytesArray, 0);
89                 case 0xfe: // uint flag
90                     return BitConverter.ToUInt32(bytesArray, 0);
91                 case 0xff: // ulong flag
92                     return BitConverter.ToUInt64(bytesArray, 0);
93                 default:
94                     return prefix;
95             }
96         }
97
98         /// <summary>
99         /// Read and decode variable integer from wrapped list object.
100         /// 
101         /// Note: Should be used only if there is some variable integer data at current position. Otherwise you will get undefined behavior, so make sure that you know what you are doing.
102         /// </summary>
103         /// <param name="wBytes"></param>
104         /// <returns></returns>
105         public static ulong ReadVarInt(ref ByteQueue wBytes)
106         {
107             byte prefix = wBytes.Get();
108
109             switch (prefix)
110             {
111                 case 0xfd: // ushort
112                     return BitConverter.ToUInt16(wBytes.Get(2), 0);
113                 case 0xfe: // uint
114                     return BitConverter.ToUInt32(wBytes.Get(4), 0);
115                 case 0xff: // ulong
116                     return BitConverter.ToUInt64(wBytes.Get(8), 0);
117                 default:
118                     return prefix;
119             }
120
121         }
122     }
123 }