3
\$\begingroup\$

I am doing a research to implement a dynamic system of parse and generation of fixed width flat files in C++....

The system works, but, it is not reliable ...

The class "FlatFileStructure", holds all the informations about the field in particular, such as position on the line, size, type of field (numeric, alpha-numeric and date) and keeps the variable pointer where the information that should be written to the file will be, or that will be read from the file

Like in this line:

_descricaoCamposHeader->push_back(new FlatFileStructure(0, 1, TipoDoCampo::NUMERICO, "0", &_header->tipoDoRegistro));

the biggest problem exists, in the case of the information stored in the vectors "_descricaoCamposTitulo" and "_descricaoCamposTituloMensagens", where there can be N lines referring to this record within the file

On the method "void geraArquivo()", I do a 'memcpy' to send all the data to the '_titulo' variable, so, in this way, the system can save the data on the file...

My question is ... what can I do to make this code better and more secure and without burdening the memory? my first attempt, for each instance of the 'model' class, I created a copy of the vector that contains the variable pointer, so it worked perfectly but the memory consumption was very high

#include <iostream>
#include <vector>
#include <string>
#include <memory>
#include <cstring>
#include <fstream>
#include <ctime>

#include "stringutil.h"
//#include "Datetime/datetimehelper.h"

typedef enum
{
    ALFANUMERICO,
    NUMERICO,
    NUMERICO_SEQUENCIAL,
    DATA
} TipoDoCampo;

template<typename T>
struct deleter : std::unary_function<const T*, void>
{
    void operator() (const T* ptr) const
    {
        if (ptr != nullptr)
        {
            delete ptr;
            ptr = nullptr;
        }
    }
};

class FlatFileStructure
{
private:
    size_t _inicialPosition;
    size_t _size;
    TipoDoCampo _tipoDoCampo;
    std::string _defaultContent;
    std::string* _content;

public:
    FlatFileStructure(size_t inicialPosition, size_t size, TipoDoCampo tipoDoCampo)
        : _inicialPosition(inicialPosition),
        _size(size),
        _tipoDoCampo(tipoDoCampo)
    {}

    FlatFileStructure(size_t inicialPosition, size_t size, TipoDoCampo tipoDoCampo, std::string defaultContent)
        : _inicialPosition(inicialPosition),
        _size(size),
        _tipoDoCampo(tipoDoCampo),
        _defaultContent(defaultContent)
    {}

    FlatFileStructure(size_t inicialPosition, size_t size, TipoDoCampo tipoDoCampo, std::string* content)
        : _inicialPosition(inicialPosition),
        _size(size),
        _tipoDoCampo(tipoDoCampo),
        _content(content)
    {
    }

    FlatFileStructure(size_t inicialPosition, size_t size, TipoDoCampo tipoDoCampo, std::string defaultContent, std::string* content)
        : _inicialPosition(inicialPosition),
        _size(size),
        _tipoDoCampo(tipoDoCampo),
        _defaultContent(defaultContent),
        _content(content)
    {
    }

    size_t getPosicaoInicial() { return _inicialPosition; }
    size_t getsize() { return _size; }
    TipoDoCampo getTipoDoCampo() { return _tipoDoCampo; }

    std::string getcontent()
    {
        if (!_defaultContent.empty())
            return _defaultContent;

        return std::string(*_content);
    }

    std::string getcontentFormatado()
    {
        if (_content->empty())
            *_content = "";

        std::string content = this->getcontent();

        if (_tipoDoCampo == TipoDoCampo::ALFANUMERICO)
        {
            if (content.size() > _size)
                content = util::truncate(content, _size);

            content = util::pad_right(content, _size, ' ');
        }

        else if (_tipoDoCampo == TipoDoCampo::NUMERICO || _tipoDoCampo == TipoDoCampo::NUMERICO_SEQUENCIAL)
        {
            if (content.size() > _size)
                content = util::truncate_numeric(content, _size);

            content = util::pad_left(content, _size, '0');
        }

        //else if (_tipoDoCampo == TipoDoCampo::DATA)
        //{
        //    if (content.empty())
        //        content = dragonfly::DateTimeHelper::hoje("%d%m%y");
        //    else
        //        content = dragonfly::DateTimeHelper::formataData_de_para(content, "%d.%m.%Y", "%d%m%y");
        //}

        return content;
    }

    void setcontent(std::string content)
    {
        *_content = std::string(content);
    }
};

class FlatFile
{
private:
    size_t _lineSize;

public:
    FlatFile(size_t lineSize) : _lineSize(lineSize) {}

    std::string buildLine(std::vector<FlatFileStructure*>* campos)
    {
        std::string str = util::pad_left("", _lineSize, ' ');

        for (int i = 0; i < campos->size(); i++)
        {
            FlatFileStructure* ffs = (*campos)[i];

            std::string content = ffs->getcontentFormatado();
            //str = str.replace(ffs->getPosicaoInicial(), content.size(), content.c_str());
            strncpy(&str[ffs->getPosicaoInicial()], content.c_str(), content.size());
        }

        return std::string(str);
    }

    void readLine(std::string line, std::vector<FlatFileStructure*>* campos)
    {
        for (int i = 0; i < campos->size(); i++)
        {
            FlatFileStructure* ffs = (*campos)[i];
            std::string content = line.substr(ffs->getPosicaoInicial(), ffs->getsize());
            ffs->setcontent(content);
        }
    }
};

class ArquivoDeTeste
{
private:
    class Header
    {
    public:
        std::string tipoDoRegistro;
        std::string identificacaoDaRemessa;
        std::string literalRemessa;
        std::string codigoDeServico;
        std::string literalServico;
        std::string codigoDaEmpresa;
        std::string nomeDaEmpresa;
        std::string numeroDoBanco;
        std::string nomeDoBanco;
        std::string dataDeGravacao;
        std::string identificacaoDoSistema;
        std::string numeroSequencialDaRemessa;
        std::string sequencial;
    };

    class TituloMensagens
    {
    public:
        std::string tipoDoRegistro;
        std::string mensagem1;
        std::string mensagem2;
        std::string sequencial;
    };

    class Titulo
    {
    public:
        std::string tipoDoRegistro;
        std::string nossoNumero;
        std::string dvNossoNumero;
        std::string nomePagador;
        std::string sequencial;

        TituloMensagens mensagens;
    };

    Header* _header;
    Titulo* _titulo;
    std::vector<Titulo*>* _titulos;


    std::vector<FlatFileStructure*>* _descricaoCamposTituloMensagens;
    std::vector<FlatFileStructure*>* _descricaoCamposHeader;
    std::vector<FlatFileStructure*>* _descricaoCamposTitulo;

public:
    ArquivoDeTeste()
        : _header(new Header()),
          _titulo(new Titulo()),
          _titulos(nullptr)
    {
        inicializaDescricaoCamposHeader();
        inicializaDescricaoCamposTitulo();
        inicializaDescricaoCamposTituloMensagens();
    }

    ~ArquivoDeTeste() 
    {
        if (_header != nullptr)
        {
            delete _header;
            _header = nullptr;
        }

        if (_titulo != nullptr)
        {
            delete _titulo;
            _titulo = nullptr;
        }

        std::for_each(_descricaoCamposHeader->begin(), _descricaoCamposHeader->end(), deleter<FlatFileStructure>());
        _descricaoCamposHeader->clear();
        delete _descricaoCamposHeader;

        std::for_each(_descricaoCamposTituloMensagens->begin(), _descricaoCamposTituloMensagens->end(), deleter<FlatFileStructure>());
        _descricaoCamposTituloMensagens->clear();
        delete _descricaoCamposTituloMensagens;

        std::for_each(_descricaoCamposTitulo->begin(), _descricaoCamposTitulo->end(), deleter<FlatFileStructure>());
        _descricaoCamposTitulo->clear();
        delete _descricaoCamposTitulo;

        std::for_each(_titulos->begin(), _titulos->end(), deleter<Titulo>());
        _titulos->clear();
        delete _titulos;

    }

private:
    void inicializaDescricaoCamposHeader()
    {
        _descricaoCamposHeader = new std::vector<FlatFileStructure*>();
        _descricaoCamposHeader->push_back(new FlatFileStructure(0, 1, TipoDoCampo::NUMERICO, "0", &_header->tipoDoRegistro));
        _descricaoCamposHeader->push_back(new FlatFileStructure(1, 1, TipoDoCampo::NUMERICO, "1", &_header->identificacaoDaRemessa));
        _descricaoCamposHeader->push_back(new FlatFileStructure(2, 7, TipoDoCampo::ALFANUMERICO, "REMESSA", &_header->literalRemessa));
        _descricaoCamposHeader->push_back(new FlatFileStructure(9, 2, TipoDoCampo::NUMERICO, "01", &_header->codigoDeServico));
        _descricaoCamposHeader->push_back(new FlatFileStructure(11, 15, TipoDoCampo::ALFANUMERICO, "COBRANCA", &_header->literalServico));
        _descricaoCamposHeader->push_back(new FlatFileStructure(26, 20, TipoDoCampo::NUMERICO, &_header->codigoDaEmpresa));
        _descricaoCamposHeader->push_back(new FlatFileStructure(46, 30, TipoDoCampo::ALFANUMERICO, &_header->nomeDaEmpresa));
        _descricaoCamposHeader->push_back(new FlatFileStructure(76, 3, TipoDoCampo::NUMERICO, "999", &_header->numeroDoBanco));
        _descricaoCamposHeader->push_back(new FlatFileStructure(79, 15, TipoDoCampo::ALFANUMERICO, "XXXXXXXX", &_header->nomeDoBanco));
        //_descricaoCamposHeader->push_back(new FlatFileStructure(94, 6, TipoDoCampo::DATA, &_header->dataDeGravacao));
        _descricaoCamposHeader->push_back(new FlatFileStructure(108, 2, TipoDoCampo::ALFANUMERICO, "ZZ", &_header->identificacaoDoSistema));
        _descricaoCamposHeader->push_back(new FlatFileStructure(110, 7, TipoDoCampo::NUMERICO, &_header->numeroSequencialDaRemessa));
        _descricaoCamposHeader->push_back(new FlatFileStructure(394, 6, TipoDoCampo::NUMERICO_SEQUENCIAL, "000001", &_header->sequencial));
    }

    void inicializaDescricaoCamposTitulo()
    {
        _descricaoCamposTitulo = new std::vector<FlatFileStructure*>();
        _descricaoCamposTitulo->push_back(new FlatFileStructure(0, 1, TipoDoCampo::NUMERICO, "1", &_titulo->tipoDoRegistro));
        _descricaoCamposTitulo->push_back(new FlatFileStructure(70, 11, TipoDoCampo::NUMERICO, &_titulo->nossoNumero));
        _descricaoCamposTitulo->push_back(new FlatFileStructure(81, 1, TipoDoCampo::ALFANUMERICO, &_titulo->dvNossoNumero));
        _descricaoCamposTitulo->push_back(new FlatFileStructure(234, 40, TipoDoCampo::ALFANUMERICO, &_titulo->nomePagador));
        _descricaoCamposTitulo->push_back(new FlatFileStructure(394, 6, TipoDoCampo::NUMERICO_SEQUENCIAL, &_titulo->sequencial));
    }

    void inicializaDescricaoCamposTituloMensagens()
    {
        _descricaoCamposTituloMensagens = new std::vector<FlatFileStructure*>();
        _descricaoCamposTituloMensagens->push_back(new FlatFileStructure( 0,  1, TipoDoCampo::NUMERICO, "2", &_titulo->mensagens.tipoDoRegistro));
        _descricaoCamposTituloMensagens->push_back(new FlatFileStructure( 1, 80, TipoDoCampo::ALFANUMERICO, &_titulo->mensagens.mensagem1));
        _descricaoCamposTituloMensagens->push_back(new FlatFileStructure(81, 80, TipoDoCampo::ALFANUMERICO, &_titulo->mensagens.mensagem2));
        _descricaoCamposTituloMensagens->push_back(new FlatFileStructure(394, 6, TipoDoCampo::NUMERICO_SEQUENCIAL, &_titulo->mensagens.sequencial));
    }

public:
    void parseArquivo()
    {
        std::unique_ptr<FlatFile> ff(new FlatFile(400));

        std::string line;
        std::ifstream infile("out.rem");

        bool registroProcessado = false;
        while (std::getline(infile, line))
        {
            switch (line[0])
            {
            case '0':
                break;
            case '1':
                {
                    if (_titulos == nullptr)
                        _titulos = new std::vector<Titulo*>();

                    if (registroProcessado == true)
                    {
                        _titulos->push_back(new Titulo(*_titulo));
                        registroProcessado = false;
                        memset(_titulo, '\0', sizeof(Titulo));
                    }

                    ff->readLine(line, _descricaoCamposTitulo);
                    registroProcessado = true;
                }
                break;
            case '2':
                {
                    ff->readLine(line, _descricaoCamposTituloMensagens);
                    break;
                }
            case '9':
                _titulos->push_back(new Titulo(*_titulo));
                break;
            default:
                break;
            }
        }
    }

    void geraArquivo()
    {
        // Gera os titulos
        if (_titulos == nullptr)
            _titulos = new std::vector<Titulo*>();

        for (int i = 2; i <= 100; i++)
        {
            auto tmpTitulo = new Titulo();

            if (i % 2 == 0)
            {
                tmpTitulo->nossoNumero = "1234567891";
                tmpTitulo->nomePagador = "AAAAAAAAAABBBBBBBBBBCCCCCCCCCCDDDDDDDDDDEEEEEEEEEEFFFFFFFFFF";
                tmpTitulo->mensagens.mensagem1 = "Ola " + util::to_string<std::string, int>(i);
                tmpTitulo->mensagens.mensagem2 = "Ola " + util::to_string<std::string, int>(i + 1);
            }
            else
            {
                tmpTitulo->nossoNumero = "1213141516";
                tmpTitulo->nomePagador = "FFFFFFFFFFEEEEEEEEEEDDDDDDDDDDCCCCCCCCCCBBBBBBBBBBAAAAAAAAAA";
            }

            _titulos->push_back(tmpTitulo);
        }

        std::ofstream outputFile("out.rem");

        std::unique_ptr<FlatFile> ff(new FlatFile(400));

        // Gera o Header
        outputFile << ff->buildLine(_descricaoCamposHeader) << std::endl;

        // Gera os titulos
        int seq = 2;
        for (auto it = _titulos->begin(); it != _titulos->end(); ++it) {
            //_titulo = new (_titulo) Titulo(*(*it));
            memcpy(_titulo, (*it), sizeof(Titulo));
            _titulo->sequencial = util::to_string<std::string, int>(seq++);
            outputFile << ff->buildLine(_descricaoCamposTitulo) << std::endl;
            if (_titulo->mensagens.mensagem1.size() != 0 || _titulo->mensagens.mensagem2.size() != 0)
            {
                _titulo->mensagens.sequencial = util::to_string<std::string, int>(seq++);
                outputFile << ff->buildLine(_descricaoCamposTituloMensagens) << std::endl;
            }
        }

        outputFile << "9" << std::endl;

        memset(_titulo, '\0', sizeof(Titulo));

        outputFile.close();
    }
};

void gera() {

    std::unique_ptr<ArquivoDeTeste> arquivoTeste(new ArquivoDeTeste());
    arquivoTeste->geraArquivo();
}

void le() {
    std::unique_ptr<ArquivoDeTeste> arquivoTeste(new ArquivoDeTeste());
    arquivoTeste->parseArquivo();
}

int main()
{
    gera();
    le();

    return 0;
}
\$\endgroup\$
  • \$\begingroup\$ Can you expand on it is not reliable? Are there errors? \$\endgroup\$ – Reinderien Jul 3 at 17:09
  • \$\begingroup\$ The code works well... but it is visible that it is not reliable ..., starting with this 'memcpy' that I made to move the information to the pointer that is used to store the read or write data of the file.... I believe there is a better way to do this that I’m doing, but, I don’t know how \$\endgroup\$ – Carlos Rodrigues Jul 3 at 17:15
  • \$\begingroup\$ OK. I would categorize that as "questionable design" rather than "unreliability", but we will see what the reviews come up with. \$\endgroup\$ – Reinderien Jul 3 at 17:23

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.