Changeset 53 for trunk/UContact.pas
- Timestamp:
- Dec 8, 2021, 2:02:17 PM (3 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/UContact.pas
r52 r53 98 98 constructor Create; 99 99 destructor Destroy; override; 100 procedure SaveToStrings(Output: TStrings); 101 function LoadFromStrings(Lines: TStrings; StartLine: Integer = 0): Integer; 102 procedure SaveToFile(FileName: string); 103 procedure LoadFromFile(FileName: string); 100 104 property Fields[Index: TContactFieldIndex]: string read GetField write SetField; 101 105 end; … … 132 136 end; 133 137 138 const 139 VCardFileExt = '.vcf'; 140 134 141 135 142 implementation … … 144 151 SFieldIndexNotDefined = 'Field index not defined'; 145 152 SContactHasNoParent = 'Contact has no parent'; 153 SExpectedProperty = 'Expected contact property'; 146 154 SLastName = 'Last Name'; 147 155 SFirstName = 'First Name'; … … 593 601 FreeAndNil(Properties); 594 602 inherited; 603 end; 604 605 procedure TContact.SaveToStrings(Output: TStrings); 606 var 607 I: Integer; 608 J: Integer; 609 NameText: string; 610 Value2: string; 611 Text: string; 612 LineIndex: Integer; 613 OutText: string; 614 LinePrefix: string; 615 const 616 MaxLineLength = 73; 617 begin 618 with Output do begin 619 Add('BEGIN:VCARD'); 620 for J := 0 to Properties.Count - 1 do 621 with Properties[J] do begin 622 NameText := Name; 623 if Attributes.Count > 0 then 624 NameText := NameText + ';' + Attributes.DelimitedText; 625 if Encoding <> '' then begin 626 Value2 := GetEncodedValue; 627 NameText := NameText + ';ENCODING=' + Encoding; 628 end else Value2 := Value; 629 if Pos(LineEnding, Value2) > 0 then begin 630 Add(NameText + ':' + GetNext(Value2, LineEnding)); 631 while Pos(LineEnding, Value2) > 0 do begin 632 Add(' ' + GetNext(Value2, LineEnding)); 633 end; 634 Add(' ' + GetNext(Value2, LineEnding)); 635 Add(''); 636 end else begin 637 OutText := NameText + ':' + Value2; 638 LineIndex := 0; 639 LinePrefix := ''; 640 while True do begin 641 if Length(OutText) > MaxLineLength then begin 642 if (LineIndex > 0) and (LinePrefix = '') then LinePrefix := ' '; 643 Add(LinePrefix + Copy(OutText, 1, MaxLineLength)); 644 System.Delete(OutText, 1, MaxLineLength); 645 Inc(LineIndex); 646 Continue; 647 end else begin 648 Add(LinePrefix + OutText); 649 Break; 650 end; 651 end; 652 if LinePrefix <> '' then Add(''); 653 end; 654 end; 655 Add('END:VCARD'); 656 end; 657 end; 658 659 function TContact.LoadFromStrings(Lines: TStrings; StartLine: Integer = 0): Integer; 660 type 661 TParseState = (psNone, psInside, psFinished); 662 var 663 ParseState: TParseState; 664 Line: string; 665 Value: string; 666 I: Integer; 667 NewProperty: TContactProperty; 668 CommandPart: string; 669 Names: string; 670 begin 671 ParseState := psNone; 672 I := StartLine; 673 while I < Lines.Count do begin 674 Line := Trim(Lines[I]); 675 if Line = '' then begin 676 // Skip empty lines 677 end else 678 if ParseState = psNone then begin 679 if Line = 'BEGIN:VCARD' then begin 680 ParseState := psInside; 681 end else begin 682 Parent.Error('Expected vCard begin', I + 1); 683 I := -1; 684 Break; 685 end; 686 end else 687 if ParseState = psInside then begin 688 if Line = 'END:VCARD' then begin 689 ParseState := psFinished; 690 Inc(I); 691 Break; 692 end else 693 if Pos(':', Line) > 0 then begin 694 CommandPart := GetNext(Line, ':'); 695 Names := CommandPart; 696 Value := Line; 697 while True do begin 698 Inc(I); 699 if (Length(Lines[I]) > 0) and (Lines[I][1] = ' ') then begin 700 Value := Value + Trim(Lines[I]); 701 end else 702 if (Length(Lines[I]) > 0) and (Length(Value) > 0) and (Value[Length(Value)] = '=') and 703 (Lines[I][1] = '=') then begin 704 Value := Value + Copy(Trim(Lines[I]), 2, MaxInt); 705 end else begin 706 Dec(I); 707 Break; 708 end; 709 end; 710 NewProperty := Properties.GetByName(Names); 711 if not Assigned(NewProperty) then begin 712 NewProperty := TContactProperty.Create; 713 Properties.Add(NewProperty); 714 end; 715 NewProperty.Attributes.DelimitedText := Names; 716 if NewProperty.Attributes.Count > 0 then begin 717 NewProperty.Name := NewProperty.Attributes[0]; 718 NewProperty.Attributes.Delete(0); 719 end; 720 NewProperty.Value := Value; 721 NewProperty.EvaluateAttributes; 722 end else begin 723 Parent.Error(SExpectedProperty, I + 1); 724 I := -1; 725 Break; 726 end; 727 end; 728 Inc(I); 729 end; 730 Result := I; 731 end; 732 733 procedure TContact.SaveToFile(FileName: string); 734 var 735 Lines: TStringList; 736 begin 737 Lines := TStringList.Create; 738 try 739 SaveToStrings(Lines); 740 Lines.SaveToFile(FileName); 741 finally 742 Lines.Free; 743 end; 744 end; 745 746 procedure TContact.LoadFromFile(FileName: string); 747 var 748 Lines: TStringList; 749 I: Integer; 750 begin 751 Lines := TStringList.Create; 752 try 753 Lines.LoadFromFile(FileName); 754 I := LoadFromStrings(Lines); 755 finally 756 Lines.Free; 757 end; 595 758 end; 596 759 … … 672 835 function TContactsFile.GetFileExt: string; 673 836 begin 674 Result := '.vcf';837 Result := VCardFileExt; 675 838 end; 676 839 … … 693 856 Output: TStringList; 694 857 I: Integer; 695 J: Integer;696 NameText: string;697 Value2: string;698 Text: string;699 LineIndex: Integer;700 OutText: string;701 LinePrefix: string;702 const703 MaxLineLength = 73;704 858 begin 705 859 inherited; 860 Output := TStringList.Create; 706 861 try 707 Output := TStringList.Create;708 862 for I := 0 to Contacts.Count - 1 do 709 with Contacts[I], Output do begin 710 Add('BEGIN:VCARD'); 711 for J := 0 to Properties.Count - 1 do 712 with Properties[J] do begin 713 NameText := Name; 714 if Attributes.Count > 0 then 715 NameText := NameText + ';' + Attributes.DelimitedText; 716 if Encoding <> '' then begin 717 Value2 := GetEncodedValue; 718 NameText := NameText + ';ENCODING=' + Encoding; 719 end else Value2 := Value; 720 if Pos(LineEnding, Value2) > 0 then begin 721 Add(NameText + ':' + GetNext(Value2, LineEnding)); 722 while Pos(LineEnding, Value2) > 0 do begin 723 Add(' ' + GetNext(Value2, LineEnding)); 724 end; 725 Add(' ' + GetNext(Value2, LineEnding)); 726 Add(''); 727 end else begin 728 OutText := NameText + ':' + Value2; 729 LineIndex := 0; 730 LinePrefix := ''; 731 while True do begin 732 if Length(OutText) > MaxLineLength then begin 733 if (LineIndex > 0) and (LinePrefix = '') then LinePrefix := ' '; 734 Add(LinePrefix + Copy(OutText, 1, MaxLineLength)); 735 System.Delete(OutText, 1, MaxLineLength); 736 Inc(LineIndex); 737 Continue; 738 end else begin 739 Add(LinePrefix + OutText); 740 Break; 741 end; 742 end; 743 if LinePrefix <> '' then Add(''); 744 end; 745 end; 746 Add('END:VCARD'); 747 end; 863 Contacts[I].SaveToStrings(Output); 748 864 Output.SaveToFile(FileName); 749 865 finally … … 755 871 var 756 872 Lines: TStringList; 757 Line: string; 758 Value: string; 759 I: Integer; 760 NewRecord: TContact; 761 NewProperty: TContactProperty; 762 CommandPart: string; 763 Names: string; 873 Contact: TContact; 874 I: Integer; 764 875 begin 765 876 inherited; 766 NewRecord := nil;767 877 Contacts.Clear; 768 878 Lines := TStringList.Create; … … 771 881 I := 0; 772 882 while I < Lines.Count do begin 773 Line := Lines[I]; 774 if Line = '' then 775 else 776 if Line = 'BEGIN:VCARD' then begin 777 NewRecord := TContact.Create; 778 NewRecord.Parent := Self; 779 end else 780 if Line = 'END:VCARD' then begin 781 if Assigned(NewRecord) then begin 782 Contacts.Add(NewRecord); 783 NewRecord := nil; 784 end else Error(SFoundBlockEndWithoutBlockStart, I + 1); 785 end else 786 if Pos(':', Line) > 0 then begin 787 CommandPart := GetNext(Line, ':'); 788 if Assigned(NewRecord) then begin 789 Names := CommandPart; 790 Value := Line; 791 while True do begin 792 Inc(I); 793 if (Length(Lines[I]) > 0) and (Lines[I][1] = ' ') then begin 794 Value := Value + Trim(Lines[I]); 795 end else 796 if (Length(Lines[I]) > 0) and (Length(Value) > 0) and (Value[Length(Value)] = '=') and 797 (Lines[I][1] = '=') then begin 798 Value := Value + Copy(Trim(Lines[I]), 2, MaxInt); 799 end else begin 800 Dec(I); 801 Break; 802 end; 803 end; 804 NewProperty := NewRecord.Properties.GetByName(Names); 805 if not Assigned(NewProperty) then begin 806 NewProperty := TContactProperty.Create; 807 NewRecord.Properties.Add(NewProperty); 808 end; 809 NewProperty.Attributes.DelimitedText := Names; 810 if NewProperty.Attributes.Count > 0 then begin 811 NewProperty.Name := NewProperty.Attributes[0]; 812 NewProperty.Attributes.Delete(0); 813 end; 814 NewProperty.Value := Value; 815 NewProperty.EvaluateAttributes; 816 end else Error(SFoundPropertiesBeforeBlockStart, I + 1); 883 Contact := TContact.Create; 884 Contact.Parent := Self; 885 I := Contact.LoadFromStrings(Lines, I); 886 if (I <= Lines.Count) and (I <> -1) then Contacts.Add(Contact) 887 else begin 888 FreeAndNil(Contact); 889 Break; 817 890 end; 818 Inc(I);819 891 end; 820 892 finally
Note:
See TracChangeset
for help on using the changeset viewer.