?? myldbcompression.pas
字號:
end; // InternalCreate
//------------------------------------------------------------------------------
// load block headers
//------------------------------------------------------------------------------
procedure TMYLDBCompressedBLOBStream.LoadHeaders;
var CHeader: TMYLDBCompressedStreamBlockHeader;
Pos,NewPos: Int64;
i,OldPos: Int64;
begin
FCompressedSize := 0;
FUncompressedSize := 0;
// always restore StartPosition as blob stream can be stored at the middle of the file
if (FCompressedStream.Position <> FBLOBDescriptor.StartPosition) then
raise EMYLDBException.Create(10080,ErrorLCannotSetPosition,
[FBLOBDescriptor.StartPosition,FCompressedStream.Position,
FCompressedStream.Size]);
FHeaders.SetSize(0);
i := 0;
while (i < FBLOBDescriptor.NumBlocks) do
begin
// store position of the current block
Pos := FCompressedStream.Position;
// check if we can read block header from current position
if (
(FCompressedStream.Size - FCompressedStream.Position) <
sizeof(TMYLDBCompressedStreamBlockHeader)
) then
begin
// stream too small
if (FRepair) then
begin
// cut compressed file (end of file was cut)
// repair this error
FBLOBDescriptor.NumBlocks := i;
FHeaders.SetSize(i);
break;
end
else
raise EMYLDBException.Create(10082,ErrorLStreamSizeTooSmall,
[FCompressedStream.Size,
FCompressedStream.Position + sizeof(TMYLDBCompressedStreamBlockHeader)]);
end; // check if we can read block header from current position
FCompressedStream.ReadBuffer(CHeader,sizeof(TMYLDBCompressedStreamBlockHeader));
Inc(FUncompressedSize,CHeader.UncompressedSize);
Inc(FCompressedSize,CHeader.CompressedSize);
FHeaders.AppendItem(CHeader,Pos);
// Commented By Leo Martin - changed from absolute to relative offset
// NewPos := CHeader.OffsetToNextHeader;
NewPos := Pos + CHeader.OffsetToNextHeader;
OldPos := FCompressedStream.Position;
FCompressedStream.Position := NewPos;
if (FCompressedStream.Position <> NewPos) then
raise EMYLDBException.Create(10083,ErrorLCannotSetPosition,
[NewPos,OldPos,FCompressedStream.Size]);
Inc(i);
end; // while (i < FBLOBDescriptor.NumBlocks)
end; // LoadHeaders
//------------------------------------------------------------------------------
// prepare buffer for writing
//------------------------------------------------------------------------------
procedure TMYLDBCompressedBLOBStream.PrepareBufferForWriting
(
InBuf: PChar;
InSize: Integer;
var OutBuf: PChar;
var Header: TMYLDBCompressedStreamBlockHeader
);
begin
OutBuf := nil;
Header.UncompressedSize := inSize;
Header.Crc32 := CRC32(0,InBuf,InSize);
if (not MYLDBInternalCompressBuffer(FCompressionAlgorithm,FCompressionMode,
InBuf,InSize,OutBuf,Header.CompressedSize)) then
begin
if (OutBuf <> nil) then
FreeMem(OutBuf);
raise EMYLDBException.Create(10085,ErrorLCompressBufferFailed,
[Byte(FCompressionAlgorithm),FCompressionMode,InSize,Header.CompressedSize]);
end;
end; //PrepareBuffer;
//------------------------------------------------------------------------------
// load block from file, decompress it and checks crc
//------------------------------------------------------------------------------
procedure TMYLDBCompressedBLOBStream.LoadBlock(
CurHeader: Int64;
var OutBuf: PChar
);
var UncompSize,CompSize: Integer;
BytesRead: Integer;
CheckSum: LongWord;
InBuf: PChar;
begin
CompSize := FHeaders.Items[curHeader].CompressedSize;
InBuf := MemoryManager.GetMem(CompSize);
try
FCompressedStream.Position := FHeaders.Positions[CurHeader] +
sizeof(TMYLDBCompressedStreamBlockHeader);
BytesRead := FCompressedStream.Read(InBuf^,CompSize);
if (BytesRead <> CompSize) then
begin
raise EMYLDBException.Create(10086,ErrorLCannotReadFromStream,
[FHeaders.Positions[CurHeader] + sizeof(TMYLDBCompressedStreamBlockHeader),
FCompressedStream.Size,CompSize,BytesRead]);
end;
UncompSize := FHeaders.Items[CurHeader].UncompressedSize;
if (not MYLDBInternalDecompressBuffer(FCompressionalgorithm,
InBuf,CompSize,OutBuf,UncompSize)) then
begin
// decompression error
raise EMYLDBException.Create(10087,ErrorLDecompressBufferFailed,
[Byte(FCompressionAlgorithm),CompSize,UncompSize]);
end;
if (FHeaders.Items[CurHeader].UncompressedSize <> UncompSize) then
begin
FreeMem(outBuf);
OutBuf := nil;
raise EMYLDBException.Create(10088,ErrorLDecompressBufferFailedInvalidSize,
[UncompSize,FHeaders.Items[CurHeader].UncompressedSize]);
end;
// check crc
CheckSum := CRC32(0,OutBuf,UncompSize);
if (FHeaders.Items[CurHeader].Crc32 <> CheckSum) then
begin
// decompression crc error
FreeMem(outBuf);
OutBuf := nil;
raise EMYLDBException.Create(10089,ErrorLDecompressBufferFailedInvalidCRC,
[CheckSum,FHeaders.Items[CurHeader].Crc32]);
end;
finally
MemoryManager.FreeAndNillMem(inBuf);
end;
end; // LoadBlock
//------------------------------------------------------------------------------
// set size of compressed stream
//------------------------------------------------------------------------------
procedure TMYLDBCompressedBLOBStream.InternalIncreaseSize(NewSize: Int64);
var Buf: PChar;
ExtensionSize,Count: Int64;
OldPos: Int64;
WriteBytes,WriteSize: Integer;
begin
Position := FUncompressedSize;
ExtensionSize := NewSize - FUncompressedSize;
if (ExtensionSize <= 0) then
raise EMYLDBException.Create(10098,ErrorLInvalidExtensionSize,
[NewSize,FUncompressedSize,ExtensionSize]);
Buf := MemoryManager.AllocMem(FBlockSize);
try
Count := 0;
while (Count < ExtensionSize) do
begin
if ((ExtensionSize - Count) < FBlockSize) then
WriteSize := ExtensionSize - Count
else
WriteSize := FBlockSize;
OldPos := Self.Position;
// write empty block
WriteBytes := Self.Write(Buf^,WriteSize);
if (WriteBytes <> WriteSize) then
raise EMYLDBException.Create(10097,ErrorLCannotWriteToStream,
[OldPos,Self.Size,WriteSize,WriteBytes]);
Inc(Count,WriteSize);
end; // while
finally
MemoryManager.FreeAndNillMem(Buf);
end;
end; // InternalIncreaseSize
//------------------------------------------------------------------------------
// set size of compressed stream
//------------------------------------------------------------------------------
procedure TMYLDBCompressedBLOBStream.InternalDecreaseSize(NewSize: Int64);
var Buf,OutBuf: PChar;
ExtensionSize,OldPos: Int64;
CurHdr,NumBlocks: Int64;
BytesWrite: Integer;
begin
CurHdr := NewSize div FBlockSize;
NumBlocks := CurHdr;
ExtensionSize := NewSize mod FBlockSize;
OutBuf := nil;
Buf := nil;
try
if (ExtensionSize > 0) then
begin
Inc(NumBlocks);
LoadBlock(CurHdr,Buf);
try
PrepareBufferForWriting(Buf,ExtensionSize,OutBuf,FHeaders.Items[CurHdr]);
finally
if (Buf <> nil) then
MemoryManager.FreeAndNillMem(Buf);
end;
end;
FBLOBDescriptor.NumBlocks := NumBlocks;
FHeaders.SetSize(NumBlocks);
if (ExtensionSize > 0) then
begin
FCompressedStream.Size := FHeaders.Positions[CurHdr];
if (FCompressedStream.Size <> FHeaders.Positions[CurHdr]) then
raise EMYLDBException.Create(10093,ErrorLInvalidStreamSize,
[FCompressedStream.Size,FHeaders.Positions[CurHdr]]);
FCompressedStream.Position := FCompressedStream.Size;
if (FCompressedStream.Position <> FCompressedStream.Size) then
raise EMYLDBException.Create(10094,ErrorLCannotSetPosition,
[FCompressedStream.Size,FCompressedStream.Position,
FCompressedStream.Size]);
FHeaders.Items[CurHdr].OffsetToNextHeader := FCompressedStream.Position +
Int64(FHeaders.Items[CurHdr].CompressedSize) +
sizeof(TMYLDBCompressedStreamBlockHeader);
FHeaders.Positions[CurHdr] := FCompressedStream.Position;
OldPos := FCompressedStream.Position;
BytesWrite := FCompressedStream.Write(FHeaders.Items[curHdr],
sizeof(TMYLDBCompressedStreamBlockHeader));
if (BytesWrite <> sizeof(TMYLDBCompressedStreamBlockHeader)) then
raise EMYLDBException.Create(10095,ErrorLWriteToStream,
[OldPos,FCompressedStream.Size,sizeof(TMYLDBCompressedStreamBlockHeader),BytesWrite]);
OldPos := FCompressedStream.Position;
BytesWrite := FCompressedStream.Write(OutBuf^,FHeaders.Items[CurHdr].CompressedSize);
if (BytesWrite <> sizeof(TMYLDBCompressedStreamBlockHeader)) then
raise EMYLDBException.Create(10096,ErrorLWriteToStream,
[OldPos,FCompressedStream.Size,sizeof(TMYLDBCompressedStreamBlockHeader),BytesWrite]);
end;
finally
if (OutBuf <> nil) then
MemoryManager.FreeAndNillMem(OutBuf);
end;
end; // InternalDecreaseSize
//------------------------------------------------------------------------------
// set size of compressed stream
//------------------------------------------------------------------------------
procedure TMYLDBCompressedBLOBStream.InternalSetSize(NewSize: Int64);
begin
if (FCompressionAlgorithm = acaNone) then
begin
FCompressedStream.Size := FStartPosition + NewSize;
end
else
if (NewSize > FUncompressedSize) then
begin
// go to last block
InternalIncreaseSize(NewSize);
end // NewSize > FUncompressedSize
else
if (NewSize < FUncompressedSize) then
begin
InternalDecreaseSize(NewSize);
end; // NewSize < FUncompressedSize
FUncompressedSize := NewSize;
FBLOBDescriptor.UncompressedSize := NewSize;
CalculateRate;
if (FPosition > FUncompressedSize) then
Position := FUncompressedSize;
end; // InternalSetSize
//------------------------------------------------------------------------------
// internal seek
//------------------------------------------------------------------------------
function TMYLDBCompressedBLOBStream.InternalSeek(NewPosition: Int64): Int64;
begin
if (FCompressionAlgorithm = acaNone) then
begin
FCompressedStream.Position := FStartPosition + NewPosition;
Result := FCompressedStream.Position - FStartPosition;
FPosition := Result;
end // no compression
else
begin
// compression
FPosition := NewPosition;
if (FPosition <= 0) then
begin
FPosition := 0;
FCurrentHeader := 0;
end
else
begin
if (FUncompressedSize = 0) then
FCurrentHeader := 0
else
FCurrentHeader := FHeaders.FindPosition(FPosition);
end;
Result := FPosition;
end; // compression
end; // InternalSeek
//------------------------------------------------------------------------------
// set size of compressed stream
//------------------------------------------------------------------------------
procedure TMYLDBCompressedBLOBStream.SetSize(NewSize: Longint);
begin
InternalSetSize(NewSize);
end; // SetSize
//------------------------------------------------------------------------------
// set size of compressed stream
//------------------------------------------------------------------------------
{$IFDEF D6H}
procedure TMYLDBCompressedBLOBStream.SetSize(const NewSize: Int64);
begin
InternalSetSize(NewSize);
end; // SetSize
{$ENDIF}
//------------------------------------------------------------------------------
// gets compressed size
//------------------------------------------------------------------------------
function TMYLDBCompressedBLOBStream.GetCompressedSize: Int64;
begin
Result := FCompressedStream.Size;
end; // GetCompressedSize
//------------------------------------------------------------------------------
// returns compression rate (100.0 if there is no compression)
//------------------------------------------------------------------------------
function TMYLDBCompressedBLOBStream.GetCompressionRate: Double;
begin
CalculateRate;
Result := FCompressionRate;
end; // GetCompressionRate
//------------------------------------------------------------------------------
// Create
//------------------------------------------------------------------------------
constructor TMYLDBCompressedBLOBStream.Create(
Stream: TStream;
BLOBDescriptor: TMYLDBBLOBDescriptor;
ToCreate: Boolean = false;
ToRepair: Boolean = false
);
begin
FCompressedStream := Stream;
FHeaders := nil;
FRepair := ToRepair;
FBLOBDescriptor := BLOBDescriptor;
FCompressionAlgorithm := TMYLDBCompressionAlgorithm(
FBLOBDescriptor.CompressionAlgorithm);
FCompressionMode := FBLOBDescriptor.CompressionMode;
FCompressedStream.Position := FBLOBDescriptor.StartPosition;
if (FCompressedStream.Position <> FBLOBDescriptor.StartPosition) then
raise EMYLDBException.Create(10103,ErrorLCannotSetPosition,
[FBLOBDescriptor.StartPosition,FCompressedStream.Position,
FCompressedStream.Size]);
FBlockSize := BLOBDescriptor.BlockSize;
FStartPosition := BLOBDescriptor.StartPosition;
if (FCompressionAlgorithm = acaNone) then
begin
// no compression
// try to set start position in source "compressed" stream
if (FCompressedStream.Position <> FBLOBDescriptor.StartPosition) then
raise EMYLDBException.Create(10079,ErrorLCannotSetPosition,
[FBLOBDescriptor.StartPosition,FCompressedStream.Position,
FCompressedStream.Size]);
// default block size
if (ToCreate) then
begin
// create new stream
FCompressedSize := 0;
FUncompressedSize := 0;
end
else
begin
// open existing stream
FUncompressedSize := FBLOBDescriptor.UncompressedSize;
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -