How to try a range of hex values in C# code?

I have the following C# Code

using System;
using System.Collections.Generic;
using System.Text;
using System.IO;


namespace Unpac {
	class Program {

		//_____________________________________________________________________
		static string		input_filename_no_ext;
		static int			current_output_index;
		static string		output_directory;
		static List<byte>	output_buffer;
		static int			image_height;
		static int			line_min_length;
		static int			line_max_length;

		//_____________________________________________________________________
		static void Main(string[] args) {

			int?		forced_image_width;
			string		input_fullpath;
			string		input_directory;
			string		input_filename;
			byte[]		input_data;
			long		input_max_valid_position;
			long		current_input_position;
			byte		input_byte;
			byte		RLE_sumador;
			int			count;
			byte		b;
			int			n;
			bool		RLE_FC_swap;
			byte		b2;
			int			width_current;


			if(args.Length<2) {
				Console.WriteLine("Use: unpac.exe <InputFile.pac> <OutputDir> [ImageWidth]");
				return;
			}

			if(args.Length>2) {
				forced_image_width = int.Parse(args[2]);
			} else {
				forced_image_width = null;
			}
			
			try {
				input_fullpath		= Path.GetFullPath(args[0]);
				input_directory		= Path.GetDirectoryName(input_fullpath);
				input_filename		= Path.GetFileName(input_fullpath);

				input_fullpath		= Path.Combine(input_directory, input_filename);
				if(!File.Exists(input_fullpath)) throw new Exception();

				int p = input_filename.LastIndexOf('.');
				if(p==-1) {
					input_filename_no_ext = input_filename;
				} else {
					input_filename_no_ext = input_filename.Substring(0, p);
				}

			} catch {
				Console.WriteLine("ERROR: invalid input file");
				return;
			}

			try {
				output_directory = Path.GetFullPath(args[1]);
				if(!Directory.Exists(output_directory)) {
					Directory.CreateDirectory(output_directory);
				}
			} catch {
				Console.WriteLine("ERROR: invalid output directory");
				return;
			}

			try {
				input_data = File.ReadAllBytes(input_fullpath);
			} catch {
				Console.WriteLine("ERROR: cannot read from input file");
				return;
			}

			Console.WriteLine($"{input_filename}");

			input_max_valid_position	= input_data.Length - 1;
			current_input_position		= 0;
			current_output_index		= 1;
			output_buffer				= new List<byte>();

			RLE_sumador					= 0;
			line_min_length				= int.MaxValue;
			line_max_length				= 0;
			width_current				= 0;
			image_height				= 0;

			while(current_input_position <= input_max_valid_position) {

				input_byte = input_data[current_input_position];
				current_input_position++;

				if(input_byte == 0xFF) {
					//==============
					// Fin de chunk
					//==============
					Save();
					current_output_index++;

					RLE_sumador			= 0;
					line_min_length		= int.MaxValue;
					line_max_length		= 0;
					width_current		= 0;
					image_height		= 0;

				} else if(input_byte == 0xFE) {
					//=================
					// Siguiente linea
					//=================
					if(width_current < line_min_length) line_min_length = width_current;
					if(width_current > line_max_length) line_max_length = width_current;

					if(forced_image_width!=null) {
						count = forced_image_width.Value - width_current;
						if(count > 0) {
							for(n=0; n<count; n++) {
								output_buffer.Add(0);
							}
						}
					}

					image_height++;
					width_current = 0;

				} else if(input_byte == 0xFD) {
					count = (int) (input_data[current_input_position]) + 1;
					current_input_position++;

					b = input_data[current_input_position];
					current_input_position++;

					for(n=0; n<count; n++) {
						output_buffer.Add(b);
					}

					width_current += count;

				} else if(input_byte == 0xFC) {
					b = input_data[current_input_position];
					current_input_position++;

					b2 = (byte)(b + 1);

					count = (int) (input_data[current_input_position]) + 1;
					current_input_position++;

					RLE_FC_swap = false;
					for(n=0; n<count; n++) {
						output_buffer.Add(
							RLE_FC_swap ? b2 : b
						);
						RLE_FC_swap = !RLE_FC_swap;
					}

					width_current += count;

				} else if(input_byte == 0xFB) {
					RLE_sumador = input_data[current_input_position];
					current_input_position++;

				} else {
					b = (byte)(input_byte >> 2);
					b += RLE_sumador;
					count = (input_byte & 3) + 1;

					for(n=0; n<count; n++) {
						output_buffer.Add(b);
					}

					width_current += count;
				}
			}

			Save();
		}

		//_____________________________________________________________________
		static void Save() {

			if(output_buffer.Count == 0) return;

			string	output_filename;
			string	output_fullpath;
			byte[]	output_array;
			int		output_length;
			bool	is_valid_image;


			output_filename	= $"{input_filename_no_ext}.{current_output_index:D3}";
			output_fullpath	= Path.Combine(output_directory, output_filename);
			output_array	= output_buffer.ToArray();
			output_length	= output_array.Length;
			is_valid_image	= false;


			if(image_height > 0) {
				if(line_min_length != line_max_length) {
					Console.WriteLine($" -> {output_filename} ({output_length}) (min width:{line_min_length}) (max width:{line_max_length}) (height:{image_height})");
				} else {
					Console.WriteLine($" -> {output_filename} ({output_length}) (width:{line_min_length}) (height:{image_height})");
					is_valid_image = true;
				}
			} else {
				Console.WriteLine($" -> {output_filename} ({output_length})");
			}

			try {
				if(is_valid_image) {
					Bitmap.Save(output_fullpath + ".bmp", output_array, line_min_length, image_height);
				} else {
					File.WriteAllBytes(output_fullpath, output_array);
				}
			} catch {
				Console.WriteLine("ERROR: cannot save to output file");
			}

			output_buffer.Clear();
		}

	}
}

How can I code in C# to try the Hex values, 0x00 to 0xFF in this code for input_byte == , i.e what should I type in the posted Code, to try the range each hex value in turn ? I looked on the internet about ranges in c# but I didn’t find anything suitable, to help me with.

What I have tried:

I have tried altering the input_byte values. But I need to be able, to try all possible combineations, of all individual Hex Values i.e. there are either 255 or 256. Where it says input_byte == in the Code. I wrote, and also copy and pasted 4x256, else if Statements in my latest modification, of my Program.cs Code. But I don’t Think the Compiled Program, is doing what I wan’t to achieve.

I asked a person who has a knowledge of C# he said maybe I could try the following in a for loop ?

for(int nSomething=0; nSomething<256: n++) { doSomething(nSomething);}

Could someone suggest a modification I could make, to my original Code, using the above C# code, to achieve what I want ? obviously the Something would be replaced with other text ? I am okay with all output Files, being saved to the same Folder. There is a seperate C# Code called Bitmap.cs, which makes up the unpac program.

Any help would be much appreciated.

Regards

Eddie Winch

I don’t quite follow what you are asking.

In your if conditions, you have expressions like input_byte == 0xFF
This is the same expression as input_byte == 255
In both cases, you are comparing input_byte to the same number. Just different representations of the same value (hex and integer forms of same number).

Iterating in a for loop through integers 0 to 255 is the same as looping through the hexadecimal numbers 0x00 to 0xFF

Console.WriteLine(0xFF == 255);   // Prints True
Console.WriteLine(0x00 == 0);   // True
Console.WriteLine(0xFC == 252);   // True
Console.WriteLine(0x32 == 50);   // True

You can convert integers 0-255 to hexadecimal strings of the form "0x00" to "0xFF" (or "00" to "FF") , but your conditions aren’t comparing strings, so I don’t see how that is helpful.
Converting hexadecimal strings to integers and vice versa can be done as well,

Console.WriteLine(0xFC.ToString("X") == 252.ToString("X")); // True

int i = Convert.ToInt32("0x31", 16);
string j = "0x" + i.ToString("X2");
int k = Convert.ToInt32(j, 16);
Console.WriteLine(i); // 49
Console.WriteLine(j); // "0x31"
Console.WriteLine(k); // 49

But I don’t see how the above helps.

Hi mtrmk,

Many thanks for your reply, I want to try out all combinations of individual input bytes when running the unpac program, where it says else if(input_byte == Hex Value ) i.e. all combinations of 0 to 255. I.e. a brute force approach so first else if could be 0x00 instead of 0xFF, second could be 0xFA instead of 0xFE etc so all combinations of 255 Hex Values. So I could use either hex and integer representations, and both would work ?

I.e.

Can anything be done with this line of Code, I mention in my post be used in the main Code ?

for(int nSomething=0; nSomething<256: n++) { doSomething(nSomething);}

I am just curious what sort of data you are iterating over.
Have you successfully read data to input_data from a file?
If so, what sort of output do you see when you print out say the first five elements of this array?
Console.WriteLine(input_data[0]); and so forth till Console.WriteLine(input_data[4]);

All the following loops are the same. They all iterate over numbers 0 to 255 (or 0x00 to 0xFF in hex) and give exact same output:

// All four loops print numbers 0 to 255 inclusive.
for (int i = 0; i < 256; i++) {
            Console.WriteLine(i);
        }

for (int i = 0x00; i < 0x100; i++) {
            Console.WriteLine(i);
        }

for (int i = 0; i <= 255; i++) {
            Console.WriteLine(i);
        }

for (int i = 0x00; i <= 0xFF; i++) {
            Console.WriteLine(i);
        }

Decimal (base 10) numbers from 0-255 are the same as Hexadecimal (base 16) numbers from 0x00 to 0xFF. Just different representations for us users. In memory, the numbers are stored as a sequence of 1’s and 0’s. So, for example the decimal number 58 can be represented as 0x3A in hex, but behind the scenes, both numbers will result in the exact same sequence of 1’s and 0’s being stored in memory.

So, iterating over a range of hex values is not a problem.

The real issue is what are do you want to do with this range of numbers? I am still not clear on that.

I don’t understand what you want to check each hex value against.
In the code you posted, you have if and else if statements checking input_byte against 0xFF, 0xFE, 0xFD, 0xFC, 0xFB. But the thing is that you have uniquely different blocks of code for each case. If you are going to do 256 different and unique things for each of the 256 hex numbers, then you will end up with 256 blocks of if-else statements or 256 cases of a switch statement.
Just to be clear == is a comparison as opposed to = which is assignment.
In conditions like (input_byte == 0xFD), you are checking whether the value stored in input_byte equals the value of the hex number 0xFD. By iterating over a range of hex numbers, we can give different values to input_byte, but I don’t see how that helps.
I mean if you just had 5 or 6 blocks of code, you can run a range of numbers through each block and store the results for analysis/inspection. But if you are going to have 256 different blocks for 256 hex numbers, then the value to the right of the == operator as well as the body of each if block will be unique. I don’t see how you can automate that unless there is an underlying pattern.

Consider this example,

byte[] numbers = {2, 4, 3, 2, 1, 11, 47, 240, 31, 239};
        
        for (int i = 0; i < numbers.Length; i++) {
            int remainder = numbers[i] % 3;
            
            if (remainder == 1) {
                numbers[i] += 2;
            } else if (remainder == 2) {
                numbers[i] += 1;
            }
        }
        
        foreach (byte n in numbers) {
            Console.WriteLine(n);
        }

The above code increments the numbers accordingly so that each number is divisible by 3.
Iterating over an array or iterating over a range is not a problem. The real issue is to understand what outcomes are possible and how we want to handle each outcome. In the above code, I am dividing each number by 3 and getting the remainder. The possible outcomes are that the remainder can be 0 or 1 or 2. No other outcome. To handle the outcomes, I do nothing if remainder is 0, add 2 to the number if remainder is 1 and add 1 to the number if remainder is 2. The end result is all numbers of the array are now multiples of 3. The point is I had to understand what the possible outcomes were AND how to handle each outcome. So, the conditions and body of each if block had to be manually set by me.
In your code, if there are 4-5 outcomes, then iterating over 256 numbers and checking them against each outcome is not an issue. But if you have 256 unique outcomes for all 256 numbers, then I don’t see how you intend to automate that.

Hi mtrmk,

The Main C# Code, is iterating over a DOS Games, Graphics Files, the Code is one of two Codes, which
make up an Program called unpac. The Program Gueses the dimensions of the Graphics, and then saves the Graphics data as a greyscale Bitmap image File. It’s a custom Run Length Encoding Compression For the Graphics.

Yes, some Bitmap images have been outputted, but nothing useful, the reason I want to try all combinations of Hex Values, in the Code i.e. by brute forcing, is in the hope I get some successful Bitmap images for the previous game. I havn’t had anything useful yet, the Code was written by another person for another game, by the same company. Yes so I am using the unpac Program, on the the previous game a WW2 Aircraft Game by the same company. And in the other game, some successful Bitmap images of the Graphics have been saved. The Hex Values Correspond, to Hex Values in the Games Graphics Files. So yes as you say, in the other game, data has successfully been read to input_data from the DOS Games Files. So I want to try all combinations, of individual hex values with the input_byte == parts of code. So I want to do the same things, with the Hex Values, but with all combinations, so using the same blocks of Code.

Hi mtrtmk,

What I am getting it is for example with the following Codes, the first is part of the original Main Code.

if(input_byte == 0xFF) {
					//==============
					// Fin de chunk
					//==============
					Save();
					current_output_index++;

					RLE_sumador			= 0;
					line_min_length		= int.MaxValue;
					line_max_length		= 0;
					width_current		= 0;
					image_height		= 0;

				} else if(input_byte == 0xFE) {
					//=================
					// Siguiente linea
					//=================
					if(width_current < line_min_length) line_min_length = width_current;
					if(width_current > line_max_length) line_max_length = width_current;

					if(forced_image_width!=null) {
						count = forced_image_width.Value - width_current;
						if(count > 0) {
							for(n=0; n<count; n++) {
								output_buffer.Add(0);
							}
						}
					}

					image_height++;
					width_current = 0;

				} else if(input_byte == 0xFD) {
					count = (int) (input_data[current_input_position]) + 1;
					current_input_position++;

					b = input_data[current_input_position];
					current_input_position++;

					for(n=0; n<count; n++) {
						output_buffer.Add(b);
					}

					width_current += count;

				} else if(input_byte == 0xFC) {
					b = input_data[current_input_position];
					current_input_position++;

					b2 = (byte)(b + 1);

					count = (int) (input_data[current_input_position]) + 1;
					current_input_position++;

					RLE_FC_swap = false;
					for(n=0; n<count; n++) {
						output_buffer.Add(
							RLE_FC_swap ? b2 : b
						);
						RLE_FC_swap = !RLE_FC_swap;
					}

					width_current += count;

				} else if(input_byte == 0xFB) {
					RLE_sumador = input_data[current_input_position];
					current_input_position++;

				} else {
					b = (byte)(input_byte >> 2);
					b += RLE_sumador;
					count = (input_byte & 3) + 1;

					for(n=0; n<count; n++) {
						output_buffer.Add(b);
					}

					width_current += count;
				}
			}

			Save();
		}

Other possible combinations could be

if(input_byte == 0xFB) {
					//==============
					// Fin de chunk
					//==============
					Save();
					current_output_index++;

					RLE_sumador			= 0;
					line_min_length		= int.MaxValue;
					line_max_length		= 0;
					width_current		= 0;
					image_height		= 0;

				} else if(input_byte == 0x02) {
					//=================
					// Siguiente linea
					//=================
					if(width_current < line_min_length) line_min_length = width_current;
					if(width_current > line_max_length) line_max_length = width_current;

					if(forced_image_width!=null) {
						count = forced_image_width.Value - width_current;
						if(count > 0) {
							for(n=0; n<count; n++) {
								output_buffer.Add(0);
							}
						}
					}

					image_height++;
					width_current = 0;

				} else if(input_byte == 0x2A) {
					count = (int) (input_data[current_input_position]) + 1;
					current_input_position++;

					b = input_data[current_input_position];
					current_input_position++;

					for(n=0; n<count; n++) {
						output_buffer.Add(b);
					}

					width_current += count;

				} else if(input_byte == 0x36) {
					b = input_data[current_input_position];
					current_input_position++;

					b2 = (byte)(b + 1);

					count = (int) (input_data[current_input_position]) + 1;
					current_input_position++;

					RLE_FC_swap = false;
					for(n=0; n<count; n++) {
						output_buffer.Add(
							RLE_FC_swap ? b2 : b
						);
						RLE_FC_swap = !RLE_FC_swap;
					}

					width_current += count;

				} else if(input_byte == 0x3E) {
					RLE_sumador = input_data[current_input_position];
					current_input_position++;

				} else {
					b = (byte)(input_byte >> 2);
					b += RLE_sumador;
					count = (input_byte & 3) + 1;

					for(n=0; n<count; n++) {
						output_buffer.Add(b);
					}

					width_current += count;
				}
			}

			Save();

		}

Or

if(input_byte == 0xFC) {
					//==============
					// Fin de chunk
					//==============
					Save();
					current_output_index++;

					RLE_sumador			= 0;
					line_min_length		= int.MaxValue;
					line_max_length		= 0;
					width_current		= 0;
					image_height		= 0;

				} else if(input_byte == 0x66) {
					//=================
					// Siguiente linea
					//=================
					if(width_current < line_min_length) line_min_length = width_current;
					if(width_current > line_max_length) line_max_length = width_current;

					if(forced_image_width!=null) {
						count = forced_image_width.Value - width_current;
						if(count > 0) {
							for(n=0; n<count; n++) {
								output_buffer.Add(0);
							}
						}
					}

					image_height++;
					width_current = 0;

				} else if(input_byte == 0xFA) {
					count = (int) (input_data[current_input_position]) + 1;
					current_input_position++;

					b = input_data[current_input_position];
					current_input_position++;

					for(n=0; n<count; n++) {
						output_buffer.Add(b);
					}

					width_current += count;

				} else if(input_byte == 0x6A) {
					b = input_data[current_input_position];
					current_input_position++;

					b2 = (byte)(b + 1);

					count = (int) (input_data[current_input_position]) + 1;
					current_input_position++;

					RLE_FC_swap = false;
					for(n=0; n<count; n++) {
						output_buffer.Add(
							RLE_FC_swap ? b2 : b
						);
						RLE_FC_swap = !RLE_FC_swap;
					}

					width_current += count;

				} else if(input_byte == 0x7B) {
					RLE_sumador = input_data[current_input_position];
					current_input_position++;

				} else {
					b = (byte)(input_byte >> 2);
					b += RLE_sumador;
					count = (input_byte & 3) + 1;

					for(n=0; n<count; n++) {
						output_buffer.Add(b);
					}

					width_current += count;
				}
			}

			Save();
		}

So I want to try all combinations, of individual Hex Values. Do you see what I am getting at here ?

Sorry I have noticed I called you mtrmk in my first reply, I meant to write mtrtmk.

Regards

Eddie Winch