Пример #1
0
def test_convert_string_to_number_overflow():
    assert convert_string_to_number(
        '1' * 100) == (Float(1.11111111111111111111111111e99), True)
    assert convert_string_to_number('-' + '1' * 100) == (
        Float(-1.111111111111111111111111e99), True)
    assert convert_string_to_number('0x' + '1' * 100) == (Float(
        float(int('1' * 100, 16))), True)
    assert convert_string_to_number('-0x' + '1' * 100) == (Int(0), False)
Пример #2
0
def test_convert_string_to_number_overflow():
    assert convert_string_to_number('1' * 100) == (
        Float(1.11111111111111111111111111e99), True)
    assert convert_string_to_number('-' + '1' * 100) == (
        Float(-1.111111111111111111111111e99), True)
    assert convert_string_to_number('0x' + '1' * 100) == (
        Float(float(int('1' * 100, 16))), True)
    assert convert_string_to_number('-0x' + '1' * 100) == (
        Int(0), False)
Пример #3
0
 def is_really_int(self, w_obj):
     if w_obj.tp == self.tp_str:
         w_obj, fully_processed = convert_string_to_number(
             self.str_w(w_obj))
         if not fully_processed:
             return None
     if w_obj.tp == self.tp_int:
         return w_obj
Пример #4
0
 def as_int_arg(self, space):
     if not self.is_numeric():
         raise ConvertError('not a numeric string')
     s = self.unwrap()
     w_obj, valid = convert_string_to_number(s)
     if not valid:
         space.ec.notice("A non well formed numeric value encountered")
     return w_obj.int_w(space)
Пример #5
0
 def is_really_int(self, w_obj):
     if w_obj.tp == self.tp_str:
         w_obj, fully_processed = convert_string_to_number(
             self.str_w(w_obj))
         if not fully_processed:
             return None
     if w_obj.tp == self.tp_int:
         return w_obj
Пример #6
0
 def as_int_arg(self, space):
     if not self.is_numeric():
         raise ConvertError('not a numeric string')
     s = self.unwrap()
     w_obj, valid = convert_string_to_number(s)
     if not valid:
         space.ec.notice("A non well formed numeric value encountered")
     return w_obj.int_w(space)
Пример #7
0
 def overflow_convert(self, space):
     w_obj, fully_processed = convert_string_to_number(self.unwrap())
     if not fully_processed:
         if self.float_w(space) != 0.0:
             space.ec.notice("A non well formed numeric "
                            "value encountered")
         else:
             raise TypeError
     return w_obj
Пример #8
0
 def overflow_convert(self, space):
     w_obj, fully_processed = convert_string_to_number(self.unwrap())
     if not fully_processed:
         if self.float_w(space) != 0.0:
             space.ec.notice("A non well formed numeric "
                            "value encountered")
         else:
             raise TypeError
     return w_obj
Пример #9
0
def load_primitive(space, fp, type_):
    if type_ == 's':
        fp.expect(':')
        old1 = fp.pos
        length = fp.read_nonneg_int_until(':')
        fp.expect('"')
        fp.error_pos = old1
        data = fp.read(length)
        fp.error_pos = fp.pos
        fp.expect('"')
        fp.error_pos = fp.pos + 1
        fp.expect(';')
        return space.newstr(data)
    elif type_ == 'N':
        fp.expect(';')
        return space.w_Null
    elif type_ == 'i':
        fp.expect(':')
        data = fp.read_until(';')
        try:
            i = int(data)
        except ValueError:
            raise SerializerError('bad int')
        return space.wrap(i)
    elif type_ == 'd':
        fp.expect(':')
        data = fp.read_until(';')
        w_number, valid = convert_string_to_number(data)
        if not valid:
            raise SerializerError('bad double')
        return space.newfloat(w_number.float_w(space))
    elif type_ == 'b':
        fp.expect(':')
        digit = fp.readchr()
        if digit == '0':
            w_result = space.w_False
        elif digit == '1':
            w_result = space.w_True
        else:
            raise SerializerError('bad bool')
        fp.expect(';')
        return w_result
    elif type_ == '}':
        space.ec.notice("unserialize(): Unexpected end of serialized data")
    raise SerializerError('malformed input')
Пример #10
0
def load_primitive(space, fp, type_):
    if type_ == 's':
        fp.expect(':')
        old1 = fp.pos
        length = fp.read_nonneg_int_until(':')
        fp.expect('"')
        fp.error_pos = old1
        data = fp.read(length)
        fp.error_pos = fp.pos
        fp.expect('"')
        fp.error_pos = fp.pos + 1
        fp.expect(';')
        return space.newstr(data)
    elif type_ == 'N':
        fp.expect(';')
        return space.w_Null
    elif type_ == 'i':
        fp.expect(':')
        data = fp.read_until(';')
        try:
            i = int(data)
        except ValueError:
            raise SerializerError('bad int')
        return space.wrap(i)
    elif type_ == 'd':
        fp.expect(':')
        data = fp.read_until(';')
        w_number, valid = convert_string_to_number(data)
        if not valid:
            raise SerializerError('bad double')
        return space.newfloat(w_number.float_w(space))
    elif type_ == 'b':
        fp.expect(':')
        digit = fp.readchr()
        if digit == '0':
            w_result = space.w_False
        elif digit == '1':
            w_result = space.w_True
        else:
            raise SerializerError('bad bool')
        fp.expect(';')
        return w_result
    elif type_ == '}':
        space.ec.notice("unserialize(): Unexpected end of serialized data")
    raise SerializerError('malformed input')
Пример #11
0
 def as_stringoffset(self, space, give_notice):
     # pom pom pom
     s = self.unwrap()
     intval, any_digit = strtol(s)
     if not any_digit:
         if give_notice:
             space.ec.warn("Illegal string offset '%s'" % s)
             return 0
         else:
             return -1
     w_number_ignored, valid = convert_string_to_number(s)
     if not valid:
         if give_notice:
             space.ec.notice("A non well formed numeric value encountered")
         else:
             return -1
     if w_number_ignored.tp != space.tp_int:
         if give_notice:
             space.ec.warn("Illegal string offset '%s'" % s)
         else:
             return -1
     return intval
Пример #12
0
 def as_stringoffset(self, space, give_notice):
     # pom pom pom
     s = self.unwrap()
     intval, any_digit = strtol(s)
     if not any_digit:
         if give_notice:
             space.ec.warn("Illegal string offset '%s'" % s)
             return 0
         else:
             return -1
     w_number_ignored, valid = convert_string_to_number(s)
     if not valid:
         if give_notice:
             space.ec.notice("A non well formed numeric value encountered")
         else:
             return -1
     if w_number_ignored.tp != space.tp_int:
         if give_notice:
             space.ec.warn("Illegal string offset '%s'" % s)
         else:
             return -1
     return intval
Пример #13
0
def test_convert_string_to_number_int():
    assert convert_string_to_number('') == (Int(0), False)
    assert convert_string_to_number('    ') == (Int(0), False)
    assert convert_string_to_number('+') == (Int(0), False)
    assert convert_string_to_number('-') == (Int(0), False)
    assert convert_string_to_number('1') == (Int(1), True)
    assert convert_string_to_number('\t-101') == (Int(-101), True)
    assert convert_string_to_number('020') == (Int(20), True)
    assert convert_string_to_number('50b') == (Int(50), False)
    assert convert_string_to_number('50x') == (Int(50), False)
    assert convert_string_to_number('5x0') == (Int(5), False)
    assert convert_string_to_number('x50') == (Int(0), False)
    assert convert_string_to_number('0x50') == (Int(80), True)
    assert convert_string_to_number('0X50') == (Int(80), True)
    assert convert_string_to_number('0X50X') == (Int(80), False)
    assert convert_string_to_number('-0x50') == (Int(0), False)
    assert convert_string_to_number('+0x50') == (Int(0), False)
Пример #14
0
 def is_really_valid_number(self, space=None):
     s = self.unwrap()
     w_number, valid = convert_string_to_number(s)
     return valid
Пример #15
0
 def as_number(self, space=None):
     s = self.unwrap()
     w_number, valid = convert_string_to_number(s)
     return w_number      # ignore 'valid'
Пример #16
0
def test_convert_string_to_number_int():
    assert convert_string_to_number('') == (Int(0), False)
    assert convert_string_to_number('    ') == (Int(0), False)
    assert convert_string_to_number('+') == (Int(0), False)
    assert convert_string_to_number('-') == (Int(0), False)
    assert convert_string_to_number('1') == (Int(1), True)
    assert convert_string_to_number('\t-101') == (Int(-101), True)
    assert convert_string_to_number('020') == (Int(20), True)
    assert convert_string_to_number('50b') == (Int(50), False)
    assert convert_string_to_number('50x') == (Int(50), False)
    assert convert_string_to_number('5x0') == (Int(5), False)
    assert convert_string_to_number('x50') == (Int(0), False)
    assert convert_string_to_number('0x50') == (Int(80), True)
    assert convert_string_to_number('0X50') == (Int(80), True)
    assert convert_string_to_number('0X50X') == (Int(80), False)
    assert convert_string_to_number('-0x50') == (Int(0), False)
    assert convert_string_to_number('+0x50') == (Int(0), False)
Пример #17
0
def test_convert_string_to_number_float():
    assert convert_string_to_number(' 5.') == (Float(5.0), True)
    assert convert_string_to_number(' -.5') == (Float(-0.5), True)
    assert convert_string_to_number(' .') == (Int(0), False)
    assert convert_string_to_number(' 10.25') == (Float(10.25), True)
    assert convert_string_to_number(' 10.25X') == (Float(10.25), False)
    #
    assert convert_string_to_number('E5') == (Int(0), False)
    assert convert_string_to_number('.E5') == (Int(0), False)
    assert convert_string_to_number('5E') == (Int(5), False)
    assert convert_string_to_number('5.E') == (Float(5.0), False)
    assert convert_string_to_number('5E-') == (Int(5), False)
    assert convert_string_to_number('5E+') == (Int(5), False)
    assert convert_string_to_number('5E0') == (Float(5.0), True)
    assert convert_string_to_number('5E+0') == (Float(5.0), True)
    assert convert_string_to_number('5E-0') == (Float(5.0), True)
    assert convert_string_to_number('5E2') == (Float(500.0), True)
    assert convert_string_to_number('5E-02') == (Float(0.05), True)
    assert convert_string_to_number('5E-02.9') == (Float(0.05), False)
    assert convert_string_to_number('5E-02E9') == (Float(0.05), False)
    assert convert_string_to_number('5e2') == (Float(500.0), True)
Пример #18
0
    def _compare(self, w_left, w_right, strict=False, ignore_order=False):

        w_left = w_left.deref()
        w_right = w_right.deref()

        left_tp = w_left.tp
        right_tp = w_right.tp

        if strict:
            if left_tp != right_tp:
                return 1

        if (left_tp == self.tp_float and right_tp == self.tp_float):
            return my_cmp(self.float_w(w_left), self.float_w(w_right),
                          ignore_order)

        if (left_tp == self.tp_int and right_tp == self.tp_float):
            return my_cmp(self.float_w(w_left), self.float_w(w_right),
                          ignore_order)

        if (left_tp == self.tp_float and right_tp == self.tp_int):
            return my_cmp(self.float_w(w_left), self.float_w(w_right),
                          ignore_order)

        elif (left_tp == self.tp_int and right_tp == self.tp_int):
            return my_cmp(self.int_w(w_left), self.int_w(w_right),
                          ignore_order)

        elif (left_tp == self.tp_array and right_tp == self.tp_array):
            return self._compare_array(w_left, w_right, strict)

        elif (left_tp == self.tp_null and right_tp == self.tp_null):
            return 0

        elif (left_tp == self.tp_null and right_tp == self.tp_bool):
            if self.is_true(w_right):
                return -1
            return 0

        elif (left_tp == self.tp_bool and right_tp == self.tp_null):
            if self.is_true(w_left):
                return 1
            return 0

        elif (left_tp == self.tp_bool and right_tp == self.tp_bool):
            return my_cmp(self.is_true(w_left), self.is_true(w_right),
                          ignore_order)

        elif (left_tp == self.tp_str and right_tp == self.tp_str):
            left = self.str_w(w_left)
            right = self.str_w(w_right)
            if not strict:
                # a small optimimization first, if both are single-char
                left_length = len(left)
                right_length = len(right)
                if (jit.isconstant(left_length) and left_length == 1
                        and jit.isconstant(right_length)
                        and right_length == 1):
                    return my_cmp(ord(left[0]), ord(right[0]), ignore_order)
                #
                w_right_num, right_valid = convert_string_to_number(right)
                if right_valid:
                    w_left_num, left_valid = convert_string_to_number(left)
                    if left_valid:
                        return self._compare(w_left_num,
                                             w_right_num,
                                             ignore_order=ignore_order)
            return my_cmp(left, right, ignore_order)

        elif (left_tp == self.tp_null and right_tp == self.tp_str):
            return my_cmp("", self.str_w(w_right), ignore_order)

        elif (left_tp == self.tp_str and right_tp == self.tp_null):
            return my_cmp(self.str_w(w_left), "", ignore_order)

        elif (left_tp == self.tp_object and right_tp == self.tp_null):
            return 1

        elif (left_tp == self.tp_null and right_tp == self.tp_object):
            return -1

        elif (left_tp == self.tp_object and right_tp == self.tp_object):
            return w_left.compare(w_right, self, strict)

        else:
            if (left_tp == self.tp_null):
                if self.is_true(w_right):
                    return -1
                return 0
            elif (right_tp == self.tp_null):
                if self.is_true(w_left):
                    return 1
                return 0
            elif (left_tp == self.tp_bool or right_tp == self.tp_bool):
                return my_cmp(self.is_true(w_left), self.is_true(w_right),
                              ignore_order)
            elif (left_tp == self.tp_array):
                return 1
            elif (right_tp == self.tp_array):
                return -1
            elif (left_tp == self.tp_object):
                return 1
            elif (right_tp == self.tp_object):
                return -1
            else:
                return self._compare(self.as_number(w_left),
                                     self.as_number(w_right),
                                     ignore_order=ignore_order)
        raise NotImplementedError()
Пример #19
0
def test_precision_issues():
    assert convert_string_to_number('55123.456') == (Float(55123.456), True)
Пример #20
0
def load_object(fp):
    fp.next_reference_obj -= 1
    needs_ref = (fp.next_reference_obj == 0)
    #
    fp.error_pos = fp.pos
    try:
        i = fp.consume(2)
    except SerializerError:
        i = fp.consume(1)
        if fp.s[i] == '}':
            fp.space.ec.notice("unserialize(): "
                               "Unexpected end of serialized data")
        raise
    s = fp.s
    tp = s[i]
    check_nonneg(i)
    check_nonneg(fp.pos)
    #
    if tp == 'i':
        if s[i + 1] != ':':
            raise SerializerError("':' expected")
        i = fp.read_int_until(';')
        w_result = fp.space.wrap(i)
    #
    elif tp == 's':
        if s[i + 1] != ':':
            raise SerializerError("':' expected")
        w_result = fp.space.newstr(load_str(fp, ';'))
    #
    elif tp == 'd':
        if s[i + 1] != ':':
            raise SerializerError("':' expected")
        data = fp.read_substring_until(';')
        w_number, valid = convert_string_to_number(data)
        if not valid:
            raise SerializerError('bad double')
        w_result = fp.space.newfloat(w_number.float_w(fp.space))
    #
    elif tp == 'b':
        if s[i + 1] != ':':
            raise SerializerError("':' expected")
        i = fp.consume(2)
        digit = s[i]
        if digit == '0':
            w_result = fp.space.w_False
        elif digit == '1':
            w_result = fp.space.w_True
        else:
            raise SerializerError('bad bool')
        if s[i + 1] != ';':
            raise SerializerError("';' expected")
    #
    elif tp == 'N':
        if s[i + 1] != ';':
            raise SerializerError("';' expected")
        w_result = fp.space.w_Null
    #
    elif tp == 'a':
        if s[i + 1] != ':':
            raise SerializerError("':' expected")
        length = fp.read_int_until(':', can_be_negative=False)
        if length < 0:
            raise SerializerError("integer overflow")
        i = fp.consume(1)
        if s[i] != '{':
            raise SerializerError("'{' expected")
        w_result = None
        if needs_ref:
            w_result = fp.space.empty_ref()
            fp.save_reference(w_result)
        # first try to load the array as a direct list
        lst_w = []
        expected = ['i', ':', '0', ';']
        for n in range(length):
            i = fp.pos
            if i + len(expected) >= len(s):
                break
            for j in range(len(expected)):
                if s[i] != expected[j]:
                    break
                i += 1
            else:
                # ok, we got exactly 'i:N;' where N is the expected index
                fp.pos = i
                lst_w.append(load_object(fp))
                # increment the expected counter
                j = len(expected) - 2
                while j >= 2:
                    if expected[j] != '9':
                        expected[j] = chr(ord(expected[j]) + 1)
                        break
                    expected[j] = '0'
                    j -= 1
                else:
                    expected = ['i', ':', '1'] + expected[2:]
                continue
            break
        else:
            # we succeeded in loading the complete array as a list
            n = length
            _succeeded_as_a_list()   # for tests
        # fill in the remaining entries, if any, the slow way
        w_array = fp.space.new_array_from_list(lst_w)
        for n in range(n, length):
            w_key = load_array_key(fp)
            w_value = load_object(fp)
            w_array = fp.space.setitem_maybe_inplace(w_array, w_key, w_value)
        fp.expect_closing_brace()
        if w_result is not None:    # needs_ref
            w_result.store(w_array, unique=True)
            return w_result
        else:
            return w_array
    #
    elif tp == 'R':
        if s[i + 1] != ':':
            raise SerializerError("':' expected")
        return load_reference(fp)
    #
    elif tp == 'r':
        if s[i + 1] != ':':
            raise SerializerError("':' expected")
        return load_reference(fp).deref()
    #
    elif tp == 'O':
        if s[i + 1] != ':':
            raise SerializerError("':' expected")
        klass_name = load_str(fp, ':')
        space = fp.space
        interp = space.ec.interpreter
        klass = interp.lookup_class_or_intf(klass_name)
        if klass is None:
            klass = k_incomplete
            w_instance = klass.get_empty_instance(space)
            w_instance.setattr(interp, '__PHP_Incomplete_Class_Name',
                               space.wrap(klass_name), None)
        else:
            w_instance = klass.get_empty_instance(space)
        w_result = w_instance
        if needs_ref:
            w_result = W_Reference(w_instance)
            fp.save_reference(w_result)
        count_attrs = fp.read_int_until(':')    # negative value accepted :-(
        i = fp.consume(1)
        if s[i] != '{':
            raise SerializerError("'{' expected")
        attrs = {}
        for i in xrange(count_attrs):
            w_attr = load_array_key(fp)
            w_value = load_object(fp)
            attr_name = space.str_w(w_attr)
            attrs[attr_name] = w_value
            w_instance.setattr(interp, attr_name, w_value, None)
        fp.expect_closing_brace()

        w_instance.unserialize(space, attrs)

        if '__wakeup' in klass.methods:
            klass.methods['__wakeup'].method_func.call_args(space.ec.interpreter,
                                                            [], w_this=w_instance,
                                                            thisclass=klass)
        return w_result
    #
    else:
        if tp == '}':
            fp.space.ec.notice("unserialize(): "
                               "Unexpected end of serialized data")
        raise SerializerError('malformed input')

    # this is for primitive types only; complex types 'return' above
    if needs_ref:
        w_result = W_Reference(w_result)
        fp.save_reference(w_result)
    return w_result
Пример #21
0
def test_convert_string_to_number_float():
    assert convert_string_to_number(' 5.') == (Float(5.0), True)
    assert convert_string_to_number(' -.5') == (Float(-0.5), True)
    assert convert_string_to_number(' .') == (Int(0), False)
    assert convert_string_to_number(' 10.25') == (Float(10.25), True)
    assert convert_string_to_number(' 10.25X') == (Float(10.25), False)
    #
    assert convert_string_to_number('E5') == (Int(0), False)
    assert convert_string_to_number('.E5') == (Int(0), False)
    assert convert_string_to_number('5E') == (Int(5), False)
    assert convert_string_to_number('5.E') == (Float(5.0), False)
    assert convert_string_to_number('5E-') == (Int(5), False)
    assert convert_string_to_number('5E+') == (Int(5), False)
    assert convert_string_to_number('5E0') == (Float(5.0), True)
    assert convert_string_to_number('5E+0') == (Float(5.0), True)
    assert convert_string_to_number('5E-0') == (Float(5.0), True)
    assert convert_string_to_number('5E2') == (Float(500.0), True)
    assert convert_string_to_number('5E-02') == (Float(0.05), True)
    assert convert_string_to_number('5E-02.9') == (Float(0.05), False)
    assert convert_string_to_number('5E-02E9') == (Float(0.05), False)
    assert convert_string_to_number('5e2') == (Float(500.0), True)
Пример #22
0
def test_precision_issues():
    assert convert_string_to_number('55123.456') == (Float(55123.456), True)
Пример #23
0
 def as_number(self, space=None):
     s = self.unwrap()
     w_number, valid = convert_string_to_number(s)
     return w_number      # ignore 'valid'
Пример #24
0
    def _compare(self, w_left, w_right, strict=False, ignore_order=False):

        w_left = w_left.deref()
        w_right = w_right.deref()

        left_tp = w_left.tp
        right_tp = w_right.tp

        if strict:
            if left_tp != right_tp:
                return 1

        if(left_tp == self.tp_float and right_tp == self.tp_float):
            return my_cmp(self.float_w(w_left), self.float_w(w_right),
                          ignore_order)

        if(left_tp == self.tp_int and right_tp == self.tp_float):
            return my_cmp(self.float_w(w_left), self.float_w(w_right),
                          ignore_order)

        if(left_tp == self.tp_float and right_tp == self.tp_int):
            return my_cmp(self.float_w(w_left), self.float_w(w_right),
                          ignore_order)

        elif(left_tp == self.tp_int and right_tp == self.tp_int):
            return my_cmp(self.int_w(w_left), self.int_w(w_right),
                          ignore_order)

        elif(left_tp == self.tp_array and right_tp == self.tp_array):
            return self._compare_array(w_left, w_right, strict)

        elif(left_tp == self.tp_null and right_tp == self.tp_null):
            return 0

        elif(left_tp == self.tp_null and right_tp == self.tp_bool):
            if self.is_true(w_right):
                return -1
            return 0

        elif(left_tp == self.tp_bool and right_tp == self.tp_null):
            if self.is_true(w_left):
                return 1
            return 0

        elif(left_tp == self.tp_bool and right_tp == self.tp_bool):
            return my_cmp(self.is_true(w_left), self.is_true(w_right),
                          ignore_order)

        elif(left_tp == self.tp_str and right_tp == self.tp_str):
            left  = self.str_w(w_left)
            right = self.str_w(w_right)
            if not strict:
                # a small optimimization first, if both are single-char
                left_length  = len(left)
                right_length = len(right)
                if (jit.isconstant(left_length)  and left_length  == 1 and
                    jit.isconstant(right_length) and right_length == 1):
                    return my_cmp(ord(left[0]), ord(right[0]), ignore_order)
                #
                w_right_num, right_valid = convert_string_to_number(right)
                if right_valid:
                    w_left_num, left_valid = convert_string_to_number(left)
                    if left_valid:
                        return self._compare(w_left_num, w_right_num,
                                             ignore_order=ignore_order)
            return my_cmp(left, right, ignore_order)

        elif(left_tp == self.tp_null and right_tp == self.tp_str):
            return my_cmp("", self.str_w(w_right), ignore_order)

        elif(left_tp == self.tp_str and right_tp == self.tp_null):
            return my_cmp(self.str_w(w_left), "", ignore_order)

        elif(left_tp == self.tp_object and right_tp == self.tp_null):
            return 1

        elif(left_tp == self.tp_null and right_tp == self.tp_object):
            return -1

        elif(left_tp == self.tp_object and right_tp == self.tp_object):
            return w_left.compare(w_right, self, strict)

        else:
            if(left_tp == self.tp_null):
                if self.is_true(w_right):
                    return -1
                return 0
            elif(right_tp == self.tp_null):
                if self.is_true(w_left):
                    return 1
                return 0
            elif(left_tp == self.tp_bool or right_tp == self.tp_bool):
                return my_cmp(self.is_true(w_left), self.is_true(w_right),
                              ignore_order)
            elif(left_tp == self.tp_array):
                return 1
            elif(right_tp == self.tp_array):
                return -1
            elif(left_tp == self.tp_object):
                return 1
            elif(right_tp == self.tp_object):
                return -1
            else:
                return self._compare(self.as_number(w_left),
                                     self.as_number(w_right),
                                     ignore_order=ignore_order)
        raise NotImplementedError()
Пример #25
0
 def is_really_valid_number(self, space=None):
     s = self.unwrap()
     w_number, valid = convert_string_to_number(s)
     return valid
Пример #26
0
def load_object(fp):
    fp.next_reference_obj -= 1
    needs_ref = (fp.next_reference_obj == 0)
    #
    fp.error_pos = fp.pos
    try:
        i = fp.consume(2)
    except SerializerError:
        i = fp.consume(1)
        if fp.s[i] == '}':
            fp.space.ec.notice("unserialize(): "
                               "Unexpected end of serialized data")
        raise
    s = fp.s
    tp = s[i]
    check_nonneg(i)
    check_nonneg(fp.pos)
    #
    if tp == 'i':
        if s[i + 1] != ':':
            raise SerializerError("':' expected")
        i = fp.read_int_until(';')
        w_result = fp.space.wrap(i)
    #
    elif tp == 's':
        if s[i + 1] != ':':
            raise SerializerError("':' expected")
        w_result = fp.space.newstr(load_str(fp, ';'))
    #
    elif tp == 'd':
        if s[i + 1] != ':':
            raise SerializerError("':' expected")
        data = fp.read_substring_until(';')
        if data == 'INF':
            w_result = fp.space.wrap(rfloat.INFINITY)
        elif data == '-INF':
            w_result = fp.space.wrap(-rfloat.INFINITY)
        elif data == 'NAN':
            w_result = fp.space.wrap(rfloat.NAN)
        else:
            w_number, valid = convert_string_to_number(data)
            if not valid:
                raise SerializerError('bad double')
            w_result = fp.space.newfloat(w_number.float_w(fp.space))
    #
    elif tp == 'b':
        if s[i + 1] != ':':
            raise SerializerError("':' expected")
        i = fp.consume(2)
        digit = s[i]
        if digit == '0':
            w_result = fp.space.w_False
        elif digit == '1':
            w_result = fp.space.w_True
        else:
            raise SerializerError('bad bool')
        if s[i + 1] != ';':
            raise SerializerError("';' expected")
    #
    elif tp == 'N':
        if s[i + 1] != ';':
            raise SerializerError("';' expected")
        w_result = fp.space.w_Null
    #
    elif tp == 'a':
        if s[i + 1] != ':':
            raise SerializerError("':' expected")
        length = fp.read_int_until(':', can_be_negative=False)
        if length < 0:
            raise SerializerError("integer overflow")
        i = fp.consume(1)
        if s[i] != '{':
            raise SerializerError("'{' expected")
        w_result = None
        if needs_ref:
            w_result = fp.space.empty_ref()
            fp.save_reference(w_result)
        # first try to load the array as a direct list
        lst_w = []
        expected = ['i', ':', '0', ';']
        for n in range(length):
            i = fp.pos
            if i + len(expected) >= len(s):
                break
            for j in range(len(expected)):
                if s[i] != expected[j]:
                    break
                i += 1
            else:
                # ok, we got exactly 'i:N;' where N is the expected index
                fp.pos = i
                lst_w.append(load_object(fp))
                # increment the expected counter
                j = len(expected) - 2
                while j >= 2:
                    if expected[j] != '9':
                        expected[j] = chr(ord(expected[j]) + 1)
                        break
                    expected[j] = '0'
                    j -= 1
                else:
                    expected = ['i', ':', '1'] + expected[2:]
                continue
            break
        else:
            # we succeeded in loading the complete array as a list
            n = length
            _succeeded_as_a_list()   # for tests
        # fill in the remaining entries, if any, the slow way
        w_array = fp.space.new_array_from_list(lst_w)
        for n in range(n, length):
            w_key = load_array_key(fp)
            w_value = load_object(fp)
            w_array = fp.space.setitem_maybe_inplace(w_array, w_key, w_value)
        fp.expect_closing_brace()
        if w_result is not None:    # needs_ref
            w_result.store(w_array, unique=True)
            return w_result
        else:
            return w_array
    #
    elif tp == 'R':
        if s[i + 1] != ':':
            raise SerializerError("':' expected")
        return load_reference(fp)
    #
    elif tp == 'r':
        if s[i + 1] != ':':
            raise SerializerError("':' expected")
        return load_reference(fp).deref()
    #
    elif tp == 'O':
        if s[i + 1] != ':':
            raise SerializerError("':' expected")
        klass_name = load_str(fp, ':')
        space = fp.space
        interp = space.ec.interpreter
        klass = interp.lookup_class_or_intf(klass_name)
        if klass is None:
            klass = k_incomplete
            w_instance = klass.get_empty_instance(space)
            w_instance.setattr(interp, '__PHP_Incomplete_Class_Name',
                               space.wrap(klass_name), None)
        else:
            w_instance = klass.get_empty_instance(space)
        w_result = w_instance
        if needs_ref:
            w_result = W_Reference(w_instance)
            fp.save_reference(w_result)
        count_attrs = fp.read_int_until(':')    # negative value accepted :-(
        i = fp.consume(1)
        if s[i] != '{':
            raise SerializerError("'{' expected")
        attrs = {}
        for i in xrange(count_attrs):
            w_attr = load_array_key(fp)
            w_value = load_object(fp)
            attr_name = space.str_w(w_attr)
            attrs[attr_name] = w_value
            w_instance.setattr(interp, attr_name, w_value, None)
        fp.expect_closing_brace()

        w_instance.unserialize(space, attrs)

        if '__wakeup' in klass.methods:
            klass.methods['__wakeup'].method_func.call_args(space.ec.interpreter,
                                                            [], w_this=w_instance,
                                                            thisclass=klass)
        return w_result
    #
    else:
        if tp == '}':
            fp.space.ec.notice("unserialize(): "
                               "Unexpected end of serialized data")
        raise SerializerError('malformed input')

    # this is for primitive types only; complex types 'return' above
    if needs_ref:
        w_result = W_Reference(w_result)
        fp.save_reference(w_result)
    return w_result
Пример #27
0
    def _compare(self, w_left, w_right, strict=False):

        w_left = w_left.deref()
        w_right = w_right.deref()

        left_tp = w_left.tp
        right_tp = w_right.tp

        if strict:
            if left_tp != right_tp:
                return 1

        if(left_tp == self.tp_float and right_tp == self.tp_float):
            return my_cmp(self.float_w(w_left), self.float_w(w_right))

        if(left_tp == self.tp_int and right_tp == self.tp_float):
            return my_cmp(self.float_w(w_left), self.float_w(w_right))

        if(left_tp == self.tp_float and right_tp == self.tp_int):
            return my_cmp(self.float_w(w_left), self.float_w(w_right))

        elif(left_tp == self.tp_int and right_tp == self.tp_int):
            return my_cmp(self.int_w(w_left), self.int_w(w_right))

        elif(left_tp == self.tp_array and right_tp == self.tp_array):
            return self._compare_array(w_left, w_right, strict)

        elif(left_tp == self.tp_null and right_tp == self.tp_null):
            return 0

        elif(left_tp == self.tp_null and right_tp == self.tp_bool):
            if self.is_true(w_right):
                return -1
            return 0

        elif(left_tp == self.tp_bool and right_tp == self.tp_null):
            if self.is_true(w_left):
                return 1
            return 0

        elif(left_tp == self.tp_bool and right_tp == self.tp_bool):
            return my_cmp(self.is_true(w_left), self.is_true(w_right))

        elif(left_tp == self.tp_str and right_tp == self.tp_str):
            if not strict:
                w_left_num, left_valid = convert_string_to_number(
                    self.str_w(w_left))
                w_right_num, right_valid = convert_string_to_number(
                    self.str_w(w_right))
                if left_valid and right_valid:
                    return self._compare(w_left_num, w_right_num)
            return my_cmp(self.str_w(w_left), self.str_w(w_right))

        elif(left_tp == self.tp_null and right_tp == self.tp_str):
            return my_cmp("", self.str_w(w_right))

        elif(left_tp == self.tp_str and right_tp == self.tp_null):
            return my_cmp(self.str_w(w_left), "")

        elif(left_tp == self.tp_object and right_tp == self.tp_null):
            return 1

        elif(left_tp == self.tp_null and right_tp == self.tp_object):
            return -1

        elif(left_tp == self.tp_object and right_tp == self.tp_object):
            # XXX missing a lot of stuff to handle custom comparison methods
            return self._compare_object(w_left, w_right, strict)

        else:
            if(left_tp == self.tp_null):
                if self.is_true(w_right):
                    return -1
                return 0
            elif(right_tp == self.tp_null):
                if self.is_true(w_left):
                    return 1
                return 0
            elif(left_tp == self.tp_bool or right_tp == self.tp_bool):
                return my_cmp(self.is_true(w_left), self.is_true(w_right))
            elif(left_tp == self.tp_array):
                return 1
            elif(right_tp == self.tp_array):
                return -1
            elif(left_tp == self.tp_object):
                return 1
            elif(right_tp == self.tp_object):
                return -1
            else:
                return self._compare(self.as_number(w_left),
                                     self.as_number(w_right))
        raise NotImplementedError()