ViewVC Help
View File | Revision Log | Show Annotations | Download File | View Changeset | Root Listing
root/public/ibx/trunk/runtime/IBBlob.pas
Revision: 1
Committed: Mon Jul 31 16:43:00 2000 UTC (23 years, 9 months ago) by tony
Content type: text/x-pascal
File size: 12831 byte(s)
Log Message:
Borland IBX Open Source Release

File Contents

# User Rev Content
1 tony 1 {************************************************************************}
2     { }
3     { Borland Delphi Visual Component Library }
4     { InterBase Express core components }
5     { }
6     { Copyright (c) 1998-2000 Inprise Corporation }
7     { }
8     { InterBase Express is based in part on the product }
9     { Free IB Components, written by Gregory H. Deatz for }
10     { Hoagland, Longo, Moran, Dunst & Doukas Company. }
11     { Free IB Components is used under license. }
12     { }
13     { The contents of this file are subject to the InterBase }
14     { Public License Version 1.0 (the "License"); you may not }
15     { use this file except in compliance with the License. You }
16     { may obtain a copy of the License at http://www.Inprise.com/IPL.html }
17     { Software distributed under the License is distributed on }
18     { an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either }
19     { express or implied. See the License for the specific language }
20     { governing rights and limitations under the License. }
21     { The Original Code was created by InterBase Software Corporation }
22     { and its successors. }
23     { Portions created by Inprise Corporation are Copyright (C) Inprise }
24     { Corporation. All Rights Reserved. }
25     { Contributor(s): Jeff Overcash }
26     { }
27     {************************************************************************}
28    
29     unit IBBlob;
30    
31     interface
32    
33     uses
34     Windows, SysUtils, Classes, Forms, IBHeader, IBErrorCodes, IBExternals,
35     DB, IB, IBDatabase, IBUtils;
36    
37     const
38     DefaultBlobSegmentSize = 16 * 1024;
39    
40     type
41     { TIBBlobStream }
42     TIBBlobStream = class(TStream)
43     private
44     FBase: TIBBase;
45     FBlobID: TISC_QUAD;
46     FBlobMaxSegmentSize,
47     FBlobNumSegments,
48     FBlobSize: Long;
49     FBlobType: Short; { 0 = segmented, 1 = streamed }
50     FBuffer: PChar;
51     FBlobInitialized: Boolean;
52     FHandle: TISC_BLOB_HANDLE;
53     FMode: TBlobStreamMode;
54     FModified: Boolean;
55     FPosition: Long;
56     protected
57     procedure CloseBlob;
58     procedure CreateBlob;
59     procedure EnsureBlobInitialized;
60     procedure GetBlobInfo;
61     function GetDatabase: TIBDatabase;
62     function GetDBHandle: PISC_DB_HANDLE;
63     function GetTransaction: TIBTransaction;
64     function GetTRHandle: PISC_TR_HANDLE;
65     procedure OpenBlob;
66     procedure SetBlobID(Value: TISC_QUAD);
67     procedure SetDatabase(Value: TIBDatabase);
68     procedure SetMode(Value: TBlobStreamMode);
69     procedure SetTransaction(Value: TIBTransaction);
70     public
71     constructor Create;
72     destructor Destroy; override;
73     function Call(ErrCode: ISC_STATUS; RaiseError: Boolean): ISC_STATUS;
74     procedure CheckReadable;
75     procedure CheckWritable;
76     procedure Finalize;
77     procedure LoadFromFile(Filename: string);
78     procedure LoadFromStream(Stream: TStream);
79     function Read(var Buffer; Count: Longint): Longint; override;
80     procedure SaveToFile(Filename: string);
81     procedure SaveToStream(Stream: TStream);
82     function Seek(Offset: Longint; Origin: Word): Longint; override;
83     procedure SetSize(NewSize: Long); override;
84     procedure Truncate;
85     function Write(const Buffer; Count: Longint): Longint; override;
86     property Handle: TISC_BLOB_HANDLE read FHandle;
87     property BlobID: TISC_QUAD read FBlobID write SetBlobID;
88     property BlobMaxSegmentSize: Long read FBlobMaxSegmentSize;
89     property BlobNumSegments: Long read FBlobNumSegments;
90     property BlobSize: Long read FBlobSize;
91     property BlobType: Short read FBlobType;
92     property Database: TIBDatabase read GetDatabase write SetDatabase;
93     property DBHandle: PISC_DB_HANDLE read GetDBHandle;
94     property Mode: TBlobStreamMode read FMode write SetMode;
95     property Modified: Boolean read FModified;
96     property Transaction: TIBTransaction read GetTransaction write SetTransaction;
97     property TRHandle: PISC_TR_HANDLE read GetTRHandle;
98     end;
99    
100     procedure GetBlobInfo(hBlobHandle: PISC_BLOB_HANDLE; var NumSegments, MaxSegmentSize,
101     TotalSize: Long; var BlobType: Short);
102     procedure ReadBlob(hBlobHandle: PISC_BLOB_HANDLE; Buffer: PChar; BlobSize: Long);
103     procedure WriteBlob(hBlobHandle: PISC_BLOB_HANDLE; Buffer: PChar; BlobSize: Long);
104    
105     implementation
106    
107     uses IBIntf, IBCustomDataSet;
108    
109     procedure GetBlobInfo(hBlobHandle: PISC_BLOB_HANDLE; var NumSegments, MaxSegmentSize,
110     TotalSize: Long; var BlobType: Short);
111     var
112     items: array[0..3] of Char;
113     results: array[0..99] of Char;
114     i, item_length: Integer;
115     item: Integer;
116     begin
117     items[0] := Char(isc_info_blob_num_segments);
118     items[1] := Char(isc_info_blob_max_segment);
119     items[2] := Char(isc_info_blob_total_length);
120     items[3] := Char(isc_info_blob_type);
121    
122     if isc_blob_info(StatusVector, hBlobHandle, 4, @items[0], SizeOf(results),
123     @results[0]) > 0 then
124     IBDatabaseError;
125    
126     i := 0;
127     while (i < SizeOf(results)) and (results[i] <> Char(isc_info_end)) do
128     begin
129     item := Integer(results[i]); Inc(i);
130     item_length := isc_vax_integer(@results[i], 2); Inc(i, 2);
131     case item of
132     isc_info_blob_num_segments:
133     NumSegments := isc_vax_integer(@results[i], item_length);
134     isc_info_blob_max_segment:
135     MaxSegmentSize := isc_vax_integer(@results[i], item_length);
136     isc_info_blob_total_length:
137     TotalSize := isc_vax_integer(@results[i], item_length);
138     isc_info_blob_type:
139     BlobType := isc_vax_integer(@results[i], item_length);
140     end;
141     Inc(i, item_length);
142     end;
143     end;
144    
145     procedure ReadBlob(hBlobHandle: PISC_BLOB_HANDLE; Buffer: PChar; BlobSize: Long);
146     var
147     CurPos: Long;
148     BytesRead, SegLen: UShort;
149     LocalBuffer: PChar;
150     begin
151     CurPos := 0;
152     LocalBuffer := Buffer;
153     SegLen := UShort(DefaultBlobSegmentSize);
154     while (CurPos < BlobSize) do
155     begin
156     if (CurPos + SegLen > BlobSize) then
157     SegLen := BlobSize - CurPos;
158     if not ((isc_get_segment(StatusVector, hBlobHandle, @BytesRead, SegLen,
159     LocalBuffer) = 0) or
160     (StatusVectorArray[1] = isc_segment)) then
161     IBDatabaseError;
162     Inc(LocalBuffer, BytesRead);
163     Inc(CurPos, BytesRead);
164     BytesRead := 0;
165     end;
166     end;
167    
168     procedure WriteBlob(hBlobHandle: PISC_BLOB_HANDLE; Buffer: PChar;
169     BlobSize: Long);
170     var
171     CurPos, SegLen: Long;
172     begin
173     CurPos := 0;
174     SegLen := DefaultBlobSegmentSize;
175     while (CurPos < BlobSize) do
176     begin
177     if (CurPos + SegLen > BlobSize) then
178     SegLen := BlobSize - CurPos;
179     if isc_put_segment(StatusVector, hBlobHandle, SegLen,
180     PChar(@Buffer[CurPos])) > 0 then
181     IBDatabaseError;
182     Inc(CurPos, SegLen);
183     end;
184     end;
185    
186    
187     { TIBBlobStream }
188     constructor TIBBlobStream.Create;
189     begin
190     inherited Create;
191     FBase := TIBBase.Create(Self);
192     FBuffer := nil;
193     FBlobSize := 0;
194     end;
195    
196     destructor TIBBlobStream.Destroy;
197     begin
198     if (FHandle <> nil) and
199     (Call(isc_close_blob(StatusVector, @FHandle), False) > 0) then
200     IBDataBaseError;
201     FBase.Free;
202     SetSize(0);
203     inherited Destroy;
204     end;
205    
206     function TIBBlobStream.Call(ErrCode: ISC_STATUS; RaiseError: Boolean): ISC_STATUS;
207     begin
208     result := 0;
209     if Transaction <> nil then
210     result := Transaction.Call(ErrCode, RaiseError)
211     else if RaiseError and (ErrCode > 0) then
212     IBDataBaseError;
213     end;
214    
215     procedure TIBBlobStream.CheckReadable;
216     begin
217     if FMode = bmWrite then IBError(ibxeBlobCannotBeRead, [nil]);
218     end;
219    
220     procedure TIBBlobStream.CheckWritable;
221     begin
222     if FMode = bmRead then IBError(ibxeBlobCannotBeWritten, [nil]);
223     end;
224    
225     procedure TIBBlobStream.CloseBlob;
226     begin
227     Finalize;
228     if (FHandle <> nil) and
229     (Call(isc_close_blob(StatusVector, @FHandle), False) > 0) then
230     IBDataBaseError;
231     end;
232    
233     procedure TIBBlobStream.CreateBlob;
234     begin
235     CheckWritable;
236     FBlobID.gds_quad_high := 0;
237     FBlobID.gds_quad_low := 0;
238     Truncate;
239     end;
240    
241     procedure TIBBlobStream.EnsureBlobInitialized;
242     begin
243     if not FBlobInitialized then
244     case FMode of
245     bmWrite:
246     CreateBlob;
247     bmReadWrite: begin
248     if (FBlobID.gds_quad_high = 0) and
249     (FBlobID.gds_quad_low = 0) then
250     CreateBlob
251     else
252     OpenBlob;
253     end;
254     else
255     OpenBlob;
256     end;
257     FBlobInitialized := True;
258     end;
259    
260     procedure TIBBlobStream.Finalize;
261     begin
262     if (not FBlobInitialized) or (FMode = bmRead) or (not FModified) then
263     exit;
264     { need to start writing to a blob, create one }
265     Call(isc_create_blob2(StatusVector, DBHandle, TRHandle, @FHandle, @FBlobID,
266     0, nil), True);
267     IBBlob.WriteBlob(@FHandle, FBuffer, FBlobSize);
268     Call(isc_close_blob(StatusVector, @FHandle), True);
269     FModified := False;
270     end;
271    
272     procedure TIBBlobStream.GetBlobInfo;
273     var
274     iBlobSize: Long;
275     begin
276     IBBlob.GetBlobInfo(@FHandle, FBlobNumSegments, FBlobMaxSegmentSize,
277     iBlobSize, FBlobType);
278     SetSize(iBlobSize);
279     end;
280    
281     function TIBBlobStream.GetDatabase: TIBDatabase;
282     begin
283     result := FBase.Database;
284     end;
285    
286     function TIBBlobStream.GetDBHandle: PISC_DB_HANDLE;
287     begin
288     result := FBase.DBHandle;
289     end;
290    
291     function TIBBlobStream.GetTransaction: TIBTransaction;
292     begin
293     result := FBase.Transaction;
294     end;
295    
296     function TIBBlobStream.GetTRHandle: PISC_TR_HANDLE;
297     begin
298     result := FBase.TRHandle;
299     end;
300    
301     procedure TIBBlobStream.LoadFromFile(Filename: string);
302     var
303     Stream: TStream;
304     begin
305     Stream := TFileStream.Create(FileName, fmOpenRead);
306     try
307     LoadFromStream(Stream);
308     finally
309     Stream.Free;
310     end;
311     end;
312    
313     procedure TIBBlobStream.LoadFromStream(Stream: TStream);
314     begin
315     CheckWritable;
316     EnsureBlobInitialized;
317     Stream.Position := 0;
318     SetSize(Stream.Size);
319     if FBlobSize <> 0 then
320     Stream.ReadBuffer(FBuffer^, FBlobSize);
321     FModified := True;
322     end;
323    
324     procedure TIBBlobStream.OpenBlob;
325     begin
326     CheckReadable;
327     Call(isc_open_blob2(StatusVector, DBHandle, TRHandle, @FHandle,
328     @FBlobID, 0, nil), True);
329     try
330     GetBlobInfo;
331     SetSize(FBlobSize);
332     IBBlob.ReadBlob(@FHandle, FBuffer, FBlobSize);
333     except
334     Call(isc_close_blob(StatusVector, @FHandle), False);
335     raise;
336     end;
337     Call(isc_close_blob(StatusVector, @FHandle), True);
338     end;
339    
340     function TIBBlobStream.Read(var Buffer; Count: Longint): Longint;
341     begin
342     CheckReadable;
343     EnsureBlobInitialized;
344     if (Count <= 0) then
345     begin
346     result := 0;
347     exit;
348     end;
349     if (FPosition + Count > FBlobSize) then
350     result := FBlobSize - FPosition
351     else
352     result := Count;
353     Move(FBuffer[FPosition], Buffer, result);
354     Inc(FPosition, Result);
355     end;
356    
357     procedure TIBBlobStream.SaveToFile(Filename: string);
358     var
359     Stream: TStream;
360     begin
361     Stream := TFileStream.Create(FileName, fmCreate);
362     try
363     SaveToStream(Stream);
364     finally
365     Stream.Free;
366     end;
367     end;
368    
369     procedure TIBBlobStream.SaveToStream(Stream: TStream);
370     begin
371     CheckReadable;
372     EnsureBlobInitialized;
373     if FBlobSize <> 0 then
374     begin
375     Seek(0, soFromBeginning);
376     Stream.WriteBuffer(FBuffer^, FBlobSize);
377     end;
378     end;
379    
380     function TIBBlobStream.Seek(Offset: Longint; Origin: Word): Longint;
381     begin
382     EnsureBlobInitialized;
383     case Origin of
384     soFromBeginning : FPosition := Offset;
385     soFromCurrent : Inc(FPosition, Offset);
386     soFromEnd : FPosition := FBlobSize + Offset;
387     end;
388     result := FPosition;
389     end;
390    
391     procedure TIBBlobStream.SetBlobID(Value: TISC_QUAD);
392     begin
393     System.Move(Value, FBlobID, SizeOf(TISC_QUAD));
394     FBlobInitialized := False;
395     end;
396    
397     procedure TIBBlobStream.SetDatabase(Value: TIBDatabase);
398     begin
399     FBase.Database := Value;
400     FBlobInitialized := False;
401     end;
402    
403     procedure TIBBlobStream.SetMode(Value: TBlobStreamMode);
404     begin
405     FMode := Value;
406     FBlobInitialized := False;
407     end;
408    
409     procedure TIBBlobStream.SetSize(NewSize: Long);
410     begin
411     if (NewSize <> FBlobSize) then
412     begin
413     ReallocMem(FBuffer, NewSize);
414     FBlobSize := NewSize;
415     if NewSize = 0 then
416     FBuffer := nil;
417     end;
418     end;
419    
420     procedure TIBBlobStream.SetTransaction(Value: TIBTransaction);
421     begin
422     FBase.Transaction := Value;
423     FBlobInitialized := False;
424     end;
425    
426     procedure TIBBlobStream.Truncate;
427     begin
428     SetSize(0);
429     end;
430    
431     function TIBBlobStream.Write(const Buffer; Count: Longint): Longint;
432     begin
433     CheckWritable;
434     EnsureBlobInitialized;
435     result := Count;
436     if Count <= 0 then
437     exit;
438     if (FPosition + Count > FBlobSize) then
439     SetSize(FPosition + Count);
440     Move(Buffer, FBuffer[FPosition], Count);
441     Inc(FPosition, Count);
442     FModified := True;
443     end;
444    
445     end.