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