Last active
July 9, 2022 02:37
-
-
Save rsp4jack/717fc5d549d67ce69be3ee75e2bb509c to your computer and use it in GitHub Desktop.
Emule Known.met parser
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Under GPLv3 | |
// you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or any later version. | |
// This code is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. | |
#include "c8r2mb.hpp" | |
#include <algorithm> | |
#include <array> | |
#include <bit> | |
#include <cstdint> | |
#include <cuchar> | |
#include <fstream> | |
#include <iostream> | |
#include <span> | |
#include <string> | |
#include <tuple> | |
#include <variant> | |
#include <vector> | |
#include <cppcodec/base32_rfc4648.hpp> | |
#include <unordered_map> | |
#include <functional> | |
using namespace std; | |
constexpr uint8_t MET_HEADER = 0x0E; | |
constexpr uint8_t MET_HEADER_I64TAGS = 0x0F; | |
constexpr size_t MD4Len = 16; | |
constexpr size_t AICHLen = 20; | |
using MD4Hash = array<uint8_t, MD4Len>; | |
using EMFileSize = unsigned long long; | |
using AICHHash = array<uint8_t, AICHLen>; | |
using Blob = span<char>; | |
enum { | |
TAGTYPE_HASH = 0x01, | |
TAGTYPE_STRING = 0x02, | |
TAGTYPE_UINT32 = 0x03, | |
TAGTYPE_FLOAT32 = 0x04, | |
TAGTYPE_BOOL = 0x05, | |
TAGTYPE_BOOLARRAY = 0x06, | |
TAGTYPE_BLOB = 0x07, | |
TAGTYPE_UINT16 = 0x08, | |
TAGTYPE_UINT8 = 0x09, | |
TAGTYPE_BSOB = 0x0A, | |
TAGTYPE_UINT64 = 0x0B, | |
TAGTYPE_STR1 = 0x11, | |
TAGTYPE_STR2 = 0x12, | |
TAGTYPE_STR3 = 0x13, | |
TAGTYPE_STR4 = 0x14, | |
TAGTYPE_STR5 = 0x15, | |
TAGTYPE_STR6 = 0x16, | |
TAGTYPE_STR7 = 0x17, | |
TAGTYPE_STR8 = 0x18, | |
TAGTYPE_STR9 = 0x19, | |
TAGTYPE_STR10 = 0x1A, | |
TAGTYPE_STR11 = 0x1B, | |
TAGTYPE_STR12 = 0x1C, | |
TAGTYPE_STR13 = 0x1D, | |
TAGTYPE_STR14 = 0x1E, | |
TAGTYPE_STR15 = 0x1F, | |
TAGTYPE_STR16 = 0x20, | |
TAGTYPE_STR17 = 0x21, // accepted by eMule 0.42f (02-Mai-2004) in receiving | |
// code only because of a flaw, those tags are handled | |
// correctly, but should not be handled at all | |
TAGTYPE_STR18 = 0x22, // accepted by eMule 0.42f (02-Mai-2004) in receiving | |
// code only because of a flaw, those tags are handled | |
// correctly, but should not be handled at all | |
TAGTYPE_STR19 = 0x23, // accepted by eMule 0.42f (02-Mai-2004) in receiving | |
// code only because of a flaw, those tags are handled | |
// correctly, but should not be handled at all | |
TAGTYPE_STR20 = 0x24, // accepted by eMule 0.42f (02-Mai-2004) in receiving | |
// code only because of a flaw, those tags are handled | |
// correctly, but should not be handled at all | |
TAGTYPE_STR21 = 0x25, // accepted by eMule 0.42f (02-Mai-2004) in receiving | |
// code only because of a flaw, those tags are handled | |
// correctly, but should not be handled at all | |
TAGTYPE_STR22 = 0x26 // accepted by eMule 0.42f (02-Mai-2004) in receiving | |
// code only because of a flaw, those tags are handled | |
// correctly, but should not be handled at all | |
}; | |
enum { | |
FT_FILENAME = 0x01, // <string> | |
FT_FILESIZE = 0x02, // <uint32> (or <uint64> when supported) | |
FT_FILESIZE_HI = 0x3A, // <uint32> | |
FT_FILETYPE = 0x03, // <string> | |
FT_FILEFORMAT = 0x04, // <string> | |
FT_LASTSEENCOMPLETE = 0x05, // <uint32> | |
FT_TRANSFERRED = 0x08, // <uint32> | |
FT_GAPSTART = 0x09, // <uint32> | |
FT_GAPEND = 0x0A, // <uint32> | |
FT_DESCRIPTION = 0x0B, // <string> | |
FT_PARTFILENAME = 0x12, // <string> | |
// #define FT_PRIORITY 0x13 // Not used anymore | |
FT_STATUS = 0x14, // <uint32> | |
FT_SOURCES = 0x15, // <uint32> | |
FT_PERMISSIONS = 0x16, // <uint32> | |
// #define FT_ULPRIORITY 0x17 // Not used anymore | |
FT_DLPRIORITY = 0x18, // Was 13 | |
FT_ULPRIORITY = 0x19, // Was 17 | |
FT_COMPRESSION = 0x1A, | |
FT_CORRUPTED = 0x1B, | |
FT_KADLASTPUBLISHKEY = 0x20, // <uint32> | |
FT_KADLASTPUBLISHSRC = 0x21, // <uint32> | |
FT_FLAGS = 0x22, // <uint32> | |
FT_DL_ACTIVE_TIME = 0x23, // <uint32> | |
FT_CORRUPTEDPARTS = 0x24, // <string> | |
FT_DL_PREVIEW = 0x25, | |
FT_KADLASTPUBLISHNOTES = 0x26, // <uint32> | |
FT_AICH_HASH = 0x27, | |
FT_FILEHASH = 0x28, | |
FT_COMPLETE_SOURCES = 0x30, // nr. of sources which share a complete version of the associated | |
// file (supported by eserver 16.46+) | |
FT_COLLECTIONAUTHOR = 0x31, | |
FT_COLLECTIONAUTHORKEY = 0x32, | |
FT_PUBLISHINFO = 0x33, // <uint32> | |
FT_LASTSHARED = 0x34, // <uint32> | |
FT_AICHHASHSET = 0x35, // <uint32> | |
// statistic | |
FT_ATTRANSFERRED = 0x50, // <uint32> | |
FT_ATREQUESTED = 0x51, // <uint32> | |
FT_ATACCEPTED = 0x52, // <uint32> | |
FT_CATEGORY = 0x53, // <uint32> | |
FT_ATTRANSFERREDHI = 0x54, // <uint32> | |
FT_MAXSOURCES = 0x55, // <uint32> | |
FT_SPREADSTART = 0x70, | |
FT_SPREADEND = 0x71, | |
FT_SPREADCOUNT = 0x72, | |
// Xman advanced upload-priority | |
FT_NOTCOUNTEDTRANSFERREDLOW = 0x90, | |
FT_NOTCOUNTEDTRANSFERREDHIGH = 0x91, | |
FT_LASTDATAUPDATE = 0x92, | |
// Xman end | |
FT_MEDIA_ARTIST = 0xD0, // <string> | |
FT_MEDIA_ALBUM = 0xD1, // <string> | |
FT_MEDIA_TITLE = 0xD2, // <string> | |
FT_MEDIA_LENGTH = 0xD3, // <uint32> !!! | |
FT_MEDIA_BITRATE = 0xD4, // <uint32> | |
FT_MEDIA_CODEC = 0xD5, // <string> | |
FT_FILECOMMENT = 0xF6, // <string> | |
FT_FILERATING = 0xF7 // <uint8> | |
}; | |
constexpr auto FT_HIDEOS = "HIDEOS"; | |
constexpr auto FT_SELECTIVE_CHUNK = "SELECT_CHUNK"; | |
constexpr auto FT_SHAREONLYTHENEED = "SHARE_ONLY_THE_NEED"; | |
constexpr auto FT_POWERSHARE = "ZZUL_POWERSHARE"; | |
constexpr auto FT_POWERSHARE_LIMIT = "POWERSHARE_LIMIT"; | |
constexpr auto FT_PS_AMOUNT_LIMIT = "PS_AMOUNT_LIMIT"; | |
constexpr size_t MAX_PS_AMOUNT_LIMIT = 10000; | |
enum : char { | |
TAG_FILENAME = '\x01', // <string> | |
TAG_FILESIZE = '\x02', // <uint32> | |
TAG_FILESIZE_HI = '\x3A', // <uint32> | |
TAG_FILETYPE = '\x03', // <string> | |
TAG_FILEFORMAT = '\x04', // <string> | |
TAG_COLLECTION = '\x05', | |
TAG_PART_PATH = '\x06', // <string> | |
TAG_PART_HASH = '\x07', | |
TAG_TRANSFERRED = '\x08', // <uint32> | |
TAG_GAPSTART = '\x09', // <uint32> | |
TAG_GAPEND = '\x0A', // <uint32> | |
TAG_DESCRIPTION = '\x0B', // <string> | |
TAG_PING = '\x0C', | |
TAG_FAIL = '\x0D', | |
TAG_PREFERENCE = '\x0E', | |
TAG_PORT = '\x0F', | |
TAG_IP_ADDRESS = '\x10', | |
TAG_VERSION = '\x11', // <string> | |
TAG_PARTFILENAME = '\x12', // <string> | |
TAG_PRIORITY = '\x13', // <uint32> | |
TAG_STATUS = '\x14', // <uint32> | |
TAG_SOURCES = '\x15', // <uint32> | |
TAG_PERMISSIONS = '\x16', | |
TAG_PARTS = '\x17', | |
TAG_COMPLETE_SOURCES = '\x30', | |
TAG_PUBLISHINFO = '\x33', // <uint32> | |
TAG_KADAICHHASHPUB = '\x36', // <AICH Hash> | |
TAG_KADAICHHASHRESULT = '\x37', // <Count 1>{<Publishers 1><AICH Hash> Count} | |
TAG_MEDIA_ARTIST = '\xD0', // <string> | |
TAG_MEDIA_ALBUM = '\xD1', // <string> | |
TAG_MEDIA_TITLE = '\xD2', // <string> | |
TAG_MEDIA_LENGTH = '\xD3', // <uint32> !!! | |
TAG_MEDIA_BITRATE = '\xD4', // <uint32> | |
TAG_MEDIA_CODEC = '\xD5', // <string> | |
TAG_KADMISCOPTIONS = '\xF2', // <uint8> | |
TAG_ENCRYPTION = '\xF3', // <uint8> | |
TAG_USER_COUNT = '\xF4', // <uint32> | |
TAG_FILE_COUNT = '\xF5', // <uint32> | |
TAG_FILECOMMENT = '\xF6', // <string> | |
TAG_FILERATING = '\xF7', // <uint8> | |
TAG_BUDDYHASH = '\xF8', // <string> | |
TAG_CLIENTLOWID = '\xF9', // <uint32> | |
TAG_SERVERPORT = '\xFA', // <uint16> | |
TAG_SERVERIP = '\xFB', // <uint32> | |
TAG_SOURCEUPORT = '\xFC', // <uint16> | |
TAG_SOURCEPORT = '\xFD', // <uint16> | |
TAG_SOURCEIP = '\xFE', // <uint32> | |
TAG_SOURCETYPE = '\xFF' // <uint8> | |
}; | |
enum : uint8_t { | |
PR_LOW = 0, | |
PR_NORMAL = 1, // Don't change this - needed for edonkey clients and server! | |
PR_HIGH = 2, | |
PR_VERYHIGH = 3, | |
PR_VERYLOW = 4, // I Had to change this because it didn't save negative number correctly.. Had to modify the sort function for this change.. | |
PR_AUTO = 5, // UAP Hunter | |
PR_POWER = 6 // Xman PowerRelease | |
}; | |
struct Tag { | |
Tag() noexcept = default; | |
~Tag() noexcept | |
{ | |
if (holds_alternative<Blob>(data)) { | |
delete[] get<Blob>(data).data(); | |
} | |
} | |
Tag(const Tag& rhs) noexcept | |
: type(rhs.type) | |
, name(rhs.name) | |
, nameID(rhs.nameID) | |
, data(rhs.data) | |
{ | |
if (holds_alternative<Blob>(rhs.data)) { | |
const auto& rdata = get<Blob>(rhs.data); | |
auto dat = Blob(new(nothrow) char[rdata.size()], rdata.size()); | |
memcpy(dat.data(), rdata.data(), rdata.size_bytes()); | |
} | |
} | |
Tag(Tag&&) noexcept = default; | |
Tag& operator=(const Tag& rhs) noexcept | |
{ | |
// What's this? | |
// This will call move assign operator. Move op will deconstruct *this and move Tag(rhs) in *this. | |
*this = Tag(rhs); | |
return *this; | |
} | |
Tag& operator=(Tag&&) noexcept = default; | |
uint8_t type{}; // data type | |
string name; | |
uint8_t nameID{}; | |
variant<string, uint32_t, Blob, float, MD4Hash, uint64_t, uint16_t, uint8_t> | |
data; | |
}; | |
struct FileStatistic { | |
uint32_t requested = 0; | |
uint32_t accepted = 0; | |
uint64_t transferred = 0; | |
uint32_t alltimerequested = 0; | |
uint64_t alltimetransferred = 0; | |
uint32_t alltimeaccepted = 0; | |
uint32_t m_uFileupdatetime = 0; | |
bool InChangedSpreadSortValue = false; | |
bool InChangedFullSpreadCount = false; | |
bool InChangedSpreadBar = false; | |
int lastSize = 0; | |
bool lastbFlat = false; | |
float lastSpreadSortValue = 0; | |
float lastFullSpreadCount = 0; | |
uint64_t m_unotcountedtransferred = 0; | |
uint32_t m_tlastdataupdate = 0; | |
vector<uint64_t> spreadBar; // Stulle use CRBMap in Emule. Seems they do not have container like std::vector. | |
}; | |
struct KnownFile { | |
uint32_t utcLastModified{}; // When it is UTC 2038/1/19 03:14:07, Emule will be | |
// gone away. | |
MD4Hash checkID{}; // md4 of parthashes concat | |
uint16_t partCount{}; | |
vector<MD4Hash> partHashes{}; | |
AICHHash aichHash{}; | |
bool hasAICHHash = false; | |
uint32_t tagCount{}; | |
vector<Tag> tags{}; | |
// high level meta | |
string fileName{}; | |
EMFileSize fileSize{}; | |
FileStatistic statistic; | |
uint8_t uploadPriority{}; | |
bool autoUploadPriority{}; | |
uint32_t m_lastPublishTimeKadSrc{}; | |
uint32_t m_lastPublishTimeKadNotes{}; | |
uint32_t metaDataVersion{}; | |
uint32_t timeLastSeen{}; // too, 32bit time_t | |
vector<AICHHash> aichHashes; | |
int powershared{}; | |
int hideos{}; | |
int selectiveChunk{}; | |
int shareOnlyTheNeed{}; | |
int PSAmountLimit{}; | |
}; | |
struct KnownMet { | |
uint8_t header; | |
bool support64bitTag; | |
uint32_t length; | |
vector<KnownFile> files; | |
}; | |
static uint8_t readU8(istream* stream) | |
{ | |
stream->exceptions(ios::badbit); | |
return static_cast<uint8_t>(static_cast<char>(stream->get())); | |
} | |
static uint16_t readU16(istream* stream, bool bswap) | |
{ | |
stream->exceptions(ios::badbit); | |
uint16_t result; | |
stream->read(reinterpret_cast<char*>(&result), 2); | |
if (bswap) { | |
result = _byteswap_ushort(result); | |
} | |
return result; | |
} | |
static uint32_t readU32(istream* stream, bool bswap) | |
{ | |
stream->exceptions(ios::badbit); | |
uint32_t result; | |
stream->read(reinterpret_cast<char*>(&result), 4); | |
if (bswap) { | |
result = _byteswap_ulong(result); | |
} | |
return result; | |
} | |
static uint64_t readU64(istream* stream, bool bswap) | |
{ | |
stream->exceptions(ios::badbit); | |
uint64_t result; | |
stream->read(reinterpret_cast<char*>(&result), 8); | |
if (bswap) { | |
result = _byteswap_uint64(result); | |
} | |
return result; | |
} | |
static void readVar(void* target, istream* stream, streamsize len, bool bswap) | |
{ | |
stream->exceptions(ios::badbit); | |
stream->read(reinterpret_cast<char*>(target), len); | |
if (bswap) { | |
reverse(reinterpret_cast<char*>(target), reinterpret_cast<char*>(target) + len); | |
} | |
} | |
// UTF-8 Support | |
static string readString(istream* stream, uint16_t size, bool utf8, bool bswap) | |
{ | |
auto* mem = new char[size + 1]; // +1 for '\0' | |
auto umem = unique_ptr<char[]>(mem); | |
mem[size] = '\0'; | |
auto* base = mem; | |
readVar(base, stream, size, bswap); | |
bool isUTF8 = false; | |
if (size >= 3 && static_cast<unsigned char>(base[0]) == 0xEFU && static_cast<unsigned char>(base[1]) == 0xBBU && static_cast<unsigned char>(base[2]) == 0XBFU) { // UTF-8 BOM | |
base += 3; | |
isUTF8 = true; | |
} else if (utf8) { | |
isUTF8 = true; | |
} | |
char* out = mem; | |
if (isUTF8) { | |
c8r2mb_s(reinterpret_cast<char*>(&out), 0, reinterpret_cast<char8_t*>(base), true); | |
} | |
return {out}; | |
} | |
static Tag readTag(istream* stream, bool useUTF8, bool bswap) | |
{ | |
Tag tag; | |
tag.type = readU8(stream); | |
if ((tag.type & 0x80) != 0) { | |
tag.type &= 0x7F; | |
tag.nameID = readU8(stream); | |
tag.name.clear(); | |
} else { | |
uint16_t length = readU16(stream, bswap); | |
if (length == 1) { | |
tag.nameID = readU8(stream); | |
tag.name.clear(); | |
} else { | |
tag.nameID = 0; | |
tag.name.resize(length); | |
readVar(tag.name.data(), stream, length, bswap); | |
} | |
} | |
switch (tag.type) { | |
case TAGTYPE_STRING: { | |
uint16_t length = readU16(stream, bswap); | |
tag.data = readString(stream, length, useUTF8, bswap); | |
break; | |
} | |
case TAGTYPE_UINT32: | |
tag.data = readU32(stream, bswap); | |
break; | |
case TAGTYPE_UINT64: | |
tag.data = readU64(stream, bswap); | |
break; | |
case TAGTYPE_UINT16: | |
tag.data = readU16(stream, bswap); | |
tag.type = TAGTYPE_UINT32; // TODO: That's weird. | |
break; | |
case TAGTYPE_UINT8: | |
tag.data = readU8(stream); | |
tag.type = TAGTYPE_UINT32; // TODO: Weird behavior | |
break; | |
case TAGTYPE_FLOAT32: | |
float value; | |
readVar(&value, stream, 4, bswap); | |
tag.data = value; | |
break; | |
// Skip fixed-size strings | |
case TAGTYPE_HASH: | |
MD4Hash hash; | |
readVar(hash.data(), stream, MD4Len, bswap); | |
tag.data = hash; | |
break; | |
case TAGTYPE_BOOL: | |
cout << "Warning: Reading BOOL tag, skip" << endl; | |
stream->seekg(1, ios::cur); | |
break; | |
case TAGTYPE_BOOLARRAY: | |
cout << "Warning: Reading BOOL ARRAY tag, skip" << endl; | |
// 07-Apr-2004: eMule versions prior to 0.42e.29 used the formula | |
// "(len+7)/8"! | |
stream->seekg((readU16(stream, bswap)), ios::cur); | |
break; | |
case TAGTYPE_BLOB: { | |
// 07-Apr-2004: eMule versions prior to 0.42e.29 handled the "len" as int16! | |
uint32_t size = readU32(stream, bswap); | |
auto* data = new char[size]; | |
try { | |
readVar(data, stream, size, bswap); | |
} catch (const std::ios_base::failure& e) { | |
if (stream->eof()) { | |
cerr << "[Error] Unexcepted EOF when reading blob" << endl; | |
} | |
delete[] data; | |
data = nullptr; | |
throw e; | |
} | |
tag.data = span<char>(data, size); | |
break; | |
} | |
default: | |
if (tag.type >= TAGTYPE_STR1 && tag.type <= TAGTYPE_STR16) { | |
uint16_t length = tag.type - TAGTYPE_STR1 + 1; | |
tag.data = readString(stream, length, useUTF8, bswap); | |
} | |
} | |
return tag; | |
} | |
template <class T> | |
constexpr void variantHelper(const auto& var, const auto& func) | |
{ | |
assert(holds_alternative<T>(var)); | |
if (holds_alternative<T>(var)) { | |
func(); | |
} | |
} | |
// If readOnly is true, the stream will close after call. | |
// Otherwise the stream will not close and open in read and write mode. | |
static tuple<bool, KnownMet, unique_ptr<fstream>> | |
loadKnown(const string& filename,bool littleendian = true) // file's byte order | |
{ | |
KnownMet result{}; | |
auto stream = make_unique<fstream>(); | |
bool ok = true; | |
bool bswap = false; | |
stream->open(filename, ios::in | ios::binary); | |
if (littleendian != (endian::native == endian::little)) { | |
bswap = true; | |
} | |
result.header = readU8(stream.get()); | |
switch (result.header) { | |
case MET_HEADER: | |
cout << "Does not support 64 bits tag" << endl; | |
result.support64bitTag = false; | |
break; | |
case MET_HEADER_I64TAGS: | |
cout << "Does support 64 bits tag" << endl; | |
result.support64bitTag = true; | |
break; | |
default: | |
cout << "Invaild Header:" << std::hex << result.header << std::dec << endl; | |
return {false, std::move(result), std::move(stream)}; | |
} | |
result.length = readU32(stream.get(), bswap); | |
result.files.resize(result.length); | |
for (uint32_t ef4az7euc8 = 0; ef4az7euc8 < result.length; ++ef4az7euc8) { | |
auto& file = result.files.at(ef4az7euc8); | |
file.utcLastModified = readU32(stream.get(), bswap); | |
// Hash | |
readVar(file.checkID.data(), stream.get(), MD4Len, bswap); | |
file.partCount = readU16(stream.get(), bswap); | |
file.partHashes.resize(file.partCount); | |
for (uint16_t j = 0; j < file.partCount; ++j) { | |
readVar((file.partHashes.data() + j)->data(), stream.get(), MD4Len, bswap); | |
} | |
// Tag | |
unordered_map<uint32_t, uint64_t> spread_start_map; | |
unordered_map<uint32_t, uint64_t> spread_end_map; | |
unordered_map<uint32_t, uint64_t> spread_count_map; | |
file.tagCount = readU32(stream.get(), bswap); | |
file.tags.resize(file.tagCount); | |
for (uint32_t l0z7f1 = 0; l0z7f1 < file.tagCount; ++l0z7f1) { | |
file.tags[l0z7f1] = readTag(stream.get(), false, bswap); | |
auto& tag = file.tags[l0z7f1]; | |
bool hadAICHHashSetTag = false; | |
switch (tag.nameID) { | |
case FT_FILENAME: | |
variantHelper<string>(tag.data, [&]() { | |
if (file.fileName.empty()) { | |
file.fileName = get<string>(tag.data); | |
} | |
}); | |
break; | |
case FT_FILESIZE: | |
variantHelper<uint64_t>( | |
tag.data, [&]() { file.fileSize = get<uint64_t>(tag.data); } | |
); | |
break; | |
case FT_ATTRANSFERRED: | |
variantHelper<uint32_t>(tag.data, [&]() { | |
file.statistic.alltimetransferred = get<uint32_t>(tag.data); | |
}); | |
break; | |
case FT_ATTRANSFERREDHI: | |
variantHelper<uint32_t>(tag.data, [&]() { | |
file.statistic.alltimetransferred = (static_cast<uint64_t>(get<uint32_t>(tag.data)) << 32) | file.statistic.alltimetransferred; | |
}); | |
break; | |
case FT_ATREQUESTED: | |
variantHelper<uint32_t>(tag.data, [&]() { | |
file.statistic.alltimerequested = get<uint32_t>(tag.data); | |
}); | |
break; | |
case FT_ATACCEPTED: | |
variantHelper<uint32_t>(tag.data, [&]() { | |
file.statistic.alltimeaccepted = get<uint32_t>(tag.data); | |
}); | |
break; | |
case FT_ULPRIORITY: | |
variantHelper<uint32_t>(tag.data, [&]() { | |
file.uploadPriority = static_cast<uint8_t>(get<uint32_t>(tag.data)); | |
/* | |
This is a editor, not emule. just show raw data | |
if (file.uploadPriority == PR_AUTO) { | |
file.uploadPriority = PR_HIGH; | |
file.autoUploadPriority = true; | |
} else { | |
if (file.uploadPriority > PR_POWER) { | |
file.uploadPriority = PR_NORMAL; | |
} | |
file.autoUploadPriority = false; | |
} | |
*/ | |
}); | |
break; | |
case FT_KADLASTPUBLISHSRC: | |
variantHelper<uint32_t>(tag.data, [&]() { | |
file.m_lastPublishTimeKadSrc = get<uint32_t>(tag.data); | |
// too. | |
}); | |
break; | |
case FT_KADLASTPUBLISHNOTES: | |
variantHelper<uint32_t>(tag.data, [&]() { | |
file.m_lastPublishTimeKadNotes = get<uint32_t>(tag.data); | |
}); | |
break; | |
case FT_FLAGS: | |
// Misc. Flags | |
// ------------------------------------------------------------------------------ | |
// Bits 3-0: Meta data version | |
// 0 untrusted meta data which was received via search results | |
// 1 trusted meta data, Unicode (strings where not stored correctly) | |
// 2 0.49c: trusted meta data, Unicode | |
// Bits 31-4: Reserved | |
variantHelper<uint32_t>(tag.data, [&]() { | |
file.metaDataVersion = get<uint32_t>(tag.data) & 0x0F; | |
}); | |
break; | |
case FT_PERMISSIONS: | |
// deprecated | |
variantHelper<uint32_t>(tag.data, []() {}); | |
break; | |
case FT_KADLASTPUBLISHKEY: | |
// deprecated | |
variantHelper<uint32_t>(tag.data, []() {}); | |
break; | |
case FT_AICH_HASH: | |
variantHelper<string>(tag.data, [&]() { | |
if (cppcodec::base32_rfc4648::decode(file.aichHash.data(), AICHLen, get<string>(tag.data)) != AICHLen) { | |
assert(false); | |
cerr << "[Error] Base32 A.I.C.H. length is not 20 bytes" << endl; | |
file.aichHash.fill(0); | |
file.hasAICHHash = false; | |
} else { | |
file.hasAICHHash = true; | |
} | |
}); | |
break; | |
case FT_LASTSHARED: | |
variantHelper<uint32_t>(tag.data, [&]() { | |
file.timeLastSeen = get<uint32_t>(tag.data); | |
}); | |
break; | |
case FT_AICHHASHSET: | |
variantHelper<Blob>(tag.data, [&]() { | |
AICHHash masterHash; | |
readVar(masterHash.data(), stream.get(), AICHLen, bswap); | |
if (file.hasAICHHash && masterHash != file.aichHash) { | |
assert(false); | |
cerr << "[Error] Loading AICH Part Hashset error: HashSet Masterhash doesn't matches with existing masterhash - hashset not loaded"; | |
} else { | |
uint16_t count = readU16(stream.get(), bswap); | |
for (int i = 0; i < count; ++i) { | |
AICHHash hash; | |
readVar(hash.data(), stream.get(), AICHLen, bswap); | |
file.aichHashes.push_back(hash); | |
} | |
} | |
hadAICHHashSetTag = true; | |
}); | |
break; | |
case FT_NOTCOUNTEDTRANSFERREDLOW: | |
variantHelper<uint32_t>(tag.data, [&]() { | |
file.statistic.m_unotcountedtransferred = get<uint32_t>(tag.data); | |
}); | |
break; | |
case FT_NOTCOUNTEDTRANSFERREDHIGH: | |
variantHelper<uint32_t>(tag.data, [&]() { | |
file.statistic.m_unotcountedtransferred = static_cast<uint64_t>(get<uint32_t>(tag.data)) | file.statistic.m_unotcountedtransferred; | |
}); | |
break; | |
case FT_LASTDATAUPDATE: | |
variantHelper<uint32_t>(tag.data, [&]() { | |
file.statistic.m_tlastdataupdate = get<uint32_t>(tag.data); | |
}); | |
break; | |
default: | |
if ((tag.nameID == 0U) && holds_alternative<uint64_t>(tag.data) && !tag.name.empty()) { | |
uint32_t spreadKey = stoi(tag.name.substr(1)); | |
if (tag.name[0] == FT_SPREADSTART) { | |
spread_start_map.at(spreadKey) = get<uint64_t>(tag.data); | |
} else if (tag.name[0] == FT_SPREADEND) { | |
spread_end_map.at(spreadKey) = get<uint64_t>(tag.data); | |
} else if (tag.name[0] == FT_SPREADCOUNT) { | |
spread_count_map.at(spreadKey) = get<uint64_t>(tag.data); | |
} else if (tag.name == FT_POWERSHARE) { | |
file.powershared = (get<uint32_t>(tag.data) <= 3 ? get<uint32_t>(tag.data) : -1); | |
} else if (tag.name == FT_HIDEOS) { | |
file.hideos = (get<uint32_t>(tag.data) <= 10 ? get<uint32_t>(tag.data) : -1); | |
} else if (tag.name == FT_SELECTIVE_CHUNK) { | |
file.selectiveChunk = (get<uint32_t>(tag.data) <= 1 ? get<uint32_t>(tag.data) : -1); | |
} else if (tag.name == FT_SHAREONLYTHENEED) { | |
file.shareOnlyTheNeed = (get<uint32_t>(tag.data) <= 1 ? get<uint32_t>(tag.data) : -1); | |
} else if (tag.name == FT_PS_AMOUNT_LIMIT) { | |
file.PSAmountLimit = (get<uint32_t>(tag.data) <= MAX_PS_AMOUNT_LIMIT ? get<uint32_t>(tag.data) : -1); | |
} | |
} | |
} // switch end | |
if (hadAICHHashSetTag) { | |
// TODO: verify aich hash set. | |
} | |
for (const auto& i : spread_start_map) { | |
const uint32_t& spreadKey = i.first; | |
if (!spread_end_map.contains(spreadKey) || !spread_count_map.contains(spreadKey)) { | |
continue; | |
} | |
const uint64_t& spread_start = i.second; | |
const uint64_t& spread_end = spread_end_map.at(spreadKey); | |
const uint64_t& spread_count = spread_count_map.at(spreadKey); | |
if (spread_count == 0 || spread_start > spread_end) { | |
continue; | |
} | |
transform(file.statistic.spreadBar.cbegin(), file.statistic.spreadBar.cend(), file.statistic.spreadBar.begin(), [&](uint64_t a) { | |
return a + spread_count; | |
}); | |
} | |
// TODO: clean tags by meta data version: KnownFile.cpp:1159 | |
} | |
} | |
return {true, std::move(result), std::move(stream)}; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Known.met Parser
This is a Known.met parser for Emule. This is just an example code, not able to run and with many errors.
The code is under GPLv3.