main funcions fixes

This commit is contained in:
2025-09-29 22:06:11 +09:00
parent 40e016e128
commit c8c3274527
7995 changed files with 1517998 additions and 1057 deletions

View File

@@ -0,0 +1,17 @@
export default interface BitmapInfo {
width: number;
height: number;
planes: number;
bitCount: number;
compression: number;
sizeImage: number;
xPelsPerMeter: number;
yPelsPerMeter: number;
colorUsed: number;
colorImportant: number;
colors: Array<{
r: number;
g: number;
b: number;
}>;
}

View File

@@ -0,0 +1 @@
export {};

View File

@@ -0,0 +1,21 @@
import IconItem from './IconItem.js';
import RawIconItem from './RawIconItem.js';
/**
* All fields except for 'data' is optional.
* Missing fields are replaced by 'data' values when generating binary.
*/
export interface IconFileItem {
width?: number;
height?: number;
colors?: number;
planes?: number;
bitCount?: number;
data: IconItem | RawIconItem;
}
export default class IconFile {
/** Containing icons */
icons: IconFileItem[];
constructor();
static from(bin: ArrayBuffer | ArrayBufferView): IconFile;
generate(): ArrayBuffer;
}

View File

@@ -0,0 +1,141 @@
import IconItem from './IconItem.js';
import RawIconItem from './RawIconItem.js';
import { readUint8WithLastOffset, readUint16WithLastOffset, readUint32WithLastOffset, copyBuffer, createDataView, } from '../util/functions.js';
function generateEntryBinary(icons) {
var count = icons.length;
/* istanbul ignore if */
if (count > 65535) {
count = 65535;
}
var tmpIcons = icons.map(function (item) {
if (item.data.isIcon()) {
return {
item: item,
bin: item.data.generate(),
offset: 0,
};
}
else {
return {
item: item,
bin: item.data.bin,
offset: 0,
};
}
});
var size = tmpIcons.reduce(function (p, icon) {
icon.offset = p;
return p + icon.bin.byteLength;
}, 6 + 16 * count);
var bin = new ArrayBuffer(size);
var view = new DataView(bin);
view.setUint16(0, 0, true); // reserved
view.setUint16(2, 1, true); // icon type
view.setUint16(4, count, true);
var offset = 6;
tmpIcons.forEach(function (icon) {
var item = icon.item;
var width;
var height;
var colors;
var planes;
var bitCount;
if (item.data.isIcon()) {
var bi = item.data.bitmapInfo;
width =
typeof item.width !== 'undefined'
? item.width
: Math.abs(bi.width);
height =
typeof item.height !== 'undefined'
? item.height
: Math.abs(bi.height / 2);
colors =
typeof item.colors !== 'undefined'
? item.colors
: bi.colorUsed || bi.colors.length;
planes =
typeof item.planes !== 'undefined' ? item.planes : bi.planes;
bitCount =
typeof item.bitCount !== 'undefined'
? item.bitCount
: bi.bitCount;
}
else {
width =
typeof item.width !== 'undefined'
? item.width
: Math.abs(item.data.width);
height =
typeof item.height !== 'undefined'
? item.height
: Math.abs(item.data.height);
colors = typeof item.colors !== 'undefined' ? item.colors : 0;
planes = typeof item.planes !== 'undefined' ? item.planes : 1;
bitCount =
typeof item.bitCount !== 'undefined'
? item.bitCount
: item.data.bitCount;
}
var dataSize = icon.bin.byteLength;
view.setUint8(offset, width >= 256 ? 0 : width);
view.setUint8(offset + 1, height >= 256 ? 0 : height);
view.setUint8(offset + 2, colors >= 256 ? 0 : colors);
view.setUint8(offset + 3, 0);
view.setUint16(offset + 4, planes, true);
view.setUint16(offset + 6, bitCount, true);
view.setUint32(offset + 8, dataSize, true);
view.setUint32(offset + 12, icon.offset, true);
offset += 16;
copyBuffer(bin, icon.offset, icon.bin, 0, dataSize);
});
return bin;
}
var IconFile = /** @class */ (function () {
function IconFile(bin) {
if (!bin) {
this.icons = [];
return;
}
var view = createDataView(bin);
var totalSize = view.byteLength;
var icons = [];
/* istanbul ignore else */
if (view.getUint16(2, true) === 1) {
var count = view.getUint16(4, true);
var offset = 6;
for (var i = 0; i < count; ++i) {
var dataSize = readUint32WithLastOffset(view, offset + 8, totalSize);
var dataOffset = readUint32WithLastOffset(view, offset + 12, totalSize);
var width = readUint8WithLastOffset(view, offset, totalSize);
var height = readUint8WithLastOffset(view, offset + 1, totalSize);
var bitCount = readUint8WithLastOffset(view, offset + 6, totalSize);
var data = void 0;
if (view.getUint32(dataOffset, true) === 0x28) {
data = IconItem.from(width, height, bin, dataOffset, dataSize);
}
else {
data = RawIconItem.from(bin, width || 256, height || 256, bitCount, dataOffset, dataSize);
}
icons.push({
width: width,
height: height,
colors: readUint8WithLastOffset(view, offset + 2, totalSize),
planes: readUint16WithLastOffset(view, offset + 4, totalSize),
bitCount: bitCount,
data: data,
});
offset += 16;
}
}
this.icons = icons;
}
IconFile.from = function (bin) {
return new IconFile(bin);
};
IconFile.prototype.generate = function () {
return generateEntryBinary(this.icons);
};
return IconFile;
}());
export default IconFile;

View File

@@ -0,0 +1,58 @@
import BitmapInfo from './BitmapInfo.js';
export default class IconItem {
/**
* Bitmap header data (`BITMAPINFOHEADER`)
*/
readonly bitmapInfo: BitmapInfo;
/**
* Horizontal size of the icon in pixel (overrides `bitmapInfo.width`).
* If `null` is specified, `bitmapInfo.width` will be used.
*/
width: number | null;
/**
* Vertical size of the icon in pixel (overrides `bitmapInfo.height`).
* If `null` is specified, `bitmapInfo.height` will be used.
*/
height: number | null;
/**
* Bitmap pixel data used for mask
* (the data will be appended immediately after `pixels` when generating icon binary)
*/
masks: ArrayBuffer;
/**
* Bitmap pixel data
*/
private _pixels;
private constructor();
/**
* Bitmap pixel data.
* @note
* On set, if `bitmapInfo.sizeImage` is non-zero, `bitmapInfo.sizeImage` will be updated.
*/
get pixels(): ArrayBuffer;
/**
* Bitmap pixel data.
* @note
* On set, if `bitmapInfo.sizeImage` is non-zero, `bitmapInfo.sizeImage` will be updated.
*/
set pixels(newValue: ArrayBuffer);
/**
* Generates `IconItem` instance from bitmap data binary.
* @param bin binary data containing the bitmap data
* @param byteOffset byte offset of `bin` referring the bitmap data
* @param byteLength available byte length for `bin` (from the offset `byteOffset`)
*/
static from(bin: ArrayBuffer | ArrayBufferView, byteOffset?: number, byteLength?: number): IconItem;
/**
* Generates `IconItem` instance from bitmap data binary width actual icon size (width and height).
* @param width icon width
* @param height icon height
* @param bin binary data containing the bitmap data
* @param byteOffset byte offset of `bin` referring the bitmap data
* @param byteLength available byte length for `bin` (from the offset `byteOffset`)
*/
static from(width: number, height: number, bin: ArrayBuffer | ArrayBufferView, byteOffset?: number, byteLength?: number): IconItem;
isIcon(): this is IconItem;
isRaw(): false;
generate(): ArrayBuffer;
}

View File

@@ -0,0 +1,164 @@
import { allocatePartialBinary, copyBuffer, createDataView, readInt32WithLastOffset, readUint8WithLastOffset, readUint16WithLastOffset, readUint32WithLastOffset, roundUp, } from '../util/functions.js';
function calcMaskSize(width, height) {
// round up to 4 bytes (32 bit)
// (mask pixels is 1-bit bitmap)
var actualWidthBytes = roundUp(Math.abs(width), 32) / 8;
return actualWidthBytes * Math.abs(height);
}
var IconItem = /** @class */ (function () {
function IconItem(width, height, bin, byteOffset, byteLength) {
var view = createDataView(bin, byteOffset, byteLength);
var totalSize = view.byteLength;
var headerSize = view.getUint32(0, true);
if (headerSize > totalSize) {
headerSize = totalSize;
}
var sizeImage = readUint32WithLastOffset(view, 20, headerSize);
var bi = {
width: readInt32WithLastOffset(view, 4, headerSize),
height: readInt32WithLastOffset(view, 8, headerSize),
planes: readUint16WithLastOffset(view, 12, headerSize),
bitCount: readUint16WithLastOffset(view, 14, headerSize),
compression: readUint32WithLastOffset(view, 16, headerSize),
sizeImage: sizeImage,
xPelsPerMeter: readInt32WithLastOffset(view, 24, headerSize),
yPelsPerMeter: readInt32WithLastOffset(view, 28, headerSize),
colorUsed: readUint32WithLastOffset(view, 32, headerSize),
colorImportant: readUint32WithLastOffset(view, 36, headerSize),
colors: [],
};
var offset = 40;
var colors = bi.colorUsed;
if (!colors) {
switch (bi.bitCount) {
case 1:
colors = 2;
break;
case 4:
colors = 16;
break;
case 8:
colors = 256;
break;
}
}
for (var i = 0; i < colors; ++i) {
bi.colors.push({
b: readUint8WithLastOffset(view, offset, totalSize),
g: readUint8WithLastOffset(view, offset + 1, totalSize),
r: readUint8WithLastOffset(view, offset + 2, totalSize),
});
offset += 4;
}
this.width = width;
this.height = height;
this.bitmapInfo = bi;
// round up to 4 bytes (32 bit)
var widthBytes = roundUp(bi.bitCount * Math.abs(bi.width), 32) / 8;
var absActualHeight = Math.abs(bi.height) / 2;
// sizeImage may be weird if compression is 0 (BI_RGB), so
// we calculate actual bitmap size from width and height
var size = bi.compression !== 0 && sizeImage !== 0
? sizeImage
: widthBytes * absActualHeight;
if (size + offset > totalSize) {
throw new Error("Unexpected bitmap data in icon: bitmap size " + size + " is larger than " + totalSize + " - " + offset);
}
this._pixels = allocatePartialBinary(view, offset, size);
offset += size;
var maskSize = calcMaskSize(bi.width, absActualHeight);
if (maskSize + offset <= totalSize) {
this.masks = allocatePartialBinary(view, offset, maskSize);
}
else {
// create a zero buffer (no mask is not allowed)
this.masks = new ArrayBuffer(maskSize);
}
}
Object.defineProperty(IconItem.prototype, "pixels", {
/**
* Bitmap pixel data.
* @note
* On set, if `bitmapInfo.sizeImage` is non-zero, `bitmapInfo.sizeImage` will be updated.
*/
get: function () {
return this._pixels;
},
/**
* Bitmap pixel data.
* @note
* On set, if `bitmapInfo.sizeImage` is non-zero, `bitmapInfo.sizeImage` will be updated.
*/
set: function (newValue) {
this._pixels = newValue;
if (this.bitmapInfo.sizeImage !== 0) {
this.bitmapInfo.sizeImage = newValue.byteLength;
}
},
enumerable: false,
configurable: true
});
IconItem.from = function (arg1, arg2, arg3, byteOffset, byteLength) {
var width;
var height;
var bin;
if (typeof arg3 === 'object') {
// second overload
width = arg1;
height = arg2;
bin = arg3;
}
else {
// first overload
width = null;
height = null;
bin = arg1;
byteOffset = arg2;
byteLength = arg3;
}
return new IconItem(width, height, bin, byteOffset, byteLength);
};
IconItem.prototype.isIcon = function () {
return true;
};
IconItem.prototype.isRaw = function () {
return false;
};
IconItem.prototype.generate = function () {
var bi = this.bitmapInfo;
var absWidth = Math.abs(bi.width);
// round up to 4 bytes (32 bit)
var absWidthBytes = roundUp(bi.bitCount * absWidth, 32) / 8;
var absActualHeight = Math.abs(bi.height) / 2;
var actualSizeImage = absWidthBytes * absActualHeight;
var sizeMask = calcMaskSize(bi.width, absActualHeight);
var colorCount = bi.colors.length;
var totalSize = 40 + 4 * colorCount + actualSizeImage + sizeMask;
var bin = new ArrayBuffer(totalSize);
var view = new DataView(bin);
view.setUint32(0, 40, true);
view.setInt32(4, bi.width, true);
view.setInt32(8, bi.height, true);
view.setUint16(12, bi.planes, true);
view.setUint16(14, bi.bitCount, true);
view.setUint32(16, bi.compression, true);
// image size
view.setUint32(20, bi.sizeImage, true);
view.setInt32(24, bi.xPelsPerMeter, true);
view.setInt32(28, bi.yPelsPerMeter, true);
view.setUint32(32, bi.colorUsed, true);
view.setUint32(36, bi.colorImportant > colorCount ? colorCount : bi.colorImportant, true);
var offset = 40;
bi.colors.forEach(function (c) {
view.setUint8(offset, c.b);
view.setUint8(offset + 1, c.g);
view.setUint8(offset + 2, c.r);
offset += 4;
});
copyBuffer(bin, offset, this.pixels, 0, actualSizeImage);
copyBuffer(bin, offset + actualSizeImage, this.masks, 0, sizeMask);
return bin;
};
return IconItem;
}());
export default IconItem;

View File

@@ -0,0 +1,13 @@
/**
* Represents the raw-graphic icon item, such as PNG data.
*/
export default class RawIconItem {
width: number;
height: number;
bitCount: number;
bin: ArrayBuffer;
constructor(bin: ArrayBuffer | ArrayBufferView, width: number, height: number, bitCount: number, byteOffset?: number, byteLength?: number);
static from(bin: ArrayBuffer | ArrayBufferView, width: number, height: number, bitCount: number, byteOffset?: number, byteLength?: number): RawIconItem;
isIcon(): false;
isRaw(): this is RawIconItem;
}

View File

@@ -0,0 +1,30 @@
import { allocatePartialBinary } from '../util/functions.js';
/**
* Represents the raw-graphic icon item, such as PNG data.
*/
var RawIconItem = /** @class */ (function () {
function RawIconItem(bin, width, height, bitCount, byteOffset, byteLength) {
this.width = width;
this.height = height;
this.bitCount = bitCount;
if (typeof byteOffset !== 'number') {
byteOffset = 0;
byteLength = bin.byteLength;
}
else if (typeof byteLength !== 'number') {
byteLength = bin.byteLength - byteOffset;
}
this.bin = allocatePartialBinary(bin, byteOffset, byteLength);
}
RawIconItem.from = function (bin, width, height, bitCount, byteOffset, byteLength) {
return new RawIconItem(bin, width, height, bitCount, byteOffset, byteLength);
};
RawIconItem.prototype.isIcon = function () {
return false;
};
RawIconItem.prototype.isRaw = function () {
return true;
};
return RawIconItem;
}());
export default RawIconItem;

View File

@@ -0,0 +1,5 @@
import BitmapInfo from './BitmapInfo.js';
import IconFile, { IconFileItem } from './IconFile.js';
import IconItem from './IconItem.js';
import RawIconItem from './RawIconItem.js';
export { BitmapInfo, IconFile, IconFileItem, IconItem, RawIconItem };

View File

@@ -0,0 +1,4 @@
import IconFile from './IconFile.js';
import IconItem from './IconItem.js';
import RawIconItem from './RawIconItem.js';
export { IconFile, IconItem, RawIconItem };

View File

@@ -0,0 +1,6 @@
import { NtExecutable, NtExecutableResource, Format } from 'pe-library';
import version from './version.js';
import * as Data from './data/index.js';
import * as Resource from './resource/index.js';
import { generateExecutableWithSign, SignerObject, DigestAlgorithmType, EncryptionAlgorithmType } from './sign/index.js';
export { NtExecutable, NtExecutableResource, version, Data, Format, Resource, generateExecutableWithSign, SignerObject, DigestAlgorithmType, EncryptionAlgorithmType, };

View File

@@ -0,0 +1,6 @@
import { NtExecutable, NtExecutableResource, Format } from 'pe-library';
import version from './version.js';
import * as Data from './data/index.js';
import * as Resource from './resource/index.js';
import { generateExecutableWithSign, } from './sign/index.js';
export { NtExecutable, NtExecutableResource, version, Data, Format, Resource, generateExecutableWithSign, };

View File

@@ -0,0 +1,45 @@
import { Type } from 'pe-library';
import IconItem from '../data/IconItem.js';
import RawIconItem from '../data/RawIconItem.js';
export interface IconGroupItem {
width: number;
height: number;
colors: number;
planes: number;
bitCount: number;
dataSize: number;
iconID: number;
}
/**
* A class that treats icon-group resource data (`RT_ICON_GROUP`).
* Note that this class does not treat `RT_ICON` data.
*
* - To pick all icons, use `IconGroupEntry.fromEntries`
* and `IconGroupEntry.prototype.getIconItemsFromEntries`.
* - The easiest way to add/replace icons is using `IconGroupEntry.replaceIconsForResource`,
* which treats both `RT_ICON_GROUP` and `RT_ICON` entries.
*/
export default class IconGroupEntry {
id: string | number;
lang: string | number;
readonly icons: IconGroupItem[];
private constructor();
static fromEntries(entries: readonly Type.ResourceEntry[]): IconGroupEntry[];
generateEntry(): Type.ResourceEntry;
/**
* Return an array of `IconItem` / `RawIconItem`, which are in the group of this `IconGroupEntry` instance,
* from specified resource entries.
*/
getIconItemsFromEntries(entries: readonly Type.ResourceEntry[]): Array<IconItem | RawIconItem>;
/**
* Add or replace icon resource entries with specified icon data.
* The IDs of individual icon resources (`RT_ICON`) are calculated automatically.
* @param destEntries base (destination) resource entries.
* @param iconGroupID the icon ID for the new resource data.
* If the icon-group resource of the ID and 'lang' value already exists,
* the resource data is replaced; otherwise the resource data is appended.
* @param lang the language for specified icons (0 for neutral, 0x409 for en-US)
* @param icons the icons to replace
*/
static replaceIconsForResource(destEntries: Type.ResourceEntry[], iconGroupID: string | number, lang: string | number, icons: Array<IconItem | RawIconItem>): void;
}

View File

@@ -0,0 +1,292 @@
import IconItem from '../data/IconItem.js';
import RawIconItem from '../data/RawIconItem.js';
import { readUint8WithLastOffset, readUint16WithLastOffset, readUint32WithLastOffset, } from '../util/functions.js';
function generateEntryBinary(icons) {
var count = icons.length;
if (count > 65535) {
count = 65535;
}
var size = 6 + 14 * icons.length;
var bin = new ArrayBuffer(size);
var view = new DataView(bin);
view.setUint16(0, 0, true); // reserved
view.setUint16(2, 1, true); // icon type
view.setUint16(4, count, true);
var offset = 6;
icons.forEach(function (icon) {
view.setUint8(offset, icon.width >= 256 ? 0 : icon.width);
view.setUint8(offset + 1, icon.height >= 256 ? 0 : icon.height);
view.setUint8(offset + 2, icon.colors >= 256 ? 0 : icon.colors);
view.setUint8(offset + 3, 0);
view.setUint16(offset + 4, icon.planes, true);
view.setUint16(offset + 6, icon.bitCount, true);
view.setUint32(offset + 8, icon.dataSize, true);
view.setUint16(offset + 12, icon.iconID, true);
offset += 14;
});
return bin;
}
function findUnusedIconID(entries, lang, isCursor) {
var type = isCursor ? 1 : 3;
// (ignore string id)
var filteredIDs = entries
.filter(function (e) { return e.type === type && e.lang === lang && typeof e.id === 'number'; })
.map(function (e) { return e.id; })
.sort(function (a, b) { return a - b; });
var idCurrent = 1;
for (var _i = 0, filteredIDs_1 = filteredIDs; _i < filteredIDs_1.length; _i++) {
var id = filteredIDs_1[_i];
if (idCurrent < id) {
return {
id: idCurrent,
last: false,
};
}
else if (idCurrent === id) {
++idCurrent;
}
}
return {
id: idCurrent,
last: true,
};
}
/**
* A class that treats icon-group resource data (`RT_ICON_GROUP`).
* Note that this class does not treat `RT_ICON` data.
*
* - To pick all icons, use `IconGroupEntry.fromEntries`
* and `IconGroupEntry.prototype.getIconItemsFromEntries`.
* - The easiest way to add/replace icons is using `IconGroupEntry.replaceIconsForResource`,
* which treats both `RT_ICON_GROUP` and `RT_ICON` entries.
*/
var IconGroupEntry = /** @class */ (function () {
function IconGroupEntry(groupEntry) {
var view = new DataView(groupEntry.bin);
var totalSize = view.byteLength;
var icons = [];
if (view.getUint16(2, true) === 1) {
var count = view.getUint16(4, true);
var offset = 6;
for (var i = 0; i < count; ++i) {
icons.push({
width: readUint8WithLastOffset(view, offset, totalSize),
height: readUint8WithLastOffset(view, offset + 1, totalSize),
colors: readUint8WithLastOffset(view, offset + 2, totalSize),
planes: readUint16WithLastOffset(view, offset + 4, totalSize),
bitCount: readUint16WithLastOffset(view, offset + 6, totalSize),
dataSize: readUint32WithLastOffset(view, offset + 8, totalSize),
iconID: readUint16WithLastOffset(view, offset + 12, totalSize),
});
offset += 14; // 16 for .ico file, but 14 for resource data
}
}
this.id = groupEntry.id;
this.lang = groupEntry.lang;
this.icons = icons;
}
IconGroupEntry.fromEntries = function (entries) {
return entries
.filter(function (e) { return e.type === 14; })
.map(function (e) { return new IconGroupEntry(e); });
};
IconGroupEntry.prototype.generateEntry = function () {
var bin = generateEntryBinary(this.icons);
return {
type: 14,
id: this.id,
lang: this.lang,
codepage: 0,
bin: bin,
};
};
/**
* Return an array of `IconItem` / `RawIconItem`, which are in the group of this `IconGroupEntry` instance,
* from specified resource entries.
*/
IconGroupEntry.prototype.getIconItemsFromEntries = function (entries) {
var _this = this;
return entries
.map(function (e) {
if (e.type !== 3 || e.lang !== _this.lang) {
return null;
}
var c = _this.icons
.filter(function (icon) { return e.id === icon.iconID; })
.shift();
if (!c) {
return null;
}
return {
entry: e,
icon: c,
};
})
.filter(function (item) { return !!item; })
.map(function (item) {
var bin = item.entry.bin;
var view = new DataView(bin);
if (view.getUint32(0, true) === 0x28) {
return IconItem.from(bin);
}
else {
var c = item.icon;
return RawIconItem.from(bin, c.width, c.height, c.bitCount);
}
});
};
/**
* Add or replace icon resource entries with specified icon data.
* The IDs of individual icon resources (`RT_ICON`) are calculated automatically.
* @param destEntries base (destination) resource entries.
* @param iconGroupID the icon ID for the new resource data.
* If the icon-group resource of the ID and 'lang' value already exists,
* the resource data is replaced; otherwise the resource data is appended.
* @param lang the language for specified icons (0 for neutral, 0x409 for en-US)
* @param icons the icons to replace
*/
IconGroupEntry.replaceIconsForResource = function (destEntries, iconGroupID, lang, icons) {
// find existing entry
var entry = destEntries
.filter(function (e) { return e.type === 14 && e.id === iconGroupID && e.lang === lang; })
.shift();
var tmpIconArray = icons.map(function (icon) {
if (icon.isIcon()) {
var width = icon.width, height = icon.height;
if (width === null) {
width = icon.bitmapInfo.width;
}
if (height === null) {
height = icon.bitmapInfo.height;
// if mask is specified, the icon height must be the half of bitmap height
if (icon.masks !== null) {
height = Math.floor(height / 2);
}
}
return {
base: icon,
bm: {
width: width,
height: height,
planes: icon.bitmapInfo.planes,
bitCount: icon.bitmapInfo.bitCount,
},
bin: icon.generate(),
id: 0,
};
}
else {
return {
base: icon,
bm: {
width: icon.width,
height: icon.height,
planes: 1,
bitCount: icon.bitCount,
},
bin: icon.bin,
id: 0,
};
}
});
if (entry) {
// remove unused icon data
for (var i = destEntries.length - 1; i >= 0; --i) {
var e = destEntries[i];
if (e != null && e.type === 3) {
// RT_ICON
if (!isIconUsed(e, destEntries, entry)) {
destEntries.splice(i, 1);
}
}
}
}
else {
// create new entry
entry = {
type: 14,
id: iconGroupID,
lang: lang,
codepage: 0,
// set later
bin: null,
};
destEntries.push(entry);
}
// append icons
var idInfo;
tmpIconArray.forEach(function (icon) {
if (!(idInfo === null || idInfo === void 0 ? void 0 : idInfo.last)) {
idInfo = findUnusedIconID(destEntries, lang, false);
}
else {
++idInfo.id;
}
destEntries.push({
type: 3,
id: idInfo.id,
lang: lang,
codepage: 0,
bin: icon.bin,
});
// set 'id' field to use in generateEntryBinary
icon.id = idInfo.id;
});
var binEntry = generateEntryBinary(tmpIconArray.map(function (icon) {
var width = Math.abs(icon.bm.width);
if (width >= 256) {
width = 0;
}
var height = Math.abs(icon.bm.height);
if (height >= 256) {
height = 0;
}
var colors = 0;
if (icon.base.isIcon()) {
var bmBase = icon.base.bitmapInfo;
colors = bmBase.colorUsed || bmBase.colors.length;
if (!colors) {
switch (bmBase.bitCount) {
case 1:
colors = 2;
break;
case 4:
colors = 16;
break;
// case 8:
// colors = 256;
// break;
}
}
if (colors >= 256) {
colors = 0;
}
}
return {
width: width,
height: height,
colors: colors,
planes: icon.bm.planes,
bitCount: icon.bm.bitCount,
dataSize: icon.bin.byteLength,
iconID: icon.id,
};
}));
// rewrite entry
entry.bin = binEntry;
function isIconUsed(icon, allEntries, excludeGroup) {
return allEntries.some(function (e) {
if (e.type !== 14 ||
(e.id === excludeGroup.id && e.lang === excludeGroup.lang)) {
return false;
}
var g = new IconGroupEntry(e);
return g.icons.some(function (c) {
return c.iconID === icon.id;
});
});
}
};
return IconGroupEntry;
}());
export default IconGroupEntry;

View File

@@ -0,0 +1,30 @@
import { NtExecutableResource, Type } from 'pe-library';
/** Utility class to create / parse String Table resource */
export default class StringTable {
/** Language value */
lang: string | number;
private items;
constructor();
/** Create StringTable instance from resource entries, with specified language. */
static fromEntries(lang: string | number, entries: readonly Type.ResourceEntry[]): StringTable;
/** Return all string entries. */
getAllStrings(): Array<{
id: number;
text: string;
}>;
/** Return the string data for ID value, which can be used for Win32API LoadString. */
getById(id: number): string | null;
/**
* Set/overwide the string data for ID value, which can be used for Win32API LoadString.
* @param id data ID
* @param text string data (entry will be removed if null or empty string is specified)
*/
setById(id: number, text: string | null): void;
/** Generates an array of Entry for resource processings */
generateEntries(): Type.ResourceEntry[];
/**
* Replace all string entries for NtExecutableResource with containing resource data.
* The only entries of same language are replaced.
*/
replaceStringEntriesForExecutable(res: NtExecutableResource): void;
}

View File

@@ -0,0 +1,130 @@
import StringTableItem from './StringTableItem.js';
/** Utility class to create / parse String Table resource */
var StringTable = /** @class */ (function () {
function StringTable() {
this.lang = 0;
this.items = [];
}
/** Create StringTable instance from resource entries, with specified language. */
StringTable.fromEntries = function (lang, entries) {
var r = new StringTable();
entries.forEach(function (e) {
// 6: RT_STRING
if (e.type !== 6 ||
e.lang !== lang ||
typeof e.id !== 'number' ||
e.id <= 0) {
return;
}
r.items[e.id - 1] = StringTableItem.fromEntry(e.bin, 0, e.bin.byteLength);
});
r.lang = lang;
return r;
};
/** Return all string entries. */
StringTable.prototype.getAllStrings = function () {
return this.items
.map(function (e, i) {
return e
.getAll()
.map(function (x, j) {
return x !== null && x !== ''
? { id: (i << 4) + j, text: x }
: null;
})
.filter(function (x) { return !!x; });
})
.reduce(function (p, c) { return p.concat(c); }, []);
};
/** Return the string data for ID value, which can be used for Win32API LoadString. */
StringTable.prototype.getById = function (id) {
var _a;
if (id < 0) {
return null;
}
var entryIndex = id >> 4;
var entryPos = id & 15;
var e = this.items[entryIndex];
return (_a = e === null || e === void 0 ? void 0 : e.get(entryPos)) !== null && _a !== void 0 ? _a : null;
};
/**
* Set/overwide the string data for ID value, which can be used for Win32API LoadString.
* @param id data ID
* @param text string data (entry will be removed if null or empty string is specified)
*/
StringTable.prototype.setById = function (id, text) {
if (id < 0) {
return;
}
var entryIndex = id >> 4;
var entryPos = id & 15;
var e = this.items[entryIndex];
if (!e) {
this.items[entryIndex] = e = new StringTableItem();
}
e.set(entryPos, text);
};
/** Generates an array of Entry for resource processings */
StringTable.prototype.generateEntries = function () {
var _this = this;
return this.items
.map(function (e, i) {
var len = e.calcByteLength();
var bin = new ArrayBuffer(len);
e.generate(bin, 0);
return {
type: 6,
id: i + 1,
lang: _this.lang,
codepage: 1200,
bin: bin,
};
})
.filter(function (e) { return !!e; });
};
/**
* Replace all string entries for NtExecutableResource with containing resource data.
* The only entries of same language are replaced.
*/
StringTable.prototype.replaceStringEntriesForExecutable = function (res) {
var entries = this.generateEntries();
var dest = res.entries;
// first try -- replace same type and same language
for (var i = 0; i < dest.length; ++i) {
var e = dest[i];
if (e != null && e.type === 6 && e.lang === this.lang) {
for (var j = dest.length - 1; j >= i; --j) {
var e2 = dest[j];
if (e2 != null && e2.type === 6 && e2.lang === this.lang) {
dest.splice(j, 1);
}
}
var f = dest.splice.bind(dest, i, 0);
f.apply(void 0, entries);
return;
}
}
// second try -- add entries next to previous language
for (var i = 0; i < dest.length; ++i) {
var e = dest[i];
if (e != null && e.type === 6 && e.lang < this.lang) {
var f = dest.splice.bind(dest, i + 1, 0);
f.apply(void 0, entries);
return;
}
}
// third try -- add entries next to the last 'String' entry
for (var i = dest.length - 1; i >= 0; --i) {
var e = dest[i];
if (e != null && e.type === 6) {
var f = dest.splice.bind(dest, i + 1, 0);
f.apply(void 0, entries);
return;
}
}
// otherwise -- add entries to the last
dest.push.apply(dest, entries);
};
return StringTable;
}());
export default StringTable;

View File

@@ -0,0 +1,11 @@
export default class StringTableItem {
readonly length = 16;
private _a;
constructor();
static fromEntry(bin: ArrayBuffer, offset: number, byteLength: number): StringTableItem;
get(index: number): string | null;
getAll(): Array<string | null>;
set(index: number, val: string | null): void;
calcByteLength(): number;
generate(bin: ArrayBuffer, offset: number): number;
}

View File

@@ -0,0 +1,71 @@
// StringTable entry:
// 16-times of {<WORD length> [<UTF-16 string>]}
var StringTableItem = /** @class */ (function () {
function StringTableItem() {
this.length = 16;
this._a = [];
this._a.length = 16;
for (var i = 0; i < 16; ++i) {
this._a[i] = '';
}
}
StringTableItem.fromEntry = function (bin, offset, byteLength) {
var view = new DataView(bin, offset, byteLength);
var ret = new StringTableItem();
var o = 0;
for (var i = 0; i < 16; ++i) {
var len = view.getUint16(o, true);
o += 2;
var s = '';
for (var j = 0; j < len; ++j) {
s += String.fromCharCode(view.getUint16(o, true));
o += 2;
}
ret._a[i] = s;
}
return ret;
};
StringTableItem.prototype.get = function (index) {
var value = this._a[index];
return value != null && value !== '' ? value : null;
};
StringTableItem.prototype.getAll = function () {
return this._a.map(function (s) { return s || null; });
};
StringTableItem.prototype.set = function (index, val) {
this._a[index] = ("" + (val !== null && val !== void 0 ? val : '')).substr(0, 4097); // length must be no longer than 4097
};
StringTableItem.prototype.calcByteLength = function () {
var len = 0;
for (var i = 0; i < 16; ++i) {
var item = this._a[i];
len += 2;
if (item != null) {
len += 2 * item.length; // UTF-16 length
}
}
// 16 alignment
return Math.floor((len + 15) / 16) * 16;
};
StringTableItem.prototype.generate = function (bin, offset) {
var out = new DataView(bin, offset);
var len = 0;
for (var i = 0; i < 16; ++i) {
var s = this._a[i];
var l = s == null ? 0 : s.length > 4097 ? 4097 : s.length;
out.setUint16(len, l, true);
len += 2;
if (s != null) {
for (var j = 0; j < l; ++j) {
// output as UTF-16
out.setUint16(len, s.charCodeAt(j), true);
len += 2;
}
}
}
// 16 alignment
return Math.floor((len + 15) / 16) * 16;
};
return StringTableItem;
}());
export default StringTableItem;

View File

@@ -0,0 +1,13 @@
/**
* Flag values used by VersionEntry.fixedInfo field.
* Zero or more enum values are stored (with OR operator).
*/
declare enum VersionFileFlags {
Debug = 1,
Prerelease = 2,
Patched = 4,
PrivateBuild = 8,
InfoInferred = 16,
SpecialBuild = 32
}
export default VersionFileFlags;

View File

@@ -0,0 +1,14 @@
/**
* Flag values used by VersionEntry.fixedInfo field.
* Zero or more enum values are stored (with OR operator).
*/
var VersionFileFlags;
(function (VersionFileFlags) {
VersionFileFlags[VersionFileFlags["Debug"] = 1] = "Debug";
VersionFileFlags[VersionFileFlags["Prerelease"] = 2] = "Prerelease";
VersionFileFlags[VersionFileFlags["Patched"] = 4] = "Patched";
VersionFileFlags[VersionFileFlags["PrivateBuild"] = 8] = "PrivateBuild";
VersionFileFlags[VersionFileFlags["InfoInferred"] = 16] = "InfoInferred";
VersionFileFlags[VersionFileFlags["SpecialBuild"] = 32] = "SpecialBuild";
})(VersionFileFlags || (VersionFileFlags = {}));
export default VersionFileFlags;

View File

@@ -0,0 +1,20 @@
/**
* OS values used by VersionEntry.fixedInfo field.
*/
declare enum VersionFileOS {
Unknown = 0,
_Windows16 = 1,
_PM16 = 2,
_PM32 = 3,
_Windows32 = 4,
DOS = 65536,
OS2_16 = 131072,
OS2_32 = 196608,
NT = 262144,
DOS_Windows16 = 65537,
DOS_Windows32 = 65540,
NT_Windows32 = 262148,
OS2_16_PM16 = 131074,
OS2_32_PM32 = 196611
}
export default VersionFileOS;

View File

@@ -0,0 +1,21 @@
/**
* OS values used by VersionEntry.fixedInfo field.
*/
var VersionFileOS;
(function (VersionFileOS) {
VersionFileOS[VersionFileOS["Unknown"] = 0] = "Unknown";
VersionFileOS[VersionFileOS["_Windows16"] = 1] = "_Windows16";
VersionFileOS[VersionFileOS["_PM16"] = 2] = "_PM16";
VersionFileOS[VersionFileOS["_PM32"] = 3] = "_PM32";
VersionFileOS[VersionFileOS["_Windows32"] = 4] = "_Windows32";
VersionFileOS[VersionFileOS["DOS"] = 65536] = "DOS";
VersionFileOS[VersionFileOS["OS2_16"] = 131072] = "OS2_16";
VersionFileOS[VersionFileOS["OS2_32"] = 196608] = "OS2_32";
VersionFileOS[VersionFileOS["NT"] = 262144] = "NT";
VersionFileOS[VersionFileOS["DOS_Windows16"] = 65537] = "DOS_Windows16";
VersionFileOS[VersionFileOS["DOS_Windows32"] = 65540] = "DOS_Windows32";
VersionFileOS[VersionFileOS["NT_Windows32"] = 262148] = "NT_Windows32";
VersionFileOS[VersionFileOS["OS2_16_PM16"] = 131074] = "OS2_16_PM16";
VersionFileOS[VersionFileOS["OS2_32_PM32"] = 196611] = "OS2_32_PM32";
})(VersionFileOS || (VersionFileOS = {}));
export default VersionFileOS;

View File

@@ -0,0 +1,20 @@
export declare enum VersionFileDriverSubtype {
Unknown = 0,
Printer = 1,
Keyboard = 2,
Language = 3,
Display = 4,
Mouse = 5,
Network = 6,
System = 7,
Installable = 8,
Sound = 9,
Comm = 10,
VersionedPrinter = 12
}
export declare enum VersionFileFontSubtype {
Unknown = 0,
Raster = 1,
Vector = 2,
TrueType = 3
}

View File

@@ -0,0 +1,22 @@
export var VersionFileDriverSubtype;
(function (VersionFileDriverSubtype) {
VersionFileDriverSubtype[VersionFileDriverSubtype["Unknown"] = 0] = "Unknown";
VersionFileDriverSubtype[VersionFileDriverSubtype["Printer"] = 1] = "Printer";
VersionFileDriverSubtype[VersionFileDriverSubtype["Keyboard"] = 2] = "Keyboard";
VersionFileDriverSubtype[VersionFileDriverSubtype["Language"] = 3] = "Language";
VersionFileDriverSubtype[VersionFileDriverSubtype["Display"] = 4] = "Display";
VersionFileDriverSubtype[VersionFileDriverSubtype["Mouse"] = 5] = "Mouse";
VersionFileDriverSubtype[VersionFileDriverSubtype["Network"] = 6] = "Network";
VersionFileDriverSubtype[VersionFileDriverSubtype["System"] = 7] = "System";
VersionFileDriverSubtype[VersionFileDriverSubtype["Installable"] = 8] = "Installable";
VersionFileDriverSubtype[VersionFileDriverSubtype["Sound"] = 9] = "Sound";
VersionFileDriverSubtype[VersionFileDriverSubtype["Comm"] = 10] = "Comm";
VersionFileDriverSubtype[VersionFileDriverSubtype["VersionedPrinter"] = 12] = "VersionedPrinter";
})(VersionFileDriverSubtype || (VersionFileDriverSubtype = {}));
export var VersionFileFontSubtype;
(function (VersionFileFontSubtype) {
VersionFileFontSubtype[VersionFileFontSubtype["Unknown"] = 0] = "Unknown";
VersionFileFontSubtype[VersionFileFontSubtype["Raster"] = 1] = "Raster";
VersionFileFontSubtype[VersionFileFontSubtype["Vector"] = 2] = "Vector";
VersionFileFontSubtype[VersionFileFontSubtype["TrueType"] = 3] = "TrueType";
})(VersionFileFontSubtype || (VersionFileFontSubtype = {}));

View File

@@ -0,0 +1,13 @@
/**
* File type values used by VersionEntry.fixedInfo field.
*/
declare enum VersionFileType {
Unknown = 0,
App = 1,
DLL = 2,
Driver = 3,
Font = 4,
VxD = 5,
StaticLibrary = 7
}
export default VersionFileType;

View File

@@ -0,0 +1,14 @@
/**
* File type values used by VersionEntry.fixedInfo field.
*/
var VersionFileType;
(function (VersionFileType) {
VersionFileType[VersionFileType["Unknown"] = 0] = "Unknown";
VersionFileType[VersionFileType["App"] = 1] = "App";
VersionFileType[VersionFileType["DLL"] = 2] = "DLL";
VersionFileType[VersionFileType["Driver"] = 3] = "Driver";
VersionFileType[VersionFileType["Font"] = 4] = "Font";
VersionFileType[VersionFileType["VxD"] = 5] = "VxD";
VersionFileType[VersionFileType["StaticLibrary"] = 7] = "StaticLibrary";
})(VersionFileType || (VersionFileType = {}));
export default VersionFileType;

View File

@@ -0,0 +1,197 @@
import { Type } from 'pe-library';
/**
* String values for the version information.
* In most cases predefined names are used for the key names (such as 'FileDescription', 'FileVersion', etc.)
* Note that the key names are case-sensitive; this library does not convert keys
* (e.g. `'fileVersion'` --> `'FileVersion'`).
*/
export declare type VersionStringValues = Record<string, string>;
/** Used by `VersionInfo.create` */
export interface VersionStringTable {
lang: number;
codepage: number;
/** Any string values */
values: VersionStringValues;
}
/** Translation information, containing LANGID and codepage value. */
export interface VersionTranslation {
lang: number;
/** Almost all cases are set to 1200 (Unicode) */
codepage: number;
}
/** Fixed version info, containing file version, product version, etc. (`VS_FIXEDFILEINFO`) */
export interface VersionFixedInfo {
/** usually major version in HIWORD(fileVersionMS), minor version in LOWORD(fileVersionMS) */
fileVersionMS: number;
/** usually patch version in HIWORD(fileVersionLS), revision in LOWORD(fileVersionLS) */
fileVersionLS: number;
productVersionMS: number;
productVersionLS: number;
/** valid values of fileFlags */
fileFlagsMask: number;
/** zero or more VersionFileFlags values, masked by fileFlagsMask */
fileFlags: number;
/** VersionFileOS value */
fileOS: number;
/** VersionFileType value */
fileType: number;
/**
* subtype values depended on fileType, such as
* `VersionFileDriverSubtype` or `VersionFileFontSubtype`.
* (if no suitable value, zero is stored)
*/
fileSubtype: number;
fileDateMS: number;
fileDateLS: number;
}
export interface VersionInfoCreateParam {
lang: string | number;
/** This field can be as a partial object; default values (zero) are used for all unspecified field. */
fixedInfo: Partial<Readonly<VersionFixedInfo>>;
strings: readonly VersionStringTable[];
}
/**
* Treats 'Version information' (`VS_VERSIONINFO`) resource data.
*/
export default class VersionInfo {
private readonly data;
private constructor();
/** Returns new `VersionInfo` instance with empty data. */
static createEmpty(): VersionInfo;
/**
* Returns new `VersionInfo` instance with specified parameters.
* `fixedInfo` can be specified as a partial object;
* default values (zero) are used for all unspecified field.
*/
static create(lang: string | number, fixedInfo: Partial<Readonly<VersionFixedInfo>>, strings: readonly VersionStringTable[]): VersionInfo;
/** Returns new `VersionInfo` instance with specified parameters. */
static create(param: Readonly<VersionInfoCreateParam>): VersionInfo;
/** Pick up all version-info entries */
static fromEntries(entries: readonly Type.ResourceEntry[]): VersionInfo[];
/** A language value for this resource entry. */
get lang(): string | number;
set lang(value: string | number);
/**
* The property of fixed version info, containing file version, product version, etc.
* (data: `VS_FIXEDFILEINFO`)
*
* Although this property is read-only, you can rewrite
* each child fields directly to apply data.
*/
get fixedInfo(): VersionFixedInfo;
/**
* Returns all languages that the executable supports. (data: `VarFileInfo`)
*
* Usually the returned array is equal to the one returned by `getAllLanguagesForStringValues`,
* but some resource-generating tools doesn't generate same values.
*/
getAvailableLanguages(): VersionTranslation[];
/**
* Replaces all languages that the executable supports.
*/
replaceAvailableLanguages(languages: readonly VersionTranslation[]): void;
/**
* Returns all string values for the specified language. (data: values in lang-charset block of `StringFileInfo`)
*/
getStringValues(language: VersionTranslation): VersionStringValues;
/**
* Returns all languages used by string values. (data: lang-charset name of `StringFileInfo`)
*
* Usually the returned array is equal to the one returned by `getAvailableLanguages`,
* but some resource-generating tools doesn't generate same values.
*/
getAllLanguagesForStringValues(): VersionTranslation[];
/**
* Add or replace the string values.
* @param language language info
* @param values string values (key-value pairs)
* @param addToAvailableLanguage set `true` to add `language` into available languages
* if not existing in `getAvailableLanguages()` (default: `true`)
*/
setStringValues(language: VersionTranslation, values: VersionStringValues, addToAvailableLanguage?: boolean): void;
/**
* Add or replace the string value.
* @param language language info
* @param key the key name of string value
* @param value the string value
* @param addToAvailableLanguage set `true` to add `language` into available languages
* if not existing in `getAvailableLanguages()` (default: `true`)
*/
setStringValue(language: VersionTranslation, key: string, value: string, addToAvailableLanguage?: boolean): void;
/**
* Remove all string values for specified language.
* @param language language info
* @param removeFromAvailableLanguage set `true` to remove `language` from available languages
* if existing in `getAvailableLanguages()` (default: `true`)
*/
removeAllStringValues(language: VersionTranslation, removeFromAvailableLanguage?: boolean): void;
/**
* Remove specified string value for specified language.
* @param language language info
* @param key the key name of string value to be removed
* @param removeFromAvailableLanguage set `true` to remove `language` from available languages
* if no more string values exist for `language` (default: `true`)
*/
removeStringValue(language: VersionTranslation, key: string, removeFromAvailableLanguage?: boolean): void;
/**
* Creates `Type.ResourceEntry` object for this instance.
* Usually `outputToResourceEntries` is suitable for generating resource data
* into executables, but you can use this method if necessary.
*/
generateResource(): Type.ResourceEntry;
/**
* Generates version info resource data (using `generateResource()`) and emits into `entries` array.
* If version info resource already exists in `entries`, this method replaces it with the new one.
* @param entries resource entry array for output
*/
outputToResourceEntries(entries: Type.ResourceEntry[]): void;
private getDefaultVersionLang;
/**
* Sets 'FileVersion' property with specified values.
* This methods writes `fixedInfo.fileVersionMS` and `fixedInfo.fileVersionLS` fields,
* and writes `FileVersion` string with the value `<major>.<minor>.<micro>.<revision>`.
* @param major The major version (clamped between 0 and 65535)
* @param minor The minor version (clamped between 0 and 65535)
* @param micro The micro version (clamped between 0 and 65535; default is 0)
* @param revision The revision value (clamped between 0 and 65535; default is 0)
* @param lang The language (default: this.lang -> picked from existings -> 1033)
* @note
* If you want to use 'Neutral' language for the version string, specify `lang` parameter to 0 explicitly
*/
setFileVersion(major: number, minor: number, micro?: number, revision?: number, lang?: number): void;
/**
* Sets 'FileVersion' property with specified values.
* This methods writes `fixedInfo.fileVersionMS` and `fixedInfo.fileVersionLS` fields,
* and writes `FileVersion` string with the value `<major>.<minor>.<micro>.<revision>`.
* @param version The version string value (should be `x.x.x.x` format; each integer clamped between 0 and 65535)
* @param lang The language (default: this.lang -> picked from existings -> 1033)
* @note
* If you want to use 'Neutral' language for the version string, specify `lang` parameter to 0 explicitly
*/
setFileVersion(version: string, lang?: number): void;
private setFileVersionImpl;
/**
* Sets 'ProductVersion' property with specified values.
* This methods writes `fixedInfo.productVersionMS` and `fixedInfo.productVersionLS` fields,
* and writes `ProductVersion` string with the value `<major>.<minor>.<micro>.<revision>`.
* @param major The major version (clamped between 0 and 65535)
* @param minor The minor version (clamped between 0 and 65535)
* @param micro The micro version (clamped between 0 and 65535; default is 0)
* @param revision The revision value (clamped between 0 and 65535; default is 0)
* @param lang The language (default: this.lang -> picked from existings -> 1033)
* @note
* If you want to use 'Neutral' language for the version string, specify `lang` parameter to 0 explicitly
*/
setProductVersion(major: number, minor: number, micro?: number, revision?: number, lang?: number): void;
/**
* Sets 'ProductVersion' property with specified values.
* This methods writes `fixedInfo.productVersionMS` and `fixedInfo.productVersionLS` fields,
* and writes `ProductVersion` string with the value `<major>.<minor>.<micro>.<revision>`.
* @param version The version string value (should be `x.x.x.x` format; each integer clamped between 0 and 65535)
* @param lang The language (default: this.lang -> picked from existings -> 1033)
* @note
* If you want to use 'Neutral' language for the version string, specify `lang` parameter to 0 explicitly
*/
setProductVersion(version: string, lang?: number): void;
private setProductVersionImpl;
}

View File

@@ -0,0 +1,739 @@
import { allocatePartialBinary, cloneObject, copyBuffer, readUint32WithLastOffset, roundUp, } from '../util/functions.js';
function readStringToNullChar(view, offset, last) {
var r = '';
while (offset + 2 <= last) {
var c = view.getUint16(offset, true);
if (!c) {
break;
}
r += String.fromCharCode(c);
offset += 2;
}
return r;
}
function writeStringWithNullChar(view, offset, value) {
for (var i = 0; i < value.length; ++i) {
view.setUint16(offset, value.charCodeAt(i), true);
offset += 2;
}
view.setUint16(offset, 0, true);
return offset + 2;
}
function createFixedInfo() {
return {
fileVersionMS: 0,
fileVersionLS: 0,
productVersionMS: 0,
productVersionLS: 0,
fileFlagsMask: 0,
fileFlags: 0,
fileOS: 0,
fileType: 0,
fileSubtype: 0,
fileDateMS: 0,
fileDateLS: 0,
};
}
////////////////////////////////////////////////////////////////////////////////
// parsings
// returns offset and structure
function parseStringTable(view, offset, last) {
var tableLen = view.getUint16(offset, true);
var valueLen = view.getUint16(offset + 2, true);
if (offset + tableLen < last) {
last = offset + tableLen;
}
// value type check is not needed; because no value is needed
var tableName = readStringToNullChar(view, offset + 6, last);
offset += roundUp(6 + 2 * (tableName.length + 1), 4);
var langAndCp = parseInt(tableName, 16);
if (isNaN(langAndCp)) {
throw new Error('Invalid StringTable data format');
}
// this should be zero
offset += roundUp(valueLen, 4);
var r = {
lang: Math.floor(langAndCp / 0x10000),
codepage: langAndCp & 0xffff,
values: {},
};
while (offset < last) {
// String structure
var childDataLen = view.getUint16(offset, true);
var childValueLen = view.getUint16(offset + 2, true);
// value type must be string; if not, skip it
if (view.getUint16(offset + 4, true) !== 1) {
offset += childDataLen;
continue;
}
var childDataLast = offset + childDataLen;
if (childDataLast > last) {
childDataLast = last;
}
var name_1 = readStringToNullChar(view, offset + 6, childDataLast);
offset = roundUp(offset + 6 + 2 * (name_1.length + 1), 4);
var childValueLast = offset + childValueLen * 2;
if (childValueLast > childDataLast) {
childValueLast = childDataLast;
}
var value = readStringToNullChar(view, offset, childValueLast);
offset = roundUp(childValueLast, 4);
r.values[name_1] = value;
}
// return 'last' instead of 'offset'
return [last, r];
}
function parseStringFileInfo(view, offset, last) {
var valueLen = view.getUint16(offset + 2, true);
// value type check is not needed; because no value is needed
offset += 36; // roundUp(6 + ByteLenWithNull(L'StringFileInfo'), 4)
// this should be zero
offset += roundUp(valueLen, 4);
var r = [];
var _loop_1 = function () {
// StringTable structure
var childData = parseStringTable(view, offset, last);
var table = childData[1];
var a = r.filter(function (e) { return e.lang === table.lang && e.codepage === table.codepage; });
if (a.length === 0) {
r.push(table);
}
else {
// merge values
for (var key in table.values) {
var value = table.values[key];
if (value != null) {
a[0].values[key] = value;
}
}
}
offset = roundUp(childData[0], 4);
};
while (offset < last) {
_loop_1();
}
return r;
}
function parseVarFileInfo(view, offset, last) {
var valueLen = view.getUint16(offset + 2, true);
// value type check is not needed; because no value is needed
offset += 32; // roundUp(6 + ByteLenWithNull(L'VarFileInfo'), 4)
// this should be zero
offset += roundUp(valueLen, 4);
var r = [];
while (offset < last) {
// Var structure
var childDataLen = view.getUint16(offset, true);
var childValueLen = view.getUint16(offset + 2, true);
// value type must be binary; if not, skip it
if (view.getUint16(offset + 4, true) !== 0) {
offset += roundUp(childDataLen, 4);
continue;
}
var childDataLast = offset + childDataLen;
if (childDataLast > last) {
childDataLast = last;
}
var name_2 = readStringToNullChar(view, offset + 6, childDataLast);
offset = roundUp(offset + 6 + 2 * (name_2.length + 1), 4);
if (name_2 !== 'Translation' || childValueLen % 4 !== 0) {
// unknown entry
offset = roundUp(childDataLast, 4);
continue;
}
var _loop_2 = function (child) {
if (offset + 4 > childDataLast) {
return "break";
}
var lang = view.getUint16(offset, true);
var codepage = view.getUint16(offset + 2, true);
offset += 4;
if (r.filter(function (e) { return e.lang === lang && e.codepage === codepage; })
.length === 0) {
r.push({ lang: lang, codepage: codepage });
}
};
for (var child = 0; child < childValueLen; child += 4) {
var state_1 = _loop_2(child);
if (state_1 === "break")
break;
}
offset = roundUp(childDataLast, 4);
}
return r;
}
function parseVersionEntry(view, entry) {
var totalLen = view.getUint16(0, true);
var dataLen = view.getUint16(2, true);
// value type must be binary
if (view.getUint16(4, true) !== 0) {
throw new Error('Invalid version data format');
}
// 40 === roundUp(6 + ByteLenWithNull(L'VS_VERSION_INFO'), 4)
if (totalLen < dataLen + 40) {
throw new Error('Invalid version data format');
}
if (readStringToNullChar(view, 6, totalLen) !== 'VS_VERSION_INFO') {
throw new Error('Invalid version data format');
}
var d = {
lang: entry.lang,
fixedInfo: createFixedInfo(),
strings: [],
translations: [],
unknowns: [],
};
var offset = 38; // without padding
if (dataLen) {
dataLen += 40; // with padding
var sig = readUint32WithLastOffset(view, 40, dataLen);
var sVer = readUint32WithLastOffset(view, 44, dataLen);
// check signature
if (sig === 0xfeef04bd && sVer <= 0x10000) {
d.fixedInfo = {
fileVersionMS: readUint32WithLastOffset(view, 48, dataLen),
fileVersionLS: readUint32WithLastOffset(view, 52, dataLen),
productVersionMS: readUint32WithLastOffset(view, 56, dataLen),
productVersionLS: readUint32WithLastOffset(view, 60, dataLen),
fileFlagsMask: readUint32WithLastOffset(view, 64, dataLen),
fileFlags: readUint32WithLastOffset(view, 68, dataLen),
fileOS: readUint32WithLastOffset(view, 72, dataLen),
fileType: readUint32WithLastOffset(view, 76, dataLen),
fileSubtype: readUint32WithLastOffset(view, 80, dataLen),
fileDateMS: readUint32WithLastOffset(view, 84, dataLen),
fileDateLS: readUint32WithLastOffset(view, 88, dataLen),
};
}
offset = dataLen;
}
offset = roundUp(offset, 4);
// parse children
while (offset < totalLen) {
var childLen = view.getUint16(offset, true);
var childLast = offset + childLen;
// failsafe
if (childLast > totalLen) {
childLast = totalLen;
}
var name_3 = readStringToNullChar(view, offset + 6, childLast);
switch (name_3) {
case 'StringFileInfo':
d.strings = d.strings.concat(parseStringFileInfo(view, offset, childLast));
break;
case 'VarFileInfo':
d.translations = d.translations.concat(parseVarFileInfo(view, offset, childLast));
break;
default:
// unknown or unsupported type
d.unknowns.push({
name: name_3,
entireBin: allocatePartialBinary(view, offset, childLen),
});
break;
}
offset += roundUp(childLen, 4);
}
return d;
}
////////////////////////////////////////////////////////////////////////////////
// serializings
function generateStringTable(table) {
// estimate size
var size = 24; // roundUp(6 + ByteLenWithNull(L'xxxxxxxx'), 4)
var keys = Object.keys(table.values);
size = keys.reduce(function (prev, key) {
var value = table.values[key];
if (value == null) {
return prev;
}
var childHeaderSize = roundUp(6 + 2 * (key.length + 1), 4);
var newSize = roundUp(prev + childHeaderSize + 2 * (value.length + 1), 4);
// limit to 65532 because the table size is restricted to 16-bit value
return newSize > 65532 ? prev : newSize;
}, size);
// generate binary
var bin = new ArrayBuffer(size);
var view = new DataView(bin);
view.setUint16(0, size, true);
view.setUint16(2, 0, true); // no value length
view.setUint16(4, 1, true);
var langAndCp = ((table.lang & 0xffff) * 0x10000 +
(table.codepage & 0xffff))
.toString(16)
.toLowerCase();
// fixed length
if (langAndCp.length < 8) {
var l = 8 - langAndCp.length;
langAndCp = '00000000'.substr(0, l) + langAndCp;
}
var offset = roundUp(writeStringWithNullChar(view, 6, langAndCp), 4);
keys.forEach(function (key) {
var value = table.values[key];
if (value == null) {
return;
}
var childHeaderSize = roundUp(6 + 2 * (key.length + 1), 4);
var newSize = roundUp(childHeaderSize + 2 * (value.length + 1), 4);
if (offset + newSize <= 65532) {
view.setUint16(offset, newSize, true);
view.setUint16(offset + 2, value.length + 1, true); // value length is in character count
view.setUint16(offset + 4, 1, true);
offset = roundUp(writeStringWithNullChar(view, offset + 6, key), 4);
offset = roundUp(writeStringWithNullChar(view, offset, value), 4);
}
});
return bin;
}
function generateStringTableInfo(tables) {
// estimate size
var size = 36; // roundUp(6 + ByteLenWithNull(L'StringFileInfo'), 4)
var tableBins = tables.map(function (table) { return generateStringTable(table); });
// (all table sizes are rounded up)
size += tableBins.reduce(function (p, c) { return p + c.byteLength; }, 0);
var bin = new ArrayBuffer(size);
var view = new DataView(bin);
view.setUint16(0, size, true);
view.setUint16(2, 0, true); // no value length
view.setUint16(4, 1, true);
var offset = roundUp(writeStringWithNullChar(view, 6, 'StringFileInfo'), 4);
tableBins.forEach(function (table) {
var len = table.byteLength;
copyBuffer(bin, offset, table, 0, len);
offset += len;
});
return bin;
}
function generateVarFileInfo(translations) {
// estimate size
var size = 32; // roundUp(6 + ByteLenWithNull(L'VarFileInfo'), 4)
// (translation data is fixed length)
var translationsValueSize = translations.length * 4;
size += 32 + translationsValueSize;
var bin = new ArrayBuffer(size);
var view = new DataView(bin);
view.setUint16(0, size, true);
view.setUint16(2, 0, true); // no value length
view.setUint16(4, 1, true);
var offset = roundUp(writeStringWithNullChar(view, 6, 'VarFileInfo'), 4);
view.setUint16(offset, 32 + translationsValueSize, true);
view.setUint16(offset + 2, translationsValueSize, true);
view.setUint16(offset + 4, 0, true);
offset = roundUp(writeStringWithNullChar(view, offset + 6, 'Translation'), 4);
translations.forEach(function (translation) {
view.setUint16(offset, translation.lang, true);
view.setUint16(offset + 2, translation.codepage, true);
offset += 4;
});
return bin;
}
function generateVersionEntryBinary(entry) {
var size = 92; // roundUp(6 + ByteLenWithNull(L'VS_VERSION_INFO'), 4) + 52 (sizeof VS_FIXEDFILEINFO)
var stringTableInfoBin = generateStringTableInfo(entry.strings);
var stringTableInfoLen = stringTableInfoBin.byteLength;
size += stringTableInfoLen;
var varFileInfoBin = generateVarFileInfo(entry.translations);
var varFileInfoLen = varFileInfoBin.byteLength;
size += varFileInfoLen;
size = entry.unknowns.reduce(function (p, data) { return p + roundUp(data.entireBin.byteLength, 4); }, size);
var bin = new ArrayBuffer(size);
var view = new DataView(bin);
view.setUint16(0, size, true);
view.setUint16(2, 52, true);
view.setUint16(4, 0, true); // value is binary
var offset = roundUp(writeStringWithNullChar(view, 6, 'VS_VERSION_INFO'), 4);
view.setUint32(offset, 0xfeef04bd, true); // signature
view.setUint32(offset + 4, 0x10000, true); // structure version
view.setUint32(offset + 8, entry.fixedInfo.fileVersionMS, true);
view.setUint32(offset + 12, entry.fixedInfo.fileVersionLS, true);
view.setUint32(offset + 16, entry.fixedInfo.productVersionMS, true);
view.setUint32(offset + 20, entry.fixedInfo.productVersionLS, true);
view.setUint32(offset + 24, entry.fixedInfo.fileFlagsMask, true);
view.setUint32(offset + 28, entry.fixedInfo.fileFlags, true);
view.setUint32(offset + 32, entry.fixedInfo.fileOS, true);
view.setUint32(offset + 36, entry.fixedInfo.fileType, true);
view.setUint32(offset + 40, entry.fixedInfo.fileSubtype, true);
view.setUint32(offset + 44, entry.fixedInfo.fileDateMS, true);
view.setUint32(offset + 48, entry.fixedInfo.fileDateLS, true);
offset += 52;
copyBuffer(bin, offset, stringTableInfoBin, 0, stringTableInfoLen);
offset += stringTableInfoLen;
copyBuffer(bin, offset, varFileInfoBin, 0, varFileInfoLen);
offset += varFileInfoLen;
entry.unknowns.forEach(function (e) {
var len = e.entireBin.byteLength;
copyBuffer(bin, offset, e.entireBin, 0, len);
offset += roundUp(len, 4);
});
return bin;
}
////////////////////////////////////////////////////////////////////////////////
function clampInt(val, min, max) {
if (isNaN(val) || val < min) {
return min;
}
else if (val >= max) {
return max;
}
return Math.floor(val);
}
function parseVersionArguments(arg1, arg2, arg3, arg4, arg5) {
var _a;
var major;
var minor;
var micro;
var revision;
var lang;
if (typeof arg1 === 'string' &&
(typeof arg2 === 'undefined' || typeof arg2 === 'number') &&
typeof arg3 === 'undefined') {
_a = arg1
.split('.')
.map(function (token) { return clampInt(Number(token), 0, 65535); })
// add zeros for missing fields
.concat(0, 0, 0), major = _a[0], minor = _a[1], micro = _a[2], revision = _a[3];
lang = arg2;
}
else {
major = clampInt(Number(arg1), 0, 65535);
minor = clampInt(Number(arg2), 0, 65535);
micro = clampInt(typeof arg3 === 'undefined' ? 0 : Number(arg3), 0, 65535);
revision = clampInt(typeof arg4 === 'undefined' ? 0 : Number(arg4), 0, 65535);
lang = arg5;
}
return [major, minor, micro, revision, lang];
}
////////////////////////////////////////////////////////////////////////////////
/**
* Treats 'Version information' (`VS_VERSIONINFO`) resource data.
*/
var VersionInfo = /** @class */ (function () {
function VersionInfo(entry) {
if (!entry) {
this.data = {
lang: 0,
fixedInfo: createFixedInfo(),
strings: [],
translations: [],
unknowns: [],
};
}
else {
var view = new DataView(entry.bin);
this.data = parseVersionEntry(view, entry);
}
}
/** Returns new `VersionInfo` instance with empty data. */
VersionInfo.createEmpty = function () {
return new VersionInfo();
};
VersionInfo.create = function (arg1, fixedInfo, strings) {
var lang;
if (typeof arg1 === 'object') {
lang = arg1.lang;
fixedInfo = arg1.fixedInfo;
strings = arg1.strings;
}
else {
lang = arg1;
}
var vi = new VersionInfo();
vi.data.lang = lang;
// copy all specified values
// (if unspecified, use default value set by `createFixedInfo`)
for (var _fixedInfoKey in fixedInfo) {
var fixedInfoKey = _fixedInfoKey;
if (fixedInfoKey in fixedInfo) {
var value = fixedInfo[fixedInfoKey];
if (value != null) {
vi.data.fixedInfo[fixedInfoKey] = value;
}
}
}
vi.data.strings = strings.map(function (_a) {
var lang = _a.lang, codepage = _a.codepage, values = _a.values;
return ({
lang: lang,
codepage: codepage,
values: cloneObject(values),
});
});
vi.data.translations = strings.map(function (_a) {
var lang = _a.lang, codepage = _a.codepage;
return ({ lang: lang, codepage: codepage });
});
return vi;
};
/** Pick up all version-info entries */
VersionInfo.fromEntries = function (entries) {
return entries
.filter(function (e) { return e.type === 16; })
.map(function (e) { return new VersionInfo(e); });
};
Object.defineProperty(VersionInfo.prototype, "lang", {
/** A language value for this resource entry. */
get: function () {
return this.data.lang;
},
set: function (value) {
this.data.lang = value;
},
enumerable: false,
configurable: true
});
Object.defineProperty(VersionInfo.prototype, "fixedInfo", {
/**
* The property of fixed version info, containing file version, product version, etc.
* (data: `VS_FIXEDFILEINFO`)
*
* Although this property is read-only, you can rewrite
* each child fields directly to apply data.
*/
get: function () {
return this.data.fixedInfo;
},
enumerable: false,
configurable: true
});
/**
* Returns all languages that the executable supports. (data: `VarFileInfo`)
*
* Usually the returned array is equal to the one returned by `getAllLanguagesForStringValues`,
* but some resource-generating tools doesn't generate same values.
*/
VersionInfo.prototype.getAvailableLanguages = function () {
return this.data.translations.slice(0);
};
/**
* Replaces all languages that the executable supports.
*/
VersionInfo.prototype.replaceAvailableLanguages = function (languages) {
this.data.translations = languages.slice(0);
};
/**
* Returns all string values for the specified language. (data: values in lang-charset block of `StringFileInfo`)
*/
VersionInfo.prototype.getStringValues = function (language) {
var a = this.data.strings
.filter(function (e) {
return e.lang === language.lang && e.codepage === language.codepage;
})
.map(function (e) { return e.values; });
return a.length > 0 ? a[0] : {};
};
/**
* Returns all languages used by string values. (data: lang-charset name of `StringFileInfo`)
*
* Usually the returned array is equal to the one returned by `getAvailableLanguages`,
* but some resource-generating tools doesn't generate same values.
*/
VersionInfo.prototype.getAllLanguagesForStringValues = function () {
return this.data.strings.map(function (_a) {
var codepage = _a.codepage, lang = _a.lang;
return ({ codepage: codepage, lang: lang });
});
};
/**
* Add or replace the string values.
* @param language language info
* @param values string values (key-value pairs)
* @param addToAvailableLanguage set `true` to add `language` into available languages
* if not existing in `getAvailableLanguages()` (default: `true`)
*/
VersionInfo.prototype.setStringValues = function (language, values, addToAvailableLanguage) {
if (addToAvailableLanguage === void 0) { addToAvailableLanguage = true; }
var a = this.data.strings.filter(function (e) { return e.lang === language.lang && e.codepage === language.codepage; });
var table;
if (a.length === 0) {
table = {
lang: language.lang,
codepage: language.codepage,
values: {},
};
this.data.strings.push(table);
}
else {
table = a[0];
}
for (var key in values) {
var value = values[key];
if (value != null) {
table.values[key] = value;
}
}
if (addToAvailableLanguage) {
// if no translation is available, then add it
var t = this.data.translations.filter(function (e) {
return e.lang === language.lang && e.codepage === language.codepage;
});
if (t.length === 0) {
this.data.translations.push({
lang: language.lang,
codepage: language.codepage,
});
}
}
};
/**
* Add or replace the string value.
* @param language language info
* @param key the key name of string value
* @param value the string value
* @param addToAvailableLanguage set `true` to add `language` into available languages
* if not existing in `getAvailableLanguages()` (default: `true`)
*/
VersionInfo.prototype.setStringValue = function (language, key, value, addToAvailableLanguage) {
var _a;
if (addToAvailableLanguage === void 0) { addToAvailableLanguage = true; }
this.setStringValues(language, (_a = {}, _a[key] = value, _a), addToAvailableLanguage);
};
/**
* Remove all string values for specified language.
* @param language language info
* @param removeFromAvailableLanguage set `true` to remove `language` from available languages
* if existing in `getAvailableLanguages()` (default: `true`)
*/
VersionInfo.prototype.removeAllStringValues = function (language, removeFromAvailableLanguage) {
if (removeFromAvailableLanguage === void 0) { removeFromAvailableLanguage = true; }
var strings = this.data.strings;
var len = strings.length;
for (var i = 0; i < len; ++i) {
var e = strings[i];
if (e != null &&
e.lang === language.lang &&
e.codepage === language.codepage) {
strings.splice(i, 1);
if (removeFromAvailableLanguage) {
var translations = this.data.translations;
for (var j = 0; j < translations.length; j++) {
var t = translations[j];
if (t != null &&
t.lang === language.lang &&
t.codepage === language.codepage) {
translations.splice(j, 1);
break;
}
}
}
break;
}
}
};
/**
* Remove specified string value for specified language.
* @param language language info
* @param key the key name of string value to be removed
* @param removeFromAvailableLanguage set `true` to remove `language` from available languages
* if no more string values exist for `language` (default: `true`)
*/
VersionInfo.prototype.removeStringValue = function (language, key, removeFromAvailableLanguage) {
if (removeFromAvailableLanguage === void 0) { removeFromAvailableLanguage = true; }
var strings = this.data.strings;
var len = strings.length;
for (var i = 0; i < len; ++i) {
var e = strings[i];
if (e != null &&
e.lang === language.lang &&
e.codepage === language.codepage) {
try {
// eslint-disable-next-line @typescript-eslint/no-dynamic-delete
delete e.values[key];
}
catch (_ex) { }
if (removeFromAvailableLanguage &&
Object.keys(e.values).length === 0) {
// if no entries are left, remove table and translations
strings.splice(i, 1);
var translations = this.data.translations;
for (var j = 0; j < translations.length; j++) {
var t = translations[j];
if (t != null &&
t.lang === language.lang &&
t.codepage === language.codepage) {
translations.splice(j, 1);
break;
}
}
}
break;
}
}
};
/**
* Creates `Type.ResourceEntry` object for this instance.
* Usually `outputToResourceEntries` is suitable for generating resource data
* into executables, but you can use this method if necessary.
*/
VersionInfo.prototype.generateResource = function () {
var bin = generateVersionEntryBinary(this.data);
return {
type: 16,
id: 1,
lang: this.lang,
codepage: 1200,
bin: bin,
};
};
/**
* Generates version info resource data (using `generateResource()`) and emits into `entries` array.
* If version info resource already exists in `entries`, this method replaces it with the new one.
* @param entries resource entry array for output
*/
VersionInfo.prototype.outputToResourceEntries = function (entries) {
var res = this.generateResource();
var len = entries.length;
for (var i = 0; i < len; ++i) {
var e = entries[i];
if (e != null &&
e.type === 16 &&
e.id === res.id &&
e.lang === res.lang) {
entries[i] = res;
return;
}
}
entries.push(res);
};
// utility methods
VersionInfo.prototype.getDefaultVersionLang = function (propName) {
// first, use `this.lang` if it is a numeric value
var num = Number(this.lang);
if (this.lang !== '' && !isNaN(num)) {
return num;
}
// second, use lang value for propName if there is only one language
var a = this.data.strings
.filter(function (e) { return propName in e.values && e.values[propName] != null; })
.map(function (e) { return e.lang; });
if (a.length === 1) {
return a[0];
}
// use English language
return 1033;
};
VersionInfo.prototype.setFileVersion = function (arg1, arg2, arg3, arg4, arg5) {
this.setFileVersionImpl.apply(this, parseVersionArguments(arg1, arg2, arg3, arg4, arg5));
};
VersionInfo.prototype.setFileVersionImpl = function (major, minor, micro, revision, lang) {
lang =
typeof lang !== 'undefined'
? lang
: this.getDefaultVersionLang('FileVersion');
this.fixedInfo.fileVersionMS = (major << 16) | minor;
this.fixedInfo.fileVersionLS = (micro << 16) | revision;
this.setStringValue({ lang: lang, codepage: 1200 }, 'FileVersion', major + "." + minor + "." + micro + "." + revision, true);
};
VersionInfo.prototype.setProductVersion = function (arg1, arg2, arg3, arg4, arg5) {
this.setProductVersionImpl.apply(this, parseVersionArguments(arg1, arg2, arg3, arg4, arg5));
};
VersionInfo.prototype.setProductVersionImpl = function (major, minor, micro, revision, lang) {
lang =
typeof lang !== 'undefined'
? lang
: this.getDefaultVersionLang('ProductVersion');
this.fixedInfo.productVersionMS = (major << 16) | minor;
this.fixedInfo.productVersionLS = (micro << 16) | revision;
this.setStringValue({ lang: lang, codepage: 1200 }, 'ProductVersion', major + "." + minor + "." + micro + "." + revision, true);
};
return VersionInfo;
}());
export default VersionInfo;

View File

@@ -0,0 +1,11 @@
import { Type } from 'pe-library';
import IconGroupEntry, { IconGroupItem } from './IconGroupEntry.js';
import StringTable from './StringTable.js';
import VersionFileFlags from './VersionFileFlags.js';
import VersionFileOS from './VersionFileOS.js';
import { VersionFileDriverSubtype, VersionFileFontSubtype } from './VersionFileSubtypes.js';
import VersionFileType from './VersionFileType.js';
import VersionInfo, { VersionInfoCreateParam, VersionFixedInfo, VersionStringTable, VersionStringValues, VersionTranslation } from './VersionInfo.js';
declare type ResourceEntry = Type.ResourceEntry;
declare type ResourceEntryBaseType<TType extends string | number, TID extends string | number, TLang extends string | number> = Type.ResourceEntryBaseType<TType, TID, TLang>;
export { IconGroupEntry, IconGroupItem, ResourceEntry, ResourceEntryBaseType, StringTable, VersionInfoCreateParam, VersionFileFlags, VersionFileOS, VersionFileDriverSubtype, VersionFileFontSubtype, VersionFileType, VersionFixedInfo, VersionInfo, VersionStringTable, VersionStringValues, VersionTranslation, };

View File

@@ -0,0 +1,8 @@
import IconGroupEntry from './IconGroupEntry.js';
import StringTable from './StringTable.js';
import VersionFileFlags from './VersionFileFlags.js';
import VersionFileOS from './VersionFileOS.js';
import { VersionFileDriverSubtype, VersionFileFontSubtype, } from './VersionFileSubtypes.js';
import VersionFileType from './VersionFileType.js';
import VersionInfo from './VersionInfo.js';
export { IconGroupEntry, StringTable, VersionFileFlags, VersionFileOS, VersionFileDriverSubtype, VersionFileFontSubtype, VersionFileType, VersionInfo, };

View File

@@ -0,0 +1,71 @@
/** Predefined algorithm types */
export declare type DigestAlgorithmType = 'sha1' | 'sha224' | 'sha256' | 'sha384' | 'sha512' | 'sha512-224' | 'sha512-256' | 'sha3-224' | 'sha3-256' | 'sha3-384' | 'sha3-512' | 'shake128' | 'shake256' | 'SHA1' | 'SHA224' | 'SHA256' | 'SHA384' | 'SHA512' | 'SHA512-224' | 'SHA512-256' | 'SHA3-224' | 'SHA3-256' | 'SHA3-384' | 'SHA3-512' | 'SHAKE128' | 'SHAKE256';
export declare type EncryptionAlgorithmType = 'rsa' | 'dsa' | 'RSA' | 'DSA';
export default interface SignerObject {
/**
* Returns the digest algorithm used in `digestData`.
* To use the algorithm other than defined in `DigestAlgorithmType`,
* return an integer array of values from OID string.
* (e.g. [1,3,14,3,2,26] for 'sha1')
*
* @note
* The newer digest algorithm (including SHA224, SHA512-256, SHA3 algorithms, etc.)
* might not be supported by Windows.
*/
getDigestAlgorithm(): DigestAlgorithmType | number[];
/**
* Returns the encryption algorithm used in `encryptData`.
* To use the algorithm other than defined in `EncryptionAlgorithmType`,
* return an integer array of values from OID string.
* (e.g. [1,2,840,113549,1,1,1] for 'rsa')
*/
getEncryptionAlgorithm(): EncryptionAlgorithmType | number[];
/**
* Returns the certificate data, which format is DER binary (X.509 certificate data
* or '.p7b' file data which is based on DER and contains certificates).
*
* You can return an `Array` (not an `ArrayLike`), which contains one or more certificates in format above.
* In this case, each certificates are stored to signed data in order.
* Note that this library does not sort certificates, so the implementation should have responsible for the order of certificates.
*/
getCertificateData(): ArrayBuffer | ArrayBufferView | Array<ArrayBuffer | ArrayBufferView>;
/**
* Returns the public key data, which format is DER binary (X.509 Public Key or '.p7b' file data which is based on DER).
*
* You can return an `Array` (not an `ArrayLike`), which contains one or more public keys in format above.
* In this case, each public keys are stored to signed data in order.
* Note that this library does not sort public keys, so the implementation should have responsible for the order of keys.
*
* @deprecated This method is renamed to {@link getCertificateData} due to the actual purpose of this method
* and `getPublicKeyData` will no longer be used in the future.
*/
getPublicKeyData?(): ArrayBuffer | ArrayBufferView | Array<ArrayBuffer | ArrayBufferView>;
/**
* Digests specified data. The digest algorithm type must be same as the result of `getDigestAlgorithm`.
* Must pick all data from `dataIterator` (until `dataIterator.next().done` is `true`).
*/
digestData(dataIterator: Iterator<ArrayBuffer, void>): PromiseLike<ArrayBuffer | ArrayBufferView>;
/**
* Encrypts specified data with **private key** (i.e. can be verified with the public key from `getCertificateData`). The private key type (algorithm) must be same as the result of `getEncryptionAlgorithm`.
* Must pick all data from `dataIterator` (until `dataIterator.next().done` is `true`).
*
* This method must be implemented if `signData` is not implemented.
*/
encryptData?(dataIterator: Iterator<ArrayBuffer, void>): PromiseLike<ArrayBuffer | ArrayBufferView>;
/**
* Signs specified data with **private key** (i.e. can be verified with the public key from `getCertificateData`).
* The private key type (algorithm) must be same as the result of `getEncryptionAlgorithm`, and the digest algorithm must be same as the result of `getDigestAlgorithm`.
* Must pick all data from `dataIterator` (until `dataIterator.next().done` is `true`).
*
* This method must be implemented if `encryptData` is not implemented.
*
* Note that even if `signData` is implemented, `digestData` must be implemented.
*/
signData?(dataIterator: Iterator<ArrayBuffer, void>): PromiseLike<ArrayBuffer | ArrayBufferView>;
/**
* Make 'timestamp' data, generated by TSA, from specified data (omit this method if not using timestamp).
* Must return entire timestamp response data.
* @param reqData timestamp request data (`TimeStampReq`) to send to TSA
*/
timestampData?(reqData: ArrayBuffer): PromiseLike<ArrayBuffer | ArrayBufferView>;
}

View File

@@ -0,0 +1,2 @@
export {};
/* eslint-enable @typescript-eslint/method-signature-style */

View File

@@ -0,0 +1,7 @@
import DERObject from './data/DERObject.js';
export declare function toUint8Array(bin: ArrayBuffer | ArrayBufferView): Uint8Array;
/** @return [length, afterOffset] */
export declare function calculateDERLength(data: number[] | Uint8Array, offset: number): [number, number];
/** @return [issuer, serialNumber] */
export declare function pickIssuerAndSerialNumberDERFromCert(bin: ArrayBuffer | ArrayBufferView | Array<ArrayBuffer | ArrayBufferView>): [number[], number[]];
export declare function certBinToCertificatesDER(bin: ArrayBuffer | ArrayBufferView | Array<ArrayBuffer | ArrayBufferView>): DERObject[];

View File

@@ -0,0 +1,246 @@
import { RawDERObject } from './data/DERObject.js';
import { OID_SIGNED_DATA } from './data/KnownOids.js';
export function toUint8Array(bin) {
if ('buffer' in bin) {
return new Uint8Array(bin.buffer, bin.byteOffset, bin.byteLength);
}
else {
return new Uint8Array(bin);
}
}
/** @return [length, afterOffset] */
export function calculateDERLength(data, offset) {
var actualLength = 0;
var value = data[offset];
if (value == null) {
throw new Error('Invalid "offset" value');
}
else if (value < 0x80) {
actualLength = value;
++offset;
}
else if (value === 0x80) {
throw new Error('Not supported certificate data (variable length)');
}
else {
var c = value & 0x7f;
++offset;
while (c--) {
if (offset >= data.length) {
throw new Error('Invalid certificate data (invalid sequence length)');
}
actualLength <<= 8;
actualLength |= data[offset];
++offset;
}
}
return [actualLength, offset];
}
function skipField(data, offsetOfDataHead) {
var _a = calculateDERLength(data, offsetOfDataHead + 1), len = _a[0], off = _a[1];
return off + len;
}
function pickCertificatesIfDERHasSignedData(ub, offset) {
var _a, _b, _c, _d, _e;
if (ub.length < offset + 2) {
return null;
}
if (ub[offset] !== 0x30) {
return null;
}
var tempLength;
_a = calculateDERLength(ub, offset + 1), tempLength = _a[0], offset = _a[1];
if (tempLength > ub.length - offset) {
throw new Error('Invalid certificate data (insufficient data length)');
}
// if the first item is not contentType, then return
if (ub[offset] !== 0x6) {
return null;
}
var signedDataOid = OID_SIGNED_DATA.toDER();
for (var i = 0; i < signedDataOid.length; ++i) {
if (ub[offset + i] !== signedDataOid[i]) {
return null;
}
}
// if contentType is OID_SIGNED_DATA, then check sequence format
// ContentInfo.content
offset += signedDataOid.length;
// [0] IMPLICIT
if (ub[offset] !== 0xa0) {
throw new Error('Invalid certificate data (no content in contentInfo)');
}
_b = calculateDERLength(ub, offset + 1), tempLength = _b[0], offset = _b[1];
if (offset + tempLength > ub.length) {
throw new Error('Invalid certificate data (invalid length for content)');
}
// sequence
if (ub[offset] !== 0x30) {
throw new Error('Invalid certificate data (unexpected signedData)');
}
_c = calculateDERLength(ub, offset + 1), tempLength = _c[0], offset = _c[1];
if (offset + tempLength > ub.length) {
throw new Error('Invalid certificate data (invalid length for signedData)');
}
// version
if (ub[offset] !== 0x2 ||
ub[offset + 1] !== 0x1 ||
ub[offset + 2] !== 0x1) {
throw new Error('Invalid certificate data (unexpected signedData.version)');
}
offset += 3;
// digestAlgorithms (skip)
if (ub[offset] !== 0x31) {
throw new Error('Invalid certificate data (no signedData.digestAlgorithms)');
}
_d = calculateDERLength(ub, offset + 1), tempLength = _d[0], offset = _d[1];
if (offset + tempLength > ub.length) {
throw new Error('Invalid certificate data (invalid length for signedData.digestAlgorithms)');
}
offset += tempLength;
// contentInfo (skip)
if (ub[offset] !== 0x30) {
throw new Error('Invalid certificate data (no signedData.contentInfo)');
}
_e = calculateDERLength(ub, offset + 1), tempLength = _e[0], offset = _e[1];
if (offset + tempLength > ub.length) {
throw new Error('Invalid certificate data (invalid length for signedData.contentInfo)');
}
offset += tempLength;
// certificates
if (ub[offset] !== 0xa0) {
throw new Error('Invalid certificate data (no signedData.certificates)');
}
var _f = calculateDERLength(ub, offset + 1), certsLength = _f[0], newOffset = _f[1];
if (newOffset + certsLength > ub.length) {
throw new Error('Invalid certificate data (invalid length for signedData.certificates)');
}
return ub.subarray(offset, newOffset + certsLength);
}
/** @return [issuer, serialNumber] */
export function pickIssuerAndSerialNumberDERFromCert(bin) {
var _a, _b;
if (Array.isArray(bin)) {
// use first one and call again
if (bin.length === 0) {
throw new Error('No data is specified.');
}
return pickIssuerAndSerialNumberDERFromCert(bin[0]);
}
var ub = toUint8Array(bin);
if (ub.length < 2) {
throw new Error('Invalid certificate data');
}
if (ub[0] !== 0x30) {
throw new Error('Not supported certificate data (non-`Certificate`-format data)');
}
var certsBin = pickCertificatesIfDERHasSignedData(ub, 0);
if (certsBin) {
// certificates
var _c = calculateDERLength(certsBin, 1), tempLength_1 = _c[0], eaten_1 = _c[1];
if (eaten_1 + tempLength_1 > certsBin.length) {
throw new Error('Invalid certificate data (invalid length for signedData.certificates)');
}
// pick first certificate and call again
if (certsBin[eaten_1] !== 0x30) {
throw new Error('Invalid certificate data (no signedData.certificates[0])');
}
var _d = calculateDERLength(certsBin, eaten_1 + 1), certLength = _d[0], tempOffset = _d[1];
if (tempOffset + certLength > certsBin.length) {
throw new Error('Invalid certificate data (invalid length for signedData.certificates[0])');
}
return pickIssuerAndSerialNumberDERFromCert(certsBin.subarray(eaten_1, tempOffset + certLength));
}
var tempLength;
var eaten;
_a = calculateDERLength(ub, 1), tempLength = _a[0], eaten = _a[1];
if (tempLength > ub.length - eaten) {
throw new Error('Invalid certificate data (insufficient data length)');
}
if (ub[eaten] !== 0x30) {
throw new Error('Invalid certificate data (missing tbsCertificate)');
}
// Certificate
var tbsCertificateLen;
_b = calculateDERLength(ub, eaten + 1), tbsCertificateLen = _b[0], eaten = _b[1];
if (tbsCertificateLen > ub.length - eaten) {
throw new Error('Invalid certificate data (invalid tbsCertificate length)');
}
var tbsOffsetLast = eaten + tbsCertificateLen;
// TBSCertificate
// :skip version
if (ub[eaten] === 0xa0) {
eaten = skipField(ub, eaten);
if (eaten >= tbsOffsetLast) {
throw new Error('Invalid certificate data (insufficient tbsCertificate data: after version)');
}
}
// pick serialNumber
if (ub[eaten] !== 2) {
throw new Error('Invalid certificate data (invalid serialNumber)');
}
var offsetAfterSerialNumber = skipField(ub, eaten);
if (eaten >= tbsOffsetLast) {
throw new Error('Invalid certificate data (insufficient tbsCertificate data: after serialNumber)');
}
var serialNumberDER = [].slice.call(ub, eaten, offsetAfterSerialNumber);
eaten = offsetAfterSerialNumber;
// :skip algorithmIdentifier
if (ub[eaten] !== 0x30) {
throw new Error('Invalid certificate data (invalid algorithmIdentifier)');
}
eaten = skipField(ub, eaten);
if (eaten >= tbsOffsetLast) {
throw new Error('Invalid certificate data (insufficient tbsCertificate data: after serialNumber)');
}
// pick issuer
// Name ::= CHOICE { RDNSequence }
// RDNSequence ::= SEQUENCE OF RelativeDistinguishedName
if (ub[eaten] !== 0x30) {
throw new Error('Invalid certificate data (invalid issuer)');
}
var offsetAfterIssuer = skipField(ub, eaten);
if (offsetAfterIssuer > tbsOffsetLast) {
throw new Error('Invalid certificate data (insufficient tbsCertificate data: issuer)');
}
return [
// return entire issuer sequence
[].slice.call(ub, eaten, offsetAfterIssuer),
serialNumberDER,
];
}
export function certBinToCertificatesDER(bin) {
if (Array.isArray(bin)) {
// use all items, map with `certBinToCertificatesDER`, and concat all
return bin
.map(certBinToCertificatesDER)
.reduce(function (prev, cur) { return prev.concat(cur); }, []);
}
var ub = toUint8Array(bin);
var certsBin = pickCertificatesIfDERHasSignedData(ub, 0);
if (certsBin) {
// certificates
var _a = calculateDERLength(certsBin, 1), tempLength = _a[0], eaten = _a[1];
if (eaten + tempLength > certsBin.length) {
throw new Error('Invalid certificate data (invalid length for signedData.certificates)');
}
var offsetLast = eaten + tempLength;
var rawData = [];
for (var offset = eaten; offset < offsetLast;) {
// pick certificates
if (certsBin[offset] !== 0x30) {
throw new Error('Invalid certificate data (no signedData.certificates[*])');
}
var _b = calculateDERLength(certsBin, offset + 1), certLength = _b[0], tempOffset = _b[1];
if (tempOffset + certLength > certsBin.length) {
throw new Error('Invalid certificate data (invalid length for signedData.certificates[*])');
}
rawData.push(new RawDERObject(certsBin.subarray(offset, tempOffset + certLength)));
offset = tempOffset + certLength;
}
return rawData;
}
else {
return [new RawDERObject(ub)];
}
}

View File

@@ -0,0 +1,7 @@
import DERObject from './DERObject.js';
import ObjectIdentifier from './ObjectIdentifier.js';
export default class AlgorithmIdentifier implements DERObject {
algorithm: ObjectIdentifier;
constructor(algorithm: ObjectIdentifier);
toDER(): number[];
}

View File

@@ -0,0 +1,14 @@
import { makeDERSequence } from './derUtil.js';
var AlgorithmIdentifier = /** @class */ (function () {
function AlgorithmIdentifier(algorithm) {
this.algorithm = algorithm;
}
AlgorithmIdentifier.prototype.toDER = function () {
var r = this.algorithm.toDER();
return makeDERSequence(r.concat(
// parameters is not used now
[0x05, 0x00]));
};
return AlgorithmIdentifier;
}());
export default AlgorithmIdentifier;

View File

@@ -0,0 +1,8 @@
import DERObject from './DERObject.js';
import ObjectIdentifier from './ObjectIdentifier.js';
export default class Attribute implements DERObject {
attrType: ObjectIdentifier;
attrValues: DERObject[];
constructor(attrType: ObjectIdentifier, attrValues: DERObject[]);
toDER(): number[];
}

View File

@@ -0,0 +1,12 @@
import { makeDERSequence, arrayToDERSet } from './derUtil.js';
var Attribute = /** @class */ (function () {
function Attribute(attrType, attrValues) {
this.attrType = attrType;
this.attrValues = attrValues;
}
Attribute.prototype.toDER = function () {
return makeDERSequence(this.attrType.toDER().concat(arrayToDERSet(this.attrValues)));
};
return Attribute;
}());
export default Attribute;

View File

@@ -0,0 +1,4 @@
import ContentInfo from './ContentInfo.js';
import SignedData from './SignedData.js';
export default class CertificateDataRoot extends ContentInfo<SignedData> {
}

View File

@@ -0,0 +1,24 @@
var __extends = (this && this.__extends) || (function () {
var extendStatics = function (d, b) {
extendStatics = Object.setPrototypeOf ||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };
return extendStatics(d, b);
};
return function (d, b) {
if (typeof b !== "function" && b !== null)
throw new TypeError("Class extends value " + String(b) + " is not a constructor or null");
extendStatics(d, b);
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
})();
import ContentInfo from './ContentInfo.js';
var CertificateDataRoot = /** @class */ (function (_super) {
__extends(CertificateDataRoot, _super);
function CertificateDataRoot() {
return _super !== null && _super.apply(this, arguments) || this;
}
return CertificateDataRoot;
}(ContentInfo));
export default CertificateDataRoot;

View File

@@ -0,0 +1,8 @@
import DERObject from './DERObject.js';
import ObjectIdentifier from './ObjectIdentifier.js';
export default class ContentInfo<TContent extends DERObject = DERObject> implements DERObject {
contentType: ObjectIdentifier;
content: TContent;
constructor(contentType: ObjectIdentifier, content: TContent);
toDER(): number[];
}

View File

@@ -0,0 +1,15 @@
import { makeDERSequence, makeDERTaggedData } from './derUtil.js';
// abstract
var ContentInfo = /** @class */ (function () {
function ContentInfo(contentType, content) {
this.contentType = contentType;
this.content = content;
}
ContentInfo.prototype.toDER = function () {
return makeDERSequence(this.contentType
.toDER()
.concat(makeDERTaggedData(0, this.content.toDER())));
};
return ContentInfo;
}());
export default ContentInfo;

View File

@@ -0,0 +1,8 @@
export default interface DERObject {
toDER: () => number[];
}
export declare class RawDERObject implements DERObject {
data: number[] | Uint8Array;
constructor(data: number[] | Uint8Array);
toDER(): number[];
}

View File

@@ -0,0 +1,10 @@
var RawDERObject = /** @class */ (function () {
function RawDERObject(data) {
this.data = data;
}
RawDERObject.prototype.toDER = function () {
return [].slice.call(this.data);
};
return RawDERObject;
}());
export { RawDERObject };

View File

@@ -0,0 +1,8 @@
import AlgorithmIdentifier from './AlgorithmIdentifier.js';
import DERObject from './DERObject.js';
export default class DigestInfo implements DERObject {
digestAlgorithm: AlgorithmIdentifier;
digest: ArrayBuffer | ArrayBufferView;
constructor(digestAlgorithm: AlgorithmIdentifier, digest: ArrayBuffer | ArrayBufferView);
toDER(): number[];
}

View File

@@ -0,0 +1,23 @@
import { makeDERSequence, makeDEROctetString } from './derUtil.js';
var DigestInfo = /** @class */ (function () {
function DigestInfo(digestAlgorithm, digest) {
this.digestAlgorithm = digestAlgorithm;
this.digest = digest;
}
DigestInfo.prototype.toDER = function () {
var digest = this.digest;
var digestArray;
if ('buffer' in digest) {
digestArray = new Uint8Array(digest.buffer, digest.byteOffset, digest.byteLength);
}
else {
digestArray = new Uint8Array(digest);
}
var derData = this.digestAlgorithm
.toDER()
.concat(makeDEROctetString(digestArray));
return makeDERSequence(derData);
};
return DigestInfo;
}());
export default DigestInfo;

View File

@@ -0,0 +1,7 @@
import DERObject from './DERObject.js';
export default class IssuerAndSerialNumber implements DERObject {
issuer: DERObject;
serialNumber: DERObject;
constructor(issuer: DERObject, serialNumber: DERObject);
toDER(): number[];
}

View File

@@ -0,0 +1,12 @@
import { makeDERSequence } from './derUtil.js';
var IssuerAndSerialNumber = /** @class */ (function () {
function IssuerAndSerialNumber(issuer, serialNumber) {
this.issuer = issuer;
this.serialNumber = serialNumber;
}
IssuerAndSerialNumber.prototype.toDER = function () {
return makeDERSequence(this.issuer.toDER().concat(this.serialNumber.toDER()));
};
return IssuerAndSerialNumber;
}());
export default IssuerAndSerialNumber;

View File

@@ -0,0 +1,23 @@
import ObjectIdentifier from './ObjectIdentifier.js';
export declare const OID_SHA1_NO_SIGN: ObjectIdentifier;
export declare const OID_SHA256_NO_SIGN: ObjectIdentifier;
export declare const OID_SHA384_NO_SIGN: ObjectIdentifier;
export declare const OID_SHA512_NO_SIGN: ObjectIdentifier;
export declare const OID_SHA224_NO_SIGN: ObjectIdentifier;
export declare const OID_SHA512_224_NO_SIGN: ObjectIdentifier;
export declare const OID_SHA512_256_NO_SIGN: ObjectIdentifier;
export declare const OID_SHA3_224_NO_SIGN: ObjectIdentifier;
export declare const OID_SHA3_256_NO_SIGN: ObjectIdentifier;
export declare const OID_SHA3_384_NO_SIGN: ObjectIdentifier;
export declare const OID_SHA3_512_NO_SIGN: ObjectIdentifier;
export declare const OID_SHAKE128_NO_SIGN: ObjectIdentifier;
export declare const OID_SHAKE256_NO_SIGN: ObjectIdentifier;
export declare const OID_RSA: ObjectIdentifier;
export declare const OID_DSA: ObjectIdentifier;
export declare const OID_SIGNED_DATA: ObjectIdentifier;
export declare const OID_CONTENT_TYPE: ObjectIdentifier;
export declare const OID_MESSAGE_DIGEST: ObjectIdentifier;
export declare const OID_SPC_STATEMENT_TYPE_OBJID: ObjectIdentifier;
export declare const OID_SPC_SP_OPUS_INFO_OBJID: ObjectIdentifier;
export declare const OID_SPC_INDIVIDUAL_SP_KEY_PURPOSE_OBJID: ObjectIdentifier;
export declare const OID_RFC3161_COUNTER_SIGNATURE: ObjectIdentifier;

View File

@@ -0,0 +1,67 @@
import ObjectIdentifier from './ObjectIdentifier.js';
// 1.3.14.3.2.26
// prettier-ignore
export var OID_SHA1_NO_SIGN = new ObjectIdentifier([1, 3, 14, 3, 2, 26]);
// 2.16.840.1.101.3.4.2.1
// prettier-ignore
export var OID_SHA256_NO_SIGN = new ObjectIdentifier([2, 16, 840, 1, 101, 3, 4, 2, 1]);
// 2.16.840.1.101.3.4.2.2
// prettier-ignore
export var OID_SHA384_NO_SIGN = new ObjectIdentifier([2, 16, 840, 1, 101, 3, 4, 2, 2]);
// 2.16.840.1.101.3.4.2.3
// prettier-ignore
export var OID_SHA512_NO_SIGN = new ObjectIdentifier([2, 16, 840, 1, 101, 3, 4, 2, 3]);
// 2.16.840.1.101.3.4.2.4
// prettier-ignore
export var OID_SHA224_NO_SIGN = new ObjectIdentifier([2, 16, 840, 1, 101, 3, 4, 2, 4]);
// 2.16.840.1.101.3.4.2.5
// prettier-ignore
export var OID_SHA512_224_NO_SIGN = new ObjectIdentifier([2, 16, 840, 1, 101, 3, 4, 2, 5]);
// 2.16.840.1.101.3.4.2.6
// prettier-ignore
export var OID_SHA512_256_NO_SIGN = new ObjectIdentifier([2, 16, 840, 1, 101, 3, 4, 2, 6]);
// 2.16.840.1.101.3.4.2.7
// prettier-ignore
export var OID_SHA3_224_NO_SIGN = new ObjectIdentifier([2, 16, 840, 1, 101, 3, 4, 2, 7]);
// 2.16.840.1.101.3.4.2.8
// prettier-ignore
export var OID_SHA3_256_NO_SIGN = new ObjectIdentifier([2, 16, 840, 1, 101, 3, 4, 2, 8]);
// 2.16.840.1.101.3.4.2.9
// prettier-ignore
export var OID_SHA3_384_NO_SIGN = new ObjectIdentifier([2, 16, 840, 1, 101, 3, 4, 2, 9]);
// 2.16.840.1.101.3.4.2.10
// prettier-ignore
export var OID_SHA3_512_NO_SIGN = new ObjectIdentifier([2, 16, 840, 1, 101, 3, 4, 2, 10]);
// 2.16.840.1.101.3.4.2.11
// prettier-ignore
export var OID_SHAKE128_NO_SIGN = new ObjectIdentifier([2, 16, 840, 1, 101, 3, 4, 2, 11]);
// 2.16.840.1.101.3.4.2.12
// prettier-ignore
export var OID_SHAKE256_NO_SIGN = new ObjectIdentifier([2, 16, 840, 1, 101, 3, 4, 2, 12]);
// 1.2.840.113549.1.1.1
// prettier-ignore
export var OID_RSA = new ObjectIdentifier([1, 2, 840, 113549, 1, 1, 1]);
// 1.2.840.10040.4.1
// prettier-ignore
export var OID_DSA = new ObjectIdentifier([1, 2, 840, 10040, 4, 1]);
// 1.2.840.113549.1.7.2
// prettier-ignore
export var OID_SIGNED_DATA = new ObjectIdentifier([1, 2, 840, 113549, 1, 7, 2]);
// 1.2.840.113549.1.9.3
// prettier-ignore
export var OID_CONTENT_TYPE = new ObjectIdentifier([1, 2, 840, 113549, 1, 9, 3]);
// 1.2.840.113549.1.9.4
// prettier-ignore
export var OID_MESSAGE_DIGEST = new ObjectIdentifier([1, 2, 840, 113549, 1, 9, 4]);
// 1.3.6.1.4.1.311.2.1.11
// prettier-ignore
export var OID_SPC_STATEMENT_TYPE_OBJID = new ObjectIdentifier([1, 3, 6, 1, 4, 1, 311, 2, 1, 11]);
// 1.3.6.1.4.1.311.2.1.12
// prettier-ignore
export var OID_SPC_SP_OPUS_INFO_OBJID = new ObjectIdentifier([1, 3, 6, 1, 4, 1, 311, 2, 1, 12]);
// 1.3.6.1.4.1.311.2.1.21
// prettier-ignore
export var OID_SPC_INDIVIDUAL_SP_KEY_PURPOSE_OBJID = new ObjectIdentifier([1, 3, 6, 1, 4, 1, 311, 2, 1, 21]);
// 1.3.6.1.4.1.311.3.3.1
// prettier-ignore
export var OID_RFC3161_COUNTER_SIGNATURE = new ObjectIdentifier([1, 3, 6, 1, 4, 1, 311, 3, 3, 1]);

View File

@@ -0,0 +1,6 @@
import DERObject from './DERObject.js';
export default class ObjectIdentifier implements DERObject {
value: number[];
constructor(value: number[] | string);
toDER(): number[];
}

View File

@@ -0,0 +1,41 @@
import { makeDERLength } from './derUtil.js';
var ObjectIdentifier = /** @class */ (function () {
function ObjectIdentifier(value) {
if (typeof value === 'string') {
this.value = value.split(/\./g).map(function (s) { return Number(s); });
}
else {
this.value = value;
}
}
ObjectIdentifier.prototype.toDER = function () {
var id = this.value;
var r = [];
if (id.length < 2) {
throw new Error("Unexpected 'value' field");
}
// first byte will be (x * 40 + y) for 'x.y.****'
r.push(id[0] * 40 + id[1]);
for (var i = 2; i < id.length; ++i) {
// store as variable-length value
var val = id[i];
var isFirst = true;
var insertPos = r.length;
while (true) {
var v = val & 0x7f;
if (!isFirst) {
v += 0x80;
}
r.splice(insertPos, 0, v);
if (val < 0x80) {
break;
}
isFirst = false;
val = Math.floor(val / 0x80);
}
}
return [0x06].concat(makeDERLength(r.length)).concat(r);
};
return ObjectIdentifier;
}());
export default ObjectIdentifier;

View File

@@ -0,0 +1,13 @@
import DigestAlgorithmIdentifier from './AlgorithmIdentifier.js';
import ContentInfo from './ContentInfo.js';
import DERObject from './DERObject.js';
export default class SignedData implements DERObject {
version: number;
digestAlgorithms: DigestAlgorithmIdentifier[];
contentInfo: ContentInfo;
signerInfos: DERObject[];
certificates?: DERObject[] | undefined;
crls?: DERObject[] | undefined;
constructor(version: number, digestAlgorithms: DigestAlgorithmIdentifier[], contentInfo: ContentInfo, signerInfos: DERObject[], certificates?: DERObject[] | undefined, crls?: DERObject[] | undefined);
toDER(): number[];
}

View File

@@ -0,0 +1,29 @@
import { arrayToDERSet, makeDERSequence, makeDERTaggedData, } from './derUtil.js';
var SignedData = /** @class */ (function () {
function SignedData(version, digestAlgorithms, contentInfo, signerInfos, certificates, crls) {
this.version = version;
this.digestAlgorithms = digestAlgorithms;
this.contentInfo = contentInfo;
this.signerInfos = signerInfos;
this.certificates = certificates;
this.crls = crls;
}
SignedData.prototype.toDER = function () {
var r = [0x02, 0x01, this.version & 0xff]
.concat(arrayToDERSet(this.digestAlgorithms))
.concat(this.contentInfo.toDER());
if (this.certificates && this.certificates.length > 0) {
var allCertsDER = arrayToDERSet(this.certificates);
// IMPLICIT SET
allCertsDER[0] = 0xa0;
r = r.concat(allCertsDER);
}
if (this.crls) {
r = r.concat(makeDERTaggedData(1, arrayToDERSet(this.crls)));
}
r = r.concat(arrayToDERSet(this.signerInfos));
return makeDERSequence(r);
};
return SignedData;
}());
export default SignedData;

View File

@@ -0,0 +1,15 @@
import DERObject from './DERObject.js';
import IssuerAndSerialNumber from './IssuerAndSerialNumber.js';
import AlgorithmIdentifier from './AlgorithmIdentifier.js';
import Attribute from './Attribute.js';
export default class SignerInfo implements DERObject {
version: number;
issuerAndSerialNumber: IssuerAndSerialNumber;
digestAlgorithm: AlgorithmIdentifier;
digestEncryptionAlgorithm: AlgorithmIdentifier;
encryptedDigest: Uint8Array;
authenticatedAttributes?: Attribute[] | undefined;
unauthenticatedAttributes?: Attribute[] | undefined;
constructor(version: number, issuerAndSerialNumber: IssuerAndSerialNumber, digestAlgorithm: AlgorithmIdentifier, digestEncryptionAlgorithm: AlgorithmIdentifier, encryptedDigest: Uint8Array, authenticatedAttributes?: Attribute[] | undefined, unauthenticatedAttributes?: Attribute[] | undefined);
toDER(): number[];
}

View File

@@ -0,0 +1,37 @@
import { makeDERSequence, arrayToDERSet, makeDEROctetString, } from './derUtil.js';
var SignerInfo = /** @class */ (function () {
function SignerInfo(version, issuerAndSerialNumber, digestAlgorithm, digestEncryptionAlgorithm, encryptedDigest, authenticatedAttributes, unauthenticatedAttributes) {
this.version = version;
this.issuerAndSerialNumber = issuerAndSerialNumber;
this.digestAlgorithm = digestAlgorithm;
this.digestEncryptionAlgorithm = digestEncryptionAlgorithm;
this.encryptedDigest = encryptedDigest;
this.authenticatedAttributes = authenticatedAttributes;
this.unauthenticatedAttributes = unauthenticatedAttributes;
}
SignerInfo.prototype.toDER = function () {
var r = [0x02, 0x01, this.version & 0xff]
.concat(this.issuerAndSerialNumber.toDER())
.concat(this.digestAlgorithm.toDER());
if (this.authenticatedAttributes &&
this.authenticatedAttributes.length > 0) {
var a = arrayToDERSet(this.authenticatedAttributes);
// [0] IMPLICIT
a[0] = 0xa0;
r = r.concat(a);
}
r = r
.concat(this.digestEncryptionAlgorithm.toDER())
.concat(makeDEROctetString(this.encryptedDigest));
if (this.unauthenticatedAttributes &&
this.unauthenticatedAttributes.length > 0) {
var u = arrayToDERSet(this.unauthenticatedAttributes);
// [1] IMPLICIT
u[0] = 0xa1;
r = r.concat(u);
}
return makeDERSequence(r);
};
return SignerInfo;
}());
export default SignerInfo;

View File

@@ -0,0 +1,21 @@
import ContentInfo from './ContentInfo.js';
import DigestInfo from './DigestInfo.js';
import ObjectIdentifier from './ObjectIdentifier.js';
import DERObject from './DERObject.js';
export declare const SPC_INDIRECT_DATA_OBJID: ObjectIdentifier;
export declare class SpcAttributeTypeAndOptionalValue<TValue extends DERObject = DERObject> {
type: ObjectIdentifier;
value: TValue;
constructor(type: ObjectIdentifier, value: TValue);
toDER(): number[];
}
export default class SpcIndirectDataContent implements DERObject {
data: SpcAttributeTypeAndOptionalValue;
messageDigest: DigestInfo;
constructor(data: SpcAttributeTypeAndOptionalValue, messageDigest: DigestInfo);
toDER(): number[];
toDERWithoutHeader(): number[];
}
export declare class SpcIndirectDataContentInfo extends ContentInfo<SpcIndirectDataContent> {
constructor(content: SpcIndirectDataContent);
}

View File

@@ -0,0 +1,54 @@
var __extends = (this && this.__extends) || (function () {
var extendStatics = function (d, b) {
extendStatics = Object.setPrototypeOf ||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };
return extendStatics(d, b);
};
return function (d, b) {
if (typeof b !== "function" && b !== null)
throw new TypeError("Class extends value " + String(b) + " is not a constructor or null");
extendStatics(d, b);
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
})();
import ContentInfo from './ContentInfo.js';
import ObjectIdentifier from './ObjectIdentifier.js';
import { makeDERSequence } from './derUtil.js';
// prettier-ignore
export var SPC_INDIRECT_DATA_OBJID = new ObjectIdentifier([1, 3, 6, 1, 4, 1, 311, 2, 1, 4]);
var SpcAttributeTypeAndOptionalValue = /** @class */ (function () {
function SpcAttributeTypeAndOptionalValue(type, value) {
this.type = type;
this.value = value;
}
SpcAttributeTypeAndOptionalValue.prototype.toDER = function () {
return makeDERSequence(this.type.toDER().concat(this.value.toDER()));
};
return SpcAttributeTypeAndOptionalValue;
}());
export { SpcAttributeTypeAndOptionalValue };
var SpcIndirectDataContent = /** @class */ (function () {
function SpcIndirectDataContent(data, messageDigest) {
this.data = data;
this.messageDigest = messageDigest;
}
SpcIndirectDataContent.prototype.toDER = function () {
return makeDERSequence(this.toDERWithoutHeader());
};
// this is used for calculating 'messageDigest'
SpcIndirectDataContent.prototype.toDERWithoutHeader = function () {
return this.data.toDER().concat(this.messageDigest.toDER());
};
return SpcIndirectDataContent;
}());
export default SpcIndirectDataContent;
var SpcIndirectDataContentInfo = /** @class */ (function (_super) {
__extends(SpcIndirectDataContentInfo, _super);
function SpcIndirectDataContentInfo(content) {
return _super.call(this, SPC_INDIRECT_DATA_OBJID, content) || this;
}
return SpcIndirectDataContentInfo;
}(ContentInfo));
export { SpcIndirectDataContentInfo };

View File

@@ -0,0 +1,16 @@
import DERObject from './DERObject.js';
/**
* Abstract data SpcLink. Must use either `SpcLinkUrl` or `SpcLinkFile` instead.
*/
export default abstract class SpcLink implements DERObject {
private readonly tag;
value: DERObject;
constructor(tag: number, value: DERObject);
toDER(): number[];
}
export declare class SpcLinkUrl extends SpcLink {
constructor(url: string);
}
export declare class SpcLinkFile extends SpcLink {
constructor(file: string);
}

View File

@@ -0,0 +1,62 @@
var __extends = (this && this.__extends) || (function () {
var extendStatics = function (d, b) {
extendStatics = Object.setPrototypeOf ||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };
return extendStatics(d, b);
};
return function (d, b) {
if (typeof b !== "function" && b !== null)
throw new TypeError("Class extends value " + String(b) + " is not a constructor or null");
extendStatics(d, b);
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
})();
import { RawDERObject } from './DERObject.js';
import { makeDERTaggedData, makeDERIA5String, makeDERBMPString, } from './derUtil.js';
/**
* Abstract data SpcLink. Must use either `SpcLinkUrl` or `SpcLinkFile` instead.
*/
var SpcLink = /** @class */ (function () {
function SpcLink(tag, value) {
this.tag = tag;
this.value = value;
}
SpcLink.prototype.toDER = function () {
var v = this.value.toDER();
if (this.tag === 2) {
// EXPLICIT
return makeDERTaggedData(this.tag, v);
}
else {
// IMPLICIT
v[0] = 0x80 + this.tag;
return v;
}
};
return SpcLink;
}());
export default SpcLink;
var SpcLinkUrl = /** @class */ (function (_super) {
__extends(SpcLinkUrl, _super);
function SpcLinkUrl(url) {
return _super.call(this, 0, new RawDERObject(makeDERIA5String(url))) || this;
}
return SpcLinkUrl;
}(SpcLink));
export { SpcLinkUrl };
// moniker is not supported now (currently unused)
var SpcLinkFile = /** @class */ (function (_super) {
__extends(SpcLinkFile, _super);
function SpcLinkFile(file) {
var _this = this;
var v = makeDERBMPString(file);
// [0] IMPLICIT BMPSTRING
v[0] = 0x80;
_this = _super.call(this, 2, new RawDERObject(v)) || this;
return _this;
}
return SpcLinkFile;
}(SpcLink));
export { SpcLinkFile };

View File

@@ -0,0 +1,19 @@
import DERObject from './DERObject.js';
import ObjectIdentifier from './ObjectIdentifier.js';
import { SpcAttributeTypeAndOptionalValue } from './SpcIndirectDataContent.js';
import SpcLink from './SpcLink.js';
export declare const SPC_PE_IMAGE_DATA_OBJID: ObjectIdentifier;
export declare const enum SpcPeImageFlags {
IncludeResources = 0,
IncludeDebugInfo = 1,
IncludeImportAddressTable = 2
}
export default class SpcPeImageData implements DERObject {
flags: SpcPeImageFlags;
file: SpcLink;
constructor(flags: SpcPeImageFlags, file: SpcLink);
toDER(): number[];
}
export declare class SpcPeImageAttributeTypeAndOptionalValue extends SpcAttributeTypeAndOptionalValue<SpcPeImageData> {
constructor(value: SpcPeImageData);
}

View File

@@ -0,0 +1,41 @@
var __extends = (this && this.__extends) || (function () {
var extendStatics = function (d, b) {
extendStatics = Object.setPrototypeOf ||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };
return extendStatics(d, b);
};
return function (d, b) {
if (typeof b !== "function" && b !== null)
throw new TypeError("Class extends value " + String(b) + " is not a constructor or null");
extendStatics(d, b);
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
})();
import ObjectIdentifier from './ObjectIdentifier.js';
import { SpcAttributeTypeAndOptionalValue } from './SpcIndirectDataContent.js';
import { makeDERSequence, makeDERTaggedData } from './derUtil.js';
// prettier-ignore
export var SPC_PE_IMAGE_DATA_OBJID = new ObjectIdentifier([1, 3, 6, 1, 4, 1, 311, 2, 1, 15]);
var SpcPeImageData = /** @class */ (function () {
function SpcPeImageData(flags, file) {
this.flags = flags;
this.file = file;
}
SpcPeImageData.prototype.toDER = function () {
return makeDERSequence([0x03, 0x01, this.flags & 0xff].concat(
// undocumented -- SpcLink must be tagged
makeDERTaggedData(0, this.file.toDER())));
};
return SpcPeImageData;
}());
export default SpcPeImageData;
var SpcPeImageAttributeTypeAndOptionalValue = /** @class */ (function (_super) {
__extends(SpcPeImageAttributeTypeAndOptionalValue, _super);
function SpcPeImageAttributeTypeAndOptionalValue(value) {
return _super.call(this, SPC_PE_IMAGE_DATA_OBJID, value) || this;
}
return SpcPeImageAttributeTypeAndOptionalValue;
}(SpcAttributeTypeAndOptionalValue));
export { SpcPeImageAttributeTypeAndOptionalValue };

View File

@@ -0,0 +1,8 @@
import DERObject from './DERObject.js';
export declare function makeDERLength(length: number): number[];
export declare function makeDERIA5String(text: string): number[];
export declare function makeDERBMPString(text: string): number[];
export declare function makeDEROctetString(bin: number[] | Uint8Array): number[];
export declare function makeDERTaggedData(tag: number, body: number[]): number[];
export declare function makeDERSequence(body: number[]): number[];
export declare function arrayToDERSet(items: Array<DERObject | number[]>): number[];

View File

@@ -0,0 +1,56 @@
export function makeDERLength(length) {
if (length < 0x80) {
return [length];
}
var r = [];
while (true) {
r.push(length & 0xff);
if (length < 0x100) {
break;
}
length >>= 8;
}
r.push(0x80 + r.length);
return r.reverse();
}
export function makeDERIA5String(text) {
// convert to char-code array and filter to [0-127]
var r = [].map
.call(text, function (c) { return c.charCodeAt(0); })
.filter(function (n) { return n < 128; });
return [0x16].concat(makeDERLength(r.length)).concat(r);
}
export function makeDERBMPString(text) {
// convert to char-code array
// NOTE: In ECMAScript `charCodeAt` returns surrogate pair for >=0x10000 codes,
// and surrogate pair is valid for BMPString data
var r = [].map.call(text, function (c) { return c.charCodeAt(0); });
var ua = new Uint8Array(r.length * 2);
var dv = new DataView(ua.buffer);
// store codes as big-endian
r.forEach(function (v, i) {
dv.setUint16(i * 2, v, false);
});
return [0x1e].concat(makeDERLength(ua.length)).concat(
// convert Uint8Array to number[] (not using spread operator)
[].slice.call(ua));
}
export function makeDEROctetString(bin) {
if (!(bin instanceof Array)) {
// convert Uint8Array to number[] (not using spread operator)
bin = [].slice.call(bin);
}
return [0x04].concat(makeDERLength(bin.length)).concat(bin);
}
export function makeDERTaggedData(tag, body) {
return [0xa0 + tag].concat(makeDERLength(body.length)).concat(body);
}
export function makeDERSequence(body) {
return [0x30].concat(makeDERLength(body.length)).concat(body);
}
export function arrayToDERSet(items) {
var r = items.reduce(function (prev, item) {
return prev.concat(item instanceof Array ? item : item.toDER());
}, []);
return [0x31].concat(makeDERLength(r.length)).concat(r);
}

View File

@@ -0,0 +1,13 @@
import { NtExecutable } from 'pe-library';
import SignerObject, { DigestAlgorithmType, EncryptionAlgorithmType } from './SignerObject.js';
/**
* Generates the executable binary data with signed info.
* This function is like an extension of `generate` method of `NtExecutable`.
* @param executable a valid instance of `NtExecutable`
* @param signer user-defined `SignerObject` instance for signing
* @param alignment alignment value for placing certificate data
* (using `executable.getFileAlignment()` if omitted)
* @return Promise-like (Thenable) object which will resolve with generated executable binary
*/
export declare function generateExecutableWithSign(executable: NtExecutable, signer: SignerObject, alignment?: number): PromiseLike<ArrayBuffer>;
export { SignerObject, DigestAlgorithmType, EncryptionAlgorithmType };

View File

@@ -0,0 +1,396 @@
// refs.
// - Windows Authenticode Portable Executable Signature Format
// https://download.microsoft.com/download/9/c/5/9c5b2167-8017-4bae-9fde-d599bac8184a/authenticode_pe.docx
// - RFC 2315 - PKCS #7: Cryptographic Message Syntax Version 1.5
// https://tools.ietf.org/html/rfc2315
// - RFC 3280 - Internet X.509 Public Key Infrastructure Certificate and Certificate Revocation List (CRL) Profile
// https://tools.ietf.org/html/rfc3280
// - Object IDs associated with Microsoft cryptography
// https://support.microsoft.com/en-us/help/287547/object-ids-associated-with-microsoft-cryptography
// - OID repository
// http://oid-info.com/
// - RFC 3161 - Internet X.509 Public Key Infrastructure Time-Stamp Protocol (TSP)
// https://tools.ietf.org/html/rfc3161
// - mono/AuthenticodeDeformatter.cs
// https://github.com/mono/mono/blob/master/mcs/class/Mono.Security/Mono.Security.Authenticode/AuthenticodeDeformatter.cs
var __generator = (this && this.__generator) || function (thisArg, body) {
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
function verb(n) { return function (v) { return step([n, v]); }; }
function step(op) {
if (f) throw new TypeError("Generator is already executing.");
while (_) try {
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
if (y = 0, t) op = [op[0] & 2, t.value];
switch (op[0]) {
case 0: case 1: t = op; break;
case 4: _.label++; return { value: op[1], done: false };
case 5: _.label++; y = op[1]; op = [0]; continue;
case 7: op = _.ops.pop(); _.trys.pop(); continue;
default:
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
if (t[2]) _.ops.pop();
_.trys.pop(); continue;
}
op = body.call(thisArg, _);
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
}
};
import { Format, calculateCheckSumForPE } from 'pe-library';
import { allocatePartialBinary, cloneToArrayBuffer, copyBuffer, roundUp, } from '../util/functions.js';
import { certBinToCertificatesDER, pickIssuerAndSerialNumberDERFromCert, toUint8Array, } from './certUtil.js';
import AlgorithmIdentifier from './data/AlgorithmIdentifier.js';
import CertificateDataRoot from './data/CertificateDataRoot.js';
import { RawDERObject } from './data/DERObject.js';
import DigestInfo from './data/DigestInfo.js';
import IssuerAndSerialNumber from './data/IssuerAndSerialNumber.js';
import * as KnownOids from './data/KnownOids.js';
import SignedData from './data/SignedData.js';
import SignerInfo from './data/SignerInfo.js';
import SpcIndirectDataContent, { SpcIndirectDataContentInfo, SPC_INDIRECT_DATA_OBJID, } from './data/SpcIndirectDataContent.js';
import SpcPeImageData, { SpcPeImageAttributeTypeAndOptionalValue, } from './data/SpcPeImageData.js';
import { SpcLinkFile } from './data/SpcLink.js';
import Attribute from './data/Attribute.js';
import { arrayToDERSet, makeDEROctetString, makeDERSequence, } from './data/derUtil.js';
import ContentInfo from './data/ContentInfo.js';
import ObjectIdentifier from './data/ObjectIdentifier.js';
import { createTimestampRequest, pickSignedDataFromTimestampResponse, } from './timestamp.js';
function makeSimpleIterator(data) {
var done = false;
return {
next: function () {
if (done) {
return {
done: true,
value: undefined,
};
}
else {
done = true;
return {
done: false,
value: data,
};
}
},
};
}
function validateSignerObject(signer) {
if (!signer.encryptData && !signer.signData) {
throw new Error('Signer object must implement either `encryptData` or `signData`.');
}
}
function calculateExecutableDigest(executable, signer, alignment) {
function inner() {
var checkSumOffset, certificateTableOffset, rawHeader, targetSections, sectionCount, sectionStartOffset, sectionEndOffset, sectionHeadersSize, secHeader, secArray_1, off, _i, targetSections_1, section, exData, alignedLength, diff;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
checkSumOffset = executable.dosHeader.newHeaderAddress + 88;
certificateTableOffset = executable.dosHeader.newHeaderAddress +
executable.newHeader.getDataDirectoryOffset() +
Format.ImageDataDirectoryArray.itemSize *
Format.ImageDirectoryEntry.Certificate;
rawHeader = executable.getRawHeader();
targetSections = executable.getAllSections();
sectionCount = targetSections.length;
sectionStartOffset = rawHeader.byteLength;
sectionEndOffset = roundUp(sectionStartOffset +
sectionCount * Format.ImageSectionHeaderArray.itemSize, executable.getFileAlignment());
sectionHeadersSize = sectionEndOffset - sectionStartOffset;
secHeader = new ArrayBuffer(sectionHeadersSize);
{
secArray_1 = Format.ImageSectionHeaderArray.from(secHeader, sectionCount);
targetSections.forEach(function (sec, i) {
secArray_1.set(i, sec.info);
});
}
// pick from head to immediately before checksum
return [4 /*yield*/, allocatePartialBinary(rawHeader, 0, checkSumOffset)];
case 1:
// pick from head to immediately before checksum
_a.sent();
// pick from the end of checksum to immediately before 'Certificate Table' header
return [4 /*yield*/, allocatePartialBinary(rawHeader, checkSumOffset + 4, certificateTableOffset - (checkSumOffset + 4))];
case 2:
// pick from the end of checksum to immediately before 'Certificate Table' header
_a.sent();
off = certificateTableOffset +
Format.ImageDataDirectoryArray.itemSize;
return [4 /*yield*/, allocatePartialBinary(executable.getRawHeader(), off, executable.getTotalHeaderSize() - off)];
case 3:
_a.sent();
// pick section header
return [4 /*yield*/, secHeader];
case 4:
// pick section header
_a.sent();
_i = 0, targetSections_1 = targetSections;
_a.label = 5;
case 5:
if (!(_i < targetSections_1.length)) return [3 /*break*/, 8];
section = targetSections_1[_i];
if (!section.data) return [3 /*break*/, 7];
return [4 /*yield*/, section.data];
case 6:
_a.sent();
_a.label = 7;
case 7:
_i++;
return [3 /*break*/, 5];
case 8:
exData = executable.getExtraData();
if (!(exData !== null)) return [3 /*break*/, 11];
return [4 /*yield*/, exData];
case 9:
_a.sent();
alignedLength = roundUp(exData.byteLength, alignment);
diff = alignedLength - exData.byteLength;
if (!(diff !== 0)) return [3 /*break*/, 11];
return [4 /*yield*/, new Uint8Array(diff).buffer];
case 10:
_a.sent();
_a.label = 11;
case 11: return [2 /*return*/];
}
});
}
return signer.digestData(inner());
}
function getAlgorithmIdentifierObject(type) {
if (typeof type !== 'string') {
return new AlgorithmIdentifier(new ObjectIdentifier(type));
}
switch (type) {
case 'sha1':
case 'SHA1':
return new AlgorithmIdentifier(KnownOids.OID_SHA1_NO_SIGN);
case 'sha256':
case 'SHA256':
return new AlgorithmIdentifier(KnownOids.OID_SHA256_NO_SIGN);
case 'sha384':
case 'SHA384':
return new AlgorithmIdentifier(KnownOids.OID_SHA384_NO_SIGN);
case 'sha512':
case 'SHA512':
return new AlgorithmIdentifier(KnownOids.OID_SHA512_NO_SIGN);
case 'sha224':
case 'SHA224':
return new AlgorithmIdentifier(KnownOids.OID_SHA224_NO_SIGN);
case 'sha512-224':
case 'SHA512-224':
return new AlgorithmIdentifier(KnownOids.OID_SHA512_224_NO_SIGN);
case 'sha512-256':
case 'SHA512-256':
return new AlgorithmIdentifier(KnownOids.OID_SHA512_256_NO_SIGN);
case 'sha3-224':
case 'SHA3-224':
return new AlgorithmIdentifier(KnownOids.OID_SHA3_224_NO_SIGN);
case 'sha3-256':
case 'SHA3-256':
return new AlgorithmIdentifier(KnownOids.OID_SHA3_256_NO_SIGN);
case 'sha3-384':
case 'SHA3-384':
return new AlgorithmIdentifier(KnownOids.OID_SHA3_384_NO_SIGN);
case 'sha3-512':
case 'SHA3-512':
return new AlgorithmIdentifier(KnownOids.OID_SHA3_512_NO_SIGN);
case 'shake128':
case 'SHAKE128':
return new AlgorithmIdentifier(KnownOids.OID_SHAKE128_NO_SIGN);
case 'shake256':
case 'SHAKE256':
return new AlgorithmIdentifier(KnownOids.OID_SHAKE256_NO_SIGN);
default:
throw new Error('Invalid or unsupported digest algorithm');
}
}
function doSign(signer, digestAlgorithm, dataIterator) {
if (signer.signData) {
return signer.signData(dataIterator);
}
else {
return signer.digestData(dataIterator).then(function (digestAttributes) {
// encrypting DigestInfo with digest of 'attributes' set
var digestInfoBin = new Uint8Array(new DigestInfo(digestAlgorithm, digestAttributes).toDER()).buffer;
// (eencryptData should be defined here)
return signer.encryptData(makeSimpleIterator(digestInfoBin));
});
}
}
/**
* Generates the executable binary data with signed info.
* This function is like an extension of `generate` method of `NtExecutable`.
* @param executable a valid instance of `NtExecutable`
* @param signer user-defined `SignerObject` instance for signing
* @param alignment alignment value for placing certificate data
* (using `executable.getFileAlignment()` if omitted)
* @return Promise-like (Thenable) object which will resolve with generated executable binary
*/
export function generateExecutableWithSign(executable, signer, alignment) {
validateSignerObject(signer);
var certAlignment;
if (typeof alignment === 'number') {
if (alignment <= 0) {
throw new Error('Invalid alignment value');
}
certAlignment = alignment;
}
else {
certAlignment = executable.getFileAlignment();
}
var digestAlgorithm = getAlgorithmIdentifierObject(signer.getDigestAlgorithm());
var digestEncryptionAlgorithm;
var a = signer.getEncryptionAlgorithm();
if (typeof a !== 'string') {
digestEncryptionAlgorithm = new AlgorithmIdentifier(new ObjectIdentifier(a));
}
else {
switch (a) {
case 'rsa':
case 'RSA':
digestEncryptionAlgorithm = new AlgorithmIdentifier(KnownOids.OID_RSA);
break;
case 'dsa':
case 'DSA':
digestEncryptionAlgorithm = new AlgorithmIdentifier(KnownOids.OID_DSA);
break;
default:
throw new Error('Invalid or unsupported digest encryption algorithm');
}
}
// (for compatibility)
// eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
var cert = signer.getCertificateData
? signer.getCertificateData()
: signer.getPublicKeyData();
var _a = pickIssuerAndSerialNumberDERFromCert(cert), issuer = _a[0], serialNumber = _a[1];
return (
// calculate digest
calculateExecutableDigest(executable, signer, certAlignment)
// make content, content's digest, and sign
.then(function (digest) {
var content = new SpcIndirectDataContent(new SpcPeImageAttributeTypeAndOptionalValue(new SpcPeImageData(0 /* IncludeResources */, new SpcLinkFile(''))), new DigestInfo(digestAlgorithm, digest));
return (signer
.digestData(makeSimpleIterator(new Uint8Array(content.toDERWithoutHeader())
.buffer))
// make sign
.then(function (contentDigest) {
var attributes = [
new Attribute(KnownOids.OID_SPC_SP_OPUS_INFO_OBJID,
// (SpcSpOpusInfo) null sequence
[new RawDERObject([0x30, 0x00])]),
new Attribute(KnownOids.OID_CONTENT_TYPE, [
SPC_INDIRECT_DATA_OBJID,
]),
new Attribute(KnownOids.OID_SPC_STATEMENT_TYPE_OBJID, [
new RawDERObject(makeDERSequence(KnownOids.OID_SPC_INDIVIDUAL_SP_KEY_PURPOSE_OBJID.toDER())),
]),
new Attribute(KnownOids.OID_MESSAGE_DIGEST, [
new RawDERObject(makeDEROctetString(toUint8Array(contentDigest))),
]),
];
// get digest of 'attributes' set
var attrBin = new Uint8Array(arrayToDERSet(attributes)).buffer;
return doSign(signer, digestAlgorithm, makeSimpleIterator(attrBin)).then(function (signed) {
return [content, attributes, signed];
});
}));
})
// make cert bin
.then(function (_a) {
var content = _a[0], attributes = _a[1], signed = _a[2];
var signerInfo = new SignerInfo(
// version
1,
// issuerAndSerialNumber
new IssuerAndSerialNumber(new RawDERObject(issuer), new RawDERObject(serialNumber)),
// digestAlgorithm
digestAlgorithm,
// digestEncryptionAlgorithm
digestEncryptionAlgorithm,
// encryptedDigest
toUint8Array(signed),
// authenticatedAttributes
attributes);
if (!signer.timestampData) {
return [content, signerInfo];
}
// timestamp
return (signer
// make digest of encrypted data for make timestamp
.digestData(makeSimpleIterator(cloneToArrayBuffer(signed)))
.then(function (digestEncryptedBase) {
var digestEncrypted = createTimestampRequest(digestEncryptedBase, digestAlgorithm);
// request timestamp
return signer.timestampData(digestEncrypted).then(function (timestamp) {
// pick up signedData
var timestampSignedData = pickSignedDataFromTimestampResponse(timestamp);
// add timestamp to 'unauthenticatedAttributes'
signerInfo.unauthenticatedAttributes = [
new Attribute(KnownOids.OID_RFC3161_COUNTER_SIGNATURE, [
new ContentInfo(KnownOids.OID_SIGNED_DATA, new RawDERObject(toUint8Array(timestampSignedData))),
]),
];
return [content, signerInfo];
});
}));
})
.then(function (_a) {
var content = _a[0], signerInfo = _a[1];
// make certificate data
var root = new CertificateDataRoot(KnownOids.OID_SIGNED_DATA, new SignedData(
// version
1,
// digestAlgorithms
[digestAlgorithm],
// contentInfo
new SpcIndirectDataContentInfo(content),
// signerInfos
[signerInfo],
// certificates
certBinToCertificatesDER(cert)));
var certBin = new Uint8Array(root.toDER());
var resultBin = new ArrayBuffer(8 + certBin.length);
// make WIN_CERTIFICATE
var resultView = new DataView(resultBin);
// dwLength
resultView.setUint32(0, certBin.length + 8, true);
// wRevision : 0x0200 (revision 2)
resultView.setUint16(4, 0x200, true);
// wCertificateType : 0x0002
resultView.setUint16(6, 0x2, true);
copyBuffer(resultBin, 8, certBin, 0, certBin.byteLength);
return resultBin;
})
.then(function (certBin) {
var alignedSize = roundUp(certBin.byteLength, certAlignment);
// NOTE: The certificate data must follow the extra data.
// To achieve this, the another size between them must be added to the padding size.
// (The extra data may not be aligned, but the certificate data should be aligned.)
var paddingSize = alignedSize;
var exData = executable.getExtraData();
if (exData !== null) {
var diffSize = roundUp(exData.byteLength, certAlignment) -
exData.byteLength;
paddingSize += diffSize;
}
var newBin = executable.generate(paddingSize);
var certOffset = newBin.byteLength - alignedSize;
var dirArray = Format.ImageDataDirectoryArray.from(newBin, executable.dosHeader.newHeaderAddress +
executable.newHeader.getDataDirectoryOffset());
dirArray.set(Format.ImageDirectoryEntry.Certificate, {
size: alignedSize,
virtualAddress: certOffset,
});
// recalculate checksum
calculateCheckSumForPE(newBin, true);
// write Certificate section data
copyBuffer(newBin, certOffset, certBin, 0, certBin.byteLength);
return newBin;
}));
}

View File

@@ -0,0 +1,3 @@
import AlgorithmIdentifier from './data/AlgorithmIdentifier.js';
export declare function createTimestampRequest(data: ArrayBuffer | ArrayBufferView, algorithmIdentifier: AlgorithmIdentifier): ArrayBufferLike;
export declare function pickSignedDataFromTimestampResponse(data: ArrayBuffer | ArrayBufferView): ArrayBuffer;

View File

@@ -0,0 +1,117 @@
import { allocatePartialBinary } from '../util/functions.js';
import { calculateDERLength, toUint8Array } from './certUtil.js';
import { makeDEROctetString, makeDERSequence } from './data/derUtil.js';
import { OID_SIGNED_DATA } from './data/KnownOids.js';
export function createTimestampRequest(data, algorithmIdentifier) {
return new Uint8Array(makeDERSequence(
// version
[0x2, 0x1, 0x1]
// messageImprint
.concat(makeDERSequence(algorithmIdentifier
.toDER()
.concat(makeDEROctetString(toUint8Array(data)))))
// certReq
.concat([0x01, 0x01, 0xff]))).buffer;
}
export function pickSignedDataFromTimestampResponse(data) {
var _a, _b, _c, _d, _e, _f;
var ub = toUint8Array(data);
if (ub.length < 2 || ub[0] !== 0x30) {
throw new Error('Invalid or unexpected timestamp response');
}
var len;
var offset;
_a = calculateDERLength(ub, 1), len = _a[0], offset = _a[1];
if (len > ub.length - offset) {
throw new Error('Invalid or unexpected timestamp response (insufficient buffer)');
}
var dataLast = offset + len;
// status PKIStatusInfo
if (ub[offset] !== 0x30) {
throw new Error('Invalid or unexpected timestamp response (no PKIStatusInfo)');
}
_b = calculateDERLength(ub, offset + 1), len = _b[0], offset = _b[1];
if (offset >= dataLast) {
throw new Error('Invalid or unexpected timestamp response (invalid length for PKIStatusInfo)');
}
var timeStampTokenOffset = offset + len;
// PKIStatusInfo.status
if (ub[offset] !== 0x2 || ub[offset + 1] !== 0x1) {
throw new Error('Invalid or unexpected timestamp response (invalid PKIStatusInfo.status)');
}
var status = ub[offset + 2];
switch (status) {
case 0: // granted
case 1: // grantedWithMods
break;
case 2: // rejection
case 3: // waiting
case 4: // revocationWarning
case 5: /* revocationNotification */ {
var msg = "Timestamp response has error status " + status;
// PKIStatusInfo.statusString
if (offset + 3 < timeStampTokenOffset && ub[offset + 3] === 0x30) {
_c = calculateDERLength(ub, offset + 4), len = _c[0], offset = _c[1];
if (offset + len <= timeStampTokenOffset &&
ub[offset] === 0xc) {
_d = calculateDERLength(ub, offset + 1), len = _d[0], offset = _d[1];
if (offset + len <= timeStampTokenOffset) {
var statusString =
// pick UTF8String body
[].slice
.call(ub, offset, offset + len)
// map 0x20<=x<=0x7e values to chars, and other values to '%xx' to be parsed by decodeURIComponent
.map(function (val) {
if (val >= 0x20 && val <= 0x7e) {
return String.fromCharCode(val);
}
else {
var s = val.toString(16);
if (s.length === 1) {
s = '0' + s;
}
return '%' + s;
}
})
.join('');
msg += ', text = ' + decodeURIComponent(statusString);
}
}
}
throw new Error(msg);
}
default:
throw new Error("Unexpected PKIStatusInfo.status: " + (status !== null && status !== void 0 ? status : '(unknown)'));
}
// TimeStampToken ::= ContentInfo
if (timeStampTokenOffset + 1 >= dataLast ||
ub[timeStampTokenOffset] !== 0x30) {
throw new Error('Invalid or unexpected timestamp response (no TimeStampToken)');
}
_e = calculateDERLength(ub, timeStampTokenOffset + 1), len = _e[0], offset = _e[1];
if (offset + len > dataLast) {
throw new Error('Invalid or unexpected timestamp response (insufficient data for TimeStampToken)');
}
// ContentInfo.contentType
var signedDataOid = OID_SIGNED_DATA.toDER();
if (ub[offset] !== 0x6) {
throw new Error('Invalid or unexpected timestamp response (no contentType in TimeStampToken)');
}
for (var i = 0; i < signedDataOid.length; ++i) {
if (ub[offset + i] !== signedDataOid[i]) {
throw new Error('Invalid or unexpected timestamp response (unexpected TimeStampToken.contentType octet)');
}
}
// ContentInfo.content
offset += signedDataOid.length;
// [0] IMPLICIT
if (ub[offset] !== 0xa0) {
throw new Error('Invalid or unexpected timestamp response (no content in TimeStampToken)');
}
_f = calculateDERLength(ub, offset + 1), len = _f[0], offset = _f[1];
if (offset + len > dataLast) {
throw new Error('Invalid or unexpected timestamp response (invalid length for TimeStampToken.content)');
}
// return content data (=== SignedData)
return allocatePartialBinary(ub, offset, len);
}

View File

@@ -0,0 +1,16 @@
/// <reference lib="dom" />
export declare function cloneObject<T extends object>(object: Readonly<T>): T;
export declare function cloneObject<T extends object>(object: T): T;
export declare function createDataView(bin: ArrayBuffer | ArrayBufferView, byteOffset?: number, byteLength?: number): DataView;
export declare function roundUp(val: number, align: number): number;
export declare function copyBuffer(dest: ArrayBuffer | ArrayBufferView, destOffset: number, src: ArrayBuffer | ArrayBufferView, srcOffset: number, length: number): void;
export declare function allocatePartialBinary(binBase: ArrayBuffer | ArrayBufferView, offset: number, length: number): ArrayBuffer;
export declare function cloneToArrayBuffer(binBase: ArrayBuffer | ArrayBufferView): ArrayBuffer;
export declare function readInt32WithLastOffset(view: DataView, offset: number, last: number): number;
export declare function readUint8WithLastOffset(view: DataView, offset: number, last: number): number;
export declare function readUint16WithLastOffset(view: DataView, offset: number, last: number): number;
export declare function readUint32WithLastOffset(view: DataView, offset: number, last: number): number;
export declare function binaryToString(bin: ArrayBuffer | ArrayBufferView): string;
export declare function stringToBinary(string: string): ArrayBuffer;
export declare function getFixedString(view: DataView, offset: number, length: number): string;
export declare function setFixedString(view: DataView, offset: number, length: number, text: string): void;

View File

@@ -0,0 +1,235 @@
// eslint-disable-next-line @typescript-eslint/triple-slash-reference
/// <reference lib='dom' />
export function cloneObject(object) {
var r = {};
Object.keys(object).forEach(function (key) {
r[key] = object[key];
});
return r;
}
/* eslint-enable @typescript-eslint/ban-types */
export function createDataView(bin, byteOffset, byteLength) {
if ('buffer' in bin) {
var newOffset = bin.byteOffset;
var newLength = bin.byteLength;
if (typeof byteOffset !== 'undefined') {
newOffset += byteOffset;
newLength -= byteOffset;
}
if (typeof byteLength !== 'undefined') {
newLength = byteLength;
}
return new DataView(bin.buffer, newOffset, newLength);
}
else {
return new DataView(bin, byteOffset, byteLength);
}
}
export function roundUp(val, align) {
return Math.floor((val + align - 1) / align) * align;
}
export function copyBuffer(dest, destOffset, src, srcOffset, length) {
var ua8Dest = 'buffer' in dest
? new Uint8Array(dest.buffer, dest.byteOffset + (destOffset || 0), length)
: new Uint8Array(dest, destOffset, length);
var ua8Src = 'buffer' in src
? new Uint8Array(src.buffer, src.byteOffset + (srcOffset || 0), length)
: new Uint8Array(src, srcOffset, length);
ua8Dest.set(ua8Src);
}
export function allocatePartialBinary(binBase, offset, length) {
var b = new ArrayBuffer(length);
copyBuffer(b, 0, binBase, offset, length);
return b;
}
export function cloneToArrayBuffer(binBase) {
if ('buffer' in binBase) {
var b = new ArrayBuffer(binBase.byteLength);
new Uint8Array(b).set(new Uint8Array(binBase.buffer, binBase.byteOffset, binBase.byteLength));
return b;
}
else {
var b = new ArrayBuffer(binBase.byteLength);
new Uint8Array(b).set(new Uint8Array(binBase));
return b;
}
}
export function readInt32WithLastOffset(view, offset, last) {
return offset + 4 <= last ? view.getInt32(offset, true) : 0;
}
export function readUint8WithLastOffset(view, offset, last) {
return offset < last ? view.getUint8(offset) : 0;
}
export function readUint16WithLastOffset(view, offset, last) {
return offset + 2 <= last ? view.getUint16(offset, true) : 0;
}
export function readUint32WithLastOffset(view, offset, last) {
return offset + 4 <= last ? view.getUint32(offset, true) : 0;
}
export function binaryToString(bin) {
if (typeof TextDecoder !== 'undefined') {
var dec = new TextDecoder();
return dec.decode(bin);
}
else if (typeof Buffer !== 'undefined') {
var b = void 0;
if ('buffer' in bin) {
b = Buffer.from(bin.buffer, bin.byteOffset, bin.byteLength);
}
else {
b = Buffer.from(bin);
}
return b.toString('utf8');
}
else {
var view = void 0;
if ('buffer' in bin) {
view = new Uint8Array(bin.buffer, bin.byteOffset, bin.byteLength);
}
else {
view = new Uint8Array(bin);
}
if (typeof decodeURIComponent !== 'undefined') {
var s = '';
for (var i = 0; i < view.length; ++i) {
var c = view[i];
if (c < 16) {
s += '%0' + c.toString(16);
}
else {
s += '%' + c.toString(16);
}
}
return decodeURIComponent(s);
}
else {
var s = '';
for (var i = 0; i < view.length; ++i) {
var c = view[i];
s += String.fromCharCode(c);
}
return s;
}
}
}
export function stringToBinary(string) {
if (typeof TextEncoder !== 'undefined') {
var enc = new TextEncoder();
return cloneToArrayBuffer(enc.encode(string));
}
else if (typeof Buffer !== 'undefined') {
return cloneToArrayBuffer(Buffer.from(string, 'utf8'));
}
else if (typeof encodeURIComponent !== 'undefined') {
var data = encodeURIComponent(string);
var len = 0;
for (var i = 0; i < data.length; ++len) {
var c = data.charCodeAt(i);
if (c === 37) {
i += 3;
}
else {
++i;
}
}
var bin = new ArrayBuffer(len);
var view = new Uint8Array(bin);
for (var i = 0, j = 0; i < data.length; ++j) {
var c = data.charCodeAt(i);
if (c === 37) {
var n = parseInt(data.substring(i + 1, i + 3), 16);
view[j] = n;
i += 3;
}
else {
view[j] = c;
++i;
}
}
return bin;
}
else {
var bin = new ArrayBuffer(string.length);
new Uint8Array(bin).set([].map.call(string, function (c) {
return c.charCodeAt(0);
}));
return bin;
}
}
export function getFixedString(view, offset, length) {
var actualLen = 0;
for (var i = 0; i < length; ++i) {
if (view.getUint8(offset + i) === 0) {
break;
}
++actualLen;
}
if (typeof Buffer !== 'undefined') {
return Buffer.from(view.buffer, view.byteOffset + offset, actualLen).toString('utf8');
}
else if (typeof decodeURIComponent !== 'undefined') {
var s = '';
for (var i = 0; i < actualLen; ++i) {
var c = view.getUint8(offset + i);
if (c < 16) {
s += '%0' + c.toString(16);
}
else {
s += '%' + c.toString(16);
}
}
return decodeURIComponent(s);
}
else {
var s = '';
for (var i = 0; i < actualLen; ++i) {
var c = view.getUint8(offset + i);
s += String.fromCharCode(c);
}
return s;
}
}
export function setFixedString(view, offset, length, text) {
if (typeof Buffer !== 'undefined') {
var u = new Uint8Array(view.buffer, view.byteOffset + offset, length);
// fill by zero
u.set(new Uint8Array(length));
u.set(Buffer.from(text, 'utf8').subarray(0, length));
}
else if (typeof encodeURIComponent !== 'undefined') {
var s = encodeURIComponent(text);
for (var i = 0, j = 0; i < length; ++i) {
if (j >= s.length) {
view.setUint8(i + offset, 0);
}
else {
var c = s.charCodeAt(j);
if (c === 37) {
// '%'
var n = parseInt(s.substr(j + 1, 2), 16);
if (typeof n === 'number' && !isNaN(n)) {
view.setUint8(i + offset, n);
}
else {
view.setUint8(i + offset, 0);
}
j += 3;
}
else {
view.setUint8(i + offset, c);
}
}
}
}
else {
for (var i = 0, j = 0; i < length; ++i) {
if (j >= text.length) {
view.setUint8(i + offset, 0);
}
else {
var c = text.charCodeAt(j);
view.setUint8(i + offset, c & 0xff);
}
}
}
}

View File

@@ -0,0 +1,2 @@
declare const _default: "1.7.2";
export default _default;

View File

@@ -0,0 +1 @@
export default '1.7.2';

View File

@@ -0,0 +1,17 @@
export default interface BitmapInfo {
width: number;
height: number;
planes: number;
bitCount: number;
compression: number;
sizeImage: number;
xPelsPerMeter: number;
yPelsPerMeter: number;
colorUsed: number;
colorImportant: number;
colors: Array<{
r: number;
g: number;
b: number;
}>;
}

View File

@@ -0,0 +1,2 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });

View File

@@ -0,0 +1,21 @@
import IconItem from './IconItem.js';
import RawIconItem from './RawIconItem.js';
/**
* All fields except for 'data' is optional.
* Missing fields are replaced by 'data' values when generating binary.
*/
export interface IconFileItem {
width?: number;
height?: number;
colors?: number;
planes?: number;
bitCount?: number;
data: IconItem | RawIconItem;
}
export default class IconFile {
/** Containing icons */
icons: IconFileItem[];
constructor();
static from(bin: ArrayBuffer | ArrayBufferView): IconFile;
generate(): ArrayBuffer;
}

View File

@@ -0,0 +1,143 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var IconItem_js_1 = require("./IconItem.js");
var RawIconItem_js_1 = require("./RawIconItem.js");
var functions_js_1 = require("../util/functions.js");
function generateEntryBinary(icons) {
var count = icons.length;
/* istanbul ignore if */
if (count > 65535) {
count = 65535;
}
var tmpIcons = icons.map(function (item) {
if (item.data.isIcon()) {
return {
item: item,
bin: item.data.generate(),
offset: 0,
};
}
else {
return {
item: item,
bin: item.data.bin,
offset: 0,
};
}
});
var size = tmpIcons.reduce(function (p, icon) {
icon.offset = p;
return p + icon.bin.byteLength;
}, 6 + 16 * count);
var bin = new ArrayBuffer(size);
var view = new DataView(bin);
view.setUint16(0, 0, true); // reserved
view.setUint16(2, 1, true); // icon type
view.setUint16(4, count, true);
var offset = 6;
tmpIcons.forEach(function (icon) {
var item = icon.item;
var width;
var height;
var colors;
var planes;
var bitCount;
if (item.data.isIcon()) {
var bi = item.data.bitmapInfo;
width =
typeof item.width !== 'undefined'
? item.width
: Math.abs(bi.width);
height =
typeof item.height !== 'undefined'
? item.height
: Math.abs(bi.height / 2);
colors =
typeof item.colors !== 'undefined'
? item.colors
: bi.colorUsed || bi.colors.length;
planes =
typeof item.planes !== 'undefined' ? item.planes : bi.planes;
bitCount =
typeof item.bitCount !== 'undefined'
? item.bitCount
: bi.bitCount;
}
else {
width =
typeof item.width !== 'undefined'
? item.width
: Math.abs(item.data.width);
height =
typeof item.height !== 'undefined'
? item.height
: Math.abs(item.data.height);
colors = typeof item.colors !== 'undefined' ? item.colors : 0;
planes = typeof item.planes !== 'undefined' ? item.planes : 1;
bitCount =
typeof item.bitCount !== 'undefined'
? item.bitCount
: item.data.bitCount;
}
var dataSize = icon.bin.byteLength;
view.setUint8(offset, width >= 256 ? 0 : width);
view.setUint8(offset + 1, height >= 256 ? 0 : height);
view.setUint8(offset + 2, colors >= 256 ? 0 : colors);
view.setUint8(offset + 3, 0);
view.setUint16(offset + 4, planes, true);
view.setUint16(offset + 6, bitCount, true);
view.setUint32(offset + 8, dataSize, true);
view.setUint32(offset + 12, icon.offset, true);
offset += 16;
functions_js_1.copyBuffer(bin, icon.offset, icon.bin, 0, dataSize);
});
return bin;
}
var IconFile = /** @class */ (function () {
function IconFile(bin) {
if (!bin) {
this.icons = [];
return;
}
var view = functions_js_1.createDataView(bin);
var totalSize = view.byteLength;
var icons = [];
/* istanbul ignore else */
if (view.getUint16(2, true) === 1) {
var count = view.getUint16(4, true);
var offset = 6;
for (var i = 0; i < count; ++i) {
var dataSize = functions_js_1.readUint32WithLastOffset(view, offset + 8, totalSize);
var dataOffset = functions_js_1.readUint32WithLastOffset(view, offset + 12, totalSize);
var width = functions_js_1.readUint8WithLastOffset(view, offset, totalSize);
var height = functions_js_1.readUint8WithLastOffset(view, offset + 1, totalSize);
var bitCount = functions_js_1.readUint8WithLastOffset(view, offset + 6, totalSize);
var data = void 0;
if (view.getUint32(dataOffset, true) === 0x28) {
data = IconItem_js_1.default.from(width, height, bin, dataOffset, dataSize);
}
else {
data = RawIconItem_js_1.default.from(bin, width || 256, height || 256, bitCount, dataOffset, dataSize);
}
icons.push({
width: width,
height: height,
colors: functions_js_1.readUint8WithLastOffset(view, offset + 2, totalSize),
planes: functions_js_1.readUint16WithLastOffset(view, offset + 4, totalSize),
bitCount: bitCount,
data: data,
});
offset += 16;
}
}
this.icons = icons;
}
IconFile.from = function (bin) {
return new IconFile(bin);
};
IconFile.prototype.generate = function () {
return generateEntryBinary(this.icons);
};
return IconFile;
}());
exports.default = IconFile;

View File

@@ -0,0 +1,58 @@
import BitmapInfo from './BitmapInfo.js';
export default class IconItem {
/**
* Bitmap header data (`BITMAPINFOHEADER`)
*/
readonly bitmapInfo: BitmapInfo;
/**
* Horizontal size of the icon in pixel (overrides `bitmapInfo.width`).
* If `null` is specified, `bitmapInfo.width` will be used.
*/
width: number | null;
/**
* Vertical size of the icon in pixel (overrides `bitmapInfo.height`).
* If `null` is specified, `bitmapInfo.height` will be used.
*/
height: number | null;
/**
* Bitmap pixel data used for mask
* (the data will be appended immediately after `pixels` when generating icon binary)
*/
masks: ArrayBuffer;
/**
* Bitmap pixel data
*/
private _pixels;
private constructor();
/**
* Bitmap pixel data.
* @note
* On set, if `bitmapInfo.sizeImage` is non-zero, `bitmapInfo.sizeImage` will be updated.
*/
get pixels(): ArrayBuffer;
/**
* Bitmap pixel data.
* @note
* On set, if `bitmapInfo.sizeImage` is non-zero, `bitmapInfo.sizeImage` will be updated.
*/
set pixels(newValue: ArrayBuffer);
/**
* Generates `IconItem` instance from bitmap data binary.
* @param bin binary data containing the bitmap data
* @param byteOffset byte offset of `bin` referring the bitmap data
* @param byteLength available byte length for `bin` (from the offset `byteOffset`)
*/
static from(bin: ArrayBuffer | ArrayBufferView, byteOffset?: number, byteLength?: number): IconItem;
/**
* Generates `IconItem` instance from bitmap data binary width actual icon size (width and height).
* @param width icon width
* @param height icon height
* @param bin binary data containing the bitmap data
* @param byteOffset byte offset of `bin` referring the bitmap data
* @param byteLength available byte length for `bin` (from the offset `byteOffset`)
*/
static from(width: number, height: number, bin: ArrayBuffer | ArrayBufferView, byteOffset?: number, byteLength?: number): IconItem;
isIcon(): this is IconItem;
isRaw(): false;
generate(): ArrayBuffer;
}

View File

@@ -0,0 +1,166 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var functions_js_1 = require("../util/functions.js");
function calcMaskSize(width, height) {
// round up to 4 bytes (32 bit)
// (mask pixels is 1-bit bitmap)
var actualWidthBytes = functions_js_1.roundUp(Math.abs(width), 32) / 8;
return actualWidthBytes * Math.abs(height);
}
var IconItem = /** @class */ (function () {
function IconItem(width, height, bin, byteOffset, byteLength) {
var view = functions_js_1.createDataView(bin, byteOffset, byteLength);
var totalSize = view.byteLength;
var headerSize = view.getUint32(0, true);
if (headerSize > totalSize) {
headerSize = totalSize;
}
var sizeImage = functions_js_1.readUint32WithLastOffset(view, 20, headerSize);
var bi = {
width: functions_js_1.readInt32WithLastOffset(view, 4, headerSize),
height: functions_js_1.readInt32WithLastOffset(view, 8, headerSize),
planes: functions_js_1.readUint16WithLastOffset(view, 12, headerSize),
bitCount: functions_js_1.readUint16WithLastOffset(view, 14, headerSize),
compression: functions_js_1.readUint32WithLastOffset(view, 16, headerSize),
sizeImage: sizeImage,
xPelsPerMeter: functions_js_1.readInt32WithLastOffset(view, 24, headerSize),
yPelsPerMeter: functions_js_1.readInt32WithLastOffset(view, 28, headerSize),
colorUsed: functions_js_1.readUint32WithLastOffset(view, 32, headerSize),
colorImportant: functions_js_1.readUint32WithLastOffset(view, 36, headerSize),
colors: [],
};
var offset = 40;
var colors = bi.colorUsed;
if (!colors) {
switch (bi.bitCount) {
case 1:
colors = 2;
break;
case 4:
colors = 16;
break;
case 8:
colors = 256;
break;
}
}
for (var i = 0; i < colors; ++i) {
bi.colors.push({
b: functions_js_1.readUint8WithLastOffset(view, offset, totalSize),
g: functions_js_1.readUint8WithLastOffset(view, offset + 1, totalSize),
r: functions_js_1.readUint8WithLastOffset(view, offset + 2, totalSize),
});
offset += 4;
}
this.width = width;
this.height = height;
this.bitmapInfo = bi;
// round up to 4 bytes (32 bit)
var widthBytes = functions_js_1.roundUp(bi.bitCount * Math.abs(bi.width), 32) / 8;
var absActualHeight = Math.abs(bi.height) / 2;
// sizeImage may be weird if compression is 0 (BI_RGB), so
// we calculate actual bitmap size from width and height
var size = bi.compression !== 0 && sizeImage !== 0
? sizeImage
: widthBytes * absActualHeight;
if (size + offset > totalSize) {
throw new Error("Unexpected bitmap data in icon: bitmap size " + size + " is larger than " + totalSize + " - " + offset);
}
this._pixels = functions_js_1.allocatePartialBinary(view, offset, size);
offset += size;
var maskSize = calcMaskSize(bi.width, absActualHeight);
if (maskSize + offset <= totalSize) {
this.masks = functions_js_1.allocatePartialBinary(view, offset, maskSize);
}
else {
// create a zero buffer (no mask is not allowed)
this.masks = new ArrayBuffer(maskSize);
}
}
Object.defineProperty(IconItem.prototype, "pixels", {
/**
* Bitmap pixel data.
* @note
* On set, if `bitmapInfo.sizeImage` is non-zero, `bitmapInfo.sizeImage` will be updated.
*/
get: function () {
return this._pixels;
},
/**
* Bitmap pixel data.
* @note
* On set, if `bitmapInfo.sizeImage` is non-zero, `bitmapInfo.sizeImage` will be updated.
*/
set: function (newValue) {
this._pixels = newValue;
if (this.bitmapInfo.sizeImage !== 0) {
this.bitmapInfo.sizeImage = newValue.byteLength;
}
},
enumerable: false,
configurable: true
});
IconItem.from = function (arg1, arg2, arg3, byteOffset, byteLength) {
var width;
var height;
var bin;
if (typeof arg3 === 'object') {
// second overload
width = arg1;
height = arg2;
bin = arg3;
}
else {
// first overload
width = null;
height = null;
bin = arg1;
byteOffset = arg2;
byteLength = arg3;
}
return new IconItem(width, height, bin, byteOffset, byteLength);
};
IconItem.prototype.isIcon = function () {
return true;
};
IconItem.prototype.isRaw = function () {
return false;
};
IconItem.prototype.generate = function () {
var bi = this.bitmapInfo;
var absWidth = Math.abs(bi.width);
// round up to 4 bytes (32 bit)
var absWidthBytes = functions_js_1.roundUp(bi.bitCount * absWidth, 32) / 8;
var absActualHeight = Math.abs(bi.height) / 2;
var actualSizeImage = absWidthBytes * absActualHeight;
var sizeMask = calcMaskSize(bi.width, absActualHeight);
var colorCount = bi.colors.length;
var totalSize = 40 + 4 * colorCount + actualSizeImage + sizeMask;
var bin = new ArrayBuffer(totalSize);
var view = new DataView(bin);
view.setUint32(0, 40, true);
view.setInt32(4, bi.width, true);
view.setInt32(8, bi.height, true);
view.setUint16(12, bi.planes, true);
view.setUint16(14, bi.bitCount, true);
view.setUint32(16, bi.compression, true);
// image size
view.setUint32(20, bi.sizeImage, true);
view.setInt32(24, bi.xPelsPerMeter, true);
view.setInt32(28, bi.yPelsPerMeter, true);
view.setUint32(32, bi.colorUsed, true);
view.setUint32(36, bi.colorImportant > colorCount ? colorCount : bi.colorImportant, true);
var offset = 40;
bi.colors.forEach(function (c) {
view.setUint8(offset, c.b);
view.setUint8(offset + 1, c.g);
view.setUint8(offset + 2, c.r);
offset += 4;
});
functions_js_1.copyBuffer(bin, offset, this.pixels, 0, actualSizeImage);
functions_js_1.copyBuffer(bin, offset + actualSizeImage, this.masks, 0, sizeMask);
return bin;
};
return IconItem;
}());
exports.default = IconItem;

View File

@@ -0,0 +1,13 @@
/**
* Represents the raw-graphic icon item, such as PNG data.
*/
export default class RawIconItem {
width: number;
height: number;
bitCount: number;
bin: ArrayBuffer;
constructor(bin: ArrayBuffer | ArrayBufferView, width: number, height: number, bitCount: number, byteOffset?: number, byteLength?: number);
static from(bin: ArrayBuffer | ArrayBufferView, width: number, height: number, bitCount: number, byteOffset?: number, byteLength?: number): RawIconItem;
isIcon(): false;
isRaw(): this is RawIconItem;
}

View File

@@ -0,0 +1,32 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var functions_js_1 = require("../util/functions.js");
/**
* Represents the raw-graphic icon item, such as PNG data.
*/
var RawIconItem = /** @class */ (function () {
function RawIconItem(bin, width, height, bitCount, byteOffset, byteLength) {
this.width = width;
this.height = height;
this.bitCount = bitCount;
if (typeof byteOffset !== 'number') {
byteOffset = 0;
byteLength = bin.byteLength;
}
else if (typeof byteLength !== 'number') {
byteLength = bin.byteLength - byteOffset;
}
this.bin = functions_js_1.allocatePartialBinary(bin, byteOffset, byteLength);
}
RawIconItem.from = function (bin, width, height, bitCount, byteOffset, byteLength) {
return new RawIconItem(bin, width, height, bitCount, byteOffset, byteLength);
};
RawIconItem.prototype.isIcon = function () {
return false;
};
RawIconItem.prototype.isRaw = function () {
return true;
};
return RawIconItem;
}());
exports.default = RawIconItem;

View File

@@ -0,0 +1,5 @@
import BitmapInfo from './BitmapInfo.js';
import IconFile, { IconFileItem } from './IconFile.js';
import IconItem from './IconItem.js';
import RawIconItem from './RawIconItem.js';
export { BitmapInfo, IconFile, IconFileItem, IconItem, RawIconItem };

View File

@@ -0,0 +1,9 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.RawIconItem = exports.IconItem = exports.IconFile = void 0;
var IconFile_js_1 = require("./IconFile.js");
exports.IconFile = IconFile_js_1.default;
var IconItem_js_1 = require("./IconItem.js");
exports.IconItem = IconItem_js_1.default;
var RawIconItem_js_1 = require("./RawIconItem.js");
exports.RawIconItem = RawIconItem_js_1.default;

View File

@@ -0,0 +1,6 @@
import { NtExecutable, NtExecutableResource, Format } from 'pe-library';
import version from './version.js';
import * as Data from './data/index.js';
import * as Resource from './resource/index.js';
import { generateExecutableWithSign, SignerObject, DigestAlgorithmType, EncryptionAlgorithmType } from './sign/index.js';
export { NtExecutable, NtExecutableResource, version, Data, Format, Resource, generateExecutableWithSign, SignerObject, DigestAlgorithmType, EncryptionAlgorithmType, };

15
desktop-operator/node_modules/resedit/dist/index.js generated vendored Normal file
View File

@@ -0,0 +1,15 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.generateExecutableWithSign = exports.Resource = exports.Format = exports.Data = exports.version = exports.NtExecutableResource = exports.NtExecutable = void 0;
var pe_library_1 = require("pe-library");
Object.defineProperty(exports, "NtExecutable", { enumerable: true, get: function () { return pe_library_1.NtExecutable; } });
Object.defineProperty(exports, "NtExecutableResource", { enumerable: true, get: function () { return pe_library_1.NtExecutableResource; } });
Object.defineProperty(exports, "Format", { enumerable: true, get: function () { return pe_library_1.Format; } });
var version_js_1 = require("./version.js");
exports.version = version_js_1.default;
var Data = require("./data/index.js");
exports.Data = Data;
var Resource = require("./resource/index.js");
exports.Resource = Resource;
var index_js_1 = require("./sign/index.js");
Object.defineProperty(exports, "generateExecutableWithSign", { enumerable: true, get: function () { return index_js_1.generateExecutableWithSign; } });

21
desktop-operator/node_modules/resedit/dist/index.mjs generated vendored Normal file
View File

@@ -0,0 +1,21 @@
import { createRequire } from 'module';
const require = createRequire(import.meta.url);
const {
NtExecutable,
NtExecutableResource,
version,
Data,
Format,
Resource,
generateExecutableWithSign,
} = require('./index.js');
export {
NtExecutable,
NtExecutableResource,
version,
Data,
Format,
Resource,
generateExecutableWithSign,
};

View File

@@ -0,0 +1,45 @@
import { Type } from 'pe-library';
import IconItem from '../data/IconItem.js';
import RawIconItem from '../data/RawIconItem.js';
export interface IconGroupItem {
width: number;
height: number;
colors: number;
planes: number;
bitCount: number;
dataSize: number;
iconID: number;
}
/**
* A class that treats icon-group resource data (`RT_ICON_GROUP`).
* Note that this class does not treat `RT_ICON` data.
*
* - To pick all icons, use `IconGroupEntry.fromEntries`
* and `IconGroupEntry.prototype.getIconItemsFromEntries`.
* - The easiest way to add/replace icons is using `IconGroupEntry.replaceIconsForResource`,
* which treats both `RT_ICON_GROUP` and `RT_ICON` entries.
*/
export default class IconGroupEntry {
id: string | number;
lang: string | number;
readonly icons: IconGroupItem[];
private constructor();
static fromEntries(entries: readonly Type.ResourceEntry[]): IconGroupEntry[];
generateEntry(): Type.ResourceEntry;
/**
* Return an array of `IconItem` / `RawIconItem`, which are in the group of this `IconGroupEntry` instance,
* from specified resource entries.
*/
getIconItemsFromEntries(entries: readonly Type.ResourceEntry[]): Array<IconItem | RawIconItem>;
/**
* Add or replace icon resource entries with specified icon data.
* The IDs of individual icon resources (`RT_ICON`) are calculated automatically.
* @param destEntries base (destination) resource entries.
* @param iconGroupID the icon ID for the new resource data.
* If the icon-group resource of the ID and 'lang' value already exists,
* the resource data is replaced; otherwise the resource data is appended.
* @param lang the language for specified icons (0 for neutral, 0x409 for en-US)
* @param icons the icons to replace
*/
static replaceIconsForResource(destEntries: Type.ResourceEntry[], iconGroupID: string | number, lang: string | number, icons: Array<IconItem | RawIconItem>): void;
}

View File

@@ -0,0 +1,294 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var IconItem_js_1 = require("../data/IconItem.js");
var RawIconItem_js_1 = require("../data/RawIconItem.js");
var functions_js_1 = require("../util/functions.js");
function generateEntryBinary(icons) {
var count = icons.length;
if (count > 65535) {
count = 65535;
}
var size = 6 + 14 * icons.length;
var bin = new ArrayBuffer(size);
var view = new DataView(bin);
view.setUint16(0, 0, true); // reserved
view.setUint16(2, 1, true); // icon type
view.setUint16(4, count, true);
var offset = 6;
icons.forEach(function (icon) {
view.setUint8(offset, icon.width >= 256 ? 0 : icon.width);
view.setUint8(offset + 1, icon.height >= 256 ? 0 : icon.height);
view.setUint8(offset + 2, icon.colors >= 256 ? 0 : icon.colors);
view.setUint8(offset + 3, 0);
view.setUint16(offset + 4, icon.planes, true);
view.setUint16(offset + 6, icon.bitCount, true);
view.setUint32(offset + 8, icon.dataSize, true);
view.setUint16(offset + 12, icon.iconID, true);
offset += 14;
});
return bin;
}
function findUnusedIconID(entries, lang, isCursor) {
var type = isCursor ? 1 : 3;
// (ignore string id)
var filteredIDs = entries
.filter(function (e) { return e.type === type && e.lang === lang && typeof e.id === 'number'; })
.map(function (e) { return e.id; })
.sort(function (a, b) { return a - b; });
var idCurrent = 1;
for (var _i = 0, filteredIDs_1 = filteredIDs; _i < filteredIDs_1.length; _i++) {
var id = filteredIDs_1[_i];
if (idCurrent < id) {
return {
id: idCurrent,
last: false,
};
}
else if (idCurrent === id) {
++idCurrent;
}
}
return {
id: idCurrent,
last: true,
};
}
/**
* A class that treats icon-group resource data (`RT_ICON_GROUP`).
* Note that this class does not treat `RT_ICON` data.
*
* - To pick all icons, use `IconGroupEntry.fromEntries`
* and `IconGroupEntry.prototype.getIconItemsFromEntries`.
* - The easiest way to add/replace icons is using `IconGroupEntry.replaceIconsForResource`,
* which treats both `RT_ICON_GROUP` and `RT_ICON` entries.
*/
var IconGroupEntry = /** @class */ (function () {
function IconGroupEntry(groupEntry) {
var view = new DataView(groupEntry.bin);
var totalSize = view.byteLength;
var icons = [];
if (view.getUint16(2, true) === 1) {
var count = view.getUint16(4, true);
var offset = 6;
for (var i = 0; i < count; ++i) {
icons.push({
width: functions_js_1.readUint8WithLastOffset(view, offset, totalSize),
height: functions_js_1.readUint8WithLastOffset(view, offset + 1, totalSize),
colors: functions_js_1.readUint8WithLastOffset(view, offset + 2, totalSize),
planes: functions_js_1.readUint16WithLastOffset(view, offset + 4, totalSize),
bitCount: functions_js_1.readUint16WithLastOffset(view, offset + 6, totalSize),
dataSize: functions_js_1.readUint32WithLastOffset(view, offset + 8, totalSize),
iconID: functions_js_1.readUint16WithLastOffset(view, offset + 12, totalSize),
});
offset += 14; // 16 for .ico file, but 14 for resource data
}
}
this.id = groupEntry.id;
this.lang = groupEntry.lang;
this.icons = icons;
}
IconGroupEntry.fromEntries = function (entries) {
return entries
.filter(function (e) { return e.type === 14; })
.map(function (e) { return new IconGroupEntry(e); });
};
IconGroupEntry.prototype.generateEntry = function () {
var bin = generateEntryBinary(this.icons);
return {
type: 14,
id: this.id,
lang: this.lang,
codepage: 0,
bin: bin,
};
};
/**
* Return an array of `IconItem` / `RawIconItem`, which are in the group of this `IconGroupEntry` instance,
* from specified resource entries.
*/
IconGroupEntry.prototype.getIconItemsFromEntries = function (entries) {
var _this = this;
return entries
.map(function (e) {
if (e.type !== 3 || e.lang !== _this.lang) {
return null;
}
var c = _this.icons
.filter(function (icon) { return e.id === icon.iconID; })
.shift();
if (!c) {
return null;
}
return {
entry: e,
icon: c,
};
})
.filter(function (item) { return !!item; })
.map(function (item) {
var bin = item.entry.bin;
var view = new DataView(bin);
if (view.getUint32(0, true) === 0x28) {
return IconItem_js_1.default.from(bin);
}
else {
var c = item.icon;
return RawIconItem_js_1.default.from(bin, c.width, c.height, c.bitCount);
}
});
};
/**
* Add or replace icon resource entries with specified icon data.
* The IDs of individual icon resources (`RT_ICON`) are calculated automatically.
* @param destEntries base (destination) resource entries.
* @param iconGroupID the icon ID for the new resource data.
* If the icon-group resource of the ID and 'lang' value already exists,
* the resource data is replaced; otherwise the resource data is appended.
* @param lang the language for specified icons (0 for neutral, 0x409 for en-US)
* @param icons the icons to replace
*/
IconGroupEntry.replaceIconsForResource = function (destEntries, iconGroupID, lang, icons) {
// find existing entry
var entry = destEntries
.filter(function (e) { return e.type === 14 && e.id === iconGroupID && e.lang === lang; })
.shift();
var tmpIconArray = icons.map(function (icon) {
if (icon.isIcon()) {
var width = icon.width, height = icon.height;
if (width === null) {
width = icon.bitmapInfo.width;
}
if (height === null) {
height = icon.bitmapInfo.height;
// if mask is specified, the icon height must be the half of bitmap height
if (icon.masks !== null) {
height = Math.floor(height / 2);
}
}
return {
base: icon,
bm: {
width: width,
height: height,
planes: icon.bitmapInfo.planes,
bitCount: icon.bitmapInfo.bitCount,
},
bin: icon.generate(),
id: 0,
};
}
else {
return {
base: icon,
bm: {
width: icon.width,
height: icon.height,
planes: 1,
bitCount: icon.bitCount,
},
bin: icon.bin,
id: 0,
};
}
});
if (entry) {
// remove unused icon data
for (var i = destEntries.length - 1; i >= 0; --i) {
var e = destEntries[i];
if (e != null && e.type === 3) {
// RT_ICON
if (!isIconUsed(e, destEntries, entry)) {
destEntries.splice(i, 1);
}
}
}
}
else {
// create new entry
entry = {
type: 14,
id: iconGroupID,
lang: lang,
codepage: 0,
// set later
bin: null,
};
destEntries.push(entry);
}
// append icons
var idInfo;
tmpIconArray.forEach(function (icon) {
if (!(idInfo === null || idInfo === void 0 ? void 0 : idInfo.last)) {
idInfo = findUnusedIconID(destEntries, lang, false);
}
else {
++idInfo.id;
}
destEntries.push({
type: 3,
id: idInfo.id,
lang: lang,
codepage: 0,
bin: icon.bin,
});
// set 'id' field to use in generateEntryBinary
icon.id = idInfo.id;
});
var binEntry = generateEntryBinary(tmpIconArray.map(function (icon) {
var width = Math.abs(icon.bm.width);
if (width >= 256) {
width = 0;
}
var height = Math.abs(icon.bm.height);
if (height >= 256) {
height = 0;
}
var colors = 0;
if (icon.base.isIcon()) {
var bmBase = icon.base.bitmapInfo;
colors = bmBase.colorUsed || bmBase.colors.length;
if (!colors) {
switch (bmBase.bitCount) {
case 1:
colors = 2;
break;
case 4:
colors = 16;
break;
// case 8:
// colors = 256;
// break;
}
}
if (colors >= 256) {
colors = 0;
}
}
return {
width: width,
height: height,
colors: colors,
planes: icon.bm.planes,
bitCount: icon.bm.bitCount,
dataSize: icon.bin.byteLength,
iconID: icon.id,
};
}));
// rewrite entry
entry.bin = binEntry;
function isIconUsed(icon, allEntries, excludeGroup) {
return allEntries.some(function (e) {
if (e.type !== 14 ||
(e.id === excludeGroup.id && e.lang === excludeGroup.lang)) {
return false;
}
var g = new IconGroupEntry(e);
return g.icons.some(function (c) {
return c.iconID === icon.id;
});
});
}
};
return IconGroupEntry;
}());
exports.default = IconGroupEntry;

View File

@@ -0,0 +1,30 @@
import { NtExecutableResource, Type } from 'pe-library';
/** Utility class to create / parse String Table resource */
export default class StringTable {
/** Language value */
lang: string | number;
private items;
constructor();
/** Create StringTable instance from resource entries, with specified language. */
static fromEntries(lang: string | number, entries: readonly Type.ResourceEntry[]): StringTable;
/** Return all string entries. */
getAllStrings(): Array<{
id: number;
text: string;
}>;
/** Return the string data for ID value, which can be used for Win32API LoadString. */
getById(id: number): string | null;
/**
* Set/overwide the string data for ID value, which can be used for Win32API LoadString.
* @param id data ID
* @param text string data (entry will be removed if null or empty string is specified)
*/
setById(id: number, text: string | null): void;
/** Generates an array of Entry for resource processings */
generateEntries(): Type.ResourceEntry[];
/**
* Replace all string entries for NtExecutableResource with containing resource data.
* The only entries of same language are replaced.
*/
replaceStringEntriesForExecutable(res: NtExecutableResource): void;
}

View File

@@ -0,0 +1,132 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var StringTableItem_js_1 = require("./StringTableItem.js");
/** Utility class to create / parse String Table resource */
var StringTable = /** @class */ (function () {
function StringTable() {
this.lang = 0;
this.items = [];
}
/** Create StringTable instance from resource entries, with specified language. */
StringTable.fromEntries = function (lang, entries) {
var r = new StringTable();
entries.forEach(function (e) {
// 6: RT_STRING
if (e.type !== 6 ||
e.lang !== lang ||
typeof e.id !== 'number' ||
e.id <= 0) {
return;
}
r.items[e.id - 1] = StringTableItem_js_1.default.fromEntry(e.bin, 0, e.bin.byteLength);
});
r.lang = lang;
return r;
};
/** Return all string entries. */
StringTable.prototype.getAllStrings = function () {
return this.items
.map(function (e, i) {
return e
.getAll()
.map(function (x, j) {
return x !== null && x !== ''
? { id: (i << 4) + j, text: x }
: null;
})
.filter(function (x) { return !!x; });
})
.reduce(function (p, c) { return p.concat(c); }, []);
};
/** Return the string data for ID value, which can be used for Win32API LoadString. */
StringTable.prototype.getById = function (id) {
var _a;
if (id < 0) {
return null;
}
var entryIndex = id >> 4;
var entryPos = id & 15;
var e = this.items[entryIndex];
return (_a = e === null || e === void 0 ? void 0 : e.get(entryPos)) !== null && _a !== void 0 ? _a : null;
};
/**
* Set/overwide the string data for ID value, which can be used for Win32API LoadString.
* @param id data ID
* @param text string data (entry will be removed if null or empty string is specified)
*/
StringTable.prototype.setById = function (id, text) {
if (id < 0) {
return;
}
var entryIndex = id >> 4;
var entryPos = id & 15;
var e = this.items[entryIndex];
if (!e) {
this.items[entryIndex] = e = new StringTableItem_js_1.default();
}
e.set(entryPos, text);
};
/** Generates an array of Entry for resource processings */
StringTable.prototype.generateEntries = function () {
var _this = this;
return this.items
.map(function (e, i) {
var len = e.calcByteLength();
var bin = new ArrayBuffer(len);
e.generate(bin, 0);
return {
type: 6,
id: i + 1,
lang: _this.lang,
codepage: 1200,
bin: bin,
};
})
.filter(function (e) { return !!e; });
};
/**
* Replace all string entries for NtExecutableResource with containing resource data.
* The only entries of same language are replaced.
*/
StringTable.prototype.replaceStringEntriesForExecutable = function (res) {
var entries = this.generateEntries();
var dest = res.entries;
// first try -- replace same type and same language
for (var i = 0; i < dest.length; ++i) {
var e = dest[i];
if (e != null && e.type === 6 && e.lang === this.lang) {
for (var j = dest.length - 1; j >= i; --j) {
var e2 = dest[j];
if (e2 != null && e2.type === 6 && e2.lang === this.lang) {
dest.splice(j, 1);
}
}
var f = dest.splice.bind(dest, i, 0);
f.apply(void 0, entries);
return;
}
}
// second try -- add entries next to previous language
for (var i = 0; i < dest.length; ++i) {
var e = dest[i];
if (e != null && e.type === 6 && e.lang < this.lang) {
var f = dest.splice.bind(dest, i + 1, 0);
f.apply(void 0, entries);
return;
}
}
// third try -- add entries next to the last 'String' entry
for (var i = dest.length - 1; i >= 0; --i) {
var e = dest[i];
if (e != null && e.type === 6) {
var f = dest.splice.bind(dest, i + 1, 0);
f.apply(void 0, entries);
return;
}
}
// otherwise -- add entries to the last
dest.push.apply(dest, entries);
};
return StringTable;
}());
exports.default = StringTable;

View File

@@ -0,0 +1,11 @@
export default class StringTableItem {
readonly length = 16;
private _a;
constructor();
static fromEntry(bin: ArrayBuffer, offset: number, byteLength: number): StringTableItem;
get(index: number): string | null;
getAll(): Array<string | null>;
set(index: number, val: string | null): void;
calcByteLength(): number;
generate(bin: ArrayBuffer, offset: number): number;
}

View File

@@ -0,0 +1,73 @@
"use strict";
// StringTable entry:
// 16-times of {<WORD length> [<UTF-16 string>]}
Object.defineProperty(exports, "__esModule", { value: true });
var StringTableItem = /** @class */ (function () {
function StringTableItem() {
this.length = 16;
this._a = [];
this._a.length = 16;
for (var i = 0; i < 16; ++i) {
this._a[i] = '';
}
}
StringTableItem.fromEntry = function (bin, offset, byteLength) {
var view = new DataView(bin, offset, byteLength);
var ret = new StringTableItem();
var o = 0;
for (var i = 0; i < 16; ++i) {
var len = view.getUint16(o, true);
o += 2;
var s = '';
for (var j = 0; j < len; ++j) {
s += String.fromCharCode(view.getUint16(o, true));
o += 2;
}
ret._a[i] = s;
}
return ret;
};
StringTableItem.prototype.get = function (index) {
var value = this._a[index];
return value != null && value !== '' ? value : null;
};
StringTableItem.prototype.getAll = function () {
return this._a.map(function (s) { return s || null; });
};
StringTableItem.prototype.set = function (index, val) {
this._a[index] = ("" + (val !== null && val !== void 0 ? val : '')).substr(0, 4097); // length must be no longer than 4097
};
StringTableItem.prototype.calcByteLength = function () {
var len = 0;
for (var i = 0; i < 16; ++i) {
var item = this._a[i];
len += 2;
if (item != null) {
len += 2 * item.length; // UTF-16 length
}
}
// 16 alignment
return Math.floor((len + 15) / 16) * 16;
};
StringTableItem.prototype.generate = function (bin, offset) {
var out = new DataView(bin, offset);
var len = 0;
for (var i = 0; i < 16; ++i) {
var s = this._a[i];
var l = s == null ? 0 : s.length > 4097 ? 4097 : s.length;
out.setUint16(len, l, true);
len += 2;
if (s != null) {
for (var j = 0; j < l; ++j) {
// output as UTF-16
out.setUint16(len, s.charCodeAt(j), true);
len += 2;
}
}
}
// 16 alignment
return Math.floor((len + 15) / 16) * 16;
};
return StringTableItem;
}());
exports.default = StringTableItem;

View File

@@ -0,0 +1,13 @@
/**
* Flag values used by VersionEntry.fixedInfo field.
* Zero or more enum values are stored (with OR operator).
*/
declare enum VersionFileFlags {
Debug = 1,
Prerelease = 2,
Patched = 4,
PrivateBuild = 8,
InfoInferred = 16,
SpecialBuild = 32
}
export default VersionFileFlags;

View File

@@ -0,0 +1,16 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
/**
* Flag values used by VersionEntry.fixedInfo field.
* Zero or more enum values are stored (with OR operator).
*/
var VersionFileFlags;
(function (VersionFileFlags) {
VersionFileFlags[VersionFileFlags["Debug"] = 1] = "Debug";
VersionFileFlags[VersionFileFlags["Prerelease"] = 2] = "Prerelease";
VersionFileFlags[VersionFileFlags["Patched"] = 4] = "Patched";
VersionFileFlags[VersionFileFlags["PrivateBuild"] = 8] = "PrivateBuild";
VersionFileFlags[VersionFileFlags["InfoInferred"] = 16] = "InfoInferred";
VersionFileFlags[VersionFileFlags["SpecialBuild"] = 32] = "SpecialBuild";
})(VersionFileFlags || (VersionFileFlags = {}));
exports.default = VersionFileFlags;

View File

@@ -0,0 +1,20 @@
/**
* OS values used by VersionEntry.fixedInfo field.
*/
declare enum VersionFileOS {
Unknown = 0,
_Windows16 = 1,
_PM16 = 2,
_PM32 = 3,
_Windows32 = 4,
DOS = 65536,
OS2_16 = 131072,
OS2_32 = 196608,
NT = 262144,
DOS_Windows16 = 65537,
DOS_Windows32 = 65540,
NT_Windows32 = 262148,
OS2_16_PM16 = 131074,
OS2_32_PM32 = 196611
}
export default VersionFileOS;

View File

@@ -0,0 +1,23 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
/**
* OS values used by VersionEntry.fixedInfo field.
*/
var VersionFileOS;
(function (VersionFileOS) {
VersionFileOS[VersionFileOS["Unknown"] = 0] = "Unknown";
VersionFileOS[VersionFileOS["_Windows16"] = 1] = "_Windows16";
VersionFileOS[VersionFileOS["_PM16"] = 2] = "_PM16";
VersionFileOS[VersionFileOS["_PM32"] = 3] = "_PM32";
VersionFileOS[VersionFileOS["_Windows32"] = 4] = "_Windows32";
VersionFileOS[VersionFileOS["DOS"] = 65536] = "DOS";
VersionFileOS[VersionFileOS["OS2_16"] = 131072] = "OS2_16";
VersionFileOS[VersionFileOS["OS2_32"] = 196608] = "OS2_32";
VersionFileOS[VersionFileOS["NT"] = 262144] = "NT";
VersionFileOS[VersionFileOS["DOS_Windows16"] = 65537] = "DOS_Windows16";
VersionFileOS[VersionFileOS["DOS_Windows32"] = 65540] = "DOS_Windows32";
VersionFileOS[VersionFileOS["NT_Windows32"] = 262148] = "NT_Windows32";
VersionFileOS[VersionFileOS["OS2_16_PM16"] = 131074] = "OS2_16_PM16";
VersionFileOS[VersionFileOS["OS2_32_PM32"] = 196611] = "OS2_32_PM32";
})(VersionFileOS || (VersionFileOS = {}));
exports.default = VersionFileOS;

View File

@@ -0,0 +1,20 @@
export declare enum VersionFileDriverSubtype {
Unknown = 0,
Printer = 1,
Keyboard = 2,
Language = 3,
Display = 4,
Mouse = 5,
Network = 6,
System = 7,
Installable = 8,
Sound = 9,
Comm = 10,
VersionedPrinter = 12
}
export declare enum VersionFileFontSubtype {
Unknown = 0,
Raster = 1,
Vector = 2,
TrueType = 3
}

View File

@@ -0,0 +1,25 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.VersionFileFontSubtype = exports.VersionFileDriverSubtype = void 0;
var VersionFileDriverSubtype;
(function (VersionFileDriverSubtype) {
VersionFileDriverSubtype[VersionFileDriverSubtype["Unknown"] = 0] = "Unknown";
VersionFileDriverSubtype[VersionFileDriverSubtype["Printer"] = 1] = "Printer";
VersionFileDriverSubtype[VersionFileDriverSubtype["Keyboard"] = 2] = "Keyboard";
VersionFileDriverSubtype[VersionFileDriverSubtype["Language"] = 3] = "Language";
VersionFileDriverSubtype[VersionFileDriverSubtype["Display"] = 4] = "Display";
VersionFileDriverSubtype[VersionFileDriverSubtype["Mouse"] = 5] = "Mouse";
VersionFileDriverSubtype[VersionFileDriverSubtype["Network"] = 6] = "Network";
VersionFileDriverSubtype[VersionFileDriverSubtype["System"] = 7] = "System";
VersionFileDriverSubtype[VersionFileDriverSubtype["Installable"] = 8] = "Installable";
VersionFileDriverSubtype[VersionFileDriverSubtype["Sound"] = 9] = "Sound";
VersionFileDriverSubtype[VersionFileDriverSubtype["Comm"] = 10] = "Comm";
VersionFileDriverSubtype[VersionFileDriverSubtype["VersionedPrinter"] = 12] = "VersionedPrinter";
})(VersionFileDriverSubtype = exports.VersionFileDriverSubtype || (exports.VersionFileDriverSubtype = {}));
var VersionFileFontSubtype;
(function (VersionFileFontSubtype) {
VersionFileFontSubtype[VersionFileFontSubtype["Unknown"] = 0] = "Unknown";
VersionFileFontSubtype[VersionFileFontSubtype["Raster"] = 1] = "Raster";
VersionFileFontSubtype[VersionFileFontSubtype["Vector"] = 2] = "Vector";
VersionFileFontSubtype[VersionFileFontSubtype["TrueType"] = 3] = "TrueType";
})(VersionFileFontSubtype = exports.VersionFileFontSubtype || (exports.VersionFileFontSubtype = {}));

View File

@@ -0,0 +1,13 @@
/**
* File type values used by VersionEntry.fixedInfo field.
*/
declare enum VersionFileType {
Unknown = 0,
App = 1,
DLL = 2,
Driver = 3,
Font = 4,
VxD = 5,
StaticLibrary = 7
}
export default VersionFileType;

View File

@@ -0,0 +1,16 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
/**
* File type values used by VersionEntry.fixedInfo field.
*/
var VersionFileType;
(function (VersionFileType) {
VersionFileType[VersionFileType["Unknown"] = 0] = "Unknown";
VersionFileType[VersionFileType["App"] = 1] = "App";
VersionFileType[VersionFileType["DLL"] = 2] = "DLL";
VersionFileType[VersionFileType["Driver"] = 3] = "Driver";
VersionFileType[VersionFileType["Font"] = 4] = "Font";
VersionFileType[VersionFileType["VxD"] = 5] = "VxD";
VersionFileType[VersionFileType["StaticLibrary"] = 7] = "StaticLibrary";
})(VersionFileType || (VersionFileType = {}));
exports.default = VersionFileType;

View File

@@ -0,0 +1,197 @@
import { Type } from 'pe-library';
/**
* String values for the version information.
* In most cases predefined names are used for the key names (such as 'FileDescription', 'FileVersion', etc.)
* Note that the key names are case-sensitive; this library does not convert keys
* (e.g. `'fileVersion'` --> `'FileVersion'`).
*/
export declare type VersionStringValues = Record<string, string>;
/** Used by `VersionInfo.create` */
export interface VersionStringTable {
lang: number;
codepage: number;
/** Any string values */
values: VersionStringValues;
}
/** Translation information, containing LANGID and codepage value. */
export interface VersionTranslation {
lang: number;
/** Almost all cases are set to 1200 (Unicode) */
codepage: number;
}
/** Fixed version info, containing file version, product version, etc. (`VS_FIXEDFILEINFO`) */
export interface VersionFixedInfo {
/** usually major version in HIWORD(fileVersionMS), minor version in LOWORD(fileVersionMS) */
fileVersionMS: number;
/** usually patch version in HIWORD(fileVersionLS), revision in LOWORD(fileVersionLS) */
fileVersionLS: number;
productVersionMS: number;
productVersionLS: number;
/** valid values of fileFlags */
fileFlagsMask: number;
/** zero or more VersionFileFlags values, masked by fileFlagsMask */
fileFlags: number;
/** VersionFileOS value */
fileOS: number;
/** VersionFileType value */
fileType: number;
/**
* subtype values depended on fileType, such as
* `VersionFileDriverSubtype` or `VersionFileFontSubtype`.
* (if no suitable value, zero is stored)
*/
fileSubtype: number;
fileDateMS: number;
fileDateLS: number;
}
export interface VersionInfoCreateParam {
lang: string | number;
/** This field can be as a partial object; default values (zero) are used for all unspecified field. */
fixedInfo: Partial<Readonly<VersionFixedInfo>>;
strings: readonly VersionStringTable[];
}
/**
* Treats 'Version information' (`VS_VERSIONINFO`) resource data.
*/
export default class VersionInfo {
private readonly data;
private constructor();
/** Returns new `VersionInfo` instance with empty data. */
static createEmpty(): VersionInfo;
/**
* Returns new `VersionInfo` instance with specified parameters.
* `fixedInfo` can be specified as a partial object;
* default values (zero) are used for all unspecified field.
*/
static create(lang: string | number, fixedInfo: Partial<Readonly<VersionFixedInfo>>, strings: readonly VersionStringTable[]): VersionInfo;
/** Returns new `VersionInfo` instance with specified parameters. */
static create(param: Readonly<VersionInfoCreateParam>): VersionInfo;
/** Pick up all version-info entries */
static fromEntries(entries: readonly Type.ResourceEntry[]): VersionInfo[];
/** A language value for this resource entry. */
get lang(): string | number;
set lang(value: string | number);
/**
* The property of fixed version info, containing file version, product version, etc.
* (data: `VS_FIXEDFILEINFO`)
*
* Although this property is read-only, you can rewrite
* each child fields directly to apply data.
*/
get fixedInfo(): VersionFixedInfo;
/**
* Returns all languages that the executable supports. (data: `VarFileInfo`)
*
* Usually the returned array is equal to the one returned by `getAllLanguagesForStringValues`,
* but some resource-generating tools doesn't generate same values.
*/
getAvailableLanguages(): VersionTranslation[];
/**
* Replaces all languages that the executable supports.
*/
replaceAvailableLanguages(languages: readonly VersionTranslation[]): void;
/**
* Returns all string values for the specified language. (data: values in lang-charset block of `StringFileInfo`)
*/
getStringValues(language: VersionTranslation): VersionStringValues;
/**
* Returns all languages used by string values. (data: lang-charset name of `StringFileInfo`)
*
* Usually the returned array is equal to the one returned by `getAvailableLanguages`,
* but some resource-generating tools doesn't generate same values.
*/
getAllLanguagesForStringValues(): VersionTranslation[];
/**
* Add or replace the string values.
* @param language language info
* @param values string values (key-value pairs)
* @param addToAvailableLanguage set `true` to add `language` into available languages
* if not existing in `getAvailableLanguages()` (default: `true`)
*/
setStringValues(language: VersionTranslation, values: VersionStringValues, addToAvailableLanguage?: boolean): void;
/**
* Add or replace the string value.
* @param language language info
* @param key the key name of string value
* @param value the string value
* @param addToAvailableLanguage set `true` to add `language` into available languages
* if not existing in `getAvailableLanguages()` (default: `true`)
*/
setStringValue(language: VersionTranslation, key: string, value: string, addToAvailableLanguage?: boolean): void;
/**
* Remove all string values for specified language.
* @param language language info
* @param removeFromAvailableLanguage set `true` to remove `language` from available languages
* if existing in `getAvailableLanguages()` (default: `true`)
*/
removeAllStringValues(language: VersionTranslation, removeFromAvailableLanguage?: boolean): void;
/**
* Remove specified string value for specified language.
* @param language language info
* @param key the key name of string value to be removed
* @param removeFromAvailableLanguage set `true` to remove `language` from available languages
* if no more string values exist for `language` (default: `true`)
*/
removeStringValue(language: VersionTranslation, key: string, removeFromAvailableLanguage?: boolean): void;
/**
* Creates `Type.ResourceEntry` object for this instance.
* Usually `outputToResourceEntries` is suitable for generating resource data
* into executables, but you can use this method if necessary.
*/
generateResource(): Type.ResourceEntry;
/**
* Generates version info resource data (using `generateResource()`) and emits into `entries` array.
* If version info resource already exists in `entries`, this method replaces it with the new one.
* @param entries resource entry array for output
*/
outputToResourceEntries(entries: Type.ResourceEntry[]): void;
private getDefaultVersionLang;
/**
* Sets 'FileVersion' property with specified values.
* This methods writes `fixedInfo.fileVersionMS` and `fixedInfo.fileVersionLS` fields,
* and writes `FileVersion` string with the value `<major>.<minor>.<micro>.<revision>`.
* @param major The major version (clamped between 0 and 65535)
* @param minor The minor version (clamped between 0 and 65535)
* @param micro The micro version (clamped between 0 and 65535; default is 0)
* @param revision The revision value (clamped between 0 and 65535; default is 0)
* @param lang The language (default: this.lang -> picked from existings -> 1033)
* @note
* If you want to use 'Neutral' language for the version string, specify `lang` parameter to 0 explicitly
*/
setFileVersion(major: number, minor: number, micro?: number, revision?: number, lang?: number): void;
/**
* Sets 'FileVersion' property with specified values.
* This methods writes `fixedInfo.fileVersionMS` and `fixedInfo.fileVersionLS` fields,
* and writes `FileVersion` string with the value `<major>.<minor>.<micro>.<revision>`.
* @param version The version string value (should be `x.x.x.x` format; each integer clamped between 0 and 65535)
* @param lang The language (default: this.lang -> picked from existings -> 1033)
* @note
* If you want to use 'Neutral' language for the version string, specify `lang` parameter to 0 explicitly
*/
setFileVersion(version: string, lang?: number): void;
private setFileVersionImpl;
/**
* Sets 'ProductVersion' property with specified values.
* This methods writes `fixedInfo.productVersionMS` and `fixedInfo.productVersionLS` fields,
* and writes `ProductVersion` string with the value `<major>.<minor>.<micro>.<revision>`.
* @param major The major version (clamped between 0 and 65535)
* @param minor The minor version (clamped between 0 and 65535)
* @param micro The micro version (clamped between 0 and 65535; default is 0)
* @param revision The revision value (clamped between 0 and 65535; default is 0)
* @param lang The language (default: this.lang -> picked from existings -> 1033)
* @note
* If you want to use 'Neutral' language for the version string, specify `lang` parameter to 0 explicitly
*/
setProductVersion(major: number, minor: number, micro?: number, revision?: number, lang?: number): void;
/**
* Sets 'ProductVersion' property with specified values.
* This methods writes `fixedInfo.productVersionMS` and `fixedInfo.productVersionLS` fields,
* and writes `ProductVersion` string with the value `<major>.<minor>.<micro>.<revision>`.
* @param version The version string value (should be `x.x.x.x` format; each integer clamped between 0 and 65535)
* @param lang The language (default: this.lang -> picked from existings -> 1033)
* @note
* If you want to use 'Neutral' language for the version string, specify `lang` parameter to 0 explicitly
*/
setProductVersion(version: string, lang?: number): void;
private setProductVersionImpl;
}

Some files were not shown because too many files have changed in this diff Show More