166 lines
4.8 KiB
C++
166 lines
4.8 KiB
C++
// 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
|