OpenRadioss 2025.1.11
OpenRadioss project
Loading...
Searching...
No Matches
checksum_list.cpp
Go to the documentation of this file.
1//Copyright> OpenRadioss
2//Copyright> Copyright (C) 1986-2025 Altair Engineering Inc.
3//Copyright>
4//Copyright> This program is free software: you can redistribute it and/or modify
5//Copyright> it under the terms of the GNU Affero General Public License as published by
6//Copyright> the Free Software Foundation, either version 3 of the License, or
7//Copyright> (at your option) any later version.
8//Copyright>
9//Copyright> This program is distributed in the hope that it will be useful,
10//Copyright> but WITHOUT ANY WARRANTY; without even the implied warranty of
11//Copyright> MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12//Copyright> GNU Affero General Public License for more details.
13//Copyright>
14//Copyright> You should have received a copy of the GNU Affero General Public License
15//Copyright> along with this program. If not, see <https://www.gnu.org/licenses/>.
16//Copyright>
17//Copyright>
18//Copyright> Commercial Alternative: Altair Radioss Software
19//Copyright>
20//Copyright> As an alternative to this open-source version, Altair also offers Altair Radioss
21//Copyright> software under a commercial license. Contact Altair to discuss further if the
22//Copyright> commercial version may interest you: https://www.altair.com/radioss/.
23#include <checksum_model.h>
25#include <checksum_list.h>
26using namespace std;
27
28
29bool List_checksum::is_integer(const std::string s) {
30 char * p;
31 char * s_cchar = (char*)s.c_str();
32 // strtol will convert the string to a long integer
33 // If the conversion is successful, p will point to the first character after the number
34 // If the conversion fails, p will point to the original string
35 long converted = strtol(s_cchar, &p, 10);
36 if (*p) {
37 return false; // Not a valid integer
38 }
39 return true;
40
41
42}
43 // -----------------------------------------------------------------------------------
44 // Tool : Format the number as a 4-digit string with leading zeros for .out files
45 // input:
46 // number : integer to be formatted
47 // output:
48 // formatted string
49 // -----------------------------------------------------------------------------------
51 // -----------------------------------------------------------------------------------
52 ostringstream oss;
53 oss << setw(4) << setfill('0') << number;
54 return oss.str();
55 }
56
57 // -----------------------------------------------------------------------------------
58 // Tool : Format the number as a 3-digit string with leading zeros for Animation & Time History files
59 // input:
60 // number : integer to be formatted
61 // output:
62 // formatted string
63 // -----------------------------------------------------------------------------------
65 // -----------------------------------------------------------------------------------
66 ostringstream oss;
67 oss << setw(3) << setfill('0') << number;
68 return oss.str();
69 }
70
71 // -----------------------------------------------------------------------------------
72 // Dos2Unix : function to remove (cr) characters from a string
73 // -----------------------------------------------------------------------------------
74 void List_checksum::remove_cr(std::string& line) {
75 line.erase(std::remove(line.begin(), line.end(), '\r'), line.end());
76 }
77
78
79
80 // -----------------------------------------------------------------------------------
81 // Tool : Return the separator for the file path according to the OS
82 // output:
83 // separator : "/" for Unix, "\" for Windows
84 // -----------------------------------------------------------------------------------
86 // -----------------------------------------------------------------------------------
87 #ifdef _WIN64
88 return "\\"; // Windows separator
89 #else
90 return "/"; // Unix separator
91 #endif
92 }
93
94 // -----------------------------------------------------------------------------------
95 // Compare two lists of checksums
96 // input:
97 // list1 : first list of checksums
98 // list2 : second list of checksums
99 // output:
100 // 1 if the lists are equal, 0 if they are not equal
101 // -----------------------------------------------------------------------------------
102 int List_checksum::compare_lists(list<string> list1, list<string> list2){
103 // -----------------------------------------------------------------------------------
104 if (list1.size() != list2.size()) {
105 return 0; // Lists are not equal in size
106 }
107 auto it1 = list1.begin();
108 auto it2 = list2.begin();
109 while (it1 != list1.end() && it2 != list2.end()) {
110 if (*it1 != *it2) {
111 return 0; // Lists are not equal
112 }
113 ++it1;
114 ++it2;
115 }
116 return 1; // Lists are equal
117 }
118
119 // -----------------------------------------------------------------------------------
120 // sorst in lists : get a filename & sort it in the corresponding list if pattern found
121 // input:
122 // fname : filename
123 // rootname : deck rootname
124 // output:
125 // void, out_file_list, th_file_list, anim_file_list are updated
126 // -----------------------------------------------------------------------------------
127 void List_checksum::sort_in_lists(std::string fname,std::string rootname){
128
129 // Grab the file extension
130 size_t pos = string(fname).find_last_of('.');
131 std::string extension = fname.substr(pos + 1);
132
133 // Input deck
134 string input_deck=rootname+"_0000.rad";
135 if (fname == input_deck){
136 deck_file_list.push_back(fname);
137 }
138
139 if (extension == "out") {
140 out_file_list.push_back(fname);
141 }
142 if (extension == "thy") {
143 th_file_list.push_back(fname);
144 }
145
146 if (extension == "checksum") {
147 int filename_length = rootname.length()+5+extension.length()+1;
148 if (fname.length() == filename_length){
149 std::string str_runnumber=fname.substr(rootname.length()+1,4);
150 if (is_integer(str_runnumber)){
151 checksum_file_list.push_back(fname);
152 }
153 }
154 }
155
156 // Old styled files Axxx, Txxx
157 string rd_run;
158 string file_A;
159 if (extension == "gz"){
160 rd_run = fname.substr(fname.length()-6,3);
161 file_A=fname.substr(0,fname.length()-6);
162 }else{
163 rd_run = fname.substr(fname.length()-3);
164 file_A=fname.substr(0,fname.length()-3);
165 }
166 string anim_pattern=rootname+ "A";
167 if ( is_integer(rd_run) && anim_pattern == file_A){
168 anim_file_list.push_back(fname);
169 }
170 string th_pattern=rootname+ "T";
171 string file_T=fname.substr(0,fname.length()-2);
172 rd_run = fname.substr(fname.length()-2);
173 if ( is_integer(rd_run) && th_pattern == file_T){
174 th_file_list.push_back(fname);
175 }
176
177 }
178
179 // -----------------------------------------------------------------------------------
180 // file_list : read all files in the directory and sort them in the corresponding list
181 // input:
182 // directory : directory where the files are located
183 // rootname : rootname of the files (without run number and extension)
184 // output:
185 // out_file_list, th_file_list, anim_file_list are updated
186 // -----------------------------------------------------------------------------------
187 void List_checksum::file_list(std::string directory,std::string rootname){
188
189 std::vector<std::string> files;
190
191#ifdef _WIN64
192 std::string search_path = directory + rootname + "*";
193 WIN32_FIND_DATAA fd;
194 HANDLE hFind = ::FindFirstFileA(search_path.c_str(), &fd);
195 if (hFind != INVALID_HANDLE_VALUE) {
196 do {
197 if (!(fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) {
198 string fname(fd.cFileName);
199 sort_in_lists(fname,rootname);
200 }
201 } while (::FindNextFileA(hFind, &fd));
202 ::FindClose(hFind);
203 }
204#else
205 string directory_cp = directory;
206 if ( directory_cp.length()==0){
207 directory_cp=".";
208 }
209 DIR* dir = opendir(directory_cp.c_str());
210 if (dir) {
211 struct dirent* entry;
212 while ((entry = readdir(dir)) != nullptr) {
213 std::string fname(entry->d_name);
214 if (fname.find(rootname) == 0) { // starts with rootname
215 sort_in_lists(fname,rootname);
216 }
217 }
218 closedir(dir);
219 }
220#endif
221
222};
223
224
225 // -----------------------------------------------------------------------------------
226 // is_file_valid : check if the file has valid fingerprint
227 // -----------------------------------------------------------------------------------
228
229 bool List_checksum::is_file_valid(std::string file){
230 return true;
231 }
232
233
234 // -------------------------------------------------------------------------------------------------------------------------------------------------
235 // Parse all .out files in the directory, grab the deck checsksums fingerprints
236 // Do an MD5 on the file
237 // input:
238 // directory : directory where the .out files are located
239 // rootname : rootname of the .out files (without run number and extension)
240 // output:
241 // list of tuples (filename, checksum match)
242 // The checksum match is 1 if the checksums are equal, 0 if they are not equal
243 // -------------------------------------------------------------------------------------------------------------------------------------------------
244 void List_checksum::parse_output_files(string directory, string rootname){
245 // -------------------------------------------------------------------------------------------------------------------------------------------------
246
247 for (const auto& item : out_file_list){
248
249 string outfile;
250 if ( directory.length() > 0 ){
251 outfile = directory + item;
252 }else{
253 outfile = item;
254 }
255
256 fstream new_file;
257 new_file.open(outfile, ios::in);
258
259 if ( !new_file.is_open() ) {
260 // cout << "Error: Unable to open file " << outfile << endl;
261 }else{
262 if (debug){
263 cout << "Parsing file: " << outfile << endl;
264 }
265 // Grab file checksums
267 list<string> checksum_list_out=out.Out_File( &new_file );
268 new_file.close();
269
270 // Compute file checksum
271 checksum file_cs;
272 string file_checksum = file_cs.compute_checksum(outfile);
273 string formated_out = outfile + " : " + file_checksum;
274
275 checksum_list.push_back(make_tuple(formated_out,checksum_list_out)); // Add the checksum list to the collection
276 file_checksum_list.insert(pair<string,string>(outfile, file_checksum)); // Add the file,checksum tuple in specific list
277 }
278 }
279 }
280
281 // -------------------------------------------------------------------------------------------------------------------------------------------------
282 // Parse all Animation files from the directory, grab the deck checsksums fingerprints
283 // Do an MD5 on the file
284 // input:
285 // directory : directory where the .out files are located
286 // rootname : rootname of the .out files (without run number and extension)
287 // output:
288 // list of tuples (filename, checksum match)
289 // The checksum match is 1 if the checksums are equal, 0 if they are not equal
290 // -------------------------------------------------------------------------------------------------------------------------------------------------
291 void List_checksum::parse_animation_files(string directory, string rootname){
292 // -------------------------------------------------------------------------------------------------------------------------------------------------
293 int run_number=1;
294 int found_out_file=1;
295
296 for (const auto& item : anim_file_list){
297
298 string anim_file;
299 if ( directory.length() > 0 ){
300 anim_file = directory + item;
301 }else{
302 anim_file = item;
303 }
304
306 FILE *new_file;
307 int success=0;
308 success=out.open_binary_file(anim_file);
309
310 if ( success == 0 ) {
311 // cout << "Error: Unable to open file " << anim_file << endl;
312 found_out_file=0; // No more .out files to process
313 }else{
314 if (debug){
315 cout << "Parsing file: " << anim_file << endl;
316 }
317
318
319 list<string> checksum_list_out=out.Animation( );
320 out.close_binary_file();
321 // Compute file checksum
322 checksum file_cs;
323 string file_checksum = file_cs.compute_checksum(anim_file);
324 string formated_out = anim_file + " : " + file_checksum;
325
326 checksum_list.push_back(make_tuple(formated_out,checksum_list_out)); // Add the checksum list to the collection
327 file_checksum_list.insert(pair<string,string>(anim_file, file_checksum)); // Add the file,checksum tuple in specific list
328
329
330 }
331 run_number++;
332 }
333 }
334
335 // -------------------------------------------------------------------------------------------------------------------------------------------------
336 // Parse all time history files from the directory, grab the deck checsksums fingerprints
337 // Do an MD5 on the file
338 // input:
339 // directory : directory where the .out files are located
340 // rootname : rootname of the .out files (without run number and extension)
341 // output:
342 // list of tuples (filename, checksum match)
343 // The checksum match is 1 if the checksums are equal, 0 if they are not equal
344 // -------------------------------------------------------------------------------------------------------------------------------------------------
345 void List_checksum::parse_th_files(string directory, string rootname){
346 // -------------------------------------------------------------------------------------------------------------------------------------------------
347 int found_out_file=1;
348
349 for (const auto& item : th_file_list){
350
351 string th_file;
352 if ( directory.length() > 0 ){
353 th_file = directory + item;
354 }else{
355 th_file = item;
356 }
357
359 int success = out.open_binary_file(th_file);
360
361 if ( success == 0 ) {
362 // cout << "Error: Unable to open file " << anim_file << endl;
363 found_out_file=0; // No more .out files to process
364 }else{
365 if (debug){
366 cout << "Parsing file: " << th_file << endl;
367 }
368 list<string> checksum_list_th=out.Time_History();
369 out.close_binary_file();
370
371 checksum file_cs;
372 string file_checksum = file_cs.compute_checksum(th_file);
373 string formated_out = th_file + " : " + file_checksum;
374
375 checksum_list.push_back(make_tuple(formated_out,checksum_list_th)); // Add the checksum list to the collection
376 file_checksum_list.insert(pair<string,string>(th_file, file_checksum)); // Add the file,checksum tuple in specific list
377 }
378 }
379 }
380
381 // -------------------------------------------------------------------------------------------------------------------------------------------------
382 // Parse all .checksum files from the directory
383 // Verifies the .checksum filefingerprint
384 //
385 // input:
386 // directory : directory where the .out files are located
387 // rootname : rootname of the .out files (without run number and extension)
388 // output:
389 // formated list of tupes
390 // -------------------------------------------------------------------------------------------------------------------------------------------------
391 void List_checksum::parse_checksum_files(string directory, string rootname){
392
393 for (const auto& item : checksum_file_list){
394
395 string chkfile;
396 if ( directory.length() > 0 ){
397 chkfile = directory + item;
398 }else{
399 chkfile = item;
400 }
401
402 bool valid_file = is_file_valid(chkfile);
403 string valid_message;
404 if (valid_file) {
405 valid_message = "Valid Fingerprint";
406 }else{
407 valid_message = "Invalid Fingerprint";
408 }
409
410 fstream new_file;
411 new_file.open(chkfile, ios::in);
412
413 if ( !new_file.is_open() ) {
414 // cout << "Error: Unable to open file " << outfile << endl;
415 }else{
416 if (debug){
417 cout << "Parsing file: " << chkfile << endl;
418 }
419 // Grab file checksums
421 std::list<std::tuple<std::string,std::string>> checksum_list_chk;
422 checksum_list_chk=out.Checksum_File( &new_file );
423 new_file.close();
424
425 string formated_out = chkfile + " : " ;
426 list<string> verify_checksum_list;
427
428 // print the checksum list
429 for (const auto& item2 :checksum_list_chk){
430 string filename = get<0>(item2);
431 string checksum = get<1>(item2);
432
433 string computed_checksum= file_checksum_list[filename];
434
435 if (computed_checksum.length() > 0){
436 if (checksum == computed_checksum){
437 verify_checksum_list.push_back(filename + "_" + "Valid Checksum" );
438 }else{
439 verify_checksum_list.push_back(filename + "_" + "Failed checksum check : File: "+ checksum + " Computed: " + computed_checksum);
440 }
441 }
442 }
443 checksum_list.push_back(make_tuple(formated_out,verify_checksum_list)); // Add the checksum list to the collection
444
445 }
446 }
447 };
448
449
451 {};
452
453
454// Class to list the compute starter input file and parse output files for checksums
455// -----------------------------------------------------------------------------------
456
457std::string List_checksum::get_path(const std::string& filepath) {
458 // Find the last occurrence of the path separator
459#ifdef _WIN64
460 size_t pos = filepath.find_last_of("/\\");
461 if (pos == std::string::npos) {
462 pos = filepath.find_last_of("/");
463 }
464#else
465 size_t pos = filepath.find_last_of("/");
466#endif
467 if (pos != std::string::npos) {
468 // Extract the substring up to the last separator
469 return filepath.substr(0, pos);
470 }
471 // If no separator is found, return an empty string
472 return "";
473}
474
475 // -------------------------------------------------------------------------------
476 // Compare the checksum from deck to output file
477 // Computes input deck checksum & parse all output files to compare the results.
478 // -------------------------------------------------------------------------------
479 // input:
480 // filename : string starter input filename
481 // directory : string directory where the input file is located
482 // output:
483 // list of checksums found in the .out file : format (filename, checksum list)
484 // -------------------------------------------------------------------------------
485 list<tuple<string,list<string>>> List_checksum::chk_list(string rootname,string directory){
486 // -------------------------------------------------------------------------------
487
488 // Debug prints
489 if (debug){
490 cout << endl;
491 cout << "Directory: " << directory << endl;
492 cout << "Rootname: " << rootname << endl;
493 cout << endl;
494 }
495
496 file_list(directory,rootname); // List all files in the directory
497
498
499 for (const auto& deck_file : deck_file_list){
500
501 // If deck is present:
502 // Compute checksum from input deck
503 MD5Checksum my_checksums;
504 my_checksums.parse(deck_file);
505 list<string> deck_checksum_list=my_checksums.get_checksums(); // Compute checksum from input deck
506
507 // Add Starter computed checksum to the list
508 checksum_list.push_back(make_tuple(deck_file,deck_checksum_list)); // Add the checksum list to the collection
509
510 if (debug){
511 cout << "Commputed Checksum list from deck: " << endl;
512 cout << "===================================" << endl;
513 for (const auto& item : deck_checksum_list){
514 cout << item << endl;
515 }
516 cout << "==============================" << endl;
517 cout << endl;
518 }
519 }
520
521
522 // Parse all .out files in the directory
523 parse_output_files(directory, rootname);
524
525 // parse all animation files in the directory
526 parse_animation_files(directory, rootname);
527
528 // parse all animation files in the directory
529 parse_th_files(directory, rootname);
530
531 // Parse all checksum files in the directory
532 parse_checksum_files(directory, rootname);
533
534 // print the checksum list from all output files
535 if (debug){
536 cout << "Checksum list from output files: " << endl;
537 cout << "==============================" << endl;
538 for (const auto& item : checksum_list){
539 cout << "File: " << get<0>(item) << endl;
540 for (const auto& checksum : get<1>(item)){
541 cout << " "<< checksum << endl;
542 }
543 cout << "==============================" << endl;
544 }
545 }
546
547 return checksum_list ;
548 }
549
550// End of class Verify_checksum
551// ------------------------------------------------------------------------------------------------------------------------
552
553
554
555// C/Fortran interface for Starter
556extern "C" {
557 void grab_checksums(int *fd,char *rootname,int *lenr,char *path,int *lenp){
558 int i;
559
560 // Convert input fortran to C Character
561
562 char rootname_c[257]; // maximum length of the input string is 256 in Starter
563 for (i=0;i<*lenr;i++){
564 rootname_c[i]=rootname[i];
565 }
566 rootname_c[*lenr]='\0'; // Add null character to the end of the string
567 string str_rootname(rootname_c); // Convert to string
568
569
570 char path_c[2029]; // maximum length of the path string is 2048 in Starter
571 for (i=0;i<*lenp;i++){
572 path_c[i]=path[i];
573 }
574 path_c[*lenp]='\0'; // Add null character to the end of the string
575 string str_path(path_c); // Convert to string
576
577
578 // Create checksum_list object
579 // grab the input deck name
580 list<tuple<string,list<string>>> checksum_list; // checksum list collection from all decks : filename, checksum list
581 List_checksum chksum_tool;
582 checksum_list=chksum_tool.chk_list(str_rootname,str_path); // Compute the checksums from the input deck and parse the output files
583
584
585 // Print the checksum list to the output file
586 const char* blank=" ";
587 int len_blank= strlen(blank);
588
589 for (const auto& item : checksum_list){
590 string filename=" File. . . . "+get<0>(item);
591 const char* line=filename.c_str();
592 int len_line= strlen(line);
593 write_out_file(fd,line,&len_line);
594 int len_blanck=1;
595 write_out_file(fd," ",&len_blank);
596
597 for (const auto& checksum : get<1>(item)){
598 size_t pos = checksum.find_last_of("_");
599 string title=checksum.substr(0,pos); // Remove the checksum value
600 string digest=checksum.substr(pos+1); // Keep only the checksum value
601 string checksum_line=" "+title+" : "+digest;
602 const char* line=checksum_line.c_str();
603 len_line= strlen(line);
604 write_out_file(fd,line,&len_line); // Fortran routine to write the checksum line
605 }
606 write_out_file(fd,blank,&len_blank);
607 write_out_file(fd,blank,&len_blank);
608 }
609
610 }
611
612}
613
614
615// ------------------------------------------------------------------------------------------------------------------------
616// Main Standalone function to test the checksum tool
617// The function will read the input file and compute the checksums
618// The function will also parse the .out files and compare the checksums with the ones computed in the input deck
619// The function will print the results to the console
620// To build in Standalone mode, use the following command:
621// On Windows:
622// icx -DMAIN -o ..\exec\checksum.exe -Ishare/includes -ID:\WS\GitHub\OpenRadioss_VS\OpenRadioss\extlib\md5\include source\output\checksum\checksum_list.cpp source\output\checksum\checksum_model.cpp source\output\checksum\checksum_output_files.cpp D:\WS\GitHub\OpenRadioss_VS\OpenRadioss\extlib\md5\win64\md5.lib ws2_32.lib
623// g++ -DMAIN -no-pie -o ../exec/checksum -Ishare/includes -I/mnt/d/WS/GitHub/OpenRadioss_VS/OpenRadioss/extlib/md5/include source/output/checksum/checksum_list.cpp source/output/checksum/checksum_model.cpp source/output/checksum/checksum_output_files.cpp /mnt/d/WS/GitHub/OpenRadioss_VS/OpenRadioss/extlib/md5/linux64/libmd5.a -std=c++14
624// Add -DDEBUG for additional debug information
625// ------------------------------------------------------------------------------------------------------------------------
626#ifdef MAIN
627
628void write_out_file(int * fd,const char * line,int * len_line){
629 // Dummy routine to permit link out of Starter
630}
631
632int main(int argc, char *argv[])
633{
634 List_checksum verify_chksum_tool;
635 cout << endl;
636 cout << "Filename to process: "<< argv[1] << endl;
637 string file=string(argv[1]);
638
639 string path=verify_chksum_tool.get_path(file); // Get the directory of the file
640 list<tuple<string,list<string>>> list = verify_chksum_tool.chk_list(file,path);
641
642 cout << endl;
643 cout << "Checksum list from output files: " << endl;
644 cout << "==============================" << endl << endl;
645
646 for (const auto& item : list){
647 cout << "File: " << get<0>(item) << endl;
648 for (const auto& checksum : get<1>(item)){
649 string title=checksum.substr(0,checksum.length()-33); // Remove the checksum value
650 string digest=checksum.substr(checksum.length()-32); // Keep only the checksum value
651 cout << " "<< title << " : " << digest << endl;
652 }
653 cout << endl;
654 }
655}
656#endif
int main()
#define write_out_file
Definition checksum.h:53
#define grab_checksums
int open_binary_file(std::string filename)
std::list< std::string > Animation()
std::list< std::string > Out_File(std::fstream *new_file)
std::list< std::string > Time_History()
std::list< std::tuple< std::string, std::string > > Checksum_File(std::fstream *new_file)
void sort_in_lists(std::string file, std::string rootname)
void parse_output_files(std::string directory, std::string rootname)
std::map< std::string, std::string > file_checksum_list
bool is_integer(const std::string s)
std::list< std::tuple< std::string, std::list< std::string > > > chk_list(std::string input, std::string directory)
std::list< std::string > th_file_list
bool is_file_valid(std::string file)
void remove_cr(std::string &line)
std::string format_as_3_digits(int number)
std::list< std::string > checksum_file_list
void parse_th_files(std::string directory, std::string rootname)
void parse_animation_files(std::string directory, std::string rootname)
std::string separator()
std::list< std::string > anim_file_list
std::list< std::tuple< std::string, std::list< std::string > > > checksum_list
std::string format_as_4_digits(int number)
std::list< std::string > out_file_list
int compare_lists(std::list< std::string > list1, std::list< std::string > list2)
std::list< std::string > deck_file_list
std::string get_path(const std::string &filepath)
void file_list(std::string directory, std::string rootname)
void parse_checksum_files(std::string directory, std::string rootname)
void parse(std::string filenam)
std::list< std::string > get_checksums()
std::string compute_checksum(std::string file)
Definition checksum.cpp:25
FILE * outfile[100]