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)
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)
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
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)
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
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')
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
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)
def is_really_valid_number(self, space=None): s = self.unwrap() w_number, valid = convert_string_to_number(s) return valid
def as_number(self, space=None): s = self.unwrap() w_number, valid = convert_string_to_number(s) return w_number # ignore 'valid'
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)
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()
def test_precision_issues(): assert convert_string_to_number('55123.456') == (Float(55123.456), True)
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
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()
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
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()