PageRenderTime 133ms CodeModel.GetById 27ms app.highlight 93ms RepoModel.GetById 1ms app.codeStats 1ms

/epstool-3.08/src/cdoc.c

#
C | 1073 lines | 881 code | 94 blank | 98 comment | 257 complexity | 28b9f76f86936dcd7893f4916686b256 MD5 | raw file
   1/* Copyright (C) 2001-2005 Ghostgum Software Pty Ltd.  All rights reserved.
   2
   3  This software is provided AS-IS with no warranty, either express or
   4  implied.
   5
   6  This software is distributed under licence and may not be copied,
   7  modified or distributed except as expressly authorised under the terms
   8  of the licence contained in the file LICENCE in this distribution.
   9
  10  For more information about licensing, please refer to
  11  http://www.ghostgum.com.au/ or contact Ghostsgum Software Pty Ltd, 
  12  218 Gallaghers Rd, Glen Waverley VIC 3150, AUSTRALIA, 
  13  Fax +61 3 9886 6616.
  14*/
  15
  16/* $Id: cdoc.c,v 1.19 2005/06/10 08:45:36 ghostgum Exp $ */
  17/* Common routines for Doc object */
  18
  19#include "common.h"
  20#include "dscparse.h"
  21#include "capp.h"
  22#define DEFINE_CDOC
  23#include "cdoc.h"
  24#include "cres.h"
  25
  26typedef enum PclType_e {
  27    PCLTYPE_UNKNOWN,
  28    PCLTYPE_PCL,
  29    PCLTYPE_PXL,
  30    PCLTYPE_POSTSCRIPT
  31} PclType;
  32
  33
  34/* private */
  35static int doc_scan(Doc *doc);	/* look for DSC comments */
  36static int doc_init(Doc *doc);
  37static int doc_gunzip(Doc *doc);
  38static int doc_bunzip2(Doc *doc);
  39static int doc_msg_len(void *handle, const char *str, int len);
  40static PclType doc_pl_parse(const char *str, int len, unsigned int *resolution);
  41static int doc_pl_readline(const char *str, int len);
  42static PclType doc_pjl_parse(const char *str, int len, unsigned int *resolution);
  43
  44/* prototypes */
  45void doc_message(void *caller_data, const char *str);
  46int show_dsc_error(void *caller_data, CDSC *dsc, 
  47	unsigned int explanation, const char *line, unsigned int line_len);
  48
  49
  50/* Create a new document object */
  51Doc *
  52doc_new(GSview *a)
  53{
  54    Doc *d = (Doc *)malloc(sizeof(Doc));
  55    if (d == NULL) {
  56	app_msg(a, "Out of memory\n");
  57	return_error(NULL);
  58    }
  59    app_lock(a);
  60    doc_init(d);
  61    d->app = a;
  62    app_ref(a);		/* doc has reference to app */
  63    doc_ref(d);		/* caller has reference to doc */
  64    app_unlock(a);
  65    return d;
  66}
  67
  68
  69/* Add document to application list of documents */
  70int 
  71doc_add(Doc *d, GSview *a)
  72{
  73    Doc *dn;
  74    app_lock(a);
  75    dn = *app_docs(a);
  76    while (dn && dn->next)
  77	dn = dn->next;
  78    if (dn == NULL)
  79	*app_docs(a) = d;
  80    else
  81	dn->next = d;
  82    doc_ref(d);		/* app has reference to doc */
  83    app_unlock(a);
  84    return 0;
  85}
  86
  87/* Remove document from application list */
  88int 
  89doc_remove(Doc *d)
  90{
  91    GSview *a = d->app;
  92    int code = 0;
  93    Doc *dn;
  94    app_lock(a);
  95    dn = *app_docs(a);
  96    if (dn == NULL) {
  97	/* not in list */
  98	char str[] = "App has no Doc\n";
  99	/* Doc has already locked app */
 100	app_msg_len_nolock(a, str, (int)strlen(str));
 101	code = -1;
 102    }
 103    else if (dn == d) {
 104	*app_docs(a) = d->next;
 105	doc_unref(d);	/* app loses reference to doc */
 106    }
 107    else {
 108	while (dn && dn->next != d)
 109	    dn = dn->next;
 110	if (dn && dn->next == d) {
 111	    dn->next = d->next;
 112	    doc_unref(d);	/* app loses reference to doc */
 113	}
 114	else {
 115	    char str[] = "Doc not found\n";
 116	    /* Doc has already locked app */
 117	    app_msg_len_nolock(a, str, (int)strlen(str));
 118	    code = -1;
 119	}
 120    }
 121    app_unlock(a);
 122    return code;
 123}
 124
 125
 126/* Increment reference count of Doc */
 127/* A View will increment refcount when it attaches to Doc */
 128/* Assumes we own the lock */
 129int
 130doc_ref(Doc *d)
 131{
 132    int refcount = ++(d->refcount);
 133    if (debug & DEBUG_DEV) {
 134	char buf[MAXSTR];
 135	snprintf(buf, sizeof(buf), "doc refcount=%d\n", refcount);
 136	buf[sizeof(buf)-1]='\0';
 137	app_msg_len_nolock(d->app, buf, (int)strlen(buf));
 138    }
 139    return refcount;
 140}
 141
 142/* Release reference to Doc. */
 143/* When reference count reaches zero, Doc is freed. */
 144/* Assumes we own the lock */
 145int
 146doc_unref(Doc *d)
 147{
 148    int refcount;
 149    GSview *a = d->app;
 150    if (d->refcount > 0)
 151	d->refcount--;
 152    refcount = d->refcount;
 153    if (debug & DEBUG_DEV) {
 154	char buf[MAXSTR];
 155	snprintf(buf, sizeof(buf), "doc refcount=%d\n", refcount);
 156	buf[sizeof(buf)-1]='\0';
 157	app_msg_len_nolock(d->app, buf, (int)strlen(buf));
 158    }
 159    if (d->refcount == 0) {
 160        doc_close(d);
 161	d->app = NULL;
 162	app_unref(a);	/* doc loses reference to app */
 163	memset(d, 0, sizeof(Doc));
 164	free(d);
 165    }
 166    return refcount;
 167}
 168
 169GSview *
 170doc_app(Doc *doc)
 171{
 172    return doc->app;
 173}
 174
 175
 176static int
 177doc_init(Doc *doc)
 178{
 179    memset(doc, 0, sizeof(Doc));
 180    doc->handle = NULL;
 181    doc->app = NULL;
 182    doc->next = NULL;
 183    doc->viewlist = NULL;
 184    doc->doctype = DOC_UNKNOWN;
 185    doc->page_count = -1;
 186    doc->ignore_dsc = FALSE;
 187    doc->dsc_warn = CDSC_ERROR_WARN;
 188    doc->verbose = TRUE;
 189    return 0;
 190}
 191
 192int
 193doc_close(Doc *doc)
 194{
 195#ifdef NOTUSED
 196    /* index of extracted text */
 197    free_text_index(doc);
 198    if (doc->text_name[0])
 199	wunlink(doc->text_name);
 200    memset(doc->text_name, 0, sizeof(doc->text_name));
 201#endif
 202
 203    /* temporary uncompressed file */
 204    if (doc->tname[0])
 205	csunlink(doc->tname);
 206
 207    memset(doc->name, 0, sizeof(doc->name));
 208    memset(doc->tname, 0, sizeof(doc->tname));
 209    doc->doctype = DOC_UNKNOWN;
 210    doc->gzip = FALSE;
 211    doc->bzip2 = FALSE;
 212    doc->page_count = 0;		
 213    doc->length1 = 0;
 214    doc->length2 = 0;
 215    doc->time1 = 0;
 216    doc->time2 = 0;
 217
 218    if (doc->dsc)
 219	dsc_unref(doc->dsc);
 220    doc->dsc = NULL;
 221    
 222#ifdef NOTUSED
 223    doc->ignore_special = FALSE;
 224#endif
 225    doc->ctrld = FALSE;
 226    doc->pjl = FALSE;
 227
 228    if (doc->pdfscan)
 229	pdf_scan_close(doc->pdfscan);
 230    doc->pdfscan = NULL;
 231    return 0;
 232}
 233
 234/* Open a new document.
 235 * +ve = non DSC
 236 * 0 = DSC
 237 * -ve = error
 238 */
 239int
 240doc_open(Doc *doc, LPCTSTR filename)
 241{
 242    int code;
 243    doc_close(doc);
 244    csncpy(doc->name, filename, sizeof(doc->name)/sizeof(TCHAR)-1);
 245    code = doc_scan(doc);
 246    if (code < 0)
 247	doc_close(doc);
 248    return code;
 249}
 250
 251DocType
 252doc_type(Doc *doc)
 253{
 254    return doc->doctype;
 255}
 256
 257BOOL
 258doc_is_open(Doc *doc)
 259{
 260    return (doc->name[0] != '\0');
 261}
 262
 263void 
 264doc_ignore_dsc(Doc *doc, BOOL flag)
 265{
 266    doc->ignore_dsc = flag;
 267}
 268
 269void 
 270doc_dsc_warn(Doc *doc, int level)
 271{
 272    doc->dsc_warn = level;
 273}
 274
 275void 
 276doc_verbose(Doc *doc, BOOL verbose)
 277{
 278    doc->verbose = verbose;
 279}
 280
 281void
 282doc_message(void *caller_data, const char *str)
 283{
 284    app_msg(((Doc *)caller_data)->app, str);
 285}
 286
 287
 288/* Debug for DSC comments */
 289void
 290doc_dump(Doc *doc)
 291{
 292    app_csmsgf(doc->app, TEXT("DSC dump for %.200s\n"), doc->name);
 293    dsc_display(doc->dsc, doc_message);
 294    app_csmsgf(doc->app, TEXT("End of DSC dump\n"));
 295}
 296
 297int 
 298show_dsc_error(void *caller_data, CDSC *dsc, 
 299	unsigned int explanation, const char *line, unsigned int line_len)
 300{
 301    Doc *doc = (Doc *)caller_data;
 302    int response = CDSC_RESPONSE_CANCEL;
 303    int severity;
 304    char buf[MAXSTR];
 305    int len;
 306    TCHAR title[MAXSTR];
 307    TCHAR linefmt[MAXSTR];
 308    int i;
 309    TCHAR *p;
 310
 311    if (explanation > dsc->max_error)
 312	return CDSC_RESPONSE_OK;
 313
 314    severity = dsc->severity[explanation];
 315
 316    /* If debug function provided, copy messages there */
 317    /* These are always in English */
 318    if (dsc->debug_print_fn) {
 319	switch (severity) {
 320	    case CDSC_ERROR_INFORM:
 321		dsc_debug_print(dsc, "\nDSC Information");
 322		break;
 323	    case CDSC_ERROR_WARN:
 324		dsc_debug_print(dsc, "\nDSC Warning");
 325		break;
 326	    case CDSC_ERROR_ERROR:
 327		dsc_debug_print(dsc, "\nDSC Error");
 328	        break;
 329	}
 330	dsc_debug_print(dsc, "\n");
 331	if (explanation <= dsc->max_error) {
 332	    if (line && line_len) {
 333		int length = min(line_len, sizeof(buf)-1);
 334		snprintf(buf, sizeof(buf), "At line %d:\n", dsc->line_count);
 335		buf[sizeof(buf)-1]='\0';
 336		dsc_debug_print(dsc, buf);
 337		strncpy(buf, line, length);
 338		buf[length]='\0';
 339		dsc_debug_print(dsc, "  ");
 340		dsc_debug_print(dsc, buf);
 341	    }
 342	    dsc_debug_print(dsc, dsc_message[explanation]);
 343	}
 344    }
 345
 346    /* Here you could prompt user for OK, Cancel, Ignore ALL DSC */
 347    if (severity <= doc->dsc_warn)
 348	return response;
 349
 350    switch (severity) {
 351	case CDSC_ERROR_INFORM:
 352	    i = IDS_DSC_INFO;
 353	    break;
 354	case CDSC_ERROR_WARN:
 355	    i = IDS_DSC_WARN;
 356	    break;
 357	case CDSC_ERROR_ERROR:
 358	    i = IDS_DSC_ERROR;
 359	    break;
 360	default:
 361	    i = -1;
 362    }
 363    if (i != -1)
 364        load_string(doc->app, i, title, sizeof(title)/sizeof(TCHAR));
 365    else
 366	title[0] = '\0';
 367
 368    /* build up string */
 369#define MLEN 4096
 370    p = (TCHAR *)malloc(MLEN*sizeof(TCHAR));
 371    memset(p, 0, MLEN*sizeof(TCHAR));
 372    if (p == (TCHAR *)NULL)
 373	return response;
 374
 375    if (line) {
 376	int len;
 377	int wlen;
 378        load_string(doc->app, IDS_DSC_LINEFMT, linefmt, sizeof(linefmt)/sizeof(TCHAR));
 379        csnprintf(p, MLEN, linefmt, title, dsc->line_count);
 380	csncat(p, TEXT("\n   "), MLEN-1-cslen(p));
 381	len = (int)cslen(p);
 382	if (line_len > 256)
 383	    line_len = 256;	/* this is the maximum DSC line length */
 384	wlen = narrow_to_cs(NULL, 0, line, line_len);
 385	narrow_to_cs(p+len, MLEN-1-len, line, line_len);
 386        p[len+wlen] = '\0';
 387    }
 388    else {
 389	csncpy(p, title, MLEN-1);
 390	csncat(p, TEXT("\n"), MLEN-1-cslen(p));
 391    }
 392    len = (int)cslen(p);
 393    load_string(doc->app, CDSC_RESOURCE_BASE+(explanation*2), 
 394	p+len, MLEN-len);
 395    len = (int)cslen(p);
 396    load_string(doc->app, CDSC_RESOURCE_BASE+(explanation*2)+1, 
 397	p+len, MLEN-len);
 398    
 399    response = get_dsc_response(doc->app, p);
 400
 401    free(p);
 402
 403    if (dsc->debug_print_fn) {
 404	switch (response) {
 405	    case CDSC_RESPONSE_OK:
 406		dsc_debug_print(dsc, "Response = OK\n");
 407		break;
 408	    case CDSC_RESPONSE_CANCEL:
 409		dsc_debug_print(dsc, "Response = Cancel\n");
 410		break;
 411	    case CDSC_RESPONSE_IGNORE_ALL:
 412		dsc_debug_print(dsc, "Response = Ignore All DSC\n");
 413		break;
 414	}
 415    }
 416
 417    return response;
 418}
 419
 420LPCTSTR
 421doc_name(Doc *doc)
 422{
 423    /* If original file was compressed, give name of uncompressed file */
 424    if ((doc->tname[0]!='\0') && ((doc->gzip) || doc->bzip2))
 425	return doc->tname;
 426    /* otherwise return original file name */
 427    return doc->name;
 428}
 429
 430
 431/* gunzip to temporary file */
 432static int
 433doc_gunzip(Doc *doc)
 434{
 435    GFile *outfile;
 436    int code;
 437    char name[MAXSTR+MAXSTR];
 438    if ((outfile = app_temp_gfile(doc->app, doc->tname, 
 439	sizeof(doc->tname)/sizeof(TCHAR)-1)) 
 440	== (GFile *)NULL) {
 441	TCHAR buf[MAXSTR];
 442	load_string(doc->app, IDS_NOTEMP, buf, sizeof(buf)/sizeof(TCHAR));
 443	app_csmsg(doc->app, buf);
 444	return_error(-1);
 445    }
 446
 447    cs_to_narrow(name, sizeof(name)-1, doc->name, (int)cslen(doc->name)+1);
 448    app_msg(doc->app, "Uncompressing ");
 449    app_msg(doc->app, name);
 450    app_msg(doc->app, " to ");
 451    app_csmsg(doc->app, doc->tname);
 452    app_msg(doc->app, "\n");
 453
 454    code = zlib_uncompress(doc->app, outfile, name);
 455    gfile_close(outfile);
 456    if (code != 0) {
 457	csunlink(doc->tname);
 458	doc->tname[0] = '\0';
 459	return_error(-1);
 460    }
 461
 462    return 0;
 463}
 464
 465
 466/* Uncompress bzip2 to temporary file */
 467static int
 468doc_bunzip2(Doc *doc)
 469{
 470    GFile *outfile;
 471    int code;
 472    char name[MAXSTR+MAXSTR];
 473    if ((outfile = app_temp_gfile(doc->app, doc->tname, 
 474	sizeof(doc->tname)/sizeof(TCHAR)-1)) 
 475	== (GFile *)NULL) {
 476	TCHAR buf[MAXSTR];
 477	load_string(doc->app, IDS_NOTEMP, buf, sizeof(buf)/sizeof(TCHAR));
 478	app_csmsg(doc->app, buf);
 479	return_error(-1);
 480    }
 481
 482    cs_to_narrow(name, sizeof(name)-1, doc->name, (int)cslen(doc->name)+1);
 483    app_msg(doc->app, "Uncompressing ");
 484    app_msg(doc->app, name);
 485    app_msg(doc->app, " to ");
 486    app_csmsg(doc->app, doc->tname);
 487    app_msg(doc->app, "\n");
 488
 489    code = bzip2_uncompress(doc->app, outfile, name);
 490    gfile_close(outfile);
 491    if (code != 0) {
 492	csunlink(doc->tname);
 493	doc->tname[0] = '\0';
 494	return_error(-1);
 495    }
 496
 497    return 0;
 498}
 499
 500/* Try to recognise PCL files.
 501 * PJL starts with
 502 *  ESC %-12345X
 503 * PCL commonly starts with 
 504 *  ESC %, ESC E, ESC *, ESC &
 505 * PCLXL commonly starts with
 506 *  ) HP-PCL XL
 507 * If the resolution is not specified, set it to 0.
 508 */
 509static PclType doc_pl_parse(const char *str, int len, unsigned int *resolution)
 510{
 511    PclType type;
 512    *resolution = 0;
 513    if ((len >= 9) && (memcmp(str, "\033%-12345X", 9) == 0))
 514	type = doc_pjl_parse(str, len, resolution);
 515    else if ((len >= 11) && (memcmp(str, ") HP-PCL XL", 11) == 0))
 516	type = PCLTYPE_PXL;
 517    else if ((len >= 2) && (str[0] == '\033') &&
 518	((str[1]=='%') || (str[1]=='E') || (str[1]=='*') || (str[1] == '&')))
 519	type = PCLTYPE_PCL;
 520    else 
 521	type = PCLTYPE_UNKNOWN;
 522    return type;
 523}
 524 
 525/* Get length of line in buffer.
 526 */
 527static int doc_pl_readline(const char *str, int len)
 528{
 529    int i = 0;
 530    /* skip until EOL */
 531    while ((i<len) && (str[i] != '\r') && (str[i] != '\n'))
 532	i++;
 533    /* skip over EOL */
 534    while ((i<len) && ((str[i] == '\r') || (str[i] == '\n')))
 535	i++;
 536    return i;
 537}
 538
 539/* PJL starts with \033%-12345X
 540 * and finishes with a line that does not start with @.
 541 * We are interested in the following lines:
 542 *  @PJL SET RESOLUTION=600
 543 *  @PJL ENTER LANGUAGE=PCL
 544 *  @PJL ENTER LANGUAGE=PCLXL
 545 *  @PJL ENTER LANGUAGE=POSTSCRIPT
 546 * If the language type is not specified but PJL is used,
 547 * assume PCL.
 548 */
 549static PclType doc_pjl_parse(const char *str, int len, unsigned int *resolution)
 550{
 551    PclType type = PCLTYPE_PCL;
 552    const char *p;
 553    int idx = 0;
 554    int count;
 555    int i;
 556    char buf[16];
 557    int bufcnt;
 558    if ((len < 9) || (memcmp(str, "\033%-12345X", 9) != 0))
 559	return PCLTYPE_UNKNOWN;
 560    idx = 9;
 561    while ((count = doc_pl_readline(str+idx, len-idx)) != 0) {
 562	p = str+idx;
 563	if ((count >= 9) && (memcmp(p, "\033%-12345X", 9) == 0)) {
 564	    count -= 9;
 565	    p += 9;
 566	    idx += 9;
 567	    if (count == 0)
 568		break;
 569	}
 570	if (*p != '@')
 571	    break; /* Not PJL */
 572	if ((count >= 19) && 
 573	    (memcmp(p, "@PJL SET RESOLUTION", 19) == 0)) {
 574	    i = 19;
 575	    while ((i<count) && (p[i] == ' '))
 576		i++;
 577	    if ((i<count) && (p[i] == '=')) {
 578		i++;
 579		while ((i<count) && (p[i] == ' '))
 580		    i++;
 581		/* now read number */
 582		bufcnt = min(count-i, (int)sizeof(buf)-1);
 583		memcpy(buf, p+i, bufcnt);
 584		buf[bufcnt] = '\0';
 585		*resolution = atoi(buf);
 586	    }
 587	}
 588	else if ((count >= 19) && 
 589	    (memcmp(p, "@PJL ENTER LANGUAGE", 19) == 0)) {
 590	    i = 19;
 591	    while ((i<count) && (p[i] == ' '))
 592		i++;
 593	    if ((i<count) && (p[i] == '=')) {
 594		i++;
 595		while ((i<count) && (p[i] == ' '))
 596		    i++;
 597		/* now read language */
 598		if ((count-i >= 10) &&
 599	            (memcmp(p+i, "POSTSCRIPT", 10) == 0))
 600		    type = PCLTYPE_POSTSCRIPT;
 601		else if ((count-i >= 5) &&
 602	            (memcmp(p+i, "PCLXL", 5) == 0))
 603		    type = PCLTYPE_PXL;
 604		else if ((count-i >= 3) &&
 605	            (memcmp(p+i, "PCL", 3) == 0))
 606		    type = PCLTYPE_PCL;
 607	    }
 608	}
 609	idx += count;
 610    }
 611    return type;
 612}
 613
 614
 615/* scan file for PostScript Document Structuring Conventions */
 616/* return -ve if error */
 617/* return +ve if not DSC */
 618/* On return, doc->dsc is non-zero if DSC */
 619int
 620doc_scan(Doc *doc)
 621{
 622char line[4096];
 623FILE_POS file_length;
 624GFile *f;
 625CDSC *dsc;
 626PclType pcltype = PCLTYPE_UNKNOWN;
 627
 628    if ( (f = gfile_open(doc->name, gfile_modeRead)) == (GFile *)NULL ) {
 629	app_msg(doc->app, "File \042");
 630	app_csmsg(doc->app, doc_name(doc));
 631	app_msg(doc->app, "\042 does not exist\n");
 632	return_error(-1);
 633    }
 634
 635    if (doc->dsc)
 636	dsc_unref(doc->dsc);
 637    doc->dsc = NULL;
 638    
 639    /* get first line to look for magic numbers */
 640    memset(line, 0, sizeof(line));
 641    gfile_read(f, line, sizeof(line)-1);
 642    gfile_seek(f, 0, gfile_begin);
 643
 644    /* check for gzip */
 645    doc->gzip = FALSE;
 646    doc->bzip2 = FALSE;
 647    if ( (line[0]=='\037') && (line[1]=='\213') ) { /* 1F 8B */
 648	doc->gzip = TRUE;
 649	gfile_close(f);
 650	if (doc_gunzip(doc) != 0) {
 651	    app_msg(doc->app, "Failed to gunzip file\n");
 652	    return_error(-1);
 653	}
 654	if ((f = gfile_open(doc_name(doc), gfile_modeRead)) == (GFile *)NULL) {
 655	    app_msg(doc->app, "File '");
 656	    app_csmsg(doc->app, doc_name(doc));
 657	    app_msg(doc->app, "' does not exist\n");
 658	    return_error(-1);
 659	}
 660	gfile_read(f, line, sizeof(line)-1);
 661	gfile_seek(f, 0, gfile_begin);
 662    }
 663
 664    /* check for bzip2 */
 665    if ( (line[0]=='B') && (line[1]=='Z') && (line[2]=='h')) { /* "BZh */
 666	doc->bzip2 = TRUE;
 667	gfile_close(f);
 668	if (doc_bunzip2(doc) != 0) {
 669	    app_msg(doc->app, "Failed to uncompress bzip2 file\n");
 670	    return_error(-1);
 671	}
 672	if ((f = gfile_open(doc_name(doc), gfile_modeRead)) == (GFile *)NULL) {
 673	    app_msg(doc->app, "File '");
 674	    app_csmsg(doc->app, doc_name(doc));
 675	    app_msg(doc->app, "' does not exist\n");
 676	    return_error(-1);
 677	}
 678	gfile_read(f, line, sizeof(line)-1);
 679	gfile_seek(f, 0, gfile_begin);
 680    }
 681
 682    file_length = gfile_get_length(f);
 683
 684    /* save file date and length */
 685    doc_savestat(doc);
 686
 687    doc->doctype = DOC_UNKNOWN;
 688    doc->dpi = 0;
 689
 690    /* check for PDF */
 691    if ( strncmp("%PDF-", line, 5) == 0 ) {
 692	gfile_close(f);
 693	doc->doctype = DOC_PDF;
 694	doc->page_count = 0;
 695	if (doc->pdfscan)
 696	    pdf_scan_close(doc->pdfscan);
 697	doc->pdfscan = NULL;
 698	doc->pdfscan = pdf_scan_open(doc_name(doc), doc->app, doc_msg_len);
 699	doc->page_count = pdf_scan_page_count(doc->pdfscan);
 700        if (debug & DEBUG_GENERAL)
 701	    app_msgf(doc->app, "PDF page count %d\n", doc->page_count);
 702	return 0;
 703    }
 704
 705    /* check for PCL */
 706#ifdef NOTUSED
 707    if ((line[0]=='\033') && (line[1]=='E') && (line[2]=='\033')) {
 708	TCHAR buf[MAXSTR];
 709	doc->doctype = DOC_PCL;
 710	load_string(doc->app, IDS_PROBABLY_PCL, buf, sizeof(buf)/sizeof(TCHAR));
 711	app_msgf(doc->app, "%s\n", buf);
 712	if (app_msg_box(doc->app, buf, MB_ICONEXCLAMATION | MB_YESNO) 
 713	    != IDYES) {
 714	    gfile_close(f);
 715	    return_error(-1);
 716	}
 717    }
 718#else
 719    pcltype = doc_pl_parse(line, (int)strlen(line), &doc->dpi);
 720    if ((pcltype == PCLTYPE_PCL) || (pcltype == PCLTYPE_PXL)) {
 721	doc->doctype = DOC_PCL;
 722        if (debug & DEBUG_GENERAL)
 723	    app_msgf(doc->app, "Document is PCL or PXL\n");
 724	gfile_close(f);
 725	return 0;
 726    }
 727#endif
 728
 729    /* check for Windows BMP or NETPBM */
 730    if ( ((line[0]=='B') && (line[1]=='M')) ||
 731	 ((line[0]=='P') && (line[1]>='1') && (line[1]<='6')) ||
 732	 (((unsigned char)line[0]==0x89) && (line[1]=='P') && 
 733	  (line[2]=='N') && (line[3]=='G'))
 734       ) {
 735	doc->doctype = DOC_BITMAP;
 736	doc->page_count = 1;
 737	gfile_close(f);
 738	return 0;
 739    }
 740
 741    /* Otherwise, assume it is PostScript */
 742    doc->doctype = DOC_PS;
 743
 744    /* check for documents that start with Ctrl-D */
 745    doc->ctrld = (line[0] == '\004');
 746    /* check for HP LaserJet prologue */
 747    doc->pjl = FALSE;
 748    if (strncmp("\033%-12345X", line, 9) == 0)
 749	doc->pjl = TRUE;
 750    if (doc->ignore_dsc)
 751	doc->dsc = (CDSC *)NULL;
 752    else  {
 753	int code = 0;
 754	int count;
 755	char *d;
 756	doc->dsc = NULL;
 757	if ( (d = (char *) malloc(COPY_BUF_SIZE)) == NULL)
 758	    return_error(-1);
 759
 760	doc->dsc = dsc_new(doc);
 761	if (doc->verbose)
 762	    dsc_set_debug_function(doc->dsc, doc_message);
 763	dsc_set_error_function(doc->dsc, show_dsc_error);
 764	dsc_set_length(doc->dsc, file_length);
 765	while ((count = (int)gfile_read(f, d, COPY_BUF_SIZE))!=0) {
 766	    code = dsc_scan_data(doc->dsc, d, count);
 767	    if ((code == CDSC_ERROR) || (code == CDSC_NOTDSC)) {
 768		/* not DSC or an error */
 769		break;
 770	    }
 771	}
 772	if ((code == CDSC_ERROR) || (code == CDSC_NOTDSC)) {
 773	    dsc_unref(doc->dsc);
 774	    doc->dsc = NULL;
 775	}
 776	else {
 777	    dsc_fixup(doc->dsc);
 778	}
 779        free(d);
 780    }
 781    gfile_close(f);
 782
 783    /* check for DSC comments */
 784    dsc = doc->dsc;
 785    if (dsc == (CDSC *)NULL)
 786	return 1;	/* OK, but not DSC */
 787
 788    if (dsc->doseps) {
 789	BOOL bad_header = FALSE;
 790	/* check for errors in header */
 791	if (dsc->doseps->ps_begin > file_length)
 792	    bad_header = TRUE;
 793	if (dsc->doseps->ps_begin + dsc->doseps->ps_length > file_length)
 794	    bad_header = TRUE;
 795	if (dsc->doseps->wmf_begin > file_length)
 796	    bad_header = TRUE;
 797	if (dsc->doseps->wmf_begin + dsc->doseps->wmf_length > file_length)
 798	    bad_header = TRUE;
 799	if (dsc->doseps->tiff_begin > file_length)
 800	    bad_header = TRUE;
 801	if (dsc->doseps->tiff_begin + dsc->doseps->tiff_length > file_length)
 802	    bad_header = TRUE;
 803	if (bad_header) {
 804	    TCHAR buf[MAXSTR];
 805	    load_string(doc->app, IDS_BAD_DOSEPS_HEADER, 
 806		buf, sizeof(buf)/sizeof(TCHAR));
 807	    app_csmsgf(doc->app, TEXT("%s\n"), buf);
 808	    app_msg_box(doc->app, buf, 0);
 809	    /* Ignore the bad information */
 810	    dsc_unref(doc->dsc);
 811	    doc->dsc = NULL;
 812	    return_error(-1);
 813	}
 814    }
 815
 816    if (debug & DEBUG_GENERAL)
 817	doc_dump(doc);
 818
 819    return 0;
 820}
 821
 822
 823/* reverse zero based page number if needed */
 824int
 825doc_map_page(Doc *doc, int page)
 826{
 827    if (doc->dsc != (CDSC *)NULL)
 828        if (doc->dsc->page_order == CDSC_DESCEND) 
 829	    return (doc->dsc->page_count - 1) - page;
 830    return page;
 831}
 832
 833int 
 834doc_page_limit(Doc *doc, int page)
 835{
 836    if (doc == NULL)
 837	return 0;
 838    if (doc->doctype == DOC_PS) {
 839	if (doc->dsc) {
 840	    if (page >= (int)doc->dsc->page_count)
 841		page = doc->dsc->page_count - 1;
 842	    if (page < 0)
 843		page = 0;
 844	}
 845	else if (doc->page_count) {
 846	    if (page >= (int)doc->page_count)
 847		page = doc->page_count - 1;
 848	}
 849    }
 850    else if (doc->doctype == DOC_PDF) {
 851	if (page >= (int)doc->page_count)
 852	    page = doc->page_count - 1;
 853	if (page < 0)
 854	    page = 0;
 855    }
 856    else if (doc->doctype == DOC_BITMAP) 
 857	page = 0;
 858    return page;
 859}
 860
 861
 862View **
 863doc_views(Doc *doc)
 864{
 865    return &doc->viewlist;
 866}
 867
 868/* append to a string in a buffer of length len */
 869static TCHAR *
 870csappend(LPTSTR dest, LPCTSTR src, int len)
 871{
 872    return csncat(dest, src, len - (int)cslen(dest)/sizeof(TCHAR) - 1);
 873}
 874
 875/* Information about a document, suitable for showing in a dialog */
 876void
 877doc_info(Doc *doc, DocInfo *info) 
 878{
 879    TCHAR buf[MAXSTR];
 880    CDSC *dsc = doc->dsc;
 881    int typelen;
 882    memset(info, 0, sizeof(DocInfo));
 883    if (cslen(doc->name))
 884	csncpy(info->name, doc->name, sizeof(info->name)/sizeof(TCHAR));
 885    else
 886	load_string(doc->app, IDS_NOFILE, info->name, 
 887	    sizeof(info->name)/sizeof(TCHAR));
 888    
 889    typelen = sizeof(info->type)/sizeof(TCHAR);
 890    if (doc->gzip)
 891	csappend(info->type, TEXT("gzip "), typelen);
 892    if (doc->bzip2)
 893	csappend(info->type, TEXT("bzip2 "), typelen);
 894    if (dsc) {
 895	load_string(doc->app, IDS_CTRLD, buf, sizeof(buf)/sizeof(TCHAR));
 896	if (doc->ctrld)
 897	    csappend(info->type, buf, typelen);
 898	load_string(doc->app, IDS_PJL, buf, sizeof(buf)/sizeof(TCHAR));
 899	if (doc->pjl)
 900	    csappend(info->type, buf, typelen);
 901	load_string(doc->app, IDS_DCS2, buf, sizeof(buf)/sizeof(TCHAR));
 902	if (dsc->dcs2)
 903	    csappend(info->type, buf, typelen);
 904	if (dsc->epsf) {
 905	    switch(dsc->preview) {
 906		default:
 907		case CDSC_NOPREVIEW:
 908		    buf[0] = '\0';
 909		    break;
 910		case CDSC_EPSI:
 911		    load_string(doc->app, IDS_EPSI, 
 912			buf, sizeof(buf)/sizeof(TCHAR));
 913		    break;
 914		case CDSC_TIFF:
 915		    load_string(doc->app, IDS_EPST, 
 916			buf, sizeof(buf)/sizeof(TCHAR));
 917		    break;
 918		case CDSC_WMF:
 919		    load_string(doc->app, IDS_EPSW, 
 920			buf, sizeof(buf)/sizeof(TCHAR));
 921		    break;
 922	    }
 923	    csappend(info->type, buf, typelen);
 924	}
 925	else {
 926	    load_string(doc->app, IDS_DSC, buf, sizeof(buf)/sizeof(TCHAR));
 927	    csappend(info->type, buf, typelen);
 928	}
 929	if (dsc->dsc_title)
 930	    narrow_to_cs(info->title, sizeof(info->title)/sizeof(TCHAR)-1,
 931		dsc->dsc_title, (int)strlen(dsc->dsc_title)+1);
 932	if (dsc->dsc_date)
 933	    narrow_to_cs(info->date, sizeof(info->date)/sizeof(TCHAR)-1,
 934		dsc->dsc_date, (int)strlen(dsc->dsc_date)+1);
 935	if (dsc->bbox) {
 936	    csnprintf(buf, sizeof(buf)/sizeof(TCHAR), 
 937		TEXT("%d %d %d %d"), dsc->bbox->llx, dsc->bbox->lly,
 938		dsc->bbox->urx, dsc->bbox->ury);
 939	    buf[sizeof(buf)-1]='\0';
 940	    csncpy(info->bbox, buf, sizeof(info->bbox)/sizeof(TCHAR));
 941	}
 942	if (dsc->hires_bbox) {
 943	    csnprintf(buf, sizeof(buf)/sizeof(TCHAR), TEXT("%g %g %g %g"), 
 944		dsc->hires_bbox->fllx, dsc->hires_bbox->flly,
 945		dsc->hires_bbox->furx, dsc->hires_bbox->fury);
 946	    buf[sizeof(buf)-1]='\0';
 947	    csncpy(info->hiresbbox, buf, 
 948		sizeof(info->hiresbbox)/sizeof(TCHAR));
 949	}
 950	switch (dsc->page_orientation) {
 951	    case CDSC_PORTRAIT:
 952		load_string(doc->app, IDS_PORTRAIT, info->orientation, 
 953		    sizeof(info->orientation)/sizeof(TCHAR));
 954		break;
 955	    case CDSC_LANDSCAPE:
 956		load_string(doc->app, IDS_LANDSCAPE, info->orientation, 
 957		    sizeof(info->orientation)/sizeof(TCHAR));
 958		break;
 959	}
 960	switch (dsc->page_order) {
 961	    case CDSC_ASCEND:
 962		load_string(doc->app, IDS_ASCEND, info->pageorder, 
 963		    sizeof(info->pageorder)/sizeof(TCHAR));
 964		break;
 965	    case CDSC_DESCEND:
 966		load_string(doc->app, IDS_LANDSCAPE, info->pageorder, 
 967		    sizeof(info->pageorder)/sizeof(TCHAR));
 968		break;
 969	    case CDSC_SPECIAL:
 970		load_string(doc->app, IDS_SPECIAL, info->pageorder, 
 971		    sizeof(info->pageorder)/sizeof(TCHAR));
 972		break;
 973	}
 974	if (dsc->page_media && dsc->page_media->name) {
 975	    int wlen = narrow_to_cs(buf, (int)sizeof(buf)/sizeof(TCHAR), 
 976		dsc->page_media->name, (int)strlen(dsc->page_media->name)+1);
 977	    csnprintf(buf+wlen, sizeof(buf)/sizeof(TCHAR)-wlen, TEXT(" %g %g"),
 978		dsc->page_media->width, dsc->page_media->height);
 979	    buf[sizeof(buf)-1]='\0';
 980	}
 981	else {
 982	    buf[0] = '\0';
 983	}
 984	csncpy(info->pagemedia, buf, sizeof(info->pages)/sizeof(TCHAR));
 985	csnprintf(buf, sizeof(buf)/sizeof(TCHAR), TEXT("%d"), dsc->page_count);
 986	buf[sizeof(buf)-1]='\0';
 987	csncpy(info->pages, buf, sizeof(info->pages)/sizeof(TCHAR));
 988    }
 989    else if (doc->doctype == DOC_PDF) {
 990	load_string(doc->app, IDS_PDF, buf, sizeof(buf)/sizeof(TCHAR));
 991	csappend(info->type, buf, typelen);
 992	csnprintf(buf, sizeof(buf)/sizeof(TCHAR), 
 993	    TEXT("%d"), doc->page_count);
 994	buf[sizeof(buf)-1]='\0';
 995	csncpy(info->pages, buf, sizeof(info->pages)/sizeof(TCHAR));
 996    }
 997}
 998
 999/* Generate string for page list box, as either
1000 *   ordinal
1001 *   ordinal    "label"
1002 */
1003void
1004doc_ordlabel(Doc *doc, char *buf, int buflen, int page_number)
1005{
1006    if (doc->doctype == DOC_PDF) {
1007        snprintf(buf, buflen, "%d", page_number+1);
1008    }
1009    else if (doc->dsc) {
1010	const char *label;
1011	int ordinal;
1012	label = doc->dsc->page[doc_map_page(doc, page_number)].label;
1013	ordinal = doc->dsc->page[doc_map_page(doc, page_number)].ordinal;
1014	snprintf(buf, buflen, "%d", ordinal);
1015	if (strcmp(buf, label) != 0) {
1016	    /* label and ordinal don't match, so use composite */
1017	    snprintf(buf, buflen, "%d  \042%s\042", ordinal, label);
1018	}
1019    }
1020}
1021
1022static int 
1023doc_msg_len(void *handle, const char *str, int len)
1024{
1025    return app_msg_len((GSview *)handle, str, len);
1026}
1027
1028/* Copy document unmodified */
1029int
1030doc_copyfile(Doc *doc, LPCTSTR filename)
1031{
1032    GFile *infile, *outfile;
1033    int code = 0;
1034    char *buf;
1035    int count = 0;
1036
1037    buf = (char *)malloc(COPY_BUF_SIZE);
1038    if (buf == (char *)NULL)
1039	return -1;
1040
1041    if ((infile = gfile_open(doc_name(doc), gfile_modeRead)) == (GFile *)NULL){
1042	app_msg(doc->app, "File \042");
1043	app_csmsg(doc->app, doc_name(doc));
1044	app_msg(doc->app, "\042 does not exist\n");
1045	free(buf);
1046	return_error(-1);
1047    }
1048    if ((outfile = gfile_open(filename, gfile_modeWrite | gfile_modeCreate)) 
1049	== (GFile *)NULL) {
1050	app_msg(doc->app, "File \042");
1051	app_csmsg(doc->app, filename);
1052	app_msg(doc->app, "\042 can not be opened for writing\n");
1053	free(buf);
1054	gfile_close(infile);
1055	return_error(-1);
1056    }
1057
1058    while (((count = (int)gfile_read(infile, buf, COPY_BUF_SIZE)) > 0))
1059        if ((int)gfile_write(outfile, buf, count) != count)
1060	    break;
1061    free(buf);
1062
1063    if (gfile_error(infile)!=0)
1064	code = -1;
1065    if (gfile_error(outfile)!=0)
1066	code = -1;
1067
1068    gfile_close(outfile);
1069    gfile_close(infile);
1070    if (code && !(debug & DEBUG_GENERAL))
1071	csunlink(filename);
1072    return code;
1073}