/* -*- c++ -*- * * fileinfo.cpp * * Copyright (C) 2003 Petter E. Stokke * * This program is free software; 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 2 * of the License, or (at your option) any later version. * * This program 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. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * */ #include #include #include #include "fileinfo.h" #include "donkeymessage.h" FileInfo::FileInfo(DonkeyMessage* msg, int proto) { first = true; updateFileInfo(msg, proto); } FileInfo::FileInfo(const FileInfo& fi) { num = fi.fileNo(); first = true; updateFileInfo(&fi); } FileInfo::~FileInfo() { } void FileInfo::updateFileInfo(const FileInfo* fi) { network = fi->fileNetwork(); names = fi->fileNames(); size = fi->fileSize(); downloaded = fi->fileDownloaded(); if (first) { firstdown = downloaded; first = false; firsttime = time(0); } nlocations = fi->fileNLocations(); nclients = fi->fileNClients(); state = fi->fileState(); abortedmsg = fi->fileAbortedMsg(); chunks = fi->fileChunks(); availability = fi->fileAvailability(); speed = fi->fileSpeed(); chunks_age = fi->fileChunksAge(); age = fi->fileAge(); format = fi->fileFormat(); formatinfo = fi->fileFormatInfo(); name = fi->fileName(); lastseen = fi->fileLastSeen(); priority = fi->filePriority(); comment = fi->fileComment(); uids = fi->fileUids(); } void FileInfo::updateFileInfo(DonkeyMessage* msg, int proto) { int i,j; num = msg->readInt32(); network = msg->readInt32(); j = msg->readInt16(); names.clear(); for (i=0; ireadString()); QByteArray md4(16); for (i=0; i<16; i++) md4[i] = msg->readInt8(); size = msg->readInt64(); downloaded = msg->readInt64(); if (first) { firstdown = downloaded; first = false; firsttime = time(0); } nlocations = msg->readInt32(); nclients = msg->readInt32(); state = (State)msg->readInt8(); if (state == 6) abortedmsg = msg->readString(); chunks = msg->readByteArray(); availability.clear(); j = msg->readInt16(); for (i=0; ireadInt32(); availability.replace(av_net, msg->readByteArray()); } speed = msg->readFloat(); j = msg->readInt16(); chunks_age.clear(); for (i=0; ireadDate(); if (a < 0) a = 0x7fffffff + a; // FIXME: Is this hack still relevant? chunks_age.append(a); } age = msg->readDate(); if (age < 0) age = 0x7fffffff + age; // FIXME: Is this hack still relevant? format = msg->readInt8(); switch (format) { case 1: { QString foo = msg->readString(); QString bar = msg->readString(); formatinfo = foo + " " + bar; } break; case 2: { QString foo = msg->readString(); int i = msg->readInt32(); int j = msg->readInt32(); int k = msg->readInt32(); int l = msg->readInt32(); formatinfo = i18n("AVI codec resolution framerate bitrate", "AVI %1 %2x%3 %4fps rate %5") .arg(foo).arg(i).arg(j).arg((double)k / 1000.0, 0, 'f', 2).arg(l); } break; case 3: { QString foo = msg->readString(); QString bar = msg->readString(); QString baz = msg->readString(); QString quux = msg->readString(); msg->readString(); int i = msg->readInt32(); msg->readInt32(); formatinfo = i18n("MP3 title artist album year track", "MP3 Ti:%1 Ar:%2 Al:%3 Yr:%4 Tr:%5") .arg(foo).arg(bar).arg(baz).arg(quux).arg(i); } break; case 4: { formatinfo = i18n("Ogg format header", "Ogg"); int i = msg->readInt16(); for (; i; i--) { int streamNo = msg->readInt32(); int foo = msg->readInt8(); QString streamType; switch (foo) { case 0: streamType = i18n("Ogg stream type: Video", "Video"); break; case 1: streamType = i18n("Ogg stream type: Audio", "Audio"); break; case 2: streamType = i18n("Ogg stream type: Text", "Text"); break; case 3: streamType = i18n("Ogg stream type: Index", "Index"); break; case 4: streamType = i18n("Ogg stream type: Vorbis", "Vorbis"); break; case 5: streamType = i18n("Ogg stream type: Theora", "Theora"); break; default: streamType = i18n("Ogg stream type: Unknown", "Unknown"); break; } int j = msg->readInt16(); QStringList tags; for (; j; j--) { int type = msg->readInt8(); switch (type) { case 0: tags.append(i18n("Ogg codec tag", "Codec:%1").arg(msg->readString())); break; case 1: tags.append(i18n("Ogg bytes per sample tag", "BPS:%1").arg(msg->readInt32())); break; case 2: tags.append(i18n("Ogg duration tag", "Dur:%1").arg(msg->readInt32())); break; case 3: tags.append(i18n("Ogg subtitle tag", "Sub")); break; case 4: tags.append(i18n("Ogg index tag", "Index")); break; case 5: tags.append(i18n("Ogg audio channels tag", "AudCh:%1").arg(msg->readInt32())); break; case 6: tags.append(i18n("Ogg audio sample rate tag", "SmpRt:%1").arg(msg->readFloat())); break; case 7: tags.append(i18n("Ogg audio block align tag", "BlkAl:%1").arg(msg->readInt32())); break; case 8: tags.append(i18n("Ogg audio average bytes per second tag", "AvgBPS:%1").arg(msg->readFloat())); break; case 9: tags.append(i18n("Ogg Vorbis version tag", "VorbisVer:%1").arg(msg->readFloat())); break; case 10: tags.append(i18n("Ogg Vorbis sample rate tag", "SmpRt:%1").arg(msg->readFloat())); break; case 11: { QStringList bitRates; int k = msg->readInt16(); for (; k; k--) { int rateType = msg->readInt8(); switch (rateType) { case 0: bitRates.append(i18n("Ogg Vorbis maximum bitrate tag", "Max:%1").arg(msg->readFloat())); break; case 1: bitRates.append(i18n("Ogg Vorbis nominal bitrate tag", "Nom:%1").arg(msg->readFloat())); break; case 2: bitRates.append(i18n("Ogg Vorbis minimum bitrate tag", "Min:%1").arg(msg->readFloat())); break; default: break; } } tags.append(i18n("Ogg Vorbis bitrates tag", "BitRate:%1").arg(bitRates.join(i18n("Ogg Vorbis bitrate tag separator", ",")))); } break; case 12: tags.append(i18n("Ogg Vorbis block size 0 tag", "BlkSz0:%1").arg(msg->readInt32())); break; case 13: tags.append(i18n("Ogg Vorbis block size 1 tag", "BlkSz1:%1").arg(msg->readInt32())); break; case 14: tags.append(i18n("Ogg video width tag", "Wt:%1").arg(msg->readFloat())); break; case 15: tags.append(i18n("Ogg video height tag", "Ht:%1").arg(msg->readFloat())); break; case 16: tags.append(i18n("Ogg video sample rate tag", "SmpRt:%1").arg(msg->readFloat())); break; case 17: tags.append(i18n("Ogg video aspect ratio tag", "Aspect:%1").arg(msg->readFloat())); break; case 18: { QString cs; switch (msg->readInt8()) { case 1: cs = i18n("Ogg Theora CS tag value: Rec470M", "Rec470M"); break; case 2: cs = i18n("Ogg Theora CS tag value: Rec470BG", "Rec470BG"); break; default: cs = i18n("Ogg Theora CS tag value: undefined", "Undef"); break; } tags.append(i18n("Ogg Theora CS tag", "CS:%1").arg(cs)); } break; case 19: tags.append(i18n("Ogg Theora quality tag", "Qual:%1").arg(msg->readInt32())); break; case 20: tags.append(i18n("Ogg Theora average bytes per second tag", "AvgBPS:%1").arg(msg->readInt32())); break; default: break; } } formatinfo += i18n("Ogg stream block", " %1:%2 [%3]").arg(streamNo).arg(streamType) .arg(tags.join(i18n("Ogg stream tag separator", " "))); } } break; default: formatinfo = i18n("Unknown format"); break; } name = msg->readString(); lastseen = msg->readInt32(); // FIXME: Is this relative? priority = msg->readInt32(); if (priority > 0x40000000) priority -= 0x80000000; comment = msg->readString(); uids.clear(); if (proto >= 31) { for (i = msg->readInt16(); i; i--) uids.append(msg->readString()); } else uids.append(QString("urn:ed2k:") + md4ToString(md4)); } const int FileInfo::fileNo() const { return num; } const int FileInfo::fileNetwork() const { return network; } const QString& FileInfo::fileName() const { return name; } const QStringList& FileInfo::fileNames() const { return names; } const QStringList& FileInfo::fileUids() const { return uids; } QString FileInfo::fileUid() const { return uids.first(); } QString FileInfo::fileUid(const QString& type) const { QRegExp match(QString("^urn:") + type + ":"); QStringList results = uids.grep(match); if (!results.count()) return QString::null; QString result(results.first()); result.replace(match, ""); return result; } const int64 FileInfo::fileSize() const { return size; } const int64 FileInfo::fileDownloaded() const { return downloaded; } const int64 FileInfo::fileFirstDownloaded() const { return firstdown; } const int FileInfo::fileNLocations() const { return nlocations; } const int FileInfo::fileNClients() const { return nclients; } const FileInfo::State FileInfo::fileState() const { return state; } const QString& FileInfo::fileAbortedMsg() const { return abortedmsg; } const QByteArray& FileInfo::fileChunks() const { return chunks; } const QMap& FileInfo::fileAvailability() const { return availability; } const double FileInfo::fileSpeed() const { return speed; } const QValueList& FileInfo::fileChunksAge() const { return chunks_age; } const time_t FileInfo::fileAge() const { return age; } const time_t FileInfo::fileFirstTime() const { return firsttime; } const int FileInfo::fileFormat() const { return format; } const QString& FileInfo::fileFormatInfo() const { return formatinfo; } const int FileInfo::fileLastSeen() const { return lastseen; } const int FileInfo::filePriority() const { return priority; } const QMap& FileInfo::fileSources() const { return sources; } const QString& FileInfo::fileComment() const { return comment; } void FileInfo::setFileName(const QString& newname) { name = newname; } void FileInfo::addSource(int source) { if (!sources.contains(source)) sources.insert(source, QString::null); } void FileInfo::removeSource(int source) { sources.remove(source); } void FileInfo::updateAvailability(int source, const QString& avail) { sources.insert(source, avail); } void FileInfo::updateDownloadStatus(DonkeyMessage* msg, int) { downloaded = msg->readInt64(); speed = msg->readFloat(); if (msg->opcode() >= 46) lastseen = msg->readInt32(); } QString FileInfo::md4ToString(const QByteArray& hash) { char foo[33], bar[16]; int i; foo[0] = 0; for (i=0; i<16; i++) { sprintf(bar, "%02x", (unsigned char)hash[i]); strcat(foo, bar); } return QString(foo).upper(); } static const QString hexmap = "0123456789ABCDEF"; QByteArray FileInfo::stringToMd4(const QString& hash) { QByteArray out(16); if (hash.length() != 32) return out; QString in = hash.upper(); int b; for (int i=0; i<(int)in.length(); i+=2) { b = hexmap.find(in[i]) << 4; b |= hexmap.find(in[i+1]); out[i>>1] = b; } return out; }