-
Notifications
You must be signed in to change notification settings - Fork 6
/
Copy pathObjArr.pas
136 lines (124 loc) · 4.48 KB
/
ObjArr.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
unit ObjArr;
////////////////////////////////////////////////////////////////////////////////
interface
////////////////////////////////////////////////////////////////////////////////
Uses
SysUtils, Classes;
Type
TCaseType = (ctAsIs,ctLowercase,ctUppercase);
TJsonObjectArrayParser = Class
// Reads the successive JSON object literals from a JSON object array literal
private
FEndOfArray,OwnsReader: Boolean;
Stream: TStream;
Reader: TStreamReader;
public
Constructor Create(const FileName: TFileName); overload;
Constructor Create(const Json: String); overload;
Constructor Create(const Stream: TStream); overload;
Constructor Create(const StreamReader: TStreamReader); overload;
Function Next(NameCase: TCaseType = ctAsIs): String;
Destructor Destroy; override;
public
Property EndOfArray: Boolean read FEndOfArray;
end;
////////////////////////////////////////////////////////////////////////////////
implementation
////////////////////////////////////////////////////////////////////////////////
Constructor TJsonObjectArrayParser.Create(const FileName: TFileName);
begin
Stream := TBufferedFileStream.Create(FileName,fmOpenRead or fmShareDenyWrite);
Create(Stream);
end;
Constructor TJsonObjectArrayParser.Create(const Json: String);
begin
Stream := TStringStream.Create(Json);
Create(Stream);
end;
Constructor TJsonObjectArrayParser.Create(const Stream: TStream);
begin
OwnsReader := true;
Reader := TStreamReader.Create(Stream,TEncoding.Ansi);
Create(Reader);
end;
Constructor TJsonObjectArrayParser.Create(const StreamReader: TStreamReader);
begin
inherited Create;
Reader := StreamReader;
// Read array start
while (not Reader.EndOfStream) and (Char(Reader.Peek) in [#10,#13,#32]) do Reader.Read;
if Reader.EndOfStream or (Char(Reader.Read) <> '[') then raise Exception.Create('Invalid Json-array');
// Read until first object
while (not Reader.EndOfStream) and (Char(Reader.Peek) in [#10,#13,#32]) do Reader.Read;
if not Reader.EndOfStream then
begin
if (Char(Reader.Peek) = ']') then
begin
Reader.Read;
FEndOfArray := true;
end;
end else
raise Exception.Create('Invalid Json-array');
end;
Function TJsonObjectArrayParser.Next(NameCase: TCaseType = ctAsIs): String;
// Returns the next JSON object literal
begin
if not FEndOfArray then
begin
// Read object string
while (not Reader.EndOfStream) and (Char(Reader.Peek) in [#10,#13,#32]) do Reader.Read;
if (not Reader.EndOfStream) and (Char(Reader.Peek) = '{') then
begin
var Name := true;
var Escape := false;
var WithinString := false;
var BracesCount := 0;
var BracketsCount := 0;
if not Reader.EndOfStream then
repeat
var Ch := Char(Reader.Read);
if not (Ch in [#10,#13]) and (WithinString or (Ch <> #32)) then
begin
if Ch = '{' then Inc(BracesCount) else if Ch = '}' then Dec(BracesCount);
if Ch = '[' then Inc(BracketsCount) else if Ch = ']' then Dec(BracketsCount);
if (Ch = '"') and not Escape then WithinString := not WithinString;
if (Ch = '\') then Escape := true else Escape := false;
if (BracesCount=1) and (BracketsCount=0) then
begin
if Ch = ':' then Name := false else
if Ch = ',' then Name := true;
// Set name case
if Name then
case NameCase of
ctAsIs: Result := Result + Ch;
ctLowercase: Result := Result + Lowercase(Ch);
ctUppercase: Result := Result + Uppercase(Ch);
end
else
Result := Result + Ch
end else
Result := Result + Ch
end;
until Reader.EndOfStream or (BracesCount = 0);
if (BracesCount > 0) or (BracketsCount > 0) then raise Exception.Create('Invalid Json-array');
end else
raise Exception.Create('Invalid Json-array');
// Read until next object;
while (not Reader.EndOfStream) and (Char(Reader.Peek) in [#10,#13,#32]) do Reader.Read;
if not Reader.EndOfStream then
begin
var Ch := Char(Reader.Read);
if Ch = ']' then FEndOfArray := true else
if Ch <> ',' then raise Exception.Create('Invalid Json-array');
end else
raise Exception.Create('Invalid Json-array');
end else
raise Exception.Create('Reading past end of Json-array');
end;
Destructor TJsonObjectArrayParser.Destroy;
begin
if OwnsReader then Reader.Free;
Stream.Free;
inherited Destroy;
end;
end.