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