home *** CD-ROM | disk | FTP | other *** search
- {********************************************************}
- { }
- { Borland Delphi Visual Component Library }
- { InterBase Express core components }
- { }
- { Copyright (c) 1998-1999 Inprise Corporation }
- { }
- { InterBase Express is based in part on the product }
- { Free IB Components, written by Gregory H. Deatz for }
- { Hoagland, Longo, Moran, Dunst & Doukas Company. }
- { Free IB Components is used under license. }
- { }
- {********************************************************}
-
- unit IBBlob;
-
- interface
-
- uses
- Windows, SysUtils, Classes, Forms, IBHeader, IBErrorCodes, IBExternals,
- DB, IB, IBDatabase, IBUtils;
-
- const
- DefaultBlobSegmentSize = 16 * 1024;
-
- type
- { TIBBlobStream }
- TIBBlobStream = class(TStream)
- private
- FBase: TIBBase;
- FBlobID: TISC_QUAD;
- FBlobMaxSegmentSize,
- FBlobNumSegments,
- FBlobSize: Long;
- FBlobType: Short; { 0 = segmented, 1 = streamed }
- FBuffer: PChar;
- FBlobInitialized: Boolean;
- FHandle: TISC_BLOB_HANDLE;
- FMode: TBlobStreamMode;
- FModified: Boolean;
- FPosition: Long;
- protected
- procedure CloseBlob;
- procedure CreateBlob;
- procedure EnsureBlobInitialized;
- procedure GetBlobInfo;
- function GetDatabase: TIBDatabase;
- function GetDBHandle: PISC_DB_HANDLE;
- function GetTransaction: TIBTransaction;
- function GetTRHandle: PISC_TR_HANDLE;
- procedure OpenBlob;
- procedure SetBlobID(Value: TISC_QUAD);
- procedure SetDatabase(Value: TIBDatabase);
- procedure SetMode(Value: TBlobStreamMode);
- procedure SetTransaction(Value: TIBTransaction);
- public
- constructor Create;
- destructor Destroy; override;
- function Call(ErrCode: ISC_STATUS; RaiseError: Boolean): ISC_STATUS;
- procedure CheckReadable;
- procedure CheckWritable;
- procedure Finalize;
- procedure LoadFromFile(Filename: string);
- procedure LoadFromStream(Stream: TStream);
- function Read(var Buffer; Count: Longint): Longint; override;
- procedure SaveToFile(Filename: string);
- procedure SaveToStream(Stream: TStream);
- function Seek(Offset: Longint; Origin: Word): Longint; override;
- procedure SetSize(NewSize: Long); override;
- procedure Truncate;
- function Write(const Buffer; Count: Longint): Longint; override;
- property Handle: TISC_BLOB_HANDLE read FHandle;
- property BlobID: TISC_QUAD read FBlobID write SetBlobID;
- property BlobMaxSegmentSize: Long read FBlobMaxSegmentSize;
- property BlobNumSegments: Long read FBlobNumSegments;
- property BlobSize: Long read FBlobSize;
- property BlobType: Short read FBlobType;
- property Database: TIBDatabase read GetDatabase write SetDatabase;
- property DBHandle: PISC_DB_HANDLE read GetDBHandle;
- property Mode: TBlobStreamMode read FMode write SetMode;
- property Modified: Boolean read FModified;
- property Transaction: TIBTransaction read GetTransaction write SetTransaction;
- property TRHandle: PISC_TR_HANDLE read GetTRHandle;
- end;
-
- procedure GetBlobInfo(hBlobHandle: PISC_BLOB_HANDLE; var NumSegments, MaxSegmentSize,
- TotalSize: Long; var BlobType: Short);
- procedure ReadBlob(hBlobHandle: PISC_BLOB_HANDLE; Buffer: PChar; BlobSize: Long);
- procedure WriteBlob(hBlobHandle: PISC_BLOB_HANDLE; Buffer: PChar; BlobSize: Long);
-
- implementation
-
- uses IBIntf, IBCustomDataSet;
-
- procedure GetBlobInfo(hBlobHandle: PISC_BLOB_HANDLE; var NumSegments, MaxSegmentSize,
- TotalSize: Long; var BlobType: Short);
- var
- items: array[0..3] of Char;
- results: array[0..99] of Char;
- i, item_length: Integer;
- item: Integer;
- begin
- items[0] := Char(isc_info_blob_num_segments);
- items[1] := Char(isc_info_blob_max_segment);
- items[2] := Char(isc_info_blob_total_length);
- items[3] := Char(isc_info_blob_type);
-
- if isc_blob_info(StatusVector, hBlobHandle, 4, @items[0], SizeOf(results),
- @results[0]) > 0 then
- IBDatabaseError;
-
- i := 0;
- while (i < SizeOf(results)) and (results[i] <> Char(isc_info_end)) do
- begin
- item := Integer(results[i]); Inc(i);
- item_length := isc_vax_integer(@results[i], 2); Inc(i, 2);
- case item of
- isc_info_blob_num_segments:
- NumSegments := isc_vax_integer(@results[i], item_length);
- isc_info_blob_max_segment:
- MaxSegmentSize := isc_vax_integer(@results[i], item_length);
- isc_info_blob_total_length:
- TotalSize := isc_vax_integer(@results[i], item_length);
- isc_info_blob_type:
- BlobType := isc_vax_integer(@results[i], item_length);
- end;
- Inc(i, item_length);
- end;
- end;
-
- procedure ReadBlob(hBlobHandle: PISC_BLOB_HANDLE; Buffer: PChar; BlobSize: Long);
- var
- CurPos: Long;
- BytesRead, SegLen: UShort;
- LocalBuffer: PChar;
- begin
- CurPos := 0;
- LocalBuffer := Buffer;
- SegLen := UShort(DefaultBlobSegmentSize);
- while (CurPos < BlobSize) do
- begin
- if (CurPos + SegLen > BlobSize) then
- SegLen := BlobSize - CurPos;
- if not ((isc_get_segment(StatusVector, hBlobHandle, @BytesRead, SegLen,
- LocalBuffer) = 0) or
- (StatusVectorArray[1] = isc_segment)) then
- IBDatabaseError;
- Inc(LocalBuffer, BytesRead);
- Inc(CurPos, BytesRead);
- BytesRead := 0;
- end;
- end;
-
- procedure WriteBlob(hBlobHandle: PISC_BLOB_HANDLE; Buffer: PChar;
- BlobSize: Long);
- var
- CurPos, SegLen: Long;
- begin
- CurPos := 0;
- SegLen := DefaultBlobSegmentSize;
- while (CurPos < BlobSize) do
- begin
- if (CurPos + SegLen > BlobSize) then
- SegLen := BlobSize - CurPos;
- if isc_put_segment(StatusVector, hBlobHandle, SegLen,
- PChar(@Buffer[CurPos])) > 0 then
- IBDatabaseError;
- Inc(CurPos, SegLen);
- end;
- end;
-
-
- { TIBBlobStream }
- constructor TIBBlobStream.Create;
- begin
- inherited Create;
- FBase := TIBBase.Create(Self);
- FBuffer := nil;
- FBlobSize := 0;
- end;
-
- destructor TIBBlobStream.Destroy;
- begin
- if (FHandle <> nil) and
- (Call(isc_close_blob(StatusVector, @FHandle), False) > 0) then
- IBDataBaseError;
- FBase.Free;
- SetSize(0);
- inherited Destroy;
- end;
-
- function TIBBlobStream.Call(ErrCode: ISC_STATUS; RaiseError: Boolean): ISC_STATUS;
- begin
- result := 0;
- if Transaction <> nil then
- result := Transaction.Call(ErrCode, RaiseError)
- else if RaiseError and (ErrCode > 0) then
- IBDataBaseError;
- end;
-
- procedure TIBBlobStream.CheckReadable;
- begin
- if FMode = bmWrite then IBError(ibxeBlobCannotBeRead, [nil]);
- end;
-
- procedure TIBBlobStream.CheckWritable;
- begin
- if FMode = bmRead then IBError(ibxeBlobCannotBeWritten, [nil]);
- end;
-
- procedure TIBBlobStream.CloseBlob;
- begin
- Finalize;
- if (FHandle <> nil) and
- (Call(isc_close_blob(StatusVector, @FHandle), False) > 0) then
- IBDataBaseError;
- end;
-
- procedure TIBBlobStream.CreateBlob;
- begin
- CheckWritable;
- FBlobID.gds_quad_high := 0;
- FBlobID.gds_quad_low := 0;
- Truncate;
- end;
-
- procedure TIBBlobStream.EnsureBlobInitialized;
- begin
- if not FBlobInitialized then
- case FMode of
- bmWrite:
- CreateBlob;
- bmReadWrite: begin
- if (FBlobID.gds_quad_high = 0) and
- (FBlobID.gds_quad_low = 0) then
- CreateBlob
- else
- OpenBlob;
- end;
- else
- OpenBlob;
- end;
- FBlobInitialized := True;
- end;
-
- procedure TIBBlobStream.Finalize;
- begin
- if (not FBlobInitialized) or (FMode = bmRead) or (not FModified) then
- exit;
- { need to start writing to a blob, create one }
- Call(isc_create_blob2(StatusVector, DBHandle, TRHandle, @FHandle, @FBlobID,
- 0, nil), True);
- IBBlob.WriteBlob(@FHandle, FBuffer, FBlobSize);
- Call(isc_close_blob(StatusVector, @FHandle), True);
- FModified := False;
- end;
-
- procedure TIBBlobStream.GetBlobInfo;
- var
- iBlobSize: Long;
- begin
- IBBlob.GetBlobInfo(@FHandle, FBlobNumSegments, FBlobMaxSegmentSize,
- iBlobSize, FBlobType);
- SetSize(iBlobSize);
- end;
-
- function TIBBlobStream.GetDatabase: TIBDatabase;
- begin
- result := FBase.Database;
- end;
-
- function TIBBlobStream.GetDBHandle: PISC_DB_HANDLE;
- begin
- result := FBase.DBHandle;
- end;
-
- function TIBBlobStream.GetTransaction: TIBTransaction;
- begin
- result := FBase.Transaction;
- end;
-
- function TIBBlobStream.GetTRHandle: PISC_TR_HANDLE;
- begin
- result := FBase.TRHandle;
- end;
-
- procedure TIBBlobStream.LoadFromFile(Filename: string);
- var
- Stream: TStream;
- begin
- Stream := TFileStream.Create(FileName, fmOpenRead);
- try
- LoadFromStream(Stream);
- finally
- Stream.Free;
- end;
- end;
-
- procedure TIBBlobStream.LoadFromStream(Stream: TStream);
- begin
- CheckWritable;
- EnsureBlobInitialized;
- Stream.Position := 0;
- SetSize(Stream.Size);
- if FBlobSize <> 0 then
- Stream.ReadBuffer(FBuffer^, FBlobSize);
- FModified := True;
- end;
-
- procedure TIBBlobStream.OpenBlob;
- begin
- CheckReadable;
- Call(isc_open_blob2(StatusVector, DBHandle, TRHandle, @FHandle,
- @FBlobID, 0, nil), True);
- try
- GetBlobInfo;
- SetSize(FBlobSize);
- IBBlob.ReadBlob(@FHandle, FBuffer, FBlobSize);
- except
- Call(isc_close_blob(StatusVector, @FHandle), False);
- raise;
- end;
- Call(isc_close_blob(StatusVector, @FHandle), True);
- end;
-
- function TIBBlobStream.Read(var Buffer; Count: Longint): Longint;
- begin
- CheckReadable;
- EnsureBlobInitialized;
- if (Count <= 0) then
- begin
- result := 0;
- exit;
- end;
- if (FPosition + Count > FBlobSize) then
- result := FBlobSize - FPosition
- else
- result := Count;
- Move(FBuffer[FPosition], Buffer, result);
- Inc(FPosition, Result);
- end;
-
- procedure TIBBlobStream.SaveToFile(Filename: string);
- var
- Stream: TStream;
- begin
- Stream := TFileStream.Create(FileName, fmCreate);
- try
- SaveToStream(Stream);
- finally
- Stream.Free;
- end;
- end;
-
- procedure TIBBlobStream.SaveToStream(Stream: TStream);
- begin
- CheckReadable;
- EnsureBlobInitialized;
- if FBlobSize <> 0 then
- begin
- Seek(0, soFromBeginning);
- Stream.WriteBuffer(FBuffer^, FBlobSize);
- end;
- end;
-
- function TIBBlobStream.Seek(Offset: Longint; Origin: Word): Longint;
- begin
- EnsureBlobInitialized;
- case Origin of
- soFromBeginning : FPosition := Offset;
- soFromCurrent : Inc(FPosition, Offset);
- soFromEnd : FPosition := FBlobSize + Offset;
- end;
- result := FPosition;
- end;
-
- procedure TIBBlobStream.SetBlobID(Value: TISC_QUAD);
- begin
- System.Move(Value, FBlobID, SizeOf(TISC_QUAD));
- FBlobInitialized := False;
- end;
-
- procedure TIBBlobStream.SetDatabase(Value: TIBDatabase);
- begin
- FBase.Database := Value;
- FBlobInitialized := False;
- end;
-
- procedure TIBBlobStream.SetMode(Value: TBlobStreamMode);
- begin
- FMode := Value;
- FBlobInitialized := False;
- end;
-
- procedure TIBBlobStream.SetSize(NewSize: Long);
- begin
- if (NewSize <> FBlobSize) then
- begin
- ReallocMem(FBuffer, NewSize);
- FBlobSize := NewSize;
- if NewSize = 0 then
- FBuffer := nil;
- end;
- end;
-
- procedure TIBBlobStream.SetTransaction(Value: TIBTransaction);
- begin
- FBase.Transaction := Value;
- FBlobInitialized := False;
- end;
-
- procedure TIBBlobStream.Truncate;
- begin
- SetSize(0);
- end;
-
- function TIBBlobStream.Write(const Buffer; Count: Longint): Longint;
- begin
- CheckWritable;
- EnsureBlobInitialized;
- result := Count;
- if Count <= 0 then
- exit;
- if (FPosition + Count > FBlobSize) then
- SetSize(FPosition + Count);
- Move(Buffer, FBuffer[FPosition], Count);
- Inc(FPosition, Count);
- FModified := True;
- end;
-
- end.
-