Added regedit unit test, a couple minor changes to regedit.
[wine] / objects / metafile.c
1 /*
2  * Metafile functions
3  *
4  * Copyright  David W. Metcalfe, 1994
5  *            Niels de Carpentier, Albrecht Kleine, Huw Davies 1996
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20  */
21
22 /*
23  * These functions are primarily involved with metafile playback or anything
24  * that touches a HMETAFILE.
25  * For recording of metafiles look in graphics/metafiledrv/
26  *
27  * Note that (32 bit) HMETAFILEs are GDI objects, while HMETAFILE16s are
28  * global memory handles so these cannot be interchanged.
29  *
30  * Memory-based metafiles are just stored as a continuous block of memory with
31  * a METAHEADER at the head with METARECORDs appended to it.  mtType is
32  * METAFILE_MEMORY (1).  Note this is indentical to the disk image of a
33  * disk-based metafile - even mtType is METAFILE_MEMORY.
34  * 16bit HMETAFILE16s are global handles to this block
35  * 32bit HMETAFILEs are GDI handles METAFILEOBJs, which contains a ptr to
36  * the memory.
37  * Disk-based metafiles are rather different. HMETAFILE16s point to a
38  * METAHEADER which has mtType equal to METAFILE_DISK (2).  Following the 9
39  * WORDs of the METAHEADER there are a further 3 WORDs of 0, 1 of 0x117, 1
40  * more 0, then 2 which may be a time stamp of the file and then the path of
41  * the file (METAHEADERDISK). I've copied this for 16bit compatibility.
42  *
43  * HDMD - 14/4/1999
44  */
45
46 #include "config.h"
47
48 #include <string.h>
49 #include <fcntl.h>
50
51 #include "wine/winbase16.h"
52 #include "wine/wingdi16.h"
53 #include "bitmap.h"
54 #include "global.h"
55 #include "wine/debug.h"
56
57 WINE_DEFAULT_DEBUG_CHANNEL(metafile);
58
59 #include "pshpack1.h"
60 typedef struct
61 {
62     DWORD dw1, dw2, dw3;
63     WORD w4;
64     CHAR filename[0x100];
65 } METAHEADERDISK;
66 #include "poppack.h"
67
68 typedef struct
69 {
70     GDIOBJHDR   header;
71     METAHEADER  *mh;
72 } METAFILEOBJ;
73
74 #define MFHEADERSIZE (sizeof(METAHEADER))
75 #define MFVERSION 0x300
76
77 /* ### start build ### */
78 extern WORD CALLBACK MF_CallTo16_word_wllwl(MFENUMPROC16,WORD,LONG,LONG,WORD,LONG);
79 /* ### stop build ### */
80
81 /******************************************************************
82  *         MF_AddHandle
83  *
84  *    Add a handle to an external handle table and return the index
85  */
86 static int MF_AddHandle(HANDLETABLE16 *ht, WORD htlen, HGDIOBJ16 hobj)
87 {
88     int i;
89
90     for (i = 0; i < htlen; i++)
91     {
92         if (*(ht->objectHandle + i) == 0)
93         {
94             *(ht->objectHandle + i) = hobj;
95             return i;
96         }
97     }
98     return -1;
99 }
100
101
102 /******************************************************************
103  *         MF_Create_HMETATFILE
104  *
105  * Creates a (32 bit) HMETAFILE object from a METAHEADER
106  *
107  * HMETAFILEs are GDI objects.
108  */
109 HMETAFILE MF_Create_HMETAFILE(METAHEADER *mh)
110 {
111     HMETAFILE hmf = 0;
112     METAFILEOBJ *metaObj = GDI_AllocObject( sizeof(METAFILEOBJ), METAFILE_MAGIC, &hmf, NULL );
113     if (metaObj)
114     {
115     metaObj->mh = mh;
116         GDI_ReleaseObj( hmf );
117     }
118     return hmf;
119 }
120
121 /******************************************************************
122  *         MF_Create_HMETATFILE16
123  *
124  * Creates a HMETAFILE16 object from a METAHEADER
125  *
126  * HMETAFILE16s are Global memory handles.
127  */
128 HMETAFILE16 MF_Create_HMETAFILE16(METAHEADER *mh)
129 {
130     HMETAFILE16 hmf;
131     DWORD size = mh->mtSize * sizeof(WORD);
132
133     hmf = GlobalAlloc16(GMEM_MOVEABLE, size);
134     if(hmf)
135     {
136         METAHEADER *mh_dest = GlobalLock16(hmf);
137         memcpy(mh_dest, mh, size);
138         GlobalUnlock16(hmf);
139     }
140     HeapFree(GetProcessHeap(), 0, mh);
141     return hmf;
142 }
143
144 /******************************************************************
145  *         MF_GetMetaHeader
146  *
147  * Returns ptr to METAHEADER associated with HMETAFILE
148  */
149 static METAHEADER *MF_GetMetaHeader( HMETAFILE hmf )
150 {
151     METAHEADER *ret = NULL;
152     METAFILEOBJ * metaObj = (METAFILEOBJ *)GDI_GetObjPtr( hmf, METAFILE_MAGIC );
153     if (metaObj)
154     {
155         ret = metaObj->mh;
156         GDI_ReleaseObj( hmf );
157     }
158     return ret;
159 }
160
161 /******************************************************************
162  *         MF_GetMetaHeader16
163  *
164  * Returns ptr to METAHEADER associated with HMETAFILE16
165  * Should be followed by call to MF_ReleaseMetaHeader16
166  */
167 static METAHEADER *MF_GetMetaHeader16( HMETAFILE16 hmf )
168 {
169     return GlobalLock16(hmf);
170 }
171
172 /******************************************************************
173  *         MF_ReleaseMetaHeader16
174  *
175  * Releases METAHEADER associated with HMETAFILE16
176  */
177 static BOOL16 MF_ReleaseMetaHeader16( HMETAFILE16 hmf )
178 {
179     return GlobalUnlock16( hmf );
180 }
181
182
183 /******************************************************************
184  *           DeleteMetaFile   (GDI.127)
185  */
186 BOOL16 WINAPI DeleteMetaFile16(  HMETAFILE16 hmf )
187 {
188     return !GlobalFree16( hmf );
189 }
190
191 /******************************************************************
192  *          DeleteMetaFile  (GDI32.@)
193  *
194  *  Delete a memory-based metafile.
195  */
196
197 BOOL WINAPI DeleteMetaFile( HMETAFILE hmf )
198 {
199     METAFILEOBJ * metaObj = (METAFILEOBJ *)GDI_GetObjPtr( hmf, METAFILE_MAGIC );
200     if (!metaObj) return FALSE;
201     HeapFree( GetProcessHeap(), 0, metaObj->mh );
202     GDI_FreeObject( hmf, metaObj );
203     return TRUE;
204 }
205
206 /******************************************************************
207  *         MF_ReadMetaFile
208  *
209  * Returns a pointer to a memory based METAHEADER read in from file HFILE
210  *
211  */
212 static METAHEADER *MF_ReadMetaFile(HFILE hfile)
213 {
214     METAHEADER *mh;
215     DWORD BytesRead, size;
216
217     size = sizeof(METAHEADER);
218     mh = HeapAlloc( GetProcessHeap(), 0, size );
219     if(!mh) return NULL;
220     if(ReadFile( hfile, mh, size, &BytesRead, NULL) == 0 ||
221        BytesRead != size) {
222         HeapFree( GetProcessHeap(), 0, mh );
223         return NULL;
224     }
225     size = mh->mtSize * 2;
226     mh = HeapReAlloc( GetProcessHeap(), 0, mh, size );
227     if(!mh) return NULL;
228     size -= sizeof(METAHEADER);
229     if(ReadFile( hfile, (char *)mh + sizeof(METAHEADER), size, &BytesRead,
230                  NULL) == 0 ||
231        BytesRead != size) {
232         HeapFree( GetProcessHeap(), 0, mh );
233         return NULL;
234     }
235
236     if (mh->mtType != METAFILE_MEMORY) {
237         WARN("Disk metafile had mtType = %04x\n", mh->mtType);
238         mh->mtType = METAFILE_MEMORY;
239     }
240     return mh;
241 }
242
243 /******************************************************************
244  *         GetMetaFile   (GDI.124)
245  */
246 HMETAFILE16 WINAPI GetMetaFile16( LPCSTR lpFilename )
247 {
248     METAHEADER *mh;
249     HANDLE hFile;
250
251     TRACE("%s\n", lpFilename);
252
253     if(!lpFilename)
254         return 0;
255
256     if((hFile = CreateFileA(lpFilename, GENERIC_READ, FILE_SHARE_READ, NULL,
257                             OPEN_EXISTING, 0, 0)) == INVALID_HANDLE_VALUE)
258         return 0;
259
260     mh = MF_ReadMetaFile(hFile);
261     CloseHandle(hFile);
262     if(!mh) return 0;
263     return MF_Create_HMETAFILE16( mh );
264 }
265
266 /******************************************************************
267  *         GetMetaFileA   (GDI32.@)
268  *
269  *  Read a metafile from a file. Returns handle to a memory-based metafile.
270  */
271 HMETAFILE WINAPI GetMetaFileA( LPCSTR lpFilename )
272 {
273     METAHEADER *mh;
274     HANDLE hFile;
275
276     TRACE("%s\n", lpFilename);
277
278     if(!lpFilename)
279         return 0;
280
281     if((hFile = CreateFileA(lpFilename, GENERIC_READ, FILE_SHARE_READ, NULL,
282                             OPEN_EXISTING, 0, 0)) == INVALID_HANDLE_VALUE)
283         return 0;
284
285     mh = MF_ReadMetaFile(hFile);
286     CloseHandle(hFile);
287     if(!mh) return 0;
288     return MF_Create_HMETAFILE( mh );
289 }
290
291
292
293 /******************************************************************
294  *         GetMetaFileW   (GDI32.@)
295  */
296 HMETAFILE WINAPI GetMetaFileW( LPCWSTR lpFilename )
297 {
298     METAHEADER *mh;
299     HANDLE hFile;
300
301     TRACE("%s\n", debugstr_w(lpFilename));
302
303     if(!lpFilename)
304         return 0;
305
306     if((hFile = CreateFileW(lpFilename, GENERIC_READ, FILE_SHARE_READ, NULL,
307                             OPEN_EXISTING, 0, 0)) == INVALID_HANDLE_VALUE)
308         return 0;
309
310     mh = MF_ReadMetaFile(hFile);
311     CloseHandle(hFile);
312     if(!mh) return 0;
313     return MF_Create_HMETAFILE( mh );
314 }
315
316
317 /******************************************************************
318  *         MF_LoadDiskBasedMetaFile
319  *
320  * Creates a new memory-based metafile from a disk-based one.
321  */
322 static METAHEADER *MF_LoadDiskBasedMetaFile(METAHEADER *mh)
323 {
324     METAHEADERDISK *mhd;
325     HANDLE hfile;
326     METAHEADER *mh2;
327
328     if(mh->mtType != METAFILE_DISK) {
329         ERR("Not a disk based metafile\n");
330         return NULL;
331     }
332     mhd = (METAHEADERDISK *)((char *)mh + sizeof(METAHEADER));
333
334     if((hfile = CreateFileA(mhd->filename, GENERIC_READ, FILE_SHARE_READ, NULL,
335                             OPEN_EXISTING, 0, 0)) == INVALID_HANDLE_VALUE) {
336         WARN("Can't open file of disk based metafile\n");
337         return NULL;
338     }
339     mh2 = MF_ReadMetaFile(hfile);
340     CloseHandle(hfile);
341     return mh2;
342 }
343
344 /******************************************************************
345  *         MF_CreateMetaHeaderDisk
346  *
347  * Take a memory based METAHEADER and change it to a disk based METAHEADER
348  * assosiated with filename.  Note: Trashes contents of old one.
349  */
350 METAHEADER *MF_CreateMetaHeaderDisk(METAHEADER *mh, LPCSTR filename)
351 {
352     METAHEADERDISK *mhd;
353     DWORD size;
354
355     mh = HeapReAlloc( GetProcessHeap(), 0, mh,
356                       sizeof(METAHEADER) + sizeof(METAHEADERDISK));
357     mh->mtType = METAFILE_DISK;
358     size = HeapSize( GetProcessHeap(), 0, mh );
359     mhd = (METAHEADERDISK *)((char *)mh + sizeof(METAHEADER));
360     strcpy(mhd->filename, filename);
361     return mh;
362 }
363
364 /******************************************************************
365  *         CopyMetaFile   (GDI.151)
366  */
367 HMETAFILE16 WINAPI CopyMetaFile16( HMETAFILE16 hSrcMetaFile, LPCSTR lpFilename)
368 {
369     METAHEADER *mh = MF_GetMetaHeader16( hSrcMetaFile );
370     METAHEADER *mh2 = NULL;
371     HANDLE hFile;
372
373     TRACE("(%08x,%s)\n", hSrcMetaFile, lpFilename);
374
375     if(!mh) return 0;
376
377     if(mh->mtType == METAFILE_DISK)
378         mh2 = MF_LoadDiskBasedMetaFile(mh);
379     else {
380         mh2 = HeapAlloc( GetProcessHeap(), 0, mh->mtSize * 2 );
381         memcpy( mh2, mh, mh->mtSize * 2 );
382     }
383     MF_ReleaseMetaHeader16( hSrcMetaFile );
384
385     if(lpFilename) {         /* disk based metafile */
386         if((hFile = CreateFileA(lpFilename, GENERIC_WRITE, 0, NULL,
387                                 CREATE_ALWAYS, 0, 0)) == INVALID_HANDLE_VALUE) {
388             HeapFree( GetProcessHeap(), 0, mh2 );
389             return 0;
390         }
391         WriteFile(hFile, mh2, mh2->mtSize * 2, NULL, NULL);
392         CloseHandle(hFile);
393         mh2 = MF_CreateMetaHeaderDisk(mh2, lpFilename);
394     }
395
396     return MF_Create_HMETAFILE16( mh2 );
397 }
398
399
400 /******************************************************************
401  *         CopyMetaFileA   (GDI32.@)
402  *
403  *  Copies the metafile corresponding to hSrcMetaFile to either
404  *  a disk file, if a filename is given, or to a new memory based
405  *  metafile, if lpFileName is NULL.
406  *
407  * RETURNS
408  *
409  *  Handle to metafile copy on success, NULL on failure.
410  *
411  * BUGS
412  *
413  *  Copying to disk returns NULL even if successful.
414  */
415 HMETAFILE WINAPI CopyMetaFileA(
416                    HMETAFILE hSrcMetaFile, /* [in] handle of metafile to copy */
417                    LPCSTR lpFilename       /* [in] filename if copying to a file */
418 ) {
419     METAHEADER *mh = MF_GetMetaHeader( hSrcMetaFile );
420     METAHEADER *mh2 = NULL;
421     HANDLE hFile;
422
423     TRACE("(%08x,%s)\n", hSrcMetaFile, lpFilename);
424
425     if(!mh) return 0;
426
427     if(mh->mtType == METAFILE_DISK)
428         mh2 = MF_LoadDiskBasedMetaFile(mh);
429     else {
430         mh2 = HeapAlloc( GetProcessHeap(), 0, mh->mtSize * 2 );
431         memcpy( mh2, mh, mh->mtSize * 2 );
432     }
433
434     if(lpFilename) {         /* disk based metafile */
435         if((hFile = CreateFileA(lpFilename, GENERIC_WRITE, 0, NULL,
436                                 CREATE_ALWAYS, 0, 0)) == INVALID_HANDLE_VALUE) {
437             HeapFree( GetProcessHeap(), 0, mh2 );
438             return 0;
439         }
440         WriteFile(hFile, mh2, mh2->mtSize * 2, NULL, NULL);
441         CloseHandle(hFile);
442         mh2 = MF_CreateMetaHeaderDisk(mh2, lpFilename);
443     }
444
445     return MF_Create_HMETAFILE( mh2 );
446 }
447
448
449 /******************************************************************
450  *         CopyMetaFileW   (GDI32.@)
451  */
452 HMETAFILE WINAPI CopyMetaFileW( HMETAFILE hSrcMetaFile,
453                                     LPCWSTR lpFilename )
454 {
455     HMETAFILE ret = 0;
456     DWORD len = WideCharToMultiByte( CP_ACP, 0, lpFilename, -1, NULL, 0, NULL, NULL );
457     LPSTR p = HeapAlloc( GetProcessHeap(), 0, len );
458
459     if (p)
460     {
461         WideCharToMultiByte( CP_ACP, 0, lpFilename, -1, p, len, NULL, NULL );
462         ret = CopyMetaFileA( hSrcMetaFile, p );
463         HeapFree( GetProcessHeap(), 0, p );
464     }
465     return ret;
466 }
467
468
469 /******************************************************************
470  *         IsValidMetaFile   (GDI.410)
471  *
472  *  Attempts to check if a given metafile is correctly formatted.
473  *  Currently, the only things verified are several properties of the
474  *  header.
475  *
476  * RETURNS
477  *  TRUE if hmf passes some tests for being a valid metafile, FALSE otherwise.
478  *
479  * BUGS
480  *  This is not exactly what windows does, see _Undocumented_Windows_
481  *  for details.
482  */
483 BOOL16 WINAPI IsValidMetaFile16(HMETAFILE16 hmf)
484 {
485     BOOL16 res=FALSE;
486     METAHEADER *mh = MF_GetMetaHeader16(hmf);
487     if (mh) {
488         if (mh->mtType == METAFILE_MEMORY || mh->mtType == METAFILE_DISK)
489             if (mh->mtHeaderSize == MFHEADERSIZE/sizeof(INT16))
490                 if (mh->mtVersion == MFVERSION)
491                     res=TRUE;
492         MF_ReleaseMetaHeader16(hmf);
493     }
494     TRACE("IsValidMetaFile %x => %d\n",hmf,res);
495     return res;
496 }
497
498
499 /*******************************************************************
500  *         MF_PlayMetaFile
501  *
502  * Helper for PlayMetaFile
503  */
504 static BOOL MF_PlayMetaFile( HDC hdc, METAHEADER *mh)
505 {
506
507     METARECORD *mr;
508     HANDLETABLE16 *ht;
509     unsigned int offset = 0;
510     WORD i;
511     HPEN hPen;
512     HBRUSH hBrush;
513     HFONT hFont;
514     BOOL loaded = FALSE;
515
516     if (!mh) return FALSE;
517     if(mh->mtType == METAFILE_DISK) { /* Create a memory-based copy */
518         mh = MF_LoadDiskBasedMetaFile(mh);
519         if(!mh) return FALSE;
520         loaded = TRUE;
521     }
522
523     /* save the current pen, brush and font */
524     hPen = GetCurrentObject(hdc, OBJ_PEN);
525     hBrush = GetCurrentObject(hdc, OBJ_BRUSH);
526     hFont = GetCurrentObject(hdc, OBJ_FONT);
527
528     /* create the handle table */
529     ht = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
530                     sizeof(HANDLETABLE16) * mh->mtNoObjects);
531     if(!ht) return FALSE;
532
533     /* loop through metafile playing records */
534     offset = mh->mtHeaderSize * 2;
535     while (offset < mh->mtSize * 2)
536     {
537         mr = (METARECORD *)((char *)mh + offset);
538         TRACE("offset=%04x,size=%08lx\n",
539             offset, mr->rdSize);
540         if (!mr->rdSize) {
541             TRACE(
542                   "Entry got size 0 at offset %d, total mf length is %ld\n",
543                   offset,mh->mtSize*2);
544                 break; /* would loop endlessly otherwise */
545         }
546         offset += mr->rdSize * 2;
547         PlayMetaFileRecord16( hdc, ht, mr, mh->mtNoObjects );
548     }
549
550     SelectObject(hdc, hBrush);
551     SelectObject(hdc, hPen);
552     SelectObject(hdc, hFont);
553
554     /* free objects in handle table */
555     for(i = 0; i < mh->mtNoObjects; i++)
556       if(*(ht->objectHandle + i) != 0)
557         DeleteObject(*(ht->objectHandle + i));
558
559     /* free handle table */
560     HeapFree( GetProcessHeap(), 0, ht );
561     if(loaded)
562         HeapFree( GetProcessHeap(), 0, mh );
563     return TRUE;
564 }
565
566 /******************************************************************
567  *         PlayMetaFile   (GDI.123)
568  *
569  */
570 BOOL16 WINAPI PlayMetaFile16( HDC16 hdc, HMETAFILE16 hmf )
571 {
572     BOOL16 ret;
573     METAHEADER *mh = MF_GetMetaHeader16( hmf );
574     ret = MF_PlayMetaFile( hdc, mh );
575     MF_ReleaseMetaHeader16( hmf );
576     return ret;
577 }
578
579 /******************************************************************
580  *         PlayMetaFile   (GDI32.@)
581  *
582  *  Renders the metafile specified by hmf in the DC specified by
583  *  hdc. Returns FALSE on failure, TRUE on success.
584  */
585 BOOL WINAPI PlayMetaFile(
586                              HDC hdc,      /* [in] handle of DC to render in */
587                              HMETAFILE hmf /* [in] handle of metafile to render */
588 )
589 {
590     METAHEADER *mh = MF_GetMetaHeader( hmf );
591     return MF_PlayMetaFile( hdc, mh );
592 }
593
594
595 /******************************************************************
596  *            EnumMetaFile   (GDI.175)
597  *
598  */
599 BOOL16 WINAPI EnumMetaFile16( HDC16 hdc, HMETAFILE16 hmf,
600                               MFENUMPROC16 lpEnumFunc, LPARAM lpData )
601 {
602     METAHEADER *mh = MF_GetMetaHeader16(hmf);
603     METARECORD *mr;
604     HANDLETABLE16 *ht;
605     HGLOBAL16 hHT;
606     SEGPTR spht;
607     unsigned int offset = 0;
608     WORD i, seg;
609     HPEN hPen;
610     HBRUSH hBrush;
611     HFONT hFont;
612     BOOL16 result = TRUE, loaded = FALSE;
613
614     TRACE("(%04x, %04x, %08lx, %08lx)\n",
615                      hdc, hmf, (DWORD)lpEnumFunc, lpData);
616
617
618     if(!mh) return FALSE;
619     if(mh->mtType == METAFILE_DISK) { /* Create a memory-based copy */
620         mh = MF_LoadDiskBasedMetaFile(mh);
621         if(!mh) return FALSE;
622         loaded = TRUE;
623     }
624
625     /* save the current pen, brush and font */
626     hPen = GetCurrentObject(hdc, OBJ_PEN);
627     hBrush = GetCurrentObject(hdc, OBJ_BRUSH);
628     hFont = GetCurrentObject(hdc, OBJ_FONT);
629
630     /* create the handle table */
631
632     hHT = GlobalAlloc16(GMEM_MOVEABLE | GMEM_ZEROINIT,
633                      sizeof(HANDLETABLE16) * mh->mtNoObjects);
634     spht = K32WOWGlobalLock16(hHT);
635
636     seg = hmf | 7;
637     offset = mh->mtHeaderSize * 2;
638
639     /* loop through metafile records */
640
641     while (offset < (mh->mtSize * 2))
642     {
643         mr = (METARECORD *)((char *)mh + offset);
644
645         if (!MF_CallTo16_word_wllwl( lpEnumFunc, hdc, spht,
646                                   MAKESEGPTR( seg + (HIWORD(offset) << __AHSHIFT), LOWORD(offset) ),
647                                      mh->mtNoObjects, (LONG)lpData ))
648         {
649             result = FALSE;
650             break;
651         }
652
653
654         offset += (mr->rdSize * 2);
655     }
656
657     SelectObject(hdc, hBrush);
658     SelectObject(hdc, hPen);
659     SelectObject(hdc, hFont);
660
661     ht = (HANDLETABLE16 *)GlobalLock16(hHT);
662
663     /* free objects in handle table */
664     for(i = 0; i < mh->mtNoObjects; i++)
665       if(*(ht->objectHandle + i) != 0)
666         DeleteObject(*(ht->objectHandle + i));
667
668     /* free handle table */
669     GlobalFree16(hHT);
670     if(loaded)
671         HeapFree( GetProcessHeap(), 0, mh );
672     MF_ReleaseMetaHeader16(hmf);
673     return result;
674 }
675
676 /******************************************************************
677  *            EnumMetaFile   (GDI32.@)
678  *
679  *  Loop through the metafile records in hmf, calling the user-specified
680  *  function for each one, stopping when the user's function returns FALSE
681  *  (which is considered to be failure)
682  *  or when no records are left (which is considered to be success).
683  *
684  * RETURNS
685  *  TRUE on success, FALSE on failure.
686  *
687  * HISTORY
688  *   Niels de carpentier, april 1996
689  */
690 BOOL WINAPI EnumMetaFile(
691                              HDC hdc,
692                              HMETAFILE hmf,
693                              MFENUMPROC lpEnumFunc,
694                              LPARAM lpData
695 ) {
696     METAHEADER *mhTemp = NULL, *mh = MF_GetMetaHeader(hmf);
697     METARECORD *mr;
698     HANDLETABLE *ht;
699     BOOL result = TRUE;
700     int i;
701     unsigned int offset = 0;
702     HPEN hPen;
703     HBRUSH hBrush;
704     HFONT hFont;
705
706     TRACE("(%08x,%08x,%p,%p)\n", hdc, hmf, lpEnumFunc, (void*)lpData);
707     if (!mh) return 0;
708     if(mh->mtType == METAFILE_DISK)
709     {
710         /* Create a memory-based copy */
711         if (!(mhTemp = MF_LoadDiskBasedMetaFile(mh))) return FALSE;
712         mh = mhTemp;
713     }
714
715     /* save the current pen, brush and font */
716     hPen = GetCurrentObject(hdc, OBJ_PEN);
717     hBrush = GetCurrentObject(hdc, OBJ_BRUSH);
718     hFont = GetCurrentObject(hdc, OBJ_FONT);
719
720     ht = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
721                             sizeof(HANDLETABLE) * mh->mtNoObjects);
722
723     /* loop through metafile records */
724     offset = mh->mtHeaderSize * 2;
725
726     while (offset < (mh->mtSize * 2))
727     {
728         mr = (METARECORD *)((char *)mh + offset);
729         if(mr->rdFunction == META_EOF) {
730             TRACE("Got META_EOF so stopping\n");
731             break;
732         }
733         TRACE("Calling EnumFunc with record type %x\n",
734               mr->rdFunction);
735         if (!lpEnumFunc( hdc, ht, mr, mh->mtNoObjects, (LONG)lpData ))
736         {
737             result = FALSE;
738             break;
739         }
740
741         offset += (mr->rdSize * 2);
742     }
743
744     /* restore pen, brush and font */
745     SelectObject(hdc, hBrush);
746     SelectObject(hdc, hPen);
747     SelectObject(hdc, hFont);
748
749     /* free objects in handle table */
750     for(i = 0; i < mh->mtNoObjects; i++)
751       if(*(ht->objectHandle + i) != 0)
752         DeleteObject(*(ht->objectHandle + i));
753
754     /* free handle table */
755     HeapFree( GetProcessHeap(), 0, ht);
756     /* free a copy of metafile */
757     if (mhTemp) HeapFree( GetProcessHeap(), 0, mhTemp );
758     return result;
759 }
760
761 static BOOL MF_Play_MetaCreateRegion( METARECORD *mr, HRGN hrgn );
762 static BOOL MF_Play_MetaExtTextOut(HDC16 hdc, METARECORD *mr);
763 /******************************************************************
764  *             PlayMetaFileRecord   (GDI.176)
765  *
766  *   Render a single metafile record specified by *mr in the DC hdc, while
767  *   using the handle table *ht, of length nHandles,
768  *   to store metafile objects.
769  *
770  * BUGS
771  *  The following metafile records are unimplemented:
772  *
773  *  DRAWTEXT, ANIMATEPALETTE, SETPALENTRIES,
774  *  RESIZEPALETTE, EXTFLOODFILL, RESETDC, STARTDOC, STARTPAGE, ENDPAGE,
775  *  ABORTDOC, ENDDOC, CREATEBRUSH, CREATEBITMAPINDIRECT, and CREATEBITMAP.
776  *
777  */
778 void WINAPI PlayMetaFileRecord16(
779           HDC16 hdc,         /* [in] DC to render metafile into */
780           HANDLETABLE16 *ht, /* [in] pointer to handle table for metafile objects */
781           METARECORD *mr,    /* [in] pointer to metafile record to render */
782           UINT16 nHandles    /* [in] size of handle table */
783 ) {
784     short s1;
785     HANDLE16 hndl;
786     char *ptr;
787     BITMAPINFOHEADER *infohdr;
788
789     TRACE("(%04x %08lx %08lx %04x) function %04x\n",
790                  hdc,(LONG)ht, (LONG)mr, nHandles, mr->rdFunction);
791
792     switch (mr->rdFunction)
793     {
794     case META_EOF:
795         break;
796
797     case META_DELETEOBJECT:
798         DeleteObject(*(ht->objectHandle + *(mr->rdParm)));
799         *(ht->objectHandle + *(mr->rdParm)) = 0;
800         break;
801
802     case META_SETBKCOLOR:
803         SetBkColor16(hdc, MAKELONG(*(mr->rdParm), *(mr->rdParm + 1)));
804         break;
805
806     case META_SETBKMODE:
807         SetBkMode16(hdc, *(mr->rdParm));
808         break;
809
810     case META_SETMAPMODE:
811         SetMapMode16(hdc, *(mr->rdParm));
812         break;
813
814     case META_SETROP2:
815         SetROP216(hdc, *(mr->rdParm));
816         break;
817
818     case META_SETRELABS:
819         SetRelAbs16(hdc, *(mr->rdParm));
820         break;
821
822     case META_SETPOLYFILLMODE:
823         SetPolyFillMode16(hdc, *(mr->rdParm));
824         break;
825
826     case META_SETSTRETCHBLTMODE:
827         SetStretchBltMode16(hdc, *(mr->rdParm));
828         break;
829
830     case META_SETTEXTCOLOR:
831         SetTextColor16(hdc, MAKELONG(*(mr->rdParm), *(mr->rdParm + 1)));
832         break;
833
834     case META_SETWINDOWORG:
835         SetWindowOrg16(hdc, *(mr->rdParm + 1), *(mr->rdParm));
836         break;
837
838     case META_SETWINDOWEXT:
839         SetWindowExt16(hdc, *(mr->rdParm + 1), *(mr->rdParm));
840         break;
841
842     case META_SETVIEWPORTORG:
843         SetViewportOrg16(hdc, *(mr->rdParm + 1), *(mr->rdParm));
844         break;
845
846     case META_SETVIEWPORTEXT:
847         SetViewportExt16(hdc, *(mr->rdParm + 1), *(mr->rdParm));
848         break;
849
850     case META_OFFSETWINDOWORG:
851         OffsetWindowOrg16(hdc, *(mr->rdParm + 1), *(mr->rdParm));
852         break;
853
854     case META_SCALEWINDOWEXT:
855         ScaleWindowExt16(hdc, *(mr->rdParm + 3), *(mr->rdParm + 2),
856                        *(mr->rdParm + 1), *(mr->rdParm));
857         break;
858
859     case META_OFFSETVIEWPORTORG:
860         OffsetViewportOrg16(hdc, *(mr->rdParm + 1), *(mr->rdParm));
861         break;
862
863     case META_SCALEVIEWPORTEXT:
864         ScaleViewportExt16(hdc, *(mr->rdParm + 3), *(mr->rdParm + 2),
865                          *(mr->rdParm + 1), *(mr->rdParm));
866         break;
867
868     case META_LINETO:
869         LineTo(hdc, (INT16)*(mr->rdParm + 1), (INT16)*(mr->rdParm));
870         break;
871
872     case META_MOVETO:
873         MoveTo16(hdc, *(mr->rdParm + 1), *(mr->rdParm));
874         break;
875
876     case META_EXCLUDECLIPRECT:
877         ExcludeClipRect16( hdc, *(mr->rdParm + 3), *(mr->rdParm + 2),
878                            *(mr->rdParm + 1), *(mr->rdParm) );
879         break;
880
881     case META_INTERSECTCLIPRECT:
882         IntersectClipRect16( hdc, *(mr->rdParm + 3), *(mr->rdParm + 2),
883                              *(mr->rdParm + 1), *(mr->rdParm) );
884         break;
885
886     case META_ARC:
887         Arc(hdc, (INT16)*(mr->rdParm + 7), (INT16)*(mr->rdParm + 6),
888                  (INT16)*(mr->rdParm + 5), (INT16)*(mr->rdParm + 4),
889                  (INT16)*(mr->rdParm + 3), (INT16)*(mr->rdParm + 2),
890                  (INT16)*(mr->rdParm + 1), (INT16)*(mr->rdParm));
891         break;
892
893     case META_ELLIPSE:
894         Ellipse(hdc, (INT16)*(mr->rdParm + 3), (INT16)*(mr->rdParm + 2),
895                      (INT16)*(mr->rdParm + 1), (INT16)*(mr->rdParm));
896         break;
897
898     case META_FLOODFILL:
899         FloodFill(hdc, (INT16)*(mr->rdParm + 3), (INT16)*(mr->rdParm + 2),
900                     MAKELONG(*(mr->rdParm), *(mr->rdParm + 1)));
901         break;
902
903     case META_PIE:
904         Pie(hdc, (INT16)*(mr->rdParm + 7), (INT16)*(mr->rdParm + 6),
905                  (INT16)*(mr->rdParm + 5), (INT16)*(mr->rdParm + 4),
906                  (INT16)*(mr->rdParm + 3), (INT16)*(mr->rdParm + 2),
907                  (INT16)*(mr->rdParm + 1), (INT16)*(mr->rdParm));
908         break;
909
910     case META_RECTANGLE:
911         Rectangle(hdc, (INT16)*(mr->rdParm + 3), (INT16)*(mr->rdParm + 2),
912                        (INT16)*(mr->rdParm + 1), (INT16)*(mr->rdParm));
913         break;
914
915     case META_ROUNDRECT:
916         RoundRect(hdc, (INT16)*(mr->rdParm + 5), (INT16)*(mr->rdParm + 4),
917                        (INT16)*(mr->rdParm + 3), (INT16)*(mr->rdParm + 2),
918                        (INT16)*(mr->rdParm + 1), (INT16)*(mr->rdParm));
919         break;
920
921     case META_PATBLT:
922         PatBlt16(hdc, *(mr->rdParm + 5), *(mr->rdParm + 4),
923                  *(mr->rdParm + 3), *(mr->rdParm + 2),
924                  MAKELONG(*(mr->rdParm), *(mr->rdParm + 1)));
925         break;
926
927     case META_SAVEDC:
928         SaveDC(hdc);
929         break;
930
931     case META_SETPIXEL:
932         SetPixel(hdc, (INT16)*(mr->rdParm + 3), (INT16)*(mr->rdParm + 2),
933                    MAKELONG(*(mr->rdParm), *(mr->rdParm + 1)));
934         break;
935
936     case META_OFFSETCLIPRGN:
937         OffsetClipRgn16( hdc, *(mr->rdParm + 1), *(mr->rdParm) );
938         break;
939
940     case META_TEXTOUT:
941         s1 = *(mr->rdParm);
942         TextOut16(hdc, *(mr->rdParm + ((s1 + 1) >> 1) + 2),
943                   *(mr->rdParm + ((s1 + 1) >> 1) + 1),
944                   (char *)(mr->rdParm + 1), s1);
945         break;
946
947     case META_POLYGON:
948         Polygon16(hdc, (LPPOINT16)(mr->rdParm + 1), *(mr->rdParm));
949         break;
950
951     case META_POLYPOLYGON:
952       PolyPolygon16(hdc, (LPPOINT16)(mr->rdParm + *(mr->rdParm) + 1),
953                     (LPINT16)(mr->rdParm + 1), *(mr->rdParm));
954       break;
955
956     case META_POLYLINE:
957         Polyline16(hdc, (LPPOINT16)(mr->rdParm + 1), *(mr->rdParm));
958         break;
959
960     case META_RESTOREDC:
961         RestoreDC(hdc, (INT16)*(mr->rdParm));
962         break;
963
964     case META_SELECTOBJECT:
965         SelectObject(hdc, *(ht->objectHandle + *(mr->rdParm)));
966         break;
967
968     case META_CHORD:
969         Chord(hdc, (INT16)*(mr->rdParm + 7), (INT16)*(mr->rdParm + 6),
970                    (INT16)*(mr->rdParm + 5), (INT16)*(mr->rdParm + 4),
971                    (INT16)*(mr->rdParm + 3), (INT16)*(mr->rdParm + 2),
972                    (INT16)*(mr->rdParm + 1), (INT16)*(mr->rdParm));
973         break;
974
975     case META_CREATEPATTERNBRUSH:
976         switch (*(mr->rdParm))
977         {
978         case BS_PATTERN:
979             infohdr = (BITMAPINFOHEADER *)(mr->rdParm + 2);
980             MF_AddHandle(ht, nHandles,
981                          CreatePatternBrush(CreateBitmap(infohdr->biWidth,
982                                       infohdr->biHeight,
983                                       infohdr->biPlanes,
984                                       infohdr->biBitCount,
985                                       (LPSTR)(mr->rdParm +
986                                       (sizeof(BITMAPINFOHEADER) / 2) + 4))));
987             break;
988
989         case BS_DIBPATTERN:
990             s1 = mr->rdSize * 2 - sizeof(METARECORD) - 2;
991             hndl = GlobalAlloc16(GMEM_MOVEABLE, s1);
992             ptr = GlobalLock16(hndl);
993             memcpy(ptr, mr->rdParm + 2, s1);
994             GlobalUnlock16(hndl);
995             MF_AddHandle(ht, nHandles,
996                          CreateDIBPatternBrush(hndl, *(mr->rdParm + 1)));
997             GlobalFree16(hndl);
998             break;
999
1000         default:
1001             ERR("META_CREATEPATTERNBRUSH: Unknown pattern type %d\n",
1002                 mr->rdParm[0]);
1003             break;
1004         }
1005         break;
1006
1007     case META_CREATEPENINDIRECT:
1008         MF_AddHandle(ht, nHandles,
1009                      CreatePenIndirect16((LOGPEN16 *)(&(mr->rdParm))));
1010         break;
1011
1012     case META_CREATEFONTINDIRECT:
1013         MF_AddHandle(ht, nHandles,
1014                      CreateFontIndirect16((LOGFONT16 *)(&(mr->rdParm))));
1015         break;
1016
1017     case META_CREATEBRUSHINDIRECT:
1018         MF_AddHandle(ht, nHandles,
1019                      CreateBrushIndirect16((LOGBRUSH16 *)(&(mr->rdParm))));
1020         break;
1021
1022     case META_CREATEPALETTE:
1023         MF_AddHandle(ht, nHandles,
1024                      CreatePalette16((LPLOGPALETTE)mr->rdParm));
1025         break;
1026
1027     case META_SETTEXTALIGN:
1028         SetTextAlign16(hdc, *(mr->rdParm));
1029         break;
1030
1031     case META_SELECTPALETTE:
1032         GDISelectPalette16(hdc, *(ht->objectHandle + *(mr->rdParm+1)),
1033                         *(mr->rdParm));
1034         break;
1035
1036     case META_SETMAPPERFLAGS:
1037         SetMapperFlags16(hdc, MAKELONG(mr->rdParm[0],mr->rdParm[1]));
1038         break;
1039
1040     case META_REALIZEPALETTE:
1041         GDIRealizePalette16(hdc);
1042         break;
1043
1044     case META_ESCAPE:
1045         FIXME("META_ESCAPE unimplemented.\n");
1046         break;
1047
1048     case META_EXTTEXTOUT:
1049         MF_Play_MetaExtTextOut( hdc, mr );
1050         break;
1051
1052     case META_STRETCHDIB:
1053       {
1054         LPBITMAPINFO info = (LPBITMAPINFO) &(mr->rdParm[11]);
1055         LPSTR bits = (LPSTR)info + DIB_BitmapInfoSize( info, mr->rdParm[2] );
1056         StretchDIBits16(hdc,mr->rdParm[10],mr->rdParm[9],mr->rdParm[8],
1057                        mr->rdParm[7],mr->rdParm[6],mr->rdParm[5],
1058                        mr->rdParm[4],mr->rdParm[3],bits,info,
1059                        mr->rdParm[2],MAKELONG(mr->rdParm[0],mr->rdParm[1]));
1060       }
1061       break;
1062
1063     case META_DIBSTRETCHBLT:
1064       {
1065         LPBITMAPINFO info = (LPBITMAPINFO) &(mr->rdParm[10]);
1066         LPSTR bits = (LPSTR)info + DIB_BitmapInfoSize( info, mr->rdParm[2] );
1067         StretchDIBits16(hdc,mr->rdParm[9],mr->rdParm[8],mr->rdParm[7],
1068                        mr->rdParm[6],mr->rdParm[5],mr->rdParm[4],
1069                        mr->rdParm[3],mr->rdParm[2],bits,info,
1070                        DIB_RGB_COLORS,MAKELONG(mr->rdParm[0],mr->rdParm[1]));
1071       }
1072       break;
1073
1074     case META_STRETCHBLT:
1075       {
1076         HDC16 hdcSrc=CreateCompatibleDC16(hdc);
1077         HBITMAP hbitmap=CreateBitmap(mr->rdParm[10], /*Width */
1078                                         mr->rdParm[11], /*Height*/
1079                                         mr->rdParm[13], /*Planes*/
1080                                         mr->rdParm[14], /*BitsPixel*/
1081                                         (LPSTR)&mr->rdParm[15]);  /*bits*/
1082         SelectObject(hdcSrc,hbitmap);
1083         StretchBlt16(hdc,mr->rdParm[9],mr->rdParm[8],
1084                     mr->rdParm[7],mr->rdParm[6],
1085                     hdcSrc,mr->rdParm[5],mr->rdParm[4],
1086                     mr->rdParm[3],mr->rdParm[2],
1087                     MAKELONG(mr->rdParm[0],mr->rdParm[1]));
1088         DeleteDC(hdcSrc);
1089       }
1090       break;
1091
1092     case META_BITBLT:
1093       {
1094         HDC16 hdcSrc=CreateCompatibleDC16(hdc);
1095         HBITMAP hbitmap=CreateBitmap(mr->rdParm[7]/*Width */,
1096                                         mr->rdParm[8]/*Height*/,
1097                                         mr->rdParm[10]/*Planes*/,
1098                                         mr->rdParm[11]/*BitsPixel*/,
1099                                         (LPSTR)&mr->rdParm[12]/*bits*/);
1100         SelectObject(hdcSrc,hbitmap);
1101         BitBlt(hdc,(INT16)mr->rdParm[6],(INT16)mr->rdParm[5],
1102                 (INT16)mr->rdParm[4],(INT16)mr->rdParm[3],
1103                 hdcSrc, (INT16)mr->rdParm[2],(INT16)mr->rdParm[1],
1104                 MAKELONG(0,mr->rdParm[0]));
1105         DeleteDC(hdcSrc);
1106       }
1107       break;
1108
1109     case META_CREATEREGION:
1110       {
1111         HRGN hrgn = CreateRectRgn(0,0,0,0);
1112
1113         MF_Play_MetaCreateRegion(mr, hrgn);
1114         MF_AddHandle(ht, nHandles, hrgn);
1115       }
1116       break;
1117
1118     case META_FILLREGION:
1119         FillRgn16(hdc, *(ht->objectHandle + *(mr->rdParm+1)),
1120                        *(ht->objectHandle + *(mr->rdParm)));
1121         break;
1122
1123     case META_FRAMEREGION:
1124         FrameRgn16(hdc, *(ht->objectHandle + *(mr->rdParm+3)),
1125                         *(ht->objectHandle + *(mr->rdParm+2)),
1126                         *(mr->rdParm+1), *(mr->rdParm));
1127         break;
1128
1129     case META_INVERTREGION:
1130         InvertRgn16(hdc, *(ht->objectHandle + *(mr->rdParm)));
1131         break;
1132
1133     case META_PAINTREGION:
1134         PaintRgn16(hdc, *(ht->objectHandle + *(mr->rdParm)));
1135         break;
1136
1137     case META_SELECTCLIPREGION:
1138         SelectClipRgn(hdc, *(ht->objectHandle + *(mr->rdParm)));
1139         break;
1140
1141     case META_DIBCREATEPATTERNBRUSH:
1142         /*  *(mr->rdParm) may be BS_PATTERN or BS_DIBPATTERN:
1143             but there's no difference */
1144
1145         TRACE("%d\n",*(mr->rdParm));
1146         s1 = mr->rdSize * 2 - sizeof(METARECORD) - 2;
1147         hndl = GlobalAlloc16(GMEM_MOVEABLE, s1);
1148         ptr = GlobalLock16(hndl);
1149         memcpy(ptr, mr->rdParm + 2, s1);
1150         GlobalUnlock16(hndl);
1151         MF_AddHandle(ht, nHandles,
1152                      CreateDIBPatternBrush16(hndl, *(mr->rdParm + 1)));
1153         GlobalFree16(hndl);
1154         break;
1155
1156     case META_DIBBITBLT:
1157       /* In practice I've found that there are two layouts for
1158          META_DIBBITBLT, one (the first here) is the usual one when a src
1159          dc is actually passed to it, the second occurs when the src dc is
1160          passed in as NULL to the creating BitBlt. As the second case has
1161          no dib, a size check will suffice to distinguish.
1162
1163          Caolan.McNamara@ul.ie */
1164
1165         if (mr->rdSize > 12) {
1166             LPBITMAPINFO info = (LPBITMAPINFO) &(mr->rdParm[8]);
1167             LPSTR bits = (LPSTR)info + DIB_BitmapInfoSize(info, mr->rdParm[0]);
1168
1169             StretchDIBits16(hdc, mr->rdParm[7], mr->rdParm[6], mr->rdParm[5],
1170                                  mr->rdParm[4], mr->rdParm[3], mr->rdParm[2],
1171                                  mr->rdParm[5], mr->rdParm[4], bits, info,
1172                                  DIB_RGB_COLORS,
1173                                  MAKELONG(mr->rdParm[0], mr->rdParm[1]));
1174         } else { /* equivalent to a PatBlt */
1175             PatBlt16(hdc, mr->rdParm[8], mr->rdParm[7],
1176                           mr->rdParm[6], mr->rdParm[5],
1177                           MAKELONG(mr->rdParm[0], mr->rdParm[1]));
1178         }
1179         break;
1180
1181     case META_SETTEXTCHAREXTRA:
1182         SetTextCharacterExtra16(hdc, (INT16)*(mr->rdParm));
1183         break;
1184
1185     case META_SETTEXTJUSTIFICATION:
1186         SetTextJustification(hdc, *(mr->rdParm + 1), *(mr->rdParm));
1187         break;
1188
1189     case META_EXTFLOODFILL:
1190         ExtFloodFill(hdc, (INT16)*(mr->rdParm + 4), (INT16)*(mr->rdParm + 3),
1191                      MAKELONG(*(mr->rdParm+1), *(mr->rdParm + 2)),
1192                      *(mr->rdParm));
1193         break;
1194
1195     case META_SETDIBTODEV:
1196       {
1197         BITMAPINFO *info = (BITMAPINFO *) &(mr->rdParm[9]);
1198         char *bits = (char *)info + DIB_BitmapInfoSize( info, mr->rdParm[0] );
1199         SetDIBitsToDevice(hdc, (INT16)mr->rdParm[8], (INT16)mr->rdParm[7],
1200                           (INT16)mr->rdParm[6], (INT16)mr->rdParm[5],
1201                           (INT16)mr->rdParm[4], (INT16)mr->rdParm[3],
1202                           mr->rdParm[2], mr->rdParm[1], bits, info,
1203                           mr->rdParm[0]);
1204         break;
1205       }
1206
1207 #define META_UNIMP(x) case x: \
1208 FIXME("PlayMetaFileRecord:record type "#x" not implemented.\n"); \
1209 break;
1210     META_UNIMP(META_DRAWTEXT)
1211     META_UNIMP(META_ANIMATEPALETTE)
1212     META_UNIMP(META_SETPALENTRIES)
1213     META_UNIMP(META_RESIZEPALETTE)
1214     META_UNIMP(META_RESETDC)
1215     META_UNIMP(META_STARTDOC)
1216     META_UNIMP(META_STARTPAGE)
1217     META_UNIMP(META_ENDPAGE)
1218     META_UNIMP(META_ABORTDOC)
1219     META_UNIMP(META_ENDDOC)
1220     META_UNIMP(META_CREATEBRUSH)
1221     META_UNIMP(META_CREATEBITMAPINDIRECT)
1222     META_UNIMP(META_CREATEBITMAP)
1223 #undef META_UNIMP
1224
1225     default:
1226         WARN("PlayMetaFileRecord: Unknown record type %x\n",
1227                                               mr->rdFunction);
1228     }
1229 }
1230
1231 /******************************************************************
1232  *         PlayMetaFileRecord   (GDI32.@)
1233  */
1234 BOOL WINAPI PlayMetaFileRecord( HDC hdc,  HANDLETABLE *handletable,
1235                                 METARECORD *metarecord, UINT handles )
1236 {
1237     HANDLETABLE16 * ht = (void *)GlobalAlloc(GPTR,
1238                                              handles*sizeof(HANDLETABLE16));
1239     unsigned int i = 0;
1240     TRACE("(%08x,%p,%p,%d)\n", hdc, handletable, metarecord,
1241           handles);
1242     for (i=0; i<handles; i++)
1243         ht->objectHandle[i] =  handletable->objectHandle[i];
1244     PlayMetaFileRecord16(hdc, ht, metarecord, handles);
1245     for (i=0; i<handles; i++)
1246         handletable->objectHandle[i] = ht->objectHandle[i];
1247     GlobalFree((HGLOBAL)ht);
1248     return TRUE;
1249 }
1250
1251 /******************************************************************
1252  *         GetMetaFileBits   (GDI.159)
1253  *
1254  * Trade in a metafile object handle for a handle to the metafile memory.
1255  *
1256  */
1257
1258 HGLOBAL16 WINAPI GetMetaFileBits16(
1259                                  HMETAFILE16 hmf /* [in] metafile handle */
1260                                  )
1261 {
1262     TRACE("hMem out: %04x\n", hmf);
1263     return hmf;
1264 }
1265
1266 /******************************************************************
1267  *         SetMetaFileBits   (GDI.160)
1268  *
1269  * Trade in a metafile memory handle for a handle to a metafile object.
1270  * The memory region should hold a proper metafile, otherwise
1271  * problems will occur when it is used. Validity of the memory is not
1272  * checked. The function is essentially just the identity function.
1273  */
1274 HMETAFILE16 WINAPI SetMetaFileBits16(
1275                                    HGLOBAL16 hMem
1276                         /* [in] handle to a memory region holding a metafile */
1277 )
1278 {
1279     TRACE("hmf out: %04x\n", hMem);
1280
1281     return hMem;
1282 }
1283
1284 /******************************************************************
1285  *         SetMetaFileBitsBetter   (GDI.196)
1286  *
1287  * Trade in a metafile memory handle for a handle to a metafile object,
1288  * making a cursory check (using IsValidMetaFile()) that the memory
1289  * handle points to a valid metafile.
1290  *
1291  * RETURNS
1292  *  Handle to a metafile on success, NULL on failure..
1293  */
1294 HMETAFILE16 WINAPI SetMetaFileBitsBetter16( HMETAFILE16 hMeta )
1295 {
1296     if( IsValidMetaFile16( hMeta ) )
1297         return (HMETAFILE16)GlobalReAlloc16( hMeta, 0,
1298                            GMEM_SHARE | GMEM_NODISCARD | GMEM_MODIFY);
1299     return (HMETAFILE16)0;
1300 }
1301
1302 /******************************************************************
1303  *         SetMetaFileBitsEx    (GDI32.@)
1304  *
1305  *  Create a metafile from raw data. No checking of the data is performed.
1306  *  Use _GetMetaFileBitsEx_ to get raw data from a metafile.
1307  */
1308 HMETAFILE WINAPI SetMetaFileBitsEx(
1309      UINT size,         /* [in] size of metafile, in bytes */
1310      const BYTE *lpData /* [in] pointer to metafile data */
1311     )
1312 {
1313     METAHEADER *mh = HeapAlloc( GetProcessHeap(), 0, size );
1314     if (!mh) return 0;
1315     memcpy(mh, lpData, size);
1316     return MF_Create_HMETAFILE(mh);
1317 }
1318
1319 /*****************************************************************
1320  *  GetMetaFileBitsEx     (GDI32.@)  Get raw metafile data
1321  *
1322  *  Copies the data from metafile _hmf_ into the buffer _buf_.
1323  *  If _buf_ is zero, returns size of buffer required. Otherwise,
1324  *  returns number of bytes copied.
1325  */
1326 UINT WINAPI GetMetaFileBitsEx(
1327      HMETAFILE hmf, /* [in] metafile */
1328      UINT nSize,    /* [in] size of buf */
1329      LPVOID buf     /* [out] buffer to receive raw metafile data */
1330 ) {
1331     METAHEADER *mh = MF_GetMetaHeader(hmf);
1332     UINT mfSize;
1333
1334     TRACE("(%08x,%d,%p)\n", hmf, nSize, buf);
1335     if (!mh) return 0;  /* FIXME: error code */
1336     if(mh->mtType == METAFILE_DISK)
1337         FIXME("Disk-based metafile?\n");
1338     mfSize = mh->mtSize * 2;
1339     if (!buf) {
1340         TRACE("returning size %d\n", mfSize);
1341         return mfSize;
1342     }
1343     if(mfSize > nSize) mfSize = nSize;
1344     memmove(buf, mh, mfSize);
1345     return mfSize;
1346 }
1347
1348 /******************************************************************
1349  *         GetWinMetaFileBits [GDI32.@]
1350  */
1351 UINT WINAPI GetWinMetaFileBits(HENHMETAFILE hemf,
1352                                 UINT cbBuffer, LPBYTE lpbBuffer,
1353                                 INT fnMapMode, HDC hdcRef)
1354 {
1355     FIXME("(%d,%d,%p,%d,%d): stub\n",
1356           hemf, cbBuffer, lpbBuffer, fnMapMode, hdcRef);
1357     return 0;
1358 }
1359
1360 /******************************************************************
1361  *         MF_Play_MetaCreateRegion
1362  *
1363  *  Handles META_CREATEREGION for PlayMetaFileRecord().
1364  */
1365
1366 /*
1367  *      The layout of the record looks something like this:
1368  *
1369  *       rdParm meaning
1370  *       0              Always 0?
1371  *       1              Always 6?
1372  *       2              Looks like a handle? - not constant
1373  *       3              0 or 1 ??
1374  *       4              Total number of bytes
1375  *       5              No. of separate bands = n [see below]
1376  *       6              Largest number of x co-ords in a band
1377  *       7-10           Bounding box x1 y1 x2 y2
1378  *       11-...         n bands
1379  *
1380  *       Regions are divided into bands that are uniform in the
1381  *       y-direction. Each band consists of pairs of on/off x-coords and is
1382  *       written as
1383  *              m y0 y1 x1 x2 x3 ... xm m
1384  *       into successive rdParm[]s.
1385  *
1386  *       This is probably just a dump of the internal RGNOBJ?
1387  *
1388  *       HDMD - 18/12/97
1389  *
1390  */
1391
1392 static BOOL MF_Play_MetaCreateRegion( METARECORD *mr, HRGN hrgn )
1393 {
1394     WORD band, pair;
1395     WORD *start, *end;
1396     INT16 y0, y1;
1397     HRGN hrgn2 = CreateRectRgn( 0, 0, 0, 0 );
1398
1399     for(band  = 0, start = &(mr->rdParm[11]); band < mr->rdParm[5];
1400                                                 band++, start = end + 1) {
1401         if(*start / 2 != (*start + 1) / 2) {
1402             WARN("Delimiter not even.\n");
1403             DeleteObject( hrgn2 );
1404             return FALSE;
1405         }
1406
1407         end = start + *start + 3;
1408         if(end > (WORD *)mr + mr->rdSize) {
1409             WARN("End points outside record.\n");
1410             DeleteObject( hrgn2 );
1411             return FALSE;
1412         }
1413
1414         if(*start != *end) {
1415             WARN("Mismatched delimiters.\n");
1416             DeleteObject( hrgn2 );
1417             return FALSE;
1418         }
1419
1420         y0 = *(INT16 *)(start + 1);
1421         y1 = *(INT16 *)(start + 2);
1422         for(pair = 0; pair < *start / 2; pair++) {
1423             SetRectRgn( hrgn2, *(INT16 *)(start + 3 + 2*pair), y0,
1424                                  *(INT16 *)(start + 4 + 2*pair), y1 );
1425             CombineRgn(hrgn, hrgn, hrgn2, RGN_OR);
1426         }
1427     }
1428     DeleteObject( hrgn2 );
1429     return TRUE;
1430  }
1431
1432
1433 /******************************************************************
1434  *         MF_Play_MetaExtTextOut
1435  *
1436  *  Handles META_EXTTEXTOUT for PlayMetaFileRecord().
1437  */
1438
1439 static BOOL MF_Play_MetaExtTextOut(HDC16 hdc, METARECORD *mr)
1440 {
1441     LPINT16 dxx;
1442     LPSTR sot;
1443     DWORD len;
1444     WORD s1;
1445
1446     s1 = mr->rdParm[2];                              /* String length */
1447     len = sizeof(METARECORD) + (((s1 + 1) >> 1) * 2) + 2 * sizeof(short)
1448       + sizeof(UINT16) +  (mr->rdParm[3] ? sizeof(RECT16) : 0);
1449                                            /* rec len without dx array */
1450
1451     sot = (LPSTR)&mr->rdParm[4];                      /* start_of_text */
1452     if (mr->rdParm[3])
1453         sot += sizeof(RECT16);  /* there is a rectangle, so add offset */
1454
1455     if (mr->rdSize == len / 2)
1456         dxx = NULL;                      /* determine if array present */
1457     else
1458         if (mr->rdSize == (len + s1 * sizeof(INT16)) / 2)
1459             dxx = (LPINT16)(sot+(((s1+1)>>1)*2));
1460         else {
1461             TRACE("%s  len: %ld\n",  sot, mr->rdSize);
1462             WARN(
1463              "Please report: ExtTextOut len=%ld slen=%d rdSize=%ld opt=%04x\n",
1464                  len, s1, mr->rdSize, mr->rdParm[3]);
1465             dxx = NULL; /* should't happen -- but if, we continue with NULL */
1466         }
1467     ExtTextOut16( hdc, mr->rdParm[1],              /* X position */
1468                        mr->rdParm[0],              /* Y position */
1469                        mr->rdParm[3],              /* options */
1470                        mr->rdParm[3] ? (LPRECT16) &mr->rdParm[4]:NULL,
1471                                                    /* rectangle */
1472                        sot,                            /* string */
1473                        s1, dxx);                   /* length, dx array */
1474     if (dxx)
1475         TRACE("%s  len: %ld  dx0: %d\n", sot, mr->rdSize, dxx[0]);
1476     return TRUE;
1477 }