BHX 4.0
Moderator: DosItHelp
BHX 4.0
This version was deprecated because bugs and the latest version is found here:
http://www.dostips.com/forum/viewtopic.php?f=3&t=6400
BHX 4.0
I left here the rebuild script for the stable version of bhx, a tool for rebuild binary data from batch.
The utility is free and open source.
The source can be found here: http://consolesoft.com/p/bhx
Note: many thanks to foxidrive, npocmaka_, Aacini, Honguito98 and einstein1969 for suggestions, bug reporting or good comments.
http://www.dostips.com/forum/viewtopic.php?f=3&t=6400
BHX 4.0
I left here the rebuild script for the stable version of bhx, a tool for rebuild binary data from batch.
The utility is free and open source.
The source can be found here: http://consolesoft.com/p/bhx
Note: many thanks to foxidrive, npocmaka_, Aacini, Honguito98 and einstein1969 for suggestions, bug reporting or good comments.
Last edited by carlos on 14 Apr 2015 07:30, edited 6 times in total.
Re: BHX 3.5.1 [stable version]
I posted a minor update. Now the latest version is 3.5.1
Re: BHX 3.5.1 [stable version]
Thanks carlos.
Re: BHX 4.0 [new stable version]
I posted a new version. The version 4.0 speedy up so much the creation of bigger files.
For get this I removed the usage of certutil.exe and also I removed the creation of a temporal file with hexadecimal data.
Instead of it, a vbs script read the data directly from the batch script.
The difference is great. See the next table for see the difference in the creation of a file of 308 KB (316317 bytes)
comparation of time of creation of bigger file (308KB)
v4.0 : 2 seconds
v3.5 : 3 minutes 16 seconds (so slow)
For get this I removed the usage of certutil.exe and also I removed the creation of a temporal file with hexadecimal data.
Instead of it, a vbs script read the data directly from the batch script.
The difference is great. See the next table for see the difference in the creation of a file of 308 KB (316317 bytes)
comparation of time of creation of bigger file (308KB)
v4.0 : 2 seconds
v3.5 : 3 minutes 16 seconds (so slow)
Re: BHX 4.0 [new stable version]
Magic! Thanks carlos.
-
- Posts: 129
- Joined: 08 Feb 2016 20:25
Re: BHX 4.0
I was attempting to download the source for bhx.exe from the link above:
But the site is now offline. I was wondering if anyone downloaded this while it was available?
Code: Select all
The source can be found here: http://consolesoft.com/p/bhx
But the site is now offline. I was wondering if anyone downloaded this while it was available?
-
- Expert
- Posts: 1166
- Joined: 06 Sep 2013 21:28
- Location: Virginia, United States
Re: BHX 4.0
mirrormirror wrote:I was attempting to download the source for bhx.exe from the link above:Code: Select all
The source can be found here: http://consolesoft.com/p/bhx
But the site is now offline. I was wondering if anyone downloaded this while it was available?
As the first post says, 4.0 has been deprecated in favor of 5.6: viewtopic.php?f=3&t=6400
-
- Posts: 129
- Joined: 08 Feb 2016 20:25
Re: BHX 4.0
As the first post says, 4.0 has been deprecated in favor of 5.6: viewtopic.php?f=3&t=6400
Yes, i saw that - and have downloaded bhx.exe v5.6 - but the source code was located on the consoesoft site (for the latest version) and I never downloaded it. Just wondering if anyone was able to get it before the site went down.
Re: BHX 4.0
carlos wrote:I left here the rebuild script for the stable version of bhx, a tool for rebuild binary data from batch.
Would someone explain for non-experienced batchers like me, in what scenarios this tool may be useful? Is it for updating & compressing something like SQL Database after adding new data to it by running BHX batch? What are the advantages of such method compare to other existing? Similar question was posted by another member here, never answered. Understanding what to use this tool for can greatly broaden its user base, so its usually in the open source author's interest to give some practical examples.
Re: BHX 4.0
sambul35 wrote:Would someone explain for non-experienced batchers like me, in what scenarios this tool may be useful?
Batch files display readable text, whereas binary files contain control characters and 8 bit characters.
This tool allows someone to include any binary file (image, program, data file or text file) within the batch script, so it can be recreated by someone. One benefit is including a utility that the batch script itself uses, inside the batch script, so no extra files are required.
-
- Posts: 129
- Joined: 08 Feb 2016 20:25
Re: BHX 4.0
Well, I found the code on google cache: http://webcache.googleusercontent.com/s ... clnk&gl=us
So now my next question...
I would love to modify this (and hopefully it is fine with Carlos as he said it is open source) to change the width of the output file - but I don't know C language !
So if anyone has some spare time and would be willing to help with this please let me know. I'd like to be able to pass the output width via a command-line parameter. I'm guessing the code that needs to change is in one or both of these places:
The whole thing is here:
So now my next question...
I would love to modify this (and hopefully it is fine with Carlos as he said it is open source) to change the width of the output file - but I don't know C language !
So if anyone has some spare time and would be willing to help with this please let me know. I'd like to be able to pass the output width via a command-line parameter. I'm guessing the code that needs to change is in one or both of these places:
Code: Select all
for (i = 0; i <= last_offset; ++i) {
fprintf(fileOutput, "%02X", buffer.data[i]);
chrs_printed += 2;
if ((64 == chrs_printed) || (i == last_offset)) {
fprintf(fileOutput, "\n");
chrs_printed = 0;
}
}
Code: Select all
if ((60 == chrs_printed) || (i == last_offset)) {
chrs_printed = 0;
fprintf(fileOutput, "\n");
}
The whole thing is here:
Code: Select all
/*
Copyright (C) 2010-2015 Carlos Montiers Aguilera
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
Carlos Montiers Aguilera
cmontiers@gmail.com
*/
/*
BHX v5.6
*/
#include <windows.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <io.h>
#include <conio.h>
#define IS_NOT_CAB (0)
#define CAB_OK (1)
#define CAB_INVALID (2)
#define CAB_NEED_OTHERS_FILES_FOR_EXPAND (3)
#define CAB_FILE_UNKNOW_COMPRESSION (4)
#define CAB_UTF_FILENAMES (5)
#define CAB_FILES_WITH_PATH_PREFIX (6)
#define cfhdrPREV_CABINET 0x0001
#define cfhdrNEXT_CABINET 0x0002
#define cfhdrRESERVE_PRESENT 0x0004
#define ifoldCONTINUED_FROM_PREV (0xFFFD)
#define ifoldCONTINUED_TO_NEXT (0xFFFE)
#define ifoldCONTINUED_PREV_AND_NEXT (0xFFFF)
#define A_NAME_IS_UTF (0x80)
#define COMPRESSION_NONE (0)
#define COMPRESSION_MSZIP (1)
#define COMPRESSION_QUANTUM (2)
#define COMPRESSION_LZX (3)
struct CFHEADER {
BYTE signature[4]; /* cabinet file signature */
DWORD reserved1; /* reserved */
DWORD cbCabinet; /* size of this cabinet file in bytes */
DWORD reserved2; /* reserved */
DWORD coffFiles; /* offset of the first CFFILE entry */
DWORD reserved3; /* reserved */
BYTE versionMinor; /* cabinet file format version, minor */
BYTE versionMajor; /* cabinet file format version, major */
WORD cFolders; /* number of CFFOLDER entries in this cabinet */
WORD cFiles; /* number of CFFILE entries in this cabinet */
WORD flags; /* cabinet file option indicators */
WORD setID; /* must be the same for all cabinets in a set */
WORD iCabinet; /* number of this cabinet file in a set */
WORD cbCFHeader; /* (optional) size of per-cabinet reserved area */
BYTE cbCFFolder; /* (optional) size of per-folder reserved area */
BYTE cbCFData; /* (optional) size of per-datablock reserved area */
BYTE *abReserve; /* (optional) per-cabinet reserved area */
BYTE *szCabinetPrev; /* (optional) name of previous cabinet file */
BYTE *szDiskPrev; /* (optional) name of previous disk */
BYTE *szCabinetNext; /* (optional) name of next cabinet file */
BYTE *szDiskNext; /* (optional) name of next disk */
};
struct BUFFER {
BYTE *data;
DWORD size;
};
struct TRACKER {
struct BUFFER *buffer;
DWORD offset;
BOOL BufferOverflowAttempt;
};
static char map_enc85[85 + 1] = {
"0123456789"
"abcdefghij"
"klmnopqrst"
"uvwxyzABCD"
"EFGHIJKLMN"
"OPQRSTUVWX"
"YZ.-:+=^`/"
"*?&<>()[]{"
"}~,$#"
};
int bhx(char *pathFile, char *options[], long number_of_options);
char *getFileName(char *);
struct BUFFER file2buffer(char *);
void help(void);
int getCabInfo(struct BUFFER *, struct CFHEADER *);
BOOL canNotIncrement(struct TRACKER *, DWORD);
BOOL skipOffset(struct TRACKER *, DWORD);
BYTE readByte(struct TRACKER *);
WORD readWord(struct TRACKER *);
DWORD readDWord(struct TRACKER *);
DWORD bufferlen(struct TRACKER *);
BOOL bufferHavePathSeparator(struct TRACKER *);
int main(int argc, char *argv[]);
void help(void)
{
printf("\nBHX v5.6\n"
"Encode a binary file in a batch script for rebuild it.\n"
"\n"
"By default, the generated batch script name is mybin.cmd.\n"
"Is recommended convert your file in a cabinet\n"
"with compression, created with this command line:\n"
"Makecab /d compressiontype=lzx file file.cab\n"
"and use the generated cabinet as source.\n"
"This can save many bytes in the output script.\n"
"\n"
"BHX source [/ne] [/o:out] [/y]\n"
"\n"
" source Binary to encode.\n"
" /ne If the source file is a cabinet, not write code\n"
" for expand it.\n"
" /o:out out is the output filename instead of mybin.cmd.\n"
" /y Overwrite the output file.\n"
" /hex Encode binary data using 16 hexadecimal characters.\n"
" The default encoder uses 85 printable characters.\n"
"\n"
"BHX /author\n"
" display the author of the program.\n" "\n");
}
int main(int argc, char *argv[])
{
if (argc == 2) {
if (!stricmp(argv[1], "/author")) {
printf
("\nBHX was programmed by Carlos Montiers Aguilera.\n\n");
goto bye;
}
}
if ((argc >= 2) && (argc <= 5)) {
char *pathFile = argv[1];
#define NUMBER_OF_OPTIONS (4)
if ((0 != stricmp(pathFile, "/?"))) {
char *options[NUMBER_OF_OPTIONS] = {
NULL,
NULL,
NULL,
NULL
};
int opt_index = 0;
int argv_index = 2;
while (opt_index < NUMBER_OF_OPTIONS) {
if (argc > (argv_index)) {
options[opt_index] = argv[argv_index];
}
opt_index++;
argv_index++;
}
return bhx(pathFile, options, NUMBER_OF_OPTIONS);
}
}
help();
bye:
return 0;
}
char *getFileName(char *filePath)
{
char *fileName = filePath;
char *pi = filePath;
while (*pi) {
if (('\\' == *pi) || ('/' == *pi)) {
fileName = pi + 1;
}
++pi;
}
return fileName;
}
int bhx(char *pathFile, char *options[], long number_of_options)
{
char *Sign = "Script made using BHX 5.6 { consolesoft.com/p/bhx }";
char *ouputFileName = "mybin.cmd"; /* Default output filename */
char *fileName;
FILE *fileOutput;
struct BUFFER buffer;
struct CFHEADER cab;
int cabinfo;
int cabinetNameIsInside = FALSE;
BOOL HexEncode = FALSE; /* Use enc85 as default */
WORD index;
BYTE *p;
long i;
long last_offset;
UINT num;
UINT divisor;
int cnt;
int chrs_printed;
int fileOutputExists;
int ExpandCabinet = TRUE; /* Generate code for expand cab file */
int Overwrite = FALSE; /* Overwrite ouput file */
int argument_error = FALSE;
char option_ne[] = { '/', 'n', 'e', '\0' };
char option_o[] = { '/', 'o', ':', '\0' };
char option_y[] = { '/', 'y', '\0' };
char option_hex[] = { '/', 'h', 'e', 'x', '\0' };
#define O_OPTION_PREFIX_LENGTH 3
for (i = 0; i < number_of_options; ++i) {
if (NULL != options[i]) {
if (!stricmp(options[i], option_ne)) {
ExpandCabinet = FALSE;
} else if (!stricmp(options[i], option_y)) {
Overwrite = TRUE;
} else if (!stricmp(options[i], option_hex)) {
HexEncode = TRUE;
} else
if (!strnicmp(options[i], option_o, O_OPTION_PREFIX_LENGTH)
) {
ouputFileName = options[i] + O_OPTION_PREFIX_LENGTH;
} else {
printf("Error: Invalid argument: %s\n", options[i]);
argument_error = TRUE;
}
}
}
if (argument_error) {
return 1;
}
buffer = file2buffer(pathFile);
if (NULL == buffer.data) {
printf("Error: Source cannot be opened for reading.\n");
return 1;
}
if (0 == buffer.size) {
printf("Error: Source is empty.\n");
free(buffer.data);
return 1;
}
fileOutputExists = (-1 != _access(ouputFileName, 0));
if (fileOutputExists && !Overwrite) {
/* Prompt for overwrite */
int goOut = FALSE;
int reply;
while (!goOut) {
printf("Overwrite \"%s\"? (y/n): ", ouputFileName);
reply = getch();
printf("%c\n", reply);
switch (reply) {
case 'Y':
case 'y':
Overwrite = TRUE;
goOut = TRUE;
break;
case 'N':
case 'n':
Overwrite = FALSE;
goOut = TRUE;
break;
}
}
if (!Overwrite) {
free(buffer.data);
return 1;
}
}
fileOutput = fopen(ouputFileName, "w");
if (NULL == fileOutput) {
printf("Error: \"%s\" cannot be opened for writing.\n",
ouputFileName);
free(buffer.data);
return 1;
}
fileName = getFileName(pathFile); /* Get fileName */
cabinfo = getCabInfo(&buffer, &cab);
/* If is cabinet not preserve attributes of files inside it */
if (CAB_OK == cabinfo) {
p = buffer.data + cab.coffFiles;
for (index = 0; index < cab.cFiles; ++index) {
p += 14;
*p++ = 0; //None attribute
*p++ = 0; //None attribute
if (!cabinetNameIsInside) {
cabinetNameIsInside = !stricmp((const char *) p, fileName);
}
p += strlen((const char *) p) + 1;
}
}
if (IS_NOT_CAB == cabinfo) {
ExpandCabinet = FALSE;
}
if (ExpandCabinet) {
if (cabinetNameIsInside) {
ExpandCabinet = FALSE;
printf
("The cabinet have inside a filename equal to the cabinet name.\n"
"If you want expand it, first rename the cabinet.\n");
} else if (CAB_OK != cabinfo) {
ExpandCabinet = FALSE;
switch (cabinfo) {
case CAB_INVALID:
printf("The cabinet archive is corrupted\n");
break;
case CAB_NEED_OTHERS_FILES_FOR_EXPAND:
printf
("The cabinet need one or more cabinets for expand it.\n");
break;
case CAB_FILE_UNKNOW_COMPRESSION:
printf
("The cabinet have inside files with unknow compression.\n");
break;
case CAB_UTF_FILENAMES:
printf("The cabinet have inside filenames with utf.\n");
break;
case CAB_FILES_WITH_PATH_PREFIX:
printf
("The cabinet have inside filenames with one or more path separator.\n");
break;
}
}
if (!ExpandCabinet) {
printf("The code for expand it will not be included !\n");
}
}
fprintf(fileOutput,
"@Echo Off\n"
"SetLocal EnableExtensions\n"
"Call :Rebuild\n"
"If ErrorLevel 1 Echo Rebuild failed.\n"
"Goto :Eof\n\n"
":Rebuild\n"
"Rem %s\n"
"SetLocal EnableExtensions EnableDelayedExpansion\n"
"Set \"bin=%s\"\n"
"Set /A \"size=%lu\"\n", Sign, fileName, buffer.size);
fprintf(fileOutput, "For %%%%# In (\n");
if (ExpandCabinet) {
p = buffer.data + cab.coffFiles;
for (index = 0; index < cab.cFiles; ++index) {
p += 16;
fprintf(fileOutput, "\"%s\"\n", p);
p += strlen((const char *) p) + 1;
}
}
fprintf(fileOutput,
"\"!bin!\" \"!bin!.da\" \"!bin!.tmp\"\n"
") Do If Exist \"%%%%#\" (Del /A /F /Q \"%%%%#\" >Nul 2>&1\n"
"If ErrorLevel 1 Exit /B 1 )\n"
"Set \"fsrc=%%~f0\"\n"
"Findstr /B /N \":+res:!bin!:\" \"!fsrc!\" >\"!bin!.tmp\"\n"
"(Set /P \"inioff=\"\n"
"Set /P \"endoff=\") <\"!bin!.tmp\"\n"
"For /F \"delims=:\" %%%%# In (\"!inioff!\") Do Set \"inioff=%%%%#\"\n"
"For /F \"delims=:\" %%%%# In (\"!endoff!\") Do Set \"endoff=%%%%#\"\n"
"Set \".=ado=\"adodb.stream\"\"\n"
"Set \".=!.! :set a=createobject(ado) :a.type=1 :a.open\"\n"
"Set \".=!.! :set u=createobject(ado) :u.type=2 :u.open\"\n"
"Set \".=!.! :set fs=createobject(\"scripting.filesystemobject\")\"\n"
"Set \".=!.! :set s=fs.opentextfile(\"!fsrc!\",1,0,0)\"\n");
if (HexEncode) {
fprintf(fileOutput,
"Set \".=!.! :for i=1 to !inioff! step 1 :s.readline :next\"\n"
"Set \".=!.! :do while i<!endoff! :d=replace(s.readline,\" \",\"\")\"\n"
"Set \".=!.! :for j=1 to len(d) step 2\"\n"
"Set \".=!.! :u.writetext chrb(\"^&h\"&mid(d,j,2))\"\n");
} else {
fprintf(fileOutput,
"Set \".=!.! :e=\"0123456789abcdefghijklmnopqrstuvwxyzABCDEF\"\n"
"Set \".=!.!GHIJKLMNOPQRSTUVWXYZ.-:+=^^`/*?&<>()[]{}~,$#\"\n"
"Set \".=!.!\" :max=!size! :wri=0 :n=array(0,0,0,0,0)\"\n"
"Set \".=!.! :for i=1 to !inioff! step 1 :s.readline :next\"\n"
"Set \".=!.! :do while i<!endoff! :d=replace(s.readline,\" \",\"\")\"\n"
"Set \".=!.! :for j=1 to len(d) step 5 :num85=mid(d,j,5)\"\n"
"Set \".=!.! :v=0 :for k=1 to len(num85) step 1\"\n"
"Set \".=!.! :v=v*85+instr(1,e,mid(num85,k,1))-1 :next\"\n"
"Set \".=!.! :n(1)=Fix(v/16777216) :v=v-n(1)*16777216\"\n"
"Set \".=!.! :n(2)=Fix(v/65536) :v=v-n(2)*65536\"\n"
"Set \".=!.! :n(3)=Fix(v/256) :n(4)=v-n(3)*256\"\n"
"Set \".=!.! :for m=1 to 4 step 1 :if (wri < max) then\"\n"
"Set \".=!.! :u.writetext chrb(n(m)) :wri=wri+1 :end if :next\"\n");
}
fprintf(fileOutput,
"Set \".=!.! :next :i=i+1 :loop\"\n"
"Set \".=!.! :u.position=2 :u.copyto a :u.close :set u=nothing\"\n"
"Set \".=!.! :a.savetofile \"!bin!\",2 :a.close :set a=nothing\"\n"
"Set \".=!.! :s.close :set s=nothing :set fs=nothing\"\n"
"Echo !.!>\"!bin!.da\"\n"
"Set \"ret=1\"\n"
"Cscript.exe /B /E:vbs \"!bin!.da\" >Nul\n"
"For %%%%# In (\"!bin!\") Do If \"%%%%~z#\"==\"!size!\" Set \"ret=0\"\n");
if (ExpandCabinet) {
fprintf(fileOutput,
"If \"0\"==\"!ret!\" Expand.exe -r \"!bin!\" -F:* . >Nul\n"
"If ErrorLevel 1 Set \"ret=1\"\n"
"Del /A /F \"!bin!\" \"!bin!.da\" \"!bin!.tmp\" >Nul\n");
} else {
fprintf(fileOutput,
"If \"1\"==\"!ret!\" If Exist \"!bin!\" Del /A /F \"!bin!\" >Nul\n"
"Del /A /F \"!bin!.da\" \"!bin!.tmp\" >Nul\n");
}
fprintf(fileOutput, "Exit /B !ret!\n\n");
fprintf(fileOutput, ":+res:%s:\n", fileName);
last_offset = buffer.size - 1;
chrs_printed = 0;
if (HexEncode) {
for (i = 0; i <= last_offset; ++i) {
fprintf(fileOutput, "%02X", buffer.data[i]);
chrs_printed += 2;
if ((64 == chrs_printed) || (i == last_offset)) {
fprintf(fileOutput, "\n");
chrs_printed = 0;
}
}
} else {
cnt = 0;
num = 0;
for (i = 0; i <= last_offset; i++) {
num = (num * 256) + buffer.data[i];
cnt++;
if (i == last_offset) {
while (cnt < 4) { //padding
num = (num * 256);
cnt++;
}
}
if (4 == cnt) {
divisor = 85 * 85 * 85 * 85;
while (divisor) {
fprintf(fileOutput, "%c",
map_enc85[num / divisor % 85]);
divisor /= 85;
}
chrs_printed += 5;
cnt = 0;
num = 0;
}
if ((60 == chrs_printed) || (i == last_offset)) {
chrs_printed = 0;
fprintf(fileOutput, "\n");
}
}
}
fprintf(fileOutput, ":+res:%s:\n", fileName);
fclose(fileOutput);
printf("\"%s\" generated.\n", ouputFileName);
free(buffer.data);
return 0;
}
struct BUFFER file2buffer(char *fileName)
{
FILE *file;
struct BUFFER buffer;
buffer.data = NULL;
buffer.size = 0;
file = fopen(fileName, "rb");
if (NULL != file) {
/* Set position to end of file */
fseek(file, 0L, SEEK_END);
/* Set BUFFER.size to size of the file */
buffer.size = ftell(file);
/* Set position to beginning of file */
fseek(file, 0L, SEEK_SET);
/* Add 1 for allow null terminator */
buffer.data = (BYTE *) malloc(1 + buffer.size);
if (NULL != buffer.data) {
fread(buffer.data, 1, buffer.size, file);
if (ferror(file)) {
free(buffer.data);
buffer.data = NULL;
buffer.size = 0;
printf("Error: Reading the file.\n");
} else {
buffer.data[buffer.size] = '\0'; /* Prevent buffer overflow */
}
} else {
buffer.size = 0;
printf("Error: Out of memory.\n");
}
fclose(file);
}
return buffer;
}
int getCabInfo(struct BUFFER *buffer, struct CFHEADER *cfheader)
{
DWORD MINIMAL_CAB_SIZE = 62;
int buffer_have_cabinet_header;
char CABINET_HEADER[] = { 'M', 'S', 'C', 'F', '\0', '\0', '\0', '\0' };
int cabinet_header_size = (int) sizeof(CABINET_HEADER);
WORD compress_type;
WORD attribs;
WORD iFolder;
WORD i;
DWORD sl;
struct TRACKER tracker;
tracker.buffer = buffer;
tracker.offset = 0;
tracker.BufferOverflowAttempt = FALSE;
#define checkOverflowAttempt() if (tracker.BufferOverflowAttempt) { goto ret_CAB_INVALID; }
if (buffer->size < MINIMAL_CAB_SIZE) {
return IS_NOT_CAB;
}
for (i = 0; i < cabinet_header_size; ++i) {
buffer_have_cabinet_header = CABINET_HEADER[i] == buffer->data[i];
if (!buffer_have_cabinet_header) {
return IS_NOT_CAB;
}
}
/* CFHEADER.signature */
skipOffset(&tracker, 4 * sizeof(BYTE));
checkOverflowAttempt();
/* CFHEADER.reserved1 */
skipOffset(&tracker, sizeof(DWORD));
checkOverflowAttempt();
/* CFHEADER.cbCabinet */
cfheader->cbCabinet = readDWord(&tracker);
checkOverflowAttempt();
if (cfheader->cbCabinet != buffer->size) {
return CAB_INVALID;
}
/* CFHEADER.reserved2 */
skipOffset(&tracker, sizeof(DWORD));
checkOverflowAttempt();
/* CFHEADER.coffFiles */
cfheader->coffFiles = readDWord(&tracker);
checkOverflowAttempt();
/* CFHEADER.reserved3 */
skipOffset(&tracker, sizeof(DWORD));
checkOverflowAttempt();
/* CFHEADER.versionMinor */
cfheader->versionMinor = readByte(&tracker);
checkOverflowAttempt();
/* CFHEADER.versionMajor */
cfheader->versionMajor = readByte(&tracker);
checkOverflowAttempt();
/* CFHEADER.cFolders */
cfheader->cFolders = readWord(&tracker);
checkOverflowAttempt();
if (cfheader->cFolders < 1) {
return CAB_INVALID;
}
/* CFHEADER.cFiles */
cfheader->cFiles = readWord(&tracker);
checkOverflowAttempt();
if (cfheader->cFiles < 1) {
return CAB_INVALID;
}
/* CFHEADER.flags */
cfheader->flags = readWord(&tracker);
checkOverflowAttempt();
/* CFHEADER.setID */
cfheader->setID = readWord(&tracker);
checkOverflowAttempt();
/* CFHEADER.iCabinet */
cfheader->iCabinet = readWord(&tracker);
checkOverflowAttempt();
/* (cfhdrRESERVE_PRESENT | cfhdrPREV_CABINET | cfhdrNEXT_CABINET) = 7 */
if (cfheader->flags > 7) {
return CAB_INVALID;
}
cfheader->cbCFHeader = (WORD) 0;
cfheader->cbCFFolder = (BYTE) 0;
cfheader->cbCFData = (BYTE) 0;
cfheader->abReserve = NULL;
cfheader->szCabinetPrev = NULL;
cfheader->szDiskPrev = NULL;
cfheader->szCabinetNext = NULL;
cfheader->szDiskNext = NULL;
if (cfheader->flags & cfhdrRESERVE_PRESENT) {
/* CFHEADER.cbCFHeader */
cfheader->cbCFHeader = readWord(&tracker);
checkOverflowAttempt();
/* CFHEADER.cbCFFolder */
cfheader->cbCFFolder = readByte(&tracker);
checkOverflowAttempt();
/* CFHEADER.cbCFData */
cfheader->cbCFData = readByte(&tracker);
checkOverflowAttempt();
if (cfheader->cbCFHeader) {
/* Not saving abReserve offset */
/* cbCFHeader is the size of CFHEADER->abReserve */
skipOffset(&tracker, cfheader->cbCFHeader);
checkOverflowAttempt();
}
}
if (cfheader->flags & cfhdrPREV_CABINET) {
cfheader->szCabinetPrev = tracker.buffer->data + tracker.offset;
sl = bufferlen(&tracker);
checkOverflowAttempt();
skipOffset(&tracker, sl + 1);
checkOverflowAttempt();
cfheader->szDiskPrev = tracker.buffer->data + tracker.offset;
sl = bufferlen(&tracker);
checkOverflowAttempt();
skipOffset(&tracker, sl + 1);
checkOverflowAttempt();
}
if (cfheader->flags & cfhdrNEXT_CABINET) {
cfheader->szCabinetNext = tracker.buffer->data + tracker.offset;
sl = bufferlen(&tracker);
checkOverflowAttempt();
skipOffset(&tracker, sl + 1);
checkOverflowAttempt();
cfheader->szDiskNext = tracker.buffer->data + tracker.offset;
sl = bufferlen(&tracker);
checkOverflowAttempt();
skipOffset(&tracker, sl + 1);
checkOverflowAttempt();
}
for (i = 1; i <= cfheader->cFolders; ++i) {
/* CFFOLDER.coffCabStart */
skipOffset(&tracker, sizeof(DWORD));
checkOverflowAttempt();
/* CFFOLDER.cCFData */
skipOffset(&tracker, sizeof(WORD));
checkOverflowAttempt();
/* CFFOLDER.typeCompress: (1st BYTE)type */
compress_type = (WORD) readByte(&tracker) & (WORD) 0xF;
checkOverflowAttempt();
switch (compress_type) {
default:
return CAB_FILE_UNKNOW_COMPRESSION;
case COMPRESSION_NONE:
case COMPRESSION_MSZIP:
case COMPRESSION_QUANTUM:
case COMPRESSION_LZX:
break;
}
/* CFFOLDER.typeCompress: (2nd BYTE)memory */
skipOffset(&tracker, sizeof(BYTE));
checkOverflowAttempt();
/* CFFOLDER.abReserve */
skipOffset(&tracker, cfheader->cbCFFolder);
checkOverflowAttempt();
}
for (i = 1; i <= cfheader->cFiles; ++i) {
skipOffset(&tracker, sizeof(DWORD)); /* CFFILE.cbFile */
checkOverflowAttempt();
skipOffset(&tracker, sizeof(DWORD)); /* CFFILE.uoffFolderStart */
checkOverflowAttempt();
iFolder = readWord(&tracker); /* CFFILE.iFolder */
checkOverflowAttempt();
switch (iFolder) {
case ifoldCONTINUED_FROM_PREV:
case ifoldCONTINUED_TO_NEXT:
case ifoldCONTINUED_PREV_AND_NEXT:
return CAB_NEED_OTHERS_FILES_FOR_EXPAND;
}
/* CFFILE.date */
skipOffset(&tracker, sizeof(WORD));
checkOverflowAttempt();
/* CFFILE.time */
skipOffset(&tracker, sizeof(WORD));
checkOverflowAttempt();
/* CFFILE.attribs */
attribs = readWord(&tracker);
checkOverflowAttempt();
if (attribs & A_NAME_IS_UTF) {
return CAB_UTF_FILENAMES;
}
sl = bufferlen(&tracker);
checkOverflowAttempt();
if (bufferHavePathSeparator(&tracker)) {
return CAB_FILES_WITH_PATH_PREFIX;
}
/* CFFILE.szName */
skipOffset(&tracker, sl + 1);
checkOverflowAttempt();
}
return CAB_OK;
ret_CAB_INVALID:
return CAB_INVALID;
}
/* Before call this, ensure that tracker.buffer.data have a null terminator */
BOOL bufferHavePathSeparator(struct TRACKER * tracker)
{
BYTE *b = tracker->buffer->data + tracker->offset;
while (*b) {
switch (*b) {
case '\\':
case '/':
return TRUE;
}
++b;
}
return FALSE;
}
DWORD bufferlen(struct TRACKER * tracker)
{
DWORD off = tracker->offset;
DWORD length = 0;
BYTE b;
for (;;) {
b = readByte(tracker);
if (tracker->BufferOverflowAttempt) {
break;
}
if ((BYTE) '\0' == b) {
break;
}
++(length);
/* check if we not found the nul terminator at the end of buffer.data */
if (tracker->offset == (tracker->buffer->size - 1)) {
tracker->BufferOverflowAttempt = TRUE;
break;
}
};
/* Restoring offset that modify readByte */
tracker->offset = off;
return length;
}
BOOL canNotIncrement(struct TRACKER * tracker, DWORD increment)
{
tracker->BufferOverflowAttempt = FALSE;
/* overflow */
if ((tracker->offset) >= (tracker->buffer->size)) {
tracker->BufferOverflowAttempt = TRUE;
}
/* overflow */
if ((tracker->offset + increment) > (tracker->buffer->size)) {
tracker->BufferOverflowAttempt = TRUE;
}
/* overrun */
if ((tracker->offset + increment) <= (tracker->offset)) {
if (increment) {
tracker->BufferOverflowAttempt = TRUE;
}
}
return tracker->BufferOverflowAttempt;
}
BOOL skipOffset(struct TRACKER * tracker, DWORD increment)
{
if (canNotIncrement(tracker, increment)) {
return FALSE;
}
tracker->offset += increment;
return TRUE;
}
/* if BufferOverflowAttempt is set to TRUE the return value is 0 */
BYTE readByte(struct TRACKER * tracker)
{
BYTE *p;
BYTE value;
if (canNotIncrement(tracker, sizeof(BYTE))) {
return (BYTE) 0;
}
p = &(tracker->buffer->data[tracker->offset]);
value = ((BYTE) (*p));
tracker->offset += sizeof(BYTE);
return value;
}
/* if BufferOverflowAttempt is set to TRUE the return value is 0 */
WORD readWord(struct TRACKER * tracker)
{
BYTE *p;
WORD value;
if (canNotIncrement(tracker, sizeof(WORD))) {
return (WORD) 0;
}
p = &(tracker->buffer->data[tracker->offset]);
value = ((WORD) (*p++)); /* Add 1st byte */
value |= (((WORD) (*p)) << 8); /* Add 2nd byte */
tracker->offset += sizeof(WORD);
return value;
}
/* if BufferOverflowAttempt is set to TRUE the return value is 0 */
DWORD readDWord(struct TRACKER * tracker)
{
BYTE *p;
DWORD value;
if (canNotIncrement(tracker, sizeof(DWORD))) {
return (DWORD) 0;
}
p = &(tracker->buffer->data[tracker->offset]);
value = ((DWORD) (*p++)); /* Add 1st byte */
value |= (((DWORD) (*p++)) << 8); /* Add 2nd byte */
value |= (((DWORD) (*p++)) << 16); /* Add 3nd byte */
value |= (((DWORD) (*p)) << 24); /* Add 4th byte */
tracker->offset += sizeof(DWORD);
return value;
}
Re: BHX 4.0
mirrormirror wrote:I would love to modify this (and hopefully it is fine with Carlos as he said it is open source) to change the width of the output file - but I don't know C language !
Thanks for the source code, mirrormirror.
I found a hexedit to change the width of the encoded data as a single byte. Is 255 large enough?
Byte: D5E changes the line width
It's hex 3C by default (3C is 60 characters)
If you patch it to 55 then you get 85 characters
If you patch it to FF then you get 255 characters
You might find a script to patch the byte for you, if that suits what you need to do.
-
- Posts: 129
- Joined: 08 Feb 2016 20:25
Re: BHX 4.0
I think 255 would work for now - and you are talking about modifying the EXE not the source code, correct? But it would be nice to eventually modify the source so that I could pass the width as a param. I'm also wondering if there was any technical reason why the length was 60 - and if changing it might break something...
Re: BHX 4.0
mirrormirror wrote:I think 255 would work for now - and you are talking about modifying the EXE not the source code, correct
Yes, it's changing a byte in the bhx.exe file itself.
Here's a script that will patch your BHX.EXE file to any number of columns that you need,
and using no parameter will reset the bhx.exe file to the default 60 columns.
It's easier for me to do that than figure out how to add a switch in carlos's code.
%1 is the number of columns in decimal (1-255)
Code: Select all
@echo off
:: patch bhx.exe V5.6 at offset D5E for the width of the encoded text
:: That byte controls the number of columns of text from 1 to 255
:: %1 is the number_of_columns
set "bhx=bhx.exe"
for %%a in (%bhx%) do if not %%~za EQU 12288 (
echo %bhx% seems to be the wrong version - requires V5.6& pause & goto :EOF
)
:: No parameter resets the value to 60 columns
if "%~1"=="" %0 60
:: test for valid input
for /f "delims=1234567890" %%a in ("%~1") do (
echo value out of range [1-255]& pause & goto :EOF
)
if %~1 LSS 1 %0 a
if %~1 GTR 255 %0 a
set file="%temp%\patchbhx.vbs"
>%file% echo Dim StdIn, StdOut
>>%file% echo Set StdIn = WScript.StdIn
>>%file% echo Set StdOut = WScript.StdOut
>>%file% echo If WScript.Arguments.Count = 1 Then
>>%file% echo Do While Not StdIn.AtEndOfStream
>>%file% echo n = n + 1
>>%file% echo If n = 3423 Then
>>%file% echo StdOut.Write Chr("&H"+Hex(WScript.Arguments(0)))
>>%file% echo StdIn.Read(1)
>>%file% echo else
>>%file% echo StdOut.Write (StdIn.Read(1))
>>%file% echo End If
>>%file% echo Loop
>>%file% echo End If
cscript /nologo %file% %~1 <%bhx% >%bhx%.1
move /y %bhx%.1 %bhx% >nul
del %file% 2>nul
I'm also wondering if there was any technical reason why the length was 60 - and if changing it might break something...
In my small sample of tests the regenerated files were all binary duplicates, but the reason why 60 was chosen could have been for Usenet posts in newsgroups, where long lines often wrap in newsreaders.
-
- Posts: 129
- Joined: 08 Feb 2016 20:25
Re: BHX 4.0
Here's a script that will patch your BHX.EXE file to any number of columns that you need,
and using no parameter will reset the bhx.exe file to the default 60 columns.
Well this is great - I know everyone's time is valuable and the time you spent on this is appreciated - thank you. It seems to work fine for what I need - I'll test it further this week.