HeaderBase.cpp

Go to the documentation of this file.
00001 /*
00002 
00003 Copyright (C) 2005-2007 by Peter Dimov.
00004 
00005 This file is part of Calitko (http://www.calitko.org).
00006 
00007 Calitko is free software; you can redistribute it and/or modify
00008 it under the terms of the GNU General Public License as published by
00009 the Free Software Foundation; either version 2 of the License, or
00010 (at your option) any later version.
00011 
00012 Calitko is distributed in the hope that it will be useful,
00013 but WITHOUT ANY WARRANTY; without even the implied warranty of
00014 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015 GNU General Public License for more details.
00016 
00017 You should have received a copy of the GNU General Public License
00018 along with Calitko; if not, write to the Free Software
00019 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
00020 
00021 */
00022 
00023 #include "Qt.h"
00024 #include "HeaderBase.h"
00025 #include "Imports.cpp"
00026 
00028 HeaderBase::HeaderBase()
00029  :  d_ptr (new Data)
00030 {
00031 }
00032 
00034 HeaderBase::HeaderBase (Data *d)
00035  :  d_ptr (d)
00036 {
00037 }
00038 
00040 HeaderBase::~HeaderBase()
00041 {
00042 }
00043 
00045 bool HeaderBase::operator== (const HeaderBase &other) const
00046 {
00047     return toRawBytes() == other.toRawBytes();
00048 }
00049 
00051 bool HeaderBase::operator!= (const HeaderBase &other) const
00052 {
00053     return !operator== (other);
00054 }
00055 
00057 auto_ptr <DataBase> HeaderBase::copy() const
00058 {
00059     return auto_ptr <DataBase> (new HeaderBase (*this));
00060 }
00061 
00063 
00073 bool HeaderBase::parse (const QByteArray &rawBytes)
00074 {
00075     auto_ptr <DataBase> tmpCopy = copy();
00076     HeaderBase &tempHeader = dynamic_cast <HeaderBase &> (*tmpCopy);
00077     if (tempHeader.doParse (rawBytes)) {
00078         *this = tempHeader;
00079         return true;
00080     } else {
00081         return false;
00082     }
00083 }
00084 
00086 
00101 QByteArray HeaderBase::toRawBytes() const
00102 {
00103     Q_SD (const Data);
00104     QByteArray ret = rawStartLine();
00105     foreach (const QByteArray &fieldName, d->orderedFieldList)
00106         ret += rawHeaderLine (fieldName);
00107     ret += "\r\n"; // Add the final <CR><LF>.
00108     return ret;
00109 }
00110 
00112 
00120 QByteArray HeaderBase::fieldValue (const QByteArray &fieldName) const
00121 {
00122     Q_SD (const Data);
00123     QByteArray nameLower = fieldName.toLower();
00124     if (!d->fieldValues.contains (nameLower))
00125         return QByteArray();
00126     else {
00127         QByteArray res;
00128         foreach (const QByteArray &value, d->fieldValues [nameLower])
00129             res += value + ", ";
00130         res.chop (2); // the last ", "
00131         return res;
00132     }
00133 }
00134 
00136 
00139 QList <QByteArray> HeaderBase::fields() const
00140 {
00141     Q_SD (const Data);
00142     return d->fieldValues.keys();
00143 }
00144 
00146 
00153 bool HeaderBase::hasField (const QByteArray &fieldName) const
00154 {
00155     Q_SD (const Data);
00156     return d->fieldValues.contains (fieldName.toLower());
00157 }
00158 
00160 
00166 QList <QByteArray> HeaderBase::fieldValues (const QByteArray &fieldName) const
00167 {
00168     Q_SD (const Data);
00169     QByteArray nameLower = fieldName.toLower();
00170     if (!d->fieldValues.contains (nameLower))
00171         return QList <QByteArray>();
00172     else
00173         return d->fieldValues [nameLower];
00174 }
00175 
00177 
00187 void HeaderBase::setFieldValue (const QByteArray &fieldName,
00188                             const QByteArray &fieldValue)
00189 {
00190     removeField (fieldName);
00191     addFieldValues (fieldName, fieldValue.split (','));
00192 }
00193 
00195 
00200 void HeaderBase::addFieldValue (const QByteArray &fieldName,
00201                                 const QByteArray &fieldValue)
00202 {
00203     Q_SD (Data);
00204     QByteArray nameLower = fieldName.toLower();
00205     QByteArray trimmedValue = fieldValue.trimmed();
00206     if (trimmedValue != "") // Don't add empty values:
00207         d->fieldValues [nameLower].push_back (fieldValue.trimmed());
00208     else
00209         d->fieldValues [nameLower]; // Makes sure nameLower is added in the map.
00210     d->originalCaseFieldNames [nameLower] = fieldName;
00211     if (!d->orderedFieldList.contains (nameLower))
00212         d->orderedFieldList.append (nameLower);
00213 }
00214 
00216 
00221 void HeaderBase::addFieldValues (const QByteArray &fieldName,
00222                              const QList <QByteArray> &fieldValues)
00223 {
00224     foreach (const QByteArray &value, fieldValues)
00225         addFieldValue (fieldName, value);
00226 }
00227 
00229 
00232 void HeaderBase::removeField (const QByteArray &fieldName)
00233 {
00234     Q_SD (Data);
00235     QByteArray nameLower (fieldName.toLower());
00236     if (d->fieldValues.contains (nameLower)) {
00237         d->fieldValues.remove (nameLower);
00238         d->originalCaseFieldNames.remove (nameLower);
00239         d->orderedFieldList.removeAll (nameLower);
00240     }
00241 }
00242 
00244 struct lineAppender : public std::unary_function <QString, void>
00245 {
00246     QList <QByteArray> &m_lines;
00247     lineAppender (QList <QByteArray> &lines) : m_lines (lines) {
00248     }
00249     void operator() (QByteArray &line) {
00250         if (!line.isEmpty()) {
00251             if (isspace (line[0])) {
00252                 if (!m_lines.isEmpty()) {
00253                     m_lines.last() += " ";
00254                     m_lines.last() += line.trimmed();
00255                 }
00256             } else {
00257                 m_lines.append (line);
00258             }
00259         }
00260     }
00261 };
00262 
00264 
00267 QByteArray HeaderBase::rawStartLine() const
00268 {
00269     return QByteArray();
00270 }
00271 
00273 QByteArray HeaderBase::rawHeaderLine (const QByteArray &fieldName) const
00274 {
00275     Q_SD (const Data);
00276     QByteArray ret;
00277     int oldLength = ret.length(); // == 0
00278     ret += d->originalCaseFieldNames [fieldName] + ":";
00279     foreach (const QByteArray &value, d->fieldValues [fieldName]) {
00280         // +1 for " ", +1 for ","
00281         if (ret.length() - oldLength + value.length() + 1 > 80) {
00282             // +2 because of "\r\n"; the "\t" counts for the next line
00283             oldLength = ret.length() + 2;
00284             ret += "\r\n\t" + value + ",";
00285         }
00286         else
00287             ret += " " + value + ",";
00288     }
00289     if (d->fieldValues [fieldName].size() > 0)
00290         ret.chop(1); // Remove the last ",".
00291     ret += "\r\n"; // Terminate the line with <CR><LF>.
00292     return ret;
00293 }
00294 
00296 
00300 bool HeaderBase::doParse (const QByteArray &rawBytes)
00301 {
00302     QList <QByteArray> lst = splitStringIntoLines (rawBytes);
00303     if (lst.isEmpty())
00304         return true;
00305 
00306     QList <QByteArray> lines;
00307     std::for_each (lst.begin(), lst.end(), lineAppender(lines));
00308     return parseAllLines (lines);
00309 }
00310 
00312 
00315 QList <QByteArray> HeaderBase::splitStringIntoLines (const QByteArray &str)
00316 {
00317     QByteArray normalizedStr = str;
00318     normalizedStr.replace ("\r\n", "\n");
00319     QList <QByteArray> lines = normalizedStr.split('\n');
00320     lines.removeAll(QByteArray()); // No empties
00321     return lines;
00322 }
00323 
00325 
00330 bool HeaderBase::parseAllLines (const QList <QByteArray> &lines)
00331 {
00332     QList <QByteArray>::const_iterator it = lines.begin();
00333     if (it != lines.end())
00334         if (!parseStartLine (*it++))
00335             return false;
00336     for(; it != lines.end(); ++it)
00337         if (!parseHeaderLine(*it))
00338             return false;
00339     return true;
00340 }
00341 
00343 
00350 bool HeaderBase::parseStartLine (const QByteArray &line)
00351 {
00352     return parseHeaderLine (line);
00353 }
00354 
00356 
00360 bool HeaderBase::parseHeaderLine (const QByteArray &line)
00361 {
00362     int i = line.indexOf(':');
00363     if (i == -1)
00364         return false;
00365 
00366     addFieldValue (line.left (i).trimmed (), line.mid (i + 1));
00367     return true;
00368 }