1 /*****************************************************************************/
2 /*  LibreDWG - free implementation of the DWG file format                    */
3 /*                                                                           */
4 /*  Copyright (C) 2018-2021 Free Software Foundation, Inc.                   */
5 /*                                                                           */
6 /*  This library is free software, licensed under the terms of the GNU       */
7 /*  General Public License as published by the Free Software Foundation,     */
8 /*  either version 3 of the License, or (at your option) any later version.  */
9 /*  You should have received a copy of the GNU General Public License        */
10 /*  along with this program.  If not, see <http://www.gnu.org/licenses/>.    */
11 /*****************************************************************************/
12 
13 /*
14  * out_dxf.c: write as Ascii DXF
15  * written by Reini Urban
16  */
17 
18 /* Works mostly.
19    TODO:
20 * down-conversions from unsupported entities on older DXF versions.
21   Since r13:
22   Entities: LWPOLYLINE, HATCH, SPLINE, LEADER, DIMENSION, MTEXT, IMAGE,
23   BLOCK_RECORD. Add CLASSES for those.
24 */
25 
26 #include "config.h"
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <string.h>
30 #include <assert.h>
31 //#include <math.h>
32 
33 #define IS_DXF
34 #include "common.h"
35 #include "bits.h"
36 #include "myalloca.h"
37 #include "dwg.h"
38 #include "decode.h"
39 #include "encode.h"
40 #include "out_dxf.h"
41 
42 static unsigned int loglevel;
43 #define DWG_LOGLEVEL loglevel
44 #include "logging.h"
45 
46 /* the current version per spec block */
47 static unsigned int cur_ver = 0;
48 static char buf[255];
49 static BITCODE_BL rcount1, rcount2;
50 
51 // imported
52 char *dwg_obj_table_get_name (const Dwg_Object *restrict obj,
53                               int *restrict error);
54 #ifndef _DWG_API_H_
55 Dwg_Object *dwg_obj_generic_to_object (const void *restrict obj,
56                                        int *restrict error);
57 #endif
58 
59 // private
60 static int dxf_common_entity_handle_data (Bit_Chain *restrict dat,
61                                           const Dwg_Object *restrict obj);
62 static int dwg_dxf_object (Bit_Chain *restrict dat,
63                            const Dwg_Object *restrict obj, int *restrict);
64 static int dxf_3dsolid (Bit_Chain *restrict dat,
65                         const Dwg_Object *restrict obj,
66                         Dwg_Entity_3DSOLID *restrict _obj);
67 static void dxf_fixup_string (Bit_Chain *restrict dat, char *restrict str,
68                               const int opts, const int dxf, const int dxfcont);
69 static void dxf_CMC (Bit_Chain *restrict dat, Dwg_Color *restrict color,
70                      const int dxf, const int opt);
71 
72 /*--------------------------------------------------------------------------------
73  * MACROS
74  */
75 
76 #define ACTION dxf
77 
78 #define FIELD(nam, type) VALUE (_obj->nam, type, 0)
79 #define FIELDG(nam, type, dxf) VALUE (_obj->nam, type, dxf)
80 #define FIELD_CAST(nam, type, cast, dxf) FIELDG (nam, cast, dxf)
81 #define FIELD_TRACE(nam, type)
82 #define SUB_FIELD(o, nam, type, dxf) FIELDG (o.nam, type, dxf)
83 #define SUB_FIELD_CAST(o, nam, type, cast, dxf) FIELDG (o.nam, cast, dxf)
84 
85 #define VALUE_TV(value, dxf)                                                  \
86   {                                                                           \
87     GROUP (dxf);                                                              \
88     dxf_fixup_string (dat, (char *)value, 1, dxf, dxf);                       \
89   }
90 #define VALUE_TV0(value, dxf)                                                 \
91   if (dxf && value && *value) {                                               \
92     GROUP (dxf);                                                              \
93     dxf_fixup_string (dat, (char *)value, 1, dxf, dxf);                       \
94   }
95 // in_json writes all strings as TV, in_dxf and decode not.
96 #define VALUE_TU(wstr, dxf)                                                   \
97   {                                                                           \
98     if (dat->opts & DWG_OPTS_INJSON)                                          \
99       {                                                                       \
100         VALUE_TV (wstr, dxf);                                                 \
101       }                                                                       \
102     else if (dxf)                                                             \
103       {                                                                       \
104         char *u8 = bit_convert_TU ((BITCODE_TU)wstr);                         \
105         GROUP (dxf);                                                          \
106         if (u8)                                                               \
107           {                                                                   \
108             dxf_fixup_string (dat, u8, 1, dxf, dxf);                          \
109           }                                                                   \
110         else                                                                  \
111           fprintf (dat->fh, "\r\n");                                          \
112         free (u8);                                                            \
113       }                                                                       \
114   }
115 #define VALUE_TFF(str, dxf)                                                   \
116   {                                                                           \
117     if (dxf)                                                                  \
118       {                                                                       \
119         GROUP (dxf);                                                          \
120         dxf_fixup_string (dat, (char *)str, 0, dxf, dxf);                     \
121       }                                                                       \
122   }
123 #define VALUE_BINARY(value, size, dxf)                                        \
124   {                                                                           \
125     if (value && dxf)                                                         \
126       {                                                                       \
127         for (unsigned long j = 0; j < (unsigned long)(size); j++)             \
128           {                                                                   \
129             if (!(j % 127))                                                   \
130               {                                                               \
131                 if (j)                                                        \
132                   fprintf (dat->fh, "\r\n");                                  \
133                 GROUP (dxf);                                                  \
134               }                                                               \
135             fprintf (dat->fh, "%02X", (value)[j]);                            \
136           }                                                                   \
137         fprintf (dat->fh, "\r\n");                                            \
138       }                                                                       \
139   }
140 #define FIELD_BINARY(name, size, dxf)                                         \
141   if (dxf)                                                                    \
142     VALUE_BINARY (_obj->name, size, dxf)
143 
144 #define FIELD_VALUE(nam) _obj->nam
145 #define ANYCODE -1
146 // the hex code
147 #define VALUE_HANDLE(ref, nam, handle_code, dxf)                              \
148   if (dxf)                                                                    \
149     {                                                                         \
150       fprintf (dat->fh, "%3i\r\n%lX\r\n", dxf,                                \
151                ref ? ((BITCODE_H)ref)->absolute_ref : 0UL);                   \
152     }
153 // the name in the table, referenced by the handle
154 // names on: 6 7 8. which else? there are more styles: plot, ...
155 // rather skip unknown handles
156 #define FIELD_HANDLE(nam, handle_code, dxf)                                   \
157   if (dxf != 0)                                                               \
158     {                                                                         \
159       if (!_obj->nam)                                                         \
160         fprintf (dat->fh, "%3i\r\n%lX\r\n", dxf, 0UL);                        \
161       else if (dxf == 6)                                                      \
162         FIELD_HANDLE_NAME (nam, dxf, LTYPE)                                   \
163       else if (dxf == 2)                                                      \
164         FIELD_HANDLE_NAME (nam, dxf, BLOCK_HEADER)                            \
165       else if (dxf == 3)                                                      \
166         FIELD_HANDLE_NAME (nam, dxf, DIMSTYLE)                                \
167       else if (dxf == 7)                                                      \
168         FIELD_HANDLE_NAME (nam, dxf, STYLE)                                   \
169       else if (dxf == 8)                                                      \
170         FIELD_HANDLE_NAME (nam, dxf, LAYER)                                   \
171       else if (dat->version >= R_13)                                          \
172         fprintf (dat->fh, "%3i\r\n%lX\r\n", dxf,                              \
173                  _obj->nam->obj ? _obj->nam->absolute_ref : 0UL);             \
174     }
175 #define SUB_FIELD_HANDLE(o, nam, handle_code, dxf)                            \
176   if (dxf != 0)                                                               \
177     {                                                                         \
178       if (!_obj->o.nam)                                                       \
179         fprintf (dat->fh, "%3i\r\n%lX\r\n", dxf, 0UL);                        \
180       else if (dxf == 6)                                                      \
181         SUB_FIELD_HANDLE_NAME (o, nam, dxf, LTYPE)                            \
182       else if (dxf == 3)                                                      \
183         SUB_FIELD_HANDLE_NAME (o, nam, dxf, DIMSTYLE)                         \
184       else if (dxf == 7)                                                      \
185         SUB_FIELD_HANDLE_NAME (o, nam, dxf, STYLE)                            \
186       else if (dxf == 8)                                                      \
187         SUB_FIELD_HANDLE_NAME (o, nam, dxf, LAYER)                            \
188       else if (dat->version >= R_13)                                          \
189         fprintf (dat->fh, "%3i\r\n%lX\r\n", dxf,                              \
190                  _obj->o.nam->obj ? _obj->o.nam->absolute_ref : 0UL);         \
191     }
192 #define FIELD_HANDLE0(nam, handle_code, dxf)                                  \
193   if (_obj->nam && _obj->nam->absolute_ref)                                   \
194     {                                                                         \
195       FIELD_HANDLE (nam, handle_code, dxf);                                   \
196     }
197 #define SUB_FIELD_HANDLE0(o, nam, handle_code, dxf)                           \
198   if (_obj->o.nam && _obj->o.nam->absolute_ref)                               \
199     {                                                                         \
200       SUB_FIELD_HANDLE (o, nam, handle_code, dxf);                            \
201     }
202 #define HEADER_9(nam)                                                         \
203   {                                                                           \
204     GROUP (9);                                                                \
205     fprintf (dat->fh, "$%s\r\n", #nam);                                       \
206   }
207 #define VALUE_H(value, dxf)                                                   \
208   if (dxf)                                                                    \
209     fprintf (dat->fh, "%3i\r\n%lX\r\n", dxf, value)
210 #define HEADER_H(nam, dxf)                                                    \
211   {                                                                           \
212     HEADER_9 (nam);                                                           \
213     VALUE_HANDLE (dwg->header_vars.nam, nam, 0, dxf);                         \
214   }
215 #define HEADER_H0(nam, dxf)                                                   \
216   if (dwg->header_vars.nam && dwg->header_vars.nam->absolute_ref)             \
217     {                                                                         \
218       HEADER_9 (nam);                                                         \
219       VALUE_H (dwg->header_vars.nam->absolute_ref, dxf);                      \
220     }
221 #define HEADER_VALUE(nam, type, dxf, value)                                   \
222   if (dxf)                                                                    \
223     {                                                                         \
224       GROUP (9);                                                              \
225       fprintf (dat->fh, "$" #nam "\r\n");                                     \
226       VALUE (value, type, dxf);                                               \
227     }
228 #define HEADER_VAR(nam, type, dxf)                                            \
229   HEADER_VALUE (nam, type, dxf, dwg->header_vars.nam)
230 #define HEADER_VALUE_TV(nam, dxf, value)                                      \
231   if (dxf)                                                                    \
232     {                                                                         \
233       GROUP (9);                                                              \
234       fprintf (dat->fh, "$" #nam "\r\n");                                     \
235       VALUE_TV (value, dxf);                                                  \
236     }
237 #define HEADER_VALUE_TU(nam, dxf, value)                                      \
238   if (dxf)                                                                    \
239     {                                                                         \
240       GROUP (9);                                                              \
241       fprintf (dat->fh, "$" #nam "\r\n");                                     \
242       VALUE_TU (value, dxf);                                                  \
243     }
244 #define HEADER_VALUE_TU0(nam, dxf, value)                                     \
245   if (dxf && !bit_empty_T (dat, (BITCODE_T)value))                            \
246     {                                                                         \
247       GROUP (9);                                                              \
248       fprintf (dat->fh, "$" #nam "\r\n");                                     \
249       VALUE_TU (value, dxf);                                                  \
250     }
251 
252 #define HEADER_3D(nam)                                                        \
253   {                                                                           \
254     HEADER_9 (nam);                                                           \
255     POINT_3D (nam, header_vars.nam, 10, 20, 30);                              \
256   }
257 #define HEADER_2D(nam)                                                        \
258   {                                                                           \
259     HEADER_9 (nam);                                                           \
260     POINT_2D (nam, header_vars.nam, 10, 20);                                  \
261   }
262 #define HEADER_BLL(nam, dxf)                                                  \
263   {                                                                           \
264     HEADER_9 (nam);                                                           \
265     VALUE_BLL (dwg->header_vars.nam, dxf);                                    \
266   }
267 
268 #define SECTION(section)                                                      \
269   LOG_INFO ("\nSection " #section "\n")                                       \
270   fprintf (dat->fh, "  0\r\nSECTION\r\n  2\r\n" #section "\r\n")
271 #define ENDSEC() fprintf (dat->fh, "  0\r\nENDSEC\r\n")
272 #define TABLE(table) fprintf (dat->fh, "  0\r\nTABLE\r\n  2\r\n" #table "\r\n")
273 #define ENDTAB() fprintf (dat->fh, "  0\r\nENDTAB\r\n")
274 #define RECORD(record) fprintf (dat->fh, "  0\r\n" #record "\r\n")
275 #define record(record) fprintf (dat->fh, "  0\r\n%s\r\n", record)
276 #define SUBCLASS(text)                                                        \
277   if (dat->version >= R_13)                                                   \
278     {                                                                         \
279       VALUE_TV (#text, 100);                                                  \
280     }
281 
282 #define GROUP(dxf) fprintf (dat->fh, "%3i\r\n", dxf)
283 /* avoid empty numbers, and fixup some bad %f GNU/BSD libc formatting */
284 #define VALUE(value, type, dxf)                                               \
285   if (dxf)                                                                    \
286     {                                                                         \
287       const char *_fmt = dxf_format (dxf);                                    \
288       assert (_fmt);                                                          \
289       if (strEQc (_fmt, DXF_FORMAT_FLT))                                          \
290         {                                                                     \
291           dxf_print_rd (dat, (double)(value), dxf);                           \
292         }                                                                     \
293       else                                                                    \
294         {                                                                     \
295           /* -Wpointer-to-int-cast */                                         \
296           const int32_t _si = (int32_t) (intptr_t) (value);                   \
297           GROUP (dxf);                                                        \
298           GCC46_DIAG_IGNORE (-Wformat-nonliteral)                             \
299           snprintf (buf, 255, _fmt, value);                                   \
300           GCC46_DIAG_RESTORE                                                  \
301           /* not a string, empty num. must be zero */                         \
302           if (strEQc (_fmt, "%s") && !*buf)                                   \
303             fprintf (dat->fh, "0\r\n");                                       \
304           else if (90 <= dxf && dxf < 100)                                    \
305             {                                                                 \
306               fprintf (dat->fh, "%9i\r\n", _si);                              \
307             }                                                                 \
308           else                                                                \
309             fprintf (dat->fh, "%s\r\n", buf);                                 \
310         }                                                                     \
311     }
312 
313 static void
dxf_print_rd(Bit_Chain * dat,BITCODE_RD value,int dxf)314 dxf_print_rd (Bit_Chain *dat, BITCODE_RD value, int dxf)
315 {
316   if (dxf)
317     {
318       char _buf[128];
319       int k;
320       fprintf (dat->fh, "%3i\r\n", dxf);
321 #ifndef DEBUG_CLASSES
322       if (bit_isnan (value))
323         value = 0.0;
324 #endif
325       snprintf (_buf, 127, DXF_FORMAT_FLT, value);
326       k = strlen (_buf);
327       if (strrchr (_buf, '.') && _buf[k - 1] == '0')
328         {
329           for (k--; k > 1 && _buf[k - 1] != '.' && _buf[k] == '0'; k--)
330             _buf[k] = '\0';
331         }
332       // max len 17 resp. 18 with -
333       if (value < 0.0)
334         _buf[DXF_FLT_MAXLEN+1] = '\0';
335       else
336         _buf[DXF_FLT_MAXLEN] = '\0';
337       fprintf (dat->fh, "%s\r\n", _buf);
338     }
339 }
340 #define VALUE_BSd(value, dxf)                                                 \
341   if (dxf)                                                                    \
342     {                                                                         \
343       GROUP (dxf);                                                            \
344       fprintf (dat->fh, "%6i\r\n", value);                                    \
345     }
346 #define VALUE_RD(value, dxf) dxf_print_rd (dat, value, dxf)
347 #define VALUE_B(value, dxf)                                                   \
348   if (dxf)                                                                    \
349     {                                                                         \
350       GROUP (dxf);                                                            \
351       if (value == 0)                                                         \
352         fprintf (dat->fh, "     0\r\n");                                      \
353       else                                                                    \
354         fprintf (dat->fh, "     1\r\n");                                      \
355     }
356 
357 #define FIELD_HANDLE_NAME(nam, dxf, table)                                    \
358   {                                                                           \
359     Dwg_Object_Ref *ref = _obj->nam;                                          \
360     Dwg_Object *o = ref ? ref->obj : NULL;                                    \
361     if (o && strEQc (o->dxfname, #table))                                     \
362       dxf_cvt_tablerecord (                                                   \
363           dat, o, o ? o->tio.object->tio.table->name : (char *)"0", dxf);     \
364     else                                                                      \
365       {                                                                       \
366         VALUE_TFF ("", dxf)                                                   \
367       }                                                                       \
368   }
369 #define SUB_FIELD_HANDLE_NAME(ob, nam, dxf, table)                            \
370   {                                                                           \
371     Dwg_Object_Ref *ref = _obj->ob.nam;                                       \
372     Dwg_Object *o = ref ? ref->obj : NULL;                                    \
373     if (o && strEQc (o->dxfname, #table))                                     \
374       dxf_cvt_tablerecord (                                                   \
375           dat, o, o ? o->tio.object->tio.table->name : (char *)"0", dxf);     \
376     else                                                                      \
377       {                                                                       \
378         VALUE_TFF ("", dxf)                                                   \
379       }                                                                       \
380   }
381 #define HEADER_HANDLE_NAME(nam, dxf, table)                                   \
382   HEADER_9 (nam);                                                             \
383   FIELD_HANDLE_NAME (nam, dxf, table)
384 
385 #define FIELD_DATAHANDLE(nam, code, dxf)                                      \
386   {                                                                           \
387     Dwg_Object_Ref *ref = _obj->nam;                                          \
388     char s[16];                                                               \
389     HEADER_9 (nam);                                                           \
390     VALUE_H (ref ? ref->handleref.value : 0UL, dxf);                          \
391   }
392 
393 #define HEADER_RC(nam, dxf)                                                   \
394   HEADER_9 (nam);                                                             \
395   FIELDG (nam, RC, dxf)
396 #define HEADER_RC0(nam, dxf)                                                  \
397   if (FIELD_VALUE (nam))                                                      \
398     {                                                                         \
399       HEADER_9 (nam);                                                         \
400       FIELDG (nam, RC, dxf);                                                  \
401     }
402 #define HEADER_RS(nam, dxf)                                                   \
403   {                                                                           \
404     HEADER_9 (nam);                                                           \
405     FIELDG (nam, RS, dxf);                                                    \
406   }
407 #define HEADER_RS0(nam, dxf)                                                  \
408   if (FIELD_VALUE (nam))                                                      \
409     {                                                                         \
410       HEADER_9 (nam);                                                         \
411       FIELDG (nam, RS, dxf);                                                  \
412     }
413 #define HEADER_RD(nam, dxf)                                                   \
414   {                                                                           \
415     HEADER_9 (nam);                                                           \
416     FIELD_RD (nam, dxf);                                                      \
417   }
418 #define HEADER_RL(nam, dxf)                                                   \
419   {                                                                           \
420     HEADER_9 (nam);                                                           \
421     FIELDG (nam, RL, dxf);                                                    \
422   }
423 #define HEADER_RLL(nam, dxf)                                                  \
424   HEADER_9 (nam);                                                             \
425   FIELDG (nam, RLL, dxf)
426 #define HEADER_TV(nam, dxf)                                                   \
427   HEADER_9 (nam);                                                             \
428   VALUE_TV (_obj->nam, dxf)
429 #define HEADER_TU(nam, dxf)                                                   \
430   HEADER_9 (nam);                                                             \
431   VALUE_TU (_obj->nam, dxf)
432 #define HEADER_T(nam, dxf)                                                    \
433   HEADER_9 (nam);                                                             \
434   VALUE_T ((char *)_obj->nam, dxf)
435 #define HEADER_T0(nam, dxf)                                                   \
436   if (dxf && !bit_empty_T (dat, _obj->nam))                                   \
437     {                                                                         \
438       HEADER_9 (nam);                                                         \
439       VALUE_T ((char*)_obj->nam, dxf);                                        \
440     }
441 #define HEADER_B(nam, dxf)                                                    \
442   HEADER_9 (nam);                                                             \
443   FIELD_B (nam, dxf)
444 #define HEADER_BS(nam, dxf)                                                   \
445   HEADER_9 (nam);                                                             \
446   FIELDG (nam, BS, dxf)
447 #define HEADER_BSd(nam, dxf)   HEADER_BS(nam, dxf)
448 #define HEADER_BD(nam, dxf)                                                   \
449   HEADER_9 (nam);                                                             \
450   FIELD_BD (nam, dxf)
451 #define HEADER_BL(nam, dxf)                                                   \
452   HEADER_9 (nam);                                                             \
453   FIELDG (nam, BL, dxf)
454 #define HEADER_BLd(nam, dxf)                                                  \
455   HEADER_9 (nam);                                                             \
456   FIELDG (nam, BLd, dxf)
457 
458 #define VALUE_BB(value, dxf) VALUE (value, RC, dxf)
459 #define VALUE_3B(value, dxf) VALUE (value, RC, dxf)
460 #define VALUE_BS(value, dxf) VALUE (value, RS, dxf)
461 #define VALUE_BL(value, dxf) VALUE (value, BL, dxf)
462 #define VALUE_BLL(value, dxf) VALUE (value, RLL, dxf)
463 #define VALUE_BD(value, dxf)                                                  \
464   {                                                                           \
465     if (dxf >= 50 && dxf < 55)                                                \
466       {                                                                       \
467         BITCODE_RD _f = rad2deg (value);                                      \
468         VALUE_RD (_f, dxf);                                                   \
469       }                                                                       \
470     else                                                                      \
471       {                                                                       \
472         VALUE_RD (value, dxf);                                                \
473       }                                                                       \
474   }
475 #define VALUE_RC(value, dxf) VALUE (value, RC, dxf)
476 #define VALUE_RS(value, dxf) VALUE (value, RS, dxf)
477 #define VALUE_RL(value, dxf) VALUE (value, RL, dxf)
478 #define VALUE_RLd(value, dxf) VALUE (value, RL, dxf)
479 #define VALUE_RLL(value, dxf) VALUE (value, RLL, dxf)
480 #define VALUE_MC(value, dxf) VALUE (value, MC, dxf)
481 #define VALUE_MS(value, dxf) VALUE (value, MS, dxf)
482 #define VALUE_2RD(pt, dxf)                                                    \
483   {                                                                           \
484     VALUE_RD (pt.x, dxf);                                                     \
485     VALUE_RD (pt.y, dxf + 10);                                                \
486   }
487 #define VALUE_3BD(pt, dxf)                                                    \
488   {                                                                           \
489     VALUE_RD (pt.x, dxf);                                                     \
490     VALUE_RD (pt.y, dxf + 10);                                                \
491     VALUE_RD (pt.z, dxf + 20);                                                \
492   }
493 
494 #define FIELD_RD(nam, dxf) VALUE_RD (_obj->nam, dxf)
495 #define FIELD_B(nam, dxf) VALUE_B (_obj->nam, dxf)
496 #define FIELD_BB(nam, dxf) FIELDG (nam, BB, dxf)
497 #define FIELD_3B(nam, dxf) FIELDG (nam, 3B, dxf)
498 #define FIELD_BS(nam, dxf) FIELDG (nam, BS, dxf)
499 #define FIELD_BSd(nam, dxf) FIELDG (nam, BSd, dxf)
500 #define FIELD_BL(nam, dxf) FIELDG (nam, BL, dxf)
501 #define FIELD_BLL(nam, dxf) FIELDG (nam, BLL, dxf)
502 #define FIELD_BD(nam, dxf) VALUE_BD (_obj->nam, dxf)
503 #define FIELD_RC(nam, dxf) FIELDG (nam, RC, dxf)
504 #define FIELD_RS(nam, dxf) FIELDG (nam, RS, dxf)
505 #define FIELD_RL(nam, dxf) FIELDG (nam, RL, dxf)
506 #define FIELD_RLL(nam, dxf) FIELDG (nam, RLL, dxf)
507 #define FIELD_MC(nam, dxf) FIELDG (nam, MC, dxf)
508 #define FIELD_MS(nam, dxf) FIELDG (nam, MS, dxf)
509 #define FIELD_TF(nam, len, dxf) VALUE_TV (_obj->nam, dxf)
510 #define FIELD_TFF(nam, len, dxf) VALUE_TV (_obj->nam, dxf)
511 #define FIELD_TV(nam, dxf)                                                    \
512   if (dxf)                                                                    \
513     {                                                                         \
514       VALUE_TV (_obj->nam, dxf);                                              \
515     }
516 #define FIELD_TU(nam, dxf)                                                    \
517   if (dxf)                                                                    \
518     {                                                                         \
519       VALUE_TU ((BITCODE_TU)_obj->nam, dxf);                                  \
520     }
521 #define FIELD_T(nam, dxf)                                                     \
522   {                                                                           \
523     if (IS_FROM_TU (dat))                                                     \
524       {                                                                       \
525         FIELD_TU (nam, dxf);                                                  \
526       }                                                                       \
527     else                                                                      \
528       {                                                                       \
529         FIELD_TV (nam, dxf);                                                  \
530       }                                                                       \
531   }
532 #define VALUE_T(value, dxf)                                                   \
533   {                                                                           \
534     if (IS_FROM_TU (dat))                                                     \
535       {                                                                       \
536         VALUE_TU (value, dxf);                                                \
537       }                                                                       \
538     else                                                                      \
539       {                                                                       \
540         VALUE_TV (value, dxf);                                                \
541       }                                                                       \
542   }
543 #define VALUE_T0(value, dxf)                                                  \
544   if (!bit_empty_T (dat, value)) VALUE_T (value,dxf)
545 #define FIELD_BT(nam, dxf) FIELDG (nam, BT, dxf);
546 #define FIELD_4BITS(nam, dxf) FIELDG (nam, 4BITS, dxf)
547 #define FIELD_BE(nam, dxf)                                                    \
548   {                                                                           \
549     if (dxf && !(_obj->nam.x == 0.0 && _obj->nam.y == 0.0 && _obj->nam.z == 1.0)) \
550       FIELD_3RD (nam, dxf)                                                    \
551   }
552 // skip if 0
553 #define FIELD_RD0(nam, dxf) FIELD_BD0(nam, dxf)
554 #define FIELD_BD0(nam, dxf)                                                   \
555   if (dxf) {                                                                  \
556     if (_obj->nam != 0.0)                                                     \
557       FIELD_BD (nam, dxf)                                                     \
558   }
559 // for scale (1.0, 1.0, 1.0) and width_factor
560 #define FIELD_RD1(nam, dxf) FIELD_BD1(nam, dxf)
561 #define FIELD_BD1(nam, dxf)                                                   \
562   if (dxf) {                                                                  \
563     if (_obj->nam != 1.0)                                                     \
564       FIELD_BD (nam, dxf)                                                     \
565   }
566 #define FIELD_BL0(nam, dxf)                                                   \
567   if (dxf) {                                                                  \
568     if (_obj->nam != 0)                                                       \
569       FIELD_BL (nam, dxf)                                                     \
570   }
571 #define FIELD_BS0(nam, dxf)                                                   \
572   if (dxf) {                                                                  \
573     if (_obj->nam != 0)                                                       \
574       FIELD_BS (nam, dxf)                                                     \
575   }
576 #define FIELD_BS1(nam, dxf)                                                   \
577   if (dxf) {                                                                  \
578     if (_obj->nam != 1)                                                       \
579       FIELD_BS (nam, dxf)                                                     \
580   }
581 #define FIELD_B0(nam, dxf)                                                    \
582   if (dxf) {                                                                  \
583     if (_obj->nam)                                                            \
584       FIELD_B (nam, dxf)                                                      \
585   }
586 #define FIELD_RC0(nam, dxf)                                                   \
587   {                                                                           \
588     if (_obj->nam != 0)                                                       \
589       FIELD_RC (nam, dxf)                                                     \
590   }
591 #define FIELD_RS0(nam, dxf)                                                   \
592   {                                                                           \
593     if (_obj->nam != 0)                                                       \
594       FIELD_RS (nam, dxf)                                                     \
595   }
596 #define FIELD_RL0(nam, dxf)                                                   \
597   {                                                                           \
598     if (_obj->nam != 0)                                                       \
599       FIELD_RL (nam, dxf)                                                     \
600   }
601 #define FIELD_BT0(nam, dxf)                                                   \
602   {                                                                           \
603     if (_obj->nam != 0)                                                       \
604       FIELD_BT (nam, dxf)                                                     \
605   }
606 #define FIELD_T0(nam, dxf)                                                    \
607   {                                                                           \
608     if (_obj->nam)                                                            \
609       {                                                                       \
610         if (IS_FROM_TU (dat))                                                 \
611           {                                                                   \
612             char *u8 = bit_convert_TU ((BITCODE_TU)_obj->nam);                \
613             if (u8 && *u8)                                                    \
614               {                                                               \
615                 GROUP (dxf);                                                  \
616                 fprintf (dat->fh, "%s\r\n", u8);                              \
617               }                                                               \
618             free (u8);                                                        \
619           }                                                                   \
620         else if (*_obj->nam)                                                  \
621           {                                                                   \
622             FIELD_TV (nam, dxf);                                              \
623           }                                                                   \
624       }                                                                       \
625   }
626 #define FIELD_TV0(nam, dxf) VALUE_TV0 (_obj->nam, dxf)
627 #define SUB_FIELD_BL0(o, nam, dxf)                                            \
628   {                                                                           \
629     if (_obj->o.nam != 0)                                                     \
630       SUB_FIELD_BL (o, nam, dxf)                                              \
631   }
632 
633 #define FIELD_DD(nam, _default, dxf) FIELD_BD (nam, dxf)
634 #define FIELD_2DD(nam, def, dxf)                                              \
635   if (dxf) {                                                                  \
636     FIELD_DD (nam.x, FIELD_VALUE (def.x), dxf);                               \
637     FIELD_DD (nam.y, FIELD_VALUE (def.y), dxf + 10);                          \
638   }
639 #define FIELD_3DD(nam, def, dxf)                                              \
640   if (dxf) {                                                                  \
641     FIELD_DD (nam.x, FIELD_VALUE (def.x), dxf);                               \
642     FIELD_DD (nam.y, FIELD_VALUE (def.y), dxf + 10);                          \
643     FIELD_DD (nam.z, FIELD_VALUE (def.z), dxf + 20);                          \
644   }
645 #define FIELD_2RD(nam, dxf)                                                   \
646   if (dxf) {                                                                  \
647     FIELD_RD (nam.x, dxf);                                                    \
648     FIELD_RD (nam.y, dxf + 10);                                               \
649   }
650 #define FIELD_2RD0(nam, dxf)                                                  \
651   if (dxf && _obj->nam.x != 0.0 && _obj->nam.y != 0.0) {                      \
652     FIELD_RD (nam.x, dxf);                                                    \
653     FIELD_RD (nam.y, dxf + 10);                                               \
654   }
655 #define FIELD_2BD(nam, dxf)                                                   \
656   if (dxf) {                                                                  \
657     FIELD_BD (nam.x, dxf);                                                    \
658     FIELD_BD (nam.y, dxf + 10);                                               \
659   }
660 #define FIELD_2BD_1(nam, dxf)                                                 \
661   if (dxf) {                                                                  \
662     FIELD_BD (nam.x, dxf);                                                    \
663     FIELD_BD (nam.y, dxf + 1);                                                \
664   }
665 #define FIELD_3RD(nam, dxf)                                                   \
666   if (dxf) {                                                                  \
667     FIELD_RD (nam.x, dxf);                                                    \
668     FIELD_RD (nam.y, dxf + 10);                                               \
669     FIELD_RD (nam.z, dxf + 20);                                               \
670   }
671 #define FIELD_3BD(nam, dxf)                                                   \
672   if (dxf) {                                                                  \
673     FIELD_BD (nam.x, dxf);                                                    \
674     FIELD_BD (nam.y, dxf + 10);                                               \
675     FIELD_BD (nam.z, dxf + 20);                                               \
676   }
677 #define FIELD_3BD_1(nam, dxf)                                                 \
678   if (dxf) {                                                                  \
679     FIELD_BD (nam.x, dxf);                                                    \
680     FIELD_BD (nam.y, dxf + 1);                                                \
681     FIELD_BD (nam.z, dxf + 2);                                                \
682   }
683 #define FIELD_3DPOINT(nam, dxf) FIELD_3BD (nam, dxf)
684 
685 #define FIELD_CMC(color, dxf) dxf_CMC (dat, (Dwg_Color*)&_obj->color, dxf, 0)
686 #define SUB_FIELD_CMC(o, color, dxf) dxf_CMC (dat, (Dwg_Color*)&_obj->o.color, dxf, 0)
687 #define FIELD_CMC0(color, dxf) dxf_CMC (dat, (Dwg_Color*)&_obj->color, dxf, 1)
688 
689 #define HEADER_TIMEBLL(nam, dxf) {                                            \
690   HEADER_9 (nam);                                                             \
691   FIELD_TIMEBLL (nam, dxf);                                                   \
692 }
693 #define FIELD_TIMEBLL(nam, dxf)                                               \
694   GROUP (dxf);                                                                \
695   fprintf (dat->fh, "%.09f\r\n", _obj->nam.value)
696 #define HEADER_CMC(nam, dxf)                                                  \
697   HEADER_9 (nam);                                                             \
698   VALUE_RS (dwg->header_vars.nam.index, dxf)
699 
700 #define POINT_3D(nam, var, c1, c2, c3)                                        \
701   {                                                                           \
702     VALUE_RD (dwg->var.x, c1);                                                \
703     VALUE_RD (dwg->var.y, c2);                                                \
704     VALUE_RD (dwg->var.z, c3);                                                \
705   }
706 #define POINT_2D(nam, var, c1, c2)                                            \
707   {                                                                           \
708     VALUE_RD (dwg->var.x, c1);                                                \
709     VALUE_RD (dwg->var.y, c2);                                                \
710   }
711 
712 // FIELD_VECTOR_N(nam, type, size):
713 // reads data of the type indicated by 'type' 'size' times and stores
714 // it all in the vector called 'nam'.
715 #define FIELD_VECTOR_N(nam, type, size, dxf)                                  \
716   if (dxf && _obj->nam)                                                       \
717     {                                                                         \
718       for (vcount = 0; vcount < (BITCODE_BL)size; vcount++)                   \
719         {                                                                     \
720           VALUE_##type (_obj->nam[vcount], dxf);                              \
721         }                                                                     \
722     }
723 #define FIELD_VECTOR_N1(nam, type, size, dxf)                                 \
724   if (dxf && _obj->nam)                                                       \
725     {                                                                         \
726       int _dxf = dxf;                                                         \
727       for (vcount = 0; vcount < (BITCODE_BL)size; _dxf++, vcount++)           \
728         {                                                                     \
729           VALUE_##type (_obj->nam[vcount], _dxf);                             \
730         }                                                                     \
731     }
732 #define FIELD_VECTOR_T(nam, type, size, dxf)                                  \
733   if (dxf && _obj->nam)                                                       \
734     {                                                                         \
735       if (IS_FROM_TU (dat))                                                   \
736       {                                                                       \
737         for (vcount = 0; vcount < (BITCODE_BL)_obj->size; vcount++)           \
738           VALUE_TU (_obj->nam[vcount], dxf);                                  \
739       }                                                                       \
740       else                                                                    \
741       {                                                                       \
742         for (vcount = 0; vcount < (BITCODE_BL)_obj->size; vcount++)           \
743           VALUE_TV (_obj->nam[vcount], dxf);                                  \
744       }                                                                       \
745     }
746 
747 #define FIELD_VECTOR(nam, type, size, dxf)                                    \
748   FIELD_VECTOR_N (nam, type, _obj->size, dxf)
749 
750 #define FIELD_2RD_VECTOR(nam, size, dxf)                                      \
751   if (dxf && _obj->nam)                                                       \
752     {                                                                         \
753       for (vcount = 0; vcount < (BITCODE_BL)_obj->size; vcount++)             \
754         {                                                                     \
755           FIELD_2RD (nam[vcount], dxf);                                       \
756         }                                                                     \
757     }
758 
759 #define FIELD_2DD_VECTOR(nam, size, dxf)                                      \
760   FIELD_2RD (nam[0], dxf);                                                    \
761   if (dxf && _obj->nam)                                                       \
762     {                                                                         \
763       for (vcount = 1; vcount < (BITCODE_BL)_obj->size; vcount++)             \
764         {                                                                     \
765           FIELD_2DD (nam[vcount], nam[vcount - 1], dxf);                      \
766         }                                                                     \
767     }
768 
769 #define FIELD_3DPOINT_VECTOR(nam, size, dxf)                                  \
770   if (dxf)                                                                    \
771     {                                                                         \
772       for (vcount = 0; vcount < (BITCODE_BL)_obj->size; vcount++)             \
773         {                                                                     \
774           FIELD_3DPOINT (nam[vcount], dxf);                                   \
775         }                                                                     \
776     }
777 
778 #define VALUE_HANDLE_N(hdlptr, nam, vcount, handle_code, dxf)                 \
779   if (dxf && hdlptr && size)                                                  \
780     {                                                                         \
781       for (vcount = 0; vcount < (BITCODE_BL)size; vcount++)                   \
782         {                                                                     \
783           VALUE_HANDLE (hdlptr[vcount], nam, handle_code, dxf);               \
784         }                                                                     \
785     }
786 #define FIELD_HANDLE_N(nam, size, handle_code, dxf)                           \
787   VALUE_HANDLE (_obj->nam, nam, handle_code, dxf)
788 #define HANDLE_VECTOR_N(nam, size, code, dxf)                                 \
789   if (dxf && _obj->nam && size)                                               \
790     {                                                                         \
791       for (vcount = 0; vcount < (BITCODE_BL)size; vcount++)                   \
792         {                                                                     \
793           FIELD_HANDLE (nam[vcount], code, dxf);                              \
794         }                                                                     \
795     }
796 
797 #define HANDLE_VECTOR(nam, sizefield, code, dxf)                              \
798   HANDLE_VECTOR_N (nam, FIELD_VALUE (sizefield), code, dxf)
799 
800 #define FIELD_NUM_INSERTS(num_inserts, type, dxf)                             \
801   FIELDG (num_inserts, type, dxf)
802 
803 #define FIELD_XDATA(nam, size)                                                \
804   dxf_write_xdata (dat, obj, _obj->nam, _obj->size)
805 
806 #define _XDICOBJHANDLE(code)                                                  \
807   if (dat->version >= R_13 && obj->tio.object->xdicobjhandle                  \
808       && obj->tio.object->xdicobjhandle->absolute_ref)                        \
809     {                                                                         \
810       fprintf (dat->fh, "102\r\n{ACAD_XDICTIONARY\r\n");                      \
811       VALUE_HANDLE (obj->tio.object->xdicobjhandle, xdicobjhandle, code,      \
812                     360);                                                     \
813       fprintf (dat->fh, "102\r\n}\r\n");                                      \
814     }
815 #define _REACTORS(code)                                                       \
816   if (dat->version >= R_13 && obj->tio.object->num_reactors                   \
817       && obj->tio.object->reactors)                                           \
818     {                                                                         \
819       fprintf (dat->fh, "102\r\n{ACAD_REACTORS\r\n");                         \
820       for (vcount = 0; vcount < obj->tio.object->num_reactors; vcount++)      \
821         { /* soft ptr */                                                      \
822           VALUE_HANDLE (obj->tio.object->reactors[vcount], reactors, code,    \
823                         330);                                                 \
824         }                                                                     \
825       fprintf (dat->fh, "102\r\n}\r\n");                                      \
826     }
827 #define ENT_REACTORS(code)                                                    \
828   if (dat->version >= R_13 && _obj->num_reactors && _obj->reactors)           \
829     {                                                                         \
830       fprintf (dat->fh, "102\r\n{ACAD_REACTORS\r\n");                         \
831       for (vcount = 0; vcount < _obj->num_reactors; vcount++)                 \
832         {                                                                     \
833           VALUE_HANDLE (_obj->reactors[vcount], reactors, code, 330);         \
834         }                                                                     \
835       fprintf (dat->fh, "102\r\n}\r\n");                                      \
836     }
837 #define REACTORS(code)
838 #define XDICOBJHANDLE(code)
839 #define ENT_XDICOBJHANDLE(code)                                               \
840   if (dat->version >= R_13 && obj->tio.entity->xdicobjhandle                  \
841       && obj->tio.entity->xdicobjhandle->absolute_ref)                        \
842     {                                                                         \
843       fprintf (dat->fh, "102\r\n{ACAD_XDICTIONARY\r\n");                      \
844       VALUE_HANDLE (obj->tio.entity->xdicobjhandle, xdicobjhandle, code,      \
845                     360);                                                     \
846       fprintf (dat->fh, "102\r\n}\r\n");                                      \
847     }
848 #define BLOCK_NAME(nam, dxf) dxf_cvt_blockname (dat, _obj->nam, dxf)
849 
850 #define COMMON_ENTITY_HANDLE_DATA
851 #define SECTION_STRING_STREAM
852 #define START_STRING_STREAM
853 #define END_STRING_STREAM
854 #define START_HANDLE_STREAM
855 
856 #ifndef DEBUG_CLASSES
857 static int
dwg_dxf_TABLECONTENT(Bit_Chain * restrict dat,const Dwg_Object * restrict obj)858 dwg_dxf_TABLECONTENT (Bit_Chain *restrict dat, const Dwg_Object *restrict obj)
859 {
860   (void)dat;
861   (void)obj;
862   return 0;
863 }
864 #else
865 static int dwg_dxf_TABLECONTENT (Bit_Chain *restrict dat,
866                                  const Dwg_Object *restrict obj);
867 #endif
868 
869 // The strcmp is being optimized away at compile-time!
870 // https://godbolt.org/g/AqkhwL
871 #define DWG_ENTITY(token)                                                     \
872   static int dwg_dxf_##token##_private (                                      \
873       Bit_Chain *dat, Bit_Chain *hdl_dat, Bit_Chain *str_dat,                 \
874       const Dwg_Object *restrict obj);                                        \
875   static int dwg_dxf_##token (Bit_Chain *restrict dat,                        \
876                               const Dwg_Object *restrict obj)                 \
877   {                                                                           \
878     int error = 0;                                                            \
879     Bit_Chain *hdl_dat = dat;                                                 \
880     Bit_Chain *str_dat = dat;                                                 \
881     if (obj->fixedtype != DWG_TYPE_##token)                                   \
882       {                                                                       \
883         LOG_ERROR ("Invalid type 0x%x, expected 0x%x %s", obj->fixedtype,     \
884                    DWG_TYPE_##token, #token);                                 \
885         return DWG_ERR_INVALIDTYPE;                                           \
886       }                                                                       \
887     if (strEQc (#token, "GEOPOSITIONMARKER"))                                 \
888       RECORD (POSITIONMARKER);                                                \
889     else if (dat->version < R_13 && strlen (#token) == 10                     \
890              && strEQc (#token, "LWPOLYLINE"))                                \
891       RECORD (POLYLINE);                                                      \
892     else if (strlen (#token) > 10 && !memcmp (#token, "DIMENSION_", 10))      \
893       RECORD (DIMENSION);                                                     \
894     else if (strlen (#token) > 9 && !memcmp (#token, "POLYLINE_", 9))         \
895       RECORD (POLYLINE);                                                      \
896     else if (strlen (#token) > 7 && !memcmp (#token, "VERTEX_", 7))           \
897       RECORD (VERTEX);                                                        \
898     else if (strEQc (#token, "MINSERT"))                                      \
899       RECORD (INSERT);                                                        \
900     else if (dat->version >= R_2010 && strEQc (#token, "TABLE"))              \
901       {                                                                       \
902         RECORD (ACAD_TABLE);                                                  \
903         return dwg_dxf_TABLECONTENT (dat, obj);                               \
904       }                                                                       \
905     else if (strlen (#token) > 3 && !memcmp (#token, "_3D", 3))               \
906       record (obj->dxfname);                                                  \
907     else if (obj->type >= 498 && obj->dxfname)                                \
908       record (obj->dxfname);                                                  \
909     else                                                                      \
910       RECORD (token);                                                         \
911     LOG_INFO ("Entity " #token ":\n")                                         \
912     SINCE (R_11)                                                              \
913     {                                                                         \
914       LOG_TRACE ("Entity handle: " FORMAT_H "\n", ARGS_H (obj->handle));      \
915       fprintf (dat->fh, "%3i\r\n%lX\r\n", 5, obj->handle.value);              \
916     }                                                                         \
917     SINCE (R_13) { error |= dxf_common_entity_handle_data (dat, obj); }       \
918     error |= dwg_dxf_##token##_private (dat, hdl_dat, str_dat, obj);          \
919     error |= dxf_write_eed (dat, obj->tio.object);                            \
920     return error;                                                             \
921   }                                                                           \
922   static int dwg_dxf_##token##_private (                                      \
923       Bit_Chain *dat, Bit_Chain *hdl_dat, Bit_Chain *str_dat,                 \
924       const Dwg_Object *restrict obj) {                                       \
925     int error = 0;                                                            \
926     BITCODE_BL vcount, rcount3, rcount4;                                      \
927     Dwg_Data *dwg = obj->parent;                                              \
928     Dwg_Entity_##token *_obj = obj->tio.entity->tio.token;                    \
929     Dwg_Object_Entity *_ent = obj->tio.entity;
930 
931 #define DWG_ENTITY_END                                                        \
932     return error;                                                             \
933   }
934 
935 #define DWG_OBJECT(token)                                                     \
936   static int dwg_dxf_##token##_private (                                      \
937       Bit_Chain *dat, Bit_Chain *hdl_dat, Bit_Chain *str_dat,                 \
938       const Dwg_Object *restrict obj);                                        \
939   static int dwg_dxf_##token (Bit_Chain *restrict dat,                        \
940                               const Dwg_Object *restrict obj)                 \
941   {                                                                           \
942     int error = 0;                                                            \
943     Bit_Chain *hdl_dat = dat, *str_dat = dat;                                 \
944     LOG_INFO ("Object " #token ":\n")                                         \
945     if (obj->fixedtype != DWG_TYPE_##token)                                   \
946       {                                                                       \
947         LOG_ERROR ("Invalid type 0x%x, expected 0x%x %s", obj->fixedtype,     \
948                    DWG_TYPE_##token, #token);                                 \
949         return DWG_ERR_INVALIDTYPE;                                           \
950       }                                                                       \
951     PRE (R_14) {                                                              \
952       if (obj->fixedtype == DWG_TYPE_PLACEHOLDER)                             \
953         return 0;                                                             \
954     }                                                                         \
955     if (!dwg_obj_is_control (obj))                                            \
956       {                                                                       \
957         if (obj->fixedtype == DWG_TYPE_TABLE)                                 \
958           ;                                                                   \
959         else if (obj->type >= 500 && obj->dxfname)                            \
960           fprintf (dat->fh, "  0\r\n%s\r\n", obj->dxfname);                   \
961         else if (obj->type == DWG_TYPE_PLACEHOLDER)                           \
962           RECORD (ACDBPLACEHOLDER);                                           \
963         else if (obj->fixedtype == DWG_TYPE_PROXY_OBJECT)                     \
964           RECORD (ACAD_PROXY_OBJECT);                                         \
965         else if (obj->type != DWG_TYPE_BLOCK_HEADER)                          \
966           RECORD (token);                                                     \
967                                                                               \
968         SINCE (R_13)                                                          \
969         {                                                                     \
970           BITCODE_BL vcount;                                                  \
971           const int dxf = obj->type == DWG_TYPE_DIMSTYLE ? 105 : 5;           \
972           VALUE_H (obj->handle.value, dxf);                                   \
973           _XDICOBJHANDLE (3);                                                 \
974           _REACTORS (4);                                                      \
975         }                                                                     \
976         SINCE (R_14)                                                          \
977         {                                                                     \
978           VALUE_HANDLE (obj->tio.object->ownerhandle, ownerhandle, 3, 330);   \
979         }                                                                     \
980       }                                                                       \
981     if (DWG_LOGLEVEL >= DWG_LOGLEVEL_TRACE)                                   \
982       {                                                                       \
983         if (dwg_obj_is_table (obj))                                           \
984           {                                                                   \
985             char *_name = dwg_obj_table_get_name (obj, &error);               \
986             LOG_TRACE ("Object handle: " FORMAT_H ", name: %s\n",             \
987                        ARGS_H (obj->handle), _name);                          \
988             if (IS_FROM_TU (dat))                                             \
989               free (_name);                                                   \
990           }                                                                   \
991         else                                                                  \
992           LOG_TRACE ("Object handle: " FORMAT_H "\n", ARGS_H (obj->handle))   \
993       }                                                                       \
994     error |= dwg_dxf_##token##_private (dat, hdl_dat, str_dat, obj);          \
995     error |= dxf_write_eed (dat, obj->tio.object);                            \
996     return error;                                                             \
997   }                                                                           \
998   static int dwg_dxf_##token##_private (                                      \
999       Bit_Chain *dat, Bit_Chain *hdl_dat, Bit_Chain *str_dat,                 \
1000       const Dwg_Object *restrict obj) {                                       \
1001     int error = 0;                                                            \
1002     BITCODE_BL vcount, rcount3, rcount4;                                      \
1003     Dwg_Data *dwg = obj->parent;                                              \
1004     Dwg_Object_##token *_obj = obj->tio.object->tio.token;
1005 
1006 // then 330, SUBCLASS
1007 
1008 #define DWG_OBJECT_END                                                        \
1009     return error;                                                             \
1010   }
1011 
1012 #undef DXF_3DSOLID
1013 #define DXF_3DSOLID dxf_3dsolid (dat, obj, (Dwg_Entity_3DSOLID *)_obj);
1014 
1015 // Skip index 256 bylayer
1016 // 257 is for method c8 NONE. Which index is for ByBlock?
1017 // If the dxf code is 90-99 rather emit the rgb only
dxf_CMC(Bit_Chain * restrict dat,Dwg_Color * restrict color,const int dxf,const int opt)1018 static void dxf_CMC (Bit_Chain *restrict dat, Dwg_Color *restrict color,
1019                      const int dxf, const int opt)
1020 {
1021   if (dat->version >= R_2004)
1022     {
1023       if (dat->from_version < R_2004)
1024         bit_upconvert_CMC (dat, color);
1025       if (dxf >= 90)
1026         {
1027           VALUE_RLd (color->rgb, dxf);
1028           return;
1029         }
1030       else if (color->method == 0xc3)
1031         {
1032           VALUE_RS (color->rgb & 0x00ffffff, dxf);
1033           return;
1034         }
1035       else if (color->method == 0xc8)
1036         {
1037           VALUE_RS (257, dxf);
1038           return;
1039         }
1040       if (!opt || color->index)
1041         {
1042           VALUE_RS (color->index, dxf);
1043         }
1044       if (color->method != 0xc2)
1045         return;
1046       VALUE_RL (color->rgb, dxf + 420 - 62);
1047       if (color->flag & 2 && color->book_name)
1048         {
1049           char name[256];
1050           if (IS_FROM_TU (dat))
1051             {
1052               char *u8 = bit_convert_TU ((BITCODE_TU)color->book_name);
1053               if (u8)
1054                 strncpy (name, u8, 127);
1055               else
1056                 name[0] = '\0';
1057               free (u8);
1058               u8 = bit_convert_TU ((BITCODE_TU)color->name);
1059               if (u8)
1060                 {
1061                   if (*name)
1062                     strcat (name, "$");
1063                   strncat (name, u8, 127);
1064                   free (u8);
1065                 }
1066             }
1067           else
1068             {
1069               strncpy (name, color->book_name, 127);
1070               if (color->name)
1071                 {
1072                   strcat (name, "$");
1073                   strncat (name, color->name, 127);
1074                 }
1075             }
1076           VALUE_TV (name, dxf + 430 - 62);
1077         }
1078       else if (color->flag & 1 && color->name)
1079         {
1080           VALUE_T (color->name, dxf + 430 - 62);
1081         }
1082       else if (color->flag)
1083         {
1084           VALUE_TFF ("UNNAMED", dxf + 430 - 62);
1085         }
1086     }
1087   else
1088     {
1089       bit_downconvert_CMC (dat, color);
1090       VALUE_RS (color->index, dxf);
1091     }
1092 }
1093 
1094 /* fixme: shift-jis decoding
1095 "\M+182B1\M+182CC\M+1907D\M+19867\M+182CD\M+18354\M+18393\M+18376\M+1838B\M+182C5\M+182B7\M+18142\M+18ED0\M+193E0\M+182CC\M+18B4B\M+18A69\M+182E2\M+18376\M+1838D\M+18362\M+1835E\M+182CC\M+18F6F\M+197CD\M+194CD\M+188CD\M+182C9\M+18D87\M+182ED\M+182B9\M+182C4\M+1934B\M+19396\M+182C9\M+195CF\M+18D58\M+182B5\M+182C4\M+182B2\M+19798\M+19770\M+182AD\M+182BE\M+182B3\M+182A2\M+18142"
1096 =>
1097 "\U+3053\U+306E\U+56F3\U+67A0\U+306F\U+30B5\U+30F3\U+30D7\U+30EB\U+3067\U+3059\U+3002\U+793E\U+5185\U+306E\U+898F\U+683C\U+3084\U+30D7\U+30ED\U+30C3\U+30BF\U+306E\U+51FA\U+529B\U+7BC4\U+56F2\U+306B\U+5408\U+308F\U+305B\U+3066\U+9069\U+5F53\U+306B\U+5909\U+66F4\U+3057\U+3066\U+3054\U+5229\U+7528\U+304F\U+3060\U+3055\U+3044\U+3002"
1098 */
1099 static char *
cquote(char * restrict dest,const int len,const char * restrict src)1100 cquote (char *restrict dest, const int len, const char *restrict src)
1101 {
1102   char c;
1103   char *d = dest;
1104   const char* dend = dest + len;
1105   const char* send = src + strlen(src);
1106   char *s = (char *)src;
1107   while ((s < send) && (c = *s++) && dest < dend)
1108     {
1109       if (c == '\n' && dest+1 < dend)
1110         {
1111           *dest++ = '^';
1112           *dest++ = 'J';
1113         }
1114       else if (c == '\r' && dest+1 < dend)
1115         {
1116           *dest++ = '^';
1117           *dest++ = 'M';
1118         }
1119       // convert shiftjis \M+1xxxx to \U+xxxx
1120       else if (c == '\\' && dest+7 < dend && memBEGINc (s, "M+1"))
1121         { // e.g. \M+1(8140) => \U+3000, 82a0 => 3042
1122           uint32_t x;
1123           sscanf (&s[3], "%4X", &x);
1124           // just convert a small subset, Hiragana + Katakana letters
1125           // see https://www.unicode.org/Public/MAPPINGS/OBSOLETE/EASTASIA/JIS/SHIFTJIS.TXT
1126           if (x < 0x829f) // < Hiragana: 8140 -> 3000: FULLWIDTH LATIN LETTER
1127             x -= 0x5140;
1128           else if (x >= 0x889f) {    // CJK
1129             LOG_WARN ("Unsupported \\M+1%04X shift-jis character", x);
1130             x -= (0x889f - 0x404c); // not really
1131           }
1132           else if (x >= 0x839f)     // > Katakana: Greek
1133             x -= (0x839f - 0x391);
1134           else
1135             x -= 0x525e; // our safe range of Hiragana + Katakana letters
1136           if (x < 0x10100)
1137             {
1138               snprintf (dest, dend - dest, "\\U+%04X", x);
1139               dest += 7;
1140               s += 7;
1141             }
1142           else
1143             {
1144               LOG_ERROR ("Invalid shift-jis sequence %s", s-1);
1145               s += 3;
1146             }
1147         }
1148       else
1149         *dest++ = c;
1150     }
1151   d[len - 1] = '\0'; // add final delim, skipped above
1152   return d;
1153 }
1154 
1155 /* If opts 1:
1156      quote \n => ^J
1157      \M+xxxxx => \U+XXXX (shift-jis)
1158    Splits overlong (len>255) lines into dxf 3 chunks with group 1
1159  */
1160 static void
dxf_fixup_string(Bit_Chain * restrict dat,char * restrict str,const int opts,const int dxf,const int dxfcont)1161 dxf_fixup_string (Bit_Chain *restrict dat, char *restrict str,
1162                   const int opts, const int dxf, const int dxfcont)
1163 {
1164   if (str && *str)
1165     {
1166       if (opts && (strchr (str, '\n') || strchr (str, '\r') || strstr (str, "\\M+1")))
1167         {
1168           const int origlen = strlen (str);
1169           int len = (2 * origlen) + 1;
1170           char *_buf;
1171           if (len > 1024)
1172             {
1173               fprintf (dat->fh, "\r\n");
1174               LOG_ERROR ("Overlarge DXF string, len=%d", origlen);
1175               return;
1176             }
1177           _buf = (char *)alloca (len);
1178           if (!_buf)
1179             {
1180               fprintf (dat->fh, "\r\n");
1181               LOG_ERROR ("Out of stack memory");
1182               return;
1183             }
1184           _buf[len - 1] = '\0';
1185           _buf = cquote (_buf, len, str);
1186           if (!_buf)
1187             {
1188               fprintf (dat->fh, "\r\n");
1189               LOG_ERROR ("Out of stack");
1190               return;
1191             }
1192           len = strlen (_buf);
1193           if (len > 255 && dxf == 1)
1194             {
1195               // GROUP 1 already printed
1196               while (len > 0)
1197                 {
1198                   fprintf (dat->fh, "%.*s\r\n", len > 255 ? 255 : len, _buf);
1199                   len -= 255;
1200                   _buf += 255;
1201                   if (len > 0)
1202                     fprintf (dat->fh, "%3d\r\n", dxfcont);
1203                 }
1204             }
1205           else
1206             fprintf (dat->fh, "%s\r\n", _buf);
1207           freea (_buf);
1208         }
1209       else
1210         {
1211           int len = strlen (str);
1212           if (len > 255 && dxf == 1)
1213             {
1214               // GROUP 1 already printed
1215               while (len > 0)
1216                 {
1217                   fprintf (dat->fh, "%.*s\r\n", len > 255 ? 255 : len, str);
1218                   len -= 255;
1219                   str += 255;
1220                   if (len > 0)
1221                     fprintf (dat->fh, "  3\r\n");
1222                 }
1223             }
1224           else
1225             fprintf (dat->fh, "%s\r\n", str);
1226         }
1227     }
1228   else
1229     fprintf (dat->fh, "\r\n");
1230 }
1231 
1232 static int
dxf_write_eed(Bit_Chain * restrict dat,const Dwg_Object_Object * restrict obj)1233 dxf_write_eed (Bit_Chain *restrict dat, const Dwg_Object_Object *restrict obj)
1234 {
1235   int error = 0;
1236   Dwg_Data *dwg = obj->dwg;
1237   for (BITCODE_BL i = 0; i < obj->num_eed; i++)
1238     {
1239       const Dwg_Eed* _obj = &obj->eed[i];
1240       if (_obj->size)
1241         {
1242           // name of APPID
1243           Dwg_Object *appid = dwg_resolve_handle (dwg, _obj->handle.value);
1244           if (appid && appid->fixedtype == DWG_TYPE_APPID)
1245             VALUE_T (appid->tio.object->tio.APPID->name, 1001)
1246           else
1247             VALUE_TFF ("ACAD", 1001);
1248         }
1249       if (_obj->data)
1250         {
1251           const Dwg_Eed_Data *data = _obj->data;
1252           const int dxf = data->code + 1000;
1253           switch (data->code)
1254             {
1255             case 0:
1256               if (!data->u.eed_0.length)
1257                 fprintf (dat->fh, "1000\r\n\r\n");
1258               else if (data->u.eed_0.is_tu)
1259                 VALUE_TU (data->u.eed_0_r2007.string, 1000)
1260               else
1261                 VALUE_TV (data->u.eed_0.string, 1000)
1262               break;
1263             case 2:
1264               if (data->u.eed_2.close)
1265                 VALUE_TFF ("}", 1002)
1266               else
1267                 VALUE_TFF ("{", 1002)
1268               break;
1269             case 3:
1270               GROUP (dxf);
1271               fprintf (dat->fh, "%9lu\r\n", (unsigned long)data->u.eed_3.layer);
1272               //VALUE_RLL (data->u.eed_3.layer, dxf);
1273               break;
1274             case 4: VALUE_BINARY (data->u.eed_4.data, data->u.eed_4.length, dxf); break;
1275             case 5: VALUE_H (data->u.eed_5.entity, dxf); break; // not in DXF
1276             case 10:
1277             case 11:
1278             case 12:
1279             case 13:
1280             case 14:
1281             case 15: VALUE_3BD (data->u.eed_10.point, dxf); break;
1282             case 40:
1283             case 41:
1284             case 42: VALUE_RD (data->u.eed_40.real, dxf); break;
1285             case 70: VALUE_RS (data->u.eed_70.rs, dxf); break;
1286             case 71: VALUE_RL (data->u.eed_71.rl, dxf); break;
1287             default: VALUE_RC (0, dxf);
1288             }
1289         }
1290     }
1291   return error;
1292 }
1293 
1294 /* If the name contains "$0$"
1295  */
1296 bool
dxf_is_xrefdep_name(Bit_Chain * restrict dat,const char * name)1297 dxf_is_xrefdep_name (Bit_Chain *restrict dat,
1298                      const char *name)
1299 {
1300   if (IS_FROM_TU (dat))
1301     {
1302       BITCODE_TU wstr = (BITCODE_TU)name;
1303 #if defined (HAVE_NATIVE_WCHAR2) && defined (HAVE_WCSSTR)
1304       if (wstr && *wstr && wcsstr (&wstr[1], L"$0$"))
1305         return true;
1306       else
1307         return false;
1308 #else
1309       bool result;
1310       char* u8 = bit_convert_TU (wstr);
1311       if (u8 && *u8 && strstr (&u8[1], "$0$"))
1312         result = true;
1313       else
1314         result = false;
1315       if (u8)
1316         free (u8);
1317       return result;
1318 #endif
1319     }
1320   else
1321     {
1322       if (name && *name && strstr (&name[1], "$0$"))
1323         return true;
1324       else
1325         return false;
1326     }
1327 }
1328 
1329 /* Layer names with active dependent xref have a name like "REF|name",
1330    or "REF|REFNAME$0$name" name.
1331    Otherwise we get Layer name with vertical bar is not marked dependent
1332    (gh44-error_2013)
1333  */
1334 bool
dxf_has_xrefdep_vertbar(Bit_Chain * restrict dat,const char * name)1335 dxf_has_xrefdep_vertbar (Bit_Chain *restrict dat,
1336                          const char *name)
1337 {
1338   if (IS_FROM_TU (dat))
1339     {
1340       BITCODE_TU wstr = (BITCODE_TU)name;
1341 #if defined (HAVE_NATIVE_WCHAR2) && defined (HAVE_WCSCHR)
1342       if (wstr && *wstr && wcschr (&wstr[1], L'|'))
1343         return true;
1344       else
1345         return false;
1346 #else
1347       bool result;
1348       char* u8 = bit_convert_TU (wstr);
1349       if (u8 && *u8 && strchr (&u8[1], '|'))
1350         result = true;
1351       else
1352         result = false;
1353       if (u8)
1354         free (u8);
1355       return result;
1356 #endif
1357     }
1358   else
1359     {
1360       if (name && *name && strchr (&name[1], '|'))
1361         return true;
1362       else
1363         return false;
1364     }
1365 }
1366 
1367 bool
dxf_has_STYLE_eed(Bit_Chain * restrict dat,const Dwg_Object_Object * restrict obj)1368 dxf_has_STYLE_eed (Bit_Chain *restrict dat,
1369                    const Dwg_Object_Object *restrict obj)
1370 {
1371   bool result = false;
1372   bool has_acadappid = false;
1373   Dwg_Data *dwg = obj->dwg;
1374   for (BITCODE_BL i = 0; i < obj->num_eed; i++)
1375     {
1376       const Dwg_Eed* _obj = &obj->eed[i];
1377       if (_obj->size)
1378         {
1379           // check for APPID ACAD and first data to be a string 0. TODO 2nd to be 71
1380           Dwg_Object *appid = dwg_resolve_handle (dwg, _obj->handle.value);
1381           if (appid && appid->fixedtype == DWG_TYPE_APPID &&
1382               bit_eq_T (dat, appid->tio.object->tio.APPID->name, "ACAD"))
1383             {
1384               has_acadappid = true;
1385               if (_obj->data && _obj->data->code == 0)
1386                 return true;
1387             }
1388         }
1389     }
1390   return result;
1391 }
1392 
1393 GCC30_DIAG_IGNORE (-Wformat-nonliteral)
1394 static int
dxf_write_xdata(Bit_Chain * restrict dat,const Dwg_Object * restrict obj,Dwg_Resbuf * restrict rbuf,BITCODE_BL size)1395 dxf_write_xdata (Bit_Chain *restrict dat, const Dwg_Object *restrict obj,
1396                  Dwg_Resbuf *restrict rbuf, BITCODE_BL size)
1397 {
1398   Dwg_Resbuf *tmp;
1399   int i;
1400 
1401   while (rbuf)
1402     {
1403       const char *fmt;
1404       short type;
1405       int dxftype = rbuf->type;
1406 
1407       fmt = dxf_format (rbuf->type);
1408       type = dwg_resbuf_value_type (rbuf->type);
1409       dxftype = (rbuf->type > 1000 || obj->fixedtype == DWG_TYPE_XRECORD)
1410                     ? rbuf->type
1411                     : rbuf->type + 1000;
1412       if (obj->fixedtype == DWG_TYPE_XRECORD && dxftype >= 80 && dxftype < 90)
1413         {
1414           fmt = "(unknown code)";
1415           type = DWG_VT_INVALID;
1416         }
1417 
1418       if (strEQc (fmt, "(unknown code)"))
1419         {
1420           if (type == DWG_VT_INVALID)
1421             {
1422               LOG_WARN ("Invalid xdata code %d", dxftype);
1423             }
1424           else
1425             {
1426               LOG_WARN ("Unknown xdata code %d => %d", dxftype,
1427                         (BITCODE_BL)type);
1428             }
1429         }
1430 
1431       tmp = rbuf->nextrb;
1432       switch (type)
1433         {
1434         case DWG_VT_STRING:
1435           if (IS_FROM_TU (dat)) { VALUE_TU (rbuf->value.str.u.wdata, dxftype); }
1436           else                  { VALUE_TV (rbuf->value.str.u.data, dxftype); }
1437           break;
1438         case DWG_VT_REAL:
1439           VALUE_RD (rbuf->value.dbl, dxftype);
1440           break;
1441         case DWG_VT_BOOL:
1442         case DWG_VT_INT8:
1443           VALUE_RC (rbuf->value.i8, dxftype);
1444           break;
1445         case DWG_VT_INT16:
1446           VALUE_RS (rbuf->value.i16, dxftype);
1447           break;
1448         case DWG_VT_INT32:
1449           VALUE_RL (rbuf->value.i32, dxftype);
1450           break;
1451         case DWG_VT_INT64:
1452           VALUE_RLL (rbuf->value.i64, dxftype);
1453           break;
1454         case DWG_VT_POINT3D:
1455           VALUE_RD (rbuf->value.pt[0], dxftype);
1456           VALUE_RD (rbuf->value.pt[1], dxftype + 10);
1457           VALUE_RD (rbuf->value.pt[2], dxftype + 20);
1458           break;
1459         case DWG_VT_BINARY:
1460           VALUE_BINARY (rbuf->value.str.u.data, rbuf->value.str.size, dxftype);
1461           break;
1462         case DWG_VT_HANDLE:
1463         case DWG_VT_OBJECTID:
1464           fprintf (dat->fh, "%3i\r\n%lX\r\n", dxftype,
1465                    (unsigned long)*(uint64_t *)rbuf->value.hdl);
1466           break;
1467         case DWG_VT_INVALID:
1468           break; // skip
1469         default:
1470           fprintf (dat->fh, "%3i\r\n\r\n", dxftype);
1471           break;
1472         }
1473       rbuf = tmp;
1474     }
1475   return 0;
1476 }
1477 
1478 // r13+ converts STANDARD to Standard, BYLAYER to ByLayer, BYBLOCK to ByBlock
1479 static void
dxf_cvt_tablerecord(Bit_Chain * restrict dat,const Dwg_Object * restrict obj,char * restrict name,const int dxf)1480 dxf_cvt_tablerecord (Bit_Chain *restrict dat, const Dwg_Object *restrict obj,
1481                      char *restrict name, const int dxf)
1482 {
1483   if (obj && obj->supertype == DWG_SUPERTYPE_OBJECT && name != NULL)
1484     {
1485       if (IS_FROM_TU (dat))
1486         {
1487           name = bit_convert_TU ((BITCODE_TU)name);
1488         }
1489       if (dat->from_version >= R_13 && dat->version < R_13)
1490         { // convert the other way round, from newer to older
1491           if (strEQc (name, "Standard"))
1492             fprintf (dat->fh, "%3i\r\nSTANDARD\r\n", dxf);
1493           else if (strEQc (name, "ByLayer"))
1494             fprintf (dat->fh, "%3i\r\nBYLAYER\r\n", dxf);
1495           else if (strEQc (name, "ByBlock"))
1496             fprintf (dat->fh, "%3i\r\nBYBLOCK\r\n", dxf);
1497           else if (strEQc (name, "*Active"))
1498             fprintf (dat->fh, "%3i\r\n*ACTIVE\r\n", dxf);
1499           else
1500             fprintf (dat->fh, "%3i\r\n%s\r\n", dxf, name);
1501         }
1502       else
1503         { // convert some standard names
1504           if (dat->version >= R_13 && strEQc (name, "STANDARD"))
1505             fprintf (dat->fh, "%3i\r\nStandard\r\n", dxf);
1506           else if (dat->version >= R_13 && strEQc (name, "BYLAYER"))
1507             fprintf (dat->fh, "%3i\r\nByLayer\r\n", dxf);
1508           else if (dat->version >= R_13 && strEQc (name, "BYBLOCK"))
1509             fprintf (dat->fh, "%3i\r\nByBlock\r\n", dxf);
1510           else if (dat->version >= R_13 && strEQc (name, "*ACTIVE"))
1511             fprintf (dat->fh, "%3i\r\n*Active\r\n", dxf);
1512           else
1513             fprintf (dat->fh, "%3i\r\n%s\r\n", dxf, name);
1514         }
1515       if (IS_FROM_TU (dat))
1516         free (name);
1517     }
1518   else
1519     {
1520       fprintf (dat->fh, "%3i\r\n\r\n", dxf);
1521     }
1522 }
1523 
1524 /* pre-r13 mspace and pspace blocks have different names:
1525    *Model_Space => $MODEL_SPACE
1526    *Paper_Space => $PAPER_SPACE
1527    TODO: Better use proper EXTNAMES
1528  */
1529 static void
dxf_cvt_blockname(Bit_Chain * restrict dat,char * restrict name,const int dxf)1530 dxf_cvt_blockname (Bit_Chain *restrict dat, char *restrict name, const int dxf)
1531 {
1532   if (!name)
1533     {
1534       fprintf (dat->fh, "%3i\r\n\r\n", dxf);
1535       return;
1536     }
1537   if (IS_FROM_TU (dat)) // r2007+ unicode names
1538     {
1539       name = bit_convert_TU ((BITCODE_TU)name);
1540     }
1541   if (dat->version == dat->from_version) // no conversion
1542     {
1543       fprintf (dat->fh, "%3i\r\n%s\r\n", dxf, name);
1544     }
1545   else if (dat->version < R_13 && dat->from_version >= R_13) // to older
1546     {
1547       if (strlen (name) < 10)
1548         fprintf (dat->fh, "%3i\r\n%s\r\n", dxf, name);
1549       else if (strEQc (name, "*Model_Space"))
1550         fprintf (dat->fh, "%3i\r\n$MODEL_SPACE\r\n", dxf);
1551       else if (strEQc (name, "*Paper_Space"))
1552         fprintf (dat->fh, "%3i\r\n$PAPER_SPACE\r\n", dxf);
1553       else if (!memcmp (name, "*Paper_Space", sizeof ("*Paper_Space") - 1))
1554         fprintf (dat->fh, "%3i\r\n$PAPER_SPACE%s\r\n", dxf, &name[12]);
1555       else
1556         fprintf (dat->fh, "%3i\r\n%s\r\n", dxf, name);
1557     }
1558   else if (dat->version >= R_13 && dat->from_version < R_13) // to newer
1559     {
1560       if (strlen (name) < 10)
1561         fprintf (dat->fh, "%3i\r\n%s\r\n", dxf, name);
1562       else if (strEQc (name, "$MODEL_SPACE"))
1563         fprintf (dat->fh, "%3i\r\n*Model_Space\r\n", dxf);
1564       else if (strEQc (name, "$PAPER_SPACE"))
1565         fprintf (dat->fh, "%3i\r\n*Paper_Space\r\n", dxf);
1566       else if (!memcmp (name, "$PAPER_SPACE", sizeof ("$PAPER_SPACE") - 1))
1567         fprintf (dat->fh, "%3i\r\n*Paper_Space%s\r\n", dxf, &name[12]);
1568       else
1569         fprintf (dat->fh, "%3i\r\n%s\r\n", dxf, name);
1570     }
1571   if (IS_FROM_TU (dat))
1572     {
1573       free (name);
1574       name = NULL;
1575     }
1576 }
1577 
1578 #define START_OBJECT_HANDLE_STREAM
1579 
1580 // Handle 5 written here first
1581 #define COMMON_TABLE_CONTROL_FLAGS                                            \
1582   if (ctrl)                                                                   \
1583     {                                                                         \
1584       SINCE (R_13)                                                            \
1585       {                                                                       \
1586         VALUE_H (ctrl->handle.value, 5);                                      \
1587         _XDICOBJHANDLE (3);                                                   \
1588         _REACTORS (4);                                                        \
1589       }                                                                       \
1590       SINCE (R_14)                                                            \
1591       {                                                                       \
1592         VALUE_HANDLE (ctrl->tio.object->ownerhandle, ownerhandle, 3, 330);    \
1593       }                                                                       \
1594     }                                                                         \
1595   SINCE (R_13) { VALUE_TV ("AcDbSymbolTable", 100); }
1596 
1597 #define COMMON_TABLE_FLAGS(acdbname)                                          \
1598   SINCE (R_13)                                                                \
1599   {                                                                           \
1600     VALUE_TV ("AcDbSymbolTableRecord", 100);                                  \
1601     VALUE_TV ("AcDb" #acdbname "TableRecord", 100);                           \
1602   }                                                                           \
1603   if (strEQc (#acdbname, "Block") && dat->version >= R_13)                    \
1604     {                                                                         \
1605       Dwg_Object *blk = dwg_ref_object (                                      \
1606           dwg, ((Dwg_Object_BLOCK_HEADER *)_obj)->block_entity);              \
1607       if (blk && blk->type == DWG_TYPE_BLOCK)                                 \
1608         {                                                                     \
1609           Dwg_Entity_BLOCK *_blk = blk->tio.entity->tio.BLOCK;                \
1610           VALUE_T (_blk->name, 2)                                             \
1611         }                                                                     \
1612       else if (_obj->name)                                                    \
1613         {                                                                     \
1614           VALUE_T (_obj->name, 2)                                             \
1615         }                                                                     \
1616       else                                                                    \
1617         VALUE_TV ("*", 2)                                                     \
1618     }                                                                         \
1619   /* Empty name with xref shape names */                                      \
1620   else if (strEQc (#acdbname, "TextStyle") &&                                 \
1621            _obj->flag & 1 &&                                                  \
1622            dxf_is_xrefdep_name (dat, _obj->name))                             \
1623     VALUE_TV ("", 2)                                                          \
1624   else if (_obj->name)                                                        \
1625     dxf_cvt_tablerecord (dat, obj, _obj->name, 2);                            \
1626   else                                                                        \
1627     VALUE_TV ("*", 2)                                                         \
1628   if (strEQc (#acdbname, "Layer") && dat->version >= R_2000)                  \
1629     {                                                                         \
1630       /* Mask off plotflag and linewt. */                                     \
1631       BITCODE_RC _flag = _obj->flag & ~0x3e0;                                 \
1632       /* Don't keep bit 16 when not xrefdep like "XREF|name" */               \
1633       if (_flag & 0x10 && !dxf_has_xrefdep_vertbar (dat, _obj->name))         \
1634         _flag &= ~0x10;                                                       \
1635       VALUE_RC (_flag, 70);                                                   \
1636     }                                                                         \
1637   else if (strEQc (#acdbname, "Block") && dat->version >= R_2000)             \
1638     ; /* skip 70 for AcDbBlockTableRecord here. done in AcDbBlockBegin */     \
1639   else                                                                        \
1640     {                                                                         \
1641       /* mask off 64, the loaded bit 6 */                                     \
1642       VALUE_RC (_obj->flag & ~64, 70);                                        \
1643     }
1644 
1645 // unused
1646 #define LAYER_TABLE_FLAGS(acdbname)                                           \
1647   SINCE (R_13)                                                                \
1648   {                                                                           \
1649     VALUE_TV ("AcDbSymbolTableRecord", 100);                                  \
1650     VALUE_TV ("AcDb" #acdbname "TableRecord", 100);                           \
1651   }                                                                           \
1652   if (_obj->name)                                                             \
1653     dxf_cvt_tablerecord (dat, obj, _obj->name, 2);                            \
1654   FIELD_RS (flag, 70)
1655 
1656 #include "dwg.spec"
1657 
1658 /* This was previously in encode, but since out_dxf needs it for r2013+ 3DSOLIDs
1659    and --disable-write is still an option, we need to move it here.
1660    A global acis_data_idx is needed, since encr_acis_data is split into blocks, but
1661    acis_data is a single stream, so we need to keep track of the current position.
1662  */
1663 EXPORT char *
dwg_encrypt_SAT1(BITCODE_BL blocksize,BITCODE_RC * restrict acis_data,int * restrict acis_data_idx)1664 dwg_encrypt_SAT1 (BITCODE_BL blocksize, BITCODE_RC *restrict acis_data,
1665                   int *restrict acis_data_idx)
1666 {
1667   BITCODE_RC* encr_sat_data = (BITCODE_RC*)calloc (blocksize + 1, 1);
1668   int i;
1669   for (i = 0; i < (int)blocksize; i++)
1670     {
1671       if (acis_data[i] <= 32)
1672         encr_sat_data[i] = acis_data[i];
1673       else
1674         encr_sat_data[i] = 159 - acis_data[i];
1675     }
1676   *acis_data_idx = i;
1677   return (char*)encr_sat_data;
1678 }
1679 
1680 static int
new_encr_sat_data_line(Dwg_Entity_3DSOLID * restrict _obj,Bit_Chain * dest,unsigned int i)1681 new_encr_sat_data_line (Dwg_Entity_3DSOLID *restrict _obj,Bit_Chain *dest,
1682                         unsigned int i)
1683 {
1684   /*
1685   if (i + 1 >= _obj->num_blocks)
1686     {
1687       _obj->encr_sat_data = realloc (_obj->encr_sat_data, (i + 2) * sizeof (char*));
1688       _obj->block_size = realloc (_obj->block_size, (i + 2) * sizeof (BITCODE_BL));
1689       _obj->num_blocks = i + 1;
1690     }
1691   _obj->encr_sat_data[i] = calloc (dest->byte + 2, 1); // fresh, the dest buf is too large
1692   bit_write_TF (dest, (BITCODE_TF) "\n\000", 2); // ensure proper eol, dxf out relies on that.
1693   memcpy (_obj->encr_sat_data[i], dest->chain, dest->byte);
1694   _obj->block_size[i] = dest->byte - 1; // dont count the final 0
1695   bit_set_position (dest, 0);
1696   i++;
1697   */
1698   bit_write_TF (dest, (BITCODE_TF) "\n", 1); // ensure proper eol, dxf out relies on that
1699   return i;
1700 }
1701 
1702 // TODO SAT_enum
1703 
1704 // logical values are class-specific, and must be strings.
1705 static const char*
SAT_boolean(const char * act_record,bool value)1706 SAT_boolean (const char *act_record, bool value)
1707 {
1708   static int argc = 0;
1709   if (!strEQc (act_record, "varblendsplsur") &&
1710       !strEQc (act_record, "face") &&
1711       !strEQc (act_record, "bdy_geom"))
1712     argc = 0;
1713 
1714   if (strEQc (act_record, "sphere") ||
1715       strEQc (act_record, "plane") ||
1716       strEQc (act_record, "stripc") ||
1717       strEQc (act_record, "torus"))
1718     return !value ? "forward_v" : "reverse_v";
1719   else if (strEQc (act_record, "spline") ||
1720            strEQc (act_record, "edge") ||
1721            strEQc (act_record, "meshsurf") ||
1722            strEQc (act_record, "pcurve") ||
1723            strEQc (act_record, "intcurve"))
1724     return !value ? "forward" : "reversed";
1725   else if (strEQc (act_record, "surfcur") ||
1726            strEQc (act_record, "bldcur") ||
1727            strEQc (act_record, "parcur") ||
1728            strEQc (act_record, "projcur") ||
1729            strEQc (act_record, "perspsil"))
1730     return !value ? "surf2" : "surf1";
1731   else if (strEQc (act_record, "sweepsur"))
1732     return !value ? "normal" : "angled";
1733   else if (strEQc (act_record, "var_cross_section"))
1734     return value ? "radius" : "no_radius";
1735   else if (strEQc (act_record, "var_radius"))
1736     return value ? "uncalibrated" : "calibrated";
1737   else if (strEQc (act_record, "wire"))
1738     return value ? "in" : "out";
1739   else if (strEQc (act_record, "adv_var_blend"))
1740     return !value ? "sharp" : "smooth";
1741   else if (strEQc (act_record, "attrib_fhlhead"))
1742     return !value ? "invalid" : "valid";
1743   else if (strEQc (act_record, "attrib_fhlplist") ||
1744            strEQc (act_record, "attrib_fhl_slist"))
1745     return !value ? "invisible" : "visible";
1746   else if (strEQc (act_record, "bl_ent_ent") ||
1747            strEQc (act_record, "bl_inst"))
1748     return !value ? "unset" : "set";
1749 
1750   // TODO orthosur undocumented
1751   // now the few classes with mult. locical args
1752   else if (strEQc (act_record, "face"))
1753     {
1754       if (!argc)
1755         {
1756           argc++;
1757           return !value ? "forward" : "reversed";
1758         }
1759       else if (argc == 1)
1760         {
1761           argc++;
1762           return !value ? "single" : "double";
1763         }
1764       else
1765         {
1766           argc = 0;
1767           return !value ? "out" : "in";
1768         }
1769     }
1770   else if (strEQc (act_record, "varblendsplsur"))
1771     {
1772       if (!argc)
1773         {
1774           argc++;
1775           return !value ? "concave" : "convex";
1776         }
1777       else
1778         {
1779           argc = 0;
1780           return !value ? "rb_snapshot" : "rb_envelope";
1781         }
1782     }
1783   else if (strEQc (act_record, "attrib_var_blend"))
1784     {
1785       if (!argc)
1786         {
1787           argc++;
1788           return value ? "uncalibrated" : "calibrated";
1789         }
1790       else if (argc == 1)
1791         {
1792           argc++;
1793           return !value ? "one_radius" : "two_radii";
1794         }
1795       else
1796         {
1797           argc = 0;
1798           return !value ? "forward" : "reversed";
1799         }
1800     }
1801   else if (strEQc (act_record, "bdy_geom"))
1802     {
1803       if (!argc)
1804         {
1805           argc++;
1806           return value ? "non_cross" : "cross";
1807         }
1808       else
1809         {
1810           argc++;
1811           return !value ? "non_smooth" : "smooth";
1812         }
1813     }
1814   else
1815     return value ? "I" : "F";
1816 }
1817 
1818 /* Converts v2 SAB acis_data in-place to SAT v1 encr_sat_data[].
1819    Sets dxf_sab_converted to 1, denoting that encr_sat_data is NOT the
1820    encrypted acis_data anymore, rather the converted from SAB for DXF.
1821 */
1822 EXPORT int
dwg_convert_SAB_to_SAT1(Dwg_Entity_3DSOLID * restrict _obj)1823 dwg_convert_SAB_to_SAT1 (Dwg_Entity_3DSOLID *restrict _obj)
1824 {
1825   Bit_Chain dest = { NULL, 0, 0, 0 };
1826   Bit_Chain src = { NULL, 0, 0, 0 };
1827   unsigned int i = 0, num_blocks = 2;
1828   BITCODE_RC c;
1829   char *p = (char*)&_obj->acis_data[15];
1830   //char *end, *dest, *enddest;
1831   long unsigned int size;
1832   BITCODE_RL version, num_records, num_entities, has_history;
1833   //char *product_string, *acis_version, *date;
1834   BITCODE_RD num_mm_units, resabs, resnor;
1835   // Note that r2013+ has ASM data instead.
1836   // const char enddata[] = "\016\003End\016\002of\016\004ACIS\r\004data";
1837   // const char enddata1[] = "\016\003End\016\002of\016\003ASM\r\004data";
1838   int l = 0;
1839   int forward = 0;
1840   int skip_hist = 0;
1841   char act_record [80];
1842   int error;
1843   // We need dwg->header.version for the target ACIS version.
1844   const Dwg_Object* obj = dwg_obj_generic_to_object (_obj, &error);
1845   const Dwg_Data *dwg = obj ? obj->parent : NULL;
1846   Dwg_Version_Type dwg_version = dwg ? dwg->header.version : R_2000;
1847   // Hack: For DXF dont write n the AcDs vs format. No history, no ASM, early versions.
1848 #ifndef CAN_ACIS_IN_DS_DATA
1849   if (dwg_version >= R_2013)
1850     dwg_version = R_2004;
1851 #endif
1852 
1853   if (_obj->num_blocks)
1854     num_blocks = _obj->num_blocks;
1855   if (!_obj->block_size)
1856     _obj->block_size = calloc (num_blocks, sizeof (BITCODE_BL));
1857   if (!_obj->encr_sat_data)
1858     _obj->encr_sat_data = calloc (num_blocks, sizeof (char *));
1859 
1860   _obj->_dxf_sab_converted = 1;
1861   if (!_obj->sab_size)
1862     _obj->sab_size = _obj->block_size[0];
1863   //end = &p[_obj->sab_size];
1864 
1865   if (!memBEGINc ((char*)_obj->acis_data, "ACIS BinaryFile"))
1866     {
1867       LOG_ERROR ("acis_data is not a SAB 2 'ACIS BinaryFile'");
1868       _obj->num_blocks = 0;
1869       _obj->encr_sat_data[0] = NULL;
1870       return 1;
1871     }
1872   //dest = &_obj->encr_sat_data[0][0];
1873   //enddest = &dest[size];
1874   bit_chain_alloc (&dest);
1875   src.chain = &_obj->acis_data[15];
1876   src.size = _obj->sab_size - 15;
1877 
1878 // header only
1879 #define SAB_RD(key)                                                     \
1880   c = bit_read_RC (&src); /* 6 */                                       \
1881   LOG_HANDLE (#key " [%d] ", c)                                         \
1882   key = bit_read_RD (&src);                                             \
1883   dest.byte += sprintf ((char*)&dest.chain[dest.byte], "%g ", key);     \
1884   LOG_TRACE ("%g ", key)
1885 // record variant
1886 #define SAB_RD1()                                                       \
1887   {                                                                     \
1888     double f = bit_read_RD (&src);                                      \
1889     int s;                                                              \
1890     if (dest.byte + 16 >= dest.size)                                    \
1891       bit_chain_alloc (&dest);                                          \
1892     if (l + 16 > 255)                                                   \
1893       {                                                                 \
1894         bit_write_TF (&dest, (BITCODE_TF) "\n", 1);                     \
1895         LOG_TRACE ("Split overlong SAT line\n");                        \
1896         l = 0;                                                          \
1897       }                                                                 \
1898     s = sprintf ((char*)&dest.chain[dest.byte], "%g ", f);              \
1899     dest.byte += s; l += s;                                             \
1900     LOG_TRACE ("%g ", f);                                               \
1901   }
1902 // key is ignored here. header only
1903 #define SAB_T(key)                                                      \
1904   {                                                                     \
1905     int len, s;                                                         \
1906     c = bit_read_RC (&src);                                             \
1907     LOG_HANDLE (#key " [%d] ", c)                                       \
1908     len = bit_read_RC (&src);                                           \
1909     s = sprintf ((char*)&dest.chain[dest.byte], "%d ", len);            \
1910     dest.byte += s; l += s;                                             \
1911     LOG_TRACE ("%d %.*s ", len, len, &src.chain[src.byte]);             \
1912     bit_write_TF (&dest, &src.chain[src.byte], len);                    \
1913     bit_write_TF (&dest, (BITCODE_TF) " ", 1);                          \
1914     l += len + 1;                                                       \
1915     src.byte += len;                                                    \
1916   }
1917 #define SAB_TF(x)                                                       \
1918   if (l + sizeof(x) > 255)                                              \
1919     {                                                                   \
1920       bit_write_TF (&dest, (BITCODE_TF) "\n", 1);                       \
1921       LOG_TRACE ("Split overlong SAT line\n");                          \
1922       l = 0;                                                            \
1923     }                                                                   \
1924   bit_write_TF (&dest, (BITCODE_TF) x, sizeof (x) - 1);                 \
1925   bit_write_TF (&dest, (BITCODE_TF) " ", 1);                            \
1926   l += sizeof (x);                                                      \
1927   LOG_TRACE ("%s ", x)
1928 #define SAB_TV(x)                                                       \
1929   if (l + strlen (x) > 255)                                             \
1930     {                                                                   \
1931       bit_write_TF (&dest, (BITCODE_TF) "\n", 1);                       \
1932       LOG_TRACE ("Split overlong SAT line\n");                          \
1933       l = 0;                                                            \
1934     }                                                                   \
1935   bit_write_TF (&dest, (BITCODE_TF) x, strlen (x));                     \
1936   bit_write_TF (&dest, (BITCODE_TF) " ", 1);                            \
1937   l += strlen (x) + 1;                                                  \
1938   LOG_TRACE ("%s ", x)
1939 
1940   // create the two vectors encr_sat_data[] and block_size[] on the fly from the SAB
1941   // http://paulbourke.net/dataformats/sat/sat.pdf
1942   /* ACIS BinaryFile [64 81 6x0[ [2 7x0]
1943      "\a\020Autodesk AutoCAD\a\024ASM 223.0.1.1930 OSX\a\030Mon Jun 18 11:09:32 2018\006"
1944      6x0 16 63 "\006\215\355\265\240\367ư>" "\006\273\275\327\331\337|\333= "\r\tasmheader" \f\377\377\377\377\004\377\377\377\377\a\f223.0.1.1930\021 \r\004body \f\377\377\377\377\004\377\377\377\377\f\377\377\377\377\f\002"
1945    */
1946   version = bit_read_RL (&src);
1947   num_records = bit_read_RL (&src);  // if 0 until end marker. total
1948   num_entities = bit_read_RL (&src); // named top in the ACIS docs
1949   has_history = bit_read_RL (&src);  // named as flags in the ACIS docs
1950   LOG_TRACE ("%d %d %d %d \n", version, num_records, num_entities, has_history);
1951 #ifndef CAN_ACIS_HISTORY
1952   if (dwg_version < R_2010)
1953     has_history = 0; // FIXME: need to delete all persubent-acadSolidHistory-attrib lines then.
1954 #endif
1955   if (dwg_version >= R_2013)
1956     version = 21800;
1957   else if (dwg_version >= R_2010)
1958     version = 21500;
1959   else if (dwg_version >= R_2007)
1960     version = 21200;
1961   else if (dwg_version >= R_2004)
1962     version = 20800;
1963   else if (dwg_version >= R_2000)
1964     version = 400;
1965   else if (dwg_version < R_2000)
1966     version = 106;
1967   dest.byte += sprintf ((char*)dest.chain, "%d %d %d %d ", version, num_records,
1968                         num_entities, has_history);
1969   LOG_TRACE ("=> %d %d %d %d \n", version, num_records, num_entities, has_history);
1970   i = new_encr_sat_data_line (_obj, &dest, i);
1971 
1972   SAB_T (product_string)
1973   SAB_T (acis_version)
1974   SAB_T (date)
1975   i = new_encr_sat_data_line (_obj, &dest, i);
1976   LOG_TRACE ("\n");
1977 
1978   SAB_RD (num_mm_units);
1979   SAB_RD (resabs);
1980   SAB_RD (resnor);
1981   i = new_encr_sat_data_line (_obj, &dest, i);
1982   LOG_TRACE ("\n");
1983 
1984   c = bit_read_RC (&src); // type tag
1985   while (src.byte < src.size)
1986     {
1987       LOG_HANDLE ("[%d] ", c)
1988       switch (c)
1989         {
1990         // check size, realloc encr_sat_data[i], set dest
1991         case 17:   //  # end of record
1992           forward = 0;
1993           if (dest.byte + 2 >= dest.size)
1994             bit_chain_alloc (&dest);
1995           if (skip_hist && !has_history)
1996             {
1997               // delete any persubent-acadSolidHistory-attrib line
1998               char *s = strrchr ((char*)dest.chain, '#');
1999               int diff = s ? (char*)&dest.chain[dest.byte] - s : 0;
2000               if (diff > 0 && dest.chain[dest.byte - diff + 1] == '\n')
2001                 {
2002                   dest.byte -= (diff - 2);
2003                 }
2004               LOG_TRACE ("# --deleted--\n");
2005             }
2006           else
2007             {
2008               int s = sprintf ((char*)&dest.chain[dest.byte], "#\n");
2009               dest.byte += s; l += s;
2010               LOG_TRACE ("#\n");
2011             }
2012           //i = new_encr_sat_data_line (_obj, &dest, i);
2013           l = 0;
2014           skip_hist = 0;
2015           break;
2016         case 13:   // ident
2017           _obj->encr_sat_data[i] = (char*)dest.chain;
2018           // fallthru
2019         case 7:  // char len
2020         case 14: // subident
2021           {
2022             int len = bit_read_RC (&src);
2023             if (dest.byte + len + 4 >= dest.size)
2024               bit_chain_alloc (&dest);
2025             if (c == 7 && i < 3)
2026               {
2027                 int s = sprintf ((char*)&dest.chain[dest.byte], "%d ", len);
2028                 dest.byte += s; l += s;
2029                 LOG_TRACE ("%d ", len);
2030               }
2031             LOG_TRACE ("%.*s%s", len, &src.chain[src.byte], c == 14 ? "-" : " ");
2032 #ifndef CAN_ACIS_IN_DS_DATA
2033             // fixup End-of-ASM-data => End-of-ACIS-data if >= r2013
2034             // downconvert ASM (AcDs) to ACIS for DXF
2035             if (len == 3 && c == 14 && !memcmp (&src.chain[src.byte], "ASM", 3))
2036               {
2037                 LOG_TRACE ("=>ACIS-");
2038                 skip_hist = 1;
2039                 bit_write_TF (&dest, (BITCODE_TF)"ACIS", 4);
2040               }
2041             else
2042 #endif
2043               bit_write_TF (&dest, &src.chain[src.byte], len);
2044 #ifndef CAN_ACIS_HISTORY
2045             if (c == 14 && len == strlen ("acadSolidHistory") &&
2046                 !memcmp (&src.chain[src.byte], "acadSolidHistory", len))
2047               {
2048                 skip_hist = 1; // skip the whole line
2049               }
2050 #endif
2051             if (c == 13 && len < 80)
2052               {
2053                 memcpy (act_record, &src.chain[src.byte], len);
2054                 act_record[len] = '\0'; // to find identifier-specific true/false strings
2055               }
2056             // TODO Begin-of-ACIS-History-Data => new line
2057             // TODO End-of-ACIS-History-Section => new line
2058             //if (has_history && c == 13 && len = 4 && memBEGINc (&src.chain[src.byte], "Data"))
2059             //  i = new_encr_sat_data_line (_obj, &dest, i);
2060             src.byte += len;
2061             if (c == 14)
2062               bit_write_TF (&dest, (BITCODE_TF)"-", 1);
2063             else
2064               bit_write_TF (&dest, (BITCODE_TF)" ", 1);
2065             l++;
2066             break;
2067           }
2068         case 8:  // short len
2069           {
2070             int len = bit_read_RS (&src);
2071             if (src.byte + len >= src.size)
2072               {
2073                 LOG_ERROR ("Invalid SAB");
2074                 bit_chain_free (&dest);
2075                 _obj->num_blocks = 0;
2076                 _obj->encr_sat_data[0] = NULL;
2077                 return 1;
2078               }
2079             if (dest.byte + len + 1 >= dest.size)
2080               bit_chain_alloc (&dest);
2081             LOG_TRACE ("%.*s%s", len, &src.chain[src.byte], " ")
2082             bit_write_TF (&dest, &src.chain[src.byte], len);
2083             src.byte += len;
2084             bit_write_TF (&dest, (BITCODE_TF)" ", 1);
2085             l += len + 1;
2086             break;
2087           }
2088         case 9:  // long len
2089           {
2090             int len = bit_read_RL (&src);
2091             if (src.byte + len >= src.size)
2092               {
2093                 LOG_ERROR ("Invalid SAB");
2094                 bit_chain_free (&dest);
2095                 _obj->num_blocks = 0;
2096                 _obj->encr_sat_data[0] = NULL;
2097                 return 1;
2098               }
2099             if (dest.byte + len + 1 >= dest.size)
2100               bit_chain_alloc (&dest);
2101             if (l + len > 255)
2102               {
2103                 bit_write_TF (&dest, (BITCODE_TF) "\n", 1);
2104                 LOG_TRACE ("Split overlong SAT line\n");
2105                 l = 0;
2106               }
2107             LOG_TRACE ("%.*s%s", len, &src.chain[src.byte], " ")
2108             bit_write_TF (&dest, &src.chain[src.byte], len);
2109             src.byte += len;
2110             bit_write_TF (&dest, (BITCODE_TF)" ", 1);
2111             l += len + 1;
2112             break;
2113           }
2114         case 10: // 0 byte TRUE
2115           {
2116             const char *s = SAT_boolean (act_record, 1);
2117             SAB_TV (s);
2118           }
2119           break;
2120         case 11: // 0 byte FALSE
2121           {
2122             const char *s = SAT_boolean (act_record, 0);
2123             SAB_TV (s);
2124           }
2125           break;
2126         case 15: // 0 byte subtype start
2127           SAB_TF ("{");
2128           break;
2129         case 16: // 1 byte subtype end
2130           SAB_TF ("}");
2131           LOG_HANDLE ("[%c] ", src.chain[src.byte]);
2132           //src.byte++;
2133           break;
2134         case 2: // char constant
2135           {
2136             int s;
2137             int8_t ll = (int8_t)bit_read_RC (&src);
2138             if (dest.byte + 4 >= dest.size)
2139               bit_chain_alloc (&dest);
2140             if (l + 3 > 255)
2141               {
2142                 bit_write_TF (&dest, (BITCODE_TF) "\n", 1);
2143                 LOG_TRACE ("Split overlong SAT line\n");
2144                 l = 0;
2145               }
2146             s = sprintf ((char*)&dest.chain[dest.byte], "%" PRId8 " ", ll);
2147             dest.byte += s; l += s;
2148             LOG_TRACE ("%" PRId8 " ", ll)
2149           }
2150           break;
2151         case 3: // short constant
2152           {
2153             int s;
2154             int16_t ll = (int16_t)bit_read_RS (&src);
2155             if (dest.byte + 8 >= dest.size)
2156               bit_chain_alloc (&dest);
2157             s = sprintf ((char*)&dest.chain[dest.byte], "%" PRId16 " ", ll);
2158             dest.byte += s; l += s;
2159             LOG_TRACE ("%" PRId16 " ", ll)
2160           }
2161           break;
2162         case 4:  // long constant
2163         case 21: // enum value. See GH jmplonka/InventorLoader:Acis.py
2164           {
2165             int s;
2166             BITCODE_RLd ll = (BITCODE_RLd)bit_read_RL (&src);
2167             if (dest.byte + 16 >= dest.size)
2168               bit_chain_alloc (&dest);
2169             s = sprintf ((char*)&dest.chain[dest.byte], "$%" PRId32 " ", ll);
2170             dest.byte += s; l += s;
2171             LOG_TRACE ("$%" PRId32 " ", ll)
2172           }
2173           break;
2174         case 5: // float constant
2175           {
2176             int s;
2177             float f = bit_read_RL (&src);
2178             if (dest.byte + 16 >= dest.size)
2179               bit_chain_alloc (&dest);
2180             if (l + 16 > 255)
2181               {
2182                 bit_write_TF (&dest, (BITCODE_TF) "\n", 1);
2183                 LOG_TRACE ("Split overlong SAT line\n");
2184                 l = 0;
2185               }
2186             s = sprintf ((char*)&dest.chain[dest.byte], "%g ", (double)f);
2187             dest.byte += s; l += s;
2188             LOG_TRACE ("%g ", (double)f)
2189           }
2190           break;
2191         case 12: // 4 byte pointer index
2192           {
2193             int s;
2194             BITCODE_RLd ll = (BITCODE_RLd)bit_read_RL (&src);
2195             if (dest.byte + 16 >= dest.size)
2196               bit_chain_alloc (&dest);
2197             if (l + 6 > 255)
2198               {
2199                 bit_write_TF (&dest, (BITCODE_TF) "\n", 1);
2200                 LOG_TRACE ("Split overlong SAT line\n");
2201                 l = 0;
2202               }
2203             s = sprintf ((char*)&dest.chain[dest.byte], "$%" PRId32 " ", ll);
2204             dest.byte += s; l += s;
2205             LOG_TRACE ("$%" PRId32 " ", ll)
2206           }
2207           break;
2208         case 19: // 3x double-float position
2209         case 20: // 3x double-float vector
2210           SAB_RD1();
2211           SAB_RD1();
2212           // fallthru
2213         case 6:  // 8 byte double-float, e.g. in the 2nd header line
2214           SAB_RD1();
2215           break;
2216         //case 22:  // U-V-Vector
2217         //  break;
2218         case 23:  // int64
2219           {
2220             int s;
2221             int64_t i64 = (int64_t)bit_read_RLL (&src);
2222             if (dest.byte + 16 >= dest.size)
2223               bit_chain_alloc (&dest);
2224             if (l + 16 > 255)
2225               {
2226                 bit_write_TF (&dest, (BITCODE_TF) "\n", 1);
2227                 LOG_TRACE ("Split overlong SAT line\n");
2228                 l = 0;
2229               }
2230             s = sprintf ((char*)&dest.chain[dest.byte], "$%" PRId64 " ", i64);
2231             dest.byte += s; l += s;
2232             LOG_TRACE ("$%" PRId64 " ", i64)
2233           }
2234           break;
2235         default:
2236           LOG_ERROR ("Unknown SAB tag %d", c);
2237         }
2238       c = bit_read_RC (&src);
2239     }
2240 
2241   //if (c != 17) // last line didn't end with #, but End-of-ACIS-data or End-of-ASM-data
2242   //  i = new_encr_sat_data_line (_obj, &dest, i);
2243   num_blocks = _obj->num_blocks = 1;
2244   // Nope, keep it. Teigha always adds it, ASM not.
2245   //if (strEQc((char*)&dest.chain[dest.byte-17], "End-of-ACIS-data "))
2246   //  dest.byte -= 17;
2247   bit_write_TF (&dest, (BITCODE_TF)"\n", 1);
2248   size = dest.byte; // total size
2249   {
2250     unsigned long off = 0;
2251     while (size > 4096)
2252       { // chunks of 4096
2253         if (i >= num_blocks) {
2254           _obj->block_size = realloc (_obj->block_size, (i + 2) * sizeof (BITCODE_BL));
2255           _obj->encr_sat_data = realloc (_obj->encr_sat_data, (i + 1) * sizeof (char**));
2256           num_blocks = i + 1;
2257         }
2258         _obj->encr_sat_data[i] = calloc (4096, 1);
2259         memcpy (_obj->encr_sat_data[i], &dest.chain[off], 4096);
2260         _obj->block_size[i] = 4096;
2261         LOG_TRACE ("block_size[%d] = 4096\n", i);
2262         i++;
2263         size -= 4096;
2264         off += 4096;
2265       }
2266     // and the smaller rest
2267     if (i >= num_blocks) {
2268       _obj->block_size = realloc (_obj->block_size, (i + 2) * sizeof (BITCODE_BL));
2269       _obj->encr_sat_data = realloc (_obj->encr_sat_data, (i + 1) * sizeof (char**));
2270       num_blocks = i + 1;
2271     }
2272     _obj->encr_sat_data[i] = calloc (size + 1, 1); // shrink it
2273     memcpy (_obj->encr_sat_data[i], &dest.chain[off], size);
2274     _obj->block_size[i] = size;
2275     LOG_TRACE ("block_size[%d] = %lu\n", i, size);
2276   }
2277   bit_chain_free (&dest);
2278   LOG_TRACE ("\n");
2279   _obj->acis_empty = 0;
2280   _obj->version = 1; // conversion complete
2281 
2282   if (i + 2 >= num_blocks)
2283     _obj->block_size = realloc (_obj->block_size, (i + 2) * sizeof (BITCODE_BL));
2284   _obj->num_blocks = i;
2285   _obj->block_size[i + 1] = 0;
2286   return 0;
2287 }
2288 
2289 /* Add history_id for old version 1 SAT if there's one */
2290 static void
dxf_check_history_id(Bit_Chain * restrict dat,const Dwg_Object * restrict obj,Dwg_Entity_3DSOLID * restrict _obj)2291 dxf_check_history_id (Bit_Chain *restrict dat, const Dwg_Object *restrict obj,
2292                       Dwg_Entity_3DSOLID *restrict _obj)
2293 {
2294   if (!_obj->history_id || !_obj->history_id->absolute_ref)
2295     {
2296       Dwg_Data *dwg = obj->parent;
2297       Dwg_Handle *hdl = NULL;
2298       if (_obj->history_id)
2299         { /* Avoid NULL HDL */
2300           Dwg_Object *o = dwg_ref_object (dwg, _obj->history_id);
2301           if (o)
2302             hdl = &o->handle;
2303         }
2304       if (!hdl)
2305         /* FIXME Just take the first HISTORY_CLASS
2306            TODO Check HISTORY_CLASS.owner (2, 360) */
2307         hdl = dwg_find_first_type_handle (dwg, DWG_TYPE_ACSH_HISTORY_CLASS);
2308       if (hdl)
2309         _obj->history_id = dwg_add_handleref (dwg, 4, hdl->value, obj);
2310       if (_obj->history_id)
2311         LOG_TRACE ("Empty %s.history_id => " FORMAT_REF "\n", obj->name,
2312                   ARGS_REF (_obj->history_id))
2313       else
2314         LOG_WARN ("Empty %s.history_id\n", obj->name)
2315     }
2316 }
2317 
2318 static int
dxf_3dsolid(Bit_Chain * restrict dat,const Dwg_Object * restrict obj,Dwg_Entity_3DSOLID * restrict _obj)2319 dxf_3dsolid (Bit_Chain *restrict dat, const Dwg_Object *restrict obj,
2320              Dwg_Entity_3DSOLID *restrict _obj)
2321 {
2322   BITCODE_BL i;
2323   int error = 0;
2324 
2325   COMMON_ENTITY_HANDLE_DATA;
2326   FIELD_B0 (acis_empty, 290);
2327   if (!FIELD_VALUE (acis_empty))
2328     {
2329       FIELD_B (unknown, 0);
2330       if (FIELD_VALUE (version) == 2)
2331         {
2332           BITCODE_RC *acis_data;
2333           LOG_TRACE ("Convert SAB ACIS BinaryFile v2 to encrypted SAT v1\n");
2334           error |= dwg_convert_SAB_to_SAT1 (_obj);
2335 
2336           for (i = 0; i < FIELD_VALUE (num_blocks); i++)
2337             {
2338               int idx = 0; // here idx is just local, always starting at 0. ignored
2339               char *ptr = dwg_encrypt_SAT1 (
2340                   _obj->block_size[i], (BITCODE_RC *)_obj->encr_sat_data[i],
2341                   &idx);
2342 
2343               free (_obj->encr_sat_data[i]);
2344               _obj->encr_sat_data[i] = ptr;
2345             }
2346           _obj->version = 1; // conversion complete
2347         }
2348       FIELD_BS (version, 70); // always 1
2349       for (i = 0; i < FIELD_VALUE (num_blocks); i++)
2350         {
2351           char *s = FIELD_VALUE (encr_sat_data[i]);
2352           // FIXME
2353           // only DXF 1, always keep len <255
2354           //int len = _obj->_dxf_sab_converted ? FIELD_VALUE (block_size[i]) : strlen (s);
2355           int len = FIELD_VALUE (block_size[i]);
2356           while (len > 0)
2357             {
2358               char *n = strchr (s, '\n');
2359               int l = len > 255 ? 255 : len;
2360               char *caret = strchr (s, '^');
2361               if (n && (n - s < len))
2362                 {
2363                   l = n - s;
2364                 }
2365               if (l)
2366                 {
2367                   GROUP (1);
2368                   // replace "^" by "^ "
2369                   while (caret && caret < n)
2370                     {
2371                       int lc = caret - s;
2372                       fprintf (dat->fh, "%.*s^ ", lc, s);
2373                       lc++;
2374                       l -= lc;
2375                       len -= lc;
2376                       s += lc;
2377                       caret = l > 1 ? strchr (s, '^') : NULL;
2378                     }
2379                   if (l > 255)
2380                     LOG_ERROR ("Overlong SAT line \"%s\" len=%d", s, l)
2381                   if (s[l - 1] == '\r')
2382                     fprintf (dat->fh, "%.*s\n", l, s);
2383                   else
2384                     fprintf (dat->fh, "%.*s\r\n", l, s);
2385                   l++;
2386                   len -= l;
2387                   s += l;
2388                 }
2389               else
2390                 {
2391                   len--;
2392                   s++;
2393                 }
2394             }
2395         }
2396     }
2397   dxf_check_history_id (dat, obj, _obj);
2398   // the rest is done in COMMON_3DSOLID in the spec.
2399   return error;
2400 }
2401 
2402 /* returns 0 on success
2403  */
2404 static int
dwg_dxf_variable_type(const Dwg_Data * restrict dwg,Bit_Chain * restrict dat,Dwg_Object * restrict obj)2405 dwg_dxf_variable_type (const Dwg_Data *restrict dwg, Bit_Chain *restrict dat,
2406                        Dwg_Object *restrict obj)
2407 {
2408   int i;
2409   Dwg_Class *klass;
2410   int is_entity;
2411 
2412   i = obj->type - 500;
2413   if (i < 0 || i >= dwg->num_classes)
2414     return DWG_ERR_INVALIDTYPE;
2415 
2416   klass = &dwg->dwg_class[i];
2417   if (!klass || !klass->dxfname)
2418     return DWG_ERR_INTERNALERROR;
2419   is_entity = dwg_class_is_entity (klass);
2420   if (dat->version < R_2000)
2421     {
2422       // keep only: IMAGE, LWPOLYLINE, HATCH
2423       if (is_entity &&
2424           strNE (klass->dxfname, "IMAGE") &&
2425           strNEc (klass->dxfname, "LWPOLYLINE") &&
2426           strNEc (klass->dxfname, "HATCH"))
2427         {
2428           LOG_WARN ("Skip %s\n", klass->dxfname)
2429           return DWG_ERR_UNHANDLEDCLASS;
2430         }
2431       // keep only: DICTIONARYVAR, MATERIAL, RASTERVARIABLES, IMAGEDEF_REACTOR, XRECORD, IDBUFFER
2432       else if (!is_entity &&
2433                strNEc (klass->dxfname, "DICTIONARYVAR") &&
2434                strNEc (klass->dxfname, "MATERIAL") &&
2435                strNEc (klass->dxfname, "RASTERVARIABLES") &&
2436                strNEc (klass->dxfname, "IDBUFFER") &&
2437                strNEc (klass->dxfname, "IMAGEDEF_REACTOR") &&
2438                strNEc (klass->dxfname, "XRECORD"))
2439         {
2440           LOG_WARN ("Skip %s\n", klass->dxfname)
2441           return DWG_ERR_UNHANDLEDCLASS;
2442         }
2443     }
2444 
2445   // if (!is_entity)
2446   //  fprintf(dat->fh, "  0\r\n%s\r\n", dxfname);
2447 
2448   // clang-format off
2449   #include "classes.inc"
2450   // clang-format on
2451 
2452   return DWG_ERR_UNHANDLEDCLASS;
2453 }
2454 
2455 /* process unsorted vertices until SEQEND */
2456 #define decl_dxf_process_VERTEX(token)                                        \
2457   static int dxf_process_VERTEX_##token (Bit_Chain *restrict dat,             \
2458                                          const Dwg_Object *restrict obj,      \
2459                                          int *restrict i)                     \
2460   {                                                                           \
2461     int error = 0;                                                            \
2462     Dwg_Entity_POLYLINE_##token *_obj                                         \
2463         = obj->tio.entity->tio.POLYLINE_##token;                              \
2464                                                                               \
2465     VERSIONS (R_13, R_2000)                                                   \
2466     {                                                                         \
2467       Dwg_Object *last_vertex = _obj->last_vertex ? _obj->last_vertex->obj : NULL; \
2468       Dwg_Object *o = _obj->first_vertex ? _obj->first_vertex->obj : NULL;    \
2469       if (!o || !last_vertex)                                                 \
2470         return DWG_ERR_INVALIDHANDLE;                                         \
2471       if (o->fixedtype == DWG_TYPE_VERTEX_##token)                            \
2472         error |= dwg_dxf_VERTEX_##token (dat, o);                             \
2473       *i = *i + 1;                                                            \
2474       do                                                                      \
2475         {                                                                     \
2476           o = dwg_next_object (o);                                            \
2477           if (!o)                                                             \
2478             return DWG_ERR_INVALIDHANDLE;                                     \
2479           if (strEQc (#token, "PFACE")                                        \
2480               && o->fixedtype == DWG_TYPE_VERTEX_PFACE_FACE)                  \
2481             {                                                                 \
2482               error |= dwg_dxf_VERTEX_PFACE_FACE (dat, o);                    \
2483             }                                                                 \
2484           else if (o->fixedtype == DWG_TYPE_VERTEX_##token)                   \
2485             {                                                                 \
2486               error |= dwg_dxf_VERTEX_##token (dat, o);                       \
2487             }                                                                 \
2488           *i = *i + 1;                                                        \
2489         }                                                                     \
2490       while (o->fixedtype != DWG_TYPE_SEQEND && o != last_vertex);            \
2491       o = _obj->seqend ? _obj->seqend->obj : NULL;                            \
2492       if (o && o->fixedtype == DWG_TYPE_SEQEND)                               \
2493         error |= dwg_dxf_SEQEND (dat, o);                                     \
2494       *i = *i + 1;                                                            \
2495     }                                                                         \
2496     SINCE (R_2004)                                                            \
2497     {                                                                         \
2498       Dwg_Object *o;                                                          \
2499       for (BITCODE_BL j = 0; j < _obj->num_owned; j++)                        \
2500         {                                                                     \
2501           o = _obj->vertex && _obj->vertex[j] ? _obj->vertex[j]->obj : NULL;  \
2502           if (strEQc (#token, "PFACE") && o                                   \
2503               && o->fixedtype == DWG_TYPE_VERTEX_PFACE_FACE)                  \
2504             {                                                                 \
2505               error |= dwg_dxf_VERTEX_PFACE_FACE (dat, o);                    \
2506             }                                                                 \
2507           else if (o && o->fixedtype == DWG_TYPE_VERTEX_##token)              \
2508             {                                                                 \
2509               error |= dwg_dxf_VERTEX_##token (dat, o);                       \
2510             }                                                                 \
2511         }                                                                     \
2512       o = _obj->seqend ? _obj->seqend->obj : NULL;                            \
2513       if (o && o->fixedtype == DWG_TYPE_SEQEND)                               \
2514         error |= dwg_dxf_SEQEND (dat, o);                                     \
2515       *i = *i + _obj->num_owned + 1;                                          \
2516     }                                                                         \
2517     return error;                                                             \
2518   }
2519 
2520 // clang-format off
2521 decl_dxf_process_VERTEX (2D)
2522 decl_dxf_process_VERTEX (3D)
decl_dxf_process_VERTEX(MESH)2523 decl_dxf_process_VERTEX (MESH)
2524 decl_dxf_process_VERTEX (PFACE)
2525 // clang-format on
2526 
2527 /* process if seqend before attribs */
2528 #define decl_dxf_process_INSERT(token)                                        \
2529   static int dxf_process_##token (Bit_Chain *restrict dat,                    \
2530                                   const Dwg_Object *restrict obj,             \
2531                                   int *restrict i)                            \
2532   {                                                                           \
2533     int error = 0;                                                            \
2534     Dwg_Entity_##token *_obj = obj->tio.entity->tio.token;                    \
2535                                                                               \
2536     if (!_obj->has_attribs)                                                   \
2537         return 0;                                                             \
2538     VERSIONS (R_13, R_2000)                                                   \
2539     {                                                                         \
2540       Dwg_Object *last_attrib                                                 \
2541           = _obj->last_attrib ? _obj->last_attrib->obj : NULL;                \
2542       Dwg_Object *o = _obj->first_attrib ? _obj->first_attrib->obj : NULL;    \
2543       if (!o || !last_attrib)                                                 \
2544         return DWG_ERR_INVALIDHANDLE;                                         \
2545       if (o->fixedtype == DWG_TYPE_ATTRIB)                                    \
2546         error |= dwg_dxf_ATTRIB (dat, o);                                     \
2547       *i = *i + 1;                                                            \
2548       do                                                                      \
2549         {                                                                     \
2550           o = dwg_next_object (o);                                            \
2551           if (!o)                                                             \
2552             return DWG_ERR_INVALIDHANDLE;                                     \
2553           if (o->fixedtype == DWG_TYPE_ATTRIB)                                \
2554             error |= dwg_dxf_ATTRIB (dat, o);                                 \
2555           *i = *i + 1;                                                        \
2556         }                                                                     \
2557       while (o->fixedtype == DWG_TYPE_ATTRIB && o != last_attrib);            \
2558       o = _obj->seqend ? _obj->seqend->obj : NULL;                            \
2559       if (o && o->fixedtype == DWG_TYPE_SEQEND)                               \
2560         error |= dwg_dxf_SEQEND (dat, o);                                     \
2561       *i = *i + 1;                                                            \
2562     }                                                                         \
2563     SINCE (R_2004)                                                            \
2564     {                                                                         \
2565       Dwg_Object *o;                                                          \
2566       for (BITCODE_BL j = 0; j < _obj->num_owned; j++)                        \
2567         {                                                                     \
2568           o = _obj->attribs && _obj->attribs[j]                 \
2569                   ? _obj->attribs[j]->obj                              \
2570                   : NULL;                                                     \
2571           if (o && o->fixedtype == DWG_TYPE_ATTRIB)                           \
2572             error |= dwg_dxf_ATTRIB (dat, o);                                 \
2573         }                                                                     \
2574       o = _obj->seqend ? _obj->seqend->obj : NULL;                            \
2575       if (o && o->fixedtype == DWG_TYPE_SEQEND)                               \
2576         error |= dwg_dxf_SEQEND (dat, o);                                     \
2577       *i = *i + _obj->num_owned + 1;                                          \
2578     }                                                                         \
2579     return error;                                                             \
2580   }
2581 
2582 // clang-format off
2583 decl_dxf_process_INSERT (INSERT)
2584 decl_dxf_process_INSERT (MINSERT)
2585 // clang-format on
2586 
2587 static int dwg_dxf_object (Bit_Chain *restrict dat,
2588                            const Dwg_Object *restrict obj,
2589                            int *restrict i)
2590 {
2591   int error = 0;
2592   int minimal;
2593 
2594   if (!obj || !obj->parent)
2595     return DWG_ERR_INTERNALERROR;
2596   minimal = obj->parent->opts & DWG_OPTS_MINIMAL;
2597 
2598   switch (obj->type)
2599     {
2600     case DWG_TYPE_TEXT:
2601       return dwg_dxf_TEXT (dat, obj);
2602     case DWG_TYPE_ATTDEF:
2603       return dwg_dxf_ATTDEF (dat, obj);
2604     case DWG_TYPE_BLOCK:
2605       return dwg_dxf_BLOCK (dat, obj);
2606     case DWG_TYPE_ENDBLK:
2607       LOG_WARN ("stale %s subentity", obj->dxfname);
2608       return 0; // dwg_dxf_ENDBLK(dat, obj);
2609     case DWG_TYPE_SEQEND:
2610       LOG_WARN ("stale %s subentity", obj->dxfname);
2611       return 0; // dwg_dxf_SEQEND(dat, obj);
2612 
2613     case DWG_TYPE_INSERT:
2614       error = dwg_dxf_INSERT (dat, obj);
2615       return error | dxf_process_INSERT (dat, obj, i);
2616     case DWG_TYPE_MINSERT:
2617       error = dwg_dxf_MINSERT (dat, obj);
2618       return error | dxf_process_MINSERT (dat, obj, i);
2619     case DWG_TYPE_POLYLINE_2D:
2620       error = dwg_dxf_POLYLINE_2D (dat, obj);
2621       return error | dxf_process_VERTEX_2D (dat, obj, i);
2622     case DWG_TYPE_POLYLINE_3D:
2623       error = dwg_dxf_POLYLINE_3D (dat, obj);
2624       return error | dxf_process_VERTEX_3D (dat, obj, i);
2625     case DWG_TYPE_POLYLINE_PFACE:
2626       error = dwg_dxf_POLYLINE_PFACE (dat, obj);
2627       return error | dxf_process_VERTEX_PFACE (dat, obj, i);
2628     case DWG_TYPE_POLYLINE_MESH:
2629       error = dwg_dxf_POLYLINE_MESH (dat, obj);
2630       return error | dxf_process_VERTEX_MESH (dat, obj, i);
2631 
2632     case DWG_TYPE_ATTRIB:
2633       LOG_WARN ("stale %s subentity", obj->dxfname);
2634       return dwg_dxf_ATTRIB (dat, obj);
2635     case DWG_TYPE_VERTEX_2D:
2636       LOG_WARN ("stale %s subentity", obj->dxfname);
2637       return dwg_dxf_VERTEX_2D (dat, obj);
2638     case DWG_TYPE_VERTEX_3D:
2639       LOG_WARN ("stale %s subentity", obj->dxfname);
2640       return dwg_dxf_VERTEX_3D (dat, obj);
2641     case DWG_TYPE_VERTEX_MESH:
2642       LOG_WARN ("stale %s subentity", obj->dxfname);
2643       return dwg_dxf_VERTEX_MESH (dat, obj);
2644     case DWG_TYPE_VERTEX_PFACE:
2645       LOG_WARN ("stale %s subentity", obj->dxfname);
2646       return dwg_dxf_VERTEX_PFACE (dat, obj);
2647     case DWG_TYPE_VERTEX_PFACE_FACE:
2648       LOG_WARN ("stale %s subentity", obj->dxfname);
2649       return dwg_dxf_VERTEX_PFACE_FACE (dat, obj);
2650 
2651     case DWG_TYPE_ARC:
2652       return dwg_dxf_ARC (dat, obj);
2653     case DWG_TYPE_CIRCLE:
2654       return dwg_dxf_CIRCLE (dat, obj);
2655     case DWG_TYPE_LINE:
2656       return dwg_dxf_LINE (dat, obj);
2657     case DWG_TYPE_DIMENSION_ORDINATE:
2658       return dwg_dxf_DIMENSION_ORDINATE (dat, obj);
2659     case DWG_TYPE_DIMENSION_LINEAR:
2660       return dwg_dxf_DIMENSION_LINEAR (dat, obj);
2661     case DWG_TYPE_DIMENSION_ALIGNED:
2662       return dwg_dxf_DIMENSION_ALIGNED (dat, obj);
2663     case DWG_TYPE_DIMENSION_ANG3PT:
2664       return dwg_dxf_DIMENSION_ANG3PT (dat, obj);
2665     case DWG_TYPE_DIMENSION_ANG2LN:
2666       return dwg_dxf_DIMENSION_ANG2LN (dat, obj);
2667     case DWG_TYPE_DIMENSION_RADIUS:
2668       return dwg_dxf_DIMENSION_RADIUS (dat, obj);
2669     case DWG_TYPE_DIMENSION_DIAMETER:
2670       return dwg_dxf_DIMENSION_DIAMETER (dat, obj);
2671     case DWG_TYPE_POINT:
2672       return dwg_dxf_POINT (dat, obj);
2673     case DWG_TYPE__3DFACE:
2674       return dwg_dxf__3DFACE (dat, obj);
2675     case DWG_TYPE_SOLID:
2676       return dwg_dxf_SOLID (dat, obj);
2677     case DWG_TYPE_TRACE:
2678       return dwg_dxf_TRACE (dat, obj);
2679     case DWG_TYPE_SHAPE:
2680       return dwg_dxf_SHAPE (dat, obj);
2681     case DWG_TYPE_VIEWPORT:
2682       return minimal ? 0 : dwg_dxf_VIEWPORT (dat, obj);
2683     case DWG_TYPE_ELLIPSE:
2684       return dwg_dxf_ELLIPSE (dat, obj);
2685     case DWG_TYPE_SPLINE:
2686       return dwg_dxf_SPLINE (dat, obj);
2687     case DWG_TYPE_REGION:
2688       return dwg_dxf_REGION (dat, obj);
2689     case DWG_TYPE__3DSOLID:
2690       return dwg_dxf__3DSOLID (dat, obj);
2691     case DWG_TYPE_BODY:
2692       return dwg_dxf_BODY (dat, obj);
2693     case DWG_TYPE_RAY:
2694       return dwg_dxf_RAY (dat, obj);
2695     case DWG_TYPE_XLINE:
2696       return dwg_dxf_XLINE (dat, obj);
2697     case DWG_TYPE_DICTIONARY:
2698       return minimal ? 0 : dwg_dxf_DICTIONARY (dat, obj);
2699     case DWG_TYPE_MTEXT:
2700       return dwg_dxf_MTEXT (dat, obj);
2701     case DWG_TYPE_LEADER:
2702       return dwg_dxf_LEADER (dat, obj);
2703     case DWG_TYPE_TOLERANCE:
2704       return dwg_dxf_TOLERANCE (dat, obj);
2705     case DWG_TYPE_MLINE:
2706 #if 1 || defined DEBUG_CLASSES
2707       // TODO: looks good, but acad import crashes
2708       return dwg_dxf_MLINE (dat, obj);
2709 #else
2710       LOG_WARN ("Unhandled Entity MLINE in out_dxf %u/%lX", obj->index,
2711                 obj->handle.value)
2712       if (0) dwg_dxf_MLINE (dat, obj);
2713       return DWG_ERR_UNHANDLEDCLASS;
2714 #endif
2715     case DWG_TYPE_BLOCK_CONTROL:
2716     case DWG_TYPE_BLOCK_HEADER:
2717     case DWG_TYPE_LAYER_CONTROL:
2718     case DWG_TYPE_LAYER:
2719     case DWG_TYPE_STYLE_CONTROL:
2720     case DWG_TYPE_STYLE:
2721     case DWG_TYPE_LTYPE_CONTROL:
2722     case DWG_TYPE_LTYPE:
2723     case DWG_TYPE_VIEW_CONTROL:
2724     case DWG_TYPE_VIEW:
2725     case DWG_TYPE_UCS_CONTROL:
2726     case DWG_TYPE_UCS:
2727     case DWG_TYPE_VPORT_CONTROL:
2728     case DWG_TYPE_VPORT:
2729     case DWG_TYPE_APPID_CONTROL:
2730     case DWG_TYPE_APPID:
2731     case DWG_TYPE_DIMSTYLE_CONTROL:
2732     case DWG_TYPE_DIMSTYLE:
2733     case DWG_TYPE_VX_CONTROL:
2734     case DWG_TYPE_VX_TABLE_RECORD:
2735       break;
2736     case DWG_TYPE_GROUP:
2737       return dwg_dxf_GROUP (dat, obj);
2738     case DWG_TYPE_MLINESTYLE:
2739       return minimal ? 0 : dwg_dxf_MLINESTYLE (dat, obj);
2740     case DWG_TYPE_OLE2FRAME:
2741       return minimal ? 0 : dwg_dxf_OLE2FRAME (dat, obj);
2742     case DWG_TYPE_DUMMY:
2743       return 0;
2744     case DWG_TYPE_LONG_TRANSACTION:
2745       return minimal ? 0 : dwg_dxf_LONG_TRANSACTION (dat, obj);
2746     case DWG_TYPE_LWPOLYLINE:
2747       return dwg_dxf_LWPOLYLINE (dat, obj);
2748     case DWG_TYPE_HATCH:
2749       return dwg_dxf_HATCH (dat, obj);
2750     case DWG_TYPE_XRECORD:
2751       return minimal ? 0 : dwg_dxf_XRECORD (dat, obj);
2752     case DWG_TYPE_PLACEHOLDER:
2753       return minimal ? 0 : dwg_dxf_PLACEHOLDER (dat, obj);
2754     case DWG_TYPE_PROXY_ENTITY:
2755        // avoid unused warnings
2756       error |= dwg_dxf_PROXY_ENTITY(dat, obj);
2757       return DWG_ERR_UNHANDLEDCLASS;
2758     case DWG_TYPE_OLEFRAME:
2759       return minimal ? 0 : dwg_dxf_OLEFRAME (dat, obj);
2760     case DWG_TYPE_VBA_PROJECT:
2761       return minimal ? 0 : dwg_dxf_VBA_PROJECT (dat, obj);
2762     case DWG_TYPE_LAYOUT:
2763       return minimal ? 0 : dwg_dxf_LAYOUT (dat, obj);
2764     default:
2765       if (obj->type == obj->parent->layout_type)
2766         {
2767           return minimal ? 0 : dwg_dxf_LAYOUT (dat, obj);
2768         }
2769       /* > 500 */
2770       else if ((error
2771                 = dwg_dxf_variable_type (obj->parent, dat, (Dwg_Object *)obj))
2772                & DWG_ERR_UNHANDLEDCLASS)
2773         {
2774           Dwg_Data *dwg = obj->parent;
2775           int j = obj->type - 500;
2776           Dwg_Class *klass = NULL;
2777 
2778           if (j >= 0 && j < (int)dwg->num_classes)
2779             klass = &dwg->dwg_class[j];
2780           if (!klass)
2781             {
2782               LOG_WARN ("Unknown object, skipping eed/reactors/xdic");
2783               return DWG_ERR_INVALIDTYPE;
2784             }
2785           return error;
2786         }
2787     }
2788   return DWG_ERR_UNHANDLEDCLASS;
2789 }
2790 
2791 static int
dxf_common_entity_handle_data(Bit_Chain * restrict dat,const Dwg_Object * restrict obj)2792 dxf_common_entity_handle_data (Bit_Chain *restrict dat,
2793                                const Dwg_Object *restrict obj)
2794 {
2795   const Dwg_Data *dwg = obj->parent;
2796   const Dwg_Object_Entity *ent = obj->tio.entity;
2797   const Dwg_Object_Entity *_obj = ent;
2798   int error = 0;
2799   BITCODE_BL vcount = 0;
2800 
2801   // clang-format off
2802   #include "common_entity_handle_data.spec"
2803   #include "common_entity_data.spec"
2804   // clang-format on
2805 
2806   return error;
2807 }
2808 
2809 RETURNS_NONNULL
2810 const char *
dxf_format(int code)2811 dxf_format (int code)
2812 {
2813   if (0 <= code && code < 5)
2814     return "%s";
2815   if (code == 5 || code == -5)
2816     return "%lX";
2817   if (5 < code && code < 10)
2818     return "%s";
2819   if (code < 60)
2820     return DXF_FORMAT_FLT;
2821   if (code < 80)
2822     return "%6i";
2823   if (80 <= code && code <= 99) // BL int32 lgtm [cpp/constant-comparison]
2824     return "%9li";
2825   if (code == 100)
2826     return "%s";
2827   if (code == 102)
2828     return "%s";
2829   if (code == 105)
2830     return "%lX";
2831   if (110 <= code && code <= 149)
2832     return DXF_FORMAT_FLT;
2833   if (160 <= code && code <= 169)
2834     return "%12li";
2835   if (170 <= code && code <= 179)
2836     return "%6i";
2837   if (210 <= code && code <= 239)
2838     return DXF_FORMAT_FLT;
2839   if (270 <= code && code <= 289)
2840     return "%6i";
2841   if (290 <= code && code <= 299)
2842     return "%6i"; // boolean
2843   if (300 <= code && code <= 319)
2844     return "%s";
2845   if (320 <= code && code <= 369)
2846     return "%lX";
2847   if (370 <= code && code <= 389)
2848     return "%6i";
2849   if (390 <= code && code <= 399)
2850     return "%lX";
2851   if (400 <= code && code <= 409)
2852     return "%6i";
2853   if (410 <= code && code <= 419)
2854     return "%s";
2855   if (420 <= code && code <= 429)
2856     return "%9li"; // int32_t
2857   if (430 <= code && code <= 439)
2858     return "%s";
2859   if (440 <= code && code <= 449)
2860     return "%9li"; // int32_t
2861   if (450 <= code && code <= 459)
2862     return "%12li"; // long
2863   if (460 <= code && code <= 469)
2864     return DXF_FORMAT_FLT;
2865   if (470 <= code && code <= 479)
2866     return "%s";
2867   if (480 <= code && code <= 481)
2868     return "%lX";
2869   if (code == 999)
2870     return "%s";
2871   if (1000 <= code && code <= 1009)
2872     return "%s";
2873   if (1010 <= code && code <= 1059)
2874     return DXF_FORMAT_FLT;
2875   if (1060 <= code && code <= 1070)
2876     return "%6i";
2877   if (code == 1071)
2878     return "%9li"; // int32_t
2879   if (code == 1002) // string => RC
2880     return "%6i";
2881   if (code == 1003) // RL layer
2882     return "%9li";
2883   if (code > 1000)
2884     return dxf_format (code - 1000);
2885 
2886   return "(unknown code)";
2887 }
2888 
2889 /* num => string. for the reverse see in_dxf.c:dxf_fixup_header()
2890    TODO: maybe use a table.
2891  */
2892 RETURNS_NONNULL
2893 const char *
dxf_codepage(int code,Dwg_Data * dwg)2894 dxf_codepage (int code, Dwg_Data *dwg)
2895 {
2896   if (code == 30 || code == 0)
2897     return "ANSI_1252"; // WesternEurope Windows
2898   else if (code == 1)
2899     return "US_ASCII";
2900   else if (code == 2)
2901     return "ISO-8859-1"; // WesternEurope Latin-1
2902   else if (code == 3)
2903     return "ISO-8859-2"; // MiddleEurope Latin-2
2904   else if (code == 4)
2905     return "ISO-8859-3"; // SouthEurope Latin-3
2906   else if (code == 5)
2907     return "ISO-8859-4"; // NorthEurope Latin-4
2908   else if (code == 6)
2909     return "ISO-8859-5"; // Cyrillic
2910   else if (code == 7)
2911     return "ISO-8859-6"; // Arabic
2912   else if (code == 8)
2913     return "ISO-8859-7"; // Greek
2914   else if (code == 9)
2915     return "ISO-8859-8"; // Hebrew
2916   else if (code == 10)
2917     return "ISO-8859-9"; // Turkish Latin-5
2918   else if (code == 11)
2919     return "CP437";     // DOS-US, DOS Latin US
2920   else if (code == 12)
2921     return "CP850";     // WesternEurope DOS
2922   else if (code == 13)
2923     return "CP852";     // CentralEurope DOS
2924   else if (code == 14)
2925     return "CP855";     // Cyrillic DOS
2926   else if (code == 15)
2927     return "CP857";     // Turkish DOS
2928   else if (code == 16)
2929     return "CP860";     // Portuguese DOS
2930   else if (code == 17)
2931     return "CP861";     // Icelandic DOS
2932   else if (code == 18)
2933     return "CP863";     // French DOS
2934   else if (code == 19)
2935     return "CP864";     // Arabic DOS
2936   else if (code == 20)
2937     return "CP865";     // Nordic DOS
2938   else if (code == 21)
2939     return "CP869";     // Greek DOS
2940   else if (code == 22)
2941     return "CP932";     // Japanese Shift JIS DOS
2942   else if (code == 23)
2943     return "MACINTOSH";
2944   else if (code == 24)
2945     return "BIG5";      // Taiwan DOS
2946   else if (code == 25)
2947     return "CP949";     // Korean UnifiedHangulCode DOS
2948   else if (code == 26)
2949     return "JOHAB";     // Korean cp1361 DOS
2950   else if (code == 27)
2951     return "CP866";     // Russian DOS
2952   else if (code == 28)
2953     return "ANSI_1250"; // CentralEurope Windows
2954   else if (code == 29)
2955     return "ANSI_1251"; // Cyrillic Windows
2956   else if (code == 31)
2957     return "GB2312";    // SimplifiedChinese
2958   else if (code == 32)
2959     return "ANSI_1253"; // Greek Windows
2960   else if (code == 33)
2961     return "ANSI_1254"; // Turkish Windows
2962   else if (code == 34)
2963     return "ANSI_1255"; // Hebrew Windows
2964   else if (code == 35)
2965     return "ANSI_1256"; // Arabic Windows
2966   else if (code == 36)
2967     return "ANSI_1257"; // Baltic Windows
2968   else if (code == 37)
2969     return "ANSI_874"; // Thai Windows
2970   else if (code == 38)
2971     return "ANSI_932"; // Japanese Windows
2972   else if (code == 39)
2973     return "ANSI_936"; // gbk UnifiedChinese Windows
2974   else if (code == 40)
2975     return "ANSI_949"; // Korean Windows
2976   else if (code == 41)
2977     return "ANSI_950"; // TradChinese Windows
2978   else if (code == 42)
2979     return "ANSI_1361"; // Korean JOHAB Windows
2980   else if (code == 43)
2981     return "ANSI_1200"; // UTF-16 LE Microsoft
2982   else if (code == 44)
2983     return "ANSI_1258"; // Vietnamese Windows
2984   else if (dwg->header.version >= R_2007)
2985     return "UTF-8"; // dwg internally: UCS-16, for DXF: UTF-8
2986   else
2987     return "";
2988 }
2989 
2990 // see
2991 // https://www.autodesk.com/techpubs/autocad/acad2000/dxf/header_section_group_codes_dxf_02.htm
2992 GCC30_DIAG_IGNORE (-Wformat-nonliteral)
2993 AFL_GCC_TOOBIG
2994 static int
dxf_header_write(Bit_Chain * restrict dat,Dwg_Data * restrict dwg)2995 dxf_header_write (Bit_Chain *restrict dat, Dwg_Data *restrict dwg)
2996 {
2997   Dwg_Header_Variables *_obj = &dwg->header_vars;
2998   Dwg_Object *obj = NULL;
2999   double ms;
3000   const int minimal = dwg->opts & DWG_OPTS_MINIMAL;
3001   const char *codepage = dxf_codepage (dwg->header.codepage, dwg);
3002 
3003   if (!*codepage)
3004     {
3005       LOG_WARN ("Unknown codepage %d, assuming ANSI_1252",
3006                 dwg->header.codepage);
3007     }
3008 
3009   // clang-format off
3010   #include "header_variables_dxf.spec"
3011   // clang-format on
3012 
3013   return 0;
3014 }
3015 AFL_GCC_POP
3016 
3017 // only called since r2000. but not really needed, unless referenced
3018 static int
dxf_classes_write(Bit_Chain * restrict dat,Dwg_Data * restrict dwg)3019 dxf_classes_write (Bit_Chain *restrict dat, Dwg_Data *restrict dwg)
3020 {
3021   BITCODE_BS j;
3022 
3023   SECTION (CLASSES);
3024   LOG_TRACE ("num_classes: %u\n", dwg->num_classes);
3025   for (j = 0; j < dwg->num_classes; j++)
3026     {
3027       const char *dxfname = dwg->dwg_class[j].dxfname;
3028       if (!dxfname)
3029         continue;
3030       // some classes are now builtin
3031       if (dat->version >= R_2004
3032           && (strEQc (dxfname, "ACDBPLACEHOLDER")
3033               || strEQc (dxfname, "LAYOUT")))
3034         continue;
3035       if (strEQc (dxfname, "DATATABLE"))
3036         dxfname = "ACDBDATATABLE";
3037       RECORD (CLASS);
3038       VALUE_TV (dxfname, 1);
3039       VALUE_T (dwg->dwg_class[j].cppname, 2);
3040       if (strEQc (dxfname, "SPATIAL_INDEX"))
3041         VALUE_TFF ("AutoCAD 2000", 3) // special-cased for DXF
3042       else
3043         VALUE_T (dwg->dwg_class[j].appname, 3)
3044       VALUE_RL (dwg->dwg_class[j].proxyflag, 90);
3045       SINCE (R_2004) {
3046         VALUE_RL (dwg->dwg_class[j].num_instances, 91);
3047       }
3048       VALUE_RS (dwg->dwg_class[j].is_zombie, 280); // acad: was-a-zombie
3049       // Is-an-entity. 1f2 for entities, 1f3 for objects
3050       VALUE_RS (dwg->dwg_class[j].item_class_id == 0x1F2 ? 1 : 0, 281);
3051     }
3052   ENDSEC ();
3053   return 0;
3054 }
3055 
3056 static int
dxf_tables_write(Bit_Chain * restrict dat,Dwg_Data * restrict dwg)3057 dxf_tables_write (Bit_Chain *restrict dat, Dwg_Data *restrict dwg)
3058 {
3059   int error = 0;
3060   unsigned int i;
3061   BITCODE_BL vcount;
3062 
3063   SECTION (TABLES);
3064   SINCE (R_9c1)
3065   {
3066     Dwg_Object *ctrl = dwg_get_first_object (dwg, DWG_TYPE_VPORT_CONTROL);
3067     if (ctrl && ctrl->tio.object && ctrl->tio.object->tio.VPORT_CONTROL)
3068       {
3069         Dwg_Object_VPORT_CONTROL *_ctrl = ctrl->tio.object->tio.VPORT_CONTROL;
3070         Dwg_Object *obj = ctrl;
3071         TABLE (VPORT);
3072         // add handle 5 here at first
3073         COMMON_TABLE_CONTROL_FLAGS;
3074         error |= dwg_dxf_VPORT_CONTROL (dat, ctrl);
3075         // TODO how far back can DXF read 1000?
3076         if (dat->version != dat->from_version && dat->from_version >= R_2000)
3077           {
3078             /* if saved from newer version, eg. AC1032: */
3079             VALUE_TV ("ACAD", 1001);
3080             VALUE_TV ("DbSaveVer", 1000);
3081             VALUE_RS (dwg->header.dwg_version, 1071); // so that 69 is R_2018
3082           }
3083         for (i = 0; i < _ctrl->num_entries; i++)
3084           {
3085             if (!_ctrl->entries)
3086               break;
3087             if (!_ctrl->entries[i])
3088               continue;
3089             obj = dwg_ref_object (dwg, _ctrl->entries[i]);
3090             if (obj && obj->type == DWG_TYPE_VPORT)
3091               {
3092                 // reordered in the DXF: 2,70,10,11,12,13,14,15,16,...
3093                 // special-cased in the spec
3094                 error |= dwg_dxf_VPORT (dat, obj);
3095               }
3096           }
3097         ENDTAB ();
3098       }
3099   }
3100   {
3101     Dwg_Object *ctrl = dwg_get_first_object (dwg, DWG_TYPE_LTYPE_CONTROL);
3102     if (ctrl && ctrl->tio.object && ctrl->tio.object->tio.LTYPE_CONTROL)
3103       {
3104         Dwg_Object_LTYPE_CONTROL *_ctrl = ctrl->tio.object->tio.LTYPE_CONTROL;
3105         Dwg_Object *obj = ctrl;
3106         TABLE (LTYPE);
3107         COMMON_TABLE_CONTROL_FLAGS;
3108         error |= dwg_dxf_LTYPE_CONTROL (dat, ctrl);
3109         // first the 2 builtin ltypes: ByBlock, ByLayer
3110         if ((obj = dwg_ref_object (dwg, dwg->header_vars.LTYPE_BYBLOCK))
3111             && obj->type == DWG_TYPE_LTYPE)
3112           {
3113             error |= dwg_dxf_LTYPE (dat, obj);
3114           }
3115         if ((obj = dwg_ref_object (dwg, dwg->header_vars.LTYPE_BYLAYER))
3116             && obj->type == DWG_TYPE_LTYPE)
3117           {
3118             error |= dwg_dxf_LTYPE (dat, obj);
3119           }
3120         // here LTYPE_CONTINUOUS is already included
3121         for (i = 0; i < _ctrl->num_entries; i++)
3122           {
3123             if (!_ctrl->entries)
3124               break;
3125             if (!_ctrl->entries[i])
3126               continue;
3127             obj = dwg_ref_object (dwg, _ctrl->entries[i]);
3128             if (obj && obj->type == DWG_TYPE_LTYPE)
3129               {
3130                 error |= dwg_dxf_LTYPE (dat, obj);
3131               }
3132           }
3133         ENDTAB ();
3134       }
3135   }
3136   {
3137     Dwg_Object *ctrl = dwg_get_first_object (dwg, DWG_TYPE_LAYER_CONTROL);
3138     if (ctrl && ctrl->tio.object && ctrl->tio.object->tio.LAYER_CONTROL)
3139       {
3140         Dwg_Object_LAYER_CONTROL *_ctrl = ctrl->tio.object->tio.LAYER_CONTROL;
3141         Dwg_Object *obj = ctrl;
3142         TABLE (LAYER);
3143         COMMON_TABLE_CONTROL_FLAGS;
3144         error |= dwg_dxf_LAYER_CONTROL (dat, ctrl);
3145         for (i = 0; i < _ctrl->num_entries; i++)
3146           {
3147             if (!_ctrl->entries)
3148               break;
3149             if (!_ctrl->entries[i])
3150               continue;
3151             obj = dwg_ref_object (dwg, _ctrl->entries[i]);
3152             if (obj && obj->type == DWG_TYPE_LAYER)
3153               error |= dwg_dxf_LAYER (dat, obj);
3154             // else if (obj && obj->type == DWG_TYPE_DICTIONARY)
3155             //  error |= dwg_dxf_DICTIONARY(dat, obj);
3156           }
3157         ENDTAB ();
3158       }
3159   }
3160   {
3161     Dwg_Object *ctrl = dwg_get_first_object (dwg, DWG_TYPE_STYLE_CONTROL);
3162     if (ctrl && ctrl->tio.object && ctrl->tio.object->tio.STYLE_CONTROL)
3163       {
3164         Dwg_Object_STYLE_CONTROL *_ctrl = ctrl->tio.object->tio.STYLE_CONTROL;
3165         Dwg_Object *obj = ctrl;
3166         TABLE (STYLE);
3167         COMMON_TABLE_CONTROL_FLAGS;
3168         error |= dwg_dxf_STYLE_CONTROL (dat, ctrl);
3169         for (i = 0; i < _ctrl->num_entries; i++)
3170           {
3171             if (!_ctrl->entries)
3172               break;
3173             if (!_ctrl->entries[i])
3174               continue;
3175             obj = dwg_ref_object (dwg, _ctrl->entries[i]);
3176             if (obj && obj->type == DWG_TYPE_STYLE)
3177               {
3178                 error |= dwg_dxf_STYLE (dat, obj);
3179               }
3180           }
3181         ENDTAB ();
3182       }
3183   }
3184   {
3185     Dwg_Object *ctrl = dwg_get_first_object (dwg, DWG_TYPE_VIEW_CONTROL);
3186     if (ctrl && ctrl->tio.object && ctrl->tio.object->tio.VIEW_CONTROL)
3187       {
3188         Dwg_Object_VIEW_CONTROL *_ctrl = ctrl->tio.object->tio.VIEW_CONTROL;
3189         Dwg_Object *obj = ctrl;
3190         TABLE (VIEW);
3191         COMMON_TABLE_CONTROL_FLAGS;
3192         error |= dwg_dxf_VIEW_CONTROL (dat, ctrl);
3193         for (i = 0; i < _ctrl->num_entries; i++)
3194           {
3195             if (!_ctrl->entries)
3196               break;
3197             if (!_ctrl->entries[i])
3198               continue;
3199             obj = dwg_ref_object (dwg, _ctrl->entries[i]);
3200             if (obj && obj->type == DWG_TYPE_VIEW)
3201               error |= dwg_dxf_VIEW (dat, obj);
3202           }
3203         ENDTAB ();
3204       }
3205   }
3206   SINCE (R_9c1)
3207   {
3208     Dwg_Object *ctrl = dwg_get_first_object (dwg, DWG_TYPE_UCS_CONTROL);
3209     if (ctrl && ctrl->tio.object && ctrl->tio.object->tio.UCS_CONTROL)
3210       {
3211         Dwg_Object_UCS_CONTROL *_ctrl = ctrl->tio.object->tio.UCS_CONTROL;
3212         Dwg_Object *obj = ctrl;
3213         TABLE (UCS);
3214         COMMON_TABLE_CONTROL_FLAGS;
3215         error |= dwg_dxf_UCS_CONTROL (dat, ctrl);
3216         for (i = 0; i < _ctrl->num_entries; i++)
3217           {
3218             if (!_ctrl->entries)
3219               break;
3220             if (!_ctrl->entries[i])
3221               continue;
3222             obj = dwg_ref_object (dwg, _ctrl->entries[i]);
3223             if (obj && obj->type == DWG_TYPE_UCS)
3224               {
3225                 error |= dwg_dxf_UCS (dat, obj);
3226               }
3227           }
3228         ENDTAB ();
3229       }
3230   }
3231   SINCE (R_10c1)
3232   {
3233     Dwg_Object *ctrl = dwg_get_first_object (dwg, DWG_TYPE_APPID_CONTROL);
3234     if (ctrl && ctrl->tio.object && ctrl->tio.object->tio.APPID_CONTROL)
3235       {
3236         Dwg_Object_APPID_CONTROL *_ctrl = ctrl->tio.object->tio.APPID_CONTROL;
3237         Dwg_Object *obj = ctrl;
3238         TABLE (APPID);
3239         COMMON_TABLE_CONTROL_FLAGS;
3240         error |= dwg_dxf_APPID_CONTROL (dat, ctrl);
3241         for (i = 0; i < _ctrl->num_entries; i++)
3242           {
3243             if (!_ctrl->entries)
3244               break;
3245             if (!_ctrl->entries[i])
3246               continue;
3247             obj = dwg_ref_object (dwg, _ctrl->entries[i]);
3248             if (obj && obj->type == DWG_TYPE_APPID)
3249               {
3250                 error |= dwg_dxf_APPID (dat, obj);
3251               }
3252           }
3253         ENDTAB ();
3254       }
3255   }
3256   SINCE (R_10c1)
3257   {
3258     Dwg_Object *ctrl = dwg_get_first_object (dwg, DWG_TYPE_DIMSTYLE_CONTROL);
3259     if (ctrl && ctrl->tio.object && ctrl->tio.object->tio.DIMSTYLE_CONTROL)
3260       {
3261         Dwg_Object_DIMSTYLE_CONTROL *_ctrl = ctrl->tio.object->tio.DIMSTYLE_CONTROL;
3262         Dwg_Object *obj = ctrl;
3263         TABLE (DIMSTYLE);
3264         COMMON_TABLE_CONTROL_FLAGS;
3265         error |= dwg_dxf_DIMSTYLE_CONTROL (dat, ctrl);
3266         // ignoring morehandles
3267         for (i = 0; i < _ctrl->num_entries; i++)
3268           {
3269             if (!_ctrl->entries)
3270               break;
3271             if (!_ctrl->entries[i])
3272               continue;
3273             obj = dwg_ref_object (dwg, _ctrl->entries[i]);
3274             if (obj && obj->type == DWG_TYPE_DIMSTYLE)
3275               {
3276                 error |= dwg_dxf_DIMSTYLE (dat, obj);
3277               }
3278           }
3279         ENDTAB ();
3280       }
3281   }
3282   // fool the warnings. this table is nowhere to be found in the wild. maybe pre-R_11
3283   if (0)
3284     {
3285       Dwg_Object *ctrl = dwg_get_first_object (dwg, DWG_TYPE_VX_CONTROL);
3286       if (ctrl)
3287         {
3288           Dwg_Object_VX_CONTROL *_ctrl = ctrl->tio.object->tio.VX_CONTROL;
3289           Dwg_Object *obj = ctrl;
3290           TABLE (VX);
3291           COMMON_TABLE_CONTROL_FLAGS;
3292           error |= dwg_dxf_VX_CONTROL (dat, ctrl);
3293           for (i = 0; i < _ctrl->num_entries; i++)
3294             {
3295               if (!_ctrl->entries)
3296                 break;
3297               if (!_ctrl->entries[i])
3298                 continue;
3299               obj = dwg_ref_object (dwg, _ctrl->entries[i]);
3300               if (obj && obj->type == DWG_TYPE_VX_TABLE_RECORD)
3301                 {
3302                   error |= dwg_dxf_VX_TABLE_RECORD (dat, obj);
3303                 }
3304             }
3305           ENDTAB ();
3306         }
3307     }
3308 
3309   SINCE (R_12)
3310   {
3311     Dwg_Object *ctrl, *obj;
3312     Dwg_Object_BLOCK_CONTROL *_ctrl = dwg_block_control (dwg);
3313     Dwg_Object_Ref *ref;
3314     Dwg_Object *mspace = NULL, *pspace = NULL;
3315     if (!_ctrl)
3316       {
3317         LOG_ERROR ("BLOCK_CONTROL missing");
3318         return DWG_ERR_INVALIDDWG;
3319       }
3320     ctrl = dwg_obj_generic_to_object (_ctrl, &error);
3321     if (!ctrl || ctrl->fixedtype != DWG_TYPE_BLOCK_CONTROL)
3322       return DWG_ERR_INVALIDDWG;
3323 
3324     obj = ctrl;
3325     TABLE (BLOCK_RECORD);
3326     COMMON_TABLE_CONTROL_FLAGS;
3327     error |= dwg_dxf_BLOCK_CONTROL (dat, ctrl);
3328 
3329 #if 0 // unordered pspace
3330     for (i = 0; i < dwg->num_objects; i++)
3331       {
3332         Dwg_Object *hdr = &dwg->object[i];
3333         if (hdr && hdr->supertype == DWG_SUPERTYPE_OBJECT
3334             && hdr->type == DWG_TYPE_BLOCK_HEADER)
3335           {
3336             // not necessarily in the same order as DXF, but exhaustive
3337             RECORD (BLOCK_RECORD);
3338             error |= dwg_dxf_BLOCK_HEADER (dat, hdr);
3339           }
3340       }
3341 #else
3342     mspace = dwg_model_space_object (dwg);
3343     if (!mspace)
3344       return DWG_ERR_INVALIDDWG;
3345     RECORD (BLOCK_RECORD);
3346     error |= dwg_dxf_BLOCK_HEADER (dat, mspace);
3347 
3348     ref = dwg_paper_space_ref (dwg);
3349     pspace = ref ? dwg_ref_object (dwg, ref) : NULL;
3350     if (pspace)
3351       {
3352         RECORD (BLOCK_RECORD);
3353         error |= dwg_dxf_BLOCK_HEADER (dat, pspace);
3354       }
3355 
3356     for (i = 0; i < dwg->block_control.num_entries; i++)
3357       {
3358         if (!dwg->block_control.entries)
3359           break;
3360         if (!dwg->block_control.entries[i])
3361           continue;
3362         obj = dwg_ref_object (dwg, dwg->block_control.entries[i]);
3363         if (obj && obj->type == DWG_TYPE_BLOCK_HEADER
3364             && obj != mspace
3365             && obj != pspace)
3366           {
3367             RECORD (BLOCK_RECORD);
3368             error |= dwg_dxf_BLOCK_HEADER (dat, obj);
3369           }
3370       }
3371 #endif
3372 
3373     ENDTAB ();
3374   }
3375   ENDSEC ();
3376   return 0;
3377 }
3378 
3379 static void
dxf_ENDBLK_empty(Bit_Chain * restrict dat,const Dwg_Object * restrict hdr)3380 dxf_ENDBLK_empty (Bit_Chain *restrict dat, const Dwg_Object *restrict hdr)
3381 {
3382   // temp. only. not registered in dwg->object[]
3383   Dwg_Object *obj = (Dwg_Object *)calloc (1, sizeof (Dwg_Object));
3384   Dwg_Data *dwg = hdr->parent;
3385   // Dwg_Entity_ENDBLK *_obj;
3386   obj->parent = dwg;
3387   obj->index = dwg->num_objects;
3388   dwg_setup_ENDBLK (obj);
3389   obj->tio.entity->ownerhandle = (BITCODE_H)calloc (1, sizeof (Dwg_Object_Ref));
3390   obj->tio.entity->ownerhandle->obj = (Dwg_Object *)hdr;
3391   obj->tio.entity->ownerhandle->handleref = hdr->handle;
3392   obj->tio.entity->ownerhandle->absolute_ref = hdr->handle.value;
3393   //_obj = obj->tio.entity->tio.ENDBLK;
3394   dwg_dxf_ENDBLK (dat, obj);
3395   free (obj->tio.entity->tio.ENDBLK);
3396   free (obj->tio.entity->ownerhandle);
3397   free (obj->tio.entity);
3398   free (obj);
3399 }
3400 
3401 // a BLOCK_HEADER
3402 static int
dxf_block_write(Bit_Chain * restrict dat,const Dwg_Object * restrict hdr,const Dwg_Object * restrict mspace,const Dwg_Object * restrict pspace,int * restrict i)3403 dxf_block_write (Bit_Chain *restrict dat, const Dwg_Object *restrict hdr,
3404                  const Dwg_Object *restrict mspace, const Dwg_Object *restrict pspace,
3405                  int *restrict i)
3406 {
3407   int error = 0;
3408   const Dwg_Object_BLOCK_HEADER *restrict _hdr
3409       = hdr->tio.object->tio.BLOCK_HEADER;
3410   Dwg_Object *restrict obj = get_first_owned_block (hdr); // BLOCK
3411   Dwg_Object *restrict endblk = NULL;
3412   unsigned long int mspace_ref = mspace ? mspace->handle.value : 0;
3413   unsigned long int pspace_ref = pspace ? pspace->handle.value : 0;
3414 
3415   if (obj)
3416     error |= dwg_dxf_object (dat, obj, i);
3417   else
3418     {
3419       SINCE (R_2004)
3420         {
3421           // first_owned_block
3422           if (IS_FROM_TU (dat))
3423             {
3424               char *s = bit_convert_TU ((BITCODE_TU)_hdr->name);
3425               LOG_ERROR ("BLOCK_HEADER %s block_entity[0] missing", s);
3426               free (s);
3427             }
3428           else
3429             LOG_ERROR ("BLOCK_HEADER %s block_entity[0] missing", _hdr->name);
3430           return DWG_ERR_INVALIDDWG;
3431         }
3432       else
3433         LOG_WARN ("BLOCK_HEADER %s block_entity[0] missing", _hdr->name);
3434     }
3435   // Skip all *Model_Space and *Paper_Space entities, esp. new ones: UNDERLAY, MULTILEADER, ...
3436   // They are all under ENTITIES later. But WIPEOUT and VIEWPORT is here.
3437   // Note: the objects may vary (e.g. example_2000), but the index not.
3438   if ((hdr == mspace) || (hdr->index == mspace->index))
3439     obj = NULL;
3440   else if ((hdr == pspace) || (pspace && hdr->index == pspace->index))
3441     obj = NULL;
3442   else
3443     obj = get_first_owned_entity (hdr); // first_entity or entities[0]
3444   while (obj)
3445     {
3446       if (obj->supertype == DWG_SUPERTYPE_ENTITY
3447           && obj->fixedtype != DWG_TYPE_ENDBLK
3448           && obj->tio.entity != NULL
3449           && (obj->tio.entity->entmode != 2 ||
3450               (obj->tio.entity->ownerhandle != NULL
3451                && obj->tio.entity->ownerhandle->absolute_ref != mspace_ref
3452                && obj->tio.entity->ownerhandle->absolute_ref != pspace_ref)))
3453         error |= dwg_dxf_object (dat, obj, i);
3454       obj = get_next_owned_block_entity (hdr, obj); // until last_entity
3455     }
3456   endblk = get_last_owned_block (hdr);
3457   if (endblk)
3458     {
3459       error |= dwg_dxf_ENDBLK (dat, endblk);
3460       LOG_INFO ("\n")
3461     }
3462   else
3463     {
3464       LOG_WARN ("Empty ENDBLK for \"%s\" %lX", _hdr->name,
3465                 hdr ? hdr->handle.value : 0);
3466       dxf_ENDBLK_empty (dat, hdr);
3467       LOG_INFO ("\n")
3468     }
3469   return error;
3470 }
3471 
3472 static int
dxf_blocks_write(Bit_Chain * restrict dat,Dwg_Data * restrict dwg)3473 dxf_blocks_write (Bit_Chain *restrict dat, Dwg_Data *restrict dwg)
3474 {
3475   int error = 0;
3476   int i;
3477   Dwg_Object *restrict mspace = dwg_model_space_object (dwg);
3478   Dwg_Object *restrict pspace = dwg_paper_space_object (dwg);
3479 
3480   if (!mspace)
3481     return DWG_ERR_UNHANDLEDCLASS;
3482 
3483   // If there's no *Model_Space block skip this BLOCKS section.
3484   // Or try handle 1F with r2000+, 17 with r14
3485   // obj = get_first_owned_block(hdr);
3486   // if (!obj)
3487   //  obj = dwg_resolve_handle(dwg, dwg->header.version >= R_2000 ? 0x1f :
3488   //  0x17);
3489   // if (!obj)
3490   //  return 1;
3491 
3492   SECTION (BLOCKS);
3493   /* There may be unconnected pspace blocks (not caught by above),
3494      such as pspace referred by a LAYOUT or DIMENSION, so for simplicity just
3495      scan all BLOCK_HEADER's and just skip *Model_Space and *Paper_Space. pspace might be NULL.
3496      #81 BLOCK_HEADER -
3497      LAYOUT - BLOCK - ENDBLK
3498    */
3499   for (i = 0; (BITCODE_BL)i < dwg->num_objects; i++)
3500     {
3501       const Dwg_Object *restrict obj = &dwg->object[i];
3502       if (obj->supertype == DWG_SUPERTYPE_OBJECT
3503           && obj->type == DWG_TYPE_BLOCK_HEADER)
3504         {
3505           error |= dxf_block_write (dat, obj, mspace, pspace, &i);
3506         }
3507   }
3508 
3509   ENDSEC ();
3510   return error;
3511 }
3512 
3513 static int
dxf_entities_write(Bit_Chain * restrict dat,Dwg_Data * restrict dwg)3514 dxf_entities_write (Bit_Chain *restrict dat, Dwg_Data *restrict dwg)
3515 {
3516   int error = 0;
3517   Dwg_Object *restrict ms = dwg_model_space_object (dwg);
3518   Dwg_Object *restrict ps = dwg_paper_space_object (dwg);
3519   Dwg_Object *obj;
3520   if (!ms)
3521     return DWG_ERR_INVALIDDWG;
3522 
3523   SECTION (ENTITIES);
3524   // how to order the entities:
3525   // 1. first all ms, then all ps
3526 #if 1
3527   // First mspace
3528   obj = get_first_owned_entity (ms); // first_entity or entities[0]
3529   while (obj)
3530     {
3531       int i = obj->index;
3532       error |= dwg_dxf_object (dat, obj, &i);
3533       obj = get_next_owned_block_entity (ms, obj); // until last_entity
3534     }
3535   // Then all pspace entities. just filter out other BLOCKS entities
3536   if (ps)
3537     {
3538       obj = get_first_owned_entity (ps);
3539       while (obj)
3540         {
3541           int i = obj->index;
3542           error |= dwg_dxf_object (dat, obj, &i);
3543           obj = get_next_owned_block_entity (ps, obj);
3544         }
3545     }
3546 #elif 0
3547   // 2. all entities in iteration order. filter out not owned by ms or ps entities.
3548   obj = get_first_owned_entity (ms);
3549   if (!obj)
3550     obj = get_first_owned_entity (ps);
3551   while (obj)
3552     {
3553       int i = obj->index;
3554       Dwg_Object_Ref *owner = obj->tio.entity->ownerhandle;
3555       if (!owner || (owner->obj == ms || owner->obj == ps))
3556         error |= dwg_dxf_object (dat, obj, &i);
3557       obj = dwg_next_entity (obj);
3558     }
3559 #else
3560   // 3. all objects in handle order, filter out not owned ms or ps entities.
3561   for (int i = 0; (BITCODE_BL)i < dwg->num_objects; i++)
3562     {
3563       Dwg_Object *obj = &dwg->object[i];
3564       if (obj->supertype == DWG_SUPERTYPE_ENTITY && obj->type != DWG_TYPE_BLOCK
3565           && obj->type != DWG_TYPE_ENDBLK)
3566         {
3567           Dwg_Object_Ref *owner = obj->tio.entity->ownerhandle;
3568           if (!owner || (owner->obj == ms || owner->obj == ps))
3569             error |= dwg_dxf_object (dat, obj, &i);
3570         }
3571     }
3572 #endif
3573   ENDSEC ();
3574   return error;
3575 }
3576 
3577 // check for valid ownerhandle. set to 0 if not
3578 int
dxf_validate_DICTIONARY(Dwg_Object * obj)3579 dxf_validate_DICTIONARY (Dwg_Object *obj)
3580 {
3581   Dwg_Object_Ref *ownerhandle = obj->tio.object->ownerhandle;
3582   if (ownerhandle && !dwg_ref_object (obj->parent, ownerhandle))
3583     {
3584       LOG_INFO ("Wrong DICTIONARY.ownerhandle %lX\n", ownerhandle->absolute_ref);
3585       ownerhandle->absolute_ref = 0;
3586       return 0;
3587     }
3588   return 1;
3589 }
3590 
3591 static int
dxf_objects_write(Bit_Chain * restrict dat,Dwg_Data * restrict dwg)3592 dxf_objects_write (Bit_Chain *restrict dat, Dwg_Data *restrict dwg)
3593 {
3594   int error = 0;
3595   int i;
3596 
3597   SECTION (OBJECTS);
3598   for (i = 0; (BITCODE_BL)i < dwg->num_objects; i++)
3599     {
3600       const Dwg_Object *restrict obj = &dwg->object[i];
3601       if (obj->supertype == DWG_SUPERTYPE_OBJECT
3602           && obj->type != DWG_TYPE_BLOCK_HEADER && !dwg_obj_is_control (obj))
3603         error |= dwg_dxf_object (dat, obj, &i);
3604     }
3605   ENDSEC ();
3606   return error;
3607 }
3608 
3609 // New ACDSDATA r2013+ section, with ACDSSCHEMA elements
3610 static int
dxf_acds_write(Bit_Chain * restrict dat,Dwg_Data * restrict dwg)3611 dxf_acds_write (Bit_Chain *restrict dat, Dwg_Data *restrict dwg)
3612 {
3613   //const char *section = "AcDsProtoype";
3614   Dwg_AcDs *_obj = &dwg->acds;
3615   if (0 && _obj->num_segidx)
3616     {
3617       SECTION (ACSDSDATA); // FIXME
3618       // 70
3619       // 71
3620       // 0 ACDSSCHEMA
3621       // TODO ...
3622       ENDSEC ();
3623     }
3624   return 0;
3625 }
3626 
3627 GCC30_DIAG_IGNORE (-Wformat-nonliteral)
3628 // TODO: Beware, there's also a new ACDSDATA section, with ACDSSCHEMA elements
3629 // and the Thumbnail_Data (per block?)
3630 static int
dxf_thumbnail_write(Bit_Chain * restrict dat,Dwg_Data * restrict dwg)3631 dxf_thumbnail_write (Bit_Chain *restrict dat, Dwg_Data *restrict dwg)
3632 {
3633   Bit_Chain *pic = (Bit_Chain *)&dwg->thumbnail;
3634   if (pic->chain && pic->size && pic->size > 10)
3635     {
3636       SECTION (THUMBNAILIMAGE);
3637       VALUE_RL (pic->size, 90);
3638       VALUE_BINARY (pic->chain, pic->size, 310);
3639       ENDSEC ();
3640     }
3641   return 0;
3642 }
3643 
3644 
3645 AFL_GCC_TOOBIG
3646 EXPORT int
dwg_write_dxf(Bit_Chain * restrict dat,Dwg_Data * restrict dwg)3647 dwg_write_dxf (Bit_Chain *restrict dat, Dwg_Data *restrict dwg)
3648 {
3649   const int minimal = dwg->opts & DWG_OPTS_MINIMAL;
3650   //struct Dwg_Header *obj = &dwg->header;
3651 
3652   loglevel = dwg->opts & DWG_OPTS_LOGLEVEL;
3653   if (dat->from_version == R_INVALID)
3654     dat->from_version = dwg->header.from_version;
3655   if (dwg->header.version <= R_2000 && dwg->header.from_version > R_2000)
3656     dwg_fixup_BLOCKS_entities (dwg);
3657 
3658   VALUE_TV (PACKAGE_STRING, 999);
3659 
3660   // A minimal header requires only $ACADVER, $HANDSEED, and then ENTITIES
3661   // see https://pythonhosted.org/ezdxf/dxfinternals/filestructure.html
3662   dxf_header_write (dat, dwg);
3663 
3664   if (!minimal)
3665     {
3666       // if downgraded to r13, but we still have classes, keep the
3667       // classes
3668       if ((dat->from_version >= R_13 && dwg->num_classes)
3669           || dat->version >= R_2000)
3670         {
3671           if (dxf_classes_write (dat, dwg) >= DWG_ERR_CRITICAL)
3672             goto fail;
3673         }
3674 
3675       if (dxf_tables_write (dat, dwg) >= DWG_ERR_CRITICAL)
3676         goto fail;
3677 
3678       if (dxf_blocks_write (dat, dwg) >= DWG_ERR_CRITICAL)
3679         goto fail;
3680     }
3681 
3682   if (dxf_entities_write (dat, dwg) >= DWG_ERR_CRITICAL)
3683     goto fail;
3684 
3685   if (!minimal)
3686     {
3687       SINCE (R_13)
3688       {
3689         if (dxf_objects_write (dat, dwg) >= DWG_ERR_CRITICAL)
3690           goto fail;
3691       }
3692       SINCE (R_2013)
3693       {
3694         if (dxf_acds_write (dat, dwg) >= DWG_ERR_CRITICAL)
3695           goto fail;
3696       }
3697       SINCE (R_2000)
3698       {
3699         if (dxf_thumbnail_write (dat, dwg) >= DWG_ERR_CRITICAL)
3700           goto fail;
3701       }
3702     }
3703   RECORD (EOF);
3704 
3705   return 0;
3706 fail:
3707   return 1;
3708 }
3709 AFL_GCC_POP
3710 
3711 #undef IS_PRINT
3712 #undef IS_DXF
3713