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 Qt Linguist of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:GPL-EXCEPT$
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 ** GNU General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU
19 ** General Public License version 3 as published by the Free Software
20 ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
21 ** included in the packaging of this file. Please review the following
22 ** information to ensure the GNU General Public License requirements will
23 ** be met: https://www.gnu.org/licenses/gpl-3.0.html.
24 **
25 ** $QT_END_LICENSE$
26 **
27 ****************************************************************************/
28 
29 #include "proitems.h"
30 
31 #include <qfileinfo.h>
32 #include <qset.h>
33 #include <qstringlist.h>
34 #include <qtextstream.h>
35 
36 QT_BEGIN_NAMESPACE
37 
38 // from qhash.cpp
hash(const QChar * p,int n)39 uint ProString::hash(const QChar *p, int n)
40 {
41     uint h = 0;
42 
43     while (n--) {
44         h = (h << 4) + (*p++).unicode();
45         h ^= (h & 0xf0000000) >> 23;
46         h &= 0x0fffffff;
47     }
48     return h;
49 }
50 
ProString()51 ProString::ProString() :
52     m_offset(0), m_length(0), m_file(0), m_hash(0x80000000)
53 {
54 }
55 
ProString(const ProString & other)56 ProString::ProString(const ProString &other) :
57     m_string(other.m_string), m_offset(other.m_offset), m_length(other.m_length), m_file(other.m_file), m_hash(other.m_hash)
58 {
59 }
60 
ProString(const ProString & other,OmitPreHashing)61 ProString::ProString(const ProString &other, OmitPreHashing) :
62     m_string(other.m_string), m_offset(other.m_offset), m_length(other.m_length), m_file(other.m_file), m_hash(0x80000000)
63 {
64 }
65 
ProString(const QString & str,DoPreHashing)66 ProString::ProString(const QString &str, DoPreHashing) :
67     m_string(str), m_offset(0), m_length(str.length()), m_file(0)
68 {
69     updatedHash();
70 }
71 
ProString(const QString & str)72 ProString::ProString(const QString &str) :
73     m_string(str), m_offset(0), m_length(str.length()), m_file(0), m_hash(0x80000000)
74 {
75 }
76 
ProString(const QStringRef & str)77 ProString::ProString(const QStringRef &str) :
78     m_string(*str.string()), m_offset(str.position()), m_length(str.size()), m_file(0), m_hash(0x80000000)
79 {
80 }
81 
ProString(const char * str,DoPreHashing)82 ProString::ProString(const char *str, DoPreHashing) :
83     m_string(QString::fromLatin1(str)), m_offset(0), m_length(qstrlen(str)), m_file(0)
84 {
85     updatedHash();
86 }
87 
ProString(const char * str)88 ProString::ProString(const char *str) :
89     m_string(QString::fromLatin1(str)), m_offset(0), m_length(qstrlen(str)), m_file(0), m_hash(0x80000000)
90 {
91 }
92 
ProString(const QString & str,int offset,int length,DoPreHashing)93 ProString::ProString(const QString &str, int offset, int length, DoPreHashing) :
94     m_string(str), m_offset(offset), m_length(length), m_file(0)
95 {
96     updatedHash();
97 }
98 
ProString(const QString & str,int offset,int length,uint hash)99 ProString::ProString(const QString &str, int offset, int length, uint hash) :
100     m_string(str), m_offset(offset), m_length(length), m_file(0), m_hash(hash)
101 {
102 }
103 
ProString(const QString & str,int offset,int length)104 ProString::ProString(const QString &str, int offset, int length) :
105     m_string(str), m_offset(offset), m_length(length), m_file(0), m_hash(0x80000000)
106 {
107 }
108 
setValue(const QString & str)109 void ProString::setValue(const QString &str)
110 {
111     m_string = str, m_offset = 0, m_length = str.length(), m_hash = 0x80000000;
112 }
113 
updatedHash() const114 uint ProString::updatedHash() const
115 {
116      return (m_hash = hash(m_string.constData() + m_offset, m_length));
117 }
118 
qHash(const ProString & str)119 uint qHash(const ProString &str)
120 {
121     if (!(str.m_hash & 0x80000000))
122         return str.m_hash;
123     return str.updatedHash();
124 }
125 
ProKey(const QString & str)126 ProKey::ProKey(const QString &str) :
127     ProString(str, DoHash)
128 {
129 }
130 
ProKey(const char * str)131 ProKey::ProKey(const char *str) :
132     ProString(str, DoHash)
133 {
134 }
135 
ProKey(const QString & str,int off,int len)136 ProKey::ProKey(const QString &str, int off, int len) :
137     ProString(str, off, len, DoHash)
138 {
139 }
140 
ProKey(const QString & str,int off,int len,uint hash)141 ProKey::ProKey(const QString &str, int off, int len, uint hash) :
142     ProString(str, off, len, hash)
143 {
144 }
145 
setValue(const QString & str)146 void ProKey::setValue(const QString &str)
147 {
148     m_string = str, m_offset = 0, m_length = str.length();
149     updatedHash();
150 }
151 
toQString() const152 QString ProString::toQString() const
153 {
154     return m_string.mid(m_offset, m_length);
155 }
156 
toQString(QString & tmp) const157 QString &ProString::toQString(QString &tmp) const
158 {
159     return tmp.setRawData(m_string.constData() + m_offset, m_length);
160 }
161 
162 /*!
163  * \brief ProString::prepareExtend
164  * \param extraLen number of new characters to be added
165  * \param thisTarget offset to which current contents should be moved
166  * \param extraTarget offset at which new characters will be added
167  * \return pointer to storage location for new characters
168  *
169  * Prepares the string for adding new characters.
170  * If the string is detached and has enough space, it will be changed in place.
171  * Otherwise, it will be replaced with a new string object, thus detaching.
172  * In either case, the hash will be reset.
173  */
prepareExtend(int extraLen,int thisTarget,int extraTarget)174 QChar *ProString::prepareExtend(int extraLen, int thisTarget, int extraTarget)
175 {
176     if (m_string.isDetached() && m_length + extraLen <= m_string.capacity()) {
177         m_string.reserve(0); // Prevent the resize() below from reallocating
178         QChar *ptr = (QChar *)m_string.constData();
179         if (m_offset != thisTarget)
180             memmove(ptr + thisTarget, ptr + m_offset, m_length * 2);
181         ptr += extraTarget;
182         m_offset = 0;
183         m_length += extraLen;
184         m_string.resize(m_length);
185         m_hash = 0x80000000;
186         return ptr;
187     } else {
188         QString neu(m_length + extraLen, Qt::Uninitialized);
189         QChar *ptr = (QChar *)neu.constData();
190         memcpy(ptr + thisTarget, m_string.constData() + m_offset, m_length * 2);
191         ptr += extraTarget;
192         *this = ProString(neu);
193         return ptr;
194     }
195 }
196 
prepend(const ProString & other)197 ProString &ProString::prepend(const ProString &other)
198 {
199     if (other.m_length) {
200         if (!m_length) {
201             *this = other;
202         } else {
203             QChar *ptr = prepareExtend(other.m_length, other.m_length, 0);
204             memcpy(ptr, other.constData(), other.m_length * 2);
205             if (!m_file)
206                 m_file = other.m_file;
207         }
208     }
209     return *this;
210 }
211 
append(const QLatin1String other)212 ProString &ProString::append(const QLatin1String other)
213 {
214     const char *latin1 = other.latin1();
215     int size = other.size();
216     if (size) {
217         QChar *ptr = prepareExtend(size, 0, m_length);
218         for (int i = 0; i < size; i++)
219             *ptr++ = QLatin1Char(latin1[i]);
220     }
221     return *this;
222 }
223 
append(QChar other)224 ProString &ProString::append(QChar other)
225 {
226     QChar *ptr = prepareExtend(1, 0, m_length);
227     *ptr = other;
228     return *this;
229 }
230 
231 // If pending != 0, prefix with space if appending to non-empty non-pending
append(const ProString & other,bool * pending)232 ProString &ProString::append(const ProString &other, bool *pending)
233 {
234     if (other.m_length) {
235         if (!m_length) {
236             *this = other;
237         } else {
238             QChar *ptr;
239             if (pending && !*pending) {
240                 ptr = prepareExtend(1 + other.m_length, 0, m_length);
241                 *ptr++ = 32;
242             } else {
243                 ptr = prepareExtend(other.m_length, 0, m_length);
244             }
245             memcpy(ptr, other.m_string.constData() + other.m_offset, other.m_length * 2);
246             if (other.m_file)
247                 m_file = other.m_file;
248         }
249         if (pending)
250             *pending = true;
251     }
252     return *this;
253 }
254 
append(const ProStringList & other,bool * pending,bool skipEmpty1st)255 ProString &ProString::append(const ProStringList &other, bool *pending, bool skipEmpty1st)
256 {
257     if (const int sz = other.size()) {
258         int startIdx = 0;
259         if (pending && !*pending && skipEmpty1st && other.at(0).isEmpty()) {
260             if (sz == 1)
261                 return *this;
262             startIdx = 1;
263         }
264         if (!m_length && sz == startIdx + 1) {
265             *this = other.at(startIdx);
266         } else {
267             int totalLength = sz - startIdx;
268             for (int i = startIdx; i < sz; ++i)
269                 totalLength += other.at(i).size();
270             bool putSpace = false;
271             if (pending && !*pending && m_length)
272                 putSpace = true;
273             else
274                 totalLength--;
275 
276             QChar *ptr = prepareExtend(totalLength, 0, m_length);
277             for (int i = startIdx; i < sz; ++i) {
278                 if (putSpace)
279                     *ptr++ = 32;
280                 else
281                     putSpace = true;
282                 const ProString &str = other.at(i);
283                 memcpy(ptr, str.m_string.constData() + str.m_offset, str.m_length * 2);
284                 ptr += str.m_length;
285             }
286             if (other.last().m_file)
287                 m_file = other.last().m_file;
288         }
289         if (pending)
290             *pending = true;
291     }
292     return *this;
293 }
294 
operator +(const ProString & one,const ProString & two)295 QString operator+(const ProString &one, const ProString &two)
296 {
297     if (two.m_length) {
298         if (!one.m_length) {
299             return two.toQString();
300         } else {
301             QString neu(one.m_length + two.m_length, Qt::Uninitialized);
302             ushort *ptr = (ushort *)neu.constData();
303             memcpy(ptr, one.m_string.constData() + one.m_offset, one.m_length * 2);
304             memcpy(ptr + one.m_length, two.m_string.constData() + two.m_offset, two.m_length * 2);
305             return neu;
306         }
307     }
308     return one.toQString();
309 }
310 
311 
mid(int off,int len) const312 ProString ProString::mid(int off, int len) const
313 {
314     ProString ret(*this, NoHash);
315     if (off > m_length)
316         off = m_length;
317     ret.m_offset += off;
318     ret.m_length -= off;
319     if ((uint)ret.m_length > (uint)len)  // Unsigned comparison to interpret < 0 as infinite
320         ret.m_length = len;
321     return ret;
322 }
323 
trimmed() const324 ProString ProString::trimmed() const
325 {
326     ProString ret(*this, NoHash);
327     int cur = m_offset;
328     int end = cur + m_length;
329     const QChar *data = m_string.constData();
330     for (; cur < end; cur++)
331         if (!data[cur].isSpace()) {
332             // No underrun check - we know there is at least one non-whitespace
333             while (data[end - 1].isSpace())
334                 end--;
335             break;
336         }
337     ret.m_offset = cur;
338     ret.m_length = end - cur;
339     return ret;
340 }
341 
operator <<(QTextStream & t,const ProString & str)342 QTextStream &operator<<(QTextStream &t, const ProString &str)
343 {
344     t << str.toQStringRef();
345     return t;
346 }
347 
ProStringList_join(const ProStringList & this_,const QChar * sep,const int sepSize)348 static QString ProStringList_join(const ProStringList &this_, const QChar *sep, const int sepSize)
349 {
350     int totalLength = 0;
351     const int sz = this_.size();
352 
353     for (int i = 0; i < sz; ++i)
354         totalLength += this_.at(i).size();
355 
356     if (sz)
357         totalLength += sepSize * (sz - 1);
358 
359     QString res(totalLength, Qt::Uninitialized);
360     QChar *ptr = (QChar *)res.constData();
361     for (int i = 0; i < sz; ++i) {
362         if (i) {
363             memcpy(ptr, sep, sepSize * sizeof(QChar));
364             ptr += sepSize;
365         }
366         const ProString &str = this_.at(i);
367         memcpy(ptr, str.constData(), str.size() * sizeof(QChar));
368         ptr += str.size();
369     }
370     return res;
371 }
372 
join(const ProString & sep) const373 QString ProStringList::join(const ProString &sep) const
374 {
375     return ProStringList_join(*this, sep.constData(), sep.size());
376 }
377 
join(const QString & sep) const378 QString ProStringList::join(const QString &sep) const
379 {
380     return ProStringList_join(*this, sep.constData(), sep.size());
381 }
382 
join(QChar sep) const383 QString ProStringList::join(QChar sep) const
384 {
385     return ProStringList_join(*this, &sep, 1);
386 }
387 
removeAll(const ProString & str)388 void ProStringList::removeAll(const ProString &str)
389 {
390     for (int i = size(); --i >= 0; )
391         if (at(i) == str)
392             remove(i);
393 }
394 
removeAll(const char * str)395 void ProStringList::removeAll(const char *str)
396 {
397     for (int i = size(); --i >= 0; )
398         if (at(i) == str)
399             remove(i);
400 }
401 
removeEach(const ProStringList & value)402 void ProStringList::removeEach(const ProStringList &value)
403 {
404     for (const ProString &str : value) {
405         if (isEmpty())
406             break;
407         if (!str.isEmpty())
408             removeAll(str);
409     }
410 }
411 
removeEmpty()412 void ProStringList::removeEmpty()
413 {
414     for (int i = size(); --i >= 0;)
415         if (at(i).isEmpty())
416             remove(i);
417 }
418 
removeDuplicates()419 void ProStringList::removeDuplicates()
420 {
421     int n = size();
422     int j = 0;
423     QSet<ProString> seen;
424     seen.reserve(n);
425     for (int i = 0; i < n; ++i) {
426         const ProString &s = at(i);
427         if (seen.contains(s))
428             continue;
429         seen.insert(s);
430         if (j != i)
431             (*this)[j] = s;
432         ++j;
433     }
434     if (n != j)
435         erase(begin() + j, end());
436 }
437 
insertUnique(const ProStringList & value)438 void ProStringList::insertUnique(const ProStringList &value)
439 {
440     for (const ProString &str : value)
441         if (!str.isEmpty() && !contains(str))
442             append(str);
443 }
444 
ProStringList(const QStringList & list)445 ProStringList::ProStringList(const QStringList &list)
446 {
447     reserve(list.size());
448     for (const QString &str : list)
449         *this << ProString(str);
450 }
451 
toQStringList() const452 QStringList ProStringList::toQStringList() const
453 {
454     QStringList ret;
455     ret.reserve(size());
456     for (const auto &e : *this)
457         ret.append(e.toQString());
458     return ret;
459 }
460 
contains(const ProString & str,Qt::CaseSensitivity cs) const461 bool ProStringList::contains(const ProString &str, Qt::CaseSensitivity cs) const
462 {
463     for (int i = 0; i < size(); i++)
464         if (!at(i).compare(str, cs))
465             return true;
466     return false;
467 }
468 
contains(const QStringRef & str,Qt::CaseSensitivity cs) const469 bool ProStringList::contains(const QStringRef &str, Qt::CaseSensitivity cs) const
470 {
471     for (int i = 0; i < size(); i++)
472         if (!at(i).toQStringRef().compare(str, cs))
473             return true;
474     return false;
475 }
476 
contains(const char * str,Qt::CaseSensitivity cs) const477 bool ProStringList::contains(const char *str, Qt::CaseSensitivity cs) const
478 {
479     for (int i = 0; i < size(); i++)
480         if (!at(i).compare(str, cs))
481             return true;
482     return false;
483 }
484 
ProFile(int id,const QString & fileName)485 ProFile::ProFile(int id, const QString &fileName)
486     : m_refCount(1),
487       m_fileName(fileName),
488       m_id(id),
489       m_ok(true),
490       m_hostBuild(false)
491 {
492     if (!fileName.startsWith(QLatin1Char('(')))
493         m_directoryName = QFileInfo( // qmake sickness: canonicalize only the directory!
494                 fileName.left(fileName.lastIndexOf(QLatin1Char('/')))).canonicalFilePath();
495 }
496 
~ProFile()497 ProFile::~ProFile()
498 {
499 }
500 
getStr(const ushort * & tPtr)501 ProString ProFile::getStr(const ushort *&tPtr)
502 {
503     uint len = *tPtr++;
504     ProString ret(items(), tPtr - tokPtr(), len);
505     ret.setSource(m_id);
506     tPtr += len;
507     return ret;
508 }
509 
getHashStr(const ushort * & tPtr)510 ProKey ProFile::getHashStr(const ushort *&tPtr)
511 {
512     uint hash = *tPtr++;
513     hash |= (uint)*tPtr++ << 16;
514     uint len = *tPtr++;
515     ProKey ret(items(), tPtr - tokPtr(), len, hash);
516     tPtr += len;
517     return ret;
518 }
519 
520 QT_END_NAMESPACE
521