C# Compress Triple Byte Array - c#

I currently got this script, which compresses byte arrays.
But I need it rewritten, so it can compress triple byte arrays [,,]
Thanks!
public static byte[] Compress(byte[] buffer)
{
MemoryStream ms = new MemoryStream();
GZipStream zip = new GZipStream(ms, CompressionMode.Compress, true);
zip.Write(buffer, 0, buffer.Length);
zip.Close();
ms.Position = 0;
MemoryStream outStream = new MemoryStream();
byte[] compressed = new byte[ms.Length];
ms.Read(compressed, 0, compressed.Length);
byte[] gzBuffer = new byte[compressed.Length + 4];
Buffer.BlockCopy(compressed, 0, gzBuffer, 4, compressed.Length);
Buffer.BlockCopy(BitConverter.GetBytes(buffer.Length), 0, gzBuffer, 0, 4);
return gzBuffer;
}
public static byte[] Decompress(byte[] gzBuffer)
{
MemoryStream ms = new MemoryStream();
int msgLength = BitConverter.ToInt32(gzBuffer, 0);
ms.Write(gzBuffer, 4, gzBuffer.Length - 4);
byte[] buffer = new byte[msgLength];
ms.Position = 0;
GZipStream zip = new GZipStream(ms, CompressionMode.Decompress);
zip.Read(buffer, 0, buffer.Length);
return buffer;
}

Update: I rewrote the code, it is running much faster now and the code is cleaner. Just tested it with some random data (see end of this post).
The Compression method:
public static byte[] Compress(byte[, ,] uncompressed)
{
if (uncompressed == null)
throw new ArgumentNullException("uncompressed",
"The given array is null!");
if (uncompressed.LongLength > (long)int.MaxValue)
throw new ArgumentException("The given array is to large!");
using (MemoryStream ms = new MemoryStream())
using (GZipStream gzs = new GZipStream(ms, CompressionMode.Compress))
{
// Save sizes of the dimensions
for (int dim = 0; dim < 3; dim++)
gzs.Write(BitConverter.GetBytes(
uncompressed.GetLength(dim)), 0, sizeof(int));
// Convert byte[,,] to byte[] by just blockcopying it
// I know, some pointer-magic/unmanaged cast wouldnt
// have to copy it, but its cleaner this way...
byte[] data = new byte[uncompressed.Length];
Buffer.BlockCopy(uncompressed, 0, data, 0, uncompressed.Length);
// Write the data to the stream to compress it
gzs.Write(data, 0, data.Length);
gzs.Close();
// Get the compressed byte array back
return ms.ToArray();
}
}
The Decompression method:
public static byte[, ,] Decompress(byte[] compressed)
{
if (compressed == null)
throw new ArgumentNullException("compressed",
"Data to decompress cant be null!");
using (MemoryStream ms = new MemoryStream(compressed))
using (GZipStream gzs = new GZipStream(ms, CompressionMode.Decompress))
{
// Read the header and restore sizes of dimensions
byte[] dimheader = new byte[sizeof(int) * 3];
gzs.Read(dimheader, 0, dimheader.Length);
int[] dims = new int[3];
for (int j = 0; j < 3; j++)
dims[j] = BitConverter.ToInt32(dimheader, sizeof(int) * j);
// Read the data into a buffer
byte[] data = new byte[dims[0] * dims[1] * dims[2]];
gzs.Read(data, 0, data.Length);
// Copy the buffer to the three-dimensional array
byte[, ,] uncompressed = new byte[dims[0], dims[1], dims[2]];
Buffer.BlockCopy(data, 0, uncompressed, 0, data.Length);
return uncompressed;
}
}
The test code:
Random rnd = new Random();
// Create a new randomly big array, fill it with random data
byte[, ,] uncomp = new byte[rnd.Next(70, 100),
rnd.Next(70, 100), rnd.Next(70, 100)];
for (int x = 0; x < uncomp.GetLength(0); x++)
for (int y = 0; y < uncomp.GetLength(1); y++)
for (int z = 0; z < uncomp.GetLength(2); z++)
uncomp[x, y, z] = (byte)rnd.Next(30, 35);
// Compress and Uncompress again
Stopwatch compTime = new Stopwatch(), uncompTime = new Stopwatch();
compTime.Start();
byte[] comp = Compress(uncomp);
compTime.Stop();
uncompTime.Start();
byte[, ,] uncompagain = Decompress(comp);
uncompTime.Stop();
// Assert all dimension lengths and contents are equal
for (int j = 0; j < 3; j++)
Debug.Assert(uncomp.GetLength(j) == uncompagain.GetLength(j));
for (int x = 0; x < uncomp.GetLength(0); x++)
for (int y = 0; y < uncomp.GetLength(1); y++)
for (int z = 0; z < uncomp.GetLength(2); z++)
Debug.Assert(uncomp[x, y, z] == uncompagain[x, y, z]);
Console.WriteLine(string.Format("Compression: {0}ms, " +
"Decompression: {1}ms, Ratio: {2}% ({3}/{4} bytes)",
compTime.ElapsedMilliseconds, uncompTime.ElapsedMilliseconds,
(int)((double)comp.LongLength / (double)uncomp.LongLength * 100),
comp.LongLength, uncomp.LongLength));
Output, for example:
Compression: 77ms, Decompression: 23ms, Ratio: 41% (191882/461538 bytes)

Related

How to write to a .wav file using a generated wave, complex[] array?

I would like to know how to write to a .wav file, I have written the following code which supposedly writes data to the file. But when I try to play the sound file it says the file is corrupt / empty.
try
{
SaveFileDialog save = new SaveFileDialog();
save.Filter = "Wave File (*.wav)|*.wav;";
if (save.ShowDialog() != System.Windows.Forms.DialogResult.OK)
return;
using (FileStream FS = new FileStream(save.FileName, FileMode.Open, FileAccess.Write))
{
BinaryWriter wr = new BinaryWriter(FS);
int subchunk1Size = 16;
short audioFormat = 1;
short bitsPerSample = 64;
short numChannels = 2;
int sampleRate = Convert.ToInt32(samplingRateBox.Text);
int byteRate = sampleRate * numChannels * (bitsPerSample / 8);
short blockAlign = (short)(numChannels * (bitsPerSample / 8));
int numSamples = Convert.ToInt32(numberOfsamplesBox.Text);
int subChunk2Size = numSamples * numChannels * (bitsPerSample / 8);
int chunkSize = 4 + (8 + subchunk1Size) + (8 + subChunk2Size);
wr.Write(getBytes("RIFF"));
wr.Write(chunkSize);
wr.Write(getBytes("WAVE"));
wr.Write(getBytes("fmt"));
wr.Write((byte)32);
wr.Write(subchunk1Size);
wr.Write(audioFormat);
wr.Write(numChannels);
wr.Write(sampleRate);
wr.Write(byteRate);
wr.Write(blockAlign);
wr.Write(bitsPerSample);
wr.Write(getBytes("data"));
wr.Write(subChunk2Size);
double[] primArray = new double[samples.Length];
byte[] byteArray = new byte[samples.Length * 8];
for (int i = 0; i < samples.Length; i++)
{
primArray[i] = Convert.ToDouble(samples[i].Real);
}
byteArray = doubleToBytes(primArray);
for (int i = 0; i < samples.Length; i++)
{
wr.Write(byteArray[i]);
}
for (int i = 0; i < samples.Length; i++)
{
primArray[i] = Convert.ToDouble(samples[i].Imaginary);
}
byteArray = doubleToBytes(primArray);
for (int i = 0; i < samples.Length; i++)
{
wr.Write(byteArray[i]);
}
wr.Close();
wr.Dispose();
}
}
catch (Exception e)
{
MessageBox.Show(e.Message);
}
As you can see I have tried converting from Complex to double, plus the header.
The sampling rate and number of samples all come from textboxes. Plus I am assuming the bit depth is that of a double.
I have also tried using this method, however the length of the audio file is 0.
This used the NAudio library.
NAudio.Wave.WaveFileWriter waveWriter = null;
WaveIn wi = new WaveIn();
double[] primArray = new double[samples.Length];
for (int i = 0; i < samples.Length; i++)
{
primArray[i] = Convert.ToDouble(samples[i].Real);
}
SaveFileDialog save = new SaveFileDialog();
save.Filter = "Wave File (*.wav)|*.wav;";
if (save.ShowDialog() != System.Windows.Forms.DialogResult.OK)
return;
wi = new NAudio.Wave.WaveIn();
wi.WaveFormat = new WaveFormat(samplingRate,1);
waveWriter = new WaveFileWriter(save.FileName, wi.WaveFormat);
byte[] byteArray = new byte[samples.Length*8];
byteArray = doubleToBytes(primArray);
waveWriter.Write(byteArray, 0, byteArray.Length);

How to convert in fly ADPCM wav file in PSM wave file in c#

i have next code to convert ADPCM wav in PCM wave how you can do without intermediate storage file to disk here WaveFileWriter.CreateWaveFile("D:\\pcm16000.wav", upsampler);
public static byte[] ADPcmToPcm(string waveFileName, int bitRate = 128)
{
using (var reader = new WaveFileReader(waveFileName))
using (var converter = WaveFormatConversionStream.CreatePcmStream(reader))
using (var upsampler = new WaveFormatConversionStream(new WaveFormat(16000, converter.WaveFormat.Channels), converter))
{
WaveFileWriter.CreateWaveFile("D:\\pcm16000.wav", upsampler);
FileStream fs = new FileStream("d:\\pcm16000.wav", FileMode.Open, FileAccess.Read);
byte [] bytes = new byte[fs.Length];
int bytesToRead = (int)fs.Length;
int bytesRead = 0;
while (bytesToRead > 0)
{
int n = fs.Read(bytes, bytesRead, bytesToRead);
if (n == 0) break;
bytesRead += n;
bytesToRead -= n;
}
bytesToRead = bytes.Length;
return bytes;
}
}

C# TLS 1.1 Implementation

For some time I've been a bit desperately trying to implement a TLS 1.1 in my application. The reason behind this is the usage of SocketType.Raw sockets, so no SslStream or other higher-level classes are available to me.
So far I'm stuck at Finished message in TLS handshake protocol - keep on receiving bad_record_mac(20) in server response. Cipher suite is 0x0005 - TLS_RSA_WITH_RC4_128_SHA.
Here's some sample code on what's happening:
byte[] client_random, server_random = new byte[28];
byte[] pre_master_secret, master_secret;
byte[] client_write_MAC_secret, server_write_MAC_secret, client_write_key, server_write_key;
byte[] handshake_messages, verify_data;
RSACryptoServiceProvider rsa;
List<X509Certificate2> certificates = new List<X509Certificate2>();
//certificates are added
rsa = (RSACryptoServiceProvider)certificates.First().PublicKey.Key;
private byte[] ClientKeyExchange()
{
pre_master_secret = new byte[48];
(new Random()).NextBytes(pre_master_secret);
//version 0302 for TLS 1.1
pre_master_secret[0] = 3;
pre_master_secret[1] = 2;
byte[] cryptedData = rsa.Encrypt(pre_master_secret, false);
//"1603020086"
string tmp_string = "100000820080" + Utils.BitConverter.ToString(cryptedData).Replace("-", "");
AddHandShakeData(Utils.BitConverter.StringToByteArray(tmp_string));
tmp_string =
"1603020086"
+ tmp_string
+ "140302000101" //Cipher Change Spec
+ "";
return Utils.BitConverter.StringToByteArray(tmp_string);
}
private void ComputeMasterSecret()
{
byte[] label = Utils.BitConverter.StringToByteArray(Utils.BitConverter.ConvertStringToHex("master secret", Encoding.ASCII));
byte[] seed = new byte[client_random.Length + server_random.Length];
Buffer.BlockCopy(client_random, 0, seed, 0, client_random.Length);
Buffer.BlockCopy(server_random, 0, seed, client_random.Length, server_random.Length);
master_secret = PRF(pre_master_secret, label, seed, 48);
}
private void ComputeKeys()
{
byte[] label = Utils.BitConverter.StringToByteArray(Utils.BitConverter.ConvertStringToHex("key expansion", Encoding.ASCII));
byte[] seed = new byte[client_random.Length + server_random.Length];
Buffer.BlockCopy(client_random, 0, seed, 0, client_random.Length);
Buffer.BlockCopy(server_random, 0, seed, client_random.Length, server_random.Length);
byte[] key_material = PRF(master_secret, label, seed, 72);
client_write_MAC_secret = new byte[20];
Buffer.BlockCopy(key_material, 0, client_write_MAC_secret, 0, 20);
server_write_MAC_secret = new byte[20];
Buffer.BlockCopy(key_material, 20, server_write_MAC_secret, 0, 20);
client_write_key = new byte[16];
Buffer.BlockCopy(key_material, 40, client_write_key, 0, 16);
server_write_key = new byte[16];
Buffer.BlockCopy(key_material, 56, server_write_key, 0, 16);
}
private void ComputeVerifyData()
{
byte[] label = Utils.BitConverter.StringToByteArray(Utils.BitConverter.ConvertStringToHex("client finished", Encoding.ASCII));
SHA1 sha1 = SHA1.Create();
MD5 md5 = MD5.Create();
md5.ComputeHash(handshake_messages);
sha1.ComputeHash(handshake_messages);
byte[] seed = new byte[md5.HashSize / 8 + sha1.HashSize / 8];
Buffer.BlockCopy(md5.Hash, 0, seed, 0, md5.HashSize / 8);
Buffer.BlockCopy(sha1.Hash, 0, seed, md5.HashSize / 8, sha1.HashSize / 8);
verify_data = PRF(master_secret, label, seed, 12);
}
private byte[] PRF(byte[] secret, byte[] label, byte[] seed, int output_size)
{
int md5_iterations = (int)Math.Ceiling((double)output_size / 16),
sha1_iterations = (int)Math.Ceiling((double)output_size / 20);
byte[] md5_data = new byte[output_size],
sha1_data = new byte[output_size];
//особое колдунство для нечетного числа
byte[] secret_1 = new byte[(int)Math.Ceiling((double)secret.Length / 2)],
secret_2 = new byte[(int)Math.Ceiling((double)secret.Length / 2)];
Buffer.BlockCopy(secret, 0, secret_1, 0, secret_1.Length);
Buffer.BlockCopy(secret, secret.Length / 2, secret_2, 0, secret_2.Length);
byte[] A = new byte[label.Length + seed.Length];
Buffer.BlockCopy(label, 0, A, 0, label.Length);
Buffer.BlockCopy(seed, 0, A, label.Length, seed.Length);
byte[] tmp = new byte[md5_iterations * 16];
//A(1) ?
//A = P_MD5(secret_1, A);
for (int i = 0; i < md5_iterations; i++)
{
A = P_MD5(secret_1, A);
Buffer.BlockCopy(A, 0, tmp, i * A.Length, A.Length);
}
Buffer.BlockCopy(tmp, 0, md5_data, 0, md5_data.Length); //output_size = md5_data.Length
tmp = new byte[sha1_iterations * 20];
//does it have to start with A(1) ?
//A = P_SHA1(secret_2, A);
for (int i = 0; i < sha1_iterations; i++)
{
A = P_SHA1(secret_2, A);
Buffer.BlockCopy(A, 0, tmp, i * A.Length, A.Length);
}
Buffer.BlockCopy(tmp, 0, sha1_data, 0, sha1_data.Length); //output_size = sha1_data.Length
for (int i = 0; i < output_size; i++)
md5_data[i] = (byte)(md5_data[i] ^ sha1_data[i]);
return md5_data;
}
private byte[] P_MD5(byte[] secret /*это ключ?*/, byte[] seed /*это дата?*/)
{
HMACMD5 HMD5 = new HMACMD5(secret);
HMD5.ComputeHash(seed);
return HMD5.Hash;
}
private byte[] P_SHA1(byte[] secret /*это ключ?*/, byte[] seed /*это дата?*/)
{
HMACSHA1 HSHA1 = new HMACSHA1(secret);
HSHA1.ComputeHash(seed);
return HSHA1.Hash;
}
private byte[] MAC(byte[] secret, byte[] data)
{
byte[] secret_64 = new byte[64];
Buffer.BlockCopy(secret, 0, secret_64, 0, secret.Length);
for (int i = 0; i < 64; i++)
secret_64[i] = (byte)(secret_64[i] ^ (byte)54);
byte[] xor_output_data = new byte[64 + data.Length];
Buffer.BlockCopy(secret_64, 0, xor_output_data, 0, 64);
Buffer.BlockCopy(data, 0, xor_output_data, 64, data.Length);
SHA1 sha1 = SHA1.Create();
sha1.ComputeHash(xor_output_data);
secret_64 = new byte[64];
Buffer.BlockCopy(secret, 0, secret_64, 0, secret.Length);
for (int i = 0; i < 64; i++)
secret_64[i] = (byte)(secret_64[i] ^ (byte)92);
xor_output_data = new byte[64 + sha1.HashSize / 8];
Buffer.BlockCopy(secret_64, 0, xor_output_data, 0, 64);
Buffer.BlockCopy(sha1.Hash, 0, xor_output_data, 64, sha1.HashSize / 8);
sha1.ComputeHash(xor_output_data);
return sha1.Hash;
}
public void RC4(ref Byte[] bytes, Byte[] key)
{
Byte[] s = new Byte[128];
Byte[] k = new Byte[128];
Byte temp;
int i, j;
for (i = 0; i < 128; i++)
{
s[i] = (Byte)i;
k[i] = key[i % key.GetLength(0)];
}
j = 0;
for (i = 0; i < 128; i++)
{
j = (j + s[i] + k[i]) % 128;
temp = s[i];
s[i] = s[j];
s[j] = temp;
}
i = j = 0;
for (int x = 0; x < bytes.GetLength(0); x++)
{
i = (i + 1) % 128;
j = (j + s[i]) % 128;
temp = s[i];
s[i] = s[j];
s[j] = temp;
int t = (s[i] + s[j]) % 128;
bytes[x] ^= s[t];
}
}
Obviously, reading such a bunch of code ain't being the best way to spend your time, so I'd like to add some questions that, hopefully, can help a lot:
HMAC_MD5 and HMAC_SHA1 - in .Net implementation they take key and they take input byte[] to compute hash from. According to RFC4346:
First, we define a data expansion function, P_hash(secret, data)
which uses a single hash function to expand a secret and seed into an
arbitrary quantity of output:
P_hash(secret, seed) = HMAC_hash(secret, A(1) + seed) +
HMAC_hash(secret, A(2) + seed) +
HMAC_hash(secret, A(3) + seed) + ...
Where + indicates concatenation.
A() is defined as:
A(0) = seed
A(i) = HMAC_hash(secret, A(i-1))
What is seed? Is it data we compute hash from? Secret = key, so far I understand. Also, do we start P_hash with A(1)?
Thanks in advance!
Seed is Client_random + Server_random. You need to preserve them from preceding steps of the handshake, the client_hello and server_hello.
A(0) = seed
A(i) = HMAC_hash(secret,A(i-1)) for i>0
The output of the A() function consists of A(1), A(2), A(3)...

C++ to C# Reading Binary File into a two dimensional float array

I have been assigned to convert a C++ app to C#.
I want to convert the following code in C# where rate_buff is a double[3,9876] two dimensional array.
if ((fread((char*) rate_buff,
(size_t) record_size,
(size_t) record_count,
stream)) == (size_t) record_count)
If I correctly guessed your requirements, this is what you want:
int record_size = 9876;
int record_count = 3;
double[,] rate_buff = new double[record_count, record_size];
// open the file
using (Stream stream = File.OpenRead("some file path"))
{
// create byte buffer for stream reading that is record_size * sizeof(double) in bytes
byte[] buffer = new byte[record_size * sizeof(double)];
for (int i = 0; i < record_count; i++)
{
// read one record
if (stream.Read(buffer, 0, buffer.Length) != buffer.Length)
throw new InvalidDataException();
// copy the doubles out of the byte buffer into the two dimensional array
// note this assumes machine-endian byte order
for (int j = 0; j < record_size; j++)
rate_buff[i, j] = BitConverter.ToDouble(buffer, j * sizeof(double));
}
}
Or more concisely with a BinaryReader:
int record_size = 9876;
int record_count = 3;
double[,] rate_buff = new double[record_count, record_size];
// open the file
using (BinaryReader reader = new BinaryReader(File.OpenRead("some file path")))
{
for (int i = 0; i < record_count; i++)
{
// read the doubles out of the byte buffer into the two dimensional array
// note this assumes machine-endian byte order
for (int j = 0; j < record_size; j++)
rate_buff[i, j] = reader.ReadDouble();
}
}

How to fill a byte[] with 0xFF bytes?

This question is a follow-up of this Question
I have written a small method to fill a byte[] just like the MemoryStream :
public static Stream FillWithPadding(Stream MS, int Count)
{
byte[] buffer = new byte[64];
for (int i = 0; i < buffer.Length; i++)
{
buffer[i] = 0xFF;
}
while (Count > buffer.Length)
{
MS.Write(buffer, 0, buffer.Length);
Count -= buffer.Length;
}
MS.Write(buffer, 0, Count);
return MS;
}
public static byte[] FillWithPadding(byte[] Buffer, int Count)
{
using (MemoryStream MS = new MemoryStream())
{
MS.Write(Buffer, 0, Buffer.Length);
MemoryStream msw = FillWithPadding(MS, Count) as MemoryStream;
return msw.GetBuffer();
}
}
This code is not working!!
Instead it is creating 0xFF + 0x00 at the End!
Can anyone Please clear-up, Why this does not work??
MemoryStream.GetBuffer() returns internal byte array that MemoryStream uses to store data. Initially it filled with 0, and filled up to stream length by Write's.
Most likely you want to use MemoryStream.ToArray() instead that returns copy of the buffer truncated to actual length.
That's the position in the Stream Now.
use MS.Position = 0 before Write.
public static Stream FillWithPadding(Stream MS, int Count)
{
byte[] buffer = new byte[64];
for (int i = 0; i < buffer.Length; i++)
{
buffer[i] = 0xFF;
}
MS.Position = 0;
while (Count > buffer.Length)
{
MS.Write(buffer, 0, buffer.Length);
Count -= buffer.Length;
}
MS.Write(buffer, 0, Count);
return MS;
}

Categories

Resources