1 // Copyright 2017 The Fuchsia Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include <lib/fidl/coding.h>
6
7 #include <inttypes.h>
8 #include <stdarg.h>
9 #include <string.h>
10
11 #include <lib/fidl/internal.h>
12 #include <zircon/assert.h>
13 #include <zircon/compiler.h>
14
15 namespace {
16
17 class StringBuilder {
18 public:
StringBuilder(char * buffer,size_t capacity)19 StringBuilder(char* buffer, size_t capacity)
20 : buffer_(buffer), capacity_(capacity) {}
21
length() const22 size_t length() const { return length_; }
23
Append(const char * data,size_t length)24 void Append(const char* data, size_t length) {
25 size_t remaining = capacity_ - length_;
26 if (length > remaining) {
27 length = remaining;
28 }
29 memcpy(buffer_ + length_, data, length);
30 length_ += length;
31 }
32
Append(const char * data)33 void Append(const char* data) {
34 Append(data, strlen(data));
35 }
36
AppendPrintf(const char * format,...)37 void AppendPrintf(const char* format, ...) __PRINTFLIKE(2, 3) {
38 va_list ap;
39 va_start(ap, format);
40 AppendVPrintf(format, ap);
41 va_end(ap);
42 }
43
AppendVPrintf(const char * format,va_list ap)44 void AppendVPrintf(const char* format, va_list ap) {
45 size_t remaining = capacity_ - length_;
46 if (remaining == 0u) {
47 return;
48 }
49 int count = vsnprintf(buffer_ + length_, remaining, format, ap);
50 if (count <= 0) {
51 return;
52 }
53 size_t length = static_cast<size_t>(count);
54 length_ += (length >= remaining ? remaining : length);
55 }
56
57 private:
58 char* buffer_;
59 size_t capacity_;
60 size_t length_ = 0u;
61 };
62
FormatNullability(StringBuilder * str,fidl::FidlNullability nullable)63 void FormatNullability(StringBuilder* str, fidl::FidlNullability nullable) {
64 if (nullable == fidl::kNullable) {
65 str->Append("?");
66 }
67 }
68
FormatStructName(StringBuilder * str,const fidl::FidlCodedStruct * coded_struct)69 void FormatStructName(StringBuilder* str, const fidl::FidlCodedStruct* coded_struct) {
70 if (coded_struct->name) {
71 str->Append(coded_struct->name);
72 } else {
73 str->Append("struct");
74 }
75 }
76
FormatUnionName(StringBuilder * str,const fidl::FidlCodedUnion * coded_union)77 void FormatUnionName(StringBuilder* str, const fidl::FidlCodedUnion* coded_union) {
78 if (coded_union->name) {
79 str->Append(coded_union->name);
80 } else {
81 str->Append("union");
82 }
83 }
84
85 void FormatTypeName(StringBuilder* str, const fidl_type_t* type);
FormatElementName(StringBuilder * str,const fidl_type_t * type)86 void FormatElementName(StringBuilder* str, const fidl_type_t* type) {
87 if (type) {
88 FormatTypeName(str, type);
89 } else {
90 // TODO(jeffbrown): Print the actual primitive type name, assuming we
91 // start recording that information in the tables.
92 str->Append("primitive");
93 }
94 }
95
FormatTypeName(StringBuilder * str,const fidl_type_t * type)96 void FormatTypeName(StringBuilder* str, const fidl_type_t* type) {
97 switch (type->type_tag) {
98 case fidl::kFidlTypeStruct:
99 FormatStructName(str, &type->coded_struct);
100 break;
101 case fidl::kFidlTypeStructPointer:
102 FormatStructName(str, type->coded_struct_pointer.struct_type);
103 str->Append("?");
104 break;
105 case fidl::kFidlTypeUnion:
106 FormatUnionName(str, &type->coded_union);
107 break;
108 case fidl::kFidlTypeUnionPointer:
109 FormatUnionName(str, type->coded_union_pointer.union_type);
110 str->Append("?");
111 break;
112 case fidl::kFidlTypeArray:
113 str->Append("array<");
114 FormatElementName(str, type->coded_array.element);
115 str->Append(">");
116 str->AppendPrintf(":%" PRIu32, type->coded_array.array_size /
117 type->coded_array.element_size);
118 break;
119 case fidl::kFidlTypeString:
120 str->Append("string");
121 if (type->coded_string.max_size != FIDL_MAX_SIZE) {
122 str->AppendPrintf(":%" PRIu32, type->coded_string.max_size);
123 }
124 FormatNullability(str, type->coded_string.nullable);
125 break;
126 case fidl::kFidlTypeHandle:
127 str->Append("handle");
128 if (type->coded_handle.handle_subtype) {
129 str->Append("<");
130 switch (type->coded_handle.handle_subtype) {
131 case fidl::kFidlHandleSubtypeHandle:
132 str->Append("handle");
133 break;
134 case fidl::kFidlHandleSubtypeProcess:
135 str->Append("process");
136 break;
137 case fidl::kFidlHandleSubtypeThread:
138 str->Append("thread");
139 break;
140 case fidl::kFidlHandleSubtypeVmo:
141 str->Append("vmo");
142 break;
143 case fidl::kFidlHandleSubtypeChannel:
144 str->Append("channel");
145 break;
146 case fidl::kFidlHandleSubtypeEvent:
147 str->Append("event");
148 break;
149 case fidl::kFidlHandleSubtypePort:
150 str->Append("port");
151 break;
152 case fidl::kFidlHandleSubtypeInterrupt:
153 str->Append("interrupt");
154 break;
155 case fidl::kFidlHandleSubtypeLog:
156 str->Append("log");
157 break;
158 case fidl::kFidlHandleSubtypeSocket:
159 str->Append("socket");
160 break;
161 case fidl::kFidlHandleSubtypeResource:
162 str->Append("resource");
163 break;
164 case fidl::kFidlHandleSubtypeEventpair:
165 str->Append("eventpair");
166 break;
167 case fidl::kFidlHandleSubtypeJob:
168 str->Append("job");
169 break;
170 case fidl::kFidlHandleSubtypeVmar:
171 str->Append("vmar");
172 break;
173 case fidl::kFidlHandleSubtypeFifo:
174 str->Append("fifo");
175 break;
176 case fidl::kFidlHandleSubtypeGuest:
177 str->Append("guest");
178 break;
179 case fidl::kFidlHandleSubtypeTimer:
180 str->Append("timer");
181 break;
182 // TODO(pascallouis): Add support for iomap, pci, and hypervisor
183 // when they are supported in FIDL.
184 default:
185 str->AppendPrintf("%" PRIu32, type->coded_handle.handle_subtype);
186 break;
187 }
188 str->Append(">");
189 }
190 FormatNullability(str, type->coded_handle.nullable);
191 break;
192 case fidl::kFidlTypeVector:
193 str->Append("vector<");
194 FormatElementName(str, type->coded_vector.element);
195 str->Append(">");
196 if (type->coded_vector.max_count != FIDL_MAX_SIZE) {
197 str->AppendPrintf(":%" PRIu32, type->coded_vector.max_count);
198 }
199 FormatNullability(str, type->coded_vector.nullable);
200 break;
201 default:
202 ZX_PANIC("unrecognized tag");
203 break;
204 }
205 }
206
207 } // namespace
208
fidl_format_type_name(const fidl_type_t * type,char * buffer,size_t capacity)209 size_t fidl_format_type_name(const fidl_type_t* type,
210 char* buffer, size_t capacity) {
211 if (!type || !buffer || !capacity) {
212 return 0u;
213 }
214
215 StringBuilder str(buffer, capacity);
216 FormatTypeName(&str, type);
217 return str.length();
218 }
219