1 /*************************************************************************** 2 saverestore.cpp - GDL library procedure 3 ------------------- 4 begin : Dec 10 2017 5 copyright : (C) 2017 by Gilles Duvert 6 7 ***************************************************************************/ 8 9 /*************************************************************************** 10 * * 11 * This program is free software; you can redistribute it and/or modify * 12 * it under the terms of the GNU General Public License as published by * 13 * the Free Software Foundation; either version 2 of the License, or * 14 * (at your option) any later version. * 15 * * 16 ***************************************************************************/ 17 18 #include "includefirst.hpp" 19 #include "datatypes.hpp" 20 #include "envt.hpp" 21 #include "dinterpreter.hpp" 22 #include "nullgdl.hpp" 23 #include <queue> 24 25 //Useful for debugging... 26 #define DEBUG_SAVERESTORE 0 27 28 using namespace std; 29 30 const string rectypes[] = {"START_MARKER", //0 31 "COMMON_VARIABLE", //1 32 "VARIABLE", //2 33 "SYSTEM_VARIABLE", //3 34 "", "", "END_MARKER", //6 35 "", "", "", "TIMESTAMP", //10 36 "", "COMPILED", //12 37 "IDENTIFICATION", //13 38 "VERSION", //14 39 "HEAP_HEADER", //15 40 "HEAP_DATA", //16 41 "PROMOTE64", //17 42 "", "NOTICE", //19 43 "DESCRIPTION", //20 44 "UNKNOWN", "UNKNOWN", "UNKNOWN"}; 45 46 const int sizeOfType[] = {0, 1, 2, 4, 4, 8, 8, 0, 0, 16,0,0,2,4,8,8}; 47 48 namespace lib { 49 50 using namespace std; 51 enum { 52 START_MARKER=0, // Start of SAVE file 53 COMMONBLOCK=1, // Block contains a common block definition 54 VARIABLE=2, // Block contains variable data 55 SYSTEM_VARIABLE=3, // Block contains system variable data 56 END_MARKER=6, // End of SAVE file 57 VARSTART=7, //start of variable data 58 ARRAYSTART=8, 59 STRUCTSTART=9, 60 TIMESTAMP=10, //Block contains time stamp information 61 COMPILED=12, // Block contains compiled procedure or function 62 IDENTIFICATION=13, // Block contains author information 63 VERSION_MARKER=14, // Block contains IDL version information 64 HEAP_HEADER=15, // Block contains heap index information 65 HEAP_DATA=16, // Block contains heap data 66 PROMOTE64=17, // Flags start of 64-bit record file offsets 67 ARRAYSTART64=18, 68 NOTICE=19, // Disclaimer notice 69 DESCRIPTION_MARKER=20 //description ? 70 } Markers; 71 72 typedef std::map<DPtr, SizeT> heapT; 73 static heapT heapIndexMapSave; //list of [ heap pointer, heap index ] used when saving. 74 static std::map<long, std::pair<BaseGDL*,DPtr>> heapIndexMapRestore; //list of [heap index , [variable,heap pointer]] used when reading. 75 static std::vector<std::string> predeflist; 76 static char* saveFileAuthor; 77 static char* saveFileDatestring; 78 static char* saveFileUser; 79 static char* saveFileHost; 80 81 static char* notice; 82 static int32_t format; 83 static char* arch = 0; 84 static char* os = 0; 85 static char* release = 0; 86 87 static bool safetyTested=false; 88 static bool isSafe=false; 89 90 static bool save_compress=false; 91 static FILE* save_fid=NULL; 92 93 #include <rpc/xdr.h> 94 95 // AC 2017-12-13 : missing in <rpc/xdr.h> for OSX 96 // Following https://www.gnu.org/software/gnulib/manual/html_node/xdr_005fint16_005ft.html 97 // it may be needed for others OS : Cygwin, Mingw (seems to be OK for *BSD) 98 99 #ifdef __APPLE__ 100 #define xdr_uint16_t xdr_u_int16_t 101 #define xdr_uint32_t xdr_u_int32_t 102 #define xdr_uint64_t xdr_u_int64_t 103 #endif 104 105 #ifdef __DragonFly__ 106 #define xdr_uint16_t xdr_u_int16_t 107 #endif 108 109 //this is the routined used by IDL as per the documentation. 110 xdr_complex(XDR * xdrs,DComplex * p)111 bool_t xdr_complex(XDR *xdrs, DComplex *p) { 112 return (xdr_float(xdrs, reinterpret_cast<float *> (p)) && xdr_float(xdrs, reinterpret_cast<float *> (p) + 1)); 113 } 114 //this is the routined used by IDL as per the documentation. 115 xdr_dcomplex(XDR * xdrs,DComplexDbl * p)116 bool_t xdr_dcomplex(XDR *xdrs, DComplexDbl *p) { 117 return (xdr_double(xdrs, reinterpret_cast<double *> (p)) && xdr_double(xdrs, reinterpret_cast<double *> (p) + 1)); 118 } 119 getTimeUserHost(XDR * xdrs)120 void getTimeUserHost(XDR *xdrs) { 121 int32_t UnknownLong; 122 for (int i = 0; i < 256; ++i) if (!xdr_int32_t(xdrs, &UnknownLong)) break; 123 { 124 free(saveFileDatestring); 125 saveFileDatestring = 0; 126 if (!xdr_string(xdrs, &saveFileDatestring, 2048)) cerr << "read error" << endl; 127 // else fprintf(stderr, "date: \"%s\"\n", saveFileDatestring); 128 } 129 { 130 free(saveFileUser); 131 saveFileUser = 0; 132 if (!xdr_string(xdrs, &saveFileUser, 2048)) cerr << "read error" << endl; 133 // else fprintf(stderr, "user: \"%s\"\n", saveFileUser); 134 } 135 { 136 free(saveFileHost); 137 saveFileHost = 0; 138 if (!xdr_string(xdrs, &saveFileHost, 2048)) cerr << "read error" << endl; 139 // else fprintf(stderr, "host: \"%s\"\n", saveFileHost); 140 } 141 } 142 writeNewRecordHeader(XDR * xdrs,int code)143 inline uint32_t writeNewRecordHeader(XDR *xdrs, int code){ 144 int32_t rectype=code; 145 xdr_int32_t(xdrs, &rectype); //-16 146 uint32_t ptrs0=0; 147 uint32_t ptrs1=0; 148 xdr_uint32_t(xdrs, &ptrs0); //-12 //void, to be updated 149 xdr_uint32_t(xdrs, &ptrs1); //-8 150 int32_t UnknownLong=0; 151 xdr_int32_t(xdrs, &UnknownLong); 152 return xdr_getpos(xdrs); //end of header 153 } 154 updateNewRecordHeader(XDR * xdrs,uint32_t cur)155 inline uint32_t updateNewRecordHeader(XDR *xdrs, uint32_t cur) { 156 uint32_t next = xdr_getpos(xdrs); 157 //dirty trick for compression: write uncompressed, rewind, read what was just written, compress, write over, reset positions. 158 if (save_compress) 159 { 160 uint32_t uLength = next - cur; 161 uLong cLength = compressBound(uLength); 162 char* uncompressed = (char*) calloc(uLength+1,1); 163 xdr_setpos(xdrs, cur); 164 size_t retval = fread(uncompressed, 1, uLength, save_fid); 165 if (retval!=uLength) cerr<<"(compress) read error:"<<retval<<"eof:"<<feof(save_fid)<<", error:"<<ferror(save_fid)<<endl; 166 char* compressed = (char*) calloc(cLength + 1,1); 167 // Deflate 168 compress2((Bytef *) compressed, &cLength, (Bytef *) uncompressed, uLength, Z_BEST_SPEED); 169 //cLength is the good length now. 170 xdr_setpos(xdrs, cur); 171 xdr_opaque(xdrs,compressed,cLength); 172 next = cur+cLength; 173 xdr_setpos(xdrs, next); 174 //if (next!=(cur+cLength)) cerr<<"problem:"<<cur+cLength<<":"<<next<<"\n"; 175 } 176 xdr_setpos(xdrs, cur-12); //ptrs0 177 xdr_uint32_t(xdrs, &next); 178 xdr_setpos(xdrs, next); 179 return next; 180 } 181 writeTimeUserHost(XDR * xdrs,char * FileDatestring,char * FileUser,char * FileHost)182 uint32_t writeTimeUserHost(XDR *xdrs, char* FileDatestring, char* FileUser, char* FileHost) { 183 uint32_t cur=writeNewRecordHeader(xdrs, TIMESTAMP); 184 int32_t UnknownLong=0; 185 for (int i = 0; i < 256; ++i) if (!xdr_int32_t(xdrs, &UnknownLong)) cerr << "write error" << endl; 186 if (!xdr_string(xdrs, &FileDatestring, strlen(FileDatestring))) cerr << "write error" << endl; 187 if (!xdr_string(xdrs, &FileUser, strlen(FileUser))) cerr << "write error" << endl; 188 if (!xdr_string(xdrs, &FileHost, strlen(FileHost))) cerr << "write error" << endl; 189 uint32_t next=updateNewRecordHeader(xdrs, cur); 190 return next; 191 } 192 writeEnd(XDR * xdrs)193 uint32_t writeEnd(XDR *xdrs) { 194 uint32_t cur=writeNewRecordHeader(xdrs, END_MARKER); 195 return cur; 196 } 197 getVersion(XDR * xdrs)198 int getVersion(XDR* xdrs) { 199 if (!xdr_int32_t(xdrs, &format)) return 0; 200 // cerr << "Format: " << format << endl; 201 free(arch); arch = 0; 202 if (!xdr_string(xdrs, &arch, 2048)) return 0; 203 // cerr << arch << endl; 204 free(os); os = 0; 205 if (!xdr_string(xdrs, &os, 2048)) return 0; 206 // cerr << os << endl; 207 free(release); release = 0; 208 if (!xdr_string(xdrs, &release, 2048)) return 0; 209 // cerr << release << endl; 210 return 1; 211 } 212 writeVersion(XDR * xdrs,int32_t * format,char * arch,char * os,char * release)213 uint32_t writeVersion(XDR* xdrs, int32_t *format, char* arch, char* os , char* release) { 214 uint32_t cur=writeNewRecordHeader(xdrs, VERSION_MARKER); 215 xdr_int32_t(xdrs, format); 216 xdr_string(xdrs, &arch, strlen(arch)); 217 xdr_string(xdrs, &os, strlen(os)); 218 xdr_string(xdrs, &release, strlen(release)); 219 uint32_t next=updateNewRecordHeader(xdrs, cur); 220 return next; 221 } 222 getNotice(XDR * xdrs)223 int getNotice(XDR* xdrs) { 224 free(notice); notice = 0; 225 if (!xdr_string(xdrs, ¬ice, 20480)) return 0; 226 // cerr << notice << endl; 227 return 1; 228 } 229 writeNotice(XDR * xdrs,char * notice)230 uint32_t writeNotice(XDR* xdrs, char* notice) { 231 uint32_t cur=writeNewRecordHeader(xdrs, NOTICE); 232 xdr_string(xdrs, ¬ice, strlen(notice)); 233 uint32_t next=updateNewRecordHeader(xdrs, cur); 234 return next; 235 } 236 getDescription(XDR * xdrs)237 char* getDescription(XDR *xdrs) { 238 int32_t length = 0; 239 if (!xdr_int32_t(xdrs, &length)) cerr << "error reading description string length" << endl; 240 if (length > 0) 241 { 242 char* chars = 0; 243 if (!xdr_string(xdrs, &chars, length)) cerr << "error getting string" << endl; 244 return chars; 245 } else return NULL; 246 } 247 writeDescription(XDR * xdrs,char * descr)248 uint32_t writeDescription(XDR *xdrs, char* descr) { 249 uint32_t cur=writeNewRecordHeader(xdrs, DESCRIPTION_MARKER); 250 int32_t length = strlen(descr); 251 if (!xdr_int32_t(xdrs, &length)) cerr << "error writing description string length" << endl; 252 if (!xdr_string(xdrs, &descr, length)) cerr << "error writing string" << endl; 253 uint32_t next=updateNewRecordHeader(xdrs, cur); 254 return next; 255 } 256 getIdentification(XDR * xdrs)257 int getIdentification(XDR *xdrs) { 258 free(saveFileAuthor); 259 saveFileAuthor = 0; 260 if (!xdr_string(xdrs, &saveFileAuthor, 2048)) return 0; 261 // cerr << author << endl; 262 char* title = 0; 263 if (!xdr_string(xdrs, &title, 2048)) return 0; 264 // cerr << title << endl; 265 char* otherinfo = 0; 266 if (!xdr_string(xdrs, &otherinfo, 2048)) return 0; 267 // cerr << otherinfo << endl; 268 return 1; 269 } 270 writeIdentification(XDR * xdrs,char * saveFileAuthor,char * title,char * otherinfo)271 uint32_t writeIdentification(XDR *xdrs, char *saveFileAuthor, char* title, char* otherinfo ) { 272 uint32_t cur=writeNewRecordHeader(xdrs, IDENTIFICATION); 273 xdr_string(xdrs, &saveFileAuthor, strlen(saveFileAuthor)); 274 xdr_string(xdrs, &title, strlen(title) ); 275 xdr_string(xdrs, &otherinfo, strlen(otherinfo) ); 276 uint32_t next=updateNewRecordHeader(xdrs, cur); 277 return next; 278 } 279 getArrDesc64(XDR * xdrs)280 dimension* getArrDesc64(XDR* xdrs) { 281 if (DEBUG_SAVERESTORE) cerr << "get 64-Bits Array descriptor ," ; 282 int64_t UnknownLong; 283 if (!xdr_int64_t(xdrs, &UnknownLong)) return NULL; 284 int64_t nbytes; 285 if (!xdr_int64_t(xdrs, &nbytes)) return NULL; 286 int64_t nEl; 287 if (!xdr_int64_t(xdrs, &nEl)) return NULL; 288 int32_t nDims; 289 if (!xdr_int32_t(xdrs, &nDims)) return NULL; //on 32 bits 290 if (!xdr_int64_t(xdrs, &UnknownLong)) return NULL; //ignored as we ignore the 2x32 bits integers in the other version. 291 if (DEBUG_SAVERESTORE) cerr << "nbytes:" << nbytes << " ,nEl:" << nEl << ", nDims:" << nDims<<" "; 292 int64_t dims[8]; 293 if (!xdr_vector(xdrs, (char*) dims, 8, sizeof (int64_t), (xdrproc_t) xdr_int64_t)) return NULL; 294 SizeT k = dims[0]; 295 dimension* theDim = new dimension(k); 296 for (int i = 1; i < 8; ++i) 297 { 298 k = dims[i]; 299 *theDim << k; 300 } 301 theDim->Purge(); 302 if (DEBUG_SAVERESTORE) cerr<<*theDim<<endl; 303 return theDim; 304 } 305 getArrDesc(XDR * xdrs)306 dimension* getArrDesc(XDR* xdrs) { 307 if (DEBUG_SAVERESTORE) cerr << "get standard 32-Bits Array descriptor ," ; 308 int32_t arrstart; 309 int32_t UnknownLong; 310 if (!xdr_int32_t(xdrs, &arrstart)) return NULL; 311 if (arrstart != ARRAYSTART && arrstart != ARRAYSTART64) //'10'o and '22'o 312 { 313 cerr << "array is not a array! abort." << endl; 314 return 0; 315 } 316 if (arrstart == ARRAYSTART64) return getArrDesc64(xdrs); //as the rest is specially coded on 8 bytes. 317 318 if (!xdr_int32_t(xdrs, &UnknownLong)) return NULL; 319 int32_t nbytes; 320 if (!xdr_int32_t(xdrs, &nbytes)) return NULL; 321 int32_t nEl; 322 if (!xdr_int32_t(xdrs, &nEl)) return NULL; 323 int32_t nDims; 324 if (!xdr_int32_t(xdrs, &nDims)) return NULL; 325 if (!xdr_int32_t(xdrs, &UnknownLong)) return NULL; 326 if (!xdr_int32_t(xdrs, &UnknownLong)) return NULL; 327 int32_t nmax; 328 if (!xdr_int32_t(xdrs, &nmax)) return NULL; 329 if (DEBUG_SAVERESTORE) cerr << "nbytes:" << nbytes << " ,nEl:" << nEl << ", nDims:" << nDims<<" "; 330 int32_t dims[nmax]; 331 if (!xdr_vector(xdrs, (char*) dims, nmax, sizeof (int32_t), (xdrproc_t) xdr_int32_t)) return NULL; 332 SizeT k = dims[0]; 333 dimension* theDim = new dimension(k); 334 for (int i = 1; i < nmax; ++i) 335 { 336 k = dims[i]; 337 *theDim << k; 338 } 339 theDim->Purge(); 340 if (DEBUG_SAVERESTORE) cerr<<*theDim<<endl; 341 return theDim; 342 } 343 writeArrDesc64(XDR * xdrs,BaseGDL * var)344 void writeArrDesc64(XDR* xdrs, BaseGDL* var) { 345 int32_t arrstart=ARRAYSTART64; 346 xdr_int32_t(xdrs, &arrstart); 347 //very important: 348 int64_t typeLength=sizeOfType[var->Type()]; 349 if (var->Type()==GDL_STRING) typeLength=(var->NBytes()/var->N_Elements())-1; 350 if (typeLength==0) typeLength=(var->NBytes()); 351 xdr_int64_t(xdrs, &typeLength); 352 int64_t nbytes=var->NBytes(); 353 xdr_int64_t(xdrs, &nbytes); 354 int64_t nEl=var->N_Elements(); 355 xdr_int64_t(xdrs, &nEl); 356 int32_t nDims=var->Rank(); 357 if (nDims==0 && var->Type()==GDL_STRUCT ) nDims=1; 358 xdr_int32_t(xdrs, &nDims); 359 int32_t UnknownLong=0; 360 xdr_int32_t(xdrs, &UnknownLong); 361 xdr_int32_t(xdrs, &UnknownLong); 362 int64_t nmax=8; 363 int64_t dims[nmax]; 364 for (int i=0; i < nmax; ++i) dims[i]=1; //yes. 365 // not written xdr_int32_t(xdrs, &nmax); 366 for (int i=0; i < nDims; ++i) if (var->Dim(i) > 0) dims[i]=var->Dim(i); 367 if (DEBUG_SAVERESTORE) std::cerr<<var->Dim()<<std::endl; 368 xdr_vector(xdrs, (char*) dims, nmax, sizeof (int64_t), (xdrproc_t) xdr_int64_t); 369 } 370 writeArrDesc32(XDR * xdrs,BaseGDL * var)371 void writeArrDesc32(XDR* xdrs, BaseGDL* var) { 372 int32_t arrstart=ARRAYSTART; 373 xdr_int32_t(xdrs, &arrstart); 374 //very important: 375 int32_t typeLength=sizeOfType[var->Type()]; 376 if (var->Type()==GDL_STRING) typeLength=(var->NBytes()/var->N_Elements())-1; 377 if (typeLength==0) typeLength=(var->NBytes()); 378 xdr_int32_t(xdrs, &typeLength); 379 int32_t nbytes=var->NBytes(); 380 xdr_int32_t(xdrs, &nbytes); 381 int32_t nEl=var->N_Elements(); 382 xdr_int32_t(xdrs, &nEl); 383 int32_t nDims=var->Rank(); 384 if (nDims==0 && var->Type()==GDL_STRUCT ) nDims=1; 385 xdr_int32_t(xdrs, &nDims); 386 int32_t UnknownLong=0; 387 xdr_int32_t(xdrs, &UnknownLong); 388 xdr_int32_t(xdrs, &UnknownLong); 389 int32_t nmax=8; 390 int32_t dims[nmax]; 391 for (int i=0; i < nmax; ++i) dims[i]=1; //yes. 392 xdr_int32_t(xdrs, &nmax); 393 for (int i=0; i < nDims; ++i) if (var->Dim(i) > 0) dims[i]=var->Dim(i); 394 if (DEBUG_SAVERESTORE) std::cerr<<var->Dim()<<std::endl; 395 xdr_vector(xdrs, (char*) dims, nmax, sizeof (int32_t), (xdrproc_t) xdr_int32_t); 396 } 397 writeArrDesc(XDR * xdrs,BaseGDL * var)398 void writeArrDesc(XDR* xdrs, BaseGDL* var) { 399 //very important check total size and switch if size is >2GO. 400 //Warning do not use a SizeT as typelength as this does not like negative values returned by for 0 length strings 401 DLong64 typeLength=sizeOfType[var->Type()]; 402 if (var->Type()==GDL_STRING) typeLength=(var->NBytes()/var->N_Elements()); 403 SizeT nEl=var->N_Elements(); 404 if (nEl*typeLength > 2000000000ULL) writeArrDesc64(xdrs,var); else writeArrDesc32(xdrs,var); 405 } 406 defineCommonBlock(EnvT * e,XDR * xdrs,int verboselevel)407 int defineCommonBlock(EnvT* e, XDR* xdrs, int verboselevel) { 408 int32_t ncommonvars; 409 if (!xdr_int32_t(xdrs, &ncommonvars)) return 0; 410 char* commonname = 0; 411 if (!xdr_string(xdrs, &commonname, 2048)) return 0; 412 char* varnames[ncommonvars]; 413 for (int i = 0; i < ncommonvars; ++i) varnames[i] = 0; 414 for (int i = 0; i < ncommonvars; ++i) if (!xdr_string(xdrs, &varnames[i], 2048)) return 0; 415 416 if (verboselevel>1){ 417 cerr << "Common " << commonname << " consists of the following variables:" << endl; 418 for (int i = 0; i < ncommonvars; ++i) cerr << varnames[i] << ","; 419 cerr << endl; 420 } 421 //populate common block 422 423 //behaviour is: if one of these variables already exist, the whole common is not defined, and 424 //the common variables become just normal variables: 425 426 EnvStackT& callStack = e->Interpreter()->CallStack(); 427 int32_t curlevnum = callStack.size(); 428 DSubUD* pro = static_cast<DSubUD*> (callStack[curlevnum - 1]->GetPro()); 429 430 for (int i = 0; i < ncommonvars; ++i) 431 { 432 std::string varName = varnames[i]; 433 if (pro->FindVar(varName) >= 0) 434 { 435 Message(varName + " is already defined with a conflicting definition."); 436 return 1; //this should not produce an error. 437 } 438 } 439 440 std::string commonName = commonname; 441 442 if (pro->Common(commonName) == NULL) 443 { //does not exist: create 444 DCommon* newCommon = new DCommon(commonName); 445 pro->AddCommon(newCommon); 446 if (verboselevel>0) Message("Restored common block: " + commonName); 447 } 448 commonName.clear(); 449 DCommonBase* currentcommon = pro->Common(std::string(commonname)); 450 for (int i = 0; i < ncommonvars; ++i) 451 { 452 std::string varName = varnames[i]; 453 currentcommon->AddVar(varName); 454 varName.clear(); 455 } 456 457 return 1; 458 } 459 getDStruct(EnvT * e,XDR * xdrs,dimension * inputdims,bool & isObjStruct)460 DStructGDL* getDStruct(EnvT* e, XDR* xdrs, dimension* inputdims, bool &isObjStruct) { 461 isObjStruct=false; 462 int32_t structstart; 463 if (!xdr_int32_t(xdrs, &structstart)) return NULL; 464 if (structstart != STRUCTSTART) 465 { 466 cerr << "structure is not a structure! abort." << endl; 467 return NULL; 468 } 469 char* structname = 0; 470 if (!xdr_string(xdrs, &structname, 2048)) return NULL; 471 int32_t structure_def_flags; 472 if (!xdr_int32_t(xdrs, &structure_def_flags)) return NULL; 473 bool ispredef = false; //ispredef means that this struct has been already defined inside the save file, 474 // but its definition may clash with an existing definition already made in GDL previous to the RESTORE command. 475 if (structure_def_flags & 0x01) 476 { 477 ispredef = true; 478 } 479 bool unknown_flag = false; 480 bool is_super = false; 481 bool inherits = false; 482 if (structure_def_flags & 0x08) 483 { 484 unknown_flag = true; 485 } 486 if (structure_def_flags & 0x02) 487 { 488 inherits = true; 489 } 490 if (structure_def_flags & 0x04) 491 { 492 is_super = true; 493 } 494 495 if (is_super || inherits) isObjStruct=true; 496 if (DEBUG_SAVERESTORE) { 497 if (isObjStruct) { 498 cerr<<std::hex<<structure_def_flags<<std::dec<<std::endl; 499 cerr << "Object name:\"" << structname << "\""; 500 if (inherits) cerr << ", inherits"; 501 if (is_super) cerr << ", is a Superclass"; 502 } else { 503 cerr << "Structure name:\"" << structname << "\""; 504 } 505 if (unknown_flag) cerr << ", is tagged by unknown flag 0x08"; 506 if (ispredef) cerr << ", is already defined"; 507 cerr<<endl; 508 } 509 510 int32_t ntags; 511 if (!xdr_int32_t(xdrs, &ntags)) return NULL; 512 int32_t struct_nbytes; 513 if (!xdr_int32_t(xdrs, &struct_nbytes)) return NULL; 514 //if predef == 1 this ends the Struct_desc, meaning that the definition of such a 515 //structure has already been presented and we should reuse it. 516 // otherwise, we define the structure using the following entries: 517 if (ispredef) { 518 std::string name = std::string(structname); 519 //beautify 520 assert(name != "$truct") ; // named struct 521 name = StrUpCase(name); 522 if( name == "IDL_OBJECT") name = GDL_OBJECT_NAME; // replacement also done in GDLParser 523 if( name == "IDL_CONTAINER") name = GDL_CONTAINER_NAME; // replacement also done in GDLParser 524 DStructDesc* desc = e->Interpreter()->GetStruct(name, e->CallingNode()); //will throw if does not exist. 525 return new DStructGDL(desc, *inputdims); 526 527 } else { 528 529 //definition of a new structure or class. Structure, if named, may be different from already existing (prior to RESTORE): clash! 530 //this is why the "RELAXED" option of RESTORE exists. 531 // Besides, if we create an Object, (a named structure) it is necessary to check wether it can be defined using XXXX__define.pro 532 // and if this definition is in accordance with the structure defined here, i.e., in the save file. 533 //TAG_DESC repated ntags times: 534 int32_t tag_typecode[ntags]; 535 char* tag_name[ntags]; 536 int32_t tag_flag[ntags]; 537 int32_t tag_offset[ntags]; 538 for (int i = 0; i < ntags; ++i) tag_name[i] = 0; 539 for (int i = 0; i < ntags; ++i) 540 { 541 //TAG_DESC: 542 if (!xdr_int32_t(xdrs, &tag_offset[i])) break; 543 if (!xdr_int32_t(xdrs, &tag_typecode[i])) break; 544 if (!xdr_int32_t(xdrs, &tag_flag[i])) break; 545 } 546 for (int i = 0; i < ntags; ++i) 547 { 548 //TAGNAMES x NTAGS: 549 if (!xdr_string(xdrs, &tag_name[i], 2048)) break; 550 } 551 552 int32_t narrays = 0; 553 int32_t nstructs = 0; 554 for (int i = 0; i < ntags; ++i) if (tag_flag[i] & 0x20) nstructs++; 555 for (int i = 0; i < ntags; ++i) if (tag_flag[i] & 0x04) narrays++; 556 dimension * tagdimensions[narrays + 1]; //Always >0: FIXME IF MEMORY LEAK! 557 //if there are any tag flags indicating the tag is an array, read the ARRDESC 558 for (int i = 0; i < narrays; ++i) 559 { 560 tagdimensions[i] = getArrDesc(xdrs); 561 if (tagdimensions[i] == NULL) return NULL; 562 } 563 564 std::string stru_name = std::string(structname); 565 if( stru_name == "IDL_OBJECT") stru_name = GDL_OBJECT_NAME; // replacement also done in GDLParser 566 if( stru_name == "IDL_CONTAINER") stru_name = GDL_CONTAINER_NAME; // replacement also done in GDLParser 567 DStructDesc* stru_desc=NULL; 568 DStructDesc* ref_desc=NULL; 569 bool checkStruct=false; 570 //take care of named structures. Here is also where one should try to create an object, since, if it exists, its structure must be 571 //compared with the current one. 572 if (stru_name.length() > 0 && stru_name[0] != '$') 573 { 574 if (isObjStruct) { //create a dummy object of this name, remove it. 575 DString objName=StrUpCase(stru_name); 576 DStructDesc* objDesc; 577 try { 578 objDesc = e->Interpreter()->GetStruct(objName, e->CallingNode()); 579 DStructGDL* objStruct = new DStructGDL(objDesc, dimension(1)); 580 DObj objID = e->NewObjHeap(1, objStruct); // owns objStruct 581 DObjGDL* newObj = new DObjGDL(objID); // the object 582 //calling the INIT function seems to intrusive. 583 // try { 584 // // call INIT function 585 // DFun* objINIT = objDesc->GetFun("INIT"); 586 // if (objINIT != NULL) { 587 // StackGuard<EnvStackT> guard(e->Interpreter()->CallStack()); 588 // 589 // // morph to obj environment and push it onto the stack again 590 // e->PushNewEnvUD(objINIT, 1, &newObj); 591 // 592 // BaseGDL* res = e->Interpreter()->call_fun(objINIT->GetTree()); 593 // GDLDelete(res); 594 // } 595 // } catch (...) { 596 // } 597 e->FreeObjHeap(objID); // delete objStruct 598 GDLDelete(newObj); 599 } catch (...) { 600 if (DEBUG_SAVERESTORE) std::cerr << stru_name<<": is NOT a known Object."<<endl; 601 } 602 } 603 stru_desc = FindInStructList(structList, stru_name); 604 605 if (stru_desc == NULL) 606 { 607 stru_desc = new DStructDesc(stru_name); 608 structList.push_back(stru_desc); 609 } else { 610 if (DEBUG_SAVERESTORE) cerr<<stru_name<<": is a known Object."<<endl; 611 checkStruct=true; 612 ref_desc=stru_desc; 613 stru_desc=new DStructDesc("$truct"); //make it anonymous, test if equality at end! 614 } 615 } else stru_desc=new DStructDesc("$truct"); 616 //summary & tag population: 617 for (int i = 0, j = 0, k = 0; i < ntags; ++i) 618 { 619 //reserved a dimension 620 dimension pardim = dimension(); 621 622 if (tag_flag[i] & 0x04) 623 { 624 // modify pardim and push index; 625 pardim = *(tagdimensions[j++]); //memory leak? 626 } 627 628 switch (tag_typecode[i]) { 629 case GDL_BYTE: // Byte 630 { 631 SpDByte entry(pardim); 632 stru_desc->AddTag(tag_name[i], &entry); 633 } 634 break; 635 636 case GDL_INT: // 16-bit Integer 637 { 638 SpDInt entry(pardim); 639 stru_desc->AddTag(tag_name[i], &entry); 640 } 641 break; 642 643 case GDL_LONG: // 32-bit Long Integer 644 { 645 SpDLong entry(pardim); 646 stru_desc->AddTag(tag_name[i], &entry); 647 } 648 break; 649 650 case GDL_FLOAT: // 32-bit Floating Point Number 651 { 652 SpDFloat entry(pardim); 653 stru_desc->AddTag(tag_name[i], &entry); 654 } 655 break; 656 657 case GDL_DOUBLE: // 64-bit Floating Point Number 658 { 659 SpDDouble entry(pardim); 660 stru_desc->AddTag(tag_name[i], &entry); 661 } 662 break; 663 664 case GDL_COMPLEX: // Complex Floating Point Number (32-bits each) 665 { 666 SpDComplex entry(pardim); 667 stru_desc->AddTag(tag_name[i], &entry); 668 } 669 break; 670 case GDL_STRING: // String 671 { 672 SpDString entry(pardim); 673 stru_desc->AddTag(tag_name[i], &entry); 674 } 675 break; 676 case GDL_STRUCT: // Structure (never a scalar) 677 { 678 bool dummy; 679 DStructGDL* parStruct = getDStruct(e, xdrs, &pardim, dummy); 680 if (parStruct == NULL) return NULL; 681 stru_desc->AddTag(tag_name[i], parStruct); 682 } 683 break; 684 685 case GDL_COMPLEXDBL: // Complex Floating Point Number (64-bits each) 686 { 687 SpDComplexDbl entry(pardim); 688 stru_desc->AddTag(tag_name[i], &entry); 689 } 690 break; 691 692 case GDL_PTR: // Heap Pointer 693 { 694 DPtrGDL entry(pardim); 695 stru_desc->AddTag(tag_name[i], &entry); 696 } 697 break; 698 case GDL_OBJ: // Object Reference (not supported by CMSVLIB) 699 { 700 DObjGDL entry(pardim); 701 stru_desc->AddTag(tag_name[i], &entry); 702 } 703 break; 704 case GDL_UINT: // 16-bit Unsigned Integer 705 { 706 SpDUInt entry(pardim); 707 stru_desc->AddTag(tag_name[i], &entry); 708 } 709 break; 710 711 case GDL_ULONG: // 32-bit Unsigned Integer 712 { 713 SpDULong entry(pardim); 714 stru_desc->AddTag(tag_name[i], &entry); 715 } 716 break; 717 718 case GDL_LONG64: // 64-bit Integer 719 { 720 SpDLong64 entry(pardim); 721 stru_desc->AddTag(tag_name[i], &entry); 722 } 723 break; 724 725 case GDL_ULONG64: // 64-bit Unsigned Integer 726 { 727 SpDULong64 entry(pardim); 728 stru_desc->AddTag(tag_name[i], &entry); 729 } 730 break; 731 732 default: // 0 ? Undefined (not allowed) 733 if (DEBUG_SAVERESTORE) cerr << "Should not happen: undefined typecode tag in getDStruct()." << endl; 734 break; 735 } 736 737 738 739 } 740 741 //Then there should be CLASSNAME if INHERITS or IS_SUPER 742 if (isObjStruct || is_super) 743 { 744 char* classname = 0; 745 if (!xdr_string(xdrs, &classname, 2048)) return NULL; 746 if (DEBUG_SAVERESTORE) cerr << "CLASSNAME: \"" << classname << "\"" << endl; 747 //NSUPCLASSES: 748 int32_t nsupclasses = 0; 749 if (!xdr_int32_t(xdrs, &nsupclasses)) return NULL; 750 if (DEBUG_SAVERESTORE) cerr << "NSUPCLASSES=" << nsupclasses << endl; 751 if (nsupclasses > 0) 752 { 753 for (int i = 0; i < nsupclasses; ++i) 754 { 755 char* supclassname = 0; 756 if (!xdr_string(xdrs, &supclassname, 2048)) return NULL; 757 if (DEBUG_SAVERESTORE) cerr << "SUPCLASSNAME " << i << ": " << supclassname << endl; 758 } 759 for (int i = 0; i < nsupclasses; ++i) 760 { 761 //define all parent classes in objheap. 762 DStructGDL* superclass = NULL; 763 bool dummy=false; 764 superclass = getDStruct(e, xdrs, new dimension(1), dummy); // will define the class as an object. 765 if (superclass) stru_desc->AddParentListOnly(superclass->Desc()); 766 // if (isObjStruct) { 767 // DPtr ptr= e->NewObjHeap(1, static_cast<DStructGDL*>(superclass)); 768 // } 769 } 770 } 771 } 772 if (checkStruct) 773 { 774 try 775 { 776 ref_desc->AssureIdentical(stru_desc); 777 stru_desc=ref_desc; //OK, switch back. 778 } catch (GDLException& ex) 779 { 780 e->Throw("Structure not restored due to conflict with existing definition: "+stru_name); 781 return NULL; 782 } 783 } 784 return new DStructGDL(stru_desc, *inputdims); 785 } 786 } 787 writeStructDesc(XDR * xdrs,DStructGDL * var,bool isObject=false,bool is_super=false)788 void writeStructDesc(XDR* xdrs, DStructGDL* var, bool isObject=false, bool is_super=false) { 789 DStructDesc* str=var->Desc(); 790 int32_t structstart=STRUCTSTART; 791 xdr_int32_t(xdrs, &structstart); 792 const char* structname = str->Name().c_str(); 793 if (DEBUG_SAVERESTORE && isObject) cerr << "Writing Object \""<< str->Name() <<"\" @"<< var << endl; 794 if (DEBUG_SAVERESTORE && !isObject) cerr << "Writing Structure \""<< str->Name() <<"\" @"<< var << endl; 795 //predef: struct name is known 796 bool ispredef = (str->Name() != "$truct"); // named struct 797 //void name if anonymous struct! 798 if (!ispredef) { 799 std::string nullstr=""; char* voidchar=(char*)nullstr.c_str(); 800 xdr_string(xdrs,(char**)&voidchar, 0); 801 } 802 else xdr_string(xdrs, (char**) &structname, str->Name().size()); 803 //now, did we already define this named structure in the file? 804 //if no, add name to list of defined (for further use) and remove is_predef (to write it). 805 if (ispredef) { 806 bool found=false; 807 for (SizeT i=0; i<predeflist.size(); ++i) 808 { 809 if (predeflist[i]==str->Name()) {found=true; break;} 810 } 811 if (!found) { 812 predeflist.push_back(str->Name()); 813 ispredef=false; 814 } 815 } 816 //flags. 817 818 int32_t structure_def_flags=0; 819 if (ispredef) structure_def_flags |= 0x01; 820 if (isObject) structure_def_flags |= 0x08; //it is a CLASS 821 if (isObject) structure_def_flags |= 0x02; 822 if (is_super) structure_def_flags |= 0x04; 823 xdr_int32_t(xdrs, &structure_def_flags); 824 int32_t ntags=str->NTags(); 825 xdr_int32_t(xdrs, &ntags); 826 int32_t struct_nbytes=(ispredef)?str->NBytes():0; 827 xdr_int32_t(xdrs, &struct_nbytes); 828 //if predef == 1 this ends the Struct_desc, meaning that we have already presented this structure. 829 if (ispredef) return; 830 //TAG_DESC repated ntags times: 831 int32_t tag_typecode[ntags]; 832 char* tag_name[ntags]; 833 int32_t tag_flag[ntags]; 834 int32_t tag_offset[ntags]; 835 int32_t byteoff=0; 836 for (int i = 0; i < ntags; ++i) tag_name[i] = (char*) str->TagName(i).c_str(); 837 for (SizeT i = 0; i < ntags; ++i) { tag_offset[i] = byteoff; byteoff+=var->GetTag(i)->NBytes();} //probably OK 838 for (int i = 0; i < ntags; ++i) 839 { 840 tag_flag[i]=0; 841 if (var->GetTag(i,0)->Rank()> 0) tag_flag[i]|=0x04; 842 switch (var->GetTag(i,0)->Type()) { 843 case GDL_STRUCT: 844 tag_flag[i] |=0x20; 845 default: 846 tag_typecode[i] = var->GetTag(i,0)->Type(); 847 } 848 } 849 for (int i = 0; i < ntags; ++i) 850 { 851 //TAG_DESC: 852 xdr_int32_t(xdrs, &tag_offset[i]); 853 xdr_int32_t(xdrs, &tag_typecode[i]); 854 xdr_int32_t(xdrs, &tag_flag[i]); 855 } 856 for (int i = 0; i < ntags; ++i) 857 { 858 //TAGNAMES x NTAGS: 859 xdr_string(xdrs, &tag_name[i], strlen(tag_name[i])); 860 } 861 //ARRDESC x NARRAYS: 862 for (int i = 0; i < ntags; ++i) 863 { 864 if (tag_flag[i] & 0x04) writeArrDesc(xdrs, var->GetTag(i)); 865 } 866 //STRUCTDESC x NARRAYS: 867 for (int i = 0; i < ntags; ++i) 868 { 869 if (tag_flag[i] & 0x20) writeStructDesc(xdrs, static_cast<DStructGDL*>(var->GetTag(i))); 870 } 871 //TBD: CLASSES 872 if (isObject) { 873 xdr_string(xdrs, (char**) &structname, str->Name().size()); //CLASSNAME 874 if (DEBUG_SAVERESTORE) std::cerr << "Object CLASS is \""<< str->Name() << std::endl; 875 std::vector< std::string> pNames; 876 str->GetParentNames(pNames); 877 //TBD: get super classes and write structs accordingly. 878 int32_t nsupclasses=pNames.size(); //do they exist??? 879 for (int i=0 ; i< nsupclasses;++i) { 880 DStructGDL* parent = new DStructGDL( pNames[i]); 881 if (parent == NULL) nsupclasses--; 882 GDLDelete(parent); 883 } 884 xdr_int32_t(xdrs, &nsupclasses); 885 if (nsupclasses > 0) { 886 DStructGDL* parents[nsupclasses]; 887 // AC not OK on OSX12: std::string pnames[nsupclasses]; 888 string *pnames = new string[nsupclasses]; 889 int k=0; 890 for (int i=0 ; i< pNames.size();++i) { 891 DStructGDL* parent = new DStructGDL( pNames[i]); 892 if (parent != NULL) { 893 pnames[k]=pNames[i]; 894 parents[k]=parent; 895 if (DEBUG_SAVERESTORE) std::cerr << " SUPCLASS: \""<< pNames[k] << std::endl; 896 k++; 897 } 898 } 899 for (int i=0 ; i< nsupclasses;++i) {char* str=(char*)(pnames[i].c_str()); xdr_string(xdrs, &str,pnames[i].size());} 900 for (int i=0 ; i< nsupclasses;++i) { 901 DStructGDL* parent = parents[i]; 902 Guard<DStructGDL> parent_guard(parent); 903 writeStructDesc(xdrs, parent, true, true); 904 } 905 delete [] pnames; 906 } 907 } 908 } 909 910 getVariable(EnvT * e,XDR * xdrs,int & isSysVar,bool & isObjStruct)911 BaseGDL* getVariable(EnvT* e, XDR* xdrs, int &isSysVar, bool &isObjStruct) { 912 bool isStructure = false; 913 bool isArray = false; 914 // start of TYPEDESC 915 // common for VARIABLE, SYSTEM_VARIABLE and HEAP_DATA: 916 // 1) TYPECODE 917 int32_t typecode; 918 if (!xdr_int32_t(xdrs, &typecode)) return NULL; 919 // 2) VARFLAGS 920 int32_t varflags; 921 if (!xdr_int32_t(xdrs, &varflags)) return NULL; 922 923 if (varflags & 0x40) return NullGDL::GetSingleInstance(); //special !NULL variable, no variable content follows. 924 925 if (varflags & 0x02) //defines a system variable. 926 { 927 isSysVar |= 0x02; 928 // cerr << " system " << endl; 929 } 930 if (varflags & 0x01) 931 { 932 isSysVar |= 0x01; 933 // cerr << " readonly " << endl; 934 } 935 936 937 if (varflags & 0x20) 938 { 939 isStructure = true; //may also be an array! 940 } 941 else if (varflags & 0x04) 942 { 943 isArray = true; 944 } 945 //This is not signaled in C. Marqwardt doc: a system variable has two supplemental int32 (0x04 and 0x02) here, that we skip. 946 if (isSysVar & 0x02) 947 { 948 int32_t dummy; 949 if (!xdr_int32_t(xdrs, &dummy)) return NULL; 950 if (!xdr_int32_t(xdrs, &dummy)) return NULL; 951 } 952 //we gonnna create a BaseGDL: 953 954 BaseGDL* var; 955 dimension* dims; 956 // if ARRAY or STRUCTURE, Read ARRAY_DESC that follows: 957 if (isStructure) 958 {//if This was a Structure, it has an ARRAY_DESC plus a STRUCT_DESC 959 dims = getArrDesc(xdrs); 960 if (dims == NULL) return NULL; 961 var = getDStruct(e, xdrs, dims, isObjStruct); 962 } else 963 { 964 if (isArray) 965 { //and NOT a structure... 966 dims = getArrDesc(xdrs); 967 if (dims == NULL) return NULL; 968 } else 969 { //normal plain variable 970 dims = new dimension(); 971 } 972 switch (typecode) { 973 case GDL_BYTE: // Byte 974 var = new DByteGDL(*dims); 975 break; 976 case GDL_INT: // 16-bit Integer 977 var = new DIntGDL(*dims); 978 break; 979 case GDL_LONG: // 32-bit Long Integer 980 var = new DLongGDL(*dims); 981 break; 982 case GDL_FLOAT: // 32-bit Floating Point Number 983 var = new DFloatGDL(*dims); 984 break; 985 case GDL_DOUBLE: // 64-bit Floating Point Number 986 var = new DDoubleGDL(*dims); 987 break; 988 case GDL_COMPLEX: // Complex Floating Point Number (32-bits each) 989 var = new DComplexGDL(*dims); 990 break; 991 case GDL_STRING: // String 992 var = new DStringGDL(*dims); 993 break; 994 case GDL_STRUCT: // Structure (never a scalar) 995 cerr << "Should not happen: struct" << endl; 996 break; 997 case GDL_COMPLEXDBL: // Complex Floating Point Number (64-bits each) 998 var = new DComplexDblGDL(*dims); 999 break; 1000 case GDL_PTR: // Heap Pointer 1001 var = new DPtrGDL(*dims); 1002 break; 1003 case GDL_OBJ: // Object Reference (not supported by CMSVLIB) 1004 var = new DObjGDL(*dims); 1005 break; 1006 case GDL_UINT: // 16-bit Unsigned Integer 1007 var = new DUIntGDL(*dims); 1008 break; 1009 case GDL_ULONG: // 32-bit Unsigned Integer 1010 var = new DULongGDL(*dims); 1011 break; 1012 case GDL_LONG64: // 64-bit Integer 1013 var = new DLong64GDL(*dims); 1014 break; 1015 case GDL_ULONG64: // 64-bit Unsigned Integer 1016 var = new DULong64GDL(*dims); 1017 break; 1018 default: // 0 ? Undefined (not allowed) 1019 var = NullGDL::GetSingleInstance(); // cerr <<"Should not happen"<<endl; 1020 break; 1021 } 1022 } 1023 1024 return var; 1025 } 1026 fillVariableData(XDR * xdrs,BaseGDL * var)1027 void fillVariableData(XDR* xdrs, BaseGDL* var) { 1028 u_int nEl = var->N_Elements(); 1029 switch (var->Type()) { 1030 1031 case GDL_BYTE: 1032 { 1033 char* addr = (char*) var->DataAddr(); 1034 if (!xdr_bytes(xdrs, &addr, &nEl, nEl)) cerr << "error GDL_BYTE" << endl; 1035 } 1036 break; 1037 case GDL_INT: 1038 { 1039 if (!xdr_vector(xdrs, (char*) var->DataAddr(), nEl, sizeof (DInt), (xdrproc_t) xdr_int16_t)) cerr << "error GDL_INT" << endl; 1040 } 1041 break; 1042 case GDL_UINT: 1043 { 1044 if (!xdr_vector(xdrs, (char*) var->DataAddr(), nEl, sizeof (DUInt), (xdrproc_t) xdr_uint16_t)) cerr << "error GDL_UINT" << endl; 1045 } 1046 break; 1047 case GDL_LONG: 1048 { 1049 if (!xdr_vector(xdrs, (char*) var->DataAddr(), nEl, sizeof (int32_t), (xdrproc_t) xdr_int32_t)) cerr << "error GDL_LONG" << endl; 1050 } 1051 break; 1052 case GDL_ULONG: 1053 { 1054 if (!xdr_vector(xdrs, (char*) var->DataAddr(), nEl, sizeof (DULong), (xdrproc_t) xdr_uint32_t)) cerr << "error GDL_ULONG" << endl; 1055 } 1056 break; 1057 case GDL_LONG64: 1058 { 1059 if (!xdr_vector(xdrs, (char*) var->DataAddr(), nEl, sizeof (DLong64), (xdrproc_t) xdr_int64_t)) cerr << "error GDL_LONG64" << endl; 1060 } 1061 break; 1062 case GDL_ULONG64: 1063 { 1064 if (!xdr_vector(xdrs, (char*) var->DataAddr(), nEl, sizeof (DULong64), (xdrproc_t) xdr_uint64_t)) cerr << "error GDL_ULONG64" << endl; 1065 } 1066 break; 1067 case GDL_FLOAT: 1068 { 1069 if (!xdr_vector(xdrs, (char*) var->DataAddr(), nEl, sizeof (DFloat), (xdrproc_t) xdr_float)) cerr << "error GDL_FLOAT" << endl; 1070 } 1071 break; 1072 case GDL_DOUBLE: 1073 { 1074 if (!xdr_vector(xdrs, (char*) var->DataAddr(), nEl, sizeof (DDouble), (xdrproc_t) xdr_double)) cerr << "error GDL_DOUBLE" << endl; 1075 } 1076 break; 1077 case GDL_COMPLEX: 1078 { 1079 u_int nEl2 = nEl * 2; 1080 if (!xdr_vector(xdrs, (char*) var->DataAddr(), nEl2, sizeof (DFloat), (xdrproc_t) xdr_float)) cerr << "error GDL_COMPLEX" << endl; 1081 } 1082 break; 1083 case GDL_COMPLEXDBL: 1084 { 1085 u_int nEl2 = nEl * 2; 1086 if (!xdr_vector(xdrs, (char*) var->DataAddr(), nEl2, sizeof (DDouble), (xdrproc_t) xdr_double)) cerr << "error GDL_COMPLEXDBL" << endl; 1087 } 1088 break; 1089 case GDL_STRING: 1090 { 1091 for (SizeT i = 0; i < nEl; ++i) 1092 { 1093 int32_t length; 1094 if (!xdr_int32_t(xdrs, &length)) cerr << "error reading string length" << endl; 1095 if (length > 0) 1096 { 1097 char* chars = 0; 1098 if (!xdr_string(xdrs, &chars, length)) cerr << "error getting string" << endl; 1099 (*static_cast<DStringGDL*> (var))[i].assign(chars); 1100 } 1101 } 1102 } 1103 break; 1104 case GDL_STRUCT: 1105 { 1106 DStructGDL* str = static_cast<DStructGDL*> (var); 1107 SizeT nTags = str->Desc()->NTags(); 1108 for (SizeT ix = 0; ix < nEl; ++ix) for (SizeT t = 0; t < nTags; ++t) fillVariableData(xdrs, str->GetTag(t, ix)); 1109 break; 1110 } 1111 case GDL_PTR: 1112 { 1113 int32_t heapNumber[nEl]; 1114 DPtrGDL* ptr = static_cast<DPtrGDL*> (var); 1115 for (SizeT ix = 0; ix < nEl; ++ix) xdr_int32_t(xdrs, &(heapNumber[ix])); 1116 for (SizeT ix = 0; ix < nEl; ++ix) 1117 { 1118 DPtr heapptr = heapIndexMapRestore.find(heapNumber[ix])->second.second; 1119 (*ptr)[ix] = heapptr; 1120 GDLInterpreter::IncRef(heapptr); 1121 if (DEBUG_SAVERESTORE) std::cerr<<"PTR at #"<<heapNumber[ix]<<" restored at "<<heapptr<<std::endl; 1122 } 1123 break; 1124 } 1125 case GDL_OBJ: 1126 { 1127 int32_t heapNumber[nEl]; 1128 DObjGDL* ptr = static_cast<DObjGDL*> (var); 1129 for (SizeT ix = 0; ix < nEl; ++ix) xdr_int32_t(xdrs, &(heapNumber[ix])); 1130 for (SizeT ix = 0; ix < nEl; ++ix) 1131 { 1132 DObj heapptr = heapIndexMapRestore.find(heapNumber[ix])->second.second; 1133 (*ptr)[ix] = heapptr; 1134 GDLInterpreter::IncRefObj(heapptr); 1135 if (DEBUG_SAVERESTORE) std::cerr<<"OBJ at #"<<heapNumber[ix]<<" restored at "<<heapptr<<std::endl; 1136 } 1137 break; 1138 } 1139 default: assert(false); 1140 } 1141 } 1142 writeVariableData(XDR * xdrs,BaseGDL * var)1143 void writeVariableData(XDR* xdrs, BaseGDL* var) { 1144 u_int nEl = var->N_Elements(); 1145 switch (var->Type()) { 1146 1147 case GDL_BYTE: 1148 { 1149 char* addr = (char*) var->DataAddr(); 1150 if (!xdr_bytes(xdrs, &addr, &nEl, nEl)) cerr << "error GDL_BYTE" << endl; 1151 } 1152 break; 1153 case GDL_INT: 1154 { 1155 if (!xdr_vector(xdrs, (char*) var->DataAddr(), nEl, sizeof (DInt), (xdrproc_t) xdr_int16_t)) cerr << "error GDL_INT" << endl; 1156 } 1157 break; 1158 case GDL_UINT: 1159 { 1160 if (!xdr_vector(xdrs, (char*) var->DataAddr(), nEl, sizeof (DUInt), (xdrproc_t) xdr_uint16_t)) cerr << "error GDL_UINT" << endl; 1161 } 1162 break; 1163 case GDL_LONG: 1164 { 1165 if (!xdr_vector(xdrs, (char*) var->DataAddr(), nEl, sizeof (int32_t), (xdrproc_t) xdr_int32_t)) cerr << "error GDL_LONG" << endl; 1166 } 1167 break; 1168 case GDL_ULONG: 1169 { 1170 if (!xdr_vector(xdrs, (char*) var->DataAddr(), nEl, sizeof (DULong), (xdrproc_t) xdr_uint32_t)) cerr << "error GDL_ULONG" << endl; 1171 } 1172 break; 1173 case GDL_LONG64: 1174 { 1175 if (!xdr_vector(xdrs, (char*) var->DataAddr(), nEl, sizeof (DLong64), (xdrproc_t) xdr_int64_t)) cerr << "error GDL_LONG64" << endl; 1176 } 1177 break; 1178 case GDL_ULONG64: 1179 { 1180 if (!xdr_vector(xdrs, (char*) var->DataAddr(), nEl, sizeof (DULong64), (xdrproc_t) xdr_uint64_t)) cerr << "error GDL_ULONG64" << endl; 1181 } 1182 break; 1183 case GDL_FLOAT: 1184 { 1185 if (!xdr_vector(xdrs, (char*) var->DataAddr(), nEl, sizeof (DFloat), (xdrproc_t) xdr_float)) cerr << "error GDL_FLOAT" << endl; 1186 } 1187 break; 1188 case GDL_DOUBLE: 1189 { 1190 if (!xdr_vector(xdrs, (char*) var->DataAddr(), nEl, sizeof (DDouble), (xdrproc_t) xdr_double)) cerr << "error GDL_DOUBLE" << endl; 1191 } 1192 break; 1193 case GDL_COMPLEX: 1194 { 1195 u_int nEl2 = nEl * 2; 1196 if (!xdr_vector(xdrs, (char*) var->DataAddr(), nEl2, sizeof (DFloat), (xdrproc_t) xdr_float)) cerr << "error GDL_COMPLEX" << endl; 1197 } 1198 break; 1199 case GDL_COMPLEXDBL: 1200 { 1201 u_int nEl2 = nEl * 2; 1202 if (!xdr_vector(xdrs, (char*) var->DataAddr(), nEl2, sizeof (DDouble), (xdrproc_t) xdr_double)) cerr << "error GDL_COMPLEXDBL" << endl; 1203 } 1204 break; 1205 case GDL_STRING: 1206 { 1207 for (SizeT i = 0; i < nEl; ++i) 1208 { 1209 const char *chars=(*static_cast<DStringGDL*> (var))[i].c_str(); 1210 int32_t length=(*static_cast<DStringGDL*> (var))[i].length(); 1211 if (!xdr_int32_t(xdrs, &length)) cerr << "error writing string length" << endl; 1212 if (length > 0) if (!xdr_string(xdrs, (char**)&chars, length)) cerr << "error writing string" << endl; 1213 } 1214 } 1215 break; 1216 case GDL_STRUCT: 1217 { 1218 DStructGDL* str = static_cast<DStructGDL*> (var); 1219 SizeT nTags = str->Desc()->NTags(); 1220 for (SizeT ix = 0; ix < nEl; ++ix) for (SizeT t = 0; t < nTags; ++t) writeVariableData(xdrs, str->GetTag(t, ix)); 1221 break; 1222 } 1223 case GDL_PTR: //we must translate PTRs as they may have been scrambled in the writing of the heap indexes. 1224 { 1225 uint32_t heapNumber[nEl]; 1226 for (SizeT i = 0; i < nEl; ++i) 1227 { 1228 heapNumber[i]=0; 1229 DPtr ptr = (*static_cast<DPtrGDL*>(var))[i]; 1230 heapT::iterator it=heapIndexMapSave.find(ptr); 1231 if (it!=heapIndexMapSave.end()) heapNumber[i]=(*it).second; 1232 } 1233 if (!xdr_vector(xdrs, (char*) &heapNumber, nEl, sizeof (int32_t), (xdrproc_t) xdr_uint32_t)) cerr << "error PTR" << endl; 1234 break; 1235 } 1236 case GDL_OBJ: 1237 { 1238 uint32_t heapNumber[nEl]; 1239 for (SizeT i = 0; i < nEl; ++i) 1240 { 1241 heapNumber[i]=0; 1242 DObj ptr = (*static_cast<DObjGDL*>(var))[i]; 1243 heapT::iterator it=heapIndexMapSave.find(ptr); 1244 if (it!=heapIndexMapSave.end()) heapNumber[i]=(*it).second; 1245 } 1246 if (!xdr_vector(xdrs, (char*) &heapNumber, nEl, sizeof (int32_t), (xdrproc_t) xdr_uint32_t)) cerr << "error OBJ" << endl; 1247 break; 1248 } 1249 default: assert(false); 1250 } 1251 } 1252 writeVariableHeader(XDR * xdrs,BaseGDL * var,bool isSysVar=false,bool readonly=false,bool isObject=false)1253 void writeVariableHeader(XDR* xdrs, BaseGDL* var, bool isSysVar=false, bool readonly=false, bool isObject=false) { 1254 if (DEBUG_SAVERESTORE) std::cerr<<"Writing normal Variable Header, isObject="<<isObject<<std::endl; 1255 int32_t varflags=0; 1256 bool isStructure = (var->Type()==GDL_STRUCT); 1257 bool isArray = (var->Rank() > 0); 1258 // start of TYPEDESC 1259 // common for VARIABLE, SYSTEM_VARIABLE and HEAP_DATA: 1260 // 1) TYPECODE 1261 int32_t typecode=0; 1262 // special case for !NULL 1263 bool nullsize=false; 1264 if ( var->N_Elements() == 0 ) nullsize=true; 1265 typecode=var->Type(); //these are the same. 1266 xdr_int32_t(xdrs, &typecode); 1267 // 2) VARFLAGS 1268 if (isSysVar) varflags |= 0x02; 1269 if (readonly) varflags |= 0x01; 1270 if (isObject) varflags |= 0x34; if (isStructure) varflags |= 0x24; else if (isArray) varflags |= 0x04; 1271 if (nullsize) varflags=0x40; 1272 xdr_int32_t(xdrs, &varflags); 1273 if (nullsize) return; 1274 //This is not signaled in C. Marqwardt doc: a system variable has two supplemental int32 (0x04 and 0x02). 1275 if (isSysVar) 1276 { 1277 int32_t dummy; 1278 xdr_int32_t(xdrs, &dummy); 1279 xdr_int32_t(xdrs, &dummy); 1280 } 1281 1282 // if ARRAY or STRUCTURE, write ARRAY_DESC that follows: 1283 if (isStructure||isArray) writeArrDesc(xdrs, var); 1284 if (isStructure) writeStructDesc(xdrs, static_cast<DStructGDL*>(var), isObject); 1285 } 1286 writeNormalVariable(XDR * xdrs,std::string varName,BaseGDL * var,int varflags=0x0)1287 uint32_t writeNormalVariable(XDR *xdrs, std::string varName, BaseGDL* var, int varflags=0x0) { 1288 bool isSysVar=false; 1289 bool readonly=false; 1290 if (varflags & 0x02) //defines a system variable. 1291 { 1292 isSysVar = true; 1293 } 1294 if (varflags & 0x01) 1295 { 1296 readonly = true; 1297 } 1298 const char* varname=varName.c_str(); 1299 uint32_t cur=writeNewRecordHeader(xdrs, isSysVar?SYSTEM_VARIABLE:VARIABLE); 1300 xdr_string(xdrs, (char**)&varname, 2048); 1301 if (var==NULL) return updateNewRecordHeader(xdrs, cur); //unexistent var 1302 if (DEBUG_SAVERESTORE) std::cerr<<"Writing normal Variable "<<varName<<std::endl; 1303 writeVariableHeader(xdrs, var, isSysVar, readonly); 1304 // !NULL variable stops here since no data 1305 if (var->N_Elements() == 0) return updateNewRecordHeader(xdrs, cur); 1306 // varstat=7 to read data 1307 int32_t varstart = VARSTART; 1308 xdr_int32_t(xdrs, &varstart); 1309 writeVariableData(xdrs, var); 1310 return updateNewRecordHeader(xdrs, cur); 1311 } 1312 writeHeapVariable(EnvT * e,XDR * xdrs,DPtr ptr,bool isObject=false)1313 uint32_t writeHeapVariable(EnvT* e, XDR *xdrs, DPtr ptr, bool isObject=false) { 1314 //what is passed is the list of existent heap positions occupied. 1315 //we write only the ones that are actuall in , depending, the 1316 heapT::iterator itheap; 1317 bool unknown=false; 1318 itheap=heapIndexMapSave.find(ptr); 1319 if ( itheap==heapIndexMapSave.end() ) unknown=true; 1320 if (unknown) { 1321 if (DEBUG_SAVERESTORE) std::cerr<<"ignoring unused heap_index "<<ptr<<std::endl; 1322 return xdr_getpos(xdrs); //do nothing. 1323 } 1324 1325 bool isSysVar=false; 1326 bool readonly=false; 1327 uint32_t cur=writeNewRecordHeader(xdrs, HEAP_DATA); //HEAP_DATA 1328 int32_t heap_index=ptr; 1329 if (DEBUG_SAVERESTORE) { 1330 if (isObject) { 1331 std::cerr << "write OBJ at heap_index " << heap_index << std::endl; 1332 } else { 1333 std::cerr << "write PTR at heap_index " << heap_index << std::endl; 1334 } 1335 } 1336 //rest is normally the same as for any other variable 1337 xdr_int32_t(xdrs, &heap_index); 1338 int32_t heap_type = 0x02; 1339 if (isObject) heap_type = 0x04; 1340 xdr_int32_t(xdrs, &heap_type); 1341 1342 // start of TYPEDESC. Structures may be objects, in which case ptr.second is negative. 1343 BaseGDL* var; 1344 try{ 1345 if (isObject) var=e->GetObjHeap(ptr); else var=e->GetHeap(ptr); //TRICK! 1346 } catch( GDLInterpreter::HeapException& hEx) 1347 { 1348 e->Throw("ID <"+i2s(ptr)+"> not found."); 1349 } 1350 if (var==NULL) return updateNewRecordHeader(xdrs, cur); //unexistent var 1351 if (DEBUG_SAVERESTORE) std::cerr<<var->TypeStr()<<" @ "<<std::hex<<var<<std::dec<<std::endl; 1352 writeVariableHeader(xdrs, var, isSysVar, readonly, isObject ); 1353 // !NULL variable stops here since no data 1354 if (var->N_Elements() == 0) return updateNewRecordHeader(xdrs, cur); 1355 // varstat=7 to read data 1356 int32_t varstart = VARSTART; 1357 xdr_int32_t(xdrs, &varstart); 1358 writeVariableData(xdrs, var); 1359 return updateNewRecordHeader(xdrs, cur); 1360 } restoreNormalVariable(EnvT * e,std::string varName,BaseGDL * ret)1361 void restoreNormalVariable(EnvT* e, std::string varName, BaseGDL* ret) { 1362 //write variable back 1363 EnvStackT& callStack = e->Interpreter()->CallStack(); 1364 DLong curlevnum = callStack.size(); 1365 DSubUD* pro = static_cast<DSubUD*> (callStack[curlevnum - 1]->GetPro()); 1366 int nKey = pro->NKey(); 1367 // cout << "nKey:" << nKey << endl; 1368 // cout << "nVar:" << nVar << endl; 1369 // cout << pro->Name() << endl; 1370 int xI = pro->FindVar(varName); 1371 // cout << "varName: " << varName << " xI: " << xI << endl; 1372 SizeT s; 1373 if (xI != -1) 1374 { 1375 s = xI; 1376 // cout << "Found Already existing Var \""<< varName <<" s=" << s << endl; 1377 //the existing var is deleted (including heap if it pointed to heap values), and restored anew. 1378 GDLDelete( ((EnvT*) (callStack[curlevnum - 1]))->GetPar(s - nKey)); 1379 ((EnvT*) (callStack[curlevnum - 1]))->GetPar(s - nKey) = ret; 1380 1381 } else 1382 { 1383 BaseGDL** varPtr = pro->GetCommonVarPtr(varName); 1384 if (varPtr) 1385 { 1386 pro->ReplaceExistingCommonVar(varName, ret); 1387 } else 1388 { 1389 SizeT u = pro->AddVar(varName); 1390 s = callStack[curlevnum - 1]->AddEnv(); 1391 // cout << "AddVar u: " << u << endl; 1392 // cout << "AddEnv s: " << s << endl; 1393 ((EnvT*) (callStack[curlevnum - 1]))->GetPar(s - nKey) = ret; 1394 } 1395 } 1396 } 1397 restoreSystemVariable(EnvT * e,std::string sysVarNameFull,BaseGDL * ret,bool rdOnly=false)1398 void restoreSystemVariable(EnvT* e, std::string sysVarNameFull, BaseGDL* ret, bool rdOnly = false) { 1399 //more or less a copy of "DEFSYSV" code... 1400 if (sysVarNameFull.length() < 2 || sysVarNameFull[0] != '!') 1401 { 1402 Warning("Not restoring illegal system variable name: " + sysVarNameFull + "."); 1403 GDLDelete(ret); 1404 return; 1405 } 1406 // strip "!", uppercase 1407 DString sysVarName = StrUpCase(sysVarNameFull.substr(1)); 1408 1409 DVar* sysVar = FindInVarList(sysVarList, sysVarName); 1410 1411 if (sysVar == NULL) 1412 { 1413 // define new 1414 DVar *newSysVar = new DVar(sysVarName, ret); 1415 sysVarList.push_back(newSysVar); 1416 1417 // rdOnly is only set at the first definition 1418 if (rdOnly) sysVarRdOnlyList.push_back(newSysVar); 1419 return; 1420 } 1421 1422 // else: re-set 1423 // make sure type and size are kept 1424 BaseGDL* oldVar = sysVar->Data(); 1425 if (oldVar->Type() != ret->Type() || oldVar->N_Elements() != ret->N_Elements()) 1426 { 1427 Message("Conflicting definition for " + sysVarNameFull + "."); 1428 GDLDelete(ret); 1429 return; 1430 } 1431 1432 // if struct -> assure equal descriptors 1433 if (oldVar->Type() == GDL_STRUCT) 1434 { 1435 DStructGDL *oldStruct = static_cast<DStructGDL*> (oldVar); 1436 // types are same -> static cast 1437 DStructGDL *newStruct = static_cast<DStructGDL*> (ret); 1438 1439 // note that IDL handles different structs more relaxed 1440 // ie. just the structure pattern is compared. 1441 if (*oldStruct->Desc() != *newStruct->Desc()) 1442 { 1443 Warning("Conflicting definition for " + sysVarNameFull + "."); 1444 GDLDelete(ret); 1445 return; 1446 } 1447 1448 DVar* sysVarRdOnly = FindInVarList(sysVarRdOnlyList, sysVarName); 1449 if (sysVarRdOnly != NULL) 1450 { 1451 // rdOnly set and is already rdOnly: do nothing 1452 if (rdOnly) return; 1453 1454 // else complain 1455 Warning("Attempt to write to a readonly variable: " + sysVarNameFull + "."); 1456 } else 1457 { 1458 // not read only 1459 GDLDelete(oldVar); 1460 sysVar->Data() = ret; 1461 } 1462 } 1463 } 1464 1465 //clever but very VERY VERY dirty trick not gentle with memory and full of leaks: 1466 uncompress_trick(FILE * fid,XDR * xdrsmem,char * & expanded,DULong64 nextptr,DULong64 currentptr)1467 XDR* uncompress_trick(FILE* fid, XDR* xdrsmem, char* &expanded, DULong64 nextptr, DULong64 currentptr) { 1468 if (expanded!=NULL) free(expanded); 1469 uLong compsz = nextptr - currentptr; 1470 char* expandable = (char*) malloc(compsz); 1471 size_t retval = fread(expandable, 1, compsz, fid); 1472 int iloop = 1; 1473 uLong uncompsz; 1474 //of course one should never do like that. One should do as in gzstream.hpp... 1475 while (1) 1476 { 1477 uncompsz = 10 * iloop*compsz; //a default starting value... 1478 expanded = (char*) malloc(uncompsz); 1479 int retval = uncompress((Bytef *) expanded, &uncompsz, (Bytef *) expandable, compsz); 1480 if (retval == Z_OK) break; //ok length was sufficient 1481 free(expanded); 1482 if (retval != Z_BUF_ERROR) throw GDLException("fatal error when uncompressing data."); 1483 iloop++; 1484 } 1485 free(expandable); 1486 xdrmem_create(xdrsmem, NULL, 0, XDR_FREE); 1487 xdrmem_create(xdrsmem, expanded, uncompsz, XDR_DECODE); 1488 return xdrsmem; 1489 } 1490 testSafety()1491 bool testSafety() { 1492 if (sizeof(int8_t) != sizeof(DByte)) return false; 1493 if (sizeof(int16_t) != sizeof(DInt)) return false; 1494 if (sizeof(int32_t) != sizeof(DLong)) return false; 1495 if (sizeof(int64_t) != sizeof(DLong64)) return false; 1496 if (sizeof(uint16_t) != sizeof(DUInt)) return false; 1497 if (sizeof(uint32_t) != sizeof(DULong)) return false; 1498 if (sizeof(uint64_t) != sizeof(DULong64)) return false; 1499 if (sizeof(double) != sizeof(DDouble)) return false; 1500 if (sizeof(float) != sizeof(DFloat)) return false; 1501 return true; 1502 } 1503 1504 // new fast restore. 1505 gdl_restore(EnvT * e)1506 void gdl_restore(EnvT* e) { 1507 1508 // xdr() is used through all the following. I program here xdr to use the 8, 16, 32 and 64 bits length 1509 // types of GDL/IDL (BYTE,INT,LONG,LONG64). However, a risk exist in some architectures that the real length 1510 // of DInt, DLong etc is not really the expected one (16 and 32 respectively). So the following is a test on these 1511 // lengths. If the test fails, 1) GDL is false for this architecture and that needs to be reported and 1512 // 2) gdl_restore cannot work. 1513 1514 if (safetyTested == false) 1515 { 1516 isSafe = testSafety(); 1517 if (!isSafe) e->Throw("Severe: internal representation of integers in this version of GDL is wrong, please report. Aborting unsafe use of RESTORE."); 1518 safetyTested = true; 1519 } 1520 //if testSafety is correct, DLong and int32_t , DInt and int16_t etc have the same meaning. 1521 1522 static int FILENAME = e->KeywordIx("FILENAME"); 1523 1524 static int VERBOSE = e->KeywordIx("VERBOSE"); 1525 bool verbose = e->KeywordSet(VERBOSE); 1526 DLong verboselevel=(verbose?1:0); 1527 if (verbose) e->AssureLongScalarKW(VERBOSE,verboselevel); 1528 1529 static int DESCRIPTION = e->KeywordIx("DESCRIPTION"); 1530 bool hasDescription = e->KeywordPresent(DESCRIPTION); 1531 // AC 20200323 : we may have this keyword set but no value in the file : should return "" 1532 if (hasDescription) e->SetKW(DESCRIPTION, new DStringGDL("")); 1533 1534 //empty heap map by security. 1535 heapIndexMapRestore.clear(); 1536 1537 std::vector<Guard<BaseGDL>* > guardVector; 1538 // std::vector<BaseGDL*> myObj; 1539 std::vector<std::pair<std::string, BaseGDL*> > variableVector; 1540 std::vector<std::pair<std::string, BaseGDL*> > systemVariableVector; 1541 std::vector<std::pair<std::string, BaseGDL*> > systemReadonlyVariableVector; //for readonly variables 1542 1543 DString name; 1544 // IDL allows here also arrays of length 1 1545 SizeT nparam = e->NParam(); 1546 if (nparam > 0) 1547 { 1548 e->AssureScalarPar<DStringGDL>(0, name); 1549 } else if (e->KeywordPresent(FILENAME)) 1550 { 1551 e->AssureScalarKW<DStringGDL>(FILENAME, name); 1552 } else name = "idlsave.dat"; 1553 1554 WordExp(name); 1555 1556 bool isCompress = false; 1557 1558 FILE *fid; 1559 fid = fopen(name.c_str(), "rb"); 1560 if (fid == NULL) e->Throw("Error opening file. Unit: XXXX, File: " + name + "."); 1561 1562 XDR* xdrsmem = new XDR; 1563 XDR* xdrs; 1564 XDR* xdrsfile = new XDR; 1565 xdrstdio_create(xdrsfile, fid, XDR_DECODE); 1566 xdrs = xdrsfile; 1567 char* expanded = NULL; 1568 1569 SizeT returned; 1570 char signature[4]; 1571 returned = fread(signature, 4, 1, fid); 1572 if (signature[0] != 'S' || signature[1] != 'R') 1573 { 1574 fclose(fid); 1575 delete xdrsmem; 1576 delete xdrsfile; 1577 e->Throw("Not a valid save file: " + name + "."); 1578 } 1579 if (signature[3]==0x06) isCompress = true; //cerr<<"probably compressed"<<endl; 1580 #define LONG sizeof(int32_t) //sizeof(DInt) 1581 #define ULONG LONG 1582 1583 1584 bool isHdr64 = false; 1585 int isSysVar = 0x00; 1586 bool isArray = false; 1587 bool isStructure = false; 1588 //will start at TMESTAMP 1589 uint64_t currentptr = 0; 1590 uint64_t nextptr = LONG; 1591 uint32_t ptrs0, ptrs1; 1592 int32_t rectype; 1593 int32_t UnknownLong; 1594 bool SomethingFussyHappened = true; 1595 1596 //pass twice. First to define heap variables only (and ancillary data). 1597 1598 while (1) 1599 { 1600 xdrs = xdrsfile; //back to file if we were smarting the xdr to read a char* due to compression. 1601 if (fseek(fid, nextptr, SEEK_SET)) break; 1602 if (!xdr_int32_t(xdrs, &rectype)) break; 1603 1604 if (DEBUG_SAVERESTORE) cerr << "Offset " << nextptr << ": record type " << rectypes[rectype] << endl; 1605 1606 if (rectype == 6) 1607 { 1608 SomethingFussyHappened = false; 1609 break; 1610 } 1611 if (isHdr64) 1612 { 1613 uint64_t my_ulong64; 1614 if (!xdr_uint64_t(xdrs, &my_ulong64)) break; 1615 nextptr = my_ulong64; 1616 if (!xdr_int32_t(xdrs, &UnknownLong)) break; 1617 if (!xdr_int32_t(xdrs, &UnknownLong)) break; 1618 } else 1619 { 1620 if (!xdr_uint32_t(xdrs, &ptrs0)) break; 1621 if (!xdr_uint32_t(xdrs, &ptrs1)) break; 1622 if (!xdr_int32_t(xdrs, &UnknownLong)) break; 1623 nextptr = ptrs0; 1624 if (ptrs1 > 0) 1625 { 1626 DULong64 tmp = ptrs1; 1627 nextptr &= (tmp << 32); 1628 } 1629 } 1630 1631 //dispatch accordingly: 1632 1633 isSysVar = 0x00; 1634 isArray = false; 1635 isStructure = false; 1636 currentptr = ftell(fid); 1637 1638 switch ((int) rectype) { 1639 case TIMESTAMP: 1640 if (nextptr < 1024) 1641 { 1642 // cerr << "version offset < 1024... probably a compressed file" << endl; 1643 // Message("sorry, can''t deal with this yet. if possible, save without the \"COMPRESS\" flag."); 1644 isCompress = true; 1645 } 1646 if (isCompress) xdrs = uncompress_trick(fid, xdrsmem, expanded, nextptr, currentptr); 1647 getTimeUserHost(xdrs); 1648 if (verbose) 1649 { 1650 if (isCompress) Message("Portable (XDR) compressed SAVE/RESTORE file."); 1651 else Message("Portable (XDR) SAVE/RESTORE file."); 1652 Message("Save file written by " + std::string(saveFileUser) + "@" + std::string(saveFileHost) + ", " + std::string(saveFileDatestring)); 1653 } 1654 break; 1655 case VERSION_MARKER: 1656 if (isCompress) xdrs = uncompress_trick(fid, xdrsmem, expanded, nextptr, currentptr); 1657 if (!getVersion(xdrs)) 1658 { 1659 cerr << "error in VERSION" << endl; 1660 break; 1661 } 1662 break; 1663 case PROMOTE64: 1664 isHdr64 = true; 1665 break; 1666 case IDENTIFICATION: 1667 if (verbose) 1668 { 1669 if (isCompress) xdrs = uncompress_trick(fid, xdrsmem, expanded, nextptr, currentptr); 1670 if (!getIdentification(xdrs)) 1671 { 1672 cerr << "error in AUTHOR" << endl; 1673 break; 1674 } 1675 } 1676 break; 1677 case NOTICE: 1678 if (isCompress) xdrs = uncompress_trick(fid, xdrsmem, expanded, nextptr, currentptr); 1679 if (!getNotice(xdrs)) 1680 { 1681 cerr << "error in NOTICE" << endl; 1682 break; 1683 } 1684 break; 1685 case DESCRIPTION_MARKER: 1686 if (verbose || hasDescription) 1687 { 1688 if (isCompress) xdrs = uncompress_trick(fid, xdrsmem, expanded, nextptr, currentptr); 1689 std::string descr(getDescription(xdrs)); 1690 if (verbose) Message("Description: " + descr); 1691 // AC 20200323 no "else" possible here, see above 1692 if (hasDescription) e->SetKW(DESCRIPTION, new DStringGDL(descr)); 1693 } 1694 break; 1695 case COMMONBLOCK: 1696 if (isCompress) xdrs = uncompress_trick(fid, xdrsmem, expanded, nextptr, currentptr); 1697 if (!defineCommonBlock(e, xdrs, verboselevel)) 1698 { 1699 cerr << "error in COMMONBLOCK" << endl; 1700 break; 1701 } 1702 break; 1703 case HEAP_HEADER: // IS IN PREAMBLE since version 5. BEFORE ANY REFERENCE TO HEAP. 1704 if (isCompress) xdrs = uncompress_trick(fid, xdrsmem, expanded, nextptr, currentptr); 1705 { 1706 int32_t elementcount; 1707 if (!xdr_int32_t(xdrs, &elementcount)) break; 1708 int32_t indices[elementcount]; 1709 if (!xdr_vector(xdrs, (char*) indices, elementcount, sizeof (int32_t), (xdrproc_t) xdr_int32_t)) break; 1710 if (DEBUG_SAVERESTORE) 1711 { 1712 cerr << "Heap indexes, " << elementcount << " elements: "; 1713 for (int i = 0; i < elementcount; ++i) cerr << indices[i] << ","; 1714 cerr << endl; 1715 } 1716 1717 break; 1718 } 1719 case HEAP_DATA: //define all HEAP_DATA variable but do not fill them yet 1720 if (isCompress) xdrs = uncompress_trick(fid, xdrsmem, expanded, nextptr, currentptr); 1721 { 1722 int32_t heap_index = 0; 1723 if (!xdr_int32_t(xdrs, &heap_index)) break; 1724 int32_t heap_unknown = 0; 1725 if (!xdr_int32_t(xdrs, &heap_unknown)) break; // start of TYPEDESC 1726 bool isObjStruct=false; 1727 BaseGDL* ret = getVariable(e, xdrs, isSysVar, isObjStruct); 1728 if (ret == NULL) 1729 { 1730 fclose(fid); 1731 delete xdrsmem; 1732 delete xdrsfile; 1733 e->Throw("error reading heap variable definition."); 1734 } 1735 1736 //allocate corresponding heap entries and store gdl variable and heap entry in heapIndexMapRestore: 1737 //if ret is a struct defining an object, use ObjHeap. 1738 DPtr ptr; 1739 if (isObjStruct) ptr = e->NewObjHeap(1, static_cast<DStructGDL*> (ret)); else ptr = e->NewHeap(1, ret); 1740 heapIndexMapRestore.insert(std::pair<long, std::pair<BaseGDL*,DPtr>>(heap_index, std::make_pair(ret,ptr))); 1741 1742 if (ret == NullGDL::GetSingleInstance()) break; //no data follows 1743 1744 // should be at varstat=VARSTAT to read data 1745 int32_t varstart = 0; 1746 if (!xdr_int32_t(xdrs, &varstart)) break; 1747 if (varstart != VARSTART) 1748 { 1749 fclose(fid); 1750 delete xdrsmem; 1751 delete xdrsfile; 1752 e->Throw("Lost track in HEAP_DATA definition at offset " + i2s(nextptr)); 1753 1754 } 1755 } 1756 break; 1757 default: 1758 break; 1759 } 1760 } 1761 1762 if (SomethingFussyHappened) 1763 { 1764 fclose(fid); 1765 delete xdrsmem; 1766 delete xdrsfile; 1767 e->Throw("Error Reading File: " + name + "."); 1768 } 1769 1770 //from then, saveFileHeapMap.second contains heap DPtr. 1771 1772 //Then on second pass, define normal variables that may be pointers to heap. 1773 rewind(fid); 1774 if (DEBUG_SAVERESTORE) cerr << "Second Pass"<<endl; 1775 currentptr = 0; 1776 nextptr = LONG; 1777 SomethingFussyHappened = true; 1778 1779 while (1) 1780 { 1781 1782 xdrs = xdrsfile; //back to file if we were smarting the xdr to read a char* due to compression. 1783 if (fseek(fid, nextptr, SEEK_SET)) break; 1784 if (!xdr_int32_t(xdrs, &rectype)) break; 1785 1786 if (DEBUG_SAVERESTORE) cerr << "Offset " << nextptr << ": record type " << rectypes[rectype] << endl; 1787 1788 if (rectype == 6) 1789 { 1790 SomethingFussyHappened = false; 1791 break; 1792 } 1793 if (isHdr64) 1794 { 1795 uint64_t my_ulong64; 1796 if (!xdr_uint64_t(xdrs, &my_ulong64)) break; 1797 nextptr = my_ulong64; 1798 if (!xdr_int32_t(xdrs, &UnknownLong)) break; 1799 if (!xdr_int32_t(xdrs, &UnknownLong)) break; 1800 } else 1801 { 1802 if (!xdr_uint32_t(xdrs, &ptrs0)) break; 1803 if (!xdr_uint32_t(xdrs, &ptrs1)) break; 1804 if (!xdr_int32_t(xdrs, &UnknownLong)) break; 1805 nextptr = ptrs0; 1806 if (ptrs1 > 0) 1807 { 1808 DULong64 tmp = ptrs1; 1809 nextptr &= (tmp << 32); 1810 } 1811 } 1812 1813 //dispatch accordingly: 1814 1815 isSysVar = 0x00; 1816 isArray = false; 1817 isStructure = false; 1818 currentptr = ftell(fid); 1819 1820 switch ((int) rectype) { 1821 case SYSTEM_VARIABLE: 1822 if (DEBUG_SAVERESTORE) cerr<<"SYSTEM "; 1823 isSysVar = 0x02; //see? no break. defines a read-write system variable (default) 1824 case VARIABLE: 1825 if (DEBUG_SAVERESTORE) cerr<<"Variable "; 1826 if (isCompress) xdrs = uncompress_trick(fid, xdrsmem, expanded, nextptr, currentptr); 1827 { 1828 char* varname = 0; 1829 if (!xdr_string(xdrs, &varname, 2048)) break; 1830 string varName(varname); 1831 if (DEBUG_SAVERESTORE) cerr<<varname<<endl; 1832 bool isObjStruct=false; 1833 BaseGDL* ret = getVariable(e, xdrs, isSysVar, isObjStruct); 1834 if (ret == NULL) 1835 { 1836 Message("Unable to restore " + varName +"."); 1837 break; 1838 } 1839 if (isObjStruct) std::cerr<<"Problem: found an Object in normal variable processing -- should not happen.\n"; 1840 // should be at varstat=VARSTAT to read data 1841 int32_t varstart = 0; 1842 if (!xdr_int32_t(xdrs, &varstart)) break; 1843 if (varstart != VARSTART) 1844 { 1845 fclose(fid); 1846 delete xdrsmem; 1847 delete xdrsfile; 1848 e->Throw("Lost track in VARIABLE definition at offset " + i2s(nextptr)); 1849 } 1850 1851 fillVariableData(xdrs, ret); 1852 1853 if (isSysVar & 0x01) systemReadonlyVariableVector.push_back(make_pair(varName, ret)); 1854 else if (isSysVar & 0x02) systemVariableVector.push_back(make_pair(varName, ret)); 1855 else variableVector.push_back(make_pair(varName, ret)); 1856 Guard<BaseGDL>* guard = new Guard<BaseGDL>; 1857 guard->Reset(ret); 1858 guardVector.push_back(guard); 1859 } 1860 break; 1861 case HEAP_DATA: //use previous variable, now that the list of heap pointers is complete. 1862 if (isCompress) xdrs = uncompress_trick(fid, xdrsmem, expanded, nextptr, currentptr); 1863 { 1864 int32_t heap_index = 0; 1865 if (!xdr_int32_t(xdrs, &heap_index)) break; 1866 int32_t heap_unknown = 0; 1867 if (!xdr_int32_t(xdrs, &heap_unknown)) break; // start of TYPEDESC 1868 bool isObjStruct=false; 1869 BaseGDL* dummy = getVariable(e, xdrs, isSysVar, isObjStruct); //obliged to read all that infortunately. 1870 // we are at varstat=VARSTAT since this has already been seen above 1871 int32_t varstart = 0; 1872 if (!xdr_int32_t(xdrs, &varstart)) break; 1873 GDLDelete(dummy); //get rid of variable that may have wrong pointers and restore the good one: 1874 if (DEBUG_SAVERESTORE) cerr<<"Restoring Heap Data initially at #"<<heap_index<<"..."; 1875 if (heapIndexMapRestore.find(heap_index) == heapIndexMapRestore.end()) { 1876 e->Throw("Lost track in HEAP VARIABLE definition at offset " + i2s(nextptr)); 1877 } else { 1878 BaseGDL* ret = heapIndexMapRestore.find(heap_index)->second.first; 1879 if (ret == NullGDL::GetSingleInstance()) break; //no data follows as this is a !NULL 1880 fillVariableData(xdrs, ret); 1881 if (DEBUG_SAVERESTORE) std::cerr<<"at offset #"<<heapIndexMapRestore.find(heap_index)->second.second<<std::endl; 1882 } 1883 1884 1885 } 1886 break; 1887 default: 1888 break; 1889 } 1890 } 1891 1892 if (expanded!=NULL) free(expanded); 1893 fclose(fid); 1894 delete xdrsmem; 1895 delete xdrsfile; 1896 1897 //if problem, guards should deleted the allocated BaseGDLs. 1898 if (SomethingFussyHappened) e->Throw("Error Reading File: " + name + "."); 1899 //here everything was ok 1900 1901 1902 1903 while (!systemVariableVector.empty()) 1904 { 1905 restoreSystemVariable(e, systemVariableVector.back().first, (systemVariableVector.back()).second); 1906 if (verbose) Message("Restored system variable: " + (systemVariableVector.back()).first); 1907 systemVariableVector.pop_back(); 1908 } 1909 while (!systemReadonlyVariableVector.empty()) 1910 { 1911 restoreSystemVariable(e, systemReadonlyVariableVector.back().first, (systemReadonlyVariableVector.back()).second, true); 1912 if (verbose) Message("Restored system variable: " + (systemReadonlyVariableVector.back()).first); 1913 systemReadonlyVariableVector.pop_back(); 1914 } 1915 while (!variableVector.empty()) 1916 { 1917 restoreNormalVariable(e, variableVector.back().first, (variableVector.back()).second); 1918 if (verbose) Message("Restored variable: " + (variableVector.back()).first+"."); 1919 variableVector.pop_back(); 1920 } 1921 1922 //heap variables have one more reference that necessary (1 at creation of the heap variable + 1 each time somthing points to it). 1923 //decrease each of them by 1: 1924 std::map<long, std::pair<BaseGDL*,DPtr>>::iterator imap; 1925 for (imap=heapIndexMapRestore.begin(); imap!=heapIndexMapRestore.end(); ++imap) { 1926 DPtr ptr=(*imap).second.second; 1927 GDLInterpreter::DecRef(ptr); 1928 GDLInterpreter::DecRefObj(ptr); //if not PTR then try Obj --- will always decrement the good one now that ptr is unique between Obj and Ptr. 1929 } 1930 //everything ok, remove guards and exit 1931 while (!guardVector.empty()) 1932 { 1933 guardVector.back()->Release(); 1934 guardVector.pop_back(); 1935 } 1936 1937 } 1938 // This adds in heaplist map:: all the OBJ or normal HEAP adresses of variables that are part of any named variable that are to be SAVEd. 1939 // GDL has 2 heaplists, one for OBJ and the other for normal pointers, but I've insured that the index in these maps is common, so 1940 // it is just as if there was only one heap list, as in IDL. addToHeapList(EnvT * e,BaseGDL * var)1941 void addToHeapList(EnvT* e, BaseGDL* var) 1942 { 1943 if (var->Type() == GDL_PTR) { 1944 for (SizeT ielem = 0; ielem < var->N_Elements(); ++ielem) { 1945 DPtr subptr = (*static_cast<DPtrGDL*> (var))[ielem]; 1946 if (subptr > 0) { 1947 heapT::iterator itheap=heapIndexMapSave.find(subptr); 1948 if ( itheap==heapIndexMapSave.end() ) { 1949 try { 1950 BaseGDL* v = e->GetHeap(subptr); //this pointed-to heap value MAY NOT EXIST. It may have been destroyed. 1951 heapIndexMapSave.insert(std::pair<DPtr, SizeT>(subptr, subptr)); 1952 if (DEBUG_SAVERESTORE) std::cerr<<"Adding Heaplist PTR: HeapIndex="<<subptr<<", id="<<std::hex<<v<<std::dec<<std::endl; 1953 if (v && v!=NullGDL::GetSingleInstance()) addToHeapList(e, v); 1954 } catch( GDLInterpreter::HeapException& hEx) 1955 { 1956 if (DEBUG_SAVERESTORE) std::cerr<<"PTR ID<"<<subptr<<"> not found."<<std::endl; 1957 } 1958 } 1959 } 1960 } 1961 } else if (var->Type() == GDL_OBJ) { 1962 for (SizeT ielem = 0; ielem < var->N_Elements(); ++ielem) { 1963 DObj subptr = (*static_cast<DObjGDL*> (var))[ielem]; 1964 if (subptr > 0) { 1965 heapT::iterator itheap=heapIndexMapSave.find(subptr); 1966 if ( itheap==heapIndexMapSave.end() ) { 1967 try { 1968 BaseGDL* v = e->GetObjHeap(subptr); //remember subptr IS uniquely increasing between OBJ and PTR Heaps indexes, but v is to be found in OBJ. 1969 heapIndexMapSave.insert(std::pair<DPtr, SizeT>(subptr, subptr)); 1970 if (DEBUG_SAVERESTORE) std::cerr<<"Adding Heaplist OBJ: HeapIndex="<<subptr<<", id="<<std::hex<<v<<std::dec<<std::endl; 1971 if (v && v!=NullGDL::GetSingleInstance() ) addToHeapList(e, v); 1972 } catch( GDLInterpreter::HeapException& hEx) 1973 { 1974 if (DEBUG_SAVERESTORE) std::cerr<<"OBJ ID <"<<subptr<<"> not found."<<std::endl; 1975 } 1976 } 1977 } 1978 } 1979 } else if (var->Type() == GDL_STRUCT) { 1980 DStructGDL* str = static_cast<DStructGDL*> (var); 1981 for (SizeT ielem = 0; ielem < var->N_Elements(); ++ielem) { 1982 for (int itag = 0; itag < str->NTags(); ++itag) { 1983 BaseGDL* v = str->GetTag(itag, ielem); 1984 if (v && v!=NullGDL::GetSingleInstance() ) addToHeapList(e, v); 1985 } 1986 } 1987 } 1988 return; 1989 } 1990 writeHeapList(XDR * xdrs)1991 uint32_t writeHeapList(XDR* xdrs) { 1992 // writing heap list for IDL compatiblilty implies to "mimic" the single heap list of IDL. 1993 //We write the PTRs first, then the OBJs after. OBJ ptrs will thus start at the last value held by PTRs plus one. 1994 int32_t elementcount = heapIndexMapSave.size(); 1995 if (elementcount < 1) return xdr_getpos(xdrs); 1996 uint32_t cur = writeNewRecordHeader(xdrs, HEAP_HEADER); //HEAP_HEADER 1997 xdr_int32_t(xdrs, &elementcount); 1998 int32_t indices[elementcount]; 1999 SizeT i = 0; 2000 heapT::iterator it; 2001 for (it = heapIndexMapSave.begin(); it != heapIndexMapSave.end(); ++it) indices[i++] = (*it).second; 2002 2003 xdr_vector(xdrs, (char*) indices, elementcount, sizeof (int32_t), (xdrproc_t) xdr_int32_t); 2004 if (DEBUG_SAVERESTORE) { 2005 cerr << "Heap indexes, " << elementcount << " elements: "; 2006 for (int i = 0; i < elementcount; ++i) cerr << indices[i] << ","; 2007 cerr << endl; 2008 } 2009 uint32_t next = updateNewRecordHeader(xdrs, cur); 2010 return next; 2011 } 2012 writeCommonList(EnvT * e,XDR * xdrs,std::string commonname)2013 uint32_t writeCommonList(EnvT*e, XDR* xdrs, std::string commonname) { 2014 if (DEBUG_SAVERESTORE) std::cerr<<"Writing Common "<<commonname<<std::endl; 2015 EnvStackT& callStack = e->Interpreter()->CallStack(); 2016 int32_t curlevnum = callStack.size(); 2017 DSubUD* pro = static_cast<DSubUD*> (callStack[curlevnum - 1]->GetPro()); 2018 DCommon* c=pro->Common(commonname); 2019 int32_t ncommonvars = c->NVar(); 2020 if (ncommonvars < 1) return xdr_getpos(xdrs); 2021 uint32_t cur = writeNewRecordHeader(xdrs, COMMONBLOCK); //COMMON 2022 xdr_int32_t(xdrs, &ncommonvars); 2023 char* name = (char*)commonname.c_str(); 2024 u_int len=c->Name().size(); 2025 xdr_string(xdrs, &name, len); 2026 char* varnames[ncommonvars]; 2027 u_int lens[ncommonvars]; 2028 for (int i = 0; i < ncommonvars; ++i) { 2029 varnames[i] = (char*)c->VarName(i).c_str(); 2030 if (DEBUG_SAVERESTORE) std::cerr<<" Name "<<c->VarName(i)<<std::endl; 2031 } 2032 for (int i = 0; i < ncommonvars; ++i) lens[i] = c->VarName(i).size(); 2033 for (int i = 0; i < ncommonvars; ++i) xdr_string(xdrs, &varnames[i], lens[i]); 2034 uint32_t next = updateNewRecordHeader(xdrs, cur); 2035 if (DEBUG_SAVERESTORE) std::cerr<<std::endl; 2036 return next; 2037 } myfunctionToSortStringsInPair(std::pair<std::string,BaseGDL * > i,std::pair<std::string,BaseGDL * > j)2038 bool myfunctionToSortStringsInPair (std::pair<std::string, BaseGDL*> i, std::pair<std::string, BaseGDL*> j) { return (i.first>j.first); } 2039 // new fast save. gdl_save(EnvT * e)2040 void gdl_save(EnvT* e) { 2041 2042 // xdr() is used through all the following. I program here xdr to use the 8, 16, 32 and 64 bits length 2043 // types of GDL/IDL (BYTE,INT,LONG,LONG64). However, a risk exist in some architectures that the real length 2044 // of DInt, DLong etc is not really the expected one (16 and 32 respectively). So the following is a test on these 2045 // lengths. If the test fails, 1) GDL is false for this architecture and that needs to be reported and 2046 // 2) gdl_restore cannot work. 2047 2048 if (safetyTested == false) 2049 { 2050 isSafe = testSafety(); 2051 if (!isSafe) e->Throw("Severe: internal representation of integers in this version of GDL is wrong, please report. Aborting unsafe use of RESTORE."); 2052 safetyTested = true; 2053 } 2054 //if testSafety is correct, DLong and int32_t , DInt and int16_t etc have the same meaning. 2055 2056 //empty maps etc by security. 2057 heapIndexMapSave.clear(); 2058 predeflist.clear(); 2059 2060 static int VERBOSE = e->KeywordIx("VERBOSE"); 2061 bool verbose = e->KeywordSet(VERBOSE); 2062 DLong verboselevel=(verbose?1:0); 2063 if (verbose) e->AssureLongScalarKW(VERBOSE,verboselevel); 2064 2065 2066 static int VARIABLES = e->KeywordIx("VARIABLES"); 2067 bool doVars=e->KeywordSet(VARIABLES); 2068 static int ALL = e->KeywordIx("ALL"); 2069 bool allVars=e->KeywordSet(ALL); 2070 static int SYSTEM_VARIABLES = e->KeywordIx("SYSTEM_VARIABLES"); 2071 bool doSys=e->KeywordSet(SYSTEM_VARIABLES); 2072 static int COMM = e->KeywordIx("COMM"); 2073 bool doComm=e->KeywordSet(COMM); 2074 static int COMPRESS = e->KeywordIx("COMPRESS"); 2075 save_compress=e->KeywordSet(COMPRESS); 2076 2077 if (allVars) { 2078 doSys=true; 2079 doComm=true; 2080 doVars=true; 2081 } 2082 2083 static int FILENAME = e->KeywordIx("FILENAME"); 2084 static int DESCRIPTION = e->KeywordIx("DESCRIPTION"); 2085 2086 bool needsDescription = e->KeywordPresent(DESCRIPTION); 2087 2088 DStringGDL* description=NULL; 2089 if (needsDescription) description=e->GetKWAs<DStringGDL>(DESCRIPTION); 2090 2091 std::vector<std::pair<std::string, BaseGDL*> > variableVector; 2092 std::vector<std::pair<std::string, BaseGDL*> > systemVariableVector; 2093 // std::vector<std::pair<std::string, BaseGDL*> > systemReadonlyVariableVector; //for readonly variables //not used 2094 set<string> commonList; 2095 2096 //Variables 2097 std::queue<std::pair<std::string, BaseGDL*> >varNameList; 2098 2099 long nparam=e->NParam(); 2100 if (!doComm && !doSys) doVars=(doVars||(nparam==0)); 2101 2102 if (doSys) 2103 { 2104 SizeT nVar = sysVarList.size(); 2105 for (SizeT v = 0; v < nVar; ++v) 2106 { 2107 DVar* var = sysVarList[v]; 2108 DString sysVarName = var->Name(); 2109 if (FindInVarList(sysVarRdOnlyList, sysVarName) != NULL) continue; //systemReadonlyVariableVector.push_back(make_pair("!" + sysVarName, sysVarRdOnly->Data())); 2110 if (FindInVarList(sysVarNoSaveList, sysVarName) != NULL) continue; 2111 systemVariableVector.push_back(make_pair("!" + sysVarName, var->Data())); 2112 } 2113 std::sort (systemVariableVector.begin(), systemVariableVector.end(), myfunctionToSortStringsInPair); 2114 } 2115 2116 if (doVars) 2117 { 2118 //will list (all) variables, incl. common defined, at desired level. 2119 EnvStackT& callStack = e->Interpreter()->CallStack(); 2120 DLong curlevnum = callStack.size(); 2121 DSubUD* pro = static_cast<DSubUD*> (callStack[curlevnum-1]->GetPro()); 2122 2123 SizeT nVar = pro->Size(); // # var in GDL for desired level 2124 SizeT nComm = pro->CommonsSize(); // # has commons? 2125 SizeT nTotVar = nVar + nComm; //All the variables availables at that lev. 2126 2127 if (nTotVar > 0) 2128 { 2129 if (nComm > 0) 2130 { 2131 DStringGDL* list = static_cast<DStringGDL*> (pro->GetCommonVarNameList()); 2132 for (SizeT i = 0; i < list->N_Elements(); ++i) { 2133 BaseGDL** var = pro->GetCommonVarPtr((*list)[i]); 2134 if (*var != NULL) varNameList.push(make_pair((*list)[i],*var)); 2135 } 2136 } 2137 if (nVar > 0 ) 2138 { 2139 for (SizeT i = 0; i < nVar; ++i) { 2140 BaseGDL* var = ((EnvT*) (callStack[curlevnum - 1]))->GetKW(i); 2141 if (var != NULL) varNameList.push(make_pair(pro->GetVarName(i),var)); 2142 } 2143 } 2144 } 2145 } 2146 2147 if (doComm) 2148 { 2149 //will list (all) variables, incl. common defined, at desired level. 2150 EnvStackT& callStack = e->Interpreter()->CallStack(); 2151 DLong curlevnum = callStack.size(); 2152 DSubUD* pro = static_cast<DSubUD*> (callStack[curlevnum - 1]->GetPro()); 2153 2154 SizeT nComm = pro->CommonsSize(); // # has commons? 2155 if (nComm > 0) 2156 { 2157 DStringGDL* list = static_cast<DStringGDL*> (pro->GetCommonVarNameList()); 2158 for (SizeT i = 0; i < list->N_Elements(); ++i) 2159 { 2160 DCommonBase* common = pro->FindCommon((*list)[i]); 2161 commonList.insert(common->Name()); 2162 } 2163 } 2164 } 2165 2166 2167 for (int i = 0; i < nparam; ++i) 2168 { 2169 BaseGDL* var = e->GetPar(i); 2170 if (var == NULL) 2171 { 2172 Message("Undefined item not saved: " + e->GetParString(i)); 2173 } else //var exists, but may have been already done by doVars. 2174 { 2175 if (!doVars) varNameList.push(make_pair(e->GetParString(i),var)); 2176 } 2177 } 2178 2179 while (!varNameList.empty()) 2180 { 2181 std::string varName = varNameList.front().first; 2182 BaseGDL* var = varNameList.front().second; 2183 varNameList.pop(); 2184 if (var->N_Elements()==0) Message("Undefined item not saved: "+varName+"."); 2185 else { 2186 //sytem variables are saved with /SYSTEM. This is a special case, test: try "SAVE,!P" with IDL: 2187 //<Expression> xxx generates an error. 2188 if (varName.substr(0, 1) == "<") e->Throw("Expression must be named variable in this context:" + varName); 2189 else 2190 { 2191 //examine variable. Cases: in common, normal. remove common name if necessary. 2192 std::size_t pos = varName.find("(", 0); 2193 if (pos != std::string::npos) varName = varName.substr(0, pos - 1); //one Blank. 2194 variableVector.push_back(make_pair(varName, var)); 2195 } 2196 } 2197 } 2198 2199 //Now, do we have heap variables in the variableVector (pointers)? If yes, we add these BaseGDL* to the heaplist unique list. 2200 //we then write the heap variables first. 2201 //then, anytime a pointer is found in any normal variable, instead of writing the data we will 2202 //just write the index of the pointed-to address in the heaplist. 2203 std::vector<std::pair<std::string, BaseGDL*> >::iterator itvar; 2204 for (itvar=variableVector.begin(); itvar!=variableVector.end(); ++itvar) { 2205 addToHeapList(e, itvar->second); 2206 } 2207 //NOTE: the following will not presently keep the information of a sysvar and readonly sysvar in heap. Which 2208 //is probably overkill? 2209 for (itvar=systemVariableVector.begin(); itvar!=systemVariableVector.end(); ++itvar) { 2210 addToHeapList(e, itvar->second); 2211 } 2212 // for (itvar=systemReadonlyVariableVector.begin(); itvar!=systemReadonlyVariableVector.end(); ++itvar) { 2213 // addToHeapList(e, itvar->second); 2214 // } 2215 2216 DString name; 2217 if (e->KeywordPresent(FILENAME)) 2218 { 2219 e->AssureScalarKW<DStringGDL>(FILENAME, name); 2220 } else name = "idlsave.dat"; 2221 2222 WordExp(name); 2223 2224 save_fid = fopen(name.c_str(), "wb+"); 2225 if (save_fid == NULL) e->Throw("Error opening file. Unit: XXXX, File: " + name + "."); 2226 2227 XDR* xdrs = new XDR; 2228 xdrstdio_create(xdrs, save_fid, XDR_ENCODE); 2229 2230 SizeT returned; 2231 char signature[4]={'S','R',0x00,0x04}; 2232 if (save_compress) signature[3]=0x06; 2233 returned = fwrite(signature, 4, 1, save_fid); 2234 2235 #define LONG sizeof(int32_t) //sizeof(DInt) 2236 #define ULONG LONG 2237 2238 2239 //will start at TIMESTAMP 2240 uint64_t currentptr = LONG; 2241 uint64_t nextptr = 0; 2242 2243 fseek(save_fid, currentptr, SEEK_SET); 2244 2245 const int MAX_DATE_STRING_LENGTH = 80; 2246 time_t t=time(0); 2247 struct tm * tstruct; 2248 tstruct=localtime(&t); 2249 char *saveFileDatestring=new char[MAX_DATE_STRING_LENGTH]; 2250 const char *dateformat="%a %h %d %T %Y";// day,month,day number,time,year 2251 SizeT res=strftime(saveFileDatestring,MAX_DATE_STRING_LENGTH,dateformat,tstruct); 2252 std::string saveFileUser = GetEnvString( "USER"); 2253 std::string saveFileHost = GetEnvString( "HOST"); 2254 if (saveFileHost == "") saveFileHost = GetEnvString( "HOSTNAME"); 2255 if (saveFileHost == "") { 2256 #define GDL_HOST_NAME_MAX 255 2257 char gethost[GDL_HOST_NAME_MAX]; 2258 size_t lgethost=GDL_HOST_NAME_MAX; 2259 // don't know if this primitive is available on Mac OS X 2260 int success = gethostname(gethost, lgethost); 2261 if( success == 0) saveFileHost=string(gethost); 2262 } 2263 //TIMESTAMP 2264 nextptr=writeTimeUserHost(xdrs, saveFileDatestring, (char*)saveFileUser.c_str(), (char*)saveFileHost.c_str()); 2265 int32_t format=9; //IDL v. 6.1 ++ 2266 DStructGDL* version = SysVar::Version(); 2267 static unsigned osTag = version->Desc()->TagIndex( "OS"); 2268 static unsigned archTag = version->Desc()->TagIndex( "ARCH"); 2269 static unsigned releaseTag = version->Desc()->TagIndex( "RELEASE"); 2270 DString os = (*static_cast<DStringGDL*>( version->GetTag( osTag, 0)))[0]; 2271 DString arch = (*static_cast<DStringGDL*>( version->GetTag( archTag, 0)))[0]; 2272 DString release = (*static_cast<DStringGDL*>( version->GetTag( releaseTag, 0)))[0]; 2273 //VERSION 2274 nextptr=writeVersion(xdrs, &format, (char*)arch.c_str(), (char*) os.c_str() , (char*) release.c_str()); 2275 //HEAPLIST 2276 if (heapIndexMapSave.size() > 0) nextptr=writeHeapList(xdrs); 2277 // promote64: NO! 2278 // //notice: 2279 // std::string notice="Made by GDL, a free software program that you can redistribute and/or modify" 2280 // " under the terms of the GPL, use at your own risks."; 2281 // nextptr=writeNotice(xdrs, (char*)notice.c_str()); 2282 if (description!=NULL) nextptr=writeDescription(xdrs,(char*)((*description)[0].c_str())); 2283 2284 //COMMON 2285 std::set<std::string>::iterator itcommon; 2286 for (itcommon=commonList.begin(); itcommon!=commonList.end(); ++itcommon) { 2287 nextptr=writeCommonList(e, xdrs, *itcommon); 2288 if (verboselevel>0) Message("Saved common block: " + *itcommon); 2289 } 2290 //HEAP Variables: all terminal variables pointed by, OBJs or PTRs 2291 2292 if (heapIndexMapSave.size() > 0) { //there is some heap... 2293 DPtrGDL* heapPtrList=e->Interpreter( )->GetAllHeap( ); 2294 for (SizeT i=0; i<heapPtrList->N_Elements(); ++i) nextptr=writeHeapVariable(e, xdrs, (*heapPtrList)[i], false); 2295 GDLDelete(heapPtrList); 2296 DObjGDL* heapObjPtrList=e->Interpreter( )->GetAllObjHeap( ); 2297 for (SizeT i=0; i<heapObjPtrList->N_Elements(); ++i) nextptr=writeHeapVariable(e, xdrs, (*heapObjPtrList)[i], true); 2298 GDLDelete(heapObjPtrList); 2299 } 2300 2301 // 2302 // while (!systemReadonlyVariableVector.empty()) 2303 // { 2304 // nextptr = writeNormalVariable(xdrs, systemReadonlyVariableVector.back().first, (systemReadonlyVariableVector.back()).second, 0x3); 2305 // if (verboselevel > 0) Message("Saved variable: " + (systemReadonlyVariableVector.back()).first + "."); 2306 // systemReadonlyVariableVector.pop_back(); 2307 // } 2308 while (!systemVariableVector.empty()) 2309 { 2310 nextptr = writeNormalVariable(xdrs, systemVariableVector.back().first, (systemVariableVector.back()).second, 0x2); 2311 if (verboselevel > 0) Message("SAVE: Saved system variable: " + (systemVariableVector.back()).first + "."); 2312 systemVariableVector.pop_back(); 2313 } 2314 2315 while (!variableVector.empty()) 2316 { 2317 nextptr=writeNormalVariable(xdrs, variableVector.back().first, (variableVector.back()).second); 2318 if (verboselevel>0) Message("SAVE: Saved variable: " + (variableVector.back()).first+"."); 2319 variableVector.pop_back(); 2320 } 2321 2322 nextptr=writeEnd(xdrs); 2323 xdr_destroy(xdrs); 2324 fclose(save_fid); 2325 } 2326 2327 } 2328 2329