3

I have the following code to download some rss files from servers, but so far I'm just getting incomplete version of my rss file.(?) The code is as follows -

#include<iostream>
#include<conio.h>
#include<stdio.h>
#include<string>
#include<cstring>
#include<wininet.h> 
using namespace std;
const int _SIZE = 307200;
int WEB_GET_DATA(char* WEB_URL){
    HINTERNET WEB_CONNECT = InternetOpen("Default_User_Agent",INTERNET_OPEN_TYPE_PRECONFIG,NULL, NULL, 0);
    if(!WEB_CONNECT){
       cout<<"Connection Failed or Syntax error";
       return 0;
    }
    HINTERNET WEB_ADDRESS = InternetOpenUrl(WEB_CONNECT,WEB_URL, NULL, 0, INTERNET_FLAG_KEEP_CONNECTION, 0);
    if(!WEB_ADDRESS){
          cout<<"ERROR...\n";
          return 0;
    }
    char _DATA_RECIEVED[_SIZE];
    DWORD NO_BYTES_READ = 0;
    while(InternetReadFile(WEB_ADDRESS,_DATA_RECIEVED,_SIZE,&NO_BYTES_READ)&&(NO_BYTES_READ)){
        cout<<_DATA_RECIEVED;
    }
    InternetCloseHandle(WEB_ADDRESS);
    InternetCloseHandle(WEB_CONNECT);
    return 0;
}
int main(){
  WEB_GET_DATA("http://themoneyconverter.com/rss-feed/AED/rss.xml");
  getch();
  return 0;   
}

I'm getting only almost half of my file and not from start but my output is seeming to be starting from somewhere in between the file and then to it's end. So where I'm going wrong? I checked that my rss file is at least gonna be 30kb large. So I have given the _SIZE const 307200 (300kb) and still it is not working? Please help me.

Divya Mamgai
  • 31
  • 1
  • 2
  • Keeping conventions and standards in mind will make your code easier to read and help you get better answers. UPPER_CASE identifiers are typically only for macros, and identifiers beginning with an underscore in the global scope are reserved for compiler use. – Cory Nelson Jul 26 '13 at 03:56
  • Okay, will keep in mind. But can you help me with my problem? – Divya Mamgai Jul 26 '13 at 14:58

3 Answers3

0

Try this instead:

int WEB_GET_DATA(char* WEB_URL)
{
    HINTERNET WEB_CONNECT = InternetOpen("Default_User_Agent", INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0);
    if (!WEB_CONNECT)
    {
       cout << "Connection Failed or Syntax error" << endl;
       return 0;
    }

    HINTERNET WEB_ADDRESS = InternetOpenUrl(WEB_CONNECT, WEB_URL, NULL, 0, INTERNET_FLAG_KEEP_CONNECTION, 0);
    if (!WEB_ADDRESS)
    {
        cout << "ERROR..." << endl;
        InternetCloseHandle(WEB_CONNECT);
        return 0;
    }

    DWORD DATA_SIZE = _SIZE;
    char *_DATA_RECIEVED = new char[DATA_SIZE];
    DWORD NO_BYTES_READ = 0;

    do
    { 
        if (InternetReadFile(WEB_ADDRESS, _DATA_RECIEVED, DATA_SIZE, &NO_BYTES_READ))
        { 
            if (NO_BYTES_READ == 0)
                break;

            cout << string(_DATA_RECIEVED, NO_BYTES_READ);
        }
        else
        {
            if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
            {
                cout << "Read error" << endl;
                break;
            }

            delete[] _DATA_RECIEVED;
            DATA_SIZE += _SIZE;
            _DATA_RECIEVED = new char[DATA_SIZE];
        }
    }
    while (true);

    InternetCloseHandle(WEB_ADDRESS);
    InternetCloseHandle(WEB_CONNECT);
    return 0;
}
Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
  • Sorry but it's not working either. I tried other files of sizes around 30kb and they all gave me the same error of missing data on the output. – Divya Mamgai Jul 26 '13 at 05:26
  • Did you check if the data has null characters in it? Did you try saving the data to a file instead of outputting it to the screen? Screen output can't display binary data. So verify the actual data, not the screen results. – Remy Lebeau Jul 26 '13 at 19:30
-1
char buffer[200000];
DWORD bytes_read = 0;
DWORD currbytes_read;
do
{
    bRead = InternetReadFile(file_handle, buffer + bytes_read, 200000 - bytes_read, &currbytes_read);
    bytes_read += currbytes_read;

} while (bRead && currbytes_read);

buffer[bytes_read] = 0;
-2

First of all, the problem you are having is that you are overwriting the same buffer and you are not clearing the data before each call of InternetReadFile. You also have not cleared the buffer before your first call. You are then throwing a potentially garbled mess of string and memory into a cout. This is very bad.

A quick fix would be to do this:

BYTE _DATA_RECIEVED[_SIZE]; // BYTE is a char, but its clearer now its not guaranteed to be a string!
BOOL ret = TRUE;
DWORD NO_BYTES_READ = 0;
while(ret){
    memset(_DATA_RECIEVED, 0, _SIZE); // clear the buffer
    ret = InternetReadFile(WEB_ADDRESS,_DATA_RECIEVED,_SIZE,&NO_BYTES_READ);
    if(NO_BYTES_READ > 0)
        cout<<_DATA_RECIEVED;
}

This is not the most elegant way of doing it (far from it), but at least you should get the data you expect back.

Remember, InternetReadFile passes back a buffer of data, not necessarily a string! It could be an image, junk, and even if it is a string, in your case, it wont have a null byte to close it off. InternetReadFile reads raw bytes, NOT text.

A more elegant solution might start like this:

std::string resultRss;
BYTE _DATA_RECIEVED[_SIZE];
DWORD NO_BYTES_READ = 0;
while(InternetReadFile(WEB_ADDRESS,_DATA_RECIEVED,_SIZE,&NO_BYTES_READ)){
    resultRss.append((char*)_DATA_RECIEVED, NO_BYTES_READ); //doesn't matter about null-byte because we are defining the number of bytes to append. This also means we don't NEED to clear the memory, although you might want to.
}
//output final result
cout << resultRss;

Also, as a commenter added, you need to lay off the ALLCAPS for variables.

Hope this helps.

  • 1
    Alright I get what you mean. But when I compiled your second approach I got an error - 55 C:\Users\Maximus7\Documents\Untitled1.cpp:24 call of overloaded 'append(BYTE [307200], DWORD&)' is ambiguous. What's this? – Divya Mamgai Jul 26 '13 at 04:37
  • 1
    And on the weird side the first approach is still giving me the same results? Also I found something interesting, that for each "\n" I included after `cout<<_DATA_RECIEVED`, I got line less! Is it related to my problem? – Divya Mamgai Jul 26 '13 at 04:40
  • 1
    Sorry, I adjusted the code, a small mistake. I changed the line resultRss.append((char*)_DATA_RECIEVED, NO_BYTES_READ); . Because we are defining it as a byte (unsigned char*), we need to cast _DATA_RECIEVED as (char*). Or, you could replace BYTE with CHAR acain. The second example is simply to get you thinking about more robust alternatives, like storing the data not just outputting it to the screen. – Rhys Butler Jul 26 '13 at 04:42
  • Not sure why, it should work ok. Another trick, is to set some breakpoints and debug to step through, looking at _DATA_RECIEVED after each call to InternetReadFile. What is happening? – Rhys Butler Jul 26 '13 at 04:48
  • 1
    Yeah I already did that but still the output is not right. (No output is being given! None! Just an Empty screen??) – Divya Mamgai Jul 26 '13 at 04:48
  • Try the second method and see if the resultRss contains the correct data or not. If it does, then perhaps your doing something funny with cout later on. Newlines should be "\r\n" – Rhys Butler Jul 26 '13 at 04:53
  • First of all I'm not doing anything funny with it, and second of all your second method is not completely working, I'm not getting any output with it. – Divya Mamgai Jul 26 '13 at 04:57
  • Alright for second method to work even a little bit, I changed the flags of `InternetOpen` to `INTERNET_OPEN_TYPE_DIRECT` and that of `InternetOpenUrl` to `INTERNET_FLAG_EXISTING_CONNECT|INTERNET_FLAG_KEEP_CONNECTION`, but still the output is missing data. – Divya Mamgai Jul 26 '13 at 05:01
  • The `memset()` is redundant. You don't need to clear the buffer before the read. This is just cargo-cult programming. What you need to do is make use of the value returned by the read, and not process the buffer beyond that point. – user207421 May 25 '23 at 10:08