libansilove

Library for converting ANSI, ASCII, and other formats to PNG
Log | Files | Refs | README | LICENSE

xbin.c (4952B)


      1 /*
      2  * xbin.c
      3  * libansilove 1.2.4
      4  * https://www.ansilove.org
      5  *
      6  * Copyright (c) 2011-2020 Stefan Vogt, Brian Cassidy, and Frederic Cambus
      7  * All rights reserved.
      8  *
      9  * libansilove is licensed under the BSD 2-Clause License.
     10  * See LICENSE file for details.
     11  */
     12 
     13 #include <gd.h>
     14 #include <stdint.h>
     15 #include <stdlib.h>
     16 #include <string.h>
     17 #include "ansilove.h"
     18 #include "config.h"
     19 #include "drawchar.h"
     20 #include "fonts.h"
     21 #include "output.h"
     22 
     23 #define XBIN_HEADER_LENGTH 11 /* 4 + 1 + 2 + 2 + 1 + 1 */
     24 #define XBIN_PALETTE_LENGTH 48
     25 
     26 int
     27 ansilove_xbin(struct ansilove_ctx *ctx, struct ansilove_options *options)
     28 {
     29 	if (ctx == NULL || options == NULL) {
     30 		if (ctx)
     31 			ctx->error = ANSILOVE_INVALID_PARAM;
     32 
     33 		return -1;
     34 	}
     35 
     36 	if (ctx->length < XBIN_HEADER_LENGTH) {
     37 		ctx->error = ANSILOVE_FORMAT_ERROR;
     38 		return -1;
     39 	}
     40 
     41 	const uint8_t *font_data;
     42 	uint8_t *font_data_xbin = NULL;
     43 
     44 	if (strncmp((char *)ctx->buffer, "XBIN\x1a", 5) != 0) {
     45 		ctx->error = ANSILOVE_FORMAT_ERROR;
     46 		return -1;
     47 	}
     48 
     49 	uint32_t xbin_width = (ctx->buffer[6] << 8) + ctx->buffer[5];
     50 	uint32_t xbin_height = (ctx->buffer[8] << 8) + ctx->buffer[7];
     51 	uint32_t xbin_fontsize = ctx->buffer[9];
     52 	uint32_t xbin_flags = ctx->buffer[10];
     53 
     54 	if (xbin_fontsize == 0) {
     55 		xbin_fontsize = 16;
     56 	}
     57 
     58 	if (xbin_fontsize > 32) {
     59 		ctx->error = ANSILOVE_FORMAT_ERROR;
     60 		return -1;
     61 	}
     62 
     63 	gdImagePtr canvas;
     64 
     65 	canvas = gdImageCreate(8 * xbin_width, xbin_fontsize * xbin_height);
     66 
     67 	if (!canvas) {
     68 		ctx->error = ANSILOVE_GD_ERROR;
     69 		return -1;
     70 	}
     71 
     72 	uint32_t colors[16];
     73 	uint32_t offset = XBIN_HEADER_LENGTH;
     74 
     75 	/* palette */
     76 	if ((xbin_flags & 1) == 1) {
     77 		size_t index, loop;
     78 
     79 		if (offset + XBIN_PALETTE_LENGTH > ctx->length) {
     80 			ctx->error = ANSILOVE_FORMAT_ERROR;
     81 			return -1;
     82 		}
     83 
     84 		for (loop = 0; loop < 16; loop++) {
     85 			index = (loop * 3) + offset;
     86 
     87 			colors[loop] = gdImageColorAllocate(canvas,
     88 			    (ctx->buffer[index] << 2 | ctx->buffer[index] >> 4),
     89 			    (ctx->buffer[index + 1] << 2 | ctx->buffer[index + 1] >> 4),
     90 			    (ctx->buffer[index + 2] << 2 | ctx->buffer[index + 2] >> 4));
     91 		}
     92 
     93 		offset += XBIN_PALETTE_LENGTH;
     94 	} else {
     95 		for (size_t i = 0; i < 16; i++) {
     96 			colors[i] = gdImageColorAllocate(canvas,
     97 			    vga_palette_red[i], vga_palette_green[i],
     98 			    vga_palette_blue[i]);
     99 		}
    100 	}
    101 
    102 	/* font */
    103 	if ((xbin_flags & 2) == 2) {
    104 		uint32_t numchars = (xbin_flags & 0x10 ? 512 : 256);
    105 		size_t fontsz = xbin_fontsize * numchars;
    106 
    107 		if (offset + fontsz > ctx->length) {
    108 			ctx->error = ANSILOVE_FORMAT_ERROR;
    109 			return -1;
    110 		}
    111 
    112 		/* allocate memory to contain the XBin font */
    113 		font_data_xbin = (uint8_t *)malloc(fontsz);
    114 		if (font_data_xbin == NULL) {
    115 			ctx->error = ANSILOVE_MEMORY_ERROR;
    116 			return -1;
    117 		}
    118 
    119 		memcpy(font_data_xbin, ctx->buffer+offset, fontsz);
    120 
    121 		font_data = font_data_xbin;
    122 
    123 		offset += fontsz;
    124 	} else {
    125 		/* using default 80x25 font */
    126 		font_data = font_pc_80x25;
    127 		xbin_fontsize = 16;
    128 	}
    129 
    130 	uint32_t column = 0, row = 0, foreground, background;
    131 	int32_t character, attribute;
    132 
    133 	/* read compressed xbin */
    134 	if ((xbin_flags & 4) == 4) {
    135 		while (offset < ctx->length && row != xbin_height) {
    136 			uint32_t ctype = ctx->buffer[offset] & 0xC0;
    137 			uint32_t counter = (ctx->buffer[offset] & 0x3F) + 1;
    138 
    139 			character = -1;
    140 			attribute = -1;
    141 
    142 			offset++;
    143 			while (counter--) {
    144 				/* none */
    145 				if (ctype == 0) {
    146 					character = ctx->buffer[offset];
    147 					attribute = ctx->buffer[offset + 1];
    148 					offset += 2;
    149 				}
    150 				/* char */
    151 				else if (ctype == 0x40) {
    152 					if (character == -1) {
    153 						character = ctx->buffer[offset];
    154 						offset++;
    155 					}
    156 					attribute = ctx->buffer[offset];
    157 					offset++;
    158 				}
    159 				/* attr */
    160 				else if (ctype == 0x80) {
    161 					if (attribute == -1) {
    162 						attribute = ctx->buffer[offset];
    163 						offset++;
    164 					}
    165 					character = ctx->buffer[offset];
    166 					offset++;
    167 				}
    168 				/* both */
    169 				else {
    170 					if (character == -1) {
    171 						character = ctx->buffer[offset];
    172 						offset++;
    173 					}
    174 					if (attribute == -1) {
    175 						attribute = ctx->buffer[offset];
    176 						offset++;
    177 					}
    178 				}
    179 
    180 				background = (attribute & 240) >> 4;
    181 				foreground = attribute & 15;
    182 
    183 				drawchar(canvas, font_data, 8, xbin_fontsize,
    184 				    column, row, colors[background],
    185 				    colors[foreground], character);
    186 
    187 				column++;
    188 
    189 				if (column == xbin_width) {
    190 					column = 0;
    191 					row++;
    192 				}
    193 			}
    194 		}
    195 	} else {
    196 		/* read uncompressed xbin */
    197 		while (offset < ctx->length && row != xbin_height) {
    198 			if (column == xbin_width) {
    199 				column = 0;
    200 				row++;
    201 			}
    202 
    203 			character = ctx->buffer[offset];
    204 			attribute = ctx->buffer[offset+1];
    205 
    206 			background = (attribute & 240) >> 4;
    207 			foreground = attribute & 15;
    208 
    209 			drawchar(canvas, font_data, 8, xbin_fontsize,
    210 			    column, row, colors[background],
    211 			    colors[foreground], character);
    212 
    213 			column++;
    214 			offset += 2;
    215 		}
    216 	}
    217 
    218 	/* create output file */
    219 	if (output(ctx, options, canvas) != 0) {
    220 		free(font_data_xbin);
    221 		font_data = NULL;
    222 		return -1;
    223 	}
    224 
    225 	free(font_data_xbin);
    226 
    227 	return 0;
    228 }