I wrote this up at the beginning of 2002 but did not post it for a few reasons.. the main reason being the BASM dos compiler was replaced with a Windows-based version. Tokiwa disappeared as well, or at least was hiding the last time I looked. ASIC is still around in archives and the Moonrock page works, at least there are a couple tiny-com compilers the modern simple problem-solver can use. Recently I've noticed a renewed interest in how ascii assembler works, and even if my application of it is a bit extreme this document provides a decent overview and links to tools. One usually does not write ascii-assembler by hand if it can possibly be helped, rather encoding/decoding techniques are used to translate existing machine code into batch-legal code. NT-like OS's redefine what is legal, be very careful using some of the raw translaters since they output code NT/XP/etc will not interpret correctly, when machine code is involved the results can be unpredictable, why I adopted a more complicated but compatible approach. If I was smart enough to write a compatible one-step encoder I would but I'm mostly batch and high-level, machine code isn't my thing unless it's for a PIC.
Standard disclaimers, not responsible if you fry your computer using these techniques and programs. Machine code can do just about anything, including horribly crash the computer the errant code is running on. Who knows my code might have a bug, all I can say is it works on my Windows 95 machine, and the output runs under XP. The batch code will likely need adapting to your environment if used, especially CONV2BAT since it is so compiler-specific. If you need to do stuff like this you probably have other specific needs, consider crafting your own solution that best suits your needs, taking code here and elsewhere as examples.
Contents:
Many times when programming in batch it is necessary to use binary data of one kind or another, be it a helper utility or simply a file without a return at the end. For the purpose of this article, binary means a sequence of bytes where the bytes can take on any value without restriction and can represent a machine code program, a gif file or any other arbitrary file. The important thing is the sequence has to remain exact, there can be no system-created changes or malfunction will likely occur. MsDos Batch is an ascii-based language which can only write files that end in CrLf (Ascii 13, 10), and cannot directly write certain characters that mean other things to the system unless specific steps are taken to ensure syntactic legality. Most of the time batch files are written to use already-existing binary files, however there are times when a single file solution would be better, particularly when distributing a solution for others to use but also to avoid accumulating extra files for trivial purposes.
Just like any programming tool there are advantages and drawbacks. Advantages: Binary-to-batch (Bin-batch) encoding techniques enable batch programmers to recreate any small file as needed. Bin-batch tools let the batch programmer write complex functions in a true HLL (high-level language) then convert it to batch code, rather than relying on unreliable version-specific batch hacks (if the function is even expressible in batch). Carefully constructed bin-batch code can run on all known dos platforms from the earliest MsDos with echo and redirection to Windows XP so long as the underlying app is compatible. Bin-batch text cannot be modified by com-infecting viruses and is safer to redistribute than raw com files, provided of course the files are clean to begin with. Any change is visible and changes the way the encoded ascii "reads" (phrases that randomly appear in a particular routine's encoded text).
Disadvantages: Encoding obscures the original content, and people are fearful of code that cannot be discerned. Depending on the context, bin-batch is no more and arguably less dangerous than simply distributing the binaries with the batch, however in an area where binaries generally are not allowed such as a discussion newsgroup. Posting bin-batch code can get you majorly flamed, in alt.msdos.batch only very small binaries written by known authors are tolerated. Bin-batch code is always a bit slower than merely accessing already-existing binaries, and it adds another layer of possible incompatibility. Creating executable binaries on-the-fly might be against company policy or require specific approval. Some lockdown-style anti-virus (AV) programs prevent the creation of executable code altogether when enabled, other AV programs slow down bin-batches because they have to scan each line of the binary file as it is written to disk. Using a separate decoder greatly reduces scanning overhead by creating the binary in one scanned step (only the decoder has to be scanned line-by-line), or write the com to a file with a non-executable extension then rename before running.
Binary to Batch Encoding Techniques
The old MsDos debug command is probably the most common method of encoding binary data for batch, the command is available on most systems but it is possible the user removed or renamed it, and if booting from floppy you'll have to make sure the debug command is available by putting it on the disk. Debug more than triples the unencoded file size so is best used for very small routines. Numerous debug-encoding utilities are available.
It is possible to write small machine code programs that consist entirely of batch-legal characters and echo it directly to a com file for execution, this method is handy for echoing characters without a CrLf, inputting data and other simple functions that otherwise cannot easily be done in batch. Writing such "ascii assembler" code though is a tedious affair even when one is familiar with assembly, often the results contain more code for patching incompatible bytes than for the task itself but still the utilities rarely exceed a few lines of ascii. Herbert Kleebauer and Laura Fairhead are established experts in this area and have published many useful ascii machine code batch routines on the alt.msdos.batch newsgroup over the years.
Among the most interesting of bin-batch utilities are com-file encoders. After being echoed to disk the com file consists of a decoder consisting entirely of batch-echoable ascii characters followed by an ascii-encoded representation of the original machine code program. When the com runs, the decoder decodes the original code and executes it, if all goes well the original code is not aware of the process. Herbert Kleebauer's Convert.bat program requires that the machine code be assembled at an offset to make room for the decoder. Laura Fairhead's Cm3.com program goes a step further and appends a copy routine, permitting it to encode standard com files.
The method I settled on uses a CM3-encoded decoder that decodes data from one redirected file to another, allowing any small file to be encoded and recreated exactly regardless of its contents. There is more overhead running machine code programs this way but the same decoder can be used multiple times, and the decoding process doesn't produce as much AV scanner activity since only the decoder itself is written line-by-line to a com file. A major reason for going with a separate decoder was to be able to control the encoding process myself, CM3 sometimes produced NT-incompatible output on the 2nd line.
Tricky stuff! Cross-compatibility information can be hard to come by so there may be errors or omissions in the above. Best to keep the encoding method simple as possible to avoid errors with some platforms.
A Universal Batch-Compatible Encoder and Decoder
For my encoding scheme I chose to reduce the range of characters from 256 to 64 starting at ascii 48 ("0") to pack 1.5 bytes per pair of encoded characters. To assure batch compatibility ascii 58 thru 64 (":" to "@") and ascii 94 thru 96 ("^" to "`") are skipped. This encoding scheme doesn't reach the problem ascii 124 pipe character. To create my solution I started with another binary-ascii encoder/decoder pair named zencode/zdecode by Tenie Remmel and replaced the 13-bit (91 position) binary fetch code with by own 12-bit code, along with changes to offset and skip as needed. I further modified the decoder so that it outputs a single RET instruction should the decoded size not match the size recorded at the beginning of the encoded data. Not as good as a checksum but at least provides some protection. The decoder is encoded using CM3, for batch use and distribution the encoder can be encoded by itself. Note that my encoder converts to raw ascii, echo redirection to a file must be added to include within a batch.
Here is a batch containing the decoder which I call "DecBin" and used to decode the encoder I call "EncBin"...
@echo off set dec=decbin.com set enc=encbin.com set tf=encbin.tmp ::--------------------- :: CM3-encoded DecBin decoder... ECHO:`h}aXP5y`P]4nP_XW(F4(F6(F=(FF)FH(FL(Fe(FR0FTs*}`A?+,>%dec% ECHO:fkOU):G*@Crv,*t$HU[rlf~#IubfRfXf(V#fj}fX4{PY$@fPfZsZ$:NvN$>>%dec% ECHO:9AyroNB-)dOKwK0rRkfTbi)ws_~[[q9wE'sqlu1sY*Bsfe=@ziNS1a)88e>>%dec% ECHO:f9RTL)9Z{3INBD?o6@MDLO{Zz4Q23E-'09NX9@Vz(42A7c8zMS:u$w6k5Q>>%dec% ECHO:N,h:le)~gF?tutTyxoe5UiIdtn';0rJ1q:{7;lAl']y:yTjZBbOo?QRIdN>>%dec% ECHO:$Bp@P/nAp_r0*4f'XcF4q3o?$_t5lx$Q-OxSfUNQ__Gd~$Q-Oxgkx=LGHU>>%dec% ECHO:S)$C6P8#>>%dec% ::--------------------- :: the EncBin encoder, encodes stdin to stdout, encoded by itself... ECHO:AALIxnCmeRf0\Uf0pWjXYBlxr0MyG02u022nc1Z5Z0r4G2ldMAj[8F34dd>%tf% ECHO:Z1Z0r4G2ld6Aj[8F34Ed3EmbG02lJpNl0jjjCt9v0407ZvjtS3I0j7rvLv>>%tf% ECHO:G203l0wUDv20F42eD3ZujTS6fmprbD2e4uwp39gwYdfDfAdng0f1f0ZF2t>>%tf% ECHO:04bemDCXj0C0LHtA2701ZsG0SFdfW]6630Jf36S6W1f0rJ2fMfQYW1YAoO>>%tf% ECHO:EAt0y[36S6W1[8LRi3}>>%tf% ::--------------------- :: decode encoder... %dec% < %tf% > %enc% if errorlevel 1 echo error decoding binary if not errorlevel 1 echo Created encoder in %enc% echo Created decoder in %dec% del %tf% |
To encode a binary manually using encbin.com run: encbin < binary > file then edit file and add "echo " or "echo:" at the beginning and redirection to the desired file at the end of each line. To do this automatically as part of a binary-to-batch batch presents a bit of difficulty, either the symmetry and simplicity of the encoder/decoder pair has to be broken by including echo and file redirection in the encoder output, or the problem can be simply solved using encoded HLL.
Com-file Compilers and Conv2Bat.bat
Several BASIC-like compilers produce com files small enough to encode for batch usage, just about all of them can be found on the Basm page (see links). Each of these has its own particular syntax which has to be memorized, at least where in the doc file the info can be found. For the most part it's like regular basic but expressions must be highly simplified and some of the commands have slightly different syntax. Basm works the best for me but each have strengths and weaknesses... Basm and Moonrock produce assembly source which can be used for hand-tweeking the compiler output. Basm provides easy access to stdin and stdout and produces simple, stable code that should run on any platform that supports dos (I have no info about NT/2000/XP compatibility, I'd guess probably ok). Moonrock worked with everything I wrote with it but the bounce.moo demo crashes and takes down Windows on my machine. Asic is the most complete but the com file often is inflated in size and must be compressed using PkLite or equivalent. Tokiwa does floating point math but I don't know much about it.
The compiler binaries and batch files need to be in path directories so they can be operated by issuing simple dos commands in the directory the source is in. Usually linking batches (@c:\path\prog.exe %1 %2 etc) in a path dir are ok for compilers but some command line parms cannot be passed (specifically asm's ";" no-prompt option) and anything that uses redirection to specify input or output must be available in binary form. On my system I have link batches for asicc.exe, mrc.exe and tbc.com, with basm.exe, asm.exe, freelink.exe and moonrock's mrlink.com in a path directory. In its default configuration Moonrock uses A86 to assemble the output, to use asm unzip mrcasm.cfg from config.zip and rename to mrc.cfg, and make sure everything listed is on the path. Of course it's not necessary to install and learn all of these, to use Basm all you need is Basm, Asm and Freelink.
Conv2bat.bat combines compiling and converting to batch into one step usable from Windows' right-click menu system. Asicc is called to compile asi files, basm/asm/freelink for bas files, Moonrock's mrc for moo files and Tokiwa's tbc for tok files. Notepad or any other text editor can be used to create the source, keep shortcuts to the docs handy. After compiling the source, Conv2bat encodes it into batch form, leaving a .com file and a .bat file with the same base name as the original source file. A batch-commented version of the original source is included in the output batch to help remember what the binary does. If the specified file's extension isn't a supported source file then Conv2Bat encodes it directly to batch, edit the output batch code as needed to use the binary.
All that sounds easy enough... for a real language! Problems... If batch is used as a drag and drop target the current directory is not set to where the file is, rather it must be determined from the passed filename. Essentially the extension must be separated from the rest of the filename but doing anything besides adding strings together is outside the scope of batch. After encoding with EncBin, "ECHO:" and ">>file" (one > on the first line, file is variable) needs to be added to each line to create runnable batch code. To include source code, "::" needs to be inserted before each line. A batch that does all that using only standard commands (if you count debug) is possible, a QBasic script would work, but the former would take quite a bit of hack-style programming, and QBasic isn't installed on every system (and flashes). Binary batch blocks written in Basm easily solved all these problems.
NT compatibility should be reasonably good but NT's find command doesn't return an errorlevel, the part that documents whether or not the com file was compressed with PkLite won't work properly but code output is not affected. Getting away from incompatibilities like this is a major reason for using binary batch (I just hope it doesn't create new incompatibilities), but since this one is minor so I don't think I'll fix unless I get an NT-like system. There may be other incompatibilities I don't know about, all I have is 95 and the Win95Cmd Cmd emulator to test with.
Here is Conv2Bat... (skip to source or more docs)
:: CONV2BAT.BAT - this batch converts HLL source or an :: existing file (<40K) into equivalent batch code. :: Required components... (assumed to be on the path) :: for ASIC (asi): ASICC :: for BASM (bas): BASM ASM FREELINK :: for Moonrock (moo): MRC (plus asm/link in mrc.cfg) :: for Tokiwa (tok): TBC :: Compresses com with PKLITE, uses Dos6+ FC and FIND to :: determine if compressed for comments. Disable below. :: The temp variable must point to a writable directory. :: This batch is designed to operate by drag-drop, from :: Windows' right-click menus, or from a dos prompt. :: Usage: CONV2BAT [path\]filename.ext :: If extension is asi bas moo or tok then produces :: filename.bat containing batch-encoded binary with :: attached source, in addition to compiler output. :: If ext not supported then encodes binary to batch. :: Tested in Win95, should be dos and NT-tolerent except :: for compression test (see comments) but maybe more. :: This is free software and comes with no guarantee, :: test thoroughly before distributing the output code. :: Last major mod 12/08/01, last mod 1/03/02 :: (C) Copyright 2002 Terry Newton :: EncBin encoder, DecBin decoder and Basm helpers :: are public domain, use as you wish. @echo off if .%1==.Shell goto %1 if not .%1==. if exist %1 goto fileexists echo Compiles HLL source and converts to batch echo Usage: CONV2BAT [path\]filename.ext echo Compiles .asi .bas .moo and .tok files echo encodes other types directly to batch goto end :fileexists :: shell with lots of environment space %comspec% /e:30000 /c %0 Shell %1 goto end :Shell ::**** options, edit as needed... :: usepklite=yes to compress with pklite set usepklite=yes :: usetempdir=yes to use temp dir in output code set usetempdir=no :: decname=filename used for decoder set decname=_d.com :: tempname=filename used for temp file set tempname=_t.tmp :: extension to output batch code to set outputext=bat :: callconv2cfg=yes to put variables in conv2cfg.bat set callconv2cfg=no :: temp filenames... set dec=%temp%.\_decbin.com set enc=%temp%.\_encbin.com set file2bat=%temp%.\_2bat.com set cmntsrc=%temp%.\_cmntsrc.com set sepname=%temp%.\_sepname.com set replace=%temp%.\_replace.com set tf=%temp%.\_tf.tmp set tf1=%temp%.\_tf1.tmp set tf2=%temp%.\_tf2.tmp :: override variables if configured... if .%callconv2cfg%==.yes call conv2cfg.bat :: double check... set xyz=0123456789012345678901234567890123456789 if not .%xyz%==.0123456789012345678901234567890123456789 goto end set xyz= echo. echo **** CONV2BAT **** 12/8/01 WTN echo Checking file support... ::----------------------- :: CM3-encoded DecBin decoder... ECHO:`h}aXP5y`P]4nP_XW(F4(F6(F=(FF)FH(FL(Fe(FR0FTs*}`A?+,>%dec% ECHO:fkOU):G*@Crv,*t$HU[rlf~#IubfRfXf(V#fj}fX4{PY$@fPfZsZ$:NvN$>>%dec% ECHO:9AyroNB-)dOKwK0rRkfTbi)ws_~[[q9wE'sqlu1sY*Bsfe=@ziNS1a)88e>>%dec% ECHO:f9RTL)9Z{3INBD?o6@MDLO{Zz4Q23E-'09NX9@Vz(42A7c8zMS:u$w6k5Q>>%dec% ECHO:N,h:le)~gF?tutTyxoe5UiIdtn';0rJ1q:{7;lAl']y:yTjZBbOo?QRIdN>>%dec% ECHO:$Bp@P/nAp_r0*4f'XcF4q3o?$_t5lx$Q-OxSfUNQ__Gd~$Q-Oxgkx=LGHU>>%dec% ECHO:S)$C6P8#>>%dec% ::---- EncBin-encoded binary ---- :: sepname.com made with BASM ASM FREELINK ECHO:AEPPr64U2y00tD61O0AAj7CDXn28A5S5D7JeRkl5Ll00xG47uvgmv5gl[5>%tf% ECHO:gGC0v]U[2uY7213301EBu1Je13dnJDrX5OIZO5QZO5ibr1Vbj3AxS5Ayv6>>%tf% ECHO:Zb02ibf3Axv6Rbf2RbC2Ayv6Jbf3abb3Axv62yK6ebr12rK6ZbC2ib42Ay>>%tf% ECHO:v6ab[3Axv6Eyj5Rb42Dn3e0J]xN53b8l3b6l3bB\2jG0gC7DB7n6j50037>>%tf% ECHO:v6j5000mF0cdr5ilW6tfC106Ld2ZNH37C6n5003yC6n5EXn5Ou3Hr5S3Fe>>%tf% ECHO:IGebC3Axv6EXn56u00qbC3ybb1EyG7qb83ExG7Myn5ebb1Dn3e07]XNJ2Z>>%tf% ECHO:ND2xT32yNN3b6M1nf3r76GeJC5eFf5thpXj5Ou3Fv5S3Ve2GR73F0500Rb>>%tf% ECHO:r2]xn5Iy[7Vb81ebn2Axv6Myr7ib41ubj2hxn5QyC8yb01t3FF451yf3s6>>%tf% ECHO:EGF0O33FK53yFyeTW5tfv2vpNT1bRl3b933b4Z2yV\3bAX0mF006NH0ev6>>%tf% ECHO:j5pZn5abW2RyFTW5RlW6rrW2r0v1fpW8sxC2WxND01Dy3e1I]XND2ZNT3b>>%tf% ECHO:9Z3ynpn59bv6ebv1ebn0Iy[7ZbK20mlZLd2xV\3b2N03b6O5pZn50mj3n6>>%tf% ECHO:n5Oe3DC5eTW5rhv2vpNT1bV\3b7T3b2\2yV\3b8Z1bNV3b8s1bUK3b8m1b>>%tf% ECHO:LR3b8g1bNd3b8a1bV\3b8X1bLR3b8R1bNo3b8L1bWp3b8F1bLR3b892n9C>>%tf% ECHO:F07DAn83Fy3D4me0Z23xlZLI2Au6y0IZK5i3WMLI3x7AcKb5Zjuxlnn2jG>>%tf% ECHO:m3xfdd30coy3PHLNtBvla0iymyylUhyHg9Z1sVLP73LNPMLNXUuXiyZOXU>>%tf% ECHO:uRiyZ8s1LVf3yvRmA[DPlxPG2yNy3byRy3TGLMmvdhHo0AN0VrwULOi3Zr>>%tf% ECHO:6sK0ivZqlfD1Pl0vwQS20ftdBYy3ebaygGZ8]3v0gxEBOUK5IXK5tBDIr5>>%tf% ECHO:46w8I33y1yC2Fy2tK0Bqr37rqa2r2j2ElnnFjGSv1nW5f0trZ0Jvb]p857>>%tf% ECHO:ZYv7WVK186K5y3hXW6s3uyhXW6ryr0gGv6hXW6rnuyhXW6r1C0lyQX3bva>>%tf% ECHO:xxQX2yPG3bvUxxPG3bvWxyPG2BF83rpA603u9yCBF0M819DFZsn0Vhy3hX>>%tf% ECHO:W6uruxhXC6F9l0CWTo16D1ZsLHVn6sK02yK6Fvv]E[m786K5013yG6K5t3>>%tf% ECHO:DKb55ov4vELK2tLO2nn9jXtB5Ib5ZJexlBGUK5EAyxFEFRAn3DCGkLlBtB>>%tf% ECHO:Hp2yPG2BPE3vRmA[0ml8n5N2041LlBt3Bf0ma0X6ixXpW4t8ix9606I9s6>>%tf% ECHO:vw001wW6f1[0X6yxgGO6j5f0Xpv4gGC61puxIs1H0esEyvRmA[0ml8f5Z\>>%tf% ECHO:9Tj4v0iyC5F0M933xxv5mbFxF3LGmbuyyvgGW6K3ujHPRmA[N600N3MBif>>%tf% ECHO:XpW4r\ixZ86u00QBK42nJDnXN202014000070DGA8D0A07000000000000>>%tf% ECHO:0000000000000000000000000000000000000000000000000000000000>>%tf% ECHO:0000000000000000000000000000000000000000000000000000000000>>%tf% ECHO:00000000whOW5jPl1g0000000000j0K00h000000001mH\SW1]TXXnOwC0>>%tf% ECHO:T\1n9]5YPmo\C0LmPnOWP\HrSwn0}>>%tf% :: BASM source... :: rem separate specified name into fpath,fbase,fext :: rem outputs sets to stdout :: $com :: a$=command$:a$=trim$(a$):a$=lcase$(a$) :: if a$="" then :: print "no parm":end :: endif :: rem loop through string, mark last \ and . :: slash=0:dot=0:ilen=len(a$) :: for i=1 to ilen :: c$=mid$(a$,i,1):if c$="\" then slash=i :: if c$="." then dot=i :: next i :: rem not an extension if \ after . :: if slash>dot then dot=0 :: fpath$="":fbase$=a$:fext$="" :: if dot>1 then :: d=dot-1:fbase$=left$(a$,d) :: d=ilen-dot:fext$=right$(a$,d) :: endif :: if slash>1 then :: rem includes trailing \ :: d=slash:fpath$=left$(a$,d) :: d=len(fbase$):d=d-slash :: fbase$=right$(fbase$,d) :: endif :: output "set fpath=";fpath$ :: output "set fbase=";fbase$ :: output "set fext=";fext$ ::------------------------------- :: decode and use _sepname.com to parse input (in %2) %dec% < %tf% > %sepname% if errorlevel 1 goto binerror %sepname% %2 > %temp%.\_sep_tmp.bat call %temp%.\_sep_tmp.bat del %temp%.\_sep_tmp.bat if .%fpath%==. goto incurrent :: change to source directory %fpath% cd %fpath% :incurrent if exist %fbase%.%fext% goto curdirok echo Could not change to directory goto cleanup :curdirok :: ******* :: ******* compiler support, edit as needed :: ******* if .%fext%==.asi goto asifile if .%fext%==.bas goto basfile if .%fext%==.moo goto moofile if .%fext%==.tok goto tokfile echo Unknown filetype, encoding as-is set compname= set madewith=???? set binfile=%fbase%.%fext% goto conv2batch :asifile set compname=ASIC set madewith=ASICC if exist %fbase%.com del %fbase%.com call asicc %fbase%.asi C goto checkcom :basfile set compname=BASM set madewith=BASM ASM FREELINK if exist %fbase%.com del %fbase%.com call basm %fbase%.bas if exist %fbase%.asm call asm %fbase%.asm ; if exist %fbase%.obj call freelink /c %fbase%.obj goto checkcom :moofile set compname=Moonrock set madewith=MRC ASM MRLINK if exist %fbase%.com del %fbase%.com call mrc %fbase%.moo goto checkcom :tokfile set compname=Tokiwa set madewith=TBC if exist %fbase%.com del %fbase%.com call tbc /c %fbase%.tok goto checkcom :: ******* end compiler commands :checkcom set binfile=%fbase%.com if exist %binfile% goto comexists echo. echo ======================================= echo Compile failed, debug and try again echo ======================================= echo. goto cleanup :comexists if exist %fbase%.obj del %fbase%.obj :: try to pklite it (if option enabled) if not .%usepklite%==.yes goto conv2batch copy %binfile% %tf1% >nul call pklite %binfile% fc /b %binfile% %tf1% > %tf2% find "00" < %tf2% > nul ::reset var for docs if not changed by pklite... ::note--not NT compatible here, PkLite status won't ::be properly indicated in the output batch comments if errorlevel 1 set usepklite=no del %tf1% del %tf2% :conv2batch echo. echo Converting to batch code... ::--------------------- :: the EncBin encoder, encodes stdin to stdout, encoded by itself... ECHO:AALIxnCmeRf0\Uf0pWjXYBlxr0MyG02u022nc1Z5Z0r4G2ldMAj[8F34dd>%tf% ECHO:Z1Z0r4G2ld6Aj[8F34Ed3EmbG02lJpNl0jjjCt9v0407ZvjtS3I0j7rvLv>>%tf% ECHO:G203l0wUDv20F42eD3ZujTS6fmprbD2e4uwp39gwYdfDfAdng0f1f0ZF2t>>%tf% ECHO:04bemDCXj0C0LHtA2701ZsG0SFdfW]6630Jf36S6W1f0rJ2fMfQYW1YAoO>>%tf% ECHO:EAt0y[36S6W1[8LRi3}>>%tf% ::--------------------- :: decode encoder... %dec% < %tf% > %enc% if errorlevel 1 goto binerror ::---- EncBin-encoded binary ---- :: 2bat.com made with BASM ASM FREELINK ECHO:AFDJr64U2y00tD61O0AAj7CDXn28p5j5D7JeRkl5ND00xG47uviEv5iD[5>%tf% ECHO:gGC0v]U[2ues213301EBu1Je13dnJDrX5OhZf5pZf5JbC2qb04pxj56yb8>>%tf% ECHO:ybC27b046xb8ubv2qbO26yb8ebv3ybr36xb8qbf2ibK26yb8Zbr36xb8ty>>%tf% ECHO:46RbK2Do3c7j0mF0e5v5hXr8fYW6sQC206N52ZO[23Gx86v0S37cn13bf3>>%tf% ECHO:RyC[W6QXW8s7W3rOv2fPW9t\W3tQr3fPW9sbW2r6v2fPW9tJC3F0MZj56x>>%tf% ECHO:b8Fbj1O335C5b]C6F0O30]f686O[2ZO]3bDc3yOp865bb8Zb437bn16y[9>>%tf% ECHO:ubK30mlZN52y]H2xOY3b7U03K6j5IZ86t3C[061y[3sLW1rnv3vpO[1b]H>>%tf% ECHO:3bBB3b6S2yb93bCc3bCU2xb93b7f3b6A2yb93bCN0mF0e5r5hHW9s7C106>>%tf% ECHO:N52ZO]0mF006O]0eG686QZ86qbr2RyC]W6QHW9tSW2sLv1hHW9uYb2fPf9>>%tf% ECHO:fbW6ubC2WxMs00Dn3c3\2tb92rOd3bB]23[xf5G0S3Bcn0R70f0600ibb2>>%tf% ECHO:tx866yWAqbn0t3Cf061n[3tYO0j6YX006GbbW6tkr1fsv6hXW8tx40e3C5>>%tf% ECHO:bfC6WxOf00Dn3e1u]xOj3b2j2B78bdf6ZO2tC62nJDWXuer0hXW8tPf0Z8>>%tf% ECHO:dX86YBptYX2no0jXJbn06xWABbW0YBlXOd2BeOh1GAg07DBb2w2x]H3b1e>>%tf% ECHO:2B78bdf6ZO6t[92nJDWXt]40bdf6ZOAs00xtb52nJDWXtKW0r2r2fpv6h1>>%tf% ECHO:WArnf0r4hGr4]GsEiyWUOd3b7r2BWU867bv1lnGlq0jXEn0lqyjG0mlAu2>>%tf% ECHO:y0]Zb5QAmxF0deC5mvdfbAN0Vt73LMgNZx0llsyyyvuleqaHIBy1LUDPkH>>%tf% ECHO:PNLMsNNbyXxBuONbyRxB78HUDV3uFvv]][N36xf7]yC7ibqy33LNkMxfMh>>%tf% ECHO:S40AkourLVDOkmC3dsW5y3XLtciyZOgMZq7bey2BoUtBsBVvMBmodBBAxh>>%tf% ECHO:ko6BiHZBRmcnCB3sfevuVJVaee2GfexBi7Keq3N30mkRDTlyWc3bwXxxWc>>%tf% ECHO:2yUk3bwOxxUk3bwQxyUk2BF83rpA603u9yCBF0M819DFZsn0Vhy3fcW8rl>>%tf% ECHO:uyfcC8F9l0CWTo16D1ZsLrVnYsS06yf7Fvv]E[kWYBps3y2tOs2nnyjXol>>%tf% ECHO:KBJ0TPDGLI8ULV2BpxMi2u022BihJvMBxfdBmlMhSQ6BpBFBx]gn03isBu>>%tf% ECHO:Cuoqiar8hGBuXFye02asxBq6070VgQLOXl63B70eVtKeV7yOhPZ867pr81>>%tf% ECHO:JDWXNe0Fabuuy7C6j5012BRQj740R3gLZfQBS46yf7tBG6Fvv]E[F0M81T>>%tf% ECHO:J200gLZfl3r20ml9s6xBHp3bssveP610Q9Jx0w00Pw2r0129s6xyUk3605>>%tf% ECHO:2BHp2yUk03spwEYsS0reJxFvv]E[F0M82Bq\N2042ySs0ma0W5u3fsW7rg>>%tf% ECHO:FxlnnxjXabVxF3KmF0e3G5fw7DBbsewRU9331IKma9WEN32nnvjXZbNx\R>>%tf% ECHO:W7YBpnnxjXmbJx1Qf1pnFDWXs2Fxj14000070DGA8D0A07000000000000>>%tf% ECHO:0000000000000000000000000000000000000000000000000000000000>>%tf% ECHO:0000000000000000000000000000000000000000000000000000000000>>%tf% ECHO:00000000000000000W000000000000000x15X3HF0t0x0x0g}>>%tf% :: BASM source... :: '2bat infile outfile tmpfile :: 'reads infile, surrounds each line with :: '"ECHO:" and ">>tmpfile" (one > 1st line) :: 'and outputs results to outfile :: $com :: $string 120 :: a$=command$:a$=ltrim$(a$):a$=rtrim$(a$) :: if a$<>"" then :: b=instr(a$," ") :: if b>0 then :: infile$=left$(a$,b) :: infile$=rtrim$(infile$) :: c=len(a$):c=c-b :: tmpfile$=right$(a$,c) :: b=instr(tmpfile$," ") :: if b>0 then :: outfile$=left$(tmpfile$,b) :: outfile$=rtrim$(outfile$) :: c=len(tmpfile$):c=c-b :: tmpfile$=right$(tmpfile$,c) :: open infile$ for input as 1 :: if err=0 then :: open outfile$ for output as 2 :: if err=0 then :: done=0:b$=">" :: while done=0 :: line input #1,a$:done=eof :: if done=0 then :: print #2,"ECHO:",a$,b$,tmpfile$ :: b$=">>" :: end if :: wend :: close 2 :: close 1 :: end if :: end if :: end if :: end if :: end if ::------------------------------- :: decode 2bat utility... %dec% < %tf% > %file2bat% if errorlevel 1 goto binerror ::---- EncBin-encoded binary ---- :: cmntsrc.com made with BASM ASM FREELINK ECHO:ADLNr64U2y00tD61O0AAj7CDXn28h5G4D7JeRkl5HB00xG47uvgCv4gB[4>%tf% ECHO:gGC0v]U[2uS1213301EBu1Je13dnJDrX5O]ZC4hZC4ybb0Zb[2hxG42yf6>>%tf% ECHO:mbj0mbW22xf6ebO1ebv02yf6NbW22xf6ly[4Nbv0Dn3e0J]xIU3b413b2H>>%tf% ECHO:3b8j2jG0gC7DAtQj2uI]3b9e2XGq2ZIb23Wxb4v0S3Fe6Gdxb4Rbn0RbO0>>%tf% ECHO:Nb022j2noCjXR62j062GQXb4VbS1pxf42yf6ebK06XG4YZb4t3Eb041nf3>>%tf% ECHO:rLYGQsW4riW2QjW6rcW2OjW4rZf2u7tB6]W4r1G2gC0lmDGXf3vlyDCGF0>>%tf% ECHO:AAmxF0bab4Z63xlZGc33QB4ar4yA]X842AyxJEf23D73mvdd0AkoFtkHTM>>%tf% ECHO:MBBxF0xsyyBvxh7qo96BkV\UN3THLMTMLU7buyYBoUibqyYBk1wUK3muym>>%tf% ECHO:G]cPu3fEv6hwW5uRFykGPNNvtfcob430XowUXVN3Dm2ZGq3rZ3td3yMBF8>>%tf% ECHO:Zsr0SutB4e44bcf4WxGa0UW6HFx3v09y0meygGS0yYW3yHZaf0tjZ0xn3D>>%tf% ECHO:jGC7Ln2rW0hEm0x[W]WT97urv75OO10aC4lyPV3bwJxxPV3b0y2xOE2yPV>>%tf% ECHO:3bw4xxPV3b0133xyK6VbFyxxK6ty06ubBytx063bFyty06YBj3erWTh0vW>>%tf% ECHO:gy0mZ0W5w9I33s1wFhlyPV3bv8xxPV0m39WvKWS756I37sLoangHv0fEj6>>%tf% ECHO:ymG]e3gWZOxsv0ptf4xnFD8XTT0Bkn1PLJsI5IgVZGpx84Au00tBsBivZo>>%tf% ECHO:hfZAulcofQZHhBmmI]SB[3veiuFJTque08[eyuJrBe2GisZVV600bVLR9O>>%tf% ECHO:SOU3j2bewNSemqaO]BV8ZH6r127D9Oye2G7bqxR7114400dBq6071XV3j6>>%tf% ECHO:Ga01v0v6Gc23[x84KQS4uy0cb4fgG4f97DABSU84EAqxiAWUGc2AumyEfm>>%tf% ECHO:pnn2jGy3hwC5F0M933pxf5ybBxJ3fx7DBbsuy3DJF06ZG4pnFDWXsgixM9>>%tf% ECHO:C7kLlBtBHp3brKxBi8f1f0XMG4g07D9TB2000101S000bD0[bD00070000>>%tf% ECHO:0000000000000000000000000000000000000000000000000000000000>>%tf% ECHO:0000000000000000000000000000000000000000000000000000000000>>%tf% ECHO:000000000000000000001h1i9j9XTg0000001]kcP\rWPi1n9]LiTh1[0t>>%tf% ECHO:0t80jt}>>%tf% :: BASM source... :: rem open file specified on command line and write :: rem to stdout with ":: " prefixed to each line :: $com :: a$=command$:a$=trim$(a$) :: if a$="" then :: print "no parm":end :: endif :: open a$ for input as 1:e=err :: if e>0 then :: print "file not found":end :: endif :: fileloop: :: line input #1,a$:e=eof :: if e=0 then :: output ":: ";a$:goto fileloop: :: endif :: close 1 ::------------------------------- :: decode cmntsrc utility... %dec% < %tf% > %cmntsrc% if errorlevel 1 goto binerror ::---- EncBin-encoded binary ---- :: replace.com made with BASM ASM FREELINK ECHO:AGINr64U2y00tD61O0AAj7CDXn28Q587D7JeRkl5S]00xG47uvfav7f][7>%tf% ECHO:gGC0v]U[2uMDA13301EBu1Je13dnJDrX5OYZ47dZ47Fbv2ibO5pyW9dr00>>%tf% ECHO:M90maRXTW1s3v3hDWJs[W5sIv5hDW9fD[0W5fmp95T3bCd2yMD7bLB3bKs>>%tf% ECHO:2y]D2r0Y29C5FRp9K17b43pyWNBbC53b85Qx87pyWPNbj2Jb45pxWPabK4>>%tf% ECHO:Fbv2pyWPJb45Bb05pxWPZb447br2pyWPBb053bv45d1b]D7bI93bBD2yhD>>%tf% ECHO:7bJh2xhD6yUD7bB81of3r4]Gr7C2F0tZ47pxWPabS2O30UC7cqv7vETq3b>>%tf% ECHO:Io3ySpS7obWPJbO43b[2pyWP7bf40mlZSU2y]D6xUD7bC]03r647]ZS7t3>>%tf% ECHO:Ds871vf3r1xGvETs3bHv3y[pS7obWPFb44VbK2pyWTZbS4Q31s870mF0bU>>%tf% ECHO:r7hDWPrFC206SU2ZTq0mF006Tq0e[6S7hZS7BbG4RyDuW7QDWPukW3rTv2>>%tf% ECHO:hDWVrxW4rfr4hDWVskW3rBv2hDWVrfW4rQb4O1obWVFbf3Vbv1pyWRZb44>>%tf% ECHO:pxWRpyWNBbv1Do3e04ac4k3bFo1dW1QDWVt]W3uIv1hDWRumr3hDvRhDWN>>%tf% ECHO:uDK1S3Je2Gmc010mlZSU2xxD7b5x03r647UZS7t3Dq871vf3r4]GugC0Wx>>%tf% ECHO:Tq02Dy3e0raySES7Fbb3RyDqW7QDWVsIW3sxv1hDWVtVv3vETq3bE93ySp>>%tf% ECHO:S7obWV3b83JbO1pyWVNbW3qe2G3bS3pxS7pyWVNb41JbO3xxS7pyWXab01>>%tf% ECHO:R7210700BbK3ubS3JbC1pyWZNbK3pxWZEyW7yb81Dn3e04ae1S]xEDAyMD>>%tf% ECHO:7b4U1nf3r3hGuGpxWZpyWJub01Dn3e0Oab1V3bCH2xU52y6DBb2p3746W7>>%tf% ECHO:003e6eWxU100j2S3ee6GBbv2pxWXJbv2pxWZubr2pyWXybr2Ry21f7t5t3>>%tf% ECHO:E1071yf3r4YGrO00f0lnJDrXh7W7tHW1sQW0rc02f0lnJDrXhDvThDWBsQ>>%tf% ECHO:r0hDvVhDWDsHr0hDvXhDWFs8W0tPr0hDv7hDWXrvW0QDWXtUW2OFW7tOC2>>%tf% ECHO:ln9CF07DAn83Fy3D4me0Z23xlZS62Au6y0YZ07i3WMS63x7Ab8b7Zjuxln>>%tf% ECHO:n2jGm3xfdd30coy3PHLNtBvla0iymyylUhyHg9Z1sVLP73LNPMLNXUuXiy>>%tf% ECHO:ZOXUuRiyZ8s1LVf3yvRmA[DPlx]D2yUD3byRy3TGLMmvdhHo0AN0VrwULO>>%tf% ECHO:N3MBFfZfv6hDOHj5v0hDO7j5r0hDWFtSayX6uxhDWBtJayX6FvF0Q9JtRy>>%tf% ECHO:JtQBJtOuJxXyMxxD2y]D03cpwEtBJvFvv]E[F0M82x]D2y6D7bwQxx6D6y>>%tf% ECHO:hD3bxLworLhDvDhDW7s[iyX67v16ytwEitrPtGhDvFhDC91putIs013vRm>>%tf% ECHO:A[0ml8W5sSiytTMBsTN3NbvWxBROMBZqrOiyZGgUZhkBwNMBxfdBmlMhSS>>%tf% ECHO:6BpBFBx]gn03isBuCuoqiarAhGBuUBkRCekTF3F0oRN3FbuxgGZ8]3v0gx>>%tf% ECHO:EBbU07YX07tBC6r746w8I33y1yC2Fy2tK0Bqr37rqa2r2j2ElnnFjGSv1n>>%tf% ECHO:W5f0trZ0Jvb]p857ZYv7WVK1O607y3hDWBtCuxhDvBhDW9t3uxhDW9t5yx>>%tf% ECHO:hDf9Z8W3xA0TZuvWSB0ml8[5HF]3v0swu3pyWBqbNxpxWB[ml00v9oO8H1>>%tf% ECHO:]1v0K2Vm2s02pyW9Fvv]E[m7O607013yW607t3C8b75ov4vES82tSC2nn9>>%tf% ECHO:jXtB46b7ZJexlBWU07EAyxFEFRAn3DCGkLlBtBHp2y]D2BPE3vRmA[0ml8>>%tf% ECHO:n5N2041LlBt3Bf0ma0X6ixXpW4ufiw9606I9s6vw001wW6f1[0X6yxhDO9>>%tf% ECHO:j5f0Xpv4hDC91puxIs800esEyvRmA[0ml8f5Z\9Tj4v0hDC7F0M933pyW7>>%tf% ECHO:ubiwu3hDW7tPFwkLlBtBHp3bpNxBi8f1f0XMG4g07D9TB200gLZfR62D09>>%tf% ECHO:2GQn2lqyjX\n2Y]D36r6W900]Bq\N30101S000bD0[bD00070000000000>>%tf% ECHO:0000000000000000000000000000000000000000000000000000000000>>%tf% ECHO:0000000000000000000000000000000000000000000000000000000000>>%tf% ECHO:00000000000000000000000000009\Tl9iS08j}>>%tf% :: BASM source... :: 'typical usage: type file | _replace "abc" "def" > newfile :: 'replace all occurences of string "abc" with string "def" :: 'read from standard input, write to standard output :: $com :: $string 512 'max line len :: chr10$=chr$(10) :: chr13$=chr$(13) :: quote$=chr$(34) :: 'parse command line... :: c$=command$ :: c$=ltrim$(c$) 'get rid of surrounding spaces :: c$=rtrim$(c$) :: d$=left$(c$,1) :: if d$<>quote$ then goto clerror :: clen=len(c$) :: clen=clen-1 :: c$=right$(c$,clen) 'remove 1st quote :: qpos=instr(c$,quote$) 'get position of 2nd quote :: if qpos<2 goto clerror 'must be at least 1 char :: qpos=qpos-1 :: str1$=left$(c$,qpos) 'slice off match string :: qpos=qpos+2 :: clen=len(c$) :: rlen=clen-qpos :: str2$=right$(c$,rlen) 'raw second half :: str2$=ltrim$(str2$) 'no extra spaces :: d$=left$(str2$,1) 'check for quotes :: if d$<>quote$ then goto clerror :: d$=right$(str2$,1) :: if d$<>quote$ then goto clerror :: clen=len(str2$) 'make sure valid string :: if clen<2 then goto clerror 'too short :: if clen>2 then 'at least 1 char :: clen=clen-1 :: str2$=right$(str2$,clen) 'remove quotes :: clen=clen-1 :: str2$=left$(str2$,clen) :: else :: str2$="" 'otherwise empty replace :: end if :: oneline$="" 'initialise main processing loop :: linelen=0 'count chars to avoid overrun :: mainloop: 'loop until no more... :: a$=stdin$ 'get one character :: if a$="" then goto nomore 'done with input :: if a$=chr13$ then goto mainloop 'skip cr :: if a$=chr10$ then 'if lf process line :: gosub process 'replace and output :: oneline$="" 'reset string :: linelen=0 :: goto mainloop 'and loop for more :: end if 'if not lf :: if linelen<512 then 'if not overflow :: oneline$=oneline$+a$ 'add to line :: linelen=linelen+1 'bump length count :: end if :: goto mainloop :: nomore: :: if linelen>0 then 'if extra chars w/ no crlf :: gosub process 'process as one line :: endif :: end 'exit to dos :: clerror: 'command line error :: print "error" :: end :: process: 'subroutine... :: replace str1$ with str2$ in oneline$ 'nice :: output oneline$ 'write to stdout+crlf :: return ::------------------------------- :: decode replace helper... %dec% < %tf% > %replace% if errorlevel 1 goto binerror :: everything is in place to convert com into batch code... :: %dec% - the decoder program :: %enc% - encodes binary to text, stdin to stdout :: %file2bat% infile outfile tmpfile - turns into echo code :: %cmntsrc% file - outputs stdout with commented file :: %replace% "search" "replace" - stdin to stdout :: %compname% = the compiler name :: %madewith% = utilities used to compile :: %usetempdir% = yes if tempdir to be used :: %decname% = decoder filename to use :: %tempname% = temp filename to use :: %fbase%.%outputext% = output filename :: determine temp names... set t= if .%usetempdir%==.yes set t=%%temp%%.\ :: create output file... set outfile=%fbase%.%outputext% echo @echo off>%outfile% echo>>%outfile% ::---- Generated by CONV2BAT ---- :: attach decoder... echo>>%outfile% :: CM3-encoded DecBin decoder... %file2bat% %dec% %tf1% %t%%decname% type>>%outfile% %tf1% :: attach encoded com file... echo>>%outfile% ::---- EncBin-encoded binary ---- echo>>%outfile% :: %binfile% made with %madewith% %enc% < %binfile% > %tf% %file2bat% %tf% %tf1% %t%%tempname% type>>%outfile% %tf1% :: attach source code... if not .%compname%==. echo>>%outfile% :: %compname% source... if not .%compname%==. %cmntsrc% %fbase%.%fext% >>%outfile% echo>>%outfile% ::------------------------------- :: attach decode/run/delete lines... echo>>%outfile% :: decode/run/delete, modify as needed... echo>%tf1% %t%%decname% {{.lt{{ %t%%tempname% }}.gt}} %t%%binfile% %replace% "{{.lt{{" "<" < %tf1% > %tf2% %replace% "}}.gt}}" ">" < %tf2% >>%outfile% if not .%compname%==. echo>>%outfile% %t%%binfile% %%1 %%2 %%3 if not .%compname%==. echo>>%outfile% del %t%%binfile% if .%compname%==. echo>>%outfile% :: use %t%%binfile% as needed echo>>%outfile% del %t%%tempname% echo>>%outfile% del %t%%decname% echo. echo =========================================================== echo Done! %binfile% is the raw binary if exist %fbase%.asm echo intermediate assembly is in %fbase%.asm echo %outfile% batch code recreates %binfile% when run echo =========================================================== echo. goto cleanup :binerror echo Error in encoded binary :cleanup if exist %tf% del %tf% if exist %tf1% del %tf1% if exist %tf2% del %tf2% if exist %enc% del %enc% if exist %dec% del %dec% if exist %replace% del %replace% if exist %sepname% del %sepname% if exist %cmntsrc% del %cmntsrc% if exist %file2bat% del %file2bat% :end |
Tasm assembly source for the DecBin decoder... (before CM3 encoding)
;decbin.asm ;original code by Tenie Remmel - zdecode.asm from ASnip ;modified by Terry Newton to use 12 bit/64 char encoding ;verifies length, if not correct outputs ret and sets el=1 Ideal Model Tiny P186 CodeSeg Org 100h Proc Program mov ah,3Fh ;Read file/device xor bx,bx ;handle for STDIN mov dx,1024 ;Start at DS:1K mov cx,63488 ;62K bytes (max) int 21h ;DOS services mov si,1024 ;SI, DI = 1K mov di,si mov ah,'A' ;AH = 'A' call GetDigit ;First digit shl al,4 ;Shift over mov ch,al ;Put in CH call GetDigit ;Second digit or ch,al ;OR into CH call GetDigit ;Third digit shl al,4 ;Shift over mov cl,al ;Put in CL call GetDigit ;Last digit or cl,al ;OR into CL push cx ;Save numbytes InpLoop: lodsb ;Load byte cmp al,21h ;< 21h? jb InpLoop ;Get new byte cmp al,'}' ;Check for right bracket je Done ;It's a right bracket, done ja InpLoop ;Get new byte dec si ;Re-load that byte lodsw ;Load word ;first char in al, 2nd in ah xor dh,dh ;Clear DH cmp al,5Eh ;restore skip ^_` (mod...) jl AL_ok0 sub al,3 AL_ok0: cmp ah,5Eh jl AH_ok0 sub ah,3 AH_ok0: cmp al,3Ah ;restore skip :;<=>?@ (mod...) jl AL_ok sub al,7 AL_ok: cmp ah,3Ah jl AH_ok sub ah,7 AH_ok: sub ax,3030h ;Adjust to binary (mod) mov dl,ah ;Save remainder mov ah,64 ;Multiply by 64 (mod) mul ah add ax,dx ;Add in remainder call Out12 ;Output 12 bits (mod) jmp InpLoop Done: pop cx ;Number of bytes (moved) ;verify size... (mod) mov ax,di ;get output pointer sub ax,1024 ;subtract starting offset cmp ax,cx ;compare actual vs recorded bytes je VerOK ;if equal then cool dec ax cmp ax,cx ;if actual is 1 more then cool jne VerNotOK ;otherwise verify fails xor ax,ax ;zero ax push ax ;save for return value VerOK: ;(stock minus pop plus label) mov ah,40h ;Write file/device mov bx,1 ;handle for STDOUT mov dx,1024 ;Start at DS:1K int 21h ;DOS services ;return errorlevel 0 or 1 depending on verify status pop ax ;get saved errorlevel mov ah, 4Ch ;exit function int 21h ;do it VerNotOK: ;here if size doesn't match (mod) mov cx,1 ;just one byte mov [byte ds:1024],0C3h ;make it a return push cx ;save for return value jmp VerOK ;write it EndP Program Proc GetDigit DLoop: lodsb cmp al,'A' jb DLoop cmp al,'P' ja DLoop sub al,'A' ret EndP GetDigit ;my code follows... SplitFlg db 0 ;if not 0 then split byte SplitByt db 0 ;buffer Proc Out12 ;output 12 bits (to out buffer) ;on calling al/ah=Byte1/Byte2low, Byte3/Byte2high, Byte4/Byte5low ; Byte6/Byte5high, Byte7/Byte8low, etc (starting at 1) push bx cx mov bl,[SplitFlg] ;get even/split flag cmp bl,0 je OutEven ;if 0 then goto OutEven mov bl,[SplitByt] ;get last split byte and bl,0Fh ;low nibble shl ah,4 ;ah=high nibble or ah,bl ;ah=reconstructed byte xchg ah,al ;swap bytes stosb ;store split byte mov al,ah ;put split byte in al stosb ;followed by whole byte mov [SplitFlg],0 ;clear flag jmp Out12x ;exit OutEven: mov [SplitByt],ah ;save split byte low nibble stosb ;store even byte mov [SplitFlg],1 ;set split flag Out12x: pop cx bx ret EndP Out12 End Program |
Tasm source for the EncBin encoder...
;encbin.asm ;original code by Tenie Remmel - zencode.asm from ASnip ;modified by Terry Newton for 12 bits per character pair ;batch-compatible encoding (64 possible values) Ideal Model Tiny P186 CodeSeg Org 100h Proc Program mov ah,3Fh ;Read file/device xor bx,bx ;handle for STDIN mov dx,24064 ;Start at DS:23.5K (mod) mov cx,40960 ;40K bytes (max) (mod) int 21h ;DOS services mov cx,ax ;Number of bytes in CX mov si,24064 ;SI = 23.5K (mod) mov di,1024 ;DI = 1K mov bx,2 ;BX = 2 (words) mov ah,'A' ;AH = 'A' mov al,ch ;First digit shr al,4 ;Shift over add al,ah ;Adjust to text stosb ;Store byte mov al,ch ;Second digit and al,0Fh ;AND mask add al,ah ;Adjust to text stosb ;Store byte mov al,cl ;Third digit shr al,4 ;Shift over add al,ah ;Adjust to text stosb ;Store byte mov al,cl ;Last digit and al,0Fh ;AND mask add al,ah ;Adjust to text stosb ;Store byte add cx,si ;CX = limit for SI InpLoop: call In12 ;Input 12 bits (mod) mov dl,64 ;Divide AX by 64 (mod) div dl ;now AL, AH <= 63 add ax,3030h ;Adjust to text 1st char="0" (mod) cmp al,3Ah ;skip :;<=>?@ (mod...) jl AL_ok add al,7 AL_ok: cmp ah,3Ah jl AH_ok add ah,7 AH_ok: cmp al,5Eh ;skip ^_` (mod...) jl AL_ok0 add al,3 AL_ok0: cmp ah,5Eh jl AH_ok0 add ah,3 AH_ok0: stosw ;Store word inc bx ;Inc line counter cmp bx,29 ;58 chars on this line? (mod) jl Next ;Jump if not xor bx,bx ;Clear line counter mov ax,0A0Dh ;Put a CRLF in AX stosw ;Store it Next: cmp si,cx ;SI > CX? jbe InpLoop ;Jump if not mov al,'}' ;Store bracket (ending char) stosb mov ax,0A0Dh ;Put a CRLF in AX (added) stosw ;Store it (added) mov ah,40h ;Write file/device mov bx,1 ;handle for STDOUT mov cx,di ;Number of bytes mov dx,1024 ;Start at DS:1K sub cx,dx ;Adjust CX int 21h ;DOS services ret ;Exit EndP Program ;the following is my code... SplitByt db 0 ;buffer byte SplitFlg db 0 ;even/split flag Proc In12 ;return next 12 bits in ax, al=whole ah=fractions ;al/ah.. Byte1/Byte2low, Byte3/Byte2high, Byte4/Byte5low etc push bx cx ;save regs mov cl,[SplitFlg] ;get flag cmp cl,0 je get2 ;if 0 then goto get2 lodsb ;get one more byte in al mov ah,[SplitByt] ;ah=left over bits from 2nd byte shr ah,4 ;top nibble mov [SplitFlg],0 ;clear even/split flag jmp exin12 ;exit get2: lodsb ;load byte into al push ax ;save it lodsb ;get next byte mov [SplitByt],al ;into buffer mov bl,al ;save it pop ax ;al=1st byte mov ah,bl ;ah=2nd byte and ah,0Fh ;ah=bottom nibble of 2nd byte mov [SplitFlg],8 ;anything but 0 exin12: pop cx bx ;restore regs ret ;back to caller EndP In12 End Program |
Using Conv2Bat and Reusing Binary Batch Code
Download and install the compilers you wish to use, copy binaries that don't access libraries (such as basm, asm and the linkers) to a path directory, create linking batch files in a path directory for the larger compilers (asicc, mrc, tbc). For Windows, make shortcuts to the doc files of the compilers you're using or make printed copies, you'll need to refer to them often as you write code. If you want to be able to right-click and select "Convert to Batch" (or however named) use Windows' View|Options File Types dialog and add entries for asi, bas, moo and tok files as needed. You can also drag and drop the source file on top of the Conv2Bat.bat file or a shortcut to it. Conv2Bat should work fine in Dos 6, it contains no Windows-specific code but does need the Dos 6 or later FIND command to properly document whether or not PkLite was used. Under NT the comments in the output batch will likely be incorrect but the code output should be the same (if there are no other incompatibilities, have only tested with Win95Cmd).
Conv2Bat outputs batch code that writes the decoder to "_d.com", the temp file to "_t.tmp" and the actual decoded program to its original filename. Edit the output code as needed for your requirements. I often change the file targets to variables (like >>%tf%) to allow writing to the temp directory without requiring a long filename on each line. Once useful utilities have been created you can copy/paste them as needed into your batch files.
I just installed a new compact html browser called "Off By One" and wanted to be able to drag an html file onto the icon to load, but the browser wants to see a file:///c:/whatever type url for local files. Basically I needed a batch that converts a quoted long filename into a url that the browser can load. First I need to convert the long name into a short name (really to get rid of the quotes but doesn't hurt to be short so a simple for loop will do), prepend "file:///" to the quoteless name, and change "\" to "/". Here's what I come up in very little time using code copied from Conv2Bat...
:: OffByOne doesn't understand disk filenames like "c:\web\file.htm" :: Convert parm to "file:///" + name without quotes and change \ to / @echo off set url= if .%1==. goto noparm if not exist %1 goto noparm set dec=%temp%.\_dec.com set tf=%temp%.\_tmp.tmp set replace=%temp%.\_rep.com ::----------------------- :: CM3-encoded DecBin decoder... ECHO:`h}aXP5y`P]4nP_XW(F4(F6(F=(FF)FH(FL(Fe(FR0FTs*}`A?+,>%dec% ECHO:fkOU):G*@Crv,*t$HU[rlf~#IubfRfXf(V#fj}fX4{PY$@fPfZsZ$:NvN$>>%dec% ECHO:9AyroNB-)dOKwK0rRkfTbi)ws_~[[q9wE'sqlu1sY*Bsfe=@ziNS1a)88e>>%dec% ECHO:f9RTL)9Z{3INBD?o6@MDLO{Zz4Q23E-'09NX9@Vz(42A7c8zMS:u$w6k5Q>>%dec% ECHO:N,h:le)~gF?tutTyxoe5UiIdtn';0rJ1q:{7;lAl']y:yTjZBbOo?QRIdN>>%dec% ECHO:$Bp@P/nAp_r0*4f'XcF4q3o?$_t5lx$Q-OxSfUNQ__Gd~$Q-Oxgkx=LGHU>>%dec% ECHO:S)$C6P8#>>%dec% ::---- EncBin-encoded binary ---- :: replace.com made with BASM ASM FREELINK ECHO:AGINr64U2y00tD61O0AAj7CDXn28Q587D7JeRkl5S]00xG47uvfav7f][7>%tf% ECHO:gGC0v]U[2uMDA13301EBu1Je13dnJDrX5OYZ47dZ47Fbv2ibO5pyW9dr00>>%tf% ECHO:M90maRXTW1s3v3hDWJs[W5sIv5hDW9fD[0W5fmp95T3bCd2yMD7bLB3bKs>>%tf% ECHO:2y]D2r0Y29C5FRp9K17b43pyWNBbC53b85Qx87pyWPNbj2Jb45pxWPabK4>>%tf% ECHO:Fbv2pyWPJb45Bb05pxWPZb447br2pyWPBb053bv45d1b]D7bI93bBD2yhD>>%tf% ECHO:7bJh2xhD6yUD7bB81of3r4]Gr7C2F0tZ47pxWPabS2O30UC7cqv7vETq3b>>%tf% ECHO:Io3ySpS7obWPJbO43b[2pyWP7bf40mlZSU2y]D6xUD7bC]03r647]ZS7t3>>%tf% ECHO:Ds871vf3r1xGvETs3bHv3y[pS7obWPFb44VbK2pyWTZbS4Q31s870mF0bU>>%tf% ECHO:r7hDWPrFC206SU2ZTq0mF006Tq0e[6S7hZS7BbG4RyDuW7QDWPukW3rTv2>>%tf% ECHO:hDWVrxW4rfr4hDWVskW3rBv2hDWVrfW4rQb4O1obWVFbf3Vbv1pyWRZb44>>%tf% ECHO:pxWRpyWNBbv1Do3e04ac4k3bFo1dW1QDWVt]W3uIv1hDWRumr3hDvRhDWN>>%tf% ECHO:uDK1S3Je2Gmc010mlZSU2xxD7b5x03r647UZS7t3Dq871vf3r4]GugC0Wx>>%tf% ECHO:Tq02Dy3e0raySES7Fbb3RyDqW7QDWVsIW3sxv1hDWVtVv3vETq3bE93ySp>>%tf% ECHO:S7obWV3b83JbO1pyWVNbW3qe2G3bS3pxS7pyWVNb41JbO3xxS7pyWXab01>>%tf% ECHO:R7210700BbK3ubS3JbC1pyWZNbK3pxWZEyW7yb81Dn3e04ae1S]xEDAyMD>>%tf% ECHO:7b4U1nf3r3hGuGpxWZpyWJub01Dn3e0Oab1V3bCH2xU52y6DBb2p3746W7>>%tf% ECHO:003e6eWxU100j2S3ee6GBbv2pxWXJbv2pxWZubr2pyWXybr2Ry21f7t5t3>>%tf% ECHO:E1071yf3r4YGrO00f0lnJDrXh7W7tHW1sQW0rc02f0lnJDrXhDvThDWBsQ>>%tf% ECHO:r0hDvVhDWDsHr0hDvXhDWFs8W0tPr0hDv7hDWXrvW0QDWXtUW2OFW7tOC2>>%tf% ECHO:ln9CF07DAn83Fy3D4me0Z23xlZS62Au6y0YZ07i3WMS63x7Ab8b7Zjuxln>>%tf% ECHO:n2jGm3xfdd30coy3PHLNtBvla0iymyylUhyHg9Z1sVLP73LNPMLNXUuXiy>>%tf% ECHO:ZOXUuRiyZ8s1LVf3yvRmA[DPlx]D2yUD3byRy3TGLMmvdhHo0AN0VrwULO>>%tf% ECHO:N3MBFfZfv6hDOHj5v0hDO7j5r0hDWFtSayX6uxhDWBtJayX6FvF0Q9JtRy>>%tf% ECHO:JtQBJtOuJxXyMxxD2y]D03cpwEtBJvFvv]E[F0M82x]D2y6D7bwQxx6D6y>>%tf% ECHO:hD3bxLworLhDvDhDW7s[iyX67v16ytwEitrPtGhDvFhDC91putIs013vRm>>%tf% ECHO:A[0ml8W5sSiytTMBsTN3NbvWxBROMBZqrOiyZGgUZhkBwNMBxfdBmlMhSS>>%tf% ECHO:6BpBFBx]gn03isBuCuoqiarAhGBuUBkRCekTF3F0oRN3FbuxgGZ8]3v0gx>>%tf% ECHO:EBbU07YX07tBC6r746w8I33y1yC2Fy2tK0Bqr37rqa2r2j2ElnnFjGSv1n>>%tf% ECHO:W5f0trZ0Jvb]p857ZYv7WVK1O607y3hDWBtCuxhDvBhDW9t3uxhDW9t5yx>>%tf% ECHO:hDf9Z8W3xA0TZuvWSB0ml8[5HF]3v0swu3pyWBqbNxpxWB[ml00v9oO8H1>>%tf% ECHO:]1v0K2Vm2s02pyW9Fvv]E[m7O607013yW607t3C8b75ov4vES82tSC2nn9>>%tf% ECHO:jXtB46b7ZJexlBWU07EAyxFEFRAn3DCGkLlBtBHp2y]D2BPE3vRmA[0ml8>>%tf% ECHO:n5N2041LlBt3Bf0ma0X6ixXpW4ufiw9606I9s6vw001wW6f1[0X6yxhDO9>>%tf% ECHO:j5f0Xpv4hDC91puxIs800esEyvRmA[0ml8f5Z\9Tj4v0hDC7F0M933pyW7>>%tf% ECHO:ubiwu3hDW7tPFwkLlBtBHp3bpNxBi8f1f0XMG4g07D9TB200gLZfR62D09>>%tf% ECHO:2GQn2lqyjX\n2Y]D36r6W900]Bq\N30101S000bD0[bD00070000000000>>%tf% ECHO:0000000000000000000000000000000000000000000000000000000000>>%tf% ECHO:0000000000000000000000000000000000000000000000000000000000>>%tf% ECHO:00000000000000000000000000009\Tl9iS08j}>>%tf% :: BASM source... :: 'typical usage: type file | _replace "abc" "def" > newfile :: 'replace all occurences of string "abc" with string "def" :: 'read from standard input, write to standard output :: $com :: $string 512 'max line len :: chr10$=chr$(10) :: chr13$=chr$(13) :: quote$=chr$(34) :: 'parse command line... :: c$=command$ :: c$=ltrim$(c$) 'get rid of surrounding spaces :: c$=rtrim$(c$) :: d$=left$(c$,1) :: if d$<>quote$ then goto clerror :: clen=len(c$) :: clen=clen-1 :: c$=right$(c$,clen) 'remove 1st quote :: qpos=instr(c$,quote$) 'get position of 2nd quote :: if qpos<2 goto clerror 'must be at least 1 char :: qpos=qpos-1 :: str1$=left$(c$,qpos) 'slice off match string :: qpos=qpos+2 :: clen=len(c$) :: rlen=clen-qpos :: str2$=right$(c$,rlen) 'raw second half :: str2$=ltrim$(str2$) 'no extra spaces :: d$=left$(str2$,1) 'check for quotes :: if d$<>quote$ then goto clerror :: d$=right$(str2$,1) :: if d$<>quote$ then goto clerror :: clen=len(str2$) 'make sure valid string :: if clen<2 then goto clerror 'too short :: if clen>2 then 'at least 1 char :: clen=clen-1 :: str2$=right$(str2$,clen) 'remove quotes :: clen=clen-1 :: str2$=left$(str2$,clen) :: else :: str2$="" 'otherwise empty replace :: end if :: oneline$="" 'initialise main processing loop :: linelen=0 'count chars to avoid overrun :: mainloop: 'loop until no more... :: a$=stdin$ 'get one character :: if a$="" then goto nomore 'done with input :: if a$=chr13$ then goto mainloop 'skip cr :: if a$=chr10$ then 'if lf process line :: gosub process 'replace and output :: oneline$="" 'reset string :: linelen=0 :: goto mainloop 'and loop for more :: end if 'if not lf :: if linelen<512 then 'if not overflow :: oneline$=oneline$+a$ 'add to line :: linelen=linelen+1 'bump length count :: end if :: goto mainloop :: nomore: :: if linelen>0 then 'if extra chars w/ no crlf :: gosub process 'process as one line :: endif :: end 'exit to dos :: clerror: 'command line error :: print "error" :: end :: process: 'subroutine... :: replace str1$ with str2$ in oneline$ 'nice :: output oneline$ 'write to stdout+crlf :: return ::------------------------------- :: decode replace helper... %dec% < %tf% > %replace% del %dec% del %tf% :: convert parameter into url... :: first get rid of quotes... for %%a in (%1) do set file=%%a :: create set for new url... echo set url=file:///%file% > %temp%.\tf1.tmp :: use helper utility to change \ to / %replace% "\" "/" < %temp%.\tf1.tmp > %temp%.\tf2.bat :: run results to set url var... call %temp%.\tf2.bat :: clean up... del %temp%.\tf2.bat del %temp%.\tf1.tmp del %replace% :: run browser... :noparm "c:\Program Files\hpsw\OffByOne\ob1.exe" %url% |
Batch file size is increased, perhaps too much for some tastes, but I don't think that's a huge disadvantage. It does require about 3 seconds to launch rather than 1 second just running the program but a single batch line starting the browser takes almost as long (bin-batch adds only a fraction of a second) and it doesn't matter anyway considering 3 seconds is about 4 times faster than opening Netscape or IE. It doesn't bother me that two com files are created and deleted in my temp directory, it looks scary and takes more bytes, I'm happy I can drag a file to OffByOne and it only took a few minutes to accomplish using a search and replace helper ripped as-is from another bin-batch. I could make it smaller by writing custom code that directly changes "\" to "/" but that would have take longer.. it's faster to copy/paste existing code than write new code if the existing code does the job, the number of lines doesn't figure unless so large it impedes things in other ways.. like when notepad will no longer load the batch. In today's world of multi-megabyte programs a bloated batch is insignificant. I could save space and make the replace utility a persistent file and not encode at all, but then I'd have another utility on my path to keep up with, not worth saving a few kilobytes. Echoed QBasic scripts can do just about anything bin-batch can do, but there's a screen flash, QBasic.exe must be available, and not being able to use "<" or ">" in the code complicates comparisons. Whatever works.
Links to binary batch code and compiler resources
(C) Copyright 2003 by Terry Newton
http://www.infionline.net/~wtnewton