Public
Edited
Mar 14
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
{
yield htl.html`Processing, please wait...`
if (!zip) {
yield htl.html`Drop file above`
} else {
const url = URL.createObjectURL(
new Blob([zip.buffer.transferToFixedLength()], { type: "application/zip-compressed" })
);
invalidation.then(() => {
URL.revokeObjectURL(url);
});
yield htl.html`
<a href=${url} download=${'CFB_'+files[0].name+'_'+Date.now()+'.zip'} target="_blank">Click to download</a>
`;
}
}
Insert cell
zip = {
if (!parsed?.cfb) return null
const MAX_ZIP_SIZE_IN_BYTES = 500 * 1024 * 1024
const MAX_POSSIBLE_SIZE_PER_FILE = 50 * 1024 * 1024

const promise = new Promise((resolve, reject) => {
const buffer = new ArrayBuffer(1024, { maxByteLength: MAX_ZIP_SIZE_IN_BYTES });
const blob = new Uint8Array(buffer);
let totalSize = 0;
const zip = new fflate.Zip((err, dat, final) => {
if (err) {
reject(err);
}
const offset = totalSize;
totalSize += dat.byteLength;

// make buffer resizable
if (buffer.byteLength < totalSize) {
buffer.resize(totalSize);
}
blob.set(dat, offset);

if (final) {
console.log('final: ' + final)
resolve(blob)
}
});
const cfb = parsed.cfb;
// root object
function walk(entry, parent) {
if (entry.objectType === 2) {
// stream object
const u8arr = cfbReader.readStreamObjectContent(
cfb,
Number(entry.startingSectorLocation),
Number(entry.streamSize)
);
const exts = sigs.find((it) => it.filter(u8arr))?.ext;
let suffix = "";
if (exts && !exts.some((it) => entry.name.endsWith(it))) {
suffix = "." + exts[0];
}
const file = new fflate.AsyncZipDeflate(`${parent}/${entry.name}${suffix}`);
zip.add(file);
file.push(u8arr, true);
}
if (entry.leftSibling) {
walk(entry.leftSibling, parent);
}
if (entry.rightSibling) {
walk(entry.rightSibling, parent);
}
if (entry.child) {
walk(entry.child, `${parent}/${entry.name}`);
}
}
walk(parsed.entries[0].child, "root_" + Date.now());
zip.end();
});

return await promise
}
Insert cell
Insert cell
parsed = {
if (files.length === 0) return null
const buf = await files[0].file.arrayBuffer()
const cfb = new cfbReader.CompoundFileBinary(buf)

const entries = []
let sec = 0
let dirOffset
let stop = false
while (!stop) {
try {
dirOffset = cfb.getDirectorySectorOffsetAt(sec)
} catch (err) {
stop = true
break
}
entries.push(...cfbReader.readDirectorySectorInfoV3(cfb, sec).entries)
++sec
}
for (const it of entries) {
it.child = entries[it.childID]
it.leftSibling = entries[it.leftSiblingID]
it.rightSibling = entries[it.rightSiblingID]
}
const file = cfbReader.readDirectoryEntryInfo(cfb, 10)
const blob = cfbReader.readStreamObjectContent(cfb, Number(file.startingSectorLocation), Number(file.streamSize))
// const file6 = cfbReader.readStreamObjectContent(cfb, 128, 2384)
return {
cfb,
entries,
file,
blob,
// file6
}
}
Insert cell
cfbReader = importPkg('https://pkg.pr.new/UnluckyNinja/cfb-reader@e63ab3b', 'dist/cfb-reader.browser.mjs')
Insert cell
sigs = {
return [{
filter: (typedArray)=>{
const sig = [0xFF, 0xD8, 0xFF]
if (typedArray.length < sig.length) return false
return sig.every((v,i)=>{
return typedArray[i] === v
})
},
ext: ['jpg', 'jpeg'],
},{
filter: (typedArray)=>{
const sig = [0x47, 0x49, 0x46, 0x38]
if (typedArray.length < sig.length) return false
return sig.every((v,i)=>{
return typedArray[i] === v
})
},
ext: ['gif'],
},{
filter: (typedArray)=>{
const sig = [0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A]
if (typedArray.length < sig.length) return false
return sig.every((v,i)=>{
return typedArray[i] === v
})
},
ext: ['png'],
},{
filter: (typedArray)=>{
const sig0 = [0x52, 0x49, 0x46, 0x46]
const sig8 = [0x57, 0x45, 0x42, 0x50]
if (typedArray.length < 12) return false
return sig0.every((v,i)=>{
return typedArray[i] === v
}) && sig8.every((v,i)=>{
return typedArray[i+8] === v
})
},
ext: ['webp'],
},{
filter: (typedArray)=>{
const sig = [0x42, 0x4D]
if (typedArray.length < sig.length) return false
return sig.every((v,i)=>{
return typedArray[i] === v
})
},
ext: ['bmp'],
}]
}
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell

Purpose-built for displays of data

Observable is your go-to platform for exploring data and creating expressive data visualizations. Use reactive JavaScript notebooks for prototyping and a collaborative canvas for visual data exploration and dashboard creation.
Learn more