1#!/usr/bin/perl 2 3# Copyright 2000-2008 Robert Krawitz <rlk@alum.mit.edu> 4# 5# This program is free software; you can redistribute it and/or modify it 6# under the terms of the GNU General Public License as published by the Free 7# Software Foundation; either version 2 of the License, or (at your option) 8# any later version. 9# 10# This program is distributed in the hope that it will be useful, but 11# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 12# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 13# for more details. 14# 15# You should have received a copy of the GNU General Public License 16# along with this program; if not, write to the Free Software 17# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 18 19use Getopt::Std; 20use strict; 21 22getopts('VvO:'); 23 24use vars qw($atend 25 $stuff 26 $opt_v 27 $opt_V 28 $opt_O 29 $curoffset 30 $curpos 31 $esc 32 $initial_vertical_position 33 $page_mgmt_unit 34 $horizontal_position 35 $horizontal_unit 36 $vertical_unit 37 $vertical_position 38 $raster_x 39 $raster_y 40 $print_offsets 41 %seqtable 42 @seqkeys 43 %chartable 44 %xchartable 45 %nchartable 46 %rchartable 47 %keylengths 48 $total_length 49 @offsets); 50 51$atend = 0; 52%chartable = (); 53%xchartable = (); 54%nchartable = (); 55%rchartable = (); 56%keylengths = (); 57 58%seqtable = ( "@", 0, 59 "(R", "REMOTE", 60 "(", "VARIABLE", 61 "U", 1, 62 "\\", 2, 63 "\$", 2, 64 "r", 1, 65 "\031", 1, 66 ".", "SPECIAL", 67 "i", "SPECIAL1", 68 "\000", 2, 69 "\001", 22 70 ); 71 72map { 73 my ($xchar) = pack("C", $_); 74 if ($_ >= 32 && $_ < 127) { 75 $chartable{$xchar} = " $xchar"; 76 $xchartable{$xchar} = " *$xchar"; 77 $rchartable{$xchar} = $xchar; 78 } else { 79 $chartable{$xchar} = sprintf("%02x", $_); 80 $xchartable{$xchar} = sprintf("*%02x", $_); 81 $rchartable{$xchar} = sprintf("%02x ", $_); 82 } 83 $nchartable{$xchar} = $_; 84} (0..255); 85 86@seqkeys = (sort { length $b <=> length $a } keys %seqtable); 87 88map { $keylengths{$_} = length $_ } @seqkeys; 89 90$esc = "\033"; 91 92$curpos = 0; 93$curoffset = 0; 94 95$page_mgmt_unit = 360; 96$horizontal_unit = 180; 97$vertical_unit = 360; 98 99$initial_vertical_position = 0; 100$vertical_position = 0; 101$horizontal_position = 0; 102$print_offsets = 0; 103$total_length = 0; 104 105sub fill_buffer($) { 106 my ($where) = @_; 107 return 1 if $total_length - $curoffset >= $where; 108 my ($end) = $total_length - $curoffset; 109 if ($curpos == 0 && $end == 0) { 110 $stuff = <>; # Need to do this once to "activate" ARGV 111 $total_length = length $stuff; 112 $end = $total_length - $curoffset; 113 } 114 my ($old_end) = $end; 115 my ($tmp); 116 my ($bytes_to_read) = 16384; 117 if ($where - $end > $bytes_to_read) { 118 $bytes_to_read = $where - $end; 119 } 120 if ($curoffset >= 16384) { 121 substr($stuff, 0, $curoffset) = ""; 122 $total_length -= $curoffset; 123 $curoffset = 0; 124 } 125 while ($end < $where) { 126 my $foo = read ARGV, $tmp, $bytes_to_read; 127 $stuff .= $tmp; 128 $end += $foo; 129 $total_length += $foo; 130 if ($old_end == $end) { 131 $atend = 1; 132 return 0; 133 } else { 134 $bytes_to_read -= $end - $old_end; 135 $old_end = $end; 136 } 137 } 138 return 1; 139} 140 141sub increment_curpos($) { 142 my ($curpos_increment) = @_; 143 $curpos += $curpos_increment; 144 $curoffset += $curpos_increment; 145} 146 147# This slows things down tremendously... 148sub xdata($;$) { 149 my ($start, $end) = @_; 150 if (defined $end) { 151 return substr($stuff, $start + $curoffset, $end); 152 } else { 153 return substr($stuff, $start + $curoffset); 154 } 155} 156 157sub do_remote_command() { 158 print "\n"; 159 printf "%08x ", $curpos; 160 print "1b ( R "; 161 increment_curpos(3); 162 fill_buffer(2); 163 my $lchar = substr($stuff, $curoffset + 0, 1); 164 my $nlchar = $nchartable{$lchar}; 165 my $hchar = substr($stuff, $curoffset + 1, 1); 166 my $nhchar = $nchartable{$hchar}; 167 printf " %02x %02x ", $nlchar, $nhchar; 168 my $skipchars = ($nhchar * 256) + $nlchar; 169 increment_curpos(2); 170 fill_buffer($skipchars); 171 for (my $i = 0; $i < $skipchars; $i++) { 172 print $rchartable{substr($stuff, $curoffset + $i, 1)}; 173 } 174 increment_curpos($skipchars); 175 while (fill_buffer(2) && 176 substr($stuff, $curoffset + 0, 2) =~ /[A-Z0-9][A-Z0-9]/) { 177 print "\n"; 178 printf "%08x ", $curpos; 179 my ($cmd) = substr($stuff, $curoffset + 0, 2); 180 print $cmd; 181 increment_curpos(2); 182 fill_buffer(2); 183 $lchar = substr($stuff, $curoffset + 0, 1); 184 $nlchar = $nchartable{$lchar}; 185 $hchar = substr($stuff, $curoffset + 1, 1); 186 $nhchar = $nchartable{$hchar}; 187 if ($cmd eq "DF") { 188 $skipchars = 0; 189 } else { 190 $skipchars = ($nhchar * 256) + $nlchar; 191 } 192 printf " %02x %02x ", $nlchar, $nhchar; 193 increment_curpos(2); 194 fill_buffer($skipchars); 195 printf "%*v02x ", " ", substr($stuff, $curoffset, $skipchars); 196 increment_curpos($skipchars); 197 } 198} 199 200sub print_prefix_bytes($$) { 201 my ($bytes_to_print) = @_; 202 print "\n"; 203 printf "%08x ", $curpos; 204 print "1b "; 205 fill_buffer($bytes_to_print); 206 my $char = substr($stuff, $curoffset + 1, 1); 207 print "$chartable{$char} "; 208 printf "%*v02x ", " ", substr($stuff, $curoffset + 2, $bytes_to_print - 2); 209 increment_curpos($bytes_to_print); 210} 211 212sub print_output_data($$$$$$) { 213 my ($comptype, $bitsperpixel, $dots, $rows, $dot_scale, $color) = @_; 214 my $counter; 215 my $fchar; 216 my $last_row = 0; 217 my $first_row = -1; 218 my $i; 219 my $vstuff; 220 $dots *= 8; 221 $dots /= $dot_scale; 222 my $real_dots = $dots / $bitsperpixel; 223 if ($opt_v) { 224 print " ($real_dots dots, $rows rows, $bitsperpixel bits"; 225 } 226 my $savedots = $dots; 227 if ($comptype == 0) { 228 fill_buffer($dots / 8); 229 if ($opt_V) { 230 printf "%*v02x ", " ", substr($stuff, $curoffset + 0, $dots / 8); 231 } 232 increment_curpos($dots / 8); 233 } elsif ($comptype == 1) { 234 foreach $i (0..$rows-1) { 235 my ($found_something) = 0; 236 $dots = $savedots; 237 my ($tstuff) = "\n $i "; 238 while ($dots > 0) { 239 fill_buffer(1); 240 $counter = ord(substr($stuff, $curoffset + 0, 1)); 241 increment_curpos(1); 242 if ($counter <= 127) { 243 $counter++; 244 fill_buffer($counter); 245 if ($opt_v || $opt_V) { 246 my $tmp = sprintf "%*v02x ", " ", substr($stuff, $curoffset + 0, $counter); 247 if (!($tmp =~ /^[0 ]+$/)) { 248 $found_something = 1; 249 $last_row = $i; 250 if ($first_row == -1) { 251 $first_row = $i; 252 } 253 } 254 if ($opt_V) { 255 $tstuff .= $tmp; 256 } 257 } 258 increment_curpos($counter); 259 } else { 260 $counter = 257 - $counter; 261 fill_buffer(1); 262 if ($opt_v || $opt_V) { 263 $fchar = sprintf "%v02x ", substr($stuff, $curoffset + 0, 1); 264 if ($fchar ne "00 ") { 265 $found_something = 1; 266 $last_row = $i; 267 if ($first_row == -1) { 268 $first_row = $i; 269 } 270 } 271 } 272 if ($opt_V) { 273 map { $tstuff .= $fchar } (0..$counter - 1); 274 } 275 increment_curpos(1); 276 } 277 $dots -= $counter * 8; 278 } 279 if ($opt_V && $found_something) { 280 $vstuff .= $tstuff; 281 } 282 } 283 } else { 284 print "\nUnknown compression type $comptype!\n"; 285 } 286 if ($opt_v) { 287 my ($offset) = $offsets[$color]; 288 my ($first_position) = ($vertical_position / $vertical_unit) 289 + ($first_row + $offset) * $raster_y; 290 my ($last_position) = ($vertical_position / $vertical_unit) 291 + ($last_row + $offset) * $raster_y; 292 my ($final_position) = ($vertical_position / $vertical_unit) 293 + ($rows + $offset) * $raster_y; 294 my ($final_horizontal) = $horizontal_position + 295 ($real_dots * $page_mgmt_unit * $raster_x); 296 if ($print_offsets) { 297 printf (" %d,%d+%d %.4f %d,%d+%d %.4f %.4f) ", 298 $horizontal_position, $first_row, $offset, $first_position, 299 $final_horizontal, $last_row, $offset, $last_position, 300 $final_position); 301 } else { 302 printf (" %d,%d %.4f %d,%d %.4f %.4f) ", 303 $horizontal_position, $first_row, $first_position, 304 $final_horizontal, $last_row, $last_position, 305 $final_position); 306 } 307 } 308 if ($opt_V) { 309 print " $vstuff"; 310 } 311} 312 313sub do_special_command() { 314 fill_buffer(8); 315 my $comptype = $nchartable{substr($stuff, $curoffset + 2, 1)}; 316 my $color = 0; 317 my $dots = unpack("v", substr($stuff, $curoffset + 6, 2)); 318 my $rows = $nchartable{substr($stuff, $curoffset + 5, 1)}; 319 print_prefix_bytes(8, 2); 320 print_output_data($comptype, 1, $dots, $rows, 8, $color); 321 fill_buffer(1); 322 while (substr($stuff, $curoffset + 0, 1) eq "\r") { 323 fill_buffer(1); 324 increment_curpos(1); 325 } 326} 327 328sub do_special1_command() { 329 fill_buffer(9); 330 my $color = $nchartable{substr($stuff, $curoffset + 2, 1)}; 331 my $comptype = $nchartable{substr($stuff, $curoffset + 3, 1)}; 332 my $bitsperpixel = $nchartable{substr($stuff, $curoffset + 4, 1)}; 333 my $dots = unpack("v", substr($stuff, $curoffset + 5, 2)); 334 my $rows = unpack("v", substr($stuff, $curoffset + 7, 2)); 335 print_prefix_bytes(9, 1); 336 print_output_data($comptype, $bitsperpixel, $dots, $rows, 1, $color); 337 fill_buffer(1); 338 while (substr($stuff, $curoffset + 0, 1) eq "\r") { 339 fill_buffer(1); 340 increment_curpos(1); 341 } 342} 343 344sub get_long($) { 345 my ($string) = @_; 346 my ($tmp) = unpack("V", $string); 347 if ($tmp >= (1 << 31)) { 348 return -(0xffffffff ^ $tmp) - 1; 349 } else { 350 return $tmp; 351 } 352} 353 354sub get_short($) { 355 my ($string) = @_; 356 my ($tmp) = unpack("v", $string); 357 if ($tmp >= (1 << 15)) { 358 return -(0xffff ^ $tmp) - 1; 359 } else { 360 return $tmp; 361 } 362} 363 364sub get_byte($) { 365 my ($string) = @_; 366 return $nchartable{$string}; 367} 368 369if ($opt_O) { 370 my (@stuff) = split(/,/, $opt_O); 371 map { 372 my ($key, $val) = split(/=/, $_); 373 if ($val) { 374 $print_offsets = 1; 375 } 376 @offsets[$key] = $val; 377 } @stuff; 378} 379 380while (! $atend) { 381 my $found; 382 my $key; 383 my $skipchars; 384 my $startoff; 385 my $kchar; 386 my $nkchar; 387 my $lchar; 388 my $nlchar; 389 my $hchar; 390 my $nhchar; 391 my $i; 392 my $char; 393 my $nchar; 394 my $bytes; 395 my ($maxklen) = $keylengths{$seqkeys[0]}; 396 fill_buffer(1); 397 my $cchar = substr($stuff, $curoffset + 0, 1); 398 if ($cchar eq "$esc") { 399 $found = 0; 400 fill_buffer(2 + $maxklen); 401 foreach $key (@seqkeys) { 402 my ($klen) = $keylengths{$key}; 403 if (substr($stuff, $curoffset + 1, $klen) eq $key) { 404 $skipchars = $seqtable{$key}; 405 if ($skipchars eq "SPECIAL") { 406 do_special_command(); 407 $found = 2; 408 } elsif ($skipchars eq "SPECIAL1") { 409 do_special1_command(); 410 $found = 2; 411 } elsif ($skipchars eq "REMOTE") { 412 do_remote_command(); 413 $found = 2; 414 } else { 415 print "\n"; 416 printf "%08x ", $curpos; 417 print "1b "; 418 $startoff = 0; 419 my $print_stuff = 0; 420 my $print_variable = 0; 421 if ($skipchars eq "VARIABLE") { 422 fill_buffer(3); 423 $print_variable = 1; 424 $kchar = substr($stuff, $curoffset + $klen + 1, 1); 425 $nkchar = unpack("C", $kchar); 426 $lchar = substr($stuff, $curoffset + $klen + 2, 1); 427 $nlchar = unpack("C", $lchar); 428 $hchar = substr($stuff, $curoffset + $klen + 3, 1); 429 $nhchar = unpack("C", $hchar); 430 $skipchars = ($nhchar * 256) + $nlchar; 431 $startoff = 3; 432 $print_stuff = 1; 433 } 434 my ($blen) = $skipchars + $klen + $startoff; 435 fill_buffer($blen + 1); 436 $char = substr($stuff, $curoffset + 1, 1); 437 print "$chartable{$char} "; 438 if ($blen > 1) { 439 $char = substr($stuff, $curoffset + 2, 1); 440 print "$chartable{$char} "; 441 if ($blen > 2) { 442 if ($print_variable && $char eq "d") { 443 printf ("%*v02x ", " ", 444 substr($stuff, $curoffset + 3, 2)); 445 } else { 446 printf ("%*v02x ", " ", 447 substr($stuff, $curoffset + 3, $blen - 2)); 448 } 449 } 450 } 451 if ($print_stuff) { 452 my $xchar = substr($stuff, $curoffset + 2, 1); 453 if ($xchar eq "c") { 454 my ($top, $bottom); 455 if ($skipchars == 8) { 456 $top = get_long(substr($stuff, $curoffset + 5, 4)); 457 if ($opt_v) { 458 $bottom = get_long(substr($stuff, $curoffset + 9, 4)); 459 } 460 } else { 461 $top = get_short(substr($stuff, $curoffset + 5, 2)); 462 if ($opt_v) { 463 $bottom = get_short(substr($stuff, $curoffset + 7, 2)); 464 } 465 } 466 if ($opt_v) { 467 printf (" (page format %d %d %.2f %.2f)", 468 $top, $bottom, $top / $page_mgmt_unit, 469 $bottom / $page_mgmt_unit); 470 } 471 $initial_vertical_position = 472 $top * $vertical_unit / $page_mgmt_unit; 473 $vertical_position = $initial_vertical_position; 474 } elsif ($xchar eq "S") { 475 if ($opt_v) { 476 my ($width, $height); 477 if ($skipchars == 8) { 478 $width = get_long(substr($stuff, $curoffset + 5, 4)); 479 $height = get_long(substr($stuff, $curoffset + 9, 4)); 480 } else { 481 $width = get_short(substr($stuff, $curoffset + 5, 2)); 482 $height = get_short(substr($stuff, $curoffset + 7, 2)); 483 } 484 printf (" (paper size %d %d %.2f %.2f)", 485 $width, $height, $width / $page_mgmt_unit, 486 $height / $page_mgmt_unit); 487 } 488 } elsif ($xchar eq "C") { 489 if ($opt_v) { 490 my ($length); 491 if ($skipchars == 4) { 492 $length = get_long(substr($stuff, $curoffset + 5, 4)); 493 } else { 494 $length = get_short(substr($stuff, $curoffset + 5, 2)); 495 } 496 printf (" (page length %d %.2f)", 497 $length, $length / $page_mgmt_unit); 498 } 499 } elsif ($xchar eq "D") { 500 my $base = get_short(substr($stuff, $curoffset + 5, 2)); 501 my $y = $nchartable{substr($stuff, $curoffset + 7, 1)}; 502 my $x = $nchartable{substr($stuff, $curoffset + 8, 1)}; 503 $raster_x = $x / $base; 504 $raster_y = $y / $base; 505 if ($opt_v) { 506 printf (" (raster base %d, %d x %d)", 507 $base, $base / $x, $base / $y); 508 } 509 } elsif ($xchar eq "U") { 510 if ($skipchars == 5) { 511 my $page_mgmt = $nchartable{substr($stuff, $curoffset + 5, 1)}; 512 my $vertical = $nchartable{substr($stuff, $curoffset + 6, 1)}; 513 my $horiz = $nchartable{substr($stuff, $curoffset + 7, 1)}; 514 my $scale = get_short(substr($stuff, $curoffset + 8, 2)); 515 $page_mgmt_unit = $scale / $page_mgmt; 516 $horizontal_unit = $scale / $horiz; 517 $vertical_unit = $scale / $vertical; 518 if ($opt_v) { 519 printf (" (units base %d mgmt %d vert %d horiz %d)", 520 $scale, $page_mgmt_unit, 521 $vertical_unit, $horizontal_unit); 522 } 523 } else { 524 my $page_mgmt = $nchartable{substr($stuff, $curoffset + 5, 1)}; 525 if ($opt_v) { 526 printf " (units base = %d/3600)", $page_mgmt; 527 } 528 $page_mgmt_unit = 3600 / $page_mgmt; 529 $horizontal_unit = 3600 / $page_mgmt; 530 $vertical_unit = 3600 / $page_mgmt; 531 } 532 } elsif ($xchar eq "v") { 533 my ($length); 534 if ($skipchars == 4) { 535 $length = get_long(substr($stuff, $curoffset + 5, 4)); 536 } else { 537 $length = get_short(substr($stuff, $curoffset + 5, 2)); 538 } 539 $vertical_position += $length; 540 if ($opt_v) { 541 printf (" (skip vertical %d at %d %.4f)", 542 $length, $vertical_position, 543 $vertical_position / $vertical_unit); 544 } 545 } elsif ($xchar eq "\$") { 546 if ($skipchars == 4) { 547 $horizontal_position = 548 get_long(substr($stuff, $curoffset + 5, 4)); 549 } else { 550 $horizontal_position = 551 get_short(substr($stuff, $curoffset + 5, 2)); 552 } 553 if ($opt_v) { 554 printf (" (horizontal position %d %.4f)", 555 $horizontal_position, 556 $horizontal_position / $horizontal_unit); 557 } 558 } elsif ($xchar eq "d") { 559 if ($opt_v) { 560 printf " (nop)"; 561 } 562 } 563 } 564 $found = 1; 565 } 566 $bytes = $klen + 1 + $skipchars + $startoff; 567 last; 568 } 569 } 570 if (! $found) { 571 print "\n"; 572 printf "%08x ", $curpos; 573 print "1b "; 574 increment_curpos(1); 575 } elsif ($found == 1) { 576 increment_curpos($bytes); 577 } 578 } elsif ($cchar eq "\0" || $cchar eq "\f") { 579 printf "\n%08x ", $curpos; 580 print "$chartable{$cchar} "; 581 $vertical_position = $initial_vertical_position; 582 increment_curpos(1); 583 } else { 584 print "$xchartable{$cchar} " if ($cchar ne "\021"); 585 increment_curpos(1); 586 } 587} 588 589print "\n" if $curpos > 1; 590 591