Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:45238 Return-Path: Mailing-List: contact internals-help@lists.php.net; run by ezmlm Delivered-To: mailing list internals@lists.php.net Received: (qmail 46540 invoked from network); 7 Aug 2009 15:24:34 -0000 Received: from unknown (HELO lists.php.net) (127.0.0.1) by localhost with SMTP; 7 Aug 2009 15:24:34 -0000 Authentication-Results: pb1.pair.com smtp.mail=david.zuelke@bitextender.com; spf=permerror; sender-id=unknown Authentication-Results: pb1.pair.com header.from=david.zuelke@bitextender.com; sender-id=unknown Received-SPF: error (pb1.pair.com: domain bitextender.com from 80.237.132.12 cause and error) X-PHP-List-Original-Sender: david.zuelke@bitextender.com X-Host-Fingerprint: 80.237.132.12 wp005.webpack.hosteurope.de Received: from [80.237.132.12] ([80.237.132.12:48526] helo=wp005.webpack.hosteurope.de) by pb1.pair.com (ecelerity 2.1.1.9-wez r(12769M)) with ESMTP id 31/07-08634-A274C7A4 for ; Fri, 07 Aug 2009 11:24:28 -0400 Received: from munich.bitxtender.net ([85.183.90.3] helo=[10.224.254.2]); authenticated by wp005.webpack.hosteurope.de running ExIM with esmtpsa (TLSv1:RC4-SHA:128) id 1MZRIt-00065q-C3; Fri, 07 Aug 2009 17:24:23 +0200 Cc: Dmitry Stogov , php-dev List Message-ID: <467D68D2-E465-4A25-B123-655A632B17AD@bitextender.com> To: jani.taskinen@iki.fi In-Reply-To: <4A6F3211.40801@sci.fi> Content-Type: multipart/signed; boundary=Apple-Mail-6-768523375; micalg=sha1; protocol="application/pkcs7-signature" Mime-Version: 1.0 (Apple Message framework v936) Date: Fri, 7 Aug 2009 17:24:22 +0200 References: <67DEF003-A344-4BE6-9C23-6BB48935786F@bitextender.com> <4A6EE1BF.8080409@zend.com> <4A6F027B.3040608@zend.com> <4A6F3211.40801@sci.fi> X-Mailer: Apple Mail (2.936) X-bounce-key: webpack.hosteurope.de;david.zuelke@bitextender.com;1249658667;ed2dd563; Subject: Re: [PHP-DEV] Re: SOAP_MARSHAL_DATETIME (or: bug #44383) From: david.zuelke@bitextender.com (=?ISO-8859-1?Q?David_Z=FClke?=) --Apple-Mail-6-768523375 Content-Type: multipart/mixed; boundary=Apple-Mail-5-768523318 --Apple-Mail-5-768523318 Content-Type: text/plain; charset=ISO-8859-1; format=flowed; delsp=yes Content-Transfer-Encoding: quoted-printable On 28.07.2009, at 19:14, Jani Taskinen wrote: > Dmitry Stogov wrote: >> David Z=FClke wrote: >>> On 28.07.2009, at 13:32, Dmitry Stogov wrote: >>> >>>> Hi David, >>>> >>>> I took only a quick look, but I like the patch. >>>> In case it doesn't break any tests, it should be committed at =20 >>>> least into >>>> HEAD. I agree to commit it into 5.3 too, but RMs take the final =20 >>>> decision. >>>> >>>> The only thing I didn't understood - why win32/php_stdint.h is =20 >>>> needed. >>> Ah, yes, that's probably an oversight. Good catch. The headers were >>> copy-pasted from some ext/date file :) >>> >>> Another thing that just occured to me is that we now have a =20 >>> dependency >>> on ext/date; I think I had trouble compiling ext/soap as a =20 >>> standalone >>> extension like this. Must check again. Any hints? >> I think ext/date can't be removed or compiled as shared extension. >> If it's the case, the only problem may be with unexported symbols. >> Just try to compile/test it as shared extension on Linux and Windows. > > ext/date is not an extension, it's part of core, just like ext/=20 > standard so you shouldn't have any problems with it. Attached (and also posted here: http://pastie.org/575559 and here: = http://bugs.php.net/44383)=20 is an update of the patch. It has the following updates: 1) all tests adjusted, reviewed and changed to work in sequence (only =20= one of the several variants was not commented out before) 2) fixed handling of unix timestamp longs There are the following outstanding issues (I'm going on a holiday =20 tomorrow, so I figured I'd shoot you an update in the meantime): 1) there seem to be problems with negative timezone offsets (see tests =20= ext/soap/tests/schema/schema0(89|91).phpt) unless I'm confused 2) at the minute, it breaks ext/soap/tests/schema/schema064.phpt. =20 Except for one of the cases where the formatting is indeed wrong, it's =20= due to time zones not being included. That obviously needs fixing, but =20= I'd like to point out that the current tests do not seem to be in =20 compliance with the XML Schema specification, which for gMonthDay, =20 gDay and gMonth states: "An optional following time zone qualifier is =20= allowed as for date". The rule for "date" and timezone postfixes is =20 "For timezoned values, append the canonical representation of the =20 =B7recoverable timezone=B7". A recoverable timezone is an offset value = in =20 the format "[+-]hh:mm". http://www.w3.org/TR/xmlschema-2/ has all the =20= details, but maybe I'm missing something. For gYearMonth and gYear, I =20= think the "dateTime" timezone rules apply, which means the canonical =20 representation must always be in UTC (and thus carry "Z" as the =20 timezone identifier, which is what the tests currently expect, so =20 those are correct). Finally, when I compile as an extension, I get the following error =20 once I reach tests that execute code relying on timelib: dyld: lazy symbol binding failed: Symbol not found: _timelib_time_ctor Referenced from: .../extensions/no-debug-non-zts-20090626/soap.so Expected in: flat namespace dyld: Symbol not found: _timelib_time_ctor Referenced from: .../extensions/no-debug-non-zts-20090626/soap.so Expected in: flat namespace I compiled without --enable-soap, then used the correct "phpize" in =20 ext/soap, ran configure with the correct --with-php-config=3D.../blah/=20= php-config, make install and enabled the extension in php.ini. Feedback/thoughts/advice appreciated. I'll be back in ~2 weeks. Cheers, - David --Apple-Mail-5-768523318 Content-Disposition: attachment; filename=44383-soap_marshal_datetime-2.patch.txt Content-Type: text/plain; x-unix-mode=0644; name="44383-soap_marshal_datetime-2.patch.txt" Content-Transfer-Encoding: 7bit Index: ext/soap/soap.c =================================================================== --- ext/soap/soap.c (Revision 286909) +++ ext/soap/soap.c (Arbeitskopie) @@ -828,6 +828,7 @@ REGISTER_LONG_CONSTANT("SOAP_SINGLE_ELEMENT_ARRAYS", SOAP_SINGLE_ELEMENT_ARRAYS, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("SOAP_WAIT_ONE_WAY_CALLS", SOAP_WAIT_ONE_WAY_CALLS, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("SOAP_USE_XSI_ARRAY_TYPE", SOAP_USE_XSI_ARRAY_TYPE, CONST_CS | CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("SOAP_MARSHAL_DATETIME", SOAP_MARSHAL_DATETIME, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("WSDL_CACHE_NONE", WSDL_CACHE_NONE, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("WSDL_CACHE_DISK", WSDL_CACHE_DISK, CONST_CS | CONST_PERSISTENT); Index: ext/soap/php_soap.h =================================================================== --- ext/soap/php_soap.h (Revision 286909) +++ ext/soap/php_soap.h (Arbeitskopie) @@ -143,6 +143,7 @@ #define SOAP_SINGLE_ELEMENT_ARRAYS (1<<0) #define SOAP_WAIT_ONE_WAY_CALLS (1<<1) #define SOAP_USE_XSI_ARRAY_TYPE (1<<2) +#define SOAP_MARSHAL_DATETIME (1<<3) #define WSDL_CACHE_NONE 0x0 #define WSDL_CACHE_DISK 0x1 Index: ext/soap/tests/schema/schema091.phpt =================================================================== --- ext/soap/tests/schema/schema091.phpt (Revision 0) +++ ext/soap/tests/schema/schema091.phpt (Revision 0) @@ -0,0 +1,36 @@ +--TEST-- +SOAP XML Schema 91: xsd:dateTime DateTime to XML conversion +--SKIPIF-- + +--INI-- +date.timezone=Etc/GMT-2 +--FILE-- + +--EXPECTF-- + +%d-%d-%dT17:35:20.12Z +object(DateTime)#5 (3) { + ["date"]=> + string(19) "%d-%d-%d 17:35:20" + ["timezone_type"]=> + int(2) + ["timezone"]=> + string(1) "Z" +} + +%d-%d-%dT09:35:20Z +object(DateTime)#6 (3) { + ["date"]=> + string(19) "%d-%d-%d 09:35:20" + ["timezone_type"]=> + int(2) + ["timezone"]=> + string(1) "Z" +} +ok \ No newline at end of file Index: ext/soap/tests/schema/schema087.phpt =================================================================== --- ext/soap/tests/schema/schema087.phpt (Revision 0) +++ ext/soap/tests/schema/schema087.phpt (Revision 0) @@ -0,0 +1,59 @@ +--TEST-- +SOAP XML Schema 87: xsd:dateTime DateTime to XML conversion +--SKIPIF-- + +--INI-- +date.timezone=Etc/GMT-2 +--FILE-- + +--EXPECT-- + +2009-06-15T13:35:20.1224Z +object(DateTime)#5 (3) { + ["date"]=> + string(19) "2009-06-15 13:35:20" + ["timezone_type"]=> + int(2) + ["timezone"]=> + string(1) "Z" +} + +2009-06-15T15:35:20.1234Z +object(DateTime)#6 (3) { + ["date"]=> + string(19) "2009-06-15 15:35:20" + ["timezone_type"]=> + int(2) + ["timezone"]=> + string(1) "Z" +} + +2009-06-15T09:35:20.12Z +object(DateTime)#5 (3) { + ["date"]=> + string(19) "2009-06-15 09:35:20" + ["timezone_type"]=> + int(2) + ["timezone"]=> + string(1) "Z" +} + +-2009-06-15T09:35:20.1234Z +object(DateTime)#6 (3) { + ["date"]=> + string(20) "-2009-06-15 09:35:20" + ["timezone_type"]=> + int(2) + ["timezone"]=> + string(1) "Z" +} +ok \ No newline at end of file Index: ext/soap/tests/schema/schema088.phpt =================================================================== --- ext/soap/tests/schema/schema088.phpt (Revision 0) +++ ext/soap/tests/schema/schema088.phpt (Revision 0) @@ -0,0 +1,36 @@ +--TEST-- +SOAP XML Schema 88: xsd:dateTime XML to DateTime conversion +--SKIPIF-- + +--INI-- +date.timezone=Europe/Berlin +--FILE-- + +--EXPECT-- + +1956-10-18 +object(DateTime)#4 (3) { + ["date"]=> + string(19) "1956-10-18 00:00:00" + ["timezone_type"]=> + int(3) + ["timezone"]=> + string(13) "Europe/Berlin" +} + +1956-10-18-07:00 +object(DateTime)#5 (3) { + ["date"]=> + string(19) "1956-10-18 00:00:00" + ["timezone_type"]=> + int(1) + ["timezone"]=> + string(6) "-07:00" +} +ok \ No newline at end of file Index: ext/soap/tests/schema/schema089.phpt =================================================================== --- ext/soap/tests/schema/schema089.phpt (Revision 0) +++ ext/soap/tests/schema/schema089.phpt (Revision 0) @@ -0,0 +1,36 @@ +--TEST-- +SOAP XML Schema 89: xsd:dateTime DateTime to XML conversion +--SKIPIF-- + +--INI-- +date.timezone=Etc/GMT-2 +--FILE-- + +--EXPECT-- + +2009-06-14T21:00:00Z +object(DateTime)#5 (3) { + ["date"]=> + string(19) "2009-06-15 02:00:00" + ["timezone_type"]=> + int(2) + ["timezone"]=> + string(1) "Z" +} + +2009-06-14T21:00:00Z +object(DateTime)#6 (3) { + ["date"]=> + string(19) "2009-06-14 21:00:00" + ["timezone_type"]=> + int(2) + ["timezone"]=> + string(1) "Z" +} +ok \ No newline at end of file Index: ext/soap/tests/schema/schema090.phpt =================================================================== --- ext/soap/tests/schema/schema090.phpt (Revision 0) +++ ext/soap/tests/schema/schema090.phpt (Revision 0) @@ -0,0 +1,36 @@ +--TEST-- +SOAP XML Schema 90: xsd:dateTime XML to DateTime conversion +--SKIPIF-- + +--INI-- +date.timezone=Europe/Berlin +--FILE-- + +--EXPECTF-- + +22:20:00.1234-07:00 +object(DateTime)#4 (3) { + ["date"]=> + string(19) "%d-%d-%d 22:20:00" + ["timezone_type"]=> + int(1) + ["timezone"]=> + string(6) "-07:00" +} + +22:20:00 +object(DateTime)#5 (3) { + ["date"]=> + string(19) "%d-%d-%d 22:20:00" + ["timezone_type"]=> + int(3) + ["timezone"]=> + string(13) "Europe/Berlin" +} +ok \ No newline at end of file Index: ext/soap/tests/schema/schema086.phpt =================================================================== --- ext/soap/tests/schema/schema086.phpt (Revision 0) +++ ext/soap/tests/schema/schema086.phpt (Revision 0) @@ -0,0 +1,58 @@ +--TEST-- +SOAP XML Schema 86: xsd:dateTime XML to DateTime conversion +--SKIPIF-- + +--INI-- +date.timezone=Europe/Berlin +--FILE-- + +--EXPECT-- + +1956-10-18T22:20:00.1234-07:00 +object(DateTime)#4 (3) { + ["date"]=> + string(19) "1956-10-18 22:20:00" + ["timezone_type"]=> + int(1) + ["timezone"]=> + string(6) "-07:00" +} + +1956-10-18T22:20:00Z +object(DateTime)#5 (3) { + ["date"]=> + string(19) "1956-10-18 22:20:00" + ["timezone_type"]=> + int(2) + ["timezone"]=> + string(1) "Z" +} + +1956-10-18T22:20:00.1234 +object(DateTime)#4 (3) { + ["date"]=> + string(19) "1956-10-18 22:20:00" + ["timezone_type"]=> + int(3) + ["timezone"]=> + string(13) "Europe/Berlin" +} + +-1956-10-18T22:20:00.1234-07:00 +object(DateTime)#5 (3) { + ["date"]=> + string(20) "-1956-10-18 22:20:00" + ["timezone_type"]=> + int(1) + ["timezone"]=> + string(6) "-07:00" +} +ok Index: ext/soap/php_encoding.c =================================================================== --- ext/soap/php_encoding.c (Revision 286909) +++ ext/soap/php_encoding.c (Arbeitskopie) @@ -27,7 +27,13 @@ #include #include "zend_strtod.h" #include "zend_interfaces.h" +#include "ext/date/lib/timelib.h" +#include "ext/date/php_date.h" +#ifdef PHP_WIN32 +# include "win32/php_stdint.h" +#endif + /* zval type decode */ static zval *to_zval_double(encodeTypePtr type, xmlNodePtr data); static zval *to_zval_long(encodeTypePtr type, xmlNodePtr data); @@ -39,6 +45,7 @@ static zval *to_zval_null(encodeTypePtr type, xmlNodePtr data); static zval *to_zval_base64(encodeTypePtr type, xmlNodePtr data); static zval *to_zval_hexbin(encodeTypePtr type, xmlNodePtr data); +static zval *to_zval_datetime(encodeTypePtr type, xmlNodePtr data); static xmlNodePtr to_xml_long(encodeTypePtr type, zval *data, int style, xmlNodePtr parent); static xmlNodePtr to_xml_double(encodeTypePtr type, zval *data, int style, xmlNodePtr parent); @@ -60,7 +67,7 @@ static xmlNodePtr to_xml_list1(encodeTypePtr enc, zval *data, int style, xmlNodePtr parent); /* Datetime encode/decode */ -static xmlNodePtr to_xml_datetime_ex(encodeTypePtr type, zval *data, char *format, int style, xmlNodePtr parent); +static xmlNodePtr to_xml_datetime_ex(encodeTypePtr type, zval *data, int style, xmlNodePtr parent, void (*format_func)(timelib_time *, smart_str *)); static xmlNodePtr to_xml_datetime(encodeTypePtr type, zval *data, int style, xmlNodePtr parent); static xmlNodePtr to_xml_time(encodeTypePtr type, zval *data, int style, xmlNodePtr parent); static xmlNodePtr to_xml_date(encodeTypePtr type, zval *data, int style, xmlNodePtr parent); @@ -146,9 +153,9 @@ {{XSD_FLOAT, XSD_FLOAT_STRING, XSD_NAMESPACE, NULL}, to_zval_double, to_xml_double}, {{XSD_DOUBLE, XSD_DOUBLE_STRING, XSD_NAMESPACE, NULL}, to_zval_double, to_xml_double}, - {{XSD_DATETIME, XSD_DATETIME_STRING, XSD_NAMESPACE, NULL}, to_zval_stringc, to_xml_datetime}, - {{XSD_TIME, XSD_TIME_STRING, XSD_NAMESPACE, NULL}, to_zval_stringc, to_xml_time}, - {{XSD_DATE, XSD_DATE_STRING, XSD_NAMESPACE, NULL}, to_zval_stringc, to_xml_date}, + {{XSD_DATETIME, XSD_DATETIME_STRING, XSD_NAMESPACE, NULL}, to_zval_datetime, to_xml_datetime}, + {{XSD_TIME, XSD_TIME_STRING, XSD_NAMESPACE, NULL}, to_zval_datetime, to_xml_time}, + {{XSD_DATE, XSD_DATE_STRING, XSD_NAMESPACE, NULL}, to_zval_datetime, to_xml_date}, {{XSD_GYEARMONTH, XSD_GYEARMONTH_STRING, XSD_NAMESPACE, NULL}, to_zval_stringc, to_xml_gyearmonth}, {{XSD_GYEAR, XSD_GYEAR_STRING, XSD_NAMESPACE, NULL}, to_zval_stringc, to_xml_gyear}, {{XSD_GMONTHDAY, XSD_GMONTHDAY_STRING, XSD_NAMESPACE, NULL}, to_zval_stringc, to_xml_gmonthday}, @@ -837,6 +844,31 @@ return ret; } +static zval *to_zval_datetime(encodeTypePtr type, xmlNodePtr data) +{ + zval *ret = to_zval_stringc(type, data); + if (SOAP_GLOBAL(features) & SOAP_MARSHAL_DATETIME) { + + zval *object; + zend_class_entry *ce = php_date_get_date_ce(); + + ALLOC_ZVAL(object); + Z_TYPE_P(object) = IS_OBJECT; + object_init_ex(object, ce); + Z_SET_REFCOUNT_P(object, 1); + Z_SET_ISREF_P(object); + + zend_call_method_with_1_params(&object, ce, &ce->constructor, "__construct", NULL, ret); + zval_ptr_dtor(&ret); + + return object; + } + else { + return ret; + } +} + + static xmlNodePtr to_xml_string(encodeTypePtr type, zval *data, int style, xmlNodePtr parent) { xmlNodePtr ret, text; @@ -2959,15 +2991,8 @@ } /* Time encode/decode */ -static xmlNodePtr to_xml_datetime_ex(encodeTypePtr type, zval *data, char *format, int style, xmlNodePtr parent) +static xmlNodePtr to_xml_datetime_ex(encodeTypePtr type, zval *data, int style, xmlNodePtr parent, void (*format_func)(timelib_time *, smart_str *)) { - /* logic hacked from ext/standard/datetime.c */ - struct tm *ta, tmbuf; - time_t timestamp; - int max_reallocs = 5; - size_t buf_len=64, real_len; - char *buf; - char tzbuf[8]; xmlNodePtr xmlParam; @@ -2975,48 +3000,59 @@ xmlAddChild(parent, xmlParam); FIND_ZVAL_NULL(data, xmlParam, style); - if (Z_TYPE_P(data) == IS_LONG) { - timestamp = Z_LVAL_P(data); - ta = php_localtime_r(×tamp, &tmbuf); - /*ta = php_gmtime_r(×tamp, &tmbuf);*/ - - buf = (char *) emalloc(buf_len); - while ((real_len = strftime(buf, buf_len, format, ta)) == buf_len || real_len == 0) { - buf_len *= 2; - buf = (char *) erealloc(buf, buf_len); - if (!--max_reallocs) break; - } - - /* Time zone support */ -#ifdef HAVE_TM_GMTOFF - snprintf(tzbuf, sizeof(tzbuf), "%c%02d:%02d", (ta->tm_gmtoff < 0) ? '-' : '+', abs(ta->tm_gmtoff / 3600), abs( (ta->tm_gmtoff % 3600) / 60 )); -#else -# if defined(__CYGWIN__) || defined(NETWARE) - snprintf(tzbuf, sizeof(tzbuf), "%c%02d:%02d", ((ta->tm_isdst ? _timezone - 3600:_timezone)>0)?'-':'+', abs((ta->tm_isdst ? _timezone - 3600 : _timezone) / 3600), abs(((ta->tm_isdst ? _timezone - 3600 : _timezone) % 3600) / 60)); -# else - snprintf(tzbuf, sizeof(tzbuf), "%c%02d:%02d", ((ta->tm_isdst ? timezone - 3600:timezone)>0)?'-':'+', abs((ta->tm_isdst ? timezone - 3600 : timezone) / 3600), abs(((ta->tm_isdst ? timezone - 3600 : timezone) % 3600) / 60)); -# endif -#endif - if (strcmp(tzbuf,"+00:00") == 0) { - strcpy(tzbuf,"Z"); - real_len++; + if (Z_TYPE_P(data) == IS_STRING) { + xmlNodeSetContentLen(xmlParam, BAD_CAST(Z_STRVAL_P(data)), Z_STRLEN_P(data)); + } else { + timelib_time *time = timelib_time_ctor(); + if (Z_TYPE_P(data) == IS_LONG) { + timelib_set_timezone(time, get_timezone_info(TSRMLS_C)); + timelib_unixtime2local(time, (timelib_sll) Z_LVAL_P(data)); + } else if ((SOAP_GLOBAL(features) & SOAP_MARSHAL_DATETIME) && Z_TYPE_P(data) == IS_OBJECT && instanceof_function(Z_OBJCE_P(data), php_date_get_date_ce() TSRMLS_CC)) { + /* XXX: when the developers decide to follow their advice, this should be + * updated to reference `timelib_time_clone`. All we need to do is clone + * the referent's time into our time data. */ + php_date_obj *dateobj = (php_date_obj *) zend_object_store_get_object(data TSRMLS_CC); + + *time = *dateobj->time; + if (dateobj->time->tz_abbr) { + time->tz_abbr = strdup(dateobj->time->tz_abbr); + } + if (dateobj->time->tz_info) { + time->tz_info = dateobj->time->tz_info; + } } else { - real_len += 6; + goto out; } - if (real_len >= buf_len) { - buf = (char *) erealloc(buf, real_len+1); + + if (time->tz_info) { + /* If we have timezone information, switch us to UTC. */ + timelib_apply_localtime(time, 0); } - strcat(buf, tzbuf); - xmlNodeSetContent(xmlParam, BAD_CAST(buf)); - efree(buf); - } else if (Z_TYPE_P(data) == IS_STRING) { - xmlNodeSetContentLen(xmlParam, BAD_CAST(Z_STRVAL_P(data)), Z_STRLEN_P(data)); + { + /* Now format it. We could use `php_format_date`, but unrolling it here + * seems to make enough sense when we want to generate a canonical + * dateTime. */ + smart_str buffer = {0}; + + /* We pass in the ptr to smart_str to the formatting function so that they + * can be chained or something. Flexible, easy, etc. */ + format_func(time, &buffer); + + /* And we can finalize it sanely here which is always good. */ + smart_str_0(&buffer); + xmlNodeSetContentLen(xmlParam, BAD_CAST(buffer.c), buffer.len); + smart_str_free(&buffer); + } + + out: + timelib_time_dtor(time); } if (style == SOAP_ENCODED) { set_ns_and_type(xmlParam, type); } + return xmlParam; } @@ -3026,45 +3062,174 @@ return to_xml_string(type, data, style, parent); } +static void to_xml_datetime_format(timelib_time *time, smart_str *buffer) +{ + char temp[33]; + int length; + int time_frac; + + /* Why are these members declared as signed long longs? I don't know about + * you, but I'm not worried about there ever being more than 12 months in + * one year, and certainly no more than INT_MAX. My poor brain can't count + * that high. */ + /* seconds are appended further down */ + length = slprintf(temp, 32, "%04d-%02d-%02dT%02d:%02d:%02d", + (int) time->y, /* Year */ + (int) time->m, /* Month */ + (int) time->d, /* Day */ + (int) time->h, /* Hour */ + (int) time->i, /* Minute */ + (int) time->s /* Second */); + smart_str_appendl(buffer, temp, length); + + time_frac = (int) floor(time->f * 1000000); + if (time_frac > 0) { + while (time_frac % 10 == 0) { + time_frac /= 10; + } + + length = slprintf(temp, 32, ".%d", time_frac); + smart_str_appendl(buffer, temp, length); + } + + if (time->tz_info) { + /* Add a 'Z' to indicate that this is a "timezoned" value. */ + smart_str_appendc(buffer, 'Z'); + } +} + static xmlNodePtr to_xml_datetime(encodeTypePtr type, zval *data, int style, xmlNodePtr parent) { - return to_xml_datetime_ex(type, data, "%Y-%m-%dT%H:%M:%S", style, parent); + return to_xml_datetime_ex(type, data, style, parent, to_xml_datetime_format /* Y-m-dTH:i:s */); } +static void to_xml_time_format(timelib_time *time, smart_str *buffer) +{ + char temp[33]; + int length; + int time_frac; + + length = slprintf(temp, 32, "%02d:%02d:%02d", + (int) time->h, /* Hour */ + (int) time->i, /* Minute */ + (int) time->s /* Second */); + smart_str_appendl(buffer, temp, length); + + time_frac = (int) floor(time->f * 1000000); + if (time_frac > 0) { + while (time_frac % 10 == 0) { + time_frac /= 10; + } + + length = slprintf(temp, 32, ".%d", time_frac); + smart_str_appendl(buffer, temp, length); + } + + if (time->tz_info) { + /* Add a 'Z' to indicate that this is a "timezoned" value. */ + smart_str_appendc(buffer, 'Z'); + } +} + static xmlNodePtr to_xml_time(encodeTypePtr type, zval *data, int style, xmlNodePtr parent) { - /* TODO: microsecconds */ - return to_xml_datetime_ex(type, data, "%H:%M:%S", style, parent); + return to_xml_datetime_ex(type, data, style, parent, to_xml_time_format /* H:i:s(.sss) */); } +static void to_xml_date_format(timelib_time *time, smart_str *buffer) +{ + char temp[33]; + int length; + + length = slprintf(temp, 32, "%04d-%02d-%02d", + (int) time->y, /* Year */ + (int) time->m, /* Month */ + (int) time->d /* Day */); + smart_str_appendl(buffer, temp, length); + + if (time->tz_info) { + /* Add a 'Z' to indicate that this is a "timezoned" value. */ + smart_str_appendc(buffer, 'Z'); + } +} + static xmlNodePtr to_xml_date(encodeTypePtr type, zval *data, int style, xmlNodePtr parent) { - return to_xml_datetime_ex(type, data, "%Y-%m-%d", style, parent); + return to_xml_datetime_ex(type, data, style, parent, to_xml_date_format /* Y-m-d */); } +static void to_xml_gyearmonth_format(timelib_time *time, smart_str *buffer) +{ + char temp[33]; + int length; + + length = slprintf(temp, 32, "%04d-%02d", + (int) time->y, /* Year */ + (int) time->m /* Month */); + smart_str_appendl(buffer, temp, length); +} + static xmlNodePtr to_xml_gyearmonth(encodeTypePtr type, zval *data, int style, xmlNodePtr parent) { - return to_xml_datetime_ex(type, data, "%Y-%m", style, parent); + return to_xml_datetime_ex(type, data, style, parent, to_xml_gyearmonth_format /* Y-m */); } +static void to_xml_gyear_format(timelib_time *time, smart_str *buffer) +{ + char temp[33]; + int length; + + length = slprintf(temp, 32, "%04d", (int) time->y /* Year */); + smart_str_appendl(buffer, temp, length); +} + static xmlNodePtr to_xml_gyear(encodeTypePtr type, zval *data, int style, xmlNodePtr parent) { - return to_xml_datetime_ex(type, data, "%Y", style, parent); + return to_xml_datetime_ex(type, data, style, parent, to_xml_gyear_format /* Y */); } +static void to_xml_gmonthday_format(timelib_time *time, smart_str *buffer) +{ + char temp[33]; + int length; + + length = slprintf(temp, 32, "--%02d-%02d", + (int) time->m, /* Month */ + (int) time->d /* Day */); + smart_str_appendl(buffer, temp, length); +} + static xmlNodePtr to_xml_gmonthday(encodeTypePtr type, zval *data, int style, xmlNodePtr parent) { - return to_xml_datetime_ex(type, data, "--%m-%d", style, parent); + return to_xml_datetime_ex(type, data, style, parent, to_xml_gmonthday_format /* --m-d */); } +static void to_xml_gday_format(timelib_time *time, smart_str *buffer) +{ + char temp[33]; + int length; + + length = slprintf(temp, 32, "---%02d", (int) time->d /* Day */); + smart_str_appendl(buffer, temp, length); +} + static xmlNodePtr to_xml_gday(encodeTypePtr type, zval *data, int style, xmlNodePtr parent) { - return to_xml_datetime_ex(type, data, "---%d", style, parent); + return to_xml_datetime_ex(type, data, style, parent, to_xml_gday_format /* ---d */); } +static void to_xml_gmonth_format(timelib_time *time, smart_str *buffer) +{ + char temp[33]; + int length; + + length = slprintf(temp, 32, "--%02d", (int) time->m /* Month */); + smart_str_appendl(buffer, temp, length); +} + static xmlNodePtr to_xml_gmonth(encodeTypePtr type, zval *data, int style, xmlNodePtr parent) { - return to_xml_datetime_ex(type, data, "--%m--", style, parent); + return to_xml_datetime_ex(type, data, style, parent, to_xml_gmonth_format /* --m */); } static zval* to_zval_list(encodeTypePtr enc, xmlNodePtr data) { --Apple-Mail-5-768523318 Content-Type: text/plain; charset=US-ASCII; format=flowed Content-Transfer-Encoding: 7bit --Apple-Mail-5-768523318-- --Apple-Mail-6-768523375 Content-Disposition: attachment; filename=smime.p7s Content-Type: application/pkcs7-signature; name=smime.p7s Content-Transfer-Encoding: base64 MIAGCSqGSIb3DQEHAqCAMIACAQExCzAJBgUrDgMCGgUAMIAGCSqGSIb3DQEHAQAAoIIGXDCCAxUw ggJ+oAMCAQICEHvgrI6DXM4XmK4XvhB7lh4wDQYJKoZIhvcNAQEFBQAwYjELMAkGA1UEBhMCWkEx JTAjBgNVBAoTHFRoYXd0ZSBDb25zdWx0aW5nIChQdHkpIEx0ZC4xLDAqBgNVBAMTI1RoYXd0ZSBQ ZXJzb25hbCBGcmVlbWFpbCBJc3N1aW5nIENBMB4XDTA4MDgyMjE0MjEzOVoXDTA5MDgyMjE0MjEz OVowTjEfMB0GA1UEAxMWVGhhd3RlIEZyZWVtYWlsIE1lbWJlcjErMCkGCSqGSIb3DQEJARYcZGF2 aWQuenVlbGtlQGJpdGV4dGVuZGVyLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB ANx+fe+8oUaO+fotZryRBmD3NAP00QikUIqIyZKiwJ4BS9M8DdqN0lAh443rdw1h/H0NVkDMv7+7 MnSUYKU+BTwulvU7WDGLm7JGkXXWkGl5vHUnUWltUkk8ImUDiunYPnuyUVyQlnZkp1ThihYoR4xo MmiiC+6mHLl8FzMKimOU/UREpGfyLqYhsNdXiVgm+W8feO6aY3fDaenn9EVZEXJs6t7KxLpCIlD2 8+0dHlX+91vV4a9zfMObjEkLW3w/uBTT+uHypySHo/EWw0/pOD34sMdhSh0Xyr4un+Uv/DHH1ft3 5TJq6DEIrIL4iUpGa7Nsqjoah5SgpWwJY+gWaC8CAwEAAaNcMFowDgYDVR0PAQH/BAQDAgSwMBEG CWCGSAGG+EIBAQQEAwIFIDAnBgNVHREEIDAegRxkYXZpZC56dWVsa2VAYml0ZXh0ZW5kZXIuY29t MAwGA1UdEwEB/wQCMAAwDQYJKoZIhvcNAQEFBQADgYEAbEPiMjevqmbl2NuGieZkF5fNV1Uhr0dL wGDDxIcIHGnBeEBVy/5NpAKJUCU4lqG+bqD1S4MdyyLxvzlhOSZEqjcEwtwXqLVsaDakYFHsRGaS DU160+1b/wlf8/OR5tof7y5MA8p6MSQHjXWOy38A71wvwFowGZPF5lY617W5mUMwggM/MIICqKAD AgECAgENMA0GCSqGSIb3DQEBBQUAMIHRMQswCQYDVQQGEwJaQTEVMBMGA1UECBMMV2VzdGVybiBD YXBlMRIwEAYDVQQHEwlDYXBlIFRvd24xGjAYBgNVBAoTEVRoYXd0ZSBDb25zdWx0aW5nMSgwJgYD VQQLEx9DZXJ0aWZpY2F0aW9uIFNlcnZpY2VzIERpdmlzaW9uMSQwIgYDVQQDExtUaGF3dGUgUGVy c29uYWwgRnJlZW1haWwgQ0ExKzApBgkqhkiG9w0BCQEWHHBlcnNvbmFsLWZyZWVtYWlsQHRoYXd0 ZS5jb20wHhcNMDMwNzE3MDAwMDAwWhcNMTMwNzE2MjM1OTU5WjBiMQswCQYDVQQGEwJaQTElMCMG A1UEChMcVGhhd3RlIENvbnN1bHRpbmcgKFB0eSkgTHRkLjEsMCoGA1UEAxMjVGhhd3RlIFBlcnNv bmFsIEZyZWVtYWlsIElzc3VpbmcgQ0EwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAMSmPFVz VftOucqZWh5owHUEcJ3f6f+jHuy9zfVb8hp2vX8MOmHyv1HOAdTlUAow1wJjWiyJFXCO3cnwK4Va qj9xVsuvPAsH5/EfkTYkKhPPK9Xzgnc9A74r/rsYPge/QIACZNenprufZdHFKlSFD0gEf6e20Txh BEAeZBlyYLf7AgMBAAGjgZQwgZEwEgYDVR0TAQH/BAgwBgEB/wIBADBDBgNVHR8EPDA6MDigNqA0 hjJodHRwOi8vY3JsLnRoYXd0ZS5jb20vVGhhd3RlUGVyc29uYWxGcmVlbWFpbENBLmNybDALBgNV HQ8EBAMCAQYwKQYDVR0RBCIwIKQeMBwxGjAYBgNVBAMTEVByaXZhdGVMYWJlbDItMTM4MA0GCSqG SIb3DQEBBQUAA4GBAEiM0VCD6gsuzA2jZqxnD3+vrL7CF6FDlpSdf0whuPg2H6otnzYvwPQcUCCT cDz9reFhYsPZOhl+hLGZGwDFGguCdJ4lUJRix9sncVcljd2pnDmOjCBPZV+V2vf3h9bGCE6u9uo0 5RAaWzVNd+NWIXiC3CEZNd4ksdMdRv9dX2VPMYIDEDCCAwwCAQEwdjBiMQswCQYDVQQGEwJaQTEl MCMGA1UEChMcVGhhd3RlIENvbnN1bHRpbmcgKFB0eSkgTHRkLjEsMCoGA1UEAxMjVGhhd3RlIFBl cnNvbmFsIEZyZWVtYWlsIElzc3VpbmcgQ0ECEHvgrI6DXM4XmK4XvhB7lh4wCQYFKw4DAhoFAKCC AW8wGAYJKoZIhvcNAQkDMQsGCSqGSIb3DQEHATAcBgkqhkiG9w0BCQUxDxcNMDkwODA3MTUyNDIz WjAjBgkqhkiG9w0BCQQxFgQUZAYD2R5fsE5+1ZE/jdUpL1Ofv2gwgYUGCSsGAQQBgjcQBDF4MHYw YjELMAkGA1UEBhMCWkExJTAjBgNVBAoTHFRoYXd0ZSBDb25zdWx0aW5nIChQdHkpIEx0ZC4xLDAq BgNVBAMTI1RoYXd0ZSBQZXJzb25hbCBGcmVlbWFpbCBJc3N1aW5nIENBAhB74KyOg1zOF5iuF74Q e5YeMIGHBgsqhkiG9w0BCRACCzF4oHYwYjELMAkGA1UEBhMCWkExJTAjBgNVBAoTHFRoYXd0ZSBD b25zdWx0aW5nIChQdHkpIEx0ZC4xLDAqBgNVBAMTI1RoYXd0ZSBQZXJzb25hbCBGcmVlbWFpbCBJ c3N1aW5nIENBAhB74KyOg1zOF5iuF74Qe5YeMA0GCSqGSIb3DQEBAQUABIIBADy1lQfHYHZylfWH 4+x9h8Ql3dCJgJTKz6FGv5RqXAU0aBBuudlJzIfp3RQrPKELHQjxVsdcbl9Lyz8RL/wXkpIp/F9K O9ZtlVtneTfEjZ5XnOLZTx35cZ4NoCumAUVfrG79vHCWqb1nftNmgr7RInSRSAaBzm4Sx1CpoWo2 R47rf8rZACURliSpNpSj3mTFn0sJy1Gl8R2gSEhiq/Y+rxk3wmhiZkpFWm2ME7KrsIkyO8cOHATN zBD+pMffXMm+SPEb3BOjgevNV+C1b2qNwFc0zu4y4ANbUMsiVE3YehwDjczlufqdbA1roc/Cgn2k 8Eh8pBh8zuyeWhCAJNnZrFcAAAAAAAA= --Apple-Mail-6-768523375--