diff --git a/.launch/Build SCViewer.launch b/.launch/Build SCViewer.launch
index 4af4922..cd3613a 100644
--- a/.launch/Build SCViewer.launch
+++ b/.launch/Build SCViewer.launch
@@ -18,6 +18,6 @@
-
+
diff --git a/README.md b/README.md
index e330fb0..ed03831 100644
--- a/README.md
+++ b/README.md
@@ -1,12 +1,8 @@
SCViewer
========
-SCViewer is composed of a set of eclipse plugins to display VCD and transaction streams
-created by the SystemC VCD trace implementation and the SystemC Verification Library (SCV).
-For further description of the SCV please refer to
-http://www.accellera.org/activities/committees/systemc-verification.
-
-> If you encounter issue when running on Linux please try running as `SWT_GTK3=0 scviewer` as there exist issues wiht GTK3.
+SCViewer is composed of a set of eclipse plugins to display VCD (e.g. created by SystemC VCD trace) and transaction streams. Those streams can be
+created by the SystemC Verification Library (SCV, For further description of the SCV please refer to https://www.accellera.org/activities/working-groups/systemc-verification) or by the **L**ight**w**eight **T**ranasaction **R**ecording for SystemC ( [LWTR4SC](https://github.com/Minres/LWTR4SC) ).
The viewer has the following features
- support of VCD files (compressed and uncompressed)
@@ -18,6 +14,8 @@ The viewer has the following features
- sqlite based
- visualization of transaction relations
+> If you encounter issue when running on Linux please try running as `SWT_GTK3=0 scviewer` as there exist issues wiht GTK3.
+
To build the plugins the Eclipse SDK or PDE can be used.
Key Shortcuts
diff --git a/doc/com.minres.scviewer.doc/.settings/org.eclipse.core.resources.prefs b/doc/com.minres.scviewer.doc/.settings/org.eclipse.core.resources.prefs
new file mode 100644
index 0000000..99f26c0
--- /dev/null
+++ b/doc/com.minres.scviewer.doc/.settings/org.eclipse.core.resources.prefs
@@ -0,0 +1,2 @@
+eclipse.preferences.version=1
+encoding/=UTF-8
diff --git a/doc/com.minres.scviewer.doc/pom.xml b/doc/com.minres.scviewer.doc/pom.xml
index bf07081..3bea441 100644
--- a/doc/com.minres.scviewer.doc/pom.xml
+++ b/doc/com.minres.scviewer.doc/pom.xml
@@ -7,7 +7,7 @@
com.minres.scviewer
com.minres.scviewer.parent
- 2.17.3
+ 2.18.0
../..
diff --git a/features/com.minres.scviewer.database.feature/.settings/org.eclipse.core.resources.prefs b/features/com.minres.scviewer.database.feature/.settings/org.eclipse.core.resources.prefs
new file mode 100644
index 0000000..99f26c0
--- /dev/null
+++ b/features/com.minres.scviewer.database.feature/.settings/org.eclipse.core.resources.prefs
@@ -0,0 +1,2 @@
+eclipse.preferences.version=1
+encoding/=UTF-8
diff --git a/features/com.minres.scviewer.database.feature/feature.xml b/features/com.minres.scviewer.database.feature/feature.xml
index 0aa2e38..004f8e3 100644
--- a/features/com.minres.scviewer.database.feature/feature.xml
+++ b/features/com.minres.scviewer.database.feature/feature.xml
@@ -77,4 +77,12 @@ http://www.eclipse.org/legal/epl-v10.html
version="0.0.0"
unpack="false"/>
+
+
diff --git a/features/com.minres.scviewer.database.feature/pom.xml b/features/com.minres.scviewer.database.feature/pom.xml
index 27095a0..dc09d82 100644
--- a/features/com.minres.scviewer.database.feature/pom.xml
+++ b/features/com.minres.scviewer.database.feature/pom.xml
@@ -5,7 +5,7 @@
com.minres.scviewer
com.minres.scviewer.parent
- 2.17.3
+ 2.18.0
../..
3.0.0-SNAPSHOT
diff --git a/features/com.minres.scviewer.e4.feature/.settings/org.eclipse.core.resources.prefs b/features/com.minres.scviewer.e4.feature/.settings/org.eclipse.core.resources.prefs
new file mode 100644
index 0000000..99f26c0
--- /dev/null
+++ b/features/com.minres.scviewer.e4.feature/.settings/org.eclipse.core.resources.prefs
@@ -0,0 +1,2 @@
+eclipse.preferences.version=1
+encoding/=UTF-8
diff --git a/features/com.minres.scviewer.e4.feature/pom.xml b/features/com.minres.scviewer.e4.feature/pom.xml
index 7b1b9da..452b73b 100644
--- a/features/com.minres.scviewer.e4.feature/pom.xml
+++ b/features/com.minres.scviewer.e4.feature/pom.xml
@@ -5,7 +5,7 @@
com.minres.scviewer
com.minres.scviewer.parent
- 2.17.3
+ 2.18.0
../..
1.1.0-SNAPSHOT
diff --git a/features/com.minres.scviewer.e4.help.feature/.settings/org.eclipse.core.resources.prefs b/features/com.minres.scviewer.e4.help.feature/.settings/org.eclipse.core.resources.prefs
new file mode 100644
index 0000000..99f26c0
--- /dev/null
+++ b/features/com.minres.scviewer.e4.help.feature/.settings/org.eclipse.core.resources.prefs
@@ -0,0 +1,2 @@
+eclipse.preferences.version=1
+encoding/=UTF-8
diff --git a/features/com.minres.scviewer.e4.help.feature/pom.xml b/features/com.minres.scviewer.e4.help.feature/pom.xml
index 3c20d60..223bbae 100644
--- a/features/com.minres.scviewer.e4.help.feature/pom.xml
+++ b/features/com.minres.scviewer.e4.help.feature/pom.xml
@@ -5,7 +5,7 @@
com.minres.scviewer
com.minres.scviewer.parent
- 2.17.3
+ 2.18.0
../..
1.0.0-SNAPSHOT
diff --git a/features/com.minres.scviewer.e4.platform.feature/.settings/org.eclipse.core.resources.prefs b/features/com.minres.scviewer.e4.platform.feature/.settings/org.eclipse.core.resources.prefs
new file mode 100644
index 0000000..99f26c0
--- /dev/null
+++ b/features/com.minres.scviewer.e4.platform.feature/.settings/org.eclipse.core.resources.prefs
@@ -0,0 +1,2 @@
+eclipse.preferences.version=1
+encoding/=UTF-8
diff --git a/features/com.minres.scviewer.e4.platform.feature/pom.xml b/features/com.minres.scviewer.e4.platform.feature/pom.xml
index e9c5d55..3092643 100644
--- a/features/com.minres.scviewer.e4.platform.feature/pom.xml
+++ b/features/com.minres.scviewer.e4.platform.feature/pom.xml
@@ -5,7 +5,7 @@
com.minres.scviewer
com.minres.scviewer.parent
- 2.17.3
+ 2.18.0
../..
1.0.0-SNAPSHOT
diff --git a/features/com.minres.scviewer.feature/.settings/org.eclipse.core.resources.prefs b/features/com.minres.scviewer.feature/.settings/org.eclipse.core.resources.prefs
new file mode 100644
index 0000000..99f26c0
--- /dev/null
+++ b/features/com.minres.scviewer.feature/.settings/org.eclipse.core.resources.prefs
@@ -0,0 +1,2 @@
+eclipse.preferences.version=1
+encoding/=UTF-8
diff --git a/features/com.minres.scviewer.feature/pom.xml b/features/com.minres.scviewer.feature/pom.xml
index 8b43b83..6ea6f9c 100644
--- a/features/com.minres.scviewer.feature/pom.xml
+++ b/features/com.minres.scviewer.feature/pom.xml
@@ -5,7 +5,7 @@
com.minres.scviewer
com.minres.scviewer.parent
- 2.17.3
+ 2.18.0
../..
1.1.0-SNAPSHOT
diff --git a/features/com.minres.scviewer.ui.feature/.settings/org.eclipse.core.resources.prefs b/features/com.minres.scviewer.ui.feature/.settings/org.eclipse.core.resources.prefs
new file mode 100644
index 0000000..99f26c0
--- /dev/null
+++ b/features/com.minres.scviewer.ui.feature/.settings/org.eclipse.core.resources.prefs
@@ -0,0 +1,2 @@
+eclipse.preferences.version=1
+encoding/=UTF-8
diff --git a/features/com.minres.scviewer.ui.feature/pom.xml b/features/com.minres.scviewer.ui.feature/pom.xml
index 5858e87..f00dea7 100644
--- a/features/com.minres.scviewer.ui.feature/pom.xml
+++ b/features/com.minres.scviewer.ui.feature/pom.xml
@@ -5,7 +5,7 @@
com.minres.scviewer
com.minres.scviewer.parent
- 2.17.3
+ 2.18.0
../..
1.1.0-SNAPSHOT
diff --git a/plugins/com.minres.scviewer.database.fst/.classpath b/plugins/com.minres.scviewer.database.fst/.classpath
new file mode 100644
index 0000000..f618580
--- /dev/null
+++ b/plugins/com.minres.scviewer.database.fst/.classpath
@@ -0,0 +1,17 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/plugins/com.minres.scviewer.database.fst/.gitignore b/plugins/com.minres.scviewer.database.fst/.gitignore
new file mode 100644
index 0000000..ddc25c7
--- /dev/null
+++ b/plugins/com.minres.scviewer.database.fst/.gitignore
@@ -0,0 +1,3 @@
+/bin/
+/.settings/
+/target/
diff --git a/plugins/com.minres.scviewer.database.fst/.project b/plugins/com.minres.scviewer.database.fst/.project
new file mode 100644
index 0000000..6ccc312
--- /dev/null
+++ b/plugins/com.minres.scviewer.database.fst/.project
@@ -0,0 +1,33 @@
+
+
+ com.minres.scviewer.database.fst
+
+
+
+
+
+ org.eclipse.jdt.core.javabuilder
+
+
+
+
+ org.eclipse.pde.ManifestBuilder
+
+
+
+
+ org.eclipse.pde.SchemaBuilder
+
+
+
+
+ org.eclipse.pde.ds.core.builder
+
+
+
+
+
+ org.eclipse.pde.PluginNature
+ org.eclipse.jdt.core.javanature
+
+
diff --git a/plugins/com.minres.scviewer.database.fst/META-INF/MANIFEST.MF b/plugins/com.minres.scviewer.database.fst/META-INF/MANIFEST.MF
new file mode 100644
index 0000000..252894f
--- /dev/null
+++ b/plugins/com.minres.scviewer.database.fst/META-INF/MANIFEST.MF
@@ -0,0 +1,17 @@
+Manifest-Version: 1.0
+Bundle-ManifestVersion: 2
+Bundle-Name: FST signal database
+Bundle-SymbolicName: com.minres.scviewer.database.fst
+Bundle-Version: 1.0.0.qualifier
+Bundle-Vendor: MINRES Technologies GmbH
+Bundle-RequiredExecutionEnvironment: JavaSE-11
+Require-Bundle: com.minres.scviewer.database;bundle-version="1.0.0",
+ org.eclipse.osgi.services;bundle-version="3.4.0",
+ com.google.guava;bundle-version="15.0.0"
+Service-Component: OSGI-INF/component.xml
+Bundle-ActivationPolicy: lazy
+Bundle-ClassPath: lib/jna-5.13.0.jar,
+ lib/jna-jpms-5.13.0.jar,
+ .
+Automatic-Module-Name: com.minres.scviewer.database.fst
+Import-Package: org.osgi.framework;version="1.10.0"
diff --git a/plugins/com.minres.scviewer.database.fst/OSGI-INF/component.xml b/plugins/com.minres.scviewer.database.fst/OSGI-INF/component.xml
new file mode 100644
index 0000000..470fc9f
--- /dev/null
+++ b/plugins/com.minres.scviewer.database.fst/OSGI-INF/component.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
diff --git a/plugins/com.minres.scviewer.database.fst/build.properties b/plugins/com.minres.scviewer.database.fst/build.properties
new file mode 100644
index 0000000..cede501
--- /dev/null
+++ b/plugins/com.minres.scviewer.database.fst/build.properties
@@ -0,0 +1,9 @@
+source.. = src/
+output.. = bin/
+bin.includes = META-INF/,\
+ .,\
+ lib/jna-5.13.0.jar,\
+ lib/jna-jpms-5.13.0.jar,\
+ linux-x86-64/,\
+ win32-x86-64/,\
+ OSGI-INF/
diff --git a/plugins/com.minres.scviewer.database.fst/csrc/fst/.gitignore b/plugins/com.minres.scviewer.database.fst/csrc/fst/.gitignore
new file mode 100644
index 0000000..84c048a
--- /dev/null
+++ b/plugins/com.minres.scviewer.database.fst/csrc/fst/.gitignore
@@ -0,0 +1 @@
+/build/
diff --git a/plugins/com.minres.scviewer.database.fst/csrc/fst/CMakeLists.txt b/plugins/com.minres.scviewer.database.fst/csrc/fst/CMakeLists.txt
new file mode 100644
index 0000000..a658245
--- /dev/null
+++ b/plugins/com.minres.scviewer.database.fst/csrc/fst/CMakeLists.txt
@@ -0,0 +1,35 @@
+cmake_minimum_required (VERSION 3.0)
+
+project (fstlib VERSION 1.0.0)
+
+set(BUILD_SHARED_LIBS ON)
+#find_package(ZLIB REQUIRED)
+include(FetchContent)
+FetchContent_Declare(
+ zlib
+ URL https://www.zlib.net/zlib-1.2.13.tar.gz
+ https://www.zlib.net/fossils/zlib-1.2.13.tar.gz
+ https://github.com/madler/zlib/releases/download/v1.2.13/zlib-1.2.13.tar.gz
+ URL_HASH MD5=9b8aa094c4e5765dabf4da391f00d15c
+)
+FetchContent_Populate(zlib)
+add_subdirectory(${zlib_SOURCE_DIR} ${zlib_BINARY_DIR} EXCLUDE_FROM_ALL)
+add_library(ZLIB::ZLIB ALIAS zlibstatic)
+target_include_directories(zlibstatic INTERFACE ${zlib_BINARY_DIR} ${zlib_SOURCE_DIR})
+
+set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON)
+add_library(fstapi fstapi.c lz4.c fastlz.c fst_helper.c)
+#target_include_directories(fstapi PUBLIC ${CMAKE_CURRENT_SOURCE_DIR} ${ZLIB_INCLUDE_DIRS})
+target_link_libraries(fstapi PRIVATE zlibstatic)
+# hack to avoid creating dummy config.h
+target_compile_definitions(fstapi PRIVATE -DFST_CONFIG_INCLUDE="fstapi.h")
+
+if(MSVC)
+ # define __MINGW32__ to minimize changes to upstream
+ target_compile_definitions(fstapi PRIVATE __MINGW32__ _CRT_SECURE_NO_WARNINGS FST_DO_MISALIGNED_OPS)
+ target_compile_options(fstapi PRIVATE /wd4244 /wd4267 /wd4146 /wd4996)
+endif()
+
+install(TARGETS fstapi
+ LIBRARY DESTINATION .
+ RUNTIME DESTINATION .)
diff --git a/plugins/com.minres.scviewer.database.fst/csrc/fst/block_format.txt b/plugins/com.minres.scviewer.database.fst/csrc/fst/block_format.txt
new file mode 100644
index 0000000..e6fe166
--- /dev/null
+++ b/plugins/com.minres.scviewer.database.fst/csrc/fst/block_format.txt
@@ -0,0 +1,130 @@
+See fstapi.h for the values for the FST_BL_XXX enums.
+
+===========================================================================
+
+compressed wrapper (typically over whole file)
+
+uint8_t FST_BL_ZWRAPPER
+uint64_t section length
+uint64_t length of uncompressed data
+[zlib compressed data]
+
+===========================================================================
+
+header block
+
+uint8_t FST_BL_HDR
+uint64_t section length
+uint64_t start time
+uint64_t end time
+double endian test for "e"
+uint64_t memory used by writer
+uint64_t scope creation count
+uint64_t var creation count
+uint64_t max var idcode
+uint64_t vc section count
+int8_t timescale exponent
+[128 bytes] version
+[128 bytes] date
+
+===========================================================================
+
+geometry block
+
+uint8_t FST_BL_GEOM
+uint64_t section length
+uint64_t length of uncompressed geometry data
+uint64_t maxhandle
+[compressed data]
+
+(length of compressed data is section length - 24)
+
+===========================================================================
+
+hierarchy block
+
+uint8_t FST_BL_HIER
+uint64_t section length
+uint64_t length of uncompressed hier data
+[zlib compressed data]
+
+or
+
+uint8_t FST_BL_HIER_LZ4
+uint64_t section length
+uint64_t length of uncompressed hier data
+[lz4 compressed data]
+
+uint8_t FST_BL_HIER_LZ4DUO
+uint64_t section length
+uint64_t length of uncompressed hier data
+varint length of hier data compressed once with lz4
+[lz4 double compressed data]
+
+
+===========================================================================
+
+dumpon/off block
+
+uint8_t FST_BL_BLACKOUT
+uint64_t section length
+varint num blackouts (section below is repeated this # times)
+[
+uint8_t on/off (nonzero = on)
+varint delta time
+]
+
+===========================================================================
+
+1..n value change blocks:
+
+// header
+
+uint8_t FST_BL_VCDATA (or FST_BL_VCDATA_DYN_ALIAS)
+uint64_t section length
+uint64_t begin time of section
+uint64_t end time of section
+uint64_t amount of buffer memory required in reader for full vc traversal
+varint maxvalpos (length of uncompressed data)
+varint length of compressed data
+varint maxhandle associated with this checkpoint data
+[compressed data]
+
+---
+
+// value changes
+
+varint maxhandle associated with the value change data
+uint8_t pack type ('F' is fastlz, '4' is lz4,
+ others ['Z'/'!'] are zlib)
+
+varint chain 0 compressed data length (0 = uncompressed)
+[compressed data]
+...
+varint chain n compressed data length (0 = uncompressed)
+[compressed data]
+
+---
+
+// index: chain pointer table (from 0..maxhandle-1)
+
+varint if &1 == 1, this is <<1 literal delta
+ if &1 == 0, this is <<1 RLE count of zeros
+ if == 0, next varint is handle of prev chain to use,
+ bit only if FST_BL_VCDATA_DYN_ALIAS or
+ later VCDATA format
+
+---
+
+uint64_t index length (subtract from here to get index position)
+
+---
+
+[compressed data for time section]
+uint64_t uncompressed data length in bytes
+uint64_t compressed data length in bytes
+uint64_t number of time items
+
+// end of section
+
+===========================================================================
diff --git a/plugins/com.minres.scviewer.database.fst/csrc/fst/build.cmd b/plugins/com.minres.scviewer.database.fst/csrc/fst/build.cmd
new file mode 100644
index 0000000..3828461
--- /dev/null
+++ b/plugins/com.minres.scviewer.database.fst/csrc/fst/build.cmd
@@ -0,0 +1,2 @@
+cmake -B build -S . -DCMAKE_INSTALL_PREFIX=../../win32-x86-64
+cmake --build build --target install --config Release
diff --git a/plugins/com.minres.scviewer.database.fst/csrc/fst/build.sh b/plugins/com.minres.scviewer.database.fst/csrc/fst/build.sh
new file mode 100644
index 0000000..8de0e7f
--- /dev/null
+++ b/plugins/com.minres.scviewer.database.fst/csrc/fst/build.sh
@@ -0,0 +1,2 @@
+cmake -B build -S . -DCMAKE_INSTALL_PREFIX=../../linux-x86-64 -DCMAKE_BUILD_TYPE=Release
+cmake --build build --target install
diff --git a/plugins/com.minres.scviewer.database.fst/csrc/fst/fastlz.c b/plugins/com.minres.scviewer.database.fst/csrc/fst/fastlz.c
new file mode 100644
index 0000000..b52a799
--- /dev/null
+++ b/plugins/com.minres.scviewer.database.fst/csrc/fst/fastlz.c
@@ -0,0 +1,549 @@
+/*
+ FastLZ - lightning-fast lossless compression library
+
+ Copyright (C) 2007 Ariya Hidayat (ariya@kde.org)
+ Copyright (C) 2006 Ariya Hidayat (ariya@kde.org)
+ Copyright (C) 2005 Ariya Hidayat (ariya@kde.org)
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ THE SOFTWARE.
+
+ SPDX-License-Identifier: MIT
+*/
+
+#include "fastlz.h"
+
+#if !defined(FASTLZ__COMPRESSOR) && !defined(FASTLZ_DECOMPRESSOR)
+
+/*
+ * Always check for bound when decompressing.
+ * Generally it is best to leave it defined.
+ */
+#define FASTLZ_SAFE
+
+
+/*
+ * Give hints to the compiler for branch prediction optimization.
+ */
+#if defined(__GNUC__) && (__GNUC__ > 2)
+#define FASTLZ_EXPECT_CONDITIONAL(c) (__builtin_expect((c), 1))
+#define FASTLZ_UNEXPECT_CONDITIONAL(c) (__builtin_expect((c), 0))
+#else
+#define FASTLZ_EXPECT_CONDITIONAL(c) (c)
+#define FASTLZ_UNEXPECT_CONDITIONAL(c) (c)
+#endif
+
+/*
+ * Use inlined functions for supported systems.
+ */
+#if defined(__GNUC__) || defined(__DMC__) || defined(__POCC__) || defined(__WATCOMC__) || defined(__SUNPRO_C)
+#define FASTLZ_INLINE inline
+#elif defined(__BORLANDC__) || defined(_MSC_VER) || defined(__LCC__)
+#define FASTLZ_INLINE __inline
+#else
+#define FASTLZ_INLINE
+#endif
+
+/*
+ * Prevent accessing more than 8-bit at once, except on x86 architectures.
+ */
+#if !defined(FASTLZ_STRICT_ALIGN)
+#define FASTLZ_STRICT_ALIGN
+#if defined(__i386__) || defined(__386) /* GNU C, Sun Studio */
+#undef FASTLZ_STRICT_ALIGN
+#elif defined(__i486__) || defined(__i586__) || defined(__i686__) || defined(__amd64) /* GNU C */
+#undef FASTLZ_STRICT_ALIGN
+#elif defined(_M_IX86) /* Intel, MSVC */
+#undef FASTLZ_STRICT_ALIGN
+#elif defined(__386)
+#undef FASTLZ_STRICT_ALIGN
+#elif defined(_X86_) /* MinGW */
+#undef FASTLZ_STRICT_ALIGN
+#elif defined(__I86__) /* Digital Mars */
+#undef FASTLZ_STRICT_ALIGN
+#endif
+#endif
+
+/* prototypes */
+int fastlz_compress(const void* input, int length, void* output);
+int fastlz_compress_level(int level, const void* input, int length, void* output);
+int fastlz_decompress(const void* input, int length, void* output, int maxout);
+
+#define MAX_COPY 32
+#define MAX_LEN 264 /* 256 + 8 */
+#define MAX_DISTANCE 8192
+
+#if !defined(FASTLZ_STRICT_ALIGN)
+#define FASTLZ_READU16(p) *((const flzuint16*)(p))
+#else
+#define FASTLZ_READU16(p) ((p)[0] | (p)[1]<<8)
+#endif
+
+#define HASH_LOG 13
+#define HASH_SIZE (1<< HASH_LOG)
+#define HASH_MASK (HASH_SIZE-1)
+#define HASH_FUNCTION(v,p) { v = FASTLZ_READU16(p); v ^= FASTLZ_READU16(p+1)^(v>>(16-HASH_LOG));v &= HASH_MASK; }
+
+#undef FASTLZ_LEVEL
+#define FASTLZ_LEVEL 1
+
+#undef FASTLZ_COMPRESSOR
+#undef FASTLZ_DECOMPRESSOR
+#define FASTLZ_COMPRESSOR fastlz1_compress
+#define FASTLZ_DECOMPRESSOR fastlz1_decompress
+static FASTLZ_INLINE int FASTLZ_COMPRESSOR(const void* input, int length, void* output);
+static FASTLZ_INLINE int FASTLZ_DECOMPRESSOR(const void* input, int length, void* output, int maxout);
+#include "fastlz.c"
+
+#undef FASTLZ_LEVEL
+#define FASTLZ_LEVEL 2
+
+#undef MAX_DISTANCE
+#define MAX_DISTANCE 8191
+#define MAX_FARDISTANCE (65535+MAX_DISTANCE-1)
+
+#undef FASTLZ_COMPRESSOR
+#undef FASTLZ_DECOMPRESSOR
+#define FASTLZ_COMPRESSOR fastlz2_compress
+#define FASTLZ_DECOMPRESSOR fastlz2_decompress
+static FASTLZ_INLINE int FASTLZ_COMPRESSOR(const void* input, int length, void* output);
+static FASTLZ_INLINE int FASTLZ_DECOMPRESSOR(const void* input, int length, void* output, int maxout);
+#include "fastlz.c"
+
+int fastlz_compress(const void* input, int length, void* output)
+{
+ /* for short block, choose fastlz1 */
+ if(length < 65536)
+ return fastlz1_compress(input, length, output);
+
+ /* else... */
+ return fastlz2_compress(input, length, output);
+}
+
+int fastlz_decompress(const void* input, int length, void* output, int maxout)
+{
+ /* magic identifier for compression level */
+ int level = ((*(const flzuint8*)input) >> 5) + 1;
+
+ if(level == 1)
+ return fastlz1_decompress(input, length, output, maxout);
+ if(level == 2)
+ return fastlz2_decompress(input, length, output, maxout);
+
+ /* unknown level, trigger error */
+ return 0;
+}
+
+int fastlz_compress_level(int level, const void* input, int length, void* output)
+{
+ if(level == 1)
+ return fastlz1_compress(input, length, output);
+ if(level == 2)
+ return fastlz2_compress(input, length, output);
+
+ return 0;
+}
+
+#else /* !defined(FASTLZ_COMPRESSOR) && !defined(FASTLZ_DECOMPRESSOR) */
+
+static FASTLZ_INLINE int FASTLZ_COMPRESSOR(const void* input, int length, void* output)
+{
+ const flzuint8* ip = (const flzuint8*) input;
+ const flzuint8* ip_bound = ip + length - 2;
+ const flzuint8* ip_limit = ip + length - 12;
+ flzuint8* op = (flzuint8*) output;
+
+ const flzuint8* htab[HASH_SIZE];
+ const flzuint8** hslot;
+ flzuint32 hval;
+
+ flzuint32 copy;
+
+ /* sanity check */
+ if(FASTLZ_UNEXPECT_CONDITIONAL(length < 4))
+ {
+ if(length)
+ {
+ /* create literal copy only */
+ *op++ = length-1;
+ ip_bound++;
+ while(ip <= ip_bound)
+ *op++ = *ip++;
+ return length+1;
+ }
+ else
+ return 0;
+ }
+
+ /* initializes hash table */
+ for (hslot = htab; hslot < htab + HASH_SIZE; hslot++)
+ *hslot = ip;
+
+ /* we start with literal copy */
+ copy = 2;
+ *op++ = MAX_COPY-1;
+ *op++ = *ip++;
+ *op++ = *ip++;
+
+ /* main loop */
+ while(FASTLZ_EXPECT_CONDITIONAL(ip < ip_limit))
+ {
+ const flzuint8* ref;
+ flzuint32 distance;
+
+ /* minimum match length */
+ flzuint32 len = 3;
+
+ /* comparison starting-point */
+ const flzuint8* anchor = ip;
+
+ /* check for a run */
+#if FASTLZ_LEVEL==2
+ if(ip[0] == ip[-1] && FASTLZ_READU16(ip-1)==FASTLZ_READU16(ip+1))
+ {
+ distance = 1;
+ /* ip += 3; */ /* scan-build, never used */
+ ref = anchor - 1 + 3;
+ goto match;
+ }
+#endif
+
+ /* find potential match */
+ HASH_FUNCTION(hval,ip);
+ hslot = htab + hval;
+ ref = htab[hval];
+
+ /* calculate distance to the match */
+ distance = anchor - ref;
+
+ /* update hash table */
+ *hslot = anchor;
+
+ /* is this a match? check the first 3 bytes */
+ if(distance==0 ||
+#if FASTLZ_LEVEL==1
+ (distance >= MAX_DISTANCE) ||
+#else
+ (distance >= MAX_FARDISTANCE) ||
+#endif
+ *ref++ != *ip++ || *ref++!=*ip++ || *ref++!=*ip++)
+ goto literal;
+
+#if FASTLZ_LEVEL==2
+ /* far, needs at least 5-byte match */
+ if(distance >= MAX_DISTANCE)
+ {
+ if(*ip++ != *ref++ || *ip++!= *ref++)
+ goto literal;
+ len += 2;
+ }
+
+ match:
+#endif
+
+ /* last matched byte */
+ ip = anchor + len;
+
+ /* distance is biased */
+ distance--;
+
+ if(!distance)
+ {
+ /* zero distance means a run */
+ flzuint8 x = ip[-1];
+ while(ip < ip_bound)
+ if(*ref++ != x) break; else ip++;
+ }
+ else
+ for(;;)
+ {
+ /* safe because the outer check against ip limit */
+ if(*ref++ != *ip++) break;
+ if(*ref++ != *ip++) break;
+ if(*ref++ != *ip++) break;
+ if(*ref++ != *ip++) break;
+ if(*ref++ != *ip++) break;
+ if(*ref++ != *ip++) break;
+ if(*ref++ != *ip++) break;
+ if(*ref++ != *ip++) break;
+ while(ip < ip_bound)
+ if(*ref++ != *ip++) break;
+ break;
+ }
+
+ /* if we have copied something, adjust the copy count */
+ if(copy)
+ /* copy is biased, '0' means 1 byte copy */
+ *(op-copy-1) = copy-1;
+ else
+ /* back, to overwrite the copy count */
+ op--;
+
+ /* reset literal counter */
+ copy = 0;
+
+ /* length is biased, '1' means a match of 3 bytes */
+ ip -= 3;
+ len = ip - anchor;
+
+ /* encode the match */
+#if FASTLZ_LEVEL==2
+ if(distance < MAX_DISTANCE)
+ {
+ if(len < 7)
+ {
+ *op++ = (len << 5) + (distance >> 8);
+ *op++ = (distance & 255);
+ }
+ else
+ {
+ *op++ = (7 << 5) + (distance >> 8);
+ for(len-=7; len >= 255; len-= 255)
+ *op++ = 255;
+ *op++ = len;
+ *op++ = (distance & 255);
+ }
+ }
+ else
+ {
+ /* far away, but not yet in the another galaxy... */
+ if(len < 7)
+ {
+ distance -= MAX_DISTANCE;
+ *op++ = (len << 5) + 31;
+ *op++ = 255;
+ *op++ = distance >> 8;
+ *op++ = distance & 255;
+ }
+ else
+ {
+ distance -= MAX_DISTANCE;
+ *op++ = (7 << 5) + 31;
+ for(len-=7; len >= 255; len-= 255)
+ *op++ = 255;
+ *op++ = len;
+ *op++ = 255;
+ *op++ = distance >> 8;
+ *op++ = distance & 255;
+ }
+ }
+#else
+
+ if(FASTLZ_UNEXPECT_CONDITIONAL(len > MAX_LEN-2))
+ while(len > MAX_LEN-2)
+ {
+ *op++ = (7 << 5) + (distance >> 8);
+ *op++ = MAX_LEN - 2 - 7 -2;
+ *op++ = (distance & 255);
+ len -= MAX_LEN-2;
+ }
+
+ if(len < 7)
+ {
+ *op++ = (len << 5) + (distance >> 8);
+ *op++ = (distance & 255);
+ }
+ else
+ {
+ *op++ = (7 << 5) + (distance >> 8);
+ *op++ = len - 7;
+ *op++ = (distance & 255);
+ }
+#endif
+
+ /* update the hash at match boundary */
+ HASH_FUNCTION(hval,ip);
+ htab[hval] = ip++;
+ HASH_FUNCTION(hval,ip);
+ htab[hval] = ip++;
+
+ /* assuming literal copy */
+ *op++ = MAX_COPY-1;
+
+ continue;
+
+ literal:
+ *op++ = *anchor++;
+ ip = anchor;
+ copy++;
+ if(FASTLZ_UNEXPECT_CONDITIONAL(copy == MAX_COPY))
+ {
+ copy = 0;
+ *op++ = MAX_COPY-1;
+ }
+ }
+
+ /* left-over as literal copy */
+ ip_bound++;
+ while(ip <= ip_bound)
+ {
+ *op++ = *ip++;
+ copy++;
+ if(copy == MAX_COPY)
+ {
+ copy = 0;
+ *op++ = MAX_COPY-1;
+ }
+ }
+
+ /* if we have copied something, adjust the copy length */
+ if(copy)
+ *(op-copy-1) = copy-1;
+ else
+ op--;
+
+#if FASTLZ_LEVEL==2
+ /* marker for fastlz2 */
+ *(flzuint8*)output |= (1 << 5);
+#endif
+
+ return op - (flzuint8*)output;
+}
+
+static FASTLZ_INLINE int FASTLZ_DECOMPRESSOR(const void* input, int length, void* output, int maxout)
+{
+ const flzuint8* ip = (const flzuint8*) input;
+ const flzuint8* ip_limit = ip + length;
+ flzuint8* op = (flzuint8*) output;
+ flzuint8* op_limit = op + maxout;
+ flzuint32 ctrl = (*ip++) & 31;
+ int loop = 1;
+
+ do
+ {
+ const flzuint8* ref = op;
+ flzuint32 len = ctrl >> 5;
+ flzuint32 ofs = (ctrl & 31) << 8;
+
+ if(ctrl >= 32)
+ {
+#if FASTLZ_LEVEL==2
+ flzuint8 code;
+#endif
+ len--;
+ ref -= ofs;
+ if (len == 7-1)
+#if FASTLZ_LEVEL==1
+ len += *ip++;
+ ref -= *ip++;
+#else
+ do
+ {
+ code = *ip++;
+ len += code;
+ } while (code==255);
+ code = *ip++;
+ ref -= code;
+
+ /* match from 16-bit distance */
+ if(FASTLZ_UNEXPECT_CONDITIONAL(code==255))
+ if(FASTLZ_EXPECT_CONDITIONAL(ofs==(31 << 8)))
+ {
+ ofs = (*ip++) << 8;
+ ofs += *ip++;
+ ref = op - ofs - MAX_DISTANCE;
+ }
+#endif
+
+#ifdef FASTLZ_SAFE
+ if (FASTLZ_UNEXPECT_CONDITIONAL(op + len + 3 > op_limit))
+ return 0;
+
+ if (FASTLZ_UNEXPECT_CONDITIONAL(ref-1 < (flzuint8 *)output))
+ return 0;
+#endif
+
+ if(FASTLZ_EXPECT_CONDITIONAL(ip < ip_limit))
+ ctrl = *ip++;
+ else
+ loop = 0;
+
+ if(ref == op)
+ {
+ /* optimize copy for a run */
+ flzuint8 b = ref[-1];
+ *op++ = b;
+ *op++ = b;
+ *op++ = b;
+ for(; len; --len)
+ *op++ = b;
+ }
+ else
+ {
+#if !defined(FASTLZ_STRICT_ALIGN)
+ const flzuint16* p;
+ flzuint16* q;
+#endif
+ /* copy from reference */
+ ref--;
+ *op++ = *ref++;
+ *op++ = *ref++;
+ *op++ = *ref++;
+
+#if !defined(FASTLZ_STRICT_ALIGN)
+ /* copy a byte, so that now it's word aligned */
+ if(len & 1)
+ {
+ *op++ = *ref++;
+ len--;
+ }
+
+ /* copy 16-bit at once */
+ q = (flzuint16*) op;
+ op += len;
+ p = (const flzuint16*) ref;
+ for(len>>=1; len > 4; len-=4)
+ {
+ *q++ = *p++;
+ *q++ = *p++;
+ *q++ = *p++;
+ *q++ = *p++;
+ }
+ for(; len; --len)
+ *q++ = *p++;
+#else
+ for(; len; --len)
+ *op++ = *ref++;
+#endif
+ }
+ }
+ else
+ {
+ ctrl++;
+#ifdef FASTLZ_SAFE
+ if (FASTLZ_UNEXPECT_CONDITIONAL(op + ctrl > op_limit))
+ return 0;
+ if (FASTLZ_UNEXPECT_CONDITIONAL(ip + ctrl > ip_limit))
+ return 0;
+#endif
+
+ *op++ = *ip++;
+ for(--ctrl; ctrl; ctrl--)
+ *op++ = *ip++;
+
+ loop = FASTLZ_EXPECT_CONDITIONAL(ip < ip_limit);
+ if(loop)
+ ctrl = *ip++;
+ }
+ }
+ while(FASTLZ_EXPECT_CONDITIONAL(loop));
+
+ return op - (flzuint8*)output;
+}
+
+#endif /* !defined(FASTLZ_COMPRESSOR) && !defined(FASTLZ_DECOMPRESSOR) */
diff --git a/plugins/com.minres.scviewer.database.fst/csrc/fst/fastlz.h b/plugins/com.minres.scviewer.database.fst/csrc/fst/fastlz.h
new file mode 100644
index 0000000..1ce44a3
--- /dev/null
+++ b/plugins/com.minres.scviewer.database.fst/csrc/fst/fastlz.h
@@ -0,0 +1,109 @@
+/*
+ FastLZ - lightning-fast lossless compression library
+
+ Copyright (C) 2007 Ariya Hidayat (ariya@kde.org)
+ Copyright (C) 2006 Ariya Hidayat (ariya@kde.org)
+ Copyright (C) 2005 Ariya Hidayat (ariya@kde.org)
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ THE SOFTWARE.
+
+ SPDX-License-Identifier: MIT
+*/
+
+#ifndef FASTLZ_H
+#define FASTLZ_H
+
+#include
+
+#define flzuint8 uint8_t
+#define flzuint16 uint16_t
+#define flzuint32 uint32_t
+
+
+#define FASTLZ_VERSION 0x000100
+
+#define FASTLZ_VERSION_MAJOR 0
+#define FASTLZ_VERSION_MINOR 0
+#define FASTLZ_VERSION_REVISION 0
+
+#define FASTLZ_VERSION_STRING "0.1.0"
+
+#if defined (__cplusplus)
+extern "C" {
+#endif
+
+/**
+ Compress a block of data in the input buffer and returns the size of
+ compressed block. The size of input buffer is specified by length. The
+ minimum input buffer size is 16.
+
+ The output buffer must be at least 5% larger than the input buffer
+ and can not be smaller than 66 bytes.
+
+ If the input is not compressible, the return value might be larger than
+ length (input buffer size).
+
+ The input buffer and the output buffer can not overlap.
+*/
+
+int fastlz_compress(const void* input, int length, void* output);
+
+/**
+ Decompress a block of compressed data and returns the size of the
+ decompressed block. If error occurs, e.g. the compressed data is
+ corrupted or the output buffer is not large enough, then 0 (zero)
+ will be returned instead.
+
+ The input buffer and the output buffer can not overlap.
+
+ Decompression is memory safe and guaranteed not to write the output buffer
+ more than what is specified in maxout.
+ */
+
+int fastlz_decompress(const void* input, int length, void* output, int maxout);
+
+/**
+ Compress a block of data in the input buffer and returns the size of
+ compressed block. The size of input buffer is specified by length. The
+ minimum input buffer size is 16.
+
+ The output buffer must be at least 5% larger than the input buffer
+ and can not be smaller than 66 bytes.
+
+ If the input is not compressible, the return value might be larger than
+ length (input buffer size).
+
+ The input buffer and the output buffer can not overlap.
+
+ Compression level can be specified in parameter level. At the moment,
+ only level 1 and level 2 are supported.
+ Level 1 is the fastest compression and generally useful for short data.
+ Level 2 is slightly slower but it gives better compression ratio.
+
+ Note that the compressed data, regardless of the level, can always be
+ decompressed using the function fastlz_decompress above.
+*/
+
+int fastlz_compress_level(int level, const void* input, int length, void* output);
+
+#if defined (__cplusplus)
+}
+#endif
+
+#endif /* FASTLZ_H */
diff --git a/plugins/com.minres.scviewer.database.fst/csrc/fst/fst_helper.c b/plugins/com.minres.scviewer.database.fst/csrc/fst/fst_helper.c
new file mode 100644
index 0000000..63d5ca1
--- /dev/null
+++ b/plugins/com.minres.scviewer.database.fst/csrc/fst/fst_helper.c
@@ -0,0 +1,31 @@
+#include "fstapi.h"
+
+int getHierType(struct fstHier * hier){
+ return hier->htyp;
+}
+
+void getHierScope(struct fstHier* h, struct fstHierScope* scope){
+ if(h->htyp==FST_HT_SCOPE)
+ *scope=h->u.scope;
+}
+
+void getHierVar(struct fstHier* h, struct fstHierVar* var){
+ if(h->htyp==FST_HT_VAR)
+ *var=h->u.var;
+}
+
+void getHierAttr(struct fstHier* h, struct fstHierAttr* attr){
+ if(h->htyp==FST_HT_ATTRBEGIN)
+ *attr=h->u.attr;
+}
+
+typedef void (*value_change_callback)(uint64_t time, fstHandle facidx, const char *value);
+
+static void forward_cb(void *user_callback_data_pointer, uint64_t time, fstHandle facidx, const unsigned char *value) {
+ //fprintf(stderr, "val: %s @ %ld\n", value, time);
+ ((value_change_callback)user_callback_data_pointer)(time, facidx, value);
+}
+
+void iterateValueChanges(void* ctx, value_change_callback vcc) {
+ fstReaderIterBlocks(ctx, forward_cb, vcc, NULL);
+}
\ No newline at end of file
diff --git a/plugins/com.minres.scviewer.database.fst/csrc/fst/fst_win_unistd.h b/plugins/com.minres.scviewer.database.fst/csrc/fst/fst_win_unistd.h
new file mode 100644
index 0000000..15ab2c1
--- /dev/null
+++ b/plugins/com.minres.scviewer.database.fst/csrc/fst/fst_win_unistd.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2009-2018 Tony Bybell.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * SPDX-License-Identifier: MIT
+ */
+
+#ifndef WIN_UNISTD_H
+#define WIN_UNISTD_H
+
+#include
+#ifdef _WIN64
+#include
+#else
+#include
+#endif
+
+#include
+
+#define ftruncate _chsize_s
+#define unlink _unlink
+#define fileno _fileno
+#define lseek _lseeki64
+
+#ifdef _WIN64
+#define ssize_t __int64
+#define SSIZE_MAX 9223372036854775807i64
+#else
+#define ssize_t long
+#define SSIZE_MAX 2147483647L
+#endif
+
+#include "stdint.h"
+
+#endif //WIN_UNISTD_H
diff --git a/plugins/com.minres.scviewer.database.fst/csrc/fst/fstapi.c b/plugins/com.minres.scviewer.database.fst/csrc/fst/fstapi.c
new file mode 100644
index 0000000..c88a45e
--- /dev/null
+++ b/plugins/com.minres.scviewer.database.fst/csrc/fst/fstapi.c
@@ -0,0 +1,7025 @@
+/*
+ * Copyright (c) 2009-2018 Tony Bybell.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * SPDX-License-Identifier: MIT
+ */
+
+/*
+ * possible disables:
+ *
+ * FST_DYNAMIC_ALIAS_DISABLE : dynamic aliases are not processed
+ * FST_DYNAMIC_ALIAS2_DISABLE : new encoding for dynamic aliases is not generated
+ * FST_WRITEX_DISABLE : fast write I/O routines are disabled
+ *
+ * possible enables:
+ *
+ * FST_DEBUG : not for production use, only enable for development
+ * FST_REMOVE_DUPLICATE_VC : glitch removal (has writer performance impact)
+ * HAVE_LIBPTHREAD -> FST_WRITER_PARALLEL : enables inclusion of parallel writer code
+ * FST_DO_MISALIGNED_OPS (defined automatically for x86 and some others) : CPU architecture can handle misaligned loads/stores
+ * _WAVE_HAVE_JUDY : use Judy arrays instead of Jenkins (undefine if LGPL is not acceptable)
+ *
+ */
+
+#ifndef FST_CONFIG_INCLUDE
+# define FST_CONFIG_INCLUDE
+#endif
+#include FST_CONFIG_INCLUDE
+
+#include "fstapi.h"
+#include "fastlz.h"
+#include "lz4.h"
+#include
+
+#ifndef HAVE_LIBPTHREAD
+#undef FST_WRITER_PARALLEL
+#endif
+
+#ifdef FST_WRITER_PARALLEL
+#include
+#endif
+
+#ifdef __MINGW32__
+#include
+#endif
+
+#ifdef HAVE_ALLOCA_H
+#include
+#elif defined(__GNUC__)
+#ifndef __MINGW32__
+#ifndef alloca
+#define alloca __builtin_alloca
+#endif
+#else
+#include
+#endif
+#elif defined(_MSC_VER)
+#include
+#define alloca _alloca
+#endif
+
+#ifndef PATH_MAX
+#define PATH_MAX (4096)
+#endif
+
+#if defined(_MSC_VER)
+typedef int64_t fst_off_t;
+#else
+typedef off_t fst_off_t;
+#endif
+
+/* note that Judy versus Jenkins requires more experimentation: they are */
+/* functionally equivalent though it appears Jenkins is slightly faster. */
+/* in addition, Jenkins is not bound by the LGPL. */
+#ifdef _WAVE_HAVE_JUDY
+#include
+#else
+/* should be more than enough for fstWriterSetSourceStem() */
+#define FST_PATH_HASHMASK ((1UL << 16) - 1)
+typedef const void *Pcvoid_t;
+typedef void *Pvoid_t;
+typedef void **PPvoid_t;
+#define JudyHSIns(a,b,c,d) JenkinsIns((a),(b),(c),(hashmask))
+#define JudyHSFreeArray(a,b) JenkinsFree((a),(hashmask))
+void JenkinsFree(void *base_i, uint32_t hashmask);
+void **JenkinsIns(void *base_i, const unsigned char *mem, uint32_t length, uint32_t hashmask);
+#endif
+
+
+#ifndef FST_WRITEX_DISABLE
+#define FST_WRITEX_MAX (64 * 1024)
+#else
+#define fstWritex(a,b,c) fstFwrite((b), (c), 1, fv)
+#endif
+
+
+/* these defines have a large impact on writer speed when a model has a */
+/* huge number of symbols. as a default, use 128MB and increment when */
+/* every 1M signals are defined. */
+#define FST_BREAK_SIZE (1UL << 27)
+#define FST_BREAK_ADD_SIZE (1UL << 22)
+#define FST_BREAK_SIZE_MAX (1UL << 31)
+#define FST_ACTIVATE_HUGE_BREAK (1000000)
+#define FST_ACTIVATE_HUGE_INC (1000000)
+
+#define FST_WRITER_STR "fstWriter"
+#define FST_ID_NAM_SIZ (512)
+#define FST_ID_NAM_ATTR_SIZ (65536+4096)
+#define FST_DOUBLE_ENDTEST (2.7182818284590452354)
+#define FST_HDR_SIM_VERSION_SIZE (128)
+#define FST_HDR_DATE_SIZE (119)
+#define FST_HDR_FILETYPE_SIZE (1)
+#define FST_HDR_TIMEZERO_SIZE (8)
+#define FST_GZIO_LEN (32768)
+#define FST_HDR_FOURPACK_DUO_SIZE (4*1024*1024)
+
+//#if defined(__i386__) || defined(__x86_64__) || defined(_AIX)
+//#define FST_DO_MISALIGNED_OPS
+//#endif
+
+#if defined(__APPLE__) && defined(__MACH__)
+#define FST_MACOSX
+#include
+#endif
+
+#ifdef __GNUC__
+/* Boolean expression more often true than false */
+#define FST_LIKELY(x) __builtin_expect(!!(x), 1)
+/* Boolean expression more often false than true */
+#define FST_UNLIKELY(x) __builtin_expect(!!(x), 0)
+#else
+#define FST_LIKELY(x) (!!(x))
+#define FST_UNLIKELY(x) (!!(x))
+#endif
+
+#define FST_APIMESS "FSTAPI | "
+
+/***********************/
+/*** ***/
+/*** common function ***/
+/*** ***/
+/***********************/
+
+#ifdef __MINGW32__
+#include
+#ifndef HAVE_FSEEKO
+#define ftello _ftelli64
+#define fseeko _fseeki64
+#endif
+#endif
+
+/*
+ * the recoded "extra" values...
+ * note that FST_RCV_Q is currently unused and is for future expansion.
+ * its intended use is as another level of escape such that any arbitrary
+ * value can be stored as the value: { time_delta, 8 bits, FST_RCV_Q }.
+ * this is currently not implemented so that the branchless decode is:
+ * uint32_t shcnt = 2 << (vli & 1); tdelta = vli >> shcnt;
+ */
+#define FST_RCV_X (1 | (0<<1))
+#define FST_RCV_Z (1 | (1<<1))
+#define FST_RCV_H (1 | (2<<1))
+#define FST_RCV_U (1 | (3<<1))
+#define FST_RCV_W (1 | (4<<1))
+#define FST_RCV_L (1 | (5<<1))
+#define FST_RCV_D (1 | (6<<1))
+#define FST_RCV_Q (1 | (7<<1))
+
+#define FST_RCV_STR "xzhuwl-?"
+/* 01234567 */
+
+
+/*
+ * prevent old file overwrite when currently being read
+ */
+static FILE *unlink_fopen(const char *nam, const char *mode)
+{
+unlink(nam);
+return(fopen(nam, mode));
+}
+
+
+/*
+ * system-specific temp file handling
+ */
+#ifdef __MINGW32__
+
+static FILE* tmpfile_open(char **nam)
+{
+char *fname = NULL;
+TCHAR szTempFileName[MAX_PATH];
+TCHAR lpTempPathBuffer[MAX_PATH];
+DWORD dwRetVal = 0;
+UINT uRetVal = 0;
+FILE *fh = NULL;
+
+if(nam) /* cppcheck warning fix: nam is always defined, so this is not needed */
+ {
+ dwRetVal = GetTempPath(MAX_PATH, lpTempPathBuffer);
+ if((dwRetVal > MAX_PATH) || (dwRetVal == 0))
+ {
+ fprintf(stderr, FST_APIMESS "GetTempPath() failed in " __FILE__ " line %d, exiting.\n", __LINE__);
+ exit(255);
+ }
+ else
+ {
+ uRetVal = GetTempFileName(lpTempPathBuffer, TEXT("FSTW"), 0, szTempFileName);
+ if (uRetVal == 0)
+ {
+ fprintf(stderr, FST_APIMESS "GetTempFileName() failed in " __FILE__ " line %d, exiting.\n", __LINE__);
+ exit(255);
+ }
+ else
+ {
+ fname = strdup(szTempFileName);
+ }
+ }
+
+ if(fname)
+ {
+ *nam = fname;
+ fh = unlink_fopen(fname, "w+b");
+ }
+ }
+
+return(fh);
+}
+
+#else
+
+static FILE* tmpfile_open(char **nam)
+{
+FILE *f = tmpfile(); /* replace with mkstemp() + fopen(), etc if this is not good enough */
+if(nam) { *nam = NULL; }
+return(f);
+}
+
+#endif
+
+
+static void tmpfile_close(FILE **f, char **nam)
+{
+if(f)
+ {
+ if(*f) { fclose(*f); *f = NULL; }
+ }
+
+if(nam)
+ {
+ if(*nam)
+ {
+ unlink(*nam);
+ free(*nam);
+ *nam = NULL;
+ }
+ }
+}
+
+/*****************************************/
+
+
+/*
+ * to remove warn_unused_result compile time messages
+ * (in the future there needs to be results checking)
+ */
+static size_t fstFread(void *buf, size_t siz, size_t cnt, FILE *fp)
+{
+return(fread(buf, siz, cnt, fp));
+}
+
+static size_t fstFwrite(const void *buf, size_t siz, size_t cnt, FILE *fp)
+{
+return(fwrite(buf, siz, cnt, fp));
+}
+
+static int fstFtruncate(int fd, fst_off_t length)
+{
+return(ftruncate(fd, length));
+}
+
+
+/*
+ * realpath compatibility
+ */
+static char *fstRealpath(const char *path, char *resolved_path)
+{
+#if defined __USE_BSD || defined __USE_XOPEN_EXTENDED || defined __CYGWIN__ || defined HAVE_REALPATH
+#if (defined(__MACH__) && defined(__APPLE__))
+if(!resolved_path)
+ {
+ resolved_path = (char *)malloc(PATH_MAX+1); /* fixes bug on Leopard when resolved_path == NULL */
+ }
+#endif
+
+return(realpath(path, resolved_path));
+
+#else
+#ifdef __MINGW32__
+if(!resolved_path)
+ {
+ resolved_path = (char *)malloc(PATH_MAX+1);
+ }
+return(_fullpath(resolved_path, path, PATH_MAX));
+#else
+(void)path;
+(void)resolved_path;
+return(NULL);
+#endif
+#endif
+}
+
+
+/*
+ * mmap compatibility
+ */
+#if defined __CYGWIN__ || defined __MINGW32__
+#include
+#define fstMmap(__addr,__len,__prot,__flags,__fd,__off) fstMmap2((__len), (__fd), (__off))
+#define fstMunmap(__addr,__len) free(__addr)
+
+static void *fstMmap2(size_t __len, int __fd, fst_off_t __off)
+{
+(void)__off;
+
+unsigned char *pnt = (unsigned char *)malloc(__len);
+fst_off_t cur_offs = lseek(__fd, 0, SEEK_CUR);
+size_t i;
+
+lseek(__fd, 0, SEEK_SET);
+for(i=0;i<__len;i+=SSIZE_MAX)
+ {
+ read(__fd, pnt + i, ((__len - i) >= SSIZE_MAX) ? SSIZE_MAX : (__len - i));
+ }
+lseek(__fd, cur_offs, SEEK_SET);
+return(pnt);
+}
+#else
+#include
+#if defined(__SUNPRO_C)
+#define FST_CADDR_T_CAST (caddr_t)
+#else
+#define FST_CADDR_T_CAST
+#endif
+#define fstMmap(__addr,__len,__prot,__flags,__fd,__off) (void*)mmap(FST_CADDR_T_CAST (__addr),(__len),(__prot),(__flags),(__fd),(__off))
+#define fstMunmap(__addr,__len) { if(__addr) munmap(FST_CADDR_T_CAST (__addr),(__len)); }
+#endif
+
+
+/*
+ * regular and variable-length integer access functions
+ */
+#ifdef FST_DO_MISALIGNED_OPS
+#define fstGetUint32(x) (*(uint32_t *)(x))
+#else
+static uint32_t fstGetUint32(unsigned char *mem)
+{
+uint32_t u32;
+unsigned char *buf = (unsigned char *)(&u32);
+
+buf[0] = mem[0];
+buf[1] = mem[1];
+buf[2] = mem[2];
+buf[3] = mem[3];
+
+return(*(uint32_t *)buf);
+}
+#endif
+
+
+static int fstWriterUint64(FILE *handle, uint64_t v)
+{
+unsigned char buf[8];
+int i;
+
+for(i=7;i>=0;i--)
+ {
+ buf[i] = v & 0xff;
+ v >>= 8;
+ }
+
+fstFwrite(buf, 8, 1, handle);
+return(8);
+}
+
+
+static uint64_t fstReaderUint64(FILE *f)
+{
+uint64_t val = 0;
+unsigned char buf[sizeof(uint64_t)];
+unsigned int i;
+
+fstFread(buf, sizeof(uint64_t), 1, f);
+for(i=0;i>7)) /* determine len to avoid temp buffer copying to cut down on load-hit-store */
+ {
+ cnt++;
+ }
+
+pnt -= cnt;
+spnt = pnt;
+cnt--;
+
+for(i=0;i>7;
+ *(spnt++) = ((unsigned char)v) | 0x80;
+ v = nxt;
+ }
+*spnt = (unsigned char)v;
+
+return(pnt);
+}
+
+
+static unsigned char *fstCopyVarint64ToRight(unsigned char *pnt, uint64_t v)
+{
+uint64_t nxt;
+
+while((nxt = v>>7))
+ {
+ *(pnt++) = ((unsigned char)v) | 0x80;
+ v = nxt;
+ }
+*(pnt++) = (unsigned char)v;
+
+return(pnt);
+}
+
+
+static uint64_t fstGetVarint64(unsigned char *mem, int *skiplen)
+{
+unsigned char *mem_orig = mem;
+uint64_t rc = 0;
+while(*mem & 0x80)
+ {
+ mem++;
+ }
+
+*skiplen = mem - mem_orig + 1;
+for(;;)
+ {
+ rc <<= 7;
+ rc |= (uint64_t)(*mem & 0x7f);
+ if(mem == mem_orig)
+ {
+ break;
+ }
+ mem--;
+ }
+
+return(rc);
+}
+
+
+static uint32_t fstReaderVarint32(FILE *f)
+{
+unsigned char buf[5];
+unsigned char *mem = buf;
+uint32_t rc = 0;
+int ch;
+
+do
+ {
+ ch = fgetc(f);
+ *(mem++) = ch;
+ } while(ch & 0x80);
+mem--;
+
+for(;;)
+ {
+ rc <<= 7;
+ rc |= (uint32_t)(*mem & 0x7f);
+ if(mem == buf)
+ {
+ break;
+ }
+ mem--;
+ }
+
+return(rc);
+}
+
+
+static uint32_t fstReaderVarint32WithSkip(FILE *f, uint32_t *skiplen)
+{
+unsigned char buf[5];
+unsigned char *mem = buf;
+uint32_t rc = 0;
+int ch;
+
+do
+ {
+ ch = fgetc(f);
+ *(mem++) = ch;
+ } while(ch & 0x80);
+*skiplen = mem - buf;
+mem--;
+
+for(;;)
+ {
+ rc <<= 7;
+ rc |= (uint32_t)(*mem & 0x7f);
+ if(mem == buf)
+ {
+ break;
+ }
+ mem--;
+ }
+
+return(rc);
+}
+
+
+static uint64_t fstReaderVarint64(FILE *f)
+{
+unsigned char buf[16];
+unsigned char *mem = buf;
+uint64_t rc = 0;
+int ch;
+
+do
+ {
+ ch = fgetc(f);
+ *(mem++) = ch;
+ } while(ch & 0x80);
+mem--;
+
+for(;;)
+ {
+ rc <<= 7;
+ rc |= (uint64_t)(*mem & 0x7f);
+ if(mem == buf)
+ {
+ break;
+ }
+ mem--;
+ }
+
+return(rc);
+}
+
+
+static int fstWriterVarint(FILE *handle, uint64_t v)
+{
+uint64_t nxt;
+unsigned char buf[10]; /* ceil(64/7) = 10 */
+unsigned char *pnt = buf;
+int len;
+
+while((nxt = v>>7))
+ {
+ *(pnt++) = ((unsigned char)v) | 0x80;
+ v = nxt;
+ }
+*(pnt++) = (unsigned char)v;
+
+len = pnt-buf;
+fstFwrite(buf, len, 1, handle);
+return(len);
+}
+
+
+/* signed integer read/write routines are currently unused */
+static int64_t fstGetSVarint64(unsigned char *mem, int *skiplen)
+{
+unsigned char *mem_orig = mem;
+int64_t rc = 0;
+const int64_t one = 1;
+const int siz = sizeof(int64_t) * 8;
+int shift = 0;
+unsigned char byt;
+
+do {
+ byt = *(mem++);
+ rc |= ((int64_t)(byt & 0x7f)) << shift;
+ shift += 7;
+
+ } while(byt & 0x80);
+
+if((shift>= 7;
+
+ if (((!v) && (!(byt & 0x40))) || ((v == -1) && (byt & 0x40)))
+ {
+ more = 0;
+ byt &= 0x7f;
+ }
+
+ *(pnt++) = byt;
+ } while(more);
+
+len = pnt-buf;
+fstFwrite(buf, len, 1, handle);
+return(len);
+}
+#endif
+
+
+/***********************/
+/*** ***/
+/*** writer function ***/
+/*** ***/
+/***********************/
+
+/*
+ * private structs
+ */
+struct fstBlackoutChain
+{
+struct fstBlackoutChain *next;
+uint64_t tim;
+unsigned active : 1;
+};
+
+
+struct fstWriterContext
+{
+FILE *handle;
+FILE *hier_handle;
+FILE *geom_handle;
+FILE *valpos_handle;
+FILE *curval_handle;
+FILE *tchn_handle;
+
+unsigned char *vchg_mem;
+
+fst_off_t hier_file_len;
+
+uint32_t *valpos_mem;
+unsigned char *curval_mem;
+
+unsigned char *outval_mem; /* for two-state / Verilator-style value changes */
+uint32_t outval_alloc_siz;
+
+char *filename;
+
+fstHandle maxhandle;
+fstHandle numsigs;
+uint32_t maxvalpos;
+
+unsigned vc_emitted : 1;
+unsigned is_initial_time : 1;
+unsigned fourpack : 1;
+unsigned fastpack : 1;
+
+int64_t timezero;
+fst_off_t section_header_truncpos;
+uint32_t tchn_cnt, tchn_idx;
+uint64_t curtime;
+uint64_t firsttime;
+uint32_t vchg_siz;
+uint32_t vchg_alloc_siz;
+
+uint32_t secnum;
+fst_off_t section_start;
+
+uint32_t numscopes;
+double nan; /* nan value for uninitialized doubles */
+
+struct fstBlackoutChain *blackout_head;
+struct fstBlackoutChain *blackout_curr;
+uint32_t num_blackouts;
+
+uint64_t dump_size_limit;
+
+unsigned char filetype; /* default is 0, FST_FT_VERILOG */
+
+unsigned compress_hier : 1;
+unsigned repack_on_close : 1;
+unsigned skip_writing_section_hdr : 1;
+unsigned size_limit_locked : 1;
+unsigned section_header_only : 1;
+unsigned flush_context_pending : 1;
+unsigned parallel_enabled : 1;
+unsigned parallel_was_enabled : 1;
+
+/* should really be semaphores, but are bytes to cut down on read-modify-write window size */
+unsigned char already_in_flush; /* in case control-c handlers interrupt */
+unsigned char already_in_close; /* in case control-c handlers interrupt */
+
+#ifdef FST_WRITER_PARALLEL
+pthread_mutex_t mutex;
+pthread_t thread;
+pthread_attr_t thread_attr;
+struct fstWriterContext *xc_parent;
+#endif
+unsigned in_pthread : 1;
+
+size_t fst_orig_break_size;
+size_t fst_orig_break_add_size;
+
+size_t fst_break_size;
+size_t fst_break_add_size;
+
+size_t fst_huge_break_size;
+
+fstHandle next_huge_break;
+
+Pvoid_t path_array;
+uint32_t path_array_count;
+
+unsigned fseek_failed : 1;
+
+char *geom_handle_nam;
+char *valpos_handle_nam;
+char *curval_handle_nam;
+char *tchn_handle_nam;
+
+fstEnumHandle max_enumhandle;
+};
+
+
+static int fstWriterFseeko(struct fstWriterContext *xc, FILE *stream, fst_off_t offset, int whence)
+{
+int rc = fseeko(stream, offset, whence);
+
+if(rc<0)
+ {
+ xc->fseek_failed = 1;
+#ifdef FST_DEBUG
+ fprintf(stderr, FST_APIMESS "Seek to #%" PRId64 " (whence = %d) failed!\n", offset, whence);
+ perror("Why");
+#endif
+ }
+
+return(rc);
+}
+
+
+static uint32_t fstWriterUint32WithVarint32(struct fstWriterContext *xc, uint32_t *u, uint32_t v, const void *dbuf, uint32_t siz)
+{
+unsigned char *buf = xc->vchg_mem + xc->vchg_siz;
+unsigned char *pnt = buf;
+uint32_t nxt;
+uint32_t len;
+
+#ifdef FST_DO_MISALIGNED_OPS
+(*(uint32_t *)(pnt)) = (*(uint32_t *)(u));
+#else
+memcpy(pnt, u, sizeof(uint32_t));
+#endif
+pnt += 4;
+
+while((nxt = v>>7))
+ {
+ *(pnt++) = ((unsigned char)v) | 0x80;
+ v = nxt;
+ }
+*(pnt++) = (unsigned char)v;
+memcpy(pnt, dbuf, siz);
+
+len = pnt-buf + siz;
+return(len);
+}
+
+
+static uint32_t fstWriterUint32WithVarint32AndLength(struct fstWriterContext *xc, uint32_t *u, uint32_t v, const void *dbuf, uint32_t siz)
+{
+unsigned char *buf = xc->vchg_mem + xc->vchg_siz;
+unsigned char *pnt = buf;
+uint32_t nxt;
+uint32_t len;
+
+#ifdef FST_DO_MISALIGNED_OPS
+(*(uint32_t *)(pnt)) = (*(uint32_t *)(u));
+#else
+memcpy(pnt, u, sizeof(uint32_t));
+#endif
+pnt += 4;
+
+while((nxt = v>>7))
+ {
+ *(pnt++) = ((unsigned char)v) | 0x80;
+ v = nxt;
+ }
+*(pnt++) = (unsigned char)v;
+
+v = siz;
+while((nxt = v>>7))
+ {
+ *(pnt++) = ((unsigned char)v) | 0x80;
+ v = nxt;
+ }
+*(pnt++) = (unsigned char)v;
+
+memcpy(pnt, dbuf, siz);
+
+len = pnt-buf + siz;
+return(len);
+}
+
+
+/*
+ * header bytes, write here so defines are set up before anything else
+ * that needs to use them
+ */
+static void fstWriterEmitHdrBytes(struct fstWriterContext *xc)
+{
+char vbuf[FST_HDR_SIM_VERSION_SIZE];
+char dbuf[FST_HDR_DATE_SIZE];
+double endtest = FST_DOUBLE_ENDTEST;
+time_t walltime;
+
+#define FST_HDR_OFFS_TAG (0)
+fputc(FST_BL_HDR, xc->handle); /* +0 tag */
+
+#define FST_HDR_OFFS_SECLEN (FST_HDR_OFFS_TAG + 1)
+fstWriterUint64(xc->handle, 329); /* +1 section length */
+
+#define FST_HDR_OFFS_START_TIME (FST_HDR_OFFS_SECLEN + 8)
+fstWriterUint64(xc->handle, 0); /* +9 start time */
+
+#define FST_HDR_OFFS_END_TIME (FST_HDR_OFFS_START_TIME + 8)
+fstWriterUint64(xc->handle, 0); /* +17 end time */
+
+#define FST_HDR_OFFS_ENDIAN_TEST (FST_HDR_OFFS_END_TIME + 8)
+fstFwrite(&endtest, 8, 1, xc->handle); /* +25 endian test for reals */
+
+#define FST_HDR_OFFS_MEM_USED (FST_HDR_OFFS_ENDIAN_TEST + 8)
+fstWriterUint64(xc->handle, xc->fst_break_size);/* +33 memory used by writer */
+
+#define FST_HDR_OFFS_NUM_SCOPES (FST_HDR_OFFS_MEM_USED + 8)
+fstWriterUint64(xc->handle, 0); /* +41 scope creation count */
+
+#define FST_HDR_OFFS_NUM_VARS (FST_HDR_OFFS_NUM_SCOPES + 8)
+fstWriterUint64(xc->handle, 0); /* +49 var creation count */
+
+#define FST_HDR_OFFS_MAXHANDLE (FST_HDR_OFFS_NUM_VARS + 8)
+fstWriterUint64(xc->handle, 0); /* +57 max var idcode */
+
+#define FST_HDR_OFFS_SECTION_CNT (FST_HDR_OFFS_MAXHANDLE + 8)
+fstWriterUint64(xc->handle, 0); /* +65 vc section count */
+
+#define FST_HDR_OFFS_TIMESCALE (FST_HDR_OFFS_SECTION_CNT + 8)
+fputc((-9)&255, xc->handle); /* +73 timescale 1ns */
+
+#define FST_HDR_OFFS_SIM_VERSION (FST_HDR_OFFS_TIMESCALE + 1)
+memset(vbuf, 0, FST_HDR_SIM_VERSION_SIZE);
+strcpy(vbuf, FST_WRITER_STR);
+fstFwrite(vbuf, FST_HDR_SIM_VERSION_SIZE, 1, xc->handle); /* +74 version */
+
+#define FST_HDR_OFFS_DATE (FST_HDR_OFFS_SIM_VERSION + FST_HDR_SIM_VERSION_SIZE)
+memset(dbuf, 0, FST_HDR_DATE_SIZE);
+time(&walltime);
+strcpy(dbuf, asctime(localtime(&walltime)));
+fstFwrite(dbuf, FST_HDR_DATE_SIZE, 1, xc->handle); /* +202 date */
+
+/* date size is deliberately overspecified at 119 bytes (originally 128) in order to provide backfill for new args */
+
+#define FST_HDR_OFFS_FILETYPE (FST_HDR_OFFS_DATE + FST_HDR_DATE_SIZE)
+fputc(xc->filetype, xc->handle); /* +321 filetype */
+
+#define FST_HDR_OFFS_TIMEZERO (FST_HDR_OFFS_FILETYPE + FST_HDR_FILETYPE_SIZE)
+fstWriterUint64(xc->handle, xc->timezero); /* +322 timezero */
+
+#define FST_HDR_LENGTH (FST_HDR_OFFS_TIMEZERO + FST_HDR_TIMEZERO_SIZE)
+ /* +330 next section starts here */
+fflush(xc->handle);
+}
+
+
+/*
+ * mmap functions
+ */
+static void fstWriterMmapSanity(void *pnt, const char *file, int line, const char *usage)
+{
+#if !defined(__CYGWIN__) && !defined(__MINGW32__)
+if(pnt == MAP_FAILED)
+ {
+ fprintf(stderr, "fstMmap() assigned to %s failed: errno: %d, file %s, line %d.\n", usage, errno, file, line);
+ perror("Why");
+ pnt = NULL;
+ }
+#endif
+}
+
+
+static void fstWriterCreateMmaps(struct fstWriterContext *xc)
+{
+fst_off_t curpos = ftello(xc->handle);
+
+fflush(xc->hier_handle);
+
+/* write out intermediate header */
+fstWriterFseeko(xc, xc->handle, FST_HDR_OFFS_START_TIME, SEEK_SET);
+fstWriterUint64(xc->handle, xc->firsttime);
+fstWriterUint64(xc->handle, xc->curtime);
+fstWriterFseeko(xc, xc->handle, FST_HDR_OFFS_NUM_SCOPES, SEEK_SET);
+fstWriterUint64(xc->handle, xc->numscopes);
+fstWriterUint64(xc->handle, xc->numsigs);
+fstWriterUint64(xc->handle, xc->maxhandle);
+fstWriterUint64(xc->handle, xc->secnum);
+fstWriterFseeko(xc, xc->handle, curpos, SEEK_SET);
+fflush(xc->handle);
+
+/* do mappings */
+if(!xc->valpos_mem)
+ {
+ fflush(xc->valpos_handle);
+ errno = 0;
+ if(xc->maxhandle)
+ {
+ fstWriterMmapSanity(xc->valpos_mem = (uint32_t *)fstMmap(NULL, xc->maxhandle * 4 * sizeof(uint32_t), PROT_READ|PROT_WRITE, MAP_SHARED, fileno(xc->valpos_handle), 0), __FILE__, __LINE__, "xc->valpos_mem");
+ }
+ }
+if(!xc->curval_mem)
+ {
+ fflush(xc->curval_handle);
+ errno = 0;
+ if(xc->maxvalpos)
+ {
+ fstWriterMmapSanity(xc->curval_mem = (unsigned char *)fstMmap(NULL, xc->maxvalpos, PROT_READ|PROT_WRITE, MAP_SHARED, fileno(xc->curval_handle), 0), __FILE__, __LINE__, "xc->curval_handle");
+ }
+ }
+}
+
+
+static void fstDestroyMmaps(struct fstWriterContext *xc, int is_closing)
+{
+#if !defined __CYGWIN__ && !defined __MINGW32__
+(void)is_closing;
+#endif
+
+fstMunmap(xc->valpos_mem, xc->maxhandle * 4 * sizeof(uint32_t));
+xc->valpos_mem = NULL;
+
+#if defined __CYGWIN__ || defined __MINGW32__
+if(xc->curval_mem)
+ {
+ if(!is_closing) /* need to flush out for next emulated mmap() read */
+ {
+ unsigned char *pnt = xc->curval_mem;
+ int __fd = fileno(xc->curval_handle);
+ fst_off_t cur_offs = lseek(__fd, 0, SEEK_CUR);
+ size_t i;
+ size_t __len = xc->maxvalpos;
+
+ lseek(__fd, 0, SEEK_SET);
+ for(i=0;i<__len;i+=SSIZE_MAX)
+ {
+ write(__fd, pnt + i, ((__len - i) >= SSIZE_MAX) ? SSIZE_MAX : (__len - i));
+ }
+ lseek(__fd, cur_offs, SEEK_SET);
+ }
+ }
+#endif
+
+fstMunmap(xc->curval_mem, xc->maxvalpos);
+xc->curval_mem = NULL;
+}
+
+
+/*
+ * set up large and small memory usages
+ * crossover point in model is FST_ACTIVATE_HUGE_BREAK number of signals
+ */
+static void fstDetermineBreakSize(struct fstWriterContext *xc)
+{
+#if defined(__linux__) || defined(FST_MACOSX)
+int was_set = 0;
+
+#ifdef __linux__
+FILE *f = fopen("/proc/meminfo", "rb");
+
+if(f)
+ {
+ char buf[257];
+ char *s;
+ while(!feof(f))
+ {
+ buf[0] = 0;
+ s = fgets(buf, 256, f);
+ if(s && *s)
+ {
+ if(!strncmp(s, "MemTotal:", 9))
+ {
+ size_t v = atol(s+10);
+ v *= 1024; /* convert to bytes */
+ v /= 8; /* chop down to 1/8 physical memory */
+ if(v > FST_BREAK_SIZE)
+ {
+ if(v > FST_BREAK_SIZE_MAX)
+ {
+ v = FST_BREAK_SIZE_MAX;
+ }
+
+ xc->fst_huge_break_size = v;
+ was_set = 1;
+ break;
+ }
+ }
+ }
+ }
+
+ fclose(f);
+ }
+
+if(!was_set)
+ {
+ xc->fst_huge_break_size = FST_BREAK_SIZE;
+ }
+#else
+int mib[2];
+int64_t v;
+size_t length;
+
+mib[0] = CTL_HW;
+mib[1] = HW_MEMSIZE;
+length = sizeof(int64_t);
+if(!sysctl(mib, 2, &v, &length, NULL, 0))
+ {
+ v /= 8;
+
+ if(v > (int64_t)FST_BREAK_SIZE)
+ {
+ if(v > (int64_t)FST_BREAK_SIZE_MAX)
+ {
+ v = FST_BREAK_SIZE_MAX;
+ }
+
+ xc->fst_huge_break_size = v;
+ was_set = 1;
+ }
+ }
+
+if(!was_set)
+ {
+ xc->fst_huge_break_size = FST_BREAK_SIZE;
+ }
+#endif
+#else
+xc->fst_huge_break_size = FST_BREAK_SIZE;
+#endif
+
+xc->fst_break_size = xc->fst_orig_break_size = FST_BREAK_SIZE;
+xc->fst_break_add_size = xc->fst_orig_break_add_size = FST_BREAK_ADD_SIZE;
+xc->next_huge_break = FST_ACTIVATE_HUGE_BREAK;
+}
+
+
+/*
+ * file creation and close
+ */
+void *fstWriterCreate(const char *nam, int use_compressed_hier)
+{
+struct fstWriterContext *xc = (struct fstWriterContext *)calloc(1, sizeof(struct fstWriterContext));
+
+xc->compress_hier = use_compressed_hier;
+fstDetermineBreakSize(xc);
+
+if((!nam)||
+ (!(xc->handle=unlink_fopen(nam, "w+b"))))
+ {
+ free(xc);
+ xc=NULL;
+ }
+ else
+ {
+ int flen = strlen(nam);
+ char *hf = (char *)calloc(1, flen + 6);
+
+ memcpy(hf, nam, flen);
+ strcpy(hf + flen, ".hier");
+ xc->hier_handle = unlink_fopen(hf, "w+b");
+
+ xc->geom_handle = tmpfile_open(&xc->geom_handle_nam); /* .geom */
+ xc->valpos_handle = tmpfile_open(&xc->valpos_handle_nam); /* .offs */
+ xc->curval_handle = tmpfile_open(&xc->curval_handle_nam); /* .bits */
+ xc->tchn_handle = tmpfile_open(&xc->tchn_handle_nam); /* .tchn */
+ xc->vchg_alloc_siz = xc->fst_break_size + xc->fst_break_add_size;
+ xc->vchg_mem = (unsigned char *)malloc(xc->vchg_alloc_siz);
+
+ if(xc->hier_handle && xc->geom_handle && xc->valpos_handle && xc->curval_handle && xc->vchg_mem && xc->tchn_handle)
+ {
+ xc->filename = strdup(nam);
+ xc->is_initial_time = 1;
+
+ fstWriterEmitHdrBytes(xc);
+ xc->nan = strtod("NaN", NULL);
+#ifdef FST_WRITER_PARALLEL
+ pthread_mutex_init(&xc->mutex, NULL);
+ pthread_attr_init(&xc->thread_attr);
+ pthread_attr_setdetachstate(&xc->thread_attr, PTHREAD_CREATE_DETACHED);
+#endif
+ }
+ else
+ {
+ fclose(xc->handle);
+ if(xc->hier_handle) { fclose(xc->hier_handle); unlink(hf); }
+ tmpfile_close(&xc->geom_handle, &xc->geom_handle_nam);
+ tmpfile_close(&xc->valpos_handle, &xc->valpos_handle_nam);
+ tmpfile_close(&xc->curval_handle, &xc->curval_handle_nam);
+ tmpfile_close(&xc->tchn_handle, &xc->tchn_handle_nam);
+ free(xc->vchg_mem);
+ free(xc);
+ xc=NULL;
+ }
+
+ free(hf);
+ }
+
+return(xc);
+}
+
+
+/*
+ * generation and writing out of value change data sections
+ */
+static void fstWriterEmitSectionHeader(void *ctx)
+{
+struct fstWriterContext *xc = (struct fstWriterContext *)ctx;
+
+if(xc)
+ {
+ unsigned long destlen;
+ unsigned char *dmem;
+ int rc;
+
+ destlen = xc->maxvalpos;
+ dmem = (unsigned char *)malloc(compressBound(destlen));
+ rc = compress2(dmem, &destlen, xc->curval_mem, xc->maxvalpos, 4); /* was 9...which caused performance drag on traces with many signals */
+
+ fputc(FST_BL_SKIP, xc->handle); /* temporarily tag the section, use FST_BL_VCDATA on finalize */
+ xc->section_start = ftello(xc->handle);
+#ifdef FST_WRITER_PARALLEL
+ if(xc->xc_parent) xc->xc_parent->section_start = xc->section_start;
+#endif
+ xc->section_header_only = 1; /* indicates truncate might be needed */
+ fstWriterUint64(xc->handle, 0); /* placeholder = section length */
+ fstWriterUint64(xc->handle, xc->is_initial_time ? xc->firsttime : xc->curtime); /* begin time of section */
+ fstWriterUint64(xc->handle, xc->curtime); /* end time of section (placeholder) */
+ fstWriterUint64(xc->handle, 0); /* placeholder = amount of buffer memory required in reader for full vc traversal */
+ fstWriterVarint(xc->handle, xc->maxvalpos); /* maxvalpos = length of uncompressed data */
+
+ if((rc == Z_OK) && (destlen < xc->maxvalpos))
+ {
+ fstWriterVarint(xc->handle, destlen); /* length of compressed data */
+ }
+ else
+ {
+ fstWriterVarint(xc->handle, xc->maxvalpos); /* length of (unable to be) compressed data */
+ }
+ fstWriterVarint(xc->handle, xc->maxhandle); /* max handle associated with this data (in case of dynamic facility adds) */
+
+ if((rc == Z_OK) && (destlen < xc->maxvalpos))
+ {
+ fstFwrite(dmem, destlen, 1, xc->handle);
+ }
+ else /* comparison between compressed / decompressed len tells if compressed */
+ {
+ fstFwrite(xc->curval_mem, xc->maxvalpos, 1, xc->handle);
+ }
+
+ free(dmem);
+ }
+}
+
+
+/*
+ * only to be called directly by fst code...otherwise must
+ * be synced up with time changes
+ */
+#ifdef FST_WRITER_PARALLEL
+static void fstWriterFlushContextPrivate2(void *ctx)
+#else
+static void fstWriterFlushContextPrivate(void *ctx)
+#endif
+{
+#ifdef FST_DEBUG
+int cnt = 0;
+#endif
+unsigned int i;
+unsigned char *vchg_mem;
+FILE *f;
+fst_off_t fpos, indxpos, endpos;
+uint32_t prevpos;
+int zerocnt;
+unsigned char *scratchpad;
+unsigned char *scratchpnt;
+unsigned char *tmem;
+fst_off_t tlen;
+fst_off_t unc_memreq = 0; /* for reader */
+unsigned char *packmem;
+unsigned int packmemlen;
+uint32_t *vm4ip;
+struct fstWriterContext *xc = (struct fstWriterContext *)ctx;
+#ifdef FST_WRITER_PARALLEL
+struct fstWriterContext *xc2 = xc->xc_parent;
+#else
+struct fstWriterContext *xc2 = xc;
+#endif
+
+#ifndef FST_DYNAMIC_ALIAS_DISABLE
+Pvoid_t PJHSArray = (Pvoid_t) NULL;
+#ifndef _WAVE_HAVE_JUDY
+uint32_t hashmask = xc->maxhandle;
+hashmask |= hashmask >> 1;
+hashmask |= hashmask >> 2;
+hashmask |= hashmask >> 4;
+hashmask |= hashmask >> 8;
+hashmask |= hashmask >> 16;
+#endif
+#endif
+
+if((xc->vchg_siz <= 1)||(xc->already_in_flush)) return;
+xc->already_in_flush = 1; /* should really do this with a semaphore */
+
+xc->section_header_only = 0;
+scratchpad = (unsigned char *)malloc(xc->vchg_siz);
+
+vchg_mem = xc->vchg_mem;
+
+f = xc->handle;
+fstWriterVarint(f, xc->maxhandle); /* emit current number of handles */
+fputc(xc->fourpack ? '4' : (xc->fastpack ? 'F' : 'Z'), f);
+fpos = 1;
+
+packmemlen = 1024; /* maintain a running "longest" allocation to */
+packmem = (unsigned char *)malloc(packmemlen); /* prevent continual malloc...free every loop iter */
+
+for(i=0;imaxhandle;i++)
+ {
+ vm4ip = &(xc->valpos_mem[4*i]);
+
+ if(vm4ip[2])
+ {
+ uint32_t offs = vm4ip[2];
+ uint32_t next_offs;
+ unsigned int wrlen;
+
+ vm4ip[2] = fpos;
+
+ scratchpnt = scratchpad + xc->vchg_siz; /* build this buffer backwards */
+ if(vm4ip[1] <= 1)
+ {
+ if(vm4ip[1] == 1)
+ {
+ wrlen = fstGetVarint32Length(vchg_mem + offs + 4); /* used to advance and determine wrlen */
+#ifndef FST_REMOVE_DUPLICATE_VC
+ xc->curval_mem[vm4ip[0]] = vchg_mem[offs + 4 + wrlen]; /* checkpoint variable */
+#endif
+ while(offs)
+ {
+ unsigned char val;
+ uint32_t time_delta, rcv;
+ next_offs = fstGetUint32(vchg_mem + offs);
+ offs += 4;
+
+ time_delta = fstGetVarint32(vchg_mem + offs, (int *)&wrlen);
+ val = vchg_mem[offs+wrlen];
+ offs = next_offs;
+
+ switch(val)
+ {
+ case '0':
+ case '1': rcv = ((val&1)<<1) | (time_delta<<2);
+ break; /* pack more delta bits in for 0/1 vchs */
+
+ case 'x': case 'X': rcv = FST_RCV_X | (time_delta<<4); break;
+ case 'z': case 'Z': rcv = FST_RCV_Z | (time_delta<<4); break;
+ case 'h': case 'H': rcv = FST_RCV_H | (time_delta<<4); break;
+ case 'u': case 'U': rcv = FST_RCV_U | (time_delta<<4); break;
+ case 'w': case 'W': rcv = FST_RCV_W | (time_delta<<4); break;
+ case 'l': case 'L': rcv = FST_RCV_L | (time_delta<<4); break;
+ default: rcv = FST_RCV_D | (time_delta<<4); break;
+ }
+
+ scratchpnt = fstCopyVarint32ToLeft(scratchpnt, rcv);
+ }
+ }
+ else
+ {
+ /* variable length */
+ /* fstGetUint32 (next_offs) + fstGetVarint32 (time_delta) + fstGetVarint32 (len) + payload */
+ unsigned char *pnt;
+ uint32_t record_len;
+ uint32_t time_delta;
+
+ while(offs)
+ {
+ next_offs = fstGetUint32(vchg_mem + offs);
+ offs += 4;
+ pnt = vchg_mem + offs;
+ offs = next_offs;
+ time_delta = fstGetVarint32(pnt, (int *)&wrlen);
+ pnt += wrlen;
+ record_len = fstGetVarint32(pnt, (int *)&wrlen);
+ pnt += wrlen;
+
+ scratchpnt -= record_len;
+ memcpy(scratchpnt, pnt, record_len);
+
+ scratchpnt = fstCopyVarint32ToLeft(scratchpnt, record_len);
+ scratchpnt = fstCopyVarint32ToLeft(scratchpnt, (time_delta << 1)); /* reserve | 1 case for future expansion */
+ }
+ }
+ }
+ else
+ {
+ wrlen = fstGetVarint32Length(vchg_mem + offs + 4); /* used to advance and determine wrlen */
+#ifndef FST_REMOVE_DUPLICATE_VC
+ memcpy(xc->curval_mem + vm4ip[0], vchg_mem + offs + 4 + wrlen, vm4ip[1]); /* checkpoint variable */
+#endif
+ while(offs)
+ {
+ unsigned int idx;
+ char is_binary = 1;
+ unsigned char *pnt;
+ uint32_t time_delta;
+
+ next_offs = fstGetUint32(vchg_mem + offs);
+ offs += 4;
+
+ time_delta = fstGetVarint32(vchg_mem + offs, (int *)&wrlen);
+
+ pnt = vchg_mem+offs+wrlen;
+ offs = next_offs;
+
+ for(idx=0;idxvchg_siz - scratchpnt;
+ unc_memreq += wrlen;
+ if(wrlen > 32)
+ {
+ unsigned long destlen = wrlen;
+ unsigned char *dmem;
+ unsigned int rc;
+
+ if(!xc->fastpack)
+ {
+ if(wrlen <= packmemlen)
+ {
+ dmem = packmem;
+ }
+ else
+ {
+ free(packmem);
+ dmem = packmem = (unsigned char *)malloc(compressBound(packmemlen = wrlen));
+ }
+
+ rc = compress2(dmem, &destlen, scratchpnt, wrlen, 4);
+ if(rc == Z_OK)
+ {
+#ifndef FST_DYNAMIC_ALIAS_DISABLE
+ PPvoid_t pv = JudyHSIns(&PJHSArray, dmem, destlen, NULL);
+ if(*pv)
+ {
+ uint32_t pvi = (intptr_t)(*pv);
+ vm4ip[2] = -pvi;
+ }
+ else
+ {
+ *pv = (void *)(intptr_t)(i+1);
+#endif
+ fpos += fstWriterVarint(f, wrlen);
+ fpos += destlen;
+ fstFwrite(dmem, destlen, 1, f);
+#ifndef FST_DYNAMIC_ALIAS_DISABLE
+ }
+#endif
+ }
+ else
+ {
+#ifndef FST_DYNAMIC_ALIAS_DISABLE
+ PPvoid_t pv = JudyHSIns(&PJHSArray, scratchpnt, wrlen, NULL);
+ if(*pv)
+ {
+ uint32_t pvi = (intptr_t)(*pv);
+ vm4ip[2] = -pvi;
+ }
+ else
+ {
+ *pv = (void *)(intptr_t)(i+1);
+#endif
+ fpos += fstWriterVarint(f, 0);
+ fpos += wrlen;
+ fstFwrite(scratchpnt, wrlen, 1, f);
+#ifndef FST_DYNAMIC_ALIAS_DISABLE
+ }
+#endif
+ }
+ }
+ else
+ {
+ /* this is extremely conservative: fastlz needs +5% for worst case, lz4 needs siz+(siz/255)+16 */
+ if(((wrlen * 2) + 2) <= packmemlen)
+ {
+ dmem = packmem;
+ }
+ else
+ {
+ free(packmem);
+ dmem = packmem = (unsigned char *)malloc(packmemlen = (wrlen * 2) + 2);
+ }
+
+ rc = (xc->fourpack) ? LZ4_compress((char *)scratchpnt, (char *)dmem, wrlen) : fastlz_compress(scratchpnt, wrlen, dmem);
+ if(rc < destlen)
+ {
+#ifndef FST_DYNAMIC_ALIAS_DISABLE
+ PPvoid_t pv = JudyHSIns(&PJHSArray, dmem, rc, NULL);
+ if(*pv)
+ {
+ uint32_t pvi = (intptr_t)(*pv);
+ vm4ip[2] = -pvi;
+ }
+ else
+ {
+ *pv = (void *)(intptr_t)(i+1);
+#endif
+ fpos += fstWriterVarint(f, wrlen);
+ fpos += rc;
+ fstFwrite(dmem, rc, 1, f);
+#ifndef FST_DYNAMIC_ALIAS_DISABLE
+ }
+#endif
+ }
+ else
+ {
+#ifndef FST_DYNAMIC_ALIAS_DISABLE
+ PPvoid_t pv = JudyHSIns(&PJHSArray, scratchpnt, wrlen, NULL);
+ if(*pv)
+ {
+ uint32_t pvi = (intptr_t)(*pv);
+ vm4ip[2] = -pvi;
+ }
+ else
+ {
+ *pv = (void *)(intptr_t)(i+1);
+#endif
+ fpos += fstWriterVarint(f, 0);
+ fpos += wrlen;
+ fstFwrite(scratchpnt, wrlen, 1, f);
+#ifndef FST_DYNAMIC_ALIAS_DISABLE
+ }
+#endif
+ }
+ }
+ }
+ else
+ {
+#ifndef FST_DYNAMIC_ALIAS_DISABLE
+ PPvoid_t pv = JudyHSIns(&PJHSArray, scratchpnt, wrlen, NULL);
+ if(*pv)
+ {
+ uint32_t pvi = (intptr_t)(*pv);
+ vm4ip[2] = -pvi;
+ }
+ else
+ {
+ *pv = (void *)(intptr_t)(i+1);
+#endif
+ fpos += fstWriterVarint(f, 0);
+ fpos += wrlen;
+ fstFwrite(scratchpnt, wrlen, 1, f);
+#ifndef FST_DYNAMIC_ALIAS_DISABLE
+ }
+#endif
+ }
+
+ /* vm4ip[3] = 0; ...redundant with clearing below */
+#ifdef FST_DEBUG
+ cnt++;
+#endif
+ }
+ }
+
+#ifndef FST_DYNAMIC_ALIAS_DISABLE
+JudyHSFreeArray(&PJHSArray, NULL);
+#endif
+
+free(packmem); packmem = NULL; /* packmemlen = 0; */ /* scan-build */
+
+prevpos = 0; zerocnt = 0;
+free(scratchpad); scratchpad = NULL;
+
+indxpos = ftello(f);
+xc->secnum++;
+
+#ifndef FST_DYNAMIC_ALIAS2_DISABLE
+if(1)
+ {
+ uint32_t prev_alias = 0;
+
+ for(i=0;imaxhandle;i++)
+ {
+ vm4ip = &(xc->valpos_mem[4*i]);
+
+ if(vm4ip[2])
+ {
+ if(zerocnt)
+ {
+ fpos += fstWriterVarint(f, (zerocnt << 1));
+ zerocnt = 0;
+ }
+
+ if(vm4ip[2] & 0x80000000)
+ {
+ if(vm4ip[2] != prev_alias)
+ {
+ fpos += fstWriterSVarint(f, (((int64_t)((uint64_t)(prev_alias = vm4ip[2]))) << 1) | 1);
+ }
+ else
+ {
+ fpos += fstWriterSVarint(f, (0 << 1) | 1);
+ }
+ }
+ else
+ {
+ fpos += fstWriterSVarint(f, ((vm4ip[2] - prevpos) << 1) | 1);
+ prevpos = vm4ip[2];
+ }
+ vm4ip[2] = 0;
+ vm4ip[3] = 0; /* clear out tchn idx */
+ }
+ else
+ {
+ zerocnt++;
+ }
+ }
+ }
+ else
+#endif
+ {
+ for(i=0;imaxhandle;i++)
+ {
+ vm4ip = &(xc->valpos_mem[4*i]);
+
+ if(vm4ip[2])
+ {
+ if(zerocnt)
+ {
+ fpos += fstWriterVarint(f, (zerocnt << 1));
+ zerocnt = 0;
+ }
+
+ if(vm4ip[2] & 0x80000000)
+ {
+ fpos += fstWriterVarint(f, 0); /* signal, note that using a *signed* varint would be more efficient than this byte escape! */
+ fpos += fstWriterVarint(f, (-(int32_t)vm4ip[2]));
+ }
+ else
+ {
+ fpos += fstWriterVarint(f, ((vm4ip[2] - prevpos) << 1) | 1);
+ prevpos = vm4ip[2];
+ }
+ vm4ip[2] = 0;
+ vm4ip[3] = 0; /* clear out tchn idx */
+ }
+ else
+ {
+ zerocnt++;
+ }
+ }
+ }
+
+if(zerocnt)
+ {
+ /* fpos += */ fstWriterVarint(f, (zerocnt << 1)); /* scan-build */
+ }
+#ifdef FST_DEBUG
+fprintf(stderr, FST_APIMESS "value chains: %d\n", cnt);
+#endif
+
+xc->vchg_mem[0] = '!';
+xc->vchg_siz = 1;
+
+endpos = ftello(xc->handle);
+fstWriterUint64(xc->handle, endpos-indxpos); /* write delta index position at very end of block */
+
+/*emit time changes for block */
+fflush(xc->tchn_handle);
+tlen = ftello(xc->tchn_handle);
+fstWriterFseeko(xc, xc->tchn_handle, 0, SEEK_SET);
+
+errno = 0;
+fstWriterMmapSanity(tmem = (unsigned char *)fstMmap(NULL, tlen, PROT_READ|PROT_WRITE, MAP_SHARED, fileno(xc->tchn_handle), 0), __FILE__, __LINE__, "tmem");
+if(tmem)
+ {
+ unsigned long destlen = tlen;
+ unsigned char *dmem = (unsigned char *)malloc(compressBound(destlen));
+ int rc = compress2(dmem, &destlen, tmem, tlen, 9);
+
+ if((rc == Z_OK) && (((fst_off_t)destlen) < tlen))
+ {
+ fstFwrite(dmem, destlen, 1, xc->handle);
+ }
+ else /* comparison between compressed / decompressed len tells if compressed */
+ {
+ fstFwrite(tmem, tlen, 1, xc->handle);
+ destlen = tlen;
+ }
+ free(dmem);
+ fstMunmap(tmem, tlen);
+ fstWriterUint64(xc->handle, tlen); /* uncompressed */
+ fstWriterUint64(xc->handle, destlen); /* compressed */
+ fstWriterUint64(xc->handle, xc->tchn_cnt); /* number of time items */
+ }
+
+xc->tchn_cnt = xc->tchn_idx = 0;
+fstWriterFseeko(xc, xc->tchn_handle, 0, SEEK_SET);
+fstFtruncate(fileno(xc->tchn_handle), 0);
+
+/* write block trailer */
+endpos = ftello(xc->handle);
+fstWriterFseeko(xc, xc->handle, xc->section_start, SEEK_SET);
+fstWriterUint64(xc->handle, endpos - xc->section_start); /* write block length */
+fstWriterFseeko(xc, xc->handle, 8, SEEK_CUR); /* skip begin time */
+fstWriterUint64(xc->handle, xc->curtime); /* write end time for section */
+fstWriterUint64(xc->handle, unc_memreq); /* amount of buffer memory required in reader for full traversal */
+fflush(xc->handle);
+
+fstWriterFseeko(xc, xc->handle, xc->section_start-1, SEEK_SET); /* write out FST_BL_VCDATA over FST_BL_SKIP */
+
+#ifndef FST_DYNAMIC_ALIAS_DISABLE
+#ifndef FST_DYNAMIC_ALIAS2_DISABLE
+fputc(FST_BL_VCDATA_DYN_ALIAS2, xc->handle);
+#else
+fputc(FST_BL_VCDATA_DYN_ALIAS, xc->handle);
+#endif
+#else
+fputc(FST_BL_VCDATA, xc->handle);
+#endif
+
+fflush(xc->handle);
+
+fstWriterFseeko(xc, xc->handle, endpos, SEEK_SET); /* seek to end of file */
+
+xc2->section_header_truncpos = endpos; /* cache in case of need to truncate */
+if(xc->dump_size_limit)
+ {
+ if(endpos >= ((fst_off_t)xc->dump_size_limit))
+ {
+ xc2->skip_writing_section_hdr = 1;
+ xc2->size_limit_locked = 1;
+ xc2->is_initial_time = 1; /* to trick emit value and emit time change */
+#ifdef FST_DEBUG
+ fprintf(stderr, FST_APIMESS "<< dump file size limit reached, stopping dumping >>\n");
+#endif
+ }
+ }
+
+if(!xc2->skip_writing_section_hdr)
+ {
+ fstWriterEmitSectionHeader(xc); /* emit next section header */
+ }
+fflush(xc->handle);
+
+xc->already_in_flush = 0;
+}
+
+
+#ifdef FST_WRITER_PARALLEL
+static void *fstWriterFlushContextPrivate1(void *ctx)
+{
+struct fstWriterContext *xc = (struct fstWriterContext *)ctx;
+struct fstWriterContext *xc_parent;
+
+pthread_mutex_lock(&(xc->xc_parent->mutex));
+fstWriterFlushContextPrivate2(xc);
+
+#ifdef FST_REMOVE_DUPLICATE_VC
+free(xc->curval_mem);
+#endif
+free(xc->valpos_mem);
+free(xc->vchg_mem);
+tmpfile_close(&xc->tchn_handle, &xc->tchn_handle_nam);
+xc_parent = xc->xc_parent;
+free(xc);
+
+xc_parent->in_pthread = 0;
+pthread_mutex_unlock(&(xc_parent->mutex));
+
+return(NULL);
+}
+
+
+static void fstWriterFlushContextPrivate(void *ctx)
+{
+struct fstWriterContext *xc = (struct fstWriterContext *)ctx;
+
+if(xc->parallel_enabled)
+ {
+ struct fstWriterContext *xc2 = (struct fstWriterContext *)malloc(sizeof(struct fstWriterContext));
+ unsigned int i;
+
+ pthread_mutex_lock(&xc->mutex);
+ pthread_mutex_unlock(&xc->mutex);
+
+ xc->xc_parent = xc;
+ memcpy(xc2, xc, sizeof(struct fstWriterContext));
+
+ xc2->valpos_mem = (uint32_t *)malloc(xc->maxhandle * 4 * sizeof(uint32_t));
+ memcpy(xc2->valpos_mem, xc->valpos_mem, xc->maxhandle * 4 * sizeof(uint32_t));
+
+ /* curval mem is updated in the thread */
+#ifdef FST_REMOVE_DUPLICATE_VC
+ xc2->curval_mem = (unsigned char *)malloc(xc->maxvalpos);
+ memcpy(xc2->curval_mem, xc->curval_mem, xc->maxvalpos);
+#endif
+
+ xc->vchg_mem = (unsigned char *)malloc(xc->vchg_alloc_siz);
+ xc->vchg_mem[0] = '!';
+ xc->vchg_siz = 1;
+
+ for(i=0;imaxhandle;i++)
+ {
+ uint32_t *vm4ip = &(xc->valpos_mem[4*i]);
+ vm4ip[2] = 0; /* zero out offset val */
+ vm4ip[3] = 0; /* zero out last time change val */
+ }
+
+ xc->tchn_cnt = xc->tchn_idx = 0;
+ xc->tchn_handle = tmpfile_open(&xc->tchn_handle_nam); /* child thread will deallocate file/name */
+ fstWriterFseeko(xc, xc->tchn_handle, 0, SEEK_SET);
+ fstFtruncate(fileno(xc->tchn_handle), 0);
+
+ xc->section_header_only = 0;
+ xc->secnum++;
+
+ while (xc->in_pthread)
+ {
+ pthread_mutex_lock(&xc->mutex);
+ pthread_mutex_unlock(&xc->mutex);
+ };
+
+ pthread_mutex_lock(&xc->mutex);
+ xc->in_pthread = 1;
+ pthread_mutex_unlock(&xc->mutex);
+
+ pthread_create(&xc->thread, &xc->thread_attr, fstWriterFlushContextPrivate1, xc2);
+ }
+ else
+ {
+ if(xc->parallel_was_enabled) /* conservatively block */
+ {
+ pthread_mutex_lock(&xc->mutex);
+ pthread_mutex_unlock(&xc->mutex);
+ }
+
+ xc->xc_parent = xc;
+ fstWriterFlushContextPrivate2(xc);
+ }
+}
+#endif
+
+
+/*
+ * queues up a flush context operation
+ */
+void fstWriterFlushContext(void *ctx)
+{
+struct fstWriterContext *xc = (struct fstWriterContext *)ctx;
+if(xc)
+ {
+ if(xc->tchn_idx > 1)
+ {
+ xc->flush_context_pending = 1;
+ }
+ }
+}
+
+
+/*
+ * close out FST file
+ */
+void fstWriterClose(void *ctx)
+{
+struct fstWriterContext *xc = (struct fstWriterContext *)ctx;
+
+#ifdef FST_WRITER_PARALLEL
+if(xc)
+ {
+ pthread_mutex_lock(&xc->mutex);
+ pthread_mutex_unlock(&xc->mutex);
+ }
+#endif
+
+if(xc && !xc->already_in_close && !xc->already_in_flush)
+ {
+ unsigned char *tmem = NULL;
+ fst_off_t fixup_offs, tlen, hlen;
+
+ xc->already_in_close = 1; /* never need to zero this out as it is freed at bottom */
+
+ if(xc->section_header_only && xc->section_header_truncpos && (xc->vchg_siz <= 1) && (!xc->is_initial_time))
+ {
+ fstFtruncate(fileno(xc->handle), xc->section_header_truncpos);
+ fstWriterFseeko(xc, xc->handle, xc->section_header_truncpos, SEEK_SET);
+ xc->section_header_only = 0;
+ }
+ else
+ {
+ xc->skip_writing_section_hdr = 1;
+ if(!xc->size_limit_locked)
+ {
+ if(FST_UNLIKELY(xc->is_initial_time)) /* simulation time never advanced so mock up the changes as time zero ones */
+ {
+ fstHandle dupe_idx;
+
+ fstWriterEmitTimeChange(xc, 0); /* emit some time change just to have one */
+ for(dupe_idx = 0; dupe_idx < xc->maxhandle; dupe_idx++) /* now clone the values */
+ {
+ fstWriterEmitValueChange(xc, dupe_idx+1, xc->curval_mem + xc->valpos_mem[4*dupe_idx]);
+ }
+ }
+ fstWriterFlushContextPrivate(xc);
+#ifdef FST_WRITER_PARALLEL
+ pthread_mutex_lock(&xc->mutex);
+ pthread_mutex_unlock(&xc->mutex);
+
+ while (xc->in_pthread)
+ {
+ pthread_mutex_lock(&xc->mutex);
+ pthread_mutex_unlock(&xc->mutex);
+ };
+#endif
+ }
+ }
+ fstDestroyMmaps(xc, 1);
+ if(xc->outval_mem)
+ {
+ free(xc->outval_mem); xc->outval_mem = NULL;
+ xc->outval_alloc_siz = 0;
+ }
+
+ /* write out geom section */
+ fflush(xc->geom_handle);
+ tlen = ftello(xc->geom_handle);
+ errno = 0;
+ if(tlen)
+ {
+ fstWriterMmapSanity(tmem = (unsigned char *)fstMmap(NULL, tlen, PROT_READ|PROT_WRITE, MAP_SHARED, fileno(xc->geom_handle), 0), __FILE__, __LINE__, "tmem");
+ }
+
+ if(tmem)
+ {
+ unsigned long destlen = tlen;
+ unsigned char *dmem = (unsigned char *)malloc(compressBound(destlen));
+ int rc = compress2(dmem, &destlen, tmem, tlen, 9);
+
+ if((rc != Z_OK) || (((fst_off_t)destlen) > tlen))
+ {
+ destlen = tlen;
+ }
+
+ fixup_offs = ftello(xc->handle);
+ fputc(FST_BL_SKIP, xc->handle); /* temporary tag */
+ fstWriterUint64(xc->handle, destlen + 24); /* section length */
+ fstWriterUint64(xc->handle, tlen); /* uncompressed */
+ /* compressed len is section length - 24 */
+ fstWriterUint64(xc->handle, xc->maxhandle); /* maxhandle */
+ fstFwrite((((fst_off_t)destlen) != tlen) ? dmem : tmem, destlen, 1, xc->handle);
+ fflush(xc->handle);
+
+ fstWriterFseeko(xc, xc->handle, fixup_offs, SEEK_SET);
+ fputc(FST_BL_GEOM, xc->handle); /* actual tag */
+
+ fstWriterFseeko(xc, xc->handle, 0, SEEK_END); /* move file pointer to end for any section adds */
+ fflush(xc->handle);
+
+ free(dmem);
+ fstMunmap(tmem, tlen);
+ }
+
+ if(xc->num_blackouts)
+ {
+ uint64_t cur_bl = 0;
+ fst_off_t bpos, eos;
+ uint32_t i;
+
+ fixup_offs = ftello(xc->handle);
+ fputc(FST_BL_SKIP, xc->handle); /* temporary tag */
+ bpos = fixup_offs + 1;
+ fstWriterUint64(xc->handle, 0); /* section length */
+ fstWriterVarint(xc->handle, xc->num_blackouts);
+
+ for(i=0;inum_blackouts;i++)
+ {
+ fputc(xc->blackout_head->active, xc->handle);
+ fstWriterVarint(xc->handle, xc->blackout_head->tim - cur_bl);
+ cur_bl = xc->blackout_head->tim;
+ xc->blackout_curr = xc->blackout_head->next;
+ free(xc->blackout_head);
+ xc->blackout_head = xc->blackout_curr;
+ }
+
+ eos = ftello(xc->handle);
+ fstWriterFseeko(xc, xc->handle, bpos, SEEK_SET);
+ fstWriterUint64(xc->handle, eos - bpos);
+ fflush(xc->handle);
+
+ fstWriterFseeko(xc, xc->handle, fixup_offs, SEEK_SET);
+ fputc(FST_BL_BLACKOUT, xc->handle); /* actual tag */
+
+ fstWriterFseeko(xc, xc->handle, 0, SEEK_END); /* move file pointer to end for any section adds */
+ fflush(xc->handle);
+ }
+
+ if(xc->compress_hier)
+ {
+ fst_off_t hl, eos;
+ gzFile zhandle;
+ int zfd;
+ int fourpack_duo = 0;
+#ifndef __MINGW32__
+ char *fnam = (char *)malloc(strlen(xc->filename) + 5 + 1);
+#endif
+
+ fixup_offs = ftello(xc->handle);
+ fputc(FST_BL_SKIP, xc->handle); /* temporary tag */
+ hlen = ftello(xc->handle);
+ fstWriterUint64(xc->handle, 0); /* section length */
+ fstWriterUint64(xc->handle, xc->hier_file_len); /* uncompressed length */
+
+ if(!xc->fourpack)
+ {
+ unsigned char *mem = (unsigned char *)malloc(FST_GZIO_LEN);
+ zfd = dup(fileno(xc->handle));
+ fflush(xc->handle);
+ zhandle = gzdopen(zfd, "wb4");
+ if(zhandle)
+ {
+ fstWriterFseeko(xc, xc->hier_handle, 0, SEEK_SET);
+ for(hl = 0; hl < xc->hier_file_len; hl += FST_GZIO_LEN)
+ {
+ unsigned len = ((xc->hier_file_len - hl) > FST_GZIO_LEN) ? FST_GZIO_LEN : (xc->hier_file_len - hl);
+ fstFread(mem, len, 1, xc->hier_handle);
+ gzwrite(zhandle, mem, len);
+ }
+ gzclose(zhandle);
+ }
+ else
+ {
+ close(zfd);
+ }
+ free(mem);
+ }
+ else
+ {
+ int lz4_maxlen;
+ unsigned char *mem;
+ unsigned char *hmem = NULL;
+ int packed_len;
+
+ fflush(xc->handle);
+
+ lz4_maxlen = LZ4_compressBound(xc->hier_file_len);
+ mem = (unsigned char *)malloc(lz4_maxlen);
+ errno = 0;
+ if(xc->hier_file_len)
+ {
+ fstWriterMmapSanity(hmem = (unsigned char *)fstMmap(NULL, xc->hier_file_len, PROT_READ|PROT_WRITE, MAP_SHARED, fileno(xc->hier_handle), 0), __FILE__, __LINE__, "hmem");
+ }
+ packed_len = LZ4_compress((char *)hmem, (char *)mem, xc->hier_file_len);
+ fstMunmap(hmem, xc->hier_file_len);
+
+ fourpack_duo = (!xc->repack_on_close) && (xc->hier_file_len > FST_HDR_FOURPACK_DUO_SIZE); /* double pack when hierarchy is large */
+
+ if(fourpack_duo) /* double packing with LZ4 is faster than gzip */
+ {
+ unsigned char *mem_duo;
+ int lz4_maxlen_duo;
+ int packed_len_duo;
+
+ lz4_maxlen_duo = LZ4_compressBound(packed_len);
+ mem_duo = (unsigned char *)malloc(lz4_maxlen_duo);
+ packed_len_duo = LZ4_compress((char *)mem, (char *)mem_duo, packed_len);
+
+ fstWriterVarint(xc->handle, packed_len); /* 1st round compressed length */
+ fstFwrite(mem_duo, packed_len_duo, 1, xc->handle);
+ free(mem_duo);
+ }
+ else
+ {
+ fstFwrite(mem, packed_len, 1, xc->handle);
+ }
+
+ free(mem);
+ }
+
+ fstWriterFseeko(xc, xc->handle, 0, SEEK_END);
+ eos = ftello(xc->handle);
+ fstWriterFseeko(xc, xc->handle, hlen, SEEK_SET);
+ fstWriterUint64(xc->handle, eos - hlen);
+ fflush(xc->handle);
+
+ fstWriterFseeko(xc, xc->handle, fixup_offs, SEEK_SET);
+ fputc(xc->fourpack ?
+ ( fourpack_duo ? FST_BL_HIER_LZ4DUO : FST_BL_HIER_LZ4) :
+ FST_BL_HIER, xc->handle); /* actual tag now also == compression type */
+
+ fstWriterFseeko(xc, xc->handle, 0, SEEK_END); /* move file pointer to end for any section adds */
+ fflush(xc->handle);
+
+#ifndef __MINGW32__
+ sprintf(fnam, "%s.hier", xc->filename);
+ unlink(fnam);
+ free(fnam);
+#endif
+ }
+
+ /* finalize out header */
+ fstWriterFseeko(xc, xc->handle, FST_HDR_OFFS_START_TIME, SEEK_SET);
+ fstWriterUint64(xc->handle, xc->firsttime);
+ fstWriterUint64(xc->handle, xc->curtime);
+ fstWriterFseeko(xc, xc->handle, FST_HDR_OFFS_NUM_SCOPES, SEEK_SET);
+ fstWriterUint64(xc->handle, xc->numscopes);
+ fstWriterUint64(xc->handle, xc->numsigs);
+ fstWriterUint64(xc->handle, xc->maxhandle);
+ fstWriterUint64(xc->handle, xc->secnum);
+ fflush(xc->handle);
+
+ tmpfile_close(&xc->tchn_handle, &xc->tchn_handle_nam);
+ free(xc->vchg_mem); xc->vchg_mem = NULL;
+ tmpfile_close(&xc->curval_handle, &xc->curval_handle_nam);
+ tmpfile_close(&xc->valpos_handle, &xc->valpos_handle_nam);
+ tmpfile_close(&xc->geom_handle, &xc->geom_handle_nam);
+ if(xc->hier_handle) { fclose(xc->hier_handle); xc->hier_handle = NULL; }
+ if(xc->handle)
+ {
+ if(xc->repack_on_close)
+ {
+ FILE *fp;
+ fst_off_t offpnt, uclen;
+ int flen = strlen(xc->filename);
+ char *hf = (char *)calloc(1, flen + 5);
+
+ strcpy(hf, xc->filename);
+ strcpy(hf+flen, ".pak");
+ fp = fopen(hf, "wb");
+
+ if(fp)
+ {
+ gzFile dsth;
+ int zfd;
+ char gz_membuf[FST_GZIO_LEN];
+
+ fstWriterFseeko(xc, xc->handle, 0, SEEK_END);
+ uclen = ftello(xc->handle);
+
+ fputc(FST_BL_ZWRAPPER, fp);
+ fstWriterUint64(fp, 0);
+ fstWriterUint64(fp, uclen);
+ fflush(fp);
+
+ fstWriterFseeko(xc, xc->handle, 0, SEEK_SET);
+ zfd = dup(fileno(fp));
+ dsth = gzdopen(zfd, "wb4");
+ if(dsth)
+ {
+ for(offpnt = 0; offpnt < uclen; offpnt += FST_GZIO_LEN)
+ {
+ size_t this_len = ((uclen - offpnt) > FST_GZIO_LEN) ? FST_GZIO_LEN : (uclen - offpnt);
+ fstFread(gz_membuf, this_len, 1, xc->handle);
+ gzwrite(dsth, gz_membuf, this_len);
+ }
+ gzclose(dsth);
+ }
+ else
+ {
+ close(zfd);
+ }
+ fstWriterFseeko(xc, fp, 0, SEEK_END);
+ offpnt = ftello(fp);
+ fstWriterFseeko(xc, fp, 1, SEEK_SET);
+ fstWriterUint64(fp, offpnt - 1);
+ fclose(fp);
+ fclose(xc->handle); xc->handle = NULL;
+
+ unlink(xc->filename);
+ rename(hf, xc->filename);
+ }
+ else
+ {
+ xc->repack_on_close = 0;
+ fclose(xc->handle); xc->handle = NULL;
+ }
+
+ free(hf);
+ }
+ else
+ {
+ fclose(xc->handle); xc->handle = NULL;
+ }
+ }
+
+#ifdef __MINGW32__
+ {
+ int flen = strlen(xc->filename);
+ char *hf = (char *)calloc(1, flen + 6);
+ strcpy(hf, xc->filename);
+
+ if(xc->compress_hier)
+ {
+ strcpy(hf + flen, ".hier");
+ unlink(hf); /* no longer needed as a section now exists for this */
+ }
+
+ free(hf);
+ }
+#endif
+
+#ifdef FST_WRITER_PARALLEL
+ pthread_mutex_destroy(&xc->mutex);
+ pthread_attr_destroy(&xc->thread_attr);
+#endif
+
+ if(xc->path_array)
+ {
+#ifndef _WAVE_HAVE_JUDY
+ const uint32_t hashmask = FST_PATH_HASHMASK;
+#endif
+ JudyHSFreeArray(&(xc->path_array), NULL);
+ }
+
+ free(xc->filename); xc->filename = NULL;
+ free(xc);
+ }
+}
+
+
+/*
+ * functions to set miscellaneous header/block information
+ */
+void fstWriterSetDate(void *ctx, const char *dat)
+{
+struct fstWriterContext *xc = (struct fstWriterContext *)ctx;
+if(xc)
+ {
+ char s[FST_HDR_DATE_SIZE];
+ fst_off_t fpos = ftello(xc->handle);
+ int len = strlen(dat);
+
+ fstWriterFseeko(xc, xc->handle, FST_HDR_OFFS_DATE, SEEK_SET);
+ memset(s, 0, FST_HDR_DATE_SIZE);
+ memcpy(s, dat, (len < FST_HDR_DATE_SIZE) ? len : FST_HDR_DATE_SIZE);
+ fstFwrite(s, FST_HDR_DATE_SIZE, 1, xc->handle);
+ fflush(xc->handle);
+ fstWriterFseeko(xc, xc->handle, fpos, SEEK_SET);
+ }
+}
+
+
+void fstWriterSetVersion(void *ctx, const char *vers)
+{
+struct fstWriterContext *xc = (struct fstWriterContext *)ctx;
+if(xc && vers)
+ {
+ char s[FST_HDR_SIM_VERSION_SIZE];
+ fst_off_t fpos = ftello(xc->handle);
+ int len = strlen(vers);
+
+ fstWriterFseeko(xc, xc->handle, FST_HDR_OFFS_SIM_VERSION, SEEK_SET);
+ memset(s, 0, FST_HDR_SIM_VERSION_SIZE);
+ memcpy(s, vers, (len < FST_HDR_SIM_VERSION_SIZE) ? len : FST_HDR_SIM_VERSION_SIZE);
+ fstFwrite(s, FST_HDR_SIM_VERSION_SIZE, 1, xc->handle);
+ fflush(xc->handle);
+ fstWriterFseeko(xc, xc->handle, fpos, SEEK_SET);
+ }
+}
+
+
+void fstWriterSetFileType(void *ctx, enum fstFileType filetype)
+{
+struct fstWriterContext *xc = (struct fstWriterContext *)ctx;
+if(xc)
+ {
+ if(/*(filetype >= FST_FT_MIN) &&*/ (filetype <= FST_FT_MAX))
+ {
+ fst_off_t fpos = ftello(xc->handle);
+
+ xc->filetype = filetype;
+
+ fstWriterFseeko(xc, xc->handle, FST_HDR_OFFS_FILETYPE, SEEK_SET);
+ fputc(xc->filetype, xc->handle);
+ fflush(xc->handle);
+ fstWriterFseeko(xc, xc->handle, fpos, SEEK_SET);
+ }
+ }
+}
+
+
+static void fstWriterSetAttrDoubleArgGeneric(void *ctx, int typ, uint64_t arg1, uint64_t arg2)
+{
+struct fstWriterContext *xc = (struct fstWriterContext *)ctx;
+if(xc)
+ {
+ unsigned char buf[11]; /* ceil(64/7) = 10 + null term */
+ unsigned char *pnt = fstCopyVarint64ToRight(buf, arg1);
+ if(arg1)
+ {
+ *pnt = 0; /* this converts any *nonzero* arg1 when made a varint into a null-term string */
+ }
+
+ fstWriterSetAttrBegin(xc, FST_AT_MISC, typ, (char *)buf, arg2);
+ }
+}
+
+
+static void fstWriterSetAttrGeneric(void *ctx, const char *comm, int typ, uint64_t arg)
+{
+struct fstWriterContext *xc = (struct fstWriterContext *)ctx;
+if(xc && comm)
+ {
+ char *s = strdup(comm);
+ char *sf = s;
+
+ while(*s)
+ {
+ if((*s == '\n') || (*s == '\r')) *s = ' ';
+ s++;
+ }
+
+ fstWriterSetAttrBegin(xc, FST_AT_MISC, typ, sf, arg);
+ free(sf);
+ }
+}
+
+
+static void fstWriterSetSourceStem_2(void *ctx, const char *path, unsigned int line, unsigned int use_realpath, int typ)
+{
+struct fstWriterContext *xc = (struct fstWriterContext *)ctx;
+
+if(xc && path && path[0])
+ {
+ uint64_t sidx = 0;
+ int slen = strlen(path);
+#ifndef _WAVE_HAVE_JUDY
+ const uint32_t hashmask = FST_PATH_HASHMASK;
+ const unsigned char *path2 = (const unsigned char *)path;
+ PPvoid_t pv;
+#else
+ char *path2 = (char *)alloca(slen + 1); /* judy lacks const qualifier in its JudyHSIns definition */
+ PPvoid_t pv;
+ strcpy(path2, path);
+#endif
+
+ pv = JudyHSIns(&(xc->path_array), path2, slen, NULL);
+ if(*pv)
+ {
+ sidx = (intptr_t)(*pv);
+ }
+ else
+ {
+ char *rp = NULL;
+
+ sidx = ++xc->path_array_count;
+ *pv = (void *)(intptr_t)(xc->path_array_count);
+
+ if(use_realpath)
+ {
+ rp = fstRealpath(
+#ifndef _WAVE_HAVE_JUDY
+ (const char *)
+#endif
+ path2, NULL);
+ }
+
+ fstWriterSetAttrGeneric(xc, rp ? rp :
+#ifndef _WAVE_HAVE_JUDY
+ (const char *)
+#endif
+ path2, FST_MT_PATHNAME, sidx);
+
+ if(rp)
+ {
+ free(rp);
+ }
+ }
+
+ fstWriterSetAttrDoubleArgGeneric(xc, typ, sidx, line);
+ }
+}
+
+
+void fstWriterSetSourceStem(void *ctx, const char *path, unsigned int line, unsigned int use_realpath)
+{
+fstWriterSetSourceStem_2(ctx, path, line, use_realpath, FST_MT_SOURCESTEM);
+}
+
+
+void fstWriterSetSourceInstantiationStem(void *ctx, const char *path, unsigned int line, unsigned int use_realpath)
+{
+fstWriterSetSourceStem_2(ctx, path, line, use_realpath, FST_MT_SOURCEISTEM);
+}
+
+
+void fstWriterSetComment(void *ctx, const char *comm)
+{
+fstWriterSetAttrGeneric(ctx, comm, FST_MT_COMMENT, 0);
+}
+
+
+void fstWriterSetValueList(void *ctx, const char *vl)
+{
+fstWriterSetAttrGeneric(ctx, vl, FST_MT_VALUELIST, 0);
+}
+
+
+void fstWriterSetEnvVar(void *ctx, const char *envvar)
+{
+fstWriterSetAttrGeneric(ctx, envvar, FST_MT_ENVVAR, 0);
+}
+
+
+void fstWriterSetTimescale(void *ctx, int ts)
+{
+struct fstWriterContext *xc = (struct fstWriterContext *)ctx;
+if(xc)
+ {
+ fst_off_t fpos = ftello(xc->handle);
+ fstWriterFseeko(xc, xc->handle, FST_HDR_OFFS_TIMESCALE, SEEK_SET);
+ fputc(ts & 255, xc->handle);
+ fflush(xc->handle);
+ fstWriterFseeko(xc, xc->handle, fpos, SEEK_SET);
+ }
+}
+
+
+void fstWriterSetTimescaleFromString(void *ctx, const char *s)
+{
+struct fstWriterContext *xc = (struct fstWriterContext *)ctx;
+if(xc && s)
+ {
+ int mat = 0;
+ int seconds_exp = -9;
+ int tv = atoi(s);
+ const char *pnt = s;
+
+ while(*pnt)
+ {
+ switch(*pnt)
+ {
+ case 'm': seconds_exp = -3; mat = 1; break;
+ case 'u': seconds_exp = -6; mat = 1; break;
+ case 'n': seconds_exp = -9; mat = 1; break;
+ case 'p': seconds_exp = -12; mat = 1; break;
+ case 'f': seconds_exp = -15; mat = 1; break;
+ case 'a': seconds_exp = -18; mat = 1; break;
+ case 'z': seconds_exp = -21; mat = 1; break;
+ case 's': seconds_exp = 0; mat = 1; break;
+ default: break;
+ }
+
+ if(mat) break;
+ pnt++;
+ }
+
+ if(tv == 10)
+ {
+ seconds_exp++;
+ }
+ else
+ if(tv == 100)
+ {
+ seconds_exp+=2;
+ }
+
+ fstWriterSetTimescale(ctx, seconds_exp);
+ }
+}
+
+
+void fstWriterSetTimezero(void *ctx, int64_t tim)
+{
+struct fstWriterContext *xc = (struct fstWriterContext *)ctx;
+if(xc)
+ {
+ fst_off_t fpos = ftello(xc->handle);
+ fstWriterFseeko(xc, xc->handle, FST_HDR_OFFS_TIMEZERO, SEEK_SET);
+ fstWriterUint64(xc->handle, (xc->timezero = tim));
+ fflush(xc->handle);
+ fstWriterFseeko(xc, xc->handle, fpos, SEEK_SET);
+ }
+}
+
+
+void fstWriterSetPackType(void *ctx, enum fstWriterPackType typ)
+{
+struct fstWriterContext *xc = (struct fstWriterContext *)ctx;
+if(xc)
+ {
+ xc->fastpack = (typ != FST_WR_PT_ZLIB);
+ xc->fourpack = (typ == FST_WR_PT_LZ4);
+ }
+}
+
+
+void fstWriterSetRepackOnClose(void *ctx, int enable)
+{
+struct fstWriterContext *xc = (struct fstWriterContext *)ctx;
+if(xc)
+ {
+ xc->repack_on_close = (enable != 0);
+ }
+}
+
+
+void fstWriterSetParallelMode(void *ctx, int enable)
+{
+struct fstWriterContext *xc = (struct fstWriterContext *)ctx;
+if(xc)
+ {
+ xc->parallel_was_enabled |= xc->parallel_enabled; /* make sticky */
+ xc->parallel_enabled = (enable != 0);
+#ifndef FST_WRITER_PARALLEL
+ if(xc->parallel_enabled)
+ {
+ fprintf(stderr, FST_APIMESS "fstWriterSetParallelMode(), FST_WRITER_PARALLEL not enabled during compile, exiting.\n");
+ exit(255);
+ }
+#endif
+ }
+}
+
+
+void fstWriterSetDumpSizeLimit(void *ctx, uint64_t numbytes)
+{
+struct fstWriterContext *xc = (struct fstWriterContext *)ctx;
+if(xc)
+ {
+ xc->dump_size_limit = numbytes;
+ }
+}
+
+
+int fstWriterGetDumpSizeLimitReached(void *ctx)
+{
+struct fstWriterContext *xc = (struct fstWriterContext *)ctx;
+if(xc)
+ {
+ return(xc->size_limit_locked != 0);
+ }
+
+return(0);
+}
+
+
+int fstWriterGetFseekFailed(void *ctx)
+{
+struct fstWriterContext *xc = (struct fstWriterContext *)ctx;
+if(xc)
+ {
+ return(xc->fseek_failed != 0);
+ }
+
+return(0);
+}
+
+
+/*
+ * writer attr/scope/var creation:
+ * fstWriterCreateVar2() is used to dump VHDL or other languages, but the
+ * underlying variable needs to map to Verilog/SV via the proper fstVarType vt
+ */
+fstHandle fstWriterCreateVar2(void *ctx, enum fstVarType vt, enum fstVarDir vd,
+ uint32_t len, const char *nam, fstHandle aliasHandle,
+ const char *type, enum fstSupplementalVarType svt, enum fstSupplementalDataType sdt)
+{
+fstWriterSetAttrGeneric(ctx, type ? type : "", FST_MT_SUPVAR, (svt<valpos_mem)
+ {
+ fstDestroyMmaps(xc, 0);
+ }
+
+ fputc(vt, xc->hier_handle);
+ fputc(vd, xc->hier_handle);
+ nlen = strlen(nam);
+ fstFwrite(nam, nlen, 1, xc->hier_handle);
+ fputc(0, xc->hier_handle);
+ xc->hier_file_len += (nlen+3);
+
+ if((vt == FST_VT_VCD_REAL) || (vt == FST_VT_VCD_REAL_PARAMETER) || (vt == FST_VT_VCD_REALTIME) || (vt == FST_VT_SV_SHORTREAL))
+ {
+ is_real = 1;
+ len = 8; /* recast number of bytes to that of what a double is */
+ }
+ else
+ {
+ is_real = 0;
+ if(vt == FST_VT_GEN_STRING)
+ {
+ len = 0;
+ }
+ }
+
+ xc->hier_file_len += fstWriterVarint(xc->hier_handle, len);
+
+ if(aliasHandle > xc->maxhandle) aliasHandle = 0;
+ xc->hier_file_len += fstWriterVarint(xc->hier_handle, aliasHandle);
+ xc->numsigs++;
+ if(xc->numsigs == xc->next_huge_break)
+ {
+ if(xc->fst_break_size < xc->fst_huge_break_size)
+ {
+ xc->next_huge_break += FST_ACTIVATE_HUGE_INC;
+ xc->fst_break_size += xc->fst_orig_break_size;
+ xc->fst_break_add_size += xc->fst_orig_break_add_size;
+
+ xc->vchg_alloc_siz = xc->fst_break_size + xc->fst_break_add_size;
+ if(xc->vchg_mem)
+ {
+ xc->vchg_mem = (unsigned char *)realloc(xc->vchg_mem, xc->vchg_alloc_siz);
+ }
+ }
+ }
+
+ if(!aliasHandle)
+ {
+ uint32_t zero = 0;
+
+ if(len)
+ {
+ fstWriterVarint(xc->geom_handle, !is_real ? len : 0); /* geom section encodes reals as zero byte */
+ }
+ else
+ {
+ fstWriterVarint(xc->geom_handle, 0xFFFFFFFF); /* geom section encodes zero len as 32b -1 */
+ }
+
+ fstFwrite(&xc->maxvalpos, sizeof(uint32_t), 1, xc->valpos_handle);
+ fstFwrite(&len, sizeof(uint32_t), 1, xc->valpos_handle);
+ fstFwrite(&zero, sizeof(uint32_t), 1, xc->valpos_handle);
+ fstFwrite(&zero, sizeof(uint32_t), 1, xc->valpos_handle);
+
+ if(!is_real)
+ {
+ for(i=0;icurval_handle);
+ }
+ }
+ else
+ {
+ fstFwrite(&xc->nan, 8, 1, xc->curval_handle); /* initialize doubles to NaN rather than x */
+ }
+
+ xc->maxvalpos+=len;
+ xc->maxhandle++;
+ return(xc->maxhandle);
+ }
+ else
+ {
+ return(aliasHandle);
+ }
+ }
+
+return(0);
+}
+
+
+void fstWriterSetScope(void *ctx, enum fstScopeType scopetype,
+ const char *scopename, const char *scopecomp)
+{
+struct fstWriterContext *xc = (struct fstWriterContext *)ctx;
+
+if(xc)
+ {
+ fputc(FST_ST_VCD_SCOPE, xc->hier_handle);
+ if(/*(scopetype < FST_ST_VCD_MODULE) ||*/ (scopetype > FST_ST_MAX)) { scopetype = FST_ST_VCD_MODULE; }
+ fputc(scopetype, xc->hier_handle);
+ fprintf(xc->hier_handle, "%s%c%s%c",
+ scopename ? scopename : "", 0,
+ scopecomp ? scopecomp : "", 0);
+
+ if(scopename)
+ {
+ xc->hier_file_len += strlen(scopename);
+ }
+ if(scopecomp)
+ {
+ xc->hier_file_len += strlen(scopecomp);
+ }
+
+ xc->hier_file_len += 4; /* FST_ST_VCD_SCOPE + scopetype + two string terminating zeros */
+ xc->numscopes++;
+ }
+}
+
+
+void fstWriterSetUpscope(void *ctx)
+{
+struct fstWriterContext *xc = (struct fstWriterContext *)ctx;
+
+if(xc)
+ {
+ fputc(FST_ST_VCD_UPSCOPE, xc->hier_handle);
+ xc->hier_file_len++;
+ }
+}
+
+
+void fstWriterSetAttrBegin(void *ctx, enum fstAttrType attrtype, int subtype,
+ const char *attrname, uint64_t arg)
+{
+struct fstWriterContext *xc = (struct fstWriterContext *)ctx;
+
+if(xc)
+ {
+ fputc(FST_ST_GEN_ATTRBEGIN, xc->hier_handle);
+ if(/*(attrtype < FST_AT_MISC) ||*/ (attrtype > FST_AT_MAX)) { attrtype = FST_AT_MISC; subtype = FST_MT_UNKNOWN; }
+ fputc(attrtype, xc->hier_handle);
+
+ switch(attrtype)
+ {
+ case FST_AT_ARRAY: if((subtype < FST_AR_NONE) || (subtype > FST_AR_MAX)) subtype = FST_AR_NONE; break;
+ case FST_AT_ENUM: if((subtype < FST_EV_SV_INTEGER) || (subtype > FST_EV_MAX)) subtype = FST_EV_SV_INTEGER; break;
+ case FST_AT_PACK: if((subtype < FST_PT_NONE) || (subtype > FST_PT_MAX)) subtype = FST_PT_NONE; break;
+
+ case FST_AT_MISC:
+ default: break;
+ }
+
+ fputc(subtype, xc->hier_handle);
+ fprintf(xc->hier_handle, "%s%c",
+ attrname ? attrname : "", 0);
+
+ if(attrname)
+ {
+ xc->hier_file_len += strlen(attrname);
+ }
+
+ xc->hier_file_len += 4; /* FST_ST_GEN_ATTRBEGIN + type + subtype + string terminating zero */
+ xc->hier_file_len += fstWriterVarint(xc->hier_handle, arg);
+ }
+}
+
+
+void fstWriterSetAttrEnd(void *ctx)
+{
+struct fstWriterContext *xc = (struct fstWriterContext *)ctx;
+
+if(xc)
+ {
+ fputc(FST_ST_GEN_ATTREND, xc->hier_handle);
+ xc->hier_file_len++;
+ }
+}
+
+
+fstEnumHandle fstWriterCreateEnumTable(void *ctx, const char *name, uint32_t elem_count, unsigned int min_valbits, const char **literal_arr, const char **val_arr)
+{
+fstEnumHandle handle = 0;
+unsigned int *literal_lens = NULL;
+unsigned int *val_lens = NULL;
+int lit_len_tot = 0;
+int val_len_tot = 0;
+int name_len;
+char elem_count_buf[16];
+int elem_count_len;
+int total_len;
+int pos = 0;
+char *attr_str = NULL;
+
+if(ctx && name && literal_arr && val_arr && (elem_count != 0))
+ {
+ struct fstWriterContext *xc = (struct fstWriterContext *)ctx;
+
+ uint32_t i;
+
+ name_len = strlen(name);
+ elem_count_len = sprintf(elem_count_buf, "%" PRIu32, elem_count);
+
+ literal_lens = (unsigned int *)calloc(elem_count, sizeof(unsigned int));
+ val_lens = (unsigned int *)calloc(elem_count, sizeof(unsigned int));
+
+ for(i=0;i 0)
+ {
+ if(val_lens[i] < min_valbits)
+ {
+ val_len_tot += (min_valbits - val_lens[i]); /* additional converted len is same for '0' character */
+ }
+ }
+ }
+
+ total_len = name_len + 1 + elem_count_len + 1 + lit_len_tot + elem_count + val_len_tot + elem_count;
+
+ attr_str = (char*)malloc(total_len);
+ pos = 0;
+
+ memcpy(attr_str+pos, name, name_len);
+ pos += name_len;
+ attr_str[pos++] = ' ';
+
+ memcpy(attr_str+pos, elem_count_buf, elem_count_len);
+ pos += elem_count_len;
+ attr_str[pos++] = ' ';
+
+ for(i=0;i 0)
+ {
+ if(val_lens[i] < min_valbits)
+ {
+ memset(attr_str+pos, '0', min_valbits - val_lens[i]);
+ pos += (min_valbits - val_lens[i]);
+ }
+ }
+
+ pos += fstUtilityBinToEsc((unsigned char*)attr_str+pos, (unsigned char*)val_arr[i], val_lens[i]);
+ attr_str[pos++] = ' ';
+ }
+
+ attr_str[pos-1] = 0;
+
+#ifdef FST_DEBUG
+ fprintf(stderr, FST_APIMESS "fstWriterCreateEnumTable() total_len: %d, pos: %d\n", total_len, pos);
+ fprintf(stderr, FST_APIMESS "*%s*\n", attr_str);
+#endif
+
+ fstWriterSetAttrBegin(xc, FST_AT_MISC, FST_MT_ENUMTABLE, attr_str, handle = ++xc->max_enumhandle);
+
+ free(attr_str);
+ free(val_lens);
+ free(literal_lens);
+ }
+
+return(handle);
+}
+
+
+void fstWriterEmitEnumTableRef(void *ctx, fstEnumHandle handle)
+{
+struct fstWriterContext *xc = (struct fstWriterContext *)ctx;
+if(xc && handle)
+ {
+ fstWriterSetAttrBegin(xc, FST_AT_MISC, FST_MT_ENUMTABLE, NULL, handle);
+ }
+}
+
+
+/*
+ * value and time change emission
+ */
+void fstWriterEmitValueChange(void *ctx, fstHandle handle, const void *val)
+{
+struct fstWriterContext *xc = (struct fstWriterContext *)ctx;
+const unsigned char *buf = (const unsigned char *)val;
+uint32_t offs;
+int len;
+
+if(FST_LIKELY((xc) && (handle <= xc->maxhandle)))
+ {
+ uint32_t fpos;
+ uint32_t *vm4ip;
+
+ if(FST_UNLIKELY(!xc->valpos_mem))
+ {
+ xc->vc_emitted = 1;
+ fstWriterCreateMmaps(xc);
+ }
+
+ handle--; /* move starting at 1 index to starting at 0 */
+ vm4ip = &(xc->valpos_mem[4*handle]);
+
+ len = vm4ip[1];
+ if(FST_LIKELY(len)) /* len of zero = variable length, use fstWriterEmitVariableLengthValueChange */
+ {
+ if(FST_LIKELY(!xc->is_initial_time))
+ {
+ fpos = xc->vchg_siz;
+
+ if(FST_UNLIKELY((fpos + len + 10) > xc->vchg_alloc_siz))
+ {
+ xc->vchg_alloc_siz += (xc->fst_break_add_size + len); /* +len added in the case of extremely long vectors and small break add sizes */
+ xc->vchg_mem = (unsigned char *)realloc(xc->vchg_mem, xc->vchg_alloc_siz);
+ if(FST_UNLIKELY(!xc->vchg_mem))
+ {
+ fprintf(stderr, FST_APIMESS "Could not realloc() in fstWriterEmitValueChange, exiting.\n");
+ exit(255);
+ }
+ }
+#ifdef FST_REMOVE_DUPLICATE_VC
+ offs = vm4ip[0];
+
+ if(len != 1)
+ {
+ if((vm4ip[3]==xc->tchn_idx)&&(vm4ip[2]))
+ {
+ unsigned char *old_value = xc->vchg_mem + vm4ip[2] + 4; /* the +4 skips old vm4ip[2] value */
+ while(*(old_value++) & 0x80) { /* skips over varint encoded "xc->tchn_idx - vm4ip[3]" */ }
+ memcpy(old_value, buf, len); /* overlay new value */
+
+ memcpy(xc->curval_mem + offs, buf, len);
+ return;
+ }
+ else
+ {
+ if(!memcmp(xc->curval_mem + offs, buf, len))
+ {
+ if(!xc->curtime)
+ {
+ int i;
+ for(i=0;icurval_mem + offs, buf, len);
+ }
+ else
+ {
+ if((vm4ip[3]==xc->tchn_idx)&&(vm4ip[2]))
+ {
+ unsigned char *old_value = xc->vchg_mem + vm4ip[2] + 4; /* the +4 skips old vm4ip[2] value */
+ while(*(old_value++) & 0x80) { /* skips over varint encoded "xc->tchn_idx - vm4ip[3]" */ }
+ *old_value = *buf; /* overlay new value */
+
+ *(xc->curval_mem + offs) = *buf;
+ return;
+ }
+ else
+ {
+ if((*(xc->curval_mem + offs)) == (*buf))
+ {
+ if(!xc->curtime)
+ {
+ if(*buf != 'x') return;
+ }
+ else
+ {
+ return;
+ }
+ }
+ }
+
+ *(xc->curval_mem + offs) = *buf;
+ }
+#endif
+ xc->vchg_siz += fstWriterUint32WithVarint32(xc, &vm4ip[2], xc->tchn_idx - vm4ip[3], buf, len); /* do one fwrite op only */
+ vm4ip[3] = xc->tchn_idx;
+ vm4ip[2] = fpos;
+ }
+ else
+ {
+ offs = vm4ip[0];
+ memcpy(xc->curval_mem + offs, buf, len);
+ }
+ }
+ }
+}
+
+void fstWriterEmitValueChange32(void *ctx, fstHandle handle,
+ uint32_t bits, uint32_t val) {
+ char buf[32];
+ char *s = buf;
+ uint32_t i;
+ for (i = 0; i < bits; ++i)
+ {
+ *s++ = '0' + ((val >> (bits - i - 1)) & 1);
+ }
+ fstWriterEmitValueChange(ctx, handle, buf);
+}
+void fstWriterEmitValueChange64(void *ctx, fstHandle handle,
+ uint32_t bits, uint64_t val) {
+ char buf[64];
+ char *s = buf;
+ uint32_t i;
+ for (i = 0; i < bits; ++i)
+ {
+ *s++ = '0' + ((val >> (bits - i - 1)) & 1);
+ }
+ fstWriterEmitValueChange(ctx, handle, buf);
+}
+void fstWriterEmitValueChangeVec32(void *ctx, fstHandle handle,
+ uint32_t bits, const uint32_t *val) {
+ struct fstWriterContext *xc = (struct fstWriterContext *)ctx;
+ if (FST_UNLIKELY(bits <= 32))
+ {
+ fstWriterEmitValueChange32(ctx, handle, bits, val[0]);
+ }
+ else if(FST_LIKELY(xc))
+ {
+ int bq = bits / 32;
+ int br = bits & 31;
+ int i;
+ int w;
+ uint32_t v;
+ unsigned char* s;
+ if (FST_UNLIKELY(bits > xc->outval_alloc_siz))
+ {
+ xc->outval_alloc_siz = bits*2 + 1;
+ xc->outval_mem = (unsigned char*)realloc(xc->outval_mem, xc->outval_alloc_siz);
+ if (FST_UNLIKELY(!xc->outval_mem))
+ {
+ fprintf(stderr,
+ FST_APIMESS "Could not realloc() in fstWriterEmitValueChangeVec32, exiting.\n");
+ exit(255);
+ }
+ }
+ s = xc->outval_mem;
+ {
+ w = bq;
+ v = val[w];
+ for (i = 0; i < br; ++i)
+ {
+ *s++ = '0' + ((v >> (br - i - 1)) & 1);
+ }
+ }
+ for (w = bq - 1; w >= 0; --w)
+ {
+ v = val[w];
+ for (i = (32 - 4); i >= 0; i -= 4) {
+ s[0] = '0' + ((v >> (i + 3)) & 1);
+ s[1] = '0' + ((v >> (i + 2)) & 1);
+ s[2] = '0' + ((v >> (i + 1)) & 1);
+ s[3] = '0' + ((v >> (i + 0)) & 1);
+ s += 4;
+ }
+ }
+ fstWriterEmitValueChange(ctx, handle, xc->outval_mem);
+ }
+}
+void fstWriterEmitValueChangeVec64(void *ctx, fstHandle handle,
+ uint32_t bits, const uint64_t *val) {
+ struct fstWriterContext *xc = (struct fstWriterContext *)ctx;
+ if (FST_UNLIKELY(bits <= 64))
+ {
+ fstWriterEmitValueChange64(ctx, handle, bits, val[0]);
+ }
+ else if(FST_LIKELY(xc))
+ {
+ int bq = bits / 64;
+ int br = bits & 63;
+ int i;
+ int w;
+ uint32_t v;
+ unsigned char* s;
+ if (FST_UNLIKELY(bits > xc->outval_alloc_siz))
+ {
+ xc->outval_alloc_siz = bits*2 + 1;
+ xc->outval_mem = (unsigned char*)realloc(xc->outval_mem, xc->outval_alloc_siz);
+ if (FST_UNLIKELY(!xc->outval_mem))
+ {
+ fprintf(stderr,
+ FST_APIMESS "Could not realloc() in fstWriterEmitValueChangeVec64, exiting.\n");
+ exit(255);
+ }
+ }
+ s = xc->outval_mem;
+ {
+ w = bq;
+ v = val[w];
+ for (i = 0; i < br; ++i)
+ {
+ *s++ = '0' + ((v >> (br - i - 1)) & 1);
+ }
+ }
+ for (w = bq - 1; w >= 0; --w) {
+ v = val[w];
+ for (i = (64 - 4); i >= 0; i -= 4)
+ {
+ s[0] = '0' + ((v >> (i + 3)) & 1);
+ s[1] = '0' + ((v >> (i + 2)) & 1);
+ s[2] = '0' + ((v >> (i + 1)) & 1);
+ s[3] = '0' + ((v >> (i + 0)) & 1);
+ s += 4;
+ }
+ }
+ fstWriterEmitValueChange(ctx, handle, xc->outval_mem);
+ }
+}
+
+
+void fstWriterEmitVariableLengthValueChange(void *ctx, fstHandle handle, const void *val, uint32_t len)
+{
+struct fstWriterContext *xc = (struct fstWriterContext *)ctx;
+const unsigned char *buf = (const unsigned char *)val;
+
+if(FST_LIKELY((xc) && (handle <= xc->maxhandle)))
+ {
+ uint32_t fpos;
+ uint32_t *vm4ip;
+
+ if(FST_UNLIKELY(!xc->valpos_mem))
+ {
+ xc->vc_emitted = 1;
+ fstWriterCreateMmaps(xc);
+ }
+
+ handle--; /* move starting at 1 index to starting at 0 */
+ vm4ip = &(xc->valpos_mem[4*handle]);
+
+ /* there is no initial time dump for variable length value changes */
+ if(FST_LIKELY(!vm4ip[1])) /* len of zero = variable length */
+ {
+ fpos = xc->vchg_siz;
+
+ if(FST_UNLIKELY((fpos + len + 10 + 5) > xc->vchg_alloc_siz))
+ {
+ xc->vchg_alloc_siz += (xc->fst_break_add_size + len + 5); /* +len added in the case of extremely long vectors and small break add sizes */
+ xc->vchg_mem = (unsigned char *)realloc(xc->vchg_mem, xc->vchg_alloc_siz);
+ if(FST_UNLIKELY(!xc->vchg_mem))
+ {
+ fprintf(stderr, FST_APIMESS "Could not realloc() in fstWriterEmitVariableLengthValueChange, exiting.\n");
+ exit(255);
+ }
+ }
+
+ xc->vchg_siz += fstWriterUint32WithVarint32AndLength(xc, &vm4ip[2], xc->tchn_idx - vm4ip[3], buf, len); /* do one fwrite op only */
+ vm4ip[3] = xc->tchn_idx;
+ vm4ip[2] = fpos;
+ }
+ }
+}
+
+
+void fstWriterEmitTimeChange(void *ctx, uint64_t tim)
+{
+struct fstWriterContext *xc = (struct fstWriterContext *)ctx;
+unsigned int i;
+int skip = 0;
+if(xc)
+ {
+ if(FST_UNLIKELY(xc->is_initial_time))
+ {
+ if(xc->size_limit_locked) /* this resets xc->is_initial_time to one */
+ {
+ return;
+ }
+
+ if(!xc->valpos_mem)
+ {
+ fstWriterCreateMmaps(xc);
+ }
+
+ skip = 1;
+
+ xc->firsttime = (xc->vc_emitted) ? 0: tim;
+ xc->curtime = 0;
+ xc->vchg_mem[0] = '!';
+ xc->vchg_siz = 1;
+ fstWriterEmitSectionHeader(xc);
+ for(i=0;imaxhandle;i++)
+ {
+ xc->valpos_mem[4*i+2] = 0; /* zero out offset val */
+ xc->valpos_mem[4*i+3] = 0; /* zero out last time change val */
+ }
+ xc->is_initial_time = 0;
+ }
+ else
+ {
+ if((xc->vchg_siz >= xc->fst_break_size) || (xc->flush_context_pending))
+ {
+ xc->flush_context_pending = 0;
+ fstWriterFlushContextPrivate(xc);
+ xc->tchn_cnt++;
+ fstWriterVarint(xc->tchn_handle, xc->curtime);
+ }
+ }
+
+ if(!skip)
+ {
+ xc->tchn_idx++;
+ }
+ fstWriterVarint(xc->tchn_handle, tim - xc->curtime);
+ xc->tchn_cnt++;
+ xc->curtime = tim;
+ }
+}
+
+
+void fstWriterEmitDumpActive(void *ctx, int enable)
+{
+struct fstWriterContext *xc = (struct fstWriterContext *)ctx;
+
+if(xc)
+ {
+ struct fstBlackoutChain *b = (struct fstBlackoutChain *)calloc(1, sizeof(struct fstBlackoutChain));
+
+ b->tim = xc->curtime;
+ b->active = (enable != 0);
+
+ xc->num_blackouts++;
+ if(xc->blackout_curr)
+ {
+ xc->blackout_curr->next = b;
+ xc->blackout_curr = b;
+ }
+ else
+ {
+ xc->blackout_head = b;
+ xc->blackout_curr = b;
+ }
+ }
+}
+
+
+/***********************/
+/*** ***/
+/*** reader function ***/
+/*** ***/
+/***********************/
+
+/*
+ * private structs
+ */
+static const char *vartypes[] = {
+ "event", "integer", "parameter", "real", "real_parameter",
+ "reg", "supply0", "supply1", "time", "tri",
+ "triand", "trior", "trireg", "tri0", "tri1",
+ "wand", "wire", "wor", "port", "sparray", "realtime",
+ "string",
+ "bit", "logic", "int", "shortint", "longint", "byte", "enum", "shortreal"
+ };
+
+static const char *modtypes[] = {
+ "module", "task", "function", "begin", "fork", "generate", "struct", "union", "class", "interface", "package", "program",
+ "vhdl_architecture", "vhdl_procedure", "vhdl_function", "vhdl_record", "vhdl_process", "vhdl_block", "vhdl_for_generate", "vhdl_if_generate", "vhdl_generate", "vhdl_package"
+ };
+
+static const char *attrtypes[] = {
+ "misc", "array", "enum", "class"
+ };
+
+static const char *arraytypes[] = {
+ "none", "unpacked", "packed", "sparse"
+ };
+
+static const char *enumvaluetypes[] = {
+ "integer", "bit", "logic", "int", "shortint", "longint", "byte",
+ "unsigned_integer", "unsigned_bit", "unsigned_logic", "unsigned_int", "unsigned_shortint", "unsigned_longint", "unsigned_byte"
+ };
+
+static const char *packtypes[] = {
+ "none", "unpacked", "packed", "tagged_packed"
+ };
+
+
+struct fstCurrHier
+{
+struct fstCurrHier *prev;
+void *user_info;
+int len;
+};
+
+
+struct fstReaderContext
+{
+/* common entries */
+
+FILE *f, *fh;
+
+uint64_t start_time, end_time;
+uint64_t mem_used_by_writer;
+uint64_t scope_count;
+uint64_t var_count;
+fstHandle maxhandle;
+uint64_t num_alias;
+uint64_t vc_section_count;
+
+uint32_t *signal_lens; /* maxhandle sized */
+unsigned char *signal_typs; /* maxhandle sized */
+unsigned char *process_mask; /* maxhandle-based, bitwise sized */
+uint32_t longest_signal_value_len; /* longest len value encountered */
+unsigned char *temp_signal_value_buf; /* malloced for len in longest_signal_value_len */
+
+signed char timescale;
+unsigned char filetype;
+
+unsigned use_vcd_extensions : 1;
+unsigned double_endian_match : 1;
+unsigned native_doubles_for_cb : 1;
+unsigned contains_geom_section : 1;
+unsigned contains_hier_section : 1; /* valid for hier_pos */
+unsigned contains_hier_section_lz4duo : 1; /* valid for hier_pos (contains_hier_section_lz4 always also set) */
+unsigned contains_hier_section_lz4 : 1; /* valid for hier_pos */
+unsigned limit_range_valid : 1; /* valid for limit_range_start, limit_range_end */
+
+char version[FST_HDR_SIM_VERSION_SIZE + 1];
+char date[FST_HDR_DATE_SIZE + 1];
+int64_t timezero;
+
+char *filename, *filename_unpacked;
+fst_off_t hier_pos;
+
+uint32_t num_blackouts;
+uint64_t *blackout_times;
+unsigned char *blackout_activity;
+
+uint64_t limit_range_start, limit_range_end;
+
+/* entries specific to read value at time functions */
+
+unsigned rvat_data_valid : 1;
+uint64_t *rvat_time_table;
+uint64_t rvat_beg_tim, rvat_end_tim;
+unsigned char *rvat_frame_data;
+uint64_t rvat_frame_maxhandle;
+fst_off_t *rvat_chain_table;
+uint32_t *rvat_chain_table_lengths;
+uint64_t rvat_vc_maxhandle;
+fst_off_t rvat_vc_start;
+uint32_t *rvat_sig_offs;
+int rvat_packtype;
+
+uint32_t rvat_chain_len;
+unsigned char *rvat_chain_mem;
+fstHandle rvat_chain_facidx;
+
+uint32_t rvat_chain_pos_tidx;
+uint32_t rvat_chain_pos_idx;
+uint64_t rvat_chain_pos_time;
+unsigned rvat_chain_pos_valid : 1;
+
+/* entries specific to hierarchy traversal */
+
+struct fstHier hier;
+struct fstCurrHier *curr_hier;
+fstHandle current_handle;
+char *curr_flat_hier_nam;
+int flat_hier_alloc_len;
+unsigned do_rewind : 1;
+char str_scope_nam[FST_ID_NAM_SIZ+1];
+char str_scope_comp[FST_ID_NAM_SIZ+1];
+
+unsigned fseek_failed : 1;
+
+/* self-buffered I/O for writes */
+
+#ifndef FST_WRITEX_DISABLE
+int writex_pos;
+int writex_fd;
+unsigned char writex_buf[FST_WRITEX_MAX];
+#endif
+
+char *f_nam;
+char *fh_nam;
+};
+
+
+int fstReaderFseeko(struct fstReaderContext *xc, FILE *stream, fst_off_t offset, int whence)
+{
+int rc = fseeko(stream, offset, whence);
+
+if(rc<0)
+ {
+ xc->fseek_failed = 1;
+#ifdef FST_DEBUG
+ fprintf(stderr, FST_APIMESS "Seek to #%" PRId64 " (whence = %d) failed!\n", offset, whence);
+ perror("Why");
+#endif
+ }
+
+return(rc);
+}
+
+
+#ifndef FST_WRITEX_DISABLE
+static void fstWritex(struct fstReaderContext *xc, void *v, int len)
+{
+unsigned char *s = (unsigned char *)v;
+
+if(len)
+ {
+ if(len < FST_WRITEX_MAX)
+ {
+ if(xc->writex_pos + len >= FST_WRITEX_MAX)
+ {
+ fstWritex(xc, NULL, 0);
+ }
+
+ memcpy(xc->writex_buf + xc->writex_pos, s, len);
+ xc->writex_pos += len;
+ }
+ else
+ {
+ fstWritex(xc, NULL, 0);
+ if (write(xc->writex_fd, s, len)) { };
+ }
+ }
+ else
+ {
+ if(xc->writex_pos)
+ {
+ if(write(xc->writex_fd, xc->writex_buf, xc->writex_pos)) { };
+ xc->writex_pos = 0;
+ }
+ }
+}
+#endif
+
+
+/*
+ * scope -> flat name handling
+ */
+static void fstReaderDeallocateScopeData(struct fstReaderContext *xc)
+{
+struct fstCurrHier *chp;
+
+free(xc->curr_flat_hier_nam); xc->curr_flat_hier_nam = NULL;
+while(xc->curr_hier)
+ {
+ chp = xc->curr_hier->prev;
+ free(xc->curr_hier);
+ xc->curr_hier = chp;
+ }
+}
+
+
+const char *fstReaderGetCurrentFlatScope(void *ctx)
+{
+struct fstReaderContext *xc = (struct fstReaderContext *)ctx;
+if(xc)
+ {
+ return(xc->curr_flat_hier_nam ? xc->curr_flat_hier_nam : "");
+ }
+ else
+ {
+ return(NULL);
+ }
+}
+
+
+void *fstReaderGetCurrentScopeUserInfo(void *ctx)
+{
+struct fstReaderContext *xc = (struct fstReaderContext *)ctx;
+if(xc)
+ {
+ return(xc->curr_hier ? xc->curr_hier->user_info : NULL);
+ }
+ else
+ {
+ return(NULL);
+ }
+}
+
+
+const char *fstReaderPopScope(void *ctx)
+{
+struct fstReaderContext *xc = (struct fstReaderContext *)ctx;
+if(xc && xc->curr_hier)
+ {
+ struct fstCurrHier *ch = xc->curr_hier;
+ if(xc->curr_hier->prev)
+ {
+ xc->curr_flat_hier_nam[xc->curr_hier->prev->len] = 0;
+ }
+ else
+ {
+ *xc->curr_flat_hier_nam = 0;
+ }
+ xc->curr_hier = xc->curr_hier->prev;
+ free(ch);
+ return(xc->curr_flat_hier_nam ? xc->curr_flat_hier_nam : "");
+ }
+
+return(NULL);
+}
+
+
+void fstReaderResetScope(void *ctx)
+{
+struct fstReaderContext *xc = (struct fstReaderContext *)ctx;
+
+if(xc)
+ {
+ while(fstReaderPopScope(xc)); /* remove any already-built scoping info */
+ }
+}
+
+
+const char *fstReaderPushScope(void *ctx, const char *nam, void *user_info)
+{
+struct fstReaderContext *xc = (struct fstReaderContext *)ctx;
+if(xc)
+ {
+ struct fstCurrHier *ch = (struct fstCurrHier *)malloc(sizeof(struct fstCurrHier));
+ int chl = xc->curr_hier ? xc->curr_hier->len : 0;
+ int len = chl + 1 + strlen(nam);
+ if(len >= xc->flat_hier_alloc_len)
+ {
+ xc->curr_flat_hier_nam = xc->curr_flat_hier_nam ? (char *)realloc(xc->curr_flat_hier_nam, len+1) : (char *)malloc(len+1);
+ }
+
+ if(chl)
+ {
+ xc->curr_flat_hier_nam[chl] = '.';
+ strcpy(xc->curr_flat_hier_nam + chl + 1, nam);
+ }
+ else
+ {
+ strcpy(xc->curr_flat_hier_nam, nam);
+ len--;
+ }
+
+ ch->len = len;
+ ch->prev = xc->curr_hier;
+ ch->user_info = user_info;
+ xc->curr_hier = ch;
+ return(xc->curr_flat_hier_nam);
+ }
+
+return(NULL);
+}
+
+
+int fstReaderGetCurrentScopeLen(void *ctx)
+{
+struct fstReaderContext *xc = (struct fstReaderContext *)ctx;
+
+if(xc && xc->curr_hier)
+ {
+ return(xc->curr_hier->len);
+ }
+
+return(0);
+}
+
+
+int fstReaderGetFseekFailed(void *ctx)
+{
+struct fstReaderContext *xc = (struct fstReaderContext *)ctx;
+if(xc)
+ {
+ return(xc->fseek_failed != 0);
+ }
+
+return(0);
+}
+
+
+/*
+ * iter mask manipulation util functions
+ */
+int fstReaderGetFacProcessMask(void *ctx, fstHandle facidx)
+{
+struct fstReaderContext *xc = (struct fstReaderContext *)ctx;
+
+if(xc)
+ {
+ facidx--;
+ if(facidxmaxhandle)
+ {
+ int process_idx = facidx/8;
+ int process_bit = facidx&7;
+
+ return( (xc->process_mask[process_idx]&(1<maxhandle)
+ {
+ int idx = facidx/8;
+ int bitpos = facidx&7;
+
+ xc->process_mask[idx] |= (1<maxhandle)
+ {
+ int idx = facidx/8;
+ int bitpos = facidx&7;
+
+ xc->process_mask[idx] &= (~(1<process_mask, 0xff, (xc->maxhandle+7)/8);
+ }
+}
+
+
+void fstReaderClrFacProcessMaskAll(void *ctx)
+{
+struct fstReaderContext *xc = (struct fstReaderContext *)ctx;
+
+if(xc)
+ {
+ memset(xc->process_mask, 0x00, (xc->maxhandle+7)/8);
+ }
+}
+
+
+/*
+ * various utility read/write functions
+ */
+signed char fstReaderGetTimescale(void *ctx)
+{
+struct fstReaderContext *xc = (struct fstReaderContext *)ctx;
+return(xc ? xc->timescale : 0);
+}
+
+
+uint64_t fstReaderGetStartTime(void *ctx)
+{
+struct fstReaderContext *xc = (struct fstReaderContext *)ctx;
+return(xc ? xc->start_time : 0);
+}
+
+
+uint64_t fstReaderGetEndTime(void *ctx)
+{
+struct fstReaderContext *xc = (struct fstReaderContext *)ctx;
+return(xc ? xc->end_time : 0);
+}
+
+
+uint64_t fstReaderGetMemoryUsedByWriter(void *ctx)
+{
+struct fstReaderContext *xc = (struct fstReaderContext *)ctx;
+return(xc ? xc->mem_used_by_writer : 0);
+}
+
+
+uint64_t fstReaderGetScopeCount(void *ctx)
+{
+struct fstReaderContext *xc = (struct fstReaderContext *)ctx;
+return(xc ? xc->scope_count : 0);
+}
+
+
+uint64_t fstReaderGetVarCount(void *ctx)
+{
+struct fstReaderContext *xc = (struct fstReaderContext *)ctx;
+return(xc ? xc->var_count : 0);
+}
+
+
+fstHandle fstReaderGetMaxHandle(void *ctx)
+{
+struct fstReaderContext *xc = (struct fstReaderContext *)ctx;
+return(xc ? xc->maxhandle : 0);
+}
+
+
+uint64_t fstReaderGetAliasCount(void *ctx)
+{
+struct fstReaderContext *xc = (struct fstReaderContext *)ctx;
+return(xc ? xc->num_alias : 0);
+}
+
+
+uint64_t fstReaderGetValueChangeSectionCount(void *ctx)
+{
+struct fstReaderContext *xc = (struct fstReaderContext *)ctx;
+return(xc ? xc->vc_section_count : 0);
+}
+
+
+int fstReaderGetDoubleEndianMatchState(void *ctx)
+{
+struct fstReaderContext *xc = (struct fstReaderContext *)ctx;
+return(xc ? xc->double_endian_match : 0);
+}
+
+
+const char *fstReaderGetVersionString(void *ctx)
+{
+struct fstReaderContext *xc = (struct fstReaderContext *)ctx;
+return(xc ? xc->version : NULL);
+}
+
+
+const char *fstReaderGetDateString(void *ctx)
+{
+struct fstReaderContext *xc = (struct fstReaderContext *)ctx;
+return(xc ? xc->date : NULL);
+}
+
+
+int fstReaderGetFileType(void *ctx)
+{
+struct fstReaderContext *xc = (struct fstReaderContext *)ctx;
+return(xc ? (int)xc->filetype : (int)FST_FT_VERILOG);
+}
+
+
+int64_t fstReaderGetTimezero(void *ctx)
+{
+struct fstReaderContext *xc = (struct fstReaderContext *)ctx;
+return(xc ? xc->timezero : 0);
+}
+
+
+uint32_t fstReaderGetNumberDumpActivityChanges(void *ctx)
+{
+struct fstReaderContext *xc = (struct fstReaderContext *)ctx;
+return(xc ? xc->num_blackouts : 0);
+}
+
+
+uint64_t fstReaderGetDumpActivityChangeTime(void *ctx, uint32_t idx)
+{
+struct fstReaderContext *xc = (struct fstReaderContext *)ctx;
+
+if(xc && (idx < xc->num_blackouts) && (xc->blackout_times))
+ {
+ return(xc->blackout_times[idx]);
+ }
+ else
+ {
+ return(0);
+ }
+}
+
+
+unsigned char fstReaderGetDumpActivityChangeValue(void *ctx, uint32_t idx)
+{
+struct fstReaderContext *xc = (struct fstReaderContext *)ctx;
+
+if(xc && (idx < xc->num_blackouts) && (xc->blackout_activity))
+ {
+ return(xc->blackout_activity[idx]);
+ }
+ else
+ {
+ return(0);
+ }
+}
+
+
+void fstReaderSetLimitTimeRange(void *ctx, uint64_t start_time, uint64_t end_time)
+{
+struct fstReaderContext *xc = (struct fstReaderContext *)ctx;
+
+if(xc)
+ {
+ xc->limit_range_valid = 1;
+ xc->limit_range_start = start_time;
+ xc->limit_range_end = end_time;
+ }
+}
+
+
+void fstReaderSetUnlimitedTimeRange(void *ctx)
+{
+struct fstReaderContext *xc = (struct fstReaderContext *)ctx;
+
+if(xc)
+ {
+ xc->limit_range_valid = 0;
+ }
+}
+
+
+void fstReaderSetVcdExtensions(void *ctx, int enable)
+{
+struct fstReaderContext *xc = (struct fstReaderContext *)ctx;
+
+if(xc)
+ {
+ xc->use_vcd_extensions = (enable != 0);
+ }
+}
+
+
+void fstReaderIterBlocksSetNativeDoublesOnCallback(void *ctx, int enable)
+{
+struct fstReaderContext *xc = (struct fstReaderContext *)ctx;
+if(xc)
+ {
+ xc->native_doubles_for_cb = (enable != 0);
+ }
+}
+
+/*
+ * hierarchy processing
+ */
+static void fstVcdID(char *buf, unsigned int value)
+{
+char *pnt = buf;
+
+/* zero is illegal for a value...it is assumed they start at one */
+while (value)
+ {
+ value--;
+ *(pnt++) = (char)('!' + value % 94);
+ value = value / 94;
+ }
+
+*pnt = 0;
+}
+
+static int fstVcdIDForFwrite(char *buf, unsigned int value)
+{
+char *pnt = buf;
+
+/* zero is illegal for a value...it is assumed they start at one */
+while (value)
+ {
+ value--;
+ *(pnt++) = (char)('!' + value % 94);
+ value = value / 94;
+ }
+
+return(pnt - buf);
+}
+
+
+static int fstReaderRecreateHierFile(struct fstReaderContext *xc)
+{
+int pass_status = 1;
+
+if(!xc->fh)
+ {
+ fst_off_t offs_cache = ftello(xc->f);
+ char *fnam = (char *)malloc(strlen(xc->filename) + 6 + 16 + 32 + 1);
+ unsigned char *mem = (unsigned char *)malloc(FST_GZIO_LEN);
+ fst_off_t hl, uclen;
+ fst_off_t clen = 0;
+ gzFile zhandle = NULL;
+ int zfd;
+ int htyp = FST_BL_SKIP;
+
+ /* can't handle both set at once should never happen in a real file */
+ if(!xc->contains_hier_section_lz4 && xc->contains_hier_section)
+ {
+ htyp = FST_BL_HIER;
+ }
+ else
+ if(xc->contains_hier_section_lz4 && !xc->contains_hier_section)
+ {
+ htyp = xc->contains_hier_section_lz4duo ? FST_BL_HIER_LZ4DUO : FST_BL_HIER_LZ4;
+ }
+
+ sprintf(fnam, "%s.hier_%d_%p", xc->filename, getpid(), (void *)xc);
+ fstReaderFseeko(xc, xc->f, xc->hier_pos, SEEK_SET);
+ uclen = fstReaderUint64(xc->f);
+#ifndef __MINGW32__
+ fflush(xc->f);
+#endif
+ if(htyp == FST_BL_HIER)
+ {
+ fstReaderFseeko(xc, xc->f, xc->hier_pos, SEEK_SET);
+ uclen = fstReaderUint64(xc->f);
+#ifndef __MINGW32__
+ fflush(xc->f);
+#endif
+ zfd = dup(fileno(xc->f));
+ zhandle = gzdopen(zfd, "rb");
+ if(!zhandle)
+ {
+ close(zfd);
+ free(mem);
+ free(fnam);
+ return(0);
+ }
+ }
+ else
+ if((htyp == FST_BL_HIER_LZ4) || (htyp == FST_BL_HIER_LZ4DUO))
+ {
+ fstReaderFseeko(xc, xc->f, xc->hier_pos - 8, SEEK_SET); /* get section len */
+ clen = fstReaderUint64(xc->f) - 16;
+ uclen = fstReaderUint64(xc->f);
+#ifndef __MINGW32__
+ fflush(xc->f);
+#endif
+ }
+
+#ifndef __MINGW32__
+ xc->fh = fopen(fnam, "w+b");
+ if(!xc->fh)
+#endif
+ {
+ xc->fh = tmpfile_open(&xc->fh_nam);
+ free(fnam); fnam = NULL;
+ if(!xc->fh)
+ {
+ tmpfile_close(&xc->fh, &xc->fh_nam);
+ free(mem);
+ return(0);
+ }
+ }
+
+#ifndef __MINGW32__
+ if(fnam) unlink(fnam);
+#endif
+
+ if(htyp == FST_BL_HIER)
+ {
+ for(hl = 0; hl < uclen; hl += FST_GZIO_LEN)
+ {
+ size_t len = ((uclen - hl) > FST_GZIO_LEN) ? FST_GZIO_LEN : (uclen - hl);
+ size_t gzreadlen = gzread(zhandle, mem, len); /* rc should equal len... */
+ size_t fwlen;
+
+ if(gzreadlen != len)
+ {
+ pass_status = 0;
+ break;
+ }
+
+ fwlen = fstFwrite(mem, len, 1, xc->fh);
+ if(fwlen != 1)
+ {
+ pass_status = 0;
+ break;
+ }
+ }
+ gzclose(zhandle);
+ }
+ else
+ if(htyp == FST_BL_HIER_LZ4DUO)
+ {
+ unsigned char *lz4_cmem = (unsigned char *)malloc(clen);
+ unsigned char *lz4_ucmem = (unsigned char *)malloc(uclen);
+ unsigned char *lz4_ucmem2;
+ uint64_t uclen2;
+ int skiplen2 = 0;
+
+ fstFread(lz4_cmem, clen, 1, xc->f);
+
+ uclen2 = fstGetVarint64(lz4_cmem, &skiplen2);
+ lz4_ucmem2 = (unsigned char *)malloc(uclen2);
+ pass_status = (uclen2 == (uint64_t)LZ4_decompress_safe_partial ((char *)lz4_cmem + skiplen2, (char *)lz4_ucmem2, clen - skiplen2, uclen2, uclen2));
+ if(pass_status)
+ {
+ pass_status = (uclen == LZ4_decompress_safe_partial ((char *)lz4_ucmem2, (char *)lz4_ucmem, uclen2, uclen, uclen));
+
+ if(fstFwrite(lz4_ucmem, uclen, 1, xc->fh) != 1)
+ {
+ pass_status = 0;
+ }
+ }
+
+ free(lz4_ucmem2);
+ free(lz4_ucmem);
+ free(lz4_cmem);
+ }
+ else
+ if(htyp == FST_BL_HIER_LZ4)
+ {
+ unsigned char *lz4_cmem = (unsigned char *)malloc(clen);
+ unsigned char *lz4_ucmem = (unsigned char *)malloc(uclen);
+
+ fstFread(lz4_cmem, clen, 1, xc->f);
+ pass_status = (uclen == LZ4_decompress_safe_partial ((char *)lz4_cmem, (char *)lz4_ucmem, clen, uclen, uclen));
+
+ if(fstFwrite(lz4_ucmem, uclen, 1, xc->fh) != 1)
+ {
+ pass_status = 0;
+ }
+
+ free(lz4_ucmem);
+ free(lz4_cmem);
+ }
+ else /* FST_BL_SKIP */
+ {
+ pass_status = 0;
+ if(xc->fh)
+ {
+ fclose(xc->fh); xc->fh = NULL; /* needed in case .hier file is missing and there are no hier sections */
+ }
+ }
+
+ free(mem);
+ free(fnam);
+
+ fstReaderFseeko(xc, xc->f, offs_cache, SEEK_SET);
+ }
+
+return(pass_status);
+}
+
+
+int fstReaderIterateHierRewind(void *ctx)
+{
+struct fstReaderContext *xc = (struct fstReaderContext *)ctx;
+int pass_status = 0;
+
+if(xc)
+ {
+ pass_status = 1;
+ if(!xc->fh)
+ {
+ pass_status = fstReaderRecreateHierFile(xc);
+ }
+
+ xc->do_rewind = 1;
+ }
+
+return(pass_status);
+}
+
+
+struct fstHier *fstReaderIterateHier(void *ctx)
+{
+struct fstReaderContext *xc = (struct fstReaderContext *)ctx;
+int isfeof;
+fstHandle alias;
+char *pnt;
+int ch;
+
+if(!xc) return(NULL);
+
+if(!xc->fh)
+ {
+ if(!fstReaderRecreateHierFile(xc))
+ {
+ return(NULL);
+ }
+ }
+
+if(xc->do_rewind)
+ {
+ xc->do_rewind = 0;
+ xc->current_handle = 0;
+ fstReaderFseeko(xc, xc->fh, 0, SEEK_SET);
+ clearerr(xc->fh);
+ }
+
+if(!(isfeof=feof(xc->fh)))
+ {
+ int tag = fgetc(xc->fh);
+ switch(tag)
+ {
+ case FST_ST_VCD_SCOPE:
+ xc->hier.htyp = FST_HT_SCOPE;
+ xc->hier.u.scope.typ = fgetc(xc->fh);
+ xc->hier.u.scope.name = pnt = xc->str_scope_nam;
+ while((ch = fgetc(xc->fh)))
+ {
+ *(pnt++) = ch;
+ }; /* scopename */
+ *pnt = 0;
+ xc->hier.u.scope.name_length = pnt - xc->hier.u.scope.name;
+
+ xc->hier.u.scope.component = pnt = xc->str_scope_comp;
+ while((ch = fgetc(xc->fh)))
+ {
+ *(pnt++) = ch;
+ }; /* scopecomp */
+ *pnt = 0;
+ xc->hier.u.scope.component_length = pnt - xc->hier.u.scope.component;
+ break;
+
+ case FST_ST_VCD_UPSCOPE:
+ xc->hier.htyp = FST_HT_UPSCOPE;
+ break;
+
+ case FST_ST_GEN_ATTRBEGIN:
+ xc->hier.htyp = FST_HT_ATTRBEGIN;
+ xc->hier.u.attr.typ = fgetc(xc->fh);
+ xc->hier.u.attr.subtype = fgetc(xc->fh);
+ xc->hier.u.attr.name = pnt = xc->str_scope_nam;
+ while((ch = fgetc(xc->fh)))
+ {
+ *(pnt++) = ch;
+ }; /* scopename */
+ *pnt = 0;
+ xc->hier.u.attr.name_length = pnt - xc->hier.u.scope.name;
+
+ xc->hier.u.attr.arg = fstReaderVarint64(xc->fh);
+
+ if(xc->hier.u.attr.typ == FST_AT_MISC)
+ {
+ if((xc->hier.u.attr.subtype == FST_MT_SOURCESTEM)||(xc->hier.u.attr.subtype == FST_MT_SOURCEISTEM))
+ {
+ int sidx_skiplen_dummy = 0;
+ xc->hier.u.attr.arg_from_name = fstGetVarint64((unsigned char *)xc->str_scope_nam, &sidx_skiplen_dummy);
+ }
+ }
+ break;
+
+ case FST_ST_GEN_ATTREND:
+ xc->hier.htyp = FST_HT_ATTREND;
+ break;
+
+ case FST_VT_VCD_EVENT:
+ case FST_VT_VCD_INTEGER:
+ case FST_VT_VCD_PARAMETER:
+ case FST_VT_VCD_REAL:
+ case FST_VT_VCD_REAL_PARAMETER:
+ case FST_VT_VCD_REG:
+ case FST_VT_VCD_SUPPLY0:
+ case FST_VT_VCD_SUPPLY1:
+ case FST_VT_VCD_TIME:
+ case FST_VT_VCD_TRI:
+ case FST_VT_VCD_TRIAND:
+ case FST_VT_VCD_TRIOR:
+ case FST_VT_VCD_TRIREG:
+ case FST_VT_VCD_TRI0:
+ case FST_VT_VCD_TRI1:
+ case FST_VT_VCD_WAND:
+ case FST_VT_VCD_WIRE:
+ case FST_VT_VCD_WOR:
+ case FST_VT_VCD_PORT:
+ case FST_VT_VCD_SPARRAY:
+ case FST_VT_VCD_REALTIME:
+ case FST_VT_GEN_STRING:
+ case FST_VT_SV_BIT:
+ case FST_VT_SV_LOGIC:
+ case FST_VT_SV_INT:
+ case FST_VT_SV_SHORTINT:
+ case FST_VT_SV_LONGINT:
+ case FST_VT_SV_BYTE:
+ case FST_VT_SV_ENUM:
+ case FST_VT_SV_SHORTREAL:
+ xc->hier.htyp = FST_HT_VAR;
+ xc->hier.u.var.svt_workspace = FST_SVT_NONE;
+ xc->hier.u.var.sdt_workspace = FST_SDT_NONE;
+ xc->hier.u.var.sxt_workspace = 0;
+ xc->hier.u.var.typ = tag;
+ xc->hier.u.var.direction = fgetc(xc->fh);
+ xc->hier.u.var.name = pnt = xc->str_scope_nam;
+ while((ch = fgetc(xc->fh)))
+ {
+ *(pnt++) = ch;
+ }; /* varname */
+ *pnt = 0;
+ xc->hier.u.var.name_length = pnt - xc->hier.u.var.name;
+ xc->hier.u.var.length = fstReaderVarint32(xc->fh);
+ if(tag == FST_VT_VCD_PORT)
+ {
+ xc->hier.u.var.length -= 2; /* removal of delimiting spaces */
+ xc->hier.u.var.length /= 3; /* port -> signal size adjust */
+ }
+
+ alias = fstReaderVarint32(xc->fh);
+
+ if(!alias)
+ {
+ xc->current_handle++;
+ xc->hier.u.var.handle = xc->current_handle;
+ xc->hier.u.var.is_alias = 0;
+ }
+ else
+ {
+ xc->hier.u.var.handle = alias;
+ xc->hier.u.var.is_alias = 1;
+ }
+
+ break;
+
+ default:
+ isfeof = 1;
+ break;
+ }
+ }
+
+return(!isfeof ? &xc->hier : NULL);
+}
+
+
+int fstReaderProcessHier(void *ctx, FILE *fv)
+{
+struct fstReaderContext *xc = (struct fstReaderContext *)ctx;
+char *str;
+char *pnt;
+int ch, scopetype;
+int vartype;
+uint32_t len, alias;
+/* uint32_t maxvalpos=0; */
+unsigned int num_signal_dyn = 65536;
+int attrtype, subtype;
+uint64_t attrarg;
+fstHandle maxhandle_scanbuild;
+
+if(!xc) return(0);
+
+xc->longest_signal_value_len = 32; /* arbitrarily set at 32...this is much longer than an expanded double */
+
+if(!xc->fh)
+ {
+ if(!fstReaderRecreateHierFile(xc))
+ {
+ return(0);
+ }
+ }
+
+str = (char *)malloc(FST_ID_NAM_ATTR_SIZ+1);
+
+if(fv)
+ {
+ char time_dimension[2] = {0, 0};
+ int time_scale = 1;
+
+ fprintf(fv, "$date\n\t%s\n$end\n", xc->date);
+ fprintf(fv, "$version\n\t%s\n$end\n", xc->version);
+ if(xc->timezero) fprintf(fv, "$timezero\n\t%" PRId64 "\n$end\n", xc->timezero);
+
+ switch(xc->timescale)
+ {
+ case 2: time_scale = 100; time_dimension[0] = 0; break;
+ case 1: time_scale = 10; /* fallthrough */
+ case 0: time_dimension[0] = 0; break;
+
+ case -1: time_scale = 100; time_dimension[0] = 'm'; break;
+ case -2: time_scale = 10; /* fallthrough */
+ case -3: time_dimension[0] = 'm'; break;
+
+ case -4: time_scale = 100; time_dimension[0] = 'u'; break;
+ case -5: time_scale = 10; /* fallthrough */
+ case -6: time_dimension[0] = 'u'; break;
+
+ case -10: time_scale = 100; time_dimension[0] = 'p'; break;
+ case -11: time_scale = 10; /* fallthrough */
+ case -12: time_dimension[0] = 'p'; break;
+
+ case -13: time_scale = 100; time_dimension[0] = 'f'; break;
+ case -14: time_scale = 10; /* fallthrough */
+ case -15: time_dimension[0] = 'f'; break;
+
+ case -16: time_scale = 100; time_dimension[0] = 'a'; break;
+ case -17: time_scale = 10; /* fallthrough */
+ case -18: time_dimension[0] = 'a'; break;
+
+ case -19: time_scale = 100; time_dimension[0] = 'z'; break;
+ case -20: time_scale = 10; /* fallthrough */
+ case -21: time_dimension[0] = 'z'; break;
+
+ case -7: time_scale = 100; time_dimension[0] = 'n'; break;
+ case -8: time_scale = 10; /* fallthrough */
+ case -9:
+ default: time_dimension[0] = 'n'; break;
+ }
+
+ if(fv) fprintf(fv, "$timescale\n\t%d%ss\n$end\n", time_scale, time_dimension);
+ }
+
+xc->maxhandle = 0;
+xc->num_alias = 0;
+
+free(xc->signal_lens);
+xc->signal_lens = (uint32_t *)malloc(num_signal_dyn*sizeof(uint32_t));
+
+free(xc->signal_typs);
+xc->signal_typs = (unsigned char *)malloc(num_signal_dyn*sizeof(unsigned char));
+
+fstReaderFseeko(xc, xc->fh, 0, SEEK_SET);
+while(!feof(xc->fh))
+ {
+ int tag = fgetc(xc->fh);
+ switch(tag)
+ {
+ case FST_ST_VCD_SCOPE:
+ scopetype = fgetc(xc->fh);
+ if((scopetype < FST_ST_MIN) || (scopetype > FST_ST_MAX)) scopetype = FST_ST_VCD_MODULE;
+ pnt = str;
+ while((ch = fgetc(xc->fh)))
+ {
+ *(pnt++) = ch;
+ }; /* scopename */
+ *pnt = 0;
+ while(fgetc(xc->fh)) { }; /* scopecomp */
+
+ if(fv) fprintf(fv, "$scope %s %s $end\n", modtypes[scopetype], str);
+ break;
+
+ case FST_ST_VCD_UPSCOPE:
+ if(fv) fprintf(fv, "$upscope $end\n");
+ break;
+
+ case FST_ST_GEN_ATTRBEGIN:
+ attrtype = fgetc(xc->fh);
+ subtype = fgetc(xc->fh);
+ pnt = str;
+ while((ch = fgetc(xc->fh)))
+ {
+ *(pnt++) = ch;
+ }; /* attrname */
+ *pnt = 0;
+
+ if(!str[0]) { strcpy(str, "\"\""); }
+
+ attrarg = fstReaderVarint64(xc->fh);
+
+ if(fv && xc->use_vcd_extensions)
+ {
+ switch(attrtype)
+ {
+ case FST_AT_ARRAY: if((subtype < FST_AR_NONE) || (subtype > FST_AR_MAX)) subtype = FST_AR_NONE;
+ fprintf(fv, "$attrbegin %s %s %s %" PRId64 " $end\n", attrtypes[attrtype], arraytypes[subtype], str, attrarg);
+ break;
+ case FST_AT_ENUM: if((subtype < FST_EV_SV_INTEGER) || (subtype > FST_EV_MAX)) subtype = FST_EV_SV_INTEGER;
+ fprintf(fv, "$attrbegin %s %s %s %" PRId64 " $end\n", attrtypes[attrtype], enumvaluetypes[subtype], str, attrarg);
+ break;
+ case FST_AT_PACK: if((subtype < FST_PT_NONE) || (subtype > FST_PT_MAX)) subtype = FST_PT_NONE;
+ fprintf(fv, "$attrbegin %s %s %s %" PRId64 " $end\n", attrtypes[attrtype], packtypes[subtype], str, attrarg);
+ break;
+ case FST_AT_MISC:
+ default: attrtype = FST_AT_MISC;
+ if(subtype == FST_MT_COMMENT)
+ {
+ fprintf(fv, "$comment\n\t%s\n$end\n", str);
+ }
+ else
+ {
+ if((subtype == FST_MT_SOURCESTEM)||(subtype == FST_MT_SOURCEISTEM))
+ {
+ int sidx_skiplen_dummy = 0;
+ uint64_t sidx = fstGetVarint64((unsigned char *)str, &sidx_skiplen_dummy);
+
+ fprintf(fv, "$attrbegin %s %02x %" PRId64 " %" PRId64 " $end\n", attrtypes[attrtype], subtype, sidx, attrarg);
+ }
+ else
+ {
+ fprintf(fv, "$attrbegin %s %02x %s %" PRId64 " $end\n", attrtypes[attrtype], subtype, str, attrarg);
+ }
+ }
+ break;
+ }
+ }
+ break;
+
+ case FST_ST_GEN_ATTREND:
+ if(fv && xc->use_vcd_extensions) fprintf(fv, "$attrend $end\n");
+ break;
+
+ case FST_VT_VCD_EVENT:
+ case FST_VT_VCD_INTEGER:
+ case FST_VT_VCD_PARAMETER:
+ case FST_VT_VCD_REAL:
+ case FST_VT_VCD_REAL_PARAMETER:
+ case FST_VT_VCD_REG:
+ case FST_VT_VCD_SUPPLY0:
+ case FST_VT_VCD_SUPPLY1:
+ case FST_VT_VCD_TIME:
+ case FST_VT_VCD_TRI:
+ case FST_VT_VCD_TRIAND:
+ case FST_VT_VCD_TRIOR:
+ case FST_VT_VCD_TRIREG:
+ case FST_VT_VCD_TRI0:
+ case FST_VT_VCD_TRI1:
+ case FST_VT_VCD_WAND:
+ case FST_VT_VCD_WIRE:
+ case FST_VT_VCD_WOR:
+ case FST_VT_VCD_PORT:
+ case FST_VT_VCD_SPARRAY:
+ case FST_VT_VCD_REALTIME:
+ case FST_VT_GEN_STRING:
+ case FST_VT_SV_BIT:
+ case FST_VT_SV_LOGIC:
+ case FST_VT_SV_INT:
+ case FST_VT_SV_SHORTINT:
+ case FST_VT_SV_LONGINT:
+ case FST_VT_SV_BYTE:
+ case FST_VT_SV_ENUM:
+ case FST_VT_SV_SHORTREAL:
+ vartype = tag;
+ /* vardir = */ fgetc(xc->fh); /* unused in VCD reader, but need to advance read pointer */
+ pnt = str;
+ while((ch = fgetc(xc->fh)))
+ {
+ *(pnt++) = ch;
+ }; /* varname */
+ *pnt = 0;
+ len = fstReaderVarint32(xc->fh);
+ alias = fstReaderVarint32(xc->fh);
+
+ if(!alias)
+ {
+ if(xc->maxhandle == num_signal_dyn)
+ {
+ num_signal_dyn *= 2;
+ xc->signal_lens = (uint32_t *)realloc(xc->signal_lens, num_signal_dyn*sizeof(uint32_t));
+ xc->signal_typs = (unsigned char *)realloc(xc->signal_typs, num_signal_dyn*sizeof(unsigned char));
+ }
+ xc->signal_lens[xc->maxhandle] = len;
+ xc->signal_typs[xc->maxhandle] = vartype;
+
+ /* maxvalpos+=len; */
+ if(len > xc->longest_signal_value_len)
+ {
+ xc->longest_signal_value_len = len;
+ }
+
+ if((vartype == FST_VT_VCD_REAL) || (vartype == FST_VT_VCD_REAL_PARAMETER) || (vartype == FST_VT_VCD_REALTIME) || (vartype == FST_VT_SV_SHORTREAL))
+ {
+ len = (vartype != FST_VT_SV_SHORTREAL) ? 64 : 32;
+ xc->signal_typs[xc->maxhandle] = FST_VT_VCD_REAL;
+ }
+ if(fv)
+ {
+ char vcdid_buf[16];
+ uint32_t modlen = (vartype != FST_VT_VCD_PORT) ? len : ((len - 2) / 3);
+ fstVcdID(vcdid_buf, xc->maxhandle+1);
+ fprintf(fv, "$var %s %" PRIu32 " %s %s $end\n", vartypes[vartype], modlen, vcdid_buf, str);
+ }
+ xc->maxhandle++;
+ }
+ else
+ {
+ if((vartype == FST_VT_VCD_REAL) || (vartype == FST_VT_VCD_REAL_PARAMETER) || (vartype == FST_VT_VCD_REALTIME) || (vartype == FST_VT_SV_SHORTREAL))
+ {
+ len = (vartype != FST_VT_SV_SHORTREAL) ? 64 : 32;
+ xc->signal_typs[xc->maxhandle] = FST_VT_VCD_REAL;
+ }
+ if(fv)
+ {
+ char vcdid_buf[16];
+ uint32_t modlen = (vartype != FST_VT_VCD_PORT) ? len : ((len - 2) / 3);
+ fstVcdID(vcdid_buf, alias);
+ fprintf(fv, "$var %s %" PRIu32 " %s %s $end\n", vartypes[vartype], modlen, vcdid_buf, str);
+ }
+ xc->num_alias++;
+ }
+
+ break;
+
+ default:
+ break;
+ }
+ }
+if(fv) fprintf(fv, "$enddefinitions $end\n");
+
+maxhandle_scanbuild = xc->maxhandle ? xc->maxhandle : 1; /*scan-build warning suppression, in reality we have at least one signal */
+
+xc->signal_lens = (uint32_t *)realloc(xc->signal_lens, maxhandle_scanbuild*sizeof(uint32_t));
+xc->signal_typs = (unsigned char *)realloc(xc->signal_typs, maxhandle_scanbuild*sizeof(unsigned char));
+
+free(xc->process_mask);
+xc->process_mask = (unsigned char *)calloc(1, (maxhandle_scanbuild+7)/8);
+
+free(xc->temp_signal_value_buf);
+xc->temp_signal_value_buf = (unsigned char *)malloc(xc->longest_signal_value_len + 1);
+
+xc->var_count = xc->maxhandle + xc->num_alias;
+
+free(str);
+return(1);
+}
+
+
+/*
+ * reader file open/close functions
+ */
+int fstReaderInit(struct fstReaderContext *xc)
+{
+fst_off_t blkpos = 0;
+fst_off_t endfile;
+uint64_t seclen;
+int sectype;
+uint64_t vc_section_count_actual = 0;
+int hdr_incomplete = 0;
+int hdr_seen = 0;
+int gzread_pass_status = 1;
+
+sectype = fgetc(xc->f);
+if(sectype == FST_BL_ZWRAPPER)
+ {
+ FILE *fcomp;
+ fst_off_t offpnt, uclen;
+ char gz_membuf[FST_GZIO_LEN];
+ gzFile zhandle;
+ int zfd;
+ int flen = strlen(xc->filename);
+ char *hf;
+
+ seclen = fstReaderUint64(xc->f);
+ uclen = fstReaderUint64(xc->f);
+
+ if(!seclen) return(0); /* not finished compressing, this is a failed read */
+
+ hf = (char *)calloc(1, flen + 16 + 32 + 1);
+
+ sprintf(hf, "%s.upk_%d_%p", xc->filename, getpid(), (void *)xc);
+ fcomp = fopen(hf, "w+b");
+ if(!fcomp)
+ {
+ fcomp = tmpfile_open(&xc->f_nam);
+ free(hf); hf = NULL;
+ if(!fcomp) { tmpfile_close(&fcomp, &xc->f_nam); return(0); }
+ }
+
+#if defined(FST_MACOSX)
+ setvbuf(fcomp, (char *)NULL, _IONBF, 0); /* keeps gzip from acting weird in tandem with fopen */
+#endif
+
+#ifdef __MINGW32__
+ setvbuf(fcomp, (char *)NULL, _IONBF, 0); /* keeps gzip from acting weird in tandem with fopen */
+ xc->filename_unpacked = hf;
+#else
+ if(hf)
+ {
+ unlink(hf);
+ free(hf);
+ }
+#endif
+
+ fstReaderFseeko(xc, xc->f, 1+8+8, SEEK_SET);
+#ifndef __MINGW32__
+ fflush(xc->f);
+#endif
+
+ zfd = dup(fileno(xc->f));
+ zhandle = gzdopen(zfd, "rb");
+ if(zhandle)
+ {
+ for(offpnt = 0; offpnt < uclen; offpnt += FST_GZIO_LEN)
+ {
+ size_t this_len = ((uclen - offpnt) > FST_GZIO_LEN) ? FST_GZIO_LEN : (uclen - offpnt);
+ size_t gzreadlen = gzread(zhandle, gz_membuf, this_len);
+ size_t fwlen;
+
+ if(gzreadlen != this_len)
+ {
+ gzread_pass_status = 0;
+ break;
+ }
+ fwlen = fstFwrite(gz_membuf, this_len, 1, fcomp);
+ if(fwlen != 1)
+ {
+ gzread_pass_status = 0;
+ break;
+ }
+ }
+ gzclose(zhandle);
+ }
+ else
+ {
+ close(zfd);
+ }
+ fflush(fcomp);
+ fclose(xc->f);
+ xc->f = fcomp;
+ }
+
+if(gzread_pass_status)
+ {
+ fstReaderFseeko(xc, xc->f, 0, SEEK_END);
+ endfile = ftello(xc->f);
+
+ while(blkpos < endfile)
+ {
+ fstReaderFseeko(xc, xc->f, blkpos, SEEK_SET);
+
+ sectype = fgetc(xc->f);
+ seclen = fstReaderUint64(xc->f);
+
+ if(sectype == EOF)
+ {
+ break;
+ }
+
+ if((hdr_incomplete) && (!seclen))
+ {
+ break;
+ }
+
+ if(!hdr_seen && (sectype != FST_BL_HDR))
+ {
+ break;
+ }
+
+ blkpos++;
+ if(sectype == FST_BL_HDR)
+ {
+ if(!hdr_seen)
+ {
+ int ch;
+ double dcheck;
+
+ xc->start_time = fstReaderUint64(xc->f);
+ xc->end_time = fstReaderUint64(xc->f);
+
+ hdr_incomplete = (xc->start_time == 0) && (xc->end_time == 0);
+
+ fstFread(&dcheck, 8, 1, xc->f);
+ xc->double_endian_match = (dcheck == FST_DOUBLE_ENDTEST);
+ if(!xc->double_endian_match)
+ {
+ union {
+ unsigned char rvs_buf[8];
+ double d;
+ } vu;
+
+ unsigned char *dcheck_alias = (unsigned char *)&dcheck;
+ int rvs_idx;
+
+ for(rvs_idx=0;rvs_idx<8;rvs_idx++)
+ {
+ vu.rvs_buf[rvs_idx] = dcheck_alias[7-rvs_idx];
+ }
+ if(vu.d != FST_DOUBLE_ENDTEST)
+ {
+ break; /* either corrupt file or wrong architecture (offset +33 also functions as matchword) */
+ }
+ }
+
+ hdr_seen = 1;
+
+ xc->mem_used_by_writer = fstReaderUint64(xc->f);
+ xc->scope_count = fstReaderUint64(xc->f);
+ xc->var_count = fstReaderUint64(xc->f);
+ xc->maxhandle = fstReaderUint64(xc->f);
+ xc->num_alias = xc->var_count - xc->maxhandle;
+ xc->vc_section_count = fstReaderUint64(xc->f);
+ ch = fgetc(xc->f);
+ xc->timescale = (signed char)ch;
+ fstFread(xc->version, FST_HDR_SIM_VERSION_SIZE, 1, xc->f);
+ xc->version[FST_HDR_SIM_VERSION_SIZE] = 0;
+ fstFread(xc->date, FST_HDR_DATE_SIZE, 1, xc->f);
+ xc->date[FST_HDR_DATE_SIZE] = 0;
+ ch = fgetc(xc->f);
+ xc->filetype = (unsigned char)ch;
+ xc->timezero = fstReaderUint64(xc->f);
+ }
+ }
+ else if((sectype == FST_BL_VCDATA) || (sectype == FST_BL_VCDATA_DYN_ALIAS) || (sectype == FST_BL_VCDATA_DYN_ALIAS2))
+ {
+ if(hdr_incomplete)
+ {
+ uint64_t bt = fstReaderUint64(xc->f);
+ xc->end_time = fstReaderUint64(xc->f);
+
+ if(!vc_section_count_actual) { xc->start_time = bt; }
+ }
+
+ vc_section_count_actual++;
+ }
+ else if(sectype == FST_BL_GEOM)
+ {
+ if(!hdr_incomplete)
+ {
+ uint64_t clen = seclen - 24;
+ uint64_t uclen = fstReaderUint64(xc->f);
+ unsigned char *ucdata = (unsigned char *)malloc(uclen);
+ unsigned char *pnt = ucdata;
+ unsigned int i;
+
+ xc->contains_geom_section = 1;
+ xc->maxhandle = fstReaderUint64(xc->f);
+ xc->longest_signal_value_len = 32; /* arbitrarily set at 32...this is much longer than an expanded double */
+
+ free(xc->process_mask);
+ xc->process_mask = (unsigned char *)calloc(1, (xc->maxhandle+7)/8);
+
+ if(clen != uclen)
+ {
+ unsigned char *cdata = (unsigned char *)malloc(clen);
+ unsigned long destlen = uclen;
+ unsigned long sourcelen = clen;
+ int rc;
+
+ fstFread(cdata, clen, 1, xc->f);
+ rc = uncompress(ucdata, &destlen, cdata, sourcelen);
+
+ if(rc != Z_OK)
+ {
+ fprintf(stderr, FST_APIMESS "fstReaderInit(), geom uncompress rc = %d, exiting.\n", rc);
+ exit(255);
+ }
+
+ free(cdata);
+ }
+ else
+ {
+ fstFread(ucdata, uclen, 1, xc->f);
+ }
+
+ free(xc->signal_lens);
+ xc->signal_lens = (uint32_t *)malloc(sizeof(uint32_t) * xc->maxhandle);
+ free(xc->signal_typs);
+ xc->signal_typs = (unsigned char *)malloc(sizeof(unsigned char) * xc->maxhandle);
+
+ for(i=0;imaxhandle;i++)
+ {
+ int skiplen;
+ uint64_t val = fstGetVarint32(pnt, &skiplen);
+
+ pnt += skiplen;
+
+ if(val)
+ {
+ xc->signal_lens[i] = (val != 0xFFFFFFFF) ? val : 0;
+ xc->signal_typs[i] = FST_VT_VCD_WIRE;
+ if(xc->signal_lens[i] > xc->longest_signal_value_len)
+ {
+ xc->longest_signal_value_len = xc->signal_lens[i];
+ }
+ }
+ else
+ {
+ xc->signal_lens[i] = 8; /* backpatch in real */
+ xc->signal_typs[i] = FST_VT_VCD_REAL;
+ /* xc->longest_signal_value_len handled above by overly large init size */
+ }
+ }
+
+ free(xc->temp_signal_value_buf);
+ xc->temp_signal_value_buf = (unsigned char *)malloc(xc->longest_signal_value_len + 1);
+
+ free(ucdata);
+ }
+ }
+ else if(sectype == FST_BL_HIER)
+ {
+ xc->contains_hier_section = 1;
+ xc->hier_pos = ftello(xc->f);
+ }
+ else if(sectype == FST_BL_HIER_LZ4DUO)
+ {
+ xc->contains_hier_section_lz4 = 1;
+ xc->contains_hier_section_lz4duo = 1;
+ xc->hier_pos = ftello(xc->f);
+ }
+ else if(sectype == FST_BL_HIER_LZ4)
+ {
+ xc->contains_hier_section_lz4 = 1;
+ xc->hier_pos = ftello(xc->f);
+ }
+ else if(sectype == FST_BL_BLACKOUT)
+ {
+ uint32_t i;
+ uint64_t cur_bl = 0;
+ uint64_t delta;
+
+ xc->num_blackouts = fstReaderVarint32(xc->f);
+ free(xc->blackout_times);
+ xc->blackout_times = (uint64_t *)calloc(xc->num_blackouts, sizeof(uint64_t));
+ free(xc->blackout_activity);
+ xc->blackout_activity = (unsigned char *)calloc(xc->num_blackouts, sizeof(unsigned char));
+
+ for(i=0;inum_blackouts;i++)
+ {
+ xc->blackout_activity[i] = fgetc(xc->f) != 0;
+ delta = fstReaderVarint64(xc->f);
+ cur_bl += delta;
+ xc->blackout_times[i] = cur_bl;
+ }
+ }
+
+ blkpos += seclen;
+ if(!hdr_seen) break;
+ }
+
+ if(hdr_seen)
+ {
+ if(xc->vc_section_count != vc_section_count_actual)
+ {
+ xc->vc_section_count = vc_section_count_actual;
+ }
+
+ if(!xc->contains_geom_section)
+ {
+ fstReaderProcessHier(xc, NULL); /* recreate signal_lens/signal_typs info */
+ }
+ }
+ }
+
+return(hdr_seen);
+}
+
+
+void *fstReaderOpenForUtilitiesOnly(void)
+{
+struct fstReaderContext *xc = (struct fstReaderContext *)calloc(1, sizeof(struct fstReaderContext));
+
+return(xc);
+}
+
+
+void *fstReaderOpen(const char *nam)
+{
+struct fstReaderContext *xc = (struct fstReaderContext *)calloc(1, sizeof(struct fstReaderContext));
+
+if((!nam)||(!(xc->f=fopen(nam, "rb"))))
+ {
+ free(xc);
+ xc=NULL;
+ }
+ else
+ {
+ int flen = strlen(nam);
+ char *hf = (char *)calloc(1, flen + 6);
+ int rc;
+
+#if defined(__MINGW32__) || defined(FST_MACOSX)
+ setvbuf(xc->f, (char *)NULL, _IONBF, 0); /* keeps gzip from acting weird in tandem with fopen */
+#endif
+
+ memcpy(hf, nam, flen);
+ strcpy(hf + flen, ".hier");
+ xc->fh = fopen(hf, "rb");
+
+ free(hf);
+ xc->filename = strdup(nam);
+ rc = fstReaderInit(xc);
+
+ if((rc) && (xc->vc_section_count) && (xc->maxhandle) && ((xc->fh)||(xc->contains_hier_section||(xc->contains_hier_section_lz4))))
+ {
+ /* more init */
+ xc->do_rewind = 1;
+ }
+ else
+ {
+ fstReaderClose(xc);
+ xc = NULL;
+ }
+ }
+
+return(xc);
+}
+
+
+static void fstReaderDeallocateRvatData(void *ctx)
+{
+struct fstReaderContext *xc = (struct fstReaderContext *)ctx;
+if(xc)
+ {
+ free(xc->rvat_chain_mem); xc->rvat_chain_mem = NULL;
+ free(xc->rvat_frame_data); xc->rvat_frame_data = NULL;
+ free(xc->rvat_time_table); xc->rvat_time_table = NULL;
+ free(xc->rvat_chain_table); xc->rvat_chain_table = NULL;
+ free(xc->rvat_chain_table_lengths); xc->rvat_chain_table_lengths = NULL;
+
+ xc->rvat_data_valid = 0;
+ }
+}
+
+
+void fstReaderClose(void *ctx)
+{
+struct fstReaderContext *xc = (struct fstReaderContext *)ctx;
+
+if(xc)
+ {
+ fstReaderDeallocateScopeData(xc);
+ fstReaderDeallocateRvatData(xc);
+ free(xc->rvat_sig_offs); xc->rvat_sig_offs = NULL;
+
+ free(xc->process_mask); xc->process_mask = NULL;
+ free(xc->blackout_times); xc->blackout_times = NULL;
+ free(xc->blackout_activity); xc->blackout_activity = NULL;
+ free(xc->temp_signal_value_buf); xc->temp_signal_value_buf = NULL;
+ free(xc->signal_typs); xc->signal_typs = NULL;
+ free(xc->signal_lens); xc->signal_lens = NULL;
+ free(xc->filename); xc->filename = NULL;
+
+ if(xc->fh)
+ {
+ tmpfile_close(&xc->fh, &xc->fh_nam);
+ }
+
+ if(xc->f)
+ {
+ tmpfile_close(&xc->f, &xc->f_nam);
+ if(xc->filename_unpacked)
+ {
+ unlink(xc->filename_unpacked);
+ free(xc->filename_unpacked);
+ }
+ }
+
+ free(xc);
+ }
+}
+
+
+/*
+ * read processing
+ */
+
+/* normal read which re-interleaves the value change data */
+int fstReaderIterBlocks(void *ctx,
+ void (*value_change_callback)(void *user_callback_data_pointer, uint64_t time, fstHandle facidx, const unsigned char *value),
+ void *user_callback_data_pointer, FILE *fv)
+{
+return(fstReaderIterBlocks2(ctx, value_change_callback, NULL, user_callback_data_pointer, fv));
+}
+
+
+int fstReaderIterBlocks2(void *ctx,
+ void (*value_change_callback)(void *user_callback_data_pointer, uint64_t time, fstHandle facidx, const unsigned char *value),
+ void (*value_change_callback_varlen)(void *user_callback_data_pointer, uint64_t time, fstHandle facidx, const unsigned char *value, uint32_t len),
+ void *user_callback_data_pointer, FILE *fv)
+{
+struct fstReaderContext *xc = (struct fstReaderContext *)ctx;
+
+uint64_t previous_time = UINT64_MAX;
+uint64_t *time_table = NULL;
+uint64_t tsec_nitems;
+unsigned int secnum = 0;
+int blocks_skipped = 0;
+fst_off_t blkpos = 0;
+uint64_t seclen, beg_tim;
+uint64_t end_tim;
+uint64_t frame_uclen, frame_clen, frame_maxhandle, vc_maxhandle;
+fst_off_t vc_start;
+fst_off_t indx_pntr, indx_pos;
+fst_off_t *chain_table = NULL;
+uint32_t *chain_table_lengths = NULL;
+unsigned char *chain_cmem;
+unsigned char *pnt;
+long chain_clen;
+fstHandle idx, pidx=0, i;
+uint64_t pval;
+uint64_t vc_maxhandle_largest = 0;
+uint64_t tsec_uclen = 0, tsec_clen = 0;
+int sectype;
+uint64_t mem_required_for_traversal;
+unsigned char *mem_for_traversal = NULL;
+uint32_t traversal_mem_offs;
+uint32_t *scatterptr, *headptr, *length_remaining;
+uint32_t cur_blackout = 0;
+int packtype;
+unsigned char *mc_mem = NULL;
+uint32_t mc_mem_len; /* corresponds to largest value encountered in chain_table_lengths[i] */
+int dumpvars_state = 0;
+
+if(!xc) return(0);
+
+scatterptr = (uint32_t *)calloc(xc->maxhandle, sizeof(uint32_t));
+headptr = (uint32_t *)calloc(xc->maxhandle, sizeof(uint32_t));
+length_remaining = (uint32_t *)calloc(xc->maxhandle, sizeof(uint32_t));
+
+if(fv)
+ {
+#ifndef FST_WRITEX_DISABLE
+ fflush(fv);
+ setvbuf(fv, (char *) NULL, _IONBF, 0); /* even buffered IO is slow so disable it and use our own routines that don't need seeking */
+ xc->writex_fd = fileno(fv);
+#endif
+ }
+
+for(;;)
+ {
+ uint32_t *tc_head = NULL;
+ traversal_mem_offs = 0;
+
+ fstReaderFseeko(xc, xc->f, blkpos, SEEK_SET);
+
+ sectype = fgetc(xc->f);
+ seclen = fstReaderUint64(xc->f);
+
+ if((sectype == EOF) || (sectype == FST_BL_SKIP))
+ {
+#ifdef FST_DEBUG
+ fprintf(stderr, FST_APIMESS "<< EOF >>\n");
+#endif
+ break;
+ }
+
+ blkpos++;
+ if((sectype != FST_BL_VCDATA) && (sectype != FST_BL_VCDATA_DYN_ALIAS) && (sectype != FST_BL_VCDATA_DYN_ALIAS2))
+ {
+ blkpos += seclen;
+ continue;
+ }
+
+ if(!seclen) break;
+
+ beg_tim = fstReaderUint64(xc->f);
+ end_tim = fstReaderUint64(xc->f);
+
+ if(xc->limit_range_valid)
+ {
+ if(end_tim < xc->limit_range_start)
+ {
+ blocks_skipped++;
+ blkpos += seclen;
+ continue;
+ }
+
+ if(beg_tim > xc->limit_range_end) /* likely the compare in for(i=0;if);
+ mem_for_traversal = (unsigned char *)malloc(mem_required_for_traversal + 66); /* add in potential fastlz overhead */
+#ifdef FST_DEBUG
+ fprintf(stderr, FST_APIMESS "sec: %u seclen: %d begtim: %d endtim: %d\n",
+ secnum, (int)seclen, (int)beg_tim, (int)end_tim);
+ fprintf(stderr, FST_APIMESS "mem_required_for_traversal: %d\n", (int)mem_required_for_traversal);
+#endif
+ /* process time block */
+ {
+ unsigned char *ucdata;
+ unsigned char *cdata;
+ unsigned long destlen /* = tsec_uclen */; /* scan-build */
+ unsigned long sourcelen /*= tsec_clen */; /* scan-build */
+ int rc;
+ unsigned char *tpnt;
+ uint64_t tpval;
+ unsigned int ti;
+
+ if(fstReaderFseeko(xc, xc->f, blkpos + seclen - 24, SEEK_SET) != 0) break;
+ tsec_uclen = fstReaderUint64(xc->f);
+ tsec_clen = fstReaderUint64(xc->f);
+ tsec_nitems = fstReaderUint64(xc->f);
+#ifdef FST_DEBUG
+ fprintf(stderr, FST_APIMESS "time section unc: %d, com: %d (%d items)\n",
+ (int)tsec_uclen, (int)tsec_clen, (int)tsec_nitems);
+#endif
+ if(tsec_clen > seclen) break; /* corrupted tsec_clen: by definition it can't be larger than size of section */
+ ucdata = (unsigned char *)malloc(tsec_uclen);
+ if(!ucdata) break; /* malloc fail as tsec_uclen out of range from corrupted file */
+ destlen = tsec_uclen;
+ sourcelen = tsec_clen;
+
+ fstReaderFseeko(xc, xc->f, -24 - ((fst_off_t)tsec_clen), SEEK_CUR);
+
+ if(tsec_uclen != tsec_clen)
+ {
+ cdata = (unsigned char *)malloc(tsec_clen);
+ fstFread(cdata, tsec_clen, 1, xc->f);
+
+ rc = uncompress(ucdata, &destlen, cdata, sourcelen);
+
+ if(rc != Z_OK)
+ {
+ fprintf(stderr, FST_APIMESS "fstReaderIterBlocks2(), tsec uncompress rc = %d, exiting.\n", rc);
+ exit(255);
+ }
+
+ free(cdata);
+ }
+ else
+ {
+ fstFread(ucdata, tsec_uclen, 1, xc->f);
+ }
+
+ free(time_table);
+ time_table = (uint64_t *)calloc(tsec_nitems, sizeof(uint64_t));
+ tpnt = ucdata;
+ tpval = 0;
+ for(ti=0;tif, blkpos+32, SEEK_SET);
+
+ frame_uclen = fstReaderVarint64(xc->f);
+ frame_clen = fstReaderVarint64(xc->f);
+ frame_maxhandle = fstReaderVarint64(xc->f);
+
+ if(secnum == 0)
+ {
+ if((beg_tim != time_table[0]) || (blocks_skipped))
+ {
+ unsigned char *mu = (unsigned char *)malloc(frame_uclen);
+ uint32_t sig_offs = 0;
+
+ if(fv)
+ {
+ char wx_buf[32];
+ int wx_len;
+
+ if(beg_tim)
+ {
+ if(dumpvars_state == 1) { wx_len = sprintf(wx_buf, "$end\n"); fstWritex(xc, wx_buf, wx_len); dumpvars_state = 2; }
+ wx_len = sprintf(wx_buf, "#%" PRIu64 "\n", beg_tim);
+ fstWritex(xc, wx_buf, wx_len);
+ if(!dumpvars_state) { wx_len = sprintf(wx_buf, "$dumpvars\n"); fstWritex(xc, wx_buf, wx_len); dumpvars_state = 1; }
+ }
+ if((xc->num_blackouts)&&(cur_blackout != xc->num_blackouts))
+ {
+ if(beg_tim == xc->blackout_times[cur_blackout])
+ {
+ wx_len = sprintf(wx_buf, "$dump%s $end\n", (xc->blackout_activity[cur_blackout++]) ? "on" : "off");
+ fstWritex(xc, wx_buf, wx_len);
+ }
+ }
+ }
+
+ if(frame_uclen == frame_clen)
+ {
+ fstFread(mu, frame_uclen, 1, xc->f);
+ }
+ else
+ {
+ unsigned char *mc = (unsigned char *)malloc(frame_clen);
+ int rc;
+
+ unsigned long destlen = frame_uclen;
+ unsigned long sourcelen = frame_clen;
+
+ fstFread(mc, sourcelen, 1, xc->f);
+ rc = uncompress(mu, &destlen, mc, sourcelen);
+ if(rc != Z_OK)
+ {
+ fprintf(stderr, FST_APIMESS "fstReaderIterBlocks2(), frame uncompress rc: %d, exiting.\n", rc);
+ exit(255);
+ }
+ free(mc);
+ }
+
+
+ for(idx=0;idxprocess_mask[process_idx]&(1<signal_lens[idx] <= 1)
+ {
+ if(xc->signal_lens[idx] == 1)
+ {
+ unsigned char val = mu[sig_offs];
+ if(value_change_callback)
+ {
+ xc->temp_signal_value_buf[0] = val;
+ xc->temp_signal_value_buf[1] = 0;
+ value_change_callback(user_callback_data_pointer, beg_tim, idx+1, xc->temp_signal_value_buf);
+ }
+ else
+ {
+ if(fv)
+ {
+ char vcd_id[16];
+
+ int vcdid_len = fstVcdIDForFwrite(vcd_id+1, idx+1);
+ vcd_id[0] = val; /* collapse 3 writes into one I/O call */
+ vcd_id[vcdid_len + 1] = '\n';
+ fstWritex(xc, vcd_id, vcdid_len + 2);
+ }
+ }
+ }
+ else
+ {
+ /* variable-length ("0" length) records have no initial state */
+ }
+ }
+ else
+ {
+ if(xc->signal_typs[idx] != FST_VT_VCD_REAL)
+ {
+ if(value_change_callback)
+ {
+ memcpy(xc->temp_signal_value_buf, mu+sig_offs, xc->signal_lens[idx]);
+ xc->temp_signal_value_buf[xc->signal_lens[idx]] = 0;
+ value_change_callback(user_callback_data_pointer, beg_tim, idx+1, xc->temp_signal_value_buf);
+ }
+ else
+ {
+ if(fv)
+ {
+ char vcd_id[16];
+ int vcdid_len = fstVcdIDForFwrite(vcd_id+1, idx+1);
+
+ vcd_id[0] = (xc->signal_typs[idx] != FST_VT_VCD_PORT) ? 'b' : 'p';
+ fstWritex(xc, vcd_id, 1);
+ fstWritex(xc,mu+sig_offs, xc->signal_lens[idx]);
+
+ vcd_id[0] = ' '; /* collapse 3 writes into one I/O call */
+ vcd_id[vcdid_len + 1] = '\n';
+ fstWritex(xc, vcd_id, vcdid_len + 2);
+ }
+ }
+ }
+ else
+ {
+ double d;
+ unsigned char *clone_d;
+ unsigned char *srcdata = mu+sig_offs;
+
+ if(value_change_callback)
+ {
+ if(xc->native_doubles_for_cb)
+ {
+ if(xc->double_endian_match)
+ {
+ clone_d = srcdata;
+ }
+ else
+ {
+ int j;
+
+ clone_d = (unsigned char *)&d;
+ for(j=0;j<8;j++)
+ {
+ clone_d[j] = srcdata[7-j];
+ }
+ }
+ value_change_callback(user_callback_data_pointer, beg_tim, idx+1, clone_d);
+ }
+ else
+ {
+ clone_d = (unsigned char *)&d;
+ if(xc->double_endian_match)
+ {
+ memcpy(clone_d, srcdata, 8);
+ }
+ else
+ {
+ int j;
+
+ for(j=0;j<8;j++)
+ {
+ clone_d[j] = srcdata[7-j];
+ }
+ }
+ sprintf((char *)xc->temp_signal_value_buf, "%.16g", d);
+ value_change_callback(user_callback_data_pointer, beg_tim, idx+1, xc->temp_signal_value_buf);
+ }
+ }
+ else
+ {
+ if(fv)
+ {
+ char vcdid_buf[16];
+ char wx_buf[64];
+ int wx_len;
+
+ clone_d = (unsigned char *)&d;
+ if(xc->double_endian_match)
+ {
+ memcpy(clone_d, srcdata, 8);
+ }
+ else
+ {
+ int j;
+
+ for(j=0;j<8;j++)
+ {
+ clone_d[j] = srcdata[7-j];
+ }
+ }
+
+ fstVcdID(vcdid_buf, idx+1);
+ wx_len = sprintf(wx_buf, "r%.16g %s\n", d, vcdid_buf);
+ fstWritex(xc, wx_buf, wx_len);
+ }
+ }
+ }
+ }
+ }
+
+ sig_offs += xc->signal_lens[idx];
+ }
+
+ free(mu);
+ fstReaderFseeko(xc, xc->f, -((fst_off_t)frame_clen), SEEK_CUR);
+ }
+ }
+
+ fstReaderFseeko(xc, xc->f, (fst_off_t)frame_clen, SEEK_CUR); /* skip past compressed data */
+
+ vc_maxhandle = fstReaderVarint64(xc->f);
+ vc_start = ftello(xc->f); /* points to '!' character */
+ packtype = fgetc(xc->f);
+
+#ifdef FST_DEBUG
+ fprintf(stderr, FST_APIMESS "frame_uclen: %d, frame_clen: %d, frame_maxhandle: %d\n",
+ (int)frame_uclen, (int)frame_clen, (int)frame_maxhandle);
+ fprintf(stderr, FST_APIMESS "vc_maxhandle: %d, packtype: %c\n", (int)vc_maxhandle, packtype);
+#endif
+
+ indx_pntr = blkpos + seclen - 24 -tsec_clen -8;
+ fstReaderFseeko(xc, xc->f, indx_pntr, SEEK_SET);
+ chain_clen = fstReaderUint64(xc->f);
+ indx_pos = indx_pntr - chain_clen;
+#ifdef FST_DEBUG
+ fprintf(stderr, FST_APIMESS "indx_pos: %d (%d bytes)\n", (int)indx_pos, (int)chain_clen);
+#endif
+ chain_cmem = (unsigned char *)malloc(chain_clen);
+ if(!chain_cmem) goto block_err;
+ fstReaderFseeko(xc, xc->f, indx_pos, SEEK_SET);
+ fstFread(chain_cmem, chain_clen, 1, xc->f);
+
+ if(vc_maxhandle > vc_maxhandle_largest)
+ {
+ free(chain_table);
+ free(chain_table_lengths);
+
+ vc_maxhandle_largest = vc_maxhandle;
+ chain_table = (fst_off_t *)calloc((vc_maxhandle+1), sizeof(fst_off_t));
+ chain_table_lengths = (uint32_t *)calloc((vc_maxhandle+1), sizeof(uint32_t));
+ }
+
+ if(!chain_table || !chain_table_lengths) goto block_err;
+
+ pnt = chain_cmem;
+ idx = 0;
+ pval = 0;
+
+ if(sectype == FST_BL_VCDATA_DYN_ALIAS2)
+ {
+ uint32_t prev_alias = 0;
+
+ do {
+ int skiplen;
+
+ if(*pnt & 0x01)
+ {
+ int64_t shval = fstGetSVarint64(pnt, &skiplen) >> 1;
+ if(shval > 0)
+ {
+ pval = chain_table[idx] = pval + shval;
+ if(idx) { chain_table_lengths[pidx] = pval - chain_table[pidx]; }
+ pidx = idx++;
+ }
+ else if(shval < 0)
+ {
+ chain_table[idx] = 0; /* need to explicitly zero as calloc above might not run */
+ chain_table_lengths[idx] = prev_alias = shval; /* because during this loop iter would give stale data! */
+ idx++;
+ }
+ else
+ {
+ chain_table[idx] = 0; /* need to explicitly zero as calloc above might not run */
+ chain_table_lengths[idx] = prev_alias; /* because during this loop iter would give stale data! */
+ idx++;
+ }
+ }
+ else
+ {
+ uint64_t val = fstGetVarint32(pnt, &skiplen);
+
+ fstHandle loopcnt = val >> 1;
+ for(i=0;i> 1);
+ if(idx) { chain_table_lengths[pidx] = pval - chain_table[pidx]; }
+ pidx = idx++;
+ }
+ else
+ {
+ fstHandle loopcnt = val >> 1;
+ for(i=0;i xc->maxhandle) idx = xc->maxhandle;
+ for(i=0;iprocess_mask[process_idx]&(1<f, vc_start + chain_table[i], SEEK_SET);
+ val = fstReaderVarint32WithSkip(xc->f, &skiplen);
+ if(val)
+ {
+ unsigned char *mu = mem_for_traversal + traversal_mem_offs; /* uncomp: dst */
+ unsigned char *mc; /* comp: src */
+ unsigned long destlen = val;
+ unsigned long sourcelen = chain_table_lengths[i];
+
+ if(mc_mem_len < chain_table_lengths[i])
+ {
+ free(mc_mem);
+ mc_mem = (unsigned char *)malloc(mc_mem_len = chain_table_lengths[i]);
+ }
+ mc = mc_mem;
+
+ fstFread(mc, chain_table_lengths[i], 1, xc->f);
+
+ switch(packtype)
+ {
+ case '4': rc = (destlen == (unsigned long)LZ4_decompress_safe_partial((char *)mc, (char *)mu, sourcelen, destlen, destlen)) ? Z_OK : Z_DATA_ERROR;
+ break;
+ case 'F': fastlz_decompress(mc, sourcelen, mu, destlen); /* rc appears unreliable */
+ break;
+ default: rc = uncompress(mu, &destlen, mc, sourcelen);
+ break;
+ }
+
+ /* data to process is for(j=0;jf);
+ /* data to process is for(j=0;jsignal_lens[i] == 1)
+ {
+ uint32_t vli = fstGetVarint32NoSkip(mem_for_traversal + headptr[i]);
+ uint32_t shcnt = 2 << (vli & 1);
+ tdelta = vli >> shcnt;
+ }
+ else
+ {
+ uint32_t vli = fstGetVarint32NoSkip(mem_for_traversal + headptr[i]);
+ tdelta = vli >> 1;
+ }
+
+ scatterptr[i] = tc_head[tdelta];
+ tc_head[tdelta] = i+1;
+ }
+ }
+ }
+
+ free(mc_mem); /* there is no usage below for this, no real need to clear out mc_mem or mc_mem_len */
+
+ for(i=0;ilimit_range_valid)
+ {
+ if(time_table[i] > xc->limit_range_end)
+ {
+ break;
+ }
+ }
+
+ if(dumpvars_state == 1) { wx_len = sprintf(wx_buf, "$end\n"); fstWritex(xc, wx_buf, wx_len); dumpvars_state = 2; }
+ wx_len = sprintf(wx_buf, "#%" PRIu64 "\n", time_table[i]);
+ fstWritex(xc, wx_buf, wx_len);
+ if(!dumpvars_state) { wx_len = sprintf(wx_buf, "$dumpvars\n"); fstWritex(xc, wx_buf, wx_len); dumpvars_state = 1; }
+
+ if((xc->num_blackouts)&&(cur_blackout != xc->num_blackouts))
+ {
+ if(time_table[i] == xc->blackout_times[cur_blackout])
+ {
+ wx_len = sprintf(wx_buf, "$dump%s $end\n", (xc->blackout_activity[cur_blackout++]) ? "on" : "off");
+ fstWritex(xc, wx_buf, wx_len);
+ }
+ }
+ previous_time = time_table[i];
+ }
+ }
+
+ while(tc_head[i])
+ {
+ idx = tc_head[i] - 1;
+ vli = fstGetVarint32(mem_for_traversal + headptr[idx], &skiplen);
+
+ if(xc->signal_lens[idx] <= 1)
+ {
+ if(xc->signal_lens[idx] == 1)
+ {
+ unsigned char val;
+ if(!(vli & 1))
+ {
+ /* tdelta = vli >> 2; */ /* scan-build */
+ val = ((vli >> 1) & 1) | '0';
+ }
+ else
+ {
+ /* tdelta = vli >> 4; */ /* scan-build */
+ val = FST_RCV_STR[((vli >> 1) & 7)];
+ }
+
+ if(value_change_callback)
+ {
+ xc->temp_signal_value_buf[0] = val;
+ xc->temp_signal_value_buf[1] = 0;
+ value_change_callback(user_callback_data_pointer, time_table[i], idx+1, xc->temp_signal_value_buf);
+ }
+ else
+ {
+ if(fv)
+ {
+ char vcd_id[16];
+ int vcdid_len = fstVcdIDForFwrite(vcd_id+1, idx+1);
+
+ vcd_id[0] = val;
+ vcd_id[vcdid_len+1] = '\n';
+ fstWritex(xc, vcd_id, vcdid_len+2);
+ }
+ }
+ headptr[idx] += skiplen;
+ length_remaining[idx] -= skiplen;
+
+ tc_head[i] = scatterptr[idx];
+ scatterptr[idx] = 0;
+
+ if(length_remaining[idx])
+ {
+ int shamt;
+ vli = fstGetVarint32NoSkip(mem_for_traversal + headptr[idx]);
+ shamt = 2 << (vli & 1);
+ tdelta = vli >> shamt;
+
+ scatterptr[idx] = tc_head[i+tdelta];
+ tc_head[i+tdelta] = idx+1;
+ }
+ }
+ else
+ {
+ unsigned char *vdata;
+ uint32_t len;
+
+ vli = fstGetVarint32(mem_for_traversal + headptr[idx], &skiplen);
+ len = fstGetVarint32(mem_for_traversal + headptr[idx] + skiplen, &skiplen2);
+ /* tdelta = vli >> 1; */ /* scan-build */
+ skiplen += skiplen2;
+ vdata = mem_for_traversal + headptr[idx] + skiplen;
+
+ if(!(vli & 1))
+ {
+ if(value_change_callback_varlen)
+ {
+ value_change_callback_varlen(user_callback_data_pointer, time_table[i], idx+1, vdata, len);
+ }
+ else
+ {
+ if(fv)
+ {
+ char vcd_id[16];
+ int vcdid_len;
+
+ vcd_id[0] = 's';
+ fstWritex(xc, vcd_id, 1);
+
+ vcdid_len = fstVcdIDForFwrite(vcd_id+1, idx+1);
+ {
+ unsigned char *vesc = (unsigned char *)malloc(len*4 + 1);
+ int vlen = fstUtilityBinToEsc(vesc, vdata, len);
+ fstWritex(xc, vesc, vlen);
+ free(vesc);
+ }
+
+ vcd_id[0] = ' ';
+ vcd_id[vcdid_len + 1] = '\n';
+ fstWritex(xc, vcd_id, vcdid_len+2);
+ }
+ }
+ }
+
+ skiplen += len;
+ headptr[idx] += skiplen;
+ length_remaining[idx] -= skiplen;
+
+ tc_head[i] = scatterptr[idx];
+ scatterptr[idx] = 0;
+
+ if(length_remaining[idx])
+ {
+ vli = fstGetVarint32NoSkip(mem_for_traversal + headptr[idx]);
+ tdelta = vli >> 1;
+
+ scatterptr[idx] = tc_head[i+tdelta];
+ tc_head[i+tdelta] = idx+1;
+ }
+ }
+ }
+ else
+ {
+ uint32_t len = xc->signal_lens[idx];
+ unsigned char *vdata;
+
+ vli = fstGetVarint32(mem_for_traversal + headptr[idx], &skiplen);
+ /* tdelta = vli >> 1; */ /* scan-build */
+ vdata = mem_for_traversal + headptr[idx] + skiplen;
+
+ if(xc->signal_typs[idx] != FST_VT_VCD_REAL)
+ {
+ if(!(vli & 1))
+ {
+ int byte = 0;
+ int bit;
+ unsigned int j;
+
+ for(j=0;j> bit) & 1) | '0';
+ xc->temp_signal_value_buf[j] = ch;
+ }
+ xc->temp_signal_value_buf[j] = 0;
+
+ if(value_change_callback)
+ {
+ value_change_callback(user_callback_data_pointer, time_table[i], idx+1, xc->temp_signal_value_buf);
+ }
+ else
+ {
+ if(fv) {
+ unsigned char ch_bp = (xc->signal_typs[idx] != FST_VT_VCD_PORT) ? 'b' : 'p';
+
+ fstWritex(xc, &ch_bp, 1);
+ fstWritex(xc, xc->temp_signal_value_buf, len);
+ }
+ }
+
+ len = byte+1;
+ }
+ else
+ {
+ if(value_change_callback)
+ {
+ memcpy(xc->temp_signal_value_buf, vdata, len);
+ xc->temp_signal_value_buf[len] = 0;
+ value_change_callback(user_callback_data_pointer, time_table[i], idx+1, xc->temp_signal_value_buf);
+ }
+ else
+ {
+ if(fv)
+ {
+ unsigned char ch_bp = (xc->signal_typs[idx] != FST_VT_VCD_PORT) ? 'b' : 'p';
+
+ fstWritex(xc, &ch_bp, 1);
+ fstWritex(xc, vdata, len);
+ }
+ }
+ }
+ }
+ else
+ {
+ double d;
+ unsigned char *clone_d /*= (unsigned char *)&d */; /* scan-build */
+ unsigned char buf[8];
+ unsigned char *srcdata;
+
+ if(!(vli & 1)) /* very rare case, but possible */
+ {
+ int bit;
+ int j;
+
+ for(j=0;j<8;j++)
+ {
+ unsigned char ch;
+ bit = 7 - (j & 7);
+ ch = ((vdata[0] >> bit) & 1) | '0';
+ buf[j] = ch;
+ }
+
+ len = 1;
+ srcdata = buf;
+ }
+ else
+ {
+ srcdata = vdata;
+ }
+
+ if(value_change_callback)
+ {
+ if(xc->native_doubles_for_cb)
+ {
+ if(xc->double_endian_match)
+ {
+ clone_d = srcdata;
+ }
+ else
+ {
+ int j;
+
+ clone_d = (unsigned char *)&d;
+ for(j=0;j<8;j++)
+ {
+ clone_d[j] = srcdata[7-j];
+ }
+ }
+ value_change_callback(user_callback_data_pointer, time_table[i], idx+1, clone_d);
+ }
+ else
+ {
+ clone_d = (unsigned char *)&d;
+ if(xc->double_endian_match)
+ {
+ memcpy(clone_d, srcdata, 8);
+ }
+ else
+ {
+ int j;
+
+ for(j=0;j<8;j++)
+ {
+ clone_d[j] = srcdata[7-j];
+ }
+ }
+ sprintf((char *)xc->temp_signal_value_buf, "%.16g", d);
+ value_change_callback(user_callback_data_pointer, time_table[i], idx+1, xc->temp_signal_value_buf);
+ }
+ }
+ else
+ {
+ if(fv)
+ {
+ char wx_buf[32];
+ int wx_len;
+
+ clone_d = (unsigned char *)&d;
+ if(xc->double_endian_match)
+ {
+ memcpy(clone_d, srcdata, 8);
+ }
+ else
+ {
+ int j;
+
+ for(j=0;j<8;j++)
+ {
+ clone_d[j] = srcdata[7-j];
+ }
+ }
+
+ wx_len = sprintf(wx_buf, "r%.16g", d);
+ fstWritex(xc, wx_buf, wx_len);
+ }
+ }
+ }
+
+ if(fv)
+ {
+ char vcd_id[16];
+ int vcdid_len = fstVcdIDForFwrite(vcd_id+1, idx+1);
+ vcd_id[0] = ' ';
+ vcd_id[vcdid_len+1] = '\n';
+ fstWritex(xc, vcd_id, vcdid_len+2);
+ }
+
+ skiplen += len;
+ headptr[idx] += skiplen;
+ length_remaining[idx] -= skiplen;
+
+ tc_head[i] = scatterptr[idx];
+ scatterptr[idx] = 0;
+
+ if(length_remaining[idx])
+ {
+ vli = fstGetVarint32NoSkip(mem_for_traversal + headptr[idx]);
+ tdelta = vli >> 1;
+
+ scatterptr[idx] = tc_head[i+tdelta];
+ tc_head[i+tdelta] = idx+1;
+ }
+ }
+ }
+ }
+
+block_err:
+ free(tc_head);
+ free(chain_cmem);
+ free(mem_for_traversal); mem_for_traversal = NULL;
+
+ secnum++;
+ if(secnum == xc->vc_section_count) break; /* in case file is growing, keep with original block count */
+ blkpos += seclen;
+ }
+
+if(mem_for_traversal) free(mem_for_traversal); /* scan-build */
+free(length_remaining);
+free(headptr);
+free(scatterptr);
+
+if(chain_table) free(chain_table);
+if(chain_table_lengths) free(chain_table_lengths);
+
+free(time_table);
+
+#ifndef FST_WRITEX_DISABLE
+if(fv)
+ {
+ fstWritex(xc, NULL, 0);
+ }
+#endif
+
+return(1);
+}
+
+
+/* rvat functions */
+
+static char *fstExtractRvatDataFromFrame(struct fstReaderContext *xc, fstHandle facidx, char *buf)
+{
+if(facidx >= xc->rvat_frame_maxhandle)
+ {
+ return(NULL);
+ }
+
+if(xc->signal_lens[facidx] == 1)
+ {
+ buf[0] = (char)xc->rvat_frame_data[xc->rvat_sig_offs[facidx]];
+ buf[1] = 0;
+ }
+ else
+ {
+ if(xc->signal_typs[facidx] != FST_VT_VCD_REAL)
+ {
+ memcpy(buf, xc->rvat_frame_data + xc->rvat_sig_offs[facidx], xc->signal_lens[facidx]);
+ buf[xc->signal_lens[facidx]] = 0;
+ }
+ else
+ {
+ double d;
+ unsigned char *clone_d = (unsigned char *)&d;
+ unsigned char *srcdata = xc->rvat_frame_data + xc->rvat_sig_offs[facidx];
+
+ if(xc->double_endian_match)
+ {
+ memcpy(clone_d, srcdata, 8);
+ }
+ else
+ {
+ int j;
+
+ for(j=0;j<8;j++)
+ {
+ clone_d[j] = srcdata[7-j];
+ }
+ }
+
+ sprintf((char *)buf, "%.16g", d);
+ }
+ }
+
+return(buf);
+}
+
+
+char *fstReaderGetValueFromHandleAtTime(void *ctx, uint64_t tim, fstHandle facidx, char *buf)
+{
+struct fstReaderContext *xc = (struct fstReaderContext *)ctx;
+fst_off_t blkpos = 0, prev_blkpos;
+uint64_t beg_tim, end_tim, beg_tim2, end_tim2;
+int sectype;
+unsigned int secnum = 0;
+uint64_t seclen;
+uint64_t tsec_uclen = 0, tsec_clen = 0;
+uint64_t tsec_nitems;
+uint64_t frame_uclen, frame_clen;
+#ifdef FST_DEBUG
+uint64_t mem_required_for_traversal;
+#endif
+fst_off_t indx_pntr, indx_pos;
+long chain_clen;
+unsigned char *chain_cmem;
+unsigned char *pnt;
+fstHandle idx, pidx=0, i;
+uint64_t pval;
+
+if((!xc) || (!facidx) || (facidx > xc->maxhandle) || (!buf) || (!xc->signal_lens[facidx-1]))
+ {
+ return(NULL);
+ }
+
+if(!xc->rvat_sig_offs)
+ {
+ uint32_t cur_offs = 0;
+
+ xc->rvat_sig_offs = (uint32_t *)calloc(xc->maxhandle, sizeof(uint32_t));
+ for(i=0;imaxhandle;i++)
+ {
+ xc->rvat_sig_offs[i] = cur_offs;
+ cur_offs += xc->signal_lens[i];
+ }
+ }
+
+if(xc->rvat_data_valid)
+ {
+ if((xc->rvat_beg_tim <= tim) && (tim <= xc->rvat_end_tim))
+ {
+ goto process_value;
+ }
+
+ fstReaderDeallocateRvatData(xc);
+ }
+
+xc->rvat_chain_pos_valid = 0;
+
+for(;;)
+ {
+ fstReaderFseeko(xc, xc->f, (prev_blkpos = blkpos), SEEK_SET);
+
+ sectype = fgetc(xc->f);
+ seclen = fstReaderUint64(xc->f);
+
+ if((sectype == EOF) || (sectype == FST_BL_SKIP) || (!seclen))
+ {
+ return(NULL); /* if this loop exits on break, it's successful */
+ }
+
+ blkpos++;
+ if((sectype != FST_BL_VCDATA) && (sectype != FST_BL_VCDATA_DYN_ALIAS) && (sectype != FST_BL_VCDATA_DYN_ALIAS2))
+ {
+ blkpos += seclen;
+ continue;
+ }
+
+ beg_tim = fstReaderUint64(xc->f);
+ end_tim = fstReaderUint64(xc->f);
+
+ if((beg_tim <= tim) && (tim <= end_tim))
+ {
+ if((tim == end_tim) && (tim != xc->end_time))
+ {
+ fst_off_t cached_pos = ftello(xc->f);
+ fstReaderFseeko(xc, xc->f, blkpos, SEEK_SET);
+
+ sectype = fgetc(xc->f);
+ seclen = fstReaderUint64(xc->f);
+
+ beg_tim2 = fstReaderUint64(xc->f);
+ end_tim2 = fstReaderUint64(xc->f);
+
+ if(((sectype != FST_BL_VCDATA)&&(sectype != FST_BL_VCDATA_DYN_ALIAS)&&(sectype != FST_BL_VCDATA_DYN_ALIAS2)) || (!seclen) || (beg_tim2 != tim))
+ {
+ blkpos = prev_blkpos;
+ break;
+ }
+ beg_tim = beg_tim2;
+ end_tim = end_tim2;
+ fstReaderFseeko(xc, xc->f, cached_pos, SEEK_SET);
+ }
+ break;
+ }
+
+ blkpos += seclen;
+ secnum++;
+ }
+
+xc->rvat_beg_tim = beg_tim;
+xc->rvat_end_tim = end_tim;
+
+#ifdef FST_DEBUG
+mem_required_for_traversal =
+#endif
+ fstReaderUint64(xc->f);
+
+#ifdef FST_DEBUG
+fprintf(stderr, FST_APIMESS "rvat sec: %u seclen: %d begtim: %d endtim: %d\n",
+ secnum, (int)seclen, (int)beg_tim, (int)end_tim);
+fprintf(stderr, FST_APIMESS "mem_required_for_traversal: %d\n", (int)mem_required_for_traversal);
+#endif
+
+/* process time block */
+{
+unsigned char *ucdata;
+unsigned char *cdata;
+unsigned long destlen /* = tsec_uclen */; /* scan-build */
+unsigned long sourcelen /* = tsec_clen */; /* scan-build */
+int rc;
+unsigned char *tpnt;
+uint64_t tpval;
+unsigned int ti;
+
+fstReaderFseeko(xc, xc->f, blkpos + seclen - 24, SEEK_SET);
+tsec_uclen = fstReaderUint64(xc->f);
+tsec_clen = fstReaderUint64(xc->f);
+tsec_nitems = fstReaderUint64(xc->f);
+#ifdef FST_DEBUG
+fprintf(stderr, FST_APIMESS "time section unc: %d, com: %d (%d items)\n",
+ (int)tsec_uclen, (int)tsec_clen, (int)tsec_nitems);
+#endif
+ucdata = (unsigned char *)malloc(tsec_uclen);
+destlen = tsec_uclen;
+sourcelen = tsec_clen;
+
+fstReaderFseeko(xc, xc->f, -24 - ((fst_off_t)tsec_clen), SEEK_CUR);
+if(tsec_uclen != tsec_clen)
+ {
+ cdata = (unsigned char *)malloc(tsec_clen);
+ fstFread(cdata, tsec_clen, 1, xc->f);
+
+ rc = uncompress(ucdata, &destlen, cdata, sourcelen);
+
+ if(rc != Z_OK)
+ {
+ fprintf(stderr, FST_APIMESS "fstReaderGetValueFromHandleAtTime(), tsec uncompress rc = %d, exiting.\n", rc);
+ exit(255);
+ }
+
+ free(cdata);
+ }
+ else
+ {
+ fstFread(ucdata, tsec_uclen, 1, xc->f);
+ }
+
+xc->rvat_time_table = (uint64_t *)calloc(tsec_nitems, sizeof(uint64_t));
+tpnt = ucdata;
+tpval = 0;
+for(ti=0;tirvat_time_table[ti] = tpval + val;
+ tpnt += skiplen;
+ }
+
+free(ucdata);
+}
+
+fstReaderFseeko(xc, xc->f, blkpos+32, SEEK_SET);
+
+frame_uclen = fstReaderVarint64(xc->f);
+frame_clen = fstReaderVarint64(xc->f);
+xc->rvat_frame_maxhandle = fstReaderVarint64(xc->f);
+xc->rvat_frame_data = (unsigned char *)malloc(frame_uclen);
+
+if(frame_uclen == frame_clen)
+ {
+ fstFread(xc->rvat_frame_data, frame_uclen, 1, xc->f);
+ }
+ else
+ {
+ unsigned char *mc = (unsigned char *)malloc(frame_clen);
+ int rc;
+
+ unsigned long destlen = frame_uclen;
+ unsigned long sourcelen = frame_clen;
+
+ fstFread(mc, sourcelen, 1, xc->f);
+ rc = uncompress(xc->rvat_frame_data, &destlen, mc, sourcelen);
+ if(rc != Z_OK)
+ {
+ fprintf(stderr, FST_APIMESS "fstReaderGetValueFromHandleAtTime(), frame decompress rc: %d, exiting.\n", rc);
+ exit(255);
+ }
+ free(mc);
+ }
+
+xc->rvat_vc_maxhandle = fstReaderVarint64(xc->f);
+xc->rvat_vc_start = ftello(xc->f); /* points to '!' character */
+xc->rvat_packtype = fgetc(xc->f);
+
+#ifdef FST_DEBUG
+fprintf(stderr, FST_APIMESS "frame_uclen: %d, frame_clen: %d, frame_maxhandle: %d\n",
+ (int)frame_uclen, (int)frame_clen, (int)xc->rvat_frame_maxhandle);
+fprintf(stderr, FST_APIMESS "vc_maxhandle: %d\n", (int)xc->rvat_vc_maxhandle);
+#endif
+
+indx_pntr = blkpos + seclen - 24 -tsec_clen -8;
+fstReaderFseeko(xc, xc->f, indx_pntr, SEEK_SET);
+chain_clen = fstReaderUint64(xc->f);
+indx_pos = indx_pntr - chain_clen;
+#ifdef FST_DEBUG
+fprintf(stderr, FST_APIMESS "indx_pos: %d (%d bytes)\n", (int)indx_pos, (int)chain_clen);
+#endif
+chain_cmem = (unsigned char *)malloc(chain_clen);
+fstReaderFseeko(xc, xc->f, indx_pos, SEEK_SET);
+fstFread(chain_cmem, chain_clen, 1, xc->f);
+
+xc->rvat_chain_table = (fst_off_t *)calloc((xc->rvat_vc_maxhandle+1), sizeof(fst_off_t));
+xc->rvat_chain_table_lengths = (uint32_t *)calloc((xc->rvat_vc_maxhandle+1), sizeof(uint32_t));
+
+pnt = chain_cmem;
+idx = 0;
+pval = 0;
+
+if(sectype == FST_BL_VCDATA_DYN_ALIAS2)
+ {
+ uint32_t prev_alias = 0;
+
+ do {
+ int skiplen;
+
+ if(*pnt & 0x01)
+ {
+ int64_t shval = fstGetSVarint64(pnt, &skiplen) >> 1;
+ if(shval > 0)
+ {
+ pval = xc->rvat_chain_table[idx] = pval + shval;
+ if(idx) { xc->rvat_chain_table_lengths[pidx] = pval - xc->rvat_chain_table[pidx]; }
+ pidx = idx++;
+ }
+ else if(shval < 0)
+ {
+ xc->rvat_chain_table[idx] = 0; /* need to explicitly zero as calloc above might not run */
+ xc->rvat_chain_table_lengths[idx] = prev_alias = shval; /* because during this loop iter would give stale data! */
+ idx++;
+ }
+ else
+ {
+ xc->rvat_chain_table[idx] = 0; /* need to explicitly zero as calloc above might not run */
+ xc->rvat_chain_table_lengths[idx] = prev_alias; /* because during this loop iter would give stale data! */
+ idx++;
+ }
+ }
+ else
+ {
+ uint64_t val = fstGetVarint32(pnt, &skiplen);
+
+ fstHandle loopcnt = val >> 1;
+ for(i=0;irvat_chain_table[idx++] = 0;
+ }
+ }
+
+ pnt += skiplen;
+ } while (pnt != (chain_cmem + chain_clen));
+ }
+ else
+ {
+ do
+ {
+ int skiplen;
+ uint64_t val = fstGetVarint32(pnt, &skiplen);
+
+ if(!val)
+ {
+ pnt += skiplen;
+ val = fstGetVarint32(pnt, &skiplen);
+ xc->rvat_chain_table[idx] = 0;
+ xc->rvat_chain_table_lengths[idx] = -val;
+ idx++;
+ }
+ else
+ if(val&1)
+ {
+ pval = xc->rvat_chain_table[idx] = pval + (val >> 1);
+ if(idx) { xc->rvat_chain_table_lengths[pidx] = pval - xc->rvat_chain_table[pidx]; }
+ pidx = idx++;
+ }
+ else
+ {
+ fstHandle loopcnt = val >> 1;
+ for(i=0;irvat_chain_table[idx++] = 0;
+ }
+ }
+
+ pnt += skiplen;
+ } while (pnt != (chain_cmem + chain_clen));
+ }
+
+free(chain_cmem);
+xc->rvat_chain_table[idx] = indx_pos - xc->rvat_vc_start;
+xc->rvat_chain_table_lengths[pidx] = xc->rvat_chain_table[idx] - xc->rvat_chain_table[pidx];
+
+for(i=0;irvat_chain_table_lengths[i];
+ if((v32 < 0) && (!xc->rvat_chain_table[i]))
+ {
+ v32 = -v32;
+ v32--;
+ if(((uint32_t)v32) < i) /* sanity check */
+ {
+ xc->rvat_chain_table[i] = xc->rvat_chain_table[v32];
+ xc->rvat_chain_table_lengths[i] = xc->rvat_chain_table_lengths[v32];
+ }
+ }
+ }
+
+#ifdef FST_DEBUG
+fprintf(stderr, FST_APIMESS "decompressed chain idx len: %" PRIu32 "\n", idx);
+#endif
+
+xc->rvat_data_valid = 1;
+
+/* all data at this point is loaded or resident in fst cache, process and return appropriate value */
+process_value:
+if(facidx > xc->rvat_vc_maxhandle)
+ {
+ return(NULL);
+ }
+
+facidx--; /* scale down for array which starts at zero */
+
+
+if(((tim == xc->rvat_beg_tim)&&(!xc->rvat_chain_table[facidx])) || (!xc->rvat_chain_table[facidx]))
+ {
+ return(fstExtractRvatDataFromFrame(xc, facidx, buf));
+ }
+
+if(facidx != xc->rvat_chain_facidx)
+ {
+ if(xc->rvat_chain_mem)
+ {
+ free(xc->rvat_chain_mem);
+ xc->rvat_chain_mem = NULL;
+
+ xc->rvat_chain_pos_valid = 0;
+ }
+ }
+
+if(!xc->rvat_chain_mem)
+ {
+ uint32_t skiplen;
+ fstReaderFseeko(xc, xc->f, xc->rvat_vc_start + xc->rvat_chain_table[facidx], SEEK_SET);
+ xc->rvat_chain_len = fstReaderVarint32WithSkip(xc->f, &skiplen);
+ if(xc->rvat_chain_len)
+ {
+ unsigned char *mu = (unsigned char *)malloc(xc->rvat_chain_len);
+ unsigned char *mc = (unsigned char *)malloc(xc->rvat_chain_table_lengths[facidx]);
+ unsigned long destlen = xc->rvat_chain_len;
+ unsigned long sourcelen = xc->rvat_chain_table_lengths[facidx];
+ int rc = Z_OK;
+
+ fstFread(mc, xc->rvat_chain_table_lengths[facidx], 1, xc->f);
+
+ switch(xc->rvat_packtype)
+ {
+ case '4': rc = (destlen == (unsigned long)LZ4_decompress_safe_partial((char *)mc, (char *)mu, sourcelen, destlen, destlen)) ? Z_OK : Z_DATA_ERROR;
+ break;
+ case 'F': fastlz_decompress(mc, sourcelen, mu, destlen); /* rc appears unreliable */
+ break;
+ default: rc = uncompress(mu, &destlen, mc, sourcelen);
+ break;
+ }
+
+ free(mc);
+
+ if(rc != Z_OK)
+ {
+ fprintf(stderr, FST_APIMESS "fstReaderGetValueFromHandleAtTime(), rvat decompress clen: %d (rc=%d), exiting.\n", (int)xc->rvat_chain_len, rc);
+ exit(255);
+ }
+
+ /* data to process is for(j=0;jrvat_chain_mem = mu;
+ }
+ else
+ {
+ int destlen = xc->rvat_chain_table_lengths[facidx] - skiplen;
+ unsigned char *mu = (unsigned char *)malloc(xc->rvat_chain_len = destlen);
+ fstFread(mu, destlen, 1, xc->f);
+ /* data to process is for(j=0;jrvat_chain_mem = mu;
+ }
+
+ xc->rvat_chain_facidx = facidx;
+ }
+
+/* process value chain here */
+
+{
+uint32_t tidx = 0, ptidx = 0;
+uint32_t tdelta;
+int skiplen;
+unsigned int iprev = xc->rvat_chain_len;
+uint32_t pvli = 0;
+int pskip = 0;
+
+if((xc->rvat_chain_pos_valid)&&(tim >= xc->rvat_chain_pos_time))
+ {
+ i = xc->rvat_chain_pos_idx;
+ tidx = xc->rvat_chain_pos_tidx;
+ }
+ else
+ {
+ i = 0;
+ tidx = 0;
+ xc->rvat_chain_pos_time = xc->rvat_beg_tim;
+ }
+
+if(xc->signal_lens[facidx] == 1)
+ {
+ while(irvat_chain_len)
+ {
+ uint32_t vli = fstGetVarint32(xc->rvat_chain_mem + i, &skiplen);
+ uint32_t shcnt = 2 << (vli & 1);
+ tdelta = vli >> shcnt;
+
+ if(xc->rvat_time_table[tidx + tdelta] <= tim)
+ {
+ iprev = i;
+ pvli = vli;
+ ptidx = tidx;
+ /* pskip = skiplen; */ /* scan-build */
+
+ tidx += tdelta;
+ i+=skiplen;
+ }
+ else
+ {
+ break;
+ }
+ }
+ if(iprev != xc->rvat_chain_len)
+ {
+ xc->rvat_chain_pos_tidx = ptidx;
+ xc->rvat_chain_pos_idx = iprev;
+ xc->rvat_chain_pos_time = tim;
+ xc->rvat_chain_pos_valid = 1;
+
+ if(!(pvli & 1))
+ {
+ buf[0] = ((pvli >> 1) & 1) | '0';
+ }
+ else
+ {
+ buf[0] = FST_RCV_STR[((pvli >> 1) & 7)];
+ }
+ buf[1] = 0;
+ return(buf);
+ }
+ else
+ {
+ return(fstExtractRvatDataFromFrame(xc, facidx, buf));
+ }
+ }
+ else
+ {
+ while(irvat_chain_len)
+ {
+ uint32_t vli = fstGetVarint32(xc->rvat_chain_mem + i, &skiplen);
+ tdelta = vli >> 1;
+
+ if(xc->rvat_time_table[tidx + tdelta] <= tim)
+ {
+ iprev = i;
+ pvli = vli;
+ ptidx = tidx;
+ pskip = skiplen;
+
+ tidx += tdelta;
+ i+=skiplen;
+
+ if(!(pvli & 1))
+ {
+ i+=((xc->signal_lens[facidx]+7)/8);
+ }
+ else
+ {
+ i+=xc->signal_lens[facidx];
+ }
+ }
+ else
+ {
+ break;
+ }
+ }
+
+ if(iprev != xc->rvat_chain_len)
+ {
+ unsigned char *vdata = xc->rvat_chain_mem + iprev + pskip;
+
+ xc->rvat_chain_pos_tidx = ptidx;
+ xc->rvat_chain_pos_idx = iprev;
+ xc->rvat_chain_pos_time = tim;
+ xc->rvat_chain_pos_valid = 1;
+
+ if(xc->signal_typs[facidx] != FST_VT_VCD_REAL)
+ {
+ if(!(pvli & 1))
+ {
+ int byte = 0;
+ int bit;
+ unsigned int j;
+
+ for(j=0;jsignal_lens[facidx];j++)
+ {
+ unsigned char ch;
+ byte = j/8;
+ bit = 7 - (j & 7);
+ ch = ((vdata[byte] >> bit) & 1) | '0';
+ buf[j] = ch;
+ }
+ buf[j] = 0;
+
+ return(buf);
+ }
+ else
+ {
+ memcpy(buf, vdata, xc->signal_lens[facidx]);
+ buf[xc->signal_lens[facidx]] = 0;
+ return(buf);
+ }
+ }
+ else
+ {
+ double d;
+ unsigned char *clone_d = (unsigned char *)&d;
+ unsigned char bufd[8];
+ unsigned char *srcdata;
+
+ if(!(pvli & 1)) /* very rare case, but possible */
+ {
+ int bit;
+ int j;
+
+ for(j=0;j<8;j++)
+ {
+ unsigned char ch;
+ bit = 7 - (j & 7);
+ ch = ((vdata[0] >> bit) & 1) | '0';
+ bufd[j] = ch;
+ }
+
+ srcdata = bufd;
+ }
+ else
+ {
+ srcdata = vdata;
+ }
+
+ if(xc->double_endian_match)
+ {
+ memcpy(clone_d, srcdata, 8);
+ }
+ else
+ {
+ int j;
+
+ for(j=0;j<8;j++)
+ {
+ clone_d[j] = srcdata[7-j];
+ }
+ }
+
+ sprintf(buf, "r%.16g", d);
+ return(buf);
+ }
+ }
+ else
+ {
+ return(fstExtractRvatDataFromFrame(xc, facidx, buf));
+ }
+ }
+}
+
+/* return(NULL); */
+}
+
+
+
+/**********************************************************************/
+#ifndef _WAVE_HAVE_JUDY
+
+/***********************/
+/*** ***/
+/*** jenkins hash ***/
+/*** ***/
+/***********************/
+
+/*
+--------------------------------------------------------------------
+mix -- mix 3 32-bit values reversibly.
+For every delta with one or two bits set, and the deltas of all three
+ high bits or all three low bits, whether the original value of a,b,c
+ is almost all zero or is uniformly distributed,
+* If mix() is run forward or backward, at least 32 bits in a,b,c
+ have at least 1/4 probability of changing.
+* If mix() is run forward, every bit of c will change between 1/3 and
+ 2/3 of the time. (Well, 22/100 and 78/100 for some 2-bit deltas.)
+mix() was built out of 36 single-cycle latency instructions in a
+ structure that could supported 2x parallelism, like so:
+ a -= b;
+ a -= c; x = (c>>13);
+ b -= c; a ^= x;
+ b -= a; x = (a<<8);
+ c -= a; b ^= x;
+ c -= b; x = (b>>13);
+ ...
+ Unfortunately, superscalar Pentiums and Sparcs can't take advantage
+ of that parallelism. They've also turned some of those single-cycle
+ latency instructions into multi-cycle latency instructions. Still,
+ this is the fastest good hash I could find. There were about 2^^68
+ to choose from. I only looked at a billion or so.
+--------------------------------------------------------------------
+*/
+#define mix(a,b,c) \
+{ \
+ a -= b; a -= c; a ^= (c>>13); \
+ b -= c; b -= a; b ^= (a<<8); \
+ c -= a; c -= b; c ^= (b>>13); \
+ a -= b; a -= c; a ^= (c>>12); \
+ b -= c; b -= a; b ^= (a<<16); \
+ c -= a; c -= b; c ^= (b>>5); \
+ a -= b; a -= c; a ^= (c>>3); \
+ b -= c; b -= a; b ^= (a<<10); \
+ c -= a; c -= b; c ^= (b>>15); \
+}
+
+/*
+--------------------------------------------------------------------
+j_hash() -- hash a variable-length key into a 32-bit value
+ k : the key (the unaligned variable-length array of bytes)
+ len : the length of the key, counting by bytes
+ initval : can be any 4-byte value
+Returns a 32-bit value. Every bit of the key affects every bit of
+the return value. Every 1-bit and 2-bit delta achieves avalanche.
+About 6*len+35 instructions.
+
+The best hash table sizes are powers of 2. There is no need to do
+mod a prime (mod is sooo slow!). If you need less than 32 bits,
+use a bitmask. For example, if you need only 10 bits, do
+ h = (h & hashmask(10));
+In which case, the hash table should have hashsize(10) elements.
+
+If you are hashing n strings (uint8_t **)k, do it like this:
+ for (i=0, h=0; i= 12)
+ {
+ a += (k[0] +((uint32_t)k[1]<<8) +((uint32_t)k[2]<<16) +((uint32_t)k[3]<<24));
+ b += (k[4] +((uint32_t)k[5]<<8) +((uint32_t)k[6]<<16) +((uint32_t)k[7]<<24));
+ c += (k[8] +((uint32_t)k[9]<<8) +((uint32_t)k[10]<<16)+((uint32_t)k[11]<<24));
+ mix(a,b,c);
+ k += 12; len -= 12;
+ }
+
+ /*------------------------------------- handle the last 11 bytes */
+ c += length;
+ switch(len) /* all the case statements fall through */
+ {
+ case 11: c+=((uint32_t)k[10]<<24); /* fallthrough */
+ case 10: c+=((uint32_t)k[9]<<16); /* fallthrough */
+ case 9 : c+=((uint32_t)k[8]<<8); /* fallthrough */
+ /* the first byte of c is reserved for the length */
+ case 8 : b+=((uint32_t)k[7]<<24); /* fallthrough */
+ case 7 : b+=((uint32_t)k[6]<<16); /* fallthrough */
+ case 6 : b+=((uint32_t)k[5]<<8); /* fallthrough */
+ case 5 : b+=k[4]; /* fallthrough */
+ case 4 : a+=((uint32_t)k[3]<<24); /* fallthrough */
+ case 3 : a+=((uint32_t)k[2]<<16); /* fallthrough */
+ case 2 : a+=((uint32_t)k[1]<<8); /* fallthrough */
+ case 1 : a+=k[0];
+ /* case 0: nothing left to add */
+ }
+ mix(a,b,c);
+ /*-------------------------------------------- report the result */
+ return(c);
+}
+
+/********************************************************************/
+
+/***************************/
+/*** ***/
+/*** judy HS emulation ***/
+/*** ***/
+/***************************/
+
+struct collchain_t
+{
+struct collchain_t *next;
+void *payload;
+uint32_t fullhash, length;
+unsigned char mem[1];
+};
+
+
+void **JenkinsIns(void *base_i, const unsigned char *mem, uint32_t length, uint32_t hashmask)
+{
+struct collchain_t ***base = (struct collchain_t ***)base_i;
+uint32_t hf, h;
+struct collchain_t **ar;
+struct collchain_t *chain, *pchain;
+
+if(!*base)
+ {
+ *base = (struct collchain_t **)calloc(1, (hashmask + 1) * sizeof(void *));
+ }
+ar = *base;
+
+h = (hf = j_hash(mem, length, length)) & hashmask;
+pchain = chain = ar[h];
+while(chain)
+ {
+ if((chain->fullhash == hf) && (chain->length == length) && !memcmp(chain->mem, mem, length))
+ {
+ if(pchain != chain) /* move hit to front */
+ {
+ pchain->next = chain->next;
+ chain->next = ar[h];
+ ar[h] = chain;
+ }
+ return(&(chain->payload));
+ }
+
+ pchain = chain;
+ chain = chain->next;
+ }
+
+chain = (struct collchain_t *)calloc(1, sizeof(struct collchain_t) + length - 1);
+memcpy(chain->mem, mem, length);
+chain->fullhash = hf;
+chain->length = length;
+chain->next = ar[h];
+ar[h] = chain;
+return(&(chain->payload));
+}
+
+
+void JenkinsFree(void *base_i, uint32_t hashmask)
+{
+struct collchain_t ***base = (struct collchain_t ***)base_i;
+uint32_t h;
+struct collchain_t **ar;
+struct collchain_t *chain, *chain_next;
+
+if(base && *base)
+ {
+ ar = *base;
+ for(h=0;h<=hashmask;h++)
+ {
+ chain = ar[h];
+ while(chain)
+ {
+ chain_next = chain->next;
+ free(chain);
+ chain = chain_next;
+ }
+ }
+
+ free(*base);
+ *base = NULL;
+ }
+}
+
+#endif
+
+/**********************************************************************/
+
+/************************/
+/*** ***/
+/*** utility function ***/
+/*** ***/
+/************************/
+
+int fstUtilityBinToEscConvertedLen(const unsigned char *s, int len)
+{
+const unsigned char *src = s;
+int dlen = 0;
+int i;
+
+for(i=0;i ' ') && (src[i] <= '~')) /* no white spaces in output */
+ {
+ dlen++;
+ }
+ else
+ {
+ dlen += 4;
+ }
+ break;
+ }
+ }
+
+return(dlen);
+}
+
+
+int fstUtilityBinToEsc(unsigned char *d, const unsigned char *s, int len)
+{
+const unsigned char *src = s;
+unsigned char *dst = d;
+unsigned char val;
+int i;
+
+for(i=0;i ' ') && (src[i] <= '~')) /* no white spaces in output */
+ {
+ *(dst++) = src[i];
+ }
+ else
+ {
+ val = src[i];
+ *(dst++) = '\\';
+ *(dst++) = (val/64) + '0'; val = val & 63;
+ *(dst++) = (val/8) + '0'; val = val & 7;
+ *(dst++) = (val) + '0';
+ }
+ break;
+ }
+ }
+
+return(dst - d);
+}
+
+
+/*
+ * this overwrites the original string if the destination pointer is NULL
+ */
+int fstUtilityEscToBin(unsigned char *d, unsigned char *s, int len)
+{
+unsigned char *src = s;
+unsigned char *dst = (!d) ? s : (s = d);
+unsigned char val[3];
+int i;
+
+for(i=0;i='A')&&(val[0]<='F')) ? (val[0] - 'A' + 10) : (val[0] - '0');
+ val[1] = ((val[1]>='A')&&(val[1]<='F')) ? (val[1] - 'A' + 10) : (val[1] - '0');
+ *(dst++) = val[0] * 16 + val[1];
+ break;
+
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7': val[0] = src[ i] - '0';
+ val[1] = src[++i] - '0';
+ val[2] = src[++i] - '0';
+ *(dst++) = val[0] * 64 + val[1] * 8 + val[2];
+ break;
+
+ default: *(dst++) = src[i]; break;
+ }
+ }
+ }
+
+return(dst - s);
+}
+
+
+struct fstETab *fstUtilityExtractEnumTableFromString(const char *s)
+{
+struct fstETab *et = NULL;
+int num_spaces = 0;
+int i;
+int newlen;
+
+if(s)
+ {
+ const char *csp = strchr(s, ' ');
+ int cnt = atoi(csp+1);
+
+ for(;;)
+ {
+ csp = strchr(csp+1, ' ');
+ if(csp) { num_spaces++; } else { break; }
+ }
+
+ if(num_spaces == (2*cnt))
+ {
+ char *sp, *sp2;
+
+ et = (struct fstETab*)calloc(1, sizeof(struct fstETab));
+ et->elem_count = cnt;
+ et->name = strdup(s);
+ et->literal_arr = (char**)calloc(cnt, sizeof(char *));
+ et->val_arr = (char**)calloc(cnt, sizeof(char *));
+
+ sp = strchr(et->name, ' ');
+ *sp = 0;
+
+ sp = strchr(sp+1, ' ');
+
+ for(i=0;iliteral_arr[i] = sp+1;
+ sp = sp2;
+
+ newlen = fstUtilityEscToBin(NULL, (unsigned char*)et->literal_arr[i], strlen(et->literal_arr[i]));
+ et->literal_arr[i][newlen] = 0;
+ }
+
+ for(i=0;ival_arr[i] = sp+1;
+ sp = sp2;
+
+ newlen = fstUtilityEscToBin(NULL, (unsigned char*)et->val_arr[i], strlen(et->val_arr[i]));
+ et->val_arr[i][newlen] = 0;
+ }
+ }
+ }
+
+return(et);
+}
+
+
+void fstUtilityFreeEnumTable(struct fstETab *etab)
+{
+if(etab)
+ {
+ free(etab->literal_arr);
+ free(etab->val_arr);
+ free(etab->name);
+ free(etab);
+ }
+}
diff --git a/plugins/com.minres.scviewer.database.fst/csrc/fst/fstapi.h b/plugins/com.minres.scviewer.database.fst/csrc/fst/fstapi.h
new file mode 100644
index 0000000..5402ecb
--- /dev/null
+++ b/plugins/com.minres.scviewer.database.fst/csrc/fst/fstapi.h
@@ -0,0 +1,466 @@
+/*
+ * Copyright (c) 2009-2018 Tony Bybell.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * SPDX-License-Identifier: MIT
+ */
+
+#ifndef FST_API_H
+#define FST_API_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include
+#include
+#include
+#include
+#include
+#include
+#if defined(_MSC_VER)
+ #include "fst_win_unistd.h"
+#else
+ #include
+#endif
+#include
+
+#define FST_RDLOAD "FSTLOAD | "
+
+typedef uint32_t fstHandle;
+typedef uint32_t fstEnumHandle;
+
+enum fstWriterPackType {
+ FST_WR_PT_ZLIB = 0,
+ FST_WR_PT_FASTLZ = 1,
+ FST_WR_PT_LZ4 = 2
+};
+
+enum fstFileType {
+ FST_FT_MIN = 0,
+
+ FST_FT_VERILOG = 0,
+ FST_FT_VHDL = 1,
+ FST_FT_VERILOG_VHDL = 2,
+
+ FST_FT_MAX = 2
+};
+
+enum fstBlockType {
+ FST_BL_HDR = 0,
+ FST_BL_VCDATA = 1,
+ FST_BL_BLACKOUT = 2,
+ FST_BL_GEOM = 3,
+ FST_BL_HIER = 4,
+ FST_BL_VCDATA_DYN_ALIAS = 5,
+ FST_BL_HIER_LZ4 = 6,
+ FST_BL_HIER_LZ4DUO = 7,
+ FST_BL_VCDATA_DYN_ALIAS2 = 8,
+
+ FST_BL_ZWRAPPER = 254, /* indicates that whole trace is gz wrapped */
+ FST_BL_SKIP = 255 /* used while block is being written */
+};
+
+enum fstScopeType {
+ FST_ST_MIN = 0,
+
+ FST_ST_VCD_MODULE = 0,
+ FST_ST_VCD_TASK = 1,
+ FST_ST_VCD_FUNCTION = 2,
+ FST_ST_VCD_BEGIN = 3,
+ FST_ST_VCD_FORK = 4,
+ FST_ST_VCD_GENERATE = 5,
+ FST_ST_VCD_STRUCT = 6,
+ FST_ST_VCD_UNION = 7,
+ FST_ST_VCD_CLASS = 8,
+ FST_ST_VCD_INTERFACE = 9,
+ FST_ST_VCD_PACKAGE = 10,
+ FST_ST_VCD_PROGRAM = 11,
+
+ FST_ST_VHDL_ARCHITECTURE = 12,
+ FST_ST_VHDL_PROCEDURE = 13,
+ FST_ST_VHDL_FUNCTION = 14,
+ FST_ST_VHDL_RECORD = 15,
+ FST_ST_VHDL_PROCESS = 16,
+ FST_ST_VHDL_BLOCK = 17,
+ FST_ST_VHDL_FOR_GENERATE = 18,
+ FST_ST_VHDL_IF_GENERATE = 19,
+ FST_ST_VHDL_GENERATE = 20,
+ FST_ST_VHDL_PACKAGE = 21,
+
+ FST_ST_MAX = 21,
+
+ FST_ST_GEN_ATTRBEGIN = 252,
+ FST_ST_GEN_ATTREND = 253,
+
+ FST_ST_VCD_SCOPE = 254,
+ FST_ST_VCD_UPSCOPE = 255
+};
+
+enum fstVarType {
+ FST_VT_MIN = 0, /* start of vartypes */
+
+ FST_VT_VCD_EVENT = 0,
+ FST_VT_VCD_INTEGER = 1,
+ FST_VT_VCD_PARAMETER = 2,
+ FST_VT_VCD_REAL = 3,
+ FST_VT_VCD_REAL_PARAMETER = 4,
+ FST_VT_VCD_REG = 5,
+ FST_VT_VCD_SUPPLY0 = 6,
+ FST_VT_VCD_SUPPLY1 = 7,
+ FST_VT_VCD_TIME = 8,
+ FST_VT_VCD_TRI = 9,
+ FST_VT_VCD_TRIAND = 10,
+ FST_VT_VCD_TRIOR = 11,
+ FST_VT_VCD_TRIREG = 12,
+ FST_VT_VCD_TRI0 = 13,
+ FST_VT_VCD_TRI1 = 14,
+ FST_VT_VCD_WAND = 15,
+ FST_VT_VCD_WIRE = 16,
+ FST_VT_VCD_WOR = 17,
+ FST_VT_VCD_PORT = 18,
+ FST_VT_VCD_SPARRAY = 19, /* used to define the rownum (index) port for a sparse array */
+ FST_VT_VCD_REALTIME = 20,
+
+ FST_VT_GEN_STRING = 21, /* generic string type (max len is defined dynamically via fstWriterEmitVariableLengthValueChange) */
+
+ FST_VT_SV_BIT = 22,
+ FST_VT_SV_LOGIC = 23,
+ FST_VT_SV_INT = 24, /* declare as size = 32 */
+ FST_VT_SV_SHORTINT = 25, /* declare as size = 16 */
+ FST_VT_SV_LONGINT = 26, /* declare as size = 64 */
+ FST_VT_SV_BYTE = 27, /* declare as size = 8 */
+ FST_VT_SV_ENUM = 28, /* declare as appropriate type range */
+ FST_VT_SV_SHORTREAL = 29, /* declare and emit same as FST_VT_VCD_REAL (needs to be emitted as double, not a float) */
+
+ FST_VT_MAX = 29 /* end of vartypes */
+};
+
+enum fstVarDir {
+ FST_VD_MIN = 0,
+
+ FST_VD_IMPLICIT = 0,
+ FST_VD_INPUT = 1,
+ FST_VD_OUTPUT = 2,
+ FST_VD_INOUT = 3,
+ FST_VD_BUFFER = 4,
+ FST_VD_LINKAGE = 5,
+
+ FST_VD_MAX = 5
+};
+
+enum fstHierType {
+ FST_HT_MIN = 0,
+
+ FST_HT_SCOPE = 0,
+ FST_HT_UPSCOPE = 1,
+ FST_HT_VAR = 2,
+ FST_HT_ATTRBEGIN = 3,
+ FST_HT_ATTREND = 4,
+
+ /* FST_HT_TREEBEGIN and FST_HT_TREEEND are not yet used by FST but are currently used when fstHier bridges other formats */
+ FST_HT_TREEBEGIN = 5,
+ FST_HT_TREEEND = 6,
+
+ FST_HT_MAX = 6
+};
+
+enum fstAttrType {
+ FST_AT_MIN = 0,
+
+ FST_AT_MISC = 0, /* self-contained: does not need matching FST_HT_ATTREND */
+ FST_AT_ARRAY = 1,
+ FST_AT_ENUM = 2,
+ FST_AT_PACK = 3,
+
+ FST_AT_MAX = 3
+};
+
+enum fstMiscType {
+ FST_MT_MIN = 0,
+
+ FST_MT_COMMENT = 0, /* use fstWriterSetComment() to emit */
+ FST_MT_ENVVAR = 1, /* use fstWriterSetEnvVar() to emit */
+ FST_MT_SUPVAR = 2, /* use fstWriterCreateVar2() to emit */
+ FST_MT_PATHNAME = 3, /* reserved for fstWriterSetSourceStem() string -> number management */
+ FST_MT_SOURCESTEM = 4, /* use fstWriterSetSourceStem() to emit */
+ FST_MT_SOURCEISTEM = 5, /* use fstWriterSetSourceInstantiationStem() to emit */
+ FST_MT_VALUELIST = 6, /* use fstWriterSetValueList() to emit, followed by fstWriterCreateVar*() */
+ FST_MT_ENUMTABLE = 7, /* use fstWriterCreateEnumTable() and fstWriterEmitEnumTableRef() to emit */
+ FST_MT_UNKNOWN = 8,
+
+ FST_MT_MAX = 8
+};
+
+enum fstArrayType {
+ FST_AR_MIN = 0,
+
+ FST_AR_NONE = 0,
+ FST_AR_UNPACKED = 1,
+ FST_AR_PACKED = 2,
+ FST_AR_SPARSE = 3,
+
+ FST_AR_MAX = 3
+};
+
+enum fstEnumValueType {
+ FST_EV_SV_INTEGER = 0,
+ FST_EV_SV_BIT = 1,
+ FST_EV_SV_LOGIC = 2,
+ FST_EV_SV_INT = 3,
+ FST_EV_SV_SHORTINT = 4,
+ FST_EV_SV_LONGINT = 5,
+ FST_EV_SV_BYTE = 6,
+ FST_EV_SV_UNSIGNED_INTEGER = 7,
+ FST_EV_SV_UNSIGNED_BIT = 8,
+ FST_EV_SV_UNSIGNED_LOGIC = 9,
+ FST_EV_SV_UNSIGNED_INT = 10,
+ FST_EV_SV_UNSIGNED_SHORTINT = 11,
+ FST_EV_SV_UNSIGNED_LONGINT = 12,
+ FST_EV_SV_UNSIGNED_BYTE = 13,
+
+ FST_EV_REG = 14,
+ FST_EV_TIME = 15,
+
+ FST_EV_MAX = 15
+};
+
+enum fstPackType {
+ FST_PT_NONE = 0,
+ FST_PT_UNPACKED = 1,
+ FST_PT_PACKED = 2,
+ FST_PT_TAGGED_PACKED = 3,
+
+ FST_PT_MAX = 3
+};
+
+enum fstSupplementalVarType {
+ FST_SVT_MIN = 0,
+
+ FST_SVT_NONE = 0,
+
+ FST_SVT_VHDL_SIGNAL = 1,
+ FST_SVT_VHDL_VARIABLE = 2,
+ FST_SVT_VHDL_CONSTANT = 3,
+ FST_SVT_VHDL_FILE = 4,
+ FST_SVT_VHDL_MEMORY = 5,
+
+ FST_SVT_MAX = 5
+};
+
+enum fstSupplementalDataType {
+ FST_SDT_MIN = 0,
+
+ FST_SDT_NONE = 0,
+
+ FST_SDT_VHDL_BOOLEAN = 1,
+ FST_SDT_VHDL_BIT = 2,
+ FST_SDT_VHDL_BIT_VECTOR = 3,
+ FST_SDT_VHDL_STD_ULOGIC = 4,
+ FST_SDT_VHDL_STD_ULOGIC_VECTOR = 5,
+ FST_SDT_VHDL_STD_LOGIC = 6,
+ FST_SDT_VHDL_STD_LOGIC_VECTOR = 7,
+ FST_SDT_VHDL_UNSIGNED = 8,
+ FST_SDT_VHDL_SIGNED = 9,
+ FST_SDT_VHDL_INTEGER = 10,
+ FST_SDT_VHDL_REAL = 11,
+ FST_SDT_VHDL_NATURAL = 12,
+ FST_SDT_VHDL_POSITIVE = 13,
+ FST_SDT_VHDL_TIME = 14,
+ FST_SDT_VHDL_CHARACTER = 15,
+ FST_SDT_VHDL_STRING = 16,
+
+ FST_SDT_MAX = 16,
+
+ FST_SDT_SVT_SHIFT_COUNT = 10, /* FST_SVT_* is ORed in by fstWriterCreateVar2() to the left after shifting FST_SDT_SVT_SHIFT_COUNT */
+ FST_SDT_ABS_MAX = ((1<<(FST_SDT_SVT_SHIFT_COUNT))-1)
+};
+
+
+struct fstHier
+{
+unsigned char htyp;
+
+union {
+ /* if htyp == FST_HT_SCOPE */
+ struct fstHierScope {
+ unsigned char typ; /* FST_ST_MIN ... FST_ST_MAX */
+ const char *name;
+ const char *component;
+ uint32_t name_length; /* strlen(u.scope.name) */
+ uint32_t component_length; /* strlen(u.scope.component) */
+ } scope;
+
+ /* if htyp == FST_HT_VAR */
+ struct fstHierVar {
+ unsigned char typ; /* FST_VT_MIN ... FST_VT_MAX */
+ unsigned char direction; /* FST_VD_MIN ... FST_VD_MAX */
+ unsigned char svt_workspace; /* zeroed out by FST reader, for client code use */
+ unsigned char sdt_workspace; /* zeroed out by FST reader, for client code use */
+ unsigned int sxt_workspace; /* zeroed out by FST reader, for client code use */
+ const char *name;
+ uint32_t length;
+ fstHandle handle;
+ uint32_t name_length; /* strlen(u.var.name) */
+ unsigned is_alias : 1;
+ } var;
+
+ /* if htyp == FST_HT_ATTRBEGIN */
+ struct fstHierAttr {
+ unsigned char typ; /* FST_AT_MIN ... FST_AT_MAX */
+ unsigned char subtype; /* from fstMiscType, fstArrayType, fstEnumValueType, fstPackType */
+ const char *name;
+ uint64_t arg; /* number of array elements, struct members, or some other payload (possibly ignored) */
+ uint64_t arg_from_name; /* for when name is overloaded as a variable-length integer (FST_AT_MISC + FST_MT_SOURCESTEM) */
+ uint32_t name_length; /* strlen(u.attr.name) */
+ } attr;
+ } u;
+};
+
+
+struct fstETab
+{
+char *name;
+uint32_t elem_count;
+char **literal_arr;
+char **val_arr;
+};
+
+
+/*
+ * writer functions
+ */
+void fstWriterClose(void *ctx);
+void * fstWriterCreate(const char *nam, int use_compressed_hier);
+fstEnumHandle fstWriterCreateEnumTable(void *ctx, const char *name, uint32_t elem_count, unsigned int min_valbits, const char **literal_arr, const char **val_arr);
+ /* used for Verilog/SV */
+fstHandle fstWriterCreateVar(void *ctx, enum fstVarType vt, enum fstVarDir vd,
+ uint32_t len, const char *nam, fstHandle aliasHandle);
+ /* future expansion for VHDL and other languages. The variable type, data type, etc map onto
+ the current Verilog/SV one. The "type" string is optional for a more verbose or custom description */
+fstHandle fstWriterCreateVar2(void *ctx, enum fstVarType vt, enum fstVarDir vd,
+ uint32_t len, const char *nam, fstHandle aliasHandle,
+ const char *type, enum fstSupplementalVarType svt, enum fstSupplementalDataType sdt);
+void fstWriterEmitDumpActive(void *ctx, int enable);
+void fstWriterEmitEnumTableRef(void *ctx, fstEnumHandle handle);
+void fstWriterEmitValueChange(void *ctx, fstHandle handle, const void *val);
+void fstWriterEmitValueChange32(void *ctx, fstHandle handle,
+ uint32_t bits, uint32_t val);
+void fstWriterEmitValueChange64(void *ctx, fstHandle handle,
+ uint32_t bits, uint64_t val);
+void fstWriterEmitValueChangeVec32(void *ctx, fstHandle handle,
+ uint32_t bits, const uint32_t *val);
+void fstWriterEmitValueChangeVec64(void *ctx, fstHandle handle,
+ uint32_t bits, const uint64_t *val);
+void fstWriterEmitVariableLengthValueChange(void *ctx, fstHandle handle, const void *val, uint32_t len);
+void fstWriterEmitTimeChange(void *ctx, uint64_t tim);
+void fstWriterFlushContext(void *ctx);
+int fstWriterGetDumpSizeLimitReached(void *ctx);
+int fstWriterGetFseekFailed(void *ctx);
+void fstWriterSetAttrBegin(void *ctx, enum fstAttrType attrtype, int subtype,
+ const char *attrname, uint64_t arg);
+void fstWriterSetAttrEnd(void *ctx);
+void fstWriterSetComment(void *ctx, const char *comm);
+void fstWriterSetDate(void *ctx, const char *dat);
+void fstWriterSetDumpSizeLimit(void *ctx, uint64_t numbytes);
+void fstWriterSetEnvVar(void *ctx, const char *envvar);
+void fstWriterSetFileType(void *ctx, enum fstFileType filetype);
+void fstWriterSetPackType(void *ctx, enum fstWriterPackType typ);
+void fstWriterSetParallelMode(void *ctx, int enable);
+void fstWriterSetRepackOnClose(void *ctx, int enable); /* type = 0 (none), 1 (libz) */
+void fstWriterSetScope(void *ctx, enum fstScopeType scopetype,
+ const char *scopename, const char *scopecomp);
+void fstWriterSetSourceInstantiationStem(void *ctx, const char *path, unsigned int line, unsigned int use_realpath);
+void fstWriterSetSourceStem(void *ctx, const char *path, unsigned int line, unsigned int use_realpath);
+void fstWriterSetTimescale(void *ctx, int ts);
+void fstWriterSetTimescaleFromString(void *ctx, const char *s);
+void fstWriterSetTimezero(void *ctx, int64_t tim);
+void fstWriterSetUpscope(void *ctx);
+void fstWriterSetValueList(void *ctx, const char *vl);
+void fstWriterSetVersion(void *ctx, const char *vers);
+
+
+/*
+ * reader functions
+ */
+void fstReaderClose(void *ctx);
+void fstReaderClrFacProcessMask(void *ctx, fstHandle facidx);
+void fstReaderClrFacProcessMaskAll(void *ctx);
+uint64_t fstReaderGetAliasCount(void *ctx);
+const char * fstReaderGetCurrentFlatScope(void *ctx);
+void * fstReaderGetCurrentScopeUserInfo(void *ctx);
+int fstReaderGetCurrentScopeLen(void *ctx);
+const char * fstReaderGetDateString(void *ctx);
+int fstReaderGetDoubleEndianMatchState(void *ctx);
+uint64_t fstReaderGetDumpActivityChangeTime(void *ctx, uint32_t idx);
+unsigned char fstReaderGetDumpActivityChangeValue(void *ctx, uint32_t idx);
+uint64_t fstReaderGetEndTime(void *ctx);
+int fstReaderGetFacProcessMask(void *ctx, fstHandle facidx);
+int fstReaderGetFileType(void *ctx);
+int fstReaderGetFseekFailed(void *ctx);
+fstHandle fstReaderGetMaxHandle(void *ctx);
+uint64_t fstReaderGetMemoryUsedByWriter(void *ctx);
+uint32_t fstReaderGetNumberDumpActivityChanges(void *ctx);
+uint64_t fstReaderGetScopeCount(void *ctx);
+uint64_t fstReaderGetStartTime(void *ctx);
+signed char fstReaderGetTimescale(void *ctx);
+int64_t fstReaderGetTimezero(void *ctx);
+uint64_t fstReaderGetValueChangeSectionCount(void *ctx);
+char * fstReaderGetValueFromHandleAtTime(void *ctx, uint64_t tim, fstHandle facidx, char *buf);
+uint64_t fstReaderGetVarCount(void *ctx);
+const char * fstReaderGetVersionString(void *ctx);
+struct fstHier *fstReaderIterateHier(void *ctx);
+int fstReaderIterateHierRewind(void *ctx);
+int fstReaderIterBlocks(void *ctx,
+ void (*value_change_callback)(void *user_callback_data_pointer, uint64_t time, fstHandle facidx, const unsigned char *value),
+ void *user_callback_data_pointer, FILE *vcdhandle);
+int fstReaderIterBlocks2(void *ctx,
+ void (*value_change_callback)(void *user_callback_data_pointer, uint64_t time, fstHandle facidx, const unsigned char *value),
+ void (*value_change_callback_varlen)(void *user_callback_data_pointer, uint64_t time, fstHandle facidx, const unsigned char *value, uint32_t len),
+ void *user_callback_data_pointer, FILE *vcdhandle);
+void fstReaderIterBlocksSetNativeDoublesOnCallback(void *ctx, int enable);
+void * fstReaderOpen(const char *nam);
+void * fstReaderOpenForUtilitiesOnly(void);
+const char * fstReaderPopScope(void *ctx);
+int fstReaderProcessHier(void *ctx, FILE *vcdhandle);
+const char * fstReaderPushScope(void *ctx, const char *nam, void *user_info);
+void fstReaderResetScope(void *ctx);
+void fstReaderSetFacProcessMask(void *ctx, fstHandle facidx);
+void fstReaderSetFacProcessMaskAll(void *ctx);
+void fstReaderSetLimitTimeRange(void *ctx, uint64_t start_time, uint64_t end_time);
+void fstReaderSetUnlimitedTimeRange(void *ctx);
+void fstReaderSetVcdExtensions(void *ctx, int enable);
+
+
+/*
+ * utility functions
+ */
+int fstUtilityBinToEscConvertedLen(const unsigned char *s, int len); /* used for mallocs for fstUtilityBinToEsc() */
+int fstUtilityBinToEsc(unsigned char *d, const unsigned char *s, int len);
+int fstUtilityEscToBin(unsigned char *d, unsigned char *s, int len);
+struct fstETab *fstUtilityExtractEnumTableFromString(const char *s);
+void fstUtilityFreeEnumTable(struct fstETab *etab); /* must use to free fstETab properly */
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/plugins/com.minres.scviewer.database.fst/csrc/fst/lz4.c b/plugins/com.minres.scviewer.database.fst/csrc/fst/lz4.c
new file mode 100644
index 0000000..55dc1a8
--- /dev/null
+++ b/plugins/com.minres.scviewer.database.fst/csrc/fst/lz4.c
@@ -0,0 +1,1521 @@
+/*
+ LZ4 - Fast LZ compression algorithm
+ Copyright (C) 2011-2015, Yann Collet.
+
+ BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are
+ met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following disclaimer
+ in the documentation and/or other materials provided with the
+ distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ SPDX-License-Identifier: BSD-2-Clause
+
+ You can contact the author at :
+ - LZ4 source repository : https://github.com/Cyan4973/lz4
+ - LZ4 public forum : https://groups.google.com/forum/#!forum/lz4c
+*/
+
+
+/**************************************
+* Tuning parameters
+**************************************/
+/*
+ * HEAPMODE :
+ * Select how default compression functions will allocate memory for their hash table,
+ * in memory stack (0:default, fastest), or in memory heap (1:requires malloc()).
+ */
+#define HEAPMODE 0
+
+/*
+ * ACCELERATION_DEFAULT :
+ * Select "acceleration" for LZ4_compress_fast() when parameter value <= 0
+ */
+#define ACCELERATION_DEFAULT 1
+
+
+/**************************************
+* CPU Feature Detection
+**************************************/
+/*
+ * LZ4_FORCE_SW_BITCOUNT
+ * Define this parameter if your target system or compiler does not support hardware bit count
+ */
+#if defined(_MSC_VER) && defined(_WIN32_WCE) /* Visual Studio for Windows CE does not support Hardware bit count */
+# define LZ4_FORCE_SW_BITCOUNT
+#endif
+
+
+/**************************************
+* Includes
+**************************************/
+#include "lz4.h"
+
+
+/**************************************
+* Compiler Options
+**************************************/
+#ifdef _MSC_VER /* Visual Studio */
+# define FORCE_INLINE static __forceinline
+# include
+# pragma warning(disable : 4127) /* disable: C4127: conditional expression is constant */
+# pragma warning(disable : 4293) /* disable: C4293: too large shift (32-bits) */
+#else
+# if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */
+# if defined(__GNUC__) || defined(__clang__)
+# define FORCE_INLINE static inline __attribute__((always_inline))
+# else
+# define FORCE_INLINE static inline
+# endif
+# else
+# define FORCE_INLINE static
+# endif /* __STDC_VERSION__ */
+#endif /* _MSC_VER */
+
+/* LZ4_GCC_VERSION is defined into lz4.h */
+#if (LZ4_GCC_VERSION >= 302) || (__INTEL_COMPILER >= 800) || defined(__clang__)
+# define expect(expr,value) (__builtin_expect ((expr),(value)) )
+#else
+# define expect(expr,value) (expr)
+#endif
+
+#define likely(expr) expect((expr) != 0, 1)
+#define unlikely(expr) expect((expr) != 0, 0)
+
+
+/**************************************
+* Memory routines
+**************************************/
+#include /* malloc, calloc, free */
+#define ALLOCATOR(n,s) calloc(n,s)
+#define FREEMEM free
+#include /* memset, memcpy */
+#define MEM_INIT memset
+
+
+/**************************************
+* Basic Types
+**************************************/
+#if defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */
+# include
+ typedef uint8_t BYTE;
+ typedef uint16_t U16;
+ typedef uint32_t U32;
+ typedef int32_t S32;
+ typedef uint64_t U64;
+#else
+ typedef unsigned char BYTE;
+ typedef unsigned short U16;
+ typedef unsigned int U32;
+ typedef signed int S32;
+ typedef unsigned long long U64;
+#endif
+
+
+/**************************************
+* Reading and writing into memory
+**************************************/
+#define STEPSIZE sizeof(size_t)
+
+static unsigned LZ4_64bits(void) { return sizeof(void*)==8; }
+
+static unsigned LZ4_isLittleEndian(void)
+{
+ const union { U32 i; BYTE c[4]; } one = { 1 }; /* don't use static : performance detrimental */
+ return one.c[0];
+}
+
+
+static U16 LZ4_read16(const void* memPtr)
+{
+ U16 val16;
+ memcpy(&val16, memPtr, 2);
+ return val16;
+}
+
+static U16 LZ4_readLE16(const void* memPtr)
+{
+ if (LZ4_isLittleEndian())
+ {
+ return LZ4_read16(memPtr);
+ }
+ else
+ {
+ const BYTE* p = (const BYTE*)memPtr;
+ return (U16)((U16)p[0] + (p[1]<<8));
+ }
+}
+
+static void LZ4_writeLE16(void* memPtr, U16 value)
+{
+ if (LZ4_isLittleEndian())
+ {
+ memcpy(memPtr, &value, 2);
+ }
+ else
+ {
+ BYTE* p = (BYTE*)memPtr;
+ p[0] = (BYTE) value;
+ p[1] = (BYTE)(value>>8);
+ }
+}
+
+static U32 LZ4_read32(const void* memPtr)
+{
+ U32 val32;
+ memcpy(&val32, memPtr, 4);
+ return val32;
+}
+
+static U64 LZ4_read64(const void* memPtr)
+{
+ U64 val64;
+ memcpy(&val64, memPtr, 8);
+ return val64;
+}
+
+static size_t LZ4_read_ARCH(const void* p)
+{
+ if (LZ4_64bits())
+ return (size_t)LZ4_read64(p);
+ else
+ return (size_t)LZ4_read32(p);
+}
+
+
+static void LZ4_copy4(void* dstPtr, const void* srcPtr) { memcpy(dstPtr, srcPtr, 4); }
+
+static void LZ4_copy8(void* dstPtr, const void* srcPtr) { memcpy(dstPtr, srcPtr, 8); }
+
+/* customized version of memcpy, which may overwrite up to 7 bytes beyond dstEnd */
+static void LZ4_wildCopy(void* dstPtr, const void* srcPtr, void* dstEnd)
+{
+ BYTE* d = (BYTE*)dstPtr;
+ const BYTE* s = (const BYTE*)srcPtr;
+ BYTE* e = (BYTE*)dstEnd;
+ do { LZ4_copy8(d,s); d+=8; s+=8; } while (d>3);
+# elif (defined(__clang__) || (LZ4_GCC_VERSION >= 304)) && !defined(LZ4_FORCE_SW_BITCOUNT)
+ return (__builtin_ctzll((U64)val) >> 3);
+# else
+ static const int DeBruijnBytePos[64] = { 0, 0, 0, 0, 0, 1, 1, 2, 0, 3, 1, 3, 1, 4, 2, 7, 0, 2, 3, 6, 1, 5, 3, 5, 1, 3, 4, 4, 2, 5, 6, 7, 7, 0, 1, 2, 3, 3, 4, 6, 2, 6, 5, 5, 3, 4, 5, 6, 7, 1, 2, 4, 6, 4, 4, 5, 7, 2, 6, 5, 7, 6, 7, 7 };
+ return DeBruijnBytePos[((U64)((val & -(long long)val) * 0x0218A392CDABBD3FULL)) >> 58];
+# endif
+ }
+ else /* 32 bits */
+ {
+# if defined(_MSC_VER) && !defined(LZ4_FORCE_SW_BITCOUNT)
+ unsigned long r;
+ _BitScanForward( &r, (U32)val );
+ return (int)(r>>3);
+# elif (defined(__clang__) || (LZ4_GCC_VERSION >= 304)) && !defined(LZ4_FORCE_SW_BITCOUNT)
+ return (__builtin_ctz((U32)val) >> 3);
+# else
+ static const int DeBruijnBytePos[32] = { 0, 0, 3, 0, 3, 1, 3, 0, 3, 2, 2, 1, 3, 2, 0, 1, 3, 3, 1, 2, 2, 2, 2, 0, 3, 1, 2, 0, 1, 0, 1, 1 };
+ return DeBruijnBytePos[((U32)((val & -(S32)val) * 0x077CB531U)) >> 27];
+# endif
+ }
+ }
+ else /* Big Endian CPU */
+ {
+ if (LZ4_64bits())
+ {
+# if defined(_MSC_VER) && defined(_WIN64) && !defined(LZ4_FORCE_SW_BITCOUNT)
+ unsigned long r = 0;
+ _BitScanReverse64( &r, val );
+ return (unsigned)(r>>3);
+# elif (defined(__clang__) || (LZ4_GCC_VERSION >= 304)) && !defined(LZ4_FORCE_SW_BITCOUNT)
+ return (__builtin_clzll((U64)val) >> 3);
+# else
+ unsigned r;
+ if (!(val>>32)) { r=4; } else { r=0; val>>=32; }
+ if (!(val>>16)) { r+=2; val>>=8; } else { val>>=24; }
+ r += (!val);
+ return r;
+# endif
+ }
+ else /* 32 bits */
+ {
+# if defined(_MSC_VER) && !defined(LZ4_FORCE_SW_BITCOUNT)
+ unsigned long r = 0;
+ _BitScanReverse( &r, (unsigned long)val );
+ return (unsigned)(r>>3);
+# elif (defined(__clang__) || (LZ4_GCC_VERSION >= 304)) && !defined(LZ4_FORCE_SW_BITCOUNT)
+ return (__builtin_clz((U32)val) >> 3);
+# else
+ unsigned r;
+ if (!(val>>16)) { r=2; val>>=8; } else { r=0; val>>=24; }
+ r += (!val);
+ return r;
+# endif
+ }
+ }
+}
+
+static unsigned LZ4_count(const BYTE* pIn, const BYTE* pMatch, const BYTE* pInLimit)
+{
+ const BYTE* const pStart = pIn;
+
+ while (likely(pIn compression run slower on incompressible data */
+
+
+/**************************************
+* Local Structures and types
+**************************************/
+typedef struct {
+ U32 hashTable[HASH_SIZE_U32];
+ U32 currentOffset;
+ U32 initCheck;
+ const BYTE* dictionary;
+ BYTE* bufferStart; /* obsolete, used for slideInputBuffer */
+ U32 dictSize;
+} LZ4_stream_t_internal;
+
+typedef enum { notLimited = 0, limitedOutput = 1 } limitedOutput_directive;
+typedef enum { byPtr, byU32, byU16 } tableType_t;
+
+typedef enum { noDict = 0, withPrefix64k, usingExtDict } dict_directive;
+typedef enum { noDictIssue = 0, dictSmall } dictIssue_directive;
+
+typedef enum { endOnOutputSize = 0, endOnInputSize = 1 } endCondition_directive;
+typedef enum { full = 0, partial = 1 } earlyEnd_directive;
+
+
+/**************************************
+* Local Utils
+**************************************/
+int LZ4_versionNumber (void) { return LZ4_VERSION_NUMBER; }
+int LZ4_compressBound(int isize) { return LZ4_COMPRESSBOUND(isize); }
+int LZ4_sizeofState() { return LZ4_STREAMSIZE; }
+
+
+
+/********************************
+* Compression functions
+********************************/
+
+static U32 LZ4_hashSequence(U32 sequence, tableType_t const tableType)
+{
+ if (tableType == byU16)
+ return (((sequence) * 2654435761U) >> ((MINMATCH*8)-(LZ4_HASHLOG+1)));
+ else
+ return (((sequence) * 2654435761U) >> ((MINMATCH*8)-LZ4_HASHLOG));
+}
+
+static const U64 prime5bytes = 889523592379ULL;
+static U32 LZ4_hashSequence64(size_t sequence, tableType_t const tableType)
+{
+ const U32 hashLog = (tableType == byU16) ? LZ4_HASHLOG+1 : LZ4_HASHLOG;
+ const U32 hashMask = (1<> (40 - hashLog)) & hashMask;
+}
+
+static U32 LZ4_hashSequenceT(size_t sequence, tableType_t const tableType)
+{
+ if (LZ4_64bits())
+ return LZ4_hashSequence64(sequence, tableType);
+ return LZ4_hashSequence((U32)sequence, tableType);
+}
+
+static U32 LZ4_hashPosition(const void* p, tableType_t tableType) { return LZ4_hashSequenceT(LZ4_read_ARCH(p), tableType); }
+
+static void LZ4_putPositionOnHash(const BYTE* p, U32 h, void* tableBase, tableType_t const tableType, const BYTE* srcBase)
+{
+ switch (tableType)
+ {
+ case byPtr: { const BYTE** hashTable = (const BYTE**)tableBase; hashTable[h] = p; return; }
+ case byU32: { U32* hashTable = (U32*) tableBase; hashTable[h] = (U32)(p-srcBase); return; }
+ case byU16: { U16* hashTable = (U16*) tableBase; hashTable[h] = (U16)(p-srcBase); return; }
+ }
+}
+
+static void LZ4_putPosition(const BYTE* p, void* tableBase, tableType_t tableType, const BYTE* srcBase)
+{
+ U32 h = LZ4_hashPosition(p, tableType);
+ LZ4_putPositionOnHash(p, h, tableBase, tableType, srcBase);
+}
+
+static const BYTE* LZ4_getPositionOnHash(U32 h, void* tableBase, tableType_t tableType, const BYTE* srcBase)
+{
+ if (tableType == byPtr) { const BYTE** hashTable = (const BYTE**) tableBase; return hashTable[h]; }
+ if (tableType == byU32) { U32* hashTable = (U32*) tableBase; return hashTable[h] + srcBase; }
+ { U16* hashTable = (U16*) tableBase; return hashTable[h] + srcBase; } /* default, to ensure a return */
+}
+
+static const BYTE* LZ4_getPosition(const BYTE* p, void* tableBase, tableType_t tableType, const BYTE* srcBase)
+{
+ U32 h = LZ4_hashPosition(p, tableType);
+ return LZ4_getPositionOnHash(h, tableBase, tableType, srcBase);
+}
+
+FORCE_INLINE int LZ4_compress_generic(
+ void* const ctx,
+ const char* const source,
+ char* const dest,
+ const int inputSize,
+ const int maxOutputSize,
+ const limitedOutput_directive outputLimited,
+ const tableType_t tableType,
+ const dict_directive dict,
+ const dictIssue_directive dictIssue,
+ const U32 acceleration)
+{
+ LZ4_stream_t_internal* const dictPtr = (LZ4_stream_t_internal*)ctx;
+
+ const BYTE* ip = (const BYTE*) source;
+ const BYTE* base;
+ const BYTE* lowLimit;
+ const BYTE* const lowRefLimit = ip - dictPtr->dictSize;
+ const BYTE* const dictionary = dictPtr->dictionary;
+ const BYTE* const dictEnd = dictionary + dictPtr->dictSize;
+ const size_t dictDelta = dictEnd - (const BYTE*)source;
+ const BYTE* anchor = (const BYTE*) source;
+ const BYTE* const iend = ip + inputSize;
+ const BYTE* const mflimit = iend - MFLIMIT;
+ const BYTE* const matchlimit = iend - LASTLITERALS;
+
+ BYTE* op = (BYTE*) dest;
+ BYTE* const olimit = op + maxOutputSize;
+
+ U32 forwardH;
+ size_t refDelta=0;
+
+ /* Init conditions */
+ if ((U32)inputSize > (U32)LZ4_MAX_INPUT_SIZE) return 0; /* Unsupported input size, too large (or negative) */
+ switch(dict)
+ {
+ case noDict:
+ default:
+ base = (const BYTE*)source;
+ lowLimit = (const BYTE*)source;
+ break;
+ case withPrefix64k:
+ base = (const BYTE*)source - dictPtr->currentOffset;
+ lowLimit = (const BYTE*)source - dictPtr->dictSize;
+ break;
+ case usingExtDict:
+ base = (const BYTE*)source - dictPtr->currentOffset;
+ lowLimit = (const BYTE*)source;
+ break;
+ }
+ if ((tableType == byU16) && (inputSize>=LZ4_64Klimit)) return 0; /* Size too large (not within 64K limit) */
+ if (inputSize> LZ4_skipTrigger);
+
+ if (unlikely(forwardIp > mflimit)) goto _last_literals;
+
+ match = LZ4_getPositionOnHash(h, ctx, tableType, base);
+ if (dict==usingExtDict)
+ {
+ if (match<(const BYTE*)source)
+ {
+ refDelta = dictDelta;
+ lowLimit = dictionary;
+ }
+ else
+ {
+ refDelta = 0;
+ lowLimit = (const BYTE*)source;
+ }
+ }
+ forwardH = LZ4_hashPosition(forwardIp, tableType);
+ LZ4_putPositionOnHash(ip, h, ctx, tableType, base);
+
+ } while ( ((dictIssue==dictSmall) ? (match < lowRefLimit) : 0)
+ || ((tableType==byU16) ? 0 : (match + MAX_DISTANCE < ip))
+ || (LZ4_read32(match+refDelta) != LZ4_read32(ip)) );
+ }
+
+ /* Catch up */
+ while ((ip>anchor) && (match+refDelta > lowLimit) && (unlikely(ip[-1]==match[refDelta-1]))) { ip--; match--; }
+
+ {
+ /* Encode Literal length */
+ unsigned litLength = (unsigned)(ip - anchor);
+ token = op++;
+ if ((outputLimited) && (unlikely(op + litLength + (2 + 1 + LASTLITERALS) + (litLength/255) > olimit)))
+ return 0; /* Check output limit */
+ if (litLength>=RUN_MASK)
+ {
+ int len = (int)litLength-RUN_MASK;
+ *token=(RUN_MASK<= 255 ; len-=255) *op++ = 255;
+ *op++ = (BYTE)len;
+ }
+ else *token = (BYTE)(litLength< matchlimit) limit = matchlimit;
+ matchLength = LZ4_count(ip+MINMATCH, match+MINMATCH, limit);
+ ip += MINMATCH + matchLength;
+ if (ip==limit)
+ {
+ unsigned more = LZ4_count(ip, (const BYTE*)source, matchlimit);
+ matchLength += more;
+ ip += more;
+ }
+ }
+ else
+ {
+ matchLength = LZ4_count(ip+MINMATCH, match+MINMATCH, matchlimit);
+ ip += MINMATCH + matchLength;
+ }
+
+ if ((outputLimited) && (unlikely(op + (1 + LASTLITERALS) + (matchLength>>8) > olimit)))
+ return 0; /* Check output limit */
+ if (matchLength>=ML_MASK)
+ {
+ *token += ML_MASK;
+ matchLength -= ML_MASK;
+ for (; matchLength >= 510 ; matchLength-=510) { *op++ = 255; *op++ = 255; }
+ if (matchLength >= 255) { matchLength-=255; *op++ = 255; }
+ *op++ = (BYTE)matchLength;
+ }
+ else *token += (BYTE)(matchLength);
+ }
+
+ anchor = ip;
+
+ /* Test end of chunk */
+ if (ip > mflimit) break;
+
+ /* Fill table */
+ LZ4_putPosition(ip-2, ctx, tableType, base);
+
+ /* Test next position */
+ match = LZ4_getPosition(ip, ctx, tableType, base);
+ if (dict==usingExtDict)
+ {
+ if (match<(const BYTE*)source)
+ {
+ refDelta = dictDelta;
+ lowLimit = dictionary;
+ }
+ else
+ {
+ refDelta = 0;
+ lowLimit = (const BYTE*)source;
+ }
+ }
+ LZ4_putPosition(ip, ctx, tableType, base);
+ if ( ((dictIssue==dictSmall) ? (match>=lowRefLimit) : 1)
+ && (match+MAX_DISTANCE>=ip)
+ && (LZ4_read32(match+refDelta)==LZ4_read32(ip)) )
+ { token=op++; *token=0; goto _next_match; }
+
+ /* Prepare next loop */
+ forwardH = LZ4_hashPosition(++ip, tableType);
+ }
+
+_last_literals:
+ /* Encode Last Literals */
+ {
+ const size_t lastRun = (size_t)(iend - anchor);
+ if ((outputLimited) && ((op - (BYTE*)dest) + lastRun + 1 + ((lastRun+255-RUN_MASK)/255) > (U32)maxOutputSize))
+ return 0; /* Check output limit */
+ if (lastRun >= RUN_MASK)
+ {
+ size_t accumulator = lastRun - RUN_MASK;
+ *op++ = RUN_MASK << ML_BITS;
+ for(; accumulator >= 255 ; accumulator-=255) *op++ = 255;
+ *op++ = (BYTE) accumulator;
+ }
+ else
+ {
+ *op++ = (BYTE)(lastRun<= LZ4_compressBound(inputSize))
+ {
+ if (inputSize < LZ4_64Klimit)
+ return LZ4_compress_generic(state, source, dest, inputSize, 0, notLimited, byU16, noDict, noDictIssue, acceleration);
+ else
+ return LZ4_compress_generic(state, source, dest, inputSize, 0, notLimited, LZ4_64bits() ? byU32 : byPtr, noDict, noDictIssue, acceleration);
+ }
+ else
+ {
+ if (inputSize < LZ4_64Klimit)
+ return LZ4_compress_generic(state, source, dest, inputSize, maxOutputSize, limitedOutput, byU16, noDict, noDictIssue, acceleration);
+ else
+ return LZ4_compress_generic(state, source, dest, inputSize, maxOutputSize, limitedOutput, LZ4_64bits() ? byU32 : byPtr, noDict, noDictIssue, acceleration);
+ }
+}
+
+
+int LZ4_compress_fast(const char* source, char* dest, int inputSize, int maxOutputSize, int acceleration)
+{
+#if (HEAPMODE)
+ void* ctxPtr = ALLOCATOR(1, sizeof(LZ4_stream_t)); /* malloc-calloc always properly aligned */
+#else
+ LZ4_stream_t ctx;
+ void* ctxPtr = &ctx;
+#endif
+
+ int result = LZ4_compress_fast_extState(ctxPtr, source, dest, inputSize, maxOutputSize, acceleration);
+
+#if (HEAPMODE)
+ FREEMEM(ctxPtr);
+#endif
+ return result;
+}
+
+
+int LZ4_compress_default(const char* source, char* dest, int inputSize, int maxOutputSize)
+{
+ return LZ4_compress_fast(source, dest, inputSize, maxOutputSize, 1);
+}
+
+
+/* hidden debug function */
+/* strangely enough, gcc generates faster code when this function is uncommented, even if unused */
+int LZ4_compress_fast_force(const char* source, char* dest, int inputSize, int maxOutputSize, int acceleration)
+{
+ LZ4_stream_t ctx;
+
+ LZ4_resetStream(&ctx);
+
+ if (inputSize < LZ4_64Klimit)
+ return LZ4_compress_generic(&ctx, source, dest, inputSize, maxOutputSize, limitedOutput, byU16, noDict, noDictIssue, acceleration);
+ else
+ return LZ4_compress_generic(&ctx, source, dest, inputSize, maxOutputSize, limitedOutput, LZ4_64bits() ? byU32 : byPtr, noDict, noDictIssue, acceleration);
+}
+
+
+/********************************
+* destSize variant
+********************************/
+
+static int LZ4_compress_destSize_generic(
+ void* const ctx,
+ const char* const src,
+ char* const dst,
+ int* const srcSizePtr,
+ const int targetDstSize,
+ const tableType_t tableType)
+{
+ const BYTE* ip = (const BYTE*) src;
+ const BYTE* base = (const BYTE*) src;
+ const BYTE* lowLimit = (const BYTE*) src;
+ const BYTE* anchor = ip;
+ const BYTE* const iend = ip + *srcSizePtr;
+ const BYTE* const mflimit = iend - MFLIMIT;
+ const BYTE* const matchlimit = iend - LASTLITERALS;
+
+ BYTE* op = (BYTE*) dst;
+ BYTE* const oend = op + targetDstSize;
+ BYTE* const oMaxLit = op + targetDstSize - 2 /* offset */ - 8 /* because 8+MINMATCH==MFLIMIT */ - 1 /* token */;
+ BYTE* const oMaxMatch = op + targetDstSize - (LASTLITERALS + 1 /* token */);
+ BYTE* const oMaxSeq = oMaxLit - 1 /* token */;
+
+ U32 forwardH;
+
+
+ /* Init conditions */
+ if (targetDstSize < 1) return 0; /* Impossible to store anything */
+ if ((U32)*srcSizePtr > (U32)LZ4_MAX_INPUT_SIZE) return 0; /* Unsupported input size, too large (or negative) */
+ if ((tableType == byU16) && (*srcSizePtr>=LZ4_64Klimit)) return 0; /* Size too large (not within 64K limit) */
+ if (*srcSizePtr> LZ4_skipTrigger);
+
+ if (unlikely(forwardIp > mflimit))
+ goto _last_literals;
+
+ match = LZ4_getPositionOnHash(h, ctx, tableType, base);
+ forwardH = LZ4_hashPosition(forwardIp, tableType);
+ LZ4_putPositionOnHash(ip, h, ctx, tableType, base);
+
+ } while ( ((tableType==byU16) ? 0 : (match + MAX_DISTANCE < ip))
+ || (LZ4_read32(match) != LZ4_read32(ip)) );
+ }
+
+ /* Catch up */
+ while ((ip>anchor) && (match > lowLimit) && (unlikely(ip[-1]==match[-1]))) { ip--; match--; }
+
+ {
+ /* Encode Literal length */
+ unsigned litLength = (unsigned)(ip - anchor);
+ token = op++;
+ if (op + ((litLength+240)/255) + litLength > oMaxLit)
+ {
+ /* Not enough space for a last match */
+ op--;
+ goto _last_literals;
+ }
+ if (litLength>=RUN_MASK)
+ {
+ unsigned len = litLength - RUN_MASK;
+ *token=(RUN_MASK<= 255 ; len-=255) *op++ = 255;
+ *op++ = (BYTE)len;
+ }
+ else *token = (BYTE)(litLength< oMaxMatch)
+ {
+ /* Match description too long : reduce it */
+ matchLength = (15-1) + (oMaxMatch-op) * 255;
+ }
+ /*printf("offset %5i, matchLength%5i \n", (int)(ip-match), matchLength + MINMATCH);*/
+ ip += MINMATCH + matchLength;
+
+ if (matchLength>=ML_MASK)
+ {
+ *token += ML_MASK;
+ matchLength -= ML_MASK;
+ while (matchLength >= 255) { matchLength-=255; *op++ = 255; }
+ *op++ = (BYTE)matchLength;
+ }
+ else *token += (BYTE)(matchLength);
+ }
+
+ anchor = ip;
+
+ /* Test end of block */
+ if (ip > mflimit) break;
+ if (op > oMaxSeq) break;
+
+ /* Fill table */
+ LZ4_putPosition(ip-2, ctx, tableType, base);
+
+ /* Test next position */
+ match = LZ4_getPosition(ip, ctx, tableType, base);
+ LZ4_putPosition(ip, ctx, tableType, base);
+ if ( (match+MAX_DISTANCE>=ip)
+ && (LZ4_read32(match)==LZ4_read32(ip)) )
+ { token=op++; *token=0; goto _next_match; }
+
+ /* Prepare next loop */
+ forwardH = LZ4_hashPosition(++ip, tableType);
+ }
+
+_last_literals:
+ /* Encode Last Literals */
+ {
+ size_t lastRunSize = (size_t)(iend - anchor);
+ if (op + 1 /* token */ + ((lastRunSize+240)/255) /* litLength */ + lastRunSize /* literals */ > oend)
+ {
+ /* adapt lastRunSize to fill 'dst' */
+ lastRunSize = (oend-op) - 1;
+ lastRunSize -= (lastRunSize+240)/255;
+ }
+ ip = anchor + lastRunSize;
+
+ if (lastRunSize >= RUN_MASK)
+ {
+ size_t accumulator = lastRunSize - RUN_MASK;
+ *op++ = RUN_MASK << ML_BITS;
+ for(; accumulator >= 255 ; accumulator-=255) *op++ = 255;
+ *op++ = (BYTE) accumulator;
+ }
+ else
+ {
+ *op++ = (BYTE)(lastRunSize<= LZ4_compressBound(*srcSizePtr)) /* compression success is guaranteed */
+ {
+ return LZ4_compress_fast_extState(state, src, dst, *srcSizePtr, targetDstSize, 1);
+ }
+ else
+ {
+ if (*srcSizePtr < LZ4_64Klimit)
+ return LZ4_compress_destSize_generic(state, src, dst, srcSizePtr, targetDstSize, byU16);
+ else
+ return LZ4_compress_destSize_generic(state, src, dst, srcSizePtr, targetDstSize, LZ4_64bits() ? byU32 : byPtr);
+ }
+}
+
+
+int LZ4_compress_destSize(const char* src, char* dst, int* srcSizePtr, int targetDstSize)
+{
+#if (HEAPMODE)
+ void* ctx = ALLOCATOR(1, sizeof(LZ4_stream_t)); /* malloc-calloc always properly aligned */
+#else
+ LZ4_stream_t ctxBody;
+ void* ctx = &ctxBody;
+#endif
+
+ int result = LZ4_compress_destSize_extState(ctx, src, dst, srcSizePtr, targetDstSize);
+
+#if (HEAPMODE)
+ FREEMEM(ctx);
+#endif
+ return result;
+}
+
+
+
+/********************************
+* Streaming functions
+********************************/
+
+LZ4_stream_t* LZ4_createStream(void)
+{
+ LZ4_stream_t* lz4s = (LZ4_stream_t*)ALLOCATOR(8, LZ4_STREAMSIZE_U64);
+ LZ4_STATIC_ASSERT(LZ4_STREAMSIZE >= sizeof(LZ4_stream_t_internal)); /* A compilation error here means LZ4_STREAMSIZE is not large enough */
+ LZ4_resetStream(lz4s);
+ return lz4s;
+}
+
+void LZ4_resetStream (LZ4_stream_t* LZ4_stream)
+{
+ MEM_INIT(LZ4_stream, 0, sizeof(LZ4_stream_t));
+}
+
+int LZ4_freeStream (LZ4_stream_t* LZ4_stream)
+{
+ FREEMEM(LZ4_stream);
+ return (0);
+}
+
+
+#define HASH_UNIT sizeof(size_t)
+int LZ4_loadDict (LZ4_stream_t* LZ4_dict, const char* dictionary, int dictSize)
+{
+ LZ4_stream_t_internal* dict = (LZ4_stream_t_internal*) LZ4_dict;
+ const BYTE* p = (const BYTE*)dictionary;
+ const BYTE* const dictEnd = p + dictSize;
+ const BYTE* base;
+
+ if ((dict->initCheck) || (dict->currentOffset > 1 GB)) /* Uninitialized structure, or reuse overflow */
+ LZ4_resetStream(LZ4_dict);
+
+ if (dictSize < (int)HASH_UNIT)
+ {
+ dict->dictionary = NULL;
+ dict->dictSize = 0;
+ return 0;
+ }
+
+ if ((dictEnd - p) > 64 KB) p = dictEnd - 64 KB;
+ dict->currentOffset += 64 KB;
+ base = p - dict->currentOffset;
+ dict->dictionary = p;
+ dict->dictSize = (U32)(dictEnd - p);
+ dict->currentOffset += dict->dictSize;
+
+ while (p <= dictEnd-HASH_UNIT)
+ {
+ LZ4_putPosition(p, dict->hashTable, byU32, base);
+ p+=3;
+ }
+
+ return dict->dictSize;
+}
+
+
+static void LZ4_renormDictT(LZ4_stream_t_internal* LZ4_dict, const BYTE* src)
+{
+ if ((LZ4_dict->currentOffset > 0x80000000) ||
+ ((size_t)LZ4_dict->currentOffset > (size_t)src)) /* address space overflow */
+ {
+ /* rescale hash table */
+ U32 delta = LZ4_dict->currentOffset - 64 KB;
+ const BYTE* dictEnd = LZ4_dict->dictionary + LZ4_dict->dictSize;
+ int i;
+ for (i=0; ihashTable[i] < delta) LZ4_dict->hashTable[i]=0;
+ else LZ4_dict->hashTable[i] -= delta;
+ }
+ LZ4_dict->currentOffset = 64 KB;
+ if (LZ4_dict->dictSize > 64 KB) LZ4_dict->dictSize = 64 KB;
+ LZ4_dict->dictionary = dictEnd - LZ4_dict->dictSize;
+ }
+}
+
+
+int LZ4_compress_fast_continue (LZ4_stream_t* LZ4_stream, const char* source, char* dest, int inputSize, int maxOutputSize, int acceleration)
+{
+ LZ4_stream_t_internal* streamPtr = (LZ4_stream_t_internal*)LZ4_stream;
+ const BYTE* const dictEnd = streamPtr->dictionary + streamPtr->dictSize;
+
+ const BYTE* smallest = (const BYTE*) source;
+ if (streamPtr->initCheck) return 0; /* Uninitialized structure detected */
+ if ((streamPtr->dictSize>0) && (smallest>dictEnd)) smallest = dictEnd;
+ LZ4_renormDictT(streamPtr, smallest);
+ if (acceleration < 1) acceleration = ACCELERATION_DEFAULT;
+
+ /* Check overlapping input/dictionary space */
+ {
+ const BYTE* sourceEnd = (const BYTE*) source + inputSize;
+ if ((sourceEnd > streamPtr->dictionary) && (sourceEnd < dictEnd))
+ {
+ streamPtr->dictSize = (U32)(dictEnd - sourceEnd);
+ if (streamPtr->dictSize > 64 KB) streamPtr->dictSize = 64 KB;
+ if (streamPtr->dictSize < 4) streamPtr->dictSize = 0;
+ streamPtr->dictionary = dictEnd - streamPtr->dictSize;
+ }
+ }
+
+ /* prefix mode : source data follows dictionary */
+ if (dictEnd == (const BYTE*)source)
+ {
+ int result;
+ if ((streamPtr->dictSize < 64 KB) && (streamPtr->dictSize < streamPtr->currentOffset))
+ result = LZ4_compress_generic(LZ4_stream, source, dest, inputSize, maxOutputSize, limitedOutput, byU32, withPrefix64k, dictSmall, acceleration);
+ else
+ result = LZ4_compress_generic(LZ4_stream, source, dest, inputSize, maxOutputSize, limitedOutput, byU32, withPrefix64k, noDictIssue, acceleration);
+ streamPtr->dictSize += (U32)inputSize;
+ streamPtr->currentOffset += (U32)inputSize;
+ return result;
+ }
+
+ /* external dictionary mode */
+ {
+ int result;
+ if ((streamPtr->dictSize < 64 KB) && (streamPtr->dictSize < streamPtr->currentOffset))
+ result = LZ4_compress_generic(LZ4_stream, source, dest, inputSize, maxOutputSize, limitedOutput, byU32, usingExtDict, dictSmall, acceleration);
+ else
+ result = LZ4_compress_generic(LZ4_stream, source, dest, inputSize, maxOutputSize, limitedOutput, byU32, usingExtDict, noDictIssue, acceleration);
+ streamPtr->dictionary = (const BYTE*)source;
+ streamPtr->dictSize = (U32)inputSize;
+ streamPtr->currentOffset += (U32)inputSize;
+ return result;
+ }
+}
+
+
+/* Hidden debug function, to force external dictionary mode */
+int LZ4_compress_forceExtDict (LZ4_stream_t* LZ4_dict, const char* source, char* dest, int inputSize)
+{
+ LZ4_stream_t_internal* streamPtr = (LZ4_stream_t_internal*)LZ4_dict;
+ int result;
+ const BYTE* const dictEnd = streamPtr->dictionary + streamPtr->dictSize;
+
+ const BYTE* smallest = dictEnd;
+ if (smallest > (const BYTE*) source) smallest = (const BYTE*) source;
+ LZ4_renormDictT((LZ4_stream_t_internal*)LZ4_dict, smallest);
+
+ result = LZ4_compress_generic(LZ4_dict, source, dest, inputSize, 0, notLimited, byU32, usingExtDict, noDictIssue, 1);
+
+ streamPtr->dictionary = (const BYTE*)source;
+ streamPtr->dictSize = (U32)inputSize;
+ streamPtr->currentOffset += (U32)inputSize;
+
+ return result;
+}
+
+
+int LZ4_saveDict (LZ4_stream_t* LZ4_dict, char* safeBuffer, int dictSize)
+{
+ LZ4_stream_t_internal* dict = (LZ4_stream_t_internal*) LZ4_dict;
+ const BYTE* previousDictEnd = dict->dictionary + dict->dictSize;
+
+ if ((U32)dictSize > 64 KB) dictSize = 64 KB; /* useless to define a dictionary > 64 KB */
+ if ((U32)dictSize > dict->dictSize) dictSize = dict->dictSize;
+
+ memmove(safeBuffer, previousDictEnd - dictSize, dictSize);
+
+ dict->dictionary = (const BYTE*)safeBuffer;
+ dict->dictSize = (U32)dictSize;
+
+ return dictSize;
+}
+
+
+
+/*******************************
+* Decompression functions
+*******************************/
+/*
+ * This generic decompression function cover all use cases.
+ * It shall be instantiated several times, using different sets of directives
+ * Note that it is essential this generic function is really inlined,
+ * in order to remove useless branches during compilation optimization.
+ */
+FORCE_INLINE int LZ4_decompress_generic(
+ const char* const source,
+ char* const dest,
+ int inputSize,
+ int outputSize, /* If endOnInput==endOnInputSize, this value is the max size of Output Buffer. */
+
+ int endOnInput, /* endOnOutputSize, endOnInputSize */
+ int partialDecoding, /* full, partial */
+ int targetOutputSize, /* only used if partialDecoding==partial */
+ int dict, /* noDict, withPrefix64k, usingExtDict */
+ const BYTE* const lowPrefix, /* == dest if dict == noDict */
+ const BYTE* const dictStart, /* only if dict==usingExtDict */
+ const size_t dictSize /* note : = 0 if noDict */
+ )
+{
+ /* Local Variables */
+ const BYTE* ip = (const BYTE*) source;
+ const BYTE* const iend = ip + inputSize;
+
+ BYTE* op = (BYTE*) dest;
+ BYTE* const oend = op + outputSize;
+ BYTE* cpy;
+ BYTE* oexit = op + targetOutputSize;
+ const BYTE* const lowLimit = lowPrefix - dictSize;
+
+ const BYTE* const dictEnd = (const BYTE*)dictStart + dictSize;
+ const size_t dec32table[] = {4, 1, 2, 1, 4, 4, 4, 4};
+ const size_t dec64table[] = {0, 0, 0, (size_t)-1, 0, 1, 2, 3};
+
+ const int safeDecode = (endOnInput==endOnInputSize);
+ const int checkOffset = ((safeDecode) && (dictSize < (int)(64 KB)));
+
+
+ /* Special cases */
+ if ((partialDecoding) && (oexit> oend-MFLIMIT)) oexit = oend-MFLIMIT; /* targetOutputSize too high => decode everything */
+ if ((endOnInput) && (unlikely(outputSize==0))) return ((inputSize==1) && (*ip==0)) ? 0 : -1; /* Empty output buffer */
+ if ((!endOnInput) && (unlikely(outputSize==0))) return (*ip==0?1:-1);
+
+
+ /* Main Loop */
+ while (1)
+ {
+ unsigned token;
+ size_t length;
+ const BYTE* match;
+
+ /* get literal length */
+ token = *ip++;
+ if ((length=(token>>ML_BITS)) == RUN_MASK)
+ {
+ unsigned s;
+ do
+ {
+ s = *ip++;
+ length += s;
+ }
+ while (likely((endOnInput)?ip(partialDecoding?oexit:oend-MFLIMIT)) || (ip+length>iend-(2+1+LASTLITERALS))) )
+ || ((!endOnInput) && (cpy>oend-COPYLENGTH)))
+ {
+ if (partialDecoding)
+ {
+ if (cpy > oend) goto _output_error; /* Error : write attempt beyond end of output buffer */
+ if ((endOnInput) && (ip+length > iend)) goto _output_error; /* Error : read attempt beyond end of input buffer */
+ }
+ else
+ {
+ if ((!endOnInput) && (cpy != oend)) goto _output_error; /* Error : block decoding must stop exactly there */
+ if ((endOnInput) && ((ip+length != iend) || (cpy > oend))) goto _output_error; /* Error : input must be consumed */
+ }
+ memcpy(op, ip, length);
+ ip += length;
+ op += length;
+ break; /* Necessarily EOF, due to parsing restrictions */
+ }
+ LZ4_wildCopy(op, ip, cpy);
+ ip += length; op = cpy;
+
+ /* get offset */
+ match = cpy - LZ4_readLE16(ip); ip+=2;
+ if ((checkOffset) && (unlikely(match < lowLimit))) goto _output_error; /* Error : offset outside destination buffer */
+
+ /* get matchlength */
+ length = token & ML_MASK;
+ if (length == ML_MASK)
+ {
+ unsigned s;
+ do
+ {
+ if ((endOnInput) && (ip > iend-LASTLITERALS)) goto _output_error;
+ s = *ip++;
+ length += s;
+ } while (s==255);
+ if ((safeDecode) && unlikely((size_t)(op+length)<(size_t)op)) goto _output_error; /* overflow detection */
+ }
+ length += MINMATCH;
+
+ /* check external dictionary */
+ if ((dict==usingExtDict) && (match < lowPrefix))
+ {
+ if (unlikely(op+length > oend-LASTLITERALS)) goto _output_error; /* doesn't respect parsing restriction */
+
+ if (length <= (size_t)(lowPrefix-match))
+ {
+ /* match can be copied as a single segment from external dictionary */
+ match = dictEnd - (lowPrefix-match);
+ memmove(op, match, length); op += length;
+ }
+ else
+ {
+ /* match encompass external dictionary and current segment */
+ size_t copySize = (size_t)(lowPrefix-match);
+ memcpy(op, dictEnd - copySize, copySize);
+ op += copySize;
+ copySize = length - copySize;
+ if (copySize > (size_t)(op-lowPrefix)) /* overlap within current segment */
+ {
+ BYTE* const endOfMatch = op + copySize;
+ const BYTE* copyFrom = lowPrefix;
+ while (op < endOfMatch) *op++ = *copyFrom++;
+ }
+ else
+ {
+ memcpy(op, lowPrefix, copySize);
+ op += copySize;
+ }
+ }
+ continue;
+ }
+
+ /* copy repeated sequence */
+ cpy = op + length;
+ if (unlikely((op-match)<8))
+ {
+ const size_t dec64 = dec64table[op-match];
+ op[0] = match[0];
+ op[1] = match[1];
+ op[2] = match[2];
+ op[3] = match[3];
+ match += dec32table[op-match];
+ LZ4_copy4(op+4, match);
+ op += 8; match -= dec64;
+ } else { LZ4_copy8(op, match); op+=8; match+=8; }
+
+ if (unlikely(cpy>oend-12))
+ {
+ if (cpy > oend-LASTLITERALS) goto _output_error; /* Error : last LASTLITERALS bytes must be literals */
+ if (op < oend-8)
+ {
+ LZ4_wildCopy(op, match, oend-8);
+ match += (oend-8) - op;
+ op = oend-8;
+ }
+ while (opprefixSize = (size_t) dictSize;
+ lz4sd->prefixEnd = (const BYTE*) dictionary + dictSize;
+ lz4sd->externalDict = NULL;
+ lz4sd->extDictSize = 0;
+ return 1;
+}
+
+/*
+*_continue() :
+ These decoding functions allow decompression of multiple blocks in "streaming" mode.
+ Previously decoded blocks must still be available at the memory position where they were decoded.
+ If it's not possible, save the relevant part of decoded data into a safe buffer,
+ and indicate where it stands using LZ4_setStreamDecode()
+*/
+int LZ4_decompress_safe_continue (LZ4_streamDecode_t* LZ4_streamDecode, const char* source, char* dest, int compressedSize, int maxOutputSize)
+{
+ LZ4_streamDecode_t_internal* lz4sd = (LZ4_streamDecode_t_internal*) LZ4_streamDecode;
+ int result;
+
+ if (lz4sd->prefixEnd == (BYTE*)dest)
+ {
+ result = LZ4_decompress_generic(source, dest, compressedSize, maxOutputSize,
+ endOnInputSize, full, 0,
+ usingExtDict, lz4sd->prefixEnd - lz4sd->prefixSize, lz4sd->externalDict, lz4sd->extDictSize);
+ if (result <= 0) return result;
+ lz4sd->prefixSize += result;
+ lz4sd->prefixEnd += result;
+ }
+ else
+ {
+ lz4sd->extDictSize = lz4sd->prefixSize;
+ lz4sd->externalDict = lz4sd->prefixEnd - lz4sd->extDictSize;
+ result = LZ4_decompress_generic(source, dest, compressedSize, maxOutputSize,
+ endOnInputSize, full, 0,
+ usingExtDict, (BYTE*)dest, lz4sd->externalDict, lz4sd->extDictSize);
+ if (result <= 0) return result;
+ lz4sd->prefixSize = result;
+ lz4sd->prefixEnd = (BYTE*)dest + result;
+ }
+
+ return result;
+}
+
+int LZ4_decompress_fast_continue (LZ4_streamDecode_t* LZ4_streamDecode, const char* source, char* dest, int originalSize)
+{
+ LZ4_streamDecode_t_internal* lz4sd = (LZ4_streamDecode_t_internal*) LZ4_streamDecode;
+ int result;
+
+ if (lz4sd->prefixEnd == (BYTE*)dest)
+ {
+ result = LZ4_decompress_generic(source, dest, 0, originalSize,
+ endOnOutputSize, full, 0,
+ usingExtDict, lz4sd->prefixEnd - lz4sd->prefixSize, lz4sd->externalDict, lz4sd->extDictSize);
+ if (result <= 0) return result;
+ lz4sd->prefixSize += originalSize;
+ lz4sd->prefixEnd += originalSize;
+ }
+ else
+ {
+ lz4sd->extDictSize = lz4sd->prefixSize;
+ lz4sd->externalDict = (BYTE*)dest - lz4sd->extDictSize;
+ result = LZ4_decompress_generic(source, dest, 0, originalSize,
+ endOnOutputSize, full, 0,
+ usingExtDict, (BYTE*)dest, lz4sd->externalDict, lz4sd->extDictSize);
+ if (result <= 0) return result;
+ lz4sd->prefixSize = originalSize;
+ lz4sd->prefixEnd = (BYTE*)dest + originalSize;
+ }
+
+ return result;
+}
+
+
+/*
+Advanced decoding functions :
+*_usingDict() :
+ These decoding functions work the same as "_continue" ones,
+ the dictionary must be explicitly provided within parameters
+*/
+
+FORCE_INLINE int LZ4_decompress_usingDict_generic(const char* source, char* dest, int compressedSize, int maxOutputSize, int safe, const char* dictStart, int dictSize)
+{
+ if (dictSize==0)
+ return LZ4_decompress_generic(source, dest, compressedSize, maxOutputSize, safe, full, 0, noDict, (BYTE*)dest, NULL, 0);
+ if (dictStart+dictSize == dest)
+ {
+ if (dictSize >= (int)(64 KB - 1))
+ return LZ4_decompress_generic(source, dest, compressedSize, maxOutputSize, safe, full, 0, withPrefix64k, (BYTE*)dest-64 KB, NULL, 0);
+ return LZ4_decompress_generic(source, dest, compressedSize, maxOutputSize, safe, full, 0, noDict, (BYTE*)dest-dictSize, NULL, 0);
+ }
+ return LZ4_decompress_generic(source, dest, compressedSize, maxOutputSize, safe, full, 0, usingExtDict, (BYTE*)dest, (const BYTE*)dictStart, dictSize);
+}
+
+int LZ4_decompress_safe_usingDict(const char* source, char* dest, int compressedSize, int maxOutputSize, const char* dictStart, int dictSize)
+{
+ return LZ4_decompress_usingDict_generic(source, dest, compressedSize, maxOutputSize, 1, dictStart, dictSize);
+}
+
+int LZ4_decompress_fast_usingDict(const char* source, char* dest, int originalSize, const char* dictStart, int dictSize)
+{
+ return LZ4_decompress_usingDict_generic(source, dest, 0, originalSize, 0, dictStart, dictSize);
+}
+
+/* debug function */
+int LZ4_decompress_safe_forceExtDict(const char* source, char* dest, int compressedSize, int maxOutputSize, const char* dictStart, int dictSize)
+{
+ return LZ4_decompress_generic(source, dest, compressedSize, maxOutputSize, endOnInputSize, full, 0, usingExtDict, (BYTE*)dest, (const BYTE*)dictStart, dictSize);
+}
+
+
+/***************************************************
+* Obsolete Functions
+***************************************************/
+/* obsolete compression functions */
+int LZ4_compress_limitedOutput(const char* source, char* dest, int inputSize, int maxOutputSize) { return LZ4_compress_default(source, dest, inputSize, maxOutputSize); }
+int LZ4_compress(const char* source, char* dest, int inputSize) { return LZ4_compress_default(source, dest, inputSize, LZ4_compressBound(inputSize)); }
+int LZ4_compress_limitedOutput_withState (void* state, const char* src, char* dst, int srcSize, int dstSize) { return LZ4_compress_fast_extState(state, src, dst, srcSize, dstSize, 1); }
+int LZ4_compress_withState (void* state, const char* src, char* dst, int srcSize) { return LZ4_compress_fast_extState(state, src, dst, srcSize, LZ4_compressBound(srcSize), 1); }
+int LZ4_compress_limitedOutput_continue (LZ4_stream_t* LZ4_stream, const char* src, char* dst, int srcSize, int maxDstSize) { return LZ4_compress_fast_continue(LZ4_stream, src, dst, srcSize, maxDstSize, 1); }
+int LZ4_compress_continue (LZ4_stream_t* LZ4_stream, const char* source, char* dest, int inputSize) { return LZ4_compress_fast_continue(LZ4_stream, source, dest, inputSize, LZ4_compressBound(inputSize), 1); }
+
+/*
+These function names are deprecated and should no longer be used.
+They are only provided here for compatibility with older user programs.
+- LZ4_uncompress is totally equivalent to LZ4_decompress_fast
+- LZ4_uncompress_unknownOutputSize is totally equivalent to LZ4_decompress_safe
+*/
+int LZ4_uncompress (const char* source, char* dest, int outputSize) { return LZ4_decompress_fast(source, dest, outputSize); }
+int LZ4_uncompress_unknownOutputSize (const char* source, char* dest, int isize, int maxOutputSize) { return LZ4_decompress_safe(source, dest, isize, maxOutputSize); }
+
+
+/* Obsolete Streaming functions */
+
+int LZ4_sizeofStreamState() { return LZ4_STREAMSIZE; }
+
+static void LZ4_init(LZ4_stream_t_internal* lz4ds, BYTE* base)
+{
+ MEM_INIT(lz4ds, 0, LZ4_STREAMSIZE);
+ lz4ds->bufferStart = base;
+}
+
+int LZ4_resetStreamState(void* state, char* inputBuffer)
+{
+ if ((((size_t)state) & 3) != 0) return 1; /* Error : pointer is not aligned on 4-bytes boundary */
+ LZ4_init((LZ4_stream_t_internal*)state, (BYTE*)inputBuffer);
+ return 0;
+}
+
+void* LZ4_create (char* inputBuffer)
+{
+ void* lz4ds = ALLOCATOR(8, LZ4_STREAMSIZE_U64);
+ LZ4_init ((LZ4_stream_t_internal*)lz4ds, (BYTE*)inputBuffer);
+ return lz4ds;
+}
+
+char* LZ4_slideInputBuffer (void* LZ4_Data)
+{
+ LZ4_stream_t_internal* ctx = (LZ4_stream_t_internal*)LZ4_Data;
+ int dictSize = LZ4_saveDict((LZ4_stream_t*)LZ4_Data, (char*)ctx->bufferStart, 64 KB);
+ return (char*)(ctx->bufferStart + dictSize);
+}
+
+/* Obsolete streaming decompression functions */
+
+int LZ4_decompress_safe_withPrefix64k(const char* source, char* dest, int compressedSize, int maxOutputSize)
+{
+ return LZ4_decompress_generic(source, dest, compressedSize, maxOutputSize, endOnInputSize, full, 0, withPrefix64k, (BYTE*)dest - 64 KB, NULL, 64 KB);
+}
+
+int LZ4_decompress_fast_withPrefix64k(const char* source, char* dest, int originalSize)
+{
+ return LZ4_decompress_generic(source, dest, 0, originalSize, endOnOutputSize, full, 0, withPrefix64k, (BYTE*)dest - 64 KB, NULL, 64 KB);
+}
+
+#endif /* LZ4_COMMONDEFS_ONLY */
+
diff --git a/plugins/com.minres.scviewer.database.fst/csrc/fst/lz4.h b/plugins/com.minres.scviewer.database.fst/csrc/fst/lz4.h
new file mode 100644
index 0000000..bd5245e
--- /dev/null
+++ b/plugins/com.minres.scviewer.database.fst/csrc/fst/lz4.h
@@ -0,0 +1,362 @@
+/*
+ LZ4 - Fast LZ compression algorithm
+ Header File
+ Copyright (C) 2011-2015, Yann Collet.
+
+ BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are
+ met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following disclaimer
+ in the documentation and/or other materials provided with the
+ distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ SPDX-License-Identifier: BSD-2-Clause
+
+ You can contact the author at :
+ - LZ4 source repository : https://github.com/Cyan4973/lz4
+ - LZ4 public forum : https://groups.google.com/forum/#!forum/lz4c
+*/
+#pragma once
+
+#if defined (__cplusplus)
+extern "C" {
+#endif
+
+/*
+ * lz4.h provides block compression functions, and gives full buffer control to programmer.
+ * If you need to generate inter-operable compressed data (respecting LZ4 frame specification),
+ * and can let the library handle its own memory, please use lz4frame.h instead.
+*/
+
+/**************************************
+* Version
+**************************************/
+#define LZ4_VERSION_MAJOR 1 /* for breaking interface changes */
+#define LZ4_VERSION_MINOR 7 /* for new (non-breaking) interface capabilities */
+#define LZ4_VERSION_RELEASE 1 /* for tweaks, bug-fixes, or development */
+#define LZ4_VERSION_NUMBER (LZ4_VERSION_MAJOR *100*100 + LZ4_VERSION_MINOR *100 + LZ4_VERSION_RELEASE)
+int LZ4_versionNumber (void);
+
+/**************************************
+* Tuning parameter
+**************************************/
+/*
+ * LZ4_MEMORY_USAGE :
+ * Memory usage formula : N->2^N Bytes (examples : 10 -> 1KB; 12 -> 4KB ; 16 -> 64KB; 20 -> 1MB; etc.)
+ * Increasing memory usage improves compression ratio
+ * Reduced memory usage can improve speed, due to cache effect
+ * Default value is 14, for 16KB, which nicely fits into Intel x86 L1 cache
+ */
+#define LZ4_MEMORY_USAGE 14
+
+
+/**************************************
+* Simple Functions
+**************************************/
+
+int LZ4_compress_default(const char* source, char* dest, int sourceSize, int maxDestSize);
+int LZ4_decompress_safe (const char* source, char* dest, int compressedSize, int maxDecompressedSize);
+
+/*
+LZ4_compress_default() :
+ Compresses 'sourceSize' bytes from buffer 'source'
+ into already allocated 'dest' buffer of size 'maxDestSize'.
+ Compression is guaranteed to succeed if 'maxDestSize' >= LZ4_compressBound(sourceSize).
+ It also runs faster, so it's a recommended setting.
+ If the function cannot compress 'source' into a more limited 'dest' budget,
+ compression stops *immediately*, and the function result is zero.
+ As a consequence, 'dest' content is not valid.
+ This function never writes outside 'dest' buffer, nor read outside 'source' buffer.
+ sourceSize : Max supported value is LZ4_MAX_INPUT_VALUE
+ maxDestSize : full or partial size of buffer 'dest' (which must be already allocated)
+ return : the number of bytes written into buffer 'dest' (necessarily <= maxOutputSize)
+ or 0 if compression fails
+
+LZ4_decompress_safe() :
+ compressedSize : is the precise full size of the compressed block.
+ maxDecompressedSize : is the size of destination buffer, which must be already allocated.
+ return : the number of bytes decompressed into destination buffer (necessarily <= maxDecompressedSize)
+ If destination buffer is not large enough, decoding will stop and output an error code (<0).
+ If the source stream is detected malformed, the function will stop decoding and return a negative result.
+ This function is protected against buffer overflow exploits, including malicious data packets.
+ It never writes outside output buffer, nor reads outside input buffer.
+*/
+
+
+/**************************************
+* Advanced Functions
+**************************************/
+#define LZ4_MAX_INPUT_SIZE 0x7E000000 /* 2 113 929 216 bytes */
+#define LZ4_COMPRESSBOUND(isize) ((unsigned)(isize) > (unsigned)LZ4_MAX_INPUT_SIZE ? 0 : (isize) + ((isize)/255) + 16)
+
+/*
+LZ4_compressBound() :
+ Provides the maximum size that LZ4 compression may output in a "worst case" scenario (input data not compressible)
+ This function is primarily useful for memory allocation purposes (destination buffer size).
+ Macro LZ4_COMPRESSBOUND() is also provided for compilation-time evaluation (stack memory allocation for example).
+ Note that LZ4_compress_default() compress faster when dest buffer size is >= LZ4_compressBound(srcSize)
+ inputSize : max supported value is LZ4_MAX_INPUT_SIZE
+ return : maximum output size in a "worst case" scenario
+ or 0, if input size is too large ( > LZ4_MAX_INPUT_SIZE)
+*/
+int LZ4_compressBound(int inputSize);
+
+/*
+LZ4_compress_fast() :
+ Same as LZ4_compress_default(), but allows to select an "acceleration" factor.
+ The larger the acceleration value, the faster the algorithm, but also the lesser the compression.
+ It's a trade-off. It can be fine tuned, with each successive value providing roughly +~3% to speed.
+ An acceleration value of "1" is the same as regular LZ4_compress_default()
+ Values <= 0 will be replaced by ACCELERATION_DEFAULT (see lz4.c), which is 1.
+*/
+int LZ4_compress_fast (const char* source, char* dest, int sourceSize, int maxDestSize, int acceleration);
+
+
+/*
+LZ4_compress_fast_extState() :
+ Same compression function, just using an externally allocated memory space to store compression state.
+ Use LZ4_sizeofState() to know how much memory must be allocated,
+ and allocate it on 8-bytes boundaries (using malloc() typically).
+ Then, provide it as 'void* state' to compression function.
+*/
+int LZ4_sizeofState(void);
+int LZ4_compress_fast_extState (void* state, const char* source, char* dest, int inputSize, int maxDestSize, int acceleration);
+
+
+/*
+LZ4_compress_destSize() :
+ Reverse the logic, by compressing as much data as possible from 'source' buffer
+ into already allocated buffer 'dest' of size 'targetDestSize'.
+ This function either compresses the entire 'source' content into 'dest' if it's large enough,
+ or fill 'dest' buffer completely with as much data as possible from 'source'.
+ *sourceSizePtr : will be modified to indicate how many bytes where read from 'source' to fill 'dest'.
+ New value is necessarily <= old value.
+ return : Nb bytes written into 'dest' (necessarily <= targetDestSize)
+ or 0 if compression fails
+*/
+int LZ4_compress_destSize (const char* source, char* dest, int* sourceSizePtr, int targetDestSize);
+
+
+/*
+LZ4_decompress_fast() :
+ originalSize : is the original and therefore uncompressed size
+ return : the number of bytes read from the source buffer (in other words, the compressed size)
+ If the source stream is detected malformed, the function will stop decoding and return a negative result.
+ Destination buffer must be already allocated. Its size must be a minimum of 'originalSize' bytes.
+ note : This function fully respect memory boundaries for properly formed compressed data.
+ It is a bit faster than LZ4_decompress_safe().
+ However, it does not provide any protection against intentionally modified data stream (malicious input).
+ Use this function in trusted environment only (data to decode comes from a trusted source).
+*/
+int LZ4_decompress_fast (const char* source, char* dest, int originalSize);
+
+/*
+LZ4_decompress_safe_partial() :
+ This function decompress a compressed block of size 'compressedSize' at position 'source'
+ into destination buffer 'dest' of size 'maxDecompressedSize'.
+ The function tries to stop decompressing operation as soon as 'targetOutputSize' has been reached,
+ reducing decompression time.
+ return : the number of bytes decoded in the destination buffer (necessarily <= maxDecompressedSize)
+ Note : this number can be < 'targetOutputSize' should the compressed block to decode be smaller.
+ Always control how many bytes were decoded.
+ If the source stream is detected malformed, the function will stop decoding and return a negative result.
+ This function never writes outside of output buffer, and never reads outside of input buffer. It is therefore protected against malicious data packets
+*/
+int LZ4_decompress_safe_partial (const char* source, char* dest, int compressedSize, int targetOutputSize, int maxDecompressedSize);
+
+
+/***********************************************
+* Streaming Compression Functions
+***********************************************/
+#define LZ4_STREAMSIZE_U64 ((1 << (LZ4_MEMORY_USAGE-3)) + 4)
+#define LZ4_STREAMSIZE (LZ4_STREAMSIZE_U64 * sizeof(long long))
+/*
+ * LZ4_stream_t
+ * information structure to track an LZ4 stream.
+ * important : init this structure content before first use !
+ * note : only allocated directly the structure if you are statically linking LZ4
+ * If you are using liblz4 as a DLL, please use below construction methods instead.
+ */
+typedef struct { long long table[LZ4_STREAMSIZE_U64]; } LZ4_stream_t;
+
+/*
+ * LZ4_resetStream
+ * Use this function to init an allocated LZ4_stream_t structure
+ */
+void LZ4_resetStream (LZ4_stream_t* streamPtr);
+
+/*
+ * LZ4_createStream will allocate and initialize an LZ4_stream_t structure
+ * LZ4_freeStream releases its memory.
+ * In the context of a DLL (liblz4), please use these methods rather than the static struct.
+ * They are more future proof, in case of a change of LZ4_stream_t size.
+ */
+LZ4_stream_t* LZ4_createStream(void);
+int LZ4_freeStream (LZ4_stream_t* streamPtr);
+
+/*
+ * LZ4_loadDict
+ * Use this function to load a static dictionary into LZ4_stream.
+ * Any previous data will be forgotten, only 'dictionary' will remain in memory.
+ * Loading a size of 0 is allowed.
+ * Return : dictionary size, in bytes (necessarily <= 64 KB)
+ */
+int LZ4_loadDict (LZ4_stream_t* streamPtr, const char* dictionary, int dictSize);
+
+/*
+ * LZ4_compress_fast_continue
+ * Compress buffer content 'src', using data from previously compressed blocks as dictionary to improve compression ratio.
+ * Important : Previous data blocks are assumed to still be present and unmodified !
+ * 'dst' buffer must be already allocated.
+ * If maxDstSize >= LZ4_compressBound(srcSize), compression is guaranteed to succeed, and runs faster.
+ * If not, and if compressed data cannot fit into 'dst' buffer size, compression stops, and function returns a zero.
+ */
+int LZ4_compress_fast_continue (LZ4_stream_t* streamPtr, const char* src, char* dst, int srcSize, int maxDstSize, int acceleration);
+
+/*
+ * LZ4_saveDict
+ * If previously compressed data block is not guaranteed to remain available at its memory location
+ * save it into a safer place (char* safeBuffer)
+ * Note : you don't need to call LZ4_loadDict() afterwards,
+ * dictionary is immediately usable, you can therefore call LZ4_compress_fast_continue()
+ * Return : saved dictionary size in bytes (necessarily <= dictSize), or 0 if error
+ */
+int LZ4_saveDict (LZ4_stream_t* streamPtr, char* safeBuffer, int dictSize);
+
+
+/************************************************
+* Streaming Decompression Functions
+************************************************/
+
+#define LZ4_STREAMDECODESIZE_U64 4
+#define LZ4_STREAMDECODESIZE (LZ4_STREAMDECODESIZE_U64 * sizeof(unsigned long long))
+typedef struct { unsigned long long table[LZ4_STREAMDECODESIZE_U64]; } LZ4_streamDecode_t;
+/*
+ * LZ4_streamDecode_t
+ * information structure to track an LZ4 stream.
+ * init this structure content using LZ4_setStreamDecode or memset() before first use !
+ *
+ * In the context of a DLL (liblz4) please prefer usage of construction methods below.
+ * They are more future proof, in case of a change of LZ4_streamDecode_t size in the future.
+ * LZ4_createStreamDecode will allocate and initialize an LZ4_streamDecode_t structure
+ * LZ4_freeStreamDecode releases its memory.
+ */
+LZ4_streamDecode_t* LZ4_createStreamDecode(void);
+int LZ4_freeStreamDecode (LZ4_streamDecode_t* LZ4_stream);
+
+/*
+ * LZ4_setStreamDecode
+ * Use this function to instruct where to find the dictionary.
+ * Setting a size of 0 is allowed (same effect as reset).
+ * Return : 1 if OK, 0 if error
+ */
+int LZ4_setStreamDecode (LZ4_streamDecode_t* LZ4_streamDecode, const char* dictionary, int dictSize);
+
+/*
+*_continue() :
+ These decoding functions allow decompression of multiple blocks in "streaming" mode.
+ Previously decoded blocks *must* remain available at the memory position where they were decoded (up to 64 KB)
+ In the case of a ring buffers, decoding buffer must be either :
+ - Exactly same size as encoding buffer, with same update rule (block boundaries at same positions)
+ In which case, the decoding & encoding ring buffer can have any size, including very small ones ( < 64 KB).
+ - Larger than encoding buffer, by a minimum of maxBlockSize more bytes.
+ maxBlockSize is implementation dependent. It's the maximum size you intend to compress into a single block.
+ In which case, encoding and decoding buffers do not need to be synchronized,
+ and encoding ring buffer can have any size, including small ones ( < 64 KB).
+ - _At least_ 64 KB + 8 bytes + maxBlockSize.
+ In which case, encoding and decoding buffers do not need to be synchronized,
+ and encoding ring buffer can have any size, including larger than decoding buffer.
+ Whenever these conditions are not possible, save the last 64KB of decoded data into a safe buffer,
+ and indicate where it is saved using LZ4_setStreamDecode()
+*/
+int LZ4_decompress_safe_continue (LZ4_streamDecode_t* LZ4_streamDecode, const char* source, char* dest, int compressedSize, int maxDecompressedSize);
+int LZ4_decompress_fast_continue (LZ4_streamDecode_t* LZ4_streamDecode, const char* source, char* dest, int originalSize);
+
+
+/*
+Advanced decoding functions :
+*_usingDict() :
+ These decoding functions work the same as
+ a combination of LZ4_setStreamDecode() followed by LZ4_decompress_x_continue()
+ They are stand-alone. They don't need nor update an LZ4_streamDecode_t structure.
+*/
+int LZ4_decompress_safe_usingDict (const char* source, char* dest, int compressedSize, int maxDecompressedSize, const char* dictStart, int dictSize);
+int LZ4_decompress_fast_usingDict (const char* source, char* dest, int originalSize, const char* dictStart, int dictSize);
+
+
+
+/**************************************
+* Obsolete Functions
+**************************************/
+/* Deprecate Warnings */
+/* Should these warnings messages be a problem,
+ it is generally possible to disable them,
+ with -Wno-deprecated-declarations for gcc
+ or _CRT_SECURE_NO_WARNINGS in Visual for example.
+ You can also define LZ4_DEPRECATE_WARNING_DEFBLOCK. */
+#ifndef LZ4_DEPRECATE_WARNING_DEFBLOCK
+# define LZ4_DEPRECATE_WARNING_DEFBLOCK
+# define LZ4_GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__)
+# if (LZ4_GCC_VERSION >= 405) || defined(__clang__)
+# define LZ4_DEPRECATED(message) __attribute__((deprecated(message)))
+# elif (LZ4_GCC_VERSION >= 301)
+# define LZ4_DEPRECATED(message) __attribute__((deprecated))
+# elif defined(_MSC_VER)
+# define LZ4_DEPRECATED(message) __declspec(deprecated(message))
+# else
+# pragma message("WARNING: You need to implement LZ4_DEPRECATED for this compiler")
+# define LZ4_DEPRECATED(message)
+# endif
+#endif /* LZ4_DEPRECATE_WARNING_DEFBLOCK */
+
+/* Obsolete compression functions */
+/* These functions are planned to start generate warnings by r131 approximately */
+int LZ4_compress (const char* source, char* dest, int sourceSize);
+int LZ4_compress_limitedOutput (const char* source, char* dest, int sourceSize, int maxOutputSize);
+int LZ4_compress_withState (void* state, const char* source, char* dest, int inputSize);
+int LZ4_compress_limitedOutput_withState (void* state, const char* source, char* dest, int inputSize, int maxOutputSize);
+int LZ4_compress_continue (LZ4_stream_t* LZ4_streamPtr, const char* source, char* dest, int inputSize);
+int LZ4_compress_limitedOutput_continue (LZ4_stream_t* LZ4_streamPtr, const char* source, char* dest, int inputSize, int maxOutputSize);
+
+/* Obsolete decompression functions */
+/* These function names are completely deprecated and must no longer be used.
+ They are only provided here for compatibility with older programs.
+ - LZ4_uncompress is the same as LZ4_decompress_fast
+ - LZ4_uncompress_unknownOutputSize is the same as LZ4_decompress_safe
+ These function prototypes are now disabled; uncomment them only if you really need them.
+ It is highly recommended to stop using these prototypes and migrate to maintained ones */
+/* int LZ4_uncompress (const char* source, char* dest, int outputSize); */
+/* int LZ4_uncompress_unknownOutputSize (const char* source, char* dest, int isize, int maxOutputSize); */
+
+/* Obsolete streaming functions; use new streaming interface whenever possible */
+LZ4_DEPRECATED("use LZ4_createStream() instead") void* LZ4_create (char* inputBuffer);
+LZ4_DEPRECATED("use LZ4_createStream() instead") int LZ4_sizeofStreamState(void);
+LZ4_DEPRECATED("use LZ4_resetStream() instead") int LZ4_resetStreamState(void* state, char* inputBuffer);
+LZ4_DEPRECATED("use LZ4_saveDict() instead") char* LZ4_slideInputBuffer (void* state);
+
+/* Obsolete streaming decoding functions */
+LZ4_DEPRECATED("use LZ4_decompress_safe_usingDict() instead") int LZ4_decompress_safe_withPrefix64k (const char* src, char* dst, int compressedSize, int maxDstSize);
+LZ4_DEPRECATED("use LZ4_decompress_fast_usingDict() instead") int LZ4_decompress_fast_withPrefix64k (const char* src, char* dst, int originalSize);
+
+
+#if defined (__cplusplus)
+}
+#endif
diff --git a/plugins/com.minres.scviewer.database.fst/lib/jna-5.13.0-javadoc.jar b/plugins/com.minres.scviewer.database.fst/lib/jna-5.13.0-javadoc.jar
new file mode 100644
index 0000000..9bdb670
Binary files /dev/null and b/plugins/com.minres.scviewer.database.fst/lib/jna-5.13.0-javadoc.jar differ
diff --git a/plugins/com.minres.scviewer.database.fst/lib/jna-5.13.0-sources.jar b/plugins/com.minres.scviewer.database.fst/lib/jna-5.13.0-sources.jar
new file mode 100644
index 0000000..d7e1a8c
Binary files /dev/null and b/plugins/com.minres.scviewer.database.fst/lib/jna-5.13.0-sources.jar differ
diff --git a/plugins/com.minres.scviewer.database.fst/lib/jna-5.13.0.jar b/plugins/com.minres.scviewer.database.fst/lib/jna-5.13.0.jar
new file mode 100644
index 0000000..3d49c81
Binary files /dev/null and b/plugins/com.minres.scviewer.database.fst/lib/jna-5.13.0.jar differ
diff --git a/plugins/com.minres.scviewer.database.fst/lib/jna-jpms-5.13.0.jar b/plugins/com.minres.scviewer.database.fst/lib/jna-jpms-5.13.0.jar
new file mode 100644
index 0000000..b832449
Binary files /dev/null and b/plugins/com.minres.scviewer.database.fst/lib/jna-jpms-5.13.0.jar differ
diff --git a/plugins/com.minres.scviewer.database.fst/linux-x86-64/libfstapi.so b/plugins/com.minres.scviewer.database.fst/linux-x86-64/libfstapi.so
new file mode 100644
index 0000000..6d37269
Binary files /dev/null and b/plugins/com.minres.scviewer.database.fst/linux-x86-64/libfstapi.so differ
diff --git a/plugins/com.minres.scviewer.database.fst/pom.xml b/plugins/com.minres.scviewer.database.fst/pom.xml
new file mode 100644
index 0000000..2983471
--- /dev/null
+++ b/plugins/com.minres.scviewer.database.fst/pom.xml
@@ -0,0 +1,14 @@
+
+ 4.0.0
+ com.minres.scviewer.database.fst
+ 1.0.0-SNAPSHOT
+
+ com.minres.scviewer
+ com.minres.scviewer.parent
+ 2.18.0
+ ../..
+
+ eclipse-plugin
+
+
diff --git a/plugins/com.minres.scviewer.database.fst/src/com/minres/scviewer/database/fst/FstDbLoader.java b/plugins/com.minres.scviewer.database.fst/src/com/minres/scviewer/database/fst/FstDbLoader.java
new file mode 100644
index 0000000..d9be5da
--- /dev/null
+++ b/plugins/com.minres.scviewer.database.fst/src/com/minres/scviewer/database/fst/FstDbLoader.java
@@ -0,0 +1,190 @@
+/*******************************************************************************
+ * Copyright (c) 2015-2021 MINRES Technologies GmbH and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * MINRES Technologies GmbH - initial API and implementation
+ *******************************************************************************/
+package com.minres.scviewer.database.fst;
+
+import java.beans.PropertyChangeListener;
+import java.beans.PropertyChangeSupport;
+import java.io.File;
+import java.util.ArrayDeque;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.Vector;
+
+import com.google.common.collect.Iterables;
+import com.minres.scviewer.database.BitVector;
+import com.minres.scviewer.database.DoubleVal;
+import com.minres.scviewer.database.EventList;
+import com.minres.scviewer.database.IEventList;
+import com.minres.scviewer.database.IWaveform;
+import com.minres.scviewer.database.IWaveformDb;
+import com.minres.scviewer.database.IWaveformDbLoader;
+import com.minres.scviewer.database.InputFormatException;
+import com.minres.scviewer.database.RelationType;
+
+/**
+ * The Class VCDDb.
+ */
+public class FstDbLoader implements IWaveformDbLoader, IFstDatabaseBuilder {
+
+
+ /** The module stack. */
+ private ArrayDeque moduleStack;
+
+ /** The signals. */
+ private List signals;
+
+ FstFileParser parser;
+ /** The max time. */
+ private long maxTime;
+
+ private long timeScaleFactor;
+
+ /** The pcs. */
+ protected PropertyChangeSupport pcs = new PropertyChangeSupport(this);
+
+ static long calculateTimescaleMultipierPower(long time_scale){
+ long answer = 1;
+ if(time_scale<=0){
+ return answer;
+ } else{
+ for(int i = 1; i<= time_scale; i++)
+ answer *= 10;
+ return answer;
+ }
+ }
+
+ /* (non-Javadoc)
+ * @see com.minres.scviewer.database.ITrDb#load(java.io.File)
+ */
+ @Override
+ public void load(File file) throws InputFormatException {
+ dispose();
+ this.maxTime=0;
+ boolean res = false;
+ signals = new Vector<>();
+ moduleStack= new ArrayDeque<>();
+ parser = new FstFileParser(file);
+ res = parser.open(this);
+ moduleStack=null;
+ if(!res)
+ throw new InputFormatException("Could not parse VCD file");
+ // calculate max time of this database
+ pcs.firePropertyChange(IWaveformDbLoader.LOADING_FINISHED, null, null);
+ }
+
+ public void dispose() {
+ if(parser!=null) {
+ parser.close();
+ parser=null;
+ }
+ moduleStack=null;
+ signals=null;
+ }
+
+ /* (non-Javadoc)
+ * @see com.minres.scviewer.database.ITrDb#getMaxTime()
+ */
+ @Override
+ public long getMaxTime() {
+ return maxTime;
+ }
+
+ /* (non-Javadoc)
+ * @see com.minres.scviewer.database.ITrDb#getAllWaves()
+ */
+ @Override
+ public Collection getAllWaves() {
+ return signals;
+ }
+
+ /* (non-Javadoc)
+ * @see com.minres.scviewer.database.vcd.ITraceBuilder#enterModule(java.lang.String)
+ */
+ @Override
+ public void enterModule(String tokenString) {
+ if(moduleStack.isEmpty()) {
+ if("SystemC".compareTo(tokenString)!=0)
+ moduleStack.push(tokenString);
+ } else
+ moduleStack.push(moduleStack.peek()+"."+tokenString);
+
+ }
+
+ /* (non-Javadoc)
+ * @see com.minres.scviewer.database.vcd.ITraceBuilder#exitModule()
+ */
+ @Override
+ public void exitModule() {
+ if(!moduleStack.isEmpty()) moduleStack.pop();
+ }
+
+ /* (non-Javadoc)
+ * @see com.minres.scviewer.database.vcd.ITraceBuilder#newNet(java.lang.String, int, int)
+ */
+ @Override
+ public void newNet(String name, int handle, int width, int direction, boolean alias) {
+ String netName = moduleStack.isEmpty()? name: moduleStack.peek()+"."+name;
+ IWaveform signal = width==0?
+ new FstSignal(this, handle, netName, width, direction):
+ new FstSignal(this, handle, netName, direction, width);
+ signals.add(signal);
+ pcs.firePropertyChange(IWaveformDbLoader.SIGNAL_ADDED, null, Iterables.getLast(signals));
+ }
+
+ /* (non-Javadoc)
+ * @see com.minres.scviewer.database.vcd.ITraceBuilder#getNetWidth(int)
+ */
+ @Override
+ public int getNetWidth(int intValue) {
+ FstSignal> signal = (FstSignal>) signals.get(intValue);
+ return signal.getRowCount();
+ }
+
+ public void setMaxTime(long maxTime, int timeScale) {
+ if(timeScale>0) timeScale=-timeScale;
+ long eff_time_scale=timeScale-IWaveformDb.databaseTimeScale;
+ this.timeScaleFactor = calculateTimescaleMultipierPower(eff_time_scale);
+ this.maxTime = maxTime*timeScaleFactor;
+ }
+ /* (non-Javadoc)
+ * @see com.minres.scviewer.database.IWaveformDbLoader#getAllRelationTypes()
+ */
+ @Override
+ public Collection getAllRelationTypes(){
+ return Collections.emptyList();
+ }
+
+ /**
+ * Adds the property change listener.
+ *
+ * @param l the l
+ */
+ @Override
+ public void addPropertyChangeListener(PropertyChangeListener l) {
+ pcs.addPropertyChangeListener(l);
+ }
+
+ /**
+ * Removes the property change listener.
+ *
+ * @param l the l
+ */
+ @Override
+ public void removePropertyChangeListener(PropertyChangeListener l) {
+ pcs.removePropertyChangeListener(l);
+ }
+
+ public void getEvents(int id, int width, IEventList values) {
+ if(values instanceof EventList)
+ parser.getValueChanges(id, width, timeScaleFactor, (EventList) values);
+ }
+}
diff --git a/plugins/com.minres.scviewer.database.fst/src/com/minres/scviewer/database/fst/FstDbLoaderFactory.java b/plugins/com.minres.scviewer.database.fst/src/com/minres/scviewer/database/fst/FstDbLoaderFactory.java
new file mode 100644
index 0000000..c32896e
--- /dev/null
+++ b/plugins/com.minres.scviewer.database.fst/src/com/minres/scviewer/database/fst/FstDbLoaderFactory.java
@@ -0,0 +1,42 @@
+/*******************************************************************************
+ * Copyright (c) 2015-2021 MINRES Technologies GmbH and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * MINRES Technologies GmbH - initial API and implementation
+ *******************************************************************************/
+package com.minres.scviewer.database.fst;
+
+import java.io.File;
+
+import com.minres.scviewer.database.IWaveformDbLoader;
+import com.minres.scviewer.database.IWaveformDbLoaderFactory;
+
+/**
+ * The Class VCDDb.
+ */
+public class FstDbLoaderFactory implements IWaveformDbLoaderFactory {
+ /**
+ * Can load.
+ *
+ * @param inputFile the input file
+ * @return true, if successful
+ */
+ @Override
+ public boolean canLoad(File inputFile) {
+ if(!inputFile.isDirectory() || inputFile.exists()) {
+ String name = inputFile.getName();
+ return name.endsWith(".fst");
+ }
+ return false;
+ }
+
+
+ @Override
+ public IWaveformDbLoader getLoader() {
+ return new FstDbLoader();
+ }
+}
diff --git a/plugins/com.minres.scviewer.database.fst/src/com/minres/scviewer/database/fst/FstFileParser.java b/plugins/com.minres.scviewer.database.fst/src/com/minres/scviewer/database/fst/FstFileParser.java
new file mode 100644
index 0000000..fe8b404
--- /dev/null
+++ b/plugins/com.minres.scviewer.database.fst/src/com/minres/scviewer/database/fst/FstFileParser.java
@@ -0,0 +1,93 @@
+/*******************************************************************************
+ * Copyright (c) 2015-2021 MINRES Technologies GmbH and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * MINRES Technologies GmbH - initial API and implementation
+ *******************************************************************************/
+package com.minres.scviewer.database.fst;
+
+import java.io.File;
+
+import com.minres.scviewer.database.BitVector;
+import com.minres.scviewer.database.EventList;
+import com.minres.scviewer.database.fst.FstLibrary.HierAttr;
+import com.minres.scviewer.database.fst.FstLibrary.HierScope;
+import com.minres.scviewer.database.fst.FstLibrary.HierType;
+import com.minres.scviewer.database.fst.FstLibrary.HierVar;
+import com.minres.scviewer.database.fst.FstLibrary.ValueChangeCallback;
+import com.sun.jna.Pointer;
+
+class FstFileParser {
+ long currentTime;
+ final File file;
+ Pointer fst;
+
+ public FstFileParser(File file) {
+ this.file=file;
+ }
+
+ public boolean open(IFstDatabaseBuilder builder) {
+ fst = FstLibrary.fstReaderOpen(file.getAbsolutePath());
+ if(!fst.equals(Pointer.NULL)) {
+ // String version = FstLibrary.fstReaderGetVersionString(fst);
+ long endTime = FstLibrary.fstReaderGetEndTime(fst);
+ byte timeScale = FstLibrary.fstReaderGetTimescale(fst);
+ builder.setMaxTime(endTime, -timeScale);
+ FstLibrary.fstReaderIterateHierRewind(fst);
+ Pointer p = FstLibrary.fstReaderIterateHier(fst);
+ while(p!=null && !p.equals(Pointer.NULL)) {
+ int hierType = FstLibrary.getHierType(p);
+ HierType type = HierType.values()[hierType];
+ switch(type) {
+ case HT_SCOPE:
+ HierScope scope = new HierScope();
+ FstLibrary.getHierScope(p, scope);
+ builder.enterModule(scope.name);
+ break;
+ case HT_UPSCOPE:
+ builder.exitModule();
+ break;
+ case HT_VAR:
+ HierVar v = new HierVar();
+ FstLibrary.getHierVar(p, v);
+ builder.newNet(v.name, v.handle, v.length, v.direction, v.is_alias!=0);
+ break;
+ case HT_ATTRBEGIN:
+ HierAttr attr = new HierAttr();
+ FstLibrary.getHierAttr(p, attr);
+ break;
+ case HT_ATTREND:
+ break;
+ case HT_TREEBEGIN:
+ break;
+ case HT_TREEEND:
+ break;
+ default:
+ break;
+ }
+ p = FstLibrary.fstReaderIterateHier(fst);
+ }
+ return true;
+ } else
+ return false;
+ }
+
+ public void getValueChanges(final int id, final int width, long timeScale, final EventList values) {
+ FstLibrary.fstReaderClrFacProcessMaskAll(fst);
+ FstLibrary.fstReaderSetFacProcessMask(fst, id);
+ FstLibrary.iterateValueChanges(fst, new ValueChangeCallback() {
+ @Override
+ public void callback(long time, int facidx, String value) {
+ values.put(time*timeScale, BitVector.fromString(width, value));
+ }
+ });
+ }
+ public void close() {
+ FstLibrary.fstReaderClose(fst);
+ }
+
+}
diff --git a/plugins/com.minres.scviewer.database.fst/src/com/minres/scviewer/database/fst/FstLibrary.java b/plugins/com.minres.scviewer.database.fst/src/com/minres/scviewer/database/fst/FstLibrary.java
new file mode 100644
index 0000000..649390d
--- /dev/null
+++ b/plugins/com.minres.scviewer.database.fst/src/com/minres/scviewer/database/fst/FstLibrary.java
@@ -0,0 +1,224 @@
+package com.minres.scviewer.database.fst;
+
+import com.sun.jna.Native;
+import com.sun.jna.Pointer;
+import com.sun.jna.Structure;
+import com.sun.jna.Structure.FieldOrder;
+import com.sun.jna.Callback;
+
+public class FstLibrary {
+ public static enum ScopeType {
+ MIN(0),
+ VCD_MODULE(0),
+ VCD_TASK(1),
+ VCD_FUNCTION(2),
+ VCD_BEGIN(3),
+ VCD_FORK(4),
+ VCD_GENERATE(5),
+ VCD_STRUCT(6),
+ VCD_UNION(7),
+ VCD_CLASS(8),
+ VCD_INTERFACE(9),
+ VCD_PACKAGE(10),
+ VCD_PROGRAM(11),
+
+ VHDL_ARCHITECTURE(12),
+ VHDL_PROCEDURE(13),
+ VHDL_FUNCTION(14),
+ VHDL_RECORD(15),
+ VHDL_PROCESS(16),
+ VHDL_BLOCK(17),
+ VHDL_FOR_GENERATE(18),
+ VHDL_IF_GENERATE(19),
+ VHDL_GENERATE(20),
+ VHDL_PACKAGE(21),
+ MAX(21),
+ ST_GEN_ATTRBEGIN(252),
+ ST_GEN_ATTREND(253),
+
+ ST_VCD_SCOPE(254),
+ ST_VCD_UPSCOPE(255);
+
+ public final int label;
+ private ScopeType(int label) {
+ this.label = label;
+ }
+ };
+ public static enum HierType {
+ HT_SCOPE(0),
+ HT_UPSCOPE(1),
+ HT_VAR(2),
+ HT_ATTRBEGIN(3),
+ HT_ATTREND(4),
+ HT_TREEBEGIN(5),
+ HT_TREEEND(6);
+ public final int type;
+ private HierType(int type) {
+ this.type = type;
+ }
+ };
+ public static enum VarType {
+ FST_VT_VCD_EVENT (0),
+ FST_VT_VCD_INTEGER (1),
+ FST_VT_VCD_PARAMETER (2),
+ FST_VT_VCD_REAL (3),
+ FST_VT_VCD_REAL_PARAMETER (4),
+ FST_VT_VCD_REG (5),
+ FST_VT_VCD_SUPPLY0 (6),
+ FST_VT_VCD_SUPPLY1 (7),
+ FST_VT_VCD_TIME (8),
+ FST_VT_VCD_TRI (9),
+ FST_VT_VCD_TRIAND (10),
+ FST_VT_VCD_TRIOR (11),
+ FST_VT_VCD_TRIREG (12),
+ FST_VT_VCD_TRI0 (13),
+ FST_VT_VCD_TRI1 (14),
+ FST_VT_VCD_WAND (15),
+ FST_VT_VCD_WIRE (16),
+ FST_VT_VCD_WOR (17),
+ FST_VT_VCD_PORT (18),
+ FST_VT_VCD_SPARRAY (19), /* used to define the rownum (index) port for a sparse array */
+ FST_VT_VCD_REALTIME (20),
+
+ FST_VT_GEN_STRING (21), /* generic string type (max len is defined dynamically via fstWriterEmitVariableLengthValueChange) */
+
+ FST_VT_SV_BIT (22),
+ FST_VT_SV_LOGIC (23),
+ FST_VT_SV_INT (24), /* declare as size = 32 */
+ FST_VT_SV_SHORTINT (25), /* declare as size = 16 */
+ FST_VT_SV_LONGINT (26), /* declare as size = 64 */
+ FST_VT_SV_BYTE (27), /* declare as size = 8 */
+ FST_VT_SV_ENUM (28), /* declare as appropriate type range */
+ FST_VT_SV_SHORTREAL (29); /* declare and emit same as FST_VT_VCD_REAL (needs to be emitted as double, not a float) */
+ public final int varType;
+ private VarType(int varType) {
+ this.varType = varType;
+ }
+ };
+
+ public static enum VarDir {
+ FST_VD_IMPLICIT (0),
+ FST_VD_INPUT (1),
+ FST_VD_OUTPUT (2),
+ FST_VD_INOUT (3),
+ FST_VD_BUFFER (4),
+ FST_VD_LINKAGE (5);
+ public final int varDir;
+ private VarDir(int varDir) {
+ this.varDir = varDir;
+ }
+ };
+
+ public static enum AttrType {
+ FST_AT_MISC ( 0), /* self-contained: does not need matching FST_HT_ATTREND */
+ FST_AT_ARRAY ( 1),
+ FST_AT_ENUM ( 2),
+ FST_AT_PACK ( 3);
+ public final int attrType;
+ private AttrType(int attrType) {
+ this.attrType = attrType;
+ }
+ };
+
+ @FieldOrder({"type","name","component", "name_length", "component_length"})
+ public static class HierScope extends Structure {
+ public byte type; /* FST_ST_MIN ... FST_ST_MAX */
+ public String name;
+ public String component;
+ public int name_length; /* strlen(u.scope.name) */
+ public int component_length; /* strlen(u.scope.component) */
+ };
+
+ @FieldOrder({"type","direction","svt_workspace", "sdt_workspace", "sxt_workspace", "name","length","handle","name_length", "is_alias"})
+ public static class HierVar extends Structure {
+ public byte type; /* FST_VT_MIN ... FST_VT_MAX */
+ public byte direction; /* FST_VD_MIN ... FST_VD_MAX */
+ public byte svt_workspace; /* zeroed out by FST reader, for client code use */
+ public byte sdt_workspace; /* zeroed out by FST reader, for client code use */
+ public int sxt_workspace; /* zeroed out by FST reader, for client code use */
+ public String name;
+ public int length;
+ public int handle; /*fstHandle*/
+ public int name_length; /* strlen(u.var.name) */
+ public int is_alias;
+ };
+
+ @FieldOrder({"type","subtype","name", "arg", "arg_from_name", "name_length"})
+ public static class HierAttr extends Structure {
+ public byte type; /* FST_AT_MIN ... FST_AT_MAX */
+ public byte subtype; /* from fstMiscType, fstArrayType, fstEnumValueType, fstPackType */
+ public String name;
+ public long arg; /* number of array elements, struct members, or some other payload (possibly ignored) */
+ public long arg_from_name; /* for when name is overloaded as a variable-length integer (FST_AT_MISC + FST_MT_SOURCESTEM) */
+ public long name_length; /* strlen(u.attr.name) */
+ };
+
+
+ public static native Pointer fstReaderOpen(String name);
+ public static native Pointer fstReaderOpenForUtilitiesOnly();
+ public static native void fstReaderClose(Pointer ctx);
+ public static native String fstReaderGetVersionString(Pointer ctx);
+ public static native String fstReaderGetDateString(Pointer ctx);
+ public static native int fstReaderGetFileType(Pointer ctx);
+ public static native long fstReaderGetVarCount(Pointer ctx);
+ public static native long fstReaderGetScopeCount(Pointer ctx);
+ public static native long fstReaderGetAliasCount(Pointer ctx);
+ public static native long fstReaderGetValueChangeSectionCount(Pointer ctx);
+ public static native long fstReaderGetStartTime(Pointer ctx);
+ public static native long fstReaderGetEndTime(Pointer ctx);
+ public static native byte fstReaderGetTimescale(Pointer ctx);
+ public static native long fstReaderGetTimezero(Pointer ctx);
+ public static native int fstReaderGetMaxHandle(Pointer ctx);
+
+ public static native void fstReaderResetScope(Pointer ctx);
+ public static native String fstReaderPushScope(Pointer ctx, String nam, Pointer user_info);
+ public static native String fstReaderPopScope(Pointer ctx);
+ public static native int fstReaderGetCurrentScopeLen(Pointer ctx);
+ public static native String fstReaderGetCurrentFlatScope(Pointer ctx);
+
+ public static native int fstReaderGetNumberDumpActivityChanges(Pointer ctx);
+ public static native long fstReaderGetDumpActivityChangeTime(Pointer ctx, int idx);
+ public static native byte fstReaderGetDumpActivityChangeValue(Pointer ctx, int idx);
+
+ public static native int fstReaderIterateHierRewind(Pointer ctx);
+ public static native Pointer fstReaderIterateHier(Pointer ctx);
+ public static native int getHierType(Pointer hier);
+ public static native void getHierScope(Pointer hier, HierScope scope);
+ public static native void getHierVar(Pointer hier, HierVar scope);
+ public static native void getHierAttr(Pointer hier, HierAttr scope);
+ public static native int fstReaderGetFacProcessMask(Pointer ctx, int facidx);
+ public static native void fstReaderSetFacProcessMask(Pointer ctx, int facidx);
+ public static native void fstReaderClrFacProcessMask(Pointer ctx, int facidx);
+ public static native void fstReaderSetFacProcessMaskAll(Pointer ctx);
+ public static native void fstReaderClrFacProcessMaskAll(Pointer ctx);
+
+ public interface ValueChangeCallback extends Callback {
+ void callback(long time, int facidx, String value);
+ }
+
+ public static native void iterateValueChanges(Pointer ctx, ValueChangeCallback vcc);
+
+ /* untranslated functions:
+ int fstReaderIterBlocks(Pointer ctx, ValueChangeCallback vcc, Pointer user_callback_data_pointer, Pointer vcdhandle);
+ Pointer fstReaderGetCurrentScopeUserInfo(Pointer ctx);
+ int fstReaderGetDoubleEndianMatchState(Pointer ctx);
+ int fstReaderGetFseekFailed(Pointer ctx);
+ long fstReaderGetMemoryUsedByWriter(Pointer ctx);
+ String fstReaderGetValueFromHandleAtTime(Pointer ctx, long tim, fstHandle facidx, Stringbuf);
+ int fstReaderIterBlocks2(Pointer ctx,
+ void (*value_change_callback)(Pointer user_callback_data_pointer, long time, fstHandle facidx, const unsigned Stringvalue),
+ void (*value_change_callback_varlen)(Pointer user_callback_data_pointer, long time, fstHandle facidx, const unsigned Stringvalue, int len),
+ Pointer user_callback_data_pointer, FILE *vcdhandle);
+ void fstReaderIterBlocksSetNativeDoublesOnCallback(Pointer ctx, int enable);
+ int fstReaderProcessHier(Pointer ctx, FILE *vcdhandle);
+ void fstReaderSetLimitTimeRange(Pointer ctx, long start_time, long end_time);
+ void fstReaderSetUnlimitedTimeRange(Pointer ctx);
+ void fstReaderSetVcdExtensions(Pointer ctx, int enable);
+*/
+
+ static {
+// System.setProperty("jna.debug_load", "true");
+ Native.register("fstapi");
+ }
+
+}
diff --git a/plugins/com.minres.scviewer.database.fst/src/com/minres/scviewer/database/fst/FstSignal.java b/plugins/com.minres.scviewer.database.fst/src/com/minres/scviewer/database/fst/FstSignal.java
new file mode 100644
index 0000000..9765844
--- /dev/null
+++ b/plugins/com.minres.scviewer.database.fst/src/com/minres/scviewer/database/fst/FstSignal.java
@@ -0,0 +1,131 @@
+/*******************************************************************************
+ * Copyright (c) 2015-2021 MINRES Technologies GmbH and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * MINRES Technologies GmbH - initial API and implementation
+ *******************************************************************************/
+package com.minres.scviewer.database.fst;
+
+import com.minres.scviewer.database.DirectionType;
+import com.minres.scviewer.database.EventEntry;
+import com.minres.scviewer.database.EventList;
+import com.minres.scviewer.database.HierNode;
+import com.minres.scviewer.database.IEvent;
+import com.minres.scviewer.database.IEventList;
+import com.minres.scviewer.database.IWaveform;
+import com.minres.scviewer.database.WaveformType;
+
+public class FstSignal extends HierNode implements IWaveform {
+
+ private final FstDbLoader loader;
+
+ private final int direction;
+
+ private final int id;
+
+ private final String fullName;
+
+ private final int width;
+
+ private final IEventList values;
+
+ public FstSignal(FstDbLoader loader, String name) {
+ this(loader, 0, name, 0, 1);
+ }
+
+ public FstSignal(FstDbLoader loader, int id, String name) {
+ this(loader, id,name, 0,1);
+ }
+
+ public FstSignal(FstDbLoader loader, int id, String name, int direction, int width) {
+ super(name);
+ fullName=name;
+ this.loader=loader;
+ this.id=id;
+ this.direction = direction;
+ this.width=width;
+ this.values=new EventList();
+ }
+
+ public FstSignal(FstSignal o, int id, String name) {
+ super(name);
+ fullName=name;
+ this.loader=o.loader;
+ this.id=id;
+ this.direction = 0;
+ this.width=o.width;
+ this.values=o.values;
+ }
+
+ @Override
+ public String getFullName() {
+ return fullName;
+ }
+
+ @Override
+ public long getId() {
+ return id;
+ }
+
+ @Override
+ public IEventList getEvents() {
+ if(values.size()==0)
+ loader.getEvents(id, width, values);
+ return values;
+ }
+
+ @Override
+ public IEvent[] getEventsAtTime(long time) {
+ return getEvents().get(time);
+ }
+
+ @Override
+ public IEvent[] getEventsBeforeTime(long time) {
+ EventEntry e = getEvents().floorEntry(time);
+ if(e==null)
+ return new IEvent[] {};
+ else
+ return getEvents().floorEntry(time).events;
+ }
+
+ @Override
+ public boolean isSame(IWaveform other) {
+ return( other instanceof FstSignal> && this.getId() == other.getId());
+ }
+
+ @Override
+ public WaveformType getType() {
+ return WaveformType.SIGNAL;
+ }
+
+ @Override
+ public int getRowCount() {
+ return 1;
+ }
+
+ @Override
+ public int getWidth() {
+ return width;
+ }
+
+ @Override
+ public String getKind() {
+ return "signal";
+ }
+
+ @Override
+ public DirectionType getDirection() {
+ switch(direction) {
+ case 1: return DirectionType.INPUT;
+ case 2: return DirectionType.OUTPUT;
+ case 3: return DirectionType.INOUT;
+ case 4: return DirectionType.BUFFER;
+ case 5: return DirectionType.LINKAGE;
+ }
+ return DirectionType.IMPLICIT;
+ }
+}
diff --git a/plugins/com.minres.scviewer.database.fst/src/com/minres/scviewer/database/fst/IFstDatabaseBuilder.java b/plugins/com.minres.scviewer.database.fst/src/com/minres/scviewer/database/fst/IFstDatabaseBuilder.java
new file mode 100644
index 0000000..07d0436
--- /dev/null
+++ b/plugins/com.minres.scviewer.database.fst/src/com/minres/scviewer/database/fst/IFstDatabaseBuilder.java
@@ -0,0 +1,49 @@
+/*******************************************************************************
+ * Copyright (c) 2015-2021 MINRES Technologies GmbH and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * MINRES Technologies GmbH - initial API and implementation
+ *******************************************************************************/
+package com.minres.scviewer.database.fst;
+
+/**
+ * The Interface IVCDDatabaseBuilder. It allows to add VCD events into the database
+ */
+public interface IFstDatabaseBuilder {
+
+ /**
+ * Enter module.
+ *
+ * @param tokenString the token string
+ */
+ public void enterModule(String tokenString);
+
+ /**
+ * Exit module.
+ */
+ public void exitModule();
+
+ /**
+ * New net.
+ *
+ * @param netName the net name
+ * @param i the index of the net, -1 if a new one, otherwise the id if the referenced
+ * @param width the width, -1 equals real, 0... is a bit vector
+ * @return the net id
+ */
+ public void newNet(String netName, int handle, int width, int direction, boolean alias) ;
+
+ /**
+ * Gets the net width.
+ *
+ * @param intValue the net id
+ * @return the net width, -1 means a real-valued net
+ */
+ public int getNetWidth(int netId);
+
+ public void setMaxTime(long time, int timeScale);
+}
diff --git a/plugins/com.minres.scviewer.database.fst/win32-x86-64/fstapi.dll b/plugins/com.minres.scviewer.database.fst/win32-x86-64/fstapi.dll
new file mode 100644
index 0000000..02d7837
Binary files /dev/null and b/plugins/com.minres.scviewer.database.fst/win32-x86-64/fstapi.dll differ
diff --git a/plugins/com.minres.scviewer.database.ftr/pom.xml b/plugins/com.minres.scviewer.database.ftr/pom.xml
index 602cf8d..b7bc540 100644
--- a/plugins/com.minres.scviewer.database.ftr/pom.xml
+++ b/plugins/com.minres.scviewer.database.ftr/pom.xml
@@ -6,7 +6,7 @@
com.minres.scviewer
com.minres.scviewer.parent
- 2.17.3
+ 2.18.0
../..
eclipse-plugin
diff --git a/plugins/com.minres.scviewer.database.ftr/src/com/minres/scviewer/database/ftr/AbstractTxStream.java b/plugins/com.minres.scviewer.database.ftr/src/com/minres/scviewer/database/ftr/AbstractTxStream.java
index 2dce2f3..2ae238a 100644
--- a/plugins/com.minres.scviewer.database.ftr/src/com/minres/scviewer/database/ftr/AbstractTxStream.java
+++ b/plugins/com.minres.scviewer.database.ftr/src/com/minres/scviewer/database/ftr/AbstractTxStream.java
@@ -37,7 +37,7 @@ abstract class AbstractTxStream extends HierNode implements IWaveform {
protected FtrDbLoader loader;
/** The events. */
- IEventList events = new EventList();
+ protected IEventList events = new EventList();
/** The max concurrency. */
private int rowCount = -1;
@@ -74,16 +74,6 @@ abstract class AbstractTxStream extends HierNode implements IWaveform {
events.put(evt.getTime(), evt);
}
- /**
- * Gets the events.
- *
- * @return the events
- */
- @Override
- public IEventList getEvents() {
- return events;
- }
-
/**
* Gets the events at time.
*
@@ -142,6 +132,11 @@ abstract class AbstractTxStream extends HierNode implements IWaveform {
return rowCount;
}
+ @Override
+ public int getWidth() {
+ return 0;
+ }
+
/**
* Calculate concurrency.
*/
@@ -150,7 +145,7 @@ abstract class AbstractTxStream extends HierNode implements IWaveform {
return;
ArrayList rowEndTime = new ArrayList<>();
HashMap rowByTxId = new HashMap<>();
- for(EventEntry entry: events) {
+ for(EventEntry entry: getEvents()) {
for(IEvent evt:entry.events) {
TxEvent txEvt = (TxEvent) evt;
ITx tx = txEvt.getTransaction();
@@ -184,5 +179,4 @@ abstract class AbstractTxStream extends HierNode implements IWaveform {
rowCount=rowEndTime.size()>0?rowEndTime.size():1;
getChildNodes().parallelStream().forEach(c -> ((TxGenerator)c).calculateConcurrency());
}
-
}
diff --git a/plugins/com.minres.scviewer.database.ftr/src/com/minres/scviewer/database/ftr/FtrDbLoader.java b/plugins/com.minres.scviewer.database.ftr/src/com/minres/scviewer/database/ftr/FtrDbLoader.java
index fea3679..a68dbb4 100644
--- a/plugins/com.minres.scviewer.database.ftr/src/com/minres/scviewer/database/ftr/FtrDbLoader.java
+++ b/plugins/com.minres.scviewer.database.ftr/src/com/minres/scviewer/database/ftr/FtrDbLoader.java
@@ -17,6 +17,7 @@ import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.nio.channels.FileChannel;
+import java.nio.channels.FileLock;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
@@ -48,13 +49,16 @@ import jacob.CborType;
*/
public class FtrDbLoader implements IWaveformDbLoader {
- enum FileType { NONE, PLAIN, GZIP, LZ4};
-
+ static final private CborType break_type = CborType.valueOf(0xff);
+
/** The max time. */
- private Long maxTime = 0L;
+ private long maxTime = 0L;
ArrayList strDict = new ArrayList<>();
+ FileInputStream fis = null;
+
+ FileLock lock = null;
/** The attr values. */
final List attrValues = new ArrayList<>();
@@ -87,14 +91,13 @@ public class FtrDbLoader implements IWaveformDbLoader {
List threads = new ArrayList<>();
File file;
-
+
private static final Logger LOG = LoggerFactory.getLogger(FtrDbLoader.class);
-
+
/** The pcs. */
protected PropertyChangeSupport pcs = new PropertyChangeSupport(this);
long time_scale_factor = 1000l;
-
/**
* Adds the property change listener.
*
@@ -104,7 +107,6 @@ public class FtrDbLoader implements IWaveformDbLoader {
public void addPropertyChangeListener(PropertyChangeListener l) {
pcs.addPropertyChangeListener(l);
}
-
/**
* Removes the property change listener.
*
@@ -114,7 +116,6 @@ public class FtrDbLoader implements IWaveformDbLoader {
public void removePropertyChangeListener(PropertyChangeListener l) {
pcs.removePropertyChangeListener(l);
}
-
/**
* Gets the max time.
*
@@ -124,12 +125,11 @@ public class FtrDbLoader implements IWaveformDbLoader {
public long getMaxTime() {
return maxTime;
}
-
/**
* Gets the transaction.
*
* @param txId the tx id
- * @return the transaction
+ * @return the transaction or null if the transaction is not available
*/
public synchronized ITx getTransaction(long txId) {
if (txCache.containsKey(txId))
@@ -139,7 +139,7 @@ public class FtrDbLoader implements IWaveformDbLoader {
txCache.put(txId, tx);
return tx;
} else {
- throw new IllegalArgumentException();
+ return null;
}
}
@@ -149,7 +149,6 @@ public class FtrDbLoader implements IWaveformDbLoader {
else
throw new IllegalArgumentException();
}
-
/**
* Gets the all waves.
*
@@ -161,7 +160,6 @@ public class FtrDbLoader implements IWaveformDbLoader {
ret.addAll(txGenerators.values());
return ret;
}
-
/**
* Gets the all relation types.
*
@@ -170,7 +168,6 @@ public class FtrDbLoader implements IWaveformDbLoader {
public Collection getAllRelationTypes() {
return relationTypes.values();
}
-
/**
* Load.
*
@@ -180,11 +177,14 @@ public class FtrDbLoader implements IWaveformDbLoader {
* @throws InputFormatException the input format exception
*/
@Override
- public void load(IWaveformDb db, File file) throws InputFormatException {
+ public void load(File file) throws InputFormatException {
dispose();
this.file=file;
- try(FileInputStream fis = new FileInputStream(file)) {
- new CborDbParser(this, fis);
+ try {
+ fis = new FileInputStream(file);
+ FileChannel channel = fis.getChannel();
+ lock=channel.lock(0, Long.MAX_VALUE, true);
+ parseInput(new CborDecoder(fis), channel);
} catch (IOException e) {
LOG.warn("Problem parsing file "+file.getName()+": " , e);
} catch (Exception e) {
@@ -192,12 +192,11 @@ public class FtrDbLoader implements IWaveformDbLoader {
transactions.clear();
throw new InputFormatException(e.toString());
}
- txStreams.values().parallelStream().forEach(TxStream::calculateConcurrency);
}
- public List extends byte[]> getChunksAtOffsets(ArrayList fileOffsets) throws InputFormatException {
+ public synchronized List extends byte[]> getChunksAtOffsets(ArrayList fileOffsets) throws InputFormatException {
List ret = new ArrayList<>();
- try(FileInputStream fis = new FileInputStream(file)) {
+ try {
FileChannel fc = fis.getChannel();
for (Long offset : fileOffsets) {
if(offset>=0) {
@@ -220,6 +219,72 @@ public class FtrDbLoader implements IWaveformDbLoader {
return ret;
}
+ void parseTx(TxStream txStream, long blockId, byte[] chunk) throws IOException {
+ CborDecoder cborDecoder = new CborDecoder(new ByteArrayInputStream(chunk));
+ long size = cborDecoder.readArrayLength();
+ assert(size==-1);
+ CborType next = cborDecoder.peekType();
+ while(next != null && !break_type.isEqualType(next)) {
+ long blockOffset = cborDecoder.getPos();
+ long tx_size = cborDecoder.readArrayLength();
+ long txId = 0;
+ long genId = 0;
+ for(long i = 0; i scvTx.endTime ? maxTime : scvTx.endTime;
+ transactions.put(txId, scvTx);
+ }
+
public List extends ITxAttribute> parseAtrributes(byte[] chunk, long blockOffset) {
List ret = new ArrayList<>();
ByteArrayInputStream bais = new ByteArrayInputStream(chunk);
@@ -290,12 +355,17 @@ public class FtrDbLoader implements IWaveformDbLoader {
TxAttributeType attrType = attributeTypes.get(attrName);
return attrType;
}
-
/**
* Dispose.
*/
@Override
public void dispose() {
+ try {
+ if(lock!=null) lock.close();
+ lock=null;
+ if(fis!=null) fis.close();
+ fis=null;
+ } catch (IOException e) { }
attrValues.clear();
relationTypes.clear();
txStreams.clear();
@@ -306,252 +376,179 @@ public class FtrDbLoader implements IWaveformDbLoader {
relationsOut.clear();
}
- /**
- * The Class TextDbParser.
- */
- static class CborDbParser extends CborDecoder {
-
- static final private CborType break_type = CborType.valueOf(0xff);
-
- /** The loader. */
- final FtrDbLoader loader;
-
- /**
- * Instantiates a new text db parser.
- *
- * @param loader the loader
- */
- public CborDbParser(FtrDbLoader loader, FileInputStream inputStream) {
- super(inputStream);
- this.loader = loader;
- try {
- long cbor_tag = readTag();
- assert(cbor_tag == 55799);
- long array_len = readArrayLength();
- assert(array_len==-1);
- CborType next = peekType();
- while(next != null && !break_type.isEqualType(next)) {
- long tag = readTag();
- switch((int)tag) {
-<<<<<<< HEAD
- case 6: // info
-=======
- case 6: { // info
->>>>>>> refs/heads/release/2.17.1
- CborDecoder cbd = new CborDecoder(new ByteArrayInputStream(readByteString()));
- long sz = cbd.readArrayLength();
- assert(sz==3);
- long time_numerator=cbd.readInt();
- long time_denominator=cbd.readInt();
- loader.time_scale_factor = 1000000000000000l*time_numerator/time_denominator;
- long epoch_tag = cbd.readTag();
- assert(epoch_tag==1);
- cbd.readInt(); // epoch
- break;
- }
- case 8: { // dictionary uncompressed
- parseDict(new CborDecoder(new ByteArrayInputStream(readByteString())));
- break;
- }
- case 9: { // dictionary compressed
- long sz = readArrayLength();
- assert(sz==2);
- readInt(); // uncompressed size
- parseDict(new CborDecoder(new BlockLZ4CompressorInputStream(new ByteArrayInputStream(readByteString()))));
- break;
- }
- case 10: { // directory uncompressed
- parseDir(new CborDecoder(new ByteArrayInputStream(readByteString())));
- break;
- }
- case 11: { // directory compressed
- long sz = readArrayLength();
- assert(sz==2);
- readInt(); // uncompressed size
- parseDir(new CborDecoder(new BlockLZ4CompressorInputStream(new ByteArrayInputStream(readByteString()))));
- break;
- }
- case 12: { //tx chunk uncompressed
- long len = readArrayLength();
- assert(len==2);
- long stream_id = readInt();
- TxStream txStream = loader.txStreams.get(stream_id);
- txStream.fileOffsets.add(inputStream.getChannel().position());
- parseTx(txStream, txStream.fileOffsets.size()-1, readByteString());
- break;
- }
- case 13: { //tx chunk compressed
- long len = readArrayLength();
- assert(len==3);
- long stream_id = readInt();
- readInt(); // uncompressed size
- TxStream txStream = loader.txStreams.get(stream_id);
- txStream.fileOffsets.add(0-inputStream.getChannel().position());
- BlockLZ4CompressorInputStream decomp = new BlockLZ4CompressorInputStream(new ByteArrayInputStream(readByteString()));
- parseTx(txStream, txStream.fileOffsets.size()-1, decomp.readAllBytes());
- decomp.close();
- break;
- }
- case 14: { // relations uncompressed
- parseRel(new CborDecoder(new ByteArrayInputStream(readByteString())));
- break;
- }
- case 15: { // relations uncompressed
- long sz = readArrayLength();
- assert(sz==2);
- readInt(); // uncompressed size
- parseRel(new CborDecoder(new BlockLZ4CompressorInputStream(new ByteArrayInputStream(readByteString()))));
- break;
- }
- }
- next = peekType();
- }
- } catch(IOException e) {
- long pos = 0;
- try {pos=inputStream.getChannel().position(); } catch (Exception ee) {}
- LOG.error("Error parsing file input stream at position" + pos, e);
- }
- }
-
-
- private void parseDict(CborDecoder cborDecoder) throws IOException {
- long size = cborDecoder.readMapLength();
- ArrayList lst = new ArrayList<>((int)size);
- for(long i = 0; i scvTx.endTime ? loader.maxTime : scvTx.endTime;
- loader.transactions.put(txId, scvTx);
- TxStream stream = loader.txStreams.get(gen.stream.getId());
- if (scvTx.beginTime == scvTx.endTime) {
- stream.addEvent(new TxEvent(loader, EventKind.SINGLE, txId, scvTx.beginTime));
- gen.addEvent(new TxEvent(loader, EventKind.SINGLE, txId, scvTx.beginTime));
- } else {
- stream.addEvent(new TxEvent(loader, EventKind.BEGIN, txId, scvTx.beginTime));
- gen.addEvent(new TxEvent(loader, EventKind.BEGIN, txId, scvTx.beginTime));
- stream.addEvent(new TxEvent(loader, EventKind.END, txId, scvTx.endTime));
- gen.addEvent(new TxEvent(loader, EventKind.END, txId, scvTx.endTime));
- }
- break;
- default: { // skip over 7:begin attr, 8:record attr, 9:end attr
- long sz = cborDecoder.readArrayLength();
- assert(sz==3);
- cborDecoder.readInt();
- long type_id = cborDecoder.readInt();
- switch(DataType.values()[(int)type_id]) {
- case BOOLEAN:
- cborDecoder.readBoolean();
- break;
- case FLOATING_POINT_NUMBER: // FLOATING_POINT_NUMBER
- case FIXED_POINT_INTEGER: // FIXED_POINT_INTEGER
- case UNSIGNED_FIXED_POINT_INTEGER: // UNSIGNED_FIXED_POINT_INTEGER
- cborDecoder.readFloat();
- break;
- case NONE: // UNSIGNED_FIXED_POINT_INTEGER
- LOG.warn("Unsupported data type: "+type_id);
- break;
- default:
- cborDecoder.readInt();
- }
- }
- }
- }
- next = cborDecoder.peekType();
- }
- }
-
- private void parseRel(CborDecoder cborDecoder) throws IOException {
- long size = cborDecoder.readArrayLength();
- assert(size==-1);
- CborType next = cborDecoder.peekType();
- while(next != null && !break_type.isEqualType(next)) {
- long sz = cborDecoder.readArrayLength();
- assert(sz==3);
- long type_id = cborDecoder.readInt();
- long from_id = cborDecoder.readInt();
- long to_id = cborDecoder.readInt();
- String rel_name = loader.strDict.get((int)type_id);
- FtrRelation ftrRel = new FtrRelation(loader.relationTypes.getOrDefault(rel_name, RelationTypeFactory.create(rel_name)), from_id, to_id);
- loader.relationsOut.put(from_id, ftrRel);
- loader.relationsIn.put(to_id, ftrRel);
- next = cborDecoder.peekType();
- }
-
- }
-
- private void add(Long id, TxStream stream) {
- loader.txStreams.put(id, stream);
- loader.pcs.firePropertyChange(IWaveformDbLoader.STREAM_ADDED, null, stream);
- }
-
- private void add(Long id, TxGenerator generator) {
- loader.txGenerators.put(id, generator);
- loader.pcs.firePropertyChange(IWaveformDbLoader.GENERATOR_ADDED, null, generator);
+ static long calculateTimescaleMultipierPower(long power){
+ long answer = 1;
+ if(power<=0){
+ return answer;
+ } else{
+ for(int i = 1; i<= power; i++)
+ answer *= 10;
+ return answer;
}
}
+ public void parseInput(CborDecoder cborDecoder, FileChannel channel) {
+ try {
+ long cbor_tag = cborDecoder.readTag();
+ assert(cbor_tag == 55799);
+ long array_len = cborDecoder.readArrayLength();
+ assert(array_len==-1);
+ CborType next = cborDecoder.peekType();
+ while(next != null && !break_type.isEqualType(next)) {
+ long tag = cborDecoder.readTag();
+ switch((int)tag) {
+ case 6: { // info
+ CborDecoder cbd = new CborDecoder(new ByteArrayInputStream(cborDecoder.readByteString()));
+ long sz = cbd.readArrayLength();
+ assert(sz==2);
+ long time_scale=cbd.readInt();
+ long eff_time_scale=time_scale-IWaveformDb.databaseTimeScale;
+ time_scale_factor = calculateTimescaleMultipierPower(eff_time_scale);
+ long epoch_tag = cbd.readTag();
+ assert(epoch_tag==1);
+ cbd.readInt(); // epoch
+ break;
+ }
+ case 8: { // dictionary uncompressed
+ parseDict(new CborDecoder(new ByteArrayInputStream(cborDecoder.readByteString())));
+ break;
+ }
+ case 9: { // dictionary compressed
+ long sz = cborDecoder.readArrayLength();
+ assert(sz==2);
+ cborDecoder.readInt(); // uncompressed size
+ parseDict(new CborDecoder(new BlockLZ4CompressorInputStream(new ByteArrayInputStream(cborDecoder.readByteString()))));
+ break;
+ }
+ case 10: { // directory uncompressed
+ parseDir(new CborDecoder(new ByteArrayInputStream(cborDecoder.readByteString())));
+ break;
+ }
+ case 11: { // directory compressed
+ long sz = cborDecoder.readArrayLength();
+ assert(sz==2);
+ cborDecoder.readInt(); // uncompressed size
+ parseDir(new CborDecoder(new BlockLZ4CompressorInputStream(new ByteArrayInputStream(cborDecoder.readByteString()))));
+ break;
+ }
+ case 12: { //tx chunk uncompressed
+ long len = cborDecoder.readArrayLength();
+ assert(len==4);
+ long stream_id = cborDecoder.readInt();
+ cborDecoder.readInt(); // start time of block
+ long end_time = cborDecoder.readInt()*time_scale_factor;
+ maxTime = end_time>maxTime?end_time:maxTime;
+ txStreams.get(stream_id).fileOffsets.add(channel.position());
+ cborDecoder.readByteString();
+ break;
+ }
+ case 13: { //tx chunk compressed
+ long len = cborDecoder.readArrayLength();
+ assert(len==5);
+ long stream_id = cborDecoder.readInt();
+ cborDecoder.readInt(); // start time of block
+ long end_time = cborDecoder.readInt()*time_scale_factor;
+ cborDecoder.readInt(); // uncompressed size
+ maxTime = end_time>maxTime?end_time:maxTime;
+ txStreams.get(stream_id).fileOffsets.add(0-channel.position());
+ cborDecoder.readByteString();
+ break;
+ }
+ case 14: { // relations uncompressed
+ parseRel(new CborDecoder(new ByteArrayInputStream(cborDecoder.readByteString())));
+ break;
+ }
+ case 15: { // relations uncompressed
+ long sz = cborDecoder.readArrayLength();
+ assert(sz==2);
+ cborDecoder.readInt(); // uncompressed size
+ parseRel(new CborDecoder(new BlockLZ4CompressorInputStream(new ByteArrayInputStream(cborDecoder.readByteString()))));
+ break;
+ }
+ }
+ next = cborDecoder.peekType();
+ }
+ } catch(IOException e) {
+ long pos = 0;
+ try {pos=channel.position(); } catch (Exception ee) {}
+ LOG.error("Error parsing file input stream at position" + pos, e);
+ }
+ }
+
+ private void parseDict(CborDecoder cborDecoder) throws IOException {
+ long size = cborDecoder.readMapLength();
+ ArrayList lst = new ArrayList<>((int)size);
+ for(long i = 0; i3?cborDecoder.readInt():-1;
+ long to_fiber = sz>3?cborDecoder.readInt():-1;
+ String rel_name = strDict.get((int)type_id);
+ FtrRelation ftrRel = new FtrRelation(relationTypes.getOrDefault(rel_name, RelationTypeFactory.create(rel_name)), from_id, to_id, from_fiber, to_fiber);
+ relationsOut.put(from_id, ftrRel);
+ relationsIn.put(to_id, ftrRel);
+ next = cborDecoder.peekType();
+ }
+ }
+
+ private void add(Long id, TxStream stream) {
+ txStreams.put(id, stream);
+ pcs.firePropertyChange(IWaveformDbLoader.STREAM_ADDED, null, stream);
+ }
+
+ private void add(Long id, TxGenerator generator) {
+ txGenerators.put(id, generator);
+ pcs.firePropertyChange(IWaveformDbLoader.GENERATOR_ADDED, null, generator);
+ }
}
diff --git a/plugins/com.minres.scviewer.database.ftr/src/com/minres/scviewer/database/ftr/FtrRelation.java b/plugins/com.minres.scviewer.database.ftr/src/com/minres/scviewer/database/ftr/FtrRelation.java
index d265c24..86f73e4 100644
--- a/plugins/com.minres.scviewer.database.ftr/src/com/minres/scviewer/database/ftr/FtrRelation.java
+++ b/plugins/com.minres.scviewer.database.ftr/src/com/minres/scviewer/database/ftr/FtrRelation.java
@@ -28,6 +28,12 @@ class FtrRelation implements Serializable {
/** The target. */
final long target;
+ /** The source. */
+ final long source_fiber;
+
+ /** The target. */
+ final long target_fiber;
+
/** The relation type. */
final RelationType relationType;
@@ -38,9 +44,11 @@ class FtrRelation implements Serializable {
* @param source the source
* @param target the target
*/
- public FtrRelation(RelationType relationType, long source, long target) {
+ public FtrRelation(RelationType relationType, long source, long target, long source_fiber, long target_fiber) {
this.source = source;
this.target = target;
+ this.source_fiber = source_fiber;
+ this.target_fiber = target_fiber;
this.relationType = relationType;
}
diff --git a/plugins/com.minres.scviewer.database.ftr/src/com/minres/scviewer/database/ftr/TxAttribute.java b/plugins/com.minres.scviewer.database.ftr/src/com/minres/scviewer/database/ftr/TxAttribute.java
index 19042a9..4bbebfc 100644
--- a/plugins/com.minres.scviewer.database.ftr/src/com/minres/scviewer/database/ftr/TxAttribute.java
+++ b/plugins/com.minres.scviewer.database.ftr/src/com/minres/scviewer/database/ftr/TxAttribute.java
@@ -81,4 +81,8 @@ public class TxAttribute implements ITxAttribute, Serializable {
return value;
}
+ @Override
+ public String toString() {
+ return "FtxAttr: " + attributeType.toString() + "=" + value;
+ }
}
diff --git a/plugins/com.minres.scviewer.database.ftr/src/com/minres/scviewer/database/ftr/TxGenerator.java b/plugins/com.minres.scviewer.database.ftr/src/com/minres/scviewer/database/ftr/TxGenerator.java
index fe11811..f755a92 100644
--- a/plugins/com.minres.scviewer.database.ftr/src/com/minres/scviewer/database/ftr/TxGenerator.java
+++ b/plugins/com.minres.scviewer.database.ftr/src/com/minres/scviewer/database/ftr/TxGenerator.java
@@ -10,10 +10,14 @@
*******************************************************************************/
package com.minres.scviewer.database.ftr;
+import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
+import com.minres.scviewer.database.DirectionType;
+import com.minres.scviewer.database.IEventList;
import com.minres.scviewer.database.IWaveform;
+import com.minres.scviewer.database.InputFormatException;
/**
* The Class TxGenerator.
@@ -54,6 +58,30 @@ class TxGenerator extends AbstractTxStream {
return (other instanceof TxGenerator && this.getId()==other.getId());
}
+ /**
+ * Gets the events.
+ *
+ * @return the events
+ */
+ @Override
+ public IEventList getEvents() {
+ if(events.size()==0) {
+ try {
+ List chunks = stream.getChunks();
+ int blockid = 0;
+ for (byte[] bs : chunks) {
+ loader.parseTx(stream, blockid, bs);
+ }
+ } catch (InputFormatException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ } catch (IOException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+ }
+ return events;
+ }
/**
* Gets the begin attrs.
*
@@ -92,4 +120,8 @@ class TxGenerator extends AbstractTxStream {
return ((AbstractTxStream)parent).getFullName()+"."+name;
}
+ @Override
+ public DirectionType getDirection() {
+ return DirectionType.IMPLICIT;
+ }
}
diff --git a/plugins/com.minres.scviewer.database.ftr/src/com/minres/scviewer/database/ftr/TxRelation.java b/plugins/com.minres.scviewer.database.ftr/src/com/minres/scviewer/database/ftr/TxRelation.java
index 0f1e8ba..6a4c158 100644
--- a/plugins/com.minres.scviewer.database.ftr/src/com/minres/scviewer/database/ftr/TxRelation.java
+++ b/plugins/com.minres.scviewer.database.ftr/src/com/minres/scviewer/database/ftr/TxRelation.java
@@ -10,8 +10,14 @@
*******************************************************************************/
package com.minres.scviewer.database.ftr;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+import com.minres.scviewer.database.IWaveform;
import com.minres.scviewer.database.RelationType;
import com.minres.scviewer.database.tx.ITx;
+import com.minres.scviewer.database.tx.ITxAttribute;
import com.minres.scviewer.database.tx.ITxRelation;
/**
@@ -53,7 +59,9 @@ class TxRelation implements ITxRelation {
*/
@Override
public ITx getSource() {
- return loader.getTransaction(scvRelation.source);
+ ITx tx = loader.getTransaction(scvRelation.source);
+ if(tx!=null) return tx;
+ return new TxFacade(scvRelation.source_fiber, scvRelation.source);
}
/**
@@ -63,7 +71,82 @@ class TxRelation implements ITxRelation {
*/
@Override
public ITx getTarget() {
- return loader.getTransaction(scvRelation.target);
+ ITx tx = loader.getTransaction(scvRelation.target);
+ if(tx!=null) return tx;
+ return new TxFacade(scvRelation.target_fiber, scvRelation.target);
}
+ private class TxFacade implements ITx {
+
+ final long fiberId;
+
+ final long txId;
+
+ ITx tx = null;
+
+ public TxFacade(long fiberId, long txId) {
+ this.fiberId = fiberId;
+ this.txId=txId;
+ }
+
+ @Override
+ public int compareTo(ITx o) {
+ return tx==null?-1:tx.compareTo(o);
+ }
+
+ @Override
+ public long getId() {
+ return txId;
+ }
+
+ @Override
+ public IWaveform getStream() {
+ if(tx==null) {
+ TxStream fiber = loader.txStreams.get(fiberId);
+ fiber.loadStream();
+ tx = loader.getTransaction(txId);
+ return loader.txStreams.get(fiberId);
+ } else
+ return tx.getStream();
+ }
+
+ @Override
+ public IWaveform getGenerator() {
+ if(tx==null) {
+ loader.txStreams.get(fiberId).loadStream();
+ tx = loader.getTransaction(txId);
+ }
+ return tx.getGenerator();
+ }
+
+ @Override
+ public long getBeginTime() {
+ return tx==null?-1:tx.getBeginTime();
+ }
+
+ @Override
+ public long getEndTime() {
+ return tx==null?-1:tx.getBeginTime();
+ }
+
+ @Override
+ public List getAttributes() {
+ return tx==null?new ArrayList<>():tx.getAttributes();
+ }
+
+ @Override
+ public Collection getIncomingRelations() {
+ return tx==null?new ArrayList<>():tx.getIncomingRelations();
+ }
+
+ @Override
+ public Collection getOutgoingRelations() {
+ return tx==null?new ArrayList<>():tx.getOutgoingRelations();
+ }
+
+ @Override
+ public String toString() {
+ return tx==null?("tx#" + getId() + "[not available]"):tx.toString();
+ }
+ }
}
diff --git a/plugins/com.minres.scviewer.database.ftr/src/com/minres/scviewer/database/ftr/TxStream.java b/plugins/com.minres.scviewer.database.ftr/src/com/minres/scviewer/database/ftr/TxStream.java
index b47f1ef..c8ab22c 100644
--- a/plugins/com.minres.scviewer.database.ftr/src/com/minres/scviewer/database/ftr/TxStream.java
+++ b/plugins/com.minres.scviewer.database.ftr/src/com/minres/scviewer/database/ftr/TxStream.java
@@ -10,9 +10,12 @@
*******************************************************************************/
package com.minres.scviewer.database.ftr;
+import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
+import com.minres.scviewer.database.DirectionType;
+import com.minres.scviewer.database.IEventList;
import com.minres.scviewer.database.IWaveform;
import com.minres.scviewer.database.InputFormatException;
@@ -69,4 +72,33 @@ class TxStream extends AbstractTxStream {
return chunks;
}
+ public void loadStream() {
+ try {
+ List chunks = getChunks();
+ int blockid = 0;
+ for (byte[] bs : chunks) {
+ loader.parseTx(this, blockid, bs);
+ blockid++;
+ }
+ } catch (InputFormatException e) {
+ } catch (IOException e) {
+ }
+ }
+ /**
+ * Gets the events.
+ *
+ * @return the events
+ */
+ @Override
+ public IEventList getEvents() {
+ if(events.size()==0) {
+ loadStream();
+ }
+ return events;
+ }
+
+ @Override
+ public DirectionType getDirection() {
+ return DirectionType.IMPLICIT;
+ }
}
diff --git a/plugins/com.minres.scviewer.database.sqlite/.settings/org.eclipse.core.resources.prefs b/plugins/com.minres.scviewer.database.sqlite/.settings/org.eclipse.core.resources.prefs
new file mode 100644
index 0000000..99f26c0
--- /dev/null
+++ b/plugins/com.minres.scviewer.database.sqlite/.settings/org.eclipse.core.resources.prefs
@@ -0,0 +1,2 @@
+eclipse.preferences.version=1
+encoding/=UTF-8
diff --git a/plugins/com.minres.scviewer.database.sqlite/pom.xml b/plugins/com.minres.scviewer.database.sqlite/pom.xml
index 60577c0..634ccfc 100644
--- a/plugins/com.minres.scviewer.database.sqlite/pom.xml
+++ b/plugins/com.minres.scviewer.database.sqlite/pom.xml
@@ -4,7 +4,7 @@
com.minres.scviewer
com.minres.scviewer.parent
- 2.17.3
+ 2.18.0
../..
eclipse-plugin
diff --git a/plugins/com.minres.scviewer.database.sqlite/src/com/minres/scviewer/database/sqlite/AbstractTxStream.java b/plugins/com.minres.scviewer.database.sqlite/src/com/minres/scviewer/database/sqlite/AbstractTxStream.java
index cb46eff..9b92b58 100644
--- a/plugins/com.minres.scviewer.database.sqlite/src/com/minres/scviewer/database/sqlite/AbstractTxStream.java
+++ b/plugins/com.minres.scviewer.database.sqlite/src/com/minres/scviewer/database/sqlite/AbstractTxStream.java
@@ -71,6 +71,11 @@ abstract class AbstractTxStream extends HierNode implements IWaveform {
return maxConcurrency;
}
+ @Override
+ public int getWidth() {
+ return 0;
+ }
+
@Override
public IEventList getEvents(){
if(events==null){
diff --git a/plugins/com.minres.scviewer.database.sqlite/src/com/minres/scviewer/database/sqlite/SQLiteDbLoader.java b/plugins/com.minres.scviewer.database.sqlite/src/com/minres/scviewer/database/sqlite/SQLiteDbLoader.java
index 7a47697..ec70b55 100644
--- a/plugins/com.minres.scviewer.database.sqlite/src/com/minres/scviewer/database/sqlite/SQLiteDbLoader.java
+++ b/plugins/com.minres.scviewer.database.sqlite/src/com/minres/scviewer/database/sqlite/SQLiteDbLoader.java
@@ -21,7 +21,6 @@ import java.util.Collection;
import java.util.List;
import com.minres.scviewer.database.IWaveform;
-import com.minres.scviewer.database.IWaveformDb;
import com.minres.scviewer.database.IWaveformDbLoader;
import com.minres.scviewer.database.InputFormatException;
import com.minres.scviewer.database.RelationType;
@@ -94,8 +93,8 @@ public class SQLiteDbLoader implements IWaveformDbLoader {
// }
@Override
- public void load(IWaveformDb db, File file) throws InputFormatException {
- database=new SQLiteDatabase(file.getAbsolutePath(), db);
+ public void load(File file) throws InputFormatException {
+ database=new SQLiteDatabase(file.getAbsolutePath());
database.setData("TIMERESOLUTION", 1L);
SQLiteDatabaseSelectHandler handler = new SQLiteDatabaseSelectHandler<>(ScvSimProps.class, database);
try {
diff --git a/plugins/com.minres.scviewer.database.sqlite/src/com/minres/scviewer/database/sqlite/TxGenerator.java b/plugins/com.minres.scviewer.database.sqlite/src/com/minres/scviewer/database/sqlite/TxGenerator.java
index c773d84..ab47980 100644
--- a/plugins/com.minres.scviewer.database.sqlite/src/com/minres/scviewer/database/sqlite/TxGenerator.java
+++ b/plugins/com.minres.scviewer.database.sqlite/src/com/minres/scviewer/database/sqlite/TxGenerator.java
@@ -16,6 +16,7 @@ import java.sql.SQLException;
import java.util.Map;
import java.util.TreeMap;
+import com.minres.scviewer.database.DirectionType;
import com.minres.scviewer.database.IWaveform;
import com.minres.scviewer.database.sqlite.db.IDatabase;
import com.minres.scviewer.database.sqlite.db.SQLiteDatabaseSelectHandler;
@@ -76,4 +77,8 @@ public class TxGenerator extends AbstractTxStream {
return transactions;
}
+ @Override
+ public DirectionType getDirection() {
+ return DirectionType.IMPLICIT;
+ }
}
diff --git a/plugins/com.minres.scviewer.database.sqlite/src/com/minres/scviewer/database/sqlite/TxStream.java b/plugins/com.minres.scviewer.database.sqlite/src/com/minres/scviewer/database/sqlite/TxStream.java
index a628600..65b2ecf 100644
--- a/plugins/com.minres.scviewer.database.sqlite/src/com/minres/scviewer/database/sqlite/TxStream.java
+++ b/plugins/com.minres.scviewer.database.sqlite/src/com/minres/scviewer/database/sqlite/TxStream.java
@@ -18,6 +18,7 @@ import java.util.List;
import java.util.Map;
import java.util.TreeMap;
+import com.minres.scviewer.database.DirectionType;
import com.minres.scviewer.database.IEvent;
import com.minres.scviewer.database.IWaveform;
import com.minres.scviewer.database.sqlite.db.IDatabase;
@@ -102,4 +103,9 @@ public class TxStream extends AbstractTxStream {
public String getKind() {
return scvStream.getKind();
}
+
+ @Override
+ public DirectionType getDirection() {
+ return DirectionType.IMPLICIT;
+ }
}
diff --git a/plugins/com.minres.scviewer.database.sqlite/src/com/minres/scviewer/database/sqlite/db/SQLiteDatabase.java b/plugins/com.minres.scviewer.database.sqlite/src/com/minres/scviewer/database/sqlite/db/SQLiteDatabase.java
index 5e1d31e..519c885 100644
--- a/plugins/com.minres.scviewer.database.sqlite/src/com/minres/scviewer/database/sqlite/db/SQLiteDatabase.java
+++ b/plugins/com.minres.scviewer.database.sqlite/src/com/minres/scviewer/database/sqlite/db/SQLiteDatabase.java
@@ -26,8 +26,6 @@ public class SQLiteDatabase implements IDatabase {
protected String dbFileName;
- protected IWaveformDb waveformDb;
-
protected HashMap props;
static {
@@ -43,10 +41,9 @@ public class SQLiteDatabase implements IDatabase {
}
}
- public SQLiteDatabase(String dbFileName, IWaveformDb waveformDb) {
+ public SQLiteDatabase(String dbFileName) {
super();
this.dbFileName = dbFileName;
- this.waveformDb = waveformDb;
props = new HashMap();
}
@@ -96,7 +93,7 @@ public class SQLiteDatabase implements IDatabase {
@Override
public IWaveformDb getWaveformDb() {
- return waveformDb;
+ return null;
}
}
diff --git a/plugins/com.minres.scviewer.database.text/.settings/org.eclipse.core.resources.prefs b/plugins/com.minres.scviewer.database.text/.settings/org.eclipse.core.resources.prefs
new file mode 100644
index 0000000..99f26c0
--- /dev/null
+++ b/plugins/com.minres.scviewer.database.text/.settings/org.eclipse.core.resources.prefs
@@ -0,0 +1,2 @@
+eclipse.preferences.version=1
+encoding/=UTF-8
diff --git a/plugins/com.minres.scviewer.database.text/pom.xml b/plugins/com.minres.scviewer.database.text/pom.xml
index 6f77df7..0bbf210 100644
--- a/plugins/com.minres.scviewer.database.text/pom.xml
+++ b/plugins/com.minres.scviewer.database.text/pom.xml
@@ -6,7 +6,7 @@
com.minres.scviewer
com.minres.scviewer.parent
- 2.17.3
+ 2.18.0
../..
eclipse-plugin
diff --git a/plugins/com.minres.scviewer.database.text/src/com/minres/scviewer/database/text/AbstractTxStream.java b/plugins/com.minres.scviewer.database.text/src/com/minres/scviewer/database/text/AbstractTxStream.java
index a3660ae..6950203 100644
--- a/plugins/com.minres.scviewer.database.text/src/com/minres/scviewer/database/text/AbstractTxStream.java
+++ b/plugins/com.minres.scviewer.database.text/src/com/minres/scviewer/database/text/AbstractTxStream.java
@@ -143,6 +143,10 @@ abstract class AbstractTxStream extends HierNode implements IWaveform {
return rowCount;
}
+ @Override
+ public int getWidth() {
+ return 0;
+ }
/**
* Calculate concurrency.
*/
diff --git a/plugins/com.minres.scviewer.database.text/src/com/minres/scviewer/database/text/TextDbLoader.java b/plugins/com.minres.scviewer.database.text/src/com/minres/scviewer/database/text/TextDbLoader.java
index 63796ec..18d291b 100644
--- a/plugins/com.minres.scviewer.database.text/src/com/minres/scviewer/database/text/TextDbLoader.java
+++ b/plugins/com.minres.scviewer.database.text/src/com/minres/scviewer/database/text/TextDbLoader.java
@@ -46,7 +46,6 @@ import com.minres.scviewer.database.AssociationType;
import com.minres.scviewer.database.DataType;
import com.minres.scviewer.database.EventKind;
import com.minres.scviewer.database.IWaveform;
-import com.minres.scviewer.database.IWaveformDb;
import com.minres.scviewer.database.IWaveformDbLoader;
import com.minres.scviewer.database.InputFormatException;
import com.minres.scviewer.database.RelationType;
@@ -222,7 +221,7 @@ public class TextDbLoader implements IWaveformDbLoader {
*/
@SuppressWarnings("unchecked")
@Override
- public void load(IWaveformDb db, File file) throws InputFormatException {
+ public void load(File file) throws InputFormatException {
dispose();
FileType fType = getFileType(file);
if (file.length() < MEMMAP_LIMIT * (fType!=FileType.PLAIN ? 1 : 10)
@@ -520,6 +519,7 @@ public class TextDbLoader implements IWaveformDbLoader {
* @return the long
*/
private long stringToScale(String scale) {
+ // TODO: scale to IWaveformDb.databaseTimeScale
String cmp = scale.trim();
if ("fs".equals(cmp))
return 1L;
diff --git a/plugins/com.minres.scviewer.database.text/src/com/minres/scviewer/database/text/TxGenerator.java b/plugins/com.minres.scviewer.database.text/src/com/minres/scviewer/database/text/TxGenerator.java
index 64c4b3f..cafc839 100644
--- a/plugins/com.minres.scviewer.database.text/src/com/minres/scviewer/database/text/TxGenerator.java
+++ b/plugins/com.minres.scviewer.database.text/src/com/minres/scviewer/database/text/TxGenerator.java
@@ -14,6 +14,7 @@ package com.minres.scviewer.database.text;
import java.util.ArrayList;
import java.util.List;
+import com.minres.scviewer.database.DirectionType;
import com.minres.scviewer.database.IWaveform;
/**
@@ -93,4 +94,8 @@ class TxGenerator extends AbstractTxStream {
return ((AbstractTxStream)parent).getFullName()+"."+name;
}
+ @Override
+ public DirectionType getDirection() {
+ return DirectionType.IMPLICIT;
+ }
}
diff --git a/plugins/com.minres.scviewer.database.text/src/com/minres/scviewer/database/text/TxStream.java b/plugins/com.minres.scviewer.database.text/src/com/minres/scviewer/database/text/TxStream.java
index 2b07cad..f19feb1 100644
--- a/plugins/com.minres.scviewer.database.text/src/com/minres/scviewer/database/text/TxStream.java
+++ b/plugins/com.minres.scviewer.database.text/src/com/minres/scviewer/database/text/TxStream.java
@@ -11,6 +11,7 @@
*******************************************************************************/
package com.minres.scviewer.database.text;
+import com.minres.scviewer.database.DirectionType;
import com.minres.scviewer.database.IWaveform;
/**
@@ -55,4 +56,8 @@ class TxStream extends AbstractTxStream {
return kind;
}
+ @Override
+ public DirectionType getDirection() {
+ return DirectionType.IMPLICIT;
+ }
}
diff --git a/plugins/com.minres.scviewer.database.ui.swt/.settings/org.eclipse.core.resources.prefs b/plugins/com.minres.scviewer.database.ui.swt/.settings/org.eclipse.core.resources.prefs
new file mode 100644
index 0000000..99f26c0
--- /dev/null
+++ b/plugins/com.minres.scviewer.database.ui.swt/.settings/org.eclipse.core.resources.prefs
@@ -0,0 +1,2 @@
+eclipse.preferences.version=1
+encoding/=UTF-8
diff --git a/plugins/com.minres.scviewer.database.ui.swt/pom.xml b/plugins/com.minres.scviewer.database.ui.swt/pom.xml
index cc91144..d8a1455 100644
--- a/plugins/com.minres.scviewer.database.ui.swt/pom.xml
+++ b/plugins/com.minres.scviewer.database.ui.swt/pom.xml
@@ -5,7 +5,7 @@
com.minres.scviewer
com.minres.scviewer.parent
- 2.17.3
+ 2.18.0
../..
4.0.0-SNAPSHOT
diff --git a/plugins/com.minres.scviewer.database.ui.swt/src/com/minres/scviewer/database/ui/ICursor.java b/plugins/com.minres.scviewer.database.ui.swt/src/com/minres/scviewer/database/ui/ICursor.java
index 9c62a46..eb7b160 100644
--- a/plugins/com.minres.scviewer.database.ui.swt/src/com/minres/scviewer/database/ui/ICursor.java
+++ b/plugins/com.minres.scviewer.database.ui.swt/src/com/minres/scviewer/database/ui/ICursor.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2015-2021 MINRES Technologies GmbH and others.
+ * Copyright (c) 2015-2023 MINRES Technologies GmbH and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
@@ -12,8 +12,8 @@ package com.minres.scviewer.database.ui;
public interface ICursor {
- public long getTime();
+ long getTime();
- public void setTime(long time);
+ void setTime(long time);
}
diff --git a/plugins/com.minres.scviewer.database.ui.swt/src/com/minres/scviewer/database/ui/IWaveformView.java b/plugins/com.minres.scviewer.database.ui.swt/src/com/minres/scviewer/database/ui/IWaveformView.java
index cdc41fc..aa87631 100644
--- a/plugins/com.minres.scviewer.database.ui.swt/src/com/minres/scviewer/database/ui/IWaveformView.java
+++ b/plugins/com.minres.scviewer.database.ui.swt/src/com/minres/scviewer/database/ui/IWaveformView.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2015-2021 MINRES Technologies GmbH and others.
+ * Copyright (c) 2015-2023 MINRES Technologies GmbH and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
@@ -35,82 +35,86 @@ public interface IWaveformView extends PropertyChangeListener, ISelectionProvide
static final int MARKER_POS = 1;
- public static final RelationType NEXT_PREV_IN_STREAM = RelationTypeFactory.create("Prev/Next in stream");
+ static final RelationType NEXT_PREV_IN_STREAM = RelationTypeFactory.create("Prev/Next in stream");
- public void addSelectionChangedListener(ISelectionChangedListener listener);
+ void addSelectionChangedListener(ISelectionChangedListener listener);
- public void removeSelectionChangedListener(ISelectionChangedListener listener);
+ void removeSelectionChangedListener(ISelectionChangedListener listener);
- public void setStyleProvider(IWaveformStyleProvider styleProvider);
+ void setStyleProvider(IWaveformStyleProvider styleProvider);
- public void update();
+ void update();
- public Control getControl();
+ Control getControl();
- public Control getNameControl();
+ Control getNameControl();
- public Control getValueControl();
+ Control getValueControl();
- public Control getWaveformControl();
+ Control getWaveformControl();
- public ISelection getSelection();
+ ISelection getSelection();
- public void setSelection(ISelection selection);
+ void setSelection(ISelection selection);
- public void setSelection(ISelection selection, boolean showIfNeeded);
+ void setSelection(ISelection selection, boolean showIfNeeded);
- public void addToSelection(ISelection selection, boolean showIfNeeded);
+ void addToSelection(ISelection selection, boolean showIfNeeded);
- public void moveSelection(GotoDirection direction);
+ void moveSelection(GotoDirection direction);
- public void moveSelection(GotoDirection direction, RelationType relationType);
+ void moveSelection(GotoDirection direction, RelationType relationType);
- public void moveCursor(GotoDirection direction);
+ void moveCursor(GotoDirection direction);
- public List getStreamList();
+ List getStreamList();
- public TrackEntry getEntryFor(ITx source);
+ TrackEntry getEntryFor(ITx source);
- public TrackEntry getEntryFor(IWaveform source);
+ TrackEntry getEntryFor(IWaveform source);
- public List