There are two programs involved. The first one has a string like "##########". The second one is a config tool to find "##########" and replace this string with user input from a textbox.
Now I have trouble in the replacing part. Here is the code.
//This is code from first program:
string myIP = "####################";
string myPort = "%%%%%%%%";
int port = Int32.Parse(myIP );
tcpClient.Connect(myIP , port);
//This is code from second program:
//Get bytes from textbox:
byte[] byte_IP = new byte[60];
byte_IP = System.Text.Encoding.ASCII.GetBytes(textBox1_ip.Text);
//Get all bytes in the first program:
byte[] buffer = File.ReadAllBytes(#"before.exe");
//Replace string with textbox input, 0x1c00 is where the "#" starts:
Buffer.BlockCopy( byte_IP, 0, buffer, 0x1c00, byte_IP.Length);
//Build a new exe:
File.WriteAllBytes(#"after.exe", buffer);
However, I get "127.0.0.1#.#.#.#.#.#." in the new exe. But I need "1.2.7...0...0...1........." to process as a valid host.
First I'd like to reiterate what has already been said in the comments: there are simpler ways to handle this stuff. That's what config files are for, or registry settings.
But if you absolutely must...
First, you have to match the encoding that the framework expects. Is the string stored as UTF8? UTF16? ASCII? Writing data in the wrong encoding will turn it into pure garbage, almost every time. Generally for strings in code like you're looking for you'll be wanting to use Encoding.UNICODE.
Next, you need some way to deal with strings of different lengths. The buffer you define needs to be large enough to contain the widest string you want to be able to set - 15 bytes for dotted numeric IPv4 addresses - but you have to allow for the minimum of 7 characters. Padding the remainder and removing that padding before using the value will probably suffice.
The minimum program I could think to use for testing this was:
class Program
{
static void Main(string[] args)
{
var addr = "###.###.###.###".TrimEnd();
Console.WriteLine("Address: [{0}]", addr);
}
}
Now in your patcher you will need to locate the starting position in the file and overwrite the bytes with the new string's bytes. Here's a Patch method, which calls a FindString method that you will have to write yourself:
static void PatchFile(string filename, string searchString, string replaceString)
{
// Open the file
using (var file = File.Open(filename, FileMode.Open, FileAccess.ReadWrite, FileShare.ReadWrite))
{
// Locate the search string in the file (needs to be implemented)
long pos = FindString(file, searchString);
if (pos < 0)
return;
// Pad and limit replacement string, then convert to bytes
string rep = string.Format("{0,-" + searchString.Length + "}", replaceString).Substring(0, searchString.Length);
byte[] replaceBytes = Encoding.Unicode.GetBytes(rep);
// Overwrite the located bytes with the replacement
file.Position = pos;
file.Write(replaceBytes, 0, replaceBytes.Length);
}
}
Hopefully it makes sense.
Related
Im currently trying to add additional bytes to a byte array.
Im trying to send a header to a server that contains the computer name. However because the computer name could change for every machine im trying to create a byte array that is a specific length like 100 bytes.
Which means once i have my string header "rdmstream§" + Dns.GetHostName()" I need to add x amounts of bytes at the end or start as padding so the overall byte length = 100.
I was wondering if this was possible?
Below is an example of my code for having a set header length:
public static void SendMultiScreen(byte[] img)
{
try
{
//string command = ("rdmstream§" + Dns.GetHostName()); //This is what I want to add.
byte[] send = new byte[img.Length + 16]; //Create a new buffer to send to the server
byte[] header = Encoding.Unicode.GetBytes("rdmstrea"); //Get the bytes of the header
Buffer.BlockCopy(header, 0, send, 0, header.Length); //Copy the header to the main buffer
fps = 800;
Buffer.BlockCopy(img, 0, send, header.Length, img.Length); //Copy the image to the main buffer
_clientSocket.Send(send, 0, send.Length, SocketFlags.None); //Send the image to the server
}
As you can see as long as the message is only 8 Characters long this works fine. However I want the characters in the message to be variable.
I don't have much knowledge on bytes if im honest so any additional help would be much appreciated.
Thankyou in advance.
One can argue about it if padding is the right way to go, but you could pad the name of your host
string hostName = "OhWhatEver".PadRight(100)
then use this as input for your GetBytes call.
Edit:
If you can't live with the spaces use that:
byte[] header = new byte[100];
byte[] hostname = System.Text.Encoding.Unicode.GetBytes("rdmstream§" + System.Net.Dns.GetHostName());
Array.Copy(hostname, header, hostname.Length);
If your concern is packet fragmentation: Socket has overloads to send a list of buffer segments in a single operation. That means you can do something like:
var segments = new List<ArraySegment<byte>>();
segments.Add(header);
segments.Add(img);
Note that it is not necessary for the header to be the full array; you can send a part of an array, which allows you to re-use the same buffer; for example:
byte[] buffer = new byte[MaxLength];
var segments = new List<ArraySegment<byte>>();
segments.Add(default); // placeholder
segments.Add(img);
foreach(...) {
string val = ...
int len = encoding.GetBytes(val, 0, val.Length, buffer, 0);
segments[0] = new ArraySegment<byte>(buffer, 0, len);
thisSocket.Send(segments);
}
However! to do this usually requires some kind of framing on the header - either a sentinel value (perhaps a trailing CR/LF/CRLF), or a prefix of the number of bytes that are the string - len here.
If that really isn't possible... just loop over the unused part of the array and set it to what you want, or use Array.Clear if zero is OK.
i searched in stackoverflow and got one way but this method only let me to write word by word in the console. My goal is to get the end of my file but get the complete result not char by char.
This code only show me char by char the end of my file:
using (var reader = new StreamReader("file.dll")
{
if (reader.BaseStream.Length > 1024)
{
reader.BaseStream.Seek(-1024, SeekOrigin.End);
}
string line;
while ((line = reader.ReadLine()) != null)
{
Console.WriteLine(line);
Console.ReadKey();
}
}
I was trying to get something like this, it's c++ but i was trying to get the same result in c#.
QFile *archivo;
archivo = new QFile();
archivo->setFileName("file.dll");
archivo->open(QFile::ReadOnly);
archivo->seek(archivo->size() - 1024);
trama = archivo->read(1024);
It's possible to get the complete result of the end of my file in c#?
If the file is line-delimited text file, you can use ReadAllLines.
string[] lines = System.IO.File.ReadAllLines("file.txt");
If it's a binary file, you can use ReadAllBytes. Shocker, I know.
byte[] data = System.IO.File.ReadAllBytes("file.dll");
if you want to be able to seek first (e.g. if you want only the last 1024 bytes of the file) you can use the stream's Read method. Again, crazy.
reader.BaseStream.Seek(-1024, SeekOrigin.End);
var chars = new char[1024];
reader.Read(chars, 0, 1024);
And before you ask, you can convert the characters to a string by passing them to the constructor:
char[] chars = new char[1024];
string s = new string(chars);
Console.WriteLine(s);
Not sure what it'll look like, since you're reading characters from a binary file, but good luck. My guess is you should be reading bytes instead though:
reader.BaseStream.Seek(-1024, SeekOrigin.End);
var bytes = new byte[1024];
reader.BaseStream.Read(bytes, 0, 1024);
(Notice you don't even need the StreamReader, since the FileStream (your base stream) exposes the Read method you need).
Ack. I am trying to open a specific entry in a zip file archive and store the contents in a string, instead of saving it to a file. I cannot use disk space for this per the client.
Here's what I have:
string scontents = "";
byte[] abbuffer = null;
MemoryStream oms = new MemoryStream();
try
{
//get the file contents
ozipentry.Open().CopyTo(oms);
int length = (int)oms.Length; // get file length
abbuffer = new byte[length]; // create buffer
int icount; // actual number of bytes read
int isum = 0; // total number of bytes read
// read until Read method returns 0 (end of the stream has been reached)
while ((icount = oms.Read(abbuffer, isum, length - isum)) > 0)
{
isum += icount; // sum is a buffer offset for next reading
}
scontents = BytesToString(abbuffer); <----abbuffer is filled with Ascii 0
}
finally
{
oms.Close();
}
The variable abbuffer is supposed to hold that contents of the stream, but all it holds is a bunch of ascii zeros, which I guess means it didn't read (or copy) the stream! But I do not get any error messages or anything. Can someone tell me how to get this working?
I've looked everywhere on stack and on the web, and no where does anyone answer this question specifically for ASP.NET 4.5 ZipArchive library. I cannot use any other library, so if you offer an answer in that, while it would be educational, won't help me at all in this instance. Thanks so much for any help!
One more thing. 'ozipentry' is of type ZipArchiveEntry and is an element in a ZipArchive Entries array. (ie ozipentry = oziparchive.Entries[i])
Oops. One more thing! The function 'BytesToString' is not included, because it is irrelevant. Before the function is called, the abbuffer array is already filled with 0's
Ok. Sorry for being so dense. I realized I was overthinking this. I changed to function to do this:
osr = new StreamReader(ozipentry.Open(), Encoding.Default);
scontents = osr.ReadToEnd();
And it worked fine! Didn't even have to worry about Encoding...
I am trying to read an email from POP3 and change to the correct encoding when I find the charset in the headers.
I use a TCP Client to connect to the POP3 server.
Below is my code :
public string ReadToEnd(POP3Client pop3client, out System.Text.Encoding messageEncoding)
{
messageEncoding = TCPStream.CurrentEncoding;
if (EOF)
return ("");
System.Text.StringBuilder sb = new System.Text.StringBuilder(m_bytetotal * 2);
string st = "";
string tmp;
do
{
tmp = TCPStream.ReadLine();
if (tmp == ".")
EOF = true;
else
sb.Append(tmp + "\r\n");
//st += tmp + "\r\n";
m_byteread += tmp.Length + 2; // CRLF discarded by read
FireReceived();
if (tmp.ToLower().Contains("content-type:") && tmp.ToLower().Contains("charset="))
{
try
{
string charSetFound = tmp.Substring(tmp.IndexOf("charset=") + "charset=".Length).Replace("\"", "").Replace(";", "");
var realEnc = System.Text.Encoding.GetEncoding(charSetFound);
if (realEnc != TCPStream.CurrentEncoding)
{
TCPStream = new StreamReader(pop3client.m_tcpClient.GetStream(), realEnc);
}
}
catch { }
}
} while (!EOF);
messageEncoding = TCPStream.CurrentEncoding;
return (sb.ToString());
}
If I remove this line:
TCPStream = new StreamReader(pop3client.m_tcpClient.GetStream(), realEnc);
Everything works fine except that when the e-mail contains different charset characters I get question marks as the initial encoding is ASCII.
Any suggestions on how to change the encoding while reading data from the Network Stream?
You're doing it wrong (tm).
Seriously, though, you are going about trying to solve this problem in completely the wrong way. Don't use a StreamReader for this. And especially don't read 1 byte at a time (as you said you needed to do in a comment on an earlier "solution").
For an explanation of why not to use a StreamReader, besides the obvious "because it isn't designed to switch between encodings during the process of reading", feel free to read over another answer I gave about the inefficiencies of using a StreamReader here: Reading an mbox file in C#
What you need to do is buffer your reads (such as a 4k buffer should be fine). Then, as you are already having to do anyway, scan for the '\n' byte to extract content on a line-by-line basis, combining header lines that were folded.
Each header may have multiple encoded-word tokens which may each be in a separate charset, assuming they are properly encoded, otherwise you'll have to deal with undeclared 8-bit data and try to massage that into unicode somehow (probably by having a set of fallback charsets). I'd recommend trying UTF-8 first followed by a selection of charsets that the user of your library has provided before finally trying iso-8859-1 (make sure not to try iso-8859-1 until you've tried everything else, because any sequence of 8-bit text will convert properly to unicode using the iso-8859-1 character encoding).
When you get to text content of the message, you'll want to check the Content-Type header for a charset parameter. If no charset parameter is defined, it should be US-ASCII, but in practice it could be anything. Even if the charset is defined, it might not match the actual character encoding used in the text body of the message, so once again you'll probably want to have a set of fallbacks.
As you've probably guessed by this point, this is very clearly not a trivial task as it requires the parser to do on-the-fly character conversion as it goes (and the character conversion requires internal parser state about what the expected charset is at any given time).
Since I've already done the work, you should really consider using MimeKit which will parse the email and properly do charset conversion on the headers and the content using the appropriate charset encoding.
I've also written a Pop3Client class that is included in my MailKit library.
If your goal is to learn and write your own library, I'd still highly recommend reading over my code because it is highly efficient and does things in a proper way.
There are some ways you can detect the encoding by looking at the Byte Order Mark, which are the firts few bytes of the stream. These will tell you the encoding. However, the stream might not have a BOM, and in these cases it could be ASCII, UTF without BOM, or others.
You can convert your stream from one encoding to another with the Encoding Class:
Encoding textEncoding = Encoding.[your detected encoding here];
byte[] converted = Encoding.UTF8.GetBytes(textEncoding.GetString(TCPStream.GetBuffer()));
You may select your preferred encoding when converting.
Hope it answers your question.
edit
You may use this code to read your stream in blocks.
MemoryStream st = new MemoryStream();
int numOfBytes = 1024;
int reads = 1;
while (reads > 0)
{
byte[] bytes = new byte[numOfBytes];
reads = yourStream.Read(bytes, 0, numOfBytes);
if (reads > 0)
{
int writes = ( reads < numOfBytes ? reads : numOfBytes);
st.Write(bytes, 0, writes);
}
}
Is there a way to know how many bytes of a stream have been used by StreamReader?
I have a project where we need to read a file that has a text header followed by the start of the binary data. My initial attempt to read this file was something like this:
private int _dataOffset;
void ReadHeader(string path)
{
using (FileStream stream = File.OpenRead(path))
{
StreamReader textReader = new StreamReader(stream);
do
{
string line = textReader.ReadLine();
handleHeaderLine(line);
} while(line != "DATA") // Yes, they used "DATA" to mark the end of the header
_dataOffset = stream.Position;
}
}
private byte[] ReadDataFrame(string path, int frameNum)
{
using (FileStream stream = File.OpenRead(path))
{
stream.Seek(_dataOffset + frameNum * cbFrame, SeekOrigin.Begin);
byte[] data = new byte[cbFrame];
stream.Read(data, 0, cbFrame);
return data;
}
return null;
}
The problem is that when I set _dataOffset to stream.Position, I get the position that the StreamReader has read to, not the end of the header. As soon as I thought about it this made sense, but I still need to be able to know where the end of the header is and I'm not sure if there's a way to do it and still take advantage of StreamReader.
You can find out how many bytes the StreamReader has actually returned (as opposed to read from the stream) in a number of ways, none of them too straightforward I'm afraid.
Get the result of textReader.CurrentEncoding.GetByteCount(totalLengthOfAllTextRead) and then seek to this position in the stream.
Use some reflection hackery to retrieve the value of the private variable of the StreamReader object that corresponds to the current byte position within the internal buffer (different from that with the stream - usually behind, but no more than equal to of course). Judging by .NET Reflector, the this variable seems to be named bytePos.
Don't bother using a StreamReader at all but instead implement your custom ReadLine function built on top of the Stream or BinaryReader even (BinaryReader is guaranteed never to read further ahead than what you request). This custom function must read from the stream char by char, so you'd actually have to use the low-level Decoder object (unless the encoding is ASCII/ANSI, in which case things are a bit simpler due to single-byte encoding).
Option 1 is going to be the least efficient I would imagine (since you're effectively re-encoding text you just decoded), and option 3 the hardest to implement, though perhaps the most elegant. I'd probably recommend against using the ugly reflection hack (option 2), even though it's looks tempting, being the most direct solution and only taking a couple of lines. (To be quite honest, the StreamReader class really ought to expose this variable via a public property, but alas it does not.) So in the end, it's up to you, but either method 1 or 3 should do the job nicely enough...
Hope that helps.
So the data is utf8 (the default encoding for StreamReader). This is a multibyte encoding, so IndexOf would be inadvisable. You could:
Encoding.UTF8.GetByteCount(string)
on your data so far, adding 1 or 2 bytes for the missing line ending.
If you're needing to count bytes, I'd go with the BinaryReader. You can take the results and cast them about as needed, but I find its idea of its current position to be more reliable (in that since it reads in binary, its immune to character-set problems).
So your last line contains 'DATA' + an unknown amount of data bytes. You could extract the position by using IndexOf() with your last read line. Then readjust the stream.Position.
But I am not sure if you should use ReadLine() at all in this case. Maybe it would be better to read byte by byte until you reach the 'DATA' mark.
The line breaks are easily identifiable without needing to decode the stream first (except for some encodings rarely used for text files like EBCDIC, UTF-16, UTF-32), so you can just read each line as bytes and then decode the entire line:
using (FileStream stream = File.OpenRead(path)) {
List<byte> buffer = new List<byte>();
bool hasCr = false;
bool done = false;
while (!done) {
int b = stream.ReadByte();
if (b == -1) throw new IOException("End of file reached in header.");
if (b == 13) {
hasCr = true;
} else if (b == 10 && hasCr) {
string line = Encoding.UTF8.GetString(buffer.ToArray(), 0, buffer.Count);
if (line == "DATA") {
done = true;
} else {
HandleHeaderLine(line);
}
buffer.Clear();
hasCr = false;
} else {
if (hasCr) buffer.Add(13);
hasCr = false;
buffer.Add((byte)b);
}
}
_dataOffset = stream.Position;
}
Instead of closing the stream and open it again, you could of course just keep on reading the data.