Fixed crashes with WM_GETDLGCODE translation.
[wine/testsucceed.git] / graphics / psdrv / ppd.c
blob8f8d5c8a48d6992bdb23baa6cf1119599a6366ae
1 /* PostScript Printer Description (PPD) file parser
3 * See http://www.adobe.com/supportservice/devrelations/PDFS/TN/5003.PPD_Spec_v4.3.pdf
5 * Copyright 1998 Huw D M Davies
6 */
8 #include <string.h>
9 #include <ctype.h>
10 #include "windows.h"
11 #include "winnt.h" /* HEAP_ZERO_MEMORY */
12 #include "heap.h"
13 #include "debug.h"
14 #include "psdrv.h"
15 #include "print.h"
17 typedef struct {
18 char *key;
19 char *option;
20 char *opttrans;
21 char *value;
22 char *valtrans;
23 } PPDTuple;
26 /* map of page names in ppd file to Windows paper constants */
28 static struct {
29 char *PSName;
30 WORD WinPage;
31 } PageTrans[] = {
32 {"A4", DMPAPER_A4},
33 {"Letter", DMPAPER_LETTER},
34 {"Legal", DMPAPER_LEGAL},
35 {"Executive", DMPAPER_EXECUTIVE},
36 {"Comm10", DMPAPER_ENV_10},
37 {"Monarch", DMPAPER_ENV_MONARCH},
38 {"DL", DMPAPER_ENV_DL},
39 {"C5", DMPAPER_ENV_C5},
40 {"B5", DMPAPER_ENV_B5},
41 {NULL, 0}
44 /* the same for bin names */
46 static struct {
47 char *PSName;
48 WORD WinBin;
49 } BinTrans[] = {
50 {"Lower", DMBIN_LOWER},
51 {"Upper", DMBIN_UPPER},
52 {"Envelope", DMBIN_ENVELOPE},
53 {"LargeCapacity", DMBIN_LARGECAPACITY},
54 {NULL, 0}
57 /***********************************************************************
59 * PSDRV_PPDDecodeHex
61 * Copies str into a newly allocated string from the process heap subsituting
62 * hex strings enclosed in '<' and '>' for their byte codes.
65 static char *PSDRV_PPDDecodeHex(char *str)
67 char *buf, *in, *out;
68 BOOL32 inhex = FALSE;
70 buf = HeapAlloc(PSDRV_Heap, 0, strlen(str) + 1);
71 if(!buf)
72 return NULL;
74 for(in = str, out = buf; *in; in++) {
75 if(!inhex) {
76 if(*in != '<')
77 *out++ = *in;
78 else
79 inhex = TRUE;
80 } else {
81 if(*in == '>') {
82 inhex = FALSE;
83 continue;
85 else if(isspace(*in))
86 continue;
87 else {
88 int i;
89 if(!isxdigit(*in) || !isxdigit(*(in + 1))) {
90 ERR(psdrv, "Invalid hex char in hex string\n");
91 HeapFree(PSDRV_Heap, 0, buf);
92 return NULL;
94 *out = 0;
95 for(i = 0; i < 2; i++) {
96 if(isdigit(*(in + i)))
97 *out |= (*(in + i) - '0') << ((1-i) * 4);
98 else
99 *out |= (toupper(*(in + i)) - 'A' + 10) << ((1-i) * 4);
101 out++;
102 in++;
106 *out = '\0';
107 return buf;
111 /***********************************************************************
113 * PSDRV_PPDGetTransValue
116 static BOOL32 PSDRV_PPDGetTransValue(char *start, PPDTuple *tuple)
118 char *buf, *end;
120 end = strpbrk(start, "\r\n");
121 if(end == start) return FALSE;
122 if(!end) end = start + strlen(start);
123 buf = HeapAlloc( PSDRV_Heap, 0, end - start + 1 );
124 memcpy(buf, start, end - start);
125 *(buf + (end - start)) = '\0';
126 tuple->valtrans = PSDRV_PPDDecodeHex(buf);
127 HeapFree( PSDRV_Heap, 0, buf );
128 return TRUE;
132 /***********************************************************************
134 * PSDRV_PPDGetInvocationValue
136 * Passed string that should be surrounded by `"'s, return string alloced
137 * from process heap.
139 static BOOL32 PSDRV_PPDGetInvocationValue(FILE *fp, char *pos, PPDTuple *tuple)
141 char *start, *end, *buf;
142 char line[257];
143 int len;
145 start = pos + 1;
146 buf = HeapAlloc( PSDRV_Heap, 0, strlen(start) + 1 );
147 len = 0;
148 do {
149 end = strchr(start, '"');
150 if(end) {
151 buf = HeapReAlloc( PSDRV_Heap, 0, buf,
152 len + (end - start) + 1 );
153 memcpy(buf + len, start, end - start);
154 *(buf + len + (end - start)) = '\0';
155 tuple->value = buf;
156 start = strchr(end, '/');
157 if(start)
158 return PSDRV_PPDGetTransValue(start + 1, tuple);
159 return TRUE;
160 } else {
161 int sl = strlen(start);
162 buf = HeapReAlloc( PSDRV_Heap, 0, buf, len + sl + 1 );
163 strcpy(buf + len, start);
164 len += sl;
166 } while( fgets((start = line), sizeof(line), fp) );
168 tuple->value = NULL;
169 HeapFree( PSDRV_Heap, 0, buf );
170 return FALSE;
174 /***********************************************************************
176 * PSDRV_PPDGetQuotedValue
178 * Passed string that should be surrounded by `"'s. Expand <xx> as hex
179 * return string alloced from process heap.
181 static BOOL32 PSDRV_PPDGetQuotedValue(FILE *fp, char *pos, PPDTuple *tuple)
183 char *buf;
185 if(!PSDRV_PPDGetInvocationValue(fp, pos, tuple))
186 return FALSE;
187 buf = PSDRV_PPDDecodeHex(tuple->value);
188 HeapFree(PSDRV_Heap, 0, tuple->value);
189 tuple->value = buf;
190 return TRUE;
194 /***********************************************************************
196 * PSDRV_PPDGetStringValue
198 * Just strip leading white space.
200 static BOOL32 PSDRV_PPDGetStringValue(char *str, PPDTuple *tuple)
202 char *start = str, *end;
204 while(*start != '\0' && isspace(*start))
205 start++;
207 end = strpbrk(start, "/\r\n");
208 if(!end) end = start + strlen(start);
209 tuple->value = HeapAlloc( PSDRV_Heap, 0, (end - start) + 1 );
210 memcpy(tuple->value, start, end - start);
211 *(tuple->value + (end - start)) = '\0';
212 if(*end == '/')
213 PSDRV_PPDGetTransValue(end + 1, tuple);
214 return TRUE;
218 /***********************************************************************
220 * PSDRV_PPDSymbolValue
222 * Not implemented yet.
224 static BOOL32 PSDRV_PPDGetSymbolValue(char *pos, PPDTuple *tuple)
226 FIXME(psdrv, "Stub\n");
227 return FALSE;
231 /*********************************************************************
233 * PSDRV_PPDGetNextTuple
235 * Gets the next Keyword Option Value tuple from the file. Allocs space off
236 * the process heap which should be free()ed by the caller if not needed.
238 static BOOL32 PSDRV_PPDGetNextTuple(FILE *fp, PPDTuple *tuple)
240 char line[257], *opt = NULL, *cp, *trans;
241 BOOL32 gotoption = TRUE;
243 memset(tuple, 0, sizeof(*tuple));
245 do {
246 if(!fgets(line, sizeof(line), fp))
247 return FALSE;
248 if(line[0] == '*' && line[1] != '%' && strncmp(line, "*End", 4))
249 break;
250 } while(1);
252 if(line[strlen(line)-1] != '\n') {
253 ERR(psdrv, "Line too long.\n");
254 return FALSE;
257 for(cp = line; !isspace(*cp); cp++)
260 if(*(cp-1) == ':') {
261 cp--;
262 gotoption = FALSE;
263 } else {
264 opt = cp;
267 tuple->key = HeapAlloc( PSDRV_Heap, 0, cp - line + 1 );
268 if(!tuple->key) return FALSE;
270 memcpy(tuple->key, line, cp - line);
271 tuple->key[cp - line] = '\0';
273 if(gotoption) {
274 while(isspace(*opt))
275 opt++;
276 cp = strpbrk(opt, ":/");
277 if(!cp) {
278 ERR(psdrv, "Error in line '%s'?\n", line);
279 return FALSE;
281 tuple->option = HeapAlloc( PSDRV_Heap, 0, cp - opt + 1 );
282 if(!tuple->option) return FALSE;
283 memcpy(tuple->option, opt, cp - opt);
284 tuple->option[cp - opt] = '\0';
285 if(*cp == '/') {
286 char *buf;
287 trans = cp + 1;
288 cp = strchr(trans, ':');
289 if(!cp) {
290 ERR(psdrv, "Error in line '%s'?\n", line);
291 return FALSE;
293 buf = HeapAlloc( PSDRV_Heap, 0, cp - trans + 1 );
294 if(!buf) return FALSE;
295 memcpy(buf, trans, cp - trans);
296 buf[cp - trans] = '\0';
297 tuple->opttrans = PSDRV_PPDDecodeHex(buf);
298 HeapFree( PSDRV_Heap, 0, buf );
301 while(!isspace(*cp))
302 cp++;
304 while(isspace(*cp))
305 cp++;
307 switch(*cp) {
308 case '"':
309 if( (!gotoption && strncmp(tuple->key, "*?", 2) ) ||
310 !strncmp(tuple->key, "*JCL", 4))
311 PSDRV_PPDGetQuotedValue(fp, cp, tuple);
312 else
313 PSDRV_PPDGetInvocationValue(fp, cp, tuple);
314 break;
316 case '^':
317 PSDRV_PPDGetSymbolValue(cp, tuple);
318 break;
320 default:
321 PSDRV_PPDGetStringValue(cp, tuple);
323 return TRUE;
326 /*********************************************************************
328 * PSDRV_PPDGetPageSizeInfo
330 * Searches ppd PageSize list to return entry matching name or creates new
331 * entry which is appended to the list if name is not found.
334 PAGESIZE *PSDRV_PPDGetPageSizeInfo(PPD *ppd, char *name)
336 PAGESIZE *page = ppd->PageSizes, *lastpage;
338 if(!page) {
339 page = ppd->PageSizes = HeapAlloc( PSDRV_Heap,
340 HEAP_ZERO_MEMORY, sizeof(*page) );
341 return page;
342 } else {
343 for( ; page; page = page->next) {
344 if(!strcmp(page->Name, name))
345 return page;
346 lastpage = page;
349 lastpage->next = HeapAlloc( PSDRV_Heap,
350 HEAP_ZERO_MEMORY, sizeof(*page) );
351 return lastpage->next;
355 /**********************************************************************
357 * PSDRV_PPDGetWord
359 * Returns ptr alloced from heap to first word in str. Strips leading spaces.
360 * Puts ptr to next word in next
362 static char *PSDRV_PPDGetWord(char *str, char **next)
364 char *start, *end, *ret;
366 start = str;
367 while(start && *start && isspace(*start))
368 start++;
369 if(!start || !*start) return FALSE;
371 end = start;
372 while(*end && !isspace(*end))
373 end++;
375 ret = HeapAlloc( PSDRV_Heap, 0, end - start + 1 );
376 memcpy(ret, start, end - start );
377 *(ret + (end - start)) = '\0';
379 while(*end && isspace(*end))
380 end++;
381 if(*end)
382 *next = end;
383 else
384 *next = NULL;
386 return ret;
389 /***********************************************************************
391 * PSDRV_ParsePPD
395 PPD *PSDRV_ParsePPD(char *fname)
397 FILE *fp;
398 PPD *ppd;
399 PPDTuple tuple;
401 TRACE(psdrv, "%s\n", fname);
403 if((fp = fopen(fname, "r")) == NULL) {
404 WARN(psdrv, "Couldn't open ppd file '%s'\n", fname);
405 return NULL;
408 ppd = HeapAlloc( PSDRV_Heap, HEAP_ZERO_MEMORY, sizeof(*ppd));
409 if(!ppd) {
410 ERR(psdrv, "Unable to allocate memory for ppd\n");
411 fclose(fp);
412 return NULL;
416 while( PSDRV_PPDGetNextTuple(fp, &tuple)) {
418 if(!strcmp("*NickName", tuple.key)) {
419 ppd->NickName = tuple.value;
420 tuple.value = NULL;
421 TRACE(psdrv, "NickName = '%s'\n", ppd->NickName);
424 else if(!strcmp("*LanguageLevel", tuple.key)) {
425 sscanf(tuple.value, "%d", &(ppd->LanguageLevel));
426 TRACE(psdrv, "LanguageLevel = %d\n", ppd->LanguageLevel);
429 else if(!strcmp("*ColorDevice", tuple.key)) {
430 if(!strcasecmp(tuple.value, "true"))
431 ppd->ColorDevice = TRUE;
432 TRACE(psdrv, "ColorDevice = %d\n", (int)ppd->ColorDevice);
435 else if(!strcmp("*DefaultResolution", tuple.key)) {
436 sscanf(tuple.value, "%d", &(ppd->DefaultResolution));
437 TRACE(psdrv, "DefaultResolution = %d\n", ppd->DefaultResolution);
440 else if(!strcmp("*Font", tuple.key)) {
441 FONTNAME *fn;
443 for(fn = ppd->InstalledFonts; fn && fn->next; fn = fn->next)
445 if(!fn) {
446 ppd->InstalledFonts = HeapAlloc(PSDRV_Heap,
447 HEAP_ZERO_MEMORY, sizeof(*fn));
448 fn = ppd->InstalledFonts;
449 } else {
450 fn->next = HeapAlloc(PSDRV_Heap,
451 HEAP_ZERO_MEMORY, sizeof(*fn));
452 fn = fn->next;
454 fn->Name = tuple.option;
455 tuple.option = NULL;
458 else if(!strcmp("*DefaultFont", tuple.key)) {
459 ppd->DefaultFont = tuple.value;
460 tuple.value = NULL;
463 else if(!strcmp("*JCLBegin", tuple.key)) {
464 ppd->JCLBegin = tuple.value;
465 tuple.value = NULL;
468 else if(!strcmp("*JCLToPSInterpreter", tuple.key)) {
469 ppd->JCLToPSInterpreter = tuple.value;
470 tuple.value = NULL;
473 else if(!strcmp("*JCLEnd", tuple.key)) {
474 ppd->JCLEnd = tuple.value;
475 tuple.value = NULL;
478 else if(!strcmp("*PageSize", tuple.key)) {
479 PAGESIZE *page;
480 page = PSDRV_PPDGetPageSizeInfo(ppd, tuple.option);
482 if(!page->Name) {
483 int i;
485 page->Name = tuple.option;
486 tuple.option = NULL;
488 for(i = 0; PageTrans[i].PSName; i++) {
489 if(!strcmp(PageTrans[i].PSName, page->Name)) { /* case ? */
490 page->WinPage = PageTrans[i].WinPage;
491 break;
494 if(!page->WinPage)
495 FIXME(psdrv, "Can't find Windows page type for '%s'\n",
496 page->Name);
498 if(!page->FullName) {
499 page->FullName = tuple.opttrans;
500 tuple.opttrans = NULL;
502 if(!page->InvocationString) {
503 page->InvocationString = tuple.value;
504 tuple.value = NULL;
508 else if(!strcmp("*ImageableArea", tuple.key)) {
509 PAGESIZE *page;
510 page = PSDRV_PPDGetPageSizeInfo(ppd, tuple.option);
512 if(!page->Name) {
513 page->Name = tuple.option;
514 tuple.option = NULL;
516 if(!page->FullName) {
517 page->FullName = tuple.opttrans;
518 tuple.opttrans = NULL;
521 #define PIA page->ImageableArea
522 if(!PIA) {
523 PIA = HeapAlloc( PSDRV_Heap, 0, sizeof(*PIA) );
524 sscanf(tuple.value, "%f%f%f%f", &PIA->llx, &PIA->lly,
525 &PIA->urx, &PIA->ury);
527 #undef PIA
531 else if(!strcmp("*PaperDimension", tuple.key)) {
532 PAGESIZE *page;
533 page = PSDRV_PPDGetPageSizeInfo(ppd, tuple.option);
535 if(!page->Name) {
536 page->Name = tuple.option;
537 tuple.option = NULL;
539 if(!page->FullName) {
540 page->FullName = tuple.opttrans;
541 tuple.opttrans = NULL;
544 #define PD page->PaperDimension
545 if(!PD) {
546 PD = HeapAlloc( PSDRV_Heap, 0, sizeof(*PD) );
547 sscanf(tuple.value, "%f%f", &PD->x, &PD->y);
549 #undef PD
552 else if(!strcmp("*LandscapeOrientation", tuple.key)) {
553 if(!strcmp(tuple.value, "Plus90"))
554 ppd->LandscapeOrientation = 90;
555 else if(!strcmp(tuple.value, "Minus90"))
556 ppd->LandscapeOrientation = -90;
558 /* anything else, namely 'any', leaves value at 0 */
560 TRACE(psdrv, "LandscapeOrientation = %d\n",
561 ppd->LandscapeOrientation);
564 else if(!strcmp("*UIConstraints", tuple.key)) {
565 char *start;
566 CONSTRAINT *con, **insert = &ppd->Constraints;
568 while(*insert)
569 insert = &((*insert)->next);
571 con = *insert = HeapAlloc( PSDRV_Heap, HEAP_ZERO_MEMORY,
572 sizeof(*con) );
574 start = tuple.value;
576 con->Feature1 = PSDRV_PPDGetWord(start, &start);
577 con->Value1 = PSDRV_PPDGetWord(start, &start);
578 con->Feature2 = PSDRV_PPDGetWord(start, &start);
579 con->Value2 = PSDRV_PPDGetWord(start, &start);
582 else if(!strcmp("*InputSlot", tuple.key)) {
583 INPUTSLOT *slot, **insert = &ppd->InputSlots;
584 int i;
586 while(*insert)
587 insert = &((*insert)->next);
589 slot = *insert = HeapAlloc( PSDRV_Heap, HEAP_ZERO_MEMORY,
590 sizeof(*slot) );
592 slot->Name = tuple.option;
593 tuple.option = NULL;
594 if(tuple.opttrans) {
595 slot->FullName = tuple.opttrans;
596 tuple.opttrans = NULL;
598 if(tuple.value) {
599 slot->InvocationString = tuple.value;
600 tuple.value = NULL;
604 for(i = 0; BinTrans[i].PSName; i++) {
605 if(!strcmp(BinTrans[i].PSName, slot->Name)) { /* case ? */
606 slot->WinBin = BinTrans[i].WinBin;
607 break;
610 if(!slot->WinBin)
611 FIXME(psdrv, "Can't find Windows bin type for '%s'\n",
612 slot->Name);
616 if(tuple.key) HeapFree(PSDRV_Heap, 0, tuple.key);
617 if(tuple.option) HeapFree(PSDRV_Heap, 0, tuple.option);
618 if(tuple.value) HeapFree(PSDRV_Heap, 0, tuple.value);
619 if(tuple.opttrans) HeapFree(PSDRV_Heap, 0, tuple.opttrans);
620 if(tuple.valtrans) HeapFree(PSDRV_Heap, 0, tuple.valtrans);
626 FONTNAME *fn;
627 PAGESIZE *page;
628 CONSTRAINT *con;
629 INPUTSLOT *slot;
631 for(fn = ppd->InstalledFonts; fn; fn = fn->next)
632 TRACE(psdrv, "'%s'\n", fn->Name);
634 for(page = ppd->PageSizes; page; page = page->next) {
635 TRACE(psdrv, "'%s' aka '%s' (%d) invoked by '%s'\n", page->Name,
636 page->FullName, page->WinPage, page->InvocationString);
637 if(page->ImageableArea)
638 TRACE(psdrv, "Area = %.2f,%.2f - %.2f, %.2f\n",
639 page->ImageableArea->llx, page->ImageableArea->lly,
640 page->ImageableArea->urx, page->ImageableArea->ury);
641 if(page->PaperDimension)
642 TRACE(psdrv, "Dimension = %.2f x %.2f\n",
643 page->PaperDimension->x, page->PaperDimension->y);
646 for(con = ppd->Constraints; con; con = con->next)
647 TRACE(psdrv, "%s %s %s %s\n", con->Feature1, con->Value1,
648 con->Feature2, con->Value2);
650 for(slot = ppd->InputSlots; slot; slot = slot->next)
651 TRACE(psdrv, "Slot '%s' Name '%s' (%d) Invocation '%s'\n",
652 slot->Name, slot->FullName, slot->WinBin,
653 slot->InvocationString);
656 return ppd;