Coverage Summary for Class: Value (org.ethereum.util)
Class |
Class, %
|
Method, %
|
Line, %
|
Value |
0%
(0/1)
|
0%
(0/30)
|
0%
(0/132)
|
1 /*
2 * This file is part of RskJ
3 * Copyright (C) 2017 RSK Labs Ltd.
4 * (derived from ethereumJ library, Copyright (c) 2016 <ether.camp>)
5 *
6 * This program is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU Lesser General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20 package org.ethereum.util;
21
22 import org.ethereum.crypto.HashUtil;
23
24 import java.math.BigInteger;
25 import java.nio.charset.StandardCharsets;
26 import java.util.Arrays;
27 import java.util.List;
28
29 /**
30 * Class to encapsulate an object and provide utilities for conversion
31 */
32 public class Value {
33
34 private Object value;
35 private byte[] rlp;
36 private byte[] keccak256;
37
38 public static Value fromRlpEncoded(byte[] data) {
39 if (data != null && data.length != 0) {
40 Value v = new Value();
41 v.init(data);
42 return v;
43 }
44 return null;
45 }
46
47 public Value() {
48 }
49
50 public void init(byte[] rlp){
51 this.rlp = rlp;
52 }
53
54 public Value(Object obj) {
55 if (obj == null) {
56 return;
57 }
58
59 if (obj instanceof Value) {
60 this.value = ((Value) obj).asObj();
61 } else {
62 this.value = obj;
63 }
64 }
65
66 /* *****************
67 * Convert
68 * *****************/
69
70 public Object asObj() {
71 return value;
72 }
73
74 public List<Object> asList() {
75 Object[] valueArray = (Object[]) value;
76 return Arrays.asList(valueArray);
77 }
78
79 public int asInt() {
80 if (isInt()) {
81 return (Integer) value;
82 } else if (isBytes()) {
83 return new BigInteger(1, asBytes()).intValue();
84 }
85 return 0;
86 }
87
88 public long asLong() {
89 if (isLong()) {
90 return (Long) value;
91 } else if (isBytes()) {
92 return new BigInteger(1, asBytes()).longValue();
93 }
94 return 0;
95 }
96
97 public BigInteger asBigInt() {
98 return (BigInteger) value;
99 }
100
101 public String asString() {
102 if (isBytes()) {
103 return new String((byte[]) value);
104 } else if (isString()) {
105 return (String) value;
106 }
107 return "";
108 }
109
110 public byte[] asBytes() {
111 if (isBytes()) {
112 return (byte[]) value;
113 } else if (isString()) {
114 return asString().getBytes(StandardCharsets.UTF_8);
115 }
116 return ByteUtil.EMPTY_BYTE_ARRAY;
117 }
118
119 public String getHex(){
120 return ByteUtil.toHexString(this.encode());
121 }
122
123 public byte[] getData(){
124 return this.encode();
125 }
126
127
128 public int[] asSlice() {
129 return (int[]) value;
130 }
131
132 public Value get(int index) {
133 if (isList()) {
134 // Guard for OutOfBounds
135 if (asList().size() <= index) {
136 return new Value(null);
137 }
138 if (index < 0) {
139 throw new RuntimeException("Negative index not allowed");
140 }
141 return new Value(asList().get(index));
142 }
143 // If this wasn't a slice you probably shouldn't be using this function
144 return new Value(null);
145 }
146
147 /* *****************
148 * Utility
149 * *****************/
150
151 public byte[] encode() {
152 if (rlp == null) {
153 rlp = RLP.encode(value);
154 }
155 return rlp;
156 }
157
158 public byte[] hash(){
159 if (keccak256 == null) {
160 keccak256 = HashUtil.keccak256(encode());
161 }
162 return keccak256;
163 }
164
165 /* *****************
166 * Checks
167 * *****************/
168
169 public boolean isList() {
170 return value != null && value.getClass().isArray() && !value.getClass().getComponentType().isPrimitive();
171 }
172
173 public boolean isString() {
174 return value instanceof String;
175 }
176
177 public boolean isInt() {
178 return value instanceof Integer;
179 }
180
181 public boolean isLong() {
182 return value instanceof Long;
183 }
184
185 public boolean isBigInt() {
186 return value instanceof BigInteger;
187 }
188
189 public boolean isBytes() {
190 return value instanceof byte[];
191 }
192
193 // it's only if the isBytes() = true
194 public boolean isReadableString() {
195
196 int readableChars = 0;
197 byte[] data = (byte[]) value;
198
199 if (data.length == 1 && data[0] > 31 && data[0] < 126) {
200 return true;
201 }
202
203 for (byte aData : data) {
204 if (aData > 32 && aData < 126) {
205 ++readableChars;
206 }
207 }
208
209 return (double) readableChars / (double) data.length > 0.55;
210 }
211
212 // it's only if the isBytes() = true
213 public boolean isHexString() {
214
215 int hexChars = 0;
216 byte[] data = (byte[]) value;
217
218 for (byte aData : data) {
219
220 if ((aData >= 48 && aData <= 57)
221 || (aData >= 97 && aData <= 102)) {
222 ++hexChars;
223 }
224 }
225
226 return (double) hexChars / (double) data.length > 0.9;
227 }
228
229 public boolean isHashCode() {
230 return this.asBytes().length == 32;
231 }
232
233 public boolean isNull() {
234 return value == null;
235 }
236
237 public boolean isEmpty() {
238 if (isNull()) {
239 return true;
240 }
241 if (isBytes() && asBytes().length == 0) {
242 return true;
243 }
244 if (isList() && asList().isEmpty()) {
245 return true;
246 }
247 if (isString() && asString().equals("")) {
248 return true;
249 }
250
251 return false;
252 }
253
254 public int length() {
255 if (isList()) {
256 return asList().size();
257 } else if (isBytes()) {
258 return asBytes().length;
259 } else if (isString()) {
260 return asString().length();
261 }
262 return 0;
263 }
264
265 public String toString() {
266
267 StringBuilder stringBuilder = new StringBuilder();
268
269 if (isList()) {
270
271 Object[] list = (Object[]) value;
272
273 // special case - key/value node
274 if (list.length == 2) {
275
276 stringBuilder.append("[ ");
277
278 Value key = new Value(list[0]);
279
280 byte[] keyNibbles = CompactEncoder.binToNibblesNoTerminator(key.asBytes());
281 String keyString = ByteUtil.nibblesToPrettyString(keyNibbles);
282 stringBuilder.append(keyString);
283
284 stringBuilder.append(",");
285
286 Value val = new Value(list[1]);
287 stringBuilder.append(val.toString());
288
289 stringBuilder.append(" ]");
290 return stringBuilder.toString();
291 }
292 stringBuilder.append(" [");
293
294 for (int i = 0; i < list.length; ++i) {
295 Value val = new Value(list[i]);
296 if (val.isString() || val.isEmpty()) {
297 stringBuilder.append("'").append(val.toString()).append("'");
298 } else {
299 stringBuilder.append(val.toString());
300 }
301 if (i < list.length - 1) {
302 stringBuilder.append(", ");
303 }
304 }
305 stringBuilder.append("] ");
306
307 return stringBuilder.toString();
308 } else if (isEmpty()) {
309 return "";
310 } else if (isBytes()) {
311
312 StringBuilder output = new StringBuilder();
313 if (isHashCode()) {
314 output.append(ByteUtil.toHexString(asBytes()));
315 } else if (isReadableString()) {
316 output.append("'");
317 for (byte oneByte : asBytes()) {
318 if (oneByte < 16) {
319 output.append("\\x").append(ByteUtil.oneByteToHexString(oneByte));
320 } else {
321 output.append(Character.valueOf((char) oneByte));
322 }
323 }
324 output.append("'");
325 return output.toString();
326 }
327 return ByteUtil.toHexString(this.asBytes());
328 } else if (isString()) {
329 return asString();
330 }
331 return "Unexpected type";
332 }
333
334 }