A JavaScript library to read, write, and merge ZIP archives in web browsers.

Overview

Armarius

About

Armarius is a JavaScript library to read, write, and merge ZIP archives in web browsers.

This library mainly focuses on a low memory footprint, especially when reading archives with tens of thousands of entries, and the ability to merge archives without decompressing and recompressing all entries.

For deflate/inflate support, this library depends on Pako.

Installation

Armarius can be installed using npm:

npm install amarius

It can then be loaded as an ES Module:

import * as armarius from 'armarius';

You should also be able to bundle the library using esbuild or webpack.

Usage

Reading a ZIP archive

To read an archive, a DataReader object is required. This library provides DataReader implementations for File and ArrayBuffer objects. Other readers can be implemented by extending the DataReader class.

let fileInput = document.getElementById('file-input');
let reader = armarius.BrowserFileReader(fileInput.files[0]);

A ReadArchive can then be created from the reader.

let archive = new armarius.ReadArchive(reader, options);
await archive.init();

The ReadArchive constructor optionally accepts an ReadArchiveOptions object with the following properties:

Name Type Description
centralDirectoryBufferSize number Buffer size used when reading central directory contents.
Larger buffer sizes may improve performance, but also increase RAM usage.
createEntryIndex boolean Whether an index of all central directory entries should be created the first time they are read.
Massively increases performance when using findEntry multiple times.
entryOptions EntryOptions Options passed to each created Entry object.

EntryOptions can have the following properties:

Name Type Description
dataProcessors Map<number, typeof DataProcessor> Map of compressionMethod => DataProcessor
Can be used to implement custom compression methods

Reading all archive entries

let entries = await archive.getAllEntries();

Since this method will load all entries (not including their compressed data) into memory, it is not recommended when working with large archives.

Iterating over archive entries

let iterator = await archive.getEntryIterator();

let entry;
while (entry = await iterator.next()) {
    console.log(await entry.getFileNameString());
}

Finding specific entries

let entry = await archive.findEntry('some/file.txt');
console.log(await entry.getFileNameString());

In most cases, this method is faster than iterating through all archive entries, since an internal index is used to find files quickly.

Reading entry data

Reading a full entry

let entry = await archive.findEntry('example.txt');
let data = await entry.getData();

// Decode UTF-8
let decoder = new TextDecoder();
let text = decoder.decode(data);

console.log(text);

Reading entry data in chunks

let entry = await archive.findEntry('example.txt');
let entryReader = await entry.getDataReader();

let chunk;
while (chunk = await reader.read(1024 * 64)) {
    console.log(chunk);
}

Note that the length parameter passed to EntryDataReader.read is the length of the compressed data read from the file. Since this data is decompressed, the size of the returned chunk might differ.

Also note that an empty chunk returned from EntryDataReader.read does not necessarily indicate that all data has been read. After all data was read, null will be returned instead.

Writing archives

New archives can be created using a WriteArchive object. The WriteArchive constructor needs to be passed a function that generates new EntrySource objects when needed.

Additionally, a WriteArchiveOptions object can be passed:

Name Type Description
forceZIP64 boolean Whether ZIP64 structures should always be created, even if not required by the archive content.
async function generateNextEntrySource() {
    //Create a new EntrySource
    return null;
}

let writeArchive = new armarius.WriteArchive(generateNextEntrySource, options);

Generating entries

Whenever a new entry needs to be written to the archive, the nextEntryFunction will be called. It should return a new Instance of EntrySource, or null if no more entries should be added to the archive.

This simple example will generate an archive that contains 10 text files:

let encoder = new TextEncoder();
let i = 0;

function generateNextEntrySource() {
    if (i >= 10) {
        return null;
    }

    let fileName = `file-${i}`;
    let fileContent = encoder.encode(`Content of file ${i}`);

    let reader = new armarius.ArrayBufferReader(fileContent.buffer);
    let entry = new armarius.DataReaderEntrySource(reader, {fileName: fileName});
    i++;
    return entry;
}

let writeArchive = new armarius.WriteArchive(generateNextEntrySource);

Any EntrySource accepts an EntrySourceOptions object with the following properties:

Name Type Description
fileComment string Entry file comment
fileName string Entry file name
forceUTF8FileName boolean Always encode the filename and file comment in UTF-8, even if it could be encoded in CP437
compressionMethod number Compression method that should be used for this entry. By default, this library only supports 0 (Store) and 8 (Deflate). More compression methods can be added using the dataProcessors option.

When using an ArchiveEntryEntrySource, this option will be ignored.
forceZIP64 boolean Whether ZIP64 structures should always be created, even if not required by the content.
minMadeByVersion number The minimum madeByVersion value to be used for this entry. If a higher version is required (e.g. because ZIP64) is used, it will be set automatically and this option will be ignored.
minExtractionVersion number The minimum extractionVersion value to be used for this entry. If a higher version is required (e.g. because ZIP64) is used, it will be set automatically and this option will be ignored.
modTime Date Last modified time of the entry
acTime Date Last access time of the entry. This option is ignored if extendedTimeStampField is false.
crTime Date File creation time of the entry. This option is ignored if extendedTimeStampField is false.
unicodeFileNameField boolean Whether a Unicode Path Extra Field should be added
unicodeCommentField boolean Whether a Unicode Comment Extra Field should be added
extendedTimeStampField boolean Whether an Extended Timestamp Extra Field should be added
internalFileAttributes number See https://pkware.cachefly.net/webdocs/casestudies/APPNOTE.TXT
externalFileAttributes number See https://pkware.cachefly.net/webdocs/casestudies/APPNOTE.TXT
dataProcessors Map<number, typeof DataProcessor> Map of compressionMethod => DataProcessor
Can be used to implement custom compression methods

Reading output chunks

The generated archive can be read using the getNextChunk function.

let chunk;
while (chunk = await writeArchive.getNextChunk()) {
    console.log('New archive chunk:', chunk);
}

Merging ZIP archives

Armarius supports merging ZIP archives without decompressing and recompressing individual entries.

let archies = [myReadArchive1, myReadArchive2];

let merger = new armarius.ArchiveMerger(archives, options);
let outputWriteArchive = merger.getOutputArchive();

let chunk;
while (chunk = await outputWriteArchive.getNextChunk()) {
    console.log('New archive chunk:', chunk);
}

The ArchiveMerger constructor accepts a list of ReadArchive or MergeSource objects and a MergeOptions object with the following properties:

Name Type Description
entrySourceOptions EntrySourceOptions Options passed to each created EntrySource object
writeArchiveOptions WriteArchiveOptions Options passed to the output WriteArchive
nextPrependingEntryFunction Function Function generating EntrySource objects that are added to the output archive before the contents of the input archives

MergeSource objects

A MergeSource object allows greater control over how a source archive is merged into the destination archive.

let mergeSource = new armarius.MergeSource(readArchive);
mergeSource
    .setBasePath('base/path/within/the/source/archive')
    .setDestinationPath('path/within/the/destination/archive')
    .setFilter((entry) => {
        if (entry.getFileNameString().endsWith('.rar')) {
            return false; //Filter entry
        } else {
            return true; //Allow entry
        }
    });

License

Armarius is open source software released under the MIT license, see license.

Contributing

You can contribute to this project by forking the repository, adding your changes to your fork, and creating a pull request.

You might also like...

Write and read comments on every page with a simple plug-in for your browser

Write and read comments on every page with a simple plug-in for your browser

Licom - comments on every webpage Licom is a simple plugin for your browser that adds the feature to leave comments on every page, even if it doesn't

Aug 4, 2022

Read without losing the plot. Well Read helps you organize your notes about books you're reading, so you're never lost when starting a new volume.

Read without losing the plot. Well Read helps you organize your notes about books you're reading, so you're never lost when starting a new volume.

Well Read Well Read is a website for tracking your reading of long book series. I made this to track how many pages I read in a session and to better

Dec 15, 2022

Tool for GitHub/GitLab to keep Repositories/Projects you are interested in and their Pull/Merge Requests in desktop Tray Menu

Tool for GitHub/GitLab to keep Repositories/Projects you are interested in and their Pull/Merge Requests in desktop Tray Menu. More info in User Guide.

Jul 31, 2022

Merge multiple Prisma schema files, model inheritance, resolving name conflicts and timings reports, all in a simple tool.

Prisma Util What is Prisma Util? • How to use? • The configuration file • Support What is Prisma Util? Prisma Util is an easy to use tool that merges

Dec 28, 2022

Learn GraphQL by building a blogging engine. Create resolvers, write schemas, write queries, design the database, test and also deploy.

GraphQL Blog graphqlblog.com Learn GraphQL by building a blogging engine. Create resolvers, write schemas, write queries, design the database, test an

Aug 17, 2022

a cobbled together alternative UI to launchdarkly, allowing read/write access via LD API access token

a cobbled together alternative UI to launchdarkly, allowing read/write access via LD API access token

discount-launchdarkly a cobbled together alternative UI to launchdarkly, allowing read/write access via LD API access token setup make sure you have a

Oct 19, 2022

💾 Read/Write Figma Files as JSON

💾 Read/Write Figma Files as JSON

Figma To JSON 💾 A set of tools to programatically work with Figma files as JSON. You can use these to read and write your own figma documents without

Jan 3, 2023

Tool made to easily merge multiple GTA 5 vehicle meta files.

mmVehiclesMetaMerger Tool made to easily merge multiple GTA5 vehicle meta files. Showcase Go to Youtube video. Download Click here to go to the releas

Jan 2, 2023

mior - Merge into one RSS

mior - Merge into one RSS

mior Merge into one RSS mior is a lightweight web service to filter and merge multiple RSS feeds into one. It provides a pure web-based, responsive us

Nov 6, 2022
Owner
Aternos
Minecraft servers. Free. Forever.
Aternos
Reference for How to Write an Open Source JavaScript Library - https://egghead.io/series/how-to-write-an-open-source-javascript-library

Reference for How to Write an Open Source JavaScript Library The purpose of this document is to serve as a reference for: How to Write an Open Source

Sarbbottam Bandyopadhyay 175 Dec 24, 2022
An online library for adding and removing a different number of books from a user collection, keeping track of the books you've read and the one's you are yet to read

Awesmoe Books A Website demo for our project of book store, The website has ability of adding and removing you books from yor library, Thats reflects

zieeco 11 Jul 8, 2022
Bys is an npm/yarn library to merge your js and ts files into one file.

Bundle your scripts (bys) Bys is an npm/yarn library to merge your js and ts files into one file. Installation Use the npm or yarn package manager to

FlamesX128 3 Dec 8, 2022
Merge multiple JSON files - Vanilla JavaScript and HTML (graphic mode: browser+explorer)

JSON Merger Usage First, git clone project git clone https://github.com/mtacnet/json-merger.git Move to cloned repository and open generate.html with

Tac 1 Sep 18, 2022
Automaticly parses known pocket ips patch resources, scans folders or zip files for matching roms and applies the patches.

Pocket Automaton Automaticly parses known pocket ips patch resources, scans folders or zip files for matching roms and applies the patches. Usage pock

null 3 Nov 27, 2022
Pack all your node_modules and other files you want inside your project to a zip file.

?? Node Modules Packer Use Cases | Usage | Examples | Headless | Benchmarks | Reference This is a library to package all your node_modules and other f

Vinicius Lourenço 14 Dec 1, 2022
Javascript client for Sanity. Works in node.js and modern browsers (older browsers needs a Promise polyfill).

@sanity/client Javascript client for Sanity. Works in node.js and modern browsers (older browsers needs a Promise polyfill). Requirements Sanity Clien

Sanity 23 Nov 29, 2022
Serve file server with single zip file as file system in Deno.

zipland Serve file server with one-single zip file in Deno. Support zip just zip32 with deflated or uncompressed serving plaintext deflate Examples Yo

Yongwook Choi 18 Nov 2, 2022
This package generates a unique ID/String for different browsers. Like chrome, Firefox and any other browsers which supports canvas and audio Fingerprinting.

Broprint.js The world's easiest, smallest and powerful visitor identifier for browsers. This package generates a unique ID/String for different browse

Rajesh Royal 68 Dec 25, 2022