Stairs/gulp-cppstringify.js

168 lines
3.6 KiB
JavaScript
Raw Permalink Normal View History

/*
* Stairs
* Copyright 2017 (c) Mark van Renswoude
*
* https://git.x2software.net/pub/Stairs
*/
'use strict';
// Borrowed heavily from gulp-concat:
// https://github.com/contra/gulp-concat/
//
// It's very much hardcoded for the ESP8266 Arduino at the moment,
// but feel free to hack away at it if you need it for other purposes!
var through = require('through2');
var path = require('path');
var File = require('vinyl');
var _ = require('lodash');
var Readable = require('stream').Readable;
function escapeContent(content, lineLength)
{
var lineRegexp = new RegExp('(.{1,' + (lineLength - 1) + '}[^\\\\])', 'g');
return content
.replace(/\\/g, '\\\\')
.replace(/"/g, '\\"')
.replace(/\r?\n/g, '\\r\\n')
.replace(lineRegexp, ' "$1"\r\n')
.replace(/\r\n$/, '');
};
function escapeContentAsByteArray(content, lineLength)
{
var bytesPerLine = Math.floor(lineLength / 5);
var lineRegexp = new RegExp('((?:0x..,){1,' + bytesPerLine + '})', 'g');
return content
.replace(/(.{2})/g, '0x$1,')
.replace(lineRegexp, ' $1\r\n')
.replace(/,\r\n$/, '');
};
function encodeFile(file, opts)
{
var variableName;
if (opts.map.hasOwnProperty(file.relative))
variableName = opts.map[file.relative];
else
variableName = file.relative.replace(/[^a-zA-Z0-9_]/g, '_');
if (variableName === null)
return '';
variableName = opts.variablePrefix + variableName;
var escapedContent;
var output;
if (opts.byteArray)
{
escapedContent = escapeContentAsByteArray(file.contents.toString('hex'), opts.lineLength);
output = "const uint8_t " + variableName + "[] PROGMEM = {\r\n" + escapedContent + "};\r\n\r\n";
}
else
{
escapedContent = escapeContent(file.contents.toString('utf-8'), opts.lineLength);
output = "const char " + variableName + "[] PROGMEM = \r\n" + escapedContent + ";\r\n\r\n";
}
return output;
}
module.exports = function(file, opts)
{
if (!file)
throw new Error('gulp-cppstringify: Missing file option');
opts = _.extend({
map: [],
headerDefineName: '__Embedded',
variablePrefix: 'Embedded',
lineLength: 100,
byteArray: false
}, opts || {});
var fileName;
var latestFile = false;
var latestMod = 0;
var output = null;
if (typeof file === 'string')
fileName = file;
else if (typeof file.path === 'string')
fileName = path.basename(file.path);
else
throw new Error('gulp-cppstringify: Missing path in file options');
function bufferContents(file, enc, cb)
{
if (file.isNull())
{
cb();
return;
}
if (file.isStream())
{
this.emit('error', new Error('gulp-cppstringify: Streaming not supported'));
cb();
return;
}
if (!latestMod || file.stat && file.stat.mtime > latestMod)
{
latestFile = file;
latestMod = file.stat && file.stat.mtime;
}
if (output == null)
{
output = new Readable();
output._read = function noop() {};
output.push("#ifndef " + opts.headerDefineName + "\r\n");
output.push("#define " + opts.headerDefineName + "\r\n\r\n");
output.push("#include <pgmspace.h>\r\n\r\n");
}
output.push(encodeFile(file, opts));
cb();
}
function endStream(cb)
{
if (!latestFile)
{
cb();
return;
}
var headerFile;
if (typeof file === 'string')
{
headerFile = latestFile.clone({contents: false});
headerFile.path = path.join(latestFile.base, file);
}
else
headerFile = new File(file);
output.push("#endif\r\n");
output.push(null);
headerFile.contents = output;
this.push(headerFile);
cb();
}
return through.obj(bufferContents, endStream);
};