How to download binary file using wxwidgets - c++

I found this code snippet for downloading file:
wxURL url(wxT("http://www.example.com/file.txt"));
if(url.GetError()==wxURL_NOERR)
{
wxString htmldata;
wxInputStream *in = url.GetInputStream();
if(in && in->IsOk())
{
wxStringOutputStream html_stream(&htmldata);
in->Read(html_stream);
wxLogMessage(htmldata);
}
delete in;
}
But fistly it just logs content of file and only for text-files. But I need to download *.exe file to execute it later. So I need to adapt this code to work with binary data, and save this data to file on the disk. Too many Streams used here for my understanding what's going on here. Please help.

I have written below code previously...
This will work fine to download binary files in any platforms.
/** START */
// ex) ht tp://mysite.com/mypath.jpg
wxString path = wxT("/mypath.jpg");
wxString server = wxT("mysite.com");
wxHTTP http;
http.SetHeader(_T("Content-type"), contentType);
http.SetTimeout(10);
// wxString imageFilePath = wxT("/tmp/image.jpg");
wxFileOutputStream output(imageFilePath);
wxDataOutputStream store(output);
if (http.Connect(server, 80))
{
wxInputStream *stream;
stream = http.GetInputStream(path);
if (stream == NULL)
{
output.Close();
}
else
{
unsigned char buffer[1024];
int byteRead;
// receive stream
while (!stream->Eof())
{
stream->Read(buffer, sizeof(buffer));
store.Write8(buffer, sizeof(buffer));
byteRead = stream->LastRead();
if (byteRead <= 0)
{
break;
}
}
output.Close();
}
}
else
{
output.Close();
}

Related

C++ remove() and rename() gives "Permission error"

I can't figure out what is happening in my program, it's a simple function to clear all the Windows '\r' from a file, putting all the chars in another file and then rename it to substitute the old file. Every time I execute the function the rename() and remove() functions give me "Permission error" even if I had all the file pointers closed and the file on my PC is closed in every program. Here's the code
static bool correctFile(string fileName) {
string name = fileName;
FILE* test = fopen(fileName.c_str(), "rb");
FILE *in, *out;
char stringTest[1000];
bool isWinFile = false;
if (!test) {
return false;
}
fread(stringTest, 1, 1000, test);
fclose(test);
for (size_t i = 0; i < strlen(stringTest) && !isWinFile; i++) {
if (stringTest[i] == '\r') {
isWinFile = true;
}
}
if (isWinFile) {
in = fopen(fileName.c_str(), "rb");
string tempFile = name + ".temp";
out = fopen(tempFile.c_str(), "wb");
if (!in || !out) {
return false;
}
char temp;
while (fread(&temp, sizeof(temp), 1, in) > 0) {
if (temp != '\r') {
fwrite(&temp, sizeof(temp), 1, out);
}
}
fclose(in);
fclose(out);
if (std::remove(fileName.c_str())) {
std::cerr << "Error: " << strerror(errno);
return false;
}
if (std::rename(tempFile.c_str(), fileName.c_str())) {
return false;
}
}
return true;
}
If you find an error in this please tell me, thanks
I found out that the old file and the new file must not be in the same folder for some reason
Disable the virus scanner and see if the problem persists. Some antivirus products block access to files for a couple of microseconds after they have been written or modified. I know of Kaspersky for example.
I have a "Antivirus" retry loop in some of my batch files because of this. So one (ugly) solution is to retry the rename/remove operations a couple of times.

Read line by line in file and store into string, Flash data saving SPIFFS

I'm working on a project with Flash data saving. I'm using SPIFFS library for ESP32, I'm currently attempting to store the data from each line into a String. Since I have control of how many content can go into the file, it won't need more than 3 Strings to store the data. I could easily manage to store the first line content using readStringUntil. But I can't manage to get the content from 2 and 3 line.
For the first line I'm using this code:
//Pegar a primeira linha do arquivo, onde será armazenado o nome do WIFI (ssid)
void first_line (){
file = SPIFFS.open("/wifi.txt", "r");
while (file.available()) {
String first_line = file.readStringUntil('\n');
Serial.print(first_line);
break;
}
file.close();
}
I'm writing the code into the File with this function:
// Escrever mensagem dentro do arquivo
void write_file_info(String message) {
file = SPIFFS.open("/wifi.txt", FILE_WRITE);
if (!file){
Serial.println("Error opening file");
return;
}else{
Serial.println("Success opening file");
}
if (file.println(message)){
Serial.println("File was written");
}else{
Serial.println("File was not written");
}
file.close();
}
And I'm using Append to add the second and third line:
void append_file_info (String message){
file = SPIFFS.open("/wifi.txt", FILE_APPEND);
if (!file){
Serial.println("Erro ao realizar APPEND ao arquivo");
}
if (file.println(message)){
Serial.println("File was added");
}else{
Serial.println("File was not added");
}
file.close();
}
This is the current output, file size is just for manage and "content inside file" is just for reference:
File size: 37
Content inside file:
first line
second line
thrid line
This is how I'm reading the file:
void read_file_info() {
file = SPIFFS.open("/wifi.txt");
Serial.print("\nFile size: ");
Serial.println(file.size());
Serial.print("Content inside file: \n");
while (file.available()){
Serial.write(file.read());
}
Serial.println("\n");
file.close();
delay(3000);
}
I thought on trying to read the data after '\n', but couldn't find any documentation on reading after certain string.
I tried creating a buffer and splitting it later, the output from the buffer is correct but I can't split it into strings correctly:
void second_line (){
file = SPIFFS.open("/wifi.txt", "r");
char buffer[64];
while (file.available()) {
int l = file.readBytesUntil('\n', buffer, sizeof(buffer));
buffer[l] = 0;
Serial.println(buffer);
}
file.close();
}
It would be simpler using vector:
#include <SPIFFS.h>
using namespace std;
void setup() {
Serial.begin(115200);
if (!SPIFFS.begin(true)) {
Serial.println("An Error has occurred while mounting SPIFFS");
return;
}
File file = SPIFFS.open("/wifi.txt");
if (!file) {
Serial.println("Failed to open file for reading");
return;
}
vector<String> v;
while (file.available()) {
v.push_back(file.readStringUntil('\n'));
}
file.close();
for (String s : v) {
Serial.println(s);
}
}
void loop() {}
Use v[0] to get first line, v[1] for second line, v[2] for third line and so on.
I could manage to get it working like this:
void all_lines (){
file = SPIFFS.open("/wifi.txt", "r");
int i = 0;
char buffer[64];
String line_one, line_two, line_three;
while (file.available()) {
int l = file.readBytesUntil('\n', buffer, sizeof(buffer));
buffer[l] = 0;
if (i == 0) {
line_one = buffer;
}
if (i == 1) {
line_two = buffer;
}
if (i == 2) {
line_three = buffer;
}
i++;
if (i == 3){
break;
}
}
file.close();
}

ESP8266 SPIFFS textfile read returns weird characters

I'm trying to store some hex color palettes in the ESP8266's SPIFFS but when I try to retrieve them I get some weird chars. The code and the log output are below:
Code (ino file):
#include "FS.h" // https://github.com/esp8266/Arduino/
#include <JsonParser.h> // https://github.com/henrikekblad/ArduinoJson
#include <JsonGenerator.h> // https://github.com/henrikekblad/ArduinoJson
using namespace ArduinoJson;
void setup(void) {
Serial.begin(9600);
SPIFFS.format();
SPIFFS.begin();
writeTxtFile("/palettes/warm.json", "[\"ffffff\",\"ed1414\",\"f6f336\",\"ff7e15\"]");
writeTxtFile("/palettes/pastel.json", "[\"ffffff\",\"ff7b7b\",\"8fff70\",\"7878ff\"]");
readPalettes();
}
void loop(void) {
}
bool readPalettes(void) {
bool succeeded = true;
Dir dir = SPIFFS.openDir("/palettes");
while (dir.next()) {
File palette = dir.openFile("r");
if (!readFile(palette, loadPaletteJson)) succeeded = false;
palette.close();
yield();
}
return succeeded;
}
bool loadPaletteJson(char* json, String fileName) {
Serial.print(fileName);Serial.print(F(": "));Serial.println(json);
Parser::JsonParser<5> parser; // one palette is 1+4*1=5 tokens
Parser::JsonArray p = parser.parseArray(json);
if (p.success()) {
//Store the palettes in a vector using a specific structure
return true;
} else {
Serial.println(F("JSON parsing failed"));
}
return false;
}
bool readFile(File file, std::function<bool (char* json, String fileName)> callback) {
if (file) {
String fileName = file.name();
size_t fileSize = file.size();
Serial.print(F("Reading "));Serial.print(fileSize);Serial.print(F(" bytes from "));Serial.println(fileName);
if (fileSize <= 1024) {
char buf[fileSize];
file.readBytes(buf, fileSize);
return callback(buf, getBaseName(fileName));
} else {
Serial.println(F("file size is too large"));
}
} else {
Serial.println(F("file open failed"));
}
return false;
}
String getBaseName(String fileName) {
return fileName.substring(fileName.lastIndexOf('/') + 1, fileName.lastIndexOf('.'));
}
bool writeTxtFile(String path, String content) {
File file = SPIFFS.open(path, "w");
if (file) {
Serial.print(F("Writing content: "));Serial.print(content);Serial.print(F(" to: "));Serial.println(path);
file.print(content);
file.close();
return true;
} else {
Serial.print(F("file open failed: "));Serial.println(path);
}
return false;
}
Arduino's IDE console output:
Writing content: ["ffffff","ed1414","f6f336","ff7e15"] to: /palettes/warm.json
Writing content: ["ffffff","ff7b7b","8fff70","7878ff"] to: /palettes/pastel.json
Reading 37 bytes from /palettes/warm.json
warm: ["ffffff","ed1414","f6f336","ff7e15"]⸮?8⸮?tu #
JSON parsing failed
Reading 37 bytes from /palettes/pastel.json
pastel: ["ffffff","ff7b7b","8fff70","7878ff"]⸮?8⸮?tu #
JSON parsing failed
I don't understand why those chars (⸮?8⸮?tu #) are added to a limited sized buffer. I tried to replace my buffer (char buf[fileSize];) with a unique pointer like this: std::unique_ptr<char[]> buf(new char[fileSize]); (in the function readFile) using buf.get() in the next 2 statements but with the exact same result.
Am I missing something?
EDIT:
As #leetibbett mentioned below, I'm writing a String while trying to read bytes. here is the correction for readFile function:
bool readFile(File file, std::function<bool (char* json, String fileName)> callback) {
if (file) {
String fileName = file.name();
size_t fileSize = file.size();
Serial.print(F("Reading "));Serial.print(fileSize);Serial.print(F(" bytes from "));Serial.println(fileName);
if (fileSize <= 1024) {
String content = file.readStringUntil('\n');
return callback((char*)content.c_str(), getBaseName(fileName));
} else {
Serial.println(F("file size is too large"));
}
} else {
Serial.println(F("file open failed"));
}
return false;
}

FTP client -- CR characters in gif is removed after get

I'm creating an FTP client.
I'm getting a gif from the server, but after that the gif is corrupted.
When I change the file extension to look at the diff, I see that the
CR/LF characters are gone.
How could this be? I made sure to use image mode.
Here's my read code in TCP socket.
string TCPSocket::long_read()
{
pollfd ufds;
ufds.fd = sd;
ufds.events = POLLIN;
ufds.revents = 0;
ssize_t bytesRead = 0;
string result;
char* buf = new char[LONGBUFLEN];
do {
bzero(buf, LONGBUFLEN);
bytesRead = ::read(sd, buf, LONGBUFLEN);
if (bytesRead == 0) {
break;
}
if (bytesRead > 0) {
result = result + string(buf, bytesRead);
}
} while (poll(&ufds, 1, 1000) > 0);
return result;
}
Here my get code in main.cpp
else if (command == command::GET) {
string filename;
cin >> filename;
string dataHost;
int dataPort;
if (enterPassiveMode(dataHost, dataPort)) {
dataSocket = new TCPSocket(dataHost.c_str(), dataPort);
if (fork() == 0) {
string result = dataSocket->long_read();
size_t length = result.size();
char* resultArr = new char[length];
memcpy(resultArr, result.data(), length);
// mode_t mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH;
FILE* file = fopen(filename.c_str(), "w+b");
if (file) {
fwrite(resultArr, length, 1, file);
fclose(file);
}
else {
cout << "open failed";
}
break;
}
else {
writeAndImmediateRead(rfc959::TYPE_I);
controlSocket->write(rfc959::RETRIVE(filename));
string result = controlSocket->read();
cout << result;
int reply = Parser::firstDigit(result);
// I'll remove incomplete local file if request fails
if (reply != rfc959::POSITIVE_PRELIMINARY_REPLY) {
remove(filename.c_str());
continue;
}
wait(NULL);
cout << controlSocket->long_read();
}
}
}
EDIT
I did make sure to use Binary mode. And when I transferred a text file(though of a smaller size), it doesn't have this problem. Here's the output:
EDIT 2
Output from Wireshark showing Request: TYPE I and Response: Opening BINARY mode
By default, FTP servers and clients perform data transfers as "ASCII mode", which means that any CRLF sequence is translated on-the-fly to the host's ASCII line ending (e.g. just bare LF on Unix mmachines). This behavior is mandated by RFC 959; see Section 3.1.1.1.
To transfer your data as binary, and avoid the ASCII mode translation, your FTP client will want to send the TYPE command first, e.g.:
TYPE I
Your .gif file should then be transferred as is, with no replacements/transformations on any CRLF sequences.
Hope this helps!

Inflation of pdf stream using zlib blank sometimes

I am a beginner programmer trying to inflate text stream from pdfs. I have adopted and slightly altered some open source code which uses zlib, and generally it works very well. However, I have been testing on some different pdfs lately and some of the inflated streams are returning blank. Could anybody advise me as to why?
I have come across this question below which seems to address the same problem but does not really give a definitive answer
zLib inflate has empty result in some cases
#include <iostream>
#include <fstream>
#include <string>
#include "zlib.h"
int main()
{
//Discard existing output:
//Open the PDF source file:
std::ifstream filei("C:\\Users\\dpbowe\\Desktop\\PIDSearch\\P&ID.PDF", std::ios::in|std::ios::binary|std::ios::ate);
if (!filei) std::cout << "Error Opening Input File" << std::endl;
//decoded output
std::ofstream fileo;
fileo.open("C:\\Users\\dpbowe\\Desktop\\Decoded.txt", std::ios::binary | std::ofstream::out);
if (!fileother) std::cout << "Error opening output file" << std::endl;
if (filei && fileo)
{
//Get the file length:
long filelen = filei.tellg(); //fseek==0 if ok
filei.seekg(0, std::ios::beg);
//Read the entire file into memory (!):
char* buffer = new char [filelen];
if (buffer == NULL) {fputs("Memory error", stderr); exit(EXIT_FAILURE);}
filei.read(buffer,filelen);
if (buffer == '\0') {fputs("Reading error", stderr); exit(EXIT_FAILURE);}
bool morestreams = true;
//Now search the buffer repeated for streams of data
while (morestreams)
{
//Search for stream, endstream. Should check the filter of the object to make sure it if FlateDecode, but skip that for now!
size_t streamstart = FindStringInBuffer (buffer, "stream", filelen); //This is my own search function
size_t streamend = FindStringInBuffer (buffer, "endstream", filelen); //This is my own search function
if (streamstart>0 && streamend>streamstart)
{
//Skip to beginning and end of the data stream:
streamstart += 6;
if (buffer[streamstart]==0x0d && buffer[streamstart+1]==0x0a) streamstart+=2;
else if (buffer[streamstart]==0x0a) streamstart++;
if (buffer[streamend-2]==0x0d && buffer[streamend-1]==0x0a) streamend-=2;
else if (buffer[streamend-1]==0x0a) streamend--;
//Assume output will fit into 10 times input buffer:
size_t outsize = (streamend - streamstart)*10;
char* output = new char [outsize]; ZeroMemory(output, outsize);
//Now use zlib to inflate:
z_stream zstrm; ZeroMemory(&zstrm, sizeof(zstrm));
zstrm.avail_in = streamend - streamstart + 1;
zstrm.avail_out = outsize;
zstrm.next_in = (Bytef*)(buffer + streamstart);
zstrm.next_out = (Bytef*)output;
int rsti = inflateInit(&zstrm);
if (rsti == Z_OK)
{
int rst2 = inflate (&zstrm, Z_FINISH);
if (rst2 >= 0)
{
size_t totout = zstrm.total_out;
//Write inflated output to file "Decoded.txt"
fileother<<output;
fileother<<"\r\nStream End\r\n\r\n";
}
else std::cout<<"output uncompressed stream is blank"<<std::endl;
}
delete[] output; output=0;
buffer+= streamend + 7;
filelen = filelen - (streamend+7);
}
else
{
morestreams = false;
std::cout<<"End of File"<<std::endl;
}
}
filei.close();
}
else
{
std::cout << "File Could Not Be Accessed\n";
}
if (fileo) fileo.close();
}