mirror of
https://github.com/SFML/SFML.git
synced 2024-11-28 22:31:09 +08:00
Fixed FTP download and upload file sizes being limited by available RAM (#565).
This commit is contained in:
parent
1851dcb109
commit
362a590454
@ -229,7 +229,7 @@ public :
|
||||
/// \param data Data containing the raw listing
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
ListingResponse(const Response& response, const std::vector<char>& data);
|
||||
ListingResponse(const Response& response, const std::string& data);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Return the array of directory/file names
|
||||
@ -452,6 +452,9 @@ public :
|
||||
/// current working directory of the server, and the local
|
||||
/// destination path is relative to the current directory
|
||||
/// of your application.
|
||||
/// If a file with the same filename as the distant file
|
||||
/// already exists in the local destination path, it will
|
||||
/// be overwritten.
|
||||
///
|
||||
/// \param remoteFile Filename of the distant file to download
|
||||
/// \param localPath The directory in which to put the file on the local computer
|
||||
|
@ -27,11 +27,13 @@
|
||||
////////////////////////////////////////////////////////////
|
||||
#include <SFML/Network/Ftp.hpp>
|
||||
#include <SFML/Network/IpAddress.hpp>
|
||||
#include <SFML/System/Err.hpp>
|
||||
#include <algorithm>
|
||||
#include <cctype>
|
||||
#include <fstream>
|
||||
#include <iterator>
|
||||
#include <sstream>
|
||||
#include <cstdio>
|
||||
|
||||
|
||||
namespace sf
|
||||
@ -48,10 +50,10 @@ public :
|
||||
Ftp::Response open(Ftp::TransferMode mode);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void send(const std::vector<char>& data);
|
||||
void send(std::istream& stream);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void receive(std::vector<char>& data);
|
||||
void receive(std::ostream& stream);
|
||||
|
||||
private :
|
||||
|
||||
@ -115,17 +117,16 @@ const std::string& Ftp::DirectoryResponse::getDirectory() const
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
Ftp::ListingResponse::ListingResponse(const Ftp::Response& response, const std::vector<char>& data) :
|
||||
Ftp::ListingResponse::ListingResponse(const Ftp::Response& response, const std::string& data) :
|
||||
Ftp::Response(response)
|
||||
{
|
||||
if (isOk())
|
||||
{
|
||||
// Fill the array of strings
|
||||
std::string paths(data.begin(), data.end());
|
||||
std::string::size_type lastPos = 0;
|
||||
for (std::string::size_type pos = paths.find("\r\n"); pos != std::string::npos; pos = paths.find("\r\n", lastPos))
|
||||
for (std::string::size_type pos = data.find("\r\n"); pos != std::string::npos; pos = data.find("\r\n", lastPos))
|
||||
{
|
||||
m_listing.push_back(paths.substr(lastPos, pos - lastPos));
|
||||
m_listing.push_back(data.substr(lastPos, pos - lastPos));
|
||||
lastPos = pos + 2;
|
||||
}
|
||||
}
|
||||
@ -206,7 +207,7 @@ Ftp::DirectoryResponse Ftp::getWorkingDirectory()
|
||||
Ftp::ListingResponse Ftp::getDirectoryListing(const std::string& directory)
|
||||
{
|
||||
// Open a data channel on default port (20) using ASCII transfer mode
|
||||
std::vector<char> directoryData;
|
||||
std::ostringstream directoryData;
|
||||
DataChannel data(*this);
|
||||
Response response = data.open(Ascii);
|
||||
if (response.isOk())
|
||||
@ -223,7 +224,7 @@ Ftp::ListingResponse Ftp::getDirectoryListing(const std::string& directory)
|
||||
}
|
||||
}
|
||||
|
||||
return ListingResponse(response, directoryData);
|
||||
return ListingResponse(response, directoryData.str());
|
||||
}
|
||||
|
||||
|
||||
@ -285,33 +286,34 @@ Ftp::Response Ftp::download(const std::string& remoteFile, const std::string& lo
|
||||
response = sendCommand("RETR", remoteFile);
|
||||
if (response.isOk())
|
||||
{
|
||||
// Extract the filename from the file path
|
||||
std::string filename = remoteFile;
|
||||
std::string::size_type pos = filename.find_last_of("/\\");
|
||||
if (pos != std::string::npos)
|
||||
filename = filename.substr(pos + 1);
|
||||
|
||||
// Make sure the destination path ends with a slash
|
||||
std::string path = localPath;
|
||||
if (!path.empty() && (path[path.size() - 1] != '\\') && (path[path.size() - 1] != '/'))
|
||||
path += "/";
|
||||
|
||||
// Create the file and truncate it if necessary
|
||||
std::ofstream file((path + filename).c_str(), std::ios_base::binary | std::ios_base::trunc);
|
||||
if (!file)
|
||||
return Response(Response::InvalidFile);
|
||||
|
||||
// Receive the file data
|
||||
std::vector<char> fileData;
|
||||
data.receive(fileData);
|
||||
data.receive(file);
|
||||
|
||||
// Close the file
|
||||
file.close();
|
||||
|
||||
// Get the response from the server
|
||||
response = getResponse();
|
||||
if (response.isOk())
|
||||
{
|
||||
// Extract the filename from the file path
|
||||
std::string filename = remoteFile;
|
||||
std::string::size_type pos = filename.find_last_of("/\\");
|
||||
if (pos != std::string::npos)
|
||||
filename = filename.substr(pos + 1);
|
||||
|
||||
// Make sure the destination path ends with a slash
|
||||
std::string path = localPath;
|
||||
if (!path.empty() && (path[path.size() - 1] != '\\') && (path[path.size() - 1] != '/'))
|
||||
path += "/";
|
||||
|
||||
// Create the file and copy the received data into it
|
||||
std::ofstream file((path + filename).c_str(), std::ios_base::binary);
|
||||
if (!file)
|
||||
return Response(Response::InvalidFile);
|
||||
|
||||
if (!fileData.empty())
|
||||
file.write(&fileData[0], static_cast<std::streamsize>(fileData.size()));
|
||||
}
|
||||
// If the download was unsuccessful, delete the partial file
|
||||
if (!response.isOk())
|
||||
std::remove((path + filename).c_str());
|
||||
}
|
||||
}
|
||||
|
||||
@ -327,13 +329,6 @@ Ftp::Response Ftp::upload(const std::string& localFile, const std::string& remot
|
||||
if (!file)
|
||||
return Response(Response::InvalidFile);
|
||||
|
||||
file.seekg(0, std::ios::end);
|
||||
std::size_t length = static_cast<std::size_t>(file.tellg());
|
||||
file.seekg(0, std::ios::beg);
|
||||
std::vector<char> fileData(length);
|
||||
if (length > 0)
|
||||
file.read(&fileData[0], static_cast<std::streamsize>(length));
|
||||
|
||||
// Extract the filename from the file path
|
||||
std::string filename = localFile;
|
||||
std::string::size_type pos = filename.find_last_of("/\\");
|
||||
@ -355,7 +350,7 @@ Ftp::Response Ftp::upload(const std::string& localFile, const std::string& remot
|
||||
if (response.isOk())
|
||||
{
|
||||
// Send the file data
|
||||
data.send(fileData);
|
||||
data.send(file);
|
||||
|
||||
// Get the response from the server
|
||||
response = getResponse();
|
||||
@ -584,15 +579,20 @@ Ftp::Response Ftp::DataChannel::open(Ftp::TransferMode mode)
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void Ftp::DataChannel::receive(std::vector<char>& data)
|
||||
void Ftp::DataChannel::receive(std::ostream& stream)
|
||||
{
|
||||
// Receive data
|
||||
data.clear();
|
||||
char buffer[1024];
|
||||
std::size_t received;
|
||||
while (m_dataSocket.receive(buffer, sizeof(buffer), received) == Socket::Done)
|
||||
{
|
||||
std::copy(buffer, buffer + received, std::back_inserter(data));
|
||||
stream.write(buffer, static_cast<std::streamsize>(received));
|
||||
|
||||
if (!stream.good())
|
||||
{
|
||||
err() << "FTP Error: Writing to the file has failed" << std::endl;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Close the data socket
|
||||
@ -601,11 +601,37 @@ void Ftp::DataChannel::receive(std::vector<char>& data)
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void Ftp::DataChannel::send(const std::vector<char>& data)
|
||||
void Ftp::DataChannel::send(std::istream& stream)
|
||||
{
|
||||
// Send data
|
||||
if (!data.empty())
|
||||
m_dataSocket.send(&data[0], data.size());
|
||||
char buffer[1024];
|
||||
std::size_t count;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
// read some data from the stream
|
||||
stream.read(buffer, sizeof(buffer));
|
||||
|
||||
if (!stream.good() && !stream.eof())
|
||||
{
|
||||
err() << "FTP Error: Reading from the file has failed" << std::endl;
|
||||
break;
|
||||
}
|
||||
|
||||
count = stream.gcount();
|
||||
|
||||
if (count > 0)
|
||||
{
|
||||
// we could read more data from the stream: send them
|
||||
if (m_dataSocket.send(buffer, count) != Socket::Done)
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
// no more data: exit the loop
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Close the data socket
|
||||
m_dataSocket.disconnect();
|
||||
|
Loading…
Reference in New Issue
Block a user