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, 2 months ago) by tony
Content type: text/x-pascal
File size: 12804 byte(s)
Log Message:
Committing updates for Release pre-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 {$Mode Delphi}
32
33 interface
34
35 uses
36 SysUtils, Classes, IBHeader, IBErrorCodes, IBExternals, DB, IB, IBDatabase;
37
38
39 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 uses IBIntf;
110
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.