#!/usr/bin/perl # # generate a Matlab function for reading or writing the header of a GE raw # data file: i.e., translate the POOL_HEADER (defined in given rdbm.h and # imagedb.h GE source files) into Matlab code # # usage: gehdr2matlab [-w] rdbm.h imagedb.h [>func.m] # # if the optional "-w" option is provided, a Matlab script is generated for # writing the header structure (the default is to generate a script for reading) # # conversion from C types -> Matlab types: # float -> float # double -> double # short -> short # long -> long # int -> int # char -> char # unsigned long -> ulong # unsigned short -> ushort # unsigned int -> uint # # note: when reading data with 'fread()' all numeric values are internally # converted to doubles by Matlab (this is desirable because most of Matlab's # math functions are only permitted on type double). however, '*char' is used # instead of 'char' keeps the source and destination formats the same (i.e., # character stings). # # the following non-standard GE-defined data types are handled by kluges: # BLOCK # ATOMIC # VARTYPE # DIMXYTYP # IMATRIXTYPE # PIXSIZETYPE # RASPOINT # RDB_MULTI_RCV_TYPE # RDB_SLICE_INFO_ENTRY # RDB_DATA_ACQ_TAB # # DB Clayton (Feb 17, 2004) #- # parse command line args if ($#ARGV < 0) {die "usage: gehdr2matlab [-w] rdbm.h imagedb.h [>func.m]\n";} $io = ($ARGV[0] eq '-w') ? 'write' : 'read'; if ($io eq 'write') {shift;} $rdbm_h = shift; $imagedb_h = shift; # read struct and revision in rdbm.h open(H, "< $rdbm_h") || die "ERROR: could not open rdbm.h file '$rdbm_h'\n"; while () { if (/#define\s+RDB_RDBM_REVISION\s+(.*)\s*/) {$rev = $1;} if (/^\s*typedef\s*struct/) {@str = ();} # start of new C struct if (/^\s*}\s*RDB_HEADER_REC\s*;/) {@rdb = @str; last;} push(@str, $_); } close(H); # read structs in imagedb.h open(H, "< $imagedb_h") || die "ERROR: could not open imagedb.h file '$imagedb_h'\n"; while () { if (/^\s*typedef\s*struct/) {@str = ();} # start of new C struct if (/^\s*}\s*EXAMDATATYPE\s*;/) {@exam = @str; next;} if (/^\s*}\s*SERIESDATATYPE\s*;/) {@series = @str; next;} if (/^\s*}\s*MRIMAGEDATATYPE\s*;/) {@image = @str; next;} push(@str, $_); } close(H); # global definitions $len_rdb_per_pass_tab = 4096; $len_rdb_nex_type = 2052; $len_toolsdata = 2048; $slice_factor = ($rev < 8.0) ? 1 : 2; $rdb_max_slices = 512; # convert the C code into Matlab code and print the resulting function to stdout print_start_func($io, $rev); print_struct('rdb', \@rdb, $io); print_line($io, 'per_pass', 'char', $len_rdb_per_pass_tab, '% lumped type RDB_PER_PASS_TAB'); print_line($io, 'unlock_raw', 'char', $len_rdb_per_pass_tab, '% lumped type RDB_PER_PASS_TAB'); print_struct('data_acq_tab', [RDB_DATA_ACQ_TAB], $io); print_line($io, 'nex_tab', 'char', $len_rdb_nex_type, '% lumped type RDB_NEX_TYPE'); print_line($io, 'nex_abort_tab', 'char', $len_rdb_nex_type, '% lumped type RDB_NEX_TYPE'); print_line($io, 'tool', 'char', $len_toolsdata, '% lumped type TOOLSDATA'); print_struct('exam', \@exam, $io); print_struct('series', \@series, $io); print_struct('image', \@image, $io); # # subroutines # # convert each line of C code to Matlab sub print_struct { my ($h, $str, $io) = @_; my ($c, $type, $name, $comment); my $n = 0; # byte offset used for struct alignment # recognized C types my $ctypes = 'float|double|short|long|int|char|unsigned long|unsigned short|unsigned int'; foreach $c (@{$str}) { # convert to equivalent C types $c =~ s/^\s*short int/short/; $c =~ s/^\s*unsigned short int/unsigned short/; # kluges for types defined by GE $c =~ s/^\s*BLOCK/char/; $c =~ s/^\s*ATOMIC/long/; $c =~ s/^\s*DIMXYTYPE/float/; $c =~ s/^\s*IMATRIXTYPE/short/; $c =~ s/^\s*PIXSIZETYPE/float/; $c =~ s/^\s*RASPOINT/float/; if ($c =~ /^\s*VARTYPE\s+(.+?);(.*)/) {vartype_type(\$n, $io, "hdr.$h.$1"); next;} if ($c =~ /^\s*RDB_MULTI_RCV_TYPE/) {multi_rcv_type(\$n, $io, "hdr.$h"); next;} if ($c =~ /^\s*RDB_DATA_ACQ_TAB/) {rdb_data_acq_tab_type(\$n, $io, "hdr.$h"); next;} # parse the line of C code and generate the equivalent Matlab code if ($c =~ /^\s*($ctypes)\s+(.+?);(.*)/) { # get C variable name, type, size, and comment ($type, $name, $comment) = ($1, $2, $3); $size = 1; while ($name =~ s/\[(\d+)\]//) {$size *= $1;} # convert to Matlab type $type =~ s/unsigned (short|long|int)/u$1/; if ($io eq 'read') {$type =~ s/char/*char/;} # for fread only # convert to Matlab comments $comment =~ s/\s*\/\*(.*)\*\/\s*/% $1/; # comment on single line $comment =~ s/\s*\/\*(.*)/% $1 (continued...)/; # comment spans multiple lines $comment =~ s/\s+/ /g; # compress white space # modify variable name $name =~ s/\s+$//; # strip any trailing white space $name =~ s/rdb_hdr_//; # strip 'rdb_hdr_' part from variable name $name =~ s/^3dwin/win3d/; # change variable name to conform with Matlab restrictions if ($name =~ /^\d/) { die "ERROR: can't convert C variable '$name': Matlab variables can't begin with a number\n"; } # print the Matlab code ###print "[$n]\t"; # DEBUG ONLY! print_line($io, "$h.$name", $type, $size, $comment, \$n); } } ###print "*** END OF STRUCT (length = $n) ***\n\n"; # DEBUG ONLY! } # handle byte alignment for structs and print the line(s) of Matlab code sub print_line { my ($io, $name, $type, $size, $comment, $n) = @_; my ($l, $b); # num bytes for this var, num bytes to shift for proper alignment my $tr = ($type eq '*char') ? "'": ""; # transpose character arrays # get proper byte alignment SWITCH: { if ($type =~ /(float|int|long)/) { $b = ${$n} % 4; $b = ($b == 0) ? 0: 4 - $b; $l = $size * 4; last SWITCH; } if ($type =~ /(double)/) { $b = ${$n} % 8; $b = ($b == 0) ? 0: 8 - $b; $l = $size * 8; last SWITCH; } if ($type =~ /(short)/) { $b = ${$n} % 2; $b = ($b == 0) ? 0: 2 - $b; $l = $size * 2; last SWITCH; } $l = $size; $b = 0; } ${$n} += $l + $b; # update the struct offset # print the appropriate line(s) of Matlab code if ($io eq 'read') { if ($b > 0) {print "fseek(id, $b, 0); % kluge for struct byte alignment\n";} print "hdr.$name = fread(id, $size, '$type')$tr; $comment\n"; } else { if ($b > 0) {print "fwrite(id, zeros(1,$b), 'char'); % kluge for struct byte alignment\n";} print "fwrite(id, hdr.$name, '$type'); $comment\n"; } } # kluge for RDB_DATA_ACQ_TAB struct (which is an array of RDB_SLICE_INFO_ENTRY structs) sub rdb_data_acq_tab_type { my ($n, $io, $h) = @_; my $len = $slice_factor * $rdb_max_slices; if ($io eq 'write') { print <> id = fopen('P12345.7', 'r', 'l'); % >> hdr = read_gehdr(id); % % note: Raw file must have RDB_RDBM_REVISION = $rev % This script was generated from GE source using 'gehdr2matlab' written by DB Clayton fseek(id, 0, -1); % go to start of raw data file END_START_READ_GEHDR } else { print <> id = fopen('P12345.7', 'w', 'l'); % >> write_gehdr(id, hdr); % This script was generated from GE source using 'gehdr2matlab' written by DB Clayton END_START_WRITE_GEHDR } }