How to execute multi parameter ODBC command by C++ - odbc

I'm working on an ODBC program that needs to store two types of long data: nvarchar (max) and nvarbinary (max). It works well when I do it with one parameter, but it gives an error for two parameters. secound loop for SQL_NEED_DATA gives odbc error
ERROR ==> [ODBC SQL Server Driver]Invalid character value for cast specification
.My code is as follows:
bool ExecuteQuery(wstring const& command_text,vector<void*> params)
{
SQLWCHAR* blob = nullptr;// (SQLWCHAR*)params[0];
SQLSMALLINT NumParams;
SQLSMALLINT i, sql_type, decimals, nullable, paramNo;
SQLULEN bytes;
RETCODE retcode;
SQLLEN cbTextSize, valueMax = 0;
vector<SQLLEN> lbytes;
PTR pParamID;
SQLLEN len;
vector<SDWORD> cbBatch;
SQLPOINTER pToken = NULL;
retcode = SQLPrepare(hstmt, (SQLWCHAR*)command_text.c_str(), SQL_NTS);
//Get number of parameters
SQLNumParams(hstmt, &NumParams);
for (i = 0; i < NumParams; i++)
{
size_t length = wcslen((wchar_t*)params[i]);
//This ia important to save all data to sql table
size_t size = length * sizeof(wchar_t);
len = SQL_LEN_DATA_AT_EXEC((SQLLEN)size);
retcode = SQLDescribeParam(hstmt, i + 1, &sql_type, &bytes, &decimals, &nullable);
//SQL_C_WCHAR for hex binary data in wchar_t and SQL_WLONGVARCHAR succeeded
short c_type = map_datatype_SQL_to_C(sql_type);
retcode = SQLBindParameter(hstmt, i + 1, INPUT, c_type, sql_type, bytes, decimals, (PTR)(1+i), 0, &len);
}
//Execute the insert query.
retcode = SQLExecute(hstmt);
// Check for EOD marker.
retcode = SQLParamData(hstmt, &pToken);
//Loop, sending the data in segments of 124
int buffer_size = sizeof(wchar_t);
int chunk = 124;
for (i = 0; i < NumParams; i++)
{
size_t length = wcslen((wchar_t*)params[i]);
blob = (wchar_t*)params[i];
while (retcode == SQL_NEED_DATA)
{
while (length > chunk)
{
retcode = SQLPutData(hstmt, blob, static_cast<SQLLEN>(chunk * buffer_size));
extract_error("", hstmt, SQL_HANDLE_STMT);
blob += chunk;
length -= chunk;
}
retcode = SQLPutData(hstmt, blob, length * buffer_size);
extract_error("", hstmt, SQL_HANDLE_STMT);
}
retcode = SQLParamData(hstmt, &pToken);
}
return SQL_SUCCEEDED(retcode);
}
short map_datatype_SQL_to_C(short sql_type)
{
switch (sql_type)
{
case SQL_TINYINT:return SQL_C_TINYINT;
case SQL_LONGVARBINARY://-4
case SQL_VARBINARY://-3
case SQL_WLONGVARCHAR://-10
case SQL_WVARCHAR: //-9
case SQL_WCHAR: //-8
return SQL_C_WCHAR;// = SQL_C_TCHAR -8
case SQL_BIT:return SQL_C_BIT;
case SQL_BINARY://-2
return SQL_C_BINARY;
case SQL_DOUBLE://8 - FLOAT, DOUBLE
return SQL_C_DOUBLE;
case SQL_SMALLINT://5
return SQL_C_SHORT;
case SQL_FLOAT://6
case SQL_REAL: //7
return SQL_C_FLOAT;//7
case SQL_INTEGER://4
return SQL_C_LONG;
case SQL_CHAR://1
case SQL_VARCHAR://12
case SQL_DECIMAL://3
case SQL_NUMERIC://2
return SQL_C_CHAR;// CHAR, VARCHAR, DECIMAL, NUMERIC
case SQL_TYPE_TIMESTAMP:return SQL_C_TIMESTAMP;
case SQL_TIME:return SQL_C_TIME;
case SQL_DATE:return SQL_C_DATE;
case SQL_GUID:return SQL_C_GUID;
default:return SQL_UNKNOWN_TYPE;
}
return 0;
}

Related

Why nghttp2_session_mem_recv does not call any callback? (language: C, library: nghttp2)

ssize_t readlen;
struct evbuffer *input = bufferevent_get_input(bev);
size_t datalen = evbuffer_get_length(input);
unsigned char *data = evbuffer_pullup(input, -1);
readlen = nghttp2_session_mem_recv(session, data, datalen);
if (readlen < 0) {
printf("Fatal error: %s\n", nghttp2_strerror((int)readlen));
return;
}
if (evbuffer_drain(input, (size_t)readlen) != 0) {
printf("Fatal error: evbuffer_drain failed\n");
return;
}
nghttp2_session_mem_recv function does not call any callback even though it has all the callbacks set and the result returned by it is a valid one (return 130 and datalen is also 130).

how to split a string into words in arduino?

I have a string in arduino
String name="apple orange banana";
Is it possible to store each item in an array arr
so that
arr[0]="apple"
arr[1]="orange" ......etc
if not store them in individual variables?
How to split a string using a specific delimiter in Arduino? I believe this would help you, you could do a while loop like:
int x;
String words[3];
while(getValue(name, ' ', x) != NULL){
words[x] = getValue(name, ' ', x);
}
Using this function:
// https://stackoverflow.com/questions/9072320/split-string-into-string-array
String getValue(String data, char separator, int index)
{
int found = 0;
int strIndex[] = {0, -1};
int maxIndex = data.length()-1;
for(int i=0; i<=maxIndex && found<=index; i++){
if(data.charAt(i)==separator || i==maxIndex){
found++;
strIndex[0] = strIndex[1]+1;
strIndex[1] = (i == maxIndex) ? i+1 : i;
}
}
return found>index ? data.substring(strIndex[0], strIndex[1]) : "";
}
If you know your list length and the max characters per list item, you could do
char arr[3][6] = {"apple", "orange", banana"};
edit: if you are looking for something like String arr[3] you aren't going to get it because of how memory is managed with the C language

Always getting same encrypted string with CryptoAPI

Is there a way to get a non-deterministic output from the CryptoAPI? In other words, a different string output when encrypting a string.
For example, using CALG_AES_256 when deriving a crypt key with password of 'password' and string to encrypt of 'a', it always returns "SnÆwÞ¢L\x1e?6FÏLþw"
I'm somewhat of a n00b in using CryptoAPI, so any assistance is appreciated.
Edited:
Here is the cryptography code from Microsoft's example code decrypte and encrypt This is the same code, just shortened/compacted. This code was compiled in VS 2017 as a Win32 Console app. pszSource and pszDest are two files in the C:\temp folder. source.txt has the letter we're trying to encrypt in it.
The problem I'm having is that this crypt/decrypt code from the CryptoAPI does not allow certain strings to be encrypted and then decrypted (i.e. n, t, L, p, aa, ab, ac, ad, ae, etc). If someone can tell me why, that would be very helpful.
#include <windows.h>
#include <tchar.h>
#include <wincrypt.h>
#define KEYLENGTH 0x00800000
#define ENCRYPT_BLOCK_SIZE 8
bool MyDecryptFile(LPTSTR szSource,LPTSTR szDestination,LPTSTR szPassword);
bool MyEncryptFile(LPTSTR szSource,LPTSTR szDestination,LPTSTR szPassword);
int _tmain(int argc, _TCHAR* argv[])
{
LPTSTR pszSource = L"c:\\temp\\source.txt";
LPTSTR pszDestination = L"c:\\temp\\dest.txt";
LPTSTR pszPassword = L"t";
if (MyEncryptFile(pszSource, pszDestination, pszPassword))
{
_tprintf(TEXT("Encryption of the file %s was successful. \n"),pszSource);
_tprintf(TEXT("The encrypted data is in file %s.\n"),pszDestination);
}
if (MyDecryptFile(pszSource, pszDestination, pszPassword))
{
_tprintf(TEXT("Encryption of the file %s was successful. \n"),pszSource);
_tprintf(TEXT("The encrypted data is in file %s.\n"),pszDestination);
}
return 0;
}
bool MyEncryptFile(LPTSTR pszSourceFile,LPTSTR pszDestinationFile,LPTSTR pszPassword)
{
bool fReturn = false;
HANDLE hSourceFile = INVALID_HANDLE_VALUE, hDestinationFile = INVALID_HANDLE_VALUE;
HCRYPTPROV hCryptProv = NULL;
HCRYPTKEY hKey = NULL, hXchgKey = NULL;
HCRYPTHASH hHash = NULL;
PBYTE pbBuffer = NULL;
DWORD dwBlockLen, dwBufferLen, dwCount;
hSourceFile = CreateFile(pszSourceFile,FILE_READ_DATA,FILE_SHARE_READ,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL);
if (INVALID_HANDLE_VALUE == hSourceFile)
goto Exit_MyEncryptFile;
hDestinationFile = CreateFile(pszDestinationFile,FILE_WRITE_DATA,FILE_SHARE_READ,NULL,OPEN_ALWAYS,FILE_ATTRIBUTE_NORMAL,NULL);
if (INVALID_HANDLE_VALUE == hDestinationFile)
goto Exit_MyEncryptFile;
CryptAcquireContext(&hCryptProv,NULL,MS_ENH_RSA_AES_PROV,PROV_RSA_AES,0);
CryptCreateHash(hCryptProv,CALG_SHA_256,0,0,&hHash);
CryptHashData(hHash,(BYTE *)pszPassword,lstrlen(pszPassword),0);
CryptDeriveKey(hCryptProv,CALG_AES_256,hHash,CRYPT_EXPORTABLE,&hKey);
dwBlockLen = 1000 - 1000 % ENCRYPT_BLOCK_SIZE;
if (ENCRYPT_BLOCK_SIZE > 1)
dwBufferLen = dwBlockLen + ENCRYPT_BLOCK_SIZE;
else
dwBufferLen = dwBlockLen;
pbBuffer = (BYTE *)malloc(dwBufferLen);
bool fEOF = FALSE;
do
{
if (ReadFile(hSourceFile,pbBuffer,dwBlockLen,&dwCount,NULL))
{
if (dwCount < dwBlockLen)
fEOF = TRUE;
if (CryptEncrypt(hKey,NULL,fEOF,0,pbBuffer,&dwCount,dwBufferLen))
WriteFile(hDestinationFile,pbBuffer,dwCount,&dwCount,NULL);
}
}
while (!fEOF);
fReturn = true;
Exit_MyEncryptFile:
if (hSourceFile) CloseHandle(hSourceFile);
if (hDestinationFile) CloseHandle(hDestinationFile);
if (pbBuffer) free(pbBuffer);
if (hHash) {CryptDestroyHash(hHash);hHash = NULL;}
if (hKey) CryptDestroyKey(hKey);
if (hCryptProv) CryptReleaseContext(hCryptProv, 0);
return fReturn;
}
bool MyDecryptFile(LPTSTR pszSourceFile,LPTSTR pszDestinationFile,LPTSTR pszPassword)
{
bool fReturn = false;
HANDLE hSourceFile = INVALID_HANDLE_VALUE, hDestinationFile = INVALID_HANDLE_VALUE;
HCRYPTKEY hKey = NULL;
HCRYPTHASH hHash = NULL;
HCRYPTPROV hCryptProv = NULL;
PBYTE pbBuffer = NULL;
DWORD dwCount, dwBlockLen, dwBufferLen;
hSourceFile = CreateFile(pszDestinationFile,FILE_READ_DATA,FILE_SHARE_READ,NULL,OPEN_ALWAYS,FILE_ATTRIBUTE_NORMAL,NULL);
if (INVALID_HANDLE_VALUE == hSourceFile)
goto Exit_MyDecryptFile;
hDestinationFile = CreateFile(pszSourceFile,FILE_WRITE_DATA,FILE_SHARE_READ,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL);
if (INVALID_HANDLE_VALUE == hDestinationFile)
goto Exit_MyDecryptFile;
CryptAcquireContext(&hCryptProv,NULL,MS_ENH_RSA_AES_PROV,PROV_RSA_AES,0);
CryptCreateHash(hCryptProv,CALG_SHA_256,0,0,&hHash);
CryptHashData(hHash,(BYTE *)pszPassword,lstrlen(pszPassword),0);
CryptDeriveKey(hCryptProv,CALG_AES_256,hHash,CRYPT_EXPORTABLE,&hKey);
dwBlockLen = 1000 - 1000 % ENCRYPT_BLOCK_SIZE;
dwBufferLen = dwBlockLen;
pbBuffer = (PBYTE)malloc(dwBufferLen);
bool fEOF = false;
do
{
if (!ReadFile(hSourceFile,pbBuffer,dwBlockLen,&dwCount,NULL))
goto Exit_MyDecryptFile;
if (dwCount <= dwBlockLen)
fEOF = TRUE;
LONG rv = CryptDecrypt(hKey,0,fEOF,0,pbBuffer,&dwCount);
if (rv==0)
{
DWORD dwErr = GetLastError(); // <--- fails if password and string are n, t, L, p, aa, ab, ac, ad , ae
goto Exit_MyDecryptFile;
}
if (!WriteFile(hDestinationFile,pbBuffer,dwCount,&dwCount,NULL))
goto Exit_MyDecryptFile;
}
while (!fEOF);
fReturn = true;
Exit_MyDecryptFile:
if (pbBuffer) free(pbBuffer);
if (hSourceFile) CloseHandle(hSourceFile);
if (hDestinationFile) CloseHandle(hDestinationFile);
if (hHash) {CryptDestroyHash(hHash);hHash = NULL;}
if (hKey) CryptDestroyKey(hKey);
if (hCryptProv) CryptReleaseContext(hCryptProv, 0);
return fReturn;
}
What about using this to get the KP_IV option?
BOOL bRV;
bRV = CryptAcquireContextW(&hCryptProv, NULL, MS_ENH_RSA_AES_PROV, PROV_RSA_AES, 0);
bRV = CryptGenKey(hCryptProv, CALG_AES_256,0,&hKey);
DWORD dwMode = CRYPT_MODE_CBC;
bRV = CryptSetKeyParam(hKey,KP_MODE,(BYTE*)&dwMode,0);
BYTE pbData[16];
memcpy(pbData,"n",sizeof("n")); // <--- Hard coded password
bRV = CryptSetKeyParam(hKey,KP_IV,pbData,0);
enter code here
If you want to obtain different cypertext when encrypting the same plaintext with the same key, you have to use the CBC mode of operation:
https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation
In order to correctly encrypt with CBC, you need to generate a different random Initialization Vector (IV) every time.
In order to decrypt, you need to know the IV used during encryption.
So, the IV must be associated (in clear) to the cyphertext.
In reference to your example, when calling the CryptDeriveKey function, the CBC is the default mode but it uses an IV set to zero and this invalidates the utility of the CBC operating mode:
https://msdn.microsoft.com/en-us/library/windows/desktop/aa379916(v=vs.85).aspx
In order to set the random IV you need to call the CryptSetKeyParam function, which accept the KP_IV param:
https://msdn.microsoft.com/en-us/library/windows/desktop/aa380272(v=vs.85).aspx
Bye
Giovanni

how to tokenize a string in arduino

i am using arduino due. what i am trying to do is to receive a string at serial. like this one:
COMSTEP 789 665 432 END
if the string starts with comstep, then to tokenize the string and get an integer array {789, 665, 432}.
is there anyway to do that?
P.S: im a noob at programming, so any help is appreciated.
I have a function that I wrote long ago to parse strings up in an easy manner. It is in use on several of my Arduino projects.
Sample usage:
char pinStr[3];
char valueStr[7];
int pinNumber, value;
getstrfld (parms_in, 0, 0, (char *)",", pinStr);
getstrfld (parms_in, 1, 0, (char *)",", valueStr);
pinNumber = atoi (pinStr);
value = atoi (valueStr);
The functions:
// My old stand-by to break delimited strings up.
char * getstrfld (char *strbuf, int fldno, int ofset, char *sep, char *retstr)
{
char *offset, *strptr;
int curfld;
offset = strptr = (char *)NULL;
curfld = 0;
strbuf += ofset;
while (*strbuf) {
strptr = !offset ? strbuf : offset;
offset = strpbrk ((!offset ? strbuf : offset), sep);
if (offset) {
offset++;
} else if (curfld != fldno) {
*retstr = 0;
break;
}
if (curfld == fldno) {
strncpy (retstr, strptr,
(int)(!offset ? strlen (strptr)+ 1 :
(int)(offset - strptr)));
if (offset)
retstr[offset - strptr - 1] = 0;
break;
}
curfld++;
}
return retstr;
}
// Included because strpbrk is not in the arduino gcc/g++ libraries
// Or I just could not find it :)
char * strpbrk (const char *s1, const char *s2)
{
const char *c = s2;
if (!*s1) {
return (char *) NULL;
}
while (*s1) {
for (c = s2; *c; c++) {
if (*s1 == *c)
break;
}
if (*c)
break;
s1++;
}
if (*c == '\0')
s1 = NULL;
return (char *) s1;
}
A light-weight approach (no strict checks on valid parses of the integers and ignoring any list elements past a fixed maximum):
char buf[32] = "COMSTEP 789 665 432 END"; // assume this has just been read
int res[8], nres = 0;
bool inlist = false;
for (char *p = strtok(buf, " "); p; p = strtok(0, " "))
if (inlist)
{
if (!strcmp(p, "END"))
{
inlist = false;
break;
}
else if (nres < sizeof(res) / sizeof(*res))
res[nres++] = atoi(p);
}
else if (!strcmp(p, "COMSTEP"))
inlist = true;
if (!inlist)
for (size_t i = 0; i < nres; ++i)
printf("%d%s", res[i], i + 1 < nres ? " " : "\n"); // do whatever

android hexToByteArray signed to unsigned

I've got the following function to make a conversion from a Hex String to a Byte array. Then, I calculate the Checksum:
private String CalcChecksum (String message) {
/**Get string's bytes*/
//byte[] bytes = DatatypeConverter.parseHexBinary(message.replaceAll("\\s","")).getBytes();
message = message.replaceAll("\\s","");
byte[] bytes = hexToByteArray(message);
byte b_checksum = 0;
for (int byte_index = 0; byte_index < bytes.length; byte_index++) {
b_checksum += bytes[byte_index];
}
int d_checksum = b_checksum; //Convert byte to int(2 byte)
int c2_checksum = 256 - d_checksum; //Hacer complemento a 2
String hexString = Integer.toHexString(c2_checksum); //Convertir el entero (decimal) a hexadecimal
return hexString;
}
public static byte[] hexToByteArray(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;
}
Making some test, for example for the hex value "e0", the hexToByteArray is getting the value "-32". So the final returning value in the CalcChecksum is "17a".
What I need is to get unsigned values in the hexToByteArray function. This is because i need to send the Checksum in a hexString to a MCU where the Checksum is calculated with unsigned values, so isntead of get the "-32" value, it gets "224" and the final hex value is "7a" instead of "17a".
i think that doing some kind of conversion like when the byte result is a negative value, do something like 255 + "negative value" + 1. This will convert "-32" into "224".
The problem is that i'm trying to do it, but i'm having some errors making the conversions between bytes, int, etc...
So, how could i do?
For the moment, I think that this can be the solution.
Just including in the CalcChecksum function the next code after int d_checksum = b_checksum;:
if (d_checksum < 0) {
d_checksum = 255 + d_checksum + 1;
}

Resources