Implemented toolbar multirow button layout.
[wine/testsucceed.git] / graphics / psdrv / ppd.c
blob213babe150f25d5dc92e4a5c41922016c65d3c8f
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 "winnt.h" /* HEAP_ZERO_MEMORY */
11 #include "heap.h"
12 #include "debug.h"
13 #include "psdrv.h"
14 #include "winspool.h"
16 DEFAULT_DEBUG_CHANNEL(psdrv)
18 typedef struct {
19 char *key;
20 char *option;
21 char *opttrans;
22 char *value;
23 char *valtrans;
24 } PPDTuple;
27 /* map of page names in ppd file to Windows paper constants */
29 static struct {
30 char *PSName;
31 WORD WinPage;
32 } PageTrans[] = {
33 {"A4", DMPAPER_A4},
34 {"Letter", DMPAPER_LETTER},
35 {"Legal", DMPAPER_LEGAL},
36 {"Executive", DMPAPER_EXECUTIVE},
37 {"Comm10", DMPAPER_ENV_10},
38 {"Monarch", DMPAPER_ENV_MONARCH},
39 {"DL", DMPAPER_ENV_DL},
40 {"C5", DMPAPER_ENV_C5},
41 {"B5", DMPAPER_ENV_B5},
42 {NULL, 0}
45 /* the same for bin names */
47 static struct {
48 char *PSName;
49 WORD WinBin;
50 } BinTrans[] = {
51 {"Lower", DMBIN_LOWER},
52 {"Upper", DMBIN_UPPER},
53 {"Envelope", DMBIN_ENVELOPE},
54 {"LargeCapacity", DMBIN_LARGECAPACITY},
55 {NULL, 0}
58 /***********************************************************************
60 * PSDRV_PPDDecodeHex
62 * Copies str into a newly allocated string from the process heap subsituting
63 * hex strings enclosed in '<' and '>' for their byte codes.
66 static char *PSDRV_PPDDecodeHex(char *str)
68 char *buf, *in, *out;
69 BOOL inhex = FALSE;
71 buf = HeapAlloc(PSDRV_Heap, 0, strlen(str) + 1);
72 if(!buf)
73 return NULL;
75 for(in = str, out = buf; *in; in++) {
76 if(!inhex) {
77 if(*in != '<')
78 *out++ = *in;
79 else
80 inhex = TRUE;
81 } else {
82 if(*in == '>') {
83 inhex = FALSE;
84 continue;
86 else if(isspace(*in))
87 continue;
88 else {
89 int i;
90 if(!isxdigit(*in) || !isxdigit(*(in + 1))) {
91 ERR(psdrv, "Invalid hex char in hex string\n");
92 HeapFree(PSDRV_Heap, 0, buf);
93 return NULL;
95 *out = 0;
96 for(i = 0; i < 2; i++) {
97 if(isdigit(*(in + i)))
98 *out |= (*(in + i) - '0') << ((1-i) * 4);
99 else
100 *out |= (toupper(*(in + i)) - 'A' + 10) << ((1-i) * 4);
102 out++;
103 in++;
107 *out = '\0';
108 return buf;
112 /***********************************************************************
114 * PSDRV_PPDGetTransValue
117 static BOOL PSDRV_PPDGetTransValue(char *start, PPDTuple *tuple)
119 char *buf, *end;
121 end = strpbrk(start, "\r\n");
122 if(end == start) return FALSE;
123 if(!end) end = start + strlen(start);
124 buf = HeapAlloc( PSDRV_Heap, 0, end - start + 1 );
125 memcpy(buf, start, end - start);
126 *(buf + (end - start)) = '\0';
127 tuple->valtrans = PSDRV_PPDDecodeHex(buf);
128 HeapFree( PSDRV_Heap, 0, buf );
129 return TRUE;
133 /***********************************************************************
135 * PSDRV_PPDGetInvocationValue
137 * Passed string that should be surrounded by `"'s, return string alloced
138 * from process heap.
140 static BOOL PSDRV_PPDGetInvocationValue(FILE *fp, char *pos, PPDTuple *tuple)
142 char *start, *end, *buf;
143 char line[257];
144 int len;
146 start = pos + 1;
147 buf = HeapAlloc( PSDRV_Heap, 0, strlen(start) + 1 );
148 len = 0;
149 do {
150 end = strchr(start, '"');
151 if(end) {
152 buf = HeapReAlloc( PSDRV_Heap, 0, buf,
153 len + (end - start) + 1 );
154 memcpy(buf + len, start, end - start);
155 *(buf + len + (end - start)) = '\0';
156 tuple->value = buf;
157 start = strchr(end, '/');
158 if(start)
159 return PSDRV_PPDGetTransValue(start + 1, tuple);
160 return TRUE;
161 } else {
162 int sl = strlen(start);
163 buf = HeapReAlloc( PSDRV_Heap, 0, buf, len + sl + 1 );
164 strcpy(buf + len, start);
165 len += sl;
167 } while( fgets((start = line), sizeof(line), fp) );
169 tuple->value = NULL;
170 HeapFree( PSDRV_Heap, 0, buf );
171 return FALSE;
175 /***********************************************************************
177 * PSDRV_PPDGetQuotedValue
179 * Passed string that should be surrounded by `"'s. Expand <xx> as hex
180 * return string alloced from process heap.
182 static BOOL PSDRV_PPDGetQuotedValue(FILE *fp, char *pos, PPDTuple *tuple)
184 char *buf;
186 if(!PSDRV_PPDGetInvocationValue(fp, pos, tuple))
187 return FALSE;
188 buf = PSDRV_PPDDecodeHex(tuple->value);
189 HeapFree(PSDRV_Heap, 0, tuple->value);
190 tuple->value = buf;
191 return TRUE;
195 /***********************************************************************
197 * PSDRV_PPDGetStringValue
199 * Just strip leading white space.
201 static BOOL PSDRV_PPDGetStringValue(char *str, PPDTuple *tuple)
203 char *start = str, *end;
205 while(*start != '\0' && isspace(*start))
206 start++;
208 end = strpbrk(start, "/\r\n");
209 if(!end) end = start + strlen(start);
210 tuple->value = HeapAlloc( PSDRV_Heap, 0, (end - start) + 1 );
211 memcpy(tuple->value, start, end - start);
212 *(tuple->value + (end - start)) = '\0';
213 if(*end == '/')
214 PSDRV_PPDGetTransValue(end + 1, tuple);
215 return TRUE;
219 /***********************************************************************
221 * PSDRV_PPDSymbolValue
223 * Not implemented yet.
225 static BOOL PSDRV_PPDGetSymbolValue(char *pos, PPDTuple *tuple)
227 FIXME(psdrv, "Stub\n");
228 return FALSE;
232 /*********************************************************************
234 * PSDRV_PPDGetNextTuple
236 * Gets the next Keyword Option Value tuple from the file. Allocs space off
237 * the process heap which should be free()ed by the caller if not needed.
239 static BOOL PSDRV_PPDGetNextTuple(FILE *fp, PPDTuple *tuple)
241 char line[257], *opt = NULL, *cp, *trans;
242 BOOL gotoption = TRUE;
244 memset(tuple, 0, sizeof(*tuple));
246 do {
247 if(!fgets(line, sizeof(line), fp))
248 return FALSE;
249 if(line[0] == '*' && line[1] != '%' && strncmp(line, "*End", 4))
250 break;
251 } while(1);
253 if(line[strlen(line)-1] != '\n') {
254 ERR(psdrv, "Line too long.\n");
255 return FALSE;
258 for(cp = line; !isspace(*cp); cp++)
261 if(*(cp-1) == ':') {
262 cp--;
263 gotoption = FALSE;
264 } else {
265 opt = cp;
268 tuple->key = HeapAlloc( PSDRV_Heap, 0, cp - line + 1 );
269 if(!tuple->key) return FALSE;
271 memcpy(tuple->key, line, cp - line);
272 tuple->key[cp - line] = '\0';
274 if(gotoption) {
275 while(isspace(*opt))
276 opt++;
277 cp = strpbrk(opt, ":/");
278 if(!cp) {
279 ERR(psdrv, "Error in line '%s'?\n", line);
280 return FALSE;
282 tuple->option = HeapAlloc( PSDRV_Heap, 0, cp - opt + 1 );
283 if(!tuple->option) return FALSE;
284 memcpy(tuple->option, opt, cp - opt);
285 tuple->option[cp - opt] = '\0';
286 if(*cp == '/') {
287 char *buf;
288 trans = cp + 1;
289 cp = strchr(trans, ':');
290 if(!cp) {
291 ERR(psdrv, "Error in line '%s'?\n", line);
292 return FALSE;
294 buf = HeapAlloc( PSDRV_Heap, 0, cp - trans + 1 );
295 if(!buf) return FALSE;
296 memcpy(buf, trans, cp - trans);
297 buf[cp - trans] = '\0';
298 tuple->opttrans = PSDRV_PPDDecodeHex(buf);
299 HeapFree( PSDRV_Heap, 0, buf );
302 while(!isspace(*cp))
303 cp++;
305 while(isspace(*cp))
306 cp++;
308 switch(*cp) {
309 case '"':
310 if( (!gotoption && strncmp(tuple->key, "*?", 2) ) ||
311 !strncmp(tuple->key, "*JCL", 4))
312 PSDRV_PPDGetQuotedValue(fp, cp, tuple);
313 else
314 PSDRV_PPDGetInvocationValue(fp, cp, tuple);
315 break;
317 case '^':
318 PSDRV_PPDGetSymbolValue(cp, tuple);
319 break;
321 default:
322 PSDRV_PPDGetStringValue(cp, tuple);
324 return TRUE;
327 /*********************************************************************
329 * PSDRV_PPDGetPageSizeInfo
331 * Searches ppd PageSize list to return entry matching name or creates new
332 * entry which is appended to the list if name is not found.
335 PAGESIZE *PSDRV_PPDGetPageSizeInfo(PPD *ppd, char *name)
337 PAGESIZE *page = ppd->PageSizes, *lastpage;
339 if(!page) {
340 page = ppd->PageSizes = HeapAlloc( PSDRV_Heap,
341 HEAP_ZERO_MEMORY, sizeof(*page) );
342 return page;
343 } else {
344 for( ; page; page = page->next) {
345 if(!strcmp(page->Name, name))
346 return page;
347 lastpage = page;
350 lastpage->next = HeapAlloc( PSDRV_Heap,
351 HEAP_ZERO_MEMORY, sizeof(*page) );
352 return lastpage->next;
356 /**********************************************************************
358 * PSDRV_PPDGetWord
360 * Returns ptr alloced from heap to first word in str. Strips leading spaces.
361 * Puts ptr to next word in next
363 static char *PSDRV_PPDGetWord(char *str, char **next)
365 char *start, *end, *ret;
367 start = str;
368 while(start && *start && isspace(*start))
369 start++;
370 if(!start || !*start) return FALSE;
372 end = start;
373 while(*end && !isspace(*end))
374 end++;
376 ret = HeapAlloc( PSDRV_Heap, 0, end - start + 1 );
377 memcpy(ret, start, end - start );
378 *(ret + (end - start)) = '\0';
380 while(*end && isspace(*end))
381 end++;
382 if(*end)
383 *next = end;
384 else
385 *next = NULL;
387 return ret;
390 /***********************************************************************
392 * PSDRV_ParsePPD
396 PPD *PSDRV_ParsePPD(char *fname)
398 FILE *fp;
399 PPD *ppd;
400 PPDTuple tuple;
402 TRACE(psdrv, "%s\n", fname);
404 if((fp = fopen(fname, "r")) == NULL) {
405 WARN(psdrv, "Couldn't open ppd file '%s'\n", fname);
406 return NULL;
409 ppd = HeapAlloc( PSDRV_Heap, HEAP_ZERO_MEMORY, sizeof(*ppd));
410 if(!ppd) {
411 ERR(psdrv, "Unable to allocate memory for ppd\n");
412 fclose(fp);
413 return NULL;
417 while( PSDRV_PPDGetNextTuple(fp, &tuple)) {
419 if(!strcmp("*NickName", tuple.key)) {
420 ppd->NickName = tuple.value;
421 tuple.value = NULL;
422 TRACE(psdrv, "NickName = '%s'\n", ppd->NickName);
425 else if(!strcmp("*LanguageLevel", tuple.key)) {
426 sscanf(tuple.value, "%d", &(ppd->LanguageLevel));
427 TRACE(psdrv, "LanguageLevel = %d\n", ppd->LanguageLevel);
430 else if(!strcmp("*ColorDevice", tuple.key)) {
431 if(!strcasecmp(tuple.value, "true"))
432 ppd->ColorDevice = TRUE;
433 TRACE(psdrv, "ColorDevice = %d\n", (int)ppd->ColorDevice);
436 else if(!strcmp("*DefaultResolution", tuple.key)) {
437 sscanf(tuple.value, "%d", &(ppd->DefaultResolution));
438 TRACE(psdrv, "DefaultResolution = %d\n", ppd->DefaultResolution);
441 else if(!strcmp("*Font", tuple.key)) {
442 FONTNAME *fn;
444 for(fn = ppd->InstalledFonts; fn && fn->next; fn = fn->next)
446 if(!fn) {
447 ppd->InstalledFonts = HeapAlloc(PSDRV_Heap,
448 HEAP_ZERO_MEMORY, sizeof(*fn));
449 fn = ppd->InstalledFonts;
450 } else {
451 fn->next = HeapAlloc(PSDRV_Heap,
452 HEAP_ZERO_MEMORY, sizeof(*fn));
453 fn = fn->next;
455 fn->Name = tuple.option;
456 tuple.option = NULL;
459 else if(!strcmp("*DefaultFont", tuple.key)) {
460 ppd->DefaultFont = tuple.value;
461 tuple.value = NULL;
464 else if(!strcmp("*JCLBegin", tuple.key)) {
465 ppd->JCLBegin = tuple.value;
466 tuple.value = NULL;
469 else if(!strcmp("*JCLToPSInterpreter", tuple.key)) {
470 ppd->JCLToPSInterpreter = tuple.value;
471 tuple.value = NULL;
474 else if(!strcmp("*JCLEnd", tuple.key)) {
475 ppd->JCLEnd = tuple.value;
476 tuple.value = NULL;
479 else if(!strcmp("*PageSize", tuple.key)) {
480 PAGESIZE *page;
481 page = PSDRV_PPDGetPageSizeInfo(ppd, tuple.option);
483 if(!page->Name) {
484 int i;
486 page->Name = tuple.option;
487 tuple.option = NULL;
489 for(i = 0; PageTrans[i].PSName; i++) {
490 if(!strcmp(PageTrans[i].PSName, page->Name)) { /* case ? */
491 page->WinPage = PageTrans[i].WinPage;
492 break;
495 if(!page->WinPage)
496 FIXME(psdrv, "Can't find Windows page type for '%s'\n",
497 page->Name);
499 if(!page->FullName) {
500 page->FullName = tuple.opttrans;
501 tuple.opttrans = NULL;
503 if(!page->InvocationString) {
504 page->InvocationString = tuple.value;
505 tuple.value = NULL;
509 else if(!strcmp("*ImageableArea", tuple.key)) {
510 PAGESIZE *page;
511 page = PSDRV_PPDGetPageSizeInfo(ppd, tuple.option);
513 if(!page->Name) {
514 page->Name = tuple.option;
515 tuple.option = NULL;
517 if(!page->FullName) {
518 page->FullName = tuple.opttrans;
519 tuple.opttrans = NULL;
522 #define PIA page->ImageableArea
523 if(!PIA) {
524 PIA = HeapAlloc( PSDRV_Heap, 0, sizeof(*PIA) );
525 sscanf(tuple.value, "%f%f%f%f", &PIA->llx, &PIA->lly,
526 &PIA->urx, &PIA->ury);
528 #undef PIA
532 else if(!strcmp("*PaperDimension", tuple.key)) {
533 PAGESIZE *page;
534 page = PSDRV_PPDGetPageSizeInfo(ppd, tuple.option);
536 if(!page->Name) {
537 page->Name = tuple.option;
538 tuple.option = NULL;
540 if(!page->FullName) {
541 page->FullName = tuple.opttrans;
542 tuple.opttrans = NULL;
545 #define PD page->PaperDimension
546 if(!PD) {
547 PD = HeapAlloc( PSDRV_Heap, 0, sizeof(*PD) );
548 sscanf(tuple.value, "%f%f", &PD->x, &PD->y);
550 #undef PD
553 else if(!strcmp("*LandscapeOrientation", tuple.key)) {
554 if(!strcmp(tuple.value, "Plus90"))
555 ppd->LandscapeOrientation = 90;
556 else if(!strcmp(tuple.value, "Minus90"))
557 ppd->LandscapeOrientation = -90;
559 /* anything else, namely 'any', leaves value at 0 */
561 TRACE(psdrv, "LandscapeOrientation = %d\n",
562 ppd->LandscapeOrientation);
565 else if(!strcmp("*UIConstraints", tuple.key)) {
566 char *start;
567 CONSTRAINT *con, **insert = &ppd->Constraints;
569 while(*insert)
570 insert = &((*insert)->next);
572 con = *insert = HeapAlloc( PSDRV_Heap, HEAP_ZERO_MEMORY,
573 sizeof(*con) );
575 start = tuple.value;
577 con->Feature1 = PSDRV_PPDGetWord(start, &start);
578 con->Value1 = PSDRV_PPDGetWord(start, &start);
579 con->Feature2 = PSDRV_PPDGetWord(start, &start);
580 con->Value2 = PSDRV_PPDGetWord(start, &start);
583 else if(!strcmp("*InputSlot", tuple.key)) {
584 INPUTSLOT *slot, **insert = &ppd->InputSlots;
585 int i;
587 while(*insert)
588 insert = &((*insert)->next);
590 slot = *insert = HeapAlloc( PSDRV_Heap, HEAP_ZERO_MEMORY,
591 sizeof(*slot) );
593 slot->Name = tuple.option;
594 tuple.option = NULL;
595 if(tuple.opttrans) {
596 slot->FullName = tuple.opttrans;
597 tuple.opttrans = NULL;
599 if(tuple.value) {
600 slot->InvocationString = tuple.value;
601 tuple.value = NULL;
605 for(i = 0; BinTrans[i].PSName; i++) {
606 if(!strcmp(BinTrans[i].PSName, slot->Name)) { /* case ? */
607 slot->WinBin = BinTrans[i].WinBin;
608 break;
611 if(!slot->WinBin)
612 FIXME(psdrv, "Can't find Windows bin type for '%s'\n",
613 slot->Name);
617 if(tuple.key) HeapFree(PSDRV_Heap, 0, tuple.key);
618 if(tuple.option) HeapFree(PSDRV_Heap, 0, tuple.option);
619 if(tuple.value) HeapFree(PSDRV_Heap, 0, tuple.value);
620 if(tuple.opttrans) HeapFree(PSDRV_Heap, 0, tuple.opttrans);
621 if(tuple.valtrans) HeapFree(PSDRV_Heap, 0, tuple.valtrans);
627 FONTNAME *fn;
628 PAGESIZE *page;
629 CONSTRAINT *con;
630 INPUTSLOT *slot;
632 for(fn = ppd->InstalledFonts; fn; fn = fn->next)
633 TRACE(psdrv, "'%s'\n", fn->Name);
635 for(page = ppd->PageSizes; page; page = page->next) {
636 TRACE(psdrv, "'%s' aka '%s' (%d) invoked by '%s'\n", page->Name,
637 page->FullName, page->WinPage, page->InvocationString);
638 if(page->ImageableArea)
639 TRACE(psdrv, "Area = %.2f,%.2f - %.2f, %.2f\n",
640 page->ImageableArea->llx, page->ImageableArea->lly,
641 page->ImageableArea->urx, page->ImageableArea->ury);
642 if(page->PaperDimension)
643 TRACE(psdrv, "Dimension = %.2f x %.2f\n",
644 page->PaperDimension->x, page->PaperDimension->y);
647 for(con = ppd->Constraints; con; con = con->next)
648 TRACE(psdrv, "%s %s %s %s\n", con->Feature1, con->Value1,
649 con->Feature2, con->Value2);
651 for(slot = ppd->InputSlots; slot; slot = slot->next)
652 TRACE(psdrv, "Slot '%s' Name '%s' (%d) Invocation '%s'\n",
653 slot->Name, slot->FullName, slot->WinBin,
654 slot->InvocationString);
657 return ppd;