Delphi encrypted file is much smaller than the original? - delphi

I am loading a binary file into a memorystream, then encoding the data, and returning the result as a string, then writing the result into another memorystream, and saving it to a file, but when it saved the file is much smaller than the original 25kb from 400kb...lol, im pretty sure it's because I've hit the limit of what a string is capable of handling.
it's definately encoding what data it does save in the new file correctly, I decrypted it and compared it to the begining of the original file.
I know this is a very long winded method and probibly has some unnecesary steps, so loading it into bStream would be a very effective resolution. My question is how could I have the data returned to bStream rather than having it returned to a string then writing the string to bStream at that point as I do believe, that it would solve my problem, any other suggestions would also be appreciated. Im using Delphi 6.
Heres My Code:
function B64Encode(pInput: pointer; pOutput: pointer; Size: longint): longint;
var
i, iptr, optr: integer;
Input, Output: PByteArray;
begin
Input := PByteArray(pInput);
Output := PByteArray(pOutput);
iptr := 0;
optr := 0;
for i := 1 to (Size div 3) do
begin
Output^[optr + 0] := B64[Input^[iptr] shr 2];
Output^[optr + 1] := B64[((Input^[iptr] and 3) shl 4) + (Input^[iptr + 1] shr 4)];
Output^[optr + 2] := B64[((Input^[iptr + 1] and 15) shl 2) + (Input^[iptr + 2] shr 6)];
Output^[optr + 3] := B64[Input^[iptr + 2] and 63];
Inc(optr, 4);
Inc(iptr, 3);
end;
case (Size mod 3) of
1:
begin
Output^[optr + 0] := B64[Input^[iptr] shr 2];
Output^[optr + 1] := B64[(Input^[iptr] and 3) shl 4];
Output^[optr + 2] := byte('=');
Output^[optr + 3] := byte('=');
end;
2:
begin
Output^[optr + 0] := B64[Input^[iptr] shr 2];
Output^[optr + 1] := B64[((Input^[iptr] and 3) shl 4) + (Input^[iptr + 1] shr 4)];
Output^[optr + 2] := B64[(Input^[iptr + 1] and 15) shl 2];
Output^[optr + 3] := byte('=');
end;
end;
Result := ((Size + 2) div 3) * 4;
end;
procedure TForm1.Button2Click(Sender: TObject);
var
aStream, bStream: TMemoryStream;
strastream: string;
szaStream: integer;
begin
bStream := TMemoryStream.Create;
aStream := TMemoryStream.Create;
aStream.LoadFromFile('C:\file1.exe');
szaStream := (astream.size + 2) div (3 * 4);
SetLength(strastream, szaStream);
B64Encode(astream.Memory, #strastream[1], Length(strastream));
bstream.WriteBuffer(strastream[1], szaStream);
AttachToFile('C:\file2.exe', bStream);
bstream.Free;
aStream.Free;
end;
Thanks.

Your length calculations are all wrong as has been pointed out in comments.
szaStream := (astream.size + 2) div (3 * 4);
This means that your encoded stream is 1/12th the size of the input stream. But it needs to be larger. You meant:
szaStream := ((astream.size * 4) div 3) + 2;
I also do not see the point of using a string here. You can write directly to the stream.
And, it's worth repeating that with base 64 you are encoding and not encrypting.
In my opinion, there is little point writing all this yourself when Delphi ships with a base 64 implementation. The unit is called EncdDecd, or Soap.EncdDecd if you are using namespaces. And the only function you need is
procedure EncodeStream(Input, Output: TStream);
Create two file streams, one for reading, one for writing, and pass them to that function. For example:
procedure EncodeFileBase64(const InFileName, OutFileName:string);
var
Input, Output: TStream;
begin
Input := TFileStream.Create(InFileName, fmOpenRead);
try
Output := TFileStream.Create(InFileName, fmCreate);
try
EncodeStream(Input, Output);
finally
Output.Free;
end;
finally
Input.Free;
end;
end;
Should you need to reverse the process, do so with, you guessed it, DecodeStream.
If performance matters then you may need to use a buffered stream rather than TFileStream. For example: Buffered files (for faster disk access)

Related

Why embedded CRC and current CRC differs?

I have found this Delphi examle. It is supposed to embed CRC and check current CRC. Both should match, but I get different results. How to fix it? And how to speed it up?
CRC32Calc.pas
unit CRC32Calc;
interface
uses Classes, SysUtils, windows, messages;
type
Long = record
LoWord: Word;
HiWord: Word;
end;
const
CRCPOLY = $EDB88320;
procedure BuildCRCTable;
function RecountCRC(b: byte; CrcOld: LongWord): LongWord;
function GetCRC32(FileName: string; Full: boolean): string;
function SetEmbeddedCRC(FileName: string): string;
function GetEmbeddedCRC(FileName: string): string;
function BytesToHexStr(pB: PByte; BufSize: LongWord): String;
function HexStrToBytes(Str: String): String;
implementation
var
CRCTable: array [0 .. 512] Of LongWord;
// A helper routine that creates and initializes
// the lookup table that is used when calculating a CRC polynomial
procedure BuildCRCTable;
var
i, j: Word;
r: LongWord;
begin
FillChar(CRCTable, SizeOf(CRCTable), 0);
for i := 0 to 255 do
begin
r := i shl 1;
for j := 8 downto 0 do
if (r and 1) <> 0 then
r := (r Shr 1) xor CRCPOLY
else
r := r shr 1;
CRCTable[i] := r;
end;
end;
// A helper routine that recalculates polynomial relative to the specified byte
function RecountCRC(b: byte; CrcOld: LongWord): LongWord;
begin
RecountCRC := CRCTable[byte(CrcOld xor LongWord(b))
] xor ((CrcOld shr 8) and $00FFFFFF)
end;
// A helper routine that converts Word into String
function HextW(w: Word): string;
const
h: array [0 .. 15] Of char = '0123456789ABCDEF';
begin
HextW := '';
HextW := h[Hi(w) shr 4] + h[Hi(w) and $F] + h[Lo(w) shr 4] + h[Lo(w) and $F];
end;
// A helper routine that converts LongWord into String
function HextL(l: LongWord): string;
begin
with Long(l) do
HextL := HextW(HiWord) + HextW(LoWord);
end;
// Calculate CRC32 checksum for the specified file
function GetCRC32(FileName: string; Full: boolean): string;
var
f: TFileStream;
i, CRC: LongWord;
aBt: byte;
begin
// Build a CRC table
BuildCRCTable;
CRC := $FFFFFFFF;
// Open the file
f := TFileStream.Create(FileName, (fmOpenRead or fmShareDenyNone));
// To calculate CRC for the whole file use this loop boundaries
if Full then
for i := 0 to f.Size - 1 do
begin
f.Read(aBt, 1);
CRC := RecountCRC(aBt, CRC);
end
else
// To calculate CRC for the file excluding the last 4 bytes
// use these loop boundaries
for i := 0 to f.Size - 5 do
begin
f.Read(aBt, 1);
CRC := RecountCRC(aBt, CRC);
end;
f.Destroy;
CRC := Not CRC;
Result := HextL(CRC);
end;
// Calculate CRC and writes it to the end of file
function SetEmbeddedCRC(FileName: string): string;
var
f: TFileStream;
CRCOffset: LongWord;
CRC: string;
begin
f := TFileStream.Create(FileName, (fmOpenReadWrite or fmShareDenyNone));
CRCOffset := f.Size;
// Append a placeholder for actual CRC to the file
f.Seek(CRCOffset, TSeekOrigin.soBeginning);
f.Write(PByte(HexStrToBytes('FFFFFFFF'))^, 4);
// Obtain CRC
CRC := GetCRC32(FileName, True);
// Write CRC to the end of file
f.Seek(CRCOffset, TSeekOrigin.soBeginning);
f.Write(PByte(HexStrToBytes(CRC))^, 4);
f.Destroy;
Result := CRC;
end;
// Extract the CRC that was stored at last 4 bytes of a file
function GetEmbeddedCRC(FileName: string): string;
var
f: TFileStream;
CRCOffset: LongWord;
pB: PByte;
begin
GetMem(pB, 4);
// Open file
f := TFileStream.Create(FileName, (fmOpenRead or fmShareDenyNone));
// Proceed upto the end of file
CRCOffset := f.Size - 4;
f.Seek(CRCOffset, TSeekOrigin.soBeginning);
// Read the last four bytes where the CRC is stored
f.Read(pB^, 4);
f.Destroy;
Result := BytesToHexStr(pB, 4);
end;
// A helper routine that converts byte value to string with hexadecimal integer
function BytesToHexStr(pB: PByte; BufSize: LongWord): String;
var
i, j, b: LongWord;
begin
SetLength(Result, 2 * BufSize);
for i := 1 to BufSize do
begin
for j := 0 to 1 do
begin
if j = 1 then
b := pB^ div 16
else
b := pB^ - (pB^ div 16) * 16;
case b of
0:
Result[2 * i - j] := '0';
1:
Result[2 * i - j] := '1';
2:
Result[2 * i - j] := '2';
3:
Result[2 * i - j] := '3';
4:
Result[2 * i - j] := '4';
5:
Result[2 * i - j] := '5';
6:
Result[2 * i - j] := '6';
7:
Result[2 * i - j] := '7';
8:
Result[2 * i - j] := '8';
9:
Result[2 * i - j] := '9';
10:
Result[2 * i - j] := 'A';
11:
Result[2 * i - j] := 'B';
12:
Result[2 * i - j] := 'C';
13:
Result[2 * i - j] := 'D';
14:
Result[2 * i - j] := 'E';
15:
Result[2 * i - j] := 'F';
end;
end;
Inc(pB);
end;
end;
// A helper routine that converts string with hexadecimal integer to byte value
function HexStrToBytes(Str: String): String;
var
b, b2: byte;
lw, lw2, lw3: LongWord;
begin
lw := Length(Str) div 2;
SetLength(Result, lw);
for lw2 := 1 to lw do
begin
b := 0;
for lw3 := 0 to 1 do
begin
case Str[2 * lw2 - lw3] of
'0':
b2 := 0;
'1':
b2 := 1;
'2':
b2 := 2;
'3':
b2 := 3;
'4':
b2 := 4;
'5':
b2 := 5;
'6':
b2 := 6;
'7':
b2 := 7;
'8':
b2 := 8;
'9':
b2 := 9;
'a':
b2 := 10;
'b':
b2 := 11;
'c':
b2 := 12;
'd':
b2 := 13;
'e':
b2 := 14;
'f':
b2 := 15;
'A':
b2 := 10;
'B':
b2 := 11;
'C':
b2 := 12;
'D':
b2 := 13;
'E':
b2 := 14;
'F':
b2 := 15;
else
b2 := 0;
end;
if lw3 = 0 then
b := b2
else
b := b + 16 * b2;
end;
Result[lw2] := char(b);
end;
end;
end.
AppendCRC
program AppendCRC;
{$APPTYPE CONSOLE}
uses
SysUtils, Classes,
CRC32Calc in '..\CRC32Checker\CRC32Calc.pas';
var
FileName: string;
begin
{ TODO -oUser -cConsole Main : Insert code here }
if ParamCount = 1 then
begin
FileName := ParamStr(1);
// Verify whether a file exists
if not FileExists(FileName) then
begin
WriteLn('The specified file does not exist.');
Exit;
end;
WriteLn('Full checksum (before): ' + GetCRC32(FileName, True));
SetEmbeddedCRC(FileName);
WriteLn('Half checksum: ' + GetCRC32(FileName, False));
WriteLn('Full checksum (after): ' + GetCRC32(FileName, True));
WriteLn('GetEmbeddedCRC: :' + GetEmbeddedCRC(FileName));
WriteLn('The checksum was successfully embedded.')
end
else
begin;
WriteLn('Wrong parameters.');
WriteLn('Parameter1 - Full path to file.');;
end;
end.
My results are:
AppendCRC.exe Hello_Delphi_World.exe
Full checksum (before): 1912DA64
Half checksum: 1912DA64
Full checksum (after): B3F0A43E
GetEmbeddedCRC: :4400A000
The checksum was successfully embedded.
I am using Delphi XE5.
You should understand how this code works.
Overall idea is to append the CRC as an extra 4 bytes, out of the EXE structure, to the end of file. (A better idea would be to put CRC into a special field inside EXE Header in the beginning).
However that raises the hen and the egg problem: after we calculate CRC and embed it - the CRC file is changed (the value of CRC is appended) and the CRC of changed files changes too.
So you basically has to implement two modes/function of CRC calculation: for the whole file and for the file without last 4 bytes. You should use the latter mode to calculate CRC after appending (you call it embedding), and the former one to calculate CRC before it on vanilla just compiled program.
Your GetCRC32 function always cuts last 4 bytes from the file, thus before embedding it calculates CRC only of some part of file, not of the whole file. But there ahve to be two different modes.
PS: you can also "embed" CRC into NTFS Alternate Stream, like having MyApp.exe program and CRC stored as MyApp.exe:CRC.
PPS. i think using unbuffered read byte by byte in the GetCRC32 should be very slow. If possible, better use TBytesStream to read the file into memory as whole and then scan in usual loop over array. Or read it by chunks of 4096 bytes rather than by byte variables.
For the last non-complete buffer you would clean the rest of buffer with zeroes for example.

How to save PngImage from clipboard

How can i save the pngimage to file copied form AdobeFirewoks(Clipboard) or Photoshop without losing the transparency.
i am using delphi2009.
thank you in advance.
#TLama
I tried this code but there is no transparency. I don't know also if i do it right.
png := TPngimage.Create;
try
png.LoadFromClipboardFormat(CF_BITMAP,
Clipboard.GetAsHandle(CF_BITMAP), CF_BITMAP);
image1.Picture.Assign(png);
finally
png.Free;
end;
Photoshop's clipboard format is horrible. The only pretty valid data that contains the alpha channel stored into the clipboard is... guess? ... a pointer to the alpha channel's memory into the "Photoshop Paste In Place" chunk.... HORRIBLE. If you copy something then restart photoshop, the alpha is... lost :)
However, you can easily understand if the clipboard contains Photoshop image.
Ask the Clipboard what chunks it have.
If the clipboard have two chunks, named "Photoshop Paste In Place" AND "Object Descriptor", you can be 99.9% sure that Photoshop IS RUNNING on the system AND Clipboard contains reference to Photoshop data. (When Photoshop quits, the Object Descriptor chunk gets removed from the Clipboard, so the alpha is lost forever)
So then, you have two choices:
Choice 1 (not recommended): Open Photoshop's Process Memory and read the raw 32-bit image data from the pointer... which is overall idiotic to do and unsecure, or
Choice 2 (recommended): Use COM to extract the image data from Photoshop. Of course, the COM method is the best way. Make your program generate and run the following VBS script:
On Error Resume Next
Set Ps = CreateObject("Photoshop.Application")
Set Shell = CreateObject("WScript.Shell")
Set FileSystem = CreateObject("Scripting.FileSystemObject")
Dim PNGFileName
PNGFileName = Shell.CurrentDirectory & "\psClipboard.png"
If FileSystem.FileExists(PNGFileName) Then
FileSystem.DeleteFile PNGFileName
End If
Set Doc = Ps.Documents.Add(1,1,72,"psClipboard",,3)
Doc.Paste()
Doc.RevealAll()
If Err.Number = 0 Then
set PNGSaveOptions = CreateObject("Photoshop.PNGSaveOptions")
doc.saveAs PNGFileName, PNGSaveOptions
End If
doc.Close()
In the script's CurrentDirectory, a file names "psClipboard.png" will be generated. Read this file in your program using libPng or whatever, and treat is as if it was come from the Clipboard. This script will DELETE the psClipboard.png, then will ask Photoshop for it. In case a Paste returns Error, the script will cease and the file will not be generated, in which case, Clipboard didn't contained valid Photoshop reference data.
Based on empirical results confirmed by my colleague having Adobe Photoshop CS 6 13.0 x32 using the following test code points out that it's not possible to save the image from clipboard copied by the Adobe Photoshop without losing transparency simply because it doesn't copy the alpha channel data.
Adobe Photoshop (at least in the version mentioned above) uses 24-bit pixel format for clipboard image data transfer. And, since it is the 24-bit bitmap there can't be an alpha channel. Don't know anyone who has the Adobe Fireworks to verify, but for sure they're using own registered clipboard format to transfer images including the alpha channel between their products.
The CF_BITMAP or CF_DIB formats used by Adobe Photoshop clipboard supposedly supports alpha channel, as some people says (I haven't tried) but that would be true only for 32-bit pixel format, not for the 24-bit pixel format. The only clipboard format, that surely supports transparency, is the CF_DIBV5 but as the others, the image have to be stored in 32-bit pixel format to preserve the alpha channel:
The following code shows the information about the currently copied clipboard content:
uses
ActiveX;
function GetClipboardFormatString(Format: Word): string;
var
S: string;
begin
case Format of
1: S := 'CF_TEXT';
2: S := 'CF_BITMAP';
3: S := 'CF_METAFILEPICT';
4: S := 'CF_SYLK';
5: S := 'CF_DIF';
6: S := 'CF_TIFF';
7: S := 'CF_OEMTEXT';
8: S := 'CF_DIB';
9: S := 'CF_PALETTE';
10: S := 'CF_PENDATA';
11: S := 'CF_RIFF';
12: S := 'CF_WAVE';
13: S := 'CF_UNICODETEXT';
14: S := 'CF_ENHMETAFILE';
15: S := 'CF_HDROP';
16: S := 'CF_LOCALE';
17: S := 'CF_DIBV5';
$0080: S := 'CF_OWNERDISPLAY';
$0081: S := 'CF_DSPTEXT';
$0082: S := 'CF_DSPBITMAP';
$0083: S := 'CF_DSPMETAFILEPICT';
$008E: S := 'CF_DSPENHMETAFILE';
$0200: S := 'CF_PRIVATEFIRST';
$02FF: S := 'CF_PRIVATELAST';
$0300: S := 'CF_GDIOBJFIRST';
$03FF: S := 'CF_GDIOBJLAST';
else
begin
SetLength(S, 255);
SetLength(S, GetClipboardFormatName(Format, PChar(S), 255));
if Length(S) = 0 then
S := 'Unknown, unregistered clipboard format';
Result := S + ' (' + IntToStr(Format) + ')';
Exit;
end;
end;
Result := 'Standard clipboard format (' + S + ')';
end;
function GetClipboardFormats: string;
var
S: string;
FormatEtc: TFormatEtc;
DataObject: IDataObject;
EnumFormatEtc: IEnumFormatEtc;
begin
Result := '';
if Succeeded(OleGetClipboard(DataObject)) then
begin
if Succeeded(DataObject.EnumFormatEtc(DATADIR_GET, EnumFormatEtc)) then
begin
S := DupeString('-', 65) + sLineBreak +
'Clipboard data formats: ' + sLineBreak +
DupeString('-', 65) + sLineBreak;
while EnumFormatEtc.Next(1, FormatEtc, nil) = S_OK do
S := S + GetClipboardFormatString(FormatEtc.cfFormat) + sLineBreak;
Result := S;
end;
end;
end;
function GetClipboardInfoDIB: string;
var
S: string;
ClipboardData: HGLOBAL;
BitmapInfoHeader: PBitmapInfoHeader;
const
BI_JPEG = 4;
BI_PNG = 5;
begin
Result := '';
if OpenClipboard(0) then
try
ClipboardData := GetClipboardData(CF_DIB);
if ClipboardData <> 0 then
begin
BitmapInfoHeader := GlobalLock(ClipboardData);
if Assigned(BitmapInfoHeader) then
try
S := DupeString('-', 65) + sLineBreak +
'Clipboard data of CF_DIB format: ' + sLineBreak +
DupeString('-', 65) + sLineBreak +
'Width: ' + IntToStr(BitmapInfoHeader.biWidth) + ' px' + sLineBreak +
'Height: ' + IntToStr(BitmapInfoHeader.biHeight) + ' px' + sLineBreak +
'Bit depth: ' + IntToStr(BitmapInfoHeader.biBitCount) + ' bpp' + sLineBreak +
'Compression format: ';
case BitmapInfoHeader.biCompression of
BI_RGB: S := S + 'Uncompressed format (BI_RGB)';
BI_RLE8: S := S + 'RLE format for bitmaps with 8 bpp (BI_RLE8)';
BI_RLE4: S := S + 'RLE format for bitmaps with 4 bpp (BI_RLE4)';
BI_BITFIELDS: S := S + 'Not compressed with color masks (BI_BITFIELDS)';
BI_JPEG: S := S + 'Compressed using JPEG file format (BI_JPEG)';
BI_PNG: S := S + 'Compressed using PNG file format (BI_PNG)';
end;
S := S + sLineBreak;
Result := S;
finally
GlobalUnlock(ClipboardData);
end;
end;
finally
CloseClipboard;
end;
end;
function GetClipboardInfoDIBV5: string;
var
S: string;
ClipboardData: HGLOBAL;
BitmapInfoHeader: PBitmapV5Header;
const
BI_JPEG = 4;
BI_PNG = 5;
begin
Result := '';
if OpenClipboard(0) then
try
ClipboardData := GetClipboardData(CF_DIBV5);
if ClipboardData <> 0 then
begin
BitmapInfoHeader := GlobalLock(ClipboardData);
if Assigned(BitmapInfoHeader) then
try
S := DupeString('-', 65) + sLineBreak +
'Clipboard data of CF_DIBV5 format: ' + sLineBreak +
DupeString('-', 65) + sLineBreak +
'Width: ' + IntToStr(BitmapInfoHeader.bV5Width) + ' px' + sLineBreak +
'Height: ' + IntToStr(BitmapInfoHeader.bV5Height) + ' px' + sLineBreak +
'Bit depth: ' + IntToStr(BitmapInfoHeader.bV5BitCount) + ' bpp' + sLineBreak +
'Compression format: ';
case BitmapInfoHeader.bV5Compression of
BI_RGB: S := S + 'Uncompressed format (BI_RGB)';
BI_RLE8: S := S + 'RLE format for bitmaps with 8 bpp (BI_RLE8)';
BI_RLE4: S := S + 'RLE format for bitmaps with 4 bpp (BI_RLE4)';
BI_BITFIELDS: S := S + 'Not compressed with color masks (BI_BITFIELDS)';
BI_JPEG: S := S + 'Compressed using JPEG file format (BI_JPEG)';
BI_PNG: S := S + 'Compressed using PNG file format (BI_PNG)';
end;
S := S + sLineBreak;
Result := S;
finally
GlobalUnlock(ClipboardData);
end;
end;
finally
CloseClipboard;
end;
end;
procedure TForm1.Button1Click(Sender: TObject);
var
S: string;
begin
S := GetClipboardFormats;
if IsClipboardFormatAvailable(CF_DIB) then
S := S + sLineBreak + GetClipboardInfoDIB;
if IsClipboardFormatAvailable(CF_DIBV5) then
S := S + sLineBreak + GetClipboardInfoDIBV5;
ShowMessage(S);
end;
Output of the above code for transparent image copied into a clipboard by Adobe Photoshop CS 6 13.0 (click to enlarge):
Something useful to read:
How to copy an image to clipboard keeping its transparency
How to copy & paste images using CF_DIBV5 format preserving transparency
The solution explained in this link may work.
unit EG_ClipboardBitmap32;
{
Author William Egge. egge#eggcentric.com
January 17, 2002
Compiles with ver 1.2 patch #1 of Graphics32
This unit will copy and paste Bitmap32 pixels to the clipboard and retain the
alpha channel.
The clipboard data will still work with regular paint programs because this
unit adds a new format only for the alpha channel and is kept seperate from
the regular bitmap storage.
}
interface
uses
ClipBrd, Windows, SysUtils, GR32;
procedure CopyBitmap32ToClipboard(const Source: TBitmap32);
procedure PasteBitmap32FromClipboard(const Dest: TBitmap32);
function CanPasteBitmap32: Boolean;
implementation
const
RegisterName = 'G32 Bitmap32 Alpha Channel';
GlobalUnlockBugErrorCode = ERROR_INVALID_PARAMETER;
var
FAlphaFormatHandle: Word = 0;
procedure RaiseSysError;
var
ErrCode: LongWord;
begin
ErrCode := GetLastError();
if ErrCode <> NO_ERROR then
raise Exception.Create(SysErrorMessage(ErrCode));
end;
function GetAlphaFormatHandle: Word;
begin
if FAlphaFormatHandle = 0 then
begin
FAlphaFormatHandle := RegisterClipboardFormat(RegisterName);
if FAlphaFormatHandle = 0 then
RaiseSysError;
end;
Result := FAlphaFormatHandle;
end;
function CanPasteBitmap32: Boolean;
begin
Result := Clipboard.HasFormat(CF_BITMAP);
end;
procedure CopyBitmap32ToClipboard(const Source: TBitmap32);
var
H: HGLOBAL;
Bytes: LongWord;
P, Alpha: PByte;
I: Integer;
begin
Clipboard.Assign(Source);
if not OpenClipboard(0) then
RaiseSysError
else
try
Bytes := 4 + (Source.Width * Source.Height);
H := GlobalAlloc(GMEM_MOVEABLE and GMEM_DDESHARE, Bytes);
if H = 0 then
RaiseSysError;
P := GlobalLock(H);
if P = nil then
RaiseSysError
else
try
PLongWord(P)^ := Bytes - 4;
Inc(P, 4);
// Copy Alpha into Array
Alpha := Pointer(Source.Bits);
Inc(Alpha, 3); // Align with Alpha
for I := 1 to (Source.Width * Source.Height) do
begin
P^ := Alpha^;
Inc(Alpha, 4);
Inc(P);
end;
finally
if (not GlobalUnlock(H)) then
if (GetLastError() <> GlobalUnlockBugErrorCode) then
RaiseSysError;
end;
SetClipboardData(GetAlphaFormatHandle, H);
finally
if not CloseClipboard then
RaiseSysError;
end;
end;
procedure PasteBitmap32FromClipboard(const Dest: TBitmap32);
var
H: HGLOBAL;
ClipAlpha, Alpha: PByte;
I, Count, PixelCount: LongWord;
begin
if Clipboard.HasFormat(CF_BITMAP) then
begin
Dest.BeginUpdate;
try
Dest.Assign(Clipboard);
if not OpenClipboard(0) then
RaiseSysError
else
try
H := GetClipboardData(GetAlphaFormatHandle);
if H <> 0 then
begin
ClipAlpha := GlobalLock(H);
if ClipAlpha = nil then
RaiseSysError
else
try
Alpha := Pointer(Dest.Bits);
Inc(Alpha, 3); // Align with Alpha
Count := PLongWord(ClipAlpha)^;
Inc(ClipAlpha, 4);
PixelCount := Dest.Width * Dest.Height;
Assert(Count = PixelCount,
'Alpha Count does not match Bitmap pixel Count,
PasteBitmap32FromClipboard(const Dest: TBitmap32);');
// Should not happen, but if it does then this is a safety catch.
if Count > PixelCount then
Count := PixelCount;
for I := 1 to Count do
begin
Alpha^ := ClipAlpha^;
Inc(Alpha, 4);
Inc(ClipAlpha);
end;
finally
if (not GlobalUnlock(H)) then
if (GetLastError() <> GlobalUnlockBugErrorCode) then
RaiseSysError;
end;
end;
finally
if not CloseClipboard then
RaiseSysError;
end;
finally
Dest.EndUpdate;
Dest.Changed;
end;
end;
end;
end.
The function PasteBitmap32FromClipboard is apparently what you need. Saving a bitmap as PNG is answered in this question.

Hex to Binary convert

I have converted my jpeg file as HEX code through hex converter.
Now how to convert that hex to binary and save as Jpeg file on disk.
Like:
var declared as Hex code and then convert that var hex code to binary and save on disk ?
Edit:
Var
myfileHex := 'FAA4F4AAA444444'; // long as HEX code of my JPEG
function HexToBin(myfileHex): string;
begin
// Convert Hex to bin and save file as...
end;
Delphi already has HexToBin (Classes) procedure, since at least D5.
Try this code:
procedure HexStringToBin;
var
BinaryStream: TMemoryStream;
HexStr: AnsiString;
begin
HexStr := 'FAA4F4AAA44444';
BinaryStream := TMemoryStream.Create;
try
BinaryStream.Size := Length(HexStr) div 2;
if BinaryStream.Size > 0 then
begin
HexToBin(PAnsiChar(HexStr), BinaryStream.Memory, BinaryStream.Size);
BinaryStream.SaveToFile('c:\myfile.bin')
end;
finally
BinaryStream.Free;
end;
end;
The same could be done with any binary TStream e.g. TFileStream.
Hex is very easy to decode manually:
procedure HexToBin(const Hex: string; Stream: TStream);
var
B: Byte;
C: Char;
Idx, Len: Integer;
begin
Len := Length(Hex);
If Len = 0 then Exit;
If (Len mod 2) <> 0 then raise Exception.Create('bad hex length');
Idx := 1;
repeat
C := Hex[Idx];
case C of
'0'..'9': B := Byte((Ord(C) - '0') shl 4);
'A'..'F': B := Byte(((Ord(C) - 'A') + 10) shl 4);
'a'..'f': B := Byte(((Ord(C) - 'a') + 10) shl 4);
else
raise Exception.Create('bad hex data');
end;
C := Hex[Idx+1];
case C of
'0'..'9': B := B or Byte(Ord(C) - '0');
'A'..'F': B := B or Byte((Ord(C) - 'A') + 10);
'a'..'f': B := B or Byte((Ord(C) - 'a') + 10);
else
raise Exception.Create('bad hex data');
end;
Stream.WriteBuffer(B, 1);
Inc(Idx, 2);
until Idx > Len;
end;
begin
FStream := TFileStream.Create('myfile.jpg', fmCreate);
HexToBin(myFileHex, FStream);
FStream.Free;
end;

Delphi: string encryption method and base64

Please suggest me a good string encryption method. Not XOR, it isn't strong enough.
Can I use Base64 to represent the encrypted string, but without "=" on the string's end? I can add it manually. Is it normal? That is a user will use Base64 without "=" in a program, and I will add it. I do not want to have a view with '=', it isn't nice :)
Thanks!!!
Here's one encryption library: http://www.cityinthesky.co.uk/opensource/dcpcrypt
Yes, you can show a base64 string without the '=' sign on the end. You just need to make sure that when you pass the value to a method the method is smart enough to add it back on before attempting the decrypt. This is a pretty common scenario.
heres a function (or a couple of functions) to encode and decode strings you can use, you can call it using Base64Encode('string to be encoded') and Base64Decode('string to be decoded') hope this helps.
const
B64: array[0..63] of byte= (65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,
81,82,83,84,85,86,87,88,89,90,97,98,99,100,101,102,103,104,105,106,107,108,
109,110,111,112,113,114,115,116,117,118,119,120,121,122,48,49,50,51,52,53,
54,55,56,57,43,47);
function B64Encode(pInput: pointer; pOutput: pointer; Size: longint): longint;
var
i, iptr, optr: integer;
Input, Output: PByteArray;
begin
Input:= PByteArray(pInput); Output:= PByteArray(pOutput);
iptr:= 0; optr:= 0;
for i:= 1 to (Size div 3) do
begin
Output^[optr+0]:= B64[Input^[iptr] shr 2];
Output^[optr+1]:= B64[((Input^[iptr] and 3) shl 4) + (Input^[iptr+1] shr 4)];
Output^[optr+2]:= B64[((Input^[iptr+1] and 15) shl 2) + (Input^[iptr+2] shr 6)];
Output^[optr+3]:= B64[Input^[iptr+2] and 63];
Inc(optr,4); Inc(iptr,3);
end;
case (Size mod 3) of
1: begin
Output^[optr+0]:= B64[Input^[iptr] shr 2];
Output^[optr+1]:= B64[(Input^[iptr] and 3) shl 4];
Output^[optr+2]:= byte('=');
Output^[optr+3]:= byte('=');
end;
2: begin
Output^[optr+0]:= B64[Input^[iptr] shr 2];
Output^[optr+1]:= B64[((Input^[iptr] and 3) shl 4) + (Input^[iptr+1] shr 4)];
Output^[optr+2]:= B64[(Input^[iptr+1] and 15) shl 2];
Output^[optr+3]:= byte('=');
end;
end;
Result:= ((Size+2) div 3) * 4;
end;
function Base64Encode(const Value: AnsiString): AnsiString;
begin
SetLength(Result,((Length(Value)+2) div 3) * 4);
B64Encode(#Value[1],#Result[1],Length(Value));
end;
function B64Decode(pInput: pointer; pOutput: pointer; Size: longint): longint;
var
i, j, iptr, optr: integer;
Temp: array[0..3] of byte;
Input, Output: PByteArray;
begin
Input:= PByteArray(pInput); Output:= PByteArray(pOutput);
iptr:= 0; optr:= 0;
Result:= 0;
for i:= 1 to (Size div 4) do
begin
for j:= 0 to 3 do
begin
case Input^[iptr] of
65..90 : Temp[j]:= Input^[iptr] - Ord('A');
97..122: Temp[j]:= Input^[iptr] - Ord('a') + 26;
48..57 : Temp[j]:= Input^[iptr] - Ord('0') + 52;
43 : Temp[j]:= 62;
47 : Temp[j]:= 63;
61 : Temp[j]:= $FF;
end;
Inc(iptr);
end;
Output^[optr]:= (Temp[0] shl 2) or (Temp[1] shr 4);
Result:= optr+1;
if (Temp[2]<> $FF) and (Temp[3]= $FF) then
begin
Output^[optr+1]:= (Temp[1] shl 4) or (Temp[2] shr 2);
Result:= optr+2;
Inc(optr)
end
else if (Temp[2]<> $FF) then
begin
Output^[optr+1]:= (Temp[1] shl 4) or (Temp[2] shr 2);
Output^[optr+2]:= (Temp[2] shl 6) or Temp[3];
Result:= optr+3;
Inc(optr,2);
end;
Inc(optr);
end;
end;
function Base64Decode(const Value: AnsiString): AnsiString;
begin
SetLength(Result,(Length(Value) div 4) * 3);
SetLength(Result,B64Decode(#Value[1],#Result[1],Length(Value)));
end;

Convert Int64 to Base30 and Back

For a registration code I want to convert an Int64 to base30 (30 so that only uppercase characters and excluding 0,O,I,1,etc.) and back.
This is not too difficult using functions like:
const
Base = 30;
Base30CharSet = '23456789ABCDEFGHJKLMNPRSTVWXYZ';
function ConvertIntToBase30(ANumber: Int64): string;
begin
if(ANumber = 0) then
Result := Copy(Base30CharSet, 1, 1)
else begin
Result := '';
while(ANumber <> 0) do begin
Result := Copy(Base30CharSet, (ANumber mod Base)+1, 1) + Result;
ANumber := ANumber div Base;
end;
end;
end;
function ConvertBase30ToInt(ANumber: string): Int64;
var
i: integer;
begin
Result := 0;
for i := 1 to Length(ANumber) do begin
Result := Result + (Pos(ANumber[i], Base30CharSet)-1);
if(i < Length(ANumber)) then
Result := Result * Base;
end;
end;
The snag is that I am interested in the Int64's bits, so I could be dealing with a number like $FFFFFFFFFFFFFFFF = -1.
To work around this I thought I would store and remove the sign (abs()) and include the sign as an extra character appended to the base30 result. The problem the occurs at the lower limit of Int64 as calling abs(-9223372036854775808) results in an overflow.
Does anyone have a solution or better algorithm to solve this problem?
The way to deal with it is having a character to indicate it is a negative number so that you can decode back. For negative number, just flip the bit from 1 to 0 and remove the sign bit before encoding and when decode, do a flip back and add the sign bit. Below is working codes
function InvertIntOff(const ANumberL, ANumberH: Integer): Int64;
asm
XOR EAX,$FFFFFFFF
XOR EDX,$FFFFFFFF
end;
function InvertIntOn(const ANumberL, ANumberH: Integer): Int64;
asm
XOR EAX,$FFFFFFFF
XOR EDX,$FFFFFFFF
OR EDX,$80000000
end;
function ConvertIntToBase(ANumber: Int64): string;
const
CBaseMap: array[0..31] of Char = (
'2','3','4','5','6','7','8','9', //0-7
'A','B','C','D','E','F','G','H', //8-15
'J','K','L','M','N', //16-20
'P','Q','R','S','T','U','V','X','W','Y','Z'); //21-31
var
I: Integer;
begin
SetLength(Result, 15);
I := 0;
if ANumber < 0 then
begin
Inc(I);
Result[I] := '1';
ANumber := InvertIntOff(ANumber and $FFFFFFFF, (ANumber and $FFFFFFFF00000000) shr 32);
end;
while ANumber <> 0 do
begin
Inc(I);
Result[I] := CBaseMap[ANumber and $1F];
ANumber := ANumber shr 5;
end;
SetLength(Result, I);
end;
function ConvertBaseToInt(const ABase: string): Int64;
var
I, Index: Integer;
N: Int64;
begin
Result := 0;
if Length(ABase) > 0 then
begin
if ABase[1] = '1' then
Index := 2
else
Index := 1;
for I := Index to Length(ABase) do
begin
case ABase[I] of
'2'..'9':
N := Ord(ABase[I]) - Ord('2');
'A'..'H':
N := Ord(ABase[I]) - Ord('A') + 8;
'J'..'N':
N := Ord(ABase[I]) - Ord('J') + 16;
'P'..'Z':
N := Ord(ABase[I]) - Ord('P') + 21;
else
raise Exception.Create('error');
end;
if I > Index then
Result := Result or (N shl ((I - Index) * 5))
else
Result := N;
end;
if ABase[1] = '1' then
Result := InvertIntOn(Result and $FFFFFFFF, (Result and $FFFFFFFF00000000) shr 32);
end;
end;
procedure TestBase32;
var
S: string;
begin
S := ConvertIntToBase(-1);
ShowMessage(S + ' / ' + IntToStr(ConvertBaseToInt(S)) + ' ? -1');
S := ConvertIntToBase(-31);
ShowMessage(S + ' / ' + IntToStr(ConvertBaseToInt(S)) + ' ? -31');
S := ConvertIntToBase(1);
ShowMessage(S + ' / ' + IntToStr(ConvertBaseToInt(S)) + ' ? 1');
S := ConvertIntToBase(123456789);
ShowMessage(S + ' / ' + IntToStr(ConvertBaseToInt(S)) + ' ? 123456789');
S := ConvertIntToBase(-123456789);
ShowMessage(S + ' / ' + IntToStr(ConvertBaseToInt(S)) + ' ? -123456789');
end;
I think you are almost there by considering abs()...
But rather than using abs() why not simply ignore the sign for processing the value of the Int64 itself ? As far as I can tell, you are in fact already doing this so only one minor addition is needed to the encoding routine:
if aNumber < 0 then
// negative
else
// positive;
The only problem then is the LOSS of sign information in the resulting Base30 string. So treat that as a separate problem to be solved using the new information gained from the aNumber < 0 test...
I see you have excluded all chars that could be confused for 0 or 1 but have also excluded 0 and 1 themselves. You could therefore use 0 and 1 to indicate positive or negative (or vice versa).
Depending on the purpose of these routines, the placement of the 0/1 in the result could be entirely arbitrary (if you wished to obfuscate things and make the placement of the 0/1 random rather than a consistent lead/trail character).
When encoding simply drop a sign indicator into the result string at random, and when decoding handle the 0/1 character whenever as the sign marker it is encountered, but skipped for the purposes of decoding the value.
Of course, if obfuscation is not an issue then simply consistently pre or post fix the sign indicator.
You could even simply choose to use '1' to indicate negative and the LACK of a '1' to indicate/assume positive (this would simplify the zero value case a little I think)
The easy answer is to turn range checking off, even just for the method that you're calling abs in.
If you don't care about an extra char or two you could split the int64 into words or dwords and string those together. I would be more tempted to go to base32 and use bit shifts for speed and ease of use. Then your encoding becomes
Base32CharSet[(ANumber shr 5) % 32]
and a similar pos() based approach for the decode.

Resources