/* * This file is part of the PySide Tools project. * * Copyright (C) 1992-2005 Trolltech AS. All rights reserved. * Copyright (C) 2009-2011 Nokia Corporation and/or its subsidiary(-ies). * * Contact: PySide team * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * version 2 as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA * */ #include #include #include #include #include #include #include #include #include #include #include #include #include "rcc.h" #include static bool qt_rcc_write_number(FILE *out, quint32 number, int width) { int dividend = 1; switch (width) { case 2: dividend = 256; break; case 3: dividend = 65536; break; case 4: dividend = 16777216; break; default: break; } // Write bytes while (dividend >= 1) { const quint8 tmp = number / dividend; if (tmp >= 32 && tmp < 127 && tmp != '"' && tmp != '\\') { /* Optimization for printable characters */ fprintf(out, "%c", tmp); } else { fprintf(out, "\\x%02x", tmp); } number -= tmp * dividend; dividend /= 256; } return true; } bool RCCFileInfo::writeDataInfo(FILE *out) { //pointer data if(flags & RCCFileInfo::Directory) { //name offset qt_rcc_write_number(out, nameOffset, 4); //flags qt_rcc_write_number(out, flags, 2); //child count qt_rcc_write_number(out, children.size(), 4); //first child offset qt_rcc_write_number(out, childOffset, 4); } else { //name offset qt_rcc_write_number(out, nameOffset, 4); //flags qt_rcc_write_number(out, flags, 2); //locale qt_rcc_write_number(out, locale.country(), 2); qt_rcc_write_number(out, locale.language(), 2); //data offset qt_rcc_write_number(out, dataOffset, 4); } fprintf(out, "\\\n"); return true; } qint64 RCCFileInfo::writeDataBlob(FILE *out, qint64 offset) { //capture the offset dataOffset = offset; //find the data to be written QFile file(fileInfo.absoluteFilePath()); if (!file.open(QFile::ReadOnly)) { fprintf(stderr, "Couldn't open %s\n", fileInfo.absoluteFilePath().toLatin1().constData()); return false; } QByteArray data = file.readAll(); #ifndef QT_NO_COMPRESS // Check if compression is useful for this file if (mCompressLevel != 0 && data.size() != 0) { QByteArray compressed = qCompress(reinterpret_cast(data.data()), data.size(), mCompressLevel); int compressRatio = int(100.0f * (float(data.size() - compressed.size()) / float(data.size()))); if (compressRatio >= mCompressThreshold) { data = compressed; flags |= Compressed; } } #endif // QT_NO_COMPRESS //write the length qt_rcc_write_number(out, data.size(), 4); fprintf(out, "\\\n"); offset += 4; //write the payload for (int i=0; iroot == 0) { fprintf(stderr, "No resources in resource description.\n"); return false; } return true; } bool RCCResourceLibrary::addFile(const QString &alias, const RCCFileInfo &file) { if (file.fileInfo.size() > 0xffffffff) { fprintf(stderr, "File too big: %s", file.fileInfo.absoluteFilePath().toLatin1().constData()); return false; } if(!root) root = new RCCFileInfo("", QFileInfo(), QLocale(), RCCFileInfo::Directory); RCCFileInfo *parent = root; const QStringList nodes = alias.split('/'); for(int i = 1; i < nodes.size()-1; ++i) { const QString node = nodes.at(i); if(!parent->children.contains(node)) { RCCFileInfo *s = new RCCFileInfo(node, QFileInfo(), QLocale(), RCCFileInfo::Directory); s->parent = parent; parent->children.insert(node, s); parent = s; } else { parent = parent->children[node]; } } const QString filename = nodes.at(nodes.size()-1); RCCFileInfo *s = new RCCFileInfo(file); s->parent = parent; parent->children.insertMulti(filename, s); return true; } bool RCCResourceLibrary::readFiles() { //read in data if (mVerbose) fprintf(stderr, "Processing %d files\n", mFileNames.size()); for (int i=0; i pending; if (!root) return ret; pending.push(root); while(!pending.isEmpty()) { RCCFileInfo *file = pending.pop(); for(QHash::iterator it = file->children.begin(); it != file->children.end(); ++it) { RCCFileInfo *child = it.value(); if(child->flags & RCCFileInfo::Directory) pending.push(child); ret.append(child->fileInfo.filePath()); } } return ret; } bool RCCResourceLibrary::output(FILE *out) { //write out if (mVerbose) fprintf(stderr, "Outputting code\n"); if (!writeHeader(out)) { fprintf(stderr, "Couldn't write header\n"); return false; } if (!writeDataBlobs(out)) { fprintf(stderr, "Couldn't write data blob\n"); return false; } if (!writeDataNames(out)) { fprintf(stderr, "Couldn't write file names\n"); return false; } if (!writeDataStructure(out)) { fprintf(stderr, "Couldn't write data tree\n"); return false; } if (!writeInitializer(out)) { fprintf(stderr, "Couldn't write footer\n"); return false; } return true; } bool RCCResourceLibrary::writeHeader(FILE *out) { fprintf(out, "# -*- coding: utf-8 -*-\n\n"); fprintf(out, "# Resource object code\n"); fprintf(out, "#\n"); fprintf(out, "# Created: %s\n", QDateTime::currentDateTime().toString().toUtf8().constData()); fprintf(out, "# by: The Resource Compiler for PySide2 (Qt v%s)\n", QT_VERSION_STR); fprintf(out, "#\n"); fprintf(out, "# WARNING! All changes made in this file will be lost!\n"); fprintf(out, "\n"); fprintf(out, "from PySide2 import QtCore\n\n"); return true; } bool RCCResourceLibrary::writeDataBlobs(FILE *out) { fprintf(out, "qt_resource_data = %s\"\\\n", mPrefix); QStack pending; if (!root) return false; pending.push(root); qint64 offset = 0; while(!pending.isEmpty()) { RCCFileInfo *file = pending.pop(); for(QHash::iterator it = file->children.begin(); it != file->children.end(); ++it) { RCCFileInfo *child = it.value(); if(child->flags & RCCFileInfo::Directory) pending.push(child); else offset = child->writeDataBlob(out, offset); } } fprintf(out, "\"\n\n"); return true; } bool RCCResourceLibrary::writeDataNames(FILE *out) { fprintf(out, "qt_resource_name = %s\"\\\n", mPrefix); QHash names; QStack pending; if (!root) return false; pending.push(root); qint64 offset = 0; while(!pending.isEmpty()) { RCCFileInfo *file = pending.pop(); for(QHash::iterator it = file->children.begin(); it != file->children.end(); ++it) { RCCFileInfo *child = it.value(); if(child->flags & RCCFileInfo::Directory) pending.push(child); if(names.contains(child->name)) { child->nameOffset = names.value(child->name); } else { names.insert(child->name, offset); offset = child->writeDataName(out, offset); } } } fprintf(out, "\"\n\n"); return true; } static bool qt_rcc_compare_hash(const RCCFileInfo *left, const RCCFileInfo *right) { return qt_hash(left->name) < qt_hash(right->name); } bool RCCResourceLibrary::writeDataStructure(FILE *out) { fprintf(out, "qt_resource_struct = %s\"\\\n", mPrefix); QStack pending; if (!root) return false; //calculate the child offsets (flat) pending.push(root); int offset = 1; while(!pending.isEmpty()) { RCCFileInfo *file = pending.pop(); file->childOffset = offset; //sort by hash value for binary lookup QList children = file->children.values(); std::sort(children.begin(), children.end(), qt_rcc_compare_hash); //write out the actual data now for(int i = 0; i < children.size(); ++i) { RCCFileInfo *child = children.at(i); ++offset; if(child->flags & RCCFileInfo::Directory) pending.push(child); } } //write out the structure (ie iterate again!) pending.push(root); root->writeDataInfo(out); while(!pending.isEmpty()) { RCCFileInfo *file = pending.pop(); //sort by hash value for binary lookup QList children = file->children.values(); std::sort(children.begin(), children.end(), qt_rcc_compare_hash); //write out the actual data now for(int i = 0; i < children.size(); ++i) { RCCFileInfo *child = children.at(i); child->writeDataInfo(out); if(child->flags & RCCFileInfo::Directory) pending.push(child); } } fprintf(out, "\"\n\n"); return true; } bool RCCResourceLibrary::writeInitializer(FILE *out) { fprintf(out, "def qInitResources():\n"); fprintf(out, " QtCore.qRegisterResourceData(0x01, qt_resource_struct, qt_resource_name, qt_resource_data)\n"); fprintf(out, "\n"); fprintf(out, "def qCleanupResources():\n"); fprintf(out, " QtCore.qUnregisterResourceData(0x01, qt_resource_struct, qt_resource_name, qt_resource_data)\n"); fprintf(out, "\n"); fprintf(out, "qInitResources()\n"); return true; }