@loaders.gl/i3s 4.0.0-alpha.1 → 4.0.0-alpha.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/arcgis-webscene-loader.d.ts +7 -0
- package/dist/arcgis-webscene-loader.d.ts.map +1 -0
- package/dist/arcgis-webscene-loader.js +28 -0
- package/dist/bundle.d.ts +2 -0
- package/dist/bundle.d.ts.map +1 -0
- package/dist/bundle.js +2 -2
- package/dist/dist.min.js +15501 -0
- package/dist/es5/arcgis-webscene-loader.js +40 -0
- package/dist/es5/arcgis-webscene-loader.js.map +1 -0
- package/dist/es5/bundle.js +6 -0
- package/dist/es5/bundle.js.map +1 -0
- package/dist/es5/i3s-attribute-loader.js +195 -0
- package/dist/es5/i3s-attribute-loader.js.map +1 -0
- package/dist/es5/i3s-building-scene-layer-loader.js +46 -0
- package/dist/es5/i3s-building-scene-layer-loader.js.map +1 -0
- package/dist/es5/i3s-content-loader.js +56 -0
- package/dist/es5/i3s-content-loader.js.map +1 -0
- package/dist/es5/i3s-loader.js +193 -0
- package/dist/es5/i3s-loader.js.map +1 -0
- package/dist/es5/i3s-node-page-loader.js +39 -0
- package/dist/es5/i3s-node-page-loader.js.map +1 -0
- package/dist/es5/i3s-slpk-loader.js +20 -0
- package/dist/es5/i3s-slpk-loader.js.map +1 -0
- package/dist/es5/index.js +82 -0
- package/dist/es5/index.js.map +1 -0
- package/dist/es5/lib/helpers/i3s-nodepages-tiles.js +312 -0
- package/dist/es5/lib/helpers/i3s-nodepages-tiles.js.map +1 -0
- package/dist/es5/lib/parsers/constants.js +72 -0
- package/dist/es5/lib/parsers/constants.js.map +1 -0
- package/dist/es5/lib/parsers/parse-arcgis-webscene.js +158 -0
- package/dist/es5/lib/parsers/parse-arcgis-webscene.js.map +1 -0
- package/dist/es5/lib/parsers/parse-i3s-attribute.js +76 -0
- package/dist/es5/lib/parsers/parse-i3s-attribute.js.map +1 -0
- package/dist/es5/lib/parsers/parse-i3s-building-scene-layer.js +65 -0
- package/dist/es5/lib/parsers/parse-i3s-building-scene-layer.js.map +1 -0
- package/dist/es5/lib/parsers/parse-i3s-tile-content.js +510 -0
- package/dist/es5/lib/parsers/parse-i3s-tile-content.js.map +1 -0
- package/dist/es5/lib/parsers/parse-i3s.js +116 -0
- package/dist/es5/lib/parsers/parse-i3s.js.map +1 -0
- package/dist/es5/lib/parsers/parse-slpk/parse-slpk.js +107 -0
- package/dist/es5/lib/parsers/parse-slpk/parse-slpk.js.map +1 -0
- package/dist/es5/lib/parsers/parse-slpk/slpk-archieve.js +258 -0
- package/dist/es5/lib/parsers/parse-slpk/slpk-archieve.js.map +1 -0
- package/dist/es5/lib/parsers/parse-zip/buffer-file-provider.js +46 -0
- package/dist/es5/lib/parsers/parse-zip/buffer-file-provider.js.map +1 -0
- package/dist/es5/lib/parsers/parse-zip/cd-file-header.js +84 -0
- package/dist/es5/lib/parsers/parse-zip/cd-file-header.js.map +1 -0
- package/dist/es5/lib/parsers/parse-zip/file-provider.js +2 -0
- package/dist/es5/lib/parsers/parse-zip/file-provider.js.map +1 -0
- package/dist/es5/lib/parsers/parse-zip/local-file-header.js +72 -0
- package/dist/es5/lib/parsers/parse-zip/local-file-header.js.map +1 -0
- package/dist/es5/lib/utils/convert-i3s-obb-to-mbs.js +17 -0
- package/dist/es5/lib/utils/convert-i3s-obb-to-mbs.js.map +1 -0
- package/dist/es5/lib/utils/customize-/321/201olors.js +184 -0
- package/dist/es5/lib/utils/customize-/321/201olors.js.map +1 -0
- package/dist/es5/lib/utils/url-utils.js +33 -0
- package/dist/es5/lib/utils/url-utils.js.map +1 -0
- package/dist/es5/types.js +26 -0
- package/dist/es5/types.js.map +1 -0
- package/dist/es5/workers/i3s-content-worker-node.js +7 -0
- package/dist/es5/workers/i3s-content-worker-node.js.map +1 -0
- package/dist/es5/workers/i3s-content-worker.js +6 -0
- package/dist/es5/workers/i3s-content-worker.js.map +1 -0
- package/dist/esm/arcgis-webscene-loader.js +16 -0
- package/dist/esm/arcgis-webscene-loader.js.map +1 -0
- package/dist/esm/bundle.js +4 -0
- package/dist/esm/bundle.js.map +1 -0
- package/dist/esm/i3s-attribute-loader.js +119 -0
- package/dist/esm/i3s-attribute-loader.js.map +1 -0
- package/dist/esm/i3s-building-scene-layer-loader.js +19 -0
- package/dist/esm/i3s-building-scene-layer-loader.js.map +1 -0
- package/dist/esm/i3s-content-loader.js +30 -0
- package/dist/esm/i3s-content-loader.js.map +1 -0
- package/dist/esm/i3s-loader.js +87 -0
- package/dist/esm/i3s-loader.js.map +1 -0
- package/dist/esm/i3s-node-page-loader.js +15 -0
- package/dist/esm/i3s-node-page-loader.js.map +1 -0
- package/dist/esm/i3s-slpk-loader.js +13 -0
- package/dist/esm/i3s-slpk-loader.js.map +1 -0
- package/dist/esm/index.js +11 -0
- package/dist/esm/index.js.map +1 -0
- package/dist/esm/lib/helpers/i3s-nodepages-tiles.js +198 -0
- package/dist/esm/lib/helpers/i3s-nodepages-tiles.js.map +1 -0
- package/dist/esm/lib/parsers/constants.js +57 -0
- package/dist/esm/lib/parsers/constants.js.map +1 -0
- package/dist/esm/lib/parsers/parse-arcgis-webscene.js +70 -0
- package/dist/esm/lib/parsers/parse-arcgis-webscene.js.map +1 -0
- package/dist/esm/lib/parsers/parse-i3s-attribute.js +60 -0
- package/dist/esm/lib/parsers/parse-i3s-attribute.js.map +1 -0
- package/dist/esm/lib/parsers/parse-i3s-building-scene-layer.js +39 -0
- package/dist/esm/lib/parsers/parse-i3s-building-scene-layer.js.map +1 -0
- package/dist/esm/lib/parsers/parse-i3s-tile-content.js +435 -0
- package/dist/esm/lib/parsers/parse-i3s-tile-content.js.map +1 -0
- package/dist/esm/lib/parsers/parse-i3s.js +83 -0
- package/dist/esm/lib/parsers/parse-i3s.js.map +1 -0
- package/dist/esm/lib/parsers/parse-slpk/parse-slpk.js +41 -0
- package/dist/esm/lib/parsers/parse-slpk/parse-slpk.js.map +1 -0
- package/dist/esm/lib/parsers/parse-slpk/slpk-archieve.js +107 -0
- package/dist/esm/lib/parsers/parse-slpk/slpk-archieve.js.map +1 -0
- package/dist/esm/lib/parsers/parse-zip/buffer-file-provider.js +23 -0
- package/dist/esm/lib/parsers/parse-zip/buffer-file-provider.js.map +1 -0
- package/dist/esm/lib/parsers/parse-zip/cd-file-header.js +37 -0
- package/dist/esm/lib/parsers/parse-zip/cd-file-header.js.map +1 -0
- package/dist/esm/lib/parsers/parse-zip/file-provider.js +2 -0
- package/dist/esm/lib/parsers/parse-zip/file-provider.js.map +1 -0
- package/dist/esm/lib/parsers/parse-zip/local-file-header.js +25 -0
- package/dist/esm/lib/parsers/parse-zip/local-file-header.js.map +1 -0
- package/dist/esm/lib/utils/convert-i3s-obb-to-mbs.js +9 -0
- package/dist/esm/lib/utils/convert-i3s-obb-to-mbs.js.map +1 -0
- package/dist/esm/lib/utils/customize-/321/201olors.js +98 -0
- package/dist/esm/lib/utils/customize-/321/201olors.js.map +1 -0
- package/dist/esm/lib/utils/url-utils.js +28 -0
- package/dist/esm/lib/utils/url-utils.js.map +1 -0
- package/dist/esm/types.js +18 -0
- package/dist/esm/types.js.map +1 -0
- package/dist/esm/workers/i3s-content-worker-node.js +5 -0
- package/dist/esm/workers/i3s-content-worker-node.js.map +1 -0
- package/dist/esm/workers/i3s-content-worker.js +4 -0
- package/dist/esm/workers/i3s-content-worker.js.map +1 -0
- package/dist/i3s-attribute-loader.d.ts +21 -0
- package/dist/i3s-attribute-loader.d.ts.map +1 -0
- package/dist/i3s-attribute-loader.js +155 -132
- package/dist/i3s-building-scene-layer-loader.d.ts +6 -0
- package/dist/i3s-building-scene-layer-loader.d.ts.map +1 -0
- package/dist/i3s-building-scene-layer-loader.js +23 -18
- package/dist/i3s-content-loader.d.ts +6 -0
- package/dist/i3s-content-loader.d.ts.map +1 -0
- package/dist/i3s-content-loader.js +29 -22
- package/dist/i3s-content-worker-node.js +197 -0
- package/dist/i3s-content-worker-node.js.map +7 -0
- package/dist/i3s-content-worker.js +2308 -1376
- package/dist/i3s-loader.d.ts +11 -0
- package/dist/i3s-loader.d.ts.map +1 -0
- package/dist/i3s-loader.js +88 -81
- package/dist/i3s-node-page-loader.d.ts +7 -0
- package/dist/i3s-node-page-loader.d.ts.map +1 -0
- package/dist/i3s-node-page-loader.js +20 -20
- package/dist/i3s-slpk-loader.d.ts +13 -0
- package/dist/i3s-slpk-loader.d.ts.map +1 -0
- package/dist/i3s-slpk-loader.js +20 -0
- package/dist/index.d.ts +12 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +23 -5
- package/dist/lib/helpers/i3s-nodepages-tiles.d.ts +74 -0
- package/dist/lib/helpers/i3s-nodepages-tiles.d.ts.map +1 -0
- package/dist/lib/helpers/i3s-nodepages-tiles.js +232 -219
- package/dist/lib/parsers/constants.d.ts +40 -0
- package/dist/lib/parsers/constants.d.ts.map +1 -0
- package/dist/lib/parsers/constants.js +87 -42
- package/dist/lib/parsers/parse-arcgis-webscene.d.ts +7 -0
- package/dist/lib/parsers/parse-arcgis-webscene.d.ts.map +1 -0
- package/dist/lib/parsers/parse-arcgis-webscene.js +88 -0
- package/dist/lib/parsers/parse-i3s-attribute.d.ts +12 -0
- package/dist/lib/parsers/parse-i3s-attribute.d.ts.map +1 -0
- package/dist/lib/parsers/parse-i3s-attribute.js +87 -62
- package/dist/lib/parsers/parse-i3s-building-scene-layer.d.ts +9 -0
- package/dist/lib/parsers/parse-i3s-building-scene-layer.d.ts.map +1 -0
- package/dist/lib/parsers/parse-i3s-building-scene-layer.js +41 -38
- package/dist/lib/parsers/parse-i3s-tile-content.d.ts +4 -0
- package/dist/lib/parsers/parse-i3s-tile-content.d.ts.map +1 -0
- package/dist/lib/parsers/parse-i3s-tile-content.js +460 -415
- package/dist/lib/parsers/parse-i3s.d.ts +6 -0
- package/dist/lib/parsers/parse-i3s.d.ts.map +1 -0
- package/dist/lib/parsers/parse-i3s.js +92 -73
- package/dist/lib/parsers/parse-slpk/parse-slpk.d.ts +4 -0
- package/dist/lib/parsers/parse-slpk/parse-slpk.d.ts.map +1 -0
- package/dist/lib/parsers/parse-slpk/parse-slpk.js +54 -0
- package/dist/lib/parsers/parse-slpk/slpk-archieve.d.ts +38 -0
- package/dist/lib/parsers/parse-slpk/slpk-archieve.d.ts.map +1 -0
- package/dist/lib/parsers/parse-slpk/slpk-archieve.js +142 -0
- package/dist/lib/parsers/parse-zip/buffer-file-provider.d.ts +37 -0
- package/dist/lib/parsers/parse-zip/buffer-file-provider.d.ts.map +1 -0
- package/dist/lib/parsers/parse-zip/buffer-file-provider.js +47 -0
- package/dist/lib/parsers/parse-zip/cd-file-header.d.ts +27 -0
- package/dist/lib/parsers/parse-zip/cd-file-header.d.ts.map +1 -0
- package/dist/lib/parsers/parse-zip/cd-file-header.js +48 -0
- package/dist/lib/parsers/parse-zip/file-provider.d.ts +31 -0
- package/dist/lib/parsers/parse-zip/file-provider.d.ts.map +1 -0
- package/dist/lib/parsers/parse-zip/file-provider.js +2 -0
- package/dist/lib/parsers/parse-zip/local-file-header.d.ts +25 -0
- package/dist/lib/parsers/parse-zip/local-file-header.d.ts.map +1 -0
- package/dist/lib/parsers/parse-zip/local-file-header.js +34 -0
- package/dist/lib/utils/convert-i3s-obb-to-mbs.d.ts +2 -0
- package/dist/lib/utils/convert-i3s-obb-to-mbs.d.ts.map +1 -0
- package/dist/lib/utils/convert-i3s-obb-to-mbs.js +19 -8
- package/dist/lib/utils/customize-/321/201olors.d.ts +14 -0
- package/dist/lib/utils/customize-/321/201olors.d.ts.map +1 -0
- package/dist/lib/utils/customize-/321/201olors.js +104 -0
- package/dist/lib/utils/url-utils.d.ts +22 -0
- package/dist/lib/utils/url-utils.d.ts.map +1 -0
- package/dist/lib/utils/url-utils.js +41 -29
- package/dist/types.d.ts +1065 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +20 -2
- package/dist/workers/i3s-content-worker-node.d.ts +2 -0
- package/dist/workers/i3s-content-worker-node.d.ts.map +1 -0
- package/dist/workers/i3s-content-worker-node.js +7 -0
- package/dist/workers/i3s-content-worker.d.ts +2 -0
- package/dist/workers/i3s-content-worker.d.ts.map +1 -0
- package/dist/workers/i3s-content-worker.js +5 -4
- package/package.json +18 -16
- package/src/arcgis-webscene-loader.ts +31 -0
- package/src/i3s-attribute-loader.ts +9 -9
- package/src/i3s-content-loader.ts +17 -5
- package/src/i3s-loader.ts +24 -13
- package/src/i3s-node-page-loader.ts +6 -10
- package/src/i3s-slpk-loader.ts +27 -0
- package/src/index.ts +28 -7
- package/src/lib/helpers/i3s-nodepages-tiles.ts +84 -57
- package/src/lib/parsers/constants.ts +71 -37
- package/src/lib/parsers/parse-arcgis-webscene.ts +102 -0
- package/src/lib/parsers/parse-i3s-attribute.ts +21 -14
- package/src/lib/parsers/parse-i3s-building-scene-layer.ts +2 -1
- package/src/lib/parsers/parse-i3s-tile-content.ts +278 -194
- package/src/lib/parsers/parse-i3s.ts +55 -39
- package/src/lib/parsers/parse-slpk/parse-slpk.ts +72 -0
- package/src/lib/parsers/parse-slpk/slpk-archieve.ts +173 -0
- package/src/lib/parsers/parse-zip/buffer-file-provider.ts +55 -0
- package/src/lib/parsers/parse-zip/cd-file-header.ts +86 -0
- package/src/lib/parsers/parse-zip/file-provider.ts +34 -0
- package/src/lib/parsers/parse-zip/local-file-header.ts +65 -0
- package/src/lib/utils/customize-/321/201olors.ts +144 -0
- package/src/lib/utils/url-utils.ts +7 -7
- package/src/types.ts +875 -86
- package/src/workers/i3s-content-worker-node.ts +6 -0
- package/dist/bundle.js.map +0 -1
- package/dist/i3s-attribute-loader.js.map +0 -1
- package/dist/i3s-building-scene-layer-loader.js.map +0 -1
- package/dist/i3s-content-loader.js.map +0 -1
- package/dist/i3s-loader.js.map +0 -1
- package/dist/i3s-node-page-loader.js.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/lib/helpers/i3s-nodepages-tiles.js.map +0 -1
- package/dist/lib/parsers/constants.js.map +0 -1
- package/dist/lib/parsers/parse-i3s-attribute.js.map +0 -1
- package/dist/lib/parsers/parse-i3s-building-scene-layer.js.map +0 -1
- package/dist/lib/parsers/parse-i3s-tile-content.js.map +0 -1
- package/dist/lib/parsers/parse-i3s.js.map +0 -1
- package/dist/lib/utils/convert-i3s-obb-to-mbs.js.map +0 -1
- package/dist/lib/utils/url-utils.js.map +0 -1
- package/dist/types.js.map +0 -1
- package/dist/workers/i3s-content-worker.js.map +0 -1
|
@@ -4,79 +4,95 @@ import {load} from '@loaders.gl/core';
|
|
|
4
4
|
import {TILE_TYPE, TILE_REFINEMENT, TILESET_TYPE} from '@loaders.gl/tiles';
|
|
5
5
|
import I3SNodePagesTiles from '../helpers/i3s-nodepages-tiles';
|
|
6
6
|
import {generateTileAttributeUrls, getUrlWithToken} from '../utils/url-utils';
|
|
7
|
+
import {
|
|
8
|
+
I3STilesetHeader,
|
|
9
|
+
I3STileHeader,
|
|
10
|
+
Mbs,
|
|
11
|
+
I3SMinimalNodeData,
|
|
12
|
+
Node3DIndexDocument
|
|
13
|
+
} from '../../types';
|
|
14
|
+
import type {LoaderOptions, LoaderContext} from '@loaders.gl/loader-utils';
|
|
7
15
|
|
|
8
|
-
export function normalizeTileData(tile
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
if (tile.featureData) {
|
|
12
|
-
tile.featureUrl = `${tile.url}/${tile.featureData[0].href}`;
|
|
13
|
-
}
|
|
14
|
-
|
|
16
|
+
export function normalizeTileData(tile : Node3DIndexDocument, context: LoaderContext): I3STileHeader {
|
|
17
|
+
const url: string = context.url || '';
|
|
18
|
+
let contentUrl: string | undefined;
|
|
15
19
|
if (tile.geometryData) {
|
|
16
|
-
|
|
20
|
+
contentUrl = `${url}/${tile.geometryData[0].href}`;
|
|
17
21
|
}
|
|
18
22
|
|
|
23
|
+
let textureUrl: string | undefined;
|
|
19
24
|
if (tile.textureData) {
|
|
20
|
-
|
|
25
|
+
textureUrl = `${url}/${tile.textureData[0].href}`;
|
|
21
26
|
}
|
|
22
27
|
|
|
28
|
+
let attributeUrls: string[] | undefined;
|
|
23
29
|
if (tile.attributeData) {
|
|
24
|
-
|
|
30
|
+
attributeUrls = generateTileAttributeUrls(url, tile);
|
|
25
31
|
}
|
|
26
32
|
|
|
27
|
-
return normalizeTileNonUrlData(
|
|
33
|
+
return normalizeTileNonUrlData({
|
|
34
|
+
...tile,
|
|
35
|
+
url,
|
|
36
|
+
contentUrl,
|
|
37
|
+
textureUrl,
|
|
38
|
+
attributeUrls,
|
|
39
|
+
isDracoGeometry: false
|
|
40
|
+
});
|
|
28
41
|
}
|
|
29
42
|
|
|
30
|
-
export function normalizeTileNonUrlData(tile) {
|
|
31
|
-
const box =
|
|
32
|
-
|
|
33
|
-
...Ellipsoid.WGS84.cartographicToCartesian(tile.obb.center), // cartesian center of box
|
|
34
|
-
...tile.obb.halfSize, // halfSize
|
|
35
|
-
...tile.obb.quaternion // quaternion
|
|
36
|
-
]
|
|
37
|
-
: undefined;
|
|
38
|
-
let sphere;
|
|
43
|
+
export function normalizeTileNonUrlData(tile : I3SMinimalNodeData): I3STileHeader {
|
|
44
|
+
const boundingVolume: {box?: number[]; sphere?: number[]} = {};
|
|
45
|
+
let mbs: Mbs = [0, 0, 0, 1];
|
|
39
46
|
if (tile.mbs) {
|
|
40
|
-
|
|
47
|
+
mbs = tile.mbs;
|
|
48
|
+
boundingVolume.sphere = [
|
|
41
49
|
...Ellipsoid.WGS84.cartographicToCartesian(tile.mbs.slice(0, 3)), // cartesian center of sphere
|
|
42
50
|
tile.mbs[3] // radius of sphere
|
|
51
|
+
] as Mbs;
|
|
52
|
+
} else if (tile.obb) {
|
|
53
|
+
boundingVolume.box = [
|
|
54
|
+
...Ellipsoid.WGS84.cartographicToCartesian(tile.obb.center), // cartesian center of box
|
|
55
|
+
...tile.obb.halfSize, // halfSize
|
|
56
|
+
...tile.obb.quaternion // quaternion
|
|
43
57
|
];
|
|
44
|
-
} else if (box) {
|
|
45
58
|
const obb = new OrientedBoundingBox().fromCenterHalfSizeQuaternion(
|
|
46
|
-
box.slice(0, 3),
|
|
59
|
+
boundingVolume.box.slice(0, 3),
|
|
47
60
|
tile.obb.halfSize,
|
|
48
61
|
tile.obb.quaternion
|
|
49
62
|
);
|
|
50
63
|
const boundingSphere = obb.getBoundingSphere();
|
|
51
|
-
sphere = [...boundingSphere.center, boundingSphere.radius];
|
|
52
|
-
|
|
64
|
+
boundingVolume.sphere = [...boundingSphere.center , boundingSphere.radius] as Mbs;
|
|
65
|
+
mbs = [...tile.obb.center, boundingSphere.radius] as Mbs;
|
|
53
66
|
}
|
|
54
67
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
// TODO only support replacement for now
|
|
64
|
-
tile.refine = TILE_REFINEMENT.REPLACE;
|
|
68
|
+
const lodMetricType = tile.lodSelection?.[0].metricType;
|
|
69
|
+
const lodMetricValue = tile.lodSelection?.[0].maxError;
|
|
70
|
+
const transformMatrix = tile.transform;
|
|
71
|
+
const type = TILE_TYPE.MESH;
|
|
72
|
+
/**
|
|
73
|
+
* I3S specification supports only REPLACE
|
|
74
|
+
*/
|
|
75
|
+
const refine = TILE_REFINEMENT.REPLACE;
|
|
65
76
|
|
|
66
|
-
return tile;
|
|
77
|
+
return {...tile, mbs, boundingVolume, lodMetricType, lodMetricValue, transformMatrix, type, refine};
|
|
67
78
|
}
|
|
68
79
|
|
|
69
|
-
export async function normalizeTilesetData(tileset, options, context) {
|
|
80
|
+
export async function normalizeTilesetData(tileset : I3STilesetHeader, options : LoaderOptions, context: LoaderContext) {
|
|
70
81
|
tileset.url = context.url;
|
|
71
82
|
|
|
72
83
|
if (tileset.nodePages) {
|
|
73
84
|
tileset.nodePagesTile = new I3SNodePagesTiles(tileset, options);
|
|
74
|
-
tileset.root =
|
|
85
|
+
tileset.root = tileset.nodePagesTile.formTileFromNodePages(0);
|
|
75
86
|
} else {
|
|
87
|
+
// @ts-expect-error options is not properly typed
|
|
76
88
|
const rootNodeUrl = getUrlWithToken(`${tileset.url}/nodes/root`, options.i3s?.token);
|
|
77
89
|
// eslint-disable-next-line no-use-before-define
|
|
78
90
|
tileset.root = await load(rootNodeUrl, tileset.loader, {
|
|
79
|
-
|
|
91
|
+
...options,
|
|
92
|
+
i3s: {
|
|
93
|
+
// @ts-expect-error options is not properly typed
|
|
94
|
+
...options.i3s,
|
|
95
|
+
loadContent: false, isTileHeader: true, isTileset: false}
|
|
80
96
|
});
|
|
81
97
|
}
|
|
82
98
|
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import type {SLPKLoaderOptions} from '../../../i3s-slpk-loader';
|
|
2
|
+
import {DataViewFileProvider} from '../parse-zip/buffer-file-provider';
|
|
3
|
+
import {parseZipCDFileHeader} from '../parse-zip/cd-file-header';
|
|
4
|
+
import {parseZipLocalFileHeader} from '../parse-zip/local-file-header';
|
|
5
|
+
import {SLPKArchive} from './slpk-archieve';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Returns one byte from the provided buffer at the provided position
|
|
9
|
+
* @param offset - position where to read
|
|
10
|
+
* @param buffer - buffer to read
|
|
11
|
+
* @returns one byte from the provided buffer at the provided position
|
|
12
|
+
*/
|
|
13
|
+
const getByteAt = (offset: number, buffer: DataView): number => {
|
|
14
|
+
return buffer.getUint8(buffer.byteOffset + offset);
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
export async function parseSLPK(data: ArrayBuffer, options: SLPKLoaderOptions = {}) {
|
|
18
|
+
const archive = new DataView(data);
|
|
19
|
+
const cdFileHeaderSignature = [80, 75, 1, 2];
|
|
20
|
+
|
|
21
|
+
const searchWindow = [
|
|
22
|
+
getByteAt(archive.byteLength - 1, archive),
|
|
23
|
+
getByteAt(archive.byteLength - 2, archive),
|
|
24
|
+
getByteAt(archive.byteLength - 3, archive),
|
|
25
|
+
undefined
|
|
26
|
+
];
|
|
27
|
+
|
|
28
|
+
let hashCDOffset = 0;
|
|
29
|
+
|
|
30
|
+
// looking for the last record in the central directory
|
|
31
|
+
for (let i = archive.byteLength - 4; i > -1; i--) {
|
|
32
|
+
searchWindow[3] = searchWindow[2];
|
|
33
|
+
searchWindow[2] = searchWindow[1];
|
|
34
|
+
searchWindow[1] = searchWindow[0];
|
|
35
|
+
searchWindow[0] = getByteAt(i, archive);
|
|
36
|
+
if (searchWindow.every((val, index) => val === cdFileHeaderSignature[index])) {
|
|
37
|
+
hashCDOffset = i;
|
|
38
|
+
break;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const fileProvider = new DataViewFileProvider(archive);
|
|
43
|
+
|
|
44
|
+
const cdFileHeader = await parseZipCDFileHeader(hashCDOffset, fileProvider);
|
|
45
|
+
|
|
46
|
+
if (cdFileHeader.fileName !== '@specialIndexFileHASH128@') {
|
|
47
|
+
throw new Error('No hash file in slpk');
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
const localFileHeader = await parseZipLocalFileHeader(
|
|
51
|
+
cdFileHeader.localHeaderOffset,
|
|
52
|
+
fileProvider
|
|
53
|
+
);
|
|
54
|
+
if (!localFileHeader) {
|
|
55
|
+
throw new Error('No hash file in slpk');
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
const fileDataOffset = localFileHeader.fileDataOffset;
|
|
59
|
+
const hashFile = archive.buffer.slice(
|
|
60
|
+
fileDataOffset,
|
|
61
|
+
fileDataOffset + localFileHeader.compressedSize
|
|
62
|
+
);
|
|
63
|
+
|
|
64
|
+
if (!hashFile) {
|
|
65
|
+
throw new Error('No hash file in slpk');
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
return await new SLPKArchive(data, hashFile).getFile(
|
|
69
|
+
options.slpk?.path ?? '',
|
|
70
|
+
options.slpk?.pathMode
|
|
71
|
+
);
|
|
72
|
+
}
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
import md5 from 'md5';
|
|
2
|
+
import {parseZipLocalFileHeader} from '../parse-zip/local-file-header';
|
|
3
|
+
import {DataViewFileProvider} from '../parse-zip/buffer-file-provider';
|
|
4
|
+
import {GZipCompression} from '@loaders.gl/compression';
|
|
5
|
+
|
|
6
|
+
/** Element of hash array */
|
|
7
|
+
type HashElement = {
|
|
8
|
+
/**
|
|
9
|
+
* File name hash
|
|
10
|
+
*/
|
|
11
|
+
hash: Buffer;
|
|
12
|
+
/**
|
|
13
|
+
* File offset in the archive
|
|
14
|
+
*/
|
|
15
|
+
offset: number;
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
/** Description of real paths for different file types */
|
|
19
|
+
const PATH_DESCRIPTIONS: {test: RegExp; extensions: string[]}[] = [
|
|
20
|
+
{
|
|
21
|
+
test: /^$/,
|
|
22
|
+
extensions: ['3dSceneLayer.json.gz']
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
test: /^nodepages\/\d+$/,
|
|
26
|
+
extensions: ['.json.gz']
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
test: /^nodes\/\d+$/,
|
|
30
|
+
extensions: ['/3dNodeIndexDocument.json.gz']
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
test: /^nodes\/\d+\/textures\/.+$/,
|
|
34
|
+
extensions: ['.jpg', '.png', '.bin.dds.gz', '.ktx']
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
test: /^nodes\/\d+\/geometries\/\d+$/,
|
|
38
|
+
extensions: ['.bin.gz', '.draco.gz']
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
test: /^nodes\/\d+\/attributes\/f_\d+\/\d+$/,
|
|
42
|
+
extensions: ['.bin.gz']
|
|
43
|
+
},
|
|
44
|
+
{
|
|
45
|
+
test: /^statistics\/f_\d+\/\d+$/,
|
|
46
|
+
extensions: ['.json.gz']
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
test: /^nodes\/\d+\/shared$/,
|
|
50
|
+
extensions: ['/sharedResource.json.gz']
|
|
51
|
+
}
|
|
52
|
+
];
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Class for handling information about slpk file
|
|
56
|
+
*/
|
|
57
|
+
export class SLPKArchive {
|
|
58
|
+
slpkArchive: DataView;
|
|
59
|
+
hashArray: {hash: Buffer; offset: number}[];
|
|
60
|
+
constructor(slpkArchiveBuffer: ArrayBuffer, hashFile: ArrayBuffer) {
|
|
61
|
+
this.slpkArchive = new DataView(slpkArchiveBuffer);
|
|
62
|
+
this.hashArray = this.parseHashFile(hashFile);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Reads hash file from buffer and returns it in ready-to-use form
|
|
67
|
+
* @param hashFile - bufer containing hash file
|
|
68
|
+
* @returns Array containing file info
|
|
69
|
+
*/
|
|
70
|
+
private parseHashFile(hashFile: ArrayBuffer): HashElement[] {
|
|
71
|
+
const hashFileBuffer = Buffer.from(hashFile);
|
|
72
|
+
const hashArray: HashElement[] = [];
|
|
73
|
+
for (let i = 0; i < hashFileBuffer.buffer.byteLength; i = i + 24) {
|
|
74
|
+
const offsetBuffer = new DataView(
|
|
75
|
+
hashFileBuffer.buffer.slice(
|
|
76
|
+
hashFileBuffer.byteOffset + i + 16,
|
|
77
|
+
hashFileBuffer.byteOffset + i + 24
|
|
78
|
+
)
|
|
79
|
+
);
|
|
80
|
+
const offset = offsetBuffer.getUint32(offsetBuffer.byteOffset, true);
|
|
81
|
+
hashArray.push({
|
|
82
|
+
hash: Buffer.from(
|
|
83
|
+
hashFileBuffer.subarray(hashFileBuffer.byteOffset + i, hashFileBuffer.byteOffset + i + 16)
|
|
84
|
+
),
|
|
85
|
+
offset
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
return hashArray;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Returns file with the given path from slpk archive
|
|
93
|
+
* @param path - path inside the slpk
|
|
94
|
+
* @param mode - currently only raw mode supported
|
|
95
|
+
* @returns buffer with ready to use file
|
|
96
|
+
*/
|
|
97
|
+
async getFile(path: string, mode: 'http' | 'raw' = 'raw'): Promise<Buffer> {
|
|
98
|
+
if (mode === 'http') {
|
|
99
|
+
const extensions = PATH_DESCRIPTIONS.find((val) => val.test.test(path))?.extensions;
|
|
100
|
+
if (extensions) {
|
|
101
|
+
let data: ArrayBuffer | undefined;
|
|
102
|
+
for (const ext of extensions) {
|
|
103
|
+
data = await this.getDataByPath(`${path}${ext}`);
|
|
104
|
+
if (data) {
|
|
105
|
+
break;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
if (data) {
|
|
109
|
+
return Buffer.from(data);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
if (mode === 'raw') {
|
|
114
|
+
const decompressedFile = await this.getDataByPath(`${path}.gz`);
|
|
115
|
+
if (decompressedFile) {
|
|
116
|
+
return Buffer.from(decompressedFile);
|
|
117
|
+
}
|
|
118
|
+
const fileWithoutCompression = await this.getFileBytes(path);
|
|
119
|
+
if (fileWithoutCompression) {
|
|
120
|
+
return Buffer.from(fileWithoutCompression);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
throw new Error('No such file in the archieve');
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* returning uncompressed data for paths that ends with .gz and raw data for all other paths
|
|
129
|
+
* @param path - path inside the archive
|
|
130
|
+
* @returns buffer with the file data
|
|
131
|
+
*/
|
|
132
|
+
private async getDataByPath(path: string): Promise<ArrayBuffer | undefined> {
|
|
133
|
+
const data = await this.getFileBytes(path);
|
|
134
|
+
if (!data) {
|
|
135
|
+
return undefined;
|
|
136
|
+
}
|
|
137
|
+
if (/\.gz$/.test(path)) {
|
|
138
|
+
const compression = new GZipCompression();
|
|
139
|
+
|
|
140
|
+
const decompressedData = await compression.decompress(data);
|
|
141
|
+
return decompressedData;
|
|
142
|
+
}
|
|
143
|
+
return Buffer.from(data);
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* Trying to get raw file data by adress
|
|
148
|
+
* @param path - path inside the archive
|
|
149
|
+
* @returns buffer with the raw file data
|
|
150
|
+
*/
|
|
151
|
+
private async getFileBytes(path: string): Promise<ArrayBuffer | undefined> {
|
|
152
|
+
const nameHash = Buffer.from(md5(path), 'hex');
|
|
153
|
+
const fileInfo = this.hashArray.find((val) => Buffer.compare(val.hash, nameHash) === 0);
|
|
154
|
+
if (!fileInfo) {
|
|
155
|
+
return undefined;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
const localFileHeader = await parseZipLocalFileHeader(
|
|
159
|
+
this.slpkArchive.byteOffset + fileInfo?.offset,
|
|
160
|
+
new DataViewFileProvider(this.slpkArchive)
|
|
161
|
+
);
|
|
162
|
+
if (!localFileHeader) {
|
|
163
|
+
return undefined;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
const compressedFile = this.slpkArchive.buffer.slice(
|
|
167
|
+
localFileHeader.fileDataOffset,
|
|
168
|
+
localFileHeader.fileDataOffset + localFileHeader.compressedSize
|
|
169
|
+
);
|
|
170
|
+
|
|
171
|
+
return compressedFile;
|
|
172
|
+
}
|
|
173
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import {FileProvider} from './file-provider';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Provides file data using DataView
|
|
5
|
+
*/
|
|
6
|
+
export class DataViewFileProvider implements FileProvider {
|
|
7
|
+
/**
|
|
8
|
+
* The DataView from which data is provided
|
|
9
|
+
*/
|
|
10
|
+
private file: DataView;
|
|
11
|
+
|
|
12
|
+
constructor(file: DataView) {
|
|
13
|
+
this.file = file;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Gets an unsigned 8-bit integer at the specified byte offset from the start of the file.
|
|
18
|
+
* @param offset The offset, in bytes, from the start of the file where to read the data.
|
|
19
|
+
*/
|
|
20
|
+
getUint8(offset: number): Promise<number> {
|
|
21
|
+
return Promise.resolve(this.file.getUint8(offset));
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Gets an unsigned 16-bit integer at the specified byte offset from the start of the file.
|
|
26
|
+
* @param offset The offset, in bytes, from the start of the file where to read the data.
|
|
27
|
+
*/
|
|
28
|
+
getUint16(offset: number): Promise<number> {
|
|
29
|
+
return Promise.resolve(this.file.getUint16(offset, true));
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Gets an unsigned 32-bit integer at the specified byte offset from the start of the file.
|
|
34
|
+
* @param offset The offset, in bytes, from the start of the file where to read the data.
|
|
35
|
+
*/
|
|
36
|
+
getUint32(offset: number): Promise<number> {
|
|
37
|
+
return Promise.resolve(this.file.getUint32(offset, true));
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* returns an ArrayBuffer whose contents are a copy of this file bytes from startOffset, inclusive, up to endOffset, exclusive.
|
|
42
|
+
* @param startOffset The offset, in bytes, from the start of the file where to start reading the data.
|
|
43
|
+
* @param endOffset The offset, in bytes, from the start of the file where to end reading the data.
|
|
44
|
+
*/
|
|
45
|
+
slice(startOffset: number, endOffset: number): Promise<ArrayBuffer> {
|
|
46
|
+
return Promise.resolve(this.file.buffer.slice(startOffset, endOffset));
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* the length (in bytes) of the data.
|
|
51
|
+
*/
|
|
52
|
+
get length() {
|
|
53
|
+
return this.file.byteLength;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import {FileProvider} from './file-provider';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* zip central directory file header info
|
|
5
|
+
* according to https://en.wikipedia.org/wiki/ZIP_(file_format)
|
|
6
|
+
*/
|
|
7
|
+
export type ZipCDFileHeader = {
|
|
8
|
+
/** Compressed size */
|
|
9
|
+
compressedSize: number;
|
|
10
|
+
/** Uncompressed size */
|
|
11
|
+
uncompressedSize: number;
|
|
12
|
+
/** File name length */
|
|
13
|
+
fileNameLength: number;
|
|
14
|
+
/** File name */
|
|
15
|
+
fileName: string;
|
|
16
|
+
/** Extra field offset */
|
|
17
|
+
extraOffset: number;
|
|
18
|
+
/** Relative offset of local file header */
|
|
19
|
+
localHeaderOffset: number;
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Parses central directory file header of zip file
|
|
24
|
+
* @param headerOffset - offset in the archive where header starts
|
|
25
|
+
* @param buffer - buffer containing whole array
|
|
26
|
+
* @returns Info from the header
|
|
27
|
+
*/
|
|
28
|
+
export const parseZipCDFileHeader = async (
|
|
29
|
+
headerOffset: number,
|
|
30
|
+
buffer: FileProvider
|
|
31
|
+
): Promise<ZipCDFileHeader> => {
|
|
32
|
+
const offsets = {
|
|
33
|
+
CD_COMPRESSED_SIZE_OFFSET: 20,
|
|
34
|
+
CD_UNCOMPRESSED_SIZE_OFFSET: 24,
|
|
35
|
+
CD_FILE_NAME_LENGTH_OFFSET: 28,
|
|
36
|
+
CD_EXTRA_FIELD_LENGTH_OFFSET: 30,
|
|
37
|
+
CD_LOCAL_HEADER_OFFSET_OFFSET: 42,
|
|
38
|
+
CD_FILE_NAME_OFFSET: 46
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
const compressedSize = await buffer.getUint32(headerOffset + offsets.CD_COMPRESSED_SIZE_OFFSET);
|
|
42
|
+
|
|
43
|
+
const uncompressedSize = await buffer.getUint32(
|
|
44
|
+
headerOffset + offsets.CD_UNCOMPRESSED_SIZE_OFFSET
|
|
45
|
+
);
|
|
46
|
+
|
|
47
|
+
const fileNameLength = await buffer.getUint16(headerOffset + offsets.CD_FILE_NAME_LENGTH_OFFSET);
|
|
48
|
+
|
|
49
|
+
const fileName = new TextDecoder().decode(
|
|
50
|
+
await buffer.slice(
|
|
51
|
+
headerOffset + offsets.CD_FILE_NAME_OFFSET,
|
|
52
|
+
headerOffset + offsets.CD_FILE_NAME_OFFSET + fileNameLength
|
|
53
|
+
)
|
|
54
|
+
);
|
|
55
|
+
|
|
56
|
+
const extraOffset = headerOffset + offsets.CD_FILE_NAME_OFFSET + fileNameLength;
|
|
57
|
+
|
|
58
|
+
const oldFormatOffset = await buffer.getUint32(
|
|
59
|
+
headerOffset + offsets.CD_LOCAL_HEADER_OFFSET_OFFSET
|
|
60
|
+
);
|
|
61
|
+
|
|
62
|
+
let fileDataOffset = oldFormatOffset;
|
|
63
|
+
if (fileDataOffset === 0xffffffff) {
|
|
64
|
+
let offsetInZip64Data = 4;
|
|
65
|
+
// looking for info that might be also be in zip64 extra field
|
|
66
|
+
if (compressedSize === 0xffffffff) {
|
|
67
|
+
offsetInZip64Data += 8;
|
|
68
|
+
}
|
|
69
|
+
if (uncompressedSize === 0xffffffff) {
|
|
70
|
+
offsetInZip64Data += 8;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// getUint32 needs to be replaced with getBigUint64 for archieves bigger than 2gb
|
|
74
|
+
fileDataOffset = await buffer.getUint32(extraOffset + offsetInZip64Data); // setting it to the one from zip64
|
|
75
|
+
}
|
|
76
|
+
const localHeaderOffset = fileDataOffset;
|
|
77
|
+
|
|
78
|
+
return {
|
|
79
|
+
compressedSize,
|
|
80
|
+
uncompressedSize,
|
|
81
|
+
fileNameLength,
|
|
82
|
+
fileName,
|
|
83
|
+
extraOffset,
|
|
84
|
+
localHeaderOffset
|
|
85
|
+
};
|
|
86
|
+
};
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Interface for providing file data
|
|
3
|
+
*/
|
|
4
|
+
export interface FileProvider {
|
|
5
|
+
/**
|
|
6
|
+
* Gets an unsigned 8-bit integer at the specified byte offset from the start of the file.
|
|
7
|
+
* @param offset The offset, in bytes, from the start of the file where to read the data.
|
|
8
|
+
*/
|
|
9
|
+
getUint8(offset: number): Promise<number>;
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Gets an unsigned 16-bit integer at the specified byte offset from the start of the file.
|
|
13
|
+
* @param offset The offset, in bytes, from the start of the file where to read the data.
|
|
14
|
+
*/
|
|
15
|
+
getUint16(offset: number): Promise<number>;
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Gets an unsigned 32-bit integer at the specified byte offset from the start of the file.
|
|
19
|
+
* @param offset The offset, in bytes, from the file of the view where to read the data.
|
|
20
|
+
*/
|
|
21
|
+
getUint32(offset: number): Promise<number>;
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* returns an ArrayBuffer whose contents are a copy of this file bytes from startOffset, inclusive, up to endOffset, exclusive.
|
|
25
|
+
* @param startOffset The offset, in bytes, from the start of the file where to start reading the data.
|
|
26
|
+
* @param endOffset The offset, in bytes, from the start of the file where to end reading the data.
|
|
27
|
+
*/
|
|
28
|
+
slice(startOffset: number, endOffset: number): Promise<ArrayBuffer>;
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* the length (in bytes) of the data.
|
|
32
|
+
*/
|
|
33
|
+
length: number;
|
|
34
|
+
}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import {FileProvider} from './file-provider';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* zip local file header info
|
|
5
|
+
* according to https://en.wikipedia.org/wiki/ZIP_(file_format)
|
|
6
|
+
*/
|
|
7
|
+
export type ZipLocalFileHeader = {
|
|
8
|
+
/** File name length */
|
|
9
|
+
fileNameLength: number;
|
|
10
|
+
/** File name */
|
|
11
|
+
fileName: string;
|
|
12
|
+
/** Extra field length */
|
|
13
|
+
extraFieldLength: number;
|
|
14
|
+
/** Offset of the file data */
|
|
15
|
+
fileDataOffset: number;
|
|
16
|
+
/** Compressed size */
|
|
17
|
+
compressedSize: number;
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
const offsets = {
|
|
21
|
+
COMPRESSED_SIZE_OFFSET: 18,
|
|
22
|
+
FILE_NAME_LENGTH_OFFSET: 26,
|
|
23
|
+
EXTRA_FIELD_LENGTH_OFFSET: 28,
|
|
24
|
+
FILE_NAME_OFFSET: 30
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
const signature = Buffer.from([0x50, 0x4b, 0x03, 0x04]);
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Parses local file header of zip file
|
|
31
|
+
* @param headerOffset - offset in the archive where header starts
|
|
32
|
+
* @param buffer - buffer containing whole array
|
|
33
|
+
* @returns Info from the header
|
|
34
|
+
*/
|
|
35
|
+
export const parseZipLocalFileHeader = async (
|
|
36
|
+
headerOffset: number,
|
|
37
|
+
buffer: FileProvider
|
|
38
|
+
): Promise<ZipLocalFileHeader | undefined> => {
|
|
39
|
+
if (Buffer.from(await buffer.slice(headerOffset, headerOffset + 4)).compare(signature) !== 0) {
|
|
40
|
+
return Promise.resolve(undefined);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const fileNameLength = await buffer.getUint16(headerOffset + offsets.FILE_NAME_LENGTH_OFFSET);
|
|
44
|
+
|
|
45
|
+
const fileName = new TextDecoder().decode(
|
|
46
|
+
await buffer.slice(
|
|
47
|
+
headerOffset + offsets.FILE_NAME_OFFSET,
|
|
48
|
+
headerOffset + offsets.FILE_NAME_OFFSET + fileNameLength
|
|
49
|
+
)
|
|
50
|
+
);
|
|
51
|
+
const extraFieldLength = await buffer.getUint16(headerOffset + offsets.EXTRA_FIELD_LENGTH_OFFSET);
|
|
52
|
+
|
|
53
|
+
const fileDataOffset =
|
|
54
|
+
headerOffset + offsets.FILE_NAME_OFFSET + fileNameLength + extraFieldLength;
|
|
55
|
+
|
|
56
|
+
const compressedSize = await buffer.getUint32(headerOffset + offsets.COMPRESSED_SIZE_OFFSET);
|
|
57
|
+
|
|
58
|
+
return {
|
|
59
|
+
fileNameLength,
|
|
60
|
+
fileName,
|
|
61
|
+
extraFieldLength,
|
|
62
|
+
fileDataOffset,
|
|
63
|
+
compressedSize
|
|
64
|
+
};
|
|
65
|
+
};
|