blob: ee82e71d6ccb49981c970dff78da7b2bcc46af41 [file] [log] [blame]
David Reissea2cba82009-03-30 21:35:00 +00001/*
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 */
David Reiss00dcccf2007-07-21 01:18:10 +000019
20#include "TDebugProtocol.h"
21
22#include <cassert>
23#include <cctype>
24#include <cstdio>
25#include <stdexcept>
26#include <boost/static_assert.hpp>
27#include <boost/lexical_cast.hpp>
28
29using std::string;
30
31
32static string byte_to_hex(const uint8_t byte) {
33 char buf[3];
34 int ret = std::sprintf(buf, "%02x", (int)byte);
35 assert(ret == 2);
36 assert(buf[2] == '\0');
37 return buf;
38}
39
40
T Jake Lucianib5e62212009-01-31 22:36:20 +000041namespace apache { namespace thrift { namespace protocol {
David Reiss00dcccf2007-07-21 01:18:10 +000042
43string TDebugProtocol::fieldTypeName(TType type) {
44 switch (type) {
45 case T_STOP : return "stop" ;
46 case T_VOID : return "void" ;
47 case T_BOOL : return "bool" ;
48 case T_BYTE : return "byte" ;
49 case T_I16 : return "i16" ;
50 case T_I32 : return "i32" ;
51 case T_U64 : return "u64" ;
52 case T_I64 : return "i64" ;
53 case T_DOUBLE : return "double" ;
54 case T_STRING : return "string" ;
55 case T_STRUCT : return "struct" ;
56 case T_MAP : return "map" ;
57 case T_SET : return "set" ;
58 case T_LIST : return "list" ;
59 case T_UTF8 : return "utf8" ;
60 case T_UTF16 : return "utf16" ;
61 default: return "unknown";
62 }
63}
64
65void TDebugProtocol::indentUp() {
66 indent_str_ += string(indent_inc, ' ');
67}
68
69void TDebugProtocol::indentDown() {
70 if (indent_str_.length() < (string::size_type)indent_inc) {
71 throw TProtocolException(TProtocolException::INVALID_DATA);
72 }
73 indent_str_.erase(indent_str_.length() - indent_inc);
74}
75
76uint32_t TDebugProtocol::writePlain(const string& str) {
77 trans_->write((uint8_t*)str.data(), str.length());
78 return str.length();
79}
80
81uint32_t TDebugProtocol::writeIndented(const string& str) {
82 trans_->write((uint8_t*)indent_str_.data(), indent_str_.length());
83 trans_->write((uint8_t*)str.data(), str.length());
84 return indent_str_.length() + str.length();
85}
86
87uint32_t TDebugProtocol::startItem() {
88 uint32_t size;
89
90 switch (write_state_.back()) {
91 case UNINIT:
92 // XXX figure out what to do here.
93 //throw TProtocolException(TProtocolException::INVALID_DATA);
94 //return writeIndented(str);
95 return 0;
96 case STRUCT:
97 return 0;
98 case SET:
99 return writeIndented("");
100 case MAP_KEY:
101 return writeIndented("");
102 case MAP_VALUE:
103 return writePlain(" -> ");
104 case LIST:
105 size = writeIndented(
106 "[" + boost::lexical_cast<string>(list_idx_.back()) + "] = ");
107 list_idx_.back()++;
108 return size;
109 default:
110 throw std::logic_error("Invalid enum value.");
111 }
112}
113
114uint32_t TDebugProtocol::endItem() {
115 //uint32_t size;
116
117 switch (write_state_.back()) {
118 case UNINIT:
119 // XXX figure out what to do here.
120 //throw TProtocolException(TProtocolException::INVALID_DATA);
121 //return writeIndented(str);
122 return 0;
123 case STRUCT:
124 return writePlain(",\n");
125 case SET:
126 return writePlain(",\n");
127 case MAP_KEY:
128 write_state_.back() = MAP_VALUE;
129 return 0;
130 case MAP_VALUE:
131 write_state_.back() = MAP_KEY;
132 return writePlain(",\n");
133 case LIST:
134 return writePlain(",\n");
135 default:
136 throw std::logic_error("Invalid enum value.");
137 }
138}
139
140uint32_t TDebugProtocol::writeItem(const std::string& str) {
141 uint32_t size = 0;
142 size += startItem();
143 size += writePlain(str);
144 size += endItem();
145 return size;
146}
147
148uint32_t TDebugProtocol::writeMessageBegin(const std::string& name,
149 const TMessageType messageType,
150 const int32_t seqid) {
David Reiss642f2d32008-04-08 05:06:32 +0000151 string mtype;
152 switch (messageType) {
David Reissf770bef2010-10-18 17:25:13 +0000153 case T_CALL : mtype = "call" ; break;
154 case T_REPLY : mtype = "reply" ; break;
155 case T_EXCEPTION : mtype = "exn" ; break;
David Reiss63228e52010-10-18 17:25:40 +0000156 case T_ONEWAY : mtype = "oneway" ; break;
David Reiss642f2d32008-04-08 05:06:32 +0000157 }
158
159 uint32_t size = writeIndented("(" + mtype + ") " + name + "(");
160 indentUp();
161 return size;
David Reiss00dcccf2007-07-21 01:18:10 +0000162}
163
164uint32_t TDebugProtocol::writeMessageEnd() {
David Reiss642f2d32008-04-08 05:06:32 +0000165 indentDown();
166 return writeIndented(")\n");
David Reiss00dcccf2007-07-21 01:18:10 +0000167}
168
David Reiss64120002008-04-29 23:12:24 +0000169uint32_t TDebugProtocol::writeStructBegin(const char* name) {
David Reiss00dcccf2007-07-21 01:18:10 +0000170 uint32_t size = 0;
171 size += startItem();
David Reiss64120002008-04-29 23:12:24 +0000172 size += writePlain(string(name) + " {\n");
David Reiss00dcccf2007-07-21 01:18:10 +0000173 indentUp();
174 write_state_.push_back(STRUCT);
175 return size;
176}
177
178uint32_t TDebugProtocol::writeStructEnd() {
179 indentDown();
180 write_state_.pop_back();
181 uint32_t size = 0;
182 size += writeIndented("}");
183 size += endItem();
184 return size;
185}
186
David Reiss64120002008-04-29 23:12:24 +0000187uint32_t TDebugProtocol::writeFieldBegin(const char* name,
David Reiss00dcccf2007-07-21 01:18:10 +0000188 const TType fieldType,
189 const int16_t fieldId) {
190 // sprintf(id_str, "%02d", fieldId);
191 string id_str = boost::lexical_cast<string>(fieldId);
192 if (id_str.length() == 1) id_str = '0' + id_str;
193
194 return writeIndented(
195 id_str + ": " +
David Reiss0c90f6f2008-02-06 22:18:40 +0000196 name + " (" +
David Reiss00dcccf2007-07-21 01:18:10 +0000197 fieldTypeName(fieldType) + ") = ");
198}
199
200uint32_t TDebugProtocol::writeFieldEnd() {
201 assert(write_state_.back() == STRUCT);
202 return 0;
203}
204
205uint32_t TDebugProtocol::writeFieldStop() {
206 return 0;
207 //writeIndented("***STOP***\n");
David Reiss0c90f6f2008-02-06 22:18:40 +0000208}
209
David Reiss00dcccf2007-07-21 01:18:10 +0000210uint32_t TDebugProtocol::writeMapBegin(const TType keyType,
211 const TType valType,
212 const uint32_t size) {
213 // TODO(dreiss): Optimize short maps?
214 uint32_t bsize = 0;
215 bsize += startItem();
216 bsize += writePlain(
217 "map<" + fieldTypeName(keyType) + "," + fieldTypeName(valType) + ">"
218 "[" + boost::lexical_cast<string>(size) + "] {\n");
219 indentUp();
220 write_state_.push_back(MAP_KEY);
221 return bsize;
222}
223
224uint32_t TDebugProtocol::writeMapEnd() {
225 indentDown();
226 write_state_.pop_back();
227 uint32_t size = 0;
228 size += writeIndented("}");
229 size += endItem();
230 return size;
231}
232
233uint32_t TDebugProtocol::writeListBegin(const TType elemType,
234 const uint32_t size) {
235 // TODO(dreiss): Optimize short arrays.
236 uint32_t bsize = 0;
237 bsize += startItem();
238 bsize += writePlain(
239 "list<" + fieldTypeName(elemType) + ">"
240 "[" + boost::lexical_cast<string>(size) + "] {\n");
241 indentUp();
242 write_state_.push_back(LIST);
243 list_idx_.push_back(0);
244 return bsize;
245}
246
247uint32_t TDebugProtocol::writeListEnd() {
248 indentDown();
249 write_state_.pop_back();
250 list_idx_.pop_back();
251 uint32_t size = 0;
252 size += writeIndented("}");
253 size += endItem();
254 return size;
255}
256
257uint32_t TDebugProtocol::writeSetBegin(const TType elemType,
258 const uint32_t size) {
259 // TODO(dreiss): Optimize short sets.
260 uint32_t bsize = 0;
261 bsize += startItem();
262 bsize += writePlain(
263 "set<" + fieldTypeName(elemType) + ">"
264 "[" + boost::lexical_cast<string>(size) + "] {\n");
265 indentUp();
266 write_state_.push_back(SET);
267 return bsize;
268}
269
270uint32_t TDebugProtocol::writeSetEnd() {
271 indentDown();
272 write_state_.pop_back();
273 uint32_t size = 0;
274 size += writeIndented("}");
275 size += endItem();
276 return size;
277}
278
279uint32_t TDebugProtocol::writeBool(const bool value) {
280 return writeItem(value ? "true" : "false");
281}
282
283uint32_t TDebugProtocol::writeByte(const int8_t byte) {
284 return writeItem("0x" + byte_to_hex(byte));
285}
286
287uint32_t TDebugProtocol::writeI16(const int16_t i16) {
288 return writeItem(boost::lexical_cast<string>(i16));
289}
290
291uint32_t TDebugProtocol::writeI32(const int32_t i32) {
292 return writeItem(boost::lexical_cast<string>(i32));
293}
294
295uint32_t TDebugProtocol::writeI64(const int64_t i64) {
296 return writeItem(boost::lexical_cast<string>(i64));
297}
David Reiss0c90f6f2008-02-06 22:18:40 +0000298
David Reiss00dcccf2007-07-21 01:18:10 +0000299uint32_t TDebugProtocol::writeDouble(const double dub) {
300 return writeItem(boost::lexical_cast<string>(dub));
301}
302
David Reiss0c90f6f2008-02-06 22:18:40 +0000303
David Reiss00dcccf2007-07-21 01:18:10 +0000304uint32_t TDebugProtocol::writeString(const string& str) {
305 // XXX Raw/UTF-8?
306
David Reissa80f0fb2008-04-08 05:06:15 +0000307 string to_show = str;
308 if (to_show.length() > (string::size_type)string_limit_) {
309 to_show = str.substr(0, string_prefix_size_);
310 to_show += "[...](" + boost::lexical_cast<string>(str.length()) + ")";
311 }
312
David Reiss00dcccf2007-07-21 01:18:10 +0000313 string output = "\"";
314
David Reissa80f0fb2008-04-08 05:06:15 +0000315 for (string::const_iterator it = to_show.begin(); it != to_show.end(); ++it) {
David Reiss00dcccf2007-07-21 01:18:10 +0000316 if (*it == '\\') {
David Reissb54deb12008-04-08 19:38:49 +0000317 output += "\\\\";
David Reiss00dcccf2007-07-21 01:18:10 +0000318 } else if (*it == '"') {
319 output += "\\\"";
320 } else if (std::isprint(*it)) {
321 output += *it;
322 } else {
323 switch (*it) {
David Reiss00dcccf2007-07-21 01:18:10 +0000324 case '\a': output += "\\a"; break;
325 case '\b': output += "\\b"; break;
326 case '\f': output += "\\f"; break;
327 case '\n': output += "\\n"; break;
328 case '\r': output += "\\r"; break;
329 case '\t': output += "\\t"; break;
330 case '\v': output += "\\v"; break;
331 default:
332 output += "\\x";
333 output += byte_to_hex(*it);
334 }
335 }
336 }
337
338 output += '\"';
339 return writeItem(output);
340}
341
David Reissc005b1b2008-02-15 01:38:18 +0000342uint32_t TDebugProtocol::writeBinary(const string& str) {
David Reissa80f0fb2008-04-08 05:06:15 +0000343 // XXX Hex?
David Reissc005b1b2008-02-15 01:38:18 +0000344 return TDebugProtocol::writeString(str);
345}
346
T Jake Lucianib5e62212009-01-31 22:36:20 +0000347}}} // apache::thrift::protocol