1*890232f2SAndroid Build Coastguard Worker #include "annotated_binary_text_gen.h"
2*890232f2SAndroid Build Coastguard Worker
3*890232f2SAndroid Build Coastguard Worker #include <sstream>
4*890232f2SAndroid Build Coastguard Worker #include <string>
5*890232f2SAndroid Build Coastguard Worker
6*890232f2SAndroid Build Coastguard Worker #include "binary_annotator.h"
7*890232f2SAndroid Build Coastguard Worker #include "flatbuffers/base.h"
8*890232f2SAndroid Build Coastguard Worker #include "flatbuffers/util.h"
9*890232f2SAndroid Build Coastguard Worker
10*890232f2SAndroid Build Coastguard Worker namespace flatbuffers {
11*890232f2SAndroid Build Coastguard Worker namespace {
12*890232f2SAndroid Build Coastguard Worker
13*890232f2SAndroid Build Coastguard Worker struct OutputConfig {
14*890232f2SAndroid Build Coastguard Worker size_t largest_type_string = 10;
15*890232f2SAndroid Build Coastguard Worker
16*890232f2SAndroid Build Coastguard Worker size_t largest_value_string = 20;
17*890232f2SAndroid Build Coastguard Worker
18*890232f2SAndroid Build Coastguard Worker size_t max_bytes_per_line = 8;
19*890232f2SAndroid Build Coastguard Worker
20*890232f2SAndroid Build Coastguard Worker size_t offset_max_char = 4;
21*890232f2SAndroid Build Coastguard Worker
22*890232f2SAndroid Build Coastguard Worker char delimiter = '|';
23*890232f2SAndroid Build Coastguard Worker };
24*890232f2SAndroid Build Coastguard Worker
ToString(const BinarySectionType type)25*890232f2SAndroid Build Coastguard Worker static std::string ToString(const BinarySectionType type) {
26*890232f2SAndroid Build Coastguard Worker switch (type) {
27*890232f2SAndroid Build Coastguard Worker case BinarySectionType::Header: return "header";
28*890232f2SAndroid Build Coastguard Worker case BinarySectionType::Table: return "table";
29*890232f2SAndroid Build Coastguard Worker case BinarySectionType::RootTable: return "root_table";
30*890232f2SAndroid Build Coastguard Worker case BinarySectionType::VTable: return "vtable";
31*890232f2SAndroid Build Coastguard Worker case BinarySectionType::Struct: return "struct";
32*890232f2SAndroid Build Coastguard Worker case BinarySectionType::String: return "string";
33*890232f2SAndroid Build Coastguard Worker case BinarySectionType::Vector: return "vector";
34*890232f2SAndroid Build Coastguard Worker case BinarySectionType::Unknown: return "unknown";
35*890232f2SAndroid Build Coastguard Worker case BinarySectionType::Union: return "union";
36*890232f2SAndroid Build Coastguard Worker case BinarySectionType::Padding: return "padding";
37*890232f2SAndroid Build Coastguard Worker default: return "todo";
38*890232f2SAndroid Build Coastguard Worker }
39*890232f2SAndroid Build Coastguard Worker }
40*890232f2SAndroid Build Coastguard Worker
IsOffset(const BinaryRegionType type)41*890232f2SAndroid Build Coastguard Worker static bool IsOffset(const BinaryRegionType type) {
42*890232f2SAndroid Build Coastguard Worker return type == BinaryRegionType::UOffset || type == BinaryRegionType::SOffset;
43*890232f2SAndroid Build Coastguard Worker }
44*890232f2SAndroid Build Coastguard Worker
ToString(T value)45*890232f2SAndroid Build Coastguard Worker template<typename T> std::string ToString(T value) {
46*890232f2SAndroid Build Coastguard Worker if (std::is_floating_point<T>::value) {
47*890232f2SAndroid Build Coastguard Worker std::stringstream ss;
48*890232f2SAndroid Build Coastguard Worker ss << value;
49*890232f2SAndroid Build Coastguard Worker return ss.str();
50*890232f2SAndroid Build Coastguard Worker } else {
51*890232f2SAndroid Build Coastguard Worker return std::to_string(value);
52*890232f2SAndroid Build Coastguard Worker }
53*890232f2SAndroid Build Coastguard Worker }
54*890232f2SAndroid Build Coastguard Worker
55*890232f2SAndroid Build Coastguard Worker template<typename T>
ToValueString(const BinaryRegion & region,const uint8_t * binary)56*890232f2SAndroid Build Coastguard Worker std::string ToValueString(const BinaryRegion ®ion, const uint8_t *binary) {
57*890232f2SAndroid Build Coastguard Worker std::string s;
58*890232f2SAndroid Build Coastguard Worker s += "0x";
59*890232f2SAndroid Build Coastguard Worker const T val = ReadScalar<T>(binary + region.offset);
60*890232f2SAndroid Build Coastguard Worker const uint64_t start_index = region.offset + region.length - 1;
61*890232f2SAndroid Build Coastguard Worker for (uint64_t i = 0; i < region.length; ++i) {
62*890232f2SAndroid Build Coastguard Worker s += ToHex(binary[start_index - i]);
63*890232f2SAndroid Build Coastguard Worker }
64*890232f2SAndroid Build Coastguard Worker s += " (";
65*890232f2SAndroid Build Coastguard Worker s += ToString(val);
66*890232f2SAndroid Build Coastguard Worker s += ")";
67*890232f2SAndroid Build Coastguard Worker return s;
68*890232f2SAndroid Build Coastguard Worker }
69*890232f2SAndroid Build Coastguard Worker
70*890232f2SAndroid Build Coastguard Worker template<>
ToValueString(const BinaryRegion & region,const uint8_t * binary)71*890232f2SAndroid Build Coastguard Worker std::string ToValueString<std::string>(const BinaryRegion ®ion,
72*890232f2SAndroid Build Coastguard Worker const uint8_t *binary) {
73*890232f2SAndroid Build Coastguard Worker return std::string(reinterpret_cast<const char *>(binary + region.offset),
74*890232f2SAndroid Build Coastguard Worker static_cast<size_t>(region.array_length));
75*890232f2SAndroid Build Coastguard Worker }
76*890232f2SAndroid Build Coastguard Worker
ToValueString(const BinaryRegion & region,const uint8_t * binary,const OutputConfig & output_config)77*890232f2SAndroid Build Coastguard Worker static std::string ToValueString(const BinaryRegion ®ion,
78*890232f2SAndroid Build Coastguard Worker const uint8_t *binary,
79*890232f2SAndroid Build Coastguard Worker const OutputConfig &output_config) {
80*890232f2SAndroid Build Coastguard Worker std::string s;
81*890232f2SAndroid Build Coastguard Worker
82*890232f2SAndroid Build Coastguard Worker if (region.array_length) {
83*890232f2SAndroid Build Coastguard Worker if (region.type == BinaryRegionType::Uint8 ||
84*890232f2SAndroid Build Coastguard Worker region.type == BinaryRegionType::Unknown) {
85*890232f2SAndroid Build Coastguard Worker // Interpet each value as a ASCII to aid debugging
86*890232f2SAndroid Build Coastguard Worker for (uint64_t i = 0; i < region.array_length; ++i) {
87*890232f2SAndroid Build Coastguard Worker const uint8_t c = *(binary + region.offset + i);
88*890232f2SAndroid Build Coastguard Worker s += isprint(c) ? static_cast<char>(c & 0x7F) : '.';
89*890232f2SAndroid Build Coastguard Worker }
90*890232f2SAndroid Build Coastguard Worker return s;
91*890232f2SAndroid Build Coastguard Worker } else if (region.type == BinaryRegionType::Char) {
92*890232f2SAndroid Build Coastguard Worker // string value
93*890232f2SAndroid Build Coastguard Worker return ToValueString<std::string>(region, binary);
94*890232f2SAndroid Build Coastguard Worker }
95*890232f2SAndroid Build Coastguard Worker }
96*890232f2SAndroid Build Coastguard Worker
97*890232f2SAndroid Build Coastguard Worker switch (region.type) {
98*890232f2SAndroid Build Coastguard Worker case BinaryRegionType::Uint32:
99*890232f2SAndroid Build Coastguard Worker return ToValueString<uint32_t>(region, binary);
100*890232f2SAndroid Build Coastguard Worker case BinaryRegionType::Int32: return ToValueString<int32_t>(region, binary);
101*890232f2SAndroid Build Coastguard Worker case BinaryRegionType::Uint16:
102*890232f2SAndroid Build Coastguard Worker return ToValueString<uint16_t>(region, binary);
103*890232f2SAndroid Build Coastguard Worker case BinaryRegionType::Int16: return ToValueString<int16_t>(region, binary);
104*890232f2SAndroid Build Coastguard Worker case BinaryRegionType::Bool: return ToValueString<bool>(region, binary);
105*890232f2SAndroid Build Coastguard Worker case BinaryRegionType::Uint8: return ToValueString<uint8_t>(region, binary);
106*890232f2SAndroid Build Coastguard Worker case BinaryRegionType::Char: return ToValueString<char>(region, binary);
107*890232f2SAndroid Build Coastguard Worker case BinaryRegionType::Byte:
108*890232f2SAndroid Build Coastguard Worker case BinaryRegionType::Int8: return ToValueString<int8_t>(region, binary);
109*890232f2SAndroid Build Coastguard Worker case BinaryRegionType::Int64: return ToValueString<int64_t>(region, binary);
110*890232f2SAndroid Build Coastguard Worker case BinaryRegionType::Uint64:
111*890232f2SAndroid Build Coastguard Worker return ToValueString<uint64_t>(region, binary);
112*890232f2SAndroid Build Coastguard Worker case BinaryRegionType::Double: return ToValueString<double>(region, binary);
113*890232f2SAndroid Build Coastguard Worker case BinaryRegionType::Float: return ToValueString<float>(region, binary);
114*890232f2SAndroid Build Coastguard Worker case BinaryRegionType::UType: return ToValueString<uint8_t>(region, binary);
115*890232f2SAndroid Build Coastguard Worker
116*890232f2SAndroid Build Coastguard Worker // Handle Offsets separately, incase they add additional details.
117*890232f2SAndroid Build Coastguard Worker case BinaryRegionType::UOffset:
118*890232f2SAndroid Build Coastguard Worker s += ToValueString<uint32_t>(region, binary);
119*890232f2SAndroid Build Coastguard Worker break;
120*890232f2SAndroid Build Coastguard Worker case BinaryRegionType::SOffset:
121*890232f2SAndroid Build Coastguard Worker s += ToValueString<int32_t>(region, binary);
122*890232f2SAndroid Build Coastguard Worker break;
123*890232f2SAndroid Build Coastguard Worker case BinaryRegionType::VOffset:
124*890232f2SAndroid Build Coastguard Worker s += ToValueString<uint16_t>(region, binary);
125*890232f2SAndroid Build Coastguard Worker break;
126*890232f2SAndroid Build Coastguard Worker
127*890232f2SAndroid Build Coastguard Worker default: break;
128*890232f2SAndroid Build Coastguard Worker }
129*890232f2SAndroid Build Coastguard Worker // If this is an offset type, include the calculated offset location in the
130*890232f2SAndroid Build Coastguard Worker // value.
131*890232f2SAndroid Build Coastguard Worker // TODO(dbaileychess): It might be nicer to put this in the comment field.
132*890232f2SAndroid Build Coastguard Worker if (IsOffset(region.type)) {
133*890232f2SAndroid Build Coastguard Worker s += " Loc: +0x";
134*890232f2SAndroid Build Coastguard Worker s += ToHex(region.points_to_offset, output_config.offset_max_char);
135*890232f2SAndroid Build Coastguard Worker }
136*890232f2SAndroid Build Coastguard Worker return s;
137*890232f2SAndroid Build Coastguard Worker }
138*890232f2SAndroid Build Coastguard Worker
139*890232f2SAndroid Build Coastguard Worker struct DocContinuation {
140*890232f2SAndroid Build Coastguard Worker // The start column where the value text first starts
141*890232f2SAndroid Build Coastguard Worker size_t value_start_column = 0;
142*890232f2SAndroid Build Coastguard Worker
143*890232f2SAndroid Build Coastguard Worker // The remaining part of the doc to print.
144*890232f2SAndroid Build Coastguard Worker std::string value;
145*890232f2SAndroid Build Coastguard Worker };
146*890232f2SAndroid Build Coastguard Worker
GenerateTypeString(const BinaryRegion & region)147*890232f2SAndroid Build Coastguard Worker static std::string GenerateTypeString(const BinaryRegion ®ion) {
148*890232f2SAndroid Build Coastguard Worker return ToString(region.type) +
149*890232f2SAndroid Build Coastguard Worker ((region.array_length)
150*890232f2SAndroid Build Coastguard Worker ? "[" + std::to_string(region.array_length) + "]"
151*890232f2SAndroid Build Coastguard Worker : "");
152*890232f2SAndroid Build Coastguard Worker }
153*890232f2SAndroid Build Coastguard Worker
GenerateComment(const BinaryRegionComment & comment,const BinarySection &)154*890232f2SAndroid Build Coastguard Worker static std::string GenerateComment(const BinaryRegionComment &comment,
155*890232f2SAndroid Build Coastguard Worker const BinarySection &) {
156*890232f2SAndroid Build Coastguard Worker std::string s;
157*890232f2SAndroid Build Coastguard Worker switch (comment.type) {
158*890232f2SAndroid Build Coastguard Worker case BinaryRegionCommentType::Unknown: s = "unknown"; break;
159*890232f2SAndroid Build Coastguard Worker case BinaryRegionCommentType::SizePrefix: s = "size prefix"; break;
160*890232f2SAndroid Build Coastguard Worker case BinaryRegionCommentType::RootTableOffset:
161*890232f2SAndroid Build Coastguard Worker s = "offset to root table `" + comment.name + "`";
162*890232f2SAndroid Build Coastguard Worker break;
163*890232f2SAndroid Build Coastguard Worker // TODO(dbaileychess): make this lowercase to follow the convention.
164*890232f2SAndroid Build Coastguard Worker case BinaryRegionCommentType::FileIdentifier: s = "File Identifier"; break;
165*890232f2SAndroid Build Coastguard Worker case BinaryRegionCommentType::Padding: s = "padding"; break;
166*890232f2SAndroid Build Coastguard Worker case BinaryRegionCommentType::VTableSize: s = "size of this vtable"; break;
167*890232f2SAndroid Build Coastguard Worker case BinaryRegionCommentType::VTableRefferingTableLength:
168*890232f2SAndroid Build Coastguard Worker s = "size of referring table";
169*890232f2SAndroid Build Coastguard Worker break;
170*890232f2SAndroid Build Coastguard Worker case BinaryRegionCommentType::VTableFieldOffset:
171*890232f2SAndroid Build Coastguard Worker s = "offset to field `" + comment.name;
172*890232f2SAndroid Build Coastguard Worker break;
173*890232f2SAndroid Build Coastguard Worker case BinaryRegionCommentType::VTableUnknownFieldOffset:
174*890232f2SAndroid Build Coastguard Worker s = "offset to unknown field (id: " + std::to_string(comment.index) + ")";
175*890232f2SAndroid Build Coastguard Worker break;
176*890232f2SAndroid Build Coastguard Worker
177*890232f2SAndroid Build Coastguard Worker case BinaryRegionCommentType::TableVTableOffset:
178*890232f2SAndroid Build Coastguard Worker s = "offset to vtable";
179*890232f2SAndroid Build Coastguard Worker break;
180*890232f2SAndroid Build Coastguard Worker case BinaryRegionCommentType::TableField:
181*890232f2SAndroid Build Coastguard Worker s = "table field `" + comment.name;
182*890232f2SAndroid Build Coastguard Worker break;
183*890232f2SAndroid Build Coastguard Worker case BinaryRegionCommentType::TableUnknownField: s = "unknown field"; break;
184*890232f2SAndroid Build Coastguard Worker case BinaryRegionCommentType::TableOffsetField:
185*890232f2SAndroid Build Coastguard Worker s = "offset to field `" + comment.name + "`";
186*890232f2SAndroid Build Coastguard Worker break;
187*890232f2SAndroid Build Coastguard Worker case BinaryRegionCommentType::StructField:
188*890232f2SAndroid Build Coastguard Worker s = "struct field `" + comment.name + "`";
189*890232f2SAndroid Build Coastguard Worker break;
190*890232f2SAndroid Build Coastguard Worker case BinaryRegionCommentType::ArrayField:
191*890232f2SAndroid Build Coastguard Worker s = "array field `" + comment.name + "`[" +
192*890232f2SAndroid Build Coastguard Worker std::to_string(comment.index) + "]";
193*890232f2SAndroid Build Coastguard Worker break;
194*890232f2SAndroid Build Coastguard Worker case BinaryRegionCommentType::StringLength: s = "length of string"; break;
195*890232f2SAndroid Build Coastguard Worker case BinaryRegionCommentType::StringValue: s = "string literal"; break;
196*890232f2SAndroid Build Coastguard Worker case BinaryRegionCommentType::StringTerminator:
197*890232f2SAndroid Build Coastguard Worker s = "string terminator";
198*890232f2SAndroid Build Coastguard Worker break;
199*890232f2SAndroid Build Coastguard Worker case BinaryRegionCommentType::VectorLength:
200*890232f2SAndroid Build Coastguard Worker s = "length of vector (# items)";
201*890232f2SAndroid Build Coastguard Worker break;
202*890232f2SAndroid Build Coastguard Worker case BinaryRegionCommentType::VectorValue:
203*890232f2SAndroid Build Coastguard Worker s = "value[" + std::to_string(comment.index) + "]";
204*890232f2SAndroid Build Coastguard Worker break;
205*890232f2SAndroid Build Coastguard Worker case BinaryRegionCommentType::VectorTableValue:
206*890232f2SAndroid Build Coastguard Worker s = "offset to table[" + std::to_string(comment.index) + "]";
207*890232f2SAndroid Build Coastguard Worker break;
208*890232f2SAndroid Build Coastguard Worker case BinaryRegionCommentType::VectorStringValue:
209*890232f2SAndroid Build Coastguard Worker s = "offset to string[" + std::to_string(comment.index) + "]";
210*890232f2SAndroid Build Coastguard Worker break;
211*890232f2SAndroid Build Coastguard Worker case BinaryRegionCommentType::VectorUnionValue:
212*890232f2SAndroid Build Coastguard Worker s = "offset to union[" + std::to_string(comment.index) + "]";
213*890232f2SAndroid Build Coastguard Worker break;
214*890232f2SAndroid Build Coastguard Worker
215*890232f2SAndroid Build Coastguard Worker default: break;
216*890232f2SAndroid Build Coastguard Worker }
217*890232f2SAndroid Build Coastguard Worker if (!comment.default_value.empty()) { s += " " + comment.default_value; }
218*890232f2SAndroid Build Coastguard Worker
219*890232f2SAndroid Build Coastguard Worker switch (comment.status) {
220*890232f2SAndroid Build Coastguard Worker case BinaryRegionStatus::OK: break; // no-op
221*890232f2SAndroid Build Coastguard Worker case BinaryRegionStatus::WARN: s = "WARN: " + s; break;
222*890232f2SAndroid Build Coastguard Worker case BinaryRegionStatus::WARN_NO_REFERENCES:
223*890232f2SAndroid Build Coastguard Worker s = "WARN: nothing refers to this section.";
224*890232f2SAndroid Build Coastguard Worker break;
225*890232f2SAndroid Build Coastguard Worker case BinaryRegionStatus::WARN_CORRUPTED_PADDING:
226*890232f2SAndroid Build Coastguard Worker s = "WARN: could be corrupted padding region.";
227*890232f2SAndroid Build Coastguard Worker break;
228*890232f2SAndroid Build Coastguard Worker case BinaryRegionStatus::WARN_PADDING_LENGTH:
229*890232f2SAndroid Build Coastguard Worker s = "WARN: padding is longer than expected.";
230*890232f2SAndroid Build Coastguard Worker break;
231*890232f2SAndroid Build Coastguard Worker case BinaryRegionStatus::ERROR: s = "ERROR: " + s; break;
232*890232f2SAndroid Build Coastguard Worker case BinaryRegionStatus::ERROR_OFFSET_OUT_OF_BINARY:
233*890232f2SAndroid Build Coastguard Worker s = "ERROR: " + s + ". Invalid offset, points outside the binary.";
234*890232f2SAndroid Build Coastguard Worker break;
235*890232f2SAndroid Build Coastguard Worker case BinaryRegionStatus::ERROR_INCOMPLETE_BINARY:
236*890232f2SAndroid Build Coastguard Worker s = "ERROR: " + s + ". Incomplete binary, expected to read " +
237*890232f2SAndroid Build Coastguard Worker comment.status_message + " bytes.";
238*890232f2SAndroid Build Coastguard Worker break;
239*890232f2SAndroid Build Coastguard Worker case BinaryRegionStatus::ERROR_LENGTH_TOO_LONG:
240*890232f2SAndroid Build Coastguard Worker s = "ERROR: " + s + ". Longer than the binary.";
241*890232f2SAndroid Build Coastguard Worker break;
242*890232f2SAndroid Build Coastguard Worker case BinaryRegionStatus::ERROR_LENGTH_TOO_SHORT:
243*890232f2SAndroid Build Coastguard Worker s = "ERROR: " + s + ". Shorter than the minimum length: ";
244*890232f2SAndroid Build Coastguard Worker break;
245*890232f2SAndroid Build Coastguard Worker case BinaryRegionStatus::ERROR_REQUIRED_FIELD_NOT_PRESENT:
246*890232f2SAndroid Build Coastguard Worker s = "ERROR: " + s + ". Required field is not present.";
247*890232f2SAndroid Build Coastguard Worker break;
248*890232f2SAndroid Build Coastguard Worker case BinaryRegionStatus::ERROR_INVALID_UNION_TYPE:
249*890232f2SAndroid Build Coastguard Worker s = "ERROR: " + s + ". Invalid union type value.";
250*890232f2SAndroid Build Coastguard Worker break;
251*890232f2SAndroid Build Coastguard Worker case BinaryRegionStatus::ERROR_CYCLE_DETECTED:
252*890232f2SAndroid Build Coastguard Worker s = "ERROR: " + s + ". Invalid offset, cycle detected.";
253*890232f2SAndroid Build Coastguard Worker break;
254*890232f2SAndroid Build Coastguard Worker }
255*890232f2SAndroid Build Coastguard Worker
256*890232f2SAndroid Build Coastguard Worker return s;
257*890232f2SAndroid Build Coastguard Worker }
258*890232f2SAndroid Build Coastguard Worker
GenerateDocumentation(const BinaryRegion & region,const BinarySection & section,const uint8_t * binary,DocContinuation & continuation,const OutputConfig & output_config)259*890232f2SAndroid Build Coastguard Worker static std::string GenerateDocumentation(const BinaryRegion ®ion,
260*890232f2SAndroid Build Coastguard Worker const BinarySection §ion,
261*890232f2SAndroid Build Coastguard Worker const uint8_t *binary,
262*890232f2SAndroid Build Coastguard Worker DocContinuation &continuation,
263*890232f2SAndroid Build Coastguard Worker const OutputConfig &output_config) {
264*890232f2SAndroid Build Coastguard Worker std::string s;
265*890232f2SAndroid Build Coastguard Worker
266*890232f2SAndroid Build Coastguard Worker // Check if there is a doc continuation that should be prioritized.
267*890232f2SAndroid Build Coastguard Worker if (continuation.value_start_column) {
268*890232f2SAndroid Build Coastguard Worker s += std::string(continuation.value_start_column - 2, ' ');
269*890232f2SAndroid Build Coastguard Worker s += output_config.delimiter;
270*890232f2SAndroid Build Coastguard Worker s += " ";
271*890232f2SAndroid Build Coastguard Worker
272*890232f2SAndroid Build Coastguard Worker s += continuation.value.substr(0, output_config.max_bytes_per_line);
273*890232f2SAndroid Build Coastguard Worker continuation.value = continuation.value.substr(
274*890232f2SAndroid Build Coastguard Worker std::min(output_config.max_bytes_per_line, continuation.value.size()));
275*890232f2SAndroid Build Coastguard Worker return s;
276*890232f2SAndroid Build Coastguard Worker }
277*890232f2SAndroid Build Coastguard Worker
278*890232f2SAndroid Build Coastguard Worker {
279*890232f2SAndroid Build Coastguard Worker std::stringstream ss;
280*890232f2SAndroid Build Coastguard Worker ss << std::setw(output_config.largest_type_string) << std::left;
281*890232f2SAndroid Build Coastguard Worker ss << GenerateTypeString(region);
282*890232f2SAndroid Build Coastguard Worker s += ss.str();
283*890232f2SAndroid Build Coastguard Worker }
284*890232f2SAndroid Build Coastguard Worker s += " ";
285*890232f2SAndroid Build Coastguard Worker s += output_config.delimiter;
286*890232f2SAndroid Build Coastguard Worker s += " ";
287*890232f2SAndroid Build Coastguard Worker if (region.array_length) {
288*890232f2SAndroid Build Coastguard Worker // Record where the value is first being outputted.
289*890232f2SAndroid Build Coastguard Worker continuation.value_start_column = s.size();
290*890232f2SAndroid Build Coastguard Worker
291*890232f2SAndroid Build Coastguard Worker // Get the full-length value, which we will chunk below.
292*890232f2SAndroid Build Coastguard Worker const std::string value = ToValueString(region, binary, output_config);
293*890232f2SAndroid Build Coastguard Worker
294*890232f2SAndroid Build Coastguard Worker std::stringstream ss;
295*890232f2SAndroid Build Coastguard Worker ss << std::setw(output_config.largest_value_string) << std::left;
296*890232f2SAndroid Build Coastguard Worker ss << value.substr(0, output_config.max_bytes_per_line);
297*890232f2SAndroid Build Coastguard Worker s += ss.str();
298*890232f2SAndroid Build Coastguard Worker
299*890232f2SAndroid Build Coastguard Worker continuation.value =
300*890232f2SAndroid Build Coastguard Worker value.substr(std::min(output_config.max_bytes_per_line, value.size()));
301*890232f2SAndroid Build Coastguard Worker } else {
302*890232f2SAndroid Build Coastguard Worker std::stringstream ss;
303*890232f2SAndroid Build Coastguard Worker ss << std::setw(output_config.largest_value_string) << std::left;
304*890232f2SAndroid Build Coastguard Worker ss << ToValueString(region, binary, output_config);
305*890232f2SAndroid Build Coastguard Worker s += ss.str();
306*890232f2SAndroid Build Coastguard Worker }
307*890232f2SAndroid Build Coastguard Worker
308*890232f2SAndroid Build Coastguard Worker s += " ";
309*890232f2SAndroid Build Coastguard Worker s += output_config.delimiter;
310*890232f2SAndroid Build Coastguard Worker s += " ";
311*890232f2SAndroid Build Coastguard Worker s += GenerateComment(region.comment, section);
312*890232f2SAndroid Build Coastguard Worker
313*890232f2SAndroid Build Coastguard Worker return s;
314*890232f2SAndroid Build Coastguard Worker }
315*890232f2SAndroid Build Coastguard Worker
GenerateRegion(const BinaryRegion & region,const BinarySection & section,const uint8_t * binary,const OutputConfig & output_config)316*890232f2SAndroid Build Coastguard Worker static std::string GenerateRegion(const BinaryRegion ®ion,
317*890232f2SAndroid Build Coastguard Worker const BinarySection §ion,
318*890232f2SAndroid Build Coastguard Worker const uint8_t *binary,
319*890232f2SAndroid Build Coastguard Worker const OutputConfig &output_config) {
320*890232f2SAndroid Build Coastguard Worker std::string s;
321*890232f2SAndroid Build Coastguard Worker bool doc_generated = false;
322*890232f2SAndroid Build Coastguard Worker DocContinuation doc_continuation;
323*890232f2SAndroid Build Coastguard Worker for (uint64_t i = 0; i < region.length; ++i) {
324*890232f2SAndroid Build Coastguard Worker if ((i % output_config.max_bytes_per_line) == 0) {
325*890232f2SAndroid Build Coastguard Worker // Start a new line of output
326*890232f2SAndroid Build Coastguard Worker s += '\n';
327*890232f2SAndroid Build Coastguard Worker s += " ";
328*890232f2SAndroid Build Coastguard Worker s += "+0x";
329*890232f2SAndroid Build Coastguard Worker s += ToHex(region.offset + i, output_config.offset_max_char);
330*890232f2SAndroid Build Coastguard Worker s += " ";
331*890232f2SAndroid Build Coastguard Worker s += output_config.delimiter;
332*890232f2SAndroid Build Coastguard Worker }
333*890232f2SAndroid Build Coastguard Worker
334*890232f2SAndroid Build Coastguard Worker // Add each byte
335*890232f2SAndroid Build Coastguard Worker s += " ";
336*890232f2SAndroid Build Coastguard Worker s += ToHex(binary[region.offset + i]);
337*890232f2SAndroid Build Coastguard Worker
338*890232f2SAndroid Build Coastguard Worker // Check for end of line or end of region conditions.
339*890232f2SAndroid Build Coastguard Worker if (((i + 1) % output_config.max_bytes_per_line == 0) ||
340*890232f2SAndroid Build Coastguard Worker i + 1 == region.length) {
341*890232f2SAndroid Build Coastguard Worker if (i + 1 == region.length) {
342*890232f2SAndroid Build Coastguard Worker // We are out of bytes but haven't the kMaxBytesPerLine, so we need to
343*890232f2SAndroid Build Coastguard Worker // zero those out to align everything globally.
344*890232f2SAndroid Build Coastguard Worker for (uint64_t j = i + 1; (j % output_config.max_bytes_per_line) != 0;
345*890232f2SAndroid Build Coastguard Worker ++j) {
346*890232f2SAndroid Build Coastguard Worker s += " ";
347*890232f2SAndroid Build Coastguard Worker }
348*890232f2SAndroid Build Coastguard Worker }
349*890232f2SAndroid Build Coastguard Worker s += " ";
350*890232f2SAndroid Build Coastguard Worker s += output_config.delimiter;
351*890232f2SAndroid Build Coastguard Worker // This is the end of the first line or its the last byte of the region,
352*890232f2SAndroid Build Coastguard Worker // generate the end-of-line documentation.
353*890232f2SAndroid Build Coastguard Worker if (!doc_generated) {
354*890232f2SAndroid Build Coastguard Worker s += " ";
355*890232f2SAndroid Build Coastguard Worker s += GenerateDocumentation(region, section, binary, doc_continuation,
356*890232f2SAndroid Build Coastguard Worker output_config);
357*890232f2SAndroid Build Coastguard Worker
358*890232f2SAndroid Build Coastguard Worker // If we have a value in the doc continuation, that means the doc is
359*890232f2SAndroid Build Coastguard Worker // being printed on multiple lines.
360*890232f2SAndroid Build Coastguard Worker doc_generated = doc_continuation.value.empty();
361*890232f2SAndroid Build Coastguard Worker }
362*890232f2SAndroid Build Coastguard Worker }
363*890232f2SAndroid Build Coastguard Worker }
364*890232f2SAndroid Build Coastguard Worker
365*890232f2SAndroid Build Coastguard Worker return s;
366*890232f2SAndroid Build Coastguard Worker }
367*890232f2SAndroid Build Coastguard Worker
GenerateSection(const BinarySection & section,const uint8_t * binary,const OutputConfig & output_config)368*890232f2SAndroid Build Coastguard Worker static std::string GenerateSection(const BinarySection §ion,
369*890232f2SAndroid Build Coastguard Worker const uint8_t *binary,
370*890232f2SAndroid Build Coastguard Worker const OutputConfig &output_config) {
371*890232f2SAndroid Build Coastguard Worker std::string s;
372*890232f2SAndroid Build Coastguard Worker s += "\n";
373*890232f2SAndroid Build Coastguard Worker s += ToString(section.type);
374*890232f2SAndroid Build Coastguard Worker if (!section.name.empty()) { s += " (" + section.name + ")"; }
375*890232f2SAndroid Build Coastguard Worker s += ":";
376*890232f2SAndroid Build Coastguard Worker for (const BinaryRegion ®ion : section.regions) {
377*890232f2SAndroid Build Coastguard Worker s += GenerateRegion(region, section, binary, output_config);
378*890232f2SAndroid Build Coastguard Worker }
379*890232f2SAndroid Build Coastguard Worker return s;
380*890232f2SAndroid Build Coastguard Worker }
381*890232f2SAndroid Build Coastguard Worker } // namespace
382*890232f2SAndroid Build Coastguard Worker
Generate(const std::string & filename,const std::string & schema_filename)383*890232f2SAndroid Build Coastguard Worker bool AnnotatedBinaryTextGenerator::Generate(
384*890232f2SAndroid Build Coastguard Worker const std::string &filename, const std::string &schema_filename) {
385*890232f2SAndroid Build Coastguard Worker OutputConfig output_config;
386*890232f2SAndroid Build Coastguard Worker output_config.max_bytes_per_line = options_.max_bytes_per_line;
387*890232f2SAndroid Build Coastguard Worker
388*890232f2SAndroid Build Coastguard Worker // Given the length of the binary, we can calculate the maximum number of
389*890232f2SAndroid Build Coastguard Worker // characters to display in the offset hex: (i.e. 2 would lead to 0XFF being
390*890232f2SAndroid Build Coastguard Worker // the max output).
391*890232f2SAndroid Build Coastguard Worker output_config.offset_max_char =
392*890232f2SAndroid Build Coastguard Worker binary_length_ > 0xFFFFFF
393*890232f2SAndroid Build Coastguard Worker ? 8
394*890232f2SAndroid Build Coastguard Worker : (binary_length_ > 0xFFFF ? 6 : (binary_length_ > 0xFF ? 4 : 2));
395*890232f2SAndroid Build Coastguard Worker
396*890232f2SAndroid Build Coastguard Worker // Find the largest type string of all the regions in this file, so we can
397*890232f2SAndroid Build Coastguard Worker // align the output nicely.
398*890232f2SAndroid Build Coastguard Worker output_config.largest_type_string = 0;
399*890232f2SAndroid Build Coastguard Worker for (const auto §ion : annotations_) {
400*890232f2SAndroid Build Coastguard Worker for (const auto ®ion : section.second.regions) {
401*890232f2SAndroid Build Coastguard Worker std::string s = GenerateTypeString(region);
402*890232f2SAndroid Build Coastguard Worker if (s.size() > output_config.largest_type_string) {
403*890232f2SAndroid Build Coastguard Worker output_config.largest_type_string = s.size();
404*890232f2SAndroid Build Coastguard Worker }
405*890232f2SAndroid Build Coastguard Worker
406*890232f2SAndroid Build Coastguard Worker // Don't consider array regions, as they will be split to multiple lines.
407*890232f2SAndroid Build Coastguard Worker if (!region.array_length) {
408*890232f2SAndroid Build Coastguard Worker s = ToValueString(region, binary_, output_config);
409*890232f2SAndroid Build Coastguard Worker if (s.size() > output_config.largest_value_string) {
410*890232f2SAndroid Build Coastguard Worker output_config.largest_value_string = s.size();
411*890232f2SAndroid Build Coastguard Worker }
412*890232f2SAndroid Build Coastguard Worker }
413*890232f2SAndroid Build Coastguard Worker }
414*890232f2SAndroid Build Coastguard Worker }
415*890232f2SAndroid Build Coastguard Worker
416*890232f2SAndroid Build Coastguard Worker // Generate each of the binary sections
417*890232f2SAndroid Build Coastguard Worker std::string s;
418*890232f2SAndroid Build Coastguard Worker
419*890232f2SAndroid Build Coastguard Worker s += "// Annotated Flatbuffer Binary\n";
420*890232f2SAndroid Build Coastguard Worker s += "//\n";
421*890232f2SAndroid Build Coastguard Worker s += "// Schema file: " + schema_filename + "\n";
422*890232f2SAndroid Build Coastguard Worker s += "// Binary file: " + filename + "\n";
423*890232f2SAndroid Build Coastguard Worker
424*890232f2SAndroid Build Coastguard Worker for (const auto §ion : annotations_) {
425*890232f2SAndroid Build Coastguard Worker s += GenerateSection(section.second, binary_, output_config);
426*890232f2SAndroid Build Coastguard Worker s += "\n";
427*890232f2SAndroid Build Coastguard Worker }
428*890232f2SAndroid Build Coastguard Worker
429*890232f2SAndroid Build Coastguard Worker // Modify the output filename.
430*890232f2SAndroid Build Coastguard Worker std::string output_filename = StripExtension(filename);
431*890232f2SAndroid Build Coastguard Worker output_filename += options_.output_postfix;
432*890232f2SAndroid Build Coastguard Worker output_filename +=
433*890232f2SAndroid Build Coastguard Worker "." + (options_.output_extension.empty() ? GetExtension(filename)
434*890232f2SAndroid Build Coastguard Worker : options_.output_extension);
435*890232f2SAndroid Build Coastguard Worker
436*890232f2SAndroid Build Coastguard Worker return SaveFile(output_filename.c_str(), s, false);
437*890232f2SAndroid Build Coastguard Worker }
438*890232f2SAndroid Build Coastguard Worker
439*890232f2SAndroid Build Coastguard Worker } // namespace flatbuffers
440