fix simple encoding
This commit is contained in:
parent
fd2ebfd6cc
commit
1a9b7effa6
@ -43,34 +43,44 @@ func StripCRC(buffer []byte) []byte {
|
||||
return buffer[:len(buffer)-2]
|
||||
}
|
||||
|
||||
// Compress compresses packet data using zlib (matches EQ compression)
|
||||
// Compress compresses packet data using zlib or simple encoding (matches C++ EQProtocolPacket::Compress)
|
||||
// Uses zlib for packets > 30 bytes, simple encoding for smaller packets
|
||||
func Compress(src []byte) ([]byte, error) {
|
||||
if len(src) == 0 {
|
||||
return src, nil
|
||||
}
|
||||
|
||||
var buf bytes.Buffer
|
||||
// C++ uses 30 bytes as threshold between simple encoding and zlib
|
||||
if len(src) > 30 {
|
||||
// Use zlib compression for larger packets
|
||||
var buf bytes.Buffer
|
||||
|
||||
// Write uncompressed length first (4 bytes) - EQ protocol requirement
|
||||
if err := binary.Write(&buf, binary.BigEndian, uint32(len(src))); err != nil {
|
||||
return nil, err
|
||||
// Write uncompressed length first (4 bytes) - EQ protocol requirement
|
||||
if err := binary.Write(&buf, binary.BigEndian, uint32(len(src))); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Compress the data
|
||||
w := zlib.NewWriter(&buf)
|
||||
if _, err := w.Write(src); err != nil {
|
||||
w.Close()
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err := w.Close(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return buf.Bytes(), nil
|
||||
}
|
||||
|
||||
// Compress the data
|
||||
w := zlib.NewWriter(&buf)
|
||||
if _, err := w.Write(src); err != nil {
|
||||
w.Close()
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err := w.Close(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return buf.Bytes(), nil
|
||||
// Use simple encoding for smaller packets (just return data as-is)
|
||||
// The 0xa5 flag is added by the caller, not here
|
||||
return src, nil
|
||||
}
|
||||
|
||||
// Decompress decompresses packet data using zlib
|
||||
// This is called after the compression flag has already been checked and removed
|
||||
func Decompress(src []byte) ([]byte, error) {
|
||||
if len(src) < 4 {
|
||||
return nil, fmt.Errorf("compressed data too small")
|
||||
@ -100,6 +110,110 @@ func Decompress(src []byte) ([]byte, error) {
|
||||
return decompressed, nil
|
||||
}
|
||||
|
||||
// CompressPacket adds compression with proper flag handling (matches C++ EQProtocolPacket::Compress)
|
||||
// Uses zlib (0x5a) for packets > 30 bytes, simple encoding (0xa5) for smaller packets
|
||||
func CompressPacket(buffer []byte) ([]byte, error) {
|
||||
if len(buffer) < 2 {
|
||||
return buffer, nil
|
||||
}
|
||||
|
||||
// Determine flag offset based on opcode size
|
||||
flagOffset := 1
|
||||
if buffer[0] == 0x00 {
|
||||
flagOffset = 2 // Two-byte opcode
|
||||
}
|
||||
|
||||
if len(buffer) <= flagOffset {
|
||||
return buffer, nil // Too small to compress
|
||||
}
|
||||
|
||||
// Get data to compress (after opcode)
|
||||
dataToCompress := buffer[flagOffset:]
|
||||
|
||||
// Choose compression method based on size (C++ uses 30 byte threshold)
|
||||
if len(dataToCompress) > 30 {
|
||||
// Use zlib compression
|
||||
compressed, err := Compress(dataToCompress)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Only use if compression actually reduced size
|
||||
if len(compressed) < len(dataToCompress) {
|
||||
result := make([]byte, flagOffset+1+len(compressed))
|
||||
copy(result[:flagOffset], buffer[:flagOffset]) // Copy opcode
|
||||
result[flagOffset] = 0x5a // Zlib flag
|
||||
copy(result[flagOffset+1:], compressed) // Compressed data
|
||||
return result, nil
|
||||
}
|
||||
} else {
|
||||
// Use simple encoding - just add flag
|
||||
result := make([]byte, len(buffer)+1)
|
||||
copy(result[:flagOffset], buffer[:flagOffset]) // Copy opcode
|
||||
result[flagOffset] = 0xa5 // Simple encoding flag
|
||||
copy(result[flagOffset+1:], dataToCompress) // Original data
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// No compression if it doesn't help
|
||||
return buffer, nil
|
||||
}
|
||||
|
||||
// DecompressPacket handles decompression with flag checking (matches C++ EQProtocolPacket::Decompress)
|
||||
// Supports both zlib compression (0x5a) and simple encoding (0xa5)
|
||||
func DecompressPacket(buffer []byte) ([]byte, error) {
|
||||
if len(buffer) < 3 {
|
||||
return buffer, nil // Too small to be compressed
|
||||
}
|
||||
|
||||
// Determine flag offset based on opcode size
|
||||
flagOffset := uint32(1)
|
||||
if buffer[0] == 0x00 {
|
||||
flagOffset = 2 // Two-byte opcode
|
||||
}
|
||||
|
||||
if uint32(len(buffer)) <= flagOffset {
|
||||
return buffer, nil // No room for compression flag
|
||||
}
|
||||
|
||||
compressionFlag := buffer[flagOffset]
|
||||
|
||||
// Check compression type
|
||||
if compressionFlag == 0x5a {
|
||||
// Zlib compression
|
||||
// Decompress data after flag, excluding last 2 CRC bytes
|
||||
dataStart := flagOffset + 1
|
||||
dataEnd := uint32(len(buffer)) - 2
|
||||
if dataEnd <= dataStart {
|
||||
return nil, fmt.Errorf("invalid compressed packet size")
|
||||
}
|
||||
|
||||
decompressed, err := Decompress(buffer[dataStart:dataEnd])
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("zlib decompression failed: %w", err)
|
||||
}
|
||||
|
||||
// Rebuild packet: opcode + decompressed data + CRC
|
||||
result := make([]byte, flagOffset+uint32(len(decompressed))+2)
|
||||
copy(result[:flagOffset], buffer[:flagOffset]) // Copy opcode
|
||||
copy(result[flagOffset:], decompressed) // Copy decompressed data
|
||||
// Copy CRC bytes
|
||||
result[len(result)-2] = buffer[len(buffer)-2]
|
||||
result[len(result)-1] = buffer[len(buffer)-1]
|
||||
|
||||
return result, nil
|
||||
} else if compressionFlag == 0xa5 {
|
||||
// Simple encoding - just remove the encoding flag
|
||||
result := make([]byte, len(buffer)-1)
|
||||
copy(result[:flagOffset], buffer[:flagOffset]) // Copy opcode
|
||||
copy(result[flagOffset:], buffer[flagOffset+1:]) // Skip flag, copy rest
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// No compression
|
||||
return buffer, nil
|
||||
}
|
||||
|
||||
// ChatEncode encodes chat data using EQ's XOR-based encoding
|
||||
func ChatEncode(buffer []byte, encodeKey int) {
|
||||
if len(buffer) == 0 || encodeKey == 0 {
|
||||
|
@ -189,7 +189,7 @@ func (p *ProtoPacket) IsCompressed() bool {
|
||||
return p.eq2Compressed
|
||||
}
|
||||
|
||||
// EQ2Compress compresses packet data (matches EQStream::EQ2_Compress)
|
||||
// EQ2Compress compresses packet data (matches EQStream::EQ2_Compress and C++ EQProtocolPacket::Compress)
|
||||
func (p *ProtoPacket) EQ2Compress(offset int8) int8 {
|
||||
if offset <= 0 || int(offset) >= len(p.Buffer) {
|
||||
return 0
|
||||
@ -197,28 +197,53 @@ func (p *ProtoPacket) EQ2Compress(offset int8) int8 {
|
||||
|
||||
// Compress data from offset onwards
|
||||
dataToCompress := p.Buffer[offset:]
|
||||
compressed, err := Compress(dataToCompress)
|
||||
if err != nil || len(compressed) >= len(dataToCompress) {
|
||||
return 0 // Compression failed or didn't reduce size
|
||||
dataLen := len(dataToCompress)
|
||||
|
||||
// C++ uses 30 bytes as threshold - match this exactly
|
||||
if dataLen > 30 {
|
||||
// Use zlib compression for larger packets
|
||||
compressed, err := Compress(dataToCompress)
|
||||
if err != nil || len(compressed) >= dataLen {
|
||||
return 0 // Compression failed or didn't reduce size
|
||||
}
|
||||
|
||||
// Rebuild buffer with zlib compression flag (0x5a)
|
||||
newSize := int(offset) + len(compressed)
|
||||
newBuffer := make([]byte, newSize)
|
||||
|
||||
// Copy header bytes before offset
|
||||
copy(newBuffer[:offset], p.Buffer[:offset])
|
||||
|
||||
// Set zlib compression flag at offset-1
|
||||
newBuffer[offset-1] = 0x5a
|
||||
|
||||
// Copy compressed data
|
||||
copy(newBuffer[offset:], compressed)
|
||||
|
||||
p.Buffer = newBuffer
|
||||
p.eq2Compressed = true
|
||||
|
||||
return offset - 1 // Return compression flag position
|
||||
} else {
|
||||
// Use simple encoding for smaller packets (0xa5)
|
||||
// Simple encoding just adds a flag, doesn't change data
|
||||
newSize := len(p.Buffer) + 1
|
||||
newBuffer := make([]byte, newSize)
|
||||
|
||||
// Copy header bytes before offset
|
||||
copy(newBuffer[:offset], p.Buffer[:offset])
|
||||
|
||||
// Set simple encoding flag at offset-1
|
||||
newBuffer[offset-1] = 0xa5
|
||||
|
||||
// Copy data after flag (shift by 1 byte)
|
||||
copy(newBuffer[offset:], p.Buffer[offset-1:])
|
||||
|
||||
p.Buffer = newBuffer
|
||||
p.eq2Compressed = true
|
||||
|
||||
return offset - 1 // Return compression flag position
|
||||
}
|
||||
|
||||
// Rebuild buffer with compression flag
|
||||
newSize := int(offset) + len(compressed)
|
||||
newBuffer := make([]byte, newSize)
|
||||
|
||||
// Copy header bytes before offset
|
||||
copy(newBuffer[:offset], p.Buffer[:offset])
|
||||
|
||||
// Set compression flag at offset-1
|
||||
newBuffer[offset-1] = 1 // Compression flag
|
||||
|
||||
// Copy compressed data
|
||||
copy(newBuffer[offset:], compressed)
|
||||
|
||||
p.Buffer = newBuffer
|
||||
p.eq2Compressed = true
|
||||
|
||||
return offset - 1 // Return compression flag position
|
||||
}
|
||||
|
||||
// EncryptPacket encrypts packet data (matches EQStream::EncryptPacket)
|
||||
@ -431,11 +456,35 @@ func (p *ProtoPacket) AppCombine(rhs *ProtoPacket) bool {
|
||||
|
||||
// MakeApplicationPacket converts to app packet (matches EQProtocolPacket::MakeApplicationPacket)
|
||||
func (p *ProtoPacket) MakeApplicationPacket(opcodeSize uint8) *AppPacket {
|
||||
// Decompress if needed
|
||||
if p.eq2Compressed {
|
||||
if decompressed, err := Decompress(p.Buffer); err == nil {
|
||||
p.Buffer = decompressed
|
||||
p.eq2Compressed = false
|
||||
// Decompress if needed - handle both zlib and simple encoding
|
||||
if p.eq2Compressed && len(p.Buffer) > 2 {
|
||||
// Check compression type at position 2 (after sequence bytes)
|
||||
compressionFlag := byte(0)
|
||||
if len(p.Buffer) > 2 {
|
||||
compressionFlag = p.Buffer[2]
|
||||
}
|
||||
|
||||
if compressionFlag == 0x5a {
|
||||
// Zlib compression - decompress data after flag
|
||||
if len(p.Buffer) > 3 {
|
||||
if decompressed, err := Decompress(p.Buffer[3:]); err == nil {
|
||||
// Rebuild buffer without compression
|
||||
newBuffer := make([]byte, 2+len(decompressed))
|
||||
copy(newBuffer[:2], p.Buffer[:2]) // Copy sequence
|
||||
copy(newBuffer[2:], decompressed)
|
||||
p.Buffer = newBuffer
|
||||
p.eq2Compressed = false
|
||||
}
|
||||
}
|
||||
} else if compressionFlag == 0xa5 {
|
||||
// Simple encoding - just remove the flag
|
||||
if len(p.Buffer) > 3 {
|
||||
newBuffer := make([]byte, len(p.Buffer)-1)
|
||||
copy(newBuffer[:2], p.Buffer[:2]) // Copy sequence
|
||||
copy(newBuffer[2:], p.Buffer[3:]) // Skip flag
|
||||
p.Buffer = newBuffer
|
||||
p.eq2Compressed = false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user