qint64 RCCFileInfo::writeDataName(FILE *out, qint64 offset) { //capture the offset nameOffset = offset; //write the length qt_rcc_write_number(out, name.length(), 2); fprintf(out, "\\\n"); offset += 2; //write the hash qt_rcc_write_number(out, qt_hash(name), 4); fprintf(out, "\\\n"); offset += 4; //write the name const QChar *unicode = name.unicode(); for (int i=0; i<name.length(); i++) { qt_rcc_write_number(out, unicode[i].unicode(), 2); if(!(i % 16)) fprintf(out, "\\\n"); } offset += name.length()*2; //done fprintf(out, "\\\n"); return offset; }
qint64 RCCFileInfo::writeDataName(RCCResourceLibrary &lib, qint64 offset) { const bool text = (lib.m_format == RCCResourceLibrary::C_Code || lib.m_format == RCCResourceLibrary::Go_Code); // capture the offset m_nameOffset = offset; // some info if (text) { lib.writeString(" // "); lib.writeByteArray(m_name.toUtf8()); lib.writeString("\n "); } // write the length lib.writeNumber2(m_name.length()); if (text) lib.writeString("\n "); offset += 2; // write the hash #if QT_VERSION >= 0x050000 lib.writeNumber4(qt_hash(m_name)); #else lib.writeNumber4(qHash(m_name)); #endif if (text) lib.writeString("\n "); offset += 4; // write the m_name const QChar *unicode = m_name.unicode(); for (int i = 0; i < m_name.length(); ++i) { lib.writeNumber2(unicode[i].unicode()); if (text && i % 16 == 0) lib.writeString("\n "); } offset += m_name.length()*2; // done if (text) lib.writeString("\n "); return offset; }
QT_BEGIN_NAMESPACE static bool containsTLDEntry(const QString &entry) { int index = qt_hash(entry) % tldCount; // select the right chunk from the big table short chunk = 0; uint chunkIndex = tldIndices[index], offset = 0; while (chunk < tldChunkCount && tldIndices[index] >= tldChunks[chunk]) { chunkIndex -= tldChunks[chunk]; offset += tldChunks[chunk]; chunk++; } // check all the entries from the given index while (chunkIndex < tldIndices[index+1] - offset) { QString currentEntry = QString::fromUtf8(tldData[chunk] + chunkIndex); if (currentEntry == entry) return true; chunkIndex += qstrlen(tldData[chunk] + chunkIndex) + 1; // +1 for the ending \0 } return false; }
void tst_QHashFunctions::qthash() { QFETCH(QString, key); const uint result = qt_hash(key); QTEST(result, "hash"); }
int QResourceRoot::findNode(const QString &_path, const QLocale &locale) const { QString path = _path; { QString root = mappingRoot(); if(!root.isEmpty()) { if(root == path) { path = QLatin1Char('/'); } else { if(!root.endsWith(QLatin1Char('/'))) root += QLatin1Char('/'); if(path.size() >= root.size() && path.startsWith(root)) path = path.mid(root.length()-1); if(path.isEmpty()) path = QLatin1Char('/'); } } } #ifdef DEBUG_RESOURCE_MATCH qDebug() << "!!!!" << "START" << path << locale.country() << locale.language(); #endif if(path == QLatin1String("/")) return 0; //the root node is always first int child_count = (tree[6] << 24) + (tree[7] << 16) + (tree[8] << 8) + (tree[9] << 0); int child = (tree[10] << 24) + (tree[11] << 16) + (tree[12] << 8) + (tree[13] << 0); //now iterate up the tree int node = -1; QStringSplitter splitter(path); while (child_count && splitter.hasNext()) { QStringRef segment = splitter.next(); #ifdef DEBUG_RESOURCE_MATCH qDebug() << " CHILDREN" << segment; for(int j = 0; j < child_count; ++j) { qDebug() << " " << child+j << " :: " << name(child+j); } #endif const uint h = qt_hash(segment); //do the binary search for the hash int l = 0, r = child_count-1; int sub_node = (l+r+1)/2; while(r != l) { const uint sub_node_hash = hash(child+sub_node); if(h == sub_node_hash) break; else if(h < sub_node_hash) r = sub_node - 1; else l = sub_node; sub_node = (l + r + 1) / 2; } sub_node += child; //now do the "harder" compares bool found = false; if(hash(sub_node) == h) { while(sub_node > child && hash(sub_node-1) == h) //backup for collisions --sub_node; for(; sub_node < child+child_count && hash(sub_node) == h; ++sub_node) { //here we go... if(name(sub_node) == segment) { found = true; int offset = findOffset(sub_node); #ifdef DEBUG_RESOURCE_MATCH qDebug() << " TRY" << sub_node << name(sub_node) << offset; #endif offset += 4; //jump past name const short flags = (tree[offset+0] << 8) + (tree[offset+1] << 0); offset += 2; if(!splitter.hasNext()) { if(!(flags & Directory)) { const short country = (tree[offset+0] << 8) + (tree[offset+1] << 0); offset += 2; const short language = (tree[offset+0] << 8) + (tree[offset+1] << 0); offset += 2; #ifdef DEBUG_RESOURCE_MATCH qDebug() << " " << "LOCALE" << country << language; #endif if(country == locale.country() && language == locale.language()) { #ifdef DEBUG_RESOURCE_MATCH qDebug() << "!!!!" << "FINISHED" << __LINE__ << sub_node; #endif return sub_node; } else if((country == QLocale::AnyCountry && language == locale.language()) || (country == QLocale::AnyCountry && language == QLocale::C && node == -1)) { node = sub_node; } continue; } else { #ifdef DEBUG_RESOURCE_MATCH qDebug() << "!!!!" << "FINISHED" << __LINE__ << sub_node; #endif return sub_node; } } if(!(flags & Directory)) return -1; child_count = (tree[offset+0] << 24) + (tree[offset+1] << 16) + (tree[offset+2] << 8) + (tree[offset+3] << 0); offset += 4; child = (tree[offset+0] << 24) + (tree[offset+1] << 16) + (tree[offset+2] << 8) + (tree[offset+3] << 0); break; } } } if(!found) break; } #ifdef DEBUG_RESOURCE_MATCH qDebug() << "!!!!" << "FINISHED" << __LINE__ << node; #endif return node; }
int main(int argc, char **argv) { QCoreApplication app(argc, argv); if (argc < 3) { printf("\nusage: %s inputFile outputFile\n\n", argv[0]); printf("'inputFile' should be a list of effective TLDs, one per line,\n"); printf("as obtained from http://publicsuffix.org . To create indices and data file\n"); printf("file, do the following:\n\n"); printf(" wget http://mxr.mozilla.org/mozilla-central/source/netwerk/dns/effective_tld_names.dat?raw=1 -O effective_tld_names.dat\n"); printf(" grep '^[^\\/\\/]' effective_tld_names.dat > effective_tld_names.dat.trimmed\n"); printf(" %s effective_tld_names.dat.trimmed effective_tld_names.dat.qt\n\n", argv[0]); printf("Now copy the data from effective_tld_names.dat.qt to the file src/corelib/io/qurltlds_p.h in your Qt repo\n\n"); exit(1); } QFile file(argv[1]); QFile outFile(argv[2]); file.open(QIODevice::ReadOnly); outFile.open(QIODevice::WriteOnly); QByteArray outIndicesBufferBA; QBuffer outIndicesBuffer(&outIndicesBufferBA); outIndicesBuffer.open(QIODevice::WriteOnly); QByteArray outDataBufferBA; QBuffer outDataBuffer(&outDataBufferBA); outDataBuffer.open(QIODevice::WriteOnly); int lineCount = 0; while (!file.atEnd()) { file.readLine(); lineCount++; } file.reset(); QVector<QString> strings(lineCount); while (!file.atEnd()) { QString s = QString::fromUtf8(file.readLine()); QString st = s.trimmed(); int num = qt_hash(st) % lineCount; QString utf8String = utf8encode(st.toUtf8()); // for domain 1.com, we could get something like // a.com\01.com, which would be interpreted as octal 01, // so we need to separate those strings with quotes QRegExp regexpOctalEscape(QLatin1String("^[0-9]")); if (!strings.at(num).isEmpty() && st.contains(regexpOctalEscape)) strings[num].append("\"\""); strings[num].append(utf8String); strings[num].append("\\0"); } outIndicesBuffer.write("static const quint16 tldCount = "); outIndicesBuffer.write(QByteArray::number(lineCount)); outIndicesBuffer.write(";\n"); outIndicesBuffer.write("static const quint32 tldIndices["); // outIndicesBuffer.write(QByteArray::number(lineCount+1)); // not needed outIndicesBuffer.write("] = {\n"); int totalUtf8Size = 0; int chunkSize = 0; int stringUtf8Size = 0; QStringList chunks; for (int a = 0; a < lineCount; a++) { bool lineIsEmpty = strings.at(a).isEmpty(); if (!lineIsEmpty) { strings[a].prepend("\""); strings[a].append("\""); } int zeroCount = strings.at(a).count(QLatin1String("\\0")); int utf8CharsCount = strings.at(a).count(QLatin1String("\\x")); int quoteCount = strings.at(a).count('"'); stringUtf8Size = strings.at(a).count() - (zeroCount + quoteCount + utf8CharsCount * 3); chunkSize += stringUtf8Size; if (chunkSize > 65535) { static int chunkCount = 0; qWarning() << "chunk" << ++chunkCount << "has length" << chunkSize - stringUtf8Size; outDataBuffer.write(",\n\n"); chunks.append(QByteArray::number(totalUtf8Size)); chunkSize = 0; } outDataBuffer.write(strings.at(a).toUtf8()); if (!lineIsEmpty) outDataBuffer.write("\n"); outIndicesBuffer.write(QByteArray::number(totalUtf8Size)); outIndicesBuffer.write(",\n"); totalUtf8Size += stringUtf8Size; } chunks.append(QByteArray::number(totalUtf8Size)); outIndicesBuffer.write(QByteArray::number(totalUtf8Size)); outIndicesBuffer.write("};\n"); outIndicesBuffer.close(); outFile.write(outIndicesBufferBA); outDataBuffer.close(); outFile.write("\nstatic const char *tldData["); // outFile.write(QByteArray::number(charSize)); // not needed outFile.write("] = {\n"); outFile.write(outDataBufferBA); outFile.write("};\n"); // write chunk information outFile.write("\nstatic const quint16 tldChunkCount = "); outFile.write(QByteArray::number(chunks.count())); outFile.write(";\nstatic const quint32 tldChunks[] = {"); outFile.write(chunks.join(", ").toLatin1()); outFile.write("};\n"); outFile.close(); printf("data generated to %s . Now copy the data from this file to src/corelib/io/qurltlds_p.h in your Qt repo\n", argv[2]); exit(0); }
static bool qt_rcc_compare_hash(const RCCFileInfo *left, const RCCFileInfo *right) { return qt_hash(left->name) < qt_hash(right->name); }