Add Buffer to ByteArray - delphi-7

I use winsock to receive a 1024byte buffer like this:
var
buffer : array[0..1023] of byte;
endarray : array of byte;
hFile : THandle;
dwWritten : DWORD;
dwRead : DWORD;
begin
SetLength (endarray, 3000); //fixxed size (doesn't really matter here, cause I know the size)
hFile := CreateFileW('test.bin', GENERIC_WRITE, FILE_SHARE_WRITE, nil, CREATE_NEW, 0, 0);
SetFilePointer(hFile, 0, nil, FILE_BEGIN);
repeat
dwRead := recv(MySock, Buffer, 1024, 0);
WriteFile(hFile, buffer[0], dwRead, dwWritten, nil); // works fine!
// Add the buffer to the endarray but how?
until (dwRead = 0) or (dwRead = -1)
[...]
CloseHandle (hFile);
end;
How can I add the buffer to the endarray automatically so it actually gets appended to the end?

Like this:
var
PrevLen: Integer;
....
dwRead := recv(MySock, Buffer, 1024, 0);
if dwRead>0 then
begin
PrevLen := Length(endarray);
SetLength(endarray, PrevLen+dwRead);
Move(Buffer[0], endarray[PrevLen], dwRead);
end;
And also remove the first line of code from your function that pre-allocates endarray.
If you'd rather allocate the buffer once (as per the code in the question) then you can code it like this:
var
endarrayLen: Integer;
.....
endarrayLen := 0;
repeat
dwRead := recv(MySock, Buffer, 1024, 0);
if dwRead>0 then
begin
Move(Buffer[0], endarray[endarrayLen], dwRead);
inc(endarrayLen, dwRead);
end;
.....
until ...
But that's a buffer overrun waiting to happen!

You can use the TMemoryStream or TBytesStream class. Both represent a dynamically-growable block of memory. TMemoryStream operates on a raw memory block, whereas TBytesStream operates on a dynamic array of bytes. For example:
var
buffer : array[0..1023] of byte;
endarray : TMemoryStream;
hFile : THandle;
iRead : Integer;
dwWritten : DWORD;
begin
endarray := TMemoryStream.Create;
try
hFile := CreateFileW('test.bin', GENERIC_WRITE, FILE_SHARE_WRITE, nil, CREATE_NEW, 0, 0);
try
repeat
iRead := recv(MySock, buffer, sizeof(buffer), 0);
if iRead < 1 then Break;
WriteFile(hFile, buffer[0], iRead, dwWritten, nil);
endarray.WriteBuffer(buffer[0], iRead);
until False;
[...]
finally
CloseHandle (hFile);
end;
// use endarray.Memory as needed, up to endarray.Size number of bytes ...
finally
endarray.Free;
end;
end;
.
var
buffer : array[0..1023] of byte;
endarray : TBytesStream;
hFile : THandle;
iRead : Integer;
dwWritten : DWORD;
begin
endarray := TBytesStream.Create(nil);
try
hFile := CreateFileW('test.bin', GENERIC_WRITE, FILE_SHARE_WRITE, nil, CREATE_NEW, 0, 0);
try
repeat
iRead := recv(MySock, buffer, sizeof(buffer), 0);
if iRead < 1 then Break;
WriteFile(hFile, buffer[0], iRead, dwWritten, nil);
endarray.WriteBuffer(buffer[0], iRead);
until False;
[...]
finally
CloseHandle (hFile);
end;
// use endarray.Bytes as needed, up to endarray.Size number of bytes ...
finally
endarray.Free;
end;
end;

Related

Pls correct these functions of float number (type: double) under binary form in delphi

I've written 2 functions to convert a float number into/from binary, but the result is incorrect. Please help me to find its bug. (I found some FAQ for this topic, but they was written for C/C++)
function MyFloatToBin(d: double): String;
var
d_ptr: ^Int64;
d_str: string;
i: Integer;
ch: char;
begin
d_ptr:= #d;
d_str:= '';
for i:= 0 to 63 do begin
if (d_ptr^ and (1 shl i)) > 0 then
ch:= '1'
else
ch:= '0';
d_str:= d_str + ch;
end;
Result:= 'F' + d_str;
end;
function MyBinToFloat: Double;
var
d_str: String;
i64: Int64;
d_ptr: ^double;
i, len: Integer;
begin
d_str:= pop;
len:= length(d_str);
if (pos('F', d_str) <> 1)and(len <> 65) then begin
push(d_str);
exit;
end;
i64:= 0;
for i:= 2 to len do
if d_str[i] = '1' then
i64:= i64 or (1 shl (i - 2));
d_ptr:= #i64;
Result:= d_ptr^;
end;
Using
temp: string;
f: double;
temp:= MyFloatToBin(pi);//pi = 3.14....
f:= MyBinToFloat(temp);//result at f is 0
I wonder the variable f should be 3.14... but..???
Please help me correct them.
Thanks
Your problem is essentially the mask computation. You do 1 shl I which gives a 32 bit value. You must do UInt64(1) shl I to get a 64 bit value.
Here is your code fixed:
function MyFloatToBinString(d: double): String;
var
VP : ^UInt64;
I : Integer;
begin
VP := #d;
Result := 'F';
for I := 63 downto 0 do begin
if (VP^ and (UInt64(1) shl I)) <> 0 then
Result := Result + '1'
else
Result := Result + '0';
end;
end;
function MyBinStringToFlat(S : String) : Double;
var
V : UInt64;
I : Integer;
J : Integer;
begin
if (Length(S) <> 65) or ((S[1] <> 'F') and (S[1] <> 'f')) then
raise Exception.Create('Invalid format');
V := 0;
for I := 65 downto 2 do begin
case S[I] of
'1': V := V or (UInt64(1) shl (65 - I));
'0': { Nothing to do };
else
raise Exception.Create('Invalid format');
end;
end;
Result := PDouble(#V)^;
end;
And if you want to test:
procedure TForm1.Button1Click(Sender: TObject);
var
V1 : Double;
V2 : Double;
S : String;
begin
V1 := 3.1416;
Memo1.Lines.Add(IntToHex(PUInt64(#V1)^));
S := MyFloatToBinString(V1);
Memo1.Lines.Add(S);
V2 := MyBinStringToFlat(S);
Memo1.Lines.Add(V2.ToString);
end;

How is a CRC32 checksum calculated with FreePascal(Lazarus)?

I have to make some project for my college, and I need to calculate CRC32. But I almost didn't work with shifts before, so even after I read theory it's still hard to me. I found some CRC32 basic algorithm for C (not mine) and I tried to rewrite it for Lazarus(Delphi). But it doesn't work. I can't understand, what's wrong. Please, help (*_ _)人
Here my code:
procedure TMyFrame.CRC32_Checksum();
var
P : Pointer;
Size, i : Integer;
CRC, j : LongWord;
B : ^Byte;
flag : Boolean;
begin
AssignFile (f, FileName);
Reset(f, 1);
Size := FileSize(f);
GetMem(P, Size);
BlockRead(f, P^, Size);
B := P;
//
//
CRC := $FFFFFFFF;
for i := 1 to Size do
begin
CRC := CRC XOR B^;
Inc(B);
for j := 0 to 7 do
begin
flag := (CRC AND 1) > 0;
if flag then
CRC := (CRC SHR 1) XOR $04C11DB7
else
CRC := CRC SHR 1;
end;
end;
LabeledEdit1.Text := IntToHEX(CRC, 8);
//
//
Freemem(P);
CloseFile(f);
end;
0xCBF43926 is the bit-wise inverse ("not") of 0x340BC6D9. You just need to use not on the result, or exclusive or with $FFFFFFFF.
Note that FPC comes with a CRC32 unit. (derived from crc32.c by Mark Adler, above )
This unit has a function to calculate the CRC for a block called crc32()
function crc32 (crc : cardinal; buf : Pbyte; len : cardinal): cardinal;
The XOR is included in this crc32.crc32() function.

Slow pascal graph unit

It's actually my first time in here, so..
What's the problem: standard graph module is too damn slow in drawing.
I have an institute task to make a big program with modules on pascal. Program has several parts but i'm interested in graphical one. I have something like counter (number) in the left corner of the screen and i need it to update fast. But I see every pixel it fills with color, lol.
I'm using Free Pascal 2.6.4.
Asking for some ideas or other ways to draw in a command window fast.
program graphical;
uses
wincrt, graph, querystring, kbd, Timer, sysutils;
const
speedX1 = 0;
speedY1 = 0;
var
//draw part
gd, gm, error, tw, th, i: integer;
speedX2: integer = 10;
speedY2: integer = 10;
speedSize: word;
speedImage: pointer;
size: word;
//qstring part
qrec: qstr;
qtext: AnsiString;
current, ch: char;
//keyboard part
kbrd: kb;
//speedometer part
counter: word = 0;
time: word;
speed: word;
//debug part
c: string;
t: comp;
procedure draw; //screens text
begin
qtext := copy(qrec.text, qrec.qpointer, Length(qrec.text) - qrec.qpointer + 1);
outTextXY(getMaxX div 2, getMaxY div 8, qtext);
end;
begin
//graphic initialization
//gd := detect;
gd := VGA;
gm := VGAHi;
initgraph(gd, gm, '..\bgi');
//checking for errors
error := graphResult;
if (error <> grOk) then
begin
writeln('800x600x256 is not supported');
halt(1);
end;
//querystring initialization
qInit(qrec);
//keyboard initialization
initKeyboard(kbrd);
//timer initialization
TimerOn;
time := 0;
//drawing
setTextStyle(defaultFont, horizDir, 8);
draw;
drawKeyboard(kbrd);
current := getCurrent(qrec);
randomize;
speedX2 := 200;
speedY2 := 100;
repeat
//on timer events
if (isTimer) then
begin
size := ImageSize(speedX1, speedY1, speedX2, speedY2);
GetMem(speedImage, size);
GetImage(speedX1, speedY1, speedX2, speedY2, speedImage^);
PutImage(speedX1, speedY1, speedImage^, 1); FreeMem(speedImage, size);
inc(time);
speed := round(counter/time/25*60);
speed := time;
outTextXY(0, 0, IntToStr(speed));
end;
if KeyPressed then
begin
ch := readkey;
if (ch = #0) then
ch := readkey;
end;
if (UpCase(ch) = UpCase(current)) then
begin
drawKeyboard(kbrd);
draw;
current := getCurrent(qrec);
inc(counter);
end
else
if (counter > 0) then
dec(counter);
until (ch = #27) or (getLength(qrec) < 0);
closegraph;
end.
What I see from the code:
drawKeyboard is called on each iteration, which might not be necessary
for each timer event, memory is allocated and released again, which normally is a rather costly operation. The memory needed seems to be of constant size, so try to move allocation and deallocation out of the loop.
Without fixing those, you'd probably have the same problems with other graph libraries too, so give it a try.

Typecasting WideString breaks array of widechar

I use this procedure to ENUM the keys into a TNTListView (UNICODE) in Delphi 7
procedure TForm1.TntButton1Click(Sender: TObject);
var
k : HKEY;
Buffer : array of widechar;
i : Integer;
iRes : Integer;
BuffSize : DWORD;
item : TTNTListItem;
WS : WideString;
begin
if RegOpenKeyExW (HKEY_CURRENT_USER, 'Software', 0, KEY_READ, K) = ERROR_SUCCESS then begin
try
i := 0;
BuffSize := 1;
while true do begin
SetLength (Buffer, BuffSize);
iRes := RegEnumKeyW(k, I, #Buffer[0], BuffSize);
if iRes = 259 then break;
if iRes = 234 then begin
inc (BuffSize);
continue;
end;
messageboxw (0, #Buffer[0], '', 0);
item := TNTListView1.Items.Add;
item.Caption := WideString (Buffer); // BREAKS IT
{ SOLUTION }
SetLength (WS, BuffSize - 1);
CopyMemory (#WS[1], #Buffer[0], (BuffSize * 2));
{ .... }
inc (i);
BuffSize := 1;
end;
finally
RegCloseKey (k);
SetLength (Buffer, 0);
end;
end;
end;
I see that most of the listviewitems are trimmed! However if I show the Buffer in the messagebox it shows the complete string in the right length. Is this a Bug of the listview or am I missing something like a NULL CHAR (or even 2)?
Thanks for help.
EDIT: I just noticed that the Buffer get's trimmed into half when I cast it to a widestring.
EDIT2: No bug in the listview. The WideString Cast breaks the string somehow and / or doesn't detect the NULL CHAR(s).
You are right - casting array of WideChar to WideString halves the string length in pre-Unicode Delphi's.
Tested on Delphi 2007:
var
A: array of WideChar;
begin
SetLength(A, 4);
ShowMessage(IntToStr(Length(WideString(A)))); // 2
end;
A quick view on the above code in debugger CPU window shows that typecasting array of WideChar-> WideString does not result in any data conversion; internal WideString format stores the string size (i.e. the number of bytes) in the same place where Delphi strings or dynarrays store length. As a result typecasting halves string length.

drawn thumbnails in tlistbox

In DelphiXE, I'm using a tFileOpenDialog to select a folder and then listing all the *.jpg files in that folder in a tListBox. I'm allowing the list items to be dragged and dropped within the list for custom sorting so that I can display them in order later.
I'd like to be able to draw a thumbnail of the image beside the filename so that the display is similar to Windows Explorer when looking at files in List view where you have the associated icon just left of the file name on the same row.
I've found a couple of old examples that lead me to believe this is possible using tListBox.onDrawItem, but I've been unable to get one to work.
What is the best approach to take to accomplish this goal using a tListBox, or by some other means?
Thanks for your help.
Update: I've been working to use tListView instead, as suggested.
I've attempted to convert the examples from Ken and Andreas to use actual images instead of dynamically created sample bitmaps. I was able to get the basics working, but without resizing, I get only the top left of the image 64*64. I'm only working with JPGs at this point. imagecount is just the count of my list of filenames in my listbox, I haven't moved the initial list creation into the listview at this point.
That is done with this code:
procedure TfrmMain.CreateThumbnails;
var
i: Integer;
FJpeg: TJpegImage;
R: TRect;
begin
for i := 0 to imageCount - 1 do
begin
FJpeg := TJpegImage.Create;
thumbs[i] := TBitmap.Create;
FJpeg.LoadFromFile(Concat(imgFolderlabel.caption,
photoList.Items.Strings[i]));
thumbs[i].Assign(FJpeg);
thumbs[i].SetSize(64, 64);
end;
imgListView.LargeImages := ImageList1;
FJpeg.Free;
end;
In order to also resize and stretch the image properly within the thumbnail, I'm trying to implement some code from here: http://delphi.about.com/od/graphics/a/resize_image.htm
The new code looks like:
procedure TfrmMain.CreateThumbnails;
var
i: Integer;
FJpeg: TJpegImage;
R: TRect;
begin
for i := 0 to imageCount - 1 do
begin
FJpeg := TJpegImage.Create;
thumbs[i] := TBitmap.Create;
FJpeg.LoadFromFile(Concat(imgFolderlabel.caption,
photoList.Items.Strings[i]));
thumbs[i].Assign(FJpeg);
//resize code
R.Left := 0;
R.Top := 0;
// proportional resize
if thumbs[i].Width > thumbs[i].Height then
begin
R.Right := 64;
R.Bottom := (64 * thumbs[i].Height) div thumbs[i].Width;
end
else
begin
R.Bottom := 64;
R.Right := (64 * thumbs[i].Width) div thumbs[i].Height;
end;
thumbs[i].Canvas.StretchDraw(R, thumbs[i]);
// resize image
//thumbs[i].Width := R.Right;
//thumbs[i].Height := R.Bottom;
thumbs[i].SetSize(64, 64); //all images must be same size for listview
end;
imgListView.LargeImages := ImageList1;
FJpeg.Free;
end;
This gives me a collage of image thumbnails with their filenames and works good.
Thank you.
Not an answer, but an alternative (using Andreas' code for creating the image array as a starting point). Drop a TListView and a TImageList on a new form, cut all the code from the editor from the interface to just above the final end. with this:
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, ImgList, ComCtrls;
type
TForm1 = class(TForm)
ImageList1: TImageList;
ListView1: TListView;
procedure FormShow(Sender: TObject);
private
{ Private declarations }
procedure CreateListItems;
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
const
N = 50;
THUMB_WIDTH = 32;
THUMB_HEIGHT = 32;
THUMB_PADDING = 4;
var
thumbs: array[0..N-1] of TBitmap;
procedure CreateThumbnails;
var
i: Integer;
begin
for i := 0 to N - 1 do
begin
thumbs[i] := TBitmap.Create;
thumbs[i].SetSize(THUMB_WIDTH, THUMB_HEIGHT);
thumbs[i].Canvas.Brush.Color := RGB(Random(255), Random(255), Random(255));
thumbs[i].Canvas.FillRect(Rect(0, 0, THUMB_WIDTH, THUMB_HEIGHT));
end;
end;
procedure TForm1.CreateListItems;
var
i: Integer;
begin
for i := 0 to N - 1 do
begin
with ListView1.Items.Add do
begin
Caption := 'Item ' + IntToStr(i);
ImageIndex := i;
end;
end;
end;
procedure TForm1.FormShow(Sender: TObject);
var
i: Integer;
begin
CreateThumbnails;
for i := 0 to N - 1 do
ImageList1.Add(thumbs[i], nil);
ListView1.LargeImages := ImageList1;
CreateListItems;
end;
OnDrawItem is a good way to go.
Simple example:
const
N = 50;
THUMB_WIDTH = 64;
THUMB_HEIGHT = 64;
THUMB_PADDING = 4;
var
thumbs: array[0..N-1] of TBitmap;
procedure CreateThumbnails;
var
i: Integer;
begin
for i := 0 to N - 1 do
begin
thumbs[i] := TBitmap.Create;
thumbs[i].SetSize(THUMB_WIDTH, THUMB_HEIGHT);
thumbs[i].Canvas.Brush.Color := RGB(Random(255), Random(255), Random(255));
thumbs[i].Canvas.FillRect(Rect(0, 0, THUMB_WIDTH, THUMB_HEIGHT));
end;
end;
procedure TForm4.FormCreate(Sender: TObject);
var
i: integer;
begin
with ListBox1.Items do
begin
BeginUpdate;
for i := 0 to N - 1 do
Add(Format('This is item %d.', [i]));
EndUpdate;
end;
ListBox1.ItemHeight := 2*THUMB_PADDING + THUMB_HEIGHT;
CreateThumbnails;
end;
procedure TForm4.ListBox1DrawItem(Control: TWinControl; Index: Integer;
Rect: TRect; State: TOwnerDrawState);
var
dc: HDC;
s: string;
r: TRect;
begin
dc := TListBox(Control).Canvas.Handle;
s := TListBox(Control).Items[Index];
FillRect(dc, Rect, GetStockObject(WHITE_BRUSH));
BitBlt(dc,
Rect.Left + THUMB_PADDING,
Rect.Top + THUMB_PADDING,
THUMB_WIDTH,
THUMB_HEIGHT,
thumbs[Index].Canvas.Handle,
0,
0,
SRCCOPY);
r := Rect;
r.Left := Rect.Left + 2*THUMB_PADDING + THUMB_WIDTH;
DrawText(dc,
PChar(s),
length(s),
r,
DT_SINGLELINE or DT_VCENTER or DT_LEFT or DT_END_ELLIPSIS);
end;
In a real-world scenario, the thumbs array would contain the actual image thumbs. In this example, however, the "thumbnails" consist of single-colour squares.

Resources