A number of CAD vendors have decided to form the "http://www.opendwg.org/" OpenDWG Alliance, which aims at making the DWG format available to everybody who joins them.
typedef word word := byte : b1, byte : b2 return (word)f | ((word)s << 8). typedef longword longp := byte : b1, byte : b2, byte : b3, byte : b4 return (longword)b1 | ((longword)b2 << 8) | ((longword)b3 << 16) | ((longword)b4 << 24). typedef longword longword := byte : b1, byte : b2, byte : b3, byte : b4 return (longword)b1 | ((longword)b2 << 8) | ((longword)b3 << 16) | ((longword)b4 << 24).
root dwg_file := [begin : end]( char[12] : version, byte, word, word, word, byte, longp : p_entities, longp : p_entend, longp : p_blocksec, byte[4], longp : p_bsend, byte[4], tablepos : block_table, tablepos : layer_table, tablepos : style_table, tablepos : ltype_table, tablepos : view_table, header, [cur : 0x3EF]byte*, tablepos : ucs_table, [cur : 0x500]byte*, tablepos : vport_table, byte[8], tablepos : appid_table, byte[6], tablepos : dimstyle_table, [cur : 0x69F]byte*, tablepos : p13_table, bytes[38], [p_entities : p_entend]entities : ents, byte[19], [block_table.start : ]blocks : block_table, [layer_table.start : ]layers : layer_table, [style_table.start : ]styles : style_table, [ltype_table.start : ]ltypes : ltype_table, [view_table.start : ]table : view_table, [ucs_table.start : ]table : ucs_table, [vport_table.start : vport_table.end]table : vport_table, [appid_table.start : ]appids : appid_table, [dimstyle_table.start : ]table : dimstyle_table, [p13_table.start : ]table : p13_table, [p_blocksec : p_bsend]entities : blocks, bytes[36], longp = p_entities, longp = p_entend, longp = blocksec, longp = bsend, bytes[12], bytes[6], longp = block_table.start, bytes[6], longp = layer_table.start, bytes[6], longp = style_table.start, bytes[6], longp = ltype_table.start, bytes[6] longp = view_table.start, bytes[6], longp = ucs_table.start, bytes[6], longp = vport_table.start, bytes[6], longp = appid_table.start, bytes[6], longp = dimstyle_table.start, bytes[6], longp = p13_table.start, bytes[6], longp bytes*, ).
tablepos := word : size, long : nr, long : start,
header := word, point(TRUE) : inbase, point(TRUE) : extmin, point(TRUE) : extmax, point(FALSE) : limmin, point(FALSE) : limmax, double[4], byte[2], double[2], byte[56], double[3], byte[18], double .
blocks := ( [size]( byte : flag, char[32] : name, word : used, byte, word, byte, word, check_2 ) )[nr] : blocks_info, check_32. check_2 := byte[2]. check_32 := byte[32].
layers := ( [size]( byte : flag, char[32] : name, word : used, word : color, word : style, check_2 ) )[nr] : layer_info, check_32.
styles := ( [size]( byte : flag, char[32] : name, word, double[3], byte, double, char[128], check_2 ) )[nr] : style_info, check_32.
ltypes := ( [size]( byte : flag, char[32] : name, word, char[48], byte, byte, double[13], check_2 ) )[nr] : ltype_info, check_32 .
appids := ( [size]( byte : flag, char[32] : name, word, check_2 ) )[nr] : appid_info, check_32 .
table := ( [size]( byte : flag, [size - 3]byte*, check_2 ) )[nr], check_32 .
entities := ( byte : kind, byte : flag, word : length, [length - 4]( word : layer, word : opts, if (flag & 1) then byte : color else color = 0 fi, if (flag & 0x40) then byte : extra else extra = 0 fi, if (extra & 2) then xdata fi, if (flag & 2) then word : type fi, if (flag & 4 && kind > 2 && kind != 22) then double : z fi, if (flag & 8) then double : th fi, if (flag & 0x20) then handle fi, if (extra & 4) then word : paper fi, switch (kind) case 1: /* LINE */ point(!(flag & 4)) : l10, point(!(flag & 4)) : l11, if (opts & 1) then point(TRUE) : l210 fi, if (opts & 2) then double : l38 fi, case 2: /* POINT */ point(!(flag & 4)) : l10, if (opts & 1) then point(TRUE) : l210 fi, if (opts & 2) then double : l38 fi, case 3: /* CIRCLE */ point(FALSE) : l10, double : l40, if (opts & 1) then point(TRUE) : l210 fi, if (opts & 2) then double : l38 fi, case 4: /* SHAPE */ point(FALSE) : l10, word : l2, if (opts & 1) then point(TRUE) : l210 fi, if (opts & 2) then double : l38 fi, case 7: /* TEXT */ point(FALSE) : l10, double : l40, string : l1, if (opts & 1) then double : l50 fi, if (opts & 2) then double : l41 fi, if (opts & 4) then double : l51 fi, /*?*/ if (opts & 8) then byte : l7 fi, if (opts & 0x10) then byte : l71 fi, if (opts & 0x20) then byte : l72 fi, if (opts & 0x40) then point(FALSE) : l11 fi, if (opts & 0x100) then byte : l73 fi, case 8: /* ARC */ point(FALSE) : l10, double : l40, double : l50, double : l51, if (opts & 1) then point(TRUE) : l210 fi, if (opts & 2) then double : l38 fi, case 9: /* TRACE */ point(FALSE) : l10, point(FALSE) : l11, point(FALSE) : l12, point(FALSE) : l13, if (opts & 1) then point(TRUE) : l210 fi, if (opts & 2) then double : l38 fi, case 11: /* SOLID */ point(FALSE) : l11, point(FALSE) : l12, point(FALSE) : l13, point(FALSE) : l14, if (opts & 1) then point(TRUE) : l210 fi, if (opts & 2) then double : l38 fi case 12: /* BLOCK */ point(FALSE) : l10, /*?*/ string : l1, /* if (opts & 1) then ? */ if (opts & 2) then string : l3 fi case 13: /* ENDBLK */ case 14: /* INSERT */ word : l1, point(FALSE) : l10, if (opts & 1) then double : l41 fi, if (opts & 2) then double : l42 fi, if (opts & 4) then double : l43 fi, if (opts & 8) then double : l50 fi, if (opts & 0x10) then word : l70 fi, if (opts & 0x20) then word : l71 fi, if (opts & 0x40) then double : l44 fi, /*?*/ if (opts & 0x80) then double : l45 fi /*?*/ case 15: /* ATTDEF */ point(FALSE) : l10, double : l40, string : l1, string : l3, string : l2, byte : l70, if (opts & 1) then byte : l73 fi, /*?*/ if (opts & 2) then double : l50 fi, /*?*/ if (opts & 4) then double : l41 fi, if (opts & 8) then double : l42 fi, if (opts & 0x10) then byte : l7 fi, if (opts & 0x20) then byte : l71 fi, if (opts & 0x40) then byte : l72 fi, if (opts & 0x80) then point(FALSE) : l11 fi, /*?*/ if (opts & 0x100) then point(TRUE) : l210 fi, if (opts & 0x200) then double : l38 fi /*?*/ case 16: /* ATTRIB */ point(FALSE) : l10, double : l40, string : l1, string : l2, byte : l70, if (opts & 1) then byte : l73 fi, /*?*/ if (opts & 2) then double : l50 fi, /*?*/ if (opts & 4) then double : l41 fi, if (opts & 8) then double : l42 fi, if (opts & 0x10) then byte : l7 fi, if (opts & 0x20) then byte : l71 fi, if (opts & 0x40) then byte : l72 fi, if (opts & 0x80) then point(FALSE) : l11 fi, /*?*/ if (opts & 0x100) then point(TRUE) : l210 fi, if (opts & 0x200) then double : l38 fi /*?*/ case 17: /* S/BEND */ long case 19: /* PLINE */ if (opts & 1) then byte : l70 fi, if (opts & 2) then double : l40 fi, /*?*/ if (opts & 4) then byte : l71 fi, /*?*/ if (opts & 8) then byte : l72 fi, /*?*/ if (opts & 0x10) then byte : l73 fi, /*?*/ if (opts & 0x20) then byte : l74 fi, /*?*/ if (opts & 0x40) then byte : l75 fi /*?*/ case 20: /* VERTEX */ point(FALSE) : l10, if (opts & 1) then double : l40 fi, /*?*/ if (opts & 2) then double : l41 fi, /*?*/ if (opts & 4) then byte : l70 fi, /*?*/ if (opts & 8) then double : l50 fi /*?*/ case 22: /* 3DFACE */ point(!(flag & 4)) : l10, point(!(flag & 4)) : l11, point(!(flag & 4)) : l12, point(!(flag & 4)) : l13 case 23: /* DIM */ word : l1, point(TRUE) : l10, point(FALSE) : l11, /*?*/ if (opts & 2) then byte : l70 fi, if (opts & 1) then point(TRUE) : l12 fi, /*?*/ if (opts & 4) then string : l1 fi, if (opts & 8) then point(TRUE) : l13 fi, if (opts & 0x10) then point(TRUE) : l14 fi, if (opts & 0x20) then point(TRUE) : l15 fi, if (opts & 0x40) then point(TRUE) : l16 fi, if (opts & 0x80) then double : l40 fi, if (opts & 0x100) then double : l50 fi, if (opts & 0x200) then double : l51 fi, if (opts & 0x400) then double : l52 fi, if (opts & 0x800) then double : l53 fi case 24: /* VPORT */ point(TRUE) : l10, double : l40, double : l41, word : l68 endswitch check_2 ) )* : entities.Still need to define xdata and handle.
In this page such a grammar, named BFF, is described. It has several construct that are not traditionally found in context free grammars for programming language. Due to the nature of binary file formats, it is important to be able to reference information that has been read before. For example, a string of characters might be preceded by a number that indicates the lengt of the string.
The terminal symbols of the grammar consist of a number of bytes, representing one of the basic data types, such as: char, short int, long int, float and double. Differences in byte ordering for integers, and the different formats for floating point numbers should be taken into account.
Due to the nature of binary formats, it is not too restrictive to use only recursive descent grammars, e.i., grammars that can be parsed top-down, and belong to the LL(1) class.
The BFF is tested for the DWG file format. As we start with this file format, BFF will naturally first focus on the requirements based on this format, and because of this it will be slightly biased.
To specify the grammar of BFF we will use a form of extended BNF.
This tool should also support the reverse engineering of binary file formats.
In a later state, a tool could be made that generates a parser and the needed data structures for reading a binary file into memory according to the grammar. As it is not always required (nor possible) to read the whole file into memory, it should be possible to generate procedures to read the file interactively.
type word := byte : first, byte : second return ((word)first | ((word)second << 8)).A word representation where the lower order byte comes before the higher order is usually used by small Endian processors. The expression used on will be based on C. We assume that the following types have been defined on top of the default types of C:
typedef unsigned char byte; typedef unsigned short int word; typedef unsigned long int longword;This leeds us to the definition of the basic types that will be supported:
C_data_types := "char" | "byte" | "short" | "word" | "long" | "longword" | "float" | "double" .(We assume for the moment that float and double represent floating numbers of 4, respectively 10 bytes.) The grammar of the rule used for defining types is:
type_def_rule := "typedef" C_data_type basic_type_name ":=" ("byte" ":" byte_name) LIST "return" expr "." .Here expr stands for C-like expression using the byte_names as they are used in the rule. The basic_type_names should not be confused with the C_type_names. It is possible that the same name is both used as a basic_type_name and a C_type_name.
BFF_grammar := type_def_rule SEQ "root" rule rule SEQ.Each rule has a non-terminal symbol on the left-hand side, and a list of elements on the right-hand side. Each element is either a elementary element, a non-terminal symbol, or a grouping of elements. Because BFF assumes a top-down parsing method, it is possible to give each non-terminal symbol a number of parameters. This leads to the following grammar for the rules:
rule := non_term_name ( "(" param LIST ")" )OPT ":=" elem LIST ".".Each element consist of the following parts:
elem := range OPT data_type ( "[" expr "]" | "*" ) ( ":" elem_name )OPT ( "=" C_expr )OPT. range := "[" file_pos (":" file_pos)OPT "]". file_pos := "begin" | "end" | "cur" | expr. data_type := "(" elem LIST ")" | basic_type_name | non_term_name ( "(" expr LIST ")" )OPT.
/* Scan DWG program -- for scanning a DWG file Copyright (C) 1995, 1996 Frans Faase, Reini Urban This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. Authors: Frans Faase, Reini Urban, rurban at sbox.tu-graz.ac.at Contributions by: Stan Hunkins, shunkins@msn.com GNU General Public License: http://home.wxs.nl/~faase009/GNU.txt */ /*-----------------22.10.95 22:59------------------- changed by Reini Urban: new features: Julian dates formatted DIMSTYLE Table section (former P12) VIEW Table section (former P8) UCS Table section (former P9) VPORT Table section found some header vars from the active VPORT at scan_header() changed ADS to APPID in table section group 3 in BLOCK entity with opt 2 for debugging: defined POINTER_VALUE changed all pointer output from long to hex "%ld" -> "%05lX" (for my hex editor) added output of pointer values to some functions in []: echo_16_bytes(), get_pointer() moved rest of header to scan_header() comment: somewhere the last handle must be stored, (only in the DWG, not in the DXF) missing flags opts: 01 01 PLINE 01 01 VERTEX 01 S/BEND 40 INSERT --------------------------------------------------*/ #include <stdio.h> #include <string.h> #include <malloc.h> #include <time.h> #include <math.h> #define TRUE 1 #define FALSE 0 #define DEBUG_P(X) printf X #define MIN(x,y) ((x) < (y) ? (x) : (y)) typedef unsigned char byte; typedef unsigned int word; typedef unsigned long int longword; typedef int bool; #define POINTER_VALUE longword cur_pos, last_pos; typedef struct { longword start, nr; word size; } ttable, *ptable; /* prototypes: */ int main(int argc, char *argv[]); void scan_table_position(char *name, ptable pt); void check_table_pos(char *name, ptable pt, int t_nr); void scan_header(void); void scan_blocks(ptable pt); void scan_layers(ptable pt); void scan_styles(ptable pt); void scan_ltypes(ptable pt); void scan_ads_table(ptable pt); /* new name */ void scan_ucs_table(char *name, ptable pt); void scan_view_table(char *name, ptable pt); void scan_vport_table(char *name, ptable pt); void scan_dim_table(ptable pt); void scan_table(char *name, ptable pt); void scan_entities(longword start, longword endi, longword sce_offset); void scan_xdata(void); void scan_handle(void); void scan_point(bool z_coord); void scan_fixed_ident(int len); void echo_16_bytes(word len); void echo_bytes(long int len); longword get_pointer(); void check_pointer(longword p); void get_check_2(void); void get_check_32(void); void skip_to_check_2(longword p); void goto_pointer(longword p); /* fio prototypes: */ void _assign(FILE *file); longword _tell(void); void _seek(long int pos); void _advance(word steps); bool _eof(void); byte _read_byte(void); short _read_word(void); longword _read_long(void); double _read_date(void); float _read_float(); double _read_double(void); char *_read_string(void); char *_read_fixed_string(int len); /*-----------------25.10.95 21:47------------------- conversion from julian date to string --------------------------------------------------*/ char *date_string (char *s, double date); longword pointer[20]; #define P_ENTITIES 0 #define P_ENTEND 1 #define P_BLOCKSEC 2 #define P_BSEND 3 ttable table[11]; /*-----------------22.10.95 00:56------------------- missing tables VIEW, UCS, VPORT added */ #define T_BLOCK 1 #define T_LAYER 2 #define T_STYLE 3 #define T_LTYPE 4 #define T_VIEW 5 /* changed */ #define T_UCS 6 /* changed */ #define T_VPORT 7 #define T_APPID 8 /* APPID section */ #define T_DIMSTYLE 9 #define T_13 10 static bool version_13 = FALSE; int main(int argc, char *argv[]) { char version[13]; { char *file1 = NULL; word i; bool error = FALSE; FILE *f; for (i = 1; i < argc && !error ; i++) { if (argv[i][0] == '/') { printf("No options"); error = TRUE; } else if (file1 == NULL) file1 = argv[i]; else { printf("dwg: too many arguments\n\n"); error = TRUE; } } if (!error && file1 == NULL) { printf("dwg: too few arguments.\n\n"); error = TRUE; } if (error) { printf("Usages: dwg file1\n"); return 2; } if (!(f = fopen(file1, "rb"))) { printf("dwg: cannot open %s - No such file\n", file1); return 2; } _assign(f); } strcpy(version, _read_fixed_string(12)); DEBUG_P(("Version: %s", version)); version_13 = !strcmp(version, "AC1010"); { int b1 = _read_byte(), w1 = _read_word(), w2 = _read_word(), w3 = _read_word(), b2 = _read_byte(); DEBUG_P((" %d %d %d %d %d\n", b1, w1, w2, w3, b2)); } pointer[P_ENTITIES] = _read_long(); pointer[P_ENTEND] = _read_long(); DEBUG_P(("ENTITIES (%05lX-%05lX)\n", pointer[P_ENTITIES], pointer[P_ENTEND])); DEBUG_P(("BLOCK SECTION ")); pointer[P_BLOCKSEC] = get_pointer(); echo_bytes(4); pointer[P_BSEND] = get_pointer(); echo_bytes(4); DEBUG_P(("\n")); DEBUG_P(("BSEC (%05lX-%05lX)\n", pointer[P_BLOCKSEC], pointer[P_BSEND])); scan_table_position("BLOCK", &table[T_BLOCK]); scan_table_position("LAYER", &table[T_LAYER]); scan_table_position("STYLE", &table[T_STYLE]); scan_table_position("LTYPE", &table[T_LTYPE]); scan_table_position("VIEW", &table[T_VIEW]); DEBUG_P(("HEADER\n")); scan_header(); scan_table_position("UCS", &table[T_UCS]); echo_bytes(0x500 - cur_pos); scan_table_position("VPORT", &table[T_VPORT]); echo_bytes(8); scan_table_position("APPID", &table[T_APPID]); echo_bytes(6); scan_table_position("DIMSTYLE", &table[T_DIMSTYLE]); /* prev. P12 */ echo_bytes(0x69F - cur_pos); scan_table_position("P13", &table[T_13]); echo_bytes(38); scan_entities(pointer[P_ENTITIES], pointer[P_ENTEND], 0L); echo_bytes(19); scan_blocks(&table[T_BLOCK]); scan_layers(&table[T_LAYER]); scan_styles(&table[T_STYLE]); scan_ltypes(&table[T_LTYPE]); scan_view_table("VIEW TABLE", &table[T_VIEW]); /* new */ scan_ucs_table("UCS TABLE", &table[T_UCS]); /* new */ scan_vport_table("VPORT TABLE", &table[T_VPORT]);/* new */ scan_ads_table(&table[T_APPID]); /* new name */ scan_dim_table(&table[T_DIMSTYLE]); /* new */ scan_table("P13 TABLE", &table[T_13]); DEBUG_P(("BLOCK SECTION\n")); scan_entities(pointer[P_BLOCKSEC], pointer[P_BSEND], pointer[P_BLOCKSEC] - 0x40000000); DEBUG_P(("P3\n")); /* new Header vars */ echo_bytes(36); check_pointer(pointer[P_ENTITIES]); check_pointer(pointer[P_ENTEND]); check_pointer(pointer[P_BLOCKSEC]); check_pointer(pointer[P_BSEND]); echo_bytes(12); check_table_pos("BLOCK", &table[T_BLOCK], 1); check_table_pos("LAYER", &table[T_LAYER], 2); check_table_pos("STYLE", &table[T_STYLE], 3); check_table_pos("LTYPE", &table[T_LTYPE], 5); check_table_pos("VIEW", &table[T_VIEW], 6); check_table_pos("UCS", &table[T_UCS], 7); check_table_pos("VPORT", &table[T_VPORT], 8); check_table_pos("APPID", &table[T_APPID], 9); check_table_pos("DIMSTYLE", &table[T_DIMSTYLE], 10); check_table_pos("P13", &table[T_13], 11); DEBUG_P(("P?: ")); get_pointer(); echo_bytes(last_pos - cur_pos); return 0; } void scan_table_position(char *name, ptable pt) { pt->size = _read_word(); pt->nr = _read_long(); pt->start = _read_long(); DEBUG_P(("%-8.8s %05lX size: %3d (%05lX-%05lX)\n", name, pt->nr, pt->size, pt->start, pt->start + pt->size * pt->nr)); } void check_table_pos(char *name, ptable pt, int t_nr) { word t, size, nr; longword start; t = _read_word(); size = _read_word(); nr = _read_word(); start = _read_long(); printf("%-8.8s %05x size: %3d (%05lx) table:%d", name, nr, size, start, t); if (t != t_nr) printf(" t %d!=%d", t, t_nr); if (nr != (pt->nr & 0xFFFF)) printf(" nr %d!=%ld", nr, pt->nr); if (size != pt->size) printf(" size %d!=%d", size, pt->size); if (start != pt->start) printf(" start %ld!=%ld", start, pt->start); printf("\n"); } void scan_header() { char tmpstr[40]; double date; DEBUG_P(("\n?w %d", _read_word())); DEBUG_P(("\n$INSBASE ")); scan_point(TRUE); DEBUG_P(("\n$EXTMIN ")); scan_point(TRUE); DEBUG_P(("\n$EXTMAX ")); scan_point(TRUE); DEBUG_P(("\n$LIMMIN ")); scan_point(FALSE); DEBUG_P(("\n$LIMMAX ")); scan_point(FALSE); /*-----------------22.10.95 01:01------------------- active vport: groups 12 ?? 40 --------------------------------------------------*/ DEBUG_P(("\n$VIEWCTR (%f,%f) ", _read_double() , _read_double())); DEBUG_P(("\nf? %f " , _read_double())); /*?*/ DEBUG_P(("\n$VIEWSIZE %f " , _read_double())); DEBUG_P(("\nw? %d ", _read_word())); /*-----------------22.10.95 01:01------------------- active vport: groups 14 or 15 --------------------------------------------------*/ DEBUG_P(("\n$SNAPUNIT (%f,%f) ", _read_double() , _read_double())); echo_bytes(56); DEBUG_P(("\nf? %f ", _read_double())); DEBUG_P(("\nf? %f ", _read_double())); DEBUG_P(("\nf? %f ", _read_double())); echo_bytes(18); DEBUG_P(("\nf? %f ", _read_double())); /* rest of header */ DEBUG_P(("\nw? %d ", _read_word())); DEBUG_P(("\nw? %d ", _read_word())); echo_bytes(44); /* DEBUG_P(("\nf? %f ", _read_double())); echo_bytes(12); */ /* menuname: length of pathstr 128 ?? */ echo_bytes((22*16)+2); DEBUG_P(("\n$DIMBLK: %s ", _read_fixed_string(32))); DEBUG_P(("\nb? %d ", _read_byte())); DEBUG_P(("\nb? %d ", _read_byte())); DEBUG_P(("\nw? %d ", _read_word())); DEBUG_P(("\nw? %d ", _read_word())); DEBUG_P(("\nb? %d ", _read_byte())); DEBUG_P(("\nb? %d ", _read_byte())); DEBUG_P(("\nb? %d ", _read_byte())); date = _read_date(); DEBUG_P(("\n$TDCREATE: %.8f %s ", date, date_string(tmpstr,date))); /* at 0x31E */ date = _read_date(); DEBUG_P(("\n$TDUPDATE: %.8f %s ", date, date_string(tmpstr,date))); /* at 0x327 */ echo_bytes(0x379 - cur_pos); DEBUG_P(("\nf? %f ", _read_double())); echo_bytes(0x3c5 - cur_pos); DEBUG_P(("\nf? %f ", _read_double())); DEBUG_P(("\nf? %f ", _read_double())); echo_bytes(0x3EF - cur_pos); } void scan_blocks(ptable pt) { longword i; DEBUG_P(("\nBLOCK TABLE\n")); for (i = 0L; i < pt->nr; i++) { longword begin = pt->start + i * pt->size, end = begin + pt->size - 2; byte flag, b1, b2; word used, w1, w2, w3, w4; goto_pointer(begin); flag = _read_byte(); scan_fixed_ident(32); used = _read_word(); b1 = _read_byte(); w1 = _read_word(); b2 = _read_byte(); w3 = _read_word(); w4 = _read_word(); DEBUG_P(("%02x %5d %3d %5d %3d %5d %5d %5d", flag, used, b1, w1, b2, w2, w3, w4)); skip_to_check_2(end); } get_check_32(); } void scan_layers(ptable pt) { longword i; DEBUG_P(("\nLAYER TABLE\n")); for (i = 0L; i < pt->nr; i++) { longword begin = pt->start + i * pt->size, end = begin + pt->size - 2; int flag, used, color, style; goto_pointer(begin); flag = _read_byte(); scan_fixed_ident(32); used = _read_word(); color = _read_word(); style = _read_word(); DEBUG_P(("%6d %s %s %s %s color: %3d ltype: %3d ", used, color < 0 ? "off" : "on ", flag & 1 ? "fr" : " ", flag & 4 ? "lc" : " ", flag & 64 ? " " : "used", color < 0 ? -color : color, style)); skip_to_check_2(end); } get_check_32(); } void scan_styles(ptable pt) { longword i; DEBUG_P(("\nSTYLE TABLE\n")); for (i = 0L; i < pt->nr; i++) { longword begin = pt->start + i * pt->size, end = begin + pt->size - 2; int flag; goto_pointer(begin); printf("%02X ", flag = _read_byte()); scan_fixed_ident(32); printf("?w: %5d ", _read_word()); printf("%f ", _read_double()); printf("%f ", _read_double()); printf("%f ", _read_double()); printf("%02X ",_read_byte()); printf("%f ", _read_double()); printf("`%s'", _read_fixed_string(128)); skip_to_check_2(end); } get_check_32(); } void scan_ltypes(ptable pt) { longword i; DEBUG_P(("\nLTYPE TABLE\n")); for (i = 0L; i < pt->nr; i++) { longword begin = pt->start + i * pt->size, end = begin + pt->size - 2; goto_pointer(begin); printf("%02X ", _read_byte()); scan_fixed_ident(32); printf("%5d ", _read_word()); printf("`%s' ", _read_fixed_string(48)); printf("%02X ", _read_byte()); { word j, k = _read_byte(); for (j = 0; j < 13; j++) printf("%s%f ", j < k ? "" : "*", _read_double()); } skip_to_check_2(end); } get_check_32(); } void scan_ads_table(ptable pt) { longword i; DEBUG_P(("\nAPPID TABLE\n")); for (i = 0L; i < pt->nr; i++) { longword begin = pt->start + i * pt->size, end = begin + pt->size - 2; goto_pointer(begin); printf("%02X ", _read_byte()); scan_fixed_ident(32); printf("?w: %5d ", _read_word()); skip_to_check_2(end); } get_check_32(); } #define OPTS(X) if (opts & (1 << (X-1))) #define SCAN_POINT(G,C) { printf(" %d:", G); scan_point(C); } #define SCAN_DOUBLE(G) printf(" %d:%f", G, _read_double()); #define SCAN_STRING(G) printf(" %d:`%s'", G, _read_string()); /* new */ #define SCAN_FIXED_STRING(G,L) printf(" %d:`%s'", G, _read_fixed_string(L)); #define SCAN_BYTE(G) printf(" %d:%02X", G, _read_byte()); #define SCAN_WORD(G) printf(" %d:%d", G, _read_word()); #define SCAN_LONG(G) printf(" %d:%ld", G, _read_long()); /*-----------------23.10.95 11:14------------------- new: --------------------------------------------------*/ void scan_dim_table(ptable pt) { longword i; DEBUG_P(("\nDIMSTYLE TABLE\n")); for (i = 0L; i < pt->nr; i++) { longword begin = pt->start + i * pt->size, end = begin + pt->size - 2; int flag; goto_pointer(begin); printf("70: %02X ", flag = _read_byte()); scan_fixed_ident(32); printf("?w: %5d ", _read_word()); printf ("\n"); SCAN_DOUBLE(40); /* DIMSCALE: */ SCAN_DOUBLE(41); /* DIMASZ: */ SCAN_DOUBLE(42); /* DIMEXO: */ SCAN_DOUBLE(43); /* DIMDLI: */ SCAN_DOUBLE(44); /* DIMEXE: */ SCAN_DOUBLE(45); /* DIMRND: */ SCAN_DOUBLE(46); /* DIMDLE: */ SCAN_DOUBLE(47); /* DIMTP: */ SCAN_DOUBLE(48); /* DIMTM: */ printf ("\n"); SCAN_DOUBLE(140); /* DIMTXT : */ SCAN_DOUBLE(141); /* DIMCEN : */ SCAN_DOUBLE(142); /* DIMTSZ : */ SCAN_DOUBLE(143); /* DIMALTF: */ SCAN_DOUBLE(144); /* DIMLFAC: */ SCAN_DOUBLE(145); /* DIMTVP : */ printf ("\n"); SCAN_BYTE (71); SCAN_BYTE (72); SCAN_BYTE (73); SCAN_BYTE (74); SCAN_BYTE (75); SCAN_BYTE (76); SCAN_BYTE (77); SCAN_BYTE (78); printf ("\n"); SCAN_BYTE (170); SCAN_BYTE (171); SCAN_BYTE (172); SCAN_BYTE (173); SCAN_BYTE (174); /*?*/ SCAN_BYTE (175); /*?*/ SCAN_FIXED_STRING (3,16); /* length ? */ SCAN_FIXED_STRING (4,16); /* length ? */ SCAN_FIXED_STRING (5,32); SCAN_FIXED_STRING (6,32); SCAN_FIXED_STRING (7,32); echo_bytes (3); /*?*/ SCAN_WORD (176); /* Colors as int ? */ SCAN_WORD (177); SCAN_WORD (178); SCAN_DOUBLE(146); /* DIMTFAC */ SCAN_DOUBLE(147); /* DIMDIST */ skip_to_check_2(end); } get_check_32(); } /*-----------------23.10.95 11:14------------------- new: --------------------------------------------------*/ void scan_view_table(char *name, ptable pt) { longword i; DEBUG_P(("\n%s\n", name)); for (i = 0L; i < pt->nr; i++) { longword begin = pt->start + i * pt->size, end = begin + pt->size - 2; goto_pointer(begin); printf("70: %02X ", _read_byte()); scan_fixed_ident(32); printf("used: %5d\n", _read_word()); /* used */ SCAN_DOUBLE(40); SCAN_POINT(10,FALSE); SCAN_DOUBLE(41); SCAN_POINT(11,TRUE); SCAN_POINT(12,TRUE); SCAN_WORD(71); /*?*/ SCAN_DOUBLE(42); SCAN_DOUBLE(43); SCAN_DOUBLE(44); SCAN_DOUBLE(50); echo_bytes(2); /*?*/ skip_to_check_2(end); } get_check_32(); } /*-----------------23.10.95 11:14------------------- new: --------------------------------------------------*/ void scan_ucs_table(char *name, ptable pt) { longword i; DEBUG_P(("\n%s\n", name)); for (i = 0L; i < pt->nr; i++) { longword begin = pt->start + i * pt->size, end = begin + pt->size - 2; goto_pointer(begin); printf("70: %02X ", _read_byte()); scan_fixed_ident(32); printf("used: %5d\n", _read_word()); /* used */ SCAN_POINT(10,TRUE); SCAN_POINT(11,TRUE); SCAN_POINT(12,TRUE); skip_to_check_2(end); } get_check_32(); } /*-----------------23.10.95 11:14------------------- new: --------------------------------------------------*/ void scan_vport_table(char *name, ptable pt) { longword i; DEBUG_P(("\n%s\n", name)); for (i = 0L; i < pt->nr; i++) { longword begin = pt->start + i * pt->size, end = begin + pt->size - 2; goto_pointer(begin); printf("70: %02X ", _read_byte()); scan_fixed_ident(32); printf("used: %5d\n", _read_word()); /* used */ SCAN_POINT(10,FALSE); SCAN_POINT(11,FALSE); printf ("\n"); SCAN_POINT(17,TRUE); SCAN_POINT(16,TRUE); /*43-51 */ printf ("\n"); SCAN_DOUBLE(50); SCAN_DOUBLE(40); SCAN_POINT(12,FALSE); printf ("\n"); SCAN_DOUBLE(41); SCAN_DOUBLE(42); SCAN_DOUBLE(43); SCAN_DOUBLE(44); printf ("\n"); SCAN_WORD(71); /*?*/ SCAN_WORD(72); SCAN_WORD(73); SCAN_WORD(74); SCAN_WORD(75); SCAN_WORD(76); SCAN_WORD(77); SCAN_WORD(78); printf ("\n"); SCAN_DOUBLE(51); printf ("\n"); SCAN_POINT(13,FALSE); SCAN_POINT(14,FALSE); SCAN_POINT(15,FALSE); skip_to_check_2(end); } get_check_32(); } void scan_table(char *name, ptable pt) { longword i; DEBUG_P(("\n%s\n", name)); for (i = 0L; i < pt->nr; i++) { longword begin = pt->start + i * pt->size, end = begin + pt->size - 2; int flag; goto_pointer(begin); printf("70: %02X ", flag = _read_byte()); scan_fixed_ident(32); printf("used: %5d\n", _read_word()); /* used */ skip_to_check_2(end); } get_check_32(); } #define NR_ENT 25 struct { char *name; int kn_flag, kn_opts; } ent_type[NR_ENT] = { { NULL, 0, 0 }, { "LINE ", 0x6F /* 1 2 4 8 .. 20 40 .. */, 0x03 /* 1 2 . . .. .. .. .. */}, { "POINT ", 0x6F /* 1 2 4 8 .. 20 40 .. */, 0x03 /* 1 2 . . .. .. .. .. */}, { "CIRCLE ", 0x6F /* 1 2 4 8 .. 20 40 .. */, 0x03 /* 1 2 . . .. .. .. .. */}, { "SHAPE ", 0x6B /* 1 2 . 8 .. 20 40 .. */, 0x03 /* 1 2 . . .. .. .. .. */}, { NULL, 0, 0 }, { NULL, 0, 0 }, { "TEXT ", 0x6B /* 1 2 . 8 .. 20 40 .. */, 0x17B/* 1 2 + 8 10 20 40 ++ 50 41 51 7 71 72 72p ? 73 1 . . . .. .. .. .. */}, { "ARC ", 0x6D /* 1 . 4 8 .. 20 40 .. */, 0x03 /* 1 2 . . .. .. .. .. */}, { "TRACE ", 0x6B /* 1 2 . 8 .. 20 40 .. */, 0x03 /* 1 2 . . .. .. .. .. */}, { NULL, 0, 0 }, { "SOLID ", 0x6B /* 1 2 . 8 .. 20 40 .. */, 0x03 /* 1 2 . . .. .. .. .. */}, /*-----------------23.10.95 12:59------------------- opts changed --------------------------------------------------*/ { "BLOCK ", 0 /* . . . . .. .. .. .. */, 0x06 /* . 2 4 . .. .. .. .. */}, { "ENDBLK ", 0, 0x004 }, { "INSERT ", 0xA2 /* . 2 . . .. 20 .. 80 */, 0x0F /* 1 2 4 8 .. .. .. .. */}, { "ATTDEF ", 0x6B /* 1 2 . 8 .. 20 40 .. */, 0x030/* + + + + 10 20 ++ ++ 73 50 41 51 7 71 72 72' 1 . . . .. .. .. .. */}, { "ATTRIB ", 0x22 /* . . . . .. .. .. .. */, 0x116/* + 2 4 + 10 ++ ++ ++ 1 . . . .. .. .. .. */}, /* 1 */ { "S/BEND ", 0x22 /* . 2 . . .. 20 .. .. */, 0x00 /* . . . . .. .. .. .. */}, { NULL, 0, 0 }, { "PLINE ", 0xA2 /* . 2 . . .. 20 .. 80 */, 0x01 /* 1 . . . .. .. .. .. */}, { "VERTEX ", 0x22 /* . 2 . . .. 20 .. .. */, 0x04 /* + + . . .. .. .. .. */}, { NULL, 0, 0 }, { "3DFACE ", 0x26 /* . 2 . . .. 20 .. .. */, 0x00 /* . . . . .. .. .. .. */}, { "DIM ", 0x22 /* . . . . .. .. .. .. */, 0x11A/* + 2 + 8 10 ++ ++ ++ 1 . . . .. .. .. .. */}, { "VPORT ", 0x63 /* 1 2 . . .. 20 40 .. */, 0x00 /* . . . . .. .. .. .. */}, }; void scan_entities(longword start, longword end, longword sce_offset) { long s_comp_ent = 0L; DEBUG_P(("ENTITIES\n")); goto_pointer(start); while (cur_pos < end - 32L) { word kind, flag, length, layer, opts, color = 0, extra = 0; longword b_pos = cur_pos, pos = cur_pos; /*printf("cur_pos %ld end %ld\n", cur_pos, end);*/ DEBUG_P(("[%05lX]", cur_pos)); kind = _read_byte(); flag = _read_byte(); length = _read_word(); pos += (long)(length - 2); if (pos > end - 2) pos = end - 2; /* printf("cur_pos %ld, till %ld, end %ld", cur_pos, pos, end); */ if (kind < NR_ENT && ent_type[kind].name != NULL) { printf("%s %02X ", ent_type[kind].name, (int)flag); if (flag & ~ent_type[kind].kn_flag) printf("!%02X", flag & ~ent_type[kind].kn_flag); } else printf("ENT_%d! %02X (%d) ", (int)kind, (int)flag, length); layer = _read_word(); opts = _read_word(); printf("l:%d %04X ", layer, opts); if ( ent_type[kind].name != NULL && opts & ~ent_type[kind].kn_opts) printf("!%02X", opts & ~ent_type[kind].kn_opts); if (flag & 1) color = _read_byte(); printf("c:%d ", color); if (flag & 0x40) extra = _read_byte(); if (extra & ~6) /* . 2 4 . .. .. .. .. */ printf("!(extra)"); if (extra & 2) scan_xdata(); if (flag & 2) printf(" TYPE:%d ", _read_word()); if (flag & 4 && kind > 2 && kind != 22) { printf(" z:"); printf("%1.2f", _read_double()); } if (flag & 8) { printf(" TH:"); printf("%1.2f", _read_double()); } if (flag & 0x20) scan_handle(); if (extra & 4) printf(" PAPER:%d", _read_word()); switch (kind) { case 1: /* LINE */ SCAN_POINT(10, !(flag & 4)); SCAN_POINT(11, !(flag & 4)); OPTS(1) SCAN_POINT(210, TRUE); OPTS(2) SCAN_DOUBLE(38); break; case 2: /* POINT */ SCAN_POINT(10, !(flag & 4)); OPTS(1) SCAN_POINT(210, TRUE); OPTS(2) SCAN_DOUBLE(38); break; case 3: /* CIRCLE */ SCAN_POINT(10, FALSE); SCAN_DOUBLE(40); OPTS(1) SCAN_POINT(210, TRUE); OPTS(2) SCAN_DOUBLE(38); break; case 4: /* SHAPE */ SCAN_POINT(10, FALSE); SCAN_WORD(2); OPTS(1) SCAN_POINT(210, TRUE); OPTS(2) SCAN_DOUBLE(38); break; case 7: /* TEXT */ SCAN_POINT(10, FALSE); SCAN_DOUBLE(40); SCAN_STRING(1); OPTS(1) SCAN_DOUBLE(50); OPTS(2) SCAN_DOUBLE(41); OPTS(3) SCAN_DOUBLE(51); /*?*/ OPTS(4) SCAN_BYTE(7); OPTS(5) SCAN_BYTE(71); OPTS(6) SCAN_BYTE(72); OPTS(7) SCAN_POINT(11, FALSE); OPTS(9) SCAN_BYTE(73); break; case 8: /* ARC */ SCAN_POINT(10, FALSE); SCAN_DOUBLE(40); SCAN_DOUBLE(50); SCAN_DOUBLE(51); OPTS(1) SCAN_POINT(210, TRUE); OPTS(2) SCAN_DOUBLE(38); break; case 9: /* TRACE */ SCAN_POINT(10, FALSE); SCAN_POINT(11, FALSE); SCAN_POINT(12, FALSE); SCAN_POINT(13, FALSE); OPTS(1) SCAN_POINT(210, TRUE); OPTS(2) SCAN_DOUBLE(38); break; case 11: /* SOLID */ SCAN_POINT(11, FALSE); SCAN_POINT(12, FALSE); SCAN_POINT(13, FALSE); SCAN_POINT(14, FALSE); OPTS(1) SCAN_POINT(210, TRUE); OPTS(2) SCAN_DOUBLE(38); break; case 12: /* BLOCK */ SCAN_POINT(10,FALSE); /*?*/ SCAN_STRING(1); OPTS(2) SCAN_STRING(3); /* nur bei opts 2 */ break; case 13: /* ENDBLK */ break; case 14: /* INSERT */ s_comp_ent = b_pos - sce_offset; SCAN_WORD(1); SCAN_POINT(10, FALSE); OPTS(1) SCAN_DOUBLE(41); OPTS(2) SCAN_DOUBLE(42); OPTS(3) SCAN_DOUBLE(43); OPTS(4) SCAN_DOUBLE(50); OPTS(5) SCAN_WORD(70); OPTS(6) SCAN_WORD(71); OPTS(7) SCAN_DOUBLE(44); /*?*/ OPTS(8) SCAN_DOUBLE(45); /*?*/ break; case 15: /* ATTDEF */ SCAN_POINT(10, FALSE); SCAN_DOUBLE(40); SCAN_STRING(1); SCAN_STRING(3); SCAN_STRING(2); SCAN_BYTE(70); OPTS(1) SCAN_BYTE(73); /*?*/ OPTS(2) SCAN_DOUBLE(50); /*?*/ OPTS(3) SCAN_DOUBLE(41); OPTS(4) SCAN_DOUBLE(42); OPTS(5) SCAN_BYTE(7); OPTS(6) SCAN_BYTE(71); OPTS(7) SCAN_BYTE(72); OPTS(8) SCAN_POINT(11, FALSE); /*?*/ OPTS(9) SCAN_POINT(210, TRUE); OPTS(10) SCAN_DOUBLE(38); /*?*/ break; case 16: /* ATTRIB */ SCAN_POINT(10, FALSE); SCAN_DOUBLE(40); SCAN_STRING(1); SCAN_STRING(2); SCAN_BYTE(70); OPTS(1) SCAN_BYTE(73); /*?*/ OPTS(2) SCAN_DOUBLE(50); /*?*/ OPTS(3) SCAN_DOUBLE(41); OPTS(4) SCAN_DOUBLE(42); OPTS(5) SCAN_BYTE(7); OPTS(6) SCAN_BYTE(71); OPTS(7) SCAN_BYTE(72); OPTS(8) SCAN_POINT(11, FALSE); /*?*/ OPTS(9) SCAN_POINT(210, TRUE); OPTS(10) SCAN_DOUBLE(38); /*?*/ break; case 17: /* S/BEND */ { longword p = _read_long(); if (p != s_comp_ent) printf("!!%04lX != %04lX", s_comp_ent, p); } break; case 19: /* PLINE */ s_comp_ent = b_pos - sce_offset; OPTS(1) SCAN_BYTE(70); OPTS(2) SCAN_DOUBLE(40); /*?*/ OPTS(3) SCAN_BYTE(71); /*?*/ OPTS(4) SCAN_BYTE(72); /*?*/ OPTS(5) SCAN_BYTE(73); /*?*/ OPTS(6) SCAN_BYTE(74); /*?*/ OPTS(7) SCAN_BYTE(75); /*?*/ break; case 20: /* VERTEX */ SCAN_POINT(10, FALSE); OPTS(1) SCAN_DOUBLE(40); /*?*/ OPTS(2) SCAN_DOUBLE(41); /*?*/ OPTS(3) SCAN_DOUBLE(50); /*?*/ OPTS(4) SCAN_BYTE(70); /*?*/ break; case 22: /* 3DFACE */ SCAN_POINT(10, !(flag & 4)); SCAN_POINT(11, !(flag & 4)); SCAN_POINT(12, !(flag & 4)); SCAN_POINT(13, !(flag & 4)); break; case 23: /* DIM */ SCAN_WORD(1); SCAN_POINT(10, TRUE); SCAN_POINT(11, FALSE); /*?*/ OPTS(2) SCAN_BYTE(70); OPTS(1) SCAN_POINT(12, TRUE); /*?*/ OPTS(3) SCAN_STRING(1); OPTS(4) SCAN_POINT(13, TRUE); OPTS(5) SCAN_POINT(14, TRUE); OPTS(6) SCAN_POINT(15, TRUE); OPTS(7) SCAN_POINT(16, TRUE); OPTS(8) SCAN_DOUBLE(40); OPTS(9) SCAN_DOUBLE(50); OPTS(10) SCAN_DOUBLE(51); OPTS(11) SCAN_DOUBLE(52); OPTS(12) SCAN_DOUBLE(53); break; case 24: /* VPORT */ SCAN_POINT(10, TRUE); SCAN_DOUBLE(40); SCAN_DOUBLE(41); SCAN_WORD(68); break; } skip_to_check_2(pos); } get_check_32(); } void scan_xdata() { int xd_length = _read_word(), i; bool go = TRUE; printf("XDATA %d: (", xd_length); while (xd_length > 0 && go) { int c = _read_byte(); xd_length--; printf(" %d:", c); switch (c) { case 0: if (xd_length < 0) go = FALSE; else { int l = _read_byte(); xd_length--; if (version_13) { _read_byte(); xd_length--; } if (l <= xd_length) { printf("`%s'", _read_fixed_string(l)); xd_length -= l; } else go = FALSE; } break; case 1: case 3: case 70: if (xd_length < 2) go = FALSE; else { printf("%d", _read_word()); xd_length -= 2; } break; case 2: if (xd_length < 1) go = FALSE; else { printf("%c", _read_byte() == 0 ? '{' : '}'); xd_length--; } break; case 5: case 40: case 41: case 42: if (xd_length < 8) go = FALSE; else { printf("%1.2f", _read_double()); xd_length -= 8; } break; case 10: case 11: case 12: if (xd_length < 24) go = FALSE; else { scan_point(TRUE); xd_length -= 24; } break; case 71: if (xd_length < 4) go = FALSE; else { printf("%ld", _read_long()); xd_length -= 4; } break; default: go = FALSE; } } if (!go) printf("!"); for (i = 0; i < xd_length; i++) { int w = _read_byte(); if (w < 0) w += 256; printf("%02X ", w); } printf(") "); } void scan_handle() { int n = _read_byte(), i; printf(" 5:"); for (i = 0; i < n; i++) { int w = _read_byte(); if (w < 0) w += 256; printf("%02X", w); } } void echo_16_bytes(word len) { int i; char buffer[16]; printf("[%05lX] ", cur_pos); for (i = 0; i < len; i++) buffer[i] = _read_byte(); for (i = 0; i < 16; i++) { if (i > 0 && i % 4 == 0) printf("| "); if (i < len) { int w = buffer[i]; if (w < 0) w += 256; printf("%02X ", w); } else printf(" "); } printf(" "); for (i = 0; i < len; i++) { char c = buffer[i]; if ((c >= 0) && (c < 32)) printf("."); else printf("%c", c); } printf("\n"); } void echo_bytes(long int len) { printf("\ndata: %ld\n", len); while(len > 0) { int len16 = (int)MIN(len, 16); echo_16_bytes(len16); len -= (longword)len16; } } void scan_point(bool z_coord) { double x = _read_double(), y = _read_double(), z = z_coord ? _read_double() : 0.0; if (z_coord) printf("(%f,%f,%f)", x, y, z); else printf("(%f,%f)", x, y); } void scan_fixed_ident(int len) { char *s = _read_fixed_string(len); if (version_13) s++; printf("`%-*.*s'", len, len, s); } longword get_pointer() { longword result = _read_long(); #ifdef POINTER_VALUE printf("(pointer: %05lX)\n", result); #else printf("(pointer)\n"); #endif return result; } void check_pointer(longword p) { printf("(pointer: %05lX) %s\n", p,_read_long() == p ? "Correct" : "Wrong"); } void get_check_2() { printf("(check_2)\n"); _advance(2); } void get_check_32() { printf("(check_32)\n"); _advance(32); } void skip_to_check_2(longword pos) { if (cur_pos < pos) { printf("!\n"); echo_bytes(pos - cur_pos); } if (cur_pos > pos) { printf("!%05lX>", cur_pos - pos); _seek(pos); } get_check_2(); } void goto_pointer(longword pos) { if (cur_pos != pos) { printf("!(pointer: %05lX)\n", pos - cur_pos); /* /n inserted */ _seek(pos); } } /************** File IO *************************/ static FILE *f = NULL; #define MAX_STRING_LENGTH 1000 static char str_buffer[MAX_STRING_LENGTH]; #define GETBYTE (byte)fgetc(f) void _assign(file) FILE *file; { int fh = fileno(file); f = file; cur_pos = 0; last_pos = lseek(fh, 0L, SEEK_END); lseek(fh, 0L, SEEK_SET); } void _advance(word len) { fseek(f, len, SEEK_CUR); cur_pos += len; } longword _tell() { return cur_pos; } void _seek(long int pos) { cur_pos = pos; fseek(f, pos, SEEK_SET); } bool _eof() { return cur_pos >= last_pos; } byte _read_byte() { cur_pos++; return GETBYTE; } short _read_word() { short result; *((byte *)&result) = GETBYTE; *((byte *)&result + 1) = GETBYTE; cur_pos += 2; return result; } longword _read_long() { longword result; { short i; byte *p = (byte *)&result; for (i = 0; i < sizeof(longword); i++) *p++ = GETBYTE; } cur_pos += sizeof(longword); return result; } float _read_float() { float result; { short i; byte *p = (byte *)&result; for (i = 0; i < sizeof(double); i++) *p++ = GETBYTE; } cur_pos += sizeof(float); return result; } /*-----------------23.10.95 23:38------------------- corrected version --------------------------------------------------*/ double _read_date() { longword l1,l2; double d1; /* <julian date> . <daytime ratio> */ /* seconds = 86400 * <daytime ratio> */ l1 = _read_long(); l2 = _read_long(); d1 = (double)l1; d1 += (double)l2 * 1e-8; /* here was an error in the prev. version!*/ return d1; } double _read_double() { double result; { short i; byte *p = (byte *)&result; for (i = 0; i < sizeof(double); i++) *p++ = GETBYTE; } cur_pos += sizeof(double); return result; } char *_read_string() { return _read_fixed_string(_read_word()); } char *_read_fixed_string(len) int len; { int i; char *str = str_buffer; for (i = 0; i < len; i++) *str++ = GETBYTE; *str = '\0'; cur_pos += len; return str_buffer; } /*-----------------25.10.95 21:47------------------- conversion of julian date into calendar date returns formatted date output from "Numerical Recipes in Pascal", p.12 room for s must be allocated! --------------------------------------------------*/ char *date_string (char *s, double date) { double t,ss; int y,m,d,hh,mm; long ja,jalpha,jb,jc,jd,je; #define TRUNC(n) (long) floor(n) t = 86400*(date-floor(date)); /* in seconds */ date = floor (date); if ( date>2299161.0 ) { jalpha = TRUNC(((date-1867216)-0.25)/36524.25); ja = (long) (date+1+jalpha-TRUNC(0.25*jalpha)); } else ja = (long)date; jb = ja+1524; jc = TRUNC(6680.0+((jb-2439870)-122.1)/365.25); jd = 365*jc+TRUNC(0.25*jc); je = TRUNC((jb-jd)/30.6001); d = (int) (jb-jd-TRUNC(30.6001*je)); m = (int) (je-1); if ( m>12 ) mm -= 12; y = (int) (jc-4715); if ( m>2 ) y--; if ( y<=0 ) y--; hh = (int) floor(t/3600.0); t -= hh*3600.0; mm = (int) floor(t/60.0); ss = t- (mm*60.0); sprintf (s, "%02d.%02d.%4d %02d:%02d:%05.2f", d,m,y,hh,mm,ss); return s; }