1 /**
2   @file uemf.c
3 
4   @brief Functions for manipulating EMF files and structures.
5 
6   [U_EMR]_set all take data and return a pointer to memory holding the constructed record.
7   The size of that record is also returned in recsize.
8   It is also in the second int32 in the record, but may have been byte swapped and so not usable.
9   If something goes wrong a NULL pointer is returned and recsize is set to 0.
10 
11   Compile with "U_VALGRIND" defined defined to enable code which lets valgrind check each record for
12   uninitialized data.
13 
14   Compile with "SOL8" defined for Solaris 8 or 9 (Sparc).
15 */
16 
17 /*
18 File:      uemf.c
19 Version:   0.0.31
20 Date:      26-JAN-2016
21 Author:    David Mathog, Biology Division, Caltech
22 email:     mathog@caltech.edu
23 Copyright: 2016 David Mathog and California Institute of Technology (Caltech)
24 */
25 
26 #ifdef __cplusplus
27 extern "C" {
28 #endif
29 
30 #include <stdlib.h>
31 #include <stdio.h>
32 #include <string.h>
33 #include <iconv.h>
34 #include <wchar.h>
35 #include <errno.h>
36 #include <string.h>
37 #include <limits.h> // for INT_MAX, INT_MIN
38 #include <math.h>   // for U_ROUND()
39 #include <stddef.h> /* for offsetof() macro */
40 #if 0
41 #include <windef.h>    //Not actually used, looking for collisions
42 #include <winnt.h>    //Not actually used, looking for collisions
43 #include <wingdi.h>   //Not actually used, looking for collisions
44 #endif
45 #include "uemf.h"
46 
47 //! \cond
48 /* one prototype from uemf_endian.  Put it here because end user should never need to see it, so
49 not in uemf.h or uemf_endian.h */
50 void U_swap2(void *ul, unsigned int count);
51 //! \endcond
52 
53 /**
54     \brief Look up the name of the EMR record by type.  Returns U_EMR_INVALID if out of range.
55 
56     \return name of the EMR record, "U_EMR_INVALID" if out of range.
57     \param idx  EMR record type.
58 
59 */
U_emr_names(unsigned int idx)60 char *U_emr_names(unsigned int idx){
61    if(idx<U_EMR_MIN || idx > U_EMR_MAX){ idx = 0; }
62    static char *U_EMR_NAMES[U_EMR_MAX+1]={
63       "U_EMR_INVALID",
64       "U_EMR_HEADER",
65       "U_EMR_POLYBEZIER",
66       "U_EMR_POLYGON",
67       "U_EMR_POLYLINE",
68       "U_EMR_POLYBEZIERTO",
69       "U_EMR_POLYLINETO",
70       "U_EMR_POLYPOLYLINE",
71       "U_EMR_POLYPOLYGON",
72       "U_EMR_SETWINDOWEXTEX",
73       "U_EMR_SETWINDOWORGEX",
74       "U_EMR_SETVIEWPORTEXTEX",
75       "U_EMR_SETVIEWPORTORGEX",
76       "U_EMR_SETBRUSHORGEX",
77       "U_EMR_EOF",
78       "U_EMR_SETPIXELV",
79       "U_EMR_SETMAPPERFLAGS",
80       "U_EMR_SETMAPMODE",
81       "U_EMR_SETBKMODE",
82       "U_EMR_SETPOLYFILLMODE",
83       "U_EMR_SETROP2",
84       "U_EMR_SETSTRETCHBLTMODE",
85       "U_EMR_SETTEXTALIGN",
86       "U_EMR_SETCOLORADJUSTMENT",
87       "U_EMR_SETTEXTCOLOR",
88       "U_EMR_SETBKCOLOR",
89       "U_EMR_OFFSETCLIPRGN",
90       "U_EMR_MOVETOEX",
91       "U_EMR_SETMETARGN",
92       "U_EMR_EXCLUDECLIPRECT",
93       "U_EMR_INTERSECTCLIPRECT",
94       "U_EMR_SCALEVIEWPORTEXTEX",
95       "U_EMR_SCALEWINDOWEXTEX",
96       "U_EMR_SAVEDC",
97       "U_EMR_RESTOREDC",
98       "U_EMR_SETWORLDTRANSFORM",
99       "U_EMR_MODIFYWORLDTRANSFORM",
100       "U_EMR_SELECTOBJECT",
101       "U_EMR_CREATEPEN",
102       "U_EMR_CREATEBRUSHINDIRECT",
103       "U_EMR_DELETEOBJECT",
104       "U_EMR_ANGLEARC",
105       "U_EMR_ELLIPSE",
106       "U_EMR_RECTANGLE",
107       "U_EMR_ROUNDRECT",
108       "U_EMR_ARC",
109       "U_EMR_CHORD",
110       "U_EMR_PIE",
111       "U_EMR_SELECTPALETTE",
112       "U_EMR_CREATEPALETTE",
113       "U_EMR_SETPALETTEENTRIES",
114       "U_EMR_RESIZEPALETTE",
115       "U_EMR_REALIZEPALETTE",
116       "U_EMR_EXTFLOODFILL",
117       "U_EMR_LINETO",
118       "U_EMR_ARCTO",
119       "U_EMR_POLYDRAW",
120       "U_EMR_SETARCDIRECTION",
121       "U_EMR_SETMITERLIMIT",
122       "U_EMR_BEGINPATH",
123       "U_EMR_ENDPATH",
124       "U_EMR_CLOSEFIGURE",
125       "U_EMR_FILLPATH",
126       "U_EMR_STROKEANDFILLPATH",
127       "U_EMR_STROKEPATH",
128       "U_EMR_FLATTENPATH",
129       "U_EMR_WIDENPATH",
130       "U_EMR_SELECTCLIPPATH",
131       "U_EMR_ABORTPATH",
132       "U_EMR_UNDEF69",
133       "U_EMR_COMMENT",
134       "U_EMR_FILLRGN",
135       "U_EMR_FRAMERGN",
136       "U_EMR_INVERTRGN",
137       "U_EMR_PAINTRGN",
138       "U_EMR_EXTSELECTCLIPRGN",
139       "U_EMR_BITBLT",
140       "U_EMR_STRETCHBLT",
141       "U_EMR_MASKBLT",
142       "U_EMR_PLGBLT",
143       "U_EMR_SETDIBITSTODEVICE",
144       "U_EMR_STRETCHDIBITS",
145       "U_EMR_EXTCREATEFONTINDIRECTW",
146       "U_EMR_EXTTEXTOUTA",
147       "U_EMR_EXTTEXTOUTW",
148       "U_EMR_POLYBEZIER16",
149       "U_EMR_POLYGON16",
150       "U_EMR_POLYLINE16",
151       "U_EMR_POLYBEZIERTO16",
152       "U_EMR_POLYLINETO16",
153       "U_EMR_POLYPOLYLINE16",
154       "U_EMR_POLYPOLYGON16",
155       "U_EMR_POLYDRAW16",
156       "U_EMR_CREATEMONOBRUSH",
157       "U_EMR_CREATEDIBPATTERNBRUSHPT",
158       "U_EMR_EXTCREATEPEN",
159       "U_EMR_POLYTEXTOUTA",
160       "U_EMR_POLYTEXTOUTW",
161       "U_EMR_SETICMMODE",
162       "U_EMR_CREATECOLORSPACE",
163       "U_EMR_SETCOLORSPACE",
164       "U_EMR_DELETECOLORSPACE",
165       "U_EMR_GLSRECORD",
166       "U_EMR_GLSBOUNDEDRECORD",
167       "U_EMR_PIXELFORMAT",
168       "U_EMR_DRAWESCAPE",
169       "U_EMR_EXTESCAPE",
170       "U_EMR_UNDEF107",
171       "U_EMR_SMALLTEXTOUT",
172       "U_EMR_FORCEUFIMAPPING",
173       "U_EMR_NAMEDESCAPE",
174       "U_EMR_COLORCORRECTPALETTE",
175       "U_EMR_SETICMPROFILEA",
176       "U_EMR_SETICMPROFILEW",
177       "U_EMR_ALPHABLEND",
178       "U_EMR_SETLAYOUT",
179       "U_EMR_TRANSPARENTBLT",
180       "U_EMR_UNDEF117",
181       "U_EMR_GRADIENTFILL",
182       "U_EMR_SETLINKEDUFIS",
183       "U_EMR_SETTEXTJUSTIFICATION",
184       "U_EMR_COLORMATCHTOTARGETW",
185       "U_EMR_CREATECOLORSPACEW"
186    };
187    return(U_EMR_NAMES[idx]);
188 }
189 
190 
191 
192 /* **********************************************************************************************
193 These definitions are for code pieces that are used many times in the following implementation.  These
194 definitions are not needed in end user code, so they are here rather than in uemf.h.
195 *********************************************************************************************** */
196 
197 //! @cond
198 
199 // this one may also be used A=Msk,B=MskBmi and F=cbMsk
200 #define SET_CB_FROM_PXBMI(A,B,C,D,E,F)    /* A=Px, B=Bmi, C=cbImage, D=cbImage4, E=cbBmi, F=cbPx */ \
201    if(A){\
202      if(!B)return(NULL);  /* size is derived from U_BITMAPINFO, but NOT from its size field, go figure*/ \
203      C = F;\
204      D = UP4(C);          /*  pixel array might not be a multiples of 4 bytes*/ \
205      E    = sizeof(U_BITMAPINFOHEADER) +  4 * get_real_color_count((const char *) &(B->bmiHeader));  /*  bmiheader + colortable*/ \
206    }\
207    else { C = 0; D = 0; E=0; }
208 
209 // variable "off" must be declared in the function
210 
211 #define APPEND_PXBMISRC(A,B,C,D,E,F,G) /* A=record, B=U_EMR,C=cbBmi, D=Bmi, E=Px, F=cbImage, G=cbImage4 */ \
212       if(C){\
213          memcpy(A + off, D, C);\
214          ((B *) A)->offBmiSrc  = off;\
215          ((B *) A)->cbBmiSrc   = C;\
216          off += C;\
217          memcpy(A + off, E, F);\
218          ((B *) A)->offBitsSrc = off;\
219          ((B *) A)->cbBitsSrc  = F;\
220          if(G - F){  \
221             off += F;\
222             memset(A + off, 0, G - F); \
223          }\
224       }\
225       else {\
226          ((B *) A)->offBmiSrc  = 0;\
227          ((B *) A)->cbBmiSrc   = 0;\
228          ((B *) A)->offBitsSrc = 0;\
229          ((B *) A)->cbBitsSrc  = 0;\
230       }
231 
232 // variable "off" must be declared in the function
233 
234 #define APPEND_MSKBMISRC(A,B,C,D,E,F,G) /* A=record, B=U_EMR*,C=cbMskBmi, D=MskBmi, E=Msk, F=cbMskImage, G=cbMskImage4 */ \
235       if(C){\
236          memcpy(A + off, D, C);\
237          ((B *) A)->offBmiMask   = off;\
238          ((B *) A)->cbBmiMask    = C;\
239          off += C;\
240          memcpy(A + off, Msk, F);\
241          ((B *) A)->offBitsMask  = off;\
242          ((B *) A)->cbBitsMask   = F;\
243          if(G - F){  memset(A + off, 0, G - F); }\
244       }\
245       else {\
246          ((B *) A)->offBmiMask   = 0;\
247          ((B *) A)->cbBmiMask    = 0;\
248          ((B *) A)->offBitsMask  = 0;\
249          ((B *) A)->cbBitsMask   = 0;\
250       }
251 
252 //! @endcond
253 
254 /* **********************************************************************************************
255 These functions are used for development and debugging and should be be includied in production code.
256 *********************************************************************************************** */
257 
258 /**
259     \brief Debugging utility, used with valgrind to find uninitialized values.  Not for use in production code.
260     \param buf memory area to examine !
261     \param size length in bytes of buf!
262 */
memprobe(const void * buf,size_t size)263 int memprobe(
264       const void   *buf,
265       size_t        size
266    ){
267    int sum=0;
268    char *ptr=(char *)buf;
269    for(;size;size--,ptr++){ sum += *ptr; }  // read all bytes, trigger valgrind warning if any uninitialized
270    return(sum);
271 }
272 
273 /**
274     \brief Dump an EMFHANDLES structure.  Not for use in production code.
275     \param string  Text to output before dumping eht structure
276     \param handle  Handle
277     \param eht     EMFHANDLES structure to dump
278 */
dumpeht(char * string,unsigned int * handle,EMFHANDLES * eht)279 void dumpeht(
280      char         *string,
281      unsigned int *handle,
282      EMFHANDLES   *eht
283   ){
284   uint32_t i;
285   printf("%s\n",string);
286   printf("sptr: %d peak: %d top: %d\n",eht->sptr,eht->peak,eht->top);
287   if(handle){
288     printf("handle: %d \n",*handle);
289   }
290   for(i=0;i<=5;i++){
291      printf("table[%d]: %d\n",i,eht->table[i]);
292   }
293   for(i=1;i<=5;i++){
294      printf("stack[%d]: %d\n",i,eht->stack[i]);
295   }
296 }
297 
298 /* **********************************************************************************************
299 These functions are used for Image conversions and other
300 utility operations.  Character type conversions are in uemf_utf.c
301 *********************************************************************************************** */
302 
303 /**
304     \brief Make up an approximate dx array to pass to emrtext_set(), based on character height and weight.
305 
306     Take abs. value of character height, get width by multiplying by 0.6, and correct weight
307     approximately, with formula (measured on screen for one text line of Arial).
308     Caller is responsible for free() on the returned pointer.
309 
310     \return pointer to dx array
311     \param height  character height (absolute value will be used)
312     \param weight  LF_Weight Enumeration (character weight)
313     \param members Number of entries to put into dx
314 
315 */
dx_set(int32_t height,uint32_t weight,uint32_t members)316 uint32_t *dx_set(
317       int32_t  height,
318       uint32_t weight,
319       uint32_t members
320    ){
321    uint32_t i, width, *dx;
322    dx = (uint32_t *) malloc(members * sizeof(uint32_t));
323    if(dx){
324        if(U_FW_DONTCARE == weight)weight=U_FW_NORMAL;
325        width = (uint32_t) U_ROUND(((float) (height > 0 ? height : -height)) * 0.6 * (0.00024*(float) weight + 0.904));
326        for ( i = 0; i < members; i++ ){ dx[i] = width; }
327    }
328    return(dx);
329 }
330 
331 /**
332     \brief Look up the properties (a bit map) of a type of EMR record.
333           Bits that may be set are defined in "Draw Properties" in uemf.h, they are U_DRAW_NOTEMPTY, etc..
334 
335     \return bitmap of EMR record properties, or U_EMR_INVALID on error or release of all memory
336     \param type EMR record type.  If U_EMR_INVALID release memory. (There is no U_EMR_INVALID EMR record type)
337 
338 */
emr_properties(uint32_t type)339 uint32_t emr_properties(uint32_t type){
340    static uint32_t *table=NULL;
341    uint32_t result = U_EMR_INVALID;  // initialized to indicate an error (on a lookup) or nothing (on a memory release)
342    if(type == U_EMR_INVALID){
343       if(table)free(table);
344       table=NULL;
345    }
346    else if(type>=1 && type<U_EMR_MAX){
347       if(!table){
348          table = (uint32_t *) malloc(sizeof(uint32_t)*(1 + U_EMR_MAX));
349          if(!table)return(result);
350    //                                                               0x80 0x40 0x20 0x10 0x08 0x04 0x02 0x01
351    //                 Path properties (U_DRAW_*)                    TEXT      ALTERS    ONLYTO    VISIBLE
352    //                                                                    PATH      FORCE     CLOSED    NOTEMPTY
353          table[  0] = 0x00;     //   Does not map to any EMR record
354          table[  1] = 0x80;     //   U_EMRHEADER                    1    0    0    0    0    0    0    0
355          table[  2] = 0x83;     //   U_EMRPOLYBEZIER                1    0    0    0    0    0    1    1
356          table[  3] = 0x87;     //   U_EMRPOLYGON                   1    0    0    0    0    1    1    1
357          table[  4] = 0x83;     //   U_EMRPOLYLINE                  1    0    0    0    0    0    1    1
358          table[  5] = 0x8B;     //   U_EMRPOLYBEZIERTO              1    0    0    0    1    0    1    1
359          table[  6] = 0x8B;     //   U_EMRPOLYLINETO                1    0    0    0    1    0    1    1
360          table[  7] = 0x83;     //   U_EMRPOLYPOLYLINE              1    0    0    0    0    0    1    1
361          table[  8] = 0x87;     //   U_EMRPOLYPOLYGON               1    0    0    0    0    1    1    1
362          table[  9] = 0xA0;     //   U_EMRSETWINDOWEXTEX            1    0    1    0    0    0    0    0
363          table[ 10] = 0xA0;     //   U_EMRSETWINDOWORGEX            1    0    1    0    0    0    0    0
364          table[ 11] = 0xA0;     //   U_EMRSETVIEWPORTEXTEX          1    0    1    0    0    0    0    0
365          table[ 12] = 0xA0;     //   U_EMRSETVIEWPORTORGEX          1    0    1    0    0    0    0    0
366          table[ 13] = 0xA0;     //   U_EMRSETBRUSHORGEX             1    0    1    0    0    0    0    0
367          table[ 14] = 0x82;     //   U_EMREOF                       1    0    1    0    0    0    0    0  Force out any pending draw
368          table[ 15] = 0x82;     //   U_EMRSETPIXELV                 1    0    0    0    0    0    1    0
369          table[ 16] = 0xA0;     //   U_EMRSETMAPPERFLAGS            1    0    1    0    0    0    0    0
370          table[ 17] = 0xA0;     //   U_EMRSETMAPMODE                1    0    1    0    0    0    0    0
371          table[ 18] = 0x20;     //   U_EMRSETBKMODE                 0    0    1    0    0    0    0    0
372          table[ 19] = 0xA0;     //   U_EMRSETPOLYFILLMODE           1    0    1    0    0    0    0    0
373          table[ 20] = 0xA0;     //   U_EMRSETROP2                   1    0    1    0    0    0    0    0
374          table[ 21] = 0xA0;     //   U_EMRSETSTRETCHBLTMODE         1    0    1    0    0    0    0    0
375          table[ 22] = 0x20;     //   U_EMRSETTEXTALIGN              0    0    1    0    0    0    0    0
376          table[ 23] = 0xA0;     //   U_EMRSETCOLORADJUSTMENT        1    0    1    0    0    0    0    0
377          table[ 24] = 0x20;     //   U_EMRSETTEXTCOLOR              0    0    1    0    0    0    0    0
378          table[ 25] = 0x20;     //   U_EMRSETBKCOLOR                0    0    1    0    0    0    0    0
379          table[ 26] = 0xA0;     //   U_EMROFFSETCLIPRGN             1    0    1    0    0    0    0    0
380          table[ 27] = 0x89;     //   U_EMRMOVETOEX                  1    0    0    0    1    0    0    1
381          table[ 28] = 0xA0;     //   U_EMRSETMETARGN                1    0    1    0    0    0    0    0
382          table[ 29] = 0xA0;     //   U_EMREXCLUDECLIPRECT           1    0    1    0    0    0    0    0
383          table[ 30] = 0xA0;     //   U_EMRINTERSECTCLIPRECT         1    0    1    0    0    0    0    0
384          table[ 31] = 0xA0;     //   U_EMRSCALEVIEWPORTEXTEX        1    0    1    0    0    0    0    0
385          table[ 32] = 0xA0;     //   U_EMRSCALEWINDOWEXTEX          1    0    1    0    0    0    0    0
386          table[ 33] = 0xA0;     //   U_EMRSAVEDC                    1    0    1    0    0    0    0    0
387          table[ 34] = 0xA0;     //   U_EMRRESTOREDC                 1    0    1    0    0    0    0    0
388          table[ 35] = 0xA0;     //   U_EMRSETWORLDTRANSFORM         1    0    1    0    0    0    0    0
389          table[ 36] = 0xA0;     //   U_EMRMODIFYWORLDTRANSFORM      1    0    1    0    0    0    0    0
390          table[ 37] = 0x20;     //   U_EMRSELECTOBJECT              0    0    1    0    0    0    0    0
391          table[ 38] = 0x20;     //   U_EMRCREATEPEN                 0    0    1    0    0    0    0    0
392          table[ 39] = 0x20;     //   U_EMRCREATEBRUSHINDIRECT       0    0    1    0    0    0    0    0
393          table[ 40] = 0x20;     //   U_EMRDELETEOBJECT              0    0    1    0    0    0    0    0
394          table[ 41] = 0x83;     //   U_EMRANGLEARC                  1    0    0    0    0    0    1    1
395          table[ 42] = 0x87;     //   U_EMRELLIPSE                   1    0    0    0    0    1    1    1
396          table[ 43] = 0x87;     //   U_EMRRECTANGLE                 1    0    0    0    0    1    1    1
397          table[ 44] = 0x87;     //   U_EMRROUNDRECT                 1    0    0    0    0    1    1    1
398          table[ 45] = 0x83;     //   U_EMRARC                       1    0    0    0    0    0    1    1
399          table[ 46] = 0x87;     //   U_EMRCHORD                     1    0    0    0    0    1    1    1
400          table[ 47] = 0x87;     //   U_EMRPIE                       1    0    0    0    0    1    1    1
401          table[ 48] = 0xA0;     //   U_EMRSELECTPALETTE             1    0    1    0    0    0    0    0
402          table[ 49] = 0xA0;     //   U_EMRCREATEPALETTE             1    0    1    0    0    0    0    0
403          table[ 50] = 0xA0;     //   U_EMRSETPALETTEENTRIES         1    0    1    0    0    0    0    0
404          table[ 51] = 0xA0;     //   U_EMRRESIZEPALETTE             1    0    1    0    0    0    0    0
405          table[ 52] = 0xA0;     //   U_EMRREALIZEPALETTE            1    0    1    0    0    0    0    0
406          table[ 53] = 0x82;     //   U_EMREXTFLOODFILL              1    0    0    0    0    0    1    0
407          table[ 54] = 0x8B;     //   U_EMRLINETO                    1    0    0    0    1    0    1    1
408          table[ 55] = 0x8B;     //   U_EMRARCTO                     1    0    0    0    1    0    1    1
409          table[ 56] = 0x83;     //   U_EMRPOLYDRAW                  1    0    0    0    0    0    1    1
410          table[ 57] = 0xA0;     //   U_EMRSETARCDIRECTION           1    0    1    0    0    0    0    0
411          table[ 58] = 0xA0;     //   U_EMRSETMITERLIMIT             1    0    1    0    0    0    0    0
412          table[ 59] = 0xE0;     //   U_EMRBEGINPATH                 1    1    1    0    0    0    0    0
413          table[ 60] = 0x80;     //   U_EMRENDPATH                   1    0    0    0    0    0    0    0
414          table[ 61] = 0x84;     //   U_EMRCLOSEFIGURE               1    0    0    0    0    1    0    0
415          table[ 62] = 0x94;     //   U_EMRFILLPATH                  1    0    0    1    0    1    0    0
416          table[ 63] = 0x94;     //   U_EMRSTROKEANDFILLPATH         1    0    0    1    0    1    0    0
417          table[ 64] = 0x90;     //   U_EMRSTROKEPATH                1    0    0    1    0    0    0    0
418          table[ 65] = 0xA0;     //   U_EMRFLATTENPATH               1    0    1    0    0    0    0    0
419          table[ 66] = 0xA0;     //   U_EMRWIDENPATH                 1    0    1    0    0    0    0    0
420          table[ 67] = 0x80;     //   U_EMRSELECTCLIPPATH            1    0    0    0    0    0    0    0  consumes the path, draws nothing
421          table[ 68] = 0xA0;     //   U_EMRABORTPATH                 1    0    1    0    0    0    0    0
422          table[ 69] = 0xA0;     //   U_EMRUNDEF69                   1    0    1    0    0    0    0    0
423          table[ 70] = 0x00;     //   U_EMRCOMMENT                   0    0    0    0    0    0    0    0
424          table[ 71] = 0x82;     //   U_EMRFILLRGN                   1    0    0    0    0    0    1    0
425          table[ 72] = 0x82;     //   U_EMRFRAMERGN                  1    0    0    0    0    0    1    0
426          table[ 73] = 0x82;     //   U_EMRINVERTRGN                 1    0    0    0    0    0    1    0
427          table[ 74] = 0x82;     //   U_EMRPAINTRGN                  1    0    0    0    0    0    1    0
428          table[ 75] = 0xA0;     //   U_EMREXTSELECTCLIPRGN          1    0    1    0    0    0    0    0
429          table[ 76] = 0x82;     //   U_EMRBITBLT                    1    0    0    0    0    0    1    0
430          table[ 77] = 0x82;     //   U_EMRSTRETCHBLT                1    0    0    0    0    0    1    0
431          table[ 78] = 0x82;     //   U_EMRMASKBLT                   1    0    0    0    0    0    1    0
432          table[ 79] = 0x82;     //   U_EMRPLGBLT                    1    0    0    0    0    0    1    0
433          table[ 80] = 0xA0;     //   U_EMRSETDIBITSTODEVICE         1    0    1    0    0    0    0    0
434          table[ 81] = 0xA0;     //   U_EMRSTRETCHDIBITS             1    0    1    0    0    0    0    0
435          table[ 82] = 0x20;     //   U_EMREXTCREATEFONTINDIRECTW    0    0    1    0    0    0    0    0
436          table[ 83] = 0x02;     //   U_EMREXTTEXTOUTA               0    0    0    0    0    0    1    0
437          table[ 84] = 0x02;     //   U_EMREXTTEXTOUTW               0    0    0    0    0    0    1    0
438          table[ 85] = 0x83;     //   U_EMRPOLYBEZIER16              1    0    0    0    0    0    1    1
439          table[ 86] = 0x83;     //   U_EMRPOLYGON16                 1    0    0    0    0    0    1    1
440          table[ 87] = 0x83;     //   U_EMRPOLYLINE16                1    0    0    0    0    0    1    1
441          table[ 88] = 0x8B;     //   U_EMRPOLYBEZIERTO16            1    0    0    0    1    0    1    1
442          table[ 89] = 0x8B;     //   U_EMRPOLYLINETO16              1    0    0    0    1    0    1    1
443          table[ 90] = 0x83;     //   U_EMRPOLYPOLYLINE16            1    0    0    0    0    0    1    1
444          table[ 91] = 0x87;     //   U_EMRPOLYPOLYGON16             1    0    0    0    0    1    1    1
445          table[ 92] = 0x83;     //   U_EMRPOLYDRAW16                1    0    0    0    0    0    1    1
446          table[ 93] = 0x80;     //   U_EMRCREATEMONOBRUSH           1    0    0    0    0    0    0    0  Not selected yet, so no change in drawing conditions
447          table[ 94] = 0x80;     //   U_EMRCREATEDIBPATTERNBRUSHPT   1    0    0    0    0    0    0    0  "
448          table[ 95] = 0x00;     //   U_EMREXTCREATEPEN              0    0    0    0    0    0    0    0  "
449          table[ 96] = 0x02;     //   U_EMRPOLYTEXTOUTA              0    0    0    0    0    0    1    0
450          table[ 97] = 0x02;     //   U_EMRPOLYTEXTOUTW              0    0    0    0    0    0    1    0
451          table[ 98] = 0xA0;     //   U_EMRSETICMMODE                1    0    1    0    0    0    0    0
452          table[ 99] = 0xA0;     //   U_EMRCREATECOLORSPACE          1    0    1    0    0    0    0    0
453          table[100] = 0xA0;     //   U_EMRSETCOLORSPACE             1    0    1    0    0    0    0    0
454          table[101] = 0xA0;     //   U_EMRDELETECOLORSPACE          1    0    1    0    0    0    0    0
455          table[102] = 0xA0;     //   U_EMRGLSRECORD                 1    0    1    0    0    0    0    0
456          table[103] = 0xA0;     //   U_EMRGLSBOUNDEDRECORD          1    0    1    0    0    0    0    0
457          table[104] = 0xA0;     //   U_EMRPIXELFORMAT               1    0    1    0    0    0    0    0
458          table[105] = 0xA0;     //   U_EMRDRAWESCAPE                1    0    1    0    0    0    0    0
459          table[106] = 0xA0;     //   U_EMREXTESCAPE                 1    0    1    0    0    0    0    0
460          table[107] = 0xA0;     //   U_EMRUNDEF107                  1    0    1    0    0    0    0    0
461          table[108] = 0x02;     //   U_EMRSMALLTEXTOUT              0    0    0    0    0    0    1    0
462          table[109] = 0xA0;     //   U_EMRFORCEUFIMAPPING           1    0    1    0    0    0    0    0
463          table[110] = 0xA0;     //   U_EMRNAMEDESCAPE               1    0    1    0    0    0    0    0
464          table[111] = 0xA0;     //   U_EMRCOLORCORRECTPALETTE       1    0    1    0    0    0    0    0
465          table[112] = 0xA0;     //   U_EMRSETICMPROFILEA            1    0    1    0    0    0    0    0
466          table[113] = 0xA0;     //   U_EMRSETICMPROFILEW            1    0    1    0    0    0    0    0
467          table[114] = 0x82;     //   U_EMRALPHABLEND                1    0    0    0    0    0    1    0
468          table[115] = 0xA0;     //   U_EMRSETLAYOUT                 1    0    1    0    0    0    0    0
469          table[116] = 0x82;     //   U_EMRTRANSPARENTBLT            1    0    0    0    0    0    1    0
470          table[117] = 0xA0;     //   U_EMRUNDEF117                  1    0    1    0    0    0    0    0
471          table[118] = 0x82;     //   U_EMRGRADIENTFILL              1    0    1    0    0    0    1    0
472          table[119] = 0xA0;     //   U_EMRSETLINKEDUFIS             1    0    1    0    0    0    0    0
473          table[120] = 0x20;     //   U_EMRSETTEXTJUSTIFICATION      0    0    1    0    0    0    0    0
474          table[121] = 0xA0;     //   U_EMRCOLORMATCHTOTARGETW       1    0    1    0    0    0    0    0
475          table[122] = 0xA0;     //   U_EMRCREATECOLORSPACEW         1    0    1    0    0    0    0    0
476       }
477       result = table[type];
478    }
479    return(result);
480 }
481 
482 /**
483     \brief Derive from bounding rect, start and end radials, for arc, chord, or pie, the center, start, and end points, and the bounding rectangle.
484 
485     \return 0 on success, other values on errors.
486     \param rclBox     bounding rectangle
487     \param ArcStart   start of arc
488     \param ArcEnd     end of arc
489     \param f1         1 if rotation angle >= 180, else 0
490     \param f2         Rotation direction, 1 if counter clockwise, else 0
491     \param center     Center coordinates
492     \param start      Start coordinates (point on the ellipse defined by rect)
493     \param end        End coordinates (point on the ellipse defined by rect)
494     \param size       W,H of the x,y axes of the bounding rectangle.
495 */
emr_arc_points_common(PU_RECTL rclBox,PU_POINTL ArcStart,PU_POINTL ArcEnd,int * f1,int f2,PU_PAIRF center,PU_PAIRF start,PU_PAIRF end,PU_PAIRF size)496 int emr_arc_points_common(
497        PU_RECTL          rclBox,
498        PU_POINTL         ArcStart,
499        PU_POINTL         ArcEnd,
500        int              *f1,
501        int               f2,
502        PU_PAIRF          center,
503        PU_PAIRF          start,
504        PU_PAIRF          end,
505        PU_PAIRF          size
506     ){
507     U_PAIRF estart;     // EMF start position, defines a radial
508     U_PAIRF eend;       // EMF end   position, defines a radial
509     U_PAIRF vec_estart; // define a unit vector from the center to estart
510     U_PAIRF vec_eend;   // define a unit vector from the center to eend
511     U_PAIRF radii;      // x,y radii of ellipse
512     U_PAIRF ratio;      // intermediate value
513     float scale, cross;
514     center->x   = ((float)(rclBox->left   + rclBox->right ))/2.0;
515     center->y   = ((float)(rclBox->top    + rclBox->bottom))/2.0;
516     size->x     =  (float)(rclBox->right  - rclBox->left );
517     size->y     =  (float)(rclBox->bottom - rclBox->top  );
518     estart.x    =  (float)(ArcStart->x);
519     estart.y    =  (float)(ArcStart->y);
520     eend.x      =  (float)(ArcEnd->x);
521     eend.y      =  (float)(ArcEnd->y);
522     radii.x     =  size->x/2.0;
523     radii.y     =  size->y/2.0;
524 
525     vec_estart.x  = (estart.x - center->x); // initial vector, not unit length
526     vec_estart.y  = (estart.y - center->y);
527     scale         = sqrt(vec_estart.x*vec_estart.x + vec_estart.y*vec_estart.y);
528     if(!scale)return(1);                    // bogus record, has start at center
529     vec_estart.x /= scale;                  // now a unit vector
530     vec_estart.y /= scale;
531 
532     vec_eend.x    = (eend.x - center->x);   // initial vector, not unit length
533     vec_eend.y    = (eend.y - center->y);
534     scale         = sqrt(vec_eend.x*vec_eend.x + vec_eend.y*vec_eend.y);
535     if(!scale)return(2);                    // bogus record, has end at center
536     vec_eend.x   /= scale;                  // now a unit vector
537     vec_eend.y   /= scale;
538 
539 
540     // Find the intersection of the vectors with the ellipse.  With no loss of generality
541     // we can translate the ellipse to the origin, then we just need to find tu (t a factor, u the unit vector)
542     // that also satisfies (x/Rx)^2 + (y/Ry)^2 = 1.  x is t*(ux), y is t*(uy), where ux,uy are the x,y components
543     // of the unit vector.  Substituting gives:
544     // (t*(ux)/Rx)^2 + (t*(uy)/Ry)^2 = 1
545     // t^2 = 1/(  (ux/Rx)^2 + (uy/Ry)^2 )
546     // t = sqrt(1/(  (ux/Rx)^2 + (uy/Ry)^2 ))
547 
548     ratio.x  = vec_estart.x/radii.x;
549     ratio.y  = vec_estart.y/radii.y;
550     ratio.x *= ratio.x;                     // we only use the square
551     ratio.y *= ratio.y;
552     scale    = 1.0/sqrt(ratio.x + ratio.y);
553     start->x = center->x + scale * vec_estart.x;
554     start->y = center->y + scale * vec_estart.y;
555 
556     ratio.x  = vec_eend.x/radii.x;
557     ratio.y  = vec_eend.y/radii.y;
558     ratio.x *= ratio.x;                     // we only use the square
559     ratio.y *= ratio.y;
560     scale    = 1.0/sqrt(ratio.x + ratio.y);
561     end->x   = center->x + scale * vec_eend.x;
562     end->y   = center->y + scale * vec_eend.y;
563 
564     //lastly figure out if the swept angle is >180 degrees or not, based on the direction of rotation
565     //and the two unit vectors.
566 
567     cross = vec_estart.x * vec_eend.y - vec_estart.y * vec_eend.x;
568     if(!f2){  // counter clockwise rotation
569       if(cross >=0){ *f1 = 1; }
570       else {         *f1 = 0; }
571     }
572     else {
573       if(cross >=0){ *f1 = 0; }
574       else {         *f1 = 1; }
575     }
576 
577 
578     return(0);
579 }
580 
581 /**
582     \brief Derive from an EMF arc, chord, or pie the center, start, and end points, and the bounding rectangle.
583 
584     \return 0 on success, other values on errors.
585     \param record     U_EMRPIE, U_EMRCHORD, or _EMRARC record
586     \param f1         1 if rotation angle >= 180, else 0
587     \param f2         Rotation direction, 1 if counter clockwise, else 0
588     \param center     Center coordinates
589     \param start      Start coordinates (point on the ellipse defined by rect)
590     \param end        End coordinates (point on the ellipse defined by rect)
591     \param size       W,H of the x,y axes of the bounding rectangle.
592 */
emr_arc_points(PU_ENHMETARECORD record,int * f1,int f2,PU_PAIRF center,PU_PAIRF start,PU_PAIRF end,PU_PAIRF size)593 int emr_arc_points(
594        PU_ENHMETARECORD  record,
595        int              *f1,
596        int               f2,
597        PU_PAIRF          center,
598        PU_PAIRF          start,
599        PU_PAIRF          end,
600        PU_PAIRF          size
601     ){
602     PU_EMRARC pEmr = (PU_EMRARC) (record);
603     return emr_arc_points_common(&(pEmr->rclBox), &(pEmr->ptlStart), &(pEmr->ptlEnd), f1, f2, center, start, end, size );
604 }
605 
606 /**
607     \brief Convert a U_RGBA 32 bit pixmap to one of many different types of DIB pixmaps.
608 
609     Conversions to formats using color tables assume that the color table can hold every color
610     in the input image.  If that assumption is false then the conversion will fail.  Conversion
611     from 8 bit color to N bit colors (N<8) do so by shifting the appropriate number of bits.
612 
613     \return 0 on success, other values on errors.
614     \param px         DIB pixel array
615     \param cbPx       DIB pixel array size in bytes
616     \param ct         DIB color table
617     \param numCt      DIB color table number of entries
618     \param rgba_px    U_RGBA pixel array (32 bits)
619     \param w          Width of pixel array
620     \param h          Height of pixel array
621     \param stride     Row stride of input pixel array in bytes
622     \param colortype  DIB BitCount Enumeration
623     \param use_ct     If true use color table (only for 1-16 bit DIBs).
624     \param invert     If DIB rows are in opposite order from RGBA rows
625 */
RGBA_to_DIB(char ** px,uint32_t * cbPx,PU_RGBQUAD * ct,int * numCt,const char * rgba_px,int w,int h,int stride,uint32_t colortype,int use_ct,int invert)626 int RGBA_to_DIB(
627        char      **px,
628        uint32_t   *cbPx,
629        PU_RGBQUAD *ct,
630        int        *numCt,
631        const char *rgba_px,
632        int         w,
633        int         h,
634        int         stride,
635        uint32_t    colortype,
636        int         use_ct,
637        int         invert
638    ){
639    int          bs;
640    int          pad;
641    int          i,j,k;
642    int          istart, iend, iinc;
643    uint8_t      r,g,b,a,tmp8;
644    char        *pxptr;
645    const char  *rptr;
646    int          found;
647    int          usedbytes;
648    U_RGBQUAD    color;
649    PU_RGBQUAD   lct;
650    int32_t      index;
651 
652    *px=NULL;
653    *ct=NULL;
654    *numCt=0;
655    *cbPx=0;
656    // sanity checking
657    if(!w || !h || !stride || !colortype || !rgba_px)return(1);
658    if(use_ct && colortype  >= U_BCBM_COLOR16)return(2);  //color tables not used above 16 bit pixels
659    if(!use_ct && colortype < U_BCBM_COLOR16)return(3);   //color tables mandatory for < 16 bit
660 
661    bs = colortype/8;
662    if(bs<1){
663       usedbytes = (w*colortype + 7)/8;      // width of line in fully and partially occupied bytes
664    }
665    else {
666       usedbytes = w*bs;
667    }
668    pad = UP4(usedbytes) - usedbytes;        // DIB rows must be aligned on 4 byte boundaries, they are padded at the end to accomplish this.;
669    *cbPx = h * (usedbytes + pad);           // Rows must start on a 4 byte boundary!
670    *px = (char *) malloc(*cbPx);
671    if(!px)return(4);
672    if(use_ct){
673        *numCt = 1<< colortype;
674        if(*numCt >w*h)*numCt=w*h;
675        lct = (PU_RGBQUAD) malloc(*numCt * sizeof(U_RGBQUAD));
676        if(!lct)return(5);
677        *ct = lct;
678    }
679 
680    if(invert){
681      istart = h-1;
682      iend   = -1;
683      iinc   = -1;
684    }
685    else {
686      istart = 0;
687      iend   = h;
688      iinc   = 1;
689    }
690 
691    found = 0;
692    tmp8  = 0;
693    pxptr = *px;
694    for(i=istart; i!=iend; i+=iinc){
695       rptr= rgba_px + i*stride;
696       for(j=0; j<w; j++){
697           r = *rptr++;
698           g = *rptr++;
699           b = *rptr++;
700           a = *rptr++;
701           if(use_ct){
702              color = U_BGRA(r,g,b,a); // color has order in memory: b,g,r,a, same as EMF+ ARGB
703              index = -1;
704              for(lct = *ct, k=0; k<found; k++,lct++){  // Is this color in the table (VERY inefficient if there are a lot of colors!!!)
705                 if(*(uint32_t *)lct != *(uint32_t *) &color)continue;
706                 index =k;
707                 break;
708              }
709              if(index==-1){  // add a color
710                 found++;
711                 if(found > *numCt){  // More colors found than are supported by the color table
712                    free(*ct);
713                    free(*px);
714                    *numCt=0;
715                    *cbPx=0;
716                    return(6);
717                 }
718                 index = found - 1;
719                 *lct = color;
720              }
721              switch(colortype){
722                 case U_BCBM_MONOCHROME: // 2 colors.    bmiColors array has two entries
723                     tmp8 = tmp8 >> 1;      // This seems wrong, as it fills from the top of each byte.  But it works.
724                     tmp8 |= index << 7;
725                     if(!((j+1) % 8)){
726                        *pxptr++ = tmp8;
727                        tmp8     = 0;
728                     }
729                     break;
730                 case U_BCBM_COLOR4:     // 2^4 colors.  bmiColors array has 16 entries
731                     tmp8 = tmp8 << 4;
732                     tmp8 |= index;
733                     if(!((j+1) % 2)){
734                        *pxptr++ = tmp8;
735                        tmp8     = 0;
736                     }
737                     break;
738                 case U_BCBM_COLOR8:     // 2^8 colors.  bmiColors array has 256 entries
739                     tmp8     = index;
740                     *pxptr++ = tmp8;
741                     break;
742                 case U_BCBM_COLOR16:    // 2^16 colors. (Several different color methods))
743                 case U_BCBM_COLOR24:    // 2^24 colors. bmiColors is not used. Pixels are U_RGBTRIPLE.
744                 case U_BCBM_COLOR32:    // 2^32 colors. bmiColors is not used. Pixels are U_RGBQUAD.
745                 case U_BCBM_EXPLICIT:   // Derinved from JPG or PNG compressed image or ?
746                 default:
747                     return(7);            // This should not be possible, but might happen with memory corruption
748              }
749           }
750           else {
751              switch(colortype){
752                 case U_BCBM_COLOR16:        // 2^16 colors. (Several different color methods))
753                    b /= 8; g /= 8; r /= 8;
754                    // Do it in this way so that the bytes are always stored Little Endian
755                    tmp8  = b;
756                    tmp8 |= g<<5;            // least significant 3 bits of green
757                    *pxptr++ = tmp8;
758                    tmp8  = g>>3;            // most  significant 2 bits of green (there are only 5 bits of data)
759                    tmp8 |= r<<2;
760                    *pxptr++ = tmp8;
761                    break;
762                 case U_BCBM_COLOR24:        // 2^24 colors. bmiColors is not used. Pixels are U_RGBTRIPLE.
763                    *pxptr++ = b;
764                    *pxptr++ = g;
765                    *pxptr++ = r;
766                    break;
767                 case U_BCBM_COLOR32:        // 2^32 colors. bmiColors is not used. Pixels are U_RGBQUAD.
768                    *pxptr++ = b;
769                    *pxptr++ = g;
770                    *pxptr++ = r;
771                    *pxptr++ = a;
772                    break;
773                 case U_BCBM_MONOCHROME:     // 2 colors.    bmiColors array has two entries
774                 case U_BCBM_COLOR4:         // 2^4 colors.  bmiColors array has 16 entries
775                 case U_BCBM_COLOR8:         // 2^8 colors.  bmiColors array has 256 entries
776                 case U_BCBM_EXPLICIT:       // Derinved from JPG or PNG compressed image or ?
777                 default:
778                   return(7);                // This should not be possible, but might happen with memory corruption
779              }
780           }
781       }
782       if( use_ct && colortype == U_BCBM_MONOCHROME && (j % 8) ){
783          *pxptr++ = tmp8;                   // Write last few indices
784          tmp8 = 0;
785       }
786       if( use_ct && colortype == U_BCBM_COLOR4     && (j % 2) ){
787          *pxptr++ = tmp8;                   // Write last few indices
788          tmp8 = 0;
789       }
790       if(pad){
791          memset(pxptr,0,pad);               // not strictly necessary, but set all bytes so that we can find important unset ones with valgrind
792          pxptr += pad;
793       }
794    }
795    return(0);
796 }
797 
798 /**
799     \brief Get the actual number of colors in the color table from the BitMapInfoHeader.
800     \return Number of entries in the color table.
801     \param Bmih  char * pointer to the U_BITMAPINFOHEADER
802 
803     BitmapInfoHeader may list 0 for some types which implies the maximum value.
804     If the image is big enough, that is set by the bit count, as in 256 for an 8
805     bit image.
806     If the image is smaller it is set by width * height.
807     Note, this may be called by WMF code, so it is not safe to assume the data is aligned.
808 */
get_real_color_count(const char * Bmih)809 int get_real_color_count(
810        const char *Bmih
811    ){
812    int Colors, BitCount, Width, Height;
813    uint32_t  utmp4;
814    uint16_t  utmp2;
815    int32_t   tmp4;
816    char     *cBmih = (char *) Bmih;
817    memcpy(&utmp4, cBmih + offsetof(U_BITMAPINFOHEADER,biClrUsed),  4);  Colors   = utmp4;
818    memcpy(&utmp2, cBmih + offsetof(U_BITMAPINFOHEADER,biBitCount), 2);  BitCount = utmp2;
819    memcpy(&tmp4,  cBmih + offsetof(U_BITMAPINFOHEADER,biWidth),    4);  Width    = tmp4;
820    memcpy(&tmp4,  cBmih + offsetof(U_BITMAPINFOHEADER,biHeight),   4);  Height   = tmp4;
821    return(get_real_color_icount(Colors, BitCount, Width, Height));
822 }
823 
824 /**
825     \brief Get the actual number of colors in the color table from the ClrUsed, BitCount, Width, and Height.
826     \return Number of entries in the color table.
827     \param Colors        Number of colors in the table.
828     \param BitCount      BitCount Enumeration
829     \param Width         bitmap width
830     \param Height        bitmap height
831 */
get_real_color_icount(int Colors,int BitCount,int Width,int Height)832 int get_real_color_icount(
833        int Colors,
834        int BitCount,
835        int Width,
836        int Height
837    ){
838    int area = Width * Height;
839    if(area < 0){ area = -area; } /* Height might be negative */
840    if(Colors == 0){
841          if(     BitCount == U_BCBM_MONOCHROME){ Colors = 2;   }
842          else if(BitCount == U_BCBM_COLOR4    ){ Colors = 16;  }
843          else if(BitCount == U_BCBM_COLOR8    ){ Colors = 256; }
844          if(Colors > area){  Colors = area; }
845    }
846    return(Colors);
847 }
848 
849 
850 /**
851     \brief Get the DIB parameters from the BMI of the record for use by DBI_to_RGBA()
852 
853     \return BI_Compression Enumeration.  For anything other than U_BI_RGB values other than px may not be valid.
854     \param record      pointer to EMR record that has a U_BITMAPINFO and bitmap
855     \param offBitsSrc  Offset to the bitmap
856     \param offBmiSrc   Offset to the U_BITMAPINFO
857     \param px          pointer to DIB pixel array in pEmr
858     \param ct          pointer to DIB color table in pEmr
859     \param numCt       DIB color table number of entries, for PNG or JPG returns the number of bytes in the image
860     \param width       Width of pixel array
861     \param height      Height of pixel array (always returned as a positive number)
862     \param colortype   DIB BitCount Enumeration
863     \param invert      If DIB rows are in opposite order from RGBA rows
864 */
get_DIB_params(const char * record,uint32_t offBitsSrc,uint32_t offBmiSrc,const char ** px,const U_RGBQUAD ** ct,uint32_t * numCt,uint32_t * width,uint32_t * height,uint32_t * colortype,uint32_t * invert)865 int get_DIB_params(
866        const char       *record,
867        uint32_t          offBitsSrc,
868        uint32_t          offBmiSrc,
869        const char      **px,
870        const U_RGBQUAD **ct,
871        uint32_t         *numCt,
872        uint32_t         *width,
873        uint32_t         *height,
874        uint32_t         *colortype,
875        uint32_t         *invert
876    ){
877    uint32_t bic;
878    PU_BITMAPINFO Bmi = (PU_BITMAPINFO)(record + offBmiSrc);
879    PU_BITMAPINFOHEADER Bmih = &(Bmi->bmiHeader);
880    /* if biCompression is not U_BI_RGB some or all of the following might not hold real values */
881    bic        = Bmih->biCompression;
882    *width     = Bmih->biWidth;
883    *colortype = Bmih->biBitCount;
884    if(Bmih->biHeight < 0){
885       *height = -Bmih->biHeight;
886       *invert = 1;
887    }
888    else {
889       *height = Bmih->biHeight;
890       *invert = 0;
891    }
892    if(bic == U_BI_RGB){
893       *numCt     = get_real_color_count((const char *) Bmih);
894       if( numCt){ *ct = (PU_RGBQUAD) ((char *)Bmi + sizeof(U_BITMAPINFOHEADER)); }
895       else {      *ct = NULL;                                                    }
896    }
897    else if(bic == U_BI_BITFIELDS){ /* to date only encountered once, for 32 bit, from PPT*/
898       *numCt     = 0;
899       *ct        = NULL;
900       bic        = U_BI_RGB;  /* there seems to be no difference, at least for the 32 bit images */
901    }
902    else {
903       *numCt     = Bmih->biSizeImage;
904       *ct        = NULL;
905    }
906    *px = record + offBitsSrc;
907    return(bic);
908 }
909 
910 /**
911     \brief Convert one of many different types of DIB pixmaps to an RGBA 32 bit pixmap.
912 
913     \return 0 on success, other values on errors.
914     \param px         DIB pixel array
915     \param ct         DIB color table
916     \param numCt      DIB color table number of entries
917     \param rgba_px    U_RGBA pixel array (32 bits), created by this routine, caller must free.
918     \param w          Width of pixel array in the record
919     \param h          Height of pixel array in the record
920     \param colortype  DIB BitCount Enumeration
921     \param use_ct     Kept for symmetry with RGBA_to_DIB, should be set to numCt
922     \param invert     If DIB rows are in opposite order from RGBA rows
923 */
DIB_to_RGBA(const char * px,const U_RGBQUAD * ct,int numCt,char ** rgba_px,int w,int h,uint32_t colortype,int use_ct,int invert)924 int DIB_to_RGBA(
925        const char      *px,
926        const U_RGBQUAD *ct,
927        int              numCt,
928        char           **rgba_px,
929        int              w,
930        int              h,
931        uint32_t         colortype,
932        int              use_ct,
933        int              invert
934    ){
935    uint32_t     cbRgba_px;
936    int          stride;
937    int          bs;
938    int          pad;
939    int          i,j;
940    int          istart, iend, iinc;
941    uint8_t      r,g,b,a,tmp8;
942    const char  *pxptr;
943    char        *rptr;
944    int          usedbytes;
945    U_RGBQUAD    color;
946    int32_t      index;
947 
948    // sanity checking
949    if(!w || !h || !colortype || !px)return(1);
950    if(use_ct && colortype  >= U_BCBM_COLOR16)return(2);  //color tables not used above 16 bit pixels
951    if(!use_ct && colortype < U_BCBM_COLOR16)return(3);   //color tables mandatory for < 16 bit
952    if(use_ct && !numCt)return(4);                        //color table not adequately described
953 
954    stride    = w * 4;
955    cbRgba_px = stride * h;
956    bs = colortype/8;
957    if(bs<1){
958       usedbytes = (w*colortype + 7)/8;      // width of line in fully and partially occupied bytes
959    }
960    else {
961       usedbytes = w*bs;
962    }
963    pad = UP4(usedbytes) - usedbytes;        // DIB rows must be aligned on 4 byte boundaries, they are padded at the end to accomplish this.;
964    *rgba_px = (char *) malloc(cbRgba_px);
965    if(!rgba_px)return(4);
966 
967    if(invert){
968      istart = h-1;
969      iend   = -1;
970      iinc   = -1;
971    }
972    else {
973      istart = 0;
974      iend   = h;
975      iinc   = 1;
976    }
977 
978    pxptr = px;
979    tmp8  = 0;  // silences a compiler warning, tmp8 always sets when j=0, so never used uninitialized
980    for(i=istart; i!=iend; i+=iinc){
981       rptr= *rgba_px + i*stride;
982       for(j=0; j<w; j++){
983           if(use_ct){
984              switch(colortype){
985                 case U_BCBM_MONOCHROME: // 2 colors.    bmiColors array has two entries
986                     if(!(j % 8)){ tmp8 = *pxptr++; }
987                     index = 0x80 & tmp8;      // This seems wrong, as lowest position is top bit, but it works.
988                     index = index >> 7;
989                     tmp8 = tmp8 << 1;
990                     break;
991                 case U_BCBM_COLOR4:     // 2^4 colors.  bmiColors array has 16 entries
992                     if(!(j % 2)){  tmp8 = *pxptr++; }
993                     index = 0xF0 & tmp8;
994                     index = index >> 4;
995                     tmp8  = tmp8  << 4;
996                     break;
997                 case U_BCBM_COLOR8:     // 2^8 colors.  bmiColors array has 256 entries
998                     index    = (uint8_t) *pxptr++;;
999                     break;
1000                 case U_BCBM_COLOR16:    // 2^16 colors. (Several different color methods))
1001                 case U_BCBM_COLOR24:    // 2^24 colors. bmiColors is not used. Pixels are U_RGBTRIPLE.
1002                 case U_BCBM_COLOR32:    // 2^32 colors. bmiColors is not used. Pixels are U_RGBQUAD.
1003                 case U_BCBM_EXPLICIT:   // Derinved from JPG or PNG compressed image or ?
1004                 default:
1005                     return(7);            // This should not be possible, but might happen with memory corruption
1006              }
1007              color = ct[index];
1008              b = U_BGRAGetB(color);
1009              g = U_BGRAGetG(color);
1010              r = U_BGRAGetR(color);
1011              a = U_BGRAGetA(color);
1012           }
1013           else {
1014              switch(colortype){
1015                 case U_BCBM_COLOR16:    // 2^16 colors. (Several different color methods))
1016                    // Do it in this way because the bytes are always stored Little Endian
1017                    tmp8  = *pxptr++;
1018                    b = (0x1F & tmp8) <<3;       // 5 bits of b into the top 5 of 8
1019                    g = tmp8 >> 5;               //  least significant 3 bits of green
1020                    tmp8  = *pxptr++;
1021                    r = (0x7C & tmp8) << 1;      // 5 bits of r into the top 5 of 8
1022                    g |= (0x3 & tmp8) << 3;      // most  significant 2 bits of green (there are only 5 bits of data)
1023                    g = g << 3;                  //  restore intensity (have lost 3 bits of accuracy)
1024                    a = 0;
1025                    break;
1026                 case U_BCBM_COLOR24:    // 2^24 colors. bmiColors is not used. Pixels are U_RGBTRIPLE.
1027                    b = *pxptr++;
1028                    g = *pxptr++;
1029                    r = *pxptr++;
1030                    a = 0;
1031                    break;
1032                 case U_BCBM_COLOR32:    // 2^32 colors. bmiColors is not used. Pixels are U_RGBQUAD.
1033                    b = *pxptr++;
1034                    g = *pxptr++;
1035                    r = *pxptr++;
1036                    a = *pxptr++;
1037                    break;
1038                 case U_BCBM_MONOCHROME: // 2 colors.    bmiColors array has two entries
1039                 case U_BCBM_COLOR4:     // 2^4 colors.  bmiColors array has 16 entries
1040                 case U_BCBM_COLOR8:     // 2^8 colors.  bmiColors array has 256 entries
1041                 case U_BCBM_EXPLICIT:   // Derinved from JPG or PNG compressed image or ?
1042                 default:
1043                   return(7);            // This should not be possible, but might happen with memory corruption
1044              }
1045           }
1046           *rptr++ = r;
1047           *rptr++ = g;
1048           *rptr++ = b;
1049           *rptr++ = a;
1050       }
1051       for(j=0; j<pad; j++){ pxptr++; }  // DIB rows are all 4 byte aligned
1052    }
1053    return(0);
1054 }
1055 
1056 /**
1057     \brief Extract a subset of an RGBA bitmap array.
1058     Frees the incoming bitmap array IF a subset is extracted, otherwise it is left alone.
1059     If the entire array is extracted it just returns the incoming pointer.
1060     If the subset requested is partially outside of the bitmap the region is clipped to the
1061       bitmap boundaries and extracted.  This seems to be a (very) grey area in EMF files, and
1062       even different Microsoft applications do not always do the same thing.  For instance,
1063       XP Preview gives some different images for EMR_BITBLT records than does the "import image"
1064       (but not unpacked) view in PowerPoint. Since all of these states are probably best viewed
1065       as undefined or errors we can only try to do something reasonable and not blow up when
1066       encountering one.
1067 
1068     \return Pointer to the sub array on success, NULL otherwise.
1069     \param rgba_px    U_RGBA pixel array (32 bits), created by this routine, caller must free.
1070     \param w          Width of pixel array in the record
1071     \param h          Height of pixel array in the record
1072     \param sl         start left position in the pixel array in the record to start extracting
1073     \param st         start top  position in the pixel array in the record to start extracting
1074     \param eew        Width of pixel array to extract
1075     \param eeh        Height of pixel array to extract
1076 */
RGBA_to_RGBA(char * rgba_px,int w,int h,int sl,int st,int * eew,int * eeh)1077 char *RGBA_to_RGBA(
1078        char        *rgba_px,
1079        int          w,
1080        int          h,
1081        int          sl,
1082        int          st,
1083        int          *eew,
1084        int          *eeh
1085    ){
1086    int          i;
1087    char        *sub;
1088    char        *sptr;
1089    int          ew = *eew;
1090    int          eh = *eeh;
1091 
1092    // sanity checking
1093    if(w<=0 || h<=0 || ew<=0 || eh<=0 || !rgba_px)return(NULL);
1094 
1095    if(sl>w || st >h)return(NULL);  // This is hopeless, the start point is outside of the array.
1096    if(sl<0){
1097       if(sl+ew<=0)return(NULL);    // This is hopeless, the start point is outside of the array.
1098       ew += sl;
1099       sl = 0;
1100    }
1101    if(st<0){
1102       if(st+eh<=0)return(NULL);    // This is hopeless, the start point is outside of the array.
1103       eh += st;
1104       st = 0;
1105    }
1106    if(sl+ew > w)ew=w-sl;
1107    if(st+eh > h)eh=h-st;
1108    if(!sl && !st && (ew == w) && (eh == h)){
1109       sub = rgba_px;
1110    }
1111    else {
1112       sptr = sub = malloc(ew*eh*4);
1113       if(!sub)return(NULL);
1114       for(i=st; i<st+eh; i++){
1115          memcpy(sptr,rgba_px + i*w*4 + sl*4,4*ew);
1116          sptr += 4*ew;
1117       }
1118       free(rgba_px);
1119    }
1120    *eeh = eh;
1121    *eew = ew;
1122    return(sub);
1123  }
1124 
1125 
1126 /* **********************************************************************************************
1127 These functions are for setting up, appending to, and then tearing down an EMF structure, including
1128 writing the final data structure out to a file.
1129 *********************************************************************************************** */
1130 
1131 /**
1132     \brief Duplicate an EMR record.
1133     \param emr record to duplicate
1134 */
emr_dup(const char * emr)1135 char *emr_dup(
1136       const char *emr
1137    ){
1138    char *dup;
1139    int   irecsize;
1140 
1141    if(!emr)return(NULL);
1142    irecsize = ((PU_EMR)emr)->nSize;
1143    dup=malloc(irecsize);
1144    if(dup){ memcpy(dup,emr,irecsize); }
1145    return(dup);
1146 }
1147 
1148 
1149 /**
1150     \brief Start constructing an emf in memory. Supply the file name and initial size.
1151     \return 0 for success, >=0 for failure.
1152     \param name  EMF filename (will be opened)
1153     \param initsize Initialize EMF in memory to hold this many bytes
1154     \param chunksize When needed increase EMF in memory by this number of bytes
1155     \param et EMF in memory
1156 
1157 
1158 */
emf_start(const char * name,const uint32_t initsize,const uint32_t chunksize,EMFTRACK ** et)1159 int  emf_start(
1160       const char       *name,
1161       const uint32_t   initsize,
1162       const uint32_t   chunksize,
1163       EMFTRACK       **et
1164    ){
1165    FILE *fp;
1166    EMFTRACK *etl=NULL;
1167 
1168    if(initsize < 1)return(1);
1169    if(chunksize < 1)return(2);
1170    if(!name)return(3);
1171    etl = (EMFTRACK *) malloc(sizeof(EMFTRACK));
1172    if(!etl)return(4);
1173    etl->buf = malloc(initsize);  // no need to zero the memory
1174    if(!etl->buf){
1175       free(etl);
1176       return(5);
1177    }
1178    fp=emf_fopen(name,U_WRITE);
1179    if(!fp){
1180       free(etl->buf);
1181       free(etl);
1182       return(6);
1183    }
1184    etl->fp         =  fp;
1185    etl->allocated  =  initsize;
1186    etl->used       =  0;
1187    etl->records    =  0;
1188    etl->PalEntries =  0;
1189    etl->chunk      =  chunksize;
1190    *et=etl;
1191    return(0);
1192 }
1193 
1194 /**
1195     \brief  Finalize the emf in memory and write it to the file.
1196     \return 0 on success, >=1 on failure
1197     \param et EMF in memory
1198     \param eht  EMF handle table (peak handle number needed)
1199 */
emf_finish(EMFTRACK * et,EMFHANDLES * eht)1200 int  emf_finish(
1201       EMFTRACK   *et,
1202       EMFHANDLES *eht
1203    ){
1204    U_EMRHEADER *record;
1205 
1206    if(!et->fp)return(1);   // This could happen if something stomps on memory, otherwise should be caught in emf_start
1207 
1208    // Set the header fields which were unknown up until this point
1209 
1210    record = (U_EMRHEADER *)et->buf;
1211    record->nBytes       = et->used;
1212    record->nRecords     = et->records;
1213    record->nHandles     = eht->peak + 1;
1214    record->nPalEntries  = et->PalEntries;
1215 
1216 #if U_BYTE_SWAP
1217     //This is a Big Endian machine, EMF data must be  Little Endian
1218     U_emf_endian(et->buf,et->used,1);
1219 #endif
1220 
1221    if(1 != fwrite(et->buf,et->used,1,et->fp))return(2);
1222    (void) fclose(et->fp);
1223    et->fp=NULL;
1224    return(0);
1225 }
1226 
1227 /**
1228     \brief Release memory for an emf structure in memory. Call this after emf_finish().
1229     \return 0 on success, >=1 on failure
1230     \param et EMF in memory
1231 */
emf_free(EMFTRACK ** et)1232 int emf_free(
1233       EMFTRACK **et
1234    ){
1235    EMFTRACK *etl;
1236    if(!et)return(1);
1237    etl=*et;
1238    if(!etl)return(2);
1239    free(etl->buf);
1240    free(etl);
1241    *et=NULL;
1242    return(0);
1243 }
1244 
1245 /**
1246     \brief wrapper for fopen, works on any platform
1247     \return 0 on success, >=1 on failure
1248     \param filename file to open (either ASCII or UTF-8)
1249     \param mode     U_READ or U_WRITE (these map to  "rb" and "wb")
1250 */
emf_fopen(const char * filename,const int mode)1251 FILE *emf_fopen(
1252       const char *filename,
1253       const int mode
1254    ){
1255    FILE *fp = NULL;
1256 #ifdef WIN32
1257    uint16_t *fn16;
1258    uint16_t *md16;
1259    if(mode == U_READ){ md16 = U_Utf8ToUtf16le("rb", 0, NULL); }
1260    else {              md16 = U_Utf8ToUtf16le("wb", 0, NULL); }
1261    fn16 = U_Utf8ToUtf16le(filename, 0, NULL);
1262    fp = _wfopen(fn16,md16);
1263    free(fn16);
1264    free(md16);
1265 #else
1266    if(mode == U_READ){ fp = fopen(filename,"rb"); }
1267    else {              fp = fopen(filename,"wb"); }
1268 #endif
1269    return(fp);
1270 }
1271 
1272 /**
1273     \brief Retrieve contents of an EMF file by name.
1274     \return 0 on success, >=1 on failure
1275     \param filename Name of file to open, including the path
1276     \param contents Contents of the file.  Buffer must be free()'d by caller.
1277     \param length   Number of bytes in Contents
1278 */
emf_readdata(const char * filename,char ** contents,size_t * length)1279 int emf_readdata(
1280       const char   *filename,
1281       char        **contents,
1282       size_t       *length
1283    ){
1284    FILE     *fp;
1285    int       status=0;
1286 
1287    *contents=NULL;
1288    fp=emf_fopen(filename,U_READ);
1289    if(!fp){ status = 1; }
1290    else {
1291       // read the entire file into memory
1292       fseek(fp, 0, SEEK_END); // move to end
1293       *length = ftell(fp);
1294       rewind(fp);
1295       *contents = (char *) malloc(*length);
1296       if(!*contents){
1297          status = 2;
1298       }
1299       else {
1300          size_t inbytes = fread(*contents,*length,1,fp);
1301          if(inbytes != 1){
1302             free(*contents);
1303             status = 3;
1304          }
1305          else {
1306 #if U_BYTE_SWAP
1307             //This is a Big Endian machine, EMF data is Little Endian
1308             U_emf_endian(*contents,*length,0);  // LE to BE
1309 #endif
1310           }
1311       }
1312       fclose(fp);
1313    }
1314     return(status);
1315 }
1316 
1317 
1318 /**
1319     \brief Append an EMF record to an emf in memory. This may reallocate buf memory.
1320     \return 0 for success, >=1 for failure.
1321     \param rec     Record to append to EMF in memory
1322     \param et      EMF in memory
1323     \param freerec If true, free rec after append
1324 */
emf_append(U_ENHMETARECORD * rec,EMFTRACK * et,int freerec)1325 int  emf_append(
1326       U_ENHMETARECORD *rec,
1327       EMFTRACK        *et,
1328       int              freerec
1329    ){
1330    size_t deficit;
1331 
1332 #ifdef U_VALGRIND
1333    printf("\nbefore \n");
1334    printf(" probe %d\n",memprobe(rec, U_EMRSIZE(rec)));
1335    printf("after \n");
1336 #endif
1337    if(!rec)return(1);
1338    if(!et)return(2);
1339    if(rec->nSize + et->used > et->allocated){
1340       deficit = rec->nSize + et->used - et->allocated;
1341       if(deficit < et->chunk)deficit = et->chunk;
1342       et->allocated += deficit;
1343       et->buf = realloc(et->buf,et->allocated);
1344       if(!et->buf)return(3);
1345    }
1346    memcpy(et->buf + et->used, rec, rec->nSize);
1347    et->used += rec->nSize;
1348    et->records++;
1349    if(rec->iType == U_EMR_EOF){ et->PalEntries = ((U_EMREOF *)rec)->cbPalEntries; }
1350    if(freerec){ free(rec); }
1351    return(0);
1352 }
1353 
1354 /**
1355     \brief Create a handle table. Entries filled with 0 are empty, entries >0 hold a handle.
1356     \return 0 for success, >=1 for failure.
1357     \param initsize Initialize with space for this number of handles
1358     \param chunksize When needed increase space by this number of handles
1359     \param eht EMF handle table
1360 */
emf_htable_create(uint32_t initsize,uint32_t chunksize,EMFHANDLES ** eht)1361 int emf_htable_create(
1362       uint32_t     initsize,
1363       uint32_t     chunksize,
1364       EMFHANDLES **eht
1365    ){
1366    EMFHANDLES *ehtl;
1367    unsigned int i;
1368 
1369    if(initsize<1)return(1);
1370    if(chunksize<1)return(2);
1371    ehtl = (EMFHANDLES *) malloc(sizeof(EMFHANDLES));
1372    if(!ehtl)return(3);
1373    ehtl->table = malloc(initsize * sizeof(uint32_t));
1374    if(!ehtl->table){
1375       free(ehtl);
1376       return(4);
1377    }
1378    ehtl->stack = malloc(initsize * sizeof(uint32_t));
1379    if(!ehtl->stack){
1380       free(ehtl->table);
1381       free(ehtl);
1382       return(5);
1383    }
1384    memset(ehtl->table , 0, initsize * sizeof(uint32_t));  // zero all slots in the table
1385    for(i=1; i<initsize; i++){ehtl->stack[i]=i;}             // preset the stack
1386    ehtl->allocated = initsize;
1387    ehtl->chunk     = chunksize;
1388    ehtl->table[0]  = 0;         // This slot isn't actually ever used
1389    ehtl->stack[0]  = 0;         // This stack position isn't actually ever used
1390    ehtl->peak      = 1;
1391    ehtl->sptr      = 1;
1392    ehtl->top       = 0;
1393    *eht            = ehtl;
1394    return(0);
1395 }
1396 
1397 /**
1398     \brief Delete an entry from the handle table. Move it back onto the stack. The specified slot is filled with a 0.
1399     \return 0 for success, >=1 for failure.
1400     \param ih  handle
1401     \param eht EMF handle table
1402 
1403 */
emf_htable_delete(uint32_t * ih,EMFHANDLES * eht)1404 int emf_htable_delete(
1405       uint32_t    *ih,
1406       EMFHANDLES  *eht
1407    ){
1408    if(!eht)return(1);
1409    if(!eht->table)return(2);
1410    if(!eht->stack)return(3);
1411    if(*ih < 1)return(4);           // invalid handle
1412    if(!eht->table[*ih])return(5);  // requested table position was not in use
1413    eht->table[*ih]=0;              // remove handle from table
1414    while(eht->top>0 && !eht->table[eht->top]){  // adjust top
1415      eht->top--;
1416    }
1417    eht->sptr--;                   // adjust stack
1418    eht->stack[eht->sptr]=*ih;      // place handle on stack
1419    *ih=0;                         // invalidate handle variable, so a second delete will of it is not possible
1420    return(0);
1421 }
1422 
1423 /**
1424     \brief Returns the index of the first free slot.
1425     Call realloc() if needed.  The slot is set to handle (indicates occupied) and the peak value is adjusted.
1426     \return 0 for success, >=1 for failure.
1427     \param ih  handle
1428     \param eht EMF handle table
1429 */
emf_htable_insert(uint32_t * ih,EMFHANDLES * eht)1430 int emf_htable_insert(
1431       uint32_t   *ih,
1432       EMFHANDLES *eht
1433    ){
1434    unsigned int i;
1435    size_t newsize;
1436 
1437    if(!eht)return(1);
1438    if(!eht->table)return(2);
1439    if(!eht->stack)return(3);
1440    if(!ih)return(4);
1441    if(eht->sptr >= eht->allocated - 1){  // need to reallocate
1442      newsize=eht->allocated + eht->chunk;
1443      eht->table = realloc(eht->table,newsize * sizeof(uint32_t));
1444      if(!eht->table)return(5);
1445      memset(&eht->table[eht->allocated] , 0, eht->chunk * sizeof(uint32_t));  // zero all NEW slots in the table
1446 
1447      eht->stack = realloc(eht->stack,newsize * sizeof(uint32_t));
1448      if(!eht->stack)return(6);
1449      for(i=eht->allocated; i<newsize;i++){ eht->stack[i] = i; }  // init all NEW slots in the stack
1450      eht->allocated = newsize;
1451    }
1452    *ih = eht->stack[eht->sptr];     // handle that is inserted
1453    if(eht->table[*ih])return(7);
1454    eht->table[*ih] = *ih;           // handle goes into preexisting (but zero) slot in table
1455    eht->stack[eht->sptr] = 0;
1456    if(*ih > eht->top){        eht->top = *ih;  }
1457    if(eht->sptr > eht->peak){ eht->peak = eht->sptr; }
1458    eht->sptr++;         // next available handle
1459    return(0);
1460 }
1461 
1462 /**
1463     \brief Free all memory in an htable.  Sets the pointer to NULL.
1464     \return 0 for success, >=1 for failure.
1465     \param eht  EMF handle table
1466 */
emf_htable_free(EMFHANDLES ** eht)1467 int emf_htable_free(
1468       EMFHANDLES **eht
1469    ){
1470    EMFHANDLES *ehtl;
1471    if(!eht)return(1);
1472    ehtl = *eht;
1473    if(!ehtl)return(2);
1474    if(!ehtl->table)return(3);
1475    if(!ehtl->stack)return(4);
1476    free(ehtl->table);
1477    free(ehtl->stack);
1478    free(ehtl);
1479    *eht=NULL;
1480    return(0);
1481 }
1482 
1483 /* **********************************************************************************************
1484 These functions create standard structures used in the EMR records.
1485 *********************************************************************************************** */
1486 
1487 
1488 /**
1489     \brief Set up fields for an EMR_HEADER from the physical device's width and height in mm and dots per millimeter.
1490     Typically this is something like 216,279,47.244 (Letter paper, 1200 DPI = 47.244 DPmm)
1491     \return 0 for success, >=1 for failure.
1492     \param xmm     Device  width in millimeters
1493     \param ymm     Device height in millimeters
1494     \param dpmm    Dots per millimeter
1495     \param szlDev  Device size structure in pixels
1496     \param szlMm   Device size structure in mm
1497 */
device_size(const int xmm,const int ymm,const float dpmm,U_SIZEL * szlDev,U_SIZEL * szlMm)1498 int device_size(
1499       const int    xmm,
1500       const int    ymm,
1501       const float  dpmm,
1502       U_SIZEL     *szlDev,
1503       U_SIZEL     *szlMm
1504    ){
1505    if(xmm < 0 || ymm < 0 || dpmm < 0)return(1);
1506    szlDev->cx          =  U_ROUND((float) xmm * dpmm);
1507    szlDev->cy          =  U_ROUND((float) ymm * dpmm);;
1508    szlMm->cx           =  xmm;
1509    szlMm->cy           =  ymm;
1510    return(0);
1511 }
1512 
1513 /**
1514     \brief Set up fields for an EMR_HEADER for drawing by physical size in mm and dots per millimeter.
1515     Technically rclBounds is supposed to be the extent of the drawing within the EMF, but libUEMF has no way
1516     of knowing this since it never actually draws anything.  Instead this is set to the full drawing size.
1517     Coordinates are inclusive inclusive, so 297 -> 0,29699.
1518     \return 0 for success, >=1 for failure.
1519     \param xmm        Drawing  width in millimeters
1520     \param ymm        Drawing height in millimeters
1521     \param dpmm       Dots per millimeter
1522     \param rclBounds  Drawing size structure in pixels
1523     \param rclFrame   Drawing size structure in mm
1524 */
drawing_size(const int xmm,const int ymm,const float dpmm,U_RECTL * rclBounds,U_RECTL * rclFrame)1525 int drawing_size(
1526       const int    xmm,
1527       const int    ymm,
1528       const float  dpmm,
1529       U_RECTL     *rclBounds,
1530       U_RECTL     *rclFrame
1531    ){
1532    if(xmm < 0 || ymm < 0 || dpmm < 0)return(1);
1533    rclBounds->left     =  0;
1534    rclBounds->top      =  0;
1535    rclBounds->right    =  U_ROUND((float) xmm  * dpmm) - 1;  // because coordinate system is 0,0 in upper left, N,M in lower right
1536    rclBounds->bottom   =  U_ROUND((float) ymm  * dpmm) - 1;
1537    rclFrame->left      =  0;
1538    rclFrame->top       =  0;
1539    rclFrame->right     =  U_ROUND((float) xmm * 100.) - 1;
1540    rclFrame->bottom    =  U_ROUND((float) ymm * 100.) - 1;
1541    return(0);
1542 }
1543 
1544 /**
1545     \brief Set a U_COLORREF value from separate R,G,B values.
1546     \param red    Red   component
1547     \param green  Green component
1548     \param blue   Blue  component
1549 
1550 */
colorref3_set(uint8_t red,uint8_t green,uint8_t blue)1551 U_COLORREF colorref3_set(
1552       uint8_t red,
1553       uint8_t green,
1554       uint8_t blue
1555    ){
1556    U_COLORREF cr = (U_COLORREF){red , green, blue, 0};
1557    return(cr);
1558 }
1559 
1560 /**
1561     \brief Set a U_COLORREF value from separate R,G,B, and Reserved values.
1562     \param red        Red      component
1563     \param green      Green    component
1564     \param blue       Blue     component
1565     \param Reserved   Reserved component
1566 
1567 */
colorref4_set(uint8_t red,uint8_t green,uint8_t blue,uint8_t Reserved)1568 U_COLORREF colorref4_set(
1569       uint8_t red,
1570       uint8_t green,
1571       uint8_t blue,
1572       uint8_t Reserved
1573    ){
1574    U_COLORREF cr = (U_COLORREF){red , green, blue, Reserved};
1575    return(cr);
1576 }
1577 
1578 /**
1579     \brief Set a U_RGBQUAD value from separate R,G,B, Reserved values.
1580     \param red       Red      component
1581     \param green     Green    component
1582     \param blue      Blue     component
1583     \param reserved  Reserved component
1584 
1585 */
rgbquad_set(uint8_t red,uint8_t green,uint8_t blue,uint8_t reserved)1586 U_RGBQUAD rgbquad_set(
1587       uint8_t red,
1588       uint8_t green,
1589       uint8_t blue,
1590       uint8_t reserved
1591    ){
1592    U_RGBQUAD cr = (U_RGBQUAD){blue , green, red, reserved};
1593    return(cr);
1594 }
1595 
1596 /**
1597     \brief Set rect and rectl objects from Upper Left and Lower Right corner points.
1598     \param ul upper left corner of rectangle
1599     \param lr lower right corner of rectangle
1600 */
rectl_set(U_POINTL ul,U_POINTL lr)1601 U_RECTL rectl_set(
1602       U_POINTL ul,
1603       U_POINTL lr
1604     ){
1605     U_RECTL rct;
1606     rct.left     =   ul.x;
1607     rct.top      =   ul.y;
1608     rct.right    =   lr.x;
1609     rct.bottom   =   lr.y;
1610     return(rct);
1611 }
1612 
1613 /**
1614     \brief Set rect and rectl objects from Upper Left and Lower Right corner points.
1615     \param array array of rectangles
1616     \param index  array entry to fill, numbered from 0
1617     \param ul upper left corner of rectangle
1618     \param lr lower right corner of rectangle
1619 */
rectli_set(PU_RECTL array,int index,U_POINTL ul,U_POINTL lr)1620 void rectli_set(
1621       PU_RECTL array,
1622       int index,
1623       U_POINTL ul,
1624       U_POINTL lr
1625     ){
1626     PU_RECTL rct = &(array[index]);
1627     rct->left     =   ul.x;
1628     rct->top      =   ul.y;
1629     rct->right    =   lr.x;
1630     rct->bottom   =   lr.y;
1631 }
1632 
1633 /**
1634     \brief Set sizel objects with X,Y values.
1635     \param x X coordinate
1636     \param y Y coordinate
1637 */
sizel_set(int32_t x,int32_t y)1638 U_SIZEL sizel_set(
1639        int32_t  x,
1640        int32_t  y
1641     ){
1642     U_SIZEL sz;
1643     sz.cx = x;
1644     sz.cy = y;
1645     return(sz);
1646 }
1647 
1648 /**
1649     \brief Set pointl objects with X,Y values.
1650     \param x X coordinate
1651     \param y Y coordinate
1652 */
point32_set(int32_t x,int32_t y)1653 U_POINTL point32_set(
1654        int32_t  x,
1655        int32_t  y
1656     ){
1657     U_POINTL pt;
1658     pt.x = x;
1659     pt.y = y;
1660     return(pt);
1661 }
1662 
1663 /**
1664     \brief Set point16 objects with 16 bit X,Y values.
1665     \param x X coordinate
1666     \param y Y coordinate
1667 */
point16_set(int16_t x,int16_t y)1668 U_POINT16 point16_set(
1669        int16_t  x,
1670        int16_t  y
1671     ){
1672     U_POINT16 pt;
1673     pt.x = x;
1674     pt.y = y;
1675     return(pt);
1676 }
1677 
1678 /**
1679     \brief Find the bounding rectangle from a polyline of a given width.
1680     \param count  number of points in the polyline
1681     \param pts    the polyline
1682     \param width  width of drawn line
1683 
1684 */
findbounds(uint32_t count,PU_POINT pts,uint32_t width)1685 U_RECT findbounds(
1686       uint32_t count,
1687       PU_POINT pts,
1688       uint32_t width
1689    ){
1690    U_RECT rect={INT32_MAX, INT32_MAX, INT32_MIN, INT32_MIN };
1691    unsigned int i;
1692 
1693    for(i=0; i<count;i++,pts++){
1694        if ( pts->x < rect.left )   rect.left   = pts->x;
1695        if ( pts->x > rect.right )  rect.right  = pts->x;
1696        if ( pts->y < rect.top )    rect.top    = pts->y;
1697        if ( pts->y > rect.bottom ) rect.bottom = pts->y;
1698    }
1699    if(width > 0){
1700      rect.left   -= width;
1701      rect.right  += width;
1702      rect.top    += width;
1703      rect.bottom -= width;
1704    }
1705    return(rect);
1706 }
1707 
1708 /**
1709     \brief Find the bounding rectangle from a polyline of a given width.
1710     \param count  number of points in the polyline
1711     \param pts    the polyline
1712     \param width  width of drawn line
1713 
1714 */
findbounds16(uint32_t count,PU_POINT16 pts,uint32_t width)1715 U_RECT findbounds16(
1716       uint32_t count,
1717       PU_POINT16 pts,
1718       uint32_t width
1719    ){
1720    U_RECT rect={INT16_MAX, INT16_MAX, INT16_MIN, INT16_MIN };
1721    unsigned int i;
1722 
1723    for(i=0; i<count;i++,pts++){
1724        if ( pts->x < rect.left )   rect.left   = pts->x;
1725        if ( pts->x > rect.right )  rect.right  = pts->x;
1726        if ( pts->y < rect.top )    rect.top    = pts->y;
1727        if ( pts->y > rect.bottom ) rect.bottom = pts->y;
1728    }
1729    if(width > 0){
1730      rect.left   -= width;
1731      rect.right  += width;
1732      rect.top    += width;
1733      rect.bottom -= width;
1734    }
1735    return(rect);
1736 }
1737 /**
1738     \brief Construct a U_LOGBRUSH structure.
1739     \return U_LOGBRUSH structure
1740     \param lbStyle   LB_Style Enumeration
1741     \param lbColor   Brush color
1742     \param lbHatch   HatchStyle Enumertaion
1743 */
logbrush_set(uint32_t lbStyle,U_COLORREF lbColor,int32_t lbHatch)1744 U_LOGBRUSH logbrush_set(
1745       uint32_t    lbStyle,
1746       U_COLORREF  lbColor,
1747       int32_t     lbHatch
1748    ){
1749    U_LOGBRUSH lb;
1750    lb.lbStyle = lbStyle;
1751    lb.lbColor = lbColor;
1752    lb.lbHatch = lbHatch;
1753    return(lb);
1754 }
1755 
1756 /**
1757     \brief Construct a U_XFORM structure.
1758     \return U_XFORM structure
1759     \param eM11 Rotation Matrix element
1760     \param eM12 Rotation Matrix element
1761     \param eM21 Rotation Matrix element
1762     \param eM22 Rotation Matrix element
1763     \param eDx  Translation element
1764     \param eDy  Translation element
1765 */
xform_set(U_FLOAT eM11,U_FLOAT eM12,U_FLOAT eM21,U_FLOAT eM22,U_FLOAT eDx,U_FLOAT eDy)1766 U_XFORM xform_set(
1767       U_FLOAT eM11,
1768       U_FLOAT eM12,
1769       U_FLOAT eM21,
1770       U_FLOAT eM22,
1771       U_FLOAT eDx,
1772       U_FLOAT eDy
1773    ){
1774    U_XFORM xform;
1775    xform.eM11 =  eM11;
1776    xform.eM12 =  eM12;
1777    xform.eM21 =  eM21;
1778    xform.eM22 =  eM22;
1779    xform.eDx  =  eDx;
1780    xform.eDy  =  eDy;
1781    return(xform);
1782 }
1783 
1784 /**
1785     \brief Construct a U_XFORM structure.
1786     \return U_XFORM structure
1787     \param scale     Scale factor
1788     \param ratio     Ratio of minor axis/major axis
1789     \param rot       Rotation angle in degrees, positive is counter clockwise from the x axis.
1790     \param axisrot   Angle in degrees defining the major axis before rotation, positive is counter clockwise from the x axis.
1791     \param eDx       Translation element
1792     \param eDy       Translation element
1793 
1794     Operation is:
1795       1  Conformal map of points based on scale, axis rotation, and axis ratio,
1796       2. Apply rotation
1797       3. Apply offset
1798 */
xform_alt_set(U_FLOAT scale,U_FLOAT ratio,U_FLOAT rot,U_FLOAT axisrot,U_FLOAT eDx,U_FLOAT eDy)1799 U_XFORM xform_alt_set(
1800       U_FLOAT scale,
1801       U_FLOAT ratio,
1802       U_FLOAT rot,
1803       U_FLOAT axisrot,
1804       U_FLOAT eDx,
1805       U_FLOAT eDy
1806    ){
1807    U_XFORM xform;
1808    U_MAT2X2 mat1, mat2;
1809    // angles are in degrees, must be in radians
1810    rot     *=  (2.0 * U_PI)/360.0;
1811    axisrot *= -(2.0 * U_PI)/360.0;
1812    mat1.M11 = cos(rot);  // set up the rotation matrix
1813    mat1.M12 = -sin(rot);
1814    mat1.M21 = sin(rot);
1815    mat1.M22 = cos(rot);
1816    if(ratio!=1.0){  // set scale/ellipticity matrix
1817       mat2.M11 =            scale*( cos(axisrot)*cos(axisrot) + ratio*sin(axisrot)*sin(axisrot) );
1818       mat2.M12 = mat2.M21 = scale*( sin(axisrot)*cos(axisrot) * (1.0 - ratio)           );
1819       mat2.M22 =            scale*( sin(axisrot)*sin(axisrot) + ratio*cos(axisrot)*cos(axisrot) );
1820    }
1821    else { // when the ratio is 1.0 then the major axis angle is ignored and only scale matters
1822       mat2.M11 = scale;
1823       mat2.M12 = 0.0;
1824       mat2.M21 = 0.0;
1825       mat2.M22 = scale;
1826    }
1827    xform.eM11 =  mat2.M11 * mat1.M11 + mat2.M12 * mat1.M21;
1828    xform.eM12 =  mat2.M11 * mat1.M12 + mat2.M12 * mat1.M22;;
1829    xform.eM21 =  mat2.M21 * mat1.M11 + mat2.M22 * mat1.M21;
1830    xform.eM22 =  mat2.M21 * mat1.M12 + mat2.M22 * mat1.M22;
1831    xform.eDx  =  eDx;
1832    xform.eDy  =  eDy;
1833    return(xform);
1834 }
1835 
1836 
1837 /**
1838     \brief Construct a U_LOGCOLORSPACEA structure.
1839     \return U_LOGCOLORSPACEA structure
1840     \param lcsCSType     LCS_CSType Enumeration
1841     \param lcsIntent     LCS_Intent Enumeration
1842     \param lcsEndpoints  CIE XYZ color space endpoints
1843     \param lcsGammaRGB   Gamma For RGB
1844     \param lcsFilename   Could name an external color profile file, otherwise empty string
1845 */
logcolorspacea_set(int32_t lcsCSType,int32_t lcsIntent,U_CIEXYZTRIPLE lcsEndpoints,U_LCS_GAMMARGB lcsGammaRGB,char * lcsFilename)1846 U_LOGCOLORSPACEA logcolorspacea_set(
1847       int32_t             lcsCSType,
1848       int32_t             lcsIntent,
1849       U_CIEXYZTRIPLE      lcsEndpoints,
1850       U_LCS_GAMMARGB      lcsGammaRGB,
1851       char                *lcsFilename
1852    ){
1853    U_LOGCOLORSPACEA lcsa;
1854    lcsa.lcsSignature  =    U_LCS_SIGNATURE;
1855    lcsa.lcsVersion    =    U_LCS_SIGNATURE;
1856    lcsa.lcsSize       =    sizeof(U_LOGCOLORSPACEA);
1857    lcsa.lcsCSType     =    lcsCSType;
1858    lcsa.lcsIntent     =    lcsIntent;
1859    lcsa.lcsEndpoints  =    lcsEndpoints;
1860    lcsa.lcsGammaRGB   =    lcsGammaRGB;
1861    strncpy(lcsa.lcsFilename,lcsFilename,U_MAX_PATH);
1862    lcsa.lcsFilename[U_MAX_PATH-1] = '\0';
1863    return(lcsa);
1864 }
1865 
1866 /**
1867 
1868     \brief Construct a U_LOGCOLORSPACEW structure.
1869     \return U_LOGCOLORSPACEW structure
1870     \param lcsCSType     LCS_CSType Enumeration
1871     \param lcsIntent     LCS_Intent Enumeration
1872     \param lcsEndpoints  CIE XYZ color space endpoints
1873     \param lcsGammaRGB   Gamma For RGB
1874     \param lcsFilename   Could name an external color profile file, otherwise empty string
1875 */
logcolorspacew_set(int32_t lcsCSType,int32_t lcsIntent,U_CIEXYZTRIPLE lcsEndpoints,U_LCS_GAMMARGB lcsGammaRGB,uint16_t * lcsFilename)1876 U_LOGCOLORSPACEW logcolorspacew_set(
1877     int32_t             lcsCSType,
1878     int32_t             lcsIntent,
1879     U_CIEXYZTRIPLE      lcsEndpoints,
1880     U_LCS_GAMMARGB      lcsGammaRGB,
1881     uint16_t            *lcsFilename
1882     ){
1883     U_LOGCOLORSPACEW lcsa;
1884     lcsa.lcsSignature  =    U_LCS_SIGNATURE;
1885     lcsa.lcsVersion    =    U_LCS_SIGNATURE;
1886     lcsa.lcsSize       =    sizeof(U_LOGCOLORSPACEW);
1887     lcsa.lcsCSType     =    lcsCSType;
1888     lcsa.lcsIntent     =    lcsIntent;
1889     lcsa.lcsEndpoints  =    lcsEndpoints;
1890     lcsa.lcsGammaRGB   =    lcsGammaRGB;
1891     wchar16strncpypad(lcsa.lcsFilename,lcsFilename,U_MAX_PATH);
1892     lcsa.lcsFilename[U_MAX_PATH-1] = '\0';
1893     return(lcsa);
1894 }
1895 
1896 /**
1897 
1898     \brief Construct a U_PANOSE structure.
1899     \return U_PANOSE structure
1900     \param bFamilyType      FamilyType Enumeration
1901     \param bSerifStyle      SerifType Enumeration
1902     \param bWeight          Weight Enumeration
1903     \param bProportion      Proportion Enumeration
1904     \param bContrast        Contrast Enumeration
1905     \param bStrokeVariation StrokeVariation Enumeration
1906     \param bArmStyle        ArmStyle Enumeration
1907     \param bLetterform      Letterform Enumeration
1908     \param bMidline         Midline Enumeration
1909     \param bXHeight         XHeight Enumeration
1910 */
panose_set(uint8_t bFamilyType,uint8_t bSerifStyle,uint8_t bWeight,uint8_t bProportion,uint8_t bContrast,uint8_t bStrokeVariation,uint8_t bArmStyle,uint8_t bLetterform,uint8_t bMidline,uint8_t bXHeight)1911 U_PANOSE panose_set(
1912       uint8_t bFamilyType,
1913       uint8_t bSerifStyle,
1914       uint8_t bWeight,
1915       uint8_t bProportion,
1916       uint8_t bContrast,
1917       uint8_t bStrokeVariation,
1918       uint8_t bArmStyle,
1919       uint8_t bLetterform,
1920       uint8_t bMidline,
1921       uint8_t bXHeight
1922     ){
1923     U_PANOSE panose;
1924     panose.bFamilyType       = bFamilyType;
1925     panose.bSerifStyle       = bSerifStyle;
1926     panose.bWeight           = bWeight;
1927     panose.bProportion       = bProportion;
1928     panose.bContrast         = bContrast;
1929     panose.bStrokeVariation  = bStrokeVariation;
1930     panose.bArmStyle         = bArmStyle;
1931     panose.bLetterform       = bLetterform;
1932     panose.bMidline          = bMidline;
1933     panose.bXHeight          = bXHeight;
1934     return(panose);
1935 }
1936 
1937 /**
1938     \brief Construct a U_LOGFONT structure.
1939     \return U_LOGFONT structure
1940     \param lfHeight         Height in Logical units
1941     \param lfWidth          Average Width in Logical units
1942     \param lfEscapement     Angle in 0.1 degrees betweem escapement vector and X axis
1943     \param lfOrientation    Angle in 0.1 degrees between baseline and X axis
1944     \param lfWeight         LF_Weight Enumeration
1945     \param lfItalic         Italics:   0 or 1
1946     \param lfUnderline      Underline: 0 or 1
1947     \param lfStrikeOut      Strikeout: 0 or 1
1948     \param lfCharSet        LF_CharSet Enumeration
1949     \param lfOutPrecision   LF_OutPrecision Enumeration
1950     \param lfClipPrecision  LF_ClipPrecision Enumeration
1951     \param lfQuality        LF_Quality Enumeration
1952     \param lfPitchAndFamily LF_PitchAndFamily Enumeration
1953     \param lfFaceName       Name of font. truncates at U_LF_FACESIZE, smaller must be null terminated
1954 
1955 */
logfont_set(int32_t lfHeight,int32_t lfWidth,int32_t lfEscapement,int32_t lfOrientation,int32_t lfWeight,uint8_t lfItalic,uint8_t lfUnderline,uint8_t lfStrikeOut,uint8_t lfCharSet,uint8_t lfOutPrecision,uint8_t lfClipPrecision,uint8_t lfQuality,uint8_t lfPitchAndFamily,uint16_t * lfFaceName)1956 U_LOGFONT logfont_set(
1957     int32_t    lfHeight,
1958     int32_t    lfWidth,
1959     int32_t    lfEscapement,
1960     int32_t    lfOrientation,
1961     int32_t    lfWeight,
1962     uint8_t    lfItalic,
1963     uint8_t    lfUnderline,
1964     uint8_t    lfStrikeOut,
1965     uint8_t    lfCharSet,
1966     uint8_t    lfOutPrecision,
1967     uint8_t    lfClipPrecision,
1968     uint8_t    lfQuality,
1969     uint8_t    lfPitchAndFamily,
1970     uint16_t  *lfFaceName
1971     ){
1972     U_LOGFONT lf;
1973     lf.lfHeight                  = lfHeight;
1974     lf.lfWidth                   = lfWidth;
1975     lf.lfEscapement              = lfEscapement;
1976     lf.lfOrientation             = lfOrientation;
1977     lf.lfWeight                  = lfWeight;
1978     lf.lfItalic                  = lfItalic;
1979     lf.lfUnderline               = lfUnderline;
1980     lf.lfStrikeOut               = lfStrikeOut;
1981     lf.lfCharSet                 = lfCharSet;
1982     lf.lfOutPrecision            = lfOutPrecision;
1983     lf.lfClipPrecision           = lfClipPrecision;
1984     lf.lfQuality                 = lfQuality;
1985     lf.lfPitchAndFamily          = lfPitchAndFamily;
1986     wchar16strncpypad(lf.lfFaceName, lfFaceName, U_LF_FACESIZE); // pad this one as the intial structure was not set to zero
1987     lf.lfFaceName[U_LF_FACESIZE-1] = '\0';
1988     return(lf);
1989 }
1990 
1991 
1992 /**
1993     \brief Construct a U_LOGFONT_PANOSE structure.
1994     \return U_LOGFONT_PANOSE structure
1995     \param elfLogFont    Basic font attributes
1996     \param elfFullName   Font full name, truncates at U_LF_FULLFACESIZE, smaller must be null terminated
1997     \param elfStyle      Font style, truncates at U_LF_FULLFACESIZE, smaller must be null terminated
1998     \param elfStyleSize  Font hinting starting at this point size, if 0, starts at Height
1999     \param elfPanose     Panose Object. If all zero, it is ignored.
2000 */
logfont_panose_set(U_LOGFONT elfLogFont,uint16_t * elfFullName,uint16_t * elfStyle,uint32_t elfStyleSize,U_PANOSE elfPanose)2001 U_LOGFONT_PANOSE logfont_panose_set(
2002       U_LOGFONT   elfLogFont,
2003       uint16_t   *elfFullName,
2004       uint16_t   *elfStyle,
2005       uint32_t    elfStyleSize,
2006       U_PANOSE    elfPanose
2007     ){
2008    U_LOGFONT_PANOSE lfp;
2009    memset(&lfp,0,sizeof(U_LOGFONT_PANOSE)); // all fields zero unless needed.  Many should be ignored or must be 0.
2010    wchar16strncpy(lfp.elfFullName, elfFullName, U_LF_FULLFACESIZE);
2011    lfp.elfFullName[U_LF_FULLFACESIZE-1] = '\0';
2012    wchar16strncpy(lfp.elfStyle,    elfStyle,    U_LF_FACESIZE);
2013    lfp.elfStyle[U_LF_FACESIZE-1] = '\0';
2014    lfp.elfLogFont    =   elfLogFont;
2015    lfp.elfStyleSize  =   elfStyleSize;
2016    lfp.elfPanose     =   elfPanose;
2017    return(lfp);
2018 }
2019 
2020 /**
2021     \brief Construct a U_BITMAPINFOHEADER structure.
2022     \return U_BITMAPINFOHEADER structure
2023     \param biWidth         Bitmap width in pixels
2024     \param biHeight        Bitmap height in pixels
2025     \param biPlanes        Planes (must be 1)
2026     \param biBitCount      BitCount Enumeration
2027     \param biCompression   BI_Compression Enumeration
2028     \param biSizeImage     Size in bytes of image
2029     \param biXPelsPerMeter X Resolution in pixels/meter
2030     \param biYPelsPerMeter Y Resolution in pixels/meter
2031     \param biClrUsed       Number of bmciColors in U_BITMAPCOREINFO
2032     \param biClrImportant  Number of bmciColors needed (0 means all).
2033 */
bitmapinfoheader_set(int32_t biWidth,int32_t biHeight,uint16_t biPlanes,uint16_t biBitCount,uint32_t biCompression,uint32_t biSizeImage,int32_t biXPelsPerMeter,int32_t biYPelsPerMeter,U_NUM_RGBQUAD biClrUsed,uint32_t biClrImportant)2034 U_BITMAPINFOHEADER bitmapinfoheader_set(
2035       int32_t       biWidth,
2036       int32_t       biHeight,
2037       uint16_t      biPlanes,
2038       uint16_t      biBitCount,
2039       uint32_t      biCompression,
2040       uint32_t      biSizeImage,
2041       int32_t       biXPelsPerMeter,
2042       int32_t       biYPelsPerMeter,
2043       U_NUM_RGBQUAD biClrUsed,
2044       uint32_t      biClrImportant
2045     ){
2046     U_BITMAPINFOHEADER Bmi;
2047     Bmi.biSize          = sizeof(U_BITMAPINFOHEADER);
2048     Bmi.biWidth         = biWidth;
2049     Bmi.biHeight        = biHeight;
2050     Bmi.biPlanes        = biPlanes;
2051     Bmi.biBitCount      = biBitCount;
2052     Bmi.biCompression   = biCompression;
2053     Bmi.biSizeImage     = biSizeImage;
2054     Bmi.biXPelsPerMeter = biXPelsPerMeter;
2055     Bmi.biYPelsPerMeter = biYPelsPerMeter;
2056     Bmi.biClrUsed       = biClrUsed;
2057     Bmi.biClrImportant  = biClrImportant;
2058     return(Bmi);
2059 }
2060 
2061 
2062 /**
2063     \brief Allocate and construct a U_BITMAPINFO structure.
2064     \return Pointer to a U_BITMAPINFO structure
2065     \param BmiHeader   Geometry and pixel properties
2066     \param BmiColors   Color table (must be NULL for some  values of BmiHeader->biBitCount)
2067 */
bitmapinfo_set(U_BITMAPINFOHEADER BmiHeader,PU_RGBQUAD BmiColors)2068 PU_BITMAPINFO bitmapinfo_set(
2069       U_BITMAPINFOHEADER  BmiHeader,
2070       PU_RGBQUAD          BmiColors
2071    ){
2072    char *record;
2073    int   irecsize;
2074    int   cbColors, cbColors4, off;
2075 
2076    cbColors  = 4*get_real_color_count((char *) &BmiHeader);
2077    cbColors4 = UP4(cbColors);
2078    irecsize  = sizeof(U_BITMAPINFOHEADER) + cbColors4;
2079    record    = malloc(irecsize);
2080    if(record){
2081      memcpy(record, &BmiHeader, sizeof(U_BITMAPINFOHEADER));
2082      if(cbColors){
2083         off = sizeof(U_BITMAPINFOHEADER);
2084         memcpy(record + off, BmiColors, cbColors);
2085         off += cbColors;
2086         if(cbColors4 - cbColors){  memset(record + off, 0, cbColors4 - cbColors); }
2087      }
2088    }
2089    return((PU_BITMAPINFO) record);
2090 }
2091 
2092 /**
2093     \brief Allocate and construct a U_EXTLOGPEN structure.
2094     \return pointer to U_EXTLOGPEN structure, or NULL on error
2095     \param elpPenStyle   PenStyle Enumeration
2096     \param elpWidth      Width in logical units (elpPenStyle & U_PS_GEOMETRIC) or 1 (pixel)
2097     \param elpBrushStyle LB_Style Enumeration
2098     \param elpColor      Pen color
2099     \param elpHatch      HatchStyle Enumeration
2100     \param elpNumEntries Count of StyleEntry array
2101     \param elpStyleEntry Array of StyleEntry (For user specified dot/dash patterns)
2102 */
extlogpen_set(uint32_t elpPenStyle,uint32_t elpWidth,uint32_t elpBrushStyle,U_COLORREF elpColor,int32_t elpHatch,U_NUM_STYLEENTRY elpNumEntries,U_STYLEENTRY * elpStyleEntry)2103 PU_EXTLOGPEN extlogpen_set(
2104       uint32_t            elpPenStyle,
2105       uint32_t            elpWidth,
2106       uint32_t            elpBrushStyle,
2107       U_COLORREF          elpColor,
2108       int32_t             elpHatch,
2109       U_NUM_STYLEENTRY    elpNumEntries,
2110       U_STYLEENTRY       *elpStyleEntry
2111    ){
2112    int irecsize,szSyleArray;
2113    char *record;
2114 
2115    if(elpNumEntries){
2116      if(!elpStyleEntry)return(NULL);
2117      szSyleArray   = elpNumEntries * sizeof(U_STYLEENTRY);
2118      irecsize = sizeof(U_EXTLOGPEN) + szSyleArray - sizeof(U_STYLEENTRY); // first one is in the record
2119    }
2120    else {
2121      szSyleArray   = 0;
2122      irecsize = sizeof(U_EXTLOGPEN);
2123    }
2124    record   = malloc(irecsize);
2125    if(record){
2126      ((PU_EXTLOGPEN) record)->elpPenStyle    = elpPenStyle;
2127      ((PU_EXTLOGPEN) record)->elpWidth       = elpWidth;
2128      ((PU_EXTLOGPEN) record)->elpBrushStyle  = elpBrushStyle;
2129      ((PU_EXTLOGPEN) record)->elpColor       = elpColor;
2130      ((PU_EXTLOGPEN) record)->elpHatch       = elpHatch;
2131      ((PU_EXTLOGPEN) record)->elpNumEntries  = elpNumEntries;
2132      if(elpNumEntries){ memcpy(((PU_EXTLOGPEN) record)->elpStyleEntry,elpStyleEntry,szSyleArray);   }
2133      else {             memset(((PU_EXTLOGPEN) record)->elpStyleEntry,0,sizeof(U_STYLEENTRY)); }  // not used, but this stops valgrind warnings
2134    }
2135    return((PU_EXTLOGPEN) record);
2136 }
2137 
2138 /**
2139     \brief Construct a U_LOGPEN structure.
2140     \return U_LOGPEN structure
2141     \param lopnStyle PenStyle Enumeration
2142     \param lopnWidth Width of pen set by X, Y is ignored
2143     \param lopnColor Pen color value
2144 
2145 */
logpen_set(uint32_t lopnStyle,U_POINT lopnWidth,U_COLORREF lopnColor)2146 U_LOGPEN logpen_set(
2147       uint32_t     lopnStyle,
2148       U_POINT      lopnWidth,
2149       U_COLORREF   lopnColor
2150    ){
2151    U_LOGPEN lp;
2152    lp.lopnStyle = lopnStyle;
2153    lp.lopnWidth = lopnWidth;
2154    lp.lopnColor = lopnColor;
2155    return(lp);
2156 }
2157 
2158 /**
2159     \brief Construct a U_LOGPLTNTRY structure.
2160     \return U_LOGPLTNTRY structure
2161     \param peReserved Ignore
2162     \param peRed      Palette entry Red Intensity
2163     \param peGreen    Palette entry Green Intensity
2164     \param peBlue     Palette entry Blue Intensity
2165 */
logpltntry_set(uint8_t peReserved,uint8_t peRed,uint8_t peGreen,uint8_t peBlue)2166 U_LOGPLTNTRY logpltntry_set(
2167       uint8_t    peReserved,
2168       uint8_t    peRed,
2169       uint8_t    peGreen,
2170       uint8_t    peBlue
2171    ){
2172    U_LOGPLTNTRY lpny;
2173    lpny.peReserved = peReserved;
2174    lpny.peRed      = peRed;
2175    lpny.peGreen    = peGreen;
2176    lpny.peBlue     = peBlue;
2177    return(lpny);
2178 }
2179 
2180 /**
2181     \brief Allocate and construct a U_LOGPALETTE structure.
2182     \return pointer to U_LOGPALETTE structure, or NULL on error.
2183     \param palNumEntries Number of U_LOGPLTNTRY objects
2184     \param palPalEntry   array, PC_Entry Enumeration
2185 */
logpalette_set(U_NUM_LOGPLTNTRY palNumEntries,PU_LOGPLTNTRY * palPalEntry)2186 PU_LOGPALETTE logpalette_set(
2187       U_NUM_LOGPLTNTRY    palNumEntries,
2188       PU_LOGPLTNTRY      *palPalEntry
2189    ){
2190    PU_LOGPALETTE record;
2191    int cbPalArray,irecsize;
2192 
2193    if(palNumEntries == 0 || !palPalEntry)return(NULL);
2194    cbPalArray = palNumEntries * sizeof(U_LOGPLTNTRY);
2195    irecsize = sizeof(U_LOGPALETTE) + cbPalArray - sizeof(U_LOGPLTNTRY);
2196    record = (PU_LOGPALETTE) malloc(irecsize);
2197    if(irecsize){
2198       record->palVersion    = U_LP_VERSION;
2199       record->palNumEntries = palNumEntries;
2200       memcpy(record->palPalEntry,palPalEntry,cbPalArray);
2201    }
2202    return(record);
2203 }
2204 
2205 /**
2206     \brief Construct a U_RGNDATAHEADER structure.
2207     \return U_RGNDATAHEADER structure
2208     \param nCount  Number of rectangles in region
2209     \param rclBounds Region bounds
2210 */
rgndataheader_set(U_NUM_RECTL nCount,U_RECTL rclBounds)2211 U_RGNDATAHEADER rgndataheader_set(
2212       U_NUM_RECTL         nCount,
2213       U_RECTL             rclBounds
2214    ){
2215    U_RGNDATAHEADER rdh;
2216    rdh.dwSize    = U_RDH_OBJSIZE;
2217    rdh.iType     = U_RDH_RECTANGLES;
2218    rdh.nCount    = nCount;
2219    rdh.nRgnSize  = nCount * sizeof(U_RECTL); // Size in bytes of rectangle array
2220    rdh.rclBounds = rclBounds;
2221    return(rdh);
2222 }
2223 
2224 /**
2225     \brief Allocate and construct a U_RGNDATA structure.
2226     \return pointer to U_RGNDATA structure, or NULL on error.
2227     \param rdh    Data description
2228     \param Buffer Array of U_RECTL elements
2229 */
rgndata_set(U_RGNDATAHEADER rdh,PU_RECTL Buffer)2230 PU_RGNDATA rgndata_set(
2231       U_RGNDATAHEADER     rdh,
2232       PU_RECTL            Buffer
2233    ){
2234    char *record;
2235    int irecsize;
2236    int szRgnArray,off;
2237 
2238    if(!Buffer || !rdh.nCount || !rdh.nRgnSize)return(NULL);
2239    szRgnArray = rdh.nRgnSize;             // size of the U_RECTL array
2240    irecsize = sizeof(U_RGNDATA) + szRgnArray - sizeof(U_RECTL);  // core + array - overlap
2241    record    = malloc(irecsize);
2242    if(record){
2243       memcpy(record, &rdh, sizeof(U_RGNDATAHEADER));
2244       off =  sizeof(U_RGNDATAHEADER);
2245       memcpy(record + off, Buffer, szRgnArray);
2246    }
2247    return((PU_RGNDATA) record);
2248 }
2249 
2250 /**
2251     \brief Construct a U_COLORADJUSTMENT structure.
2252     \return U_COLORADJUSTMENT structure
2253     \param Size            Size of this structure in bytes
2254     \param Flags           ColorAdjustment Enumeration
2255     \param IlluminantIndex Illuminant Enumeration
2256     \param RedGamma        Red   Gamma correction (range:2500:65000, 10000 is no correction)
2257     \param GreenGamma      Green Gamma correction (range:2500:65000, 10000 is no correction)
2258     \param BlueGamma       Blue  Gamma correction (range:2500:65000, 10000 is no correction)
2259     \param ReferenceBlack  Values less than this are black (range:0:4000)
2260     \param ReferenceWhite  Values more than this are white (range:6000:10000)
2261     \param Contrast        Contrast     adjustment (range:-100:100, 0 is no correction)
2262     \param Brightness      Brightness   adjustment (range:-100:100, 0 is no correction)
2263     \param Colorfulness    Colorfulness adjustment (range:-100:100, 0 is no correction)
2264     \param RedGreenTint    Tine         adjustment (range:-100:100, 0 is no correction)
2265 */
coloradjustment_set(uint16_t Size,uint16_t Flags,uint16_t IlluminantIndex,uint16_t RedGamma,uint16_t GreenGamma,uint16_t BlueGamma,uint16_t ReferenceBlack,uint16_t ReferenceWhite,int16_t Contrast,int16_t Brightness,int16_t Colorfulness,int16_t RedGreenTint)2266 U_COLORADJUSTMENT coloradjustment_set(
2267       uint16_t            Size,
2268       uint16_t            Flags,
2269       uint16_t            IlluminantIndex,
2270       uint16_t            RedGamma,
2271       uint16_t            GreenGamma,
2272       uint16_t            BlueGamma,
2273       uint16_t            ReferenceBlack,
2274       uint16_t            ReferenceWhite,
2275       int16_t             Contrast,
2276       int16_t             Brightness,
2277       int16_t             Colorfulness,
2278       int16_t             RedGreenTint
2279    ){
2280    U_COLORADJUSTMENT ca;
2281    ca.caSize            = Size;
2282    ca.caFlags           = Flags;
2283    ca.caIlluminantIndex = IlluminantIndex;
2284    ca.caRedGamma        = U_MNMX(RedGamma,       U_RGB_GAMMA_MIN,       U_RGB_GAMMA_MAX);
2285    ca.caGreenGamma      = U_MNMX(GreenGamma,     U_RGB_GAMMA_MIN,       U_RGB_GAMMA_MAX);
2286    ca.caBlueGamma       = U_MNMX(BlueGamma,      U_RGB_GAMMA_MIN,       U_RGB_GAMMA_MAX);
2287    // Next one is different to eliminate compiler warning -  U_R_B_MIN is 0 and unsigned
2288    ca.caReferenceBlack  = U_MAX( ReferenceBlack, U_REFERENCE_BLACK_MAX);
2289    ca.caReferenceWhite  = U_MNMX(ReferenceWhite, U_REFERENCE_WHITE_MIN, U_REFERENCE_WHITE_MAX);
2290    ca.caContrast        = U_MNMX(Contrast,       U_COLOR_ADJ_MIN,       U_COLOR_ADJ_MAX);
2291    ca.caBrightness      = U_MNMX(Brightness,     U_COLOR_ADJ_MIN,       U_COLOR_ADJ_MAX);
2292    ca.caColorfulness    = U_MNMX(Colorfulness,   U_COLOR_ADJ_MIN,       U_COLOR_ADJ_MAX);
2293    ca.caRedGreenTint    = U_MNMX(RedGreenTint,   U_COLOR_ADJ_MIN,       U_COLOR_ADJ_MAX);
2294    return(ca);
2295 }
2296 
2297 /**
2298     \brief Construct a U_PIXELFORMATDESCRIPTOR structure.
2299     \return U_PIXELFORMATDESCRIPTOR structure
2300     \param dwFlags         PFD_dwFlags Enumeration
2301     \param iPixelType      PFD_iPixelType Enumeration
2302     \param cColorBits      RGBA: total bits per pixel
2303     \param cRedBits        Red   bits per pixel
2304     \param cRedShift       Red   shift to data bits
2305     \param cGreenBits      Green bits per pixel
2306     \param cGreenShift     Green shift to data bits
2307     \param cBlueBits       Blue  bits per pixel
2308     \param cBlueShift      Blue  shift to data bits
2309     \param cAlphaBits      Alpha bits per pixel
2310     \param cAlphaShift     Alpha shift to data bits
2311     \param cAccumBits      Accumulator buffer, total bitplanes
2312     \param cAccumRedBits   Red   accumulator buffer bitplanes
2313     \param cAccumGreenBits Green accumulator buffer bitplanes
2314     \param cAccumBlueBits  Blue  accumulator buffer bitplanes
2315     \param cAccumAlphaBits Alpha accumulator buffer bitplanes
2316     \param cDepthBits      Depth of Z-buffer
2317     \param cStencilBits    Depth of stencil buffer
2318     \param cAuxBuffers     Depth of auxilliary buffers (not supported)
2319     \param iLayerType      PFD_iLayerType Enumeration, may be ignored
2320     \param bReserved       Bits 0:3/4:7 are number of Overlay/Underlay planes
2321     \param dwLayerMask     may be ignored
2322     \param dwVisibleMask   color or index of underlay plane
2323     \param dwDamageMask    may be ignored
2324 */
pixelformatdescriptor_set(uint32_t dwFlags,uint8_t iPixelType,uint8_t cColorBits,uint8_t cRedBits,uint8_t cRedShift,uint8_t cGreenBits,uint8_t cGreenShift,uint8_t cBlueBits,uint8_t cBlueShift,uint8_t cAlphaBits,uint8_t cAlphaShift,uint8_t cAccumBits,uint8_t cAccumRedBits,uint8_t cAccumGreenBits,uint8_t cAccumBlueBits,uint8_t cAccumAlphaBits,uint8_t cDepthBits,uint8_t cStencilBits,uint8_t cAuxBuffers,uint8_t iLayerType,uint8_t bReserved,uint32_t dwLayerMask,uint32_t dwVisibleMask,uint32_t dwDamageMask)2325 U_PIXELFORMATDESCRIPTOR pixelformatdescriptor_set(
2326       uint32_t   dwFlags,
2327       uint8_t    iPixelType,
2328       uint8_t    cColorBits,
2329       uint8_t    cRedBits,
2330       uint8_t    cRedShift,
2331       uint8_t    cGreenBits,
2332       uint8_t    cGreenShift,
2333       uint8_t    cBlueBits,
2334       uint8_t    cBlueShift,
2335       uint8_t    cAlphaBits,
2336       uint8_t    cAlphaShift,
2337       uint8_t    cAccumBits,
2338       uint8_t    cAccumRedBits,
2339       uint8_t    cAccumGreenBits,
2340       uint8_t    cAccumBlueBits,
2341       uint8_t    cAccumAlphaBits,
2342       uint8_t    cDepthBits,
2343       uint8_t    cStencilBits,
2344       uint8_t    cAuxBuffers,
2345       uint8_t    iLayerType,
2346       uint8_t    bReserved,
2347       uint32_t   dwLayerMask,
2348       uint32_t   dwVisibleMask,
2349       uint32_t   dwDamageMask
2350    ){
2351    U_PIXELFORMATDESCRIPTOR pfd;
2352    pfd.nSize           = sizeof(U_PIXELFORMATDESCRIPTOR);
2353    pfd.nVersion        = 1;
2354    pfd.dwFlags         = dwFlags;
2355    pfd.iPixelType      = iPixelType;
2356    pfd.cColorBits      = cColorBits;
2357    pfd.cRedBits        = cRedBits;
2358    pfd.cRedShift       = cRedShift;
2359    pfd.cGreenBits      = cGreenBits;
2360    pfd.cGreenShift     = cGreenShift;
2361    pfd.cBlueBits       = cBlueBits;
2362    pfd.cBlueShift      = cBlueShift;
2363    pfd.cAlphaBits      = cAlphaBits;
2364    pfd.cAlphaShift     = cAlphaShift;
2365    pfd.cAccumBits      = cAccumBits;
2366    pfd.cAccumRedBits   = cAccumRedBits;
2367    pfd.cAccumGreenBits = cAccumGreenBits;
2368    pfd.cAccumBlueBits  = cAccumBlueBits;
2369    pfd.cAccumAlphaBits = cAccumAlphaBits;
2370    pfd.cDepthBits      = cDepthBits;
2371    pfd.cStencilBits    = cStencilBits;
2372    pfd.cAuxBuffers     = cAuxBuffers;
2373    pfd.iLayerType      = iLayerType;
2374    pfd.bReserved       = bReserved;
2375    pfd.dwLayerMask     = dwLayerMask;
2376    pfd.dwVisibleMask   = dwVisibleMask;
2377    pfd.dwDamageMask    = dwDamageMask;
2378    return(pfd);
2379 }
2380 
2381 /**
2382     \brief Allocate and create a U_EMRTEXT structure followed by its variable pieces via a char* pointer.
2383     Dx cannot be NULL, if the calling program has no appropriate values call dx_set() first.
2384     \return char* pointer to U_EMRTEXT structure followed by its variable pieces, or NULL on error
2385     \param ptlReference String start coordinates
2386     \param NumString    Number of characters in string, does NOT include a terminator
2387     \param cbChar       Number of bytes per character
2388     \param String       String to write
2389     \param fOptions     ExtTextOutOptions Enumeration
2390     \param rcl          (Optional, when fOptions & 7) grayed/clipping/opaque rectangle
2391     \param Dx           Character spacing array from the start of the RECORD
2392 */
emrtext_set(U_POINTL ptlReference,U_NUM_STR NumString,uint32_t cbChar,void * String,uint32_t fOptions,U_RECTL rcl,uint32_t * Dx)2393 char *emrtext_set(
2394       U_POINTL         ptlReference,
2395       U_NUM_STR        NumString,
2396       uint32_t         cbChar,
2397       void            *String,
2398       uint32_t         fOptions,
2399       U_RECTL          rcl,
2400       uint32_t        *Dx
2401     ){
2402     int   irecsize,cbDxArray,cbString4,cbString,off;
2403     char *record;
2404     uint32_t *loffDx;
2405 
2406     if(!String)return(NULL);
2407     if(!Dx)return(NULL);
2408     cbString = cbChar * NumString;                   // size of the string in bytes
2409     cbString4 = UP4(cbString);                       // size of the string buffer
2410     cbDxArray = sizeof(uint32_t)*NumString;          // size of Dx array storage
2411     if(fOptions & U_ETO_PDY)cbDxArray += cbDxArray;  // of the Dx buffer, here do both X and Y coordinates
2412     irecsize = sizeof(U_EMRTEXT) + sizeof(uint32_t) + cbString4 + cbDxArray;    // core structure  + offDx + string buf + dx buf
2413     if(!(fOptions & U_ETO_NO_RECT)){ irecsize += sizeof(U_RECTL); } // plus variable U_RECTL, when it is present
2414     record   = malloc(irecsize);
2415     if(record){
2416       ((PU_EMRTEXT)record)->ptlReference    = ptlReference;
2417       ((PU_EMRTEXT)record)->nChars          = NumString;
2418       // pick up ((PU_EMRTEXT)record)->offString later
2419       ((PU_EMRTEXT)record)->fOptions        = fOptions;
2420       off = sizeof(U_EMRTEXT);              // location where variable pieces will start to be written
2421       if(!(fOptions & U_ETO_NO_RECT)){      // variable field, may or may not be present
2422          memcpy(record + off,&rcl, sizeof(U_RECTL));
2423          off += sizeof(U_RECTL);
2424       }
2425       loffDx = (uint32_t *)(record + off);                  // offDx will go here, but we do not know with what value yet
2426       off += sizeof(uint32_t);
2427       memcpy(record + off,String,cbString);                 // copy the string data to its buffer
2428       ((PU_EMRTEXT)record)->offString       = off;          // now save offset in the structure
2429       off += cbString;
2430       if(cbString < cbString4){
2431         memset(record+off,0,cbString4-cbString); // keeps valgrind happy (initialize padding after string)
2432         off += cbString4-cbString;
2433       }
2434       memcpy(record + off, Dx, cbDxArray);                  // copy the Dx data to its buffer
2435       *loffDx = off;                                        // now save offDx to the structure
2436     }
2437     return(record);
2438 }
2439 
2440 
2441 
2442 /* **********************************************************************************************
2443 These functions are simpler or more convenient ways to generate the specified types of EMR records.
2444 Each should be called in preference to the underlying "base" EMR function.
2445 *********************************************************************************************** */
2446 
2447 
2448 /**
2449     \brief Allocate and construct a U_EMRCOMMENT structure with a UTF8 string.
2450     A U_EMRCOMMENT contains application specific data, and that may include contain null characters. This function may be used when the
2451     comment only incluces UT8 text.
2452     \return pointer to U_EMRCOMMENT structure, or NULL on error.
2453     \param string  UTF8 string to store in the comment
2454 
2455 
2456 */
textcomment_set(const char * string)2457 char *textcomment_set(
2458       const char *string
2459    ){
2460    if(!string)return(NULL);
2461    return(U_EMRCOMMENT_set(1 + strlen(string),string));
2462 }
2463 
2464 /**
2465     \brief Allocate and construct a U_EMRDELETEOBJECT structure and also delete the requested object from the table.
2466     Use this function instead of calling U_EMRDELETEOBJECT_set() directly.
2467     \return pointer to U_EMRDELETEOBJECT structure, or NULL on error.
2468     \param ihObject  Pointer to handle to delete.  This value is set to 0 if the function succeeds.
2469     \param eht       EMF handle table
2470 
2471     Note that calling this function should always be conditional on the specifed object being defined.  It is easy to
2472     write a program where deleteobject_set() is called in a sequence where, at the time, we know that ihObject is defined.
2473     Then a later modification, possibly quite far away in the code, causes it to be undefined.  That distant change will
2474     result in a failure when this function reutrns.  That problem cannot be handled here because the only  values which
2475     may be returned are a valid U_EMRDELETEOBJECT record or a NULL, and other errors could result in the NULL.
2476     So the object must be checked before the call.
2477 */
deleteobject_set(uint32_t * ihObject,EMFHANDLES * eht)2478 char *deleteobject_set(
2479       uint32_t    *ihObject,
2480       EMFHANDLES  *eht
2481    ){
2482    uint32_t saveObject=*ihObject;
2483    if(emf_htable_delete(ihObject,eht))return(NULL);  // invalid handle or other problem, cannot be deleted
2484    return(U_EMRDELETEOBJECT_set(saveObject));
2485 }
2486 
2487 /**
2488     \brief Allocate and construct a U_EMRSELECTOBJECT structure, checks that the handle specified is one that can actually be selected.
2489     Use this function instead of calling U_EMRSELECTOBJECT_set() directly.
2490     \return pointer to U_EMRSELECTOBJECT structure, or NULL on error.
2491     \param ihObject  handle to select
2492     \param eht       EMF handle table
2493 */
selectobject_set(uint32_t ihObject,EMFHANDLES * eht)2494 char *selectobject_set(
2495       uint32_t    ihObject,
2496       EMFHANDLES *eht
2497    ){
2498    if(!(U_STOCK_OBJECT & ihObject)){        // not a stock object, those go straight through
2499      if(ihObject > eht->top)return(NULL);   // handle this high is not in the table
2500      if(!eht->table[ihObject])return(NULL); // handle is not in the table, so not active, so cannot be selected
2501    }
2502    return(U_EMRSELECTOBJECT_set(ihObject));
2503 }
2504 
2505 /**
2506     \brief Allocate and construct a U_EMREXTCREATEPEN structure, create a handle and return it.
2507     Use this function instead of calling U_EMREXTCREATEPEN_set() directly.
2508     \return pointer to U_EMREXTCREATEPEN structure, or NULL on error.
2509     \param ihPen handle to be used by new object
2510     \param eht   EMF handle table
2511     \param Bmi   bitmapbuffer
2512     \param cbPx   Size in bytes of pixel array (row stride * height, there may be some padding at the end of each row)
2513     \param Px     pixel array (NULL if cbPx == 0)
2514     \param elp   Pen parameters (Size is Variable!!!!)
2515 */
extcreatepen_set(uint32_t * ihPen,EMFHANDLES * eht,PU_BITMAPINFO Bmi,const uint32_t cbPx,char * Px,PU_EXTLOGPEN elp)2516 char *extcreatepen_set(
2517       uint32_t        *ihPen,
2518       EMFHANDLES      *eht,
2519       PU_BITMAPINFO    Bmi,
2520       const uint32_t   cbPx,
2521       char            *Px,
2522       PU_EXTLOGPEN     elp
2523    ){
2524    if(emf_htable_insert(ihPen, eht))return(NULL);
2525    return(U_EMREXTCREATEPEN_set(*ihPen, Bmi, cbPx, Px, elp ));
2526 }
2527 
2528 /**
2529     \brief Allocate and construct a U_EMRCREATEPEN structure, create a handle and returns it
2530     Use this function instead of calling U_EMRCREATEPEN_set() directly.
2531     \return pointer to U_EMRCREATEPEN structure, or NULL on error.
2532     \param ihPen handle to be used by new object
2533     \param eht   EMF handle table
2534     \param lopn  Pen parameters
2535 */
createpen_set(uint32_t * ihPen,EMFHANDLES * eht,U_LOGPEN lopn)2536 char *createpen_set(
2537       uint32_t   *ihPen,
2538       EMFHANDLES *eht,
2539       U_LOGPEN    lopn
2540    ){
2541    if(emf_htable_insert(ihPen, eht))return(NULL);
2542    return(U_EMRCREATEPEN_set(*ihPen, lopn));
2543 }
2544 
2545 /**
2546     \brief Allocate and construct a U_EMRCREATEBRUSHINDIRECT structure, create a handle and returns it
2547     Use this function instead of calling U_EMRCREATEBRUSHINDIRECT_set() directly.
2548     \return pointer to U_EMRCREATEBRUSHINDIRECT structure, or NULL on error.
2549     \param ihBrush handle to be used by new object
2550     \param eht     EMF handle table
2551     \param lb      Brush parameters
2552 */
createbrushindirect_set(uint32_t * ihBrush,EMFHANDLES * eht,U_LOGBRUSH lb)2553 char *createbrushindirect_set(
2554       uint32_t    *ihBrush,
2555       EMFHANDLES  *eht,
2556       U_LOGBRUSH   lb
2557    ){
2558    if(emf_htable_insert(ihBrush, eht))return(NULL);
2559    return(U_EMRCREATEBRUSHINDIRECT_set(*ihBrush, lb));
2560 }
2561 
2562 /**
2563     \brief Allocate and construct a U_EMRCREATEDIBPATTERNBRUSHPT_set structure, create a handle and returns it
2564     Use this function instead of calling U_EMRCREATEDIBPATTERNBRUSHPT_set() directly.
2565     \return pointer to U_EMRCREATEDIBPATTERNBRUSHPT_set structure, or NULL on error.
2566     \param ihBrush handle to be used by new object
2567     \param eht     EMF handle table
2568     \param iUsage  DIBColors enumeration
2569     \param Bmi     Bitmap info
2570     \param cbPx    Size in bytes of pixel array (row stride * height, there may be some padding at the end of each row)
2571     \param Px      (Optional) bitmapbuffer (pixel array section )
2572 */
createdibpatternbrushpt_set(uint32_t * ihBrush,EMFHANDLES * eht,const uint32_t iUsage,PU_BITMAPINFO Bmi,const uint32_t cbPx,const char * Px)2573 char *createdibpatternbrushpt_set(
2574       uint32_t            *ihBrush,
2575       EMFHANDLES          *eht,
2576       const uint32_t       iUsage,
2577       PU_BITMAPINFO        Bmi,
2578       const uint32_t       cbPx,
2579       const char          *Px
2580 
2581    ){
2582    if(emf_htable_insert(ihBrush, eht))return(NULL);
2583    return(U_EMRCREATEDIBPATTERNBRUSHPT_set(*ihBrush, iUsage, Bmi, cbPx, Px));
2584 }
2585 
2586 /**
2587     \brief Allocate and construct a U_EMRCREATEMONOBRUSH_set structure, create a handle and returns it
2588     Use this function instead of calling U_EMRCREATEMONOBRUSH_set() directly.
2589     \return pointer to U_EMRCREATEMONOBRUSH_set structure, or NULL on error.
2590     \param ihBrush handle to be used by new object
2591     \param eht     EMF handle table
2592     \param iUsage  DIBColors enumeration
2593     \param Bmi     Bitmap info
2594     \param cbPx    Size in bytes of pixel array (row stride * height, there may be some padding at the end of each row)
2595     \param Px      (Optional) bitmapbuffer (pixel array section )
2596 */
createmonobrush_set(uint32_t * ihBrush,EMFHANDLES * eht,const uint32_t iUsage,PU_BITMAPINFO Bmi,const uint32_t cbPx,const char * Px)2597 char *createmonobrush_set(
2598       uint32_t            *ihBrush,
2599       EMFHANDLES          *eht,
2600       const uint32_t       iUsage,
2601       PU_BITMAPINFO        Bmi,
2602       const uint32_t       cbPx,
2603       const char          *Px
2604 
2605    ){
2606    if(emf_htable_insert(ihBrush, eht))return(NULL);
2607    return(U_EMRCREATEMONOBRUSH_set(*ihBrush, iUsage, Bmi, cbPx, Px));
2608 }
2609 
2610 
2611 /**
2612     \brief Allocate and construct a U_EMRCREATECOLORSPACE structure, create a handle and returns it
2613     Use this function instead of calling U_EMRCREATECOLORSPACE_set() directly.
2614     \return pointer to U_EMRCREATECOLORSPACE structure, or NULL on error.
2615     \param ihCS  ColorSpace handle, will be created and returned
2616     \param eht   Pointer to structure holding all EMF handles
2617     \param lcs    ColorSpace parameters
2618 */
createcolorspace_set(uint32_t * ihCS,EMFHANDLES * eht,U_LOGCOLORSPACEA lcs)2619 char *createcolorspace_set(
2620       uint32_t          *ihCS,
2621       EMFHANDLES         *eht,
2622       U_LOGCOLORSPACEA    lcs
2623    ){
2624    if(emf_htable_insert(ihCS, eht))return(NULL);
2625    return(U_EMRCREATECOLORSPACE_set(*ihCS,lcs));
2626 }
2627 
2628 /**
2629     \brief Allocate and construct a U_EMRCREATECOLORSPACEW structure, create a handle and returns it
2630     Use this function instead of calling U_EMRCREATECOLORSPACEW_set() directly.
2631     \return pointer to U_EMRCREATECOLORSPACEW structure, or NULL on error.
2632     \param ihCS    ColorSpace handle, will be created and returned
2633     \param eht     Pointer to structure holding all EMF handles
2634     \param lcs     ColorSpace parameters
2635     \param dwFlags If low bit set Data is present
2636     \param cbData  Number of bytes of theData field.
2637     \param Data    (Optional, dwFlags & 1) color profile data
2638 */
createcolorspacew_set(uint32_t * ihCS,EMFHANDLES * eht,U_LOGCOLORSPACEW lcs,uint32_t dwFlags,U_CBDATA cbData,uint8_t * Data)2639 char *createcolorspacew_set(
2640       uint32_t           *ihCS,
2641       EMFHANDLES         *eht,
2642       U_LOGCOLORSPACEW    lcs,
2643       uint32_t            dwFlags,
2644       U_CBDATA            cbData,
2645       uint8_t            *Data
2646    ){
2647    if(emf_htable_insert(ihCS, eht))return(NULL);
2648    return(U_EMRCREATECOLORSPACEW_set(*ihCS, lcs, dwFlags, cbData, Data));
2649 }
2650 
2651 /**
2652     \brief Allocate and construct a U_EMREXTCREATEFONTINDIRECTW structure, create a handle and returns it
2653     Use this function instead of calling U_EMREXTCREATEFONTINDIRECTW_set() directly.
2654     \return pointer to U_EMREXTCREATEFONTINDIRECTW structure, or NULL on error.
2655     \param ihFont  Font handle, will be created and returned
2656     \param eht     Pointer to structure holding all EMF handles
2657     \param elf     Pointer to Font parameters asPU_LOGFONT
2658     \param elfw    Pointer to Font parameters as U_LOGFONT_PANOSE
2659 */
extcreatefontindirectw_set(uint32_t * ihFont,EMFHANDLES * eht,const char * elf,const char * elfw)2660 char *extcreatefontindirectw_set(
2661       uint32_t   *ihFont,
2662       EMFHANDLES *eht,
2663       const char *elf,
2664       const char *elfw
2665    ){
2666    if(emf_htable_insert(ihFont, eht))return(NULL);
2667    return(U_EMREXTCREATEFONTINDIRECTW_set(*ihFont, elf, elfw));
2668 }
2669 
2670 /**
2671     \brief Allocate and construct a U_EMRCREATEPALETTE structure, create a handle and returns it
2672     Use this function instead of calling U_EMRCREATEPALETTE_set() directly.
2673     \return pointer to U_EMRCREATEPALETTE structure, or NULL on error.
2674     \param ihPal  Palette handle, will be created and returned
2675     \param eht    Pointer to structure holding all EMF handles
2676     \param lgpl   PaletteFont parameters
2677 */
createpalette_set(uint32_t * ihPal,EMFHANDLES * eht,U_LOGPALETTE lgpl)2678 char *createpalette_set(
2679       uint32_t     *ihPal,
2680       EMFHANDLES   *eht,
2681       U_LOGPALETTE  lgpl
2682    ){
2683   if(emf_htable_insert(ihPal, eht))return(NULL);
2684    return(U_EMRCREATEPALETTE_set(*ihPal, lgpl));
2685 }
2686 
2687 /**
2688     \brief Allocate and construct a U_EMRSETPALETTEENTRIES structure, create a handle and returns it
2689     Use this function instead of calling U_EMRSETPALETTEENTRIES_set() directly.
2690     \return pointer to U_EMRSETPALETTEENTRIES structure, or NULL on error.
2691     \param ihPal       Palette handle, will be created and returned
2692     \param eht         Pointer to structure holding all EMF handles
2693     \param iStart      First Palette entry in selected object to set
2694     \param cEntries    Number of Palette entries in selected object to set
2695     \param aPalEntries Values to set with
2696 */
setpaletteentries_set(uint32_t * ihPal,EMFHANDLES * eht,const uint32_t iStart,const U_NUM_LOGPLTNTRY cEntries,const PU_LOGPLTNTRY aPalEntries)2697 char *setpaletteentries_set(
2698       uint32_t               *ihPal,
2699       EMFHANDLES             *eht,
2700       const uint32_t         iStart,
2701       const U_NUM_LOGPLTNTRY cEntries,
2702       const PU_LOGPLTNTRY    aPalEntries
2703    ){
2704    if(emf_htable_insert(ihPal, eht))return(NULL);
2705    return(U_EMRSETPALETTEENTRIES_set(*ihPal, iStart, cEntries, aPalEntries));
2706 }
2707 
2708 /**
2709     \brief Allocate and construct a U_EMRFILLRGN structure, create a handle and returns it
2710     Use this function instead of calling U_EMRFILLRGN_set() directly.
2711     \return pointer to U_EMRFILLRGN structure, or NULL on error.
2712     \param ihBrush   Brush handle, will be created and returned
2713     \param eht       Pointer to structure holding all EMF handles
2714     \param rclBounds Bounding rectangle in device units
2715     \param RgnData   Pointer to a U_RGNDATA structure
2716 */
fillrgn_set(uint32_t * ihBrush,EMFHANDLES * eht,const U_RECTL rclBounds,const PU_RGNDATA RgnData)2717 char *fillrgn_set(
2718       uint32_t         *ihBrush,
2719       EMFHANDLES       *eht,
2720       const U_RECTL     rclBounds,
2721       const PU_RGNDATA  RgnData
2722    ){
2723    if(emf_htable_insert(ihBrush, eht))return(NULL);
2724    return(U_EMRFILLRGN_set(rclBounds, *ihBrush, RgnData));
2725 }
2726 
2727 /**
2728     \brief Allocate and construct a U_EMRFRAMERGN structure, create a handle and returns it
2729     Use this function instead of calling U_EMRFRAMERGN_set() directly.
2730     \return pointer to U_EMRFRAMERGN structure, or NULL on error.
2731     \param ihBrush   Brush handle, will be created and returned
2732     \param eht       Pointer to structure holding all EMF handles
2733     \param rclBounds Bounding rectangle in device units
2734     \param szlStroke W & H of Brush stroke
2735     \param RgnData   Pointer to a U_RGNDATA structure
2736 */
framergn_set(uint32_t * ihBrush,EMFHANDLES * eht,const U_RECTL rclBounds,const U_SIZEL szlStroke,const PU_RGNDATA RgnData)2737 char *framergn_set(
2738       uint32_t         *ihBrush,
2739       EMFHANDLES       *eht,
2740       const U_RECTL     rclBounds,
2741       const U_SIZEL     szlStroke,
2742       const PU_RGNDATA  RgnData
2743    ){
2744    if(emf_htable_insert(ihBrush, eht))return(NULL);
2745    return(U_EMRFRAMERGN_set(rclBounds, *ihBrush, szlStroke, RgnData));
2746 }
2747 
2748 /**
2749     \brief Allocate and construct an array of U_POINT objects which has been subjected to a U_XFORM
2750     \returns pointer to an array of U_POINT structures.
2751     \param points  pointer to the source U_POINT structures
2752     \param count   number of members in points
2753     \param xform   U_XFORM to apply
2754 
2755     May also be used to modify U_RECT by doubling the count and casting the pointer.
2756 */
points_transform(PU_POINT points,int count,U_XFORM xform)2757 PU_POINT points_transform(PU_POINT points, int count, U_XFORM xform){
2758    PU_POINT newpts;
2759    int i;
2760    float x,y;
2761    newpts = (PU_POINT) malloc(count * sizeof(U_POINT));
2762    for(i=0; i<count; i++){
2763       x = (float) points[i].x;
2764       y = (float) points[i].y;
2765       newpts[i].x = U_ROUND(x * xform.eM11 + y * xform.eM21 + xform.eDx);
2766       newpts[i].y = U_ROUND(x * xform.eM12 + y * xform.eM22 + xform.eDy);
2767    }
2768    return(newpts);
2769 }
2770 
2771 /**
2772     \brief Allocate and construct an array of U_POINT16 objects  which has been subjected to a U_XFORM
2773     \returns pointer to an array of U_POINT16 structures.
2774     \param points  pointer to the source U_POINT16 structures
2775     \param count   number of members in points
2776     \param xform   U_XFORM to apply
2777 
2778     Transformed src points {x0,y0} appear at {x0*xscale + x, y0*yscale + y}
2779 */
point16_transform(PU_POINT16 points,int count,U_XFORM xform)2780 PU_POINT16 point16_transform(PU_POINT16 points, int count, U_XFORM xform){
2781    PU_POINT16 newpts;
2782    int i;
2783    float x,y;
2784    newpts = (PU_POINT16) malloc(count * sizeof(U_POINT16));
2785    for(i=0; i<count; i++){
2786       x = (float) points[i].x;
2787       y = (float) points[i].y;
2788       newpts[i].x = U_ROUND(x * xform.eM11 + y * xform.eM21 + xform.eDx);
2789       newpts[i].y = U_ROUND(x * xform.eM12 + y * xform.eM22 + xform.eDy);
2790    }
2791    return(newpts);
2792 }
2793 
2794 /**
2795     \brief Allocate and construct an array of U_TRIVERTEX objects  which has been subjected to a U_XFORM
2796     \returns pointer to an array of U_TRIVERTEX structures.
2797     \param tv  pointer to the source U_TRIVERTEX structures
2798     \param count   number of members in points
2799     \param xform   U_XFORM to apply
2800 
2801     Transformed Trivertex points {x0,y0} appear at {x0*xscale + x, y0*yscale + y}
2802 */
trivertex_transform(PU_TRIVERTEX tv,int count,U_XFORM xform)2803 PU_TRIVERTEX trivertex_transform(PU_TRIVERTEX tv, int count, U_XFORM xform){
2804    PU_TRIVERTEX newtvs;
2805    int i;
2806    float x,y;
2807    newtvs = (PU_TRIVERTEX) malloc(count * sizeof(U_TRIVERTEX));
2808    for(i=0; i<count; i++){
2809       x = (float) tv[i].x;
2810       y = (float) tv[i].y;
2811       newtvs[i]   = tv[i];
2812       newtvs[i].x = U_ROUND(x * xform.eM11 + y * xform.eM21 + xform.eDx);
2813       newtvs[i].y = U_ROUND(x * xform.eM12 + y * xform.eM22 + xform.eDy);
2814    }
2815    return(newtvs);
2816 }
2817 
2818 /**
2819     \brief Allocate and construct an array of U_POINT objects from a set of U_POINT16 objects
2820     \returns pointer to an array of U_POINT structures.
2821     \param points  pointer to the source U_POINT16 structures
2822     \param count   number of members in points
2823 
2824 */
point16_to_point(PU_POINT16 points,int count)2825 PU_POINT point16_to_point(PU_POINT16 points, int count){
2826    PU_POINT newpts;
2827    int i;
2828    newpts = (PU_POINT) malloc(count * sizeof(U_POINT));
2829    for(i=0; i<count; i++){
2830       newpts[i].x = points[i].x;
2831       newpts[i].y = points[i].y;
2832    }
2833    return(newpts);
2834 }
2835 
2836 /**
2837     \brief Allocate and construct an array of U_POINT16 objects from a set of U_POINT objects
2838     \returns pointer to an array of U_POINT16 structures.
2839     \param points  pointer to the source U_POINT structures
2840     \param count   number of members in points
2841 
2842     If a coordinate is out of range it saturates at boundary.
2843 */
point_to_point16(PU_POINT points,int count)2844 PU_POINT16 point_to_point16(PU_POINT points, int count){
2845    PU_POINT16 newpts;
2846    int i;
2847    newpts = (PU_POINT16) malloc(count * sizeof(U_POINT16));
2848    for(i=0; i<count; i++){
2849       newpts[i].x = U_MNMX(points[i].x, INT16_MIN, INT16_MAX);
2850       newpts[i].y = U_MNMX(points[i].y, INT16_MIN, INT16_MAX);
2851    }
2852    return(newpts);
2853 }
2854 
2855 // hide these from Doxygen
2856 //! @cond
2857 /* **********************************************************************************************
2858 These functions contain shared code used by various U_EMR*_set functions.  These should NEVER be called
2859 by end user code and to further that end prototypes are NOT provided and they are hidden from Doxygen.
2860 
2861 
2862    These are (mostly) ordered by U_EMR_* index number.
2863    For all _set functions the caller must eventually call free() on the returned pointer.
2864 
2865     CORE1(uint32_t iType, U_RECTL rclBounds, const uint32_t cptl, const U_POINTL *points){
2866     CORE2(uint32_t iType, U_RECTL rclBounds, const uint32_t nPolys, const uint32_t *aPolyCounts,const uint32_t cptl, const U_POINTL *points){
2867     CORE3(uint32_t iType, uint32_t iMode){       (generic 1 uint)
2868     CORE4(uint32_t iType, U_RECTL rclBox){
2869     CORE5(uint32_t iType){                       (generic noargs)
2870     CORE6(uint32_t iType, U_RECTL rclBounds, const uint32_t cpts, const U_POINT16 *points){  (16bit form of CORE1)
2871     CORE7(uint32_t iType, U_PAIR pair){
2872     CORE8(uint32_t iType, U_RECTL rclBounds, uint32_t iGraphicsMode, U_FLOAT exScale, U_FLOAT eyScale, PU_EMRTEXT emrtext){
2873     CORE9(uint32_t iType, U_RECTL rclBox, U_POINTL ptlStart, U_POINTL ptlEnd){
2874     CORE10(uint32_t iType, U_RECTL rclBounds, const uint32_t nPolys, const uint32_t *aPolyCounts,const uint32_t cpts, const U_POINT16 *points){ (16bit form of CORE2)
2875     CORE11(uint32_t iType, PU_RGNDATA RgnData){
2876     CORE12(uint32_t iType, uint32_t ihBrush, uint32_t iUsage, PU_BITMAPINFO Bmi){
2877     CORE13(uint32_t iType, U_RECTL rclBounds, U_POINTL Dest, U_POINTL cDest,
2878               U_POINTL Src, U_POINTL cSrc, U_XFORM xformSrc, U_COLORREF crBkColorSrc, uint32_t iUsageSrc,
2879               uint32_t Data, PU_BITMAPINFO Bmi);
2880 *********************************************************************************************** */
2881 
2882 
2883 // Functions with the same form starting with U_EMRPOLYBEZIER_set
U_EMR_CORE1_set(uint32_t iType,U_RECTL rclBounds,const uint32_t cptl,const U_POINTL * points)2884 char *U_EMR_CORE1_set(uint32_t iType, U_RECTL rclBounds, const uint32_t cptl, const U_POINTL *points){
2885    char *record;
2886    int   cbPoints;
2887    int   irecsize;
2888 
2889    cbPoints    = sizeof(U_POINTL)*cptl;
2890    irecsize = sizeof(U_EMRPOLYBEZIER) + cbPoints - sizeof(U_POINTL); // First instance is in struct
2891    record    = malloc(irecsize);
2892    if(record){
2893       ((PU_EMR)           record)->iType     = iType;
2894       ((PU_EMR)           record)->nSize     = irecsize;
2895       ((PU_EMRPOLYBEZIER) record)->rclBounds = rclBounds;
2896       ((PU_EMRPOLYBEZIER) record)->cptl      = cptl;
2897       memcpy(((PU_EMRPOLYBEZIER) record)->aptl,points,cbPoints);
2898    }
2899    return(record);
2900 }
2901 
2902 // Functions with the same form starting with U_EMR_POLYPOLYLINE
U_EMR_CORE2_set(uint32_t iType,U_RECTL rclBounds,const uint32_t nPolys,const uint32_t * aPolyCounts,const uint32_t cptl,const U_POINTL * points)2903 char *U_EMR_CORE2_set(uint32_t iType, U_RECTL rclBounds, const uint32_t nPolys, const uint32_t *aPolyCounts,const uint32_t cptl, const U_POINTL *points){
2904    char *record;
2905    int   cbPolys,cbPoints,off;
2906    int   irecsize;
2907 
2908    cbPoints    = sizeof(U_POINTL)*cptl;
2909    cbPolys    = sizeof(uint32_t)*nPolys;
2910    irecsize = sizeof(U_EMRPOLYPOLYLINE) + cbPoints + cbPolys - sizeof(uint32_t); // First instance of each is in struct
2911    record   = malloc(irecsize);
2912    if(record){
2913       ((PU_EMR)             record)->iType     = iType;
2914       ((PU_EMR)             record)->nSize     = irecsize;
2915       ((PU_EMRPOLYPOLYLINE) record)->rclBounds = rclBounds;
2916       ((PU_EMRPOLYPOLYLINE) record)->nPolys    = nPolys;
2917       ((PU_EMRPOLYPOLYLINE) record)->cptl      = cptl;
2918       memcpy(((PU_EMRPOLYPOLYLINE) record)->aPolyCounts,aPolyCounts,cbPolys);
2919       off = sizeof(U_EMRPOLYPOLYLINE) - 4 + cbPolys;
2920       memcpy(record + off,points,cbPoints);
2921    }
2922    return(record);
2923 }
2924 
2925 // Functions with the same form starting with U_EMR_SETMAPMODE_set
U_EMR_CORE3_set(uint32_t iType,uint32_t iMode)2926 char *U_EMR_CORE3_set(uint32_t iType, uint32_t iMode){
2927    char *record;
2928    int   irecsize;
2929 
2930    irecsize = sizeof(U_EMRSETMAPMODE);
2931    record   = malloc(irecsize);
2932    if(record){
2933       ((PU_EMR)          record)->iType     = iType;
2934       ((PU_EMR)          record)->nSize     = irecsize;
2935       ((PU_EMRSETMAPMODE)record)->iMode     = iMode;
2936    }
2937    return(record);
2938 }
2939 
2940 // Functions taking a single U_RECT or U_RECTL, starting with U_EMRELLIPSE_set, also U_EMRFILLPATH,
U_EMR_CORE4_set(uint32_t iType,U_RECTL rclBox)2941 char *U_EMR_CORE4_set(uint32_t iType, U_RECTL rclBox){
2942    char *record;
2943    int   irecsize;
2944 
2945    irecsize = sizeof(U_EMRELLIPSE);
2946    record   = malloc(irecsize);
2947    memset(record,0,irecsize);
2948    if(record){
2949       ((PU_EMR)       record)->iType  = iType;
2950       ((PU_EMR)       record)->nSize  = irecsize;
2951       ((PU_EMRELLIPSE)record)->rclBox = rclBox;  // bounding rectangle in logical units
2952    }
2953    return(record);
2954 }
2955 
2956 // Functions with the same form starting with U_EMRSETMETARGN_set
U_EMR_CORE5_set(uint32_t iType)2957 char *U_EMR_CORE5_set(uint32_t iType){
2958    char *record;
2959    int   irecsize = 8;
2960 
2961    record   = malloc(irecsize);
2962    if(record){
2963       ((PU_EMR)       record)->iType  = iType;
2964       ((PU_EMR)       record)->nSize  = irecsize;
2965    }
2966    return(record);
2967 }
2968 
2969 // Functions with the same form starting with U_EMRPOLYBEZIER16_set
U_EMR_CORE6_set(uint32_t iType,U_RECTL rclBounds,const uint32_t cpts,const U_POINT16 * points)2970 char *U_EMR_CORE6_set(uint32_t iType, U_RECTL rclBounds, const uint32_t cpts, const U_POINT16 *points){
2971    char *record;
2972    int   cbPoints,cbPoints4,off;
2973    int   irecsize;
2974 
2975    cbPoints   = sizeof(U_POINT16)*cpts;
2976    cbPoints4   = UP4(cbPoints);
2977    off      = sizeof(U_EMR) + sizeof(U_RECTL) + sizeof(U_NUM_POINT16); // offset to the start of the variable region
2978    irecsize = off + cbPoints4; // First instance is in struct
2979    record    = malloc(irecsize);
2980    if(record){
2981       ((PU_EMR)             record)->iType     = iType;
2982       ((PU_EMR)             record)->nSize     = irecsize;
2983       ((PU_EMRPOLYBEZIER16) record)->rclBounds = rclBounds;
2984       ((PU_EMRPOLYBEZIER16) record)->cpts      = cpts;
2985       memcpy(record + off, points, cbPoints);
2986       if(cbPoints < cbPoints4){
2987          off += cbPoints;
2988          memset(record + off, 0, cbPoints4 - cbPoints);
2989       }
2990    }
2991    return(record);
2992 }
2993 
2994 
2995 // Functions that take a single struct argument which contains two uint32_t, starting with U_EMRSETWINDOWEXTEX_set
2996 // these all pass two 32 bit ints and are cast by the caller to U_PAIR
U_EMR_CORE7_set(uint32_t iType,U_PAIR pair)2997 char *U_EMR_CORE7_set(uint32_t iType, U_PAIR pair){
2998    char *record;
2999    int   irecsize = sizeof(U_EMRGENERICPAIR);
3000 
3001    record   = malloc(irecsize);
3002    if(record){
3003       ((PU_EMR)           record)->iType   = iType;
3004       ((PU_EMR)           record)->nSize   = irecsize;
3005       ((PU_EMRGENERICPAIR)record)->pair    = pair;
3006    }
3007    return(record);
3008 }
3009 
3010 // For U_EMREXTTEXTOUTA and U_EMREXTTEXTOUTW
U_EMR_CORE8_set(uint32_t iType,U_RECTL rclBounds,uint32_t iGraphicsMode,U_FLOAT exScale,U_FLOAT eyScale,PU_EMRTEXT emrtext)3011 char *U_EMR_CORE8_set(
3012        uint32_t            iType,
3013        U_RECTL             rclBounds,          // Bounding rectangle in device units
3014        uint32_t            iGraphicsMode,      // Graphics mode Enumeration
3015        U_FLOAT             exScale,            // scale to 0.01 mm units ( only if iGraphicsMode & GM_COMPATIBLE)
3016        U_FLOAT             eyScale,            // scale to 0.01 mm units ( only if iGraphicsMode & GM_COMPATIBLE)
3017        PU_EMRTEXT          emrtext             // Text parameters
3018    ){
3019    char *record;
3020    int   irecsize,cbString,cbString4,cbDx,cbEmrtext,cbEmrtextAll;
3021    uint32_t *loffDx;
3022    int  csize;
3023 
3024    if(     iType == U_EMR_EXTTEXTOUTA){ csize = 1; } // how many bytes per character
3025    else if(iType == U_EMR_EXTTEXTOUTW){ csize = 2; }
3026    else { return(NULL); }
3027 
3028    cbString = csize * emrtext->nChars;
3029    cbString4 = UP4(cbString);                                   // size of the string buffer
3030    cbEmrtext = sizeof(U_EMRTEXT);                             // size of the constant part of the U_EMRTEXT structure
3031    if(!(emrtext->fOptions & U_ETO_NO_RECT)){ cbEmrtext += sizeof(U_RECTL); } // plus the variable U_RECTL, when it is present
3032    cbDx = emrtext->nChars * sizeof(int32_t);             // size of Dx buffer
3033    if(emrtext->fOptions & U_ETO_PDY)cbDx += cbDx;      // size of Dx buffer when both x and y offsets are used
3034    cbEmrtextAll = cbEmrtext + sizeof(uint32_t) + cbString4 + cbDx;   // structure (+- rect) + offDx + string buf + dx buf + offDx
3035 
3036    /* adjust offset fields in emrtext to match the EMRTEXTOUT* field, currently they match EMRTEXT.
3037       This works because the variable pieces have all been moved outside of the U_EMRTEXT and U_EMRTEXTOUTA strutures.
3038    */
3039    ((PU_EMRTEXT)emrtext)->offString  += sizeof(U_EMREXTTEXTOUTA) - sizeof(U_EMRTEXT);   // adjust offString
3040     loffDx = (uint32_t *)((char *)emrtext + cbEmrtext);
3041     *loffDx += sizeof(U_EMREXTTEXTOUTA) - sizeof(U_EMRTEXT);
3042 
3043    // final record size is: U_EMREXTTEXTOUTA (includes constant part of U_EMRTEXT) + U_RECTL (if present) + offDx + dx buffer + string buffer
3044    irecsize = sizeof(U_EMREXTTEXTOUTA) + cbEmrtextAll - sizeof(U_EMRTEXT); // do not count core emrtext strcture twice
3045    record    = malloc(irecsize);
3046    if(record){
3047       ((PU_EMR)            record)->iType         = iType;
3048       ((PU_EMR)            record)->nSize         = irecsize;
3049       ((PU_EMREXTTEXTOUTA) record)->iGraphicsMode = iGraphicsMode;
3050       ((PU_EMREXTTEXTOUTA) record)->rclBounds     = rclBounds;
3051       ((PU_EMREXTTEXTOUTA) record)->exScale       = exScale;
3052       ((PU_EMREXTTEXTOUTA) record)->eyScale       = eyScale;
3053       // copy the adjusted U_EMRTEXT into the emrtext part of the full record..
3054       memcpy(&(((PU_EMREXTTEXTOUTA) record)->emrtext), emrtext, cbEmrtextAll);
3055    }
3056    return(record);
3057 }
3058 
3059 // Functions that take a rect and a pair of points, starting with U_EMRARC_set
U_EMR_CORE9_set(uint32_t iType,U_RECTL rclBox,U_POINTL ptlStart,U_POINTL ptlEnd)3060 char *U_EMR_CORE9_set(uint32_t iType, U_RECTL rclBox, U_POINTL ptlStart, U_POINTL ptlEnd){
3061    char *record;
3062    int   irecsize = sizeof(U_EMRARC);
3063 
3064    record   = malloc(irecsize);
3065    if(record){
3066       ((PU_EMR)           record)->iType    = iType;
3067       ((PU_EMR)           record)->nSize    = irecsize;
3068       ((PU_EMRARC)        record)->rclBox   = rclBox;
3069       ((PU_EMRARC)        record)->ptlStart = ptlStart;
3070       ((PU_EMRARC)        record)->ptlEnd   = ptlEnd;
3071    }
3072    return(record);
3073 }
3074 
3075 // Functions with the same form starting with U_EMR_POLYPOLYLINE16
U_EMR_CORE10_set(uint32_t iType,U_RECTL rclBounds,const uint32_t nPolys,const uint32_t * aPolyCounts,const uint32_t cpts,const U_POINT16 * points)3076 char *U_EMR_CORE10_set(uint32_t iType, U_RECTL rclBounds, const uint32_t nPolys, const uint32_t *aPolyCounts,const uint32_t cpts, const U_POINT16 *points){
3077    char *record;
3078    int   cbPoints,cbPolys,off;
3079    int   irecsize;
3080 
3081    cbPolys  = sizeof(uint32_t)*nPolys;
3082    cbPoints = sizeof(U_POINT16)*cpts;
3083    irecsize = sizeof(U_EMRPOLYPOLYLINE16) + cbPoints + cbPolys - sizeof(uint32_t); // First instance of each is in struct
3084    record   = malloc(irecsize);
3085    if(record){
3086       ((PU_EMR)               record)->iType     = iType;
3087       ((PU_EMR)               record)->nSize     = irecsize;
3088       ((PU_EMRPOLYPOLYLINE16) record)->rclBounds = rclBounds;
3089       ((PU_EMRPOLYPOLYLINE16) record)->nPolys    = nPolys;
3090       ((PU_EMRPOLYPOLYLINE16) record)->cpts      = cpts;
3091       memcpy(((PU_EMRPOLYPOLYLINE16) record)->aPolyCounts,aPolyCounts,cbPolys);
3092       off = sizeof(U_EMRPOLYPOLYLINE16) - 4 + cbPolys;
3093       memcpy(record + off,points,cbPoints);
3094    }
3095    return(record);
3096 }
3097 
3098 // common code for U_EMRINVERTRGN and U_EMRPAINTRGN,
U_EMR_CORE11_set(uint32_t iType,PU_RGNDATA RgnData)3099 char *U_EMR_CORE11_set(uint32_t iType, PU_RGNDATA RgnData){
3100    char *record;
3101    int   irecsize;
3102    int   cbRgns,cbRgns4,rds,rds4,off;
3103 
3104    if(!RgnData)return(NULL);
3105    cbRgns   = ((PU_RGNDATAHEADER) RgnData)->nRgnSize;
3106    cbRgns4  = UP4(cbRgns);
3107    rds      = sizeof(U_RGNDATAHEADER) + cbRgns;
3108    rds4     = UP4(rds);
3109    irecsize = sizeof(U_EMRINVERTRGN) - sizeof(U_RECTL) + cbRgns4;  // core + array - overlap of one rectL
3110    record    = malloc(irecsize);
3111    if(record){
3112       ((PU_EMR)           record)->iType     = iType;
3113       ((PU_EMR)           record)->nSize     = irecsize;
3114       ((PU_EMRINVERTRGN)  record)->rclBounds = ((PU_RGNDATAHEADER) RgnData)->rclBounds;
3115       ((PU_EMRINVERTRGN)  record)->cbRgnData = rds;
3116       off = sizeof(U_EMRINVERTRGN) - sizeof(U_RGNDATA);
3117       memcpy(record + off, RgnData, rds);
3118       off += rds;
3119       if(rds < rds4){ memset(record + off,0, rds4 - rds); } // clear any unused bytes
3120    }
3121    return(record);
3122 }
3123 
3124 
3125 // common code for U_EMRCREATEMONOBRUSH_set and U_EMRCREATEDIBPATTERNBRUSHPT_set,
U_EMR_CORE12_set(uint32_t iType,uint32_t ihBrush,uint32_t iUsage,PU_BITMAPINFO Bmi,const uint32_t cbPx,const char * Px)3126 char *U_EMR_CORE12_set(
3127        uint32_t            iType,
3128        uint32_t            ihBrush,            // Index to place object in EMF object table (this entry must not yet exist)
3129        uint32_t            iUsage,             // DIBcolors Enumeration
3130        PU_BITMAPINFO       Bmi,                // (Optional) bitmapbuffer (U_BITMAPINFO + pixel array)
3131        const uint32_t      cbPx,               // Size in bytes of pixel array (row stride * height, there may be some padding at the end of each row)
3132        const char         *Px                  // (Optional) bitmapbuffer (pixel array section )
3133    ){
3134    char *record;
3135    int   irecsize;
3136    int   cbImage,cbImage4,cbBmi,off;
3137 
3138    SET_CB_FROM_PXBMI(Px,Bmi,cbImage,cbImage4,cbBmi,cbPx);
3139 
3140    irecsize = sizeof(U_EMRCREATEMONOBRUSH) + cbBmi + cbImage4;
3141    record   = malloc(irecsize);
3142    if(record){
3143       ((PU_EMR)                      record)->iType   = iType;
3144       ((PU_EMR)                      record)->nSize   = irecsize;
3145       ((PU_EMRCREATEMONOBRUSH)       record)->ihBrush = ihBrush;
3146       ((PU_EMRCREATEMONOBRUSH)       record)->iUsage  = iUsage;
3147       if(cbBmi){
3148          off = sizeof(U_EMRCREATEMONOBRUSH);
3149          memcpy(record + off, Bmi, cbBmi);
3150          ((PU_EMRCREATEMONOBRUSH)    record)->offBmi  = off;
3151          ((PU_EMRCREATEMONOBRUSH)    record)->cbBmi   = cbBmi;
3152          off += cbBmi;
3153          memcpy(record + off, Px, cbPx);
3154          ((PU_EMRCREATEMONOBRUSH)    record)->offBits = off;
3155          ((PU_EMRCREATEMONOBRUSH)    record)->cbBits  = cbImage;
3156       }
3157       else {
3158          ((PU_EMRCREATEMONOBRUSH)    record)->offBmi  = 0;
3159          ((PU_EMRCREATEMONOBRUSH)    record)->cbBmi   = 0;
3160          ((PU_EMRCREATEMONOBRUSH)    record)->offBits = 0;
3161          ((PU_EMRCREATEMONOBRUSH)    record)->cbBits  = 0;
3162       }
3163    }
3164    return(record);
3165 }
3166 
3167 // common code for U_EMRBLEND_set and U_EMRTRANSPARENTBLT_set,
U_EMR_CORE13_set(uint32_t iType,U_RECTL rclBounds,U_POINTL Dest,U_POINTL cDest,U_POINTL Src,U_POINTL cSrc,U_XFORM xformSrc,U_COLORREF crBkColorSrc,uint32_t iUsageSrc,uint32_t Data,const PU_BITMAPINFO Bmi,const uint32_t cbPx,char * Px)3168 char *U_EMR_CORE13_set(
3169       uint32_t             iType,
3170       U_RECTL              rclBounds,       // Bounding rectangle in device units
3171       U_POINTL             Dest,            // Destination UL corner in logical units
3172       U_POINTL             cDest,           // Destination width in logical units
3173       U_POINTL             Src,             // Source UL corner in logical units
3174       U_POINTL             cSrc,            // Src W & H in logical units
3175       U_XFORM              xformSrc,        // Transform to apply to source
3176       U_COLORREF           crBkColorSrc,    // Background color
3177       uint32_t             iUsageSrc,       // DIBcolors Enumeration
3178       uint32_t             Data,            // The meaning and type of this field varies, but it is always 4 bytes
3179       const PU_BITMAPINFO  Bmi,             // (Optional) bitmapbuffer (U_BITMAPINFO section)
3180       const uint32_t       cbPx,            // Size in bytes of pixel array (row stride * height, there may be some padding at the end of each row)
3181       char                *Px               // (Optional) bitmapbuffer (pixel array section )
3182    ){
3183    char *record;
3184    int   irecsize;
3185    int   cbImage,cbImage4,cbBmi,off;
3186 
3187    SET_CB_FROM_PXBMI(Px,Bmi,cbImage,cbImage4,cbBmi,cbPx);
3188 
3189    irecsize = sizeof(U_EMRALPHABLEND) + cbBmi + cbImage4;
3190    record   = malloc(irecsize);
3191    if(record){
3192       ((PU_EMR)                 record)->iType        = iType;
3193       ((PU_EMR)                 record)->nSize        = irecsize;
3194       ((PU_EMRALPHABLEND)       record)->rclBounds    = rclBounds;
3195       ((PU_EMRALPHABLEND)       record)->Dest         = Dest;
3196       ((PU_EMRALPHABLEND)       record)->cDest        = cDest;
3197       ((PU_EMRALPHABLEND)       record)->Blend        =  *((PU_BLEND)&Data);
3198       ((PU_EMRALPHABLEND)       record)->Src          = Src;
3199       ((PU_EMRALPHABLEND)       record)->xformSrc     = xformSrc;
3200       ((PU_EMRALPHABLEND)       record)->crBkColorSrc = crBkColorSrc;
3201       ((PU_EMRALPHABLEND)       record)->iUsageSrc    = iUsageSrc;
3202       off = sizeof(U_EMRALPHABLEND);
3203       APPEND_PXBMISRC(record, U_EMRALPHABLEND, cbBmi, Bmi, Px, cbImage, cbImage4);
3204       ((PU_EMRALPHABLEND)       record)->cSrc         = cSrc;
3205    }
3206    return(record);
3207 }
3208 //! @endcond
3209 
3210 /* **********************************************************************************************
3211 These are the core EMR functions, each creates a particular type of record.
3212 All return these records via a char* pointer, which is NULL if the call failed.
3213 They are listed in order by the corresponding U_EMR_* index number.
3214 *********************************************************************************************** */
3215 
3216 // U_EMRHEADER_set                     1
3217 
3218 /**
3219     \brief Allocate and construct a U_EMRHEADER record.
3220     \return pointer to U_EMRHEADER record, or NULL on error.
3221     \param rclBounds       Bounding rectangle in device units
3222     \param rclFrame        Bounding rectangle in 0.01 mm units
3223     \param pfmtDesc        Pointer to a PixelFormatDescriptor
3224     \param nDesc           number of characters in Description, will include first three '\0'
3225     \param Description     Description, formatted like: text1\0text2\0\0
3226     \param szlDevice       Reference device size in pixels
3227     \param szlMillimeters  Reference device size in 0.01 mm
3228     \param bOpenGL         nonZero if OpenGL commands are included
3229 */
U_EMRHEADER_set(const U_RECTL rclBounds,const U_RECTL rclFrame,U_PIXELFORMATDESCRIPTOR * const pfmtDesc,U_CBSTR nDesc,uint16_t * const Description,const U_SIZEL szlDevice,const U_SIZEL szlMillimeters,const uint32_t bOpenGL)3230 char *U_EMRHEADER_set(
3231       const U_RECTL                  rclBounds,
3232       const U_RECTL                  rclFrame,
3233       U_PIXELFORMATDESCRIPTOR* const pfmtDesc,
3234       U_CBSTR                        nDesc,
3235       uint16_t* const                Description,
3236       const U_SIZEL                  szlDevice,
3237       const U_SIZEL                  szlMillimeters,
3238       const uint32_t                 bOpenGL
3239    ){
3240 
3241    char *record;
3242    int cbPFD,cbDesc,cbDesc4;
3243    uint32_t off;
3244    int irecsize;
3245 
3246    if(pfmtDesc){    cbPFD = sizeof(U_PIXELFORMATDESCRIPTOR); }
3247    else  {          cbPFD = 0;                               }
3248    if(Description){ cbDesc = 2*nDesc;                         } // also copy the terminator.  Size is in bytes
3249    else  {          cbDesc = 0;                               }
3250    cbDesc4  = UP4(cbDesc);
3251    irecsize = sizeof(U_EMRHEADER) + cbPFD + cbDesc4;
3252    record   = malloc(irecsize);
3253    if(record){
3254       off = sizeof(U_EMRHEADER);
3255       ((PU_EMR)           record)->iType             = U_EMR_HEADER;
3256       ((PU_EMR)           record)->nSize             = irecsize;
3257       ((PU_EMRHEADER)     record)->rclBounds         = rclBounds;
3258       ((PU_EMRHEADER)     record)->rclFrame          = rclFrame;
3259       ((PU_EMRHEADER)     record)->dSignature        = U_ENHMETA_SIGNATURE;
3260       ((PU_EMRHEADER)     record)->nVersion          = U_ENHMETA_VERSION;
3261       ((PU_EMRHEADER)     record)->nBytes            = 0;  // Not known yet
3262       ((PU_EMRHEADER)     record)->nRecords          = 0;  // Not known yet
3263       ((PU_EMRHEADER)     record)->nHandles          = 0;  // Not known yet
3264       ((PU_EMRHEADER)     record)->sReserved         = 0;  // Must be 0
3265       ((PU_EMRHEADER)     record)->nDescription      = nDesc;
3266       ((PU_EMRHEADER)     record)->offDescription    = 0;  // may change below
3267       ((PU_EMRHEADER)     record)->nPalEntries       = 0;  // Not known yet
3268       ((PU_EMRHEADER)     record)->szlDevice         = szlDevice;
3269       ((PU_EMRHEADER)     record)->szlMillimeters    = szlMillimeters;
3270       ((PU_EMRHEADER)     record)->cbPixelFormat     = cbPFD;
3271       ((PU_EMRHEADER)     record)->offPixelFormat    = 0;  // may change below
3272       ((PU_EMRHEADER)     record)->bOpenGL           = bOpenGL;
3273       ((PU_EMRHEADER)     record)->szlMicrometers.cx = szlMillimeters.cx*1000;
3274       ((PU_EMRHEADER)     record)->szlMicrometers.cy = szlMillimeters.cy*1000;
3275       if(cbDesc4){
3276           ((PU_EMRHEADER) record)->offDescription    = off;
3277           memcpy(record + off, Description, cbDesc);
3278           off += cbDesc;
3279           if(cbDesc < cbDesc4)memset(record + off,0,cbDesc4-cbDesc);  // clear any unused bytes
3280           off += cbDesc4 - cbDesc;
3281       }
3282       if(cbPFD){
3283          ((PU_EMRHEADER)  record)->offPixelFormat   = off;
3284          memcpy(record+off,pfmtDesc,cbPFD);
3285       }
3286    }
3287    return(record);
3288 }
3289 
3290 // U_EMRPOLYBEZIER_set                 2
3291 /**
3292     \brief Allocate and construct a U_EMR_POLYBEZIER record.
3293     \return pointer to U_EMR_POLYBEZIER record, or NULL on error.
3294     \param rclBounds   bounding rectangle in device units
3295     \param cptl        Number of points to draw
3296     \param points      array of points
3297 */
U_EMRPOLYBEZIER_set(const U_RECTL rclBounds,const uint32_t cptl,const U_POINTL * points)3298 char *U_EMRPOLYBEZIER_set(
3299       const U_RECTL   rclBounds,
3300       const uint32_t  cptl,
3301       const U_POINTL *points
3302    ){
3303    return(U_EMR_CORE1_set(U_EMR_POLYBEZIER, rclBounds, cptl, points));
3304 }
3305 
3306 // U_EMRPOLYGON_set                    3
3307 /**
3308     \brief Allocate and construct a U_EMR_POLYGON record.
3309     \return pointer to U_EMR_POLYGON record, or NULL on error.
3310     \param rclBounds   bounding rectangle in device units
3311     \param cptl        Number of points to draw
3312     \param points      array of points
3313 */
U_EMRPOLYGON_set(const U_RECTL rclBounds,const uint32_t cptl,const U_POINTL * points)3314 char *U_EMRPOLYGON_set(
3315       const U_RECTL   rclBounds,
3316       const uint32_t  cptl,
3317       const U_POINTL *points
3318    ){
3319    return(U_EMR_CORE1_set(U_EMR_POLYGON, rclBounds, cptl, points));
3320 }
3321 
3322 // U_EMRPOLYLINE_set                   4
3323 /**
3324     \brief Allocate and construct a U_EMR_POLYLINE record.
3325     \return pointer to U_EMR_POLYLINE record, or NULL on error.
3326     \param rclBounds   bounding rectangle in device units
3327     \param cptl        Number of points to draw
3328     \param points      array of points
3329 */
U_EMRPOLYLINE_set(const U_RECTL rclBounds,const uint32_t cptl,const U_POINTL * points)3330 char *U_EMRPOLYLINE_set(
3331       const U_RECTL   rclBounds,
3332       const uint32_t  cptl,
3333       const U_POINTL *points
3334    ){
3335    return(U_EMR_CORE1_set(U_EMR_POLYLINE, rclBounds, cptl, points));
3336 }
3337 
3338 // U_EMRPOLYBEZIERTO_set               5
3339 /**
3340     \brief Allocate and construct a U_EMR_POLYBEZIERTO record.
3341     \return pointer to U_EMR_POLYBEZIERTO record, or NULL on error.
3342     \param rclBounds   bounding rectangle in device units
3343     \param cptl        Number of points to draw
3344     \param points      array of points
3345 */
U_EMRPOLYBEZIERTO_set(const U_RECTL rclBounds,const uint32_t cptl,const U_POINTL * points)3346 char *U_EMRPOLYBEZIERTO_set(
3347       const U_RECTL   rclBounds,
3348       const uint32_t  cptl,
3349       const U_POINTL *points
3350    ){
3351    return(U_EMR_CORE1_set(U_EMR_POLYBEZIERTO, rclBounds, cptl, points));
3352 }
3353 
3354 // U_EMRPOLYLINETO_set                 6
3355 /**
3356     \brief Allocate and construct a U_EMR_POLYLINETO record.
3357     \return pointer to U_EMR_POLYLINETO record, or NULL on error.
3358     \param rclBounds   bounding rectangle in device units
3359     \param cptl        Number of points to draw
3360     \param points      array of points
3361 */
U_EMRPOLYLINETO_set(const U_RECTL rclBounds,const uint32_t cptl,const U_POINTL * points)3362 char *U_EMRPOLYLINETO_set(
3363       const U_RECTL   rclBounds,
3364       const uint32_t  cptl,
3365       const U_POINTL *points
3366    ){
3367    return(U_EMR_CORE1_set(U_EMR_POLYLINETO, rclBounds, cptl, points));
3368 }
3369 
3370 // U_EMRPOLYPOLYLINE_set               7
3371 /**
3372     \brief Allocate and construct a U_EMR_POLYPOLYLINE record.
3373     \return pointer to U_EMR_POLYPOLYLINE record, or NULL on error.
3374     \param rclBounds    bounding rectangle in device units
3375     \param nPolys       Number of elements in aPolyCounts
3376     \param aPolyCounts  Number of points in each poly (sequential)
3377     \param cptl         Total number of points (over all poly)
3378     \param points       array of points
3379 */
U_EMRPOLYPOLYLINE_set(const U_RECTL rclBounds,const uint32_t nPolys,const uint32_t * aPolyCounts,const uint32_t cptl,const U_POINTL * points)3380 char *U_EMRPOLYPOLYLINE_set(
3381       const U_RECTL   rclBounds,
3382       const uint32_t  nPolys,
3383       const uint32_t *aPolyCounts,
3384       const uint32_t  cptl,
3385       const U_POINTL *points
3386    ){
3387    return(U_EMR_CORE2_set(U_EMR_POLYPOLYLINE, rclBounds, nPolys, aPolyCounts,cptl, points));
3388 }
3389 
3390 // U_EMRPOLYPOLYGON_set                8
3391 /**
3392     \brief Allocate and construct a U_EMR_POLYPOLYGON record.
3393     \return pointer to U_EMR_POLYPOLYGON record, or NULL on error.
3394     \param rclBounds    bounding rectangle in device units
3395     \param nPolys       Number of elements in aPolyCounts
3396     \param aPolyCounts  Number of points in each poly (sequential)
3397     \param cptl         Total number of points (over all poly)
3398     \param points       array of points
3399 */
U_EMRPOLYPOLYGON_set(const U_RECTL rclBounds,const uint32_t nPolys,const uint32_t * aPolyCounts,const uint32_t cptl,const U_POINTL * points)3400 char *U_EMRPOLYPOLYGON_set(
3401       const U_RECTL   rclBounds,
3402       const uint32_t  nPolys,
3403       const uint32_t *aPolyCounts,
3404       const uint32_t  cptl,
3405       const U_POINTL *points
3406    ){
3407    return(U_EMR_CORE2_set(U_EMR_POLYPOLYGON, rclBounds, nPolys, aPolyCounts,cptl, points));
3408 }
3409 
3410 // U_EMRSETWINDOWEXTEX_set             9
3411 /**
3412     \brief Allocate and construct a U_EMR_SETWINDOWEXTEX record.
3413     \return pointer to U_EMR_SETWINDOWEXTEX record, or NULL on error.
3414     \param szlExtent H & V extent in logical units
3415 */
U_EMRSETWINDOWEXTEX_set(const U_SIZEL szlExtent)3416 char *U_EMRSETWINDOWEXTEX_set(
3417       const U_SIZEL szlExtent
3418    ){
3419    U_PAIR temp;
3420    temp.x = szlExtent.cx;
3421    temp.y = szlExtent.cy;
3422    return(U_EMR_CORE7_set(U_EMR_SETWINDOWEXTEX, temp));
3423 }
3424 
3425 // U_EMRSETWINDOWORGEX_set            10
3426 /**
3427     \brief Allocate and construct a U_EMR_SETWINDOWORGEX record.
3428     \return pointer to U_EMR_SETWINDOWORGEX record, or NULL on error.
3429     \param ptlOrigin H & V origin in logical units
3430 */
U_EMRSETWINDOWORGEX_set(const U_POINTL ptlOrigin)3431 char *U_EMRSETWINDOWORGEX_set(
3432       const U_POINTL ptlOrigin
3433    ){
3434    return(U_EMR_CORE7_set(U_EMR_SETWINDOWORGEX, ptlOrigin)); // U_PAIR and U_POINTL are the same thing
3435 }
3436 
3437 // U_EMRSETVIEWPORTEXTEX_set          11
3438 /**
3439     \brief Allocate and construct a U_EMR_SETVIEWPORTEXTEX record.
3440     \return pointer to U_EMR_SETVIEWPORTEXTEX record, or NULL on error.
3441     \param szlExtent  H & V extent in logical units
3442 */
U_EMRSETVIEWPORTEXTEX_set(const U_SIZEL szlExtent)3443 char *U_EMRSETVIEWPORTEXTEX_set(
3444       const U_SIZEL szlExtent
3445    ){
3446    U_PAIR temp;
3447    temp.x = szlExtent.cx;
3448    temp.y = szlExtent.cy;
3449    return(U_EMR_CORE7_set(U_EMR_SETVIEWPORTEXTEX, temp));
3450 }
3451 
3452 // U_EMRSETVIEWPORTORGEX_set          12
3453 /**
3454     \brief Allocate and construct a U_EMR_SETVIEWPORTORGEX record.
3455     \return pointer to U_EMR_SETVIEWPORTORGEX record, or NULL on error.
3456     \param ptlOrigin  H & V origin in logical units
3457 */
U_EMRSETVIEWPORTORGEX_set(const U_POINTL ptlOrigin)3458 char *U_EMRSETVIEWPORTORGEX_set(
3459       const U_POINTL ptlOrigin
3460    ){
3461    return(U_EMR_CORE7_set(U_EMR_SETVIEWPORTORGEX, ptlOrigin));  // U_PAIR and U_POINTL are the same thing
3462 }
3463 
3464 // U_EMRSETBRUSHORGEX_set             13
3465 /**
3466     \brief Allocate and construct a U_EMR_SETBRUSHORGEX record.
3467     \return pointer to U_EMR_SETBRUSHORGEX record, or NULL on error.
3468     \param ptlOrigin   H & V origin in logical units
3469 */
U_EMRSETBRUSHORGEX_set(const U_POINTL ptlOrigin)3470 char *U_EMRSETBRUSHORGEX_set(
3471       const U_POINTL ptlOrigin
3472    ){
3473    return(U_EMR_CORE7_set(U_EMR_SETBRUSHORGEX, *((PU_PAIR) & ptlOrigin)));
3474 }
3475 
3476 // U_EMREOF_set                       14
3477 /**
3478     \brief Allocate and construct a U_EMR_EOF record.
3479     \return pointer to U_EMR_EOF record, or NULL on error.
3480     \param cbPalEntries  Number of palette entries
3481     \param PalEntries    (optional) array of PalEntries
3482     \param et            tracking information, needed for nSizeLast calculation
3483 */
U_EMREOF_set(const U_CBPLENTRIES cbPalEntries,const PU_LOGPLTNTRY PalEntries,EMFTRACK * et)3484 char *U_EMREOF_set(
3485       const U_CBPLENTRIES  cbPalEntries,
3486       const PU_LOGPLTNTRY  PalEntries,
3487       EMFTRACK            *et
3488    ){
3489    char *record;
3490    char *ptr;
3491    int  irecsize;
3492    int  cbPals;   // space allocated for Palette Entries
3493    uint32_t off;
3494 
3495    if(cbPalEntries && !PalEntries)return(NULL);
3496    if(!et)return(NULL);
3497    cbPals     = cbPalEntries * sizeof(U_LOGPLTNTRY);
3498    irecsize  = sizeof(U_EMREOF) + cbPals + sizeof(uint32_t);  //invariant core, variable palette, palette byte count
3499    record    = malloc(irecsize);
3500    if(record){
3501       ((PU_EMR)         record)->iType         = U_EMR_EOF;
3502       ((PU_EMR)         record)->nSize         = irecsize;
3503       ((PU_EMREOF)      record)->cbPalEntries  = cbPalEntries;
3504       ((PU_EMREOF)      record)->offPalEntries = 0;  // May be changed below
3505       off = sizeof(U_EMREOF);         //start of the variable region
3506       if(cbPals){
3507          ((PU_EMREOF)   record)->offPalEntries = off;
3508          memcpy(record+off,PalEntries,cbPals);
3509          off += cbPals;
3510       }
3511       ptr = record + off;
3512       *(uint32_t *)ptr = irecsize + et->used;  // EMREOF nSizeLast field, not at a fixed position, cannot be accessed by field name
3513    }
3514    et->PalEntries = cbPalEntries;
3515    return(record);
3516 }
3517 
3518 
3519 // U_EMRSETPIXELV_set                 15
3520 /**
3521     \brief Allocate and construct a U_EMR_SETPIXELV record.
3522     \return pointer to U_EMR_SETPIXELV record, or NULL on error.
3523     \param ptlPixel Pixel coordinates (logical)
3524     \param crColor  Pixel color
3525 */
U_EMRSETPIXELV_set(const U_POINTL ptlPixel,const U_COLORREF crColor)3526 char *U_EMRSETPIXELV_set(
3527       const U_POINTL    ptlPixel,
3528       const U_COLORREF  crColor
3529    ){
3530    char *record;
3531    int  irecsize;
3532 
3533    irecsize = sizeof(U_EMRSETPIXELV);
3534    record   = malloc(irecsize);
3535    if(record){
3536       ((PU_EMR)         record)->iType    = U_EMR_SETPIXELV;
3537       ((PU_EMR)         record)->nSize    = irecsize;
3538       ((PU_EMRSETPIXELV)record)->ptlPixel = ptlPixel;
3539       ((PU_EMRSETPIXELV)record)->crColor  = crColor;
3540    }
3541    return(record);
3542 }
3543 
3544 
3545 // U_EMRSETMAPPERFLAGS_set            16
3546 /**
3547     \brief Allocate and construct a U_EMR_SETMAPPERFLAGS record.
3548     \return pointer to U_EMR_SETMAPPERFLAGS record, or NULL on error.
3549 */
U_EMRSETMAPPERFLAGS_set(void)3550 char *U_EMRSETMAPPERFLAGS_set(void){
3551    char *record;
3552    int  irecsize;
3553 
3554    irecsize = sizeof(U_EMRSETMAPPERFLAGS);
3555    record   = malloc(irecsize);
3556    if(record){
3557       ((PU_EMR)              record)->iType   = U_EMR_SETMAPPERFLAGS;
3558       ((PU_EMR)              record)->nSize   = irecsize;
3559       ((PU_EMRSETMAPPERFLAGS)record)->dwFlags = 1;
3560    }
3561    return(record);
3562 }
3563 
3564 // U_EMRSETMAPMODE_set                17
3565 /**
3566     \brief Allocate and construct a U_EMR_SETMAPMODE record.
3567     \return pointer to U_EMR_SETMAPMODE record, or NULL on error.
3568     \param iMode  MapMode Enumeration
3569 */
U_EMRSETMAPMODE_set(const uint32_t iMode)3570 char *U_EMRSETMAPMODE_set(
3571       const uint32_t iMode
3572    ){
3573    return(U_EMR_CORE3_set(U_EMR_SETMAPMODE, iMode));
3574 }
3575 
3576 // U_EMRSETBKMODE_set                 18
3577 /**
3578     \brief Allocate and construct a U_EMR_SETBKMODE record.
3579     \return pointer to U_EMR_SETBKMODE record, or NULL on error.
3580     \param iMode BackgroundMode Enumeration
3581 */
U_EMRSETBKMODE_set(const uint32_t iMode)3582 char *U_EMRSETBKMODE_set(
3583       const uint32_t iMode
3584    ){
3585   return(U_EMR_CORE3_set(U_EMR_SETBKMODE, iMode));
3586 }
3587 
3588 // U_EMRSETPOLYFILLMODE_set           19
3589 /**
3590     \brief Allocate and construct a U_EMR_SETPOLYFILLMODE record.
3591     \return pointer to U_EMR_SETPOLYFILLMODE record, or NULL on error.
3592     \param iMode  PolygonFillMode Enumeration
3593 */
U_EMRSETPOLYFILLMODE_set(const uint32_t iMode)3594 char *U_EMRSETPOLYFILLMODE_set(
3595       const uint32_t iMode
3596    ){
3597    return(U_EMR_CORE3_set(U_EMR_SETPOLYFILLMODE, iMode));
3598 }
3599 
3600 // U_EMRSETROP2_set                   20
3601 /**
3602     \brief Allocate and construct a U_EMR_SETROP2 record.
3603     \return pointer to U_EMR_SETROP2 record, or NULL on error.
3604     \param iMode  RasterOperation2 Enumeration
3605 */
U_EMRSETROP2_set(const uint32_t iMode)3606 char *U_EMRSETROP2_set(
3607       const uint32_t iMode
3608    ){
3609    return(U_EMR_CORE3_set(U_EMR_SETROP2, iMode));
3610 }
3611 
3612 // U_EMRSETSTRETCHBLTMODE_set         21
3613 /**
3614     \brief Allocate and construct a U_EMR_SETSTRETCHBLTMODE record.
3615     \return pointer to U_EMR_SETSTRETCHBLTMODE record, or NULL on error.
3616     \param iMode  StretchMode Enumeration
3617 */
U_EMRSETSTRETCHBLTMODE_set(const uint32_t iMode)3618 char *U_EMRSETSTRETCHBLTMODE_set(
3619       const uint32_t iMode
3620    ){
3621    return(U_EMR_CORE3_set(U_EMR_SETSTRETCHBLTMODE, iMode));
3622 }
3623 
3624 // U_EMRSETTEXTALIGN_set              22
3625 /**
3626     \brief Allocate and construct a U_EMR_SETTEXTALIGN record.
3627     \return pointer to U_EMR_SETTEXTALIGN record, or NULL on error.
3628     \param iMode  TextAlignment Enumeration
3629 */
U_EMRSETTEXTALIGN_set(const uint32_t iMode)3630 char *U_EMRSETTEXTALIGN_set(
3631       const uint32_t iMode
3632    ){
3633    return(U_EMR_CORE3_set(U_EMR_SETTEXTALIGN, iMode));
3634 }
3635 
3636 // U_EMRSETCOLORADJUSTMENT_set        23
3637 /**
3638     \brief Allocate and construct a U_EMR_SETCOLORADJUSTMENT record.
3639     \return pointer to U_EMR_SETCOLORADJUSTMENT record, or NULL on error.
3640     \param ColorAdjustment Color Adjustment
3641 */
U_EMRSETCOLORADJUSTMENT_set(const U_COLORADJUSTMENT ColorAdjustment)3642 char *U_EMRSETCOLORADJUSTMENT_set(
3643       const U_COLORADJUSTMENT ColorAdjustment
3644    ){
3645    char *record;
3646    int  irecsize;
3647 
3648    irecsize = sizeof(U_EMRSETCOLORADJUSTMENT);
3649    record   = malloc(irecsize);
3650    if(record){
3651       ((PU_EMR)                   record)->iType           = U_EMR_SETCOLORADJUSTMENT;
3652       ((PU_EMR)                   record)->nSize           = irecsize;
3653       ((PU_EMRSETCOLORADJUSTMENT) record)->ColorAdjustment = ColorAdjustment;
3654    }
3655    return(record);
3656 }
3657 
3658 // U_EMRSETTEXTCOLOR_set              24
3659 /**
3660     \brief Allocate and construct a U_EMR_SETTEXTCOLOR record.
3661     \return pointer to U_EMR_SETTEXTCOLOR record, or NULL on error.
3662     \param crColor  Text Color
3663 */
U_EMRSETTEXTCOLOR_set(const U_COLORREF crColor)3664 char *U_EMRSETTEXTCOLOR_set(
3665       const U_COLORREF crColor
3666   ){
3667   return(U_EMR_CORE3_set(U_EMR_SETTEXTCOLOR, *(uint32_t *) &crColor));
3668 }
3669 
3670 // U_EMRSETBKCOLOR_set                25
3671 /**
3672     \brief Allocate and construct a U_EMR_SETBKCOLOR record.
3673     \return pointer to U_EMR_SETBKCOLOR record, or NULL on error.
3674     \param crColor Background Color
3675 */
U_EMRSETBKCOLOR_set(const U_COLORREF crColor)3676 char *U_EMRSETBKCOLOR_set(
3677       const U_COLORREF crColor
3678   ){
3679   return(U_EMR_CORE3_set(U_EMR_SETBKCOLOR, *(uint32_t *) &crColor));
3680 }
3681 
3682 // U_EMROFFSETCLIPRGN_set             26
3683 /**
3684     \brief Allocate and construct a U_EMR_OFFSETCLIPRGN record.
3685     \return pointer to U_EMR_OFFSETCLIPRGN record, or NULL on error.
3686     \param ptl Clipping region
3687 */
U_EMROFFSETCLIPRGN_set(const U_POINTL ptl)3688 char *U_EMROFFSETCLIPRGN_set(
3689       const U_POINTL ptl
3690    ){
3691   return(U_EMR_CORE7_set(U_EMR_OFFSETCLIPRGN, ptl));
3692 }
3693 
3694 // U_EMRMOVETOEX_set                  27
3695 /**
3696     \brief Allocate and construct a U_EMR_MOVETOEX record.
3697     \return pointer to U_EMR_MOVETOEX record, or NULL on error.
3698     \param ptl Point coordinates
3699 */
U_EMRMOVETOEX_set(const U_POINTL ptl)3700 char *U_EMRMOVETOEX_set(
3701       const U_POINTL ptl
3702    ){
3703    return(U_EMR_CORE7_set(U_EMR_MOVETOEX, ptl));
3704 }
3705 
3706 // U_EMRSETMETARGN_set                28
3707 /**
3708     \brief Allocate and construct a U_EMR_SETMETARGN record.
3709     \return pointer to U_EMR_SETMETARGN record, or NULL on error.
3710 */
U_EMRSETMETARGN_set(void)3711 char *U_EMRSETMETARGN_set(void){
3712   return(U_EMR_CORE5_set(U_EMR_SETMETARGN));
3713 }
3714 
3715 // U_EMREXCLUDECLIPRECT_set           29
3716 /**
3717     \brief Allocate and construct a U_EMR_EXCLUDECLIPRECT record.
3718     \return pointer to U_EMR_EXCLUDECLIPRECT record, or NULL on error.
3719     \param rclClip Clipping Region
3720 */
U_EMREXCLUDECLIPRECT_set(const U_RECTL rclClip)3721 char *U_EMREXCLUDECLIPRECT_set(
3722       const U_RECTL rclClip
3723     ){
3724     return(U_EMR_CORE4_set(U_EMR_EXCLUDECLIPRECT,rclClip));
3725 }
3726 
3727 // U_EMRINTERSECTCLIPRECT_set         30
3728 /**
3729     \brief Allocate and construct a U_EMR_INTERSECTCLIPRECT record.
3730     \return pointer to U_EMR_INTERSECTCLIPRECT record, or NULL on error.
3731     \param rclClip Clipping Region
3732 */
U_EMRINTERSECTCLIPRECT_set(const U_RECTL rclClip)3733 char *U_EMRINTERSECTCLIPRECT_set(
3734       const U_RECTL rclClip
3735     ){
3736     return(U_EMR_CORE4_set(U_EMR_INTERSECTCLIPRECT,rclClip));
3737 }
3738 
3739 // U_EMRSCALEVIEWPORTEXTEX_set        31
3740 /**
3741     \brief Allocate and construct a U_EMR_SCALEVIEWPORTEXTEX record.
3742     \return pointer to U_EMR_SCALEVIEWPORTEXTEX record, or NULL on error.
3743     \param xNum   Horizontal multiplier (!=0)
3744     \param xDenom Horizontal divisor    (!=0)
3745     \param yNum   Vertical   multiplier (!=0)
3746     \param yDenom Vertical   divisor    (!=0)
3747 */
U_EMRSCALEVIEWPORTEXTEX_set(const int32_t xNum,const int32_t xDenom,const int32_t yNum,const int32_t yDenom)3748 char *U_EMRSCALEVIEWPORTEXTEX_set(
3749     const int32_t  xNum,
3750     const int32_t  xDenom,
3751     const int32_t  yNum,
3752     const int32_t  yDenom
3753   ){
3754   return(U_EMR_CORE4_set(U_EMR_SCALEVIEWPORTEXTEX,(U_RECTL){xNum,xDenom,yNum,yDenom}));
3755 }
3756 
3757 
3758 // U_EMRSCALEWINDOWEXTEX_set          32
3759 /**
3760     \brief Allocate and construct a U_EMR_SCALEWINDOWEXTEX record.
3761     \return pointer to U_EMR_SCALEWINDOWEXTEX record, or NULL on error.
3762     \param xNum   Horizontal multiplier (!=0)
3763     \param xDenom Horizontal divisor    (!=0)
3764     \param yNum   Vertical   multiplier (!=0)
3765     \param yDenom Vertical   divisor    (!=0)
3766 */
U_EMRSCALEWINDOWEXTEX_set(const int32_t xNum,const int32_t xDenom,const int32_t yNum,const int32_t yDenom)3767 char *U_EMRSCALEWINDOWEXTEX_set(
3768     const int32_t  xNum,
3769     const int32_t  xDenom,
3770     const int32_t  yNum,
3771     const int32_t  yDenom
3772   ){
3773   return(U_EMR_CORE4_set(U_EMR_SCALEWINDOWEXTEX,(U_RECTL){xNum,xDenom,yNum,yDenom}));
3774 }
3775 
3776 // U_EMRSAVEDC_set                    33
3777 /**
3778     \brief Allocate and construct a U_EMR_SAVEDC record.
3779     \return pointer to U_EMR_SAVEDC record, or NULL on error.
3780 */
U_EMRSAVEDC_set(void)3781 char *U_EMRSAVEDC_set(void){
3782   return(U_EMR_CORE5_set(U_EMR_SAVEDC));
3783 }
3784 
3785 // U_EMRRESTOREDC_set                 34
3786 /**
3787     \brief Allocate and construct a U_EMR_RESTOREDC record.
3788     \return pointer to U_EMR_RESTOREDC record, or NULL on error.
3789     \param iRelative DC to restore. -1 is preceding
3790 */
U_EMRRESTOREDC_set(const int32_t iRelative)3791 char *U_EMRRESTOREDC_set(
3792     const int32_t iRelative
3793   ){
3794   return(U_EMR_CORE3_set(U_EMR_RESTOREDC, (uint32_t) iRelative));
3795 }
3796 
3797 // U_EMRSETWORLDTRANSFORM_set         35
3798 /**
3799     \brief Allocate and construct a U_EMR_SETWORLDTRANSFORM record.
3800     \return pointer to U_EMR_SETWORLDTRANSFORM record, or NULL on error.
3801     \param xform Transform to use
3802 */
U_EMRSETWORLDTRANSFORM_set(const U_XFORM xform)3803 char *U_EMRSETWORLDTRANSFORM_set(
3804       const U_XFORM xform
3805    ){
3806    char *record;
3807    int  irecsize;
3808 
3809    irecsize = sizeof(U_EMRSETWORLDTRANSFORM);
3810    record   = malloc(irecsize);
3811    if(record){
3812       ((PU_EMR)                  record)->iType = U_EMR_SETWORLDTRANSFORM;
3813       ((PU_EMR)                  record)->nSize = irecsize;
3814       ((PU_EMRSETWORLDTRANSFORM) record)->xform = xform;
3815    }
3816    return(record);
3817 }
3818 
3819 // U_EMRMODIFYWORLDTRANSFORM_set      36
3820 /**
3821     \brief Allocate and construct a U_EMR_MODIFYWORLDTRANSFORM record.
3822     \return pointer to U_EMR_MODIFYWORLDTRANSFORM record, or NULL on error.
3823     \param xform Transform to use
3824     \param iMode ModifyWorldTransformMode Enumeration
3825 */
U_EMRMODIFYWORLDTRANSFORM_set(const U_XFORM xform,const uint32_t iMode)3826 char *U_EMRMODIFYWORLDTRANSFORM_set(
3827       const U_XFORM  xform,
3828       const uint32_t iMode
3829    ){
3830    char *record;
3831    int irecsize;
3832 
3833    irecsize = sizeof(U_EMRMODIFYWORLDTRANSFORM);
3834    record   = malloc(irecsize);
3835    if(record){
3836       ((PU_EMR)                     record)->iType = U_EMR_MODIFYWORLDTRANSFORM;
3837       ((PU_EMR)                     record)->nSize = irecsize;
3838       ((PU_EMRMODIFYWORLDTRANSFORM) record)->xform = xform;
3839       ((PU_EMRMODIFYWORLDTRANSFORM) record)->iMode = iMode;
3840    }
3841    return(record);
3842 }
3843 
3844 // U_EMRSELECTOBJECT_set              37
3845 /**
3846     \brief Allocate and construct a U_EMR_SELECTOBJECT record.
3847     Use selectobject_set() instead of calling this function directly.
3848     \return pointer to U_EMR_SELECTOBJECT record, or NULL on error.
3849     \param ihObject Number of a stock or created object
3850 */
U_EMRSELECTOBJECT_set(const uint32_t ihObject)3851 char *U_EMRSELECTOBJECT_set(
3852       const uint32_t ihObject
3853    ){
3854    char *record;
3855    int  irecsize;
3856 
3857    irecsize = sizeof(U_EMRSELECTOBJECT);
3858    record   = malloc(irecsize);
3859    if(record){
3860       ((PU_EMR)             record)->iType    = U_EMR_SELECTOBJECT;
3861       ((PU_EMR)             record)->nSize    = irecsize;
3862       ((PU_EMRSELECTOBJECT) record)->ihObject = ihObject;  // Index of object to SELECT
3863    }
3864    return(record);
3865 }
3866 
3867 // U_EMRCREATEPEN_set                 38
3868 /**
3869     \brief Allocate and construct a U_EMR_CREATEPEN record.
3870     Use createpen_set() instead of calling this function directly.
3871     \return pointer to U_EMR_CREATEPEN record, or NULL on error.
3872     \param ihPen Handle of created pen
3873     \param lopn  U_LOGPEN structure describing this pen
3874 */
U_EMRCREATEPEN_set(const uint32_t ihPen,const U_LOGPEN lopn)3875 char *U_EMRCREATEPEN_set(
3876       const uint32_t ihPen,
3877       const U_LOGPEN lopn
3878    ){
3879    char *record;
3880    int irecsize=sizeof(U_EMRCREATEPEN);
3881 
3882    record   = malloc(irecsize);
3883    if(record){
3884       ((PU_EMR)          record)->iType = U_EMR_CREATEPEN;
3885       ((PU_EMR)          record)->nSize = irecsize;
3886       ((PU_EMRCREATEPEN) record)->ihPen = ihPen;
3887       ((PU_EMRCREATEPEN) record)->lopn  = lopn;
3888    }
3889    return(record);
3890 }
3891 
3892 // U_EMRCREATEBRUSHINDIRECT_set       39
3893 /**
3894     \brief Allocate and construct a U_EMR_CREATEBRUSHINDIRECT record.
3895     Use createbrushindirect_set() instead of calling this function directly.
3896     \return pointer to U_EMR_CREATEBRUSHINDIRECT record, or NULL on error.
3897     \param ihBrush Index to place object in EMF object table (this entry must not yet exist)
3898     \param lb      Brush properties
3899 */
U_EMRCREATEBRUSHINDIRECT_set(const uint32_t ihBrush,const U_LOGBRUSH lb)3900 char *U_EMRCREATEBRUSHINDIRECT_set(
3901       const uint32_t   ihBrush,
3902       const U_LOGBRUSH lb
3903    ){
3904    char *record;
3905    int  irecsize;
3906 
3907    irecsize = sizeof(U_EMRCREATEBRUSHINDIRECT);
3908    record   = malloc(irecsize);
3909    if(record){
3910       ((PU_EMR)                    record)->iType   = U_EMR_CREATEBRUSHINDIRECT;
3911       ((PU_EMR)                    record)->nSize   = irecsize;
3912       ((PU_EMRCREATEBRUSHINDIRECT) record)->ihBrush = ihBrush;  // Index to place object in EMF object table (this entry must not yet exist)
3913       ((PU_EMRCREATEBRUSHINDIRECT) record)->lb      = lb;
3914    }
3915    return(record);
3916 }
3917 
3918 // U_EMRDELETEOBJECT_set              40
3919 /**
3920     \brief Allocate and construct a U_EMR_DELETEOBJECT record.
3921     Use deleteobject_set() instead of calling this function directly.
3922     \return pointer to U_EMR_DELETEOBJECT record, or NULL on error.
3923     \param ihObject Number of a stock or created object
3924 */
U_EMRDELETEOBJECT_set(const uint32_t ihObject)3925 char *U_EMRDELETEOBJECT_set(
3926       const uint32_t ihObject
3927    ){
3928    char *record;
3929    int  irecsize;
3930 
3931    irecsize = sizeof(U_EMRDELETEOBJECT);
3932    record   = malloc(irecsize);
3933    if(record){
3934       ((PU_EMR)             record)->iType    = U_EMR_DELETEOBJECT;
3935       ((PU_EMR)             record)->nSize    = irecsize;
3936       ((PU_EMRDELETEOBJECT) record)->ihObject = ihObject;  // Index of object to DELETE
3937    }
3938    return(record);
3939 }
3940 
3941 // U_EMRANGLEARC_set                  41
3942 /**
3943     \brief Allocate and construct a U_EMR_ANGLEARC record.
3944     \return pointer to U_EMR_ANGLEARC record, or NULL on error.
3945     \param ptlCenter   Center in logical units
3946     \param nRadius     Radius in logical units
3947     \param eStartAngle Starting angle in degrees (counter clockwise from x axis)
3948     \param eSweepAngle Sweep angle in degrees
3949 */
U_EMRANGLEARC_set(const U_POINTL ptlCenter,const uint32_t nRadius,const U_FLOAT eStartAngle,const U_FLOAT eSweepAngle)3950 char *U_EMRANGLEARC_set(
3951       const U_POINTL  ptlCenter,
3952       const uint32_t  nRadius,
3953       const U_FLOAT   eStartAngle,
3954       const U_FLOAT   eSweepAngle
3955    ){
3956    char *record;
3957    int  irecsize;
3958 
3959    irecsize = sizeof(U_EMRANGLEARC);
3960    record   = malloc(irecsize);
3961    if(record){
3962       ((PU_EMR)         record)->iType       = U_EMR_ANGLEARC;
3963       ((PU_EMR)         record)->nSize       = irecsize;
3964       ((PU_EMRANGLEARC) record)->ptlCenter   = ptlCenter;
3965       ((PU_EMRANGLEARC) record)->nRadius     = nRadius;
3966       ((PU_EMRANGLEARC) record)->eStartAngle = eStartAngle;
3967       ((PU_EMRANGLEARC) record)->eSweepAngle = eSweepAngle;
3968    }
3969    return(record);
3970 }
3971 
3972 // U_EMRELLIPSE_set                   42
3973 /**
3974     \brief Allocate and construct a U_EMR_ELLIPSE record.
3975     \return pointer to U_EMR_ELLIPSE record, or NULL on error.
3976     \param rclBox bounding rectangle in logical units
3977 */
U_EMRELLIPSE_set(const U_RECTL rclBox)3978 char *U_EMRELLIPSE_set(
3979       const U_RECTL rclBox
3980    ){
3981    return(U_EMR_CORE4_set(U_EMR_ELLIPSE,rclBox));
3982 }
3983 
3984 // U_EMRRECTANGLE_set                 43
3985 /**
3986     \brief Allocate and construct a U_EMR_RECTANGLE record.
3987     \return pointer to U_EMR_RECTANGLE record, or NULL on error.
3988     \param rclBox bounding rectangle in logical units
3989 */
U_EMRRECTANGLE_set(const U_RECTL rclBox)3990 char *U_EMRRECTANGLE_set(
3991       const U_RECTL rclBox
3992    ){
3993    return(U_EMR_CORE4_set(U_EMR_RECTANGLE,rclBox));
3994 }
3995 
3996 // U_EMRROUNDRECT_set                 44
3997 /**
3998     \brief Allocate and construct a U_EMR_ROUNDRECT record.
3999     \return pointer to U_EMR_ROUNDRECT record, or NULL on error.
4000     \param rclBox    bounding rectangle in logical units
4001     \param szlCorner W & H in logical units of ellipse used to round corner
4002 */
U_EMRROUNDRECT_set(const U_RECTL rclBox,const U_SIZEL szlCorner)4003 char *U_EMRROUNDRECT_set(
4004       const U_RECTL rclBox,
4005       const U_SIZEL szlCorner
4006    ){
4007    char *record;
4008    int  irecsize;
4009 
4010    irecsize = sizeof(U_EMRROUNDRECT);
4011    record   = malloc(irecsize);
4012    if(record){
4013       ((PU_EMR)          record)->iType       = U_EMR_ROUNDRECT;
4014       ((PU_EMR)          record)->nSize       = irecsize;
4015       ((PU_EMRROUNDRECT) record)->rclBox      = rclBox;
4016       ((PU_EMRROUNDRECT) record)->szlCorner   = szlCorner;
4017    }
4018    return(record);
4019 }
4020 
4021 // U_EMRARC_set                       45
4022 /**
4023     \brief Allocate and construct a U_EMR_ARC record.
4024     \return pointer to U_EMR_ARC record, or NULL on error.
4025     \param rclBox   bounding rectangle in logical units
4026     \param ptlStart Start point in logical units
4027     \param ptlEnd   End point in logical units
4028 */
U_EMRARC_set(const U_RECTL rclBox,const U_POINTL ptlStart,const U_POINTL ptlEnd)4029 char *U_EMRARC_set(
4030       const U_RECTL  rclBox,
4031       const U_POINTL ptlStart,
4032       const U_POINTL ptlEnd
4033    ){
4034    return(U_EMR_CORE9_set(U_EMR_ARC,rclBox, ptlStart, ptlEnd));
4035 }
4036 
4037 // U_EMRCHORD_set                     46
4038 /**
4039     \brief Allocate and construct a U_EMR_CHORD record.
4040     \return pointer to U_EMR_CHORD record, or NULL on error.
4041     \param rclBox   bounding rectangle in logical units
4042     \param ptlStart Start point in logical units
4043     \param ptlEnd   End point in logical units
4044 */
U_EMRCHORD_set(const U_RECTL rclBox,const U_POINTL ptlStart,const U_POINTL ptlEnd)4045 char *U_EMRCHORD_set(
4046       const U_RECTL  rclBox,
4047       const U_POINTL ptlStart,
4048       const U_POINTL ptlEnd
4049    ){
4050    return(U_EMR_CORE9_set(U_EMR_CHORD,rclBox, ptlStart, ptlEnd));
4051 }
4052 
4053 // U_EMRPIE_set                       47
4054 /**
4055     \brief Allocate and construct a U_EMR_PIE record.
4056     \return pointer to U_EMR_PIE record, or NULL on error.
4057     \param rclBox   bounding rectangle in logical units
4058     \param ptlStart Start point in logical units
4059     \param ptlEnd   End point in logical units
4060 */
U_EMRPIE_set(const U_RECTL rclBox,const U_POINTL ptlStart,const U_POINTL ptlEnd)4061 char *U_EMRPIE_set(
4062       const U_RECTL  rclBox,
4063       const U_POINTL ptlStart,
4064       const U_POINTL ptlEnd
4065    ){
4066    return(U_EMR_CORE9_set(U_EMR_PIE,rclBox, ptlStart, ptlEnd));
4067 }
4068 
4069 // U_EMRSELECTPALETTE_set             48
4070 /**
4071     \brief Allocate and construct a U_EMR_SELECTPALETTE record.
4072     \return pointer to U_EMR_SELECTPALETTE record, or NULL on error.
4073     \param ihPal Index of a Palette object in the EMF object table
4074 */
U_EMRSELECTPALETTE_set(const uint32_t ihPal)4075 char *U_EMRSELECTPALETTE_set(
4076       const uint32_t ihPal
4077    ){
4078    return(U_EMR_CORE3_set(U_EMR_SELECTPALETTE, ihPal));
4079 }
4080 
4081 // U_EMRCREATEPALETTE_set             49
4082 /**
4083     \brief Allocate and construct a U_EMR_CREATEPALETTE record.
4084     Use createpalette_set() instead of calling this function directly.
4085     \return pointer to U_EMR_CREATEPALETTE record, or NULL on error.
4086     \param ihPal Index to place object in EMF object table (this entry must not yet exist)
4087     \param lgpl   Palette properties
4088 */
U_EMRCREATEPALETTE_set(const uint32_t ihPal,const U_LOGPALETTE lgpl)4089 char *U_EMRCREATEPALETTE_set(
4090       const uint32_t     ihPal,
4091       const U_LOGPALETTE lgpl
4092    ){
4093    char *record;
4094    int  irecsize;
4095 
4096    irecsize = sizeof(U_EMRCREATEPALETTE);
4097    record   = malloc(irecsize);
4098    if(record){
4099       ((PU_EMR)              record)->iType   = U_EMR_CREATEPALETTE;
4100       ((PU_EMR)              record)->nSize   = irecsize;
4101       ((PU_EMRCREATEPALETTE) record)->ihPal   = ihPal;
4102       ((PU_EMRCREATEPALETTE) record)->lgpl    = lgpl;
4103    }
4104    return(record);
4105 }
4106 
4107 // U_EMRSETPALETTEENTRIES_set         50
4108 /**
4109     \brief Allocate and construct a U_EMR_SETPALETTEENTRIES record.
4110     Use setpaletteentries_set() instead of calling this function directly.
4111     \return pointer to U_EMR_SETPALETTEENTRIES record, or NULL on error.
4112     \param ihPal        Index of a Palette object in the EMF object table
4113     \param iStart       First Palette entry in selected object to set
4114     \param cEntries     Number of Palette entries in selected object to set
4115     \param aPalEntries  Values to set with
4116 */
U_EMRSETPALETTEENTRIES_set(const uint32_t ihPal,const uint32_t iStart,const U_NUM_LOGPLTNTRY cEntries,const PU_LOGPLTNTRY aPalEntries)4117 char *U_EMRSETPALETTEENTRIES_set(
4118       const uint32_t         ihPal,
4119       const uint32_t         iStart,
4120       const U_NUM_LOGPLTNTRY cEntries,
4121       const PU_LOGPLTNTRY    aPalEntries
4122    ){
4123    char *record;
4124    int  irecsize;
4125    int  cbPals;
4126 
4127    if(!aPalEntries)return(NULL);
4128    cbPals    = cEntries * sizeof(U_LOGPLTNTRY);
4129    irecsize = sizeof(U_EMRSETPALETTEENTRIES) + cbPals - sizeof(U_LOGPLTNTRY);
4130    record   = malloc(irecsize);
4131    if(record){
4132       ((PU_EMR)                  record)->iType      = U_EMR_SETPALETTEENTRIES;
4133       ((PU_EMR)                  record)->nSize      = irecsize;
4134       ((PU_EMRSETPALETTEENTRIES) record)->ihPal      = ihPal;
4135       ((PU_EMRSETPALETTEENTRIES) record)->iStart     = iStart;
4136       ((PU_EMRSETPALETTEENTRIES) record)->cEntries   = cEntries;
4137       memcpy(((PU_EMRSETPALETTEENTRIES) record)->aPalEntries, aPalEntries,cbPals);
4138    }
4139    return(record);
4140 }
4141 
4142 // U_EMRRESIZEPALETTE_set             51
4143 /**
4144     \brief Allocate and construct a U_EMR_RESIZEPALETTE record.
4145     \return pointer to U_EMR_RESIZEPALETTE record, or NULL on error.
4146     \param ihPal    Index of a Palette object in the EMF object table
4147     \param cEntries Number to expand or truncate the Palette entry list to
4148 */
U_EMRRESIZEPALETTE_set(const uint32_t ihPal,const uint32_t cEntries)4149 char *U_EMRRESIZEPALETTE_set(
4150       const uint32_t ihPal,
4151       const uint32_t cEntries
4152    ){
4153    return(U_EMR_CORE7_set(U_EMR_RESIZEPALETTE, (U_PAIR){ihPal,cEntries}));
4154 }
4155 
4156 // U_EMRREALIZEPALETTE_set            52
4157 /**
4158     \brief Allocate and construct a U_EMR_REALIZEPALETTE record.
4159     \return pointer to U_EMR_REALIZEPALETTE record, or NULL on error.
4160 */
U_EMRREALIZEPALETTE_set(void)4161 char *U_EMRREALIZEPALETTE_set(void){
4162   return(U_EMR_CORE5_set(U_EMR_REALIZEPALETTE));
4163 }
4164 
4165 // U_EMREXTFLOODFILL_set              53
4166 /**
4167     \brief Allocate and construct a U_EMR_EXTFLOODFILL record.
4168     \return pointer to U_EMR_EXTFLOODFILL record, or NULL on error.
4169     \param ptlStart Start point in logical units
4170     \param crColor  Color to fill with
4171     \param iMode    FloodFill Enumeration
4172 */
U_EMREXTFLOODFILL_set(const U_POINTL ptlStart,const U_COLORREF crColor,const uint32_t iMode)4173 char *U_EMREXTFLOODFILL_set(
4174       const U_POINTL   ptlStart,
4175       const U_COLORREF crColor,
4176       const uint32_t   iMode
4177    ){
4178    char *record;
4179    int  irecsize;
4180 
4181    irecsize = sizeof(U_EMREXTFLOODFILL);
4182    record   = malloc(irecsize);
4183    if(record){
4184       ((PU_EMR)             record)->iType    = U_EMR_EXTFLOODFILL;
4185       ((PU_EMR)             record)->nSize    = irecsize;
4186       ((PU_EMREXTFLOODFILL) record)->ptlStart = ptlStart;
4187       ((PU_EMREXTFLOODFILL) record)->crColor  = crColor;
4188       ((PU_EMREXTFLOODFILL) record)->iMode    = iMode;
4189    }
4190    return(record);
4191 }
4192 
4193 // U_EMRLINETO_set                    54
4194 /**
4195     \brief Allocate and construct a U_EMR_LINETO record.
4196     \return pointer to U_EMR_LINETO record, or NULL on error.
4197     \param ptl Point coordinates
4198 */
U_EMRLINETO_set(const U_POINTL ptl)4199 char *U_EMRLINETO_set(
4200       const U_POINTL ptl
4201    ){
4202    return(U_EMR_CORE7_set(U_EMR_LINETO, ptl));
4203 }
4204 
4205 // U_EMRARCTO_set                     55
4206 /**
4207     \brief Allocate and construct a U_EMR_ARCTO record.
4208     \return pointer to U_EMR_ARCTO record, or NULL on error.
4209     \param rclBox   bounding rectangle in logical units
4210     \param ptlStart Start point in logical units
4211     \param ptlEnd   End point in logical units
4212 
4213     Note that the draw begins with a line from the current point to ptlStart, which is
4214     not indicated in the Microsoft EMF documentation for this record.
4215 */
U_EMRARCTO_set(U_RECTL rclBox,U_POINTL ptlStart,U_POINTL ptlEnd)4216 char *U_EMRARCTO_set(
4217       U_RECTL             rclBox,
4218       U_POINTL            ptlStart,
4219       U_POINTL            ptlEnd
4220    ){
4221    return(U_EMR_CORE9_set(U_EMR_ARCTO,rclBox, ptlStart, ptlEnd));
4222 }
4223 
4224 // U_EMRPOLYDRAW_set                  56
4225 /**
4226     \brief Allocate and construct a U_EMR_POLYDRAW record.
4227     \return pointer to U_EMR_POLYDRAW record, or NULL on error.
4228     \param rclBounds Bounding rectangle in device units
4229     \param cptl      Number of U_POINTL objects
4230     \param aptl      Array of U_POINTL objects
4231     \param abTypes   Array of Point Enumeration
4232 */
U_EMRPOLYDRAW_set(const U_RECTL rclBounds,const U_NUM_POINTL cptl,const U_POINTL * aptl,const uint8_t * abTypes)4233 char *U_EMRPOLYDRAW_set(
4234       const U_RECTL       rclBounds,
4235       const U_NUM_POINTL  cptl,
4236       const U_POINTL     *aptl,
4237       const uint8_t      *abTypes
4238    ){
4239    char *record;
4240    int  irecsize;
4241    int  cbPoints, cbAbTypes, cbAbTypes4, off;
4242 
4243    if(!cptl || !aptl || !abTypes)return(NULL);
4244    cbPoints    = cptl * sizeof(U_POINTL);    // space for aptl
4245    cbAbTypes    = cptl;                       // number of abTypes (same array size, 1 byte each)
4246    cbAbTypes4    = UP4(cbAbTypes);                // space for abTypes
4247    irecsize = sizeof(U_EMRPOLYDRAW) + cbPoints + cbAbTypes4 - sizeof(U_POINTL) - 1;
4248    record   = malloc(irecsize);
4249    if(record){
4250       ((PU_EMR)         record)->iType       = U_EMR_POLYDRAW;
4251       ((PU_EMR)         record)->nSize       = irecsize;
4252       ((PU_EMRPOLYDRAW) record)->rclBounds   = rclBounds;
4253       ((PU_EMRPOLYDRAW) record)->cptl        = cptl;
4254       off = sizeof(U_EMR) + sizeof(U_RECTL) + sizeof(uint32_t);  // offset to first variable part
4255       memcpy(record+off,aptl,cbPoints);
4256       off += cbPoints;
4257       memcpy(record+off,abTypes,cbAbTypes);
4258       off += cbAbTypes;
4259       if(cbAbTypes4 > cbAbTypes){ memset(record+off,0,cbAbTypes4-cbAbTypes); } // keeps valgrind happy (initialize padding after byte array)
4260    }
4261    return(record);
4262 }
4263 
4264 // U_EMRSETARCDIRECTION_set           57
4265 /**
4266     \brief Allocate and construct a U_EMR_SETARCDIRECTION record.
4267     \return pointer to U_EMR_SETARCDIRECTION record, or NULL on error.
4268     \param iArcDirection ArcDirection Enumeration
4269 */
U_EMRSETARCDIRECTION_set(const uint32_t iArcDirection)4270 char *U_EMRSETARCDIRECTION_set(
4271       const uint32_t iArcDirection
4272    ){
4273    return(U_EMR_CORE3_set(U_EMR_SETARCDIRECTION, iArcDirection));
4274 }
4275 
4276 // U_EMRSETMITERLIMIT_set             58
4277 /**
4278     \brief Allocate and construct a U_EMR_SETMITERLIMIT record.
4279     \return pointer to U_EMR_SETMITERLIMIT record, or NULL on error.
4280     \param eMiterLimit MapMode Enumeration
4281 */
U_EMRSETMITERLIMIT_set(const uint32_t eMiterLimit)4282 char *U_EMRSETMITERLIMIT_set(
4283       const uint32_t eMiterLimit
4284    ){
4285    return(U_EMR_CORE3_set(U_EMR_SETMITERLIMIT, eMiterLimit));
4286 }
4287 
4288 
4289 // U_EMRBEGINPATH_set                 59
4290 /**
4291     \brief Allocate and construct a U_EMR_BEGINPATH record.
4292     \return pointer to U_EMR_BEGINPATH record, or NULL on error.
4293 */
U_EMRBEGINPATH_set(void)4294 char *U_EMRBEGINPATH_set(void){
4295    return(U_EMR_CORE5_set(U_EMR_BEGINPATH));
4296 }
4297 
4298 // U_EMRENDPATH_set                   60
4299 /**
4300     \brief Allocate and construct a U_EMR_ENDPATH record.
4301     \return pointer to U_EMR_ENDPATH record, or NULL on error.
4302 */
U_EMRENDPATH_set(void)4303 char *U_EMRENDPATH_set(void){
4304    return(U_EMR_CORE5_set(U_EMR_ENDPATH));
4305 }
4306 
4307 // U_EMRCLOSEFIGURE_set               61
4308 /**
4309     \brief Allocate and construct a U_EMR_CLOSEFIGURE record.
4310     \return pointer to U_EMR_CLOSEFIGURE record, or NULL on error.
4311 */
U_EMRCLOSEFIGURE_set(void)4312 char *U_EMRCLOSEFIGURE_set(void){
4313    return(U_EMR_CORE5_set(U_EMR_CLOSEFIGURE));
4314 }
4315 
4316 // U_EMRFILLPATH_set                  62
4317 /**
4318     \brief Allocate and construct a U_EMR_FILLPATH record.
4319     \return pointer to U_EMR_FILLPATH record, or NULL on error.
4320     \param rclBox Bounding rectangle in device units
4321 
4322     U_EMR_FILLPATH closes the open figure before filling.
4323 */
U_EMRFILLPATH_set(const U_RECTL rclBox)4324 char *U_EMRFILLPATH_set(
4325       const U_RECTL rclBox
4326    ){
4327    return(U_EMR_CORE4_set(U_EMR_FILLPATH,rclBox));
4328 }
4329 
4330 // U_EMRSTROKEANDFILLPATH_set         63
4331 /**
4332     \brief Allocate and construct a U_EMR_STROKEANDFILLPATH record.
4333     \return pointer to U_EMR_STROKEANDFILLPATH record, or NULL on error.
4334     \param rclBox Bounding rectangle in device units
4335 
4336     U_EMR_STROKEANDFILLPATH closes the open figure before filling and stroking.
4337     There appears to be no way to fill an open path while stroking it, as any one
4338     of U_EMRFILLPATH, U_EMRSTROKEPATH, or U_EMRSTROKEANDFILEPATH will "use up" the path,
4339 */
U_EMRSTROKEANDFILLPATH_set(const U_RECTL rclBox)4340 char *U_EMRSTROKEANDFILLPATH_set(
4341       const U_RECTL rclBox
4342    ){
4343    return(U_EMR_CORE4_set(U_EMR_STROKEANDFILLPATH,rclBox));
4344 }
4345 
4346 // U_EMRSTROKEPATH_set                64
4347 /**
4348     \brief Allocate and construct a U_EMR_STROKEPATH record.
4349     \return pointer to U_EMR_STROKEPATH record, or NULL on error.
4350     \param rclBox Bounding rectangle in device units
4351 
4352     U_EMR_STROKEPATH does NOT close the open figure before stroking it.
4353 */
U_EMRSTROKEPATH_set(const U_RECTL rclBox)4354 char *U_EMRSTROKEPATH_set(
4355       const U_RECTL rclBox
4356    ){
4357    return(U_EMR_CORE4_set(U_EMR_STROKEPATH,rclBox));
4358 }
4359 
4360 // U_EMRFLATTENPATH_set               65
4361 /**
4362     \brief Allocate and construct a U_EMR_FLATTENPATH record.
4363     \return pointer to U_EMR_FLATTENPATH record, or NULL on error.
4364 */
U_EMRFLATTENPATH_set(void)4365 char *U_EMRFLATTENPATH_set(void){
4366    return(U_EMR_CORE5_set(U_EMR_FLATTENPATH));
4367 }
4368 
4369 // U_EMRWIDENPATH_set                 66
4370 /**
4371     \brief Allocate and construct a U_EMR_WIDENPATH record.
4372     \return pointer to U_EMR_WIDENPATH record, or NULL on error.
4373 */
U_EMRWIDENPATH_set(void)4374 char *U_EMRWIDENPATH_set(void){
4375    return(U_EMR_CORE5_set(U_EMR_WIDENPATH));
4376 }
4377 
4378 // U_EMRSELECTCLIPPATH_set            67
4379 /**
4380     \brief Allocate and construct a U_EMR_SELECTCLIPPATH record.
4381     \return pointer to U_EMR_SELECTCLIPPATH record, or NULL on error.
4382     \param iMode RegionMode Enumeration
4383 */
U_EMRSELECTCLIPPATH_set(const uint32_t iMode)4384 char *U_EMRSELECTCLIPPATH_set(
4385       const uint32_t iMode
4386    ){
4387    return(U_EMR_CORE3_set(U_EMR_SELECTCLIPPATH, iMode));
4388 }
4389 
4390 // U_EMRABORTPATH_set                 68
4391 /**
4392     \brief Allocate and construct a U_EMR_ABORTPATH record.
4393     \return pointer to U_EMR_ABORTPATH record, or NULL on error.
4394 */
U_EMRABORTPATH_set(void)4395 char *U_EMRABORTPATH_set(void){
4396    return(U_EMR_CORE5_set(U_EMR_ABORTPATH));
4397 }
4398 
4399 // U_EMRUNDEF69                       69
4400 
4401 // U_EMRCOMMENT_set                   70  Comment (any binary data, interpretation is program specific)
4402 /**
4403     \brief Allocate and construct a U_EMR_COMMENT record.
4404     \return pointer to U_EMR_COMMENT record, or NULL on error.
4405     \param cbData Number of bytes in comment
4406     \param Data   Comment (any binary data, interpretation is program specific)
4407 */
U_EMRCOMMENT_set(const U_CBDATA cbData,const char * Data)4408 char *U_EMRCOMMENT_set(
4409       const U_CBDATA cbData,
4410       const char    *Data
4411    ){
4412    char *record;
4413    unsigned int   cbData4;
4414    int   irecsize;
4415 
4416    cbData4    = UP4(cbData);
4417    irecsize = sizeof(U_EMR) + sizeof(U_CBDATA) + cbData4;
4418    record    = malloc(irecsize);
4419    if(record){
4420       ((PU_EMR)           record)->iType   = U_EMR_COMMENT;
4421       ((PU_EMR)           record)->nSize   = irecsize;
4422       ((PU_EMRCOMMENT)    record)->cbData  = cbData;
4423       memcpy(record + irecsize - cbData4,Data,cbData);
4424       if(cbData4 > cbData)memset(record + irecsize - cbData4 + cbData,0,cbData4-cbData);  // clear any unused bytes
4425    }
4426    return(record);
4427 }
4428 
4429 // U_EMRFILLRGN_set                   71
4430 /**
4431     \brief Allocate and construct a U_EMR_FILLRGN record.
4432     Use fillrgn_set() instead of calling this function directly.
4433     \return pointer to U_EMR_FILLRGN record, or NULL on error.
4434     \param rclBounds  Bounding rectangle in device units
4435     \param ihBrush    Index of a Brush object in the EMF object table
4436     \param RgnData    Pointer to a U_RGNDATA structure
4437 */
U_EMRFILLRGN_set(const U_RECTL rclBounds,const uint32_t ihBrush,const PU_RGNDATA RgnData)4438 char *U_EMRFILLRGN_set(
4439       const U_RECTL     rclBounds,
4440       const uint32_t    ihBrush,
4441       const PU_RGNDATA  RgnData
4442    ){
4443    char *record;
4444    int   irecsize;
4445    int   cbRgns,cbRgns4,rds,rds4,off;
4446 
4447    if(!RgnData)return(NULL);
4448    cbRgns   = ((PU_RGNDATAHEADER) RgnData)->nRgnSize;
4449    cbRgns4  = UP4(cbRgns);
4450    rds      = sizeof(U_RGNDATAHEADER) + cbRgns;
4451    rds4     = UP4(rds);
4452    irecsize = sizeof(U_EMRFILLRGN) - sizeof(U_RECTL) + cbRgns4;  // core + array - overlap of one rectL
4453    record    = malloc(irecsize);
4454    if(record){
4455       ((PU_EMR)           record)->iType     = U_EMR_FILLRGN;
4456       ((PU_EMR)           record)->nSize     = irecsize;
4457       ((PU_EMRFILLRGN)    record)->rclBounds = rclBounds;
4458       ((PU_EMRFILLRGN)    record)->cbRgnData = rds;
4459       ((PU_EMRFILLRGN)    record)->ihBrush   = ihBrush;
4460       off = sizeof(U_EMRFILLRGN) - sizeof(U_RGNDATA);
4461       memcpy(record + off, RgnData, rds);
4462       off += rds;
4463       if(rds < rds4){ memset(record + off,0, rds4 - rds); } // clear any unused bytes
4464    }
4465    return(record);
4466 }
4467 
4468 // U_EMRFRAMERGN_set                  72
4469 /**
4470     \brief Allocate and construct a U_EMR_FRAMERGN record.
4471     Use framegrn_set() instead of calling this function directly.
4472     \return pointer to U_EMR_FRAMERGN record, or NULL on error.
4473     \param rclBounds  Bounding rectangle in device units
4474     \param ihBrush    Index of a Brush object in the EMF object table
4475     \param szlStroke  W & H of Brush stroke
4476     \param RgnData    Pointer to a U_RGNDATA structure
4477 */
U_EMRFRAMERGN_set(const U_RECTL rclBounds,const uint32_t ihBrush,const U_SIZEL szlStroke,const PU_RGNDATA RgnData)4478 char *U_EMRFRAMERGN_set(
4479       const U_RECTL     rclBounds,
4480       const uint32_t    ihBrush,
4481       const U_SIZEL     szlStroke,
4482       const PU_RGNDATA  RgnData
4483    ){
4484    char *record;
4485    int   irecsize;
4486    int   cbRgns,cbRgns4,rds,rds4,off;
4487 
4488    if(!RgnData)return(NULL);
4489    cbRgns   = ((PU_RGNDATAHEADER) RgnData)->nRgnSize;
4490    cbRgns4  = UP4(cbRgns);
4491    rds      = sizeof(U_RGNDATAHEADER) + cbRgns;
4492    rds4     = UP4(rds);
4493    irecsize = sizeof(U_EMRFRAMERGN) - sizeof(U_RECTL) + cbRgns4;  // core + array - overlap of one rectL
4494    record    = malloc(irecsize);
4495    if(record){
4496       ((PU_EMR)           record)->iType     = U_EMR_FRAMERGN;
4497       ((PU_EMR)           record)->nSize     = irecsize;
4498       ((PU_EMRFRAMERGN)   record)->rclBounds = rclBounds;
4499       ((PU_EMRFRAMERGN)   record)->cbRgnData = rds;
4500       ((PU_EMRFRAMERGN)   record)->ihBrush   = ihBrush;
4501       ((PU_EMRFRAMERGN)   record)->szlStroke = szlStroke;
4502       off = sizeof(U_EMRFRAMERGN) - sizeof(U_RGNDATA);
4503       memcpy(record + off, RgnData, rds);
4504       off += rds;
4505       if(rds < rds4){ memset(record + off,0, rds4 - rds); } // clear any unused bytes
4506    }
4507    return(record);
4508 }
4509 
4510 // U_EMRINVERTRGN_set                 73
4511 /**
4512     \brief Allocate and construct a U_EMR_INVERTRGN record.
4513     \return pointer to U_EMR_INVERTRGN record, or NULL on error.
4514     \param RgnData Variable size U_RGNDATA structure
4515 */
U_EMRINVERTRGN_set(const PU_RGNDATA RgnData)4516 char *U_EMRINVERTRGN_set(
4517       const PU_RGNDATA RgnData
4518    ){
4519    return(U_EMR_CORE11_set(U_EMR_INVERTRGN, RgnData));
4520 }
4521 
4522 // U_EMRPAINTRGN_set                  74
4523 /**
4524     \brief Allocate and construct a U_EMR_PAINTRGN record.
4525     \return pointer to U_EMR_PAINTRGN record, or NULL on error.
4526     \param RgnData Variable size U_RGNDATA structure
4527 */
U_EMRPAINTRGN_set(const PU_RGNDATA RgnData)4528 char *U_EMRPAINTRGN_set(
4529       const PU_RGNDATA RgnData
4530    ){
4531    return(U_EMR_CORE11_set(U_EMR_PAINTRGN, RgnData));
4532 }
4533 
4534 // U_EMREXTSELECTCLIPRGN_set          75
4535 /**
4536     \brief Allocate and construct a U_EMR_EXTSELECTCLIPRGN record.
4537     \return pointer to U_EMR_EXTSELECTCLIPRGN or NULL on error.
4538     \param iMode   RegionMode Enumeration
4539     \param RgnData Variable size U_RGNDATA structure
4540 */
U_EMREXTSELECTCLIPRGN_set(const uint32_t iMode,const PU_RGNDATA RgnData)4541 char *U_EMREXTSELECTCLIPRGN_set(
4542       const uint32_t    iMode,
4543       const PU_RGNDATA  RgnData
4544    ){
4545    char *record;
4546    int   irecsize;
4547    int   cbRgns,cbRgns4,rds,rds4,off;
4548 
4549    if(!RgnData)return(NULL);
4550    cbRgns   = ((PU_RGNDATAHEADER) RgnData)->nRgnSize;
4551    cbRgns4  = UP4(cbRgns);
4552    rds      = sizeof(U_RGNDATAHEADER) + cbRgns;
4553    rds4     = UP4(rds);
4554    irecsize = sizeof(U_EMREXTSELECTCLIPRGN) - sizeof(U_RECTL) + cbRgns4;  // core + array - overlap of one rectL
4555    record    = malloc(irecsize);
4556    if(record){
4557       ((PU_EMR)                  record)->iType     = U_EMR_EXTSELECTCLIPRGN;
4558       ((PU_EMR)                  record)->nSize     = irecsize;
4559       ((PU_EMREXTSELECTCLIPRGN)  record)->cbRgnData = rds;
4560       ((PU_EMREXTSELECTCLIPRGN)  record)->iMode     = iMode;
4561       off = sizeof(U_EMREXTSELECTCLIPRGN) - sizeof(U_RGNDATA);
4562       memcpy(record + off, RgnData, rds);
4563       off += rds;
4564       if(rds < rds4){ memset(record + off,0, rds4 - rds); } // clear any unused bytes
4565    }
4566    return(record);
4567 }
4568 
4569 // U_EMRBITBLT_set                    76
4570 /**
4571     \brief Allocate and construct a U_EMR_BITBLT record.
4572     \return pointer to U_EMR_BITBLT record, or NULL on error.
4573     \param rclBounds    Bounding rectangle in device units
4574     \param Dest         Destination UL corner in logical units
4575     \param cDest        Destination width in logical units
4576     \param Src          Source rectangle UL corner in logical units
4577     \param xformSrc     Source bitmap transform (world to page coordinates)
4578     \param crBkColorSrc Source bitmap background color
4579     \param iUsageSrc    DIBcolors Enumeration
4580     \param dwRop        Ternary Raster Operation enumeration
4581     \param Bmi          (Optional) bitmapbuffer (U_BITMAPINFO section)
4582     \param cbPx         Size in bytes of pixel array (row stride * height, there may be some padding at the end of each row)
4583     \param Px           (Optional) bitmapbuffer (pixel array section )
4584 */
U_EMRBITBLT_set(const U_RECTL rclBounds,const U_POINTL Dest,const U_POINTL cDest,const U_POINTL Src,const U_XFORM xformSrc,const U_COLORREF crBkColorSrc,const uint32_t iUsageSrc,const uint32_t dwRop,const PU_BITMAPINFO Bmi,const uint32_t cbPx,char * Px)4585 char *U_EMRBITBLT_set(
4586       const U_RECTL        rclBounds,
4587       const U_POINTL       Dest,
4588       const U_POINTL       cDest,
4589       const U_POINTL       Src,
4590       const U_XFORM        xformSrc,
4591       const U_COLORREF     crBkColorSrc,
4592       const uint32_t       iUsageSrc,
4593       const uint32_t       dwRop,
4594       const PU_BITMAPINFO  Bmi,
4595       const uint32_t       cbPx,
4596       char                *Px
4597    ){
4598    char *record;
4599    int   irecsize;
4600    int   cbImage,cbImage4,cbBmi,off;
4601 
4602    SET_CB_FROM_PXBMI(Px,Bmi,cbImage,cbImage4,cbBmi,cbPx);
4603    irecsize = sizeof(U_EMRBITBLT) + cbBmi + cbImage4;
4604    record   = malloc(irecsize);
4605    if(record){
4606       ((PU_EMR)             record)->iType        = U_EMR_BITBLT;
4607       ((PU_EMR)             record)->nSize        = irecsize;
4608       ((PU_EMRBITBLT)       record)->rclBounds    = rclBounds;
4609       ((PU_EMRBITBLT)       record)->Dest         = Dest;
4610       ((PU_EMRBITBLT)       record)->cDest        = cDest;
4611       ((PU_EMRBITBLT)       record)->dwRop        = dwRop;
4612       ((PU_EMRBITBLT)       record)->Src          = Src;
4613       ((PU_EMRBITBLT)       record)->xformSrc     = xformSrc;
4614       ((PU_EMRBITBLT)       record)->crBkColorSrc = crBkColorSrc;
4615       ((PU_EMRBITBLT)       record)->iUsageSrc    = iUsageSrc;
4616       off = sizeof(U_EMRBITBLT);
4617       APPEND_PXBMISRC(record, U_EMRBITBLT, cbBmi, Bmi, Px, cbImage, cbImage4);
4618    }
4619    return(record);
4620 }
4621 
4622 // U_EMRSTRETCHBLT_set                77
4623 /**
4624     \brief Allocate and construct a U_EMR_STRETCHBLT record.
4625     \return pointer to U_EMR_STRETCHBLT record, or NULL on error.
4626     \param rclBounds    Bounding rectangle in device units
4627     \param Dest         Destination UL corner in logical units
4628     \param cDest        Destination width in logical units
4629     \param Src          Source UL corner in logical units
4630     \param cSrc         Src W & H in logical units
4631     \param xformSrc     Transform to apply to source
4632     \param crBkColorSrc Background color
4633     \param iUsageSrc    DIBcolors Enumeration
4634     \param dwRop        Ternary Raster Operation enumeration
4635     \param Bmi          (Optional) bitmapbuffer (U_BITMAPINFO section)
4636     \param cbPx         Size in bytes of pixel array (row stride * height, there may be some padding at the end of each row)
4637     \param Px           (Optional) bitmapbuffer (pixel array section )
4638 */
U_EMRSTRETCHBLT_set(const U_RECTL rclBounds,const U_POINTL Dest,const U_POINTL cDest,const U_POINTL Src,const U_POINTL cSrc,const U_XFORM xformSrc,const U_COLORREF crBkColorSrc,const uint32_t iUsageSrc,const uint32_t dwRop,const PU_BITMAPINFO Bmi,const uint32_t cbPx,char * Px)4639 char *U_EMRSTRETCHBLT_set(
4640       const U_RECTL        rclBounds,
4641       const U_POINTL       Dest,
4642       const U_POINTL       cDest,
4643       const U_POINTL       Src,
4644       const U_POINTL       cSrc,
4645       const U_XFORM        xformSrc,
4646       const U_COLORREF     crBkColorSrc,
4647       const uint32_t       iUsageSrc,
4648       const uint32_t       dwRop,
4649       const PU_BITMAPINFO  Bmi,
4650       const uint32_t       cbPx,
4651       char                *Px
4652    ){
4653    char *record;
4654    int   irecsize;
4655    int   cbImage,cbImage4,cbBmi,off;
4656 
4657    SET_CB_FROM_PXBMI(Px,Bmi,cbImage,cbImage4,cbBmi,cbPx);
4658 
4659    irecsize = sizeof(U_EMRSTRETCHBLT) + cbBmi + cbImage4;
4660    record   = malloc(irecsize);
4661    if(record){
4662       ((PU_EMR)                 record)->iType        = U_EMR_STRETCHBLT;
4663       ((PU_EMR)                 record)->nSize        = irecsize;
4664       ((PU_EMRSTRETCHBLT)       record)->rclBounds    = rclBounds;
4665       ((PU_EMRSTRETCHBLT)       record)->Dest         = Dest;
4666       ((PU_EMRSTRETCHBLT)       record)->cDest        = cDest;
4667       ((PU_EMRSTRETCHBLT)       record)->dwRop        = dwRop;
4668       ((PU_EMRSTRETCHBLT)       record)->Src          = Src;
4669       ((PU_EMRSTRETCHBLT)       record)->xformSrc     = xformSrc;
4670       ((PU_EMRSTRETCHBLT)       record)->crBkColorSrc = crBkColorSrc;
4671       ((PU_EMRSTRETCHBLT)       record)->iUsageSrc    = iUsageSrc;
4672       off = sizeof(U_EMRSTRETCHBLT);
4673       APPEND_PXBMISRC(record, U_EMRSTRETCHBLT, cbBmi, Bmi, Px, cbImage, cbImage4);
4674       ((PU_EMRSTRETCHBLT)       record)->cSrc         = cSrc;
4675    }
4676    return(record);
4677 }
4678 
4679 // U_EMRMASKBLT_set                   78
4680 /**
4681     \brief Allocate and construct a U_EMR_MASKBLT record.
4682     \return pointer to U_EMR_MASKBLT record, or NULL on error.
4683     \param rclBounds    Bounding rectangle in device units
4684     \param Dest         Destination UL corner in logical units
4685     \param cDest        Destination width in logical units
4686     \param Src          Source UL corner in logical units
4687     \param xformSrc     Transform to apply to source
4688     \param crBkColorSrc Background color
4689     \param iUsageSrc    DIBcolors Enumeration
4690     \param Mask         Mask UL corner in logical units
4691     \param iUsageMask   DIBcolors Enumeration
4692     \param dwRop        Ternary Raster Operation enumeration
4693     \param Bmi          (Optional) bitmapbuffer (U_BITMAPINFO section)
4694     \param cbPx         Size in bytes of pixel array (row stride * height, there may be some padding at the end of each row)
4695     \param Px           (Optional) bitmapbuffer (pixel array section )
4696     \param MskBmi       (Optional) bitmapbuffer (U_BITMAPINFO section)
4697     \param cbMsk        Size in bytes of mask array (row stride * height, there may be some padding at the end of each row)
4698     \param Msk          (Optional) bitmapbuffer (mask section )
4699 */
U_EMRMASKBLT_set(const U_RECTL rclBounds,const U_POINTL Dest,const U_POINTL cDest,const U_POINTL Src,const U_XFORM xformSrc,const U_COLORREF crBkColorSrc,const uint32_t iUsageSrc,const U_POINTL Mask,const uint32_t iUsageMask,const uint32_t dwRop,const PU_BITMAPINFO Bmi,const uint32_t cbPx,char * Px,const PU_BITMAPINFO MskBmi,const uint32_t cbMsk,char * Msk)4700 char *U_EMRMASKBLT_set(
4701       const U_RECTL        rclBounds,
4702       const U_POINTL       Dest,
4703       const U_POINTL       cDest,
4704       const U_POINTL       Src,
4705       const U_XFORM        xformSrc,
4706       const U_COLORREF     crBkColorSrc,
4707       const uint32_t       iUsageSrc,
4708       const U_POINTL       Mask,
4709       const uint32_t       iUsageMask,
4710       const uint32_t       dwRop,
4711       const PU_BITMAPINFO  Bmi,
4712       const uint32_t       cbPx,
4713       char                *Px,
4714       const PU_BITMAPINFO  MskBmi,
4715       const uint32_t       cbMsk,
4716       char                *Msk
4717    ){
4718    char *record;
4719    int   irecsize;
4720    int   cbImage,cbImage4,cbBmi,cbMskImage,cbMskImage4,cbMskBmi,off;
4721 
4722    SET_CB_FROM_PXBMI(Px,Bmi,cbImage,cbImage4,cbBmi,cbPx);
4723    SET_CB_FROM_PXBMI(Msk,MskBmi,cbMskImage,cbMskImage4,cbMskBmi,cbMsk);
4724 
4725    irecsize = sizeof(U_EMRMASKBLT) + cbBmi + cbImage4 + cbMskBmi + cbMskImage4;
4726    record   = malloc(irecsize);
4727    if(record){
4728       ((PU_EMR)              record)->iType        = U_EMR_MASKBLT;
4729       ((PU_EMR)              record)->nSize        = irecsize;
4730       ((PU_EMRMASKBLT)       record)->rclBounds    = rclBounds;
4731       ((PU_EMRMASKBLT)       record)->Dest         = Dest;
4732       ((PU_EMRMASKBLT)       record)->cDest        = cDest;
4733       ((PU_EMRMASKBLT)       record)->dwRop        = dwRop;
4734       ((PU_EMRMASKBLT)       record)->Src          = Src;
4735       ((PU_EMRMASKBLT)       record)->xformSrc     = xformSrc;
4736       ((PU_EMRMASKBLT)       record)->crBkColorSrc = crBkColorSrc;
4737       ((PU_EMRMASKBLT)       record)->iUsageSrc    = iUsageSrc;
4738       ((PU_EMRMASKBLT)       record)->Mask         = Mask;
4739       ((PU_EMRMASKBLT)       record)->iUsageMask   = iUsageMask;
4740       off = sizeof(U_EMRMASKBLT);
4741       APPEND_PXBMISRC(record, U_EMRMASKBLT, cbBmi, Bmi, Px, cbImage, cbImage4);
4742       APPEND_MSKBMISRC(record, U_EMRMASKBLT, cbMskBmi, MskBmi, Msk, cbMskImage, cbMskImage4);
4743    }
4744    return(record);
4745 }
4746 
4747 // U_EMRPLGBLT_set                    79
4748 
4749 /**
4750     \brief Allocate and construct a U_EMRPLGBLT record.
4751     \return U_EMRPLGBLT record.
4752     \param rclBounds    Bounding rectangle in device units
4753     \param aptlDst      Defines parallelogram, UL, UR, LL corners, LR is derived (3 points)
4754     \param Src          Source UL corner in logical units
4755     \param cSrc         Source width in logical units
4756     \param xformSrc     Transform to apply to source
4757     \param crBkColorSrc Background color
4758     \param iUsageSrc    DIBcolors Enumeration
4759     \param Mask         Mask UL corner in logical units
4760     \param iUsageMask   DIBcolors Enumeration
4761     \param Bmi          (Optional) bitmapbuffer (U_BITMAPINFO section)
4762     \param cbPx         Size in bytes of pixel array (row stride * height, there may be some padding at the end of each row)
4763     \param Px           (Optional) bitmapbuffer (pixel array section )
4764     \param MskBmi       (Optional) bitmapbuffer (U_BITMAPINFO section)
4765     \param cbMsk        Size in bytes of mask array (row stride * height, there may be some padding at the end of each row)
4766     \param Msk          (Optional) bitmapbuffer (mask section )
4767 */
U_EMRPLGBLT_set(const U_RECTL rclBounds,const PU_POINTL aptlDst,const U_POINTL Src,const U_POINTL cSrc,const U_XFORM xformSrc,const U_COLORREF crBkColorSrc,const uint32_t iUsageSrc,const U_POINTL Mask,const uint32_t iUsageMask,const PU_BITMAPINFO Bmi,const uint32_t cbPx,char * Px,const PU_BITMAPINFO MskBmi,const uint32_t cbMsk,char * Msk)4768 char *U_EMRPLGBLT_set(
4769       const U_RECTL       rclBounds,
4770       const PU_POINTL     aptlDst,
4771       const U_POINTL      Src,
4772       const U_POINTL      cSrc,
4773       const U_XFORM       xformSrc,
4774       const U_COLORREF    crBkColorSrc,
4775       const uint32_t      iUsageSrc,
4776       const U_POINTL      Mask,
4777       const uint32_t      iUsageMask,
4778       const PU_BITMAPINFO Bmi,
4779       const uint32_t      cbPx,
4780       char               *Px,
4781       const PU_BITMAPINFO MskBmi,
4782       const uint32_t      cbMsk,
4783       char               *Msk
4784    ){
4785    char *record;
4786    int   irecsize;
4787    int   cbImage,cbImage4,cbBmi,cbMskImage,cbMskImage4,cbMskBmi,off;
4788 
4789    SET_CB_FROM_PXBMI(Px,Bmi,cbImage,cbImage4,cbBmi,cbPx);
4790    SET_CB_FROM_PXBMI(Msk,MskBmi,cbMskImage,cbMskImage4,cbMskBmi,cbMsk);
4791 
4792    irecsize = sizeof(U_EMRPLGBLT) + cbBmi + cbImage4 + cbMskBmi + cbMskImage4;
4793    record   = malloc(irecsize);
4794    if(record){
4795       ((PU_EMR)             record)->iType        = U_EMR_PLGBLT;
4796       ((PU_EMR)             record)->nSize        = irecsize;
4797       ((PU_EMRPLGBLT)       record)->rclBounds    = rclBounds;
4798       memcpy(((PU_EMRPLGBLT)  record)->aptlDst,aptlDst,3*sizeof(U_POINTL));
4799       ((PU_EMRPLGBLT)       record)->Src          = Src;
4800       ((PU_EMRPLGBLT)       record)->cSrc         = cSrc;
4801       ((PU_EMRPLGBLT)       record)->xformSrc     = xformSrc;
4802       ((PU_EMRPLGBLT)       record)->crBkColorSrc = crBkColorSrc;
4803       ((PU_EMRPLGBLT)       record)->iUsageSrc    = iUsageSrc;
4804       ((PU_EMRPLGBLT)       record)->Mask         = Mask;
4805       ((PU_EMRPLGBLT)       record)->iUsageMask   = iUsageMask;
4806       off = sizeof(U_EMRPLGBLT);
4807       APPEND_PXBMISRC(record, U_EMRPLGBLT, cbBmi, Bmi, Px, cbImage, cbImage4);
4808       APPEND_MSKBMISRC(record, U_EMRPLGBLT, cbMskBmi, MskBmi, Msk, cbMskImage, cbMskImage4);
4809    }
4810    return(record);
4811 }
4812 
4813 // U_EMRSETDIBITSTODEVICE_set         80
4814 /**
4815     \brief Allocate and construct a U_EMR_SETDIBITSTODEVICE record.
4816     \return pointer to U_EMR_SETDIBITSTODEVICE record, or NULL on error.
4817     \param rclBounds  Bounding rectangle in device units
4818     \param Dest       Destination UL corner in logical units
4819     \param Src        Source UL corner in logical units
4820     \param cSrc       Source W & H in logical units
4821     \param iUsageSrc  DIBColors Enumeration
4822     \param iStartScan First scan line
4823     \param cScans     Number of scan lines
4824     \param Bmi        (Optional) bitmapbuffer (U_BITMAPINFO section)
4825     \param cbPx       Size in bytes of pixel array (row stride * height, there may be some padding at the end of each row)
4826     \param Px         (Optional) bitmapbuffer (pixel array section )
4827 */
U_EMRSETDIBITSTODEVICE_set(const U_RECTL rclBounds,const U_POINTL Dest,const U_POINTL Src,const U_POINTL cSrc,const uint32_t iUsageSrc,const uint32_t iStartScan,const uint32_t cScans,const PU_BITMAPINFO Bmi,const uint32_t cbPx,char * Px)4828 char *U_EMRSETDIBITSTODEVICE_set(
4829       const U_RECTL        rclBounds,
4830       const U_POINTL       Dest,
4831       const U_POINTL       Src,
4832       const U_POINTL       cSrc,
4833       const uint32_t       iUsageSrc,
4834       const uint32_t       iStartScan,
4835       const uint32_t       cScans,
4836       const PU_BITMAPINFO  Bmi,
4837       const uint32_t       cbPx,
4838       char                *Px
4839    ){
4840    char *record;
4841    int   irecsize;
4842    int   cbImage,cbImage4,cbBmi,off;
4843 
4844    SET_CB_FROM_PXBMI(Px,Bmi,cbImage,cbImage4,cbBmi,cbPx);
4845 
4846    irecsize = sizeof(U_EMRSETDIBITSTODEVICE) + cbBmi + cbImage4;
4847    record   = malloc(irecsize);
4848    if(record){
4849       ((PU_EMR)                       record)->iType      = U_EMR_SETDIBITSTODEVICE;
4850       ((PU_EMR)                       record)->nSize      = irecsize;
4851       ((PU_EMRSETDIBITSTODEVICE)      record)->rclBounds  = rclBounds;
4852       ((PU_EMRSETDIBITSTODEVICE)      record)->Dest       = Dest;
4853       ((PU_EMRSETDIBITSTODEVICE)      record)->Src        = Src;
4854       ((PU_EMRSETDIBITSTODEVICE)      record)->cSrc       = cSrc;
4855       ((PU_EMRSETDIBITSTODEVICE)      record)->iUsageSrc  = iUsageSrc;
4856       ((PU_EMRSETDIBITSTODEVICE)      record)->iStartScan = iStartScan;
4857       ((PU_EMRSETDIBITSTODEVICE)      record)->cScans     = cScans;
4858       off = sizeof(U_EMRSETDIBITSTODEVICE);
4859       APPEND_PXBMISRC(record, U_EMRSETDIBITSTODEVICE, cbBmi, Bmi, Px, cbImage, cbImage4);
4860    }
4861    return(record);
4862 }
4863 
4864 // U_EMRSTRETCHDIBITS_set             81
4865 /**
4866     \brief Allocate and construct a U_EMR_EMRSTRETCHDIBITS record.
4867     \return pointer to U_EMR_EMRSTRETCHDIBITS record, or NULL on error.
4868     \param rclBounds Bounding rectangle in device units
4869     \param Dest      Destination UL corner in logical units
4870     \param cDest     Destination W & H in logical units
4871     \param Src       Source UL corner in logical units
4872     \param cSrc      Source W & H in logical units
4873     \param iUsageSrc DIBColors Enumeration
4874     \param dwRop     RasterOPeration Enumeration
4875     \param Bmi       (Optional) bitmapbuffer (U_BITMAPINFO section)
4876     \param cbPx      Size in bytes of pixel array (row STRIDE * height, there may be some padding at the end of each row)
4877     \param Px        (Optional) bitmapbuffer (pixel array section )
4878 */
U_EMRSTRETCHDIBITS_set(const U_RECTL rclBounds,const U_POINTL Dest,const U_POINTL cDest,const U_POINTL Src,const U_POINTL cSrc,const uint32_t iUsageSrc,const uint32_t dwRop,const PU_BITMAPINFO Bmi,const uint32_t cbPx,char * Px)4879 char *U_EMRSTRETCHDIBITS_set(
4880       const U_RECTL        rclBounds,
4881       const U_POINTL       Dest,
4882       const U_POINTL       cDest,
4883       const U_POINTL       Src,
4884       const U_POINTL       cSrc,
4885       const uint32_t       iUsageSrc,
4886       const uint32_t       dwRop,
4887       const PU_BITMAPINFO  Bmi,
4888       const uint32_t       cbPx,
4889       char                *Px
4890    ){
4891    char *record;
4892    int   irecsize;
4893    int   cbImage,cbImage4,cbBmi,off;
4894 
4895    SET_CB_FROM_PXBMI(Px,Bmi,cbImage,cbImage4,cbBmi,cbPx);
4896 
4897    irecsize = sizeof(U_EMRSTRETCHDIBITS) + cbBmi + cbImage4;
4898    record   = malloc(irecsize);
4899    if(record){
4900       ((PU_EMR)                    record)->iType      = U_EMR_STRETCHDIBITS;
4901       ((PU_EMR)                    record)->nSize      = irecsize;
4902       ((PU_EMRSTRETCHDIBITS)       record)->rclBounds  = rclBounds;
4903       ((PU_EMRSTRETCHDIBITS)       record)->Dest       = Dest;
4904       ((PU_EMRSTRETCHDIBITS)       record)->Src        = Src;
4905       ((PU_EMRSTRETCHDIBITS)       record)->cSrc       = cSrc;
4906       ((PU_EMRSTRETCHDIBITS)       record)->iUsageSrc  = iUsageSrc;
4907       ((PU_EMRSTRETCHDIBITS)       record)->dwRop      = dwRop;
4908       ((PU_EMRSTRETCHDIBITS)       record)->cDest      = cDest;
4909       off = sizeof(U_EMRSTRETCHDIBITS);
4910       APPEND_PXBMISRC(record, U_EMRSTRETCHDIBITS, cbBmi, Bmi, Px, cbImage, cbImage4);
4911    }
4912    return(record);
4913 }
4914 
4915 // U_EMREXTCREATEFONTINDIRECTW_set    82
4916 /**
4917     \brief Allocate and construct a U_EMR_EXTCREATEFONTINDIRECTW record.
4918     Use extcreatefontindirectw_set() instead of calling this function directly.
4919     \return pointer to U_EMR_EXTCREATEFONTINDIRECTW record, or NULL on error.
4920     \param ihFont Index of the font in the EMF object table
4921     \param elf    Font parameters as U_LOGFONT
4922     \param elfw   Font parameters as U_LOGFONT_PANOSE
4923 */
U_EMREXTCREATEFONTINDIRECTW_set(const uint32_t ihFont,const char * elf,const char * elfw)4924 char *U_EMREXTCREATEFONTINDIRECTW_set(
4925       const uint32_t               ihFont,
4926       const char *                 elf,
4927       const char *                 elfw
4928    ){
4929    char *record;
4930    const char *cptr;
4931    int   irecsize;
4932    int   cbLf,off;
4933 
4934    if((elf && elfw) || (!elf && !elfw))return(NULL);  // ONE only must be passed
4935    if(elf){ cbLf = sizeof(U_LOGFONT);        cptr = elf;  }
4936    else {   cbLf = sizeof(U_LOGFONT_PANOSE); cptr = elfw; }
4937 
4938    irecsize = sizeof(U_EMR) + sizeof(uint32_t) + cbLf;
4939    record    = malloc(irecsize);
4940    if(record){
4941       ((PU_EMR)                       record)->iType  = U_EMR_EXTCREATEFONTINDIRECTW;
4942       ((PU_EMR)                       record)->nSize  = irecsize;
4943       ((PU_EMREXTCREATEFONTINDIRECTW) record)->ihFont = ihFont;
4944       off = sizeof(U_EMR) + sizeof(uint32_t);
4945       memcpy(record + off, cptr, cbLf);    // No need to add padding for either structure
4946    }
4947    return(record);
4948 }
4949 
4950 // U_EMREXTTEXTOUTA_set               83
4951 /**
4952     \brief Allocate and construct a U_EMR_EXTTEXTOUTA record.
4953     \return pointer to U_EMR_EXTTEXTOUTA record, or NULL on error.
4954     \param rclBounds     Bounding rectangle in device units
4955     \param iGraphicsMode Graphics mode Enumeration
4956     \param exScale       scale to 0.01 mm units ( only if iGraphicsMode & GM_COMPATIBLE)
4957     \param eyScale       scale to 0.01 mm units ( only if iGraphicsMode & GM_COMPATIBLE)
4958     \param emrtext       Text parameters
4959 */
U_EMREXTTEXTOUTA_set(const U_RECTL rclBounds,const uint32_t iGraphicsMode,const U_FLOAT exScale,const U_FLOAT eyScale,const PU_EMRTEXT emrtext)4960 char *U_EMREXTTEXTOUTA_set(
4961       const U_RECTL     rclBounds,
4962       const uint32_t    iGraphicsMode,
4963       const U_FLOAT     exScale,
4964       const U_FLOAT     eyScale,
4965       const PU_EMRTEXT  emrtext
4966    ){
4967    return(U_EMR_CORE8_set(U_EMR_EXTTEXTOUTA,rclBounds, iGraphicsMode, exScale, eyScale,emrtext));
4968 }
4969 
4970 // U_EMREXTTEXTOUTW_set               84
4971 /**
4972     \brief Allocate and construct a U_EMR_EXTTEXTOUTW record.
4973     \return pointer to U_EMR_EXTTEXTOUTW record, or NULL on error.
4974     \param rclBounds     Bounding rectangle in device units
4975     \param iGraphicsMode Graphics mode Enumeration
4976     \param exScale       scale to 0.01 mm units ( only if iGraphicsMode & GM_COMPATIBLE)
4977     \param eyScale       scale to 0.01 mm units ( only if iGraphicsMode & GM_COMPATIBLE)
4978     \param emrtext       Text parameters
4979 */
U_EMREXTTEXTOUTW_set(const U_RECTL rclBounds,const uint32_t iGraphicsMode,const U_FLOAT exScale,const U_FLOAT eyScale,const PU_EMRTEXT emrtext)4980 char *U_EMREXTTEXTOUTW_set(
4981       const U_RECTL    rclBounds,
4982       const uint32_t   iGraphicsMode,
4983       const U_FLOAT    exScale,
4984       const U_FLOAT    eyScale,
4985       const PU_EMRTEXT emrtext
4986    ){
4987    return(U_EMR_CORE8_set(U_EMR_EXTTEXTOUTW,rclBounds, iGraphicsMode, exScale, eyScale,emrtext));
4988 }
4989 
4990 // U_EMRPOLYBEZIER16_set              85
4991 /**
4992     \brief Allocate and construct a U_EMR_POLYBEZIER16 record.
4993     \return pointer to U_EMR_POLYBEZIER16 record, or NULL on error.
4994     \param rclBounds Bounding rectangle in device units
4995     \param cpts      Number of POINT16 in array
4996     \param points    Array of POINT16
4997 */
U_EMRPOLYBEZIER16_set(const U_RECTL rclBounds,const uint32_t cpts,const U_POINT16 * points)4998 char *U_EMRPOLYBEZIER16_set(
4999       const U_RECTL    rclBounds,
5000       const uint32_t   cpts,
5001       const U_POINT16 *points
5002    ){
5003    return(U_EMR_CORE6_set(U_EMR_POLYBEZIER16, rclBounds, cpts, points));
5004 }
5005 
5006 // U_EMRPOLYGON16_set                 86
5007 /**
5008     \brief Allocate and construct a U_EMR_POLYGON16 record.
5009     \return pointer to U_EMR_POLYGON16 record, or NULL on error.
5010     \param rclBounds Bounding rectangle in device units
5011     \param cpts      Number of POINT16 in array
5012     \param points    Array of POINT16
5013 */
U_EMRPOLYGON16_set(const U_RECTL rclBounds,const uint32_t cpts,const U_POINT16 * points)5014 char *U_EMRPOLYGON16_set(
5015       const U_RECTL    rclBounds,
5016       const uint32_t   cpts,
5017       const U_POINT16 *points
5018    ){
5019    return(U_EMR_CORE6_set(U_EMR_POLYGON16, rclBounds, cpts, points));
5020 }
5021 
5022 // U_EMRPOLYLINE16_set                87
5023 /**
5024     \brief Allocate and construct a U_EMR_POLYLINE16 record.
5025     \return pointer to U_EMR_POLYLINE16 record, or NULL on error.
5026     \param rclBounds Bounding rectangle in device units
5027     \param cpts      Number of POINT16 in array
5028     \param points    Array of POINT16
5029 */
U_EMRPOLYLINE16_set(const U_RECTL rclBounds,const uint32_t cpts,const U_POINT16 * points)5030 char *U_EMRPOLYLINE16_set(
5031       const U_RECTL    rclBounds,
5032       const uint32_t   cpts,
5033       const U_POINT16 *points
5034    ){
5035    return(U_EMR_CORE6_set(U_EMR_POLYLINE16, rclBounds, cpts, points));
5036 }
5037 
5038 // U_EMRPOLYBEZIERTO16_set            88
5039 /**
5040     \brief Allocate and construct a U_EMR_POLYBEZIERTO record.
5041     \return pointer to U_EMR_POLYBEZIERTO record, or NULL on error.
5042     \param rclBounds Bounding rectangle in device units
5043     \param cpts      Number of POINT16 in array
5044     \param points    Array of POINT16
5045 */
U_EMRPOLYBEZIERTO16_set(const U_RECTL rclBounds,const uint32_t cpts,const U_POINT16 * points)5046 char *U_EMRPOLYBEZIERTO16_set(
5047       const U_RECTL    rclBounds,
5048       const uint32_t   cpts,
5049       const U_POINT16 *points
5050    ){
5051    return(U_EMR_CORE6_set(U_EMR_POLYBEZIERTO16, rclBounds, cpts, points));
5052 }
5053 
5054 // U_EMRPOLYLINETO16_set              89
5055 /**
5056     \brief Allocate and construct a U_EMR_POLYLINETO record.
5057     \return pointer to U_EMR_POLYLINETO record, or NULL on error.
5058     \param rclBounds Bounding rectangle in device units
5059     \param cpts      Number of POINT16 in array
5060     \param points    Array of POINT16
5061 */
U_EMRPOLYLINETO16_set(const U_RECTL rclBounds,const uint32_t cpts,const U_POINT16 * points)5062 char *U_EMRPOLYLINETO16_set(
5063       const U_RECTL    rclBounds,
5064       const uint32_t   cpts,
5065       const U_POINT16 *points
5066    ){
5067    return(U_EMR_CORE6_set(U_EMR_POLYLINETO16, rclBounds, cpts, points));
5068 }
5069 
5070 // U_EMRPOLYPOLYLINE16_set            90
5071 /**
5072     \brief Allocate and construct a U_EMR_POLYPOLYLINE16 record.
5073     \return pointer to U_EMR_POLYPOLYLINE16 record, or NULL on error.
5074     \param rclBounds   Bounding rectangle in device units
5075     \param nPolys      Number of elements in aPolyCounts
5076     \param aPolyCounts Number of points in each poly (sequential)
5077     \param cpts        Number of POINT16 in array
5078     \param points      Array of POINT16
5079 */
U_EMRPOLYPOLYLINE16_set(const U_RECTL rclBounds,const uint32_t nPolys,const uint32_t * aPolyCounts,const uint32_t cpts,const U_POINT16 * points)5080 char *U_EMRPOLYPOLYLINE16_set(
5081       const U_RECTL    rclBounds,
5082       const uint32_t   nPolys,
5083       const uint32_t  *aPolyCounts,
5084       const uint32_t   cpts,
5085       const U_POINT16 *points
5086    ){
5087    return(U_EMR_CORE10_set(U_EMR_POLYPOLYLINE16, rclBounds, nPolys, aPolyCounts,cpts, points));
5088 }
5089 
5090 // U_EMRPOLYPOLYGON16_set             91
5091 /**
5092     \brief Allocate and construct a U_EMR_POLYPOLYGON16 record.
5093     \return pointer to U_EMR_POLYPOLYGON16 record, or NULL on error.
5094     \param rclBounds   Bounding rectangle in device units
5095     \param nPolys      Number of elements in aPolyCounts
5096     \param aPolyCounts Number of points in each poly (sequential)
5097     \param cpts        Number of POINT16 in array
5098     \param points      Array of POINT16
5099 */
U_EMRPOLYPOLYGON16_set(const U_RECTL rclBounds,const uint32_t nPolys,const uint32_t * aPolyCounts,const uint32_t cpts,const U_POINT16 * points)5100 char *U_EMRPOLYPOLYGON16_set(
5101       const U_RECTL    rclBounds,
5102       const uint32_t   nPolys,
5103       const uint32_t  *aPolyCounts,
5104       const uint32_t   cpts,
5105       const U_POINT16 *points
5106    ){
5107    return(U_EMR_CORE10_set(U_EMR_POLYPOLYGON16, rclBounds, nPolys, aPolyCounts,cpts, points));
5108 }
5109 
5110 
5111 // U_EMRPOLYDRAW16_set                92
5112 /**
5113     \brief Allocate and construct a U_EMR_POLYDRAW16 record.
5114     \return pointer to U_EMR_POLYDRAW16 record, or NULL on error.
5115     \param rclBounds Bounding rectangle in device units
5116     \param cpts      Number of U_POINTL objects
5117     \param aptl      Array of U_POINTL objects
5118     \param abTypes   Array of Point Enumeration
5119 */
U_EMRPOLYDRAW16_set(const U_RECTL rclBounds,const U_NUM_POINT16 cpts,const U_POINT16 * aptl,const uint8_t * abTypes)5120 char *U_EMRPOLYDRAW16_set(
5121      const U_RECTL        rclBounds,
5122      const U_NUM_POINT16  cpts,
5123      const U_POINT16     *aptl,
5124      const uint8_t       *abTypes
5125    ){
5126    char *record;
5127    int  irecsize;
5128    int  cbPoints, cbAbTypes, cbAbTypes4, off;
5129 
5130    if(!cpts || !aptl || !abTypes)return(NULL);
5131    cbPoints    = cpts * sizeof(U_POINT16);  // space for aptl
5132    cbAbTypes    = cpts;                     // number of abTypes (same array size, 1 byte each)
5133    cbAbTypes4    = UP4(cbAbTypes);          // space for abTypes
5134    irecsize = sizeof(U_EMRPOLYDRAW16) + cbPoints + cbAbTypes4 - sizeof(U_POINT16) - 1;
5135    record   = malloc(irecsize);
5136    if(record){
5137       ((PU_EMR)           record)->iType      = U_EMR_POLYDRAW16;
5138       ((PU_EMR)           record)->nSize      = irecsize;
5139       ((PU_EMRPOLYDRAW16) record)->rclBounds  = rclBounds;
5140       ((PU_EMRPOLYDRAW16) record)->cpts       = cpts;
5141       off = sizeof(U_EMR) + sizeof(U_RECTL) + sizeof(uint32_t);  // offset to first variable part
5142       memcpy(record+off,aptl,cbPoints);
5143       off += cbPoints;
5144       memcpy(record+off,abTypes,cbAbTypes);
5145       off += cbAbTypes;
5146       if(cbAbTypes4 > cbAbTypes){ memset(record+off,0,cbAbTypes4-cbAbTypes); } // keeps valgrind happy (initialize padding after byte array)
5147    }
5148    return(record);
5149 }
5150 
5151 // U_EMRCREATEMONOBRUSH_set           93
5152 /**
5153     \brief Allocate and construct a U_EMR_CREATEMONOBRUSH record.
5154     \return pointer to U_EMR_CREATEMONOBRUSH record, or NULL on error.
5155     \param ihBrush Index to place object in EMF object table (this entry must not yet exist)
5156     \param iUsage  DIBcolors Enumeration
5157     \param Bmi     (Optional) bitmapbuffer (U_BITMAPINFO + pixel array)
5158     \param cbPx    Size in bytes of pixel array (row stride * height, there may be some padding at the end of each row)
5159     \param Px      (Optional) bitmapbuffer (pixel array section )
5160 */
U_EMRCREATEMONOBRUSH_set(const uint32_t ihBrush,const uint32_t iUsage,const PU_BITMAPINFO Bmi,const uint32_t cbPx,const char * Px)5161 char *U_EMRCREATEMONOBRUSH_set(
5162       const uint32_t            ihBrush,
5163       const uint32_t            iUsage,
5164       const PU_BITMAPINFO       Bmi,
5165       const uint32_t            cbPx,
5166       const char               *Px
5167    ){
5168    return(U_EMR_CORE12_set(U_EMR_CREATEMONOBRUSH,ihBrush,iUsage,Bmi,cbPx,Px));
5169 }
5170 
5171 // U_EMRCREATEDIBPATTERNBRUSHPT_set   94
5172 /**
5173     \brief Allocate and construct a U_EMR_CREATEDIBPATTERNBRUSHPT record.
5174     Use createdibpatternbrushpt_set() instead of calling this function directly.
5175     \return pointer to U_EMR_CREATEDIBPATTERNBRUSHPT record, or NULL on error.
5176     \param ihBrush Index to place object in EMF object table (this entry must not yet exist)
5177     \param iUsage  DIBcolors Enumeration
5178     \param Bmi     (Optional) bitmapbuffer (U_BITMAPINFO + pixel array)
5179     \param cbPx    Size in bytes of pixel array (row stride * height, there may be some padding at the end of each row)
5180     \param Px      (Optional) bitmapbuffer (pixel array section )
5181 */
U_EMRCREATEDIBPATTERNBRUSHPT_set(const uint32_t ihBrush,const uint32_t iUsage,const PU_BITMAPINFO Bmi,const uint32_t cbPx,const char * Px)5182 char *U_EMRCREATEDIBPATTERNBRUSHPT_set(
5183       const uint32_t            ihBrush,
5184       const uint32_t            iUsage,
5185       const PU_BITMAPINFO       Bmi,
5186       const uint32_t            cbPx,
5187       const char               *Px
5188    ){
5189     return(U_EMR_CORE12_set(U_EMR_CREATEDIBPATTERNBRUSHPT,ihBrush,iUsage,Bmi,cbPx,Px));
5190 }
5191 
5192 
5193 // U_EMREXTCREATEPEN_set              95
5194 /**
5195     \brief Allocate and construct a U_EMR_EXTCREATEPEN record.
5196     Use extcreatepen_set() instead of calling this function directly.
5197     \return pointer to U_EMR_EXTCREATEPEN record, or NULL on error.
5198     \param ihPen ihPen Index to place object in EMF object table (this entry must not yet exist)
5199     \param Bmi   Bmi   bitmapbuffer
5200     \param cbPx  cbPx  Size in bytes of pixel array (row stride * height, there may be some padding at the end of each row)
5201     \param Px    Px    pixel array (NULL if cbPx == 0)
5202     \param elp   elp   Pen parameters (Size is Variable!!!!)
5203 */
U_EMREXTCREATEPEN_set(const uint32_t ihPen,const PU_BITMAPINFO Bmi,const uint32_t cbPx,char * Px,const PU_EXTLOGPEN elp)5204 char *U_EMREXTCREATEPEN_set(
5205       const uint32_t      ihPen,
5206       const PU_BITMAPINFO Bmi,
5207       const uint32_t      cbPx,
5208       char               *Px,
5209       const PU_EXTLOGPEN  elp
5210    ){
5211    char *record;
5212    int   cbImage,cbImage4,cbBmi,off;
5213    int   irecsize,cbStyleArray,cbElp;
5214 
5215    if(!elp)return(NULL);
5216 
5217    SET_CB_FROM_PXBMI(Px,Bmi,cbImage,cbImage4,cbBmi,cbPx);
5218 
5219    cbStyleArray   = elp->elpNumEntries * sizeof(U_STYLEENTRY);                         // space actually used by penstyle entries
5220    // EXTLOGPEN is already included in EMREXTCREATEPEN, including the possibly unused first penstyle entry
5221    if(cbStyleArray){
5222       cbElp   = sizeof(U_EXTLOGPEN) + cbStyleArray - sizeof(U_STYLEENTRY);  // space actually used by elp
5223       irecsize = sizeof(U_EMREXTCREATEPEN) + cbBmi + cbImage4 + cbStyleArray - sizeof(U_STYLEENTRY);
5224    }
5225    else {
5226       cbElp   = sizeof(U_EXTLOGPEN);                                  //    first U_STYLEENTRY is present but unused
5227       irecsize = sizeof(U_EMREXTCREATEPEN) + cbBmi + cbImage4;
5228    }
5229    record   = malloc(irecsize);
5230 
5231    if(record){
5232       ((PU_EMR)                 record)->iType      = U_EMR_EXTCREATEPEN;
5233       ((PU_EMR)                 record)->nSize      = irecsize;
5234       ((PU_EMREXTCREATEPEN)     record)->ihPen      = ihPen;
5235       memcpy(&(((PU_EMREXTCREATEPEN) record)->elp),elp,cbElp);
5236       if(cbStyleArray){
5237          off = sizeof(U_EMREXTCREATEPEN) + cbStyleArray - sizeof(U_STYLEENTRY);
5238       }
5239       else {
5240          off = sizeof(U_EMREXTCREATEPEN);
5241       }
5242       // Cannot use APPEND_PXBMISRC here because there is no "Src" in the field names
5243       if(cbBmi){
5244          memcpy(record + off, Bmi, cbBmi);
5245          ((PU_EMREXTCREATEPEN) record)->offBmi     = off;
5246          ((PU_EMREXTCREATEPEN) record)->cbBmi      = cbBmi;
5247          off += cbBmi;
5248          memcpy(record + off, Px, cbImage);
5249          ((PU_EMREXTCREATEPEN) record)->offBits    = off;
5250          ((PU_EMREXTCREATEPEN) record)->cbBits     = cbImage;
5251          off += cbImage;
5252          if(cbImage4 - cbImage){  memset(record + off, 0, cbImage4 - cbImage); }
5253       }
5254       else {
5255          ((PU_EMREXTCREATEPEN) record)->cbBmi      = 0;
5256          ((PU_EMREXTCREATEPEN) record)->offBmi     = 0;
5257          ((PU_EMREXTCREATEPEN) record)->cbBits     = 0;
5258          ((PU_EMREXTCREATEPEN) record)->offBits    = 0;
5259       }
5260    }
5261    return(record);
5262 }
5263 
5264 // U_EMRPOLYTEXTOUTA_set              96 NOT IMPLEMENTED, denigrated after Windows NT
5265 // U_EMRPOLYTEXTOUTW_set              97 NOT IMPLEMENTED, denigrated after Windows NT
5266 
5267 // U_EMRSETICMMODE_set                98
5268 /**
5269     \brief Allocate and construct a U_EMR_SETICMMODE record.
5270     \return pointer to U_EMR_SETICMMODE record, or NULL on error.
5271     \param iMode ICMMode Enumeration
5272 */
U_EMRSETICMMODE_set(const uint32_t iMode)5273 char *U_EMRSETICMMODE_set(
5274       const uint32_t iMode
5275    ){
5276    return(U_EMR_CORE3_set(U_EMR_SETICMMODE, iMode));
5277 }
5278 
5279 // U_EMRCREATECOLORSPACE_set          99
5280 /**
5281     \brief Allocate and construct a U_EMR_CREATECOLORSPACE record.
5282     Use createcolorspace_set() instead of calling this function directly.
5283     \return pointer to U_EMR_CREATECOLORSPACE record, or NULL on error.
5284     \param ihCS Index to place object in EMF object table (this entry must not yet exist)
5285     \param lcs  ColorSpace parameters
5286 */
U_EMRCREATECOLORSPACE_set(const uint32_t ihCS,const U_LOGCOLORSPACEA lcs)5287 char *U_EMRCREATECOLORSPACE_set(
5288       const uint32_t            ihCS,
5289       const U_LOGCOLORSPACEA    lcs
5290    ){
5291    char *record;
5292    int   irecsize;
5293 
5294    irecsize = sizeof(U_EMRCREATECOLORSPACE);
5295    record   = malloc(irecsize);
5296    if(record){
5297       ((PU_EMR)                 record)->iType = U_EMR_CREATECOLORSPACE;
5298       ((PU_EMR)                 record)->nSize = irecsize;
5299       ((PU_EMRCREATECOLORSPACE) record)->ihCS  = ihCS;
5300       ((PU_EMRCREATECOLORSPACE) record)->lcs   = lcs;
5301    }
5302    return(record);
5303 }
5304 
5305 // U_EMRSETCOLORSPACE_set            100
5306 /**
5307     \brief Allocate and construct a U_EMR_SETCOLORSPACE record.
5308     \return pointer to U_EMR_SETCOLORSPACE record, or NULL on error.
5309     \param ihCS Index of object in EMF object table
5310 */
U_EMRSETCOLORSPACE_set(const uint32_t ihCS)5311 char *U_EMRSETCOLORSPACE_set(
5312       const uint32_t             ihCS
5313    ){
5314    return(U_EMR_CORE3_set(U_EMR_SETCOLORSPACE, ihCS));
5315 }
5316 
5317 // U_EMRDELETECOLORSPACE_set         101
5318 /**
5319     \brief Allocate and construct a U_EMR_DELETECOLORSPACE record.
5320     \return pointer to U_EMR_DELETECOLORSPACE record, or NULL on error.
5321     \param ihCS Index of object in EMF object table
5322 */
U_EMRDELETECOLORSPACE_set(const uint32_t ihCS)5323 char *U_EMRDELETECOLORSPACE_set(
5324       const uint32_t             ihCS
5325    ){
5326    return(U_EMR_CORE3_set(U_EMR_DELETECOLORSPACE, ihCS));
5327 }
5328 
5329 // U_EMRGLSRECORD_set                102  Not implemented
5330 // U_EMRGLSBOUNDEDRECORD_set         103  Not implemented
5331 // U_EMRPIXELFORMAT_set              104
5332 /**
5333     \brief Allocate and construct a U_EMR_PIXELFORMAT record.
5334     \return pointer to U_EMR_PIXELFORMAT record, or NULL on error.
5335     \param pfd PixelFormatDescriptor
5336 */
U_EMRPIXELFORMAT_set(const U_PIXELFORMATDESCRIPTOR pfd)5337 char *U_EMRPIXELFORMAT_set(
5338       const U_PIXELFORMATDESCRIPTOR pfd
5339    ){
5340    char *record;
5341    int   irecsize;
5342 
5343    irecsize = sizeof(U_EMRPIXELFORMAT);
5344    record   = malloc(irecsize);
5345    if(record){
5346       ((PU_EMR)            record)->iType   = U_EMR_PIXELFORMAT;
5347       ((PU_EMR)            record)->nSize   = irecsize;
5348       ((PU_EMRPIXELFORMAT) record)->pfd     = pfd;
5349    }
5350    return(record);
5351 }
5352 // U_EMRDRAWESCAPE_set               105  Not implemented
5353 // U_EMREXTESCAPE_set                106  Not implemented
5354 // U_EMRUNDEF107_set                 107  Not implemented
5355 
5356 // U_EMRSMALLTEXTOUT_set             108
5357 /**
5358     \brief Allocate and construct a U_EMR_SMALLTEXTOUT record.
5359     \return pointer to U_EMR_SMALLTEXTOUT record, or NULL on error.
5360     \param Dest          Where to draw the text
5361     \param cChars        Characters in TextString (not null terminated)
5362     \param fuOptions     ExtTextOutOptions Enumeration
5363     \param iGraphicsMode GraphicsMode Enumeration
5364     \param exScale       scale on X axis
5365     \param eyScale       scale on Y axis
5366     \param rclBounds     OPTIONAL Bounding rectangle (absent when: fuOPtions & ETO_NO_U_RECT)
5367     \param TextString    text to output (fuOptions & ETO_SMALL_CHARS ? 8 bit : 16 bit)
5368 */
U_EMRSMALLTEXTOUT_set(const U_POINTL Dest,const U_NUM_STR cChars,const uint32_t fuOptions,const uint32_t iGraphicsMode,const U_FLOAT exScale,const U_FLOAT eyScale,const U_RECTL rclBounds,const char * TextString)5369 char *U_EMRSMALLTEXTOUT_set(
5370       const U_POINTL   Dest,
5371       const U_NUM_STR  cChars,
5372       const uint32_t   fuOptions,
5373       const uint32_t   iGraphicsMode,
5374       const U_FLOAT    exScale,
5375       const U_FLOAT    eyScale,
5376       const U_RECTL    rclBounds,
5377       const char      *TextString
5378    ){
5379    char *record;
5380    int   irecsize,cbString,cbString4,cbRectl,off;
5381    int   csize;
5382 
5383    if( fuOptions & U_ETO_SMALL_CHARS ){  csize = 1; }         // how many bytes per character
5384    else {                                csize = 2; }
5385    cbString = csize * cChars;                                   // filled contents of the string buffer
5386    cbString4 = UP4(cbString);                                      // size of the variable string buffer
5387    if(fuOptions & U_ETO_NO_RECT){ cbRectl = 0;               } // size of the optional U_RECTL field
5388    else {                         cbRectl = sizeof(U_RECTL); }
5389 
5390    irecsize = sizeof(U_EMRSMALLTEXTOUT) + cbString4 + cbRectl;
5391    record    = malloc(irecsize);
5392    if(record){
5393       ((PU_EMR)             record)->iType         = U_EMR_SMALLTEXTOUT;
5394       ((PU_EMR)             record)->nSize         = irecsize;
5395       ((PU_EMRSMALLTEXTOUT) record)->Dest          = Dest;
5396       ((PU_EMRSMALLTEXTOUT) record)->cChars        = cChars;
5397       ((PU_EMRSMALLTEXTOUT) record)->fuOptions     = fuOptions;
5398       ((PU_EMRSMALLTEXTOUT) record)->iGraphicsMode = iGraphicsMode;
5399       ((PU_EMRSMALLTEXTOUT) record)->exScale       = exScale;
5400       ((PU_EMRSMALLTEXTOUT) record)->eyScale       = eyScale;
5401       off = sizeof(U_EMRSMALLTEXTOUT);  //offset to the start of the variable fields
5402       if(cbRectl){
5403          memcpy(record + off, &rclBounds, cbRectl);
5404          off += cbRectl;
5405       }
5406       memcpy(record + off, TextString, cbString);
5407       if(cbString < cbString4){
5408          off += cbString;
5409          memset(record + off, 0, cbString4 - cbString);
5410       }
5411    }
5412    return(record);
5413 }
5414 
5415 // U_EMRFORCEUFIMAPPING_set          109  Not implemented
5416 // U_EMRNAMEDESCAPE_set              110  Not implemented
5417 // U_EMRCOLORCORRECTPALETTE_set      111  Not implemented
5418 // U_EMRSETICMPROFILEA_set           112  Not implemented
5419 // U_EMRSETICMPROFILEW_set           113  Not implemented
5420 
5421 // U_EMRALPHABLEND_set               114
5422 /**
5423     \brief Allocate and construct a U_EMR_ALPHABLEND record.
5424     \return pointer to U_EMR_ALPHABLEND record, or NULL on error.
5425     \param rclBounds    Bounding rectangle in device units
5426     \param Dest         Destination UL corner in logical units
5427     \param cDest        Destination width in logical units
5428     \param Src          Source UL corner in logical units
5429     \param cSrc         Src W & H in logical units
5430     \param xformSrc     Transform to apply to source
5431     \param crBkColorSrc Background color
5432     \param iUsageSrc    DIBcolors Enumeration
5433     \param Blend        Blend function
5434     \param Bmi          (Optional) bitmapbuffer (U_BITMAPINFO section)
5435     \param cbPx         Size in bytes of pixel array (row stride * height, there may be some padding at the end of each row)
5436     \param Px           (Optional) bitmapbuffer (pixel array section )
5437 */
U_EMRALPHABLEND_set(const U_RECTL rclBounds,const U_POINTL Dest,const U_POINTL cDest,const U_POINTL Src,const U_POINTL cSrc,const U_XFORM xformSrc,const U_COLORREF crBkColorSrc,const uint32_t iUsageSrc,const U_BLEND Blend,const PU_BITMAPINFO Bmi,const uint32_t cbPx,char * Px)5438 char *U_EMRALPHABLEND_set(
5439       const U_RECTL       rclBounds,
5440       const U_POINTL      Dest,
5441       const U_POINTL      cDest,
5442       const U_POINTL      Src,
5443       const U_POINTL      cSrc,
5444       const U_XFORM       xformSrc,
5445       const U_COLORREF    crBkColorSrc,
5446       const uint32_t      iUsageSrc,
5447       const U_BLEND       Blend,
5448       const PU_BITMAPINFO Bmi,
5449       const uint32_t      cbPx,
5450       char               *Px
5451    ){
5452    return(U_EMR_CORE13_set(U_EMR_ALPHABLEND,rclBounds,Dest,cDest,Src,cSrc,xformSrc,crBkColorSrc,iUsageSrc,*((uint32_t *) &Blend),Bmi,cbPx,Px));
5453 }
5454 
5455 // U_EMRSETLAYOUT_set                115
5456 /**
5457     \brief Allocate and construct a U_EMR_SETLAYOUT record.
5458     \return pointer to U_EMR_SETLAYOUT record, or NULL on error.
5459     \param iMode Mirroring Enumeration
5460 */
U_EMRSETLAYOUT_set(uint32_t iMode)5461 char *U_EMRSETLAYOUT_set(uint32_t iMode){
5462   return(U_EMR_CORE3_set(U_EMR_SETLAYOUT, iMode));
5463 }
5464 
5465 // U_EMRTRANSPARENTBLT_set           116
5466 /**
5467     \brief Allocate and construct a U_EMR_TRANSPARENTBLT record.
5468     \return pointer to U_EMR_TRANSPARENTBLT record, or NULL on error.
5469     \param rclBounds    Bounding rectangle in device units
5470     \param Dest         Destination UL corner in logical units
5471     \param cDest        Destination width in logical units
5472     \param Src          Source UL corner in logical units
5473     \param cSrc         Src W & H in logical units
5474     \param xformSrc     Transform to apply to source
5475     \param crBkColorSrc Background color
5476     \param iUsageSrc    DIBcolors Enumeration
5477     \param TColor       Bitmap color to be treated as transparent
5478     \param Bmi          (Optional) bitmapbuffer (U_BITMAPINFO section)
5479     \param cbPx         Size in bytes of pixel array (row stride * height, there may be some padding at the end of each row)
5480     \param Px           (Optional) bitmapbuffer (pixel array section )
5481 */
U_EMRTRANSPARENTBLT_set(const U_RECTL rclBounds,const U_POINTL Dest,const U_POINTL cDest,const U_POINTL Src,const U_POINTL cSrc,const U_XFORM xformSrc,const U_COLORREF crBkColorSrc,const uint32_t iUsageSrc,const uint32_t TColor,const PU_BITMAPINFO Bmi,const uint32_t cbPx,char * Px)5482 char *U_EMRTRANSPARENTBLT_set(
5483       const U_RECTL       rclBounds,
5484       const U_POINTL      Dest,
5485       const U_POINTL      cDest,
5486       const U_POINTL      Src,
5487       const U_POINTL      cSrc,
5488       const U_XFORM       xformSrc,
5489       const U_COLORREF    crBkColorSrc,
5490       const uint32_t      iUsageSrc,
5491       const uint32_t      TColor,
5492       const PU_BITMAPINFO Bmi,
5493       const uint32_t      cbPx,
5494       char               *Px
5495    ){
5496    return(U_EMR_CORE13_set(U_EMR_TRANSPARENTBLT,rclBounds,Dest,cDest,Src,cSrc,xformSrc,crBkColorSrc,iUsageSrc,TColor,Bmi,cbPx,Px));
5497 }
5498 // U_EMRUNDEF117_set                 117  Not implemented
5499 // U_EMRGRADIENTFILL_set             118
5500 /**
5501     \brief Allocate and construct a U_EMR_TRANSPARENTBLT record.
5502     \return pointer to U_EMR_TRANSPARENTBLT record, or NULL on error.
5503     \param rclBounds    Bounding rectangle in device units
5504     \param nTriVert     Number of TriVertex objects in TriVert
5505     \param nGradObj     Number of gradient triangle/rectangle objects
5506     \param ulMode       Gradientfill Enumeration (determines Triangle/Rectangle)
5507     \param TriVert      Array of TriVertex objects
5508     \param GradObj      Array of gradient objects (each has 2 [rect] or 3 [triangle] indices into TriVert array)
5509 
5510 There is an MS documentation or library problem for this record, as the size of the GradObj must always be set
5511 as if it was an array of U_GRADIENT3 objects for both rect and triangle.  For horizontal and vertical gradients
5512 this means that there will be unused bytes at the end of the record.  This is not what the documentation says,
5513 but it is how MS's libraries work.
5514 
5515 */
U_EMRGRADIENTFILL_set(const U_RECTL rclBounds,const U_NUM_TRIVERTEX nTriVert,const U_NUM_GRADOBJ nGradObj,const uint32_t ulMode,const PU_TRIVERTEX TriVert,const uint32_t * GradObj)5516 char *U_EMRGRADIENTFILL_set(
5517       const U_RECTL             rclBounds,
5518       const U_NUM_TRIVERTEX     nTriVert,
5519       const U_NUM_GRADOBJ       nGradObj,
5520       const uint32_t            ulMode,
5521       const PU_TRIVERTEX        TriVert,
5522       const uint32_t           *GradObj
5523    ){
5524    char *record;
5525    unsigned int   cbTriVert,cbGradObj,off;
5526    unsigned int   cbGradObjAlloc; /* larger than cbGradObj, because of problem described above */
5527    int   irecsize;
5528 
5529    cbTriVert = sizeof(U_TRIVERTEX) * nTriVert;  // all of the cb's will be a multiple of 4 bytes
5530    if(     ulMode == U_GRADIENT_FILL_TRIANGLE){ cbGradObj = sizeof(U_GRADIENT3) * nGradObj; }
5531    else if(ulMode == U_GRADIENT_FILL_RECT_H ||
5532            ulMode == U_GRADIENT_FILL_RECT_V){   cbGradObj = sizeof(U_GRADIENT4) * nGradObj; }
5533    else {                                       return(NULL);                               }
5534    cbGradObjAlloc = sizeof(U_GRADIENT3) * nGradObj;
5535 
5536    irecsize = sizeof(U_EMRGRADIENTFILL) + cbTriVert + cbGradObjAlloc;
5537    record   = malloc(irecsize);
5538    if(record){
5539       ((PU_EMR)             record)->iType      = U_EMR_GRADIENTFILL;
5540       ((PU_EMR)             record)->nSize      = irecsize;
5541       ((PU_EMRGRADIENTFILL) record)->rclBounds  = rclBounds;
5542       ((PU_EMRGRADIENTFILL) record)->nTriVert   = nTriVert;
5543       ((PU_EMRGRADIENTFILL) record)->nGradObj   = nGradObj;
5544       ((PU_EMRGRADIENTFILL) record)->ulMode     = ulMode;
5545       off = sizeof(U_EMRGRADIENTFILL); // offset to TriVert field
5546       memcpy(record + off, TriVert, cbTriVert);
5547       off += cbTriVert;
5548       memcpy(record + off, GradObj, cbGradObj);
5549       off += cbGradObj;
5550       if(cbGradObjAlloc > cbGradObj){
5551          memset(record+off,0,cbGradObjAlloc - cbGradObj);
5552       }
5553    }
5554    return(record);
5555 }
5556 
5557 // U_EMRSETLINKEDUFIS_set            119  Not implemented
5558 // U_EMRSETTEXTJUSTIFICATION_set     120  Not implemented (denigrated)
5559 // U_EMRCOLORMATCHTOTARGETW_set      121  Not implemented
5560 
5561 // U_EMRCREATECOLORSPACEW_set        122
5562 /**
5563     \brief Allocate and construct a U_EMR_CREATECOLORSPACEW record.
5564     Use createcolorspacew_set() instead of calling this function directly.
5565     \return pointer to U_EMR_CREATECOLORSPACEW record, or NULL on error.
5566     \param ihCS     Index to place object in EMF object table (this entry must not yet exist)
5567     \param lcs      ColorSpace parameters
5568     \param dwFlags  If low bit set Data is present
5569     \param cbData   Number of bytes of theData field.
5570     \param Data     (Optional, dwFlags & 1) color profile data
5571 */
U_EMRCREATECOLORSPACEW_set(const uint32_t ihCS,const U_LOGCOLORSPACEW lcs,const uint32_t dwFlags,const U_CBDATA cbData,const uint8_t * Data)5572 char *U_EMRCREATECOLORSPACEW_set(
5573       const uint32_t          ihCS,
5574       const U_LOGCOLORSPACEW  lcs,
5575       const uint32_t          dwFlags,
5576       const U_CBDATA          cbData,
5577       const uint8_t          *Data
5578    ){
5579    char *record;
5580    unsigned int   cbData4,off;
5581    int   irecsize;
5582 
5583    cbData4 = UP4(cbData);                     // buffer to hold Data
5584    irecsize = sizeof(U_EMRCREATECOLORSPACEW) + cbData4;
5585    record   = malloc(irecsize);
5586    if(record){
5587       ((PU_EMR)                  record)->iType   = U_EMR_CREATECOLORSPACEW;
5588       ((PU_EMR)                  record)->nSize   = irecsize;
5589       ((PU_EMRCREATECOLORSPACEW) record)->ihCS    = ihCS;
5590       ((PU_EMRCREATECOLORSPACEW) record)->lcs     = lcs;
5591       ((PU_EMRCREATECOLORSPACEW) record)->dwFlags = dwFlags;
5592       ((PU_EMRCREATECOLORSPACEW) record)->cbData  = cbData;
5593       off = sizeof(U_EMR) + sizeof(uint32_t) + sizeof(U_LOGCOLORSPACEW) + sizeof(uint32_t) + sizeof(U_CBDATA); // offset to Data field
5594       memcpy(record + off, Data, cbData);
5595       if(cbData < cbData4){
5596         off += cbData;
5597         memset(record + off,0,cbData4-cbData);
5598       }
5599    }
5600    return(record);
5601 }
5602 
5603 
5604 #ifdef __cplusplus
5605 }
5606 #endif
5607