For my project I need to read some single line text from a SD card, then get the hex or dec value of each character within the string and group those values in an array.
There are no whitespaces in the text and the lines end with \n
I'm using this code to read all the content into a single string!
String line = "";
while (dataFile.available() != 0)
{
line = dataFile.readStringUntil('\n');
if (line == "")
break;
}
For later use I need to calculate the hex values of each character, this code should iterate over the String and group it in an array.
int lineSize = line.length();
uint8_t data[lineSize];
for (int i = 0; i < lineSize; i++)
{
data[i] = line.charAt(i);
}
I really don't know wether this works or not, but I doubt that I will get the actual hex values...
The values are somewhere but I really don't know how to access them!
The result should look like this:
uint8_t data[] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07}
Think of Hexadecimal as just another format to display any data type (uint8_t, or char or int...) stored in memory. In memory, its all binary, or hexadecimal. Just depends on how you want to look at it.
For example: the following statements:
long int A = 34;
uint8_t B = 34;
char C = 34;
int D = 34;
printf("0x%02x\n", 'A'); // surrounded with '' gives ASCII value of 65, then displayed in Hex
printf("0x%02x\n", A);
printf("0x%02x\n", B);
printf("0x%02x\n", C);
printf("0x%02x\n", D);
Results in:
Breaking any string into its fundamental elements, (char, or uint8_t) and printing them as shown above will yield similar results for you.
Edit:
For this input file (call it in.txt, in the executable directory):
lkjahldfkjghlskjhlskjhlakdjgglsjkahlkj4hl5k6jh67=83kjhlkjshdf8f7s698s7dfgbslfkjbg
And using this code:
int main(void)
{
FILE *fp;
char filename[]=".\\in.txt";
uint8_t c;
int length=0, i=0;
uint8_t *array;
//Get number of entries in file:
fp=fopen(filename, "r");
c= fgetc(fp);
while(c<255)
{
length++;
c= fgetc(fp);
}
fclose(fp);
//give array sufficient space
array = malloc(sizeof(uint8_t)*length);
fp=fopen(filename, "r");
//read file into array, and display as hexadecimal
c = fgetc(fp);
while(c<255)
{
array[i++]= c;
printf("0x%02x\n", c);
c = fgetc(fp);
}
fclose(fp);
getchar();//stop execution to view files (hit any key to exit)
return 0
}
You should see this output: (only first 20 or so values shown...)
Strings in C/C++ are already arrays (even when abstracted by a higher level class like std::string). The array elements are the character values of each character. Are you sure you can't just grab the string's .c_str() (or .data()) and use that, possibly with a cast?
Well, if by getting the hex code you mean getting the hex representation of those characters, you can do this -
const String hexDigits = "0123456789abcdef";
char hex[2] = "";
hex[0] = hexDigits[ (int)line.at(i) / 16 ];
hex[1] = hexDigits[ (int)line.at(i) % 16 ];
For example, if line.at(i) = A, then hex will be "41".
Related
I'm trying to write an algorithm which adds two numbers that are stored as chars in two arrays. Unfortunately, it doesn't work. When I try to debug it, I see that the variables a and b get the value -1 which makes no sense. Any idea what might be the problem?
public class rechner2 {
public static void main(String[] args) {
final char[] zahl1 = {1, 2, 3};
final char[] zahl2 = {7, 8, 9};
//Add arrays zahl1 and zahl2.
char [] zwischenarray = add(zahl1, zahl2);
for (int i = 0; i < zwischenarray.length; i++) {
System.out.println(zwischenarray[i]);
}
}
private static char[] add(char[] zahl1, char[] zahl2) {
int len;
if (zahl1.length < zahl2.length) {
len = zahl2.length;
} else {
len = zahl1.length;
}
char[] finalresult = new char [len + 1];
int carryover = 0;
for (int i = 0; i < len; i++) {
int a = Character.getNumericValue(zahl1[i]);
int b = Character.getNumericValue(zahl2[i]);
int c = a + b + carryover;
if (c > 9) {
carryover = 1;
c = c - 10;
} else {
carryover = 0;
}
finalresult[i] = (char)c;
}
if (carryover == 1) {
finalresult[len + 1] = 1;
}
return finalresult;
}
}
in this code I believe 2 bug
instead of char , i guess better to us int
length of the array
here is the code:
public class rechner2 {
public static void main(String[] args) {
int[] zahl1 = {1,2,3};
int[] zahl2 = {7,8,9};
//Add arrays zahl1 and zahl2.
int [] zwischenarray = add(zahl1, zahl2);
for (int i = 0; i < zwischenarray.length; i++) {
System.out.println(zwischenarray[i]);
}
}
private static int[] add(int[] zahl1, int[] zahl2) {
int len;
if (zahl1.length < zahl2.length) {
len = zahl2.length;
} else {
len = zahl1.length;
}
int[] finalresult = new int [len + 1];
int carryover = 0;
for (int i = 0; i <= len-1; i++) {
int a = (zahl1[i]);
int b = (zahl2[i]);
int c = a + b + carryover;
if (c > 9) {
carryover = 1;
c = c - 10;
} else {
carryover = 0;
}
finalresult[i] = c;
}
if (carryover == 1) {
finalresult[len] = 1;
}
return finalresult;
}
}
Your code is conflicted: The numbers / characters in your array are actually integers, not "printable" or "human readable" characters. But, parts of your code are treating them as if they are "printable".
Let's go back decades, and use ASCII for the beginning of this explanation. ASCII has "Printable" and "Nonprintable" characters. The "Nonprintable" characters are known as "Control codes."
Control codes include codes that move the cursor on a display terminal or print head on a printing terminal. They include thing like CR (Carriage Return), LF (Line Feed), HT (Horizontal tab), and BS (Backspace). Others are used by data communications hardware to control the flow of data, or to report status.
Printable characters correspond to what you see on a terminal screen or printout. They include uppercase alphabetic, lower case alphabetic, digits, punctuation, and the space character. They are "human readable."
Look at the list of printable characters in the Wikipedia article. Take 5 as an example. It's represented as '53' in base ten, which corresponds to '35' in base sixteen, or '011 0101' in binary. Note that it is not the same as the binary number five, which would be '0000 0101'.
Java uses 16 bit Unicode, not ASCII, for its char type. The Java compiler allows arithmetic to be done on char data, as if it was the same as short.
These lines in your code expect your char variables and constants are printable characters:
int a = Character.getNumericValue(zahl1[i]);
int b = Character.getNumericValue(zahl2[i]);
In addition, that you specified zwischenarray as char tells the compiler to handle the contents as printable characters in this line:
System.out.println(zwischenarray[i]);
But, the rest of your code treats your char data as integer data types.
You have a bug in this line: finalresult[len + 1] = 1;. After that bug is fixed, how do you fix the rest of your code? There are different ways, and which is best depends on your intention.
For demonstration purpose, try this: Replace the following
int a = Character.getNumericValue(zahl1[i]);
int b = Character.getNumericValue(zahl2[i]);
int c = a + b + carryover;
with
int c = zahl1[i] + zahl2 [i] + carryover;
Also, put a cast in your output line:
System.out.println((short)zwischenarray[i]);
And run it. That will demonstrate you can do arithmetic on Java char data.
Now, remove the (short) cast in output line, and change all occurrences of char to short (or int). Your program still works.
This is because of the way you entered the values for zahl1 and zahl2. Your source code consists of printable characters and white space. By omitting the single quotes, you told the compiler to convert the values to binary integers. For example, your source code 9 became binary 0000 1001 in the runtime code. If you wanted your 9 to remain as a printable character, you needed to enclose it in single quote marks: '9' .
By enclosing all the values in zahl1 and zahl2 in single quote marks, the use of Character.getNumericValue is appropriate. But, you would still need the (short) or (int) cast in your System.out. line to see your output.
Character.getNumericValue is returning -1 because the values passed are outside of the range it was designed to work with.
Here are two ways to convert a base 10 digit represented as a binary integer to the equivalent printable character:
finalresult[i] = (char) (c + '0');
But, my preference is for this:
final String digit = "0123456789";
finalresult[i] = digit.charAt (c);
I want to convert decimal -10 value to hex in a String and byte array format.
I have tried
String minHex = Integer.toHexString(Integer.valueOf(-10));
System.out.println(minHex);
Which results in fffffff6, and I think it is not correct. And for converting byte array I am using below function which I found from
Convert a string representation of a hex dump to a byte array using Java?
public static byte[] hexStringToByteArray(String s) {
int len = s.length();
byte[] data = new byte[len / 2];
for (int i = 0; i < len; i += 2) {
data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4)
+ Character.digit(s.charAt(i+1), 16));
}
return data;
}
So also not sure it will work for minus hex value or not.
To convert an hex to a String the way you expect it i.e. -10 is converted to -a, use:
String hex = Integer.toString(-10, 16);
To convert to a byte array, simply convert the int to a byte array, it is represented the same way:
byte[] bytes = ByteBuffer.allocate(4).putInt(-10).array();
/*keyArray contains a line of cipherkey, and inputArray contains a text that is being encrypted.*/
public static void addRoundKey() {
String keyEle = "";
String inputEle = "";
String result = "";
for(int col=0; col<4; col++) {
for(int row = 0; row<4; row++) {
keyEle = Integer.toHexString(keyArray[row][col] & 0xff);
inputEle = Integer.toHexString(inputArray[row][col] & 0xff);
if(keyEle.equals("0")) {
keyEle = "00";
}
if(inputEle.equals("0")) {
inputEle = "00";
}
BigInteger keyNum = new BigInteger(keyEle,16);
BigInteger inputNum = new BigInteger(inputEle, 16);
result = keyNum.xor(inputNum).toString();
System.out.println("result = " + result);
keyArray[row][col] = Byte.valueOf(result, 16);
//The above line causes Exception in thread "main" java.lang.NumberFormatException: Value out of range. Value:"99" Radix:16`
//keyArray[row][col] = (byte) (Integer.parseInt(result) & 0xff);
}
}
}
I think addRoundKey step takes a column from each of cipher key and text that I am trying to encrypt, and then xor them, right?
So, that's my implementation, I understand why "value out of range" error occurs, it's because byte takes numbers that range from -128 to 127, right?
But I am not so sure how to fix it. I can't change the type of keyArray, which is Byte.
Change line
keyArray[row][col] = Byte.valueOf(result, 16);
to
keyArray[row][col] = (byte) Integer.valueOf(result, 16).intValue();
edit
or even shorter, as correctly stated in Bohemian's answer :
keyArray[row][col] = (byte) Integer.parseInt(result, 16);
You are getting an error parsing "99" as a byte using base 16, which may be paraphrased as:
byte b = Byte.valueOf("99", 16);
because byte is signed, with valid range -128 to 127, but you are
First parse it as an Integer, using Integer.parseInt(), then convert it to a signed byte, eg:
keyArray[row][col] = (byte)Integer.parseInt(result, 16);
This is a code that takes in an array of all the printing characters of the ASCII table. I am trying to make it so that any String message in the form of integers (e.g. String "aba" that is converted 97098097 can be put back into its original String form. 100101101 can be taken and made back into "dee". I've really tried hard with this method but it does not seem to be working, especially when it comes to numbers and such please help me. It is in Java by the way and I am using Eclipse.
public static String IntToString (){
int n = 0;
String message = "";
String message2 = null;
String [] ASCII = {" ","!","\"","#","$","%","&","\'","(",")","*","+",",","-",".","/","0","1","2","3","4","5","6","7","8","9",":",";","<","=",">","?","#","A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P","Q","R","S","T","U","V","W","X","Y","Z","[","\\","]","^","_","`","a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z","{","|","}","~"};
String IntMessage = result.toString();
String firstChar = IntMessage.substring(0,2);
if (IntMessage.substring(0,1)=="1" && IntMessage.length()%3==0)
{
for (int x = (IntMessage.length() % 3 - 3) % 3; x < IntMessage.length()-2; x += 3)
n = Integer.parseInt(IntMessage.substring(Math.max(x, 0), x + 3));
message=message.concat(ASCII[n-31]);
return message;
}
else if (IntMessage.length()%3==2)
message2=ASCII[(Integer.parseInt(firstChar))-31];
for (int x = 2; x < IntMessage.length()-2; x += 3)
n = Integer.parseInt(IntMessage.substring(x, x + 3));
message=message2+=ASCII [n - 31];
return message;
It would seem that your encoding scheme is, er, crazy.
First, you take the ASCII value of a string, then take the character representation of that ASCII value, then store it as a string.
So "abc" => {97, 98, 99} => "979899".
But since you are using ASCII, which can have values of 100 or more, you are padding your ints with 0 if they are under 100:
"abc" => {97, 98, 99} => {"097", "098", "099"} => "097098099"
But you decide to do this only sometimes, because somehow
"aba" => "97098097"
That is, the first "a" is turned into "97", but the last "a" is turned into "097".
I'd say you should fix your encoding scheme first.
Also, these are hopefully not "random integers" because you are trying to turn them into sensible strings. Otherwise a simple mapping such as base64 would easily map any integers to strings, they just might not make much sense.
In fact, they aren't even really integers. You're storing your encoded strings as strings.
public static void main(String[] srgs){
String aaa = "100101101";
String[] a = split(aaa, 3);
String s = "";
for(int i=0;i<a.length;i++){
char c = (char)Integer.parseInt(a[i]);
s += Character.toString(c);
}
System.out.println(s);
}
public static String[] split(String str, int groupIndex){
int strLength = str.length();
int arrayLength = strLength/groupIndex;
String[] splitedArray = new String[strLength/groupIndex];
for(int i=0;i<arrayLength;i++){
String splitedStr = str.substring(0, groupIndex);
str = str.substring(groupIndex, str.length());
arrayLength = str.length();
splitedArray[i] = splitedStr;
}
return splitedArray;
}
The most important is that ASCII string covert to Char value, than turn it to real Character value in the string. The ASCII code length need be fix by 3 can be helpful in this case.
I'm trying to do a simple caesarian shift on a binary string, and it needs to be reversable. I've done this with this method..
public static String cShift(String ptxt, int addFactor)
{
String ascii = "";
for (int i = 0; i < ptxt.length(); i+=8)
{
int character = Integer.parseInt(ptxt.substring(i, i+8), 2);
byte sum = (byte) (character + addFactor);
ascii += (char)sum;
}
String returnToBinary = convertToBinary(ascii);
return returnToBinary;
}
This works fine in some cases. However, I think when it rolls over being representable by one byte it's irreversable. On the test string "test!22*F ", with an addFactor of 12, the string becomes irreversible. Why is that and how can I stop it?
edit: For clarification sake, the test string is converted to binary before being passed in. Here is convertToBinary
public static String convertToBinary(String str)
{
char [] array = str.toCharArray();
String binaryToBeReturned = "";
for (int i = 0; i < str.length(); i++)
{
String binary = Integer.toBinaryString((int)array[i]);
binary = padZeroes(binary);
binaryToBeReturned += binary;
}
return binaryToBeReturned;
}
When I run this with a cShift of 12, followed by a cShift of -12 to reverse, I get this...
01110100011001010111001101110100001000010011001000110010010001100010101000100000
111111111000000001110001011111111111111110000000001011010011111000111110010100100011011000101100
ÿ?qÿ?->>R6,
ÿótesÿót!22F*
The first string is just converting the test string to binary. The second string is the result of the cShift in binary. The third string is the result of converting this to ascii, and the fourth string is the result of reversing with -12 on cShift and converting to ascii.
It's pretty clear to me that somehow there are extra bits being added from the roll over and I'm not totally sure how to deal with it. Thanks.
You need to mask the byte when widening to char, because otherwise the sign bit will be extended.
ascii += (char)(sum & 0xFF)
This masking pattern applies when widening a signed numeric type if you don't want the sign extension.
anInt = aByte & 0xFF;
anInt = aShort & 0xFFFF;
aLong = anInt & 0xFFFFFFFFL; // notice the L
Here's an example to illustrate:
byte b = -1; // 0xFF
char ch = (char) b; // 0xFFFF
int i = ch;
System.out.println(i); // prints "65535", which is 0xFFFF
byte b = -1; // 0xFF
char ch = (char) (b & 0xFF); // 0xFF
int i = ch;
System.out.println(i); // prints "255", which is 0xFF
There is a lesson to be had here. If you've read Java Puzzlers, you'll see a few that revolves around sign extension hooplas. This puzzle from the book is essentially the same as the one I had above, but perhaps more confusing:
// Java Puzzlers, Puzzle 6: Multicast
System.out.println((int) (char) (byte) -1); // prints 65535
There are two ways to remedy this:
Avoid working with byte and short. You rarely need to.
If you are working with them, always be wary of the need to mask.
byte to char is always tricky because:
Although char is wider than byte...
char is unsigned while byte is!!!
Therefore, it's not a straightforward widening conversion, but a widening-narrowing conversion!
JLS 5.1.4 Widening and Narrowing Primitive Conversions
The following conversion combines both widening and narrowing primitive conversions:
byte to char.
First, the byte is converted to an int via widening primitive conversion, and then the resulting int is converted to a char by narrowing primitive conversion.
Additional references
5.1.2 Widening Primitive Conversion
5.1.3 Narrowing Primitive Conversions