Пишу программу для получения данных из
Microsoft OLE2 files. Нашёл
библиотеку, с помощью которой можно вытаскивать данные. Всё хорошо, всё работает. Но нужно улучшать код, бороться с утечками.
Как это работает?
Microsoft OLE2 files представляет собой файловую систему - там есть директории и файлы (stream).
Программа находит два файла (/path/to/Data, /path/to/Property), читает их, извлекает данные, далее их можно записать в БД.
#include <iostream>
#include "com.h"
#include "utf.h"
#include <windows.h>
#include <cstdint>
#include <algorithm>
#include <sstream>
#include <iomanip>
#include <vector>
#pragma execution_character_set( "utf-8" )
const CFB::COMPOUND_FILE_ENTRY* FindStream(const CFB::CompoundFileReader& reader, const char* streamName) {
const CFB::COMPOUND_FILE_ENTRY* ret = nullptr;
reader.EnumFiles(reader.GetRootEntry(), -1,
[&](const CFB::COMPOUND_FILE_ENTRY* entry, const CFB::utf16string& u16dir, int level)->void {
if (reader.IsStream(entry)) {
std::string name = UTF16ToUTF8(entry->name);
if (u16dir.length() > 0) {
std::string dirName = UTF16ToUTF8(u16dir.c_str(), u16dir.length());
std::replace(dirName.begin(), dirName.end(), '\n', '\\');
dirName.erase(std::remove(dirName.begin(), dirName.end(), (char) 0x00), dirName.end());
std::string fullName = dirName + '\\' + name;
if (strcmp(fullName.c_str(), streamName) == 0) {
ret = entry;
}
}
else {
if (strcmp(streamName, name.c_str()) == 0)
{
ret = entry;
}
}
}
}
);
return ret;
}
char* ReadStream(const CFB::CompoundFileReader& reader, const CFB::COMPOUND_FILE_ENTRY* entry) {
char* buf = new char[entry->size];
reader.ReadFile(entry, 0, buf, entry->size);
return buf;
}
void ExtractFromDataStream(const CFB::CompoundFileReader& reader, const CFB::COMPOUND_FILE_ENTRY* entry) {
char* buf = ReadStream(reader, entry);
...
delete[] buf;
}
// returns some struct, not void.
void ExtractFromPropertyStream(const CFB::CompoundFileReader& reader, const CFB::COMPOUND_FILE_ENTRY* entry) {
char* buf = ReadStream(reader, entry);
...
delete[] buf;
}
const CFB::CompoundFileReader GetReader(std::string path) {
FILE* fp;
fopen_s(&fp, path.c_str(), "rb");
if (fp == NULL) {
std::cerr << "read file error" << std::endl;
}
fseek(fp, 0, SEEK_END);
size_t len = ftell(fp);
unsigned char* buffer = new unsigned char[len];
fseek(fp, 0, SEEK_SET);
len = fread(buffer, 1, len, fp);
fclose(fp);
CFB::CompoundFileReader reader(buffer, len);
return reader;
}
int main()
{
SetConsoleCP(1251);
SetConsoleOutputCP(1251);
std::string path = "path\\to\\file.dat";
auto reader = GetReader(path);
auto dataStream = FindStream(reader, "path\\to\\Data");
if (dataStream == nullptr) {
std::cerr << "dataStream is null" << std::endl;
return 1;
}
auto propertyStream = FindStream(reader, "path\\to\\Property");
std::cout << propertyStream->size << std::endl;
if (propertyStream == nullptr) {
std::cerr << "propertyStream is null" << std::endl;
return 1;
}
ExtractFromPropertyStream(reader, propertyStream);
}
Я знаю, этот код ужасен, но нужно найти ошибки и их исправить.
1) Как гарантировать, что
sizeof char
== 1?
2) Как в этом случае лучше обрабатывать ошибки? Например, в функции GetReader не обрабатывается, что с fp может быть что-то не так. Как вариант, бросать исключение, обрабатывать в main.
3) Как быть с утечкой памяти, когда создаётся
unsigned char* buffer
в GetReader? Я пробовал unique_ptr, но, как я понял, из-за того, что указатель выходил из скоупа, данные очищались -> access violation
4) Как лучше всего обрабатывать данные?
5) Как в общем улучшить код?