{$A+,B-,D+,E+,F-,G-,I+,L+,N-,O-,P-,Q+,R+,S+,T-,V-,X+,Y+} {$M 4096,0,655360} PROGRAM Simple_XB_Viewer; USES CRT, { Standard CRT unit } STM, { Streams } VGA; { VGA functions } TYPE Char4 = ARRAY [0..3] OF Char; Const XB_ID : Char4 = 'XBIN'; XBIN_PALETTE = $01; XBIN_FONT = $02; XBIN_COMPRESS= $04; XBIN_NONBLINK= $08; XBIN_512 = $10; XBIN_RESERVED= $E0; TYPE XB_Header = RECORD ID : Char4; EofChar : Byte; Width : Word; Height : Word; Fontsize: Byte; Flags : Byte; END; LineStart = ARRAY[0..1023] OF LongInt; LineStartPtr = ^LineStart; VAR XBIN : Stream; XBHdr : XB_Header; Lines : ARRAY[0..63] OF LineStartPtr; { Offset in File of line start } Font : ARRAY[0..(512*32)-1] OF Byte; { Font Table } Palette : ARRAY[0..15,1..3] OF Byte; { Palette } FontDepth : Word; { 256 or 512 characters } Count : Word; X, Y : Word; CountByte : Byte; RunLength : Byte; Choice : Char; LineBuf : ARRAY[1..128] OF BYTE; PROCEDURE Abort (Str: String); BEGIN WriteLn; WriteLn('SimpleXB V1.00. Execution aborted.'); WriteLn; WriteLn(Str); WriteLn; Halt(1); END; FUNCTION Strf(Val:Word):String; VAR Temp : STRING; BEGIN Str(Val,Temp); Strf:=Temp; END; {Û Show palette : Quick & Dirty method ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ} PROCEDURE ShowPalette; Const BW_Pal : Array[1..6] of Byte = (0,0,0,63,63,63); VAR Count : Word; X, Y : Word; Col : Word; Row : Word; WMode : Boolean; BEGIN WMode:=DirectVideo; { Save DirectVideo status } DirectVideo:=FALSE; { Set it to false } VGA_Mode($13); { Set mode 320*200 256 colors } { Color setup for showing the palette } { 0 : remains black } { 1 : white } { 2-17 : Palette from XBIN } VGA_SetPalette(0,2,BW_Pal); VGA_SetPalette(2,16,Palette); TextColor(1); TextBackGround(0); WriteLn; WriteLn; WriteLn(' XBIN PALETTE'); WriteLn(' --------------'); WriteLn; WriteLn(' 0 1 2 3 4 5 6 7'); WriteLn; WriteLn; WriteLn; WriteLn; WriteLn; WriteLn; WriteLn(' 8 9 10 11 12 13 14 15'); FOR Count:=0 TO 15 DO BEGIN Col:=Count MOD 8; Row:=Count DIV 8; { Draw box } FOR X:=0 TO 31 DO BEGIN MEM[SegA000:(49+Row*56)*320+(X+Col*40)+4] := 1; MEM[SegA000:(80+Row*56)*320+(X+Col*40)+4] := 1; END; FOR Y:=0 TO 31 DO BEGIN MEM[SegA000:(49+Y+Row*56)*320+(Col*40)+ 4] := 1; MEM[SegA000:(49+Y+Row*56)*320+(Col*40)+35] := 1; END; FOR X:=1 TO 30 DO BEGIN FOR Y:=1 to 30 DO BEGIN MEM[SegA000:(49+Y+Row*56)*320+(X+Col*40)+4] := Count+2; MEM[SegA000:(49+Y+Row*56)*320+(X+Col*40)+4] := Count+2; END; END; END; IF (ReadKey=#0) THEN ReadKey; TextMode(Co80); DirectVideo:=WMode; { Restore orriginal DirectVideo } END; {Û Show font : Quick & Dirty method ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ} PROCEDURE ShowFont; VAR Count : Word; Y : Word; Block : Word; Col : Word; Row : Word; WMode : Boolean; Part : Word; BEGIN WMode:=DirectVideo; { Save DirectVideo status } DirectVideo:=FALSE; { Set it to false } VGA_Mode($12); { Set mode 640*480 16 colors } Part:=0; REPEAT WriteLn(' XBIN Font (Part ',Part+1,')'); WriteLn(' --------------------'); WriteLn; WriteLn(' x> 0 1 2 3 4 5 6 7 8 9 A B C D E F x> 0 1 2 3 4 5 6 7 8 9 A B C D E F'); WriteLn(' 0x','8x':38); WriteLn; WriteLn(' 1x','9x':38); WriteLn; WriteLn(' 2x','Ax':38); WriteLn; WriteLn(' 3x','Bx':38); WriteLn; WriteLn(' 4x','Cx':38); WriteLn; WriteLn(' 5x','Dx':38); WriteLn; WriteLn(' 6x','Ex':38); WriteLn; WriteLn(' 7x','Fx':38); WriteLn; For Count:=0 to 255 DO BEGIN Row :=(Count MOD 128) DIV 16; Col :=(Count MOD 128) MOD 16; Block:=Count DIV 128; FOR Y:=0 TO XBHdr.FontSize-1 DO MEM[SegA000:((Row*32)+64+Y)*80+Col*2+38*Block+7]:= Font[(Part*256+Count)*XBHdr.FontSize+Y]; END; Inc(Part); IF (XBHdr.Flags AND XBIN_512) = 0 THEN Inc(Part); { Set Part to 2 if 256 characters } UNTIL Part=2; IF (ReadKey=#0) THEN ReadKey; TextMode(Co80); DirectVideo:=WMode; { Restore original DirectVideo } END; {Û Show Image ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ} PROCEDURE ShowImage(DispHeight : WORD); TYPE VideoWord = RECORD Case Boolean of True : (Character:Byte; Attribute:Byte); False: (CharAttr :Word); END; VAR TopX : WORD; TopY : WORD; X,Y : WORD; Len : WORD; CH : Char; VidW : VideoWord; Count: BYTE; BEGIN GotoXY(1,1); TopX:=0; TopY:=0; IF (XBHdr.Width<80) THEN Len:=XBHdr.Width ELSE Len:=80; IF XBHdr.Height 0 THEN BEGIN STM_Goto(XBIN,Lines[(Y+TopY) DIV 1024]^[(Y+TopY) MOD 1024]); IF (XBIN.LastErr<>STM_OK) THEN BEGIN TextMode(Co80); Abort('Error reading XBIN.'); END; X:=0; WHILE XSTM_OK) THEN BEGIN TextMode(Co80); Abort('Invalid XBIN. Out of data.'); END; RunLength := (CountByte AND $3F) + 1; CASE (CountByte AND $C0) OF $00 : STM_Read(XBIN,LineBuf,RunLength*2); $40 : STM_Read(XBIN,LineBuf,1+RunLength); $80 : STM_Read(XBIN,LineBuf,1+RunLength); $C0 : STM_Read(XBIN,LineBuf,2); END; IF (XBin.lastErr<>STM_OK) THEN BEGIN TextMode(Co80); Abort('Invalid XBIN. Out of data.'); END; FOR Count:=1 TO RunLength DO BEGIN CASE (CountByte AND $C0) OF $00 : BEGIN VidW.Character:=LineBuf[Count*2-1]; VidW.Attribute:=LineBuf[Count*2]; END; $40 : BEGIN VidW.Character:=LineBuf[1]; VidW.Attribute:=LineBuf[Count+1]; END; $80 : BEGIN VidW.Character:=LineBuf[Count+1]; VidW.Attribute:=LineBuf[1]; END; $C0 : BEGIN VidW.Character:=LineBuf[1]; VidW.Attribute:=LineBuf[2]; END; END; IF (X>=TopX) AND (XSTM_OK) THEN BEGIN TextMode(Co80); Abort('Error reading XBIN.'); END; STM_Read(XBIN,MEM[SegB800:Y*160],Len*2); IF (XBIN.LastErr<>STM_OK) THEN BEGIN TextMode(Co80); Abort('Error reading XBIN.'); END; END; END; CH:=ReadKey; IF CH=#0 THEN BEGIN CH:=ReadKey; CASE Ch OF #72 : IF TopY>0 THEN Dec(TopY); { Up key } #80 : IF TopY0 THEN Dec(TopX); { Left key } #77 : IF TopX1) THEN Abort('SimpleXB Filename'); WriteLn('Opening XBIN ('+ParamStr(1)+')...'); STM_Open(XBIN,ParamStr(1),NOCREATE); IF (XBIN.LastErr<>STM_OK) THEN Abort('Error opening XBIN file '+ParamStr(1)); { --- Read XBIN Header ------------------------------------------------- } WriteLn('Reading XBIN Header...'); STM_Read(XBIN,XBHdr,Sizeof(XBHdr)); IF (XBIN.LastErr<>STM_OK) THEN Abort('Error reading XBIN Header.'); { --- ID bytes check out ? --------------------------------------------- } IF (XBHdr.ID<>XB_ID) OR (XBHdr.EofChar<>26) THEN Abort('File is not an eXtended BIN'); WriteLn(' Image width : ',XBHdr.Width); WriteLn(' Image height : ',XBHdr.Height); { IF Width=0 then Height must be 0 too. and vice versa } IF ((XBHdr.Width =0) AND (XBHdr.Height<>0) OR (XBHdr.Width<>0) AND (XBHdr.Height =0)) THEN Abort('Invalid XBIN. and must both be equal or different from 0'); Write (' Palette : '); IF (XBHdr.Flags AND XBIN_PALETTE) <> 0 THEN WriteLn('Alternate palette present') ELSE WriteLn('Default palette'); IF XBHdr.Flags AND XBIN_512 <> 0 THEN FontDepth:=512 ELSE FontDepth:=256; Write (' Font set : '); IF (XBHdr.Flags AND XBIN_FONT) <> 0 THEN BEGIN WriteLn('Alternate font, ',FontDepth,' characters.'); WriteLn(' Fontsize : ',XBHdr.Fontsize); END ELSE BEGIN WriteLn('Default font, ',FontDepth,' characters'); WriteLn(' Fontsize : ',XBHdr.FontSize,' (Default font)'); IF XBHdr.Fontsize<>16 THEN Abort('Invalid XBIN. Default should be 16.'); IF FontDepth<>256 THEN Abort('Invalid XBIN. Default font must have 256 characters.'); END; IF (XBHdr.FontSize=0) OR (XBHdr.FontSize>32) THEN Abort('Invalid XBIN. must be between 1 and 32.'); Write (' Compression : '); IF (XBHdr.Flags AND XBIN_COMPRESS) <> 0 THEN WriteLn('XBIN Compressed') ELSE WriteLn('Uncompressed BIN'); Write (' Blinking : '); IF (XBHdr.Flags AND XBIN_NONBLINK) <> 0 THEN WriteLn('Disabled') ELSE WriteLn('Enabled'); IF (XBHdr.Flags AND XBIN_RESERVED) <> 0 THEN WriteLn('Invalid XBIN. Reserved must be zero.'); { --- IF a Palette is present, read it --------------------------------- } IF (XBHdr.Flags AND XBIN_PALETTE <> 0) THEN BEGIN WriteLn('Reading palette...'); STM_Read(XBIN,Palette,Sizeof(Palette)); IF (XBIN.LastErr<>STM_OK) THEN Abort('Error reading XBIN palette.'); FOR Count:=Low(Palette) TO High(Palette) DO BEGIN IF Palette[Count][1]>63 THEN Abort('Invalid palette value for color '+Strf(Count)+' RED'); IF Palette[Count][2]>63 THEN Abort('Invalid palette value for color '+Strf(Count)+' GREEN'); IF Palette[Count][3]>63 THEN Abort('Invalid palette value for color '+Strf(Count)+' BLUE'); END; END; { --- IF a font is present, read it ------------------------------------ } IF (XBHdr.Flags AND XBIN_FONT <> 0) THEN BEGIN WriteLn('Reading font...'); STM_Read(XBIN,Font,FontDepth*XBHdr.Fontsize); IF (XBIN.LastErr<>STM_OK) THEN Abort('Error reading XBIN font.'); END; { --- Check Image data & mode ------------------------------------------ } IF (XBHdr.Width>0) THEN BEGIN IF (XBHdr.Flags AND XBIN_COMPRESS) <> 0 THEN BEGIN WriteLn('Checking and preparing XBIN compressed image data...'); Y:=0; WHILE YSTM_OK) THEN Abort('Invalid XBIN. Out of data.'); RunLength := (CountByte AND $3F) + 1; Inc(X,RunLength); CASE (CountByte AND $C0) OF $00 : STM_Read(XBIN,LineBuf,RunLength*2); $40 : STM_Read(XBIN,LineBuf,1+RunLength); $80 : STM_Read(XBIN,LineBuf,1+RunLength); $C0 : STM_Read(XBIN,LineBuf,2); END; IF (XBin.lastErr<>STM_OK) THEN Abort('Invalid XBIN. Out of data.'); END; IF (X>XBHdr.Width) THEN Abort('Invalid XBIN. Compressed across line boundary.'); Inc(Y); END; Write(#13,'':79,#13); END ELSE BEGIN WriteLn('Checking and preparing uncompressed image data...'); IF STM_GetSize(XBIN)alette, ont, magedata, BIN, All other keys quit : '); Choice:=Upcase(Readkey); WriteLn(Choice); IF Choice=#0 THEN BEGIN { Function key was pressed } Choice:=Readkey; { Process the next scancode } Choice:=#27; { All others keys quit... } END; CASE (Choice) OF 'P' : BEGIN IF (XBHdr.Flags AND XBIN_PALETTE) <> 0 THEN ShowPalette ELSE WriteLn('Default palette applies'); END; 'F' : BEGIN IF (XBHdr.Flags AND XBIN_FONT) <> 0 THEN ShowFont ELSE WriteLn('Default palette applies'); END; 'I' : BEGIN ShowImage(25); TextMode(Co80); END; 'X' : BEGIN VGA_Set8PixelFont; { This'll look better } IF (XBHdr.Flags AND XBIN_PALETTE) <> 0 THEN BEGIN VGA_SetFlatTextPal; VGA_SetPalette(0,16,Palette); END; IF (XBHdr.Flags AND XBIN_NONBLINK) <> 0 THEN VGA_SetBlink(FALSE); IF (XBHdr.Flags AND XBIN_512) <> 0 THEN VGA_SetActiveFont(0,4); { Activate Character map 0 and 4 } { 0 and 4 are adjacent Character } { maps } VGA_SetFontSize(XBHdr.FontSize); IF (XBHDR.Flags AND XBIN_FONT) <> 0 THEN VGA_SetFont(0,FontDepth,XBHdr.FontSize,0,Font); ShowImage(400 DIV XBHdr.FontSize); { 400 Scanlines are on screen } TextMode(Co80); END; ELSE Choice:=#27; END; UNTIL (Choice=#27); { --- Free allocated memory -------------------------------------------- } WriteLn('Closing XBIN...'); STM_Close (XBIN); { --- Free allocated memory -------------------------------------------- } WriteLn('Freeing memory...'); FOR Count:=Low(Lines) TO High(Lines) DO BEGIN Dispose(Lines[Count]); END; END.