Branch 'kolab/integration/4.13.0' - kcalcore/icalformat.cpp kcalcore/icalformat.h kcalcore/icalformat_p.cpp kcalcore/icalformat_p.h

Christian Mollekopf mollekopf at kolabsys.com
Wed Sep 24 21:49:38 CEST 2014


 kcalcore/icalformat.cpp   |   33 +++++++++++++++++++++++++++++++++
 kcalcore/icalformat.h     |   17 +++++++++++++++++
 kcalcore/icalformat_p.cpp |   24 ++++++++++++++++++++++++
 kcalcore/icalformat_p.h   |    2 ++
 4 files changed, 76 insertions(+)

New commits:
commit e773b80ef526b01466ac070536b693e2d66c3e23
Author: Christian Mollekopf <chrigi_1 at fastmail.fm>
Date:   Wed Sep 24 21:42:39 2014 +0200

    ICalFormat: Introduce incidence parsing that ignores timezoneinformation.
    
    This is orders of magnitudes faster when used in the akonadi serializer,
    and uses a lot less memory (from 500mb to 100 for 10k events).

diff --git a/kcalcore/icalformat.cpp b/kcalcore/icalformat.cpp
index 362710d..27bec95 100644
--- a/kcalcore/icalformat.cpp
+++ b/kcalcore/icalformat.cpp
@@ -145,6 +145,39 @@ bool ICalFormat::fromString(const Calendar::Ptr &cal, const QString &string,
     return fromRawString(cal, string.toUtf8(), deleted, notebook);
 }
 
+Incidence::Ptr ICalFormat::readIncidence( const QByteArray &string, ICalTimeZones *tzlist )
+{
+    icalcomponent *calendar;
+
+    // Let's defend const correctness until the very gates of hell^Wlibical
+    calendar = icalcomponent_new_from_string(const_cast<char*>((const char *)string));
+    if (!calendar) {
+        kError() << "parse error ; string is empty?" << string.isEmpty();
+        setException(new Exception(Exception::ParseErrorIcal));
+        return Incidence::Ptr();
+    }
+
+    Incidence::Ptr incidence;
+    if (icalcomponent_isa(calendar) == ICAL_VCALENDAR_COMPONENT) {
+        incidence = d->mImpl->readOneIncidence(calendar, tzlist);
+    } else if (icalcomponent_isa(calendar) == ICAL_XROOT_COMPONENT) {
+        icalcomponent *comp = icalcomponent_get_first_component(calendar, ICAL_VCALENDAR_COMPONENT);
+        if (comp) {
+            incidence = d->mImpl->readOneIncidence(comp, tzlist);
+        }
+    }
+
+    if (!incidence) {
+        kDebug() << "No VCALENDAR component found";
+        setException(new Exception(Exception::NoCalendar));
+    }
+
+    icalcomponent_free(calendar);
+    icalmemory_free_ring();
+
+    return incidence;
+}
+
 bool ICalFormat::fromRawString(const Calendar::Ptr &cal, const QByteArray &string,
                                bool deleted, const QString &notebook)
 {
diff --git a/kcalcore/icalformat.h b/kcalcore/icalformat.h
index 534f134..358362b 100644
--- a/kcalcore/icalformat.h
+++ b/kcalcore/icalformat.h
@@ -100,6 +100,23 @@ public:
     Incidence::Ptr fromString(const QString &string);
 
     /**
+      Parses a string, returning the first iCal component as an Incidence, ignored timezone information.
+
+      This function is significantly faster than fromString by avoiding the overhead of parsing timezone information.
+      Timezones are instead solely interpreted by using system-timezones.
+
+      @param string is a utf8 QByteArray containing the data to be parsed.
+      @param tzlist is a collection of timezones used for the parsed date-times.
+      This collection may be empty or pre-populated. If it is empty, it is populated
+      automatically from the systemtimezones and thus acts as a cache. The tzlist may be 0
+      if the timezone should be read everytime from the system.
+
+      @return non-zero pointer if the parsing was successful; 0 otherwise.
+      @see fromString(const QString &), fromRawString()
+    */
+    Incidence::Ptr readIncidence(const QByteArray &string, ICalTimeZones *tzlist);
+
+    /**
       Parses a string and fills a RecurrenceRule object with the information.
 
       @param rule is a pointer to a RecurrenceRule object.
diff --git a/kcalcore/icalformat_p.cpp b/kcalcore/icalformat_p.cpp
index b1d119c..0f54e39 100644
--- a/kcalcore/icalformat_p.cpp
+++ b/kcalcore/icalformat_p.cpp
@@ -2656,6 +2656,29 @@ icalcomponent *ICalFormatImpl::createCalendarComponent(const Calendar::Ptr &cal)
     return calendar;
 }
 
+Incidence::Ptr ICalFormatImpl::readOneIncidence(icalcomponent *calendar, ICalTimeZones *tzlist)
+{
+    if (!calendar) {
+        kWarning() << "Populate called with empty calendar";
+        return Incidence::Ptr();
+    }
+    icalcomponent *c;
+    c = icalcomponent_get_first_component(calendar, ICAL_VEVENT_COMPONENT);
+    if (c) {
+        return readEvent(c, tzlist);
+    }
+    c = icalcomponent_get_first_component(calendar, ICAL_VTODO_COMPONENT);
+    if (c) {
+        return readTodo(c, tzlist);
+    }
+    c = icalcomponent_get_first_component(calendar, ICAL_VJOURNAL_COMPONENT);
+    if (c) {
+        return readJournal(c, tzlist);
+    }
+    kWarning() << "Found no incidence";
+    return Incidence::Ptr();
+}
+
 // take a raw vcalendar (i.e. from a file on disk, clipboard, etc. etc.
 // and break it down from its tree-like format into the dictionary format
 // that is used internally in the ICalFormatImpl.
@@ -2736,6 +2759,7 @@ bool ICalFormatImpl::populate(const Calendar::Ptr &cal, icalcomponent *calendar,
     }
 
     // Populate the calendar's time zone collection with all VTIMEZONE components
+    // FIXME: HUUUUUGE memory consumption
     ICalTimeZones *tzlist = cal->timeZones();
     ICalTimeZoneSource tzs;
     tzs.parse(calendar, *tzlist);
diff --git a/kcalcore/icalformat_p.h b/kcalcore/icalformat_p.h
index ccc03ec..dfb5047 100644
--- a/kcalcore/icalformat_p.h
+++ b/kcalcore/icalformat_p.h
@@ -108,6 +108,8 @@ public:
     bool populate(const Calendar::Ptr &calendar, icalcomponent *fs,
                   bool deleted = false, const QString &notebook = QString());
 
+    Incidence::Ptr readOneIncidence(icalcomponent *calendar, ICalTimeZones *tzlist);
+
     icalcomponent *writeIncidence(const IncidenceBase::Ptr &incidence,
                                   iTIPMethod method = iTIPRequest,
                                   ICalTimeZones *tzList = 0,




More information about the commits mailing list