標籤:

翻譯 known.met 程序

翻譯 known.met 程序

在 $HOME/.aMule 目錄下有個 known.met 二進位文件,

其儲存了(完成或未完成)下載文件的一些信息。

寫個翻譯程序,方便肉眼觀察。

#!/usr/bin/python3import timefrom io import SEEK_CURMET_HEADER = 0x0EMET_HEADER_WITH_LARGEFILES = 0x0FTAGTYPE_HASH16 = 0x01TAGTYPE_STRING = 0x02TAGTYPE_UINT32 = 0x03TAGTYPE_FLOAT32 = 0x04TAGTYPE_BOOL = 0x05TAGTYPE_BOOLARRAY = 0x06TAGTYPE_BLOB = 0x07TAGTYPE_UINT16 = 0x08TAGTYPE_UINT8 = 0x09TAGTYPE_BSOB = 0x0ATAGTYPE_UINT64 = 0x0BTAGTYPE_STR1 = 0x11TAGTYPE_STR16 = TAGTYPE_STR1 + 15tagtype = [ TAGTYPE_HASH16, TAGTYPE_STRING, TAGTYPE_UINT32, TAGTYPE_FLOAT32, TAGTYPE_BOOL, TAGTYPE_BOOLARRAY, TAGTYPE_BLOB, TAGTYPE_UINT16, TAGTYPE_UINT8, TAGTYPE_BSOB, TAGTYPE_UINT64]nameid = { 0x01:FT_FILENAME, 0x02:FT_FILESIZE, 0x3A:FT_FILESIZE_HI, 0x03:FT_FILETYPE, 0x04:FT_FILEFORMAT, 0x05:FT_LASTSEENCOMPLETE, 0x08:FT_TRANSFERRED, 0x09:FT_GAPSTART, 0x0A:FT_GAPEND, 0x0B:FT_DESCRIPTION, 0x12:FT_PARTFILENAME, 0x14:FT_STATUS, 0x15:FT_SOURCES, 0x16:FT_PERMISSIONS, 0x18:FT_DLPRIORITY, 0x19:FT_ULPRIORITY, 0x1A:FT_COMPRESSION, 0x1B:FT_CORRUPTED, 0x20:FT_KADLASTPUBLISHKEY, 0x21:FT_KADLASTPUBLISHSRC, 0x22:FT_FLAGS, 0x23:FT_DL_ACTIVE_TIME, 0x24:FT_CORRUPTEDPARTS, 0x25:FT_DL_PREVIEW, 0x26:FT_KADLASTPUBLISHNOTES, 0x27:FT_AICH_HASH, 0x28:FT_FILEHASH, 0x30:FT_COMPLETE_SOURCES, 0x31:FT_COLLECTIONAUTHOR, 0x32:FT_COLLECTIONAUTHORKEY, 0x33:FT_PUBLISHINFO, 0x34:FT_LASTSHARED, 0x35:FT_AICHHASHSET, 0x50:FT_ATTRANSFERRED, 0x51:FT_ATREQUESTED, 0x52:FT_ATACCEPTED, 0x53:FT_CATEGORY, 0x54:FT_ATTRANSFERREDHI, 0x55:FT_MAXSOURCES, 0x90:FT_NOTCOUNTEDTRANSFERREDLOW, 0x91:FT_NOTCOUNTEDTRANSFERREDHIGH, 0x92:FT_LASTDATAUPDATE, 0xD0:FT_MEDIA_ARTIST, 0xD1:FT_MEDIA_ALBUM, 0xD2:FT_MEDIA_TITLE, 0xD3:FT_MEDIA_LENGTH, 0xD4:FT_MEDIA_BITRATE, 0xD5:FT_MEDIA_CODEC, 0xF6:FT_FILECOMMENT, 0xF7:FT_FILERATING,}def get_uint8(fin): return int.from_bytes(fin.read(1), byteorder=little, signed=False)def get_uint16(fin): return int.from_bytes(fin.read(2), byteorder=little, signed=False)def get_uint32(fin): return int.from_bytes(fin.read(4), byteorder=little, signed=False)class Tag: def __init__(self, fin): self.name_id = 0 self.name = None self.value = None self.type_ = get_uint8(fin) if (self.type_ & 0x80) != 0: self.type_ &= 0x7F self.name_id = get_uint8(fin) else: len_ = get_uint16(fin) if len_ == 1: self.name_id = get_uint8(fin) else: self.name_id = 0 self.name = fin.read(len_).decode(); if self.type_ == TAGTYPE_STRING: self.value = fin.read(get_uint16(fin)).decode() elif self.type_ == TAGTYPE_UINT32: self.value = get_uint32(fin) elif self.type_ == TAGTYPE_UINT64: self.value = get_uint64(fin) elif self.type_ == TAGTYPE_UINT16: self.value = get_uint16(fin) elif self.type_ == TAGTYPE_UINT8: self.value = get_uint8(fin) elif self.type_ == TAGTYPE_FLOAT32: self.value = get_uint32(fin) elif self.type_ == TAGTYPE_HASH16: self.value = fin.read(16) elif self.type_ == TAGTYPE_BOOL: fin.seek(1, SEEK_CUR) elif self.type_ == TAGTYPE_BOOLARRAY: fin.seek(get_uint16(fin)/8 + 1, SEEK_CUR) elif self.type_ == TAGTYPE_BLOB: self.value = fin.read(get_uint32(fin)) elif (self.type_ >= TAGTYPE_STR1) and (self.type_ <= TAGTYPE_STR16): self.value = fin.read(self.type_ - TAGTYPE_STR1 + 1).decode() self.type_ = TAGTYPE_STRING; else: raise ValueError() class KnownMetRecord: def __init__(self): self.last_date = None self.file_hash = None self.tags = None def load_last_date(self, fin): self.last_date = get_uint32(fin) def load_file_hash(self, fin): self.file_hash = fin.read(16) fin.seek(get_uint16(fin)*16, SEEK_CUR) def load_tags(self, fin): self.tags = [] tag_count = get_uint32(fin) while tag_count > 0: tag_count -= 1 tag = Tag(fin) self.tags.append(tag) class ReadKnownMet: def __init__(self, fin): self.fin = fin self.version = None def read_header(self): self.version = get_uint8(self.fin) if (self.version != MET_HEADER and self.version != MET_HEADER_WITH_LARGEFILES): raise ValueError() def read_body(self): self.records = [] record_count = get_uint32(self.fin) if record_count == 0: raise ValueError() while record_count > 0: record_count -= 1 r = KnownMetRecord() r.load_last_date(self.fin) r.load_file_hash(self.fin) r.load_tags(self.fin) self.records.append(r) def get_detail(self): s = "Version: " + str(self.version) s += "
Record count: " + str(len(self.records)) for r in self.records: s += "
Hash: " + r.file_hash.hex().upper() s += "
Last: " + time.asctime(time.localtime(r.last_date)) s += "
Tag count: " + str(len(r.tags)) for i in range(0, len(r.tags)): s += "
Tag(%s):" % (i+1,) s += "
Name ID: " + nameid[r.tags[i].name_id] s += "
Name: " + str(r.tags[i].name) s += "
type: " + tagtype[r.tags[i].type_-1] s += "
Value: " + str(r.tags[i].value) return s if __name__ == "__main__": import sys if len(sys.argv) < 2: exit(1) try: f = open(sys.argv[1], rb) r = ReadKnownMet(f) r.read_header() r.read_body() except Exception as err: sys.stderr.write(err.args +
) finally: f.close() print(r.get_detail())

如下輸入:

chmod u+x ReadKnownMet.pyReadKnownMet.py $HOME/.aMule/known.met | less

將內容重定向到 less 程序,是因為輸出的內容有寬字元編碼,而 less 不會顯示亂碼。

aMule 分別用 UTF-8 和 wxString 保存 下載文件名,

wxString 估計是 wchar_t,在 Linux 下是 4 位元組。

eMule 使用的是 CString,將 Linux 上的 known.dat 挪到 Windows 不知道是否兼容。

(在 less 里顯示)


推薦閱讀:

Linux Audio ALSA Technical specification(Linu...
【乾貨整理】Docker,從入門說起……
Linux基本命令(mkdir、touch、remove、alias,copy)
Win8伺服器添加Shtml腳本支持的方法有哪些?
Linux驅動入門

TAG:eMule | Python | Linux |