CScript: disassembly support
[NovacoinLibrary.git] / Novacoin / CScript.cs
1 \feffusing System;
2 using System.Text;
3
4 using System.Collections;
5 using System.Collections.Generic;
6
7 namespace Novacoin
8 {
9     public class CScriptException : Exception
10     {
11         public CScriptException()
12         {
13         }
14
15         public CScriptException(string message)
16             : base(message)
17         {
18         }
19
20         public CScriptException(string message, Exception inner)
21             : base(message, inner)
22         {
23         }
24     }
25
26     /// <summary>
27     /// Representation of script code
28     /// </summary>
29         public class CScript
30         {
31         private List<byte> codeBytes;
32
33         /// <summary>
34         /// Initializes an empty instance of CScript
35         /// </summary>
36                 public CScript ()
37                 {
38             codeBytes = new List<byte>();
39                 }
40
41         /// <summary>
42         /// Initializes new instance of CScript and fills it with supplied bytes
43         /// </summary>
44         /// <param name="bytes">List of bytes</param>
45         public CScript(IList<byte> bytes)
46         {
47             codeBytes = new List<byte>(bytes);
48         }
49
50         /// <summary>
51         /// Initializes new instance of CScript and fills it with supplied bytes
52         /// </summary>
53         /// <param name="bytes">Array of bytes</param>
54         public CScript(byte[] bytes)
55         {
56             codeBytes = new List<byte>(bytes);
57         }
58
59         /// <summary>
60         /// Adds specified operation to opcode bytes list
61         /// </summary>
62         /// <param name="opcode"></param>
63         public void AddOp(opcodetype opcode)
64         {
65             if (opcode < opcodetype.OP_0 || opcode > opcodetype.OP_INVALIDOPCODE)
66             {
67                 throw new CScriptException("CScript::AddOp() : invalid opcode");
68             }
69
70             codeBytes.Add((byte)opcode);
71         }
72
73         /// <summary>
74         /// Adds hash to opcode bytes list.
75         ///    New items are added in this format:
76         ///    hash_length_byte hash_bytes
77         /// </summary>
78         /// <param name="hash">Hash160 instance</param>
79         public void AddHash(Hash160 hash)
80         {
81             codeBytes.Add((byte)hash.hashSize);
82             codeBytes.AddRange(hash.hashBytes);
83         }
84
85         /// <summary>
86         /// Adds hash to opcode bytes list.
87         ///    New items are added in this format:
88         ///    hash_length_byte hash_bytes
89         /// </summary>
90         /// <param name="hash">Hash256 instance</param>
91         public void AddHash(Hash256 hash)
92         {
93             codeBytes.Add((byte)hash.hashSize);
94             codeBytes.AddRange(hash.hashBytes);
95         }
96
97         public void PushData(IList<byte> dataBytes)
98         {
99             if (dataBytes.Count < (int)opcodetype.OP_PUSHDATA1)
100             {
101                 codeBytes.Add((byte)dataBytes.Count);
102             }
103             else if (dataBytes.Count < 0xff)
104             {
105                 codeBytes.Add((byte)opcodetype.OP_PUSHDATA1);
106                 codeBytes.Add((byte)dataBytes.Count);
107             }
108             else if (dataBytes.Count < 0xffff)
109             {
110                 codeBytes.Add((byte)opcodetype.OP_PUSHDATA2);
111
112                 byte[] szBytes = BitConverter.GetBytes((short)dataBytes.Count);
113                 if (BitConverter.IsLittleEndian)
114                     Array.Reverse(szBytes);
115
116                 codeBytes.AddRange(szBytes);
117             }
118             else if ((uint)dataBytes.Count < 0xffffffff)
119             {
120                 codeBytes.Add((byte)opcodetype.OP_PUSHDATA2);
121
122                 byte[] szBytes = BitConverter.GetBytes((uint)dataBytes.Count);
123                 if (BitConverter.IsLittleEndian)
124                     Array.Reverse(szBytes);
125
126                 codeBytes.AddRange(szBytes);
127             }
128             codeBytes.AddRange(dataBytes);
129         }
130
131         /// <summary>
132         /// Disassemble current script code
133         /// </summary>
134         /// <returns>Code listing</returns>
135                 public override string ToString()
136                 {
137                         StringBuilder sb = new StringBuilder();
138
139             WrappedList<byte> wCodeBytes = new WrappedList<byte>(codeBytes);
140
141             while (wCodeBytes.ItemsLeft > 0)
142             {
143                 if (sb.Length != 0)
144                 {
145                     sb.Append(" ");
146                 }
147
148                 opcodetype opcode;
149                 IEnumerable<byte> pushArgs;
150                 if (!ScriptOpcode.GetOp(ref wCodeBytes, out opcode, out pushArgs))
151                 {
152                     sb.Append("[error]");
153                     break;
154                 }
155
156                 if (0 <= opcode && opcode <= opcodetype.OP_PUSHDATA4)
157                 {
158                     sb.Append(ScriptOpcode.ValueString(pushArgs));
159                 }
160                 else
161                 {
162                     sb.Append(ScriptOpcode.GetOpName(opcode));
163                 }
164             }
165
166             return sb.ToString();
167                 }
168         }
169 }
170