File indexing completed on 2024-05-12 05:44:35
0001 /*************************************************************************** 0002 * Copyright (C) 2005-2009 by Rajko Albrecht * 0003 * ral@alwins-world.de * 0004 * * 0005 * This program is free software; you can redistribute it and/or * 0006 * modify it under the terms of the GNU Lesser General Public * 0007 * License as published by the Free Software Foundation; either * 0008 * version 2.1 of the License, or (at your option) any later version. * 0009 * * 0010 * This program is distributed in the hope that it will be useful, * 0011 * but WITHOUT ANY WARRANTY; without even the implied warranty of * 0012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * 0013 * Lesser General Public License for more details. * 0014 * * 0015 * You should have received a copy of the GNU Lesser General Public * 0016 * License along with this program (in the file LGPL.txt); if not, * 0017 * write to the Free Software Foundation, Inc., 51 Franklin St, * 0018 * Fifth Floor, Boston, MA 02110-1301 USA * 0019 * * 0020 * This software consists of voluntary contributions made by many * 0021 * individuals. For exact contribution history, see the revision * 0022 * history and logs, available at https://commits.kde.org/kdesvn. * 0023 ***************************************************************************/ 0024 0025 /*************************************************************************** 0026 * Lot of code and ideas taken from KDE 4 KConfigGroup source code * 0027 * ksvn://anonsvn.kde.org/home/kde/branches/KDE/4.2/kdelibs/kdecore/config * 0028 ***************************************************************************/ 0029 #include "ReposConfig.h" 0030 #include "LogCache.h" 0031 #include "svnqt/path.h" 0032 0033 namespace svn 0034 { 0035 namespace cache 0036 { 0037 0038 class ReposConfigPrivate 0039 { 0040 public: 0041 static QByteArray serializeList(const QList<QByteArray> &list); 0042 static QStringList deserializeList(const QByteArray &data); 0043 static QVariant convertToQVariant(const QByteArray &value, const QVariant &aDefault); 0044 }; 0045 0046 static QVector<int> asIntVec(const QByteArray &string) 0047 { 0048 const QList<QByteArray> strList = string.split(','); 0049 QVector<int> vec; 0050 vec.reserve(strList.size()); 0051 for (const QByteArray &s : strList) 0052 vec << s.toInt(); 0053 return vec; 0054 } 0055 0056 QByteArray ReposConfigPrivate::serializeList(const QList<QByteArray> &list) 0057 { 0058 QByteArray value; 0059 0060 if (!list.isEmpty()) { 0061 QList<QByteArray>::ConstIterator it = list.constBegin(); 0062 const QList<QByteArray>::ConstIterator end = list.constEnd(); 0063 0064 value = QByteArray(*it).replace('\\', "\\\\").replace(',', "\\,"); 0065 0066 while (++it != end) { 0067 // In the loop, so it is not done when there is only one element. 0068 // Doing it repeatedly is a pretty cheap operation. 0069 value.reserve(4096); 0070 0071 value += ','; 0072 value += QByteArray(*it).replace('\\', "\\\\").replace(',', "\\,"); 0073 } 0074 0075 // To be able to distinguish an empty list from a list with one empty element. 0076 if (value.isEmpty()) { 0077 value = "\\0"; 0078 } 0079 } 0080 0081 return value; 0082 } 0083 0084 QStringList ReposConfigPrivate::deserializeList(const QByteArray &data) 0085 { 0086 if (data.isEmpty()) { 0087 return QStringList(); 0088 } 0089 if (data == "\\0") { 0090 return QStringList(QString()); 0091 } 0092 QStringList value; 0093 QString val; 0094 val.reserve(data.size()); 0095 bool quoted = false; 0096 for (int p = 0; p < data.length(); p++) { 0097 if (quoted) { 0098 val += QLatin1Char(data[p]); 0099 quoted = false; 0100 } else if (data[p] == '\\') { 0101 quoted = true; 0102 } else if (data[p] == ',') { 0103 val.squeeze(); // release any unused memory 0104 value.append(val); 0105 val.clear(); 0106 val.reserve(data.size() - p); 0107 } else { 0108 val += QLatin1Char(data[p]); 0109 } 0110 } 0111 value.append(val); 0112 return value; 0113 } 0114 0115 QVariant ReposConfigPrivate::convertToQVariant(const QByteArray &value, const QVariant &aDefault) 0116 { 0117 // if a type handler is added here you must add a QVConversions definition 0118 // to conversion_check.h, or ConversionCheck::to_QVariant will not allow 0119 // readEntry<T> to convert to QVariant. 0120 switch (aDefault.type()) { 0121 case QVariant::Invalid: 0122 return QVariant(); 0123 case QVariant::String: 0124 // this should return the raw string not the dollar expanded string. 0125 // imho if processed string is wanted should call 0126 // readEntry(key, QString) not readEntry(key, QVariant) 0127 return QString::fromUtf8(value); 0128 case QVariant::List: 0129 case QVariant::StringList: 0130 return deserializeList(value); 0131 case QVariant::ByteArray: 0132 return value; 0133 case QVariant::Bool: { 0134 const QByteArray lower(value.toLower()); 0135 if (lower == "false" || lower == "no" || lower == "off" || lower == "0") { 0136 return false; 0137 } 0138 return true; 0139 } 0140 case QVariant::Double: 0141 case QMetaType::Float: 0142 case QVariant::Int: 0143 case QVariant::UInt: 0144 case QVariant::LongLong: 0145 case QVariant::ULongLong: { 0146 QVariant tmp = value; 0147 if (!tmp.convert(aDefault.type())) { 0148 tmp = aDefault; 0149 } 0150 return tmp; 0151 } 0152 case QVariant::DateTime: { 0153 const QVector<int> list = asIntVec(value); 0154 if (list.count() != 6) { 0155 return aDefault; 0156 } 0157 const QDate date(list.at(0), list.at(1), list.at(2)); 0158 const QTime time(list.at(3), list.at(4), list.at(5)); 0159 const QDateTime dt(date, time); 0160 if (!dt.isValid()) { 0161 return aDefault; 0162 } 0163 return dt; 0164 } 0165 case QVariant::Date: { 0166 QVector<int> list = asIntVec(value); 0167 if (list.count() == 6) { 0168 list = list.mid(0, 3); // don't break config files that stored QDate as QDateTime 0169 } 0170 if (list.count() != 3) { 0171 return aDefault; 0172 } 0173 const QDate date(list.at(0), list.at(1), list.at(2)); 0174 if (!date.isValid()) { 0175 return aDefault; 0176 } 0177 return date; 0178 } 0179 default: 0180 break; 0181 } 0182 0183 qWarning("unhandled type %s", aDefault.typeName()); 0184 return QVariant(); 0185 } 0186 0187 ReposConfig *ReposConfig::mSelf = nullptr; 0188 0189 ReposConfig *ReposConfig::self() 0190 { 0191 if (!mSelf) { 0192 mSelf = new ReposConfig(); 0193 } 0194 return mSelf; 0195 } 0196 0197 ReposConfig::ReposConfig() 0198 { 0199 } 0200 0201 void ReposConfig::setValue(const QString &repository, const QString &key, const QVariant &value) 0202 { 0203 QByteArray data; 0204 switch (value.type()) { 0205 case QVariant::Invalid: 0206 break; 0207 case QVariant::ByteArray: 0208 data = value.toByteArray(); 0209 break; 0210 case QVariant::String: 0211 case QVariant::Int: 0212 case QVariant::UInt: 0213 case QVariant::Double: 0214 case QMetaType::Float: 0215 case QVariant::Bool: 0216 case QVariant::LongLong: 0217 case QVariant::ULongLong: 0218 data = value.toString().toUtf8(); 0219 break; 0220 case QVariant::List: 0221 case QVariant::StringList: 0222 setValue(repository, key, value.toList()); 0223 return; 0224 case QVariant::Date: { 0225 QVariantList list; 0226 const QDate date = value.toDate(); 0227 0228 list.insert(0, date.year()); 0229 list.insert(1, date.month()); 0230 list.insert(2, date.day()); 0231 0232 setValue(repository, key, list); 0233 return; 0234 } 0235 case QVariant::DateTime: { 0236 QVariantList list; 0237 const QDateTime rDateTime = value.toDateTime(); 0238 0239 const QTime time = rDateTime.time(); 0240 const QDate date = rDateTime.date(); 0241 0242 list.insert(0, date.year()); 0243 list.insert(1, date.month()); 0244 list.insert(2, date.day()); 0245 0246 list.insert(3, time.hour()); 0247 list.insert(4, time.minute()); 0248 list.insert(5, time.second()); 0249 0250 setValue(repository, key, list); 0251 return; 0252 } 0253 0254 default: 0255 qWarning("ReposConfig: Unhandled type"); 0256 return; 0257 } 0258 0259 svn::cache::LogCache::self()->setRepositoryParameter(svn::Path(repository), key, data); 0260 } 0261 0262 void ReposConfig::eraseValue(const QString &repository, const QString &key) 0263 { 0264 svn::cache::LogCache::self()->setRepositoryParameter(svn::Path(repository), key, QVariant()); 0265 } 0266 0267 void ReposConfig::setValue(const QString &repository, const QString &key, const QVariantList &list) 0268 { 0269 QList<QByteArray> data; 0270 0271 for (const QVariant &v : list) { 0272 if (v.type() == QVariant::ByteArray) { 0273 data << v.toByteArray(); 0274 } else { 0275 data << v.toString().toUtf8(); 0276 } 0277 } 0278 0279 setValue(repository, key, ReposConfigPrivate::serializeList(data)); 0280 } 0281 0282 void ReposConfig::setValue(const QString &repository, const QString &key, const QStringList &list) 0283 { 0284 QList<QByteArray> balist; 0285 for (const QString &entry : list) 0286 balist.append(entry.toUtf8()); 0287 setValue(repository, key, ReposConfigPrivate::serializeList(balist)); 0288 } 0289 0290 void ReposConfig::setValue(const QString &repository, const QString &key, const QString &value) 0291 { 0292 setValue(repository, key, value.toUtf8()); 0293 } 0294 0295 QVariant ReposConfig::readEntry(const QString &repository, const QString &key, const QVariant &aDefault) 0296 { 0297 QVariant v = svn::cache::LogCache::self()->getRepositoryParameter(svn::Path(repository), key); 0298 if (!v.isValid()) { 0299 return aDefault; 0300 } 0301 return ReposConfigPrivate::convertToQVariant(v.toByteArray(), aDefault); 0302 } 0303 0304 int ReposConfig::readEntry(const QString &repository, const QString &key, int aDefault) 0305 { 0306 return readEntry(repository, key, QVariant(aDefault)).toInt(); 0307 } 0308 0309 bool ReposConfig::readEntry(const QString &repository, const QString &key, bool aDefault) 0310 { 0311 return readEntry(repository, key, QVariant(aDefault)).toBool(); 0312 } 0313 0314 QStringList ReposConfig::readEntry(const QString &repository, const QString &key, const QStringList &aDefault) 0315 { 0316 return readEntry(repository, key, QVariant(aDefault)).toStringList(); 0317 } 0318 0319 } // namespace cache 0320 } // namespace svn