I'm having a bit of a problem with the following code. I've seen tons of examples for using InternetReadFile to save to a file. But I cant find one, or get it to work for a char[]. I want to add the szBuffer up to get holdBuff, and then set content equal to holdBuff.
#include <stdio.h>
#include <tchar.h>
#include <string.h>
#include <windows.h>
#include <WinInet.h>
HINTERNET hSession;
void urlToChar(char* url, char** content);
int main()
{
hSession = InternetOpen("Mozilla/4.0 (compatible) Poison", INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0);
char* content;
urlToChar("http://google.com/", &content);
printf("%s",content);
return 0;
}
void urlToChar(char* url, char** content)
{
HINTERNET hConnect = InternetConnect(hSession, _T(""),INTERNET_DEFAULT_HTTP_PORT, NULL, NULL, INTERNET_SERVICE_HTTP, 0, 1);
HINTERNET hRequest = InternetOpenUrl(hSession, url, NULL, 0, 0, 0);
if (hRequest)
{
char holdBuff[] = "";
char szBuff[1025];
memset(szBuff, 0x00, sizeof(szBuff));
DWORD bytesRead;
while (InternetReadFile(hRequest, szBuff, 1024, &bytesRead) == TRUE && bytesRead > 0)
{
// Cat szBuff to holdBuff
memset(szBuff, 0x00, sizeof(szBuff));
}
*content = holdBuff;
// memset(holdBuff, 0x00, sizeof(holdBuff)); <-- Need this?
}
InternetCloseHandle(hRequest);
InternetCloseHandle(hConnect);
}
The variable declaration
char xyz[] = "Hello World!";
will tell the compiler to put the contents of the string on the stack. Of course, the stack goes away when your function returns.
So in your case:
char holdBuff[] = "";
...
*content = holdBuff;
This tells the compiler to create a string of length one (the NULL terminator) as a local variable. Just because you've set the value of content to holdBuff doesn't mean that what holdBuff was pointing exists anymore.
You have to correct two things. Firstly, you must use strcpy() or similar function. Second, you must allocate sufficient space for holdBuff.
Example:
char holdBuff[4096]; // or some other sufficiently large size
...
*content = malloc (strlen(holdBuff) + 1);
strcpy (*content, holdBuff);
You'll then need to free(content) in main() once you're finished with it.
Now, for how to actually do the concatenation: Your performance will be much better if you forget about using szBuff at all and just write directly to holdBuff.
char* temp = holdBuff;
while (InternetReadFile(hRequest, temp, 1024, &bytesRead) == TRUE && bytesRead > 0)
{
temp += bytesRead;
}
*temp = '\0'; // manually append NULL terminator
Now holdBuff will have the data you want with no need for intermediary concatenation.
void urlToChar(char* url, char** content)
{
HINTERNET hConnect = InternetConnect(hSession, _T(""),INTERNET_DEFAULT_HTTP_PORT, NULL, NULL, INTERNET_SERVICE_HTTP, 0, 1);
HINTERNET hRequest = InternetOpenUrl(hSession, url, NULL, 0, 0, 0);
if (hRequest)
{
char holdBuff[] = ""; //do not use fixed size char array and allocate buffer in stack,you can allocate large enough buffer in heap,but recommend you can use string or CString
char szBuff[1025];
memset(szBuff, 0x00, sizeof(szBuff));
DWORD bytesRead;
while (InternetReadFile(hRequest, szBuff, 1024, &bytesRead) == TRUE && bytesRead > 0)
{
// Cat szBuff to holdBuff
//strcat when using char array
// operator+ when using stl string
// [stl string][1]
memset(szBuff, 0x00, sizeof(szBuff));
}
*content = holdBuff;
// memset(holdBuff, 0x00, sizeof(holdBuff)); <-- Need this?
}
InternetCloseHandle(hRequest);
InternetCloseHandle(hConnect);
}
Related
So, I'm working on a preprocessor for C, my post on another site went semi viral (cprogramming.com)
What I want is a function, using PCRE2, that replaces a string with another string.
I also want a function that replaces a string with the result of a callback (a null-terminated) string for each match of a string
Ruby has
str.gsub /foo/ do |i|
end
I have code that does the first one, see (https://cboard.cprogramming.com/c-programming/181161-c-regular-expressions.html)
#define PCRE2_CODE_UNIT_WIDTH 8
#include <pcre2.h>
char* gsub (const char* str, const char* reg, const char* rep) {
size_t outlen;
static const char* error_str = "\"DONT KNOW HOW TO ALLOCATE MEM FOR REGEX\"";
char* out = malloc(outlen =strlen(str) * strlen(rep)) ;
if (out == NULL) {
error:
fputs(error_str, stderr);
return NULL;
}
int error;
PCRE2_SIZE erroffset;
// printf(\" %l \",
const PCRE2_SPTR pattern = (PCRE2_SPTR)reg;
const PCRE2_SPTR subject = (PCRE2_SPTR)str;
const PCRE2_SPTR replacement = (PCRE2_SPTR)rep;
pcre2_code *re = pcre2_compile(pattern, PCRE2_ZERO_TERMINATED, 0, &error, &erroffset, 0);
if (re == 0) return NULL;
// return 1;
pcre2_jit_compile(re, PCRE2_JIT_COMPLETE);
int rc = pcre2_substitute(re, subject, PCRE2_ZERO_TERMINATED, 0, PCRE2_SUBSTITUTE_GLOBAL | PCRE2_SUBSTITUTE_EXTENDED, 0, 0, replacement, PCRE2_ZERO_TERMINATED, out, &outlen);
if (rc >= 0);
// printf(%s\\n, output);
pcre2_code_free(re);
size_t new_len = strlen(out);
char* new_out = realloc(out,new_len + 1);
if (new_out == NULL) goto error;
return new_out;
}
Could someone help me to make the second function ?
Is there any way to have PCRE automatically account for memory allocation sizes?
I am trying to create a registry key with type REG_SZ and with a value longer than 4 chars.
But I can't figure out the right way to pass the data as argument :
#include <windows.h>
#include <stdio.h>
HKEY OpenKey(HKEY hRootKey, wchar_t* strKey)
{
HKEY hKey;
LONG nError = RegOpenKeyEx(hRootKey, strKey, 0, KEY_ALL_ACCESS, &hKey);
if (nError == ERROR_FILE_NOT_FOUND)
{
printf("Debug: Creating registry key\n");
nError = RegCreateKeyEx(hRootKey, strKey, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hKey, NULL);
}
if (nError) {
printf("Error: Could not find or create\n");
}
return hKey;
}
void SetValSZ(HKEY hKey, LPCTSTR lpValue, LPCTSTR data)
{
LONG nError = RegSetValueEx(hKey, lpValue, 0, REG_SZ, (const BYTE*) data, sizeof(data));
if (nError)
printf("Error: Could not set registry value\n");
}
int main()
{
HKEY hKey = OpenKey(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Policies\\Microsoft\\FVE");
const wchar_t data[] = L"AAAABBBBCCCC";
SetValSZ(hKey, L"RecoveryKeyMessage", data);
RegCloseKey(hKey);
return 0;
}
When I run it, only the first 4 characters are saved.
I must have a type mistake...
Do you have any idea to help me to fix it ?
Thank you.
PS: I hope my english is clear enoth, feel free to ask me more if it isn't.
void SetValSZ(HKEY hKey, LPCTSTR lpValue, LPCTSTR data)
{
RegSetValueEx(hKey, lpValue, 0, REG_SZ, (const BYTE*) data, sizeof(data));
}
data is being passed as a pointer to a function, so its actual size will be lost. sizeof(data) is translated to the size of a pointer, which is 4 bytes in this case.
You have to either pass in the size as a parameter:
int len = sizeof(data);
SetValSZ(..., data, len);
Or better yet, use wcslen() to calculate the string length, then multiply that by sizeof(wchar_t).
Since you are using those T macros, the function can be written as:
RegSetValueEx(hKey,lpValue,0,REG_SZ,(const BYTE*)data,sizeof(TCHAR)*(lstrlen(data) + 1));
Edit: The size should also include the terminating null character
I am concatenating few strings using a custom function. The functions works correctly and I get the proper values but after few statements the values in the char pointers gets corrupted. I do not understand the reason behind this. Below is the part of a larger function. I am just providing the code till where the corruption happens
char* my_strcpy(char*dest, const char* src, int hasLen, int length) {
if (!hasLen) {
while ((*dest = *src++))
++dest;
} else {
while (length-- && (*dest = *src++))
++dest;
}
return dest;
}
int addSubscriptionInCache(subs_t* subs, str* pres_uri, int read_response) {
redisReply *reply;
char temp_key[1] = "";
char *tk = my_strcpy(temp_key, "", 0, 0);
char *subs_cache_key = tk;
char temp_value[1] = "";
char *tv = my_strcpy(temp_value, "", 0, 0);
char *subs_cache_value = tv;
tk = my_strcpy(tk, SUBSCRIPTION_SET_PREFIX, 0, 0);
tk = my_strcpy(tk, "-", 0, 0);
tk = my_strcpy(tk, subs->pres_uri.s, 0, 0);
tk = my_strcpy(tk, ":", 0, 0);
tk = my_strcpy(tk, subs->event->name.s, 0, 0);
*tk = '\0';
// this prints correctly.
printf("subs_cache_key: %d %s \n", strlen(subs_cache_key), subs_cache_key);
int subs_cache_value_len = subs->callid.len + subs->to_tag.len + 1; // add 1 for :
tv = my_strcpy(tv, subs->to_tag.s, 1,subs->to_tag.len);
tv = my_strcpy(tv, ":", 0, 0);
tv = my_strcpy(tv, subs->callid.s, 1,subs->callid.len);
*tv= '\0';
// this prints correctly.
printf("subs_cache_value: %d %s \n", strlen(subs_cache_value), subs_cache_value);
//add in pipeline
redisAppendCommand(redis_context, "SADD %s %s", subs_cache_key, subs_cache_value))
//set expires
redisAppendCommand(redis_context, "EXPIRE %s %d", subs_cache_key, subs->expires);
// create hash for to_tag:call_id
int argc = 0;
char *arvg[22];
size_t argvlen[22];
// this prints fine.
printf("Before corruption: %s", subs_cache_value);
arvg[argc] = "HMSET";
// below prints corrupted values
printf("After corruption: %s", subs_cache_value);
printf("After corruption: %s", subs_cache_key);
argvlen[argc] = 5;
argc++;
arvg[argc] = subs_cache_value;
argvlen[argc] = subs_cache_value_len;
argc++;
.......
//rest of the code
}
I am using the custom function so that not to traverse the whole string again and again.
Please help me understand if I have done something because of which corruption is happening.
Thanks
You have
char temp_key[1] = "";
char *tk = my_strcpy(temp_key, "", 0, 0);
and go on to use tk in subsequent calls to my_strcpy.
The problem is that you don't have enough memory. Using memory beyond the valid limits leads to undefined behavior.
Use something like:
char temp_key[1000] = ""; // Make the size large enough for
// the kinds of strings you are
// expecting to see.
Similarly, use:
char temp_value[1000] = "";
I'm implementing an iterator to go over the records from a Berkeley DB. However, it seems I need to set the DB_DBT_USERMEM flag before the call to cursor->get with DB_NEXT.
Doing it that way would make my iterator less cohesive and will have to implement multiple iterators for each data type I want to retrieve.
Is there a way to have a generic iterator that can traverse structures w/o pointers, and basic data types? Here's what I'm trying to achieve.
#include <stdio.h>
#include <string.h>
#include <db.h>
// let this function handle integers and use DB_DBT_USERMEM for memory alignment
void integer_items(DBT key, DBT data) {
int number = 0;
data.data = &number;
data.flags = DB_DBT_USERMEM;
data.ulen = sizeof(int);
printf("key is: %s, data is: %d\n", (char *) key.data,number);
}
// let this function handle pointer structs. No need for DB_DBT_USERMEM
void ptr_struct_items(DBT key, DBT data) {
// MY_STRUCT user;
// marshall struct...
// buffsize = sizeof(int) +(strlen(user.familiar_name) + strlen(user.surname) + 2);
// databuff = malloc(buffsize);
// memset(databuff, 0, buffsize);
// ...
// printf("key is: %s, data is: %d\n", (char *) key.data,number);
}
int iterator(DB *database, void(*function)(DBT key, DBT data)) {
DBT key, data;
DBC *cursor;
memset(&key, 0, sizeof(DBT));
memset(&data, 0, sizeof(DBT));
database->cursor(database, NULL, &cursor, 0);
while(cursor->c_get(cursor, &key, &data, DB_NEXT) == 0){
(*function)(key, data);
}
cursor->c_close(cursor);
return 0;
}
int main() {
DB_ENV *myEnv;
DB *dbp;
DBT key, data;
int r, v = 10;
char *k = "Test";
db_env_create(&myEnv, 0);
myEnv->open(myEnv, "./", DB_CREATE | DB_INIT_MPOOL, 0);
db_create(&dbp, myEnv, 0);
dbp->open(dbp, NULL, "test.db", NULL, DB_HASH, DB_CREATE, 0664);
memset(&key, 0, sizeof(key));
memset(&data, 0, sizeof(data));
key.data = k;
key.size = strlen(k) +1;
data.data = &v;
data.size = sizeof(int);
if((r=dbp->put(dbp, NULL, &key, &data, 0)!=0))
fprintf(stderr, "%s\n", db_strerror(r));
iterator(dbp, integer_items);
iterator(dbp, ptr_struct_items);
return 0;
}
You almost always want to use DB_DBT_USERMEM, if only to avoiding the malloc() from inside BDB for DB_DBT_MALLOC/REALLOC. When you use it, you must pass in your own memory large enough to hold the largest item in your database. This holds for the key DBT too, as you may want to use it there.
In your example, as the key and data are so small, I'd just put character arrays on the stack in your "iterator" function, and then initialize key and data after the call to memset(). What you've got above is wrong because you're setting USERMEM after the call to c_get().
Here's a reworked example that gives BDB 256 bytes to work with for key and data.
void integer_items(DBT key, DBT data) {
int number = 0;
if (data.size == sizeof number) {
number = *(int *)data.data;
printf("key is: %s, data is: %d\n", (char *) key.data, number);
}
}
int iterator(DB *database, void(*function)(DBT key, DBT data)) {
DBT key, data;
DBC *cursor;
char kmem[256];
char dmem[256];
memset(&key, 0, sizeof(DBT));
memset(&data, 0, sizeof(DBT));
key.flags = DB_DBT_USERMEM;
key.data = kmem;
key.ulen = sizeof kmem;
data.flags = DB_DBT_USERMEM;
data.data = dmem;
data.ulen = sizeof dmem;
database->cursor(database, NULL, &cursor, 0);
while(cursor->c_get(cursor, &key, &data, DB_NEXT) == 0){
(*function)(key, data);
}
cursor->c_close(cursor);
return 0;
}
To handle different structures inside your iterator, include the data type as part of the key somehow. For example, instead of a bare integer for the key, use a struct, and have the first character define which kind of type it is. Then, inside your iterator function, you can switch on that.
The code:
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <Windows.h>
HANDLE creatFile(void);
long WriteBuffer(HANDLE);
char * GetBuffer(void);
void main(void)
{
HANDLE hFile;
printf("CreateFile: ");
hFile = creatFile();
if(hFile != NULL)
{
WriteBuffer(hFile);
FlushFileBuffers(hFile);
}
CloseHandle(hFile);
printf("\n\rDone");
getchar();
}
HANDLE creatFile(void)
{
HANDLE hFile;
LPCWSTR sFileName = L"\\\\.\\E:";
DWORD dwDesiredAccess = GENERIC_WRITE;
DWORD fShareMode = FILE_SHARE_WRITE | FILE_SHARE_WRITE;
DWORD fCreationDisposition = OPEN_EXISTING;
DWORD fFlagsAndAttributes = FILE_ATTRIBUTE_NORMAL;
hFile = CreateFile(sFileName, dwDesiredAccess,fShareMode,
NULL, fCreationDisposition, fFlagsAndAttributes,
NULL);
if (hFile == INVALID_HANDLE_VALUE)
{
hFile = NULL;
printf("INVALID_HANDLE_VALUE: ");
switch (GetLastError())
{
case 5:
printf("\n\r Administrative Account required to run this program\n\r");
break;
case 87:
printf("\n\r Invalid Parameter in CreateFile Call \n\r");
break;
default:
printf("Error %d\n",GetLastError());
break;
}
return NULL;
}
else
{
printf("Attached -> %d\n\r",hFile);
return hFile;
}
}
long WriteBuffer(HANDLE hFile)
{
char *str = GetBuffer(); // x 64 will give us 512 (sector sized buffer) ;
DWORD bytesWritten;
long totalBytesWritten = 0;
long idx = 0;
int len = strlen(str);
for(idx = 0; idx < 100000; idx ++)
{
if(WriteFile(hFile, str, 512 * sizeof(char), &bytesWritten, NULL))
{
totalBytesWritten += bytesWritten;
printf("Sectors Written : %d\r",idx+1);
}
else
{
int le = GetLastError();
printf("Last Error : %d\r",GetLastError());
break;
}
}
printf("\n\r");
printf("Bytes Written: %d\n\r", totalBytesWritten);
printf("Handle -> %d\n\r",hFile);
return totalBytesWritten;
}
char * GetBuffer(void)
{
int i = 0, idx = 0;
const char * cstr_init = "ERASED1 ";
char *buffer = (char*)malloc(512);
char word2[512];
for (idx = 0; idx < 512; idx+=8) {
for (i = 0; i < 8; i++) {
buffer[idx+i] = cstr_init[i];
if(strlen(buffer) == 512)
break;
}
}
return buffer;
}
The problems:
char * GetBuffer has extraneous data of 16 bytes in it. I modified WriteFile so that it only write 512 (instead of the 528) chars that the buffer actually holds.
After 16 sectors of writing - WriteFile fails with GetLastError = 5 (Access Denied)
The Questions:
How do I fix WriteFile so that it does NOT fail after 16 sectors and...
How do I fix GetBuffer so it actually produces a 512 buffer and not 528?
Notes
The application is ANSI C and the program is being run as admin.
I can't speak to the error with WriteFile(), however, you've got issues with your string operations.
C strings are null terminated, that is, the string literal "abc" is actually an array of characters like: {'a','b','c','\0'} All str...() operations rely on this fact. There is no information stored anywhere on the length of the string, only the fact that it is expected to end with a '\0'.
Your GetBuffer() function improved:
char * GetBuffer(void)
{
int i = 0, idx = 0;
const char * cstr_init = "ERASED1 ";
char *buffer = malloc(513); // Space for a '\0'
for (idx = 0; idx < 512; idx+=8) {
for (i = 0; i < 8; i++) {
buffer[idx+i] = cstr_init[i];
}
}
}
You were getting weird results for strlen() because it looks for a '\0' and was only finding one at 528 bytes, reading outside of the 512 bytes malloced is invoking undefined behavior, you could have found a '\0' at 513 bytes, or never found one.
Other comments, after calling GetBuffer() you never free() the char * returned, that is a memory leak since it was malloced and lost outside of that context. Also, a better implementation of GetBuffer() would be:
char * GetBuffer(void)
{
const char * cstr_init = "ERASED1 ";
const int cstr_init_len = strlen(cstr_init);
char * buffer = calloc(1,513); // Guaranteed zeroed
int i;
for (i = 0; i < 512; i+=8) {
memcpy(buffer+i, cstr_init, cstr_init_len);
// Or strcpy(buffer+1, cstr_init);
// Or strcat(buffer, cstr_init); // Inefficient because each call runs from buffer[0] to find a '\0' for where to start appending
}
return buffer;
}
the INT type could only be a 2 byte number from 0 - 65536 unsigned. replace all INT types with LONG (long) to start with...Not sure what compiler environment you are in though - as this change may not apply
I was unable to fix question 2 - the way I would have liked. However, by Telling WriteFile to write 512 bytes out of the buffer of 528 bytes - I got the desired results. As for Question 1.
Because The Disk drive has a Filesystem on it - Windows OS recognises that fact and prevents writing to the full drive. All I needed to do was in fact Lock the drive and that would give me exclusive access to the drive.
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <Windows.h>
#include <winioctl.h>
HANDLE creatFile(void);
long WriteBuffer(HANDLE);
char * GetBuffer(void);
void main(void)
{
HANDLE hFile;
printf("CreateFile: ");
hFile = creatFile();
if(hFile != NULL)
{
WriteBuffer(hFile);
FlushFileBuffers(hFile);
}
CloseHandle(hFile);
printf("\n\rDone");
getchar();
}
HANDLE creatFile(void)
{
HANDLE hFile;
LPCWSTR sFileName = L"\\\\.\\E:";
DWORD dwDesiredAccess = GENERIC_WRITE;
DWORD fShareMode = FILE_SHARE_WRITE | FILE_SHARE_WRITE;
DWORD fCreationDisposition = OPEN_EXISTING;
DWORD fFlagsAndAttributes = FILE_ATTRIBUTE_NORMAL;
BOOL bResult = FALSE; // results flag
LPDWORD lpBytesReturned = 0;
hFile = CreateFile(sFileName, dwDesiredAccess,fShareMode,
NULL, fCreationDisposition, fFlagsAndAttributes,
NULL);
if (hFile == INVALID_HANDLE_VALUE)
{
hFile = NULL;
printf("INVALID_HANDLE_VALUE: ");
switch (GetLastError())
{
case 5:
printf("\n\r Administrative Account required to run this program\n\r");
break;
case 87:
printf("\n\r Invalid Parameter in CreateFile Call \n\r");
break;
default:
printf("Error %d\n",GetLastError());
break;
}
return NULL;
}
else
{
printf("Attached -> %d\n\r",hFile);
// HERE I JUST ADD THE FSCTL_LOCK_VOLUME command to stop Windows preventing me from writing to the drive
bResult = DeviceIoControl(hFile, // device to be queried
FSCTL_LOCK_VOLUME, // dwIoControlCode
NULL, 0, // no input buffer
NULL, 0, // output buffer
lpBytesReturned, // # bytes returned
(LPOVERLAPPED) NULL); // synchronous I/O
return hFile;
}
}
long WriteBuffer(HANDLE hFile)
{
char *str = GetBuffer(); // x 64 will give us 512 (sector sized buffer) ;
DWORD bytesWritten;
long totalBytesWritten = 0;
long idx = 0;
int len = strlen(str);
for(idx = 0; idx < 100000; idx ++)
{
if(WriteFile(hFile, str, 512 * sizeof(char), &bytesWritten, NULL))
{
totalBytesWritten += bytesWritten;
printf("Sectors Written : %d\r",idx+1);
}
else
{
int le = GetLastError();
printf("\n\rLast Error : %d\r",GetLastError());
break;
}
}
printf("\n\r");
printf("Bytes Written: %d\n\r", totalBytesWritten);
printf("Handle -> %d\n\r",hFile);
return totalBytesWritten;
}
char * GetBuffer(void)
{
const char * cstr_init = "ERASED2 ";
const int cstr_init_len = strlen(cstr_init);
char *buffer = (char*)malloc(513);
int i;
for (i = 0; i < 512; i+=8) {
memcpy(buffer+i, cstr_init, cstr_init_len);
// Or strcpy(buffer+1, cstr_init);
// Or strcat(buffer, cstr_init); // Inefficient because each call runs from buffer[0] to find a '\0' for where to start appending
}
return buffer;
}
So for future reference, if you wish to write directly to the drive it is important to LOCK the volume first. I know that there are memory leaks within the above code - but as a learning exercise for the Writing of data to a drive I am not bothered. The code will be tidied up and made into a .dll