/* * Test bookfile_*.c routines, usage: * * testbook [-f file] [-d def-file] [-t table] [-n entry] [-i iter] * * options (all options have mandatory following argument): * -f Bookreader file to read (def: bookreader.decw$book). * -d Default file spec for open (def: sys$disk:[].decw$book). * -t Table (index) to use. If option specifed as "*", all tables * present in book will be listed. If option not present, * bookfile_demo will use first type 5 (TOC) table found. * Note that names are case sensitive. * -n Entry number within selected table to display. The section * of the book pointed to by the entry will be displayed. * If option not present, the table entries will be listed. * -i Iteration count, number of additional sections to display * from file. */ #include #include #include #include "bookreader_recdef.h" #include "bookfile_io.h" #include "bookfile_index.h" #include "bookfile_section.h" #include "bookfile_text.h" int LIB$INIT_TIMER(), LIB$SHOW_TIMER(); static void show_section ( void *, void *, char *, int, int, int ); static void show_part ( void * bkf, int part_num ); void show_font ( void *bki, long font_page, long fontcount ); static int convert_text3 ( int length, char *in, char *out ) { int i, offset, slen, glue, j; for ( j = offset = 0; offset < length; ) { bkt_text3_scan ( length, in, &offset, &out[j], &slen, &glue ); j += slen; if ( offset < length ) { sprintf(&out[j], "|%x|", glue ); j += strlen ( &out[j] ); /* out[j++] = ' '; */ } } out[j] = '\0'; return j; } int main ( int argc, char **argv ) { int i, bad, status, part_length, length, single_sect; int ndx_type, ndx_count, iter_count, font_count; char *bookfile, *defdir, *table, *sec_str; char ndx_name[256]; bkrdr_recptr root, subrec; bktxt_fntptr fontdef; void *bkf, *bki; /* * Interpret command line arguments. */ bookfile = "bookreader.decw$book"; defdir = "sys$disk:[].decw$book"; table = sec_str = (char *) 0; single_sect = 0; iter_count = 0; for ( bad = 0, i = 1; !bad && i < argc; i++ ) { if ( argv[i][0] != '-' ) { bad = 1; break;} if ( i + 1 >= argc ) { bad = 1; break; } switch ( argv[i][1] ) { case 'f': bookfile = argv[++i]; break; case 'd': defdir = argv[++i]; break; case 't': table = argv[++i]; break; case 'n': sec_str = argv[++i]; break; case 'i': iter_count = atoi(argv[++i]); break; case 's': single_sect = atoi(argv[++i]); break; default: bad = 1; break; } } if ( bad ) { printf("Usage: 'testbook [-f file] [-d dir] [-t table] [-n entry]'\n"); exit ( 1 ); } /* * Open file, read root page, and display some of it's fields. */ LIB$INIT_TIMER(); status = bkf_open ( bookfile, defdir, &bkf ); if ( (status&1) == 0 ) { printf("error opening bookfile '%s'\n", bookfile ); exit ( status ); } LIB$SHOW_TIMER(); status = bkf_read_page ( bkf, 0, &part_length, &root, &length ); if ( (status&1) == 0 ) { printf("error reading root part: %d\n", status ); exit ( status ); } LIB$SHOW_TIMER(); printf("Book opened, root info:\n title: '%s'\n parts: %d\n", root->first.title, root->first.partcount ); printf(" sections: %d\n author: '%s'\n\n", root->first.sectioncount, root->first.author ); /* * Read font table. */ status = bkt_read_font_map ( bkf, &fontdef, &font_count ); printf("Font data status: %d, font count: %d table: %d\n", status, font_count, fontdef ); if ( table ) for ( i = 0; i < font_count; i++ ) printf ( "Font[%d] = '%s'\n pixel_size: %d point: %d enc: '%s'\n", fontdef[i].fontno, fontdef[i].name, fontdef[i].pixel_size, fontdef[i].point_size, fontdef[i].encoding ); LIB$SHOW_TIMER(); /* * Lookup table name. */ status = bki_create_context ( bkf, &bki ); if ( (status&1) == 0 ) { printf("error creating index context\n" ); exit ( status ); } if ( table ) { int list_mode; list_mode = (strcmp(table,"*") == 0); if ( list_mode ) printf ( "Available tables:\n" ); for ( status = bki_find_index ( bki,table,-1, ndx_name, &ndx_type, &ndx_count ); (status&1) == 1 && list_mode; status = bki_find_index ( bki, table, -1, ndx_name, &ndx_type, &ndx_count ) ) { printf(" '%s', type = %d, size = %d entries\n", ndx_name, ndx_type, ndx_count ); } if ( list_mode ) exit ( 1 ); } else { /* * No table given on command line, find name of first type 5 * table and use it. */ status = bki_find_index ( bki, "*", 5, ndx_name, &ndx_type, &ndx_count ); } if ( (status&1) == 0 ) { printf("Unable to find index '%s'\n", table ? table : "{contents}" ); exit ( status ); } bki_find_index_end ( bki ); /* show_font ( bkf, root->first.font_page, root->first.fontcount ); */ /* * Open table for section access using matched name returned by find_index. */ status = bki_open_index ( bki, ndx_name ); if ( (status&1) == 0 ) { printf("Unable to open index '%s'\n", ndx_name ); exit ( status ); } printf("Table '%s' opened, entries: %d\n", ndx_name, ndx_count ); /* * Now display section corresponding to matching */ show_section ( bkf, bki, sec_str, single_sect, ndx_count, iter_count ); /* * Cleanup. */ status = bki_close_index ( bki ); status = bki_delete_context ( bki ); status = bkf_close ( bkf ); return status; } static char *rtype ( short type ) { static char *desc[26] = { "unknown", "first", "Unknown2", "bodypart", "index", "last", "secmap", "fdx", "unknown8", "font", "cont_mid", "cont_end", "sb_tblhdr", "ascz_32", "sb_font", "sb_fdesc", "sb_ixtxt", "unknown11", "text", "figure", "hotspot", "sb_unk15", "sb_extension", "sb_unk17", "sb_license", ">24" }; static char out_of_range[20]; if ( (type < 0) || (type > 24) ) { sprintf(out_of_range, "unknown%d", type ); return out_of_range; } else { return desc[type]; } } /**************************************************************************/ /* Retreive and display contents section specified by table entry number. */ static void show_section ( void *bkf, void *bki, char *entry_num_str, int single_sect, int ndx_size, int iter_count ) { char *desc; void *cursor; long ndx_value; int status, count, part_num, match, iter; short ndx_hdr[9]; unsigned char attr[4]; char name[256]; /* * Convert entry number string to integer (match), if string null, * set to last table entry. */ match = ndx_size; if ( entry_num_str ) match = atoi ( entry_num_str ); if ( match < 1 ) match = 1; if ( match > ndx_size ) match = ndx_size; /* * Iterate through sub-records in selected table (bki) to retrieve the * desired table entry information. */ if ( single_sect ) { ndx_value = single_sect; if ( iter_count == 0 ) iter_count = 1; desc = ""; } else for ( count = 0; count < match; count++ ) { status = bki_read_index( bki, ndx_hdr, attr, name, &desc, &ndx_value); if ( (status&1) == 0 ) { printf("Error reading index entry %d\n", count ); exit ( status ); } /* * If null entry specified, list the table members. */ if ( !entry_num_str ) printf ( "[%d] %s, (sect=%d)\n", count+1, desc, ndx_value ); } if ( !entry_num_str && !single_sect ) return; /* Done with list */ /* * Create data structures used by bookfile_section.c */ status = bks_create_section_cursor ( bkf, &cursor ); if ( (status&1) == 0 ) { printf("Error creating cursor: %d\n", status ); exit ( status ); } else { int first, type, length; long hdr[9]; /* * Report entry information and lookup part number containing section. */ printf("Entry %d found in table:\n title: '%s'\n Sect #: %d\n", count, desc, ndx_value ); if ( iter_count <= 0 ) { status = bkf_lookup_first_section ( bkf, ndx_value, &part_num, &first ); if ( (status &1) == 1 ) status = bks_seek_part ( cursor, part_num, 0, &iter_count ); else iter_count = 0; printf ( " Part #: %d first sect: %d, sub-records: %d (lookup status: %d)\n\n", part_num, first, iter_count, status ); ndx_value = first; /* reset to start of page */ } else { status = bkf_lookup_section ( bkf, ndx_value, &part_num ); printf ( " Part #: %d (lookup status: %d)\n\n", part_num, status ); first = -1; } /* * Show the next iter_count sections. */ for ( iter = 0; (iter < iter_count); iter++ ) { int is_last, t_type, t_len; short h_v[2]; unsigned char attr[4]; char *data; char buffer[2560]; /* * seek. Aboslute on first read. */ if ( ndx_value == first ) { first = -1; status = bks_seek_section ( cursor, 0, 1, &type, &length, hdr ); } else if ( iter == 0 ) status = bks_seek_section ( cursor, ndx_value+iter, 0, &type, &length, hdr ); else status = bks_seek_section ( cursor, 1, 1, &type, &length, hdr ); if ( (status&1) == 0 ) printf("Error in seek: %d\n", status); if ( (status&1) == 0 ) break; /* * Now call read_section in loop to extract the contents * of the current section. is_last will be set true when * sub-record returned is last in section. */ is_last = 0; if ( type == BKSBREC_FIGURE ) { unsigned char *ub; ndx_value = hdr[2]; printf("[sect=%d,type='%s',len=%d]\n", ndx_value, rtype(type), length); printf(" fig: X=%d Y=%d Width=%d Height=%d picbytes: %d\n", hdr[3], hdr[4], hdr[5], hdr[6], hdr[7] ); ub = (unsigned char *) &hdr[8]; printf(" fig: primitive: %d ???: %d %d %d\n", ub[0], ub[1], ub[2], ub[3] ); } else if ( type != BKSBREC_BODYTEXT ) { int j; printf("[sect=(%d),type='%s', h_v=%d/%d, len=%d, args: ", ndx_value, rtype(type), h_v[0], h_v[1], length); for(j=0;j<9;j++) printf("%d%s",hdr[j],j<8?" ":"]\n"); status = bks_read_section ( cursor, &t_type, h_v, attr, &t_len, &data, &is_last ); } else { ndx_value = hdr[1]; printf("[sect=%d,type='%s'(%d), h_v=%d/%d, len=%d]\n", ndx_value, rtype(type), type, h_v[0], h_v[1], length); } while ( !is_last ) { status = bks_read_section ( cursor, &t_type, h_v, attr, &t_len, &data, &is_last ); if ( (status&1) == 0 ) printf(" xxx: {read error, status: %d, is_last: %d}\n", status, is_last ); if ( (status&1) == 0 ) break; /* * Convert type 3 data into single string. */ if ( t_type == 1 ) { printf ( " ---: {type %d}\n", t_type ); /* can't handle */ } else if ( t_len > 0 && t_len < 256 ) { if ( (t_type == 2) || (t_type == 3) ) t_len = convert_text3 ( t_len, data, buffer ); buffer[t_len] = '\0'; printf("%4d: %s {%d}\n", t_len, buffer, attr[0] ); } else if ( t_len > 255 ) { int j; printf(" ***: {overflow, %d bytes}\n", t_len); printf("subrec data:"); for ( j = 0; j < t_len; j++ ) printf("%d%s", data[j], ((j0) ? " " : "\n" ); } } if ( is_last == 2 ) printf("////: {part boundary}\n"); } } bks_delete_section_cursor ( cursor ); } void show_font ( void *bkf, long font_page, long fontcount ) { bkrdr_recptr font, sub; int status, length, i, part_length, j, sublen; status = bkf_read_page ( bkf, font_page, &part_length, &font, &length ); printf("Status of reading font page (%d): %d, length: %d/%d\n", font_page, status, length, part_length ); if ( (status&1) == 0 ) return; printf("Font record type: %s, size: %d, count: %d\n", rtype(font->gen.type), font->gen.length, fontcount ); if ( font->gen.type != BKREC_FONT ) return; for ( i=sizeof(font->font); i < font->font.length; i+=sub->gen.length) { sub = (bkrdr_recptr) &font->reloff[i]; if ( sub->gen.type == BKSBREC_FONT ) { printf ( "Font #%d is '%s' l=%d\n", sub->fontdef.fontno, sub->fontdef.name, sub->gen.length ); } else { printf("%s subrec at offset %d, size: %d\n", rtype(sub->gen.type), i, sub->fontdef.length); printf("subrec data: \n"); sublen = sub->gen.length - sizeof(sub->gen); for ( j = 1; j <= sublen; j++ ) printf("%d%s", sub->raw[j+5], ((jraw[8] ); } } }