mirror of
				https://github.com/YosysHQ/yosys
				synced 2025-10-31 11:42:30 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			7221 lines
		
	
	
	
		
			252 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			7221 lines
		
	
	
	
		
			252 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| /*
 | |
|  * Copyright (c) 2009-2023 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
 | |
|  * _WAVE_HAVE_JUDY : use Judy arrays instead of Jenkins (undefine if LGPL is not acceptable)
 | |
|  *
 | |
|  */
 | |
| 
 | |
| #ifndef FST_CONFIG_INCLUDE
 | |
| # define FST_CONFIG_INCLUDE "config.h"
 | |
| #endif
 | |
| #include FST_CONFIG_INCLUDE
 | |
| 
 | |
| #include "fstapi.h"
 | |
| #include "fastlz.h"
 | |
| #include "lz4.h"
 | |
| #include <errno.h>
 | |
| 
 | |
| #ifndef HAVE_LIBPTHREAD
 | |
| #undef FST_WRITER_PARALLEL
 | |
| #endif
 | |
| 
 | |
| #ifdef FST_WRITER_PARALLEL
 | |
| #include <pthread.h>
 | |
| #endif
 | |
| 
 | |
| #if defined __CYGWIN__ || defined __MINGW32__ || defined _MSC_VER
 | |
| #define WIN32_LEAN_AND_MEAN
 | |
| #include <windows.h>
 | |
| #endif
 | |
| 
 | |
| #ifdef HAVE_ALLOCA_H
 | |
| #include <alloca.h>
 | |
| #elif defined(__GNUC__)
 | |
| #ifndef __MINGW32__
 | |
| #ifndef alloca
 | |
| #define alloca __builtin_alloca
 | |
| #endif
 | |
| #else
 | |
| #include <malloc.h>
 | |
| #endif
 | |
| #elif defined(_MSC_VER)
 | |
| #include <malloc.h>
 | |
| #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 <Judy.h>
 | |
| #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)
 | |
| #define FST_ZWRAPPER_HDR_SIZE           (1+8+8)
 | |
| 
 | |
| #if defined(__APPLE__) && defined(__MACH__)
 | |
| #define FST_MACOSX
 | |
| #include <sys/sysctl.h>
 | |
| #endif
 | |
| 
 | |
| #if defined(FST_MACOSX) || defined(__MINGW32__) || defined(_MSC_VER) || defined(__OpenBSD__) || defined(__FreeBSD__) || defined(__NetBSD__)
 | |
| #define FST_UNBUFFERED_IO
 | |
| #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 ***/
 | |
| /***                 ***/
 | |
| /***********************/
 | |
| 
 | |
| #if defined(__MINGW32__) || defined(_MSC_VER)
 | |
| #include <io.h>
 | |
| #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 */
 | |
| 
 | |
| 
 | |
| /*
 | |
|  * report abort messages
 | |
|  */
 | |
| static void chk_report_abort(const char *s)
 | |
| {
 | |
| fprintf(stderr,"Triggered %s security check, exiting.\n", s);
 | |
| abort();
 | |
| }
 | |
| 
 | |
| 
 | |
| /*
 | |
|  * 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 __MINGW32__ || defined _MSC_VER
 | |
| #include <limits.h>
 | |
| #define fstMmap(__addr,__len,__prot,__flags,__fd,__off) fstMmap2((__len), (__fd), (__off))
 | |
| #define fstMunmap(__addr,__len)                         UnmapViewOfFile((LPCVOID)__addr)
 | |
| 
 | |
| static void *fstMmap2(size_t __len, int __fd, fst_off_t __off)
 | |
| {
 | |
| DWORD64 len64 = __len;  /* Must be 64-bit for shift below */
 | |
| HANDLE handle = CreateFileMapping((HANDLE)_get_osfhandle(__fd), NULL,
 | |
| 				  PAGE_READWRITE, (DWORD)(len64 >> 32),
 | |
| 				  (DWORD)__len, NULL);
 | |
| if (!handle) { return NULL; }
 | |
| 
 | |
| void *ptr = MapViewOfFileEx(handle, FILE_MAP_READ | FILE_MAP_WRITE,
 | |
| 			    0, (DWORD)__off, (SIZE_T)__len, (LPVOID)NULL);
 | |
| CloseHandle(handle);
 | |
| return ptr;
 | |
| }
 | |
| #else
 | |
| #include <sys/mman.h>
 | |
| #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
 | |
|  */
 | |
| static uint32_t fstGetUint32(unsigned char *mem)
 | |
| {
 | |
| uint32_t u32;
 | |
| unsigned char *buf = (unsigned char *)(&u32);
 | |
| 
 | |
| memcpy(buf, mem, sizeof(uint32_t));
 | |
| 
 | |
| return(*(uint32_t *)buf);
 | |
| }
 | |
| 
 | |
| 
 | |
| 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<sizeof(uint64_t);i++)
 | |
|         {
 | |
|         val <<= 8;
 | |
|         val |= buf[i];
 | |
|         }
 | |
| 
 | |
| return(val);
 | |
| }
 | |
| 
 | |
| 
 | |
| static uint32_t fstGetVarint32(unsigned char *mem, int *skiplen)
 | |
| {
 | |
| unsigned char *mem_orig = mem;
 | |
| uint32_t rc = 0;
 | |
| while(*mem & 0x80)
 | |
|         {
 | |
|         mem++;
 | |
|         }
 | |
| 
 | |
| *skiplen = mem - mem_orig + 1;
 | |
| for(;;)
 | |
|         {
 | |
|         rc <<= 7;
 | |
|         rc |= (uint32_t)(*mem & 0x7f);
 | |
|         if(mem == mem_orig)
 | |
|                 {
 | |
|                 break;
 | |
|                 }
 | |
|         mem--;
 | |
|         }
 | |
| 
 | |
| return(rc);
 | |
| }
 | |
| 
 | |
| 
 | |
| static uint32_t fstGetVarint32Length(unsigned char *mem)
 | |
| {
 | |
| unsigned char *mem_orig = mem;
 | |
| 
 | |
| while(*mem & 0x80)
 | |
|         {
 | |
|         mem++;
 | |
|         }
 | |
| 
 | |
| return(mem - mem_orig + 1);
 | |
| }
 | |
| 
 | |
| 
 | |
| static uint32_t fstGetVarint32NoSkip(unsigned char *mem)
 | |
| {
 | |
| unsigned char *mem_orig = mem;
 | |
| uint32_t rc = 0;
 | |
| while(*mem & 0x80)
 | |
|         {
 | |
|         mem++;
 | |
|         }
 | |
| 
 | |
| for(;;)
 | |
|         {
 | |
|         rc <<= 7;
 | |
|         rc |= (uint32_t)(*mem & 0x7f);
 | |
|         if(mem == mem_orig)
 | |
|                 {
 | |
|                 break;
 | |
|                 }
 | |
|         mem--;
 | |
|         }
 | |
| 
 | |
| return(rc);
 | |
| }
 | |
| 
 | |
| 
 | |
| static unsigned char *fstCopyVarint32ToLeft(unsigned char *pnt, uint32_t v)
 | |
| {
 | |
| unsigned char *spnt;
 | |
| uint32_t nxt = v;
 | |
| int cnt = 1;
 | |
| int i;
 | |
| 
 | |
| while((nxt = nxt>>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<cnt;i++) /* now generate left to right as normal */
 | |
|         {
 | |
|         nxt = v>>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)
 | |
| {
 | |
| const int chk_len_max = 5; /* TALOS-2023-1783 */
 | |
| int chk_len = chk_len_max;
 | |
| unsigned char buf[chk_len_max];
 | |
| unsigned char *mem = buf;
 | |
| uint32_t rc = 0;
 | |
| int ch;
 | |
| 
 | |
| do
 | |
|         {
 | |
|         ch = fgetc(f);
 | |
|         *(mem++) = ch;
 | |
|         } while((ch & 0x80) && (--chk_len));
 | |
| 
 | |
| if(ch & 0x80) chk_report_abort("TALOS-2023-1783");
 | |
| 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)
 | |
| {
 | |
| const int chk_len_max = 5; /* TALOS-2023-1783 */
 | |
| int chk_len = chk_len_max;
 | |
| unsigned char buf[chk_len_max];
 | |
| unsigned char *mem = buf;
 | |
| uint32_t rc = 0;
 | |
| int ch;
 | |
| 
 | |
| do
 | |
|         {
 | |
|         ch = fgetc(f);
 | |
|         *(mem++) = ch;
 | |
|         } while((ch & 0x80) && (--chk_len));
 | |
| 
 | |
| if(ch & 0x80) chk_report_abort("TALOS-2023-1783");
 | |
| *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)
 | |
| {
 | |
| const int chk_len_max = 16; /* TALOS-2023-1783 */
 | |
| int chk_len = chk_len_max;
 | |
| unsigned char buf[chk_len_max];
 | |
| unsigned char *mem = buf;
 | |
| uint64_t rc = 0;
 | |
| int ch;
 | |
| 
 | |
| do
 | |
|         {
 | |
|         ch = fgetc(f);
 | |
|         *(mem++) = ch;
 | |
|         } while((ch & 0x80) && (--chk_len));
 | |
| 
 | |
| if(ch & 0x80) chk_report_abort("TALOS-2023-1783");
 | |
| 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<siz) && (byt & 0x40))
 | |
|         {
 | |
|         rc |= -(one << shift); /* sign extend */
 | |
|         }
 | |
| 
 | |
| *skiplen = mem - mem_orig;
 | |
| 
 | |
| return(rc);
 | |
| }
 | |
| 
 | |
| 
 | |
| #ifndef FST_DYNAMIC_ALIAS2_DISABLE
 | |
| static int fstWriterSVarint(FILE *handle, int64_t v)
 | |
| {
 | |
| unsigned char buf[15]; /* ceil(64/7) = 10 + sign byte padded way up */
 | |
| unsigned char byt;
 | |
| unsigned char *pnt = buf;
 | |
| int more = 1;
 | |
| int len;
 | |
| 
 | |
| do      {
 | |
|         byt = v | 0x80;
 | |
|         v >>= 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;
 | |
| 
 | |
| memcpy(pnt, u, sizeof(uint32_t));
 | |
| 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;
 | |
| 
 | |
| memcpy(pnt, u, sizeof(uint32_t));
 | |
| 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(pnt == NULL
 | |
| #ifdef MAP_FAILED
 | |
|    || pnt == MAP_FAILED
 | |
| #endif
 | |
|   )
 | |
| 	{
 | |
| 	fprintf(stderr, "fstMmap() assigned to %s failed: errno: %d, file %s, line %d.\n", usage, errno, file, line);
 | |
| #if !defined(__MINGW32__)
 | |
| 	perror("Why");
 | |
| #else
 | |
| 	LPSTR mbuf = NULL;
 | |
| 	FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM
 | |
| 		      | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, GetLastError(),
 | |
| 		      MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
 | |
| 		      (LPSTR)&mbuf, 0, NULL);
 | |
| 	fprintf(stderr, "%s", mbuf);
 | |
| 	LocalFree(mbuf);
 | |
| #endif
 | |
| 	pnt = NULL;
 | |
| 	}
 | |
| }
 | |
| 
 | |
| 
 | |
| 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)
 | |
| {
 | |
| (void)is_closing;
 | |
| 
 | |
| fstMunmap(xc->valpos_mem, xc->maxhandle * 4 * sizeof(uint32_t));
 | |
| xc->valpos_mem = NULL;
 | |
| 
 | |
| 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;i<xc->maxhandle;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;idx<vm4ip[1];idx++)
 | |
|                                         {
 | |
|                                         if((pnt[idx] == '0') || (pnt[idx] == '1'))
 | |
|                                                 {
 | |
|                                                 continue;
 | |
|                                                 }
 | |
|                                                 else
 | |
|                                                 {
 | |
|                                                 is_binary = 0;
 | |
|                                                 break;
 | |
|                                                 }
 | |
|                                         }
 | |
| 
 | |
|                                 if(is_binary)
 | |
|                                         {
 | |
|                                         unsigned char acc = 0;
 | |
|                                         /* new algorithm */
 | |
|                                         idx = ((vm4ip[1]+7) & ~7);
 | |
|                                         switch(vm4ip[1] & 7)
 | |
|                                                 {
 | |
|                                                 case 0: do {    acc  = (pnt[idx+7-8] & 1) << 0; /* fallthrough */
 | |
|                                                 case 7:         acc |= (pnt[idx+6-8] & 1) << 1; /* fallthrough */
 | |
|                                                 case 6:         acc |= (pnt[idx+5-8] & 1) << 2; /* fallthrough */
 | |
|                                                 case 5:         acc |= (pnt[idx+4-8] & 1) << 3; /* fallthrough */
 | |
|                                                 case 4:         acc |= (pnt[idx+3-8] & 1) << 4; /* fallthrough */
 | |
|                                                 case 3:         acc |= (pnt[idx+2-8] & 1) << 5; /* fallthrough */
 | |
|                                                 case 2:         acc |= (pnt[idx+1-8] & 1) << 6; /* fallthrough */
 | |
|                                                 case 1:         acc |= (pnt[idx+0-8] & 1) << 7;
 | |
|                                                                 *(--scratchpnt) = acc;
 | |
|                                                                 idx -= 8;
 | |
|                                                         } while(idx);
 | |
|                                                 }
 | |
| 
 | |
|                                         scratchpnt = fstCopyVarint32ToLeft(scratchpnt, (time_delta << 1));
 | |
|                                         }
 | |
|                                         else
 | |
|                                         {
 | |
|                                         scratchpnt -= vm4ip[1];
 | |
|                                         memcpy(scratchpnt, pnt, vm4ip[1]);
 | |
| 
 | |
|                                         scratchpnt = fstCopyVarint32ToLeft(scratchpnt, (time_delta << 1) | 1);
 | |
|                                         }
 | |
|                                 }
 | |
|                         }
 | |
| 
 | |
|                 wrlen = scratchpad + xc->vchg_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_default((char *)scratchpnt, (char *)dmem, wrlen, packmemlen) : 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;i<xc->maxhandle;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)
 | |
|                                         {
 | |
| 					int32_t  t_i32 = ((int32_t)(prev_alias = vm4ip[2])); /* vm4ip is generic unsigned data */
 | |
| 					int64_t  t_i64 = (int64_t)t_i32; /* convert to signed */
 | |
| 					uint64_t t_u64 = (uint64_t)t_i64; /* sign extend through 64b */
 | |
| 
 | |
| 					fpos += fstWriterSVarint(f, (int64_t)((t_u64 << 1) | 1)); /* all in this block was: fpos += fstWriterSVarint(f, (((int64_t)((int32_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;i<xc->maxhandle;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));
 | |
| 
 | |
| 	if(sizeof(size_t) < sizeof(uint64_t))
 | |
| 		{
 | |
| 		/* TALOS-2023-1777 for 32b overflow */
 | |
| 		uint64_t chk_64 = xc->maxhandle * 4 * sizeof(uint32_t);
 | |
| 		size_t   chk_32 = xc->maxhandle * 4 * sizeof(uint32_t);
 | |
| 		if(chk_64 != chk_32) chk_report_abort("TALOS-2023-1777");
 | |
| 		}
 | |
| 
 | |
|         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;i<xc->maxhandle;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;i<xc->num_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__
 | |
| 		int fnam_len = strlen(xc->filename) + 5 + 1;
 | |
|                 char *fnam = (char *)malloc(fnam_len);
 | |
| #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_default((char *)hmem, (char *)mem, xc->hier_file_len, lz4_maxlen);
 | |
|                         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_default((char *)mem, (char *)mem_duo, packed_len, lz4_maxlen_duo);
 | |
| 
 | |
|                                 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__
 | |
|                 snprintf(fnam, fnam_len, "%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<<FST_SDT_SVT_SHIFT_COUNT) | (sdt & FST_SDT_ABS_MAX));
 | |
| return(fstWriterCreateVar(ctx, vt, vd, len, nam, aliasHandle));
 | |
| }
 | |
| 
 | |
| 
 | |
| fstHandle fstWriterCreateVar(void *ctx, enum fstVarType vt, enum fstVarDir vd,
 | |
|         uint32_t len, const char *nam, fstHandle aliasHandle)
 | |
| {
 | |
| struct fstWriterContext *xc = (struct fstWriterContext *)ctx;
 | |
| unsigned int i;
 | |
| int nlen, is_real;
 | |
| 
 | |
| if(xc && nam)
 | |
|         {
 | |
|         if(xc->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;i<len;i++)
 | |
|                                 {
 | |
|                                 fputc('x', xc->curval_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 = snprintf(elem_count_buf, 16, "%" 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<elem_count;i++)
 | |
| 		{
 | |
| 		literal_lens[i] = strlen(literal_arr[i]);
 | |
| 		lit_len_tot += fstUtilityBinToEscConvertedLen((unsigned char*)literal_arr[i], literal_lens[i]);
 | |
| 
 | |
| 		val_lens[i] =  strlen(val_arr[i]);
 | |
| 		val_len_tot += fstUtilityBinToEscConvertedLen((unsigned char*)val_arr[i], val_lens[i]);
 | |
| 
 | |
| 		if(min_valbits > 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<elem_count;i++)
 | |
| 		{
 | |
| 		pos += fstUtilityBinToEsc((unsigned char*)attr_str+pos, (unsigned char*)literal_arr[i], literal_lens[i]);
 | |
| 		attr_str[pos++] = ' ';
 | |
| 		}
 | |
| 
 | |
| 	for(i=0;i<elem_count;i++)
 | |
| 		{
 | |
| 		if(min_valbits > 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;i<len;i++)
 | |
|                                                                 {
 | |
|                                                                 if(buf[i]!='x') break;
 | |
|                                                                 }
 | |
| 
 | |
|                                                         if(i<len) return;
 | |
|                                                         }
 | |
|                                                         else
 | |
|                                                         {
 | |
|                                                         return;
 | |
|                                                         }
 | |
|                                                 }
 | |
|                                         }
 | |
| 
 | |
|                                 memcpy(xc->curval_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;i<xc->maxhandle;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];
 | |
| char *str_scope_attr;
 | |
| 
 | |
| 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, uint32_t len) /* TALOS-2023-1793: change len to unsigned */
 | |
| {
 | |
| 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(facidx<xc->maxhandle)
 | |
|                 {
 | |
|                 int process_idx = facidx/8;
 | |
|                 int process_bit = facidx&7;
 | |
| 
 | |
|                 return( (xc->process_mask[process_idx]&(1<<process_bit)) != 0 );
 | |
|                 }
 | |
|         }
 | |
| return(0);
 | |
| }
 | |
| 
 | |
| 
 | |
| void fstReaderSetFacProcessMask(void *ctx, fstHandle facidx)
 | |
| {
 | |
| struct fstReaderContext *xc = (struct fstReaderContext *)ctx;
 | |
| 
 | |
| if(xc)
 | |
|         {
 | |
|         facidx--;
 | |
|         if(facidx<xc->maxhandle)
 | |
|                 {
 | |
|                 int idx = facidx/8;
 | |
|                 int bitpos = facidx&7;
 | |
| 
 | |
|                 xc->process_mask[idx] |= (1<<bitpos);
 | |
|                 }
 | |
|         }
 | |
| }
 | |
| 
 | |
| 
 | |
| void fstReaderClrFacProcessMask(void *ctx, fstHandle facidx)
 | |
| {
 | |
| struct fstReaderContext *xc = (struct fstReaderContext *)ctx;
 | |
| 
 | |
| if(xc)
 | |
|         {
 | |
|         facidx--;
 | |
|         if(facidx<xc->maxhandle)
 | |
|                 {
 | |
|                 int idx = facidx/8;
 | |
|                 int bitpos = facidx&7;
 | |
| 
 | |
|                 xc->process_mask[idx] &= (~(1<<bitpos));
 | |
|                 }
 | |
|         }
 | |
| }
 | |
| 
 | |
| 
 | |
| void fstReaderSetFacProcessMaskAll(void *ctx)
 | |
| {
 | |
| struct fstReaderContext *xc = (struct fstReaderContext *)ctx;
 | |
| 
 | |
| if(xc)
 | |
|         {
 | |
|         memset(xc->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;
 | |
|  int len = 0;
 | |
| 
 | |
| /* zero is illegal for a value...it is assumed they start at one */
 | |
| while (value && len < 14)
 | |
|         {
 | |
|         value--;
 | |
| 	++len;
 | |
|         *(pnt++) = (char)('!' + value % 94);
 | |
|         value = value / 94;
 | |
|         }
 | |
| 
 | |
| return len;
 | |
| }
 | |
| 
 | |
| 
 | |
| static int fstReaderRecreateHierFile(struct fstReaderContext *xc)
 | |
| {
 | |
| int pass_status = 1;
 | |
| 
 | |
| if(!xc->fh)
 | |
|         {
 | |
|         fst_off_t offs_cache = ftello(xc->f);
 | |
| 	int fnam_len = strlen(xc->filename) + 6 + 16 + 32 + 1;
 | |
|         char *fnam = (char *)malloc(fnam_len);
 | |
|         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;
 | |
|                 }
 | |
| 
 | |
|         snprintf(fnam, fnam_len, "%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);
 | |
| 	int cl;
 | |
|         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;
 | |
| 			cl = 0;
 | |
|                         while((ch = fgetc(xc->fh)))
 | |
|                                 {
 | |
| 				if(cl < FST_ID_NAM_SIZ)
 | |
| 					{
 | |
| 					pnt[cl++] = ch;
 | |
| 					}
 | |
|                                 }; /* scopename */
 | |
|                         pnt[cl] = 0;
 | |
|                         xc->hier.u.scope.name_length = cl;
 | |
| 
 | |
|                         xc->hier.u.scope.component = pnt = xc->str_scope_comp;
 | |
| 			cl = 0;
 | |
|                         while((ch = fgetc(xc->fh)))
 | |
|                                 {
 | |
| 				if(cl < FST_ID_NAM_SIZ)
 | |
| 					{
 | |
| 					pnt[cl++] = ch;
 | |
| 					}
 | |
|                                 }; /* scopecomp */
 | |
|                         pnt[cl] = 0;
 | |
|                         xc->hier.u.scope.component_length = cl;
 | |
|                         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);
 | |
| 			if(!xc->str_scope_attr)
 | |
| 				{
 | |
| 				xc->str_scope_attr = (char *)calloc(1, FST_ID_NAM_ATTR_SIZ+1);
 | |
| 				}
 | |
|                         xc->hier.u.attr.name = pnt = xc->str_scope_attr;
 | |
| 			cl = 0;
 | |
|                         while((ch = fgetc(xc->fh)))
 | |
|                                 {
 | |
| 				if(cl < FST_ID_NAM_ATTR_SIZ)
 | |
| 					{
 | |
| 					pnt[cl++] = ch;
 | |
| 					}
 | |
|                                 }; /* attrname */
 | |
| 			pnt[cl] = 0;
 | |
|                         xc->hier.u.attr.name_length = cl;
 | |
| 
 | |
|                         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_attr, &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;
 | |
| 			cl = 0;
 | |
|                         while((ch = fgetc(xc->fh)))
 | |
|                                 {
 | |
| 				if(cl < FST_ID_NAM_SIZ)
 | |
| 					{
 | |
| 					pnt[cl++] = ch;
 | |
| 					}
 | |
|                                 }; /* varname */
 | |
|                         pnt[cl] = 0;
 | |
|                         xc->hier.u.var.name_length = cl;
 | |
|                         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;
 | |
| int cl;
 | |
| 
 | |
| 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;
 | |
| 			cl = 0;
 | |
|                         while((ch = fgetc(xc->fh)))
 | |
|                                 {
 | |
| 				if(cl < FST_ID_NAM_ATTR_SIZ)
 | |
| 					{
 | |
| 					pnt[cl++] = ch;
 | |
| 					}
 | |
|                                 }; /* scopename */
 | |
|                         pnt[cl] = 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;
 | |
| 			cl = 0;
 | |
|                         while((ch = fgetc(xc->fh)))
 | |
|                                 {
 | |
| 				if(cl < FST_ID_NAM_ATTR_SIZ)
 | |
| 					{
 | |
| 					pnt[cl++] = ch;
 | |
| 					}
 | |
|                                 }; /* attrname */
 | |
|                         pnt[cl] = 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;
 | |
| 			cl = 0;
 | |
|                         while((ch = fgetc(xc->fh)))
 | |
|                                 {
 | |
| 				if(cl < FST_ID_NAM_ATTR_SIZ)
 | |
| 					{
 | |
| 					pnt[cl++] = ch;
 | |
| 					}
 | |
|                                 }; /* varname */
 | |
|                         pnt[cl] = 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;
 | |
| 	int hf_len;
 | |
| 
 | |
|         seclen = fstReaderUint64(xc->f);
 | |
|         uclen = fstReaderUint64(xc->f);
 | |
| 
 | |
|         if(!seclen) return(0); /* not finished compressing, this is a failed read */
 | |
| 
 | |
| 	hf_len = flen + 16 + 32 + 1;
 | |
|         hf = (char *)calloc(1, hf_len);
 | |
| 
 | |
|         snprintf(hf, hf_len, "%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_UNBUFFERED_IO)
 | |
|         setvbuf(fcomp, (char *)NULL, _IONBF, 0);   /* keeps gzip from acting weird in tandem with fopen */
 | |
| #endif
 | |
| 
 | |
| #ifdef __MINGW32__
 | |
|         xc->filename_unpacked = hf;
 | |
| #else
 | |
|         if(hf)
 | |
|                 {
 | |
|                 unlink(hf);
 | |
|                 free(hf);
 | |
|                 }
 | |
| #endif
 | |
| 
 | |
|         fstReaderFseeko(xc, xc->f, FST_ZWRAPPER_HDR_SIZE, SEEK_SET);
 | |
| #if !defined(__MINGW32__) && !defined(_MSC_VER)
 | |
|         fflush(xc->f);
 | |
| #else
 | |
| 	/* Windows UCRT runtime library reads one byte ahead in the file
 | |
| 	   even with buffering disabled and does not synchronise the
 | |
| 	   file position after fseek. */
 | |
| 	_lseek(fileno(xc->f), FST_ZWRAPPER_HDR_SIZE, SEEK_SET);
 | |
| #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;i<xc->maxhandle;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;i<xc->num_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(FST_UNBUFFERED_IO)
 | |
|         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;
 | |
| 	free(xc->str_scope_attr); xc->str_scope_attr = 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;
 | |
| 	uint32_t tc_head_items = 0;
 | |
|         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;i<tsec_nitems;i++) below would do this earlier */
 | |
|                         {
 | |
|                         break;
 | |
|                         }
 | |
|                 }
 | |
| 
 | |
| 
 | |
|         mem_required_for_traversal = fstReaderUint64(xc->f) + 66; /* add in potential fastlz overhead */
 | |
|         mem_for_traversal = (unsigned char *)malloc(mem_required_for_traversal);
 | |
| #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-66);
 | |
| #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);
 | |
| 
 | |
| 	if(sizeof(size_t) < sizeof(uint64_t))
 | |
| 		{
 | |
| 		/* TALOS-2023-1792 for 32b overflow */
 | |
| 		uint64_t chk_64 = tsec_nitems * sizeof(uint64_t);
 | |
| 		size_t   chk_32 = ((size_t)tsec_nitems) * sizeof(uint64_t);
 | |
| 		if(chk_64 != chk_32) chk_report_abort("TALOS-2023-1792");
 | |
| 		}
 | |
| 	else
 | |
| 		{
 | |
| 		uint64_t chk_64 = tsec_nitems * sizeof(uint64_t);
 | |
| 		if((chk_64/sizeof(uint64_t)) != tsec_nitems)
 | |
| 			{
 | |
| 			chk_report_abort("TALOS-2023-1792");
 | |
| 			}
 | |
| 		}
 | |
|         time_table = (uint64_t *)calloc(tsec_nitems, sizeof(uint64_t));
 | |
|         tpnt = ucdata;
 | |
|         tpval = 0;
 | |
|         for(ti=0;ti<tsec_nitems;ti++)
 | |
|                 {
 | |
|                 int skiplen;
 | |
|                 uint64_t val = fstGetVarint64(tpnt, &skiplen);
 | |
|                 tpval = time_table[ti] = tpval + val;
 | |
|                 tpnt += skiplen;
 | |
|                 }
 | |
| 
 | |
| 	tc_head_items = tsec_nitems /* scan-build */ ? tsec_nitems : 1;
 | |
| 	if(sizeof(size_t) < sizeof(uint64_t))
 | |
| 		{
 | |
| 		/* TALOS-2023-1792 for 32b overflow */
 | |
| 		uint64_t chk_64 = tc_head_items * sizeof(uint32_t);
 | |
| 		size_t   chk_32 = ((size_t)tc_head_items) * sizeof(uint32_t);
 | |
| 		if(chk_64 != chk_32) chk_report_abort("TALOS-2023-1792");
 | |
| 		}
 | |
| 	else
 | |
| 		{
 | |
| 		uint64_t chk_64 = tc_head_items * sizeof(uint32_t);
 | |
| 		if((chk_64/sizeof(uint32_t)) != tc_head_items)
 | |
| 			{
 | |
| 			chk_report_abort("TALOS-2023-1792");
 | |
| 			}
 | |
| 		}
 | |
|         tc_head = (uint32_t *)calloc(tc_head_items, sizeof(uint32_t));
 | |
|         free(ucdata);
 | |
|         }
 | |
| 
 | |
|         fstReaderFseeko(xc, xc->f, 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 = snprintf(wx_buf, 32, "$end\n"); fstWritex(xc, wx_buf, wx_len); dumpvars_state = 2; }
 | |
|                                         wx_len = snprintf(wx_buf, 32, "#%" PRIu64 "\n", beg_tim);
 | |
|                                         fstWritex(xc, wx_buf, wx_len);
 | |
| 					if(!dumpvars_state) { wx_len = snprintf(wx_buf, 32, "$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 = snprintf(wx_buf, 32, "$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;idx<frame_maxhandle;idx++)
 | |
|                                 {
 | |
|                                 int process_idx = idx/8;
 | |
|                                 int process_bit = idx&7;
 | |
| 
 | |
|                                 if(xc->process_mask[process_idx]&(1<<process_bit))
 | |
|                                         {
 | |
|                                         if(xc->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)
 | |
|                                                                 {
 | |
| 								if(xc->signal_lens[idx] > xc->longest_signal_value_len)
 | |
| 									{
 | |
| 									chk_report_abort("TALOS-2023-1797");
 | |
| 									}
 | |
|                                                                 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);
 | |
| 									if((sig_offs + xc->signal_lens[idx]) > frame_uclen)
 | |
| 										{
 | |
| 										chk_report_abort("TALOS-2023-1793");
 | |
| 										}
 | |
|                                                                         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];
 | |
|                                                                                         }
 | |
|                                                                                 }
 | |
|                                                                         snprintf((char *)xc->temp_signal_value_buf, xc->longest_signal_value_len + 1, "%.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 = snprintf(wx_buf, 64, "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;
 | |
| 
 | |
| 		if(!(vc_maxhandle+1))
 | |
| 			{
 | |
| 			chk_report_abort("TALOS-2023-1798");
 | |
| 			}
 | |
| 
 | |
| 		if(sizeof(size_t) < sizeof(uint64_t))
 | |
| 			{
 | |
| 			/* TALOS-2023-1798 for 32b overflow */
 | |
| 			uint64_t chk_64 = (vc_maxhandle+1) * sizeof(fst_off_t);
 | |
| 			size_t   chk_32 = ((size_t)(vc_maxhandle+1)) * sizeof(fst_off_t);
 | |
| 			if(chk_64 != chk_32) chk_report_abort("TALOS-2023-1798");
 | |
| 			}
 | |
| 		else
 | |
| 			{
 | |
| 			uint64_t chk_64 = (vc_maxhandle+1) * sizeof(fst_off_t);
 | |
| 				if((chk_64/sizeof(fst_off_t)) != (vc_maxhandle+1))
 | |
| 				{
 | |
| 				chk_report_abort("TALOS-2023-1798");
 | |
| 				}
 | |
| 			}
 | |
|                 chain_table = (fst_off_t *)calloc((vc_maxhandle+1), sizeof(fst_off_t));
 | |
| 
 | |
| 		if(sizeof(size_t) < sizeof(uint64_t))
 | |
| 			{
 | |
| 			/* TALOS-2023-1798 for 32b overflow */
 | |
| 			uint64_t chk_64 = (vc_maxhandle+1) * sizeof(uint32_t);
 | |
| 			size_t   chk_32 = ((size_t)(vc_maxhandle+1)) * sizeof(uint32_t);
 | |
| 			if(chk_64 != chk_32) chk_report_abort("TALOS-2023-1798");
 | |
| 			}
 | |
| 		else
 | |
| 			{
 | |
| 			uint64_t chk_64 = (vc_maxhandle+1) * sizeof(uint32_t);
 | |
| 				if((chk_64/sizeof(uint32_t)) != (vc_maxhandle+1))
 | |
| 				{
 | |
| 				chk_report_abort("TALOS-2023-1798");
 | |
| 				}
 | |
| 			}
 | |
|                 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;
 | |
| 				if((idx+loopcnt-1) > vc_maxhandle) /* TALOS-2023-1789 */
 | |
| 					{
 | |
| 					chk_report_abort("TALOS-2023-1789");
 | |
| 					}
 | |
| 
 | |
|                                 for(i=0;i<loopcnt;i++)
 | |
|                                         {
 | |
|                                         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);
 | |
|                                 chain_table[idx] = 0;                   /* need to explicitly zero as calloc above might not run */
 | |
|                                 chain_table_lengths[idx] = -val;        /* because during this loop iter would give stale data! */
 | |
|                                 idx++;
 | |
|                                 }
 | |
|                         else
 | |
|                         if(val&1)
 | |
|                                 {
 | |
|                                 pval = chain_table[idx] = pval + (val >> 1);
 | |
|                                 if(idx) { chain_table_lengths[pidx] = pval - chain_table[pidx]; }
 | |
|                                 pidx = idx++;
 | |
|                                 }
 | |
|                         else
 | |
|                                 {
 | |
|                                 fstHandle loopcnt = val >> 1;
 | |
| 
 | |
| 				if((idx+loopcnt-1) > vc_maxhandle) /* TALOS-2023-1789 */
 | |
| 					{
 | |
| 					chk_report_abort("TALOS-2023-1789");
 | |
| 					}
 | |
| 
 | |
|                                 for(i=0;i<loopcnt;i++)
 | |
|                                         {
 | |
|                                         chain_table[idx++] = 0;
 | |
|                                         }
 | |
|                                 }
 | |
| 
 | |
|                         pnt += skiplen;
 | |
|                         } while (pnt != (chain_cmem + chain_clen));
 | |
|                 }
 | |
| 
 | |
|         chain_table[idx] = indx_pos - vc_start;
 | |
|         chain_table_lengths[pidx] = chain_table[idx] - chain_table[pidx];
 | |
| 
 | |
|         for(i=0;i<idx;i++)
 | |
|                 {
 | |
|                 int32_t v32 = chain_table_lengths[i];
 | |
|                 if((v32 < 0) && (!chain_table[i]))
 | |
|                         {
 | |
|                         v32 = -v32;
 | |
|                         v32--;
 | |
|                         if(((uint32_t)v32) < i) /* sanity check */
 | |
|                                 {
 | |
|                                 chain_table[i] = chain_table[v32];
 | |
|                                 chain_table_lengths[i] = chain_table_lengths[v32];
 | |
|                                 }
 | |
|                         }
 | |
|                 }
 | |
| 
 | |
| #ifdef FST_DEBUG
 | |
|         fprintf(stderr, FST_APIMESS "decompressed chain idx len: %" PRIu32 "\n", idx);
 | |
| #endif
 | |
| 
 | |
|         mc_mem_len = 16384;
 | |
|         mc_mem = (unsigned char *)malloc(mc_mem_len); /* buffer for compressed reads */
 | |
| 
 | |
|         /* check compressed VC data */
 | |
|         if(idx > xc->maxhandle) idx = xc->maxhandle;
 | |
|         for(i=0;i<idx;i++)
 | |
|                 {
 | |
|                 if(chain_table[i])
 | |
|                         {
 | |
|                         int process_idx = i/8;
 | |
|                         int process_bit = i&7;
 | |
| 
 | |
|                         if(xc->process_mask[process_idx]&(1<<process_bit))
 | |
|                                 {
 | |
|                                 int rc = Z_OK;
 | |
|                                 uint32_t val;
 | |
|                                 uint32_t skiplen;
 | |
|                                 uint32_t tdelta;
 | |
| 
 | |
|                                 fstReaderFseeko(xc, xc->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(traversal_mem_offs >= mem_required_for_traversal)
 | |
| 						{
 | |
| 						chk_report_abort("TALOS-2023-1785");
 | |
| 						}
 | |
| 
 | |
|                                         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;j<destlen;j++) in mu[j] */
 | |
|                                         headptr[i] = traversal_mem_offs;
 | |
|                                         length_remaining[i] = val;
 | |
|                                         traversal_mem_offs += val;
 | |
|                                         }
 | |
|                                         else
 | |
|                                         {
 | |
|                                         int destlen = chain_table_lengths[i] - skiplen;
 | |
|                                         unsigned char *mu = mem_for_traversal + traversal_mem_offs;
 | |
| 
 | |
| 					if(traversal_mem_offs >= mem_required_for_traversal)
 | |
| 						{
 | |
| 						chk_report_abort("TALOS-2023-1785");
 | |
| 						}
 | |
| 
 | |
|                                         fstFread(mu, destlen, 1, xc->f);
 | |
|                                         /* data to process is for(j=0;j<destlen;j++) in mu[j] */
 | |
|                                         headptr[i] = traversal_mem_offs;
 | |
|                                         length_remaining[i] = destlen;
 | |
|                                         traversal_mem_offs += destlen;
 | |
|                                         }
 | |
| 
 | |
|                                 if(rc != Z_OK)
 | |
|                                         {
 | |
|                                         fprintf(stderr, FST_APIMESS "fstReaderIterBlocks2(), fac: %d clen: %d (rc=%d), exiting.\n", (int)i, (int)val, rc);
 | |
|                                         exit(255);
 | |
|                                         }
 | |
| 
 | |
|                                 if(xc->signal_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;
 | |
|                                         }
 | |
| 
 | |
| 				if(tdelta >= tc_head_items)
 | |
| 					{
 | |
| 					chk_report_abort("TALOS-2023-1791");
 | |
| 					}
 | |
| 
 | |
|                                 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;i<tsec_nitems;i++)
 | |
|                 {
 | |
|                 uint32_t tdelta;
 | |
|                 int skiplen, skiplen2;
 | |
|                 uint32_t vli;
 | |
| 
 | |
|                 if(fv)
 | |
|                         {
 | |
|                         char wx_buf[32];
 | |
|                         int wx_len;
 | |
| 
 | |
|                         if(time_table[i] != previous_time)
 | |
|                                 {
 | |
|                                 if(xc->limit_range_valid)
 | |
|                                         {
 | |
|                                         if(time_table[i] > xc->limit_range_end)
 | |
|                                                 {
 | |
|                                                 break;
 | |
|                                                 }
 | |
|                                         }
 | |
| 
 | |
| 				if(dumpvars_state == 1) { wx_len = snprintf(wx_buf, 32, "$end\n"); fstWritex(xc, wx_buf, wx_len); dumpvars_state = 2; }
 | |
|                                 wx_len = snprintf(wx_buf, 32, "#%" PRIu64 "\n", time_table[i]);
 | |
|                                 fstWritex(xc, wx_buf, wx_len);
 | |
| 				if(!dumpvars_state) { wx_len = snprintf(wx_buf, 32, "$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 = snprintf(wx_buf, 32, "$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;
 | |
| 
 | |
| 						if((tdelta+i) >= tc_head_items)
 | |
| 							{
 | |
| 							chk_report_abort("TALOS-2023-1791");
 | |
| 							}
 | |
| 
 | |
|                                                 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);
 | |
|                                                                 {
 | |
| 								if(sizeof(size_t) < sizeof(uint64_t))
 | |
|                 							{
 | |
|                 							/* TALOS-2023-1790 for 32b overflow */
 | |
|                 							uint64_t chk_64 = len*4 + 1;
 | |
|                 							size_t   chk_32 = len*4 + 1;
 | |
|                 							if(chk_64 != chk_32) chk_report_abort("TALOS-2023-1790");
 | |
|                 							}
 | |
| 
 | |
|                                                                 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;
 | |
| 
 | |
| 						if((tdelta+i) >= tc_head_items)
 | |
| 							{
 | |
| 							chk_report_abort("TALOS-2023-1791");
 | |
| 							}
 | |
| 
 | |
|                                                 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(len > xc->longest_signal_value_len)
 | |
| 						{
 | |
| 						chk_report_abort("TALOS-2023-1797");
 | |
| 						}
 | |
| 
 | |
|                                         if(!(vli & 1))
 | |
|                                                 {
 | |
|                                                 int byte = 0;
 | |
|                                                 int bit;
 | |
|                                                 unsigned int j;
 | |
| 
 | |
|                                                 for(j=0;j<len;j++)
 | |
|                                                         {
 | |
|                                                         unsigned char ch;
 | |
|                                                         byte = j/8;
 | |
|                                                         bit = 7 - (j & 7);
 | |
|                                                         ch = ((vdata[byte] >> 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';
 | |
| 								uint64_t mem_required_for_traversal_chk = vdata - mem_for_traversal + len;
 | |
| 
 | |
|                                                                 fstWritex(xc, &ch_bp, 1);
 | |
| 								if(mem_required_for_traversal_chk > mem_required_for_traversal)
 | |
| 									{
 | |
| 									chk_report_abort("TALOS-2023-1793");
 | |
| 									}
 | |
|                                                                 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];
 | |
|                                                                         }
 | |
|                                                                 }
 | |
|                                                         snprintf((char *)xc->temp_signal_value_buf, xc->longest_signal_value_len + 1, "%.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 = snprintf(wx_buf, 32, "r%.16g", d);
 | |
|                                                         if (wx_len > 32 || wx_len < 0) wx_len = 32;
 | |
|                                                         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;
 | |
| 
 | |
| 					if((tdelta+i) >= tc_head_items)
 | |
| 						{
 | |
| 						chk_report_abort("TALOS-2023-1791");
 | |
| 						}
 | |
| 
 | |
|                                         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];
 | |
|                                 }
 | |
|                         }
 | |
| 
 | |
|                 snprintf((char *)buf, 32, "%.16g", d); /* this will write 18 bytes */
 | |
|                 }
 | |
|         }
 | |
| 
 | |
| 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;
 | |
| #ifdef FST_DEBUG
 | |
| unsigned int secnum = 0;
 | |
| #endif
 | |
| 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;i<xc->maxhandle;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;
 | |
| #ifdef FST_DEBUG
 | |
|         secnum++;
 | |
| #endif
 | |
|         }
 | |
| 
 | |
| 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;ti<tsec_nitems;ti++)
 | |
|         {
 | |
|         int skiplen;
 | |
|         uint64_t val = fstGetVarint64(tpnt, &skiplen);
 | |
|         tpval = xc->rvat_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;i<loopcnt;i++)
 | |
|                                 {
 | |
|                                 xc->rvat_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;i<loopcnt;i++)
 | |
| 	                        {
 | |
| 	                        xc->rvat_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;i<idx;i++)
 | |
|         {
 | |
|         int32_t v32 = xc->rvat_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;j<destlen;j++) in mu[j] */
 | |
|                 xc->rvat_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;j<destlen;j++) in mu[j] */
 | |
|                 xc->rvat_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(i<xc->rvat_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(i<xc->rvat_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;j<xc->signal_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];
 | |
|                                         }
 | |
|                                 }
 | |
| 
 | |
|                         snprintf(buf, 32, "r%.16g", d); /* this will write 19 bytes */
 | |
|                         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<n; ++i) h = hash( k[i], len[i], h);
 | |
| 
 | |
| By Bob Jenkins, 1996.  bob_jenkins@burtleburtle.net.  You may use this
 | |
| code any way you wish, private, educational, or commercial.  It's free.
 | |
| 
 | |
| See http://burtleburtle.net/bob/hash/evahash.html
 | |
| Use for hash table lookup, or anything where one collision in 2^^32 is
 | |
| acceptable.  Do NOT use for cryptographic purposes.
 | |
| --------------------------------------------------------------------
 | |
| */
 | |
| 
 | |
| static uint32_t j_hash(const uint8_t *k, uint32_t length, uint32_t initval)
 | |
| {
 | |
|    uint32_t a,b,c,len;
 | |
| 
 | |
|    /* Set up the internal state */
 | |
|    len = length;
 | |
|    a = b = 0x9e3779b9;  /* the golden ratio; an arbitrary value */
 | |
|    c = initval;         /* the previous hash value */
 | |
| 
 | |
|    /*---------------------------------------- handle most of the key */
 | |
|    while (len >= 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<len;i++)
 | |
|         {
 | |
|         switch(src[i])
 | |
|                 {
 | |
|                 case '\a':      /* fallthrough */
 | |
|                 case '\b':	/* fallthrough */
 | |
|                 case '\f':	/* fallthrough */
 | |
|                 case '\n':	/* fallthrough */
 | |
|                 case '\r':	/* fallthrough */
 | |
|                 case '\t':	/* fallthrough */
 | |
|                 case '\v':	/* fallthrough */
 | |
|                 case '\'':	/* fallthrough */
 | |
|                 case '\"':	/* fallthrough */
 | |
|                 case '\\':	/* fallthrough */
 | |
|                 case '\?':      dlen += 2; break;
 | |
|                 default:        if((src[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<len;i++)
 | |
|         {
 | |
|         switch(src[i])
 | |
|                 {
 | |
|                 case '\a':      *(dst++) = '\\'; *(dst++) = 'a'; break;
 | |
|                 case '\b':      *(dst++) = '\\'; *(dst++) = 'b'; break;
 | |
|                 case '\f':      *(dst++) = '\\'; *(dst++) = 'f'; break;
 | |
|                 case '\n':      *(dst++) = '\\'; *(dst++) = 'n'; break;
 | |
|                 case '\r':      *(dst++) = '\\'; *(dst++) = 'r'; break;
 | |
|                 case '\t':      *(dst++) = '\\'; *(dst++) = 't'; break;
 | |
|                 case '\v':      *(dst++) = '\\'; *(dst++) = 'v'; break;
 | |
|                 case '\'':      *(dst++) = '\\'; *(dst++) = '\''; break;
 | |
|                 case '\"':      *(dst++) = '\\'; *(dst++) = '\"'; break;
 | |
|                 case '\\':      *(dst++) = '\\'; *(dst++) = '\\'; break;
 | |
|                 case '\?':      *(dst++) = '\\'; *(dst++) = '\?'; break;
 | |
|                 default:        if((src[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<len;i++)
 | |
|         {
 | |
|         if(src[i] != '\\')
 | |
|                 {
 | |
|                 *(dst++) = src[i];
 | |
|                 }
 | |
|                 else
 | |
|                 {
 | |
|                 switch(src[++i])
 | |
|                         {
 | |
|                         case 'a':       *(dst++) = '\a'; break;
 | |
|                         case 'b':       *(dst++) = '\b'; break;
 | |
|                         case 'f':       *(dst++) = '\f'; break;
 | |
|                         case 'n':       *(dst++) = '\n'; break;
 | |
|                         case 'r':       *(dst++) = '\r'; break;
 | |
|                         case 't':       *(dst++) = '\t'; break;
 | |
|                         case 'v':       *(dst++) = '\v'; break;
 | |
|                         case '\'':      *(dst++) = '\''; break;
 | |
|                         case '\"':      *(dst++) = '\"'; break;
 | |
|                         case '\\':      *(dst++) = '\\'; break;
 | |
|                         case '\?':      *(dst++) = '\?'; break;
 | |
| 
 | |
|                         case 'x':       val[0] = toupper(src[++i]);
 | |
|                                         val[1] = toupper(src[++i]);
 | |
|                                         val[0] = ((val[0]>='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;i<cnt;i++)
 | |
| 			{
 | |
| 			sp2 = strchr(sp+1, ' ');
 | |
| 			*(char*)sp2 = 0;
 | |
| 			et->literal_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;i<cnt;i++)
 | |
| 			{
 | |
| 			sp2 = strchr(sp+1, ' ');
 | |
| 			if(sp2) { *sp2 = 0; }
 | |
| 			et->val_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);
 | |
| 	}
 | |
| }
 |