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_json.c: write as JSON
15  * written by Reini Urban
16  */
17 
18 #include "config.h"
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <string.h>
22 #include <assert.h>
23 #ifdef HAVE_CTYPE_H
24 #  include <ctype.h>
25 #endif
26 
27 #define IS_JSON
28 #include "common.h"
29 #include "bits.h"
30 #include "myalloca.h"
31 #include "dwg.h"
32 #include "decode.h"
33 #include "out_json.h"
34 
35 #define DWG_LOGLEVEL DWG_LOGLEVEL_NONE
36 #include "logging.h"
37 
38 /* the current version per spec block */
39 static unsigned int cur_ver = 0;
40 static BITCODE_BL rcount1, rcount2;
41 
42 /* see also examples/unknown.c */
43 #ifdef HAVE_NATIVE_WCHAR2
44 static wchar_t *wcquote (wchar_t *restrict dest, const wchar_t *restrict src);
45 #else
46 static void print_wcquote (Bit_Chain *restrict dat,
47                            dwg_wchar_t *restrict wstr);
48 #endif
49 
50 static int json_3dsolid (Bit_Chain *restrict dat,
51                          const Dwg_Object *restrict obj,
52                          Dwg_Entity_3DSOLID *restrict _obj);
53 static void _prefix (Bit_Chain *dat);
54 static char *_path_field (const char *path);
55 
56 /*--------------------------------------------------------------------------------
57  * MACROS
58  */
59 
60 #define ACTION json
61 
62 #define ISFIRST (dat->opts & DWG_OPTS_JSONFIRST)
63 #define SETFIRST dat->opts |= DWG_OPTS_JSONFIRST
64 #define CLEARFIRST dat->opts &= ~DWG_OPTS_JSONFIRST
65 
66 #define PREFIX _prefix (dat);
67 #define PRINTFIRST                                                            \
68   {                                                                           \
69     if (!ISFIRST)                                                             \
70       fprintf (dat->fh, ",\n");                                               \
71     else                                                                      \
72       CLEARFIRST;                                                             \
73   }
74 #define FIRSTPREFIX PRINTFIRST PREFIX
75 
76 #define KEYs(nam) FIRSTPREFIX fprintf (dat->fh, "\"%s\": ", nam)
77 // strip path to field only
78 #define KEY(nam) FIRSTPREFIX fprintf (dat->fh, "\"%s\": ", _path_field(#nam))
79 
80 #define ARRAY                                                                 \
81   {                                                                           \
82     fprintf (dat->fh, "[\n");                                                 \
83     SETFIRST;                                                                 \
84     dat->bit++;                                                               \
85   }
86 #define ENDARRAY                                                              \
87   {                                                                           \
88     fprintf (dat->fh, "\n");                                                  \
89     dat->bit--;                                                               \
90     PREFIX fprintf (dat->fh, "]");                                            \
91     CLEARFIRST;                                                               \
92   }
93 #define HASH                                                                  \
94   {                                                                           \
95     fprintf (dat->fh, "{\n");                                                 \
96     SETFIRST;                                                                 \
97     dat->bit++;                                                               \
98   }
99 #define ENDHASH                                                               \
100   {                                                                           \
101     fprintf (dat->fh, "\n");                                                  \
102     dat->bit--;                                                               \
103     PREFIX fprintf (dat->fh, "}");                                            \
104     CLEARFIRST;                                                               \
105   }
106 
107 #define TABLE(nam)                                                            \
108   KEY (nam);                                                                  \
109   HASH
110 #define ENDTAB()                                                              \
111   ENDHASH
112 // a named hash
113 #define RECORD(nam)                                                           \
114   KEY (nam);                                                                  \
115   HASH
116 #define ENDRECORD()                                                           \
117   ENDHASH
118 // a named list
119 #define SECTION(nam)                                                          \
120   KEY (nam);                                                                  \
121   ARRAY
122 #define ENDSEC() ENDARRAY
123 
124 #undef FORMAT_H
125 #undef FORMAT_RLL
126 #undef FORMAT_BLL
127 #undef FORMAT_RC
128 #undef FORMAT_RSx
129 #undef FORMAT_RLx
130 #undef FORMAT_BLx
131 #undef FORMAT_BLX
132 #undef FORMAT_4BITS
133 #undef ARGS_H
134 #define ARGS_H(hdl) hdl.code, hdl.value
135 #define FORMAT_H "[%u, %lu]"
136 #define ARGS_HREF(ref) ref->handleref.code, ref->handleref.size, ref->handleref.value, ref->absolute_ref
137 #undef FORMAT_RD
138 #undef FORMAT_BD
139 #define FORMAT_RD "%.14f"
140 #define FORMAT_BD FORMAT_RD
141 #define FORMAT_HREF "[%u, %u, %lu, %lu]"
142 #define FORMAT_RLL "%" PRIu64
143 #define FORMAT_BLL "%" PRIu64
144 #define FORMAT_RC "%d"
145 #define FORMAT_RSx FORMAT_RS
146 #define FORMAT_RLx FORMAT_RL
147 #define FORMAT_BLx FORMAT_BL
148 #define FORMAT_BLX FORMAT_BL
149 #define FORMAT_4BITS FORMAT_RC
150 
151 #define VALUE(value, type, dxf)                                               \
152   fprintf (dat->fh, FORMAT_##type, value)
153 #define VALUE_B(value, dxf) VALUE (value, B, dxf)
154 #define VALUE_RC(value, dxf) VALUE (value, RC, dxf)
155 #define VALUE_RS(value, dxf) VALUE (value, RS, dxf)
156 #define VALUE_RL(value, dxf) VALUE (value, RL, dxf)
157 #define VALUE_RLL(value, dxf) VALUE (value, RLL, dxf)
158 #ifdef IS_RELEASE
159 #  define VALUE_RD(value, dxf)                                                \
160     if (bit_isnan (value))                                                    \
161       _VALUE_RD (0.0, dxf)                                                    \
162     else                                                                      \
163       _VALUE_RD (value, dxf)
164 #else
165 #  define VALUE_RD(value, dxf) _VALUE_RD (value, dxf)
166 #endif
167 #define _VALUE_RD(value, dxf)                                                 \
168   {                                                                           \
169     char _buf[256];                                                           \
170     int k;                                                                    \
171     snprintf (_buf, 255, FORMAT_RD, value);                                   \
172     k = strlen (_buf);                                                        \
173     if (strrchr (_buf, '.') && _buf[k - 1] == '0')                            \
174       {                                                                       \
175         for (k--; k > 1 && _buf[k - 1] != '.' && _buf[k] == '0'; k--)         \
176           _buf[k] = '\0';                                                     \
177       }                                                                       \
178     fprintf (dat->fh, "%s", _buf);                                            \
179   }
180 #define VALUE_2RD(pt, dxf)                                                    \
181   {                                                                           \
182     fprintf (dat->fh, "[ ");                                                  \
183     VALUE_RD (pt.x, 0);                                                       \
184     fprintf (dat->fh, ", ");                                                  \
185     VALUE_RD (pt.y, 0);                                                       \
186     fprintf (dat->fh, " ]");                                                  \
187   }
188 #define VALUE_2DD(pt, def, dxf) VALUE_2RD (pt, dxf)
189 #define VALUE_3RD(pt, dxf)                                                    \
190   {                                                                           \
191     fprintf (dat->fh, "[ ");                                                  \
192     VALUE_RD (pt.x, 0);                                                       \
193     fprintf (dat->fh, ", ");                                                  \
194     VALUE_RD (pt.y, 0);                                                       \
195     fprintf (dat->fh, ", ");                                                  \
196     VALUE_RD (pt.z, 0);                                                       \
197     fprintf (dat->fh, " ]");                                                  \
198   }
199 #define VALUE_3BD(pt, dxf) VALUE_3RD (pt, dxf)
200 #define VALUE_TV(nam, dxf)
201 
202 #define FIELD(nam, type, dxf)                                                 \
203   if (!memBEGINc (#nam, "num_"))                                              \
204     {                                                                         \
205       FIRSTPREFIX fprintf (dat->fh, "\"%s\": " FORMAT_##type,                 \
206                            _path_field (#nam), _obj->nam);                    \
207     }
208 #define _FIELD(nam, type, value)                                              \
209   {                                                                           \
210     FIRSTPREFIX fprintf (dat->fh, "\"" #nam "\": " FORMAT_##type, obj->nam);  \
211   }
212 #define ENT_FIELD(nam, type, value)                                           \
213   {                                                                           \
214     FIRSTPREFIX fprintf (dat->fh, "\"%s\": " FORMAT_##type,                   \
215                          _path_field (#nam), _ent->nam);                      \
216   }
217 #define SUB_FIELD(o, nam, type, dxf)                                          \
218   if (!memBEGINc (#nam, "num_"))                                              \
219     {                                                                         \
220       FIRSTPREFIX fprintf (dat->fh, "\"%s\": " FORMAT_##type,                 \
221                            _path_field (#nam), _obj->o.nam);                  \
222     }
223 #define FIELD_CAST(nam, type, cast, dxf) FIELD (nam, cast, dxf)
224 #define SUB_FIELD_CAST(o, nam, type, cast, dxf) SUB_FIELD (o, nam, cast, dxf)
225 #define FIELD_TRACE(nam, type)
226 #define FIELD_G_TRACE(nam, type, dxf)
227 #define FIELD_TEXT(nam, str)                                                  \
228   {                                                                           \
229     FIRSTPREFIX fprintf (dat->fh, "\"%s\": ", _path_field(#nam));             \
230     VALUE_TEXT ((char*)str)                                                   \
231   }
232 
233 #define VALUE_TEXT(str)                                                       \
234   {                                                                           \
235     if (str                                                                   \
236         && (1 || strchr (str, '"') || strchr (str, '\\')                      \
237             || strchr (str, '\n')))                                           \
238       {                                                                       \
239         const int len = strlen (str);                                         \
240         if (len < 4096 / 6)                                                   \
241           {                                                                   \
242             const int _len = 6 * len + 1;                                     \
243             char *_buf = (char*)alloca (_len);                                \
244             fprintf (dat->fh, "\"%s\"", json_cquote (_buf, str, _len));       \
245             freea (_buf);                                                     \
246           }                                                                   \
247         else                                                                  \
248           {                                                                   \
249             const int _len = 6 * len + 1;                                     \
250             char *_buf = (char*)malloc (_len);                                \
251             fprintf (dat->fh, "\"%s\"", json_cquote (_buf, str, _len));       \
252             free (_buf);                                                      \
253           }                                                                   \
254       }                                                                       \
255     else                                                                      \
256       {                                                                       \
257         fprintf (dat->fh, "\"%s\"", str ? str : "");                          \
258       }                                                                       \
259   }
260 
261 #ifdef HAVE_NATIVE_WCHAR2
262 #  define VALUE_TEXT_TU(wstr)                                                 \
263     if (wstr                                                                  \
264         && (1 || wcschr ((wchar_t *)wstr, L'"')                               \
265             || wcschr ((wchar_t *)wstr, L'\\')                                \
266             || wcschr ((wchar_t *)wstr, L'\n')))                              \
267       {                                                                       \
268         wchar_t *_buf = malloc (6 * wcslen ((wchar_t *)wstr) + 2);            \
269         fprintf (dat->fh, "\"%ls\"", wcquote (_buf, (wchar_t *)wstr));        \
270         free (_buf);                                                          \
271       }                                                                       \
272     else                                                                      \
273       {                                                                       \
274         fprintf (dat->fh, "\"%ls\"", wstr ? (wchar_t *)wstr : L"");           \
275       }
276 #else
277 #  define VALUE_TEXT_TU(wstr) print_wcquote (dat, (BITCODE_TU)wstr)
278 #endif
279 #define FIELD_TEXT_TU(nam, wstr)                                              \
280   {                                                                           \
281     KEY (nam);                                                                \
282     VALUE_TEXT_TU ((BITCODE_TU)wstr);                                         \
283   }
284 
285 #define FIELD_VALUE(nam) _obj->nam
286 #define ANYCODE -1
287 // todo: only the name, not the ref
288 #define VALUE_HANDLE(hdlptr, nam, handle_code, dxf)                           \
289   if (hdlptr)                                                                 \
290     {                                                                         \
291       fprintf (dat->fh, FORMAT_HREF "", ARGS_HREF (hdlptr));                  \
292     }                                                                         \
293   else                                                                        \
294     {                                                                         \
295       fprintf (dat->fh, "[0, 0]");                                            \
296     }
297 #define VALUE_H(hdl, dxf) \
298   fprintf (dat->fh, FORMAT_H "", hdl.code, hdl.value)
299 #define FIELD_HANDLE(nam, handle_code, dxf)                                   \
300   {                                                                           \
301     if (_obj->nam)                                                            \
302       {                                                                       \
303         FIRSTPREFIX fprintf (dat->fh, "\"%s\": " FORMAT_HREF "",              \
304                              _path_field (#nam), ARGS_HREF (_obj->nam));      \
305       }                                                                       \
306     else                                                                      \
307       {                                                                       \
308         FIRSTPREFIX fprintf (dat->fh, "\"%s\": [0, 0]", _path_field (#nam));  \
309       }                                                                       \
310   }
311 #define SUB_FIELD_HANDLE(o, nam, handle_code, dxf)                            \
312   {                                                                           \
313     if (_obj->o.nam)                                                          \
314       {                                                                       \
315         FIRSTPREFIX fprintf (dat->fh, "\"%s\": " FORMAT_HREF "",              \
316                              _path_field (#nam), ARGS_HREF (_obj->o.nam));    \
317       }                                                                       \
318     else                                                                      \
319       {                                                                       \
320         FIRSTPREFIX fprintf (dat->fh, "\"%s\": [0, 0]", _path_field (#nam));  \
321       }                                                                       \
322   }
323 #define FIELD_DATAHANDLE(nam, code, dxf) FIELD_HANDLE (nam, code, dxf)
324 #define FIELD_HANDLE_N(nam, vcount, handle_code, dxf)                         \
325   PRINTFIRST;                                                                 \
326   if (_obj->nam)                                                              \
327     {                                                                         \
328       PREFIX fprintf (dat->fh, FORMAT_HREF "", ARGS_HREF (_obj->nam));        \
329     }                                                                         \
330   else                                                                        \
331     {                                                                         \
332       PREFIX fprintf (dat->fh, "[0, 0]");                                     \
333     }
334 #define SUB_FIELD_HANDLE_N(o, nam, handle_code, dxf)                          \
335   PRINTFIRST;                                                                 \
336   if (_obj->o.nam)                                                            \
337     {                                                                         \
338       PREFIX fprintf (dat->fh, FORMAT_HREF "", ARGS_HREF (_obj->o.nam));      \
339     }                                                                         \
340   else                                                                        \
341     {                                                                         \
342       PREFIX fprintf (dat->fh, "[0, 0]");                                     \
343     }
344 #define VALUE_BINARY(buf, len, dxf)                                           \
345   {                                                                           \
346     fprintf (dat->fh, "\"");                                                  \
347     if (buf && len)                                                           \
348       {                                                                       \
349         for (long _j = 0; _j < (long)len; _j++)                               \
350           {                                                                   \
351             fprintf (dat->fh, "%02X", ((BITCODE_RC *)buf)[_j]);               \
352           }                                                                   \
353       }                                                                       \
354     fprintf (dat->fh, "\"");                                                  \
355   }
356 #define FIELD_BINARY(nam, size, dxf)                                          \
357   {                                                                           \
358     KEY (nam);                                                                \
359     fprintf (dat->fh, "\"");                                                  \
360     if (_obj->nam)                                                            \
361       {                                                                       \
362         for (long _j = 0; _j < (long)size; _j++)                              \
363           {                                                                   \
364             fprintf (dat->fh, "%02X", ((BITCODE_RC *)_obj->nam)[_j]);         \
365           }                                                                   \
366       }                                                                       \
367     fprintf (dat->fh, "\"");                                                  \
368   }
369 
370 #define FIELD_B(nam, dxf) FIELD (nam, B, dxf)
371 #define FIELD_BB(nam, dxf) FIELD (nam, BB, dxf)
372 #define FIELD_3B(nam, dxf) FIELD (nam, 3B, dxf)
373 #define FIELD_BS(nam, dxf) FIELD (nam, BS, dxf)
374 #define FIELD_BL(nam, dxf) FIELD (nam, BL, dxf)
375 #define FIELD_BLL(nam, dxf) FIELD (nam, BLL, dxf)
376 #ifdef IS_RELEASE
377 #  define FIELD_BD(nam, dxf)                                                  \
378     {                                                                         \
379       if (!bit_isnan (_obj->nam))                                             \
380         {                                                                     \
381           FIRSTPREFIX fprintf (dat->fh, "\"%s\": ", _path_field (#nam));      \
382           _VALUE_RD (_obj->nam, dxf);                                         \
383         }                                                                     \
384     }
385 #  define FIELD_2RD(nam, dxf)                                                 \
386     {                                                                         \
387       if (!bit_isnan (_obj->nam.x) && !bit_isnan (_obj->nam.y))               \
388         {                                                                     \
389           FIRSTPREFIX fprintf (dat->fh, "\"" #nam "\": ");                    \
390           VALUE_2RD (_obj->nam, dxf);                                         \
391         }                                                                     \
392     }
393 #  define FIELD_3RD(nam, dxf)                                                 \
394     {                                                                         \
395       if (!bit_isnan (_obj->nam.x) && !bit_isnan (_obj->nam.y)                \
396           && !bit_isnan (_obj->nam.z))                                        \
397         {                                                                     \
398           FIRSTPREFIX fprintf (dat->fh, "\"" #nam "\": ");                    \
399           VALUE_3RD (_obj->nam, dxf);                                         \
400         }                                                                     \
401     }
402 #  define SUB_FIELD_BD(o, nam, dxf)                                           \
403     {                                                                         \
404       if (!bit_isnan (_obj->o.nam))                                           \
405         {                                                                     \
406           FIRSTPREFIX fprintf (dat->fh, "\"%s\": ", _path_field (#nam));      \
407           _VALUE_RD (_obj->o.nam, dxf);                                       \
408         }                                                                     \
409     }
410 #else /* IS_RELEASE */
411 #  define FIELD_BD(nam, dxf)                                                  \
412     {                                                                         \
413       FIRSTPREFIX fprintf (dat->fh, "\"%s\": ", _path_field (#nam));          \
414       _VALUE_RD (_obj->nam, dxf);                                             \
415     }
416 #  define FIELD_2RD(nam, dxf)                                                 \
417     {                                                                         \
418       FIRSTPREFIX fprintf (dat->fh, "\"" #nam "\": ");                        \
419       VALUE_2RD (_obj->nam, dxf);                                             \
420     }
421 #  define FIELD_3RD(nam, dxf)                                                 \
422     {                                                                         \
423       FIRSTPREFIX fprintf (dat->fh, "\"" #nam "\": ");                        \
424       VALUE_3RD (_obj->nam, dxf);                                             \
425     }
426 #  define SUB_FIELD_BD(o, nam, dxf)                                           \
427     {                                                                         \
428       FIRSTPREFIX fprintf (dat->fh, "\"%s\": ", _path_field (#nam));          \
429       _VALUE_RD (_obj->o.nam, dxf);                                           \
430     }
431 #endif
432 
433 #define FIELD_RC(nam, dxf) FIELD (nam, RC, dxf)
434 #define FIELD_RCx(nam, dxf) FIELD (nam, RC, dxf)
435 #define FIELD_RS(nam, dxf) FIELD (nam, RS, dxf)
436 #define FIELD_RD(nam, dxf) FIELD_BD (nam, dxf)
437 #define FIELD_RL(nam, dxf) FIELD (nam, RL, dxf)
438 #define FIELD_RLL(nam, dxf) FIELD (nam, RLL, dxf)
439 #define FIELD_MC(nam, dxf) FIELD (nam, MC, dxf)
440 #define FIELD_MS(nam, dxf) FIELD (nam, MS, dxf)
441 #define FIELD_TF(nam, len, dxf) FIELD_TEXT (nam, _obj->nam)
442 #define FIELD_TFF(nam, len, dxf) FIELD_TEXT (nam, (const char*)_obj->nam)
443 #define FIELD_TFFx(nam, len, dxf) FIELD_BINARY (nam, len, dxf)
444 #define FIELD_TV(nam, dxf) FIELD_TEXT (nam, _obj->nam)
445 #define FIELD_TU(nam, dxf) FIELD_TEXT_TU (nam, (BITCODE_TU)_obj->nam)
446 #define FIELD_T16(nam, dxf) FIELD_TV (nam, dxf)
447 #define FIELD_TU16(nam, dxf) FIELD_TU (nam, dxf)
448 #define FIELD_T32(nam, dxf) FIELD_T (nam, dxf)
449 #define FIELD_T(nam, dxf)                                                     \
450   {                                                                           \
451     if (IS_FROM_TU (dat))                                                     \
452       {                                                                       \
453         FIELD_TU (nam, dxf);                                                  \
454       }                                                                       \
455     else                                                                      \
456       {                                                                       \
457         FIELD_TV (nam, dxf);                                                  \
458       }                                                                       \
459   }
460 #define _FIELD_T(nam, str)                                                    \
461   {                                                                           \
462     if (IS_FROM_TU (dat))                                                     \
463       {                                                                       \
464         FIELD_TEXT_TU (nam, str);                                             \
465       }                                                                       \
466     else                                                                      \
467       {                                                                       \
468         FIELD_TEXT (nam, str);                                                \
469       }                                                                       \
470   }
471 #define VALUE_T(str)                                                          \
472   {                                                                           \
473     if (IS_FROM_TU (dat))                                                     \
474       {                                                                       \
475         VALUE_TEXT_TU (str);                                                  \
476       }                                                                       \
477     else                                                                      \
478       {                                                                       \
479         VALUE_TEXT (str)                                                      \
480       }                                                                       \
481   }
482 #define _FIELD_TV_ALPHA(nam, str)                                             \
483   if ((str) && isalpha (*(str)))                                              \
484     {                                                                         \
485       FIELD_TEXT (nam, str)                                                   \
486     }
487 #define FIELD_BT(nam, dxf) FIELD (nam, BT, dxf);
488 #define FIELD_4BITS(nam, dxf) FIELD (nam, 4BITS, dxf)
489 #define FIELD_BE(nam, dxf) FIELD_3RD (nam, dxf)
490 #define FIELD_DD(nam, _default, dxf) FIELD_BD (nam, dxf)
491 #define FIELD_2BD(nam, dxf) FIELD_2RD (nam, dxf)
492 #define FIELD_2BD_1(nam, dxf) FIELD_2RD (nam, dxf)
493 #define FIELD_2DD(nam, def, dxf) FIELD_2RD (nam, dxf)
494 #define FIELD_3DD(nam, def, dxf) FIELD_3RD (nam, dxf)
495 #define FIELD_3BD(nam, dxf) FIELD_3RD (nam, dxf)
496 #define FIELD_3BD_1(nam, dxf) FIELD_3RD (nam, dxf)
497 #define FIELD_3DPOINT(nam, dxf) FIELD_3BD (nam, dxf)
498 
499 #define SUB_FIELD_T(o, nam, dxf)                                              \
500   {                                                                           \
501     if (IS_FROM_TU (dat))                                                     \
502       {                                                                       \
503         KEY (nam);                                                            \
504         VALUE_TEXT_TU ((BITCODE_TU)_obj->o.nam);                              \
505       }                                                                       \
506     else                                                                      \
507       {                                                                       \
508         PRINTFIRST;                                                           \
509         PREFIX fprintf (dat->fh, "\"" #nam "\": \"%s\"", _obj->o.nam);        \
510       }                                                                       \
511   }
512 #define SUB_FIELD_B(o, nam, dxf) SUB_FIELD (o, nam, B, dxf)
513 #define SUB_FIELD_BB(o, nam, dxf) SUB_FIELD (o, nam, BB, dxf)
514 #define SUB_FIELD_3B(o, nam, dxf) SUB_FIELD (o, nam, 3B, dxf)
515 #define SUB_FIELD_BS(o, nam, dxf) SUB_FIELD (o, nam, BS, dxf)
516 #define SUB_FIELD_BSd(o, nam, dxf) SUB_FIELD (o, nam, BSd, dxf)
517 #define SUB_FIELD_BL(o, nam, dxf) SUB_FIELD (o, nam, BL, dxf)
518 #define SUB_FIELD_BLx(o, nam, dxf) SUB_FIELD (o, nam, BLx, dxf)
519 #define SUB_FIELD_BLd(o, nam, dxf) SUB_FIELD (o, nam, BLd, dxf)
520 #define SUB_FIELD_RC(o, nam, dxf) SUB_FIELD (o, nam, RC, dxf)
521 #define SUB_FIELD_RS(o, nam, dxf) SUB_FIELD (o, nam, RS, dxf)
522 #define SUB_FIELD_RL(o, nam, dxf) SUB_FIELD (o, nam, RL, dxf)
523 #define SUB_FIELD_BLL(o, nam, dxf) SUB_FIELD (o, nam, BLL, dxf)
524 #define SUB_FIELD_RLL(o, nam, dxf) SUB_FIELD (o, nam, RLL, dxf)
525 
526 #define SUB_FIELD_RD(o, nam, dxf) SUB_FIELD_BD (o, nam, dxf)
527 #define SUB_FIELD_3BD_inl(o, nam, dxf)                                        \
528   SUB_FIELD_RD (o, x, dxf);                                                   \
529   SUB_FIELD_RD (o, y, dxf);                                                   \
530   SUB_FIELD_RD (o, z, dxf)
531 #define SUB_FIELD_2BD(o, nam, dxf)                                            \
532   KEY (nam);                                                                  \
533   VALUE_2RD (_obj->o.nam, dxf)
534 #define SUB_FIELD_2BD_1(o, nam, dxf)                                          \
535   KEY (nam);                                                                  \
536   VALUE_2RD (_obj->o.nam, dxf)
537 #define SUB_FIELD_2RD(o, nam, dxf)                                            \
538   KEY (nam);                                                                  \
539   VALUE_2RD (_obj->o.nam, dxf)
540 #define SUB_FIELD_3RD(o, nam, dxf)                                            \
541   KEY (nam);                                                                  \
542   VALUE_3RD (_obj->o.nam, dxf)
543 #define SUB_FIELD_3BD(o, nam, dxf)                                            \
544   KEY (nam);                                                                  \
545   VALUE_3RD (_obj->o.nam, dxf)
546 #define SUB_FIELD_3DPOINT(o, nam, dxf)                                        \
547   KEY (nam);                                                                  \
548   VALUE_3RD (_obj->o.nam, dxf)
549 
550 static void
field_cmc(Bit_Chain * dat,const char * restrict key,const Dwg_Color * restrict _obj)551 field_cmc (Bit_Chain *dat, const char *restrict key,
552            const Dwg_Color *restrict _obj)
553 {
554   if (dat->version >= R_2004)
555     {
556       KEYs (_path_field(key));
557       HASH;
558       if (_obj->index)
559         {
560           FIELD_BS (index, 62);
561         }
562       FIRSTPREFIX fprintf (dat->fh, "\"rgb\": \"%06x\"", (unsigned)_obj->rgb);
563       if (_obj->flag)
564         {
565           FIELD_BS (flag, 0);
566         }
567       if (_obj->flag > 0 && _obj->flag < 8)
568         {
569           if (_obj->flag & 1)
570             _FIELD_TV_ALPHA (name, _obj->name)
571           if (_obj->flag & 2)
572             _FIELD_TV_ALPHA (book_name, _obj->book_name)
573         }
574       ENDHASH;
575     }
576   else
577     {
578       FIRSTPREFIX fprintf (dat->fh, "\"%s\": %d", _path_field (key),
579                            _obj->index);
580     }
581 }
582 
583 #define FIELD_CMC(color, dxf) field_cmc (dat, #color, &_obj->color)
584 #define SUB_FIELD_CMC(o, color, dxf)                                          \
585   field_cmc (dat, #color, &_obj->o.color)
586 
587 #define FIELD_TIMEBLL(nam, dxf)                                               \
588   FIRSTPREFIX fprintf (dat->fh,                                               \
589                   "\"" #nam "\": [ " FORMAT_BL ", " FORMAT_BL " ]",           \
590                   _obj->nam.days, _obj->nam.ms)
591 #define FIELD_TIMERLL(nam, dxf) FIELD_TIMEBLL (nam, dxf)
592 
593 // FIELD_VECTOR_N(nam, type, size):
594 // reads data of the type indicated by 'type' 'size' times and stores
595 // it all in the vector called 'nam'.
596 #define FIELD_VECTOR_N(nam, type, size, dxf)                                  \
597   KEY (nam);                                                                  \
598   ARRAY;                                                                      \
599   if (_obj->nam)                                                              \
600     {                                                                         \
601       for (vcount = 0; vcount < (BITCODE_BL)size; vcount++)                   \
602         {                                                                     \
603           FIRSTPREFIX fprintf (dat->fh, FORMAT_##type, _obj->nam[vcount]); \
604         }                                                                     \
605     }                                                                         \
606   else                                                                        \
607     FIRSTPREFIX                                                               \
608   ENDARRAY;
609 #define SUB_FIELD_VECTOR_N(o, nam, type, size, dxf)                           \
610   KEY (nam);                                                                  \
611   ARRAY;                                                                      \
612   if (_obj->o.nam)                                                              \
613     {                                                                         \
614       for (vcount = 0; vcount < (BITCODE_BL)size; vcount++)                   \
615         {                                                                     \
616           FIRSTPREFIX fprintf (dat->fh, FORMAT_##type, _obj->o.nam[vcount]);  \
617         }                                                                     \
618     }                                                                         \
619   else                                                                        \
620     FIRSTPREFIX                                                               \
621   ENDARRAY;
622 #define FIELD_VECTOR_T(nam, type, size, dxf)                                  \
623   KEY (nam);                                                                  \
624   ARRAY;                                                                      \
625   if (_obj->nam)                                                              \
626     {                                                                         \
627       BITCODE_BL _size = (BITCODE_BL)_obj->size;                              \
628       if (IS_FROM_TU (dat))                                                   \
629       {                                                                       \
630         for (vcount = 0; vcount < _size; vcount++)                            \
631           {                                                                   \
632             FIRSTPREFIX VALUE_TEXT_TU (_obj->nam[vcount]);                    \
633           }                                                                   \
634       }                                                                       \
635       else                                                                    \
636       {                                                                       \
637         for (vcount = 0; vcount < _size; vcount++)                            \
638           {                                                                   \
639             FIRSTPREFIX VALUE_TEXT (_obj->nam[vcount])                        \
640           }                                                                   \
641       }                                                                       \
642     }                                                                         \
643   else                                                                        \
644     FIRSTPREFIX                                                               \
645   ENDARRAY;
646 
647 #define SUB_FIELD_VECTOR_TYPESIZE(o, nam, size, typesize, dxf)                \
648   KEY (nam);                                                                  \
649   ARRAY;                                                                      \
650   if (_obj->o.size && _obj->o.nam)                                            \
651     {                                                                         \
652       for (vcount = 0; vcount < (BITCODE_BL)_obj->o.size; vcount++)           \
653         {                                                                     \
654           switch (typesize)                                                   \
655             {                                                                 \
656             case 0:                                                           \
657               break;                                                          \
658             case 1:                                                           \
659               FIRSTPREFIX fprintf (dat->fh, FORMAT_RC,                        \
660                                    (BITCODE_RC)_obj->o.nam[vcount]);          \
661               break;                                                          \
662             case 2:                                                           \
663               FIRSTPREFIX fprintf (dat->fh, FORMAT_RS,                        \
664                                    (BITCODE_RS)_obj->o.nam[vcount]);          \
665               break;                                                          \
666             case 4:                                                           \
667               FIRSTPREFIX fprintf (dat->fh, FORMAT_RL,                        \
668                                    (BITCODE_RL)_obj->o.nam[vcount]);          \
669               break;                                                          \
670             case 8:                                                           \
671               FIRSTPREFIX fprintf (dat->fh, FORMAT_RLL,                       \
672                                    (BITCODE_RLL)_obj->o.nam[vcount]);         \
673               break;                                                          \
674             default:                                                          \
675               LOG_ERROR ("Unkown SUB_FIELD_VECTOR_TYPESIZE " #nam             \
676                          " typesize %d", typesize);                           \
677               break;                                                          \
678             }                                                                 \
679         }                                                                     \
680     }                                                                         \
681   else                                                                        \
682     FIRSTPREFIX                                                               \
683   ENDARRAY;
684 
685 #define FIELD_VECTOR(nam, type, size, dxf)                                    \
686   FIELD_VECTOR_N (nam, type, _obj->size, dxf)
687 #define FIELD_VECTOR_INL(nam, type, size, dxf)                                \
688   FIELD_VECTOR_N(nam, type, size, dxf)
689 
690 #define FIELD_2RD_VECTOR(nam, size, dxf)                                      \
691   if (_obj->nam)                                                              \
692   {                                                                           \
693     KEY (nam);                                                                \
694     ARRAY;                                                                    \
695     for (vcount = 0; vcount < (BITCODE_BL)_obj->size; vcount++)               \
696       {                                                                       \
697         FIRSTPREFIX VALUE_2RD (FIELD_VALUE (nam[vcount]), dxf);                \
698       }                                                                       \
699     ENDARRAY;                                                                 \
700   }
701 
702 #define FIELD_2DD_VECTOR(nam, size, dxf)                                      \
703   if (_obj->nam)                                                              \
704   {                                                                           \
705     KEY (nam);                                                                \
706     ARRAY;                                                                    \
707     for (vcount = 0; vcount < (BITCODE_BL)_obj->size; vcount++)               \
708       {                                                                       \
709         FIRSTPREFIX VALUE_2RD (_obj->nam[vcount], dxf);                       \
710       }                                                                       \
711     ENDARRAY;                                                                 \
712   }
713 
714 #define FIELD_3DPOINT_VECTOR(nam, size, dxf)                                  \
715   if (_obj->nam)                                                              \
716   {                                                                           \
717     KEY (nam);                                                                \
718     ARRAY;                                                                    \
719     for (vcount = 0; vcount < (BITCODE_BL)_obj->size; vcount++)               \
720       {                                                                       \
721         FIRSTPREFIX VALUE_3BD (FIELD_VALUE (nam[vcount]), dxf);               \
722       }                                                                       \
723     ENDARRAY;                                                                 \
724   }
725 
726 #define HANDLE_VECTOR_N(nam, size, code, dxf)                                 \
727   if (_obj->nam)                                                              \
728   {                                                                           \
729     KEY (nam);                                                                \
730     ARRAY;                                                                    \
731     for (vcount = 0; vcount < (BITCODE_BL)size; vcount++)                     \
732       {                                                                       \
733         FIELD_HANDLE_N (nam[vcount], vcount, code, dxf);                      \
734       }                                                                       \
735     ENDARRAY;                                                                 \
736   }
737 
738 #define HANDLE_VECTOR(nam, sizefield, code, dxf)                              \
739   HANDLE_VECTOR_N (nam, FIELD_VALUE (sizefield), code, dxf)
740 
741 #define SUB_HANDLE_VECTOR(o, nam, size, code, dxf)                            \
742   KEY (nam);                                                                  \
743   if (_obj->o.nam)                                                            \
744     {                                                                         \
745       ARRAY;                                                                  \
746       for (vcount = 0; vcount < (BITCODE_BL)_obj->o.size; vcount++)           \
747         {                                                                     \
748           SUB_FIELD_HANDLE_N (o, nam[vcount], code, dxf);                     \
749         }                                                                     \
750       ENDARRAY;                                                               \
751     }                                                                         \
752   else                                                                        \
753     {                                                                         \
754       ARRAY;                                                                  \
755       ENDARRAY;                                                               \
756     }
757 
758 #define REACTORS(code)                                                        \
759   if (dat->version >= R_13 && obj->tio.object->num_reactors                   \
760       && obj->tio.object->reactors)                                           \
761     {                                                                         \
762       KEY (reactors);                                                         \
763       ARRAY;                                                                  \
764       for (vcount = 0; vcount < obj->tio.object->num_reactors; vcount++)      \
765         {                                                                     \
766           FIRSTPREFIX VALUE_HANDLE (obj->tio.object->reactors[vcount], reactors, \
767                                     code, 330);                               \
768         }                                                                     \
769       ENDARRAY;                                                               \
770     }
771 #define ENT_REACTORS(code)                                                    \
772   if (dat->version >= R_13 && ent->num_reactors && ent->reactors)             \
773     {                                                                         \
774       KEY (reactors);                                                         \
775       ARRAY;                                                                  \
776       for (vcount = 0; vcount < ent->num_reactors; vcount++)                  \
777         {                                                                     \
778           FIRSTPREFIX VALUE_HANDLE (ent->reactors[vcount], reactors, code, 330);   \
779         }                                                                     \
780       ENDARRAY;                                                               \
781     }
782 
783 // violates duplicate keys
784 #define SUBCLASS(name) \
785   FIRSTPREFIX fprintf (dat->fh, "\"_subclass\": \"" #name "\"");
786 
787 // FIXME: for KEY not the complete nam path, only the field.
788 // e.g. verts[rcount1].lines[rcount2].segparms
789 #define _REPEAT_N(times, nam, type, idx)                                      \
790   if (_obj->nam)                                                              \
791     {                                                                         \
792       KEY (nam);                                                              \
793       ARRAY;                                                                  \
794       for (rcount##idx = 0; rcount##idx < (BITCODE_BL)times; rcount##idx++)   \
795         {
796 #define REPEAT_N(times, nam, type) _REPEAT_N(times, nam, type, 1)
797 #define REPEAT_CN(times, nam, type) REPEAT_N(times, nam, type)
798 #define _REPEAT_C(times, nam, type, idx) _REPEAT_N (_obj->times, nam, type, idx)
799 #define _REPEAT(times, nam, type, idx) _REPEAT_N (_obj->times, nam, type, idx)
800 #define REPEAT(times, nam, type) _REPEAT (times, nam, type, 1)
801 #define REPEAT2(times, nam, type) _REPEAT (times, nam, type, 2)
802 #define REPEAT3(times, nam, type) _REPEAT (times, nam, type, 3)
803 #define REPEAT4(times, nam, type) _REPEAT (times, nam, type, 4)
804 #define REPEAT_C(times, nam, type) _REPEAT_C (times, nam, type, 1)
805 #define REPEAT2_C(times, nam, type) _REPEAT_C (times, nam, type, 2)
806 #define REPEAT3_C(times, nam, type) _REPEAT_C (times, nam, type, 3)
807 #define REPEAT4_C(times, nam, type) _REPEAT_C (times, nam, type, 4)
808 #define _REPEAT_CN(times, nam, type, idx) _REPEAT_N (times, nam, type, idx)
809 #define _REPEAT_CNF(times, nam, type, idx) _REPEAT_N (times, nam, type, idx)
810 #define _REPEAT_NF(times, nam, type, idx) _REPEAT_N (times, nam, type, idx)
811 
812 #undef REPEAT_BLOCK
813 #define REPEAT_BLOCK                                                          \
814     FIRSTPREFIX HASH;
815 #undef END_REPEAT_BLOCK
816 #define END_REPEAT_BLOCK                                                      \
817     ENDHASH;
818 #undef END_REPEAT
819 #define END_REPEAT(nam)                                                       \
820       }                                                                       \
821       ENDARRAY;                                                               \
822     }
823 
824 #define FIELD_NUM_INSERTS(num_inserts, type, dxf)                             \
825   FIELD (num_inserts, type, dxf)
826 
827 #define FIELD_XDATA(nam, size)                                                \
828   error |= json_xdata (dat, _obj)
829 
830 #define XDICOBJHANDLE(code)                                                   \
831   if ((dat->version < R_2004 || obj->tio.object->is_xdic_missing != 0)      \
832       && (obj->tio.object->xdicobjhandle != NULL)                             \
833       && (obj->tio.object->xdicobjhandle->handleref.value != 0))              \
834     {                                                                         \
835       KEY (xdicobjhandle);                                                    \
836       VALUE_HANDLE (obj->tio.object->xdicobjhandle, xdicobjhandle, code, -3); \
837     }
838 #define ENT_XDICOBJHANDLE(code)                                               \
839   if ((dat->version < R_2004 || (ent->is_xdic_missing != 0))                \
840       && (ent->xdicobjhandle != NULL)                                         \
841       && (ent->xdicobjhandle->handleref.value != 0))                          \
842     {                                                                         \
843       KEY (xdicobjhandle);                                                    \
844       VALUE_HANDLE (ent->xdicobjhandle, xdicobjhandle, code, -3);             \
845     }
846 
847 #define COMMON_ENTITY_HANDLE_DATA
848 #define SECTION_STRING_STREAM
849 #define START_STRING_STREAM
850 #define END_STRING_STREAM
851 #define START_HANDLE_STREAM
852 #define START_OBJECT_HANDLE_STREAM
853 #define CONTROL_HANDLE_STREAM
854 
855 static void
_prefix(Bit_Chain * dat)856 _prefix (Bit_Chain *dat)
857 {
858   for (int _i = 0; _i < dat->bit; _i++)
859     {
860       fprintf (dat->fh, "  ");
861     }
862 }
863 
864 #define DWG_ENTITY(token)                                                     \
865   static int dwg_json_##token##_private (                                     \
866       Bit_Chain *dat, Bit_Chain *hdl_dat, Bit_Chain *str_dat,                 \
867       Dwg_Object *restrict obj);                                              \
868   GCC30_DIAG_IGNORE (-Wshadow)                                                \
869   static int dwg_json_##token (Bit_Chain *restrict dat,                       \
870                                Dwg_Object *restrict obj)                      \
871   {                                                                           \
872     int error = 0;                                                            \
873     Bit_Chain *str_dat = dat;                                                 \
874     Bit_Chain *hdl_dat = dat;                                                 \
875     Dwg_Data *dwg = obj->parent;                                              \
876     Dwg_Entity_##token *ent, *_obj;                                           \
877     Dwg_Object_Entity *_ent;                                                  \
878     const char *name = #token;                                                \
879     LOG_INFO ("Entity " #token ":\n")                                         \
880     _ent = obj->tio.entity;                                                   \
881     _obj = ent = _ent->tio.token;                                             \
882     if (*name == '_')                                                         \
883       FIELD_TEXT (entity, &name[1])                                           \
884     else                                                                      \
885       FIELD_TEXT (entity, name)                                               \
886     if (obj->dxfname && strNE (obj->dxfname, #token))                         \
887       FIELD_TEXT (dxfname, obj->dxfname);                                     \
888     _FIELD (index, RL, 0);                                                    \
889     _FIELD (type, RL, 0);                                                     \
890     KEY (handle);                                                             \
891     VALUE_H (obj->handle, 5);                                                 \
892     _FIELD (size, RL, 0);                                                     \
893     _FIELD (bitsize, BL, 0);                                                  \
894     if (_ent->preview_exists)                                                 \
895       ENT_FIELD (preview_exists, B, 0);                                       \
896     error |= json_common_entity_data (dat, obj);                              \
897     return error | dwg_json_##token##_private (dat, hdl_dat, str_dat, obj);   \
898   }                                                                           \
899   static int dwg_json_##token##_private (                                     \
900         Bit_Chain *dat, Bit_Chain *hdl_dat, Bit_Chain *str_dat,               \
901         Dwg_Object *restrict obj)                                             \
902   {                                                                           \
903     int error = 0;                                                            \
904     BITCODE_BL vcount, rcount3, rcount4;                                      \
905     Dwg_Data *dwg = obj->parent;                                              \
906     Dwg_Object_Entity *_ent = obj->tio.entity;                                \
907     Dwg_Entity_##token *_obj = _ent->tio.token;
908 
909 #define DWG_ENTITY_END                                                        \
910     return error;                                                             \
911   }
912 
913 #define DWG_OBJECT(token)                                                     \
914   static int dwg_json_##token##_private (                                     \
915       Bit_Chain *dat, Bit_Chain *hdl_dat, Bit_Chain *str_dat,                 \
916       Dwg_Object *restrict obj);                                              \
917   GCC30_DIAG_IGNORE (-Wshadow)                                                \
918   static int dwg_json_##token (Bit_Chain *restrict dat,                       \
919                                Dwg_Object *restrict obj)                      \
920   {                                                                           \
921     int error = 0;                                                            \
922     Bit_Chain *str_dat = dat;                                                 \
923     Bit_Chain *hdl_dat = dat;                                                 \
924     const char *name = #token;                                                \
925     Dwg_Object_##token *_obj;                                                 \
926     LOG_INFO ("Object "#token ":\n")                                          \
927     _obj = obj->tio.object->tio.token;                                        \
928     if (*name == '_')                                                         \
929       FIELD_TEXT (object, &name[1])                                           \
930     else                                                                      \
931       FIELD_TEXT (object, name)                                               \
932     if (obj->dxfname && strNE (obj->dxfname, #token))                         \
933       FIELD_TEXT (dxfname, obj->dxfname);                                     \
934     _FIELD (index, RL, 0);                                                    \
935     _FIELD (type, RL, 0);                                                     \
936     KEY (handle);                                                             \
937     VALUE_H (obj->handle, 5);                                                 \
938     _FIELD (size, RL, 0);                                                     \
939     _FIELD (bitsize, BL, 0);                                                  \
940     error |= json_eed (dat, obj->tio.object);                                 \
941     error |= json_common_object_handle_data (dat, obj);                       \
942     return error | dwg_json_##token##_private (dat, hdl_dat, str_dat, obj);   \
943   }                                                                           \
944   static int dwg_json_##token##_private (                                     \
945         Bit_Chain *dat, Bit_Chain *hdl_dat, Bit_Chain *str_dat,               \
946         Dwg_Object *restrict obj)                                             \
947   {                                                                           \
948     int error = 0;                                                            \
949     BITCODE_BL vcount, rcount3, rcount4;                                      \
950     Dwg_Data *dwg = obj->parent;                                              \
951     Dwg_Object_##token *_obj = obj->tio.object->tio.token;
952 
953 #define DWG_OBJECT_END                                                        \
954     return 0;                                                                 \
955   }
956 
957 #undef JSON_3DSOLID
958 #define JSON_3DSOLID json_3dsolid (dat, obj, (Dwg_Entity_3DSOLID *)_obj);
959 
_path_field(const char * path)960 static char* _path_field(const char *path)
961 {
962   const char *s = strrchr (path, ']');
963   if (s && s[1] == '.')
964     {
965       return (char*)&s[2];
966     }
967   return (char*)path;
968 }
969 
970 static int
json_eed(Bit_Chain * restrict dat,const Dwg_Object_Object * restrict obj)971 json_eed (Bit_Chain *restrict dat,
972           const Dwg_Object_Object *restrict obj)
973 {
974   int error = 0;
975   if (!obj->num_eed)
976     return 0;
977   KEY (eed);
978   ARRAY;
979   for (BITCODE_BL i = 0; i < obj->num_eed; i++)
980     {
981       const Dwg_Eed* _obj = &obj->eed[i];
982       FIRSTPREFIX HASH;
983       if (_obj->size)
984         {
985           FIELD (size, RS, 0);
986           KEY (handle);
987           fprintf (dat->fh, FORMAT_H, ARGS_H (_obj->handle));
988         }
989       if (_obj->data)
990         {
991           const Dwg_Eed_Data *data = _obj->data;
992           KEY (code); VALUE_RC (data->code, 0);
993           KEY (value);
994           switch (data->code)
995             {
996             case 0:
997               if (!data->u.eed_0.is_tu)
998                 VALUE_TEXT (data->u.eed_0.string)
999               else {
1000                 VALUE_TEXT_TU (data->u.eed_0_r2007.string);
1001               }
1002               break;
1003             case 2: VALUE_RC (data->u.eed_2.close, 0); break;
1004             case 3: VALUE_RLL (data->u.eed_3.layer, 0); break;
1005             case 4: VALUE_BINARY (data->u.eed_4.data, data->u.eed_4.length, 0); break;
1006             case 5: fprintf (dat->fh, FORMAT_H "", 5, data->u.eed_5.entity); break;
1007             case 10:
1008             case 11:
1009             case 12:
1010             case 13:
1011             case 14:
1012             case 15:
1013                     VALUE_3RD (data->u.eed_10.point, 0); break;
1014             case 40:
1015             case 41:
1016             case 42:
1017                     VALUE_RD (data->u.eed_40.real, 0); break;
1018             case 70: VALUE_RS (data->u.eed_70.rs, 0); break;
1019             case 71: VALUE_RL (data->u.eed_71.rl, 0); break;
1020             default: VALUE_RC (0, 0);
1021             }
1022         }
1023       ENDHASH
1024     }
1025   ENDARRAY;
1026   return error;
1027 }
1028 
1029 static int
json_xdata(Bit_Chain * restrict dat,const Dwg_Object_XRECORD * restrict obj)1030 json_xdata (Bit_Chain *restrict dat, const Dwg_Object_XRECORD *restrict obj)
1031 {
1032   int error = 0;
1033   Dwg_Resbuf *rbuf = obj->xdata;
1034   KEY (xdata);
1035   ARRAY;
1036   for (BITCODE_BL i = 0; i < obj->num_xdata; i++)
1037     {
1038       enum RESBUF_VALUE_TYPE type;
1039       FIRSTPREFIX ARRAY;
1040       FIRSTPREFIX VALUE_RS (rbuf->type, 0);
1041       FIRSTPREFIX
1042       type = dwg_resbuf_value_type (rbuf->type);
1043       switch (type)
1044         {
1045         case DWG_VT_STRING:
1046           if (!rbuf->value.str.is_tu)
1047             {
1048               VALUE_TEXT (rbuf->value.str.u.data);
1049               LOG_TRACE ("xdata[%u]: \"%s\" [TV %d]\n", i, rbuf->value.str.u.data,
1050                          rbuf->type);
1051             }
1052           else
1053             {
1054               VALUE_TEXT_TU (rbuf->value.str.u.data);
1055               LOG_TRACE_TU ("xdata", rbuf->value.str.u.data, rbuf->type);
1056             }
1057           break;
1058         case DWG_VT_BINARY:
1059           VALUE_BINARY (rbuf->value.str.u.data, rbuf->value.str.size, 0);
1060           LOG_TRACE ("xdata[%u]: \"%s\" [TF %d]\n", i, rbuf->value.str.u.data,
1061                      rbuf->type);
1062           break;
1063         case DWG_VT_REAL:
1064           VALUE_RD (rbuf->value.dbl, 0);
1065           LOG_TRACE ("xdata[%u]: %f [RD %d]\n", i, rbuf->value.dbl,
1066                      rbuf->type);
1067           break;
1068         case DWG_VT_BOOL:
1069         case DWG_VT_INT8:
1070           VALUE_RC (rbuf->value.i8, 0);
1071           LOG_TRACE ("xdata[%u]: %d [RC %d]\n", i, (int)rbuf->value.i8,
1072                      rbuf->type);
1073           break;
1074         case DWG_VT_INT16:
1075           VALUE_RS (rbuf->value.i16, 0);
1076           LOG_TRACE ("xdata[%u]: %d [RS %d]\n", i, (int)rbuf->value.i16,
1077                      rbuf->type);
1078           break;
1079         case DWG_VT_INT32:
1080           VALUE_RL (rbuf->value.i32, 0);
1081           LOG_TRACE ("xdata[%u]: %d [RL %d]\n", i, (int)rbuf->value.i32,
1082                      rbuf->type);
1083           break;
1084         case DWG_VT_INT64:
1085           VALUE_RLL (rbuf->value.i64, 0);
1086           LOG_TRACE ("xdata[%u]: %ld [RLL %d]\n", i, (long)rbuf->value.i64,
1087                      rbuf->type);
1088           break;
1089         case DWG_VT_POINT3D:
1090           fprintf (dat->fh, "[ " FORMAT_RD ", " FORMAT_RD ", " FORMAT_RD " ]",
1091                    rbuf->value.pt[0], rbuf->value.pt[1], rbuf->value.pt[2]);
1092           LOG_TRACE ("xdata[%u]: (%f,%f,%f) [3RD %d]\n", i, rbuf->value.pt[0],
1093                      rbuf->value.pt[1], rbuf->value.pt[2], rbuf->type);
1094           break;
1095         case DWG_VT_HANDLE:
1096         case DWG_VT_OBJECTID:
1097           fprintf (dat->fh, FORMAT_H "", ARGS_H (rbuf->value.h));
1098           break;
1099         case DWG_VT_INVALID:
1100         default:
1101           break;
1102         }
1103       rbuf = rbuf->nextrb;
1104       ENDARRAY
1105     }
1106   ENDARRAY;
1107   return error;
1108 }
1109 
1110 static int
json_common_entity_data(Bit_Chain * restrict dat,const Dwg_Object * restrict obj)1111 json_common_entity_data (Bit_Chain *restrict dat,
1112                          const Dwg_Object *restrict obj)
1113 {
1114   Dwg_Object_Entity *ent, *_obj;
1115   // Dwg_Data *dwg = obj->parent;
1116   int error = 0;
1117   BITCODE_BL vcount = 0;
1118   ent = obj->tio.entity;
1119   _obj = ent;
1120 
1121   error |= json_eed (dat, (Dwg_Object_Object *)ent);
1122 
1123   // clang-format off
1124   #include "common_entity_handle_data.spec"
1125   #include "common_entity_data.spec"
1126   // clang-format on
1127 
1128   return error;
1129 }
1130 
1131 static int
json_common_object_handle_data(Bit_Chain * restrict dat,const Dwg_Object * restrict obj)1132 json_common_object_handle_data (Bit_Chain *restrict dat,
1133                                 const Dwg_Object *restrict obj)
1134 {
1135   Dwg_Object_Object *_obj;
1136   Dwg_Data *dwg = obj->parent;
1137   int error = 0;
1138   BITCODE_BL vcount = 0;
1139   _obj = obj->tio.object;
1140 
1141   // clang-format off
1142   #include "common_object_handle_data.spec"
1143   // clang-format on
1144   return error;
1145 }
1146 
1147 #include "dwg.spec"
1148 
ishex(int c)1149 static int ishex (int c)
1150 {
1151   return ((c >= '0' && c <= '9') || (c >= 'a' && c <= 'f')
1152           || (c >= 'A' && c <= 'F'));
1153 }
1154 // Usage: hex(c >> 4), hex(c & 0xf)
hex(unsigned char c)1155 static int hex (unsigned char c)
1156 {
1157   c &= 0xf; // 0-15
1158   return c >= 10 ? 'a' + c - 10 : '0' + c;
1159 }
1160 
1161 #ifndef HAVE_NATIVE_WCHAR2
1162 
1163 static void
print_wcquote(Bit_Chain * restrict dat,dwg_wchar_t * restrict wstr)1164 print_wcquote (Bit_Chain *restrict dat, dwg_wchar_t *restrict wstr)
1165 {
1166   BITCODE_TU ws = (BITCODE_TU)wstr;
1167   uint16_t c;
1168   if (!ws)
1169     {
1170       fprintf (dat->fh, "\"\"");
1171       return;
1172     }
1173   fprintf (dat->fh, "\"");
1174   while (1)
1175     {
1176 #ifdef HAVE_ALIGNED_ACCESS_REQUIRED
1177       // for strict alignment CPU's like sparc only. also for UBSAN.
1178       if ((uintptr_t)wstr % SIZEOF_SIZE_T)
1179         {
1180           unsigned char *b = (unsigned char *)ws;
1181           c = TU_to_int(b);
1182           ws++;
1183         }
1184       else
1185 #endif
1186         c = *ws++;
1187       if (!c)
1188         break;
1189       if (c == L'"')
1190         {
1191           fprintf (dat->fh, "\\\"");
1192         }
1193       else if (c == L'\\' && ws[0] == L'U' && ws[1] == L'+' && ishex (ws[2])
1194                && ishex (ws[3]) && ishex (ws[4]) && ishex (ws[5]))
1195         {
1196           fprintf (dat->fh, "\\u");
1197           ws += 2;
1198         }
1199       else if (c == L'\\')
1200         {
1201           fprintf (dat->fh, "\\\\");
1202         }
1203       else if (c == L'\n')
1204         {
1205           fprintf (dat->fh, "\\n");
1206         }
1207       else if (c == L'\r')
1208         {
1209           fprintf (dat->fh, "\\r");
1210         }
1211       else if (c < 0x1f || c > 0xff)
1212         {
1213           // FIXME: handle surrogate pairs properly
1214           if (c >= 0xd800 && c < 0xdc00)
1215             {
1216               fprintf (dat->fh, "\\u%04x", c - 0x1000);
1217             }
1218           else if (c >= 0xdc00 && c < 0xe000)
1219             ;
1220           else
1221             fprintf (dat->fh, "\\u%04x", c);
1222         }
1223       else
1224         fprintf (dat->fh, "%c", (char)(c & 0xff));
1225     }
1226   fprintf (dat->fh, "\"");
1227 }
1228 
1229 #else
1230 
1231 static wchar_t *
wcquote(wchar_t * restrict dest,const wchar_t * restrict src)1232 wcquote (wchar_t *restrict dest, const wchar_t *restrict src)
1233 {
1234   wchar_t c;
1235   wchar_t *d = dest;
1236   wchar_t *s = (wchar_t *)src;
1237   while ((c = *s++))
1238     {
1239       if (c == L'"')
1240         {
1241           *dest++ = L'\\';
1242           *dest++ = c;
1243         }
1244       else if (c == L'\\' && s[0] == L'U' && s[1] == L'+' && ishex (s[2])
1245                && ishex (s[3]) && ishex (s[4]) && ishex (s[5]))
1246         {
1247           *dest++ = '\\';
1248           *dest++ = 'u';
1249           s += 2;
1250         }
1251       else if (c == L'\\')
1252         {
1253           *dest++ = L'\\';
1254           *dest++ = c;
1255         }
1256       else if (c == L'\n')
1257         {
1258           *dest++ = L'\\';
1259           *dest++ = L'n';
1260         }
1261       else if (c == L'\r')
1262         {
1263           *dest++ = L'\\';
1264           *dest++ = L'r';
1265         }
1266       else if (c < 0x1f)
1267         {
1268           *dest++ = L'\\';
1269           *dest++ = L'u';
1270           *dest++ = L'0';
1271           *dest++ = L'0';
1272           *dest++ = hex (c >> 4);
1273           *dest++ = hex (c & 0xf);
1274         }
1275       else
1276         *dest++ = c;
1277     }
1278   *dest = 0; // add final delim, skipped above
1279   return d;
1280 }
1281 
1282 #endif /* HAVE_NATIVE_WCHAR2 */
1283 
1284 char *
json_cquote(char * restrict dest,const char * restrict src,const int len)1285 json_cquote (char *restrict dest, const char *restrict src, const int len)
1286 {
1287   unsigned char c;
1288   unsigned char *s = (unsigned char *)src;
1289   const char* endp = dest + len;
1290   char *d = dest;
1291   while ((c = *s++))
1292     {
1293       if (dest >= endp)
1294         {
1295           *dest = 0;
1296           return d;
1297         }
1298       if (c == '"' && dest+1 < endp)
1299         {
1300           *dest++ = '\\';
1301           *dest++ = c;
1302         }
1303       else if (c == '\\' && dest+2 < endp)
1304         {
1305           if (dest+5 < endp && s[0] == 'U' && s[1] == '+' && ishex (s[2])
1306               && ishex (s[3]) && ishex (s[4]) && ishex (s[5]))
1307             {
1308               *dest++ = '\\';
1309               *dest++ = 'u';
1310               s += 2;
1311             }
1312           else
1313             {
1314               *dest++ = '\\';
1315               *dest++ = c;
1316             }
1317         }
1318       else if (c == '\n' && dest+1 < endp)
1319         {
1320           *dest++ = '\\';
1321           *dest++ = 'n';
1322         }
1323       else if (c == '\r' && dest+1 < endp)
1324         {
1325           *dest++ = '\\';
1326           *dest++ = 'r';
1327         }
1328       else if (c < 0x1f && dest+5 < endp)
1329         {
1330           *dest++ = '\\';
1331           *dest++ = 'u';
1332           *dest++ = '0';
1333           *dest++ = '0';
1334           *dest++ = hex (c >> 4);
1335           *dest++ = hex (c & 0xf);
1336         }
1337       else
1338         *dest++ = c;
1339     }
1340   *dest = 0; // add final delim, skipped above
1341   return d;
1342 }
1343 
1344 static int
json_3dsolid(Bit_Chain * restrict dat,const Dwg_Object * restrict obj,Dwg_Entity_3DSOLID * restrict _obj)1345 json_3dsolid (Bit_Chain *restrict dat, const Dwg_Object *restrict obj,
1346               Dwg_Entity_3DSOLID *restrict _obj)
1347 {
1348   Dwg_Data *dwg = obj->parent;
1349   BITCODE_BL vcount;
1350   BITCODE_BL i;
1351   int error = 0;
1352 
1353   FIELD_B (acis_empty, 0);
1354   if (!FIELD_VALUE (acis_empty))
1355     {
1356       char *s, *p;
1357       FIELD_B (unknown, 0);
1358       FIELD_BS (version, 70);
1359       KEY (acis_data);
1360       ARRAY;
1361       s = p = (char*)_obj->acis_data;
1362       if (!p)
1363         {
1364           FIRSTPREFIX fprintf (dat->fh, "\"\"");
1365         }
1366       else if (_obj->version < 2)
1367         { // split lines by \n
1368           for (; *p; p++)
1369             {
1370               char buf[256]; // acis lines are not much longer
1371               if (*p == '\n' && p - s < 256)
1372                 {
1373                   FIRSTPREFIX fprintf (dat->fh, "\"%s\"", json_cquote (buf, s, p - s));
1374                   s = p + 1;
1375                 }
1376             }
1377           // the remainder
1378           if (s != p && *s)
1379             {
1380               FIRSTPREFIX VALUE_TEXT (s);
1381             }
1382         }
1383       else // version 2, SAB. split into two lines for easier identification
1384         {
1385           FIRSTPREFIX fprintf (dat->fh, "\"%.*s\"", 15, _obj->acis_data);
1386           FIRSTPREFIX VALUE_BINARY (&_obj->acis_data[15], _obj->sab_size - 15, 1);
1387         }
1388       ENDARRAY;
1389       if (_obj->encr_sat_data) // dxfin/out may create this for SAB
1390         {
1391           KEY (encr_sat_data);
1392           ARRAY;
1393           for (i = 0; i < FIELD_VALUE (num_blocks); i++)
1394             {
1395               FIRSTPREFIX VALUE_BINARY (FIELD_VALUE (encr_sat_data[i]), FIELD_VALUE (block_size[i]), 1);
1396             }
1397           ENDARRAY;
1398         }
1399 
1400       FIELD_B (wireframe_data_present, 0);
1401       if (FIELD_VALUE (wireframe_data_present))
1402         {
1403           FIELD_B (point_present, 0);
1404           if (FIELD_VALUE (point_present))
1405             {
1406               FIELD_3BD (point, 0);
1407             }
1408           FIELD_BL (isolines, 0);
1409           FIELD_B (isoline_present, 0);
1410           if (FIELD_VALUE (isoline_present))
1411             {
1412               FIELD_BL (num_wires, 0);
1413               REPEAT (num_wires, wires, Dwg_3DSOLID_wire)
1414               REPEAT_BLOCK
1415                   WIRESTRUCT_fields (wires[rcount1])
1416               END_REPEAT_BLOCK
1417               SET_PARENT_OBJ (wires)
1418               END_REPEAT (wires);
1419               FIELD_BL (num_silhouettes, 0);
1420               REPEAT (num_silhouettes, silhouettes, Dwg_3DSOLID_silhouette)
1421               REPEAT_BLOCK
1422                   SUB_FIELD_BL (silhouettes[rcount1], vp_id, 0);
1423                   SUB_FIELD_3BD (silhouettes[rcount1], vp_target, 0);
1424                   SUB_FIELD_3BD (silhouettes[rcount1], vp_dir_from_target, 0);
1425                   SUB_FIELD_3BD (silhouettes[rcount1], vp_up_dir, 0);
1426                   SUB_FIELD_B (silhouettes[rcount1], vp_perspective, 0);
1427                   SUB_FIELD_B (silhouettes[rcount1], has_wires, 0);
1428                   if (_obj->silhouettes[rcount1].has_wires)
1429                     {
1430                       SUB_FIELD_BL (silhouettes[rcount1], num_wires, 0);
1431                       REPEAT2 (silhouettes[rcount1].num_wires, silhouettes[rcount1].wires, Dwg_3DSOLID_wire)
1432                       REPEAT_BLOCK
1433                           WIRESTRUCT_fields (silhouettes[rcount1].wires[rcount2])
1434                       END_REPEAT_BLOCK
1435                       SET_PARENT_OBJ (silhouettes[rcount1].wires)
1436                       END_REPEAT (silhouettes[rcount1].wires);
1437                     }
1438               END_REPEAT_BLOCK
1439               SET_PARENT_OBJ (silhouettes)
1440               END_REPEAT (silhouettes);
1441             }
1442         }
1443 
1444       FIELD_B (acis_empty_bit, 0);
1445       if (FIELD_VALUE (version) > 1) {
1446         SINCE (R_2007) {
1447           FIELD_BL (num_materials, 0);
1448           REPEAT (num_materials, materials, Dwg_3DSOLID_material)
1449           REPEAT_BLOCK
1450               SUB_FIELD_BL (materials[rcount1], array_index, 0);
1451               SUB_FIELD_BL (materials[rcount1], mat_absref, 0);   /* ?? */
1452               SUB_FIELD_HANDLE (materials[rcount1], material_handle, 5, 0);
1453           END_REPEAT_BLOCK
1454           SET_PARENT (materials, (Dwg_Entity__3DSOLID*)_obj)
1455           END_REPEAT (materials);
1456         }
1457       }
1458       SINCE (R_2013) {
1459         FIELD_B (has_revision_guid, 290);
1460         FIELD_BL (revision_major, 0);
1461         FIELD_BS (revision_minor1, 0);
1462         FIELD_BS (revision_minor2, 0);
1463         FIELD_TFFx (revision_bytes, 8, 0);
1464         dxf_3dsolid_revisionguid ((Dwg_Entity_3DSOLID*)_obj);
1465         FIELD_TV (revision_guid, 0);
1466         FIELD_BL (end_marker, 0);
1467       }
1468       COMMON_ENTITY_HANDLE_DATA;
1469       if (FIELD_VALUE (version) > 1)
1470         {
1471           SINCE (R_2007) { FIELD_HANDLE (history_id, 0, 350); }
1472         }
1473     }
1474   return error;
1475 }
1476 
1477 /* returns 0 on success
1478  */
1479 static int
dwg_json_variable_type(Dwg_Data * restrict dwg,Bit_Chain * restrict dat,Dwg_Object * restrict obj)1480 dwg_json_variable_type (Dwg_Data *restrict dwg, Bit_Chain *restrict dat,
1481                         Dwg_Object *restrict obj)
1482 {
1483   int i;
1484   Dwg_Class *klass;
1485   int is_entity;
1486 
1487   i = obj->type - 500;
1488   if (i < 0 || i >= (int)dwg->num_classes)
1489     return DWG_ERR_INVALIDTYPE;
1490 
1491   klass = &dwg->dwg_class[i];
1492   if (!klass || !klass->dxfname)
1493     return DWG_ERR_INTERNALERROR;
1494   is_entity = dwg_class_is_entity (klass);
1495 
1496   // clang-format off
1497   #include "classes.inc"
1498   // clang-format on
1499 
1500   return DWG_ERR_UNHANDLEDCLASS;
1501 }
1502 
1503 static int
dwg_json_object(Bit_Chain * restrict dat,Dwg_Object * restrict obj)1504 dwg_json_object (Bit_Chain *restrict dat, Dwg_Object *restrict obj)
1505 {
1506   int error = 0;
1507   switch (obj->type)
1508     {
1509     case DWG_TYPE_TEXT:
1510       return dwg_json_TEXT (dat, obj);
1511     case DWG_TYPE_ATTRIB:
1512       return dwg_json_ATTRIB (dat, obj);
1513     case DWG_TYPE_ATTDEF:
1514       return dwg_json_ATTDEF (dat, obj);
1515     case DWG_TYPE_BLOCK:
1516       return dwg_json_BLOCK (dat, obj);
1517     case DWG_TYPE_ENDBLK:
1518       return dwg_json_ENDBLK (dat, obj);
1519     case DWG_TYPE_SEQEND:
1520       return dwg_json_SEQEND (dat, obj);
1521     case DWG_TYPE_INSERT:
1522       return dwg_json_INSERT (dat, obj);
1523     case DWG_TYPE_MINSERT:
1524       return dwg_json_MINSERT (dat, obj);
1525     case DWG_TYPE_VERTEX_2D:
1526       return dwg_json_VERTEX_2D (dat, obj);
1527     case DWG_TYPE_VERTEX_3D:
1528       return dwg_json_VERTEX_3D (dat, obj);
1529     case DWG_TYPE_VERTEX_MESH:
1530       return dwg_json_VERTEX_MESH (dat, obj);
1531     case DWG_TYPE_VERTEX_PFACE:
1532       return dwg_json_VERTEX_PFACE (dat, obj);
1533     case DWG_TYPE_VERTEX_PFACE_FACE:
1534       return dwg_json_VERTEX_PFACE_FACE (dat, obj);
1535     case DWG_TYPE_POLYLINE_2D:
1536       return dwg_json_POLYLINE_2D (dat, obj);
1537     case DWG_TYPE_POLYLINE_3D:
1538       return dwg_json_POLYLINE_3D (dat, obj);
1539     case DWG_TYPE_ARC:
1540       return dwg_json_ARC (dat, obj);
1541     case DWG_TYPE_CIRCLE:
1542       return dwg_json_CIRCLE (dat, obj);
1543     case DWG_TYPE_LINE:
1544       return dwg_json_LINE (dat, obj);
1545     case DWG_TYPE_DIMENSION_ORDINATE:
1546       return dwg_json_DIMENSION_ORDINATE (dat, obj);
1547     case DWG_TYPE_DIMENSION_LINEAR:
1548       return dwg_json_DIMENSION_LINEAR (dat, obj);
1549     case DWG_TYPE_DIMENSION_ALIGNED:
1550       return dwg_json_DIMENSION_ALIGNED (dat, obj);
1551     case DWG_TYPE_DIMENSION_ANG3PT:
1552       return dwg_json_DIMENSION_ANG3PT (dat, obj);
1553     case DWG_TYPE_DIMENSION_ANG2LN:
1554       return dwg_json_DIMENSION_ANG2LN (dat, obj);
1555     case DWG_TYPE_DIMENSION_RADIUS:
1556       return dwg_json_DIMENSION_RADIUS (dat, obj);
1557     case DWG_TYPE_DIMENSION_DIAMETER:
1558       return dwg_json_DIMENSION_DIAMETER (dat, obj);
1559     case DWG_TYPE_POINT:
1560       return dwg_json_POINT (dat, obj);
1561     case DWG_TYPE__3DFACE:
1562       return dwg_json__3DFACE (dat, obj);
1563     case DWG_TYPE_POLYLINE_PFACE:
1564       return dwg_json_POLYLINE_PFACE (dat, obj);
1565     case DWG_TYPE_POLYLINE_MESH:
1566       return dwg_json_POLYLINE_MESH (dat, obj);
1567     case DWG_TYPE_SOLID:
1568       return dwg_json_SOLID (dat, obj);
1569     case DWG_TYPE_TRACE:
1570       return dwg_json_TRACE (dat, obj);
1571     case DWG_TYPE_SHAPE:
1572       return dwg_json_SHAPE (dat, obj);
1573     case DWG_TYPE_VIEWPORT:
1574       return dwg_json_VIEWPORT (dat, obj);
1575     case DWG_TYPE_ELLIPSE:
1576       return dwg_json_ELLIPSE (dat, obj);
1577     case DWG_TYPE_SPLINE:
1578       return dwg_json_SPLINE (dat, obj);
1579     case DWG_TYPE_REGION:
1580       return dwg_json_REGION (dat, obj);
1581     case DWG_TYPE__3DSOLID:
1582       return dwg_json__3DSOLID (dat, obj);
1583     case DWG_TYPE_BODY:
1584       return dwg_json_BODY (dat, obj);
1585     case DWG_TYPE_RAY:
1586       return dwg_json_RAY (dat, obj);
1587     case DWG_TYPE_XLINE:
1588       return dwg_json_XLINE (dat, obj);
1589     case DWG_TYPE_DICTIONARY:
1590       return dwg_json_DICTIONARY (dat, obj);
1591     case DWG_TYPE_MTEXT:
1592       return dwg_json_MTEXT (dat, obj);
1593     case DWG_TYPE_LEADER:
1594       return dwg_json_LEADER (dat, obj);
1595     case DWG_TYPE_TOLERANCE:
1596       return dwg_json_TOLERANCE (dat, obj);
1597     case DWG_TYPE_MLINE:
1598       return dwg_json_MLINE (dat, obj);
1599     case DWG_TYPE_BLOCK_CONTROL:
1600       return dwg_json_BLOCK_CONTROL (dat, obj);
1601     case DWG_TYPE_BLOCK_HEADER:
1602       return dwg_json_BLOCK_HEADER (dat, obj);
1603     case DWG_TYPE_LAYER_CONTROL:
1604       return dwg_json_LAYER_CONTROL (dat, obj);
1605     case DWG_TYPE_LAYER:
1606       return dwg_json_LAYER (dat, obj);
1607     case DWG_TYPE_STYLE_CONTROL:
1608       return dwg_json_STYLE_CONTROL (dat, obj);
1609     case DWG_TYPE_STYLE:
1610       return dwg_json_STYLE (dat, obj);
1611     case DWG_TYPE_LTYPE_CONTROL:
1612       return dwg_json_LTYPE_CONTROL (dat, obj);
1613     case DWG_TYPE_LTYPE:
1614       return dwg_json_LTYPE (dat, obj);
1615     case DWG_TYPE_VIEW_CONTROL:
1616       return dwg_json_VIEW_CONTROL (dat, obj);
1617     case DWG_TYPE_VIEW:
1618       return dwg_json_VIEW (dat, obj);
1619     case DWG_TYPE_UCS_CONTROL:
1620       return dwg_json_UCS_CONTROL (dat, obj);
1621     case DWG_TYPE_UCS:
1622       return dwg_json_UCS (dat, obj);
1623     case DWG_TYPE_VPORT_CONTROL:
1624       return dwg_json_VPORT_CONTROL (dat, obj);
1625     case DWG_TYPE_VPORT:
1626       return dwg_json_VPORT (dat, obj);
1627     case DWG_TYPE_APPID_CONTROL:
1628       return dwg_json_APPID_CONTROL (dat, obj);
1629     case DWG_TYPE_APPID:
1630       return dwg_json_APPID (dat, obj);
1631     case DWG_TYPE_DIMSTYLE_CONTROL:
1632       return dwg_json_DIMSTYLE_CONTROL (dat, obj);
1633     case DWG_TYPE_DIMSTYLE:
1634       return dwg_json_DIMSTYLE (dat, obj);
1635     case DWG_TYPE_VX_CONTROL:
1636       return dwg_json_VX_CONTROL (dat, obj);
1637     case DWG_TYPE_VX_TABLE_RECORD:
1638       return dwg_json_VX_TABLE_RECORD (dat, obj);
1639     case DWG_TYPE_GROUP:
1640       return dwg_json_GROUP (dat, obj);
1641     case DWG_TYPE_MLINESTYLE:
1642       return dwg_json_MLINESTYLE (dat, obj);
1643     case DWG_TYPE_OLE2FRAME:
1644       return dwg_json_OLE2FRAME (dat, obj);
1645     case DWG_TYPE_DUMMY:
1646       return dwg_json_DUMMY (dat, obj);
1647     case DWG_TYPE_LONG_TRANSACTION:
1648       return dwg_json_LONG_TRANSACTION (dat, obj);
1649     case DWG_TYPE_LWPOLYLINE:
1650       return dwg_json_LWPOLYLINE (dat, obj);
1651     case DWG_TYPE_HATCH:
1652       return dwg_json_HATCH (dat, obj);
1653     case DWG_TYPE_XRECORD:
1654       return dwg_json_XRECORD (dat, obj);
1655     case DWG_TYPE_PLACEHOLDER:
1656       return dwg_json_PLACEHOLDER (dat, obj);
1657     case DWG_TYPE_PROXY_ENTITY:
1658       return dwg_json_PROXY_ENTITY (dat, obj);
1659     case DWG_TYPE_PROXY_OBJECT:
1660       return dwg_json_PROXY_OBJECT (dat, obj);
1661     case DWG_TYPE_OLEFRAME:
1662       return dwg_json_OLEFRAME (dat, obj);
1663     case DWG_TYPE_VBA_PROJECT:
1664       LOG_ERROR ("Unhandled Object VBA_PROJECT. Has its own section\n");
1665       // dwg_json_VBA_PROJECT(dat, obj);
1666       break;
1667     case DWG_TYPE_LAYOUT:
1668       return dwg_json_LAYOUT (dat, obj);
1669     default:
1670       if (obj->type != 0 && obj->type == obj->parent->layout_type)
1671         {
1672           return dwg_json_LAYOUT (dat, obj);
1673         }
1674       /* > 500 */
1675       else if (DWG_ERR_UNHANDLEDCLASS
1676                & (error = dwg_json_variable_type (obj->parent, dat, obj)))
1677         {
1678           Dwg_Data *dwg = obj->parent;
1679           int is_entity;
1680           int i = obj->type - 500;
1681           Dwg_Class *klass = NULL;
1682           int num_bytes = obj->num_unknown_bits / 8;
1683           if (obj->num_unknown_bits & 8)
1684             num_bytes++;
1685 
1686           if (i >= 0 && i < (int)dwg->num_classes)
1687             {
1688               klass = &dwg->dwg_class[i];
1689               is_entity = dwg_class_is_entity (klass);
1690             }
1691           // properly dwg_decode_object/_entity for eed, reactors, xdic
1692           if (klass && !is_entity)
1693             {
1694               error |= dwg_json_UNKNOWN_OBJ (dat, obj);
1695               KEY (num_unknown_bits);
1696               VALUE_RL (obj->num_unknown_bits, 0);
1697               KEY (unknown_bits);
1698               VALUE_BINARY (obj->unknown_bits, num_bytes, 0);
1699               return error;
1700             }
1701           else if (klass)
1702             {
1703               error |= dwg_json_UNKNOWN_ENT (dat, obj);
1704               KEY (num_unknown_bits);
1705               VALUE_RL (obj->num_unknown_bits, 0);
1706               KEY (unknown_bits);
1707               VALUE_BINARY (obj->unknown_bits, num_bytes, 0);
1708               return error;
1709             }
1710           else // not a class
1711             {
1712               goto invalid_type;
1713             }
1714         }
1715       else
1716         return 0;
1717     }
1718  invalid_type:
1719   LOG_WARN ("Unknown object, skipping eed/reactors/xdic/...");
1720   FIELD_TEXT (object, obj->name);
1721   if (obj->dxfname && strNE (obj->dxfname, obj->name))
1722     FIELD_TEXT (dxfname, obj->dxfname);
1723   _FIELD (index, RL, 0);
1724   _FIELD (type, RL, 0);
1725   KEY (handle);
1726   VALUE_H (obj->handle, 5);
1727   _FIELD (size, RL, 0);
1728   _FIELD (bitsize, BL, 0);
1729   return DWG_ERR_INVALIDTYPE;
1730 }
1731 
1732 static int
json_fileheader_write(Bit_Chain * restrict dat,Dwg_Data * restrict dwg)1733 json_fileheader_write (Bit_Chain *restrict dat, Dwg_Data *restrict dwg)
1734 {
1735   Dwg_Header *_obj = &dwg->header;
1736   Dwg_Object *obj = NULL;
1737   int i;
1738 
1739   RECORD (FILEHEADER); // single hash
1740   KEY (version);
1741   fprintf (dat->fh, "\"%s\"", version_codes[dwg->header.version]);
1742   // clang-format off
1743   #include "header.spec"
1744   // clang-format on
1745   ENDRECORD ();
1746   return 0;
1747 }
1748 
1749 static int
json_header_write(Bit_Chain * restrict dat,Dwg_Data * restrict dwg)1750 json_header_write (Bit_Chain *restrict dat, Dwg_Data *restrict dwg)
1751 {
1752   Dwg_Header_Variables *_obj = &dwg->header_vars;
1753   Dwg_Object *obj = NULL;
1754   // const int minimal = 0;
1755   char buf[4096];
1756   double ms;
1757   const char *codepage
1758       = (dwg->header.codepage == 30 || dwg->header.codepage == 0)
1759             ? "ANSI_1252"
1760             : (dwg->header.version >= R_2007) ? "UTF-8" : "ANSI_1252";
1761 
1762   RECORD (HEADER); // single hash
1763   // clang-format off
1764   #include "header_variables.spec"
1765   // clang-format on
1766   ENDRECORD ();
1767   return 0;
1768 }
1769 
1770 static int
json_classes_write(Bit_Chain * restrict dat,Dwg_Data * restrict dwg)1771 json_classes_write (Bit_Chain *restrict dat, Dwg_Data *restrict dwg)
1772 {
1773   BITCODE_BS i;
1774 
1775   SECTION (CLASSES); // list of classes
1776   for (i = 0; i < dwg->num_classes; i++)
1777     {
1778       Dwg_Class *_obj = &dwg->dwg_class[i];
1779       FIRSTPREFIX HASH;
1780       FIELD_BS (number, 0);
1781       FIELD_TV (dxfname, 1);
1782       FIELD_T (cppname, 2);
1783       FIELD_T (appname, 3);
1784       FIELD_BS (proxyflag, 90);
1785       FIELD_BL (num_instances, 91);
1786       FIELD_B (is_zombie, 280);
1787       FIELD_BS (item_class_id, 281);
1788       ENDHASH
1789       CLEARFIRST;
1790     }
1791   ENDSEC ();
1792   return 0;
1793 }
1794 
1795 static int
json_objects_write(Bit_Chain * restrict dat,Dwg_Data * restrict dwg)1796 json_objects_write (Bit_Chain *restrict dat, Dwg_Data *restrict dwg)
1797 {
1798   BITCODE_BL i;
1799 
1800   CLEARFIRST;
1801   SECTION (OBJECTS);
1802   for (i = 0; i < dwg->num_objects; i++)
1803     {
1804       int error;
1805       Dwg_Object *obj = &dwg->object[i];
1806       FIRSTPREFIX HASH;
1807       error = dwg_json_object (dat, obj);
1808       ENDHASH
1809       CLEARFIRST;
1810     }
1811   ENDSEC ();
1812   return 0;
1813 }
1814 
1815 #if 0
1816 /* The object map/handles section */
1817 static int
1818 json_handles_write (Bit_Chain *restrict dat, Dwg_Data *restrict dwg)
1819 {
1820   BITCODE_BL j;
1821   CLEARFIRST;
1822   SECTION (HANDLES);
1823   for (j = 0; j < dwg->num_objects; j++)
1824     {
1825       Dwg_Object *obj = &dwg->object[j];
1826       // handle => abs. offset
1827       // TODO: The real HANDLES section omap has handleoffset (deleted holes) and addressoffset
1828       FIRSTPREFIX fprintf (dat->fh, "[ %lu, %lu ]", obj->handle.value, obj->address);
1829     }
1830   ENDSEC ();
1831   return 0;
1832 }
1833 #endif
1834 
1835 static int
json_thumbnail_write(Bit_Chain * restrict dat,Dwg_Data * restrict dwg)1836 json_thumbnail_write (Bit_Chain *restrict dat, Dwg_Data *restrict dwg)
1837 {
1838   Bit_Chain *_obj = (Bit_Chain *)&dwg->thumbnail;
1839   if (_obj->chain && _obj->size && _obj->size > 10)
1840     {
1841       /* SECTION_PREVIEW includes the sentinel.
1842          _obj->byte is at the BMP offset, via dwg_bmp */
1843       if (dwg->header.from_version >= R_2004)
1844         _obj->chain += 16; /* skip the sentinel */
1845       KEY (THUMBNAILIMAGE);
1846       HASH;
1847       FIRSTPREFIX fprintf (dat->fh, "\"size\": %lu", _obj->size);
1848       FIELD_BINARY (chain, _obj->size, 310);
1849       if (dwg->header.from_version >= R_2004)
1850         _obj->chain -= 16; /* undo for free */
1851       ENDHASH;
1852     }
1853   return 0;
1854 }
1855 
1856 static int
json_section_r2004fileheader(Bit_Chain * restrict dat,Dwg_Data * restrict dwg)1857 json_section_r2004fileheader (Bit_Chain *restrict dat, Dwg_Data *restrict dwg)
1858 {
1859   Dwg_R2004_Header *_obj = &dwg->r2004_header;
1860   Dwg_Object *obj = NULL;
1861   int i;
1862 
1863   RECORD (R2004_Header); // single hash
1864   // clang-format off
1865   #include "r2004_file_header.spec"
1866   // clang-format on
1867   ENDRECORD ();
1868   return 0;
1869 }
1870 
1871 static int
json_section_summary(Bit_Chain * restrict dat,Dwg_Data * restrict dwg)1872 json_section_summary (Bit_Chain *restrict dat, Dwg_Data *restrict dwg)
1873 {
1874   Dwg_SummaryInfo *_obj = &dwg->summaryinfo;
1875   Dwg_Object *obj = NULL;
1876   int error = 0;
1877 
1878   RECORD (SummaryInfo); // single hash
1879   // clang-format off
1880   #include "summaryinfo.spec"
1881   // clang-format on
1882   ENDRECORD ();
1883   return 0;
1884 }
1885 
1886 static int
json_section_vbaproject(Bit_Chain * restrict dat,Dwg_Data * restrict dwg)1887 json_section_vbaproject (Bit_Chain *restrict dat, Dwg_Data *restrict dwg)
1888 {
1889   Dwg_VBAProject *_obj = &dwg->vbaproject;
1890   Dwg_Object *obj = NULL;
1891   int error = 0;
1892 
1893   RECORD (VBAProject); // single hash
1894   HASH;
1895   // clang-format off
1896   //#include "vbaproject.spec"
1897   // clang-format on
1898   ENDRECORD ();
1899   return 0;
1900 }
1901 
1902 static int
json_section_appinfo(Bit_Chain * restrict dat,Dwg_Data * restrict dwg)1903 json_section_appinfo (Bit_Chain *restrict dat, Dwg_Data *restrict dwg)
1904 {
1905   Dwg_AppInfo *_obj = &dwg->appinfo;
1906   Dwg_Object *obj = NULL;
1907   int error = 0;
1908 
1909   RECORD (AppInfo); // single hash
1910   // clang-format off
1911   #include "appinfo.spec"
1912   // clang-format on
1913   ENDRECORD ();
1914   return 0;
1915 }
1916 
1917 static int
json_section_appinfohistory(Bit_Chain * restrict dat,Dwg_Data * restrict dwg)1918 json_section_appinfohistory (Bit_Chain *restrict dat, Dwg_Data *restrict dwg)
1919 {
1920   Dwg_AppInfoHistory *_obj = &dwg->appinfohistory;
1921   Dwg_Object *obj = NULL;
1922   int error = 0;
1923 
1924   RECORD (AppInfoHistory); // single hash
1925   FIRSTPREFIX fprintf (dat->fh, "\"size\": %d", _obj->size);
1926   FIELD_BINARY (unknown_bits, _obj->size, 0);
1927   // clang-format off
1928   //#include "appinfohistory.spec"
1929   // clang-format on
1930   ENDRECORD ();
1931   return 0;
1932 }
1933 
1934 static int
json_section_filedeplist(Bit_Chain * restrict dat,Dwg_Data * restrict dwg)1935 json_section_filedeplist (Bit_Chain *restrict dat, Dwg_Data *restrict dwg)
1936 {
1937   Dwg_FileDepList *_obj = &dwg->filedeplist;
1938   Dwg_Object *obj = NULL;
1939   int error = 0;
1940   BITCODE_RL vcount;
1941 
1942   RECORD (FileDepList); // single hash
1943   // clang-format off
1944   #include "filedeplist.spec"
1945   // clang-format on
1946   ENDRECORD ();
1947   return 0;
1948 }
1949 
1950 static int
json_section_security(Bit_Chain * restrict dat,Dwg_Data * restrict dwg)1951 json_section_security (Bit_Chain *restrict dat, Dwg_Data *restrict dwg)
1952 {
1953   Dwg_Security *_obj = &dwg->security;
1954   Dwg_Object *obj = NULL;
1955   int error = 0;
1956 
1957   RECORD (Security); // single hash
1958   // clang-format off
1959   #include "security.spec"
1960   // clang-format on
1961   ENDRECORD ();
1962   return 0;
1963 }
1964 
1965 static int
json_section_revhistory(Bit_Chain * restrict dat,Dwg_Data * restrict dwg)1966 json_section_revhistory (Bit_Chain *restrict dat, Dwg_Data *restrict dwg)
1967 {
1968   Dwg_RevHistory *_obj = &dwg->revhistory;
1969   Dwg_Object *obj = NULL;
1970   int error = 0;
1971   BITCODE_RL vcount;
1972 
1973   RECORD (RevHistory); // single hash
1974   FIELD_RL (class_version, 0);
1975   FIELD_RL (class_minor, 0);
1976   FIELD_RL (num_histories, 0);
1977   FIELD_VECTOR (histories, RL, num_histories, 0)
1978   ENDRECORD ();
1979   return 0;
1980 }
1981 
1982 static int
json_section_objfreespace(Bit_Chain * restrict dat,Dwg_Data * restrict dwg)1983 json_section_objfreespace (Bit_Chain *restrict dat, Dwg_Data *restrict dwg)
1984 {
1985   Dwg_ObjFreeSpace *_obj = &dwg->objfreespace;
1986   Dwg_Object *obj = NULL;
1987   int error = 0;
1988 
1989   RECORD (ObjFreeSpace); // single hash
1990   // clang-format off
1991   #include "objfreespace.spec"
1992   // clang-format on
1993   ENDRECORD ();
1994   return 0;
1995 }
1996 
1997 static int
json_section_acds(Bit_Chain * restrict dat,Dwg_Data * restrict dwg)1998 json_section_acds (Bit_Chain *restrict dat, Dwg_Data *restrict dwg)
1999 {
2000   Dwg_AcDs *_obj = &dwg->acds;
2001   Dwg_Object *obj = NULL;
2002   int error = 0;
2003   BITCODE_RL rcount3 = 0, rcount4, vcount;
2004 
2005   RECORD (AcDs); // single hash
2006   {
2007     // clang-format off
2008     #include "acds.spec"
2009     // clang-format on
2010   }
2011   ENDRECORD ();
2012   return 0;
2013 }
2014 
2015 static int
json_section_template(Bit_Chain * restrict dat,Dwg_Data * restrict dwg)2016 json_section_template (Bit_Chain *restrict dat, Dwg_Data *restrict dwg)
2017 {
2018   Dwg_Template *_obj = &dwg->Template;
2019   Dwg_Object *obj = NULL;
2020   int error = 0;
2021 
2022   RECORD (Template); // single hash. i.e MEASUREMENT metric/imperial
2023   // clang-format off
2024   #include "template.spec"
2025   // clang-format on
2026   ENDRECORD ();
2027   return 0;
2028 }
2029 
2030 static int
json_section_auxheader(Bit_Chain * restrict dat,Dwg_Data * restrict dwg)2031 json_section_auxheader (Bit_Chain *restrict dat, Dwg_Data *restrict dwg)
2032 {
2033   Dwg_AuxHeader *_obj = &dwg->auxheader;
2034   Dwg_Object *obj = NULL;
2035   int error = 0, i;
2036   BITCODE_RL vcount;
2037 
2038   RECORD (AuxHeader); // single hash
2039   // clang-format off
2040   #include "auxheader.spec"
2041   // clang-format on
2042   ENDRECORD ();
2043   return 0;
2044 }
2045 
2046 #if 0
2047 static int
2048 json_section_signature (Bit_Chain *restrict dat, Dwg_Data *restrict dwg)
2049 {
2050   struct Dwg_Signature *_obj = &dwg->signature;
2051   Dwg_Object *obj = NULL;
2052   int error = 0;
2053 
2054   RECORD (Signature); // single hash
2055   // clang-format off
2056   #include "signature.spec"
2057   // clang-format on
2058   ENDRECORD ();
2059   return 0;
2060 }
2061 
2062 static int
2063 json_section_2ndheader (Bit_Chain *restrict dat, Dwg_Data *restrict dwg)
2064 {
2065   struct _dwg_second_header *_obj = &dwg->second_header;
2066   Dwg_Object *obj = NULL;
2067   int error = 0;
2068 
2069   RECORD (SecondHeader); // single hash
2070   HASH;
2071   // clang-format off
2072   //#include "2ndheader.spec"
2073   // clang-format on
2074   ENDRECORD ();
2075   return 0;
2076 }
2077 #endif
2078 
2079 EXPORT int
dwg_write_json(Bit_Chain * restrict dat,Dwg_Data * restrict dwg)2080 dwg_write_json (Bit_Chain *restrict dat, Dwg_Data *restrict dwg)
2081 {
2082   const int minimal = dwg->opts & DWG_OPTS_MINIMAL;
2083   Dwg_Header *obj = &dwg->header;
2084   int error = 0;
2085 
2086   fprintf (dat->fh, "{\n  \"created_by\": \"%s\"", PACKAGE_STRING);
2087   dat->bit++; // ident
2088 
2089   if (!minimal)
2090     {
2091       json_fileheader_write (dat, dwg);
2092     }
2093 
2094   // A minimal HEADER requires only $ACADVER, $HANDSEED, and then ENTITIES
2095   json_header_write (dat, dwg);
2096 
2097   if (!minimal && dat->version >= R_13)
2098     {
2099       if (json_classes_write (dat, dwg) >= DWG_ERR_CRITICAL)
2100         goto fail;
2101     }
2102 
2103   if (json_objects_write (dat, dwg) >= DWG_ERR_CRITICAL)
2104     goto fail;
2105 
2106   if (!minimal && dat->version >= R_13)
2107     {
2108       if (json_thumbnail_write (dat, dwg) >= DWG_ERR_CRITICAL)
2109         goto fail;
2110       /* the other sections */
2111       if (dat->version <= R_2000)
2112         {
2113           error |= json_section_template (dat, dwg); // i.e. MEASUREMENT
2114           error |= json_section_auxheader (dat, dwg);
2115           //error |= json_section_2ndheader (dat, dwg);
2116         }
2117       if (dat->version >= R_2004)
2118         {
2119           error |= json_section_r2004fileheader (dat, dwg);
2120           if (dwg->header.summaryinfo_address)
2121             error |= json_section_summary (dat, dwg);
2122           if (dwg->header.vbaproj_address)
2123             error |= json_section_vbaproject (dat, dwg);
2124           error |= json_section_appinfo (dat, dwg);
2125           error |= json_section_appinfohistory (dat, dwg);
2126           error |= json_section_filedeplist (dat, dwg);
2127           error |= json_section_security (dat, dwg);
2128           error |= json_section_revhistory (dat, dwg);
2129           error |= json_section_objfreespace (dat, dwg);
2130           //error |= json_section_signature (dat, dwg);
2131           error |= json_section_template (dat, dwg);
2132           error |= json_section_acds (dat, dwg);
2133         }
2134     }
2135 
2136 #if 0
2137   /* object map */
2138   if (!minimal && dat->version >= R_13)
2139     {
2140       if (json_handles_write (dat, dwg) >= DWG_ERR_CRITICAL)
2141         goto fail;
2142     }
2143 #endif
2144 
2145   dat->bit--;
2146   fprintf (dat->fh, "}\n");
2147   return 0;
2148 fail:
2149   return 1;
2150 }
2151