Blog
개발중인 미완성 페이지로, 일부 기능이 동작하지 않을 수 있습니다.

C BMP 역직렬화, 입력

2024. 6. 19.|2024. 10. 6.

저번 글에서는 bmp 직렬화를 해 봤다.

이번에는 C로 bmp 역직렬화를 구현해보자.

bmp.h
#pragma once

#include <stddef.h>
#include <stdint.h>
#include <stdbool.h>

typedef struct bmp_pixel {
  uint8_t r;
  uint8_t g;
  uint8_t b;
} bmp_pixel_t;

typedef struct bmp {
  size_t width;
  size_t height;
  bmp_pixel_t extra[];
} bmp_t;

/**
 * @brief Serialize bmp
 *
 * @param buffer buffer to deserialize
 * @param length length of buffer
 * @param out result
 * @return true on failure
 * @return false on success
 */
bool deserialize_bmp(const void *buf, size_t length, bmp_t **out);

귀찮으니 저번 글에서 쓴 그 형식으로 된 것만 처리하고, 나머지는 오류로 처리하자.

bmp.c
#include "bmp.h"

#include <stdlib.h>

static uint16_t u16_to_le(uint16_t u16) {
  const uint16_t test = 42;
  const char *const source = (const char *)&u16;
  uint16_t result;
  char *const dest = (char *)&result;

  if (*((char *)&test))
    return (u16);
  dest[0] = source[1];
  dest[1] = source[0];
  return (result);
}

static uint32_t u32_to_le(uint32_t u32) {
  const uint32_t test = 42;
  const char *const source = (const char *)&u32;
  uint32_t result;
  char *const dest = (char *)&result;

  if (*((char *)&test))
    return (u32);
  dest[0] = source[3];
  dest[1] = source[2];
  dest[2] = source[1];
  dest[3] = source[0];
  return (result);
}

bool deserialize_bmp(const void *buf, size_t length, bmp_t **out) {
  const char *const str = buf;

  if (length <= 54 || str[0] != 'B' || str[1] != 'M' ||
      u16_to_le(*((uint16_t *)&str[28])) != 24 ||
      u32_to_le(*((uint32_t *)&str[30])) != 0)
    return (true);

  size_t offset = *((uint32_t *)&str[10]);
  int64_t width = (int32_t)u32_to_le(*((uint32_t *)&str[18]));
  bool width_reversed = width < 0;
  if (width_reversed) {
    width = -width;
  }
  int64_t height = (int32_t)u32_to_le(*((uint32_t *)&str[22]));
  bool height_reversed = height < 0;
  if (height_reversed) {
    height = -height;
  }
  size_t row_padding = (4 - (width * 3) % 4) % 4;
  size_t row_size = width * 3 + row_padding;
  size_t whole_size = row_size * height - row_padding;

  if (length < offset + whole_size)
    return (true);

  bmp_t *const result =
      malloc(sizeof(bmp_t) + sizeof(bmp_pixel_t) * width * height);
  if (!result) {
    return true;
  }

  result->width = width;
  result->height = height;

  const uint8_t *arr = buf + offset;
  for (size_t y = 0; y < height; y++) {
    for (size_t x = 0; x < width; x++) {
      size_t actual_x = x;
      size_t actual_y = y;
      if (width_reversed)
        actual_x = width - 1 - x;
      if (!height_reversed)
        actual_y = height - 1 - y;
      result->extra[actual_y * width + actual_x].r =
          arr[y * row_size + x * 3 + 2];
      result->extra[actual_y * width + actual_x].g =
          arr[y * row_size + x * 3 + 1];
      result->extra[actual_y * width + actual_x].b = arr[y * row_size + x * 3];
    }
  }

  *out = result;
  return false;
}
C
BMP
토막글

Comments