diff --git a/src/lpt.c b/src/lpt.c index fbd048beb..824b695be 100644 --- a/src/lpt.c +++ b/src/lpt.c @@ -10,7 +10,7 @@ #include "lpt.h" #include "sound/snd_lpt_dac.h" #include "sound/snd_lpt_dss.h" - +#include "printer/prt_devs.h" char lpt_device_names[3][16]; @@ -26,6 +26,8 @@ static const struct {"Disney Sound Source", "dss", &dss_device}, {"LPT DAC / Covox Speech Thing", "lpt_dac", &lpt_dac_device}, {"Stereo LPT DAC", "lpt_dac_stereo", &lpt_dac_stereo_device}, + {"Generic Text Printer", "text_prt", &lpt_prt_text_device}, + {"Generic ESC/P Dot-Matrix", "dot_matrix", &lpt_prt_escp_device}, {"", "", NULL} }; diff --git a/src/plat.h b/src/plat.h index b3b6e10a8..9d7bad792 100644 --- a/src/plat.h +++ b/src/plat.h @@ -71,6 +71,7 @@ extern FILE *plat_fopen(wchar_t *path, wchar_t *mode); extern void plat_remove(wchar_t *path); extern int plat_getcwd(wchar_t *bufp, int max); extern int plat_chdir(wchar_t *path); +extern void plat_tempfile(wchar_t *bufp, wchar_t *prefix, wchar_t *suffix); extern void plat_get_exe_name(wchar_t *s, int size); extern wchar_t *plat_get_filename(wchar_t *s); extern wchar_t *plat_get_extension(wchar_t *s); diff --git a/src/printer/png.c b/src/printer/png.c new file mode 100644 index 000000000..fbe3b39a0 --- /dev/null +++ b/src/printer/png.c @@ -0,0 +1,349 @@ +/* + * VARCem Virtual ARchaeological Computer EMulator. + * An emulator of (mostly) x86-based PC systems and devices, + * using the ISA,EISA,VLB,MCA and PCI system buses, roughly + * spanning the era between 1981 and 1995. + * + * This file is part of the VARCem Project. + * + * Provide centralized access to the PNG image handler. + * + * Version: @(#)png.c 1.0.4 2018/10/07 + * + * Author: Fred N. van Kempen, + * + * Copyright 2018 Fred N. van Kempen. + * + * Redistribution and use in source and binary forms, with + * or without modification, are permitted provided that the + * following conditions are met: + * + * 1. Redistributions of source code must retain the entire + * above notice, this list of conditions and the following + * disclaimer. + * + * 2. Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names + * of its contributors may be used to endorse or promote + * products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#include +#include +#include +#include +#include +#include +#define PNG_DEBUG 0 +#include +#include "../86box.h" +#include "../plat.h" +#include "../plat_dynld.h" +#include "../ui.h" +#include "../video/video.h" +#include "png_struct.h" + +#ifdef _WIN32 +# define PATH_PNG_DLL "libpng16-16.dll" +#else +# define PATH_PNG_DLL "libpng16.so" +#endif + + +static void *png_handle = NULL; /* handle to DLL */ +# define PNGFUNC(x) PNG_ ## x + + +/* Pointers to the real functions. */ +static png_structp (*PNG_create_write_struct)(png_const_charp user_png_ver, + png_voidp error_ptr, + png_error_ptr error_fn, + png_error_ptr warn_fn); +static void (*PNG_destroy_write_struct)(png_structpp png_ptr_ptr, + png_infopp info_ptr_ptr); +static png_infop (*PNG_create_info_struct)(png_const_structrp png_ptr); +static void (*PNG_init_io)(png_structrp png_ptr, png_FILE_p fp); +static void (*PNG_set_IHDR)(png_const_structrp png_ptr, + png_inforp info_ptr, png_uint_32 width, + png_uint_32 height, int bit_depth, + int color_type, int interlace_method, + int compression_method, + int filter_method); +static png_size_t (*PNG_get_rowbytes)(png_const_structrp png_ptr, + png_const_inforp info_ptr); +static void (*PNG_write_info)(png_structrp png_ptr, + png_const_inforp info_ptr); +static void (*PNG_write_image)(png_structrp png_ptr, + png_bytepp image); +static void (*PNG_write_row)(png_structrp png_ptr, + png_bytep row); +static void (*PNG_write_rows)(png_structrp png_ptr, + png_bytepp rows, int num); +static void (*PNG_write_end)(png_structrp png_ptr, + png_inforp info_ptr); + + +static dllimp_t png_imports[] = { + { "png_create_write_struct", &PNG_create_write_struct }, + { "png_destroy_write_struct", &PNG_destroy_write_struct }, + { "png_create_info_struct", &PNG_create_info_struct }, + { "png_init_io", &PNG_init_io }, + { "png_set_IHDR", &PNG_set_IHDR }, + { "png_get_rowbytes", &PNG_get_rowbytes }, + { "png_write_info", &PNG_write_info }, + { "png_write_row", &PNG_write_row }, + { "png_write_rows", &PNG_write_rows }, + { "png_write_image", &PNG_write_image }, + { "png_write_end", &PNG_write_end }, + { NULL, NULL } +}; + + +static void +error_handler(png_structp arg, const char *str) +{ + pclog("PNG: stream 0x%08lx error '%s'\n", arg, str); +} + + +static void +warning_handler(png_structp arg, const char *str) +{ + pclog("PNG: stream 0x%08lx warning '%s'\n", arg, str); +} + + +/* Prepare the PNG library for use, load DLL if needed. */ +int +png_load(void) +{ + const char *fn = PATH_PNG_DLL; + + /* If already loaded, good! */ + if (png_handle != NULL) return(1); + + /* Try loading the DLL. */ + png_handle = dynld_module(fn, png_imports); + if (png_handle == NULL) { + ui_msgbox(MBX_ERROR, (wchar_t *)IDS_2081); + pclog("PNG: unable to load '%s'; format disabled!\n", fn); + return(0); + } else + pclog("PNG: module '%s' loaded.\n", fn); + + return(1); +} + + +/* PNG library no longer needed, unload DLL if needed. */ +void +png_unload(void) +{ + /* Unload the DLL if possible. */ + if (png_handle != NULL) + dynld_close(png_handle); + + png_handle = NULL; +} + + +/* Write the given image as an 8-bit GrayScale PNG image file. */ +int +png_write_gray(wchar_t *fn, int inv, uint8_t *pix, int16_t w, int16_t h) +{ + png_structp png = NULL; + png_infop info = NULL; + png_bytep row; + int16_t x, y; + FILE *fp; + + /* Load the DLL if needed, give up if that fails. */ + if (! png_load()) return(0); + + /* Create the image file. */ + fp = plat_fopen(fn, L"wb"); + if (fp == NULL) { + /* Yes, this looks weird. */ + if (fp == NULL) + pclog("PNG: file %ls could not be opened for writing!\n", fn); + else +error: + pclog("PNG: fatal error, bailing out, error = %i\n", errno); + if (png != NULL) + PNGFUNC(destroy_write_struct)(&png, &info); + if (fp != NULL) + (void)fclose(fp); + return(0); + } + + /* Initialize PNG stuff. */ + png = PNGFUNC(create_write_struct)(PNG_LIBPNG_VER_STRING, NULL, + error_handler, warning_handler); + if (png == NULL) { + pclog("PNG: create_write_struct failed!\n"); + goto error; + } + + info = PNGFUNC(create_info_struct)(png); + if (info == NULL) { + pclog("PNG: create_info_struct failed!\n"); + goto error; + } + + + PNGFUNC(init_io)(png, fp); + + PNGFUNC(set_IHDR)(png, info, w, h, 8, PNG_COLOR_TYPE_GRAY, + PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, + PNG_FILTER_TYPE_DEFAULT); + + PNGFUNC(write_info)(png, info); + + /* Create a buffer for one scanline of pixels. */ + row = (png_bytep)malloc(PNGFUNC(get_rowbytes)(png, info)); + + /* Process all scanlines in the image. */ + for (y = 0; y < h; y++) { + for (x = 0; x < w; x++) { + /* Copy the pixel data. */ + if (inv) + row[x] = 255 - pix[(y * w) + x]; + else + row[x] = pix[(y * w) + x]; + } + + /* Write image to the file. */ + PNGFUNC(write_rows)(png, &row, 1); + } + + /* No longer need the row buffer. */ + free(row); + + PNGFUNC(write_end)(png, NULL); + + PNGFUNC(destroy_write_struct)(&png, &info); + + /* Clean up. */ + (void)fclose(fp); + + return(1); +} + + +/* Write the given BITMAP-format image as an 8-bit RGBA PNG image file. */ +int +png_write_rgb(wchar_t *fn, uint8_t *pix, int16_t w, int16_t h) +{ + png_structp png = NULL; + png_infop info = NULL; + png_bytepp rows; + uint8_t *r, *b; + uint32_t *rgb; + FILE *fp; + int y, x; + + /* Load the DLL if needed, give up if that fails. */ + if (! png_load()) return(0); + + /* Create the image file. */ + fp = plat_fopen(fn, L"wb"); + if (fp == NULL) { + pclog("PNG: File %ls could not be opened for writing!\n", fn); +error: + if (png != NULL) + PNGFUNC(destroy_write_struct)(&png, &info); + if (fp != NULL) + (void)fclose(fp); + return(0); + } + + /* Initialize PNG stuff. */ + png = PNGFUNC(create_write_struct)(PNG_LIBPNG_VER_STRING, NULL, + error_handler, warning_handler); + if (png == NULL) { + pclog("PNG: create_write_struct failed!\n"); + goto error; + } + + info = PNGFUNC(create_info_struct)(png); + if (info == NULL) { + pclog("PNG: create_info_struct failed!\n"); + goto error; + } + + PNGFUNC(init_io)(png, fp); + + PNGFUNC(set_IHDR)(png, info, w, h, 8, PNG_COLOR_TYPE_RGB, + PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, + PNG_FILTER_TYPE_DEFAULT); + + PNGFUNC(write_info)(png, info); + + /* Create a buffer for scanlines of pixels. */ + rows = (png_bytepp)malloc(sizeof(png_bytep) * h); + for (y = 0; y < h; y++) { + /* Create a buffer for this scanline. */ + rows[y] = (png_bytep)malloc(PNGFUNC(get_rowbytes)(png, info)); + } + + /* + * Process all scanlines in the image. + * + * Since the bitmap is in 'bottom-up' mode, we have to + * convert all pixels to RGB mode, but also 'flip' the + * image to the normal top-down mode. + */ + for (y = 0; y < h; y++) { + for (x = 0; x < w; x++) { + /* Get pointer to pixel in bitmap data. */ + b = &pix[((y * w) + x) * 4]; + + /* Transform if needed. */ + if (invert_display) { + rgb = (uint32_t *)b; + *rgb = video_color_transform(*rgb); + } + + /* Get pointer to png row data. */ + r = &rows[(h - 1) - y][x * 3]; + + /* Copy the pixel data. */ + r[0] = b[2]; + r[1] = b[1]; + r[2] = b[0]; + } + } + + /* Write image to the file. */ + PNGFUNC(write_image)(png, rows); + + /* No longer need the row buffers. */ + for (y = 0; y < h; y++) + free(rows[y]); + free(rows); + + PNGFUNC(write_end)(png, NULL); + + PNGFUNC(destroy_write_struct)(&png, &info); + + /* Clean up. */ + (void)fclose(fp); + + return(1); +} diff --git a/src/printer/png_struct.h b/src/printer/png_struct.h new file mode 100644 index 000000000..8aa306fb2 --- /dev/null +++ b/src/printer/png_struct.h @@ -0,0 +1,69 @@ +/* + * VARCem Virtual ARchaeological Computer EMulator. + * An emulator of (mostly) x86-based PC systems and devices, + * using the ISA,EISA,VLB,MCA and PCI system buses, roughly + * spanning the era between 1981 and 1995. + * + * This file is part of the VARCem Project. + * + * Definitions for the centralized PNG image handler. + * + * Version: @(#)png_struct.h 1.0.1 2018/09/01 + * + * Author: Fred N. van Kempen, + * + * Copyright 2018 Fred N. van Kempen. + * + * Redistribution and use in source and binary forms, with + * or without modification, are permitted provided that the + * following conditions are met: + * + * 1. Redistributions of source code must retain the entire + * above notice, this list of conditions and the following + * disclaimer. + * + * 2. Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names + * of its contributors may be used to endorse or promote + * products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef EMU_PNG_STRUCT_H +# define EMU_PNG_STRUCT_H + + +#ifdef __cplusplus +extern "C" { +#endif + +extern int png_load(void); +extern void png_unload(void); + +extern int png_write_gray(wchar_t *path, int invert, + uint8_t *pix, int16_t w, int16_t h); + +extern int png_write_rgb(wchar_t *fn, + uint8_t *pix, int16_t w, int16_t h); + +#ifdef __cplusplus +} +#endif + + +#endif /*EMU_PNG_STRUCT_H*/ diff --git a/src/printer/printer.h b/src/printer/printer.h new file mode 100644 index 000000000..f5fe558ff --- /dev/null +++ b/src/printer/printer.h @@ -0,0 +1,64 @@ +/* + * VARCem Virtual ARchaeological Computer EMulator. + * An emulator of (mostly) x86-based PC systems and devices, + * using the ISA,EISA,VLB,MCA and PCI system buses, roughly + * spanning the era between 1981 and 1995. + * + * This file is part of the VARCem Project. + * + * Definitions for the printers module. + * + * Version: @(#)printer.h 1.0.3 2018/09/03 + * + * Author: Fred N. van Kempen, + * + * Copyright 2018 Fred N. van Kempen. + * + * Redistribution and use in source and binary forms, with + * or without modification, are permitted provided that the + * following conditions are met: + * + * 1. Redistributions of source code must retain the entire + * above notice, this list of conditions and the following + * disclaimer. + * + * 2. Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names + * of its contributors may be used to endorse or promote + * products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef PRINTER_H +# define PRINTER_H + + +#define FONT_FILE_DOTMATRIX L"dotmatrix.ttf" + +#define FONT_FILE_ROMAN L"roman.ttf" +#define FONT_FILE_SANSSERIF L"sansserif.ttf" +#define FONT_FILE_COURIER L"courier.ttf" +#define FONT_FILE_SCRIPT L"script.ttf" +#define FONT_FILE_OCRA L"ocra.ttf" +#define FONT_FILE_OCRB L"ocra.ttf" + + +extern const uint16_t *select_codepage(uint16_t num); + + +#endif /*PRINTER_H*/ diff --git a/src/printer/prt_cpmap.c b/src/printer/prt_cpmap.c new file mode 100644 index 000000000..5540f1872 --- /dev/null +++ b/src/printer/prt_cpmap.c @@ -0,0 +1,589 @@ +/* + * VARCem Virtual ARchaeological Computer EMulator. + * An emulator of (mostly) x86-based PC systems and devices, + * using the ISA,EISA,VLB,MCA and PCI system buses, roughly + * spanning the era between 1981 and 1995. + * + * This file is part of the VARCem Project. + * + * Various ASCII to Unicode maps, for the various codepages. + * + * Version: @(#)prt_cpmap.c 1.0.2 2018/10/05 + * + * Authors: Michael Drüing, + * Fred N. van Kempen, + * + * Based on code by Frederic Weymann (originally for DosBox.) + * + * Copyright 2018 Michael Drüing. + * Copyright 2018 Fred N. van Kempen. + * + * Redistribution and use in source and binary forms, with + * or without modification, are permitted provided that the + * following conditions are met: + * + * 1. Redistributions of source code must retain the entire + * above notice, this list of conditions and the following + * disclaimer. + * + * 2. Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names + * of its contributors may be used to endorse or promote + * products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#include +#include +#include +#include +#include +#include "../86box.h" +#include "../plat.h" +#include "printer.h" + + +static const uint16_t cp437Map[256] = { + 0x0000,0x0001,0x0002,0x0003,0x0004,0x0005,0x0006,0x0007, + 0x0008,0x0009,0x000a,0x000b,0x000c,0x000d,0x000e,0x000f, + 0x0010,0x0011,0x0012,0x0013,0x0014,0x0015,0x0016,0x0017, + 0x0018,0x0019,0x001a,0x001b,0x001c,0x001d,0x001e,0x001f, + 0x0020,0x0021,0x0022,0x0023,0x0024,0x0025,0x0026,0x0027, + 0x0028,0x0029,0x002a,0x002b,0x002c,0x002d,0x002e,0x002f, + 0x0030,0x0031,0x0032,0x0033,0x0034,0x0035,0x0036,0x0037, + 0x0038,0x0039,0x003a,0x003b,0x003c,0x003d,0x003e,0x003f, + 0x0040,0x0041,0x0042,0x0043,0x0044,0x0045,0x0046,0x0047, + 0x0048,0x0049,0x004a,0x004b,0x004c,0x004d,0x004e,0x004f, + 0x0050,0x0051,0x0052,0x0053,0x0054,0x0055,0x0056,0x0057, + 0x0058,0x0059,0x005a,0x005b,0x005c,0x005d,0x005e,0x005f, + 0x0060,0x0061,0x0062,0x0063,0x0064,0x0065,0x0066,0x0067, + 0x0068,0x0069,0x006a,0x006b,0x006c,0x006d,0x006e,0x006f, + 0x0070,0x0071,0x0072,0x0073,0x0074,0x0075,0x0076,0x0077, + 0x0078,0x0079,0x007a,0x007b,0x007c,0x007d,0x007e,0x007f, + 0x00c7,0x00fc,0x00e9,0x00e2,0x00e4,0x00e0,0x00e5,0x00e7, + 0x00ea,0x00eb,0x00e8,0x00ef,0x00ee,0x00ec,0x00c4,0x00c5, + 0x00c9,0x00e6,0x00c6,0x00f4,0x00f6,0x00f2,0x00fb,0x00f9, + 0x00ff,0x00d6,0x00dc,0x00a2,0x00a3,0x00a5,0x20a7,0x0192, + 0x00e1,0x00ed,0x00f3,0x00fa,0x00f1,0x00d1,0x00aa,0x00ba, + 0x00bf,0x2310,0x00ac,0x00bd,0x00bc,0x00a1,0x00ab,0x00bb, + 0x2591,0x2592,0x2593,0x2502,0x2524,0x2561,0x2562,0x2556, + 0x2555,0x2563,0x2551,0x2557,0x255d,0x255c,0x255b,0x2510, + 0x2514,0x2534,0x252c,0x251c,0x2500,0x253c,0x255e,0x255f, + 0x255a,0x2554,0x2569,0x2566,0x2560,0x2550,0x256c,0x2567, + 0x2568,0x2564,0x2565,0x2559,0x2558,0x2552,0x2553,0x256b, + 0x256a,0x2518,0x250c,0x2588,0x2584,0x258c,0x2590,0x2580, + 0x03b1,0x00df,0x0393,0x03c0,0x03a3,0x03c3,0x00b5,0x03c4, + 0x03a6,0x0398,0x03a9,0x03b4,0x221e,0x03c6,0x03b5,0x2229, + 0x2261,0x00b1,0x2265,0x2264,0x2320,0x2321,0x00f7,0x2248, + 0x00b0,0x2219,0x00b7,0x221a,0x207f,0x00b2,0x25a0,0x00a0 +}; + +static const uint16_t cp737Map[256] = { + 0x0000,0x0001,0x0002,0x0003,0x0004,0x0005,0x0006,0x0007, + 0x0008,0x0009,0x000a,0x000b,0x000c,0x000d,0x000e,0x000f, + 0x0010,0x0011,0x0012,0x0013,0x0014,0x0015,0x0016,0x0017, + 0x0018,0x0019,0x001a,0x001b,0x001c,0x001d,0x001e,0x001f, + 0x0020,0x0021,0x0022,0x0023,0x0024,0x0025,0x0026,0x0027, + 0x0028,0x0029,0x002a,0x002b,0x002c,0x002d,0x002e,0x002f, + 0x0030,0x0031,0x0032,0x0033,0x0034,0x0035,0x0036,0x0037, + 0x0038,0x0039,0x003a,0x003b,0x003c,0x003d,0x003e,0x003f, + 0x0040,0x0041,0x0042,0x0043,0x0044,0x0045,0x0046,0x0047, + 0x0048,0x0049,0x004a,0x004b,0x004c,0x004d,0x004e,0x004f, + 0x0050,0x0051,0x0052,0x0053,0x0054,0x0055,0x0056,0x0057, + 0x0058,0x0059,0x005a,0x005b,0x005c,0x005d,0x005e,0x005f, + 0x0060,0x0061,0x0062,0x0063,0x0064,0x0065,0x0066,0x0067, + 0x0068,0x0069,0x006a,0x006b,0x006c,0x006d,0x006e,0x006f, + 0x0070,0x0071,0x0072,0x0073,0x0074,0x0075,0x0076,0x0077, + 0x0078,0x0079,0x007a,0x007b,0x007c,0x007d,0x007e,0x007f, + 0x0391,0x0392,0x0393,0x0394,0x0395,0x0396,0x0397,0x0398, + 0x0399,0x039a,0x039b,0x039c,0x039d,0x039e,0x039f,0x03a0, + 0x03a1,0x03a3,0x03a4,0x03a5,0x03a6,0x03a7,0x03a8,0x03a9, + 0x03b1,0x03b2,0x03b3,0x03b4,0x03b5,0x03b6,0x03b7,0x03b8, + 0x03b9,0x03ba,0x03bb,0x03bc,0x03bd,0x03be,0x03bf,0x03c0, + 0x03c1,0x03c3,0x03c2,0x03c4,0x03c5,0x03c6,0x03c7,0x03c8, + 0x2591,0x2592,0x2593,0x2502,0x2524,0x2561,0x2562,0x2556, + 0x2555,0x2563,0x2551,0x2557,0x255d,0x255c,0x255b,0x2510, + 0x2514,0x2534,0x252c,0x251c,0x2500,0x253c,0x255e,0x255f, + 0x255a,0x2554,0x2569,0x2566,0x2560,0x2550,0x256c,0x2567, + 0x2568,0x2564,0x2565,0x2559,0x2558,0x2552,0x2553,0x256b, + 0x256a,0x2518,0x250c,0x2588,0x2584,0x258c,0x2590,0x2580, + 0x03c9,0x03ac,0x03ad,0x03ae,0x03ca,0x03af,0x03cc,0x03cd, + 0x03cb,0x03ce,0x0386,0x0388,0x0389,0x038a,0x038c,0x038e, + 0x038f,0x00b1,0x2265,0x2264,0x03aa,0x03ab,0x00f7,0x2248, + 0x00b0,0x2219,0x00b7,0x221a,0x207f,0x00b2,0x25a0,0x00a0 +}; + +static const uint16_t cp775Map[256] = { + 0x0000,0x0001,0x0002,0x0003,0x0004,0x0005,0x0006,0x0007, + 0x0008,0x0009,0x000a,0x000b,0x000c,0x000d,0x000e,0x000f, + 0x0010,0x0011,0x0012,0x0013,0x0014,0x0015,0x0016,0x0017, + 0x0018,0x0019,0x001a,0x001b,0x001c,0x001d,0x001e,0x001f, + 0x0020,0x0021,0x0022,0x0023,0x0024,0x0025,0x0026,0x0027, + 0x0028,0x0029,0x002a,0x002b,0x002c,0x002d,0x002e,0x002f, + 0x0030,0x0031,0x0032,0x0033,0x0034,0x0035,0x0036,0x0037, + 0x0038,0x0039,0x003a,0x003b,0x003c,0x003d,0x003e,0x003f, + 0x0040,0x0041,0x0042,0x0043,0x0044,0x0045,0x0046,0x0047, + 0x0048,0x0049,0x004a,0x004b,0x004c,0x004d,0x004e,0x004f, + 0x0050,0x0051,0x0052,0x0053,0x0054,0x0055,0x0056,0x0057, + 0x0058,0x0059,0x005a,0x005b,0x005c,0x005d,0x005e,0x005f, + 0x0060,0x0061,0x0062,0x0063,0x0064,0x0065,0x0066,0x0067, + 0x0068,0x0069,0x006a,0x006b,0x006c,0x006d,0x006e,0x006f, + 0x0070,0x0071,0x0072,0x0073,0x0074,0x0075,0x0076,0x0077, + 0x0078,0x0079,0x007a,0x007b,0x007c,0x007d,0x007e,0x007f, + 0x0106,0x00fc,0x00e9,0x0101,0x00e4,0x0123,0x00e5,0x0107, + 0x0142,0x0113,0x0156,0x0157,0x012b,0x0179,0x00c4,0x00c5, + 0x00c9,0x00e6,0x00c6,0x014d,0x00f6,0x0122,0x00a2,0x015a, + 0x015b,0x00d6,0x00dc,0x00f8,0x00a3,0x00d8,0x00d7,0x00a4, + 0x0100,0x012a,0x00f3,0x017b,0x017c,0x017a,0x201d,0x00a6, + 0x00a9,0x00ae,0x00ac,0x00bd,0x00bc,0x0141,0x00ab,0x00bb, + 0x2591,0x2592,0x2593,0x2502,0x2524,0x0104,0x010c,0x0118, + 0x0116,0x2563,0x2551,0x2557,0x255d,0x012e,0x0160,0x2510, + 0x2514,0x2534,0x252c,0x251c,0x2500,0x253c,0x0172,0x016a, + 0x255a,0x2554,0x2569,0x2566,0x2560,0x2550,0x256c,0x017d, + 0x0105,0x010d,0x0119,0x0117,0x012f,0x0161,0x0173,0x016b, + 0x017e,0x2518,0x250c,0x2588,0x2584,0x258c,0x2590,0x2580, + 0x00d3,0x00df,0x014c,0x0143,0x00f5,0x00d5,0x00b5,0x0144, + 0x0136,0x0137,0x013b,0x013c,0x0146,0x0112,0x0145,0x2019, + 0x00ad,0x00b1,0x201c,0x00be,0x00b6,0x00a7,0x00f7,0x201e, + 0x00b0,0x2219,0x00b7,0x00b9,0x00b3,0x00b2,0x25a0,0x00a0 +}; + +static const uint16_t cp850Map[256] = { + 0x0000,0x0001,0x0002,0x0003,0x0004,0x0005,0x0006,0x0007, + 0x0008,0x0009,0x000a,0x000b,0x000c,0x000d,0x000e,0x000f, + 0x0010,0x0011,0x0012,0x0013,0x0014,0x0015,0x0016,0x0017, + 0x0018,0x0019,0x001a,0x001b,0x001c,0x001d,0x001e,0x001f, + 0x0020,0x0021,0x0022,0x0023,0x0024,0x0025,0x0026,0x0027, + 0x0028,0x0029,0x002a,0x002b,0x002c,0x002d,0x002e,0x002f, + 0x0030,0x0031,0x0032,0x0033,0x0034,0x0035,0x0036,0x0037, + 0x0038,0x0039,0x003a,0x003b,0x003c,0x003d,0x003e,0x003f, + 0x0040,0x0041,0x0042,0x0043,0x0044,0x0045,0x0046,0x0047, + 0x0048,0x0049,0x004a,0x004b,0x004c,0x004d,0x004e,0x004f, + 0x0050,0x0051,0x0052,0x0053,0x0054,0x0055,0x0056,0x0057, + 0x0058,0x0059,0x005a,0x005b,0x005c,0x005d,0x005e,0x005f, + 0x0060,0x0061,0x0062,0x0063,0x0064,0x0065,0x0066,0x0067, + 0x0068,0x0069,0x006a,0x006b,0x006c,0x006d,0x006e,0x006f, + 0x0070,0x0071,0x0072,0x0073,0x0074,0x0075,0x0076,0x0077, + 0x0078,0x0079,0x007a,0x007b,0x007c,0x007d,0x007e,0x007f, + 0x00c7,0x00fc,0x00e9,0x00e2,0x00e4,0x00e0,0x00e5,0x00e7, + 0x00ea,0x00eb,0x00e8,0x00ef,0x00ee,0x00ec,0x00c4,0x00c5, + 0x00c9,0x00e6,0x00c6,0x00f4,0x00f6,0x00f2,0x00fb,0x00f9, + 0x00ff,0x00d6,0x00dc,0x00f8,0x00a3,0x00d8,0x00d7,0x0192, + 0x00e1,0x00ed,0x00f3,0x00fa,0x00f1,0x00d1,0x00aa,0x00ba, + 0x00bf,0x00ae,0x00ac,0x00bd,0x00bc,0x00a1,0x00ab,0x00bb, + 0x2591,0x2592,0x2593,0x2502,0x2524,0x00c1,0x00c2,0x00c0, + 0x00a9,0x2563,0x2551,0x2557,0x255d,0x00a2,0x00a5,0x2510, + 0x2514,0x2534,0x252c,0x251c,0x2500,0x253c,0x00e3,0x00c3, + 0x255a,0x2554,0x2569,0x2566,0x2560,0x2550,0x256c,0x00a4, + 0x00f0,0x00d0,0x00ca,0x00cb,0x00c8,0x0131,0x00cd,0x00ce, + 0x00cf,0x2518,0x250c,0x2588,0x2584,0x00a6,0x00cc,0x2580, + 0x00d3,0x00df,0x00d4,0x00d2,0x00f5,0x00d5,0x00b5,0x00fe, + 0x00de,0x00da,0x00db,0x00d9,0x00fd,0x00dd,0x00af,0x00b4, + 0x00ad,0x00b1,0x2017,0x00be,0x00b6,0x00a7,0x00f7,0x00b8, + 0x00b0,0x00a8,0x00b7,0x00b9,0x00b3,0x00b2,0x25a0,0x00a0 +}; + +static const uint16_t cp852Map[256] = { + 0x0000,0x0001,0x0002,0x0003,0x0004,0x0005,0x0006,0x0007, + 0x0008,0x0009,0x000a,0x000b,0x000c,0x000d,0x000e,0x000f, + 0x0010,0x0011,0x0012,0x0013,0x0014,0x0015,0x0016,0x0017, + 0x0018,0x0019,0x001a,0x001b,0x001c,0x001d,0x001e,0x001f, + 0x0020,0x0021,0x0022,0x0023,0x0024,0x0025,0x0026,0x0027, + 0x0028,0x0029,0x002a,0x002b,0x002c,0x002d,0x002e,0x002f, + 0x0030,0x0031,0x0032,0x0033,0x0034,0x0035,0x0036,0x0037, + 0x0038,0x0039,0x003a,0x003b,0x003c,0x003d,0x003e,0x003f, + 0x0040,0x0041,0x0042,0x0043,0x0044,0x0045,0x0046,0x0047, + 0x0048,0x0049,0x004a,0x004b,0x004c,0x004d,0x004e,0x004f, + 0x0050,0x0051,0x0052,0x0053,0x0054,0x0055,0x0056,0x0057, + 0x0058,0x0059,0x005a,0x005b,0x005c,0x005d,0x005e,0x005f, + 0x0060,0x0061,0x0062,0x0063,0x0064,0x0065,0x0066,0x0067, + 0x0068,0x0069,0x006a,0x006b,0x006c,0x006d,0x006e,0x006f, + 0x0070,0x0071,0x0072,0x0073,0x0074,0x0075,0x0076,0x0077, + 0x0078,0x0079,0x007a,0x007b,0x007c,0x007d,0x007e,0x007f, + 0x00c7,0x00fc,0x00e9,0x00e2,0x00e4,0x016f,0x0107,0x00e7, + 0x0142,0x00eb,0x0150,0x0151,0x00ee,0x0179,0x00c4,0x0106, + 0x00c9,0x0139,0x013a,0x00f4,0x00f6,0x013d,0x013e,0x015a, + 0x015b,0x00d6,0x00dc,0x0164,0x0165,0x0141,0x00d7,0x010d, + 0x00e1,0x00ed,0x00f3,0x00fa,0x0104,0x0105,0x017d,0x017e, + 0x0118,0x0119,0x00ac,0x017a,0x010c,0x015f,0x00ab,0x00bb, + 0x2591,0x2592,0x2593,0x2502,0x2524,0x00c1,0x00c2,0x011a, + 0x015e,0x2563,0x2551,0x2557,0x255d,0x017b,0x017c,0x2510, + 0x2514,0x2534,0x252c,0x251c,0x2500,0x253c,0x0102,0x0103, + 0x255a,0x2554,0x2569,0x2566,0x2560,0x2550,0x256c,0x00a4, + 0x0111,0x0110,0x010e,0x00cb,0x010f,0x0147,0x00cd,0x00ce, + 0x011b,0x2518,0x250c,0x2588,0x2584,0x0162,0x016e,0x2580, + 0x00d3,0x00df,0x00d4,0x0143,0x0144,0x0148,0x0160,0x0161, + 0x0154,0x00da,0x0155,0x0170,0x00fd,0x00dd,0x0163,0x00b4, + 0x00ad,0x02dd,0x02db,0x02c7,0x02d8,0x00a7,0x00f7,0x00b8, + 0x00b0,0x00a8,0x02d9,0x0171,0x0158,0x0159,0x25a0,0x00a0 +}; + +static const uint16_t cp855Map[256] = { + 0x0000,0x0001,0x0002,0x0003,0x0004,0x0005,0x0006,0x0007, + 0x0008,0x0009,0x000a,0x000b,0x000c,0x000d,0x000e,0x000f, + 0x0010,0x0011,0x0012,0x0013,0x0014,0x0015,0x0016,0x0017, + 0x0018,0x0019,0x001a,0x001b,0x001c,0x001d,0x001e,0x001f, + 0x0020,0x0021,0x0022,0x0023,0x0024,0x0025,0x0026,0x0027, + 0x0028,0x0029,0x002a,0x002b,0x002c,0x002d,0x002e,0x002f, + 0x0030,0x0031,0x0032,0x0033,0x0034,0x0035,0x0036,0x0037, + 0x0038,0x0039,0x003a,0x003b,0x003c,0x003d,0x003e,0x003f, + 0x0040,0x0041,0x0042,0x0043,0x0044,0x0045,0x0046,0x0047, + 0x0048,0x0049,0x004a,0x004b,0x004c,0x004d,0x004e,0x004f, + 0x0050,0x0051,0x0052,0x0053,0x0054,0x0055,0x0056,0x0057, + 0x0058,0x0059,0x005a,0x005b,0x005c,0x005d,0x005e,0x005f, + 0x0060,0x0061,0x0062,0x0063,0x0064,0x0065,0x0066,0x0067, + 0x0068,0x0069,0x006a,0x006b,0x006c,0x006d,0x006e,0x006f, + 0x0070,0x0071,0x0072,0x0073,0x0074,0x0075,0x0076,0x0077, + 0x0078,0x0079,0x007a,0x007b,0x007c,0x007d,0x007e,0x007f, + 0x0452,0x0402,0x0453,0x0403,0x0451,0x0401,0x0454,0x0404, + 0x0455,0x0405,0x0456,0x0406,0x0457,0x0407,0x0458,0x0408, + 0x0459,0x0409,0x045a,0x040a,0x045b,0x040b,0x045c,0x040c, + 0x045e,0x040e,0x045f,0x040f,0x044e,0x042e,0x044a,0x042a, + 0x0430,0x0410,0x0431,0x0411,0x0446,0x0426,0x0434,0x0414, + 0x0435,0x0415,0x0444,0x0424,0x0433,0x0413,0x00ab,0x00bb, + 0x2591,0x2592,0x2593,0x2502,0x2524,0x0445,0x0425,0x0438, + 0x0418,0x2563,0x2551,0x2557,0x255d,0x0439,0x0419,0x2510, + 0x2514,0x2534,0x252c,0x251c,0x2500,0x253c,0x043a,0x041a, + 0x255a,0x2554,0x2569,0x2566,0x2560,0x2550,0x256c,0x00a4, + 0x043b,0x041b,0x043c,0x041c,0x043d,0x041d,0x043e,0x041e, + 0x043f,0x2518,0x250c,0x2588,0x2584,0x041f,0x044f,0x2580, + 0x042f,0x0440,0x0420,0x0441,0x0421,0x0442,0x0422,0x0443, + 0x0423,0x0436,0x0416,0x0432,0x0412,0x044c,0x042c,0x2116, + 0x00ad,0x044b,0x042b,0x0437,0x0417,0x0448,0x0428,0x044d, + 0x042d,0x0449,0x0429,0x0447,0x0427,0x00a7,0x25a0,0x00a0 +}; + +static const uint16_t cp857Map[256] = { + 0x0000,0x0001,0x0002,0x0003,0x0004,0x0005,0x0006,0x0007, + 0x0008,0x0009,0x000a,0x000b,0x000c,0x000d,0x000e,0x000f, + 0x0010,0x0011,0x0012,0x0013,0x0014,0x0015,0x0016,0x0017, + 0x0018,0x0019,0x001a,0x001b,0x001c,0x001d,0x001e,0x001f, + 0x0020,0x0021,0x0022,0x0023,0x0024,0x0025,0x0026,0x0027, + 0x0028,0x0029,0x002a,0x002b,0x002c,0x002d,0x002e,0x002f, + 0x0030,0x0031,0x0032,0x0033,0x0034,0x0035,0x0036,0x0037, + 0x0038,0x0039,0x003a,0x003b,0x003c,0x003d,0x003e,0x003f, + 0x0040,0x0041,0x0042,0x0043,0x0044,0x0045,0x0046,0x0047, + 0x0048,0x0049,0x004a,0x004b,0x004c,0x004d,0x004e,0x004f, + 0x0050,0x0051,0x0052,0x0053,0x0054,0x0055,0x0056,0x0057, + 0x0058,0x0059,0x005a,0x005b,0x005c,0x005d,0x005e,0x005f, + 0x0060,0x0061,0x0062,0x0063,0x0064,0x0065,0x0066,0x0067, + 0x0068,0x0069,0x006a,0x006b,0x006c,0x006d,0x006e,0x006f, + 0x0070,0x0071,0x0072,0x0073,0x0074,0x0075,0x0076,0x0077, + 0x0078,0x0079,0x007a,0x007b,0x007c,0x007d,0x007e,0x007f, + 0x00c7,0x00fc,0x00e9,0x00e2,0x00e4,0x00e0,0x00e5,0x00e7, + 0x00ea,0x00eb,0x00e8,0x00ef,0x00ee,0x0131,0x00c4,0x00c5, + 0x00c9,0x00e6,0x00c6,0x00f4,0x00f6,0x00f2,0x00fb,0x00f9, + 0x0130,0x00d6,0x00dc,0x00f8,0x00a3,0x00d8,0x015e,0x015f, + 0x00e1,0x00ed,0x00f3,0x00fa,0x00f1,0x00d1,0x011e,0x011f, + 0x00bf,0x00ae,0x00ac,0x00bd,0x00bc,0x00a1,0x00ab,0x00bb, + 0x2591,0x2592,0x2593,0x2502,0x2524,0x00c1,0x00c2,0x00c0, + 0x00a9,0x2563,0x2551,0x2557,0x255d,0x00a2,0x00a5,0x2510, + 0x2514,0x2534,0x252c,0x251c,0x2500,0x253c,0x00e3,0x00c3, + 0x255a,0x2554,0x2569,0x2566,0x2560,0x2550,0x256c,0x00a4, + 0x00ba,0x00aa,0x00ca,0x00cb,0x00c8,0x0000,0x00cd,0x00ce, + 0x00cf,0x2518,0x250c,0x2588,0x2584,0x00a6,0x00cc,0x2580, + 0x00d3,0x00df,0x00d4,0x00d2,0x00f5,0x00d5,0x00b5,0x0000, + 0x00d7,0x00da,0x00db,0x00d9,0x00ec,0x00ff,0x00af,0x00b4, + 0x00ad,0x00b1,0x0000,0x00be,0x00b6,0x00a7,0x00f7,0x00b8, + 0x00b0,0x00a8,0x00b7,0x00b9,0x00b3,0x00b2,0x25a0,0x00a0 +}; + +static const uint16_t cp860Map[256] = { + 0x0000,0x0001,0x0002,0x0003,0x0004,0x0005,0x0006,0x0007, + 0x0008,0x0009,0x000a,0x000b,0x000c,0x000d,0x000e,0x000f, + 0x0010,0x0011,0x0012,0x0013,0x0014,0x0015,0x0016,0x0017, + 0x0018,0x0019,0x001a,0x001b,0x001c,0x001d,0x001e,0x001f, + 0x0020,0x0021,0x0022,0x0023,0x0024,0x0025,0x0026,0x0027, + 0x0028,0x0029,0x002a,0x002b,0x002c,0x002d,0x002e,0x002f, + 0x0030,0x0031,0x0032,0x0033,0x0034,0x0035,0x0036,0x0037, + 0x0038,0x0039,0x003a,0x003b,0x003c,0x003d,0x003e,0x003f, + 0x0040,0x0041,0x0042,0x0043,0x0044,0x0045,0x0046,0x0047, + 0x0048,0x0049,0x004a,0x004b,0x004c,0x004d,0x004e,0x004f, + 0x0050,0x0051,0x0052,0x0053,0x0054,0x0055,0x0056,0x0057, + 0x0058,0x0059,0x005a,0x005b,0x005c,0x005d,0x005e,0x005f, + 0x0060,0x0061,0x0062,0x0063,0x0064,0x0065,0x0066,0x0067, + 0x0068,0x0069,0x006a,0x006b,0x006c,0x006d,0x006e,0x006f, + 0x0070,0x0071,0x0072,0x0073,0x0074,0x0075,0x0076,0x0077, + 0x0078,0x0079,0x007a,0x007b,0x007c,0x007d,0x007e,0x007f, + 0x00c7,0x00fc,0x00e9,0x00e2,0x00e3,0x00e0,0x00c1,0x00e7, + 0x00ea,0x00ca,0x00e8,0x00cd,0x00d4,0x00ec,0x00c3,0x00c2, + 0x00c9,0x00c0,0x00c8,0x00f4,0x00f5,0x00f2,0x00da,0x00f9, + 0x00cc,0x00d5,0x00dc,0x00a2,0x00a3,0x00d9,0x20a7,0x00d3, + 0x00e1,0x00ed,0x00f3,0x00fa,0x00f1,0x00d1,0x00aa,0x00ba, + 0x00bf,0x00d2,0x00ac,0x00bd,0x00bc,0x00a1,0x00ab,0x00bb, + 0x2591,0x2592,0x2593,0x2502,0x2524,0x2561,0x2562,0x2556, + 0x2555,0x2563,0x2551,0x2557,0x255d,0x255c,0x255b,0x2510, + 0x2514,0x2534,0x252c,0x251c,0x2500,0x253c,0x255e,0x255f, + 0x255a,0x2554,0x2569,0x2566,0x2560,0x2550,0x256c,0x2567, + 0x2568,0x2564,0x2565,0x2559,0x2558,0x2552,0x2553,0x256b, + 0x256a,0x2518,0x250c,0x2588,0x2584,0x258c,0x2590,0x2580, + 0x03b1,0x00df,0x0393,0x03c0,0x03a3,0x03c3,0x00b5,0x03c4, + 0x03a6,0x0398,0x03a9,0x03b4,0x221e,0x03c6,0x03b5,0x2229, + 0x2261,0x00b1,0x2265,0x2264,0x2320,0x2321,0x00f7,0x2248, + 0x00b0,0x2219,0x00b7,0x221a,0x207f,0x00b2,0x25a0,0x00a0 +}; + +static const uint16_t cp861Map[256] = { + 0x0000,0x0001,0x0002,0x0003,0x0004,0x0005,0x0006,0x0007, + 0x0008,0x0009,0x000a,0x000b,0x000c,0x000d,0x000e,0x000f, + 0x0010,0x0011,0x0012,0x0013,0x0014,0x0015,0x0016,0x0017, + 0x0018,0x0019,0x001a,0x001b,0x001c,0x001d,0x001e,0x001f, + 0x0020,0x0021,0x0022,0x0023,0x0024,0x0025,0x0026,0x0027, + 0x0028,0x0029,0x002a,0x002b,0x002c,0x002d,0x002e,0x002f, + 0x0030,0x0031,0x0032,0x0033,0x0034,0x0035,0x0036,0x0037, + 0x0038,0x0039,0x003a,0x003b,0x003c,0x003d,0x003e,0x003f, + 0x0040,0x0041,0x0042,0x0043,0x0044,0x0045,0x0046,0x0047, + 0x0048,0x0049,0x004a,0x004b,0x004c,0x004d,0x004e,0x004f, + 0x0050,0x0051,0x0052,0x0053,0x0054,0x0055,0x0056,0x0057, + 0x0058,0x0059,0x005a,0x005b,0x005c,0x005d,0x005e,0x005f, + 0x0060,0x0061,0x0062,0x0063,0x0064,0x0065,0x0066,0x0067, + 0x0068,0x0069,0x006a,0x006b,0x006c,0x006d,0x006e,0x006f, + 0x0070,0x0071,0x0072,0x0073,0x0074,0x0075,0x0076,0x0077, + 0x0078,0x0079,0x007a,0x007b,0x007c,0x007d,0x007e,0x007f, + 0x00c7,0x00fc,0x00e9,0x00e2,0x00e4,0x00e0,0x00e5,0x00e7, + 0x00ea,0x00eb,0x00e8,0x00d0,0x00f0,0x00de,0x00c4,0x00c5, + 0x00c9,0x00e6,0x00c6,0x00f4,0x00f6,0x00fe,0x00fb,0x00dd, + 0x00fd,0x00d6,0x00dc,0x00f8,0x00a3,0x00d8,0x20a7,0x0192, + 0x00e1,0x00ed,0x00f3,0x00fa,0x00c1,0x00cd,0x00d3,0x00da, + 0x00bf,0x2310,0x00ac,0x00bd,0x00bc,0x00a1,0x00ab,0x00bb, + 0x2591,0x2592,0x2593,0x2502,0x2524,0x2561,0x2562,0x2556, + 0x2555,0x2563,0x2551,0x2557,0x255d,0x255c,0x255b,0x2510, + 0x2514,0x2534,0x252c,0x251c,0x2500,0x253c,0x255e,0x255f, + 0x255a,0x2554,0x2569,0x2566,0x2560,0x2550,0x256c,0x2567, + 0x2568,0x2564,0x2565,0x2559,0x2558,0x2552,0x2553,0x256b, + 0x256a,0x2518,0x250c,0x2588,0x2584,0x258c,0x2590,0x2580, + 0x03b1,0x00df,0x0393,0x03c0,0x03a3,0x03c3,0x00b5,0x03c4, + 0x03a6,0x0398,0x03a9,0x03b4,0x221e,0x03c6,0x03b5,0x2229, + 0x2261,0x00b1,0x2265,0x2264,0x2320,0x2321,0x00f7,0x2248, + 0x00b0,0x2219,0x00b7,0x221a,0x207f,0x00b2,0x25a0,0x00a0 +}; + +static const uint16_t cp862Map[256] = { + 0x0000,0x0001,0x0002,0x0003,0x0004,0x0005,0x0006,0x0007, + 0x0008,0x0009,0x000a,0x000b,0x000c,0x000d,0x000e,0x000f, + 0x0010,0x0011,0x0012,0x0013,0x0014,0x0015,0x0016,0x0017, + 0x0018,0x0019,0x001a,0x001b,0x001c,0x001d,0x001e,0x001f, + 0x0020,0x0021,0x0022,0x0023,0x0024,0x0025,0x0026,0x0027, + 0x0028,0x0029,0x002a,0x002b,0x002c,0x002d,0x002e,0x002f, + 0x0030,0x0031,0x0032,0x0033,0x0034,0x0035,0x0036,0x0037, + 0x0038,0x0039,0x003a,0x003b,0x003c,0x003d,0x003e,0x003f, + 0x0040,0x0041,0x0042,0x0043,0x0044,0x0045,0x0046,0x0047, + 0x0048,0x0049,0x004a,0x004b,0x004c,0x004d,0x004e,0x004f, + 0x0050,0x0051,0x0052,0x0053,0x0054,0x0055,0x0056,0x0057, + 0x0058,0x0059,0x005a,0x005b,0x005c,0x005d,0x005e,0x005f, + 0x0060,0x0061,0x0062,0x0063,0x0064,0x0065,0x0066,0x0067, + 0x0068,0x0069,0x006a,0x006b,0x006c,0x006d,0x006e,0x006f, + 0x0070,0x0071,0x0072,0x0073,0x0074,0x0075,0x0076,0x0077, + 0x0078,0x0079,0x007a,0x007b,0x007c,0x007d,0x007e,0x007f, + 0x05d0,0x05d1,0x05d2,0x05d3,0x05d4,0x05d5,0x05d6,0x05d7, + 0x05d8,0x05d9,0x05da,0x05db,0x05dc,0x05dd,0x05de,0x05df, + 0x05e0,0x05e1,0x05e2,0x05e3,0x05e4,0x05e5,0x05e6,0x05e7, + 0x05e8,0x05e9,0x05ea,0x00a2,0x00a3,0x00a5,0x20a7,0x0192, + 0x00e1,0x00ed,0x00f3,0x00fa,0x00f1,0x00d1,0x00aa,0x00ba, + 0x00bf,0x2310,0x00ac,0x00bd,0x00bc,0x00a1,0x00ab,0x00bb, + 0x2591,0x2592,0x2593,0x2502,0x2524,0x2561,0x2562,0x2556, + 0x2555,0x2563,0x2551,0x2557,0x255d,0x255c,0x255b,0x2510, + 0x2514,0x2534,0x252c,0x251c,0x2500,0x253c,0x255e,0x255f, + 0x255a,0x2554,0x2569,0x2566,0x2560,0x2550,0x256c,0x2567, + 0x2568,0x2564,0x2565,0x2559,0x2558,0x2552,0x2553,0x256b, + 0x256a,0x2518,0x250c,0x2588,0x2584,0x258c,0x2590,0x2580, + 0x03b1,0x00df,0x0393,0x03c0,0x03a3,0x03c3,0x00b5,0x03c4, + 0x03a6,0x0398,0x03a9,0x03b4,0x221e,0x03c6,0x03b5,0x2229, + 0x2261,0x00b1,0x2265,0x2264,0x2320,0x2321,0x00f7,0x2248, + 0x00b0,0x2219,0x00b7,0x221a,0x207f,0x00b2,0x25a0,0x00a0 +}; + +static const uint16_t cp863Map[256] = { + 0x0000,0x0001,0x0002,0x0003,0x0004,0x0005,0x0006,0x0007, + 0x0008,0x0009,0x000a,0x000b,0x000c,0x000d,0x000e,0x000f, + 0x0010,0x0011,0x0012,0x0013,0x0014,0x0015,0x0016,0x0017, + 0x0018,0x0019,0x001a,0x001b,0x001c,0x001d,0x001e,0x001f, + 0x0020,0x0021,0x0022,0x0023,0x0024,0x0025,0x0026,0x0027, + 0x0028,0x0029,0x002a,0x002b,0x002c,0x002d,0x002e,0x002f, + 0x0030,0x0031,0x0032,0x0033,0x0034,0x0035,0x0036,0x0037, + 0x0038,0x0039,0x003a,0x003b,0x003c,0x003d,0x003e,0x003f, + 0x0040,0x0041,0x0042,0x0043,0x0044,0x0045,0x0046,0x0047, + 0x0048,0x0049,0x004a,0x004b,0x004c,0x004d,0x004e,0x004f, + 0x0050,0x0051,0x0052,0x0053,0x0054,0x0055,0x0056,0x0057, + 0x0058,0x0059,0x005a,0x005b,0x005c,0x005d,0x005e,0x005f, + 0x0060,0x0061,0x0062,0x0063,0x0064,0x0065,0x0066,0x0067, + 0x0068,0x0069,0x006a,0x006b,0x006c,0x006d,0x006e,0x006f, + 0x0070,0x0071,0x0072,0x0073,0x0074,0x0075,0x0076,0x0077, + 0x0078,0x0079,0x007a,0x007b,0x007c,0x007d,0x007e,0x007f, + 0x00c7,0x00fc,0x00e9,0x00e2,0x00c2,0x00e0,0x00b6,0x00e7, + 0x00ea,0x00eb,0x00e8,0x00ef,0x00ee,0x2017,0x00c0,0x00a7, + 0x00c9,0x00c8,0x00ca,0x00f4,0x00cb,0x00cf,0x00fb,0x00f9, + 0x00a4,0x00d4,0x00dc,0x00a2,0x00a3,0x00d9,0x00db,0x0192, + 0x00a6,0x00b4,0x00f3,0x00fa,0x00a8,0x00b8,0x00b3,0x00af, + 0x00ce,0x2310,0x00ac,0x00bd,0x00bc,0x00be,0x00ab,0x00bb, + 0x2591,0x2592,0x2593,0x2502,0x2524,0x2561,0x2562,0x2556, + 0x2555,0x2563,0x2551,0x2557,0x255d,0x255c,0x255b,0x2510, + 0x2514,0x2534,0x252c,0x251c,0x2500,0x253c,0x255e,0x255f, + 0x255a,0x2554,0x2569,0x2566,0x2560,0x2550,0x256c,0x2567, + 0x2568,0x2564,0x2565,0x2559,0x2558,0x2552,0x2553,0x256b, + 0x256a,0x2518,0x250c,0x2588,0x2584,0x258c,0x2590,0x2580, + 0x03b1,0x00df,0x0393,0x03c0,0x03a3,0x03c3,0x00b5,0x03c4, + 0x03a6,0x0398,0x03a9,0x03b4,0x221e,0x03c6,0x03b5,0x2229, + 0x2261,0x00b1,0x2265,0x2264,0x2320,0x2321,0x00f7,0x2248, + 0x00b0,0x2219,0x00b7,0x221a,0x207f,0x00b2,0x25a0,0x00a0 +}; + +static const uint16_t cp864Map[256] = { + 0x0000,0x0001,0x0002,0x0003,0x0004,0x0005,0x0006,0x0007, + 0x0008,0x0009,0x000a,0x000b,0x000c,0x000d,0x000e,0x000f, + 0x0010,0x0011,0x0012,0x0013,0x0014,0x0015,0x0016,0x0017, + 0x0018,0x0019,0x001a,0x001b,0x001c,0x001d,0x001e,0x001f, + 0x0020,0x0021,0x0022,0x0023,0x0024,0x066a,0x0026,0x0027, + 0x0028,0x0029,0x002a,0x002b,0x002c,0x002d,0x002e,0x002f, + 0x0030,0x0031,0x0032,0x0033,0x0034,0x0035,0x0036,0x0037, + 0x0038,0x0039,0x003a,0x003b,0x003c,0x003d,0x003e,0x003f, + 0x0040,0x0041,0x0042,0x0043,0x0044,0x0045,0x0046,0x0047, + 0x0048,0x0049,0x004a,0x004b,0x004c,0x004d,0x004e,0x004f, + 0x0050,0x0051,0x0052,0x0053,0x0054,0x0055,0x0056,0x0057, + 0x0058,0x0059,0x005a,0x005b,0x005c,0x005d,0x005e,0x005f, + 0x0060,0x0061,0x0062,0x0063,0x0064,0x0065,0x0066,0x0067, + 0x0068,0x0069,0x006a,0x006b,0x006c,0x006d,0x006e,0x006f, + 0x0070,0x0071,0x0072,0x0073,0x0074,0x0075,0x0076,0x0077, + 0x0078,0x0079,0x007a,0x007b,0x007c,0x007d,0x007e,0x007f, + 0x00b0,0x00b7,0x2219,0x221a,0x2592,0x2500,0x2502,0x253c, + 0x2524,0x252c,0x251c,0x2534,0x2510,0x250c,0x2514,0x2518, + 0x03b2,0x221e,0x03c6,0x00b1,0x00bd,0x00bc,0x2248,0x00ab, + 0x00bb,0xfef7,0xfef8,0x0000,0x0000,0xfefb,0xfefc,0x0000, + 0x00a0,0x00ad,0xfe82,0x00a3,0x00a4,0xfe84,0x0000,0x0000, + 0xfe8e,0xfe8f,0xfe95,0xfe99,0x060c,0xfe9d,0xfea1,0xfea5, + 0x0660,0x0661,0x0662,0x0663,0x0664,0x0665,0x0666,0x0667, + 0x0668,0x0669,0xfed1,0x061b,0xfeb1,0xfeb5,0xfeb9,0x061f, + 0x00a2,0xfe80,0xfe81,0xfe83,0xfe85,0xfeca,0xfe8b,0xfe8d, + 0xfe91,0xfe93,0xfe97,0xfe9b,0xfe9f,0xfea3,0xfea7,0xfea9, + 0xfeab,0xfead,0xfeaf,0xfeb3,0xfeb7,0xfebb,0xfebf,0xfec1, + 0xfec5,0xfecb,0xfecf,0x00a6,0x00ac,0x00f7,0x00d7,0xfec9, + 0x0640,0xfed3,0xfed7,0xfedb,0xfedf,0xfee3,0xfee7,0xfeeb, + 0xfeed,0xfeef,0xfef3,0xfebd,0xfecc,0xfece,0xfecd,0xfee1, + 0xfe7d,0x0651,0xfee5,0xfee9,0xfeec,0xfef0,0xfef2,0xfed0, + 0xfed5,0xfef5,0xfef6,0xfedd,0xfed9,0xfef1,0x25a0,0x00a0 +}; + +static const uint16_t cp865Map[256] = { + 0x0000,0x0001,0x0002,0x0003,0x0004,0x0005,0x0006,0x0007, + 0x0008,0x0009,0x000a,0x000b,0x000c,0x000d,0x000e,0x000f, + 0x0010,0x0011,0x0012,0x0013,0x0014,0x0015,0x0016,0x0017, + 0x0018,0x0019,0x001a,0x001b,0x001c,0x001d,0x001e,0x001f, + 0x0020,0x0021,0x0022,0x0023,0x0024,0x0025,0x0026,0x0027, + 0x0028,0x0029,0x002a,0x002b,0x002c,0x002d,0x002e,0x002f, + 0x0030,0x0031,0x0032,0x0033,0x0034,0x0035,0x0036,0x0037, + 0x0038,0x0039,0x003a,0x003b,0x003c,0x003d,0x003e,0x003f, + 0x0040,0x0041,0x0042,0x0043,0x0044,0x0045,0x0046,0x0047, + 0x0048,0x0049,0x004a,0x004b,0x004c,0x004d,0x004e,0x004f, + 0x0050,0x0051,0x0052,0x0053,0x0054,0x0055,0x0056,0x0057, + 0x0058,0x0059,0x005a,0x005b,0x005c,0x005d,0x005e,0x005f, + 0x0060,0x0061,0x0062,0x0063,0x0064,0x0065,0x0066,0x0067, + 0x0068,0x0069,0x006a,0x006b,0x006c,0x006d,0x006e,0x006f, + 0x0070,0x0071,0x0072,0x0073,0x0074,0x0075,0x0076,0x0077, + 0x0078,0x0079,0x007a,0x007b,0x007c,0x007d,0x007e,0x007f, + 0x00c7,0x00fc,0x00e9,0x00e2,0x00e4,0x00e0,0x00e5,0x00e7, + 0x00ea,0x00eb,0x00e8,0x00ef,0x00ee,0x00ec,0x00c4,0x00c5, + 0x00c9,0x00e6,0x00c6,0x00f4,0x00f6,0x00f2,0x00fb,0x00f9, + 0x00ff,0x00d6,0x00dc,0x00f8,0x00a3,0x00d8,0x20a7,0x0192, + 0x00e1,0x00ed,0x00f3,0x00fa,0x00f1,0x00d1,0x00aa,0x00ba, + 0x00bf,0x2310,0x00ac,0x00bd,0x00bc,0x00a1,0x00ab,0x00a4, + 0x2591,0x2592,0x2593,0x2502,0x2524,0x2561,0x2562,0x2556, + 0x2555,0x2563,0x2551,0x2557,0x255d,0x255c,0x255b,0x2510, + 0x2514,0x2534,0x252c,0x251c,0x2500,0x253c,0x255e,0x255f, + 0x255a,0x2554,0x2569,0x2566,0x2560,0x2550,0x256c,0x2567, + 0x2568,0x2564,0x2565,0x2559,0x2558,0x2552,0x2553,0x256b, + 0x256a,0x2518,0x250c,0x2588,0x2584,0x258c,0x2590,0x2580, + 0x03b1,0x00df,0x0393,0x03c0,0x03a3,0x03c3,0x00b5,0x03c4, + 0x03a6,0x0398,0x03a9,0x03b4,0x221e,0x03c6,0x03b5,0x2229, + 0x2261,0x00b1,0x2265,0x2264,0x2320,0x2321,0x00f7,0x2248, + 0x00b0,0x2219,0x00b7,0x221a,0x207f,0x00b2,0x25a0,0x00a0 +}; + +static const uint16_t cp866Map[256] = { + 0x0000,0x0001,0x0002,0x0003,0x0004,0x0005,0x0006,0x0007, + 0x0008,0x0009,0x000a,0x000b,0x000c,0x000d,0x000e,0x000f, + 0x0010,0x0011,0x0012,0x0013,0x0014,0x0015,0x0016,0x0017, + 0x0018,0x0019,0x001a,0x001b,0x001c,0x001d,0x001e,0x001f, + 0x0020,0x0021,0x0022,0x0023,0x0024,0x0025,0x0026,0x0027, + 0x0028,0x0029,0x002a,0x002b,0x002c,0x002d,0x002e,0x002f, + 0x0030,0x0031,0x0032,0x0033,0x0034,0x0035,0x0036,0x0037, + 0x0038,0x0039,0x003a,0x003b,0x003c,0x003d,0x003e,0x003f, + 0x0040,0x0041,0x0042,0x0043,0x0044,0x0045,0x0046,0x0047, + 0x0048,0x0049,0x004a,0x004b,0x004c,0x004d,0x004e,0x004f, + 0x0050,0x0051,0x0052,0x0053,0x0054,0x0055,0x0056,0x0057, + 0x0058,0x0059,0x005a,0x005b,0x005c,0x005d,0x005e,0x005f, + 0x0060,0x0061,0x0062,0x0063,0x0064,0x0065,0x0066,0x0067, + 0x0068,0x0069,0x006a,0x006b,0x006c,0x006d,0x006e,0x006f, + 0x0070,0x0071,0x0072,0x0073,0x0074,0x0075,0x0076,0x0077, + 0x0078,0x0079,0x007a,0x007b,0x007c,0x007d,0x007e,0x007f, + 0x0410,0x0411,0x0412,0x0413,0x0414,0x0415,0x0416,0x0417, + 0x0418,0x0419,0x041a,0x041b,0x041c,0x041d,0x041e,0x041f, + 0x0420,0x0421,0x0422,0x0423,0x0424,0x0425,0x0426,0x0427, + 0x0428,0x0429,0x042a,0x042b,0x042c,0x042d,0x042e,0x042f, + 0x0430,0x0431,0x0432,0x0433,0x0434,0x0435,0x0436,0x0437, + 0x0438,0x0439,0x043a,0x043b,0x043c,0x043d,0x043e,0x043f, + 0x2591,0x2592,0x2593,0x2502,0x2524,0x2561,0x2562,0x2556, + 0x2555,0x2563,0x2551,0x2557,0x255d,0x255c,0x255b,0x2510, + 0x2514,0x2534,0x252c,0x251c,0x2500,0x253c,0x255e,0x255f, + 0x255a,0x2554,0x2569,0x2566,0x2560,0x2550,0x256c,0x2567, + 0x2568,0x2564,0x2565,0x2559,0x2558,0x2552,0x2553,0x256b, + 0x256a,0x2518,0x250c,0x2588,0x2584,0x258c,0x2590,0x2580, + 0x0440,0x0441,0x0442,0x0443,0x0444,0x0445,0x0446,0x0447, + 0x0448,0x0449,0x044a,0x044b,0x044c,0x044d,0x044e,0x044f, + 0x0401,0x0451,0x0404,0x0454,0x0407,0x0457,0x040e,0x045e, + 0x00b0,0x2219,0x00b7,0x221a,0x2116,0x00a4,0x25a0,0x00a0 +}; + + +static const struct { + uint16_t code; + const uint16_t *map; +} maps[] = { + { 437, cp437Map }, + { 737, cp737Map }, + { 775, cp775Map }, + { 850, cp850Map }, + { 852, cp852Map }, + { 855, cp855Map }, + { 857, cp857Map }, + { 860, cp860Map }, + { 861, cp861Map }, + { 862, cp862Map }, + { 863, cp863Map }, + { 864, cp864Map }, + { 865, cp865Map }, + { 866, cp866Map }, + { -1, NULL } +}; + + +/* Select a ASCII->Unicode mapping by CP number */ +const uint16_t * +select_codepage(uint16_t code) +{ + int i; + + for (i = 0; maps[i].code != -1; i++) + if (maps[i].code == code) return(maps[i].map); + + if (code == 0) + return(maps[0].map); + + //ERRLOG("CPMAP: unsupported code page %i, using CP437...\n", code); + + return(maps[0].map); +} diff --git a/src/printer/prt_devs.h b/src/printer/prt_devs.h new file mode 100644 index 000000000..e43ec67cc --- /dev/null +++ b/src/printer/prt_devs.h @@ -0,0 +1,2 @@ +extern const lpt_device_t lpt_prt_text_device; +extern const lpt_device_t lpt_prt_escp_device; \ No newline at end of file diff --git a/src/printer/prt_escp.c b/src/printer/prt_escp.c new file mode 100644 index 000000000..9b400b793 --- /dev/null +++ b/src/printer/prt_escp.c @@ -0,0 +1,2006 @@ +/* + * VARCem Virtual ARchaeological Computer EMulator. + * An emulator of (mostly) x86-based PC systems and devices, + * using the ISA,EISA,VLB,MCA and PCI system buses, roughly + * spanning the era between 1981 and 1995. + * + * This file is part of the VARCem Project. + * + * Implementation of the Generic ESC/P Dot-Matrix printer. + * + * Version: @(#)prt_escp.c 1.0.3 2018/10/06 + * + * Authors: Michael Drüing, + * Fred N. van Kempen, + * + * Based on code by Frederic Weymann (originally for DosBox.) + * + * Copyright 2018 Michael Drüing. + * Copyright 2018 Fred N. van Kempen. + * + * Redistribution and use in source and binary forms, with + * or without modification, are permitted provided that the + * following conditions are met: + * + * 1. Redistributions of source code must retain the entire + * above notice, this list of conditions and the following + * disclaimer. + * + * 2. Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names + * of its contributors may be used to endorse or promote + * products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#include +#include +#include +#include +#include +#include +#include +#include FT_FREETYPE_H +#include "../86box.h" +#include "../cpu/cpu.h" +#include "../machine/machine.h" +#include "../timer.h" +#include "../mem.h" +#include "../rom.h" +#include "../plat.h" +#include "../plat_dynld.h" +#include "../ui.h" +#include "../lpt.h" +#include "png_struct.h" +#include "printer.h" +#include "prt_devs.h" + + +/* Default page values (for now.) */ +#define COLOR_BLACK 7<<5 +#define PAGE_WIDTH 8.5 /* standard U.S. Letter */ +#define PAGE_HEIGHT 11 +#define PAGE_LMARGIN 0.0 +#define PAGE_RMARGIN PAGE_WIDTH +#define PAGE_TMARGIN 0.0 +#define PAGE_BMARGIN PAGE_HEIGHT +#define PAGE_DPI 360 +#define PAGE_CPI 10.0 /* standard 10 cpi */ +#define PAGE_LPI 6.0 /* standard 6 lpi */ + + +#ifdef _WIN32 +# define PATH_FREETYPE_DLL "libfreetype-6.dll" +#else +# define PATH_FREETYPE_DLL "libfreetype.so.6" +#endif + + +/* FreeType library handles - global so they can be shared. */ +FT_Library ft_lib = NULL; +void *ft_handle = NULL; + +static int (*ft_Init_FreeType)(FT_Library *alibrary); +static int (*ft_Done_Face)(FT_Face face); +static int (*ft_New_Face)(FT_Library library, const char *filepathname, + FT_Long face_index, FT_Face *aface); +static int (*ft_Set_Char_Size)(FT_Face face, FT_F26Dot6 char_width, + FT_F26Dot6 char_height, + FT_UInt horz_resolution, + FT_UInt vert_resolution); +static int (*ft_Set_Transform)(FT_Face face, FT_Matrix *matrix, + FT_Vector *delta); +static int (*ft_Get_Char_Index)(FT_Face face, FT_ULong charcode); +static int (*ft_Load_Glyph)(FT_Face face, FT_UInt glyph_index, + FT_Int32 load_flags); +static int (*ft_Render_Glyph)(FT_GlyphSlot slot, + FT_Render_Mode render_mode); + + +static dllimp_t ft_imports[] = { + { "FT_Init_FreeType", &ft_Init_FreeType }, + { "FT_New_Face", &ft_New_Face }, + { "FT_Done_Face", &ft_Done_Face }, + { "FT_Set_Char_Size", &ft_Set_Char_Size }, + { "FT_Set_Transform", &ft_Set_Transform }, + { "FT_Get_Char_Index", &ft_Get_Char_Index }, + { "FT_Load_Glyph", &ft_Load_Glyph }, + { "FT_Render_Glyph", &ft_Render_Glyph }, + { NULL, NULL } +}; + + +/* The fonts. */ +#define FONT_DEFAULT 0 +#define FONT_ROMAN 1 +#define FONT_SANSSERIF 2 +#define FONT_COURIER 3 +#define FONT_SCRIPT 4 +#define FONT_OCRA 5 +#define FONT_OCRB 6 + +/* Font styles. */ +#define STYLE_PROP 0x0001 +#define STYLE_CONDENSED 0x0002 +#define STYLE_BOLD 0x0004 +#define STYLE_DOUBLESTRIKE 0x0008 +#define STYLE_DOUBLEWIDTH 0x0010 +#define STYLE_ITALICS 0x0020 +#define STYLE_UNDERLINE 0x0040 +#define STYLE_SUPERSCRIPT 0x0080 +#define STYLE_SUBSCRIPT 0x0100 +#define STYLE_STRIKETHROUGH 0x0200 +#define STYLE_OVERSCORE 0x0400 +#define STYLE_DOUBLEWIDTHONELINE 0x0800 +#define STYLE_DOUBLEHEIGHT 0x1000 + +/* Underlining styles. */ +#define SCORE_NONE 0x00 +#define SCORE_SINGLE 0x01 +#define SCORE_DOUBLE 0x02 +#define SCORE_SINGLEBROKEN 0x05 +#define SCORE_DOUBLEBROKEN 0x06 + +/* Print quality. */ +#define QUALITY_DRAFT 0x01 +#define QUALITY_LQ 0x02 + +/* Typefaces. */ +#define TYPEFACE_ROMAN 0 +#define TYPEFACE_SANSSERIF 1 +#define TYPEFACE_COURIER 2 +#define TYPEFACE_PRESTIGE 3 +#define TYPEFACE_SCRIPT 4 +#define TYPEFACE_OCRB 5 +#define TYPEFACE_OCRA 6 +#define TYPEFACE_ORATOR 7 +#define TYPEFACE_ORATORS 8 +#define TYPEFACE_SCRIPTC 9 +#define TYPEFACE_ROMANT 10 +#define TYPEFACE_SANSSERIFH 11 +#define TYPEFACE_SVBUSABA 30 +#define TYPEFACE_SVJITTRA 31 + + +/* Some helper macros. */ +#define PARAM16(x) (dev->esc_parms[x+1] * 256 + dev->esc_parms[x]) +#define PIXX ((uint32_t)floor(dev->curr_x * dev->dpi + 0.5)) +#define PIXY ((uint32_t)floor(dev->curr_y * dev->dpi + 0.5)) + + +typedef struct { + int8_t dirty; /* has the page been printed on? */ + char pad; + + uint16_t w; /* size and pitch //INFO */ + uint16_t h; + uint16_t pitch; + + uint8_t *pixels; /* grayscale pixel data */ +} psurface_t; + + +typedef struct { + const char *name; + + uint8_t color; + + /* page data (TODO: make configurable) */ + double page_width, /* all in inches */ + page_height, + left_margin, + top_margin, + right_margin, + bottom_margin; + uint16_t dpi; + double cpi; /* defined chars per inch */ + double lpi; /* defined lines per inch */ + + /* font data */ + double actual_cpi; /* actual cpi as with current font */ + double linespacing; /* in inch */ + double hmi; /* hor. motion index (inch); overrides CPI */ + + /* tabstops */ + double horizontal_tabs[32]; + int16_t num_horizontal_tabs; + double vertical_tabs[16]; + int16_t num_vertical_tabs; + + /* bit graphics data */ + uint16_t bg_h_density; /* in dpi */ + uint16_t bg_v_density; /* in dpi */ + int8_t bg_adjacent; /* print adjacent pixels (ignored) */ + uint8_t bg_bytes_per_column; + uint16_t bg_remaining_bytes; /* #bytes left before img is complete */ + uint8_t bg_column[6]; /* #bytes of the current and last col */ + uint8_t bg_bytes_read; /* #bytes read so far for current col */ + + /* handshake data */ + uint8_t data; + int8_t ack; + int8_t select; + int8_t busy; + int8_t int_pending; + int8_t error; + int8_t autofeed; + + /* ESC command data */ + int8_t esc_seen; /* set to 1 if an ESC char was seen */ + int8_t fss_seen; + uint16_t esc_pending; /* in which ESC command are we */ + uint8_t esc_parms_req; + uint8_t esc_parms_curr; + uint8_t esc_parms[10]; /* 10 should be enough for everybody */ + + /* internal page data */ + wchar_t fontpath[1024]; + wchar_t pagepath[1024]; + psurface_t *page; + double curr_x, curr_y; /* print head position (inch) */ + uint16_t current_font; + FT_Face fontface; + int8_t lq_typeface; + int8_t font_style; + int8_t print_quality; + uint8_t font_score; + double extra_intra_space; /* extra spacing between chars (inch) */ + + /* other internal data */ + uint16_t char_tables[4]; /* the character tables for ESC t */ + uint16_t curr_char_table; /* the active char table index */ + uint16_t curr_cpmap[256]; /* current ASCII->Unicode map table */ + + int8_t multipoint_mode; /* multipoint mode, ESC X */ + double multipoint_size; /* size of font, in points */ + double multipoint_cpi; /* chars per inch in multipoint mode */ + + uint8_t density_k; /* density modes for ESC K/L/Y/Z */ + uint8_t density_l; + uint8_t density_y; + uint8_t density_z; + + int8_t print_upper_control; /* ESC 6, ESC 7 */ + int8_t print_everything_count; /* for ESC ( ^ */ + + double defined_unit; /* internal unit for some ESC/P + * commands. -1 = use default */ + + int8_t msb; /* MSB mode, -1 = off */ +} escp_t; + + +static void +new_page(escp_t *dev, int8_t save, int8_t resetx); + +/* Codepage table, needed for ESC t ( */ +static const uint16_t codepages[15] = { + 0, 437, 932, 850, 851, 853, 855, 860, + 863, 865, 852, 857, 862, 864, 866 +}; + + +/* "patches" to the codepage for the international charsets + * these bytes patch the following 12 positions of the char table, in order: + * 0x23 0x24 0x40 0x5b 0x5c 0x5d 0x5e 0x60 0x7b 0x7c 0x7d 0x7e + * TODO: Implement the missing international charsets + */ +static const uint16_t intCharSets[15][12] = { + { 0x0023, 0x0024, 0x0040, 0x005b, 0x005c, 0x005d, /* 0 USA */ + 0x005e, 0x0060, 0x007b, 0x007c, 0x007d, 0x007e }, + + { 0x0023, 0x0024, 0x00e0, 0x00ba, 0x00e7, 0x00a7, /* 1 France */ + 0x005e, 0x0060, 0x00e9, 0x00f9, 0x00e8, 0x00a8 }, + + { 0x0023, 0x0024, 0x00a7, 0x00c4, 0x00d6, 0x00dc, /* 2 Germany */ + 0x005e, 0x0060, 0x00e4, 0x00f6, 0x00fc, 0x00df }, + + { 0x00a3, 0x0024, 0x0040, 0x005b, 0x005c, 0x005d, /* 3 UK */ + 0x005e, 0x0060, 0x007b, 0x007c, 0x007d, 0x007e }, + + { 0x0023, 0x0024, 0x0040, 0x00c6, 0x00d8, 0x00c5, /* 4 Denmark (1) */ + 0x005e, 0x0060, 0x00e6, 0x00f8, 0x00e5, 0x007e }, + + { 0x0023, 0x00a4, 0x00c9, 0x00c4, 0x00d6, 0x00c5, /* 5 Sweden */ + 0x00dc, 0x00e9, 0x00e4, 0x00f6, 0x00e5, 0x00fc }, + + { 0x0023, 0x0024, 0x0040, 0x00ba, 0x005c, 0x00e9, /* 6 Italy */ + 0x005e, 0x00f9, 0x00e0, 0x00f2, 0x00e8, 0x00ec }, + + { 0x0023, 0x0024, 0x0040, 0x005b, 0x005c, 0x005d, /* 7 Spain 1 */ + 0x005e, 0x0060, 0x007b, 0x007c, 0x007d, 0x007e }, /* TODO */ + + { 0x0023, 0x0024, 0x0040, 0x005b, 0x005c, 0x005d, /* 8 Japan (English) */ + 0x005e, 0x0060, 0x007b, 0x007c, 0x007d, 0x007e }, /* TODO */ + + { 0x0023, 0x0024, 0x0040, 0x005b, 0x005c, 0x005d, /* 9 Norway */ + 0x005e, 0x0060, 0x007b, 0x007c, 0x007d, 0x007e }, /* TODO */ + + { 0x0023, 0x0024, 0x0040, 0x005b, 0x005c, 0x005d, /* 10 Denmark (2) */ + 0x005e, 0x0060, 0x007b, 0x007c, 0x007d, 0x007e }, /* TODO */ + + { 0x0023, 0x0024, 0x0040, 0x005b, 0x005c, 0x005d, /* 11 Spain (2) */ + 0x005e, 0x0060, 0x007b, 0x007c, 0x007d, 0x007e }, /* TODO */ + + { 0x0023, 0x0024, 0x0040, 0x005b, 0x005c, 0x005d, /* 12 Latin America */ + 0x005e, 0x0060, 0x007b, 0x007c, 0x007d, 0x007e }, /* TODO */ + + { 0x0023, 0x0024, 0x0040, 0x005b, 0x005c, 0x005d, /* 13 Korea */ + 0x005e, 0x0060, 0x007b, 0x007c, 0x007d, 0x007e }, /* TODO */ + + { 0x0023, 0x0024, 0x00a7, 0x00c4, 0x0027, 0x0022, /* 14 Legal */ + 0x00b6, 0x0060, 0x00a9, 0x00ae, 0x2020, 0x2122 } +}; + + +/* Select a ASCII->Unicode mapping by CP number */ +static void +init_codepage(escp_t *dev, uint16_t num) +{ + const uint16_t *cp; + + /* Get the codepage map for this number. */ + cp = select_codepage(num); + + /* Copy the map over since it might get modified later. */ + memcpy(dev->curr_cpmap, cp, 256 * sizeof(uint16_t)); +} + + +static void +update_font(escp_t *dev) +{ + wchar_t path[1024]; + wchar_t *fn; + char temp[1024]; + FT_Matrix matrix; + double hpoints = 10.5; + double vpoints = 10.5; + + /* We need the FreeType library. */ + if (ft_lib == NULL) return; + + /* Release current font if we have one. */ + if (dev->fontface) + ft_Done_Face(dev->fontface); + + if (dev->print_quality == QUALITY_DRAFT) { + fn = FONT_FILE_DOTMATRIX; + } + else { + switch (dev->lq_typeface) { + case TYPEFACE_ROMAN: + //pclog("Roman TTF\n"); + fn = FONT_FILE_ROMAN; + break; + + case TYPEFACE_SANSSERIF: + //pclog("Sansserif TTF\n"); + fn = FONT_FILE_SANSSERIF; + break; + + case TYPEFACE_COURIER: + //pclog("Courier TTF\n"); + fn = FONT_FILE_COURIER; + break; + + case TYPEFACE_SCRIPT: + //pclog("Script TTF\n"); + fn = FONT_FILE_SCRIPT; + break; + + case TYPEFACE_OCRA: + //pclog("Ocra TTF\n"); + fn = FONT_FILE_OCRA; + break; + + case TYPEFACE_OCRB: + //pclog("Ocrb TTF\n"); + fn = FONT_FILE_OCRB; + break; + + default: + //pclog("Dot matrix TTF\n"); + fn = FONT_FILE_DOTMATRIX; + } + } + + /* Create a full pathname for the ROM file. */ + wcscpy(path, dev->fontpath); + wcscat(path, fn); + + /* Convert (back) to ANSI for the FreeType API. */ + wcstombs(temp, path, sizeof(temp)); + + //pclog("Font face=%d\n", dev->fontface); + + /* Load the new font. */ + if (ft_New_Face(ft_lib, temp, 0, &dev->fontface)) { + //pclog("ESC/P: unable to load font '%s'\n", temp); + //pclog("ESC/P: text printing disabled\n"); + dev->fontface = 0; + } + + if (dev->multipoint_mode == 0) { + dev->actual_cpi = dev->cpi; + + if ((dev->cpi != 10.0) && !(dev->font_style & STYLE_CONDENSED)) { + hpoints *= 10.0 / dev->cpi; + vpoints *= 10.0 / dev->cpi; + } + + if (! (dev->font_style & STYLE_PROP)) { + if ((dev->cpi == 10.0) && (dev->font_style & STYLE_CONDENSED)) { + dev->actual_cpi = 17.14; + hpoints *= 10.0 / 17.14; + vpoints *= 10.0 / 17.14; + } + + if ((dev->cpi == 12) && (dev->font_style & STYLE_CONDENSED)) { + dev->actual_cpi = 20.0; + hpoints *= 10.0 / 20.0; + vpoints *= 10.0 / 20.0; + } + } + + if (dev->font_style & (STYLE_PROP | STYLE_CONDENSED)) { + hpoints /= 2.0; + vpoints /= 2.0; + } + + if ((dev->font_style & STYLE_DOUBLEWIDTH) || + (dev->font_style & STYLE_DOUBLEWIDTHONELINE)) { + dev->actual_cpi /= 2.0; + hpoints *= 2.0; + } + + if (dev->font_style & STYLE_DOUBLEHEIGHT) + vpoints *= 2.0; + } else { + /* Multipoint mode. */ + dev->actual_cpi = dev->multipoint_cpi; + hpoints = vpoints = dev->multipoint_size; + } + + if ((dev->font_style & STYLE_SUPERSCRIPT) || + (dev->font_style & STYLE_SUBSCRIPT)) { + hpoints *= 2.0 / 3.0; + vpoints *= 2.0 / 3.0; + dev->actual_cpi /= 2.0 / 3.0; + } + + ft_Set_Char_Size(dev->fontface, + (uint16_t)(hpoints * 64), + (uint16_t)(vpoints * 64), + dev->dpi, dev->dpi); + + if ((dev->font_style & STYLE_ITALICS) || + (dev->char_tables[dev->curr_char_table] == 0)) { + /* Italics transformation. */ + matrix.xx = 0x10000L; + matrix.xy = (FT_Fixed)(0.20 * 0x10000L); + matrix.yx = 0; + matrix.yy = 0x10000L; + ft_Set_Transform(dev->fontface, &matrix, 0); + } +} + + +/* Dump the current page into a formatted file. */ +static void +dump_page(escp_t *dev) +{ + wchar_t path[1024]; + wchar_t temp[128]; + + wcscpy(path, dev->pagepath); + plat_tempfile(temp, NULL, L".png"); + wcscat(path, temp); + png_write_gray(path, 1, dev->page->pixels, dev->page->w, dev->page->h); +} + + +static void +new_page(escp_t *dev, int8_t save, int8_t resetx) +{ + /* Dump the current page if needed. */ + if (save) + dump_page(dev); + if (resetx) + dev->curr_x = dev->left_margin; + + /* Clear page. */ + dev->curr_y = dev->top_margin; + dev->page->dirty = 0; + memset(dev->page->pixels, 0x00, dev->page->h * dev->page->pitch); +} + + +static void +reset_printer(escp_t *dev) +{ + int16_t i; + + /* TODO: these should be configurable. */ + dev->color = COLOR_BLACK; + dev->page_width = PAGE_WIDTH; + dev->page_height = PAGE_HEIGHT; + dev->left_margin = PAGE_LMARGIN; + dev->right_margin = PAGE_RMARGIN; + dev->top_margin = PAGE_TMARGIN; + dev->bottom_margin = PAGE_BMARGIN; + dev->dpi = PAGE_DPI; + dev->cpi = PAGE_CPI; + dev->lpi = PAGE_LPI; + + dev->hmi = -1.0; + dev->curr_x = dev->curr_y = 0.0; + dev->linespacing = 1.0 / dev->lpi; + + dev->char_tables[0] = 0; /* italics */ + dev->char_tables[1] = dev->char_tables[2] = dev->char_tables[3] = 437; /* all other tables use CP437 */ + dev->curr_char_table = 1; + init_codepage(dev, dev->char_tables[dev->curr_char_table]); + + dev->num_horizontal_tabs = 32; + for (i = 0; i < 32; i++) + dev->horizontal_tabs[i] = i * 8.0 / dev->cpi; + dev->num_vertical_tabs = -1; + + dev->current_font = FONT_COURIER; + dev->lq_typeface = TYPEFACE_COURIER; + dev->fontface = 0; + dev->multipoint_mode = 0; + dev->multipoint_size = 0.0; + dev->multipoint_cpi = 0.0; + dev->font_style = 0; + dev->font_score = 0; + dev->print_quality = QUALITY_DRAFT; + + dev->bg_h_density = dev->bg_v_density = 0; + dev->bg_adjacent = 0; + dev->bg_bytes_per_column = dev->bg_bytes_read = 0; + dev->bg_remaining_bytes = 0; + memset(dev->bg_column, 0x00, sizeof(dev->bg_column)); + + dev->esc_seen = 0; + dev->fss_seen = 0; + dev->esc_pending = 0; + dev->esc_parms_req = dev->esc_parms_curr = 0; + memset(dev->esc_parms, 0x00, sizeof(dev->esc_parms)); + + dev->msb = -1; + dev->print_everything_count = 0; + dev->print_upper_control = 0; + if (dev->page != NULL) + dev->page->dirty = 0; + dev->extra_intra_space = 0.0; + dev->defined_unit = -1.0; + dev->density_k = 0; + dev->density_l = 1; + dev->density_y = 2; + dev->density_z = 3; + + update_font(dev); + + //pclog("ESC/P: width=%.1fin,height=%.1fin dpi=%i cpi=%i lpi=%i\n", + //dev->page_width, dev->page_height, + //(int)dev->dpi, (int)dev->cpi, (int)dev->lpi); +} + + +static void +setup_bit_image(escp_t *dev, uint8_t density, uint16_t num_columns) +{ + switch (density) { + case 0: + dev->bg_h_density = 60; + dev->bg_v_density = 60; + dev->bg_adjacent = 1; + dev->bg_bytes_per_column = 1; + break; + + case 1: + dev->bg_h_density = 120; + dev->bg_v_density = 60; + dev->bg_adjacent = 1; + dev->bg_bytes_per_column = 1; + break; + + case 2: + dev->bg_h_density = 120; + dev->bg_v_density = 60; + dev->bg_adjacent = 0; + dev->bg_bytes_per_column = 1; + break; + + case 3: + dev->bg_h_density = 60; + dev->bg_v_density = 240; + dev->bg_adjacent = 0; + dev->bg_bytes_per_column = 1; + break; + + case 4: + dev->bg_h_density = 80; + dev->bg_v_density = 60; + dev->bg_adjacent = 1; + dev->bg_bytes_per_column = 1; + break; + + case 6: + dev->bg_h_density = 90; + dev->bg_v_density = 60; + dev->bg_adjacent = 1; + dev->bg_bytes_per_column = 1; + break; + + case 32: + dev->bg_h_density = 60; + dev->bg_v_density = 180; + dev->bg_adjacent = 1; + dev->bg_bytes_per_column = 3; + break; + + case 33: + dev->bg_h_density = 120; + dev->bg_v_density = 180; + dev->bg_adjacent = 1; + dev->bg_bytes_per_column = 3; + break; + + case 38: + dev->bg_h_density = 90; + dev->bg_v_density = 180; + dev->bg_adjacent = 1; + dev->bg_bytes_per_column = 3; + break; + + case 39: + dev->bg_h_density = 180; + dev->bg_v_density = 180; + dev->bg_adjacent = 1; + dev->bg_bytes_per_column = 3; + break; + + case 40: + dev->bg_h_density = 360; + dev->bg_v_density = 180; + dev->bg_adjacent = 0; + dev->bg_bytes_per_column = 3; + break; + + case 71: + dev->bg_h_density = 180; + dev->bg_v_density = 360; + dev->bg_adjacent = 1; + dev->bg_bytes_per_column = 6; + break; + + case 72: + dev->bg_h_density = 360; + dev->bg_v_density = 360; + dev->bg_adjacent = 0; + dev->bg_bytes_per_column = 6; + break; + + case 73: + dev->bg_h_density = 360; + dev->bg_v_density = 360; + dev->bg_adjacent = 1; + dev->bg_bytes_per_column = 6; + break; + + default: + pclog("ESC/P: Unsupported bit image density %d.\n", density); + } + + dev->bg_remaining_bytes = num_columns * dev->bg_bytes_per_column; + dev->bg_bytes_read = 0; +} + + +/* This is the actual ESC/P interpreter. */ +static int +process_char(escp_t *dev, uint8_t ch) +{ + double new_x, new_y; + double move_to; + double unit_size; + uint16_t rel_move; + int16_t i; + + //pclog("Esc_seen=%d, fss_seen=%d\n", dev->esc_seen, dev->fss_seen); + /* Determine number of additional command params that are expected. */ + if (dev->esc_seen || dev->fss_seen) { + dev->esc_pending = ch; + if (dev->fss_seen) dev->esc_pending |= 0x800; + dev->esc_seen = dev->fss_seen = 0; + dev->esc_parms_curr = 0; + + //pclog("Command pending=%02x\n", dev->esc_pending); + switch (dev->esc_pending) { + case 0x02: // Undocumented + case 0x0a: // Reverse line feed + case 0x0c: // Return to top of current page + case 0x0e: // Select double-width printing (one line) (ESC SO) + case 0x0f: // Select condensed printing (ESC SI) + case 0x23: // Cancel MSB control (ESC #) + case 0x30: // Select 1/8-inch line spacing (ESC 0) + case 0x32: // Select 1/6-inch line spacing (ESC 2) + case 0x34: // Select italic font (ESC 4) + case 0x35: // Cancel italic font (ESC 5) + case 0x36: // Enable printing of upper control codes (ESC 6) + case 0x37: // Enable upper control codes (ESC 7) + case 0x3c: // Unidirectional mode (one line) (ESC <) + case 0x3d: // Set MSB to 0 (ESC =) + case 0x3e: // Set MSB to 1 (ESC >) + case 0x40: // Initialize printer (ESC @) + case 0x45: // Select bold font (ESC E) + case 0x46: // Cancel bold font (ESC F) + case 0x47: // Select double-strike printing (ESC G) + case 0x48: // Cancel double-strike printing (ESC H) + case 0x4d: // Select 10.5-point, 12-cpi (ESC M) + case 0x4f: // Cancel bottom margin + case 0x50: // Select 10.5-point, 10-cpi (ESC P) + case 0x54: // Cancel superscript/subscript printing (ESC T) + case 0x5e: // Enable printing of all character codes on next character + case 0x67: // Select 10.5-point, 15-cpi (ESC g) + case 0x73: // Select low-speed mode (ESC s) + case 0x834: // Select italic font (FS 4) (= ESC 4) + case 0x835: // Cancel italic font (FS 5) (= ESC 5) + case 0x846: // Select forward feed mode (FS F) + case 0x852: // Select reverse feed mode (FS R) + dev->esc_parms_req = 0; + break; + + case 0x19: // Control paper loading/ejecting (ESC EM) + case 0x20: // Set intercharacter space (ESC SP) + case 0x21: // Master select (ESC !) + case 0x2b: // Set n/360-inch line spacing (ESC +) + case 0x2d: // Turn underline on/off (ESC -) + case 0x2f: // Select vertical tab channel (ESC /) + case 0x33: // Set n/180-inch line spacing (ESC 3) + case 0x41: // Set n/60-inch line spacing + case 0x43: // Set page length in lines (ESC C) + case 0x4a: // Advance print position vertically (ESC J n) + case 0x4e: // Set bottom margin (ESC N) + case 0x51: // Set right margin (ESC Q) + case 0x52: // Select an international character set (ESC R) + case 0x53: // Select superscript/subscript printing (ESC S) + case 0x55: // Turn unidirectional mode on/off (ESC U) + case 0x57: // Turn double-width printing on/off (ESC W) + case 0x61: // Select justification (ESC a) + case 0x6b: // Select typeface (ESC k) + case 0x6c: // Set left margin (ESC 1) + case 0x70: // Turn proportional mode on/off (ESC p) + case 0x72: // Select printing color (ESC r) + case 0x74: // Select character table (ESC t) + case 0x77: // Turn double-height printing on/off (ESC w) + case 0x78: // Select LQ or draft (ESC x) + case 0x7e: // Select/Deselect slash zero (ESC ~) + case 0x832: // Select 1/6-inch line spacing (FS 2) (= ESC 2) + case 0x833: // Set n/360-inch line spacing (FS 3) (= ESC +) + case 0x841: // Set n/60-inch line spacing (FS A) (= ESC A) + case 0x843: // Select LQ type style (FS C) (= ESC k) + case 0x845: // Select character width (FS E) + case 0x849: // Select character table (FS I) (= ESC t) + case 0x853: // Select High Speed/High Density elite pitch (FS S) + case 0x856: // Turn double-height printing on/off (FS V) (= ESC w) + dev->esc_parms_req = 1; + break; + + case 0x24: // Set absolute horizontal print position (ESC $) + case 0x3f: // Reassign bit-image mode (ESC ?) + case 0x4b: // Select 60-dpi graphics (ESC K) + case 0x4c: // Select 120-dpi graphics (ESC L) + case 0x59: // Select 120-dpi, double-speed graphics (ESC Y) + case 0x5a: // Select 240-dpi graphics (ESC Z) + case 0x5c: // Set relative horizontal print position (ESC \) + case 0x63: // Set horizontal motion index (HMI) (ESC c) + case 0x65: // Set vertical tab stops every n lines (ESC e) + case 0x85a: // Print 24-bit hex-density graphics (FS Z) + dev->esc_parms_req = 2; + break; + + case 0x2a: // Select bit image (ESC *) + case 0x58: // Select font by pitch and point (ESC X) + dev->esc_parms_req = 3; + break; + + case 0x5b: // Select character height, width, line spacing + dev->esc_parms_req = 7; + break; + + case 0x62: // Set vertical tabs in VFU channels (ESC b) + case 0x42: // Set vertical tabs (ESC B) + dev->num_vertical_tabs = 0; + return 1; + + case 0x44: // Set horizontal tabs (ESC D) + dev->num_horizontal_tabs = 0; + return 1; + + case 0x25: // Select user-defined set (ESC %) + case 0x26: // Define user-defined characters (ESC &) + case 0x3a: // Copy ROM to RAM (ESC :) + //ERRLOG("ESC/P: User-defined characters not supported.\n"); + return 1; + + case 0x28: // Two bytes sequence + /* return and wait for second ESC byte */ + return 1; + + default: + //ERRLOG("ESC/P: Unknown command ESC %c (0x%02x). Unable to skip parameters.\n", + // dev->esc_pending >= 0x20 ? dev->esc_pending : '?', + // dev->esc_pending); + dev->esc_parms_req = 0; + dev->esc_pending = 0; + return 1; + } + + if (dev->esc_parms_req > 0) { + /* return and wait for parameters to appear */ + return 1; + } + } + + /* parameter checking for the 2-byte ESC/P2 commands */ + if (dev->esc_pending == '(') { + dev->esc_pending = 0x0200 + ch; + + switch (dev->esc_pending) { + case 0x0242: // Bar code setup and print (ESC (B) + case 0x025e: // Print data as characters (ESC (^) + dev->esc_parms_req = 2; + break; + + case 0x0255: // Set unit (ESC (U) + dev->esc_parms_req = 3; + break; + + case 0x0243: // Set page length in defined unit (ESC (C) + case 0x0256: // Set absolute vertical print position (ESC (V) + case 0x0276: // Set relative vertical print position (ESC (v) + dev->esc_parms_req = 4; + break; + + case 0x0228: // Assign character table (ESC (t) + case 0x022d: // Select line/score (ESC (-) + dev->esc_parms_req = 5; + break; + + case 0x0263: // Set page format (ESC (c) + dev->esc_parms_req = 6; + break; + + default: + // ESC ( commands are always followed by a "number of parameters" word parameter + //ERRLOG("ESC/P: Skipping unsupported extended command ESC ( %c (0x%02x).\n", + // dev->esc_pending >= 0x20 ? dev->esc_pending : '?', + // dev->esc_pending); + dev->esc_parms_req = 2; + dev->esc_pending = 0x101; /* dummy value to be checked later */ + return 1; + } + + /* If we need parameters, return and wait for them to appear. */ + if (dev->esc_parms_req > 0) return 1; + } + + /* Ignore VFU channel setting. */ + if (dev->esc_pending == 0x62) { + dev->esc_pending = 0x42; + return 1; + } + + /* Collect vertical tabs. */ + if (dev->esc_pending == 0x42) { + /* check if we're done */ + if ((ch == 0) || + (dev->num_vertical_tabs > 0 && dev->vertical_tabs[dev->num_vertical_tabs - 1] > (double)ch * dev->linespacing)) { + dev->esc_pending = 0; + } else { + if (dev->num_vertical_tabs < 16) { + dev->vertical_tabs[dev->num_vertical_tabs++] = (double)ch * dev->linespacing; + } + } + } + + /* Collect horizontal tabs. */ + if (dev->esc_pending == 0x44) { + /* check if we're done... */ + if ((ch == 0) || + (dev->num_horizontal_tabs > 0 && dev->horizontal_tabs[dev->num_horizontal_tabs - 1] > (double)ch * (1.0 / dev->cpi))) { + dev->esc_pending = 0; + } else { + if (dev->num_horizontal_tabs < 32) { + dev->horizontal_tabs[dev->num_horizontal_tabs++] = (double)ch * (1.0 / dev->cpi); + } + } + } + + /* Check if we're still collecting parameters for the current command. */ + if (dev->esc_parms_curr < dev->esc_parms_req) { + /* store current parameter */ + dev->esc_parms[dev->esc_parms_curr++] = ch; + + /* do we still need to continue collecting parameters? */ + if (dev->esc_parms_curr < dev->esc_parms_req) + return 1; + } + + /* Handle the pending ESC command. */ + if (dev->esc_pending != 0) { + switch (dev->esc_pending) { + case 0x02: /* undocumented; ignore */ + break; + + case 0x0e: /* select double-width (one line) (ESC SO) */ + if (! dev->multipoint_mode) { + dev->hmi = -1; + dev->font_style |= STYLE_DOUBLEWIDTHONELINE; + update_font(dev); + } + break; + + case 0x0f: /* select condensed printing (ESC SI) */ + if (! dev->multipoint_mode) { + dev->hmi = -1; + dev->font_style |= STYLE_CONDENSED; + update_font(dev); + } + break; + + case 0x19: /* control paper loading/ejecting (ESC EM) */ + /* We are not really loading paper, so most + * commands can be ignored */ + if (dev->esc_parms[0] == 'R') + new_page(dev, 1, 0); + + break; + case 0x20: /* set intercharacter space (ESC SP) */ + if (! dev->multipoint_mode) { + dev->extra_intra_space = (double)dev->esc_parms[0] / (dev->print_quality == QUALITY_DRAFT ? 120.0 : 180.0); + dev->hmi = -1; + update_font(dev); + } + break; + + case 0x21: /* master select (ESC !) */ + dev->cpi = dev->esc_parms[0] & 0x01 ? 12.0 : 10.0; + + /* Reset first seven bits. */ + dev->font_style &= ~0x7f; + if (dev->esc_parms[0] & 0x02) + dev->font_style |= STYLE_PROP; + if (dev->esc_parms[0] & 0x04) + dev->font_style |= STYLE_CONDENSED; + if (dev->esc_parms[0] & 0x08) + dev->font_style |= STYLE_BOLD; + if (dev->esc_parms[0] & 0x10) + dev->font_style |= STYLE_DOUBLESTRIKE; + if (dev->esc_parms[0] & 0x20) + dev->font_style |= STYLE_DOUBLEWIDTH; + if (dev->esc_parms[0] & 0x40) + dev->font_style |= STYLE_ITALICS; + if (dev->esc_parms[0] & 0x80) { + dev->font_score = SCORE_SINGLE; + dev->font_style |= STYLE_UNDERLINE; + } + + dev->hmi = -1; + dev->multipoint_mode = 0; + update_font(dev); + break; + + case 0x23: /* cancel MSB control (ESC #) */ + dev->msb = -1; + break; + + case 0x24: /* set abs horizontal print position (ESC $) */ + unit_size = dev->defined_unit; + if (unit_size < 0) + unit_size = 60.0; + + new_x = dev->left_margin + (double)PARAM16(0) / unit_size; + if (new_x <= dev->right_margin) + dev->curr_x = new_x; + break; + + case 0x85a: /* Print 24-bit hex-density graphics (FS Z) */ + setup_bit_image(dev, 40, PARAM16(0)); + break; + + case 0x2a: /* select bit image (ESC *) */ + setup_bit_image(dev, dev->esc_parms[0], PARAM16(1)); + break; + + case 0x2b: /* set n/360-inch line spacing (ESC +) */ + case 0x833: /* Set n/360-inch line spacing (FS 3) */ + dev->linespacing = (double)dev->esc_parms[0] / 360.0; + break; + + case 0x2d: /* turn underline on/off (ESC -) */ + if (dev->esc_parms[0] == 0 || dev->esc_parms[0] == '0') + dev->font_style &= ~STYLE_UNDERLINE; + if (dev->esc_parms[0] == 1 || dev->esc_parms[0] == '1') { + dev->font_style |= STYLE_UNDERLINE; + dev->font_score = SCORE_SINGLE; + } + update_font(dev); + break; + + case 0x2f: /* select vertical tab channel (ESC /) */ + /* Ignore */ + break; + + case 0x30: /* select 1/8-inch line spacing (ESC 0) */ + dev->linespacing = 1.0 / 8.0; + break; + + case 0x32: /* select 1/6-inch line spacing (ESC 2) */ + dev->linespacing = 1.0 / 6.0; + break; + + case 0x33: /* set n/180-inch line spacing (ESC 3) */ + dev->linespacing = (double)dev->esc_parms[0] / 180.0; + break; + + case 0x34: /* select italic font (ESC 4) */ + dev->font_style |= STYLE_ITALICS; + update_font(dev); + break; + + case 0x35: /* cancel italic font (ESC 5) */ + dev->font_style &= ~STYLE_ITALICS; + update_font(dev); + break; + + case 0x36: /* enable printing of upper control codes (ESC 6) */ + dev->print_upper_control = 1; + break; + + case 0x37: /* enable upper control codes (ESC 7) */ + dev->print_upper_control = 0; + break; + + case 0x3c: /* unidirectional mode (one line) (ESC <) */ + /* We don't have a print head, so just + * ignore this. */ + break; + + case 0x3d: /* set MSB to 0 (ESC =) */ + dev->msb = 0; + break; + + case 0x3e: /* set MSB to 1 (ESC >) */ + dev->msb = 1; + break; + + case 0x3f: /* reassign bit-image mode (ESC ?) */ + if (dev->esc_parms[0] == 'K') + dev->density_k = dev->esc_parms[1]; + if (dev->esc_parms[0] == 'L') + dev->density_l = dev->esc_parms[1]; + if (dev->esc_parms[0] == 'Y') + dev->density_y = dev->esc_parms[1]; + if (dev->esc_parms[0] == 'Z') + dev->density_z = dev->esc_parms[1]; + break; + + case 0x40: /* initialize printer (ESC @) */ + reset_printer(dev); + break; + + case 0x41: /* set n/60-inch line spacing */ + dev->linespacing = (double)dev->esc_parms[0] / 60.0; + break; + + case 0x43: /* set page length in lines (ESC C) */ + if (dev->esc_parms[0]) { + dev->page_height = dev->bottom_margin = (double)dev->esc_parms[0] * dev->linespacing; + } else { /* == 0 => Set page length in inches */ + dev->esc_parms_req = 1; + dev->esc_parms_curr = 0; + dev->esc_pending = 0x100; /* dummy value for later */ + return 1; + } + break; + + case 0x45: /* select bold font (ESC E) */ + dev->font_style |= STYLE_BOLD; + update_font(dev); + break; + + case 0x46: /* cancel bold font (ESC F) */ + dev->font_style &= ~STYLE_BOLD; + update_font(dev); + break; + + case 0x47: /* select dobule-strike printing (ESC G) */ + dev->font_style |= STYLE_DOUBLESTRIKE; + break; + + case 0x48: /* cancel double-strike printing (ESC H) */ + dev->font_style &= ~STYLE_DOUBLESTRIKE; + break; + + case 0x4a: /* advance print pos vertically (ESC J n) */ + dev->curr_y += (double)dev->esc_parms[0] / 180.0; + if (dev->curr_y > dev->bottom_margin) { + new_page(dev, 1, 0); + } + break; + + case 0x4b: /* select 60-dpi graphics (ESC K) */ + /* TODO: graphics stuff */ + setup_bit_image(dev, dev->density_k, PARAM16(0)); + break; + + case 0x4c: /* select 120-dpi graphics (ESC L) */ + /* TODO: graphics stuff */ + setup_bit_image(dev, dev->density_l, PARAM16(0)); + break; + + case 0x4d: /* select 10.5-point, 12-cpi (ESC M) */ + dev->cpi = 12.0; + dev->hmi = -1; + dev->multipoint_mode = 0; + update_font(dev); + break; + + case 0x4e: /* set bottom margin (ESC N) */ + dev->top_margin = 0.0; + dev->bottom_margin = (double)dev->esc_parms[0] * dev->linespacing; + break; + + case 0x4f: /* cancel bottom (and top) margin */ + dev->top_margin = 0.0; + dev->bottom_margin = dev->page_height; + break; + + case 0x50: /* select 10.5-point, 10-cpi (ESC P) */ + dev->cpi = 10.0; + dev->hmi = -1; + dev->multipoint_mode = 0; + update_font(dev); + break; + + case 0x51: /* set right margin */ + dev->right_margin = ((double)dev->esc_parms[0] - 1.0) / dev->cpi; + break; + + case 0x52: /* select an intl character set (ESC R) */ + if (dev->esc_parms[0] <= 13 || dev->esc_parms[0] == '@') { + if (dev->esc_parms[0] == '@') + dev->esc_parms[0] = 14; + + dev->curr_cpmap[0x23] = intCharSets[dev->esc_parms[0]][0]; + dev->curr_cpmap[0x24] = intCharSets[dev->esc_parms[0]][1]; + dev->curr_cpmap[0x40] = intCharSets[dev->esc_parms[0]][2]; + dev->curr_cpmap[0x5b] = intCharSets[dev->esc_parms[0]][3]; + dev->curr_cpmap[0x5c] = intCharSets[dev->esc_parms[0]][4]; + dev->curr_cpmap[0x5d] = intCharSets[dev->esc_parms[0]][5]; + dev->curr_cpmap[0x5e] = intCharSets[dev->esc_parms[0]][6]; + dev->curr_cpmap[0x60] = intCharSets[dev->esc_parms[0]][7]; + dev->curr_cpmap[0x7b] = intCharSets[dev->esc_parms[0]][8]; + dev->curr_cpmap[0x7c] = intCharSets[dev->esc_parms[0]][9]; + dev->curr_cpmap[0x7d] = intCharSets[dev->esc_parms[0]][10]; + dev->curr_cpmap[0x7e] = intCharSets[dev->esc_parms[0]][11]; + } + break; + + case 0x53: /* select superscript/subscript printing (ESC S) */ + if (dev->esc_parms[0] == 0 || dev->esc_parms[0] == '0') + dev->font_style |= STYLE_SUBSCRIPT; + if (dev->esc_parms[0] == 1 || dev->esc_parms[1] == '1') + dev->font_style |= STYLE_SUPERSCRIPT; + update_font(dev); + break; + + case 0x54: /* cancel superscript/subscript printing (ESC T) */ + dev->font_style &= ~(STYLE_SUPERSCRIPT | STYLE_SUBSCRIPT); + update_font(dev); + break; + + case 0x55: /* turn unidirectional mode on/off (ESC U) */ + /* We don't have a print head, so just ignore this. */ + break; + + case 0x57: /* turn double-width printing on/off (ESC W) */ + if (!dev->multipoint_mode) { + dev->hmi = -1; + if (dev->esc_parms[0] == 0 || dev->esc_parms[0] == '0') + dev->font_style &= ~STYLE_DOUBLEWIDTH; + if (dev->esc_parms[0] == 1 || dev->esc_parms[0] == '1') + dev->font_style |= STYLE_DOUBLEWIDTH; + update_font(dev); + } + break; + + case 0x58: /* select font by pitch and point (ESC X) */ + dev->multipoint_mode = 1; + /* Copy currently non-multipoint CPI if no value was set so far. */ + if (dev->multipoint_cpi == 0.0) { + dev->multipoint_cpi= dev->cpi; + } + if (dev->esc_parms[0] > 0) { /* set CPI */ + if (dev->esc_parms[0] == 1) { + /* Proportional spacing. */ + dev->font_style |= STYLE_PROP; + } else if (dev->esc_parms[0] >= 5) { + dev->multipoint_cpi = 360.0 / (double)dev->esc_parms[0]; + } + } + if (dev->multipoint_size == 0.0) { + dev->multipoint_size = 10.5; + } + if (PARAM16(1) > 0) { + /* set points */ + dev->multipoint_size = ((double)PARAM16(1)) / 2.0; + } + update_font(dev); + break; + + case 0x59: /* select 120-dpi, double-speed graphics (ESC Y) */ + /* TODO: graphics stuff */ + setup_bit_image(dev, dev->density_y, PARAM16(0)); + break; + + case 0x5a: /* select 240-dpi graphics (ESC Z) */ + /* TODO: graphics stuff */ + setup_bit_image(dev, dev->density_z, PARAM16(0)); + break; + + case 0x5c: /* set relative horizontal print pos (ESC \) */ + rel_move = PARAM16(0); + unit_size = dev->defined_unit; + if (unit_size < 0) + unit_size = (dev->print_quality == QUALITY_DRAFT ? 120.0 : 180.0); + dev->curr_x += ((double)rel_move / unit_size); + break; + + case 0x61: /* select justification (ESC a) */ + /* Ignore. */ + break; + + case 0x63: /* set horizontal motion index (HMI) (ESC c) */ + dev->hmi = (double)PARAM16(0) / 360.0; + dev->extra_intra_space = 0.0; + break; + + case 0x67: /* select 10.5-point, 15-cpi (ESC g) */ + dev->cpi = 15; + dev->hmi = -1; + dev->multipoint_mode = 0; + update_font(dev); + break; + + case 0x6b: /* select typeface (ESC k) */ + if (dev->esc_parms[0] <= 11 || dev->esc_parms[0] == 30 || dev->esc_parms[0] == 31) { + dev->lq_typeface = dev->esc_parms[0]; + } + update_font(dev); + break; + + case 0x6c: /* set left margin (ESC 1) */ + dev->left_margin = ((double)dev->esc_parms[0] - 1.0) / dev->cpi; + if (dev->curr_x < dev->left_margin) + dev->curr_x = dev->left_margin; + break; + + case 0x70: /* Turn proportional mode on/off (ESC p) */ + if (dev->esc_parms[0] == 0 || dev->esc_parms[0] == '0') + dev->font_style &= ~STYLE_PROP; + if (dev->esc_parms[0] == 1 || dev->esc_parms[0] == '1') { + dev->font_style |= STYLE_PROP; + dev->print_quality = QUALITY_LQ; + } + dev->multipoint_mode = 0; + dev->hmi = -1; + update_font(dev); + break; + + case 0x72: /* select printing color (ESC r) */ + if (dev->esc_parms[0] == 0 || dev->esc_parms[0] > 6) + dev->color = COLOR_BLACK; + else + dev->color = dev->esc_parms[0] << 5; + break; + + case 0x73: /* select low-speed mode (ESC s) */ + /* Ignore. */ + break; + + case 0x74: /* select character table (ESC t) */ + case 0x849: /* Select character table (FS I) */ + if (dev->esc_parms[0] < 4) { + dev->curr_char_table = dev->esc_parms[0]; + } else if ((dev->esc_parms[0] >= '0') && (dev->esc_parms[0] <= '3')) { + dev->curr_char_table = dev->esc_parms[0] - '0'; + } + init_codepage(dev, dev->char_tables[dev->curr_char_table]); + update_font(dev); + break; + + case 0x77: /* turn double-height printing on/off (ESC w) */ + if (! dev->multipoint_mode) { + if (dev->esc_parms[0] == 0 || dev->esc_parms[0] == '0') + dev->font_style &= ~STYLE_DOUBLEHEIGHT; + if (dev->esc_parms[0] == 1 || dev->esc_parms[0] == '1') + dev->font_style |= STYLE_DOUBLEHEIGHT; + update_font(dev); + } + break; + + case 0x78: /* select LQ or draft (ESC x) */ + if (dev->esc_parms[0] == 0 || dev->esc_parms[0] == '0') + dev->print_quality = QUALITY_DRAFT; + if (dev->esc_parms[0] == 1 || dev->esc_parms[0] == '1') + dev->print_quality = QUALITY_LQ; + update_font(dev); + break; + + /* Our special command markers. */ + case 0x0100: /* set page length in inches (ESC C NUL) */ + dev->page_height = (double)dev->esc_parms[0]; + dev->bottom_margin = dev->page_height; + dev->top_margin = 0.0; + break; + + case 0x0101: /* skip unsupported ESC ( command */ + dev->esc_parms_req = PARAM16(0); + dev->esc_parms_curr = 0; + break; + + /* Extended ESC ( commands */ + case 0x0228: /* assign character table (ESC (t) */ + case 0x0274: + if (dev->esc_parms[2] < 4 && dev->esc_parms[3] < 16) { + dev->char_tables[dev->esc_parms[2]] = codepages[dev->esc_parms[3]]; + if (dev->esc_parms[2] == dev->curr_char_table) { + init_codepage(dev, dev->char_tables[dev->curr_char_table]); + } + } + break; + + case 0x022d: /* select line/score (ESC (-) */ + dev->font_style &= ~(STYLE_UNDERLINE | STYLE_STRIKETHROUGH | STYLE_OVERSCORE); + dev->font_score = dev->esc_parms[4]; + if (dev->font_score) { + if (dev->esc_parms[3] == 1) + dev->font_style |= STYLE_UNDERLINE; + if (dev->esc_parms[3] == 2) + dev->font_style |= STYLE_STRIKETHROUGH; + if (dev->esc_parms[3] == 3) + dev->font_style |= STYLE_OVERSCORE; + } + update_font(dev); + break; + + case 0x0242: /* bar code setup and print (ESC (B) */ + //ERRLOG("ESC/P: Barcode printing not supported.\n"); + + /* Find out how many bytes to skip. */ + dev->esc_parms_req = PARAM16(0); + dev->esc_parms_curr = 0; + break; + + case 0x0243: /* set page length in defined unit (ESC (C) */ + if (dev->esc_parms[0] && (dev->defined_unit> 0)) { + dev->page_height = dev->bottom_margin = (double)PARAM16(2) * dev->defined_unit; + dev->top_margin = 0.0; + } + break; + + case 0x0255: /* set unit (ESC (U) */ + dev->defined_unit = 3600.0 / (double)dev->esc_parms[2]; + break; + + case 0x0256: /* set abse vertical print pos (ESC (V) */ + unit_size = dev->defined_unit; + if (unit_size < 0) + unit_size = 360.0; + new_y = dev->top_margin + (double)PARAM16(2) * unit_size; + if (new_y > dev->bottom_margin) + new_page(dev, 1, 0); + else + dev->curr_y = new_y; + break; + + case 0x025e: /* print data as characters (ESC (^) */ + dev->print_everything_count = PARAM16(0); + break; + + case 0x0263: /* set page format (ESC (c) */ + if (dev->defined_unit > 0.0) { + dev->top_margin = (double)PARAM16(2) * dev->defined_unit; + dev->bottom_margin = (double)PARAM16(4) * dev->defined_unit; + } + break; + + case 0x0276: /* set relative vertical print pos (ESC (v) */ + { + unit_size = dev->defined_unit; + if (unit_size < 0.0) + unit_size = 360.0; + new_y = dev->curr_y + (double)((int16_t)PARAM16(2)) * unit_size; + if (new_y > dev->top_margin) { + if (new_y > dev->bottom_margin) { + new_page(dev, 1, 0); + } else { + dev->curr_y = new_y; + } + } + } + break; + + default: + //ERRLOG("ESC/P: Unhandled ESC command.\n"); + break; + } + + dev->esc_pending = 0; + return 1; + } + + //pclog("CH=%02x\n", ch); + /* Now handle the "regular" control characters. */ + switch (ch) { + case 0x00: + return 1; + + case 0x07: /* Beeper (BEL) */ + /* TODO: beep? */ + return 1; + + case 0x08: /* Backspace (BS) */ + new_x = dev->curr_x - (1.0 / dev->actual_cpi); + if (dev->hmi > 0) + new_x = dev->curr_x - dev->hmi; + if (new_x >= dev->left_margin) + dev->curr_x = new_x; + return 1; + + case 0x09: /* Tab horizontally (HT) */ + /* Find tab right to current pos. */ + move_to = -1.0; + for (i = 0; i < dev->num_horizontal_tabs; i++) { + if (dev->horizontal_tabs[i] > dev->curr_x) { + move_to = dev->horizontal_tabs[i]; + break; + } + } + + /* Nothing found or out of page bounds => Ignore. */ + if (move_to > 0.0 && move_to < dev->right_margin) + dev->curr_x = move_to; + return 1; + + case 0x0b: /* Tab vertically (VT) */ + if (dev->num_vertical_tabs == 0) { + /* All tabs cleared? => Act like CR */ + dev->curr_x = dev->left_margin; + } else if (dev->num_vertical_tabs < 0) { + /* No tabs set since reset => Act like LF */ + dev->curr_x = dev->left_margin; + dev->curr_y += dev->linespacing; + if (dev->curr_y > dev->bottom_margin) + new_page(dev, 1, 0); + } else { + /* Find tab below current pos. */ + move_to = -1; + for (i = 0; i < dev->num_vertical_tabs; i++) { + if (dev->vertical_tabs[i] > dev->curr_y) { + move_to = dev->vertical_tabs[i]; + break; + } + } + + /* Nothing found => Act like FF. */ + if (move_to > dev->bottom_margin || move_to < 0) + new_page(dev, 1, 0); + else + dev->curr_y = move_to; + } + + if (dev->font_style & STYLE_DOUBLEWIDTHONELINE) { + dev->font_style &= ~STYLE_DOUBLEWIDTHONELINE; + update_font(dev); + } + return 1; + + case 0x0c: /* Form feed (FF) */ + if (dev->font_style & STYLE_DOUBLEWIDTHONELINE) { + dev->font_style &= ~STYLE_DOUBLEWIDTHONELINE; + update_font(dev); + } + new_page(dev, 1, 1); + return 1; + + case 0x0d: /* Carriage Return (CR) */ + dev->curr_x = dev->left_margin; + if (!dev->autofeed) + { + return 1; + } + /*FALLTHROUGH*/ + + case 0x0a: /* Line feed */ + if (dev->font_style & STYLE_DOUBLEWIDTHONELINE) { + dev->font_style &= ~STYLE_DOUBLEWIDTHONELINE; + update_font(dev); + } + dev->curr_x = dev->left_margin; + dev->curr_y += dev->linespacing; + if (dev->curr_y > dev->bottom_margin) { + new_page(dev, 1, 0); + } + return 1; + + case 0x0e: /* select Real64-width printing (one line) (SO) */ + if (! dev->multipoint_mode) { + dev->hmi = -1; + dev->font_style |= STYLE_DOUBLEWIDTHONELINE; + update_font(dev); + } + return 1; + + case 0x0f: /* select condensed printing (SI) */ + if (! dev->multipoint_mode) { + dev->hmi = -1; + dev->font_style |= STYLE_CONDENSED; + update_font(dev); + } + return 1; + + case 0x11: /* select printer (DC1) */ + /* Ignore. */ + return 1; + + case 0x12: /* cancel condensed printing (DC2) */ + dev->hmi = -1; + dev->font_style &= ~STYLE_CONDENSED; + update_font(dev); + return 1; + + case 0x13: /* deselect printer (DC3) */ + /* Ignore. */ + return 1; + + case 0x14: /* cancel double-width printing (one line) (DC4) */ + dev->hmi = -1; + dev->font_style &= ~STYLE_DOUBLEWIDTHONELINE; + update_font(dev); + return 1; + + case 0x18: /* cancel line (CAN) */ + return 1; + + case 0x1b: /* ESC */ + dev->esc_seen = 1; + return 1; + + case 0x1c: /* FS (IBM commands) */ + dev->fss_seen = 1; + return 1; + + default: + break; + } + + /* This is a printable character -> print it. */ + return 0; +} + + +/* TODO: This can be optimized quite a bit... I'm just too lazy right now ;-) */ +static void +blit_glyph(escp_t *dev, uint16_t destx, uint16_t desty, int8_t add) +{ + FT_Bitmap *bitmap = &dev->fontface->glyph->bitmap; + uint16_t x, y; + uint8_t src, *dst; + + /* check if freetype is available */ + if (ft_lib == NULL) return; + + for (y = 0; y < bitmap->rows; y++) { + for (x = 0; x < bitmap->width; x++) { + src = *(bitmap->buffer + y * bitmap->pitch + x); + /* ignore background, and respect page size */ + if (src > 0 && (destx + x < dev->page->w) && (desty + y < dev->page->h)) { + dst = (uint8_t *)dev->page->pixels + x + destx + (y + desty) * dev->page->pitch; + src >>= 3; + + if (add) { + if (((*dst) & 0x1f) + src > 31) + *dst |= (dev->color | 0x1f); + else { + *dst += src; + *dst |= dev->color; + } + } + else + *dst = src|dev->color; + } + } + } +} + + +/* Draw anti-aliased line. */ +static void +draw_hline(escp_t *dev, uint16_t from_x, uint16_t to_x, uint16_t y, int8_t broken) +{ + uint16_t breakmod = dev->dpi / 15; + uint16_t gapstart = (breakmod * 4) / 5; + uint16_t x; + + for (x = from_x; x <= to_x; x++) { + /* Skip parts if broken line or going over the border. */ + if ((!broken || (x % breakmod <= gapstart)) && (x < dev->page->w)) { + if (y > 0 && (y - 1) < dev->page->h) + *((uint8_t*)dev->page->pixels + x + (y - 1)*dev->page->pitch) = 120; + if (y < dev->page->h) + *((uint8_t*)dev->page->pixels + x + y * dev->page->pitch) = !broken ? 255 : 120; + if (y + 1 < dev->page->h) + *((uint8_t*)dev->page->pixels + x + (y + 1)*dev->page->pitch) = 120; + } + } +} + + +static void +print_bit_graph(escp_t *dev, uint8_t ch) +{ + uint8_t pixel_w; /* width of the "pixel" */ + uint8_t pixel_h; /* height of the "pixel" */ + uint8_t i, j, xx, yy; + double old_y; + + dev->bg_column[dev->bg_bytes_read++] = ch; + dev->bg_remaining_bytes--; + + /* Only print after reading a full column. */ + if (dev->bg_bytes_read < dev->bg_bytes_per_column) + return; + + old_y = dev->curr_y; + + pixel_w = 1; + pixel_h = 1; + + if (dev->bg_adjacent) + { + /* if page DPI is bigger than bitgraphics DPI, drawn pixels get "bigger" */ + pixel_w = dev->dpi / dev->bg_h_density > 0 ? dev->dpi / dev->bg_h_density : 1; + pixel_h = dev->dpi / dev->bg_v_density > 0 ? dev->dpi / dev->bg_v_density : 1; + } + + + + for (i = 0; i < dev->bg_bytes_per_column; i++) { + /* for each byte */ + for (j = 128; j != 0; j >>= 1) { + /* for each bit */ + if (dev->bg_column[i] & j) { + /* draw a "pixel" */ + for (xx = 0; xx < pixel_w; xx++) { + for (yy = 0; yy < pixel_h; yy++) { + if (((PIXX + xx) < dev->page->w) && ((PIXY + yy) < dev->page->h)) { + *((uint8_t *)dev->page->pixels + (PIXX + xx) + (PIXY + yy)*dev->page->pitch) |= (dev->color | 0x1f); + //((uint8_t *)(dev->page->pixels))[(PIXY + yy) * dev->page->pitch + (PIXX + xx)] |= (dev->color | 0x1f); + } + } + } + } + + dev->curr_y += 1.0 / dev->bg_v_density; + } + } + + /* Mark page dirty. */ + dev->page->dirty = 1; + + /* Restore Y-position. */ + dev->curr_y = old_y; + + /* Advance print head. */ + dev->curr_x += 1.0 / dev->bg_h_density; +} + + +static void +handle_char(escp_t *dev) +{ + FT_UInt char_index; + uint16_t pen_x, pen_y; + uint8_t ch = dev->data; + uint16_t line_start, line_y; + double x_advance; + + if (dev->page == NULL) return; + + /* MSB mode */ + if (dev->msb != 255) { + if (dev->msb == 0) + ch &= 0x7f; + else if (dev->msb == 1) + ch |= 0x80; + } + + if (dev->bg_remaining_bytes > 0) { + print_bit_graph(dev, ch); + return; + } + + //pclog("Device data=%02x\n", ch); + + /* "print everything" mode? aka. ESC ( ^ */ + if (dev->print_everything_count > 0) { + /* do not process command char, just continue */ + dev->print_everything_count--; + } else if (process_char(dev, ch)) { + /* command was processed */ + return; + } + + /* We cannot print if we have no font loaded. */ + if (dev->fontface == 0) return; + + /* ok, so we need to print the character now */ + if (ft_lib) { + char_index = ft_Get_Char_Index(dev->fontface, dev->curr_cpmap[ch]); + ft_Load_Glyph(dev->fontface, char_index, FT_LOAD_DEFAULT); + ft_Render_Glyph(dev->fontface->glyph, FT_RENDER_MODE_NORMAL); + } + + pen_x = PIXX + dev->fontface->glyph->bitmap_left; + pen_y = (uint16_t)(PIXY - dev->fontface->glyph->bitmap_top + dev->fontface->size->metrics.ascender / 64); + + if (dev->font_style & STYLE_SUBSCRIPT) + pen_y += dev->fontface->glyph->bitmap.rows / 2; + + /* mark the page as dirty if anything is drawn */ + if ((ch != 0x20) || (dev->font_score != SCORE_NONE)) + dev->page->dirty = 1; + + /* draw the glyph */ + blit_glyph(dev, pen_x, pen_y, 0); + + /* doublestrike -> draw glyph a second time, 1px below */ + if (dev->font_style & STYLE_DOUBLESTRIKE) + blit_glyph(dev, pen_x, pen_y + 1, 1); + + /* bold -> draw glyph a second time, 1px to the right */ + if (dev->font_style & STYLE_BOLD) + blit_glyph(dev, pen_x + 1, pen_y, 1); + + line_start = PIXX; + + if (dev->font_style & STYLE_PROP) { + x_advance = dev->fontface->glyph->advance.x / (dev->dpi * 64.0); + } else { + if (dev->hmi < 0) + x_advance = 1.0 / dev->actual_cpi; + else + x_advance = dev->hmi; + } + + x_advance += dev->extra_intra_space; + dev->curr_x += x_advance; + + /* Line printing (underline etc.) */ + if (dev->font_score != SCORE_NONE && (dev->font_style & (STYLE_UNDERLINE | STYLE_STRIKETHROUGH | STYLE_OVERSCORE))) { + /* Find out where to put the line. */ + line_y = PIXY; + + if (dev->font_style & STYLE_UNDERLINE) + line_y = pen_y + 5 + dev->fontface->glyph->bitmap.rows; + if (dev->font_style & STYLE_STRIKETHROUGH) + line_y = (PIXY + (uint16_t)(dev->fontface->size->metrics.ascender / 128.0)); + if (dev->font_style & STYLE_OVERSCORE) + line_y = PIXY - ((dev->font_score == SCORE_DOUBLE || dev->font_score == SCORE_DOUBLEBROKEN) ? 5 : 0); + + draw_hline(dev, pen_x, PIXX, line_y, dev->font_score == SCORE_SINGLEBROKEN || dev->font_score == SCORE_DOUBLEBROKEN); + + if (dev->font_score == SCORE_DOUBLE || dev->font_score == SCORE_DOUBLEBROKEN) + draw_hline(dev, line_start, PIXX, line_y + 5, dev->font_score == SCORE_SINGLEBROKEN || dev->font_score == SCORE_DOUBLEBROKEN); + } + + if ((dev->curr_x + x_advance) > dev->right_margin) { + dev->curr_x = dev->left_margin; + dev->curr_y += dev->linespacing; + if (dev->curr_y > dev->bottom_margin) + new_page(dev, 1, 0); + } +} + + +static void +write_data(uint8_t val, void *priv) +{ + escp_t *dev = (escp_t *)priv; + + //DBGLOG(1, "ESC/P: data(%02x)\n", val); + + if (dev == NULL) return; + + dev->data = val; +} + + +static void +write_ctrl(uint8_t val, void *priv) +{ + escp_t *dev = (escp_t *)priv; + + ////pclog("ESC/P: ctrl(%02x)\n", val); + + if (dev == NULL) return; + + /* set autofeed value */ + dev->autofeed = val & 0x02 ? 1 : 0; + + if (val & 0x08) { /* SELECT */ + /* select printer */ + dev->select = 1; + } + + if ((val & 0x04) == 0) { + /* reset printer */ + dev->select = 0; + + reset_printer(dev); + } + + //pclog("Write control %02x\n", val & 1); + + if (val & 0x01) { /* STROBE */ + /* Process incoming character. */ + handle_char(dev); + + /* ACK it, will be read on next READ STATUS. */ + dev->ack = 1; + } +} + + +static uint8_t +read_status(void *priv) +{ + escp_t *dev = (escp_t *)priv; + uint8_t ret; + + if (dev == NULL) { + ret = 0xdf; + + return(ret); + } + else { + ret = 0x1f; + + if (!dev->busy) + ret |= 0x80; + + if (!dev->ack) + ret |= 0x40; + + //DEBUG("ESC/P: status(%02x)\n", ret); + + return(ret); + } + +} + + +static void * +escp_init(const lpt_device_t *INFO) +{ + const char *fn = PATH_FREETYPE_DLL; + escp_t *dev; + + //pclog("ESC/P: LPT printer '%s' initializing\n", INFO->name); + + /* Dynamically load FreeType. */ + if (ft_handle == NULL) { + ft_handle = dynld_module(fn, ft_imports); + if (ft_handle == NULL) { + ui_msgbox(MBX_ERROR, (wchar_t *)IDS_2081); + //ERRLOG("ESC/P: unable to load FreeType DLL !\n"); + return(NULL); + } + } + + /* Initialize FreeType. */ + if (ft_lib == NULL) { + if (ft_Init_FreeType(&ft_lib)) { + ui_msgbox(MBX_ERROR, (wchar_t *)IDS_2081); + //ERRLOG("ESC/P: error initializing FreeType !\n"); + dynld_close(ft_lib); + ft_lib = NULL; + return(NULL); + } + } + + /* Initialize a device instance. */ + dev = (escp_t *)malloc(sizeof(escp_t)); + memset(dev, 0x00, sizeof(escp_t)); + dev->name = INFO->name; + + /* Create a full pathname for the font files. */ + wcscpy(dev->fontpath, exe_path); + plat_path_slash(dev->fontpath); + wcscpy(dev->fontpath, L"roms/printer/"); + wcscat(dev->fontpath, L"fonts/"); + + /* Create the full path for the page images. */ + plat_append_filename(dev->pagepath, usr_path, L"printer"); + if (! plat_dir_check(dev->pagepath)) + plat_dir_create(dev->pagepath); + plat_path_slash(dev->pagepath); + + /* Initialize parameters. */ + reset_printer(dev); + + /* Create 8-bit grayscale buffer for the page. */ + dev->page = (psurface_t *)malloc(sizeof(psurface_t)); + dev->page->w = (int)(dev->dpi * dev->page_width); + dev->page->h = (int)(dev->dpi * dev->page_height); + dev->page->pitch = dev->page->w; + dev->page->pixels = (uint8_t *)malloc(dev->page->pitch * dev->page->h); + memset(dev->page->pixels, 0x00, dev->page->pitch * dev->page->h); + + //pclog("ESC/P: created a virtual page of dimensions %d x %d pixels.\n", + //dev->page->w, dev->page->h); + return(dev); +} + + +static void +escp_close(void *priv) +{ + escp_t *dev = (escp_t *)priv; + + if (dev == NULL) return; + + if (dev->page != NULL) { + /* Print last page if it contains data. */ + if (dev->page->dirty) + dump_page(dev); + + if (dev->page->pixels != NULL) + free(dev->page->pixels); + free(dev->page); + } + + free(dev); +} + + +const lpt_device_t lpt_prt_escp_device = { + "EPSON ESC/P compatible printer", + escp_init, + escp_close, + write_data, + write_ctrl, + read_status +}; diff --git a/src/printer/prt_text.c b/src/printer/prt_text.c new file mode 100644 index 000000000..9236820cd --- /dev/null +++ b/src/printer/prt_text.c @@ -0,0 +1,458 @@ +/* + * VARCem Virtual ARchaeological Computer EMulator. + * An emulator of (mostly) x86-based PC systems and devices, + * using the ISA,EISA,VLB,MCA and PCI system buses, roughly + * spanning the era between 1981 and 1995. + * + * This file is part of the VARCem Project. + * + * Implementation of a generic text printer. + * + * Simple old text printers were unable to do any formatting + * of the text. They were just sheets of paper with a fixed + * size (in the U.S., this would be Letter, 8.5"x11") with a + * set of fixed margings to allow for proper operation of the + * printer mechanics. This would lead to a page being 66 lines + * of 80 characters each. + * + * Version: @(#)prt_text.c 1.0.3 2018/10/05 + * + * Author: Fred N. van Kempen, + * + * Copyright 2018 Fred N. van Kempen. + * + * Redistribution and use in source and binary forms, with + * or without modification, are permitted provided that the + * following conditions are met: + * + * 1. Redistributions of source code must retain the entire + * above notice, this list of conditions and the following + * disclaimer. + * + * 2. Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names + * of its contributors may be used to endorse or promote + * products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#include +#include +#include +#include +#include +#include "../86box.h" +#include "../device.h" +#include "../timer.h" +#include "../plat.h" +#include "../lpt.h" +#include "printer.h" +#include "prt_devs.h" + + +#define FULL_PAGE 1 /* set if no top/bot margins */ + + +/* Default page values (for now.) */ +#define PAGE_WIDTH 8.5 /* standard U.S. Letter */ +#define PAGE_HEIGHT 11 +#define PAGE_LMARGIN 0.25 /* 0.25" left and right */ +#define PAGE_RMARGIN 0.25 +#if FULL_PAGE +# define PAGE_TMARGIN 0 +# define PAGE_BMARGIN 0 +#else +# define PAGE_TMARGIN 0.25 +# define PAGE_BMARGIN 0.25 +#endif +#define PAGE_CPI 10.0 /* standard 10 cpi */ +#define PAGE_LPI 6.0 /* standard 6 lpi */ + + +typedef struct { + int8_t dirty; /* has the page been printed on? */ + char pad; + + uint8_t w; /* size //INFO */ + uint8_t h; + + char *chars; /* character data */ +} psurface_t; + + +typedef struct { + const char *name; + + /* Output file name. */ + wchar_t filename[1024]; + + /* page data (TODO: make configurable) */ + double page_width, /* all in inches */ + page_height, + left_margin, + top_margin, + right_margin, + bot_margin; + + /* internal page data */ + psurface_t *page; + uint8_t max_chars, + max_lines; + uint8_t curr_x, /* print head position (chars) */ + curr_y; + + /* font data */ + double cpi, /* defined chars per inch */ + lpi; /* defined lines per inch */ + + /* handshake data */ + uint8_t data; + int8_t ack; + int8_t select; + int8_t busy; + int8_t int_pending; + int8_t error; + int8_t autofeed; +} prnt_t; + + +/* Dump the current page into a formatted file. */ +static void +dump_page(prnt_t *dev) +{ + wchar_t path[1024]; + uint16_t x, y; + uint8_t ch; + FILE *fp; + + /* Create the full path for this file. */ + memset(path, 0x00, sizeof(path)); + plat_append_filename(path, usr_path, L"printer"); + if (! plat_dir_check(path)) + plat_dir_create(path); + plat_path_slash(path); + wcscat(path, dev->filename); + + /* Create the file. */ + fp = plat_fopen(path, L"a"); + if (fp == NULL) { + //ERRLOG("PRNT: unable to create print page '%ls'\n", path); + return; + } + fseek(fp, 0, SEEK_END); + + /* If this is not a new file, add a formfeed first. */ + if (ftell(fp) != 0) + fputc('\014', fp); + + for (y = 0; y < dev->curr_y; y++) { + for (x = 0; x < dev->page->w; x++) { + ch = dev->page->chars[(y * dev->page->w) + x]; + if (ch == 0x00) { + /* End of line marker. */ + fputc('\n', fp); + break; + } else { + fputc(ch, fp); + } + } + } + + /* All done, close the file. */ + fclose(fp); +} + + +static void +new_page(prnt_t *dev) +{ + /* Dump the current page if needed. */ + if (dev->page->dirty) + dump_page(dev); + + /* Clear page. */ + memset(dev->page->chars, 0x00, dev->page->h * dev->page->w); + dev->curr_y = 0; + dev->page->dirty = 0; +} + + +static void +reset_printer(prnt_t *dev) +{ + /* TODO: these three should be configurable */ + dev->page_width = PAGE_WIDTH; + dev->page_height = PAGE_HEIGHT; + dev->left_margin = PAGE_LMARGIN; + dev->right_margin = PAGE_RMARGIN; + dev->top_margin = PAGE_TMARGIN; + dev->bot_margin = PAGE_BMARGIN; + dev->cpi = PAGE_CPI; + dev->lpi = PAGE_LPI; + + /* Default page layout. */ + dev->max_chars = (int) ((dev->page_width - dev->left_margin - dev->right_margin) * dev->cpi); + dev->max_lines = (int) ((dev->page_height -dev->top_margin - dev->bot_margin) * dev->lpi); + + //INFO("PRNT: width=%.1fin,height=%.1fin cpi=%i lpi=%i cols=%i lines=%i\n", + // dev->page_width, dev->page_height, (int)dev->cpi, + // (int)dev->lpi, dev->max_chars, dev->max_lines); + + dev->curr_x = dev->curr_y = 0; + + if (dev->page != NULL) + dev->page->dirty = 0; + + /* Create a file for this page. */ + plat_tempfile(dev->filename, NULL, L".txt"); +} + + +static int +process_char(prnt_t *dev, uint8_t ch) +{ + uint8_t i; + + switch (ch) { + case 0x07: /* Beeper (BEL) */ + /* TODO: beep? */ + return 1; + + case 0x08: /* Backspace (BS) */ + if (dev->curr_x > 0) + dev->curr_x--; + return 1; + + case 0x09: /* Tab horizontally (HT) */ + /* Find tab right to current pos. */ + i = dev->curr_x; + dev->page->chars[(dev->curr_y * dev->page->w) + i++] = ' '; + while ((i < dev->max_chars) && ((i % 8) != 0)) { + dev->page->chars[(dev->curr_y * dev->page->w) + i] = ' '; + i++; + } + dev->curr_x = i; + return 1; + + case 0x0b: /* Tab vertically (VT) */ + dev->curr_x = 0; + return 1; + + case 0x0c: /* Form feed (FF) */ + new_page(dev); + return 1; + + case 0x0d: /* Carriage Return (CR) */ + dev->curr_x = 0; + if (! dev->autofeed) + return 1; + /*FALLTHROUGH*/ + + case 0x0a: /* Line feed */ + dev->curr_x = 0; + if (++dev->curr_y >= dev->max_lines) + new_page(dev); + return 1; + + case 0x0e: /* select wide printing (SO) */ + /* Ignore. */ + return 1; + + case 0x0f: /* select condensed printing (SI) */ + /* Ignore. */ + return 1; + + case 0x11: /* select printer (DC1) */ + /* Ignore. */ + return 1; + + case 0x12: /* cancel condensed printing (DC2) */ + /* Ignore. */ + return 1; + + case 0x13: /* deselect printer (DC3) */ + /* Ignore. */ + return 1; + + case 0x14: /* cancel double-width printing (one line) (DC4) */ + /* Ignore. */ + return 1; + + case 0x18: /* cancel line (CAN) */ + /* Ignore. */ + return 1; + + case 0x1b: /* ESC */ + /* Ignore. */ + return 1; + + default: + break; + } + + /* Just a printable character. */ + return(0); +} + + +static void +handle_char(prnt_t *dev) +{ + uint8_t ch = dev->data; + + if (dev->page == NULL) return; + + if (process_char(dev, ch) == 1) { + /* Command was processed. */ + return; + } + + /* Store character in the page buffer. */ + dev->page->chars[(dev->curr_y * dev->page->w) + dev->curr_x] = ch; + dev->page->dirty = 1; + + /* Update print head position. */ + if (++dev->curr_x >= dev->max_chars) { + dev->curr_x = 0; + if (++dev->curr_y >= dev->max_lines) + new_page(dev); + } +} + + +static void +write_data(uint8_t val, void *priv) +{ + prnt_t *dev = (prnt_t *)priv; + + if (dev == NULL) return; + + dev->data = val; +} + + +static void +write_ctrl(uint8_t val, void *priv) +{ + prnt_t *dev = (prnt_t *)priv; + + if (dev == NULL) return; + + /* set autofeed value */ + dev->autofeed = val & 0x02 ? 1 : 0; + + if (val & 0x08) { /* SELECT */ + /* select printer */ + dev->select = 1; + } + + if ((val & 0x04) == 0) { + /* reset printer */ + dev->select = 0; + + reset_printer(dev); + } + + if (val & 0x01) { /* STROBE */ + /* Process incoming character. */ + handle_char(dev); + + /* ACK it, will be read on next READ STATUS. */ + dev->ack = 1; + } +} + + +static uint8_t +read_status(void *priv) +{ + prnt_t *dev = (prnt_t *)priv; + uint8_t ret = 0xff; + + if (dev == NULL) return(ret); + + ret = (dev->ack ? 0x00 : 0x40) | + (dev->select ? 0x10 : 0x00) | + (dev->busy ? 0x00 : 0x80) | + (dev->int_pending ? 0x00 : 0x04) | + (dev->error ? 0x00 : 0x08); + + /* Clear ACK after reading status. */ + dev->ack = 0; + + return(ret); +} + + +static void * +prnt_init(const lpt_device_t *INFO) +{ + prnt_t *dev; + + /* Initialize a device instance. */ + dev = (prnt_t *)malloc(sizeof(prnt_t)); + memset(dev, 0x00, sizeof(prnt_t)); + dev->name = INFO->name; + + //INFO("PRNT: LPT printer '%s' initializing\n", dev->name); + + /* Initialize parameters. */ + reset_printer(dev); + + /* Create a page buffer. */ + dev->page = (psurface_t *)malloc(sizeof(psurface_t)); + dev->page->w = dev->max_chars; + dev->page->h = dev->max_lines; + dev->page->chars = (char *)malloc(dev->page->w * dev->page->h); + memset(dev->page->chars, 0x00, dev->page->w * dev->page->h); + + //DEBUG("PRNT: created a virtual %ix%i page.\n", dev->page->w, dev->page->h); + + return(dev); +} + + +static void +prnt_close(void *priv) +{ + prnt_t *dev = (prnt_t *)priv; + + if (dev == NULL) return; + + /* print last page if it contains data */ + if (dev->page->dirty) + dump_page(dev); + + if (dev->page != NULL) { + if (dev->page->chars != NULL) + free(dev->page->chars); + free(dev->page); + } + + free(dev); +} + + +const lpt_device_t lpt_prt_text_device = { + "Generic TEXT printer", + prnt_init, + prnt_close, + write_data, + write_ctrl, + read_status +}; diff --git a/src/video/vid_sigma.c b/src/video/vid_sigma.c index a22b26119..66fe48300 100644 --- a/src/video/vid_sigma.c +++ b/src/video/vid_sigma.c @@ -426,7 +426,7 @@ static void sigma_text80(sigma_t *sigma) cols[0] = (attr >> 4) | 16; } - if (drawcursor && !(x & 1)) { + if (drawcursor) { for (c = 0; c < 8; c++) { if (sigma->sigmamode & MODE_FONT16) buffer->line[sigma->displine][(x << 3) + c + 8] = cols[(fontdatm[chr][sigma->sc & 15] & (1 << (c ^ 7))) ? 1 : 0] ^ 0x0f; diff --git a/src/win/Makefile.mingw b/src/win/Makefile.mingw index bad6fcabc..b93b201fe 100644 --- a/src/win/Makefile.mingw +++ b/src/win/Makefile.mingw @@ -199,6 +199,7 @@ endif ######################################################################### VPATH := $(EXPATH) . cpu \ cdrom disk floppy game machine \ + printer \ sound \ sound/munt sound/munt/c_interface sound/munt/sha1 \ sound/munt/srchelper \ @@ -495,6 +496,9 @@ NETOBJ := network.o \ net_3c503.o net_ne2000.o \ net_wd8003.o +PRINTOBJ := png.o prt_cpmap.o \ + prt_escp.o prt_text.o + SNDOBJ := sound.o \ openal.o \ snd_opl.o snd_dbopl.o \ @@ -555,7 +559,7 @@ PLATOBJ := win.o \ OBJ := $(MAINOBJ) $(INTELOBJ) $(CPUOBJ) $(MCHOBJ) $(DEVOBJ) \ $(FDDOBJ) $(CDROMOBJ) $(ZIPOBJ) $(HDDOBJ) \ - $(USBOBJ) $(NETOBJ) $(SCSIOBJ) $(SNDOBJ) $(VIDOBJ) \ + $(USBOBJ) $(NETOBJ) $(PRINTOBJ) $(SCSIOBJ) $(SNDOBJ) $(VIDOBJ) \ $(PLATOBJ) $(UIOBJ) $(FSYNTHOBJ) $(MUNTOBJ) \ $(DEVBROBJ) ifdef EXOBJ diff --git a/src/win/win.c b/src/win/win.c index e4950b7f8..bd3b259c8 100644 --- a/src/win/win.c +++ b/src/win/win.c @@ -431,6 +431,25 @@ plat_get_exe_name(wchar_t *s, int size) GetModuleFileName(hinstance, s, size); } +void +plat_tempfile(wchar_t *bufp, wchar_t *prefix, wchar_t *suffix) +{ + SYSTEMTIME SystemTime; + char temp[1024]; + + if (prefix != NULL) + sprintf(temp, "%ls-", prefix); + else + strcpy(temp, ""); + + GetSystemTime(&SystemTime); + sprintf(&temp[strlen(temp)], "%d%02d%02d-%02d%02d%02d-%03d%ls", + SystemTime.wYear, SystemTime.wMonth, SystemTime.wDay, + SystemTime.wHour, SystemTime.wMinute, SystemTime.wSecond, + SystemTime.wMilliseconds, + suffix); + mbstowcs(bufp, temp, strlen(temp)+1); +} int plat_getcwd(wchar_t *bufp, int max)