LCOV - code coverage report
Current view: top level - src/base - pdf-time.c (source / functions) Hit Total Coverage
Test: libgnupdf.info Lines: 320 350 91.4 %
Date: 2011-12-09 Functions: 38 39 97.4 %
Branches: 163 252 64.7 %

           Branch data     Line data    Source code
       1                 :            : /* -*- mode: C -*-
       2                 :            :  *
       3                 :            :  *       File:         pdf-time.c
       4                 :            :  *       Date:         Mon Apr 28 23:23:04 2008
       5                 :            :  *
       6                 :            :  *       GNU PDF Library - Time Module source
       7                 :            :  *
       8                 :            :  */
       9                 :            : 
      10                 :            : /* Copyright (C) 2008-2011 Free Software Foundation, Inc. */
      11                 :            : 
      12                 :            : /* This program is free software: you can redistribute it and/or modify
      13                 :            :  * it under the terms of the GNU General Public License as published by
      14                 :            :  * the Free Software Foundation, either version 3 of the License, or
      15                 :            :  * (at your option) any later version.
      16                 :            :  *
      17                 :            :  * This program is distributed in the hope that it will be useful,
      18                 :            :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      19                 :            :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      20                 :            :  * GNU General Public License for more details.
      21                 :            :  *
      22                 :            :  * You should have received a copy of the GNU General Public License
      23                 :            :  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
      24                 :            :  */
      25                 :            : 
      26                 :            : #include <config.h>
      27                 :            : 
      28                 :            : #include <time.h>
      29                 :            : 
      30                 :            : #include <pdf-alloc.h>
      31                 :            : #include <pdf-time.h>
      32                 :            : #include <pdf-time-context.h>
      33                 :            : #include <pdf-time-string.h>
      34                 :            : 
      35                 :            : /* Useful constants */
      36                 :            : 
      37                 :            : #define PDF_SECS_PER_DAY      86400
      38                 :            : #define PDF_SECS_PER_HOUR      3600
      39                 :            : #define PDF_SECS_PER_MIN         60
      40                 :            : #define PDF_MINS_PER_HOUR        60
      41                 :            : #define PDF_HOURS_PER_DAY        24
      42                 :            : #define PDF_MINS_PER_DAY       1440
      43                 :            : #define PDF_DAYS_IN_YEAR        365
      44                 :            : #define PDF_DAYS_IN_LEAP_YEAR   366
      45                 :            : 
      46                 :            : enum pdf_time_cal_type_e {
      47                 :            :   PDF_TIME_CAL_LOCAL,
      48                 :            :   PDF_TIME_CAL_UTC
      49                 :            : };
      50                 :            : 
      51                 :            : enum pdf_time_month_e {
      52                 :            :   PDF_TIME_JANUARY    = 1,
      53                 :            :   PDF_TIME_FEBRUARY   = 2,
      54                 :            :   PDF_TIME_MARCH      = 3,
      55                 :            :   PDF_TIME_APRIL      = 4,
      56                 :            :   PDF_TIME_MAY        = 5,
      57                 :            :   PDF_TIME_JUNE       = 6,
      58                 :            :   PDF_TIME_JULY       = 7,
      59                 :            :   PDF_TIME_AUGUST     = 8,
      60                 :            :   PDF_TIME_SEPTEMBER  = 9,
      61                 :            :   PDF_TIME_OCTOBER    = 10,
      62                 :            :   PDF_TIME_NOVEMBER   = 11,
      63                 :            :   PDF_TIME_DECEMBER   = 12,
      64                 :            :   PDF_TIME_NMONTHS
      65                 :            : };
      66                 :            : 
      67                 :            : /* Returns PDF_TRUE if the Olimpic Games [were/will be] celebrated in the given
      68                 :            :  *  year. A leap year is divisable by 4, but not by 100, except if divisable by
      69                 :            :  *  400 */
      70                 :            : #define IS_LEAP_YEAR(year)                      \
      71                 :            :   (((year % 4 == 0) &&                          \
      72                 :            :     ((year % 100 != 0) ||                       \
      73                 :            :      (year % 400 == 0))) ?                      \
      74                 :            :    PDF_TRUE : PDF_FALSE)
      75                 :            : 
      76                 :            : /* Returns number of days in the given month (year-dependent due to leap
      77                 :            :  * years) */
      78                 :            : static pdf_u32_t
      79                 :    1749363 : pdf_time_get_days_in_month (const pdf_u32_t             year,
      80                 :            :                             const enum pdf_time_month_e month)
      81                 :            : {
      82   [ +  +  +  - ]:    1749363 :   switch (month)
      83                 :            :   {
      84                 :            :     case PDF_TIME_JANUARY:
      85                 :            :     case PDF_TIME_MARCH:
      86                 :            :     case PDF_TIME_MAY:
      87                 :            :     case PDF_TIME_JULY:
      88                 :            :     case PDF_TIME_AUGUST:
      89                 :            :     case PDF_TIME_OCTOBER:
      90                 :            :     case PDF_TIME_DECEMBER:
      91                 :    1012536 :       return 31;
      92                 :            :     case PDF_TIME_APRIL:
      93                 :            :     case PDF_TIME_JUNE:
      94                 :            :     case PDF_TIME_SEPTEMBER:
      95                 :            :     case PDF_TIME_NOVEMBER:
      96                 :     481738 :       return 30;
      97                 :            :     case PDF_TIME_FEBRUARY:
      98 [ +  + ][ +  + ]:     255089 :       return (IS_LEAP_YEAR (year) ? 29 : 28);
                 [ +  - ]
      99                 :            :     default:
     100                 :    1749363 :       return 0;
     101                 :            :   }
     102                 :            : }
     103                 :            : 
     104                 :            : /* Returns number of days before the given month */
     105                 :            : static pdf_u32_t
     106                 :            : pdf_time_get_days_before_month (const pdf_u32_t            year,
     107                 :            :                                const enum pdf_time_month_e month)
     108                 :            : {
     109                 :     310134 :   enum pdf_time_month_e walk = PDF_TIME_JANUARY;
     110                 :     310134 :   pdf_u32_t sum = 0;
     111                 :            : 
     112 [ +  + ][ +  + ]:    1948338 :   while (walk != month) {
                 [ +  + ]
     113                 :    1638204 :     sum += pdf_time_get_days_in_month (year, walk++);
     114                 :            :   }
     115                 :            : 
     116                 :     310134 :   return sum;
     117                 :            : }
     118                 :            : 
     119                 :            : /* Get Break-Down calendar from pdf_time_t */
     120                 :            : static void
     121                 :      35505 : pdf_time_get_cal (const pdf_time_t               *time_var,
     122                 :            :                   const enum pdf_time_cal_type_e  cal_type,
     123                 :            :                   struct pdf_time_cal_s          *cal_time)
     124                 :            : {
     125                 :            :   /* Based on glibc's __offtime function */
     126                 :            : 
     127                 :            :   pdf_i32_t days;
     128                 :            :   pdf_i32_t remaining;
     129                 :            :   pdf_i32_t years;
     130                 :            :   pdf_i32_t months;
     131                 :            :   pdf_time_t new_time_var;
     132                 :            : 
     133                 :            :   /* Duplicate time var */
     134                 :      35505 :   pdf_time_init_dup (&new_time_var, time_var);
     135                 :            : 
     136                 :            :   /* pdf_time_t always stores the date & time in UTC timescale, so we only need
     137                 :            :    *  to modify the time_var IF gmt_offset is not zero, in order to move the
     138                 :            :    *  date & time from UTC to local time specified by the offset */
     139   [ +  +  +  + ]:      35505 :   if ((cal_type == PDF_TIME_CAL_LOCAL) &&
     140                 :      17313 :       (time_var->gmt_offset != 0))
     141                 :            :     {
     142                 :      16876 :       pdf_time_add_span (&new_time_var, time_var->gmt_offset);
     143                 :            :     }
     144                 :            : 
     145                 :            :   /* Get date as days */
     146                 :      35505 :   days = (pdf_i32_t) (new_time_var.seconds / PDF_SECS_PER_DAY);
     147                 :            :   /* Get time in seconds */
     148                 :      35505 :   remaining = (pdf_i32_t) (new_time_var.seconds % PDF_SECS_PER_DAY);
     149                 :            :   /* Get hours */
     150                 :      35505 :   cal_time->hour = remaining / PDF_SECS_PER_HOUR;
     151                 :            :   /* Get remaining */
     152                 :      35505 :   remaining = remaining % PDF_SECS_PER_HOUR;
     153                 :            :   /* Get minutes */
     154                 :      35505 :   cal_time->minute = remaining / PDF_MINS_PER_HOUR;
     155                 :            :   /* Get seconds */
     156                 :      35505 :   cal_time->second = remaining % PDF_MINS_PER_HOUR;
     157                 :            : 
     158                 :            :   /* Seems that Unix origin time was thursday */
     159                 :      35505 :   cal_time->dow = ((days + 4) % 7);
     160                 :            : 
     161                 :      35505 :   years = 1970;
     162                 :            : 
     163 [ +  + ][ +  + ]:     120420 :   while ((days < 0) ||
     164 [ +  + ][ +  + ]:      59213 :          (days >= (IS_LEAP_YEAR (years) ?
                 [ +  - ]
     165                 :            :                    (PDF_DAYS_IN_YEAR + 1) :
     166                 :            :                    (PDF_DAYS_IN_YEAR))))
     167                 :            :     {
     168                 :            :       pdf_i32_t yg;
     169                 :            : 
     170                 :      25702 :       yg = years;
     171                 :            :       /* Compute number of years (assuming all years of 365 days) between the
     172                 :            :        *  origin and our date */
     173                 :      25702 :       yg += (days / PDF_DAYS_IN_YEAR);
     174                 :            :       /* Get number of remaining days after having added the fixed-size years
     175                 :            :          If the number of remaining days is less than zero, go down 1 year */
     176                 :      25702 :       yg -= ((days % PDF_DAYS_IN_YEAR) < 0);
     177                 :            : 
     178                 :            : #define LEAPS_THRU_END_OF(y) ((y) / 4 - (y) / 100 + (y) / 400)
     179                 :            :       /* Remove number of days due to the leap years */
     180                 :     154212 :       days -= (((yg - years)*PDF_DAYS_IN_YEAR) +
     181                 :      77106 :                (LEAPS_THRU_END_OF (yg - 1)) -
     182                 :      77106 :                (LEAPS_THRU_END_OF (years - 1)));
     183                 :      25702 :       years = yg;
     184                 :            :     }
     185                 :            : 
     186                 :            :   /* Set year */
     187                 :      35505 :   cal_time->year = years; /* - 1900; */
     188                 :            : 
     189         [ +  + ]:     256758 :   for (months = 11;
     190                 :     221253 :        days < pdf_time_get_days_before_month (cal_time->year,months);
     191                 :     185748 :        --months)
     192                 :     185748 :     continue;
     193                 :            : 
     194                 :      71010 :   days -= pdf_time_get_days_before_month (cal_time->year,months);
     195                 :            : 
     196                 :            :   /* Set month and day of month */
     197                 :      35505 :   cal_time->month = months;
     198         [ +  + ]:      35505 :   if (pdf_time_get_days_in_month (cal_time->year,
     199                 :      71010 :                                   cal_time->month) < (days + 1))
     200                 :            :     {
     201                 :      15841 :       cal_time->day = days + 1 - pdf_time_get_days_in_month (cal_time->year,
     202                 :      15841 :                                                              cal_time->month);
     203                 :      15841 :       cal_time->month += 1;
     204         [ -  + ]:      15841 :       if (cal_time->month == 13)
     205                 :            :         {
     206                 :          0 :           cal_time->month = 1;
     207                 :          0 :           cal_time->year += 1;
     208                 :            :         }
     209                 :            :     }
     210                 :            :   else
     211                 :            :     {
     212                 :      19664 :       cal_time->day = days + 1;
     213                 :            :     }
     214                 :            : 
     215                 :            :   /* Finally, set gmt offset */
     216                 :      35505 :   cal_time->gmt_offset = new_time_var.gmt_offset;
     217                 :            : 
     218                 :      35505 :   pdf_time_deinit (&new_time_var);
     219                 :      35505 : }
     220                 :            : 
     221                 :            : /* Function to normalize a given date after having added YEARS */
     222                 :            : static void
     223                 :            : pdf_time_calendar_add_years (struct pdf_time_cal_s *p_calendar,
     224                 :            :                              const pdf_i32_t        delta_years)
     225                 :            : {
     226                 :            :   pdf_i32_t years;
     227                 :            : 
     228         [ +  + ]:       5792 :   if (delta_years == 0)
     229                 :            :     return;
     230                 :            : 
     231                 :            :   /* ADD years */
     232                 :       3632 :   years = p_calendar->year + delta_years;
     233                 :            : 
     234                 :            :   /* The only thing to normalize is in case we reach Feb.29 in a non-leap
     235                 :            :    *  year */
     236 [ +  + ][ +  + ]:       3632 :   if ((!IS_LEAP_YEAR (years)) &&
         [ -  + ][ -  + ]
     237                 :            :       (p_calendar->month == PDF_TIME_FEBRUARY) &&
     238                 :            :       (p_calendar->day == 29))
     239                 :            :     {
     240                 :          0 :       p_calendar->day = 28;
     241                 :            :     }
     242                 :            : 
     243         [ -  + ]:       3632 :   PDF_ASSERT (years >= 0);
     244                 :       3632 :   p_calendar->year = years;
     245                 :            : }
     246                 :            : 
     247                 :            : /* Function to normalize a given date after having added MONTHS */
     248                 :            : static void
     249                 :       6032 : pdf_time_calendar_add_months (struct pdf_time_cal_s *p_calendar,
     250                 :            :                               const pdf_i32_t        delta_months)
     251                 :            : {
     252         [ +  + ]:       6032 :   if (delta_months == 0)
     253                 :            :     return;
     254                 :            : 
     255         [ +  + ]:       4256 :   if (delta_months > 0)
     256                 :            :     {
     257                 :       3440 :       p_calendar->month += delta_months;
     258         [ -  + ]:       3440 :       while (p_calendar->month > 12)
     259                 :            :         {
     260                 :          0 :           p_calendar->month -= 12;
     261                 :          0 :           p_calendar->year++;
     262                 :            :         }
     263                 :            :     }
     264                 :            :   else
     265                 :            :     {
     266                 :            :       pdf_i32_t months;
     267                 :            : 
     268                 :        816 :       months = p_calendar->month + delta_months;
     269         [ +  + ]:       1056 :       while (months < 1)
     270                 :            :         {
     271                 :        240 :           months += 12;
     272                 :        240 :           p_calendar->year--;
     273                 :            :         }
     274                 :            : 
     275         [ -  + ]:        816 :       PDF_ASSERT (months >= 1);
     276         [ -  + ]:        816 :       PDF_ASSERT (months <= 12);
     277                 :        816 :       p_calendar->month = months;
     278                 :            :     }
     279                 :            : 
     280                 :            :   /* After having added months, we could need to normalize the days */
     281         [ +  + ]:       4256 :   if (pdf_time_get_days_in_month (p_calendar->year,
     282                 :       4256 :                                   p_calendar->month) < p_calendar->day)
     283                 :            :     {
     284                 :        121 :       p_calendar->day = pdf_time_get_days_in_month (p_calendar->year,
     285                 :        121 :                                                     p_calendar->month);
     286                 :            :     }
     287                 :            : 
     288         [ -  + ]:       4256 :   PDF_ASSERT (p_calendar->month >= 1);
     289         [ -  + ]:       6032 :   PDF_ASSERT (p_calendar->month <= 12);
     290                 :            : }
     291                 :            : 
     292                 :            : /* Function to normalize a given date after having added DAYS */
     293                 :            : static void
     294                 :       7950 : pdf_time_calendar_add_days (struct pdf_time_cal_s *p_calendar,
     295                 :            :                             const pdf_i32_t        delta_days)
     296                 :            : {
     297                 :       7950 :   pdf_i32_t delta = delta_days;
     298                 :            : 
     299         [ +  + ]:       7950 :   if (delta_days == 0)
     300                 :            :     return;
     301                 :            : 
     302                 :            :   /* ADD days */
     303         [ +  + ]:       2060 :   if (delta_days > 0)
     304                 :            :     {
     305                 :            :       pdf_i32_t days_in_month;
     306                 :            : 
     307                 :            :       /* Initialize days in month */
     308                 :       1820 :       days_in_month = pdf_time_get_days_in_month (p_calendar->year,
     309                 :            :                                                   (enum pdf_time_month_e)p_calendar->month);
     310         [ -  + ]:       1820 :       while (delta > (days_in_month - p_calendar->day))
     311                 :            :         {
     312                 :            :           /* Go to start of next month */
     313                 :          0 :           p_calendar->day = 1;
     314                 :          0 :           pdf_time_calendar_add_months (p_calendar, 1);
     315                 :            : 
     316                 :            :           /* Update remaining delta and new days_in_month */
     317                 :          0 :           delta -= (days_in_month - p_calendar->day + 1);
     318                 :          0 :           days_in_month = pdf_time_get_days_in_month (p_calendar->year,
     319                 :            :                                                       (enum pdf_time_month_e)p_calendar->month);
     320                 :            :         }
     321                 :            :       /* Add final delta, which doesn't require month change */
     322                 :       1820 :       p_calendar->day += delta;
     323                 :            :     }
     324                 :            :   /* SUBSTRACT days */
     325                 :            :   else
     326                 :            :     {
     327                 :            :       pdf_i32_t days_in_month;
     328                 :            : 
     329                 :            :       /* Initialize days in month */
     330                 :        240 :       days_in_month = p_calendar->day - 1;
     331                 :            : 
     332         [ +  + ]:        480 :       while (days_in_month <= (-delta))
     333                 :            :         {
     334                 :            :           /* Go to the begin of previous month */
     335                 :        240 :           p_calendar->day = 1;
     336                 :        240 :           pdf_time_calendar_add_months (p_calendar, -1);
     337                 :            : 
     338                 :            :           /* Update remaining delta and new days_in_month */
     339                 :        240 :           delta += days_in_month;
     340                 :        240 :           days_in_month = pdf_time_get_days_in_month (p_calendar->year,
     341                 :            :                                                       (enum pdf_time_month_e)p_calendar->month);
     342                 :            :         }
     343                 :            :       /* Add final delta, which doesn't require month change */
     344                 :        240 :       delta += days_in_month;
     345                 :        240 :       p_calendar->day += delta;
     346                 :            :     }
     347                 :            : 
     348         [ -  + ]:       2060 :   PDF_ASSERT (p_calendar->month >= 1);
     349         [ -  + ]:       7950 :   PDF_ASSERT (p_calendar->month <= 12);
     350                 :            : }
     351                 :            : 
     352                 :            : /* Function to normalize a given date after having added HOURS */
     353                 :            : static void
     354                 :       8400 : pdf_time_calendar_add_hours (struct pdf_time_cal_s *p_calendar,
     355                 :            :                              const pdf_i32_t        delta_hours)
     356                 :            : {
     357                 :            :   pdf_i32_t hours;
     358                 :            :   pdf_i32_t days;
     359                 :            :   pdf_i32_t remaining_hours;
     360                 :            : 
     361         [ +  + ]:       8400 :   if (delta_hours == 0)
     362                 :            :     return;
     363                 :            : 
     364                 :            :   /* No real problem with hours, as 1 day is always 24h */
     365                 :       2158 :   days = delta_hours / PDF_HOURS_PER_DAY;
     366                 :       2158 :   remaining_hours = delta_hours % PDF_HOURS_PER_DAY;
     367                 :            : 
     368                 :            :   /* Add remaining hours */
     369                 :       2158 :   hours = p_calendar->hour + remaining_hours;
     370                 :            : 
     371                 :            :   /* If we went back to the previous day, correct time and add 1 day more
     372                 :            :    * to remove */
     373         [ -  + ]:       2158 :   if (hours < 0)
     374                 :            :     {
     375                 :          0 :       hours += PDF_HOURS_PER_DAY;
     376                 :          0 :       days--;
     377                 :            :     }
     378                 :            :   /* If we went forward to the next day, correct time and add 1 day more
     379                 :            :    * to add */
     380         [ -  + ]:       2158 :   else if (hours >= PDF_HOURS_PER_DAY)
     381                 :            :     {
     382                 :          0 :       hours -= PDF_HOURS_PER_DAY;
     383                 :          0 :       days++;
     384                 :            :     }
     385                 :            : 
     386         [ -  + ]:       2158 :   PDF_ASSERT (hours >= 0);
     387         [ -  + ]:       2158 :   PDF_ASSERT (hours < 24);
     388                 :       2158 :   p_calendar->hour = hours;
     389                 :            : 
     390                 :            :   /* Add/Remove days... */
     391                 :       8400 :   pdf_time_calendar_add_days (p_calendar, days);
     392                 :            : }
     393                 :            : 
     394                 :            : /* Function to normalize a given date after having added MINUTES */
     395                 :            : static void
     396                 :       8760 : pdf_time_calendar_add_minutes (struct pdf_time_cal_s *p_calendar,
     397                 :            :                                const pdf_i32_t        delta_minutes)
     398                 :            : {
     399                 :            :   pdf_i32_t minutes;
     400                 :            :   pdf_i32_t hours;
     401                 :            :   pdf_i32_t remaining_minutes;
     402                 :            : 
     403         [ +  + ]:       8760 :   if (delta_minutes == 0)
     404                 :            :     return;
     405                 :            : 
     406                 :            :   /* No real problem with minutes, as 1 hour is always 60minutes */
     407                 :       2608 :   hours = delta_minutes / PDF_MINS_PER_HOUR;
     408                 :       2608 :   remaining_minutes = delta_minutes % PDF_MINS_PER_HOUR;
     409                 :            : 
     410                 :            :   /* Add remaining minutes */
     411                 :       2608 :   minutes = p_calendar->minute + remaining_minutes;
     412                 :            : 
     413                 :            :   /* If we went back to the previous hour, correct time and add 1 hour more
     414                 :            :    * to remove */
     415         [ -  + ]:       2608 :   if (minutes < 0)
     416                 :            :     {
     417                 :          0 :       minutes += PDF_MINS_PER_HOUR;
     418                 :          0 :       hours--;
     419                 :            :     }
     420                 :            :   /* If we went forward to the next day, correct time and add 1 hour more
     421                 :            :    * to add */
     422         [ -  + ]:       2608 :   else if (minutes >= PDF_MINS_PER_HOUR)
     423                 :            :     {
     424                 :          0 :       minutes -= PDF_MINS_PER_HOUR;
     425                 :          0 :       hours++;
     426                 :            :     }
     427                 :            : 
     428         [ -  + ]:       2608 :   PDF_ASSERT (minutes >= 0);
     429         [ -  + ]:       2608 :   PDF_ASSERT (minutes < 60);
     430                 :       2608 :   p_calendar->minute = minutes;
     431                 :            : 
     432                 :            :   /* Add/Remove hours... */
     433                 :       8760 :   pdf_time_calendar_add_hours (p_calendar, hours);
     434                 :            : }
     435                 :            : 
     436                 :            : /* Function to normalize a given date after having added SECONDS */
     437                 :            : static void
     438                 :            : pdf_time_calendar_add_seconds (struct pdf_time_cal_s *p_calendar,
     439                 :            :                                const pdf_i32_t        delta_seconds)
     440                 :            : {
     441                 :            :   pdf_i32_t seconds;
     442                 :            :   pdf_i32_t minutes;
     443                 :            :   pdf_i32_t remaining_seconds;
     444                 :            : 
     445         [ +  + ]:       5792 :   if (delta_seconds == 0)
     446                 :            :     return;
     447                 :            : 
     448                 :            :   /* No real problem with minutes, as 1 hour is always 60minutes */
     449                 :       2968 :   minutes = delta_seconds / PDF_SECS_PER_MIN;
     450                 :       2968 :   remaining_seconds = delta_seconds % PDF_SECS_PER_MIN;
     451                 :            : 
     452                 :            :   /* Add remaining seconds */
     453                 :       2968 :   seconds = p_calendar->second + remaining_seconds;
     454                 :            : 
     455                 :            :   /* If we went back to the previous minute, correct time and add 1 minute more
     456                 :            :    * to remove */
     457         [ -  + ]:       2968 :   if (seconds < 0)
     458                 :            :     {
     459                 :          0 :       seconds += PDF_SECS_PER_MIN;
     460                 :          0 :       minutes--;
     461                 :            :     }
     462                 :            :   /* If we went forward to the next minute, correct time and add 1 minute more
     463                 :            :    * to add */
     464         [ -  + ]:       2968 :   else if (seconds >= PDF_SECS_PER_MIN)
     465                 :            :     {
     466                 :          0 :       seconds -= PDF_SECS_PER_MIN;
     467                 :          0 :       minutes++;
     468                 :            :     }
     469                 :            : 
     470         [ -  + ]:       2968 :   PDF_ASSERT (seconds >= 0);
     471         [ -  + ]:       2968 :   PDF_ASSERT (seconds < 60);
     472                 :       2968 :   p_calendar->second = seconds;
     473                 :            : 
     474                 :            :   /* Add/Remove minutes... */
     475                 :       2968 :   pdf_time_calendar_add_minutes (p_calendar, minutes);
     476                 :            : }
     477                 :            : 
     478                 :            : /* --------------------- Time Module Initialization ------------------------- */
     479                 :            : 
     480                 :            : /* Initialize Time module. */
     481                 :            : pdf_bool_t
     482                 :        745 : pdf_time_module_init (pdf_error_t **error)
     483                 :            : {
     484                 :            :   /* Start Time context */
     485                 :        745 :   return pdf_time_context_init (error);
     486                 :            : }
     487                 :            : 
     488                 :            : /* --------------------- Time Creation and Destruction ---------------------- */
     489                 :            : 
     490                 :            : static pdf_time_t *
     491                 :          6 : pdf_time_allocate (pdf_error_t **error)
     492                 :            : {
     493                 :            :   pdf_time_t *time_var;
     494                 :            : 
     495                 :            :   /* Allocate object & Initialize all contents */
     496                 :          6 :   time_var = (pdf_time_t *) pdf_alloc (sizeof(struct pdf_time_s));
     497         [ -  + ]:          6 :   if (!time_var)
     498                 :            :     {
     499                 :          0 :       pdf_set_error (error,
     500                 :            :                      PDF_EDOMAIN_BASE_TIME,
     501                 :            :                      PDF_ENOMEM,
     502                 :            :                      "cannot create new time object: "
     503                 :            :                      "couldn't allocate %lu bytes",
     504                 :            :                      (unsigned long)sizeof (struct pdf_time_s));
     505                 :            :     }
     506                 :            : 
     507                 :          6 :   return time_var;
     508                 :            : }
     509                 :            : 
     510                 :            : /* Create new pdf_time_t object in heap */
     511                 :            : pdf_time_t *
     512                 :          4 : pdf_time_new (pdf_error_t **error)
     513                 :            : {
     514                 :            :   pdf_time_t *time_var;
     515                 :            : 
     516                 :          4 :   time_var = pdf_time_allocate (error);
     517         [ +  - ]:          4 :   if (time_var)
     518                 :          4 :     pdf_time_clear (time_var);
     519                 :            : 
     520                 :          4 :   return time_var;
     521                 :            : }
     522                 :            : 
     523                 :            : /* Duplicate pdf_time_t object in heap */
     524                 :            : pdf_time_t *
     525                 :          2 : pdf_time_dup (const pdf_time_t  *time_var_orig,
     526                 :            :               pdf_error_t      **error)
     527                 :            : {
     528                 :            :   pdf_time_t *time_var;
     529                 :            : 
     530         [ -  + ]:          2 :   PDF_ASSERT_POINTER_RETURN_VAL (time_var_orig, NULL);
     531                 :            : 
     532                 :          2 :   time_var = pdf_time_allocate (error);
     533         [ +  - ]:          2 :   if (time_var)
     534                 :          2 :     pdf_time_copy (time_var, time_var_orig);
     535                 :            : 
     536                 :          2 :   return time_var;
     537                 :            : }
     538                 :            : 
     539                 :            : /* Destroy a pdf_time_t object from heap */
     540                 :            : void
     541                 :          6 : pdf_time_destroy (pdf_time_t *time_var)
     542                 :            : {
     543         [ +  - ]:          6 :   if (time_var)
     544                 :          6 :     pdf_dealloc (time_var);
     545                 :          6 : }
     546                 :            : 
     547                 :            : /* Initializes a preallocated (heap or stack) pdf_time_t */
     548                 :            : void
     549                 :      90981 : pdf_time_init (pdf_time_t *time_var)
     550                 :            : {
     551         [ -  + ]:      90981 :   PDF_ASSERT_POINTER_RETURN (time_var);
     552                 :            : 
     553                 :      90981 :   pdf_time_clear (time_var);
     554                 :            : }
     555                 :            : 
     556                 :            : /* Initializes a preallocated (heap or stack) pdf_time_t with same contents as
     557                 :            :  * another given pdf_time_t. Just a sequence of
     558                 :            :  * pdf_time_init() + pdf_time_copy() */
     559                 :            : void
     560                 :      39853 : pdf_time_init_dup (pdf_time_t       *time_var,
     561                 :            :                    const pdf_time_t *time_var_orig)
     562                 :            : {
     563         [ -  + ]:      39853 :   PDF_ASSERT_POINTER_RETURN (time_var_orig);
     564         [ -  + ]:      39853 :   PDF_ASSERT_POINTER_RETURN (time_var);
     565                 :            : 
     566                 :      39853 :   pdf_time_copy (time_var, time_var_orig);
     567                 :            : }
     568                 :            : 
     569                 :            : void
     570                 :     112817 : pdf_time_deinit (pdf_time_t *time_var)
     571                 :            : {
     572                 :            :   /* Currently a no-op */
     573                 :     112817 : }
     574                 :            : 
     575                 :            : /* ------------------------- Managing Time Values --------------------------- */
     576                 :            : 
     577                 :            : /* Copy the contents of a given pdf_time_t object */
     578                 :            : void
     579                 :      39856 : pdf_time_copy (pdf_time_t       *copy,
     580                 :            :                const pdf_time_t *orig)
     581                 :            : {
     582         [ -  + ]:      39856 :   PDF_ASSERT_POINTER_RETURN (orig);
     583         [ -  + ]:      39856 :   PDF_ASSERT_POINTER_RETURN (copy);
     584                 :            : 
     585                 :      39856 :   copy->seconds = orig->seconds;
     586                 :      39856 :   copy->gmt_offset = orig->gmt_offset;
     587                 :            : }
     588                 :            : 
     589                 :            : /* Clear contents of the pdf_time_t object */
     590                 :            : void
     591                 :      92666 : pdf_time_clear (pdf_time_t *time_var)
     592                 :            : {
     593                 :            :   /* Set time as January 1st, 1970 */
     594                 :      92666 :   time_var->seconds = 0;
     595                 :            :   /* UTC */
     596                 :      92666 :   time_var->gmt_offset = 0;
     597                 :      92666 : }
     598                 :            : 
     599                 :            : /* Set time value with a pdf_i64_t variable representing UTC Unix time */
     600                 :            : void
     601                 :      33453 : pdf_time_set_utc (pdf_time_t *time_var,
     602                 :            :                   pdf_i64_t   utc_seconds)
     603                 :            : {
     604         [ -  + ]:      33453 :   PDF_ASSERT_POINTER_RETURN (time_var);
     605                 :            : 
     606                 :      33453 :   time_var->seconds = utc_seconds;
     607                 :      33453 :   time_var->gmt_offset = 0;
     608                 :            : }
     609                 :            : 
     610                 :            : /* Set time value with a pdf_i64_t variable representing Local Unix time */
     611                 :            : void
     612                 :          0 : pdf_time_set_local (pdf_time_t *time_var,
     613                 :            :                     pdf_i64_t   local_seconds,
     614                 :            :                     pdf_i32_t   local_gmt_offset)
     615                 :            : {
     616         [ #  # ]:          0 :   PDF_ASSERT_POINTER_RETURN (time_var);
     617                 :            : 
     618                 :            :   /* pdf_time_t always stores seconds in UTC */
     619                 :          0 :   time_var->seconds = local_seconds - local_gmt_offset;
     620                 :          0 :   time_var->gmt_offset = local_gmt_offset;
     621                 :            : }
     622                 :            : 
     623                 :            : #ifdef PDF_HOST_WIN32
     624                 :            : /* Windows-specific function to set the time with a FILETIME structure */
     625                 :            : pdf_bool_t
     626                 :            : pdf_time_w32_set_from_filetime (pdf_time_t      *time_var,
     627                 :            :                                 const FILETIME  *filetime,
     628                 :            :                                 pdf_error_t    **error)
     629                 :            : {
     630                 :            :   struct pdf_time_cal_s calendar;
     631                 :            :   SYSTEMTIME systemtime;
     632                 :            : 
     633                 :            :   /*
     634                 :            :     BOOL WINAPI
     635                 :            :     FileTimeToSystemTime(const FILETIME *lpFileTime,
     636                 :            :                          LPSYSTEMTIME lpSystemTime);
     637                 :            : 
     638                 :            :     If the function succeeds, the return value is nonzero.
     639                 :            : 
     640                 :            :     typedef struct _SYSTEMTIME {
     641                 :            :       WORD wYear;
     642                 :            :       WORD wMonth;        (1: january, 2: february...)
     643                 :            :       WORD wDayOfWeek;    (0:sunday, 1: monday...)
     644                 :            :       WORD wDay;
     645                 :            :       WORD wHour;
     646                 :            :       WORD wMinute;
     647                 :            :       WORD wSecond;
     648                 :            :       WORD wMilliseconds;
     649                 :            :     } SYSTEMTIME;
     650                 :            : 
     651                 :            :    */
     652                 :            : 
     653                 :            :   /* Convert filetime to systemtime calendar */
     654                 :            :   if (FileTimeToSystemTime (filetime, &systemtime) == 0)
     655                 :            :     {
     656                 :            :       /* TODO: Use FormatMessage() to include a string with the exact error
     657                 :            :        * in the pdf_error_t */
     658                 :            :       pdf_set_error (error,
     659                 :            :                      PDF_EDOMAIN_BASE_TIME,
     660                 :            :                      PDF_ERROR,
     661                 :            :                      "couldn't get system time from FILETIME: %d",
     662                 :            :                      (pdf_i32_t)GetLastError ());
     663                 :            :       return PDF_FALSE;
     664                 :            :     }
     665                 :            : 
     666                 :            :   /* Convert from systemtime calendar to our pdf_time_cal_s */
     667                 :            :   calendar.year = systemtime.wYear;
     668                 :            :   calendar.month = systemtime.wMonth;
     669                 :            :   calendar.day = systemtime.wDay;
     670                 :            :   calendar.hour = systemtime.wHour;
     671                 :            :   calendar.minute = systemtime.wMinute;
     672                 :            :   calendar.second = systemtime.wSecond;
     673                 :            :   /* Round seconds if milliseconds available */
     674                 :            :   if (systemtime.wMilliseconds >= 500)
     675                 :            :     calendar.second++;
     676                 :            : 
     677                 :            :   /* Store as UTC? */
     678                 :            :   calendar.gmt_offset = 0;
     679                 :            : 
     680                 :            :   /* For us, sunday is 7 */
     681                 :            :   calendar.dow = (systemtime.wDayOfWeek == 0) ? 7 : systemtime.wDayOfWeek;
     682                 :            : 
     683                 :            :   pdf_time_set_from_cal (time_var, &calendar);
     684                 :            : 
     685                 :            :   return PDF_TRUE;
     686                 :            : }
     687                 :            : #endif
     688                 :            : 
     689                 :            : /*
     690                 :            : *  Based on the work done by Perl guys in DateTime:
     691                 :            : *  http://search.cpan.org/dist/DateTime/lib/DateTime.pm#Adding_a_Duration_to_a_Datetime
     692                 :            : *
     693                 :            : *  "DateTime.pm always adds (or subtracts) days, then months, minutes, and then
     694                 :            : *   seconds and nanoseconds. If there are any boundary overflows, these are
     695                 :            : *   normalized at each step. For the days and months (the calendar) the local
     696                 :            : *   (not UTC) values are used. For minutes and seconds, the local values are
     697                 :            : *   used. This generally just works.
     698                 :            : *
     699                 :            : *   This means that adding one month and one day to February 28, 2003 will
     700                 :            : *   produce the date April 1, 2003, not March 29, 2003."
     701                 :            : *
     702                 :            : * Thanks to S.Jansen for the link!
     703                 :            : */
     704                 :            : static void
     705                 :       5792 : pdf_time_add_cal_span_with_sign (pdf_time_t                       *time_var,
     706                 :            :                                  const struct pdf_time_cal_span_s *cal_span,
     707                 :            :                                  pdf_bool_t                        negate)
     708                 :            : {
     709                 :            :   struct pdf_time_cal_s calendar;
     710                 :            :   pdf_i32_t sign;
     711                 :            : 
     712         [ +  + ]:       5792 :   sign = (negate ? -1 : 1);
     713                 :            : 
     714                 :            :   /* Create Calendar type from the time object */
     715                 :       5792 :   pdf_time_get_utc_cal (time_var, &calendar);
     716                 :       5792 :   pdf_time_calendar_add_days    (&calendar,  sign * cal_span->days);
     717                 :       5792 :   pdf_time_calendar_add_months  (&calendar,  sign * cal_span->months);
     718                 :       5792 :   pdf_time_calendar_add_years   (&calendar,  sign * cal_span->years);
     719                 :       5792 :   pdf_time_calendar_add_hours   (&calendar,  sign * cal_span->hours);
     720                 :       5792 :   pdf_time_calendar_add_minutes (&calendar,  sign * cal_span->minutes);
     721                 :       5792 :   pdf_time_calendar_add_seconds (&calendar,  sign * cal_span->seconds);
     722                 :            : 
     723                 :            :   /* Check for possible underflow condition */
     724         [ +  + ]:       5792 :   if (calendar.year < 1970)
     725                 :            :     {
     726                 :            :       /* If underflow, reset the time to Unix time origin */
     727                 :        240 :       pdf_time_clear (time_var);
     728                 :        240 :       return;
     729                 :            :     }
     730                 :            : 
     731                 :            :   /* Generate time from the new calendar */
     732                 :       5792 :   pdf_time_set_from_cal (time_var, &calendar);
     733                 :            : }
     734                 :            : 
     735                 :            : /* Add the time span represented by cal_span to the text object. */
     736                 :            : void
     737                 :       5072 : pdf_time_add_cal_span (pdf_time_t                       *time_var,
     738                 :            :                        const struct pdf_time_cal_span_s *cal_span)
     739                 :            : {
     740         [ -  + ]:       5072 :   PDF_ASSERT_POINTER_RETURN (time_var);
     741         [ -  + ]:       5072 :   PDF_ASSERT_POINTER_RETURN (cal_span);
     742                 :            : 
     743                 :       5072 :   pdf_time_add_cal_span_with_sign (time_var,
     744                 :            :                                    cal_span,
     745                 :            :                                    PDF_FALSE);
     746                 :            : }
     747                 :            : 
     748                 :            : /* Substract the time span represented by cal_span from the text object */
     749                 :            : void
     750                 :        720 : pdf_time_sub_cal_span (pdf_time_t                       *time_var,
     751                 :            :                        const struct pdf_time_cal_span_s *cal_span)
     752                 :            : {
     753         [ -  + ]:        720 :   PDF_ASSERT_POINTER_RETURN (time_var);
     754         [ -  + ]:        720 :   PDF_ASSERT_POINTER_RETURN (cal_span);
     755                 :            : 
     756                 :        720 :   pdf_time_add_cal_span_with_sign (time_var,
     757                 :            :                                    cal_span,
     758                 :            :                                    PDF_TRUE);
     759                 :            : }
     760                 :            : 
     761                 :            : /* Add the time span contained in time_span to time. As the time span is stored
     762                 :            :  * in seconds, the adding is direct. */
     763                 :            : void
     764                 :      18317 : pdf_time_add_span (pdf_time_t *time_var,
     765                 :            :                    pdf_i32_t   time_span)
     766                 :            : {
     767         [ -  + ]:      18317 :   PDF_ASSERT_POINTER_RETURN (time_var);
     768                 :            :   /*
     769                 :            :    * TODO: Why does this fail?
     770                 :            :    * PDF_ASSERT_RETURN ((PDF_U64_MAX - time_var->seconds) >= time_span);
     771                 :            :    **/
     772                 :            : 
     773                 :      18317 :   time_var->seconds += time_span;
     774                 :            : }
     775                 :            : 
     776                 :            : /* Subtract the time span contained in time_span to time. As the time span is
     777                 :            :  * stored in seconds. */
     778                 :            : void
     779                 :          2 : pdf_time_sub_span (pdf_time_t *time_var,
     780                 :            :                    pdf_i32_t   time_span)
     781                 :            : {
     782         [ -  + ]:          2 :   PDF_ASSERT_POINTER_RETURN (time_var);
     783         [ -  + ]:          2 :   PDF_ASSERT_RETURN (time_var->seconds >= time_span);
     784                 :            : 
     785                 :          2 :   time_var->seconds -= time_span;
     786                 :            : }
     787                 :            : 
     788                 :            : /* Fill local_cal with the local calendar time of object. */
     789                 :            : void
     790                 :      17313 : pdf_time_get_local_cal (const pdf_time_t      *time_var,
     791                 :            :                         struct pdf_time_cal_s *local_cal)
     792                 :            : {
     793         [ -  + ]:      17313 :   PDF_ASSERT_POINTER_RETURN (time_var);
     794         [ -  + ]:      17313 :   PDF_ASSERT_POINTER_RETURN (local_cal);
     795                 :            : 
     796                 :      17313 :   pdf_time_get_cal (time_var,
     797                 :            :                     PDF_TIME_CAL_LOCAL,
     798                 :            :                     local_cal);
     799                 :            : }
     800                 :            : 
     801                 :            : /* Get the UTC calendar time of a given time variable. */
     802                 :            : void
     803                 :      13872 : pdf_time_get_utc_cal (const pdf_time_t      *time_var,
     804                 :            :                       struct pdf_time_cal_s *utc_cal)
     805                 :            : {
     806         [ -  + ]:      13872 :   PDF_ASSERT_POINTER_RETURN (time_var);
     807         [ -  + ]:      13872 :   PDF_ASSERT_POINTER_RETURN (utc_cal);
     808                 :            : 
     809                 :      13872 :   pdf_time_get_cal (time_var,
     810                 :            :                     PDF_TIME_CAL_UTC,
     811                 :            :                     utc_cal);
     812                 :            : }
     813                 :            : 
     814                 :            : /* Set the value of a time variable to a given calendar time. */
     815                 :            : void
     816                 :      53376 : pdf_time_set_from_cal (pdf_time_t                  *time_var,
     817                 :            :                        const struct pdf_time_cal_s *cal)
     818                 :            : {
     819                 :            :   pdf_u64_t aux;
     820                 :            :   pdf_i32_t walker;
     821                 :            : 
     822         [ -  + ]:      53376 :   PDF_ASSERT_POINTER_RETURN (time_var);
     823         [ -  + ]:      53376 :   PDF_ASSERT_POINTER_RETURN (cal);
     824                 :            : 
     825                 :            :   /* Wrong calendar contents are treated as programmer errors */
     826         [ -  + ]:      53376 :   PDF_ASSERT_RETURN (cal->year >= 1970);
     827         [ -  + ]:      53376 :   PDF_ASSERT_RETURN (cal->month >= 1);
     828         [ -  + ]:      53376 :   PDF_ASSERT_RETURN (cal->month <= 12);
     829         [ -  + ]:      53376 :   PDF_ASSERT_RETURN (cal->day > 0);
     830         [ -  + ]:      53376 :   PDF_ASSERT_RETURN (cal->day <= pdf_time_get_days_in_month (cal->year, cal->month));
     831         [ -  + ]:      53376 :   PDF_ASSERT_RETURN (cal->hour < 24);
     832         [ -  + ]:      53376 :   PDF_ASSERT_RETURN (cal->minute < 60);
     833         [ -  + ]:      53376 :   PDF_ASSERT_RETURN (cal->second < 60);
     834                 :            : 
     835                 :            :   /* Note: There is no possible overflow with this procedure to
     836                 :            :    * get Unix time from calendar (year is 2-bytes max) */
     837                 :            : 
     838                 :            :   /* Add days per year until the current year in the calendar */
     839                 :      53376 :   aux = 0;
     840         [ +  + ]:     859365 :   for (walker = 1970; walker < cal->year; walker++)
     841                 :            :     {
     842 [ +  + ][ +  + ]:     805989 :       aux += (IS_LEAP_YEAR (walker) ?
                 [ +  - ]
     843                 :            :               PDF_DAYS_IN_LEAP_YEAR : PDF_DAYS_IN_YEAR);
     844                 :            :     }
     845                 :            : 
     846                 :            :   /* Add days per month until the current month in the calendar */
     847                 :     106752 :   aux += pdf_time_get_days_before_month (cal->year, cal->month);
     848                 :            : 
     849                 :            :   /* Add days in current month until the current required day */
     850                 :      53376 :   aux += (cal->day - 1);
     851                 :            : 
     852                 :            :   /* Set date as seconds in the output variable */
     853                 :      53376 :   time_var->seconds = aux * PDF_SECS_PER_DAY;
     854                 :            : 
     855                 :            :   /* Add hours as seconds */
     856                 :      53376 :   time_var->seconds += (cal->hour * PDF_SECS_PER_HOUR);
     857                 :            : 
     858                 :            :   /* Add minutes as seconds */
     859                 :      53376 :   time_var->seconds += (cal->minute * PDF_SECS_PER_MIN);
     860                 :            : 
     861                 :            :   /* Finally, add seconds */
     862                 :      53376 :   time_var->seconds += cal->second;
     863                 :            : 
     864                 :            :   /* Set specific GMT offset if any */
     865         [ +  + ]:      53376 :   if (cal->gmt_offset != 0)
     866                 :            :     {
     867         [ -  + ]:      45774 :       if (cal->gmt_offset > time_var->seconds)
     868                 :            :         {
     869                 :            :           /* Avoid the underflow, by just resetting seconds to zero.
     870                 :            :            * This is very unlikely to happen, so no worth having a
     871                 :            :            * pdf_error_t arg just for this. */
     872                 :          0 :           time_var->seconds = 0;
     873                 :            :         }
     874                 :            :       else
     875                 :            :         {
     876                 :            :           /* pdf_time_t always stores seconds in UTC */
     877                 :      45774 :           time_var->seconds -= cal->gmt_offset;
     878                 :            :         }
     879                 :            :     }
     880                 :            : 
     881                 :            :   /* Store the offset */
     882                 :      53376 :   time_var->gmt_offset = cal->gmt_offset;
     883                 :            : }
     884                 :            : 
     885                 :            : /* Set the local time offset of time to the one used by the operating system. */
     886                 :            : void
     887                 :         77 : pdf_time_set_local_offset (pdf_time_t *time_var)
     888                 :            : {
     889         [ -  + ]:         77 :   PDF_ASSERT_POINTER_RETURN (time_var);
     890                 :            : 
     891                 :            :   /* Set local GMT offset */
     892                 :         77 :   time_var->gmt_offset = pdf_time_context_get_gmt_offset ();
     893                 :            : }
     894                 :            : 
     895                 :            : /* ----------------------- Getting Time Intervals --------------------------- */
     896                 :            : 
     897                 :            : /* Get time interval as Calendar Span */
     898                 :            : void
     899                 :       2160 : pdf_time_diff_cal (const pdf_time_t           *time1,
     900                 :            :                    const pdf_time_t           *time2,
     901                 :            :                    struct pdf_time_cal_span_s *cal_span)
     902                 :            : {
     903                 :            :   struct pdf_time_cal_s calendar1;
     904                 :            :   struct pdf_time_cal_s calendar2;
     905                 :            :   struct pdf_time_cal_s *p_big;
     906                 :            :   struct pdf_time_cal_s *p_small;
     907                 :            :   pdf_i32_t aux;
     908                 :            : 
     909         [ -  + ]:       2160 :   PDF_ASSERT_POINTER_RETURN (time1);
     910         [ -  + ]:       2160 :   PDF_ASSERT_POINTER_RETURN (time2);
     911         [ -  + ]:       2160 :   PDF_ASSERT_POINTER_RETURN (cal_span);
     912                 :            : 
     913                 :       2160 :   pdf_time_get_cal (time1,
     914                 :            :                     PDF_TIME_CAL_UTC,
     915                 :            :                     &calendar1);
     916                 :       2160 :   pdf_time_get_cal (time2,
     917                 :            :                     PDF_TIME_CAL_UTC,
     918                 :            :                     &calendar2);
     919                 :            : 
     920                 :            :   /* Check which of the dates is bigger */
     921         [ -  + ]:       2160 :   if (pdf_time_cmp (time1, time2) > 0)
     922                 :            :     {
     923                 :          0 :       cal_span->sign = PDF_TRUE;
     924                 :          0 :       p_big = &calendar1;
     925                 :          0 :       p_small = &calendar2;
     926                 :            :     }
     927                 :            :   else
     928                 :            :     {
     929                 :       2160 :       cal_span->sign = PDF_FALSE;
     930                 :       2160 :       p_big = &calendar2;
     931                 :       2160 :       p_small = &calendar1;
     932                 :            :     }
     933                 :            : 
     934                 :            :   /* Get diff of years directly (always + or 0) */
     935                 :       2160 :   cal_span->years = p_big->year - p_small->year;
     936                 :            : 
     937                 :            : #define DIFF_AND_CORRECT(field,spanfield,spanupperfield)     \
     938                 :            :   do {                                                       \
     939                 :            :     aux = p_big->field - p_small->field;                     \
     940                 :            :     if (aux < 0) {                                           \
     941                 :            :       cal_span->spanupperfield--;                            \
     942                 :            :       cal_span->spanfield = (-1) * aux;                      \
     943                 :            :     } else {                                                 \
     944                 :            :       cal_span->spanfield = aux;                             \
     945                 :            :     }                                                        \
     946                 :            :   } while(0)
     947                 :            : 
     948                 :            :   /* Get diff of months (could be -) */
     949         [ -  + ]:       2160 :   DIFF_AND_CORRECT (month,   months,   years);
     950                 :            :   /* Get diff of days (could be -) */
     951         [ -  + ]:       2160 :   DIFF_AND_CORRECT (day,     days,     months);
     952                 :            :   /* Get diff of hours (could be -) */
     953         [ -  + ]:       2160 :   DIFF_AND_CORRECT (hour,    hours,    days);
     954                 :            :   /* Get diff of minutes (could be -) */
     955         [ -  + ]:       2160 :   DIFF_AND_CORRECT (minute,  minutes,  hours);
     956                 :            :   /* Get diff of seconds (could be -) */
     957         [ -  + ]:       2160 :   DIFF_AND_CORRECT (second,  seconds,  minutes);
     958                 :            : 
     959                 :            : #undef DIFF_AND_CORRECT
     960                 :            : }
     961                 :            : 
     962                 :            : /* Get time interval as Span */
     963                 :            : pdf_i64_t
     964                 :       2881 : pdf_time_diff (const pdf_time_t *time1,
     965                 :            :                const pdf_time_t *time2)
     966                 :            : {
     967         [ -  + ]:       2881 :   PDF_ASSERT_POINTER_RETURN_VAL (time1, -1);
     968         [ -  + ]:       2881 :   PDF_ASSERT_POINTER_RETURN_VAL (time2, -1);
     969                 :            : 
     970                 :       2881 :   return  ((pdf_i64_t)time1->seconds - (pdf_i64_t)time2->seconds);
     971                 :            : }
     972                 :            : 
     973                 :            : /* ---------------------------- Time comparison ----------------------------- */
     974                 :            : 
     975                 :            : /* Compares two times. */
     976                 :            : pdf_i8_t
     977                 :      39167 : pdf_time_cmp (const pdf_time_t *time1,
     978                 :            :               const pdf_time_t *time2)
     979                 :            : {
     980         [ +  + ]:      39167 :   if (time1->seconds > time2->seconds)
     981                 :          6 :     return 1;
     982         [ +  + ]:      39161 :   if (time1->seconds < time2->seconds)
     983                 :       2140 :     return -1;
     984                 :      39167 :   return 0;
     985                 :            : }
     986                 :            : 
     987                 :            : /* ---------------------- Time printing and parsing ------------------------- */
     988                 :            : 
     989                 :            : /* Create a string representation of a given time. */
     990                 :            : pdf_char_t *
     991                 :      17151 : pdf_time_to_string (const pdf_time_t                     *time_var,
     992                 :            :                     const enum pdf_time_string_format_e   time_format,
     993                 :            :                     pdf_u32_t                             options,
     994                 :            :                     pdf_error_t                         **error)
     995                 :            : {
     996         [ -  + ]:      17151 :   PDF_ASSERT_POINTER_RETURN_VAL (time_var, NULL);
     997                 :            :   PDF_ASSERT_RETURN_VAL (time_format >= PDF_TIME_STRING_FORMAT_PDF, NULL);
     998         [ -  + ]:      17151 :   PDF_ASSERT_RETURN_VAL (time_format <= PDF_TIME_STRING_FORMAT_GENERALIZED_ASN1, NULL);
     999                 :            : 
    1000   [ +  +  +  +  :      17151 :   switch (time_format)
                      - ]
    1001                 :            :     {
    1002                 :            :     case PDF_TIME_STRING_FORMAT_PDF:
    1003                 :       6860 :       return pdf_time_to_string_pdf (time_var,
    1004                 :       6860 :                                      (options & PDF_TIME_STRING_TRAILING_APOSTROPHE),
    1005                 :            :                                      error);
    1006                 :            :     case PDF_TIME_STRING_FORMAT_ISO_8601:
    1007                 :       3431 :       return pdf_time_to_string_iso8601 (time_var, error);
    1008                 :            :     case PDF_TIME_STRING_FORMAT_UTC_ASN1:
    1009                 :       3430 :       return pdf_time_to_string_utc_asn1 (time_var, error);
    1010                 :            :     case PDF_TIME_STRING_FORMAT_GENERALIZED_ASN1:
    1011                 :       3430 :       return pdf_time_to_string_generalized_asn1 (time_var, error);
    1012                 :            :     default:
    1013                 :            :       /* Make compiler happy */
    1014                 :      17151 :       return NULL;
    1015                 :            :     }
    1016                 :            : }
    1017                 :            : 
    1018                 :            : /* Get a string containing a time specification in some format and fill a time
    1019                 :            :  *  variable with the parsed values. */
    1020                 :            : pdf_bool_t
    1021                 :      40076 : pdf_time_set_from_string (pdf_time_t                           *time_var,
    1022                 :            :                           const pdf_char_t                     *time_str,
    1023                 :            :                           const enum pdf_time_string_format_e   time_format,
    1024                 :            :                           pdf_u32_t                             options,
    1025                 :            :                           pdf_error_t                         **error)
    1026                 :            : {
    1027         [ -  + ]:      40076 :   PDF_ASSERT_POINTER_RETURN_VAL (time_var, PDF_FALSE);
    1028         [ -  + ]:      40076 :   PDF_ASSERT_POINTER_RETURN_VAL (time_str, PDF_FALSE);
    1029                 :            :   PDF_ASSERT_RETURN_VAL (time_format >= PDF_TIME_STRING_FORMAT_PDF, PDF_FALSE);
    1030         [ -  + ]:      40076 :   PDF_ASSERT_RETURN_VAL (time_format <= PDF_TIME_STRING_FORMAT_GENERALIZED_ASN1, PDF_FALSE);
    1031                 :            : 
    1032   [ +  +  +  +  :      40076 :   switch (time_format)
                      - ]
    1033                 :            :     {
    1034                 :            :     case PDF_TIME_STRING_FORMAT_PDF:
    1035                 :      15718 :       return pdf_time_from_string_pdf (time_var,
    1036                 :            :                                        time_str,
    1037                 :      15718 :                                        (options & PDF_TIME_STRING_TRAILING_APOSTROPHE),
    1038                 :            :                                        error);
    1039                 :            :     case PDF_TIME_STRING_FORMAT_ISO_8601:
    1040                 :       8208 :       return pdf_time_from_string_iso8601 (time_var, time_str, error);
    1041                 :            :     case PDF_TIME_STRING_FORMAT_UTC_ASN1:
    1042                 :       7988 :       return pdf_time_from_string_utc_asn1 (time_var, time_str, error);
    1043                 :            :     case PDF_TIME_STRING_FORMAT_GENERALIZED_ASN1:
    1044                 :       8162 :       return pdf_time_from_string_generalized_asn1 (time_var, time_str, error);
    1045                 :            :     default:
    1046                 :            :       /* Make compiler happy */
    1047                 :      40076 :       return PDF_FALSE;
    1048                 :            :     }
    1049                 :            : }
    1050                 :            : 
    1051                 :            : /* ---------------------- Getting the Current Time -------------------------- */
    1052                 :            : 
    1053                 :            : /* Set the value of object to the current local time used by the operating
    1054                 :            :  *  system. */
    1055                 :            : void
    1056                 :          2 : pdf_time_set_to_current_local_time (pdf_time_t *time_var)
    1057                 :            : {
    1058                 :            :   /* time() always returns UTC */
    1059                 :          2 :   time_var->seconds = time (NULL);
    1060                 :            :   /* Store offset in the gmt_offset */
    1061                 :          2 :   time_var->gmt_offset = pdf_time_context_get_gmt_offset ();
    1062                 :          2 : }
    1063                 :            : 
    1064                 :            : /* Set the value of object to the current UTC time used by the operating
    1065                 :            :  *  system. */
    1066                 :            : void
    1067                 :       7989 : pdf_time_set_to_current_utc_time (pdf_time_t *time_var)
    1068                 :            : {
    1069                 :            :   /* time() always returns UTC */
    1070                 :       7989 :   time_var->seconds = time (NULL);
    1071                 :       7989 :   time_var->gmt_offset = 0;
    1072                 :       7989 : }
    1073                 :            : 
    1074                 :            : /* ---------------------- Calendar Spans Management ------------------------- */
    1075                 :            : 
    1076                 :            : static pdf_i32_t
    1077                 :       2880 : pdf_time_span_from_cal_span (const struct pdf_time_cal_span_s *cal_span,
    1078                 :            :                              const pdf_time_t                 *base_time)
    1079                 :            : {
    1080                 :            :   pdf_i64_t span;
    1081                 :            :   pdf_time_t new_time;
    1082                 :            : 
    1083                 :            :   /* Duplicate base object and add calendar span */
    1084                 :       2880 :   pdf_time_init_dup (&new_time, base_time);
    1085                 :       2880 :   pdf_time_add_cal_span (&new_time, cal_span);
    1086                 :            : 
    1087                 :            :   /* Get the difference in seconds */
    1088                 :       2880 :   span = pdf_time_diff (&new_time, base_time);
    1089                 :            : 
    1090                 :       2880 :   pdf_time_deinit (&new_time);
    1091                 :            : 
    1092                 :       2880 :   return span;
    1093                 :            : }
    1094                 :            : 
    1095                 :            : static void
    1096                 :       1440 : pdf_time_span_to_cal_span (pdf_i32_t                   span,
    1097                 :            :                            const pdf_time_t           *base_time,
    1098                 :            :                            struct pdf_time_cal_span_s *cal_span)
    1099                 :            : {
    1100                 :            :   pdf_time_t new_time;
    1101                 :            : 
    1102                 :            :   /* Duplicate base object and add calendar span,
    1103                 :            :    *  and get both initial and new times as calendars
    1104                 :            :    */
    1105                 :       1440 :   pdf_time_init_dup (&new_time, base_time);
    1106                 :       1440 :   pdf_time_add_span (&new_time, span);
    1107                 :            : 
    1108                 :            :   /* Now, directly get calendar diff */
    1109                 :       1440 :   pdf_time_diff_cal (base_time, &new_time, cal_span);
    1110                 :            : 
    1111                 :       1440 :   pdf_time_deinit (&new_time);
    1112                 :       1440 : }
    1113                 :            : 
    1114                 :            : /* Add two calendar spans. Since the calendar spans are relative (some years
    1115                 :            :  *  has more days than another) the calendar spans are first resolved from a
    1116                 :            :  *  base time to get the number of seconds, and then that number is stored in
    1117                 :            :  *  the resulting calendar span */
    1118                 :            : void
    1119                 :        720 : pdf_time_add_cal_span_with_base (const struct pdf_time_cal_span_s *span1,
    1120                 :            :                                  const struct pdf_time_cal_span_s *span2,
    1121                 :            :                                  const pdf_time_t                 *base_time,
    1122                 :            :                                  struct pdf_time_cal_span_s       *result)
    1123                 :            : {
    1124                 :            :   pdf_i32_t span_time;
    1125                 :            : 
    1126         [ -  + ]:        720 :   PDF_ASSERT_POINTER_RETURN (span1);
    1127         [ -  + ]:        720 :   PDF_ASSERT_POINTER_RETURN (span2);
    1128         [ -  + ]:        720 :   PDF_ASSERT_POINTER_RETURN (base_time);
    1129         [ -  + ]:        720 :   PDF_ASSERT_POINTER_RETURN (result);
    1130                 :            : 
    1131                 :        720 :   span_time = pdf_time_span_from_cal_span (span1, base_time);
    1132                 :        720 :   span_time += pdf_time_span_from_cal_span (span2, base_time);
    1133                 :            : 
    1134                 :            :   /* Get calendar span from the new result */
    1135                 :        720 :   pdf_time_span_to_cal_span (span_time, base_time, result);
    1136                 :            : }
    1137                 :            : 
    1138                 :            : /* Compare two calendar spans previously resolved with a given base time. */
    1139                 :            : pdf_i8_t
    1140                 :         14 : pdf_time_cal_span_cmp (const struct pdf_time_cal_span_s *span1,
    1141                 :            :                        const struct pdf_time_cal_span_s *span2,
    1142                 :            :                        const pdf_time_t                 *base_time)
    1143                 :            : {
    1144                 :            :   /* Probably the best way to do it is convert the cal spans into pdf_time_t
    1145                 :            :    * and then compare the pdf_time_t objects */
    1146                 :            :   pdf_time_t time1;
    1147                 :            :   pdf_time_t time2;
    1148                 :            :   pdf_i8_t cmp_ret;
    1149                 :            : 
    1150         [ -  + ]:         14 :   PDF_ASSERT_POINTER_RETURN_VAL (span1, -1);
    1151         [ -  + ]:         14 :   PDF_ASSERT_POINTER_RETURN_VAL (span2, -1);
    1152         [ -  + ]:         14 :   PDF_ASSERT_POINTER_RETURN_VAL (base_time, -1);
    1153                 :            : 
    1154                 :         14 :   pdf_time_init_dup (&time1, base_time);
    1155                 :         14 :   pdf_time_init_dup (&time2, base_time);
    1156                 :            : 
    1157                 :         14 :   pdf_time_add_cal_span (&time1, span1);
    1158                 :         14 :   pdf_time_add_cal_span (&time2, span2);
    1159                 :            : 
    1160                 :         14 :   cmp_ret = pdf_time_cmp (&time1, &time2);
    1161                 :            : 
    1162                 :         14 :   pdf_time_deinit (&time1);
    1163                 :         14 :   pdf_time_deinit (&time2);
    1164                 :            : 
    1165                 :         14 :   return cmp_ret;
    1166                 :            : }
    1167                 :            : 
    1168                 :            : /* Compute the difference between two calendar spans relative to a given base
    1169                 :            :  *  time and store it in a given calendar span. */
    1170                 :            : void
    1171                 :        720 : pdf_time_cal_span_diff (const struct pdf_time_cal_span_s *span1,
    1172                 :            :                         const struct pdf_time_cal_span_s *span2,
    1173                 :            :                         const pdf_time_t                 *base_time,
    1174                 :            :                         struct pdf_time_cal_span_s       *result)
    1175                 :            : {
    1176                 :            :   pdf_i32_t span_time;
    1177                 :            : 
    1178                 :        720 :   span_time = pdf_time_span_from_cal_span (span1, base_time);
    1179                 :        720 :   span_time -= pdf_time_span_from_cal_span (span2, base_time);
    1180                 :            : 
    1181                 :            :   /* Get calendar span from the new result */
    1182                 :        720 :   pdf_time_span_to_cal_span (span_time, base_time, result);
    1183                 :        720 : }
    1184                 :            : 
    1185                 :            : /* End of pdf-time.c */

Generated by: LCOV version 1.8