1 /*****************************************************************************/
2 /*  LibreDWG - free implementation of the DWG file format                    */
3 /*                                                                           */
4 /*  Copyright (C) 2009-2010,2018-2021 Free Software Foundation, Inc.         */
5 /*  Copyright (C) 2010 Thien-Thi Nguyen                                      */
6 /*                                                                           */
7 /*  This library is free software, licensed under the terms of the GNU       */
8 /*  General Public License as published by the Free Software Foundation,     */
9 /*  either version 3 of the License, or (at your option) any later version.  */
10 /*  You should have received a copy of the GNU General Public License        */
11 /*  along with this program.  If not, see <http://www.gnu.org/licenses/>.    */
12 /*****************************************************************************/
13 
14 /*
15  * encode.c: encoding functions to write a DWG
16  * written by Felipe Castro
17  * modified by Felipe Corrêa da Silva Sances
18  * modified by Rodrigo Rodrigues da Silva
19  * modified by Thien-Thi Nguyen
20  * modified by Till Heuschmann
21  * modified by Anderson Pierre Cardoso
22  * modified by Reini Urban
23  */
24 
25 //#define HAVE_COMPRESS_R2004_SECTION
26 
27 #include "config.h"
28 #ifdef __STDC_ALLOC_LIB__
29 #  define __STDC_WANT_LIB_EXT2__ 1 /* for strdup */
30 #else
31 #  define _USE_BSD 1
32 #endif
33 #include <stdbool.h>
34 #include <stdio.h>
35 #include <stdlib.h>
36 #include <stdint.h>
37 #include <string.h>
38 #include <assert.h>
39 #ifdef HAVE_CTYPE_H
40 #  include <ctype.h>
41 #endif
42 
43 #include "common.h"
44 #include "bits.h"
45 #include "dwg.h"
46 #include "encode.h"
47 #include "decode.h"
48 #include "classes.h"
49 #include "free.h"
50 
51 // from dynapi
52 bool is_dwg_object (const char *name);
53 bool is_dwg_entity (const char *name);
54 int dwg_dynapi_entity_size (const char *restrict name);
55 // from dwg_api
56 BITCODE_T dwg_add_u8_input (Dwg_Data *restrict dwg,
57                             const char *restrict u8str);
58 Dwg_Object_APPID *dwg_add_APPID (Dwg_Data *restrict dwg,
59                                  const char *restrict name);
60 unsigned long dwg_obj_generic_handlevalue (void *_obj);
61 
62 /* The logging level for the write (encode) path.  */
63 static unsigned int loglevel;
64 /* the current version per spec block */
65 static unsigned int cur_ver = 0;
66 static BITCODE_BL rcount1 = 0, rcount2 = 0;
67 
68 #ifdef USE_TRACING
69 /* This flag means we have checked the environment variable
70    LIBREDWG_TRACE and set `loglevel' appropriately.  */
71 static bool env_var_checked_p;
72 #endif /* USE_TRACING */
73 #define DWG_LOGLEVEL loglevel
74 
75 #include "logging.h"
76 
77 /*--------------------------------------------------------------------------------
78  * spec MACROS
79  */
80 
81 #define ACTION encode
82 #define IS_ENCODER
83 
84 #define ANYCODE -1
85 
86 #undef LOG_POS
87 #define LOG_POS                                                               \
88   LOG_INSANE (" @%lu.%u", obj ? dat->byte - obj->address : dat->byte, dat->bit)\
89   LOG_TRACE ("\n")
90 #define LOG_RPOS                                                              \
91   LOG_INSANE (" @%lu.%u", dat->byte, dat->bit)                                \
92   LOG_TRACE ("\n")
93 #define LOG_HPOS                                                              \
94   LOG_INSANE (" @%lu.%u",                                                     \
95               obj && hdl_dat->byte > obj->address                             \
96                   ? hdl_dat->byte - obj->address                              \
97                   : hdl_dat->byte,                                            \
98               hdl_dat->bit)                                                   \
99   LOG_TRACE ("\n")
100 
101 #define VALUE(value, type, dxf)                                               \
102   {                                                                           \
103     bit_write_##type (dat, value);                                            \
104     LOG_TRACE (FORMAT_##type " [" #type " %d]", (BITCODE_##type)value, dxf);  \
105     LOG_POS                                                                   \
106   }
107 #define VALUE_RC(value, dxf) VALUE (value, RC, dxf)
108 #define VALUE_RS(value, dxf) VALUE (value, RS, dxf)
109 #define VALUE_RL(value, dxf) VALUE (value, RL, dxf)
110 #define VALUE_BS(value, dxf) VALUE (value, BS, dxf)
111 #define VALUE_BL(value, dxf) VALUE (value, BL, dxf)
112 #define VALUE_RD(value, dxf) VALUE (value, RD, dxf)
113 #define VALUE_BD(value, dxf) VALUE (value, BD, dxf)
114 
115 #define FIELD(nam, type)                                                      \
116   {                                                                           \
117     bit_write_##type (dat, _obj->nam);                                        \
118     FIELD_TRACE (nam, type);                                                  \
119   }
120 #define FIELDG(nam, type, dxf)                                                \
121   {                                                                           \
122     bit_write_##type (dat, _obj->nam);                                        \
123     FIELD_G_TRACE (nam, type, dxf);                                           \
124   }
125 #define FIELD_TRACE(nam, type)                                                \
126   LOG_TRACE (#nam ": " FORMAT_##type, _obj->nam)                              \
127   LOG_POS
128 #define FIELD_G_TRACE(nam, type, dxfgroup)                                    \
129   LOG_TRACE (#nam ": " FORMAT_##type " [" #type " " #dxfgroup "]", _obj->nam) \
130   LOG_POS
131 #define FIELD_CAST(nam, type, cast, dxf)                                      \
132   {                                                                           \
133     bit_write_##type (dat, (BITCODE_##type)_obj->nam);                        \
134     LOG_TRACE (#nam ": " FORMAT_##type " [" #type " " #dxf "]",               \
135                (BITCODE_##type)_obj->nam);                                    \
136     LOG_POS                                                                   \
137   }
138 #define SUB_FIELD(o, nam, type, dxf) FIELD (o.nam, type)
139 #define SUB_FIELD_CAST(o, nam, type, cast, dxf)                               \
140   {                                                                           \
141     bit_write_##type (dat, (BITCODE_##type)_obj->o.nam);                      \
142     FIELD_G_TRACE (o.nam, cast, dxf);                                         \
143   }
144 
145 #define FIELD_VALUE(nam) _obj->nam
146 
147 #define FIELD_B(nam, dxf) FIELDG (nam, B, dxf)
148 #define FIELD_BB(nam, dxf) FIELDG (nam, BB, dxf)
149 #define FIELD_3B(nam, dxf) FIELDG (nam, 3B, dxf)
150 #define FIELD_BS(nam, dxf) FIELDG (nam, BS, dxf)
151 #define FIELD_BSd(nam, dxf) FIELD_CAST (nam, BS, BSd, dxf)
152 #define FIELD_RSx(nam, dxf) FIELD_CAST (nam, RS, RSx, dxf)
153 #define FIELD_RLx(nam, dxf) FIELD_CAST (nam, RL, RLx, dxf)
154 #define FIELD_BLx(nam, dxf) FIELD_CAST (nam, BL, BLx, dxf)
155 #define FIELD_BLd(nam, dxf) FIELD_CAST (nam, BL, BLd, dxf)
156 #define FIELD_RLd(nam, dxf) FIELD_CAST (nam, RL, RLd, dxf)
157 #define FIELD_BL(nam, dxf) FIELDG (nam, BL, dxf)
158 #define FIELD_BLL(nam, dxf) FIELDG (nam, BLL, dxf)
159 #define FIELD_BD(nam, dxf) FIELDG (nam, BD, dxf)
160 #define FIELD_RC(nam, dxf) FIELDG (nam, RC, dxf)
161 #define FIELD_RS(nam, dxf) FIELDG (nam, RS, dxf)
162 #define FIELD_RD(nam, dxf) FIELDG (nam, RD, dxf)
163 #define FIELD_RL(nam, dxf) FIELDG (nam, RL, dxf)
164 #define FIELD_RLL(nam, dxf) FIELDG (nam, RLL, dxf)
165 #define FIELD_RLLu(nam, dxf)                                            \
166   {                                                                     \
167     bit_write_RLL (dat, _obj->nam);                                     \
168     FIELD_G_TRACE (nam, BLL, dxf);                                      \
169   }
170 #define FIELD_MC(nam, dxf) FIELDG (nam, MC, dxf)
171 #define FIELD_MS(nam, dxf) FIELDG (nam, MS, dxf)
172 #define FIELD_TV(nam, dxf)                                                    \
173   {                                                                           \
174     IF_ENCODE_FROM_EARLIER                                                    \
175     {                                                                         \
176       if (!_obj->nam)                                                         \
177         _obj->nam = strdup ("");                                              \
178     }                                                                         \
179     bit_write_TV (dat, _obj->nam);                                            \
180     LOG_TRACE (#nam ": \"%s\" [TV %d]", _obj->nam, dxf);                      \
181     LOG_POS                                                                   \
182   }
183 // may need to convert from/to TV<=>TU
184 #define FIELD_T(nam, dxf)                                                     \
185   {                                                                           \
186     if (dat->version < R_2007)                                                \
187       {                                                                       \
188         bit_write_T (dat, _obj->nam);                                         \
189         LOG_TRACE (#nam ": \"%s\" [T %d]", _obj->nam, dxf);                   \
190         LOG_POS                                                               \
191       }                                                                       \
192     else                                                                      \
193       {                                                                       \
194         bit_write_T (str_dat, _obj->nam);                                     \
195         LOG_TRACE_TU (#nam, _obj->nam, dxf);                                  \
196       }                                                                       \
197   }
198 #define FIELD_TF(nam, len, dxf)                                               \
199   {                                                                           \
200     LOG_TRACE (#nam ": [TF %d %d]\n", (int)len, dxf);                         \
201     if (len > 0)                                                              \
202       {                                                                       \
203         if (!_obj->nam)                                                       \
204           { /* empty field, write zeros */                                    \
205             for (int _i = 0; _i < (int)(len); _i++)                           \
206               bit_write_RC (dat, 0);                                          \
207           }                                                                   \
208         else                                                                  \
209           {                                                                   \
210             bit_write_TF (dat, (BITCODE_TF)_obj->nam, len);                   \
211           }                                                                   \
212       }                                                                       \
213     LOG_TRACE_TF (FIELD_VALUE (nam), (int)len);                               \
214   }
215 #define FIELD_TFF(nam, len, dxf) FIELD_TF (nam, len, dxf)
216 #define FIELD_TU(nam, dxf)                                                    \
217   {                                                                           \
218     if (_obj->nam)                                                            \
219       bit_write_TU (str_dat, (BITCODE_TU)_obj->nam);                          \
220     LOG_TRACE_TU (#nam, (BITCODE_TU)_obj->nam, dxf);                          \
221   }
222 #define FIELD_TU16(nam, dxf)                                                  \
223   {                                                                           \
224     if (_obj->nam)                                                            \
225       bit_write_TU16 (str_dat, _obj->nam);                                    \
226     LOG_TRACE_TU (#nam, (BITCODE_TU)_obj->nam, dxf);                          \
227   }
228 #define FIELD_T32(nam, dxf)                                                   \
229   {                                                                           \
230     if (_obj->nam)                                                            \
231       bit_write_T32 (str_dat, _obj->nam);                                     \
232     if (dat->version < R_2007)                                                \
233       LOG_TRACE (#nam ": \"%s\" [T32 %d]\n", _obj->nam, dxf)                  \
234     else                                                                      \
235       LOG_TRACE_TU (#nam, (BITCODE_TU)_obj->nam, dxf)                         \
236   }
237 #define FIELD_TU32(nam, dxf)                                                  \
238   {                                                                           \
239     if (_obj->nam)                                                            \
240       bit_write_TU32 (str_dat, _obj->nam);                                    \
241     if (dat->version < R_2007)                                                \
242       LOG_TRACE (#nam ": \"%s\" [TU32 %d]\n", _obj->nam, dxf)                 \
243     else                                                                      \
244       LOG_TRACE_TU (#nam, (BITCODE_TU)_obj->nam, dxf)                         \
245   }
246 #define FIELD_BT(nam, dxf) FIELDG (nam, BT, dxf);
247 
248 #define _FIELD_DD(nam, _default, dxf)                                         \
249   bit_write_DD (dat, FIELD_VALUE (nam), _default);
250 #define FIELD_DD(nam, _default, dxf)                                          \
251   {                                                                           \
252     BITCODE_BB b1 = _FIELD_DD (nam, _default, dxf);                           \
253     if (b1 == 3)                                                              \
254       LOG_TRACE (#nam ": %f [DD %d]", _obj->nam, dxf)                         \
255     else                                                                      \
256       LOG_TRACE (#nam ": %f [DD/%d %d]", _obj->nam, b1, dxf)                  \
257     LOG_POS                                                                   \
258   }
259 #define FIELD_2DD(nam, def, dxf)                                              \
260   {                                                                           \
261     BITCODE_BB b2, b1 = _FIELD_DD (nam.x, FIELD_VALUE (def.x), dxf);          \
262     b2 = _FIELD_DD (nam.y, FIELD_VALUE (def.y), dxf + 10);                    \
263     if (b1 == 3 && b2 == 3)                                                   \
264       LOG_TRACE (#nam ": (%f, %f) [2DD %d]", _obj->nam.x, _obj->nam.y, dxf)   \
265     else                                                                      \
266       LOG_TRACE (#nam ": (%f, %f) [2DD/%d%d %d]", _obj->nam.x, _obj->nam.y,   \
267                    b1, b2, dxf)                                               \
268     LOG_POS                                                                   \
269   }
270 #define FIELD_3DD(nam, def, dxf)                                              \
271   {                                                                           \
272     _FIELD_DD (nam.x, FIELD_VALUE (def.x), dxf);                              \
273     _FIELD_DD (nam.y, FIELD_VALUE (def.y), dxf + 10);                         \
274     _FIELD_DD (nam.z, FIELD_VALUE (def.z), dxf + 20);                         \
275     LOG_TRACE (#nam ": (%f, %f, %f) [3DD %d]", _obj->nam.x, _obj->nam.y,      \
276                _obj->nam.z, dxf)                                              \
277     LOG_POS                                                                   \
278   }
279 #define FIELD_2RD(nam, dxf)                                                   \
280   {                                                                           \
281     bit_write_RD (dat, _obj->nam.x);                                          \
282     bit_write_RD (dat, _obj->nam.y);                                          \
283     LOG_TRACE (#nam ": (%f, %f) [3RD %d]", _obj->nam.x, _obj->nam.y, dxf)     \
284     LOG_POS                                                                   \
285   }
286 #define FIELD_2BD(nam, dxf)                                                   \
287   {                                                                           \
288     bit_write_BD (dat, _obj->nam.x);                                          \
289     bit_write_BD (dat, _obj->nam.y);                                          \
290     LOG_TRACE (#nam ": (%f, %f) [3BD %d]", _obj->nam.x, _obj->nam.y, dxf)     \
291     LOG_POS                                                                   \
292   }
293 #define FIELD_2BD_1(nam, dxf) FIELD_2BD (nam, dxf)
294 #define FIELD_3RD(nam, dxf)                                                   \
295   {                                                                           \
296     bit_write_RD (dat, _obj->nam.x);                                          \
297     bit_write_RD (dat, _obj->nam.y);                                          \
298     bit_write_RD (dat, _obj->nam.z);                                          \
299     LOG_TRACE (#nam ": (%f, %f, %f) [3RD %d]", _obj->nam.x, _obj->nam.y,      \
300                _obj->nam.z, dxf)                                              \
301     LOG_POS                                                                   \
302   }
303 #define FIELD_3BD(nam, dxf)                                                   \
304   {                                                                           \
305     bit_write_BD (dat, _obj->nam.x);                                          \
306     bit_write_BD (dat, _obj->nam.y);                                          \
307     bit_write_BD (dat, _obj->nam.z);                                          \
308     LOG_TRACE (#nam ": (%f, %f, %f) [3BD %d]", _obj->nam.x, _obj->nam.y,      \
309                _obj->nam.z, dxf)                                              \
310     LOG_POS                                                                   \
311   }
312 #define FIELD_3BD_1(nam, dxf) FIELD_3BD (nam, dxf)
313 #define FIELD_3DPOINT(nam, dxf) FIELD_3BD (nam, dxf)
314 #define FIELD_4BITS(nam, dxf)                                                 \
315   {                                                                           \
316     unsigned char _b = (unsigned char)_obj->nam;                              \
317     bit_write_4BITS (dat, _b);                                                \
318     LOG_TRACE (#nam ": b%d%d%d%d [4BITS %d]", _b & 8, _b & 4, _b & 2,         \
319                _b & 1, dxf);                                                  \
320     LOG_POS                                                                   \
321   }
322 #define FIELD_TIMEBLL(nam, dxf)                                               \
323   {                                                                           \
324     bit_write_TIMEBLL (dat, (BITCODE_TIMEBLL)_obj->nam);                      \
325     LOG_TRACE (#nam ": " FORMAT_BL "." FORMAT_BL " [TIMEBLL %d]",             \
326                _obj->nam.days, _obj->nam.ms, dxf);                            \
327     LOG_POS                                                                   \
328   }
329 #define FIELD_TIMERLL(nam, dxf)                                               \
330   {                                                                           \
331     bit_write_TIMERLL (dat, (BITCODE_TIMERLL)_obj->nam);                      \
332     LOG_TRACE (#nam ": " FORMAT_RL "." FORMAT_RL " [TIMERLL %d]",             \
333                _obj->nam.days, _obj->nam.ms, dxf);                            \
334     LOG_POS                                                                   \
335   }
336 
337 #define FIELD_CMC(color, dxf)                                                 \
338   {                                                                           \
339     bit_write_CMC (dat, str_dat, &_obj->color);                               \
340     LOG_TRACE (#color ".index: %d [CMC.BS %d]\n", _obj->color.index, dxf);    \
341     LOG_INSANE (" @%lu.%u\n", obj ? dat->byte - obj->address : dat->byte, dat->bit) \
342     if (dat->version >= R_2004)                                               \
343       {                                                                       \
344         LOG_TRACE (#color ".rgb: 0x%08x [CMC.BL %d]\n",                       \
345                    (unsigned)_obj->color.rgb, dxf + 420 - 62);                \
346         LOG_TRACE (#color ".flag: 0x%x [CMC.RC]\n",                           \
347                    (unsigned)_obj->color.flag);                               \
348         if (_obj->color.flag & 1)                                             \
349           LOG_TRACE (#color ".name: %s [CMC.T]\n", _obj->color.name);         \
350         if (_obj->color.flag & 2)                                             \
351           LOG_TRACE (#color ".bookname: %s [CMC.T]\n",                        \
352                      _obj->color.book_name);                                  \
353         LOG_INSANE (" @%lu.%u\n", obj ? dat->byte - obj->address : dat->byte, dat->bit) \
354       }                                                                       \
355   }
356 #define SUB_FIELD_CMC(o, color, dxf)                                          \
357   {                                                                           \
358     bit_write_CMC (dat, str_dat, &_obj->o.color);                             \
359     LOG_TRACE (#color ".index: %d [CMC.BS %d]\n", _obj->o.color.index, dxf);  \
360     LOG_INSANE (" @%lu.%u\n", obj ? dat->byte - obj->address : dat->byte,     \
361                 dat->bit)                                                     \
362     if (dat->version >= R_2004)                                               \
363       {                                                                       \
364         LOG_TRACE (#color ".rgb: 0x%06x [CMC.BL %d]\n",                       \
365                    (unsigned)_obj->o.color.rgb, dxf + 420 - 62);              \
366         LOG_TRACE (#color ".flag: 0x%x [CMC.RC]\n",                           \
367                    (unsigned)_obj->o.color.flag);                             \
368         if (_obj->o.color.flag & 1)                                           \
369           LOG_TRACE (#color ".name: %s [CMC.T]\n", _obj->o.color.name);       \
370         if (_obj->o.color.flag & 2)                                           \
371           LOG_TRACE (#color ".bookname: %s [CMC.T]\n",                        \
372                      _obj->o.color.book_name);                                \
373         LOG_INSANE (" @%lu.%u\n", obj ? dat->byte - obj->address : dat->byte, \
374                     dat->bit)                                                 \
375       }                                                                       \
376   }
377 
378 #define LOG_TF(level, var, len)                                               \
379   if (var)                                                                    \
380     {                                                                         \
381       int _i;                                                                 \
382       for (_i = 0; _i < (len); _i++)                                          \
383         {                                                                     \
384           LOG (level, "%02X", (unsigned char)((char *)var)[_i]);              \
385         }                                                                     \
386       LOG (level, "\n");                                                      \
387       if (DWG_LOGLEVEL >= DWG_LOGLEVEL_INSANE)                                \
388         {                                                                     \
389           for (_i = 0; _i < (len); _i++)                                      \
390             {                                                                 \
391               unsigned char c = ((unsigned char *)var)[_i];                   \
392               LOG_INSANE ("%-2c", isprint (c) ? c : ' ');                     \
393             }                                                                 \
394           LOG_INSANE ("\n");                                                  \
395         }                                                                     \
396     }
397 #define LOG_TRACE_TF(var, len) LOG_TF (TRACE, var, len)
398 #define LOG_INSANE_TF(var, len) LOG_TF (INSANE, var, len)
399 
400 #define FIELD_BE(nam, dxf)                                                    \
401   bit_write_BE (dat, FIELD_VALUE (nam.x), FIELD_VALUE (nam.y),                \
402                 FIELD_VALUE (nam.z));
403 
404 #define OVERFLOW_CHECK(nam, size)                                             \
405   if ((long)(size) > 0xff00L || (!_obj->nam && size) || (_obj->nam && !size)) \
406     {                                                                         \
407       LOG_ERROR ("Invalid " #nam " %ld", (long)size);                         \
408       return DWG_ERR_VALUEOUTOFBOUNDS;                                        \
409     }
410 #define OVERFLOW_CHECK_LV(nam, size)                                          \
411   if ((long)(size) > 0xff00L)                                                 \
412     {                                                                         \
413       LOG_ERROR ("Invalid " #nam " %ld, set to 0", (long)size);               \
414       size = 0;                                                               \
415       return DWG_ERR_VALUEOUTOFBOUNDS;                                        \
416     }
417 #define OVERFLOW_NULL_CHECK_LV(nam, size)                                     \
418   if ((long)(size) > 0xff00L || (!_obj->nam && size) || (_obj->nam && !size)) \
419     {                                                                         \
420       LOG_ERROR ("Invalid " #nam " %ld, set to 0", (long)size);               \
421       size = 0;                                                               \
422       return DWG_ERR_VALUEOUTOFBOUNDS;                                        \
423     }
424 
425 #define FIELD_2RD_VECTOR(nam, size, dxf)                                      \
426   OVERFLOW_NULL_CHECK_LV (nam, _obj->size)                                    \
427   for (vcount = 0; vcount < (BITCODE_BL)_obj->size; vcount++)                 \
428     {                                                                         \
429       FIELD_2RD (nam[vcount], dxf);                                           \
430     }
431 
432 #define FIELD_2DD_VECTOR(nam, size, dxf)                                      \
433   OVERFLOW_NULL_CHECK_LV (nam, _obj->size)                                    \
434   if (_obj->size)                                                             \
435     FIELD_2RD (nam[0], dxf);                                                  \
436   for (vcount = 1; vcount < (BITCODE_BL)_obj->size; vcount++)                 \
437     {                                                                         \
438       FIELD_2DD (nam[vcount], nam[vcount - 1], dxf);                          \
439     }
440 
441 #define FIELD_3DPOINT_VECTOR(nam, size, dxf)                                  \
442   OVERFLOW_NULL_CHECK_LV (nam, _obj->size)                                    \
443   for (vcount = 0; vcount < (BITCODE_BL)_obj->size; vcount++)                 \
444     {                                                                         \
445       FIELD_3DPOINT (nam[vcount], dxf);                                       \
446     }
447 
448 #define REACTORS(code)                                                        \
449   if (obj->tio.object->reactors)                                              \
450     {                                                                         \
451       OVERFLOW_CHECK_LV (num_reactors, obj->tio.object->num_reactors)         \
452       SINCE (R_13)                                                            \
453       {                                                                       \
454         for (vcount = 0; vcount < (BITCODE_BL)obj->tio.object->num_reactors;  \
455              vcount++)                                                        \
456           {                                                                   \
457             VALUE_HANDLE (obj->tio.object->reactors[vcount], reactors, code,  \
458                           330);                                               \
459           }                                                                   \
460       }                                                                       \
461     }
462 
463 #define XDICOBJHANDLE(code)                                                   \
464   RESET_VER                                                                   \
465   SINCE (R_2004)                                                              \
466   {                                                                           \
467     if (!obj->tio.object->is_xdic_missing)                                  \
468       {                                                                       \
469         VALUE_HANDLE (obj->tio.object->xdicobjhandle, xdicobjhandle, code,    \
470                       360);                                                   \
471       }                                                                       \
472   }                                                                           \
473   else                                                                        \
474   {                                                                           \
475     SINCE (R_13)                                                              \
476     {                                                                         \
477       VALUE_HANDLE (obj->tio.object->xdicobjhandle, xdicobjhandle, code,      \
478                     360);                                                     \
479     }                                                                         \
480   }                                                                           \
481   RESET_VER
482 
483 #define ENT_XDICOBJHANDLE(code)                                               \
484   RESET_VER                                                                   \
485   SINCE (R_2004)                                                              \
486   {                                                                           \
487     if (!obj->tio.entity->is_xdic_missing)                                    \
488       {                                                                       \
489         VALUE_HANDLE (obj->tio.entity->xdicobjhandle, xdicobjhandle, 3,       \
490                       360);                                                   \
491       }                                                                       \
492   }                                                                           \
493   else                                                                        \
494   {                                                                           \
495     SINCE (R_13)                                                              \
496     {                                                                         \
497       VALUE_HANDLE (obj->tio.entity->xdicobjhandle, xdicobjhandle, 3,         \
498                     360);                                                     \
499     }                                                                         \
500   }                                                                           \
501   RESET_VER
502 
503 // FIELD_VECTOR_N(nam, type, size, dxf):
504 // writes a 'size' elements vector of data of the type indicated by 'type'
505 #define FIELD_VECTOR_N(nam, type, size, dxf)                                  \
506   if (size > 0 && _obj->nam)                                                  \
507     {                                                                         \
508       OVERFLOW_CHECK (nam, size)                                              \
509       for (vcount = 0; vcount < (BITCODE_BL)size; vcount++)                   \
510         {                                                                     \
511           bit_write_##type (dat, _obj->nam[vcount]);                          \
512           LOG_TRACE (#nam "[%ld]: " FORMAT_##type " [%s %d]", (long)vcount,   \
513                      _obj->nam[vcount], #type, dxf)                           \
514           LOG_POS                                                             \
515         }                                                                     \
516     }
517 #define FIELD_VECTOR_T(nam, type, size, dxf)                                  \
518   if (_obj->size > 0 && _obj->nam)                                            \
519     {                                                                         \
520       OVERFLOW_CHECK_LV (nam, _obj->size)                                     \
521       for (vcount = 0; vcount < (BITCODE_BL)_obj->size; vcount++)             \
522         {                                                                     \
523           if (dat->version != dat->from_version)                              \
524             FIELD_##type (nam[vcount], dxf) else if (dat->version < R_2007)   \
525             {                                                                 \
526               bit_write_TV (dat, (BITCODE_TV)_obj->nam[vcount]);              \
527               LOG_TRACE (#nam "[%d]: \"%s\" [TV %d]", (int)vcount,            \
528                          _obj->nam[vcount], dxf)                              \
529               LOG_POS                                                         \
530             }                                                                 \
531           else                                                                \
532             {                                                                 \
533               bit_write_##type (dat, _obj->nam[vcount]);                      \
534               LOG_TRACE_TU (#nam, _obj->nam[vcount], dxf)                     \
535             }                                                                 \
536         }                                                                     \
537       RESET_VER                                                               \
538     }
539 #define FIELD_VECTOR_T1(nam, type, size, dxf)                                 \
540   if (_obj->size > 0 && _obj->nam)                                            \
541     {                                                                         \
542       OVERFLOW_CHECK_LV (nam, _obj->size)                                     \
543       for (vcount = 0; vcount < (BITCODE_BL)_obj->size; vcount++)             \
544         {                                                                     \
545           if (dat->version < R_2007)                                          \
546             {                                                                 \
547               unsigned _len = strlen (_obj->nam[vcount]);                     \
548               bit_write_BS (dat, _len);                                       \
549               bit_write_TF (dat, (BITCODE_TF)_obj->nam[vcount], _len);        \
550               LOG_TRACE (#nam "[%d]: \"%s\" [TV1 %d]", (int)vcount,           \
551                          _obj->nam[vcount], dxf)                              \
552               LOG_POS                                                         \
553             }                                                                 \
554           else                                                                \
555             {                                                                 \
556               bit_write_##type (dat, _obj->nam[vcount]);                      \
557               LOG_TRACE_TU (#nam, _obj->nam[vcount], dxf)                     \
558             }                                                                 \
559         }                                                                     \
560       RESET_VER                                                               \
561     }
562 
563 #define FIELD_VECTOR(nam, type, size, dxf)                                    \
564   FIELD_VECTOR_N (nam, type, _obj->size, dxf)
565 #define FIELD_VECTOR_INL(nam, type, size, dxf)                                \
566   FIELD_VECTOR_N (nam, type, size, dxf)
567 
568 #define SUB_FIELD_VECTOR_TYPESIZE(o, nam, size, typesize, dxf)                \
569   if (_obj->o.size > 0 && _obj->o.nam)                                        \
570     {                                                                         \
571       OVERFLOW_CHECK (nam, _obj->o.size)                                      \
572       for (vcount = 0; vcount < (BITCODE_BL)_obj->o.size; vcount++)           \
573         {                                                                     \
574           bit_write_##type (dat, _obj->nam[vcount]);                          \
575           switch (typesize)                                                   \
576             {                                                                 \
577             case 0:                                                           \
578               break;                                                          \
579             case 1:                                                           \
580               bit_write_RC (dat, _obj->o.name[vcount]);                       \
581               break;                                                          \
582             case 2:                                                           \
583               bit_write_RS (dat, _obj->o.name[vcount]);                       \
584               break;                                                          \
585             case 4:                                                           \
586               bit_write_RL (dat, _obj->o.name[vcount]);                       \
587               break;                                                          \
588             case 8:                                                           \
589               bit_write_RLL (dat, _obj->o.name[vcount]);                      \
590               break;                                                          \
591             default:                                                          \
592               LOG_ERROR ("Unkown SUB_FIELD_VECTOR_TYPE " #nam " typesize %d", \
593                          typesize);                                           \
594               break;                                                          \
595             }                                                                 \
596           LOG_TRACE (#nam "[%u]: %d\n", vcount, _obj->nam[vcount])            \
597         }                                                                     \
598     }
599 
600 #define VALUE_HANDLE(hdlptr, nam, handle_code, dxf)                           \
601   IF_ENCODE_SINCE_R13                                                         \
602   {                                                                           \
603     RESET_VER                                                                 \
604     if (!hdlptr)                                                              \
605       {                                                                       \
606         Dwg_Handle null_handle = { 0, 0, 0UL, 0 };                            \
607         null_handle.code = handle_code;                                       \
608         bit_write_H (hdl_dat, &null_handle);                                  \
609         LOG_TRACE (#nam ": (%d.0.0) abs:0 [H %d]", handle_code, dxf)          \
610         LOG_HPOS                                                              \
611       }                                                                       \
612     else                                                                      \
613       {                                                                       \
614         if (handle_code != ANYCODE && (hdlptr)->handleref.code != handle_code \
615             && (handle_code == 4 && (hdlptr)->handleref.code < 6))            \
616           {                                                                   \
617             LOG_WARN ("Expected a CODE %d handle, got a %d", handle_code,     \
618                       (hdlptr)->handleref.code);                              \
619           }                                                                   \
620         bit_write_H (hdl_dat, &(hdlptr)->handleref);                          \
621         LOG_TRACE (#nam ": " FORMAT_REF " [H %d]", ARGS_REF (hdlptr), dxf)    \
622         LOG_HPOS                                                              \
623       }                                                                       \
624   }
625 
626 #define FIELD_HANDLE(nam, handle_code, dxf)                                   \
627   VALUE_HANDLE (_obj->nam, nam, handle_code, dxf)
628 #define SUB_FIELD_HANDLE(o, nam, handle_code, dxf)                            \
629   VALUE_HANDLE (_obj->o.nam, nam, handle_code, dxf)
630 #define FIELD_DATAHANDLE(nam, handle_code, dxf)                               \
631   {                                                                           \
632     bit_write_H (dat, _obj->nam ? &_obj->nam->handleref : NULL);              \
633   }
634 
635 #define FIELD_HANDLE_N(nam, vcount, handle_code, dxf)                         \
636   IF_ENCODE_SINCE_R13                                                         \
637   {                                                                           \
638     RESET_VER                                                                 \
639     if (!_obj->nam)                                                           \
640       {                                                                       \
641         bit_write_H (hdl_dat, NULL);                                          \
642         LOG_TRACE (#nam "[%d]: NULL %d [H* %d]", (int)vcount, handle_code,    \
643                    dxf)                                                       \
644         LOG_HPOS                                                              \
645       }                                                                       \
646     else                                                                      \
647       {                                                                       \
648         if (handle_code != ANYCODE                                            \
649             && _obj->nam->handleref.code != handle_code                       \
650             && (handle_code == 4 && _obj->nam->handleref.code < 6))           \
651           {                                                                   \
652             LOG_WARN ("Expected a CODE %x handle, got a %x", handle_code,     \
653                       _obj->nam->handleref.code);                             \
654           }                                                                   \
655         bit_write_H (hdl_dat, &_obj->nam->handleref);                         \
656         LOG_TRACE (#nam "[%d]: " FORMAT_REF " [H* %d]", (int)vcount,          \
657                    ARGS_REF (_obj->nam), dxf)                                 \
658         LOG_HPOS                                                              \
659       }                                                                       \
660   }
661 
662 #define HANDLE_VECTOR_N(nam, size, code, dxf)                                 \
663   if (size > 0 && _obj->nam)                                                  \
664     {                                                                         \
665       OVERFLOW_CHECK (nam, size)                                              \
666       for (vcount = 0; vcount < (BITCODE_BL)size; vcount++)                   \
667         {                                                                     \
668           if (_obj->nam[vcount])                                              \
669             {                                                                 \
670               FIELD_HANDLE_N (nam[vcount], vcount, code, dxf);                \
671             }                                                                 \
672         }                                                                     \
673     }
674 
675 #define FIELD_NUM_INSERTS(num_inserts, type, dxf)                             \
676   for (vcount = 0; vcount < FIELD_VALUE (num_inserts); vcount++)              \
677     {                                                                         \
678       bit_write_RC (dat, 1);                                                  \
679     }                                                                         \
680   bit_write_RC (dat, 0);                                                      \
681   LOG_TRACE ("num_inserts: %d [RC* 0]", FIELD_VALUE (num_inserts))            \
682   LOG_POS
683 
684 #define HANDLE_VECTOR(nam, sizefield, code, dxf)                              \
685   HANDLE_VECTOR_N (nam, FIELD_VALUE (sizefield), code, dxf)
686 
687 #define FIELD_XDATA(nam, size)                                                \
688   error |= dwg_encode_xdata (dat, _obj, _obj->size)
689 
690 #define COMMON_ENTITY_HANDLE_DATA                                             \
691   SINCE (R_13)                                                                \
692   {                                                                           \
693     START_HANDLE_STREAM;                                                      \
694   }                                                                           \
695   RESET_VER
696 
697 #define START_OBJECT_HANDLE_STREAM  START_HANDLE_STREAM
698 #define CONTROL_HANDLE_STREAM       START_HANDLE_STREAM
699 
700 #define SECTION_STRING_STREAM                                                 \
701   {                                                                           \
702     Bit_Chain sav_dat = *dat;                                                 \
703     dat = str_dat;
704 
705 /* TODO: dump all TU strings here */
706 #define START_STRING_STREAM                                                   \
707   bit_write_B (dat, obj->has_strings);                                        \
708   RESET_VER                                                                   \
709   if (obj->has_strings)                                                       \
710     {                                                                         \
711       Bit_Chain sav_dat = *dat;                                               \
712       obj_string_stream (dat, obj, dat);
713 
714 #define END_STRING_STREAM                                                     \
715   *dat = sav_dat;                                                             \
716   }
717 #define ENCODE_COMMON_HANDLES                                                 \
718   if (obj->supertype == DWG_SUPERTYPE_OBJECT && dat->version >= R_13)         \
719     {                                                                         \
720       VALUE_HANDLE (obj->tio.object->ownerhandle, ownerhandle, 4, 330);       \
721       REACTORS (4);                                                           \
722       XDICOBJHANDLE (3);                                                      \
723     }                                                                         \
724  else if (obj->supertype == DWG_SUPERTYPE_ENTITY && dat->version >= R_13)     \
725    {                                                                          \
726      error |= dwg_encode_common_entity_handle_data (dat, hdl_dat, obj);       \
727    }
728 
729 #define START_HANDLE_STREAM                                                   \
730   LOG_INSANE ("HANDLE_STREAM @%lu.%u\n", dat->byte - obj->address, dat->bit)  \
731   if (!obj->bitsize ||                                                        \
732        /* DD sizes can vary, but let unknown_bits asis */                     \
733       has_entity_DD (obj) ||                                                  \
734        /* strings may be zero-terminated or not */                            \
735       obj_has_strings (obj) ||                                                \
736        (dwg->header.version != dwg->header.from_version                       \
737         && obj->fixedtype != DWG_TYPE_UNKNOWN_OBJ                             \
738         && obj->fixedtype != DWG_TYPE_UNKNOWN_ENT))                           \
739     {                                                                         \
740       obj->bitsize = bit_position (dat) - (obj->address * 8);                 \
741       LOG_TRACE ("-bitsize calc from HANDLE_STREAM " FORMAT_RL " @%lu.%u (%lu)\n", \
742                  obj->bitsize, dat->byte - obj->address, dat->bit, obj->address); \
743       obj->was_bitsize_set = 1;                                               \
744     }                                                                         \
745   if (!obj->hdlpos)                                                           \
746     obj->hdlpos = bit_position (dat);                                         \
747   {                                                                           \
748     unsigned long _hpos = bit_position (hdl_dat);                             \
749     if (_hpos > 0)                                                            \
750       {                                                                       \
751         /* save away special accumulated hdls, need to write common first */  \
752         Bit_Chain dat1 = *hdl_dat;                                            \
753         Bit_Chain dat2;                                                       \
754         bit_chain_init_dat (&dat2, 12, dat);                                  \
755         hdl_dat = &dat2;                                                      \
756         ENCODE_COMMON_HANDLES                                                 \
757         obj_flush_hdlstream (obj, dat, hdl_dat); /* common */                 \
758         obj_flush_hdlstream (obj, dat, &dat1); /* special accumulated */      \
759         bit_chain_free (&dat1);                                               \
760         bit_chain_free (&dat2);                                               \
761         *hdl_dat = *dat;                                                      \
762         hdl_dat = dat;                                                        \
763       }                                                                       \
764     else                                                                      \
765       {                                                                       \
766         if (hdl_dat != dat)                                                   \
767           bit_chain_free (hdl_dat);                                           \
768         hdl_dat = dat;                                                        \
769         ENCODE_COMMON_HANDLES                                                 \
770       }                                                                       \
771   }                                                                           \
772   RESET_VER
773 
774 static void
obj_flush_hdlstream(Dwg_Object * restrict obj,Bit_Chain * restrict dat,Bit_Chain * restrict hdl_dat)775 obj_flush_hdlstream (Dwg_Object *restrict obj, Bit_Chain *restrict dat,
776                      Bit_Chain *restrict hdl_dat)
777 {
778   unsigned long datpos = bit_position (dat);
779   unsigned long hdlpos = bit_position (hdl_dat);
780   unsigned long objpos = obj->address * 8;
781   LOG_TRACE ("Flush handle stream of size %lu (@%lu.%u) to @%lu.%lu\n", hdlpos,
782              hdl_dat->byte, hdl_dat->bit, (datpos - objpos) / 8,
783              (datpos - objpos) % 8);
784   bit_copy_chain (dat, hdl_dat);
785 }
786 
787 #if 0
788 /** See dec_macro.h instead.
789    Returns -1 if not added, else returns the new objid.
790    Does a complete handleref rescan to invalidate and resolve
791    all internal obj pointers after a object[] realloc.
792 */
793 EXPORT long dwg_add_##token (Dwg_Data * dwg)    \
794 {                                               \
795   Bit_Chain dat = { 0 };                        \
796   BITCODE_BL num_objs  = dwg->num_objects;      \
797   int error = 0;                                \
798   dat.size = sizeof(Dwg_Entity_##token) + 40;   \
799   LOG_INFO ("Add entity " #token " ")           \
800   dat.chain = calloc (dat.size, 1);             \
801   dat.version = dwg->header.version;            \
802   dat.from_version = dwg->header.from_version;  \
803   bit_write_MS (&dat, dat.size);                \
804   if (dat.version >= R_2010) {                  \
805     /* FIXME: should be UMC handlestream_size */\
806     bit_write_UMC (&dat, 8*sizeof(Dwg_Entity_##token)); \
807     bit_write_BOT &dat, DWG_TYPE_##token);      \
808   } else {                                      \
809     bit_write_BS (&dat, DWG_TYPE_##token);      \
810   }                                             \
811   bit_set_position (&dat, 0);                   \
812   error = dwg_decode_add_object (dwg, &dat, &dat, 0);\
813   if (-1 == error)                              \
814     dwg_resolve_objectrefs_silent (dwg);        \
815   if (num_objs == dwg->num_objects)             \
816     return -1;                                  \
817   else                                          \
818     return (long)dwg->num_objects;              \
819 }
820 
821 EXPORT long dwg_add_##token (Dwg_Data * dwg)     \
822 {                                                \
823   Bit_Chain dat = { 0 };                         \
824   int error = 0;                                 \
825   BITCODE_BL num_objs  = dwg->num_objects;       \
826   dat.size = sizeof(Dwg_Object_##token) + 40;    \
827   LOG_INFO ("Add object " #token " ")            \
828   dat.chain = calloc (dat.size, 1);              \
829   dat.version = dwg->header.version;             \
830   dat.from_version = dwg->header.from_version;   \
831   bit_write_MS (&dat, dat.size);                 \
832   if (dat.version >= R_2010) {                   \
833     /* FIXME: should be UMC handlestream_size */ \
834     bit_write_UMC (&dat, 8*sizeof(Dwg_Object_##token)); \
835     bit_write_BOT (&dat, DWG_TYPE_##token);      \
836   } else {                                       \
837     bit_write_BS (&dat, DWG_TYPE_##token);       \
838   }                                              \
839   bit_set_position(&dat, 0);                     \
840   error = dwg_decode_add_object(dwg, &dat, &dat, 0);\
841   if (-1 ==  error) \
842     dwg_resolve_objectrefs_silent(dwg);          \
843   if (num_objs == dwg->num_objects)              \
844     return -1;                                   \
845   else                                           \
846     return (long)dwg->num_objects;               \
847 }
848 
849 #endif
850 
851 #define DWG_ENTITY(token)                                                     \
852   static int dwg_encode_##token##_private (                                   \
853       Bit_Chain *dat, Bit_Chain *hdl_dat, Bit_Chain *str_dat,                 \
854       Dwg_Object *restrict obj);                                              \
855   static int dwg_encode_##token (Bit_Chain *restrict dat,                     \
856                                  Dwg_Object *restrict obj)                    \
857   {                                                                           \
858     int error;                                                                \
859     Bit_Chain _hdl_dat = { 0 };                                               \
860     Bit_Chain *hdl_dat = &_hdl_dat; /* a new copy */                          \
861     Bit_Chain *str_dat = dat;       /* a ref */                               \
862     LOG_INFO ("Encode entity " #token "\n");                                  \
863     bit_chain_init_dat (hdl_dat, 128, dat);                                   \
864     error = dwg_encode_entity (obj, dat, hdl_dat, str_dat);                   \
865     if (error)                                                                \
866       {                                                                       \
867         LOG_HANDLE ("Early DWG_ENTITY exit\n");                               \
868         if (hdl_dat != dat && hdl_dat->chain != dat->chain)                   \
869           bit_chain_free (hdl_dat);                                           \
870         return error;                                                         \
871       }                                                                       \
872     error = dwg_encode_##token##_private (dat, hdl_dat, str_dat, obj);        \
873     if (error & DWG_ERR_VALUEOUTOFBOUNDS && hdl_dat != dat                    \
874         && hdl_dat->chain != dat->chain)                                      \
875       {                                                                       \
876         LOG_HANDLE ("VALUEOUTOFBOUNDS bypassed DWG_ENTITY_END\n");            \
877         /*bit_chain_free (hdl_dat);*/                                         \
878       }                                                                       \
879     return error;                                                             \
880   }                                                                           \
881   static int dwg_encode_##token##_private (                                   \
882       Bit_Chain *dat, Bit_Chain *hdl_dat, Bit_Chain *str_dat,                 \
883       Dwg_Object *restrict obj)                                               \
884   {                                                                           \
885     int error = 0;                                                            \
886     BITCODE_BL vcount, rcount3, rcount4;                                      \
887     Dwg_Data *dwg = obj->parent;                                              \
888     Dwg_Object_Entity *_ent = obj->tio.entity;                                \
889     Dwg_Entity_##token *_obj = _ent->tio.token;
890 
891 #define DWG_ENTITY_END                                                        \
892     if (hdl_dat->byte > dat->byte)                                            \
893       {                                                                       \
894         dat->byte = hdl_dat->byte;                                            \
895         dat->bit = hdl_dat->bit;                                              \
896       }                                                                       \
897     if (hdl_dat != dat && hdl_dat->chain != dat->chain)                       \
898       bit_chain_free (hdl_dat);                                               \
899     return error;                                                             \
900   }
901 
902 /** Returns -1 if not added, else returns the new objid.
903    Does a complete handleref rescan to invalidate and resolve
904    all internal obj pointers after a object[] realloc.
905 */
906 #define DWG_OBJECT(token)                                                     \
907   static int dwg_encode_##token##_private (                                   \
908       Bit_Chain *dat, Bit_Chain *hdl_dat, Bit_Chain *str_dat,                 \
909       Dwg_Object *restrict obj);                                              \
910   static int dwg_encode_##token (Bit_Chain *restrict dat,                     \
911                                  Dwg_Object *restrict obj)                    \
912   {                                                                           \
913     int error;                                                                \
914     Bit_Chain _hdl_dat = { 0 };                                               \
915     Bit_Chain *hdl_dat = &_hdl_dat; /* a new copy */                          \
916     Bit_Chain *str_dat = dat;       /* a ref */                               \
917     LOG_INFO ("Encode object " #token "\n");                                  \
918     bit_chain_init_dat (hdl_dat, 128, dat);                                   \
919     error = dwg_encode_object (obj, dat, hdl_dat, str_dat);                   \
920     if (error)                                                                \
921       {                                                                       \
922         if (hdl_dat != dat)                                                   \
923           bit_chain_free (hdl_dat);                                           \
924         return error;                                                         \
925       }                                                                       \
926     error = dwg_encode_##token##_private (dat, hdl_dat, str_dat, obj);        \
927     if (error & DWG_ERR_VALUEOUTOFBOUNDS && hdl_dat != dat                    \
928         && hdl_dat->chain != dat->chain)                                      \
929       bit_chain_free (hdl_dat);                                               \
930     return error;                                                             \
931   }                                                                           \
932   static int dwg_encode_##token##_private (                                   \
933         Bit_Chain *dat, Bit_Chain *hdl_dat, Bit_Chain *str_dat,               \
934         Dwg_Object *restrict obj)                                             \
935   {                                                                           \
936     int error = 0;                                                            \
937     BITCODE_BL vcount, rcount3, rcount4;                                      \
938     Dwg_Data *dwg = obj->parent;                                              \
939     Dwg_Object_##token *_obj = obj->tio.object->tio.token;
940 
941 // some objects specs forgot about the common streams, so add it here
942 #define DWG_OBJECT_END                                                        \
943     if (!obj->hdlpos)                                                         \
944       {                                                                       \
945         START_OBJECT_HANDLE_STREAM                                            \
946       }                                                                       \
947     if (hdl_dat->byte > dat->byte)                                            \
948       {                                                                       \
949         dat->byte = hdl_dat->byte;                                            \
950         dat->bit = hdl_dat->bit;                                              \
951       }                                                                       \
952     if (hdl_dat != dat && hdl_dat->chain != dat->chain)                       \
953       bit_chain_free (hdl_dat);                                               \
954     return error;                                                             \
955   }
956 
957 #define ENT_REACTORS(code)                                                    \
958   if (dat->version >= R_13 && _obj->num_reactors > 0x1000)                    \
959     {                                                                         \
960       LOG_ERROR ("Invalid num_reactors: %ld\n", (long)_obj->num_reactors);    \
961       return DWG_ERR_VALUEOUTOFBOUNDS;                                        \
962     }                                                                         \
963   SINCE (R_13)                                                                \
964   {                                                                           \
965     if (_obj->num_reactors && !_obj->reactors)                                \
966       {                                                                       \
967         LOG_ERROR ("NULL entity.reactors");                                   \
968         return DWG_ERR_VALUEOUTOFBOUNDS;                                      \
969       }                                                                       \
970     for (vcount = 0; vcount < _obj->num_reactors; vcount++)                   \
971       {                                                                       \
972         FIELD_HANDLE_N (reactors[vcount], vcount, code, 330);                 \
973       }                                                                       \
974   }
975 
976 #undef DEBUG_POS
977 #define DEBUG_POS                                                             \
978   if (DWG_LOGLEVEL >= DWG_LOGLEVEL_TRACE)                                     \
979     {                                                                         \
980       LOG_TRACE ("DEBUG_POS @%u.%u / 0x%x (%lu)\n", (unsigned int)dat->byte,  \
981                  dat->bit, (unsigned int)dat->byte, bit_position (dat));      \
982     }
983 
984 /*--------------------------------------------------------------------------------*/
985 typedef struct
986 {
987   unsigned long handle;
988   long address;
989   BITCODE_BL index;
990 } Object_Map;
991 
992 /*--------------------------------------------------------------------------------
993  * Private functions prototypes
994  */
995 static int encode_preR13 (Dwg_Data *restrict dwg, Bit_Chain *restrict dat);
996 
997 static int dwg_encode_entity (Dwg_Object *restrict obj, Bit_Chain *dat,
998                               Bit_Chain *restrict hdl_dat, Bit_Chain *str_dat);
999 static int dwg_encode_object (Dwg_Object *restrict obj, Bit_Chain *dat,
1000                               Bit_Chain *restrict hdl_dat, Bit_Chain *str_dat);
1001 static int dwg_encode_common_entity_handle_data (Bit_Chain *dat,
1002                                                  Bit_Chain *hdl_dat,
1003                                                  Dwg_Object *restrict obj);
1004 static int dwg_encode_header_variables (Bit_Chain *dat, Bit_Chain *hdl_dat,
1005                                         Bit_Chain *str_dat,
1006                                         Dwg_Data *restrict dwg);
1007 static int dwg_encode_variable_type (Dwg_Data *restrict dwg,
1008                                      Bit_Chain *restrict dat,
1009                                      Dwg_Object *restrict obj);
1010 void dwg_encode_handleref (Bit_Chain *hdl_dat, Dwg_Object *restrict obj,
1011                            Dwg_Data *restrict dwg,
1012                            Dwg_Object_Ref *restrict ref);
1013 void dwg_encode_handleref_with_code (Bit_Chain *hdl_dat,
1014                                      Dwg_Object *restrict obj,
1015                                      Dwg_Data *restrict dwg,
1016                                      Dwg_Object_Ref *restrict ref,
1017                                      unsigned int code);
1018 int dwg_encode_add_object (Dwg_Object *restrict obj, Bit_Chain *restrict dat,
1019                            unsigned long address);
1020 
1021 static int dwg_encode_xdata (Bit_Chain *restrict dat,
1022                              Dwg_Object_XRECORD *restrict obj, unsigned size);
1023 static unsigned long add_LibreDWG_APPID (Dwg_Data *dwg);
1024 static BITCODE_BL add_DUMMY_eed (Dwg_Object *obj);
1025 static void fixup_NOD (Dwg_Data *restrict dwg, Dwg_Object *restrict obj);
1026 
1027 /* Imported */
1028 BITCODE_H
1029 dwg_find_tablehandle_silent (Dwg_Data *restrict dwg, const char *restrict name,
1030                              const char *restrict table);
1031 void set_handle_size (Dwg_Handle *restrict hdl);
1032 
1033 /*--------------------------------------------------------------------------------
1034  * Public functions
1035  */
1036 
1037 static BITCODE_RL
encode_patch_RLsize(Bit_Chain * dat,long unsigned int pvzadr)1038 encode_patch_RLsize (Bit_Chain *dat, long unsigned int pvzadr)
1039 {
1040   unsigned long pos;
1041   BITCODE_RL size;
1042   if (dat->bit) // padding
1043     {
1044       dat->bit = 0;
1045       dat->byte++;
1046     }
1047   size = dat->byte - pvzadr - 4; // minus the RL size
1048   pos = bit_position (dat);
1049   assert (pvzadr);
1050   bit_set_position (dat, pvzadr * 8);
1051   bit_write_RL (dat, size);
1052   LOG_TRACE ("size: " FORMAT_RL " [RL] @%lu\n", size, pvzadr);
1053   bit_set_position (dat, pos);
1054   return size;
1055 }
1056 
1057 /* if an error in this section should immediately return with a critical error,
1058  * like INVALIDDWG */
1059 #if 0
1060 static bool
1061 is_section_critical (Dwg_Section_Type i)
1062 {
1063   return (i == SECTION_OBJECTS || i == SECTION_HEADER || i == SECTION_CLASSES
1064           || i == SECTION_HANDLES) ? true : false;
1065 }
1066 #endif
1067 static bool
is_section_r13_critical(Dwg_Section_Type_R13 i)1068 is_section_r13_critical (Dwg_Section_Type_R13 i)
1069 {
1070   return i <= SECTION_HANDLES_R13 ? true : false;
1071 }
1072 
1073 /* Limitations: */
1074 
1075 static unsigned long
add_LibreDWG_APPID(Dwg_Data * dwg)1076 add_LibreDWG_APPID (Dwg_Data *dwg)
1077 {
1078   BITCODE_H appid = dwg_find_tablehandle_silent (dwg, "LibreDWG", "APPID");
1079   BITCODE_H appctl;
1080   Dwg_Object *obj;
1081   Dwg_Object_APPID *_obj;
1082   Dwg_Object_APPID_CONTROL *o;
1083   unsigned long absref;
1084   //int error = 0;
1085 
1086   if (appid)
1087     return appid->absolute_ref;
1088 
1089   // This breaks json.test roundtrips tests as it adds a new object.
1090   // But sooner or later we want to delete yet unsupported objects
1091   // (Dictionaries, MATERIAL, VISUALSTYLE, dynblocks, surfaces, assoc*, ...)
1092 
1093   // add APPID
1094 #if 1
1095 
1096   _obj = dwg_add_APPID (dwg, "LibreDWG");
1097   return dwg_obj_generic_handlevalue (_obj);
1098 
1099 #else
1100   if (!(appctl = dwg->header_vars.APPID_CONTROL_OBJECT))
1101     appctl = dwg_find_table_control (dwg, "APPID_CONTROL");
1102   if (!appctl)
1103     {
1104       LOG_ERROR ("APPID_CONTROL not found")
1105       return 0;
1106     }
1107   absref = dwg->object[dwg->num_objects - 1].handle.value + 1;
1108   dwg_add_object (dwg);
1109   obj = &dwg->object[dwg->num_objects - 1];
1110   if (dwg_setup_APPID (obj) >= DWG_ERR_CRITICAL)
1111     return 0;
1112   dwg_add_handle (&obj->handle, 0, absref, obj);
1113   //obj->type = obj->fixedtype = DWG_TYPE_APPID;
1114   _obj = obj->tio.object->tio.APPID;
1115   // precise size, bitsize done by encode
1116   obj->size = 25;
1117   obj->bitsize = 164;
1118   obj->tio.object->ownerhandle = dwg_add_handleref (dwg, 4, appctl->absolute_ref, NULL);
1119   obj->tio.object->xdicobjhandle = dwg_add_handleref (dwg, 3, 0, NULL);
1120 
1121   _obj->name = dwg_add_u8_input (dwg, "LibreDWG");
1122   _obj->is_xref_ref = 1;
1123   _obj->xref = dwg_add_handleref (dwg, 5, 0, NULL);
1124 
1125   // add to APPID_CONTROL
1126   obj = dwg_ref_object (dwg, appctl);
1127   if (!obj)
1128     {
1129       LOG_ERROR ("APPID_CONTROL not found")
1130       return 0;
1131     }
1132   o = obj->tio.object->tio.APPID_CONTROL;
1133   PUSH_HV (o, num_entries, entries, dwg_add_handleref (dwg, 2, absref, NULL));
1134   return absref;
1135 
1136 #endif
1137 
1138   return 0x12; // APPID.ACAD
1139 }
1140 
1141 static BITCODE_BL
add_DUMMY_eed(Dwg_Object * obj)1142 add_DUMMY_eed (Dwg_Object *obj)
1143 {
1144   Dwg_Object_Entity *ent = obj->tio.entity;
1145   //const int is_entity = obj->supertype == DWG_SUPERTYPE_ENTITY;
1146   const BITCODE_BL num_eed = ent->num_eed; // same offset for object
1147   Dwg_Data *dwg = obj->parent;
1148   char *name = obj->dxfname;
1149   BITCODE_H appid;
1150   Dwg_Eed_Data *data;
1151   int i = 1, off = 0;
1152   int len, size;
1153   const bool is_tu = dwg->header.version >= R_2007;
1154 
1155   // FIXME
1156 #ifdef _WIN
1157 
1158   return 0;
1159 
1160 #else
1161 
1162 #ifdef HAVE_STDDEF_H /* windows (mingw32,cygwin) not */
1163   assert (offsetof (Dwg_Object_Object, num_eed) == offsetof (Dwg_Object_Entity, num_eed));
1164   assert (offsetof (Dwg_Object_Object, eed) == offsetof (Dwg_Object_Entity, eed));
1165 #endif
1166 
1167   if (num_eed) // replace it
1168     dwg_free_eed (obj);
1169   appid = dwg_find_tablehandle_silent (dwg, "LibreDWG", "APPID");
1170   if (!appid)
1171     {
1172       LOG_WARN ("APPID LibreDWG not found, no EED added");
1173       ent->num_eed = 0;
1174       return 0;
1175     }
1176   ent->num_eed = 1;
1177   ent->eed = calloc (2, sizeof (Dwg_Eed));
1178   len = strlen (name);
1179   size = is_tu ? 1 + 2 + ((len + 1) * 2) // RC + RS_LE + wstr
1180                : 1 + 3 + len + 1;        // RC + RC+RS_LE + str
1181   data = ent->eed[0].data = (Dwg_Eed_Data *)calloc (size + 3, 1);
1182   ent->eed[0].size = size;
1183   dwg_add_handle (&ent->eed[0].handle, 5, appid->absolute_ref, NULL);
1184   data->code = 0; // RC
1185   if (is_tu) // probably never used, write DUMMY placeholder to R_2007
1186     {
1187       BITCODE_TU wstr = bit_utf8_to_TU (name, 0);
1188       data->u.eed_0_r2007.is_tu = 1;
1189       data->u.eed_0_r2007.length = len; // RS
1190       memcpy (data->u.eed_0_r2007.string, wstr, len * 2);
1191     }
1192   else
1193     {
1194       data->u.eed_0.is_tu = 0;
1195       data->u.eed_0.length = len;  // RC
1196       data->u.eed_0.codepage = 30; // RS
1197       memcpy (data->u.eed_0.string, name, len);
1198     }
1199   LOG_TRACE ("-EED[0]: code: 0, string: %s (len: %d)\n", name, len);
1200 
1201   if (!obj->num_unknown_bits)
1202     return 1;
1203   // unknown_bits in chunks of 256
1204   len = obj->num_unknown_bits / 8;
1205   if (obj->num_unknown_bits % 8)
1206     len++;
1207   size = (len / 256) + 1;
1208   if (size > 1) // we already reserved for two eeds
1209     {
1210       ent->eed = realloc (ent->eed, (1 + size) * sizeof (Dwg_Eed));
1211       memset (&ent->eed[1], 0, size * sizeof (Dwg_Eed));
1212     }
1213   do
1214     {
1215       int l = len > 255 ? 255 : len;
1216       ent->num_eed++;
1217       ent->eed[i].size = 0;
1218       ent->eed[0].size += l + 2;
1219       data = ent->eed[i].data = (Dwg_Eed_Data *)calloc (l + 2, 1);
1220       data->code = 4;           // RC
1221       data->u.eed_4.length = l; // also just an RC. max 256, how odd
1222       memcpy (data->u.eed_4.data, &obj->unknown_bits[off], data->u.eed_4.length);
1223       LOG_TRACE ("-EED[%d]: code: 4, unknown_bits: %d\n", i, data->u.eed_4.length);
1224       if (len > 255)
1225         {
1226           len -= 256;
1227           off += 256;
1228           i++;
1229         }
1230       else
1231         break;
1232     }
1233   while (1);
1234   return i;
1235 #endif
1236 }
1237 
1238 #ifdef ENCODE_UNKNOWN_AS_DUMMY
1239 
1240 /** We cannot write unknown bits into another version. Also with indxf we don't
1241  * have that luxury. Write a DUMMY/PLACEHOLDER or POINT instead. Later maybe
1242  * PROXY. This leaks and is controversial. But it silences many ACAD import
1243  * warnings, and preserves information.
1244  */
1245 static void
encode_unknown_as_dummy(Bit_Chain * restrict dat,Dwg_Object * restrict obj,BITCODE_BS placeholder_type)1246 encode_unknown_as_dummy (Bit_Chain *restrict dat, Dwg_Object *restrict obj,
1247                          BITCODE_BS placeholder_type)
1248 {
1249   Dwg_Data *dwg = obj->parent;
1250   int is_entity = obj->supertype == DWG_SUPERTYPE_ENTITY;
1251 
1252   obj->size = 0;
1253   obj->bitsize = 0;
1254 
1255   if (is_entity)
1256     { // POINT is better than DUMMY to preserve the next_entity chain.
1257       // TODO much better would be PROXY_ENTITY
1258       Dwg_Entity_POINT *_obj = obj->tio.entity->tio.POINT;
1259       LOG_WARN ("fixup unsupported %s %lX as POINT", obj->dxfname, obj->handle.value);
1260       if (!obj->tio.entity->xdicobjhandle)
1261         obj->tio.entity->xdicobjhandle = dwg_add_handleref (dwg, 3, 0, NULL);
1262       /*
1263       if (obj->tio.entity->num_reactors)
1264         {
1265           free (obj->tio.entity->reactors);
1266           obj->tio.entity->num_reactors = 0;
1267           obj->tio.entity->reactors = NULL;
1268         }
1269       */
1270       add_DUMMY_eed (obj); // broken on windows
1271       dwg_free_object_private (obj);
1272       free (obj->unknown_bits);
1273       obj->tio.entity->tio.POINT = _obj
1274           = realloc (_obj, sizeof (Dwg_Entity_POINT));
1275       // memset (_obj, 0, sizeof (Dwg_Entity_POINT)); // asan cries
1276       _obj->parent = obj->tio.entity;
1277       _obj->x = 0.0;
1278       _obj->y = 0.0;
1279       _obj->z = 0.0;
1280       _obj->thickness = 1e25; // let it stand out
1281       _obj->extrusion.x = 0.0;
1282       _obj->extrusion.y = 0.0;
1283       _obj->extrusion.z = 1.0;
1284       _obj->x_ang = 0.0;
1285       obj->type = DWG_TYPE_POINT;
1286       obj->fixedtype = DWG_TYPE_POINT;
1287       if (dwg->opts & DWG_OPTS_INJSON)
1288         {
1289           free (obj->name);
1290           obj->name = strdup ("POINT");
1291         }
1292       else
1293         obj->name = (char *)"POINT";
1294       if (dwg->opts & DWG_OPTS_IN)
1295         {
1296           free (obj->dxfname);
1297           obj->dxfname = strdup ("POINT");
1298         }
1299       else
1300         obj->dxfname = (char *)"POINT";
1301     }
1302   else
1303     {
1304       const char *name;
1305       const char *dxfname;
1306 
1307       add_DUMMY_eed (obj); // broken on windows
1308       dwg_free_object_private (obj);
1309       // if PLACEHOLDER is available, or even PROXY_OBJECT.
1310       // PLOTSETTINGS uses PLACEHOLDER though
1311       if (placeholder_type)
1312         {
1313           obj->type = placeholder_type;
1314           obj->fixedtype = DWG_TYPE_PLACEHOLDER;
1315           name = "PLACEHOLDER";
1316           dxfname = "ACDBPLACEHOLDER";
1317         }
1318       else
1319         {
1320           obj->type = DWG_TYPE_DUMMY;
1321           obj->fixedtype = DWG_TYPE_DUMMY;
1322           name = "DUMMY";
1323           dxfname = "DUMMY";
1324         }
1325       LOG_INFO ("fixup unsupported %s %lX as %s, Type %d\n", obj->dxfname,
1326                 obj->handle.value, name, obj->type);
1327       if (!obj->tio.object->xdicobjhandle)
1328         obj->tio.object->xdicobjhandle = dwg_add_handleref (dwg, 3, 0, NULL);
1329       // keep owner, xdicobj, reactors
1330       if (dwg->opts & DWG_OPTS_INJSON)
1331         {
1332           free (obj->name);
1333           obj->name = strdup (name);
1334         }
1335       else
1336         obj->name = (char *)name;
1337       if (dwg->opts & DWG_OPTS_IN)
1338         {
1339           free (obj->dxfname);
1340           obj->dxfname = strdup (dxfname);
1341         }
1342       else
1343         obj->dxfname = (char *)dxfname;
1344       free (obj->unknown_bits);
1345     }
1346   obj->hdlpos = 0;
1347 }
1348 #endif
1349 
1350 // delete this NOD entry
1351 // only needed until we can write all object types (at least the ones from the NOD)
1352 static void
remove_NOD_item(Dwg_Object_DICTIONARY * _obj,const int i,const char * name)1353 remove_NOD_item (Dwg_Object_DICTIONARY *_obj, const int i, const char *name)
1354 {
1355   int last = _obj->numitems - 1;
1356   LOG_TRACE ("Disable link to " FORMAT_REF " for NOD.%s\n",
1357              ARGS_REF (_obj->itemhandles[i]), name);
1358   if (i < last)
1359     {
1360       free (_obj->texts[i]);
1361       if (!_obj->itemhandles[i]->handleref.is_global)
1362         free (_obj->itemhandles[i]);
1363       memmove (&_obj->texts[i], &_obj->texts[i+1], (last - i) * sizeof (BITCODE_T));
1364       memmove (&_obj->itemhandles[i], &_obj->itemhandles[i+1], (last - i) * sizeof (BITCODE_H));
1365     }
1366   _obj->numitems--;
1367   return;
1368 }
1369 
1370 // NOD: ACAD_TABLESTYLE => DICT name[0] - itemhandles[0] => TABLESTYLE (Unstable)
1371 // AcDbVariableDictionary: CTABLESTYLE => DICTVAR str
1372 // only needed until we can write all object types (at least the ones from the NOD)
1373 static void
fixup_NOD(Dwg_Data * restrict dwg,Dwg_Object * restrict obj)1374 fixup_NOD (Dwg_Data *restrict dwg, Dwg_Object *restrict obj) // named object dict
1375 {
1376   Dwg_Object_DICTIONARY *_obj;
1377   int is_tu = dwg->header.version >= R_2007;
1378   if (obj->handle.value != 0xC)
1379     return;
1380   _obj = obj->tio.object->tio.DICTIONARY;
1381   // => DICTIONARY with name of current style, and link to it.
1382   // If the link target is disabled (unstable, unhandled or such), remove it from the NOD.
1383 #define DISABLE_NODSTYLE(name)                                                \
1384   if (!is_type_stable (DWG_TYPE_##name))                                      \
1385     {                                                                         \
1386       if (is_tu)                                                              \
1387         {                                                                     \
1388           char *u8 = bit_convert_TU ((BITCODE_TU)_obj->texts[i]);             \
1389           if (u8 && strEQc (u8, "ACAD_" #name))                               \
1390             remove_NOD_item (_obj, i, "ACAD_" #name);                         \
1391           free (u8);                                                          \
1392         }                                                                     \
1393       else if (_obj->texts[i] && strEQc (_obj->texts[i], "ACAD_" #name))      \
1394         remove_NOD_item (_obj, i, "ACAD_" #name);                             \
1395     }
1396 
1397   for (BITCODE_BL i = 0; i < _obj->numitems; i++)
1398     {
1399       DISABLE_NODSTYLE (ASSOCNETWORK)
1400       else DISABLE_NODSTYLE (ASSOCPERSSUBENTMANAGER)
1401       else DISABLE_NODSTYLE (DETAILVIEWSTYLE)
1402       else DISABLE_NODSTYLE (MATERIAL)
1403       else DISABLE_NODSTYLE (MLEADERSTYLE)
1404       else DISABLE_NODSTYLE (MLINESTYLE)
1405       else DISABLE_NODSTYLE (PERSUBENTMGR)
1406       else DISABLE_NODSTYLE (PLOTSETTINGS)
1407       // else DISABLE_NODSTYLE (PLOTSTYLENAME)
1408       else DISABLE_NODSTYLE (SECTIONVIEWSTYLE)
1409       else DISABLE_NODSTYLE (TABLESTYLE)
1410       else DISABLE_NODSTYLE (VISUALSTYLE)
1411     }
1412 #undef DISABLE_NODSTYLE
1413 }
1414 
1415 /* Copy the decomp buffer uncompressed into dat of a DWG r2004+ file. Sets comp_data_size. */
copy_R2004_section(Bit_Chain * restrict dat,BITCODE_RC * restrict decomp,uint32_t decomp_data_size,uint32_t * comp_data_size)1416 static int copy_R2004_section (Bit_Chain *restrict dat, BITCODE_RC *restrict decomp,
1417                                uint32_t decomp_data_size, uint32_t *comp_data_size)
1418 {
1419   if (dat->byte + decomp_data_size >= dat->size)
1420     {
1421       dat->size = dat->byte + decomp_data_size;
1422       bit_chain_alloc (dat);
1423     }
1424   assert (!dat->bit);
1425   memcpy (&dat->chain[dat->byte], decomp, decomp_data_size);
1426   dat->byte += decomp_data_size;
1427   *comp_data_size = decomp_data_size;
1428   return 0;
1429 }
1430 
1431 /* 1 for yes, 0 for no */
1432 static int
section_encrypted(const Dwg_Data * dwg,const Dwg_Section_Type id)1433 section_encrypted (const Dwg_Data *dwg, const Dwg_Section_Type id)
1434 {
1435   switch (id)
1436     {
1437     case SECTION_SECURITY: //??
1438     case SECTION_FILEDEPLIST:
1439     case SECTION_APPINFO:
1440       return 1;
1441     case SECTION_UNKNOWN:
1442     case SECTION_HEADER:
1443     case SECTION_REVHISTORY:
1444     case SECTION_OBJECTS:
1445     case SECTION_OBJFREESPACE:
1446     case SECTION_TEMPLATE:
1447     case SECTION_HANDLES:
1448     case SECTION_CLASSES:
1449     case SECTION_AUXHEADER:
1450     case SECTION_SUMMARYINFO:
1451     case SECTION_PREVIEW:
1452     case SECTION_APPINFOHISTORY:
1453     case SECTION_VBAPROJECT:
1454     case SECTION_SIGNATURE:
1455     case SECTION_ACDS:
1456     case SECTION_SYSTEM_MAP:
1457     case SECTION_INFO:
1458     default:
1459       return 0;
1460     }
1461 }
1462 
1463 /* 1 for yes, 0 for no */
1464 static int
section_compressed(const Dwg_Data * dwg,const Dwg_Section_Type id)1465 section_compressed (const Dwg_Data *dwg, const Dwg_Section_Type id)
1466 {
1467   switch (id)
1468     {
1469     case SECTION_UNKNOWN:
1470     case SECTION_HEADER:
1471     case SECTION_REVHISTORY:
1472     case SECTION_OBJECTS:
1473     case SECTION_OBJFREESPACE:
1474     case SECTION_TEMPLATE:
1475     case SECTION_HANDLES:
1476     case SECTION_CLASSES:
1477     case SECTION_AUXHEADER:
1478     case SECTION_SYSTEM_MAP:
1479     case SECTION_INFO:
1480       return 1;
1481     case SECTION_SUMMARYINFO:
1482     case SECTION_PREVIEW:
1483     case SECTION_APPINFO:
1484     case SECTION_APPINFOHISTORY:
1485     case SECTION_FILEDEPLIST:
1486     case SECTION_SECURITY:
1487     case SECTION_VBAPROJECT:
1488     case SECTION_SIGNATURE:
1489     case SECTION_ACDS:
1490     default:
1491       return 0;
1492     }
1493 }
1494 
1495 /* r2004 compressed sections, LZ77 WIP */
1496 
1497 #define MIN_COMPRESSED_SECTION 19
1498 #define COMPRESSION_BUFFER_SIZE 0x400
1499 #define COMPRESSION_WINDOW_SIZE 0x800
1500 
1501 static void
1502 write_length (Bit_Chain *dat, uint32_t u1, uint32_t match, uint32_t u2);
1503 
1504 /* R2004 Write literal length
1505  */
1506 static unsigned char
write_literal_length(Bit_Chain * restrict dat,BITCODE_RC * restrict buf,uint32_t len)1507 write_literal_length (Bit_Chain *restrict dat, BITCODE_RC *restrict buf, uint32_t len)
1508 {
1509 #if 0
1510   if (len <= (0x0F + 3)) // single byte, opcode 0
1511     {
1512       bit_write_RC (dat, len - 3);
1513       return 0;
1514     }
1515   else if (len < 0xf0)
1516     {
1517       bit_write_RC (dat, len);
1518       return length & 0xff;
1519     }
1520   else
1521     {
1522       uint32_t total = 0x0f;
1523       while (leng >= 0xf0)
1524         {
1525           bit_write_RC (dat, 0);
1526           len -= 0xFF;
1527           total += 0xFF;
1528         }
1529       bit_write_RC (dat, len - 3); // ??
1530       return 0;
1531     }
1532 #else
1533   if (len)
1534     {
1535       if (len > 3) {
1536         write_length (dat, 0, len - 1, 0x11);
1537       }
1538       LOG_INSANE ("LIT %x\n", len)
1539       bit_write_TF (dat, buf, len);
1540     }
1541   return 0;
1542 #endif
1543 }
1544 
1545 /* R2004 Long Compression Offset
1546  */
1547 static void
write_long_compression_offset(Bit_Chain * dat,uint32_t offset)1548 write_long_compression_offset (Bit_Chain *dat, uint32_t offset)
1549 {
1550   while (offset > 0xff)
1551     {
1552       bit_write_RC (dat, 0);
1553       offset -= 0xff;
1554     }
1555   LOG_INSANE (">O 00 %x", offset)
1556   bit_write_RC (dat, (unsigned char)offset);
1557 }
1558 
1559 static void
write_length(Bit_Chain * dat,uint32_t u1,uint32_t match,uint32_t u2)1560 write_length (Bit_Chain *dat, uint32_t u1, uint32_t match, uint32_t u2)
1561 {
1562   if (u2 < match)
1563     {
1564       LOG_INSANE (">L %x ", u1 & 0xff)
1565       bit_write_RC (dat, u1 & 0xff);
1566       write_long_compression_offset (dat, match - u2);
1567       LOG_INSANE ("\n")
1568     }
1569   else
1570     {
1571       LOG_INSANE (">L %x\n", (u1 | (match - 2)) & 0xff);
1572       bit_write_RC (dat, (u1 | (match - 2)) & 0xff);
1573     }
1574 }
1575 
1576 /* R2004 Two Byte Offset
1577  */
1578 #if 0
1579 static unsigned int
1580 write_two_byte_offset (Bit_Chain *restrict dat, uint32_t offset)
1581 {
1582   BITCODE_RC b1, b2;
1583   b1 = offset << 2;
1584   b2 = offset >> 6;
1585   //offset = (firstByte >> 2) | (secondByte << 6);
1586   bit_write_RC (dat, b1);
1587   bit_write_RC (dat, b2);
1588   //*lit_length = (firstByte & 0x03);
1589   return b1 & 0x03;
1590 }
1591 #endif
1592 
1593 static void
write_two_byte_offset(Bit_Chain * restrict dat,uint32_t oldlen,uint32_t offset,uint32_t len)1594 write_two_byte_offset (Bit_Chain *restrict dat, uint32_t oldlen, uint32_t offset, uint32_t len)
1595 {
1596   const unsigned lookahead_buffer_size = COMPRESSION_BUFFER_SIZE;
1597   uint32_t b1, b2;
1598 
1599   LOG_INSANE ("2O %x %x %x: ", oldlen, offset, len)
1600   if ((offset < 0xf) && (oldlen < 0x401))
1601     {
1602       b1 = (offset + 1) * 0x10 | ((oldlen - 1U) & 3) << 2;
1603       b2 = (oldlen - 1U) >> 2;
1604     }
1605   else
1606     {
1607       if (oldlen <= lookahead_buffer_size)
1608         {
1609           b2 = oldlen - 1;
1610           write_length (dat, 0x20, offset, 0x21);
1611         }
1612       else
1613         {
1614           b2 = oldlen - lookahead_buffer_size;
1615           write_length (dat, ((b2 >> 0xb) & 8U) | 0x10, offset, 9);
1616         }
1617       b1 = (b2 & 0xff) << 2;
1618       b2 = b2 >> 6;
1619     }
1620   if (len < 4)
1621     b1 = b1 | len;
1622   LOG_INSANE ("> %x %x\n", b1, b2)
1623   bit_write_RC (dat, b1 & 0xff);
1624   bit_write_RC (dat, b2 & 0xff);
1625 }
1626 
1627 /* Finds the longest match to the substring starting at i
1628    in the lookahead buffer (size ?) from the history window (size ?). */
1629 static int
find_longest_match(BITCODE_RC * restrict decomp,uint32_t decomp_data_size,uint32_t i,uint32_t * lenp)1630 find_longest_match (BITCODE_RC *restrict decomp, uint32_t decomp_data_size, uint32_t i, uint32_t *lenp)
1631 {
1632   const unsigned lookahead_buffer_size = COMPRESSION_BUFFER_SIZE;
1633   const unsigned window_size = COMPRESSION_WINDOW_SIZE;
1634   int offset = 0;
1635   uint32_t bufend = MIN (i + lookahead_buffer_size, decomp_data_size + 1);
1636   *lenp = 0;
1637   // only substring lengths >= 2, anything else compression is longer
1638   for (uint32_t j = i + 2; j < bufend; j++)
1639     {
1640       int start = MAX (0, (int)(i - window_size));
1641       BITCODE_RC *s = &decomp[i];
1642       uint32_t slen = j - i;
1643       for (int k = start; k < (int)i; k++)
1644         {
1645           int curr_offset = i - k;
1646           //unsigned int repetitions = slen / curr_offset;
1647           //unsigned int last = slen % curr_offset;
1648           BITCODE_RC *match = &decomp[k]; // ...
1649           //int matchlen = k + last;
1650           if ((memcmp (s, match, slen) == 0)
1651               && slen > *lenp)
1652             {
1653               offset = curr_offset;
1654               *lenp = slen;
1655             }
1656         }
1657     }
1658   if (offset)
1659     {
1660       LOG_INSANE (">M %u (%u)\n", offset, *lenp)
1661     }
1662   return offset;
1663 }
1664 
1665 /* Compress the decomp buffer into dat of a DWG r2004+ file. Sets comp_data_size.
1666    Variant of the LZ77 algo. ODA section 4.7
1667 */
compress_R2004_section(Bit_Chain * restrict dat,BITCODE_RC * restrict decomp,uint32_t decomp_data_size,uint32_t * comp_data_size)1668 static int compress_R2004_section (Bit_Chain *restrict dat, BITCODE_RC *restrict decomp,
1669                                    uint32_t decomp_data_size, uint32_t *comp_data_size)
1670 {
1671   uint32_t i = 0;
1672   uint32_t match = 0, oldlen = 0;
1673   uint32_t len = 0;
1674   unsigned long pos = bit_position (dat);
1675   LOG_WARN ("compress_R2004_section %d", decomp_data_size);
1676   assert (decomp_data_size > MIN_COMPRESSED_SECTION);
1677   while (i < decomp_data_size - MIN_COMPRESSED_SECTION)
1678     {
1679       int offset = find_longest_match (decomp, decomp_data_size, i, &len);
1680       if (offset)
1681         {
1682           // encode offset + len
1683           if (match)
1684             write_two_byte_offset (dat, oldlen, match, len);
1685           write_literal_length (dat, &decomp[i], len);
1686           i += match;
1687           match = offset;
1688           oldlen = len;
1689         }
1690       else
1691         {
1692           i += 1; // no match found
1693         }
1694     }
1695   len = decomp_data_size - i;
1696   if (match)
1697     write_two_byte_offset (dat, oldlen, match, len);
1698   write_literal_length (dat, &decomp[i], len);
1699   bit_write_RC (dat, 0x11);
1700   bit_write_RC (dat, 0);
1701   bit_write_RC (dat, 0);
1702   *comp_data_size = bit_position (dat) - pos;
1703   LOG_INSANE ("> 11 0 => %u\n", *comp_data_size)
1704   return 0;
1705 }
1706 
1707 static Dwg_Section_Info *
find_section_info_type(const Dwg_Data * restrict dwg,Dwg_Section_Type type)1708 find_section_info_type (const Dwg_Data *restrict dwg, Dwg_Section_Type type)
1709 {
1710   for (unsigned i = 0; i < dwg->header.section_infohdr.num_desc; i++)
1711     {
1712       Dwg_Section_Info *info = &dwg->header.section_info[i];
1713       if (info->fixedtype == type)
1714         return info;
1715     }
1716   return NULL;
1717 }
1718 
1719 /* header.section pointers changed, rebuild all info->sections */
1720 static void
section_info_rebuild(Dwg_Data * dwg,Dwg_Section_Type lasttype)1721 section_info_rebuild (Dwg_Data *dwg, Dwg_Section_Type lasttype)
1722 {
1723   Dwg_Section_Type type;
1724   // we only need to rebuild sections up to the given type
1725   for (type = 0; type <= lasttype; type++)
1726     {
1727       Dwg_Section_Info *info = find_section_info_type (dwg, type);
1728       if (info)
1729         {
1730           unsigned ssi = 0;
1731           for (unsigned i = 0; i < dwg->header.num_sections; i++)
1732             {
1733               Dwg_Section *sec = &dwg->header.section[i];
1734               if (sec->type == type) // first section
1735                 {
1736                   info->sections[ssi] = sec;
1737                   ssi++;
1738                 }
1739               else if (sec->type > type) // sorted by type
1740                 break;
1741             }
1742         }
1743     }
1744 }
1745 
1746 /**
1747  * dwg_encode(): the current generic encoder entry point.
1748  *
1749  * TODO: preR13 tables, 2007 maps.
1750  * 2010+ uses the 2004 format.
1751  * Returns a summary bitmask of all errors.
1752  */
1753 AFL_GCC_TOOBIG
1754 EXPORT int
dwg_encode(Dwg_Data * restrict dwg,Bit_Chain * restrict dat)1755 dwg_encode (Dwg_Data *restrict dwg, Bit_Chain *restrict dat)
1756 {
1757   int ckr_missing = 1;
1758   int error = 0;
1759   BITCODE_BL i, j;
1760   long unsigned int section_address;
1761   long unsigned int pvzadr;
1762   unsigned int ckr;
1763   unsigned int sec_size = 0;
1764   long unsigned int last_offset;
1765   BITCODE_BL last_handle;
1766   Object_Map *omap;
1767   Bit_Chain *old_dat = NULL, *str_dat, *hdl_dat;
1768   int sec_id;
1769   Dwg_Version_Type orig_from_version = dwg->header.from_version;
1770   Bit_Chain sec_dat[SECTION_SYSTEM_MAP + 1]; // to encode each r2004 section
1771 
1772   if (dwg->opts)
1773     loglevel = dwg->opts & DWG_OPTS_LOGLEVEL;
1774 #ifdef USE_TRACING
1775   /* Before starting, set the logging level, but only do so once.  */
1776   if (!env_var_checked_p)
1777     {
1778       char *probe = getenv ("LIBREDWG_TRACE");
1779       if (probe)
1780         loglevel = atoi (probe);
1781       env_var_checked_p = true;
1782     }
1783 #endif /* USE_TRACING */
1784 
1785   if (dwg->header.version != dwg->header.from_version)
1786     LOG_TRACE ("Encode version %s (%s) from version %s (%s)\n",
1787                version_codes[dwg->header.version],
1788                dwg_version_type (dwg->header.version),
1789                version_codes[dwg->header.from_version],
1790                dwg_version_type (dwg->header.from_version))
1791   else
1792     LOG_TRACE ("Encode version %s (%s)\n", version_codes[dwg->header.version],
1793                dwg_version_type (dwg->header.version))
1794 
1795 #ifdef ENCODE_UNKNOWN_AS_DUMMY
1796   // We cannot write unknown_bits into another version, or when it's coming
1797   // from DXF. Write a PLACEHOLDER/DUMMY or POINT instead. Later maybe PROXY.
1798   // This is controversial and breaks roundtrip tests, but helps
1799   // ACAD imports.
1800   if (dwg->header.version != dwg->header.from_version
1801       || (dwg->opts & DWG_OPTS_IN))
1802     {
1803       int fixup = 0;
1804       // Scan for invalid/unstable/unsupported objects and entities
1805       // and eliminate or replace them with placeholders.
1806       LOG_TRACE ("Scan for unsupported objects\n");
1807       for (i = 0; i < dwg->num_objects; i++)
1808         {
1809           Dwg_Object *obj = &dwg->object[i];
1810           if (obj->fixedtype == DWG_TYPE_UNKNOWN_OBJ
1811               || obj->fixedtype == DWG_TYPE_UNKNOWN_ENT
1812               // WIPEOUT causes hang, TABLEGEOMETRY crash
1813               || (dwg->opts & DWG_OPTS_IN &&
1814                   (obj->fixedtype == DWG_TYPE_WIPEOUT ||
1815                    obj->fixedtype == DWG_TYPE_TABLEGEOMETRY)))
1816             {
1817               fixup++;
1818               break;
1819             }
1820         }
1821       if (fixup)
1822         {
1823           unsigned long new_appid;
1824           BITCODE_BS placeholder_type = 0;
1825           LOG_TRACE ("Found unsupported objects, add APPID LibreDWG\n");
1826           new_appid = add_LibreDWG_APPID (dwg);
1827           if (new_appid)
1828             {
1829               fixup = 0;
1830               // if not found leaves placeholder_type at 0 to use DUMMY
1831               dwg_find_class (dwg, "ACDBPLACEHOLDER", &placeholder_type);
1832               for (i = 0; i < dwg->num_objects; i++)
1833                 {
1834                   Dwg_Object *obj = &dwg->object[i];
1835                   if (obj->fixedtype == DWG_TYPE_UNKNOWN_OBJ
1836                       || obj->fixedtype == DWG_TYPE_UNKNOWN_ENT
1837                       || (dwg->opts & DWG_OPTS_IN &&
1838                           (obj->fixedtype == DWG_TYPE_WIPEOUT ||
1839                            obj->fixedtype == DWG_TYPE_TABLEGEOMETRY)))
1840                     {
1841                       fixup++;
1842                       // replace entities with points, objects with
1843                       // placeholders
1844                       encode_unknown_as_dummy (dat, obj, placeholder_type);
1845                     }
1846                   // what to do with links to MATERIAL/...
1847                   if (obj->handle.value == 0xC
1848                       && obj->fixedtype == DWG_TYPE_DICTIONARY)
1849                     fixup_NOD (dwg, obj); // named object dict
1850                 }
1851               LOG_TRACE ("Fixed %d unsupported objects\n\n", fixup);
1852             }
1853         }
1854     }
1855 #endif
1856 
1857   bit_chain_alloc (dat);
1858   hdl_dat = dat; // splitted later in objects/entities
1859   if (!dat->version)
1860     {
1861       dat->version = dwg->header.version;
1862       dat->from_version = dwg->header.from_version;
1863       dat->opts = dwg->opts;
1864     }
1865 
1866   /*------------------------------------------------------------
1867    * Header
1868    */
1869   strcpy ((char *)dat->chain,
1870           version_codes[dwg->header.version]); // Chain version
1871   dat->byte += 6;
1872 
1873   {
1874     Dwg_Header *_obj = &dwg->header;
1875     Dwg_Object *obj = NULL;
1876     if (!_obj->dwg_version) // ie from DXF
1877       {
1878         _obj->zero_one_or_three = 1;
1879         _obj->dwg_version = 0x21;
1880         _obj->is_maint = 0xf;
1881         _obj->maint_version = 29;
1882         if (dwg->header.version < R_13)
1883           {
1884             _obj->dwg_version = 0x14;
1885           }
1886         /*
1887         switch (dwg->header.version)
1888           {
1889           case R_9:
1890             _obj->dwg_version = 0x0b;
1891             break;
1892           case R_10:
1893             _obj->dwg_version = 0x0d;
1894             break;
1895           case R_11:
1896             _obj->dwg_version = 0x10;
1897             break;
1898           case R_13:
1899             _obj->dwg_version = 0x13;
1900             break;
1901           case R_13c3:
1902             _obj->dwg_version = 0x14;
1903             break;
1904           case R_14:
1905             _obj->dwg_version = 0x15;
1906             break;
1907           case R_2000:
1908             _obj->dwg_version = 0x17;
1909             _obj->is_maint = 0xf;
1910             break;
1911           case R_2004:
1912             _obj->dwg_version = 0x19; // or 0x18/0x1a
1913             _obj->is_maint = 0x68;
1914             break;
1915           case R_2007:
1916             _obj->dwg_version = 0x1b;
1917             _obj->is_maint = 0x32;
1918             break;
1919           case R_2010:
1920             _obj->dwg_version = 0x1d;
1921             _obj->is_maint = 0x6d;
1922             break;
1923           case R_2013:
1924             _obj->dwg_version = 0x1f;
1925             _obj->is_maint = 0x7d;
1926             break;
1927           case R_2018:
1928             _obj->dwg_version = 0x21;
1929             _obj->is_maint = 0x1d;
1930             break;
1931           case R_INVALID:
1932           case R_AFTER:
1933           case R_1_1:
1934           case R_1_2:
1935           case R_1_3:
1936           case R_1_4:
1937           case R_1_402b:
1938           case R_2_0:
1939           case R_2_1:
1940           case R_2_21:
1941           case R_2_22:
1942           case R_2_4:
1943           case R_2_5:
1944           case R_2_6:
1945           case R_9c1:
1946           case R_10c1:
1947           case R_10c2:
1948           case R_12:
1949           case R_12c1:
1950           default:
1951             break;
1952           }
1953           */
1954         if (!_obj->app_dwg_version)
1955           _obj->app_dwg_version = _obj->dwg_version;
1956       }
1957     if (!_obj->codepage)
1958       _obj->codepage = 30;
1959 
1960     // clang-format off
1961     #include "header.spec"
1962     // clang-format on
1963   }
1964   section_address = dat->byte;
1965 
1966 #define WE_CAN                                                                \
1967   "This version of LibreDWG is only capable of encoding "                     \
1968   "version R13-R2000 (code: AC1012-AC1015) DWG files.\n"
1969 
1970   PRE (R_13)
1971   {
1972     // TODO: tables, entities, block entities
1973     LOG_ERROR (WE_CAN "We don't encode preR13 tables, entities, blocks yet")
1974 #ifndef IS_RELEASE
1975     return encode_preR13 (dwg, dat);
1976 #endif
1977   }
1978 
1979   PRE (R_2004)
1980   {
1981     /* section 0: header vars
1982      *         1: class section
1983      *         2: object map
1984      *         3: (R13 c3 and later): 2nd header (special table no sentinels)
1985      *         4: optional: MEASUREMENT
1986      *         5: optional: AuxHeader
1987      */
1988     /* Usually 3-5, max 6 */
1989     if (!dwg->header.num_sections
1990         || (dat->from_version >= R_2004 && dwg->header.num_sections > 6))
1991       {
1992         dwg->header.num_sections = dwg->header.version < R_2000 ? 5 : 6;
1993         // minimal DXF:
1994         if (!dwg->header_vars.HANDSEED || !dwg->header_vars.TDCREATE.days)
1995           {
1996             dwg->header.num_sections = 5;
1997             // hack to trigger IF_ENCODE_FROM_EARLIER defaults. undone after
1998             // HEADER
1999             dat->from_version = R_11;
2000             if (dat->version <= dat->from_version)
2001               dat->from_version = (Dwg_Version_Type)((int)dat->version - 1);
2002           }
2003       }
2004     LOG_TRACE ("num_sections: " FORMAT_RL " [RL]\n", dwg->header.num_sections);
2005     bit_write_RL (dat, dwg->header.num_sections);
2006     if (!dwg->header.section)
2007       dwg->header.section = (Dwg_Section*)calloc (dwg->header.num_sections,
2008                                                   sizeof (Dwg_Section));
2009     if (!dwg->header.section)
2010       {
2011         LOG_ERROR ("Out of memory");
2012         return DWG_ERR_OUTOFMEM;
2013       }
2014     section_address = dat->byte;                 // save section address
2015     dat->byte += (dwg->header.num_sections * 9); /* RC + 2*RL */
2016     bit_write_CRC (dat, 0, 0xC0C1);
2017     bit_write_sentinel (dat, dwg_sentinel (DWG_SENTINEL_HEADER_END));
2018 
2019     /*------------------------------------------------------------
2020      * AuxHeader section 5
2021      * R2000+, mostly redundant file header information
2022      */
2023     if (dwg->header.num_sections > 5)
2024       {
2025         Dwg_AuxHeader *_obj = &dwg->auxheader;
2026         Dwg_Object *obj = NULL;
2027         BITCODE_BL vcount;
2028         assert (!dat->bit);
2029         LOG_INFO ("\n=======> AuxHeader: %8u\n",
2030                   (unsigned)dat->byte); // size: 123
2031 
2032         dwg->header.section[SECTION_AUXHEADER_R2000].number = 5;
2033         dwg->header.section[SECTION_AUXHEADER_R2000].address = dat->byte;
2034 
2035         if (!_obj->dwg_version) // todo: needed?
2036           {
2037             BITCODE_RS def_unknown_6rs[] = { 4, 0x565, 0, 0, 2, 1 };
2038             LOG_TRACE ("Use AuxHeader defaults...\n");
2039             FIELD_VALUE (aux_intro[0]) = 0xff;
2040             FIELD_VALUE (aux_intro[1]) = 0x77;
2041             FIELD_VALUE (aux_intro[2]) = 0x01;
2042             FIELD_VALUE (minus_1) = -1;
2043             FIELD_VALUE (dwg_version) = dwg->header.dwg_version;
2044             FIELD_VALUE (maint_version) = dwg->header.maint_version;
2045             FIELD_VALUE (dwg_version_1) = dwg->header.dwg_version;
2046             FIELD_VALUE (dwg_version_2) = dwg->header.dwg_version;
2047             FIELD_VALUE (maint_version_1) = dwg->header.maint_version;
2048             FIELD_VALUE (maint_version_2) = dwg->header.maint_version;
2049             memcpy (FIELD_VALUE (unknown_6rs), def_unknown_6rs,
2050                     sizeof (def_unknown_6rs));
2051             FIELD_VALUE (TDCREATE) = dwg->header_vars.TDCREATE.value;
2052             FIELD_VALUE (TDUPDATE) = dwg->header_vars.TDUPDATE.value;
2053             if (dwg->header_vars.HANDSEED)
2054               FIELD_VALUE (HANDSEED) = dwg->header_vars.HANDSEED->absolute_ref;
2055           }
2056 
2057           // clang-format off
2058         #include "auxheader.spec"
2059         // clang-format on
2060 
2061         assert (!dat->bit);
2062         dwg->header.section[SECTION_AUXHEADER_R2000].size
2063             = dat->byte - dwg->header.section[SECTION_AUXHEADER_R2000].address;
2064       }
2065   }
2066 
2067   VERSION (R_2007)
2068   {
2069     LOG_ERROR (WE_CAN "We don't encode R2007 sections yet");
2070     dat->version = dwg->header.version = R_2010; // rather do 2010
2071     // return DWG_ERR_NOTYETSUPPORTED;
2072   }
2073 
2074   /* r2004 file header (compressed + encrypted) */
2075   SINCE (R_2004)
2076   {
2077     LOG_INFO ("\n");
2078     LOG_ERROR (WE_CAN "Writing R2004 sections not yet finished");
2079 
2080     memset (&sec_dat, 0, (SECTION_SYSTEM_MAP + 1) * sizeof (Bit_Chain));
2081     if (dwg->header.section_infohdr.num_desc && !dwg->header.section_info)
2082       dwg->header.section_info = (Dwg_Section_Info *)calloc (
2083           dwg->header.section_infohdr.num_desc, sizeof (Dwg_Section_Info));
2084     LOG_TRACE ("\n#### r2004 File Header ####\n");
2085     if (dat->byte + 0x80 >= dat->size - 1)
2086       {
2087         dwg->header.num_sections = 28; // room for some object pages
2088         dwg->header.section = calloc (28, sizeof (Dwg_Section));
2089       }
2090     if (!dwg->header.section_info)
2091       {
2092         dwg->header.section_infohdr.num_desc = SECTION_SYSTEM_MAP + 1;
2093         dwg->header.section_info
2094             = calloc (SECTION_SYSTEM_MAP + 1, sizeof (Dwg_Section_Info));
2095       }
2096   }
2097 
2098   /*------------------------------------------------------------
2099    * THUMBNAIL preview pictures
2100    */
2101   old_dat = dat;
2102   SINCE (R_2004)
2103   {
2104     bit_chain_init_dat (&sec_dat[SECTION_PREVIEW], dwg->thumbnail.size + 64, dat);
2105     str_dat = hdl_dat = dat = &sec_dat[SECTION_PREVIEW];
2106   }
2107   else
2108   {
2109     if (!dwg->header.thumbnail_address)
2110       dwg->header.thumbnail_address = dat->byte;
2111   }
2112   dat->bit = 0;
2113   LOG_TRACE ("\n=======> Thumbnail:       %4u\n", (unsigned)dat->byte);
2114   // dwg->thumbnail.size = 0; // to disable
2115   bit_write_sentinel (dat, dwg_sentinel (DWG_SENTINEL_THUMBNAIL_BEGIN));
2116   if (dwg->thumbnail.size == 0)
2117     {
2118       bit_write_RL (dat, 5); // overall size
2119       LOG_TRACE ("Thumbnail size: 5 [RL]\n");
2120       bit_write_RC (dat, 0); // num_pictures
2121       LOG_TRACE ("Thumbnail num_pictures: 0 [RC]\n");
2122     }
2123   else
2124     {
2125       bit_write_TF (dat, dwg->thumbnail.chain, dwg->thumbnail.size);
2126     }
2127   bit_write_sentinel (dat, dwg_sentinel (DWG_SENTINEL_THUMBNAIL_END));
2128 
2129   {
2130     BITCODE_RL bmpsize;
2131     dwg_bmp (dwg, &bmpsize);
2132     if (bmpsize > dwg->thumbnail.size)
2133       LOG_ERROR ("BMP size overflow: %i > %lu\n", bmpsize,
2134                  dwg->thumbnail.size);
2135   }
2136   LOG_TRACE ("         Thumbnail (end): %4u\n", (unsigned)dat->byte);
2137 
2138   /*------------------------------------------------------------
2139    * Header Variables
2140    */
2141   SINCE (R_2004)
2142   {
2143     sec_id = SECTION_HEADER;
2144     bit_chain_init_dat (&sec_dat[sec_id], sizeof (Dwg_Header) + 64, dat);
2145     str_dat = hdl_dat = dat = &sec_dat[sec_id];
2146   }
2147   assert (!dat->bit);
2148   LOG_INFO ("\n=======> Header Variables:   %4u\n", (unsigned)dat->byte);
2149   if (!dwg->header.section)
2150     {
2151       LOG_ERROR ("Empty header.section");
2152       return DWG_ERR_OUTOFMEM;
2153     }
2154   dwg->header.section[0].number = 0;
2155   dwg->header.section[0].address = dat->byte;
2156   bit_write_sentinel (dat, dwg_sentinel (DWG_SENTINEL_VARIABLE_BEGIN));
2157 
2158   pvzadr = dat->byte;      // Size position
2159   bit_write_RL (dat, 540); // Size placeholder
2160   // if (dat->version >= R_2007)
2161   //  str_dat = dat;
2162   dwg_encode_header_variables (dat, hdl_dat, dat, dwg);
2163   // undo minimal HEADER hack
2164   if (dat->from_version != orig_from_version)
2165     dat->from_version = orig_from_version;
2166   encode_patch_RLsize (dat, pvzadr);
2167   bit_write_CRC (dat, pvzadr, 0xC0C1);
2168 
2169   // XXX trying to fix CRC 2-byte overflow. Must find actual reason.
2170   // dat->byte -= 2;
2171   bit_write_sentinel (dat, dwg_sentinel (DWG_SENTINEL_VARIABLE_END));
2172   assert ((long)dat->byte > (long)dwg->header.section[0].address);
2173   dwg->header.section[0].size
2174       = (BITCODE_RL) ((long)dat->byte - (long)dwg->header.section[0].address);
2175   LOG_TRACE ("         Header Variables (end): %4u\n", (unsigned)dat->byte);
2176 
2177   /*------------------------------------------------------------
2178    * Classes
2179    */
2180   SINCE (R_2004)
2181   {
2182     sec_id = SECTION_CLASSES;
2183     bit_chain_init_dat (&sec_dat[sec_id],
2184                     (sizeof (Dwg_Class) * dwg->num_classes) + 32, dat);
2185     str_dat = hdl_dat = dat = &sec_dat[sec_id];
2186   }
2187   else sec_id = SECTION_CLASSES_R13;
2188   LOG_INFO ("\n=======> Classes: %4u (%d)\n", (unsigned)dat->byte,
2189             dwg->num_classes);
2190   if (dwg->num_classes > 5000)
2191     {
2192       LOG_ERROR ("Invalid dwg->num_classes %d", dwg->num_classes)
2193       dwg->num_classes = 0;
2194       error |= DWG_ERR_VALUEOUTOFBOUNDS | DWG_ERR_CLASSESNOTFOUND;
2195     }
2196   dwg->header.section[sec_id].number = 1;
2197   dwg->header.section[sec_id].address = dat->byte; // FIXME
2198   bit_write_sentinel (dat, dwg_sentinel (DWG_SENTINEL_CLASS_BEGIN));
2199   pvzadr = dat->byte;    // Size position
2200   bit_write_RL (dat, 0); // Size placeholder
2201 
2202   for (j = 0; j < dwg->num_classes; j++)
2203     {
2204       Dwg_Class *klass;
2205       klass = &dwg->dwg_class[j];
2206       bit_write_BS (dat, klass->number);
2207       bit_write_BS (dat, klass->proxyflag);
2208       SINCE (R_2007) {
2209         bit_write_T (dat, klass->appname);
2210         bit_write_T (dat, klass->cppname);
2211       } else {
2212         bit_write_TV (dat, klass->appname);
2213         bit_write_TV (dat, klass->cppname);
2214       }
2215       SINCE (R_2007) // only when we have it. like not for 2004 => 2007
2216                      // conversions
2217       {
2218         if (klass->dxfname_u)
2219           bit_write_TU (dat, klass->dxfname_u);
2220         else
2221           bit_write_T (dat, klass->dxfname);
2222       }
2223       else // we always have this one
2224           bit_write_TV (dat, klass->dxfname);
2225       bit_write_B (dat, klass->is_zombie);
2226       bit_write_BS (dat, klass->item_class_id);
2227       LOG_TRACE ("Class %d 0x%x %s\n"
2228                  " %s \"%s\" %d 0x%x\n",
2229                  klass->number, klass->proxyflag, klass->dxfname,
2230                  klass->cppname, klass->appname, klass->is_zombie,
2231                  klass->item_class_id)
2232 
2233       SINCE (R_2007)
2234       {
2235         if (dat->from_version < R_2007 && !klass->dwg_version) {
2236           // defaults
2237           klass->dwg_version = (BITCODE_BL)dwg->header.dwg_version;
2238           klass->maint_version = (BITCODE_BL)dwg->header.maint_version;
2239           // TODO num_instances
2240         }
2241         bit_write_BL (dat, klass->num_instances);
2242         bit_write_BL (dat, klass->dwg_version);
2243         bit_write_BL (dat, klass->maint_version);
2244         bit_write_BL (dat, klass->unknown_1);
2245         bit_write_BL (dat, klass->unknown_2);
2246         LOG_TRACE (" %d %d\n", (int)klass->num_instances,
2247                    (int)klass->dwg_version);
2248       }
2249     }
2250 
2251   /* Write the size of the section at its beginning
2252    */
2253   assert (pvzadr);
2254   encode_patch_RLsize (dat, pvzadr);
2255   bit_write_CRC (dat, pvzadr, 0xC0C1);
2256   bit_write_sentinel (dat, dwg_sentinel (DWG_SENTINEL_CLASS_END));
2257   dwg->header.section[SECTION_CLASSES_R13].size
2258       = dat->byte - dwg->header.section[SECTION_CLASSES_R13].address;
2259   LOG_TRACE ("       Classes (end): %4u\n", (unsigned)dat->byte);
2260 
2261   bit_write_RL (dat, 0x0DCA); // 0xDCA Unknown bitlong inter class and objects
2262   LOG_TRACE ("unknown: %04X [RL]\n", 0x0DCA);
2263 
2264   /*------------------------------------------------------------
2265    * Objects
2266    */
2267 
2268   SINCE (R_2004)
2269   {
2270     sec_id = SECTION_OBJECTS;
2271     bit_chain_alloc (&sec_dat[sec_id]);
2272     str_dat = hdl_dat = dat = &sec_dat[sec_id];
2273     bit_chain_set_version (dat, old_dat);
2274   }
2275   LOG_INFO ("\n=======> Objects: %4u\n", (unsigned)dat->byte);
2276   pvzadr = dat->byte;
2277 
2278   /* Sort object-map by ascending handles
2279    */
2280   LOG_TRACE ("num_objects: %i\n", dwg->num_objects);
2281   LOG_TRACE ("num_object_refs: %i\n", dwg->num_object_refs);
2282   omap = (Object_Map *)calloc (dwg->num_objects, sizeof (Object_Map));
2283   if (!omap)
2284     {
2285       LOG_ERROR ("Out of memory");
2286       return DWG_ERR_OUTOFMEM;
2287     }
2288   if (DWG_LOGLEVEL >= DWG_LOGLEVEL_HANDLE)
2289     {
2290       LOG_HANDLE ("\nSorting objects...\n");
2291       for (i = 0; i < dwg->num_objects; i++)
2292         fprintf (OUTPUT, "Object(%3i): %4lX / idx: %u\n", i,
2293                  dwg->object[i].handle.value, dwg->object[i].index);
2294     }
2295   // init unsorted
2296   for (i = 0; i < dwg->num_objects; i++)
2297     {
2298       omap[i].index = i; // i.e. dwg->object[j].index
2299       omap[i].handle = dwg->object[i].handle.value;
2300     }
2301   // insertion sort
2302   for (i = 0; i < dwg->num_objects; i++)
2303     {
2304       Object_Map tmap;
2305       j = i;
2306       tmap = omap[i];
2307       while (j > 0 && omap[j - 1].handle > tmap.handle)
2308         {
2309           omap[j] = omap[j - 1];
2310           j--;
2311         }
2312       omap[j] = tmap;
2313     }
2314   if (DWG_LOGLEVEL >= DWG_LOGLEVEL_HANDLE)
2315     {
2316       LOG_HANDLE ("\nSorted handles:\n");
2317       for (i = 0; i < dwg->num_objects; i++)
2318         fprintf (OUTPUT, "Handle(%3i): %4lX / idx: %u\n", i, omap[i].handle,
2319                  omap[i].index);
2320     }
2321 
2322   /* Write the sorted objects
2323    */
2324   for (i = 0; i < dwg->num_objects; i++)
2325     {
2326       Dwg_Object *obj;
2327       BITCODE_BL index = omap[i].index;
2328       unsigned long hdloff = omap[i].handle - (i ? omap[i - 1].handle : 0);
2329       int off = dat->byte - (i ? omap[i - 1].address : 0);
2330       unsigned long end_address;
2331       LOG_TRACE ("\n> Next object: " FORMAT_BL
2332                  " Handleoff: %lX [UMC] Offset: %d [MC] @%lu\n"
2333                  "==========================================\n",
2334                  i, hdloff, off, dat->byte);
2335       omap[i].address = dat->byte;
2336       if (index > dwg->num_objects)
2337         {
2338           LOG_ERROR ("Invalid object map index " FORMAT_BL ", max " FORMAT_BL
2339                      ". Skipping",
2340                      index, dwg->num_objects)
2341           error |= DWG_ERR_VALUEOUTOFBOUNDS;
2342           continue;
2343         }
2344       obj = &dwg->object[index];
2345       // change the address to the linearly sorted one
2346 #ifndef NDEBUG
2347       PRE (R_2004)
2348         assert (dat->byte);
2349 #endif
2350       if (!obj->parent)
2351         obj->parent = dwg;
2352       error |= dwg_encode_add_object (obj, dat, dat->byte);
2353 
2354 #ifndef NDEBUG
2355       // check if this object overwrote at address 0. but with r2004 it starts
2356       // fresh.
2357       if (dwg->header.version >= R_1_2 && dwg->header.version < R_2004)
2358         {
2359           if (dat->size < 6 || dat->chain[0] != 'A' || dat->chain[1] != 'C')
2360             {
2361               LOG_ERROR ("Encode overwrite pos 0, invalid DWG magic");
2362               return DWG_ERR_INVALIDDWG;
2363             }
2364           assert (dat->size > 6);
2365           assert (dat->chain[0] == 'A');
2366           assert (dat->chain[1] == 'C');
2367         }
2368 #endif
2369       end_address = omap[i].address + (unsigned long)obj->size; // from RL
2370       if (end_address > dat->size)
2371         {
2372           dat->size = end_address;
2373           bit_chain_alloc (dat);
2374         }
2375     }
2376 
2377   if (DWG_LOGLEVEL >= DWG_LOGLEVEL_HANDLE)
2378     {
2379       LOG_HANDLE ("\nSorted objects:\n");
2380       for (i = 0; i < dwg->num_objects; i++)
2381         LOG_HANDLE ("Object(%d): %lX / Address: %ld / Idx: %d\n", i,
2382                     omap[i].handle, omap[i].address, omap[i].index);
2383     }
2384 
2385   /* Unknown CRC between objects and object map
2386    */
2387   bit_write_RS (dat, 0);
2388   LOG_TRACE ("unknown crc?: %04X [RS]\n", 0);
2389 
2390   /*------------------------------------------------------------
2391    * Object-map
2392    * split into chunks of max. 2030
2393    */
2394   LOG_INFO ("\n=======> Object Map: %4u\n", (unsigned)dat->byte);
2395   SINCE (R_2004)
2396   {
2397     sec_id = SECTION_HANDLES;
2398     bit_chain_init_dat (&sec_dat[sec_id], (8 * dwg->num_objects) + 32, dat);
2399     str_dat = hdl_dat = dat = &sec_dat[sec_id];
2400   }
2401   else
2402   {
2403     sec_id = SECTION_HANDLES_R13;
2404     dwg->header.section[sec_id].number = 2;
2405     dwg->header.section[sec_id].address = dat->byte;
2406     pvzadr = dat->byte; // Correct value of section size must be written later
2407     dat->byte += 2;
2408   }
2409 
2410   last_offset = 0;
2411   last_handle = 0;
2412   for (i = 0; i < dwg->num_objects; i++)
2413     {
2414       BITCODE_BL index;
2415       BITCODE_UMC handleoff;
2416       BITCODE_MC offset;
2417 
2418       index = omap[i].index;
2419       handleoff = omap[i].handle - last_handle;
2420       bit_write_UMC (dat, handleoff);
2421       LOG_HANDLE ("Handleoff(%3i): %4lX [UMC] (%4lX), ", index, handleoff,
2422                   omap[i].handle)
2423       last_handle = omap[i].handle;
2424 
2425       offset = omap[i].address - last_offset;
2426       bit_write_MC (dat, offset);
2427       last_offset = omap[i].address;
2428       LOG_HANDLE ("Offset: %8d [MC] @%lu\n", (int)offset, last_offset);
2429 
2430       ckr_missing = 1;
2431       if (dat->byte - pvzadr > 2030) // 2029
2432         {
2433           ckr_missing = 0;
2434           sec_size = dat->byte - pvzadr;
2435           assert (pvzadr);
2436           // i.e. encode_patch_RS_LE_size
2437           dat->chain[pvzadr] = sec_size >> 8;
2438           dat->chain[pvzadr + 1] = sec_size & 0xFF;
2439           LOG_TRACE ("Handles page size: %u [RS_LE] @%lu\n", sec_size, pvzadr);
2440           bit_write_CRC_LE (dat, pvzadr, 0xC0C1);
2441 
2442           pvzadr = dat->byte;
2443           dat->byte += 2;
2444           last_offset = 0;
2445           last_handle = 0;
2446         }
2447     }
2448   // printf ("Obj size: %u\n", i);
2449   if (ckr_missing)
2450     {
2451       sec_size = dat->byte - pvzadr;
2452 #ifndef NDEBUG
2453       PRE (R_2004)
2454         assert (pvzadr);
2455 #endif
2456       if (pvzadr + 1 >= dat->size)
2457         bit_chain_alloc(dat);
2458       // i.e. encode_patch_RS_LE_size
2459       dat->chain[pvzadr] = sec_size >> 8;
2460       dat->chain[pvzadr + 1] = sec_size & 0xFF;
2461       LOG_TRACE ("Handles page size: %u [RS_LE] @%lu\n", sec_size, pvzadr);
2462       bit_write_CRC_LE (dat, pvzadr, 0xC0C1);
2463     }
2464 #ifndef NDEBUG
2465   if (dwg->header.version >= R_1_2 && dwg->header.version < R_2004)
2466     {
2467       if (dat->size < 4 || dat->chain[0] != 'A' || dat->chain[1] != 'C')
2468         {
2469           LOG_ERROR ("Encode overwrite pos 0");
2470           return DWG_ERR_INVALIDDWG;
2471         }
2472       assert (dat->chain[0] == 'A');
2473       assert (dat->chain[1] == 'C');
2474     }
2475   PRE (R_2004)
2476     assert (dat->byte);
2477 #endif
2478   pvzadr = dat->byte;
2479   bit_write_RS_LE (dat, 2); // last section_size 2
2480   LOG_TRACE ("Handles page size: %u [RS_LE] @%lu\n", 2, pvzadr);
2481   bit_write_CRC_LE (dat, pvzadr, 0xC0C1);
2482 
2483   /* Calculate and write the size of the object map
2484    */
2485   dwg->header.section[sec_id].size
2486       = dat->byte - dwg->header.section[sec_id].address;
2487   free (omap);
2488 
2489   /*------------------------------------------------------------
2490    * Second header, section 3. R13-R2000 only.
2491    * But partially also since r2004. (TODO: under which name? AuxHeader?)
2492    */
2493   if (dwg->header.version >= R_13 && dwg->header.version < R_2004 // TODO
2494       && dwg->second_header.num_sections > 3)
2495     {
2496       struct _dwg_second_header *_obj = &dwg->second_header;
2497       Dwg_Object *obj = NULL;
2498       BITCODE_BL vcount;
2499 
2500       assert (dat->byte);
2501       if (!_obj->address)
2502         _obj->address = dat->byte;
2503       dwg->header.section[SECTION_2NDHEADER_R13].number = 3;
2504       dwg->header.section[SECTION_2NDHEADER_R13].address = _obj->address;
2505       dwg->header.section[SECTION_2NDHEADER_R13].size = _obj->size;
2506       LOG_INFO ("\n=======> Second Header: %4u\n", (unsigned)dat->byte);
2507       bit_write_sentinel (dat,
2508                           dwg_sentinel (DWG_SENTINEL_SECOND_HEADER_BEGIN));
2509 
2510       pvzadr = dat->byte; // Keep the first address of the section to write its
2511                           // size later
2512       LOG_TRACE ("pvzadr: %u\n", (unsigned)pvzadr);
2513       if (!_obj->size && !_obj->num_sections)
2514         {
2515           LOG_TRACE ("Use second_header defaults...\n");
2516           strcpy ((char *)&_obj->version[0],
2517                   &version_codes[dwg->header.version][0]);
2518           memset (&_obj->version[7], 0, 4);
2519           _obj->version[11] = '\n';
2520           _obj->unknown_10 = 0x10;
2521           _obj->unknown_rc4[0] = 0x84;
2522           _obj->unknown_rc4[1] = 0x74;
2523           _obj->unknown_rc4[2] = 0x78;
2524           _obj->unknown_rc4[3] = 0x1;
2525           _obj->junk_r14_1 = 1957593121; //?
2526           _obj->junk_r14_2 = 2559919056; //?
2527           // TODO handlers defaults
2528         }
2529       // always recomputed, even with dwgrewrite
2530       if (dwg->header.version <= R_2000)
2531         {
2532           _obj->num_sections = dwg->header.num_sections;
2533           for (i = 0; i < _obj->num_sections; i++)
2534             {
2535               _obj->section[i].nr = dwg->header.section[i].number;
2536               _obj->section[i].address = dwg->header.section[i].address;
2537               _obj->section[i].size = dwg->header.section[i].size;
2538             }
2539         }
2540       FIELD_RL (size, 0);
2541       if (FIELD_VALUE (address) != (BITCODE_RL) (pvzadr - 16))
2542         {
2543           LOG_WARN ("second_header->address %u != %u", FIELD_VALUE (address),
2544                     (unsigned)(pvzadr - 16));
2545           FIELD_VALUE (address) = pvzadr - 16;
2546           dwg->header.section[SECTION_2NDHEADER_R13].address = _obj->address;
2547           dwg->header.section[SECTION_2NDHEADER_R13].size = _obj->size;
2548         }
2549       FIELD_BL (address, 0);
2550 
2551       // AC1012, AC1014 or AC1015. This is a char[11], zero padded.
2552       // with \n at 12.
2553       bit_write_TF (dat, (BITCODE_TF)_obj->version, 12);
2554       LOG_TRACE ("version: %s [TFF 12]\n", _obj->version)
2555 
2556       for (i = 0; i < 4; i++)
2557         FIELD_B (null_b[i], 0);
2558       FIELD_RC (unknown_10, 0); // 0x10
2559       for (i = 0; i < 4; i++)
2560         FIELD_RC (unknown_rc4[i], 0);
2561 
2562       UNTIL (R_2000)
2563       {
2564         FIELD_RC (num_sections, 0); // r14: 5, r2000: 6 (auxheader)
2565         for (i = 0; i < FIELD_VALUE (num_sections); i++)
2566           {
2567             FIELD_RC (section[i].nr, 0);
2568             FIELD_BL (section[i].address, 0);
2569             FIELD_BLd (section[i].size, 0);
2570           }
2571 
2572         FIELD_BS (num_handlers, 0); // 14, resp. 16 in r14
2573         if (FIELD_VALUE (num_handlers) > 16)
2574           {
2575             LOG_ERROR ("Second header num_handlers > 16: %d\n",
2576                        FIELD_VALUE (num_handlers));
2577             FIELD_VALUE (num_handlers) = 14;
2578           }
2579         for (i = 0; i < FIELD_VALUE (num_handlers); i++)
2580           {
2581             FIELD_RC (handlers[i].size, 0);
2582             FIELD_RC (handlers[i].nr, 0);
2583             FIELD_VECTOR (handlers[i].data, RC, handlers[i].size, 0);
2584           }
2585 
2586         _obj->size = encode_patch_RLsize (dat, pvzadr);
2587         bit_write_CRC (dat, pvzadr, 0xC0C1);
2588 
2589         VERSION (R_14)
2590         {
2591           FIELD_RL (junk_r14_1, 0);
2592           FIELD_RL (junk_r14_2, 0);
2593         }
2594       }
2595       bit_write_sentinel (dat, dwg_sentinel (DWG_SENTINEL_SECOND_HEADER_END));
2596       dwg->header.section[SECTION_2NDHEADER_R13].size
2597           = dat->byte - _obj->address;
2598     }
2599   else if (dwg->header.num_sections > SECTION_2NDHEADER_R13
2600            && dwg->header.version < R_2004) // TODO
2601     {
2602       dwg->header.section[SECTION_2NDHEADER_R13].number = 3;
2603       dwg->header.section[SECTION_2NDHEADER_R13].address = 0;
2604       dwg->header.section[SECTION_2NDHEADER_R13].size = 0;
2605     }
2606 
2607   /*------------------------------------------------------------
2608    * MEASUREMENT/Template Section 4
2609    * In a DXF under header_vars
2610    */
2611   SINCE (R_2004)
2612   {
2613     sec_id = SECTION_TEMPLATE;
2614     bit_chain_init_dat (&sec_dat[sec_id], 16, dat);
2615     str_dat = hdl_dat = dat = &sec_dat[sec_id];
2616   }
2617   else sec_id = SECTION_MEASUREMENT_R13;
2618 
2619   if (dwg->header.version >= R_2004 || (int)dwg->header.num_sections > sec_id)
2620     {
2621       LOG_INFO ("\n=======> MEASUREMENT: %4u\n", (unsigned)dat->byte);
2622       dwg->header.section[sec_id].number = 4;
2623       dwg->header.section[sec_id].address = dat->byte;
2624       dwg->header.section[sec_id].size = 4;
2625       // 0 - English, 1- Metric
2626       bit_write_RL_LE (dat, (BITCODE_RL)dwg->header_vars.MEASUREMENT ? 256 : 0);
2627       LOG_TRACE ("HEADER.MEASUREMENT: %d [RL_LE]\n",
2628                  dwg->header_vars.MEASUREMENT);
2629     }
2630 
2631   /* End of the file
2632    */
2633   dat->size = dat->byte;
2634   SINCE (R_2004)
2635   {
2636     Dwg_Section_Type type;
2637     Dwg_Object *obj = NULL;
2638     BITCODE_BL vcount, rcount3;
2639     size_t size;
2640     unsigned total_size = 0;
2641 
2642     // write remaining section data
2643     for (type = SECTION_OBJFREESPACE; type < SECTION_SYSTEM_MAP; type++)
2644       {
2645         if (type != SECTION_OBJECTS && type != SECTION_PREVIEW)
2646           LOG_TRACE ("\n=== Section %s ===\n", dwg_section_name (dwg, type))
2647         switch (type)
2648           {
2649           case SECTION_HEADER: // ignore, already done
2650           case SECTION_AUXHEADER:
2651           case SECTION_CLASSES:
2652           case SECTION_HANDLES:
2653           case SECTION_TEMPLATE:
2654           case SECTION_PREVIEW:
2655           case SECTION_OBJECTS:
2656           case SECTION_UNKNOWN: // deferred
2657           case SECTION_INFO:
2658           case SECTION_SYSTEM_MAP:
2659             break;
2660           case SECTION_OBJFREESPACE:
2661             {
2662               Dwg_ObjFreeSpace *_obj = &dwg->objfreespace;
2663               bit_chain_alloc (&sec_dat[type]);
2664               str_dat = hdl_dat = dat = &sec_dat[type];
2665               bit_chain_set_version (dat, old_dat);
2666 #include "objfreespace.spec"
2667               LOG_TRACE ("-size: %lu\n", dat->byte)
2668             }
2669             break;
2670           case SECTION_REVHISTORY:
2671             {
2672               Dwg_RevHistory *_obj = &dwg->revhistory;
2673               bit_chain_alloc (&sec_dat[type]);
2674               str_dat = hdl_dat = dat = &sec_dat[type];
2675               bit_chain_set_version (dat, old_dat);
2676 #include "revhistory.spec"
2677               LOG_TRACE ("-size: %lu\n", dat->byte)
2678             }
2679             break;
2680           case SECTION_SUMMARYINFO:
2681             {
2682               Dwg_SummaryInfo *_obj = &dwg->summaryinfo;
2683               bit_chain_alloc (&sec_dat[type]);
2684               str_dat = hdl_dat = dat = &sec_dat[type];
2685               bit_chain_set_version (dat, old_dat);
2686 #include "summaryinfo.spec"
2687               LOG_TRACE ("-size: %lu\n", dat->byte)
2688             }
2689             break;
2690           case SECTION_APPINFO:
2691             {
2692               Dwg_AppInfo *_obj = &dwg->appinfo;
2693               bit_chain_alloc (&sec_dat[type]);
2694               str_dat = hdl_dat = dat = &sec_dat[type];
2695               bit_chain_set_version (dat, old_dat);
2696 #include "appinfo.spec"
2697               LOG_TRACE ("-size: %lu\n", dat->byte)
2698             }
2699             break;
2700           case SECTION_APPINFOHISTORY:
2701             {
2702 #if 0
2703               Dwg_AppInfoHistory *_obj = &dwg->appinfohistory;
2704               bit_chain_alloc (&sec_dat[type]);
2705               str_dat = hdl_dat = dat = &sec_dat[type];
2706               bit_chain_set_version (dat, old_dat);
2707 #  include "appinfohistory.spec"
2708               LOG_TRACE ("-size: %lu\n", dat->byte)
2709 #endif
2710             }
2711             break;
2712           case SECTION_FILEDEPLIST:
2713             {
2714               Dwg_FileDepList *_obj = &dwg->filedeplist;
2715               bit_chain_alloc (&sec_dat[type]);
2716               str_dat = hdl_dat = dat = &sec_dat[type];
2717               bit_chain_set_version (dat, old_dat);
2718 #include "filedeplist.spec"
2719               LOG_TRACE ("-size: %lu\n", dat->byte)
2720             }
2721             break;
2722           case SECTION_SECURITY:
2723             {
2724               Dwg_Security *_obj = &dwg->security;
2725               bit_chain_alloc (&sec_dat[type]);
2726               str_dat = hdl_dat = dat = &sec_dat[type];
2727               bit_chain_set_version (dat, old_dat);
2728 #include "security.spec"
2729               LOG_TRACE ("-size: %lu\n", dat->byte)
2730             }
2731             break;
2732           case SECTION_SIGNATURE:
2733             {
2734 #if 0
2735               Dwg_Signature *_obj = &dwg->signature;
2736               bit_chain_alloc (&sec_dat[type]);
2737               str_dat = hdl_dat = dat = &sec_dat[type];
2738               bit_chain_set_version (dat, old_dat);
2739               {
2740 #  include "signature.spec"
2741               }
2742               LOG_TRACE ("-size: %lu\n", dat->byte)
2743 #endif
2744             }
2745             break;
2746           case SECTION_ACDS:
2747             {
2748 #if 0
2749               Dwg_AcDs *_obj = &dwg->acds;
2750               bit_chain_alloc (&sec_dat[type]);
2751               str_dat = hdl_dat = dat = &sec_dat[type];
2752               bit_chain_set_version (dat, old_dat);
2753               {
2754 #  include "acds.spec"
2755               }
2756               LOG_TRACE ("-size: %lu\n", dat->byte)
2757 #endif
2758             }
2759             break;
2760           case SECTION_VBAPROJECT: // nyi
2761           default:
2762             break;
2763           }
2764       }
2765     // and write system and data section maps.
2766     dat = old_dat;
2767 
2768     /*-------------------------------------------------------------------------
2769      * Section map and info
2770      */
2771     // no gaps, so header->num_sections == r2004_header->numsections
2772     // get together all the section sizes, and set the addresses
2773     {
2774       int ssize;
2775       int si, info_id;
2776       unsigned address;
2777 
2778       const Dwg_Section_Type section_map_order[] = {
2779         // R2004_Header
2780         SECTION_UNKNOWN, // the empty section 128-256
2781         SECTION_SECURITY,       SECTION_FILEDEPLIST, SECTION_ACDS,
2782         SECTION_VBAPROJECT,
2783         SECTION_APPINFOHISTORY, //? at least before AppInfo
2784         SECTION_APPINFO,        SECTION_PREVIEW,
2785         SECTION_SUMMARYINFO, // sometimes this is before Preview
2786         SECTION_REVHISTORY,     SECTION_OBJECTS,     SECTION_OBJFREESPACE,
2787         SECTION_TEMPLATE,       SECTION_HANDLES,     SECTION_CLASSES,
2788         SECTION_AUXHEADER,      SECTION_HEADER,      SECTION_SIGNATURE,
2789 
2790         SECTION_INFO,           SECTION_SYSTEM_MAP
2791       };
2792 
2793       // not the order in the system map, but the order in the dat stream.
2794       const Dwg_Section_Type stream_order[]
2795           = {                  // R2004_Header
2796               SECTION_UNKNOWN, // the empty section 128-256
2797               SECTION_SUMMARYINFO, SECTION_PREVIEW,        SECTION_VBAPROJECT,
2798               SECTION_APPINFO,     SECTION_APPINFOHISTORY, SECTION_FILEDEPLIST,
2799               SECTION_ACDS,        SECTION_REVHISTORY,     SECTION_SECURITY,
2800               SECTION_OBJECTS,     SECTION_OBJFREESPACE,   SECTION_TEMPLATE,
2801               SECTION_HANDLES,     SECTION_CLASSES,        SECTION_AUXHEADER,
2802               SECTION_HEADER,
2803 
2804               SECTION_SIGNATURE, //?
2805 
2806               SECTION_INFO,        SECTION_SYSTEM_MAP
2807             };
2808 
2809       dwg->r2004_header.numsections = 0;
2810       dwg->r2004_header.numgaps = 0;
2811 
2812       //sec_dat[SECTION_UNKNOWN].byte = 0;
2813       sec_dat[SECTION_INFO].byte = 10
2814                                    + (dwg->header.section_infohdr.num_desc
2815                                       * sizeof (Dwg_Section_Info));
2816       // only a guess, reserve at least one page
2817       sec_dat[SECTION_SYSTEM_MAP].byte = (4 * 20 * sizeof (Dwg_Section));
2818 
2819       section_address = 0x100;
2820       // first all the data pages, than a number gap of 1, and last the two
2821       // system page maps, info and system_map the data_pages (system_map
2822       // sections) can include multiple pages of the same type.
2823       LOG_TRACE ("\n=== Section map and info page sizes ===\n");
2824       for (si = 0, info_id = 0, type = 0; type <= SECTION_SYSTEM_MAP;
2825            type++, i++)
2826         {
2827           if (sec_dat[type].byte)
2828             {
2829               const unsigned int max_decomp_size
2830                   = section_max_decomp_size (dwg, type);
2831               const char *name = dwg_section_name (dwg, type);
2832               Dwg_Section_Info *info;
2833               if (sec_dat[type].bit)
2834                 {
2835                   LOG_WARN ("Unpadded section %d", type);
2836                   sec_dat[type].byte++;
2837                 }
2838               ssize = (int)sec_dat[type].byte;
2839               sec_dat[type].size = ssize;
2840               if (info_id >= (int)dwg->header.section_infohdr.num_desc)
2841                 {
2842                   dwg->header.section_infohdr.num_desc = info_id + 1;
2843                   dwg->header.section_info
2844                       = realloc (dwg->header.section_info,
2845                                  (info_id + 1) * sizeof (Dwg_Section));
2846                 }
2847               info = &dwg->header.section_info[info_id];
2848               info->fixedtype = type;
2849               info->type = type;
2850               info->unknown = 1;
2851               if (name && si && type < SECTION_INFO) // not UNKNOWN and the last two
2852                 strcpy (info->name, name);
2853               else
2854                 memset (info->name, 0, 64);
2855               info->size = ssize;
2856               info->max_decomp_size = max_decomp_size;
2857               info->encrypted = section_encrypted (dwg, type);
2858               info->compressed = 1 + section_compressed (dwg, type);
2859 #ifndef HAVE_COMPRESS_R2004_SECTION
2860               info->compressed = 1;
2861 #endif
2862               // pre-calc num_sections for both
2863               if ((unsigned)ssize <= max_decomp_size)
2864                 info->num_sections = 1;
2865               else
2866                 {
2867                   info->num_sections = (unsigned)ssize / max_decomp_size;
2868                   if ((unsigned)ssize % max_decomp_size)
2869                     info->num_sections++;
2870                 }
2871               info->sections
2872                   = calloc (info->num_sections, sizeof (Dwg_Section*));
2873               // enough sections?
2874               if (si + info->num_sections > dwg->header.num_sections)
2875                 {
2876                   Dwg_Section *oldsecs = dwg->header.section;
2877                   dwg->header.num_sections = si + info->num_sections;
2878                   dwg->header.section = realloc (dwg->header.section,
2879                                                  dwg->header.num_sections
2880                                                      * sizeof (Dwg_Section));
2881                   if (dwg->header.section != oldsecs)
2882                     // need to rebuild all info->sections
2883                     section_info_rebuild (dwg, type);
2884                 }
2885               {
2886                 int ssi = 0;
2887                 do
2888                   {
2889                     Dwg_Section *sec = &dwg->header.section[si];
2890                     total_size += ssize;
2891                     sec->number = si + 1; // index starting at 1
2892                     sec->size = MIN (max_decomp_size, (unsigned)ssize);
2893                     sec->decomp_data_size = sec->size;
2894                     sec->type = type;
2895                     sec->compression_type = info->compressed;
2896                     info->sections[ssi] = sec;
2897                     LOG_TRACE ("section[%d] %s[%d].sections[%d]: number=%d "
2898                                "size=%d\n", si,
2899                                dwg_section_name (dwg, type), info_id, ssi,
2900                                sec->number, (int)sec->size);
2901                     ssize -= max_decomp_size;
2902                     ssi++; // info->sections index
2903                     si++;  // section index
2904                   }
2905                 while (ssize > (int)max_decomp_size); // keep same type
2906               }
2907               info_id++;
2908             }
2909           else
2910             LOG_TRACE ("section_info %s is empty, skipped. size=0\n",
2911                        dwg_section_name (dwg, type));
2912         }
2913       dwg->r2004_header.numsections = si;
2914       // section_info [27] and section_map [28] as two last already added.
2915       if ((unsigned)si > dwg->header.num_sections) // needed?
2916         {
2917           Dwg_Section *oldsecs = dwg->header.section;
2918           dwg->header.num_sections = si;
2919           dwg->header.section = realloc (dwg->header.section, si * sizeof (Dwg_Section));
2920           if (dwg->header.section != oldsecs)
2921             section_info_rebuild (dwg, SECTION_SYSTEM_MAP);
2922         }
2923       dwg->r2004_header.section_info_id = dwg->r2004_header.numsections + 1; // a gap of 3
2924       dwg->r2004_header.section_map_id = dwg->r2004_header.numsections + 2;
2925       dwg->r2004_header.section_array_size = dwg->r2004_header.numsections + 2;
2926       dwg->r2004_header.last_section_id = dwg->r2004_header.section_map_id;
2927       dwg->header.section[si - 2].number = dwg->r2004_header.section_info_id;
2928       dwg->header.section[si - 1].number = dwg->r2004_header.section_map_id;
2929 
2930       LOG_TRACE ("\n=== Section Info %d in map order ===\n",
2931                  dwg->r2004_header.section_info_id);
2932       // write into sec_dat[type] first, then compress
2933       sec_id = SECTION_INFO;
2934       sec_dat[sec_id].size = sec_dat[sec_id].byte;
2935       bit_chain_alloc (&sec_dat[sec_id]);
2936       dat = &sec_dat[sec_id];
2937       bit_chain_set_version (dat, old_dat);
2938       bit_set_position (dat, 0); // so far we faked the content. now write it
2939 
2940       {
2941         Dwg_Section_InfoHdr *_obj = &dwg->header.section_infohdr;
2942         Dwg_Section *sec = &dwg->header.section[si - 2];
2943         Dwg_Section_Info *info = find_section_info_type (dwg, sec_id);
2944         // index starting at 1
2945         sec->number = dwg->r2004_header.section_info_id;
2946         sec->size = MIN (0x7400, sec->size);
2947         sec->decomp_data_size = sec->size;
2948         sec->type = type;
2949         if (info)
2950           {
2951             sec->compression_type = info->compressed;
2952             // very unlikely, more than 1 page
2953             info->sections[0] = sec;
2954           }
2955         if (_obj->compressed == 2 && sec->size <= MIN_COMPRESSED_SECTION)
2956           _obj->compressed = 1;
2957 #ifndef HAVE_COMPRESS_R2004_SECTION
2958         _obj->compressed = 1;
2959 #endif
2960         LOG_HANDLE ("InfoHdr @%lu.0\n", dat->byte);
2961         FIELD_RL (num_desc, 0);
2962         FIELD_RL (compressed, 0);
2963         FIELD_RL (max_size, 0);
2964         FIELD_RL (encrypted, 0);
2965         FIELD_RL (num_desc2, 0);
2966       }
2967       for (i = 0; i < ARRAY_SIZE (section_map_order); i++)
2968         {
2969           Dwg_Section_Info *_obj;
2970           type = section_map_order[i];
2971           _obj = find_section_info_type (dwg, type);
2972           if (_obj)
2973             {
2974               assert (type == _obj->fixedtype);
2975               LOG_TRACE ("\nSection_Info %s [%d]\n",
2976                          dwg_section_name (dwg, type), i);
2977               FIELD_RLLu (size, 0);
2978               FIELD_RL (num_sections, 0);
2979               FIELD_RL (max_decomp_size, 0);
2980               FIELD_RL (unknown, 0);
2981               FIELD_RL (compressed, 0);
2982               FIELD_RL (type, 0);
2983               FIELD_RL (encrypted, 0);
2984               bit_write_TF (dat, (unsigned char *)_obj->name, 64);
2985               LOG_TRACE ("name: %s\n", *_obj->name ? _obj->name : "");
2986             }
2987         }
2988 
2989       LOG_TRACE ("\n=== Section System Map %d in map order ===\n",
2990                  dwg->r2004_header.section_map_id);
2991       sec_id = type = SECTION_SYSTEM_MAP;
2992       {
2993         //Dwg_Section_InfoHdr *_obj = &dwg->header.section_infohdr;
2994         Dwg_Section *sec = &dwg->header.section[si - 1];
2995         Dwg_Section_Info *info = find_section_info_type (dwg, type);
2996         if (!info || !info->sections)
2997           {
2998             LOG_ERROR ("SECTION_SYSTEM_MAP not found");
2999             return DWG_ERR_SECTIONNOTFOUND;
3000           }
3001 
3002         sec_dat[sec_id].size = sec_dat[sec_id].byte;
3003         bit_chain_alloc (&sec_dat[sec_id]);
3004         str_dat = hdl_dat = dat = &sec_dat[sec_id];
3005         bit_chain_set_version (dat, old_dat);
3006         bit_set_position (dat, 0); // so far we faked the content. now write it
3007 
3008         // index starting at 1
3009         sec->number = dwg->r2004_header.section_map_id;
3010         sec->size = MIN (0x7400, sec->size);
3011         sec->decomp_data_size = sec->size;
3012         sec->type = type;
3013         sec->compression_type = info->compressed;
3014         // very unlikely, more than 1 page
3015         info->sections[0] = sec;
3016       }
3017 
3018       address = 0x100;
3019       for (i = 0; i < dwg->header.num_sections; i++)
3020         {
3021           Dwg_Section *_obj = &dwg->header.section[i];
3022 
3023           FIELD_RL (number, 0);
3024           FIELD_RL (size, 0);
3025           _obj->address = address;
3026           FIELD_RLL (address, 0);
3027           address += _obj->size;
3028           if (_obj->number < 0) // gap. unused. we deleted all gaps
3029             {
3030               FIELD_RL (parent, 0);
3031               FIELD_RL (left, 0);
3032               FIELD_RL (right, 0);
3033               FIELD_RL (x00, 0);
3034             }
3035         }
3036       dwg->r2004_header.decomp_data_size = dat->byte; // system_map_size
3037       LOG_TRACE ("-size: %lu\n", dat->byte);
3038 
3039       dat = old_dat;
3040 #ifndef NDEBUG
3041       if (dwg->header.version >= R_1_2)
3042         {
3043           if (dat->size < 4 || dat->chain[0] != 'A' || dat->chain[1] != 'C')
3044             {
3045               LOG_ERROR ("Encode overwrite pos 0");
3046               return DWG_ERR_INVALIDDWG;
3047             }
3048           assert (dat->chain[0] == 'A');
3049           assert (dat->chain[1] == 'C');
3050           assert (dat->byte <= 0x100);
3051         }
3052 #endif
3053 
3054       // now write all the sections in the stream order
3055       LOG_TRACE ("\n=== Write sections in stream order ===\n");
3056       size = total_size
3057              + (8 * ((dwg->r2004_header.numsections + 2) * 24)); // no gaps
3058       dat->byte = section_address;
3059       if (dat->byte + size >= dat->size)
3060         {
3061           dat->size = dat->byte + size;
3062           bit_chain_alloc (dat);
3063         }
3064       LOG_HANDLE ("@%lu.0\n", dat->byte);
3065       for (i = 0; i < ARRAY_SIZE (stream_order); i++)
3066         {
3067           Dwg_Section_Info *info;
3068           type = stream_order[i];
3069           info = find_section_info_type (dwg, type);
3070           if (info)
3071             {
3072               LOG_TRACE ("Write %s pages @%lu (%u/%lu)\n",
3073                          dwg_section_name (dwg, type), dat->byte,
3074                          info->num_sections, sec_dat[type].size);
3075               for (unsigned k = 0; k < info->num_sections; k++)
3076                 {
3077                   Dwg_Section *sec = info->sections[k];
3078                   if (!sec)
3079                     {
3080                       LOG_ERROR ("empty info->sections[%u]", k);
3081                       continue;
3082                     }
3083                   if (!sec_dat[type].chain)
3084                     {
3085                       LOG_ERROR ("empty %s.chain", dwg_section_name (dwg, type));
3086                       continue;
3087                     }
3088 #ifndef NDEBUG
3089                   if (info->fixedtype < SECTION_INFO)
3090                     assert (info->fixedtype == sec->type);
3091 #endif
3092                   if (info->fixedtype == SECTION_SUMMARYINFO)
3093                     dwg->header.summaryinfo_address = dat->byte;
3094                   else if (info->fixedtype == SECTION_PREVIEW)
3095                     dwg->header.thumbnail_address = dat->byte;
3096                   else if (info->fixedtype == SECTION_VBAPROJECT)
3097                     dwg->header.vbaproj_address = dat->byte;
3098                   else if (info->fixedtype == SECTION_SYSTEM_MAP)
3099                     {
3100                       dwg->r2004_header.section_map_address = dat->byte - 0x100;
3101                       dwg->r2004_header.last_section_address = dat->byte + sec->size - 0x100;
3102                       dwg->r2004_header.second_header_address = 0; // TODO
3103                     }
3104                   sec->address = dat->byte;
3105 
3106                   if (info->encrypted)
3107                     {
3108                       BITCODE_RC *decr = calloc (sec->size, 1);
3109                       LOG_HANDLE ("Encrypt %s (%u/%d)\n", info->name, k,
3110                                   sec->size);
3111                       decrypt_R2004_header (decr, sec_dat[type].chain,
3112                                             sec->size);
3113                       free (sec_dat[type].chain);
3114                       sec_dat[type].chain = decr;
3115                     }
3116                   assert (sec->size <= MIN_COMPRESSED_SECTION ? info->compressed == 1 : 1);
3117                   if (info->compressed == 2)
3118                     {
3119                       LOG_HANDLE ("Compress %s (%u/%d)\n", info->name, k,
3120                                   sec->size);
3121                       compress_R2004_section (dat, sec_dat[type].chain,
3122                                               sec->size, &sec->comp_data_size);
3123                       LOG_TRACE ("sec->comp_data_size: " FORMAT_RL "\n", sec->comp_data_size);
3124                     }
3125                   else
3126                     {
3127                       LOG_HANDLE ("Copy uncompressed %s (%u/%d)\n", info->name,
3128                                   k, sec->size);
3129                       copy_R2004_section (dat, sec_dat[type].chain, sec->size,
3130                                           &sec->comp_data_size);
3131                     }
3132                 }
3133               bit_chain_free (&sec_dat[type]);
3134             }
3135         }
3136     }
3137 
3138     {
3139       Dwg_R2004_Header *_obj = &dwg->r2004_header;
3140       Bit_Chain file_dat = { NULL, sizeof (Dwg_R2004_Header), 0UL, 0, 0, 0, 0, NULL };
3141       Bit_Chain *orig_dat = dat;
3142       /* "AcFssFcAJMB" encrypted: 6840F8F7922AB5EF18DD0BF1 */
3143       const unsigned char enc_file_ID_string[]
3144           = { '\x68', '\x40', '\xF8', '\xF7', '\x92', '\x2A',
3145               '\xB5', '\xEF', '\x18', '\xDD', '\x0B', '\xF1' };
3146       uint32_t checksum;
3147 
3148       file_dat.chain = calloc (1, sizeof (Dwg_R2004_Header));
3149       dat = &file_dat;
3150       LOG_TRACE ("\nSection R2004_Header @0x100\n");
3151 
3152       checksum = _obj->crc32;
3153       LOG_HANDLE ("old crc32: 0x%x\n", _obj->crc32);
3154       _obj->crc32 = 0;
3155       // recalc the CRC32, without the padding, but the crc32 as 0
3156       _obj->crc32
3157           = bit_calc_CRC32 (0, (unsigned char *)&dwg->r2004_header, 0x6c);
3158       LOG_HANDLE ("calc crc32: 0x%x\n", _obj->crc32);
3159 
3160       // clang-format off
3161       #include "r2004_file_header.spec"
3162       // clang-format on
3163 
3164       // go back and encrypt it
3165       dat = orig_dat;
3166       decrypt_R2004_header (&dat->chain[0x80], file_dat.chain,
3167                             sizeof (Dwg_R2004_Header));
3168       bit_chain_free (&file_dat);
3169       LOG_HANDLE ("encrypted R2004_Header:\n");
3170       LOG_TF (HANDLE, &dat->chain[0x80], (int)sizeof (Dwg_R2004_Header));
3171       if (memcmp (&dat->chain[0x80], enc_file_ID_string,
3172                   sizeof (enc_file_ID_string)))
3173         {
3174           LOG_ERROR ("r2004_file_header encryption error");
3175           return error | DWG_ERR_INVALIDDWG;
3176         }
3177     } // R2004_Header
3178   } // R_2004
3179 
3180   assert (!dat->bit);
3181   dat->size = dat->byte;
3182   LOG_INFO ("\nFinal DWG size: %u\n", (unsigned)dat->size);
3183 
3184   UNTIL (R_2000)
3185   {
3186     /* Patch section addresses
3187      */
3188     assert (section_address);
3189     dat->byte = section_address;
3190     dat->bit = 0;
3191     LOG_INFO ("\n=======> section addresses: %4u\n", (unsigned)dat->byte);
3192     for (j = 0; j < dwg->header.num_sections; j++)
3193       {
3194         LOG_TRACE ("section[%u].number: %4d [RC] %s\n", j,
3195                    (int)dwg->header.section[j].number,
3196                    j < 6 ? dwg_section_name (dwg, j) : "");
3197         LOG_TRACE ("section[%u].offset: %4u [RL]\n", j,
3198                    (unsigned)dwg->header.section[j].address);
3199         LOG_TRACE ("section[%u].size:   %4u [RL]\n", j,
3200                    (int)dwg->header.section[j].size);
3201         if ((unsigned long)dwg->header.section[j].address
3202                 + dwg->header.section[j].size
3203             > dat->size)
3204           {
3205             if (is_section_r13_critical (j))
3206               {
3207                 LOG_ERROR ("section[%u] %s address or size overflow", j,
3208                            j < 6 ? dwg_section_name (dwg, j) : "");
3209                 return DWG_ERR_INVALIDDWG;
3210               }
3211             else
3212               {
3213                 LOG_WARN ("section[%u] %s address or size overflow, skipped",
3214                           j, j < 6 ? dwg_section_name (dwg, j) : "");
3215                 dwg->header.section[j].address = 0;
3216                 dwg->header.section[j].size = 0;
3217               }
3218           }
3219         bit_write_RC (dat, dwg->header.section[j].number);
3220         bit_write_RL (dat, dwg->header.section[j].address);
3221         bit_write_RL (dat, dwg->header.section[j].size);
3222       }
3223 
3224     /* Write CRC's
3225      */
3226     bit_write_CRC (dat, 0, 0);
3227     dat->byte -= 2;
3228     ckr = bit_read_CRC (dat);
3229     dat->byte -= 2;
3230     // FIXME: r13-2000 only
3231     switch (dwg->header.num_sections)
3232       {
3233       case 3:
3234         ckr ^= 0xA598;
3235         break;
3236       case 4:
3237         ckr ^= 0x8101;
3238         break;
3239       case 5:
3240         ckr ^= 0x3CC4;
3241         break;
3242       case 6:
3243         ckr ^= 0x8461;
3244         break;
3245       default:
3246         break;
3247       }
3248     bit_write_RS (dat, ckr);
3249     LOG_TRACE ("crc: %04X (from 0)\n", ckr);
3250   }
3251 
3252   return 0;
3253   }
3254   AFL_GCC_POP
3255 
encode_preR13(Dwg_Data * restrict dwg,Bit_Chain * restrict dat)3256   static int encode_preR13 (Dwg_Data * restrict dwg, Bit_Chain * restrict dat)
3257   {
3258     return DWG_ERR_NOTYETSUPPORTED;
3259   }
3260 
3261 #include "dwg.spec"
3262 
3263 // expand aliases: name => CLASSES.dxfname
3264 static const char *
dxf_encode_alias(char * restrict name)3265 dxf_encode_alias (char *restrict name)
3266 {
3267   if (strEQc (name, "DICTIONARYWDFLT"))
3268     return "ACDBDICTIONARYWDFLT";
3269   else if (strEQc (name, "SECTIONVIEWSTYLE"))
3270     return "ACDBSECTIONVIEWSTYLE";
3271   else if (strEQc (name, "PLACEHOLDER"))
3272     return "ACDBPLACEHOLDER";
3273   else if (strEQc (name, "DETAILVIEWSTYLE"))
3274     return "ACDBDETAILVIEWSTYLE";
3275   else if (strEQc (name, "ASSOCPERSSUBENTMANAGER"))
3276     return "ACDBASSOCPERSSUBENTMANAGER";
3277   else if (strEQc (name, "EVALUATION_GRAPH"))
3278     return "ACAD_EVALUATION_GRAPH";
3279   else if (strEQc (name, "ASSOCACTION"))
3280     return "ACDBASSOCACTION";
3281   else if (strEQc (name, "ASSOCALIGNEDDIMACTIONBODY"))
3282     return "ACDBASSOCALIGNEDDIMACTIONBODY";
3283   else if (strEQc (name, "ASSOCOSNAPPOINTREFACTIONPARAM"))
3284     return "ACDBASSOCOSNAPPOINTREFACTIONPARAM";
3285   else if (strEQc (name, "ASSOCVERTEXACTIONPARAM"))
3286     return "ACDBASSOCVERTEXACTIONPARAM";
3287   else if (strEQc (name, "ASSOCGEOMDEPENDENCY"))
3288     return "ACDBASSOCGEOMDEPENDENCY";
3289   else if (strEQc (name, "ASSOCDEPENDENCY"))
3290     return "ACDBASSOCDEPENDENCY";
3291   else if (strEQc (name, "TABLE"))
3292     return "ACAD_TABLE";
3293   else
3294     return NULL;
3295 }
3296 
3297 Dwg_Class *
dwg_encode_get_class(Dwg_Data * dwg,Dwg_Object * obj)3298 dwg_encode_get_class (Dwg_Data *dwg, Dwg_Object *obj)
3299 {
3300   int i;
3301   Dwg_Class *klass = NULL;
3302   if (!dwg || !dwg->dwg_class)
3303     return NULL;
3304   // indxf has a different class order
3305   if (obj->dxfname) // search class by name, not offset
3306     {
3307       int invalid_klass = 0;
3308       for (i = 0; i < dwg->num_classes; i++)
3309         {
3310           klass = &dwg->dwg_class[i];
3311           if (!klass->dxfname)
3312             {
3313               invalid_klass++;
3314               continue;
3315             }
3316           if (strEQ (obj->dxfname, klass->dxfname))
3317             {
3318               obj->type = 500 + i;
3319               break;
3320             }
3321           else
3322             {
3323               // alias DICTIONARYWDFLT => ACDBDICTIONARYWDFLT
3324               const char *alias = dxf_encode_alias (obj->dxfname);
3325               if (alias && klass->dxfname && strEQ (alias, klass->dxfname))
3326                 {
3327                   // a static string, which cannot be free'd. important for
3328                   // indxf
3329                   if (dwg->opts & DWG_OPTS_IN)
3330                     obj->dxfname = strdup ((char *)alias);
3331                   else
3332                     obj->dxfname = (char *)alias;
3333                   obj->type = 500 + i;
3334                   break;
3335                 }
3336               klass = NULL; // inefficient
3337 
3338               if (invalid_klass > 2 && !(dwg->opts & DWG_OPTS_IN))
3339                 goto search_by_index;
3340             }
3341         }
3342     }
3343   else // search by index
3344     {
3345     search_by_index:
3346       i = obj->type - 500;
3347       if (i < 0 || i >= (int)dwg->num_classes)
3348         {
3349           LOG_WARN ("Invalid object type %d, only %u classes", obj->type,
3350                     dwg->num_classes);
3351           return NULL;
3352         }
3353 
3354       klass = &dwg->dwg_class[i];
3355       if (!klass->dxfname)
3356         return NULL;
3357       obj->dxfname = klass->dxfname;
3358     }
3359   return klass;
3360 }
3361 
3362 /** dwg_encode_variable_type
3363  * Encode object by class name, not type. if type > 500.
3364  * Returns 0 on success, else some Dwg_Error.
3365  */
3366 static int
dwg_encode_variable_type(Dwg_Data * restrict dwg,Bit_Chain * restrict dat,Dwg_Object * restrict obj)3367 dwg_encode_variable_type (Dwg_Data *restrict dwg, Bit_Chain *restrict dat,
3368                           Dwg_Object *restrict obj)
3369 {
3370   //int error = 0;
3371   int is_entity;
3372   Dwg_Class *klass = dwg_encode_get_class (dwg, obj);
3373 
3374   if (!klass)
3375     return DWG_ERR_INVALIDTYPE;
3376   is_entity = dwg_class_is_entity (klass);
3377   // check if it really was an entity
3378   if ((is_entity && obj->supertype == DWG_SUPERTYPE_OBJECT)
3379       || (!is_entity && obj->supertype == DWG_SUPERTYPE_ENTITY))
3380     {
3381       if (is_dwg_object (obj->name))
3382         {
3383           if (is_entity)
3384             {
3385               LOG_INFO ("Fixup Class %s item_class_id to %s for %s\n",
3386                         klass->dxfname, "OBJECT", obj->name);
3387               klass->item_class_id = 0x1f2;
3388               if (!klass->dxfname || strNE (klass->dxfname, obj->dxfname))
3389                 {
3390                   free (klass->dxfname);
3391                   klass->dxfname = strdup (obj->dxfname);
3392                 }
3393               is_entity = 0;
3394             }
3395           else
3396             {
3397               LOG_INFO ("Fixup %s.supertype to %s\n", obj->name, "OBJECT");
3398               obj->supertype = DWG_SUPERTYPE_OBJECT;
3399             }
3400         }
3401       else if (is_dwg_entity (obj->name))
3402         {
3403           if (!is_entity)
3404             {
3405               LOG_INFO ("Fixup Class %s item_class_id to %s for %s\n",
3406                         klass->dxfname, "ENTITY", obj->name);
3407               klass->item_class_id = 0x1f3;
3408               if (!klass->dxfname || strNE (klass->dxfname, obj->dxfname))
3409                 {
3410                   free (klass->dxfname);
3411                   klass->dxfname = strdup (obj->dxfname);
3412                 }
3413               is_entity = 1;
3414             }
3415           else
3416             {
3417               LOG_INFO ("Fixup %s.supertype to %s", obj->name, "ENTITY");
3418               obj->supertype = DWG_SUPERTYPE_ENTITY;
3419             }
3420         }
3421       else
3422         {
3423           LOG_ERROR ("Illegal Class %s is_%s item_class_id for %s",
3424                      klass->dxfname, is_entity ? "entity" : "object",
3425                      obj->name);
3426           return DWG_ERR_INVALIDTYPE;
3427         }
3428     }
3429 
3430   if (dwg->opts & DWG_OPTS_IN) // DXF or JSON import
3431     {
3432       unsigned long pos = bit_position (dat);
3433 
3434       /* Should not be triggered. Only when undef ENCODE_UNKNOWN_AS_DUMMY */
3435       if (is_type_unstable (obj->fixedtype) &&
3436           (obj->fixedtype == DWG_TYPE_WIPEOUT ||
3437            obj->fixedtype == DWG_TYPE_TABLEGEOMETRY))
3438         {
3439           LOG_WARN ("Skip broken %s", obj->name); // acad crashes still
3440           obj->type = is_entity ? DWG_TYPE_UNKNOWN_ENT : DWG_TYPE_PLACEHOLDER;
3441           klass->dxfname = strdup (is_entity ? "UNKNOWN_ENT" : "UNKNOWN_OBJ");
3442         }
3443       dat->byte = obj->address;
3444       dat->bit = 0;
3445       LOG_TRACE ("fixup Type: %d [BS] @%lu\n", obj->type, obj->address);
3446       bit_write_BS (dat, obj->type); // fixup wrong type
3447       bit_set_position (dat, pos);
3448     }
3449 
3450   // clang-format off
3451   #include "classes.inc"
3452   // clang-format on
3453 
3454   LOG_WARN ("Unknown Class %s %d %s (0x%x%s)", is_entity ? "entity" : "object",
3455             klass->number, klass->dxfname, klass->proxyflag,
3456             klass->is_zombie ? "is_zombie" : "")
3457 
3458 #undef WARN_UNHANDLED_CLASS
3459 #undef WARN_UNSTABLE_CLASS
3460 
3461   return DWG_ERR_UNHANDLEDCLASS;
3462 }
3463 
3464 int
dwg_encode_add_object(Dwg_Object * restrict obj,Bit_Chain * restrict dat,unsigned long address)3465 dwg_encode_add_object (Dwg_Object *restrict obj, Bit_Chain *restrict dat,
3466                        unsigned long address)
3467 {
3468   int error = 0;
3469   //unsigned long oldpos;
3470   unsigned long end_address = address + obj->size;
3471   Dwg_Data *dwg = obj->parent;
3472 
3473   //oldpos = bit_position (dat);
3474   PRE (R_2004)
3475     {
3476       if (!address)
3477         return DWG_ERR_INVALIDDWG;
3478       assert (address);
3479     }
3480   dat->byte = address;
3481   dat->bit = 0;
3482 
3483   LOG_INFO ("Object number: %lu", (unsigned long)obj->index);
3484   if (obj->size > 0x100000)
3485     {
3486       LOG_ERROR ("Object size %u overflow", obj->size);
3487       return DWG_ERR_VALUEOUTOFBOUNDS;
3488     }
3489   while (dat->byte + obj->size >= dat->size)
3490     bit_chain_alloc (dat);
3491 
3492   // First write an aproximate size here.
3493   // Then calculate size from the fields. Either <0x7fff or more.
3494   // Patch it afterwards and check old<>new size if enough space allocated.
3495   bit_write_MS (dat, obj->size);
3496   obj->address = dat->byte;
3497   PRE (R_2010)
3498   {
3499     bit_write_BS (dat, obj->type);
3500     LOG_INFO (", Size: %d [MS], Type: %d [BS], Address: %lu\n", obj->size, obj->type, obj->address)
3501   }
3502   LATER_VERSIONS
3503   {
3504     if (!obj->handlestream_size && obj->bitsize)
3505       obj->handlestream_size = obj->size * 8 - obj->bitsize;
3506     bit_write_UMC (dat, obj->handlestream_size);
3507     obj->address = dat->byte;
3508     bit_write_BOT (dat, obj->type);
3509     LOG_INFO (", Size: %d [MS], Hdlsize: %lu [UMC], Type: %d [BOT], Address: %lu\n",
3510               obj->size, (unsigned long)obj->handlestream_size, obj->type, obj->address)
3511   }
3512 
3513   /* Write the specific type to dat */
3514   switch (obj->type)
3515     {
3516     case DWG_TYPE_TEXT:
3517       error = dwg_encode_TEXT (dat, obj);
3518       break;
3519     case DWG_TYPE_ATTRIB:
3520       error = dwg_encode_ATTRIB (dat, obj);
3521       break;
3522     case DWG_TYPE_ATTDEF:
3523       error = dwg_encode_ATTDEF (dat, obj);
3524       break;
3525     case DWG_TYPE_BLOCK:
3526       error = dwg_encode_BLOCK (dat, obj);
3527       break;
3528     case DWG_TYPE_ENDBLK:
3529       error = dwg_encode_ENDBLK (dat, obj);
3530       break;
3531     case DWG_TYPE_SEQEND:
3532       error = dwg_encode_SEQEND (dat, obj);
3533       break;
3534     case DWG_TYPE_INSERT:
3535       error = dwg_encode_INSERT (dat, obj);
3536       break;
3537     case DWG_TYPE_MINSERT:
3538       error = dwg_encode_MINSERT (dat, obj);
3539       break;
3540     case DWG_TYPE_VERTEX_2D:
3541       error = dwg_encode_VERTEX_2D (dat, obj);
3542       break;
3543     case DWG_TYPE_VERTEX_3D:
3544       error = dwg_encode_VERTEX_3D (dat, obj);
3545       break;
3546     case DWG_TYPE_VERTEX_MESH:
3547       error = dwg_encode_VERTEX_MESH (dat, obj);
3548       break;
3549     case DWG_TYPE_VERTEX_PFACE:
3550       error = dwg_encode_VERTEX_PFACE (dat, obj);
3551       break;
3552     case DWG_TYPE_VERTEX_PFACE_FACE:
3553       error = dwg_encode_VERTEX_PFACE_FACE (dat, obj);
3554       break;
3555     case DWG_TYPE_POLYLINE_2D:
3556       error = dwg_encode_POLYLINE_2D (dat, obj);
3557       break;
3558     case DWG_TYPE_POLYLINE_3D:
3559       error = dwg_encode_POLYLINE_3D (dat, obj);
3560       break;
3561     case DWG_TYPE_ARC:
3562       error = dwg_encode_ARC (dat, obj);
3563       break;
3564     case DWG_TYPE_CIRCLE:
3565       error = dwg_encode_CIRCLE (dat, obj);
3566       break;
3567     case DWG_TYPE_LINE:
3568       error = dwg_encode_LINE (dat, obj);
3569       break;
3570     case DWG_TYPE_DIMENSION_ORDINATE:
3571       error = dwg_encode_DIMENSION_ORDINATE (dat, obj);
3572       break;
3573     case DWG_TYPE_DIMENSION_LINEAR:
3574       error = dwg_encode_DIMENSION_LINEAR (dat, obj);
3575       break;
3576     case DWG_TYPE_DIMENSION_ALIGNED:
3577       error = dwg_encode_DIMENSION_ALIGNED (dat, obj);
3578       break;
3579     case DWG_TYPE_DIMENSION_ANG3PT:
3580       error = dwg_encode_DIMENSION_ANG3PT (dat, obj);
3581       break;
3582     case DWG_TYPE_DIMENSION_ANG2LN:
3583       error = dwg_encode_DIMENSION_ANG2LN (dat, obj);
3584       break;
3585     case DWG_TYPE_DIMENSION_RADIUS:
3586       error = dwg_encode_DIMENSION_RADIUS (dat, obj);
3587       break;
3588     case DWG_TYPE_DIMENSION_DIAMETER:
3589       error = dwg_encode_DIMENSION_DIAMETER (dat, obj);
3590       break;
3591     case DWG_TYPE_POINT:
3592       error = dwg_encode_POINT (dat, obj);
3593       break;
3594     case DWG_TYPE__3DFACE:
3595       error = dwg_encode__3DFACE (dat, obj);
3596       break;
3597     case DWG_TYPE_POLYLINE_PFACE:
3598       error = dwg_encode_POLYLINE_PFACE (dat, obj);
3599       break;
3600     case DWG_TYPE_POLYLINE_MESH:
3601       error = dwg_encode_POLYLINE_MESH (dat, obj);
3602       break;
3603     case DWG_TYPE_SOLID:
3604       error = dwg_encode_SOLID (dat, obj);
3605       break;
3606     case DWG_TYPE_TRACE:
3607       error = dwg_encode_TRACE (dat, obj);
3608       break;
3609     case DWG_TYPE_SHAPE:
3610       error = dwg_encode_SHAPE (dat, obj);
3611       break;
3612     case DWG_TYPE_VIEWPORT:
3613       error = dwg_encode_VIEWPORT (dat, obj);
3614       break;
3615     case DWG_TYPE_ELLIPSE:
3616       error = dwg_encode_ELLIPSE (dat, obj);
3617       break;
3618     case DWG_TYPE_SPLINE:
3619       error = dwg_encode_SPLINE (dat, obj);
3620       break;
3621     case DWG_TYPE_REGION:
3622       error = dwg_encode_REGION (dat, obj);
3623       break;
3624     case DWG_TYPE__3DSOLID:
3625       error = dwg_encode__3DSOLID (dat, obj);
3626       break;
3627     case DWG_TYPE_BODY:
3628       error = dwg_encode_BODY (dat, obj);
3629       break;
3630     case DWG_TYPE_RAY:
3631       error = dwg_encode_RAY (dat, obj);
3632       break;
3633     case DWG_TYPE_XLINE:
3634       error = dwg_encode_XLINE (dat, obj);
3635       break;
3636     case DWG_TYPE_DICTIONARY:
3637       error = dwg_encode_DICTIONARY (dat, obj);
3638       break;
3639     case DWG_TYPE_MTEXT:
3640       error = dwg_encode_MTEXT (dat, obj);
3641       break;
3642     case DWG_TYPE_LEADER:
3643       error = dwg_encode_LEADER (dat, obj);
3644       break;
3645     case DWG_TYPE_TOLERANCE:
3646       error = dwg_encode_TOLERANCE (dat, obj);
3647       break;
3648     case DWG_TYPE_MLINE:
3649       error = dwg_encode_MLINE (dat, obj);
3650       break;
3651     case DWG_TYPE_BLOCK_CONTROL:
3652       error = dwg_encode_BLOCK_CONTROL (dat, obj);
3653       break;
3654     case DWG_TYPE_BLOCK_HEADER:
3655       error = dwg_encode_BLOCK_HEADER (dat, obj);
3656       break;
3657     case DWG_TYPE_LAYER_CONTROL:
3658       error = dwg_encode_LAYER_CONTROL (dat, obj);
3659       break;
3660     case DWG_TYPE_LAYER:
3661       error = dwg_encode_LAYER (dat, obj);
3662       break;
3663     case DWG_TYPE_STYLE_CONTROL:
3664       error = dwg_encode_STYLE_CONTROL (dat, obj);
3665       break;
3666     case DWG_TYPE_STYLE:
3667       error = dwg_encode_STYLE (dat, obj);
3668       break;
3669     case DWG_TYPE_LTYPE_CONTROL:
3670       error = dwg_encode_LTYPE_CONTROL (dat, obj);
3671       break;
3672     case DWG_TYPE_LTYPE:
3673       error = dwg_encode_LTYPE (dat, obj);
3674       break;
3675     case DWG_TYPE_VIEW_CONTROL:
3676       error = dwg_encode_VIEW_CONTROL (dat, obj);
3677       break;
3678     case DWG_TYPE_VIEW:
3679       error = dwg_encode_VIEW (dat, obj);
3680       break;
3681     case DWG_TYPE_UCS_CONTROL:
3682       error = dwg_encode_UCS_CONTROL (dat, obj);
3683       break;
3684     case DWG_TYPE_UCS:
3685       error = dwg_encode_UCS (dat, obj);
3686       break;
3687     case DWG_TYPE_VPORT_CONTROL:
3688       error = dwg_encode_VPORT_CONTROL (dat, obj);
3689       break;
3690     case DWG_TYPE_VPORT:
3691       error = dwg_encode_VPORT (dat, obj);
3692       break;
3693     case DWG_TYPE_APPID_CONTROL:
3694       error = dwg_encode_APPID_CONTROL (dat, obj);
3695       break;
3696     case DWG_TYPE_APPID:
3697       error = dwg_encode_APPID (dat, obj);
3698       break;
3699     case DWG_TYPE_DIMSTYLE_CONTROL:
3700       error = dwg_encode_DIMSTYLE_CONTROL (dat, obj);
3701       break;
3702     case DWG_TYPE_DIMSTYLE:
3703       error = dwg_encode_DIMSTYLE (dat, obj);
3704       break;
3705     case DWG_TYPE_VX_CONTROL:
3706       error = dwg_encode_VX_CONTROL (dat, obj);
3707       break;
3708     case DWG_TYPE_VX_TABLE_RECORD:
3709       error = dwg_encode_VX_TABLE_RECORD (dat, obj);
3710       break;
3711     case DWG_TYPE_GROUP:
3712       error = dwg_encode_GROUP (dat, obj);
3713       break;
3714     case DWG_TYPE_MLINESTYLE:
3715       error = dwg_encode_MLINESTYLE (dat, obj);
3716       (void)dwg_encode_get_class (dwg, obj);
3717       break;
3718     case DWG_TYPE_OLE2FRAME:
3719       error = dwg_encode_OLE2FRAME (dat, obj);
3720       (void)dwg_encode_get_class (dwg, obj);
3721       break;
3722     case DWG_TYPE_DUMMY:
3723       error = dwg_encode_DUMMY (dat, obj);
3724       break;
3725     case DWG_TYPE_LONG_TRANSACTION:
3726       error = dwg_encode_LONG_TRANSACTION (dat, obj);
3727       break;
3728     case DWG_TYPE_LWPOLYLINE:
3729       error = dwg_encode_LWPOLYLINE (dat, obj);
3730       (void)dwg_encode_get_class (dwg, obj);
3731       break;
3732     case DWG_TYPE_HATCH:
3733       error = dwg_encode_HATCH (dat, obj);
3734       (void)dwg_encode_get_class (dwg, obj);
3735       break;
3736     case DWG_TYPE_XRECORD:
3737       error = dwg_encode_XRECORD (dat, obj);
3738       (void)dwg_encode_get_class (dwg, obj);
3739       break;
3740     case DWG_TYPE_PLACEHOLDER:
3741       error = dwg_encode_PLACEHOLDER (dat, obj);
3742       (void)dwg_encode_get_class (dwg, obj);
3743       break;
3744     case DWG_TYPE_OLEFRAME:
3745       error = dwg_encode_OLEFRAME (dat, obj);
3746       (void)dwg_encode_get_class (dwg, obj);
3747       break;
3748     case DWG_TYPE_VBA_PROJECT:
3749       //LOG_ERROR ("Unhandled Object VBA_PROJECT. Has its own AcDb::VBAProject section");
3750       error = dwg_encode_VBA_PROJECT (dat, obj);
3751       (void)dwg_encode_get_class (dwg, obj);
3752       break;
3753     case DWG_TYPE_LAYOUT:
3754       error |= dwg_encode_LAYOUT (dat, obj);
3755       (void)dwg_encode_get_class (dwg, obj);
3756       break;
3757     case DWG_TYPE_PROXY_ENTITY:
3758       error = dwg_encode_PROXY_ENTITY (dat, obj);
3759       break;
3760     case DWG_TYPE_PROXY_OBJECT:
3761       error = dwg_encode_PROXY_OBJECT (dat, obj);
3762       break;
3763     default:
3764       if (dwg && obj->type == dwg->layout_type
3765           && obj->fixedtype == DWG_TYPE_LAYOUT)
3766         {
3767           error = dwg_encode_LAYOUT (dat, obj);
3768           (void)dwg_encode_get_class (dwg, obj);
3769         }
3770       else if (dwg != NULL
3771                && (error = dwg_encode_variable_type (dwg, dat, obj))
3772                       & DWG_ERR_UNHANDLEDCLASS)
3773         {
3774           int is_entity;
3775           Dwg_Class *klass = dwg_encode_get_class (dwg, obj);
3776           if (klass)
3777             is_entity = klass->item_class_id == 0x1f2
3778                         && obj->supertype == DWG_SUPERTYPE_ENTITY;
3779           else
3780             is_entity = obj->supertype == DWG_SUPERTYPE_ENTITY;
3781 
3782           assert (address);
3783           dat->byte = address; // restart and write into the UNKNOWN_OBJ object
3784           dat->bit = 0;
3785 
3786           bit_write_MS (dat, obj->size); // unknown blobs have a known size
3787           if (dat->version >= R_2010)
3788             {
3789               bit_write_UMC (dat, obj->handlestream_size);
3790               bit_write_BOT (dat, obj->type);
3791             }
3792           else
3793             bit_write_BS (dat, obj->type);
3794 
3795           // from json and dwg can write to these. from dxf not.
3796           if (is_entity)
3797             {
3798               if (obj->bitsize && dwg->header.version == dwg->header.from_version)
3799                 obj->was_bitsize_set = 1;
3800               error = dwg_encode_UNKNOWN_ENT (dat, obj);
3801             }
3802           else
3803             {
3804               // skip START_OBJECT_HANDLE_STREAM (see DWG_OBJECT_END)
3805               // unknown_bits already includes that.
3806               if (!obj->hdlpos)
3807                 {
3808                   if (obj->bitsize)
3809                     {
3810                       obj->hdlpos = (obj->address * 8) + obj->bitsize;
3811                       if (dwg->header.version == dwg->header.from_version)
3812                         obj->was_bitsize_set = 1;
3813                     }
3814                   else
3815                     obj->hdlpos = (obj->address * 8) + obj->num_unknown_bits;
3816                 }
3817               error = dwg_encode_UNKNOWN_OBJ (dat, obj);
3818             }
3819 
3820           if (dwg->header.version == dwg->header.from_version
3821               && obj->unknown_bits && obj->num_unknown_bits) // cannot calculate
3822             {
3823               int len = obj->num_unknown_bits / 8;
3824               const int mod = obj->num_unknown_bits % 8;
3825               if (mod)
3826                 len++;
3827               bit_write_TF (dat, obj->unknown_bits, len);
3828               LOG_TRACE ("unknown_bits: %d/%u [TF]\n", len, (unsigned)obj->num_unknown_bits);
3829               LOG_TRACE_TF (obj->unknown_bits, len);
3830               if (mod)
3831                 bit_advance_position (dat, mod - 8);
3832               obj->was_bitsize_set = 1;
3833             }
3834         }
3835     }
3836 
3837   /* DXF/JSON/RW across versions: patchup size and bitsize */
3838   /* Across versions size+bitsize must be recalculated.
3839      Sizes are unreliable when changing versions. */
3840   if (!obj->size || dwg->header.from_version != dwg->header.version
3841       || obj->was_bitsize_set)
3842     {
3843       BITCODE_BL pos = bit_position (dat);
3844       BITCODE_RL old_size = obj->size;
3845       if (dwg->header.version < R_2004 || obj->index)
3846         {
3847           if (!address)
3848             return DWG_ERR_INVALIDDWG;
3849           assert (address);
3850         }
3851       if (dat->byte > obj->address)
3852         {
3853           // The size and CRC fields are not included in the obj->size
3854           obj->size = dat->byte - obj->address;
3855           if (dat->bit)
3856             obj->size++;
3857         }
3858       if (dat->byte >= dat->size)
3859         bit_chain_alloc (dat);
3860       // assert (obj->bitsize); // on errors
3861       if (!obj->bitsize ||
3862           (dwg->header.from_version != dwg->header.version
3863            // and not calculated from HANDLE_STREAM or via unknown_bits already
3864            && !obj->was_bitsize_set))
3865         {
3866           LOG_TRACE ("-bitsize calc from address (no handle) @%lu.%u\n",
3867                      dat->byte - obj->address, dat->bit);
3868           obj->bitsize = pos - (obj->address * 8);
3869         }
3870       bit_set_position (dat, address * 8);
3871       if (obj->size > 0x7fff && old_size <= 0x7fff)
3872         {
3873           // with overlarge sizes >0x7fff memmove dat right by 2, one more RS added.
3874           LOG_INFO ("overlarge size %u > 0x7fff @%lu\n", (unsigned)obj->size, dat->byte);
3875           if (dat->byte + obj->size + 2 >= dat->size)
3876             bit_chain_alloc (dat);
3877           memmove (&dat->chain[dat->byte + 2], &dat->chain[dat->byte], obj->size);
3878           obj->size += 2;
3879           obj->bitsize += 16;
3880           obj->bitsize_pos += 16;
3881           pos += 16;
3882         }
3883       if (obj->size <= 0x7fff && old_size > 0x7fff)
3884         {
3885           // with old overlarge sizes >0x7fff memmove dat left by 2, one RS removed.
3886           LOG_INFO ("was overlarge size %u < 0x7fff @%lu\n", (unsigned)old_size, dat->byte);
3887           memmove (&dat->chain[dat->byte], &dat->chain[dat->byte + 2], obj->size);
3888           obj->size -= 2;
3889           obj->bitsize -= 16;
3890           obj->bitsize_pos -= 16;
3891           pos -= 16;
3892         }
3893       bit_write_MS (dat, obj->size);
3894       LOG_TRACE ("-size: %u [MS] @%lu\n", obj->size, address);
3895       SINCE (R_2013)
3896       {
3897         if (!obj->handlestream_size && obj->bitsize)
3898           obj->handlestream_size = (obj->size * 8) - obj->bitsize;
3899         bit_write_UMC (dat, obj->handlestream_size);
3900         LOG_TRACE ("-handlestream_size: %lu [UMC]\n", obj->handlestream_size);
3901       }
3902       SINCE (R_2000)
3903       {
3904         if (obj->bitsize_pos && obj->bitsize)
3905           {
3906             bit_set_position (dat, obj->bitsize_pos);
3907             bit_write_RL (dat, obj->bitsize);
3908             LOG_TRACE ("-bitsize: %u [RL] @%lu.%lu\n", obj->bitsize,
3909                        obj->bitsize_pos / 8, obj->bitsize_pos % 8);
3910           }
3911       }
3912       bit_set_position (dat, pos);
3913     }
3914 
3915   /* Now 1 padding bits until next byte, and then a RS CRC */
3916   if (dat->bit)
3917     LOG_TRACE ("padding: +%d [*B]\n", 8 - dat->bit)
3918   while (dat->bit)
3919     bit_write_B (dat, 1);
3920   end_address = obj->address + obj->size;
3921   if (end_address != dat->byte)
3922     {
3923       if (obj->size)
3924         LOG_WARN ("Wrong object size: %lu + %u = %lu != %lu: %ld off",
3925                   address, obj->size, end_address, dat->byte,
3926                   (long)(end_address - dat->byte));
3927       //dat->byte = end_address;
3928     }
3929   assert (!dat->bit);
3930   bit_write_CRC (dat, address, 0xC0C1);
3931   return error;
3932 }
3933 
3934 /** writes the data part, if there's no raw.
3935  */
3936 static int
dwg_encode_eed_data(Bit_Chain * restrict dat,Dwg_Eed_Data * restrict data,const int i)3937 dwg_encode_eed_data (Bit_Chain *restrict dat, Dwg_Eed_Data *restrict data, const int i)
3938 {
3939   unsigned long pos = bit_position (dat);
3940   unsigned long size;
3941   bit_write_RC (dat, data->code);
3942   LOG_TRACE ("EED[%d] code: %d [RC] ", i, data->code);
3943   switch (data->code)
3944     {
3945     case 0:
3946       {
3947         PRE (R_2007)
3948         {
3949           // only if from r2007+ DWG, not JSON, DXF
3950           if (data->u.eed_0.is_tu)
3951             {
3952               BITCODE_RS length = data->u.eed_0_r2007.length;
3953               BITCODE_RS *s = (BITCODE_RS *)&data->u.eed_0_r2007.string;
3954               BITCODE_RS codepage = 30; //FIXME
3955               char *dest;
3956               if (length + 5 + dat->byte >= dat->size)
3957                 bit_chain_alloc (dat);
3958               if (length > 255)
3959                 {
3960                   LOG_ERROR ("eed: overlong string %d stripped", (int)length);
3961                   length = 255;
3962                 }
3963               dest = bit_embed_TU_size (s, length);
3964               bit_write_RC (dat, length);
3965               bit_write_RS_LE (dat, codepage);
3966               bit_write_TF (dat, (unsigned char *)dest, length);
3967               LOG_TRACE ("string: len=%d [RC] cp=%d [RS_LE] \"%s\" [TF]",
3968                          length, codepage, dest);
3969               free (dest);
3970             }
3971           else
3972             {
3973               if (!*data->u.eed_0.string)
3974                 data->u.eed_0.length = 0;
3975               if (data->u.eed_0.length + 5 + dat->byte >= dat->size)
3976                 bit_chain_alloc (dat);
3977               bit_write_RC (dat, data->u.eed_0.length);
3978               bit_write_RS_LE (dat, data->u.eed_0.codepage);
3979               bit_write_TF (dat, (BITCODE_TF)data->u.eed_0.string, data->u.eed_0.length);
3980               LOG_TRACE ("string: len=%d [RC] cp=%d [RS_LE] \"%s\" [TF]",
3981                          data->u.eed_0.length, data->u.eed_0.codepage,
3982                          data->u.eed_0.string);
3983             }
3984         }
3985         LATER_VERSIONS
3986         {
3987           // from ASCII DWG or JSON, DXF
3988           if (!data->u.eed_0.is_tu)
3989             {
3990               BITCODE_RS length = data->u.eed_0.length;
3991               BITCODE_TU dest = bit_utf8_to_TU (data->u.eed_0.string, 0);
3992               if ((length * 2) + 5 + dat->byte >= dat->size)
3993                 bit_chain_alloc (dat);
3994               bit_write_RS (dat, length);
3995               for (int j = 0; j < length; j++)
3996                 bit_write_RS (dat, *dest++);
3997               data->u.eed_0_r2007.length = length;
3998               LOG_TRACE ("wstring: len=%d [RS] \"%s\" [TU]",
3999                          (int)length, data->u.eed_0.string);
4000             }
4001           else
4002             {
4003               BITCODE_RS length = data->u.eed_0_r2007.length;
4004               BITCODE_RS *s = (BITCODE_RS *)&data->u.eed_0_r2007.string;
4005               if ((length * 2) + 5 + dat->byte >= dat->size)
4006                 bit_chain_alloc (dat);
4007               bit_write_RS (dat, length);
4008               for (int j = 0; j < length; j++)
4009                 bit_write_RS (dat, *s++);
4010 #ifdef _WIN32
4011               LOG_TRACE ("wstring: len=%d [RS] \"" FORMAT_TU "\" [TU]",
4012                          (int)data->u.eed_0_r2007.length,
4013                          data->u.eed_0_r2007.string);
4014 #else
4015               if (DWG_LOGLEVEL >= DWG_LOGLEVEL_TRACE)
4016                 {
4017                   char *u8 = bit_TU_to_utf8_len (data->u.eed_0_r2007.string,
4018                                                  data->u.eed_0_r2007.length);
4019                   LOG_TRACE ("wstring: len=%d [RS] \"%s\" [TU]",
4020                              (int)data->u.eed_0_r2007.length, u8);
4021                   free (u8);
4022                 }
4023 #endif
4024             }
4025         }
4026       }
4027       break;
4028     case 2:
4029       bit_write_RC (dat, data->u.eed_2.close);
4030       LOG_TRACE ("close: %d [RC]", (int)data->u.eed_2.close);
4031       break;
4032     case 3:
4033       bit_write_RLL (dat, data->u.eed_3.layer);
4034       LOG_TRACE ("layer: 0x%lX [RLL]", (unsigned long)data->u.eed_3.layer);
4035       break;
4036     case 4:
4037       bit_write_RC (dat, data->u.eed_4.length);
4038       bit_write_TF (dat, (BITCODE_TF)data->u.eed_4.data,
4039                     data->u.eed_4.length);
4040       LOG_TRACE ("binary: ");
4041       LOG_TRACE_TF (data->u.eed_4.data, data->u.eed_4.length);
4042       break;
4043     case 5:
4044       bit_write_RLL (dat, (BITCODE_RLL)data->u.eed_5.entity);
4045       LOG_TRACE ("entity: 0x%lX [ulong]", data->u.eed_5.entity);
4046       break;
4047     case 10:
4048     case 11:
4049     case 12:
4050     case 13:
4051     case 14:
4052     case 15:
4053       bit_write_RD (dat, data->u.eed_10.point.x);
4054       bit_write_RD (dat, data->u.eed_10.point.y);
4055       bit_write_RD (dat, data->u.eed_10.point.z);
4056       LOG_TRACE ("3dpoint: (%f, %f, %f) [3RD]", data->u.eed_10.point.x,
4057                  data->u.eed_10.point.y, data->u.eed_10.point.z);
4058       break;
4059     case 40:
4060     case 41:
4061     case 42:
4062       bit_write_RD (dat, data->u.eed_40.real);
4063       LOG_TRACE ("real: %f [RD]", data->u.eed_40.real);
4064       break;
4065     case 70:
4066       bit_write_RS (dat, data->u.eed_70.rs);
4067       LOG_TRACE ("short: " FORMAT_RS " [RS]", data->u.eed_70.rs);
4068       break;
4069     case 71:
4070       bit_write_RL (dat, data->u.eed_71.rl);
4071       LOG_TRACE ("long: " FORMAT_RL " [RL]", data->u.eed_71.rl);
4072       break;
4073     default:
4074       dat->byte--;
4075       LOG_ERROR ("unknown EED code %d", data->code);
4076     }
4077   size = bit_position (dat) - pos;
4078   return (size % 8) ? (int)(size / 8) + 1 : (int)(size / 8);
4079 }
4080 
4081 #define dat_flush(orig, dat) bit_copy_chain (orig, dat)
4082 
4083 /** Either writes the raw part.
4084     Only members with size have raw and a handle.
4085     Otherwise (indxf) defer to dwg_encode_eed_data.
4086     On does_cross_unicode_datversion skip raw, and recalc the sizes.
4087  */
4088 static int
dwg_encode_eed(Bit_Chain * restrict dat,Dwg_Object * restrict obj)4089 dwg_encode_eed (Bit_Chain *restrict dat, Dwg_Object *restrict obj)
4090 {
4091   //unsigned long off = obj->address;
4092   //unsigned dat_size = 0;
4093   Dwg_Handle *last_handle = NULL;
4094   Bit_Chain dat1 = { 0 };
4095   int i, num_eed = obj->tio.object->num_eed;
4096   BITCODE_BS size = 0;
4097   int last_size = 0;
4098   int new_size = 0;
4099   int did_raw = 0;
4100   int need_recalc = does_cross_unicode_datversion (dat);
4101 
4102   bit_chain_init (&dat1, 1024);
4103   dat1.from_version = dat->from_version;
4104   dat1.version = dat->version;
4105   dat1.opts = dat->opts;
4106 
4107   // Skip DICTIONARY AE3 AcDsRecords/AcDsSchemas 1070 . 2, wrong ACIS version
4108   if (dat->opts & DWG_OPTS_INDXF &&
4109       dat->version < R_2007 &&
4110       obj->fixedtype == DWG_TYPE_DICTIONARY &&
4111       num_eed == 1)
4112     {
4113       Dwg_Eed *eed = &obj->tio.object->eed[0];
4114       if (eed->handle.value == 0x12 &&
4115           eed->data->code == 70 &&
4116           eed->data->u.eed_70.rs > 1)
4117         {
4118           LOG_TRACE ("skip AcDs DICTIONARY EED to use ACIS ver 2\n");
4119           num_eed = 0;
4120         }
4121     }
4122 
4123   for (i = 0; i < num_eed; i++)
4124     {
4125       Dwg_Eed *eed = &obj->tio.object->eed[i];
4126       if (eed->size) // start of a new EED appid section
4127         {
4128           size = eed->size;
4129           if (eed->raw && !need_recalc)
4130             {
4131               did_raw = 1;
4132               bit_write_BS (dat, size);
4133               LOG_TRACE ("EED[%d] size: " FORMAT_BS " [BS]", i, size); LOG_POS
4134               bit_write_H (dat, &eed->handle);
4135               LOG_TRACE ("EED[%d] handle: " FORMAT_H " [H]", i,
4136                          ARGS_H (eed->handle)); LOG_POS
4137               LOG_TRACE ("EED[%d] raw [TF %d]\n", i, size);
4138               bit_write_TF (dat, eed->raw, size);
4139               LOG_TRACE_TF (eed->raw, size);
4140               new_size = 0;
4141             }
4142           // indxf
4143           else if (eed->data)
4144             {
4145               did_raw = 0;
4146               if (new_size) // flush old
4147                 {
4148 
4149 // FIXME DXF import of ACAD EED crashes (GH #244)
4150 // on BLOCK_HEADER with 0 . "DesignCenter Data"
4151 #define EED_ALLOWED !(dat->opts & DWG_OPTS_INDXF) || last_handle->value != 0x12 \
4152                     || obj->fixedtype != DWG_TYPE_BLOCK_HEADER
4153 
4154                   if (EED_ALLOWED)
4155                     {
4156                       eed->size = new_size;
4157                       bit_write_BS (dat, new_size);
4158                       LOG_TRACE ("EED[%d] size: " FORMAT_BS " [BS]", last_size, new_size); LOG_POS;
4159                       bit_write_H (dat, last_handle);
4160                       LOG_TRACE ("EED[%d] handle: " FORMAT_H " [H]", last_size,
4161                                  ARGS_H (*last_handle)); LOG_POS;
4162                       LOG_TRACE ("flush eed_data %lu.%d\n", dat1.byte, dat1.bit);
4163                       dat_flush (dat, &dat1);
4164                     }
4165                   else
4166                     {
4167                       LOG_WARN ("skip EED[%d] handle: " FORMAT_H " [H] for DesignCenter Data", last_size,
4168                                  ARGS_H (*last_handle)); LOG_POS;
4169                       dat1.byte = 0;
4170                     }
4171                   new_size = 0;
4172                 }
4173               new_size = dwg_encode_eed_data (&dat1, eed->data, i);
4174               LOG_POS;
4175             }
4176           last_size = i;
4177           last_handle = &eed->handle;
4178         }
4179       // and if not already written by the previous raw (this has size=0)
4180       else if (!did_raw && eed->data)
4181         {
4182           new_size += dwg_encode_eed_data (&dat1, eed->data, i);
4183           LOG_POS;
4184         }
4185     }
4186   if (new_size && last_handle) // flush remaining rest
4187     {
4188       // FIXME HACK, see above
4189       if (EED_ALLOWED)
4190         {
4191           bit_write_BS (dat, new_size);
4192           LOG_TRACE ("EED[%d] size: " FORMAT_BS " [BS]", last_size, new_size); LOG_POS;
4193           bit_write_H (dat, last_handle);
4194           LOG_TRACE ("EED[%d] handle: " FORMAT_H " [H]", last_size,
4195                      ARGS_H (*last_handle)); LOG_POS;
4196           last_handle = NULL;
4197         }
4198       else
4199         {
4200           LOG_TRACE ("skip EED[%d] handle: " FORMAT_H " [H] for DesignCenter Data", last_size,
4201                      ARGS_H (*last_handle)); LOG_POS;
4202           dat1.byte = 0;
4203         }
4204     }
4205   if (dat1.byte)
4206     LOG_TRACE ("flush eed_data %lu.%d\n", dat1.byte, dat1.bit);
4207   dat_flush (dat, &dat1);
4208   bit_write_BS (dat, 0);
4209   if (i)
4210     LOG_TRACE ("EED[%d] size: 0 [BS] (end)\n", i);
4211   LOG_TRACE ("num_eed: %d\n", num_eed);
4212   bit_chain_free (&dat1);
4213   return 0;
4214 }
4215 
4216 /* The first common part of every entity.
4217 
4218    The last common part is common_entity_handle_data.spec
4219    which is read from the hdl stream.
4220    See DWG_SUPERTYPE_ENTITY in dwg_encode().
4221  */
4222 static int
dwg_encode_entity(Dwg_Object * restrict obj,Bit_Chain * dat,Bit_Chain * restrict hdl_dat,Bit_Chain * str_dat)4223 dwg_encode_entity (Dwg_Object *restrict obj, Bit_Chain *dat,
4224                    Bit_Chain *restrict hdl_dat, Bit_Chain *str_dat)
4225 {
4226   int error = 0;
4227   Dwg_Object_Entity *ent = obj->tio.entity;
4228   Dwg_Object_Entity *_obj = ent;
4229   Dwg_Data *dwg = ent->dwg;
4230 
4231   if (!obj || !dat || !ent)
4232     return DWG_ERR_INVALIDDWG;
4233 
4234   hdl_dat->from_version = dat->from_version;
4235   hdl_dat->version = dat->version;
4236   hdl_dat->opts = dat->opts;
4237 
4238   PRE (R_13)
4239   {
4240 
4241     if (FIELD_VALUE (flag_r11) & 4 && FIELD_VALUE (kind_r11) > 2
4242         && FIELD_VALUE (kind_r11) != 22)
4243       FIELD_RD (elevation_r11, 30);
4244     if (FIELD_VALUE (flag_r11) & 8)
4245       FIELD_RD (thickness_r11, 39);
4246     if (FIELD_VALUE (flag_r11) & 0x20)
4247       {
4248         Dwg_Object_Ref *hdl
4249             = dwg_decode_handleref_with_code (dat, obj, dwg, 0);
4250         if (hdl)
4251           obj->handle = hdl->handleref;
4252       }
4253     if (FIELD_VALUE (extra_r11) & 4)
4254       FIELD_RS (paper_r11, 0);
4255   }
4256 
4257   SINCE (R_2007) { *str_dat = *dat; }
4258   VERSIONS (R_2000, R_2007)
4259   {
4260     obj->bitsize_pos = bit_position (dat);
4261     bit_write_RL (dat, obj->bitsize);
4262     LOG_TRACE ("bitsize: %u [RL] (@%lu.%lu)\n", obj->bitsize,
4263                obj->bitsize_pos / 8, obj->bitsize_pos % 8);
4264   }
4265   obj->was_bitsize_set = 0;
4266   if (obj->bitsize)
4267     {
4268       obj->hdlpos = (obj->address * 8) + obj->bitsize;
4269     }
4270   SINCE (R_2007)
4271   {
4272     // The handle stream offset, i.e. end of the object, right after
4273     // the has_strings bit.
4274     SINCE (R_2010)
4275     {
4276       if (obj->bitsize)
4277         {
4278           obj->hdlpos += 8;
4279           // LOG_HANDLE ("(bitsize: " FORMAT_RL ", ", obj->bitsize);
4280           LOG_HANDLE ("hdlpos: %lu\n", obj->hdlpos);
4281         }
4282     }
4283     // and set the string stream (restricted to size)
4284     error |= obj_string_stream (dat, obj, str_dat);
4285   }
4286 
4287   bit_write_H (dat, &obj->handle);
4288   LOG_TRACE ("handle: " FORMAT_H " [H 5]", ARGS_H (obj->handle))
4289   LOG_INSANE (" @%lu.%u", dat->byte - obj->address, dat->bit)
4290   LOG_TRACE ("\n")
4291   PRE (R_13) { return DWG_ERR_NOTYETSUPPORTED; }
4292 
4293   error |= dwg_encode_eed (dat, obj);
4294   // if (error & (DWG_ERR_INVALIDTYPE|DWG_ERR_VALUEOUTOFBOUNDS))
4295   //  return error;
4296 
4297   // clang-format off
4298   #include "common_entity_data.spec"
4299   // clang-format on
4300 
4301   return error;
4302 }
4303 
4304 static int
dwg_encode_common_entity_handle_data(Bit_Chain * dat,Bit_Chain * hdl_dat,Dwg_Object * restrict obj)4305 dwg_encode_common_entity_handle_data (Bit_Chain *dat, Bit_Chain *hdl_dat,
4306                                       Dwg_Object *restrict obj)
4307 {
4308   Dwg_Object_Entity *ent;
4309   // Dwg_Data *dwg = obj->parent;
4310   Dwg_Object_Entity *_obj;
4311   BITCODE_BL vcount;
4312   int error = 0;
4313   ent = obj->tio.entity;
4314   _obj = ent;
4315 
4316   // clang-format off
4317   #include "common_entity_handle_data.spec"
4318   // clang-format on
4319 
4320   return error;
4321 }
4322 
4323 
4324 void
dwg_encode_handleref(Bit_Chain * hdl_dat,Dwg_Object * restrict obj,Dwg_Data * restrict dwg,Dwg_Object_Ref * restrict ref)4325 dwg_encode_handleref (Bit_Chain *hdl_dat, Dwg_Object *restrict obj,
4326                       Dwg_Data *restrict dwg, Dwg_Object_Ref *restrict ref)
4327 {
4328   // this function should receive a Object_Ref without an abs_ref, calculate it
4329   // and return a Dwg_Handle this should be a higher level function not sure if
4330   // the prototype is correct
4331   assert (obj);
4332 }
4333 
4334 /**
4335  * code:
4336  *  TYPEDOBJHANDLE:
4337  *   2 Soft owner
4338  *   3 Hard owner
4339  *   4 Soft pointer
4340  *   5 Hard pointer
4341  *  OFFSETOBJHANDLE for soft owners or pointers:
4342  *   6 ref + 1
4343  *   8 ref - 1
4344  *   a ref + offset
4345  *   c ref - offset
4346  */
4347 void
dwg_encode_handleref_with_code(Bit_Chain * hdl_dat,Dwg_Object * restrict obj,Dwg_Data * restrict dwg,Dwg_Object_Ref * restrict ref,unsigned int code)4348 dwg_encode_handleref_with_code (Bit_Chain *hdl_dat, Dwg_Object *restrict obj,
4349                                 Dwg_Data *restrict dwg,
4350                                 Dwg_Object_Ref *restrict ref,
4351                                 unsigned int code)
4352 {
4353   // XXX fixme. create the handle, then check the code. allow relative handle
4354   // soft codes.
4355   dwg_encode_handleref (hdl_dat, obj, dwg, ref);
4356   if (ref->absolute_ref == 0 && ref->handleref.code != code)
4357     {
4358       /*
4359        * With TYPEDOBJHANDLE 2-5 the code indicates the type of ownership.
4360        * With OFFSETOBJHANDLE >5 the handle is stored as an offset from some
4361        * other handle.
4362        */
4363       switch (ref->handleref.code)
4364         {
4365         case 0x06:
4366           ref->absolute_ref = (obj->handle.value + 1);
4367           break;
4368         case 0x08:
4369           ref->absolute_ref = (obj->handle.value - 1);
4370           break;
4371         case 0x0A:
4372           ref->absolute_ref = (obj->handle.value + ref->handleref.value);
4373           break;
4374         case 0x0C:
4375           ref->absolute_ref = (obj->handle.value - ref->handleref.value);
4376           break;
4377         case 2:
4378         case 3:
4379         case 4:
4380         case 5:
4381           ref->absolute_ref = ref->handleref.value;
4382           break;
4383         case 0: // ignore (ANYCODE)
4384           ref->absolute_ref = ref->handleref.value;
4385           break;
4386         default:
4387           LOG_WARN ("Invalid handle pointer code %d", ref->handleref.code);
4388           break;
4389         }
4390     }
4391 }
4392 
4393 /* The first common part of every object.
4394 
4395    There is no COMMON_ENTITY_DATA for objects, handles are deferred and flushed later.
4396    See DWG_SUPERTYPE_OBJECT in dwg_encode().
4397 */
4398 static int
dwg_encode_object(Dwg_Object * restrict obj,Bit_Chain * dat,Bit_Chain * restrict hdl_dat,Bit_Chain * str_dat)4399 dwg_encode_object (Dwg_Object *restrict obj, Bit_Chain *dat,
4400                    Bit_Chain *restrict hdl_dat, Bit_Chain *str_dat)
4401 {
4402   int error = 0;
4403   BITCODE_BL vcount;
4404 
4405   hdl_dat->from_version = dat->from_version;
4406   hdl_dat->version = dat->version;
4407   hdl_dat->opts = dat->opts;
4408 
4409   {
4410     Dwg_Object *_obj = obj;
4411     VERSIONS (R_2000, R_2007)
4412     {
4413       obj->bitsize_pos = bit_position (dat);
4414       FIELD_RL (bitsize, 0);
4415     }
4416     obj->was_bitsize_set = 0;
4417     if (obj->bitsize)
4418       // the handle stream offset
4419       obj->hdlpos = bit_position (dat) + obj->bitsize;
4420     SINCE (R_2007) { obj_string_stream (dat, obj, str_dat); }
4421     if (!_obj || !obj->tio.object)
4422       return DWG_ERR_INVALIDDWG;
4423 
4424     bit_write_H (dat, &obj->handle);
4425     LOG_TRACE ("handle: " FORMAT_H " [H 5]\n", ARGS_H (obj->handle));
4426     error |= dwg_encode_eed (dat, obj);
4427 
4428     VERSIONS (R_13, R_14)
4429     {
4430       obj->bitsize_pos = bit_position (dat);
4431       FIELD_RL (bitsize, 0);
4432     }
4433   }
4434 
4435   SINCE (R_13) {
4436     Dwg_Object_Object *_obj = obj->tio.object;
4437     FIELD_BL (num_reactors, 0);
4438     SINCE (R_2004) { FIELD_B (is_xdic_missing, 0); }
4439     SINCE (R_2013) { FIELD_B (has_ds_data, 0); } // AcDs DATA
4440   }
4441   return error;
4442 }
4443 
4444 AFL_GCC_TOOBIG
4445 static int
dwg_encode_header_variables(Bit_Chain * dat,Bit_Chain * hdl_dat,Bit_Chain * str_dat,Dwg_Data * restrict dwg)4446 dwg_encode_header_variables (Bit_Chain *dat, Bit_Chain *hdl_dat,
4447                              Bit_Chain *str_dat, Dwg_Data *restrict dwg)
4448 {
4449   Dwg_Header_Variables *_obj = &dwg->header_vars;
4450   Dwg_Object *obj = NULL;
4451   Dwg_Version_Type old_from = dat->from_version;
4452 
4453   if (!_obj->HANDSEED) // minimal or broken DXF
4454     {
4455       BITCODE_H last_hdl;
4456       unsigned long seed = 0;
4457       dwg->opts |= DWG_OPTS_MINIMAL;
4458       dat->from_version = (Dwg_Version_Type)((int)dat->version - 1);
4459       LOG_TRACE ("encode from minimal DXF\n");
4460 
4461       _obj->HANDSEED = (Dwg_Object_Ref*)calloc (1, sizeof (Dwg_Object_Ref));
4462       // check the object map for the next available handle
4463       last_hdl = dwg->num_object_refs ? dwg->object_ref[ dwg->num_object_refs - 1] : NULL;
4464       if (last_hdl)
4465         {
4466           // find the largest handle
4467           seed = last_hdl->absolute_ref;
4468           LOG_TRACE ("compute HANDSEED %lu ", seed);
4469           for (unsigned i = 0; i < dwg->num_object_refs; i++)
4470             {
4471               Dwg_Object_Ref *ref = dwg->object_ref[i];
4472               if (ref->absolute_ref > seed)
4473                 seed = ref->absolute_ref;
4474             }
4475           _obj->HANDSEED->absolute_ref = seed + 1;
4476           LOG_TRACE ("-> %lu\n", seed);
4477         }
4478       else
4479         _obj->HANDSEED->absolute_ref = 0x72E;
4480     }
4481 
4482     // clang-format off
4483   #include "header_variables.spec"
4484   // clang-format on
4485 
4486   dat->from_version = old_from;
4487   return 0;
4488 }
4489 AFL_GCC_POP
4490 
4491 static int
dwg_encode_xdata(Bit_Chain * restrict dat,Dwg_Object_XRECORD * restrict _obj,unsigned xdata_size)4492 dwg_encode_xdata (Bit_Chain *restrict dat, Dwg_Object_XRECORD *restrict _obj,
4493                   unsigned xdata_size)
4494 {
4495   Dwg_Resbuf *rbuf = _obj->xdata;
4496   enum RESBUF_VALUE_TYPE type;
4497   int error = 0;
4498   int i;
4499   unsigned j = 0;
4500   //BITCODE_BL num_xdata = _obj->num_xdata;
4501   unsigned long start = dat->byte, end = start + xdata_size;
4502   Dwg_Data *dwg = _obj->parent->dwg;
4503   Dwg_Object *obj = &dwg->object[_obj->parent->objid];
4504 
4505   if (dat->opts & DWG_OPTS_IN) // loosen the overflow checks on dxf/json imports
4506     end += xdata_size;
4507 
4508   while (rbuf)
4509     {
4510       bit_write_RS (dat, rbuf->type);
4511       LOG_INSANE ("xdata[%u] type: " FORMAT_RS " [RS] @%lu.%u\n", j,
4512                   rbuf->type, dat->byte - obj->address, dat->bit)
4513       type = dwg_resbuf_value_type (rbuf->type);
4514       switch (type)
4515         {
4516         case DWG_VT_STRING:
4517           PRE (R_2007)
4518           {
4519             if (dat->byte + 3 + rbuf->value.str.size > end)
4520               break;
4521             // from TU DWG only
4522             if (rbuf->value.str.size && rbuf->value.str.is_tu)
4523               {
4524                 BITCODE_TV new = bit_embed_TU_size (rbuf->value.str.u.wdata,
4525                                                     rbuf->value.str.size);
4526                 int len = strlen(new);
4527                 bit_write_RS (dat, len);
4528                 bit_write_RC (dat, rbuf->value.str.codepage);
4529                 if (rbuf->value.str.u.data)
4530                   bit_write_TF (dat, (BITCODE_TF)new, len);
4531                 else
4532                   bit_write_TF (dat, (BITCODE_TF)"", 0);
4533                 LOG_TRACE ("xdata[%u]: \"%s\" [TF %d %d]", j,
4534                            rbuf->value.str.u.data, len, rbuf->type);
4535                 free (new);
4536               }
4537             else
4538               {
4539                 bit_write_RS (dat, rbuf->value.str.size);
4540                 bit_write_RC (dat, rbuf->value.str.codepage);
4541                 if (rbuf->value.str.u.data)
4542                   bit_write_TF (dat, (BITCODE_TF)rbuf->value.str.u.data, rbuf->value.str.size);
4543                 else
4544                   bit_write_TF (dat, (BITCODE_TF)"", 0);
4545                 LOG_TRACE ("xdata[%u]: \"%s\" [TF %d %d]", j,
4546                            rbuf->value.str.u.data, rbuf->value.str.size, rbuf->type);
4547               }
4548             LOG_POS;
4549           }
4550           LATER_VERSIONS
4551           {
4552             if (dat->byte + 2 + (2 * rbuf->value.str.size) > end)
4553               break;
4554             if (rbuf->value.str.size && !rbuf->value.str.is_tu)
4555               {
4556                 // TODO: same len when converted to TU? normally yes
4557                 BITCODE_TU new = bit_utf8_to_TU (rbuf->value.str.u.data, 0);
4558                 bit_write_RS (dat, rbuf->value.str.size);
4559                 for (i = 0; i < rbuf->value.str.size; i++)
4560                   bit_write_RS (dat, new[i]);
4561                 LOG_TRACE_TU ("xdata", new, rbuf->type);
4562                 free (new);
4563               }
4564             else
4565               {
4566                 bit_write_RS (dat, rbuf->value.str.size);
4567                 for (i = 0; i < rbuf->value.str.size; i++)
4568                   bit_write_RS (dat, rbuf->value.str.u.wdata[i]);
4569                 LOG_TRACE_TU ("xdata", rbuf->value.str.u.wdata, rbuf->type);
4570               }
4571             LOG_POS;
4572           }
4573           break;
4574         case DWG_VT_REAL:
4575           if (dat->byte + 8 > end)
4576             break;
4577           bit_write_RD (dat, rbuf->value.dbl);
4578           LOG_TRACE ("xdata[%u]: %f [RD %d]", j, rbuf->value.dbl,
4579                      rbuf->type);
4580           LOG_POS;
4581           break;
4582         case DWG_VT_BOOL:
4583         case DWG_VT_INT8:
4584           bit_write_RC (dat, rbuf->value.i8);
4585           LOG_TRACE ("xdata[%u]: %d [RC %d]", j, (int)rbuf->value.i8,
4586                      rbuf->type);
4587           LOG_POS;
4588           break;
4589         case DWG_VT_INT16:
4590           if (dat->byte + 2 > end)
4591             break;
4592           bit_write_RS (dat, rbuf->value.i16);
4593           LOG_TRACE ("xdata[%u]: %d [RS %d]", j, (int)rbuf->value.i16,
4594                      rbuf->type);
4595           LOG_POS;
4596           break;
4597         case DWG_VT_INT32:
4598           if (dat->byte + 4 > end)
4599             break;
4600           bit_write_RL (dat, rbuf->value.i32);
4601           LOG_TRACE ("xdata[%d]: %ld [RL %d]", j, (long)rbuf->value.i32,
4602                      rbuf->type);
4603           LOG_POS;
4604           break;
4605         case DWG_VT_INT64:
4606           if (dat->byte + 8 > end)
4607             break;
4608           bit_write_RLL (dat, rbuf->value.i64);
4609           LOG_TRACE ("xdata[%u]: " FORMAT_RLL " [RLL %d]", j,
4610                      rbuf->value.i64, rbuf->type);
4611           LOG_POS;
4612           break;
4613         case DWG_VT_POINT3D:
4614           if (dat->byte + 24 > end)
4615             break;
4616           bit_write_RD (dat, rbuf->value.pt[0]);
4617           bit_write_RD (dat, rbuf->value.pt[1]);
4618           bit_write_RD (dat, rbuf->value.pt[2]);
4619           LOG_TRACE ("xdata[%u]: (%f,%f,%f) [3RD %d]", j, rbuf->value.pt[0],
4620                      rbuf->value.pt[1], rbuf->value.pt[2], rbuf->type);
4621           LOG_POS;
4622           break;
4623         case DWG_VT_BINARY:
4624           if (dat->byte + rbuf->value.str.size > end)
4625             break;
4626           // 128 is a tradeoff, which of both data is wrong or right.
4627           if (!rbuf->value.str.u.data && rbuf->value.str.size > 128)
4628             {
4629               LOG_ERROR("Empty xdata string. Write size %u as 0", (unsigned)rbuf->value.str.size);
4630               bit_write_RC (dat, 0);
4631             }
4632           else
4633             bit_write_RC (dat, rbuf->value.str.size);
4634           if (rbuf->value.str.size)
4635             bit_write_TF (dat, (BITCODE_TF)rbuf->value.str.u.data, rbuf->value.str.size);
4636           LOG_TRACE ("xdata[%u]: [TF %d %d] ", j, rbuf->value.str.size,
4637                      rbuf->type);
4638           LOG_TRACE_TF (rbuf->value.str.u.data, rbuf->value.str.size);
4639           LOG_POS;
4640           break;
4641         case DWG_VT_HANDLE:
4642         case DWG_VT_OBJECTID:
4643           if (dat->byte + 8 > end)
4644             break;
4645           for (i = 0; i < 8; i++)
4646             bit_write_RC (dat, rbuf->value.hdl[i]);
4647           LOG_TRACE ("xdata[%u]: " FORMAT_H " [H %d]", j,
4648                      ARGS_H (rbuf->value.h), rbuf->type);
4649           LOG_POS;
4650           break;
4651         case DWG_VT_INVALID:
4652         default:
4653           LOG_ERROR ("Invalid group code in xdata: %d", rbuf->type);
4654           error = DWG_ERR_INVALIDEED;
4655           break;
4656         }
4657       rbuf = rbuf->nextrb;
4658       j++;
4659       if (j >= _obj->num_xdata)
4660         break;
4661       if (dat->byte >= end)
4662         {
4663           LOG_WARN ("xdata overflow %u", xdata_size);
4664           break;
4665         }
4666     }
4667   if (_obj->xdata_size != dat->byte - start)
4668     {
4669       if (dat->opts & DWG_OPTS_IN) // imprecise xdata_size: calculate
4670         {
4671           _obj->xdata_size = dat->byte - start;
4672           LOG_TRACE ("-xdata_size: " FORMAT_BL " (calculated)\n", _obj->xdata_size);
4673           return error;
4674         }
4675       else
4676         {
4677           LOG_WARN ("xdata Written %lu, expected " FORMAT_BL, dat->byte - start,
4678                     _obj->xdata_size);
4679           _obj->xdata_size = dat->byte - start;
4680           return error ? error : 1;
4681         }
4682     }
4683   return 0;
4684 }
4685 
4686 #undef IS_ENCODER
4687