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
10 #include "winnt.h" /* HEAP_ZERO_MEMORY */
16 DEFAULT_DEBUG_CHANNEL(psdrv)
27 /* map of page names in ppd file to Windows paper constants */
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},
45 /* the same for bin names */
51 {"Lower", DMBIN_LOWER},
52 {"Upper", DMBIN_UPPER},
53 {"Envelope", DMBIN_ENVELOPE},
54 {"LargeCapacity", DMBIN_LARGECAPACITY},
58 /***********************************************************************
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)
71 buf = HeapAlloc(PSDRV_Heap, 0, strlen(str) + 1);
75 for(in = str, out = buf; *in; in++) {
90 if(!isxdigit(*in) || !isxdigit(*(in + 1))) {
91 ERR(psdrv, "Invalid hex char in hex string\n");
92 HeapFree(PSDRV_Heap, 0, buf);
96 for(i = 0; i < 2; i++) {
97 if(isdigit(*(in + i)))
98 *out |= (*(in + i) - '0') << ((1-i) * 4);
100 *out |= (toupper(*(in + i)) - 'A' + 10) << ((1-i) * 4);
112 /***********************************************************************
114 * PSDRV_PPDGetTransValue
117 static BOOL PSDRV_PPDGetTransValue(char *start, PPDTuple *tuple)
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 );
133 /***********************************************************************
135 * PSDRV_PPDGetInvocationValue
137 * Passed string that should be surrounded by `"'s, return string alloced
140 static BOOL PSDRV_PPDGetInvocationValue(FILE *fp, char *pos, PPDTuple *tuple)
142 char *start, *end, *buf;
147 buf = HeapAlloc( PSDRV_Heap, 0, strlen(start) + 1 );
150 end = strchr(start, '"');
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';
157 start = strchr(end, '/');
159 return PSDRV_PPDGetTransValue(start + 1, tuple);
162 int sl = strlen(start);
163 buf = HeapReAlloc( PSDRV_Heap, 0, buf, len + sl + 1 );
164 strcpy(buf + len, start);
167 } while( fgets((start = line), sizeof(line), fp) );
170 HeapFree( PSDRV_Heap, 0, buf );
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)
186 if(!PSDRV_PPDGetInvocationValue(fp, pos, tuple))
188 buf = PSDRV_PPDDecodeHex(tuple->value);
189 HeapFree(PSDRV_Heap, 0, tuple->value);
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))
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';
214 PSDRV_PPDGetTransValue(end + 1, tuple);
219 /***********************************************************************
221 * PSDRV_PPDSymbolValue
223 * Not implemented yet.
225 static BOOL PSDRV_PPDGetSymbolValue(char *pos, PPDTuple *tuple)
227 FIXME(psdrv, "Stub\n");
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));
247 if(!fgets(line, sizeof(line), fp))
249 if(line[0] == '*' && line[1] != '%' && strncmp(line, "*End", 4))
253 if(line[strlen(line)-1] != '\n') {
254 ERR(psdrv, "Line too long.\n");
258 for(cp = line; !isspace(*cp); 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';
277 cp = strpbrk(opt, ":/");
279 ERR(psdrv, "Error in line '%s'?\n", line);
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';
289 cp = strchr(trans, ':');
291 ERR(psdrv, "Error in line '%s'?\n", line);
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 );
310 if( (!gotoption && strncmp(tuple->key, "*?", 2) ) ||
311 !strncmp(tuple->key, "*JCL", 4))
312 PSDRV_PPDGetQuotedValue(fp, cp, tuple);
314 PSDRV_PPDGetInvocationValue(fp, cp, tuple);
318 PSDRV_PPDGetSymbolValue(cp, tuple);
322 PSDRV_PPDGetStringValue(cp, tuple);
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;
340 page = ppd->PageSizes = HeapAlloc( PSDRV_Heap,
341 HEAP_ZERO_MEMORY, sizeof(*page) );
344 for( ; page; page = page->next) {
345 if(!strcmp(page->Name, name))
350 lastpage->next = HeapAlloc( PSDRV_Heap,
351 HEAP_ZERO_MEMORY, sizeof(*page) );
352 return lastpage->next;
356 /**********************************************************************
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;
368 while(start && *start && isspace(*start))
370 if(!start || !*start) return FALSE;
373 while(*end && !isspace(*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))
390 /***********************************************************************
396 PPD *PSDRV_ParsePPD(char *fname)
402 TRACE(psdrv, "%s\n", fname);
404 if((fp = fopen(fname, "r")) == NULL) {
405 WARN(psdrv, "Couldn't open ppd file '%s'\n", fname);
409 ppd = HeapAlloc( PSDRV_Heap, HEAP_ZERO_MEMORY, sizeof(*ppd));
411 ERR(psdrv, "Unable to allocate memory for ppd\n");
417 while( PSDRV_PPDGetNextTuple(fp, &tuple)) {
419 if(!strcmp("*NickName", tuple.key)) {
420 ppd->NickName = tuple.value;
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 (!strcmp("*DefaultJCLResolution", tuple.key))) {
438 sscanf(tuple.value, "%d", &(ppd->DefaultResolution));
439 TRACE(psdrv, "DefaultResolution = %d\n", ppd->DefaultResolution);
442 else if(!strcmp("*Font", tuple.key)) {
445 for(fn = ppd->InstalledFonts; fn && fn->next; fn = fn->next)
448 ppd->InstalledFonts = HeapAlloc(PSDRV_Heap,
449 HEAP_ZERO_MEMORY, sizeof(*fn));
450 fn = ppd->InstalledFonts;
452 fn->next = HeapAlloc(PSDRV_Heap,
453 HEAP_ZERO_MEMORY, sizeof(*fn));
456 fn->Name = tuple.option;
460 else if(!strcmp("*DefaultFont", tuple.key)) {
461 ppd->DefaultFont = tuple.value;
465 else if(!strcmp("*JCLBegin", tuple.key)) {
466 ppd->JCLBegin = tuple.value;
470 else if(!strcmp("*JCLToPSInterpreter", tuple.key)) {
471 ppd->JCLToPSInterpreter = tuple.value;
475 else if(!strcmp("*JCLEnd", tuple.key)) {
476 ppd->JCLEnd = tuple.value;
480 else if(!strcmp("*PageSize", tuple.key)) {
482 page = PSDRV_PPDGetPageSizeInfo(ppd, tuple.option);
487 page->Name = tuple.option;
490 for(i = 0; PageTrans[i].PSName; i++) {
491 if(!strcmp(PageTrans[i].PSName, page->Name)) { /* case ? */
492 page->WinPage = PageTrans[i].WinPage;
497 FIXME(psdrv, "Can't find Windows page type for '%s'\n",
500 if(!page->FullName) {
501 page->FullName = tuple.opttrans;
502 tuple.opttrans = NULL;
504 if(!page->InvocationString) {
505 page->InvocationString = tuple.value;
510 else if(!strcmp("*ImageableArea", tuple.key)) {
512 page = PSDRV_PPDGetPageSizeInfo(ppd, tuple.option);
515 page->Name = tuple.option;
518 if(!page->FullName) {
519 page->FullName = tuple.opttrans;
520 tuple.opttrans = NULL;
523 #define PIA page->ImageableArea
525 PIA = HeapAlloc( PSDRV_Heap, 0, sizeof(*PIA) );
526 sscanf(tuple.value, "%f%f%f%f", &PIA->llx, &PIA->lly,
527 &PIA->urx, &PIA->ury);
533 else if(!strcmp("*PaperDimension", tuple.key)) {
535 page = PSDRV_PPDGetPageSizeInfo(ppd, tuple.option);
538 page->Name = tuple.option;
541 if(!page->FullName) {
542 page->FullName = tuple.opttrans;
543 tuple.opttrans = NULL;
546 #define PD page->PaperDimension
548 PD = HeapAlloc( PSDRV_Heap, 0, sizeof(*PD) );
549 sscanf(tuple.value, "%f%f", &PD->x, &PD->y);
554 else if(!strcmp("*LandscapeOrientation", tuple.key)) {
555 if(!strcmp(tuple.value, "Plus90"))
556 ppd->LandscapeOrientation = 90;
557 else if(!strcmp(tuple.value, "Minus90"))
558 ppd->LandscapeOrientation = -90;
560 /* anything else, namely 'any', leaves value at 0 */
562 TRACE(psdrv, "LandscapeOrientation = %d\n",
563 ppd->LandscapeOrientation);
566 else if(!strcmp("*UIConstraints", tuple.key)) {
568 CONSTRAINT *con, **insert = &ppd->Constraints;
571 insert = &((*insert)->next);
573 con = *insert = HeapAlloc( PSDRV_Heap, HEAP_ZERO_MEMORY,
578 con->Feature1 = PSDRV_PPDGetWord(start, &start);
579 con->Value1 = PSDRV_PPDGetWord(start, &start);
580 con->Feature2 = PSDRV_PPDGetWord(start, &start);
581 con->Value2 = PSDRV_PPDGetWord(start, &start);
584 else if(!strcmp("*InputSlot", tuple.key)) {
585 INPUTSLOT *slot, **insert = &ppd->InputSlots;
589 insert = &((*insert)->next);
591 slot = *insert = HeapAlloc( PSDRV_Heap, HEAP_ZERO_MEMORY,
594 slot->Name = tuple.option;
597 slot->FullName = tuple.opttrans;
598 tuple.opttrans = NULL;
601 slot->InvocationString = tuple.value;
606 for(i = 0; BinTrans[i].PSName; i++) {
607 if(!strcmp(BinTrans[i].PSName, slot->Name)) { /* case ? */
608 slot->WinBin = BinTrans[i].WinBin;
613 FIXME(psdrv, "Can't find Windows bin type for '%s'\n",
618 if(tuple.key) HeapFree(PSDRV_Heap, 0, tuple.key);
619 if(tuple.option) HeapFree(PSDRV_Heap, 0, tuple.option);
620 if(tuple.value) HeapFree(PSDRV_Heap, 0, tuple.value);
621 if(tuple.opttrans) HeapFree(PSDRV_Heap, 0, tuple.opttrans);
622 if(tuple.valtrans) HeapFree(PSDRV_Heap, 0, tuple.valtrans);
633 OPTIONENTRY *optionEntry;
635 for(fn = ppd->InstalledFonts; fn; fn = fn->next)
636 TRACE(psdrv, "'%s'\n", fn->Name);
638 for(page = ppd->PageSizes; page; page = page->next) {
639 TRACE(psdrv, "'%s' aka '%s' (%d) invoked by '%s'\n", page->Name,
640 page->FullName, page->WinPage, page->InvocationString);
641 if(page->ImageableArea)
642 TRACE(psdrv, "Area = %.2f,%.2f - %.2f, %.2f\n",
643 page->ImageableArea->llx, page->ImageableArea->lly,
644 page->ImageableArea->urx, page->ImageableArea->ury);
645 if(page->PaperDimension)
646 TRACE(psdrv, "Dimension = %.2f x %.2f\n",
647 page->PaperDimension->x, page->PaperDimension->y);
650 for(con = ppd->Constraints; con; con = con->next)
651 TRACE(psdrv, "CONSTRAINTS@ %s %s %s %s\n", con->Feature1,
652 con->Value1, con->Feature2, con->Value2);
654 for(option = ppd->InstalledOptions; option; option = option->next) {
655 TRACE(psdrv, "OPTION: %s %s %s\n", option->OptionName,
656 option->FullName, option->DefaultOption);
657 for(optionEntry = option->Options; optionEntry;
658 optionEntry = optionEntry->next)
659 TRACE(psdrv, "\tOPTIONENTRY: %s %s %s\n", optionEntry->Name,
660 optionEntry->FullName, optionEntry->InvocationString);
663 for(slot = ppd->InputSlots; slot; slot = slot->next)
664 TRACE(psdrv, "INPUTSLOTS '%s' Name '%s' (%d) Invocation '%s'\n",
665 slot->Name, slot->FullName, slot->WinBin,
666 slot->InvocationString);