blob: 92e9d36ef05dd1128308ac1368c1c8c008c59d39 [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) {
David Reiss642f2d32008-04-08 05:06:32 +0000138 string mtype;
139 switch (messageType) {
140 case T_CALL : mtype = "call" ; break;
141 case T_REPLY : mtype = "reply" ; break;
142 case T_EXCEPTION : mtype = "exn" ; break;
143 }
144
145 uint32_t size = writeIndented("(" + mtype + ") " + name + "(");
146 indentUp();
147 return size;
David Reiss00dcccf2007-07-21 01:18:10 +0000148}
149
150uint32_t TDebugProtocol::writeMessageEnd() {
David Reiss642f2d32008-04-08 05:06:32 +0000151 indentDown();
152 return writeIndented(")\n");
David Reiss00dcccf2007-07-21 01:18:10 +0000153}
154
David Reiss64120002008-04-29 23:12:24 +0000155uint32_t TDebugProtocol::writeStructBegin(const char* name) {
David Reiss00dcccf2007-07-21 01:18:10 +0000156 uint32_t size = 0;
157 size += startItem();
David Reiss64120002008-04-29 23:12:24 +0000158 size += writePlain(string(name) + " {\n");
David Reiss00dcccf2007-07-21 01:18:10 +0000159 indentUp();
160 write_state_.push_back(STRUCT);
161 return size;
162}
163
164uint32_t TDebugProtocol::writeStructEnd() {
165 indentDown();
166 write_state_.pop_back();
167 uint32_t size = 0;
168 size += writeIndented("}");
169 size += endItem();
170 return size;
171}
172
David Reiss64120002008-04-29 23:12:24 +0000173uint32_t TDebugProtocol::writeFieldBegin(const char* name,
David Reiss00dcccf2007-07-21 01:18:10 +0000174 const TType fieldType,
175 const int16_t fieldId) {
176 // sprintf(id_str, "%02d", fieldId);
177 string id_str = boost::lexical_cast<string>(fieldId);
178 if (id_str.length() == 1) id_str = '0' + id_str;
179
180 return writeIndented(
181 id_str + ": " +
David Reiss0c90f6f2008-02-06 22:18:40 +0000182 name + " (" +
David Reiss00dcccf2007-07-21 01:18:10 +0000183 fieldTypeName(fieldType) + ") = ");
184}
185
186uint32_t TDebugProtocol::writeFieldEnd() {
187 assert(write_state_.back() == STRUCT);
188 return 0;
189}
190
191uint32_t TDebugProtocol::writeFieldStop() {
192 return 0;
193 //writeIndented("***STOP***\n");
David Reiss0c90f6f2008-02-06 22:18:40 +0000194}
195
David Reiss00dcccf2007-07-21 01:18:10 +0000196uint32_t TDebugProtocol::writeMapBegin(const TType keyType,
197 const TType valType,
198 const uint32_t size) {
199 // TODO(dreiss): Optimize short maps?
200 uint32_t bsize = 0;
201 bsize += startItem();
202 bsize += writePlain(
203 "map<" + fieldTypeName(keyType) + "," + fieldTypeName(valType) + ">"
204 "[" + boost::lexical_cast<string>(size) + "] {\n");
205 indentUp();
206 write_state_.push_back(MAP_KEY);
207 return bsize;
208}
209
210uint32_t TDebugProtocol::writeMapEnd() {
211 indentDown();
212 write_state_.pop_back();
213 uint32_t size = 0;
214 size += writeIndented("}");
215 size += endItem();
216 return size;
217}
218
219uint32_t TDebugProtocol::writeListBegin(const TType elemType,
220 const uint32_t size) {
221 // TODO(dreiss): Optimize short arrays.
222 uint32_t bsize = 0;
223 bsize += startItem();
224 bsize += writePlain(
225 "list<" + fieldTypeName(elemType) + ">"
226 "[" + boost::lexical_cast<string>(size) + "] {\n");
227 indentUp();
228 write_state_.push_back(LIST);
229 list_idx_.push_back(0);
230 return bsize;
231}
232
233uint32_t TDebugProtocol::writeListEnd() {
234 indentDown();
235 write_state_.pop_back();
236 list_idx_.pop_back();
237 uint32_t size = 0;
238 size += writeIndented("}");
239 size += endItem();
240 return size;
241}
242
243uint32_t TDebugProtocol::writeSetBegin(const TType elemType,
244 const uint32_t size) {
245 // TODO(dreiss): Optimize short sets.
246 uint32_t bsize = 0;
247 bsize += startItem();
248 bsize += writePlain(
249 "set<" + fieldTypeName(elemType) + ">"
250 "[" + boost::lexical_cast<string>(size) + "] {\n");
251 indentUp();
252 write_state_.push_back(SET);
253 return bsize;
254}
255
256uint32_t TDebugProtocol::writeSetEnd() {
257 indentDown();
258 write_state_.pop_back();
259 uint32_t size = 0;
260 size += writeIndented("}");
261 size += endItem();
262 return size;
263}
264
265uint32_t TDebugProtocol::writeBool(const bool value) {
266 return writeItem(value ? "true" : "false");
267}
268
269uint32_t TDebugProtocol::writeByte(const int8_t byte) {
270 return writeItem("0x" + byte_to_hex(byte));
271}
272
273uint32_t TDebugProtocol::writeI16(const int16_t i16) {
274 return writeItem(boost::lexical_cast<string>(i16));
275}
276
277uint32_t TDebugProtocol::writeI32(const int32_t i32) {
278 return writeItem(boost::lexical_cast<string>(i32));
279}
280
281uint32_t TDebugProtocol::writeI64(const int64_t i64) {
282 return writeItem(boost::lexical_cast<string>(i64));
283}
David Reiss0c90f6f2008-02-06 22:18:40 +0000284
David Reiss00dcccf2007-07-21 01:18:10 +0000285uint32_t TDebugProtocol::writeDouble(const double dub) {
286 return writeItem(boost::lexical_cast<string>(dub));
287}
288
David Reiss0c90f6f2008-02-06 22:18:40 +0000289
David Reiss00dcccf2007-07-21 01:18:10 +0000290uint32_t TDebugProtocol::writeString(const string& str) {
291 // XXX Raw/UTF-8?
292
David Reissa80f0fb2008-04-08 05:06:15 +0000293 string to_show = str;
294 if (to_show.length() > (string::size_type)string_limit_) {
295 to_show = str.substr(0, string_prefix_size_);
296 to_show += "[...](" + boost::lexical_cast<string>(str.length()) + ")";
297 }
298
David Reiss00dcccf2007-07-21 01:18:10 +0000299 string output = "\"";
300
David Reissa80f0fb2008-04-08 05:06:15 +0000301 for (string::const_iterator it = to_show.begin(); it != to_show.end(); ++it) {
David Reiss00dcccf2007-07-21 01:18:10 +0000302 if (*it == '\\') {
David Reissb54deb12008-04-08 19:38:49 +0000303 output += "\\\\";
David Reiss00dcccf2007-07-21 01:18:10 +0000304 } else if (*it == '"') {
305 output += "\\\"";
306 } else if (std::isprint(*it)) {
307 output += *it;
308 } else {
309 switch (*it) {
David Reiss00dcccf2007-07-21 01:18:10 +0000310 case '\a': output += "\\a"; break;
311 case '\b': output += "\\b"; break;
312 case '\f': output += "\\f"; break;
313 case '\n': output += "\\n"; break;
314 case '\r': output += "\\r"; break;
315 case '\t': output += "\\t"; break;
316 case '\v': output += "\\v"; break;
317 default:
318 output += "\\x";
319 output += byte_to_hex(*it);
320 }
321 }
322 }
323
324 output += '\"';
325 return writeItem(output);
326}
327
David Reissc005b1b2008-02-15 01:38:18 +0000328uint32_t TDebugProtocol::writeBinary(const string& str) {
David Reissa80f0fb2008-04-08 05:06:15 +0000329 // XXX Hex?
David Reissc005b1b2008-02-15 01:38:18 +0000330 return TDebugProtocol::writeString(str);
331}
332
David Reiss00dcccf2007-07-21 01:18:10 +0000333}}} // facebook::thrift::protocol