Dilwyn,
attached is a file that decodes a SAV file - as promised. Hope you can
read my code after all these years!
Cheers,
Norman.
1000 REMark _SAV file decoder
1005 :
1010 CLS
1015 PRINT 'SAV File Decoder'\\
1020 INPUT 'Which _sav file ? ';sav$
1025 IF sav$ = '' THEN STOP: END IF
1030 :
1035 initialise
1040 decode_header
1045 IF NOT quit
1050 decode_name_table
1055 decode_program
1060 END IF
1065 RELEASE_HEAP float_buffer
1070 CLOSE #3
1075 :
1080 DEFine PROCedure decode_header
1085 LOCal head$(4), name_table_length
1090 quit = 0
1095 OPEN_IN #3,sav$
1100 head$ = FETCH_BYTES(#3, 4)
1105 IF (head$ <> 'Q1' & CHR$(0) & CHR$(0)) AND (head$ <> 'Q1' & CHR$(2) &
CHR$(192))
1110 PRINT head$, head$(1);head$(2)!!CODE(head$(3))!CODE(head$(4))\
1115 PRINT sav$ & ' is not a SAV file, or has a new flag.'
1120 CLOSE #3
1125 quit = 1
1130 RETurn
1135 END IF
1140 name_table_entries = GET_WORD(#3)
1145 name_table_length = GET_WORD(#3)
1150 program_lines = GET_WORD(#3)
1155 max_name_size = name_table_length - (4 * name_table_entries) /
name_table_entries
1160 :
1165 PRINT sav$
1170 PRINT 'Number of name table entries : '; name_table_entries
1175 PRINT 'Name table length : '; name_table_length
1180 PRINT 'Number of program lines : '; program_lines
1185 PRINT
1190 :
1195 DIM name_table$(name_table_entries -1, max_name_size)
1200 float_buffer = RESERVE_HEAP(6)
1205 quit = (float_buffer < 1)
1210 END DEFine decode_header
1215 :
1220 DEFine PROCedure decode_name_table
1225 LOCal x, name_type, line_no, name_length, name$, lose_it$(1)
1230 LOCal num_procs, num_fns
1235 num_procs = 0
1240 num_fns = 0
1245 FOR x = 0 TO name_table_entries -1
1250 name_type = GET_WORD(#3)
1255 line_no = GET_WORD(#3)
1260 name_length = GET_WORD(#3)
1265 name$ = FETCH_BYTES(#3, name_length)
1270 IF name_length && 1
1275 lose_it$ = INKEY$(#3)
1280 END IF
1285 IF name_type = 5122 THEN num_procs = num_procs + 1
1290 IF name_type >= 5377 AND name_type <= 5379
1295 num_fns = num_fns + 1
1300 END IF
1305 PRINT x;' Name type = '; HEX$(name_type, 16) & ' ';
1310 PRINT 'Line number = '; line_no & ' ';
1315 PRINT 'Name length = '; name_length; ' ';
1320 PRINT 'Name = <' & name$ & '>'
1325 name_table$(x) = name$
1330 END FOR x
1335 PRINT 'There are ' & num_procs & ' PROCs'
1340 PRINT 'There are ' & num_fns & ' FNs'
1345 END DEFine decode_name_table
1350 :
1355 :
1360 DEFine PROCedure decode_program
1365 LOCal x, type_byte, program_line
1370 :
1375 REMark WORD = size change
1380 REMark LONG = $8D00.line number
1385 REMark rest of line
1390 :
1395 REPeat program_line
1400 IF EOF(#3) THEN EXIT program_line: END IF
1405 line_size = line_size + GET_WORD(#3)
1410 IF line_size > 65536 THEN line_size = line_size - 65536: END IF
1415 IF GET_WORD(#3) <> HEX('8d00')
1420 PRINT 'Program out of step.'
1425 CLOSE #3
1430 STOP
1435 END IF
1440 PRINT GET_WORD(#3); ' ';
1445 line_done = 0
1450 REPeat line_contents
1455 type_byte = CODE(INKEY$(#3))
1460 SELect ON type_byte
1465 = HEX('80'): multi_spaces
1470 = HEX('81'): keywords
1475 = HEX('84'): symbols
1480 = HEX('85'): operators
1485 = HEX('86'): monadics
1490 = HEX('88'): names
1495 = HEX('8B'): strings
1500 = HEX('8C'): text
1505 = HEX('8E'): separators
1510 = REMAINDER : floating_points
1515 END SELect
1520 IF line_done THEN EXIT line_contents: END IF
1525 END REPeat line_contents
1530 END REPeat program_line
1535 END DEFine decode_program
1540 :
1545 :
1550 DEFine PROCedure multi_spaces
1555 :
1560 REMark $80.nn = print nn spaces
1565 :
1570 PRINT FILL$(' ', GET_BYTE(#3));
1575 END DEFine multi_spaces
1580 :
1585 :
1590 DEFine PROCedure keywords
1595 :
1600 REMark $81.nn = keyword$(nn)
1605 :
1610 PRINT keyword$(GET_BYTE(#3));' ';
1615 END DEFine keywords
1620 :
1625 :
1630 DEFine PROCedure symbols
1635 LOCal sym
1640 :
1645 REMark $84.nn = symbol$(nn)
1650 :
1655 sym = GET_BYTE(#3)
1660 PRINT symbol$(sym);
1665 line_done = (sym = 10)
1670 END DEFine symbols
1675 :
1680 :
1685 DEFine PROCedure operators
1690 :
1695 REMark $85.nn = operator$(nn)
1700 :
1705 PRINT operator$(GET_BYTE(#3));
1710 END DEFine operators
1715 :
1720 :
1725 DEFine PROCedure monadics
1730 :
1735 REMark $86.nn = monadic$(nn)
1740 :
1745 PRINT monadic$(GET_BYTE(#3));
1750 END DEFine monadic
1755 :
1760 :
1765 DEFine PROCedure names
1770 LOCal ignore
1775 :
1780 REMark $8800.nnnn = name_table$(nnnn)
1785 :
1790 ignore = GET_BYTE(#3)
1795 ignore = GET_WORD(#3)
1800 IF ignore > 32768 THEN ignore = ignore - 32768: END IF
1805 PRINT name_table$(ignore);
1810 END DEFine names
1815 :
1820 :
1825 DEFine PROCedure strings
1830 LOCal delim$(1), size
1835 :
1840 REMark $8B.delim.string_size = 'delim'; string; 'delim'
1845 :
1850 delim$ = INKEY$(#3)
1855 size = GET_WORD(#3)
1860 PRINT delim$; FETCH_BYTES(#3, size); delim$;
1865 IF size && 1
1870 size = GET_BYTE(#3)
1875 END IF
1880 END DEFine strings
1885 :
1890 :
1895 DEFine PROCedure text
1900 LOCal size
1905 :
1910 REMark $8C00.size = text
1915 :
1920 size = GET_BYTE(#3)
1925 size = GET_WORD(#3)
1930 PRINT FETCH_BYTES(#3, size);
1935 IF size && 1
1940 size = GET_BYTE(#3)
1945 END IF
1950 END DEFine text
1955 :
1960 :
1965 DEFine PROCedure separators
1970 :
1975 REMark $8E.nn = separator$(nn)
1980 :
1985 PRINT separator$(GET_BYTE(#3));
1990 END DEFine separators
1995 :
2000 :
2005 DEFine PROCedure floating_points
2010 LOCal number$(6)
2015 :
2020 REMark $Fx.xx.xx.xx.xx.xx - need to mask out the first $F !
2025 :
2030 MOVE_POSITION #3, -1: REMark back up to the first byte
2035 number$ = FETCH_BYTES(#3, 6)
2040 number$(1) = CHR$( CODE(number$(1)) && 15)
2045 POKE_STRING float_buffer, number$
2050 PRINT PEEK_FLOAT(float_buffer);
2055 END DEFine floating_points
2060 :
2065 :
2070 DEFine PROCedure initialise
2075 LOCal x
2080 :
2085 quit = 0
2090 last_line_size = 0
2095 line_size = 0
2100 name_table_entries = 0
2105 :
2110 RESTORE 2125
2115 DIM keyword$(31, 9)
2120 FOR x = 1 TO 31: READ keyword$(x): END FOR x
2125 DATA 'END', 'FOR', 'IF', 'REPeat', 'SELect', 'WHEN', 'DEFine'
2130 DATA 'PROCedure', 'FuNction', 'GO', 'TO', 'SUB', '', 'ERRor', ''
2135 DATA '', 'RESTORE', 'NEXT', 'EXIT', 'ELSE', 'ON', 'RETurn'
2140 DATA 'REMAINDER', 'DATA', 'DIM', 'LOCal', 'LET', 'THEN', 'STEP'
2145 DATA 'REMark', 'MISTake'
2150 :
2155 DIM symbol$(10)
2160 symbol$ = '=:#,(){} ' & CHR$(10)
2165 :
2170 DIM operator$(22, 5)
2175 FOR x = 1 TO 22: READ operator$(x): END FOR x
2180 DATA '+', '-', '*', '/', '>=', '>', '==', '=', '<>', '<=', '<'
2185 DATA '||', '&&', '^^', '^', '&', 'OR', 'AND', 'XOR', 'MOD'
2190 DATA 'DIV', 'INSTR'
2195 :
2200 DIM monadic$(4, 3)
2205 FOR x = 1 TO 4: READ monadic$(x): END FOR x
2210 DATA '+', '-', '~~', 'NOT'
2215 :
2220 DIM separator$(5, 2)
2225 FOR x = 1 TO 5: READ separator$(x): END FOR x
2230 DATA ',', ';', '\', '!', 'TO'
2235 :
2240 END DEFine initialise
2245 :
2250 :
2255 DEFine PROCedure sa
2260 SAVE 'win2_decode_sav_file_bas'
2265 QSAVE 'win2_decode_sav_file'
2270 END DEFine sa
_______________________________________________
QL-Users Mailing List
http://www.q-v-d.demon.co.uk/smsqe.htm