Files
GrowController/Tools/MakeByteArray.pl

269 lines
6.1 KiB
Perl

# MakeByteArray
#
#
use strict;
use warnings;
use Cwd qw(cwd);
my $maxCols = 16;
my $maxLines = 0;
my $ESP = 0;
my $DIR = 0;
my $ROOT = 0;
my $UINT8 = 0;
my $file = "";
my $ctrlC = 0; # User induced termination
my $lineT = 0; # Linecount induced termination
$SIG{INT} = \&CtrlCHandler;
$SIG{QUIT} = \&CtrlCHandler;
my %DirInfo; # Name and FileSize
my $prg = $0;
$prg =~ s/^.*[\\\/](.*)/$1/;
$prg =~ s/(.*)\..*/$1/;
my $VERSION = 1.0;
# Extension in this list must be lower case.
my %FileType = (
"htm" => "text/html",
"html" => "text/html",
"gif" => "image/gif",
"svg" => "image/svg+xml",
"css" => "text/css",
"ico" => "image/x-icon",
"png" => "image/png",
"jpg" => "image/jpeg",
"js" => "text/javascript",
);
if (!@ARGV)
{
print <<EOM;
$prg [file|<wildcard> [...]] [-n=##] [-l=##] [-ESP] [-DIR] [-o=outfile]
version $VERSION
Dumps out the contents of the [file(s)] as a c array.
If the file is binary, it emits a hex char-array using
the -n and -l settings.
If the file is text, it emits as an ascii char-array
where each source line is one ascii quoted line.
-ESP adds the PROGMEM attribute to the byte array data.
-DIR adds a 'directory' at the end of the output, providing
a reference to each input file. Most useful for a set
of files.
-ROOT prefixes each entry in the 'directory' with '/',
so "index.htm" becomes
-o=outfile Writes the output to outfile.
-u overrides the default 'char' array to be 'uint8_t'
NOTE that the filename and type info remains 'char'.
-n=## sets the byte count for each line, defaults 32.
-l=## sets a termination after ## lines have been printed.
Example: MakeByteArray -ESP srcpath\\*.* -o=dstpath\\Web_Resources.h
EOM
exit;
}
my @files;
my $outfile = "";
#printf("ARGS: '%s'\n", join("|", @ARGV));
foreach (@ARGV)
{
if (/-n=(\d+)/)
{ $maxCols = $1; }
elsif (/-l=(\d+)/)
{ $maxLines = $1; }
elsif (/-o=(.*)/)
{ $outfile = $1; }
elsif (/-ESP/)
{ $ESP = 1; }
elsif (/-ROOT/)
{ $ROOT = 1; }
elsif (/-DIR/)
{ $DIR = 1; }
elsif (/-u/)
{ $UINT8 = 1; }
elsif (-e $_ )
{ push @files, $_; }
elsif (/[\*\?]/)
{
my @gFiles = glob($_);
foreach (@gFiles)
{
push @files, $_ if (-e $_);
}
}
else
{ print "unrecognized command.\n"; exit; }
}
if (!@files)
{
print "No files to process.\n";
exit;
}
my $oldHandle;
if ($outfile ne "") {
#printf("Open for write '%s'\n", $outfile);
open(FO, ">$outfile") || die("Can't write to $outfile");
$oldHandle = select FO;
} else {
printf("No outfile, emitting to console.\n");
}
printf("//\n");
printf("// Command: %s %s\n", $prg, join(" ", @ARGV));
printf("// version: %2.1f\n", $VERSION);
printf("// From cwd: %s\n", cwd);
printf("// Generated: %s\n", scalar localtime());
printf("// NOTE: Run script in command shell, not PowerShell\n");
printf("//\n");
if ($ESP) {
print <<EOM;
// PROGMEM is not recognized by Win32 tools...
#ifdef WIN32
#define PROGMEM
#endif
EOM
}
my @summary;
foreach my $file (@files) {
push @summary, Process($file);
last if ($ctrlC);
}
print "\n// Prototypes:\n// " . join("\n// ", @summary) . "\n";
if ($DIR) {
my $type = "char "; #($UINT8) ? "uint8_t" : "char ";
print <<EOM;
// Directory of Files
//
// This typedef is used to iterate through the directory listing, until
// an empty "" Filename is reached.
//
typedef struct {
const char * Filename;
const $type * Filedata;
const char * Filetype;
uint16_t Filesize;
} DirEntry;
EOM
printf("const DirEntry Directory[] %s= {\n", ($ESP) ? "PROGMEM " : "");
foreach my $file (sort keys %DirInfo) {
#printf(STDERR "file %s, title %s, size %d\n", $file, $DirInfo{$file}{'reference'}, $DirInfo{$file}{'size'});
my $title = $DirInfo{$file}{'reference'};
my $fn = sprintf("\"%s%s\"", $ROOT ? "/" : "", $file);
my $ext = "";
$ext = $1 if ($file =~ /.*\.(.*)/);
my $ftype = sprintf("\"%s\"", $FileType{$ext});
#printf(STDERR "ext: '%s' => '%s'\n", $ext, $FileType{lc($ext)});
printf("\t{ %-20s, %-20s, %24s, %6d },\n", $fn, $title, $ftype, $DirInfo{$file}{'size'});
}
printf("\t{ %-20s, %-20s, %24s, %6d }\n", "NULL", "NULL", "NULL", 0);
printf("};\n\n");
}
if ($outfile) {
close FO;
select($oldHandle);
}
print "\nTerminated by operator\n" if ($ctrlC == 1);
exit;
# ####################################
sub Process {
my $file = shift;
my $title = $file;
my $isText = 0;
my $prototype;
$title =~ s/\./_/g;
$isText = 1 if (-T $file);
open(FH, "<$file") || die("Can't read $file.\n");
binmode FH if ($isText);
my $cols = 0;
my $c;
my $ascii = "";
my $address = 0;
my $lineCount = 0;
printf("\n");
printf("// File: %s\n", $file);
printf("//\n");
$prototype = sprintf("const %s %s[]%s", ($UINT8) ? "uint8_t" : "char", $title, ($ESP) ? " PROGMEM" : "");
printf("%s = {\n", $prototype);
my $size = 0;
if ($isText) {
while (<FH>) {
my $line = $_;
chomp $line;
$line =~ s/\t/ /g;
$line =~ s/\\"/"/g;
$line =~ s/\r//g;
$line =~ s/"/\\"/g;
printf("\t\"%s\\n\"\n", $line);
$size += length($line) + 1; # +1 for the \n line termination.
}
} else {
printf("\t");
while (sysread(FH, $c, 1) && !$ctrlC && !$lineT) {
my $b = ord($c);
printf("0x%02X,", $b);
if ($b >= 0x20 && $b <= 0x7F)
{ $ascii .= chr($b); }
else
{ $ascii .= "."; }
++$cols;
++$address;
$cols %= $maxCols;
if ($cols == 0) {
#print " // $ascii";
print "\n";
$ascii = "";
$lineCount++;
$lineT = 1 if ($maxLines && $lineCount >= $maxLines);
if (!$lineT) {
printf("\t");
}
}
$size += 1;
}
if ($ascii ne "") {
print " " x ($maxCols - $cols);
}
printf("\n");
}
printf("}; // %s, %d bytes\n", $title, $size);
close FH;
$DirInfo{$file}{'reference'} = $title;
$DirInfo{$file}{'size'} = $size;
return $prototype;
}
# If the user presses Control-C, signal it.
#
sub CtrlCHandler {
$ctrlC = 1;
}