blob: 40aa36bad2c97b28a6bb81f7f8a660f3a5a1eb32 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
#include "TDebugProtocol.h"
#include <cassert>
#include <cctype>
#include <cstdio>
#include <stdexcept>
#include <boost/static_assert.hpp>
#include <boost/lexical_cast.hpp>
using std::string;
static string byte_to_hex(const uint8_t byte) {
char buf[3];
int ret = std::sprintf(buf, "%02x", (int)byte);
assert(ret == 2);
assert(buf[2] == '\0');
return buf;
}
namespace apache { namespace thrift { namespace protocol {
string TDebugProtocol::fieldTypeName(TType type) {
switch (type) {
case T_STOP : return "stop" ;
case T_VOID : return "void" ;
case T_BOOL : return "bool" ;
case T_BYTE : return "byte" ;
case T_I16 : return "i16" ;
case T_I32 : return "i32" ;
case T_U64 : return "u64" ;
case T_I64 : return "i64" ;
case T_DOUBLE : return "double" ;
case T_STRING : return "string" ;
case T_STRUCT : return "struct" ;
case T_MAP : return "map" ;
case T_SET : return "set" ;
case T_LIST : return "list" ;
case T_UTF8 : return "utf8" ;
case T_UTF16 : return "utf16" ;
default: return "unknown";
}
}
void TDebugProtocol::indentUp() {
indent_str_ += string(indent_inc, ' ');
}
void TDebugProtocol::indentDown() {
if (indent_str_.length() < (string::size_type)indent_inc) {
throw TProtocolException(TProtocolException::INVALID_DATA);
}
indent_str_.erase(indent_str_.length() - indent_inc);
}
uint32_t TDebugProtocol::writePlain(const string& str) {
trans_->write((uint8_t*)str.data(), str.length());
return str.length();
}
uint32_t TDebugProtocol::writeIndented(const string& str) {
trans_->write((uint8_t*)indent_str_.data(), indent_str_.length());
trans_->write((uint8_t*)str.data(), str.length());
return indent_str_.length() + str.length();
}
uint32_t TDebugProtocol::startItem() {
uint32_t size;
switch (write_state_.back()) {
case UNINIT:
// XXX figure out what to do here.
//throw TProtocolException(TProtocolException::INVALID_DATA);
//return writeIndented(str);
return 0;
case STRUCT:
return 0;
case SET:
return writeIndented("");
case MAP_KEY:
return writeIndented("");
case MAP_VALUE:
return writePlain(" -> ");
case LIST:
size = writeIndented(
"[" + boost::lexical_cast<string>(list_idx_.back()) + "] = ");
list_idx_.back()++;
return size;
default:
throw std::logic_error("Invalid enum value.");
}
}
uint32_t TDebugProtocol::endItem() {
//uint32_t size;
switch (write_state_.back()) {
case UNINIT:
// XXX figure out what to do here.
//throw TProtocolException(TProtocolException::INVALID_DATA);
//return writeIndented(str);
return 0;
case STRUCT:
return writePlain(",\n");
case SET:
return writePlain(",\n");
case MAP_KEY:
write_state_.back() = MAP_VALUE;
return 0;
case MAP_VALUE:
write_state_.back() = MAP_KEY;
return writePlain(",\n");
case LIST:
return writePlain(",\n");
default:
throw std::logic_error("Invalid enum value.");
}
}
uint32_t TDebugProtocol::writeItem(const std::string& str) {
uint32_t size = 0;
size += startItem();
size += writePlain(str);
size += endItem();
return size;
}
uint32_t TDebugProtocol::writeMessageBegin(const std::string& name,
const TMessageType messageType,
const int32_t seqid) {
string mtype;
switch (messageType) {
case T_CALL : mtype = "call" ; break;
case T_REPLY : mtype = "reply" ; break;
case T_EXCEPTION : mtype = "exn" ; break;
}
uint32_t size = writeIndented("(" + mtype + ") " + name + "(");
indentUp();
return size;
}
uint32_t TDebugProtocol::writeMessageEnd() {
indentDown();
return writeIndented(")\n");
}
uint32_t TDebugProtocol::writeStructBegin(const char* name) {
uint32_t size = 0;
size += startItem();
size += writePlain(string(name) + " {\n");
indentUp();
write_state_.push_back(STRUCT);
return size;
}
uint32_t TDebugProtocol::writeStructEnd() {
indentDown();
write_state_.pop_back();
uint32_t size = 0;
size += writeIndented("}");
size += endItem();
return size;
}
uint32_t TDebugProtocol::writeFieldBegin(const char* name,
const TType fieldType,
const int16_t fieldId) {
// sprintf(id_str, "%02d", fieldId);
string id_str = boost::lexical_cast<string>(fieldId);
if (id_str.length() == 1) id_str = '0' + id_str;
return writeIndented(
id_str + ": " +
name + " (" +
fieldTypeName(fieldType) + ") = ");
}
uint32_t TDebugProtocol::writeFieldEnd() {
assert(write_state_.back() == STRUCT);
return 0;
}
uint32_t TDebugProtocol::writeFieldStop() {
return 0;
//writeIndented("***STOP***\n");
}
uint32_t TDebugProtocol::writeMapBegin(const TType keyType,
const TType valType,
const uint32_t size) {
// TODO(dreiss): Optimize short maps?
uint32_t bsize = 0;
bsize += startItem();
bsize += writePlain(
"map<" + fieldTypeName(keyType) + "," + fieldTypeName(valType) + ">"
"[" + boost::lexical_cast<string>(size) + "] {\n");
indentUp();
write_state_.push_back(MAP_KEY);
return bsize;
}
uint32_t TDebugProtocol::writeMapEnd() {
indentDown();
write_state_.pop_back();
uint32_t size = 0;
size += writeIndented("}");
size += endItem();
return size;
}
uint32_t TDebugProtocol::writeListBegin(const TType elemType,
const uint32_t size) {
// TODO(dreiss): Optimize short arrays.
uint32_t bsize = 0;
bsize += startItem();
bsize += writePlain(
"list<" + fieldTypeName(elemType) + ">"
"[" + boost::lexical_cast<string>(size) + "] {\n");
indentUp();
write_state_.push_back(LIST);
list_idx_.push_back(0);
return bsize;
}
uint32_t TDebugProtocol::writeListEnd() {
indentDown();
write_state_.pop_back();
list_idx_.pop_back();
uint32_t size = 0;
size += writeIndented("}");
size += endItem();
return size;
}
uint32_t TDebugProtocol::writeSetBegin(const TType elemType,
const uint32_t size) {
// TODO(dreiss): Optimize short sets.
uint32_t bsize = 0;
bsize += startItem();
bsize += writePlain(
"set<" + fieldTypeName(elemType) + ">"
"[" + boost::lexical_cast<string>(size) + "] {\n");
indentUp();
write_state_.push_back(SET);
return bsize;
}
uint32_t TDebugProtocol::writeSetEnd() {
indentDown();
write_state_.pop_back();
uint32_t size = 0;
size += writeIndented("}");
size += endItem();
return size;
}
uint32_t TDebugProtocol::writeBool(const bool value) {
return writeItem(value ? "true" : "false");
}
uint32_t TDebugProtocol::writeByte(const int8_t byte) {
return writeItem("0x" + byte_to_hex(byte));
}
uint32_t TDebugProtocol::writeI16(const int16_t i16) {
return writeItem(boost::lexical_cast<string>(i16));
}
uint32_t TDebugProtocol::writeI32(const int32_t i32) {
return writeItem(boost::lexical_cast<string>(i32));
}
uint32_t TDebugProtocol::writeI64(const int64_t i64) {
return writeItem(boost::lexical_cast<string>(i64));
}
uint32_t TDebugProtocol::writeDouble(const double dub) {
return writeItem(boost::lexical_cast<string>(dub));
}
uint32_t TDebugProtocol::writeString(const string& str) {
// XXX Raw/UTF-8?
string to_show = str;
if (to_show.length() > (string::size_type)string_limit_) {
to_show = str.substr(0, string_prefix_size_);
to_show += "[...](" + boost::lexical_cast<string>(str.length()) + ")";
}
string output = "\"";
for (string::const_iterator it = to_show.begin(); it != to_show.end(); ++it) {
if (*it == '\\') {
output += "\\\\";
} else if (*it == '"') {
output += "\\\"";
} else if (std::isprint(*it)) {
output += *it;
} else {
switch (*it) {
case '\a': output += "\\a"; break;
case '\b': output += "\\b"; break;
case '\f': output += "\\f"; break;
case '\n': output += "\\n"; break;
case '\r': output += "\\r"; break;
case '\t': output += "\\t"; break;
case '\v': output += "\\v"; break;
default:
output += "\\x";
output += byte_to_hex(*it);
}
}
}
output += '\"';
return writeItem(output);
}
uint32_t TDebugProtocol::writeBinary(const string& str) {
// XXX Hex?
return TDebugProtocol::writeString(str);
}
}}} // apache::thrift::protocol