Dump Lora.read() to array - c++

I want to dump chars from a Lora transmitter using Arduino Nano. With this line I assume it can be store the chars into an array:
char* dump = (char)LoRa.read();
char in[255];
strcpy(in, dump);
char str[] = in;
But unfortunately I get this compiler error:
exit status 1
initializer fails to determine size of 'str'
How I fix it?
UPDATE
I give my entire code. I used shox96 shox96 from siara-cc for my objective to compress the data from Lora.read().
void print_compressed(char *in, int len) {
int l;
byte bit;
//Serial.write("\nCompressed bits:");
for (l=0; l<len*8; l++) {
bit = (in[l/8]>>(7-l%8))&0x01;
//Serial.print((int)bit);
//if (l%8 == 7) Serial.print(" ");
}
}
void loop() {
char* dump = (char)LoRa.read();
char in[255];
strcpy(in, dump);
char str[] = in;
char cbuf[300];
char dbuf[300];
int len = sizeof(str);
if (len > 0) {
memset(cbuf, 0, sizeof(cbuf));
int ctot = shox96_0_2_compress(str, len, cbuf, NULL);
print_compressed(cbuf, ctot);
memset(dbuf, 0, sizeof(dbuf));
int dlen = shox96_0_2_decompress(cbuf, ctot, dbuf, NULL);
dbuf[dlen] = 0;
float perc = (dlen-ctot);
perc /= dlen;
perc *= 100;
Serial.print(ctot);
Serial.write(",");
Serial.println(dlen);
}
delay(1000);
}

The compiler can only supply the size of an array for you on creation if it has a brace enclosed initializer list. Like this:
int array[] = {1, 2, 3, 4, 5};
If you're doing anything other than that then you need to put a number inside those braces. Since you're making a copy of the array in and that array is 255 char then this one needs to be 255 char as well in order to accommodate.
char str[255] = in;
My comment on your question still stands though. This answer clears your compiler error, but I don't think it is really a solution to your larger problem. But without seeing more of your code and knowing more about it I can't tell much about it. You already have two copies of this data by the time you get to that line. I'm not sure why you think you need to have a third.

Related

strcpy to multi-dimensional array in C++

I've been having issues attempting to copy a word into a multi-dimensional array.
Here is the code I use to create the array:
char *word_buffer;
char *return_result[64];
int buffer_count = 0;
int word_start = 0;
int word_end = 0;
// Some extra, irreverent code.
for (int i = 0; i < length; i += 1) {
if (text[i] == delim) { // Delim is a value such as '\n'
word_end = i;
word_buffer = (char*) malloc(sizeof(char)*64);
strncpy(word_buffer, text + word_start, word_end - word_start); // Copy the word into word_buffer
strcpy(*(return_result + buffer_count), word_buffer);
word_start = i + 1;
}
}
I believe my issue lies with the last line. I attempt to give strcpy a pointer to the address of the 2d array where I want the result of word_buffer to be place. However, this results in a Segmentation Fault.
The goal is to have an array of words returned. I.E.
char *result[10] = { "foo", "bar", "x", "y", "z" };
But to have this done dynamically with code. My code to split the words is working fine. Though, I don't know how to place the value into a 2d array.
Edit: User SHR recommended I try replacing the strcpy line with return_array[buffer_count]=word_buffer;. This does partially work but it crashes after a random amount of values in the array every time. I don't really see how this could be due to high memory usage. Tracking the memory usage of the binary shows nothing out of the ordinary.

C++ AES Encryption getting truncated to 16 characters

I've got a function that I worked on a while ago in C++ that does AES 256 encryption using CBC.
I wrote the method a while ago so I unfortunately can't remember where I got the code from, but I've since found that I have a problem where if the string being encrypted is over 16 characters, its only the first 16 characters of the string that get encrypted.
The code is below:
string Encryption::encryptOrDecrypt(string stringToEncrypt, Mode mode)
{
HelperMethods helperMethods;
try
{
EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new();
EVP_CIPHER_CTX_init(ctx);
unsigned char key[33] = "my_key";
unsigned char iv[17] = "my_iv";
if (mode == Decrypt)
{
stringToEncrypt = helperMethods.base64Decode(stringToEncrypt);
}
vector<unsigned char> encrypted;
size_t max_output_len = stringToEncrypt.length() + 16 - (stringToEncrypt.length() % 16);
//size_t max_output_len = 16 - (stringToEncrypt.length() % 16);
encrypted.resize(max_output_len);
EVP_CipherInit_ex(ctx, EVP_aes_256_cbc(), NULL, key, iv, mode);
// EVP_CipherUpdate can encrypt all your data at once, or you can do
// small chunks at a time.
int actual_size = 0;
EVP_CipherUpdate(ctx,
&encrypted[0], &actual_size,
reinterpret_cast<unsigned char *>(&stringToEncrypt[0]), stringToEncrypt.size());
// EVP_CipherFinal_ex is what applies the padding. If your data is
// a multiple of the block size, you'll get an extra AES block filled
// with nothing but padding.
int final_size = 0;
EVP_CipherFinal_ex(ctx, &encrypted[actual_size], &final_size);
actual_size += final_size;
encrypted.resize(actual_size);
char * buff_str = (char*)malloc(encrypted.size() * 2 + 1);
memset(buff_str, 0, (encrypted.size() * 2 + 1));
char * buff_ptr = buff_str;
size_t index = 0;
for (index = 0; index < encrypted.size(); ++index)
{
buff_ptr += sprintf(buff_ptr, "%c", encrypted[index]);
}
EVP_CIPHER_CTX_cleanup(ctx);
EVP_CIPHER_CTX_free(ctx);
if (mode == Encrypt)
{
string encryptedString = buff_str;
free(buff_str);
return helperMethods.base64Encode(encryptedString.c_str(), encryptedString.length());
}
else
{
string decryptedString = buff_str;
free(buff_str);
return decryptedString;
}
}
catch (exception ex)
{
return stringToEncrypt;
}
}
I've stepped through the code to see where the problem might be and I can't see any reason why, its probably something stupidly simple.
The size_t max_output_len is 768 (the actual string is 752) so this is +16 for padding I believe, but I'm not sure if this should 768 as well but as the method is setting this itself not sure.
The pointer int final_size that gets passed into EVP_CipherFinal_ex becomes 16 when that method completes and the actual_size is also 768 so not sure where the problem is.
I think I've figured the problem, although not 100% sure why this works and the original way doesn't.
I don't believe its a null byte from looking at the content of buffer when debugging but I've changed it to the following which seems to resolve it.
Instead of
string encryptedString = buff_str;
I have changed it to the following
int i = 0;
stringstream encryptedStringStream;
for (i = 0; i < index; i++)
{
encryptedStringStream << buff_str[i];
}
string encryptedString = encryptedStringStream.str();

Displaying element from pointer struct

I have run onto a little problem and I have looked everywhere but I believe I am looking in the wrong direction. I created an account here in hopes of solving a slight issue I have. I am in the middle of programming an RPG and when I attempt to display one characters "magic spells", I can only display [3]. [0] [1] [2] crashes my game. Game is in C++.
Example of my code below:
Create my struct:
struct Fighter {
int HP; //max 999
int maxHP;
int MP; //max 999
int maxMP;
int STR; //max 255
int CON; //max 255
int AGL; //max 100
bool dead;
const char* Magic[];
};
Fighter * player = new Fighter[5];
Initializing and assigning elements with these parameters for 4 party members:
void InitPlayer(int pClass, int p)
{
if(pClass == 0) //Knight
{
player[p].maxHP = 750;
player[p].HP = player[p].maxHP;
player[p].maxMP = 0;
player[p].MP = player[p].maxMP;
player[p].STR = 200;
player[p].CON = 0;
player[p].AGL = 35;
}
else if(pClass == 1) //Ninja
{
player[p].maxHP = 675;
player[p].HP = player[p].maxHP;
player[p].maxMP = 0;
player[p].MP = player[p].maxMP;
player[p].STR = 175;
player[p].CON = 0;
player[p].AGL = 80;
player[p].Magic[0] = "Cure";
player[p].Magic[1] = "Haste";
player[p].Magic[2] = "Sleep";
}
//... More Character code
}
Here I draw/print "Magic" to the screen:
Printf_xy(123,223,player[0].Magic[0]); //Crash
Printf_xy(123,233,player[1].Magic[0]); //Crash
Printf_xy(123,243,player[2].Magic[0]); //Crash
Printf_xy(123,253,player[3].Magic[0]); //Prints "Cure" does not crash
As you can see, it will work but only if I display player[3]. I am sure I am forgetting to do something or initializing something incorrectly. Any help would be greatly appreciated.
Magic is a zero length array - when you assign anything into it, or even try to access Magic[0] you are accessing outside of the array boundaries.
If you know the maximum number of magic entries you need, use that as your array size, something like:
const int MagicLimit = 10
...
const char* Magic[MagicLimit];
Better still, if you are using c++, use a std::vector to hold the magic strings (also use std::string), that way you can easily tell the length of the list.
For example:
std::vector<std::string> Magic;

Access violation, cant figure out the reason

So, been building this class:
public class BitArray {
public:
unsigned char* Data;
UInt64 BitLen;
UInt64 ByteLen;
private:
void SetLen(UInt64 BitLen) {
this->BitLen = BitLen;
ByteLen = (BitLen + 7) / 8;
Data = new unsigned char(ByteLen + 1);
Data[ByteLen] = 0;
}
public:
BitArray(UInt64 BitLen) {
SetLen(BitLen);
}
BitArray(unsigned char* Data, UInt64 BitLen) {
SetLen(BitLen);
memcpy(this->Data, Data, ByteLen);
}
unsigned char GetByte(UInt64 BitStart) {
UInt64 ByteStart = BitStart / 8;
unsigned char BitsLow = (BitStart - ByteStart * 8);
unsigned char BitsHigh = 8 - BitsLow;
unsigned char high = (Data[ByteStart] & ((1 << BitsHigh) - 1)) << BitsLow;
unsigned char low = (Data[ByteStart + 1] >> BitsHigh) & ((1 << BitsLow) - 1);
return high | low;
}
BitArray* SubArray(UInt64 BitStart, UInt64 BitLen) {
BitArray* ret = new BitArray(BitLen);
UInt64 rc = 0;
for (UInt64 i = BitStart; i < BitLen; i += 8) {
ret->Data[rc] = GetByte(i);
rc++;
}
Data[rc - 1] ^= (1 << (BitLen - ret->ByteLen * 8)) - 1;
return ret;
}
};
just finished writing the SubArray function and went on to test but I get "Access violation: attempted to read protected memory" on the line where GetByte(i) gets called. I tested a bit and it doesn't seem to have anything to do with the data array or i, placing "int derp = GetByte(0)" on the first line of the function produces the same error.
calling GetByte from outside the class works fine, I don't understand whats going on.
the test function looks like this:
unsigned char test[] = { 0, 1, 2, 3, 4, 5, 6, 7 };
BitArray* juku = new BitArray(test, 64);
auto banana = juku->GetByte(7); //this works fine
auto pie = juku->SubArray(7, 8);
You might want to consider creating an array of characters, changing:
Data = new unsigned char(ByteLen + 1);
into:
Data = new unsigned char[ByteLen + 1];
In the former, the value inside the parentheses is not the desired length, it's the value that *Data gets initialised to. If you use 65 (in an ASCII system), the first character becomes A.
Having said that, C++ already has a pretty efficient std::bitset for exactly the situation you seem to be in. If your intent is to learn how to make classes, by all means write your own. However, if you want to just make your life simple, you may want to consider using the facilities already provided rather than rolling your own.

Writing data to memory in C++

I want to write a a mix of int, char, real in void *data.
I am using a file pointer to run through the data block.
Now my question is that since the data type is void, I have to typecast it to int while writing integer and char for writing string.
While typecasting I used the following sample code:
*((int *)data+0) = 14; //writing int
*((int *)data+4) = 5; //writing int, left a space of 4 bytes for int
*((char *)data+8) = 'a'; //writing char
*((char *)data+9) = 'f'; //writing char
But then while reading the values back it didnt give the correct value.
cout<<*((int *)data+0);
cout<<*((int *)data+3);
cout<<*((char *)data+8);
Is the way my code is written correct? I am doubtful about it as data is void.
*((int *)data+4) = 5; // writing 4th int
cout<<*((int *)data+3); // but reading third one
And just in case, ((int *)data+4) points to 4th integer (that is, 16th byte given int size = 4), not to 4th byte. That is, you code overwrites bytes 0-3, then 16-19, then 8th, then 9th. What you probably meant is: *(int *)( (char*)data + X )
Edited to correct mistake pointed out by MSalters
Apart from the typo that others have mentioned (data+3 instead of data+4), you also need to change e.g.
*((int *)data+4)
to
*((int *)data+1)
because adding 4 to an int * doesn't add 4 to the address, it adds 4 * sizeof (int).
If you need to write to an offset that is not a multiple of sizeof(int) (say, 7), you need:
*(int *)((char *)data+7)
For this reason, it might be better to make data a char * to start with, so you can just say
*(int *)(data+7)
Use a class or a struct.
Here, pointer arithmetics is misleading you. When you add 4 to an int * you are adding actually four times sizeof int.
If your data has a constant layout, why don't you just use a struct such as
struct MemoryLayout {
int _first;
int _second;
char _c1;
char _c2;
};
?
You're writing the second one with:
*((int *)data+4) = 5; // offset = 4
and reading it back with:
cout<<*((int *)data+3); // offset = 3
In addition, the (int*) cast is binding to data, not data+4 so that your 4 is scaled up by the size of an int.
If you really want to do this (and a struct is not a possibility due to variances in the data formats), you should cast data to a char*, then add the number of bytes to get the char offset, then cast that to your desired type.
That would be something like:
*((int*)((char*)(data + 0)) = 14; //writing int
*((int*)((char*)(data + 4)) = 5; //writing int
*((char*)data + 8) = 'a'; //writing char
*((char*)data + 9) = 'f'; //writing char
int Data;
//char Data;
//float Data;
FILE *File = fopen("File.txt","wb");
fwrite((char *)&Data,sizeof(Data),1,File);
fclose(File);
File = fopen("File.txt","rb");
fread((char *)&Data,sizeof(Data),1,File);
fclose(File);
...
int DataInt1 = 200;
char DataChar1 = 'N';
FILE *File = fopen("File.txt","wb");
fwrite((char *)&DataInt1,sizeof(DataInt1),1,File);
fwrite((char *)&DataChar1,sizeof(DataChar1),1,File);
fclose(File);
int DataInt2 = 0;
char DataChar2 = 0;
File = fopen("File.txt","rb");
fread((char *)&DataInt2,sizeof(DataInt2),1,File);
fread((char *)&DataChar2,sizeof(DataChar2),1,File);
fclose(File);
printf("%d %d!\n",DataInt2,DataChar2);