redo hexDump
ludicrously inefficient (cf. toHex() ), and inflexible.
This commit is contained in:
@ -4,8 +4,6 @@
|
||||
* in file LICENSE that is included with this distribution.
|
||||
*/
|
||||
|
||||
#include <sstream>
|
||||
|
||||
#include <osiSock.h>
|
||||
|
||||
#include <pv/byteBuffer.h>
|
||||
@ -15,9 +13,6 @@
|
||||
#include <pv/remote.h>
|
||||
#include <pv/hexDump.h>
|
||||
|
||||
using std::ostringstream;
|
||||
using std::hex;
|
||||
|
||||
using namespace epics::pvData;
|
||||
|
||||
namespace epics {
|
||||
@ -44,13 +39,10 @@ void ResponseHandler::handleResponse(osiSockAddr* responseFrom,
|
||||
char ipAddrStr[48];
|
||||
ipAddrToDottedIP(&responseFrom->ia, ipAddrStr, sizeof(ipAddrStr));
|
||||
|
||||
ostringstream prologue;
|
||||
prologue<<"Message [0x"<<hex<<(int)command<<", v0x"<<hex;
|
||||
prologue<<(int)version<<"] received from "<<ipAddrStr<<" on "<<transport->getRemoteName();
|
||||
|
||||
hexDump(prologue.str(), _description,
|
||||
(const int8*)payloadBuffer->getArray(),
|
||||
payloadBuffer->getPosition(), static_cast<int>(payloadSize));
|
||||
std::cerr<<"Message [0x"<<std::hex<<(int)command<<", v0x"<<std::hex
|
||||
<<int(version)<<"] received from "<<ipAddrStr<<" on "<<transport->getRemoteName()
|
||||
<<" : "<<_description<<"\n"
|
||||
<<HexDump(*payloadBuffer, payloadSize);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -185,12 +185,6 @@ void AbstractCodec::processReadNormal() {
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
hexDump("Header", (const int8*)_socketBuffer.getArray(),
|
||||
_socketBuffer.getPosition(), PVA_MESSAGE_HEADER_SIZE);
|
||||
|
||||
*/
|
||||
|
||||
// read header fields
|
||||
processHeader();
|
||||
bool isControl = ((_flags & 0x01) == 0x01);
|
||||
@ -797,14 +791,6 @@ void AbstractCodec::send(ByteBuffer *buffer)
|
||||
//int p = buffer.position();
|
||||
int bytesSent = write(buffer);
|
||||
|
||||
/*
|
||||
if (IS_LOGGABLE(logLevelTrace)) {
|
||||
hexDump(std::string("AbstractCodec::send WRITE"),
|
||||
(const int8 *)buffer->getArray(),
|
||||
buffer->getPosition(), buffer->getRemaining());
|
||||
}
|
||||
*/
|
||||
|
||||
if (bytesSent < 0)
|
||||
{
|
||||
// connection lost
|
||||
@ -1302,13 +1288,6 @@ int BlockingTCPTransportCodec::read(epics::pvData::ByteBuffer* dst) {
|
||||
|
||||
// NOTE: do not log here, you might override SOCKERRNO relevant to recv() operation above
|
||||
|
||||
/*
|
||||
if (IS_LOGGABLE(logLevelTrace)) {
|
||||
hexDump(std::string("READ"),
|
||||
(const int8 *)(dst->getArray()+pos), bytesRead);
|
||||
}
|
||||
*/
|
||||
|
||||
if(unlikely(bytesRead<=0)) {
|
||||
|
||||
if (bytesRead<0)
|
||||
|
@ -2998,10 +2998,14 @@ public:
|
||||
{
|
||||
if (command < 0 || command >= (int8)m_handlerTable.size())
|
||||
{
|
||||
// TODO remove debug output
|
||||
char buf[100];
|
||||
sprintf(buf, "Invalid (or unsupported) command %d, its payload", command);
|
||||
hexDump(buf, (const int8*)(payloadBuffer->getArray()), payloadBuffer->getPosition(), payloadSize);
|
||||
LOG(logLevelError,
|
||||
"Invalid (or unsupported) command: %x.", (0xFF&command));
|
||||
|
||||
if(pvAccessIsLoggable(logLevelError)) {
|
||||
std::cerr<<"Invalid PVA header "<<hex<<(int)(0xFF&command)
|
||||
<<", its payload buffer\n"
|
||||
<<HexDump(*payloadBuffer, payloadSize);
|
||||
}
|
||||
return;
|
||||
}
|
||||
// delegate
|
||||
|
@ -155,16 +155,14 @@ void ServerResponseHandler::handleResponse(osiSockAddr* responseFrom,
|
||||
{
|
||||
if(command<0||command>=(int8)m_handlerTable.size())
|
||||
{
|
||||
LOG(logLevelDebug,
|
||||
LOG(logLevelError,
|
||||
"Invalid (or unsupported) command: %x.", (0xFF&command));
|
||||
|
||||
// TODO remove debug output
|
||||
std::ostringstream name;
|
||||
name<<"Invalid PVA header "<<hex<<(int)(0xFF&command);
|
||||
name<<", its payload buffer";
|
||||
|
||||
hexDump(name.str(), (const int8*)payloadBuffer->getArray(),
|
||||
payloadBuffer->getPosition(), payloadSize);
|
||||
if(pvAccessIsLoggable(logLevelError)) {
|
||||
std::cerr<<"Invalid PVA header "<<hex<<(int)(0xFF&command)
|
||||
<<", its payload buffer\n"
|
||||
<<HexDump(*payloadBuffer, payloadSize);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -7,102 +7,92 @@
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <iomanip>
|
||||
#include <algorithm>
|
||||
|
||||
#include <pv/byteBuffer.h>
|
||||
|
||||
#define epicsExportSharedSymbols
|
||||
#include <pv/hexDump.h>
|
||||
|
||||
using namespace epics::pvData;
|
||||
using std::string;
|
||||
using std::stringstream;
|
||||
using std::endl;
|
||||
using std::cout;
|
||||
|
||||
namespace epics {
|
||||
namespace pvAccess {
|
||||
|
||||
/// Byte to hexchar mapping.
|
||||
static const char lookup[] = {
|
||||
'0', '1', '2', '3', '4', '5', '6', '7',
|
||||
'8', '9', 'A', 'B', 'C', 'D', 'E', 'F'
|
||||
};
|
||||
HexDump::HexDump(const char* buf, size_t len)
|
||||
:buf(buf)
|
||||
,buflen(len)
|
||||
,_limit(1024u)
|
||||
,_groupBy(4u)
|
||||
,_perLine(16u)
|
||||
{}
|
||||
|
||||
/// Get hex representation of byte.
|
||||
string toHex(int8 b) {
|
||||
string sb;
|
||||
|
||||
int upper = (b>>4)&0x0F;
|
||||
sb += lookup[upper];
|
||||
|
||||
int lower = b&0x0F;
|
||||
sb += lookup[lower];
|
||||
|
||||
sb += ' ';
|
||||
|
||||
return sb;
|
||||
HexDump::HexDump(const pvData::ByteBuffer& bb,
|
||||
size_t size, size_t offset)
|
||||
:buf(bb.getBuffer() + bb.getPosition())
|
||||
,buflen(bb.getRemaining())
|
||||
,_limit((size_t)-1)
|
||||
,_groupBy(4u)
|
||||
,_perLine(16u)
|
||||
{
|
||||
if(offset > buflen)
|
||||
offset = buflen;
|
||||
buf += offset;
|
||||
buflen -= offset;
|
||||
if(buflen > size)
|
||||
buflen = size;
|
||||
}
|
||||
|
||||
/// Get ASCII representation of byte, dot if non-readable.
|
||||
char toAscii(int8 b) {
|
||||
if(b>(int8)31&&b<(int8)127)
|
||||
return (char)b;
|
||||
else
|
||||
return '.';
|
||||
HexDump::~HexDump() {}
|
||||
|
||||
static
|
||||
size_t ilog2(size_t val)
|
||||
{
|
||||
size_t ret = 0;
|
||||
while(val >>= 1)
|
||||
ret++;
|
||||
return ret;
|
||||
}
|
||||
|
||||
void hexDump(std::string const & name, const int8 *bs, int len) {
|
||||
hexDump(name, bs, 0, len);
|
||||
static
|
||||
size_t bits2bytes(size_t val)
|
||||
{
|
||||
// round up to next multiple of 8
|
||||
val -= 1u;
|
||||
val |= 7u;
|
||||
val += 1u;
|
||||
// bits -> bytes
|
||||
val /= 8u;
|
||||
return val;
|
||||
}
|
||||
|
||||
void hexDump(std::string const & name, const int8 *bs, int start, int len) {
|
||||
hexDump("", name, bs, start, len);
|
||||
}
|
||||
epicsShareFunc
|
||||
std::ostream& operator<<(std::ostream& strm, const HexDump& hex)
|
||||
{
|
||||
size_t len = std::min(hex.buflen, hex._limit);
|
||||
// find address width in hex chars
|
||||
// find bit width, rounded up to 8 bits, divide down to bytes
|
||||
size_t addrwidth = bits2bytes(ilog2(len))*2u;
|
||||
|
||||
void hexDump(std::string const & prologue, string const & name, const int8 *bs,
|
||||
int start, int len) {
|
||||
for(size_t i=0; i<len; i++)
|
||||
{
|
||||
unsigned val = hex.buf[i]&0xff;
|
||||
size_t col = i%hex._perLine;
|
||||
|
||||
stringstream header;
|
||||
|
||||
header<<prologue<<endl<<"Hexdump ["<<name<<"] size = "<<len;
|
||||
|
||||
string out(header.str());
|
||||
|
||||
string chars;
|
||||
|
||||
for(int i = start; i<(start+len); i++) {
|
||||
if(((i-start)%16)==0) {
|
||||
out += chars;
|
||||
out += '\n';
|
||||
chars.erase();
|
||||
if(col==0) {
|
||||
// first address of this row
|
||||
strm<<"0x"<<std::hex<<std::setw(addrwidth)<<std::setfill('0')<<i;
|
||||
}
|
||||
|
||||
chars += toAscii(bs[i]);
|
||||
|
||||
out += toHex(bs[i]);
|
||||
|
||||
if(((i-start)%4)==3) {
|
||||
chars += ' ';
|
||||
out += ' ';
|
||||
if(col%hex._groupBy == 0) {
|
||||
strm<<' ';
|
||||
}
|
||||
strm<<std::hex<<std::setw(2)<<std::setfill('0')<<val;
|
||||
if(col+1u==hex._perLine && i+1u!=len)
|
||||
strm<<'\n';
|
||||
}
|
||||
|
||||
if(len%16!=0) {
|
||||
int pad = 0;
|
||||
int delta_bytes = 16-(len%16);
|
||||
|
||||
//rest of line (no of bytes)
|
||||
//each byte takes two chars plus one ws
|
||||
pad = delta_bytes*3;
|
||||
|
||||
//additional whitespaces after four bytes
|
||||
pad += (delta_bytes/4);
|
||||
pad++;
|
||||
|
||||
for(int i = 0; i<pad; i++)
|
||||
chars.insert(0, " ");
|
||||
}
|
||||
|
||||
out += chars;
|
||||
cout<<out<<endl;
|
||||
if(len==hex._limit && len<hex.buflen)
|
||||
strm<<" ...";
|
||||
strm<<'\n';
|
||||
return strm;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -7,6 +7,8 @@
|
||||
#ifndef HEXDUMP_H_
|
||||
#define HEXDUMP_H_
|
||||
|
||||
#include <ostream>
|
||||
|
||||
#ifdef epicsExportSharedSymbols
|
||||
# define hexDumpEpicsExportSharedSymbols
|
||||
# undef epicsExportSharedSymbols
|
||||
@ -22,35 +24,34 @@
|
||||
#include <shareLib.h>
|
||||
|
||||
namespace epics {
|
||||
namespace pvData {
|
||||
class ByteBuffer;
|
||||
}
|
||||
namespace pvAccess {
|
||||
|
||||
/**
|
||||
* Output a buffer in hex format.
|
||||
* @param name name (description) of the message.
|
||||
* @param bs buffer to dump
|
||||
* @param len first bytes (length) to dump.
|
||||
*/
|
||||
epicsShareFunc void hexDump(std::string const & name, const epics::pvData::int8 *bs, int len);
|
||||
class epicsShareClass HexDump {
|
||||
const char* buf;
|
||||
size_t buflen;
|
||||
size_t _limit;
|
||||
unsigned _groupBy;
|
||||
unsigned _perLine;
|
||||
public:
|
||||
HexDump(const char* buf, size_t len);
|
||||
explicit HexDump(const pvData::ByteBuffer& buf, size_t size=(size_t)-1, size_t offset=0u);
|
||||
~HexDump();
|
||||
|
||||
/**
|
||||
* Output a buffer in hex format.
|
||||
* @param[in] name name (description) of the message.
|
||||
* @param[in] bs buffer to dump
|
||||
* @param[in] start dump message using given offset.
|
||||
* @param[in] len first bytes (length) to dump.
|
||||
*/
|
||||
epicsShareFunc void hexDump(std::string const & name, const epics::pvData::int8 *bs, int start, int len);
|
||||
//! safety limit on max bytes printed
|
||||
inline HexDump& limit(size_t n=(size_t)-1) { _limit = n; return *this; }
|
||||
//! insert a space after this many bytes
|
||||
inline HexDump& bytesPerGroup(size_t n=(size_t)-1) { _groupBy = n; return *this; }
|
||||
//! start a new line after this many bytes
|
||||
inline HexDump& bytesPerLine(size_t n=(size_t)-1) { _perLine = n; return *this; }
|
||||
|
||||
/**
|
||||
* Output a buffer in hex format.
|
||||
* @param[in] prologue string to prefixed to debug output, can be <code>null</code>
|
||||
* @param[in] name name (description) of the message.
|
||||
* @param[in] bs buffer to dump
|
||||
* @param[in] start dump message using given offset.
|
||||
* @param[in] len first bytes (length) to dump.
|
||||
*/
|
||||
epicsShareFunc void hexDump(std::string const & prologue, std::string const & name,
|
||||
const epics::pvData::int8 *bs, int start, int len);
|
||||
friend std::ostream& operator<<(std::ostream& strm, const HexDump& hex);
|
||||
};
|
||||
|
||||
epicsShareFunc
|
||||
std::ostream& operator<<(std::ostream& strm, const HexDump& hex);
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,9 @@
|
||||
#include <epicsUnitTest.h>
|
||||
|
||||
#include <sstream>
|
||||
|
||||
#include <testMain.h>
|
||||
|
||||
#include <pv/pvUnitTest.h>
|
||||
#include <pv/hexDump.h>
|
||||
|
||||
using namespace epics::pvData;
|
||||
@ -8,19 +11,16 @@ using namespace epics::pvAccess;
|
||||
|
||||
MAIN(testHexDump)
|
||||
{
|
||||
testPlan(3);
|
||||
testPlan(1);
|
||||
testDiag("Tests for hexDump");
|
||||
|
||||
char TO_DUMP[] = "pvAccess dump test\0\1\2\3\4\5\6\254\255\256";
|
||||
char TO_DUMP[] = "pvAccess dump test\0\1\2\3\4\5\6\xfd\xfe\xff";
|
||||
|
||||
hexDump("test", (int8*)TO_DUMP, 18+9);
|
||||
testPass("Entire array");
|
||||
std::ostringstream msg;
|
||||
msg<<HexDump(TO_DUMP, sizeof(TO_DUMP)-1);
|
||||
|
||||
hexDump("only text", (int8*)TO_DUMP, 18);
|
||||
testPass("Only text");
|
||||
|
||||
hexDump("22 byte test", (int8*)TO_DUMP, 22);
|
||||
testPass("22 bytes test");
|
||||
testEqual(msg.str(), "0x00 70764163 63657373 2064756d 70207465\n"
|
||||
"0x10 73740001 02030405 06fdfeff\n");
|
||||
|
||||
return testDone();
|
||||
}
|
||||
|
Reference in New Issue
Block a user