bin2c.c revision e64031e20c39650a7bc902a3e1aba613b9415dee
/* $Id$ */
/** @file
* bin2c - Binary 2 C Structure Converter.
*/
/*
* Copyright (C) 2006-2007 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
* you can redistribute it and/or modify it under the terms of the GNU
* General Public License (GPL) as published by the Free Software
* Foundation, in version 2 as it comes in the "COPYING" file of the
* VirtualBox OSE distribution. VirtualBox OSE is distributed in the
* hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
*/
/*******************************************************************************
* Header Files *
*******************************************************************************/
#include <ctype.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
/**
* File size.
*
* @returns file size in bytes.
* @returns 0 on failure.
* @param pFile File to size.
*/
static size_t fsize(FILE *pFile)
{
long cbFile;
off_t Pos = ftell(pFile);
if ( Pos >= 0
&& !fseek(pFile, 0, SEEK_END))
{
cbFile = ftell(pFile);
if ( cbFile >= 0
&& !fseek(pFile, 0, SEEK_SET))
return cbFile;
}
return 0;
}
static int usage(const char *argv0)
{
fprintf(stderr,
"Syntax: %s [options] <arrayname> <binaryfile> <outname>\n"
" -min <n> check if <binaryfile> is not smaller than <n>KB\n"
" -max <n> check if <binaryfile> is not bigger than <n>KB\n"
" -mask <n> check if size of binaryfile is <n>-aligned\n"
" -width <n> number of bytes per line (default: 16)\n"
" -break <n> break every <n> lines (default: -1)\n"
" -ascii show ASCII representation of binary as comment\n",
argv0);
return 1;
}
int main(int argc, char *argv[])
{
FILE *pFileIn;
FILE *pFileOut;
int iArg;
size_t cbMin = 0;
size_t cbMax = ~0U;
size_t uMask = 0;
int fAscii = 0;
int fExport = 0;
long iBreakEvery = -1;
unsigned char abLine[32];
size_t cbLine = 16;
size_t off;
size_t cbRead;
size_t cbBin;
int rc = 1; /* assume the worst... */
if (argc < 2)
return usage(argv[0]);
for (iArg = 1; iArg < argc; iArg++)
{
if (!strcmp(argv[iArg], "-min"))
{
if (++iArg >= argc)
return usage(argv[0]);
cbMin = 1024 * strtoul(argv[iArg], NULL, 0);
}
else if (!strcmp(argv[iArg], "-max"))
{
if (++iArg >= argc)
return usage(argv[0]);
cbMax = 1024 * strtoul(argv[iArg], NULL, 0);
}
else if (!strcmp(argv[iArg], "-mask"))
{
if (++iArg >= argc)
return usage(argv[0]);
uMask = strtoul(argv[iArg], NULL, 0);
}
else if (!strcmp(argv[iArg], "-ascii"))
{
fAscii = 1;
}
else if (!strcmp(argv[iArg], "-export"))
{
fExport = 1;
}
else if (!strcmp(argv[iArg], "-width"))
{
if (++iArg >= argc)
return usage(argv[0]);
cbLine = strtoul(argv[iArg], NULL, 0);
if (cbLine == 0 || cbLine > sizeof(abLine))
{
fprintf(stderr, "%s: '%s' is too wide, max %u\n",
argv[0], argv[iArg], (unsigned)sizeof(abLine));
return 1;
}
}
else if (!strcmp(argv[iArg], "-break"))
{
if (++iArg >= argc)
return usage(argv[0]);
iBreakEvery = strtol(argv[iArg], NULL, 0);
if (iBreakEvery <= 0 && iBreakEvery != -1)
{
fprintf(stderr, "%s: -break value '%s' is not >= 1 or -1.\n",
argv[0], argv[iArg]);
return 1;
}
}
else if (iArg == argc - 3)
break;
else
{
fprintf(stderr, "%s: syntax error: Unknown argument '%s'\n",
argv[0], argv[iArg]);
return usage(argv[0]);
}
}
pFileIn = fopen(argv[iArg+1], "rb");
if (!pFileIn)
{
fprintf(stderr, "Error: failed to open input file '%s'!\n", argv[iArg+1]);
return 1;
}
pFileOut = fopen(argv[iArg+2], "wb");
if (!pFileOut)
{
fprintf(stderr, "Error: failed to open output file '%s'!\n", argv[iArg+2]);
fclose(pFileIn);
return 1;
}
cbBin = fsize(pFileIn);
fprintf(pFileOut,
"/*\n"
" * This file was automatically generated\n"
" * from %s\n"
" * by %s.\n"
" */\n"
"\n"
"#include <iprt/cdefs.h>\n"
"\n"
"%sconst unsigned char%s g_ab%s[] =\n"
"{\n",
argv[iArg+1], argv[0], fExport ? "DECLEXPORT(" : "", fExport ? ")" : "", argv[iArg]);
/* check size restrictions */
if (uMask && (cbBin & uMask))
fprintf(stderr, "%s: size=%ld - Not aligned!\n", argv[0], (long)cbBin);
else if (cbBin < cbMin || cbBin > cbMax)
fprintf(stderr, "%s: size=%ld - Not %ld-%ldb in size!\n",
argv[0], (long)cbBin, (long)cbMin, (long)cbMax);
else
{
/* the binary data */
off = 0;
while ((cbRead = fread(&abLine[0], 1, cbLine, pFileIn)) > 0)
{
size_t j;
if ( iBreakEvery > 0
&& off
&& (off / cbLine) % iBreakEvery == 0)
fprintf(pFileOut, "\n");
fprintf(pFileOut, " ");
for (j = 0; j < cbRead; j++)
fprintf(pFileOut, " 0x%02x,", abLine[j]);
for (; j < cbLine; j++)
fprintf(pFileOut, " ");
if (fAscii)
{
fprintf(pFileOut, " /* 0x%08lx: ", (long)off);
for (j = 0; j < cbRead; j++)
/* be careful with '/' prefixed/followed by a '*'! */
fprintf(pFileOut, "%c",
isprint(abLine[j]) && abLine[j] != '/' ? abLine[j] : '.');
for (; j < cbLine; j++)
fprintf(pFileOut, " ");
fprintf(pFileOut, " */");
}
fprintf(pFileOut, "\n");
off += cbRead;
}
/* check for errors */
if (ferror(pFileIn) && !feof(pFileIn))
fprintf(stderr, "%s: read error\n", argv[0]);
else if (off != cbBin)
fprintf(stderr, "%s: read error off=%ld cbBin=%ld\n", argv[0], (long)off, (long)cbBin);
else
{
/* no errors, finish the structure. */
fprintf(pFileOut,
"};\n"
"\n"
"%sconst unsigned%s g_cb%s = sizeof(g_ab%s);\n"
"/* end of file */\n",
fExport ? "DECLEXPORT(" : "", fExport ? ")" : "", argv[iArg], argv[iArg]);
/* flush output and check for error. */
fflush(pFileOut);
if (ferror(pFileOut))
fprintf(stderr, "%s: write error\n", argv[0]);
else
rc = 0; /* success! */
}
}
/* cleanup, delete the output file on failure. */
fclose(pFileOut);
fclose(pFileIn);
if (rc)
remove(argv[iArg+2]);
return rc;
}