Index: third_party/protobuf/python/google/protobuf/internal/decoder.py |
diff --git a/third_party/protobuf/python/google/protobuf/internal/decoder.py b/third_party/protobuf/python/google/protobuf/internal/decoder.py |
index 461a30c0e732bd7867ee65c190940adf8e9cdf53..55f746f50fb1cbe163848441c0aaf235eff74480 100755 |
--- a/third_party/protobuf/python/google/protobuf/internal/decoder.py |
+++ b/third_party/protobuf/python/google/protobuf/internal/decoder.py |
@@ -86,6 +86,13 @@ from google.protobuf.internal import wire_format |
from google.protobuf import message |
+# This will overflow and thus become IEEE-754 "infinity". We would use |
+# "float('inf')" but it doesn't work on Windows pre-Python-2.6. |
+_POS_INF = 1e10000 |
+_NEG_INF = -_POS_INF |
+_NAN = _POS_INF * 0 |
+ |
+ |
# This is not for optimization, but rather to avoid conflicts with local |
# variables named "message". |
_DecodeError = message.DecodeError |
@@ -269,6 +276,72 @@ def _StructPackDecoder(wire_type, format): |
return _SimpleDecoder(wire_type, InnerDecode) |
+def _FloatDecoder(): |
+ """Returns a decoder for a float field. |
+ |
+ This code works around a bug in struct.unpack for non-finite 32-bit |
+ floating-point values. |
+ """ |
+ |
+ local_unpack = struct.unpack |
+ |
+ def InnerDecode(buffer, pos): |
+ # We expect a 32-bit value in little-endian byte order. Bit 1 is the sign |
+ # bit, bits 2-9 represent the exponent, and bits 10-32 are the significand. |
+ new_pos = pos + 4 |
+ float_bytes = buffer[pos:new_pos] |
+ |
+ # If this value has all its exponent bits set, then it's non-finite. |
+ # In Python 2.4, struct.unpack will convert it to a finite 64-bit value. |
+ # To avoid that, we parse it specially. |
+ if ((float_bytes[3] in '\x7F\xFF') |
+ and (float_bytes[2] >= '\x80')): |
+ # If at least one significand bit is set... |
+ if float_bytes[0:3] != '\x00\x00\x80': |
+ return (_NAN, new_pos) |
+ # If sign bit is set... |
+ if float_bytes[3] == '\xFF': |
+ return (_NEG_INF, new_pos) |
+ return (_POS_INF, new_pos) |
+ |
+ # Note that we expect someone up-stack to catch struct.error and convert |
+ # it to _DecodeError -- this way we don't have to set up exception- |
+ # handling blocks every time we parse one value. |
+ result = local_unpack('<f', float_bytes)[0] |
+ return (result, new_pos) |
+ return _SimpleDecoder(wire_format.WIRETYPE_FIXED32, InnerDecode) |
+ |
+ |
+def _DoubleDecoder(): |
+ """Returns a decoder for a double field. |
+ |
+ This code works around a bug in struct.unpack for not-a-number. |
+ """ |
+ |
+ local_unpack = struct.unpack |
+ |
+ def InnerDecode(buffer, pos): |
+ # We expect a 64-bit value in little-endian byte order. Bit 1 is the sign |
+ # bit, bits 2-12 represent the exponent, and bits 13-64 are the significand. |
+ new_pos = pos + 8 |
+ double_bytes = buffer[pos:new_pos] |
+ |
+ # If this value has all its exponent bits set and at least one significand |
+ # bit set, it's not a number. In Python 2.4, struct.unpack will treat it |
+ # as inf or -inf. To avoid that, we treat it specially. |
+ if ((double_bytes[7] in '\x7F\xFF') |
+ and (double_bytes[6] >= '\xF0') |
+ and (double_bytes[0:7] != '\x00\x00\x00\x00\x00\x00\xF0')): |
+ return (_NAN, new_pos) |
+ |
+ # Note that we expect someone up-stack to catch struct.error and convert |
+ # it to _DecodeError -- this way we don't have to set up exception- |
+ # handling blocks every time we parse one value. |
+ result = local_unpack('<d', double_bytes)[0] |
+ return (result, new_pos) |
+ return _SimpleDecoder(wire_format.WIRETYPE_FIXED64, InnerDecode) |
+ |
+ |
# -------------------------------------------------------------------- |
@@ -294,8 +367,8 @@ Fixed32Decoder = _StructPackDecoder(wire_format.WIRETYPE_FIXED32, '<I') |
Fixed64Decoder = _StructPackDecoder(wire_format.WIRETYPE_FIXED64, '<Q') |
SFixed32Decoder = _StructPackDecoder(wire_format.WIRETYPE_FIXED32, '<i') |
SFixed64Decoder = _StructPackDecoder(wire_format.WIRETYPE_FIXED64, '<q') |
-FloatDecoder = _StructPackDecoder(wire_format.WIRETYPE_FIXED32, '<f') |
-DoubleDecoder = _StructPackDecoder(wire_format.WIRETYPE_FIXED64, '<d') |
+FloatDecoder = _FloatDecoder() |
+DoubleDecoder = _DoubleDecoder() |
BoolDecoder = _ModifiedDecoder( |
wire_format.WIRETYPE_VARINT, _DecodeVarint, bool) |