1 package FileIO::FingerprintsFPFileIO; 2 # 3 # File: FingerprintsFPFileIO.pm 4 # Author: Manish Sud <msud@san.rr.com> 5 # 6 # Copyright (C) 2024 Manish Sud. All rights reserved. 7 # 8 # This file is part of MayaChemTools. 9 # 10 # MayaChemTools is free software; you can redistribute it and/or modify it under 11 # the terms of the GNU Lesser General Public License as published by the Free 12 # Software Foundation; either version 3 of the License, or (at your option) any 13 # later version. 14 # 15 # MayaChemTools is distributed in the hope that it will be useful, but without 16 # any warranty; without even the implied warranty of merchantability of fitness 17 # for a particular purpose. See the GNU Lesser General Public License for more 18 # details. 19 # 20 # You should have received a copy of the GNU Lesser General Public License 21 # along with MayaChemTools; if not, see <http://www.gnu.org/licenses/> or 22 # write to the Free Software Foundation Inc., 59 Temple Place, Suite 330, 23 # Boston, MA, 02111-1307, USA. 24 # 25 26 use strict; 27 use Carp; 28 use Exporter; 29 use Scalar::Util (); 30 use TextUtil (); 31 use FileUtil (); 32 use TimeUtil (); 33 use Fingerprints::FingerprintsStringUtil (); 34 use PackageInfo (); 35 use FileIO::FileIO; 36 37 use vars qw(@ISA @EXPORT @EXPORT_OK %EXPORT_TAGS); 38 39 @ISA = qw(FileIO::FileIO Exporter); 40 @EXPORT = qw(); 41 @EXPORT_OK = qw(IsFingerprintsFPFile); 42 43 %EXPORT_TAGS = (all => [@EXPORT, @EXPORT_OK]); 44 45 # Setup class variables... 46 my($ClassName); 47 _InitializeClass(); 48 49 # Class constructor... 50 sub new { 51 my($Class, %NamesAndValues) = @_; 52 53 # Initialize object... 54 my $This = $Class->SUPER::new(); 55 bless $This, ref($Class) || $Class; 56 $This->_InitializeFingerprintsFPFileIO(); 57 58 $This->_InitializeFingerprintsFPFileIOProperties(%NamesAndValues); 59 60 return $This; 61 } 62 63 # Initialize object data... 64 # 65 sub _InitializeFingerprintsFPFileIO { 66 my($This) = @_; 67 68 # Fingerprints string data format during read/write... 69 # 70 # For file read: 71 # 72 # AutoDetect - automatically detect format of fingerprints string 73 # FingerprintsBitVectorString - Bit vector fingerprints string format 74 # FingerprintsVectorString - Vector fingerprints string format 75 # 76 # Default value: AutoDetect 77 # 78 # For file write: 79 # 80 # FingerprintsBitVectorString - Bit vector fingerprints string format 81 # FingerprintsVectorString - Vector fingerprints string format 82 # 83 # Default value: undef 84 # 85 $This->{FingerprintsStringMode} = undef; 86 87 # For file read: 88 # 89 # o Fingerprints bit-vector and vector object for current fingerprints string 90 # 91 # For file write: 92 # 93 # o Fingerprints bit-vector and vector object for current fingerprints string 94 # o Any supported fingerprints object: PathLengthFingerprints, ExtendedConnectivity, and so on. 95 # 96 $This->{FingerprintsObject} = undef; 97 98 # Fingeprints string for current line during read/write... 99 $This->{FingerprintsString} = undef; 100 101 # Partial fingeprints string corresponding to what's on the current line for current 102 # line during read/write... 103 $This->{PartialFingerprintsString} = undef; 104 105 # Required header data keys and values during read/write... 106 @{$This->{RequiredHeaderDataKeys}} = (); 107 %{$This->{RequiredHeaderDataKeysAndValues}} = (); 108 109 # First data line read/write... 110 $This->{FirstDataLineIO} = 1; 111 112 # Current fingerprints string data line number during read/write... 113 $This->{LineNum} = 0; 114 115 # FP line data during read/write... 116 $This->{DataLine} = undef; 117 118 # Initialize parameters for read... 119 $This->_InitializeFingerprintsFPFileIORead(); 120 121 # Initialize parameters for write... 122 $This->_InitializeFingerprintsFPFileIOWrite(); 123 124 return $This; 125 } 126 127 # Initialize class ... 128 sub _InitializeClass { 129 #Class name... 130 $ClassName = __PACKAGE__; 131 132 } 133 134 # Initialize object data for reading fingerprints FP file... 135 # 136 sub _InitializeFingerprintsFPFileIORead { 137 my($This) = @_; 138 139 # Header data keys and values... 140 # 141 @{$This->{HeaderDataKeys}} = (); 142 %{$This->{HeaderDataKeysAndValues}} = (); 143 %{$This->{CannonicalHeaderDataKeysAndValues}} = (); 144 145 # By default, the fingerprints data is assumed to be valid and no validation is 146 # performed before generating fingerprints objects... 147 # 148 $This->{ValidateData} = 1; 149 150 # Level of detail to print during validation of data for invalid or missing data... 151 $This->{DetailLevel} = 1; 152 153 # Number of missing and invalid fingerprints string data lines... 154 $This->{NumOfLinesWithMissingData} = 0; 155 $This->{NumOfLinesWithInvalidData} = 0; 156 157 # Compound ID for current fingerprints string... 158 $This->{CompoundID} = undef; 159 160 # Status of data in fingerprints FP file... 161 $This->{ValidFileData} = 0; 162 $This->{ValidRequiredHeaderDataKeys} = 0; 163 $This->{ValidFingerprintsStringMode} = 0; 164 165 return $This; 166 } 167 168 # Initialize object data for writing fingerprints FP file... 169 # 170 sub _InitializeFingerprintsFPFileIOWrite { 171 my($This) = @_; 172 173 # Fingerprints bit vector string format... 174 # 175 # Possible values: BinaryString or HexadecimalString [Default] 176 # 177 # Default BitStringFormat is set during first write using Fingerprints::FingerprintsStringUtil::GetDefaultBitStringFormat. 178 # 179 $This->{BitStringFormat} = undef; 180 181 # Bits order in fingerprints bit vector string... 182 # 183 # Ascending - First bit in each byte as the lowest bit [Default] 184 # Descending - First bit in each byte as the highest bit 185 # 186 # Default BitsOrder is set during first write using Fingerprints::FingerprintsStringUtil::GetDefaultBitsOrder. 187 # 188 $This->{BitsOrder} = undef; 189 190 # Fingerprints vector string format... 191 # 192 # Possible values: IDsAndValuesString, IDsAndValuesPairsString, ValuesAndIDsString, ValuesAndIDsPairsString, ValuesString 193 # 194 # Default VectorStringFormat is set during first write using Fingerprints::FingerprintsStringUtil::GetDefaultVectorStringFormat. 195 # For fingerprints vector object containing vector NumericalValues, it corresponds to IDsAndValuesString; otherwise, 196 # it's set to ValuesString. 197 # 198 $This->{VectorStringFormat} = undef; 199 200 # Overwriting existing file... 201 $This->{Overwrite} = 0; 202 203 return $This; 204 } 205 206 # Initialize object values... 207 sub _InitializeFingerprintsFPFileIOProperties { 208 my($This, %NamesAndValues) = @_; 209 210 # All other property names and values along with all Set/Get<PropertyName> methods 211 # are implemented on-demand using ObjectProperty class. 212 213 my($Name, $Value, $MethodName); 214 while (($Name, $Value) = each %NamesAndValues) { 215 $MethodName = "Set${Name}"; 216 $This->$MethodName($Value); 217 } 218 219 if (!exists $NamesAndValues{Name}) { 220 croak "Error: ${ClassName}->New: Object can't be instantiated without specifying file name..."; 221 } 222 223 # Make sure it's a fingerprints file... 224 $Name = $NamesAndValues{Name}; 225 if (!$This->IsFingerprintsFPFile($Name)) { 226 croak "Error: ${ClassName}->New: Object can't be instantiated: File, $Name, doesn't appear to be fingerprints format..."; 227 } 228 229 if ($This->GetMode() =~ /^Read$/i) { 230 $This->_InitializeFingerprintsFPFileIOReadProperties(%NamesAndValues); 231 } 232 elsif ($This->GetMode() =~ /^(Write|Append)$/i) { 233 $This->_InitializeFingerprintsFPFileIOWriteProperties(%NamesAndValues); 234 } 235 236 return $This; 237 } 238 239 # Initialize object properties for reading fingerprints FP file... 240 # 241 sub _InitializeFingerprintsFPFileIOReadProperties { 242 my($This, %NamesAndValues) = @_; 243 244 # Set default value for FingerprintsStringMode... 245 if (!$This->{FingerprintsStringMode}) { 246 $This->{FingerprintsStringMode} = 'AutoDetect'; 247 } 248 249 $This->_PrepareForReadingFingerprintsFPFileData(); 250 251 return $This; 252 } 253 254 # Initialize object properties for writing fingerprints FP file... 255 # 256 sub _InitializeFingerprintsFPFileIOWriteProperties { 257 my($This, %NamesAndValues) = @_; 258 259 # Check FingerprintsStringMode value... 260 if (!exists $NamesAndValues{FingerprintsStringMode}) { 261 croak "Error: ${ClassName}->New: Object can't be instantiated without specifying FingerprintsStringMode..."; 262 } 263 264 if ($This->{FingerprintsStringMode} !~ /^(FingerprintsBitVectorString|FingerprintsVectorString)$/i) { 265 croak "Error: ${ClassName}->New: Object can't be instantiated: FingerprintsStringMode value, $This->{FingerprintsStringMode}, is not valid; Supported values for write/append: FingerprintsBitVectorString or FingerprintsVectorString..."; 266 } 267 268 $This->_PrepareForWritingFingerprintsFPFileData(); 269 270 return $This; 271 } 272 273 # Set FingerprintsStringMode... 274 # 275 sub SetFingerprintsStringMode { 276 my($This, $Value) = @_; 277 278 # AutoDetect - automatically detect format of fingerprints string 279 # FingerprintsBitVectorString - Bit vector fingerprints string format 280 # FingerprintsVectorString - Vector fingerprints string format 281 282 if ($Value !~ /^(AutoDetect|FingerprintsBitVectorString|FingerprintsVectorString)$/i) { 283 croak "Error: ${ClassName}->SetFingerprintsStringMode: FingerprintsStringMode value, $Value, is not valid; Supported values: AutoDetect, FingerprintsBitVectorString or FingerprintsVectorString..."; 284 } 285 286 $This->{FingerprintsStringMode} = $Value; 287 288 return $This; 289 } 290 291 # Set DetailLevel... 292 # 293 sub SetDetailLevel { 294 my($This, $Value) = @_; 295 296 if (!TextUtil::IsPositiveInteger($Value)) { 297 croak "Error: ${ClassName}->SetDetailLevel: DetailLevel value, $Value, is not valid; Supported values: > 0..."; 298 } 299 300 $This->{DetailLevel} = $Value; 301 302 return $This; 303 } 304 305 # Set BitStringFormat... 306 # 307 sub SetBitStringFormat { 308 my($This, $Value) = @_; 309 310 if ($Value !~ /^(BinaryString|HexadecimalString)$/i) { 311 croak "Error: ${ClassName}->SetBitStringFormat: BitStringFormat value, $Value, is not valid; Supported values: BinaryString or HexadecimalString..."; 312 } 313 314 $This->{BitStringFormat} = $Value; 315 316 return $This; 317 } 318 319 # Set BitsOrder... 320 # 321 sub SetBitsOrder { 322 my($This, $Value) = @_; 323 324 # Ascending - First bit in each byte as the lowest bit 325 # Descending - First bit in each byte as the highest bit 326 # 327 if ($Value !~ /^(Ascending|Descending)$/i) { 328 croak "Error: ${ClassName}->SetBitsOrder: FingerprintsStringMode value, $Value, is not valid; Supported values: Ascending or Descending..."; 329 } 330 331 $This->{BitsOrder} = $Value; 332 333 return $This; 334 } 335 336 # Set compound ID... 337 # 338 sub SetCompoundID { 339 my($This, $Value) = @_; 340 341 if ($Value =~ / /) { 342 $Value =~ s/ //g; 343 carp "Warning: ${ClassName}->SetCompoundID: Spaces are not allowed in compound ID; They have been removed..."; 344 } 345 346 $This->{CompoundID} = $Value; 347 348 return $This; 349 } 350 351 # Set VectorStringFormat... 352 # 353 sub SetVectorStringFormat { 354 my($This, $Value) = @_; 355 356 # Possible values: IDsAndValuesString, IDsAndValuesPairsString, ValuesAndIDsString, ValuesAndIDsPairsString 357 358 if ($Value !~ /^(IDsAndValuesString|IDsAndValuesPairsString|ValuesAndIDsString|ValuesAndIDsPairsString|ValuesString)$/i) { 359 croak "Error: ${ClassName}->SetVectorStringFormat: FingerprintsStringMode value, $Value, is not valid; Supported values: IDsAndValuesString, IDsAndValuesPairsString, ValuesAndIDsString, ValuesAndIDsPairsString, or ValuesString..."; 360 } 361 362 $This->{VectorStringFormat} = $Value; 363 364 return $This; 365 } 366 367 # Get header data keys or number of header data keys in header data block... 368 # 369 sub GetHeaderDataKeys { 370 my($This) = @_; 371 372 return wantarray ? @{$This->{HeaderDataKeys}} : scalar @{$This->{HeaderDataKeys}}; 373 } 374 375 # Set header data keys... 376 # 377 sub SetHeaderDataKeys { 378 my($This, @Keys) = @_; 379 380 croak "Error: ${ClassName}->SetHeaderDataKeys: Can't set HeaderDataKeys: Not allowed..."; 381 382 return $This; 383 } 384 385 # Get header data keys and values hash... 386 # 387 sub GetHeaderDataKeysAndValues { 388 my($This) = @_; 389 390 return %{$This->{HeaderDataKeysAndValues}}; 391 } 392 393 # Set header data keys and values hash... 394 # 395 sub SetHeaderDataKeysAndValues { 396 my($This, %KeysAndValues) = @_; 397 398 croak "Error: ${ClassName}->SetHeaderDataKeysAndValues: Can't set HeaderDataKeysAndValues: Not allowed..."; 399 400 return $This; 401 } 402 403 # Get required header data keys or number of header data keys in header data block... 404 # 405 sub GetRequiredHeaderDataKeys { 406 my($This) = @_; 407 408 return wantarray ? @{$This->{RequiredHeaderDataKeys}} : scalar @{$This->{RequiredHeaderDataKeys}}; 409 } 410 411 # Set required header data keys... 412 # 413 sub SetRequiredHeaderDataKeys { 414 my($This, @Keys) = @_; 415 416 croak "Error: ${ClassName}->SetRequiredHeaderDataKeys: Can't set RequiredHeaderDataKeys: Not allowed..."; 417 418 return $This; 419 } 420 421 # Get required header data keys and values hash... 422 # 423 sub GetRequiredHeaderDataKeysAndValues { 424 my($This) = @_; 425 426 return %{$This->{RequiredHeaderDataKeysAndValues}}; 427 } 428 429 # Set required header data keys and values hash... 430 # 431 sub SetRequiredHeaderDataKeysAndValues { 432 my($This, %KeysAndValues) = @_; 433 434 croak "Error: ${ClassName}->SetRequiredHeaderDataKeysAndValues: Can't set RequiredHeaderDataKeysAndValues: Not allowed..."; 435 436 return $This; 437 } 438 439 # Get fingerprints object for current data line... 440 # 441 sub GetFingerprints { 442 my($This) = @_; 443 444 return $This->{FingerprintsObject}; 445 } 446 447 # Set fingerprints object for current data line... 448 # 449 sub SetFingerprints { 450 my($This, $FingerprintsObject) = @_; 451 452 $This->{FingerprintsObject} = $FingerprintsObject; 453 454 return $This; 455 } 456 457 # Get fingerprints string for current data line... 458 # 459 sub GetFingerprintsString { 460 my($This) = @_; 461 462 return $This->{FingerprintsString} ? $This->{FingerprintsString} : 'None'; 463 } 464 465 # Set fingerprints string for current data line... 466 # 467 sub SetFingerprintsString { 468 my($This, $FingerprintsString) = @_; 469 470 $This->{FingerprintsString} = $FingerprintsString; 471 472 return $This; 473 } 474 475 # Get partial fingerprints string for current data line... 476 # 477 sub GetPartialFingerprintsString { 478 my($This) = @_; 479 480 return $This->{PartialFingerprintsString} ? $This->{PartialFingerprintsString} : 'None'; 481 } 482 483 # Set partial fingerprints string for current data line... 484 # 485 sub SetPartialFingerprintsString { 486 my($This, $PartialFingerprintsString) = @_; 487 488 $This->{PartialFingerprintsString} = $PartialFingerprintsString; 489 490 return $This; 491 } 492 493 # Does fingerprints FP file contain valid data? 494 # 495 sub IsFingerprintsFileDataValid { 496 my($This) = @_; 497 498 return $This->{ValidFileData} ? 1 : 0; 499 } 500 501 # Does current data line contains valid fingerprints object data? 502 # 503 sub IsFingerprintsDataValid { 504 my($This) = @_; 505 506 return defined $This->{FingerprintsObject} ? 1 : 0; 507 } 508 509 # Check presence of a header data key... 510 # 511 sub IsHeaderDataKeyPresent { 512 my($This, $Key) = @_; 513 my($CannonicalKey); 514 515 $CannonicalKey = lc $Key; 516 517 return exists $This->{CannonicalHeaderDataKeysAndValues}{$CannonicalKey} ? 1 : 0; 518 } 519 520 # Get value of header data key... 521 # 522 sub GetHeaderDataKeyValue { 523 my($This, $Key) = @_; 524 my($CannonicalKey); 525 526 $CannonicalKey = lc $Key; 527 528 return exists $This->{CannonicalHeaderDataKeysAndValues}{$CannonicalKey} ? $This->{CannonicalHeaderDataKeysAndValues}{$CannonicalKey} : undef; 529 } 530 531 # 532 # Read next available fingerprints line, process it and generate appropriate fingerprints 533 # objects... 534 # 535 sub Read { 536 my($This) = @_; 537 538 # Read data line... 539 if (!$This->_ReadDataLine()) { 540 return undef; 541 } 542 543 # No need to process invalid FP file with invalid data... 544 if (!$This->{ValidFileData}) { 545 if ($This->{ValidateData}) { 546 $This->{NumOfLinesWithMissingData} += 1; 547 } 548 return $This; 549 } 550 551 # Perform data validation... 552 if ($This->{ValidateData}) { 553 if (!$This->_ValidateReadDataLine()) { 554 return $This; 555 } 556 } 557 558 # Check again to handle problematic data for non-validated data lines... 559 if (!$This->{FingerprintsString}) { 560 return $This; 561 } 562 563 # Generate fingeprints object... 564 $This->_GenerateFingerprintsObject(); 565 566 # Setup fingerprints compound ID for fingerprints string... 567 $This->_GenerateCompoundID(); 568 569 return $This; 570 } 571 572 # Read next available fingerprints line, process it and generate appropriate fingerprints 573 # objects... 574 # 575 sub Next { 576 my($This) = @_; 577 578 return $This->Read(); 579 } 580 581 # Read fingerprints data line line... 582 # 583 sub _ReadDataLine { 584 my($This) = @_; 585 586 # Initialize data for current line... 587 $This->_InitializeReadDataLine(); 588 589 if ($This->{FirstDataLineIO}) { 590 # Get first data line... 591 $This->_ProcessFirstDataLineRead(); 592 } 593 else { 594 # Get next data line... 595 $This->{LineNum} += 1; 596 $This->{DataLine} = TextUtil::GetTextLine($This->{FileHandle}); 597 } 598 599 # Is it end of file? 600 if (!$This->{DataLine}) { 601 return 0; 602 } 603 604 # Process data line to retrieve compound ID and fingerprints string information... 605 $This->_ProcessDataLineRead(); 606 607 return 1; 608 } 609 610 # Process data line to retrieve compound ID and fingerprints string information... 611 # 612 sub _ProcessDataLineRead { 613 my($This) = @_; 614 my($CompoundID, $PartialFingerprintsString); 615 616 ($CompoundID, $PartialFingerprintsString) = $This->{DataLine} =~ /^(.*?)[ ]+(.*?)$/; 617 618 if (!(defined($CompoundID) && defined($PartialFingerprintsString))) { 619 return $This; 620 } 621 622 $This->{CompoundID} = $CompoundID; 623 $This->{PartialFingerprintsString} = $PartialFingerprintsString; 624 625 # Set up fingerprints string... 626 $This->_GenerateFingerprintsStringFromPartialFingerprintsString(); 627 628 return $This; 629 } 630 631 # Initialize data line for reading... 632 # 633 sub _InitializeReadDataLine { 634 my($This) = @_; 635 636 $This->{CompoundID} = undef; 637 $This->{DataLine} = undef; 638 639 $This->{FingerprintsObject} = undef; 640 641 $This->{FingerprintsString} = undef; 642 $This->{PartialFingerprintsString} = undef; 643 644 return $This; 645 } 646 647 # Validate fingerprints string data line... 648 # 649 sub _ValidateReadDataLine { 650 my($This) = @_; 651 652 # Check for missing data... 653 if (!($This->{CompoundID} && $This->{PartialFingerprintsString})) { 654 # Missing data... 655 $This->{NumOfLinesWithMissingData} += 1; 656 if ($This->{DetailLevel} >= 3) { 657 carp "Warning: ${ClassName}->_ValidateReadDataLine: Data line number $This->{LineNum} contains no fingerprints data: $This->{DataLine}..."; 658 } 659 elsif ($This->{DetailLevel} >= 2) { 660 carp "Warning: ${ClassName}->_ValidateReadDataLine: Data line number $This->{LineNum} contains no fingerprints data..."; 661 } 662 return 0; 663 } 664 665 # Check for invalid data... 666 my($InvalidFingerprintsData); 667 668 $InvalidFingerprintsData = 0; 669 if ($This->{FingerprintsString}) { 670 $InvalidFingerprintsData = Fingerprints::FingerprintsStringUtil::AreFingerprintsStringValuesValid($This->{FingerprintsString}) ? 0 : 1; 671 } 672 else { 673 $InvalidFingerprintsData = 1; 674 } 675 676 if ($InvalidFingerprintsData) { 677 $This->{NumOfLinesWithInvalidData} += 1; 678 if ($This->{DetailLevel} >= 3) { 679 carp "Warning: ${ClassName}->_ValidateReadDataLine: Data line number $This->{LineNum} contains invalid fingerprints data: $This->{DataLine}..."; 680 } 681 elsif ($This->{DetailLevel} >= 2) { 682 carp "Warning: ${ClassName}->_ValidateReadDataLine: Data line number $This->{LineNum} contains invalid fingerprints data..."; 683 } 684 return 0; 685 } 686 687 return 1; 688 } 689 690 # Setup fingerprints compound ID for fingerprints string... 691 sub _GenerateCompoundID { 692 my($This) = @_; 693 694 # Set fingerprints ID... 695 if ($This->{FingerprintsObject}) { 696 $This->{FingerprintsObject}->SetID($This->{CompoundID}); 697 } 698 699 return $This; 700 } 701 702 # Process first read... 703 # 704 sub _ProcessFirstDataLineRead { 705 my($This) = @_; 706 my($Line); 707 708 $This->{FirstDataLineIO} = 0; 709 710 # Skip over header data lines and collect first data line... 711 712 LINE: while ($Line = TextUtil::GetTextLine($This->{FileHandle})) { 713 $This->{LineNum} += 1; 714 715 # Is it a header data line? 716 if ($Line =~ /^#/) { 717 next LINE; 718 } 719 $This->{DataLine} = $Line; 720 last LINE; 721 } 722 723 return $This; 724 } 725 726 # Get ready for reading fingerprints FP file... 727 # 728 sub _PrepareForReadingFingerprintsFPFileData { 729 my($This) = @_; 730 731 # Retrieve FP file data headers information.... 732 $This->_RetrieveFPFileDataHeaders(); 733 734 # Validate header data keys and values information... 735 $This->_ValidateReadHeaderDataKeysAndValues(); 736 737 # Validate fingeprints string mode information... 738 if ($This->{ValidRequiredHeaderDataKeys}) { 739 $This->_ValidateReadFingerprintsStringMode(); 740 } 741 742 # Set status of FP file data... 743 $This->{ValidFileData} = ($This->{ValidRequiredHeaderDataKeys} && $This->{ValidFingerprintsStringMode}) ? 1 : 0; 744 745 return $This; 746 } 747 748 # Retrieve information about fingerprints date header in FP file... 749 # 750 sub _RetrieveFPFileDataHeaders { 751 my($This) = @_; 752 my($FPFile, $Line, $Index, $KeyValuePair, $Key, $Value, $KeyValueDelimiter, $KeyValuePairDelimiter, @LineKeyValuePairs); 753 754 $FPFile = $This->{Name}; 755 756 if (!(-e $FPFile)) { 757 croak "Error: ${ClassName}->_RetrieveFPFileDataHeaders: File, $FPFile, doesn't exist..."; 758 } 759 760 if (!open FPFILE, "$FPFile") { 761 croak "Error: ${ClassName}->_RetrieveFPFileDataHeaders: Couldn't open input FP file $FPFile: $! ..."; 762 } 763 764 # Process header key/value pair data... 765 # 766 $KeyValueDelimiter = '='; 767 $KeyValuePairDelimiter = ';'; 768 769 @{$This->{HeaderDataKeys}} = (); 770 %{$This->{HeaderDataKeysAndValues}} = (); 771 %{$This->{CannonicalHeaderDataKeysAndValues}} = (); 772 773 LINE: while ($Line = TextUtil::GetTextLine(\*FPFILE)) { 774 # Is it a key/value pairs line? 775 if ($Line !~ /^#/) { 776 last LINE; 777 } 778 779 # Take out starting hash mark before processing key/value pairs... 780 $Line =~ s/^#//; 781 if (TextUtil::IsEmpty($Line)) { 782 next LINE; 783 } 784 785 @LineKeyValuePairs = (); 786 787 for $KeyValuePair (split "$KeyValuePairDelimiter", $Line) { 788 ($Key, $Value) = split "$KeyValueDelimiter", $KeyValuePair; 789 790 $Key = defined($Key) ? TextUtil::RemoveLeadingAndTrailingWhiteSpaces($Key) : ''; 791 $Value = defined($Value) ? TextUtil::RemoveLeadingAndTrailingWhiteSpaces($Value) : ''; 792 793 if (TextUtil::IsEmpty($Key) || TextUtil::IsEmpty($Value)) { 794 carp "Warning: ${ClassName}->_RetrieveFPFileDataHeaders: Data header line containing \"Key = Value\" pairs is not valid: It must contain even number of \"Key = Value\" pairs with valid values. Ignoring data header line: \"$Line\"..."; 795 next LINE; 796 } 797 push @{$This->{HeaderDataKeys}}, $Key; 798 push @LineKeyValuePairs, ($Key, $Value); 799 } 800 801 for ($Index = 0; $Index < $#LineKeyValuePairs; $Index += 2) { 802 $Key = $LineKeyValuePairs[$Index]; $Value = $LineKeyValuePairs[$Index + 1]; 803 804 $This->{HeaderDataKeysAndValues}{$Key} = $Value; 805 $This->{CannonicalHeaderDataKeysAndValues}{lc($Key)} = $Value; 806 } 807 } 808 close FPFILE; 809 810 return $This; 811 } 812 813 # Validate header data and keys... 814 # 815 sub _ValidateReadHeaderDataKeysAndValues { 816 my($This) = @_; 817 my($FingerprintsStringType, $Key, $Value, @RequiredHeaderDataKeys); 818 819 $This->{ValidRequiredHeaderDataKeys} = 0; 820 @{$This->{RequiredHeaderDataKeys}} = (); 821 822 # Is FingerprintsStringType key is present? 823 if (!$This->IsHeaderDataKeyPresent('FingerprintsStringType')) { 824 carp "carp: ${ClassName}->_ValidateReadHeaderDataKeysAndValues: FingerprintsStringType data header key is missing in fingerprints file..."; 825 return 0; 826 } 827 $FingerprintsStringType = $This->GetHeaderDataKeyValue('FingerprintsStringType'); 828 829 # Are all required data header keys present? 830 # 831 @RequiredHeaderDataKeys = (); 832 833 if ($FingerprintsStringType =~ /^(FingerprintsBitVector|FingerprintsVector)$/i) { 834 push @RequiredHeaderDataKeys, $This->_GetRequiredHeaderDataKeys($FingerprintsStringType); 835 } 836 else { 837 carp "Warning: ${ClassName}->_ValidateReadHeaderDataKeysAndValues: FingerprintsStringType data header key value, $FingerprintsStringType, is not valid. SUpported values: FingerprintsBitVector or FingerprintsVector..."; 838 return 0; 839 } 840 841 for $Key (@RequiredHeaderDataKeys) { 842 if (!$This->IsHeaderDataKeyPresent($Key)) { 843 croak "Error: ${ClassName}->_ValidateReadHeaderDataKeysAndValues: Requires data header key, $Key, is missing in fingerprints file..."; 844 } 845 } 846 847 push @{$This->{RequiredHeaderDataKeys}}, @RequiredHeaderDataKeys; 848 849 # Are all required data header key values valid? 850 # 851 if (!$This->_ValidateRequiredHeaderDataKeyValues()) { 852 return 0; 853 } 854 855 # Process required header key values... 856 # 857 $This->_ProcessRequiredHeaderDataKeyValues(); 858 859 $This->{ValidRequiredHeaderDataKeys} = 1; 860 861 return 1; 862 } 863 864 # Validate data header key values.... 865 # 866 sub _ValidateRequiredHeaderDataKeyValues { 867 my($This) = @_; 868 my($Key, $Value); 869 870 for $Key (@{$This->{RequiredHeaderDataKeys}}) { 871 $Value = $This->GetHeaderDataKeyValue($Key); 872 KEY: { 873 if ($Key =~ /^FingerprintsStringType$/i) { 874 if ($Value !~ /^(FingerprintsBitVector|FingerprintsVector)$/i) { 875 carp "Warning: ${ClassName}->_ValidateRequiredHeaderDataKeyValues: Required $Key data header key value, $Value, is not valid. Supported values: FingerprintsBitVector or FingerprintsVector..."; 876 return 0; 877 } 878 last KEY; 879 } 880 if ($Key =~ /^Size$/i) { 881 if (!TextUtil::IsPositiveInteger($Value)) { 882 carp "Warning: ${ClassName}->_ValidateRequiredHeaderDataKeyValues: Required $Key data header key value, $Value, is not valid. Supported values: > 0..."; 883 return 0; 884 } 885 last KEY; 886 } 887 if ($Key =~ /^BitStringFormat$/i) { 888 if ($Value !~ /^(BinaryString|HexadecimalString)$/i) { 889 carp "Warning: ${ClassName}->_ValidateRequiredHeaderDataKeyValues: Required $Key data header key value, $Value, is not valid. Supported values: BinaryString or HexadecimalString ..."; 890 return 0; 891 } 892 last KEY; 893 } 894 if ($Key =~ /^BitsOrder$/i) { 895 if ($Value !~ /^(Ascending|Descending)$/i) { 896 carp "Warning: ${ClassName}->_ValidateRequiredHeaderDataKeyValues: Required $Key data header key value, $Value, is not valid. Supported values: Ascending or Descending..."; 897 return 0; 898 } 899 last KEY; 900 } 901 if ($Key =~ /^VectorStringFormat$/i) { 902 if ($Value !~ /^(IDsAndValuesString|IDsAndValuesPairsString|ValuesAndIDsString|ValuesAndIDsPairsString|ValuesString)$/i) { 903 carp "Warning: ${ClassName}->_ValidateRequiredHeaderDataKeyValues: Required $Key data header key value, $Value, is not valid. Supported values: IDsAndValuesString, IDsAndValuesPairsString, ValuesAndIDsString, ValuesAndIDsPairsString, or ValuesString ..."; 904 return 0; 905 } 906 last KEY; 907 } 908 if ($Key =~ /^VectorValuesType$/i) { 909 if ($Value !~ /^(OrderedNumericalValues|NumericalValues|AlphaNumericalValues)$/i) { 910 carp "Warning: ${ClassName}->_ValidateRequiredHeaderDataKeyValues: Required $Key data header key value, $Value, is not valid. Supported values: OrderedNumericalValues, NumericalValues or AlphaNumericalValues..."; 911 return 0; 912 } 913 last KEY; 914 } 915 if ($Key =~ /^Description$/i) { 916 if (TextUtil::IsEmpty($Value)) { 917 carp "Warning: ${ClassName}->_ValidateRequiredHeaderDataKeyValues: Required $Key data header key value is not valid. Supported value: A no-empty text string..."; 918 return 0; 919 } 920 last KEY; 921 } 922 carp "Warning: ${ClassName}->_ValidateRequiredHeaderDataKeyValues: Required $Key data header key is not not supported..."; 923 return 0; 924 } 925 } 926 927 return 1; 928 } 929 930 # Process required header key valeues for access during complete fingerprints 931 # string generation from a partial fingerprints string specified on fingerprints 932 # line... 933 # 934 sub _ProcessRequiredHeaderDataKeyValues { 935 my($This) = @_; 936 my($Key, $Value, @Keys); 937 938 %{$This->{RequiredHeaderDataKeysAndValues}} = (); 939 940 for $Key (@{$This->{RequiredHeaderDataKeys}}) { 941 $Value = $This->GetHeaderDataKeyValue($Key); 942 $This->{RequiredHeaderDataKeysAndValues}{$Key} = $Value; 943 } 944 945 # Setup prefixes for generating fingerprints strings... 946 $This->{FingerprintsBitVectorStringPrefix} = ''; 947 $This->{FingerprintsVectorStringPrefix1} = ''; 948 $This->{FingerprintsVectorStringPrefix2} = ''; 949 950 if ($This->{RequiredHeaderDataKeysAndValues}{FingerprintsStringType} =~ /^FingerprintsBitVector$/i) { 951 @Keys = qw(FingerprintsStringType Description Size BitStringFormat BitsOrder); 952 $This->{FingerprintsBitVectorStringPrefix} = $This->_GenerateFingerprintsPrefixUsingKeys(@Keys); 953 } 954 elsif ($This->{RequiredHeaderDataKeysAndValues}{FingerprintsStringType} =~ /^FingerprintsVector$/i) { 955 @Keys = qw(FingerprintsStringType Description); 956 $This->{FingerprintsVectorStringPrefix1} = $This->_GenerateFingerprintsPrefixUsingKeys(@Keys); 957 958 @Keys = qw(VectorValuesType VectorStringFormat); 959 $This->{FingerprintsVectorStringPrefix2} = $This->_GenerateFingerprintsPrefixUsingKeys(@Keys); 960 } 961 962 return $This; 963 } 964 965 # Generate fingerprints prefix using header keys data... 966 # 967 sub _GenerateFingerprintsPrefixUsingKeys { 968 my($This, @Keys) = @_; 969 my($Delimiter, $Key, @Values); 970 971 $Delimiter = Fingerprints::FingerprintsStringUtil::GetFingeprintsStringDelimiter(); 972 973 @Values = (); 974 for $Key (@Keys) { 975 push @Values, $This->{RequiredHeaderDataKeysAndValues}{$Key}; 976 } 977 978 return join($Delimiter, @Values) 979 } 980 981 # Get required header data keys... 982 # 983 sub _GetRequiredHeaderDataKeys { 984 my($This, $FingerprintsStringType) = @_; 985 my(@RequiredKeys); 986 987 @RequiredKeys = (); 988 989 if ($FingerprintsStringType =~ /FingerprintsBitVector$/i) { 990 push @RequiredKeys, qw(FingerprintsStringType Description Size BitStringFormat BitsOrder); 991 } 992 elsif ($FingerprintsStringType =~ /^FingerprintsVector/i) { 993 push @RequiredKeys, qw(FingerprintsStringType Description VectorStringFormat VectorValuesType); 994 } 995 else { 996 carp "Warning: ${ClassName}->GetRequiredHeaderDataKeys: FingerprintsStringType value, $FingerprintsStringType, is not valid. Supported values: FingerprintsBitVector or FingerprintsVector..."; 997 } 998 999 return @RequiredKeys; 1000 } 1001 1002 # Validate fingerprints string mode information... 1003 # 1004 sub _ValidateReadFingerprintsStringMode { 1005 my($This) = @_; 1006 my($FingerprintsStringType, $FingerprintsStringDescription, $FingerprintsBitVectorStringMode, $FingerprintsVectorStringMode, $FirstFingerprintsStringType, $FirstFingerprintsStringDescription); 1007 1008 $This->{ValidFingerprintsStringMode} = 0; 1009 $This->{FingerprintsBitVectorStringMode} = 0; 1010 $This->{FingerprintsVectorStringMode} = 0; 1011 1012 $This->{FirstFingerprintsStringType} = ''; 1013 $This->{FirstFingerprintsStringDescription} = ''; 1014 1015 $FingerprintsBitVectorStringMode = 0; 1016 $FingerprintsVectorStringMode = 0; 1017 1018 $FirstFingerprintsStringType = ''; 1019 $FirstFingerprintsStringDescription = ''; 1020 1021 $FingerprintsStringType = $This->GetHeaderDataKeyValue('FingerprintsStringType'); 1022 $FingerprintsStringDescription = $This->GetHeaderDataKeyValue('Description'); 1023 1024 if ($This->{FingerprintsStringMode} =~ /^FingerprintsBitVectorString$/i) { 1025 if ($FingerprintsStringType !~ /^FingerprintsBitVector$/i) { 1026 carp "Warning: ${ClassName}->_ValidateReadFingerprintsStringMode: Fingerprints string data type, $FingerprintsStringType, doesn't correspond to, FingerprintsBitVectorString, specified using \"FingerprintsStringMode\"..."; 1027 return 0; 1028 } 1029 $FingerprintsBitVectorStringMode = 1; 1030 $FirstFingerprintsStringType = 'FingerprintsBitVector'; 1031 $FirstFingerprintsStringDescription = $FingerprintsStringDescription; 1032 } 1033 elsif ($This->{FingerprintsStringMode} =~ /^FingerprintsVectorString$/i) { 1034 if ($FingerprintsStringType !~ /^FingerprintsVector$/i) { 1035 carp "Warning: ${ClassName}->_ValidateReadFingerprintsStringMode: Fingerprints string data type, $FingerprintsStringType, doesn't correspond to, FingerprintsVectorString, specified using \"FingerprintsStringMode\"..."; 1036 return 0; 1037 } 1038 $FingerprintsVectorStringMode = 1; 1039 $FirstFingerprintsStringType = 'FingerprintsVector'; 1040 $FirstFingerprintsStringDescription = $FingerprintsStringDescription; 1041 } 1042 else { 1043 # AutoDetect mode... 1044 if ($FingerprintsStringType =~ /^FingerprintsBitVector$/i) { 1045 $FingerprintsBitVectorStringMode = 1; 1046 } 1047 elsif ($FingerprintsStringType =~ /^FingerprintsVector$/i) { 1048 $FingerprintsVectorStringMode = 1; 1049 } 1050 else { 1051 carp "Warning: ${ClassName}->_ValidateReadFingerprintsStringMode: Fingerprints string data type, $FingerprintsStringType, identified during, AutoDetect, value of \"FingerprintsStringMode\" is not valid; Supported fingerprints types: FingerprintBitVector or FingerprintsVector..."; 1052 return 0; 1053 } 1054 $FirstFingerprintsStringType = $FingerprintsStringType; 1055 $FirstFingerprintsStringDescription = $FingerprintsStringDescription; 1056 } 1057 1058 $This->{ValidFingerprintsStringMode} = 1; 1059 1060 $This->{FingerprintsBitVectorStringMode} = $FingerprintsBitVectorStringMode; 1061 $This->{FingerprintsVectorStringMode} = $FingerprintsVectorStringMode; 1062 1063 $This->{FirstFingerprintsStringType} = $FirstFingerprintsStringType; 1064 $This->{FirstFingerprintsStringDescription} = $FirstFingerprintsStringDescription; 1065 1066 return 1; 1067 } 1068 1069 # Write fingerprints string generated from specified fingerprints - fingerprints-bit vector or 1070 # fingerprints vector - object and other data to FP file... 1071 # 1072 sub WriteFingerprints { 1073 my($This, $FingerprintsObject, $CompoundID) = @_; 1074 1075 # Initialize data for current line... 1076 $This->_InitializeWriteDataLine(); 1077 1078 # Set fingerprints object and compound ID... 1079 $This->{FingerprintsObject} = $FingerprintsObject; 1080 $This->SetCompoundID($CompoundID); 1081 1082 # Generate fingerprints string... 1083 $This->_GenerateFingerprintsString(); 1084 1085 # Generate partial fingerprints string... 1086 $This->_GeneratePartialFingerprintsStringFromFingerprintsString(); 1087 1088 # Write data line.. 1089 $This->_WriteDataLine(); 1090 1091 return $This; 1092 } 1093 1094 # Write fingerprints string and other data to FP file... 1095 # 1096 # Notes: 1097 # o FingerprintsStringMode, BitStringFormat, BitsOrder, VectorStringFormat values 1098 # are ignored during writing of fingerprints and it's written to the file as it is. 1099 # o FingerprintsString is a regular fingerprints string as oppose to a partial fingerprints 1100 # string. 1101 # 1102 sub WriteFingerprintsString { 1103 my($This, $FingerprintsString, $CompoundID) = @_; 1104 1105 # Initialize data for current line... 1106 $This->_InitializeWriteDataLine(); 1107 1108 # Set fingerprints string and compound ID... 1109 $This->{FingerprintsString} = $FingerprintsString; 1110 $This->SetCompoundID($CompoundID); 1111 1112 # Generate fingerprints object... 1113 $This->_GenerateFingerprintsObject(); 1114 1115 # Generate partial fingerprints string... 1116 $This->_GeneratePartialFingerprintsStringFromFingerprintsString(); 1117 1118 # Write data line.. 1119 $This->_WriteDataLine(); 1120 1121 return $This; 1122 } 1123 1124 # Initialize data line for reading... 1125 # 1126 sub _InitializeWriteDataLine { 1127 my($This) = @_; 1128 1129 $This->{DataLine} = undef; 1130 $This->{CompoundID} = undef; 1131 1132 $This->{FingerprintsObject} = undef; 1133 1134 $This->{FingerprintsString} = undef; 1135 $This->{PartialFingerprintsString} = undef; 1136 1137 return $This; 1138 } 1139 1140 # Write fingerprints data line line... 1141 # 1142 sub _WriteDataLine { 1143 my($This) = @_; 1144 my($FileHandle, $Line); 1145 1146 if ($This->{FirstDataLineIO}) { 1147 $This->_ProcessFirstDataLineWrite(); 1148 } 1149 1150 # Write data compound ID along with partial fingerprints string... 1151 $Line = $This->{CompoundID} . ' ' . $This->{PartialFingerprintsString}; 1152 1153 $This->{LineNum} += 1; 1154 $FileHandle = $This->{FileHandle}; 1155 print $FileHandle "$Line\n"; 1156 1157 $This->{DataLine} = $Line; 1158 1159 return $This; 1160 } 1161 1162 # Process first write... 1163 # 1164 sub _ProcessFirstDataLineWrite { 1165 my($This) = @_; 1166 my($Line, $FileHandle); 1167 1168 $This->{FirstDataLineIO} = 0; 1169 1170 if ($This->GetMode() =~ /^Write$/i) { 1171 # Skip it for append mode... 1172 $This->_WritePackageAndTimeStampHeaderKeys(); 1173 $This->_WriteRequiredHeaderDataKeys(); 1174 } 1175 1176 return $This; 1177 } 1178 1179 # Write out package and time stamp information... 1180 # 1181 sub _WritePackageAndTimeStampHeaderKeys { 1182 my($This) = @_; 1183 my($FileHandle, $Key, $Value); 1184 1185 $FileHandle = $This->{FileHandle}; 1186 1187 # Package information... 1188 $This->{LineNum} += 1; 1189 $Key = "Package"; $Value = PackageInfo::GetPackageName() . " " . PackageInfo::GetVersionNumber(); 1190 print $FileHandle "# $Key = $Value\n"; 1191 1192 $This->{LineNum} += 1; 1193 $Key = "Release Date"; $Value = PackageInfo::GetReleaseDate(); 1194 print $FileHandle "# $Key = $Value\n"; 1195 1196 # Timestamp information... 1197 $This->{LineNum} += 1; 1198 print $FileHandle "#\n"; 1199 1200 $This->{LineNum} += 1; 1201 $Key = "TimeStamp"; $Value = TimeUtil::FPFileTimeStamp(); 1202 print $FileHandle "# $Key = $Value\n"; 1203 1204 return $This; 1205 } 1206 1207 # Write out required header data keys... 1208 # 1209 sub _WriteRequiredHeaderDataKeys { 1210 my($This) = @_; 1211 my($FileHandle, $Key, $Value); 1212 1213 $FileHandle = $This->{FileHandle}; 1214 1215 $This->_GenerateWriteRequiredHeaderDataKeys(); 1216 1217 $This->{LineNum} += 1; 1218 print $FileHandle "#\n"; 1219 1220 for $Key (@{$This->{RequiredHeaderDataKeys}}) { 1221 $Value = $This->{RequiredHeaderDataKeysAndValues}{$Key}; 1222 1223 $This->{LineNum} += 1; 1224 print $FileHandle "# $Key = $Value\n"; 1225 1226 if ($Key =~ /^FingerprintsStringType$/i) { 1227 $This->{LineNum} += 1; 1228 print $FileHandle "#\n"; 1229 } 1230 } 1231 1232 $This->{LineNum} += 1; 1233 print $FileHandle "#\n"; 1234 1235 return $This; 1236 } 1237 1238 sub _GenerateWriteRequiredHeaderDataKeys { 1239 my($This) = @_; 1240 1241 if ($This->{FingerprintsBitVectorStringMode} && ($This->{FingerprintsString} =~ /^FingerprintsBitVector/i)) { 1242 $This->_GenerateWriteRequiredHeaderDataKeysForBitVectorString(); 1243 } 1244 elsif ($This->{FingerprintsVectorStringMode} && ($This->{FingerprintsString} =~ /^FingerprintsVector/i)) { 1245 $This->_GenerateWriteRequiredHeaderDataKeysForVectorString(); 1246 } 1247 else { 1248 croak "Error: ${ClassName}->_GenerateWriteRequiredHeaderDataKeys: Required header data keys can't be generated: FingerprintsStringMode value, $This->{FingerprintsStringMode}, doesn't correspond to type of first FingerprintsString: $This->{FingerprintsString}..."; 1249 } 1250 1251 return $This; 1252 } 1253 1254 # Generate required data header keys and values for writing fingerprints bit vector string... 1255 # 1256 sub _GenerateWriteRequiredHeaderDataKeysForBitVectorString { 1257 my($This) = @_; 1258 my($Key, $VectorType, $Description, $Size, $BitStringFormat, $BitsOrder); 1259 1260 @{$This->{RequiredHeaderDataKeys}} = (); 1261 push @{$This->{RequiredHeaderDataKeys}}, $This->_GetRequiredHeaderDataKeys('FingerprintsBitVector'); 1262 1263 ($VectorType, $Description, $Size, $BitStringFormat, $BitsOrder) = Fingerprints::FingerprintsStringUtil::GetFingerprintsStringValues($This->{FingerprintsString}); 1264 1265 %{$This->{RequiredHeaderDataKeysAndValues}} = (); 1266 1267 for $Key (@{$This->{RequiredHeaderDataKeys}}) { 1268 KEYTYPE: { 1269 if ($Key =~ /^FingerprintsStringType$/i) { 1270 $This->{RequiredHeaderDataKeysAndValues}{$Key} = $VectorType; 1271 last KEYTYPE; 1272 } 1273 if ($Key =~ /^Description$/i) { 1274 $This->{RequiredHeaderDataKeysAndValues}{$Key} = $Description; 1275 last KEYTYPE; 1276 } 1277 if ($Key =~ /^Size$/i) { 1278 $This->{RequiredHeaderDataKeysAndValues}{$Key} = $Size; 1279 last KEYTYPE; 1280 } 1281 if ($Key =~ /^BitStringFormat$/i) { 1282 $This->{RequiredHeaderDataKeysAndValues}{$Key} = $BitStringFormat; 1283 last KEYTYPE; 1284 } 1285 if ($Key =~ /^BitsOrder$/i) { 1286 $This->{RequiredHeaderDataKeysAndValues}{$Key} = $BitsOrder; 1287 last KEYTYPE; 1288 } 1289 croak "Error: ${ClassName}->_GenerateWriteRequiredHeaderDataKeysForBitVectorString: Required header data key, $Key, value can't be generated: It's not a known key ..."; 1290 } 1291 } 1292 1293 return $This; 1294 } 1295 1296 # Generate required data header keys and values for writing fingerprints vector string... 1297 # 1298 sub _GenerateWriteRequiredHeaderDataKeysForVectorString { 1299 my($This) = @_; 1300 my($Key, $Value, $VectorType, $Description, $NumOfValues, $VectorValuesType, $VectorStringFormat); 1301 1302 @{$This->{RequiredHeaderDataKeys}} = (); 1303 push @{$This->{RequiredHeaderDataKeys}}, $This->_GetRequiredHeaderDataKeys('FingerprintsVector'); 1304 1305 ($VectorType, $Description, $NumOfValues, $VectorValuesType, $VectorStringFormat) = Fingerprints::FingerprintsStringUtil::GetFingerprintsStringValues($This->{FingerprintsString}); 1306 1307 %{$This->{RequiredHeaderDataKeysAndValues}} = (); 1308 1309 for $Key (@{$This->{RequiredHeaderDataKeys}}) { 1310 KEYTYPE: { 1311 if ($Key =~ /^FingerprintsStringType$/i) { 1312 $This->{RequiredHeaderDataKeysAndValues}{$Key} = $VectorType; 1313 last KEYTYPE; 1314 } 1315 if ($Key =~ /^Description$/i) { 1316 $This->{RequiredHeaderDataKeysAndValues}{$Key} = $Description; 1317 last KEYTYPE; 1318 } 1319 if ($Key =~ /^VectorValuesType$/i) { 1320 $This->{RequiredHeaderDataKeysAndValues}{$Key} = $VectorValuesType; 1321 last KEYTYPE; 1322 } 1323 if ($Key =~ /^VectorStringFormat$/i) { 1324 $This->{RequiredHeaderDataKeysAndValues}{$Key} = $VectorStringFormat; 1325 last KEYTYPE; 1326 } 1327 croak "Error: ${ClassName}->_GenerateWriteRequiredHeaderDataKeysForVectorString: Required header data key, $Key, value can't be generated: It's not a known key ..."; 1328 } 1329 } 1330 1331 return $This; 1332 } 1333 1334 1335 # Get ready for writing fingerprints FP file... 1336 # 1337 sub _PrepareForWritingFingerprintsFPFileData { 1338 my($This) = @_; 1339 my($FPFile, $FileDir, $FileName, $FileExt, $OutDelim); 1340 1341 $FPFile = $This->{Name}; 1342 if (!$This->{Overwrite}) { 1343 if (-e $FPFile) { 1344 croak "Error: ${ClassName}->_PrepareForWritingFingerprintsFPFileData: File, $FPFile, already exist. Use overwrite option..."; 1345 } 1346 } 1347 1348 # Setup FingerprintsStringMode status... 1349 # 1350 $This->{FingerprintsBitVectorStringMode} = 0; 1351 $This->{FingerprintsVectorStringMode} = 0; 1352 $This->{ValidFingerprintsStringMode} = 0; 1353 1354 if ($This->{FingerprintsStringMode} =~ /^FingerprintsBitVectorString$/i) { 1355 $This->{FingerprintsBitVectorStringMode} = 1; 1356 } 1357 elsif ($This->{FingerprintsStringMode} =~ /^FingerprintsVectorString$/i) { 1358 $This->{FingerprintsVectorStringMode} = 1; 1359 } 1360 1361 $This->{ValidFingerprintsStringMode} = ($This->{FingerprintsBitVectorStringMode} || $This->{FingerprintsVectorStringMode}) ? 1 : 0; 1362 1363 if ($This->{FingerprintsBitVectorStringMode}) { 1364 $This->_SetDefaultBitStringFormat(); 1365 $This->_SetDefaultBitsOrder(); 1366 } 1367 elsif ($This->{FingerprintsVectorStringMode}) { 1368 $This->_SetDefaultVectorStringFormat(); 1369 } 1370 1371 return $This; 1372 } 1373 1374 # Set default value for bit string format... 1375 # 1376 sub _SetDefaultBitStringFormat { 1377 my($This) = @_; 1378 1379 if (!$This->{BitStringFormat}) { 1380 $This->{BitStringFormat} = Fingerprints::FingerprintsStringUtil::GetDefaultBitStringFormat(); 1381 } 1382 1383 return $This; 1384 } 1385 1386 # Set default value for bit string format... 1387 # 1388 sub _SetDefaultBitsOrder { 1389 my($This) = @_; 1390 1391 if (!$This->{BitsOrder}) { 1392 $This->{BitsOrder} = Fingerprints::FingerprintsStringUtil::GetDefaultBitsOrder(); 1393 } 1394 1395 return $This; 1396 } 1397 1398 # Set default value for vector string format... 1399 # 1400 sub _SetDefaultVectorStringFormat { 1401 my($This) = @_; 1402 1403 if (!$This->{VectorStringFormat} && $This->{FingerprintsObject}) { 1404 $This->{VectorStringFormat} = Fingerprints::FingerprintsStringUtil::GetDefaultVectorStringFormat($This->{FingerprintsObject}); 1405 } 1406 1407 return $This; 1408 } 1409 1410 # Generate fingerprints object using current fingerprints string... 1411 # 1412 sub _GenerateFingerprintsObject { 1413 my($This) = @_; 1414 1415 $This->{FingerprintsObject} = undef; 1416 1417 if (!$This->{FingerprintsString}) { 1418 return $This; 1419 } 1420 1421 if ($This->{FingerprintsBitVectorStringMode}) { 1422 $This->{FingerprintsObject} = Fingerprints::FingerprintsStringUtil::ParseFingerprintsBitVectorString($This->{FingerprintsString}); 1423 } 1424 elsif ($This->{FingerprintsVectorStringMode}) { 1425 $This->{FingerprintsObject} = Fingerprints::FingerprintsStringUtil::ParseFingerprintsVectorString($This->{FingerprintsString}); 1426 } 1427 else { 1428 return undef; 1429 } 1430 1431 return $This; 1432 } 1433 1434 # Generate fingerprints string using current fingerprints object... 1435 # 1436 sub _GenerateFingerprintsString { 1437 my($This) = @_; 1438 1439 $This->{FingerprintsString} = ''; 1440 1441 if (!$This->{FingerprintsObject}) { 1442 return $This; 1443 } 1444 1445 if ($This->{FingerprintsBitVectorStringMode}) { 1446 $This->{FingerprintsString} = Fingerprints::FingerprintsStringUtil::GenerateFingerprintsString($This->{FingerprintsObject}, $This->{BitStringFormat}, $This->{BitsOrder}); 1447 } 1448 elsif ($This->{FingerprintsVectorStringMode}) { 1449 $This->{FingerprintsString} = Fingerprints::FingerprintsStringUtil::GenerateFingerprintsString($This->{FingerprintsObject}, $This->{VectorStringFormat}); 1450 } 1451 1452 return $This; 1453 } 1454 1455 # Generate fingerprints string using partial fingerprints string and header keys data... 1456 # 1457 # Notes: 1458 # o FP file fingerprints data line only contain partial fingerprints data which 1459 # can't be used directly to create fingerprints bit-vector or vector objects 1460 # using functions available in FingerprintsStringUtil.pm module 1461 # 1462 sub _GenerateFingerprintsStringFromPartialFingerprintsString { 1463 my($This) = @_; 1464 my($FPStringDelim); 1465 1466 $This->{FingerprintsString} = ''; 1467 1468 if (!$This->{PartialFingerprintsString}) { 1469 return $This; 1470 } 1471 1472 $FPStringDelim = Fingerprints::FingerprintsStringUtil::GetFingeprintsStringDelimiter(); 1473 1474 if ($This->{FingerprintsBitVectorStringMode}) { 1475 $This->{FingerprintsString} = $This->{FingerprintsBitVectorStringPrefix} . $FPStringDelim . $This->{PartialFingerprintsString}; 1476 } 1477 elsif ($This->{FingerprintsVectorStringMode}) { 1478 my($NumOfValues, $VectorStringData); 1479 1480 ($NumOfValues, $VectorStringData) = $This->{PartialFingerprintsString} =~ /^(.*?)$FPStringDelim(.*?)$/; 1481 if (!(defined($NumOfValues) && defined($VectorStringData) && $VectorStringData)) { 1482 return $This; 1483 } 1484 1485 $This->{FingerprintsString} = $This->{FingerprintsVectorStringPrefix1} . $FPStringDelim . $NumOfValues . $FPStringDelim . $This->{FingerprintsVectorStringPrefix2} . $FPStringDelim . $VectorStringData; 1486 } 1487 1488 return $This; 1489 } 1490 1491 # Generate partial fingerprints string using fingerprints string and header keys data... 1492 # 1493 # Notes: 1494 # o FP file fingerprints data line only contain partial fingerprints data which 1495 # can't be used directly to create fingerprints bit-vector or vector objects 1496 # using functions available in FingerprintsStringUtil.pm module 1497 # 1498 sub _GeneratePartialFingerprintsStringFromFingerprintsString { 1499 my($This) = @_; 1500 1501 $This->{PartialFingerprintsString} = ''; 1502 1503 if (!$This->{FingerprintsString}) { 1504 return $This; 1505 } 1506 1507 if ($This->{FingerprintsBitVectorStringMode}) { 1508 my($VectorType, $Description, $Size, $BitStringFormat, $BitsOrder, $BitVectorString); 1509 1510 ($VectorType, $Description, $Size, $BitStringFormat, $BitsOrder, $BitVectorString) = Fingerprints::FingerprintsStringUtil::GetFingerprintsStringValues($This->{FingerprintsString}); 1511 $This->{PartialFingerprintsString} = $BitVectorString; 1512 } 1513 elsif ($This->{FingerprintsVectorStringMode}) { 1514 my($FPStringDelim, $VectorType, $Description, $NumOfValues, $VectorValuesType, $VectorStringFormat, $VectorString1, $VectorString2, $VectorString); 1515 1516 $FPStringDelim = Fingerprints::FingerprintsStringUtil::GetFingeprintsStringDelimiter(); 1517 1518 ($VectorType, $Description, $NumOfValues, $VectorValuesType, $VectorStringFormat, $VectorString1, $VectorString2) = Fingerprints::FingerprintsStringUtil::GetFingerprintsStringValues($This->{FingerprintsString}); 1519 $VectorString = TextUtil::IsEmpty($VectorString2) ? $VectorString1 : "${VectorString1}${FPStringDelim}${VectorString2}"; 1520 1521 $This->{PartialFingerprintsString} = $NumOfValues . $FPStringDelim . $VectorString; 1522 } 1523 1524 return $This; 1525 } 1526 1527 # Is it a fingerprints file? 1528 sub IsFingerprintsFPFile ($;$) { 1529 my($FirstParameter, $SecondParameter) = @_; 1530 my($This, $FileName, $Status); 1531 1532 if ((@_ == 2) && (_IsFingerprintsFPFileIO($FirstParameter))) { 1533 ($This, $FileName) = ($FirstParameter, $SecondParameter); 1534 } 1535 else { 1536 $FileName = $FirstParameter; 1537 } 1538 1539 # Check file extension... 1540 $Status = FileUtil::CheckFileType($FileName, "fpf fp"); 1541 1542 return $Status; 1543 } 1544 1545 # Is it a FingerprintsFPFileIO object? 1546 sub _IsFingerprintsFPFileIO { 1547 my($Object) = @_; 1548 1549 return (Scalar::Util::blessed($Object) && $Object->isa($ClassName)) ? 1 : 0; 1550 } 1551