ViewVC Help
View File | Revision Log | Show Annotations | Download File | View Changeset | Root Listing
root/public/ibx/trunk/runtime/IBBlob.pas
Revision: 5
Committed: Fri Feb 18 16:26:16 2011 UTC (13 years, 9 months ago) by tony
Content type: text/x-pascal
File size: 12804 byte(s)
Log Message:
Committing updates for Release pre-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 tony 5 {$Mode Delphi}
32    
33 tony 1 interface
34    
35     uses
36 tony 5 SysUtils, Classes, IBHeader, IBErrorCodes, IBExternals, DB, IB, IBDatabase;
37 tony 1
38 tony 5
39 tony 1 const
40     DefaultBlobSegmentSize = 16 * 1024;
41    
42     type
43     { TIBBlobStream }
44     TIBBlobStream = class(TStream)
45     private
46     FBase: TIBBase;
47     FBlobID: TISC_QUAD;
48     FBlobMaxSegmentSize,
49     FBlobNumSegments,
50     FBlobSize: Long;
51     FBlobType: Short; { 0 = segmented, 1 = streamed }
52     FBuffer: PChar;
53     FBlobInitialized: Boolean;
54     FHandle: TISC_BLOB_HANDLE;
55     FMode: TBlobStreamMode;
56     FModified: Boolean;
57     FPosition: Long;
58     protected
59     procedure CloseBlob;
60     procedure CreateBlob;
61     procedure EnsureBlobInitialized;
62     procedure GetBlobInfo;
63     function GetDatabase: TIBDatabase;
64     function GetDBHandle: PISC_DB_HANDLE;
65     function GetTransaction: TIBTransaction;
66     function GetTRHandle: PISC_TR_HANDLE;
67     procedure OpenBlob;
68     procedure SetBlobID(Value: TISC_QUAD);
69     procedure SetDatabase(Value: TIBDatabase);
70     procedure SetMode(Value: TBlobStreamMode);
71     procedure SetTransaction(Value: TIBTransaction);
72     public
73     constructor Create;
74     destructor Destroy; override;
75     function Call(ErrCode: ISC_STATUS; RaiseError: Boolean): ISC_STATUS;
76     procedure CheckReadable;
77     procedure CheckWritable;
78     procedure Finalize;
79     procedure LoadFromFile(Filename: string);
80     procedure LoadFromStream(Stream: TStream);
81     function Read(var Buffer; Count: Longint): Longint; override;
82     procedure SaveToFile(Filename: string);
83     procedure SaveToStream(Stream: TStream);
84     function Seek(Offset: Longint; Origin: Word): Longint; override;
85     procedure SetSize(NewSize: Long); override;
86     procedure Truncate;
87     function Write(const Buffer; Count: Longint): Longint; override;
88     property Handle: TISC_BLOB_HANDLE read FHandle;
89     property BlobID: TISC_QUAD read FBlobID write SetBlobID;
90     property BlobMaxSegmentSize: Long read FBlobMaxSegmentSize;
91     property BlobNumSegments: Long read FBlobNumSegments;
92     property BlobSize: Long read FBlobSize;
93     property BlobType: Short read FBlobType;
94     property Database: TIBDatabase read GetDatabase write SetDatabase;
95     property DBHandle: PISC_DB_HANDLE read GetDBHandle;
96     property Mode: TBlobStreamMode read FMode write SetMode;
97     property Modified: Boolean read FModified;
98     property Transaction: TIBTransaction read GetTransaction write SetTransaction;
99     property TRHandle: PISC_TR_HANDLE read GetTRHandle;
100     end;
101    
102     procedure GetBlobInfo(hBlobHandle: PISC_BLOB_HANDLE; var NumSegments, MaxSegmentSize,
103     TotalSize: Long; var BlobType: Short);
104     procedure ReadBlob(hBlobHandle: PISC_BLOB_HANDLE; Buffer: PChar; BlobSize: Long);
105     procedure WriteBlob(hBlobHandle: PISC_BLOB_HANDLE; Buffer: PChar; BlobSize: Long);
106    
107     implementation
108    
109 tony 5 uses IBIntf;
110 tony 1
111     procedure GetBlobInfo(hBlobHandle: PISC_BLOB_HANDLE; var NumSegments, MaxSegmentSize,
112     TotalSize: Long; var BlobType: Short);
113     var
114     items: array[0..3] of Char;
115     results: array[0..99] of Char;
116     i, item_length: Integer;
117     item: Integer;
118     begin
119     items[0] := Char(isc_info_blob_num_segments);
120     items[1] := Char(isc_info_blob_max_segment);
121     items[2] := Char(isc_info_blob_total_length);
122     items[3] := Char(isc_info_blob_type);
123    
124     if isc_blob_info(StatusVector, hBlobHandle, 4, @items[0], SizeOf(results),
125     @results[0]) > 0 then
126     IBDatabaseError;
127    
128     i := 0;
129     while (i < SizeOf(results)) and (results[i] <> Char(isc_info_end)) do
130     begin
131     item := Integer(results[i]); Inc(i);
132     item_length := isc_vax_integer(@results[i], 2); Inc(i, 2);
133     case item of
134     isc_info_blob_num_segments:
135     NumSegments := isc_vax_integer(@results[i], item_length);
136     isc_info_blob_max_segment:
137     MaxSegmentSize := isc_vax_integer(@results[i], item_length);
138     isc_info_blob_total_length:
139     TotalSize := isc_vax_integer(@results[i], item_length);
140     isc_info_blob_type:
141     BlobType := isc_vax_integer(@results[i], item_length);
142     end;
143     Inc(i, item_length);
144     end;
145     end;
146    
147     procedure ReadBlob(hBlobHandle: PISC_BLOB_HANDLE; Buffer: PChar; BlobSize: Long);
148     var
149     CurPos: Long;
150     BytesRead, SegLen: UShort;
151     LocalBuffer: PChar;
152     begin
153     CurPos := 0;
154     LocalBuffer := Buffer;
155     SegLen := UShort(DefaultBlobSegmentSize);
156     while (CurPos < BlobSize) do
157     begin
158     if (CurPos + SegLen > BlobSize) then
159     SegLen := BlobSize - CurPos;
160     if not ((isc_get_segment(StatusVector, hBlobHandle, @BytesRead, SegLen,
161     LocalBuffer) = 0) or
162     (StatusVectorArray[1] = isc_segment)) then
163     IBDatabaseError;
164     Inc(LocalBuffer, BytesRead);
165     Inc(CurPos, BytesRead);
166     BytesRead := 0;
167     end;
168     end;
169    
170     procedure WriteBlob(hBlobHandle: PISC_BLOB_HANDLE; Buffer: PChar;
171     BlobSize: Long);
172     var
173     CurPos, SegLen: Long;
174     begin
175     CurPos := 0;
176     SegLen := DefaultBlobSegmentSize;
177     while (CurPos < BlobSize) do
178     begin
179     if (CurPos + SegLen > BlobSize) then
180     SegLen := BlobSize - CurPos;
181     if isc_put_segment(StatusVector, hBlobHandle, SegLen,
182     PChar(@Buffer[CurPos])) > 0 then
183     IBDatabaseError;
184     Inc(CurPos, SegLen);
185     end;
186     end;
187    
188    
189     { TIBBlobStream }
190     constructor TIBBlobStream.Create;
191     begin
192     inherited Create;
193     FBase := TIBBase.Create(Self);
194     FBuffer := nil;
195     FBlobSize := 0;
196     end;
197    
198     destructor TIBBlobStream.Destroy;
199     begin
200     if (FHandle <> nil) and
201     (Call(isc_close_blob(StatusVector, @FHandle), False) > 0) then
202     IBDataBaseError;
203     FBase.Free;
204     SetSize(0);
205     inherited Destroy;
206     end;
207    
208     function TIBBlobStream.Call(ErrCode: ISC_STATUS; RaiseError: Boolean): ISC_STATUS;
209     begin
210     result := 0;
211     if Transaction <> nil then
212     result := Transaction.Call(ErrCode, RaiseError)
213     else if RaiseError and (ErrCode > 0) then
214     IBDataBaseError;
215     end;
216    
217     procedure TIBBlobStream.CheckReadable;
218     begin
219     if FMode = bmWrite then IBError(ibxeBlobCannotBeRead, [nil]);
220     end;
221    
222     procedure TIBBlobStream.CheckWritable;
223     begin
224     if FMode = bmRead then IBError(ibxeBlobCannotBeWritten, [nil]);
225     end;
226    
227     procedure TIBBlobStream.CloseBlob;
228     begin
229     Finalize;
230     if (FHandle <> nil) and
231     (Call(isc_close_blob(StatusVector, @FHandle), False) > 0) then
232     IBDataBaseError;
233     end;
234    
235     procedure TIBBlobStream.CreateBlob;
236     begin
237     CheckWritable;
238     FBlobID.gds_quad_high := 0;
239     FBlobID.gds_quad_low := 0;
240     Truncate;
241     end;
242    
243     procedure TIBBlobStream.EnsureBlobInitialized;
244     begin
245     if not FBlobInitialized then
246     case FMode of
247     bmWrite:
248     CreateBlob;
249     bmReadWrite: begin
250     if (FBlobID.gds_quad_high = 0) and
251     (FBlobID.gds_quad_low = 0) then
252     CreateBlob
253     else
254     OpenBlob;
255     end;
256     else
257     OpenBlob;
258     end;
259     FBlobInitialized := True;
260     end;
261    
262     procedure TIBBlobStream.Finalize;
263     begin
264     if (not FBlobInitialized) or (FMode = bmRead) or (not FModified) then
265     exit;
266     { need to start writing to a blob, create one }
267     Call(isc_create_blob2(StatusVector, DBHandle, TRHandle, @FHandle, @FBlobID,
268     0, nil), True);
269     IBBlob.WriteBlob(@FHandle, FBuffer, FBlobSize);
270     Call(isc_close_blob(StatusVector, @FHandle), True);
271     FModified := False;
272     end;
273    
274     procedure TIBBlobStream.GetBlobInfo;
275     var
276     iBlobSize: Long;
277     begin
278     IBBlob.GetBlobInfo(@FHandle, FBlobNumSegments, FBlobMaxSegmentSize,
279     iBlobSize, FBlobType);
280     SetSize(iBlobSize);
281     end;
282    
283     function TIBBlobStream.GetDatabase: TIBDatabase;
284     begin
285     result := FBase.Database;
286     end;
287    
288     function TIBBlobStream.GetDBHandle: PISC_DB_HANDLE;
289     begin
290     result := FBase.DBHandle;
291     end;
292    
293     function TIBBlobStream.GetTransaction: TIBTransaction;
294     begin
295     result := FBase.Transaction;
296     end;
297    
298     function TIBBlobStream.GetTRHandle: PISC_TR_HANDLE;
299     begin
300     result := FBase.TRHandle;
301     end;
302    
303     procedure TIBBlobStream.LoadFromFile(Filename: string);
304     var
305     Stream: TStream;
306     begin
307     Stream := TFileStream.Create(FileName, fmOpenRead);
308     try
309     LoadFromStream(Stream);
310     finally
311     Stream.Free;
312     end;
313     end;
314    
315     procedure TIBBlobStream.LoadFromStream(Stream: TStream);
316     begin
317     CheckWritable;
318     EnsureBlobInitialized;
319     Stream.Position := 0;
320     SetSize(Stream.Size);
321     if FBlobSize <> 0 then
322     Stream.ReadBuffer(FBuffer^, FBlobSize);
323     FModified := True;
324     end;
325    
326     procedure TIBBlobStream.OpenBlob;
327     begin
328     CheckReadable;
329     Call(isc_open_blob2(StatusVector, DBHandle, TRHandle, @FHandle,
330     @FBlobID, 0, nil), True);
331     try
332     GetBlobInfo;
333     SetSize(FBlobSize);
334     IBBlob.ReadBlob(@FHandle, FBuffer, FBlobSize);
335     except
336     Call(isc_close_blob(StatusVector, @FHandle), False);
337     raise;
338     end;
339     Call(isc_close_blob(StatusVector, @FHandle), True);
340     end;
341    
342     function TIBBlobStream.Read(var Buffer; Count: Longint): Longint;
343     begin
344     CheckReadable;
345     EnsureBlobInitialized;
346     if (Count <= 0) then
347     begin
348     result := 0;
349     exit;
350     end;
351     if (FPosition + Count > FBlobSize) then
352     result := FBlobSize - FPosition
353     else
354     result := Count;
355     Move(FBuffer[FPosition], Buffer, result);
356     Inc(FPosition, Result);
357     end;
358    
359     procedure TIBBlobStream.SaveToFile(Filename: string);
360     var
361     Stream: TStream;
362     begin
363     Stream := TFileStream.Create(FileName, fmCreate);
364     try
365     SaveToStream(Stream);
366     finally
367     Stream.Free;
368     end;
369     end;
370    
371     procedure TIBBlobStream.SaveToStream(Stream: TStream);
372     begin
373     CheckReadable;
374     EnsureBlobInitialized;
375     if FBlobSize <> 0 then
376     begin
377     Seek(0, soFromBeginning);
378     Stream.WriteBuffer(FBuffer^, FBlobSize);
379     end;
380     end;
381    
382     function TIBBlobStream.Seek(Offset: Longint; Origin: Word): Longint;
383     begin
384     EnsureBlobInitialized;
385     case Origin of
386     soFromBeginning : FPosition := Offset;
387     soFromCurrent : Inc(FPosition, Offset);
388     soFromEnd : FPosition := FBlobSize + Offset;
389     end;
390     result := FPosition;
391     end;
392    
393     procedure TIBBlobStream.SetBlobID(Value: TISC_QUAD);
394     begin
395     System.Move(Value, FBlobID, SizeOf(TISC_QUAD));
396     FBlobInitialized := False;
397     end;
398    
399     procedure TIBBlobStream.SetDatabase(Value: TIBDatabase);
400     begin
401     FBase.Database := Value;
402     FBlobInitialized := False;
403     end;
404    
405     procedure TIBBlobStream.SetMode(Value: TBlobStreamMode);
406     begin
407     FMode := Value;
408     FBlobInitialized := False;
409     end;
410    
411     procedure TIBBlobStream.SetSize(NewSize: Long);
412     begin
413     if (NewSize <> FBlobSize) then
414     begin
415     ReallocMem(FBuffer, NewSize);
416     FBlobSize := NewSize;
417     if NewSize = 0 then
418     FBuffer := nil;
419     end;
420     end;
421    
422     procedure TIBBlobStream.SetTransaction(Value: TIBTransaction);
423     begin
424     FBase.Transaction := Value;
425     FBlobInitialized := False;
426     end;
427    
428     procedure TIBBlobStream.Truncate;
429     begin
430     SetSize(0);
431     end;
432    
433     function TIBBlobStream.Write(const Buffer; Count: Longint): Longint;
434     begin
435     CheckWritable;
436     EnsureBlobInitialized;
437     result := Count;
438     if Count <= 0 then
439     exit;
440     if (FPosition + Count > FBlobSize) then
441     SetSize(FPosition + Count);
442     Move(Buffer, FBuffer[FPosition], Count);
443     Inc(FPosition, Count);
444     FModified := True;
445     end;
446    
447     end.