Я пишу парсер растровых изображений (bpm), чтобы практиковать c ++ во время обучения. Однако в разных версиях есть много разных заголовков изображений, и я наткнулся на стену о том, как подойти к этому, так как кажется, что он избегает многих проверок и выглядит элегантно. Не могли бы вы дать мне совет относительно некоторых из следующих подходов или предложить другие?
Вот подходы, о которых я подумал. Основная причина, по которой у меня возникли проблемы, заключается в том, что я хочу использовать memcpy
, чтобы избежать копирования каждого поля по отдельности. Единственное, что согласуется во всех структурах - это первые 4 байта, определяющие размер заголовка / структуры.
Используйте несколько указателей в классе. Установите каждый на nullptr при инициализации. Затем используйте один reinterpret_cast
, чтобы определить, какой заголовок использовать при первом анализе файла. С этого момента проверьте, какой указатель не является nullptr, чтобы определить, какой из них использовать.
Используйте poid void и используйте reinterpret_cast
всякий раз, когда выполняете операцию получения или установки значений взаголовок. Вероятно, не лучший вариант, но он есть.
Создайте ABC (что, я не уверен, я полностью понимаю). Позволил бы для структуры наследования. Не уверен, что это будет работать гладко с memcpy
, потому что из того, что я понимаю, наличие виртуальных методов добавит невидимый указатель в начале структуры, который сломается при использовании неизмененного буфера, скопировав его непосредственно в структуру. (Пожалуйста, скажите мне, если я ошибаюсь по этому поводу.)
В настоящее время пытаюсь приблизиться к одному. Вот мой заголовочный файл.
#ifndef BITMAP_H_INCLUDE
#define BITMAP_H_INCLUDE
#include <fstream>
#include <iostream>
#include <vector>
#include <cstring>
enum HeaderSizes
{
File = 14,
Core = 12,
InfoV1 = 40,
OS2 = 64,
InfoV4 = 108,
InfoV5 = 124,
};
enum InfoCompressionMethod
{
// omitted for brevity
};
enum HalftoneAlgorithms
{
// omitted for brevity
};
struct FileHeader
{
// omitted for brevity, first header is always 14 bytes
};
struct CoreHeader
{
uint32_t header_size;
uint16_t width;
uint16_t height;
uint16_t planes;
uint16_t bit_depth;
};
struct InfoV1Header
{
uint32_t header_size;
int32_t width;
int32_t height;
uint16_t planes;
uint16_t bit_depth;
uint32_t compression;
uint32_t size_image;
int32_t x_resolution;
int32_t y_resolution;
uint32_t color_used;
uint32_t color_important;
};
struct OS2Header : public InfoV1Header
{
uint16_t resolution_units;
uint16_t reserved;
uint16_t fill_direction;
uint16_t halftone_algorithm;
uint32_t halftone_param_1;
uint32_t halftone_param_2;
uint32_t color_encoding;
uint32_t application_defined;
};
struct InfoV4Header : public InfoV1Header
{
uint32_t red_mask;
uint32_t green_mask;
uint32_t blue_mask;
uint32_t alpha_mask;
uint32_t cs_type;
uint64_t red_x;
uint64_t red_y;
uint64_t red_z;
uint64_t green_x;
uint64_t green_y;
uint64_t green_z;
uint64_t blue_x;
uint64_t blue_y;
uint64_t blue_z;
uint32_t gamma_red;
uint32_t gamma_green;
uint32_t gamma_blue;
};
struct InfoV5Header : public InfoV4Header
{
uint32_t intent;
uint32_t profile_data;
uint32_t profile_size;
uint32_t reserved;
};
class Bitmap
{
public:
Bitmap(std::string in_path);
~Bitmap();
void save(std::string out_path);
private:
FileHeader* file_header;
// Info Header Options
CoreHeader* core_header;
OS2Header* os2_header;
InfoV1Header* info_v1_header;
InfoV4Header* info_v4_header;
InfoV5Header* info_v5_header;
void verify_file_header() const;
};
#endif /* BITMAP_H_INCLUDE */
Кажется, что сейчас это лучший вариант, но я не согласен с идеей написать кучу методов, которые начинаются с проверки на nullptr в заголовках информации. Надеюсь, мне чего-то не хватает, потому что я не очень хорошо знаю c ++.
(В настоящее время работаю в c ++ 14, но не против использования 17, если это имеет смысл. В Linux Zorin OS 15, используя gcc 7.4,с помощью cmake 3.15.2.)