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
);