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
58MetaInfo::MetaInfo()
59{
60 clear();
61}
62
63void 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
79bool 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(akey: "info"))
94 return false;
95
96 QMap<QByteArray, QVariant> info = qvariant_cast<Dictionary>(v: dict.value(akey: "info"));
97
98 if (info.contains(akey: "files")) {
99 metaInfoFileForm = MultiFileForm;
100
101 QList<QVariant> files = info.value(akey: "files").toList();
102
103 for (int i = 0; i < files.size(); ++i) {
104 const QMap<QByteArray, QVariant> file = qvariant_cast<Dictionary>(v: files.at(i));
105 const QList<QVariant> pathElements = file.value(akey: "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(akey: "length").toLongLong();
115 multiFile.path = QString::fromUtf8(str: path);
116 multiFile.md5sum = file.value(akey: "md5sum").toByteArray();
117 metaInfoMultiFiles << multiFile;
118 }
119
120 metaInfoName = QString::fromUtf8(str: info.value(akey: "name").toByteArray());
121 metaInfoPieceLength = info.value(akey: "piece length").toInt();
122 QByteArray pieces = info.value(akey: "pieces").toByteArray();
123 for (int i = 0; i < pieces.size(); i += 20)
124 metaInfoSha1Sums << pieces.mid(index: i, len: 20);
125 } else if (info.contains(akey: "length")) {
126 metaInfoFileForm = SingleFileForm;
127 metaInfoSingleFile.length = info.value(akey: "length").toLongLong();
128 metaInfoSingleFile.md5sum = info.value(akey: "md5sum").toByteArray();
129 metaInfoSingleFile.name = QString::fromUtf8(str: info.value(akey: "name").toByteArray());
130 metaInfoSingleFile.pieceLength = info.value(akey: "piece length").toInt();
131
132 QByteArray pieces = info.value(akey: "pieces").toByteArray();
133 for (int i = 0; i < pieces.size(); i += 20)
134 metaInfoSingleFile.sha1Sums << pieces.mid(index: i, len: 20);
135 }
136
137 metaInfoAnnounce = QString::fromUtf8(str: dict.value(akey: "announce").toByteArray());
138
139 if (dict.contains(akey: "announce-list")) {
140 // ### unimplemented
141 }
142
143 if (dict.contains(akey: "creation date"))
144 metaInfoCreationDate.setSecsSinceEpoch(dict.value(akey: "creation date").toInt());
145 if (dict.contains(akey: "comment"))
146 metaInfoComment = QString::fromUtf8(str: dict.value(akey: "comment").toByteArray());
147 if (dict.contains(akey: "created by"))
148 metaInfoCreatedBy = QString::fromUtf8(str: dict.value(akey: "created by").toByteArray());
149
150 return true;
151}
152
153QByteArray MetaInfo::infoValue() const
154{
155 return infoData;
156}
157
158QString MetaInfo::errorString() const
159{
160 return errString;
161}
162
163MetaInfo::FileForm MetaInfo::fileForm() const
164{
165 return metaInfoFileForm;
166}
167
168QString MetaInfo::announceUrl() const
169{
170 return metaInfoAnnounce;
171}
172
173QStringList MetaInfo::announceList() const
174{
175 return metaInfoAnnounceList;
176}
177
178QDateTime MetaInfo::creationDate() const
179{
180 return metaInfoCreationDate;
181}
182
183QString MetaInfo::comment() const
184{
185 return metaInfoComment;
186}
187
188QString MetaInfo::createdBy() const
189{
190 return metaInfoCreatedBy;
191}
192
193MetaInfoSingleFile MetaInfo::singleFile() const
194{
195 return metaInfoSingleFile;
196}
197
198QList<MetaInfoMultiFile> MetaInfo::multiFiles() const
199{
200 return metaInfoMultiFiles;
201}
202
203QString MetaInfo::name() const
204{
205 return metaInfoName;
206}
207
208int MetaInfo::pieceLength() const
209{
210 return metaInfoPieceLength;
211}
212
213QList<QByteArray> MetaInfo::sha1Sums() const
214{
215 return metaInfoSha1Sums;
216}
217
218qint64 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

source code of qtbase/examples/network/torrent/metainfo.cpp