@mlightcad/libredwg-web 0.7.9 → 0.7.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/README.md +1 -1
- package/dist/libredwg-web.js +146 -5
- package/dist/libredwg-web.umd.cjs +146 -5
- package/lib/converter/converter.d.ts +20 -0
- package/lib/converter/converter.js +135 -0
- package/lib/converter/entityConverter.js +2 -2
- package/lib/database/codepage.js +2 -1
- package/lib/database/index.d.ts +1 -0
- package/lib/database/index.js +1 -0
- package/lib/database/textEscapes.d.ts +5 -0
- package/lib/database/textEscapes.js +19 -0
- package/lib/libredwg.js +12 -2
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -53,7 +53,7 @@ pnpm build
|
|
|
53
53
|
In order to reduce the size of wasm file, the following functionalities are not included by default when building web assembly.
|
|
54
54
|
|
|
55
55
|
- write dwg file
|
|
56
|
-
-
|
|
56
|
+
- write dxf file
|
|
57
57
|
- import/export json file
|
|
58
58
|
|
|
59
59
|
If you want those functionalities, just modify command `build:prepare` defined in [package.json](./package.json) and remove the following options.
|
package/dist/libredwg-web.js
CHANGED
|
@@ -94,8 +94,9 @@ const encodings = [
|
|
|
94
94
|
"macintosh",
|
|
95
95
|
// 23
|
|
96
96
|
"big5",
|
|
97
|
-
|
|
98
|
-
|
|
97
|
+
// WHATWG 'euc-kr' decodes windows-949, which covers CP949 (Wansung + UHC).
|
|
98
|
+
"euc-kr",
|
|
99
|
+
// Korean (CP949 / Wansung + UHC)
|
|
99
100
|
"utf-8",
|
|
100
101
|
// Johab?
|
|
101
102
|
"ibm866",
|
|
@@ -529,6 +530,16 @@ var DwgDictionaryCloningFlags = /* @__PURE__ */ ((DwgDictionaryCloningFlags2) =>
|
|
|
529
530
|
DwgDictionaryCloningFlags2[DwgDictionaryCloningFlags2["UnmangleName"] = 5] = "UnmangleName";
|
|
530
531
|
return DwgDictionaryCloningFlags2;
|
|
531
532
|
})(DwgDictionaryCloningFlags || {});
|
|
533
|
+
const UNICODE_ESCAPE = /\\U\+([0-9A-Fa-f]{4})/g;
|
|
534
|
+
function decodeUnicodeEscapes(text) {
|
|
535
|
+
if (!text || !text.includes("\\U+")) {
|
|
536
|
+
return text;
|
|
537
|
+
}
|
|
538
|
+
return text.replace(
|
|
539
|
+
UNICODE_ESCAPE,
|
|
540
|
+
(_, hex) => String.fromCharCode(parseInt(hex, 16))
|
|
541
|
+
);
|
|
542
|
+
}
|
|
532
543
|
const dwgVersions = [
|
|
533
544
|
{
|
|
534
545
|
type: "invalid",
|
|
@@ -2701,7 +2712,7 @@ class LibreEntityConverter {
|
|
|
2701
2712
|
const elevation = libredwg.dwg_dynapi_entity_data(entity, "elevation");
|
|
2702
2713
|
const thickness = libredwg.dwg_dynapi_entity_data(entity, "thickness");
|
|
2703
2714
|
const extrusionDirection = libredwg.dwg_dynapi_entity_data(entity, "extrusion");
|
|
2704
|
-
const vertices = libredwg.dwg_entity_polyline_2d_get_vertices(object);
|
|
2715
|
+
const vertices = libredwg.dwg_entity_polyline_2d_get_vertices(object) ?? [];
|
|
2705
2716
|
return {
|
|
2706
2717
|
type: "POLYLINE2D",
|
|
2707
2718
|
...commonAttrs,
|
|
@@ -2737,7 +2748,7 @@ class LibreEntityConverter {
|
|
|
2737
2748
|
const startWidth = libredwg.dwg_dynapi_entity_data(entity, "start_width");
|
|
2738
2749
|
const endWidth = libredwg.dwg_dynapi_entity_data(entity, "end_width");
|
|
2739
2750
|
const extrusionDirection = libredwg.dwg_dynapi_entity_data(entity, "extrusion");
|
|
2740
|
-
const vertices = libredwg.dwg_entity_polyline_3d_get_vertices(object);
|
|
2751
|
+
const vertices = libredwg.dwg_entity_polyline_3d_get_vertices(object) ?? [];
|
|
2741
2752
|
return {
|
|
2742
2753
|
type: "POLYLINE3D",
|
|
2743
2754
|
...commonAttrs,
|
|
@@ -3341,12 +3352,24 @@ class LibreDwgConverter {
|
|
|
3341
3352
|
constructor(instance) {
|
|
3342
3353
|
__publicField(this, "libredwg");
|
|
3343
3354
|
__publicField(this, "entityConverter");
|
|
3355
|
+
/**
|
|
3356
|
+
* Entity object indices keyed by owning BLOCK_HEADER object pointer.
|
|
3357
|
+
* Built lazily when an ownership walk returns no entities (LibreDWG
|
|
3358
|
+
* https://github.com/LibreDWG/libredwg/issues/1199).
|
|
3359
|
+
*/
|
|
3360
|
+
__publicField(this, "orphanEntitiesByBlock", null);
|
|
3361
|
+
/** Entity indices whose ownerhandle does not resolve to any object. */
|
|
3362
|
+
__publicField(this, "ownerlessOrphanIndices", null);
|
|
3363
|
+
__publicField(this, "orphanIndexDataPtr", null);
|
|
3344
3364
|
this.libredwg = instance;
|
|
3345
3365
|
this.entityConverter = new LibreEntityConverter(instance);
|
|
3346
3366
|
}
|
|
3347
3367
|
convert(data) {
|
|
3348
3368
|
var _a;
|
|
3349
3369
|
this.entityConverter.clear();
|
|
3370
|
+
this.orphanEntitiesByBlock = null;
|
|
3371
|
+
this.ownerlessOrphanIndices = null;
|
|
3372
|
+
this.orphanIndexDataPtr = data;
|
|
3350
3373
|
const db = {
|
|
3351
3374
|
tables: {
|
|
3352
3375
|
APPID: {
|
|
@@ -3600,6 +3623,26 @@ class LibreDwgConverter {
|
|
|
3600
3623
|
}
|
|
3601
3624
|
}
|
|
3602
3625
|
}
|
|
3626
|
+
if (this.orphanIndexDataPtr != null) {
|
|
3627
|
+
const orphans = this.convertOrphanOwnedEntities(
|
|
3628
|
+
this.orphanIndexDataPtr,
|
|
3629
|
+
obj,
|
|
3630
|
+
commonAttrs.handle,
|
|
3631
|
+
isModelSpace(commonAttrs.name) === true
|
|
3632
|
+
);
|
|
3633
|
+
if (orphans.length) {
|
|
3634
|
+
if (entities.length === 0) {
|
|
3635
|
+
entities = orphans;
|
|
3636
|
+
} else {
|
|
3637
|
+
const seen = new Set(entities.map((e) => e.handle));
|
|
3638
|
+
for (const entity of orphans) {
|
|
3639
|
+
if (!seen.has(entity.handle)) {
|
|
3640
|
+
entities.push(entity);
|
|
3641
|
+
}
|
|
3642
|
+
}
|
|
3643
|
+
}
|
|
3644
|
+
}
|
|
3645
|
+
}
|
|
3603
3646
|
return {
|
|
3604
3647
|
...commonAttrs,
|
|
3605
3648
|
flags,
|
|
@@ -3628,6 +3671,89 @@ class LibreDwgConverter {
|
|
|
3628
3671
|
}
|
|
3629
3672
|
return entities;
|
|
3630
3673
|
}
|
|
3674
|
+
/**
|
|
3675
|
+
* Builds (once) a map of BLOCK_HEADER object pointer → entity object indices
|
|
3676
|
+
* for entities that are not reachable through the ownership chain, then
|
|
3677
|
+
* converts the entities owned by `blockHeaderPtr`.
|
|
3678
|
+
*
|
|
3679
|
+
* @param includeOwnerless - When true (only for *Model_Space), also convert
|
|
3680
|
+
* entities that still have no resolvable owner after ownerhandle + entmode
|
|
3681
|
+
* fallback via dwg_entity_owner.
|
|
3682
|
+
*/
|
|
3683
|
+
convertOrphanOwnedEntities(data, blockHeaderPtr, ownerHandle, includeOwnerless) {
|
|
3684
|
+
this.ensureOrphanEntityIndex(data);
|
|
3685
|
+
const byBlock = this.orphanEntitiesByBlock ?? /* @__PURE__ */ new Map();
|
|
3686
|
+
const owned = byBlock.get(blockHeaderPtr) ?? [];
|
|
3687
|
+
const ownerless = includeOwnerless && this.ownerlessOrphanIndices ? this.ownerlessOrphanIndices : [];
|
|
3688
|
+
const indices = owned.length && ownerless.length ? owned.concat(ownerless) : owned.length ? owned : ownerless;
|
|
3689
|
+
if (indices.length === 0) {
|
|
3690
|
+
return [];
|
|
3691
|
+
}
|
|
3692
|
+
const libredwg = this.libredwg;
|
|
3693
|
+
const converter = this.entityConverter;
|
|
3694
|
+
const entities = [];
|
|
3695
|
+
for (const index of indices) {
|
|
3696
|
+
const object = libredwg.dwg_get_object(data, index);
|
|
3697
|
+
const entity = converter.convert(object);
|
|
3698
|
+
if (entity) {
|
|
3699
|
+
entity.ownerBlockRecordSoftId = ownerHandle;
|
|
3700
|
+
entities.push(entity);
|
|
3701
|
+
}
|
|
3702
|
+
}
|
|
3703
|
+
return entities;
|
|
3704
|
+
}
|
|
3705
|
+
ensureOrphanEntityIndex(data) {
|
|
3706
|
+
if (this.orphanEntitiesByBlock) {
|
|
3707
|
+
return;
|
|
3708
|
+
}
|
|
3709
|
+
const libredwg = this.libredwg;
|
|
3710
|
+
const numObjects = libredwg.dwg_get_num_objects(data);
|
|
3711
|
+
const indexByEntityPtr = /* @__PURE__ */ new Map();
|
|
3712
|
+
const entityIndices = [];
|
|
3713
|
+
const blockHeaderPtrs = [];
|
|
3714
|
+
const blockObjByTio = /* @__PURE__ */ new Map();
|
|
3715
|
+
for (let i = 0; i < numObjects; i++) {
|
|
3716
|
+
const obj = libredwg.dwg_get_object(data, i);
|
|
3717
|
+
if (!obj) continue;
|
|
3718
|
+
if (libredwg.dwg_object_get_supertype(obj) === Dwg_Object_Supertype.DWG_SUPERTYPE_ENTITY) {
|
|
3719
|
+
entityIndices.push(i);
|
|
3720
|
+
indexByEntityPtr.set(obj, i);
|
|
3721
|
+
} else if (libredwg.dwg_object_get_fixedtype(obj) === Dwg_Object_Type.DWG_TYPE_BLOCK_HEADER) {
|
|
3722
|
+
blockHeaderPtrs.push(obj);
|
|
3723
|
+
const tio = libredwg.dwg_object_to_object_tio(obj);
|
|
3724
|
+
if (tio) blockObjByTio.set(tio, obj);
|
|
3725
|
+
}
|
|
3726
|
+
}
|
|
3727
|
+
const claimed = /* @__PURE__ */ new Set();
|
|
3728
|
+
for (const blockHeader of blockHeaderPtrs) {
|
|
3729
|
+
let current = libredwg.get_first_owned_entity(blockHeader);
|
|
3730
|
+
let steps = 0;
|
|
3731
|
+
while (current && steps++ <= entityIndices.length) {
|
|
3732
|
+
const index = indexByEntityPtr.get(current);
|
|
3733
|
+
if (index === void 0 || claimed.has(index)) break;
|
|
3734
|
+
claimed.add(index);
|
|
3735
|
+
current = libredwg.get_next_owned_entity(blockHeader, current);
|
|
3736
|
+
}
|
|
3737
|
+
}
|
|
3738
|
+
const orphansByBlock = /* @__PURE__ */ new Map();
|
|
3739
|
+
const ownerless = [];
|
|
3740
|
+
for (const index of entityIndices) {
|
|
3741
|
+
if (claimed.has(index)) continue;
|
|
3742
|
+
const obj = libredwg.dwg_get_object(data, index);
|
|
3743
|
+
const etio = obj ? libredwg.dwg_object_to_entity_tio(obj) : 0;
|
|
3744
|
+
const ownerTio = etio ? libredwg.dwg_entity_owner(etio) : 0;
|
|
3745
|
+
const owner = ownerTio ? blockObjByTio.get(ownerTio) ?? 0 : 0;
|
|
3746
|
+
if (owner) {
|
|
3747
|
+
const owned = orphansByBlock.get(owner);
|
|
3748
|
+
if (owned) owned.push(index);
|
|
3749
|
+
else orphansByBlock.set(owner, [index]);
|
|
3750
|
+
} else {
|
|
3751
|
+
ownerless.push(index);
|
|
3752
|
+
}
|
|
3753
|
+
}
|
|
3754
|
+
this.orphanEntitiesByBlock = orphansByBlock;
|
|
3755
|
+
this.ownerlessOrphanIndices = ownerless;
|
|
3756
|
+
}
|
|
3631
3757
|
convertDimStyle(item, obj) {
|
|
3632
3758
|
const libredwg = this.libredwg;
|
|
3633
3759
|
const commonAttrs = this.getCommonTableEntryAttrs(item, obj);
|
|
@@ -6449,6 +6575,9 @@ const _LibreDwg = class _LibreDwg {
|
|
|
6449
6575
|
if (value.bin && this.decoder) {
|
|
6450
6576
|
value.data = this.decoder.decode(value.bin);
|
|
6451
6577
|
}
|
|
6578
|
+
if (typeof value.data === "string") {
|
|
6579
|
+
value.data = decodeUnicodeEscapes(value.data);
|
|
6580
|
+
}
|
|
6452
6581
|
return value;
|
|
6453
6582
|
}
|
|
6454
6583
|
/**
|
|
@@ -6502,7 +6631,18 @@ const _LibreDwg = class _LibreDwg {
|
|
|
6502
6631
|
* @returns Returns the sub-field value of one complex field.
|
|
6503
6632
|
*/
|
|
6504
6633
|
dwg_dynapi_subclass_value(obj, subclass, field) {
|
|
6505
|
-
|
|
6634
|
+
const value = this.wasmInstance.dwg_dynapi_subclass_value(
|
|
6635
|
+
obj,
|
|
6636
|
+
subclass,
|
|
6637
|
+
field
|
|
6638
|
+
);
|
|
6639
|
+
if (value.bin && this.decoder) {
|
|
6640
|
+
value.data = this.decoder.decode(value.bin);
|
|
6641
|
+
}
|
|
6642
|
+
if (typeof value.data === "string") {
|
|
6643
|
+
value.data = decodeUnicodeEscapes(value.data);
|
|
6644
|
+
}
|
|
6645
|
+
return value;
|
|
6506
6646
|
}
|
|
6507
6647
|
/**
|
|
6508
6648
|
* Returns the sub-field data of one complex field.
|
|
@@ -6938,6 +7078,7 @@ export {
|
|
|
6938
7078
|
HEADER_VARIABLES,
|
|
6939
7079
|
LibreDwg,
|
|
6940
7080
|
default2 as createModule,
|
|
7081
|
+
decodeUnicodeEscapes,
|
|
6941
7082
|
dwgCodePageToEncoding,
|
|
6942
7083
|
dwgVersions
|
|
6943
7084
|
};
|
|
@@ -96,8 +96,9 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
|
|
|
96
96
|
"macintosh",
|
|
97
97
|
// 23
|
|
98
98
|
"big5",
|
|
99
|
-
|
|
100
|
-
|
|
99
|
+
// WHATWG 'euc-kr' decodes windows-949, which covers CP949 (Wansung + UHC).
|
|
100
|
+
"euc-kr",
|
|
101
|
+
// Korean (CP949 / Wansung + UHC)
|
|
101
102
|
"utf-8",
|
|
102
103
|
// Johab?
|
|
103
104
|
"ibm866",
|
|
@@ -531,6 +532,16 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
|
|
|
531
532
|
DwgDictionaryCloningFlags2[DwgDictionaryCloningFlags2["UnmangleName"] = 5] = "UnmangleName";
|
|
532
533
|
return DwgDictionaryCloningFlags2;
|
|
533
534
|
})(DwgDictionaryCloningFlags || {});
|
|
535
|
+
const UNICODE_ESCAPE = /\\U\+([0-9A-Fa-f]{4})/g;
|
|
536
|
+
function decodeUnicodeEscapes(text) {
|
|
537
|
+
if (!text || !text.includes("\\U+")) {
|
|
538
|
+
return text;
|
|
539
|
+
}
|
|
540
|
+
return text.replace(
|
|
541
|
+
UNICODE_ESCAPE,
|
|
542
|
+
(_, hex) => String.fromCharCode(parseInt(hex, 16))
|
|
543
|
+
);
|
|
544
|
+
}
|
|
534
545
|
const dwgVersions = [
|
|
535
546
|
{
|
|
536
547
|
type: "invalid",
|
|
@@ -2703,7 +2714,7 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
|
|
|
2703
2714
|
const elevation = libredwg.dwg_dynapi_entity_data(entity, "elevation");
|
|
2704
2715
|
const thickness = libredwg.dwg_dynapi_entity_data(entity, "thickness");
|
|
2705
2716
|
const extrusionDirection = libredwg.dwg_dynapi_entity_data(entity, "extrusion");
|
|
2706
|
-
const vertices = libredwg.dwg_entity_polyline_2d_get_vertices(object);
|
|
2717
|
+
const vertices = libredwg.dwg_entity_polyline_2d_get_vertices(object) ?? [];
|
|
2707
2718
|
return {
|
|
2708
2719
|
type: "POLYLINE2D",
|
|
2709
2720
|
...commonAttrs,
|
|
@@ -2739,7 +2750,7 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
|
|
|
2739
2750
|
const startWidth = libredwg.dwg_dynapi_entity_data(entity, "start_width");
|
|
2740
2751
|
const endWidth = libredwg.dwg_dynapi_entity_data(entity, "end_width");
|
|
2741
2752
|
const extrusionDirection = libredwg.dwg_dynapi_entity_data(entity, "extrusion");
|
|
2742
|
-
const vertices = libredwg.dwg_entity_polyline_3d_get_vertices(object);
|
|
2753
|
+
const vertices = libredwg.dwg_entity_polyline_3d_get_vertices(object) ?? [];
|
|
2743
2754
|
return {
|
|
2744
2755
|
type: "POLYLINE3D",
|
|
2745
2756
|
...commonAttrs,
|
|
@@ -3343,12 +3354,24 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
|
|
|
3343
3354
|
constructor(instance) {
|
|
3344
3355
|
__publicField(this, "libredwg");
|
|
3345
3356
|
__publicField(this, "entityConverter");
|
|
3357
|
+
/**
|
|
3358
|
+
* Entity object indices keyed by owning BLOCK_HEADER object pointer.
|
|
3359
|
+
* Built lazily when an ownership walk returns no entities (LibreDWG
|
|
3360
|
+
* https://github.com/LibreDWG/libredwg/issues/1199).
|
|
3361
|
+
*/
|
|
3362
|
+
__publicField(this, "orphanEntitiesByBlock", null);
|
|
3363
|
+
/** Entity indices whose ownerhandle does not resolve to any object. */
|
|
3364
|
+
__publicField(this, "ownerlessOrphanIndices", null);
|
|
3365
|
+
__publicField(this, "orphanIndexDataPtr", null);
|
|
3346
3366
|
this.libredwg = instance;
|
|
3347
3367
|
this.entityConverter = new LibreEntityConverter(instance);
|
|
3348
3368
|
}
|
|
3349
3369
|
convert(data) {
|
|
3350
3370
|
var _a;
|
|
3351
3371
|
this.entityConverter.clear();
|
|
3372
|
+
this.orphanEntitiesByBlock = null;
|
|
3373
|
+
this.ownerlessOrphanIndices = null;
|
|
3374
|
+
this.orphanIndexDataPtr = data;
|
|
3352
3375
|
const db = {
|
|
3353
3376
|
tables: {
|
|
3354
3377
|
APPID: {
|
|
@@ -3602,6 +3625,26 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
|
|
|
3602
3625
|
}
|
|
3603
3626
|
}
|
|
3604
3627
|
}
|
|
3628
|
+
if (this.orphanIndexDataPtr != null) {
|
|
3629
|
+
const orphans = this.convertOrphanOwnedEntities(
|
|
3630
|
+
this.orphanIndexDataPtr,
|
|
3631
|
+
obj,
|
|
3632
|
+
commonAttrs.handle,
|
|
3633
|
+
isModelSpace(commonAttrs.name) === true
|
|
3634
|
+
);
|
|
3635
|
+
if (orphans.length) {
|
|
3636
|
+
if (entities.length === 0) {
|
|
3637
|
+
entities = orphans;
|
|
3638
|
+
} else {
|
|
3639
|
+
const seen = new Set(entities.map((e) => e.handle));
|
|
3640
|
+
for (const entity of orphans) {
|
|
3641
|
+
if (!seen.has(entity.handle)) {
|
|
3642
|
+
entities.push(entity);
|
|
3643
|
+
}
|
|
3644
|
+
}
|
|
3645
|
+
}
|
|
3646
|
+
}
|
|
3647
|
+
}
|
|
3605
3648
|
return {
|
|
3606
3649
|
...commonAttrs,
|
|
3607
3650
|
flags,
|
|
@@ -3630,6 +3673,89 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
|
|
|
3630
3673
|
}
|
|
3631
3674
|
return entities;
|
|
3632
3675
|
}
|
|
3676
|
+
/**
|
|
3677
|
+
* Builds (once) a map of BLOCK_HEADER object pointer → entity object indices
|
|
3678
|
+
* for entities that are not reachable through the ownership chain, then
|
|
3679
|
+
* converts the entities owned by `blockHeaderPtr`.
|
|
3680
|
+
*
|
|
3681
|
+
* @param includeOwnerless - When true (only for *Model_Space), also convert
|
|
3682
|
+
* entities that still have no resolvable owner after ownerhandle + entmode
|
|
3683
|
+
* fallback via dwg_entity_owner.
|
|
3684
|
+
*/
|
|
3685
|
+
convertOrphanOwnedEntities(data, blockHeaderPtr, ownerHandle, includeOwnerless) {
|
|
3686
|
+
this.ensureOrphanEntityIndex(data);
|
|
3687
|
+
const byBlock = this.orphanEntitiesByBlock ?? /* @__PURE__ */ new Map();
|
|
3688
|
+
const owned = byBlock.get(blockHeaderPtr) ?? [];
|
|
3689
|
+
const ownerless = includeOwnerless && this.ownerlessOrphanIndices ? this.ownerlessOrphanIndices : [];
|
|
3690
|
+
const indices = owned.length && ownerless.length ? owned.concat(ownerless) : owned.length ? owned : ownerless;
|
|
3691
|
+
if (indices.length === 0) {
|
|
3692
|
+
return [];
|
|
3693
|
+
}
|
|
3694
|
+
const libredwg = this.libredwg;
|
|
3695
|
+
const converter = this.entityConverter;
|
|
3696
|
+
const entities = [];
|
|
3697
|
+
for (const index of indices) {
|
|
3698
|
+
const object = libredwg.dwg_get_object(data, index);
|
|
3699
|
+
const entity = converter.convert(object);
|
|
3700
|
+
if (entity) {
|
|
3701
|
+
entity.ownerBlockRecordSoftId = ownerHandle;
|
|
3702
|
+
entities.push(entity);
|
|
3703
|
+
}
|
|
3704
|
+
}
|
|
3705
|
+
return entities;
|
|
3706
|
+
}
|
|
3707
|
+
ensureOrphanEntityIndex(data) {
|
|
3708
|
+
if (this.orphanEntitiesByBlock) {
|
|
3709
|
+
return;
|
|
3710
|
+
}
|
|
3711
|
+
const libredwg = this.libredwg;
|
|
3712
|
+
const numObjects = libredwg.dwg_get_num_objects(data);
|
|
3713
|
+
const indexByEntityPtr = /* @__PURE__ */ new Map();
|
|
3714
|
+
const entityIndices = [];
|
|
3715
|
+
const blockHeaderPtrs = [];
|
|
3716
|
+
const blockObjByTio = /* @__PURE__ */ new Map();
|
|
3717
|
+
for (let i = 0; i < numObjects; i++) {
|
|
3718
|
+
const obj = libredwg.dwg_get_object(data, i);
|
|
3719
|
+
if (!obj) continue;
|
|
3720
|
+
if (libredwg.dwg_object_get_supertype(obj) === Dwg_Object_Supertype.DWG_SUPERTYPE_ENTITY) {
|
|
3721
|
+
entityIndices.push(i);
|
|
3722
|
+
indexByEntityPtr.set(obj, i);
|
|
3723
|
+
} else if (libredwg.dwg_object_get_fixedtype(obj) === Dwg_Object_Type.DWG_TYPE_BLOCK_HEADER) {
|
|
3724
|
+
blockHeaderPtrs.push(obj);
|
|
3725
|
+
const tio = libredwg.dwg_object_to_object_tio(obj);
|
|
3726
|
+
if (tio) blockObjByTio.set(tio, obj);
|
|
3727
|
+
}
|
|
3728
|
+
}
|
|
3729
|
+
const claimed = /* @__PURE__ */ new Set();
|
|
3730
|
+
for (const blockHeader of blockHeaderPtrs) {
|
|
3731
|
+
let current = libredwg.get_first_owned_entity(blockHeader);
|
|
3732
|
+
let steps = 0;
|
|
3733
|
+
while (current && steps++ <= entityIndices.length) {
|
|
3734
|
+
const index = indexByEntityPtr.get(current);
|
|
3735
|
+
if (index === void 0 || claimed.has(index)) break;
|
|
3736
|
+
claimed.add(index);
|
|
3737
|
+
current = libredwg.get_next_owned_entity(blockHeader, current);
|
|
3738
|
+
}
|
|
3739
|
+
}
|
|
3740
|
+
const orphansByBlock = /* @__PURE__ */ new Map();
|
|
3741
|
+
const ownerless = [];
|
|
3742
|
+
for (const index of entityIndices) {
|
|
3743
|
+
if (claimed.has(index)) continue;
|
|
3744
|
+
const obj = libredwg.dwg_get_object(data, index);
|
|
3745
|
+
const etio = obj ? libredwg.dwg_object_to_entity_tio(obj) : 0;
|
|
3746
|
+
const ownerTio = etio ? libredwg.dwg_entity_owner(etio) : 0;
|
|
3747
|
+
const owner = ownerTio ? blockObjByTio.get(ownerTio) ?? 0 : 0;
|
|
3748
|
+
if (owner) {
|
|
3749
|
+
const owned = orphansByBlock.get(owner);
|
|
3750
|
+
if (owned) owned.push(index);
|
|
3751
|
+
else orphansByBlock.set(owner, [index]);
|
|
3752
|
+
} else {
|
|
3753
|
+
ownerless.push(index);
|
|
3754
|
+
}
|
|
3755
|
+
}
|
|
3756
|
+
this.orphanEntitiesByBlock = orphansByBlock;
|
|
3757
|
+
this.ownerlessOrphanIndices = ownerless;
|
|
3758
|
+
}
|
|
3633
3759
|
convertDimStyle(item, obj) {
|
|
3634
3760
|
const libredwg = this.libredwg;
|
|
3635
3761
|
const commonAttrs = this.getCommonTableEntryAttrs(item, obj);
|
|
@@ -6451,6 +6577,9 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
|
|
|
6451
6577
|
if (value.bin && this.decoder) {
|
|
6452
6578
|
value.data = this.decoder.decode(value.bin);
|
|
6453
6579
|
}
|
|
6580
|
+
if (typeof value.data === "string") {
|
|
6581
|
+
value.data = decodeUnicodeEscapes(value.data);
|
|
6582
|
+
}
|
|
6454
6583
|
return value;
|
|
6455
6584
|
}
|
|
6456
6585
|
/**
|
|
@@ -6504,7 +6633,18 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
|
|
|
6504
6633
|
* @returns Returns the sub-field value of one complex field.
|
|
6505
6634
|
*/
|
|
6506
6635
|
dwg_dynapi_subclass_value(obj, subclass, field) {
|
|
6507
|
-
|
|
6636
|
+
const value = this.wasmInstance.dwg_dynapi_subclass_value(
|
|
6637
|
+
obj,
|
|
6638
|
+
subclass,
|
|
6639
|
+
field
|
|
6640
|
+
);
|
|
6641
|
+
if (value.bin && this.decoder) {
|
|
6642
|
+
value.data = this.decoder.decode(value.bin);
|
|
6643
|
+
}
|
|
6644
|
+
if (typeof value.data === "string") {
|
|
6645
|
+
value.data = decodeUnicodeEscapes(value.data);
|
|
6646
|
+
}
|
|
6647
|
+
return value;
|
|
6508
6648
|
}
|
|
6509
6649
|
/**
|
|
6510
6650
|
* Returns the sub-field data of one complex field.
|
|
@@ -6939,6 +7079,7 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
|
|
|
6939
7079
|
exports2.Dwg_Object_Type_Inverted = Dwg_Object_Type_Inverted;
|
|
6940
7080
|
exports2.HEADER_VARIABLES = HEADER_VARIABLES;
|
|
6941
7081
|
exports2.LibreDwg = LibreDwg;
|
|
7082
|
+
exports2.decodeUnicodeEscapes = decodeUnicodeEscapes;
|
|
6942
7083
|
exports2.dwgCodePageToEncoding = dwgCodePageToEncoding;
|
|
6943
7084
|
exports2.dwgVersions = dwgVersions;
|
|
6944
7085
|
Object.defineProperty(exports2, Symbol.toStringTag, { value: "Module" });
|
|
@@ -7,6 +7,15 @@ import { Dwg_Data_Ptr } from '../types';
|
|
|
7
7
|
export declare class LibreDwgConverter {
|
|
8
8
|
private libredwg;
|
|
9
9
|
private entityConverter;
|
|
10
|
+
/**
|
|
11
|
+
* Entity object indices keyed by owning BLOCK_HEADER object pointer.
|
|
12
|
+
* Built lazily when an ownership walk returns no entities (LibreDWG
|
|
13
|
+
* https://github.com/LibreDWG/libredwg/issues/1199).
|
|
14
|
+
*/
|
|
15
|
+
private orphanEntitiesByBlock;
|
|
16
|
+
/** Entity indices whose ownerhandle does not resolve to any object. */
|
|
17
|
+
private ownerlessOrphanIndices;
|
|
18
|
+
private orphanIndexDataPtr;
|
|
10
19
|
constructor(instance: LibreDwgEx);
|
|
11
20
|
convert(data: Dwg_Data_Ptr): DwgDatabase;
|
|
12
21
|
getConversionStats(): {
|
|
@@ -18,6 +27,17 @@ export declare class LibreDwgConverter {
|
|
|
18
27
|
private convertAppId;
|
|
19
28
|
private convertBlockRecord;
|
|
20
29
|
private convertEntities;
|
|
30
|
+
/**
|
|
31
|
+
* Builds (once) a map of BLOCK_HEADER object pointer → entity object indices
|
|
32
|
+
* for entities that are not reachable through the ownership chain, then
|
|
33
|
+
* converts the entities owned by `blockHeaderPtr`.
|
|
34
|
+
*
|
|
35
|
+
* @param includeOwnerless - When true (only for *Model_Space), also convert
|
|
36
|
+
* entities that still have no resolvable owner after ownerhandle + entmode
|
|
37
|
+
* fallback via dwg_entity_owner.
|
|
38
|
+
*/
|
|
39
|
+
private convertOrphanOwnedEntities;
|
|
40
|
+
private ensureOrphanEntityIndex;
|
|
21
41
|
private convertDimStyle;
|
|
22
42
|
private convertLayer;
|
|
23
43
|
private convertLineType;
|
|
@@ -9,12 +9,24 @@ import { idToString, isModelSpace, isPaperSpace, uint8ArrayToHexString } from '.
|
|
|
9
9
|
export class LibreDwgConverter {
|
|
10
10
|
libredwg;
|
|
11
11
|
entityConverter;
|
|
12
|
+
/**
|
|
13
|
+
* Entity object indices keyed by owning BLOCK_HEADER object pointer.
|
|
14
|
+
* Built lazily when an ownership walk returns no entities (LibreDWG
|
|
15
|
+
* https://github.com/LibreDWG/libredwg/issues/1199).
|
|
16
|
+
*/
|
|
17
|
+
orphanEntitiesByBlock = null;
|
|
18
|
+
/** Entity indices whose ownerhandle does not resolve to any object. */
|
|
19
|
+
ownerlessOrphanIndices = null;
|
|
20
|
+
orphanIndexDataPtr = null;
|
|
12
21
|
constructor(instance) {
|
|
13
22
|
this.libredwg = instance;
|
|
14
23
|
this.entityConverter = new LibreEntityConverter(instance);
|
|
15
24
|
}
|
|
16
25
|
convert(data) {
|
|
17
26
|
this.entityConverter.clear();
|
|
27
|
+
this.orphanEntitiesByBlock = null;
|
|
28
|
+
this.ownerlessOrphanIndices = null;
|
|
29
|
+
this.orphanIndexDataPtr = data;
|
|
18
30
|
const db = {
|
|
19
31
|
tables: {
|
|
20
32
|
APPID: {
|
|
@@ -287,6 +299,27 @@ export class LibreDwgConverter {
|
|
|
287
299
|
}
|
|
288
300
|
}
|
|
289
301
|
}
|
|
302
|
+
// Some DWG writers (including LibreDWG's own) declare first_entity /
|
|
303
|
+
// last_entity handles that resolve to no object, or only link a
|
|
304
|
+
// partial ownership chain. Fall back to entity objects whose owner
|
|
305
|
+
// (ownerhandle / entmode via dwg_entity_owner) names this block.
|
|
306
|
+
// For *Model_Space only, also pick up entities with no resolvable owner.
|
|
307
|
+
if (this.orphanIndexDataPtr != null) {
|
|
308
|
+
const orphans = this.convertOrphanOwnedEntities(this.orphanIndexDataPtr, obj, commonAttrs.handle, isModelSpace(commonAttrs.name) === true);
|
|
309
|
+
if (orphans.length) {
|
|
310
|
+
if (entities.length === 0) {
|
|
311
|
+
entities = orphans;
|
|
312
|
+
}
|
|
313
|
+
else {
|
|
314
|
+
const seen = new Set(entities.map(e => e.handle));
|
|
315
|
+
for (const entity of orphans) {
|
|
316
|
+
if (!seen.has(entity.handle)) {
|
|
317
|
+
entities.push(entity);
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
}
|
|
290
323
|
return {
|
|
291
324
|
...commonAttrs,
|
|
292
325
|
flags: flags,
|
|
@@ -315,6 +348,108 @@ export class LibreDwgConverter {
|
|
|
315
348
|
}
|
|
316
349
|
return entities;
|
|
317
350
|
}
|
|
351
|
+
/**
|
|
352
|
+
* Builds (once) a map of BLOCK_HEADER object pointer → entity object indices
|
|
353
|
+
* for entities that are not reachable through the ownership chain, then
|
|
354
|
+
* converts the entities owned by `blockHeaderPtr`.
|
|
355
|
+
*
|
|
356
|
+
* @param includeOwnerless - When true (only for *Model_Space), also convert
|
|
357
|
+
* entities that still have no resolvable owner after ownerhandle + entmode
|
|
358
|
+
* fallback via dwg_entity_owner.
|
|
359
|
+
*/
|
|
360
|
+
convertOrphanOwnedEntities(data, blockHeaderPtr, ownerHandle, includeOwnerless) {
|
|
361
|
+
this.ensureOrphanEntityIndex(data);
|
|
362
|
+
const byBlock = this.orphanEntitiesByBlock ?? new Map();
|
|
363
|
+
const owned = byBlock.get(blockHeaderPtr) ?? [];
|
|
364
|
+
const ownerless = includeOwnerless && this.ownerlessOrphanIndices
|
|
365
|
+
? this.ownerlessOrphanIndices
|
|
366
|
+
: [];
|
|
367
|
+
const indices = owned.length && ownerless.length
|
|
368
|
+
? owned.concat(ownerless)
|
|
369
|
+
: owned.length
|
|
370
|
+
? owned
|
|
371
|
+
: ownerless;
|
|
372
|
+
if (indices.length === 0) {
|
|
373
|
+
return [];
|
|
374
|
+
}
|
|
375
|
+
const libredwg = this.libredwg;
|
|
376
|
+
const converter = this.entityConverter;
|
|
377
|
+
const entities = [];
|
|
378
|
+
for (const index of indices) {
|
|
379
|
+
const object = libredwg.dwg_get_object(data, index);
|
|
380
|
+
const entity = converter.convert(object);
|
|
381
|
+
if (entity) {
|
|
382
|
+
entity.ownerBlockRecordSoftId = ownerHandle;
|
|
383
|
+
entities.push(entity);
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
return entities;
|
|
387
|
+
}
|
|
388
|
+
ensureOrphanEntityIndex(data) {
|
|
389
|
+
if (this.orphanEntitiesByBlock) {
|
|
390
|
+
return;
|
|
391
|
+
}
|
|
392
|
+
const libredwg = this.libredwg;
|
|
393
|
+
const numObjects = libredwg.dwg_get_num_objects(data);
|
|
394
|
+
const indexByEntityPtr = new Map();
|
|
395
|
+
const entityIndices = [];
|
|
396
|
+
const blockHeaderPtrs = [];
|
|
397
|
+
// dwg_entity_owner returns a BLOCK_HEADER TIO pointer; map it back to the
|
|
398
|
+
// Dwg_Object* used as the orphan-index key.
|
|
399
|
+
const blockObjByTio = new Map();
|
|
400
|
+
for (let i = 0; i < numObjects; i++) {
|
|
401
|
+
const obj = libredwg.dwg_get_object(data, i);
|
|
402
|
+
if (!obj)
|
|
403
|
+
continue;
|
|
404
|
+
if (libredwg.dwg_object_get_supertype(obj) ===
|
|
405
|
+
Dwg_Object_Supertype.DWG_SUPERTYPE_ENTITY) {
|
|
406
|
+
entityIndices.push(i);
|
|
407
|
+
indexByEntityPtr.set(obj, i);
|
|
408
|
+
}
|
|
409
|
+
else if (libredwg.dwg_object_get_fixedtype(obj) ===
|
|
410
|
+
Dwg_Object_Type.DWG_TYPE_BLOCK_HEADER) {
|
|
411
|
+
blockHeaderPtrs.push(obj);
|
|
412
|
+
const tio = libredwg.dwg_object_to_object_tio(obj);
|
|
413
|
+
if (tio)
|
|
414
|
+
blockObjByTio.set(tio, obj);
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
const claimed = new Set();
|
|
418
|
+
for (const blockHeader of blockHeaderPtrs) {
|
|
419
|
+
let current = libredwg.get_first_owned_entity(blockHeader);
|
|
420
|
+
let steps = 0;
|
|
421
|
+
while (current && steps++ <= entityIndices.length) {
|
|
422
|
+
const index = indexByEntityPtr.get(current);
|
|
423
|
+
if (index === undefined || claimed.has(index))
|
|
424
|
+
break;
|
|
425
|
+
claimed.add(index);
|
|
426
|
+
current = libredwg.get_next_owned_entity(blockHeader, current);
|
|
427
|
+
}
|
|
428
|
+
}
|
|
429
|
+
const orphansByBlock = new Map();
|
|
430
|
+
const ownerless = [];
|
|
431
|
+
for (const index of entityIndices) {
|
|
432
|
+
if (claimed.has(index))
|
|
433
|
+
continue;
|
|
434
|
+
const obj = libredwg.dwg_get_object(data, index);
|
|
435
|
+
const etio = obj ? libredwg.dwg_object_to_entity_tio(obj) : 0;
|
|
436
|
+
// Resolves ownerhandle, then entmode → MSPACE/PSPACE (LibreDWG).
|
|
437
|
+
const ownerTio = etio ? libredwg.dwg_entity_owner(etio) : 0;
|
|
438
|
+
const owner = ownerTio ? (blockObjByTio.get(ownerTio) ?? 0) : 0;
|
|
439
|
+
if (owner) {
|
|
440
|
+
const owned = orphansByBlock.get(owner);
|
|
441
|
+
if (owned)
|
|
442
|
+
owned.push(index);
|
|
443
|
+
else
|
|
444
|
+
orphansByBlock.set(owner, [index]);
|
|
445
|
+
}
|
|
446
|
+
else {
|
|
447
|
+
ownerless.push(index);
|
|
448
|
+
}
|
|
449
|
+
}
|
|
450
|
+
this.orphanEntitiesByBlock = orphansByBlock;
|
|
451
|
+
this.ownerlessOrphanIndices = ownerless;
|
|
452
|
+
}
|
|
318
453
|
convertDimStyle(item, obj) {
|
|
319
454
|
const libredwg = this.libredwg;
|
|
320
455
|
const commonAttrs = this.getCommonTableEntryAttrs(item, obj);
|
|
@@ -1320,7 +1320,7 @@ export class LibreEntityConverter {
|
|
|
1320
1320
|
const elevation = libredwg.dwg_dynapi_entity_data(entity, 'elevation');
|
|
1321
1321
|
const thickness = libredwg.dwg_dynapi_entity_data(entity, 'thickness');
|
|
1322
1322
|
const extrusionDirection = libredwg.dwg_dynapi_entity_data(entity, 'extrusion');
|
|
1323
|
-
const vertices = libredwg.dwg_entity_polyline_2d_get_vertices(object);
|
|
1323
|
+
const vertices = libredwg.dwg_entity_polyline_2d_get_vertices(object) ?? [];
|
|
1324
1324
|
return {
|
|
1325
1325
|
type: 'POLYLINE2D',
|
|
1326
1326
|
...commonAttrs,
|
|
@@ -1356,7 +1356,7 @@ export class LibreEntityConverter {
|
|
|
1356
1356
|
const startWidth = libredwg.dwg_dynapi_entity_data(entity, 'start_width');
|
|
1357
1357
|
const endWidth = libredwg.dwg_dynapi_entity_data(entity, 'end_width');
|
|
1358
1358
|
const extrusionDirection = libredwg.dwg_dynapi_entity_data(entity, 'extrusion');
|
|
1359
|
-
const vertices = libredwg.dwg_entity_polyline_3d_get_vertices(object);
|
|
1359
|
+
const vertices = libredwg.dwg_entity_polyline_3d_get_vertices(object) ?? [];
|
|
1360
1360
|
return {
|
|
1361
1361
|
type: 'POLYLINE3D',
|
|
1362
1362
|
...commonAttrs,
|
package/lib/database/codepage.js
CHANGED
|
@@ -73,7 +73,8 @@ const encodings = [
|
|
|
73
73
|
'shift-jis', // DOS Japanese (shiftjis)
|
|
74
74
|
'macintosh', // 23
|
|
75
75
|
'big5',
|
|
76
|
-
'
|
|
76
|
+
// WHATWG 'euc-kr' decodes windows-949, which covers CP949 (Wansung + UHC).
|
|
77
|
+
'euc-kr', // Korean (CP949 / Wansung + UHC)
|
|
77
78
|
'utf-8', // Johab?
|
|
78
79
|
'ibm866', // Russian
|
|
79
80
|
'windows-1250', // Central + Eastern European
|
package/lib/database/index.d.ts
CHANGED
package/lib/database/index.js
CHANGED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AutoCAD stores characters outside the drawing's code page as `\U+XXXX`
|
|
3
|
+
* escape sequences (exactly four hex digits). Decode them so TEXT / MTEXT /
|
|
4
|
+
* ATTRIB / layer names become real Unicode instead of literal escapes.
|
|
5
|
+
*
|
|
6
|
+
* Adjacent high/low surrogate escapes (e.g. `\U+D83D\U+DE00`) expand to
|
|
7
|
+
* UTF-16 code units that form one supplementary-plane character in JS strings.
|
|
8
|
+
*/
|
|
9
|
+
const UNICODE_ESCAPE = /\\U\+([0-9A-Fa-f]{4})/g;
|
|
10
|
+
/**
|
|
11
|
+
* Replaces AutoCAD `\U+XXXX` escapes with the corresponding Unicode characters.
|
|
12
|
+
*/
|
|
13
|
+
export function decodeUnicodeEscapes(text) {
|
|
14
|
+
if (!text || !text.includes('\\U+')) {
|
|
15
|
+
return text;
|
|
16
|
+
}
|
|
17
|
+
return text.replace(UNICODE_ESCAPE, (_, hex) => String.fromCharCode(parseInt(hex, 16)));
|
|
18
|
+
}
|
|
19
|
+
//# sourceMappingURL=textEscapes.js.map
|
package/lib/libredwg.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import createModule from '../wasm/libredwg-web.js';
|
|
2
2
|
import { LibreDwgConverter } from './converter';
|
|
3
|
-
import { dwgCodePageToEncoding, dwgVersions } from './database';
|
|
3
|
+
import { decodeUnicodeEscapes, dwgCodePageToEncoding, dwgVersions } from './database';
|
|
4
4
|
import { SvgConverter } from './svg';
|
|
5
5
|
import { Dwg_Error, Dwg_File_Type, Dwg_Object_Type } from './types';
|
|
6
6
|
export { createModule };
|
|
@@ -799,6 +799,9 @@ export class LibreDwg {
|
|
|
799
799
|
if (value.bin && this.decoder) {
|
|
800
800
|
value.data = this.decoder.decode(value.bin);
|
|
801
801
|
}
|
|
802
|
+
if (typeof value.data === 'string') {
|
|
803
|
+
value.data = decodeUnicodeEscapes(value.data);
|
|
804
|
+
}
|
|
802
805
|
return value;
|
|
803
806
|
}
|
|
804
807
|
/**
|
|
@@ -852,7 +855,14 @@ export class LibreDwg {
|
|
|
852
855
|
* @returns Returns the sub-field value of one complex field.
|
|
853
856
|
*/
|
|
854
857
|
dwg_dynapi_subclass_value(obj, subclass, field) {
|
|
855
|
-
|
|
858
|
+
const value = this.wasmInstance.dwg_dynapi_subclass_value(obj, subclass, field);
|
|
859
|
+
if (value.bin && this.decoder) {
|
|
860
|
+
value.data = this.decoder.decode(value.bin);
|
|
861
|
+
}
|
|
862
|
+
if (typeof value.data === 'string') {
|
|
863
|
+
value.data = decodeUnicodeEscapes(value.data);
|
|
864
|
+
}
|
|
865
|
+
return value;
|
|
856
866
|
}
|
|
857
867
|
/**
|
|
858
868
|
* Returns the sub-field data of one complex field.
|
package/package.json
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"description": "A DWG/DXF JavaScript parser based on libredwg",
|
|
4
4
|
"license": "GPL-3.0",
|
|
5
5
|
"private": false,
|
|
6
|
-
"version": "0.7.
|
|
6
|
+
"version": "0.7.11",
|
|
7
7
|
"author": "MLight Lee <mlight.lee@outlook.com>",
|
|
8
8
|
"type": "module",
|
|
9
9
|
"engines": {
|
|
@@ -87,6 +87,6 @@
|
|
|
87
87
|
"test": "node --test test/node-api.test.mjs",
|
|
88
88
|
"test:node": "pnpm build && pnpm test",
|
|
89
89
|
"publish:npm": "pnpm publish --access public --no-git-checks",
|
|
90
|
-
"release": "node
|
|
90
|
+
"release": "node script/release.mjs"
|
|
91
91
|
}
|
|
92
92
|
}
|