lgogdownloader/src/util.cpp
2013-03-16 23:35:57 +02:00

181 lines
5.8 KiB
C++

/* This program is free software. It comes without any warranty, to
* the extent permitted by applicable law. You can redistribute it
* and/or modify it under the terms of the Do What The Fuck You Want
* To Public License, Version 2, as published by Sam Hocevar. See
* http://sam.zoy.org/wtfpl/COPYING for more details. */
#include "util.h"
#include <boost/filesystem.hpp>
#include <tinyxml.h>
/*
Create filepath from specified directory and path
Remove the leading slash from path if needed
Use gamename as base directory if specified
*/
std::string Util::makeFilepath(const std::string& directory, const std::string& path, const std::string& gamename)
{
std::string filepath;
if (gamename.empty())
{
if (path.at(0)=='/')
{
std::string tmp_path = path.substr(1,path.length());
filepath = directory + tmp_path;
}
else
{
filepath = directory + path;
}
}
else
{
std::string extras = "";
if (path.find("extras")!=std::string::npos)
{
extras = "/extras";
}
std::string filename = path.substr(path.find_last_of("/")+1, path.length());
filepath = directory + gamename + extras + "/" + filename;
}
return filepath;
}
std::string Util::getFileHash(const std::string& filename, unsigned hash_id)
{
unsigned char digest[rhash_get_digest_size(hash_id)];
char result[rhash_get_hash_length(hash_id)];
rhash_library_init();
int i = rhash_file(hash_id, filename.c_str(), digest);
if (i < 0)
std::cout << "LibRHash error: " << strerror(errno) << std::endl;
else
rhash_print_bytes(result, digest, rhash_get_digest_size(hash_id), RHPR_HEX);
return result;
}
std::string Util::getChunkHash(unsigned char *chunk, size_t chunk_size, unsigned hash_id)
{
unsigned char digest[rhash_get_digest_size(hash_id)];
char result[rhash_get_hash_length(hash_id)];
rhash_library_init();
int i = rhash_msg(hash_id, chunk, chunk_size, digest);
if (i < 0)
std::cout << "LibRHash error: " << strerror(errno) << std::endl;
else
rhash_print_bytes(result, digest, rhash_get_digest_size(hash_id), RHPR_HEX);
return result;
}
// Create GOG XML
int Util::createXML(std::string filepath, size_t chunk_size, std::string xml_dir)
{
int res = 0;
FILE *infile;
FILE *xmlfile;
size_t filesize, size;
int chunks, i;
std::string home = (std::string)getenv("HOME");
if (xml_dir.empty())
xml_dir = home + "/.gogdownloader/xml";
// Make sure directory exists
boost::filesystem::path path = xml_dir;
if (!boost::filesystem::exists(path)) {
if (!boost::filesystem::create_directories(path)) {
std::cout << "Failed to create directory: " << path << std::endl;
return res;
}
}
if ((infile=fopen(filepath.c_str(), "r"))!=NULL) {
//File exists
fseek(infile, 0, SEEK_END);
filesize = ftell(infile);
rewind(infile);
} else {
std::cout << filepath << " doesn't exist" << std::endl;
return res;
}
// Get filename
boost::filesystem::path pathname = filepath;
std::string filename = pathname.filename().string();
std::string filenameXML = xml_dir + "/" + filename + ".xml";
std::cout << filename << std::endl;
//Determine number of chunks
int remaining = filesize % chunk_size;
chunks = (remaining == 0) ? filesize/chunk_size : (filesize/chunk_size)+1;
std::cout << "Filesize: " << filesize << " bytes" << std::endl
<< "Chunks: " << chunks << std::endl
<< "Chunk size: " << (chunk_size >> 20) << " MB" << std::endl
<< "MD5: " << std::flush;
std::string file_md5 = Util::getFileHash(filepath.c_str(), RHASH_MD5);
std::cout << file_md5 << std::endl;
TiXmlDocument xml;
TiXmlElement *fileElem = new TiXmlElement("file");
fileElem->SetAttribute("name", filename);
fileElem->SetAttribute("md5", file_md5);
fileElem->SetAttribute("chunks", chunks);
fileElem->SetAttribute("total_size", filesize);
std::cout << "Getting MD5 for chunks" << std::endl;
for (i = 0; i < chunks; i++) {
size_t range_begin = i*chunk_size;
fseek(infile, range_begin, SEEK_SET);
if ((i == chunks-1) && (remaining != 0))
chunk_size = remaining;
size_t range_end = range_begin + chunk_size - 1;
unsigned char *chunk = (unsigned char *) malloc(chunk_size * sizeof(unsigned char *));
if (chunk == NULL)
{
std::cout << "Memory error" << std::endl;
return res;
}
size = fread(chunk, 1, chunk_size, infile);
if (size != chunk_size)
{
std::cout << "Read error" << std::endl;
free(chunk);
return res;
}
std::string hash = Util::getChunkHash(chunk, chunk_size, RHASH_MD5);
free(chunk);
TiXmlElement *chunkElem = new TiXmlElement("chunk");
chunkElem->SetAttribute("id", i);
chunkElem->SetAttribute("from", range_begin);
chunkElem->SetAttribute("to", range_end);
chunkElem->SetAttribute("method", "md5");
TiXmlText *text = new TiXmlText(hash);
chunkElem->LinkEndChild(text);
fileElem->LinkEndChild(chunkElem);
std::cout << "Chunks hashed " << (i+1) << " / " << chunks << "\r" << std::flush;
}
fclose(infile);
xml.LinkEndChild(fileElem);
std::cout << std::endl << "Writing XML: " << filenameXML << std::endl;
if ((xmlfile=fopen(filenameXML.c_str(), "w"))!=NULL) {
xml.Print(xmlfile);
fclose(xmlfile);
res = 1;
} else {
std::cout << "Can't create " << filenameXML << std::endl;
return res;
}
return res;
}