Compare commits
3 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
93a642f242
|
|||
|
8a641cbc02
|
|||
|
b3d5aace89
|
@@ -1,26 +0,0 @@
|
|||||||
import js from '@eslint/js'
|
|
||||||
import globals from 'globals'
|
|
||||||
import tseslint from 'typescript-eslint'
|
|
||||||
import { defineConfig, globalIgnores } from 'eslint/config'
|
|
||||||
|
|
||||||
export default defineConfig([
|
|
||||||
globalIgnores(['dist']),
|
|
||||||
{
|
|
||||||
files: ['**/*.{ts,tsx}'],
|
|
||||||
extends: [
|
|
||||||
js.configs.recommended,
|
|
||||||
tseslint.configs.recommended,
|
|
||||||
],
|
|
||||||
languageOptions: {
|
|
||||||
ecmaVersion: 2020,
|
|
||||||
globals: globals.browser,
|
|
||||||
},
|
|
||||||
rules: {
|
|
||||||
"@typescript-eslint/ban-ts-comment": [
|
|
||||||
"error", {
|
|
||||||
"ts-ignore": "allow-with-description"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
}
|
|
||||||
},
|
|
||||||
])
|
|
||||||
24
eslint.config.ts
Normal file
24
eslint.config.ts
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
import js from "@eslint/js";
|
||||||
|
import globals from "globals";
|
||||||
|
import tseslint from "typescript-eslint";
|
||||||
|
import { defineConfig, globalIgnores } from "eslint/config";
|
||||||
|
|
||||||
|
export default defineConfig([
|
||||||
|
globalIgnores(["dist"]),
|
||||||
|
{
|
||||||
|
files: ["**/*.{ts,tsx}"],
|
||||||
|
extends: [js.configs.recommended, tseslint.configs.recommended],
|
||||||
|
languageOptions: {
|
||||||
|
ecmaVersion: 2020,
|
||||||
|
globals: globals.browser
|
||||||
|
},
|
||||||
|
rules: {
|
||||||
|
"@typescript-eslint/ban-ts-comment": [
|
||||||
|
"error",
|
||||||
|
{
|
||||||
|
"ts-ignore": "allow-with-description"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]);
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "@hamradio/packet",
|
"name": "@hamradio/packet",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"version": "1.0.5",
|
"version": "1.1.0",
|
||||||
"description": "Low level packet parsing library (for radio protocols)",
|
"description": "Low level packet parsing library (for radio protocols)",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"HAM radio",
|
"HAM radio",
|
||||||
@@ -45,6 +45,7 @@
|
|||||||
"@vitest/coverage-v8": "^4.0.18",
|
"@vitest/coverage-v8": "^4.0.18",
|
||||||
"eslint": "^10.0.3",
|
"eslint": "^10.0.3",
|
||||||
"globals": "^17.4.0",
|
"globals": "^17.4.0",
|
||||||
|
"jiti": "^2.6.1",
|
||||||
"prettier": "3.8.1",
|
"prettier": "3.8.1",
|
||||||
"tsup": "^8.5.1",
|
"tsup": "^8.5.1",
|
||||||
"typescript": "^5.9.3",
|
"typescript": "^5.9.3",
|
||||||
|
|||||||
@@ -1,28 +1,30 @@
|
|||||||
import { describe, it, expect } from 'vitest';
|
import { describe, it, expect } from "vitest";
|
||||||
import { Reader, Writer } from '.';
|
import { Reader, Writer } from ".";
|
||||||
|
|
||||||
describe('Reader/Writer round-trip', () => {
|
describe("Reader/Writer round-trip", () => {
|
||||||
it('writes then reads a variety of types correctly', () => {
|
it("writes then reads a variety of types correctly", () => {
|
||||||
const writer = new Writer(1024);
|
const writer = new Writer(1024);
|
||||||
|
|
||||||
// values to write
|
// values to write
|
||||||
const bBool = true;
|
const bBool = true;
|
||||||
|
const bChar = "A";
|
||||||
const bInt8 = -42;
|
const bInt8 = -42;
|
||||||
const bUint8 = 200;
|
const bUint8 = 200;
|
||||||
const bUint16 = 0xBEEF;
|
const bUint16 = 0xbeef;
|
||||||
const bUint32 = 0xDEADBEEF >>> 0;
|
const bUint32 = 0xdeadbeef >>> 0;
|
||||||
const bUint64 = 0x1122334455667788n;
|
const bUint64 = 0x1122334455667788n;
|
||||||
const bFloat32 = 3.1415927;
|
const bFloat32 = 3.1415927;
|
||||||
const bFloat64 = 1.23456789e5;
|
const bFloat64 = 1.23456789e5;
|
||||||
const bCString = 'hello';
|
const bCString = "hello";
|
||||||
const bUtf8 = 'π≈3.14';
|
const bUtf8 = "π≈3.14";
|
||||||
const words = [0x1234, 0x5678, 0x9ABC];
|
const words = [0x1234, 0x5678, 0x9abc];
|
||||||
const dwords = [0x11223344 >>> 0, 0x55667788 >>> 0];
|
const dwords = [0x11223344 >>> 0, 0x55667788 >>> 0];
|
||||||
const qwords = [0x8000000000000000n, 0xAABBCCDDEEFF0011n];
|
const qwords = [0x8000000000000000n, 0xaabbccddeeff0011n];
|
||||||
const rawBytes = new Uint8Array([1, 2, 3, 4]);
|
const rawBytes = new Uint8Array([1, 2, 3, 4]);
|
||||||
|
|
||||||
// write sequence
|
// write sequence
|
||||||
writer.bool(bBool);
|
writer.bool(bBool);
|
||||||
|
writer.char(bChar);
|
||||||
writer.int8(bInt8);
|
writer.int8(bInt8);
|
||||||
writer.uint8(bUint8);
|
writer.uint8(bUint8);
|
||||||
writer.uint16(bUint16);
|
writer.uint16(bUint16);
|
||||||
@@ -45,6 +47,7 @@ describe('Reader/Writer round-trip', () => {
|
|||||||
|
|
||||||
// read back in same order
|
// read back in same order
|
||||||
expect(reader.bool()).toBe(bBool);
|
expect(reader.bool()).toBe(bBool);
|
||||||
|
expect(reader.char()).toBe(bChar);
|
||||||
expect(reader.int8()).toBe(bInt8);
|
expect(reader.int8()).toBe(bInt8);
|
||||||
expect(reader.uint8()).toBe(bUint8);
|
expect(reader.uint8()).toBe(bUint8);
|
||||||
expect(reader.uint16()).toBe(bUint16);
|
expect(reader.uint16()).toBe(bUint16);
|
||||||
|
|||||||
32
src/index.ts
32
src/index.ts
@@ -35,6 +35,17 @@ export class Reader {
|
|||||||
return value !== 0;
|
return value !== 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Read an 8-bit character from the buffer at the current offset, and advance the offset by 1 byte.
|
||||||
|
* @returns A string containing the character read from the buffer.
|
||||||
|
*/
|
||||||
|
public char(): string {
|
||||||
|
this.checkBounds(1);
|
||||||
|
const value = this.view.getUint8(this.offset);
|
||||||
|
this.offset += 1;
|
||||||
|
return String.fromCharCode(value);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Read an 8-bit signed integer from the buffer at the current offset, and advance the offset by 1 byte.
|
* Read an 8-bit signed integer from the buffer at the current offset, and advance the offset by 1 byte.
|
||||||
*
|
*
|
||||||
@@ -434,6 +445,27 @@ export class Writer {
|
|||||||
this.offset += 1;
|
this.offset += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Write an 8-bit character to the buffer at the current offset, and advance the offset by 1 byte.
|
||||||
|
*
|
||||||
|
* @param value The character or its ASCII code to write.
|
||||||
|
*/
|
||||||
|
public char(value: string | number): void {
|
||||||
|
if (typeof value === "string") {
|
||||||
|
if (value.length !== 1) {
|
||||||
|
throw new Error("Input must be a single character");
|
||||||
|
}
|
||||||
|
this.checkBounds(1);
|
||||||
|
this.view.setUint8(this.offset, value.charCodeAt(0));
|
||||||
|
} else if (typeof value === "number") {
|
||||||
|
this.checkBounds(1);
|
||||||
|
this.view.setUint8(this.offset, value);
|
||||||
|
} else {
|
||||||
|
throw new Error("Input must be a string or number");
|
||||||
|
}
|
||||||
|
this.offset += 1;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Write an 8-bit signed integer to the buffer at the current offset, and advance the offset by
|
* Write an 8-bit signed integer to the buffer at the current offset, and advance the offset by
|
||||||
* 1 byte.
|
* 1 byte.
|
||||||
|
|||||||
74
src/types.ts
74
src/types.ts
@@ -1,9 +1,7 @@
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Type definitions for the packet parsing library.
|
* Type definitions for the packet parsing library.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Enumeration of supported field types for dissecting packets.
|
* Enumeration of supported field types for dissecting packets.
|
||||||
*
|
*
|
||||||
@@ -13,51 +11,52 @@
|
|||||||
*/
|
*/
|
||||||
export const FieldType = {
|
export const FieldType = {
|
||||||
// Boolean types
|
// Boolean types
|
||||||
BOOL: 'BOOL', // Boolean value (stored as a byte, 0 for false, non-zero for true)
|
BOOL: "BOOL", // Boolean value (stored as a byte, 0 for false, non-zero for true)
|
||||||
|
|
||||||
// Number types
|
// Number types
|
||||||
BITS: 'BITS', // 1-bit values stored in a number (1 bit per value, packed into bytes)
|
BITS: "BITS", // 1-bit values stored in a number (1 bit per value, packed into bytes)
|
||||||
INT8: 'INT8', // 8-bit signed integer (1 byte)
|
CHAR: "CHAR", // 8-bit character (1 byte)
|
||||||
INT16_LE: 'INT16_LE', // 16-bit signed integer (little-endian)
|
INT8: "INT8", // 8-bit signed integer (1 byte)
|
||||||
INT16_BE: 'INT16_BE', // 16-bit signed integer (big-endian)
|
INT16_LE: "INT16_LE", // 16-bit signed integer (little-endian)
|
||||||
INT32_LE: 'INT32_LE', // 32-bit signed integer (little-endian)
|
INT16_BE: "INT16_BE", // 16-bit signed integer (big-endian)
|
||||||
INT32_BE: 'INT32_BE', // 32-bit signed integer (big-endian)
|
INT32_LE: "INT32_LE", // 32-bit signed integer (little-endian)
|
||||||
INT64_LE: 'INT64_LE', // 64-bit signed integer (little-endian)
|
INT32_BE: "INT32_BE", // 32-bit signed integer (big-endian)
|
||||||
INT64_BE: 'INT64_BE', // 64-bit signed integer (big-endian)
|
INT64_LE: "INT64_LE", // 64-bit signed integer (little-endian)
|
||||||
UINT8: 'UINT8', // 8-bit unsigned integer
|
INT64_BE: "INT64_BE", // 64-bit signed integer (big-endian)
|
||||||
UINT16_LE: 'UINT16_LE', // 16-bit unsigned integer (little-endian)
|
UINT8: "UINT8", // 8-bit unsigned integer
|
||||||
UINT16_BE: 'UINT16_BE', // 16-bit unsigned integer (big-endian)
|
UINT16_LE: "UINT16_LE", // 16-bit unsigned integer (little-endian)
|
||||||
UINT32_LE: 'UINT32_LE', // 32-bit unsigned integer (little-endian)
|
UINT16_BE: "UINT16_BE", // 16-bit unsigned integer (big-endian)
|
||||||
UINT32_BE: 'UINT32_BE', // 32-bit unsigned integer (big-endian)
|
UINT32_LE: "UINT32_LE", // 32-bit unsigned integer (little-endian)
|
||||||
UINT64_LE: 'UINT64_LE', // 64-bit unsigned integer (little-endian)
|
UINT32_BE: "UINT32_BE", // 32-bit unsigned integer (big-endian)
|
||||||
UINT64_BE: 'UINT64_BE', // 64-bit unsigned integer (big-endian)
|
UINT64_LE: "UINT64_LE", // 64-bit unsigned integer (little-endian)
|
||||||
FLOAT32_LE: 'FLOAT32_LE', // 32-bit IEEE floating point (little-endian)
|
UINT64_BE: "UINT64_BE", // 64-bit unsigned integer (big-endian)
|
||||||
FLOAT32_BE: 'FLOAT32_BE', // 32-bit IEEE floating point (big-endian)
|
FLOAT32_LE: "FLOAT32_LE", // 32-bit IEEE floating point (little-endian)
|
||||||
FLOAT64_LE: 'FLOAT64_LE', // 64-bit IEEE floating point (little-endian)
|
FLOAT32_BE: "FLOAT32_BE", // 32-bit IEEE floating point (big-endian)
|
||||||
FLOAT64_BE: 'FLOAT64_BE', // 64-bit IEEE floating point (big-endian)
|
FLOAT64_LE: "FLOAT64_LE", // 64-bit IEEE floating point (little-endian)
|
||||||
VARINT: 'VARINT', // Variable-length integer (unsigned, LEB128 encoding)
|
FLOAT64_BE: "FLOAT64_BE", // 64-bit IEEE floating point (big-endian)
|
||||||
VARSINT: 'VARSINT', // Variable-length integer (signed, LEB128 encoding)
|
VARINT: "VARINT", // Variable-length integer (unsigned, LEB128 encoding)
|
||||||
|
VARSINT: "VARSINT", // Variable-length integer (signed, LEB128 encoding)
|
||||||
|
|
||||||
// Date/time types (stored as integer timestamps)
|
// Date/time types (stored as integer timestamps)
|
||||||
DATE32_LE: 'DATE32_LE', // 32-bit integer date (e.g., seconds since epoch) little-endian
|
DATE32_LE: "DATE32_LE", // 32-bit integer date (e.g., seconds since epoch) little-endian
|
||||||
DATE32_BE: 'DATE32_BE', // 32-bit integer date big-endian
|
DATE32_BE: "DATE32_BE", // 32-bit integer date big-endian
|
||||||
DATE64_LE: 'DATE64_LE', // 64-bit integer date (e.g., ms since epoch) little-endian
|
DATE64_LE: "DATE64_LE", // 64-bit integer date (e.g., ms since epoch) little-endian
|
||||||
DATE64_BE: 'DATE64_BE', // 64-bit integer date big-endian
|
DATE64_BE: "DATE64_BE", // 64-bit integer date big-endian
|
||||||
|
|
||||||
// Array buffer types
|
// Array buffer types
|
||||||
BYTES: 'BYTES', // 8-bits per value array (Uint8Array)
|
BYTES: "BYTES", // 8-bits per value array (Uint8Array)
|
||||||
C_STRING: 'C_STRING', // Null-terminated string (C-style) (Uint8Array)
|
C_STRING: "C_STRING", // Null-terminated string (C-style) (Uint8Array)
|
||||||
UTF8_STRING: 'UTF8_STRING', // UTF-8 encoded string (Uint8Array)
|
UTF8_STRING: "UTF8_STRING", // UTF-8 encoded string (Uint8Array)
|
||||||
WORDS: 'WORDS', // 16-bits per value array (Uint16Array)
|
WORDS: "WORDS", // 16-bits per value array (Uint16Array)
|
||||||
DWORDS: 'DWORDS', // 32-bits per value array (Uint32Array)
|
DWORDS: "DWORDS", // 32-bits per value array (Uint32Array)
|
||||||
QWORDS: 'QWORDS', // 64-bits per value array (BigUint64Array)
|
QWORDS: "QWORDS", // 64-bits per value array (BigUint64Array)
|
||||||
|
|
||||||
// Aliases
|
// Aliases
|
||||||
FLAG: 'BOOL', // alternate name for boolean/flag fields
|
FLAG: "BOOL", // alternate name for boolean/flag fields
|
||||||
STRING: 'UTF8_STRING', // alias for UTF8 encoded strings
|
STRING: "UTF8_STRING" // alias for UTF8 encoded strings
|
||||||
} as const;
|
} as const;
|
||||||
|
|
||||||
export type FieldType = typeof FieldType[keyof typeof FieldType];
|
export type FieldType = (typeof FieldType)[keyof typeof FieldType];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Interface for a packet, which can be dissected into segments and fields. This is a placeholder
|
* Interface for a packet, which can be dissected into segments and fields. This is a placeholder
|
||||||
@@ -110,6 +109,7 @@ export type Dissected = Segment[];
|
|||||||
export interface Segment {
|
export interface Segment {
|
||||||
name: string;
|
name: string;
|
||||||
data?: ArrayBuffer; // Optional raw data for the segment (if needed for parsing / serialization)
|
data?: ArrayBuffer; // Optional raw data for the segment (if needed for parsing / serialization)
|
||||||
|
isString?: boolean; // Optional flag indicating if the segment represents a string (for special handling)
|
||||||
fields: Field[];
|
fields: Field[];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user