From e23fd541c698f9f7222e87422055db22a3e3e9c2 Mon Sep 17 00:00:00 2001 From: Olivier Gayot Date: Wed, 17 Sep 2014 17:39:56 +0000 Subject: reader: read and parse a BMP headers we retrieve valuable information such as the data offset, the width and the height of the picture which path is passed as parameter. Signed-off-by: Olivier Gayot --- stegmp.c | 180 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 180 insertions(+) create mode 100644 stegmp.c (limited to 'stegmp.c') diff --git a/stegmp.c b/stegmp.c new file mode 100644 index 0000000..b1f42a8 --- /dev/null +++ b/stegmp.c @@ -0,0 +1,180 @@ +/* + * Copyright (C) 2014 Olivier Gayot + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include +#include +#include +#include + +#include +#include + +#include "bmp.h" + +static int stegmp_parse_windows_bitmap_info_header(const unsigned char *addr, + size_t size, struct bitmap *bmpp) +{ + struct bitmap_info_header info_header; + + if (size < sizeof(typeof(info_header))) { + bmp_errno = BMP_EINVALSIZ; + return -1; + } + + info_header = *((typeof(info_header) *)addr); + + switch (info_header.bpp) { + case 8: + case 16: + case 24: + case 32: + bmpp->bpp = info_header.bpp; + break; + default: + bmp_errno = BMP_EINVALBPP; + return -1; + } + + /* TODO check the compression type */ + + bmpp->width = info_header.bmp_width; + bmpp->height = info_header.bmp_height; + + return 0; +} + +/* guess which type of DIB header it is and handle it or not */ +static int stegmp_parse_dib_header(const unsigned char *addr, size_t size, + struct bitmap *bmpp) +{ + uint32_t dib_size; + + if (size < sizeof(typeof(dib_size))) { + bmp_errno = BMP_EINVALSIZ; + return -1; + } + + dib_size = *((typeof(dib_size) *)addr); + + switch (dib_size) { + case 12: + case 52: + case 56: + case 64: + case 108: + case 124: + bmp_errno = BMP_ENOTSUPP; + return -1; + + case 40: + return stegmp_parse_windows_bitmap_info_header(addr, size, bmpp); + + default: + bmp_errno = BMP_ENOTBMP; + return -1; + } +} + +/* parse the main header of the bmp file */ +static int stegmp_parse_headers(const unsigned char *addr, size_t orig_size, + struct bitmap *bmpp) +{ + struct packed_bmp_header packed_header; + + if (orig_size < sizeof(packed_header)) { + bmp_errno = BMP_ENOTBMP; + return -1; + } + + packed_header = *((typeof(packed_header) *)addr); + + switch (packed_header.magic) { + case BMP_MAGIC_BM: + break; + + case BMP_MAGIC_BA: + case BMP_MAGIC_CI: + case BMP_MAGIC_CP: + case BMP_MAGIC_IC: + case BMP_MAGIC_PT: + bmp_errno = BMP_ENOTSUPP; + return -1; + default: + bmp_errno = BMP_ENOTBMP; + return -1; + } + + if (packed_header.bmp_size != orig_size) { + bmp_errno = BMP_EINVALSIZ; + return -1; + } + + bmpp->data_offset = packed_header.data_offset; + bmpp->size = packed_header.bmp_size; + + stegmp_parse_dib_header(addr + sizeof(packed_header), orig_size, bmpp); + + return 0; +} + +static int stegmp(const char *filename) +{ + void *addr; + struct stat stat; + struct bitmap bmp; + FILE *fh = fopen(filename, "r+"); + + if (fh == NULL) { + fprintf(stderr, "%s: %m\n", filename); + return -1; + } + + fstat(fileno(fh), &stat); + addr = mmap(NULL, stat.st_size, PROT_READ | PROT_WRITE, MAP_PRIVATE, + fileno(fh), 0); + + if (addr == MAP_FAILED) { + fprintf(stderr, "%s: %m\n", filename); + fclose(fh); + return -1; + } + + /* retrieve the required information (i.e. width, height, bpp .. ) */ + if (stegmp_parse_headers(addr, stat.st_size, &bmp) >= 0) { + /* TODO */ + } else { + fprintf(stderr, "unable to parse headers: %s\n", + bmp_strerror(bmp_errno)); + } + + munmap(addr, stat.st_size); + fclose(fh); + + return 0; +} + +int main(int argc, char *argv[]) +{ + /* we need a file passed as argument since we want to map it */ + if (argc < 2) { + fprintf(stderr, "usage: %s BMP\n", argv[0]); + return -1; + } + + return stegmp(argv[1]); +} -- cgit v1.2.3