Skip to content
Snippets Groups Projects
Commit 1c4a3972 authored by Alexander Rose's avatar Alexander Rose
Browse files

support loading of zip and gz files

- only zip files with a single entry
parent 4930018a
No related branches found
No related tags found
No related merge requests found
......@@ -125,7 +125,7 @@ export const OpenFile = StateAction.build({
params: (a, ctx: PluginContext) => {
const { extensions, options } = ctx.dataFormat.registry
return {
file: PD.File({ accept: Array.from(extensions.values()).map(e => `.${e}`).join(',')}),
file: PD.File({ accept: Array.from(extensions.values()).map(e => `.${e}`).join(',') + ',.gz,.zip' }),
format: PD.Select('auto', options),
visuals: PD.Boolean(true, { description: 'Add default visuals' }),
}
......
......@@ -8,6 +8,9 @@
*/
import { Task, RuntimeContext } from '../mol-task';
import { parse, ungzip } from './zip/zip';
// import { inflate, inflateRaw, parse } from 'uzip-module';
import { utf8Read } from '../mol-io/common/utf8';
// polyfill XMLHttpRequest in node.js
const XHR = typeof document === 'undefined' ? require('xhr2') as {
......@@ -20,6 +23,12 @@ const XHR = typeof document === 'undefined' ? require('xhr2') as {
readonly UNSENT: number;
} : XMLHttpRequest
export enum DataCompressionMethod {
None,
Gzip,
Zip,
}
type DataType = 'json' | 'xml' | 'string' | 'binary'
type DataValue = 'string' | any | XMLDocument | Uint8Array
type DataResponse<T extends DataType> =
......@@ -105,18 +114,49 @@ function readData<T extends XMLHttpRequest | FileReader>(ctx: RuntimeContext, ac
});
}
function processFile<T extends DataType>(reader: FileReader, type: T): DataResponse<T> {
function getCompression(name: string) {
return /\.gz$/i.test(name) ? DataCompressionMethod.Gzip :
/\.zip$/i.test(name) ? DataCompressionMethod.Zip :
DataCompressionMethod.None
}
function decompress(data: Uint8Array, compression: DataCompressionMethod): Uint8Array {
switch (compression) {
case DataCompressionMethod.None: return data
case DataCompressionMethod.Gzip: return ungzip(data)
case DataCompressionMethod.Zip:
const parsed = parse(data.buffer)
const names = Object.keys(parsed)
if (names.length !== 1) throw new Error('can only decompress zip files with a single entry')
return parsed[names[0]] as Uint8Array
}
}
function processFile<T extends DataType>(reader: FileReader, type: T, compression: DataCompressionMethod): DataResponse<T> {
const { result } = reader
if (type === 'binary' && result instanceof ArrayBuffer) {
return new Uint8Array(result) as DataResponse<T>
} else if (type === 'string' && typeof result === 'string') {
return result as DataResponse<T>
} else if (type === 'xml' && typeof result === 'string') {
let data = result instanceof ArrayBuffer ? new Uint8Array(result) : result
if (data === null) throw new Error('no data given')
if (compression !== DataCompressionMethod.None) {
if (!(data instanceof Uint8Array)) throw new Error('need Uint8Array for decompression')
const decompressed = decompress(data, compression);
if (type === 'string') {
data = utf8Read(decompressed, 0, decompressed.length);
} else {
data = decompressed
}
}
if (type === 'binary' && data instanceof Uint8Array) {
return data as DataResponse<T>
} else if (type === 'string' && typeof data === 'string') {
return data as DataResponse<T>
} else if (type === 'xml' && typeof data === 'string') {
const parser = new DOMParser();
return parser.parseFromString(result, 'application/xml') as DataResponse<T>
} else if (type === 'json' && typeof result === 'string') {
return JSON.parse(result) as DataResponse<T>
return parser.parseFromString(data, 'application/xml') as DataResponse<T>
} else if (type === 'json' && typeof data === 'string') {
return JSON.parse(data) as DataResponse<T>
}
throw new Error(`could not get requested response data '${type}'`)
}
......@@ -126,15 +166,19 @@ function readFromFileInternal<T extends DataType>(file: File, type: T): Task<Dat
return Task.create('Read File', async ctx => {
try {
reader = new FileReader();
const compression = getCompression(file.name)
if (type === 'binary') reader.readAsArrayBuffer(file)
else reader.readAsText(file)
if (type === 'binary' || compression !== DataCompressionMethod.None) {
reader.readAsArrayBuffer(file)
} else {
reader.readAsText(file)
}
await ctx.update({ message: 'Opening file...', canAbort: true });
const fileReader = await readData(ctx, 'Reading...', reader);
await ctx.update({ message: 'Parsing file...', canAbort: false });
return processFile(fileReader, type);
return processFile(fileReader, type, compression);
} finally {
reader = void 0;
}
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment