How to merge two array buffers into one?
Asked Answered
D

2

5

I have a big blob for a rar file. To uncompress it I had to use this library unrar.js

The blob I am testing with is about 23MB, to readAsArrayBuffer then feed it to unrar.js I had to slice it.

For some reason unrar.js does not play well with sliced blobs--it would throw an unknown archive type error if the sliced blob range does not start with 0 or end with blob.size . -weird?-

The only workaround I can think of is to read the blob as slices then collect it back again in the onloadend function. -is that even possible?-

Collect the array buffers in one array then feed it to unrar.js to uncompress the file as if it was read from one blob.

If this sound too annoying for you I would appreciate any other way to read rar files in javascript/phonegap environment.

Darnelldarner answered 12/2, 2016 at 21:35 Comment(0)
P
6

I am not sure I fully understand why the blob is segmented, but if they are, you could probably do something like:

var blobs = [new Blob(['Hello ']),new Blob(['World'])];
var buffers = [];
var buffersFilled = 0;

for(var i=0; i < blobs.length; i++) {
  buffers.push(new Uint8Array()); 
}


for(var i=0; i<blobs.length; i++) {
    var fileReader = new FileReader();
  
    fileReader.onload = (function(i,fileReader) {
      return function(){
        buffers[i] = fileReader.result;
        isBuffersDone();
      }
    })(i,fileReader);
    fileReader.readAsArrayBuffer(blobs[i]);
}

function isBuffersDone() {
  buffersFilled++;
  if(buffersFilled >= blobs.length) {
    var result = spliceBuffers();  
    
    //*****************
    // result is the spliced together buffers that could be given to unrar.js
    console.log(result);
  }
}

function spliceBuffers() {
  var tmpResult = new Uint8Array();
  
  for(var i=0; i < buffers.length; i++) {
    tmpResult = appendBuffer(tmpResult, buffers[i]);
  }
  
  return tmpResult;
}




function appendBuffer(buffer1, buffer2) {
  var tmp = new Uint8Array(buffer1.byteLength + buffer2.byteLength);
  tmp.set(new Uint8Array(buffer1), 0);
  tmp.set(new Uint8Array(buffer2), buffer1.byteLength);
  return tmp;
};

While the above works, take it with a grain of salt because with my limited understanding of what you are doing I don't know this is the best solution

Pursuivant answered 13/2, 2016 at 22:47 Comment(2)
This is exactly what I want to do. Will have to simplify it a bit though. One question result is an array buffer like fileReader.result right?Darnelldarner
@Darnelldarner result is of type Uint8Array. To get to an ArrayBuffer like fileReader.result provides, you will need to use result.buffer, this will give you the ArrayBuffer that if referenced but the Uint8Array. See: developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…Pursuivant
P
1

Ive updated the code from Dustin - now it works magnitudes faster

function spliceBuffers(buffers) {

  const len = buffers.map((buffer) => buffer.byteLength).reduce((prevLength, curr) => {return prevLength + curr}, 0);
  
  const tmp = new Uint8Array(len);

  let bufferOffset = 0;
  
  for(var i=0; i < buffers.length; i++) {
    tmp.set(new Uint8Array(buffers[i]), bufferOffset);
    bufferOffset += buffers[i].byteLength;
  }
  
  return tmp;
}
Perdomo answered 16/5 at 13:43 Comment(1)
As it’s currently written, your answer is unclear. Please edit to add additional details that will help others understand how this addresses the question asked. You can find more information on how to write good answers in the help center.Scutiform

© 2022 - 2024 — McMap. All rights reserved.