All Rights Reserved.
This software is provided AS-IS with no warranty, either express or
implied.
This software is distributed under license and may not be copied,
modified or distributed except as expressly authorized under the terms
of the license contained in the file LICENSE in this distribution.
Refer to licensing information at http://www.artifex.com or contact
Artifex Software, Inc., 39 Mesa Street, Suite 108A, San Francisco,
CA 94129, USA, for further information.
*/
* New DLL interface, uses display device.
* Uses same interface to gspmdrv.c as os2pm device.
*/
#define INCL_DOS
#define INCL_DOSERRORS
#define INCL_WIN
#define INCL_GPI
#include <os2.h>
#include <stdio.h>
#include <string.h>
#include <time.h>
#include <io.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/select.h>
#include "gscdefs.h"
#define GS_REVISION gs_revision
#include "ierrors.h"
#include "iapi.h"
#include "gdevdsp.h"
#define MAXSTR 256
#define BITMAPINFO2_SIZE 40
const char *szDllName = "GSDLL2.DLL";
char start_string[] = "systemdict /start get exec\n";
int debug = TRUE ;
#define MIN_COMMIT 4096
#define ID_NAME "GSPMDRV_%u_%u"
#define SHARED_NAME "\\SHAREMEM\\%s"
#define SYNC_NAME "\\SEM32\\SYNC_%s"
#define MUTEX_NAME "\\SEM32\\MUTEX_%s"
LONG display_planes;
LONG display_bitcount;
LONG display_hasPalMan;
ULONG os_version;
typedef struct tagGSDLL {
HMODULE hmodule;
PFN_gsapi_revision revision;
PFN_gsapi_new_instance new_instance;
PFN_gsapi_delete_instance delete_instance;
PFN_gsapi_set_stdio set_stdio;
PFN_gsapi_set_poll set_poll;
PFN_gsapi_set_display_callback set_display_callback;
PFN_gsapi_init_with_args init_with_args;
PFN_gsapi_run_string run_string;
PFN_gsapi_exit exit;
PFN_gsapi_set_arg_encoding set_arg_encoding;
PFN_gsapi_set_default_device_list set_default_device_list;
PFN_gsapi_get_default_device_list get_default_device_list;
PFN_gsapi_run_file run_file;
PFN_gsapi_run_string_begin run_string_begin;
PFN_gsapi_run_string_continue run_string_continue;
PFN_gsapi_run_string_end run_string_end;
PFN_gsapi_run_string_with_length run_string_with_length;
PFN_gsapi_set_param set_param;
PFN_gsapi_add_control_path add_control_path;
PFN_gsapi_remove_control_path remove_control_path;
PFN_gsapi_purge_control_paths purge_control_paths;
PFN_gsapi_activate_path_control activate_path_control;
PFN_gsapi_is_path_control_active is_path_control_active;
PFN_gsapi_add_fs add_fs;
PFN_gsapi_remove_fs remove_fs;
} GSDLL;
GSDLL gsdll;
void *instance;
TID tid;
void
gs_addmess(char *str)
{
fputs(str, stdout);
fflush(stdout);
}
BOOL
gs_free_dll(void)
{
char buf[MAXSTR];
APIRET rc;
if (gsdll.hmodule == (HMODULE) NULL)
return TRUE;
rc = DosFreeModule(gsdll.hmodule);
if (rc) {
gs_snprintf(buf, sizeof(buf), "DosFreeModule returns %d\n", rc);
gs_addmess(buf);
gs_snprintf(buf, sizeof(buf), "Unloaded GSDLL\n\n");
gs_addmess(buf);
}
return !rc;
}
void
gs_load_dll_cleanup(void)
{
char buf[MAXSTR];
gs_free_dll();
}
BOOL
gs_load_dll(void)
{
char buf[MAXSTR + 40];
APIRET rc;
char *p;
int i;
const char *dllname;
PTIB pptib;
PPIB pppib;
char szExePath[MAXSTR];
char fullname[1024];
const char *shortname;
gsapi_revision_t rv;
if ((rc = DosGetInfoBlocks(&pptib, &pppib)) != 0) {
fprintf(stdout, "Couldn't get pid, rc = \n", rc);
return FALSE;
}
if ((rc = DosQueryModuleName(pppib->pib_hmte, sizeof(szExePath),
szExePath)) != 0) {
fprintf(stdout, "Couldn't get module name, rc = %d\n", rc);
return FALSE;
}
if ((p = strrchr(szExePath, '\\')) != (char *)NULL) {
p++;
*p = '\0';
}
dllname = szDllName;
#ifdef DEBUG
if (debug) {
gs_snprintf(buf, sizeof(buf), "Trying to load %s\n", dllname);
gs_addmess(buf);
}
#endif
memset(buf, 0, sizeof(buf));
rc = DosLoadModule(buf, sizeof(buf), dllname, &gsdll.hmodule);
if (rc) {
if ((shortname = strrchr((char *)szDllName, '\\'))
== (const char *)NULL)
shortname = szDllName;
strcpy(fullname, szExePath);
if ((p = strrchr(fullname, '\\')) != (char *)NULL)
p++;
else
p = fullname;
*p = '\0';
strcat(fullname, shortname);
dllname = fullname;
#ifdef DEBUG
if (debug) {
gs_snprintf(buf, sizeof(buf), "Trying to load %s\n", dllname);
gs_addmess(buf);
}
#endif
rc = DosLoadModule(buf, sizeof(buf), dllname, &gsdll.hmodule);
if (rc) {
dllname = shortname;
#ifdef DEBUG
if (debug) {
gs_snprintf(buf, sizeof(buf), "Trying to load %s\n", dllname);
gs_addmess(buf);
}
#endif
rc = DosLoadModule(buf, sizeof(buf), dllname, &gsdll.hmodule);
}
}
if (rc == 0) {
#ifdef DEBUG
if (debug)
gs_addmess("Loaded Ghostscript DLL\n");
#endif
if ((rc = DosQueryProcAddr(gsdll.hmodule, 0, "GSAPI_REVISION",
(PFN *) (&gsdll.revision))) != 0) {
gs_snprintf(buf, sizeof(buf), "Can't find GSAPI_REVISION, rc = %d\n", rc);
gs_addmess(buf);
gs_load_dll_cleanup();
return FALSE;
}
if (gsdll.revision(&rv, sizeof(rv)) != 0) {
gs_snprintf(buf, sizeof(buf), "Unable to identify Ghostscript DLL revision - it must be newer than needed.\n");
gs_addmess(buf);
gs_load_dll_cleanup();
return FALSE;
}
if (rv.revision != GS_REVISION) {
gs_snprintf(buf, sizeof(buf), "Wrong version of DLL found.\n Found version %ld\n Need version %ld\n", rv.revision, (long)GS_REVISION);
gs_addmess(buf);
gs_load_dll_cleanup();
return FALSE;
}
if ((rc = DosQueryProcAddr(gsdll.hmodule, 0, "GSAPI_NEW_INSTANCE",
(PFN *) (&gsdll.new_instance))) != 0) {
gs_snprintf(buf, sizeof(buf), "Can't find GSAPI_NEW_INSTANCE, rc = %d\n", rc);
gs_addmess(buf);
gs_load_dll_cleanup();
return FALSE;
}
if ((rc = DosQueryProcAddr(gsdll.hmodule, 0, "GSAPI_DELETE_INSTANCE",
(PFN *) (&gsdll.delete_instance))) != 0) {
gs_snprintf(buf, sizeof(buf), "Can't find GSAPI_DELETE_INSTANCE, rc = %d\n", rc);
gs_addmess(buf);
gs_load_dll_cleanup();
return FALSE;
}
if ((rc = DosQueryProcAddr(gsdll.hmodule, 0, "GSAPI_SET_STDIO",
(PFN *) (&gsdll.set_stdio))) != 0) {
gs_snprintf(buf, sizeof(buf), "Can't find GSAPI_SET_STDIO, rc = %d\n", rc);
gs_addmess(buf);
gs_load_dll_cleanup();
return FALSE;
}
if ((rc = DosQueryProcAddr(gsdll.hmodule, 0, "GSAPI_SET_DISPLAY_CALLBACK",
(PFN *) (&gsdll.set_display_callback))) != 0) {
gs_snprintf(buf, sizeof(buf), "Can't find GSAPI_SET_DISPLAY_CALLBACK, rc = %d\n", rc);
gs_addmess(buf);
gs_load_dll_cleanup();
return FALSE;
}
if ((rc = DosQueryProcAddr(gsdll.hmodule, 0, "GSAPI_SET_POLL",
(PFN *) (&gsdll.set_poll))) != 0) {
gs_snprintf(buf, sizeof(buf), "Can't find GSAPI_SET_POLL, rc = %d\n", rc);
gs_addmess(buf);
gs_load_dll_cleanup();
return FALSE;
}
if ((rc = DosQueryProcAddr(gsdll.hmodule, 0,
"GSAPI_INIT_WITH_ARGS",
(PFN *) (&gsdll.init_with_args))) != 0) {
gs_snprintf(buf, sizeof(buf), "Can't find GSAPI_INIT_WITH_ARGS, rc = %d\n", rc);
gs_addmess(buf);
gs_load_dll_cleanup();
return FALSE;
}
if ((rc = DosQueryProcAddr(gsdll.hmodule, 0, "GSAPI_RUN_STRING",
(PFN *) (&gsdll.run_string))) != 0) {
gs_snprintf(buf, sizeof(buf), "Can't find GSAPI_RUN_STRING, rc = %d\n", rc);
gs_addmess(buf);
gs_load_dll_cleanup();
return FALSE;
}
if ((rc = DosQueryProcAddr(gsdll.hmodule, 0, "GSAPI_EXIT",
(PFN *) (&gsdll.exit))) != 0) {
gs_snprintf(buf, sizeof(buf), "Can't find GSAPI_EXIT, rc = %d\n", rc);
gs_addmess(buf);
gs_load_dll_cleanup();
return FALSE;
}
} else {
gs_snprintf(buf, sizeof(buf), "Can't load Ghostscript DLL %s \nDosLoadModule rc = %d\n",
szDllName, rc);
gs_addmess(buf);
gs_load_dll_cleanup();
return FALSE;
}
return TRUE;
}
static int
gsdll_stdin(void *instance, char *buf, int len)
{
return read(fileno(stdin), buf, len);
}
static int
gsdll_stdout(void *instance, const char *str, int len)
{
fwrite(str, 1, len, stdout);
fflush(stdout);
return len;
}
static int
gsdll_stderr(void *instance, const char *str, int len)
{
fwrite(str, 1, len, stderr);
fflush(stderr);
return len;
}
#define DISPLAY_DEBUG
*/
typedef struct IMAGE_S IMAGE;
struct IMAGE_S {
void *handle;
void *device;
PID pid;
HEV sync_event;
HMTX bmp_mutex;
HQUEUE term_queue;
ULONG session_id;
PID process_id;
int width;
int height;
int raster;
int format;
BOOL format_known;
unsigned char *bitmap;
ULONG committed;
IMAGE *next;
};
IMAGE *first_image = NULL;
static IMAGE *image_find(void *handle, void *device);
static IMAGE *
image_find(void *handle, void *device)
{
IMAGE *img;
for (img = first_image; img!=0; img=img->next) {
if ((img->handle == handle) && (img->device == device))
return img;
}
return NULL;
}
static int run_gspmdrv(IMAGE *img)
{
int ccode;
PCHAR pdrvname = "gspmdrv.exe";
CHAR error_message[256];
CHAR term_queue_name[128];
CHAR id[128];
CHAR arg[1024];
STARTDATA sdata;
APIRET rc;
PTIB pptib;
PPIB pppib;
CHAR progname[256];
PCHAR tail;
#ifdef DEBUG
if (debug)
fprintf(stdout, "run_gspmdrv: starting\n");
#endif
gs_snprintf(id, sizeof(id), ID_NAME, img->pid, (ULONG)img->device);
gs_snprintf(term_queue_name, sizeof(term_queue_name), "\\QUEUES\\TERMQ_%s", id);
if (DosCreateQueue(&(img->term_queue), QUE_FIFO, term_queue_name)) {
fprintf(stdout, "run_gspmdrv: failed to create termination queue\n");
return gs_error_limitcheck;
}
if ((rc = DosGetInfoBlocks(&pptib, &pppib)) != 0) {
fprintf(stdout, "run_gspmdrv: Couldn't get module handle, rc = %d\n",
rc);
return gs_error_limitcheck;
}
if ((rc = DosQueryModuleName(pppib->pib_hmte, sizeof(progname) - 1,
progname)) != 0) {
fprintf(stdout, "run_gspmdrv: Couldn't get module name, rc = %d\n",
rc);
return gs_error_limitcheck;
}
if ((tail = strrchr(progname, '\\')) != (PCHAR) NULL) {
tail++;
*tail = '\0';
} else
tail = progname;
strcat(progname, pdrvname);
gs_snprintf(arg, sizeof(arg), "-d %s", id);
* we must use start session not DosExecPgm() */
sdata.Length = sizeof(sdata);
sdata.Related = SSF_RELATED_CHILD;
sdata.FgBg = SSF_FGBG_BACK;
sdata.TraceOpt = 0;
sdata.PgmTitle = "Ghostscript PM driver session";
sdata.PgmName = progname;
sdata.PgmInputs = arg;
sdata.TermQ = term_queue_name;
sdata.Environment = pppib->pib_pchenv;
sdata.InheritOpt = 0;
sdata.SessionType = SSF_TYPE_DEFAULT;
sdata.IconFile = NULL;
sdata.PgmHandle = 0;
sdata.PgmControl = 0;
sdata.InitXPos = 0;
sdata.InitYPos = 0;
sdata.InitXSize = 0;
sdata.InitYSize = 0;
sdata.ObjectBuffer = error_message;
sdata.ObjectBuffLen = sizeof(error_message);
rc = DosStartSession(&sdata, &img->session_id, &img->process_id);
if (rc == ERROR_FILE_NOT_FOUND) {
sdata.PgmName = pdrvname;
rc = DosStartSession(&sdata, &img->session_id, &img->process_id);
}
if (rc) {
fprintf(stdout, "run_gspmdrv: failed to run %s, rc = %d\n",
sdata.PgmName, rc);
fprintf(stdout, "run_gspmdrv: error_message: %s\n", error_message);
return gs_error_limitcheck;
}
#ifdef DEBUG
if (debug)
fprintf(stdout, "run_gspmdrv: returning\n");
#endif
return 0;
}
void
image_color(unsigned int format, int index,
unsigned char *r, unsigned char *g, unsigned char *b)
{
switch (format & DISPLAY_COLORS_MASK) {
case DISPLAY_COLORS_NATIVE:
switch (format & DISPLAY_DEPTH_MASK) {
case DISPLAY_DEPTH_1:
*r = *g = *b = (index ? 0 : 255);
break;
case DISPLAY_DEPTH_4:
if (index == 7)
*r = *g = *b = 170;
else if (index == 8)
*r = *g = *b = 85;
else {
int one = index & 8 ? 255 : 128;
*r = (index & 4 ? one : 0);
*g = (index & 2 ? one : 0);
*b = (index & 1 ? one : 0);
}
break;
case DISPLAY_DEPTH_8:
if (index < 64) {
int one = 255 / 3;
*r = ((index & 0x30) >> 4) * one;
*g = ((index & 0x0c) >> 2) * one;
*b = (index & 0x03) * one;
}
else {
int val = index & 0x1f;
*r = *g = *b = (val << 3) + (val >> 2);
}
break;
}
break;
case DISPLAY_COLORS_GRAY:
switch (format & DISPLAY_DEPTH_MASK) {
case DISPLAY_DEPTH_1:
*r = *g = *b = (index ? 255 : 0);
break;
case DISPLAY_DEPTH_4:
*r = *g = *b = (unsigned char)((index<<4) + index);
break;
case DISPLAY_DEPTH_8:
*r = *g = *b = (unsigned char)index;
break;
}
break;
}
}
static int image_palette_size(int format)
{
int palsize = 0;
switch (format & DISPLAY_COLORS_MASK) {
case DISPLAY_COLORS_NATIVE:
switch (format & DISPLAY_DEPTH_MASK) {
case DISPLAY_DEPTH_1:
palsize = 2;
break;
case DISPLAY_DEPTH_4:
palsize = 16;
break;
case DISPLAY_DEPTH_8:
palsize = 96;
break;
}
break;
case DISPLAY_COLORS_GRAY:
switch (format & DISPLAY_DEPTH_MASK) {
case DISPLAY_DEPTH_1:
palsize = 2;
break;
case DISPLAY_DEPTH_4:
palsize = 16;
break;
case DISPLAY_DEPTH_8:
palsize = 256;
break;
}
break;
}
return palsize;
}
int display_open(void *handle, void *device)
{
APIRET rc;
IMAGE *img;
PTIB pptib;
PPIB pppib;
CHAR id[128];
CHAR name[128];
PBITMAPINFO2 bmi;
#ifdef DISPLAY_DEBUG
if (debug)
fputc('o', stdout);
fprintf(stdout, "display_open(0x%x, 0x%x)\n", handle, device);
#endif
if (first_image) {
* gspmdrv.exe which is a PM application. To start
* gspmdrv.exe, DosStartSession is used with SSF_RELATED_CHILD.
* A process can have only one child session marked SSF_RELATED_CHILD.
* When we call DosStopSession for the second session, it will
* close, but it will not write to the termination queue.
* When we wait for the session to end by reading the
* termination queue, we wait forever.
* For this reason, multiple image windows are disabled
* for OS/2.
* To get around this, we would need to replace the current
* method of one gspmdrv.exe session per window, to having
* a new PM application which can display multiple windows
* within a single session.
*/
return gs_error_limitcheck;
}
img = (IMAGE *)malloc(sizeof(IMAGE));
if (img == NULL)
return gs_error_limitcheck;
memset(img, 0, sizeof(IMAGE));
img->next = first_image;
first_image = img;
img->handle = handle;
img->device = device;
if (DosGetInfoBlocks(&pptib, &pppib)) {
fprintf(stdout, "\ndisplay_open: Couldn't get pid\n");
return gs_error_limitcheck;
}
img->pid = pppib->pib_ulppid;
gs_snprintf(id, sizeof(id), ID_NAME, img->pid, (ULONG) img->device);
gs_snprintf(name, sizeof(name), SYNC_NAME, id);
if (DosCreateEventSem(name, &(img->sync_event), 0, FALSE)) {
fprintf(stdout, "display_open: failed to create event semaphore %s\n", name);
return gs_error_limitcheck;
}
gs_snprintf(name, sizeof(name), MUTEX_NAME, id);
if (DosCreateMutexSem(name, &(img->bmp_mutex), 0, FALSE)) {
DosCloseEventSem(img->sync_event);
fprintf(stdout, "display_open: failed to create mutex semaphore %s\n", name);
return gs_error_limitcheck;
}
* allocate too much.
*/
gs_snprintf(name, sizeof(name), SHARED_NAME, id);
if (DosAllocSharedMem((PPVOID) & img->bitmap, name,
13 * 1024 * 1024, PAG_READ | PAG_WRITE)) {
fprintf(stdout, "display_open: failed allocating shared BMP memory %s\n", name);
return gs_error_limitcheck;
}
if (DosSetMem(img->bitmap, MIN_COMMIT, PAG_COMMIT | PAG_DEFAULT)) {
DosFreeMem(img->bitmap);
fprintf(stdout, "display: failed committing BMP memory\n");
return gs_error_limitcheck;
}
img->committed = MIN_COMMIT;
bmi = (PBITMAPINFO2) img->bitmap;
bmi->cbFix = BITMAPINFO2_SIZE;
bmi->cx = 0;
bmi->cy = 0;
bmi->cPlanes = 1;
bmi->cBitCount = 24;
bmi->ulCompression = BCA_UNCOMP;
bmi->cbImage = 0;
bmi->cxResolution = 0;
bmi->cyResolution = 0;
bmi->cclrUsed = 0;
bmi->cclrImportant = 0;
#ifdef DISPLAY_DEBUG
if (debug)
fputc('O', stdout);
#endif
return 0;
}
int display_preclose(void *handle, void *device)
{
IMAGE *img;
REQUESTDATA Request;
ULONG DataLength;
PVOID DataAddress;
PULONG QueueEntry;
BYTE ElemPriority;
#ifdef DISPLAY_DEBUG
if (debug)
fputc('l', stdout);
fprintf(stdout, "display_preclose(0x%x, 0x%x)\n", handle, device);
#endif
img = image_find(handle, device);
if (img) {
if (img->session_id) {
DosStopSession(STOP_SESSION_SPECIFIED, img->session_id);
Request.pid = img->pid;
Request.ulData = 0;
DosReadQueue(img->term_queue, &Request, &DataLength,
&DataAddress, 0, DCWW_WAIT, &ElemPriority, (HEV) NULL);
DosCloseQueue(img->term_queue);
}
img->session_id = 0;
img->term_queue = 0;
DosCloseEventSem(img->sync_event);
DosCloseMutexSem(img->bmp_mutex);
}
#ifdef DISPLAY_DEBUG
if (debug)
fputc('L', stdout);
#endif
return 0;
}
int display_close(void *handle, void *device)
{
IMAGE *img;
#ifdef DISPLAY_DEBUG
if (debug)
fputc('c', stdout);
fprintf(stdout, "display_close(0x%x, 0x%x)\n", handle, device);
#endif
img = image_find(handle, device);
if (img) {
DosFreeMem(img->bitmap);
img->bitmap = (unsigned char *)NULL;
img->committed = 0;
}
#ifdef DISPLAY_DEBUG
if (debug)
fputc('C', stdout);
#endif
return 0;
}
int display_presize(void *handle, void *device, int width, int height,
int raster, unsigned int format)
{
IMAGE *img;
#ifdef DISPLAY_DEBUG
if (debug)
fputc('r', stdout);
fprintf(stdout, "display_presize(0x%x 0x%x, %d, %d, %d, %d)\n",
handle, device, width, height, raster, format);
#endif
img = image_find(handle, device);
if (img) {
int color = format & DISPLAY_COLORS_MASK;
int depth = format & DISPLAY_DEPTH_MASK;
int alpha = format & DISPLAY_ALPHA_MASK;
img->format_known = FALSE;
if ( ((color == DISPLAY_COLORS_NATIVE) ||
(color == DISPLAY_COLORS_GRAY))
&&
((depth == DISPLAY_DEPTH_1) ||
(depth == DISPLAY_DEPTH_4) ||
(depth == DISPLAY_DEPTH_8)) )
img->format_known = TRUE;
if ((color == DISPLAY_COLORS_RGB) && (depth == DISPLAY_DEPTH_8) &&
(alpha == DISPLAY_ALPHA_NONE))
img->format_known = TRUE;
if (!img->format_known) {
fprintf(stdout, "display_presize: format %d = 0x%x is unsupported\n", format, format);
return gs_error_limitcheck;
}
DosRequestMutexSem(img->bmp_mutex, 120000);
img->width = width;
img->height = height;
img->raster = raster;
img->format = format;
}
#ifdef DISPLAY_DEBUG
if (debug)
fputc('R', stdout);
#endif
return 0;
}
int display_size(void *handle, void *device, int width, int height,
int raster, unsigned int format, unsigned char *pimage)
{
IMAGE *img;
PBITMAPINFO2 bmi;
int nColors;
int i;
#ifdef DISPLAY_DEBUG
if (debug)
fputc('z', stdout);
fprintf(stdout, "display_size(0x%x 0x%x, %d, %d, %d, %ld, 0x%x)\n",
handle, device, width, height, raster, format, pimage);
#endif
img = image_find(handle, device);
if (img) {
if (!img->format_known)
return gs_error_limitcheck;
img->width = width;
img->height = height;
img->raster = raster;
img->format = format;
bmi = (PBITMAPINFO2) img->bitmap;
bmi->cbFix = BITMAPINFO2_SIZE;
bmi->cx = img->width;
bmi->cy = img->height;
bmi->cPlanes = 1;
bmi->cBitCount = 24;
bmi->ulCompression = BCA_UNCOMP;
bmi->cbImage = 0;
bmi->cxResolution = 0;
bmi->cyResolution = 0;
bmi->cclrUsed = bmi->cclrImportant = image_palette_size(format);
switch (img->format & DISPLAY_DEPTH_MASK) {
default:
case DISPLAY_DEPTH_1:
bmi->cBitCount = 1;
break;
case DISPLAY_DEPTH_4:
bmi->cBitCount = 4;
break;
case DISPLAY_DEPTH_8:
if ((img->format & DISPLAY_COLORS_MASK) == DISPLAY_COLORS_NATIVE)
bmi->cBitCount = 8;
else if ((img->format & DISPLAY_COLORS_MASK) == DISPLAY_COLORS_GRAY)
bmi->cBitCount = 8;
else
bmi->cBitCount = 24;
break;
}
nColors = bmi->cclrUsed;
if (nColors) {
unsigned char *p;
p = img->bitmap + BITMAPINFO2_SIZE;
for (i = 0; i < nColors; i++) {
image_color(img->format, i, p+2, p+1, p);
*(p+3) = 0;
p += 4;
}
}
DosReleaseMutexSem(img->bmp_mutex);
}
#ifdef DISPLAY_DEBUG
if (debug) {
fprintf(stdout, "\nBMP dump\n");
fprintf(stdout, " bitmap=%lx\n", img->bitmap);
fprintf(stdout, " committed=%lx\n", img->committed);
fprintf(stdout, " cx=%d\n", bmi->cx);
fprintf(stdout, " cy=%d\n", bmi->cy);
fprintf(stdout, " cPlanes=%d\n", bmi->cPlanes);
fprintf(stdout, " cBitCount=%d\n", bmi->cBitCount);
fprintf(stdout, " ulCompression=%d\n", bmi->ulCompression);
fprintf(stdout, " cbImage=%d\n", bmi->cbImage);
fprintf(stdout, " cxResolution=%d\n", bmi->cxResolution);
fprintf(stdout, " cyResolution=%d\n", bmi->cyResolution);
fprintf(stdout, " cclrUsed=%d\n", bmi->cclrUsed);
fprintf(stdout, " cclrImportant=%d\n", bmi->cclrImportant);
}
if (debug)
fputc('Z', stdout);
#endif
return 0;
}
int display_sync(void *handle, void *device)
{
IMAGE *img;
#ifdef DISPLAY_DEBUG
if (debug)
fputc('s', stdout);
fprintf(stdout, "display_sync(0x%x, 0x%x)\n", handle, device);
#endif
img = image_find(handle, device);
if (img) {
if (!img->format_known)
return gs_error_limitcheck;
if (!img->session_id && (img->width != 0) && (img->height != 0))
run_gspmdrv(img);
DosPostEventSem(img->sync_event);
}
#ifdef DISPLAY_DEBUG
if (debug)
fputc('S', stdout);
#endif
return 0;
}
int display_page(void *handle, void *device, int copies, int flush)
{
#ifdef DISPLAY_DEBUG
if (debug)
fputc('p', stdout);
fprintf(stdout, "display_page(0x%x, 0x%x, copies=%d, flush=%d)\n",
handle, device, copies, flush);
#endif
display_sync(handle, device);
#ifdef DISPLAY_DEBUG
if (debug)
fputc('P', stdout);
#endif
return 0;
}
void *display_memalloc(void *handle, void *device, unsigned long size)
{
IMAGE *img;
unsigned long needed;
unsigned long header;
APIRET rc;
void *mem = NULL;
#ifdef DISPLAY_DEBUG
if (debug)
fputc('m', stdout);
fprintf(stdout, "display_memalloc(0x%x 0x%x %d)\n",
handle, device, size);
#endif
img = image_find(handle, device);
if (img) {
* preallocated shared memory.
* First work out size of header + palette.
* We allocate space for the header and tell Ghostscript
* that the memory starts just after the header.
* We rely on the Ghostscript memory device placing the
* raster at the start of this memory and having a
* raster length the same as the length of a BMP row.
*/
header = BITMAPINFO2_SIZE + image_palette_size(img->format) * 4;
needed = (size + header + MIN_COMMIT - 1) & (~(MIN_COMMIT - 1));
if (needed > img->committed) {
if (rc = DosSetMem(img->bitmap + img->committed,
needed - img->committed,
PAG_COMMIT | PAG_DEFAULT)) {
fprintf(stdout, "No memory in display_memalloc rc = %d\n", rc);
return NULL;
}
img->committed = needed;
}
mem = img->bitmap + header;
}
#ifdef DISPLAY_DEBUG
fprintf(stdout, " returning 0x%x\n", (int)mem);
if (debug)
fputc('M', stdout);
#endif
return mem;
}
int display_memfree(void *handle, void *device, void *mem)
{
#ifdef DISPLAY_DEBUG
fprintf(stdout, "display_memfree(0x%x, 0x%x, 0x%x)\n",
handle, device, mem);
#endif
}
int display_update(void *handle, void *device,
int x, int y, int w, int h)
{
return 0;
}
display_callback display = {
sizeof(display_callback),
DISPLAY_VERSION_MAJOR,
DISPLAY_VERSION_MINOR,
display_open,
display_preclose,
display_close,
display_presize,
display_size,
display_sync,
display_page,
display_update,
display_memalloc,
display_memfree
};
int
main(int argc, char *argv[])
{
int code, code1;
int exit_code;
int exit_status;
int nargc;
char **nargv;
char dformat[64];
ULONG version[3];
void *instance = NULL;
if (DosQuerySysInfo(QSV_VERSION_MAJOR, QSV_VERSION_REVISION,
&version, sizeof(version)))
os_version = 201000;
else
os_version = version[0] * 10000 + version[1] * 100 + version[2];
if (!gs_load_dll()) {
fprintf(stdout, "Can't load %s\n", szDllName);
return -1;
}
{ int format = DISPLAY_COLORS_NATIVE | DISPLAY_ALPHA_NONE |
DISPLAY_DEPTH_1 | DISPLAY_LITTLEENDIAN | DISPLAY_BOTTOMFIRST;
int depth;
HPS ps = WinGetPS(HWND_DESKTOP);
HDC hdc = GpiQueryDevice(ps);
DevQueryCaps(hdc, CAPS_COLOR_PLANES, 1, &display_planes);
DevQueryCaps(hdc, CAPS_COLOR_BITCOUNT, 1, &display_bitcount);
DevQueryCaps(hdc, CAPS_ADDITIONAL_GRAPHICS, 1, &display_hasPalMan);
display_hasPalMan &= CAPS_PALETTE_MANAGER;
depth = display_planes * display_bitcount;
if ((depth <= 8) && !display_hasPalMan)
depth = 24;
WinReleasePS(ps);
if (depth > 8)
format = DISPLAY_COLORS_RGB | DISPLAY_ALPHA_NONE |
DISPLAY_DEPTH_8 | DISPLAY_LITTLEENDIAN | DISPLAY_BOTTOMFIRST;
else if (depth >= 8)
format = DISPLAY_COLORS_NATIVE | DISPLAY_ALPHA_NONE |
DISPLAY_DEPTH_8 | DISPLAY_LITTLEENDIAN | DISPLAY_BOTTOMFIRST;
else if (depth >= 4)
format = DISPLAY_COLORS_NATIVE | DISPLAY_ALPHA_NONE |
DISPLAY_DEPTH_4 | DISPLAY_LITTLEENDIAN | DISPLAY_BOTTOMFIRST;
gs_snprintf(dformat, sizeof(dformat), "-dDisplayFormat=%d", format);
}
nargc = argc + 1;
#ifdef DEBUG
if (debug)
fprintf(stdout, "%s\n", dformat);
#endif
nargc = argc + 1;
nargv = (char **)malloc(nargc * sizeof(char *));
nargv[0] = argv[0];
nargv[1] = dformat;
memcpy(&nargv[2], &argv[1], (argc-1) * sizeof(char *));
if ( (code = gsdll.new_instance(&instance, NULL)) == 0) {
gsdll.set_stdio(instance, gsdll_stdin, gsdll_stdout, gsdll_stderr);
gsdll.set_display_callback(instance, &display);
code = gsdll.init_with_args(instance, nargc, nargv);
if (code == 0)
code = gsdll.run_string(instance, start_string, 0, &exit_code);
code1 = gsdll.exit(instance);
if (code == 0 || (code == gs_error_Quit && code1 != 0))
code = code1;
gsdll.delete_instance(instance);
}
gs_free_dll();
free(nargv);
exit_status = 0;
switch (code) {
case 0:
case gs_error_Info:
case gs_error_Quit:
break;
case gs_error_Fatal:
exit_status = 1;
break;
default:
exit_status = 255;
}
return exit_status;
}