/*****************************************************************************/ /* LibreDWG - free implementation of the DWG file format */ /* */ /* Copyright (C) 2018-2019 Free Software Foundation, Inc. */ /* */ /* This library is free software, licensed under the terms of the GNU */ /* General Public License as published by the Free Software Foundation, */ /* either version 3 of the License, or (at your option) any later version. */ /* You should have received a copy of the GNU General Public License */ /* along with this program. If not, see . */ /*****************************************************************************/ /* * unknown.c: decode unknown bitstreams * written by Reini Urban * * A sample program to find the most likely * fields for all unknown dwg entities and objects. * Gather all binary raw data from all unknown dwg entities and objects * into examples/alldwg.inc and examples/alldxf_*.inc * With the available likely fields try permutations of most likely types. * When no identifiable field value was found, (filled is empty) 0.0% is * printed and the entity is printed to stderr for alldwg.skip to be ignored * later. * See also HACKING "reverse-engineering with examples/unknown" * or https://savannah.gnu.org/forum/forum.php?forum_id=9197 and * https://savannah.gnu.org/forum/forum.php?forum_id=9203. */ #include "../src/config.h" #include #include #include #include #include //dirname,basename #include "dwg.h" #include "../src/bits.h" #include "../src/logging.h" #include "../src/common.h" #include "../src/myalloca.h" // not needed anymore // void *memmem (const void *big, size_t big_len, const void *little, // size_t little_len); #define CHAIN_SIZE 128 int cur_hdl; // to avoid dupl. search #include "unknown.h" static struct _unknown_dxf unknown_dxf[] = { // see log_unknown_dxf.pl #include "alldxf_0.inc" { NULL, NULL, 0, "", 0, 0, 0, 0, 0, 0, 0, NULL } }; #include "alldxf_1.inc" /* not needed for the solver, only to check against afterwards */ #if 0 static struct _unknown { const char *name; const char *log; const char *bits; const char *dxf; const unsigned int handle; const int is_entity; const int num_bits; const int commonsize; const int hdloff; const int strsize; const int hdlsize; const int bitsize; } unknowns[] = { { "ACAD_EVALUATION_GRAPH", "example_2000.log", 0x2E3, "40501406481013fffffffcffffffff3fffffffcffffffff980c0c80b8bee", "test/test-data/example_2000.dxf", 0, 234, 60, -60, 0, 268 }, /* the following types: 5 ACDBASSOCGEOMDEPENDENCY 3 ACDBASSOCNETWORK 53 ACDBDETAILVIEWSTYLE 53 ACDBSECTIONVIEWSTYLE 5 ACDB_LEADEROBJECTCONTEXTDATA_CLASS 63 CELLSTYLEMAP 245 MATERIAL 1 MULTILEADER 1 SUN 97 TABLESTYLE */ // see log_unknown.pl # include "alldwg.inc" { 0, NULL, "", "", NULL, 0L, 0, 0, 0, 0, 0, 0 } }; #endif static struct _bd { const char *value; const char *bin; } bd[] = { // see bd-unknown.pl #include "bd-unknown.inc" { NULL, NULL } }; static void bits_TV (Bit_Chain *restrict dat, struct _unknown_field *restrict g) { bit_write_TV (dat, (char *)g->value); g->type = BITS_TV; } static void bits_TU (Bit_Chain *restrict dat, struct _unknown_field *restrict g) { // the source is always utf8 BITCODE_TU wstr = bit_utf8_to_TU ((char *)g->value, 0); bit_write_TU (dat, wstr); g->type = BITS_TU; free (wstr); } static void bits_TF (Bit_Chain *restrict dat, struct _unknown_field *restrict g, int len) { bit_write_TF (dat, (BITCODE_TF)g->value, len); g->type = BITS_TF; } static void bits_string (Bit_Chain *restrict dat, struct _unknown_field *restrict g) { if (dat->version >= R_2007) bits_TU (dat, g); else bits_TV (dat, g); } static void bits_hexstring (Bit_Chain *restrict dat, struct _unknown_field *restrict g) { // convert hex to string int len = strlen (g->value) / 2; unsigned char buf[1024]; for (int i = 0; i < len; i++) { unsigned char *s = (unsigned char *)&g->value[i * 2]; buf[i] = ((*s < 'A') ? *s - '0' : *s + 10 - 'A') << 4; s++; buf[i] += (*s < 'A') ? *s - '0' : *s + 10 - 'A'; } bit_write_TF (dat, buf, len); g->type = BITS_TF; } static void bits_B (Bit_Chain *restrict dat, struct _unknown_field *restrict g) { if (*g->value == '0') { bit_write_B (dat, 0); g->type = BITS_B; } else if (*g->value == '1') { bit_write_B (dat, 0); g->type = BITS_B; } else { LOG_ERROR ("Invalid B %s", g->value); } } static void bits_RD (Bit_Chain *restrict dat, struct _unknown_field *restrict g) { double d = strtod (g->value, NULL); bit_write_RD (dat, d); g->type = BITS_RD; } static void bits_BD (Bit_Chain *restrict dat, struct _unknown_field *restrict g) { double d = strtod (g->value, NULL); // properly found are: 0.0, 1.0, 5929.403601723592, 607.2183823688756, // 4.0, 2.0, 0.36, 5.0, 4.131293495034893, 4701.847034571434, // 0.5024999976158142 // hard-code some special values not properly converted and found. if (strEQc (g->value, "0.5")) d = 0.5; else if (strEQc (g->value, "10.0")) d = 10.0; else if (strEQc (g->value, "11.0")) d = 11.0; else if (strEQc (g->value, "63.5")) d = 63.5; g->type = BITS_BD; // some more not found BD values for (struct _bd *b = &bd[0]; b->value; b++) { if (strEQ (g->value, b->value)) { bit_write_bits (dat, b->bin); return; } } // sscanf(g->value, "%lf", &d); bit_write_BD (dat, d); } static void bits_angle_BD (Bit_Chain *restrict dat, struct _unknown_field *restrict g) { double d = strtod (g->value, NULL); // sscanf(g->value, "%lf", &d); d = deg2rad (d); bit_write_BD (dat, d); g->type = BITS_BD; } static void bits_RC (Bit_Chain *restrict dat, struct _unknown_field *restrict g) { BITCODE_RC l = (BITCODE_RC)strtol (g->value, NULL, 10); bit_write_RC (dat, l); g->type = BITS_RC; } static void bits_BS (Bit_Chain *restrict dat, struct _unknown_field *restrict g) { BITCODE_BS l = (BITCODE_BS)strtol (g->value, NULL, 10); bit_write_BS (dat, l); g->type = BITS_BS; } static void bits_BL (Bit_Chain *restrict dat, struct _unknown_field *restrict g) { uint32_t l = (uint32_t)strtol (g->value, NULL, 10); bit_write_BL (dat, l); g->type = BITS_BL; } static void bits_BLd (Bit_Chain *restrict dat, struct _unknown_field *restrict g) { int32_t l = (int32_t)strtol (g->value, NULL, 10); bit_write_BLd (dat, l); g->type = BITS_BLd; } static void bits_RS (Bit_Chain *restrict dat, struct _unknown_field *restrict g) { BITCODE_RS l = (BITCODE_RS)strtol (g->value, NULL, 10); bit_write_RS (dat, l); g->type = BITS_RS; } static void bits_RL (Bit_Chain *restrict dat, struct _unknown_field *restrict g) { uint32_t l = (uint32_t)strtol (g->value, NULL, 10); bit_write_RL (dat, l); g->type = BITS_RL; } static void bits_CMC (Bit_Chain *restrict dat, struct _unknown_field *restrict g) { // dat should know if >= R_2004, but we just search for the index (62) // we try ENC on entities, CMC on objects Dwg_Color color; memset (&color, 0, sizeof (color)); color.index = strtol (g->value, NULL, 10); if (dat->version >= R_2004) { // check next g field struct _unknown_field *ng = g + 1; struct _unknown_field *ng2 = g + 2; // TODO: need to detect book_name (flag 2) if (ng->code >= 420 && ng->code < 430) { color.rgb = strtol (ng->value, NULL, 10); if (ng2->code >= 430 && ng2->code < 440) { color.flag |= 0x1; color.name = (char *)ng2->value; ng2++; } } } bit_write_CMC (dat, dat, &color); g->type = BITS_CMC; } // needs to know color.index (62) and color.rgb (421) at least, opt. also alpha // (441) static void bits_ENC (Bit_Chain *restrict dat, struct _unknown_field *restrict g) { // dat should know if >= R_2004, but we just search for the index Dwg_Color color; memset (&color, 0, sizeof (color)); color.index = strtol (g->value, NULL, 10); if (dat->version >= R_2004) { // check next g field struct _unknown_field *ng = g + 1; struct _unknown_field *ng2 = g + 2; if (ng->code >= 420 && ng->code < 430) { color.flag = 0x80; color.rgb = strtol (ng->value, NULL, 10); if (ng2->code >= 430 && ng2->code < 440) { color.flag |= 0x1; color.name = (char *)ng2->value; ng2++; if (ng2->code >= 440 && ng2->code < 450) { color.flag |= 0x20; color.alpha = strtol (ng2->value, NULL, 10); } } else if (ng2->code >= 440 && ng2->code < 450) { color.flag |= 0x20; color.alpha = strtol (ng2->value, NULL, 10); } } else if (ng->code >= 440 && ng->code < 450) { color.flag = 0x20; color.alpha = strtol (ng->value, NULL, 10); } } bit_write_ENC (dat, dat, dat, &color); g->type = BITS_ENC; } static void handle_string (char *restrict dest, const int code, const char *restrict hdl, const long relhandle) { Dwg_Handle handle; // parse hex -> owner handle; sscanf (hdl, "%lX", &handle.value); handle.code = code; if (code > 5) { // relative offset to objhandle switch (code) { case 6: handle.value = 0; break; case 8: handle.value = 0; break; case 0xA: handle.value -= relhandle; break; case 0xC: handle.value = relhandle - handle.value; break; default: break; } } if (handle.value == 0) handle.size = 0; else if (handle.value < 0xff) handle.size = 1; else if (handle.value < 0xffff) handle.size = 2; else if (handle.value < 0xffffff) handle.size = 3; else handle.size = 4; sprintf (dest, FORMAT_H, ARGS_H (handle)); } static void bits_handle (Bit_Chain *restrict dat, struct _unknown_field *restrict g, int code, unsigned int objhandle) { Dwg_Handle handle; // parse hex -> owner handle; sscanf (g->value, "%lX", &handle.value); handle.code = code; cur_hdl = code; if (code > 5) { // relative offset to objhandle switch (code) { case 6: handle.value = 0; break; case 8: handle.value = 0; break; case 0xA: handle.value -= objhandle; break; case 0xC: handle.value = objhandle - handle.value; break; default: break; } } if (handle.value == 0) handle.size = 0; else if (handle.value < 0xff) handle.size = 1; else if (handle.value < 0xffff) handle.size = 2; else if (handle.value < 0xffffff) handle.size = 3; else handle.size = 4; printf (" handle " FORMAT_H " (%X)\n", ARGS_H (handle), objhandle); bit_write_H (dat, &handle); g->type = BITS_HANDLE; } static int is_handle (int code) { return code == 5 || code == 105 || (code >= 320 && code <= 369) || (code >= 390 && code <= 399) || (code >= 480 && code <= 481); } static void bits_try_handle (struct _unknown_field *g, int code, unsigned int objhandle) { Bit_Chain dat = EMPTY_CHAIN (CHAIN_SIZE); dat.chain = calloc (1, CHAIN_SIZE); bits_handle (&dat, g, code, objhandle); g->bytes = dat.chain; g->num_bits = (dat.byte * 8) + dat.bit; } static int dxf_is16 (struct _unknown_dxf *dxf) { return strstr (dxf->dxf, "/2007/") || strstr (dxf->dxf, "_2007.dxf") || strstr (dxf->dxf, "/201") || strstr (dxf->dxf, "_201") ? 1 : 0; } static void bits_format (struct _unknown_field *g, const int version, struct _unknown_dxf *dxf) { int code = g->code; Bit_Chain dat = EMPTY_CHAIN (CHAIN_SIZE); const int is16 = version >= 2007 ? 1 : 0; dat.chain = calloc (1, CHAIN_SIZE); if (version) { char s[16]; sprintf (s, "r%d", version); dat.version = dwg_version_as (s); } if (0 <= code && code < 5) bits_string (&dat, g); else if (code == 5 || code == -5) bits_handle (&dat, g, 0, 0); else if (5 < code && code < 10) // 6 ltype handle or BS index, 7 style handle, 8 layer handle bits_string (&dat, g); else if (code < 50) bits_BD (&dat, g); else if (code < 60) bits_angle_BD (&dat, g); // deg2rad for angles else if (code < 70) { if (dat.version >= R_2004 && dxf->is_entity) bits_ENC (&dat, g); else bits_CMC (&dat, g); } else if (code < 80) if (code == 75 && strEQc (g->name, "ref.has_lastpt_ref")) bits_B (&dat, g); else bits_BS (&dat, g); else if (80 <= code && code <= 99) // BL int32 bits_BL (&dat, g); else if (code == 100) return; else if (code == 102) // this is never stored in a DWG bits_string (&dat, g); else if (code == 105) bits_handle (&dat, g, 3, 0); else if (110 <= code && code <= 149) bits_BD (&dat, g); else if (160 <= code && code <= 169) bits_BL (&dat, g); else if (code <= 179) bits_BS (&dat, g); else if (210 <= code && code <= 239) bits_BD (&dat, g); else if (270 <= code && code <= 289) bits_BS (&dat, g); else if (code <= 299) bits_B (&dat, g); else if (code <= 309) bits_string (&dat, g); else if (code <= 319) bits_hexstring (&dat, g); else if (code >= 320 && code < 360) bits_handle (&dat, g, 4, 0); // 2 or 4 or 3.0 else if (code >= 340 && code < 360) bits_handle (&dat, g, 5, 0); else if (code >= 360 && code <= 369) bits_handle (&dat, g, 3, 0); else if (code <= 389) bits_BS (&dat, g); else if (code <= 399) bits_handle (&dat, g, 5, 0); else if (code <= 409) bits_BS (&dat, g); else if (code <= 419) bits_string (&dat, g); else if (code <= 429) bits_BLd (&dat, g); // int32_t. ignore if after color else if (code <= 439) bits_string (&dat, g); // ignore if after color else if (code <= 449) bits_BLd (&dat, g); // int32_t. ignore if after color else if (code <= 459) bits_BL (&dat, g); // long else if (code <= 469) bits_BD (&dat, g); else if (code <= 479) bits_string (&dat, g); else if (code <= 481) bits_handle (&dat, g, 5, 0); else if (code == 999) ; else if (1000 <= code && code <= 1009) bits_string (&dat, g); else if (1010 <= code && code <= 1049) bits_BD (&dat, g); else if (1050 <= code && code <= 1059) bits_angle_BD (&dat, g); else if (1060 <= code && code <= 1070) bits_BS (&dat, g); else if (code == 1071) bits_BL (&dat, g); // int32_t else fprintf (stderr, "Unknown DXF code %d\n", code); if (g->type) { g->bytes = dat.chain; g->num_bits = (dat.byte * 8) + dat.bit; } else { free (dat.chain); dat.chain = NULL; } } // check how many of the given fields (code=value pairs) exist in the DXF #if 0 static int num_dxf (const struct _unknown_field *g, const struct _unknown_dxf *dxf) { int num_dxf = 0; struct _unknown_field *f = (struct _unknown_field *)dxf->fields; while (f->value) { if (f->code == g->code && strEQ (f->value, g->value)) num_dxf++; f++; } return num_dxf; } #endif static int is_common_entity_data (int dxf) { return dxf == 8 || dxf == 440 || dxf == 420 || dxf == 430 || dxf == 48 || dxf == 284 || dxf == 370; } static int set_found (struct _dxf *dxf, const struct _unknown_field *g) { // check for overlap, if already found by some other field int overlap = 0; if (g->num_bits + g->pos[0] > dxf->num_bits) { fprintf (stderr, "overflow with found group %d %s: %d+%d >= %d\n", g->code, g->name, g->num_bits, g->pos[0], dxf->num_bits); return 1; } for (int k = g->pos[0]; k < g->num_bits + g->pos[0]; k++) { if (dxf->found[k] && !overlap && k < g->num_bits) { overlap = 1; printf ("position %d already found\n", k); } dxf->found[k]++; } return overlap; } static int set_found_i (struct _dxf *dxf, const struct _unknown_field *g, int i) { // check for overlap, if already found by some other field int overlap = 0; if (g->num_bits + g->pos[i] > dxf->num_bits) { fprintf (stderr, "overflow with found group %d %s: %d+%d >= %d\n", g->code, g->name, g->num_bits, g->pos[i], dxf->num_bits); return 1; } for (int k = g->pos[i]; k < g->num_bits + g->pos[i]; k++) { if (dxf->found[k] && !overlap) { overlap = 1; printf ("field %d %s already found at %d\n", g->code, g->name, k); } dxf->found[k]++; } return overlap; } static void set_possible_pos (struct _dxf *dxf, const struct _unknown_field *g, const int pos) { // add coverage counter for each bit if (g->num_bits + pos > dxf->num_bits) { fprintf (stderr, "overflow with possible group %d %s: %d+%d >= %d\n", g->code, g->name, g->num_bits, pos, dxf->num_bits); return; } for (int k = pos; k < g->num_bits + pos; k++) { dxf->possible[k]++; } } #if 0 static void set_possible(struct _dxf *dxf, const struct _unknown_field *g, const int i) { // add coverage counter for each bit for (int j=0; jpos[j]; k < g->num_bits + g->pos[j]; k++) { dxf->possible[k]++; } } } #endif // The i-th bit of a string. See bit_read_B() // 0x1: 10000000,0 >> 8 = 1 #define BIT(b, i) (((b)[(i) / 8] & (0x80 >> (i) % 8)) >> (7 - (i) % 8)) //#define BIT(b,i) (((b)[(i)/8] >> (8-((i)%8))) & 1) // like memmem but for bits, not bytes. // search for the bits of small in big. returns the bit offset in big or -1. // handle bits before and after. static int membits (const unsigned char *restrict big, const int bigsize, const unsigned char *restrict small, const int smallsize, int offset) { int pos = offset; if (smallsize > bigsize) return -1; while (pos + smallsize < bigsize) { int i = 0; while (i < smallsize) { if (BIT (big, pos + i) != BIT (small, i)) break; i++; // found, check next bit } if (i == smallsize) // found all smallsize bits return pos; pos++; } return -1; } static int search_bits (int j, struct _unknown_field *g, struct _unknown_dxf *udxf, struct _dxf *dxf, int offset) { int size; unsigned char *s; unsigned char *found; int num_found = 0; int dxf_num_bits = udxf->num_bits; int dxf_size = dxf_num_bits / 8; if (!g->type || !g->num_bits || !dxf_size) return 0; size = (g->num_bits / 8) + (g->num_bits % 8 ? 1 : 0); dxf_size += (dxf_size % 8 ? 1 : 0); if (size > dxf_size) return 0; s = alloca (size); printf (" search %d bits of type %s [%d] in %d:%d ", g->num_bits, dwg_bits_name[g->type], j, dxf_num_bits - offset, offset); bit_print_bits (g->bytes, g->num_bits); while ((offset = membits ((unsigned char *)udxf->bytes, udxf->num_bits, g->bytes, g->num_bits, offset)) != -1) { if (num_found < 5) // record only the first 5 offsets for the solver g->pos[num_found] = offset; num_found++; set_possible_pos ( dxf, g, offset); // but record all other offsets here as counts 0-255 // if (num_found > 5) // break; offset++; } freea (s); return num_found; } /* Not the same as json_cquote. This is only for C */ static char * cquote (char *restrict dest, const char *restrict src) { char c; char *d = dest; char *s = (char *)src; while ((c = *s++)) { if (c == '"') { *dest++ = '\\'; *dest++ = c; } else if (c == '\\') { *dest++ = '\\'; *dest++ = c; } else *dest++ = c; } *dest = 0; // add final delim, skipped above return d; } static void pi_filename (char *restrict pi_fn, uint16_t i) { if (i) { char tmp[36]; snprintf (tmp, 35, ".%hu", i); tmp[35] = '\0'; strcat (pi_fn, tmp); } strcat (pi_fn, ".pi"); } static int open_pi (FILE *pi, char *restrict class, char *pi_fn) { if (!pi) { fprintf (stderr, "Failed to write %s\n", pi_fn); return 1; } fprintf (pi, "import unknown.\n\n" "/* %s field packing problem.\n" " examples/unknown generated example, needs picat-lang.org.\n" " Usage: picat [-g go2] %s\n" "*/\n", class, pi_fn); return 0; } static void close_pi (FILE *pi, long class_filled, long class_size, int k) { int i; // class_summary fprintf (pi, "\n%% summary: %ld/%ld=%.1f%%\n\n", class_filled, class_size, 100.0 * class_filled / class_size); for (i = 0; i < k; i++) { fprintf (pi, "go%d ?=> def(%d,Data).\n", i, i); } fprintf (pi, "\nmain => go0%s\n", k == 1 ? "." : ","); for (i = 1; i < k; i++) { fprintf (pi, " go%d%s\n", i, i == k - 1 ? "." : ","); } fclose (pi); } int main (int argc, char *argv[]) { unsigned i = 1, ic, j, num_classes = 0; unsigned long sum_filled = 0, sum_size = 0; char *class = NULL; char *file = NULL; #define MAX_CLASSES 200 char *classes[MAX_CLASSES]; // create files per classes struct _dxf *dxf = calloc (sizeof (unknown_dxf) / sizeof (unknown_dxf[0]), sizeof (struct _dxf)); // clang-format off #include "alldxf_2.inc" // clang-format on if (argc > 2 && strEQc (argv[i], "--class")) { class = argv[i + 1]; i = 3; } if (argc - i >= 2 && strEQc (argv[i], "--file")) file = argv[i + 1]; // process per class, not per logged instances. if (!class) { num_classes = 0; for (i = 0; unknown_dxf[i].name; i++) { // TODO: alldwg/alldxf needs to be sorted per class, not file. if (!class || !strEQ (class, unknown_dxf[i].name)) { classes[num_classes++] = (char *)unknown_dxf[i].name; class = (char *)unknown_dxf[i].name; if (num_classes >= MAX_CLASSES) { fprintf (stderr, "Too many classes: %d (unsorted?)\n", MAX_CLASSES); break; } } } } else { num_classes = 1; classes[0] = class; } for (ic = 0; ic < num_classes; ic++) { FILE *pi; char pi_fn[256]; char base_pi_fn[256]; int k = 0; long class_filled = 0, class_size = 0; char *dn; uint16_t i_pi = 0; class = classes[ic]; // dirname should be examples, but can also be examples/.libs dn = dirname (argv[0]); printf ("dirname(%s): %s\n", argv[0], dn); if (dn && strstr (dn, "/examples/.libs")) { size_t l = strlen (dn); strcpy (pi_fn, dn); pi_fn[l - 5] = '\0'; } else if (dn && strEQc (basename (dn), "examples")) { strcpy (pi_fn, dn); strcat (pi_fn, "/"); } else if (strEQc (argv[0], "examples")) { strcpy (pi_fn, "examples/"); } else strcpy (pi_fn, ""); strcat (pi_fn, class); strcpy (base_pi_fn, pi_fn); pi_filename (pi_fn, i_pi); pi = fopen (pi_fn, "w"); if (open_pi (pi, class, pi_fn)) continue; for (i = 0; unknown_dxf[i].name; i++) { unsigned num_fields; unsigned num_found = -1; unsigned size = unknown_dxf[i].num_bits; struct _unknown_field *g = (struct _unknown_field *)unknown_dxf[i].fields; const int is16 = dxf_is16 (&unknown_dxf[i]); int have_struct = 0; int is_dict = 0; int is_react = 0; int version = 0; char *s; if (class && !strEQ (class, unknown_dxf[i].name)) continue; if (file && !strEQ (file, unknown_dxf[i].dxf)) continue; /*if (strEQc (unknown_dxf[i].name, "TABLEGEOMETRY")) { printf("skip TABLEGEOMETRY\n"); continue; }*/ s = strstr (unknown_dxf[i].dxf, "20"); if (s) sscanf (s, "%d", &version); else { s = strstr (unknown_dxf[i].dxf, "_r"); if (s) sscanf (s + 2, "%d", &version); } dxf[i].found = calloc (1, unknown_dxf[i].num_bits + 1); dxf[i].possible = calloc (1, unknown_dxf[i].num_bits + 1); dxf[i].num_bits = unknown_dxf[i].num_bits + 1; // TODO offline: find the shortest objects. printf ("\n%s: 0x%X (%d) %s\n", unknown_dxf[i].name, unknown_dxf[i].handle, size, unknown_dxf[i].dxf); printf (" =bits:\n"); bit_print_bits ((unsigned char *)unknown_dxf[i].bytes, size); fprintf (pi, "def(%d, Data) =>\n" " println(\"%s: 0x%X (%d) %s:\"),\n" " Class=\"%s\",\n" " Dxf=\"%s\",\n" " Version=%d,\n" " Offsets=[%d, %d, %d, %d, %d], %% hdloff, strsize, " "commonsize, bitsize, hdlsize\n", k, class, unknown_dxf[i].handle, size, unknown_dxf[i].dxf, class, unknown_dxf[i].dxf, version, unknown_dxf[i].hdloff, unknown_dxf[i].strsize, unknown_dxf[i].commonsize, unknown_dxf[i].bitsize, unknown_dxf[i].hdlsize); fprintf (pi, " S=\""); bit_fprint_bits (pi, (unsigned char *)unknown_dxf[i].bytes, size); fprintf (pi, "\",\n" " %% name: [1] bits, [2] value, [3] poslist, [4] " "fieldname, [5] dxfcode\n" " Fields = [\n"); for (j = 0; g[j].code; j++) { char *piname; int offset = 0; printf ("%d: %s\n", g[j].code, g[j].value); if (g[j].code == 102) { if (strEQc (g[j].value, "{ACAD_XDICTIONARY")) is_dict = 1; else if (strEQc (g[j].value, "{ACAD_REACTORS")) is_react = 1; else if (strEQc (g[j].value, "}")) { is_react = 0; is_dict = 0; } continue; } if (g[j].code == 100 || g[j].code >= 1000) { continue; } // if we came here from continue, i.e. not_found // store the binary repr bits_format (&g[j], version, &unknown_dxf[i]); SEARCH: // searching for it in the stream and store found position if // found only once num_found = search_bits (j, &g[j], &unknown_dxf[i], &dxf[i], offset); if (!num_found) { // try alternate formats than the standard one from // bits_format: int code = g[j].code; if (is_handle (code) && code != 5) { int handles[] = { 2, 3, 4, 5, 6, 8, 0xa, 0xc }; unsigned int hdl; int cur_code = cur_hdl; sscanf (g[j].value, "%X", &hdl); // for 330 start with 6 (relative reactors) for (int c = code == 330 ? 4 : 0; c < 8; c++) { if (handles[c] == cur_code) continue; if (handles[c] == 6 && hdl != unknown_dxf[i].handle + 1) //+1 continue; if (handles[c] == 8 && hdl != unknown_dxf[i].handle - 1) //-1 continue; if (handles[c] == 0xa && hdl < unknown_dxf[i].handle) //> continue; if (handles[c] == 0xc && hdl > unknown_dxf[i].handle) //< continue; bits_try_handle (&g[j], handles[c], unknown_dxf[i].handle); num_found = search_bits (j, &g[j], &unknown_dxf[i], &dxf[i], offset); if (num_found) { // cur_hdl is set // sprintf(&g[j].value, "%x..%X", handles[c], // hdl); goto FOUND; } } } if (g[j].type == BITS_ENC) { Bit_Chain dat = EMPTY_CHAIN (CHAIN_SIZE); dat.chain = calloc (1, CHAIN_SIZE); bits_CMC (&dat, &g[j]); g[j].bytes = dat.chain; g[j].num_bits = (dat.byte * 8) + dat.bit; num_found = search_bits (j, &g[j], &unknown_dxf[i], &dxf[i], offset); if (num_found) goto FOUND; } if (g[j].type == BITS_BS && strlen (g[j].value) < 3) { Bit_Chain dat = EMPTY_CHAIN (CHAIN_SIZE); dat.chain = calloc (1, CHAIN_SIZE); bits_RC (&dat, &g[j]); g[j].bytes = dat.chain; g[j].num_bits = (dat.byte * 8) + dat.bit; num_found = search_bits (j, &g[j], &unknown_dxf[i], &dxf[i], offset); if (num_found) goto FOUND; } if (g[j].type == BITS_BS) { Bit_Chain dat = EMPTY_CHAIN (CHAIN_SIZE); dat.chain = calloc (1, CHAIN_SIZE); bits_BL (&dat, &g[j]); g[j].bytes = dat.chain; g[j].num_bits = (dat.byte * 8) + dat.bit; num_found = search_bits (j, &g[j], &unknown_dxf[i], &dxf[i], offset); if (num_found) goto FOUND; bit_set_position (&dat, 0); bits_RS (&dat, &g[j]); g[j].bytes = dat.chain; g[j].num_bits = (dat.byte * 8) + dat.bit; num_found = search_bits (j, &g[j], &unknown_dxf[i], &dxf[i], offset); if (num_found) goto FOUND; } if ((g[j].type == BITS_BL || g[j].type == BITS_BLd) && strlen (g[j].value) <= 5) { Bit_Chain dat = EMPTY_CHAIN (CHAIN_SIZE); dat.chain = calloc (1, CHAIN_SIZE); bits_BS (&dat, &g[j]); g[j].bytes = dat.chain; g[j].num_bits = (dat.byte * 8) + dat.bit; num_found = search_bits (j, &g[j], &unknown_dxf[i], &dxf[i], offset); if (num_found) goto FOUND; bit_set_position (&dat, 0); bits_RL (&dat, &g[j]); g[j].bytes = dat.chain; g[j].num_bits = (dat.byte * 8) + dat.bit; num_found = search_bits (j, &g[j], &unknown_dxf[i], &dxf[i], offset); if (num_found) goto FOUND; } if (g[j].type == BITS_RC) { Bit_Chain dat = EMPTY_CHAIN (CHAIN_SIZE); dat.chain = calloc (1, CHAIN_SIZE); bits_BS (&dat, &g[j]); g[j].bytes = dat.chain; g[j].num_bits = (dat.byte * 8) + dat.bit; num_found = search_bits (j, &g[j], &unknown_dxf[i], &dxf[i], offset); if (num_found) goto FOUND; } if (g[j].type == BITS_BD) { Bit_Chain dat = EMPTY_CHAIN (CHAIN_SIZE); dat.chain = calloc (1, CHAIN_SIZE); bits_RD (&dat, &g[j]); g[j].bytes = dat.chain; g[j].num_bits = (dat.byte * 8) + dat.bit; num_found = search_bits (j, &g[j], &unknown_dxf[i], &dxf[i], offset); if (num_found) goto FOUND; } // relaxed BD search, less mantissa precision. // e.g. 49:"0.0008202099737533" (66 bits of type BD) // 52 -> 44 bit if (g[j].type == BITS_RD && strlen (g[j].value) >= 3) { double d; Bit_Chain dat = EMPTY_CHAIN (CHAIN_SIZE); dat.chain = calloc (1, CHAIN_SIZE); bits_BD (&dat, &g[j]); // g.value -> dat g[j].bytes = dat.chain; if (dat.byte == 8) g[j].num_bits = 58; // from 66 else goto FOUND; // print rounded found value and show bit diff printf ( " imprecise BD search, 42bit mantissa precision\n"); num_found = search_bits (j, &g[j], &unknown_dxf[i], &dxf[i], offset); if (num_found) { free (dat.chain); dat.chain = (unsigned char *)unknown_dxf[i].bytes; g[j].bytes = dat.chain; dat.size = unknown_dxf[i].num_bits / 8; bit_set_position (&dat, g[j].pos[0]); d = bit_read_BD (&dat); if (fabs (d - strtod (g[j].value, NULL)) < 0.001) { printf (" found imprecise %f value (42bit)\n", d); goto FOUND; } else { printf (" result too imprecise %f (42bit)\n", d); } } else { g[j].num_bits = 54; // from 66 // printf(" more imprecise BD search, 38bit mantissa // precision\n"); num_found = search_bits (j, &g[j], &unknown_dxf[i], &dxf[i], offset); if (num_found) { free (dat.chain); dat.chain = (unsigned char *)unknown_dxf[i].bytes; g[j].bytes = dat.chain; dat.size = unknown_dxf[i].num_bits / 8; bit_set_position (&dat, g[j].pos[0]); d = bit_read_BD (&dat); if (fabs (d - strtod (g[j].value, NULL)) < 0.001) { printf (" found imprecise BD %f value " "(38bit)\n", d); goto FOUND; } else { printf ( " result too imprecise BD (38bit)\n"); } } } } // ditto relaxed RD search, without the BB prefix if (g[j].type == BITS_RD && strlen (g[j].value) >= 3) { double d; Bit_Chain dat = EMPTY_CHAIN (CHAIN_SIZE); dat.chain = calloc (1, CHAIN_SIZE); bits_RD (&dat, &g[j]); // g.value -> dat g[j].bytes = dat.chain; if (dat.byte == 8) g[j].num_bits = 56; // from 64 else goto FOUND; // print rounded found value and show bit diff printf ( " imprecise RD search, 42bit mantissa precision\n"); num_found = search_bits (j, &g[j], &unknown_dxf[i], &dxf[i], offset); if (num_found) { free (dat.chain); dat.chain = (unsigned char *)unknown_dxf[i].bytes; dat.size = unknown_dxf[i].num_bits / 8; bit_set_position (&dat, g[j].pos[0]); d = bit_read_BD (&dat); if (fabs (d - strtod (g[j].value, NULL)) < 0.001) { printf ( " found imprecise RD %f value (42bit)\n", d); goto FOUND; } else { printf (" result too imprecise RD %f (42bit)\n", d); } } else { g[j].num_bits = 52; // from 64 // printf(" more imprecise RD search, 38bit mantissa // precision\n"); num_found = search_bits (j, &g[j], &unknown_dxf[i], &dxf[i], offset); if (num_found) { free (dat.chain); dat.chain = (unsigned char *)unknown_dxf[i].bytes; dat.size = unknown_dxf[i].num_bits / 8; bit_set_position (&dat, g[j].pos[0]); d = bit_read_BD (&dat); if (fabs (d - strtod (g[j].value, NULL)) < 0.001) { printf (" found imprecise RD %f value " "(38bit)\n", d); goto FOUND; } else { printf ( " result too imprecise RD %f (38bit)\n", d); } } } } // TU not found, try TV (unsuccessful) or TF (wrong len?) // the length usually includes the final \0 if (g[j].type == BITS_TV || g[j].type == BITS_TU) { Bit_Chain dat = EMPTY_CHAIN (CHAIN_SIZE); int len = strlen (g[j].value); dat.chain = calloc (1, CHAIN_SIZE); #if 0 /* TU/TF cannot be mixed */ if (is16) { bits_TV (&dat, &g[j]); g[j].bytes = dat.chain; g[j].num_bits = (dat.byte * 8) + dat.bit; num_found = search_bits (j, &g[j], &unknown_dxf[i], &dxf[i], offset); if (num_found) goto FOUND; } #endif if (len) { bit_set_position (&dat, 0); // search without the final \0 bits_TF (&dat, &g[j], len); g[j].bytes = dat.chain; g[j].num_bits = (dat.byte * 8) + dat.bit; num_found = search_bits (j, &g[j], &unknown_dxf[i], &dxf[i], offset); if (num_found) goto FOUND; } } if (!num_found || is_common_entity_data (g[j].code)) { piname = (char *)dwg_bits_name[g[j].type]; if (strEQc (piname, "HANDLE")) piname = (char *)"H"; // unfound DXF field for the picat file. // later could be used as hints for the picat solver fprintf (pi, " %%new_struct('_%s%d', [\"", piname, g[j].code); bit_fprint_bits (pi, g[j].bytes, g[j].num_bits); if (g[j].type == BITS_HANDLE) { char buf[32]; handle_string (buf, cur_hdl, g[j].value, unknown_dxf[i].handle); fprintf (pi, "\", '%s', [], \"%s\", %d])\n", buf, g[j].name, g[j].code); } else if ((g[j].type == BITS_TV || g[j].type == BITS_TU || g[j].type == BITS_TF) && strchr (g[j].value, '\\')) { char *buf = alloca (2 * strlen (g[j].value)); fprintf (pi, "\", \"%s\", [], \"%s\", %d])\n", cquote (buf, g[j].value), g[j].name, g[j].code); freea (buf); } else { fprintf (pi, "\", '%s', [], \"%s\", %d])\n", g[j].value, g[j].name, g[j].code); } } continue; } FOUND: piname = (char *)dwg_bits_name[g[j].type]; if (g[j].type == BITS_HANDLE) piname = (char *)"H"; fprintf (pi, " %snew_struct('%s%d', [\"", have_struct ? "," : " ", piname, g[j].code); have_struct = 1; bit_fprint_bits (pi, g[j].bytes, g[j].num_bits); if (g[j].type == BITS_HANDLE) { char buf[32]; // reactors or xdict? handle_string (buf, cur_hdl, g[j].value, unknown_dxf[i].handle); fprintf (pi, "\", '%s', [], \"%s\", %d])\n", buf, g[j].name, g[j].code); } /* i.e. if string value contains \ */ else if ((g[j].type == BITS_TV || g[j].type == BITS_TU || g[j].type == BITS_TF) && strchr (g[j].value, '\\')) { char *buf = alloca (2 * strlen (g[j].value)); fprintf (pi, "\", \"%s\", [], \"%s\", %d])\n", cquote (buf, g[j].value), g[j].name, g[j].code); freea (buf); } else { fprintf (pi, "\", '%s', [], \"%s\", %d])\n", g[j].value, g[j].name, g[j].code); } if (num_found == 1) { // we still need to skip already reserved offsets if (set_found (&dxf[i], &g[j])) { offset = g[j].pos[0] + 1; goto SEARCH; } printf ("+ %d: %s [%s] found 1 at offset %d-%d /%d\n", g[j].code, g[j].value, dwg_bits_name[g[j].type], g[j].pos[0], g[j].pos[0] + g[j].num_bits - 1, size); if (g[j].num > 1) printf (" but we have %d same DXF fields\n", g[j].num); else dxf[i].num_filled += g[j].num_bits; } else if (num_found == 2) { printf ( "%s %d: %s [%s] found 2 at offsets %d-%d, %d-%d /%d\n", 2 == g[j].num ? "+" : "?", g[j].code, g[j].value, dwg_bits_name[g[j].type], g[j].pos[0], g[j].pos[0] + g[j].num_bits - 1, g[j].pos[1], g[j].pos[1] + g[j].num_bits - 1, size); // check if we have two of those fields, then it's unique // also if (2 == g[j].num) { printf (" and we have %d same DXF fields\n", 2); set_found (&dxf[i], &g[j]); set_found_i (&dxf[i], &g[j], 1); dxf[i].num_filled += g[j].num_bits; } else if (g[j].num > 1) { printf (" but we have %d same DXF fields\n", g[j].num); } } else if (num_found == 3) { printf ( "%s %d: %s [%s] found 3 at offsets %d-%d, %d, %d /%d\n", 3 == g[j].num ? "+" : "?", g[j].code, g[j].value, dwg_bits_name[g[j].type], g[j].pos[0], g[j].pos[0] + g[j].num_bits - 1, g[j].pos[1], g[j].pos[2], size); if (3 == g[j].num) { printf (" and we have %d same DXF fields\n", 3); set_found (&dxf[i], &g[j]); set_found_i (&dxf[i], &g[j], 1); set_found_i (&dxf[i], &g[j], 2); dxf[i].num_filled += g[j].num_bits; } else if (g[j].num > 1) { printf (" but we have %d same DXF fields\n", g[j].num); } } else if (num_found == 4) { printf ("%s %d: %s [%s] found 4 at offsets %d-%d, %d, %d, " "%d /%d\n", 4 == g[j].num ? "+" : "?", g[j].code, g[j].value, dwg_bits_name[g[j].type], g[j].pos[0], g[j].pos[0] + g[j].num_bits - 1, g[j].pos[1], g[j].pos[2], g[j].pos[3], size); if (4 == g[j].num) { printf (" and we have %d same DXF fields\n", 4); set_found (&dxf[i], &g[j]); set_found_i (&dxf[i], &g[j], 1); set_found_i (&dxf[i], &g[j], 2); set_found_i (&dxf[i], &g[j], 3); dxf[i].num_filled += g[j].num_bits; } else if (g[j].num > 1) { printf (" but we have %d same DXF fields\n", g[j].num); } } else if (num_found == 5) { printf ("%s %d: %s [%s] found 5 at offsets %d-%d, %d, %d, " "%d, %d /%d\n", 5 == g[j].num ? "+" : "?", g[j].code, g[j].value, dwg_bits_name[g[j].type], g[j].pos[0], g[j].pos[0] + g[j].num_bits - 1, g[j].pos[1], g[j].pos[2], g[j].pos[3], g[j].pos[4], size); if (5 == g[j].num) { printf (" and we have %d same DXF fields\n", 5); set_found (&dxf[i], &g[j]); set_found_i (&dxf[i], &g[j], 1); set_found_i (&dxf[i], &g[j], 2); set_found_i (&dxf[i], &g[j], 3); set_found_i (&dxf[i], &g[j], 4); dxf[i].num_filled += g[j].num_bits; } else if (g[j].num > 1) { printf (" but we have %d same DXF fields\n", g[j].num); } } else if (num_found > 5 && num_found == g[j].num) { printf ("? %d: %s [%s] found %d at offsets %d-%d, %d, %d, " "%d, %d, ... /%d\n", g[j].code, g[j].value, dwg_bits_name[g[j].type], num_found, g[j].pos[0], g[j].pos[0] + g[j].num_bits - 1, g[j].pos[1], g[j].pos[2], g[j].pos[3], g[j].pos[4], size); printf (" and we have %d same DXF fields\n", num_found); set_found (&dxf[i], &g[j]); set_found_i (&dxf[i], &g[j], 1); set_found_i (&dxf[i], &g[j], 2); set_found_i (&dxf[i], &g[j], 3); set_found_i (&dxf[i], &g[j], 4); dxf[i].num_filled += g[j].num_bits; } else if (num_found > 5) { printf ("? %d: %s [%s] found %d >5 at offsets %d-%d, %d, " "%d, %d, %d, ... /%d\n", g[j].code, g[j].value, dwg_bits_name[g[j].type], num_found, g[j].pos[0], g[j].pos[0] + g[j].num_bits - 1, g[j].pos[1], g[j].pos[2], g[j].pos[3], g[j].pos[4], size); if (g[j].num > 1) printf (" but we have %d same DXF fields\n", g[j].num); } // same pos, search for next. but only if it's a bigger hit, not // just 1-2 bits /*if (num_found >= 1 && g->num_bits > 2 && set_found(&dxf[i], &g[j])) { offset = g[j].pos[0]+1; goto SEARCH; } */ if (0) { free (g[j].bytes); g[j].bytes = NULL; } } fprintf (pi, " ],\n" " Data = [S,Fields,Class,Dxf,Version,Offsets],\n" " go(Data).\n\n"); num_fields = j; // check for holes and percentage of found ranges /*printf("coverage: ["); for (j=0; j 1 (BLxxxxxx) printf ("x"); } else if (dxf[i].possible[j]) { dxf[i].num_possible++; printf ("%c", dxf[i].possible[j] >= 10 ? '.' : dxf[i].possible[j] + '0'); } else { printf (" "); } } printf ("]\n"); // TODO: try likely field combinations and print the top 3. // See unknown.pi // there are various heuristics, like the handle and string stream at // the end. points BD's being neighbors, ... free (dxf[i].found); free (dxf[i].possible); k++; if (k >= 50) { strcpy (pi_fn, base_pi_fn); pi_filename (pi_fn, ++i_pi); close_pi (pi, class_filled, class_size, k); k = 0; pi = fopen (pi_fn, "w"); if (open_pi (pi, class, pi_fn)) continue; } } close_pi (pi, class_filled, class_size, k); } printf ("summary: %ld/%ld=%.2f%%\n", sum_filled, sum_size, 100.0 * sum_filled / sum_size); return 0; }