LEX 'SHUTTLEX' ID #92 MSG 0 POLL 0 ENTRY S00078 CHAR #F ENTRY S00082 CHAR #F KEY 'CPRSRG$' TOKEN 1 KEY 'EXPDRG$' TOKEN 2 NIBHEX 1FF ***************************************** * SHUTTLEX provides two functions that allow you to "compress" and "expand" * raster graphics data strings. This allows you to store graphics data in TEXT * files that may take as little as 1/5 of the RAM required if the data were not * compressed. See SHUTLDOC for further details. * * A$=CPRSRG$(B$) : A$ holds the packed form of B$ * B$=EXPDRG$(A$) : B$ holds the original raster graphics data * * Example: 00 00 00 00 00 00 55 FF FF FF FF FF becomes 00 05 55 FF 04 * (HEX representation of ASCII strings) * * The above method takes advantage of the fact that most plots have only a few * pixels on in any given row of graphics. The rest of the graphics data is * either 00 bytes (blank areas). Occasionally, an area is filled with FF bytes * (solid black fill) for contrast. The above method allows you to represent a * string of up to 256 FF or 00 bytes with a two byte equivalent: FF FF or 00 FF * * If you work with the thinjet, your raster data strings will be at most 160 * bytes long, not including escape sequences (1280 pixels/row/8 bits/byte). * Other printers may require longer strings. * * SHUTTLEX can actually handle any number of consecutive 00 or FF bytes, up to * the maximum string length allowed by the HP-71. * * CAUTION: if you try to expand an artificially contrieved string such as * EXPDRG$(RPT$(CHR$(255),????)), you risk a memory lost if the resulting * expanded exceeds the 65K maximum length. * * Disassembly and comments by Michael Markov, 1988 * ************************************************ NIBHEX 411 CPRSRG$ entry point S00078 ST=0 1 compress / expand toggle GOTO S00085 NIBHEX 411 EXPDRG$ entry point S00082 ST=1 1 S00085 SETHEX GOSBVL #0BD31 =REVPOP CD0EX save D0 in R0 CR0EX CD1EX D0=C D0,D1 @ first byte in string, D1=C which is in reverse order LCHEX 00000 clear B[A] - why not B=0 A? BCEX A GOSBVL #1A460 =D=AVMS set up D[A] for memcheck S000AD ?A=0 A zero lenght parameter or end of parm? (main loop) GOYES S000D5 yes, done! C=DAT0 B read the byte D0=D0+ 2 advance input pointer A=A-1 A decrement the length of string counter A=A-1 A GOSBVL #18504 =STKCHR add byte to output string B=B+1 A incr counter in B[A], byte lenght of output string ?C=0 B if an 00 byte, GOYES S000D9 go do 00 byte handling C=C+1 B is it FF? (should follow-up with GOC S00115) ?C=0 B GOYES S00115 go do FF byte handling GONC S000AD if neither, repeat main loop S000D5 GOTO S0017F main loop exit S000D9 ?ST=1 1 00 byte handler GOYES S00153 go expand 00 bytes LCHEX 00 add 00 byte - PACK00 (counter byte) GOSBVL #18504 =STKCHR B=B+1 A increment output string lenght pointer S000EB ?A=0 A check for end of input string GOYES S000D5 if yes, we are done, main loop exit C=DAT0 B no, read next byte ?C#0 B if not an 00 byte, return to mainloop GOYES S000AD C=DAT1 B increment counter byte if another 00 C=C+1 B ?C=0 B until we reach the maximum count of 255 GOYES S000AD (should use GOC S000AD) if more, mainloop DAT1=C B D0=D0+ 2 to next byte in input string A=A-1 A decrement length counter by one byte/2 nibbles A=A-1 A GOTO S000EB repeat PACK00 loop S00111 GOTO S000AD S00115 C=C-1 B FF byte handler. set C[B] = FF ?ST=1 1 GOYES S00153 go expand FF bytes LCHEX 00 PACKFF - add the FF counter byte GOSBVL #18504 =STKCHR B=B+1 A increment output string length accordingly S0012A ?A=0 A done with input string? GOYES S0017F if yes, main loop exit C=DAT0 B read byte from input string C=C+1 B test for FF ?C#0 B if not FF (should use GONC S000AD or S000111) GOYES S00111 go do main loop C=DAT1 B increment FF counter byte C=C+1 B and repeat until max allowable count ?C=0 B (should use GOC S00111) GOYES S00111 DAT1=C B store incremented counter D0=D0+ 2 @ next input byte A=A-1 A decrement input lenght counter by 2 nibs A=A-1 A GOTO S0012A repeat PACKFF * the routine below expands both FF and 00 bytes. On entry, C[B] is either * FF or 00, depending on what needs to be expanded. For simplicity's sake, I * describe the process in terms of expanding a byte pair FFxx. The xx portion * is replaced with xx bytes with value FF. S00153 CR1EX Expand FF bytes - save FF in R1[B] ?A=0 A last input byte (are we done?) GOYES S00111 yes, return to main loop C=DAT0 B no, read FF counter byte D0=D0+ 2 advance input pointer A=A-1 A decrement lenght of input counter A=A-1 A by two nibs=one byte S00165 ?C=0 B if counter byte is 00 GOYES S00111 then return to main loop CR1EX exchange FF byte and FF counter GOSBVL #18504 =STKCHR add FF byte to output string B=B+1 A increment output string counter CR1EX exchange FF byte with counter C=C-1 A decrement counter GOTO S00165 repeat until counter is zero * mainloop exit - last byte has been processed S0017F AD0EX save input pointer in A[A] D1=D1- 2 set D0 to start of output string CD1EX this is current output pointer position C=C+B A plus the output string byte counter C=C+B A twice, for nibble address CD0EX D0 @ start of source D1=A set D1 to top of input string (@ Destination) R1=A set-up R1 for ADHEAD S00195 ?B=0 A is the output string a null$? GOYES S001AC skip move up routine (why not use a mainframe move C=DAT0 B routine?) read byte D0=D0- 2 set-up next byte B=B-1 A decrement counter GOSBVL #18504 =STKCHR store byte at higher address * note that D1=D1- 2 DAT1=C B is faster & shorter. No need to check memory, * we are only recovering the space used by the input string GONC S00195 B.E.T - move whole string up. S001AC ST=1 0 set S0 to return from ADHEAD GOSBVL #181B7 =ADHEAD CR0EX restore D0 CD0EX GOVLNG #0F23C =EXPR Done, at last! END * we can save a few nibs in the last sequence: * S001AC CR0EX * CD0EX * ST=0 0 * GOVLNG #181B7 =ADHEAD