[0001] [0002] [0003] [0004] [0005] [0006] [0007] [0008] [0009] [0010] [0011] [0012] [0013] [0014] [0015] [0016] [0017] [0018] [0019] [0020] [0021] [0022] [0023] [0024] [0025] [0026] [0027] [0028] [0029] [0030] [0031] [0032] [0033] [0034] [0035] [0036] [0037] [0038] [0039] [0040] [0041] [0042] [0043] [0044] [0045] [0046] [0047] [0048] [0049] [0050] [0051] [0052] [0053] [0054] [0055] [0056] [0057] [0058] [0059] [0060] [0061] [0062] [0063] [0064] [0065] [0066] [0067] [0068] [0069] [0070] [0071] [0072] [0073] [0074] [0075] [0076] [0077] [0078] [0079] [0080] [0081] [0082] [0083] [0084] [0085] [0086] [0087] [0088] [0089] [0090] [0091] [0092] [0093] [0094] [0095] [0096] [0097] [0098] [0099] [0100] [0101] [0102] [0103] [0104] [0105] [0106] [0107] [0108] [0109] [0110] [0111] [0112] [0113] [0114] [0115] [0116] [0117] [0118] [0119] [0120] [0121] [0122] [0123] [0124] [0125] [0126] [0127] [0128] [0129] [0130] [0131] [0132] [0133] [0134] [0135] [0136] [0137] [0138] [0139] [0140] [0141] [0142] [0143] [0144] [0145] [0146] [0147] [0148] [0149] [0150] [0151] [0152] [0153] [0154] [0155] [0156] [0157] [0158] [0159] [0160] [0161] [0162] [0163] [0164] [0165] [0166] [0167] [0168] [0169] [0170] [0171] [0172] [0173] [0174] [0175] [0176] [0177] [0178] [0179] [0180] [0181] [0182] [0183] [0184] [0185] [0186] [0187] [0188] [0189] [0190] [0191] [0192] [0193] [0194] [0195] [0196] [0197] [0198] [0199] [0200] [0201] [0202] [0203] [0204] [0205] [0206] [0207] [0208] [0209] [0210] [0211] [0212] [0213] [0214] [0215] [0216] [0217] [0218] [0219] [0220] [0221] [0222] [0223] [0224] [0225] [0226] [0227] [0228] [0229] [0230] [0231] [0232] [0233] [0234] [0235] [0236] [0237] [0238] [0239] [0240] [0241] [0242] [0243] [0244] [0245] [0246] [0247] [0248] [0249] [0250] [0251] [0252] [0253] [0254] [0255] [0256] [0257] [0258] [0259] [0260] [0261] [0262] [0263] [0264] [0265] [0266] [0267] [0268] [0269] [0270] [0271] [0272] [0273] [0274] [0275] [0276] [0277] [0278] [0279] [0280] [0281] [0282] [0283] [0284] [0285] [0286] [0287] [0288] [0289] [0290] [0291] [0292] [0293] [0294] [0295] [0296] [0297] [0298] [0299] [0300] [0301] [0302] [0303] [0304] [0305] [0306] [0307] [0308] [0309] [0310] [0311] [0312] [0313] [0314] [0315] [0316] [0317] [0318] [0319] [0320] [0321] [0322] [0323] [0324] [0325] [0326] [0327] [0328] [0329] [0330] [0331] [0332] [0333] [0334] [0335] [0336] [0337] [0338] [0339] [0340] [0341] [0342] [0343] [0344] [0345] [0346] [0347] [0348] [0349] [0350] [0351] [0352] [0353] [0354] [0355] [0356] [0357] [0358] [0359] [0360] [0361] [0362] [0363] [0364] [0365] [0366] [0367] [0368] [0369] [0370] [0371] [0372] [0373] [0374] [0375] [0376] [0377] [0378] [0379] [0380] [0381] [0382] [0383] [0384] [0385] [0386]
.TITLE FIX_BOOK - Fix .DECW$BOOK or .BKB file after download .IDENT /X01.03/ ;+ ; FIX_BOOK.MAR - Try to fix mangled (by http: download) .DECW$BOOK or .BKB file ; ; Description: ; ; OpenVMS ODLs (Online Documentation Library CD files) are being presented ; at http://odl.sysworks.biz. When downloading .DECW$BOOK or .BKB files from ; this site, they are unsuable, because the download removes the required ; record format (sequential file with variable length records) through the ; download as octet-stream and/or the copy operation with FTP or sftp. ; ; This program tries to reconstruct a valid .DECW$BOOK or .BKB bookreader file ; ; Initiated by note EISNER::VMS 3726 ; ; ; Build with: ; ; $ MACRO fix_book ! for OpenVMS VAX ; $ MACRO/MIGRATE fix_book ! for OpenVMS Alpha, I64 or x86_64 ; $ LINK fix_book ; ; Run with: ; ; $ DEFINE INFILE filename.DECW$BOOK (or filename.BKB) ; $ DEFINE OUTFILE new_filename.DECW$BOOK ; $ RUN fix_book ; ; Parameters: ; ; Input: INFILE - logical pointing to mangled .DECW$BOOK/.BKB ; Output: OUTFILE - logical pointing to reconstructed .DECW$BOOK/.BKB ; ; 25-MAR-2021 Volker Halle [ halle (at) encompasserve.org ] ; ; Modification history: ; ; X01.00 VH Initial test release ; ; X01.01 VH Do not specify RAT in OUTRAB (force Record Attributes = none) ; 26-MAR-2021 Check for RFM=VAR and output appropriate SET FILE/ATTR message ; Refer to 'bytes on disk' in good_book message ; ; X01.02 VH Fix 'end of file byte' discrepancy in LAST record ; 27-MAR-2021 Output no. of parts in book together with title ; ; X01.03 VH Fix %MACRO-E-BRDESTRANG, Branch destination out of range errors ; 29-MAR-2021 to make FIX_BOOK also work with OpenVMS VAX macro assembler ;- .PSECT DATA,WRT,NOEXE INFAB: $FAB FNM = <INFILE:>,- ; Input file name FAC = <BIO,GET> ; Block I/O read operations INRAB: $RAB FAB = INFAB,- ; Pointer to FAB BKT = 0,- ; Start with current block UBF = REC_BUFF,- ; Record buffer USZ = REC_SIZE ; and size OUTFAB: $FAB FNM = <OUTFILE:>,- ; Output file name FOP = CBT,- ; Try for contiguous file MRS = 0,- ; Maximum record size FAC = <PUT> ; Record I/O write operations OUTRAB: $RAB FAB = OUTFAB,- ; Pointer to FAB BKT = 0,- ; Start with current block RBF = REC_BUFF ; Output uses same buffer ; as input REC_SIZE = 62*1024 ; Maximum record size REC_BUFF: .BLKB REC_SIZE ; Record buffer end_of_rec_buff: .ADDRESS . ; pointer to end of REC_BUFF vbn: .LONG 1 ; starting VBN for $READ good_str: .ASCID /%FIX_BOOK-I-GOOD, looks like a good .DECW$BOOK (bytes on disk)/ var_str: .ASCID \%FIX_BOOK-W-NOT_VAR, use SET FILE/ATTRIB=(RFM=VAR,RAT=NONE) infile\ bad_str: .ASCID /%FIX_BOOK-E-BAD, does not look like a mangled .DECW$BOOK/ title_str: .ASCID /%FIX_BOOK-I-TITLE, book title: !AC (!UL parts)/ rec_str: .ASCID /%FIX_BOOK-I-RECORD, record: !UL starts with !XL/ bad_rec: .ASCID /%FIX_BOOK-E-BAD_REC, unexpected start of record/ read_str: .ASCID /%FIX_BOOK-I-READ, reading !UL bytes starting at VBN !UL/ FAOOUT: .WORD 256 .BYTE DSC$K_DTYPE_T .BYTE DSC$K_CLASS_S .ADDRESS .+4 .BLKB 256 record: .LONG 1 ; Record no. (starting at 1) rec_ptr: .BLKL 1 ; pointer to next record in REC_BUFF n_parts: .BLKL 1 ; no. of parts in book .PSECT CODE,NOWRT,EXE .ENTRY FIX_BOOK,^M<> ; No registers to save $OPEN FAB=INFAB BLBC R0,EXIT1 $CONNECT RAB=INRAB BLBC R0,EXIT2 MOVL INFAB+FAB$L_ALQ,- OUTFAB+FAB$L_ALQ $CREATE FAB=OUTFAB BLBC R0,EXIT3 $CONNECT RAB=OUTRAB BLBC R0,EXIT4 BRB READ EXIT1: MOVL INFAB+FAB$L_STS,R2 MOVL INFAB+FAB$L_STV,R3 BRW EXIT EXIT2: MOVL INRAB+RAB$L_STS,R2 MOVL INFAB+RAB$L_STV,R3 BRW EXIT EXIT3: MOVL OUTFAB+FAB$L_STS,R2 MOVL OUTFAB+FAB$L_STV,R3 BRW EXIT EXIT4: MOVL OUTFAB+RAB$L_STS,R2 MOVL OUTFAB+RAB$L_STV,R3 BRW EXIT READ: MOVW #256, faoout ; reset buffer length $FAO_S CTRSTR=read_str,- OUTBUF=faoout,- OUTLEN=faoout,- P1=INRAB+RAB$W_USZ,- ; no. of bytes to read P2=vbn ; starting VBN PUSHAQ faoout CALLS #1, G^LIB$PUT_OUTPUT $READ RAB=INRAB BLBS R0,check_book CMPL R0,#RMS$_EOF BEQL 80$ BRW EXIT2 80$: BRW done ; branch aid for VAX good_book: ; looks like a valid .DECW$BOOK file PUSHAQ good_str CALLS #1,G^LIB$PUT_OUTPUT CMPB INFAB+FAB$B_RFM, #FAB$C_VAR ; RFM = variable length records ? BEQL 90$ PUSHAQ var_str CALLS #1,G^LIB$PUT_OUTPUT 90$: BISL #FAB$M_DLT,OUTFAB+FAB$L_FOP ; delete OUTFILE on close BRW done bad_book: ; not an octet-stream mangled .DECW$BOOK PUSHAQ bad_str CALLS #1,G^LIB$PUT_OUTPUT BRW done check_book: CMPW #^x03FE,rec_buff ; correct 1st hdr record length ? BEQL good_book ; EQL -> yes -> exit CMPW #1,rec_buff ; octet-stream .DECW$BOOK ? BNEQ bad_book ; NEQ -> no ; ; Special handling of first and possibly second record in mangled .DECW$BOOK ; MOVL rec_buff+^x46, n_parts ; no. of parts in book MOVW #256, faoout ; reset buffer length $FAO_S CTRSTR=title_str,- OUTBUF=faoout,- OUTLEN=faoout,- P1=#rec_buff+^x7E,- ; ptr to title P2=n_parts ; no. of parts in book PUSHAQ faoout CALLS #1, G^LIB$PUT_OUTPUT MOVW #256, faoout ; reset buffer length $FAO_S CTRSTR=rec_str,- OUTBUF=faoout,- OUTLEN=faoout,- P1=record,- ; record number P2=rec_buff ; 1st longword of record PUSHAQ faoout CALLS #1, G^LIB$PUT_OUTPUT CMPW rec_buff,#1 ; check 1st record type field BEQL 1$ PUSHAQ bad_rec CALLS #1, G^LIB$PUT_OUTPUT BISL #FAB$M_DLT,OUTFAB+FAB$L_FOP ; delete OUTFILE on close BRW done 1$: MOVW #^x03FE,OUTRAB+RAB$W_RSZ ; 1st record is 0x3FE long MOVAB rec_buff,OUTRAB+RAB$L_RBF ; start of offset 0 $PUT RAB=OUTRAB ; output 1st HDR record BLBS R0, 2$ BRW EXIT4 2$: MOVAL rec_buff+^x03FE,rec_ptr ; point to next record CMPW #2,rec_buff+^x03FE ; 2nd header type field = 2 ? BNEQ copy_records INCL record ; increment record number MOVW #256, faoout ; reset buffer length $FAO_S CTRSTR=rec_str,- OUTBUF=faoout,- OUTLEN=faoout,- P1=record,- ; record number P2=rec_buff+^x03FE ; 1st longword of record 2 PUSHAQ faoout CALLS #1, G^LIB$PUT_OUTPUT ADDL2 #^x03FE,OUTRAB+RAB$L_RBF ; point to hdr 2 $PUT RAB=OUTRAB ; output 2nd HDR record BLBS R0, 5$ BRW EXIT4 5$: ADDL2 #^x03FE, rec_ptr ; point to next record ; ; Copy remaining records of a mangled .DECW$BOOK file ; ; rec_ptr - point to start of next record in REC_BUFF ; contents of @rec_ptr should be xxxxtttt ; with xxxx = length of next record in bytes ; tttt = type of record copy_records: MOVL rec_ptr, R2 ; address of next record ADDL2 #2, R2 ; point to size word MOVZWL (R2), OUTRAB+RAB$W_RSZ ; size of next record MOVZWL (R2), R3 ; record size ADDL2 rec_ptr, R3 ; point past next record CMPL R3, end_of_rec_buff ; outside REC_BUFF ? BGTRU 11$ ; next record inside REC_BUFF MOVL rec_ptr,OUTRAB+RAB$L_RBF ; start of record INCL record ; increment record number MOVW #256, faoout ; reset buffer length $FAO_S CTRSTR=rec_str,- OUTBUF=faoout,- OUTLEN=faoout,- P1=record,- ; record number P2=@rec_ptr ; 1st longword of record PUSHAQ faoout CALLS #1, G^LIB$PUT_OUTPUT TSTL @rec_ptr ; NULL = end-of-file BEQL 19$ ; if EQL -> done CMPW @rec_ptr, #0 ; must be > 0 BLEQ 18$ CMPW @rec_ptr, #32 ; check record type field < 33 ? BLEQ 20$ BRB 18$ 11$: BRW 10$ ; branch aid for VAX 18$: PUSHAQ bad_rec CALLS #1, G^LIB$PUT_OUTPUT BISL #FAB$M_DLT,OUTFAB+FAB$L_FOP ; delete OUTFILE on close 19$: BRW done ; branch aid for VAX 20$: CMPW @rec_ptr, #5 ; 5 = LAST record ? BNEQ 25$ ; ; for the LAST record to be written, correctly determine record length ; ; The last record looks like this (from hyperreader.c): ; ; "Last" Record ; ------------- ; variable size ; part type: short 0x00 (type=0x0005) ; part length: long 0x02 ; then starting at offset 0x06: ; (1 .. number of parts in the book) series of 10 byte units, each: ; VBN (512) of part long 0x00 ; position in VBN of part short 0x04 ; length of this part long 0x06 ; MULL3 n_parts, #10, R2 ; no. of parts times 10 bytes ADDL2 #6, R2 ; add part type + length MOVL R2, OUTRAB+RAB$W_RSZ ; actual size of LAST record 25$: $PUT RAB=OUTRAB ; output record BLBS R0, 26$ BRW EXIT4 26$: CMPW @rec_ptr, #5 ; 5 = LAST record written ? BEQL 27$ ; EQL: yes -> done MOVL R3, rec_ptr ; point to next record BRW copy_records ; copy next record 27$: BRW done ; branch aid for VAX ; ; current record exceeds end of data in REC_BUFF ; copy record data from @rec_ptr until @end_of_rec_buff to start of REC_BUFF, ; then read next blocks from INFILE, then output current record ; 10$: MOVL end_of_rec_buff, R2 SUBL2 rec_ptr, R2 ; no of bytes to copy PUSHL R2 MOVC3 R2, @rec_ptr, rec_buff POPL R2 MOVAL rec_buff, rec_ptr ; point to beginning of REC_BUFF ADDL2 #rec_buff, R2 ; point past copied part of record MOVL R2, INRAB+RAB$L_UBF ; set input read buffer address SUBL3 R2, #end_of_rec_buff, R2 ; get no. of bytes to read DIVL2 #512, R2 ; get rounded no. of blocks ADDL2 R2, vbn ; starting VBN for next $READ MULL2 #512, R2 ; set no. of bytes to read MOVW R2, INRAB+RAB$W_USZ ; set input buffer size MOVL INRAB+RAB$L_UBF,end_of_rec_buff ADDL2 R2, end_of_rec_buff ; new end of rec_buff MOVZWL INRAB+RAB$W_USZ, R2 MOVW #256, faoout ; reset buffer length $FAO_S CTRSTR=read_str,- OUTBUF=faoout,- OUTLEN=faoout,- P1=R2,- ; no. of bytes to read P2=vbn ; starting VBN PUSHAQ faoout CALLS #1, G^LIB$PUT_OUTPUT $READ RAB=INRAB BLBC R0, 12$ BRW copy_records ; process next record 12$: CMPL R0,#RMS$_EOF BEQL DONE BRW EXIT2 DONE: $CLOSE FAB=INFAB $CLOSE FAB=OUTFAB RET EXIT: PUSHL R3 PUSHL R2 CALLS #2, G^LIB$SIGNAL RET .END FIX_BOOK