blob: 182589ad3d1c94ffe6961ad2899aae8a17fd67b2 [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.
// Date: Thu Nov 22 13:57:56 CST 2012
#include <inttypes.h>
#include "butil/iobuf.h"
#include "butil/binary_printer.h"
namespace butil {
static char s_binary_char_map[] = {
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
'A', 'B', 'C', 'D', 'E', 'F'
};
template <typename Appender>
class BinaryCharPrinter {
public:
static const size_t BUF_SIZE = 127;
explicit BinaryCharPrinter(Appender* a) : _n(0), _appender(a) {}
~BinaryCharPrinter() { Flush(); }
void PushChar(unsigned char c);
void Flush();
private:
uint32_t _n;
Appender* _appender;
char _buf[BUF_SIZE];
};
template <typename Appender>
void BinaryCharPrinter<Appender>::Flush() {
if (_n > 0) {
_appender->Append(_buf, _n);
_n = 0;
}
}
template <typename Appender>
void BinaryCharPrinter<Appender>::PushChar(unsigned char c) {
if (_n > BUF_SIZE - 3) {
_appender->Append(_buf, _n);
_n = 0;
}
if (c >= 32 && c <= 126) { // displayable ascii characters
if (c != '\\') {
_buf[_n++] = c;
} else {
_buf[_n++] = '\\';
_buf[_n++] = '\\';
}
} else {
_buf[_n++] = '\\';
switch (c) {
case '\b': _buf[_n++] = 'b'; break;
case '\t': _buf[_n++] = 't'; break;
case '\n': _buf[_n++] = 'n'; break;
case '\r': _buf[_n++] = 'r'; break;
default:
_buf[_n++] = s_binary_char_map[c >> 4];
_buf[_n++] = s_binary_char_map[c & 0xF];
break;
}
}
}
class OStreamAppender {
public:
OStreamAppender(std::ostream& os) : _os(&os) {}
void Append(const char* b, size_t n) { _os->write(b, n); }
private:
std::ostream* _os;
};
class StringAppender {
public:
StringAppender(std::string* str) : _str(str) {}
void Append(const char* b, size_t n) { _str->append(b, n); }
private:
std::string* _str;
};
template <typename Appender>
static void PrintIOBuf(Appender* appender, const IOBuf& b, size_t max_length) {
BinaryCharPrinter<Appender> printer(appender);
const size_t n = b.backing_block_num();
size_t nw = 0;
for (size_t i = 0; i < n; ++i) {
StringPiece blk = b.backing_block(i);
for (size_t j = 0; j < blk.size(); ++j) {
if (nw >= max_length) {
printer.Flush();
char buf[48];
int len = snprintf(buf, sizeof(buf), "...<skipping %" PRIu64 " bytes>",
(uint64_t)(b.size() - nw));
appender->Append(buf, len);
return;
}
++nw;
printer.PushChar(blk[j]);
}
}
}
template <typename Appender>
static void PrintString(Appender* appender, const StringPiece& s, size_t max_length) {
BinaryCharPrinter<Appender> printer(appender);
for (size_t i = 0; i < s.size(); ++i) {
if (i >= max_length) {
printer.Flush();
char buf[48];
int len = snprintf(buf, sizeof(buf), "...<skipping %" PRIu64 " bytes>",
(uint64_t)(s.size() - i));
appender->Append(buf, len);
return;
}
printer.PushChar(s[i]);
}
}
void ToPrintable::Print(std::ostream& os) const {
OStreamAppender appender(os);
if (_iobuf) {
PrintIOBuf(&appender, *_iobuf, _max_length);
} else if (!_str.empty()) {
PrintString(&appender, _str, _max_length);
}
}
std::string ToPrintableString(const IOBuf& data, size_t max_length) {
std::string result;
StringAppender appender(&result);
PrintIOBuf(&appender, data, max_length);
return result;
}
std::string ToPrintableString(const StringPiece& data, size_t max_length) {
std::string result;
StringAppender appender(&result);
PrintString(&appender, data, max_length);
return result;
}
std::string ToPrintableString(const void* data, size_t n, size_t max_length) {
std::string result;
StringAppender appender(&result);
PrintString(&appender, StringPiece((const char*)data, n), max_length);
return result;
}
} // namespace butil