blob: 2f23b1129f65d3be1fdbec6bde537eb88f43613b [file] [log] [blame]
David Reiss00dcccf2007-07-21 01:18:10 +00001// Copyright (c) 2006- Facebook
2// Distributed under the Thrift Software License
3//
4// See accompanying file LICENSE or visit the Thrift site at:
5// http://developers.facebook.com/thrift/
6
7#include "TDebugProtocol.h"
8
9#include <cassert>
10#include <cctype>
11#include <cstdio>
12#include <stdexcept>
13#include <boost/static_assert.hpp>
14#include <boost/lexical_cast.hpp>
15
16using std::string;
17
18
19static string byte_to_hex(const uint8_t byte) {
20 char buf[3];
21 int ret = std::sprintf(buf, "%02x", (int)byte);
22 assert(ret == 2);
23 assert(buf[2] == '\0');
24 return buf;
25}
26
27
David Reiss0c90f6f2008-02-06 22:18:40 +000028namespace facebook { namespace thrift { namespace protocol {
David Reiss00dcccf2007-07-21 01:18:10 +000029
30string TDebugProtocol::fieldTypeName(TType type) {
31 switch (type) {
32 case T_STOP : return "stop" ;
33 case T_VOID : return "void" ;
34 case T_BOOL : return "bool" ;
35 case T_BYTE : return "byte" ;
36 case T_I16 : return "i16" ;
37 case T_I32 : return "i32" ;
38 case T_U64 : return "u64" ;
39 case T_I64 : return "i64" ;
40 case T_DOUBLE : return "double" ;
41 case T_STRING : return "string" ;
42 case T_STRUCT : return "struct" ;
43 case T_MAP : return "map" ;
44 case T_SET : return "set" ;
45 case T_LIST : return "list" ;
46 case T_UTF8 : return "utf8" ;
47 case T_UTF16 : return "utf16" ;
48 default: return "unknown";
49 }
50}
51
52void TDebugProtocol::indentUp() {
53 indent_str_ += string(indent_inc, ' ');
54}
55
56void TDebugProtocol::indentDown() {
57 if (indent_str_.length() < (string::size_type)indent_inc) {
58 throw TProtocolException(TProtocolException::INVALID_DATA);
59 }
60 indent_str_.erase(indent_str_.length() - indent_inc);
61}
62
63uint32_t TDebugProtocol::writePlain(const string& str) {
64 trans_->write((uint8_t*)str.data(), str.length());
65 return str.length();
66}
67
68uint32_t TDebugProtocol::writeIndented(const string& str) {
69 trans_->write((uint8_t*)indent_str_.data(), indent_str_.length());
70 trans_->write((uint8_t*)str.data(), str.length());
71 return indent_str_.length() + str.length();
72}
73
74uint32_t TDebugProtocol::startItem() {
75 uint32_t size;
76
77 switch (write_state_.back()) {
78 case UNINIT:
79 // XXX figure out what to do here.
80 //throw TProtocolException(TProtocolException::INVALID_DATA);
81 //return writeIndented(str);
82 return 0;
83 case STRUCT:
84 return 0;
85 case SET:
86 return writeIndented("");
87 case MAP_KEY:
88 return writeIndented("");
89 case MAP_VALUE:
90 return writePlain(" -> ");
91 case LIST:
92 size = writeIndented(
93 "[" + boost::lexical_cast<string>(list_idx_.back()) + "] = ");
94 list_idx_.back()++;
95 return size;
96 default:
97 throw std::logic_error("Invalid enum value.");
98 }
99}
100
101uint32_t TDebugProtocol::endItem() {
102 //uint32_t size;
103
104 switch (write_state_.back()) {
105 case UNINIT:
106 // XXX figure out what to do here.
107 //throw TProtocolException(TProtocolException::INVALID_DATA);
108 //return writeIndented(str);
109 return 0;
110 case STRUCT:
111 return writePlain(",\n");
112 case SET:
113 return writePlain(",\n");
114 case MAP_KEY:
115 write_state_.back() = MAP_VALUE;
116 return 0;
117 case MAP_VALUE:
118 write_state_.back() = MAP_KEY;
119 return writePlain(",\n");
120 case LIST:
121 return writePlain(",\n");
122 default:
123 throw std::logic_error("Invalid enum value.");
124 }
125}
126
127uint32_t TDebugProtocol::writeItem(const std::string& str) {
128 uint32_t size = 0;
129 size += startItem();
130 size += writePlain(str);
131 size += endItem();
132 return size;
133}
134
135uint32_t TDebugProtocol::writeMessageBegin(const std::string& name,
136 const TMessageType messageType,
137 const int32_t seqid) {
138 throw TProtocolException(TProtocolException::NOT_IMPLEMENTED,
139 "TDebugProtocol does not support messages (yet).");
140}
141
142uint32_t TDebugProtocol::writeMessageEnd() {
143 throw TProtocolException(TProtocolException::NOT_IMPLEMENTED,
144 "TDebugProtocol does not support messages (yet).");
145}
146
147uint32_t TDebugProtocol::writeStructBegin(const string& name) {
148 uint32_t size = 0;
149 size += startItem();
150 size += writePlain(name + " {\n");
151 indentUp();
152 write_state_.push_back(STRUCT);
153 return size;
154}
155
156uint32_t TDebugProtocol::writeStructEnd() {
157 indentDown();
158 write_state_.pop_back();
159 uint32_t size = 0;
160 size += writeIndented("}");
161 size += endItem();
162 return size;
163}
164
165uint32_t TDebugProtocol::writeFieldBegin(const string& name,
166 const TType fieldType,
167 const int16_t fieldId) {
168 // sprintf(id_str, "%02d", fieldId);
169 string id_str = boost::lexical_cast<string>(fieldId);
170 if (id_str.length() == 1) id_str = '0' + id_str;
171
172 return writeIndented(
173 id_str + ": " +
David Reiss0c90f6f2008-02-06 22:18:40 +0000174 name + " (" +
David Reiss00dcccf2007-07-21 01:18:10 +0000175 fieldTypeName(fieldType) + ") = ");
176}
177
178uint32_t TDebugProtocol::writeFieldEnd() {
179 assert(write_state_.back() == STRUCT);
180 return 0;
181}
182
183uint32_t TDebugProtocol::writeFieldStop() {
184 return 0;
185 //writeIndented("***STOP***\n");
David Reiss0c90f6f2008-02-06 22:18:40 +0000186}
187
David Reiss00dcccf2007-07-21 01:18:10 +0000188uint32_t TDebugProtocol::writeMapBegin(const TType keyType,
189 const TType valType,
190 const uint32_t size) {
191 // TODO(dreiss): Optimize short maps?
192 uint32_t bsize = 0;
193 bsize += startItem();
194 bsize += writePlain(
195 "map<" + fieldTypeName(keyType) + "," + fieldTypeName(valType) + ">"
196 "[" + boost::lexical_cast<string>(size) + "] {\n");
197 indentUp();
198 write_state_.push_back(MAP_KEY);
199 return bsize;
200}
201
202uint32_t TDebugProtocol::writeMapEnd() {
203 indentDown();
204 write_state_.pop_back();
205 uint32_t size = 0;
206 size += writeIndented("}");
207 size += endItem();
208 return size;
209}
210
211uint32_t TDebugProtocol::writeListBegin(const TType elemType,
212 const uint32_t size) {
213 // TODO(dreiss): Optimize short arrays.
214 uint32_t bsize = 0;
215 bsize += startItem();
216 bsize += writePlain(
217 "list<" + fieldTypeName(elemType) + ">"
218 "[" + boost::lexical_cast<string>(size) + "] {\n");
219 indentUp();
220 write_state_.push_back(LIST);
221 list_idx_.push_back(0);
222 return bsize;
223}
224
225uint32_t TDebugProtocol::writeListEnd() {
226 indentDown();
227 write_state_.pop_back();
228 list_idx_.pop_back();
229 uint32_t size = 0;
230 size += writeIndented("}");
231 size += endItem();
232 return size;
233}
234
235uint32_t TDebugProtocol::writeSetBegin(const TType elemType,
236 const uint32_t size) {
237 // TODO(dreiss): Optimize short sets.
238 uint32_t bsize = 0;
239 bsize += startItem();
240 bsize += writePlain(
241 "set<" + fieldTypeName(elemType) + ">"
242 "[" + boost::lexical_cast<string>(size) + "] {\n");
243 indentUp();
244 write_state_.push_back(SET);
245 return bsize;
246}
247
248uint32_t TDebugProtocol::writeSetEnd() {
249 indentDown();
250 write_state_.pop_back();
251 uint32_t size = 0;
252 size += writeIndented("}");
253 size += endItem();
254 return size;
255}
256
257uint32_t TDebugProtocol::writeBool(const bool value) {
258 return writeItem(value ? "true" : "false");
259}
260
261uint32_t TDebugProtocol::writeByte(const int8_t byte) {
262 return writeItem("0x" + byte_to_hex(byte));
263}
264
265uint32_t TDebugProtocol::writeI16(const int16_t i16) {
266 return writeItem(boost::lexical_cast<string>(i16));
267}
268
269uint32_t TDebugProtocol::writeI32(const int32_t i32) {
270 return writeItem(boost::lexical_cast<string>(i32));
271}
272
273uint32_t TDebugProtocol::writeI64(const int64_t i64) {
274 return writeItem(boost::lexical_cast<string>(i64));
275}
David Reiss0c90f6f2008-02-06 22:18:40 +0000276
David Reiss00dcccf2007-07-21 01:18:10 +0000277uint32_t TDebugProtocol::writeDouble(const double dub) {
278 return writeItem(boost::lexical_cast<string>(dub));
279}
280
David Reiss0c90f6f2008-02-06 22:18:40 +0000281
David Reiss00dcccf2007-07-21 01:18:10 +0000282uint32_t TDebugProtocol::writeString(const string& str) {
283 // XXX Raw/UTF-8?
284
285 string output = "\"";
286
287 for (string::const_iterator it = str.begin(); it != str.end(); ++it) {
288 if (*it == '\\') {
289 output += "\\";
290 } else if (*it == '"') {
291 output += "\\\"";
292 } else if (std::isprint(*it)) {
293 output += *it;
294 } else {
295 switch (*it) {
296 case '\"': output += "\\\""; break;
297 case '\a': output += "\\a"; break;
298 case '\b': output += "\\b"; break;
299 case '\f': output += "\\f"; break;
300 case '\n': output += "\\n"; break;
301 case '\r': output += "\\r"; break;
302 case '\t': output += "\\t"; break;
303 case '\v': output += "\\v"; break;
304 default:
305 output += "\\x";
306 output += byte_to_hex(*it);
307 }
308 }
309 }
310
311 output += '\"';
312 return writeItem(output);
313}
314
315}}} // facebook::thrift::protocol