Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | RSS feed
/** 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