1/* -*- c -*- */
2/*****************************************************************************/
3/*  LibreDWG - free implementation of the DWG file format                    */
4/*                                                                           */
5/*  Copyright (C) 2020-2021 Free Software Foundation, Inc.                   */
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 * acds.spec: AcDb:AcDsProtoype_1b datastorage section specification,
16 *            containing new SAB ACIS content.
17 * written by Reini Urban
18 */
19
20  #include "spec.h"
21
22  static char _AcDs_Schema_Prop_types[] = {0, 0, 2, 1, 2, 4, 8, 1, 2, 4, 8, 4, 8, 0, 0, 0};
23
24  DECODER {
25    LOG_TRACE ("unknown_bits [%ld (%u,%d,%d) %ld TF]: ", dat->size * 8,
26               0, 0, 0, dat->size);
27    LOG_TRACE_TF (dat->chain, (int)dat->size);
28    LOG_TRACE ("\n");
29  }
30  // header
31  FIELD_RLx (file_signature, 0);
32  FIELD_RL (file_header_size, 0);
33  FIELD_RL (unknown_1, 0);  // always 2
34  FIELD_RL (version, 0);    // always 2
35  FIELD_RL (unknown_2, 0);  // always 0
36  FIELD_RL (ds_version, 0); // datastorage revision
37  FIELD_RL (segidx_offset, 0);
38  FIELD_RL (segidx_unknown, 0);
39  FIELD_RL (num_segidx, 0);
40  FIELD_RL (schidx_segidx, 0);
41  FIELD_RL (datidx_segidx, 0);
42  FIELD_RL (search_segidx, 0);
43  FIELD_RL (prvsav_segidx, 0);
44  FIELD_RL (file_size, 0);
45  dat->byte = _obj->segidx_offset;
46#ifdef IS_DECODER
47  if (dat->byte > dat->size)
48    {
49      LOG_ERROR ("Invalid segidx_offset");
50      return DWG_ERR_VALUEOUTOFBOUNDS;
51    }
52  if ((size_t)(_obj->num_segidx * sizeof (Dwg_AcDs_Segment)) >
53      (size_t)(dat->size - dat->byte))
54    {
55      LOG_ERROR ("Invalid num_segidx");
56      return DWG_ERR_VALUEOUTOFBOUNDS;
57    }
58  _obj->segments = (Dwg_AcDs_Segment *)calloc (_obj->num_segidx,
59                                               sizeof (Dwg_AcDs_Segment));
60#endif
61#ifndef IS_JSON
62  if (FIELD_VALUE(num_segidx))
63    {
64      SUB_FIELD_RSx (segments[0],signature, 0); /* always 0xD5AC (ACD5 in the TF) */
65      FIELD_TFF (segments[0].name, 6, 0);       /* always segidx */
66      DECODER { _obj->segments[0].type = 0; }
67      JSON { SUB_FIELD (segments[0],type, RC, 0); }
68      SUB_FIELD (segments[0],segment_idx, RL, 0);
69      SUB_FIELD (segments[0],is_blob01, RL, 0);
70      SUB_FIELD (segments[0],segsize, RL, 0);
71      SUB_FIELD (segments[0],unknown_2, RL, 0);
72      SUB_FIELD (segments[0],ds_version, RL, 0); // datastorage revision
73      SUB_FIELD (segments[0],unknown_3, RL, 0);
74      SUB_FIELD (segments[0],data_algn_offset, RL, 0);
75      SUB_FIELD (segments[0],objdata_algn_offset, RL, 0);
76      FIELD_TFF (segments[0].padding, 8, 0); // always 8x 0x55
77    }
78#endif
79
80  REPEAT (num_segidx, segidx, Dwg_AcDs_SegmentIndex)
81  REPEAT_BLOCK
82#ifdef IS_JSON
83      KEY (index); VALUE_RL (rcount1, 0);
84#endif
85      SUB_FIELD_RLL (segidx[rcount1],offset, 0);
86      SUB_FIELD_RL (segidx[rcount1],size, 0);
87      DECODER { if (_obj->segidx[rcount1].offset) _obj->total_segments++; }
88  END_REPEAT_BLOCK
89#ifdef IS_JSON
90  END_REPEAT (segidx) // still needed, free later
91#endif
92
93  _REPEAT_NF (_obj->num_segidx, segments, Dwg_AcDs_Segment, 1)
94  REPEAT_BLOCK
95      if (_obj->segidx[rcount1].offset)
96        {
97#ifdef IS_JSON
98          KEY (index); VALUE_RL (rcount1, 0);
99#endif
100#ifdef IS_DECODER
101          if (_obj->segidx[rcount1].offset >= dat->size)
102            {
103              LOG_ERROR ("Invalid AcDs.segments[%d] offset: " FORMAT_RLL "\n", rcount1,
104                         _obj->segidx[rcount1].offset);
105              _obj->segidx[rcount1].offset = 0;
106              continue;
107            }
108          else
109            {
110              LOG_TRACE ("\nsegments[%d] offset: " FORMAT_RLL "\n", rcount1,
111                         _obj->segidx[rcount1].offset);
112              dat->byte = _obj->segidx[rcount1].offset;
113            }
114#endif
115        }
116      else
117        {
118#ifdef IS_JSON
119          ENDHASH;
120#endif
121          continue;
122        }
123
124      SUB_FIELD_RSx (segments[rcount1],signature, 0); /* always 0xD5AC (ACD5 in the TF) */
125      DECODER {
126        if (_obj->segments[rcount1].signature != 0xD5AC)
127          {
128            LOG_ERROR ("Invalid AcDs.segments[%d].signature %x != 0xd5ac", rcount1,
129                       _obj->segments[rcount1].signature);
130            error |= DWG_ERR_SECTIONNOTFOUND;
131            //continue;
132          }
133      }
134      /* segidx, datidx, _data_, schidx, schdat, search, blob01, prvsav, freesp */
135      FIELD_TFF (segments[rcount1].name, 6, 0);
136      DECODER {
137        _obj->segments[rcount1].name[6] = '\0';
138        _obj->segments[rcount1].type = -1;
139        if (strEQc ((char*)_obj->segments[rcount1].name, "segidx"))
140          _obj->segments[rcount1].type = 0;
141        else if (strEQc ((char*)_obj->segments[rcount1].name, "datidx"))
142          _obj->segments[rcount1].type = 1;
143        else if (strEQc ((char*)_obj->segments[rcount1].name, "_data_"))
144          _obj->segments[rcount1].type = 2;
145        else if (strEQc ((char*)_obj->segments[rcount1].name, "schidx"))
146          _obj->segments[rcount1].type = 3;
147        else if (strEQc ((char*)_obj->segments[rcount1].name, "schdat"))
148          _obj->segments[rcount1].type = 4;
149        else if (strEQc ((char*)_obj->segments[rcount1].name, "search"))
150          _obj->segments[rcount1].type = 5;
151        else if (strEQc ((char*)_obj->segments[rcount1].name, "blob01"))
152          _obj->segments[rcount1].type = 6;
153        else if (strEQc ((char*)_obj->segments[rcount1].name, "prvsav")) // ODA undocumented
154          _obj->segments[rcount1].type = 7;
155        else if (strEQc ((char*)_obj->segments[rcount1].name, "freesp")) // ODA undocumented
156          _obj->segments[rcount1].type = 8;
157        else
158          {
159            LOG_ERROR ("Invalid AcDs.segments[%d].name %s", rcount1,
160                       (char *)_obj->segments[rcount1].name);
161            error |= DWG_ERR_SECTIONNOTFOUND;
162            continue;
163          }
164      }
165      JSON {
166        SUB_FIELD (segments[rcount1],type, RC, 0);
167      }
168      SUB_FIELD (segments[rcount1],segment_idx, RL, 0);
169      SUB_FIELD (segments[rcount1],is_blob01, RL, 0);
170      SUB_FIELD (segments[rcount1],segsize, RL, 0);
171      SUB_FIELD (segments[rcount1],unknown_2, RL, 0);
172      SUB_FIELD (segments[rcount1],ds_version, RL, 0); // datastorage revision
173      SUB_FIELD (segments[rcount1],unknown_3, RL, 0);
174      SUB_FIELD (segments[rcount1],data_algn_offset, RL, 0);
175      SUB_FIELD (segments[rcount1],objdata_algn_offset, RL, 0);
176      FIELD_TFF (segments[rcount1].padding, 8, 0); // always 8x 0x55
177
178      switch (_obj->segments[rcount1].type) {
179      case 0: // hmm, more than 1 segidx?
180#if 0
181        REPEAT2 (num_segidx, segidx, Dwg_AcDs_SegmentIndex)
182        REPEAT_BLOCK
183# ifdef IS_JSON
184            KEY (index); VALUE_RL (rcount2, 0);
185# endif
186            SUB_FIELD_RLL (segidx[rcount2],offset, 0);
187            SUB_FIELD_RL (segidx[rcount2],size, 0);
188        END_REPEAT_BLOCK
189        END_REPEAT (segidx)
190#endif
191        break;
192      case 1:
193        if (_obj->datidx_segidx != rcount1)
194          LOG_WARN ("Possibly wrong datidx_segidx %d for %d", _obj->datidx_segidx, rcount1);
195        SUB_FIELD_RL (datidx,num_entries, 0);
196        SUB_FIELD_RL (datidx,di_unknown, 0);
197        REPEAT2 (datidx.num_entries, datidx.entries, Dwg_AcDs_DataIndex_Entry)
198        REPEAT_BLOCK
199#ifdef IS_JSON
200            KEY (index); VALUE_RL (rcount2, 0);
201#endif
202            SUB_FIELD_RL (datidx.entries[rcount2],segidx, 0);
203            SUB_FIELD_RL (datidx.entries[rcount2],offset, 0);
204            SUB_FIELD_RL (datidx.entries[rcount2],schidx, 0);
205        END_REPEAT_BLOCK
206        END_REPEAT (datidx.entries)
207        break;
208      case 3:
209        if (_obj->schidx_segidx != rcount1)
210          LOG_WARN ("Possibly wrong schidx_segidx %d for %d", _obj->schidx_segidx, rcount1);
211        SUB_FIELD_RL (schidx,num_props, 0); // or RLL
212        SUB_FIELD_RL (schidx,si_unknown_1, 0);
213        REPEAT2 (schidx.num_props, schidx.props, Dwg_AcDs_SchemaIndex_Prop)
214        REPEAT_BLOCK
215            SUB_FIELD_RL (schidx.props[rcount2],index, 0);
216            SUB_FIELD_RL (schidx.props[rcount2],segidx, 0);
217            SUB_FIELD_RL (schidx.props[rcount2],offset, 0);
218        END_REPEAT_BLOCK
219        END_REPEAT (schidx.props)
220        SUB_FIELD_RLL (schidx,si_tag, 0); /* 0x0af10c */
221        SUB_FIELD_RL (schidx,num_prop_entries, 0); // or RLL
222        SUB_FIELD_RL (schidx,si_unknown_2, 0);
223        REPEAT2 (schidx.num_prop_entries, schidx.prop_entries, Dwg_AcDs_SchemaIndex_Prop)
224        REPEAT_BLOCK
225            SUB_FIELD_RL (schidx.prop_entries[rcount2],index, 0);
226            SUB_FIELD_RL (schidx.prop_entries[rcount2],segidx, 0);
227            SUB_FIELD_RL (schidx.prop_entries[rcount2],offset, 0);
228        END_REPEAT_BLOCK
229        END_REPEAT (schidx.prop_entries)
230        break;
231      case 4:
232        DEBUG_HERE
233        DECODER { _obj->schdat.num_uprops = 1; } // FIXME
234        REPEAT2 (schdat.num_uprops, schdat.uprops, Dwg_AcDs_SchemaData_UProp)
235        REPEAT_BLOCK
236          SUB_FIELD_RL (schdat.uprops[rcount2], size, 0);
237          SUB_FIELD_RL (schdat.uprops[rcount2], flags, 0);
238        END_REPEAT_BLOCK
239        END_REPEAT (schdat.uprops)
240        DEBUG_HERE
241        REPEAT2 (schdat.num_schemas, schdat.schemas, Dwg_AcDs_Schema)
242        REPEAT_BLOCK
243            SUB_FIELD_RS (schdat.schemas[rcount2],num_index, 0);
244            SUB_FIELD_VECTOR (schdat.schemas[rcount2],index, num_index, RLL, 0);
245            SUB_FIELD_RS (schdat.schemas[rcount2],num_props, 0);
246            REPEAT2 (schdat.schemas[rcount2].num_props, schdat.schemas[rcount2].props, Dwg_AcDs_Schema_Prop)
247#define prop schdat.schemas[rcount2].props[rcount3]
248            REPEAT_BLOCK
249                SUB_FIELD_RL (prop,flags, 91); // 1, 2, 8
250                SUB_FIELD_RL (prop,namidx, 2);
251                if (!(_obj->prop.flags & 2))
252                {
253                  SUB_FIELD_RL (prop,type, 280);
254                  if (_obj->prop.type  == 0xe)
255                    {
256                      SUB_FIELD_RL (prop,type_size, 0)
257                    }
258                  else
259                    _obj->prop.type_size = _AcDs_Schema_Prop_types[_obj->prop.type];
260                }
261                if (_obj->prop.flags == 1)
262                  {
263                    SUB_FIELD_RL (prop,unknown_1, 0)
264                  }
265                else if (_obj->prop.flags == 8)
266                  {
267                    SUB_FIELD_RL (prop,unknown_2, 0)
268                  }
269                SUB_FIELD_RS (prop,num_values, 0);
270                if (_obj->prop.type_size)
271                  {
272                    SUB_FIELD_VECTOR_TYPESIZE (prop, values, num_values,
273                                               _obj->prop.type_size, 0);
274                  }
275            END_REPEAT_BLOCK
276#undef prop
277            END_REPEAT (schdat.schemas[rcount2].props)
278        END_REPEAT_BLOCK
279        END_REPEAT (schdat.schemas)
280        LOG_WARN ("AcDs %s segment yet unhandled", _obj->segments[rcount1].name)
281        break;
282      case 5: // search
283        if (_obj->search_segidx != rcount1)
284          LOG_WARN ("Possibly wrong search_segidx %d for %d", _obj->search_segidx, rcount1);
285        SUB_FIELD_RL (search,num_search, 0);
286        REPEAT2 (search.num_search, search.search, Dwg_AcDs_Search_Data)
287        REPEAT_BLOCK
288          SUB_FIELD_RL (search.search[rcount2],schema_namidx, 0);
289          SUB_FIELD_RL (search.search[rcount2],num_sortedidx, 0);
290          SUB_FIELD_VECTOR (search.search[rcount2],sortedidx, num_sortedidx, RLL, 0);
291          SUB_FIELD_RL (search.search[rcount2],num_ididxs, 0);
292          SUB_FIELD_RL (search.search[rcount2],unknown, 0);
293          REPEAT3 (search.search[rcount2].num_ididxs, search.search[rcount2].ididxs, Dwg_AcDs_Search_IdIdxs)
294          REPEAT_BLOCK
295            SUB_FIELD_RL (search.search[rcount2].ididxs[rcount3],num_ididx, 0);
296            REPEAT4 (search.search[rcount2].ididxs[rcount3].num_ididx, search.search[rcount2].ididxs[rcount3].ididx, Dwg_AcDs_Search_IdIdx)
297            REPEAT_BLOCK
298              SUB_FIELD_RLL (search.search[rcount2].ididxs[rcount3].ididx[rcount4],handle, 0);
299              SUB_FIELD_RL (search.search[rcount2].ididxs[rcount3].ididx[rcount4],num_ididx, 0);
300              SUB_FIELD_VECTOR (search.search[rcount2].ididxs[rcount3].ididx[rcount4],ididx, num_ididx, RLL, 0);
301            END_REPEAT_BLOCK
302            END_REPEAT (search.search[rcount2].ididxs[rcount3].ididx)
303          END_REPEAT_BLOCK
304          END_REPEAT (search.search[rcount2].ididxs)
305        END_REPEAT_BLOCK
306        END_REPEAT (search.search)
307        break;
308      case 7: // prvsav
309        if (_obj->prvsav_segidx != rcount1)
310          LOG_WARN ("Possibly wrong prvsav_segidx %d for %d", _obj->prvsav_segidx, rcount1);
311        // fallthru
312        //break;
313      case 8: // freesp
314        //break;
315      case 2: // _data_
316        //break;
317      case 6: // blob01
318        //break;
319      default:
320#ifndef IS_FREE
321        LOG_WARN ("AcDs %s segment yet unhandled", _obj->segments[rcount1].name)
322#endif
323        break;
324      }
325  END_REPEAT_BLOCK
326  END_REPEAT (segments)
327#ifdef IS_FREE
328  END_REPEAT (segidx)
329#endif
330
331#ifdef IS_DECODER
332  DECODER {
333    char *s, *e;
334    unsigned int i = 0;
335    char *acis_sab_data;
336    const BITCODE_B acis_empty = 0;
337    const BITCODE_BS version = 2;
338    BITCODE_BL num_acis_sab_data;
339    const unsigned int wanted = dwg->num_acis_sab_hdl;
340    // 414349532042696E61727946696C65 @10504/2 = 5252
341    const char start[] = "ACIS BinaryFile";
342    // 0E03456E640E026F660E0341534D0D0464617461 @13822/2 = 6911
343    const char end[] = "\016\003End\016\002of\016\003ASM\r\004data";
344    LOG_TRACE ("\nSearch for ACIS BinaryFile data:\n");
345    num_acis_sab_data = 0;
346    while ((s = (char *)memmem (&dat->chain[i], dat->size - i, start,
347                                strlen (start))))
348      {
349        unsigned j = s - (char*)&dat->chain[0]; // absolute_offset of found range
350        if ((e = (char *)memmem (s, dat->size - j, end, strlen (end))))
351          {
352            BITCODE_H hdl;
353            Dwg_Object *o;
354            Dwg_Entity_3DSOLID *sol;
355            unsigned size = e - s;
356            size += strlen (end);
357            LOG_TRACE ("acis_sab_data[%d]: found %s at %u, size %u\n",
358                       num_acis_sab_data, start, j, size);
359            if (!dwg->num_acis_sab_hdl)
360              {
361                LOG_ERROR ("Not enough %u 3DSOLIDs for the %u-th AcDs SAB data",
362                           wanted, num_acis_sab_data)
363                return DWG_ERR_INVALIDHANDLE;
364              }
365            hdl = SHIFT_HV (dwg, num_acis_sab_hdl, acis_sab_hdl);
366            o = dwg_resolve_handle (dwg, hdl->handleref.value);
367            LOG_TRACE ("%s.acis_sab_hdl[%u] = " FORMAT_REF "\n", o->name,
368                       dwg->num_acis_sab_hdl + 1, ARGS_REF (hdl))
369            if (!o || !dwg_obj_is_3dsolid (o))
370              {
371                LOG_ERROR ("Matching object %s " FORMAT_REF " not a 3DSOLID",
372                           o ? o->name : "", ARGS_REF (hdl))
373                free (hdl);
374                error |= DWG_ERR_INVALIDHANDLE;
375                continue;
376              }
377            sol = o->tio.entity->tio._3DSOLID;
378            // not NULL terminated
379            acis_sab_data = (char*)malloc (size);
380            memcpy (acis_sab_data, s, size);
381            num_acis_sab_data++;
382            dwg_dynapi_entity_set_value (sol, o->name, "acis_data", &acis_sab_data, 0);
383            dwg_dynapi_entity_set_value (sol, o->name, "sab_size", &size, 0);
384            dwg_dynapi_entity_set_value (sol, o->name, "version", &version, 0);
385            // FIXME only until we can write acds:
386            dwg_dynapi_entity_set_value (sol, o->name, "acis_empty", &acis_empty, 0);
387            // o->tio.entity->has_ds_data = 0; // maybe there is more, like the wires and silhuettes
388            LOG_TRACE ("%s.acis_data = %u " FORMAT_REF "\n", o->name, size, ARGS_REF (hdl))
389            free (hdl); // it is a non-global, free'able handleref. Created in common_entity_data.spec
390            i = j + size; // next offset to try
391          }
392        else
393          {
394            LOG_WARN ("No End-of-ASM-data found from %u - %lu for %d-th SAB data",
395                       j, dat->size, num_acis_sab_data);
396            i = j + 20;
397          }
398      }
399    if (wanted == num_acis_sab_data)
400      {
401        LOG_TRACE ("Matching number of %u 3DSOLID entities and AcDs SAB data\n",
402                   wanted)
403      }
404    else
405      {
406        LOG_WARN ("Not matching number of %u 3DSOLID entities and %u AcDs SAB data\n",
407                  wanted, num_acis_sab_data);
408        while (dwg->num_acis_sab_hdl > 0)
409          free (SHIFT_HV (dwg, num_acis_sab_hdl, acis_sab_hdl));
410      }
411  }
412#endif
413