1 : /* -*- mode: C -*-
2 : *
3 : * File: pdf-time-string.c
4 : * Date: Sun May 18 13:08:37 2008
5 : *
6 : * GNU PDF Library - Time Module String utilities
7 : *
8 : */
9 :
10 : /* Copyright (C) 2008 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 <stdio.h>
29 : #include <string.h>
30 : #include <stdlib.h>
31 :
32 : #include <pdf-alloc.h>
33 : #include <pdf-time-string.h>
34 :
35 :
36 : /* In order to use this macro, make sure that every byte represents a digit */
37 : #define __GET_FIELD2(str,start,dest) \
38 : (dest += ((str[start]-48)*10 + (str[start+1]-48)));
39 :
40 :
41 : /* Macro to check if given bytes are digits or not */
42 : #define __CHECK_MASK(mask, masklength, str, i) while(i<masklength) { \
43 : if(mask & (1 << i)) { \
44 : if((str[i] < '0') || \
45 : (str[i] > '9')) { \
46 : PDF_DEBUG_BASE("Expected digit and found '%c' in '%s'", str[i], str); \
47 : return PDF_EBADDATA; \
48 : } \
49 : } \
50 : i++; \
51 : }
52 :
53 : /* Maximum length of strings, including trailing NUL */
54 : #define PDF_MAX_ISO8601_STR_LENGTH 30
55 : #define PDF_MAX_UTCASN1_STR_LENGTH 19
56 : #define PDF_MAX_GENASN1_STR_LENGTH 21
57 : #define PDF_MAX_PDFDATE_STR_LENGTH 24
58 :
59 : static pdf_status_t
60 : pdf_time_check_string_pdf (const pdf_char_t *time_str,
61 : const pdf_size_t time_str_length,
62 : pdf_bool_t require_trailing_apostrophe)
63 : {
64 : pdf_i32_t i;
65 :
66 : /* Check minimum length D:YYYY */
67 9260 : if(time_str_length < 6)
68 : {
69 : PDF_DEBUG_BASE("Invalid PDF time string (too short): '%s'",
70 : time_str);
71 0 : return PDF_EBADDATA;
72 : }
73 : /* Check prefix */
74 9260 : if(strncmp((char *)time_str,"D:",2) != 0)
75 : {
76 : PDF_DEBUG_BASE("Invalid PDF time string (no prefix): '%s'",
77 : time_str);
78 0 : return PDF_EBADDATA;
79 : }
80 :
81 : /* We need to check the input characters are digits when we expect digits and
82 : * the opposite as well. */
83 :
84 : #define PDF_STRING_DIGIT_MASK 0x36FFFC /* 0011 0110 1111 1111 1111 1100 */
85 :
86 : /* Don't really need to check again two first bytes, as already done before */
87 9260 : i = 2;
88 189830 : __CHECK_MASK(PDF_STRING_DIGIT_MASK, time_str_length, time_str, i);
89 :
90 :
91 : /* Check time zone definer */
92 9260 : if((time_str_length >=16) && \
93 : (time_str[16] != 'Z') && \
94 : (time_str[16] != '+') && \
95 : (time_str[16] != '-'))
96 : {
97 : PDF_DEBUG_BASE("Invalid time zone definer '%c' found in '%s'",
98 : time_str[16], time_str);
99 0 : return PDF_EBADDATA;
100 : }
101 :
102 : /* Check additional ' characters. Remember that the last ' character is
103 : * mandatory depending on the require_trailing_apostrophe parameter */
104 9260 : if ((time_str_length >= 20) &&
105 : (time_str[19] != '\''))
106 : {
107 : PDF_DEBUG_BASE("Invalid separator found ('%c') in '%s'",
108 : time_str[19], time_str);
109 0 : return PDF_EBADDATA;
110 : }
111 :
112 9260 : if (require_trailing_apostrophe)
113 : {
114 4630 : if ((time_str_length < 23) ||
115 : ((time_str[22] != '\'')))
116 : {
117 : PDF_DEBUG_BASE("Invalid separator found ('%c') in '%s'",
118 : (time_str_length >= 21) ? time_str[22] : ' ',
119 : time_str);
120 2315 : return PDF_EBADDATA;
121 : }
122 : }
123 : else
124 : {
125 4630 : if (time_str_length >= 23)
126 : {
127 : PDF_DEBUG_BASE("Invalid separator found ('%c') in '%s'",
128 : time_str[19], time_str);
129 2315 : return PDF_EBADDATA;
130 : }
131 : }
132 :
133 4630 : return PDF_OK;
134 : }
135 :
136 :
137 : pdf_status_t
138 : pdf_time_from_string_pdf (pdf_time_t time_var,
139 : const pdf_char_t *time_str,
140 : pdf_bool_t require_trailing_apostrophe)
141 9260 : {
142 : /*
143 : * From PDF Reference 1.7: ( D:YYYYMMDDHHmmSSOHH'mm' )
144 : * From ISO 32000: ( D:YYYYMMDDHHmmSSOHH'mm )
145 : *
146 : * Notes: Year is mandatory, all the other fields may appear if the preceding
147 : * also appear.
148 : *
149 : * D: = string "D:"
150 : * YYYY = four-digit year
151 : * MM = two-digit month (01=January, etc.)
152 : * DD = two-digit day of month (01 through 31)
153 : * HH = two digits of hour (00 through 23)
154 : * mm = two digits of minute (00 through 59)
155 : * SS = two digits of second (00 through 59)
156 : * O = either '+', '-' or 'Z'
157 : * HH = two digits of hour (00 through 23) for the GMT offset
158 : * ' = string "'"
159 : * MM = two digits of minute (00 through 59) for the GMT offset
160 : * ' = string "'" (NOTE: Mandatory in 1.7, non-valid in ISO32000)
161 : */
162 : struct pdf_time_cal_s calendar;
163 : pdf_status_t ret_code;
164 9260 : pdf_size_t time_str_length = strlen((char *)time_str);
165 :
166 18520 : ret_code = pdf_time_check_string_pdf (time_str,
167 : time_str_length,
168 : require_trailing_apostrophe);
169 9260 : if(ret_code != PDF_OK)
170 : {
171 : PDF_DEBUG_BASE("Input Date in PDF format is not valid (%s)",
172 : time_str);
173 4630 : return ret_code;
174 : }
175 :
176 : /* Reset calendar (all integers to zero) */
177 4630 : memset(&calendar, 0, sizeof(calendar));
178 :
179 : while(1)
180 : {
181 : /* Get century */
182 4630 : __GET_FIELD2(time_str, 2, calendar.year);
183 4630 : calendar.year *= 100;
184 : /* Get year in century */
185 4630 : __GET_FIELD2(time_str, 4, calendar.year);
186 : /* more than year ? */
187 4630 : if(time_str_length == 6)
188 : {
189 0 : calendar.month = 1;
190 0 : calendar.day = 1;
191 0 : break;
192 : }
193 :
194 : /* Get month */
195 4630 : __GET_FIELD2(time_str, 6, calendar.month);
196 : /* more than month ? */
197 4630 : if(time_str_length == 8)
198 : {
199 0 : calendar.day = 1;
200 0 : break;
201 : }
202 :
203 : /* Get day */
204 4630 : __GET_FIELD2(time_str, 8, calendar.day);
205 : /* more than day ? */
206 4630 : if(time_str_length == 10)
207 0 : break;
208 :
209 : /* Get hour */
210 4630 : __GET_FIELD2(time_str, 10, calendar.hour);
211 : /* more than hour ? */
212 4630 : if(time_str_length == 12)
213 0 : break;
214 :
215 : /* Get minute */
216 4630 : __GET_FIELD2(time_str, 12, calendar.minute);
217 : /* more than minute ? */
218 4630 : if(time_str_length == 14)
219 0 : break;
220 :
221 : /* Get second */
222 4630 : __GET_FIELD2(time_str, 14, calendar.second);
223 : /* more than second ? */
224 4630 : if(time_str_length <= 17) /* Considering timezone offset separator */
225 0 : break;
226 :
227 : /* Get timezone offset hours */
228 4630 : __GET_FIELD2(time_str, 17, calendar.gmt_offset);
229 : /* And convert it in minutes */
230 4630 : calendar.gmt_offset *= 60;
231 :
232 : /* Get timezone offset minutes */
233 4630 : if(time_str_length > 19)
234 : {
235 4630 : __GET_FIELD2(time_str, 20, calendar.gmt_offset);
236 : }
237 :
238 : /* Convert from minutes to seconds */
239 4630 : calendar.gmt_offset *= 60;
240 :
241 : /* Set proper sign */
242 4630 : if(time_str[16]=='-')
243 : {
244 2580 : calendar.gmt_offset *= (-1);
245 : }
246 :
247 : /* Stop loop :-) */
248 : break;
249 : }
250 :
251 : /* Get time value from break-down UTC calendar !*/
252 4630 : ret_code = pdf_time_from_cal(time_var, &calendar);
253 :
254 4630 : return ret_code;
255 : }
256 :
257 :
258 : static pdf_status_t
259 : pdf_time_check_string_utc_asn1(const pdf_char_t *time_str,
260 : const pdf_size_t time_str_length)
261 : {
262 : pdf_i32_t i;
263 : pdf_i32_t base_mask;
264 : pdf_i32_t mask_length;
265 : pdf_bool_t with_gmt_offset;
266 :
267 : #define UTCASN1_STRING_DIGIT_MASK1 0x03FF /* 0000 0011 1111 1111 */
268 : #define UTCASN1_STRING_DIGIT_MASK2 0x0FFF /* 0000 1111 1111 1111 */
269 :
270 : /* Check length */
271 4630 : if((time_str_length == 11) || \
272 : (time_str_length == 15))
273 : {
274 2315 : base_mask = UTCASN1_STRING_DIGIT_MASK1;
275 2315 : mask_length = 10;
276 : }
277 2315 : else if((time_str_length == 13) || \
278 : (time_str_length == 17))
279 : {
280 2315 : base_mask = UTCASN1_STRING_DIGIT_MASK2;
281 2315 : mask_length = 12;
282 : }
283 : else
284 : {
285 : PDF_DEBUG_BASE("Invalid UTC-ASN1 time string (invalid length): '%s'",
286 : time_str);
287 0 : return PDF_EBADDATA;
288 : }
289 :
290 : /* Check if GMT offset is expected */
291 4630 : with_gmt_offset = (time_str_length >=15) ? PDF_TRUE : PDF_FALSE;
292 :
293 : /* Check extra non-digit characters */
294 4630 : if((!with_gmt_offset) && \
295 : (time_str[time_str_length-1] != 'Z'))
296 : {
297 : PDF_DEBUG_BASE("Expected UTC string, but not valid");
298 0 : return PDF_EBADDATA;
299 : }
300 4630 : else if((with_gmt_offset) && \
301 : ((time_str[time_str_length-5] != '+') && \
302 : (time_str[time_str_length-5] != '-')))
303 : {
304 : PDF_DEBUG_BASE("Expected non-UTC string, but not valid");
305 0 : return PDF_EBADDATA;
306 : }
307 :
308 : /* Check mask if base string */
309 4630 : i=0;
310 50930 : __CHECK_MASK(base_mask, mask_length, time_str, i);
311 : /* Check mask of offset string if available */
312 4630 : if(with_gmt_offset)
313 : {
314 4630 : i=time_str_length-4;
315 0 : __CHECK_MASK(0x000F, 4, time_str, i);
316 : }
317 :
318 4630 : return PDF_OK;
319 : }
320 :
321 : static pdf_i32_t
322 : pdf_time_get_century_in_sliding_window(pdf_i32_t year_in_century)
323 : {
324 4630 : pdf_i32_t full_year = -1;
325 : pdf_time_t current;
326 : struct pdf_time_cal_s current_cal;
327 4630 : pdf_time_new (¤t);
328 :
329 4630 : if((current != NULL) && \
330 : (pdf_time_set_to_current_utc_time(current) == PDF_OK) && \
331 : (pdf_time_get_utc_cal(current, ¤t_cal) == PDF_OK))
332 : {
333 : /* Get century from full current year */
334 4630 : pdf_i32_t century = 100 * (current_cal.year / 100);
335 : /* Appy current century */
336 4630 : full_year = century + year_in_century;
337 :
338 : /* Check if the century must be changed */
339 4630 : if((full_year > current_cal.year) && \
340 : ((full_year - current_cal.year) > 50))
341 : {
342 2890 : full_year -= 100;
343 : }
344 1740 : else if((full_year < current_cal.year) && \
345 : ((current_cal.year - full_year) > 50))
346 : {
347 0 : full_year += 100;
348 : }
349 : }
350 :
351 4630 : pdf_time_destroy(current);
352 4630 : return full_year;
353 : }
354 :
355 : pdf_status_t
356 : pdf_time_from_string_utc_asn1(pdf_time_t time_var,
357 : const pdf_char_t *time_str)
358 4630 : {
359 : /*
360 : * yymmddhhmmZ
361 : * yymmddhhmmssZ
362 : * yymmddhhmm+hhmm
363 : * yymmddhhmm-hhmm
364 : * yymmddhhmmss+hhmm
365 : * yymmddhhmmss-hhmm
366 : *
367 : * Note: As year is only stored in 2 digits, a sliding window of [-50,+50]
368 : * years will be used to get the century.
369 : */
370 : struct pdf_time_cal_s calendar;
371 4630 : pdf_size_t time_str_length = strlen((char *)time_str);
372 :
373 4630 : if(pdf_time_check_string_utc_asn1(time_str, time_str_length) != PDF_OK)
374 : {
375 : PDF_DEBUG_BASE("Input Date in UTC ASN1 format is not valid (%s)",
376 : time_str);
377 0 : return PDF_EBADDATA;
378 : }
379 :
380 : /* Reset calendar (all integers to zero) */
381 4630 : memset(&calendar, 0, sizeof(calendar));
382 :
383 : while(1)
384 : {
385 4630 : pdf_bool_t has_seconds = PDF_FALSE;
386 : /* Get year in century */
387 4630 : __GET_FIELD2(time_str, 0, calendar.year);
388 : /* Get 4-digit year from 2-digit year */
389 9260 : calendar.year = pdf_time_get_century_in_sliding_window(calendar.year);
390 :
391 : /* Get month */
392 4630 : __GET_FIELD2(time_str, 2, calendar.month);
393 :
394 : /* Get day */
395 4630 : __GET_FIELD2(time_str, 4, calendar.day);
396 :
397 : /* Get hour */
398 4630 : __GET_FIELD2(time_str, 6, calendar.hour);
399 :
400 : /* Get minute */
401 4630 : __GET_FIELD2(time_str, 8, calendar.minute);
402 :
403 : /* Get second if available */
404 4630 : if((time_str[10] >= '0') && \
405 : (time_str[10] <= '9'))
406 : {
407 2315 : has_seconds = PDF_TRUE;
408 2315 : __GET_FIELD2(time_str, 10, calendar.second);
409 : }
410 :
411 : /* Check if we have GMT offset */
412 4630 : if(time_str[time_str_length-1] == 'Z')
413 : {
414 0 : break;
415 : }
416 :
417 : /* Get timezone offset hours */
418 4630 : __GET_FIELD2(time_str, (has_seconds ? 13 : 11), calendar.gmt_offset);
419 : /* And convert it in minutes */
420 4630 : calendar.gmt_offset *= 60;
421 : /* Get timezone offset minutes */
422 4630 : __GET_FIELD2(time_str, (has_seconds ? 15 : 13), calendar.gmt_offset);
423 : /* Convert from minutes to seconds */
424 4630 : calendar.gmt_offset *= 60;
425 :
426 : /* Set proper sign */
427 4630 : if(time_str[(has_seconds ? 12 : 10)] == '-')
428 : {
429 2580 : calendar.gmt_offset *= (-1);
430 : }
431 :
432 : /* Stop loop :-) */
433 : break;
434 : }
435 :
436 : /* Get time value from break-down UTC calendar !*/
437 4630 : return pdf_time_from_cal(time_var, &calendar);
438 : }
439 :
440 : pdf_status_t
441 : pdf_time_from_string_generalized_asn1(pdf_time_t time_var,
442 : const pdf_char_t *time_str)
443 4804 : {
444 : /*
445 : * Year:
446 : * YYYY (eg 1997)
447 : * Year and month:
448 : * YYYYMM (eg 199707)
449 : * Complete date:
450 : * YYYYMMDD (eg 19970716)
451 : * Complete date plus hours and minutes:
452 : * YYYYMMDDhhmmTZD (eg 199707161920+01:00)
453 : * Complete date plus hours, minutes and seconds:
454 : * YYYYMMDDhhmmssTZD (eg 19970716192030+01:00)
455 : * Complete date plus hours, minutes, seconds and a decimal fraction of a
456 : * second
457 : * YYYYMMDDThhmmss.sTZD (eg 1997071619:20:30.45+01:00)
458 : *
459 : * where:
460 : *
461 : * YYYY = four-digit year
462 : * MM = two-digit month (01=January, etc.)
463 : * DD = two-digit day of month (01 through 31)
464 : * hh = two digits of hour (00 through 23) (am/pm NOT allowed)
465 : * mm = two digits of minute (00 through 59)
466 : * ss = two digits of second (00 through 59)
467 : * s = one or more digits representing a decimal fraction of a second
468 : * TZD = time zone designator (Z or +hh:mm or -hh:mm)
469 : *
470 : */
471 : struct pdf_time_cal_s calendar;
472 4804 : pdf_size_t time_str_length = strlen((char *)time_str);
473 :
474 : /* Check minimum length */
475 4804 : if(time_str_length < 4)
476 : {
477 : PDF_DEBUG_BASE("Invalid Generalized ASN1 time string (too short): '%s'",
478 : time_str);
479 0 : return PDF_EBADDATA;
480 : }
481 :
482 : /* Reset calendar */
483 4804 : memset(&calendar, 0, sizeof(calendar));
484 :
485 : while(1)
486 : {
487 : /* Get century */
488 4804 : __GET_FIELD2(time_str, 0, calendar.year);
489 4804 : calendar.year *= 100;
490 : /* Get year in century */
491 4804 : __GET_FIELD2(time_str, 2, calendar.year);
492 : /* more than year ? */
493 4804 : if(time_str_length == 4)
494 : {
495 40 : calendar.month = 1;
496 40 : calendar.day = 1;
497 40 : break;
498 : }
499 :
500 :
501 : /* Get month */
502 4764 : __GET_FIELD2(time_str, 4, calendar.month);
503 : /* more than month ? */
504 4764 : if(time_str_length == 6)
505 : {
506 48 : calendar.day = 1;
507 48 : break;
508 : }
509 :
510 : /* Get day */
511 4716 : __GET_FIELD2(time_str, 6, calendar.day);
512 : /* more than day ? */
513 4716 : if(time_str_length == 8)
514 86 : break;
515 :
516 : /* Get hour and minutes */
517 4630 : __GET_FIELD2(time_str, 8, calendar.hour);
518 4630 : __GET_FIELD2(time_str, 10, calendar.minute);
519 :
520 : /* Get second if available */
521 4630 : if((time_str[17] >= '0') && \
522 : (time_str[17] <= '9'))
523 : {
524 2315 : __GET_FIELD2(time_str, 12, calendar.second);
525 : }
526 :
527 : /* Note: Fractional part of seconds not considered */
528 :
529 4630 : if(time_str[time_str_length-1] == 'Z')
530 : {
531 0 : break;
532 : }
533 :
534 : /* Get timezone offset hours */
535 4630 : __GET_FIELD2(time_str, (time_str_length-4), calendar.gmt_offset);
536 : /* And convert it in minutes */
537 4630 : calendar.gmt_offset *= 60;
538 : /* Get timezone offset minutes */
539 4630 : __GET_FIELD2(time_str, (time_str_length-2), calendar.gmt_offset);
540 : /* Convert from minutes to seconds */
541 4630 : calendar.gmt_offset *= 60;
542 :
543 : /* Set proper sign */
544 4630 : if(time_str[(time_str_length-5)]=='-')
545 : {
546 2580 : calendar.gmt_offset *= (-1);
547 : }
548 :
549 : /* Stop loop :-) */
550 : break;
551 : }
552 :
553 : /* Get time value from break-down calendar !*/
554 4804 : return pdf_time_from_cal(time_var, &calendar);
555 : }
556 :
557 : pdf_status_t
558 : pdf_time_from_string_iso8601(pdf_time_t time_var,
559 : const pdf_char_t *time_str)
560 4850 : {
561 : /*
562 : * Year:
563 : * YYYY (eg 1997)
564 : * Year and month:
565 : * YYYY-MM (eg 1997-07)
566 : * Complete date:
567 : * YYYY-MM-DD (eg 1997-07-16)
568 : * Complete date plus hours and minutes:
569 : * YYYY-MM-DDThh:mmTZD (eg 1997-07-16T19:20+01:00)
570 : * Complete date plus hours, minutes and seconds:
571 : * YYYY-MM-DDThh:mm:ssTZD (eg 1997-07-16T19:20:30+01:00)
572 : * Complete date plus hours, minutes, seconds and a decimal fraction of a
573 : * second
574 : * YYYY-MM-DDThh:mm:ss.sTZD (eg 1997-07-16T19:20:30.45+01:00)
575 : *
576 : * where:
577 : *
578 : * YYYY = four-digit year
579 : * MM = two-digit month (01=January, etc.)
580 : * DD = two-digit day of month (01 through 31)
581 : * hh = two digits of hour (00 through 23) (am/pm NOT allowed)
582 : * mm = two digits of minute (00 through 59)
583 : * ss = two digits of second (00 through 59)
584 : * s = one or more digits representing a decimal fraction of a second
585 : * TZD = time zone designator (Z or +hh:mm or -hh:mm)
586 : *
587 : */
588 : struct pdf_time_cal_s calendar;
589 4850 : pdf_size_t time_str_length = strlen((char *)time_str);
590 :
591 : /* Check minimum length */
592 4850 : if(time_str_length < 4)
593 : {
594 : PDF_DEBUG_BASE("Invalid ISO-8601 time string (too short): '%s'",
595 : time_str);
596 0 : return PDF_EBADDATA;
597 : }
598 :
599 : /* Reset calendar */
600 4850 : memset(&calendar, 0, sizeof(calendar));
601 :
602 : while(1)
603 : {
604 : /* Get century */
605 4850 : __GET_FIELD2(time_str, 0, calendar.year);
606 4850 : calendar.year *= 100;
607 : /* Get year in century */
608 4850 : __GET_FIELD2(time_str, 2, calendar.year);
609 : /* more than year ? */
610 4850 : if(time_str_length == 4)
611 : {
612 86 : calendar.month = 1;
613 86 : calendar.day = 1;
614 86 : break;
615 : }
616 :
617 :
618 : /* Get month */
619 4764 : __GET_FIELD2(time_str, 5, calendar.month);
620 : /* more than month ? */
621 4764 : if(time_str_length == 7)
622 : {
623 48 : calendar.day = 1;
624 48 : break;
625 : }
626 :
627 : /* Get day */
628 4716 : __GET_FIELD2(time_str, 8, calendar.day);
629 : /* more than day ? */
630 4716 : if(time_str_length == 10)
631 86 : break;
632 :
633 : /* Get hour and minutes */
634 4630 : __GET_FIELD2(time_str, 11, calendar.hour);
635 4630 : __GET_FIELD2(time_str, 14, calendar.minute);
636 :
637 :
638 : /* Get second if available */
639 4630 : if((time_str[17] >= '0') && \
640 : (time_str[17] <= '9') && \
641 : (time_str[16] == ':'))
642 : {
643 2315 : __GET_FIELD2(time_str, 17, calendar.second);
644 : }
645 :
646 : /* Note: Fractional part of seconds not considered */
647 :
648 4630 : if(time_str[time_str_length-1] == 'Z')
649 : {
650 0 : break;
651 : }
652 :
653 : /* Get timezone offset hours */
654 4630 : __GET_FIELD2(time_str, (time_str_length-5), calendar.gmt_offset);
655 : /* And convert it in minutes */
656 4630 : calendar.gmt_offset *= 60;
657 : /* Get timezone offset minutes */
658 4630 : __GET_FIELD2(time_str, (time_str_length-2), calendar.gmt_offset);
659 : /* Convert from minutes to seconds */
660 4630 : calendar.gmt_offset *= 60;
661 :
662 : /* Set proper sign */
663 4630 : if(time_str[(time_str_length-6)]=='-')
664 : {
665 2580 : calendar.gmt_offset *= (-1);
666 : }
667 :
668 : /* Stop loop :-) */
669 : break;
670 : }
671 :
672 : /* Get time value from break-down calendar !*/
673 4850 : return pdf_time_from_cal(time_var, &calendar);
674 : }
675 :
676 :
677 : /* Get Date as a string in PDF format */
678 : pdf_char_t *
679 : pdf_time_to_string_pdf (const pdf_time_t time_var,
680 : pdf_bool_t include_trailing_apostrophe)
681 4988 : {
682 : pdf_char_t *str;
683 : struct pdf_time_cal_s calendar;
684 :
685 4988 : str = (pdf_char_t *) pdf_alloc (PDF_MAX_PDFDATE_STR_LENGTH * sizeof(pdf_char_t));
686 4988 : if(str != NULL)
687 : {
688 : /* D:YYYYMMDDHHmmSSOHH'mm' */
689 4988 : if (pdf_time_get_local_cal(time_var, &calendar) == PDF_OK)
690 : {
691 4988 : if (calendar.gmt_offset != 0)
692 : {
693 : pdf_i32_t offset_hours;
694 : pdf_i32_t offset_minutes;
695 :
696 4988 : offset_hours = (((calendar.gmt_offset < 0) ? (-1) : (1)) * calendar.gmt_offset) / 3600;
697 4988 : offset_minutes = (((calendar.gmt_offset < 0) ? (-1) : (1)) * calendar.gmt_offset) % 3600;
698 4988 : offset_minutes /= 60; /* Get only full minutes */
699 4988 : sprintf((char *)str, "D:%4d%s%d%s%d%s%d%s%d%s%d%c%s%d'%s%d", \
700 : calendar.year,
701 : (calendar.month < 10 ? "0" : ""), calendar.month,
702 : (calendar.day < 10 ? "0" : ""), calendar.day,
703 : (calendar.hour < 10 ? "0" : ""), calendar.hour,
704 : (calendar.minute < 10 ? "0" : ""), calendar.minute,
705 : (calendar.second < 10 ? "0" : ""), calendar.second,
706 : ((calendar.gmt_offset < 0) ? '-' : '+'),
707 : (offset_hours < 10 ? "0" : ""), offset_hours,
708 : (offset_minutes < 10 ? "0" : ""), offset_minutes);
709 :
710 4988 : if (include_trailing_apostrophe)
711 : {
712 2494 : str[PDF_MAX_PDFDATE_STR_LENGTH - 2] = '\'';
713 2494 : str[PDF_MAX_PDFDATE_STR_LENGTH - 1] = 0;
714 : }
715 : }
716 : else
717 : {
718 0 : sprintf((char *)str, "D:%4d%s%d%s%d%s%d%s%d%s%dZ", \
719 : calendar.year,
720 : (calendar.month < 10 ? "0" : ""), calendar.month,
721 : (calendar.day < 10 ? "0" : ""), calendar.day,
722 : (calendar.hour < 10 ? "0" : ""), calendar.hour,
723 : (calendar.minute < 10 ? "0" : ""), calendar.minute,
724 : (calendar.second < 10 ? "0" : ""), calendar.second);
725 : }
726 : }
727 : else
728 : {
729 : PDF_DEBUG_BASE("Could not get local calendar from pdf_time_t...");
730 0 : pdf_dealloc(str);
731 0 : str = NULL;
732 : }
733 : }
734 :
735 4988 : return str;
736 : }
737 :
738 :
739 : /* Get Date as a string in UTC-ASN1 format */
740 : pdf_char_t *
741 : pdf_time_to_string_utc_asn1(const pdf_time_t time_var)
742 2494 : {
743 : pdf_char_t *str;
744 : struct pdf_time_cal_s calendar;
745 :
746 2494 : str = (pdf_char_t *)pdf_alloc(PDF_MAX_UTCASN1_STR_LENGTH*sizeof(pdf_char_t));
747 2494 : if(str != NULL)
748 : {
749 2494 : if(pdf_time_get_local_cal(time_var, &calendar) == PDF_OK)
750 : {
751 : pdf_i32_t smallyear;
752 : /* Convert 4-digit year to 2-digit year */
753 2494 : smallyear = calendar.year -1900;
754 5858 : while(smallyear > 99)
755 : {
756 870 : smallyear -= 100;
757 : }
758 :
759 2494 : if(calendar.gmt_offset != 0)
760 : {
761 : pdf_i32_t offset_hours;
762 : pdf_i32_t offset_minutes;
763 :
764 2494 : offset_hours = (((calendar.gmt_offset < 0) ? (-1) : (1)) * calendar.gmt_offset) / 3600;
765 2494 : offset_minutes = (((calendar.gmt_offset < 0) ? (-1) : (1)) * calendar.gmt_offset) % 3600;
766 2494 : offset_minutes /= 60;
767 : /* yymmddhhmmss+hhmm
768 : * yymmddhhmmss-hhmm
769 : */
770 2494 : sprintf((char *)str, "%s%d%s%d%s%d%s%d%s%d%s%d%c%s%d%s%d", \
771 : (smallyear < 10 ? "0" : ""), smallyear,
772 : (calendar.month < 10 ? "0" : ""), calendar.month,
773 : (calendar.day < 10 ? "0" : ""), calendar.day,
774 : (calendar.hour < 10 ? "0" : ""), calendar.hour,
775 : (calendar.minute < 10 ? "0" : ""), calendar.minute,
776 : (calendar.second < 10 ? "0" : ""), calendar.second,
777 : ((calendar.gmt_offset < 0) ? '-' : '+'),
778 : (offset_hours < 10 ? "0" : ""), offset_hours,
779 : (offset_minutes < 10 ? "0" : ""), offset_minutes);
780 : }
781 : else
782 : {
783 : /*
784 : * yymmddhhmmssZ
785 : */
786 0 : sprintf((char *)str, "%s%d%s%d%s%d%s%d%s%d%s%dZ", \
787 : (smallyear < 10 ? "0" : ""), smallyear,
788 : (calendar.month < 10 ? "0" : ""), calendar.month,
789 : (calendar.day < 10 ? "0" : ""), calendar.day,
790 : (calendar.hour < 10 ? "0" : ""), calendar.hour,
791 : (calendar.minute < 10 ? "0" : ""), calendar.minute,
792 : (calendar.second < 10 ? "0" : ""), calendar.second);
793 : }
794 : }
795 : else
796 : {
797 : PDF_DEBUG_BASE("Could not get local calendar from pdf_time_t...");
798 0 : pdf_dealloc(str);
799 0 : str = NULL;
800 : }
801 : }
802 :
803 2494 : return str;
804 : }
805 :
806 : /* Get Date as a string in Generalized ASN1 format */
807 : pdf_char_t *
808 : pdf_time_to_string_generalized_asn1(const pdf_time_t time_var)
809 2494 : {
810 : pdf_char_t *str;
811 : struct pdf_time_cal_s calendar;
812 :
813 2494 : str = (pdf_char_t *)pdf_alloc(PDF_MAX_ISO8601_STR_LENGTH*sizeof(pdf_char_t));
814 2494 : if(str != NULL)
815 : {
816 : /* YYYYMMDDhhmmssTZD (eg 19970716192030+01:00) */
817 2494 : if(pdf_time_get_local_cal(time_var, &calendar) == PDF_OK)
818 : {
819 2494 : if(calendar.gmt_offset != 0)
820 : {
821 : pdf_i32_t offset_hours;
822 : pdf_i32_t offset_minutes;
823 :
824 2494 : offset_hours = (((calendar.gmt_offset < 0) ? (-1) : (1)) * calendar.gmt_offset) / 3600;
825 2494 : offset_minutes = (((calendar.gmt_offset < 0) ? (-1) : (1)) * calendar.gmt_offset) % 3600;
826 2494 : offset_minutes /= 60;
827 2494 : sprintf((char *)str, "%4d%s%d%s%d%s%d%s%d%s%d%c%s%d%s%d", \
828 : calendar.year,
829 : (calendar.month < 10 ? "0" : ""), calendar.month,
830 : (calendar.day < 10 ? "0" : ""), calendar.day,
831 : (calendar.hour < 10 ? "0" : ""), calendar.hour,
832 : (calendar.minute < 10 ? "0" : ""), calendar.minute,
833 : (calendar.second < 10 ? "0" : ""), calendar.second,
834 : ((calendar.gmt_offset < 0) ? '-' : '+'),
835 : (offset_hours < 10 ? "0" : ""), offset_hours,
836 : (offset_minutes < 10 ? "0" : ""), offset_minutes);
837 : }
838 : else
839 : {
840 0 : sprintf((char *)str, "%4d%s%d%s%d%s%d%s%d%s%dZ", \
841 : calendar.year,
842 : (calendar.month < 10 ? "0" : ""), calendar.month,
843 : (calendar.day < 10 ? "0" : ""), calendar.day,
844 : (calendar.hour < 10 ? "0" : ""), calendar.hour,
845 : (calendar.minute < 10 ? "0" : ""), calendar.minute,
846 : (calendar.second < 10 ? "0" : ""), calendar.second);
847 : }
848 : }
849 : else
850 : {
851 : PDF_DEBUG_BASE("Could not get local calendar from pdf_time_t...");
852 0 : pdf_dealloc(str);
853 0 : str = NULL;
854 : }
855 : }
856 :
857 2494 : return str;
858 : }
859 :
860 : /* Get Date as a string in ISO8601 format */
861 : pdf_char_t *
862 : pdf_time_to_string_iso8601(const pdf_time_t time_var)
863 2495 : {
864 : pdf_char_t *str;
865 : struct pdf_time_cal_s calendar;
866 :
867 2495 : str = (pdf_char_t *)pdf_alloc(PDF_MAX_ISO8601_STR_LENGTH*sizeof(pdf_char_t));
868 2495 : if(str != NULL)
869 : {
870 : /* YYYY-MM-DDThh:mm:ss.sTZD (eg 1997-07-16T19:20:30.45+01:00) */
871 2495 : if(pdf_time_get_local_cal(time_var, &calendar) == PDF_OK)
872 : {
873 2495 : if(calendar.gmt_offset != 0)
874 : {
875 : pdf_i32_t offset_hours;
876 : pdf_i32_t offset_minutes;
877 :
878 2494 : offset_hours = (((calendar.gmt_offset < 0) ? (-1) : (1)) * calendar.gmt_offset) / 3600;
879 2494 : offset_minutes = (((calendar.gmt_offset < 0) ? (-1) : (1)) * calendar.gmt_offset) % 3600;
880 2494 : offset_minutes /= 60; /* Get only full minutes */
881 2494 : sprintf((char *)str, "%4d-%s%d-%s%dT%s%d:%s%d:%s%d%c%s%d:%s%d", \
882 : calendar.year,
883 : (calendar.month < 10 ? "0" : ""), calendar.month,
884 : (calendar.day < 10 ? "0" : ""), calendar.day,
885 : (calendar.hour < 10 ? "0" : ""), calendar.hour,
886 : (calendar.minute < 10 ? "0" : ""), calendar.minute,
887 : (calendar.second < 10 ? "0" : ""), calendar.second,
888 : ((calendar.gmt_offset < 0) ? '-' : '+'),
889 : (offset_hours < 10 ? "0" : ""), offset_hours,
890 : (offset_minutes < 10 ? "0" : ""), offset_minutes);
891 : }
892 : else
893 : {
894 1 : sprintf((char *)str, "%4d-%s%d-%s%dT%s%d:%s%d:%s%dZ", \
895 : calendar.year,
896 : (calendar.month < 10 ? "0" : ""), calendar.month,
897 : (calendar.day < 10 ? "0" : ""), calendar.day,
898 : (calendar.hour < 10 ? "0" : ""), calendar.hour,
899 : (calendar.minute < 10 ? "0" : ""), calendar.minute,
900 : (calendar.second < 10 ? "0" : ""), calendar.second);
901 : }
902 : }
903 : else
904 : {
905 : PDF_DEBUG_BASE("Could not get local calendar from pdf_time_t...");
906 0 : pdf_dealloc(str);
907 0 : str = NULL;
908 : }
909 : }
910 :
911 2495 : return str;
912 : }
913 :
914 :
915 :
916 : /* End of pdf-time-string.c */
|