📄 qresource.cpp
字号:
/******************************************************************************** Copyright (C) 1992-2006 Trolltech ASA. All rights reserved.**** This file is part of the QtCore module of the Qt Toolkit.**** This file may be used under the terms of the GNU General Public** License version 2.0 as published by the Free Software Foundation** and appearing in the file LICENSE.GPL included in the packaging of** this file. Please review the following information to ensure GNU** General Public Licensing requirements will be met:** http://www.trolltech.com/products/qt/opensource.html**** If you are unsure which license is appropriate for your use, please** review the following information:** http://www.trolltech.com/products/qt/licensing.html or contact the** sales department at sales@trolltech.com.**** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.******************************************************************************/#include "qresource_p.h"#include "qset.h"#include "qhash.h"#include "qlocale.h"#include "qglobal.h"#include "qdatetime.h"#include "qbytearray.h"#include "qstringlist.h"#include "qvector.h"#include "private/qabstractfileengine_p.h"//resource glueclass QResource{ enum Flags { Compressed = 0x01, Directory = 0x02 }; const uchar *tree, *names, *payloads; int findNode(const QString &path) const; inline int findOffset(int node) const { return node * 14; } //sizeof each tree element inline int hash(int offset) const; inline QString name(int offset) const;public: inline QResource(): tree(0), names(0), payloads(0) {} inline QResource(const uchar *t, const uchar *n, const uchar *d) : tree(t), names(n), payloads(d) {} bool isContainer(const QString &path) const; bool exists(const QString &path) const; QByteArray data(const QString &path) const; QStringList children(const QString &path) const; inline bool operator==(const QResource &other) const { return tree == other.tree && names == other.names && payloads == other.payloads; } inline bool operator!=(const QResource &other) const { return !operator==(other); }};Q_DECLARE_TYPEINFO(QResource, Q_MOVABLE_TYPE);inline int QResource::hash(int node) const{ if(!node) //root return 0; const int offset = findOffset(node); int name_offset = (tree[offset+0] << 24) + (tree[offset+1] << 16) + (tree[offset+2] << 8) + (tree[offset+3] << 0); name_offset += 2; //jump past name length return (names[name_offset+0] << 24) + (names[name_offset+1] << 16) + (names[name_offset+2] << 8) + (names[name_offset+3] << 0);}inline QString QResource::name(int node) const{ if(!node) // root return QString(); const int offset = findOffset(node); QString ret; int name_offset = (tree[offset+0] << 24) + (tree[offset+1] << 16) + (tree[offset+2] << 8) + (tree[offset+3] << 0); const short name_length = (names[name_offset+0] << 8) + (names[name_offset+1] << 0); name_offset += 2; name_offset += 4; //jump past hash for(int i = 0; i < name_length*2; i+=2) ret += QChar(names[name_offset+i+1], names[name_offset+i]); return ret;}int QResource::findNode(const QString &path) const{ 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; QLocale locale; QStringList segments = path.split('/', QString::SkipEmptyParts); for(int i = 0; child_count && i < segments.size(); ++i) { const QString &segment = segments[i]; const int h = qHash(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 int 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) + 4; //jump past name const short flags = (tree[offset+0] << 8) + (tree[offset+1] << 0); offset += 2; if(i == segments.size()-1) { 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; if(country == locale.country() && language == locale.language()) return sub_node; else if((country == QLocale::AnyCountry && language == locale.language()) || (country == QLocale::AnyCountry && language == QLocale::C && node == -1)) node = sub_node; continue; } else { 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; } return node;}bool QResource::isContainer(const QString &path) const{ int node = findNode(path); if(node == -1) return false; const int offset = findOffset(node) + 4; //jump past name const short flags = (tree[offset+0] << 8) + (tree[offset+1] << 0); return flags & Directory;}bool QResource::exists(const QString &path) const{ return findNode(path) != -1;}QByteArray QResource::data(const QString &path) const{ const int node = findNode(path); if(node == -1) return QByteArray(); int offset = findOffset(node) + 4; //jump past name const short flags = (tree[offset+0] << 8) + (tree[offset+1] << 0); offset += 2; offset += 4; //jump past locale QByteArray ret; if(!(flags & Directory)) { const int data_offset = (tree[offset+0] << 24) + (tree[offset+1] << 16) + (tree[offset+2] << 8) + (tree[offset+3] << 0); const uint data_length = (payloads[data_offset+0] << 24) + (payloads[data_offset+1] << 16) + (payloads[data_offset+2] << 8) + (payloads[data_offset+3] << 0); const uchar *data = payloads+data_offset+4;#ifndef QT_NO_COMPRESS if(flags & Compressed) ret = qUncompress(data, data_length); else ret = QByteArray((char*)data, data_length);#else Q_ASSERT_X(!(flags & Compressed), "QResource::data", "Qt built without support for compression"); #endif } return ret;}QStringList QResource::children(const QString &path) const{ int node = findNode(path); if(node == -1) return QStringList(); int offset = findOffset(node) + 4; //jump past name const short flags = (tree[offset+0] << 8) + (tree[offset+1] << 0); offset += 2; QStringList ret; if(flags & Directory) { const int child_count = (tree[offset+0] << 24) + (tree[offset+1] << 16) + (tree[offset+2] << 8) + (tree[offset+3] << 0); offset += 4; const int child_off = (tree[offset+0] << 24) + (tree[offset+1] << 16) + (tree[offset+2] << 8) + (tree[offset+3] << 0); for(int i = child_off; i < child_off+child_count; ++i) ret << name(i); } return ret;}Q_GLOBAL_STATIC(QStringList, qt_resource_search_paths)bool qt_resource_add_search_path(const QString &path){ if(path[0] != QLatin1Char('/')) { qWarning("QDir::addResourceSearchPath: Search paths must be absolute (start with /) [%s]", path.toLocal8Bit().data()); return false; } qt_resource_search_paths()->prepend(path); return true;}typedef QVector<QResource> ResourceList;Q_GLOBAL_STATIC(ResourceList, resourceList)class QResourceInfo{ QString file, searchFile; ResourceList related; uint container : 1; mutable uint hasData : 1; mutable uint hasChildren : 1; mutable uint initialized : 1; mutable QByteArray mData; mutable QStringList mChildren; inline void clear() { searchFile.clear(); file.clear(); hasData = hasChildren = 0; container = 0; related.clear(); initialized = 0; } bool loadResource(const QString &);public: QResourceInfo() { clear(); } QResourceInfo(const QString &f) : file(f), initialized(0) {} void setFileName(const QString &f) { clear(); file = f; } QString fileName() const { return file; } QString searchFileName() const { ensureInitialized(); return searchFile; } bool exists() const { ensureInitialized(); return !related.isEmpty(); } bool isContainer() const { ensureInitialized(); return container; } QByteArray data() const; QStringList children() const; void ensureInitialized() const;};boolQResourceInfo::loadResource(const QString &path){ ensureInitialized(); const ResourceList *list = resourceList(); for(int i = 0; i < list->size(); ++i) { QResource res = list->at(i); if(res.exists(path)) { if(related.isEmpty()) container = res.isContainer(path); else if(res.isContainer(path) != container) qWarning("Resource [%s] has both data and children!", file.toLatin1().constData()); related.append(res); } } return !related.isEmpty();}void QResourceInfo::ensureInitialized() const{ if (initialized) return; initialized = 1; QResourceInfo *that = const_cast<QResourceInfo *>(this); if(file == QLatin1String(":")) that->file += QLatin1Char('/'); that->searchFile = file; QString path = file; if(path.startsWith(QLatin1Char(':'))) path = path.mid(1); if(path.startsWith(QLatin1Char('/'))) { that->loadResource(path); return; } else { QStringList searchPaths = *qt_resource_search_paths(); searchPaths << QLatin1String(""); for(int i = 0; i < searchPaths.size(); ++i) { const QString searchPath(searchPaths.at(i) + QLatin1Char('/') + path); if(that->loadResource(searchPath)) { that->searchFile = QLatin1Char(':') + searchPath; break; } } }}QByteArray QResourceInfo::data() const{ if(container || related.isEmpty()) return QByteArray(); if(!hasData) { hasData = true; QString path = searchFile; if(path.startsWith(QLatin1Char(':'))) path = path.mid(1); mData = related.at(0).data(path); } return mData;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -