I am working on calculation of MD5, MD4, SHA1, SHA256, SHA512, RIPEMD160 etc. for selected file.
I have created the following algorithm but it has problem.
string finalHash;
byte[] buffer;
byte[] oldBuffer;
int bytesRead;
int oldBytesRead;
long streamSize;
long totalBytesRead = 0;
try
{
if (!String.IsNullOrEmpty(selectedFile))
{
_dataStream = File.OpenRead(selectedFile);
selectedFile = string.Empty;
}
foreach (var hashObject in from Control ctrl in Controls where ctrl is CheckBox && ((CheckBox)ctrl).Checked select HashObject)
{
//totalBytesRead = 0;
streamSize = _dataStream.Length;
buffer = new byte[4096];
bytesRead = _dataStream.Read(buffer, 0, buffer.Length);
totalBytesRead += bytesRead;
do
{
oldBytesRead = bytesRead;
oldBuffer = buffer;
buffer = new byte[4096];
bytesRead = _dataStream.Read(buffer, 0, buffer.Length);
totalBytesRead += bytesRead;
if (bytesRead == 0)
{
hashObject.TransformFinalBlock(oldBuffer, 0, oldBytesRead);
}
else
{
hashObject.TransformBlock(oldBuffer, 0, oldBytesRead, oldBuffer, 0);
}
hashCalculationWorker.ReportProgress((int)((double)totalBytesRead * 100 / streamSize));
} while (bytesRead != 0);
e.Result = hashObject.Hash;
finalHash = GenerateHex(hashObject.Hash);
Invoke(new MethodInvoker(() =>
{
// Get finalHash
}));
hashObject.Dispose();
}
}
catch (Exception)
{
}
private HashAlgorithm HashObject
{
get
{
if (isMD5Selected)
{
_hashObject = MD5.Create();
isMD5Selected = false;
}
else if (isMD4Selected)
{
_hashObject = MD4.Create();
isMD4Selected = false;
}
else if (isSHA1Selected)
{
_hashObject = SHA1.Create();
isSHA1Selected = false;
}
...
return _hashObject;
}
}
In the above code, foreach statement depends on number of selected hash algorithms. It calculates first selected hash correctly but on the second and other every next iteration it gives wrong values.
Whats wrong. Can anybody help me?
Thanks a lot in advance.
You are not resetting the stream so that you can re-read its contents for each iteration through the loop. Your buffer management logic can be simplified quite a bit, and it would be desireable to call hashObject.Dispose in a finally block so resources are released in case an exception is thrown.
streamSize = _dataStream.Length;
buffer = new byte[4096];
foreach (var hashObject in from Control ctrl in Controls where ctrl is CheckBox && ((CheckBox)ctrl).Checked select HashObject)
{
try
{
// reset stream position, progress
_dataStream.Position = 0;
_totalBytesRead = 0;
do
{
bytesRead = _dataStream.Read(buffer, 0, buffer.Length);
totalBytesRead += bytesRead;
if (_dataStream.Position == _dataStream.Length)
{
hashObject.TransformFinalBlock(buffer, 0, bytesRead);
}
else
{
hashObject.TransformBlock(buffer, 0, bytesRead, buffer, 0);
}
hashCalculationWorker.ReportProgress((int)((double)totalBytesRead * 100 / streamSize));
} while (_dataStream.Position < _dataStream.Length);
e.Result = hashObject.Hash;
finalHash = GenerateHex(hashObject.Hash);
Invoke(new MethodInvoker(() =>
{
// Get finalHash
}));
}
finally
{
hashObject.Dispose();
}
}
Better solution if the files are not large:
It may be more performant to read all of the data from the stream into a buffer once, and then re-use it:
if (!String.IsNullOrEmpty(selectedFile))
{
buffer = File.ReadAllBytes(selectedFile);
streamSize = buffer.Length;
selectedFile = string.Empty;
}
foreach (var hashObject in from Control ctrl in Controls where ctrl is CheckBox && ((CheckBox)ctrl).Checked select HashObject)
{
int offset = 0;
while (buffer.Length - offset >= streamSize)
{
offset += hashObject.TransformBlock(buffer, offset, streamSize, buffer, offset);
hashCalculationWorker.ReportProgress((int)((double)offset * 100 / streamSize));
}
hashObject.TransformFinalBlock(buffer, offset, buffer.Length - offset);
hashCalculationWorker.ReportProgress(100);
e.Result = hashObject.Hash;
finalHash = GenerateHex(hashObject.Hash);
Invoke(new MethodInvoker(() =>
{
// Get finalHash
}));
hashObject.Dispose();
}
Related
I have found the answer for Java: https://stackoverflow.com/a/36357819/202179 and tried to port it to Xamarin.
Here is the code that I've made:
const string COMPRESSED_AUDIO_FILE_MIME_TYPE = "audio/mp4a-latm";
const int COMPRESSED_AUDIO_FILE_BIT_RATE = 64000; // 64kbps
const int SAMPLING_RATE = 48000;
const int BUFFER_SIZE = 48000;
const int CODEC_TIMEOUT_IN_MS = 5000;
void Compress()
{
var inputFile = new Java.IO.File(tempFileWavPath);
var fis = new Java.IO.FileInputStream(inputFile);
var outputFile = new Java.IO.File(fileM4APath);
if (outputFile.Exists())
outputFile.Delete();
var mux = new MediaMuxer(outputFile.AbsolutePath, MuxerOutputType.Mpeg4);
MediaFormat outputFormat = MediaFormat.CreateAudioFormat(COMPRESSED_AUDIO_FILE_MIME_TYPE, SAMPLING_RATE, 1);
outputFormat.SetInteger(MediaFormat.KeyAacProfile, (int)MediaCodecProfileType.Aacobjectlc);
outputFormat.SetInteger(MediaFormat.KeyBitRate, COMPRESSED_AUDIO_FILE_BIT_RATE);
outputFormat.SetInteger(MediaFormat.KeyMaxInputSize, 16384);
MediaCodec codec = MediaCodec.CreateEncoderByType(COMPRESSED_AUDIO_FILE_MIME_TYPE);
codec.Configure(outputFormat, null, null, MediaCodecConfigFlags.Encode);
codec.Start();
MediaCodec.BufferInfo outBuffInfo = new MediaCodec.BufferInfo();
byte[] tempBuffer = new byte[BUFFER_SIZE];
var hasMoreData = true;
double presentationTimeUs = 0;
int audioTrackIdx = 0;
int totalBytesRead = 0;
int percentComplete = 0;
do
{
int inputBufIndex = 0;
while (inputBufIndex != -1 && hasMoreData)
{
inputBufIndex = codec.DequeueInputBuffer(CODEC_TIMEOUT_IN_MS);
if (inputBufIndex >= 0)
{
var dstBuf = codec.GetInputBuffer(inputBufIndex);
dstBuf.Clear();
int bytesRead = fis.Read(tempBuffer, 0, dstBuf.Limit());
if (bytesRead == -1)
{ // -1 implies EOS
hasMoreData = false;
codec.QueueInputBuffer(inputBufIndex, 0, 0, (long)presentationTimeUs, MediaCodecBufferFlags.EndOfStream);
}
else
{
totalBytesRead += bytesRead;
dstBuf.Put(tempBuffer, 0, bytesRead);
codec.QueueInputBuffer(inputBufIndex, 0, bytesRead, (long)presentationTimeUs, 0);
presentationTimeUs = 1000000l * (totalBytesRead / 2) / SAMPLING_RATE;
}
}
}
// Drain audio
int outputBufIndex = 0;
while (outputBufIndex != (int)MediaCodecInfoState.TryAgainLater)
{
outputBufIndex = codec.DequeueOutputBuffer(outBuffInfo, CODEC_TIMEOUT_IN_MS);
if (outputBufIndex >= 0)
{
var encodedData = codec.GetOutputBuffer(outputBufIndex);
encodedData.Position(outBuffInfo.Offset);
encodedData.Limit(outBuffInfo.Offset + outBuffInfo.Size);
if ((outBuffInfo.Flags & MediaCodecBufferFlags.CodecConfig) != 0 && outBuffInfo.Size != 0)
{
codec.ReleaseOutputBuffer(outputBufIndex, false);
}
else
{
mux.WriteSampleData(audioTrackIdx, encodedData, outBuffInfo);
codec.ReleaseOutputBuffer(outputBufIndex, false);
}
}
else if (outputBufIndex == (int)MediaCodecInfoState.OutputFormatChanged)
{
outputFormat = codec.OutputFormat;
audioTrackIdx = mux.AddTrack(outputFormat);
mux.Start();
}
}
percentComplete = (int)Math.Round(((float)totalBytesRead / (float)inputFile.Length()) * 100.0);
} while (outBuffInfo.Flags != MediaCodecBufferFlags.EndOfStream);
fis.Close();
mux.Stop();
mux.Release();
}
This almost works as it converts the file, but the resulting file appears to be encoded too fast - the pitch is too high and speed is too high and the reproduction lasts shorter than expected.
It is likely that just some slight change is needed, but I am not sure what. Can anyone suggest?
I could reproduce the resulting file appears to be encoded too fast when i use the different size of SAMPLING_RATE.
For example, i download a wav file online. The Sampline Rate is 11025. If i use the original rate 48000 in the code, it would play too fast. When i use 11025, it would work.
So we need to know the Sampling Rate of the wav fille and then set it in the code.
const int SAMPLING_RATE = 11025;//44100, 48000
I'm sending byte of 8254789 bytes. It is undergoing the loop but when it reaches the at 8246597 and has to read 8192 bytes. It is going out from while loop to nowhere. Can someone explain please, what is the problem?
public static byte[] ReadFully(Stream stream, int initialLength)
{
// If we've been passed an unhelpful initial length, justS
// use 32K.
if (initialLength < 1)
{
initialLength = 32768;
}
byte[] buffer = new byte[3824726];
int read = 0;
int chunk;
try
{
while ((chunk = stream.Read(buffer, read, 3824726 - read)) > 0)
{
Console.WriteLine("Length of chunk" + chunk);
read += chunk;
Console.WriteLine("Length of read" + read);
if (read == 0)
{
stream.Close();
return buffer;
}
// If we've reached the end of our buffer, check to see if there's
// any more information
if (read == buffer.Length)
{
Console.WriteLine("Length of Buffer" + buffer.Length);
int nextByte = stream.ReadByte();
// End of stream? If so, we're done
if (nextByte == -1)
{
return buffer;
}
// Nope. Resize the buffer, put in the byte we've just
// read, and continue
byte[] newBuffer = new byte[buffer.Length * 2];
Console.WriteLine("Length of newBuffer" + newBuffer.Length);
Array.Copy(buffer, newBuffer, buffer.Length);
newBuffer[read] = (byte)nextByte;
buffer = newBuffer;
read++;
}
}
// Buffer is now too big. Shrink it.
byte[] ret = new byte[read];
Array.Copy(buffer, ret, read);
return ret;
}
catch (Exception ex)
{ throw ex; }
}
Normally you don't write your stream loops like that. Instead try something like this:
byte[] buffer = new byte[BUFFER_SIZE];
int read = -1;
while((read = stream.Read(buffer, 0, buffer.Length)) > 0)
{
// ... use read bytes in buffer here
}
You're attempting to adjust your offset each time, but you don't need to because use cursors - so you're basically skipping ahead.
In the below code state is an object which has a property msgLength which is the total message length.The msgLength is the first four bytes of the message.
I am getting unexpected results in the state.msgLength propery when more than one message is received in "quick" succesion.When the state.msglength is not as expected
I get an error trying to receive. Specified argument was out of the range of valid values.
StateObj state = (StateObj)ar.AsyncState;
try
{
state.read += state.socket.EndReceive(ar);
if (state.read == 0)
{
state.socket.Close();
state.socket.Dispose();
state.socket = null;
this.Invoke((MethodInvoker)delegate { listBox1.Items.Add(DateTime.Now.ToString("HH:mm ss") + " socket closed"); });
return;
}
}
catch (Exception)
{
this.Invoke((MethodInvoker)delegate { listBox1.Items.Add(DateTime.Now.ToString("HH:mm ss") + " socket closed"); });
return;
}
if (state.read < 4)
{
//read again you dont have state,msglength
state.socket.BeginReceive(state.dataBuffer, state.read, 4 - state.read, 0, cbReceive, state);
}
else
{
state.msglength = BitConverter.ToInt32(state.dataBuffer, 0);
}
if (state.read < state.msglength)
{
//read again you dont have the complete message
//here is the error Specified argument was out of the range of valid values.
state.socket.BeginReceive(state.dataBuffer, state.read, state.msglength - state.read, 0, cbReceive, state);
}
else
{
//process here
if (state.read > state.msglength )
{
state.read = state.read - state.msglength;
}
else
{
state.read = 0;
}
state.socket.BeginReceive(state.dataBuffer, 0, state.dataBuffer.Length, 0, cbReceive, state);
}
I think that state.socket.BeginReceive is executed twice.
Because when it is reading it's header, both if (state.read < 4) and if (state.read < state.msglength) are true. Return after the first state.socket.BeginReceive(.. could solve the issue.
if (state.read < 4)
{
//read again you dont have state,msglength
state.socket.BeginReceive(state.dataBuffer, state.read, 4 - state.read, 0, cbReceive, state);
return; // <------
}
else
{
state.msglength = BitConverter.ToInt32(state.dataBuffer, 0);
}
if (state.read < state.msglength)
{
//read again you dont have the complete message
//here is the error Specified argument was out of the range of valid values.
state.socket.BeginReceive(state.dataBuffer, state.read, state.msglength - state.read, 0, cbReceive, state);
}
else
{
state.read = 0;
//process correctly expected message
}
I think I found another issue, If the messageLength specified within the message is only the size of the data. You should read if (state.read < state.msglength+4) Because the length header is included in your buffer.
I mostly split-up reading header/data. Like: (PSEUDO)
byte[] header;
byte[] buffer;
int bytesRead;
public void ReadHeader()
{
bytesNeeded = 4;
bytesRead = 0;
BeginReadHeader();
}
public void BeginReadHeader()
{
BeginReceive(header, bytesRead, bytesNeeded-bytesRead, EndReadHeader);
}
public void EndReadHeader()
{
int read = EndReceive();
if(read == 0)
{
CloseSocket();
return;
}
bytesRead += read;
if(bytesRead == byteNeeded)
ReadData();
else
BeginReadHeader();
}
public void ReadData()
{
bytesNeeded = BitConverter.ToInt32(header, 0);
bytesRead = 0;
if(buffer.Length < bytesNeeded)
buffer = new byte[bytesNeeded];
BeginReadData();
}
public void BeginReadData()
{
BeginReceive(buffer, bytesRead, bytesNeeded-bytesRead, EndReadData);
}
public void EndReadData()
{
int read = EndReceive();
if(read == 0)
{
CloseSocket();
}
bytesRead += read;
if(bytesRead == byteNeeded)
{
HandleData();
}
else
BeginReadData();
}
public void HandleData()
{
// handle data in buffer. BinaryReader
ReadHeader();
}
I made a client & server that establishes a TCP connection through sockets, I'm trying to send binary data over the socket but I could only send txt or pdf files, I had no luck with exe files, I use fread and fseek to read the file and split it into a buffer. When I read the whole exe file it gets sent successfully but when I split it, it gets sent corrupted!
I read some books about sockets but I still don't know much and I have some questions.
is it okay to send the whole file in one send()?? or I should continue with sending it in small chunks?
Also, why exe files get corrupted when I send them in chunks?
Thank you!
Client Code (in c):
int bufSize = 10000;
int sentBytes = 0;
FILE * pFile;
long remainingBytes;
char * buffer;
size_t result;
pFile = fopen ( "D:\\file.exe" , "rb" );
fseek (pFile , 0 , SEEK_END);
remainingBytes = ftell (pFile);
rewind (pFile);
int bufferSize = remainingBytes > bufSize ? bufSize : remainingBytes;
buffer = (char*) malloc (sizeof(char)*bufferSize);
send(Socket, (char*)&remainingBytes, 4, 0);
while(remainingBytes > 0)
{
fseek (pFile , sentBytes , SEEK_SET);
result = fread(buffer,1,bufferSize,pFile);
if(bufferSize < remainingBytes)
{
send(Socket, buffer, bufferSize, 0);
}
else
{
send(Socket, buffer, remainingBytes, 0);
bufferSize = remainingBytes;
}
remainingBytes -= bufferSize;
sentBytes += bufferSize;
}
Server code (in c#)
try
{
int bufferSize = 200;
int len = 0;
int receivedBytes = 0;
int remainingBytes = len;
byte[] length = new byte[4];
//byte[] imgBuf = new byte[bufferSize];
int current = 0;
List<byte[]> coming = new List<byte[]>();
sockets[number].Receive(length,4,0);
len = BitConverter.ToInt32(length, 0);
remainingBytes = len;
bufferSize = len < bufferSize ? len : bufferSize;
while(receivedBytes < len)
{
if (remainingBytes > bufferSize)
{
coming.Add(new byte[bufferSize]);
//imgBuf = new byte[bufferSize];
sockets[number].Receive(coming[current], bufferSize, 0);
}
else
{
coming.Add(new byte[remainingBytes]);
//imgBuf = new byte[remainingBytes];
sockets[number].Receive(coming[current], remainingBytes, 0);
bufferSize = remainingBytes;
}
remainingBytes -= bufferSize;
receivedBytes += bufferSize;
current++;
//Array.Clear(imgBuf, 0, imgBuf.Length);
}
using (var stream = new FileStream(#"C:\receivedFile.exe",FileMode.Create))
{
using (var binaryWriter = new BinaryWriter(stream))
{
foreach (byte[] buffer in coming)
{
binaryWriter.Write(buffer);
}
}
}
}
catch (Exception ex)
{ this.setText(ex.Message, textBox2); }
Edit: Thanks for the help, I got it working :)
try
{
int bufferSize = 1024 * 100;
int len = 0;
int receivedBytes = 0;
int remainingBytes = len;
int reached = 0;
byte[] length = new byte[4];
byte[] imgBuf = new byte[bufferSize];
int current = 0;
sockets[number].Receive(length,4,0);
len = BitConverter.ToInt32(length, 0);
remainingBytes = len;
bufferSize = len < bufferSize ? len : bufferSize;
imgBuf = new byte[len];
while (reached < len)
{
reached += sockets[number].Receive(imgBuf, receivedBytes, remainingBytes, 0);
remainingBytes = len - reached;
receivedBytes = reached;
current++;
//Array.Clear(imgBuf, 0, imgBuf.Length);
}
using (var stream = new FileStream(#"C:\putty.exe",FileMode.Create))
{
using (var binaryWriter = new BinaryWriter(stream))
{
binaryWriter.Write(imgBuf);
}
}
Array.Clear(imgBuf, 0, imgBuf.Length);
}
catch (Exception ex)
{ this.setText(ex.Message, textBox2); }
You don't check how many bytes you actually received in sockets[number].Receive(coming[current], bufferSize, 0); . It doesn't have to be equal to the buffer size you have declared.
Additionaly, as said in comments, keeping whole file in memory is not a good idea.
In addition to checking the number of bytes received, you need to check the number of bytes sent by each send call -- if your TCP transmit window fills up, a send call might send less data than you requested, in which case the you'll need to resend the unsent data.
In general, you ALWAYS need to check the return value of your system calls to check for the all the various odd corner cases that can occur. Read the man pages for send(2) and recv(2) for a full list of everything that can happen.
I'm making a simple file transfer sender and receiver app through the wire. What I have so far is that the sender converts the file into a byte array and sends chunks of that array to the receiver.
This works with file of up to 256mb, but this line throws a "System out of memory" exception for anything above:
byte[] buffer = StreamFile(fileName); //This is where I convert the file
I'm looking for a way to read the file in chunks then write that chunk instead of loading the whole file into a byte. How can I do this with a FileStream?
EDIT:
Sorry, heres my crappy code so far:
private void btnSend(object sender, EventArgs e)
{
Socket clientSock = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
byte[] fileName = Encoding.UTF8.GetBytes(fName); //file name
byte[] fileData = null;
try
{
fileData = StreamFile(textBox1.Text); //file
}
catch (OutOfMemoryException ex)
{
MessageBox.Show("Out of memory");
return;
}
byte[] fileNameLen = BitConverter.GetBytes(fileName.Length); //length of file name
clientData = new byte[4 + fileName.Length + fileData.Length];
fileNameLen.CopyTo(clientData, 0);
fileName.CopyTo(clientData, 4);
fileData.CopyTo(clientData, 4 + fileName.Length);
clientSock.Connect("172.16.12.91", 9050);
clientSock.Send(clientData, 0, 4 + fileName.Length, SocketFlags.None);
for (int i = 4 + fileName.Length; i < clientData.Length; i++)
{
clientSock.Send(clientData, i, 1 , SocketFlags.None);
}
clientSock.Close();
}
And here's how I receive (the code was from a tutorial)
public void ReadCallback(IAsyncResult ar)
{
int fileNameLen = 1;
String content = String.Empty;
StateObject state = (StateObject)ar.AsyncState;
Socket handler = state.workSocket;
int bytesRead = handler.EndReceive(ar);
if (bytesRead > 0)
{
if (flag == 0)
{
Thread.Sleep(1000);
fileNameLen = BitConverter.ToInt32(state.buffer, 0);
string fileName = Encoding.UTF8.GetString(state.buffer, 4, fileNameLen);
receivedPath = fileName;
flag++;
}
if (flag >= 1)
{
BinaryWriter writer = new BinaryWriter(File.Open(receivedPath, FileMode.Append));
if (flag == 1)
{
writer.Write(state.buffer, 4 + fileNameLen, bytesRead - (4 + fileNameLen));
flag++;
}
else
writer.Write(state.buffer, 0, bytesRead);
writer.Close();
handler.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0,
new AsyncCallback(ReadCallback), state);
}
}
else
{
Invoke(new MyDelegate(LabelWriter));
}
}
I just really want to know how I can read the file in chunks so that I dont need to convert it to a byte.
Thanks for the responses so far, I think I'm starting to get it :D
Just call Read repeatedly with a small buffer (I tend to use something like 16K). Note that the call to Read may end up reading a smaller amount than you request. If you're using a fixed chunk size and need the whole chunk in memory, you could just use an array of that size of course.
Without knowing how you're sending the file, it's hard to give much advice about how to structure your code, but it could be something like this:
byte[] chunk = new byte[MaxChunkSize];
while (true)
{
int index = 0;
// There are various different ways of structuring this bit of code.
// Fundamentally we're trying to keep reading in to our chunk until
// either we reach the end of the stream, or we've read everything we need.
while (index < chunk.Length)
{
int bytesRead = stream.Read(chunk, index, chunk.Length - index);
if (bytesRead == 0)
{
break;
}
index += bytesRead;
}
if (index != 0) // Our previous chunk may have been the last one
{
SendChunk(chunk, index); // index is the number of bytes in the chunk
}
if (index != chunk.Length) // We didn't read a full chunk: we're done
{
return;
}
}
If I was more awake I'd probably find a more readable way of writing this, but it'll do for now. One option is to extract another method from the middle section:
// Attempts to read an entire chunk into the given array; returns the size of
// chunk actually read.
int ReadChunk(Stream stream, byte[] chunk)
{
int index = 0;
while (index < chunk.Length)
{
int bytesRead = stream.Read(chunk, index, chunk.Length - index);
if (bytesRead == 0)
{
break;
}
index += bytesRead;
}
return index;
}
var b = new byte[1<<15]; // 32k
while((count = inStream.Read(b, 0, b.Length)) > 0)
{
outStream.Write(b, 0, count);
}
public static IEnumerable<byte[]> SplitStreamIntoChunks(Stream stream, int chunkSize)
{
var bytesRemaining = stream.Length;
while (bytesRemaining > 0)
{
var size = Math.Min((int) bytesRemaining, chunkSize);
var buffer = new byte[size];
var bytesRead = stream.Read(buffer, 0, size);
if (bytesRead <= 0)
break;
yield return buffer;
bytesRemaining -= bytesRead;
}
}