@@ -339,89 +339,85 @@
#ifdef IS_DECODER
DECODER {
- char *s, *e;
- unsigned int i = 0;
- char *acis_sab_data;
+ /* --- uncad local patch (see docs/CAVEATS.md, "Local patches to the
+ vendored LibreDWG"): each ACIS body goes to the entity whose handle
+ its _data_ record names. Upstream searched the section for the
+ "ACIS BinaryFile" signature and handed the bodies it found to the
+ drawing's solids in the order they came, which is not the order the
+ records are written in -- bodies landed on the wrong solids -- and it
+ missed the "ASM BinaryFile4" bodies R2018 writes altogether.
+ A _data_ segment is a 0x30-byte segment header, then an array of
+ 20-byte record headers (RL 0x14, RL 1, RLL handle, RL offset), then
+ the records: at the array's end plus a header's offset, an RL size and
+ that many bytes. --- end uncad local patch --- */
+#define UNCAD_LE32(q) \
+ ((BITCODE_RL)(q)[0] | ((BITCODE_RL)(q)[1] << 8) \
+ | ((BITCODE_RL)(q)[2] << 16) | ((BITCODE_RL)(q)[3] << 24))
const BITCODE_B acis_empty = 0;
const BITCODE_BS version = 2;
- BITCODE_BL num_acis_sab_data;
- const unsigned int wanted = dwg->num_acis_sab_hdl;
- // 414349532042696E61727946696C65 @10504/2 = 5252
- const char start[] = "ACIS BinaryFile";
- // 0E03456E640E026F660E0341534D0D0464617461 @13822/2 = 6911
- const char end[] = "\016\003End\016\002of\016\003ASM\r\004data";
- LOG_TRACE ("\nSearch for ACIS BinaryFile data:\n");
- num_acis_sab_data = 0;
- while (i < dat->size
- && (s = (char *)memmem (&dat->chain[i], dat->size - i, start,
- strlen (start))))
+ const size_t seg_hdr_size = 0x30;
+ const size_t rec_hdr_size = 20;
+ size_t i = 0;
+ while (i + 8 <= dat->size)
{
- size_t j = s - (char*)&dat->chain[0]; // absolute_offset of found range
- if ((e = (char *)memmem (s, dat->size - j, end, strlen (end))))
+ unsigned char *seg = (unsigned char *)memmem (
+ &dat->chain[i], dat->size - i, "\254\325_data_", 8);
+ size_t start, hdrs, base, n, k;
+ if (!seg)
+ break;
+ start = (size_t)(seg - dat->chain);
+ i = start + 8;
+ hdrs = start + seg_hdr_size;
+ n = 0;
+ while (hdrs + (n + 1) * rec_hdr_size <= dat->size
+ && UNCAD_LE32 (&dat->chain[hdrs + n * rec_hdr_size])
+ == rec_hdr_size)
+ n++;
+ base = hdrs + n * rec_hdr_size;
+ for (k = 0; k < n; k++)
{
- BITCODE_H hdl;
+ const unsigned char *h = &dat->chain[hdrs + k * rec_hdr_size];
+ BITCODE_RLL handle = (BITCODE_RLL)UNCAD_LE32 (h + 8)
+ | ((BITCODE_RLL)UNCAD_LE32 (h + 12) << 32);
+ size_t rec = base + UNCAD_LE32 (h + 16);
+ size_t size;
Dwg_Object *o;
Dwg_Entity_3DSOLID *sol;
- size_t size = e - s;
- size += strlen (end);
- LOG_TRACE ("acis_sab_data[%d]: found %s at %" PRIuSIZE ", size %" PRIuSIZE "\n",
- num_acis_sab_data, start, j, size);
- if (!dwg->num_acis_sab_hdl)
+ char *acis_sab_data;
+ if (rec < base || rec + 4 > dat->size)
+ continue;
+ size = UNCAD_LE32 (&dat->chain[rec]);
+ if (size < 15 || size > dat->size - rec - 4)
+ continue;
+ if (memcmp (&dat->chain[rec + 4], "ACIS BinaryFile", 15)
+ && memcmp (&dat->chain[rec + 4], "ASM BinaryFile4", 15))
+ continue;
+ o = dwg_resolve_handle (dwg, handle);
+ if (!o || o->supertype != DWG_SUPERTYPE_ENTITY
+ || !dwg_obj_is_3dsolid (o))
{
- LOG_ERROR ("Not enough %u 3DSOLIDs for the %u-th AcDs SAB data",
- wanted, num_acis_sab_data);
- return DWG_ERR_INVALIDHANDLE;
- }
- hdl = SHIFT_HV (dwg, num_acis_sab_hdl, acis_sab_hdl);
- o = dwg_resolve_handle (dwg, hdl->handleref.value);
- LOG_TRACE ("%s.acis_sab_hdl[%u] = " FORMAT_REF "\n", o->name,
- dwg->num_acis_sab_hdl + 1, ARGS_REF (hdl));
- if (!o || !dwg_obj_is_3dsolid (o))
- {
- LOG_ERROR ("Matching object %s " FORMAT_REF " not a 3DSOLID",
- o ? o->name : "", ARGS_REF (hdl));
- free (hdl);
- error |= DWG_ERR_INVALIDHANDLE;
+ LOG_WARN ("AcDs SAB data for " FORMAT_RLLx
+ " which is not a 3DSOLID", handle);
continue;
}
sol = o->tio.entity->tio._3DSOLID;
- // not NULL terminated
- acis_sab_data = (char*)malloc (size);
- memcpy (acis_sab_data, s, size);
- num_acis_sab_data++;
- dwg_dynapi_entity_set_value (sol, o->name, "acis_data", &acis_sab_data, 0);
+ acis_sab_data = (char *)malloc (size);
+ if (!acis_sab_data)
+ continue;
+ memcpy (acis_sab_data, &dat->chain[rec + 4], size);
+ dwg_dynapi_entity_set_value (sol, o->name, "acis_data",
+ &acis_sab_data, 0);
dwg_dynapi_entity_set_value (sol, o->name, "sab_size", &size, 0);
dwg_dynapi_entity_set_value (sol, o->name, "version", &version, 0);
- // FIXME only until we can write acds:
- dwg_dynapi_entity_set_value (sol, o->name, "acis_empty", &acis_empty, 0);
- // o->tio.entity->has_ds_data = 0; // maybe there is more, like the
- // wires and silhuettes
- LOG_TRACE ("%s.acis_data = %" PRIuSIZE " " FORMAT_REF "\n", o->name, size,
- ARGS_REF (hdl));
- free (hdl); // it is a non-global, free'able handleref. Created in
- // common_entity_data.spec
- i = (j + size) & UINT_MAX; // next offset to try
- }
- else
- {
- LOG_WARN ("No End-of-ASM-data found from %" PRIuSIZE " - %" PRIuSIZE
- " for %d-th SAB data",
- j, dat->size, num_acis_sab_data);
- i = (j + 20) & UINT_MAX;
+ dwg_dynapi_entity_set_value (sol, o->name, "acis_empty",
+ &acis_empty, 0);
+ LOG_TRACE ("%s.acis_data = %" PRIuSIZE " from AcDs record " FORMAT_RLLx
+ "\n", o->name, size, handle);
}
}
- if (wanted == num_acis_sab_data)
- {
- LOG_TRACE ("Matching number of %u 3DSOLID entities and AcDs SAB data\n",
- wanted);
- }
- else
- {
- LOG_WARN ("Not matching number of %u 3DSOLID entities and %u AcDs SAB "
- "data\n",
- wanted, num_acis_sab_data);
- while (dwg->num_acis_sab_hdl > 0)
- free (SHIFT_HV (dwg, num_acis_sab_hdl, acis_sab_hdl));
- }
+#undef UNCAD_LE32
+ /* The handles queued for the search this replaces. */
+ while (dwg->num_acis_sab_hdl > 0)
+ free (SHIFT_HV (dwg, num_acis_sab_hdl, acis_sab_hdl));
}
#endif