📄 uwinhelpfiles.pas
字号:
{Calculates the hash value of a name of a topic in the help file.
~param TopicName the name of a topic to calculate the hash value from
~result the hash value of the name }
function GetTopicNameHashValue(const TopicName: String): String;
//values for the hash algorithm
const HashTranslationTable: array[Char] of Byte =
($00, $D1, $D2, $D3, $D4, $D5, $D6, $D7,
$D8, $D9, $DA, $DB, $DC, $DD, $DE, $DF,
$E0, $E1, $E2, $E3, $E4, $E5, $E6, $E7,
$E8, $E9, $EA, $EB, $EC, $ED, $EE, $EF,
$F0, $0B, $F2, $F3, $F4, $F5, $F6, $F7,
$F8, $F9, $FA, $FB, $FC, $FD, $0C, $FF,
$0A, $01, $02, $03, $04, $05, $06, $07,
$08, $09, $0A, $0B, $0C, $0D, $0E, $0F,
$10, $11, $12, $13, $14, $15, $16, $17,
$18, $19, $1A, $1B, $1C, $1D, $1E, $1F,
$20, $21, $22, $23, $24, $25, $26, $27,
$28, $29, $2A, $0B, $0C, $0D, $0E, $0D,
$10, $11, $12, $13, $14, $15, $16, $17,
$18, $19, $1A, $1B, $1C, $1D, $1E, $1F,
$20, $21, $22, $23, $24, $25, $26, $27,
$28, $29, $2A, $2B, $2C, $2D, $2E, $2F,
$50, $51, $52, $53, $54, $55, $56, $57,
$58, $59, $5A, $5B, $5C, $5D, $5E, $5F,
$60, $61, $62, $63, $64, $65, $66, $67,
$68, $69, $6A, $6B, $6C, $6D, $6E, $6F,
$70, $71, $72, $73, $74, $75, $76, $77,
$78, $79, $7A, $7B, $7C, $7D, $7E, $7F,
$80, $81, $82, $83, $0B, $85, $86, $87,
$88, $89, $8A, $8B, $8C, $8D, $8E, $8F,
$90, $91, $92, $93, $94, $95, $96, $97,
$98, $99, $9A, $9B, $9C, $9D, $9E, $9F,
$A0, $A1, $A2, $A3, $A4, $A5, $A6, $A7,
$A8, $A9, $AA, $AB, $AC, $AD, $AE, $AF,
$B0, $B1, $B2, $B3, $B4, $B5, $B6, $B7,
$B8, $B9, $BA, $BB, $BC, $BD, $BE, $BF,
$C0, $C1, $C2, $C3, $C4, $C5, $C6, $C7,
$C8, $C9, $CA, $CB, $CC, $CD, $CE, $CF);
var Hash :DWord; //the hash value
i :Integer; //counter through the string
begin
if TopicName = '' then //string empty?
Result := #01#00#00#00 //is p.d. the value 1
else
begin //else calculate the hash value
Hash := 0;
for i := 1 to Length(TopicName) do
Hash := Hash * 43 + HashTranslationTable[TopicName[i]];
Result := Char(Hash) + Char(Hash shr 8) + //and return it as bytes
Char(Hash shr 16) + Char(Hash shr 24);
end;
end;
{Writes the compressed content of the bitmap into the stream.
~param Bitmap the bitmap whose content should be written
~param Compressed stream to write the compressed content into }
procedure GetCompressedBitmapContent(Bitmap: TBitmap;
Compressed: TMemoryStream);
{$IFDEF UseLZ77}
const N = 4096; // = 2 ^ 12 //number of bytes in the buffer
F = 16; // = 2 ^ (16 - 12) //number of bytes to copy from buffer
{Compresses the data from one stream to another one with the LZ77 algorithm.
~param Source the data to compress
~param ComprStream the stream to write the compressed data to }
procedure Compress(Source, ComprStream: TStream);
const THRESHOLD = 3; //minimum matching bytes to reference
NotInList = -1; //entry for end of list/tree
var buffer :Pointer; //whole needed buffer
//tree nodes to search matching sequences of bytes
node :PSmallInt;
dad :PSmallInt; //list of parents (node+1)
lson :PSmallInt; //list of lesser (left) nodes (node+1+N)
rson :PSmallInt; //list of bigger (right) nodes (node+1+N+N)
root :PSmallInt; //root(s) of the bytes (node+1+N+N+N)
{Inserts the sequence of bytes in the sorted tree.
~param index index of the bytes
~param length number of bytes in the sequence
~param matchpos out: position of matching bytes
~result number of already matching bytes }
function Insert(index, length: SmallInt; var matchpos: SmallInt): SmallInt;
var p :PSmallInt; //current node in the sorted tree of sequences
j :SmallInt; //index of currently comparing bytes
k, l :SmallInt; //minimum equal bytes
n :SmallInt; //counter through bytes to compare
c :SmallInt; //difference of bytes
begin
k := 1; //only the first byte will be equal
l := 1;
Result := THRESHOLD - 1; //no match so far
//get entry in tree for value of the first byte
p := PSmallInt(Integer(root) + PByte(Integer(Buffer) + index)^ * 2);
//remove the current position from the tree
PSmallInt(Integer(lson) + index * 2)^ := NotInList;
PSmallInt(Integer(rson) + index * 2)^ := NotInList;
c := 1;
//while end of tree not reached and not found
while (p^ <> NotInList) and (c <> 0) do
begin
j := p^; //get index from the current tree node
n := k; //get number of minimal equal bytes
if l < n then
n := l;
while (n < length) and //compare all equal bytes
(PByte(Integer(Buffer) + j + n)^ =
PByte(Integer(Buffer) + index + n)^) do
inc(n);
c := PByte(Integer(Buffer) + j + n)^ - //compare last byte
PByte(Integer(Buffer) + index + n)^;
if n > Result then //new best match?
begin
Result := n; //save it and
matchpos := j; //its position
end;
if c < 0 then //sequence of bytes smaller than current one?
begin
p := PSmallInt(Integer(lson) + j * 2); //follow left node of the tree
k := n;
end
else
if c > 0 then //sequence of bytes bigger than current one?
begin
p := PSmallInt(Integer(rson) + j * 2); //follow right node of the tree
l := n;
end
else //sequences are equal
begin //remove old sequence
PSmallInt(Integer(dad) + j * 2)^ := NotInList;
//move old children to new parent
PSmallInt(Integer(dad) + PSmallInt(Integer(lson) + j * 2)^ * 2)^ :=
(Integer(lson) - Integer(node)) div 2 + index;
PSmallInt(Integer(dad) + PSmallInt(Integer(rson) + j * 2)^ * 2)^ :=
(Integer(rson) - Integer(node)) div 2 + index;
PSmallInt(Integer(lson) + index * 2)^ :=
PSmallInt(Integer(lson) + j * 2)^;
PSmallInt(Integer(rson) + index * 2)^ :=
PSmallInt(Integer(rson) + j * 2)^;
end; // c = 0
end; //while p^ <> NotInList and c <> 0
//set node for this byte sequence
PSmallInt(Integer(dad) + index * 2)^ := (Integer(p) - Integer(node)) div 2;
p^ := index; //and save the sequence in the tree
end;
{Deletes a sequence of bytes from the sorted tree.
~param index index of the bytes }
procedure Delete(index: SmallInt);
var j :SmallInt; //general index
begin
if PSmallInt(Integer(dad) + index * 2)^ <> NotInList then //in the tree?
begin //no right child?
if PSmallInt(Integer(rson) + index * 2)^ = NotInList then
j := PSmallInt(Integer(lson) + index * 2)^ //just move the left one
else //no left child?
if PSmallInt(Integer(lson) + index * 2)^ = NotInList then
j := PSmallInt(Integer(rson) + index * 2)^ //just move the right one
else
begin //two children
//get biggest descendant on the lesser half
j := PSmallInt(Integer(lson) + index * 2)^;
if PSmallInt(Integer(rson) + j * 2)^ <> NotInList then
begin
//get biggest descendant
repeat
j := PSmallInt(Integer(rson) + j * 2)^
until PSmallInt(Integer(rson) + j * 2)^ = NotInList;
//remove this biggest descendant from the tree
PSmallInt(Integer(node) + PSmallInt(Integer(dad) + j * 2)^ * 2)^ :=
PSmallInt(Integer(lson) + j * 2)^;
PSmallInt(Integer(dad) + PSmallInt(Integer(lson) + j * 2)^ * 2)^ :=
PSmallInt(Integer(dad) + j * 2)^;
PSmallInt(Integer(lson) + j * 2)^ :=
PSmallInt(Integer(lson) + index * 2)^;
PSmallInt(Integer(dad) +
PSmallInt(Integer(lson) + index * 2)^ * 2)^ :=
(Integer(lson) - Integer(node)) div 2 + j;
end;
//move the original bigger sub-tree to this node
PSmallInt(Integer(rson) + j * 2)^ :=
PSmallInt(Integer(rson) + index * 2)^;
PSmallInt(Integer(dad) + PSmallInt(Integer(rson) + index * 2)^ * 2)^ :=
(Integer(rson) - Integer(node)) div 2 + j;
end;
//move the other node to replace the node to be deleted
PSmallInt(Integer(dad) + j * 2)^ := PSmallInt(Integer(dad) + index * 2)^;
PSmallInt(Integer(node) +
PSmallInt(Integer(dad) + index * 2)^ * 2)^ := j;
PSmallInt(Integer(dad) + index * 2)^ := NotInList;
end; //if in tree
end;
{Gets a byte from the compressed content of the bitmap.
~param TheByte the byte form the content (only if available) is returned
~result whether there was still a byte of data that could be returned }
function GetNextContentByte(var TheByte: Byte): Boolean;
begin
Result := Source.Read(TheByte, 1) = 1; //just read one byte
end;
var
len :SmallInt; //number of bytes in the buffer
run :SmallInt; //number of bytes needed to add them
index :SmallInt; //current position inside the buffer
size :SmallInt; //number of bytes in write buffer
mask :SmallInt; //counter through bits in index byte
match :SmallInt; //number of matching bytes
matchpos :SmallInt; //position of matching sequence
ch :Byte; //each single byte from the stream
Read :Boolean; //if a byte could be read
buf :array[0..16] of Char; //buffer to write data
begin
//get whole needed buffer in one peace (buffer for bytes and sorted tree)
GetMem(Buffer, N+F + (N+1+N+N+256) * SizeOf(WORD));
try
Node := PSmallInt(Integer(Buffer) + N + F); //root of the tree = NIL
dad := PSmallInt(Integer(Node) + 2 * 1); //parent nodes
rson := PSmallInt(Integer(Node) + 2 * (1+N)); //nodes of the children
lson := PSmallInt(Integer(Node) + 2 * (1+N+N));
//roots for each byte in the buffer
root := PSmallInt(Integer(Node) + 2 * (1+N+N+N));
//clear all roots, the NIL entry and all parent nodes
FillChar(root^, 256 * 2, NotInList); //for(i=0;i<256;i++) root[i]=NIL;
FillChar(Node^, (N + 1) * 2, NotInList); //for(i=NIL;i<N;i++) dad[i]=NIL;
Size := 1; //buffer contains only the index byte
Mask := 1; //mask for the first bit
buf[0] := #0; //index byte is empty so far
index := N-F-F; //start filling at the end of the buffer
len := 0; //no bytes read so far
while (len < F) and GetNextContentByte(ch) do //read first chunk of bytes
begin
PByte(Integer(Buffer) + index + F)^ := ch; //save byte
index := (index + 1) and (N - 1); //next index in buffer
inc(len); //another valid byte
end;
run := len; //use default chunk size, or less if only data is too short
repeat //compress all bytes
Read := GetNextContentByte(ch); //read another byte
if not Read then
ch := $FF;
if index >= N - F then //index is at the end of the buffer?
begin
Delete(index + F - N); //delete position of oldest byte
PByte(Integer(Buffer) + index + F)^ := ch; //write it to the end and
PByte(Integer(Buffer) + index + F - N)^ := ch; //beginning of buffer
end
else
begin
Delete(index + F); //delete position of previous byte
PByte(Integer(Buffer) + index + F)^ := ch; //write the byte to buffer
end;
//insert current byte in sorted tree, and get number matching bytes
match := Insert(index, run, matchpos);
if not Read then //end of the data reached?
begin
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -