1 /* libwmf (player.c): library for wmf conversion
2    Copyright (C) 2000,2001 - various; see CREDITS, ChangeLog, and sources
3 
4    The libwmf Library is free software; you can redistribute it and/or
5    modify it under the terms of the GNU Library General Public License as
6    published by the Free Software Foundation; either version 2 of the
7    License, or (at your option) any later version.
8 
9    The libwmf Library is distributed in the hope that it will be useful,
10    but WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12    Library General Public License for more details.
13 
14    You should have received a copy of the GNU Library General Public
15    License along with the libwmf Library; see the file COPYING.  If not,
16    write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17    Boston, MA 02111-1307, USA.  */
18 
19 
20 #ifdef HAVE_CONFIG_H
21 #include "wmfconfig.h"
22 #endif
23 
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <math.h>
28 
29 #ifdef HAVE_UNISTD_H
30 #include <unistd.h>
31 #endif
32 
33 #include "wmfdefs.h"
34 #include "metadefs.h"
35 
36 #include "player.h"
37 #include "player/region.h"   /* Provides: REGION manipulation functions  */
38 #include "player/clip.h"     /* Provides: clip function                  */
39 #include "player/color.h"    /* Provides: color stuff                    */
40 #include "player/coord.h"    /* Provides: coordinate translations        */
41 #include "player/dc.h"       /* Provides: dc stack & other dc functions  */
42 #include "player/defaults.h" /* Provides: default settings               */
43 #include "player/record.h"   /* Provides: parameter mechanism            */
44 #include "player/meta.h"     /* Provides: record interpreters            */
45 #include <stdint.h>
46 
47 /**
48  * @internal
49  */
wmf_player_init(wmfAPI * API)50 wmf_error_t wmf_player_init (wmfAPI* API)
51 {	wmfPlayer_t* P = 0;
52 
53 	WMF_DEBUG (API,"~~~~~~~~wmf_player_init");
54 
55 	API->player_data = wmf_malloc (API,sizeof (wmfPlayer_t));
56 
57 	if (ERR (API))
58 	{	WMF_DEBUG (API,"bailing...");
59 		return (API->err);
60 	}
61 
62 	P = (wmfPlayer_t*) API->player_data;
63 
64 	P->flags = 0;
65 
66 	return (API->err);
67 }
68 
69 /**
70  * Scan the metafile.
71  *
72  * @param API   the API handle
73  * @param flags (unused)
74  * @param d_r   for bounding-box return
75  *
76  * Before the metafile can be played, it must be scanned. This is because metafile headers do not always
77  * provide image size information. Although the device layer (the graphics exporter) is initialized in
78  * wmf_api_create(), the output device is not opened until after the metafile is scanned. By scanning,
79  * therefore, the device layer can be provided on opening not only with size information but also a list
80  * of colors to expect (not including those in raster images) and of other required resources, if necessary.
81  * Finally, if scanning fails, then there's certainly no point in playing the metafile.
82  *
83  * The bounding box, in device coordinates, is returned in \p *d_r.
84  *
85  * @return Returns the library error state (\b wmf_E_None on success).
86  */
wmf_scan(wmfAPI * API,unsigned long flags,wmfD_Rect * d_r)87 wmf_error_t wmf_scan (wmfAPI* API,unsigned long flags,wmfD_Rect* d_r)
88 {	(void)flags;
89 	wmfPlayer_t* P  = (wmfPlayer_t*) API->player_data;
90 
91 	WMF_DEBUG (API,"~~~~~~~~wmf_scan");
92 
93 	if (ERR (API))
94 	{	WMF_DEBUG (API,"bailing...");
95 		return (API->err);
96 	}
97 
98 /* wmf_scan doesn't allow re-scanning, but I suppose there may be a case
99  * implementing a rescan function (or WMF_RESCAN flag?) at some point ??
100  */
101 	if (P->flags & PLAYER_SCANNED)
102 	{	WMF_DEBUG (API,"already scanned; skipping...");
103 		return (API->err);
104 	}
105 
106 	P->dc_stack_maxlen = 0;
107 	P->dc_stack = 0;
108 
109 	P->objects = 0;
110 
111 	P->D_TL.x = 0;
112 	P->D_TL.y = 0;
113 	P->D_BR.x = 0;
114 	P->D_BR.y = 0;
115 
116 	d_r->TL = P->D_TL;
117 	d_r->BR = P->D_BR;
118 
119 	P->flags &= ~PLAYER_PLAY; /* Set scan mode */
120 
121 	wmf_header_read (API);
122 
123 	if (ERR (API))
124 	{	WMF_DEBUG (API,"bailing...");
125 		return (API->err);
126 	}
127 
128 	if (API->File->wmfheader->NumOfObjects > 0)
129 	{	P->objects = (wmfObject*) wmf_malloc (API,NUM_OBJECTS (API) * sizeof (wmfObject));
130 
131 		if (ERR (API))
132 		{	WMF_DEBUG (API,"bailing...");
133 			return (API->err);
134 		}
135 	}
136 
137 	if (MAX_REC_SIZE(API) > UINT32_MAX / 2)
138 	{
139 		API->err = wmf_E_InsMem;
140 		WMF_DEBUG (API,"bailing...");
141 		return (API->err);
142 	}
143 
144 	U32 nMaxRecordSize = (MAX_REC_SIZE(API)  ) * 2 * sizeof (unsigned char);
145 	if (nMaxRecordSize)
146 	{
147 		//before allocating memory do a sanity check on size by seeking
148 		//to claimed end to see if its possible. We're constrained here
149 		//by the api and existing implementations to not simply seeking
150 		//to SEEK_END. So use what we have to skip to the last byte and
151 		//try and read it.
152 		const long nPos = WMF_TELL (API);
153 		WMF_SEEK (API, nPos + nMaxRecordSize - 1);
154 		if (ERR (API))
155 		{	WMF_DEBUG (API,"bailing...");
156 			return (API->err);
157 		}
158 		int byte = WMF_READ (API);
159 		if (byte == (-1))
160 		{	WMF_ERROR (API,"Unexpected EOF!");
161 		       	API->err = wmf_E_EOF;
162 		       	return (API->err);
163 		}
164 		WMF_SEEK (API, nPos);
165 	}
166 
167  	P->Parameters = (unsigned char*) wmf_malloc (API, nMaxRecordSize);
168 
169 	if (ERR (API))
170 	{	WMF_DEBUG (API,"bailing...");
171 		return (API->err);
172 	}
173 
174 	WmfPlayMetaFile (API);
175 
176 	if (ERR (API))
177 	{	WMF_DEBUG (API,"bailing...");
178 		return (API->err);
179 	}
180 
181 	d_r->TL = P->D_TL;
182 	d_r->BR = P->D_BR;
183 
184 	P->flags |= PLAYER_SCANNED;
185 
186 	return (API->err);
187 }
188 
189 /**
190  * Get image size.
191  *
192  * @param API    the API handle
193  * @param width  width return
194  * @param height height return
195  *
196  * wmf_size() returns image width in \p *width and image height in \p *height. If supplied, the metafile
197  * header values are used, otherwise the width and height found by wmf_scan() are used.
198  *
199  * @return Returns the library error state (\b wmf_E_None on success).
200  *         Possible library error state of \b wmf_E_Glitch (the metafile has not been scanned).
201  */
wmf_size(wmfAPI * API,float * width,float * height)202 wmf_error_t wmf_size (wmfAPI* API,float* width,float* height)
203 {	wmfPlayer_t* P  = (wmfPlayer_t*) API->player_data;
204 
205 	S16 default_width;
206 	S16 default_height;
207 
208 	WMF_DEBUG (API,"~~~~~~~~wmf_size");
209 
210 	if (ERR (API))
211 	{	WMF_DEBUG (API,"bailing...");
212 		return (API->err);
213 	}
214 
215 	if ((P->flags & PLAYER_SCANNED) == 0)
216 	{	WMF_ERROR (API,"attempt to determine size of unscanned metafile!");
217 		API->err = wmf_E_Glitch;
218 		return (API->err);
219 	}
220 
221 	default_width  = WMF_BBOX_RIGHT (API) - WMF_BBOX_LEFT (API);
222 	default_height = WMF_BBOX_TOP (API) - WMF_BBOX_BOTTOM (API);
223 
224 	default_width  = ABS (default_width );
225 	default_height = ABS (default_height);
226 
227 	if (default_width && default_height)
228 	{	(*width)  = (float) default_width;
229 		(*height) = (float) default_height;
230 	}
231 	else
232 	{	(*width)  = P->D_BR.x - P->D_TL.x;
233 		(*height) = P->D_BR.y - P->D_TL.y;
234 	}
235 
236 	return (API->err);
237 }
238 
239 /**
240  * Get estimate of image display size.
241  *
242  * @param API    the API handle
243  * @param width  width return
244  * @param height height return
245  * @param res_x  x-resolution of display
246  * @param res_y  y-resolution of display
247  *
248  * wmf_display_size() returns image width in \p *width and image height in \p *height.
249  * wmf_size() is used to get the calculated/estimate width and height of the image,
250  * and these values are converted to integer width and height estimates for display.
251  *
252  * @return Returns the library error state (\b wmf_E_None on success).
253  *         Possible library error state of \b wmf_E_Glitch (the metafile has not been scanned).
254  */
wmf_display_size(wmfAPI * API,unsigned int * width,unsigned int * height,double res_x,double res_y)255 wmf_error_t wmf_display_size (wmfAPI* API,unsigned int* width,unsigned int* height,
256 			      double res_x,double res_y)
257 {	unsigned int units_per_inch = 1440;
258 
259 	double disp_width;
260 	double disp_height;
261 
262 	float est_width;
263 	float est_height;
264 
265 	WMF_DEBUG (API,"~~~~~~~~wmf_display_size");
266 
267 	if (ERR (API))
268 	{	WMF_DEBUG (API,"bailing...");
269 		return (API->err);
270 	}
271 
272 	wmf_size (API, &est_width, &est_height);
273 
274 	if (ERR (API))
275 	{	WMF_DEBUG (API,"bailing...");
276 		return (API->err);
277 	}
278 
279 	if (PLACEABLE (API))
280 	{	units_per_inch = DPI (API);
281 	}
282 	else if ((est_width * est_height) < (1024 * 1024))
283 	{	units_per_inch = 72;
284 	}
285 
286 	disp_width  = ((double) est_width ) * res_x / (double) units_per_inch;
287 	disp_height = ((double) est_height) * res_y / (double) units_per_inch;
288 
289 	if (width)  *width  = (unsigned int) disp_width;
290 	if (height) *height = (unsigned int) disp_height;
291 
292 	return API->err;
293 }
294 
295 /**
296  * Play the metafile.
297  *
298  * @param API   the API handle
299  * @param flags (unused)
300  * @param d_r   for bounding-box return
301  *
302  * Before the metafile can be played, it must be scanned - see wmf_scan().
303  *
304  * The first time (and only the first time) the metafile is played, it first calls \b device_open() for the
305  * device layer specified (and initialized) in wmf_api_create(). Then, and also each subsequent time the
306  * metafile is played, it calls \b device_begin(), plays the metafile (with calls to various other device
307  * layer functions), and finally it calls \b device_end(). \b device_close() is only ever called via
308  * wmf_api_destroy().
309  *
310  * \p d_r is recomputed, but should not change.
311  *
312  * @return Returns the library error state (\b wmf_E_None on success).
313  */
wmf_play(wmfAPI * API,unsigned long flags,wmfD_Rect * d_r)314 wmf_error_t wmf_play (wmfAPI* API,unsigned long flags,wmfD_Rect* d_r)
315 {	(void)flags;
316 	wmfPlayer_t*          P  = (wmfPlayer_t*)          API->player_data;
317 	wmfFunctionReference* FR = (wmfFunctionReference*) API->function_reference;
318 
319 	WMF_DEBUG (API,"~~~~~~~~wmf_play");
320 
321 	if (ERR (API))
322 	{	WMF_DEBUG (API,"bailing...");
323 		return (API->err);
324 	}
325 
326 	if ((P->flags & PLAYER_SCANNED) == 0)
327 	{	WMF_ERROR (API,"attempt to play unscanned metafile!");
328 		API->err = wmf_E_Glitch;
329 		return (API->err);
330 	}
331 
332 	if ((API->flags & API_DEVICE_OPEN) == 0)
333 	{	if (FR->device_open) FR->device_open (API);
334 
335 		if (ERR (API))
336 		{	WMF_DEBUG (API,"bailing...");
337 			return (API->err);
338 		}
339 
340 		API->flags |= API_DEVICE_OPEN;
341 	}
342 
343 	d_r->TL = P->D_TL;
344 	d_r->BR = P->D_BR;
345 
346 	P->flags |= PLAYER_PLAY; /* Set play mode */
347 
348 	WmfPlayMetaFile (API);
349 
350 	if (ERR (API))
351 	{	WMF_DEBUG (API,"bailing...");
352 		return (API->err);
353 	}
354 
355 	d_r->TL = P->D_TL;
356 	d_r->BR = P->D_BR;
357 
358 	return (API->err);
359 }
360 
WmfPlayMetaFile(wmfAPI * API)361 static wmf_error_t WmfPlayMetaFile (wmfAPI* API)
362 {	unsigned int i;
363 	int byte;
364 	int changed;
365 
366 	unsigned char* Par;
367 
368 	unsigned int Function;
369 	unsigned long Size;
370 	unsigned long number;
371 
372 	long pos_params;
373 	long pos_current;
374 	long pos_max;
375 
376 	wmfObject* objects = 0;
377 
378 	wmfUserData_t userdata;
379 
380 	wmfRegion* visible;
381 
382 	wmfRecord Record;
383 
384 	wmfPlayer_t*          P  = (wmfPlayer_t*)          API->player_data;
385 	wmfFunctionReference* FR = (wmfFunctionReference*) API->function_reference;
386 	wmfFontData*          FD = (wmfFontData*)          API->font_data;
387 
388 	wmfAttributes   attrlist;
389 	wmfAttributes * atts = 0;
390 
391 	WMF_DEBUG (API,"~~~~~~~~WmfPlayMetaFile");
392 
393 	P->dc_stack_length = 0;
394 
395 	visible = &(P->visible);
396 
397 	visible->numRects = 0;
398 	visible->rects = 0;
399 	visible->size = 0;
400 
401 	P->current.x = 0; /* Should this be in the DC ?? */
402 	P->current.y = 0;
403 
404 	P->Viewport_Origin.x = 0; /* Should this be in the DC ?? */
405 	P->Viewport_Origin.y = 0;
406 
407 	P->Viewport_Width  = 1024; /* Should this be in the DC ?? */
408 	P->Viewport_Height = 1024;
409 
410 /* Can SetDefaults go in player_init ??
411  */
412 	if (FD == 0)
413 	{	WMF_ERROR (API,"Glitch! No font engine interface!");
414 		API->err = wmf_E_Glitch;
415 		return (API->err);
416 	}
417 
418 	if (FD->map == 0)
419 	{	WMF_ERROR (API,"Glitch! No font-mapper!");
420 		API->err = wmf_E_Glitch;
421 		return (API->err);
422 	}
423 
424 	if (FD->stringwidth == 0)
425 	{	WMF_ERROR (API,"Glitch! No string width function!");
426 		API->err = wmf_E_Glitch;
427 		return (API->err);
428 	}
429 
430 	if ((API->bbuf.read == 0) || (API->bbuf.seek == 0) || (API->bbuf.tell == 0))
431 	{	WMF_ERROR (API,"WmfPlayMetaFile: input functions set improperly!");
432 		API->err = wmf_E_Glitch;
433 		return (API->err);
434 	}
435 
436 	P->dc = dc_copy (API,0);
437 
438 	if (ERR (API))
439 	{	WMF_DEBUG (API,"bailing...");
440 		return (API->err);
441 	}
442 
443 	WmfSetMapMode (API,(U16)(PLACEABLE (API) ? MM_DPI : MM_TEXT));
444 
445 	if (PLAY (API))
446 	{	if (FR->device_begin) FR->device_begin (API);
447 
448 		if (ERR (API))
449 		{	WMF_DEBUG (API,"bailing...");
450 			return (API->err);
451 		}
452 	}
453 
454 	Par = P->Parameters;
455 
456 	objects = P->objects;
457 
458 	for (i = 0; i < NUM_OBJECTS (API); i++) objects[i].type = 0;
459 
460 	WMF_SEEK (API,API->File->pos);
461 
462 	if (ERR (API))
463 	{	WMF_DEBUG (API,"bailing...");
464 		return (API->err);
465 	}
466 
467 	wmf_attr_new (API, &attrlist);
468 
469 	if (ERR (API))
470 	{	WMF_DEBUG (API,"bailing...");
471 		return (API->err);
472 	}
473 
474 	number = 0;
475 	do
476 	{	if (++number < API->store.count)
477 		{	atts = API->store.attrlist + number;
478 		}
479 		else
480 		{	atts = &attrlist;
481 			wmf_attr_clear (API, atts);
482 		}
483 
484 		Size     = wmf_read_32 (API,0,0);
485 		Function = wmf_read_16 (API);
486 
487 		if ((Size == 3) && (Function == 0))
488 		{	if (SCAN (API)) wmf_write (API, Size, Function, "empty",
489 					atts->atts, 0, 0);
490 			break; /* Probably final record ?? */
491 		}
492 
493 /*		if ((Size > MAX_REC_SIZE (API)) || (Size < 3))
494  */		if (((Size - 3) > MAX_REC_SIZE (API)) || (Size < 3))
495 		{	WMF_ERROR (API,"libwmf: wmf with bizarre record size; bailing...");
496 			WMF_ERROR (API,"        please send it to us at http://www.wvware.com/");
497 			wmf_printf (API,"maximum record size = %u\n",(unsigned) MAX_REC_SIZE (API));
498 			wmf_printf (API,"record size = %u\n",(unsigned) Size);
499 			API->err = wmf_E_BadFormat;
500 			break;
501 		}
502 
503 		pos_params = WMF_TELL (API);
504 
505 		if (pos_params < 0)
506 		{	WMF_ERROR (API,"API's tell() failed on input stream!");
507 			API->err = wmf_E_BadFile;
508 			break;
509 		}
510 
511 		for (i = 0; i < ((Size - 3) * 2); i++)
512 		{	byte = WMF_READ (API);
513 			if (byte == (-1))
514 			{	WMF_ERROR (API,"Unexpected EOF!");
515 				API->err = wmf_E_EOF;
516 				break;
517 			}
518 			Par[i] = (unsigned char) byte;
519 		}
520 
521 		if (ERR (API))
522 		{	WMF_DEBUG (API,"bailing...");
523 			break;
524 		}
525 
526 		Record.size = Size - 3;
527 		Record.function = Function;
528 		Record.parameter = Par;
529 		Record.position = pos_params;
530 
531 		switch (Function)
532 		{
533 		case META_SETMAPMODE:
534 			SCAN_DIAGNOSTIC (API,"New Record: SETMAPMODE");
535 			changed = meta_mapmode (API,&Record);
536 			if (SCAN (API)) wmf_write (API, Size, Function, "setmapmode",
537 					atts->atts, Record.parameter, Record.size * 2);
538 			if (changed && ((Record.size * 2 + 6) == atts->length))
539 			{	memcpy (atts->buffer + 6, Record.parameter, Record.size * 2);
540 			}
541 			SCAN_DIAGNOSTIC (API,"\n");
542 		break;
543 
544 		case META_SETWINDOWORG:
545 			SCAN_DIAGNOSTIC (API,"New Record: SETWINDOWORG");
546 			changed = meta_orgext (API,&Record);
547 			if (SCAN (API)) wmf_write (API, Size, Function, "setwindoworg",
548 					atts->atts, Record.parameter, Record.size * 2);
549 			if (changed && ((Record.size * 2 + 6) == atts->length))
550 			{	memcpy (atts->buffer + 6, Record.parameter, Record.size * 2);
551 			}
552 			SCAN_DIAGNOSTIC (API,"\n");
553 		break;
554 
555 		case META_SETVIEWPORTORG:
556 			SCAN_DIAGNOSTIC (API,"New Record: SETVIEWPORTORG");
557 			meta_orgext (API,&Record);
558 			if (SCAN (API)) wmf_write (API, Size, Function, "setviewportorg",
559 					atts->atts, Record.parameter, Record.size * 2);
560 			SCAN_DIAGNOSTIC (API,"\n");
561 		break;
562 
563 		case META_SETVIEWPORTEXT:
564 			SCAN_DIAGNOSTIC (API,"New Record: SETVIEWPORTEXT");
565 			changed = meta_orgext (API,&Record);
566 			if (SCAN (API)) wmf_write (API, Size, Function, "setviewportext",
567 					atts->atts, Record.parameter, Record.size * 2);
568 			if (changed && ((Record.size * 2 + 6) == atts->length))
569 			{	memcpy (atts->buffer + 6, Record.parameter, Record.size * 2);
570 			}
571 			SCAN_DIAGNOSTIC (API,"\n");
572 		break;
573 
574 		case META_SETWINDOWEXT:
575 			SCAN_DIAGNOSTIC (API,"New Record: SETWINDOWEXT");
576 			changed = meta_orgext (API,&Record);
577 			if (SCAN (API)) wmf_write (API, Size, Function, "setwindowext",
578 					atts->atts, Record.parameter, Record.size * 2);
579 			if (changed && ((Record.size * 2 + 6) == atts->length))
580 			{	memcpy (atts->buffer + 6, Record.parameter, Record.size * 2);
581 			}
582 			SCAN_DIAGNOSTIC (API,"\n");
583 		break;
584 
585 		case META_OFFSETWINDOWORG:
586 			SCAN_DIAGNOSTIC (API,"New Record: OFFSETWINDOWORG");
587 			changed = meta_orgext (API,&Record);
588 			if (SCAN (API)) wmf_write (API, Size, Function, "offsetwindoworg",
589 					atts->atts, Record.parameter, Record.size * 2);
590 			if (changed && ((Record.size * 2 + 6) == atts->length))
591 			{	memcpy (atts->buffer + 6, Record.parameter, Record.size * 2);
592 			}
593 			SCAN_DIAGNOSTIC (API,"\n");
594 		break;
595 
596 		case META_OFFSETVIEWPORTORG:
597 			SCAN_DIAGNOSTIC (API,"New Record: OFFSETVIEWPORTORG");
598 			changed = meta_orgext (API,&Record);
599 			if (SCAN (API)) wmf_write (API, Size, Function, "offsetviewportorg",
600 					atts->atts, Record.parameter, Record.size * 2);
601 			if (changed && ((Record.size * 2 + 6) == atts->length))
602 			{	memcpy (atts->buffer + 6, Record.parameter, Record.size * 2);
603 			}
604 			SCAN_DIAGNOSTIC (API,"\n");
605 		break;
606 
607 		case META_SCALEWINDOWEXT:
608 			SCAN_DIAGNOSTIC (API,"New Record: SCALEWINDOWEXT");
609 			changed = meta_scale (API,&Record);
610 			if (SCAN (API)) wmf_write (API, Size, Function, "scalewindowext",
611 					atts->atts, Record.parameter, Record.size * 2);
612 			if (changed && ((Record.size * 2 + 6) == atts->length))
613 			{	memcpy (atts->buffer + 6, Record.parameter, Record.size * 2);
614 			}
615 			SCAN_DIAGNOSTIC (API,"\n");
616 		break;
617 
618 		case META_SCALEVIEWPORTEXT:
619 			SCAN_DIAGNOSTIC (API,"New Record: SCALEVIEWPORTEXT");
620 			changed = meta_scale (API,&Record);
621 			if (SCAN (API)) wmf_write (API, Size, Function, "scaleviewportext",
622 					atts->atts, Record.parameter, Record.size * 2);
623 			if (changed && ((Record.size * 2 + 6) == atts->length))
624 			{	memcpy (atts->buffer + 6, Record.parameter, Record.size * 2);
625 			}
626 			SCAN_DIAGNOSTIC (API,"\n");
627 		break;
628 
629 /* Following were originally play-only:
630  * (a) basic draw
631  * (b) REGION calls
632  * (c) BMP & ROP stuff
633  * (d) DC set
634  * (e) text & font
635  * (f) palette
636  * (g) create & delete; save & restore; ...
637  * (h) ==== other ====
638  */
639 
640 /* (a) basic draw
641  */
642 		case META_MOVETO:
643 			SCAN_DIAGNOSTIC (API,"New Record: MOVETO");
644 			changed = meta_moveto (API,&Record);
645 			if (SCAN (API)) wmf_write (API, Size, Function, "moveto",
646 					atts->atts, Record.parameter, Record.size * 2);
647 			if (changed && ((Record.size * 2 + 6) == atts->length))
648 			{	memcpy (atts->buffer + 6, Record.parameter, Record.size * 2);
649 			}
650 			SCAN_DIAGNOSTIC (API,"\n");
651 		break;
652 
653 		case META_FLOODFILL:
654 			SCAN_DIAGNOSTIC (API,"New Record: FLOODFILL");
655 			changed = meta_flood (API,&Record);
656 			if (SCAN (API)) wmf_write (API, Size, Function, "floodfill",
657 					atts->atts, Record.parameter, Record.size * 2);
658 			if (changed && ((Record.size * 2 + 6) == atts->length))
659 			{	memcpy (atts->buffer + 6, Record.parameter, Record.size * 2);
660 			}
661 			SCAN_DIAGNOSTIC (API,"\n");
662 		break;
663 
664 		case META_EXTFLOODFILL:
665 			SCAN_DIAGNOSTIC (API,"New Record: EXTFLOODFILL");
666 			changed = meta_flood (API,&Record);
667 			if (SCAN (API)) wmf_write (API, Size, Function, "extfloodfill",
668 					atts->atts, Record.parameter, Record.size * 2);
669 			if (changed && ((Record.size * 2 + 6) == atts->length))
670 			{	memcpy (atts->buffer + 6, Record.parameter, Record.size * 2);
671 			}
672 			SCAN_DIAGNOSTIC (API,"\n");
673 		break;
674 
675 		case META_SETPIXEL:
676 			SCAN_DIAGNOSTIC (API,"New Record: SETPIXEL");
677 			changed = meta_pixel (API,&Record);
678 			if (SCAN (API)) wmf_write (API, Size, Function, "setpixel",
679 					atts->atts, Record.parameter, Record.size * 2);
680 			if (changed && ((Record.size * 2 + 6) == atts->length))
681 			{	memcpy (atts->buffer + 6, Record.parameter, Record.size * 2);
682 			}
683 			SCAN_DIAGNOSTIC (API,"\n");
684 		break;
685 
686 		case META_PIE:
687 			SCAN_DIAGNOSTIC (API,"New Record: PIE");
688 			changed = meta_arc (API,&Record);
689 			if (SCAN (API)) wmf_write (API, Size, Function, "pie",
690 					atts->atts, Record.parameter, Record.size * 2);
691 			if (changed && ((Record.size * 2 + 6) == atts->length))
692 			{	memcpy (atts->buffer + 6, Record.parameter, Record.size * 2);
693 			}
694 			SCAN_DIAGNOSTIC (API,"\n");
695 		break;
696 
697 		case META_CHORD:
698 			SCAN_DIAGNOSTIC (API,"New Record: CHORD");
699 			changed = meta_arc (API,&Record);
700 			if (SCAN (API)) wmf_write (API, Size, Function, "chord",
701 					atts->atts, Record.parameter, Record.size * 2);
702 			if (changed && ((Record.size * 2 + 6) == atts->length))
703 			{	memcpy (atts->buffer + 6, Record.parameter, Record.size * 2);
704 			}
705 			SCAN_DIAGNOSTIC (API,"\n");
706 		break;
707 
708 		case META_ARC:
709 			SCAN_DIAGNOSTIC (API,"New Record: ARC");
710 			changed = meta_arc (API,&Record);
711 			if (SCAN (API)) wmf_write (API, Size, Function, "arc",
712 					atts->atts, Record.parameter, Record.size * 2);
713 			if (changed && ((Record.size * 2 + 6) == atts->length))
714 			{	memcpy (atts->buffer + 6, Record.parameter, Record.size * 2);
715 			}
716 			SCAN_DIAGNOSTIC (API,"\n");
717 		break;
718 
719 		case META_ELLIPSE:
720 			SCAN_DIAGNOSTIC (API,"New Record: ELLIPSE");
721 			changed = meta_ellipse (API,&Record);
722 			if (SCAN (API)) wmf_write (API, Size, Function, "ellipse",
723 					atts->atts, Record.parameter, Record.size * 2);
724 			if (changed && ((Record.size * 2 + 6) == atts->length))
725 			{	memcpy (atts->buffer + 6, Record.parameter, Record.size * 2);
726 			}
727 			SCAN_DIAGNOSTIC (API,"\n");
728 		break;
729 
730 		case META_LINETO:
731 			SCAN_DIAGNOSTIC (API,"New Record: LINETO");
732 			changed = meta_line (API,&Record);
733 			if (SCAN (API)) wmf_write (API, Size, Function, "lineto",
734 					atts->atts, Record.parameter, Record.size * 2);
735 			if (changed && ((Record.size * 2 + 6) == atts->length))
736 			{	memcpy (atts->buffer + 6, Record.parameter, Record.size * 2);
737 			}
738 			SCAN_DIAGNOSTIC (API,"\n");
739 		break;
740 
741 		case META_POLYLINE:
742 			SCAN_DIAGNOSTIC (API,"New Record: POLYLINE");
743 			changed = meta_lines (API,&Record);
744 			if (SCAN (API)) wmf_write (API, Size, Function, "polyline",
745 					atts->atts, Record.parameter, Record.size * 2);
746 			if (changed && ((Record.size * 2 + 6) == atts->length))
747 			{	memcpy (atts->buffer + 6, Record.parameter, Record.size * 2);
748 			}
749 			SCAN_DIAGNOSTIC (API,"\n");
750 		break;
751 
752 		case META_POLYGON:
753 			SCAN_DIAGNOSTIC (API,"New Record: POLYGON");
754 			changed = meta_polygon (API,&Record);
755 			if (SCAN (API)) wmf_write (API, Size, Function, "polygon",
756 					atts->atts, Record.parameter, Record.size * 2);
757 			if (changed && ((Record.size * 2 + 6) == atts->length))
758 			{	memcpy (atts->buffer + 6, Record.parameter, Record.size * 2);
759 			}
760 			SCAN_DIAGNOSTIC (API,"\n");
761 		break;
762 
763 		case META_POLYPOLYGON:
764 			SCAN_DIAGNOSTIC (API,"New Record: POLYPOLYGON");
765 			changed = meta_polygons (API,&Record);
766 			if (SCAN (API)) wmf_write (API, Size, Function, "polypolygon",
767 					atts->atts, Record.parameter, Record.size * 2);
768 			if (changed && ((Record.size * 2 + 6) == atts->length))
769 			{	memcpy (atts->buffer + 6, Record.parameter, Record.size * 2);
770 			}
771 			SCAN_DIAGNOSTIC (API,"\n");
772 		break;
773 
774 		case META_ROUNDRECT:
775 			SCAN_DIAGNOSTIC (API,"New Record: ROUNDRECT");
776 			changed = meta_round (API,&Record);
777 			if (SCAN (API)) wmf_write (API, Size, Function, "roundrect",
778 					atts->atts, Record.parameter, Record.size * 2);
779 			if (changed && ((Record.size * 2 + 6) == atts->length))
780 			{	memcpy (atts->buffer + 6, Record.parameter, Record.size * 2);
781 			}
782 			SCAN_DIAGNOSTIC (API,"\n");
783 		break;
784 
785 		case META_RECTANGLE:
786 			SCAN_DIAGNOSTIC (API,"New Record: RECTANGLE");
787 			changed = meta_rect (API,&Record);
788 			if (SCAN (API)) wmf_write (API, Size, Function, "rectangle",
789 					atts->atts, Record.parameter, Record.size * 2);
790 			if (changed && ((Record.size * 2 + 6) == atts->length))
791 			{	memcpy (atts->buffer + 6, Record.parameter, Record.size * 2);
792 			}
793 			SCAN_DIAGNOSTIC (API,"\n");
794 		break;
795 
796 /* (b) REGION calls
797  */
798 		case META_FRAMEREGION:
799 			SCAN_DIAGNOSTIC (API,"New Record: FRAMEREGION");
800 			changed = meta_rgn_brush (API,&Record);
801 			if (SCAN (API)) wmf_write (API, Size, Function, "frameregion",
802 					atts->atts, Record.parameter, Record.size * 2);
803 			if (changed && ((Record.size * 2 + 6) == atts->length))
804 			{	memcpy (atts->buffer + 6, Record.parameter, Record.size * 2);
805 			}
806 			SCAN_DIAGNOSTIC (API,"\n");
807 		break;
808 
809 		case META_FILLREGION:
810 			SCAN_DIAGNOSTIC (API,"New Record: FILLREGION");
811 			changed = meta_rgn_brush (API,&Record);
812 			if (SCAN (API)) wmf_write (API, Size, Function, "fillregion",
813 					atts->atts, Record.parameter, Record.size * 2);
814 			if (changed && ((Record.size * 2 + 6) == atts->length))
815 			{	memcpy (atts->buffer + 6, Record.parameter, Record.size * 2);
816 			}
817 			SCAN_DIAGNOSTIC (API,"\n");
818 		break;
819 
820 		case META_INVERTREGION:
821 			SCAN_DIAGNOSTIC (API,"New Record: INVERTREGION");
822 			changed = meta_rgn_paint (API,&Record);
823 			if (SCAN (API)) wmf_write (API, Size, Function, "invertregion",
824 					atts->atts, Record.parameter, Record.size * 2);
825 			if (changed && ((Record.size * 2 + 6) == atts->length))
826 			{	memcpy (atts->buffer + 6, Record.parameter, Record.size * 2);
827 			}
828 			SCAN_DIAGNOSTIC (API,"\n");
829 		break;
830 
831 		case META_PAINTREGION:
832 			SCAN_DIAGNOSTIC (API,"New Record: PAINTREGION");
833 			changed = meta_rgn_paint (API,&Record);
834 			if (SCAN (API)) wmf_write (API, Size, Function, "paintregion",
835 					atts->atts, Record.parameter, Record.size * 2);
836 			if (changed && ((Record.size * 2 + 6) == atts->length))
837 			{	memcpy (atts->buffer + 6, Record.parameter, Record.size * 2);
838 			}
839 			SCAN_DIAGNOSTIC (API,"\n");
840 		break;
841 
842 		case META_CREATEREGION:
843 			SCAN_DIAGNOSTIC (API,"New Record: CREATEREGION");
844 			changed = meta_rgn_create (API,&Record);
845 			if (SCAN (API)) wmf_write (API, Size, Function, "createregion",
846 					atts->atts, Record.parameter, Record.size * 2);
847 			if (changed && ((Record.size * 2 + 6) == atts->length))
848 			{	memcpy (atts->buffer + 6, Record.parameter, Record.size * 2);
849 			}
850 			SCAN_DIAGNOSTIC (API,"\n");
851 		break;
852 
853 		case META_SELECTCLIPREGION:
854 			SCAN_DIAGNOSTIC (API,"New Record: SELECTCLIPREGION");
855 			changed = meta_clip_select (API,&Record);
856 			if (SCAN (API)) wmf_write (API, Size, Function, "selectclipregion",
857 					atts->atts, Record.parameter, Record.size * 2);
858 			if (changed && ((Record.size * 2 + 6) == atts->length))
859 			{	memcpy (atts->buffer + 6, Record.parameter, Record.size * 2);
860 			}
861 			SCAN_DIAGNOSTIC (API,"\n");
862 		break;
863 
864 		case META_OFFSETCLIPRGN:
865 			SCAN_DIAGNOSTIC (API,"New Record: OFFSETCLIPREGION");
866 			changed = meta_clip_offset (API,&Record);
867 			if (SCAN (API)) wmf_write (API, Size, Function, "offsetclipregion",
868 					atts->atts, Record.parameter, Record.size * 2);
869 			if (changed && ((Record.size * 2 + 6) == atts->length))
870 			{	memcpy (atts->buffer + 6, Record.parameter, Record.size * 2);
871 			}
872 			SCAN_DIAGNOSTIC (API,"\n");
873 		break;
874 
875 		case META_EXCLUDECLIPRECT:
876 			SCAN_DIAGNOSTIC (API,"New Record: EXCLUDECLIPRECT");
877 			changed = meta_clip_combine (API,&Record);
878 			if (SCAN (API)) wmf_write (API, Size, Function, "excludecliprect",
879 					atts->atts, Record.parameter, Record.size * 2);
880 			if (changed && ((Record.size * 2 + 6) == atts->length))
881 			{	memcpy (atts->buffer + 6, Record.parameter, Record.size * 2);
882 			}
883 			SCAN_DIAGNOSTIC (API,"\n");
884 		break;
885 
886 		case META_INTERSECTCLIPRECT:
887 			SCAN_DIAGNOSTIC (API,"New Record: INTERSECTCLIPRECT");
888 			changed = meta_clip_combine (API,&Record);
889 			if (SCAN (API)) wmf_write (API, Size, Function, "intersectcliprect",
890 					atts->atts, Record.parameter, Record.size * 2);
891 			if (changed && ((Record.size * 2 + 6) == atts->length))
892 			{	memcpy (atts->buffer + 6, Record.parameter, Record.size * 2);
893 			}
894 			SCAN_DIAGNOSTIC (API,"\n");
895 		break;
896 
897 /* (c) BMP & ROP stuff
898  * Notes: (1) BMP width/height may be signed! ?? i.e., -width,-height ??
899  *        (2) Check! Check! Check!
900  */
901 		case META_SETDIBTODEV:
902 			SCAN_DIAGNOSTIC (API,"New Record: SETDIBTODEV");
903 			changed = meta_dib_draw (API,&Record);
904 			if (SCAN (API)) wmf_write (API, Size, Function, "setdibtodev",
905 					atts->atts, Record.parameter, Record.size * 2);
906 			if (changed && ((Record.size * 2 + 6) == atts->length))
907 			{	memcpy (atts->buffer + 6, Record.parameter, Record.size * 2);
908 			}
909 			SCAN_DIAGNOSTIC (API,"\n");
910 		break;
911 
912 		case META_STRETCHDIB:
913 			SCAN_DIAGNOSTIC (API,"New Record: STRETCHDIB");
914 			changed = meta_dib_draw (API,&Record);
915 			if (SCAN (API)) wmf_write (API, Size, Function, "stretchdib",
916 					atts->atts, Record.parameter, Record.size * 2);
917 			if (changed && ((Record.size * 2 + 6) == atts->length))
918 			{	memcpy (atts->buffer + 6, Record.parameter, Record.size * 2);
919 			}
920 			SCAN_DIAGNOSTIC (API,"\n");
921 		break;
922 
923 		case META_DIBSTRETCHBLT:
924 			SCAN_DIAGNOSTIC (API,"New Record: DIBSTRETCHBLT");
925 			changed = meta_dib_draw (API,&Record);
926 			if (SCAN (API)) wmf_write (API, Size, Function, "dibstretchblt",
927 					atts->atts, Record.parameter, Record.size * 2);
928 			if (changed && ((Record.size * 2 + 6) == atts->length))
929 			{	memcpy (atts->buffer + 6, Record.parameter, Record.size * 2);
930 			}
931 			SCAN_DIAGNOSTIC (API,"\n");
932 		break;
933 
934 		case META_DIBBITBLT:
935 			SCAN_DIAGNOSTIC (API,"New Record: DIBBITBLT");
936 			changed = meta_dib_draw (API,&Record);
937 			if (SCAN (API)) wmf_write (API, Size, Function, "dibbitblt",
938 					atts->atts, Record.parameter, Record.size * 2);
939 			if (changed && ((Record.size * 2 + 6) == atts->length))
940 			{	memcpy (atts->buffer + 6, Record.parameter, Record.size * 2);
941 			}
942 			SCAN_DIAGNOSTIC (API,"\n");
943 		break;
944 
945 		case META_DIBCREATEPATTERNBRUSH:
946 			SCAN_DIAGNOSTIC (API,"New Record: DIBCREATEPATTERNBRUSH");
947 			changed = meta_dib_brush (API,&Record);
948 			if (SCAN (API)) wmf_write (API, Size, Function, "dibcreatepatternbrush",
949 					atts->atts, Record.parameter, Record.size * 2);
950 			if (changed && ((Record.size * 2 + 6) == atts->length))
951 			{	memcpy (atts->buffer + 6, Record.parameter, Record.size * 2);
952 			}
953 			SCAN_DIAGNOSTIC (API,"\n");
954 		break;
955 
956 		case META_PATBLT:
957 			SCAN_DIAGNOSTIC (API,"New Record: PATBLT");
958 			changed = meta_rop_draw (API,&Record);
959 			if (SCAN (API)) wmf_write (API, Size, Function, "patblt",
960 					atts->atts, Record.parameter, Record.size * 2);
961 			if (changed && ((Record.size * 2 + 6) == atts->length))
962 			{	memcpy (atts->buffer + 6, Record.parameter, Record.size * 2);
963 			}
964 			SCAN_DIAGNOSTIC (API,"\n");
965 		break;
966 
967 /* (d) DC set
968  */
969 		case META_SETROP2:
970 			SCAN_DIAGNOSTIC (API,"New Record: SETROP2");
971 			changed = meta_dc_set (API,&Record);
972 			if (SCAN (API)) wmf_write (API, Size, Function, "setrop2",
973 					atts->atts, Record.parameter, Record.size * 2);
974 			if (changed && ((Record.size * 2 + 6) == atts->length))
975 			{	memcpy (atts->buffer + 6, Record.parameter, Record.size * 2);
976 			}
977 			SCAN_DIAGNOSTIC (API,"\n");
978 		break;
979 
980 		case META_SETTEXTJUSTIFICATION:
981 			SCAN_DIAGNOSTIC (API,"New Record: SETTEXTJUSTIFICATION");
982 			changed = meta_dc_set (API,&Record);
983 			if (SCAN (API)) wmf_write (API, Size, Function, "settextjustification",
984 					atts->atts, Record.parameter, Record.size * 2);
985 			if (changed && ((Record.size * 2 + 6) == atts->length))
986 			{	memcpy (atts->buffer + 6, Record.parameter, Record.size * 2);
987 			}
988 			SCAN_DIAGNOSTIC (API,"\n");
989 		break;
990 
991 		case META_SETTEXTCHAREXTRA:
992 			SCAN_DIAGNOSTIC (API,"New Record: SETTEXTCHAREXTRA");
993 			changed = meta_dc_set (API,&Record);
994 			if (SCAN (API)) wmf_write (API, Size, Function, "settextcharextra",
995 					atts->atts, Record.parameter, Record.size * 2);
996 			if (changed && ((Record.size * 2 + 6) == atts->length))
997 			{	memcpy (atts->buffer + 6, Record.parameter, Record.size * 2);
998 			}
999 			SCAN_DIAGNOSTIC (API,"\n");
1000 		break;
1001 
1002 		case META_SETPOLYFILLMODE:
1003 			SCAN_DIAGNOSTIC (API,"New Record: SETPOLYFILLMODE");
1004 			changed = meta_dc_set (API,&Record);
1005 			if (SCAN (API)) wmf_write (API, Size, Function, "setpolyfillmode",
1006 					atts->atts, Record.parameter, Record.size * 2);
1007 			if (changed && ((Record.size * 2 + 6) == atts->length))
1008 			{	memcpy (atts->buffer + 6, Record.parameter, Record.size * 2);
1009 			}
1010 			SCAN_DIAGNOSTIC (API,"\n");
1011 		break;
1012 
1013 		case META_SETSTRETCHBLTMODE:
1014 			SCAN_DIAGNOSTIC (API,"New Record: SETSTRETCHBLTMODE");
1015 			changed = meta_unused (API,&Record);
1016 			if (SCAN (API)) wmf_write (API, Size, Function, "setstretchbltmode",
1017 					atts->atts, Record.parameter, Record.size * 2);
1018 			if (changed && ((Record.size * 2 + 6) == atts->length))
1019 			{	memcpy (atts->buffer + 6, Record.parameter, Record.size * 2);
1020 			}
1021 			SCAN_DIAGNOSTIC (API,"\n");
1022 		break;
1023 
1024 		case META_SETTEXTALIGN:
1025 			SCAN_DIAGNOSTIC (API,"New Record: SETTEXTALIGN");
1026 			changed = meta_dc_set (API,&Record);
1027 			if (SCAN (API)) wmf_write (API, Size, Function, "settextalign",
1028 					atts->atts, Record.parameter, Record.size * 2);
1029 			if (changed && ((Record.size * 2 + 6) == atts->length))
1030 			{	memcpy (atts->buffer + 6, Record.parameter, Record.size * 2);
1031 			}
1032 			SCAN_DIAGNOSTIC (API,"\n");
1033 		break;
1034 
1035 		case META_SETTEXTCOLOR:
1036 			SCAN_DIAGNOSTIC (API,"New Record: SETTEXTCOLOUR");
1037 			changed = meta_dc_color (API,&Record,atts);
1038 			if (SCAN (API)) wmf_write (API, Size, Function, "settextcolour",
1039 					atts->atts, Record.parameter, Record.size * 2);
1040 			if (changed && ((Record.size * 2 + 6) == atts->length))
1041 			{	memcpy (atts->buffer + 6, Record.parameter, Record.size * 2);
1042 			}
1043 			SCAN_DIAGNOSTIC (API,"\n");
1044 		break;
1045 
1046 		case META_SETBKCOLOR:
1047 			SCAN_DIAGNOSTIC (API,"New Record: SETBKCOLOR");
1048 			changed = meta_dc_color (API,&Record,atts);
1049 			if (SCAN (API)) wmf_write (API, Size, Function, "setbkcolor",
1050 					atts->atts, Record.parameter, Record.size * 2);
1051 			if (changed && ((Record.size * 2 + 6) == atts->length))
1052 			{	memcpy (atts->buffer + 6, Record.parameter, Record.size * 2);
1053 			}
1054 			SCAN_DIAGNOSTIC (API,"\n");
1055 		break;
1056 
1057 		case META_SETBKMODE:
1058 			SCAN_DIAGNOSTIC (API,"New Record: SETBKMODE");
1059 			changed = meta_dc_set (API,&Record);
1060 			if (SCAN (API)) wmf_write (API, Size, Function, "setbkmode",
1061 					atts->atts, Record.parameter, Record.size * 2);
1062 			if (changed && ((Record.size * 2 + 6) == atts->length))
1063 			{	memcpy (atts->buffer + 6, Record.parameter, Record.size * 2);
1064 			}
1065 			SCAN_DIAGNOSTIC (API,"\n");
1066 		break;
1067 
1068 		case META_SELECTOBJECT:
1069 			SCAN_DIAGNOSTIC (API,"New Record: SELECTOBJECT");
1070 			changed = meta_dc_select (API,&Record);
1071 			if (SCAN (API)) wmf_write (API, Size, Function, "selectobject",
1072 					atts->atts, Record.parameter, Record.size * 2);
1073 			if (changed && ((Record.size * 2 + 6) == atts->length))
1074 			{	memcpy (atts->buffer + 6, Record.parameter, Record.size * 2);
1075 			}
1076 			SCAN_DIAGNOSTIC (API,"\n");
1077 		break;
1078 
1079 /* (e) text & font
1080  */
1081 		case META_TEXTOUT:
1082 			SCAN_DIAGNOSTIC (API,"New Record: TEXTOUT");
1083 			changed = meta_text (API,&Record);
1084 			if (SCAN (API)) wmf_write (API, Size, Function, "textout",
1085 					atts->atts, Record.parameter, Record.size * 2);
1086 			if (changed && ((Record.size * 2 + 6) == atts->length))
1087 			{	memcpy (atts->buffer + 6, Record.parameter, Record.size * 2);
1088 			}
1089 			SCAN_DIAGNOSTIC (API,"\n");
1090 		break;
1091 
1092 		case META_EXTTEXTOUT:
1093 			SCAN_DIAGNOSTIC (API,"New Record: EXTTEXTOUT");
1094 			changed = meta_text (API,&Record);
1095 			if (SCAN (API)) wmf_write (API, Size, Function, "exttextout",
1096 					atts->atts, Record.parameter, Record.size * 2);
1097 			if (changed && ((Record.size * 2 + 6) == atts->length))
1098 			{	memcpy (atts->buffer + 6, Record.parameter, Record.size * 2);
1099 			}
1100 			SCAN_DIAGNOSTIC (API,"\n");
1101 		break;
1102 
1103 		case META_CREATEFONTINDIRECT:
1104 			SCAN_DIAGNOSTIC (API,"New Record: CREATEFONTINDIRECT");
1105 			changed = meta_font_create (API,&Record);
1106 			if (SCAN (API)) wmf_write (API, Size, Function, "createfontindirect",
1107 					atts->atts, Record.parameter, Record.size * 2);
1108 			if (changed && ((Record.size * 2 + 6) == atts->length))
1109 			{	memcpy (atts->buffer + 6, Record.parameter, Record.size * 2);
1110 			}
1111 			SCAN_DIAGNOSTIC (API,"\n");
1112 		break;
1113 
1114 		case META_SETMAPPERFLAGS:
1115 			SCAN_DIAGNOSTIC (API,"New Record: SETMAPPERFLAGS");
1116 			changed = meta_unused (API,&Record);
1117 			if (SCAN (API)) wmf_write (API, Size, Function, "setmapperflags",
1118 					atts->atts, Record.parameter, Record.size * 2);
1119 			if (changed && ((Record.size * 2 + 6) == atts->length))
1120 			{	memcpy (atts->buffer + 6, Record.parameter, Record.size * 2);
1121 			}
1122 			SCAN_DIAGNOSTIC (API,"\n");
1123 		break;
1124 
1125 /* (f) palette
1126  */
1127 		case META_CREATEPALETTE:
1128 			SCAN_DIAGNOSTIC (API,"New Record: CREATEPALETTE");
1129 			changed = meta_palette_create (API);
1130 			if (SCAN (API)) wmf_write (API, Size, Function, "createpalette",
1131 					atts->atts, Record.parameter, Record.size * 2);
1132 			if (changed && ((Record.size * 2 + 6) == atts->length))
1133 			{	memcpy (atts->buffer + 6, Record.parameter, Record.size * 2);
1134 			}
1135 			SCAN_DIAGNOSTIC (API,"\n");
1136 		break;
1137 
1138 		case META_REALIZEPALETTE:
1139 			SCAN_DIAGNOSTIC (API,"New Record: REALIZEPALETTE");
1140 			changed = meta_unused (API,&Record);
1141 			if (SCAN (API)) wmf_write (API, Size, Function, "realizepalette",
1142 					atts->atts, Record.parameter, Record.size * 2);
1143 			if (changed && ((Record.size * 2 + 6) == atts->length))
1144 			{	memcpy (atts->buffer + 6, Record.parameter, Record.size * 2);
1145 			}
1146 			SCAN_DIAGNOSTIC (API,"\n");
1147 		break;
1148 
1149 		case META_SELECTPALETTE:
1150 			SCAN_DIAGNOSTIC (API,"New Record: SELECTPALETTE");
1151 			changed = meta_unused (API,&Record);
1152 			if (SCAN (API)) wmf_write (API, Size, Function, "selectpalette",
1153 					atts->atts, Record.parameter, Record.size * 2);
1154 			if (changed && ((Record.size * 2 + 6) == atts->length))
1155 			{	memcpy (atts->buffer + 6, Record.parameter, Record.size * 2);
1156 			}
1157 			SCAN_DIAGNOSTIC (API,"\n");
1158 		break;
1159 
1160 		case META_SETPALENTRIES:
1161 			SCAN_DIAGNOSTIC (API,"New Record: SETPALENTRIES");
1162 			changed = meta_unused (API,&Record);
1163 			if (SCAN (API)) wmf_write (API, Size, Function, "setpalentries",
1164 					atts->atts, Record.parameter, Record.size * 2);
1165 			if (changed && ((Record.size * 2 + 6) == atts->length))
1166 			{	memcpy (atts->buffer + 6, Record.parameter, Record.size * 2);
1167 			}
1168 			SCAN_DIAGNOSTIC (API,"\n");
1169 		break;
1170 
1171 /* (g) create & delete; save & restore; ...
1172  */
1173 		case META_SAVEDC:
1174 			SCAN_DIAGNOSTIC (API,"New Record: SAVEDC");
1175 			changed = meta_dc_save (API,&Record);
1176 			if (SCAN (API)) wmf_write (API, Size, Function, "savedc",
1177 					atts->atts, Record.parameter, Record.size * 2);
1178 			if (changed && ((Record.size * 2 + 6) == atts->length))
1179 			{	memcpy (atts->buffer + 6, Record.parameter, Record.size * 2);
1180 			}
1181 			SCAN_DIAGNOSTIC (API,"\n");
1182 		break;
1183 
1184 		case META_RESTOREDC:
1185 			SCAN_DIAGNOSTIC (API,"New Record: RESTOREDC");
1186 			changed = meta_dc_restore (API,&Record);
1187 			if (SCAN (API)) wmf_write (API, Size, Function, "restoredc",
1188 					atts->atts, Record.parameter, Record.size * 2);
1189 			if (changed && ((Record.size * 2 + 6) == atts->length))
1190 			{	memcpy (atts->buffer + 6, Record.parameter, Record.size * 2);
1191 			}
1192 			SCAN_DIAGNOSTIC (API,"\n");
1193 		break;
1194 
1195 		case META_CREATEPENINDIRECT:
1196 			SCAN_DIAGNOSTIC (API,"New Record: CREATEPENINDIRECT");
1197 			changed = meta_pen_create (API,&Record,atts);
1198 			if (SCAN (API)) wmf_write (API, Size, Function, "createpenindirect",
1199 					atts->atts, Record.parameter, Record.size * 2);
1200 			if (changed && ((Record.size * 2 + 6) == atts->length))
1201 			{	memcpy (atts->buffer + 6, Record.parameter, Record.size * 2);
1202 			}
1203 			SCAN_DIAGNOSTIC (API,"\n");
1204 		break;
1205 
1206 		case META_CREATEBRUSHINDIRECT:
1207 			SCAN_DIAGNOSTIC (API,"New Record: CREATEBRUSHINDIRECT");
1208 			changed = meta_brush_create (API,&Record,atts);
1209 			if (SCAN (API)) wmf_write (API, Size, Function, "createbrushindirect",
1210 					atts->atts, Record.parameter, Record.size * 2);
1211 			if (changed && ((Record.size * 2 + 6) == atts->length))
1212 			{	memcpy (atts->buffer + 6, Record.parameter, Record.size * 2);
1213 			}
1214 			SCAN_DIAGNOSTIC (API,"\n");
1215 		break;
1216 
1217 		case META_DELETEOBJECT:
1218 			SCAN_DIAGNOSTIC (API,"New Record: DELETEOBJECT");
1219 			changed = meta_delete (API,&Record);
1220 			if (SCAN (API)) wmf_write (API, Size, Function, "deleteobject",
1221 					atts->atts, Record.parameter, Record.size * 2);
1222 			if (changed && ((Record.size * 2 + 6) == atts->length))
1223 			{	memcpy (atts->buffer + 6, Record.parameter, Record.size * 2);
1224 			}
1225 			SCAN_DIAGNOSTIC (API,"\n");
1226 		break;
1227 
1228 /* (h) ==== other ====
1229  */
1230 		case META_ESCAPE:
1231 			SCAN_DIAGNOSTIC (API,"New Record: ESCAPE");
1232 			changed = meta_unused (API,&Record);
1233 			if (SCAN (API)) wmf_write (API, Size, Function, "escape",
1234 					atts->atts, Record.parameter, Record.size * 2);
1235 			if (changed && ((Record.size * 2 + 6) == atts->length))
1236 			{	memcpy (atts->buffer + 6, Record.parameter, Record.size * 2);
1237 			}
1238 			SCAN_DIAGNOSTIC (API,"\n");
1239 		break;
1240 
1241 		default:
1242 			SCAN_DIAGNOSTIC (API,"New Record: UNKNOWN");
1243 			changed = meta_unused (API,&Record);
1244 			if (SCAN (API)) wmf_write (API, Size, Function, "unknown",
1245 					atts->atts, Record.parameter, Record.size * 2);
1246 			if (changed && ((Record.size * 2 + 6) == atts->length))
1247 			{	memcpy (atts->buffer + 6, Record.parameter, Record.size * 2);
1248 			}
1249 			SCAN_DIAGNOSTIC (API,"\n");
1250 		break;
1251 		}
1252 
1253 		if (PLAY (API) && API->status.function)
1254 		{	pos_current = WMF_TELL (API);
1255 			if (pos_current < 0)
1256 			{	WMF_ERROR (API,"API's tell() failed on input stream!");
1257 				API->err = wmf_E_BadFile;
1258 				break;
1259 			}
1260 			pos_current -= API->File->pos;
1261 			pos_max = (FILE_SIZE(API) - API->File->pos)*2;
1262 			if (API->status.function (API->status.context,(float) pos_current / (float) pos_max))
1263 			{	API->err = wmf_E_UserExit;
1264 			}
1265 		}
1266 
1267 	} while (API->err == wmf_E_None);
1268 
1269 	if (Size == 0)
1270 	{	WMF_DEBUG (API,"size was 0, giving up now silently...");
1271 		if (API->err == wmf_E_EOF)
1272 		{	WMF_DEBUG (API,"discarding an EOF error, however.");
1273 			API->err = wmf_E_None;
1274 		}
1275 	}
1276 
1277 	if (ERR (API)) /* Quit now ?? */
1278 	{	WMF_DEBUG (API,"bailing...");
1279 		return (API->err);
1280 	}
1281 
1282 	wmf_attr_free (API, &attrlist);
1283 
1284 	if (SCAN (API)) wmf_write_end (API);
1285 
1286 	while (P->dc_stack_length)
1287 	{	if (P->dc)
1288 		{	userdata.dc = P->dc;
1289 			userdata.data = P->dc->userdata;
1290 
1291 			if (FR->udata_free) FR->udata_free (API,&userdata);
1292 			wmf_free (API,P->dc);
1293 		}
1294 		P->dc = dc_stack_pop (API);
1295 	}
1296 
1297 	if (P->dc)
1298 	{	userdata.dc = P->dc;
1299 		userdata.data = P->dc->userdata;
1300 
1301 		if (PLAY (API) && FR->udata_free) FR->udata_free (API,&userdata);
1302 		wmf_free (API,P->dc);
1303 	}
1304 
1305 	dc_stack_free (API);
1306 
1307 	for (i = 0; i < NUM_OBJECTS(API); i++)
1308 	{	if (objects[i].type == OBJ_BRUSH)
1309 		{	if (objects[i].obj.brush.lbStyle == BS_DIBPATTERN)
1310 			{	if (objects[i].obj.brush.bmp.data && FR->bmp_free)
1311 				{	FR->bmp_free (API,&(objects[i].obj.brush.bmp));
1312 				}
1313 			}
1314 		}
1315 		else if (objects[i].type == OBJ_REGION)
1316 		{	wmf_free (API,objects[i].obj.rgn.rects);
1317 		}
1318 		else if (objects[i].type == OBJ_FONT)
1319 		{	wmf_free (API,objects[i].obj.font.lfFaceName);
1320 		}
1321 	}
1322 
1323 	if (PLAY (API) && FR->device_end) FR->device_end (API);
1324 
1325 	return (API->err);
1326 }
1327