@altronix/webtobin 0.5.0 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@altronix/webtobin",
3
- "version": "0.5.0",
3
+ "version": "0.7.0",
4
4
  "type": "module",
5
5
  "description": "",
6
6
  "main": "./webtobin.mjs",
package/webtobin.d.ts CHANGED
@@ -1,7 +1,49 @@
1
- export default class {
1
+ export interface McubootVersion {
2
+ major: number;
3
+ minor: number;
4
+ revision: number;
5
+ build: number;
6
+ }
7
+
8
+ export interface McubootHeader {
9
+ magic: number;
10
+ loadAddr: number;
11
+ hdrSize: number;
12
+ protectTlvSize: number;
13
+ imgSize: number;
14
+ flags: number;
15
+ version: McubootVersion;
16
+ }
17
+
18
+ export interface McubootTlv {
19
+ type: number;
20
+ value: Uint8Array;
21
+ }
22
+
23
+ export interface McubootImage {
24
+ header: McubootHeader;
25
+ image: Uint8Array;
26
+ protectedTlvs: McubootTlv[];
27
+ tlvs: McubootTlv[];
28
+ }
29
+
30
+ export function parseMcubootImages(bin: Buffer | Uint8Array): McubootImage[];
31
+
32
+ export class AltronixImage {
33
+ partitionIndex: number;
34
+ partitionName: string;
35
+ constructor(mcubootImage: McubootImage);
36
+ static fromMcubootImage(img: McubootImage): AltronixImage;
37
+ readTlv(type: number): Uint8Array | null;
38
+ get header(): McubootHeader;
39
+ get image(): Uint8Array;
40
+ get version(): McubootVersion;
41
+ }
42
+
43
+ export default class Webtobin {
2
44
  constructor();
3
45
  files: { path: string; data: Uint8Array }[];
4
- static from(bin: Uint8Array): this;
46
+ static from(bin: Uint8Array): Webtobin;
5
47
  append(path: string, data: string | Uint8Array): this;
6
48
  remove(path: string): this;
7
49
  print(): Uint8Array;
package/webtobin.mjs CHANGED
@@ -1,5 +1,214 @@
1
1
  //! webtobin.mjs
2
2
 
3
+ const IMAGE_MAGIC = 0x96f3b83d;
4
+ const TLV_INFO_MAGIC = 0x6907;
5
+ const TLV_PROT_INFO_MAGIC = 0x6908;
6
+
7
+ /**
8
+ * @typedef {Object} McubootVersion
9
+ * @property {number} major
10
+ * @property {number} minor
11
+ * @property {number} revision
12
+ * @property {number} build
13
+ */
14
+
15
+ /**
16
+ * @typedef {Object} McubootHeader
17
+ * @property {number} magic
18
+ * @property {number} loadAddr
19
+ * @property {number} hdrSize
20
+ * @property {number} protectTlvSize
21
+ * @property {number} imgSize
22
+ * @property {number} flags
23
+ * @property {McubootVersion} version
24
+ */
25
+
26
+ /**
27
+ * @typedef {Object} McubootTlv
28
+ * @property {number} type
29
+ * @property {Uint8Array} value
30
+ */
31
+
32
+ /**
33
+ * @typedef {Object} McubootImage
34
+ * @property {McubootHeader} header
35
+ * @property {Uint8Array} image
36
+ * @property {McubootTlv[]} protectedTlvs
37
+ * @property {McubootTlv[]} tlvs
38
+ */
39
+
40
+ /**
41
+ * Parse MCUboot signed binary into array of images
42
+ * @param {Buffer|Uint8Array} bin
43
+ * @returns {McubootImage[]}
44
+ */
45
+ export function parseMcubootImages(bin) {
46
+ const images = [];
47
+ const buf = new Uint8Array(bin).buffer;
48
+ const view = new DataView(buf);
49
+ const le = true;
50
+
51
+ let offset = 0;
52
+ while (offset < buf.byteLength) {
53
+ const magic = view.getUint32(offset, le);
54
+ if (magic !== IMAGE_MAGIC) break;
55
+
56
+ const header = parseHeader(view, offset);
57
+ const imgStart = offset + header.hdrSize;
58
+ const imgEnd = imgStart + header.imgSize;
59
+ const image = new Uint8Array(buf.slice(imgStart, imgEnd));
60
+
61
+ const protectedTlvs = [];
62
+ const tlvs = [];
63
+ let tlvOffset = imgEnd;
64
+
65
+ // Parse protected TLVs (magic 0x6908)
66
+ if (header.protectTlvSize > 0) {
67
+ const protMagic = view.getUint16(tlvOffset, le);
68
+ if (protMagic === TLV_PROT_INFO_MAGIC) {
69
+ const protSize = view.getUint16(tlvOffset + 2, le);
70
+ parseTlvs(view, tlvOffset + 4, protSize - 4, protectedTlvs);
71
+ tlvOffset += protSize;
72
+ }
73
+ }
74
+
75
+ // Parse standard TLVs (magic 0x6907)
76
+ const tlvMagic = view.getUint16(tlvOffset, le);
77
+ if (tlvMagic === TLV_INFO_MAGIC) {
78
+ const tlvSize = view.getUint16(tlvOffset + 2, le);
79
+ parseTlvs(view, tlvOffset + 4, tlvSize - 4, tlvs);
80
+ tlvOffset += tlvSize;
81
+ }
82
+
83
+ images.push({ header, image, protectedTlvs, tlvs });
84
+ offset = tlvOffset;
85
+ }
86
+
87
+ return images;
88
+ }
89
+
90
+ /**
91
+ * @param {DataView} view
92
+ * @param {number} offset
93
+ * @returns {McubootHeader}
94
+ */
95
+ function parseHeader(view, offset) {
96
+ const le = true;
97
+ return {
98
+ magic: view.getUint32(offset + 0x00, le),
99
+ loadAddr: view.getUint32(offset + 0x04, le),
100
+ hdrSize: view.getUint16(offset + 0x08, le),
101
+ protectTlvSize: view.getUint16(offset + 0x0a, le),
102
+ imgSize: view.getUint32(offset + 0x0c, le),
103
+ flags: view.getUint32(offset + 0x10, le),
104
+ version: {
105
+ major: view.getUint8(offset + 0x14),
106
+ minor: view.getUint8(offset + 0x15),
107
+ revision: view.getUint16(offset + 0x16, le),
108
+ build: view.getUint32(offset + 0x18, le),
109
+ },
110
+ };
111
+ }
112
+
113
+ /**
114
+ * @param {DataView} view
115
+ * @param {number} offset
116
+ * @param {number} length
117
+ * @param {McubootTlv[]} out
118
+ */
119
+ function parseTlvs(view, offset, length, out) {
120
+ const le = true;
121
+ const end = offset + length;
122
+ while (offset < end) {
123
+ const type = view.getUint16(offset, le);
124
+ const len = view.getUint16(offset + 2, le);
125
+ const data = new Uint8Array(view.buffer.slice(offset + 4, offset + 4 + len));
126
+ out.push({ type, value: data });
127
+ offset += 4 + len;
128
+ }
129
+ }
130
+
131
+ // Application-specific TLV types
132
+ const TLV_PARTITION_INDEX = 0x8001;
133
+ const TLV_PARTITION_NAME = 0x8002;
134
+
135
+ /**
136
+ * @typedef {Object} AltronixImageInfo
137
+ * @property {number} partitionIndex
138
+ * @property {string} partitionName
139
+ * @property {McubootHeader} header
140
+ * @property {Uint8Array} image
141
+ * @property {McubootVersion} version
142
+ */
143
+
144
+ /** Application-specific wrapper for MCUboot images */
145
+ export class AltronixImage {
146
+ #mcuboot;
147
+
148
+ /** @type {number} */
149
+ partitionIndex;
150
+
151
+ /** @type {string} */
152
+ partitionName;
153
+
154
+ /**
155
+ * @param {McubootImage} mcubootImage
156
+ */
157
+ constructor(mcubootImage) {
158
+ this.#mcuboot = mcubootImage;
159
+
160
+ const indexTlv = this.#mcuboot.protectedTlvs.find((t) => t.type === TLV_PARTITION_INDEX);
161
+ if (!indexTlv) {
162
+ throw new Error("AltronixImage: missing required TLV_PARTITION_INDEX (0x8001)");
163
+ }
164
+ this.partitionIndex = new DataView(
165
+ indexTlv.value.buffer,
166
+ indexTlv.value.byteOffset,
167
+ indexTlv.value.byteLength
168
+ ).getUint32(0, true);
169
+
170
+ const nameTlv = this.#mcuboot.protectedTlvs.find((t) => t.type === TLV_PARTITION_NAME);
171
+ if (!nameTlv) {
172
+ throw new Error("AltronixImage: missing required TLV_PARTITION_NAME (0x8002)");
173
+ }
174
+ this.partitionName = new TextDecoder().decode(nameTlv.value);
175
+ }
176
+
177
+ /**
178
+ * Create AltronixImage from McubootImage
179
+ * @param {McubootImage} img
180
+ * @returns {AltronixImage}
181
+ */
182
+ static fromMcubootImage(img) {
183
+ return new AltronixImage(img);
184
+ }
185
+
186
+ /**
187
+ * Read a TLV value by type from protected TLVs
188
+ * @param {number} type
189
+ * @returns {Uint8Array|null}
190
+ */
191
+ readTlv(type) {
192
+ const tlv = this.#mcuboot.protectedTlvs.find((t) => t.type === type);
193
+ return tlv ? tlv.value : null;
194
+ }
195
+
196
+ /** @returns {McubootHeader} */
197
+ get header() {
198
+ return this.#mcuboot.header;
199
+ }
200
+
201
+ /** @returns {Uint8Array} */
202
+ get image() {
203
+ return this.#mcuboot.image;
204
+ }
205
+
206
+ /** @returns {McubootVersion} */
207
+ get version() {
208
+ return this.#mcuboot.header.version;
209
+ }
210
+ }
211
+
3
212
  /** Class holding Webtobin state */
4
213
  export default class Webtobin {
5
214
  constructor() {