unit RLELite;
interface
uses
Windows;
function RLELength(pInput
ointer;dwCount
WORD)
WORD;
function RLEEncode(pInput
ointer;dwCount
WORD;pOutput
ointer)
WORD;
function RLEDecode(pInput
ointer;pOutput
ointer)
WORD;
implementation
// Global Variables
var
dwCodeLength
WORD = 19;
// Return the Run Length Encoded Size
function RLELength(pInput
ointer;dwCount
WORD)
WORD;
label
_LoadByte, _CompareBytes, _Finished, _BuildCode, _CheckShift,_ShiftData,
_Continue, _Exit, _Done;
var
dwNewCount, dwMaxRun,dwUnusedByte
WORD;
fOutput:Boolean;
begin
// Compressed Count
dwNewCount := 4;
// Max Run Length
// Variables Used for Code Shifting
dwUnusedByte := 0;
fOutput := FALSE;
asm
pushad;
// Calculate the Maximum Run Length
MOV EDX,1;
MOV ECX,dwCodeLength;
SUB ECX,9;
SHL EDX,CL;
SUB EDX,1;
MOV dwMaxRun,EDX;
// Load the Count of Bytes to Encode
MOV EDX,dwCount;
// Initialize the Output Bits
XOR EDI,EDI;
// Initialize the Storage DWORD
XOR ESI,ESI;
// Load the Byte to Compare
_LoadByte:
// Save the Storage DWORD
PUSH ESI;
// Load a Byte
MOV ESI,pInput;
MOV AL,[ESI];
// Initialize the Run Length Count to 1
MOV ECX,DWORD PTR 1;
// Compare the Bytes
_CompareBytes:
// Check for EOD
CMP EDX,0;
JZ _Finished;
// Compare to the Max Length for an Encode
CMP ECX,dwMaxRun;
JA _Finished;
// Compare the Bytes
CMP AL,[ESI + ECX];
// Increment the Run Length
LEA ECX,[ECX + 1];
// Decrement the Bytes Processed
LEA EDX,[EDX - 1];
// Branch for the Comparison
JE _CompareBytes;
// Finished Encoding
_Finished:
// Decrement the Run Length for Encoding
DEC ECX;
// Increment the Pointer to the Source Data
ADD ESI,ECX;
MOV pInput,ESI;
// Restore the Storage DWORD
POP ESI;
// Check for a 1:1 Character Copy
CMP ECX,1;
JNZ _BuildCode;
// Move in the Character
XOR EBX,EBX;
MOV BH,1;
MOV BL,AL;
// Set the Code Length
MOV ECX,9;
// Jump to Checking the Bit Shifting
JMP _CheckShift;
// Build the Compression Code
_BuildCode:
MOV EBX,ECX;
SHL EBX,8;
MOV BL,AL;
// Set the Code Length
MOV ECX,dwCodeLength;
// See How Many Bits Can be Shifted to the Output DWORD
_CheckShift:
ADD EDI,ECX;
CMP EDI,32;
JLE _ShiftData;
// See How Many Bits of the Last Code Can't Be Used
SUB EDI,32;
// Adjust ECX to Handle only the Bits that Can Be Used
SUB ECX,EDI;
// Save the Code
MOV dwUnusedByte,EBX;
// Shift the Input Symbol to the Right
PUSH ECX;
MOV ECX,EDI;
SHR EBX,CL;
POP ECX;
// Set the Output Flag
MOV fOutput,TRUE;
// Shift the Output Data
_ShiftData:
// Shift the Output Symbol to Handle a New Symbol
SHL ESI,CL;
// OR the Output Symbol with New Symbol
OR ESI,EBX;
// Check for Outputting a full DWORD
CMP fOutput,FALSE;
JE _Continue;
// Increment the Compression Count
ADD dwNewCount,4;
// Remove the Bits we Used
MOV EAX,32;
SUB EAX,EDI;
MOV ECX,EAX ;
// Restore the Unused Portion of the Code
MOV EAX,dwUnusedByte;
SHL EAX,CL;
SHR EAX,CL;
// Update the Code to Have the Left Over Bits
MOV ESI,EAX;
// Initialize the Left Over Bits
MOV dwUnusedByte,0;
// Reset the Output Flag
MOV fOutput,FALSE;
// Compare for More Data
_Continue:
CMP EDX,0;
JZ _Exit;
// Go Back for More Bytes
JMP _LoadByte;
// Finished Encoding
_Exit:
// Update Any Remaining Compression data in the Buffer
CMP EDI,0;
JE _Done;
// Left Shift the Remaining Bits
MOV EAX,32;
SUB EAX,EDI;
MOV ECX,EAX;
SHL ESI,CL;
// Increment the Compression Count
ADD dwNewCount,4;
// Done Encoding
_Done:
popad;
end;
// Return the Compressed Count
Result := dwNewCount;
end;
// Run Length Encode the Input Data to the Output Data
function RLEEncode(pInput
ointer;dwCount
WORD;pOutput
ointer)
WORD;
label
_LoadByte, _CompareBytes ,_Finished, _BuildCode, _CheckShift, _ShiftData,
_Continue, _Exit, _Done;
var
dwNewCount
WORD;
dwUnusedByte: DWORD;
fOutput: Boolean;
dwMaxRun
WORD;
begin
// Compressed Count
dwNewCount := 4;
// Variables Used for Code Shifting
dwUnusedByte := 0;
fOutput := FALSE;
// Max Run Length
asm
// Calculate the Maximum Run Length
pushad;
MOV EDX,1
MOV ECX,dwCodeLength
SUB ECX,9
SHL EDX,CL
SUB EDX,1
MOV dwMaxRun,EDX
// Point to the Input Byte
MOV EDI,pOutput
// Load the Count of Bytes to Encode
MOV EDX,dwCount
// Store the Original Length in the Compressed Data
MOV [EDI],EDX
// Increment the Input Data Pointer
ADD EDI,4
MOV pOutput,EDI
// Initialize the Output Bits
XOR EDI,EDI
// Initialize the Storage DWORD
XOR ESI,ESI
// Load the Byte to Compare
_LoadByte:
// Save the Storage DWORD
PUSH ESI
// Load a Byte
MOV ESI,pInput
MOV AL,[ESI]
// Initialize the Run Length Count to 1
MOV ECX,DWORD PTR 1
// Compare the Bytes
_CompareBytes:
// Check for EOD
CMP EDX,0
JZ _Finished
// Compare to the Max Length for an Encode
CMP ECX,dwMaxRun
JA _Finished
// Compare the Bytes
CMP AL,[ESI + ECX]
// Increment the Run Length
LEA ECX,[ECX + 1]
// Decrement the Bytes Processed
LEA EDX,[EDX - 1]
// Branch for the Comparison
JE _CompareBytes
// Finished Encoding
_Finished:
// Decrement the Run Length for Encoding
DEC ECX
// Increment the Pointer to the Source Data
ADD ESI,ECX
MOV pInput,ESI
// Restore the Storage DWORD
POP ESI
// Check for a 1:1 Character Copy
CMP ECX,1
JNZ _BuildCode
// Move in the Character
XOR EBX,EBX
MOV BH,1
MOV BL,AL
// Set the Code Length
MOV ECX,9
// Jump to Checking the Bit Shifting
JMP _CheckShift
// Build the Compression Code
_BuildCode:
MOV EBX,ECX
SHL EBX,8
MOV BL,AL
// Set the Code Length
MOV ECX,dwCodeLength
// See How Many Bits Can be Shifted to the Output DWORD
_CheckShift:
ADD EDI,ECX
CMP EDI,32
JLE _ShiftData
// See How Many Bits of the Last Code Can't Be Used
SUB EDI,32
// Adjust ECX to Handle only the Bits that Can Be Used
SUB ECX,EDI
// Save the Code
MOV dwUnusedByte,EBX
// Shift the Input Symbol to the Right
PUSH ECX
MOV ECX,EDI
SHR EBX,CL
POP ECX
// Set the Output Flag
MOV fOutput,TRUE
// Shift the Output Data
_ShiftData:
// Shift the Output Symbol to Handle a New Symbol
SHL ESI,CL
// OR the Output Symbol with New Symbol
OR ESI,EBX
// Check for Outputting a full DWORD
CMP fOutput,FALSE
JE _Continue
// Output an Encoded Symbol
MOV EAX,ESI
PUSH EDI
MOV EDI,pOutput
MOV [EDI],EAX
ADD EDI,4
MOV pOutput,EDI
POP EDI
// Increment the Compression Count
ADD dwNewCount,4
// Remove the Bits we Used
MOV EAX,32
SUB EAX,EDI
MOV ECX,EAX
// Restore the Unused Portion of the Code
MOV EAX,dwUnusedByte
SHL EAX,CL
SHR EAX,CL
// Update the Code to Have the Left Over Bits
MOV ESI,EAX
// Initialize the Left Over Bits
MOV dwUnusedByte,0
// Reset the Output Flag
MOV fOutput,FALSE
// Compare for More Data
_Continue:
CMP EDX,0
JZ _Exit
// Go Back for More Bytes
JMP _LoadByte
// Finished Encoding
_Exit:
// Update Any Remaining Compression data in the Buffer
CMP EDI,0
JE _Done
// Left Shift the Remaining Bits
MOV EAX,32
SUB EAX,EDI
MOV ECX,EAX
SHL ESI,CL
// Output the Final Encoded Symbol
MOV EAX,ESI
MOV EDI,pOutput
MOV [EDI],EAX
// Increment the Compression Count
ADD dwNewCount,4
// Done Encoding
_Done:
popad;
end;
// Return the Compressed Count
Result := dwNewCount;
end;
// Run Length Decode the Input Data to the Output Data
function RLEDecode(pInput
ointer;pOutput
ointer)
WORD;
label
_LoopInput, _LeftShift, _Output,_CheckBits, _Exit ;
var
dwCount
WORD;
dwCompCount
WORD;
dwCodeLength2
WORD;
begin
// Compressed Count
asm
pushad;
// Get the CodeLength - 1 for Checking a 1:1 Compression
MOV EAX,dwCodeLength
DEC EAX
MOV dwCodeLength2,EAX
// Point to the Input Byte
MOV ESI,pInput
// Point to the Output Byte
MOV EDI,pOutput
// Load the Count of Bytes Encoded
LODSD
// Save the New Input Location
MOV pInput,ESI
// Save the Count of the UnCompressed Data
MOV dwCompCount,EAX
// Initialize the Count of Bytes Decoded
MOV dwCount,EAX
// Initialize Number of Bits for Current Symbol to Process
MOV ESI,dwCodeLength
// Initialize the Decode Storage
XOR EDX,EDX
// Main Loop for Reading Input
_LoopInput:
// Save the Number of Bits for the Current Symbol
PUSH ESI
// Point to the Input Data
MOV ESI,pInput
// Read an Encoded DWORD
LODSD
// Save the Pointer to the Input Data
MOV pInput,ESI
// Restore the Number of Bits for the Current Symbol
POP ESI
// Initialize Number of Bits to Process
MOV EBX,32
// Shift in an Encoded Symbol, 1 bit at a time
_LeftShift:
// Shift 1 Bit of the Input Code to the Output
SHLD EDX,EAX,1
// Shift the Input Code 1 Bit to the Left
SHL EAX,1
// Decrement the Number of Bits Processed
DEC ESI
// Check for a Fully Encoded Symbol
JZ _Output
// Compare the High Bit for RLE or Character Encode
CMP ESI,dwCodeLength2
JNZ _CheckBits
// Compare the High Bit, 0 = RLE, 1 = 1:1 Character Encode
CMP EDX,0
JZ _CheckBits
// Update the Bits Left to 8
MOV ESI,8
// Check for More Bits to Process
_CheckBits:
// Decrement the Number of Bits Processed in the Input DWORD
DEC EBX
// Continue Shifting More Bits
JNZ _LeftShift
// Read Another DWORD of Data
JMP _LoopInput
// Output the Run Length Amount of the Code
_Output:
// Get the Run Length
MOV ECX,EDX
SHR ECX,8
// Get the Code
AND EDX,255
// Save the Input DWORD
PUSH EAX
// Copy the Code
MOV EAX,EDX
// Save the Run Length
PUSH ECX
// Output the Run Length Amount of the Code
REP STOSB
// Restore the Run Length
POP ECX
// Restore the Input DWORD
POP EAX
// Check for More Data to Decode
SUB dwCompCount,ECX
JZ _Exit
// Initialize the Decode Storage
XOR EDX,EDX
// Initialize Number of Bits for Current Symbol to Process
MOV ESI,dwCodeLength
// Check for More Bits to Process
JMP _CheckBits
// Finished
_Exit:
popad;
end;
// Return the Count of Uncompressed Data
Result := dwCount;
end;
end.