BinToBat.bat - Easily install files of any type or size!

Discussion forum for all Windows batch related topics.

Moderator: DosItHelp

Message
Author
Aacini
Expert
Posts: 1885
Joined: 06 Dec 2011 22:15
Location: México City, México
Contact:

BinToBat.bat - Easily install files of any type or size!

#1 Post by Aacini » 09 Aug 2013 22:50

I take my old BinToHex.bat and HexToBin.bat conversion programs, that allows to encode and decode any binary file into Ascii digits, and modified they in order to keep them updated. The new encoding/decoding method can manage several data files in the same Batch program, as foxidrive suggested some time ago, and have also some features that are useful when installing a large number of files. I also optimized the JScript code so even large files, of about 10-15 MB size, can be encoded and decoded in a reasonably period of time.

EDIT: I fixed the small bug that foxidrive reported in his reply...
EDIT: I added an IF to avoid the inclusion of BinToBat.bat itself.
EDIT: Oct/16/2013: I modified the method to encode text files preserving they as text, so the resulting encoded file is lesser.
EDIT: Oct/20/2013: I added the ability to split a large output file in several parts of a maximum given size.

BinToBat.bat:

Code: Select all

@if (@CodeSection == @Batch) @then

@echo off

REM BinToBat.bat: Create an installer Batch program for binary and text data files
REM Antonio Perez Ayala

if "%~1" neq "" if "%~1" neq "/?" goto begin

echo Create an installer Batch program for data files of any type
echo/
echo BINTOBAT [/T:.ext1.ext2...] [/L:lineSize] [/F[:fileSize]] filename ...
echo/
echo   /T:.ext1.ext2    Specify the extensions of text type files that will not be
echo                    encoded as hexadecimal digits, but preserved as text.
echo   /L:lineSize      Specify the size of output lines (default: 78).
echo   /F[:fileSize]    /F switch specify to generate a Full installer file.
echo                    The optional fileSize specify the maximum output file size.
echo/
echo BinToBat encode the given data files as hexadecimal digits (or preserve they
echo as compressed text) and insert they into InstallFiles.bat program; when this
echo program run, it generates the original data files.
echo/
echo You may rename the InstallFiles.bat program as you wish, but preserving the
echo "Install" prefix is suggested.
echo/
echo You may use wild-cards in the filename list.
echo/
echo If the /F switch is not given, a Partial installer is created:
echo - You may insert a short description for each file.
echo - You may insert divisions in the file listing via a dash in the parameters.
echo - The installer allows to select which files will be downloaded and ask
echo   before overwrite existent files.
echo/
echo If the /F switch is given, a Full installer is created:
echo - The installer always download all files.
echo - You may specify commands that will be executed after the files were copied.
echo - You may specify the maximum size of the output file via /F:fileFize, so in
echo   this case the output file will be divided in parts with a numeric postfix.
echo/
echo   If you use /F switch you can NOT rename the InstallFiles??.bat files; the
echo   first one is the installer and the rest just contain data.
echo/
goto :EOF

:begin
setlocal EnableDelayedExpansion
set atSign=@

rem Process parameters: BinToBat /T:.ext1.ext2 /L:lineSize /F:fileSize file list ...
set "myself=%~F0"
set "params=%*"

set "param=%~1"
set "textTypes="
if /I "%param:~0,3%" equ "/T:" (
   set "textTypes=%param:~3%."
   set "params=!params:* =!"
   shift
)

set "param=%~1"
set lineSize=78
if /I "%param:~0,3%" equ "/L:" (
   set "lineSize=%param:~3%"
   set "params=!params:* =!"
   shift
)

set "param=%~1"
if /I "%param:~0,2%" equ "/F" goto FullInstaller


:PartialInstaller

rem Create the heading part of output file
(
echo %atSign%if (@CodeSection == @Batch^) @then
call :getResource BatchSection-PartialInstaller
echo %atSign%end
call :getResource JScriptSection
echo %atSign%if (@CodeSection == @Resources^) @then
) > InstallFiles.bat

rem Convert each given file to hex digits and embed them in its resource
echo --^>  Enter a short description for each division or file
echo/
set /A id=0, dId=0
for %%a in (%params%) do if /I "%%~NXa" neq "InstallFiles.bat" if /I "%%~NXa" neq "%~NX0" (
   if "%%a" neq "-" (
      if not exist "%%~a" (
         echo File not found: %%a
      ) else (
         set /A id+=1
         set "desc= "
         set /P "desc=!id!- %%~NXa: "
         set type=notx
         if defined textTypes if "!textTypes:%%~Xa.=!" neq "%textTypes%" set type=text
         ( rem Start of redirected block
         echo/
         echo ^<resource id="!id!|%%~Za|%%~NXa|!type!|!desc!"^>
         Cscript //nologo //E:JScript "%myself%" !id! "%%~a" !type! !lineSize!
         echo ^</resource^>
         ) >> InstallFiles.bat
         echo %%~NXa file embedded
      )
   ) else (
      set /A dId-=1
      set "desc= "
      set /P "desc=- "
      ( rem Start of redirected block
      echo/
      echo ^<resource id="!dId!|0|- |div|!desc!"^>
      echo ^</resource^>
      ) >> InstallFiles.bat
   )
   echo/
)

rem Create the trailing part of output file
(
echo/
echo :getLastID
echo set lastID=!id!
echo exit /B
echo/
echo %atSign%end
) >> InstallFiles.bat
goto endFile


:FullInstaller

rem Get the maximum file size from this parameter: /F:fileSize
for /F "tokens=2 delims=:" %%a in ("%param%") do set "maxSize=%%a"
if defined maxSize (
   set /A maxSize-=10
) else (
   set /A maxSize=0x7FFFFFFF
)
set "params=!params:* =!"

rem Create the heading part of output file
del InstallFiles??.bat 2> NUL
(
echo %atSign%if (@CodeSection == @Batch^) @then
call :getResource BatchSection-FullInstaller
) > InstallFiles00.bat
echo Enter commands that will be executed after the files were copied,
echo or an empty line to continue:
echo/
:nextCommand
   set "command="
   set /P "command=> "
   if not defined command goto continue
   echo !command!>> InstallFiles00.bat
goto nextCommand
:continue
( rem Start of redirected block
echo goto :EOF
echo/
echo End of Batch section
echo/
echo/
echo %atSign%end
call :getResource JScriptSection
echo %atSign%if (@CodeSection == @Resources^) @then
) >> InstallFiles00.bat

rem Sort files by size in descending order
for %%a in (%params%) do set "N=%%~Na" & if /I "!N:~0,12!%%~Xa" neq "InstallFiles.bat" if /I "%%~Fa" neq "%myself%" (
   if not exist "%%~a" (
      echo File not found: %%a
   ) else (
      set /A fileSize=0x7FFFFFFF-%%~Za
      set fileSize=000000000!fileSize!
      set "fileName[!fileSize:~-10!-%%a]=1"
   )
)

rem Convert each given file to hex digits or encoded text and embed they in its resource
echo/
set id=0
set lastFile=100
for /F "tokens=2 delims=-]" %%a in ('set fileName[') do (
   set /A id+=1
   set type=notx
   if defined textTypes if "!textTypes:%%~Xa.=!" neq "%textTypes%" set type=text
   ( rem Start of redirected block
   echo/
   echo ^<resource id="!id!|%%~Za|%%~NXa|!type!| "^>
   Cscript //nologo //E:JScript "%myself%" !id! "%%~a" !type! !lineSize!
   echo ^</resource^>
   ) > InstallFiles.bat
   rem Insert this data in the first output file with enough free space
   for %%f in (InstallFiles.bat) do set increment=%%~Zf
   for /L %%i in (100,1,!lastFile!) do if exist InstallFiles.bat (
      set i=%%i
      for %%f in ("InstallFiles!i:~1!.bat") do set /A newSize=%%~Zf+increment
      if !newSize! leq %maxSize% (
         type InstallFiles.bat >> InstallFiles!i:~1!.bat
         del  InstallFiles.bat
      )
   )
   if exist InstallFiles.bat (
      rem Create a new output file
      set /A lastFile+=1
      (
      echo :InstallFiles!lastFile:~1!.bat
      echo/
      echo @goto :EOF
      ) > InstallFiles!lastFile:~1!.bat
      if !increment! leq %maxSize% (
         rem Insert this data in the new empty file
         type InstallFiles.bat >> InstallFiles!lastFile:~1!.bat
         del  InstallFiles.bat
      ) else (
         rem Split this data in several new files
         echo Creating part !lastFile:~1!
         set adjust=0
         if !id! gtr 9 set adjust=1
         set /A "line=0, maxLines=(maxSize-1)/(lineSize+4+adjust)+1"
         for /F "delims=" %%b in (InstallFiles.bat) do (
            set /A line+=1
            if !line! equ !maxLines! (
               echo ^</resource^>>> InstallFiles!lastFile:~1!.bat
               set /A lastFile+=1, line=0
               (
               echo :InstallFiles!lastFile:~1!.bat
               echo/
               echo @goto :EOF
               echo ^<resource id="!id!|%%~Za|%%~NXa|!type!| "^>
               ) > InstallFiles!lastFile:~1!.bat
               echo Creating part !lastFile:~1!
            )
            (
            setlocal DisableDelayedExpansion
            echo %%b
            endlocal
            ) >> InstallFiles!lastFile:~1!.bat
         )
         del InstallFiles.bat
      )
   )
   echo %%~NXa file embedded
)

rem Create the trailing part of output file
(
echo/
echo %atSign%end
) >> InstallFiles00.bat


:endFile
echo/
echo InstallFiles.bat file(s) created
goto :EOF


:getResource resourceId
rem Resource data start format: ^<resource id="resourceId"^>
set start=
set lines=
for /F "tokens=1,3 delims=:=>" %%a in ('findstr /N "^</*resource" "%myself%"') do (
   if not defined start (
      if "%1" equ "%%~b" set start=%%a
   ) else (
      if not defined lines set /A lines=%%a-start-1
   )
)
set line=0
for /F "skip=%start% tokens=1* delims=]" %%a in ('find /N /V "" ^< "%myself%"') do (
   setlocal DisableDelayedExpansion
   echo(%%b
   endlocal
   set /A line+=1
   if !line! equ %lines% exit /B
)
exit /B

End of Batch section


@end


// JScript section

// Convert original input file to encoded Stdout
// Antonio Perez Ayala

// Arguments: idNumber fileName type lineSize

var id = WScript.Arguments(0), lineSize = parseInt(WScript.Arguments(3));

if ( WScript.Arguments(2) == "text" ) {

// Convert input text file into an encoded text form in Stdout
// Each line is encoded as: <number of spaces from 3 to 29><line length>:<line contents>

var fso = new ActiveXObject("Scripting.FileSystemObject");
var input = fso.OpenTextFile(WScript.Arguments(1), 1);  // ForReading = 1
var output = WScript.Stdout, outputLine = "", atSign, key, pos;

while ( ! input.AtEndOfStream ) {
   var inputLine = input.ReadLine(), spaces = 0;
   // Encode <number of spaces>
   while ( inputLine.charAt(spaces) == " " ) spaces++;
   if ( 3 <= spaces && spaces <= 29 ) {
      outputLine += spaces;
      inputLine = inputLine.substr(spaces);
   } else {
      outputLine += "0";
   }
   // Break JScript conditional compilation statements
   atSign = 1;
   while ( atSign ) {
      atSign = inputLine.length;
      for ( key in {"if":0,"elif":0,"else":0,"end":0} ) {
         if ( pos = inputLine.indexOf("@"+key)+1 ) atSign=Math.min(atSign,pos);
      }
      if ( atSign < inputLine.length ) {
         outputLine += atSign+":"+inputLine.substr(0,atSign)+"@";
         inputLine = inputLine.substr(atSign);
      } else {
         atSign = 0;
      }
   }
   // Encode joined <line length>:
   if ( inputLine.length ) outputLine += inputLine.length;
   outputLine += ":";
   if ( outputLine.length >= lineSize ) {
      output.WriteLine(id+":"+outputLine);
      outputLine = "";
   }
   // Encode line contents
   if ( inputLine.length ) outputLine += inputLine;
   // Output result in segments
   while ( outputLine.length > lineSize ) {
      output.WriteLine(id+":"+outputLine.substr(0,lineSize));
      outputLine = outputLine.substr(lineSize);
   }
}
if ( outputLine.length ) output.WriteLine(id+":"+outputLine);

} else {

// Convert binary bytes from input file to Hex digits in Stdout

var ado = WScript.CreateObject("ADODB.Stream");
ado.Type = 2;  // adTypeText = 2
ado.CharSet = "iso-8859-1";  // code page with minimum adjustments for input
ado.Open();
ado.LoadFromFile(WScript.Arguments(1));

var adjustment = "\u20AC\u0081\u201A\u0192\u201E\u2026\u2020\u2021" +
                 "\u02C6\u2030\u0160\u2039\u0152\u008D\u017D\u008F" +
                 "\u0090\u2018\u2019\u201C\u201D\u2022\u2013\u2014" +
                 "\u02DC\u2122\u0161\u203A\u0153\u009D\u017E\u0178" ;

var thisByte = ado.ReadText(1), lastByte = thisByte.charCodeAt(0), lastCount = 1, lastLen = 0,
    output = WScript.Stdout, outputLine = "";
if ( lastByte > 255 ) lastByte = 128 + adjustment.indexOf(thisByte);
while ( ! ado.EOS ) {
   var inputLine = ado.ReadText(128*1024);
   for ( var index = 0; index < inputLine.length; index++ ) {
      thisByte = inputLine.charCodeAt(index);
      if ( thisByte > 255 ) thisByte = 128 + adjustment.indexOf(inputLine.charAt(index));
      if ( thisByte == lastByte ) {
         lastCount++;
      } else {
         lastLen = outputLine.length;
         lastByte = ("0"+lastByte.toString(16)).slice(-2);
         if ( (lastByte == "00" && lastCount == 1) || (lastByte != "00" && lastCount < 4 ) ) {
            for ( var i = 1; i <= lastCount; i++ ) {
               outputLine += lastByte;
            }
         } else {
            outputLine += '[' + lastCount;
            if ( lastByte != "00" ) outputLine += 'x' + lastByte;
            outputLine += ']';
         }
         lastByte = thisByte;
         lastCount = 1;
         if ( outputLine.length > lineSize ) {
            output.WriteLine(id+':'+outputLine.substr(0,lastLen));
            outputLine = outputLine.substr(lastLen);
         }
      }
   }
   WScript.Stderr.Write((ado.Position/ado.Size*100).toFixed() + " % converted\r");
}
lastByte = ("0"+lastByte.toString(16)).slice(-2);
if ( lastCount < 4 ) {
   for ( i = 1; i <= lastCount; i++ ) {
      outputLine += lastByte;
   }
} else {
   outputLine += '[' + lastCount;
   if ( lastByte != "00" ) {
      outputLine += 'x' + lastByte;
   }
   outputLine += ']';
}
output.WriteLine(id+':'+outputLine);
ado.Close();

}

// End of JScript section


@if (@CodeSection == @Resources) @then


<resource id="BatchSection-PartialInstaller">


@echo off
setlocal EnableDelayedExpansion
if "%~1" neq "" if "%~1" neq "/?" goto begin
if "%~1" equ "" (
   echo This program can install the following data files:
   echo/
   for /F tokens^=2-6^ delims^=^"^| %%a in ('findstr "^<resource" "%~F0"') do (
      if %%a gtr 0 (
         echo   %%a- %%c %%e
      ) else (
         echo/
         echo - %%e
      )
   )
   echo/
   echo For help, type: %0 /?
) else (
   echo This program is an installer of several data files included in it.
   echo/
   echo To show a list of the included files, type just:  %0
   echo/
   echo Enter the numbers of the desired files using the same format of "tokens=..."
   echo FOR command's option (type: FOR /? for further details^). For example:
   echo/
   echo     Install just file 6:                 %0 6
   echo     Install files 2, 4 and from 7 to 9:  %0 2,4,7-9
   echo     Install files from 14 to last one:   %0 14*
   echo     Install all files:                   %0 *
   echo/
   echo/
   echo Created using BinToBat.bat file written by Antonio Perez Ayala (aka Aacini^)
)
echo/
goto :EOF

:begin
call :getLastID
set argv=%*
if "%argv%" equ "*" (
   set argv=1-%lastID%
) else (
   if "%argv:~-1%" equ "*" (
      if "%argv:~-2%" equ ",*" set argv=%argv:~0,-1%
      set argv=!argv:~0,-1!-%lastID%
   )
)
set idList=/
for %%a in (%argv%) do (
   for /F "tokens=1,2 delims=-" %%b in ("%%a") do (
      if "%%c" equ "" (
         set idList=!idList!%%b/
      ) else (
         for /L %%i in (%%b,1,%%c) do set idList=!idList!%%i/
      )
   )
)
set action=N
for /F tokens^=2-5^ delims^=^"^| %%a in ('findstr "^<resource" "%~F0"') do (
   if "!idList:/%%a/=/!" neq "%idList%" (
      set "output=%~DP0%%c"
      if exist "!output!" (
         if /I !action! neq A (
            set /P "action=Overwrite %%c? (No/Yes/All): "
            set "action=!action:~0,1!
         )
         set act=!action!
         if /I !act! equ A set act=Y
         if /I !act! equ Y del "!output!"
         if /I !action! neq A set action=N
      )
      if not exist "!output!" (
         echo/
         echo Extracting %%c
         findstr "^%%a:" "%~F0" | Cscript //nologo //E:JScript "%~F0" "!output!" %%b %%d
         echo %%c file created
      )
      echo/
   )
)
goto :EOF

End of Batch section


</resource>


<resource id="BatchSection-FullInstaller">

@echo off
setlocal EnableDelayedExpansion

cd "%~P0"
set lastFile=:dummy:
for %%f in (InstallFiles*.bat) do (
   for /F tokens^=2-5^ delims^=^"^| %%a in ('findstr "^<resource" "%%f"') do (
      if "%%c" neq "!lastFile!" (
         echo Extracting %%c
         set "part="
      ) else (
         echo Appending next part
         set part=part
      )
      findstr "^%%a:" "%%f" | Cscript //nologo //E:JScript InstallFiles00.bat "%%c!part!" %%b %%d
      if defined part (
         type "%%c!part!" >> "%%c"
         del  "%%c!part!"
         echo Part appended
      ) else (
         echo %%c file created
      )
      set "lastFile=%%c"
   )
)
</resource>


<resource id="JScriptSection">


// JScript section

// Convert encoded Stdin to original output file
// Antonio Perez Ayala

// Arguments: fileName size type

if ( WScript.Arguments(2) == "text" ) {

// Convert encoded text from Stdin to output text file
// Each line is encoded as: <number of spaces from 3 to 29><line length>:<line contents>

var fso = new ActiveXObject("Scripting.FileSystemObject");
var output = fso.CreateTextFile(WScript.Arguments(0), true);
//            12345678901234567890123456789
var spaces = "                             ", cutId, digits, inputBuf;
var input = WScript.StdIn, inputLine = "", newLine = "", len;

while ( ! input.AtEndOfStream || inputLine.length ) {
   if ( ! inputLine.length ) {
      inputLine = input.ReadLine();
      for ( cutId = 0; inputLine.charAt(cutId++) != ":"; );
      inputLine = inputLine.substr(cutId);
   }
   len = inputLine.charAt(0);
   inputLine = inputLine.substr(1);
   if ( len == "1"  ||  len == "2" ) {
      len += inputLine.charAt(0);
      inputLine = inputLine.substr(1);
   }
   if ( len != "@"  ) output.Write(newLine+spaces.substr(0,parseInt(len)));
   newLine = "\r\n";
   for ( digits = 0; inputLine.charAt(digits) != ":"; digits++ );
   len = digits ? parseInt(inputLine.substr(0,digits)) : 0;
   inputLine = inputLine.substr(digits+1);
   while ( inputLine.length < len ) {
      inputBuf = input.ReadLine();
      for ( cutId = 0; inputBuf.charAt(cutId++) != ":"; );
      inputLine += inputBuf.substr(cutId);
   }
   output.Write(inputLine.substr(0,len));
   inputLine = inputLine.substr(len);
}
output.WriteLine();
output.Close();

} else {

// Convert Hex digits from Stdin to binary bytes in output file

var ado = WScript.CreateObject("ADODB.Stream");
ado.Type = 2;  // adTypeText = 2
ado.CharSet = "iso-8859-1";  // right code page for output (no adjustments)
ado.Open();

var input = WScript.StdIn, cutId = 0, outputLine = "", byte, count;
var size = parseInt(WScript.Arguments(1));
while ( ! input.AtEndOfStream ) {
   var inputLine = input.ReadLine();
   if ( cutId == 0 ) while ( inputLine.charAt(cutId++) != ':' );
   for ( var index = cutId; index < inputLine.length; ) {
      if ( inputLine.charAt(index) == '[' ) {
         for ( count = ++index; inputLine.charAt(index) != 'x' &&
                                inputLine.charAt(index) != ']' ; index++ ) ;
         count = parseInt(inputLine.slice(count,index++));
         if ( inputLine.charAt(index-1) == 'x' ) {
            byte = String.fromCharCode(parseInt(inputLine.substr(index,2),16));
            index += 3;
         } else {
            byte = String.fromCharCode(0);
         }
         for ( var i = 1; i <= count; i++ ) {
            outputLine += byte;
         }
      } else {
         outputLine += String.fromCharCode(parseInt(inputLine.substr(index,2),16));
         index += 2;
      }
   }
   if ( outputLine.charAt(32*1024) != "" ) {
      ado.WriteText(outputLine);
      outputLine = "";
      WScript.Stderr.Write((ado.Position/size*100).toFixed() + " % converted\r");
   }
}
if ( outputLine.length ) ado.WriteText(outputLine);
ado.SaveToFile(WScript.Arguments(0),2);  // adSaveCreateOverWrite = 2
ado.Close();

}

// End of JScript section


</resource>


@end


I personally don't like this approach because the resulting installer files are too large, but I must admit that this method is simpler to follow. However, I think that the new complaints will come now from the opposite way: "Why I must download a huge program if I only want a small file included in it?" :wink:

Antonio
Last edited by Aacini on 21 Oct 2013 00:25, edited 5 times in total.

foxidrive
Expert
Posts: 6031
Joined: 10 Feb 2012 02:20

Re: BinToBat.bat - Easily install files of any type or size!

#2 Post by foxidrive » 10 Aug 2013 02:10

That's a nice idea Aacini.

I tested it and have to report a bug.

When executing this on around 16 files:

bin2bat.bat *
and
bin2bat.bat *.txt

and then restoring the files in M:\ with InstallFiles.bat * and running fc /b *.* m:*.* I got an error on two files both times.
When testing just on those two files it worked fine.

Here is one error:

Comparing files text1.txt and M:text1.txt
00000000: 32 00
00000001: 30 00
00000002: 31 02
00000003: 33 00
00000004: 30 00
00000005: 37 3F
FC: text1.txt longer than M:text1.txt




It looks to have lots of potential. Nice work otherwise.

Aacini
Expert
Posts: 1885
Joined: 06 Dec 2011 22:15
Location: México City, México
Contact:

Re: BinToBat.bat - Easily install files of any type or size!

#3 Post by Aacini » 10 Aug 2013 04:52

Thanks a lot for your answer, foxi! :D

Do you mean that if you encode 16 files there is an error in text1.txt file and another one, but if you encode just these files there is NO error? This is strange: the code for the encoding/decoding is the same in both cases...

Are the files with error in certain positions inside the list of 16 files? Happen the error again if the files change positions in the list?

May I ask you to do a small test? Please extract the section that corresponds to text1.txt file from the two InstallFiles.bat (including the "<resource id=" lines), modify one of them so the number of the resource be the same in both cases and then FC both sections; indicate in the result which section is the correct one and which one have the error. I apologize for this request, but I tested my program several times and found no error... :?

Antonio

Aacini
Expert
Posts: 1885
Joined: 06 Dec 2011 22:15
Location: México City, México
Contact:

Re: BinToBat.bat - Easily install files of any type or size!

#4 Post by Aacini » 10 Aug 2013 06:20

BUG FIXED :!: :D

Thanks again, foxidrive :mrgreen:

Antonio

foxidrive
Expert
Posts: 6031
Joined: 10 Feb 2012 02:20

Re: BinToBat.bat - Easily install files of any type or size!

#5 Post by foxidrive » 10 Aug 2013 06:31

The two sections compare identically.

I've PM'd you an FTP link for the files to check.

The files that fail to decode properly are 6 and 9.

EDIT: That's great. I've tested your new version and it's working fine.

Magialisk
Posts: 104
Joined: 25 Jul 2013 19:00

Re: BinToBat.bat - Easily install files of any type or size!

#6 Post by Magialisk » 10 Aug 2013 08:13

Wow Aacini this is fantastically useful, and to be honest it couldn't have come at a better time for a project I'm working on in another thread.

I was literally going to start a new thread in the next day or two asking if anyone knew how to take an entire file and convert it to hex, and then back again. This is because I am writing an AES encryption cipher over in the string encryption thread and I wanted to be able to point it at a file and encrypt the hex data representing that file 128 bits at a time.

I have the encryption working, haven't coded the decryption yet, but once I get there I had no idea how to translate a file to hex and back. I just downloaded and tested your BinToHex from the linked thread and it works perfectly. I should be able to use that as the front end into the encryptor and just parse the result 32 hex characters at a time. THANK YOU :!:

I had a little more trouble using your HexToBin.bat to recover the file. It works fine with the associated HexChar.vbs script, but the HexChar.exe doesn't work because it says it's not compatible with 64-bit versions of Windows. I guess that means it's a 16-bit executable? In reading your initial thread I very much agree that I'd prefer not to have a .vbs script required for recovering the binary file, so I was wondering how difficult it would be to create a 64-bit compatible exe? Even without that this is a fantastic set of utilities that I'll definitely be playing with once I get my own code finished. Thanks again!

penpen
Expert
Posts: 1991
Joined: 23 Jun 2013 06:15
Location: Germany

Re: BinToBat.bat - Easily install files of any type or size!

#7 Post by penpen » 10 Aug 2013 14:26

If you have .NET installed, you may use jsc.exe to compile JScript.NET code to an executable, that will work on your system.
Just create jsc.bat:

Code: Select all

:main
   @echo off
   setlocal
   cls

   set "jsc="

   pushd "%SystemRoot%\Microsoft.NET\Framework"
   for /f "tokens=* delims=" %%i in ('dir /b /o:n "v*"') do (
      dir /a-d /b "%%~fi\jsc.exe" >nul 2>&1 && set "jsc="%%~fi\jsc.exe""
   )
   popd

   if defined jsc (
      echo most recent JScript.NET compiler located in:
      echo %jsc%.
   ) else (
      echo JScript.NET compiler not found.
      goto :eof
   )

   %jsc% /nologo /target:exe /out:"%~f1.exe" "%~f1.js"
   goto :eof

Then create the JScript.NET source file to compile.
Note, that WScript is not defined there, so you have to encapsulate this functionality within an own class.
Maybe some other classes are not accessible from .NET... you have just to try it out.
Here is just an example Test.js:

Code: Select all

import System;

class WScript {
   public static function Arguments (index:int) : String {
      return System.Environment.GetCommandLineArgs() [index];
   }

   public static function Echo (message:String) : void {
      print (message);
   }
}

WScript.Echo (WScript.Arguments(1));

And compile all using:

Code: Select all

jsc.bat Test
This will produce Test.exe.
Much fun with that :mrgreen:

penpen

Magialisk
Posts: 104
Joined: 25 Jul 2013 19:00

Re: BinToBat.bat - Easily install files of any type or size!

#8 Post by Magialisk » 10 Aug 2013 15:12

Thank you penpen but I have to admit you're talking a little over my head. Apart from 'gcc -o name name.c' my experience compiling source is as close to zero as to be indistinguishable :oops:.

I actually understand your instructions and I believe I could follow them with some trial and error, however forgive me for not understanding this one particular point: Would I have to take Aacini's .vbs code and re-write it in javascript (or JScript.NET as you called it) or would .NET compile the VB? I'm sure that sounds like a noob question, but I've only ever written C/C++, never Java, Javascript or VBS, and I've certainly never done any .NET programming. I'd probably be better off just rewriting it in C if I'm going to have to port it either way.

penpen
Expert
Posts: 1991
Joined: 23 Jun 2013 06:15
Location: Germany

Re: BinToBat.bat - Easily install files of any type or size!

#9 Post by penpen » 10 Aug 2013 15:59

Magialisk wrote:Would I have to take Aacini's .vbs code and re-write it in javascript (or JScript.NET as you called it) or would .NET compile the VB?
Acini's code to convert hex digits to bytes above is in JScript, and i thought the reverse operation is done in JScript, too.
If this were the case you can use this code, then add the WScript class surogate (the above example is not complete, and should only show, that you only have to define the needed functions), save it to a *.js file and compile the file(s).

But if it is done in vbs, you may use the VB.NET compiler vbc.exe instead of the jsc.exe (with some slight changes to the script, too) to compile it.
If VBS/VB.NET is not your favorite you may translate it to JScript.NET code if you want (or to C# code with csc.exe C#.NET compiler).
:idea: Or maybe Aacini translates it from VBS to VB.NET or JScript.NET.

penpen

PS: JScript.NET is not JScript is not javascript:
javascript is specified by the W3C. JScript 1.0 is compatible with this javascript 1.0 (the same with higher versions i think), but has some extra features..., but in the actual version of JScript it is nearly another language.
JScript is interpreted only; this is done by the WSH (Windows Scripting Host).
JScript.NET is part of the .NET idea and produces executable code only, these two differs mainly on different objects that are accessible, for example the WScript object.
The .NET compilers are little brothers of the compilers contained in Microsofts Visual Studio (much more code optimization, and interface definitions).
But the .NET compilers suffices in most cases, for small tasks as this one (hex value <-> byte).

Magialisk
Posts: 104
Joined: 25 Jul 2013 19:00

Re: BinToBat.bat - Easily install files of any type or size!

#10 Post by Magialisk » 10 Aug 2013 18:18

penpen I really appreciate your attempts to help me, but I'm afraid I'm more confused now after your second post than I was after your first. I'm just out of touch with programming anything that isn't a batch file :P

I'll read your post again with clearer eyes in the morning, but I may just have to fall back to my original plan for doing hex->ascii. I was just going to use a lookup table of sorts to do the conversion, since jeb and dbenham and others have found ways to represent almost every ascii character (all but null?) in batch, I was thinking I could just run the hex through a lookup table to reconstitute the original ascii text. I'm assuming that the reason Aacini's solution is more complicated is because of one of the following:
1.) He's encoding executables, and/or other binary data that isn't strictly ASCII text whereas I'm only concerned about encoding text files. - or -
2.) I haven't given this problem enough thought, and I really need something like Aacini created but I don't know it yet

In any case I still need to code the decryption portion of my AES algorithm before I can worry about running files through it, so I'll have to revist this issue again when the time comes. Thanks again for your help!

carlos
Expert
Posts: 503
Joined: 20 Aug 2010 13:57
Location: Chile
Contact:

Re: BinToBat.bat - Easily install files of any type or size!

#11 Post by carlos » 10 Aug 2013 19:11

aacini i run it for know it and i get a message error using windows xp xp3:

Code: Select all

C:\Documents and Settings\Carlos\Escritorio\bintobat.cmd(195, 1) WScript.CreateObject: No se pudo crear el objeto denominado "ADODB.Stream".


also, you look my bhx utility

Code: Select all

http://www.dostips.com/forum/viewtopic.php?f=3&t=4104
, i work hard in it, it can generate compatible code for do rebuilds in windows nt, and also, if the file es cabinet it automatically add the code for expand it, and is open source.

brinda
Posts: 78
Joined: 25 Apr 2012 23:51

Re: BinToBat.bat - Easily install files of any type or size!

#12 Post by brinda » 11 Aug 2013 07:16

antonio,
thanks working in win2000 and winxp. another way to pass executable through email. Unless the anti-virus starts detecting... :D

Aacini
Expert
Posts: 1885
Joined: 06 Dec 2011 22:15
Location: México City, México
Contact:

Re: BinToBat.bat - Easily install files of any type or size!

#13 Post by Aacini » 16 Oct 2013 10:14

@carlos:

The main reason I had to write this program was the capability to include several files in the same encoded data and extract individual files. My first program can be used to encode/decode any data file including those formats that contain several files, althought I prefer the more common .zip format instead of the .cab one, but there is no method to extract an individual file from anyone of these compressed formats. Also, my program is entirely provided in source code.

___________________________________________________________________________________


I modified the BinToBat.bat program in order to preserve the format of text files and not encode they in hexadecimal digits, so the size of the resulting data is lesser. The posted code have now the updated version.

Antonio

Aacini
Expert
Posts: 1885
Joined: 06 Dec 2011 22:15
Location: México City, México
Contact:

Re: BinToBat.bat - Easily install files of any type or size!

#14 Post by Aacini » 09 Jan 2014 19:41

I started the conversion programs mentioned at beginning of this thread with the purpose to have a method to convert binary files to Ascii text and vice versa, so they can be copied from forums like this one or sent via email, for example. The programs of that thread evolved into this one so the last version of BinToBat.bat have multiple features useful for encode a large number of files, select which ones to extract, split the encoded data in several parts of a maximum size, etc. However, as foxidrive indicated several times, these methods are not simple enough to be used by a novice Batch file user. This is a problem if you write a program that use a binary file (for example, one of my Auxiliary .EXE Programs) and you want that the Batch file be downloaded and used by anyone.

I extracted the decoding part from BinToBat.bat program and isolate it into a subroutine that may be easily called in a Batch program; this subroutine is a simpler form suitable for small files. This way, you may develop your own Batch file applications with embedded binary data so the final user have not to complete any additional step in order to use they, besides downloading the program.

Code: Select all

@if (@CodeSection == @Batch) @then


@echo off

rem Place your Batch code here.
echo This program requires filename.ext binary file.

rem Use :ExtractBinaryFile subroutine to extract the binary file; for example:
if not exist filename.ext call :ExtractBinaryFile filename.ext

goto :EOF


rem Extract Binary File from hexadecimal digits placed in a "resource" in this .bat file

:ExtractBinaryFile filename.ext
setlocal EnableDelayedExpansion
set "start="
set "end="
for /F "tokens=1,3 delims=:=>" %%a in ('findstr /N /B "</*resource" "%~F0"') do (
   if not defined start (
      if "%%~b" equ "%~1" set start=%%a
   ) else if not defined end set end=%%a
)
(for /F "skip=%start% tokens=1* delims=:" %%a in ('findstr /N "^" "%~F0"') do (
   if "%%a" == "%end%" goto decodeHexFile
   echo %%b
)) > "%~1.hex"
:decodeHexFile
< "%~1.hex" Cscript //nologo //E:JScript "%~F0" Extract "%~1"
del "%~1.hex"
exit /B

<resource id="filename.ext">
Put here the hexadecimal digits representation of "filename.ext". You may create it with BinToHex.bat program:
http://www.dostips.com/forum/viewtopic.php?f=3&t=3202
</resource>

<resource id="anotherFile.ext">
You may include several binary files, each one with its own resource id.
</resource>


@end


// Convert Ascii hexadecimal digits from Stdin to a binary string
var count, byte, output = "";
while ( !WScript.Stdin.AtEndOfStream ) {
   var input = WScript.Stdin.ReadLine();
   for ( var index = 0; index < input.length; ) {
      if ( input.charAt(index) == '[' ) {
         for ( count = ++index; input.charAt(index) != 'x' &&
                                input.charAt(index) != ']' ; index++ ) ;
         count = parseInt(input.slice(count,index++));
         if ( input.charAt(index-1) == 'x' ) {
            byte = String.fromCharCode(parseInt(input.substr(index,2),16));
            index += 3;
         } else {
            byte = String.fromCharCode(0);
         }
         for ( var i = 1; i <= count; i++ ) output += byte;
      } else {
         output += String.fromCharCode(parseInt(input.substr(index,2),16));
         index += 2;
      }
   }
}

// Write the binary string to the output file
var ado = WScript.CreateObject("ADODB.Stream");
ado.Type = 2;  // adTypeText = 2
ado.CharSet = "iso-8859-1";  // right code page for output (no adjustments)
ado.Open();
ado.WriteText(output);
ado.SaveToFile(WScript.Arguments(0),2); // adSaveCreateOverWrite = 2
ado.Close();


You may review and example of this method at this post.

Antonio
Last edited by Aacini on 10 Jan 2014 12:58, edited 1 time in total.

siberia-man
Posts: 208
Joined: 26 Dec 2013 09:28
Contact:

Re: BinToBat.bat - Easily install files of any type or size!

#15 Post by siberia-man » 10 Jan 2014 08:07

Aacini, you have posted very interesting solution at your first post. I've just began to learn it and found the weird code. Could you give more details on it?

Code: Select all

   // Encode <number of spaces>
   while ( inputLine.charAt(spaces) == " " ) spaces++;
   if ( 3 <= spaces && spaces <= 29 ) {
      outputLine += spaces;
      inputLine = inputLine.substr(spaces);
   } else {
      outputLine += "0";
   }


Why the number of leading spaces to be trimmed is limited by 3 and 29?
I cannot understand what is the big difference between 29 and 30 leading spaces =)Why leading spaces only, not trailing?
Is it possible to rewrite it to be better understandable? What will happen if I replace the part above by the following example (it looks much better):

Code: Select all

// Encode the number of leading spaces
var re = /^ +/;
var m = re.exec(inputLine) || { lastIndex: 0 };

inputLine = inputLine.slice(m.lastIndex);
outputLine += m.lastIndex;


update

Could you be so kind as to perform the following changes to your script
1. Replace the first line of the script with (append the opening js-comment /*)

Code: Select all

@if (@CodeSection == @Batch) @then /*

2. Put the closing JS-comment between cmd and js parts

Code: Select all

@end
*/


Of course, we can do it ourselves. But it will help folks reading the code in editors with syntax highlighting.

Post Reply