eq2go/old/common/packet/packet_dump.hpp
2025-08-06 19:00:30 -05:00

190 lines
4.9 KiB
C++

// Copyright (C) 2007 EQ2EMulator Development Team - GNU GPL v3+ License
#pragma once
#include <iostream>
#include <iomanip>
#include <cstdio>
#include <cstring>
#include "eq_packet.hpp"
#include "../debug.hpp"
#include "../types.hpp"
#include "../servertalk.hpp"
#include "../stream/eq_stream.hpp"
using namespace std;
class ServerPacket;
// Function declarations
void DumpPacketAscii(const uchar* buf, int32 size, int32 cols = 16, int32 skip = 0);
void DumpPacketHex(const uchar* buf, int32 size, int32 cols = 16, int32 skip = 0);
void DumpPacketBin(const void* data, int32 len);
void DumpPacket(const uchar* buf, int32 size);
void DumpPacket(const ServerPacket* pack, bool iShowInfo = false);
void DumpPacketBin(const ServerPacket* pack);
void DumpPacketBin(int32 data);
void DumpPacketBin(int16 data);
void DumpPacketBin(int8 data);
// Outputs packet buffer as ASCII characters with formatted columns
// Non-printable characters are displayed as dots
void DumpPacketAscii(const uchar* buf, int32 size, int32 cols, int32 skip)
{
for(int32 i = skip; i < size; i++) {
if ((i - skip) % cols == 0) {
cout << endl << setw(3) << setfill(' ') << i - skip << ":";
}
else if ((i - skip) % (cols / 2) == 0) {
cout << " - ";
}
if (buf[i] > 32 && buf[i] < 127) {
cout << buf[i];
}
else {
cout << '.';
}
}
cout << endl << endl;
}
// Outputs packet buffer as hexadecimal with ASCII representation sidebar
// Includes offset addresses and formatted column layout
void DumpPacketHex(const uchar* buf, int32 size, int32 cols, int32 skip)
{
if (size == 0 || size > 39565)
return;
char output[4];
int j = 0;
auto ascii = std::make_unique<char[]>(cols + 1);
memset(ascii.get(), 0, cols + 1);
int32 i;
for(i = skip; i < size; i++) {
if ((i - skip) % cols == 0) {
if (i != skip)
cout << " | " << ascii.get() << endl;
cout << setw(4) << setfill(' ') << i - skip << ": ";
memset(ascii.get(), 0, cols + 1);
j = 0;
}
else if ((i - skip) % (cols / 2) == 0) {
cout << "- ";
}
sprintf(output, "%02X ", static_cast<unsigned char>(buf[i]));
cout << output;
if (buf[i] >= 32 && buf[i] < 127) {
ascii[j++] = buf[i];
}
else {
ascii[j++] = '.';
}
}
int32 k = ((i - skip) - 1) % cols;
if (k < 8)
cout << " ";
for (int32 h = k + 1; h < cols; h++) {
cout << " ";
}
cout << " | " << ascii.get() << endl;
}
// Simple wrapper to dump packet in hexadecimal format
void DumpPacket(const uchar* buf, int32 size)
{
DumpPacketHex(buf, size);
}
// Dumps ServerPacket with optional header information display
// Shows opcode and size when iShowInfo is true
void DumpPacket(const ServerPacket* pack, bool iShowInfo)
{
if (iShowInfo) {
cout << "Dumping ServerPacket: 0x" << hex << setfill('0') << setw(4) << pack->opcode << dec;
cout << " size:" << pack->size << endl;
}
DumpPacketHex(pack->pBuffer, pack->size);
}
// Wrapper to dump ServerPacket buffer in binary format
void DumpPacketBin(const ServerPacket* pack)
{
DumpPacketBin(pack->pBuffer, pack->size);
}
// Dumps 32-bit integer in binary format
void DumpPacketBin(int32 data)
{
DumpPacketBin(reinterpret_cast<const uchar*>(&data), sizeof(int32));
}
// Dumps 16-bit integer in binary format
void DumpPacketBin(int16 data)
{
DumpPacketBin(reinterpret_cast<const uchar*>(&data), sizeof(int16));
}
// Dumps 8-bit integer in binary format
void DumpPacketBin(int8 data)
{
DumpPacketBin(reinterpret_cast<const uchar*>(&data), sizeof(int8));
}
// Outputs data buffer in binary format with hexadecimal values sidebar
// Each byte is displayed as 8 binary digits with offset addressing
void DumpPacketBin(const void* iData, int32 len)
{
if (!len)
return;
const int8* data = static_cast<const int8*>(iData);
int32 k = 0;
for (k = 0; k < len; k++) {
if (k % 4 == 0) {
if (k != 0) {
cout << " | " << hex << setw(2) << setfill('0') << static_cast<int>(data[k-4]) << dec;
cout << " " << hex << setw(2) << setfill('0') << static_cast<int>(data[k-3]) << dec;
cout << " " << hex << setw(2) << setfill('0') << static_cast<int>(data[k-2]) << dec;
cout << " " << hex << setw(2) << setfill('0') << static_cast<int>(data[k-1]) << dec;
cout << endl;
}
cout << setw(4) << setfill('0') << k << ":";
}
else if (k % 2 == 0)
cout << " ";
cout << " ";
// Output each bit of the byte
for (int bit = 0; bit < 8; bit++) {
cout << ((data[k] & (1 << bit)) ? "1" : "0");
}
}
// Handle final line formatting
int8 tmp = (k % 4);
if (!tmp)
tmp = 4;
if (tmp <= 3)
cout << " ";
if (tmp <= 2)
cout << " ";
if (tmp <= 1)
cout << " ";
cout << " | " << hex << setw(2) << setfill('0') << static_cast<int>(data[k-4]) << dec;
if (tmp > 1)
cout << " " << hex << setw(2) << setfill('0') << static_cast<int>(data[k-3]) << dec;
if (tmp > 2)
cout << " " << hex << setw(2) << setfill('0') << static_cast<int>(data[k-2]) << dec;
if (tmp > 3)
cout << " " << hex << setw(2) << setfill('0') << static_cast<int>(data[k-1]) << dec;
cout << endl;
}