From f97acc3aaf1927ce12c80f7a401f8399fd2f4867 Mon Sep 17 00:00:00 2001 From: Frank Date: Fri, 8 Dec 2023 08:19:03 +0100 Subject: [PATCH 1/7] npm, convert library and wasm action --- .github/workflows/main.yml | 12 ++++ CMakeLists.txt | 10 ++- bindings/js/README.md | 55 +++++++++++++++ bindings/js/index.cjs | 4 ++ bindings/js/index.mjs | 4 ++ bindings/js/package.json | 21 ++++++ configure.ac | 10 +++ programs/convert.c | 134 +++++++++++++++++++++++++++++++++++++ 8 files changed, 247 insertions(+), 3 deletions(-) create mode 100644 bindings/js/README.md create mode 100644 bindings/js/index.cjs create mode 100644 bindings/js/index.mjs create mode 100644 bindings/js/package.json create mode 100644 programs/convert.c diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 1a2faaa716..7e6d946869 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -293,3 +293,15 @@ jobs: - run: ninja - run: copy libredwg.dll test\unit-testing\ - run: ctest . --output-on-failure + wasm: + runs-on: ubuntu-latest + timeout-minutes: 20 + steps: + - name: checkout + uses: actions/checkout@v3 + with: + fetch-depth: 1 + submodules: recursive + - name: Setup Emscripten toolchain + uses: mymindstorm/setup-emsdk@v13 + - name: emmake diff --git a/CMakeLists.txt b/CMakeLists.txt index cbf9341494..831cf6303c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,6 +1,7 @@ cmake_minimum_required(VERSION 2.8...3.27) project(libredwg C) # Supported options -DLIBREDWG_LIBONLY=On +# -DLIBREDWG_CONVERTONLY=On # -DLIBREDWG_DISABLE_WRITE=On # -DLIBREDWG_DISABLE_JSON=On # -DENABLE_MIMALLOC=On @@ -29,6 +30,7 @@ string(STRIP "${NL_PACKAGE_VERSION}" PACKAGE_VERSION) option(BUILD_SHARED_LIBS "shared libredwg library" ON) option(LIBREDWG_LIBONLY "only the libredwg library" OFF) +option(LIBREDWG_CONVERTONLY "only the libredwg convert library" OFF) option(LIBREDWG_DISABLE_WRITE "no libredwg write support" OFF) option(DISABLE_WERROR "no -Werror" OFF) option(ENABLE_LTO "IPO/LTO Link Time Optimizations (default ON)" ON) @@ -264,8 +266,8 @@ set(libredwg_SOURCES src/print.c) add_library(${redwg} - ${libredwg_HEADERS} - ${libredwg_SOURCES}) + ${libredwg_HEADERS} + ${libredwg_SOURCES}) set_property(TARGET ${redwg} PROPERTY C_STANDARD 99) set_property(TARGET ${redwg} PROPERTY C_STANDARD_REQUIRED ON) @@ -283,7 +285,9 @@ target_include_directories(${redwg} PUBLIC link_libraries(${redwg} ${LIBS} ${CMAKE_THREAD_LIBS_INIT}) -if(NOT LIBREDWG_LIBONLY) +if(LIBREDWG_CONVERTONLY) + add_library(convert programs/convert.c) +elseif(NOT LIBREDWG_LIBONLY) if(NOT HAVE_GETOPT_H) set(getopt_c programs/getopt.c) endif(NOT HAVE_GETOPT_H) diff --git a/bindings/js/README.md b/bindings/js/README.md new file mode 100644 index 0000000000..185d7fb707 --- /dev/null +++ b/bindings/js/README.md @@ -0,0 +1,55 @@ +These are the (initial) Javascript bindings for GNU LibreDWG. +You can convert between DWG, DXF, DXFB (binary) and JSON. +It is based on WASM (emscripten). + +Please wait for the official release before using this in production. + +GNU LibreDWG is a free C library to handle DWG files. It aims to be a free replacement for the OpenDWG libraries. DWG is the native file format of AutoCAD. + +LibreDWG is based on LibDWG, originally written by Felipe Castro. + +LibreDWG is in beta development stage. Not all planned features are yet completed, but the API should stay mostly stable. At the moment our decoder (i.e. reader) is done, just some very advanced R2010+ and pre-R13 entities fail to read and are skipped over. The writer is good enough for R2000. Among the example applications we wrote using LibreDWG is a reader (from dwg, dxf, json), a writer (convert from dwg, dxf, json or add from scratch), a rewriter (i.e. saveas), an initial SVG and Postscript conversion, converters from and to DXF and JSON, dwggrep to search for text, and dwglayer to print the list of layers. + +More information: https://www.gnu.org/software/libredwg/ + +Usage: + +```js +import { convert } from 'libredwg' + +let input = /* ... obtain a DWG ArrayBuffer using upload, fetch or IndexedDB */ + +/* + * Available inputs/outputs (case sensitive): dwg, dxf, dxfb, json, jsonString + * jsonString is json as a string, without the cost of internal (de)serialization + * Available DWG/DXF/DXFB versions: [TODO], true = detect / don't care, falsy = no export + * Available log levels: falsy: none, 1/error, 2/warn, 3/info, 4/trace, 5/insane, 9/all + * [TODO buffer sizes including log] + * + * default: + * { + * input: + * from: { dwg: true }, // detect + * json: true, + * level: 'warn' + * } + */ +const res = convert({input, from: { dwg: 'R_2000' }, json: true, dxfb: 'R_2004', level: 'warn'}) + +/* Result: + * { + * error: 'INVALIDDWG', + * log: '...', + * } + * or: + * { + * log: '...', + * json: {...} + * dxfb: + * } + * [TODO list of codes] + */ +console.log('result', res) +``` + +Later versions might add the actual API, native node.js, streams, promises and Typescript. diff --git a/bindings/js/index.cjs b/bindings/js/index.cjs new file mode 100644 index 0000000000..1157aeea74 --- /dev/null +++ b/bindings/js/index.cjs @@ -0,0 +1,4 @@ +exports.convert = (args) => { + const { input, from, to } = args; + console.log("from cjs", args); +}; diff --git a/bindings/js/index.mjs b/bindings/js/index.mjs new file mode 100644 index 0000000000..057d584f99 --- /dev/null +++ b/bindings/js/index.mjs @@ -0,0 +1,4 @@ +export function convert(args) { + const { input, from, to } = args; + console.log("from mjs", args); +} diff --git a/bindings/js/package.json b/bindings/js/package.json new file mode 100644 index 0000000000..8dc59cc279 --- /dev/null +++ b/bindings/js/package.json @@ -0,0 +1,21 @@ +{ + "name": "libredwg", + "version": "0.0.0-dev.0", + "description": "GNU LibreDWG is a free library to handle DWG/DXF files", + "main": "index.js", + "repository": "git://fr-an-k/libredwg.git", + "author": "Frank van Leeuwen", + "keywords": [ + "DWG", + "DXF", + "DXFB" + ], + "license": "ISC", + "private": false, + "exports": { + ".": { + "require": "./index.cjs", + "import": "./index.mjs" + } + } +} diff --git a/configure.ac b/configure.ac index c711ac639e..874e3c31e1 100644 --- a/configure.ac +++ b/configure.ac @@ -450,6 +450,16 @@ AC_CHECK_FUNCS([setenv],[], [AC_MSG_RESULT([setenv not needed. no --enable-trace.])] )) +dnl --convert-only build only the LibreDWG simple convert library +AC_MSG_CHECKING([for --convert-only]) +AC_ARG_ENABLE([convertonly],AS_HELP_STRING([--convert-only],[ + Build only the LibreDWG simple convert library (default: no).]),[],[convertonly=no]) +AM_CONDITIONAL([CONVERTONLY], [test x$convertonly = xyes]) +AS_IF([test x$convertonly = xyes], + AC_DEFINE([CONVERTONLY],1,[Define to build only the LibreDWG simple convert library.]) + AC_MSG_RESULT([yes]), + AC_MSG_RESULT([no (default)])) + dnl --disable-dxf only useful for faster debug/test cycles AC_MSG_CHECKING([for --disable-dxf]) AC_ARG_ENABLE([dxf],AS_HELP_STRING([--disable-dxf],[ diff --git a/programs/convert.c b/programs/convert.c new file mode 100644 index 0000000000..87b8cd2208 --- /dev/null +++ b/programs/convert.c @@ -0,0 +1,134 @@ +/*****************************************************************************/ +/* LibreDWG - free implementation of the DWG file format */ +/* */ +/* Copyright (C) 2018-2023 Free Software Foundation, Inc. */ +/* */ +/* This library is free software, licensed under the terms of the GNU */ +/* General Public License as published by the Free Software Foundation, */ +/* either version 3 of the License, or (at your option) any later version. */ +/* You should have received a copy of the GNU General Public License */ +/* along with this program. If not, see . */ +/*****************************************************************************/ + +/* convert.c: simple API to read/write any format. + * Single read, multiple write supported. + * You should call done() once you're done. + * + * written by Frank van Leeuwen + */ + +#include "dwg.h" +#include "decode.h" +#ifndef DISABLE_JSON +# include "in_json.h" +# include "out_json.h" +#endif +#ifndef DISABLE_DXF +# include "in_dxf.h" +# include "out_dxf.h" +#endif + +Dwg_Data dwg; +int readError = DWG_ERR_IOERROR; + +EXPORT +void done() { + if (!readError) + dwg_free(&dwg); +} + +EXPORT +void read(unsigned char* buf, size_t size, const char* type, unsigned char level) { + Bit_Chain dat = EMPTY_CHAIN (0); + dat.chain = buf; + dat.size = size; + dat.opts = level & DWG_OPTS_LOGLEVEL; + memset (&dwg, 0, sizeof (Dwg_Data)); + + if (!readError) + done(); + + int error = 0; + if (!strcmp(type, "dwg")) { + error = dwg_decode (&dat, &dwg); + if (error) + dwg_free(&dwg); + } +#ifndef DISABLE_DXF + else if (!strcmp(type, "dxf")) { + error = dwg_read_dxf (&dat, &dwg); + } + else if (!strcmp(type, "dxfb")) { + error = dwg_read_dxfb (&dat, &dwg); + } +#endif +#ifndef DISABLE_JSON + else if (!strcmp(type, "json")) { + error = dwg_read_json (&dat, &dwg); + } +#endif + else if (!strcmp(type, "geojson")) { + error = DWG_ERR_NOTYETSUPPORTED; + } + else if (!strcmp(type, "yaml")) { + error = DWG_ERR_NOTYETSUPPORTED; + } + else if (!strcmp(type, "xml")) { + error = DWG_ERR_NOTYETSUPPORTED; + } + else { + error = DWG_ERR_INVALIDTYPE; + } + readError = error; + return error; +} + +EXPORT +void write(unsigned char* buf, size_t size, const char* type, const char* version, int level, bool minimal) { + Bit_Chain dat = EMPTY_CHAIN (0); + dat.chain = buf; + dat.size = size; + dat.opts = (level & DWG_OPTS_LOGLEVEL) | (minimal ? DWG_OPTS_MINIMAL : 0); + + if (readError) + return DWG_ERR_IOERROR; + if (version && *version) + dwg.header.version = dwg_version_as(version); + if (dwg.header.version == R_INVALID) { + return DWG_ERR_INVALIDTYPE; + } + + int error = 0; + if (!type) { + error = DWG_ERR_INVALIDTYPE; + } + else if (!strcmp(type, "dwg")) { + error = dwg_encode(&dat, &dwg); + } +#ifndef DISABLE_DXF + else if (!strcmp(type, "dxf")) { + error = dwg_write_dxf(&dat, &dwg); + } + else if (!strcmp(type, "dxfb")) { + error = dwg_write_dxfb(&dat, &dwg); + } +#endif +#ifndef DISABLE_JSON + else if (!strcmp(type, "json")) { + error = dwg_write_json(&dat, &dwg); + } + else if (!strcmp(type, "geojson")) { + error = dwg_write_geojson(&dat, &dwg); + } +#endif + else if (!strcmp(type, "yaml")) { + error = DWG_ERR_NOTYETSUPPORTED; + } + else if (!strcmp(type, "xml")) { + error = DWG_ERR_NOTYETSUPPORTED; + } + else { + error = DWG_ERR_INVALIDTYPE; + } + return error; +} From 11d928b35671c2f5f2399b92987effaaa862f55b Mon Sep 17 00:00:00 2001 From: Frank Date: Fri, 8 Dec 2023 08:21:11 +0100 Subject: [PATCH 2/7] npm, convert library and wasm action --- src/config.h.in | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/config.h.in b/src/config.h.in index fe3ca5b163..dd75028c81 100644 --- a/src/config.h.in +++ b/src/config.h.in @@ -6,6 +6,9 @@ /* Defined to or if strcasecmp is found */ #undef AX_STRCASECMP_HEADER +/* Define to build only the LibreDWG simple convert library. */ +#undef CONVERTONLY + /* Define to 1 if using 'alloca.c'. */ #undef C_ALLOCA From 4cc7e64b4843e59710e6c0ccb991bc494a9b2fba Mon Sep 17 00:00:00 2001 From: Frank Date: Fri, 8 Dec 2023 08:23:57 +0100 Subject: [PATCH 3/7] npm, convert library and wasm action --- .github/workflows/main.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 7e6d946869..ca3b67f580 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -304,4 +304,5 @@ jobs: submodules: recursive - name: Setup Emscripten toolchain uses: mymindstorm/setup-emsdk@v13 - - name: emmake + - run: emconfigure ./configure --convert-only + - run: emmake -j From 81e74cb7196ae90663b565184acb2649f5254ad2 Mon Sep 17 00:00:00 2001 From: Frank Date: Fri, 8 Dec 2023 08:31:14 +0100 Subject: [PATCH 4/7] manually test workflow --- .github/workflows/main.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index ca3b67f580..70485471b0 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -11,6 +11,9 @@ on: pull_request: branches: - '*' + workflow_dispatch: + branches: + - '*' concurrency: group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} From 20fdec6a9913b6e9c0fbcafded0fc09389164fb1 Mon Sep 17 00:00:00 2001 From: Frank Date: Sat, 9 Dec 2023 21:46:26 +0100 Subject: [PATCH 5/7] flag still not working --- .github/workflows/main.yml | 5 +++-- CMakeLists.txt | 14 ++++++++------ bindings/js/README.md | 3 ++- configure.ac | 19 +++++++++---------- src/config.h.in | 2 +- 5 files changed, 23 insertions(+), 20 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 70485471b0..aee32fc0b2 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -307,5 +307,6 @@ jobs: submodules: recursive - name: Setup Emscripten toolchain uses: mymindstorm/setup-emsdk@v13 - - run: emconfigure ./configure --convert-only - - run: emmake -j + - run: ./autogen.sh + - run: emconfigure ./configure --enable-libconvert-only --disable-bindings --disable-shared + - run: emmake make -j \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt index 831cf6303c..e4246ac76e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,7 +1,7 @@ cmake_minimum_required(VERSION 2.8...3.27) project(libredwg C) # Supported options -DLIBREDWG_LIBONLY=On -# -DLIBREDWG_CONVERTONLY=On +# -DLIBREDWG_LIBCONVERTONLY=On # -DLIBREDWG_DISABLE_WRITE=On # -DLIBREDWG_DISABLE_JSON=On # -DENABLE_MIMALLOC=On @@ -30,7 +30,7 @@ string(STRIP "${NL_PACKAGE_VERSION}" PACKAGE_VERSION) option(BUILD_SHARED_LIBS "shared libredwg library" ON) option(LIBREDWG_LIBONLY "only the libredwg library" OFF) -option(LIBREDWG_CONVERTONLY "only the libredwg convert library" OFF) +option(LIBREDWG_LIBCONVERTONLY "only the libredwg pure file format conversion library" OFF) option(LIBREDWG_DISABLE_WRITE "no libredwg write support" OFF) option(DISABLE_WERROR "no -Werror" OFF) option(ENABLE_LTO "IPO/LTO Link Time Optimizations (default ON)" ON) @@ -184,8 +184,10 @@ else() add_link_options(-fstack-protector-strong) endif() if (HAVE_C_FSTACK_CLASH_PROTECTION) - add_compile_options(-fstack-clash-protection) - add_link_options(-fstack-clash-protection) + if (NOT LIBREDWG_LIBCONVERTONLY) + add_compile_options(-fstack-clash-protection) + add_link_options(-fstack-clash-protection) + endif() endif() if (HAVE_C_FCF_PROTECTION) add_compile_options(-fcf-protection=full) @@ -285,7 +287,7 @@ target_include_directories(${redwg} PUBLIC link_libraries(${redwg} ${LIBS} ${CMAKE_THREAD_LIBS_INIT}) -if(LIBREDWG_CONVERTONLY) +if(LIBREDWG_LIBCONVERTONLY) add_library(convert programs/convert.c) elseif(NOT LIBREDWG_LIBONLY) if(NOT HAVE_GETOPT_H) @@ -315,7 +317,7 @@ elseif(NOT LIBREDWG_LIBONLY) #target_include_directories(dwggrep PUBLIC pcre2) endif(HAVE_PCRE2_H) -endif(NOT LIBREDWG_LIBONLY) +endif(LIBREDWG_LIBCONVERTONLY) if(ipo_supported) message(STATUS "IPO / LTO enabled") diff --git a/bindings/js/README.md b/bindings/js/README.md index 185d7fb707..d1e66358fd 100644 --- a/bindings/js/README.md +++ b/bindings/js/README.md @@ -1,5 +1,6 @@ These are the (initial) Javascript bindings for GNU LibreDWG. -You can convert between DWG, DXF, DXFB (binary) and JSON. +You can convert between DWG, DXF, DXFB (binary) and JSON and output GeoJSON. +You can output multiple files after reading a single file. It is based on WASM (emscripten). Please wait for the official release before using this in production. diff --git a/configure.ac b/configure.ac index 874e3c31e1..09dca9334f 100644 --- a/configure.ac +++ b/configure.ac @@ -450,16 +450,6 @@ AC_CHECK_FUNCS([setenv],[], [AC_MSG_RESULT([setenv not needed. no --enable-trace.])] )) -dnl --convert-only build only the LibreDWG simple convert library -AC_MSG_CHECKING([for --convert-only]) -AC_ARG_ENABLE([convertonly],AS_HELP_STRING([--convert-only],[ - Build only the LibreDWG simple convert library (default: no).]),[],[convertonly=no]) -AM_CONDITIONAL([CONVERTONLY], [test x$convertonly = xyes]) -AS_IF([test x$convertonly = xyes], - AC_DEFINE([CONVERTONLY],1,[Define to build only the LibreDWG simple convert library.]) - AC_MSG_RESULT([yes]), - AC_MSG_RESULT([no (default)])) - dnl --disable-dxf only useful for faster debug/test cycles AC_MSG_CHECKING([for --disable-dxf]) AC_ARG_ENABLE([dxf],AS_HELP_STRING([--disable-dxf],[ @@ -491,6 +481,15 @@ AS_IF([test x$enable_bindings = xno], AC_MSG_RESULT([yes]), AC_MSG_RESULT([no (default)])) +dnl --enable-libconvert-only +AC_MSG_CHECKING([for --enable-libconvert-only]) +AC_ARG_ENABLE([libconvert-only],AS_HELP_STRING([--enable-libconvert-only],[ + Build only the library for pure file format conversion (default: no).]), + [libconvert_only=yes + AC_MSG_RESULT([yes])], + AC_MSG_RESULT([no (default)])) +AM_CONDITIONAL([LIBCONVERTONLY], [test x$libconvert_only = xyes]) + dnl --enable-check-less AC_MSG_CHECKING([for --enable-check-less]) AC_ARG_ENABLE([check-less],AS_HELP_STRING([--enable-check-less],[ diff --git a/src/config.h.in b/src/config.h.in index dd75028c81..7ec176e908 100644 --- a/src/config.h.in +++ b/src/config.h.in @@ -7,7 +7,7 @@ #undef AX_STRCASECMP_HEADER /* Define to build only the LibreDWG simple convert library. */ -#undef CONVERTONLY +#undef LIBCONVERTONLY /* Define to 1 if using 'alloca.c'. */ #undef C_ALLOCA From 4836dff4f3805a90bb194d65cbfb2e9753a62700 Mon Sep 17 00:00:00 2001 From: Frank Date: Sat, 9 Dec 2023 21:51:10 +0100 Subject: [PATCH 6/7] undo --- CMakeLists.txt | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index e4246ac76e..aaf6ebb85b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -183,11 +183,9 @@ else() add_compile_options(-fstack-protector-strong) add_link_options(-fstack-protector-strong) endif() - if (HAVE_C_FSTACK_CLASH_PROTECTION) - if (NOT LIBREDWG_LIBCONVERTONLY) - add_compile_options(-fstack-clash-protection) - add_link_options(-fstack-clash-protection) - endif() + if (NOT LIBREDWG_LIBCONVERTONLY) + add_compile_options(-fstack-clash-protection) + add_link_options(-fstack-clash-protection) endif() if (HAVE_C_FCF_PROTECTION) add_compile_options(-fcf-protection=full) @@ -268,8 +266,8 @@ set(libredwg_SOURCES src/print.c) add_library(${redwg} - ${libredwg_HEADERS} - ${libredwg_SOURCES}) + ${libredwg_HEADERS} + ${libredwg_SOURCES}) set_property(TARGET ${redwg} PROPERTY C_STANDARD 99) set_property(TARGET ${redwg} PROPERTY C_STANDARD_REQUIRED ON) From 16e8294a665a78b8a9dd6348cbcdc8b5e1160807 Mon Sep 17 00:00:00 2001 From: Frank Date: Sat, 9 Dec 2023 21:57:52 +0100 Subject: [PATCH 7/7] undo --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index aaf6ebb85b..51c3d0be23 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -183,7 +183,7 @@ else() add_compile_options(-fstack-protector-strong) add_link_options(-fstack-protector-strong) endif() - if (NOT LIBREDWG_LIBCONVERTONLY) + if (HAVE_C_FSTACK_CLASH_PROTECTION) add_compile_options(-fstack-clash-protection) add_link_options(-fstack-clash-protection) endif()