6 Replies - 420 Views - Last Post: 04 March 2012 - 01:11 PM Rate Topic: -----

#1 juryben  Icon User is offline

  • D.I.C Head

Reputation: -3
  • View blog
  • Posts: 74
  • Joined: 30-November 10

Can't Store Downloaded Data in One Big Buffer using InternetReadFi

Posted 03 March 2012 - 02:09 PM

I want to write all the contents of InternetReadFile() into one big buffer. But everything I do doesn't work. I can print it out in the loop, but not store all the data in a buffer and then print it out. Why?
Am I doing something wrong? I've tried almost everything!

							ret = (BYTE*) malloc (contentlen + 1);
							while(InternetReadFile(hIurl, buf, sizeof(buf), &numrcved))
							{
								ret =+ buf;
								total =+ numrcved;

								//printf((char*)ret); //Works Here

								if(numrcved==0) break;

							}
						}

						InternetCloseHandle(hIurl);
						InternetCloseHandle(hInet);

						printf((char*)ret); //Not Here

						free(ret);




Full Code:
// A file download subsystem


#include <Windows.h>
#include <iostream>
#include <WinInet.h>

#pragma comment (lib, "Wininet")

using namespace std;

bool httpverOK(HINTERNET hIurl)
{
	char str[80];
	unsigned long len = 79;

	if(!HttpQueryInfo(hIurl, HTTP_QUERY_VERSION, &str, &len, NULL))
		return false;

	// First, check major version number
	char *p = strchr(str, '/');
	p++;
	if(*p == '0')
		return false;       // can't use HTTP 0.x

	// Now, find start of minor HTTP version number
	p = strchr(str, '.');
	p++;

	// convert to int
	int minorVerNum = atoi(p);

	if(minorVerNum > 0)
		return true;

	return false;
}

bool getfname(char *url, char *fname)
{
	// Find last slash /
	char *p = strrchr(url, '/');

	// Copy filename afther the last slash
	if(p && (strlen(p) < 512))
	{
		p++;
		strcpy_s(fname, 256, p);
		return true;
	}
	else
	{
		return false;
	}
}



// Confirm that the URL specifies HTTP
bool ishttp(char *url)
{
	char str[5] = "";

	// get the first four characters from the URL
	strncpy_s(str, url, 4);

	// convert to lowercase
	for(char *p = str; *p; p++)
		*p = tolower(*p);

	return !strcmp("http", str);
}

unsigned long openfile(char *url, FILE * pFile)
{
	char fname[512];

	if(getfname(url, fname))
	{

		fopen_s(&pFile, fname, "w");

		if(pFile != NULL)
		{
			fseek(pFile, 0L, SEEK_END);
			long sz  = ftell(pFile) ;
			fseek(pFile, 0L, SEEK_SET);
			return sz;
		}
	}
	return 0;
}


bool download(char *url)
{
	BYTE buf[10240];// input buffer
	unsigned long numrcved;     // number of bytes read
	unsigned long filelen;      // length of the file on disk
	HINTERNET hIurl;
	HINTERNET hInet;     // internet handles
	unsigned long contentlen;   // length of content
	unsigned long len;          // length of contentlen
	unsigned long total = 0;    // running total of bytes received
	char header[80];            // holds Range header

	if(ishttp(url))
	{
		FILE * pFile;
		char fname[512];
		getfname(url, fname);


		fopen_s(&pFile, fname, "wb");
		filelen = openfile(url, pFile) ;

		if(InternetAttemptConnect(0) == ERROR_SUCCESS)
		{
			hInet = InternetOpen("downloader", INTERNET_OPEN_TYPE_DIRECT, NULL, NULL, 0);
			if(hInet != NULL)
			{
				sprintf_s(header, "Range:bytes=%d-", filelen);
				hIurl = InternetOpenUrl(hInet, url, header, strlen(header), INTERNET_FLAG_NO_CACHE_WRITE, 0);
				if(hIurl != NULL)
				{
					int total = 0;
					BYTE *ret = NULL;
					len = sizeof contentlen;
					if(HttpQueryInfo(hIurl, HTTP_QUERY_CONTENT_LENGTH | HTTP_QUERY_FLAG_NUMBER, &contentlen, &len, NULL))
					{
						if(filelen!= contentlen )
						{
							DWORD dataSize = 0;

							ret = (BYTE*) malloc (contentlen + 1);
							while(InternetReadFile(hIurl, buf, sizeof(buf), &numrcved))
							{
								ret =+ buf;
								total =+ numrcved;

								//printf((char*)ret); //Works Here

								if(numrcved==0) break;

							}
						}

						InternetCloseHandle(hIurl);
						InternetCloseHandle(hInet);

						printf((char*)ret); //Not Here

						free(ret);

						return true;

					}
				}
			}
		}
	}
	return false;
}
int main(int argc, char *argv[])
{
	char url[] = "http://download.tuxfamily.org/notepadplus/5.9.8/npp.5.9.8.Installer.exe";


	printf("Beginning download\n");
	if(download(url))
	{

		printf("Download Complete\n");
	}
	system("PAUSE");
	return EXIT_SUCCESS;
}


This post has been edited by juryben: 03 March 2012 - 02:10 PM


Is This A Good Question/Topic? 0
  • +

Replies To: Can't Store Downloaded Data in One Big Buffer using InternetReadFi

#2 JackOfAllTrades  Icon User is offline

  • Saucy!
  • member icon

Reputation: 5669
  • View blog
  • Posts: 22,517
  • Joined: 23-August 08

Re: Can't Store Downloaded Data in One Big Buffer using InternetReadFi

Posted 03 March 2012 - 03:22 PM

Because binary files are not strings, so you can't print them like they're strings? Binary files can have embedded null characters that will stop the printing of it as a string right in its tracks.
Was This Post Helpful? 0
  • +
  • -

#3 baavgai  Icon User is offline

  • Dreaming Coder
  • member icon

Reputation: 4884
  • View blog
  • Posts: 11,280
  • Joined: 16-October 07

Re: Can't Store Downloaded Data in One Big Buffer using InternetReadFi

Posted 03 March 2012 - 03:54 PM

// why allocate the whole thing, you have a buffer?
ret = (BYTE*) malloc (contentlen + 1);
// ok
while(InternetReadFile(hIurl, buf, sizeof(buf), &numrcved)) {
	// what the hell does this mean?
	ret =+ buf;



Don't bother with ret. Use the bytes read into buf to append to the file from the buffer.
Was This Post Helpful? 0
  • +
  • -

#4 juryben  Icon User is offline

  • D.I.C Head

Reputation: -3
  • View blog
  • Posts: 74
  • Joined: 30-November 10

Re: Can't Store Downloaded Data in One Big Buffer using InternetReadFi

Posted 03 March 2012 - 06:41 PM

View Postbaavgai, on 03 March 2012 - 03:54 PM, said:

// why allocate the whole thing, you have a buffer?
ret = (BYTE*) malloc (contentlen + 1);
// ok
while(InternetReadFile(hIurl, buf, sizeof(buf), &numrcved)) {
	// what the hell does this mean?
	ret =+ buf;



Don't bother with ret. Use the bytes read into buf to append to the file from the buffer.

I don't want to write to a file. I want to store all the data in memory. So I need to concatenate the buffer to one big buffer but it doesn't work for some reason.

View PostJackOfAllTrades, on 03 March 2012 - 03:22 PM, said:

Because binary files are not strings, so you can't print them like they're strings? Binary files can have embedded null characters that will stop the printing of it as a string right in its tracks.

You can print them like strings. I was able to use fwrite((char*)buf, ... ) and it successfully worked. I suppose you are right about that the data could have a null character, but that's not the problem.

This post has been edited by juryben: 03 March 2012 - 06:50 PM

Was This Post Helpful? 0
  • +
  • -

#5 baavgai  Icon User is offline

  • Dreaming Coder
  • member icon

Reputation: 4884
  • View blog
  • Posts: 11,280
  • Joined: 16-October 07

Re: Can't Store Downloaded Data in One Big Buffer using InternetReadFi

Posted 03 March 2012 - 06:59 PM

View Postjuryben, on 03 March 2012 - 09:41 PM, said:

I want to store all the data in memory. So I need to concatenate the buffer to one big buffer but it doesn't work for some reason.


Interesting. You can't concatenate arrays like that.

I'd drop the buffer entirely. Pick your chunk size and go from there:
#define CHUNK_SIZE 8096

// why +1???
// ret = (BYTE*) malloc (contentlen + 1);
BYTE *ret, *current;
current = ret = (BYTE*) malloc(contentlen);
while(InternetReadFile(hIurl, current, CHUNK_SIZE, &numrcved)) {
	current += numrcved; // what you're doing here is moving the pointer forward
	total += numrcved;



You check the file size first. It looked like you were doing something clever like being able to restart with the file you'd previously written to. Guess I was wrong.

This post has been edited by baavgai: 03 March 2012 - 07:00 PM

Was This Post Helpful? 0
  • +
  • -

#6 juryben  Icon User is offline

  • D.I.C Head

Reputation: -3
  • View blog
  • Posts: 74
  • Joined: 30-November 10

Re: Can't Store Downloaded Data in One Big Buffer using InternetReadFi

Posted 03 March 2012 - 11:03 PM

Nothing works... I might have to resort to something crazy like appending a resource.

This post has been edited by juryben: 04 March 2012 - 08:48 AM

Was This Post Helpful? 0
  • +
  • -

#7 baavgai  Icon User is offline

  • Dreaming Coder
  • member icon

Reputation: 4884
  • View blog
  • Posts: 11,280
  • Joined: 16-October 07

Re: Can't Store Downloaded Data in One Big Buffer using InternetReadFi

Posted 04 March 2012 - 01:11 PM

Odd. The code I offered works. Just taking your code, removing the unused junk, and adding some notifications:
#include <Windows.h>
#include <iostream>
#include <WinInet.h>

#pragma comment (lib, "Wininet")

using namespace std;


bool ishttp(const char *url) {
	return tolower(url[0])=='h'
		&& tolower(url[1])=='t'
		&& tolower(url[2])=='t'
		&& tolower(url[3])=='p';
}

void showError(const char *msg) { printf("ERROR: %s\n", msg); }


bool download(char *url) {
	// BYTE buf[10240];// input buffer
	BYTE *ret = NULL;
	//unsigned long numrcved;     // number of bytes read
	// unsigned long filelen;      // length of the file on disk
	// HINTERNET hIurl;
	// HINTERNET hInet;     // internet handles
	DWORD contentlen = 0; // length of content
	// unsigned long len;          // length of contentlen
	DWORD total = 0;    // running total of bytes received
	// char header[80];            // holds Range header

	if(ishttp(url)) {
		// FILE * pFile;
		// char fname[512];
		// getfname(url, fname);

		// fopen_s(&pFile, fname, "wb");
		// filelen = openfile(url, pFile) ;

		if(InternetAttemptConnect(0) == ERROR_SUCCESS) {
			HINTERNET hInet = InternetOpen("downloader", INTERNET_OPEN_TYPE_DIRECT, NULL, NULL, 0);
			if(hInet != NULL) {
				// sprintf_s(header, "Range:bytes=%d-", filelen);
				// hIurl = InternetOpenUrl(hInet, url, header, strlen(header), INTERNET_FLAG_NO_CACHE_WRITE, 0);
				HINTERNET hIurl = InternetOpenUrl(hInet, url, NULL, 0, INTERNET_FLAG_NO_CACHE_WRITE, 0);
				if(hIurl != NULL) {
					// int total = 0;
					// BYTE *ret = NULL;
					DWORD len = sizeof(DWORD);
					if(HttpQueryInfo(hIurl, HTTP_QUERY_CONTENT_LENGTH | HTTP_QUERY_FLAG_NUMBER, &contentlen, &len, NULL) && contentlen>0) {
						const int CHUNK_SIZE = 10240;
						BYTE *dp;
						DWORD numrcved;
						// if(filelen!= contentlen ) {
						// DWORD dataSize = 0;

						// ret = (BYTE*) malloc (contentlen + 1);
						printf("Expected Size: %d\n", contentlen);

						ret = dp = (BYTE*) malloc (contentlen );
						while(InternetReadFile(hIurl, dp, CHUNK_SIZE, &numrcved)) {
							dp += numrcved;
							// ret =+ buf;
							// reversed!!!
							//total =+ numrcved;
							total += numrcved;
							printf(" %d", total);
							if(numrcved==0) break;
						}
						printf("\n Total: %d\n", total);

						// printf((char*)ret); //Not Here

						// free(ret);
					InternetCloseHandle(hIurl);

						// return true;
					} else {
						showError("Failed to get size");
					}

				} else {
					showError("Failed to open URL");
				}
				InternetCloseHandle(hInet);
			} else {
				showError("Failed to open downloader");
			}
		} else {
			showError("Failed to connect to internet");
		}
	} else {
		showError("Invalid URL");
	}
	if (ret!=NULL) {
		// do something
		free(ret);
		return true;
	}
	return false;
}

int main(int argc, char *argv[]) {
	char *url = "http://download.tuxfamily.org/notepadplus/5.9.8/npp.5.9.8.Installer.exe";

	printf("Beginning download\n");
	if(download(url)) {
		printf("Download Complete\n");
	}
	system("PAUSE");
	return EXIT_SUCCESS;
}



Like your code, it doesn't actually do anything with the result. Also, understand that HTTP_QUERY_CONTENT_LENGTH isn't always going to be available.

Let's do something marginally more useful and save that data to a file. Now we probably do want to grab the filename, just to save.

#include <stdio.h>
#include <stdlib.h>

#include <Windows.h>
#include <WinInet.h>

#pragma comment (lib, "Wininet")


typedef struct {
	const char *url, *filename;
	BYTE *data;
	DWORD size, bytesRead;
} DownloadInfo;

BOOL ishttp(const char *url) {
	return tolower(url[0])=='h'
		&& tolower(url[1])=='t'
		&& tolower(url[2])=='t'
		&& tolower(url[3])=='p';
}

BOOL initInfo(DownloadInfo *info, const char *url) {
	info->url = url;
	info->data = NULL;
	info->size = info->bytesRead = 0;
	if (ishttp(url)) {
		info->filename = strrchr(url, '/');
		if (info->filename!=NULL) { info->filename++; }
		return 1;
	}
	info->filename = NULL;
	return 0;
}

void freeInfo(DownloadInfo *info) {
	if (info->data!=NULL) { 
		free(info->data); 
		info->data = NULL;
	}
	info->filename = info->url = NULL;
	info->size = info->bytesRead = 0;
}

void showError(const char *msg) {
	printf("ERROR: %s\n", msg);
}

void showInfo(DownloadInfo *info) {
	printf("URL: %s\n", info->url);
	printf("Filename: %s\n", (info->filename==NULL ? "Unknown" : info->filename));
	printf("Size: %d\n", info->size);
	printf("Read: %d\n", info->bytesRead);
}

void saveInfo(DownloadInfo *info) {
	FILE *fh;
	fopen_s(&fh, info->filename, "wb");
	fwrite(info->data, info->bytesRead, 1, fh);
	fclose(fh);
}

BOOL loadSize(DownloadInfo *info, HINTERNET hIurl) {
	DWORD dataSize = sizeof(info->size);
	return HttpQueryInfo(hIurl, HTTP_QUERY_CONTENT_LENGTH | HTTP_QUERY_FLAG_NUMBER, &info->size, &dataSize, NULL);
}


BOOL readUrlAll(HINTERNET hIurl, DownloadInfo *info) {
	return InternetReadFile(hIurl, info->data, info->size, &info->bytesRead);
}

BOOL readUrl(HINTERNET hIurl, DownloadInfo *info) {
	const int CHUNK_SIZE = 1024;
	DWORD bytesRead;
	BYTE *dp = info->data;

	printf("downloading:");
	while(info->bytesRead<info->size && InternetReadFile(hIurl, dp, CHUNK_SIZE, &bytesRead)) {
		dp += bytesRead;
		info->bytesRead += bytesRead;
		printf(" ."); fflush(stdout);
	}
	printf("\n");
}


BOOL downloadOpenUrl(HINTERNET hIurl, DownloadInfo *info) {
	BOOL isGood = FALSE;
	if (!loadSize(info, hIurl) || info->size==0) {
		showError("unable to get size");
	} else if ((info->data = (BYTE *)malloc(info->size))==NULL) {
		showError("unable to allocate memory");
	} else if (!readUrl(hIurl, info)) {
	// } else if (!readUrlAll(hIurl, info)) {
		showError("error reading");
	} else {
		return TRUE;
	}
	return FALSE;
}

BOOL downloadUrl(HINTERNET hInet, const char *url, DownloadInfo *info) {
	BOOL isGood = FALSE;
	if (!initInfo(info, url)) {
		showError("invalid url");
	} else {
		HINTERNET hIurl;
		if((hIurl = InternetOpenUrl(hInet, url, NULL, 0, INTERNET_FLAG_NO_CACHE_WRITE, 0)) == NULL) {
			showError("unable to open url");
		} else {
			isGood = downloadOpenUrl(hIurl, info);
			InternetCloseHandle(hIurl);
		}
	}
	return isGood;
}



int main(int argc, char *argv[]) {
	HINTERNET hInet;

	if(InternetAttemptConnect(0) == ERROR_SUCCESS && (hInet = InternetOpen("downloader", INTERNET_OPEN_TYPE_DIRECT, NULL, NULL, 0))!=NULL) {
		DownloadInfo info;
		//downloadUrl(hInet, "http://download.tuxfamily.org/notepadplus/5.9.8/npp.5.9.8.Installer.exe", &info);
		downloadUrl(hInet, "http://www.google.com/intl/en_com/images/srpr/logo3w.png", &info);
		InternetCloseHandle(hInet);
		showInfo(&info);
		saveInfo(&info);
		freeInfo(&info);
		system("PAUSE");
		return 0;
	}
	system("PAUSE");
	return 1;
}




Your code is essentially C code in a C++ context. My test is straight C, just to be honest.

C++ methodology would help you considerably here. A vector of BYTE would mean you needn't know the size ahead of time. Even better, you needn't allocate it ahead of time.
Was This Post Helpful? 1
  • +
  • -

Page 1 of 1