/*****************************************************************************/
/* 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;
}