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 (24 years, 4 months ago) by tony
Content type: text/x-pascal
File size: 12831 byte(s)
Log Message:
Borland IBX Open Source Release

File Contents

# Content
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.