2 // This file is part of the aMule Project.
4 // Copyright (c) 2007-2011 Johannes Krampf ( wuischke@amule.org )
8 // Angel Vidal Veiga aka Kry <kry@amule.org>
9 // * changed class names
11 // Marcelo Malheiros <mgmalheiros@gmail.com>
12 // * fixed error with FT_FILEHASH
13 // * added inital 5 tag/file support
15 // Any parts of this program derived from the xMule, lMule or eMule project,
16 // or contributed by third-party developers are copyrighted by their
17 // respective authors.
19 // This program is free software; you can redistribute it and/or modify
20 // it under the terms of the GNU General Public License as published by
21 // the Free Software Foundation; either version 2 of the License, or
22 // (at your option) any later version.
24 // This program is distributed in the hope that it will be useful,
25 // but WITHOUT ANY WARRANTY; without even the implied warranty of
26 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
27 // GNU General Public License for more details.
29 // You should have received a copy of the GNU General Public License
30 // along with this program; if not, write to the Free Software
31 // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
35 #include "MuleCollection.h"
45 CollectionFile::CollectionFile(
46 const std::string
&fileName
,
48 const std::string
&fileHash
)
57 CMuleCollection::CMuleCollection()
64 CMuleCollection::~CMuleCollection()
69 bool CMuleCollection::Open(const std::string
&File
)
71 return OpenBinary(File
) || OpenText(File
);
75 std::string
CMuleCollection::GetEd2kLink(size_t index
) const
77 if (index
>= GetFileCount()) {
78 return "Invalid Index!";
81 std::stringstream retvalue
;
82 // ed2k://|file|fileName|fileSize|fileHash|/
84 << "ed2k://|file|" << GetFileName(index
)
85 << "|" << GetFileSize(index
)
86 << "|" << GetFileHash(index
)
89 return retvalue
.str();
93 std::string
CMuleCollection::GetFileName(size_t index
) const
95 if (index
>= GetFileCount()) {
96 return "Invalid Index!";
99 std::string retvalue
= vCollection
[index
].m_fileName
;
100 if (retvalue
.empty()) {
101 return "Empty String!";
108 uint64_t CMuleCollection::GetFileSize(size_t index
) const
110 if (index
>= GetFileCount()) {
114 return vCollection
[index
].m_fileSize
;
118 std::string
CMuleCollection::GetFileHash(size_t index
) const
120 if (index
>= GetFileCount()) {
121 return "Invalid Index!";
123 std::string retvalue
= vCollection
[index
].m_fileHash
;
124 if (retvalue
.empty()) {
125 return "Empty String!";
131 template <typename intType
>
132 intType
CMuleCollection::ReadInt(std::ifstream
& infile
)
135 infile
.read(reinterpret_cast<char *>(&integer
),sizeof(intType
));
139 std::string
CMuleCollection::ReadString(std::ifstream
& infile
, int TagType
= 0x02)
141 if (TagType
>= 0x11 && TagType
<= 0x20) {
142 std::vector
<char> buffer(TagType
- 0x10);
143 infile
.read(&buffer
[0], TagType
- 0x10);
144 return buffer
.empty() ?
146 std::string (buffer
.begin(), buffer
.end());
148 if (TagType
== 0x02) {
149 uint16_t TagStringSize
= ReadInt
<uint16_t>(infile
);
150 std::vector
<char> buffer (TagStringSize
);
151 infile
.read(&buffer
[0], TagStringSize
);
152 return buffer
.empty() ?
154 std::string (buffer
.begin(), buffer
.end());
156 return std::string();
159 bool CMuleCollection::OpenBinary(const std::string
&File
)
161 std::ifstream infile
;
163 infile
.open(File
.c_str(), std::ifstream::in
|std::ifstream::binary
);
164 if(!infile
.is_open()) {
168 uint32_t cVersion
= ReadInt
<uint32_t>(infile
);
170 if (!infile
.good() ||
171 ( cVersion
!= 0x01 && cVersion
!= 0x02)) {
176 uint32_t hTagCount
= ReadInt
<uint32_t>(infile
);
177 if (!infile
.good() ||
183 for (size_t hTi
= 0; hTi
< hTagCount
;hTi
++) {
184 int hTagType
= infile
.get();
186 // hTagFormat == 1 -> FT-value is given
187 uint16_t hTagFormat
= ReadInt
<uint16_t>(infile
);
188 if (hTagFormat
!= 0x0001) {
193 int hTag
= infile
.get();
194 if (!infile
.good()) {
201 std::string fileName
= ReadString(infile
, hTagType
);
204 // FT_COLLECTIONAUTHOR
206 std::string CollectionAuthor
= ReadString(infile
, hTagType
);
209 // FT_COLLECTIONAUTHORKEY
211 uint32_t hTagBlobSize
= ReadInt
<uint32_t>(infile
);
212 if (!infile
.good()) {
216 std::vector
<char> CollectionAuthorKey(hTagBlobSize
);
217 infile
.read(&CollectionAuthorKey
[0], hTagBlobSize
);
222 if (!infile
.good()) {
230 uint32_t cFileCount
= ReadInt
<uint32_t>(infile
);
233 softlimit is set to 1024 to avoid problems with big uint32_t values
234 I don't believe anyone would want to use an emulecollection file
235 to store more than 1024 files, but just raise below value in case
236 you know someone who does.
245 for (size_t cFi
= 0; cFi
< cFileCount
; ++cFi
) {
246 uint32_t fTagCount
= ReadInt
<uint32_t>(infile
);
248 if (!infile
.good() ||
254 std::string fileHash
= std::string(32, '0');
255 uint64_t fileSize
= 0;
256 std::string fileName
;
257 std::string FileComment
;
258 for(size_t fTi
= 0; fTi
< fTagCount
; ++fTi
) {
259 int fTagType
= infile
.get();
260 if (!infile
.good()) {
265 int fTag
= infile
.get();
266 if (!infile
.good()) {
274 std::vector
<char> bFileHash(16);
275 infile
.read(&bFileHash
[0], 16);
276 std::string hex
= "0123456789abcdef";
277 for (int pos
= 0; pos
< 16; pos
++) {
278 fileHash
[pos
*2] = hex
[((bFileHash
[pos
] >> 4) & 0xF)];
279 fileHash
[(pos
*2) + 1] = hex
[(bFileHash
[pos
]) & 0x0F];
287 fileSize
= ReadInt
<uint32_t>(infile
);
291 fileSize
= ReadInt
<uint16_t>(infile
);
295 fileSize
= infile
.get();
299 fileSize
= ReadInt
<uint64_t>(infile
);
302 default: // Invalid file structure
311 fileName
= ReadString(infile
, fTagType
^0x80);
316 FileComment
= ReadString(infile
, fTagType
^0x80);
321 if (fTagType
== 0x89) { // TAGTYPE_UINT8
322 // uint8_t FileRating =
337 if( !infile
.good() ) {
342 AddFile(fileName
, fileSize
, fileHash
);
350 bool CMuleCollection::OpenText(const std::string
&File
)
354 std::ifstream infile
;
356 infile
.open(File
.c_str(), std::ifstream::in
|std::ifstream::binary
);
357 if (!infile
.is_open()) {
361 while (getline(infile
, line
, (char)10 /* LF */)) {
362 int last
= line
.size()-1;
363 if ((1 < last
) && ((char)13 /* CR */ == line
.at(last
))) {
380 bool CMuleCollection::AddLink(const std::string
&Link
)
382 // 12345678901234 56 7 + 32 + 89 = 19+32=51
383 // ed2k://|file|fileName|fileSize|fileHash|/
384 if (Link
.size() < 51 ||
385 Link
.substr(0,13) != "ed2k://|file|" ||
386 Link
.substr(Link
.size()-2) != "|/") {
390 size_t iName
= Link
.find("|",13);
391 if (iName
== std::string::npos
) {
394 std::string fileName
= Link
.substr(13,iName
-13);
396 size_t iSize
= Link
.find("|",iName
+1);
397 if (iSize
== std::string::npos
) {
400 std::stringstream sFileSize
;
401 sFileSize
<< Link
.substr(iName
+1,iSize
-iName
-1);
403 if ((sFileSize
>> std::dec
>> fileSize
).fail()) {
407 size_t iHash
= Link
.find("|",iSize
+1);
408 if (iHash
== std::string::npos
) {
411 std::string fileHash
= Link
.substr(iSize
+1,32);
413 return AddFile(fileName
, fileSize
, fileHash
);
417 bool CMuleCollection::AddFile(
418 const std::string
&fileName
,
420 const std::string
&fileHash
)
422 if (fileName
== "" ||
424 fileSize
> 0xffffffffLL
||
425 !IsValidHash(fileHash
)) {
429 vCollection
.push_back(
430 CollectionFile(fileName
, fileSize
, fileHash
));
435 bool CMuleCollection::IsValidHash(const std::string
&fileHash
)
437 if (fileHash
.size() != 32 || fileHash
== "") {
441 // fileHash needs to be a valid MD4Hash
442 std::string hex
= "0123456789abcdefABCDEF";
443 for(size_t i
= 0; i
< fileHash
.size(); ++i
) {
444 if (hex
.find(fileHash
[i
]) == std::string::npos
) {