Skip to content

Commit

Permalink
Use Zip.js to support ZIP files that do not contain compressed size i…
Browse files Browse the repository at this point in the history
…nfo (#47)
  • Loading branch information
cdauth committed Jul 18, 2024
1 parent 285bbd2 commit 181d1c7
Show file tree
Hide file tree
Showing 3 changed files with 18 additions and 30 deletions.
1 change: 1 addition & 0 deletions frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
"@ckpack/vue-color": "^1.5.0",
"@tmcw/togeojson": "^5.8.1",
"@vitejs/plugin-vue": "^5.0.4",
"@zip.js/zip.js": "^2.7.47",
"blob": "^0.1.0",
"bootstrap": "^5.3.3",
"copy-to-clipboard": "^3.3.3",
Expand Down
39 changes: 9 additions & 30 deletions frontend/src/lib/utils/files.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,36 +24,15 @@ export interface FileResultObject {
}

async function extractKmz(zip: Uint8Array): Promise<Uint8Array | undefined> {
const dataView = new DataView(zip.buffer);
let index = 0;
while (true) { // eslint-disable-line no-constant-condition
const signature = dataView.getUint32(index, true);
if (signature === 0x04034b50) { // local file
const fileNameLength = dataView.getUint16(index + 26, true);
const fileName = [...zip.slice(index + 30, index + 30 + fileNameLength)].map((b) => String.fromCharCode(b)).join("");
const startsAt = index + 30 + fileNameLength + dataView.getUint16(index + 28, true);
const compressedSize = dataView.getUint32(index + 18, true);
// According to https://developers.google.com/kml/documentation/kmzarchives#recommended-directory-structure, the first .kml
// file on the root level is used.
if (!fileName.includes("/") && fileName.toLowerCase().endsWith(".kml")) {
const compressionMethod = dataView.getUint16(index + 8, true);
const buffer = zip.slice(startsAt, startsAt + compressedSize);
if (compressionMethod === 0x00){
return buffer;
} else if (compressionMethod === 0x08) {
return new Uint8Array(await new Response(new Blob([buffer]).stream().pipeThrough(new DecompressionStream("deflate-raw"))).arrayBuffer());
} else {
throw new Error(`Unknown compression method 0x${compressionMethod.toString(16)}`);
}
} else {
index = startsAt + compressedSize;
}
} else if (signature === 0x02014b50) { // central directory
index += 46 + dataView.getUint16(index + 28, true) + dataView.getUint16(index + 30, true) + dataView.getUint16(index + 32, true);
} else if (signature === 0x06054b50) { // end of central directory
break;
} else {
throw new Error(`Unrecognized signature 0x${signature.toString(16)}`);
const { ZipReader, Uint8ArrayReader, Uint8ArrayWriter } = await import("@zip.js/zip.js");

const entries = await new ZipReader(new Uint8ArrayReader(zip)).getEntries();

for (const entry of entries) {
// According to https://developers.google.com/kml/documentation/kmzarchives#recommended-directory-structure, the first .kml
// file on the root level is used.
if (entry.filename.toLowerCase().endsWith(".kml") && !entry.filename.includes("/") && entry.getData) {
return await entry.getData(new Uint8ArrayWriter());
}
}
}
Expand Down
8 changes: 8 additions & 0 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -1862,6 +1862,13 @@ __metadata:
languageName: node
linkType: hard

"@zip.js/zip.js@npm:^2.7.47":
version: 2.7.47
resolution: "@zip.js/zip.js@npm:2.7.47"
checksum: 027c72f20babd58feb672a0a4edde9bd8630fd5350805d95afe4ad6f6470897da918ff4fd06e4c41398f391162796aac53564f80baa36acb8e07a22244ff9224
languageName: node
linkType: hard

"JSONStream@npm:0.8.0":
version: 0.8.0
resolution: "JSONStream@npm:0.8.0"
Expand Down Expand Up @@ -3978,6 +3985,7 @@ __metadata:
"@types/lodash-es": ^4.17.12
"@types/pluralize": ^0.0.33
"@vitejs/plugin-vue": ^5.0.4
"@zip.js/zip.js": ^2.7.47
blob: ^0.1.0
bootstrap: ^5.3.3
copy-to-clipboard: ^3.3.3
Expand Down

0 comments on commit 181d1c7

Please sign in to comment.