/* 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 #include /* 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; }