| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| |
|
| |
|
| | #include <FCConfig.h>
|
| |
|
| |
|
| | #include <limits>
|
| |
|
| | #if defined(FC_OS_WIN32)
|
| | # include <Windows.h>
|
| | # include <cstdint>
|
| | #endif
|
| |
|
| | #include <openssl/hmac.h>
|
| | #include <openssl/md5.h>
|
| | #include <openssl/pem.h>
|
| | #include <openssl/sha.h>
|
| |
|
| | #include <curl/curl.h>
|
| |
|
| | #include <App/Application.h>
|
| | #include <App/Document.h>
|
| | #include <App/DocumentObject.h>
|
| | #include <App/DocumentPy.h>
|
| | #include <Base/Console.h>
|
| | #include <Base/Tools.h>
|
| | #include <Base/PyObjectBase.h>
|
| |
|
| | #include <CXX/Extensions.hxx>
|
| | #include <CXX/Objects.hxx>
|
| |
|
| | #include "AppCloud.h"
|
| |
|
| |
|
| | using namespace App;
|
| | using namespace std;
|
| | using namespace boost::placeholders;
|
| | XERCES_CPP_NAMESPACE_USE
|
| |
|
| |
|
| | PyMOD_INIT_FUNC(Cloud)
|
| | {
|
| | PyObject* mod = Cloud::initModule();
|
| | Base::Console().log("Loading Cloud module... done\n");
|
| | PyMOD_Return(mod);
|
| | }
|
| |
|
| | Py::Object Cloud::Module::sCloudURL(const Py::Tuple& args)
|
| | {
|
| | char* URL;
|
| | if (!PyArg_ParseTuple(args.ptr(), "et", "utf-8", &URL)) {
|
| | throw Py::Exception();
|
| | }
|
| |
|
| | std::string strURL = URL;
|
| | PyMem_Free(URL);
|
| | if (this->URL.getStrValue() != strURL) {
|
| | this->URL.setValue(strURL);
|
| | }
|
| |
|
| | return Py::None();
|
| | }
|
| |
|
| | Py::Object Cloud::Module::sCloudTokenAuth(const Py::Tuple& args)
|
| | {
|
| | char* TokenAuth;
|
| | if (!PyArg_ParseTuple(args.ptr(), "et", "utf-8", &TokenAuth)) {
|
| | throw Py::Exception();
|
| | }
|
| |
|
| | std::string strTokenAuth = TokenAuth;
|
| | PyMem_Free(TokenAuth);
|
| | if (this->TokenAuth.getStrValue() != strTokenAuth) {
|
| | this->TokenAuth.setValue(strTokenAuth);
|
| | }
|
| |
|
| | return Py::None();
|
| | }
|
| |
|
| | Py::Object Cloud::Module::sCloudTokenSecret(const Py::Tuple& args)
|
| | {
|
| | char* TokenSecret;
|
| | if (!PyArg_ParseTuple(args.ptr(), "et", "utf-8", &TokenSecret)) {
|
| | throw Py::Exception();
|
| | }
|
| |
|
| | std::string strTokenSecret = TokenSecret;
|
| | PyMem_Free(TokenSecret);
|
| | if (this->TokenSecret.getStrValue() != strTokenSecret) {
|
| | this->TokenSecret.setValue(strTokenSecret);
|
| | }
|
| |
|
| | return Py::None();
|
| | }
|
| |
|
| | Py::Object Cloud::Module::sCloudTCPPort(const Py::Tuple& args)
|
| | {
|
| | char* TCPPort;
|
| | if (!PyArg_ParseTuple(args.ptr(), "et", "utf-8", &TCPPort)) {
|
| | throw Py::Exception();
|
| | }
|
| |
|
| | std::string strTCPPort = TCPPort;
|
| | PyMem_Free(TCPPort);
|
| | if (this->TCPPort.getStrValue() != strTCPPort) {
|
| | this->TCPPort.setValue(strTCPPort);
|
| | }
|
| |
|
| | return Py::None();
|
| | }
|
| |
|
| | Py::Object Cloud::Module::sCloudSave(const Py::Tuple& args)
|
| | {
|
| | char* pDoc;
|
| | if (!PyArg_ParseTuple(args.ptr(), "et", "utf-8", &pDoc)) {
|
| | throw Py::Exception();
|
| | }
|
| |
|
| | std::string strpDoc = pDoc;
|
| | PyMem_Free(pDoc);
|
| | cloudSave(strpDoc.c_str());
|
| |
|
| | return Py::None();
|
| | }
|
| |
|
| |
|
| | Py::Object Cloud::Module::sCloudRestore(const Py::Tuple& args)
|
| | {
|
| | char* pDoc;
|
| | if (!PyArg_ParseTuple(args.ptr(), "et", "utf-8", &pDoc)) {
|
| | throw Py::Exception();
|
| | }
|
| |
|
| | std::string strpDoc = pDoc;
|
| | PyMem_Free(pDoc);
|
| | cloudRestore(strpDoc.c_str());
|
| |
|
| | return Py::None();
|
| | }
|
| |
|
| | Py::Object Cloud::Module::sCloudProtocolVersion(const Py::Tuple& args)
|
| | {
|
| | char* ProtocolVersion;
|
| | if (!PyArg_ParseTuple(args.ptr(), "et", "utf-8", &ProtocolVersion)) {
|
| | throw Py::Exception();
|
| | }
|
| |
|
| | std::string strProtocolVersion = ProtocolVersion;
|
| | PyMem_Free(ProtocolVersion);
|
| | if (this->ProtocolVersion.getStrValue() != strProtocolVersion) {
|
| | this->ProtocolVersion.setValue(strProtocolVersion);
|
| | }
|
| |
|
| | return Py::None();
|
| | }
|
| |
|
| | Py::Object Cloud::Module::sCloudRegion(const Py::Tuple& args)
|
| | {
|
| | char* Region;
|
| | if (!PyArg_ParseTuple(args.ptr(), "et", "utf-8", &Region)) {
|
| | throw Py::Exception();
|
| | }
|
| |
|
| | std::string strRegion = Region;
|
| | PyMem_Free(Region);
|
| | if (this->Region.getStrValue() != strRegion) {
|
| | this->Region.setValue(strRegion);
|
| | }
|
| |
|
| | return Py::None();
|
| | }
|
| |
|
| | struct data_buffer
|
| | {
|
| | const char* ptr;
|
| | size_t remaining_size;
|
| | };
|
| |
|
| | static size_t read_callback(void* ptr, size_t size, size_t nmemb, void* stream)
|
| | {
|
| |
|
| | struct data_buffer* local_ptr = (struct data_buffer*)stream;
|
| | size_t data_to_transfer = size * nmemb;
|
| |
|
| | if (local_ptr->remaining_size) {
|
| |
|
| | size_t copy_this_much = local_ptr->remaining_size;
|
| | if (copy_this_much > data_to_transfer) {
|
| | copy_this_much = data_to_transfer;
|
| | }
|
| | memcpy(ptr, local_ptr->ptr, copy_this_much);
|
| |
|
| | local_ptr->ptr += copy_this_much;
|
| | local_ptr->remaining_size -= copy_this_much;
|
| | return copy_this_much;
|
| | }
|
| |
|
| | return 0;
|
| | }
|
| |
|
| | void Cloud::CloudWriter::checkXML(DOMNode* node)
|
| | {
|
| | if (node) {
|
| | switch (node->getNodeType()) {
|
| | case DOMNode::ELEMENT_NODE:
|
| | checkElement(static_cast<DOMElement*>(node));
|
| | break;
|
| | case DOMNode::TEXT_NODE:
|
| | checkText(static_cast<DOMText*>(node));
|
| | break;
|
| | default:
|
| | break;
|
| | }
|
| | DOMNode* child = node->getFirstChild();
|
| | while (child) {
|
| | DOMNode* next = child->getNextSibling();
|
| | checkXML(child);
|
| | child = next;
|
| | }
|
| | }
|
| | }
|
| |
|
| | void Cloud::CloudWriter::checkElement(DOMElement* element)
|
| | {
|
| | char* name = XMLString::transcode(element->getTagName());
|
| | if (strcmp(name, "Code") == 0) {
|
| | print = 1;
|
| | }
|
| | XMLString::release(&name);
|
| | }
|
| |
|
| | void Cloud::CloudWriter::checkText(DOMText* text)
|
| | {
|
| |
|
| | XMLCh* buffer = new XMLCh[XMLString::stringLen(text->getData()) + 1];
|
| | XMLString::copyString(buffer, text->getData());
|
| | XMLString::trim(buffer);
|
| | char* content = XMLString::transcode(buffer);
|
| | delete[] buffer;
|
| | if (print) {
|
| | strcpy(errorCode, content);
|
| | }
|
| | print = 0;
|
| | XMLString::release(&content);
|
| | }
|
| |
|
| |
|
| | void Cloud::CloudWriter::createBucket()
|
| | {
|
| | struct Cloud::AmzData* RequestData;
|
| | struct Cloud::AmzDatav4* RequestDatav4;
|
| | CURL* curl;
|
| | CURLcode res;
|
| |
|
| | struct data_buffer curl_buffer;
|
| |
|
| | char path[1024];
|
| | sprintf(path, "/%s/", this->Bucket);
|
| | std::string strURL(this->URL);
|
| | eraseSubStr(strURL, "http://");
|
| | eraseSubStr(strURL, "https://");
|
| |
|
| | if (this->ProtocolVersion == "2") {
|
| | RequestData
|
| | = Cloud::ComputeDigestAmzS3v2("PUT", "application/xml", path, this->TokenSecret, nullptr, 0);
|
| | }
|
| | else {
|
| | RequestDatav4 = Cloud::ComputeDigestAmzS3v4(
|
| | "PUT",
|
| | strURL.c_str(),
|
| | "application/xml",
|
| | path,
|
| | this->TokenSecret,
|
| | nullptr,
|
| | 0,
|
| | nullptr,
|
| | this->Region
|
| | );
|
| | }
|
| |
|
| |
|
| | curl_global_init(CURL_GLOBAL_ALL);
|
| | curl = curl_easy_init();
|
| | #ifdef ALLOW_SELF_SIGNED_CERTIFICATE
|
| | curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0);
|
| | curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0);
|
| | #endif
|
| |
|
| | if (curl) {
|
| | struct curl_slist* chunk = nullptr;
|
| | char URL[256];
|
| |
|
| | std::string strURL(this->URL);
|
| | eraseSubStr(strURL, "http://");
|
| | eraseSubStr(strURL, "https://");
|
| | if (this->ProtocolVersion == "2") {
|
| | chunk = Cloud::BuildHeaderAmzS3v2(strURL.c_str(), this->TCPPort, this->TokenAuth, RequestData);
|
| | delete RequestData;
|
| | }
|
| | else {
|
| | chunk = Cloud::BuildHeaderAmzS3v4(strURL.c_str(), this->TokenAuth, RequestDatav4);
|
| | delete RequestDatav4;
|
| | }
|
| |
|
| | curl_easy_setopt(curl, CURLOPT_HTTPHEADER, chunk);
|
| |
|
| |
|
| |
|
| | sprintf(URL, "%s:%s/%s/", this->URL, this->TCPPort, this->Bucket);
|
| | curl_easy_setopt(curl, CURLOPT_URL, URL);
|
| |
|
| | curl_easy_setopt(curl, CURLOPT_UPLOAD, 1L);
|
| | curl_easy_setopt(curl, CURLOPT_PUT, 1L);
|
| |
|
| | curl_easy_setopt(curl, CURLOPT_READFUNCTION, read_callback);
|
| |
|
| | curl_buffer.ptr = nullptr;
|
| | curl_buffer.remaining_size = (size_t)0;
|
| |
|
| | curl_easy_setopt(curl, CURLOPT_READDATA, &curl_buffer);
|
| |
|
| | curl_easy_setopt(curl, CURLOPT_INFILESIZE_LARGE, (curl_off_t)0);
|
| | res = curl_easy_perform(curl);
|
| | if (res != CURLE_OK) {
|
| | fprintf(stderr, "curl_easy_perform() failed: %s\n", curl_easy_strerror(res));
|
| | }
|
| | curl_easy_cleanup(curl);
|
| | }
|
| | }
|
| |
|
| |
|
| | struct Cloud::AmzDatav4* Cloud::ComputeDigestAmzS3v4(
|
| | char* operation,
|
| | const char* server,
|
| | char* data_type,
|
| | const char* target,
|
| | const char* Secret,
|
| | const char* ptr,
|
| | long size,
|
| | char* parameters,
|
| | std::string Region
|
| | )
|
| | {
|
| | struct AmzDatav4* returnData;
|
| | returnData = new Cloud::AmzDatav4;
|
| | struct tm* tm;
|
| | char* canonical_request;
|
| | char* canonicalRequestHash;
|
| | char* stringToSign;
|
| |
|
| | strcpy(returnData->ContentType, data_type);
|
| |
|
| | #if defined(FC_OS_WIN32)
|
| | _putenv("TZ=GMT");
|
| | time_t rawtime;
|
| |
|
| | time(&rawtime);
|
| | tm = localtime(&rawtime);
|
| | #else
|
| | struct timeval tv;
|
| | setenv("TZ", "GMT", 1);
|
| | gettimeofday(&tv, nullptr);
|
| | tm = localtime(&tv.tv_sec);
|
| | #endif
|
| | strftime(returnData->dateFormattedD, 256, "%Y%m%d", tm);
|
| | strftime(returnData->dateFormattedS, 256, "%Y%m%dT%H%M%SZ", tm);
|
| | returnData->MD5 = nullptr;
|
| |
|
| |
|
| | canonical_request = (char*)malloc(4096 * (sizeof(char*)));
|
| | strcpy(canonical_request, operation);
|
| | strcat(canonical_request, "\n");
|
| | strcat(canonical_request, target);
|
| | strcat(canonical_request, "\n");
|
| | if (parameters == nullptr) {
|
| | strcat(canonical_request, "\n");
|
| | }
|
| | else {
|
| | strcat(canonical_request, parameters);
|
| | strcat(canonical_request, "\n");
|
| | }
|
| | strcat(canonical_request, "host:");
|
| | strcat(canonical_request, server);
|
| | strcat(canonical_request, "\n");
|
| | strcat(canonical_request, "x-amz-date:");
|
| | strcat(canonical_request, returnData->dateFormattedS);
|
| | strcat(canonical_request, "\n\n");
|
| | strcat(canonical_request, "host;x-amz-date\n");
|
| |
|
| | returnData->SHA256Sum = nullptr;
|
| | if (strcmp(operation, "PUT") == 0) {
|
| | if (ptr != nullptr) {
|
| | returnData->SHA256Sum = Cloud::SHA256Sum(ptr, size);
|
| | strcat(canonical_request, returnData->SHA256Sum);
|
| | }
|
| | else {
|
| | strcat(canonical_request, "UNSIGNED-PAYLOAD");
|
| | }
|
| | }
|
| | else {
|
| | strcat(canonical_request, "UNSIGNED-PAYLOAD");
|
| | }
|
| | canonicalRequestHash = Cloud::SHA256Sum(canonical_request, strlen(canonical_request));
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| | stringToSign = (char*)malloc(4096 * sizeof(char));
|
| | strcat(stringToSign, "AWS4-HMAC-SHA256");
|
| | strcat(stringToSign, "\n");
|
| | strcat(stringToSign, returnData->dateFormattedS);
|
| | strcat(stringToSign, "\n");
|
| | strcat(stringToSign, returnData->dateFormattedD);
|
| | strcat(stringToSign, "/us/s3/aws4_request");
|
| | strcat(stringToSign, "\n");
|
| | strcat(stringToSign, canonicalRequestHash);
|
| | strcat(stringToSign, "\0");
|
| |
|
| |
|
| |
|
| | char kSecret[256];
|
| | unsigned char *kDate, *kRegion, *kService, *kSigned, *kSigning;
|
| |
|
| | strcpy(kSecret, "AWS4");
|
| | strcat(kSecret, Secret);
|
| | unsigned int HMACLength;
|
| |
|
| | std::string temporary;
|
| |
|
| | kDate = HMAC(
|
| | EVP_sha256(),
|
| | kSecret,
|
| | strlen(kSecret),
|
| | (const unsigned char*)returnData->dateFormattedD,
|
| | strlen(returnData->dateFormattedD),
|
| | nullptr,
|
| | &HMACLength
|
| | );
|
| |
|
| | temporary = getHexValue(kDate, HMACLength);
|
| | temporary = getHexValue(kDate, HMACLength);
|
| |
|
| |
|
| | kRegion = HMAC(
|
| | EVP_sha256(),
|
| | kDate,
|
| | HMACLength,
|
| | (const unsigned char*)Region.c_str(),
|
| | strlen(Region.c_str()),
|
| | nullptr,
|
| | &HMACLength
|
| | );
|
| |
|
| | temporary = getHexValue(kRegion, HMACLength);
|
| |
|
| | kService = HMAC(
|
| | EVP_sha256(),
|
| | kRegion,
|
| | HMACLength,
|
| | (const unsigned char*)"s3",
|
| | strlen("s3"),
|
| | nullptr,
|
| | &HMACLength
|
| | );
|
| |
|
| | temporary = getHexValue(kService, HMACLength);
|
| |
|
| | kSigning = HMAC(
|
| | EVP_sha256(),
|
| | kService,
|
| | HMACLength,
|
| | (const unsigned char*)"aws4_request",
|
| | strlen("aws4_request"),
|
| | nullptr,
|
| | &HMACLength
|
| | );
|
| |
|
| | temporary = getHexValue(kService, HMACLength);
|
| |
|
| |
|
| | kSigned = HMAC(
|
| | EVP_sha256(),
|
| | kSigning,
|
| | HMACLength,
|
| | (const unsigned char*)stringToSign,
|
| | strlen(stringToSign),
|
| | nullptr,
|
| | &HMACLength
|
| | );
|
| |
|
| | temporary = getHexValue(kSigned, HMACLength);
|
| |
|
| | returnData->digest = string(temporary);
|
| | returnData->Region = Region;
|
| | free(canonical_request);
|
| | return (returnData);
|
| | }
|
| |
|
| | std::string Cloud::getHexValue(unsigned char* input, unsigned int HMACLength)
|
| | {
|
| | char* Hex;
|
| | unsigned char* ptr = input;
|
| | std::string resultReadable;
|
| | Hex = (char*)malloc(HMACLength * 2 * sizeof(char) + 1);
|
| | for (unsigned int i = 0; i < HMACLength; i++) {
|
| | sprintf(Hex, "%02x", *ptr);
|
| | ptr++;
|
| | Hex[2] = '\0';
|
| | resultReadable += Hex;
|
| | }
|
| | return resultReadable;
|
| | }
|
| |
|
| | struct Cloud::AmzData* Cloud::ComputeDigestAmzS3v2(
|
| | char* operation,
|
| | char* data_type,
|
| | const char* target,
|
| | const char* Secret,
|
| | const char* ptr,
|
| | long size
|
| | )
|
| | {
|
| | struct AmzData* returnData;
|
| |
|
| | struct tm* tm;
|
| | char date_formatted[256];
|
| | char StringToSign[1024];
|
| | unsigned char* digest;
|
| | unsigned int HMACLength;
|
| |
|
| |
|
| |
|
| | returnData = new Cloud::AmzData;
|
| | strcpy(returnData->ContentType, data_type);
|
| | #if defined(FC_OS_WIN32)
|
| | _putenv("TZ=GMT");
|
| | time_t rawtime;
|
| |
|
| | time(&rawtime);
|
| | tm = localtime(&rawtime);
|
| | #else
|
| | struct timeval tv;
|
| | setenv("TZ", "GMT", 1);
|
| | gettimeofday(&tv, nullptr);
|
| | tm = localtime(&tv.tv_sec);
|
| | #endif
|
| | strftime(date_formatted, 256, "%a, %d %b %Y %T %z", tm);
|
| | returnData->MD5 = nullptr;
|
| | if (strcmp(operation, "PUT") == 0) {
|
| | if (ptr != nullptr) {
|
| | returnData->MD5 = Cloud::MD5Sum(ptr, size);
|
| | sprintf(
|
| | StringToSign,
|
| | "%s\n%s\n%s\n%s\n%s",
|
| | operation,
|
| | returnData->MD5,
|
| | data_type,
|
| | date_formatted,
|
| | target
|
| | );
|
| | }
|
| | else {
|
| | sprintf(StringToSign, "%s\n\n%s\n%s\n%s", operation, data_type, date_formatted, target);
|
| | }
|
| | }
|
| | else {
|
| | sprintf(StringToSign, "%s\n\n%s\n%s\n%s", operation, data_type, date_formatted, target);
|
| | }
|
| |
|
| | digest = HMAC(
|
| | EVP_sha1(),
|
| | Secret,
|
| | strlen(Secret),
|
| | (const unsigned char*)&StringToSign,
|
| | strlen(StringToSign),
|
| | nullptr,
|
| | &HMACLength
|
| | );
|
| | returnData->digest = Base::base64_encode(digest, HMACLength);
|
| | strcpy(returnData->dateFormatted, date_formatted);
|
| | return returnData;
|
| | }
|
| |
|
| | char* Cloud::SHA256Sum(const char* ptr, long size)
|
| | {
|
| | char* output;
|
| | std::string local;
|
| | std::string resultReadable;
|
| | unsigned char result[SHA256_DIGEST_LENGTH];
|
| | output = (char*)malloc(2 * SHA256_DIGEST_LENGTH * sizeof(char) + 1);
|
| | SHA256((unsigned char*)ptr, size, result);
|
| |
|
| | strcpy(output, getHexValue(result, SHA256_DIGEST_LENGTH).c_str());
|
| |
|
| | return (output);
|
| | }
|
| |
|
| | char* Cloud::MD5Sum(const char* ptr, long size)
|
| | {
|
| | char* output;
|
| | std::string local;
|
| | unsigned char result[MD5_DIGEST_LENGTH];
|
| | output = (char*)malloc(2 * MD5_DIGEST_LENGTH * sizeof(char) + 1);
|
| | MD5((unsigned char*)ptr, size, result);
|
| | local = Base::base64_encode(result, MD5_DIGEST_LENGTH);
|
| | strcpy(output, local.c_str());
|
| | return (output);
|
| | }
|
| |
|
| | struct curl_slist* Cloud::BuildHeaderAmzS3v4(
|
| | const char* URL,
|
| | const char* PublicKey,
|
| | struct Cloud::AmzDatav4* Data
|
| | )
|
| | {
|
| | char header_data[1024];
|
| | struct curl_slist* chunk = nullptr;
|
| |
|
| |
|
| | sprintf(header_data, "Host: %s", URL);
|
| | chunk = curl_slist_append(chunk, header_data);
|
| |
|
| |
|
| |
|
| | sprintf(header_data, "X-Amz-Date: %s", Data->dateFormattedS);
|
| | chunk = curl_slist_append(chunk, header_data);
|
| |
|
| |
|
| |
|
| | sprintf(header_data, "Content-Type:%s", Data->ContentType);
|
| | chunk = curl_slist_append(chunk, header_data);
|
| |
|
| |
|
| |
|
| | if (Data->MD5 != nullptr) {
|
| | sprintf(header_data, "Content-MD5: %s", Data->MD5);
|
| | chunk = curl_slist_append(chunk, header_data);
|
| |
|
| | free((void*)Data->MD5);
|
| | }
|
| |
|
| | if (Data->SHA256Sum != nullptr) {
|
| | sprintf(header_data, "x-amz-content-sha256: %s", Data->SHA256Sum);
|
| | chunk = curl_slist_append(chunk, header_data);
|
| |
|
| | free((void*)Data->SHA256Sum);
|
| | }
|
| | else {
|
| | chunk = curl_slist_append(chunk, "x-amz-content-sha256: UNSIGNED-PAYLOAD");
|
| | }
|
| |
|
| |
|
| | sprintf(
|
| | header_data,
|
| | "Authorization: AWS4-HMAC-SHA256 Credential=%s/%s/%s/%s/aws4_request, "
|
| | "SignedHeaders=%s, Signature=%s",
|
| | PublicKey,
|
| | Data->dateFormattedD,
|
| | "us",
|
| | "s3",
|
| | "host;x-amz-date",
|
| | Data->digest.c_str()
|
| | );
|
| | chunk = curl_slist_append(chunk, header_data);
|
| |
|
| | return chunk;
|
| | }
|
| |
|
| | struct curl_slist* Cloud::BuildHeaderAmzS3v2(
|
| | const char* URL,
|
| | const char* TCPPort,
|
| | const char* PublicKey,
|
| | struct Cloud::AmzData* Data
|
| | )
|
| | {
|
| | char header_data[1024];
|
| | struct curl_slist* chunk = nullptr;
|
| |
|
| |
|
| |
|
| | sprintf(header_data, "Host: %s:%s", URL, TCPPort);
|
| | chunk = curl_slist_append(chunk, header_data);
|
| |
|
| |
|
| | sprintf(header_data, "Date: %s", Data->dateFormatted);
|
| | chunk = curl_slist_append(chunk, header_data);
|
| |
|
| |
|
| | sprintf(header_data, "Content-Type:%s", Data->ContentType);
|
| | chunk = curl_slist_append(chunk, header_data);
|
| |
|
| |
|
| |
|
| | if (Data->MD5 != nullptr) {
|
| | sprintf(header_data, "Content-MD5: %s", Data->MD5);
|
| | chunk = curl_slist_append(chunk, header_data);
|
| |
|
| | free((void*)Data->MD5);
|
| | }
|
| |
|
| |
|
| |
|
| | sprintf(header_data, "Authorization: AWS %s:%s", PublicKey, Data->digest.c_str());
|
| | chunk = curl_slist_append(chunk, header_data);
|
| |
|
| | return chunk;
|
| | }
|
| |
|
| | Cloud::CloudWriter::CloudWriter(
|
| | const char* URL,
|
| | const char* TokenAuth,
|
| | const char* TokenSecret,
|
| | const char* TCPPort,
|
| | const char* Bucket,
|
| | std::string ProtocolVersion,
|
| | std::string Region
|
| | )
|
| | {
|
| | struct Cloud::AmzData* RequestData;
|
| | struct Cloud::AmzDatav4* RequestDatav4;
|
| | CURL* curl;
|
| | CURLcode res;
|
| |
|
| | std::string s;
|
| |
|
| | this->URL = URL;
|
| | this->TokenAuth = TokenAuth;
|
| | this->TokenSecret = TokenSecret;
|
| | this->TCPPort = TCPPort;
|
| | this->Bucket = Bucket;
|
| | if (!ProtocolVersion.empty()) {
|
| | this->ProtocolVersion = ProtocolVersion;
|
| | }
|
| | else {
|
| | this->ProtocolVersion = "2";
|
| | }
|
| | this->Region = Region;
|
| | this->FileName = "";
|
| | char path[1024];
|
| | sprintf(path, "/%s/", this->Bucket);
|
| | std::string strURL(this->URL);
|
| | eraseSubStr(strURL, "http://");
|
| | eraseSubStr(strURL, "https://");
|
| | if (this->ProtocolVersion == "2") {
|
| | RequestData
|
| | = Cloud::ComputeDigestAmzS3v2("GET", "application/xml", path, this->TokenSecret, nullptr, 0);
|
| | }
|
| | else {
|
| | RequestDatav4 = Cloud::ComputeDigestAmzS3v4(
|
| | "GET",
|
| | strURL.c_str(),
|
| | "application/xml",
|
| | path,
|
| | this->TokenSecret,
|
| | nullptr,
|
| | 0,
|
| | nullptr,
|
| | this->Region
|
| | );
|
| | }
|
| |
|
| | curl_global_init(CURL_GLOBAL_ALL);
|
| | curl = curl_easy_init();
|
| | #ifdef ALLOW_SELF_SIGNED_CERTIFICATE
|
| | curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0);
|
| | curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0);
|
| | #endif
|
| | if (curl) {
|
| |
|
| | struct curl_slist* chunk = nullptr;
|
| | char URL[256];
|
| | std::string strURL(this->URL);
|
| | eraseSubStr(strURL, "http://");
|
| | eraseSubStr(strURL, "https://");
|
| | if (this->ProtocolVersion == "2") {
|
| | chunk = Cloud::BuildHeaderAmzS3v2(strURL.c_str(), this->TCPPort, this->TokenAuth, RequestData);
|
| | delete RequestData;
|
| | }
|
| | else {
|
| | chunk = Cloud::BuildHeaderAmzS3v4(strURL.c_str(), this->TokenAuth, RequestDatav4);
|
| | delete RequestDatav4;
|
| | }
|
| |
|
| | curl_easy_setopt(curl, CURLOPT_HTTPHEADER, chunk);
|
| |
|
| |
|
| |
|
| | sprintf(URL, "%s:%s/%s/", this->URL, this->TCPPort, this->Bucket);
|
| | curl_easy_setopt(curl, CURLOPT_URL, URL);
|
| |
|
| | curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, CurlWrite_CallbackFunc_StdString);
|
| | curl_easy_setopt(curl, CURLOPT_WRITEDATA, &s);
|
| |
|
| | res = curl_easy_perform(curl);
|
| | if (res != CURLE_OK) {
|
| | fprintf(stderr, "curl_easy_perform() failed: %s\n", curl_easy_strerror(res));
|
| | }
|
| | curl_easy_cleanup(curl);
|
| | createBucket();
|
| |
|
| | std::stringstream input(s);
|
| |
|
| | try {
|
| | XMLPlatformUtils::Initialize();
|
| | }
|
| | catch (const XMLException& toCatch) {
|
| | char* message = XMLString::transcode(toCatch.getMessage());
|
| | cout << "Error during initialization! :\n" << message << "\n";
|
| | XMLString::release(&message);
|
| | return;
|
| | }
|
| |
|
| | XercesDOMParser* parser = new XercesDOMParser();
|
| | parser->setValidationScheme(XercesDOMParser::Val_Always);
|
| | parser->setDoNamespaces(true);
|
| |
|
| | xercesc::MemBufInputSource myxml_buf(
|
| | (const XMLByte* const)s.c_str(),
|
| | s.size(),
|
| | "myxml (in memory)"
|
| | );
|
| |
|
| | parser->parse(myxml_buf);
|
| | auto* dom = parser->getDocument();
|
| |
|
| |
|
| | checkXML(dom);
|
| | if (strcmp(errorCode, "NoSuchBucket") == 0) {
|
| |
|
| | createBucket();
|
| | }
|
| | }
|
| | }
|
| |
|
| | Cloud::CloudWriter::~CloudWriter()
|
| | {}
|
| |
|
| | size_t Cloud::CurlWrite_CallbackFunc_StdString(void* contents, size_t size, size_t nmemb, std::string* s)
|
| | {
|
| | size_t newLength = size * nmemb;
|
| | try {
|
| | s->append((char*)contents, newLength);
|
| | }
|
| | catch (std::bad_alloc&) {
|
| |
|
| | return 0;
|
| | }
|
| | return newLength;
|
| | }
|
| |
|
| | void Cloud::CloudReader::checkElement(DOMElement* element)
|
| | {
|
| | char* name = XMLString::transcode(element->getTagName());
|
| | if (strcmp(name, "Key") == 0) {
|
| | file = 1;
|
| | }
|
| | if (strcmp(name, "NextContinuationToken") == 0) {
|
| | continuation = 1;
|
| | }
|
| | if (strcmp(name, "IsTruncated") == 0) {
|
| | truncated = 1;
|
| | }
|
| | XMLString::release(&name);
|
| | }
|
| |
|
| | void Cloud::CloudReader::checkText(DOMText* text)
|
| | {
|
| |
|
| | XMLCh* buffer = new XMLCh[XMLString::stringLen(text->getData()) + 1];
|
| | XMLString::copyString(buffer, text->getData());
|
| | XMLString::trim(buffer);
|
| | struct Cloud::CloudReader::FileEntry* new_entry;
|
| | char* content = XMLString::transcode(buffer);
|
| | delete[] buffer;
|
| | if (file) {
|
| | new_entry = new Cloud::CloudReader::FileEntry;
|
| | strcpy(new_entry->FileName, content);
|
| | Cloud::CloudReader::FileList.push_back(new_entry);
|
| | }
|
| | file = 0;
|
| | if (continuation == 1) {
|
| | strcpy(Cloud::CloudReader::NextFileName, content);
|
| | continuation = 0;
|
| | }
|
| | if (truncated == 1) {
|
| | if (strncmp(content, "true", 4) != 0) {
|
| | truncated = 0;
|
| | }
|
| | else {
|
| | truncated = 2;
|
| | }
|
| | }
|
| | XMLString::release(&content);
|
| | }
|
| |
|
| | void Cloud::CloudReader::addFile(struct Cloud::CloudReader::FileEntry* new_entry)
|
| | {
|
| | Cloud::CloudReader::FileList.push_back(new_entry);
|
| | }
|
| |
|
| | void Cloud::CloudReader::checkXML(DOMNode* node)
|
| | {
|
| | if (node) {
|
| | switch (node->getNodeType()) {
|
| | case DOMNode::ELEMENT_NODE:
|
| | checkElement(static_cast<DOMElement*>(node));
|
| | break;
|
| | case DOMNode::TEXT_NODE:
|
| | checkText(static_cast<DOMText*>(node));
|
| | break;
|
| | default:
|
| | break;
|
| | }
|
| | DOMNode* child = node->getFirstChild();
|
| | while (child) {
|
| | DOMNode* next = child->getNextSibling();
|
| | checkXML(child);
|
| | child = next;
|
| | }
|
| | }
|
| | }
|
| |
|
| |
|
| | Cloud::CloudReader::~CloudReader()
|
| | {}
|
| |
|
| | Cloud::CloudReader::CloudReader(
|
| | const char* URL,
|
| | const char* TokenAuth,
|
| | const char* TokenSecret,
|
| | const char* TCPPort,
|
| | const char* Bucket,
|
| | std::string ProtocolVersion,
|
| | std::string Region
|
| | )
|
| | {
|
| | struct Cloud::AmzData* RequestData;
|
| | struct Cloud::AmzDatav4* RequestDatav4;
|
| | CURL* curl;
|
| | CURLcode res;
|
| | bool GetBucketContentList = true;
|
| | struct curl_slist* chunk = nullptr;
|
| | char parameters[1024];
|
| |
|
| |
|
| | this->URL = URL;
|
| | this->TokenAuth = TokenAuth;
|
| | this->TokenSecret = TokenSecret;
|
| | this->TCPPort = TCPPort;
|
| | this->Bucket = Bucket;
|
| | if (!ProtocolVersion.empty()) {
|
| | this->ProtocolVersion = ProtocolVersion;
|
| | }
|
| | else {
|
| | this->ProtocolVersion = "2";
|
| | }
|
| | this->Region = Region;
|
| |
|
| | char path[1024];
|
| | sprintf(path, "/%s/", this->Bucket);
|
| | Cloud::CloudReader::NextFileName = (char*)malloc(sizeof(char) * 1024);
|
| | for (int i = 0; i < 1024; i++) {
|
| | NextFileName[i] = '\0';
|
| | }
|
| |
|
| |
|
| |
|
| | curl_global_init(CURL_GLOBAL_ALL);
|
| | while (GetBucketContentList) {
|
| | std::string s;
|
| | curl = curl_easy_init();
|
| | #ifdef ALLOW_SELF_SIGNED_CERTIFICATE
|
| | curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0);
|
| | curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0);
|
| | #endif
|
| | if (curl) {
|
| |
|
| | char URL[256];
|
| | std::string strURL(this->URL);
|
| | eraseSubStr(strURL, "http://");
|
| | eraseSubStr(strURL, "https://");
|
| | if (strlen(NextFileName) == 0) {
|
| | sprintf(parameters, "list-type=2");
|
| | }
|
| | else {
|
| | sprintf(parameters, "list-type=2&continuation-token=%s", NextFileName);
|
| | }
|
| | sprintf(URL, "%s:%s/%s/?%s", this->URL, this->TCPPort, this->Bucket, parameters);
|
| | curl_easy_setopt(curl, CURLOPT_URL, URL);
|
| |
|
| | if (this->ProtocolVersion == "2") {
|
| | RequestData = Cloud::ComputeDigestAmzS3v2(
|
| | "GET",
|
| | "application/xml",
|
| | path,
|
| | this->TokenSecret,
|
| | nullptr,
|
| | 0
|
| | );
|
| | chunk = Cloud::BuildHeaderAmzS3v2(
|
| | strURL.c_str(),
|
| | this->TCPPort,
|
| | this->TokenAuth,
|
| | RequestData
|
| | );
|
| | delete RequestData;
|
| | }
|
| | else {
|
| | RequestDatav4 = Cloud::ComputeDigestAmzS3v4(
|
| | "GET",
|
| | strURL.c_str(),
|
| | "application/xml",
|
| | path,
|
| | this->TokenSecret,
|
| | nullptr,
|
| | 0,
|
| | (char*)¶meters[0],
|
| | this->Region
|
| | );
|
| | chunk = Cloud::BuildHeaderAmzS3v4(strURL.c_str(), this->TokenAuth, RequestDatav4);
|
| | delete RequestDatav4;
|
| | }
|
| | curl_easy_setopt(curl, CURLOPT_HTTPHEADER, chunk);
|
| |
|
| | curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, CurlWrite_CallbackFunc_StdString);
|
| | curl_easy_setopt(curl, CURLOPT_WRITEDATA, &s);
|
| |
|
| |
|
| | res = curl_easy_perform(curl);
|
| |
|
| | for (int i = 0; i < 1024; i++) {
|
| | NextFileName[i] = '\0';
|
| | }
|
| | if (res != CURLE_OK) {
|
| | fprintf(stderr, "curl_easy_perform() failed: %s\n", curl_easy_strerror(res));
|
| | }
|
| | curl_easy_cleanup(curl);
|
| |
|
| |
|
| | std::stringstream input(s);
|
| |
|
| | try {
|
| | XMLPlatformUtils::Initialize();
|
| | }
|
| | catch (const XMLException& toCatch) {
|
| | char* message = XMLString::transcode(toCatch.getMessage());
|
| | cout << "Error during initialization! :\n" << message << "\n";
|
| | XMLString::release(&message);
|
| | return;
|
| | }
|
| |
|
| | XercesDOMParser* parser = new XercesDOMParser();
|
| | parser->setValidationScheme(XercesDOMParser::Val_Always);
|
| | parser->setDoNamespaces(true);
|
| |
|
| | xercesc::MemBufInputSource myxml_buf(
|
| | (const XMLByte* const)s.c_str(),
|
| | s.size(),
|
| | "myxml (in memory)"
|
| | );
|
| |
|
| | parser->parse(myxml_buf);
|
| | auto* dom = parser->getDocument();
|
| | checkXML(dom);
|
| | }
|
| | if (truncated == 0) {
|
| | GetBucketContentList = false;
|
| | }
|
| | else {
|
| | truncated = 0;
|
| | continuation = 0;
|
| | file = 0;
|
| | }
|
| | }
|
| | }
|
| |
|
| | void Cloud::CloudReader::DownloadFile(Cloud::CloudReader::FileEntry* entry)
|
| | {
|
| | struct Cloud::AmzData* RequestData;
|
| | struct Cloud::AmzDatav4* RequestDatav4;
|
| | CURL* curl;
|
| | CURLcode res;
|
| |
|
| | std::string s;
|
| |
|
| |
|
| | char path[1024];
|
| | sprintf(path, "/%s/%s", this->Bucket, entry->FileName);
|
| | std::string strURL(this->URL);
|
| | eraseSubStr(strURL, "http://");
|
| | eraseSubStr(strURL, "https://");
|
| | if (this->ProtocolVersion == "2") {
|
| | RequestData = Cloud::ComputeDigestAmzS3v2(
|
| | "GET",
|
| | "application/octet-stream",
|
| | path,
|
| | this->TokenSecret,
|
| | nullptr,
|
| | 0
|
| | );
|
| | }
|
| | else {
|
| | RequestDatav4 = Cloud::ComputeDigestAmzS3v4(
|
| | "GET",
|
| | strURL.c_str(),
|
| | "application/octet-stream",
|
| | path,
|
| | this->TokenSecret,
|
| | nullptr,
|
| | 0,
|
| | nullptr,
|
| | this->Region
|
| | );
|
| | }
|
| |
|
| |
|
| | curl_global_init(CURL_GLOBAL_ALL);
|
| | curl = curl_easy_init();
|
| | #ifdef ALLOW_SELF_SIGNED_CERTIFICATE
|
| | curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0);
|
| | curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0);
|
| | #endif
|
| | if (curl) {
|
| | struct curl_slist* chunk = nullptr;
|
| | char URL[256];
|
| |
|
| | std::string strURL(this->URL);
|
| | eraseSubStr(strURL, "http://");
|
| | eraseSubStr(strURL, "https://");
|
| | if (this->ProtocolVersion == "2") {
|
| | chunk = Cloud::BuildHeaderAmzS3v2(strURL.c_str(), this->TCPPort, this->TokenAuth, RequestData);
|
| | delete RequestData;
|
| | }
|
| | else {
|
| | chunk = Cloud::BuildHeaderAmzS3v4(strURL.c_str(), this->TokenAuth, RequestDatav4);
|
| | delete RequestDatav4;
|
| | }
|
| |
|
| | curl_easy_setopt(curl, CURLOPT_HTTPHEADER, chunk);
|
| |
|
| | sprintf(URL, "%s:%s/%s/%s", this->URL, this->TCPPort, this->Bucket, entry->FileName);
|
| | curl_easy_setopt(curl, CURLOPT_URL, URL);
|
| |
|
| | curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, CurlWrite_CallbackFunc_StdString);
|
| | curl_easy_setopt(curl, CURLOPT_WRITEDATA, &s);
|
| |
|
| |
|
| | res = curl_easy_perform(curl);
|
| | if (res != CURLE_OK) {
|
| | fprintf(stderr, "curl_easy_perform() failed: %s\n", curl_easy_strerror(res));
|
| | }
|
| | curl_easy_cleanup(curl);
|
| |
|
| | entry->FileStream << s;
|
| | }
|
| | }
|
| |
|
| | struct Cloud::CloudReader::FileEntry* Cloud::CloudReader::GetEntry(std::string FileName)
|
| | {
|
| | struct Cloud::CloudReader::FileEntry* current_entry = nullptr;
|
| | list<FileEntry*>::const_iterator it1;
|
| |
|
| | for (it1 = FileList.begin(); it1 != FileList.end(); ++it1) {
|
| | if (strcmp(FileName.c_str(), (*it1)->FileName) == 0) {
|
| | current_entry = (*it1);
|
| | break;
|
| | }
|
| | }
|
| |
|
| | if (current_entry != nullptr) {
|
| | (*it1)->touch = 1;
|
| | DownloadFile(*it1);
|
| | }
|
| |
|
| | return (current_entry);
|
| | }
|
| |
|
| | int Cloud::CloudReader::isTouched(std::string FileName)
|
| | {
|
| | list<FileEntry*>::const_iterator it1;
|
| | for (it1 = FileList.begin(); it1 != FileList.end(); ++it1) {
|
| | if (strcmp(FileName.c_str(), (*it1)->FileName) == 0) {
|
| | if ((*it1)->touch) {
|
| | return (1);
|
| | }
|
| | else {
|
| | return (0);
|
| | }
|
| | }
|
| | }
|
| | return (0);
|
| | }
|
| |
|
| | void Cloud::eraseSubStr(std::string& Str, const std::string& toErase)
|
| | {
|
| | size_t pos = Str.find(toErase);
|
| | if (pos != std::string::npos) {
|
| | Str.erase(pos, toErase.length());
|
| | }
|
| | }
|
| |
|
| |
|
| | void Cloud::CloudWriter::putNextEntry(const char* file)
|
| | {
|
| | this->FileName = file;
|
| | this->FileStream.str("");
|
| | this->FileStream << std::fixed;
|
| | this->FileStream.precision(std::numeric_limits<double>::digits10 + 1);
|
| | this->FileStream.setf(ios::fixed, ios::floatfield);
|
| | this->FileStream.imbue(std::locale::classic());
|
| | }
|
| |
|
| | bool Cloud::CloudWriter::shouldWrite(const std::string&, const Base::Persistence*) const
|
| | {
|
| | return true;
|
| | }
|
| |
|
| | void Cloud::CloudWriter::pushCloud(const char* FileName, const char* data, long size)
|
| | {
|
| | struct Cloud::AmzData* RequestData;
|
| | struct Cloud::AmzDatav4* RequestDatav4;
|
| | CURL* curl;
|
| | CURLcode res;
|
| | struct data_buffer curl_buffer;
|
| |
|
| | char path[1024];
|
| | sprintf(path, "/%s/%s", this->Bucket, FileName);
|
| |
|
| | std::string strURL(this->URL);
|
| | eraseSubStr(strURL, "http://");
|
| | eraseSubStr(strURL, "https://");
|
| | if (this->ProtocolVersion == "2") {
|
| | RequestData = Cloud::ComputeDigestAmzS3v2(
|
| | "PUT",
|
| | "application/octet-stream",
|
| | path,
|
| | this->TokenSecret,
|
| | data,
|
| | size
|
| | );
|
| | }
|
| | else {
|
| | RequestDatav4 = Cloud::ComputeDigestAmzS3v4(
|
| | "PUT",
|
| | strURL.c_str(),
|
| | "application/octet-stream",
|
| | path,
|
| | this->TokenSecret,
|
| | data,
|
| | size,
|
| | nullptr,
|
| | this->Region
|
| | );
|
| | }
|
| |
|
| |
|
| | curl_global_init(CURL_GLOBAL_ALL);
|
| | curl = curl_easy_init();
|
| | #ifdef ALLOW_SELF_SIGNED_CERTIFICATE
|
| | curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0);
|
| | curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0);
|
| | #endif
|
| | if (curl) {
|
| | struct curl_slist* chunk = nullptr;
|
| | char URL[256];
|
| |
|
| | std::string strURL(this->URL);
|
| | eraseSubStr(strURL, "http://");
|
| | eraseSubStr(strURL, "https://");
|
| | if (this->ProtocolVersion == "2") {
|
| | chunk = Cloud::BuildHeaderAmzS3v2(strURL.c_str(), this->TCPPort, this->TokenAuth, RequestData);
|
| | delete RequestData;
|
| | }
|
| | else {
|
| | chunk = Cloud::BuildHeaderAmzS3v4(strURL.c_str(), this->TokenAuth, RequestDatav4);
|
| | delete RequestDatav4;
|
| | }
|
| |
|
| | curl_easy_setopt(curl, CURLOPT_HTTPHEADER, chunk);
|
| |
|
| |
|
| |
|
| | sprintf(URL, "%s:%s/%s/%s", this->URL, this->TCPPort, this->Bucket, FileName);
|
| | curl_easy_setopt(curl, CURLOPT_URL, URL);
|
| |
|
| | curl_easy_setopt(curl, CURLOPT_UPLOAD, 1L);
|
| | curl_easy_setopt(curl, CURLOPT_PUT, 1L);
|
| |
|
| | curl_easy_setopt(curl, CURLOPT_READFUNCTION, read_callback);
|
| | curl_buffer.ptr = data;
|
| | curl_buffer.remaining_size = (size_t)size;
|
| |
|
| | curl_easy_setopt(curl, CURLOPT_READDATA, &curl_buffer);
|
| |
|
| | curl_easy_setopt(curl, CURLOPT_INFILESIZE_LARGE, (curl_off_t)size);
|
| |
|
| |
|
| | res = curl_easy_perform(curl);
|
| | if (res != CURLE_OK) {
|
| | fprintf(stderr, "curl_easy_perform() failed: %s\n", curl_easy_strerror(res));
|
| | }
|
| | curl_easy_cleanup(curl);
|
| | }
|
| | }
|
| |
|
| | void Cloud::CloudWriter::writeFiles(void)
|
| | {
|
| |
|
| |
|
| | std::string tmp = "";
|
| | char* cstr;
|
| | size_t index = 0;
|
| | if (strlen(this->FileName.c_str()) > 1) {
|
| |
|
| | const std::string tmp = this->FileStream.str();
|
| | const char* cstr = tmp.data();
|
| | pushCloud((const char*)this->FileName.c_str(), cstr, tmp.size());
|
| | }
|
| | while (index < FileList.size()) {
|
| | FileEntry entry = FileList.begin()[index];
|
| |
|
| | if (shouldWrite(entry.FileName, entry.Object)) {
|
| | this->FileStream.str("");
|
| | this->FileStream.precision(std::numeric_limits<double>::digits10 + 1);
|
| | this->FileStream.setf(ios::fixed, ios::floatfield);
|
| | this->FileStream.imbue(std::locale::classic());
|
| | entry.Object->SaveDocFile(*this);
|
| | tmp = this->FileStream.str();
|
| | cstr = (char*)tmp.data();
|
| | pushCloud((const char*)entry.FileName.c_str(), (const char*)cstr, tmp.size());
|
| | this->FileStream.str("");
|
| | }
|
| |
|
| | index++;
|
| | }
|
| | }
|
| |
|
| |
|
| | bool Cloud::Module::cloudSave(const char* BucketName)
|
| | {
|
| | Document* doc = GetApplication().getActiveDocument();
|
| |
|
| | auto hGrp = App::GetApplication().GetParameterGroupByPath(
|
| | "User parameter:BaseApp/Preferences/Document"
|
| | );
|
| |
|
| |
|
| | if (doc->Tip.getValue()) {
|
| | doc->TipName.setValue(doc->Tip.getValue()->getNameInDocument());
|
| | }
|
| |
|
| | std::string LastModifiedDateString = Base::Tools::currentDateTimeString();
|
| | doc->LastModifiedDate.setValue(LastModifiedDateString.c_str());
|
| |
|
| | bool saveAuthor = App::GetApplication()
|
| | .GetParameterGroupByPath("User parameter:BaseApp/Preferences/Document")
|
| | ->GetBool("prefSetAuthorOnSave", false);
|
| | if (saveAuthor) {
|
| | std::string Author = App::GetApplication()
|
| | .GetParameterGroupByPath("User parameter:BaseApp/Preferences/Document")
|
| | ->GetASCII("prefAuthor", "");
|
| | doc->LastModifiedBy.setValue(Author.c_str());
|
| | }
|
| | if (strcmp(BucketName, doc->Label.getValue()) != 0) {
|
| | doc->Label.setValue(BucketName);
|
| | }
|
| |
|
| | Cloud::CloudWriter mywriter(
|
| | (const char*)this->URL.getStrValue().c_str(),
|
| | (const char*)this->TokenAuth.getStrValue().c_str(),
|
| | (const char*)this->TokenSecret.getStrValue().c_str(),
|
| | (const char*)this->TCPPort.getStrValue().c_str(),
|
| | BucketName,
|
| | (const char*)this->ProtocolVersion.getStrValue().c_str(),
|
| | this->Region.getStrValue()
|
| | );
|
| |
|
| | mywriter.putNextEntry("Document.xml");
|
| |
|
| | if (hGrp->GetBool("SaveBinaryBrep", false)) {
|
| | mywriter.setMode("BinaryBrep");
|
| | }
|
| | mywriter.Stream() << "<?xml version='1.0' encoding='utf-8'?>" << endl
|
| | << "<!--" << endl
|
| | << " FreeCAD Document, see https://www.freecad.org for more information..."
|
| | << endl
|
| | << "-->" << endl;
|
| | doc->Save(mywriter);
|
| |
|
| |
|
| | doc->signalSaveDocument(mywriter);
|
| |
|
| |
|
| | mywriter.writeFiles();
|
| |
|
| | return (true);
|
| | }
|
| |
|
| | void readFiles(Cloud::CloudReader reader, Base::XMLReader* xmlreader)
|
| | {
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| | std::vector<Base::XMLReader::FileEntry>::const_iterator it = xmlreader->FileList.begin();
|
| | while (it != xmlreader->FileList.end()) {
|
| | if (reader.isTouched(it->FileName.c_str()) == 0) {
|
| | Base::Reader localreader(
|
| | reader.GetEntry(it->FileName.c_str())->FileStream,
|
| | it->FileName,
|
| | xmlreader->FileVersion
|
| | );
|
| |
|
| | if (false) {
|
| | std::stringstream ss;
|
| | ss << localreader.getStream().rdbuf();
|
| | auto aString = ss.str();
|
| | aString = "";
|
| | }
|
| | it->Object->RestoreDocFile(localreader);
|
| | if (localreader.getLocalReader() != nullptr) {
|
| | readFiles(reader, localreader.getLocalReader().get());
|
| | }
|
| | }
|
| | it++;
|
| | }
|
| | }
|
| |
|
| | void Cloud::Module::LinkXSetValue(std::string filename)
|
| | {
|
| |
|
| |
|
| |
|
| |
|
| | std::vector<Document*> Documents;
|
| | Documents = App::GetApplication().getDocuments();
|
| | for (std::vector<Document*>::iterator it = Documents.begin(); it != Documents.end(); it++) {
|
| | if ((*it)->FileName.getValue() == filename) {
|
| |
|
| |
|
| | return;
|
| | }
|
| | }
|
| |
|
| | size_t header = filename.find_first_of(":");
|
| | string protocol = filename.substr(0, header);
|
| | string url_new = filename.substr(header + 3);
|
| | size_t part2 = url_new.find_first_of("/");
|
| | string path = url_new.substr(part2 + 1);
|
| |
|
| |
|
| | App::Document* newDoc;
|
| | string newName;
|
| | Document* currentDoc = GetApplication().getActiveDocument();
|
| | newName = GetApplication().getUniqueDocumentName("unnamed");
|
| | newDoc = GetApplication().newDocument(newName.c_str(), (const char*)path.c_str(), true);
|
| | GetApplication().setActiveDocument(newDoc);
|
| | this->cloudRestore((const char*)path.c_str());
|
| | GetApplication().setActiveDocument(currentDoc);
|
| | }
|
| |
|
| | bool Cloud::Module::cloudRestore(const char* BucketName)
|
| | {
|
| |
|
| | Document* doc = GetApplication().getActiveDocument();
|
| |
|
| |
|
| | doc->signalLinkXsetValue.connect(boost::bind(&Cloud::Module::LinkXSetValue, this, _1));
|
| |
|
| | doc->clearUndos();
|
| |
|
| | doc->clearDocument();
|
| |
|
| | std::stringstream oss;
|
| |
|
| | Cloud::CloudReader myreader(
|
| | (const char*)this->URL.getStrValue().c_str(),
|
| | (const char*)this->TokenAuth.getStrValue().c_str(),
|
| | (const char*)this->TokenSecret.getStrValue().c_str(),
|
| | (const char*)this->TCPPort.getStrValue().c_str(),
|
| | BucketName,
|
| | (const char*)this->ProtocolVersion.getStrValue().c_str(),
|
| | this->Region.getStrValue()
|
| | );
|
| |
|
| |
|
| |
|
| | Base::XMLReader reader("Document.xml", myreader.GetEntry("Document.xml")->FileStream);
|
| |
|
| | if (!reader.isValid()) {
|
| | throw Base::FileException("Error reading Document.xml file", "Document.xml");
|
| | }
|
| |
|
| |
|
| | GetApplication().signalStartRestoreDocument(*doc);
|
| | doc->setStatus(Document::Restoring, true);
|
| |
|
| | try {
|
| | doc->Restore(reader);
|
| | }
|
| | catch (const Base::Exception& e) {
|
| | Base::Console().error("Invalid Document.xml: %s\n", e.what());
|
| | }
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| | doc->signalRestoreDocument(reader);
|
| |
|
| | readFiles(myreader, &reader);
|
| |
|
| |
|
| |
|
| | doc->afterRestore(true);
|
| |
|
| | GetApplication().signalFinishRestoreDocument(*doc);
|
| | doc->setStatus(Document::Restoring, false);
|
| | doc->Label.setValue(BucketName);
|
| |
|
| | string uri;
|
| | uri = this->URL.getStrValue() + ":" + this->TCPPort.getStrValue() + "/" + string(BucketName);
|
| | doc->FileName.setValue(uri);
|
| | doc->signalLinkXsetValue.disconnect(boost::bind(&Cloud::Module::LinkXSetValue, this, _1));
|
| | return (true);
|
| | }
|
| |
|