blob: 63ea14de2aaaa0ed3c312c46c9f020d9fdd56fec [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
Roger Meier4285ba22013-06-10 21:17:23 +020020#include <thrift/protocol/TDebugProtocol.h>
David Reiss00dcccf2007-07-21 01:18:10 +000021
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);
Carl Yeksigian7cb7fc82013-06-07 07:33:01 -040035 THRIFT_UNUSED_VARIABLE(ret);
David Reiss00dcccf2007-07-21 01:18:10 +000036 assert(ret == 2);
37 assert(buf[2] == '\0');
38 return buf;
39}
40
41
T Jake Lucianib5e62212009-01-31 22:36:20 +000042namespace apache { namespace thrift { namespace protocol {
David Reiss00dcccf2007-07-21 01:18:10 +000043
44string TDebugProtocol::fieldTypeName(TType type) {
45 switch (type) {
46 case T_STOP : return "stop" ;
47 case T_VOID : return "void" ;
48 case T_BOOL : return "bool" ;
49 case T_BYTE : return "byte" ;
50 case T_I16 : return "i16" ;
51 case T_I32 : return "i32" ;
52 case T_U64 : return "u64" ;
53 case T_I64 : return "i64" ;
54 case T_DOUBLE : return "double" ;
55 case T_STRING : return "string" ;
56 case T_STRUCT : return "struct" ;
57 case T_MAP : return "map" ;
58 case T_SET : return "set" ;
59 case T_LIST : return "list" ;
60 case T_UTF8 : return "utf8" ;
61 case T_UTF16 : return "utf16" ;
62 default: return "unknown";
63 }
64}
65
66void TDebugProtocol::indentUp() {
67 indent_str_ += string(indent_inc, ' ');
68}
69
70void TDebugProtocol::indentDown() {
71 if (indent_str_.length() < (string::size_type)indent_inc) {
72 throw TProtocolException(TProtocolException::INVALID_DATA);
73 }
74 indent_str_.erase(indent_str_.length() - indent_inc);
75}
76
77uint32_t TDebugProtocol::writePlain(const string& str) {
Roger Meierb69d24d2012-10-04 18:02:15 +000078 if(str.length() > (std::numeric_limits<uint32_t>::max)())
79 throw TProtocolException(TProtocolException::SIZE_LIMIT);
80 trans_->write((uint8_t*)str.data(), static_cast<uint32_t>(str.length()));
81 return static_cast<uint32_t>(str.length());
David Reiss00dcccf2007-07-21 01:18:10 +000082}
83
84uint32_t TDebugProtocol::writeIndented(const string& str) {
Roger Meierb69d24d2012-10-04 18:02:15 +000085 if(str.length() > (std::numeric_limits<uint32_t>::max)())
86 throw TProtocolException(TProtocolException::SIZE_LIMIT);
87 if(indent_str_.length() > (std::numeric_limits<uint32_t>::max)())
88 throw TProtocolException(TProtocolException::SIZE_LIMIT);
89 uint64_t total_len = indent_str_.length() + str.length();
90 if(total_len > (std::numeric_limits<uint32_t>::max)())
91 throw TProtocolException(TProtocolException::SIZE_LIMIT);
92 trans_->write((uint8_t*)indent_str_.data(), static_cast<uint32_t>(indent_str_.length()));
93 trans_->write((uint8_t*)str.data(), static_cast<uint32_t>(str.length()));
94 return static_cast<uint32_t>(indent_str_.length() + str.length());
David Reiss00dcccf2007-07-21 01:18:10 +000095}
96
97uint32_t TDebugProtocol::startItem() {
98 uint32_t size;
99
100 switch (write_state_.back()) {
101 case UNINIT:
102 // XXX figure out what to do here.
103 //throw TProtocolException(TProtocolException::INVALID_DATA);
104 //return writeIndented(str);
105 return 0;
106 case STRUCT:
107 return 0;
108 case SET:
109 return writeIndented("");
110 case MAP_KEY:
111 return writeIndented("");
112 case MAP_VALUE:
113 return writePlain(" -> ");
114 case LIST:
115 size = writeIndented(
116 "[" + boost::lexical_cast<string>(list_idx_.back()) + "] = ");
117 list_idx_.back()++;
118 return size;
119 default:
120 throw std::logic_error("Invalid enum value.");
121 }
122}
123
124uint32_t TDebugProtocol::endItem() {
125 //uint32_t size;
126
127 switch (write_state_.back()) {
128 case UNINIT:
129 // XXX figure out what to do here.
130 //throw TProtocolException(TProtocolException::INVALID_DATA);
131 //return writeIndented(str);
132 return 0;
133 case STRUCT:
134 return writePlain(",\n");
135 case SET:
136 return writePlain(",\n");
137 case MAP_KEY:
138 write_state_.back() = MAP_VALUE;
139 return 0;
140 case MAP_VALUE:
141 write_state_.back() = MAP_KEY;
142 return writePlain(",\n");
143 case LIST:
144 return writePlain(",\n");
145 default:
146 throw std::logic_error("Invalid enum value.");
147 }
148}
149
150uint32_t TDebugProtocol::writeItem(const std::string& str) {
151 uint32_t size = 0;
152 size += startItem();
153 size += writePlain(str);
154 size += endItem();
155 return size;
156}
157
158uint32_t TDebugProtocol::writeMessageBegin(const std::string& name,
159 const TMessageType messageType,
160 const int32_t seqid) {
Roger Meier3b771a12010-11-17 22:11:26 +0000161 (void) seqid;
David Reiss642f2d32008-04-08 05:06:32 +0000162 string mtype;
163 switch (messageType) {
David Reissf770bef2010-10-18 17:25:13 +0000164 case T_CALL : mtype = "call" ; break;
165 case T_REPLY : mtype = "reply" ; break;
166 case T_EXCEPTION : mtype = "exn" ; break;
David Reiss63228e52010-10-18 17:25:40 +0000167 case T_ONEWAY : mtype = "oneway" ; break;
David Reiss642f2d32008-04-08 05:06:32 +0000168 }
169
170 uint32_t size = writeIndented("(" + mtype + ") " + name + "(");
171 indentUp();
172 return size;
David Reiss00dcccf2007-07-21 01:18:10 +0000173}
174
175uint32_t TDebugProtocol::writeMessageEnd() {
David Reiss642f2d32008-04-08 05:06:32 +0000176 indentDown();
177 return writeIndented(")\n");
David Reiss00dcccf2007-07-21 01:18:10 +0000178}
179
David Reiss64120002008-04-29 23:12:24 +0000180uint32_t TDebugProtocol::writeStructBegin(const char* name) {
David Reiss00dcccf2007-07-21 01:18:10 +0000181 uint32_t size = 0;
182 size += startItem();
David Reiss64120002008-04-29 23:12:24 +0000183 size += writePlain(string(name) + " {\n");
David Reiss00dcccf2007-07-21 01:18:10 +0000184 indentUp();
185 write_state_.push_back(STRUCT);
186 return size;
187}
188
189uint32_t TDebugProtocol::writeStructEnd() {
190 indentDown();
191 write_state_.pop_back();
192 uint32_t size = 0;
193 size += writeIndented("}");
194 size += endItem();
195 return size;
196}
197
David Reiss64120002008-04-29 23:12:24 +0000198uint32_t TDebugProtocol::writeFieldBegin(const char* name,
David Reiss00dcccf2007-07-21 01:18:10 +0000199 const TType fieldType,
200 const int16_t fieldId) {
201 // sprintf(id_str, "%02d", fieldId);
202 string id_str = boost::lexical_cast<string>(fieldId);
203 if (id_str.length() == 1) id_str = '0' + id_str;
204
205 return writeIndented(
206 id_str + ": " +
David Reiss0c90f6f2008-02-06 22:18:40 +0000207 name + " (" +
David Reiss00dcccf2007-07-21 01:18:10 +0000208 fieldTypeName(fieldType) + ") = ");
209}
210
211uint32_t TDebugProtocol::writeFieldEnd() {
212 assert(write_state_.back() == STRUCT);
213 return 0;
214}
215
216uint32_t TDebugProtocol::writeFieldStop() {
217 return 0;
218 //writeIndented("***STOP***\n");
David Reiss0c90f6f2008-02-06 22:18:40 +0000219}
220
David Reiss00dcccf2007-07-21 01:18:10 +0000221uint32_t TDebugProtocol::writeMapBegin(const TType keyType,
222 const TType valType,
223 const uint32_t size) {
224 // TODO(dreiss): Optimize short maps?
225 uint32_t bsize = 0;
226 bsize += startItem();
227 bsize += writePlain(
228 "map<" + fieldTypeName(keyType) + "," + fieldTypeName(valType) + ">"
229 "[" + boost::lexical_cast<string>(size) + "] {\n");
230 indentUp();
231 write_state_.push_back(MAP_KEY);
232 return bsize;
233}
234
235uint32_t TDebugProtocol::writeMapEnd() {
236 indentDown();
237 write_state_.pop_back();
238 uint32_t size = 0;
239 size += writeIndented("}");
240 size += endItem();
241 return size;
242}
243
244uint32_t TDebugProtocol::writeListBegin(const TType elemType,
245 const uint32_t size) {
246 // TODO(dreiss): Optimize short arrays.
247 uint32_t bsize = 0;
248 bsize += startItem();
249 bsize += writePlain(
250 "list<" + fieldTypeName(elemType) + ">"
251 "[" + boost::lexical_cast<string>(size) + "] {\n");
252 indentUp();
253 write_state_.push_back(LIST);
254 list_idx_.push_back(0);
255 return bsize;
256}
257
258uint32_t TDebugProtocol::writeListEnd() {
259 indentDown();
260 write_state_.pop_back();
261 list_idx_.pop_back();
262 uint32_t size = 0;
263 size += writeIndented("}");
264 size += endItem();
265 return size;
266}
267
268uint32_t TDebugProtocol::writeSetBegin(const TType elemType,
269 const uint32_t size) {
270 // TODO(dreiss): Optimize short sets.
271 uint32_t bsize = 0;
272 bsize += startItem();
273 bsize += writePlain(
274 "set<" + fieldTypeName(elemType) + ">"
275 "[" + boost::lexical_cast<string>(size) + "] {\n");
276 indentUp();
277 write_state_.push_back(SET);
278 return bsize;
279}
280
281uint32_t TDebugProtocol::writeSetEnd() {
282 indentDown();
283 write_state_.pop_back();
284 uint32_t size = 0;
285 size += writeIndented("}");
286 size += endItem();
287 return size;
288}
289
290uint32_t TDebugProtocol::writeBool(const bool value) {
291 return writeItem(value ? "true" : "false");
292}
293
294uint32_t TDebugProtocol::writeByte(const int8_t byte) {
295 return writeItem("0x" + byte_to_hex(byte));
296}
297
298uint32_t TDebugProtocol::writeI16(const int16_t i16) {
299 return writeItem(boost::lexical_cast<string>(i16));
300}
301
302uint32_t TDebugProtocol::writeI32(const int32_t i32) {
303 return writeItem(boost::lexical_cast<string>(i32));
304}
305
306uint32_t TDebugProtocol::writeI64(const int64_t i64) {
307 return writeItem(boost::lexical_cast<string>(i64));
308}
David Reiss0c90f6f2008-02-06 22:18:40 +0000309
David Reiss00dcccf2007-07-21 01:18:10 +0000310uint32_t TDebugProtocol::writeDouble(const double dub) {
311 return writeItem(boost::lexical_cast<string>(dub));
312}
313
David Reiss0c90f6f2008-02-06 22:18:40 +0000314
David Reiss00dcccf2007-07-21 01:18:10 +0000315uint32_t TDebugProtocol::writeString(const string& str) {
316 // XXX Raw/UTF-8?
317
David Reissa80f0fb2008-04-08 05:06:15 +0000318 string to_show = str;
319 if (to_show.length() > (string::size_type)string_limit_) {
320 to_show = str.substr(0, string_prefix_size_);
321 to_show += "[...](" + boost::lexical_cast<string>(str.length()) + ")";
322 }
323
David Reiss00dcccf2007-07-21 01:18:10 +0000324 string output = "\"";
325
David Reissa80f0fb2008-04-08 05:06:15 +0000326 for (string::const_iterator it = to_show.begin(); it != to_show.end(); ++it) {
David Reiss00dcccf2007-07-21 01:18:10 +0000327 if (*it == '\\') {
David Reissb54deb12008-04-08 19:38:49 +0000328 output += "\\\\";
David Reiss00dcccf2007-07-21 01:18:10 +0000329 } else if (*it == '"') {
330 output += "\\\"";
331 } else if (std::isprint(*it)) {
332 output += *it;
333 } else {
334 switch (*it) {
David Reiss00dcccf2007-07-21 01:18:10 +0000335 case '\a': output += "\\a"; break;
336 case '\b': output += "\\b"; break;
337 case '\f': output += "\\f"; break;
338 case '\n': output += "\\n"; break;
339 case '\r': output += "\\r"; break;
340 case '\t': output += "\\t"; break;
341 case '\v': output += "\\v"; break;
342 default:
343 output += "\\x";
344 output += byte_to_hex(*it);
345 }
346 }
347 }
348
349 output += '\"';
350 return writeItem(output);
351}
352
David Reissc005b1b2008-02-15 01:38:18 +0000353uint32_t TDebugProtocol::writeBinary(const string& str) {
David Reissa80f0fb2008-04-08 05:06:15 +0000354 // XXX Hex?
David Reissc005b1b2008-02-15 01:38:18 +0000355 return TDebugProtocol::writeString(str);
356}
357
T Jake Lucianib5e62212009-01-31 22:36:20 +0000358}}} // apache::thrift::protocol