ViewVC Help
View File | Revision Log | Show Annotations | Download File | View Changeset | Root Listing
root/public/ibx/trunk/fbintf/client/FBOutputBlock.pas
Revision: 209
Committed: Wed Mar 14 12:48:51 2018 UTC (6 years, 1 month ago) by tony
Content type: text/x-pascal
File size: 35113 byte(s)
Log Message:
Fixes Merged

File Contents

# User Rev Content
1 tony 45 (*
2     * Firebird Interface (fbintf). The fbintf components provide a set of
3     * Pascal language bindings for the Firebird API.
4     *
5     * The contents of this file are subject to the Initial Developer's
6     * Public License Version 1.0 (the "License"); you may not use this
7     * file except in compliance with the License. You may obtain a copy
8     * of the License here:
9     *
10     * http://www.firebirdsql.org/index.php?op=doc&id=idpl
11     *
12     * Software distributed under the License is distributed on an "AS
13     * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
14     * implied. See the License for the specific language governing rights
15     * and limitations under the License.
16     *
17     * The Initial Developer of the Original Code is Tony Whyman.
18     *
19     * The Original Code is (C) 2016 Tony Whyman, MWA Software
20     * (http://www.mwasoftware.co.uk).
21     *
22     * All Rights Reserved.
23     *
24     * Contributor(s): ______________________________________.
25     *
26     *)
27     unit FBOutputBlock;
28 tony 56 {$IFDEF MSWINDOWS}
29     {$DEFINE WINDOWS}
30     {$ENDIF}
31 tony 45
32     {$IFDEF FPC}
33 tony 56 {$mode delphi}
34 tony 45 {$codepage UTF8}
35     {$interfaces COM}
36     {$ENDIF}
37    
38     { $DEFINE DEBUGOUTPUTBLOCK}
39    
40     interface
41    
42     {Provides common handling for the DB Info results, SQL Info and Service Response Block}
43    
44     uses
45     Classes, SysUtils, FBClientAPI, IB, FBActivityMonitor;
46    
47     const
48     DefaultBufferSize = 32000;
49 tony 143 DBInfoDefaultBufferSize = DefaultBufferSize; {allow for database page}
50 tony 45
51     type
52     TItemDataType = (dtString, dtString2, dtByte, dtBytes, dtInteger, dtIntegerFixed, dtnone,
53 tony 143 dtList,dtSpecial, dtDateTime, dtOctetString);
54 tony 45
55     POutputBlockItemData = ^TOutputBlockItemData;
56     TOutputBlockItemData = record
57     {Describes a Clumplet in the buffer. FBufPtr always points to the clumplet id
58     the rest of the clumplet up to the FSize is data. The data format is
59     given by FDataType, and the data length is given by FDataLength}
60 tony 56 FBufPtr: PByte;
61 tony 45 FDataLength: integer;
62     FSize: integer;
63     FDataType: TItemDataType;
64     FTruncated: boolean;
65     FError: boolean;
66     FSubItems: array of POutputBlockItemData;
67     end;
68    
69     { TOutputBlock }
70    
71     TOutputBlock = class(TFBInterfacedObject)
72     private
73 tony 56 FBuffer: PByte;
74 tony 45 FBufSize: integer;
75     FBufferParsed: boolean;
76     procedure ParseBuffer;
77     {$IFDEF DEBUGOUTPUTBLOCK}
78     procedure FormattedPrint(const aItems: array of POutputBlockItemData;
79 tony 56 Indent: AnsiString);
80 tony 45 {$ENDIF}
81     procedure PrintBuf;
82     protected
83     FIntegerType: TItemDataType;
84     FError: boolean;
85     FTruncated: boolean;
86     FItems: array of POutputBlockItemData;
87     procedure DoParseBuffer; virtual; abstract;
88 tony 56 function AddItem(BufPtr: PByte): POutputBlockItemData;
89     function AddIntegerItem(BufPtr: PByte): POutputBlockItemData;
90     function AddStringItem(BufPtr: PByte): POutputBlockItemData;
91     function AddShortStringItem(BufPtr: PByte): POutputBlockItemData;
92     function AddByteItem(BufPtr: PByte): POutputBlockItemData;
93     function AddBytesItem(BufPtr: PByte): POutputBlockItemData;
94     function AddListItem(BufPtr: PByte): POutputBlockItemData; virtual;
95     function AddSpecialItem(BufPtr: PByte): POutputBlockItemData; virtual;
96 tony 143 function AddDateTimeItem(BufPtr: PByte): POutputBlockItemData;
97     function AddOctetString(BufPtr: PByte): POutputBlockItemData;
98 tony 45 public
99     constructor Create(aSize: integer = DefaultBufferSize);
100     destructor Destroy; override;
101 tony 56 function Buffer: PByte;
102 tony 45 function getBufSize: integer;
103    
104     public
105     function GetCount: integer;
106     function GetItem(index: integer): POutputBlockItemData;
107     function Find(ItemType: byte): POutputBlockItemData;
108     property Count: integer read GetCount;
109     property Items[index: integer]: POutputBlockItemData read getItem; default;
110     end;
111    
112     { TOutputBlockItem }
113    
114     TOutputBlockItem = class(TFBInterfacedObject,IUnknown)
115     private
116     FOwner: TOutputBlock;
117     FOwnerIntf: IUnknown;
118     FItemData: POutputBlockItemData;
119     protected
120     function GetItem(index: integer): POutputBlockItemData;
121     function Find(ItemType: byte): POutputBlockItemData;
122 tony 56 procedure SetString(out S: AnsiString; Buf: PByte; Len: integer;
123 tony 45 CodePage: TSystemCodePage);
124     property ItemData: POutputBlockItemData read FItemData;
125     property Owner: TOutputBlock read FOwner;
126     public
127     constructor Create(AOwner: TOutputBlock; Data: POutputBlockItemData);
128     public
129     function GetCount: integer;
130     function getItemType: byte;
131     function getSize: integer;
132     procedure getRawBytes(var Buffer);
133     function getAsInteger: integer;
134     function getParamType: byte;
135 tony 56 function getAsString: AnsiString;
136 tony 45 function getAsByte: byte;
137     function getAsBytes: TByteArray;
138 tony 143 function getAsDateTime: TDateTime;
139 tony 45 function CopyTo(stream: TStream; count: integer): integer;
140     end;
141    
142 tony 56 TServiceQueryResultSubItem = class(TOutputBlockItem,IServiceQueryResultSubItem);
143    
144 tony 45 { TCustomOutputBlock }
145    
146 tony 56 {$IFDEF FPC}
147     TCustomOutputBlock<_TItem,_IItem> = class(TOutputBlock)
148     {$ELSE}
149     TOutputBlockItemClass = class of TOutputBlockItem;
150     TCustomOutputBlock<_TItem: TOutputBlockItem;_IItem: IUnknown> = class(TOutputBlock)
151     {$ENDIF}
152 tony 45 public
153     function getItem(index: integer): _IItem;
154     function find(ItemType: byte): _IItem;
155     property Items[index: integer]: _IItem read getItem; default;
156     end;
157    
158     { TOutputBlockItemGroup }
159    
160 tony 56 {$IFDEF FPC}
161     TOutputBlockItemGroup<_TItem,_IItem> = class(TOutputBlockItem)
162     {$ELSE}
163     TOutputBlockItemGroup<_TItem: TOutputBlockItem; _IItem: IUnknown> = class(TOutputBlockItem)
164     {$ENDIF}
165 tony 45 public
166     function GetItem(index: integer): _IItem;
167     function Find(ItemType: byte): _IItem;
168     property Items[index: integer]: _IItem read getItem; default;
169     end;
170    
171     { TDBInfoItem }
172    
173 tony 56 {$IFDEF FPC}
174     TDBInfoItem = class;
175    
176     TDBInfoItem = class(TOutputBlockItemGroup<TDBInfoItem,IDBInfoItem>,IDBInfoItem)
177     {$ELSE}
178     TDBInfoItem = class(TOutputBlockItemGroup<TOutputBlockItem,IDBInfoItem>,IDBInfoItem)
179     {$ENDIF}
180 tony 45 public
181 tony 56 procedure DecodeIDCluster(var ConnectionType: integer; var DBFileName, DBSiteName: AnsiString);
182     procedure DecodeVersionString(var Version: byte; var VersionString: AnsiString);
183 tony 45 procedure DecodeUserNames(UserNames: TStrings);
184     function getOperationCounts: TDBOperationCounts;
185 tony 143 end;
186 tony 45
187     { TDBInformation }
188    
189 tony 56 TDBInformation = class(TCustomOutputBlock<TDBInfoItem,IDBInfoItem>, IDBInformation)
190 tony 45 protected
191 tony 56 function AddSpecialItem(BufPtr: PByte): POutputBlockItemData; override;
192 tony 45 procedure DoParseBuffer; override;
193     public
194     constructor Create(aSize: integer=DBInfoDefaultBufferSize);
195 tony 143 {$IFNDEF FPC}
196     function Find(ItemType: byte): IDBInfoItem;
197     {$ENDIF}
198 tony 45 end;
199    
200     { TServiceQueryResultItem }
201    
202 tony 56 TServiceQueryResultItem = class(TOutputBlockItemGroup<TServiceQueryResultSubItem,IServiceQueryResultSubItem>,
203 tony 45 IServiceQueryResultItem);
204    
205     { TServiceQueryResults }
206    
207 tony 56 TServiceQueryResults = class(TCustomOutputBlock<TServiceQueryResultItem,IServiceQueryResultItem>, IServiceQueryResults)
208 tony 45 protected
209 tony 56 function AddListItem(BufPtr: PByte): POutputBlockItemData; override;
210     function AddSpecialItem(BufPtr: PByte): POutputBlockItemData; override;
211 tony 45 procedure DoParseBuffer; override;
212 tony 143 {$IFNDEF FPC}
213     public
214     function Find(ItemType: byte): IServiceQueryResultItem;
215     {$ENDIF}
216 tony 45 end;
217    
218 tony 56
219 tony 45 { ISQLInfoItem }
220    
221 tony 56 ISQLInfoSubItem = interface
222     ['{39852ee4-4851-44df-8dc0-26b991250098}']
223 tony 45 function getItemType: byte;
224     function getSize: integer;
225 tony 56 function getAsString: AnsiString;
226 tony 45 function getAsInteger: integer;
227 tony 56 end;
228    
229     ISQLInfoItem = interface(ISQLInfoSubItem)
230     ['{34e3c39d-fe4f-4211-a7e3-0266495a359d}']
231 tony 45 function GetCount: integer;
232 tony 56 function GetItem(index: integer): ISQLInfoSubItem;
233     function Find(ItemType: byte): ISQLInfoSubItem;
234 tony 45 property Count: integer read GetCount;
235 tony 56 property Items[index: integer]: ISQLInfoSubItem read getItem; default;
236 tony 45 end;
237    
238     {ISQLInfoResults}
239    
240     ISQLInfoResults = interface
241 tony 56 ['{0b3fbe20-6f80-44e7-85ef-e708bc1f2043}']
242 tony 45 function GetCount: integer;
243     function GetItem(index: integer): ISQLInfoItem;
244     function Find(ItemType: byte): ISQLInfoItem;
245     property Count: integer read GetCount;
246     property Items[index: integer]: ISQLInfoItem read getItem; default;
247     end;
248    
249 tony 56 TSQLInfoResultsSubItem = class(TOutputBlockItem,ISQLInfoSubItem);
250 tony 45
251     { TSQLInfoResultsItem }
252    
253 tony 56 TSQLInfoResultsItem = class(TOutputBlockItemGroup<TSQLInfoResultsSubItem,ISQLInfoSubItem>,ISQLInfoItem);
254 tony 45
255     { TSQLInfoResultsBuffer }
256    
257 tony 56 TSQLInfoResultsBuffer = class(TCustomOutputBlock<TSQLInfoResultsItem,ISQLInfoItem>, ISQLInfoResults)
258 tony 45 protected
259 tony 56 function AddListItem(BufPtr: PByte): POutputBlockItemData; override;
260 tony 45 procedure DoParseBuffer; override;
261     public
262     constructor Create(aSize: integer = 1024);
263     end;
264    
265 tony 56 IBlobInfoItem = interface
266     ['{3a55e558-b97f-4cf3-af95-53b84f4d9a65}']
267     function getItemType: byte;
268     function getSize: integer;
269     function getAsString: AnsiString;
270     function getAsInteger: integer;
271     end;
272    
273     IBlobInfo = interface
274     ['{8a340109-f600-4d26-ab1d-e0be2c759f1c}']
275     function GetCount: integer;
276     function GetItem(index: integer): IBlobInfoItem;
277     function Find(ItemType: byte): IBlobInfoItem;
278     property Count: integer read GetCount;
279     property Items[index: integer]: IBlobInfoItem read getItem; default;
280     end;
281    
282     {$IFDEF FPC}
283     TBlobInfoItem = class;
284    
285     TBlobInfoItem = class(TOutputBlockItemGroup<TBlobInfoItem,IBlobInfoItem>,IBlobInfoItem)
286     {$ELSE}
287     TBlobInfoItem = class(TOutputBlockItemGroup<TOutputBlockItem,IBlobInfoItem>,IBlobInfoItem)
288     {$ENDIF}
289    
290     end;
291    
292     { TBlobInfo }
293    
294     TBlobInfo = class(TCustomOutputBlock<TBlobInfoItem,IBlobInfoItem>, IBlobInfo)
295     protected
296     procedure DoParseBuffer; override;
297     public
298     constructor Create(aSize: integer=DBInfoDefaultBufferSize);
299     end;
300    
301 tony 45 implementation
302    
303 tony 56 uses FBMessages {$IFNDEF FPC}, TypInfo {$ENDIF};
304 tony 45
305 tony 144 function BufToStr(P: PByte; Len: integer):AnsiString;
306     begin
307     SetLength(Result,Len);
308     Move(P^,Result[1],Len);
309     end;
310    
311 tony 56 {$IFDEF FPC}
312 tony 45 { TOutputBlockItemGroup }
313    
314 tony 56 function TOutputBlockItemGroup<_TItem,_IItem>.GetItem(index: integer): _IItem;
315 tony 45 var P: POutputBlockItemData;
316     begin
317     P := inherited getItem(index);
318     Result := _TItem.Create(self.Owner,P);
319     end;
320    
321 tony 56 function TOutputBlockItemGroup<_TItem,_IItem>.Find(ItemType: byte): _IItem;
322 tony 45 var P: POutputBlockItemData;
323     begin
324     P := inherited Find(ItemType);
325     Result := _TItem.Create(self.Owner,P);
326     end;
327    
328     { TCustomOutputBlock }
329    
330 tony 56 function TCustomOutputBlock<_TItem,_IItem>.getItem(index: integer): _IItem;
331 tony 45 var P: POutputBlockItemData;
332     begin
333     P := inherited getItem(index);
334     Result := _TItem.Create(self,P)
335     end;
336    
337 tony 56 function TCustomOutputBlock<_TItem,_IItem>.find(ItemType: byte): _IItem;
338 tony 45 var P: POutputBlockItemData;
339     begin
340     P := inherited Find(ItemType);
341 tony 143 if P = nil then
342     Result := nil
343     else
344     Result := _TItem.Create(self,P)
345 tony 45 end;
346    
347 tony 56 {$ELSE}
348    
349 tony 45 { TOutputBlockItemGroup }
350    
351 tony 56 function TOutputBlockItemGroup<_TItem,_IItem>.GetItem(index: integer): _IItem;
352     var P: POutputBlockItemData;
353     Obj: TOutputBlockItem;
354     begin
355     P := inherited getItem(index);
356     Obj := TOutputBlockItemClass(_TItem).Create(self.Owner,P);
357     if Obj.QueryInterface(GetTypeData(TypeInfo(_IItem))^.Guid,Result) <> 0 then
358     IBError(ibxeInterfaceNotSupported,[GuidToString(GetTypeData(TypeInfo(_IItem))^.Guid)]);
359     end;
360    
361     function TOutputBlockItemGroup<_TItem,_IItem>.Find(ItemType: byte): _IItem;
362     var P: POutputBlockItemData;
363     Obj: TOutputBlockItem;
364     begin
365     P := inherited Find(ItemType);
366 tony 143 if P = nil then
367     Result := Default(_IITEM)
368     else
369     begin
370     Obj := TOutputBlockItemClass(_TItem).Create(self.Owner,P);
371     if Obj.QueryInterface(GetTypeData(TypeInfo(_IItem))^.Guid,Result) <> 0 then
372     IBError(ibxeInterfaceNotSupported,[GuidToString(GetTypeData(TypeInfo(_IItem))^.Guid)]);
373     end;
374 tony 56 end;
375    
376     { TCustomOutputBlock }
377    
378     function TCustomOutputBlock<_TItem,_IItem>.getItem(index: integer): _IItem;
379     var P: POutputBlockItemData;
380     Obj: TOutputBlockItem;
381     begin
382     P := inherited getItem(index);
383     Obj := TOutputBlockItemClass(_TItem).Create(self,P);
384     if Obj.QueryInterface(GetTypeData(TypeInfo(_IItem))^.Guid,Result) <> 0 then
385     IBError(ibxeInterfaceNotSupported,[GuidToString(GetTypeData(TypeInfo(_IItem))^.Guid)]);
386     end;
387    
388     function TCustomOutputBlock<_TItem,_IItem>.find(ItemType: byte): _IItem;
389     var P: POutputBlockItemData;
390     Obj: TOutputBlockItem;
391     begin
392     P := inherited Find(ItemType);
393     Obj := TOutputBlockItemClass(_TItem).Create(self,P);
394     if Obj.QueryInterface(GetTypeData(TypeInfo(_IItem))^.Guid,Result) <> 0 then
395     IBError(ibxeInterfaceNotSupported,[GuidToString(GetTypeData(TypeInfo(_IItem))^.Guid)]);
396     end;
397    
398     {$ENDIF}
399    
400     { TOutputBlockItem }
401    
402 tony 45 function TOutputBlockItem.GetCount: integer;
403     begin
404     Result := Length(FItemData^.FSubItems);
405     end;
406    
407     function TOutputBlockItem.GetItem(index: integer): POutputBlockItemData;
408     begin
409     if (index >= 0) and (index < Length(FItemData^.FSubItems)) then
410     Result := FItemData^.FSubItems[index]
411     else
412     with FirebirdClientAPI do
413     IBError(ibxeOutputBlockIndexError,[index]);
414     end;
415    
416     function TOutputBlockItem.Find(ItemType: byte): POutputBlockItemData;
417     var i: integer;
418     begin
419     Result := nil;
420     for i := 0 to GetCount - 1 do
421 tony 56 if byte(FItemData^.FSubItems[i]^.FBufPtr^) = ItemType then
422 tony 45 begin
423     Result := FItemData^.FSubItems[i];
424     Exit;
425     end;
426     end;
427    
428     { TOutputBlockItem }
429    
430 tony 56 procedure TOutputBlockItem.SetString(out S: AnsiString; Buf: PByte;
431     Len: integer; CodePage: TSystemCodePage);
432 tony 45 var rs: RawByteString;
433 tony 209 i: integer;
434 tony 45 begin
435 tony 209 {There seems to be a memory manager problem with SetString that can cause
436     an unhandled exception at the end of a program if it is used to set the
437     string. Safer to copy characters one by one. Note that Setlength does
438     not work around the bug either.}
439     rs := '';
440     for i := 0 to len-1 do
441     rs := rs + PAnsiChar(buf+i)^;
442     // system.SetString(rs,PAnsiChar(Buf),len);
443 tony 45 SetCodePage(rs,CodePage,false);
444     S := rs;
445     end;
446    
447     constructor TOutputBlockItem.Create(AOwner: TOutputBlock;
448     Data: POutputBlockItemData);
449     begin
450     inherited Create;
451     FOwner := AOwner;
452     FOwnerIntf := AOwner;
453     FItemData := Data;
454     end;
455    
456     function TOutputBlockItem.getItemType: byte;
457     begin
458     Result := byte(FItemData^.FBufPtr^);
459     end;
460    
461     function TOutputBlockItem.getSize: integer;
462     begin
463 tony 143 if FItemData = nil then
464     Result := 0
465     else
466     Result := FItemData^.FDataLength;
467 tony 45 end;
468    
469     procedure TOutputBlockItem.getRawBytes(var Buffer);
470     begin
471     with FItemData^ do
472     Move(FBufPtr^,Buffer,FDatalength);
473     end;
474    
475     function TOutputBlockItem.getAsInteger: integer;
476     var len: integer;
477     begin
478     with FItemData^ do
479     case FDataType of
480     dtIntegerFixed:
481     with FirebirdClientAPI do
482     Result := DecodeInteger(FBufPtr+1,4);
483    
484     dtByte,
485     dtInteger:
486     with FirebirdClientAPI do
487     begin
488     len := DecodeInteger(FBufPtr+1,2);
489     Result := DecodeInteger(FBufPtr+3,len);
490     end;
491     else
492     IBError(ibxeOutputBlockTypeError,[nil]);
493     end;
494     end;
495    
496     function TOutputBlockItem.getParamType: byte;
497     begin
498     Result := byte(FItemData^.FBufPtr^)
499     end;
500    
501 tony 56 function TOutputBlockItem.getAsString: AnsiString;
502 tony 45 var len: integer;
503     begin
504     Result := '';
505     with FItemData^ do
506     case FDataType of
507 tony 144 dtIntegerFixed,
508 tony 45 dtInteger:
509     Result := IntToStr(getAsInteger);
510     dtByte:
511     Result := IntToStr(getAsByte);
512     dtString:
513     begin
514     len := byte((FBufPtr+1)^);
515     SetString(Result,FBufPtr+2,len,CP_ACP);
516     end;
517     dtString2:
518     begin
519     with FirebirdClientAPI do
520     len := DecodeInteger(FBufPtr+1,2);
521     SetString(Result,FBufPtr+3,len,CP_ACP);
522     end;
523 tony 143 dtOctetString:
524     begin
525     with FirebirdClientAPI do
526     len := DecodeInteger(FBufPtr+1,2);
527     SetString(Result,FBufPtr+3,len,CP_NONE);
528     end;
529 tony 45 else
530     IBError(ibxeOutputBlockTypeError,[nil]);
531     end;
532     end;
533    
534     function TOutputBlockItem.getAsByte: byte;
535     begin
536     with FItemData^ do
537     if FDataType = dtByte then
538     Result := byte((FBufPtr+2)^)
539     else
540     IBError(ibxeOutputBlockTypeError,[nil]);
541     end;
542    
543     function TOutputBlockItem.getAsBytes: TByteArray;
544     var i: integer;
545 tony 56 P: PByte;
546 tony 45 begin
547     with FItemData^ do
548     if FDataType = dtBytes then
549     begin
550     SetLength(Result,FDataLength);
551     P := FBufPtr;
552     for i := 0 to FDataLength - 1 do
553     begin
554     Result[i] := byte(P^);
555     Inc(P);
556     end
557     end
558     else
559     IBError(ibxeOutputBlockTypeError,[nil]);
560     end;
561    
562 tony 143 function TOutputBlockItem.getAsDateTime: TDateTime;
563     var aDate: integer;
564     aTime: integer;
565     begin
566     with FItemData^, FirebirdClientAPI do
567     if FDataType = dtDateTime then
568     begin
569     aDate := DecodeInteger(FBufPtr+3,4);
570     aTime := DecodeInteger(FBufPtr+7,4);
571     Result := SQLDecodeDate(@aDate) + SQLDecodeTime(@aTime)
572     end
573     else
574     IBError(ibxeOutputBlockTypeError,[nil]);
575     end;
576    
577    
578 tony 45 function TOutputBlockItem.CopyTo(stream: TStream; count: integer): integer;
579     var len: integer;
580     begin
581     if count < 0 then count := 0;
582     with FItemData^ do
583     begin
584     case FDataType of
585     dtString:
586     begin
587     len := byte((FBufPtr+1)^);
588     if (count > 0) and (count < len) then len := count;
589     Result := stream.Write((FBufPtr+2)^,len);
590     end;
591     dtString2:
592     begin
593     with FirebirdClientAPI do
594     len := DecodeInteger(FBufPtr+1,2);
595     if (count > 0) and (count < len) then len := count;
596     Result := stream.Write((FBufPtr+3)^,len);
597     end;
598     else
599     IBError(ibxeOutputBlockTypeError,[nil]);
600     end;
601     end;
602     end;
603    
604     { TOutputBlock }
605    
606     procedure TOutputBlock.ParseBuffer;
607     begin
608     if not FBufferParsed then
609     begin
610     {$IFDEF DEBUGOUTPUTBLOCK}
611     PrintBuf;
612     {$ENDIF}
613     DoParseBuffer;
614     if FError or FTruncated then
615     SetLength(FItems,Length(FItems)-1);
616     {$IFDEF DEBUGOUTPUTBLOCK}
617     FormattedPrint(FItems,'');
618     {$ENDIF}
619     end;
620     FBufferParsed := true;
621     end;
622    
623 tony 56 function TOutputBlock.AddItem(BufPtr: PByte): POutputBlockItemData;
624 tony 45 begin
625     new(Result);
626     with Result^ do
627     begin
628     FDataType := dtNone;
629     FBufPtr := BufPtr;
630     FDataLength := 0;
631     FSize := 1;
632     SetLength(FSubItems,0);
633     end;
634     end;
635    
636 tony 56 function TOutputBlock.AddIntegerItem(BufPtr: PByte): POutputBlockItemData;
637 tony 45 begin
638     new(Result);
639     with Result^ do
640     begin
641     FDataType := FIntegerType;
642     FBufPtr := BufPtr;
643     if FDataType = dtIntegerFixed then
644     begin
645     FDataLength := 4;
646     FSize := 5;
647     end
648     else
649     begin
650     with FirebirdClientAPI do
651     FDataLength := DecodeInteger(FBufPtr+1, 2);
652     FSize := FDataLength + 3;
653     end;
654     SetLength(FSubItems,0);
655     end;
656     end;
657    
658 tony 56 function TOutputBlock.AddStringItem(BufPtr: PByte): POutputBlockItemData;
659 tony 45 begin
660     new(Result);
661     with Result^ do
662     begin
663     FDataType := dtString2;
664     FBufPtr := BufPtr;
665     with FirebirdClientAPI do
666     FDataLength := DecodeInteger(FBufPtr+1, 2);
667     FSize := FDataLength + 3;
668     SetLength(FSubItems,0);
669     end;
670     end;
671    
672 tony 56 function TOutputBlock.AddShortStringItem(BufPtr: PByte): POutputBlockItemData;
673 tony 45 begin
674     new(Result);
675     with Result^ do
676     begin
677     FDataType := dtString;
678     FBufPtr := BufPtr;
679     FDataLength := byte((FBufPtr+1)^);
680     FSize := FDataLength + 2;
681     SetLength(FSubItems,0);
682     end;
683     end;
684    
685 tony 56 function TOutputBlock.AddByteItem(BufPtr: PByte): POutputBlockItemData;
686 tony 45 begin
687     new(Result);
688     with Result^ do
689     begin
690     FDataType := dtByte;
691     FBufPtr := BufPtr;
692     FDataLength := 1;
693     FSize := 2;
694     SetLength(FSubItems,0);
695     end;
696     end;
697    
698 tony 56 function TOutputBlock.AddBytesItem(BufPtr: PByte): POutputBlockItemData;
699 tony 45 begin
700     new(Result);
701     with Result^ do
702     begin
703     FDataType := dtBytes;
704     FBufPtr := BufPtr;
705     with FirebirdClientAPI do
706     FDataLength := DecodeInteger(FBufPtr+1, 2);
707     FSize := FDataLength + 3;
708     SetLength(FSubItems,0);
709     end;
710     end;
711    
712 tony 56 function TOutputBlock.AddListItem(BufPtr: PByte): POutputBlockItemData;
713 tony 45 begin
714     new(Result);
715     with Result^ do
716     begin
717     FDataType := dtList;
718     FBufPtr := BufPtr;
719     FSize := FBuffer + FBufSize - FBufPtr;
720     FDataLength := FSize - 1;
721     SetLength(FSubItems,0);
722     end;
723     end;
724    
725 tony 56 function TOutputBlock.AddSpecialItem(BufPtr: PByte): POutputBlockItemData;
726 tony 45 begin
727     new(Result);
728     with Result^ do
729     begin
730     FDataType := dtSpecial;
731     FBufPtr := BufPtr;
732     FSize := FBuffer + FBufSize - FBufPtr;
733     FDataLength := FSize - 1;
734     SetLength(FSubItems,0);
735     end;
736     end;
737    
738 tony 143 function TOutputBlock.AddDateTimeItem(BufPtr: PByte): POutputBlockItemData;
739     begin
740     new(Result);
741     with Result^ do
742     begin
743     FDataType := dtDateTime;
744     FBufPtr := BufPtr;
745     with FirebirdClientAPI do
746     FDataLength := DecodeInteger(FBufPtr+1, 2);
747     FSize := FDataLength + 3;
748     SetLength(FSubItems,0);
749     end;
750     end;
751    
752     function TOutputBlock.AddOctetString(BufPtr: PByte): POutputBlockItemData;
753     begin
754     new(Result);
755     with Result^ do
756     begin
757     FDataType := dtOctetString;
758     FBufPtr := BufPtr;
759     with FirebirdClientAPI do
760     FDataLength := DecodeInteger(FBufPtr+1, 2);
761     FSize := FDataLength + 3;
762     SetLength(FSubItems,0);
763     end;
764     end;
765    
766 tony 45 constructor TOutputBlock.Create(aSize: integer);
767     begin
768     inherited Create;
769     FBufSize := aSize;
770     GetMem(FBuffer,aSize);
771     if FBuffer = nil then
772     OutOfMemoryError;
773     FillChar(FBuffer^,aSize,255);
774     FBufferParsed := false;
775     FIntegerType := dtIntegerFixed;
776     end;
777    
778     destructor TOutputBlock.Destroy;
779     var i, j: integer;
780     begin
781     for i := 0 to length(FItems) - 1 do
782     begin
783 tony 144 if FItems[i] <> nil then
784     begin
785     for j := 0 to Length(FItems[i]^.FSubItems) -1 do
786     if FItems[i]^.FSubItems[j] <> nil then
787     dispose(FItems[i]^.FSubItems[j]);
788     dispose(FItems[i]);
789     end;
790 tony 45 end;
791     FreeMem(FBuffer);
792     inherited Destroy;
793     end;
794    
795 tony 56 function TOutputBlock.Buffer: PByte;
796 tony 45 begin
797     Result := FBuffer;
798     end;
799    
800     function TOutputBlock.getBufSize: integer;
801     begin
802     Result := FBufSize;
803     end;
804    
805     function TOutputBlock.GetCount: integer;
806     begin
807     ParseBuffer;
808     Result := length(FItems);
809     end;
810    
811     function TOutputBlock.GetItem(index: integer): POutputBlockItemData;
812     begin
813     ParseBuffer;
814     if (index >= 0) and (index < Length(FItems)) then
815     Result := FItems[index]
816     else
817     IBError(ibxeOutputBlockIndexError,[index]);
818     end;
819    
820     function TOutputBlock.Find(ItemType: byte): POutputBlockItemData;
821     var i: integer;
822     begin
823     Result := nil;
824     for i := 0 to getCount - 1 do
825 tony 56 if byte(FItems[i]^.FBufPtr^) = ItemType then
826 tony 45 begin
827     Result := FItems[i];
828     Exit;
829     end;
830     end;
831    
832     {$IFDEF DEBUGOUTPUTBLOCK}
833     procedure TOutputBlock.FormattedPrint(
834 tony 56 const aItems: array of POutputBlockItemData; Indent: AnsiString);
835 tony 45
836     var i: integer;
837     item: TOutputBlockItem;
838     begin
839     if FError then
840     writeln('Error')
841     else
842     if FTruncated then
843     writeln('Truncated')
844     else
845     for i := 0 to Length(aItems) - 1 do
846     with aItems[i]^ do
847     begin
848     if FError then
849     writeln('Error')
850     else
851     if FTruncated then
852     writeln('Truncated')
853     else
854     case FDataType of
855     dtList:
856     begin
857     writeln(Indent,'ItemType = ',byte(FBufPtr^));
858     FormattedPrint(FSubItems,Indent + ' ');
859     end;
860     dtSpecial:
861     writeln(Indent,'ItemType = ',byte(FBufPtr^),' Length = ',FSize);
862     else
863     begin
864     item := TOutputBlockItem.Create(self,(aItems[i]));
865 tony 144 try
866     writeln(Indent,'ItemType = ',byte(FBufPtr^),' Value = ',(item as TOutputBlockItem).GetAsString);
867     except
868     writeln(Indent,'Unknown ItemType = ',byte(FBufPtr^));
869     end;
870 tony 45 end;
871     end;
872     end;
873     end;
874     {$ENDIF}
875    
876     procedure TOutputBlock.PrintBuf;
877     var i: integer;
878     begin
879     write(classname,': ');
880     for i := 0 to getBufSize - 1 do
881     begin
882     write(Format('%x ',[byte(Buffer[i])]));
883     if byte(FBuffer[i]) = isc_info_end then break;
884     end;
885     writeln;
886 tony 144 for i := 0 to getBufSize - 1 do
887     begin
888     if chr(FBuffer[i]) in [' '..'~'] then
889     write(chr(Buffer[i]))
890     else
891     write('.');
892     if byte(FBuffer[i]) = isc_info_end then break;
893     end;
894     writeln;
895 tony 45 end;
896    
897     { TDBInfoItem }
898    
899     procedure TDBInfoItem.DecodeIDCluster(var ConnectionType: integer;
900 tony 56 var DBFileName, DBSiteName: AnsiString);
901     var P: PByte;
902 tony 45 begin
903     with ItemData^ do
904 tony 56 if FBufPtr^ = isc_info_db_id then
905 tony 45 begin
906     P := FBufPtr + 3;
907     if FDataLength > 0 then
908     ConnectionType := integer(P^);
909     Inc(P);
910     SetString(DBFileName,P+1,byte(P^),CP_ACP);
911 tony 56 P := P + Length(DBFileName) + 1;
912 tony 45 SetString(DBSiteName,P+1,byte(P^),CP_ACP);
913     end
914     else
915     IBError(ibxeInfoBufferTypeError,[integer(FBufPtr^)]);
916     end;
917    
918     procedure TDBInfoItem.DecodeVersionString(var Version: byte;
919 tony 56 var VersionString: AnsiString);
920     var P: PByte;
921 tony 45 begin
922     with ItemData^ do
923 tony 56 if FBufPtr^ = isc_info_version then
924 tony 45 begin
925     P := FBufPtr+3;
926     VersionString := '';
927     Version := byte(P^);
928     Inc(P);
929     SetString(VersionString,P+1,byte(P^),CP_ACP);
930     end
931     else
932     IBError(ibxeInfoBufferTypeError,[integer(FBufPtr^)]);
933     end;
934    
935     procedure TDBInfoItem.DecodeUserNames(UserNames: TStrings);
936 tony 56 var P: PByte;
937     s: AnsiString;
938 tony 45 begin
939     with ItemData^ do
940 tony 56 if FBufPtr^ = isc_info_user_names then
941 tony 45 begin
942     P := FBufPtr+3;
943     while (P < FBufPtr + FSize) do
944     begin
945     SetString(s,P+1,byte(P^),CP_ACP);
946     UserNames.Add(s);
947 tony 56 P := P + Length(s) + 1;
948 tony 45 end;
949     end
950     else
951     IBError(ibxeInfoBufferTypeError,[integer(FBufPtr^)]);
952     end;
953    
954     function TDBInfoItem.getOperationCounts: TDBOperationCounts;
955     var tableCounts: integer;
956 tony 56 P: PByte;
957 tony 45 i: integer;
958     begin
959     with ItemData^ do
960     if byte(FBufPtr^) in [isc_info_backout_count, isc_info_delete_count,
961     isc_info_expunge_count,isc_info_insert_count, isc_info_purge_count,
962     isc_info_read_idx_count, isc_info_read_seq_count, isc_info_update_count] then
963     begin
964     tableCounts := FDataLength div 6;
965     SetLength(Result,TableCounts);
966     P := FBufPtr + 3;
967     for i := 0 to TableCounts -1 do
968     with FirebirdClientAPI do
969     begin
970     Result[i].TableID := DecodeInteger(P,2);
971     Inc(P,2);
972     Result[i].Count := DecodeInteger(P,4);
973     Inc(P,4);
974     end;
975     end
976     else
977     IBError(ibxeInfoBufferTypeError,[integer(FBufPtr^)]);
978     end;
979    
980     { TDBInformation }
981    
982 tony 56 function TDBInformation.AddSpecialItem(BufPtr: PByte): POutputBlockItemData;
983 tony 45 begin
984     Result := inherited AddSpecialItem(BufPtr);
985     with Result^ do
986     begin
987     with FirebirdClientAPI do
988     FDataLength := DecodeInteger(FBufPtr+1,2);
989     FSize := FDataLength + 3;
990     end;
991     end;
992    
993     procedure TDBInformation.DoParseBuffer;
994 tony 56 var P: PByte;
995 tony 45 index: integer;
996     begin
997     P := Buffer;
998     index := 0;
999     SetLength(FItems,0);
1000 tony 56 while (P^ <> isc_info_end) and (P < Buffer + getBufSize) do
1001 tony 45 begin
1002     SetLength(FItems,index+1);
1003     case byte(P^) of
1004 tony 61 isc_info_db_read_only,
1005 tony 45 isc_info_no_reserve,
1006     isc_info_allocation,
1007     isc_info_ods_minor_version,
1008     isc_info_ods_version,
1009     isc_info_db_SQL_dialect,
1010     isc_info_page_size,
1011     isc_info_current_memory,
1012     isc_info_forced_writes,
1013     isc_info_max_memory,
1014     isc_info_num_buffers,
1015     isc_info_sweep_interval,
1016     isc_info_fetches,
1017     isc_info_marks,
1018     isc_info_reads,
1019 tony 143 isc_info_writes,
1020     isc_info_active_tran_count,
1021     fb_info_pages_used,
1022     fb_info_pages_free,
1023     fb_info_conn_flags:
1024 tony 45 FItems[index] := AddIntegerItem(P);
1025    
1026     isc_info_implementation,
1027     isc_info_base_level:
1028     FItems[index] := AddBytesItem(P);
1029    
1030 tony 143 isc_info_creation_date:
1031     FItems[index] := AddDateTimeItem(P);
1032    
1033     fb_info_page_contents:
1034     FItems[index] := AddOctetString(P);
1035    
1036     fb_info_crypt_key:
1037     FItems[index] := AddStringItem(P);
1038    
1039 tony 45 isc_info_db_id,
1040     isc_info_version,
1041     isc_info_backout_count,
1042     isc_info_delete_count,
1043     isc_info_expunge_count,
1044     isc_info_insert_count,
1045     isc_info_purge_count,
1046     isc_info_read_idx_count,
1047     isc_info_read_seq_count,
1048     isc_info_update_count,
1049     isc_info_user_names:
1050     FItems[index] := AddSpecialItem(P);
1051    
1052     else
1053     FItems[index] := AddSpecialItem(P);
1054     end;
1055 tony 56 P := P + FItems[index]^.FSize;
1056 tony 45 Inc(index);
1057     end;
1058     end;
1059    
1060 tony 143 {$IFNDEF FPC}
1061     function TDBInformation.Find(ItemType: byte): IDBInfoItem;
1062     begin
1063     Result := inherited Find(ItemType);
1064     if Result.GetSize = 0 then
1065     Result := nil;
1066     end;
1067     {$ENDIF}
1068    
1069 tony 45 constructor TDBInformation.Create(aSize: integer);
1070     begin
1071     inherited Create(aSize);
1072     FIntegerType := dtInteger;
1073     end;
1074    
1075     { TServiceQueryResults }
1076    
1077 tony 56 function TServiceQueryResults.AddListItem(BufPtr: PByte): POutputBlockItemData;
1078     var P: PByte;
1079 tony 45 i: integer;
1080     group: byte;
1081     begin
1082     Result := inherited AddListItem(BufPtr);
1083     P := BufPtr + 1;
1084     i := 0;
1085     group := byte(BufPtr^);
1086     if group in [isc_info_svc_get_users,isc_info_svc_limbo_trans] then
1087     begin
1088     with FirebirdClientAPI do
1089     Result^.FSize := DecodeInteger(P,2) + 3;
1090     Inc(P,2);
1091     end;
1092     with Result^ do
1093     begin
1094 tony 56 while (P < FBufPtr + FSize) and (P^ <> isc_info_flag_end) do
1095 tony 45 begin
1096     SetLength(FSubItems,i+1);
1097 tony 144 FSubItems[i] := nil;
1098 tony 45 case group of
1099     isc_info_svc_svr_db_info:
1100     case integer(P^) of
1101     isc_spb_num_att,
1102     isc_spb_num_db:
1103     FSubItems[i] := AddIntegerItem(P);
1104    
1105     isc_spb_dbname:
1106     FSubItems[i] := AddStringItem(P);
1107    
1108     else
1109 tony 144 IBError(ibxeOutputParsingError, [integer(P^),BufToStr(P,FSize - (P-FBufPtr))]);
1110 tony 45 end;
1111    
1112     isc_info_svc_get_license:
1113     case integer(P^) of
1114     isc_spb_lic_id,
1115     isc_spb_lic_key:
1116     FSubItems[i] := AddIntegerItem(P);
1117     else
1118 tony 144 IBError(ibxeOutputParsingError, [integer(P^),BufToStr(P,FSize - (P-FBufPtr))]);
1119 tony 45 end;
1120    
1121     isc_info_svc_limbo_trans:
1122     case integer(P^) of
1123     isc_spb_tra_id,
1124     isc_spb_single_tra_id,
1125     isc_spb_multi_tra_id:
1126     FSubItems[i] := AddIntegerItem(P);
1127    
1128     isc_spb_tra_host_site,
1129     isc_spb_tra_remote_site,
1130     isc_spb_tra_db_path:
1131     FSubItems[i] := AddStringItem(P);
1132    
1133     isc_spb_tra_advise,
1134     isc_spb_tra_state:
1135     FSubItems[i] := AddByteItem(P);
1136     else
1137 tony 144 IBError(ibxeOutputParsingError, [integer(P^),BufToStr(P,FSize - (P-FBufPtr))]);
1138 tony 45 end;
1139    
1140     isc_info_svc_get_users:
1141     case integer(P^) of
1142 tony 143 isc_spb_sec_admin,
1143 tony 45 isc_spb_sec_userid,
1144     isc_spb_sec_groupid:
1145     FSubItems[i] := AddIntegerItem(P);
1146    
1147     isc_spb_sec_username,
1148     isc_spb_sec_password,
1149     isc_spb_sec_firstname,
1150     isc_spb_sec_middlename,
1151     isc_spb_sec_lastname:
1152     FSubItems[i] := AddStringItem(P);
1153    
1154     else
1155 tony 144 IBError(ibxeOutputParsingError, [integer(P^),BufToStr(P,FSize - (P-FBufPtr))]);
1156 tony 45 end;
1157    
1158     end;
1159 tony 56 P := P + FSubItems[i]^.FSize;
1160 tony 45 Inc(i);
1161     end;
1162     FDataLength := 0;
1163     for i := 0 to Length(FSubItems) - 1 do
1164 tony 56 FDataLength := FDataLength + FSubItems[i]^.FSize;
1165 tony 45 if group in [isc_info_svc_get_users,isc_info_svc_limbo_trans] then
1166     Exit;
1167    
1168 tony 56 if (P < FBufPtr + FSize) and (P^ = isc_info_flag_end) then
1169 tony 45 FSize := FDataLength + 2 {include start and end flag}
1170     else
1171     FSize := FDataLength + 1; {start flag only}
1172     end;
1173     end;
1174    
1175 tony 56 function TServiceQueryResults.AddSpecialItem(BufPtr: PByte
1176 tony 45 ): POutputBlockItemData;
1177 tony 56 var P: PByte;
1178 tony 45 i: integer;
1179     begin
1180     Result := inherited AddSpecialItem(BufPtr);
1181     with Result^ do
1182     begin
1183     with FirebirdClientAPI do
1184     FDataLength := DecodeInteger(FBufPtr+1, 2);
1185    
1186     P := FBufPtr + 3; {skip length bytes}
1187     i := 0;
1188     while P < FBufPtr + FDataLength do
1189     begin
1190     FSubItems[i] := AddIntegerItem(P);
1191 tony 56 P := P + FSubItems[i]^.FSize;
1192 tony 45 Inc(i);
1193     end;
1194     end;
1195     end;
1196    
1197     procedure TServiceQueryResults.DoParseBuffer;
1198 tony 56 var P: PByte;
1199 tony 45 i: integer;
1200     begin
1201     P := Buffer;
1202     i := 0;
1203 tony 56 while (P < Buffer + getBufSize) and (P^ <> isc_info_end) do
1204 tony 45 begin
1205     SetLength(FItems,i+1);
1206 tony 144 FItems[i] := nil;
1207 tony 45 case integer(P^) of
1208     isc_info_svc_line,
1209     isc_info_svc_get_env,
1210     isc_info_svc_get_env_lock,
1211     isc_info_svc_get_env_msg,
1212     isc_info_svc_user_dbpath,
1213     isc_info_svc_server_version,
1214     isc_info_svc_implementation,
1215     isc_info_svc_to_eof:
1216     FItems[i] := AddStringItem(P);
1217    
1218     isc_info_svc_get_license_mask,
1219     isc_info_svc_capabilities,
1220     isc_info_svc_version,
1221     isc_info_svc_running,
1222     isc_info_svc_stdin:
1223     FItems[i] := AddIntegerItem(P);
1224    
1225     isc_info_svc_timeout,
1226     isc_info_data_not_ready,
1227     isc_info_truncated:
1228     FItems[i] := AddItem(P);
1229    
1230     isc_info_svc_svr_db_info,
1231     isc_info_svc_get_license,
1232     isc_info_svc_limbo_trans,
1233     isc_info_svc_get_users:
1234     FItems[i] := AddListItem(P);
1235    
1236     isc_info_svc_get_config:
1237     FItems[i] := AddSpecialItem(P);
1238    
1239    
1240     else
1241 tony 144 IBError(ibxeOutputParsingError, [integer(P^),BufToStr(P,getBufSize - (P-Buffer))]);
1242 tony 45 end;
1243 tony 56 P := P + FItems[i]^.FSize;
1244 tony 45 Inc(i);
1245     end;
1246     end;
1247    
1248 tony 143 {$IFNDEF FPC}
1249     function TServiceQueryResults.Find(ItemType: byte): IServiceQueryResultItem;
1250     begin
1251     Result := inherited Find(ItemType);
1252     if Result.GetSize = 0 then
1253     Result := nil;
1254     end;
1255     {$ENDIF}
1256    
1257 tony 45 { TSQLInfoResultsBuffer }
1258    
1259 tony 56 function TSQLInfoResultsBuffer.AddListItem(BufPtr: PByte): POutputBlockItemData;
1260     var P: PByte;
1261 tony 45 i: integer;
1262     begin
1263     Result := inherited AddListItem(BufPtr);
1264     P := BufPtr + 1;
1265     i := 0;
1266    
1267     if byte(BufPtr^) = isc_info_sql_records then
1268     begin
1269     with FirebirdClientAPI do
1270     Result^.FSize := DecodeInteger(P,2) + 3;
1271     Inc(P,2);
1272     with Result^ do
1273     begin
1274     while (P < FBufPtr + FSize) and (byte(P^) <> isc_info_end) do
1275     begin
1276     SetLength(FSubItems,i+1);
1277     case integer(P^) of
1278     isc_info_req_select_count,
1279     isc_info_req_insert_count,
1280     isc_info_req_update_count,
1281     isc_info_req_delete_count:
1282     FSubItems[i] := AddIntegerItem(P);
1283    
1284     isc_info_truncated:
1285     begin
1286     FTruncated := true;
1287     Exit;
1288     end;
1289    
1290     isc_info_error:
1291     begin
1292     FError := true;
1293     Exit;
1294     end;
1295     else
1296     FSubItems[i] := AddSpecialItem(P);
1297     end;
1298 tony 56 P := P + FSubItems[i]^.FSize;
1299 tony 45 Inc(i);
1300     end;
1301     end;
1302     end;
1303     end;
1304    
1305     procedure TSQLInfoResultsBuffer.DoParseBuffer;
1306 tony 56 var P: PByte;
1307 tony 45 index: integer;
1308     begin
1309     P := Buffer;
1310     index := 0;
1311     SetLength(FItems,0);
1312 tony 56 while (P^ <> isc_info_end) and (P < Buffer + getBufSize) do
1313 tony 45 begin
1314     SetLength(FItems,index+1);
1315     case byte(P^) of
1316     isc_info_sql_stmt_type:
1317     FItems[index] := AddIntegerItem(P);
1318    
1319     isc_info_sql_get_plan:
1320     FItems[index] := AddStringItem(P);
1321    
1322     isc_info_sql_records:
1323     FItems[index] := AddListItem(P);
1324    
1325     isc_info_truncated:
1326     begin
1327     FTruncated := true;
1328     Exit;
1329     end;
1330    
1331     isc_info_error:
1332     begin
1333     FError := true;
1334     Exit;
1335     end;
1336    
1337     else
1338     FItems[index] := AddSpecialItem(P);
1339     end;
1340 tony 56 P := P + FItems[index]^.FSize;
1341 tony 45 Inc(index);
1342     end;
1343     end;
1344    
1345     constructor TSQLInfoResultsBuffer.Create(aSize: integer);
1346     begin
1347     inherited Create(aSize);
1348     FIntegerType := dtInteger;
1349     end;
1350    
1351 tony 56 { TBlobInfo }
1352    
1353     procedure TBlobInfo.DoParseBuffer;
1354     var P: PByte;
1355     index: integer;
1356     begin
1357     P := Buffer;
1358     index := 0;
1359     SetLength(FItems,0);
1360     while (P^ <> isc_info_end) and (P < Buffer + getBufSize) do
1361     begin
1362     SetLength(FItems,index+1);
1363     case byte(P^) of
1364     isc_info_blob_num_segments,
1365     isc_info_blob_max_segment,
1366     isc_info_blob_total_length,
1367     isc_info_blob_type:
1368     FItems[index] := AddIntegerItem(P);
1369     else
1370     FItems[index] := AddSpecialItem(P);
1371     end;
1372     P := P + FItems[index]^.FSize;
1373     Inc(index);
1374     end;
1375     end;
1376    
1377     constructor TBlobInfo.Create(aSize: integer);
1378     begin
1379     inherited Create(aSize);
1380     FIntegerType := dtInteger;
1381     end;
1382    
1383 tony 45 end.
1384