ViewVC Help
View File | Revision Log | Show Annotations | Download File | View Changeset | Root Listing
root/public/ibx/trunk/fbintf/client/FBOutputBlock.pas
Revision: 144
Committed: Sat Feb 24 23:15:51 2018 UTC (6 years, 2 months ago) by tony
Content type: text/x-pascal
File size: 34764 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     begin
434 tony 56 system.SetString(rs,PAnsiChar(Buf),len);
435 tony 45 SetCodePage(rs,CodePage,false);
436     S := rs;
437     end;
438    
439     constructor TOutputBlockItem.Create(AOwner: TOutputBlock;
440     Data: POutputBlockItemData);
441     begin
442     inherited Create;
443     FOwner := AOwner;
444     FOwnerIntf := AOwner;
445     FItemData := Data;
446     end;
447    
448     function TOutputBlockItem.getItemType: byte;
449     begin
450     Result := byte(FItemData^.FBufPtr^);
451     end;
452    
453     function TOutputBlockItem.getSize: integer;
454     begin
455 tony 143 if FItemData = nil then
456     Result := 0
457     else
458     Result := FItemData^.FDataLength;
459 tony 45 end;
460    
461     procedure TOutputBlockItem.getRawBytes(var Buffer);
462     begin
463     with FItemData^ do
464     Move(FBufPtr^,Buffer,FDatalength);
465     end;
466    
467     function TOutputBlockItem.getAsInteger: integer;
468     var len: integer;
469     begin
470     with FItemData^ do
471     case FDataType of
472     dtIntegerFixed:
473     with FirebirdClientAPI do
474     Result := DecodeInteger(FBufPtr+1,4);
475    
476     dtByte,
477     dtInteger:
478     with FirebirdClientAPI do
479     begin
480     len := DecodeInteger(FBufPtr+1,2);
481     Result := DecodeInteger(FBufPtr+3,len);
482     end;
483     else
484     IBError(ibxeOutputBlockTypeError,[nil]);
485     end;
486     end;
487    
488     function TOutputBlockItem.getParamType: byte;
489     begin
490     Result := byte(FItemData^.FBufPtr^)
491     end;
492    
493 tony 56 function TOutputBlockItem.getAsString: AnsiString;
494 tony 45 var len: integer;
495     begin
496     Result := '';
497     with FItemData^ do
498     case FDataType of
499 tony 144 dtIntegerFixed,
500 tony 45 dtInteger:
501     Result := IntToStr(getAsInteger);
502     dtByte:
503     Result := IntToStr(getAsByte);
504     dtString:
505     begin
506     len := byte((FBufPtr+1)^);
507     SetString(Result,FBufPtr+2,len,CP_ACP);
508     end;
509     dtString2:
510     begin
511     with FirebirdClientAPI do
512     len := DecodeInteger(FBufPtr+1,2);
513     SetString(Result,FBufPtr+3,len,CP_ACP);
514     end;
515 tony 143 dtOctetString:
516     begin
517     with FirebirdClientAPI do
518     len := DecodeInteger(FBufPtr+1,2);
519     SetString(Result,FBufPtr+3,len,CP_NONE);
520     end;
521 tony 45 else
522     IBError(ibxeOutputBlockTypeError,[nil]);
523     end;
524     end;
525    
526     function TOutputBlockItem.getAsByte: byte;
527     begin
528     with FItemData^ do
529     if FDataType = dtByte then
530     Result := byte((FBufPtr+2)^)
531     else
532     IBError(ibxeOutputBlockTypeError,[nil]);
533     end;
534    
535     function TOutputBlockItem.getAsBytes: TByteArray;
536     var i: integer;
537 tony 56 P: PByte;
538 tony 45 begin
539     with FItemData^ do
540     if FDataType = dtBytes then
541     begin
542     SetLength(Result,FDataLength);
543     P := FBufPtr;
544     for i := 0 to FDataLength - 1 do
545     begin
546     Result[i] := byte(P^);
547     Inc(P);
548     end
549     end
550     else
551     IBError(ibxeOutputBlockTypeError,[nil]);
552     end;
553    
554 tony 143 function TOutputBlockItem.getAsDateTime: TDateTime;
555     var aDate: integer;
556     aTime: integer;
557     begin
558     with FItemData^, FirebirdClientAPI do
559     if FDataType = dtDateTime then
560     begin
561     aDate := DecodeInteger(FBufPtr+3,4);
562     aTime := DecodeInteger(FBufPtr+7,4);
563     Result := SQLDecodeDate(@aDate) + SQLDecodeTime(@aTime)
564     end
565     else
566     IBError(ibxeOutputBlockTypeError,[nil]);
567     end;
568    
569    
570 tony 45 function TOutputBlockItem.CopyTo(stream: TStream; count: integer): integer;
571     var len: integer;
572     begin
573     if count < 0 then count := 0;
574     with FItemData^ do
575     begin
576     case FDataType of
577     dtString:
578     begin
579     len := byte((FBufPtr+1)^);
580     if (count > 0) and (count < len) then len := count;
581     Result := stream.Write((FBufPtr+2)^,len);
582     end;
583     dtString2:
584     begin
585     with FirebirdClientAPI do
586     len := DecodeInteger(FBufPtr+1,2);
587     if (count > 0) and (count < len) then len := count;
588     Result := stream.Write((FBufPtr+3)^,len);
589     end;
590     else
591     IBError(ibxeOutputBlockTypeError,[nil]);
592     end;
593     end;
594     end;
595    
596     { TOutputBlock }
597    
598     procedure TOutputBlock.ParseBuffer;
599     begin
600     if not FBufferParsed then
601     begin
602     {$IFDEF DEBUGOUTPUTBLOCK}
603     PrintBuf;
604     {$ENDIF}
605     DoParseBuffer;
606     if FError or FTruncated then
607     SetLength(FItems,Length(FItems)-1);
608     {$IFDEF DEBUGOUTPUTBLOCK}
609     FormattedPrint(FItems,'');
610     {$ENDIF}
611     end;
612     FBufferParsed := true;
613     end;
614    
615 tony 56 function TOutputBlock.AddItem(BufPtr: PByte): POutputBlockItemData;
616 tony 45 begin
617     new(Result);
618     with Result^ do
619     begin
620     FDataType := dtNone;
621     FBufPtr := BufPtr;
622     FDataLength := 0;
623     FSize := 1;
624     SetLength(FSubItems,0);
625     end;
626     end;
627    
628 tony 56 function TOutputBlock.AddIntegerItem(BufPtr: PByte): POutputBlockItemData;
629 tony 45 begin
630     new(Result);
631     with Result^ do
632     begin
633     FDataType := FIntegerType;
634     FBufPtr := BufPtr;
635     if FDataType = dtIntegerFixed then
636     begin
637     FDataLength := 4;
638     FSize := 5;
639     end
640     else
641     begin
642     with FirebirdClientAPI do
643     FDataLength := DecodeInteger(FBufPtr+1, 2);
644     FSize := FDataLength + 3;
645     end;
646     SetLength(FSubItems,0);
647     end;
648     end;
649    
650 tony 56 function TOutputBlock.AddStringItem(BufPtr: PByte): POutputBlockItemData;
651 tony 45 begin
652     new(Result);
653     with Result^ do
654     begin
655     FDataType := dtString2;
656     FBufPtr := BufPtr;
657     with FirebirdClientAPI do
658     FDataLength := DecodeInteger(FBufPtr+1, 2);
659     FSize := FDataLength + 3;
660     SetLength(FSubItems,0);
661     end;
662     end;
663    
664 tony 56 function TOutputBlock.AddShortStringItem(BufPtr: PByte): POutputBlockItemData;
665 tony 45 begin
666     new(Result);
667     with Result^ do
668     begin
669     FDataType := dtString;
670     FBufPtr := BufPtr;
671     FDataLength := byte((FBufPtr+1)^);
672     FSize := FDataLength + 2;
673     SetLength(FSubItems,0);
674     end;
675     end;
676    
677 tony 56 function TOutputBlock.AddByteItem(BufPtr: PByte): POutputBlockItemData;
678 tony 45 begin
679     new(Result);
680     with Result^ do
681     begin
682     FDataType := dtByte;
683     FBufPtr := BufPtr;
684     FDataLength := 1;
685     FSize := 2;
686     SetLength(FSubItems,0);
687     end;
688     end;
689    
690 tony 56 function TOutputBlock.AddBytesItem(BufPtr: PByte): POutputBlockItemData;
691 tony 45 begin
692     new(Result);
693     with Result^ do
694     begin
695     FDataType := dtBytes;
696     FBufPtr := BufPtr;
697     with FirebirdClientAPI do
698     FDataLength := DecodeInteger(FBufPtr+1, 2);
699     FSize := FDataLength + 3;
700     SetLength(FSubItems,0);
701     end;
702     end;
703    
704 tony 56 function TOutputBlock.AddListItem(BufPtr: PByte): POutputBlockItemData;
705 tony 45 begin
706     new(Result);
707     with Result^ do
708     begin
709     FDataType := dtList;
710     FBufPtr := BufPtr;
711     FSize := FBuffer + FBufSize - FBufPtr;
712     FDataLength := FSize - 1;
713     SetLength(FSubItems,0);
714     end;
715     end;
716    
717 tony 56 function TOutputBlock.AddSpecialItem(BufPtr: PByte): POutputBlockItemData;
718 tony 45 begin
719     new(Result);
720     with Result^ do
721     begin
722     FDataType := dtSpecial;
723     FBufPtr := BufPtr;
724     FSize := FBuffer + FBufSize - FBufPtr;
725     FDataLength := FSize - 1;
726     SetLength(FSubItems,0);
727     end;
728     end;
729    
730 tony 143 function TOutputBlock.AddDateTimeItem(BufPtr: PByte): POutputBlockItemData;
731     begin
732     new(Result);
733     with Result^ do
734     begin
735     FDataType := dtDateTime;
736     FBufPtr := BufPtr;
737     with FirebirdClientAPI do
738     FDataLength := DecodeInteger(FBufPtr+1, 2);
739     FSize := FDataLength + 3;
740     SetLength(FSubItems,0);
741     end;
742     end;
743    
744     function TOutputBlock.AddOctetString(BufPtr: PByte): POutputBlockItemData;
745     begin
746     new(Result);
747     with Result^ do
748     begin
749     FDataType := dtOctetString;
750     FBufPtr := BufPtr;
751     with FirebirdClientAPI do
752     FDataLength := DecodeInteger(FBufPtr+1, 2);
753     FSize := FDataLength + 3;
754     SetLength(FSubItems,0);
755     end;
756     end;
757    
758 tony 45 constructor TOutputBlock.Create(aSize: integer);
759     begin
760     inherited Create;
761     FBufSize := aSize;
762     GetMem(FBuffer,aSize);
763     if FBuffer = nil then
764     OutOfMemoryError;
765     FillChar(FBuffer^,aSize,255);
766     FBufferParsed := false;
767     FIntegerType := dtIntegerFixed;
768     end;
769    
770     destructor TOutputBlock.Destroy;
771     var i, j: integer;
772     begin
773     for i := 0 to length(FItems) - 1 do
774     begin
775 tony 144 if FItems[i] <> nil then
776     begin
777     for j := 0 to Length(FItems[i]^.FSubItems) -1 do
778     if FItems[i]^.FSubItems[j] <> nil then
779     dispose(FItems[i]^.FSubItems[j]);
780     dispose(FItems[i]);
781     end;
782 tony 45 end;
783     FreeMem(FBuffer);
784     inherited Destroy;
785     end;
786    
787 tony 56 function TOutputBlock.Buffer: PByte;
788 tony 45 begin
789     Result := FBuffer;
790     end;
791    
792     function TOutputBlock.getBufSize: integer;
793     begin
794     Result := FBufSize;
795     end;
796    
797     function TOutputBlock.GetCount: integer;
798     begin
799     ParseBuffer;
800     Result := length(FItems);
801     end;
802    
803     function TOutputBlock.GetItem(index: integer): POutputBlockItemData;
804     begin
805     ParseBuffer;
806     if (index >= 0) and (index < Length(FItems)) then
807     Result := FItems[index]
808     else
809     IBError(ibxeOutputBlockIndexError,[index]);
810     end;
811    
812     function TOutputBlock.Find(ItemType: byte): POutputBlockItemData;
813     var i: integer;
814     begin
815     Result := nil;
816     for i := 0 to getCount - 1 do
817 tony 56 if byte(FItems[i]^.FBufPtr^) = ItemType then
818 tony 45 begin
819     Result := FItems[i];
820     Exit;
821     end;
822     end;
823    
824     {$IFDEF DEBUGOUTPUTBLOCK}
825     procedure TOutputBlock.FormattedPrint(
826 tony 56 const aItems: array of POutputBlockItemData; Indent: AnsiString);
827 tony 45
828     var i: integer;
829     item: TOutputBlockItem;
830     begin
831     if FError then
832     writeln('Error')
833     else
834     if FTruncated then
835     writeln('Truncated')
836     else
837     for i := 0 to Length(aItems) - 1 do
838     with aItems[i]^ do
839     begin
840     if FError then
841     writeln('Error')
842     else
843     if FTruncated then
844     writeln('Truncated')
845     else
846     case FDataType of
847     dtList:
848     begin
849     writeln(Indent,'ItemType = ',byte(FBufPtr^));
850     FormattedPrint(FSubItems,Indent + ' ');
851     end;
852     dtSpecial:
853     writeln(Indent,'ItemType = ',byte(FBufPtr^),' Length = ',FSize);
854     else
855     begin
856     item := TOutputBlockItem.Create(self,(aItems[i]));
857 tony 144 try
858     writeln(Indent,'ItemType = ',byte(FBufPtr^),' Value = ',(item as TOutputBlockItem).GetAsString);
859     except
860     writeln(Indent,'Unknown ItemType = ',byte(FBufPtr^));
861     end;
862 tony 45 end;
863     end;
864     end;
865     end;
866     {$ENDIF}
867    
868     procedure TOutputBlock.PrintBuf;
869     var i: integer;
870     begin
871     write(classname,': ');
872     for i := 0 to getBufSize - 1 do
873     begin
874     write(Format('%x ',[byte(Buffer[i])]));
875     if byte(FBuffer[i]) = isc_info_end then break;
876     end;
877     writeln;
878 tony 144 for i := 0 to getBufSize - 1 do
879     begin
880     if chr(FBuffer[i]) in [' '..'~'] then
881     write(chr(Buffer[i]))
882     else
883     write('.');
884     if byte(FBuffer[i]) = isc_info_end then break;
885     end;
886     writeln;
887 tony 45 end;
888    
889     { TDBInfoItem }
890    
891     procedure TDBInfoItem.DecodeIDCluster(var ConnectionType: integer;
892 tony 56 var DBFileName, DBSiteName: AnsiString);
893     var P: PByte;
894 tony 45 begin
895     with ItemData^ do
896 tony 56 if FBufPtr^ = isc_info_db_id then
897 tony 45 begin
898     P := FBufPtr + 3;
899     if FDataLength > 0 then
900     ConnectionType := integer(P^);
901     Inc(P);
902     SetString(DBFileName,P+1,byte(P^),CP_ACP);
903 tony 56 P := P + Length(DBFileName) + 1;
904 tony 45 SetString(DBSiteName,P+1,byte(P^),CP_ACP);
905     end
906     else
907     IBError(ibxeInfoBufferTypeError,[integer(FBufPtr^)]);
908     end;
909    
910     procedure TDBInfoItem.DecodeVersionString(var Version: byte;
911 tony 56 var VersionString: AnsiString);
912     var P: PByte;
913 tony 45 begin
914     with ItemData^ do
915 tony 56 if FBufPtr^ = isc_info_version then
916 tony 45 begin
917     P := FBufPtr+3;
918     VersionString := '';
919     Version := byte(P^);
920     Inc(P);
921     SetString(VersionString,P+1,byte(P^),CP_ACP);
922     end
923     else
924     IBError(ibxeInfoBufferTypeError,[integer(FBufPtr^)]);
925     end;
926    
927     procedure TDBInfoItem.DecodeUserNames(UserNames: TStrings);
928 tony 56 var P: PByte;
929     s: AnsiString;
930 tony 45 begin
931     with ItemData^ do
932 tony 56 if FBufPtr^ = isc_info_user_names then
933 tony 45 begin
934     P := FBufPtr+3;
935     while (P < FBufPtr + FSize) do
936     begin
937     SetString(s,P+1,byte(P^),CP_ACP);
938     UserNames.Add(s);
939 tony 56 P := P + Length(s) + 1;
940 tony 45 end;
941     end
942     else
943     IBError(ibxeInfoBufferTypeError,[integer(FBufPtr^)]);
944     end;
945    
946     function TDBInfoItem.getOperationCounts: TDBOperationCounts;
947     var tableCounts: integer;
948 tony 56 P: PByte;
949 tony 45 i: integer;
950     begin
951     with ItemData^ do
952     if byte(FBufPtr^) in [isc_info_backout_count, isc_info_delete_count,
953     isc_info_expunge_count,isc_info_insert_count, isc_info_purge_count,
954     isc_info_read_idx_count, isc_info_read_seq_count, isc_info_update_count] then
955     begin
956     tableCounts := FDataLength div 6;
957     SetLength(Result,TableCounts);
958     P := FBufPtr + 3;
959     for i := 0 to TableCounts -1 do
960     with FirebirdClientAPI do
961     begin
962     Result[i].TableID := DecodeInteger(P,2);
963     Inc(P,2);
964     Result[i].Count := DecodeInteger(P,4);
965     Inc(P,4);
966     end;
967     end
968     else
969     IBError(ibxeInfoBufferTypeError,[integer(FBufPtr^)]);
970     end;
971    
972     { TDBInformation }
973    
974 tony 56 function TDBInformation.AddSpecialItem(BufPtr: PByte): POutputBlockItemData;
975 tony 45 begin
976     Result := inherited AddSpecialItem(BufPtr);
977     with Result^ do
978     begin
979     with FirebirdClientAPI do
980     FDataLength := DecodeInteger(FBufPtr+1,2);
981     FSize := FDataLength + 3;
982     end;
983     end;
984    
985     procedure TDBInformation.DoParseBuffer;
986 tony 56 var P: PByte;
987 tony 45 index: integer;
988     begin
989     P := Buffer;
990     index := 0;
991     SetLength(FItems,0);
992 tony 56 while (P^ <> isc_info_end) and (P < Buffer + getBufSize) do
993 tony 45 begin
994     SetLength(FItems,index+1);
995     case byte(P^) of
996 tony 61 isc_info_db_read_only,
997 tony 45 isc_info_no_reserve,
998     isc_info_allocation,
999     isc_info_ods_minor_version,
1000     isc_info_ods_version,
1001     isc_info_db_SQL_dialect,
1002     isc_info_page_size,
1003     isc_info_current_memory,
1004     isc_info_forced_writes,
1005     isc_info_max_memory,
1006     isc_info_num_buffers,
1007     isc_info_sweep_interval,
1008     isc_info_fetches,
1009     isc_info_marks,
1010     isc_info_reads,
1011 tony 143 isc_info_writes,
1012     isc_info_active_tran_count,
1013     fb_info_pages_used,
1014     fb_info_pages_free,
1015     fb_info_conn_flags:
1016 tony 45 FItems[index] := AddIntegerItem(P);
1017    
1018     isc_info_implementation,
1019     isc_info_base_level:
1020     FItems[index] := AddBytesItem(P);
1021    
1022 tony 143 isc_info_creation_date:
1023     FItems[index] := AddDateTimeItem(P);
1024    
1025     fb_info_page_contents:
1026     FItems[index] := AddOctetString(P);
1027    
1028     fb_info_crypt_key:
1029     FItems[index] := AddStringItem(P);
1030    
1031 tony 45 isc_info_db_id,
1032     isc_info_version,
1033     isc_info_backout_count,
1034     isc_info_delete_count,
1035     isc_info_expunge_count,
1036     isc_info_insert_count,
1037     isc_info_purge_count,
1038     isc_info_read_idx_count,
1039     isc_info_read_seq_count,
1040     isc_info_update_count,
1041     isc_info_user_names:
1042     FItems[index] := AddSpecialItem(P);
1043    
1044     else
1045     FItems[index] := AddSpecialItem(P);
1046     end;
1047 tony 56 P := P + FItems[index]^.FSize;
1048 tony 45 Inc(index);
1049     end;
1050     end;
1051    
1052 tony 143 {$IFNDEF FPC}
1053     function TDBInformation.Find(ItemType: byte): IDBInfoItem;
1054     begin
1055     Result := inherited Find(ItemType);
1056     if Result.GetSize = 0 then
1057     Result := nil;
1058     end;
1059     {$ENDIF}
1060    
1061 tony 45 constructor TDBInformation.Create(aSize: integer);
1062     begin
1063     inherited Create(aSize);
1064     FIntegerType := dtInteger;
1065     end;
1066    
1067     { TServiceQueryResults }
1068    
1069 tony 56 function TServiceQueryResults.AddListItem(BufPtr: PByte): POutputBlockItemData;
1070     var P: PByte;
1071 tony 45 i: integer;
1072     group: byte;
1073     begin
1074     Result := inherited AddListItem(BufPtr);
1075     P := BufPtr + 1;
1076     i := 0;
1077     group := byte(BufPtr^);
1078     if group in [isc_info_svc_get_users,isc_info_svc_limbo_trans] then
1079     begin
1080     with FirebirdClientAPI do
1081     Result^.FSize := DecodeInteger(P,2) + 3;
1082     Inc(P,2);
1083     end;
1084     with Result^ do
1085     begin
1086 tony 56 while (P < FBufPtr + FSize) and (P^ <> isc_info_flag_end) do
1087 tony 45 begin
1088     SetLength(FSubItems,i+1);
1089 tony 144 FSubItems[i] := nil;
1090 tony 45 case group of
1091     isc_info_svc_svr_db_info:
1092     case integer(P^) of
1093     isc_spb_num_att,
1094     isc_spb_num_db:
1095     FSubItems[i] := AddIntegerItem(P);
1096    
1097     isc_spb_dbname:
1098     FSubItems[i] := AddStringItem(P);
1099    
1100     else
1101 tony 144 IBError(ibxeOutputParsingError, [integer(P^),BufToStr(P,FSize - (P-FBufPtr))]);
1102 tony 45 end;
1103    
1104     isc_info_svc_get_license:
1105     case integer(P^) of
1106     isc_spb_lic_id,
1107     isc_spb_lic_key:
1108     FSubItems[i] := AddIntegerItem(P);
1109     else
1110 tony 144 IBError(ibxeOutputParsingError, [integer(P^),BufToStr(P,FSize - (P-FBufPtr))]);
1111 tony 45 end;
1112    
1113     isc_info_svc_limbo_trans:
1114     case integer(P^) of
1115     isc_spb_tra_id,
1116     isc_spb_single_tra_id,
1117     isc_spb_multi_tra_id:
1118     FSubItems[i] := AddIntegerItem(P);
1119    
1120     isc_spb_tra_host_site,
1121     isc_spb_tra_remote_site,
1122     isc_spb_tra_db_path:
1123     FSubItems[i] := AddStringItem(P);
1124    
1125     isc_spb_tra_advise,
1126     isc_spb_tra_state:
1127     FSubItems[i] := AddByteItem(P);
1128     else
1129 tony 144 IBError(ibxeOutputParsingError, [integer(P^),BufToStr(P,FSize - (P-FBufPtr))]);
1130 tony 45 end;
1131    
1132     isc_info_svc_get_users:
1133     case integer(P^) of
1134 tony 143 isc_spb_sec_admin,
1135 tony 45 isc_spb_sec_userid,
1136     isc_spb_sec_groupid:
1137     FSubItems[i] := AddIntegerItem(P);
1138    
1139     isc_spb_sec_username,
1140     isc_spb_sec_password,
1141     isc_spb_sec_firstname,
1142     isc_spb_sec_middlename,
1143     isc_spb_sec_lastname:
1144     FSubItems[i] := AddStringItem(P);
1145    
1146     else
1147 tony 144 IBError(ibxeOutputParsingError, [integer(P^),BufToStr(P,FSize - (P-FBufPtr))]);
1148 tony 45 end;
1149    
1150     end;
1151 tony 56 P := P + FSubItems[i]^.FSize;
1152 tony 45 Inc(i);
1153     end;
1154     FDataLength := 0;
1155     for i := 0 to Length(FSubItems) - 1 do
1156 tony 56 FDataLength := FDataLength + FSubItems[i]^.FSize;
1157 tony 45 if group in [isc_info_svc_get_users,isc_info_svc_limbo_trans] then
1158     Exit;
1159    
1160 tony 56 if (P < FBufPtr + FSize) and (P^ = isc_info_flag_end) then
1161 tony 45 FSize := FDataLength + 2 {include start and end flag}
1162     else
1163     FSize := FDataLength + 1; {start flag only}
1164     end;
1165     end;
1166    
1167 tony 56 function TServiceQueryResults.AddSpecialItem(BufPtr: PByte
1168 tony 45 ): POutputBlockItemData;
1169 tony 56 var P: PByte;
1170 tony 45 i: integer;
1171     begin
1172     Result := inherited AddSpecialItem(BufPtr);
1173     with Result^ do
1174     begin
1175     with FirebirdClientAPI do
1176     FDataLength := DecodeInteger(FBufPtr+1, 2);
1177    
1178     P := FBufPtr + 3; {skip length bytes}
1179     i := 0;
1180     while P < FBufPtr + FDataLength do
1181     begin
1182     FSubItems[i] := AddIntegerItem(P);
1183 tony 56 P := P + FSubItems[i]^.FSize;
1184 tony 45 Inc(i);
1185     end;
1186     end;
1187     end;
1188    
1189     procedure TServiceQueryResults.DoParseBuffer;
1190 tony 56 var P: PByte;
1191 tony 45 i: integer;
1192     begin
1193     P := Buffer;
1194     i := 0;
1195 tony 56 while (P < Buffer + getBufSize) and (P^ <> isc_info_end) do
1196 tony 45 begin
1197     SetLength(FItems,i+1);
1198 tony 144 FItems[i] := nil;
1199 tony 45 case integer(P^) of
1200     isc_info_svc_line,
1201     isc_info_svc_get_env,
1202     isc_info_svc_get_env_lock,
1203     isc_info_svc_get_env_msg,
1204     isc_info_svc_user_dbpath,
1205     isc_info_svc_server_version,
1206     isc_info_svc_implementation,
1207     isc_info_svc_to_eof:
1208     FItems[i] := AddStringItem(P);
1209    
1210     isc_info_svc_get_license_mask,
1211     isc_info_svc_capabilities,
1212     isc_info_svc_version,
1213     isc_info_svc_running,
1214     isc_info_svc_stdin:
1215     FItems[i] := AddIntegerItem(P);
1216    
1217     isc_info_svc_timeout,
1218     isc_info_data_not_ready,
1219     isc_info_truncated:
1220     FItems[i] := AddItem(P);
1221    
1222     isc_info_svc_svr_db_info,
1223     isc_info_svc_get_license,
1224     isc_info_svc_limbo_trans,
1225     isc_info_svc_get_users:
1226     FItems[i] := AddListItem(P);
1227    
1228     isc_info_svc_get_config:
1229     FItems[i] := AddSpecialItem(P);
1230    
1231    
1232     else
1233 tony 144 IBError(ibxeOutputParsingError, [integer(P^),BufToStr(P,getBufSize - (P-Buffer))]);
1234 tony 45 end;
1235 tony 56 P := P + FItems[i]^.FSize;
1236 tony 45 Inc(i);
1237     end;
1238     end;
1239    
1240 tony 143 {$IFNDEF FPC}
1241     function TServiceQueryResults.Find(ItemType: byte): IServiceQueryResultItem;
1242     begin
1243     Result := inherited Find(ItemType);
1244     if Result.GetSize = 0 then
1245     Result := nil;
1246     end;
1247     {$ENDIF}
1248    
1249 tony 45 { TSQLInfoResultsBuffer }
1250    
1251 tony 56 function TSQLInfoResultsBuffer.AddListItem(BufPtr: PByte): POutputBlockItemData;
1252     var P: PByte;
1253 tony 45 i: integer;
1254     begin
1255     Result := inherited AddListItem(BufPtr);
1256     P := BufPtr + 1;
1257     i := 0;
1258    
1259     if byte(BufPtr^) = isc_info_sql_records then
1260     begin
1261     with FirebirdClientAPI do
1262     Result^.FSize := DecodeInteger(P,2) + 3;
1263     Inc(P,2);
1264     with Result^ do
1265     begin
1266     while (P < FBufPtr + FSize) and (byte(P^) <> isc_info_end) do
1267     begin
1268     SetLength(FSubItems,i+1);
1269     case integer(P^) of
1270     isc_info_req_select_count,
1271     isc_info_req_insert_count,
1272     isc_info_req_update_count,
1273     isc_info_req_delete_count:
1274     FSubItems[i] := AddIntegerItem(P);
1275    
1276     isc_info_truncated:
1277     begin
1278     FTruncated := true;
1279     Exit;
1280     end;
1281    
1282     isc_info_error:
1283     begin
1284     FError := true;
1285     Exit;
1286     end;
1287     else
1288     FSubItems[i] := AddSpecialItem(P);
1289     end;
1290 tony 56 P := P + FSubItems[i]^.FSize;
1291 tony 45 Inc(i);
1292     end;
1293     end;
1294     end;
1295     end;
1296    
1297     procedure TSQLInfoResultsBuffer.DoParseBuffer;
1298 tony 56 var P: PByte;
1299 tony 45 index: integer;
1300     begin
1301     P := Buffer;
1302     index := 0;
1303     SetLength(FItems,0);
1304 tony 56 while (P^ <> isc_info_end) and (P < Buffer + getBufSize) do
1305 tony 45 begin
1306     SetLength(FItems,index+1);
1307     case byte(P^) of
1308     isc_info_sql_stmt_type:
1309     FItems[index] := AddIntegerItem(P);
1310    
1311     isc_info_sql_get_plan:
1312     FItems[index] := AddStringItem(P);
1313    
1314     isc_info_sql_records:
1315     FItems[index] := AddListItem(P);
1316    
1317     isc_info_truncated:
1318     begin
1319     FTruncated := true;
1320     Exit;
1321     end;
1322    
1323     isc_info_error:
1324     begin
1325     FError := true;
1326     Exit;
1327     end;
1328    
1329     else
1330     FItems[index] := AddSpecialItem(P);
1331     end;
1332 tony 56 P := P + FItems[index]^.FSize;
1333 tony 45 Inc(index);
1334     end;
1335     end;
1336    
1337     constructor TSQLInfoResultsBuffer.Create(aSize: integer);
1338     begin
1339     inherited Create(aSize);
1340     FIntegerType := dtInteger;
1341     end;
1342    
1343 tony 56 { TBlobInfo }
1344    
1345     procedure TBlobInfo.DoParseBuffer;
1346     var P: PByte;
1347     index: integer;
1348     begin
1349     P := Buffer;
1350     index := 0;
1351     SetLength(FItems,0);
1352     while (P^ <> isc_info_end) and (P < Buffer + getBufSize) do
1353     begin
1354     SetLength(FItems,index+1);
1355     case byte(P^) of
1356     isc_info_blob_num_segments,
1357     isc_info_blob_max_segment,
1358     isc_info_blob_total_length,
1359     isc_info_blob_type:
1360     FItems[index] := AddIntegerItem(P);
1361     else
1362     FItems[index] := AddSpecialItem(P);
1363     end;
1364     P := P + FItems[index]^.FSize;
1365     Inc(index);
1366     end;
1367     end;
1368    
1369     constructor TBlobInfo.Create(aSize: integer);
1370     begin
1371     inherited Create(aSize);
1372     FIntegerType := dtInteger;
1373     end;
1374    
1375 tony 45 end.
1376