Specify the proper call convention in the PropSysFreeString()
[wine] / dlls / wineps / escape.c
1 /*
2  *      PostScript driver Escape function
3  *
4  *      Copyright 1998  Huw D M Davies
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  */
20 #include <stdarg.h>
21
22 #include "windef.h"
23 #include "winbase.h"
24 #include "wingdi.h"
25 #include "wine/wingdi16.h"
26 #include "wine/winuser16.h"
27 #include "wownt32.h"
28 #include "psdrv.h"
29 #include "wine/debug.h"
30 #include "winspool.h"
31 #include "heap.h"
32
33 WINE_DEFAULT_DEBUG_CHANNEL(psdrv);
34
35 static const char psbegindocument[] =
36 "%%BeginDocument: Wine passthrough\n";
37
38 /**********************************************************************
39  *           ExtEscape  (WINEPS.@)
40  */
41 INT PSDRV_ExtEscape( PSDRV_PDEVICE *physDev, INT nEscape, INT cbInput, LPCVOID in_data,
42                      INT cbOutput, LPVOID out_data )
43 {
44     switch(nEscape)
45     {
46     case QUERYESCSUPPORT:
47         if(cbInput < sizeof(INT))
48         {
49             WARN("cbInput < sizeof(INT) (=%d) for QUERYESCSUPPORT\n", cbInput);
50             return 0;
51         } else {
52             UINT num = *(const UINT *)in_data;
53             TRACE("QUERYESCSUPPORT for %d\n", num);
54
55             switch(num) {
56             case NEXTBAND:
57             case SETCOPYCOUNT:
58             case GETTECHNOLOGY:
59             case SETLINECAP:
60             case SETLINEJOIN:
61             case SETMITERLIMIT:
62             case SETCHARSET:
63             case EXT_DEVICE_CAPS:
64             case SET_BOUNDS:
65             case EPSPRINTING:
66             case POSTSCRIPT_DATA:
67             case PASSTHROUGH:
68             case POSTSCRIPT_PASSTHROUGH:
69             case POSTSCRIPT_IGNORE:
70             case BEGIN_PATH:
71             case CLIP_TO_PATH:
72             case END_PATH:
73                 return TRUE;
74
75             default:
76                 return FALSE;
77             }
78         }
79
80     case NEXTBAND:
81     {
82         RECT *r = out_data;
83         if(!physDev->job.banding) {
84             physDev->job.banding = TRUE;
85             r->left   = 0;
86             r->top    = 0;
87             r->right  = physDev->horzRes;
88             r->bottom = physDev->vertRes;
89             TRACE("NEXTBAND returning %ld,%ld - %ld,%ld\n", r->left, r->top, r->right, r->bottom );
90             return 1;
91         }
92         r->left   = 0;
93         r->top    = 0;
94         r->right  = 0;
95         r->bottom = 0;
96         TRACE("NEXTBAND rect to 0,0 - 0,0\n" );
97         physDev->job.banding = FALSE;
98         return EndPage( physDev->hdc );
99     }
100
101     case SETCOPYCOUNT:
102         {
103             const INT *NumCopies = in_data;
104             INT *ActualCopies = out_data;
105             if(cbInput != sizeof(INT)) {
106                 WARN("cbInput != sizeof(INT) (=%d) for SETCOPYCOUNT\n", cbInput);
107                 return 0;
108             }
109             TRACE("SETCOPYCOUNT %d\n", *NumCopies);
110             *ActualCopies = 1;
111             return 1;
112         }
113
114     case GETTECHNOLOGY:
115         {
116             LPSTR p = out_data;
117             strcpy(p, "PostScript");
118             *(p + strlen(p) + 1) = '\0'; /* 2 '\0's at end of string */
119             return 1;
120         }
121
122     case SETLINECAP:
123         {
124             INT newCap = *(const INT *)in_data;
125             if(cbInput != sizeof(INT)) {
126                 WARN("cbInput != sizeof(INT) (=%d) for SETLINECAP\n", cbInput);
127                 return 0;
128             }
129             TRACE("SETLINECAP %d\n", newCap);
130             return 0;
131         }
132
133     case SETLINEJOIN:
134         {
135             INT newJoin = *(const INT *)in_data;
136             if(cbInput != sizeof(INT)) {
137                 WARN("cbInput != sizeof(INT) (=%d) for SETLINEJOIN\n", cbInput);
138                 return 0;
139             }
140             TRACE("SETLINEJOIN %d\n", newJoin);
141             return 0;
142         }
143
144     case SETMITERLIMIT:
145         {
146             INT newLimit = *(const INT *)in_data;
147             if(cbInput != sizeof(INT)) {
148                 WARN("cbInput != sizeof(INT) (=%d) for SETMITERLIMIT\n", cbInput);
149                 return 0;
150             }
151             TRACE("SETMITERLIMIT %d\n", newLimit);
152             return 0;
153         }
154
155     case SETCHARSET:
156       /* Undocumented escape used by winword6.
157          Switches between ANSI and a special charset.
158          If *lpInData == 1 we require that
159          0x91 is quoteleft
160          0x92 is quoteright
161          0x93 is quotedblleft
162          0x94 is quotedblright
163          0x95 is bullet
164          0x96 is endash
165          0x97 is emdash
166          0xa0 is non break space - yeah right.
167
168          If *lpInData == 0 we get ANSI.
169          Since there's nothing else there, let's just make these the default
170          anyway and see what happens...
171       */
172         return 1;
173
174     case EXT_DEVICE_CAPS:
175         {
176             UINT cap = *(const UINT *)in_data;
177             if(cbInput != sizeof(UINT)) {
178                 WARN("cbInput != sizeof(UINT) (=%d) for EXT_DEVICE_CAPS\n", cbInput);
179                 return 0;
180             }
181             TRACE("EXT_DEVICE_CAPS %d\n", cap);
182             return 0;
183         }
184
185     case SET_BOUNDS:
186         {
187             const RECT *r = in_data;
188             if(cbInput != sizeof(RECT)) {
189                 WARN("cbInput != sizeof(RECT) (=%d) for SET_BOUNDS\n", cbInput);
190                 return 0;
191             }
192             TRACE("SET_BOUNDS (%ld,%ld) - (%ld,%ld)\n", r->left, r->top,
193                   r->right, r->bottom);
194             return 0;
195         }
196
197     case EPSPRINTING:
198         {
199             UINT epsprint = *(const UINT*)in_data;
200             /* FIXME: In this mode we do not need to send page intros and page
201              * ends according to the doc. But I just ignore that detail
202              * for now.
203              */
204             TRACE("EPS Printing support %sable.\n",epsprint?"en":"dis");
205             return 1;
206         }
207
208     case POSTSCRIPT_DATA:
209     case PASSTHROUGH:
210     case POSTSCRIPT_PASSTHROUGH:
211         {
212             /* Write directly to spool file, bypassing normal PS driver
213              * processing that is done along with writing PostScript code
214              * to the spool.
215              * We have a WORD before the data counting the size, but
216              * cbInput is just this +2.
217              * However Photoshop 7 has a bug that sets cbInput to 2 less than the
218              * length of the string, rather than 2 more.  So we'll use the WORD at
219              * in_data[0] instead.
220              */
221             if(!physDev->job.in_passthrough) {
222                 WriteSpool16(physDev->job.hJob, (LPSTR)psbegindocument, sizeof(psbegindocument)-1);
223                 physDev->job.in_passthrough = TRUE;
224             }
225             return WriteSpool16(physDev->job.hJob,((char*)in_data)+2,*(const WORD*)in_data);
226         }
227
228     case POSTSCRIPT_IGNORE:
229       {
230         BOOL ret = physDev->job.quiet;
231         TRACE("POSTSCRIPT_IGNORE %d\n", *(const short*)in_data);
232         physDev->job.quiet = *(const short*)in_data;
233         return ret;
234       }
235
236     case GETSETPRINTORIENT:
237         {
238             /* If lpInData is present, it is a 20 byte structure, first 32
239              * bit LONG value is the orientation. if lpInData is NULL, it
240              * returns the current orientation.
241              */
242             FIXME("GETSETPRINTORIENT not implemented (data %p)!\n",in_data);
243             return 1;
244         }
245     case BEGIN_PATH:
246         TRACE("BEGIN_PATH\n");
247         if(physDev->pathdepth)
248             FIXME("Nested paths not yet handled\n");
249         return ++physDev->pathdepth;
250
251     case END_PATH:
252       {
253         const struct PATH_INFO *info = (const struct PATH_INFO*)in_data;
254
255         TRACE("END_PATH\n");
256         if(!physDev->pathdepth) {
257             ERR("END_PATH called without a BEIGN_PATH\n");
258             return -1;
259         }
260         TRACE("RenderMode = %d, FillMode = %d, BkMode = %d\n",
261               info->RenderMode, info->FillMode, info->BkMode);
262         switch(info->RenderMode) {
263         case RENDERMODE_NO_DISPLAY:
264             PSDRV_WriteClosePath(physDev); /* not sure if this is necessary, but it can't hurt */
265             break;
266         case RENDERMODE_OPEN:
267         case RENDERMODE_CLOSED:
268         default:
269             FIXME("END_PATH: RenderMode %d, not yet supported\n", info->RenderMode);
270             break;
271         }
272         return --physDev->pathdepth;
273       }
274
275     case CLIP_TO_PATH:
276       {
277         WORD mode = *(const WORD*)in_data;
278
279         switch(mode) {
280         case CLIP_SAVE:
281             TRACE("CLIP_TO_PATH: CLIP_SAVE\n");
282             PSDRV_WriteGSave(physDev);
283             return 1;
284         case CLIP_RESTORE:
285             TRACE("CLIP_TO_PATH: CLIP_RESTORE\n");
286             PSDRV_WriteGRestore(physDev);
287             return 1;
288         case CLIP_INCLUSIVE:
289             TRACE("CLIP_TO_PATH: CLIP_INCLUSIVE\n");
290             /* FIXME to clip or eoclip ? (see PATH_INFO.FillMode) */
291             PSDRV_WriteClip(physDev);
292             PSDRV_WriteNewPath(physDev);
293             return 1;
294         case CLIP_EXCLUSIVE:
295             FIXME("CLIP_EXCLUSIVE: not implemented\n");
296             return 0;
297         default:
298             FIXME("Unknown CLIP_TO_PATH mode %d\n", mode);
299             return 0;
300         }
301       }
302     default:
303         FIXME("Unimplemented code 0x%x\n", nEscape);
304         return 0;
305     }
306 }
307
308 /************************************************************************
309  *           PSDRV_StartPage
310  */
311 INT PSDRV_StartPage( PSDRV_PDEVICE *physDev )
312 {
313     if(!physDev->job.OutOfPage) {
314         FIXME("Already started a page?\n");
315         return 1;
316     }
317
318     if(physDev->job.PageNo++ == 0) {
319         if(!PSDRV_WriteHeader( physDev, physDev->job.DocName ))
320             return 0;
321     }
322
323     if(!PSDRV_WriteNewPage( physDev ))
324         return 0;
325     physDev->job.OutOfPage = FALSE;
326     return 1;
327 }
328
329
330 /************************************************************************
331  *           PSDRV_EndPage
332  */
333 INT PSDRV_EndPage( PSDRV_PDEVICE *physDev )
334 {
335     if(physDev->job.OutOfPage) {
336         FIXME("Already ended a page?\n");
337         return 1;
338     }
339     if(!PSDRV_WriteEndPage( physDev ))
340         return 0;
341     PSDRV_EmptyDownloadList(physDev, FALSE);
342     physDev->job.OutOfPage = TRUE;
343     return 1;
344 }
345
346
347 /************************************************************************
348  *           PSDRV_StartDocA
349  */
350 INT PSDRV_StartDocA( PSDRV_PDEVICE *physDev, const DOCINFOA *doc )
351 {
352     LPCSTR output = "LPT1:";
353     BYTE buf[300];
354     HANDLE hprn = INVALID_HANDLE_VALUE;
355     PRINTER_INFO_5A *pi5 = (PRINTER_INFO_5A*)buf;
356     DWORD needed;
357
358     if(physDev->job.hJob) {
359         FIXME("hJob != 0. Now what?\n");
360         return 0;
361     }
362
363     if(doc->lpszOutput)
364         output = doc->lpszOutput;
365     else if(physDev->job.output)
366         output = physDev->job.output;
367     else {
368         if(OpenPrinterA(physDev->pi->FriendlyName, &hprn, NULL) &&
369            GetPrinterA(hprn, 5, buf, sizeof(buf), &needed)) {
370             output = pi5->pPortName;
371         }
372         if(hprn != INVALID_HANDLE_VALUE)
373             ClosePrinter(hprn);
374     }
375
376     physDev->job.hJob = OpenJob16(output,  doc->lpszDocName, HDC_16(physDev->hdc) );
377     if(!physDev->job.hJob) {
378         WARN("OpenJob failed\n");
379         return 0;
380     }
381     physDev->job.banding = FALSE;
382     physDev->job.OutOfPage = TRUE;
383     physDev->job.PageNo = 0;
384     physDev->job.quiet = FALSE;
385     physDev->job.in_passthrough = FALSE;
386     physDev->job.had_passthrough_rect = FALSE;
387     if(doc->lpszDocName) {
388         physDev->job.DocName = HeapAlloc(GetProcessHeap(), 0, strlen(doc->lpszDocName)+1);
389         strcpy(physDev->job.DocName, doc->lpszDocName);
390     } else
391         physDev->job.DocName = NULL;
392
393     return physDev->job.hJob;
394 }
395
396 /************************************************************************
397  *           PSDRV_StartDoc
398  */
399 INT PSDRV_StartDoc( PSDRV_PDEVICE *physDev, const DOCINFOW *doc )
400 {
401     DOCINFOA docA;
402     INT ret;
403
404     docA.cbSize = doc->cbSize;
405     docA.lpszDocName = doc->lpszDocName ?
406       HEAP_strdupWtoA( GetProcessHeap(), 0, doc->lpszDocName ) : NULL;
407     docA.lpszOutput = doc->lpszOutput ?
408       HEAP_strdupWtoA( GetProcessHeap(), 0, doc->lpszOutput ) : NULL;
409     docA.lpszDatatype = doc->lpszDatatype ?
410       HEAP_strdupWtoA( GetProcessHeap(), 0, doc->lpszDatatype ) : NULL;
411     docA.fwType = doc->fwType;
412
413     ret = PSDRV_StartDocA(physDev, &docA);
414
415     HeapFree( GetProcessHeap(), 0, (LPSTR)docA.lpszDocName );
416     HeapFree( GetProcessHeap(), 0, (LPSTR)docA.lpszOutput );
417     HeapFree( GetProcessHeap(), 0, (LPSTR)docA.lpszDatatype );
418
419     return ret;
420 }
421
422 /************************************************************************
423  *           PSDRV_EndDoc
424  */
425 INT PSDRV_EndDoc( PSDRV_PDEVICE *physDev )
426 {
427     INT ret = 1;
428     if(!physDev->job.hJob) {
429         FIXME("hJob == 0. Now what?\n");
430         return 0;
431     }
432
433     if(!physDev->job.OutOfPage) {
434         WARN("Somebody forgot an EndPage\n");
435         PSDRV_EndPage( physDev );
436     }
437     PSDRV_WriteFooter( physDev );
438
439     if( CloseJob16( physDev->job.hJob ) == SP_ERROR ) {
440         WARN("CloseJob error\n");
441         ret = 0;
442     }
443     physDev->job.hJob = 0;
444     HeapFree(GetProcessHeap(), 0, physDev->job.DocName);
445     physDev->job.DocName = NULL;
446
447     return ret;
448 }