-
Notifications
You must be signed in to change notification settings - Fork 25
/
Copy pathCromis.SimpleStorage.pas
3080 lines (2654 loc) · 92.5 KB
/
Cromis.SimpleStorage.pas
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
(*
* This software is distributed under BSD license.
*
* Copyright (c) 2006-2010 Iztok Kacin, Cromis (iztok.kacin@gmail.com).
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright notice, this
* list of conditions and the following disclaimer in the documentation and/or
* other materials provided with the distribution.
* - Neither the name of the Iztok Kacin nor the names of its contributors may be
* used to endorse or promote products derived from this software without specific
* prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE.
*
* ==================================================================================
* A simple data storage based on OmniXML.
* ==================================================================================
* 12/01/2010 (1.5.1)
* - Support for encryption based on XTEA algorithm
* ==================================================================================
* 06/02/2010 (1.6.1)
* - Added IDocumentsCollection interface for easy XML document searches
* ==================================================================================
* 07/02/2010 (1.6.2)
* - Added GetAttr / EnsureAttr function to simplify the attribute manipulation
* ==================================================================================
* 08/02/2010 (1.6.3)
* - Changes in SimpleStorage.Collection related to single document handling
* ==================================================================================
* 08/03/2010 (1.6.5)
* - Overloaded all functions that accept XPath. Now it is possible to use path
* in the form of an array of strings. It is easier to use constants this way
* - Included StorageBuilder as part of SimpleStorage
* - Was forced to expose XMLNode as Element property
* - Fixed Element.Remove inconsistencies
* - Remove can compact empty parent nodes
* - SaveChanges added to IDocument in Collection
* ==================================================================================
* 28/03/2010 (1.7.0)
* - Added IDocumentFilter as a base for document wide filtering
* - Added IDocumentFilterChain as a means to chain the multiple filters together
* - Added IStorageFilter to allow doument filtering through ISimpleStorage interface
* - IEncryptedSimpleStorage now inherits from IDocumentFilter
* - Added ICompressedStorage document filter
* - IDocuments now uses FilterChain to possibly filter the XML documents
* ==================================================================================
* 05/11/2010 (1.7.1)
* - ICustomFilterData added to allow one filter syntax for both elements and documents
* - renamed some of the internally used interfaces to have a clearer structure
* ==================================================================================
* 25/11/2010 (1.7.2)
* - Filter chaining code is now consistent
* - Do not directly work on filter input streams
* ==================================================================================
* 25/01/2011 (1.7.3)
* - TElement.Assign and TElement.Merge now correctly handle CData
* ==================================================================================
* 30/05/2011 (1.7.4)
* - TAttributes.Exists does not raise exception if no XML node is present (returns false)
* ==================================================================================
* 30/05/2011 (1.7.5)
* - AppendAllElements now assigns child nodes before the recursion to keep node order
* ==================================================================================
* 29/01/2012 (1.7.6)
* - Fixed Merge procedure
* ==================================================================================
* 12/06/2012 (1.7.7)
* - StorageFromXMLdocument and TSimpleStorage.LoadFromXMLDocument added
* - XMLDocument for ISimpleStorage allows acces to underlying document object
* - Added LastLoadStatus to allow the handling of XML parsing errors
* ==================================================================================
*)
unit Cromis.SimpleStorage;
interface
uses
SysUtils, Classes, Controls, Contnrs, Graphics, GraphUtil,
// omniXML library units
{$IFNDEF USE_MSXML}OmniXML{$ELSE}MSXML, OmniXML_MSXML{$ENDIF},OmniXML_Types, OmniXMLUtils,
// internal cromis units
Cromis.StringUtils, Cromis.Streams;
type
TElementType = (etValue, etNode);
ICustomFilterData = interface;
ISimpleStorage = Interface;
IElement = Interface;
IValue = Interface;
IValueData = Interface(IInterface)
['{ABB5B59C-4AEB-46E8-BBD3-9D4CFB449E77}']
function _GetIsValid: Boolean;
property IsValid: Boolean read _GetIsValid;
end;
ICData = Interface(IValueData)
['{6D1018C6-99EE-4175-8356-823E4D43E620}']
function _GetData: IValue;
// getters and setters
// CData functions and procedures
procedure SaveToStream(const Stream: TStream; const FailIfInvalid: Boolean = False);
procedure LoadFromStream(const Stream: TStream);
property Data: IValue read _GetData;
end;
IBinary = Interface(IValueData)
['{6CD7653A-55F8-477A-9F64-E49131982026}']
// getters and setters
function _GetStream: TStream;
// binary functions and procedures
procedure SaveToFile(const FileName: string; const FailIfInvalid: Boolean = False);
procedure LoadFromFile(const FileName: string; const Mode: Word = fmShareDenyNone);
procedure SaveToStream(const Stream: TStream; const FailIfInvalid: Boolean = False);
procedure LoadFromBuffer(const Buffer: Pointer; const Size: Cardinal);
procedure LoadFromElement(const Element: IElement);
procedure LoadFromStream(const Stream: TStream);
procedure SaveToBuffer(var Buffer: Pointer);
procedure LoadFromXML(const XML: XmlString);
property Stream: TStream read _GetStream;
end;
IStorageBase = Interface(IInterface)
['{C41F71F0-1EEC-40E3-A7D7-B83EBBB45C3B}']
function GetElementNode: IXMLNode;
procedure SetElementNode(const Value: IXMLNode);
function LoadValueAsString: XmlString;
procedure LoadValueAsStream(const Value: TStream);
procedure SaveValueAsStream(const Value: TStream);
procedure SaveValueAsString(const Value: XmlString);
property ElementNode: IXMLNode read GetElementNode write SetElementNode;
end;
IStorageData = Interface(IStorageBase)
['{284493C8-994E-4853-BF32-348B801A73F4}']
end;
IValueFilterData = Interface(IStorageData)
['{78BC0D4B-EE30-4E7C-B778-3A3751A9758B}']
function GetNextFilter: IValueFilterData;
procedure AddFilter(const Data: IValueFilterData);
procedure LoadChainValue(const Value, Result: TStream);
procedure SaveChainValue(const Value, Result: TStream);
property NextFilter: IValueFilterData read GetNextFilter;
end;
IAdapterData = Interface(IInterface)
['{284493C8-994E-4853-BF32-348B801A73F4}']
// property getters and setters
function GetElement: IElement;
procedure SetElement(const Value: IElement);
// storage load / save procedures / functions
procedure LoadAdapterData(const DataObject: TObject);
procedure SaveAdapterData(const DataObject: TObject);
// IAdapterData properties
property Element: IElement read GetElement write SetElement;
end;
IAdapter = Interface(IInterface)
['{11548A74-E56D-46BE-9D23-F294431B0139}']
procedure Load(const SourceObject: TObject);
procedure Save(const TargetObject: TObject);
end;
IValue = Interface(IValueData)
['{3D25DFB7-CC19-4598-9010-8FA55322F126}']
// getters and setters
function _GetName: XmlString;
function _GetAsTime: TTime;
function _GetAsDate: TDate;
function _GetAsFloat: Real;
function _GetAsInt64: Int64;
function _GetAsCData: ICData;
function _GetAsColor: TColor;
function _GetAsBinary: IBinary;
function _GetAsString: XmlString;
function _GetAsInteger: Integer;
function _GetAsBoolean: Boolean;
function _GetAsDateTime: TDateTime;
procedure _SetAsTime(Value: TTime);
procedure _SetAsDate(Value: TDate);
procedure _SetAsFloat(Value: Real);
procedure _SetAsInt64(Value: Int64);
procedure _SetAsColor(Value: TColor);
procedure _SetAsString(Value: XmlString);
procedure _SetAsInteger(Value: Integer);
procedure _SetAsBoolean(Value: Boolean);
procedure _SetAsDateTime(Value: TDateTime);
// value properties that get/set value in different formats
function AsFloatDef(const DefValue: Real = 0): Real;
function AsInt64Def(const DefValue: Int64 = 0): Int64;
function AsColorDef(const DefValue: TColor = clNone): TColor;
function AsStringDef(const DefValue: XmlString = ''): XmlString;
function AsIntegerDef(const DefValue: Integer = 0): Integer;
function AsBooleanDef(const DefValue: Boolean = False): Boolean;
function AsDateTimeDef(const DefValue: TDateTime = 0): TDateTime;
property AsDateTime: TDateTime read _GetAsDateTime write _SetAsDateTime;
property AsBoolean: Boolean read _GetAsBoolean write _SetAsBoolean;
property AsInteger: Integer read _GetAsInteger write _SetAsInteger;
property AsString: XmlString read _GetAsString write _SetAsString;
property AsColor: TColor read _GetAsColor write _SetAsColor;
property AsInt64: Int64 read _GetAsInt64 write _SetAsInt64;
property AsFloat: Real read _GetAsFloat write _SetAsFloat;
property AsTime: TTime read _GetAsTime write _SetAsTime;
property AsDate: TDate read _GetAsDate write _SetAsDate;
property AsBinary: IBinary read _GetAsBinary;
property AsCData: ICData read _GetAsCData;
property Name: XmlString read _GetName;
end;
IAttributesEnumerator = Interface(IInterface)
['{D0F64552-2B5A-4874-951C-C4064C482B6D}']
// getters and setters
function _GetCurrent: IValue;
// iterator function and procedures
function MoveNext: Boolean;
property Current: IValue read _GetCurrent;
end;
IAttributes = Interface(IInterface)
['{36A4A35F-260F-4EC9-A8CD-84DF4DA12BCF}']
procedure Assign(const Attributes: IAttributes);
procedure Update(const Attributes: IAttributes);
function GetEnumerator: IAttributesEnumerator;
function Ensure(const Name: XmlString): IValue;
function Exists(const Name: XmlString): Boolean;
function Get(const Name: XmlString): IValue;
procedure Remove(const Name: XmlString);
function Count: Integer;
end;
IBaseEnumerator = Interface(IInterface)
['{A9525AC0-2831-451B-A112-B333B69D9168}']
// getters and setters
function _GetCurrent: IElement;
// iterator function and procedures
function MoveNext: Boolean;
property Current: IElement read _GetCurrent;
end;
IElementsEnumerator = Interface(IBaseEnumerator)
['{E523BEAD-9B50-4749-B864-3F1E38CD35E5}']
end;
IElementsList = Interface(IInterface)
['{87AEE05F-1DED-49E1-96E1-55F6C8728F79}']
function Count: Integer;
function _GetLast: IElement;
function _GetFirst: IElement;
function GetEnumerator: IElementsEnumerator;
function _GetItem(const Index: Integer): IElement;
property Item[const Index: Integer]: IElement read _GetItem;
property First: IElement read _GetFirst;
property Last: IElement read _GetLast;
end;
INodesEnumerator = Interface(IBaseEnumerator)
['{825AB39D-F783-42B1-AE1A-239286D3C2B6}']
end;
INodesList = Interface(IInterface)
['{87AEE05F-1DED-49E1-96E1-55F6C8728F79}']
function GetEnumerator: INodesEnumerator;
function Count: Integer;
end;
IValuesEnumerator = Interface(IBaseEnumerator)
['{E523BEAD-9B50-4749-B864-3F1E38CD35E5}']
end;
IValuesList = Interface(IInterface)
['{87AEE05F-1DED-49E1-96E1-55F6C8728F79}']
function GetEnumerator: IValuesEnumerator;
function Count: Integer;
end;
IValueFilter = Interface(IValue)
['{E9AA30DA-4581-4922-A58A-4476E9D49AC2}']
function Filter(const Data: ICustomFilterData): IValueFilter;
end;
IDocumentFilterData = interface(IInterface)
['{5230BB12-6B92-450D-B8EA-C7D475C612E8}']
function LoadFromFile(const FileName: string): ISimpleStorage;
function LoadFromStream(const Stream: TStream): ISimpleStorage;
procedure SaveToFile(const Storage: ISimpleStorage; const FileName: string);
procedure SaveToStream(const Storage: ISimpleStorage; const Stream: TStream);
procedure DirectFilterIn(const SourceStream: TStream; const TargetFile: string); overload;
procedure DirectFilterIn(const SourceFile: string; const TargetStream: TStream); overload;
procedure DirectFilterIn(const SourceStream, TargetStream: TStream); overload;
procedure DirectFilterIn(const SourceFile, TargetFile: string); overload;
procedure DirectFilterOut(const SourceStream: TStream; const TargetFile: string); overload;
procedure DirectFilterOut(const SourceFile: string; const TargetStream: TStream); overload;
procedure DirectFilterOut(const SourceStream, TargetStream: TStream); overload;
procedure DirectFilterOut(const SourceFile, TargetFile: string); overload;
end;
IDocumentFilterChain = interface(IDocumentFilterData)
['{FF9AA033-E77A-4149-83B9-55E5219CEBB1}']
procedure AddFilter(const Filter: IDocumentFilterData);
function Count: Integer;
procedure Clear;
end;
IDocumentFilter = Interface(IInterface)
['{76DCCC1D-8D1B-46B9-A12A-05D6BAD8DB29}']
procedure SaveToFile(const FileName: string);
procedure SaveToStream(const Stream: TStream);
procedure LoadFromFile(const FileName: string);
procedure LoadFromStream(const Stream: TStream);
function Filter(const Filter: ICustomFilterData): IDocumentFilter;
end;
ICustomFilterData = Interface(IInterface)
['{E6AEC66D-733C-4126-8ACD-4F9CD841911C}']
function ValueFilterData(const Node: IXMLNode): IValueFilterData;
function DocumentFilterData: IDocumentFilterData;
end;
IElement = Interface(IValue)
['{D42DB0F3-766B-4392-A670-DA009D4BCB20}']
// getters and setters
function _GetParent: IElement;
function _GetXMLNode: IXMLNode;
function _GetHasNodes: Boolean;
function _GetHasValues: Boolean;
function _GetNodeIndex: Integer;
function _GetHasElements: Boolean;
function _GetRootElement: IElement;
function _GetElementType: TElementType;
// element functions and procedures
function Attributes: IAttributes;
procedure RemoveAllElements;
procedure Merge(const Element: IElement);
procedure Remove(const Path: XmlString; const Compact: Boolean = False); overload;
procedure Remove(const Element: IElement; const Compact: Boolean = False); overload;
procedure Remove(const Path: array of XmlString; const Compact: Boolean = False); overload;
function Storage(const Path: array of XmlString): ISimpleStorage; overload;
function Storage(const Path: XmlString = ''): ISimpleStorage; overload;
function Elements(const Params: XmlString = '*'): IElementsList;
function Values(const Params: XmlString = '*'): IValuesList;
function Nodes(const Params: XmlString = '*'): INodesList;
procedure Assign(const Element: IElement; const InDepth: Boolean = False); overload;
procedure Assign(const Nodes: INodesList; const InDepth: Boolean = False); overload;
procedure Assign(const Nodes: IElementsList; const InDepth: Boolean = False); overload;
function Append(const Element: IElement; const InDepth: Boolean = True): IElement; overload;
procedure Append(const Elements: IElementsList; const InDepth: Boolean = False); overload;
procedure Append(const Nodes: INodesList; const InDepth: Boolean = False); overload;
function Append(const Path: array of XmlString): IElement; overload;
function Append(const Path: XmlString): IElement; overload;
procedure Append(const Values: IValuesList); overload;
function EnsureAttr(const Path: array of XmlString; const Name: XmlString): IValue; overload;
function GetAttr(const Path: array of XmlString; const Name: XmlString): IValue; overload;
function EnsureAttr(const Path, Name: XmlString): IValue; overload;
function GetAttr(const Path, Name: XmlString): IValue; overload;
function EnsureAttr(const Name: XmlString): IValue; overload;
function GetAttr(const Name: XmlString): IValue; overload;
function Ensure(const Path: array of XmlString): IElement; overload;
function Exists(const Path: array of XmlString): Boolean; overload;
function Get(const Path: array of XmlString): IElement; overload;
function Ensure(const Path: XmlString): IElement; overload;
function Exists(const Path: XmlString): Boolean; overload;
function Get(const Path: XmlString): IElement; overload;
function FirstChild: IElement;
// custom plugin funtions. returns the interface
function Filter(const Data: ICustomFilterData): IValueFilter; overload;
function Filter(const Name: string): IValueFilter; overload; deprecated;
function Adapter(const Data: IAdapterData): IAdapter; overload;
function Adapter(const Name: string): IAdapter; overload; deprecated;
// properties of the elements
property ElementType: TElementType read _GetElementType;
property RootElement: IElement read _GetRootElement;
property HasElements: Boolean read _GetHasElements;
property HasValues: Boolean read _GetHasValues;
property NodeIndex: Integer read _GetNodeIndex;
property HasNodes: Boolean read _GetHasNodes;
property XMLNode: IXMLNode read _GetXMLNode;
property Parent: IElement read _GetParent;
end;
TLoadError = record
ErrorCode: Integer;
SrcText: XmlString;
FilePos: Integer;
LinePos: Integer;
Reason: string;
Line: Integer;
end;
TLoadStatus = record
Success: Boolean;
Error: TLoadError;
end;
ISimpleStorage = Interface(IElement)
['{16EEA551-3D02-49C3-B097-0A1A6FA0B1CD}']
// storage function and procedures
procedure Clear;
procedure SaveToFile(const FileName: XmlString);
procedure SaveToStream(const OutStream: TStream);
procedure LoadFromXML(const XML: XmlString);
procedure LoadFromFile(const FileName: XmlString);
procedure LoadFromStream(const InStream: TStream);
procedure LoadFromXMLDocument(const Document: IXMLDocument);
function Content(const Structured: Boolean = False): XmlString;
function Filter(const Data: ICustomFilterData): IDocumentFilter; overload;
function LastLoadStatus: TLoadStatus;
function XMLDocument: IXMLDocument;
end;
// ***************************************************************************************
// Storage, filter and adapter data classes.
// They have to be overriden with actual implementation.
// WARNING: Constructor must not be redeclared or overriden !!!
// ***************************************************************************************
TStorageBase = class(TInterfacedObject, IStorageBase)
private
FElementNode: IXMLNode;
function GetElementNode: IXMLNode;
procedure SetElementNode(const Value: IXMLNode);
public
constructor Create(const ElementNode: IXMLNode);
function LoadValueAsString: XmlString; virtual; abstract;
procedure LoadValueAsStream(const Value: TStream); virtual; abstract;
procedure SaveValueAsStream(const Value: TStream); virtual; abstract;
procedure SaveValueAsString(const Value: XmlString); virtual; abstract;
property ElementNode: IXMLNode read GetElementNode write SetElementNode;
end;
TStorageData = class(TStorageBase, IStorageData)
protected
function DoLoadValueAsString: XmlString; virtual; abstract;
procedure DoLoadValueAsStream(const Value: TStream); virtual; abstract;
procedure DoSaveValueAsStream(const Value: TStream); virtual; abstract;
procedure DoSaveValueAsString(const Value: XmlString); virtual; abstract;
public
function LoadValueAsString: XmlString; override;
procedure LoadValueAsStream(const Value: TStream); override;
procedure SaveValueAsStream(const Value: TStream); override;
procedure SaveValueAsString(const Value: XmlString); override;
end;
// ***************************************************************************************
// Value filter base class. It has to be overriden with actual implementation
// WARNING: Constructor must not be redeclared or overriden !!!
// ***************************************************************************************
TValueFilterData = class(TStorageBase, IValueFilterData)
private
FNextFilter: IValueFilterData;
function GetNextFilter: IValueFilterData;
procedure InternalLoadValueAsStream(const Value: TStream);
procedure InternalSaveValueAsStream(const Value: TStream);
protected
procedure DoLoadValueAsStream(const Value, Result: TStream); virtual; abstract;
procedure DoSaveValueAsStream(const Value, Result: TStream); virtual; abstract;
public
procedure AddFilter(const Filter: IValueFilterData);
function LoadValueAsString: XmlString; override;
procedure LoadChainValue(const Value, Result: TStream);
procedure SaveChainValue(const Value, Result: TStream);
procedure LoadValueAsStream(const Value: TStream); override;
procedure SaveValueAsStream(const Value: TStream); override;
procedure SaveValueAsString(const Value: XmlString); override;
property NextFilter: IValueFilterData read GetNextFilter;
end;
TAdapterData = class(TInterfacedObject, IAdapterData)
private
FElement: IElement;
function GetElement: IElement;
procedure SetElement(const Value: IElement);
protected
procedure DoLoadAdapterData(const DataObject: TObject); virtual; abstract;
procedure DoSaveAdapterData(const DataObject: TObject); virtual; abstract;
public
procedure LoadAdapterData(const DataObject: TObject);
procedure SaveAdapterData(const DataObject: TObject);
property Element: IElement read GetElement write SetElement;
end;
// generic class for storage and adapter data
TStorageDataClass = class of TValueFilterData;
TAdapterDataClass = class of TAdapterData;
// ***************************************************************************************
// Document filter base class. It has to be overriden with actual implementation
// WARNING: Constructor must not be redeclared or overriden !!!
// ***************************************************************************************
TDocumentFilterData = class(TInterfacedObject, IDocumentFilterData)
private
procedure DirectFilterIn(const SourceStream: TStream; const TargetFile: string); overload;
procedure DirectFilterIn(const SourceFile: string; const TargetStream: TStream); overload;
procedure DirectFilterIn(const SourceFile, TargetFile: string); overload;
procedure DirectFilterOut(const SourceStream: TStream; const TargetFile: string); overload;
procedure DirectFilterOut(const SourceFile: string; const TargetStream: TStream); overload;
procedure DirectFilterOut(const SourceFile, TargetFile: string); overload;
protected
procedure DirectFilterIn(const SourceStream, TargetStream: TStream); overload; virtual; abstract;
procedure DirectFilterOut(const SourceStream, TargetStream: TStream); overload; virtual; abstract;
public
function LoadFromFile(const FileName: string): ISimpleStorage; virtual;
function LoadFromStream(const Stream: TStream): ISimpleStorage; virtual;
procedure SaveToFile(const Storage: ISimpleStorage; const FileName: string); virtual;
procedure SaveToStream(const Storage: ISimpleStorage; const Stream: TStream); virtual;
end;
// function that create SimpleStorage from different input data
function CreateStorage(const RootNode: XmlString = ''): ISimpleStorage;
function StorageFromXML(const XML: XmlString): ISimpleStorage;
function StorageFromFile(const FileName: XmlString): ISimpleStorage;
function StorageFromStream(const Stream: TStream): ISimpleStorage;
function StorageFromElement(const Element: IElement): ISimpleStorage;
function StorageFromXMLDocument(const Document: IXMLDocument): ISimpleStorage;
// function that takes a single XML node and makes an IElement
function ElementFromXMLNode(const Node: IXMLNode): IElement;
// functions that registers the global plugins for all simple storages
procedure RegisterFilter(const Name: string; const DataClass: TStorageDataClass);
procedure RegisterAdapter(const Name: string; const DataClass: TAdapterDataClass);
// constructors for storage data
function AttrNormalProxy(const ElementNode: IXMLNode): IStorageData;
function NodeNormalProxy(const ElementNode: IXMLNode): IStorageData;
function CDataProxy(const ElementNode: IXMLNode): IStorageData;
// function that creates a new document filter chain
function CreateDocumentFilterChain: IDocumentFilterChain;
implementation
const
DATA_ROOT = 'Data';
// *****************************************************************************************
// internal classes declarations hidden from the user
// *****************************************************************************************
type
TValueData = class(TInterfacedObject, IValueData)
private
function _GetIsValid: Boolean;
protected
FStorageData: IStorageData;
public
constructor Create(const StorageData: IStorageData); virtual;
property IsValid: Boolean read _GetIsValid;
end;
TCData = class(TValueData, ICData)
private
function _GetData: IValue;
public
procedure SaveToStream(const Stream: TStream; const FailIfNoData: Boolean = False);
procedure LoadFromStream(const Stream: TStream);
property Data: IValue read _GetData;
end;
TBinaryStream = class(TMemoryStream)
public
function CopyFrom(Source: TStream; Count: Int64): Int64; reintroduce;
end;
TBinary = class(TValueData, IBinary)
private
FMemoryStream: TBinaryStream;
function _GetStream: TStream;
public
constructor Create(const StorageData: IStorageData); override;
destructor Destroy; override;
// binary functions and procedures
procedure SaveToFile(const FileName: string; const FailIfNoData: Boolean = False);
procedure LoadFromFile(const FileName: string; const Mode: Word = fmShareDenyNone);
procedure SaveToStream(const Stream: TStream; const FailIfNoData: Boolean = False);
procedure LoadFromBuffer(const Buffer: Pointer; const Size: Cardinal);
procedure LoadFromElement(const Element: IElement);
procedure LoadFromStream(const Stream: TStream);
procedure SaveToBuffer(var Buffer: Pointer);
procedure LoadFromXML(const XML: XmlString);
property Stream: TStream read _GetStream;
end;
TValue = class(TValueData, IValue)
private
function _GetName: XmlString;
function _GetAsTime: TTime;
function _GetAsDate: TDate;
function _GetAsFloat: Real;
function _GetAsInt64: Int64;
function _GetAsCData: ICData;
function _GetAsColor: TColor;
function _GetAsBinary: IBinary;
function _GetAsString: XmlString;
function _GetAsInteger: Integer;
function _GetAsBoolean: Boolean;
function _GetAsDateTime: TDateTime;
procedure _SetAsTime(Value: TTime);
procedure _SetAsDate(Value: TDate);
procedure _SetAsFloat(Value: Real);
procedure _SetAsInt64(Value: Int64);
procedure _SetAsColor(Value: TColor);
procedure _SetAsString(Value: XmlString);
procedure _SetAsInteger(Value: Integer);
procedure _SetAsBoolean(Value: Boolean);
procedure _SetAsDateTime(Value: TDateTime);
public
function AsFloatDef(const DefValue: Real = 0): Real;
function AsInt64Def(const DefValue: Int64 = 0): Int64;
function AsColorDef(const DefValue: TColor = clNone): TColor;
function AsStringDef(const DefValue: XmlString = ''): XmlString;
function AsIntegerDef(const DefValue: Integer = 0): Integer;
function AsBooleanDef(const DefValue: Boolean = False): Boolean;
function AsDateTimeDef(const DefValue: TDateTime = 0): TDateTime;
property AsDateTime: TDateTime read _GetAsDateTime write _SetAsDateTime;
property AsBoolean: Boolean read _GetAsBoolean write _SetAsBoolean;
property AsInteger: Integer read _GetAsInteger write _SetAsInteger;
property AsString: XmlString read _GetAsString write _SetAsString;
property AsColor: TColor read _GetAsColor write _SetAsColor;
property AsInt64: Int64 read _GetAsInt64 write _SetAsInt64;
property AsFloat: Real read _GetAsFloat write _SetAsFloat;
property AsTime: TTime read _GetAsTime write _SetAsTime;
property AsDate: TDate read _GetAsDate write _SetAsDate;
property AsBinary: IBinary read _GetAsBinary;
property AsCData: ICData read _GetAsCData;
property Name: XmlString read _GetName;
end;
TAttributes = class(TInterfacedObject, IAttributes)
private
FElementNode: IXMLNode;
public
constructor Create(const ElementNode: IXMLNode);
procedure Assign(const Attributes: IAttributes);
procedure Update(const Attributes: IAttributes);
function GetEnumerator: IAttributesEnumerator;
function Ensure(const Name: XmlString): IValue;
function Exists(const Name: XmlString): Boolean;
function Get(const Name: XmlString): IValue;
procedure Remove(const Name: XmlString);
function Count: Integer;
end;
TAttributesEnumerator = class(TInterfacedObject, IAttributesEnumerator)
private
FIndex: Integer;
FElementNode: IXMLNode;
FCurrentNode: IXMLNode;
function _GetCurrent: IValue;
public
constructor Create(const RootNode: IXMLNode);
function MoveNext: Boolean;
property Current: IValue read _GetCurrent;
end;
TElementAdapter = class(TInterfacedObject, IAdapter)
private
FData: IAdapterData;
public
constructor Create(const Data: IAdapterData);
procedure Load(const SourceObject: TObject);
procedure Save(const TargetObject: TObject);
end;
TValueFilter = class(TValue, IValueFilter)
public
function Filter(const Data: ICustomFilterData): IValueFilter;
end;
TElement = class(TValue, IElement)
private
function _GetParent: IElement;
function _GetXMLNode: IXMLNode;
function _GetHasNodes: Boolean;
function _GetNodeIndex: Integer;
function _GetHasValues: Boolean;
function _GetHasElements: Boolean;
function _GetRootElement: IElement;
function _GetElementType: TElementType;
function DoConstructPath(const Path: array of XmlString): XmlString;
function AssignUniqueValueNode(const Template, Target: IElement; const IndexList: TList): IElement;
function InternalAppend(const Path: XmlString; const Append: Boolean): IXMLNode;
procedure AppendAllElements(const Element, Node: IElement; const Recurse: Boolean);
procedure DeleteAllChildNodes(const ParentNode: IXMLNode);
procedure MergeAllElements(const Element, Node: IElement);
public
function Attributes: IAttributes;
procedure RemoveAllElements;
procedure Merge(const Element: IElement);
procedure Remove(const Path: XmlString; const Compact: Boolean = False); overload;
procedure Remove(const Element: IElement; const Compact: Boolean = False); overload;
procedure Remove(const Path: array of XmlString; const Compact: Boolean = False); overload;
function Storage(const Path: array of XmlString): ISimpleStorage; overload;
function Storage(const Path: XmlString = ''): ISimpleStorage; overload;
function Elements(const Params: XmlString = '*'): IElementsList;
function Values(const Params: XmlString = '*'): IValuesList;
function Nodes(const Params: XmlString = '*'): INodesList;
procedure Assign(const Element: IElement; const InDepth: Boolean = False); overload;
procedure Assign(const Nodes: INodesList; const InDepth: Boolean = False); overload;
procedure Assign(const Nodes: IElementsList; const InDepth: Boolean = False); overload;
function Append(const Element: IElement; const InDepth: Boolean = True): IElement; overload;
procedure Append(const Elements: IElementsList; const InDepth: Boolean = False); overload;
procedure Append(const Nodes: INodesList; const InDepth: Boolean = False); overload;
function Append(const Path: array of XmlString): IElement; overload;
function Append(const Path: XmlString): IElement; overload;
procedure Append(const Values: IValuesList); overload;
function EnsureAttr(const Path: array of XmlString; const Name: XmlString): IValue; overload;
function GetAttr(const Path: array of XmlString; const Name: XmlString): IValue; overload;
function EnsureAttr(const Path, Name: XmlString): IValue; overload;
function GetAttr(const Path, Name: XmlString): IValue; overload;
function EnsureAttr(const Name: XmlString): IValue; overload;
function GetAttr(const Name: XmlString): IValue; overload;
function Ensure(const Path: array of XmlString): IElement; overload;
function Exists(const Path: array of XmlString): Boolean; overload;
function Get(const Path: array of XmlString): IElement; overload;
function Ensure(const Path: XmlString): IElement; overload;
function Exists(const Path: XmlString): Boolean; overload;
function Get(const Path: XmlString): IElement; overload;
function FirstChild: IElement;
// custom plugin funtions. returns the interface
function Filter(const Data: ICustomFilterData): IValueFilter; overload;
function Filter(const Name: string): IValueFilter; overload;
function Adapter(const Data: IAdapterData): IAdapter; overload;
function Adapter(const Name: string): IAdapter; overload;
// properties of the elements
property ElementType: TElementType read _GetElementType;
property RootElement: IElement read _GetRootElement;
property HasElements: Boolean read _GetHasElements;
property HasValues: Boolean read _GetHasValues;
property NodeIndex: Integer read _GetNodeIndex;
property HasNodes: Boolean read _GetHasNodes;
property XMLNode: IXMLNode read _GetXMLNode;
property Parent: IElement read _GetParent;
end;
TBaseEnumerator = class(TInterfacedObject, IElementsEnumerator)
private
function _GetCurrent: IElement;
protected
FElements: IXMLNodeList;
FCurrentNode: IXMLNode;
public
constructor Create(const Elements: IXMLNodeList);
function MoveNext: Boolean; virtual; abstract;
property Current: IElement read _GetCurrent;
end;
TElementsEnumerator = class(TBaseEnumerator, IElementsEnumerator)
public
function MoveNext: Boolean; override;
end;
TValuesEnumerator = class(TElementsEnumerator, IValuesEnumerator)
public
function MoveNext: Boolean; override;
end;
TNodesEnumerator = class(TElementsEnumerator, INodesEnumerator)
public
function MoveNext: Boolean; override;
end;
TElementsList = class(TInterfacedObject, IElementsList)
private
FElements: IXMLNodeList;
function _GetLast: IElement;
function _GetFirst: IElement;
function _GetItem(const Index: Integer): IElement;
public
constructor Create(const Elements: IXMLNodeList);
function Count: Integer;
function GetEnumerator: IElementsEnumerator;
property Item[const Index: Integer]: IElement read _GetItem;
property First: IElement read _GetFirst;
property Last: IElement read _GetLast;
end;
TNodesList = class(TInterfacedObject, INodesList)
private
FElements: IXMLNodeList;
public
constructor Create(const Elements: IXMLNodeList);
function GetEnumerator: INodesEnumerator;
function Count: Integer;
end;
TValuesList = class(TInterfacedObject, IValuesList)
private
FElements: IXMLNodeList;
public
constructor Create(const Elements: IXMLNodeList);
function GetEnumerator: IValuesEnumerator;
function Count: Integer;
end;
TDocumentFilterChain = class(TDocumentFilterData, IDocumentFilterChain)
private
FFilterList: TInterfaceList;
public
constructor Create;
destructor Destroy; override;
procedure DirectFilterIn(const SourceStream, TargetStream: TStream); overload; override;
procedure DirectFilterOut(const SourceStream, TargetStream: TStream); overload; override;
procedure AddFilter(const Filter: IDocumentFilterData);
function Count: Integer;
procedure Clear;
end;
TDocumentFilter = class(TInterfacedObject, IDocumentFilter)
private
FFilterChain: IDocumentFilterChain;
FStorage: ISimpleStorage;
public
constructor Create(const Storage: ISimpleStorage; const FilterChain: IDocumentFilterChain);
procedure SaveToFile(const FileName: string);
procedure SaveToStream(const Stream: TStream);
procedure LoadFromFile(const FileName: string);
procedure LoadFromStream(const Stream: TStream);
function Filter(const Filter: ICustomFilterData): IDocumentFilter;
end;
TSimpleStorage = class(TElement, ISimpleStorage)
private
FDataXML: IXMLDocument;
FLoadStatus: TLoadStatus;
procedure FillLoadError(const Success: Boolean);
procedure InternalCreate(const RootNode: XmlString);
procedure InitializeStorage(const RootNode: XmlString = '');
public
constructor Create(const RootNode: XmlString); reintroduce;
destructor Destroy; override;
procedure Clear;
procedure SaveToFile(const FileName: XmlString);
procedure SaveToStream(const OutStream: TStream);
procedure LoadFromXML(const XML: XmlString);
procedure LoadFromFile(const FileName: XmlString);
procedure LoadFromStream(const InStream: TStream);
procedure LoadFromXMLDocument(const Document: IXMLDocument);
function Content(const Structured: Boolean = False): XmlString;
function Filter(const Data: ICustomFilterData): IDocumentFilter; overload;
function LastLoadStatus: TLoadStatus;
function XMLDocument: IXMLDocument;
end;
// normal attribute data proxy
TAttrNormalProxy = class(TStorageData)
protected
function DoLoadValueAsString: XmlString; override;
procedure DoLoadValueAsStream(const Value: TStream); override;
procedure DoSaveValueAsStream(const Value: TStream); override;
procedure DoSaveValueAsString(const Value: XmlString); override;
end;
// normal element (node) data proxy
TNodeNormalProxy = class(TStorageData)
protected
function DoLoadValueAsString: XmlString; override;
procedure DoLoadValueAsStream(const Value: TStream); override;
procedure DoSaveValueAsStream(const Value: TStream); override;
procedure DoSaveValueAsString(const Value: XmlString); override;
end;
// normal element (node) data proxy
TCDataProxy = class(TStorageData)
protected
function DoLoadValueAsString: XmlString; override;
procedure DoLoadValueAsStream(const Value: TStream); override;
procedure DoSaveValueAsStream(const Value: TStream); override;
procedure DoSaveValueAsString(const Value: XmlString); override;
end;
TCustomPlugin = class
private
FName: string;
public
property Name: string read FName;
end;
TFilterPlugin = class(TCustomPlugin)
private
FDataClass: TStorageDataClass;
public
constructor Create(const Name: string; const DataClass: TStorageDataClass);
property DataClass: TStorageDataClass read FDataClass;
end;
TAdapterPlugin = class(TCustomPlugin)
private
FDataClass: TAdapterDataClass;
public
constructor Create(const Name: string; const DataClass: TAdapterDataClass);
property DataClass: TAdapterDataClass read FDataClass;
end;
TPluginList = class
private
FFilterList: TList;
FAdapterList: TList;
public
constructor Create;
destructor Destroy; override;
function GetFilter(const Name: string; const Node: IXMLNode): IValueFilterData;
function GetAdapter(const Name: string; const Element: IElement): IAdapterData;
procedure RegisterFilter(const Name: string; const DataClass: TStorageDataClass);
procedure RegisterAdapter(const Name: string; const DataClass: TAdapterDataClass);
end;
var
Plugins: TPluginList;
// function that registers the global filter for all simple storages
procedure RegisterFilter(const Name: string; const DataClass: TStorageDataClass);
begin
if not Assigned(Plugins) then
Plugins := TPluginList.Create;
// register the filter with name
Plugins.RegisterFilter(Name, DataClass);
end;
// function that registers the global filter for all simple storages
procedure RegisterAdapter(const Name: string; const DataClass: TAdapterDataClass);
begin
if not Assigned(Plugins) then
Plugins := TPluginList.Create;
// register the adapter with name
Plugins.RegisterAdapter(Name, DataClass);
end;
// *****************************************************************************************
// begin of the constructor functions section
// *****************************************************************************************
function CreateStorage(const RootNode: XmlString): ISimpleStorage;
begin
if RootNode <> '' then
Result := TSimpleStorage.Create(RootNode)
else
Result := TSimpleStorage.Create(DATA_ROOT);
end;
function StorageFromXML(const XML: XmlString): ISimpleStorage;
begin
Result := TSimpleStorage.Create(DATA_ROOT);
Result.LoadFromXML(XML);
end;
function StorageFromFile(const FileName: XmlString): ISimpleStorage;
begin
Result := TSimpleStorage.Create(DATA_ROOT);
Result.LoadFromFile(FileName);
end;
function StorageFromStream(const Stream: TStream): ISimpleStorage;
begin
Result := TSimpleStorage.Create(DATA_ROOT);
Result.LoadFromStream(Stream);
end;
function StorageFromElement(const Element: IElement): ISimpleStorage;
var
SubElement: IElement;
begin
Result := TSimpleStorage.Create(Element.Name);
Result.Assign(Element);
for SubElement in Element.Nodes do
Result.Append(SubElement, True);
for SubElement in Element.Values do
Result.Append(SubElement, False);
end;
function StorageFromXMLDocument(const Document: IXMLDocument): ISimpleStorage;
begin
Result := TSimpleStorage.Create(DATA_ROOT);
Result.LoadFromXMLDocument(Document);
end;