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
11 #include "winnt.h" /* HEAP_ZERO_MEMORY */
26 /* map of page names in ppd file to Windows paper constants */
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},
44 /* the same for bin names */
50 {"Lower", DMBIN_LOWER},
51 {"Upper", DMBIN_UPPER},
52 {"Envelope", DMBIN_ENVELOPE},
53 {"LargeCapacity", DMBIN_LARGECAPACITY},
57 /***********************************************************************
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)
70 buf = HeapAlloc(PSDRV_Heap, 0, strlen(str) + 1);
74 for(in = str, out = buf; *in; in++) {
89 if(!isxdigit(*in) || !isxdigit(*(in + 1))) {
90 ERR(psdrv, "Invalid hex char in hex string\n");
91 HeapFree(PSDRV_Heap, 0, buf);
95 for(i = 0; i < 2; i++) {
96 if(isdigit(*(in + i)))
97 *out |= (*(in + i) - '0') << ((1-i) * 4);
99 *out |= (toupper(*(in + i)) - 'A' + 10) << ((1-i) * 4);
111 /***********************************************************************
113 * PSDRV_PPDGetTransValue
116 static BOOL32 PSDRV_PPDGetTransValue(char *start, PPDTuple *tuple)
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 );
132 /***********************************************************************
134 * PSDRV_PPDGetInvocationValue
136 * Passed string that should be surrounded by `"'s, return string alloced
139 static BOOL32 PSDRV_PPDGetInvocationValue(FILE *fp, char *pos, PPDTuple *tuple)
141 char *start, *end, *buf;
146 buf = HeapAlloc( PSDRV_Heap, 0, strlen(start) + 1 );
149 end = strchr(start, '"');
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';
156 start = strchr(end, '/');
158 return PSDRV_PPDGetTransValue(start + 1, tuple);
161 int sl = strlen(start);
162 buf = HeapReAlloc( PSDRV_Heap, 0, buf, len + sl + 1 );
163 strcpy(buf + len, start);
166 } while( fgets((start = line), sizeof(line), fp) );
169 HeapFree( PSDRV_Heap, 0, buf );
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)
185 if(!PSDRV_PPDGetInvocationValue(fp, pos, tuple))
187 buf = PSDRV_PPDDecodeHex(tuple->value);
188 HeapFree(PSDRV_Heap, 0, tuple->value);
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))
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';
213 PSDRV_PPDGetTransValue(end + 1, tuple);
218 /***********************************************************************
220 * PSDRV_PPDSymbolValue
222 * Not implemented yet.
224 static BOOL32 PSDRV_PPDGetSymbolValue(char *pos, PPDTuple *tuple)
226 FIXME(psdrv, "Stub\n");
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));
246 if(!fgets(line, sizeof(line), fp))
248 if(line[0] == '*' && line[1] != '%' && strncmp(line, "*End", 4))
252 if(line[strlen(line)-1] != '\n') {
253 ERR(psdrv, "Line too long.\n");
257 for(cp = line; !isspace(*cp); 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';
276 cp = strpbrk(opt, ":/");
278 ERR(psdrv, "Error in line '%s'?\n", line);
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';
288 cp = strchr(trans, ':');
290 ERR(psdrv, "Error in line '%s'?\n", line);
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 );
309 if( (!gotoption && strncmp(tuple->key, "*?", 2) ) ||
310 !strncmp(tuple->key, "*JCL", 4))
311 PSDRV_PPDGetQuotedValue(fp, cp, tuple);
313 PSDRV_PPDGetInvocationValue(fp, cp, tuple);
317 PSDRV_PPDGetSymbolValue(cp, tuple);
321 PSDRV_PPDGetStringValue(cp, tuple);
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;
339 page = ppd->PageSizes = HeapAlloc( PSDRV_Heap,
340 HEAP_ZERO_MEMORY, sizeof(*page) );
343 for( ; page; page = page->next) {
344 if(!strcmp(page->Name, name))
349 lastpage->next = HeapAlloc( PSDRV_Heap,
350 HEAP_ZERO_MEMORY, sizeof(*page) );
351 return lastpage->next;
355 /**********************************************************************
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;
367 while(start && *start && isspace(*start))
369 if(!start || !*start) return FALSE;
372 while(*end && !isspace(*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))
389 /***********************************************************************
395 PPD *PSDRV_ParsePPD(char *fname)
401 TRACE(psdrv, "%s\n", fname);
403 if((fp = fopen(fname, "r")) == NULL) {
404 WARN(psdrv, "Couldn't open ppd file '%s'\n", fname);
408 ppd = HeapAlloc( PSDRV_Heap, HEAP_ZERO_MEMORY, sizeof(*ppd));
410 ERR(psdrv, "Unable to allocate memory for ppd\n");
416 while( PSDRV_PPDGetNextTuple(fp, &tuple)) {
418 if(!strcmp("*NickName", tuple.key)) {
419 ppd->NickName = tuple.value;
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)) {
443 for(fn = ppd->InstalledFonts; fn && fn->next; fn = fn->next)
446 ppd->InstalledFonts = HeapAlloc(PSDRV_Heap,
447 HEAP_ZERO_MEMORY, sizeof(*fn));
448 fn = ppd->InstalledFonts;
450 fn->next = HeapAlloc(PSDRV_Heap,
451 HEAP_ZERO_MEMORY, sizeof(*fn));
454 fn->Name = tuple.option;
458 else if(!strcmp("*DefaultFont", tuple.key)) {
459 ppd->DefaultFont = tuple.value;
463 else if(!strcmp("*JCLBegin", tuple.key)) {
464 ppd->JCLBegin = tuple.value;
468 else if(!strcmp("*JCLToPSInterpreter", tuple.key)) {
469 ppd->JCLToPSInterpreter = tuple.value;
473 else if(!strcmp("*JCLEnd", tuple.key)) {
474 ppd->JCLEnd = tuple.value;
478 else if(!strcmp("*PageSize", tuple.key)) {
480 page = PSDRV_PPDGetPageSizeInfo(ppd, tuple.option);
485 page->Name = tuple.option;
488 for(i = 0; PageTrans[i].PSName; i++) {
489 if(!strcmp(PageTrans[i].PSName, page->Name)) { /* case ? */
490 page->WinPage = PageTrans[i].WinPage;
495 FIXME(psdrv, "Can't find Windows page type for '%s'\n",
498 if(!page->FullName) {
499 page->FullName = tuple.opttrans;
500 tuple.opttrans = NULL;
502 if(!page->InvocationString) {
503 page->InvocationString = tuple.value;
508 else if(!strcmp("*ImageableArea", tuple.key)) {
510 page = PSDRV_PPDGetPageSizeInfo(ppd, tuple.option);
513 page->Name = tuple.option;
516 if(!page->FullName) {
517 page->FullName = tuple.opttrans;
518 tuple.opttrans = NULL;
521 #define PIA page->ImageableArea
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);
531 else if(!strcmp("*PaperDimension", tuple.key)) {
533 page = PSDRV_PPDGetPageSizeInfo(ppd, tuple.option);
536 page->Name = tuple.option;
539 if(!page->FullName) {
540 page->FullName = tuple.opttrans;
541 tuple.opttrans = NULL;
544 #define PD page->PaperDimension
546 PD = HeapAlloc( PSDRV_Heap, 0, sizeof(*PD) );
547 sscanf(tuple.value, "%f%f", &PD->x, &PD->y);
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)) {
566 CONSTRAINT *con, **insert = &ppd->Constraints;
569 insert = &((*insert)->next);
571 con = *insert = HeapAlloc( PSDRV_Heap, HEAP_ZERO_MEMORY,
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;
587 insert = &((*insert)->next);
589 slot = *insert = HeapAlloc( PSDRV_Heap, HEAP_ZERO_MEMORY,
592 slot->Name = tuple.option;
595 slot->FullName = tuple.opttrans;
596 tuple.opttrans = NULL;
599 slot->InvocationString = tuple.value;
604 for(i = 0; BinTrans[i].PSName; i++) {
605 if(!strcmp(BinTrans[i].PSName, slot->Name)) { /* case ? */
606 slot->WinBin = BinTrans[i].WinBin;
611 FIXME(psdrv, "Can't find Windows bin type for '%s'\n",
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);
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);