I want an array to have two different values, based on a condition. I can initialize the array inside the condition with the values i want.
if (myCondition == 0)
{
byte my_message[8] = {0x00, 0xAB, 0xEE, 0xFF, 0x00, 0x01, 0x0A, 0x0B};
}
else if (myCondition == 1)
{
byte my_message[8] = {0x11, 0xA1, 0xBC, 0x71, 0x00, 0x02, 0x94, 0x10};
}
The problem with the previous approach is that the array has local scope, and it cannot be "seen" by the code beneath.
If I try to declare the array outside the condition with:
byte my_message[8];
then, inside the condition, I cannot use the previous way of initializing the whole array all at once.
There is no pattern in the data so I can use a for loop- inside the condition- in order to give value to each element of the array easily.
Is there a way of giving values to the array, besides the cumbersome:
if (myCondition == 0)
{
my_message[0] = {0x00};
my_message[1] = {0xAB};
my_message[2] = {0xEE};
....
}
In C you can use standard function memcpy and compound literals the following way
byte my_message[8];
if (myCondition == 0)
{
memcpy( my_message, ( byte [] ){0x00, 0xAB, 0xEE, 0xFF, 0x00, 0x01, 0x0A, 0x0B}, 8 * sizeof( byte ));
}
else if (myCondition == 1)
{
memcpy( my_message, ( byte[] ){0x11, 0xA1, 0xBC, 0x71, 0x00, 0x02, 0x94, 0x10}, 8 * sizeof( byte ) );
}
In C++ it is better to use std::array instead of a raw array. For example
std::array<byte, 8> my_message;
if (myCondition == 0)
{
my_message = {0x00, 0xAB, 0xEE, 0xFF, 0x00, 0x01, 0x0A, 0x0B};
}
else if (myCondition == 1)
{
my_message = {0x11, 0xA1, 0xBC, 0x71, 0x00, 0x02, 0x94, 0x10};
}
Or if to use a raw array then if the compiler supports C++ 20 then you can use the range based for loop the following way
byte my_message[8];
if (myCondition == 0)
{
for ( auto *p = my_message; auto item : {0x00, 0xAB, 0xEE, 0xFF, 0x00, 0x01, 0x0A, 0x0B} )
{
*p++ = item;
}
}
else if (myCondition == 1)
{
for ( auto *p = my_message; auto item : {0x11, 0xA1, 0xBC, 0x71, 0x00, 0x02, 0x94, 0x10} )
{
*p++ = item;
}
}
Otherwise if the compiler does not support C++ 20 then this declaration
auto *p = my_message;
must be moved outside the range based for loop.
If my_message isn't changed, you could use a pointer instead of an array.
const byte my_messages[2][8] = {
{ 0x00, 0xAB, 0xEE, 0xFF, 0x00, 0x01, 0x0A, 0x0B },
{ 0x11, 0xA1, 0xBC, 0x71, 0x00, 0x02, 0x94, 0x10 },
};
const byte *my_message = my_messages[ myCondition ];
If you need to be able to change my_array, I'd use the following:
const byte my_messages[2][8] = {
{ 0x00, 0xAB, 0xEE, 0xFF, 0x00, 0x01, 0x0A, 0x0B },
{ 0x11, 0xA1, 0xBC, 0x71, 0x00, 0x02, 0x94, 0x10 },
};
byte my_message[8];
memcpy( my_message, my_messages[ myCondition ], sizeof( my_message ) );
You could memcpy from an anonymous array, but it's overly complicated and involves code repetition:
byte my_message[8];
if ( myCondition ) {
memcpy( my_message, ( byte[] ){ 0x11, 0xA1, 0xBC, 0x71, 0x00, 0x02, 0x94, 0x10 }, sizeof( my_message) );
} else {
memcpy( my_message, ( byte[] ){ 0x00, 0xAB, 0xEE, 0xFF, 0x00, 0x01, 0x0A, 0x0B }, sizeof( my_message) );
}
You can wrap the message into the struct and use assign operator with compound literal.
You can use compound literal + memcpy
typedef unsigned char byte;
typedef struct
{
byte my_message[8];
}message_t;
int foo(int myCondition)
{
message_t my_message;
if (myCondition == 0)
{
my_message = (message_t){0x00, 0xAB, 0xEE, 0xFF, 0x00, 0x01, 0x0A, 0x0B};
}
else if (myCondition == 1)
{
my_message = (message_t){0x11, 0xA1, 0xBC, 0x71, 0x00, 0x02, 0x94, 0x10};
}
return 0;
}
int bar(int myCondition)
{
byte my_message[8];
if (myCondition == 0)
{
memcpy(my_message, (byte[]){0x00, 0xAB, 0xEE, 0xFF, 0x00, 0x01, 0x0A, 0x0B}, sizeof(my_message));
}
else if (myCondition == 1)
{
memcpy(my_message, (byte[]){0x11, 0xA1, 0xBC, 0x71, 0x00, 0x02, 0x94, 0x10}, sizeof(my_message));
}
return 0;
}
or you can myCondition as index:
int zoo(int myCondition)
{
byte my_message[8];
memcpy(my_message,
(byte[][8]){{0x00, 0xAB, 0xEE, 0xFF, 0x00, 0x01, 0x0A, 0x0B},
{0x11, 0xA1, 0xBC, 0x71, 0x00, 0x02, 0x94, 0x10}}[myCondition],
sizeof(my_message));
return 0;
}
memcpy way looks the most efficient:
https://godbolt.org/z/d6bMfejz5
Variadic template variant:
#include <array>
#include <cstdint>
#include <cstdlib>
#include <iostream>
using byte = unsigned char;
template <typename T, typename... Ts>
std::array<T, sizeof...(Ts)> make_array(Ts... ts) {
return std::array<T, sizeof...(Ts)> { (T)ts... };
}
int main()
{
bool myCondition = false;
std::array<byte, 8> ary = myCondition
? make_array<byte>(7,6,5,4,3,2,1,0)
: make_array<byte>(0,1,2,3,4,5,6,7);
for(auto it=ary.begin(); it != ary.end(); ++it)
{
std::cout << (int)*it << std::endl;
}
return 0;
}
Why "design-in" a boolean limitation of only two conditions?
The following allows for what could be easily be less code in main(), and up to four conditions... (I've altered the values of the 4x8 bytes to bury an Easter Egg for those who are curious. Happy hunting...)
#include <stdio.h>
void show( byte *m ) { printf( "%.8s\n", m ); }
int main() {
const byte my_messages[][8] = {
{ 0x41, 0x4C, 0x4c, 0x20, 0x47, 0x4F, 0x4F, 0x44 },
{ 0x48, 0x41, 0x54, 0x45, 0x4D, 0x41, 0x52, 0x53 },
{ 0x53, 0x45, 0x4E, 0x44, 0x48, 0x45, 0x4C, 0x50 },
{ 0x54, 0x4F, 0x4F, 0x20, 0x4C, 0x41, 0x54, 0x45 },
};
byte msg[8];
# define FETCH( m, cond ) do { memcpy( m, my_messages[cond], sizeof m ); } while(0)
FETCH( msg, 0 ); show( msg ); // prove
FETCH( msg, 1 ); show( msg ); // prove
FETCH( msg, 2 ); show( msg ); // prove
FETCH( msg, 3 ); show( msg ); // prove
return 0;
}
Surprisingly, this effect is achievable using a reference to an array in C++. I'm not sure how compliant this solution is but it compiles in pedantic mode for CLANG, GCC, ICC and MSVC.
int foo(bool cond) {
byte arr0[8] = {0x00, 0xAB, 0xEE, 0xFF, 0x00, 0x01, 0x0A, 0x0B};
byte arr1[8] = {0x11, 0xA1, 0xBC, 0x71, 0x00, 0x02, 0x94, 0x10};
byte (&tab)[8] = cond ? arr0 : arr1;
return tab[0];
}
See https://godbolt.org/z/P6Th7bfcn
Related
Below is a sketch inspired from an example, that I stripped down to the very bare minimum to fit my needs :
#include <Crypto.h>
#include <AES.h>
#include <string.h>
struct TestVector
{
const char *name;
byte key[32];
byte plaintext[16];
byte ciphertext[16];
};
// Define the ECB test vectors from the FIPS specification.
static TestVector const testVectorAES128 = {
.name = "AES-128-ECB",
.key = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F},
.plaintext = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF},
.ciphertext = {0x69, 0xC4, 0xE0, 0xD8, 0x6A, 0x7B, 0x04, 0x30,
0xD8, 0xCD, 0xB7, 0x80, 0x70, 0xB4, 0xC5, 0x5A}
};
AES128 aes128;
byte buffer[16];
void testCipher(BlockCipher *cipher, const struct TestVector *test)
{
crypto_feed_watchdog();
Serial.print(test->name);
Serial.print(" Encryption ... ");
cipher->setKey(test->key, cipher->keySize());
cipher->encryptBlock(buffer, test->plaintext);
if (memcmp(buffer, test->ciphertext, 16) == 0)
Serial.println("Passed");
else
Serial.println("Failed");
Serial.print(test->name);
Serial.print(" Decryption ... ");
cipher->decryptBlock(buffer, test->ciphertext);
if (memcmp(buffer, test->plaintext, 16) == 0)
Serial.println("Passed");
else
Serial.println("Failed");
}
void setup()
{
Serial.begin(9600);
delay(3000);
Serial.println();
Serial.println(sizeof(AES128));
Serial.println();
testCipher(&aes128, &testVectorAES128);
Serial.println();
}
void loop()
{
}
It works.
I would like to modify this so that I end up with 2 functions : encrypt() and decrypt() which would both take a char array as a parameter.
The sketch above has .plaintext and .ciphertext hardcoded as a constant array of hex values/bytes (I guess?). How do I make these "dynamic"/variable, in order to feed encrypt() and decrypt()?
I am not comfortable with c++.
My project is to have this script feed a var like char hushhush[123] = "s0m3 3ncrypt3d stuff", then I would send the content of hushhush to a webserver/API running PHP, and decrypt with openssl_decrypt() (https://www.php.net/manual/en/function.openssl-decrypt.php)
My second problem will be: openssl_decrypt() needs the key to be of type string $passphrase. What is the "string" of 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F ?
As part of firmware, I want to save a graphic or graphics into the EEPROM of a MCU. The space is not much, 1K, however it can save some program space. And yes you can seperate the glyphs of the graphic to save space however it is not easy to manage and you need more code to display it right.
Most of the monochrome GUI graphics do not fill the screen entirely and contain allot of empty space or repeating pixels. The images are already compressed, each bit in a byte represent 8 pixels.
I show the graphics on a tiny display of 128x32 pixels. Display it and erase the parts that are not relevant, works perfectly fine and efficient.
So I came up with the idea to filter those repeats, to compress it a little. With success, a bitmap like this (see below), is 496 bytes and 'compressed' with my method less 401 bytes.
That doesn't sound much however is a 20% decrease in total size, really great when there is only 1K storage available.
Example of byte array:
PROGMEM const uint8_t TEP_DISPLAY [] = { /* 496 bytes */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x80, 0x00, 0x00, 0x00, 0x00,
0x06, 0x00, 0x80, 0x90, 0x00, 0x3E, 0x01, 0x80, 0x03, 0xC0, 0x01, 0x80, 0x00, 0x47, 0x0F, 0xFE,
0x17, 0x01, 0xC0, 0x90, 0x00, 0x30, 0x00, 0x00, 0x03, 0x60, 0x01, 0x80, 0x01, 0x87, 0x10, 0x02,
0x30, 0x83, 0xE3, 0xFC, 0x00, 0x61, 0xE7, 0x39, 0xB6, 0x6F, 0x0F, 0x00, 0x03, 0x07, 0x36, 0xDA,
0x7F, 0xF0, 0x83, 0xFC, 0x7C, 0x7D, 0xB3, 0x6D, 0xB6, 0x61, 0x9B, 0x1F, 0x03, 0x87, 0x36, 0xDA,
0x30, 0x43, 0xE1, 0xF8, 0x00, 0x61, 0xB3, 0x6D, 0xA7, 0xCF, 0xB3, 0x00, 0x01, 0x80, 0x36, 0xDA,
0x13, 0x81, 0xC0, 0x60, 0x00, 0xC3, 0x66, 0x6D, 0xCC, 0x1B, 0x36, 0x00, 0x01, 0x07, 0x10, 0x02,
0x03, 0x00, 0x80, 0x60, 0x00, 0xFB, 0x66, 0x39, 0x8C, 0x0F, 0x1E, 0x00, 0x02, 0x07, 0x0F, 0xFE,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x01, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1C, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x2A, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xA2, 0xD5, 0x54,
0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x02,
0x00, 0xC0, 0x22, 0x00, 0x08, 0x00, 0x02, 0x20, 0x00, 0x82, 0x48, 0x20, 0x00, 0x08, 0x00, 0x00,
0x40, 0xC0, 0x01, 0xE0, 0x00, 0x01, 0xC0, 0x1E, 0x00, 0x01, 0x50, 0x00, 0xFE, 0x00, 0x0C, 0x02,
0x00, 0xC0, 0x20, 0x10, 0x08, 0x07, 0xC2, 0x01, 0x00, 0x80, 0x00, 0x21, 0x01, 0x08, 0x0E, 0x00,
0x4F, 0xFC, 0x00, 0xFE, 0x00, 0x0F, 0x40, 0x3F, 0xF8, 0x03, 0xF8, 0x03, 0x01, 0x80, 0x0B, 0x02,
0x1C, 0xC2, 0x21, 0x11, 0x08, 0x1C, 0x42, 0x40, 0x04, 0x84, 0x04, 0x21, 0x11, 0x08, 0x69, 0x80,
0x59, 0xE2, 0x01, 0x11, 0x00, 0x18, 0x40, 0x55, 0x54, 0x05, 0x54, 0x03, 0x39, 0x80, 0x3B, 0x02,
0x12, 0xD2, 0x21, 0x11, 0x08, 0x10, 0x42, 0x40, 0x04, 0x84, 0x04, 0x21, 0x7D, 0x08, 0x1E, 0x00,
0x54, 0xCA, 0x01, 0x83, 0x00, 0x10, 0x40, 0x55, 0x54, 0x05, 0x54, 0x03, 0x11, 0x80, 0x3E, 0x02,
0x12, 0x12, 0x21, 0x01, 0x08, 0x11, 0xC2, 0x40, 0x04, 0x84, 0x04, 0x21, 0x11, 0x08, 0x6B, 0x00,
0x51, 0xE2, 0x01, 0x01, 0x00, 0x13, 0xC0, 0x47, 0xC4, 0x04, 0x44, 0x01, 0x11, 0x00, 0x09, 0x82,
0x10, 0x02, 0x21, 0x01, 0x08, 0x71, 0x82, 0x40, 0x04, 0x84, 0x04, 0x23, 0x01, 0x88, 0x0B, 0x00,
0x4F, 0xFC, 0x01, 0xFF, 0x00, 0xF0, 0x00, 0x3F, 0xF8, 0x05, 0x54, 0x01, 0x01, 0x00, 0x0E, 0x02,
0x0F, 0xFC, 0x20, 0xFE, 0x08, 0x60, 0x02, 0x1F, 0xF0, 0x84, 0x04, 0x20, 0xFE, 0x08, 0x0C, 0x00,
0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02
};
Still there is one problem and I think it is a small error in code and I cannot detect it (because spend a couple days on it to think about how to get it some smaller). Maybe there is somebody that can point me into the right direction to solve the problem.
The problem
The problem occurs when there are allot of similarties, more than 255 repetitions of the same, such as many 0xFF repeating lines or 0x00 repeating empty spaces. In my code I take some precautions to avoid a byte overflow however it fails (and now cannot figure out why). What I try to do is when there is an overflow, record it and start allover again with counting. I cannot figure out it is a problem of the read function or just the write function.
This is the layout of storage
At start address:
-----------------
<byte width>
<byte heigth>
<uint16 dataSize>
<data>
<if data=0xFF>
<0xFF>
<repeat count>
</if>
<if data=0x00>
<0x00>
<repeat count>
</if>
<else data>
</data>
Here is my code:
uint16_t TOLEDdisplay::writeToEeprom( uint16_t iAddress )
{
if( width == 0 || height == 0 || cacheSize == 0 )
{ return 0; }
uint8_t iZeros = 0;
uint8_t iFFs = 0;
bool bIsZero = false;
bool bIsFF = false;
bool bZeroOverflow = false;
bool bFFOverflow = false;
uint16_t iBits = 0;
uint8_t* pByteSize = (uint8_t*)&iBits;
uint8_t iZeroCount = 0; // empty stripes , same pixels in a row
uint8_t iFFCount = 0; // filled stripes, same pixels in a row
// Write screen bounds, when read it back with readFromEeprom,
// this bounds must match with the current screen bounds.
EEPROM.write( iAddress++, width );
EEPROM.write( iAddress++, height );
// Reserve two bytes for stream size
uint16_t iSizeAddress = iAddress++;
++iAddress;
// Write the cache content to the EEPROM
uint16_t i = 0;
while( i < cacheSize )
{
iBits = getCacheRawBits( i );
//iBits = displayCache[ i ];
bIsFF = ( iBits == 0xFF );
bIsZero = ( iBits == 0x00 );
if( bIsFF && !bFFOverflow )
{ ++iFFs; }
bFFOverflow = (iFFs == 0xFF);
if( bIsZero && !bZeroOverflow )
{ ++iZeros; }
bZeroOverflow = (iZeros == 0xFF);
if( (!bIsFF && !bIsZero) || bFFOverflow || bZeroOverflow )
{
if( (!bIsFF && iFFs > 0) || bFFOverflow )
{
// Read function knows if there is a 0xFF, amount of 0xFF
// will be follow.
EEPROM.write( iAddress++, 0xFF );
// Write the amount of FF's
EEPROM.write( iAddress++, iFFs );
iFFCount+=iFFs;
// If there is no byte 'overflow' iFFs = 0, otherwise it is 1
iFFs = (uint8_t)bIsFF;
}
if( (!bIsZero && iZeros > 0) || bZeroOverflow )
{
// Read function knows if there is a zero, amount of zeros
// will be follow.
EEPROM.write( iAddress++, 0 );
// Write the amount of zero's
EEPROM.write( iAddress++, iZeros );
iZeroCount+=iZeros;
// If there is no byte 'overflow' iZeros = 0, otherwise it is 1
iZeros = (uint8_t)bIsZero;
}
// Avoid confusion writing a FF or zero
if( !bIsFF && !bIsZero )
{ EEPROM.write( iAddress++, iBits ); }
}
++i;
}
// Calculate stream size
iBits=iAddress-iSizeAddress-1;
// Write size of stream
EEPROM.write( iSizeAddress , *pByteSize++ );
EEPROM.write( iSizeAddress+1, *pByteSize );
Serial.print( "Zeros found: " );
Serial.println( iZeroCount );
Serial.print( "FF found: " );
Serial.println( iFFCount );
Serial.print( "SIZE: " );
Serial.println( iBits );
// return bytes written
return iBits+2;
}
bool TOLEDdisplay::readFromEeprom( uint16_t iAddress )
{
uint8_t bits = 0;
uint16_t i = 0;
uint8_t* pI = (uint8_t*)&i;
uint8_t iZeros = 0;
uint8_t iFFs = 0;
uint8_t iWidth = EEPROM.read( iAddress++ );
uint8_t iHeight = EEPROM.read( iAddress++ );
// Read stream size, read two bytes
*pI = EEPROM.read( iAddress++ );
*pI++;
*pI = EEPROM.read( iAddress++ );
// Clear the screen
clear();
Serial.print( "Size: " );
Serial.println( i );
Serial.print( "Width: " );
Serial.println( iWidth );
Serial.print( "Height: " );
Serial.println( iHeight );
// If an error (no image on EEPROM address) or screen bounds
// doesn't match, skip to continue
if( i == 0 || iWidth != width || iHeight != height )
{
update( true );
return false;
}
uint16_t iCacheAddress = 0;
while( i-- )
{
do {
if( iFFs == 0 && iZeros == 0 )
{
bits = EEPROM.read( iAddress++ );
if( bits == 0xFF )
{
// read amount of FF's minus this one
iFFs = EEPROM.read( iAddress++ )-1;
Serial.print( "iFFs: ");
Serial.println( iFFs );
}
else if( bits == 0x00 )
{
// read amount of zeros minus this one
iZeros = EEPROM.read( iAddress++ )-1;
Serial.print( "iZeros: ");
Serial.println( iZeros );
}
}
else {
if( iFFs > 0 )
{
--iFFs;
bits = 0xFF;
}
else if( iZeros > 0 )
{
--iZeros;
bits = 0x00;
}
}
setCacheRawBits( iCacheAddress, bits );
++iCacheAddress;
}
while( iFFs == 0 && iZeros == 0 );
}
update( true );
return true;
}
Any ideas?
NOTE:
I don't want to use any expensive compression method, 96% of program space is already in use and my method seems to work fine but with some error and I need to know the error, no alternative compression method. It has some compression already, bits in a byte to represent 8 pixels and just want to slim it down a bit (proven however with error at byte overflow).
The first time thru the loop, bFFOverflow and bZeroOverflow are accessed without having been initialized.
The main problem, though, is that after you record your 255 0 or 0xFF bytes, you set the count to 1 if there are more. However, this should be zero, since you detect the overflow after you've counted the 255th copy of that byte.
So always set bFFOverflow and bZeroOverflow to 0 writing out the counts.
After some sleep I redone it with much better results and less code, I overcomplicated such thing too much.
I got impressive results with it and think about to refine it with an examination method to find the best 'compression' by selecting the bytes that repeats the most and record this into the EEPROM 'file'.
Anyway, this is my code, much better comparing to the first one, maybe it can help others. It is very lightweight solution to save some bytes.
For example a blank screen or full filled screen with a resolution of 128x32 pixels results in only 9 bytes, half by half only 17 bytes. The screen I showed in the question before 'compiles' to only 405 bytes, a saving of about 100 bytes.
Here is my renewed code:
uint8_t TOLEDdisplay::getCacheRawBits( uint16_t iAddress )
{
if( iAddress < cacheSize )
{ return displayCache[ iAddress ]; }
return 0x00;
}
bool TOLEDdisplay::setCacheRawBits( uint16_t iAddress, uint8_t iBitByte )
{
if( iAddress < cacheSize )
{
displayCache[ iAddress ]=iBitByte;
return true;
}
return false;
}
uint16_t TOLEDdisplay::writeToEeprom( uint16_t iAddress )
{
if( cacheSize == 0 || width == 0 || height == 0 )
{ return 0; }
uint8_t iBits; // Pixel * 8 = byte
uint8_t iFoundBits; // 'Type' of detected
uint16_t iByteSize = 0; // Total byte size of stream
uint8_t iCount = 0; // Count of repeats found
bool bSame; // Boolean to evaluate repeats
// Write screen bounds, when read it back with readFromEeprom,
// these bounds need to match with current screen bounds.
EEPROM.write( iAddress++, width );
EEPROM.write( iAddress++, height );
// Reserve two bytes for stream size
uint16_t iSizeAddress = iAddress;
iAddress+=2;
// Write the cache content to the EEPROM
uint16_t i = 0;
while( i < cacheSize )
{
// Get a byte with bits
iBits = getCacheRawBits( i );
++i;
// Find repeating lines or empty lines
if( iBits == 0xFF || iBits == 0x00 )
{
iFoundBits = iBits; // Set found bits to detect changes
bSame = true; // Set to true to able to start loop
iCount=1; // Count this found one
// Loop to find duplicates
while( bSame && ( iCount < 0xFF ) && ( i < cacheSize ))
{
iBits = getCacheRawBits( i ); // Get next byte with bits
bSame = (iBits == iFoundBits); // Determine is repeat, the same
iCount+=bSame; // Increment count when same is found
i+=bSame;
}
// Finally write result to EEPROM
EEPROM.write( iAddress++, iFoundBits ); // type
// Write the amount
EEPROM.write( iAddress++, iCount ); // count
// Goto main loop and find next if any
}
else {
// Write found value normally to EEPROM
EEPROM.write( iAddress++, iBits );
}
}
// Final EOF address is one pos back
--iAddress;
// Calculate stream size
iByteSize=iAddress-iSizeAddress;
uint8_t* pByteSize = (uint8_t*)&iByteSize;
// Write size of stream
EEPROM.write( iSizeAddress , *pByteSize++ );
EEPROM.write( iSizeAddress+1, *pByteSize );
// return bytes written including width and height bytes (+2 bytes)
return iByteSize+2;
}
bool TOLEDdisplay::readFromEeprom( uint16_t iAddress )
{
uint8_t iBits;
uint8_t iRepeats;
uint16_t i = 0;
uint8_t* pI = (uint8_t*)&i;
uint8_t iWidth = EEPROM.read( iAddress++ );
uint8_t iHeight = EEPROM.read( iAddress++ );
// Read stream size, read two bytes
*pI = EEPROM.read( iAddress++ );
*pI++;
*pI = EEPROM.read( iAddress++ );
// Clear the screen
clear();
// If an error (no image on EEPROM address) or screen bounds
// doesn't match, skip to continue
if( i == 0 || iWidth != width || iHeight != height )
{
update( true ); // Set screen to blank
return false;
}
uint16_t iCacheAddress = 0;
while( i-- )
{
// Get a byte with bits
iBits = EEPROM.read( iAddress++ );
// Explode repeats if detected
if( iBits == 0xFF || iBits == 0x00 )
{
// read amount of repeats
iRepeats = EEPROM.read( iAddress++ );
// Explode it into cache
while( iRepeats-- )
{ setCacheRawBits( iCacheAddress++, iBits ); }
}
else {
// Put value normally into cache
setCacheRawBits( iCacheAddress++, iBits );
}
}
// Done, update the screen
update( true );
// Return success
return true;
}
Maybe I have to add some EEPROM boundry checks but for now it works fine.
I have two arrays:
unsigned char channeltab1[7][12]; //array which I receive from socket(Array is the same as below)
unsigned char equal_channeltab1[7][12] //arrays which I wants to compare with channeltab1
{
{0x10, 0x0f, 0x02, 0x02, 0x01, 0x00, 0x00, 0x06, 0x10, 0x0e, 0xff, 0xef},
{0x10, 0x0f, 0x02, 0x02, 0x02, 0x00, 0x00, 0x06, 0x10, 0x0e, 0xff, 0xef},
{0x10, 0x0f, 0x02, 0x02, 0x03, 0x00, 0x00, 0x06, 0x10, 0x0e, 0xff, 0xef},
{0x10, 0x0f, 0x02, 0x02, 0x04, 0x00, 0x00, 0x06, 0x10, 0x0e, 0xff, 0xef},
{0x10, 0x0f, 0x02, 0x02, 0x05, 0x00, 0x00, 0x06, 0x10, 0x0e, 0xff, 0xef},
{0x10, 0x0f, 0x02, 0x02, 0x06, 0x00, 0x00, 0x06, 0x10, 0x0e, 0xff, 0xef},
{0x10, 0x0f, 0x02, 0x02, 0x07, 0x00, 0x00, 0x06, 0x10, 0x0e, 0xff, 0xef},
};
I want compare this arrays, but function strcmp work only with one-dimensional arrays.
I try use strncmp:
for(int x = 0; x<7; x++)
{
for(int i =1; x<12;i++)
{
if (strncmp (reinterpret_cast<const char*>(channeltab1[x][i]),reinterpret_cast<const char*>(equal_channeltab1[x][i]),2) == 0)
{
/*...*/
}
else
{
/*...*/
}
}
}
But when application run this instruction says:
Memory fault
If i use:
for(int x = 0; x<7; x++)
{
if (strncmp (reinterpret_cast<const char*>(channeltab1[x]),reinterpret_cast<const char*>(equal_channeltab1[x]),2) == 0)
{
/*..*/
}
else
{
/*..*/
}
}
They are not the same for program.
What should I do?
Following may help:
bool is_equal(const unsigned char (&lhs)[7][12], const unsigned char (&rhs)[7][12])
{
for (int i = 0; i != 7; ++i) {
if (memcmp(lhs[i], rhs[i], 12) != 0) {
return false;
}
}
return true;
}
or even (thanks to Hanno Binder)
bool is_equal(const unsigned char (&lhs)[7][12], const unsigned char (&rhs)[7][12])
{
return memcmp(lhs, rhs, sizeof(lhs)) != 0;
}
You can simply use memcmp
(sizeof(channeltab1) == sizeof(equal_channeltab1)
&& (memcmp(channeltab1, equal_channeltab1, sizeof(equal_channeltab1)) == 0)
Note you have to make sure theirs sizes are equal.
I would suggest you to implement a new comparing function rather then trying to use these C functions. You can start from something like this:
bool checkEquals(unsigned char** a, unsigned char** b, size_t outterSize, size_t innerSize)
{
for (size_t i = 0; i < outterSize; ++i)
{
for (size_t j = 0; j < innerSize; ++j)
{
if (a[i][j] != b[i][j])
{
return false;
}
}
}
return true;
}
"strncmp" is used for standard "C" strings comparsion (or ASCII ones) not for data as it's in your case (data and arrays are always the same in "C++" language). So you should use 'memcpy' instead. So your code will look something like this:
for(int x = 0; x<7; x++)
{
if (memcmp((void*)channeltab1[x],(void*)equal_channeltab1[x], 12 * sizeof(unsigned char)) == 0)
{
/*equal*/
}
else
{
/*not equal*/
}
}
Use std::Array
std::array<unsigned char, 7*12> channeltab1;
std::array<unsigned char, 7*12> equal_channeltab1 = {
0x10, 0x0f, 0x02, 0x02, 0x01, 0x00, 0x00, 0x06, 0x10, 0x0e, 0xff, 0xef,
0x10, 0x0f, 0x02, 0x02, 0x02, 0x00, 0x00, 0x06, 0x10, 0x0e, 0xff, 0xef,
0x10, 0x0f, 0x02, 0x02, 0x03, 0x00, 0x00, 0x06, 0x10, 0x0e, 0xff, 0xef,
0x10, 0x0f, 0x02, 0x02, 0x04, 0x00, 0x00, 0x06, 0x10, 0x0e, 0xff, 0xef,
0x10, 0x0f, 0x02, 0x02, 0x05, 0x00, 0x00, 0x06, 0x10, 0x0e, 0xff, 0xef,
0x10, 0x0f, 0x02, 0x02, 0x06, 0x00, 0x00, 0x06, 0x10, 0x0e, 0xff, 0xef,
0x10, 0x0f, 0x02, 0x02, 0x07, 0x00, 0x00, 0x06, 0x10, 0x0e, 0xff, 0xef
};
and to compare, you can now do:
if (channeltab1 == equal_channeltab1){
//do stuff
}
note, an array[x*y] is the same as an array[x][y]
Multidimensional arrays are store in continuous memory so actually memcmp should work, memcmp avoids mistakes in the cast.
memcmp(channeltab1, equal_channeltab1, sizeof(channeltab1))
Edit: strncmp doesn't work because there could be zero's in the values.
I have a problem converting UTF8 encoded char array to CP1250 encoded char array.
I tried making a static iconv lib, but when compiling my UTF8->CP1250 code it always fail with
1>foo.obj : error LNK2001: unresolved external symbol libiconv_close
1>foo.obj : error LNK2001: unresolved external symbol libiconv_open
1>foo.obj : error LNK2001: unresolved external symbol libiconv
I also tried a lot of compiled static libraries, but always the same error.
Doesn't matter if /MD or /MT is set.
I do not insist on using iconv. Is there any other simple solution for this problem? Thanks
Since you're coding in Windows, why not use the Windows API. Use MultiByteToWideChar to convert losslessly up to UTF-16. Then use WideCharToMultiByte to convert down to e.g. CP 1250.
Addendum: the code below seems to work OK.
#include <assert.h> // assert
#include <iostream> // std::wcout, std::wcerr
#include <iterator> // std::begin, std::end
#include <string> // std::string, std::wstring
#include <stddef.h> // ptrdiff_t
#include <stdexcept> // std::system_error
#include <stdlib.h> // EXIT_SUCCESS
#include <string.h> // memcmp
#include <system_error> // std::system_error etc.
// Example of how to include Microsoft's <windows.h>.
// More support stuff is generally needed for more serious code.
#undef UNICODE
#define UNICODE
#undef NOMINMAX
#define NOMINMAX
#undef STRICT
#define STRICT
#include <windows.h> // E_FAIL, etc.
namespace cppx {
using std::begin;
using std::end;
using std::error_code;
using std::string;
using std::system_error;
using std::system_category;
typedef unsigned char Byte;
typedef ptrdiff_t Size;
template< class Type >
auto size( Type const& c )
-> Size
{ return end( c ) - begin( c ); }
auto hopefully( bool const condition ) -> bool { return condition; }
auto fail(
string const& message,
int const code = 0
)
-> bool
{
throw system_error(
error_code( code, system_category() ), message
);
}
} // namespace cppx
namespace data {
using cppx::Byte;
using cppx::hopefully;
using cppx::fail;
using std::string;
using std::wstring;
char const utf8_bom[] = "\xEF\xBB\xBF";
template< class Type, int n >
auto dummy()
-> Type&
{ static Type the_dummy; return the_dummy; }
auto utf16_from_utf8( char const* bytes, int length )
-> wstring
{
if( length >= 3 && ::memcmp( bytes, utf8_bom, 3 ) == 0 )
{
bytes += 3; length -= 3;
}
assert( length >= 0 );
if( length == 0 ) { return L""; }
int const buffer_size = ::MultiByteToWideChar(
CP_UTF8,
0, // flags, must be 0 for UTF-8
bytes,
length,
nullptr, // output buffer
0 // buffer size
);
hopefully( buffer_size > 0 )
|| fail( "MultiByteToWideChar (1st call)", ::GetLastError() );
wstring result( buffer_size, L'#' );
int const n_encoding_values = ::MultiByteToWideChar(
CP_UTF8,
0, // flags, must be 0 for UTF-8
bytes,
length,
&result[0], // output buffer
buffer_size
);
hopefully( n_encoding_values > 0 )
|| fail( "MultiByteToWideChar (2nd call)", ::GetLastError() );
assert( n_encoding_values <= buffer_size );
result.resize( n_encoding_values ); // Possible down-sizing.
return result;
}
auto utf16_from_utf8( Byte const* const bytes, int const length )
-> wstring
{
return utf16_from_utf8( reinterpret_cast<char const*>( bytes ), length );
}
auto sbcs_from(
wchar_t const* const s,
int const length,
unsigned const codepage = ::GetACP(),
bool& used_default_char = dummy<bool, 1>()
)
-> string
{
assert( codepage != CP_UTF8 );
if( length == 0 ) { return ""; }
DWORD const flags = WC_NO_BEST_FIT_CHARS; // Must be 0 for UTF-8.
char const* const default_char = "\x7F"; // ASCII DEL
int const buffer_size = WideCharToMultiByte(
codepage,
flags,
s,
length,
nullptr, // buffer
0, // buffer size
default_char,
nullptr
);
hopefully( buffer_size > 0 )
|| fail( "WideCharToMultiByte (1st call)", ::GetLastError() );
string result = string( buffer_size, '#' );
BOOL defaulted = false;
int const n_bytes = WideCharToMultiByte(
codepage,
flags,
s,
length,
&result[0], // buffer
buffer_size,
default_char,
&defaulted
);
hopefully( n_bytes > 0 )
|| fail( "WideCharToMultiByte (2nd call)", ::GetLastError() );
assert( n_bytes <= buffer_size );
result.resize( n_bytes );
used_default_char = !!defaulted;
return result;
}
auto sbcs_from(
wstring const& s,
unsigned const codepage = ::GetACP(),
bool& used_default_char = dummy<bool, 1>()
)
-> string
{
if( s.length() == 0 ) { return ""; }
return sbcs_from( &s[0], s.length(), codepage, used_default_char );
}
} // namespace data
void cpp_main()
{
using cppx::Byte;
using cppx::fail;
using cppx::size;
using std::string;
using std::wstring;
auto const infobox = MB_ICONINFORMATION | MB_SETFOREGROUND;
Byte const utf8_bytes[] = // UTF-8 with BOM, as if from a file.
{
0xEF, 0xBB, 0xBF, 0x42, 0x6C, 0xC3, 0xA5, 0x62, 0xC3, 0xA6,
0x72, 0x73, 0x79, 0x6C, 0x74, 0x65, 0x74, 0xC3, 0xB8, 0x79,
0x21, 0x20, 0xE6, 0x97, 0xA5, 0xE6, 0x9C, 0xAC, 0xE5, 0x9B,
0xBD, 0x20, 0xD0, 0xBA, 0xD0, 0xBE, 0xD1, 0x88, 0xD0, 0xBA,
0xD0, 0xB0, 0x21, 0x0D, 0x0A, 0x0D, 0x0A, 0x48, 0x75, 0x6E,
0x67, 0x61, 0x72, 0x69, 0x61, 0x6E, 0x20, 0x61, 0x6C, 0x70,
0x68, 0x61, 0x62, 0x65, 0x74, 0x3A, 0x0D, 0x0A, 0x41, 0x20,
0xC3, 0x81, 0x20, 0x42, 0x20, 0x43, 0x20, 0x43, 0x73, 0x20,
0x44, 0x20, 0x44, 0x7A, 0x20, 0x44, 0x7A, 0x73, 0x20, 0x45,
0x20, 0xC3, 0x89, 0x20, 0x46, 0x20, 0x47, 0x20, 0x47, 0x79,
0x20, 0x48, 0x20, 0x49, 0x20, 0xC3, 0x8D, 0x20, 0x4A, 0x20,
0x4B, 0x20, 0x4C, 0x20, 0x4C, 0x79, 0x20, 0x4D, 0x20, 0x4E,
0x0D, 0x0A, 0x4E, 0x79, 0x20, 0x4F, 0x20, 0xC3, 0x93, 0x20,
0xC3, 0x96, 0x20, 0xC5, 0x90, 0x20, 0x50, 0x20, 0x28, 0x51,
0x29, 0x20, 0x52, 0x20, 0x53, 0x20, 0x53, 0x7A, 0x20, 0x54,
0x20, 0x54, 0x79, 0x20, 0x55, 0x20, 0xC3, 0x9A, 0x20, 0xC3,
0x9C, 0x20, 0xC5, 0xB0, 0x20, 0x56, 0x20, 0x28, 0x57, 0x29,
0x20, 0x28, 0x58, 0x29, 0x20, 0x28, 0x59, 0x29, 0x20, 0x5A,
0x20, 0x5A, 0x73, 0x0D, 0x0A
};
wstring const text = data::utf16_from_utf8( utf8_bytes, size( utf8_bytes ) );
::MessageBox( 0, text.c_str(), L"Original text:", infobox );
string const sbcs_text = data::sbcs_from( text, 1250 );
WORD const hungarian = MAKELANGID(
LANG_HUNGARIAN, SUBLANG_HUNGARIAN_HUNGARY
);
DWORD const hungarian_locale_id = MAKELCID( hungarian, SORT_DEFAULT );
SetThreadLocale( hungarian_locale_id )
|| fail( "SetThreadLocale", ::GetLastError() );
DWORD thread_cp = 0;
::GetLocaleInfo(
::GetThreadLocale(), // Not LOCALE_USER_DEFAULT,
LOCALE_IDEFAULTANSICODEPAGE | LOCALE_RETURN_NUMBER,
reinterpret_cast<wchar_t*>( &thread_cp ),
sizeof( thread_cp )/sizeof( wchar_t )
)
|| fail( "GetLocaleInfo", ::GetLastError() );
//::MessageBox( 0, std::to_wstring( thread_cp ).c_str(), L"Codepage:", MB_SETFOREGROUND );
assert( thread_cp == 1250 );
::MessageBoxA( 0, sbcs_text.c_str(), "SBCS codepage 1250 text:", infobox );
}
auto main()
-> int
{
using namespace std;
try
{
cpp_main();
return EXIT_SUCCESS;
}
catch( system_error const& x )
{
auto const code = x.code().value();
cerr << "!" << x.what() << " (code: " << code << ")" << endl;
return code;
}
catch( exception const& x )
{
cerr << "!" << x.what() << endl;
return E_FAIL;
}
}
Example output (Windows messageboxes):
And yes, the dummy function is an abomination, unsound and ungood, but hey. :)
#pragma once
#include <string>
#include <vector>
#include <stdint.h>
class PasswordCrypt
{
public:
PasswordCrypt(std::vector<uint8_t> buffer);
~PasswordCrypt(void);
void PassCrypto(std::vector<uint8_t> buffer);
const std::vector<uint8_t>& Encrypt(const std::vector<uint8_t>& buffer);
const std::vector<uint8_t>& Decrypt(std::vector<uint8_t>& buffer);
private:
uint8_t* key;
};
--------------------------------------------------------------------------------------
#include "PasswordCrypt.h"
PasswordCrypt::PasswordCrypt(std::vector<uint8_t> buffer)
{
this->key = new uint8_t[200];
int sum = 0;
for (int i = 0 ; i< buffer.size() ;i++)
sum += buffer[i];
srand(sum);
uint8_t hash[0x10];
for (int i = 0; i < 0x10; i++)
hash[i] =(uint8_t)rand();
for (int i = 1; i < 0x100; i++)
{
key[i * 2] = (uint8_t)i;
key[(i * 2) + 1] = (uint8_t)(i ^ hash[i & 0x0F]);
}
for (int i = 1; i < 0x100; i++)
for (int j = 1 + i; j < 0x100; j++)
if (key[(i * 2) + 1] < key[(j * 2) + 1])
{
key[i * 2] ^= key[j * 2];
key[j * 2] ^= key[i * 2];
key[i * 2] ^= key[j * 2];
key[(i * 2) + 1] ^= key[(j * 2) + 1];
key[(j * 2) + 1] ^= key[(i * 2) + 1];
key[(i * 2) + 1] ^= key[(j * 2) + 1];
}
}
PasswordCrypt::~PasswordCrypt(void)
{
delete[] this->key;
}
const uint8_t scanCodeToVirtualKeyMap[] =
{
0x00, 0x1B, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x30, 0xBD, 0xBB, 0x08, 0x09,
0x51, 0x57, 0x45, 0x52, 0x54, 0x59, 0x55, 0x49, 0x4F, 0x50, 0xDB, 0xDD, 0x0D, 0x11, 0x41, 0x53,
0x44, 0x46, 0x47, 0x48, 0x4A, 0x4B, 0x4C, 0xBA, 0xC0, 0xDF, 0x10, 0xDE, 0x5A, 0x58, 0x43, 0x56,
0x42, 0x4E, 0x4D, 0xBC, 0xBE, 0xBF, 0x10, 0x6A, 0x12, 0x20, 0x14, 0x70, 0x71, 0x72, 0x73, 0x74,
0x75, 0x76, 0x77, 0x78, 0x79, 0x90, 0x91, 0x24, 0x26, 0x21, 0x6D, 0x25, 0x0C, 0x27, 0x6B, 0x23,
0x28, 0x22, 0x2D, 0x2E, 0x2C, 0x00, 0xDC, 0x7A, 0x7B, 0x0C, 0xEE, 0xF1, 0xEA, 0xF9, 0xF5, 0xF3,
0x00, 0x00, 0xFB, 0x2F, 0x7C, 0x7D, 0x7E, 0x7F, 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0xED,
0x00, 0xE9, 0x00, 0xC1, 0x00, 0x00, 0x87, 0x00, 0x00, 0x00, 0x00, 0xEB, 0x09, 0x00, 0xC2, 0x00,
};
const uint8_t virtualKeyToScanCodeMap[] =
{
0x00, 0x00, 0x00, 0x46, 0x00, 0x00, 0x00, 0x00, 0x0E, 0x0F, 0x00, 0x00, 0x4C, 0x1C, 0x00, 0x00,
0x2A, 0x1D, 0x38, 0x00, 0x3A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
0x39, 0x49, 0x51, 0x4F, 0x47, 0x4B, 0x48, 0x4D, 0x50, 0x00, 0x00, 0x00, 0x54, 0x52, 0x53, 0x63,
0x0B, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x1E, 0x30, 0x2E, 0x20, 0x12, 0x21, 0x22, 0x23, 0x17, 0x24, 0x25, 0x26, 0x32, 0x31, 0x18,
0x19, 0x10, 0x13, 0x1F, 0x14, 0x16, 0x2F, 0x11, 0x2D, 0x15, 0x2C, 0x5B, 0x5C, 0x5D, 0x00, 0x5F,
0x52, 0x4F, 0x50, 0x51, 0x4B, 0x4C, 0x4D, 0x47, 0x48, 0x49, 0x37, 0x4E, 0x00, 0x4A, 0x53, 0x35,
0x3B, 0x3C, 0x3D, 0x3E, 0x3F, 0x40, 0x41, 0x42, 0x43, 0x44, 0x57, 0x58, 0x64, 0x65, 0x66, 0x67,
0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x45, 0x46, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x2A, 0x36, 0x1D, 0x1D, 0x38, 0x38, 0x6A, 0x69, 0x67, 0x68, 0x65, 0x66, 0x32, 0x20, 0x2E, 0x30,
0x19, 0x10, 0x24, 0x22, 0x6C, 0x6D, 0x6B, 0x21, 0x00, 0x00, 0x27, 0x0D, 0x33, 0x0C, 0x34, 0x35,
0x28, 0x73, 0x7E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1A, 0x56, 0x1B, 0x2B, 0x29,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x71, 0x5C, 0x7B, 0x00, 0x6F, 0x5A, 0x00,
0x00, 0x5B, 0x00, 0x5F, 0x00, 0x5E, 0x00, 0x00, 0x00, 0x5D, 0x00, 0x62, 0x00, 0x00, 0x00, 0x00
};
const std::vector<uint8_t>& PasswordCrypt::Encrypt(const std::vector<uint8_t>& buffer)
{
std::vector<uint8_t> result(buffer.size());
for (int i = 0; i < buffer.size(); i++)
{
bool upper = false;
if (buffer[i] == 0) break;
else
{
uint8_t b =this->key[buffer[i] * 2];
if (b > 0x80)
{
b = (uint8_t)(this->key[buffer[i] * 2] - 0x80);
upper = true;
}
result[i] += scanCodeToVirtualKeyMap[b];
}
if (!upper && result[i] >= 'A' && result[i] <= 'Z') result[i] += 'a' - 'A';
}
return result;
}
const std::vector<uint8_t>& PasswordCrypt::Decrypt(std::vector<uint8_t>& buffer)
{
std::vector<uint8_t> result(buffer.size(), 0);
for (int j = 0; j < buffer.size(); j++)
{
uint8_t c = buffer[j];
if (buffer[j] >= 'a' && buffer[j] <= 'z')
buffer[j] -= 'a' - 'A';
uint8_t d = virtualKeyToScanCodeMap[buffer[j]];
if (c >= 'A' && c <= 'Z')
d += 0x80;
for (uint8_t i = 0; i <= 255; i++)
{
uint8_t b = (uint8_t)this->key[i * 2];
if (b == d)
{
result[j] = i;
break;
}
}
}
return result;
}
---------------------------------------------------------------------------------------
#include <iostream>
#include <Windows.h>
#include <string>
#include <stdint.h>
#include "PasswordCrypt.h"
#include <iomanip>
using namespace std;
void output_hex(std::ostream& out, std::vector<uint8_t>& data) {
for (std::vector<uint8_t>::iterator i=data.begin();i<data.end();i++)
out << std::hex
<< std::setw(2)
<< std::setfill('0')
<< static_cast<int>(data[*i])
<< " ";
out << endl;
}
int main()
{
std::string test="Hellow World!";
std::vector<uint8_t> buf(test.begin(), test.end());
PasswordCrypt dec(buf);
//output_hex(cout, buf);
std::vector<uint8_t> enced = dec.Encrypt(buf);
//output_hex(cout, enced);
std::vector<uint8_t> deced = dec.Decrypt(enced);
//output_hex(cout, deced);
system("pause");
return 0;
}
Error:
Windows has triggered a breakpoint in
testcrypto.exe.
This may be due to a corruption of the
heap, which indicates a bug in
testcrypto.exe or any of the DLLs it
has loaded.
This may also be due to the user
pressing F12 while testcrypto.exe has
focus.
You have a classic buffer overrun. Here you allocate 200 bytes for key:
this->key = new uint8_t[200];
Here, however:
for (int i = 1; i < 0x100; i++)
{
key[i * 2] = (uint8_t)i;
You (attempt to) write to k[2] through key[2 * 0x100]. 2 * 0x100 is 0x200, which is 512 in decimal. It would appear that where you allocate the buffer, you should really allocate 0x200 elements.
Some of the other code looks like it tries to access key[0x200] -- to make that work, you'd want/need to allocate 0x201 elements (0x200 elements will run from key[0] through key[0x1ff] inclusive).
Edit: doing a bit more looking, it gets even worse. Perhaps putting these three lines next to each other will make the next problem more obvious:
const std::vector<uint8_t>& PasswordCrypt::Encrypt(const std::vector<uint8_t>& buffer)
{
std::vector<uint8_t> result(buffer.size());
[ ...]
return result;
You're returning a reference to a local variable, so the caller receives a dangling reference.
j < 0x100;
0x100 is not the same as 100. It's 256. And your key array is only 200 elements long.
You then go off and try to access key[j * 2], which is way off the end of the array, trampling all over random bits of memory. That's your problem.
Your other problem is using xor-swapping instead of something more readable - while you might think it's a "neat trick", it really isn't. It makes things much less legible and doesn't provide any meaningful performance benefit.