/*
This file is part of the Notesnook project (https://notesnook.com/)
Copyright (C) 2023 Streetwriters (Private) Limited
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see .
*/
import { OneNoteReader } from "../reader";
import { BufferReader } from "./reader";
export enum CBFormat {
UINT32 = 0,
ULONG64 = 1,
UINT8_COMPRESSED = 2,
UINT16_COMPRESSED = 3
}
export enum STPFormat {
ULONG64 = 0,
UINT32 = 1,
UINT16 = 2,
UINT32_COMPRESSED = 3
}
export function StpFormatFromNumber(number: number) {
if (!STPFormat[number])
throw new Error(
`Invalid stpFormat. Expected one of 0, 1, 2, 3 but got ${number}.`
);
return number as STPFormat;
}
export function CbFormatFromNumber(number: number) {
if (!CBFormat[number])
throw new Error(
`Invalid cbFormat. Expected one of 0, 1, 2, 3 but got ${number}.`
);
return number as CBFormat;
}
/**
* Values considered "invalid" for each STP format per [MS-ONESTORE] 2.2.1.
* ULONG64 uses the nearest representable double to 2^64 - 1; reading an
* all-ones UINT64 produces the same rounded double so equality still holds.
*/
const STPInvalidIntegers = {
[STPFormat.ULONG64]: 0xffffffffffffffff,
[STPFormat.UINT32]: 0xffffffff,
[STPFormat.UINT16]: 0x7fff8,
[STPFormat.UINT32_COMPRESSED]: 0x7fffffff8
} as const;
export class FileChunkReference<
TStpFormat extends STPFormat | unknown = unknown,
TCbFormat extends CBFormat | unknown = unknown
> {
readonly stp: number;
readonly cb: number;
constructor(
private readonly reader: OneNoteReader,
buffer: BufferReader,
private readonly stpFormat: TStpFormat,
private readonly cbFormat: TCbFormat
) {
this.stp =
stpFormat === STPFormat.ULONG64
? buffer.readUInt64()
: stpFormat === STPFormat.UINT32
? buffer.readUInt32()
: stpFormat === STPFormat.UINT16
? buffer.readUInt16() * 8
: stpFormat === STPFormat.UINT32_COMPRESSED
? buffer.readUInt32() * 8
: 0;
this.cb =
cbFormat === CBFormat.UINT32
? buffer.readUInt32()
: cbFormat === CBFormat.ULONG64
? buffer.readUInt64()
: cbFormat === CBFormat.UINT8_COMPRESSED
? buffer.readUInt8() * 8
: cbFormat === CBFormat.UINT16_COMPRESSED
? buffer.readUInt16() * 8
: 0;
}
get isNil() {
const INVALID = STPInvalidIntegers[this.stpFormat as STPFormat];
const isStpNil =
this.stpFormat === STPFormat.ULONG64
? this.stp === INVALID
: (this.stp & INVALID) === INVALID;
return isStpNil && this.cb === 0;
}
get isZero() {
return this.stp === 0 && this.cb === 0;
}
is64x32(): this is FileChunkReference {
return (
this.stpFormat === STPFormat.ULONG64 && this.cbFormat === CBFormat.UINT32
);
}
seek() {
this.reader.seek(this.stp);
}
}
export class FileChunkReference32 extends FileChunkReference<
STPFormat.UINT32,
CBFormat.UINT32
> {}
export class FileChunkReference64x32 extends FileChunkReference<
STPFormat.ULONG64,
CBFormat.UINT32
> {}