blob: 40aa36bad2c97b28a6bb81f7f8a660f3a5a1eb32 [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) {
153 case T_CALL : mtype = "call" ; break;
154 case T_REPLY : mtype = "reply" ; break;
155 case T_EXCEPTION : mtype = "exn" ; break;
156 }
157
158 uint32_t size = writeIndented("(" + mtype + ") " + name + "(");
159 indentUp();
160 return size;
David Reiss00dcccf2007-07-21 01:18:10 +0000161}
162
163uint32_t TDebugProtocol::writeMessageEnd() {
David Reiss642f2d32008-04-08 05:06:32 +0000164 indentDown();
165 return writeIndented(")\n");
David Reiss00dcccf2007-07-21 01:18:10 +0000166}
167
David Reiss64120002008-04-29 23:12:24 +0000168uint32_t TDebugProtocol::writeStructBegin(const char* name) {
David Reiss00dcccf2007-07-21 01:18:10 +0000169 uint32_t size = 0;
170 size += startItem();
David Reiss64120002008-04-29 23:12:24 +0000171 size += writePlain(string(name) + " {\n");
David Reiss00dcccf2007-07-21 01:18:10 +0000172 indentUp();
173 write_state_.push_back(STRUCT);
174 return size;
175}
176
177uint32_t TDebugProtocol::writeStructEnd() {
178 indentDown();
179 write_state_.pop_back();
180 uint32_t size = 0;
181 size += writeIndented("}");
182 size += endItem();
183 return size;
184}
185
David Reiss64120002008-04-29 23:12:24 +0000186uint32_t TDebugProtocol::writeFieldBegin(const char* name,
David Reiss00dcccf2007-07-21 01:18:10 +0000187 const TType fieldType,
188 const int16_t fieldId) {
189 // sprintf(id_str, "%02d", fieldId);
190 string id_str = boost::lexical_cast<string>(fieldId);
191 if (id_str.length() == 1) id_str = '0' + id_str;
192
193 return writeIndented(
194 id_str + ": " +
David Reiss0c90f6f2008-02-06 22:18:40 +0000195 name + " (" +
David Reiss00dcccf2007-07-21 01:18:10 +0000196 fieldTypeName(fieldType) + ") = ");
197}
198
199uint32_t TDebugProtocol::writeFieldEnd() {
200 assert(write_state_.back() == STRUCT);
201 return 0;
202}
203
204uint32_t TDebugProtocol::writeFieldStop() {
205 return 0;
206 //writeIndented("***STOP***\n");
David Reiss0c90f6f2008-02-06 22:18:40 +0000207}
208
David Reiss00dcccf2007-07-21 01:18:10 +0000209uint32_t TDebugProtocol::writeMapBegin(const TType keyType,
210 const TType valType,
211 const uint32_t size) {
212 // TODO(dreiss): Optimize short maps?
213 uint32_t bsize = 0;
214 bsize += startItem();
215 bsize += writePlain(
216 "map<" + fieldTypeName(keyType) + "," + fieldTypeName(valType) + ">"
217 "[" + boost::lexical_cast<string>(size) + "] {\n");
218 indentUp();
219 write_state_.push_back(MAP_KEY);
220 return bsize;
221}
222
223uint32_t TDebugProtocol::writeMapEnd() {
224 indentDown();
225 write_state_.pop_back();
226 uint32_t size = 0;
227 size += writeIndented("}");
228 size += endItem();
229 return size;
230}
231
232uint32_t TDebugProtocol::writeListBegin(const TType elemType,
233 const uint32_t size) {
234 // TODO(dreiss): Optimize short arrays.
235 uint32_t bsize = 0;
236 bsize += startItem();
237 bsize += writePlain(
238 "list<" + fieldTypeName(elemType) + ">"
239 "[" + boost::lexical_cast<string>(size) + "] {\n");
240 indentUp();
241 write_state_.push_back(LIST);
242 list_idx_.push_back(0);
243 return bsize;
244}
245
246uint32_t TDebugProtocol::writeListEnd() {
247 indentDown();
248 write_state_.pop_back();
249 list_idx_.pop_back();
250 uint32_t size = 0;
251 size += writeIndented("}");
252 size += endItem();
253 return size;
254}
255
256uint32_t TDebugProtocol::writeSetBegin(const TType elemType,
257 const uint32_t size) {
258 // TODO(dreiss): Optimize short sets.
259 uint32_t bsize = 0;
260 bsize += startItem();
261 bsize += writePlain(
262 "set<" + fieldTypeName(elemType) + ">"
263 "[" + boost::lexical_cast<string>(size) + "] {\n");
264 indentUp();
265 write_state_.push_back(SET);
266 return bsize;
267}
268
269uint32_t TDebugProtocol::writeSetEnd() {
270 indentDown();
271 write_state_.pop_back();
272 uint32_t size = 0;
273 size += writeIndented("}");
274 size += endItem();
275 return size;
276}
277
278uint32_t TDebugProtocol::writeBool(const bool value) {
279 return writeItem(value ? "true" : "false");
280}
281
282uint32_t TDebugProtocol::writeByte(const int8_t byte) {
283 return writeItem("0x" + byte_to_hex(byte));
284}
285
286uint32_t TDebugProtocol::writeI16(const int16_t i16) {
287 return writeItem(boost::lexical_cast<string>(i16));
288}
289
290uint32_t TDebugProtocol::writeI32(const int32_t i32) {
291 return writeItem(boost::lexical_cast<string>(i32));
292}
293
294uint32_t TDebugProtocol::writeI64(const int64_t i64) {
295 return writeItem(boost::lexical_cast<string>(i64));
296}
David Reiss0c90f6f2008-02-06 22:18:40 +0000297
David Reiss00dcccf2007-07-21 01:18:10 +0000298uint32_t TDebugProtocol::writeDouble(const double dub) {
299 return writeItem(boost::lexical_cast<string>(dub));
300}
301
David Reiss0c90f6f2008-02-06 22:18:40 +0000302
David Reiss00dcccf2007-07-21 01:18:10 +0000303uint32_t TDebugProtocol::writeString(const string& str) {
304 // XXX Raw/UTF-8?
305
David Reissa80f0fb2008-04-08 05:06:15 +0000306 string to_show = str;
307 if (to_show.length() > (string::size_type)string_limit_) {
308 to_show = str.substr(0, string_prefix_size_);
309 to_show += "[...](" + boost::lexical_cast<string>(str.length()) + ")";
310 }
311
David Reiss00dcccf2007-07-21 01:18:10 +0000312 string output = "\"";
313
David Reissa80f0fb2008-04-08 05:06:15 +0000314 for (string::const_iterator it = to_show.begin(); it != to_show.end(); ++it) {
David Reiss00dcccf2007-07-21 01:18:10 +0000315 if (*it == '\\') {
David Reissb54deb12008-04-08 19:38:49 +0000316 output += "\\\\";
David Reiss00dcccf2007-07-21 01:18:10 +0000317 } else if (*it == '"') {
318 output += "\\\"";
319 } else if (std::isprint(*it)) {
320 output += *it;
321 } else {
322 switch (*it) {
David Reiss00dcccf2007-07-21 01:18:10 +0000323 case '\a': output += "\\a"; break;
324 case '\b': output += "\\b"; break;
325 case '\f': output += "\\f"; break;
326 case '\n': output += "\\n"; break;
327 case '\r': output += "\\r"; break;
328 case '\t': output += "\\t"; break;
329 case '\v': output += "\\v"; break;
330 default:
331 output += "\\x";
332 output += byte_to_hex(*it);
333 }
334 }
335 }
336
337 output += '\"';
338 return writeItem(output);
339}
340
David Reissc005b1b2008-02-15 01:38:18 +0000341uint32_t TDebugProtocol::writeBinary(const string& str) {
David Reissa80f0fb2008-04-08 05:06:15 +0000342 // XXX Hex?
David Reissc005b1b2008-02-15 01:38:18 +0000343 return TDebugProtocol::writeString(str);
344}
345
T Jake Lucianib5e62212009-01-31 22:36:20 +0000346}}} // apache::thrift::protocol