Problem with manual code migration from C# to C - c#

I am trying to migrate a code written in C# to C for better performance and to be able to use it in another software as it supports C based DLL.
I have this function in C# which performs as expected
private byte[] authDataExtract(byte[] concatenatedData)
{
try
{
byte[] authData = null;
authData = new byte[concatenatedData.Length - 10];
int blockCount = 0;
while (true)
{
if (concatenatedData.Length - 10 - blockCount < 4)
break;
else if (concatenatedData.Length - 10 - blockCount >= 4)
{
if ((isAllZero(concatenatedData, blockCount) == true) || (isAllff(concatenatedData, blockCount) == true)) //Modified to handle 0xFF padding - Sudhanwa
break;
int dlc = int.Parse(concatenatedData[blockCount + 3].ToString("X2"), System.Globalization.NumberStyles.HexNumber); //Modified to handle exceptiion in case of Padding CR - Sudhanwa
//int dlc = int.Parse(bytetostring(concatenatedData[blockCount + 3]));
if ((dlc > concatenatedData.Length - 10 - blockCount))
{
authData = new byte[concatenatedData.Length - 10];
Buffer.BlockCopy(concatenatedData, 0, authData, 0, concatenatedData.Length - 10);
blockCount = concatenatedData.Length - 10;
break;
}
authData = new byte[blockCount + 4 + dlc];
Buffer.BlockCopy(concatenatedData, 0, authData, 0, blockCount + 4 + dlc);
blockCount += dlc + 4;
}
}
return authData;
}
catch (Exception)
{
throw;
}
}
I want to write equivalent C code for this
My current C code is
void authDataExtract(unsigned char payload [],unsigned int size_payload,unsigned char * arr)
{
//unsigned char rec_tMAC [8];
int blockcount=0;
int dlc=0;
//unsigned char* arr= NULL;
//memcpy(&rec_tMAC[0],&payload[size_payload-8],8);
//printArr(rec_tMAC,8);
while (1)
{
if (size_payload- 10 - blockcount < 4)
break;
else if (size_payload - 10 - blockcount >= 4)
{
if ((isAllZero(payload,size_payload,blockcount) == true) ||
(isAllff(payload,size_payload, blockcount) == true))
break;
dlc= payload[blockcount + 3];
if ((dlc > size_payload - 10 - blockcount))
{
arr = (unsigned char*)calloc(size_payload-10,sizeof(unsigned char));
memcpy(arr,payload,size_payload-10);
blockcount = size_payload - 10;
break;
}
arr = (unsigned char*)calloc(blockcount + 4 + dlc,sizeof(unsigned char));
memcpy(arr,payload,blockcount + 4 + dlc);
blockcount += dlc + 4;
}
}
}
But it is giving exceptions with pointer .I believe I have an issue
with dynamic memory allocation.
Assuming the logic inc C# code is correct ,request your help to have exact same logic with C function.
Thanks in advance.

Do you see that C# function is returning byte[]
private byte[] authDataExtract(byte[] concatenatedData)
But C function is not.
void authDataExtract(unsigned char payload [],unsigned int size_payload,unsigned char * arr)
Note that arr is new variable and it is local to authDataExtract
function. It has no effect on the caller function.
Try as below.
unsigned char* authDataExtract(unsigned char payload [],unsigned int size_payload,unsigned char * arr) {
while(1) {
...
}
return arr;
}
from main
unsigned char *p = authDataExtract(….);
if (!p) error;
You could also use pointer to pointer but I leave that to you.

Related

Compression Performance Difference between swift and Managed(c#)

I'm implementing LZF compress in managed memory environment and decompress from ios environment.
So this is my code implement lzf decompress like this
in c#
private static int LZFDecompress(byte[] input, byte[] output)
{
int inputLength = input.Length;
int outputLength = output.Length;
uint iidx = 0;
uint oidx = 0;
do
{
uint ctrl = input[iidx++];
if (ctrl < (1 << 5)) /* literal run */
{
ctrl++;
if (oidx + ctrl > outputLength)
{
//SET_ERRNO (E2BIG);
return 0;
}
do
output[oidx++] = input[iidx++];
while ((--ctrl) != 0);
}
else /* back reference */
{
uint len = ctrl >> 5;
int reference = (int)(oidx - ((ctrl & 0x1f) << 8) - 1);
if (len == 7)
len += input[iidx++];
reference -= input[iidx++];
if (oidx + len + 2 > outputLength)
{
//SET_ERRNO (E2BIG);
return 0;
}
if (reference < 0)
{
//SET_ERRNO (EINVAL);
return 0;
}
output[oidx++] = output[reference++];
output[oidx++] = output[reference++];
do
output[oidx++] = output[reference++];
while ((--len) != 0);
}
}
while (iidx < inputLength);
return (int)oidx;
}
and porting to swift like this
private static func LZFDecompress(input: [UInt8],
output: inout [UInt8])
-> Int
{
let inputLength = input.count
let outputLength = output.count
var iidx = 0
var oidx = 0
repeat
{
var ctrl = Int(input[iidx])
iidx += 1
if ctrl < (1 << 5)
{
ctrl += 1
if oidx + ctrl > outputLength
{
return 0
}
repeat
{
output[oidx] = input[iidx]
oidx += 1
iidx += 1
ctrl -= 1
}
while ctrl != 0
}
else
{
var len = ctrl >> 5
var reference = oidx - ((ctrl & 0x1f) << 8) - 1
if len == 7
{
len += Int(input[iidx])
iidx += 1
}
reference -= Int(input[iidx])
iidx += 1
if oidx + len + 2 > outputLength
{
return 0
}
if reference < 0
{
return 0
}
output[oidx] = output[reference]
oidx += 1
reference += 1
output[oidx] = output[reference]
oidx += 1
reference += 1
repeat
{
output[oidx] = output[reference]
oidx += 1
reference += 1
len -= 1
}
while len != 0
}
}
while iidx < inputLength
return oidx
}
But I have a problem, it is a performance difference.
It costs 2-3 seconds in c# but costs 9-10 seconds in swift to decompress same files...
I can't understand this situation.
I tested c# from console in windows.
And I tested swift from playground or project in mac.
It was not efficient code unconsidered SIMD and CPUs.
So I used decompress method (lz4, zlib) is provided by apple.
It's so faster than before. It costs below 1-second decompressing 200Mb file.
But In a managed environment (c#) it's slower than unmanaged.
If you want more performance, implement native.
I use these lzib managed codes.
https://github.com/jstedfast/Ionic.Zlib
https://github.com/Kulestar/unity-zlib (unity version, dotnet-mono)
It costs 6-7 seconds for decompressing and 30 seconds for compressing at the same file.
And then you should know this code to be compatible to lzip in apple.
It includes adding the header for compressed data.
public static byte[] Compress(byte[] inputData)
{
var zlib = new ZlibCodec(CompressionMode.Compress);
zlib.CompressLevel = Zlib.CompressionLevel.AppleSupported; // Level5
zlib.InputBuffer = inputData;
zlib.OutputBuffer = new byte[inputData.Length];
zlib.NextIn = 0;
zlib.AvailableBytesIn = inputData.Length;
zlib.NextOut = 0;
zlib.AvailableBytesOut = inputData.Length;
zlib.InitializeDeflate(Zlib.CompressionLevel.AppleSupported, false);
// 'false' means it's 1951(deflate) version not 1950(lzib) version
zlib.Deflate(FlushType.Finish);
var output = new byte[zlib.TotalBytesOut];
Array.Copy(zlib.OutputBuffer, output, (int)zlib.TotalBytesOut);
return output;
}
public static byte[] Decompress(byte[] inputData, int outputSize)
{
var zlib = new ZlibCodec(CompressionMode.Decompress);
zlib.CompressLevel = Zlib.CompressionLevel.AppleSupported;
zlib.InputBuffer = inputData;
zlib.OutputBuffer = new byte[outputSize];
zlib.NextIn = 0;
zlib.AvailableBytesIn = inputData.Length;
zlib.NextOut = 0;
zlib.AvailableBytesOut = outputSize;
zlib.InitializeInflate(false);
zlib.Inflate(FlushType.Finish);
var output = new byte[zlib.TotalBytesOut];
Array.Copy(zlib.OutputBuffer, output, (int)zlib.TotalBytesOut);
return output;
}
I wish to help the same person like me who implement multi-platform compressing.

Encryption issue in Web API

I am developing an API for my web application. In my API i am connecting the same database that has been used in my web application. I need to encrypt and compare the password in my API with the password which is already present in my db in an encrypted format. Now since i am new to this project the problem is i don't know how the password was encrypted while storing it in db earlier, so what format do i use to encrypt my password in API.
Earlier the function which was used to encrypt the password was something like this:
Public Function Encrypt(ByVal input() As Byte) As Byte()
Dim i As Integer = 0
Dim iLen As Integer = input.Length
Dim output(0) As Byte
Dim newInput() As Byte
Dim inBuffer(BlockSize - 1) As Byte
Dim buffer(BlockSize - 1) As Byte
Dim count As Integer = 0
Try
count = GetArraySize(input.Length)
output = New Byte(count- 1) {}
newInput - New Byte(count - 1) {}
System.Array.copy(input, 0, newInput, 0, input.Length)
For i = 0 To count - BlockSize
System.Array.Copy(newInput, i, inBuffer, 0, BlockSize)
System.Array.copy(Cipher(inBuffer), 0, output, i, Blocksize)
Next i
Catch excep As Exception
Throw
End Try
Return output
End Function
Private Function Cipher(ByVal input() As Byte) As Byte()
Dim buffer1 As Byte() = New Byte(16 - 1) {}
Try
Me.State = New Byte(4 - 1, Me.Nb - 1) {}
Dim num1 As Integer
For num1 = 0 To (4 * Me.Nb) - 1
Me.State((num1 Mod 4), Int(num1 / 4)) = input(num1)
Next num1
Me.AddRoundKey(0)
Dim num2 As Integer = 1
Do While (num2 <= (Me.Nr - 1))
Me.SubBytes()
Me.ShiftRows()
Me.MixColumns()
Me.AddRoundKeys(num2)
num2 +=1
Loop
Me.SubBytes()
Me.ShiftRows()
Me.AddRoundKey(Me.Nr)
Dim num3 As Integer
For num3 = 0 To (4 * Me.Nb) - 1
buffer1(num3) = Me.State((num3 Mod 4), Int(num3 / 4))
Next num3
Catch exception As Exception
Throw
End Try
Return buffer1
End Function
Also previously the code was in VB.NET and my API is API with MVC.
As I understood,
If your migrate your project from Vb to C# Web API and
your database is still same.
then you face one problem that how can you code to decrypt password in c# where its already encrypted in vb or vice versa.
Means you want a same encryption or decryption algorithm in c# that you used in Vb.
So for this
Here i added C# equivalent code for your vb encrypt and cipher method that your added in your question
1) For Encryption
//Encrypt
public byte[] Encrypt(byte[] input)
{
int i = 0;
int iLen = input.Length;
byte[] output = new byte[1];
byte[] newInput;
byte[] inBuffer = new byte[BlockSize - 1 + 1];
byte[] buffer = new byte[BlockSize - 1 + 1];
int count = 0;
try
{
count = GetArraySize(input.Length);
output = new byte[count - 1 + 1];
newInput[-new byte[count - 1 + 1]];
System.Array.copy(input, 0, newInput, 0, input.Length);
for (i = 0; i <= count - BlockSize; i++)
{
System.Array.Copy(newInput, i, inBuffer, 0, BlockSize);
System.Array.copy(Cipher(inBuffer), 0, output, i, Blocksize);
}
}
catch (Exception excep)
{
throw;
}
return output;
}
2) For Cypher
//Cypher
private byte[] Cipher(byte[] input)
{
byte[] buffer1 = new byte[16] { };
try
{
this.State = new byte[4, this.Nb - 1 + 1];
int num1;
for (num1 = 0; num1 <= (4 * this.Nb) - 1; num1++)
this.State((num1 % 4), Conversion.Int(num1 / (double)4)) = input[num1];
this.AddRoundKey(0);
int num2 = 1;
while ((num2 <= (this.Nr - 1)))
{
this.SubBytes();
this.ShiftRows();
this.MixColumns();
this.AddRoundKeys(num2);
num2 += 1;
}
this.SubBytes();
this.ShiftRows();
this.AddRoundKey(this.Nr);
int num3;
for (num3 = 0; num3 <= (4 * this.Nb) - 1; num3++)
buffer1[num3] = this.State((num3 % 4), Conversion.Int(num3 / (double)4));
}
catch (Exception exception)
{
throw;
}
return buffer1;
}
Try once may it help you.

Difference in outputs between C# and java

I am trying to write a Java equivalent for a function in C#. The code follows.
In C#:
byte[] a = new byte[sizeof(Int32)];
readBytes(fStream, a, 0, sizeof(Int32)); //fstream is System.IO.Filestream
int answer = BitConverter.ToInt32(a, 0);
In Java:
InputStream fstream = new FileInputStream(fileName);
DataInputStream in = new DataInputStream(fstream);
BufferedReader br = new BufferedReader(new InputStreamReader(in));
byte[] a = new byte[4];
readBytes(in, a, 0, 4);
int answer = byteArrayToInt(a);
Both Java and C#:
int readBytes(Stream stream, byte[] storageBuffer, int offset, int requiredCount)
{
int totalBytesRead = 0;
while (totalBytesRead < requiredCount)
{
int bytesRead = stream.Read(
storageBuffer,
offset + totalBytesRead,
requiredCount - totalBytesRead);
if (bytesRead == 0)
{
break; // while
}
totalBytesRead += bytesRead;
}
return totalBytesRead;
}
Output:
In C#: answer = 192 (Correct)
In JAVA: answer = -1073741824
There is a difference in the two.I am reading from a file input stream which is encoded and parsing the first four bytes. The C# code seems to produce 192 which is the correct answer while Java produces -1073741824 which is the wrong answer. Why and how ?
EDIT
Here is my byteArrayToInt
public static int byteArrayToInt(byte[] b, int offset) {
int value = 0;
for (int i = 0; i < 4; i++) {
int shift = (4 - 1 - i) * 8;
value += (b[i + offset] & 0x000000FF) << shift;
}
return value;
}
SOLUTION
The right solution for byteArrayToInt
public static int byteArrayToInt(byte[] b)
{
long value = 0;
for (int i = 0; i < b.length; i++)
{
value += (b[i] & 0xff) << (8 * i);
}
return (int) value;
}
This gives the right output
In java bytes are signed, so your -64 in java byte is binary equivalent to 192 in c# byte (192 == 256 - 64).
The problem is probaby in byteArrayToInt() where you assume it's unsigned during the conversion.
A simple
`b & 0x000000FF`
might help in that case.
Java's byte object is signed as soulcheck wrote. The binary value for 192 on an unsigned 8 bit integer would be 11000000.
If you are reading this value with a signed format, a leading 1 will indicate a negative. This means 11000000 becomes negative 01000000, which is -64.

How to convert a byte array (MD5 hash) into a string (36 chars)?

I've got a byte array that was created using a hash function. I would like to convert this array into a string. So far so good, it will give me hexadecimal string.
Now I would like to use something different than hexadecimal characters, I would like to encode the byte array with these 36 characters: [a-z][0-9].
How would I go about?
Edit: the reason I would to do this, is because I would like to have a smaller string, than a hexadecimal string.
I adapted my arbitrary-length base conversion function from this answer to C#:
static string BaseConvert(string number, int fromBase, int toBase)
{
var digits = "0123456789abcdefghijklmnopqrstuvwxyz";
var length = number.Length;
var result = string.Empty;
var nibbles = number.Select(c => digits.IndexOf(c)).ToList();
int newlen;
do {
var value = 0;
newlen = 0;
for (var i = 0; i < length; ++i) {
value = value * fromBase + nibbles[i];
if (value >= toBase) {
if (newlen == nibbles.Count) {
nibbles.Add(0);
}
nibbles[newlen++] = value / toBase;
value %= toBase;
}
else if (newlen > 0) {
if (newlen == nibbles.Count) {
nibbles.Add(0);
}
nibbles[newlen++] = 0;
}
}
length = newlen;
result = digits[value] + result; //
}
while (newlen != 0);
return result;
}
As it's coming from PHP it might not be too idiomatic C#, there are also no parameter validity checks. However, you can feed it a hex-encoded string and it will work just fine with
var result = BaseConvert(hexEncoded, 16, 36);
It's not exactly what you asked for, but encoding the byte[] into hex is trivial.
See it in action.
Earlier tonight I came across a codereview question revolving around the same algorithm being discussed here. See: https://codereview.stackexchange.com/questions/14084/base-36-encoding-of-a-byte-array/
I provided a improved implementation of one of its earlier answers (both use BigInteger). See: https://codereview.stackexchange.com/a/20014/20654. The solution takes a byte[] and returns a Base36 string. Both the original and mine include simple benchmark information.
For completeness, the following is the method to decode a byte[] from an string. I'll include the encode function from the link above as well. See the text after this code block for some simple benchmark info for decoding.
const int kByteBitCount= 8; // number of bits in a byte
// constants that we use in FromBase36String and ToBase36String
const string kBase36Digits= "0123456789abcdefghijklmnopqrstuvwxyz";
static readonly double kBase36CharsLengthDivisor= Math.Log(kBase36Digits.Length, 2);
static readonly BigInteger kBigInt36= new BigInteger(36);
// assumes the input 'chars' is in big-endian ordering, MSB->LSB
static byte[] FromBase36String(string chars)
{
var bi= new BigInteger();
for (int x= 0; x < chars.Length; x++)
{
int i= kBase36Digits.IndexOf(chars[x]);
if (i < 0) return null; // invalid character
bi *= kBigInt36;
bi += i;
}
return bi.ToByteArray();
}
// characters returned are in big-endian ordering, MSB->LSB
static string ToBase36String(byte[] bytes)
{
// Estimate the result's length so we don't waste time realloc'ing
int result_length= (int)
Math.Ceiling(bytes.Length * kByteBitCount / kBase36CharsLengthDivisor);
// We use a List so we don't have to CopyTo a StringBuilder's characters
// to a char[], only to then Array.Reverse it later
var result= new System.Collections.Generic.List<char>(result_length);
var dividend= new BigInteger(bytes);
// IsZero's computation is less complex than evaluating "dividend > 0"
// which invokes BigInteger.CompareTo(BigInteger)
while (!dividend.IsZero)
{
BigInteger remainder;
dividend= BigInteger.DivRem(dividend, kBigInt36, out remainder);
int digit_index= Math.Abs((int)remainder);
result.Add(kBase36Digits[digit_index]);
}
// orientate the characters in big-endian ordering
result.Reverse();
// ToArray will also trim the excess chars used in length prediction
return new string(result.ToArray());
}
"A test 1234. Made slightly larger!" encodes to Base64 as "165kkoorqxin775ct82ist5ysteekll7kaqlcnnu6mfe7ag7e63b5"
To decode that Base36 string 1,000,000 times takes 12.6558909 seconds on my machine (I used the same build and machine conditions as provided in my answer on codereview)
You mentioned that you were dealing with a byte[] for the MD5 hash, rather than a hexadecimal string representation of it, so I think this solution provide the least overhead for you.
If you want a shorter string and can accept [a-zA-Z0-9] and + and / then look at Convert.ToBase64String
Using BigInteger (needs the System.Numerics reference)
Using BigInteger (needs the System.Numerics reference)
const string chars = "0123456789abcdefghijklmnopqrstuvwxyz";
// The result is padded with chars[0] to make the string length
// (int)Math.Ceiling(bytes.Length * 8 / Math.Log(chars.Length, 2))
// (so that for any value [0...0]-[255...255] of bytes the resulting
// string will have same length)
public static string ToBaseN(byte[] bytes, string chars, bool littleEndian = true, int len = -1)
{
if (bytes.Length == 0 || len == 0)
{
return String.Empty;
}
// BigInteger saves in the last byte the sign. > 7F negative,
// <= 7F positive.
// If we have a "negative" number, we will prepend a 0 byte.
byte[] bytes2;
if (littleEndian)
{
if (bytes[bytes.Length - 1] <= 0x7F)
{
bytes2 = bytes;
}
else
{
// Note that Array.Resize doesn't modify the original array,
// but creates a copy and sets the passed reference to the
// new array
bytes2 = bytes;
Array.Resize(ref bytes2, bytes.Length + 1);
}
}
else
{
bytes2 = new byte[bytes[0] > 0x7F ? bytes.Length + 1 : bytes.Length];
// We copy and reverse the array
for (int i = bytes.Length - 1, j = 0; i >= 0; i--, j++)
{
bytes2[j] = bytes[i];
}
}
BigInteger bi = new BigInteger(bytes2);
// A little optimization. We will do many divisions based on
// chars.Length .
BigInteger length = chars.Length;
// We pre-calc the length of the string. We know the bits of
// "information" of a byte are 8. Using Log2 we calc the bits of
// information of our new base.
if (len == -1)
{
len = (int)Math.Ceiling(bytes.Length * 8 / Math.Log(chars.Length, 2));
}
// We will build our string on a char[]
var chs = new char[len];
int chsIndex = 0;
while (bi > 0)
{
BigInteger remainder;
bi = BigInteger.DivRem(bi, length, out remainder);
chs[littleEndian ? chsIndex : len - chsIndex - 1] = chars[(int)remainder];
chsIndex++;
if (chsIndex < 0)
{
if (bi > 0)
{
throw new OverflowException();
}
}
}
// We append the zeros that we skipped at the beginning
if (littleEndian)
{
while (chsIndex < len)
{
chs[chsIndex] = chars[0];
chsIndex++;
}
}
else
{
while (chsIndex < len)
{
chs[len - chsIndex - 1] = chars[0];
chsIndex++;
}
}
return new string(chs);
}
public static byte[] FromBaseN(string str, string chars, bool littleEndian = true, int len = -1)
{
if (str.Length == 0 || len == 0)
{
return new byte[0];
}
// This should be the maximum length of the byte[] array. It's
// the opposite of the one used in ToBaseN.
// Note that it can be passed as a parameter
if (len == -1)
{
len = (int)Math.Ceiling(str.Length * Math.Log(chars.Length, 2) / 8);
}
BigInteger bi = BigInteger.Zero;
BigInteger length2 = chars.Length;
BigInteger mult = BigInteger.One;
for (int j = 0; j < str.Length; j++)
{
int ix = chars.IndexOf(littleEndian ? str[j] : str[str.Length - j - 1]);
// We didn't find the character
if (ix == -1)
{
throw new ArgumentOutOfRangeException();
}
bi += ix * mult;
mult *= length2;
}
var bytes = bi.ToByteArray();
int len2 = bytes.Length;
// BigInteger adds a 0 byte for positive numbers that have the
// last byte > 0x7F
if (len2 >= 2 && bytes[len2 - 1] == 0)
{
len2--;
}
int len3 = Math.Min(len, len2);
byte[] bytes2;
if (littleEndian)
{
if (len == bytes.Length)
{
bytes2 = bytes;
}
else
{
bytes2 = new byte[len];
Array.Copy(bytes, bytes2, len3);
}
}
else
{
bytes2 = new byte[len];
for (int i = 0; i < len3; i++)
{
bytes2[len - i - 1] = bytes[i];
}
}
for (int i = len3; i < len2; i++)
{
if (bytes[i] != 0)
{
throw new OverflowException();
}
}
return bytes2;
}
Be aware that they are REALLY slow! REALLY REALLY slow! (2 minutes for 100k). To speed them up you would probably need to rewrite the division/mod operation so that they work directly on a buffer, instead of each time recreating the scratch pads as it's done by BigInteger. And it would still be SLOW. The problem is that the time needed to encode the first byte is O(n) where n is the length of the byte array (this because all the array needs to be divided by 36). Unless you want to work with blocks of 5 bytes and lose some bits. Each symbol of Base36 carries around 5.169925001 bits. So 8 of these symbols would carry 41.35940001 bits. Very near 40 bytes.
Note that these methods can work both in little-endian mode and in big-endian mode. The endianness of the input and of the output is the same. Both methods accept a len parameter. You can use it to trim excess 0 (zeroes). Note that if you try to make an output too much small to contain the input, an OverflowException will be thrown.
System.Text.Encoding enc = System.Text.Encoding.ASCII;
string myString = enc.GetString(myByteArray);
You can play with what encoding you need:
System.Text.ASCIIEncoding,
System.Text.UnicodeEncoding,
System.Text.UTF7Encoding,
System.Text.UTF8Encoding
To match the requrements [a-z][0-9] you can use it:
Byte[] bytes = new Byte[] { 200, 180, 34 };
string result = String.Join("a", bytes.Select(x => x.ToString()).ToArray());
You will have string representation of bytes with char separator. To convert back you will need to split, and convert the string[] to byte[] using the same approach with .Select().
Usually a power of 2 is used - that way one character maps to a fixed number of bits. An alphabet of 32 bits for instance would map to 5 bits. The only challenge in that case is how to deserialize variable-length strings.
For 36 bits you could treat the data as a large number, and then:
divide by 36
add the remainder as character to your result
repeat until the division results in 0
Easier said than done perhaps.
you can use modulu.
this example encode your byte array to string of [0-9][a-z].
change it if you want.
public string byteToString(byte[] byteArr)
{
int i;
char[] charArr = new char[byteArr.Length];
for (i = 0; i < byteArr.Length; i++)
{
int byt = byteArr[i] % 36; // 36=num of availible charachters
if (byt < 10)
{
charArr[i] = (char)(byt + 48); //if % result is a digit
}
else
{
charArr[i] = (char)(byt + 87); //if % result is a letter
}
}
return new String(charArr);
}
If you don't want to lose data for de-encoding you can use this example:
public string byteToString(byte[] byteArr)
{
int i;
char[] charArr = new char[byteArr.Length*2];
for (i = 0; i < byteArr.Length; i++)
{
charArr[2 * i] = (char)((int)byteArr[i] / 36+48);
int byt = byteArr[i] % 36; // 36=num of availible charachters
if (byt < 10)
{
charArr[2*i+1] = (char)(byt + 48); //if % result is a digit
}
else
{
charArr[2*i+1] = (char)(byt + 87); //if % result is a letter
}
}
return new String(charArr);
}
and now you have a string double-lengthed when odd char is the multiply of 36 and even char is the residu. for example: 200=36*5+20 => "5k".

Need some help porting this C code to C#

I am not very good at c at all. I have tried to capture the essense of what the C code does in C# using this wikipedia article. However my version is totally different and does not achive the same compression that the C code does. Therefore, I'd like to port the following code from C to C#. However, i do not need it to read/write to files.
I am not familiar with how file reading and writing works in C. Therefore all of the file related fluff confuses me. Also these lines are a little confusing: token = i - 1 | 0x80; and length = (token & ~0x80) + 1;
/******************************************************************************
* LoadRLE / SaveRLE - Load and save binary data using RLE compression.
* Run-length tokens have a set MSB, while data tokens have a cleared
* MSB. The value of the token's remaining bits plus one indicates the
* length of the block. The minimum run length is three bytes, while
* the maximum is 128.
*
* data - Array holding data to load or save.
* size - Size of the data array.
* file - The file pointer to use.
* return - Total number of bytes read from or written to data[].
*/
size_t SaveRLE (unsigned char data[], size_t size, FILE *file)
{
unsigned char token;
unsigned int i;
size_t total = 0;
while(size)
{
/*This loop identifies blocks of repeating data:*/
i = 2;
while(i < size && i < 128 &&
data[i] == data[i - 1] && data[i - 1] == data[i - 2])
i++;
/*If repeating data was found, save it:*/
if(i > 2){
token = i - 1 | 0x80;
if(!fwrite(&token, 1, 1, file))
return total;
if(!fwrite(data, 1, 1, file))
return total;
data += i, size -= i, total += i;
}
/*This loop identifies blocks of non-repeating data:*/
i = 0;
while(i < size && i < 128 && (i + 2 > size ? 1 :
data[i] != data[i + 1] || data[i + 1] != data[i + 2]))
i++;
/*If non-repeating data was found, save it:*/
if(i){
token = i - 1;
if(!fwrite(&token, 1, 1, file))
return total;
if(fwrite(data, 1, i, file) != i)
return total;
data += i, size -= i, total += i;
}
}
return total;
}
size_t LoadRLE (unsigned char data[], size_t size, FILE *file)
{
unsigned char token;
unsigned int length;
size_t total = 0;
while(size && fread(&token, 1, 1, file)){
length = (token & ~0x80) + 1;
if (length > size)
return total;
if(token & 0x80){
if(!fread(&token, 1, 1, file))
return total;
memset(data, token, length);
}else{
if(fread(data, 1, length, file) != length)
return total;
}
data += length, size -= length, total += length;
}
return total;
}
Any help is greatly appreciated.
For your file question, I would strongly suggest consulting the C standard library documentation.
fread fwrite
token = i - 1 | 0x80;
i minus 1, | does a bitwise OR operation, in this case setting the 8th bit in token.
length = (token & ~0x80) + 1;
token & ~0x80 takes the NOT of 0x80 (all bits but the high bit) and does a bitwise AND (bit is set when both bits are set). In this case, it returns every but but the 8th bit.
As for what this means in your case, look at some articles about RLE.
/* 0 */
unsigned char token;
unsigned char data[];
FILE *file;
/* 1 */
if(!fwrite(&token, 1, 1, file))
return total;
/* 2 */
if(!fwrite(data, 1, 1, file))
return total;
/* 3 */
if(fwrite(data, 1, i, file) != i)
return total;
/* 4 */
if(!fread(&token, 1, 1, file))
return total;
/* 5 */
if(fread(data, 1, length, file) != length)
return total;
/* 6 */
while(size && fread(&token, 1, 1, file))
/* 7 */
data += i;
data[i];
/* 0 */
int token; // I'm using 'int' here to easier read single byte from Stream object, in your C code 'token' variable does not overflow so there will be no problem with that is has other type then 'byte'
byte[] data;
int data_pos = 0; // instead of moving 'data' pointer use additional index variable
Stream file; // some stream to read/write bytes
try {
/* 1 */
file.WriteByte((byte)token);
/* 2 */
file.Write(data, data_pos, 1);
/* 3 */
file.Write(data, data_pos, i);
/* 4 */
if ((token = file.ReadByte()) < 0)
return total;
/* 5 */
if (file.Read(data, data_pos, length) < length)
return total;
/* 6 */
while((size != 0) && ((token = file.ReadByte()) >= 0))
/* 7 */
data_pos += i;
data[data_pos + i];
} catch (IOException e) {
return total;
}
token = i - 1 | 0x80;
The | symbol is a bitwise OR, so it is combining i - 1 with 0x80 (hex for 128). I will leave the research into bitwise operations to you.
length = (token & ~0x80) + 1;
The & is a bitwise AND, while ~ negates the following value (flips the 1s and 0s). So that:
~1111000 = 00001111
Incidentally, all these operators are in C# and work in more or less the same way.

Categories