#include "dpiImpl.h"
int dpiUtils__allocateMemory(size_t numMembers, size_t memberSize,
int clearMemory, const char *action, void **ptr, dpiError *error)
{
if (clearMemory)
*ptr = calloc(numMembers, memberSize);
else *ptr = malloc(numMembers * memberSize);
if (!*ptr)
return dpiError__set(error, action, DPI_ERR_NO_MEMORY);
if (dpiDebugLevel & DPI_DEBUG_LEVEL_MEM)
dpiDebug__print("allocated %u bytes at %p (%s)\n",
numMembers * memberSize, *ptr, action);
return DPI_SUCCESS;
}
int dpiUtils__checkClientVersion(dpiVersionInfo *versionInfo,
int minVersionNum, int minReleaseNum, dpiError *error)
{
if (versionInfo->versionNum < minVersionNum ||
(versionInfo->versionNum == minVersionNum &&
versionInfo->releaseNum < minReleaseNum))
return dpiError__set(error, "check Oracle Client version",
DPI_ERR_ORACLE_CLIENT_TOO_OLD, versionInfo->versionNum,
versionInfo->releaseNum, minVersionNum, minReleaseNum);
return DPI_SUCCESS;
}
int dpiUtils__checkClientVersionMulti(dpiVersionInfo *versionInfo,
int minVersionNum1, int minReleaseNum1, int minVersionNum2,
int minReleaseNum2, dpiError *error)
{
if (versionInfo->versionNum < minVersionNum1 ||
(versionInfo->versionNum == minVersionNum1 &&
versionInfo->releaseNum < minReleaseNum1) ||
(versionInfo->versionNum > minVersionNum1 &&
versionInfo->versionNum < minVersionNum2) ||
(versionInfo->versionNum == minVersionNum2 &&
versionInfo->releaseNum < minReleaseNum2))
return dpiError__set(error, "check Oracle Client version",
DPI_ERR_ORACLE_CLIENT_TOO_OLD_MULTI, versionInfo->versionNum,
versionInfo->releaseNum, minVersionNum1, minReleaseNum1,
minVersionNum2, minReleaseNum2);
return DPI_SUCCESS;
}
int dpiUtils__checkDatabaseVersion(dpiConn *conn, int minVersionNum,
int minReleaseNum, dpiError *error)
{
if (dpiConn__getServerVersion(conn, 0, error) < 0)
return DPI_FAILURE;
if (conn->versionInfo.versionNum < minVersionNum ||
(conn->versionInfo.versionNum == minVersionNum &&
conn->versionInfo.releaseNum < minReleaseNum))
return dpiError__set(error, "check Oracle Database version",
DPI_ERR_ORACLE_DB_TOO_OLD, conn->versionInfo.versionNum,
conn->versionInfo.releaseNum, minVersionNum, minReleaseNum);
return DPI_SUCCESS;
}
void dpiUtils__clearMemory(void *ptr, size_t length)
{
volatile unsigned char *temp = (unsigned char *) ptr;
while (length--)
*temp++ = '\0';
}
int dpiUtils__ensureBuffer(size_t desiredSize, const char *action,
void **ptr, size_t *currentSize, dpiError *error)
{
if (desiredSize <= *currentSize)
return DPI_SUCCESS;
if (*ptr) {
dpiUtils__freeMemory(*ptr);
*ptr = NULL;
*currentSize = 0;
}
if (dpiUtils__allocateMemory(1, desiredSize, 0, action, ptr, error) < 0)
return DPI_FAILURE;
*currentSize = desiredSize;
return DPI_SUCCESS;
}
void dpiUtils__freeMemory(void *ptr)
{
if (dpiDebugLevel & DPI_DEBUG_LEVEL_MEM)
dpiDebug__print("freed ptr at %p\n", ptr);
free(ptr);
}
int dpiUtils__getAttrStringWithDup(const char *action, const void *ociHandle,
uint32_t ociHandleType, uint32_t ociAttribute, const char **value,
uint32_t *valueLength, dpiError *error)
{
char *source, *temp;
if (dpiOci__attrGet(ociHandle, ociHandleType, (void*) &source,
valueLength, ociAttribute, action, error) < 0)
return DPI_FAILURE;
if (*valueLength == 0) {
*value = NULL;
} else {
if (dpiUtils__allocateMemory(1, *valueLength, 0, action,
(void**) &temp, error) < 0)
return DPI_FAILURE;
*value = (const char*) memcpy(temp, source, *valueLength);
}
return DPI_SUCCESS;
}
#ifdef _WIN32
int dpiUtils__getWindowsError(DWORD errorNum, char **buffer,
size_t *bufferLength, dpiError *error)
{
char *fallbackErrorFormat = "failed to get message for Windows Error %d";
wchar_t *wLoadError = NULL;
DWORD length = 0, status;
status = FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_ALLOCATE_BUFFER,
NULL, errorNum, MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US),
(LPWSTR) &wLoadError, 0, NULL);
if (!status && GetLastError() == ERROR_MUI_FILE_NOT_FOUND)
FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_ALLOCATE_BUFFER,
NULL, errorNum, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(LPWSTR) &wLoadError, 0, NULL);
if (wLoadError) {
length = (DWORD) wcslen(wLoadError);
while (length > 0) {
if (wLoadError[length - 1] > 127 ||
(wLoadError[length - 1] != L'.' &&
!isspace(wLoadError[length - 1])))
break;
length--;
}
wLoadError[length] = L'\0';
if (length > 0) {
length = WideCharToMultiByte(CP_UTF8, 0, wLoadError, -1, NULL, 0,
NULL, NULL);
if (length > 0) {
if (dpiUtils__ensureBuffer(length,
"allocate buffer for Windows error message",
(void**) buffer, bufferLength, error) < 0) {
LocalFree(wLoadError);
return DPI_FAILURE;
}
length = WideCharToMultiByte(CP_UTF8, 0, wLoadError, -1,
*buffer, (int) *bufferLength, NULL, NULL);
}
}
LocalFree(wLoadError);
}
if (length == 0) {
if (dpiUtils__ensureBuffer(strlen(fallbackErrorFormat) + 20,
"allocate buffer for fallback error message",
(void**) buffer, bufferLength, error) < 0)
return DPI_FAILURE;
(void) sprintf(*buffer, fallbackErrorFormat, errorNum);
}
return DPI_SUCCESS;
}
#endif
int dpiUtils__parseNumberString(const char *value, uint32_t valueLength,
uint16_t charsetId, int *isNegative, int16_t *decimalPointIndex,
uint8_t *numDigits, uint8_t *digits, dpiError *error)
{
char convertedValue[DPI_NUMBER_AS_TEXT_CHARS], exponentDigits[4];
uint8_t numExponentDigits, digit;
uint32_t convertedValueLength;
uint16_t *utf16chars, i;
int exponentIsNegative;
const char *endValue;
int16_t exponent;
if (valueLength == 0)
return dpiError__set(error, "zero length", DPI_ERR_INVALID_NUMBER);
if ((charsetId == DPI_CHARSET_ID_UTF16 &&
valueLength > DPI_NUMBER_AS_TEXT_CHARS * 2) ||
(charsetId != DPI_CHARSET_ID_UTF16 &&
valueLength > DPI_NUMBER_AS_TEXT_CHARS))
return dpiError__set(error, "check length",
DPI_ERR_NUMBER_STRING_TOO_LONG);
if (charsetId == DPI_CHARSET_ID_UTF16) {
utf16chars = (uint16_t*) value;
convertedValue[0] = '\0';
convertedValueLength = valueLength / 2;
for (i = 0; i < convertedValueLength; i++) {
if (*utf16chars > 127)
return dpiError__set(error, "convert from UTF-16",
DPI_ERR_INVALID_NUMBER);
convertedValue[i] = (char) *utf16chars++;
}
value = convertedValue;
valueLength = convertedValueLength;
}
endValue = value + valueLength;
*isNegative = (*value == '-');
if (*isNegative)
value++;
*numDigits = 0;
while (value < endValue) {
if (*value == '.' || *value == 'e' || *value == 'E')
break;
if (*value < '0' || *value > '9')
return dpiError__set(error, "check digits before decimal point",
DPI_ERR_INVALID_NUMBER);
digit = (uint8_t) (*value++ - '0');
if (digit == 0 && *numDigits == 0)
continue;
*digits++ = digit;
(*numDigits)++;
}
*decimalPointIndex = *numDigits;
if (value < endValue && *value == '.') {
value++;
while (value < endValue) {
if (*value == 'e' || *value == 'E')
break;
if (*value < '0' || *value > '9')
return dpiError__set(error, "check digits after decimal point",
DPI_ERR_INVALID_NUMBER);
digit = (uint8_t) (*value++ - '0');
if (digit == 0 && *numDigits == 0) {
(*decimalPointIndex)--;
continue;
}
*digits++ = digit;
(*numDigits)++;
}
}
if (value < endValue && (*value == 'e' || *value == 'E')) {
value++;
exponentIsNegative = 0;
numExponentDigits = 0;
if (value < endValue && (*value == '+' || *value == '-')) {
exponentIsNegative = (*value == '-');
value++;
}
while (value < endValue) {
if (*value < '0' || *value > '9')
return dpiError__set(error, "check digits in exponent",
DPI_ERR_INVALID_NUMBER);
if (numExponentDigits == 3)
return dpiError__set(error, "check exponent digits > 3",
DPI_ERR_NOT_SUPPORTED);
exponentDigits[numExponentDigits] = *value++;
numExponentDigits++;
}
if (numExponentDigits == 0)
return dpiError__set(error, "no digits in exponent",
DPI_ERR_INVALID_NUMBER);
exponentDigits[numExponentDigits] = '\0';
exponent = (int16_t) strtol(exponentDigits, NULL, 10);
if (exponentIsNegative)
exponent = -exponent;
*decimalPointIndex += exponent;
}
if (value < endValue)
return dpiError__set(error, "check string used",
DPI_ERR_INVALID_NUMBER);
digits--;
while (*numDigits > 0 && *digits-- == 0)
(*numDigits)--;
if (*numDigits > DPI_NUMBER_MAX_DIGITS || *decimalPointIndex > 126 ||
*decimalPointIndex < -129) {
return dpiError__set(error, "check value can be represented",
DPI_ERR_NUMBER_NO_REPR);
}
return DPI_SUCCESS;
}
int dpiUtils__parseOracleNumber(void *oracleValue, int *isNegative,
int16_t *decimalPointIndex, uint8_t *numDigits, uint8_t *digits,
dpiError *error)
{
uint8_t *source, length, i, byte, digit;
int8_t ociExponent;
source = (uint8_t*) oracleValue;
length = *source++ - 1;
if (length > 20)
return dpiError__set(error, "check mantissa length",
DPI_ERR_INVALID_OCI_NUMBER);
ociExponent = (int8_t) *source++;
*isNegative = (ociExponent & 0x80) ? 0 : 1;
if (*isNegative)
ociExponent = ~ociExponent;
ociExponent -= 193;
*decimalPointIndex = ociExponent * 2 + 2;
if (length == 0) {
if (*isNegative) {
*digits = 1;
*decimalPointIndex = 127;
}
else {
*decimalPointIndex = 1;
*digits = 0;
}
*numDigits = 1;
return DPI_SUCCESS;
}
if (*isNegative && source[length - 1] == 102)
length--;
*numDigits = length * 2;
for (i = 0; i < length; i++) {
byte = *source++;
if (*isNegative)
byte = 101 - byte;
else byte--;
digit = (uint8_t) (byte / 10);
if (digit == 0 && i == 0) {
(*numDigits)--;
(*decimalPointIndex)--;
} else if (digit == 10) {
(*numDigits)++;
(*decimalPointIndex)++;
*digits++ = 1;
*digits++ = 0;
} else *digits++ = digit;
digit = byte % 10;
if (digit == 0 && i == length - 1)
(*numDigits)--;
else *digits++ = digit;
}
return DPI_SUCCESS;
}
int dpiUtils__setAttributesFromCommonCreateParams(void *handle,
uint32_t handleType, const dpiCommonCreateParams *params,
dpiError *error)
{
if (params->driverName && params->driverNameLength > 0 &&
dpiOci__attrSet(handle, handleType, (void*) params->driverName,
params->driverNameLength, DPI_OCI_ATTR_DRIVER_NAME,
"set driver name", error) < 0)
return DPI_FAILURE;
if (params->edition && params->editionLength > 0 &&
dpiOci__attrSet(handle, handleType,
(void*) params->edition, params->editionLength,
DPI_OCI_ATTR_EDITION, "set edition", error) < 0)
return DPI_FAILURE;
return DPI_SUCCESS;
}
int dpiUtils__setAccessTokenAttributes(void *handle,
dpiAccessToken *accessToken, dpiVersionInfo *versionInfo,
dpiError *error)
{
int isBearer = 1;
if (!accessToken->token || accessToken->tokenLength == 0 ||
(accessToken->privateKey && accessToken->privateKeyLength == 0))
return dpiError__set(error,
"check token based authentication parameters",
DPI_ERR_TOKEN_BASED_AUTH);
if (accessToken->privateKey) {
if (dpiUtils__checkClientVersionMulti(versionInfo, 19, 14, 21, 5,
error) < 0)
return DPI_FAILURE;
} else {
if (dpiUtils__checkClientVersionMulti(versionInfo, 19, 15, 21, 7,
error) < 0)
return DPI_FAILURE;
}
if (dpiOci__attrSet(handle, DPI_OCI_HTYPE_AUTHINFO,
(void*) accessToken->token, accessToken->tokenLength,
DPI_OCI_ATTR_TOKEN, "set access token", error) < 0)
return DPI_FAILURE;
if (accessToken->privateKey) {
if (dpiOci__attrSet(handle, DPI_OCI_HTYPE_AUTHINFO,
(void*) accessToken->privateKey,
accessToken->privateKeyLength, DPI_OCI_ATTR_IAM_PRIVKEY,
"set access token private key", error) < 0)
return DPI_FAILURE;
} else {
if (dpiOci__attrSet(handle, DPI_OCI_HTYPE_AUTHINFO,
(void*) &isBearer, 0, DPI_OCI_ATTR_TOKEN_ISBEARER,
"set bearer flag", error) < 0)
return DPI_FAILURE;
}
return DPI_SUCCESS;
}