Skip to content

Commit

Permalink
use custom error types
Browse files Browse the repository at this point in the history
  • Loading branch information
KurtThiemann committed Feb 1, 2023
1 parent 938209d commit 3138097
Show file tree
Hide file tree
Showing 21 changed files with 75 additions and 29 deletions.
6 changes: 6 additions & 0 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -58,4 +58,10 @@ export { default as EntrySourceOptions } from "./src/Options/EntrySourceOptions.
export { default as ReadArchiveOptions } from "./src/Options/ReadArchiveOptions.js";
export { default as WriteArchiveOptions } from "./src/Options/WriteArchiveOptions.js";

export { default as ArmariusError } from "./src/Error/ArmariusError.js";
export { default as ChecksumError } from "./src/Error/ChecksumError.js";
export { default as FeatureError } from "./src/Error/FeatureError.js";
export { default as OptionError } from "./src/Error/OptionError.js";
export { default as ZipError } from "./src/Error/ZipError.js";

export { default as Constants } from "./src/Constants.js";
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "armarius",
"version": "1.8.2",
"version": "1.9.0",
"description": "A JavaScript library to read, write, and merge ZIP archives in web browsers.",
"repository": "github:aternosorg/armarius",
"type": "module",
Expand Down
6 changes: 4 additions & 2 deletions src/Archive/Entry/ArchiveEntry.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ import MsDosTime from '../../Util/MsDosTime.js';
import EntryOptions from '../../Options/EntryOptions.js';
import BigInt from '../../Util/BigInt.js';
import CRC32 from '../../Util/CRC32.js';
import FeatureError from '../../Error/FeatureError.js';
import ArmariusError from '../../Error/ArmariusError.js';

const decoder = new TextDecoder();

Expand Down Expand Up @@ -215,7 +217,7 @@ export default class ArchiveEntry {
async getDataProcessor() {
let Processor = this.options.dataProcessors.get(this.centralDirectoryFileHeader.compressionMethod);
if (!Processor) {
throw new Error(`Unsupported compression method ${this.centralDirectoryFileHeader.compressionMethod}`);
throw new FeatureError(`Unsupported compression method ${this.centralDirectoryFileHeader.compressionMethod}`);
}
return new Processor(await this.getRawDataReader(), false, true);
}
Expand All @@ -233,7 +235,7 @@ export default class ArchiveEntry {
*/
async getDataReader() {
if (this.isDirectory()) {
throw new Error(`Cannot create data reader: ${this.getFileNameString()} is a directory`);
throw new ArmariusError(`Cannot create data reader: ${this.getFileNameString()} is a directory`);
}
await this.readLocalFileHeader();
return new EntryDataReader(
Expand Down
3 changes: 2 additions & 1 deletion src/Archive/Entry/EntryDataReader.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import CRC32 from "../../Util/CRC32.js";
import ChecksumError from '../../Error/ChecksumError.js';

export default class EntryDataReader {
/** @type {DataProcessor} */ dataProcessor;
Expand Down Expand Up @@ -30,7 +31,7 @@ export default class EntryDataReader {

if (this.dataProcessor.getPostCrc()) {
if (eof && this.dataProcessor.getPostCrc().finish() !== this.expectedCrc32) {
throw new Error('CRC32 checksum does not match expected value');
throw new ChecksumError('CRC32 checksum does not match expected value');
}
}

Expand Down
3 changes: 2 additions & 1 deletion src/Archive/EntrySource/DataReaderEntrySource.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import EntrySource from "./EntrySource.js";
import Constants from "../../Constants.js";
import CRC32 from "../../Util/CRC32.js";
import BigInt from "../../Util/BigInt.js";
import OptionError from '../../Error/OptionError.js';

export default class DataReaderEntrySource extends EntrySource {
/** @type {DataReader} */ reader;
Expand All @@ -16,7 +17,7 @@ export default class DataReaderEntrySource extends EntrySource {
*/
constructor(reader, options) {
if (!options.fileName) {
throw new Error('Missing required fileName option');
throw new OptionError('Missing required fileName option');
}
if (options.fileName.endsWith('/')) {
options.fileName = options.fileName.substring(0, options.fileName.length - 1);
Expand Down
3 changes: 2 additions & 1 deletion src/Archive/EntrySource/DirectoryEntrySource.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import EntrySource from "./EntrySource.js";
import Constants from "../../Constants.js";
import OptionError from '../../Error/OptionError.js';

export default class DirectoryEntrySource extends EntrySource {
/** @type {boolean} */ zip64;
Expand All @@ -9,7 +10,7 @@ export default class DirectoryEntrySource extends EntrySource {
*/
constructor(options) {
if (!options.fileName) {
throw new Error('Missing required fileName option');
throw new OptionError('Missing required fileName option');
}
if (!options.fileName.endsWith('/')) {
options.fileName += '/';
Expand Down
3 changes: 2 additions & 1 deletion src/Archive/EntrySource/EntrySource.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import UnicodeExtraField from '../Structure/ExtraField/UnicodeExtraField.js';
import MsDosTime from '../../Util/MsDosTime.js';
import BigInt from '../../Util/BigInt.js';
import {CRC32} from '../../../index.js';
import FeatureError from '../../Error/FeatureError.js';

const encoder = new TextEncoder();

Expand Down Expand Up @@ -314,7 +315,7 @@ export default class EntrySource {
getDataProcessor(reader, method = this.options.compressionMethod) {
let Processor = this.options.dataProcessors.get(method);
if (!Processor) {
throw new Error(`Unsupported compression method ${method}`);
throw new FeatureError(`Unsupported compression method ${method}`);
}
return new Processor(reader, true);
}
Expand Down
16 changes: 9 additions & 7 deletions src/Archive/ReadArchive.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ import EntryReference from "./Entry/EntryReference.js";
import EntryIterator from "./Entry/EntryIterator.js";
import ReadArchiveOptions from "../Options/ReadArchiveOptions.js";
import BigInt from "../Util/BigInt.js";
import ZipError from '../Error/ZipError.js';
import FeatureError from '../Error/FeatureError.js';

export default class ReadArchive {
/** @type {DataReader} */ reader;
Expand Down Expand Up @@ -40,7 +42,7 @@ export default class ReadArchive {
*/
async init() {
if (this.reader.byteLength < Constants.LENGTH_END_OF_CENTRAL_DIR) {
throw new Error('Total file length is shorter than end of central directory record');
throw new ZipError('Total file length is shorter than end of central directory record');
}

this.endOfCentralDirectoryOffset = await this.findEndOfCentralDirectoryRecord();
Expand All @@ -53,7 +55,7 @@ export default class ReadArchive {
this.prependedDataLength = 0;

if(this.endOfCentralDirectoryRecord.diskNumber !== 0 || this.endOfCentralDirectoryRecord.centralDirectoryDiskNumber !== 0) {
throw new Error('Multi disk archives are not supported');
throw new FeatureError('Multi disk archives are not supported');
}

/*
Expand All @@ -69,7 +71,7 @@ export default class ReadArchive {
}

if (this.centralDirectoryOffset < 0 || this.centralDirectoryOffset >= this.reader.byteLength) {
throw new Error('Invalid central directory data offset');
throw new ZipError('Invalid central directory data offset');
}

let offset = 0;
Expand All @@ -96,7 +98,7 @@ export default class ReadArchive {
}
}
if (this.centralDirectoryOffset < 0 || this.centralDirectoryOffset >= this.reader.byteLength) {
throw new Error('Invalid central directory data offset');
throw new ZipError('Invalid central directory data offset');
}
}

Expand All @@ -114,7 +116,7 @@ export default class ReadArchive {
this.reader.byteLength - Constants.LENGTH_END_OF_CENTRAL_DIR
);
if (endOfDirectoryOffset === -1) {
throw new Error('Unable to find end of central directory record');
throw new ZipError('Unable to find end of central directory record');
}
}
return endOfDirectoryOffset;
Expand All @@ -133,7 +135,7 @@ export default class ReadArchive {
this.endOfCentralDirectoryLocator64 = await EndOfCentralDirectoryLocator64.fromReader(endOfDirectoryLocatorReader);

if(this.endOfCentralDirectoryLocator64.disks > 1) {
throw new Error('Multi disk archives are not supported');
throw new FeatureError('Multi disk archives are not supported');
}

this.endOfCentralDirectoryOffset64 = Number(this.endOfCentralDirectoryLocator64.centralDirectoryEndOffset);
Expand Down Expand Up @@ -165,7 +167,7 @@ export default class ReadArchive {

if(this.endOfCentralDirectoryRecord64.diskNumber !== 0 ||
this.endOfCentralDirectoryRecord64.centralDirectoryDiskNumber !== 0) {
throw new Error('Multi disk archives are not supported');
throw new FeatureError('Multi disk archives are not supported');
}

this.centralDirectoryByteLength = Number(this.endOfCentralDirectoryRecord64.centralDirectorySize);
Expand Down
3 changes: 2 additions & 1 deletion src/Archive/Structure/ExtraField/UnicodeExtraField.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import ExtraField from "./ExtraField.js";
import FeatureError from '../../../Error/FeatureError.js';

export default class UnicodeExtraField extends ExtraField {
/**
Expand Down Expand Up @@ -28,7 +29,7 @@ export default class UnicodeExtraField extends ExtraField {
await super.read(reader);
this.version = await reader.getUint8();
if (this.version !== 1) {
throw new Error(`Unknown unicode extra field version ${this.version}`);
throw new FeatureError(`Unknown unicode extra field version ${this.version}`);
}
this.crc32 = await reader.getUint32();
this.data = await reader.read(this.size - 5);
Expand Down
3 changes: 2 additions & 1 deletion src/Archive/Structure/SignatureStructure.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import Structure from "./Structure.js";
import ZipError from '../../Error/ZipError.js';

/**
* @abstract
Expand All @@ -12,7 +13,7 @@ export default class SignatureStructure extends Structure {
setSignature(signature) {
let correctSignature = this.constructor.getSignature();
if (signature !== correctSignature) {
throw new Error(`Invalid signature for ${this.constructor.name}. Expected 0x${correctSignature.toString(16)}, got 0x${signature.toString(16)}`);
throw new ZipError(`Invalid signature for ${this.constructor.name}. Expected 0x${correctSignature.toString(16)}, got 0x${signature.toString(16)}`);
}
this.signature = signature;
}
Expand Down
3 changes: 2 additions & 1 deletion src/DataProcessor/FallbackDataProcessor.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import DataProcessor from './DataProcessor.js';
import FeatureError from '../Error/FeatureError.js';

export default class FallbackDataProcessor extends DataProcessor {
/** @type {DataProcessor} */ dataProcessor;
Expand Down Expand Up @@ -32,7 +33,7 @@ export default class FallbackDataProcessor extends DataProcessor {
}

if(!this.dataProcessor) {
throw (lastError || new Error('Failed to find working DataProcessor'));
throw (lastError || new FeatureError('Failed to find working DataProcessor'));
}
}

Expand Down
3 changes: 3 additions & 0 deletions src/Error/ArmariusError.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export default class ArmariusError extends Error {

}
5 changes: 5 additions & 0 deletions src/Error/ChecksumError.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import ZipError from './ZipError.js';

export default class ChecksumError extends ZipError {

}
5 changes: 5 additions & 0 deletions src/Error/FeatureError.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import ArmariusError from './ArmariusError.js';

export default class FeatureError extends ArmariusError {

}
5 changes: 5 additions & 0 deletions src/Error/OptionError.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import ArmariusError from './ArmariusError.js';

export default class OptionError extends ArmariusError {

}
5 changes: 5 additions & 0 deletions src/Error/ZipError.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import ArmariusError from './ArmariusError.js';

export default class ZipError extends ArmariusError {

}
3 changes: 2 additions & 1 deletion src/Index/ArchiveIndex.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import CRC32 from "../Util/CRC32.js";
import ArmariusError from '../Error/ArmariusError.js';
const encoder = new TextEncoder();

/**
Expand Down Expand Up @@ -62,7 +63,7 @@ export default class ArchiveIndex {
*/
getPossibleOffsetsByHash(crc) {
if(!this.finalized) {
throw new Error('Index is not finalized');
throw new ArmariusError('Index is not finalized');
}
let firstIndex = this.find(crc);
if(firstIndex === null) {
Expand Down
5 changes: 3 additions & 2 deletions src/Reader/ArrayBufferReader.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import DataReader from "./DataReader.js";
import BigIntUtils from "../Util/BigIntUtils.js";
import ArmariusError from '../Error/ArmariusError.js';


export default class ArrayBufferReader extends DataReader {
Expand Down Expand Up @@ -35,10 +36,10 @@ export default class ArrayBufferReader extends DataReader {
*/
async readAt(offset, length, longLived) {
if (offset < 0) {
throw new Error(`Cannot read at negative offsets (got ${offset})`);
throw new ArmariusError(`Cannot read at negative offsets (got ${offset})`);
}
if (offset + length > this.byteLength) {
throw new Error(`Cannot read beyond end of data (trying to read ${length} bytes at ${offset}, data length is ${this.byteLength})`);
throw new ArmariusError(`Cannot read beyond end of data (trying to read ${length} bytes at ${offset}, data length is ${this.byteLength})`);
}
if (longLived && this.byteLength - length > 64) {
return this.data.slice(this.byteOffset + offset, this.byteOffset + offset + length);
Expand Down
11 changes: 6 additions & 5 deletions src/Reader/BrowserFileReader.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import DataReader from "./DataReader.js";
import BigIntUtils from "../Util/BigIntUtils.js";
import ArmariusError from '../Error/ArmariusError.js';


export default class BrowserFileReader extends DataReader {
Expand All @@ -21,7 +22,7 @@ export default class BrowserFileReader extends DataReader {
this.byteLength = byteLength !== null ? byteLength : file.size - byteOffset;
this.byteOffset = byteOffset;
if (this.byteLength < 0 || this.file.size < this.byteOffset + this.byteLength) {
throw new Error('Invalid file range');
throw new ArmariusError('Invalid file range');
}
}

Expand Down Expand Up @@ -53,10 +54,10 @@ export default class BrowserFileReader extends DataReader {
return reject(Error('Multiple simultaneous reads are not supported'));
}
if (offset < 0) {
return reject(new Error(`Cannot read at negative offsets (got ${offset})`));
return reject(new ArmariusError(`Cannot read at negative offsets (got ${offset})`));
}
if (offset + length > this.byteLength) {
return reject(new Error(`Cannot read beyond end of data (trying to read ${length} bytes at ${offset}, data length is ${this.byteLength})`));
return reject(new ArmariusError(`Cannot read beyond end of data (trying to read ${length} bytes at ${offset}, data length is ${this.byteLength})`));
}
this.blocked = true;
this.reader.onload = () => {
Expand All @@ -66,7 +67,7 @@ export default class BrowserFileReader extends DataReader {
resolve(new Uint8Array(res));
};
this.reader.onerror = () => {
reject(this.reader.error || new Error('An unknown error occurred while reading from Blob'));
reject(this.reader.error || new ArmariusError('An unknown error occurred while reading from Blob'));
};
this.reader.readAsArrayBuffer(this.file.slice(this.byteOffset + offset, this.byteOffset + offset + length));
});
Expand All @@ -82,7 +83,7 @@ export default class BrowserFileReader extends DataReader {
readFromBuffer(offset, length, longLived = false) {
let bufferOffset = offset - this.bufferStartOffset;
if (bufferOffset < 0 || bufferOffset + length > this.buffer.byteLength) {
throw new Error(`Cannot read ${length} bytes of buffer at ${bufferOffset}`);
throw new ArmariusError(`Cannot read ${length} bytes of buffer at ${bufferOffset}`);
}

if (longLived && this.buffer.byteLength - length > 512) {
Expand Down
5 changes: 3 additions & 2 deletions src/Reader/DataReader.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import BigInt from "../Util/BigInt.js";
import BigIntUtils from "../Util/BigIntUtils.js";
import ArmariusError from '../Error/ArmariusError.js';

export default class DataReader {
/** @type {TextDecoder} */ textDecoder = new TextDecoder();
Expand All @@ -15,7 +16,7 @@ export default class DataReader {
* @abstract
*/
async clone(cloneOffset = 0, cloneLength = null) {
throw new Error(`clone() is not implemented in ${this.constructor.name}.`);
throw new ArmariusError(`clone() is not implemented in ${this.constructor.name}.`);
}

/**
Expand All @@ -26,7 +27,7 @@ export default class DataReader {
* @abstract
*/
async readAt(offset, length, longLived = true) {
throw new Error(`readAt() is not implemented in ${this.constructor.name}.`);
throw new ArmariusError(`readAt() is not implemented in ${this.constructor.name}.`);
}

/**
Expand Down
6 changes: 4 additions & 2 deletions src/Util/CP437.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import ArmariusError from '../Error/ArmariusError.js';

export default class CP437 {
/** @type {number[]} */ static chars = [
0x0000, 0x263a, 0x263b, 0x2665, 0x2666, 0x2663, 0x2660, 0x2022, 0x25d8, 0x25cb, 0x25d9, 0x2642, 0x2640, 0x266a,
Expand Down Expand Up @@ -44,7 +46,7 @@ export default class CP437 {
let index = this.chars.indexOf(str.codePointAt(i));
if (index === -1) {
let char = str.charAt(i);
throw new Error(`Cannot encode character '${char}' at '${str.substring(0, i).slice(-16)}[${char}]${str.substring(i + 1, i + 17)}'`);
throw new ArmariusError(`Cannot encode character '${char}' at '${str.substring(0, i).slice(-16)}[${char}]${str.substring(i + 1, i + 17)}'`);
}
result[i] = index;
}
Expand All @@ -61,7 +63,7 @@ export default class CP437 {
let char = this.chars[value];
if (typeof char !== 'number') {
let hex = value.toString(16).padStart(4, '0');
throw new Error(`Cannot decode character 0x${hex} at '${result.slice(-16)}\\u${hex}'`);
throw new ArmariusError(`Cannot decode character 0x${hex} at '${result.slice(-16)}\\u${hex}'`);
}
result += String.fromCodePoint(char);
}
Expand Down

0 comments on commit 3138097

Please sign in to comment.