From fce0efcfc2043aedac7d68cd927622cf26892ce8 Mon Sep 17 00:00:00 2001 From: false_genesis Date: Thu, 27 Mar 2008 23:53:17 +0000 Subject: [PATCH] * updated+fixed object update. (still not working on ascent) * added conf option "DumpPackets" to dump wrong packets for later analysis --- bin/conf/PseuWoW.conf.default | 10 +++ src/Client/PseuWoW.cpp | 1 + src/Client/PseuWoW.h | 1 + src/Client/World/MovementMgr.h | 35 ++------- src/Client/World/UpdateData.cpp | 125 ++++++++++++++++++++---------- src/Client/World/UpdateData.h | 81 ++++++++++++++++--- src/Client/World/WorldSession.cpp | 65 +++++++++++++++- src/Client/World/WorldSession.h | 1 + src/shared/tools.cpp | 8 +- src/shared/tools.h | 2 +- 10 files changed, 245 insertions(+), 84 deletions(-) diff --git a/bin/conf/PseuWoW.conf.default b/bin/conf/PseuWoW.conf.default index 6b298dc..8b4fc01 100644 --- a/bin/conf/PseuWoW.conf.default +++ b/bin/conf/PseuWoW.conf.default @@ -122,4 +122,14 @@ useMaps=0 // Sometimes they even cause problems, like make the console window beep... SkipAddonChat=1 +// Dump invalid packets or those which caused an error/exception for further analyis. +// Directory is "./packetdumps/" +// Note that packet dumps are valid for 1 session only, the counter gets reset when the WorldSession is destroyed. +// This means they get overwritten if not saved! +// 0 - no packet dumping +// 1 - dump packets that caused an excpetion or object update error +// 2 - like [1] + all packets with opcodes not handled by the core +// (doesn't matter if they have scripts attached or not, they will be dumped always) +DumpPackets=1 + diff --git a/src/Client/PseuWoW.cpp b/src/Client/PseuWoW.cpp index ec78072..36cc55b 100644 --- a/src/Client/PseuWoW.cpp +++ b/src/Client/PseuWoW.cpp @@ -414,6 +414,7 @@ void PseuInstanceConf::ApplyFromVarSet(VarSet &v) rmcontrolhost=v.Get("RMCONTROLHOST"); useMaps=(bool)atoi(v.Get("USEMAPS").c_str()); skipaddonchat=(bool)atoi(v.Get("SKIPADDONCHAT").c_str()); + dumpPackets=(uint8)atoi(v.Get("DUMPPACKETS").c_str()); // clientversion is a bit more complicated to add { diff --git a/src/Client/PseuWoW.h b/src/Client/PseuWoW.h index 90c11a9..ba1f1a8 100644 --- a/src/Client/PseuWoW.h +++ b/src/Client/PseuWoW.h @@ -56,6 +56,7 @@ class PseuInstanceConf std::string rmcontrolhost; bool useMaps; bool skipaddonchat; + uint8 dumpPackets; // gui related bool enablegui; diff --git a/src/Client/World/MovementMgr.h b/src/Client/World/MovementMgr.h index d98d50c..8b5a5b8 100644 --- a/src/Client/World/MovementMgr.h +++ b/src/Client/World/MovementMgr.h @@ -2,39 +2,16 @@ #define MOVEMENTMGR_H #include "common.h" +#include "UpdateData.h" #define MOVE_HEARTBEAT_DELAY 500 -enum MovementFlags -{ - MOVEMENTFLAG_NONE = 0x00000000, - MOVEMENTFLAG_FORWARD = 0x00000001, - MOVEMENTFLAG_BACKWARD = 0x00000002, - MOVEMENTFLAG_STRAFE_LEFT = 0x00000004, - MOVEMENTFLAG_STRAFE_RIGHT = 0x00000008, - MOVEMENTFLAG_LEFT = 0x00000010, - MOVEMENTFLAG_RIGHT = 0x00000020, - MOVEMENTFLAG_PITCH_UP = 0x00000040, - MOVEMENTFLAG_PITCH_DOWN = 0x00000080, - MOVEMENTFLAG_WALK = 0x00000100, - MOVEMENTFLAG_ONTRANSPORT = 0x00000200, - MOVEMENTFLAG_UNK1 = 0x00000400, - MOVEMENTFLAG_FLY_UNK1 = 0x00000800, - MOVEMENTFLAG_JUMPING = 0x00001000, - MOVEMENTFLAG_UNK4 = 0x00002000, - MOVEMENTFLAG_FALLING = 0x00004000, - // 0x8000, 0x10000, 0x20000, 0x40000, 0x80000, 0x100000 - MOVEMENTFLAG_SWIMMING = 0x00200000, // appears with fly flag also - MOVEMENTFLAG_FLY_UP = 0x00400000, - MOVEMENTFLAG_CAN_FLY = 0x00800000, - MOVEMENTFLAG_FLYING = 0x01000000, - MOVEMENTFLAG_UNK5 = 0x02000000, - MOVEMENTFLAG_SPLINE = 0x04000000, // probably wrong name - MOVEMENTFLAG_SPLINE2 = 0x08000000, - MOVEMENTFLAG_WATERWALKING = 0x10000000, - MOVEMENTFLAG_SAFE_FALL = 0x20000000, // active rogue safe fall spell (passive) - MOVEMENTFLAG_UNK3 = 0x40000000, +// -- +// -- MovementFlags and MovementInfo can be found in UpdateData.h +// -- +enum MovementFlagsEx +{ // custom flags MOVEMENTFLAG_ANY_MOVE = (MOVEMENTFLAG_BACKWARD | MOVEMENTFLAG_FORWARD | MOVEMENTFLAG_STRAFE_LEFT | MOVEMENTFLAG_STRAFE_RIGHT | MOVEMENTFLAG_LEFT | MOVEMENTFLAG_RIGHT) diff --git a/src/Client/World/UpdateData.cpp b/src/Client/World/UpdateData.cpp index ef8cb55..f64231b 100644 --- a/src/Client/World/UpdateData.cpp +++ b/src/Client/World/UpdateData.cpp @@ -37,10 +37,11 @@ void WorldSession::_HandleCompressedUpdateObjectOpcode(WorldPacket& recvPacket) void WorldSession::_HandleUpdateObjectOpcode(WorldPacket& recvPacket) { uint8 utype; - uint8 unk8; + uint8 hasTransport; uint32 usize, ublocks; uint64 uguid; - recvPacket >> ublocks >> unk8; + recvPacket >> ublocks >> hasTransport; + logdev("UpdateObject: hasTransport = %u", hasTransport); while(recvPacket.rpos() < recvPacket.size()) { recvPacket >> utype; @@ -210,6 +211,16 @@ void WorldSession::_HandleUpdateObjectOpcode(WorldPacket& recvPacket) logerror("UPDATE_OBJECT: Got unk updatetype 0x%X",utype); logerror("UPDATE_OBJECT: Read %u / %u bytes, skipped rest",recvPacket.rpos(),recvPacket.size()); logerror("%s",toHexDump((uint8*)recvPacket.contents(),recvPacket.size(),true).c_str()); + char buf[100]; + sprintf(buf,"Got unk updatetype=0x%X, read %u / %u bytes",utype,recvPacket.rpos(),recvPacket.size()); + + if(GetInstance()->GetConf()->dumpPackets) + { + char buf[100]; + sprintf(buf,"Got unk updatetype=0x%X, read %u / %u bytes",utype,recvPacket.rpos(),recvPacket.size()); + DumpPacket(recvPacket, recvPacket.rpos(),buf); + } + return; } } // switch @@ -219,66 +230,94 @@ void WorldSession::_HandleUpdateObjectOpcode(WorldPacket& recvPacket) void WorldSession::_MovementUpdate(uint8 objtypeid, uint64 uguid, WorldPacket& recvPacket) { - uint8 flags,unk8; - uint32 unk32,flags2,time,transtime,higuid; - float unkfx,unkfy,unkfz,x,y,z,o,tx,ty,tz,to; - uint64 transguid; + MovementInfo mi; // TODO: use a reference to a MovementInfo in Unit/Player class once implemented + uint8 flags; + float unkfx,unkfy,unkfz; // uint64 fullguid; // see below float speedWalk, speedRun, speedSwimBack, speedSwim, speedWalkBack, speedTurn, speedFly, speedFlyBack; + uint32 unk32; Object *obj = (Object*)objmgr.GetObj(uguid); - Unit *u = (Unit*)obj; // only use for Unit:: functions!! - - recvPacket >> flags; - flags2 = 0; // not sure if its correct to set it to 0 (needs some starting flag?) - - if(flags & UPDATEFLAG_LIVING) + Unit *u = NULL; + if(obj) { - recvPacket >> flags2 >> unk8 >> time; + if(obj->IsUnit()) + u = (Unit*)obj; // only use for Unit:: functions!! + else + logdev("MovementUpdate: object "I64FMT" is not Unit (typeId=%u)",obj->GetGUID(),obj->GetTypeId()); + } + else + { + logerror("MovementUpdate for unknown object "I64FMT" typeid=%u",uguid,objtypeid); } - logdev("MovementUpdate TypeID=%u GUID="I64FMT" pObj=%X flags=%u flags2=%u",objtypeid,uguid,obj,flags,flags2); + recvPacket >> flags; + + mi.flags = 0; // not sure if its correct to set it to 0 (needs some starting flag?) + if(flags & UPDATEFLAG_LIVING) + { + recvPacket >> mi.flags >> mi.unk1 >> mi.time; + } + else + { + logdev("MovementUpdate: UPDATEFLAG_LIVING *NOT* set! (no MovementInfo)"); + } + + logdev("MovementUpdate: TypeID=%u GUID="I64FMT" pObj=%X flags=%u mi.flags=%u",objtypeid,uguid,obj,flags,mi.flags); if(flags & UPDATEFLAG_HASPOSITION) { if(flags & UPDATEFLAG_TRANSPORT) { - recvPacket >> unkfx >> unkfy >> unkfz >> o; // 3x (float)0 followed by orientation - logdev("TRANSPORT_FLOATS @ flags: x=%f y=%f z=%f o=%f",unkfx,unkfy,unkfz,o); + recvPacket >> unkfx >> unkfy >> unkfz >> mi.o; // 3x (float)0 followed by orientation + logdev("TRANSPORT_FLOATS @ flags: x=%f y=%f z=%f o=%f", unkfx, unkfy, unkfz, mi.o); } else { - recvPacket >> x >> y >> z >> o; - logdev("FLOATS: x=%f y=%f z=%f o=%f",x,y,z,o); + recvPacket >> mi.x >> mi.y >> mi.z >> mi.o; + logdev("FLOATS: x=%f y=%f z=%f o=%f",mi.x, mi.y, mi.z ,mi.o); if(obj->IsWorldObject()) - ((WorldObject*)obj)->SetPosition(x,y,z,o); + ((WorldObject*)obj)->SetPosition(mi.x, mi.y, mi.z, mi.o); } } if(flags & UPDATEFLAG_LIVING) { - if(flags2 & FLAGS2_TRANSPORT) + if(mi.flags & MOVEMENTFLAG_ONTRANSPORT) { - recvPacket >> transguid >> tx >> ty >> tz >> to; - recvPacket >> unk32; // added in 2.0.3 - logdev("TRANSPORT_FLOATS @ flags2: x=%f y=%f z=%f o=%f",tx,ty,tz,to); + recvPacket >> mi.t_guid >> mi.t_x >> mi.t_y >> mi.t_z >> mi.t_o; + recvPacket >> mi.t_time; // added in 2.0.3 + logdev("TRANSPORT @ mi.flags: guid="I64FMT" x=%f y=%f z=%f o=%f", mi.t_guid, mi.t_x, mi.t_y, mi.t_z, mi.t_o); } - recvPacket >> unk32; + if(mi.flags & (MOVEMENTFLAG_SWIMMING | MOVEMENTFLAG_UNK5)) + { + recvPacket >> mi.s_angle; + logdev("MovementUpdate: MOVEMENTFLAG_SWIMMING is set, angle = %f!", mi.s_angle); + } - /* - // not sure if this is/was correct, MaNGOS doesnt use it anymore - if(flags2 & 0x2000) // 0x2000 = ?? - { - recvPacket >> unkf >> unkf >> unkf >> unkf; - } - */ + recvPacket >> mi.fallTime; + logdev("MovementUpdate: FallTime = %u", mi.fallTime); - recvPacket >> speedWalk >> speedRun >> speedSwimBack >> speedSwim; + if(mi.flags & MOVEMENTFLAG_JUMPING) + { + recvPacket >> mi.j_unk >> mi.j_sinAngle >> mi.j_cosAngle >> mi.j_xyspeed; + logdev("MovementUpdate: MOVEMENTFLAG_JUMPING is set, unk=%f sinA=%f cosA=%f xyspeed=%f = %u", mi.j_unk, mi.j_sinAngle, mi.j_cosAngle, mi.j_xyspeed); + } + + if(mi.flags & MOVEMENTFLAG_SPLINE) + { + recvPacket >> mi.u_unk1; + logdev("MovementUpdate: MOVEMENTFLAG_SPLINE is set, got %u", mi.u_unk1); + } + + + recvPacket >> speedWalk >> speedRun >> speedSwimBack >> speedSwim; // speedRun can also be mounted speed if player is mounted recvPacket >> speedWalkBack >> speedFly >> speedFlyBack >> speedTurn; // fly added in 2.0.x + logdev("MovementUpdate: Got speeds, walk=%f run=%f turn=%f", speedWalk, speedRun, speedTurn); if(u) { - u->SetPosition(x,y,z,o); + u->SetPosition(mi.x, mi.y, mi.z, mi.o); u->SetSpeed(MOVE_WALK,speedWalk); u->SetSpeed(MOVE_RUN,speedRun); u->SetSpeed(MOVE_SWIMBACK,speedSwimBack); @@ -288,33 +327,39 @@ void WorldSession::_MovementUpdate(uint8 objtypeid, uint64 uguid, WorldPacket& r u->SetSpeed(MOVE_FLY,speedFly); u->SetSpeed(MOVE_FLYBACK,speedFlyBack); } - else + + // TODO: correct this one as soon as its meaning is known OR if it appears often and needs to be fixed + if(mi.flags & MOVEMENTFLAG_SPLINE2) { - logerror("WorldSession::_MovementUpdate for unknown guid "I64FMT" typeid=%u",uguid,objtypeid); + logerror("MovementUpdate: MOVEMENTFLAG_SPLINE2 is set, if you see this message please report it!"); + return; } } - if(flags & UPDATEFLAG_ALL) + if(flags & UPDATEFLAG_LOWGUID) { recvPacket >> unk32; + logdev("MovementUpdate: UPDATEFLAG_LOWGUID is set, got %X", unk32); } if(flags & UPDATEFLAG_HIGHGUID) { - recvPacket >> higuid; // 2.0.6 - high guid was there, unk for 2.0.12 + recvPacket >> unk32; // 2.0.6 - high guid was there, unk for 2.0.12 // not sure if this is correct, MaNGOS sends 0 always. //obj->SetUInt32Value(OBJECT_FIELD_GUID+1,higuid); // note that this sets only the high part of the guid + logdev("MovementUpdate: UPDATEFLAG_HIGHGUID is set, got %X", unk32); } if(flags & UPDATEFLAG_FULLGUID) { - // unused in mangos? but what if its needed? - // recvPacket >> fullguid; + uint64 unkguid = recvPacket.GetPackedGuid(); // MaNGOS sends uint8(0) always, but its probably be a packed guid + logdev("MovementUpdate: UPDATEFLAG_FULLGUID is set, got "I64FMT, unkguid); } if(flags & UPDATEFLAG_TRANSPORT) { - recvPacket >> transtime; // whats this used for? + recvPacket >> unk32; // whats this used for? + logdev("MovementUpdate: UPDATEFLAG_TRANSPORT is set, got %u", unk32); } } diff --git a/src/Client/World/UpdateData.h b/src/Client/World/UpdateData.h index 3ba895b..f13401f 100644 --- a/src/Client/World/UpdateData.h +++ b/src/Client/World/UpdateData.h @@ -13,20 +13,79 @@ enum OBJECT_UPDATE_TYPE enum OBJECT_UPDATE_FLAGS { - UPDATEFLAG_SELF = 0x01, - UPDATEFLAG_TRANSPORT = 0x02, - UPDATEFLAG_FULLGUID = 0x04, - UPDATEFLAG_HIGHGUID = 0x08, - UPDATEFLAG_ALL = 0x10, - UPDATEFLAG_LIVING = 0x20, - UPDATEFLAG_HASPOSITION = 0x40 + UPDATEFLAG_NONE = 0x00, + UPDATEFLAG_SELF = 0x01, + UPDATEFLAG_TRANSPORT = 0x02, + UPDATEFLAG_FULLGUID = 0x04, + UPDATEFLAG_LOWGUID = 0x08, + UPDATEFLAG_HIGHGUID = 0x10, + UPDATEFLAG_LIVING = 0x20, + UPDATEFLAG_HASPOSITION = 0x40 }; -// not sure about those flags, mangos hasnt a description for it either -enum FLAGS2_UPDATE_FLAGS +enum MovementFlags { - FLAGS2_TRANSPORT = 0x200, - FLAGS2_SPIRITHEALER = 0x10000000, + MOVEMENTFLAG_NONE = 0x00000000, + MOVEMENTFLAG_FORWARD = 0x00000001, + MOVEMENTFLAG_BACKWARD = 0x00000002, + MOVEMENTFLAG_STRAFE_LEFT = 0x00000004, + MOVEMENTFLAG_STRAFE_RIGHT = 0x00000008, + MOVEMENTFLAG_LEFT = 0x00000010, + MOVEMENTFLAG_RIGHT = 0x00000020, + MOVEMENTFLAG_PITCH_UP = 0x00000040, + MOVEMENTFLAG_PITCH_DOWN = 0x00000080, + MOVEMENTFLAG_WALK = 0x00000100, + MOVEMENTFLAG_ONTRANSPORT = 0x00000200, + MOVEMENTFLAG_UNK1 = 0x00000400, + MOVEMENTFLAG_FLY_UNK1 = 0x00000800, + MOVEMENTFLAG_JUMPING = 0x00001000, + MOVEMENTFLAG_UNK4 = 0x00002000, + MOVEMENTFLAG_FALLING = 0x00004000, + // 0x8000, 0x10000, 0x20000, 0x40000, 0x80000, 0x100000 + MOVEMENTFLAG_SWIMMING = 0x00200000, // appears with fly flag also + MOVEMENTFLAG_FLY_UP = 0x00400000, + MOVEMENTFLAG_CAN_FLY = 0x00800000, + MOVEMENTFLAG_FLYING = 0x01000000, + MOVEMENTFLAG_UNK5 = 0x02000000, + MOVEMENTFLAG_SPLINE = 0x04000000, // probably wrong name + MOVEMENTFLAG_SPLINE2 = 0x08000000, + MOVEMENTFLAG_WATERWALKING = 0x10000000, + MOVEMENTFLAG_SAFE_FALL = 0x20000000, // active rogue safe fall spell (passive) + MOVEMENTFLAG_UNK3 = 0x40000000 +}; + +struct MovementInfo +{ + // common + uint32 flags; + uint8 unk1; + uint32 time; + float x, y, z, o; + // transport + uint64 t_guid; + float t_x, t_y, t_z, t_o; + uint32 t_time; + // swimming and unk + float s_angle; + // last fall time + uint32 fallTime; + // jumping + float j_unk, j_sinAngle, j_cosAngle, j_xyspeed; + // spline + float u_unk1; + + MovementInfo() + { + flags = time = t_time = fallTime = 0; + unk1 = 0; + x = y = z = o = t_x = t_y = t_z = t_o = s_angle = j_unk = j_sinAngle = j_cosAngle = j_xyspeed = u_unk1 = 0.0f; + t_guid = 0; + } + + void SetMovementFlags(uint32 _flags) + { + flags = _flags; + } }; bool IsFloatField(uint8, uint32); diff --git a/src/Client/World/WorldSession.cpp b/src/Client/World/WorldSession.cpp index 86cb965..eb13b83 100644 --- a/src/Client/World/WorldSession.cpp +++ b/src/Client/World/WorldSession.cpp @@ -189,6 +189,11 @@ void WorldSession::HandleWorldPacket(WorldPacket *packet) logcustom(1,YELLOW,">> Opcode %u [%s] (%s, %u bytes)", packet->GetOpcode(), GetOpcodeName(packet->GetOpcode()), (known ? (disabledOpcode ? "Disabled" : "Known") : "UNKNOWN"), packet->size()); } + if( (!known) && GetInstance()->GetConf()->dumpPackets > 1) + { + DumpPacket(*packet); + } + try { // if there is a script attached to that opcode, call it now. @@ -213,14 +218,18 @@ void WorldSession::HandleWorldPacket(WorldPacket *packet) } catch (ByteBufferException bbe) { + char errbuf[200]; + sprintf(errbuf,"attempt to \"%s\" %u bytes at position %u out of total %u bytes. (wpos=%u)", bbe.action, bbe.readsize, bbe.rpos, bbe.cursize, bbe.wpos); logerror("Exception while handling opcode %u [%s]!",packet->GetOpcode(),GetOpcodeName(packet->GetOpcode())); logerror("WorldSession: ByteBufferException"); - logerror("ByteBuffer reported: attempt to \"%s\" %u bytes at position %u out of total %u bytes. (wpos=%u)", - bbe.action, bbe.readsize, bbe.rpos, bbe.cursize, bbe.wpos); + logerror("ByteBuffer reported: %s", errbuf); // copied from below logerror("Data: pktsize=%u, handler=0x%X queuesize=%u",packet->size(),table[hpos].handler,pktQueue.size()); logerror("Packet Hexdump:"); logerror("%s",toHexDump((uint8*)packet->contents(),packet->size(),true).c_str()); + + if(GetInstance()->GetConf()->dumpPackets) + DumpPacket(*packet, bbe.rpos, errbuf); } catch (...) { @@ -228,6 +237,9 @@ void WorldSession::HandleWorldPacket(WorldPacket *packet) logerror("Data: pktsize=%u, handler=0x%X queuesize=%u",packet->size(),table[hpos].handler,pktQueue.size()); logerror("Packet Hexdump:"); logerror("%s",toHexDump((uint8*)packet->contents(),packet->size(),true).c_str()); + + if(GetInstance()->GetConf()->dumpPackets) + DumpPacket(*packet, packet->rpos(), "unknown exception"); } delete packet; @@ -367,6 +379,55 @@ void WorldSession::_DoTimedActions(void) } } +std::string WorldSession::DumpPacket(WorldPacket& pkt, int errpos, char *errstr) +{ + static std::map opstore; + std::stringstream s; + s << "TIMESTAMP: " << getDateString() << "\n"; + s << "OPCODE: " << pkt.GetOpcode() << " " << GetOpcodeName(pkt.GetOpcode()) << "\n"; + s << "SIZE: " << pkt.size() << "\n"; + if(errpos > 0) + s << "ERROR-AT: " << errpos << "\n"; + if(errstr) + s << "ERROR: " << errstr << "\n"; + if(pkt.size()) + { + s << "DATA-HEX:\n"; + s << toHexDump((uint8*)pkt.contents(),pkt.size(),true,32); + s << "\n"; + + s << "DATA-TEXT:\n"; + for(uint32 i = 0; i < pkt.size(); i++) + { + s << (isprint(pkt[i]) ? (char)pkt[i] : '.'); + if((i+1) % 32 == 0) + s << "\n"; + } + s << "\n"; + + } + s << "\n"; + + CreateDir("packetdumps"); + if(opstore.find(pkt.GetOpcode()) == opstore.end()) + opstore[pkt.GetOpcode()] = 0; + else + opstore[pkt.GetOpcode()]++; + std::fstream fh; + std::stringstream fn; + fn << "./packetdumps/" << GetOpcodeName(pkt.GetOpcode()) << "_" << opstore[pkt.GetOpcode()] << ".txt"; + fh.open(fn.str().c_str(), std::ios_base::out); + if(!fh.is_open()) + { + logerror("Packet dump failed! (%s)",fn.str().c_str()); + return fn.str(); + } + fh << s.str(); + fh.close(); + logdetail("Packet successfully dumped to '%s'", fn.str().c_str()); + return fn.str(); +} + std::string WorldSession::GetOrRequestPlayerName(uint64 guid) { if(!guid || GUID_HIPART(guid) != HIGHGUID_PLAYER) diff --git a/src/Client/World/WorldSession.h b/src/Client/World/WorldSession.h index fea4680..e5636ec 100644 --- a/src/Client/World/WorldSession.h +++ b/src/Client/World/WorldSession.h @@ -71,6 +71,7 @@ public: inline World *GetWorld(void) { return _world; } std::string GetOrRequestPlayerName(uint64); + std::string DumpPacket(WorldPacket& pkt, int errpos = -1, char *errstr = NULL); // CMSGConstructor diff --git a/src/shared/tools.cpp b/src/shared/tools.cpp index d95b976..cea1532 100644 --- a/src/shared/tools.cpp +++ b/src/shared/tools.cpp @@ -87,7 +87,7 @@ uint64 toInt(std::string str) return strtoul(str.c_str(),NULL,10); } -std::string toHexDump(uint8* array,uint32 size,bool spaces) +std::string toHexDump(uint8* array, uint32 size, bool spaces, uint32 per_line) { std::stringstream ss; char buf[5]; @@ -101,6 +101,12 @@ std::string toHexDump(uint8* array,uint32 size,bool spaces) else ss << "00"; // little hacklike fix + if(per_line && !((i+1) % per_line)) + { + ss << "\n"; + continue; + } + if(spaces) ss << ' '; } diff --git a/src/shared/tools.h b/src/shared/tools.h index 0e7ee8a..2266888 100644 --- a/src/shared/tools.h +++ b/src/shared/tools.h @@ -14,7 +14,7 @@ std::string stringToLower(std::string); std::string toString(uint64); std::string getDateString(void); uint64 toInt(std::string); -std::string toHexDump(uint8* array,uint32 size,bool spaces=true); +std::string toHexDump(uint8* array,uint32 size,bool spaces=true,uint32 per_line=0); std::deque GetFileList(std::string); bool FileExists(std::string); bool CreateDir(const char*);