📄 generalizedtime.c
字号:
/*- * Copyright (c) 2003, 2004 Lev Walkin <vlm@lionet.info>. All rights reserved. * Redistribution and modifications are permitted subject to BSD license. */#define _POSIX_PTHREAD_SEMANTICS /* for Sun */#define _REENTRANT /* for Sun */#include <asn_internal.h>#include <GeneralizedTime.h>#include <time.h>#include <errno.h>#ifndef __NO_ASSERT_H__#include <assert.h>#endif /* __NO_ASSERT_H__ */#if defined(WIN32)#warning PLEASE STOP AND READ!#warning localtime_r is implemented via localtime(), which may be not thread-safe.#warning gmtime_r is implemented via gmtime(), which may be not thread-safe.#warning#warning You must fix the code by inserting appropriate locking#warning if you want to use asn_GT2time() or asn_UT2time().#warning PLEASE STOP AND READ!static struct tm *localtime_r(const time_t *tloc, struct tm *result) { struct tm *tm; if((tm = localtime(tloc))) return memcpy(result, tm, sizeof(struct tm)); return 0;}static struct tm *gmtime_r(const time_t *tloc, struct tm *result) { struct tm *tm; if((tm = gmtime(tloc))) return memcpy(result, tm, sizeof(struct tm)); return 0;}#define tzset() _tzset()#define putenv() _putenv()#define _EMULATE_TIMEGM#endif /* WIN32 */#if defined(sun)#define _EMULATE_TIMEGM#endif/* * Where to look for offset from GMT, Phase I. * Several platforms are known. */#if defined(__FreeBSD__) \ || (defined(__GNUC__) && defined(__APPLE_CC__)) \ || (defined __GLIBC__ && __GLIBC__ >= 2)#undef HAVE_TM_GMTOFF#define HAVE_TM_GMTOFF#endif /* BSDs and newer glibc *//* * Where to look for offset from GMT, Phase II. */#ifdef HAVE_TM_GMTOFF#define GMTOFF(tm) ((tm).tm_gmtoff)#else /* HAVE_TM_GMTOFF */#define GMTOFF(tm) (-timezone)#endif /* HAVE_TM_GMTOFF *//* * Override our GMTOFF decision for other known platforms. */#ifdef __CYGWIN__#undef GMTOFFstatic long GMTOFF(struct tm a){ struct tm *lt; time_t local_time, gmt_time; long zone; tzset(); gmt_time = time (NULL); lt = gmtime(&gmt_time); local_time = mktime(lt); return (gmt_time - local_time);}#define _EMULATE_TIMEGM#endif /* __CYGWIN__ */#ifdef _EMULATE_TIMEGMstatic time_t timegm(struct tm *tm) { time_t tloc; char *tz; char *buf; tz = getenv("TZ"); putenv("TZ=UTC"); tzset(); tloc = mktime(tm); if (tz) { int bufsize = strlen(tz) + 4; buf = alloca(bufsize); snprintf(buf, bufsize, "TZ=%s", tz); } else { buf = "TZ="; } putenv(buf); tzset(); return tloc;}#endif /* _EMULATE_TIMEGM */#ifndef __NO_ASN_TABLE__/* * GeneralizedTime basic type description. */static ber_tlv_tag_t asn_DEF_GeneralizedTime_tags[] = { (ASN_TAG_CLASS_UNIVERSAL | (24 << 2)), /* [UNIVERSAL 24] IMPLICIT ...*/ (ASN_TAG_CLASS_UNIVERSAL | (26 << 2)), /* [UNIVERSAL 26] IMPLICIT ...*/ (ASN_TAG_CLASS_UNIVERSAL | (4 << 2)) /* ... OCTET STRING */};asn_TYPE_descriptor_t asn_DEF_GeneralizedTime = { "GeneralizedTime", "GeneralizedTime", OCTET_STRING_free, GeneralizedTime_print, GeneralizedTime_constraint, /* Check validity of time */ OCTET_STRING_decode_ber, /* Implemented in terms of OCTET STRING */ GeneralizedTime_encode_der, OCTET_STRING_decode_xer_utf8, GeneralizedTime_encode_xer, 0, /* Use generic outmost tag fetcher */ asn_DEF_GeneralizedTime_tags, sizeof(asn_DEF_GeneralizedTime_tags) / sizeof(asn_DEF_GeneralizedTime_tags[0]) - 2, asn_DEF_GeneralizedTime_tags, sizeof(asn_DEF_GeneralizedTime_tags) / sizeof(asn_DEF_GeneralizedTime_tags[0]), 0, 0, /* No members */ 0 /* No specifics */};#endif /* __NO_ASN_TABLE__ *//* * Check that the time looks like the time. */intGeneralizedTime_constraint(asn_TYPE_descriptor_t *td, const void *sptr, asn_app_consume_bytes_f *app_errlog, void *app_key) { const GeneralizedTime_t *st = (const GeneralizedTime_t *)sptr; time_t tloc; errno = EPERM; /* Just an unlikely error code */ tloc = asn_GT2time(st, 0, 0); if(tloc == -1 && errno != EPERM) { _ASN_ERRLOG(app_errlog, app_key, "%s: Invalid time format: %s (%s:%d)", td->name, strerror(errno), __FILE__, __LINE__); return -1; } return 0;}asn_enc_rval_tGeneralizedTime_encode_der(asn_TYPE_descriptor_t *td, void *ptr, int tag_mode, ber_tlv_tag_t tag, asn_app_consume_bytes_f *cb, void *app_key) { GeneralizedTime_t *st = (GeneralizedTime_t *)ptr; asn_enc_rval_t erval; /* If not canonical DER, re-encode into canonical DER. */ if(st->size && st->buf[st->size-1] != 0x5a) { struct tm tm; time_t tloc; errno = EPERM; tloc = asn_GT2time(st, &tm, 1); /* Recognize time */ if(tloc == -1 && errno != EPERM) { /* Failed to recognize time. Fail completely. */ erval.encoded = -1; erval.failed_type = td; erval.structure_ptr = ptr; return erval; } st = asn_time2GT(0, &tm, 1); /* Save time canonically */ if(!st) { /* Memory allocation failure. */ erval.encoded = -1; erval.failed_type = td; erval.structure_ptr = ptr; return erval; } } erval = OCTET_STRING_encode_der(td, st, tag_mode, tag, cb, app_key); if(st != ptr) { FREEMEM(st->buf); FREEMEM(st); } return erval;}asn_enc_rval_tGeneralizedTime_encode_xer(asn_TYPE_descriptor_t *td, void *sptr, int ilevel, enum xer_encoder_flags_e flags, asn_app_consume_bytes_f *cb, void *app_key) { OCTET_STRING_t st; if(flags & XER_F_CANONICAL) { char buf[32]; struct tm tm; ssize_t ret; errno = EPERM; if(asn_GT2time((GeneralizedTime_t *)sptr, &tm, 1) == -1 && errno != EPERM) _ASN_ENCODE_FAILED; ret = snprintf(buf, sizeof(buf), "%04d%02d%02d%02d%02d%02dZ", tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec); assert(ret > 0 && ret < (int)sizeof(buf)); st.buf = (uint8_t *)buf; st.size = ret; sptr = &st; } return OCTET_STRING_encode_xer_utf8(td, sptr, ilevel, flags, cb, app_key);}intGeneralizedTime_print(asn_TYPE_descriptor_t *td, const void *sptr, int ilevel, asn_app_consume_bytes_f *cb, void *app_key) { const GeneralizedTime_t *st = (const GeneralizedTime_t *)sptr; (void)td; /* Unused argument */ (void)ilevel; /* Unused argument */ if(st && st->buf) { char buf[32]; struct tm tm; int ret; errno = EPERM; if(asn_GT2time(st, &tm, 1) == -1 && errno != EPERM) return (cb("<bad-value>", 11, app_key) < 0) ? -1 : 0; ret = snprintf(buf, sizeof(buf), "%04d-%02d-%02d %02d:%02d%02d (GMT)", tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec); assert(ret > 0 && ret < (int)sizeof(buf)); return (cb(buf, ret, app_key) < 0) ? -1 : 0; } else { return (cb("<absent>", 8, app_key) < 0) ? -1 : 0; }}time_tasn_GT2time(const GeneralizedTime_t *st, struct tm *ret_tm, int as_gmt) { struct tm tm_s; uint8_t *buf; uint8_t *end; int gmtoff_h = 0; int gmtoff_m = 0; int gmtoff = 0; /* h + m */ int offset_specified = 0; time_t tloc; if(!st || !st->buf) { errno = EINVAL; return -1; } else { buf = st->buf; end = buf + st->size; } if(st->size < 10) { errno = EINVAL; return -1; } /* * Decode first 10 bytes: "AAAAMMJJhh" */ memset(&tm_s, 0, sizeof(tm_s));#undef B2F#undef B2T#define B2F(var) do { \ unsigned ch = *buf; \ if(ch < 0x30 && ch > 0x39) { \ errno = EINVAL; \ return -1; \ } else { \ var = var * 10 + (ch - 0x30); \ buf++; \ } \ } while(0)#define B2T(var) B2F(tm_s.var) B2T(tm_year); /* 1: A */ B2T(tm_year); /* 2: A */ B2T(tm_year); /* 3: A */ B2T(tm_year); /* 4: A */ B2T(tm_mon); /* 5: M */ B2T(tm_mon); /* 6: M */ B2T(tm_mday); /* 7: J */ B2T(tm_mday); /* 8: J */ B2T(tm_hour); /* 9: h */ B2T(tm_hour); /* 0: h */ if(buf == end) goto local_finish; /* * Parse [mm[ss[(.|,)ffff]]] * ^^ */ switch(*buf) { case 0x30: case 0x31: case 0x32: case 0x33: case 0x34: case 0x35: case 0x36: case 0x37: case 0x38: case 0x39: tm_s.tm_min = (*buf++) - 0x30; if(buf == end) { errno = EINVAL; return -1; } B2T(tm_min); break; case 0x2B: case 0x2D: /* +, - */ goto offset; case 0x5A: /* Z */ goto utc_finish; default: errno = EINVAL; return -1; } if(buf == end) goto local_finish; /* * Parse [mm[ss[(.|,)ffff]]] * ^^ */ switch(*buf) { case 0x30: case 0x31: case 0x32: case 0x33: case 0x34: case 0x35: case 0x36: case 0x37: case 0x38: case 0x39: tm_s.tm_sec = (*buf++) - 0x30; if(buf == end) { errno = EINVAL; return -1; } B2T(tm_sec); break; case 0x2B: case 0x2D: /* +, - */ goto offset; case 0x5A: /* Z */ goto utc_finish; default: errno = EINVAL; return -1; } if(buf == end) goto local_finish; /* * Parse [mm[ss[(.|,)ffff]]] * ^ ^ */ switch(*buf) { case 0x2C: case 0x2E: /* (.|,) */ /* Fractions of seconds are not supported * by time_t or struct tm. Skip them */ for(buf++; buf < end; buf++) { switch(*buf) { case 0x30: case 0x31: case 0x32: case 0x33: case 0x34: case 0x35: case 0x36: case 0x37: case 0x38: case 0x39: continue; default: break; } break; } } if(buf == end) goto local_finish; switch(*buf) { case 0x2B: case 0x2D: /* +, - */ goto offset; case 0x5A: /* Z */ goto utc_finish; default: errno = EINVAL; return -1; }offset: if(end - buf < 3) { errno = EINVAL; return -1; } buf++; B2F(gmtoff_h); B2F(gmtoff_h); if(buf[-3] == 0x2D) /* Negative */ gmtoff = -1; else gmtoff = 1; if((end - buf) == 2) { B2F(gmtoff_m); B2F(gmtoff_m); } else if(end != buf) { errno = EINVAL; return -1; } gmtoff = gmtoff * (3600 * gmtoff_h + 60 * gmtoff_m); /* Fall through */utc_finish: offset_specified = 1; /* Fall through */local_finish: /* * Validation. */ if((tm_s.tm_mon > 12 || tm_s.tm_mon < 1) || (tm_s.tm_mday > 31 || tm_s.tm_mday < 1) || (tm_s.tm_hour > 23) || (tm_s.tm_sec > 60) ) { errno = EINVAL; return -1; } /* Canonicalize */ tm_s.tm_mon -= 1; /* 0 - 11 */ tm_s.tm_year -= 1900; tm_s.tm_isdst = -1; tm_s.tm_sec -= gmtoff; /*** AT THIS POINT tm_s is either GMT or local (unknown) ****/ if(offset_specified) { tloc = timegm(&tm_s); } else { /* * Without an offset (or "Z"), * we can only guess that it is a local zone. * Interpret it in this fashion. */ tloc = mktime(&tm_s); } if(tloc == -1) { errno = EINVAL; return -1; } if(ret_tm) { if(as_gmt) { if(offset_specified) { *ret_tm = tm_s; } else { if(gmtime_r(&tloc, ret_tm) == 0) { errno = EINVAL; return -1; } } } else { if(localtime_r(&tloc, ret_tm) == 0) { errno = EINVAL; return -1; } } } return tloc;}GeneralizedTime_t *asn_time2GT(GeneralizedTime_t *opt_gt, const struct tm *tm, int force_gmt) { struct tm tm_s; long gmtoff; const unsigned int buf_size = 24; /* 4+2+2 +2+2+2 +4 + cushion */ char *buf; char *p; int size; /* Check arguments */ if(!tm) { errno = EINVAL; return 0; } /* Pre-allocate a buffer of sufficient yet small length */ buf = (char *)MALLOC(buf_size); if(!buf) return 0; gmtoff = GMTOFF(*tm); if(force_gmt && gmtoff) { tm_s = *tm; tm_s.tm_sec -= gmtoff; timegm(&tm_s); /* Fix the time */ tm = &tm_s;#ifdef HAVE_TM_GMTOFF assert(!GMTOFF(tm_s)); /* Will fix itself */#else gmtoff = 0; /* Intervention required */#endif } size = snprintf(buf, buf_size, "%04d%02d%02d%02d%02d%02d", tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec ); assert(size == 14); p = buf + size; if(force_gmt) { *p++ = 0x5a; /* "Z" */ *p++ = 0; size++; } else { int ret = snprintf(p, buf_size - size, "%+03ld%02ld", gmtoff / 3600, gmtoff % 3600); assert(ret >= 5 && ret <= 7); size += ret; } if(opt_gt) { if(opt_gt->buf) FREEMEM(opt_gt->buf); } else { opt_gt = (GeneralizedTime_t *)CALLOC(1, sizeof *opt_gt); if(!opt_gt) { free(buf); return 0; } } opt_gt->buf = (unsigned char *)buf; opt_gt->size = size; return opt_gt;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -