-
Notifications
You must be signed in to change notification settings - Fork 0
/
AFieldTable.java
171 lines (137 loc) · 5.77 KB
/
AFieldTable.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
import java.util.*;
//Field table type
public class AFieldTable extends AMQPNativeType {
/*
A Field Table looks like this:
Long_UINT (4 bytes) = Length of table payload
For each member in the field:
ShortString Key
AOctet Value-Type (Basically one char specifying the type, see spec for full list)
Variable Value
*/
//LinkedHashMap of all data stored within the Field Table
//Linked because we want to store the order of the elements (which should really
//not matter but it might be good for fuzzing later on)
LinkedHashMap<AShortString, AMQPNativeType> members = new LinkedHashMap<AShortString, AMQPNativeType>();
//Constructor when not created from an incoming data buffer
AFieldTable(LinkedHashMap<AShortString, AMQPNativeType> members) {
this.members = members;
this.type = AMQPNativeType.Type.FIELD_TABLE;
}
//Empty constructor, used when creating data programmatically
AFieldTable() {
this.type = AMQPNativeType.Type.FIELD_TABLE;
}
//Constructor
//Takes the ByteArrayBuffer and pops one complete Field Table from it
AFieldTable(ByteArrayBuffer byteArrayBuffer) throws InvalidTypeException {
if (byteArrayBuffer.length() < 4) throw new InvalidTypeException("Invalid Field Table length");
this.type = AMQPNativeType.Type.FIELD_TABLE;
//Pop first 4 bytes of the buffer into an ALongUInt
ALongUInt length = new ALongUInt(byteArrayBuffer);
//System.out.println("Creating new Field Table with byte size: " + length.toInt());
//Pop the field table payload
ByteArrayBuffer payload = byteArrayBuffer.pop(length.toLong());
//Loop over the fields and store them one by one in the LinkedHashMap
while (payload.length() > 0) {
//System.out.println("FieldTable: Length left: " + payload.length());
//System.out.println("----------------------------");
//Pop the key string from the buffer
AShortString key = new AShortString(payload);
//System.out.println("Key : " + key.toString());
//Pop the value type
AOctet valueType = new AOctet(payload);
//System.out.println("Value type : " + valueType.toString());
//Now we know the key and the value type, and we need to create different
//AMQPNativeType objects depending on what the valueType is
//long-string
if (valueType.toWire().toString().equals("S")) {
ALongString value = new ALongString(payload);
//System.out.println("Long String: " + value.toString());
members.put(key, value);
continue;
}
//short-string
if (valueType.toWire().toString().equals("s")) {
AShortString value = new AShortString(payload);
//System.out.println("Long String: " + value.toString());
members.put(key, value);
continue;
}
//field-table
if (valueType.toWire().toString().equals("F")) {
//System.out.println("Building nested field table from:");
//System.out.println(payload.toHexString());
AFieldTable value = new AFieldTable(payload);
//System.out.println("Ending nested field table");
members.put(key, value);
continue;
}
//boolean
if (valueType.toWire().toString().equals("t")) {
ABoolean value = new ABoolean(payload);
//System.out.println("Boolean: " + (value.toBool() ? "true" : "false"));
members.put(key, value);
continue;
}
//If we reach down here, we were unable to understand the value type and we need to stop
throw new InvalidTypeException("Unknown Field Table type: " + valueType.toString());
}
}
//Number of members in this field table
public int length() {
return members.size();
}
//Manually append a value to the Field Table, useful when programmatically
//creating payloads
public void append(AShortString key, AMQPNativeType value) {
members.put(key, value);
}
//Encode data for being sent over the network
public ByteArrayBuffer toWire() {
//Return data, to be populated
ByteArrayBuffer ret = new ByteArrayBuffer();
//This will be populated with all data in the Field Table
ByteArrayBuffer payload = new ByteArrayBuffer();
//Loop over our members
for(AShortString key : members.keySet()) {
//Member to be encoded
AMQPNativeType val = members.get(key);
//Put name of element, this is always a short string, hence
//1 octet length + the string itself
payload.put(key.toWire());
try {
//Put the value type, 1 octet length (for exampel S, s, F, t etc)
payload.put(val.getFieldTableType());
} catch (InvalidTypeException e) {
//FIXME: This should never happen as the AFieldTable should nevre allow
//an unsupported type to be encoded in it
System.err.println("Unable to encode a data type to wire frame format: " + e.toString());
}
//Put the actual payload
payload.put(val.toWire());
}
//Length header for the Field Table, 4 octets
ByteArrayBuffer length = (new ALongUInt(payload.length())).toWire();
//System.out.println("Field table length: " + length.toHexString());
//Put payload length as 4 octets
ret.put(length);
//Add actual payload
ret.put(payload);
return ret;
}
//For debugging, return all fields
public String toString() {
//StringBuilder is not needed for academic code
String ret = "Debug: Printing Field-Table values:\n";
ret += "----- BEGIN FIELD TABLE -----\n";
for(AShortString key : members.keySet()) {
ret += "Field name: " + key.toString() + "\n";
ret += "Field type: " + members.get(key).getClass().getSimpleName() + "\n";
ret += "Field valu: " + members.get(key).toString() + "\n";
ret += "----- NEXT VALUE -----\n";
}
ret += "----- END FIELD TABLE -----\n";
return ret;
}
};