Load from String - Length in Header does not match

I am loading strings of glb files like in this example https://playground.babylonjs.com/#7F6S08#2.
Our code is pasted below. Now we get the glb files and encode them to base64. After the loading process is exactly the same. I get following error:

logger.ts:83 BJS - Unable to import meshes from blob:http://localhost/3bd4aca6-d21c-4acc-980b-bd11181c063a: Length in header does not match actual data length: 96321519 != 1516

I think the encoding from glb string to base64 but cant see what i do wrong. I encode it with this line:

							let base64String = Base64.encode(data)
						var base64_model_content = "data:base64," + base64String;
						var raw_content = BABYLON.Tools.DecodeBase64(base64_model_content);
						var blob = new Blob([raw_content]);
						var url = URL.createObjectURL(blob);
						return BABYLON.SceneLoader.Append(null, url, scene, undefined, undefined, undefined, ".glb")
							.then(function (result) {

								let bimProducts = geometryMap[checksum];
								positionMesh(result.meshes[1], bimProducts[0].position, bimProducts[0].rotation, bimProducts[0].ifc_guid);
								assetContainer.meshes.push(result.meshes[1]);

								for (let i = 1; i < bimProducts.length; i++) {
									let clone = result.meshes[1].clone(bimProducts[i].ifc_guid);
									positionMesh(clone, bimProducts[i].position, bimProducts[i].rotation, bimProducts[i].ifc_guid);
									assetContainer.meshes.push(clone);
								}
							});

I think you should setup a repro PG, it will be easier to look for the problem.

In the code you pasted there are at least two problems:

  • return BABYLON.SceneLoader.Append: you should remove the return instruction
  • Append does not return a Promise, so you should not use the .then construct

The code does work like that if I load local files into the scene and not from string, so the return and the .then function should not be the problem. I think the problem is at the encoding to base64. I cant create a PG because i cant add the .glb as a string to the PG.

When i decode the base64 string and then encode the same again i wont get the same base64 result: Do you know how they encoded the glb string the correct way in this example or one of the others in the playground: https://playground.babylonjs.com/#7F6S08#2

You can use this site to encode your glb file to base64: https://www.base64encode.org/

I did it with this site before and it didnt work.

this is my glb:

glTFø”JSON{“accessors”:[{“name”:“2ftx4ft_1_positions”,“componentType”:5126,“count”:24,“min”:[-24,0,-12],“max”:[24,2,12],“type”:“VEC3”,“bufferView”:0,“byteOffset”:0},{“name”:“2ftx4ft_1_normals”,“componentType”:5126,“count”:24,“min”:[-1,-1,-1],“max”:[1,1,1],“type”:“VEC3”,“bufferView”:0,“byteOffset”:288},{“name”:“2ftx4ft_1_texcoords”,“componentType”:5126,“count”:24,“min”:[-1.3407000303268433,-1.681399941444397],“max”:[5.362800121307373,3.6814000606536865],“type”:“VEC2”,“bufferView”:1,“byteOffset”:0},{“name”:“2ftx4ft_1_0_indices”,“componentType”:5123,“count”:36,“min”:[0],“max”:[23],“type”:“SCALAR”,“bufferView”:2,“byteOffset”:0}],“asset”:{“generator”:“obj2gltf”,“version”:“2.0”},“buffers”:[{“name”:“input”,“byteLength”:840}],“bufferViews”:[{“name”:“bufferView_0”,“buffer”:0,“byteLength”:576,“byteOffset”:0,“byteStride”:12,“target”:34962},{“name”:“bufferView_1”,“buffer”:0,“byteLength”:192,“byteOffset”:576,“byteStride”:8,“target”:34962},{“name”:“bufferView_2”,“buffer”:0,“byteLength”:72,“byteOffset”:768,“target”:34963}],“materials”:[{“name”:“wire_191191191”,“pbrMetallicRoughness”:{“baseColorFactor”:[0.5,0.5,0.5,1],“metallicFactor”:0,“roughnessFactor”:1},“emissiveFactor”:[0,0,0],“alphaMode”:“OPAQUE”,“doubleSided”:false}],“meshes”:[{“name”:“2ftx4ft_1”,“primitives”:[{“attributes”:{“POSITION”:0,“NORMAL”:1,“TEXCOORD_0”:2},“indices”:3,“material”:0,“mode”:4}]}],“nodes”:[{“name”:“2ftx4ft”,“mesh”:0}],“scene”:0,“scenes”:[{“nodes”:[0]}]}HBINÀÁ€@AÀÁ@@ÁÀÁ@ÁÀÁ@@AÀÁ@ÁÀA@@ÁÀA@ÁÀÁ@@ÁÀA@ÁÀA@@AÀA€@AÀA@@ÁÀA€@AÀÁ@@AÀÁ€@AÀA@@AÀA@@AÀÁ@@ÁÀÁ@@AÀA@@ÁÀA€@AÀÁ@ÁÀA@ÁÀÁ€@A€¿€€¿€€¿€€¿€€€¿€€€¿€€€¿€€€¿€€?€€€?€€€?€€€?€€€?€?€?€?€¿€¿€¿€¿€?€?€?€?œ+@€?ŽÈF?€?œ+@ŽÈF?œ«@€?ŽÈF?€?œ«@ŽÈF?œ+@€?€ŽÈF?€€?œ+@ŽÈF?œ«@€?ŽÈF?€?œ«@ŽÈF?œ«?8׿œ«¿œk@œ«?œk@œ«¿8׿·Ñ88׿²+@œk@²+@8׿·Ñ8œk@a


You should not copy / paste the binary, you should upload the file instead: see the Encode files into Base64 format section in the site.

I tested with a glb file I have on my computer and it does work.

That makes sense. How can i do that when i receive a stream of glb binarys… currently i am encoding them in javascript, should I now create a file first? or how would you solve that?

It seems window.btoa() should do it.

Also, you can try a google search like convert binary to base64 javascript.

Thank you so far for your help. I am not sure if the base64 string now is correct or not but I have an different error than before:

Uncaught TypeError: Cannot read property 'indexOf' of null at Function../Loading/sceneLoader.ts.SceneLoader._LoadData (sceneLoader.ts:491) at Function../Loading/sceneLoader.ts.SceneLoader.Append (sceneLoader.ts:844) at (index):101 at (index):121 at Array.forEach (<anonymous>) at onProgressFunc ((index):121) at XMLHttpRequest.onprogress (dsbim.js:72)

do you know anything about this?

You should pass an empty string and not a null string for the rootUrl parameter (1st parameter) of SceneLoader.Append.

You are right. Unfortunately I still get an error that the Length in header does not match actual data length.

I think you will have to make a PG and post a link to your glb file so that we can look further.

This is almost impossible to help without a repro of the issue in the pg:(

https://www.babylonjs-playground.com/#7F6S08#19

I managed to create one with two glb strings.

You can’t put binary data this way:

var string = 'glTFᅵᅵ';

The squares in the string are not the right characters. You should have something like \xYY with YY being the char code instead.

You should either use something like fetch to retrieve the binary data of your file from the web server or use the https://www.base64encode.org/ site to directly retrieve the base64 encoded data of your file and paste it in the PG.

I cant manage to find the correct char code for the binary data string. Do you know which one is used for glb?

I receive the string like that, do I need to convert it after or is it not possible to load it from that situation?

Where does it come from? Is it from fetching the file from a web server? Can you show the code (preferably in PG) if it’s coming from code?

This string is not usable, there could be some non displayable characters in the binary representation of the glb that can’t be captured in such strings.

I receive the data as a stream via AJAX call from the backend. This is our Stream Function

export async function streamData(url = "", data = {}, onprogressFunc = (checksum, data) => null) {
let lastResponseLength = false;
let currentText;
let restResponse = "";

return $.ajax({
    method: "POST",
    url: url,
    data: JSON.stringify(data),
    dataType: "json",
    headers: {
        "Content-Type": "application/json",
        "Access-Control-Allow-Origin": "*",
    },
    processData: false,
    xhrFields: {
        // Getting on progress streaming response
        onprogress: function (e) {
            let progressResponse;
            let response = e.currentTarget.response;

            if (lastResponseLength === false) {
                // beginning of the message
                progressResponse = response;
                lastResponseLength = response.length;
                currentText = progressResponse;
            }
            else {
                progressResponse = response.substring(lastResponseLength);
                lastResponseLength = response.length;
                currentText = restResponse + progressResponse;
            }
            let responseLength = currentText.length;
            let currentPosition = 0;
            let checksum;
            let data;
            while (currentPosition <= responseLength) {
                if (responseLength - currentPosition < CHECKSUM_LENGTH) {
                    break;
                }
                checksum = currentText.slice(currentPosition, currentPosition + CHECKSUM_LENGTH);
                // read the byteSize until the break character is found and parse it as an int.
                let nextStop = currentText.indexOf(BREAK_CHARACTER, currentPosition + CHECKSUM_LENGTH);
                if (nextStop == -1) {
                    break;
                }
                data = currentText.slice(currentPosition + CHECKSUM_LENGTH, nextStop);
                currentPosition = nextStop + 7;
                onprogressFunc(checksum, data);
            }
            restResponse = currentText.slice(currentPosition);
        }
    }
});
}

in the onprogressFunc the binary data will be send from the backend and received in the frontend. Is there any way we can make that string usable or do we need to find a new solution?

You should look for “reading binary data with jquery” in google, in your request you instruct jQuery that the data you download are json, which is not right.

I would advice to first use fetch as a proof of concept that retrieving the file as a binary stream does work, then switch to jQuery to do it (or not - you may consider using fetch instead).

Here’s an example of fetch usage: