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..2757ffa --- /dev/null +++ b/plugins/com.minres.scviewer.database.fst/.gitignore @@ -0,0 +1,2 @@ +/bin/ +/.settings/ 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..1e681be --- /dev/null +++ b/plugins/com.minres.scviewer.database.fst/build.properties @@ -0,0 +1,7 @@ +source.. = src/ +output.. = bin/ +bin.includes = META-INF/,\ + .,\ + lib/jna-5.13.0.jar,\ + lib/jna-jpms-5.13.0.jar,\ + linux-x86-64/ 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..9b43064 --- /dev/null +++ b/plugins/com.minres.scviewer.database.fst/csrc/fst/CMakeLists.txt @@ -0,0 +1,21 @@ +cmake_minimum_required (VERSION 3.0) + +project (fstlib VERSION 1.0.0) + +set(BUILD_SHARED_LIBS ON) +find_package(ZLIB REQUIRED) + +add_library(fstapi fstapi.c lz4.c fastlz.c) +target_include_directories(fstapi PUBLIC ${CMAKE_CURRENT_SOURCE_DIR} ${ZLIB_INCLUDE_DIRS}) +target_link_libraries(fstapi PRIVATE ${ZLIB_LIBRARIES}) +# 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 .) 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/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_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..1ee4ab4 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/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..2712963 --- /dev/null +++ b/plugins/com.minres.scviewer.database.fst/src/com/minres/scviewer/database/fst/FstDbLoader.java @@ -0,0 +1,215 @@ +/******************************************************************************* + * 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.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.util.ArrayDeque; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.Vector; +import java.util.zip.GZIPInputStream; + +import com.google.common.collect.Iterables; +import com.minres.scviewer.database.BitVector; +import com.minres.scviewer.database.DoubleVal; +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 Constant TIME_RES. */ + private static final Long TIME_RES = 1000L; // ps + + /** The module stack. */ + private ArrayDeque moduleStack; + + /** The signals. */ + private List signals; + + /** The max time. */ + private long maxTime; + + /** The pcs. */ + protected PropertyChangeSupport pcs = new PropertyChangeSupport(this); + + /* (non-Javadoc) + * @see com.minres.scviewer.database.ITrDb#load(java.io.File) + */ + @SuppressWarnings("unchecked") + @Override + public void load(IWaveformDb db, File file) throws InputFormatException { + dispose(); + this.maxTime=0; + boolean res = false; + signals = new Vector<>(); + moduleStack= new ArrayDeque<>(); + res = new FstFileParser(file).load(this); + moduleStack=null; + if(!res) + throw new InputFormatException("Could not parse VCD file"); + // calculate max time of this database + for(IWaveform waveform:signals) { + IEventList events =waveform.getEvents(); + if(!events.isEmpty()) + maxTime= Math.max(maxTime, events.lastKey()); + } + // extend signals to have a last value set at max time + for(IWaveform s:signals){ + if(s instanceof FstSignal) { + IEventList events = ((FstSignal)s).getEvents(); + if(events.size()>0 && events.lastKey())s).addSignalChange(maxTime, (BitVector) val); + } else if(val instanceof DoubleVal) + ((FstSignal)s).addSignalChange(maxTime, (DoubleVal) val); + } + } + } + pcs.firePropertyChange(IWaveformDbLoader.LOADING_FINISHED, null, null); + } + + public void dispose() { + 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) + */ + @SuppressWarnings("unchecked") + @Override + public Integer newNet(String name, int i, int width) { + String netName = moduleStack.isEmpty()? name: moduleStack.peek()+"."+name; + int id = signals.size(); + if(width==0) { + signals.add( i<0 ? new FstSignal(id, netName, width) : + new FstSignal((FstSignal)signals.get(i), id, netName)); + } else if(width>0){ + signals.add( i<0 ? new FstSignal(id, netName, width) : + new FstSignal((FstSignal)signals.get(i), id, netName)); + } + pcs.firePropertyChange(IWaveformDbLoader.SIGNAL_ADDED, null, Iterables.getLast(signals)); + return id; + } + + /* (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(); + } + + /* (non-Javadoc) + * @see com.minres.scviewer.database.vcd.ITraceBuilder#appendTransition(int, long, com.minres.scviewer.database.vcd.BitVector) + */ + @SuppressWarnings("unchecked") + @Override + public void appendTransition(int signalId, long currentTime, BitVector value) { + FstSignal signal = (FstSignal) signals.get(signalId); + Long time = currentTime* TIME_RES; + signal.addSignalChange(time, value); + } + + /* (non-Javadoc) + * @see com.minres.scviewer.database.vcd.ITraceBuilder#appendTransition(int, long, com.minres.scviewer.database.vcd.BitVector) + */ + @SuppressWarnings("unchecked") + @Override + public void appendTransition(int signalId, long currentTime, double value) { + FstSignal signal = (FstSignal) signals.get(signalId); + Long time = currentTime* TIME_RES; + signal.addSignalChange(time, new DoubleVal(value)); + } + + /* (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); + } + + +} 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..d057e88 --- /dev/null +++ b/plugins/com.minres.scviewer.database.fst/src/com/minres/scviewer/database/fst/FstFileParser.java @@ -0,0 +1,39 @@ +/******************************************************************************* + * 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.*; +import java.text.ParseException; +import java.util.*; + +import com.minres.scviewer.database.BitValue; +import com.minres.scviewer.database.BitVector; +import com.sun.jna.Pointer; + +class FstFileParser { + long currentTime; + final File file; + + public FstFileParser(File file) { + this.file=file; + } + + public boolean load(IFstDatabaseBuilder builder) { + Pointer ctx = FstLibrary.fstReaderOpen(file.getAbsolutePath()); + if(!ctx.equals(Pointer.NULL)) { + String version = FstLibrary.fstReaderGetVersionString(ctx); + System.out.println(version); + FstLibrary.fstReaderClose(ctx); + } + return false; + } + +} 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..4b9df63 --- /dev/null +++ b/plugins/com.minres.scviewer.database.fst/src/com/minres/scviewer/database/fst/FstLibrary.java @@ -0,0 +1,105 @@ +package com.minres.scviewer.database.fst; + +import com.sun.jna.Native; +import com.sun.jna.Platform; +import com.sun.jna.Pointer; + +public class FstLibrary { + public enum FstScopeType { + 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), + FST_ST_GEN_ATTRBEGIN(252), + FST_ST_GEN_ATTREND(253), + + FST_ST_VCD_SCOPE(254), + FST_ST_VCD_UPSCOPE(255); + + public final int label; + private FstScopeType(int label) { + this.label = label; + } + }; + + + public static native Pointer fstReaderOpen(String name); + 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 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); + + /* + void fstReaderClrFacProcessMask(Pointer ctx, fstHandle facidx); + void fstReaderClrFacProcessMaskAll(Pointer ctx); + String fstReaderGetCurrentFlatScope(Pointer ctx); + Pointer fstReaderGetCurrentScopeUserInfo(Pointer ctx); + int fstReaderGetDoubleEndianMatchState(Pointer ctx); + long fstReaderGetDumpActivityChangeTime(Pointer ctx, int idx); + byte fstReaderGetDumpActivityChangeValue(Pointer ctx, int idx); + int fstReaderGetFacProcessMask(Pointer ctx, fstHandle facidx); + int fstReaderGetFseekFailed(Pointer ctx); + fstHandle fstReaderGetMaxHandle(Pointer ctx); + long fstReaderGetMemoryUsedByWriter(Pointer ctx); + int fstReaderGetNumberDumpActivityChanges(Pointer ctx); + String fstReaderGetValueFromHandleAtTime(Pointer ctx, long tim, fstHandle facidx, Stringbuf); + struct fstHier *fstReaderIterateHier(Pointer ctx); + int fstReaderIterateHierRewind(Pointer ctx); + int fstReaderIterBlocks(Pointer ctx, + void (*value_change_callback)(Pointer user_callback_data_pointer, long time, fstHandle facidx, const unsigned Stringvalue), + Pointer user_callback_data_pointer, FILE *vcdhandle); + 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); + Pointer fstReaderOpenForUtilitiesOnly(void); + int fstReaderProcessHier(Pointer ctx, FILE *vcdhandle); + void fstReaderSetFacProcessMask(Pointer ctx, fstHandle facidx); + void fstReaderSetFacProcessMaskAll(Pointer ctx); + 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"); +// System.out.println(System.getProperty("jna.library.path", "UNKNOWN")); + 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..036d012 --- /dev/null +++ b/plugins/com.minres.scviewer.database.fst/src/com/minres/scviewer/database/fst/FstSignal.java @@ -0,0 +1,112 @@ +/******************************************************************************* + * 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.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 long id; + + private String fullName; + + private final int width; + + private IEventList values; + + public FstSignal(String name) { + this(0, name, 1); + } + + public FstSignal(int id, String name) { + this(id,name,1); + } + + public FstSignal(int id, String name, int width) { + super(name); + fullName=name; + this.id=id; + this.width=width; + this.values=new EventList(); + } + + public FstSignal(FstSignal o, int id, String name) { + super(name); + fullName=name; + this.id=id; + this.width=o.width; + this.values=o.values; + } + + @Override + public String getFullName() { + return fullName; + } + + public void setId(int id) { + this.id=id; + } + + @Override + public long getId() { + return id; + } + + public void addSignalChange(Long time, T value){ + values.put(time, value); + } + + @Override + public IEventList getEvents() { + return values; + } + + @Override + public IEvent[] getEventsAtTime(long time) { + return values.get(time); + } + + @Override + public IEvent[] getEventsBeforeTime(long time) { + EventEntry e = values.floorEntry(time); + if(e==null) + return new IEvent[] {}; + else + return values.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 width; + } + + @Override + public String getKind() { + return "signal"; + } + +} diff --git a/plugins/com.minres.scviewer.database.fst/src/com/minres/scviewer/database/fst/HelloWorld.java b/plugins/com.minres.scviewer.database.fst/src/com/minres/scviewer/database/fst/HelloWorld.java new file mode 100644 index 0000000..7e5339d --- /dev/null +++ b/plugins/com.minres.scviewer.database.fst/src/com/minres/scviewer/database/fst/HelloWorld.java @@ -0,0 +1,27 @@ +package com.minres.scviewer.database.fst; + +import com.sun.jna.Library; +import com.sun.jna.Native; +import com.sun.jna.Platform; + +/** Simple example of JNA interface mapping and usage. */ +public class HelloWorld { + + // This is the standard, stable way of mapping, which supports extensive + // customization and mapping of Java to native types. + + public interface CLibrary extends Library { + CLibrary INSTANCE = (CLibrary) + Native.load((Platform.isWindows() ? "msvcrt" : "c"), + CLibrary.class); + + void printf(String format, Object... args); + } + + public static void main(String[] args) { + CLibrary.INSTANCE.printf("Hello, World\n"); + for (int i=0;i < args.length;i++) { + CLibrary.INSTANCE.printf("Argument %d: %s\n", i, args[i]); + } + } +} \ No newline at end of file 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..df61ca6 --- /dev/null +++ b/plugins/com.minres.scviewer.database.fst/src/com/minres/scviewer/database/fst/IFstDatabaseBuilder.java @@ -0,0 +1,68 @@ +/******************************************************************************* + * 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.BitVector; + +/** + * 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 Integer newNet(String netName, int i, int width) ; + + /** + * Gets the net width. + * + * @param intValue the net id + * @return the net width, -1 means a real-valued net + */ + public int getNetWidth(int netId); + + /** + * Append transition. + * + * @param netId the int value + * @param currentTime the current time in ps + * @param decodedValues the decoded values + */ + public void appendTransition(int netId, long currentTime, BitVector decodedValue); + + /** + * Append transition. + * + * @param netId the int value + * @param currentTime the current time in ps + * @param decodedValue the decoded values + */ + public void appendTransition(int netId, long currentTime, double decodedValue); + +} 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 c0e2f4e..483651f 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; @@ -55,7 +56,10 @@ public class FtrDbLoader implements IWaveformDbLoader { ArrayList strDict = new ArrayList<>(); - + FileInputStream fis = null; + + FileLock lock = null; + /** The attr values. */ final List attrValues = new ArrayList<>(); @@ -183,7 +187,9 @@ public class FtrDbLoader implements IWaveformDbLoader { public void load(IWaveformDb db, File file) throws InputFormatException { dispose(); this.file=file; - try(FileInputStream fis = new FileInputStream(file)) { + try { + fis = new FileInputStream(file); + lock=fis.getChannel().lock(0, Long.MAX_VALUE, true); new CborDbParser(this, fis); } catch (IOException e) { LOG.warn("Problem parsing file "+file.getName()+": " , e); @@ -197,7 +203,7 @@ public class FtrDbLoader implements IWaveformDbLoader { public List 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) { @@ -296,6 +302,12 @@ public class FtrDbLoader implements IWaveformDbLoader { */ @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(); diff --git a/tests/com.minres.scviewer.database.test/inputs/my_db.fst b/tests/com.minres.scviewer.database.test/inputs/my_db.fst new file mode 100644 index 0000000..42f3e3e Binary files /dev/null and b/tests/com.minres.scviewer.database.test/inputs/my_db.fst differ diff --git a/tests/com.minres.scviewer.database.test/src/com/minres/scviewer/database/test/DatabaseServicesTest.java b/tests/com.minres.scviewer.database.test/src/com/minres/scviewer/database/test/DatabaseServicesTest.java index b0d8293..04168f3 100644 --- a/tests/com.minres.scviewer.database.test/src/com/minres/scviewer/database/test/DatabaseServicesTest.java +++ b/tests/com.minres.scviewer.database.test/src/com/minres/scviewer/database/test/DatabaseServicesTest.java @@ -144,6 +144,7 @@ public class DatabaseServicesTest { assertEquals(3, attr.size()); }); } + @Test public void testCFtr() throws Exception { File f = new File("inputs/my_db_c.ftr").getAbsoluteFile(); @@ -178,4 +179,21 @@ public class DatabaseServicesTest { assertEquals(3, attr.size()); }); } + + @Test + public void testFst() throws Exception { + File f = new File("inputs/my_db.fst").getAbsoluteFile(); + assertTrue(f.exists()); + waveformDb.load(f); + assertNotNull(waveformDb); + List waves= waveformDb.getAllWaves(); + assertEquals(14, waves.size()); + assertEquals(2, waveformDb.getChildNodes().size()); + IWaveform bus_data_wave = waves.get(0); + EventEntry bus_data_entry = bus_data_wave.getEvents().floorEntry(1400000000L); + assertEquals("00001011", bus_data_entry.events[0].toString()); + IWaveform rw_wave = waves.get(2); + EventEntry rw_entry = rw_wave.getEvents().floorEntry(2360000000L); + assertEquals("1", rw_entry.events[0].toString()); + } }