npm.io
0.0.1 • Published 2 months ago

qtdatastream-web

Licence
MIT
Version
0.0.1
Deps
0
Size
111 kB
Vulns
0
Weekly
0

qtdatastream-web

License: MIT

A TypeScript (de)serializer for Qt's QDataStream format that runs natively in the browser — built only on Uint8Array, DataView, BigInt, and TextEncoder/TextDecoder. No Buffer, no Node streams, no polyfills.

Supported types: QBool, QShort, QInt, QInt64, QUInt, QUInt64, QDouble, QMap, QList, QString, QVariant, QStringList, QByteArray, QUserType, QDateTime, QTime, QChar, QInvalid.

Install

npm install qtdatastream-web

The package ships ES modules and TypeScript declarations. There is no default runtime dependency.

Quick start

import { read, write } from 'qtdatastream-web';

// Serialize a value to a Uint8Array...
const bytes = write({ AString: 'BString', CString: 42 });

// ...and read it back.
const value = read(bytes); // { AString: 'BString', CString: 42 }

write/read operate on a single QVariant with no framing — convenient for reading from and writing to files. Input to read may be a Uint8Array, ArrayBuffer, any TypedArray, or a number[]; output is always a Uint8Array.

Reading a file in the browser
import { read } from 'qtdatastream-web';

const file = input.files[0];
const value = read(await file.arrayBuffer());
Writing a file in the browser
import { write } from 'qtdatastream-web';

const blob = new Blob([write(value)], { type: 'application/octet-stream' });
const url = URL.createObjectURL(blob);

API

import {
  read, write,           // single QVariant, no length prefix
  readAll,               // read every QVariant until the buffer is exhausted
  readPacket, writePacket, // QVariant prefixed with a 4-byte big-endian length
  ReadBuffer,            // sequential big-endian reader over a byte buffer
  types,                 // all Q* type classes + Types enum
  util,                  // str(), date <-> Julian day, deep mapping
  bytes,                 // low-level byte/encoding helpers
  serialization,         // Serializable / serialize decorators
} from 'qtdatastream-web';

Submodules are also importable directly, e.g. qtdatastream-web/types.

Type inference

JavaScript values are coerced to Qt types automatically.

JavaScript QClass
string QString
number QUInt (configurable)
bigint QInt64
boolean QBool
Array QList<QVariant<?>>
Date QDateTime
Map QMap
Object QMap

Force any value into a specific Qt type with <QClass>.from:

import { types } from 'qtdatastream-web';
const qbytearray = types.QByteArray.from('hello'); // string written as a QByteArray

Change the default class plain numbers coerce to:

import { types } from 'qtdatastream-web';
types.QVariant.coerceNumbersTo(types.Types.DOUBLE); // numbers now serialize as QDouble
Reading back to JavaScript
QClass JavaScript
QString string
QUInt/QInt/QShort/QDouble/QTime number
QUInt64/QInt64 bigint
QBool boolean
QList Array
QStringList Array<string>
QByteArray Uint8Array
QMap Object
QUserType Object
QDateTime Date
QChar string
QInvalid undefined

64-bit integers are read as bigint and may be written as bigint or number.

QUserType

QUserType covers Qt's user-defined types (QVariant::UserType). Register a parser/serializer for each type by name before use.

import { types } from 'qtdatastream-web';
const { QUserType, Types } = types;

// Simple usertype backed by a single Qt type
QUserType.register('NetworkId', Types.INT);

// Structured usertype (parsing order is preserved)
QUserType.register('BufferInfo', [
  { id: Types.INT },
  { network: Types.INT },
  { type: Types.SHORT },
  { name: Types.BYTEARRAY },
]);

// Usertypes may nest other usertypes by name (declare the referenced one first)
QUserType.register('BufferInfoContainer', [
  { id: Types.INT },
  { bufferInfo: 'BufferInfo' },
]);

Writing a usertype value:

import { write, types } from 'qtdatastream-web';

const bytes = write({
  BufferInfo: new types.QUserType('BufferInfo', {
    id: 2,
    network: 4,
    type: 5,
    name: 'BufferInfo name',
  }),
});

Decorators

Classes can declare their serialization shape with decorators. These use the legacy decorator syntax, so enable experimentalDecorators in your tsconfig.json (or the equivalent Babel plugin).

import { types, Serializable, serialize } from 'qtdatastream-web';
const { QString, QUInt, Types, QUserType } = types;

QUserType.register('Network::Server', Types.MAP);

@Serializable('Network::Server')
class Server {
  @serialize(QString, { in: 'HostIn', out: 'HostOut' })
  host?: string;

  @serialize(QUInt, 'Port')
  port = 6667;

  @serialize(QUInt)
  sslVersion = 0;

  constructor(args: Partial<Server>) {
    Object.assign(this, args);
  }
}

Serializable's argument (the usertype name) is optional; without it, instances export as a QMap. If a serializable class implements _export(), its return value is serialized instead of the instance's own attributes.

Development

yarn install
yarn build       # compile to dist/
yarn typecheck   # type-check without emitting
yarn test        # run the test suite (Vitest)
yarn test:watch  # run Vitest in watch mode

Credits

This project is based on the original node-qtdatastream by Joël Charles, whose work defines the QDataStream encoding implemented here.

License

MIT.

Keywords