-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathVarRecUtils.pas
145 lines (131 loc) · 4.16 KB
/
VarRecUtils.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
unit VarRecUtils;
interface
type
TConstArray = array of TVarRec;
// Copies a TVarRec and its contents. If the content is referenced
// the value will be copied to a new location and the reference
// updated.
function CopyVarRec(const Item: TVarRec): TVarRec;
// Creates a TConstArray out of the values given. Uses CopyVarRec
// to make copies of the original elements.
function Values(const Elements: array of const): TConstArray;
// TVarRecs created by CopyVarRec must be finalized with this function.
// You should not use it on other TVarRecs.
procedure FinalizeVarRec(var Item: TVarRec);
// A TConstArray contains TVarRecs that must be finalized. This function
// does that for all items in the array.
procedure FinalizeConstArray(var Arr: TConstArray);
implementation
uses
SysUtils;
function CopyVarRec(const Item: TVarRec): TVarRec;
var
W: WideString;
begin
// Copy entire TVarRec first
Result := Item;
// Now handle special cases
case Item.VType of
vtExtended:
begin
New(Result.VExtended);
Result.VExtended^ := Item.VExtended^;
end;
vtString:
begin
// Improvement suggestion by Hallvard Vassbotn: only copy real length.
//Result.VString := GetMem(Length(Item.VString^) + 1);
Result.VString^ := Item.VString^;
end;
vtPChar:
Result.VPChar := StrNew(Item.VPChar);
// There is no StrNew for PWideChar
vtPWideChar:
begin
W := Item.VPWideChar;
GetMem(Result.VPWideChar,
(Length(W) + 1) * SizeOf(WideChar));
Move(PWideChar(W)^, Result.VPWideChar^,
(Length(W) + 1) * SizeOf(WideChar));
end;
// A little trickier: casting to AnsiString will ensure
// reference counting is done properly.
vtAnsiString:
begin
// nil out first, so no attempt to decrement reference count.
Result.VAnsiString := nil;
AnsiString(Result.VAnsiString) := AnsiString(Item.VAnsiString);
end;
vtCurrency:
begin
New(Result.VCurrency);
Result.VCurrency^ := Item.VCurrency^;
end;
vtVariant:
begin
New(Result.VVariant);
Result.VVariant^ := Item.VVariant^;
end;
// Casting ensures proper reference counting.
vtInterface:
begin
Result.VInterface := nil;
IInterface(Result.VInterface) := IInterface(Item.VInterface);
end;
// Casting ensures a proper copy is created.
vtWideString:
begin
Result.VWideString := nil;
WideString(Result.VWideString) := WideString(Item.VWideString);
end;
vtInt64:
begin
New(Result.VInt64);
Result.VInt64^ := Item.VInt64^;
end;
vtUnicodeString:
begin
// Similar to AnsiString.
Result.VUnicodeString := nil;
UnicodeString(Result.VUnicodeString) := UnicodeString(Item.VUnicodeString);
end;
// VPointer and VObject don't have proper copy semantics so it
// is impossible to write generic code that copies the contents
end;
end;
function Values(const Elements: array of const): TConstArray;
var
I: Integer;
begin
SetLength(Result, Length(Elements));
for I := Low(Elements) to High(Elements) do
Result[I] := CopyVarRec(Elements[I]);
end;
// use this function on copied TVarRecs only!
procedure FinalizeVarRec(var Item: TVarRec);
begin
case Item.VType of
vtExtended: Dispose(Item.VExtended);
vtString: Dispose(Item.VString);
vtPChar: StrDispose(Item.VPChar);
vtPWideChar: FreeMem(Item.VPWideChar);
vtAnsiString: AnsiString(Item.VAnsiString) := '';
vtCurrency: Dispose(Item.VCurrency);
vtVariant: Dispose(Item.VVariant);
vtInterface: IInterface(Item.VInterface) := nil;
vtWideString: WideString(Item.VWideString) := '';
vtInt64: Dispose(Item.VInt64);
vtUnicodeString: UnicodeString(Item.VUnicodeString) := '';
end;
Item.VInteger := 0;
end;
procedure FinalizeConstArray(var Arr: TConstArray);
var
I: Integer;
begin
for I := Low(Arr) to High(Arr) do
FinalizeVarRec(Arr[I]);
Finalize(Arr);
Arr := nil;
end;
end.