00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024 #include <qglobal.h>
00025 #include <QObject>
00026 #include <QByteArray>
00027 #include <QString>
00028 #include <QUrl>
00029 #include <QTextCodec>
00030 #include <QDateTime>
00031 #include <QRect>
00032 #include <QIcon>
00033 #include <QColor>
00034 #include <QBrush>
00035 #include <QDomDocument>
00036 #include <QTextFormat>
00037
00038 #include "klfdefs.h"
00039 #include "klfpobj.h"
00040 #include "klfutil.h"
00041 #include "klfdatautil.h"
00042
00043 #include "klfdatautil_p.h"
00044
00045
00046 static inline bool klf_is_hex_char(char c)
00047 {
00048 return ('0' <= c && c <= '9') || ('a' <= c && c <= 'f') || ('A' <= c && c <= 'F');
00049 }
00050
00051
00052
00053 #define KLF_BRUSH_STYLE(sty) \
00054 { Qt::sty##Pattern, #sty }
00055
00056 static struct { int brushStyle; const char *style; } klf_brush_styles[] = {
00057 { Qt::NoBrush, "NoBrush" },
00058 { Qt::SolidPattern, "" },
00059 { Qt::SolidPattern, "Solid" },
00060 KLF_BRUSH_STYLE(Dense1),
00061 KLF_BRUSH_STYLE(Dense2),
00062 KLF_BRUSH_STYLE(Dense3),
00063 KLF_BRUSH_STYLE(Dense4),
00064 KLF_BRUSH_STYLE(Dense5),
00065 KLF_BRUSH_STYLE(Dense6),
00066 KLF_BRUSH_STYLE(Dense7),
00067 KLF_BRUSH_STYLE(Hor),
00068 KLF_BRUSH_STYLE(Ver),
00069 KLF_BRUSH_STYLE(Cross),
00070 KLF_BRUSH_STYLE(BDiag),
00071 KLF_BRUSH_STYLE(FDiag),
00072 KLF_BRUSH_STYLE(DiagCross),
00073 { -1, NULL }
00074 };
00075
00076
00077
00078 #define KLF_TEXT_FORMAT_FORMAT(fmt) \
00079 { QTextFormat::fmt##Format, #fmt "Format" }
00080
00081 static struct { int formatId; const char *format; } klf_text_format_formats[] = {
00082 KLF_TEXT_FORMAT_FORMAT(Invalid),
00083 KLF_TEXT_FORMAT_FORMAT(Block),
00084 KLF_TEXT_FORMAT_FORMAT(Char),
00085 KLF_TEXT_FORMAT_FORMAT(List),
00086 KLF_TEXT_FORMAT_FORMAT(Table),
00087 KLF_TEXT_FORMAT_FORMAT(Frame),
00088 KLF_TEXT_FORMAT_FORMAT(User),
00089 { -100, NULL }
00090 };
00091
00092
00093 #define KLF_TEXT_FORMAT_PROP(p, type) \
00094 { QTextFormat::p, #p, #type }
00095
00096 static struct { int propId; const char *key; const char *type; } klf_text_format_props[] = {
00097 KLF_TEXT_FORMAT_PROP(ForegroundBrush, QBrush),
00098 KLF_TEXT_FORMAT_PROP(BackgroundBrush, QBrush),
00099 KLF_TEXT_FORMAT_PROP(FontFamily, QString),
00100 KLF_TEXT_FORMAT_PROP(FontPointSize, int),
00101 KLF_TEXT_FORMAT_PROP(FontWeight, int),
00102 KLF_TEXT_FORMAT_PROP(FontItalic, bool),
00103 KLF_TEXT_FORMAT_PROP(TextUnderlineStyle, int),
00104
00105 { QTextFormat::ForegroundBrush, "FG", "QBrush" },
00106 { QTextFormat::BackgroundBrush, "BG", "QBrush" },
00107
00108 { -1, NULL, NULL }
00109 };
00110
00111 static struct { const char * keyword; int propId; QVariant fixed_value; } klf_text_format_keywords[] = {
00112 { "NORMALWEIGHT", QTextFormat::FontWeight, QVariant(QFont::Normal) },
00113 { "BOLD", QTextFormat::FontWeight, QVariant(QFont::Bold) },
00114 { "NORMALSTYLE", QTextFormat::FontItalic, QVariant(false) },
00115 { "ITALIC", QTextFormat::FontItalic, QVariant(true) },
00116
00117 { NULL, -1, QVariant() }
00118 };
00119
00120
00121
00122
00123 KLF_EXPORT QByteArray klfDataToEscaped(const QByteArray& value_ba, char escapechar)
00124 {
00125 KLF_DEBUG_BLOCK(KLF_FUNC_NAME) ;
00126
00127 klfDbg("len="<<value_ba.size()<<" , data=`"<<value_ba<<"' escapechar="<<klfFmtCC("'\\x%02X'", (int)escapechar));
00128
00129 QByteArray data;
00130 int k;
00131 for (k = 0; k < value_ba.size(); ++k) {
00132
00133 if (value_ba[k] >= 32 && value_ba[k] <= 126 && value_ba[k] != escapechar) {
00134
00135 data += value_ba[k];
00136 } else if (value_ba[k] == escapechar) {
00137
00138 data += escapechar;
00139 data += escapechar;
00140 } else {
00141 data += escapechar;
00142 data += QString("x%1").arg((uint)(uchar)value_ba[k], 2, 16, QChar('0')).toLatin1();
00143 }
00144 }
00145 return data;
00146 }
00147
00148 KLF_EXPORT QByteArray klfEscapedToData(const QByteArray& data, char escapechar)
00149 {
00150 KLF_DEBUG_BLOCK(KLF_FUNC_NAME) ;
00151 klfDbg("data=`"<<data<<"', escapechar="<<klfFmtCC("'\\x%02X'", (int)escapechar));
00152
00153 bool convertOk;
00154 int k;
00155 QByteArray value_ba;
00156 k = 0;
00157 while (k < data.size()) {
00158 if (data[k] != escapechar) {
00159 value_ba += data[k];
00160 ++k;
00161 continue;
00162 }
00163
00164 if (data[k] == escapechar && k+1 >= data.size()) {
00165 value_ba += escapechar;
00166 ++k;
00167 continue;
00168 }
00169
00170 if (data[k+1] != 'x') {
00171
00172
00173 if (data[k+1] == 'n')
00174 value_ba += '\n';
00175 if (data[k+1] == '0')
00176 value_ba += '\0';
00177 if (data[k+1] == 't')
00178 value_ba += '\t';
00179 if (data[k+1] == 'a')
00180 value_ba += '\a';
00181 if (data[k+1] == 'b')
00182 value_ba += '\b';
00183 if (data[k+1] == 'f')
00184 value_ba += '\f';
00185 if (data[k+1] == 'r')
00186 value_ba += '\r';
00187 if (data[k+1] == 'v')
00188 value_ba += '\v';
00189 else
00190 value_ba += data[k+1];
00191 k += 2;
00192 continue;
00193 }
00194
00195 if (k+3 >= data.size() || !klf_is_hex_char(data[k+2]) || !klf_is_hex_char(data[k+3])) {
00196
00197 klfDbg("ignoring invalid escape sequence `"<<data.mid(k,4)<<"'") ;
00198 value_ba += data[k];
00199 ++k;
00200 continue;
00201 }
00202
00203 uchar cval = data.mid(k+2, 2).toUInt(&convertOk, 16);
00204 value_ba += (char)cval;
00205 k += 4;
00206 }
00207 return value_ba;
00208 }
00209
00210
00211 static QByteArray encaps_list(const QList<QByteArray>& list)
00212 {
00213 QByteArray data = "[";
00214 for (int k = 0; k < list.size(); ++k) {
00215 QByteArray d = list[k];
00216 d.replace("\\", "\\\\");
00217 d.replace(";", "\\;");
00218 d.replace("[", "\\[");
00219 d.replace("]", "\\]");
00220 data += d;
00221 if (k < list.size()-1)
00222 data += ";";
00223 }
00224 data += "]";
00225 return data;
00226 }
00227
00228
00229 static QByteArray encaps_map(const QList<QPair<QByteArray,QByteArray> >& sections, bool ignore_empty_values = false)
00230 {
00231 QByteArray data;
00232 data = "{";
00233 bool first_item = true;
00234 int k;
00235 for (k = 0; k < sections.size(); ++k) {
00236 if (!first_item) {
00237 data += ";";
00238 }
00239 first_item = false;
00240 QByteArray key = sections[k].first;
00241 QByteArray val = sections[k].second;
00242
00243 key.replace("\\", "\\\\");
00244 key.replace(";", "\\;");
00245 key.replace("=", "\\=");
00246 val.replace("\\", "\\\\");
00247 val.replace(";", "\\;");
00248 if (val.isEmpty() && ignore_empty_values)
00249 data += key;
00250 else
00251 data += key + "=" + val;
00252 }
00253 data += "}";
00254 return data;
00255 }
00256
00257
00258 static QList<QByteArray> decaps_list(const QByteArray& ba_data)
00259 {
00260 klfDbg("decaps_list, data="<<ba_data);
00261 QByteArray data = ba_data.trimmed();
00262 if (data[0] != '[')
00263 return QList<QByteArray>();
00264
00265 QList<QByteArray> sections;
00266 QByteArray chunk;
00267
00268
00269 int k = 1;
00270 while (k < data.size()) {
00271 if (data[k] == ';') {
00272
00273 sections.append(chunk);
00274
00275 chunk = QByteArray();
00276 ++k;
00277 }
00278 if (data[k] == '\\') {
00279 if (k+1 < data.size()) {
00280 chunk += data[k+1];
00281 k += 2;
00282 } else {
00283 chunk += data[k];
00284 ++k;
00285 }
00286 continue;
00287 }
00288 if (data[k] == ']') {
00289
00290
00291 if (!chunk.isEmpty())
00292 sections.append(chunk);
00293 chunk = "";
00294 break;
00295 }
00296
00297 chunk += data[k];
00298 ++k;
00299 }
00300 if (!chunk.isEmpty()) {
00301
00302 sections.append(chunk);
00303 }
00304
00305 klfDbg("sections="<<sections);
00306
00307 return sections;
00308 }
00309
00310 static QList<QPair<QByteArray,QByteArray> > decaps_map(const QByteArray& ba_data, bool allow_empty_values = false)
00311 {
00312 QByteArray data = ba_data.trimmed();
00313 if (data[0] != '{')
00314 return QList<QPair<QByteArray,QByteArray> >();
00315 if ( !data.contains('}') )
00316 data += '}';
00317
00318 QList<QPair<QByteArray, QByteArray> > sections;
00319 QByteArray chunkkey;
00320 QByteArray chunkvalue;
00321 QByteArray *curChunk = &chunkkey;
00322
00323
00324 int k = 1;
00325 while (k < data.size()) {
00326 if (data[k] == ';') {
00327
00328 if (!allow_empty_values && curChunk == &chunkkey)
00329 qWarning()<<KLF_FUNC_NAME<<": no '=' in pair at pos "<<k<<" in string: "<<data<<"";
00330 sections << QPair<QByteArray,QByteArray>(chunkkey, chunkvalue);
00331
00332 chunkkey = QByteArray();
00333 chunkvalue = QByteArray();
00334 curChunk = &chunkkey;
00335 ++k;
00336 }
00337 if (data[k] == '\\') {
00338 if (k+1 < data.size()) {
00339 *curChunk += data[k+1];
00340 k += 2;
00341 } else {
00342 *curChunk += data[k];
00343 ++k;
00344 }
00345 continue;
00346 }
00347 if (curChunk == &chunkkey && data[k] == '=') {
00348
00349 curChunk = &chunkvalue;
00350 ++k;
00351 continue;
00352 }
00353 if (data[k] == '}') {
00354
00355
00356 if (!allow_empty_values && curChunk == &chunkkey)
00357 qWarning()<<"klfLoadVariantFromText: no '=' in pair at pos "<<k<<" in string: "<<data<<"";
00358 sections << QPair<QByteArray,QByteArray>(chunkkey, chunkvalue);
00359 break;
00360 }
00361
00362 *curChunk += data[k];
00363 ++k;
00364 }
00365 return sections;
00366 }
00367
00368
00369
00370
00371 static QDomElement make_xml_wrapper(const QString& rootname)
00372 {
00373 QDomDocument xmldoc(rootname);
00374 QDomElement root = xmldoc.createElement(rootname);
00375 xmldoc.appendChild(root);
00376 return root;
00377 }
00378
00379 static QDomElement parse_xml_wrapper(const QByteArray& xmldata, const QString& shouldBeRootName)
00380 {
00381 QDomDocument xmldoc(shouldBeRootName);
00382 bool result = xmldoc.setContent(xmldata);
00383 KLF_ASSERT_CONDITION(result, "Failed to read wrapper XML for klfLoadVariantFromText()",
00384 return QDomElement() ) ;
00385
00386 QDomElement el = xmldoc.documentElement();
00387 KLF_ASSERT_CONDITION( el.nodeName() == shouldBeRootName,
00388 "Wrong XML root node in wrapper for klfLoadVariantFromText(): "
00389 <<el.nodeName() , ; ) ;
00390 return el;
00391 }
00392
00393 KLF_EXPORT QByteArray klfSaveVariantToText(const QVariant& value, bool saveListAndMapsAsXML, QByteArray *savedType,
00394 QByteArray *savedListOrMapType)
00395 {
00396 QTextCodec *tc = QTextCodec::codecForLocale();
00397
00398 QString s;
00399 QByteArray data;
00400 int k;
00401
00402 if (!value.isValid() || value.isNull()) {
00403 klfDbg("saving null variant.");
00404 if (savedType != NULL)
00405 *savedType = QByteArray();
00406 return QByteArray();
00407 }
00408
00409
00410 switch ((int)value.type()) {
00411 case QMetaType::Bool:
00412 data = value.toBool() ? "true" : "false";
00413 break;
00414 case QMetaType::Int:
00415 case QMetaType::UInt:
00416 case QMetaType::Short:
00417 case QMetaType::UShort:
00418 case QMetaType::Long:
00419 case QMetaType::ULong:
00420 case QMetaType::LongLong:
00421 case QMetaType::ULongLong:
00422 case QMetaType::Double:
00423 data = value.toString().toLocal8Bit();
00424 break;
00425 case QMetaType::Char:
00426 {
00427 char c = value.value<char>();
00428 if (c >= 32 && c <= 126 && c != '\\') {
00429 data = QByteArray(1, c);
00430 } else if (c == '\\') {
00431 data = "\\\\";
00432 } else {
00433 data = "\\" + QString::number(c, 16).toUpper().toLatin1();
00434 }
00435 break;
00436 }
00437 case QMetaType::QChar:
00438 {
00439 QChar c = value.toChar();
00440 if (tc->canEncode(c) && c != '\\') {
00441 data = tc->fromUnicode(QString(c));
00442 } else if (c == '\\') {
00443 data = "\\\\";
00444 } else {
00445 data = "\\" + QString::number(c.unicode(), 16).toUpper().toLatin1();
00446 }
00447 break;
00448 }
00449 case QMetaType::QString:
00450 {
00451 s = value.toString();
00452 if (tc->canEncode(s)) {
00453
00454 data = tc->fromUnicode(s.replace("\\", "\\\\"));
00455 } else {
00456
00457 data = QByteArray("");
00458 for (k = 0; k < s.length(); ++k) {
00459 if (tc->canEncode(s[k])) {
00460 data += tc->fromUnicode(s.mid(k,1));
00461 } else {
00462 data += QString("\\x%1").arg((uint)s[k].unicode(), 4, 16, QChar('0')).toLatin1();
00463 }
00464 }
00465 }
00466 break;
00467 }
00468 case QMetaType::QStringList:
00469 {
00470 const QStringList list = value.toStringList();
00471 QList<QByteArray> sections;
00472 int k;
00473 for (k = 0; k < list.size(); ++k) {
00474 sections.append(klfDataToEscaped(list[k].toUtf8()));
00475 }
00476 data = encaps_list(sections);
00477 break;
00478 }
00479 case QMetaType::QUrl:
00480 data = value.toUrl().toEncoded(); break;
00481 case QMetaType::QByteArray:
00482 {
00483 data = klfDataToEscaped(value.value<QByteArray>());
00484 break;
00485 }
00486 case QMetaType::QDate:
00487 data = value.value<QDate>().toString(Qt::SystemLocaleShortDate).toLocal8Bit(); break;
00488 case QMetaType::QTime:
00489 data = value.value<QTime>().toString(Qt::SystemLocaleShortDate).toLocal8Bit(); break;
00490 case QMetaType::QDateTime:
00491 data = value.value<QDateTime>().toString(Qt::SystemLocaleShortDate).toLocal8Bit(); break;
00492 case QMetaType::QSize:
00493 { QSize sz = value.toSize();
00494 data = QString("(%1 %2)").arg(sz.width()).arg(sz.height()).toLatin1();
00495 break;
00496 }
00497 case QMetaType::QPoint:
00498 { QPoint pt = value.toPoint();
00499 data = QString("(%1 %2)").arg(pt.x()).arg(pt.y()).toLatin1();
00500 break;
00501 }
00502 case QMetaType::QRect:
00503 { QRect r = value.toRect();
00504 data = QString("(%1 %2 %3x%4)").arg(r.left()).arg(r.top()).arg(r.width()).arg(r.height()).toLatin1();
00505 break;
00506 }
00507 case QMetaType::QColor:
00508 { QColor c = value.value<QColor>();
00509 klfDbg("Saving color "<<c<<": alpha="<<c.alpha()) ;
00510 if (c.alpha() == 255)
00511 data = QString("(%1 %2 %3)").arg(c.red()).arg(c.green()).arg(c.blue()).toLatin1();
00512 else
00513 data = QString("(%1 %2 %3 %4)").arg(c.red()).arg(c.green()).arg(c.blue()).arg(c.alpha()).toLatin1();
00514 break;
00515 }
00516 case QMetaType::QFont:
00517 { QFont f = value.value<QFont>();
00518 data = "'" + f.family().toLocal8Bit() + "'";
00519 switch (f.weight()) {
00520 case QFont::Light: data += " Light"; break;
00521 case QFont::Normal: break;
00522 case QFont::DemiBold: data += " DemiBold"; break;
00523 case QFont::Bold: data += " Bold"; break;
00524 case QFont::Black: data += " Black"; break;
00525 default: data += QString(" Wgt=%1").arg(f.weight()); break;
00526 }
00527 switch (f.style()) {
00528 case QFont::StyleNormal: break;
00529 case QFont::StyleItalic: data += " Italic"; break;
00530 case QFont::StyleOblique: data += " Oblique"; break;
00531 default: break;
00532 }
00533
00534 data += " " + QString::number(QFontInfo(f).pointSize()).toLatin1();
00535 break;
00536 }
00537 case QMetaType::QBrush:
00538 { QBrush b = value.value<QBrush>();
00539 if (!b.matrix().isIdentity())
00540 break;
00541 int bstyle = b.style();
00542
00543 int k;
00544 bool found_style = false;
00545 for (k = 0; klf_brush_styles[k].brushStyle >= 0 && klf_brush_styles[k].style != NULL; ++k) {
00546 if (klf_brush_styles[k].brushStyle == bstyle) {
00547 found_style = true;
00548 break;
00549 }
00550 }
00551 if (!found_style) {
00552
00553 break;
00554 }
00555
00556 data = "(";
00557 data += klf_brush_styles[k].style;
00558 if (strlen(klf_brush_styles[k].style))
00559 data += " ";
00560 QColor c = b.color();
00561 data += QString("%1 %2 %3 %4").arg(c.red()).arg(c.green()).arg(c.blue()).arg(c.alpha());
00562 data += ")";
00563 break;
00564 }
00565 case QMetaType::QTextFormat:
00566 {
00567 QTextFormat tf = value.value<QTextFormat>();
00568 const QMap<int,QVariant> props = tf.properties();
00569
00570 QList<QPair<QByteArray,QByteArray> > sections;
00571
00572
00573 int k;
00574 for (k = 0; klf_text_format_formats[k].format != NULL; ++k)
00575 if (klf_text_format_formats[k].formatId == tf.type())
00576 break;
00577 if (klf_text_format_formats[k].format == NULL) {
00578
00579
00580 data = QByteArray();
00581 break;
00582 }
00583
00584 sections << QPair<QByteArray,QByteArray>(klf_text_format_formats[k].format, QByteArray());
00585
00586 QMap<int,QVariant>::const_iterator it;
00587 for (it = props.begin(); it != props.end(); ++it) {
00588 int propId = it.key();
00589 QVariant propValue = it.value();
00590
00591
00592
00593 for (k = 0; klf_text_format_keywords[k].keyword != NULL; ++k)
00594 if (klf_text_format_keywords[k].propId == propId &&
00595 klf_text_format_keywords[k].fixed_value == propValue)
00596 break;
00597 const char *kw = klf_text_format_keywords[k].keyword;
00598 if (kw != NULL) {
00599
00600 QByteArray key = kw;
00601 sections << QPair<QByteArray,QByteArray>(kw, QByteArray());
00602 continue;
00603 }
00604
00605
00606 for (k = 0; klf_text_format_props[k].key != NULL; ++k)
00607 if (klf_text_format_props[k].propId == propId)
00608 break;
00609 if (klf_text_format_props[k].key != NULL) {
00610
00611 if ( !strcmp(klf_text_format_props[k].type, propValue.typeName()) ) {
00612
00613 QByteArray key = klf_text_format_props[k].key;
00614 QByteArray value = klfSaveVariantToText(propValue, true);
00615 sections << QPair<QByteArray,QByteArray>(key, value);
00616 continue;
00617 } else {
00618 qWarning()<<KLF_FUNC_NAME<<": QTextFormat property "<<klf_text_format_props[k].key
00619 <<" 's type is `"<<propValue.typeName()<<"' which is not the known type: "
00620 <<klf_text_format_props[k].type;
00621 }
00622 }
00623
00624
00625 QByteArray key = QString::number(propId).toLatin1();
00626 QByteArray value;
00627 value = QByteArray("[")+propValue.typeName()+"]"+klfSaveVariantToText(propValue, true);
00628 }
00629 data = encaps_map(sections, true);
00630 break;
00631 }
00632 case QMetaType::QVariantList:
00633 {
00634 klfDbg("Saving list!") ;
00635 const QList<QVariant>& list = value.toList();
00636 if (saveListAndMapsAsXML) {
00637 QDomElement el = make_xml_wrapper("variant-list");
00638 el = klfSaveVariantListToXML(list, el);
00639 data = el.ownerDocument().toByteArray(-1);
00640 } else {
00641 QList<QByteArray> sections;
00642 QByteArray innertype;
00643 for (k = 0; k < list.size(); ++k) {
00644 if (k == 0)
00645 innertype = list[k].typeName();
00646 if (innertype != list[k].typeName()) {
00647 klfWarning("saving list: not all inner QVariants have same type. Found a "<<innertype
00648 <<" along with a "<<list[k].typeName());
00649 }
00650 sections << klfSaveVariantToText(list[k]);
00651 }
00652 if (savedListOrMapType != NULL)
00653 *savedListOrMapType = innertype;
00654 data = encaps_list(sections);
00655 }
00656 break;
00657 }
00658 case QMetaType::QVariantMap:
00659 {
00660 klfDbg("Saving Map!") ;
00661 const QMap<QString,QVariant>& map = value.toMap();
00662 if (saveListAndMapsAsXML) {
00663 QDomElement el = make_xml_wrapper("variant-map");
00664 klfDbg("map="<<map) ;
00665 el = klfSaveVariantMapToXML(map, el);
00666 data = el.ownerDocument().toByteArray(-1);
00667 klfDbg("saved XML: data="<<data) ;
00668 } else {
00669 QList<QPair<QByteArray, QByteArray> > sections;
00670 QByteArray innertype, thistype;
00671 bool firstround = true;
00672 for (QMap<QString,QVariant>::const_iterator it = map.begin(); it != map.end(); ++it) {
00673 QByteArray k = klfSaveVariantToText(QVariant(it.key()));
00674 QByteArray v = klfSaveVariantToText(it.value());
00675 thistype = it.value().typeName();
00676 if (firstround) {
00677 innertype = thistype;
00678 firstround = false;
00679 }
00680 if (innertype != thistype) {
00681 klfWarning("saving map: not all inner QVariants have same type. Found a "<<innertype
00682 <<" along with a "<<thistype);
00683 }
00684 sections << QPair<QByteArray,QByteArray>(k, v);
00685 }
00686 if (savedListOrMapType != NULL)
00687 *savedListOrMapType = innertype;
00688 data = encaps_map(sections);
00689 }
00690 break;
00691 }
00692 default:
00693 break;
00694 };
00695
00696
00697
00698 QByteArray typeName = value.typeName();
00699
00700 QByteArray typeSpec = QByteArray();
00701 if (KLFSpecifyableRegisteredType::isRegistered(typeName)) {
00702 KLFSpecifyableType * t =
00703 const_cast<KLFSpecifyableType*>(static_cast<const KLFSpecifyableType*>(value.data()));
00704
00705 typeSpec = t->specification();
00706 if (savedType != NULL) {
00707 *savedType = typeName + "/" + typeSpec;
00708 }
00709 } else {
00710 if (savedType != NULL)
00711 *savedType = typeName;
00712 }
00713
00714 if (typeName == "KLFEnumType") {
00715
00716 KLFEnumType e = value.value<KLFEnumType>();
00717 data = QByteArray::number(e.value());
00718 }
00719
00720 if (KLFPObjRegisteredType::isRegistered(typeName)) {
00721 KLFAbstractPropertizedObject * obj =
00722 const_cast<KLFAbstractPropertizedObject*>(static_cast<const KLFAbstractPropertizedObject*>(value.data()));
00723
00724 bool hasfixedtypes = obj->hasFixedTypes();
00725
00726 QVariantMap props = obj->allProperties();
00727 if (!hasfixedtypes) {
00728 return klfSaveVariantToText(props, true);
00729 }
00730
00731 QVariantMap propstexts;
00732 for (QVariantMap::const_iterator it = props.begin(); it != props.end(); ++it) {
00733 propstexts[it.key()] = klfSaveVariantToText(it.value(), true);
00734 klfDbg("Saving property "<<it.key()<<" to text, value = "<<propstexts[it.key()]) ;
00735 }
00736 props = propstexts;
00737 return klfSaveVariantToText(props, false);
00738
00739
00740 }
00741
00742
00743
00744 if (data.startsWith("[QVariant]") || data.startsWith("\\")) {
00745 data = "\\"+data;
00746 }
00747
00748
00749
00750
00751 if (data.isNull()) {
00752 QByteArray vdata;
00753 {
00754 QDataStream stream(&vdata, QIODevice::WriteOnly);
00755 stream.setVersion(QDataStream::Qt_4_4);
00756 stream << value;
00757 }
00758 QByteArray vdata_esc = klfDataToEscaped(vdata);
00759 qDebug("\tVariant value is %s, len=%d", vdata.constData(), vdata.size());
00760 data = QByteArray("[QVariant]");
00761 data += vdata_esc;
00762 }
00763
00764 klfDbg( "klfSaveVariantToText("<<value<<"): saved data (len="<<data.size()<<") : "<<data ) ;
00765 return data;
00766 }
00767
00768
00769
00770
00771 KLF_EXPORT QVariant klfLoadVariantFromText(const QByteArray& stringdata, const char * dataTypeName,
00772 const char *listOrMapDataTypeName)
00773 {
00774 KLF_DEBUG_TIME_BLOCK(KLF_FUNC_NAME) ;
00775
00776
00777
00778 #define RX_INT "-?\\d+"
00779 #define RX_COORD_SEP "\\s*(?:[,;]|\\s)\\s*" // note: non-capturing parenthesis
00780 #define RX_SIZE_SEP "\\s*(?:[,;x]|\\s)\\s*" // note: non-capturing parenthesis
00781
00782
00783 QRegExp v2rx("^\\(?\\s*(" RX_INT ")" RX_COORD_SEP "(" RX_INT ")\\s*\\)?");
00784 static const int V2RX_X = 1, V2RX_Y = 2;
00785
00786
00787 QRegExp szrx("^\\(?\\s*(" RX_INT ")" RX_SIZE_SEP "(" RX_INT ")\\s*\\)?");
00788 static const int SZRX_W = 1, SZRX_H = 2;
00789
00790
00791 QRegExp rectrx("^\\(?\\s*(" RX_INT ")" RX_COORD_SEP "(" RX_INT ")"
00792
00793 "(?:" RX_COORD_SEP "|\\s*([+])\\s*)"
00794
00795 "(" RX_INT ")(?:" RX_COORD_SEP "|\\s*([x])\\s*)(" RX_INT ")\\s*\\)?");
00796 static const int RECTRX_X1 = 1, RECTRX_Y1 = 2, RECTRX_MIDDLESEP_PLUS = 3,
00797 RECTRX_X2orW = 4, RECTRX_LASTSEP_X = 5, RECTRX_Y2orH = 6;
00798
00799
00800 QRegExp colrx("^(?:rgba?)?\\(?\\s*(\\d+)" RX_COORD_SEP "(\\d+)" RX_COORD_SEP "(\\d+)"
00801
00802 "(" RX_COORD_SEP "(\\d+))?\\s*\\)?", Qt::CaseInsensitive);
00803 static const int COLRX_R = 1, COLRX_G = 2, COLRX_B = 3, COLRX_MAYBE_ALPHA = 4, COLRX_A = 5;
00804
00805
00806 QRegExp brushrx("^(?:q?brush)?\\(?\\s*(?:([A-Za-z_]\\w*)" RX_COORD_SEP ")?(\\d+)" RX_COORD_SEP "(\\d+)"
00807
00808 RX_COORD_SEP "(\\d+)" "(" RX_COORD_SEP "(\\d+))?" "\\s*\\)?", Qt::CaseInsensitive);
00809 static const int BRUSHRX_STYLE = 1, BRUSHRX_R = 2, BRUSHRX_G = 3, BRUSHRX_B = 4, BRUSHRX_A = 6;
00810
00811
00812 QRegExp fontrx("^([\"']?)\\s*(.+)\\s*\\1"
00813
00814 "(\\s+(Light|Normal|DemiBold|Bold|Black|Wgt\\s*=\\s*(\\d+)))?"
00815
00816 "(\\s+(Normal|Italic|Oblique))?(\\s+(\\d+))?$");
00817 fontrx.setMinimal(true);
00818 static const int FONTRX_FAMILY = 2, FONTRX_WEIGHT_TEXT = 4, FONTRX_WEIGHT_VALUE = 5,
00819 FONTRX_STYLE_TEXT = 7, FONTRX_POINTSIZE = 9;
00820
00821
00822
00823
00824 QByteArray data = stringdata;
00825
00826
00827 if (dataTypeName == NULL || *dataTypeName == 0) {
00828 klfDbg("loading null variant.");
00829 return QVariant();
00830 }
00831
00832 QVariant value;
00833 if (data.startsWith("[QVariant]")) {
00834 QByteArray vdata_esc = data.mid(strlen("[QVariant]"));
00835 QByteArray vdata = klfEscapedToData(vdata_esc);
00836 klfDbg( "\tAbout to read raw variant from datastr="<<vdata_esc<<", ie. from data len="<<vdata.size() ) ;
00837 QDataStream stream(vdata);
00838 stream.setVersion(QDataStream::Qt_4_4);
00839 stream >> value;
00840 return value;
00841 }
00842 if (data.startsWith("\\"))
00843 data = data.mid(1);
00844
00845 klfDbg( "Will start loading a `"<<dataTypeName<<"' from data (len="<<data.size()<<") : "<<data ) ;
00846
00847
00848 QByteArray tname = dataTypeName;
00849
00850 int idslash;
00851 QByteArray tspecification = QByteArray();
00852 if ((idslash = tname.indexOf('/')) >= 0) {
00853 tspecification = tname.mid(idslash+1);
00854 tname = tname.left(idslash);
00855 klfDbg("tspecification="<<tspecification<<", tname="<<tname) ;
00856 }
00857
00858
00859 int type = QMetaType::type(tname);
00860 klfDbg("Type is "<<type) ;
00861 bool convertOk = false;
00862 int k;
00863 switch (type) {
00864 case QMetaType::Bool:
00865 {
00866 klfDbg("bool!") ;
00867 QByteArray lowerdata = data.trimmed().toLower();
00868 QChar c = QChar(lowerdata[0]);
00869
00870 return QVariant::fromValue<bool>(c == 't' || c == 'y' || c == '1' || lowerdata == "on");
00871 }
00872 case QMetaType::Int:
00873 {
00874 klfDbg("int!") ;
00875 int i = data.toInt(&convertOk);
00876 if (convertOk)
00877 return QVariant::fromValue<int>(i);
00878 break;
00879 }
00880 case QMetaType::UInt:
00881 {
00882 klfDbg("uint!") ;
00883 uint i = data.toUInt(&convertOk);
00884 if (convertOk)
00885 return QVariant::fromValue<uint>(i);
00886 break;
00887 }
00888 case QMetaType::Short:
00889 {
00890 klfDbg("short!") ;
00891 short i = data.toShort(&convertOk);
00892 if (convertOk)
00893 return QVariant::fromValue<short>(i);
00894 break;
00895 }
00896 case QMetaType::UShort:
00897 {
00898 klfDbg("ushort!") ;
00899 ushort i = data.toUShort(&convertOk);
00900 if (convertOk)
00901 return QVariant::fromValue<ushort>(i);
00902 break;
00903 }
00904 case QMetaType::Long:
00905 {
00906 klfDbg("long!") ;
00907 long i = data.toLong(&convertOk);
00908 if (convertOk)
00909 return QVariant::fromValue<long>(i);
00910 break;
00911 }
00912 case QMetaType::ULong:
00913 {
00914 klfDbg("ulong!") ;
00915 ulong i = data.toULong(&convertOk);
00916 if (convertOk)
00917 return QVariant::fromValue<ulong>(i);
00918 break;
00919 }
00920 case QMetaType::LongLong:
00921 {
00922 klfDbg("longlong!") ;
00923 qlonglong i = data.toLongLong(&convertOk);
00924 if (convertOk)
00925 return QVariant::fromValue<qlonglong>(i);
00926 break;
00927 }
00928 case QMetaType::ULongLong:
00929 {
00930 klfDbg("ulonglong!") ;
00931 qulonglong i = data.toULongLong(&convertOk);
00932 if (convertOk)
00933 return QVariant::fromValue<qulonglong>(i);
00934 break;
00935 }
00936 case QMetaType::Double:
00937 {
00938 klfDbg("double!") ;
00939 double val = data.toDouble(&convertOk);
00940 if (convertOk)
00941 return QVariant::fromValue<double>(val);
00942 break;
00943 }
00944 case QMetaType::Char:
00945 {
00946 klfDbg("char!") ;
00947 if (data[0] == '\\') {
00948 if (data.size() < 2)
00949 break;
00950 if (data[1] == '\\')
00951 return QVariant::fromValue<char>('\\');
00952 if (data.size() < 3)
00953 break;
00954 uint c = data.mid(1).toUInt(&convertOk, 16);
00955 if (!convertOk)
00956 break;
00957 convertOk = false;
00958 if (c > 255)
00959 break;
00960 return QVariant::fromValue<char>( (char)c );
00961 }
00962 return QVariant::fromValue<char>( (char)data[0] );
00963 }
00964 case QMetaType::QChar:
00965 {
00966 klfDbg("QChar!") ;
00967 if (data[0] == '\\') {
00968 if (data.size() < 2)
00969 break;
00970 if (data[1] == '\\')
00971 return QVariant::fromValue<QChar>(QChar('\\'));
00972 if (data.size() < 3)
00973 break;
00974 uint c = data.mid(1).toUInt(&convertOk, 16);
00975 if (!convertOk)
00976 break;
00977 convertOk = false;
00978 if (c > 255)
00979 break;
00980 return QVariant::fromValue<QChar>( QChar(c) );
00981 }
00982 return QVariant::fromValue<QChar>( QChar(data[0]) );
00983 }
00984 case QMetaType::QString:
00985 {
00986 klfDbg("qstring!") ;
00987 QString s;
00988 QByteArray chunk;
00989 k = 0;
00990 while (k < data.size()) {
00991 if (data[k] != '\\') {
00992 chunk += data[k];
00993 ++k;
00994 continue;
00995 }
00996 if (data[k] == '\\' && k+1 >= data.size()) {
00997 chunk += '\\';
00998 ++k;
00999 continue;
01000 }
01001
01002 if (data[k+1] != 'x') {
01003
01004 chunk += data[k+1];
01005 k += 2;
01006 continue;
01007 }
01008
01009 int nlen = -1;
01010 if (k+5 < data.size() && klf_is_hex_char(data[k+2]) && klf_is_hex_char(data[k+3])
01011 && klf_is_hex_char(data[k+4]) && klf_is_hex_char(data[k+5])) {
01012 nlen = 4;
01013 }
01014 if (k+3 < data.size() && klf_is_hex_char(data[k+2]) && klf_is_hex_char(data[k+3])) {
01015 nlen = 2;
01016 }
01017 if (nlen < 0) {
01018
01019 chunk += data[k];
01020 ++k;
01021 continue;
01022 }
01023
01024 ushort cval = data.mid(k+2, nlen).toUShort(&convertOk, 16);
01025 QChar ch(cval);
01026
01027 s += QString::fromLocal8Bit(chunk) + ch;
01028
01029 chunk = QByteArray();
01030
01031
01032 k += 2 + nlen;
01033 }
01034
01035 s += QString::fromLocal8Bit(chunk);
01036 return QVariant::fromValue<QString>(s);
01037 }
01038 case QMetaType::QStringList:
01039 {
01040 klfDbg("qstringlist!") ;
01041 QList<QByteArray> sections = decaps_list(data);
01042
01043
01044 QStringList list;
01045 for (k = 0; k < sections.size(); ++k) {
01046 list << QString::fromUtf8(klfEscapedToData(sections[k]));
01047 }
01048
01049 return QVariant::fromValue<QStringList>(list);
01050 }
01051 case QMetaType::QUrl:
01052 {
01053 klfDbg("url!") ;
01054 return QVariant::fromValue<QUrl>(QUrl(QString::fromLocal8Bit(data), QUrl::TolerantMode));
01055 }
01056 case QMetaType::QByteArray:
01057 {
01058 klfDbg("qbytearray!") ;
01059 QByteArray value_ba = klfEscapedToData(data);
01060 return QVariant::fromValue<QByteArray>(value_ba);
01061 }
01062 case QMetaType::QDate:
01063 {
01064 klfDbg("qdate!") ;
01065 QString s = QString::fromLocal8Bit(data);
01066 QDate date = QDate::fromString(s, Qt::SystemLocaleShortDate);
01067 if (!date.isValid()) date = QDate::fromString(s, Qt::ISODate);
01068 if (!date.isValid()) date = QDate::fromString(s, Qt::SystemLocaleLongDate);
01069 if (!date.isValid()) date = QDate::fromString(s, Qt::DefaultLocaleShortDate);
01070 if (!date.isValid()) date = QDate::fromString(s, Qt::TextDate);
01071 if (!date.isValid()) date = QDate::fromString(s, "dd-MM-yyyy");
01072 if (!date.isValid()) date = QDate::fromString(s, "dd.MM.yyyy");
01073 if (!date.isValid()) date = QDate::fromString(s, "dd MM yyyy");
01074 if (!date.isValid()) date = QDate::fromString(s, "yyyy-MM-dd");
01075 if (!date.isValid()) date = QDate::fromString(s, "yyyy.MM.dd");
01076 if (!date.isValid()) date = QDate::fromString(s, "yyyy MM dd");
01077 if (!date.isValid()) date = QDate::fromString(s, "yyyyMMdd");
01078 if (!date.isValid())
01079 break;
01080 return QVariant::fromValue<QDate>(date);
01081 }
01082 case QMetaType::QTime:
01083 {
01084 klfDbg("qtime!") ;
01085 QString s = QString::fromLocal8Bit(data);
01086 QTime time = QTime::fromString(s, Qt::SystemLocaleShortDate);
01087 if (!time.isValid()) time = QTime::fromString(s, Qt::ISODate);
01088 if (!time.isValid()) time = QTime::fromString(s, Qt::SystemLocaleLongDate);
01089 if (!time.isValid()) time = QTime::fromString(s, Qt::DefaultLocaleShortDate);
01090 if (!time.isValid()) time = QTime::fromString(s, Qt::TextDate);
01091 if (!time.isValid()) time = QTime::fromString(s, "hh:mm:ss.z");
01092 if (!time.isValid()) time = QTime::fromString(s, "hh:mm:ss");
01093 if (!time.isValid()) time = QTime::fromString(s, "hh:mm:ss AP");
01094 if (!time.isValid()) time = QTime::fromString(s, "hh.mm.ss");
01095 if (!time.isValid()) time = QTime::fromString(s, "hh.mm.ss AP");
01096 if (!time.isValid()) time = QTime::fromString(s, "hh mm ss");
01097 if (!time.isValid()) time = QTime::fromString(s, "hh mm ss AP");
01098 if (!time.isValid()) time = QTime::fromString(s, "hhmmss");
01099 if (!time.isValid())
01100 break;
01101 return QVariant::fromValue<QTime>(time);
01102 }
01103 case QMetaType::QDateTime:
01104 {
01105 klfDbg("qdatetime!") ;
01106 QString s = QString::fromLocal8Bit(data);
01107 QDateTime dt = QDateTime::fromString(s, Qt::SystemLocaleShortDate);
01108 if (!dt.isValid()) dt = QDateTime::fromString(s, Qt::ISODate);
01109 if (!dt.isValid()) dt = QDateTime::fromString(s, Qt::SystemLocaleLongDate);
01110 if (!dt.isValid()) dt = QDateTime::fromString(s, Qt::DefaultLocaleShortDate);
01111 if (!dt.isValid()) dt = QDateTime::fromString(s, Qt::TextDate);
01112 if (!dt.isValid()) dt = QDateTime::fromString(s, "dd-MM-yyyy hh:mm:ss");
01113 if (!dt.isValid()) dt = QDateTime::fromString(s, "dd-MM-yyyy hh.mm.ss");
01114 if (!dt.isValid()) dt = QDateTime::fromString(s, "dd.MM.yyyy hh:mm:ss");
01115 if (!dt.isValid()) dt = QDateTime::fromString(s, "dd.MM.yyyy hh.mm.ss");
01116 if (!dt.isValid()) dt = QDateTime::fromString(s, "dd MM yyyy hh mm ss");
01117 if (!dt.isValid()) dt = QDateTime::fromString(s, "yyyy-MM-dd hh:mm:ss");
01118 if (!dt.isValid()) dt = QDateTime::fromString(s, "yyyy-MM-dd hh.mm.ss");
01119 if (!dt.isValid()) dt = QDateTime::fromString(s, "yyyy.MM.dd hh:mm:ss");
01120 if (!dt.isValid()) dt = QDateTime::fromString(s, "yyyy.MM.dd hh.mm.ss");
01121 if (!dt.isValid()) dt = QDateTime::fromString(s, "yyyy MM dd hh mm ss");
01122 if (!dt.isValid()) dt = QDateTime::fromString(s, "yyyyMMddhhmmss");
01123 if (!dt.isValid())
01124 break;
01125 return QVariant::fromValue<QDateTime>(dt);
01126 }
01127 case QMetaType::QSize:
01128 {
01129 klfDbg("qsize!") ;
01130 QString s = QString::fromLocal8Bit(data.trimmed());
01131 if (szrx.indexIn(s) < 0)
01132 break;
01133 QStringList vals = szrx.capturedTexts();
01134 return QVariant::fromValue<QSize>(QSize(vals[SZRX_W].toInt(), vals[SZRX_H].toInt()));
01135 }
01136 case QMetaType::QPoint:
01137 {
01138 klfDbg("qpoint!") ;
01139 QString s = QString::fromLocal8Bit(data.trimmed());
01140 if (v2rx.indexIn(s) < 0)
01141 break;
01142 QStringList vals = v2rx.capturedTexts();
01143 return QVariant::fromValue<QPoint>(QPoint(vals[V2RX_X].toInt(), vals[V2RX_Y].toInt()));
01144 }
01145 case QMetaType::QRect:
01146 {
01147 klfDbg("qrect!") ;
01148 QString s = QString::fromLocal8Bit(data.trimmed());
01149 if (rectrx.indexIn(s) < 0)
01150 break;
01151 QStringList vals = rectrx.capturedTexts();
01152 if (vals[RECTRX_MIDDLESEP_PLUS] == "+" || vals[RECTRX_LASTSEP_X] == "x") {
01153 return QVariant::fromValue<QRect>(QRect( QPoint(vals[RECTRX_X1].toInt(), vals[RECTRX_Y1].toInt()),
01154 QSize(vals[RECTRX_X2orW].toInt(), vals[RECTRX_Y2orH].toInt()) ));
01155 }
01156 return QVariant::fromValue<QRect>(QRect( QPoint(vals[RECTRX_X1].toInt(), vals[RECTRX_Y1].toInt()),
01157 QPoint(vals[RECTRX_X2orW].toInt(), vals[RECTRX_Y2orH].toInt()) ));
01158 }
01159 case QMetaType::QColor:
01160 {
01161 klfDbg("qcolor!") ;
01162 QString colstr = QString::fromLocal8Bit(data.trimmed());
01163
01164 if (colrx.indexIn(colstr) < 0) {
01165 klfDbg("color "<<colstr<<" does not match regexp="<<colrx.pattern()<<", trying named...") ;
01166
01167 QColor color; color.setNamedColor(colstr);
01168
01169 if (color.isValid())
01170 return color;
01171 break;
01172 }
01173
01174 QStringList vals = colrx.capturedTexts();
01175 QColor color = QColor(vals[COLRX_R].toInt(), vals[COLRX_G].toInt(), vals[COLRX_B].toInt(), 255);
01176 if (!vals[COLRX_MAYBE_ALPHA].isEmpty())
01177 color.setAlpha(vals[COLRX_A].toInt());
01178 return QVariant::fromValue<QColor>(color);
01179 }
01180 case QMetaType::QFont:
01181 {
01182 klfDbg("qfont!") ;
01183 if (fontrx.indexIn(QString::fromLocal8Bit(data.trimmed())) < 0) {
01184 klfDbg("malformed font: "<<data);
01185 break;
01186 }
01187 QStringList vals = fontrx.capturedTexts();
01188 klfDbg("parsing font: data="<<data<<"; captured texts are: "<<vals );
01189
01190 QString family = vals[FONTRX_FAMILY].trimmed();
01191 QString weighttxt = vals[FONTRX_WEIGHT_TEXT];
01192 QString weightval = vals[FONTRX_WEIGHT_VALUE];
01193 QString styletxt = vals[FONTRX_STYLE_TEXT];
01194 QString ptsval = vals[FONTRX_POINTSIZE];
01195
01196 int weight = QFont::Normal;
01197 if (weighttxt == "Light") weight = QFont::Light;
01198 else if (weighttxt == "Normal") weight = QFont::Normal;
01199 else if (weighttxt == "DemiBold") weight = QFont::DemiBold;
01200 else if (weighttxt == "Bold") weight = QFont::Bold;
01201 else if (weighttxt == "Black") weight = QFont::Black;
01202 else if (weighttxt.startsWith("Wgt")) weight = weightval.toInt();
01203
01204
01205 QFont::Style style = QFont::StyleNormal;
01206 if (styletxt == "Normal") style = QFont::StyleNormal;
01207 else if (styletxt == "Italic") style = QFont::StyleItalic;
01208 else if (styletxt == "Oblique") style = QFont::StyleOblique;
01209
01210 int pt = -1;
01211 if (!ptsval.isEmpty())
01212 pt = ptsval.toInt();
01213
01214 QFont font(family, pt, weight);
01215 font.setStyle(style);
01216 return QVariant::fromValue<QFont>(font);
01217 }
01218 case QMetaType::QBrush:
01219 {
01220 klfDbg("qbrush!") ;
01221 if (brushrx.indexIn(QString::fromLocal8Bit(data.trimmed())) < 0) {
01222 klfDbg("malformed brush text: "<<data) ;
01223 break;
01224 }
01225 QStringList vals = brushrx.capturedTexts();
01226 QString style = vals[BRUSHRX_STYLE];
01227
01228 int k;
01229 bool style_found = false;
01230 for (k = 0; klf_brush_styles[k].brushStyle >= 0 && klf_brush_styles[k].style != NULL; ++k) {
01231 if (klf_brush_styles[k].style == style) {
01232 style_found = true;
01233 break;
01234 }
01235 }
01236 if (!style_found) {
01237 klfDbg("Can't find style"<<style<<" in brush style list!");
01238 break;
01239 }
01240 int qbrush_style = klf_brush_styles[k].brushStyle;
01241
01242 QColor c = QColor(vals[BRUSHRX_R].toInt(), vals[BRUSHRX_G].toInt(),
01243 vals[BRUSHRX_B].toInt());
01244 if (!vals[BRUSHRX_A].isEmpty())
01245 c.setAlpha(vals[BRUSHRX_A].toInt());
01246 return QBrush(c, static_cast<Qt::BrushStyle>(qbrush_style));
01247 }
01248 case QMetaType::QTextFormat:
01249 {
01250 klfDbg("qtextformat!") ;
01251 int k;
01252 QList<QPair<QByteArray,QByteArray> > sections = decaps_map(data, true);
01253 if (sections.isEmpty()) {
01254 klfDbg("Invalid QTextFormat data.") ;
01255 break;
01256 }
01257 QPair<QByteArray,QByteArray> firstSection = sections.takeFirst();
01258 QString fmttype = QString::fromLatin1(firstSection.first);
01259
01260 for (k = 0; klf_text_format_formats[k].format != NULL; ++k)
01261 if (QString::compare(fmttype, QLatin1String(klf_text_format_formats[k].format),
01262 Qt::CaseInsensitive) == 0)
01263 break;
01264 if (klf_text_format_formats[k].format == NULL) {
01265 klfDbg("QTextFormat: Invalid format type: "<<fmttype) ;
01266 break;
01267 }
01268 int qtextformat_type = klf_text_format_formats[k].formatId;
01269
01270
01271 QTextFormat textformat(qtextformat_type);
01272 QList<QPair<QByteArray,QByteArray> >::const_iterator it;
01273 for (it = sections.begin(); it != sections.end(); ++it) {
01274 QByteArray key = (*it).first.trimmed();
01275 QByteArray value = (*it).second;
01276 klfDbg("QTextFormat: considering property pair key="<<key<<"; value="<<value) ;
01277
01278 for (k = 0; klf_text_format_keywords[k].keyword != NULL; ++k)
01279 if (QString::compare(QLatin1String(klf_text_format_keywords[k].keyword),
01280 key, Qt::CaseInsensitive) == 0)
01281 break;
01282 if (klf_text_format_keywords[k].keyword != NULL) {
01283
01284 klfDbg("QTextFormat: is keyword, propId="<<klf_text_format_keywords[k].propId<<", fixed_value="
01285 <<klf_text_format_keywords[k].fixed_value) ;
01286 textformat.setProperty(klf_text_format_keywords[k].propId,
01287 klf_text_format_keywords[k].fixed_value);
01288 continue;
01289 }
01290
01291 for (k = 0; klf_text_format_props[k].key != NULL; ++k)
01292 if (QString::compare(QLatin1String(klf_text_format_props[k].key),
01293 key, Qt::CaseInsensitive) == 0)
01294 break;
01295 if (klf_text_format_props[k].key != NULL) {
01296 klfDbg("QTextFormat: is known property of type "<<klf_text_format_props[k].type) ;
01297
01298 QVariant vval = klfLoadVariantFromText(value, klf_text_format_props[k].type, "XML");
01299 textformat.setProperty(klf_text_format_props[k].propId, vval);
01300 continue;
01301 }
01302
01303
01304 bool tointok = true;
01305 int propid = key.toInt(&tointok);
01306 if (!tointok) {
01307 qWarning()<<KLF_FUNC_NAME<<": QTextFormat bad format for general property key=value pair; "
01308 <<"key is not a numerical property ID, nor is it a known property name.";
01309 }
01310
01311 klfDbg("QTextFormat: property is not a known one. propid="<<propid) ;
01312
01313
01314 while (value.size() && QChar(value[0]).isSpace())
01315 value.remove(0, 1);
01316 int i;
01317 if (value.isEmpty() || !value.startsWith("[") || ((i = value.indexOf(']')) == -1)) {
01318 qWarning().nospace()<<KLF_FUNC_NAME<<": QTextFormat bad format for general property, value does "
01319 <<"not begin with \"[type-name]\".";
01320 continue;
01321 }
01322 QByteArray typenm = value.mid(1, i-1);
01323 QByteArray valuedata = value.mid(i+1);
01324 QVariant vval = klfLoadVariantFromText(valuedata, typenm);
01325 klfDbg("setting generalized property "<<propid<<" to value "<<vval) ;
01326 textformat.setProperty(propid, vval);
01327 }
01328 return textformat;
01329 }
01330 case QMetaType::QVariantList:
01331 {
01332 klfDbg("qvariantlist!") ;
01333 if (listOrMapDataTypeName == QLatin1String("XML")) {
01334 QDomElement el = parse_xml_wrapper(data, "variant-list");
01335 return klfLoadVariantListFromXML(el);
01336 } else {
01337 QList<QByteArray> sections = decaps_list(data);
01338
01339
01340 QVariantList list;
01341 for (k = 0; k < sections.size(); ++k) {
01342 QVariant val = klfLoadVariantFromText(sections[k], listOrMapDataTypeName);
01343 list << val;
01344 }
01345
01346 return QVariant::fromValue<QVariantList>(list);
01347 }
01348 }
01349 case QMetaType::QVariantMap:
01350 {
01351 klfDbg("qvariantmap!") ;
01352 if (listOrMapDataTypeName == QLatin1String("XML")) {
01353 QDomElement el = parse_xml_wrapper(data, "variant-map");
01354 return klfLoadVariantMapFromXML(el);
01355 } else {
01356 const QList<QPair<QByteArray,QByteArray> > sections = decaps_map(data);
01357 QVariantMap vmap;
01358 QList<QPair<QByteArray,QByteArray> >::const_iterator it;
01359 for (it = sections.begin(); it != sections.end(); ++it) {
01360 QString key = klfLoadVariantFromText((*it).first, "QString").toString();
01361 QVariant value = klfLoadVariantFromText((*it).second, listOrMapDataTypeName);
01362 vmap[key] = value;
01363 }
01364 return QVariant::fromValue<QVariantMap>(vmap);
01365 }
01366 }
01367 default:
01368 break;
01369 }
01370
01371 if (tname == "KLFEnumType") {
01372
01373 KLFEnumType e;
01374 e.setSpecification(tspecification);
01375 e.setValue(data.toInt());
01376 return QVariant::fromValue<KLFEnumType>(e);
01377 }
01378
01379 klfDbg("other type or failed to load the good type!") ;
01380
01381
01382 if (KLFPObjRegisteredType::isRegistered(tname)) {
01383
01384 QVariant value(QMetaType::type(dataTypeName), (const void*)NULL);
01385 KLFAbstractPropertizedObject * obj =
01386 const_cast<KLFAbstractPropertizedObject*>(static_cast<const KLFAbstractPropertizedObject*>(value.data()));
01387
01388 if (tspecification.size()) {
01389 KLFSpecifyableType * st =
01390 const_cast<KLFSpecifyableType*>(static_cast<const KLFSpecifyableType*>(value.data()));
01391 st->setSpecification(tspecification);
01392 }
01393
01394 bool hasfixedtypes = obj->hasFixedTypes();
01395
01396 klfDbg("loading an abstr.prop.obj: "<<obj) ;
01397 klfDbg("obj is of type "<<obj->objectKind()<<", fixedtypes="<<hasfixedtypes) ;
01398
01399 QVariantMap props = klfLoadVariantFromText(data, "QVariantMap", hasfixedtypes ? "QByteArray" : "XML").toMap();
01400 if (!hasfixedtypes) {
01401 obj->setAllProperties(props);
01402 return value;
01403 }
01404
01405 QVariantMap propsconverted;
01406 for (QVariantMap::const_iterator it = props.begin(); it != props.end(); ++it) {
01407 QByteArray tn = obj->typeNameFor(it.key());
01408
01409 QByteArray ts = obj->typeSpecificationFor(it.key());
01410 if (ts.size())
01411 tn += "/"+ts;
01412 propsconverted[it.key()] = klfLoadVariantFromText(it.value().toByteArray(), tn,
01413 "XML");
01414 klfDbg("Loading property "<<it.key()<<" from saved text, value = "<<propsconverted[it.key()]) ;
01415 }
01416 props = propsconverted;
01417 obj->setAllProperties(props);
01418 return value;
01419 }
01420
01421 qWarning("klfLoadVariantFromText: Can't load a %s from %s !", dataTypeName, stringdata.constData());
01422 return QVariant();
01423 }
01424
01425
01426
01427
01428
01429
01430
01431
01432
01433
01434
01435 KLF_EXPORT QDomElement klfSaveVariantMapToXML(const QVariantMap& vmap, QDomElement baseNode)
01436 {
01437 KLF_DEBUG_BLOCK(KLF_FUNC_NAME) ;
01438
01439 QDomDocument doc = baseNode.ownerDocument();
01440
01441 for (QVariantMap::const_iterator it = vmap.begin(); it != vmap.end(); ++it) {
01442 QString key = it.key();
01443 QVariant value = it.value();
01444
01445 QDomElement pairNode = doc.createElement("pair");
01446
01447 QDomElement keyNode = doc.createElement("key");
01448 QDomText keyText = doc.createTextNode(key);
01449 keyNode.appendChild(keyText);
01450 pairNode.appendChild(keyNode);
01451
01452 QDomElement vdataNode = doc.createElement("value");
01453 QString vtype = QLatin1String(value.typeName());
01454 if (vtype == "QVariantMap") {
01455 vdataNode.setAttribute(QLatin1String("type"), vtype);
01456 vdataNode = klfSaveVariantMapToXML(value.toMap(), vdataNode);
01457 } else if (vtype == "QVariantList") {
01458 vdataNode.setAttribute(QLatin1String("type"), vtype);
01459 vdataNode = klfSaveVariantListToXML(value.toList(), vdataNode);
01460 } else {
01461 QByteArray savedvtype;
01462 QDomText vdataText = doc.createTextNode(QString::fromLocal8Bit(klfSaveVariantToText(value, false, &savedvtype)));
01463 vdataNode.appendChild(vdataText);
01464 vdataNode.setAttribute(QLatin1String("type"), QString::fromUtf8(savedvtype));
01465 }
01466 pairNode.appendChild(vdataNode);
01467
01468 baseNode.appendChild(pairNode);
01469 }
01470 return baseNode;
01471 }
01472
01473 KLF_EXPORT QVariantMap klfLoadVariantMapFromXML(const QDomElement& xmlNode)
01474 {
01475 KLF_DEBUG_BLOCK(KLF_FUNC_NAME) ;
01476
01477 QVariantMap vmap;
01478
01479 QDomNode n;
01480 for (n = xmlNode.firstChild(); ! n.isNull(); n = n.nextSibling()) {
01481 QDomElement e = n.toElement();
01482 if ( e.isNull() || n.nodeType() != QDomNode::ElementNode )
01483 continue;
01484 if ( e.nodeName() != "pair" ) {
01485 klfWarning("Ignoring unexpected tag "<<e.nodeName()) ;
01486 continue;
01487 }
01488
01489 QString key;
01490 QByteArray valuetype;
01491 QByteArray valuedata;
01492 QDomElement valueNode;
01493 QDomNode nn;
01494 for (nn = e.firstChild(); ! nn.isNull(); nn = nn.nextSibling()) {
01495 klfDbg("inside <pair>: read node "<<nn.nodeName()) ;
01496 QDomElement ee = nn.toElement();
01497 if ( ee.isNull() || nn.nodeType() != QDomNode::ElementNode )
01498 continue;
01499 if ( ee.nodeName() == "key" ) {
01500 key = ee.text();
01501 continue;
01502 }
01503 if ( ee.nodeName() == "value" ) {
01504
01505 valueNode = ee;
01506 valuedata = ee.text().toLocal8Bit();
01507 valuetype = ee.attribute("type").toUtf8();
01508 continue;
01509 }
01510 klfWarning("Ignoring unexpected tag "<<ee.nodeName()<<" in <pair>!") ;
01511 }
01512 QVariant value;
01513 if (valuetype == "QVariantMap") {
01514 value = QVariant::fromValue<QVariantMap>(klfLoadVariantMapFromXML(valueNode));
01515 } else if (valuetype == "QVariantList") {
01516 value = QVariant::fromValue<QVariantList>(klfLoadVariantListFromXML(valueNode));
01517 } else {
01518 value = klfLoadVariantFromText(valuedata, valuetype.constData());
01519 }
01520
01521 vmap[key] = value;
01522 }
01523 return vmap;
01524 }
01525
01526
01527 KLF_EXPORT QDomElement klfSaveVariantListToXML(const QVariantList& vlist, QDomElement baseNode)
01528 {
01529 QDomDocument doc = baseNode.ownerDocument();
01530
01531 for (QVariantList::const_iterator it = vlist.begin(); it != vlist.end(); ++it) {
01532 QVariant value = *it;
01533
01534 QDomElement elNode = doc.createElement(QLatin1String("item"));
01535 QString vtype = QString::fromLatin1(value.typeName());
01536
01537 if (vtype == "QVariantMap") {
01538 elNode.setAttribute(QLatin1String("type"), vtype);
01539 elNode = klfSaveVariantMapToXML(value.toMap(), elNode);
01540 } else if (vtype == "QVariantList") {
01541 elNode.setAttribute(QLatin1String("type"), vtype);
01542 elNode = klfSaveVariantListToXML(value.toList(), elNode);
01543 } else {
01544 QByteArray savedvtype;
01545 QDomText vdataText = doc.createTextNode(QString::fromLocal8Bit(klfSaveVariantToText(value, false, &savedvtype)));
01546 elNode.appendChild(vdataText);
01547 elNode.setAttribute(QLatin1String("type"), QString::fromUtf8(savedvtype));
01548 }
01549
01550
01551 baseNode.appendChild(elNode);
01552 }
01553
01554 return baseNode;
01555 }
01556
01557 KLF_EXPORT QVariantList klfLoadVariantListFromXML(const QDomElement& xmlNode)
01558 {
01559 KLF_DEBUG_BLOCK(KLF_FUNC_NAME) ;
01560
01561 QVariantList vlist;
01562
01563 QDomNode n;
01564 for (n = xmlNode.firstChild(); ! n.isNull(); n = n.nextSibling()) {
01565 QDomElement e = n.toElement();
01566 if ( e.isNull() || n.nodeType() != QDomNode::ElementNode )
01567 continue;
01568 if ( e.nodeName() != QLatin1String("item") ) {
01569 qWarning("%s: ignoring unexpected tag `%s'!\n", KLF_FUNC_NAME, qPrintable(e.nodeName()));
01570 continue;
01571 }
01572
01573 QString vtype = e.attribute(QLatin1String("type"));
01574
01575 QVariant value;
01576 if (vtype == QLatin1String("QVariantMap")) {
01577 value = QVariant::fromValue<QVariantMap>(klfLoadVariantMapFromXML(e));
01578 } else if (vtype == QLatin1String("QVariantList")) {
01579 value = QVariant::fromValue<QVariantList>(klfLoadVariantListFromXML(e));
01580 } else {
01581 value = klfLoadVariantFromText(e.text().toLocal8Bit(), vtype.toLatin1().constData());
01582 }
01583
01584
01585 vlist << value;
01586 }
01587 return vlist;
01588 }
01589
01590
01591
01592
01593
01594
01595 KLFAbstractPropertizedObjectSaver::KLFAbstractPropertizedObjectSaver()
01596 : KLFFactoryBase(&pFactoryManager)
01597 {
01598 }
01599 KLFAbstractPropertizedObjectSaver::~KLFAbstractPropertizedObjectSaver()
01600 {
01601 }
01602
01603
01604 KLFFactoryManager KLFAbstractPropertizedObjectSaver::pFactoryManager;
01605
01606
01607 KLFAbstractPropertizedObjectSaver *
01608 KLFAbstractPropertizedObjectSaver::findRecognizedFormat(const QByteArray& data, QString * format)
01609 {
01610 QList<KLFFactoryBase*> allFactories = pFactoryManager.registeredFactories();
01611 QString s;
01612 foreach (KLFFactoryBase * ff, allFactories) {
01613 KLFAbstractPropertizedObjectSaver *f = (KLFAbstractPropertizedObjectSaver*) ff;
01614 if ((s = f->recognizeDataFormat(data)).size() != 0) {
01615
01616 if (format != NULL)
01617 *format = s;
01618 return f;
01619 }
01620 }
01621
01622 if (format != NULL)
01623 *format = QString();
01624 return NULL;
01625 }
01626
01627
01628 KLFAbstractPropertizedObjectSaver *
01629 KLFAbstractPropertizedObjectSaver::findSaverFor(const QString& format)
01630 {
01631 return dynamic_cast<KLFAbstractPropertizedObjectSaver*>(pFactoryManager.findFactoryFor(format));
01632 }
01633
01634
01635 KLFBaseFormatsPropertizedObjectSaver __klf_baseformats_pobj_saver;
01636
01637
01638 KLF_EXPORT QByteArray klfSave(const KLFAbstractPropertizedObject * obj, const QString& format)
01639 {
01640 KLF_DEBUG_BLOCK(KLF_FUNC_NAME) ;
01641 KLFAbstractPropertizedObjectSaver * saver =
01642 KLFAbstractPropertizedObjectSaver::findSaverFor(format);
01643 KLF_ASSERT_NOT_NULL(saver, "Can't find object saver for format="<<format<<" !", return QByteArray(); ) ;
01644 return saver->save(obj, format);
01645 }
01646
01647 KLF_EXPORT bool klfLoad(const QByteArray& data, KLFAbstractPropertizedObject * obj, const QString& format)
01648 {
01649 KLF_DEBUG_BLOCK(KLF_FUNC_NAME) ;
01650 KLFAbstractPropertizedObjectSaver * saver;
01651 QString f = format;
01652 if (f.isEmpty()) {
01653 saver = KLFAbstractPropertizedObjectSaver::findRecognizedFormat(data, &f);
01654 KLF_ASSERT_CONDITION(!f.isEmpty(), "Can't recognize data format!", return false; ) ;
01655 } else {
01656 saver = KLFAbstractPropertizedObjectSaver::findSaverFor(f);
01657 }
01658 KLF_ASSERT_NOT_NULL(saver, "Can't find object saver for format="<<f<<" !", return false; ) ;
01659 return saver->load(data, obj, f);
01660 }
01661
01662