/* -*-objc-*- * * GNUstep RSS Kit * Copyright (C) 2006 Guenther Noack * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation, in version 2.1 * of the License * * This library 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ // Dublin Core Module // Written by Guenther Noack // For the date format, please consider taking a look at // http://www.w3.org/TR/NOTE-datetime #import "DublinCore.h" //#define DEBUG 1 // ------------------------------------------------------------- // G L O B A L V A R I A B L E S // index always points to the *next* character // this is a global variable so that you can find out where it failed. int position; NSString* dc_error; // ------------------------------------------------------------- // M A C R O S #define nextIsNumber (isdigit(str[position])) #define breakMethod(reason) \ { \ free(str); \ dc_error = reason; \ return nil; \ } #define eatNextNumber(item) \ { \ (item) = (item)*10 + (str[position]-(unichar)'0'); \ position++; \ } #define indexOutOfBounds (position>=length) #define eatNextNumberOrBreak(item) \ { \ if (indexOutOfBounds) \ breakMethod(@"index out of bounds"); \ \ if (nextIsNumber) \ eatNextNumber((item)) \ else \ breakMethod(@"not a number"); \ } #define eatNextNumberOrBreakTimes(item,n) \ { \ for(i=0;i<(n);i++) \ { \ eatNextNumberOrBreak((item)); \ } \ } #define eat(character,retval) \ { \ if (indexOutOfBounds) \ return retval; \ \ if (str[position]!=character) \ breakMethod(@"expected something else"); \ \ position++; \ } #define successReturnValue \ [ NSCalendarDate \ dateWithYear: ((year!=0)?year:2005) \ month: ((month!=0)?month:1) \ day: ((dayOfMonth!=0)?dayOfMonth:1) \ hour: hours \ minute: minutes \ second: seconds \ timeZone: timeZone ] #define eatOrSucceed(character) \ eat(character,successReturnValue); #define eatOrDie(character) \ eat(character,nil); // ------------------------------------------------------------- // D A T E P A R S E R NSDate* parseDublinCoreDate( NSString* dateStr ) { unichar* str; int length; int i; // just for small loops int year =0; int month =0; int dayOfMonth =0; int hours =0; int minutes =0; int seconds =0; int deciseconds =0; NSTimeZone* timeZone = nil; int tzHrs =0; int tzMins =0; int tzSign =0; length = [dateStr length]; str = (unichar*) malloc(length*sizeof(unichar)); [dateStr getCharacters: str]; // reset position position = 0; eatNextNumberOrBreakTimes(year,4); eatOrSucceed('-'); eatNextNumberOrBreakTimes(month,2); eatOrSucceed('-'); eatNextNumberOrBreakTimes(dayOfMonth,2); eatOrSucceed('T'); eatNextNumberOrBreakTimes(hours,2); eatOrDie(':'); eatNextNumberOrBreakTimes(minutes,2); // Optional Seconds if (indexOutOfBounds) breakMethod(@"out of bounds where seconds or TZD should follow"); if (str[position] == (unichar)':') { position++; eatNextNumberOrBreakTimes(seconds,2); if (indexOutOfBounds) breakMethod(@"out of bounds where deciseconds or TZD should follow"); if (str[position] == (unichar)'.') { position++; eatNextNumberOrBreak(deciseconds); } } // Time Zone if (indexOutOfBounds) breakMethod(@"out of bounds where time zone definition should follow"); if (str[position] == (unichar)'-') { eatOrDie('-'); tzSign = -1; // GOTO PARSETZDREST } else if (str[position] == (unichar)'+') { eatOrDie('+'); tzSign = 1; // GOTO PARSETZDREST } // putting together the time zone if (tzSign != 0) { // PARSETZDREST: eatNextNumberOrBreakTimes(tzHrs,2); eatOrDie(':'); eatNextNumberOrBreakTimes(tzMins,2); timeZone = [NSTimeZone timeZoneForSecondsFromGMT: tzSign * ((tzHrs*60 + tzMins)*60)]; } else { NSString* subStr = [dateStr substringFromIndex: position]; timeZone = [NSTimeZone timeZoneWithAbbreviation: subStr]; } /* Process is done. It should be safe to free str */ free(str); return successReturnValue; }