ViewVC Help
View File | Revision Log | Show Annotations | Download File | View Changeset | Root Listing
root/public/ibx/trunk/runtime/IBBlob.pas
(Generate patch)

Comparing ibx/trunk/runtime/IBBlob.pas (file contents):
Revision 5 by tony, Fri Feb 18 16:26:16 2011 UTC vs.
Revision 17 by tony, Sat Dec 28 19:22:24 2013 UTC

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

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines