How to convert some C# code to Pascal? - c#

I have a couple of functions that I need to convert to Pascal to include in my inno setup installer, to validate a serial number on install.
Any assistance would be appreciated, as I haven't written any pascal in about 8 years.
Here is the C# code.
public static long DecodeAuthID(String keyset, String toDecode)
{
StringBuilder retval = new StringBuilder();
for (int i = 0; i < toDecode.Length; i++)
{
char[] toDecodeCharArray = toDecode.ToCharArray();
retval.Append(keyset.IndexOf(toDecodeCharArray[i]));
}
return Int32.Parse(retval.ToString());
}
public static string ReverseString(string stringToReverse)
{
char[] values = stringToReverse.ToCharArray();
Array.Reverse(values);
return new string(values);
}
private static void GetLocationFromAuthenticationID()
{
// Get Authentication Key from the Registry
string registryValue = GetAuthIDFromRegistry();
// Decode the Authentication Key to get the location
string value1 = ReverseString(registryValue);
string value2 = value1.Substring(0, 12);
string keyset = ReverseString(value2);
string valuesReversed = value1.Substring(12, value1.Length - 12);
string values = ReverseString(valuesReversed);
// Decode the AuthID
string authID = DecodeAuthID(keyset, values).ToString();
// Convert to Location ID
int locationID = Int32.Parse(authID) - (Int32.Parse(authID) - 1);
}

You can take a look at this (untested, other than it compiles if I comment out the line with GetAuthIDFromRegistry which is unimplemented - couldn't test because I don't have any sample input/output data to work with from your question). It may not be 100% correct, but it should at least get you started in the right direction.
function DecodeAuthID(KeySet: string; toDecode: string): longint;
var
idx, c: Integer;
Temp: string;
begin
Temp := '';
for idx := 1 to Length(toDecode) do
begin
// Replaces keyset.IndexOf. Handles no match found in KeySet just in case.
c := Pos(toDecode[idx], KeySet);
if c > 0 then
Temp := Temp + KeySet[c];
end;
// Handles no values set in result by returning 0
Result := StrToIntDef(Temp, 0);
end;
function ReverseString(stringToReverse: string): string;
var
i: Integer;
begin
Result := '';
for i := 1 to Length(stringToReverse) do
Result := stringToReverse[i] + Result;
end;
procedure GetLocationFromAuthenticationID;
var
registryValue: string;
value1, value2, keyset: string;
valuesReversed: string;
values: string;
authID: LongInt;
locationID: Integer;
begin
// GetAuthIDFromRegistry code not provided in question.
// See InnoSetup Help File, Pascal Scripting: Support Functions Reference,
// subheading "Registry functions"
registryValue := GetAuthIDFromRegistry;
value1 := ReverseString(registryValue);
// Delphi strings are 1 based, as opposed to the C# char array's 0 base
value2 := Copy(value1, 1, 12);
keyset := ReverseString(value2);
valuesReversed := Copy(Value1, 13, Length(value1) - 12);
values := ReverseString(valuesReversed);
authID := DecodeAuthID(keyset, values);
locationID := authID - (authID - 1);
end;
All of the functions not containing source here are listed as supported in the InnoSetup help file in either the "Pascal Scripting: Support Functions Reference".

You can try the C# to Oxygene converter that does this conversion to Oxygene, the Object Pascal used in Delphi Prism.
The problem is that this code makes use of .NET classes (like StringBuilder) and converters (Int32.Parse) that are not available in InnoSetup.

Related

Pascal code to C# code conversion (ord and chr)

I'm actualy trying to convert pascal code into c# code (we are re-writing old application).
Pascal code:
function DecryptStr(Source: PChar): string;
var
st: string;
i, k, mask: byte;
begin
Result := '';
try
SetString(st, Source, 32);
if st[1] <> #0 then
begin
mask := ord(st[1]);
k := ord(st[2]) xor mask;
SetLength(Result, k);
for i := 1 to k do
begin
inc(mask);
k := ord(st[i + 2]) xor mask;
Result[i] := chr(k);
// Result := Result + chr(k);
end;
end;
except
end;
end;
And my C# code:
public static string decrypt(string hash)
{ string buffer;
byte i, k, mask;
string result = "";
buffer = hash.Substring(0, 32);
mask = (byte)(buffer[0]);
k = (byte)((byte)(buffer[1])^mask);
for (i = 0; i<k-1; i++)
{
mask += 1;
k = (byte)((byte)(buffer[i+2])^mask);
result+=(char)(k);
}
// string decoded = System.
return (result);
}
Please, tell me, is it similar or pascal got some hidden stuff?
Example:
input in c#:
акРЖђЏГ€€њљђНѓGН q6™&і—'n1•\›ЛH[
output in c#:
\u0011$\f\v&\t\b
But it doesnt look like the real password.
Please, advice me what is going wrong.
The problem was in two things:
PChar format of input string - means it stores "0" at the end.
Idiotic mechanism of encryption - actualy, the guy who wrote down the code represented in question just chosed byte mask as a rand(200) + 32 was storing it in first byte of encrypted pass and then in cycle he was incrementing mask by one every step for all of pass length.
So the logic of decrypting is following:
Grab the mask - buffer[0] in this case
Do XOR for every other character with this mask, increasing it by one on every step.
3.???
Profit!
Thanks for everyone who participated in this theme!

Can't get the same result as the Delphi code, after I exclusive-OR an address of a char array in C#

Parameters: InLong = 0, Posit = 5, and from an ASCII file TmPChar{.,STX,NUL,NUL}
Delphi code
Procedure TForm1.GetLongFromBuf(Var InLong : Longint; Posit : Integer; ZRepB : ZrepBuf);
Var
TmpPChar : Array[0..3] Of Char;
PLong : ^Longint;
I : Byte;
Begin
For I:= 0 To 3 Do
TmpPChar[I] := ZRepB[Posit+I];
PLong := #TmpPChar;
InLong := PLong^;
End;
Outputs: TmPChar {'.', #2, #0, #0}, PLong = 13F54C, InLong = 558
C# code
unsafe static long GetLongFromBuf(long InLong, int Posit, char[] ZRepB){
long* Plong;
char[] TmpPChar = new char[4];
for (byte i = 0; i < TmpPChar.Length; i++){
TmpPChar[i] = ZRepB[(Posit-1) + (i)];
}
fixed(char* ch = TmpPChar){
PLong = (long*)&ch;
InLong ^= (long)PLong;
}
return InLong;
}
Outputs: TmPChar{'.','\u0002','\0','0'}, PLong = 0x0000000000b3cc18, InLong = 11783192
It appears that you are using this Delphi code without really understanding what it is doing. From your results, we can conclude you are using a pre-unicode version of Delphi (ie: D2007 or earlier). We can also guess that ZrepBuf is defining an array of bytes or [Ansi]Char. The method, then, works as follows :
For I:= 0 To 3 Do
TmpPChar[I] := ZRepB[Posit+I]; /* Copy four sequential bytes to TmpPChar array */
PLong := #TmpPChar; /* Take a pointer to the head of the array */
InLong := PLong^; /* Dereference the pointer, interpreting as a 32-bit int */
This is code to convert four bytes to a 32-bit integer. In Delphi the LongInt type is an alias for the 32-bit integer type, equivalent to the int type in C#, not long. There is no use of the XOR operator in the Delphi code. In PLong^, the ^ operator is a dereference operation.
In C# you can avoid unsafe code entirely and simply perform this conversion using the BitConverter class:
byte[] b = new byte[4] { 0x2E, 0x02, 0x00, 0x00 };
int result = BitConverter.ToInt32(b, 0); // result == 558
Here I've defined the input array as a byte[] since a char in C# (and in Delphi 2009 or newer) is a 16-bit type (two bytes) for storing Unicode characters. The data you are reading is ANSI encoded - I'm presuming you understand how to read your text file into a byte array.
Incidentally, in more modern Delphi you could also re-write the pointer code above to use the TEncoding class to perform this function as described here in a similar way to the BitConverter class in C#.

Byte to String in Delphi

I want to convert a Byte to String in Delphi
in c# for example is:
Convert.ToString(Byte, 16);
I tried:
SetString(AnsiStr, PAnsiChar(#ByteArray[0]), LengthOfByteArray);
StringVar := Chr(ByteVar);
Thanks
Assuming that Byte is a placeholder for a value of type byte, your C# code converts a single byte to its hexadecimal representation. The Delphi equivalent is IntToHex.
var
s: string;
b: Byte;
....
b := ...;
s := IntToHex(b);
Your Delphi code hints at you actually wishing to convert an array of bytes to their hexadecimal representation. In which case the function you need is BinToHex. I can't really give you much more detail because your question itself was lacking in detail. Without knowledge of the types of the variables, we are left making guesses. In future questions, it would be wise to supply a Minimal, Complete, and Verifiable example.
Finally I use this function;
function TForm1.bintostr(const bin: array of byte): string;
const HexSymbols = '0123456789ABCDEF';
var i: integer;
begin
SetLength(Result, 2*Length(bin));
for i := 0 to Length(bin)-1 do begin
Result[1 + 2*i + 0] := HexSymbols[1 + bin[i] shr 4];
Result[1 + 2*i + 1] := HexSymbols[1 + bin[i] and $0F];
end;
end;

Pascal to C# conversion

I am trying to convert this pascal code into C# in order to communicate with a peripheral device attached to a comm port. This piece of code should calculate the Control Byte, however I'm not getting the right hex Value therefore I'm wondering if I'm converting the code in the right way.
Pascal:
begin
check := 255;
for i:= 3 to length(sequence)-4 do
check := check xor byte(sequence[i]);
end;
C#:
int check = 255;
for (int x = 3; x < (sequence.Length - 4); x++)
{
check = check ^ (byte)(sequence[x]);
}
Pascal function:
{ *** conversion of number into string ‘hex’ *** }
function word_to_hex (w: word) : string;
var
i : integer;
s : string;
b : byte;
c : char;
begin
s := ‘’;
for i:= 0 to 3 do
begin
b := (hi(w) shr 4) and 15;
case b of
0..9 : c := char(b+$30);
10..15 : c := char(b+$41-10);
end;
s := s + c;
w := w shl 4;
end;
word_ to_hex := s;
end;
C# Equivalent:
public string ControlByte(string check)
{
string s = "";
byte b;
char c = '\0';
//shift = check >> 4 & 15;
for (int x = 0; x <= 3; x++)
{
b = (byte)((Convert.ToInt32(check) >> 4) & 15);
if (b >= 0 && b <= 9)
{
c = (char)(b + 0x30);
}
else if (b >= 10 && b <= 15)
{
c = (char)(b + 0x41 - 10);
}
s = s + c;
check = (Convert.ToInt32(check) << 4).ToString();
}
return s;
}
And last pascal:
function byte_to_hex (b:byte) : string;
begin
byte_to_hex := copy(word_to_hex(word(b)),3,2);
end;
which i am not sure how is substringing the result from the function. So please let me know if there is something wrong with the code conversion and whether I need to convert the function result into bytes. I appreciate your help, UF.
Further info EDIT: Initially I send a string sequence containing the command and information that printer is supposed to print. Since every sequence has a unique Control Byte (in Hex) I have to calculate this from the sequence (sequence = "P1;1$l201PrinterPrinterPrinter1B/100.00/100.00/0/\") which is what upper code does according to POSNET=>"cc – control byte, encoded as 2 HEX digits (EXOR of all characters after ESC P to this byte with #255 initial quantity), according to the following algorithm in PASCAL language:(see first code block)".=>1. check number calculated in the above loop which constitutes control byte should be recoded into two HEX characters (ASCII characters from scope: ‘0’..’9’,’A’..’F’,’a’..’f’), utilizing the following byte_to_hex function:(see third code block). =>{* conversion of byte into 2 characters *}(see 5th code block)
The most obvious problem that I can see is that the Pascal code operates on 1-based 8 bit encoded strings, and the C# code operates on 0-based 16 bit encoded strings. To convert the Pascal/Delphi code that you use to C# you need to address the mis-match. Perhaps like this:
byte[] bytes = Encoding.Default.GetBytes(sequence);
int check = 255;
for (int i = 2; i < bytes.Length-4; i++)
{
check ^= bytes[i];
}
Now, in order to write this I've had to make quite a few assumptions, because you did not include anywhere near enough code in the question. Here's what I assumed:
The Pascal sequence variable is a 1-based 8 bit ANSI encoded Delphi AnsiString.
The Pascal check variable is a Delphi 32 bit signed Integer.
The C# sequence variable is a C# string.
If any of those assumptions prove to be false, then the code above will be no good. For instance, perhaps the Pascal check is really Byte. In which case I guess the C# code should be:
byte[] bytes = Encoding.Default.GetBytes(sequence);
byte check = 255;
for (int i = 2; i < bytes.Length - 4; i++)
{
check ^= bytes[i];
}
I hope that this persuades you of the importance of supplying complete information.
That's really all the meat of this question. The rest of the code concerns converting values to hex strings in C# code. That has been covered again and again here on Stack Overflow. For instance:
C# convert integer to hex and back again
How do you convert Byte Array to Hexadecimal String, and vice versa?
There are many many more such questions.

In SQL Server, I need to pack 2 characters into 1 character, similar to HEX. How?

I have a SQL Server table that has a column in it that is defined as Binary(7).
It is updated with data from a Cobol program that has Comp-3 data (packed decimal).
I wrote a C# program to take a number and create the Comp-3 value. I have it available to SQL Server via CLR Integration. I'm able to access it like a stored procedure.
My problem is, I need to take the value from this program and save it in the binary column. When I select a row of data that is already in there, I am seeing a value like the following:
0x00012F0000000F
The value shown is COBOL comp-3 (packed decimal) data, stored in the SQL table. Remember, this field is defined as Binary(7). There are two values concatenated and stored here. Unsigned value 12, and unsigned value 0.
I need to concatenate 0x00012F (length of 3 characters) and 0x0000000F (length of 4 characters) together and write it to the column.
My question is two part.
1) I am able to return a string representation of the Comp-3 value from my program. But, I'm not sure if this is the format I need to return to make this work. What format should I return to SQL, so it can be used correctly?
2) What do I need to do to convert this to make it work?
I hope I was clear enough. It's a lot to digest...Thanks!
I figured it out!
I needed to change the output to byte[], and reference it coming out of the program in SQL as varbinary.
This is the code, if anyone else in the future needs it. I hope this helps others that need to create Comp-3 (packed decimal) in SQL. I'll outline the steps to use it below.
Below is the source for the C# program. Compile it as a dll.
using System;
using System.Collections.Generic;
using System.Data;
using Microsoft.SqlServer.Server;
using System.Data.SqlTypes;
namespace Numeric2Comp3
{
//PackedDecimal conversions
public class PackedDecimal
{
[Microsoft.SqlServer.Server.SqlProcedure]
public static void ToComp3(string numberin, out byte[] hexarray, out string hexvalue)
{
long value;
bool result = Int64.TryParse(numberin, out value);
if (!result)
{
hexarray = null;
hexvalue = null;
return;
}
Stack<byte> comp3 = new Stack<byte>(10);
byte currentByte;
if (value < 0)
{
currentByte = 0x0d; //signed -
value = -value;
}
else if (numberin.Trim().StartsWith("+"))
{
currentByte = 0x0c; //signed +
}
else
{
currentByte = 0x0f; //unsigned
}
bool byteComplete = false;
while (value != 0)
{
if (byteComplete)
currentByte = (byte)(value % 10);
else
currentByte |= (byte)((value % 10) << 4);
value /= 10;
byteComplete = !byteComplete;
if (byteComplete)
comp3.Push(currentByte);
}
if (!byteComplete)
comp3.Push(currentByte);
hexarray = comp3.ToArray();
hexvalue = bytesToHex(comp3.ToArray());
}
private static string bytesToHex(byte[] buf)
{
string HexChars = "0123456789ABCDEF";
System.Text.StringBuilder sb = new System.Text.StringBuilder((buf.Length / 2) * 5 + 3);
for (int i = 0; i < buf.Length; i++)
{
sbyte b = Convert.ToSByte(buf[i]);
b = (sbyte)(b >> 4); // Hit to bottom
b = (sbyte)(b & 0x0F); // get HI byte
sb.Append(HexChars[b]);
b = Convert.ToSByte(buf[i]); // refresh
b = (sbyte)(b & 0x0F); // get LOW byte
sb.Append(HexChars[b]);
}
return sb.ToString();
}
}
}
Save the dll somewhere in a folder on the SQL Server machine. I used 'C:\NTA\Libraries\Numeric2Comp3.dll'.
Next, you'll need to enable CLR Integration on SQL Server. Read about it on Microsoft's website here: Introduction to SQL Server CLR Integration. Open SQL Server Management Studio and execute the following to enable CLR Integration:
sp_configure 'show advanced options', 1;
GO
RECONFIGURE;
GO
sp_configure 'clr enabled', 1;
GO
RECONFIGURE;
GO
Once that is done, execute the following in Management Studio:
CREATE ASSEMBLY Numeric2Comp3 from 'C:\NTA\Libraries\Numeric2Comp3.dll' WITH PERMISSION_SET = SAFE
You can execute the following to remove the assembly, if you need to for any reason:
drop assembly Numeric2Comp3
Next, in Management studio, execute the following to create the stored procedure to reference the dll:
CREATE PROCEDURE Numeric2Comp3
#numberin nchar(27), #hexarray varbinary(27) OUTPUT, #hexstring nchar(27) OUTPUT
AS
EXTERNAL NAME Numeric2Comp3.[Numeric2Comp3.PackedDecimal].ToComp3
If everything above runs successfully, you're done!
Here is some SQL to test it out:
DECLARE #in nchar(27), #hexstring nchar(27), #hexarray varbinary(27)
set #in = '20120123'
EXEC Numeric2Comp3 #in, #hexarray out, #hexstring out
select len(#hexarray), #hexarray
select len(#hexstring), #hexstring
This will return the following values:
(No column name) (No column name)
5 0x020120123F
(No column name) (No column name)
10 020120123F
In my case, what I need is the value coming out of #hexarray. This will be written to the Binary column in my table.
I hope this helps others that may need it!
If you have Comp-3 stored in a binary filed as a hex string, well I wonder if the process that created this is working as it should.
Be that as it may, the best solution would be to cast them in the select; the cast sytax is simple, but I don't know if a comp-3 cast is available.
Here are examples on MSDN.
So let's work with the string: To transform the string you use this:
string in2 = "020120123C";
long iOut = Convert.ToInt64(in2.Substring(0, in2.Length - 1))
* (in2.Substring(in2.Length - 1, 1)=="D"? -1 : 1 ) ;
It treats the last character as th sign, with 'D' being the one negative sign. Both 'F' and 'C' would be positive.
Will you also need to write the data back?
I am curious: What string representaion comes out for fractional numbers like 123.45 ?
( I'll leave the original answer for reference..:)
Here are a few lines of code to show how you can work with bit and bytes.
The operations to use are:
shift the data n bits right or left: << n or >> n
masking/clearing unwanted high bits: e.g. set all to 0 except the last 4 bits: & 0xF
adding bitwise: |
If you have a string representation like the one you have shown the out3 and out4 byte would be the result. The other conversions are just examples how to process bit; you can't possibly have decimals as binarys or binarys that look like decimals. Maybe you get integers - then out7 and out8 would be the results.
To combine two bytes into one integer look at the last calculation!
// 3 possible inputs:
long input = 0x00012F0000071F;
long input2 = 3143;
string inputS = "0x00012F0000071F";
// take binary input as such
byte out1 = (byte)((input >> 4) & 0xFFFFFF );
byte out2 = (byte)(input >> 36);
// take string as decimals
byte out3 = Convert.ToByte(inputS.Substring(5, 2));
byte out4 = Convert.ToByte(inputS.Substring(13, 2));
// take binary as decimal
byte out5 = (byte)(10 * ((input >> 40) & 0xF) + (byte)((input >> 36) & 0xF));
byte out6 = (byte)(10 * ((input >> 8) & 0xF) + (byte)((input >> 4) & 0xF));
// take integer and pick out 3rd and last byte
byte out7 = (byte)(input2 >> 8);
byte out8 = (byte)(input2 & 0xFF);
// combine two bytes to one integer
int byte1and2 = (byte)(12) << 8 | (byte)(71) ;
Console.WriteLine(out1.ToString());
Console.WriteLine(out2.ToString());
Console.WriteLine(out3.ToString());
Console.WriteLine(out4.ToString());
Console.WriteLine(out5.ToString());
Console.WriteLine(out6.ToString());
Console.WriteLine(out7.ToString());
Console.WriteLine(out8.ToString());
Console.WriteLine(byte2.ToString());

Categories