Добавление строки или массива char в байтовый вектор - PullRequest
1 голос
/ 28 апреля 2010

В настоящее время я работаю над классом для создания и считывания пакетов, отправляемых через сеть, до сих пор он работает с 16-битными и 8-битными целыми числами (ну без знака, но все же).

Теперь проблема в том, что я перепробовал множество способов скопировать его, но каким-то образом _buffer был искажен, он поврежден или результат был неправильным.

Буду признателен, если кто-нибудь покажет мне рабочий пример.

Мой текущий код можно увидеть ниже.

Спасибо, Xeross

Главная

#include <iostream>
#include <stdio.h>
#include "Packet.h"

using namespace std;

int main(int argc, char** argv)
{
    cout << "#################################" << endl;
    cout << "#       Internal Use Only       #" << endl;
    cout << "#     Codename PACKETSTORM      #" << endl;
    cout << "#################################" << endl;
    cout << endl;

    Packet packet = Packet();
    packet.SetOpcode(0x1f4d);

    cout << "Current opcode is: " << packet.GetOpcode() << endl << endl;

    packet.add(uint8_t(5))
          .add(uint16_t(4000))
          .add(uint8_t(5));

    for(uint8_t i=0; i<10;i++)
        printf("Byte %u = %x\n", i, packet._buffer[i]);

    printf("\nReading them out: \n1 = %u\n2 = %u\n3 = %u\n4 = %s",
        packet.readUint8(),
        packet.readUint16(),
        packet.readUint8());

    return 0;
}

Packet.h

#ifndef _PACKET_H_
#define _PACKET_H_

#include <iostream>
#include <vector>

#include <stdio.h>
#include <stdint.h>
#include <string.h>

using namespace std;

class Packet
{
    public:
        Packet() : m_opcode(0), _buffer(0), _wpos(0), _rpos(0) {}
        Packet(uint16_t opcode) : m_opcode(opcode), _buffer(0), _wpos(0), _rpos(0) {}

        uint16_t GetOpcode() { return m_opcode; }
        void SetOpcode(uint16_t opcode) { m_opcode = opcode; }

        Packet& add(uint8_t value)
        {
            if(_buffer.size() < _wpos + 1)
                _buffer.resize(_wpos + 1);

            memcpy(&_buffer[_wpos], &value, 1);
            _wpos += 1;

            return *this;
        }
        Packet& add(uint16_t value)
        {
            if(_buffer.size() < _wpos + 2)
                _buffer.resize(_wpos + 2);

            memcpy(&_buffer[_wpos], &value, 2);
            _wpos += 2;

            return *this;
        }

        uint8_t readUint8()
        {
            uint8_t result = _buffer[_rpos];
            _rpos += sizeof(uint8_t);
            return result;
        }
        uint16_t readUint16()
        {
            uint16_t result;
            memcpy(&result, &_buffer[_rpos], sizeof(uint16_t));

            _rpos += sizeof(uint16_t);
            return result;

        }

        uint16_t m_opcode;
        std::vector<uint8_t> _buffer;
    protected:

        size_t _wpos; // Write position
        size_t _rpos; // Read position
};

#endif // _PACKET_H_

Ответы [ 3 ]

5 голосов
/ 28 апреля 2010

Поскольку вы используете std :: vector для своего буфера, вы можете также позволить ему отслеживать саму позицию записи и избегать необходимости вручную изменять его размер. Вы также можете избежать записи нескольких перегрузок функции добавления, используя шаблон функции:

template <class T>
Packet& add(T value) {
    std::copy((uint8_t*) &value, ((uint8_t*) &value) + sizeof(T), std::back_inserter(_buffer));
    return *this;
}

Теперь вы можете записать любой тип POD в ваш буфер.

неявно:

int i = 5;
o.write(i);

или явно:

o.write<int>(5);

Для чтения из буфера вам необходимо отслеживать позицию чтения:

template <class T>
T read() {
    T result;
    uint8_t *p = &_buffer[_rpos];
    std::copy(p, p + sizeof(T), (uint8_t*) &result);
    _rpos += sizeof(T);
    return result;
}

Вам нужно будет явно передать параметр типа для чтения. т.е.

int i = o.read<int>();

Предостережение: я часто использовал этот шаблон, но, поскольку я набираю его на макушке, в коде могут быть несколько ошибок.

Редактировать: Я только что заметил, что вы хотите иметь возможность добавлять строки или другие не POD-типы в ваш буфер. Вы можете сделать это через специализацию шаблона:

template <>
Packet& add(std::string s) {
    add(string.length());
    for (size_t i = 0; i < string.length(); ++i)
        add(string[i]);
    return *this;
}

Это говорит компилятору: если add вызывается со строковым типом, используйте эту функцию вместо универсальной функции add ().

и прочитать строку:

template <>
std::string read<>() {
    size_t len = read<size_t>();
    std::string s;
    while (len--)
        s += read<char>();
    return s;
}
1 голос
/ 28 апреля 2010

Вы можете использовать std::string в качестве внутреннего буфера и использовать append () при добавлении новых элементов.

Таким образом, добавление строк или const char * будет тривиальным.

Добавление / запись uint8 можно выполнить путем приведения его к типу char, записи uint16 - к типу * с длиной sizeof (uint16_t).

void write_uint16( uint16_t val )
{
    m_strBuffer.append( (char*)(&var), sizeof(val) );
}

Чтение uint16:

uint16_t read_int16()
{
    return ( *(uint16_t*)(m_strBuffer.c_str() + m_nOffset) );
}
0 голосов
/ 28 апреля 2010

Вы, кажется, пытаетесь распечатать десять байтов из буфера, когда вы только добавили четыре, и, таким образом, вы бежите от конца вектора. Это может быть причиной вашей ошибки сегмента.

Также ваш printf пытается напечатать символ в виде целого без знака с% x. Вам нужно использовать static_cast<unsigned>(packet._buffer[i]) в качестве параметра.

Стилистически: Packet packet = Packet(); потенциально может привести к созданию двух объектов. Просто используйте Packet packet;

Обычно старайтесь избегать защищенных атрибутов (защищенные методы хороши), поскольку они уменьшают инкапсуляцию вашего класса.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...