1 /****************************************************************************
2 **
3 ** Copyright (C) 2016 The Qt Company Ltd.
4 ** Contact: https://www.qt.io/licensing/
5 **
6 ** This file is part of the examples of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:BSD$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and The Qt Company. For licensing terms
14 ** and conditions see https://www.qt.io/terms-conditions. For further
15 ** information use the contact form at https://www.qt.io/contact-us.
16 **
17 ** BSD License Usage
18 ** Alternatively, you may use this file under the terms of the BSD license
19 ** as follows:
20 **
21 ** "Redistribution and use in source and binary forms, with or without
22 ** modification, are permitted provided that the following conditions are
23 ** met:
24 ** * Redistributions of source code must retain the above copyright
25 ** notice, this list of conditions and the following disclaimer.
26 ** * Redistributions in binary form must reproduce the above copyright
27 ** notice, this list of conditions and the following disclaimer in
28 ** the documentation and/or other materials provided with the
29 ** distribution.
30 ** * Neither the name of The Qt Company Ltd nor the names of its
31 ** contributors may be used to endorse or promote products derived
32 ** from this software without specific prior written permission.
33 **
34 **
35 ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
36 ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
37 ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
38 ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
39 ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
40 ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
41 ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
42 ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
43 ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
44 ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
45 ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
46 **
47 ** $QT_END_LICENSE$
48 **
49 ****************************************************************************/
50
51 #include "bencodeparser.h"
52 #include "metainfo.h"
53
54 #include <QDateTime>
55 #include <QMetaType>
56 #include <QString>
57
MetaInfo()58 MetaInfo::MetaInfo()
59 {
60 clear();
61 }
62
clear()63 void MetaInfo::clear()
64 {
65 errString = "Unknown error";
66 content.clear();
67 infoData.clear();
68 metaInfoMultiFiles.clear();
69 metaInfoAnnounce.clear();
70 metaInfoAnnounceList.clear();
71 metaInfoCreationDate = QDateTime();
72 metaInfoComment.clear();
73 metaInfoCreatedBy.clear();
74 metaInfoName.clear();
75 metaInfoPieceLength = 0;
76 metaInfoSha1Sums.clear();
77 }
78
parse(const QByteArray & data)79 bool MetaInfo::parse(const QByteArray &data)
80 {
81 clear();
82 content = data;
83
84 BencodeParser parser;
85 if (!parser.parse(content)) {
86 errString = parser.errorString();
87 return false;
88 }
89
90 infoData = parser.infoSection();
91
92 QMap<QByteArray, QVariant> dict = parser.dictionary();
93 if (!dict.contains("info"))
94 return false;
95
96 QMap<QByteArray, QVariant> info = qvariant_cast<Dictionary>(dict.value("info"));
97
98 if (info.contains("files")) {
99 metaInfoFileForm = MultiFileForm;
100
101 QList<QVariant> files = info.value("files").toList();
102
103 for (int i = 0; i < files.size(); ++i) {
104 const QMap<QByteArray, QVariant> file = qvariant_cast<Dictionary>(files.at(i));
105 const QList<QVariant> pathElements = file.value("path").toList();
106 QByteArray path;
107 for (const QVariant &p : pathElements) {
108 if (!path.isEmpty())
109 path += '/';
110 path += p.toByteArray();
111 }
112
113 MetaInfoMultiFile multiFile;
114 multiFile.length = file.value("length").toLongLong();
115 multiFile.path = QString::fromUtf8(path);
116 multiFile.md5sum = file.value("md5sum").toByteArray();
117 metaInfoMultiFiles << multiFile;
118 }
119
120 metaInfoName = QString::fromUtf8(info.value("name").toByteArray());
121 metaInfoPieceLength = info.value("piece length").toInt();
122 QByteArray pieces = info.value("pieces").toByteArray();
123 for (int i = 0; i < pieces.size(); i += 20)
124 metaInfoSha1Sums << pieces.mid(i, 20);
125 } else if (info.contains("length")) {
126 metaInfoFileForm = SingleFileForm;
127 metaInfoSingleFile.length = info.value("length").toLongLong();
128 metaInfoSingleFile.md5sum = info.value("md5sum").toByteArray();
129 metaInfoSingleFile.name = QString::fromUtf8(info.value("name").toByteArray());
130 metaInfoSingleFile.pieceLength = info.value("piece length").toInt();
131
132 QByteArray pieces = info.value("pieces").toByteArray();
133 for (int i = 0; i < pieces.size(); i += 20)
134 metaInfoSingleFile.sha1Sums << pieces.mid(i, 20);
135 }
136
137 metaInfoAnnounce = QString::fromUtf8(dict.value("announce").toByteArray());
138
139 if (dict.contains("announce-list")) {
140 // ### unimplemented
141 }
142
143 if (dict.contains("creation date"))
144 metaInfoCreationDate.setSecsSinceEpoch(dict.value("creation date").toInt());
145 if (dict.contains("comment"))
146 metaInfoComment = QString::fromUtf8(dict.value("comment").toByteArray());
147 if (dict.contains("created by"))
148 metaInfoCreatedBy = QString::fromUtf8(dict.value("created by").toByteArray());
149
150 return true;
151 }
152
infoValue() const153 QByteArray MetaInfo::infoValue() const
154 {
155 return infoData;
156 }
157
errorString() const158 QString MetaInfo::errorString() const
159 {
160 return errString;
161 }
162
fileForm() const163 MetaInfo::FileForm MetaInfo::fileForm() const
164 {
165 return metaInfoFileForm;
166 }
167
announceUrl() const168 QString MetaInfo::announceUrl() const
169 {
170 return metaInfoAnnounce;
171 }
172
announceList() const173 QStringList MetaInfo::announceList() const
174 {
175 return metaInfoAnnounceList;
176 }
177
creationDate() const178 QDateTime MetaInfo::creationDate() const
179 {
180 return metaInfoCreationDate;
181 }
182
comment() const183 QString MetaInfo::comment() const
184 {
185 return metaInfoComment;
186 }
187
createdBy() const188 QString MetaInfo::createdBy() const
189 {
190 return metaInfoCreatedBy;
191 }
192
singleFile() const193 MetaInfoSingleFile MetaInfo::singleFile() const
194 {
195 return metaInfoSingleFile;
196 }
197
multiFiles() const198 QList<MetaInfoMultiFile> MetaInfo::multiFiles() const
199 {
200 return metaInfoMultiFiles;
201 }
202
name() const203 QString MetaInfo::name() const
204 {
205 return metaInfoName;
206 }
207
pieceLength() const208 int MetaInfo::pieceLength() const
209 {
210 return metaInfoPieceLength;
211 }
212
sha1Sums() const213 QList<QByteArray> MetaInfo::sha1Sums() const
214 {
215 return metaInfoSha1Sums;
216 }
217
totalSize() const218 qint64 MetaInfo::totalSize() const
219 {
220 if (fileForm() == SingleFileForm)
221 return singleFile().length;
222
223 qint64 size = 0;
224 for (const MetaInfoMultiFile &file : metaInfoMultiFiles)
225 size += file.length;
226 return size;
227 }
228