static VALUE
time_mload(VALUE time, VALUE str)
{
struct time_object *tobj;
unsigned long p, s;
time_t sec;
long usec;
unsigned char *buf;
struct vtm vtm;
int i, gmt;
long nsec;
VALUE submicro, nano_num, nano_den, offset;
wideval_t timew;
time_modify(time);
nano_num = rb_attr_get(str, id_nano_num);
if (nano_num != Qnil) {
st_delete(rb_generic_ivar_table(str), (st_data_t*)&id_nano_num, 0);
}
nano_den = rb_attr_get(str, id_nano_den);
if (nano_den != Qnil) {
st_delete(rb_generic_ivar_table(str), (st_data_t*)&id_nano_den, 0);
}
submicro = rb_attr_get(str, id_submicro);
if (submicro != Qnil) {
st_delete(rb_generic_ivar_table(str), (st_data_t*)&id_submicro, 0);
}
offset = rb_attr_get(str, id_offset);
if (offset != Qnil) {
validate_utc_offset(offset);
st_delete(rb_generic_ivar_table(str), (st_data_t*)&id_offset, 0);
}
rb_copy_generic_ivar(time, str);
StringValue(str);
buf = (unsigned char *)RSTRING_PTR(str);
if (RSTRING_LEN(str) != 8) {
rb_raise(rb_eTypeError, "marshaled time format differ");
}
p = s = 0;
for (i=0; i<4; i++) {
p |= buf[i]<<(8*i);
}
for (i=4; i<8; i++) {
s |= buf[i]<<(8*(i-4));
}
if ((p & (1UL<<31)) == 0) {
gmt = 0;
offset = Qnil;
sec = p;
usec = s;
nsec = usec * 1000;
timew = wadd(rb_time_magnify(TIMET2WV(sec)), wmulquoll(WINT2FIXWV(usec), TIME_SCALE, 1000000));
}
else {
p &= ~(1UL<<31);
gmt = (int)((p >> 30) & 0x1);
vtm.year = INT2FIX(((int)(p >> 14) & 0xffff) + 1900);
vtm.mon = ((int)(p >> 10) & 0xf) + 1;
vtm.mday = (int)(p >> 5) & 0x1f;
vtm.hour = (int) p & 0x1f;
vtm.min = (int)(s >> 26) & 0x3f;
vtm.sec = (int)(s >> 20) & 0x3f;
vtm.utc_offset = INT2FIX(0);
vtm.yday = vtm.wday = 0;
vtm.isdst = 0;
vtm.zone = "";
usec = (long)(s & 0xfffff);
nsec = usec * 1000;
vtm.subsecx = mulquo(LONG2FIX(nsec), INT2FIX(TIME_SCALE), LONG2FIX(1000000000));
if (nano_num != Qnil) {
VALUE nano = quo(num_exact(nano_num), num_exact(nano_den));
vtm.subsecx = add(vtm.subsecx, mulquo(nano, INT2FIX(TIME_SCALE), LONG2FIX(1000000000)));
}
else if (submicro != Qnil) { /* for Ruby 1.9.1 compatibility */
unsigned char *ptr;
long len;
int digit;
ptr = (unsigned char*)StringValuePtr(submicro);
len = RSTRING_LEN(submicro);
nsec = 0;
if (0 < len) {
if (10 <= (digit = ptr[0] >> 4)) goto end_submicro;
nsec += digit * 100;
if (10 <= (digit = ptr[0] & 0xf)) goto end_submicro;
nsec += digit * 10;
}
if (1 < len) {
if (10 <= (digit = ptr[1] >> 4)) goto end_submicro;
nsec += digit;
}
vtm.subsecx = add(vtm.subsecx, mulquo(LONG2FIX(nsec), INT2FIX(TIME_SCALE), LONG2FIX(1000000000)));
end_submicro: ;
}
timew = timegmw(&vtm);
}
GetTimeval(time, tobj);
tobj->tm_got = 0;
tobj->timew = timew;
if (gmt) {
TIME_SET_UTC(tobj);
}
else if (!NIL_P(offset)) {
time_set_utc_offset(time, offset);
time_fixoff(time);
}
return time;
}