Commit 2bc2a2e3 authored by YOU's avatar YOU Committed by Dylan Trotter

Add _struct, _md5, md5 to third_party/pypy

parent 0c8a6d7e
...@@ -54,8 +54,8 @@ RUNNER = $(RUNNER_BIN) $(COMPILER) $(RUNTIME) $(STDLIB) ...@@ -54,8 +54,8 @@ RUNNER = $(RUNNER_BIN) $(COMPILER) $(RUNTIME) $(STDLIB)
GRUMPY_STDLIB_SRCS := $(shell find lib -name '*.py') GRUMPY_STDLIB_SRCS := $(shell find lib -name '*.py')
GRUMPY_STDLIB_PACKAGES := $(foreach x,$(GRUMPY_STDLIB_SRCS),$(patsubst lib/%.py,%,$(patsubst lib/%/__init__.py,%,$(x)))) GRUMPY_STDLIB_PACKAGES := $(foreach x,$(GRUMPY_STDLIB_SRCS),$(patsubst lib/%.py,%,$(patsubst lib/%/__init__.py,%,$(x))))
THIRD_PARTY_STDLIB_SRCS := $(wildcard third_party/stdlib/*.py) THIRD_PARTY_STDLIB_SRCS := $(wildcard third_party/stdlib/*.py) $(wildcard third_party/pypy/*.py)
THIRD_PARTY_STDLIB_PACKAGES := $(foreach x,$(THIRD_PARTY_STDLIB_SRCS),$(patsubst third_party/stdlib/%.py,%,$(x))) THIRD_PARTY_STDLIB_PACKAGES := $(foreach x,$(THIRD_PARTY_STDLIB_SRCS),$(patsubst third_party/stdlib/%.py,%,$(patsubst third_party/pypy/%.py,%,$(x))))
STDLIB_SRCS := $(GRUMPY_STDLIB_SRCS) $(THIRD_PARTY_STDLIB_SRCS) STDLIB_SRCS := $(GRUMPY_STDLIB_SRCS) $(THIRD_PARTY_STDLIB_SRCS)
STDLIB_PACKAGES := $(GRUMPY_STDLIB_PACKAGES) $(THIRD_PARTY_STDLIB_PACKAGES) STDLIB_PACKAGES := $(GRUMPY_STDLIB_PACKAGES) $(THIRD_PARTY_STDLIB_PACKAGES)
STDLIB := $(patsubst %,$(PKG_DIR)/grumpy/lib/%.a,$(STDLIB_PACKAGES)) STDLIB := $(patsubst %,$(PKG_DIR)/grumpy/lib/%.a,$(STDLIB_PACKAGES))
...@@ -188,7 +188,7 @@ build/src/grumpy/lib/$(2)/module.go: $(1) $(COMPILER) ...@@ -188,7 +188,7 @@ build/src/grumpy/lib/$(2)/module.go: $(1) $(COMPILER)
build/src/grumpy/lib/$(2)/module.d: $(1) build/src/grumpy/lib/$(2)/module.d: $(1)
@mkdir -p build/src/grumpy/lib/$(2) @mkdir -p build/src/grumpy/lib/$(2)
@$(PYTHON) -m modulefinder -p $(ROOT_DIR)/lib:$(ROOT_DIR)/third_party/stdlib $$< | awk '{if (($$$$1 == "m" || $$$$1 == "P") && $$$$2 != "__main__" && $$$$2 != "$(2)") {gsub(/\./, "/", $$$$2); print "$(PKG_DIR)/grumpy/lib/$(2).a: $(PKG_DIR)/grumpy/lib/" $$$$2 ".a"}}' > $$@ @$(PYTHON) -m modulefinder -p $(ROOT_DIR)/lib:$(ROOT_DIR)/third_party/stdlib:$(ROOT_DIR)/third_party/pypy $$< | awk '{if (($$$$1 == "m" || $$$$1 == "P") && $$$$2 != "__main__" && $$$$2 != "$(2)") {gsub(/\./, "/", $$$$2); print "$(PKG_DIR)/grumpy/lib/$(2).a: $(PKG_DIR)/grumpy/lib/" $$$$2 ".a"}}' > $$@
$(PKG_DIR)/grumpy/lib/$(2).a: build/src/grumpy/lib/$(2)/module.go $(RUNTIME) $(PKG_DIR)/grumpy/lib/$(2).a: build/src/grumpy/lib/$(2)/module.go $(RUNTIME)
@mkdir -p $(PKG_DIR)/grumpy/lib/$(dir $(2)) @mkdir -p $(PKG_DIR)/grumpy/lib/$(dir $(2))
......
...@@ -27,10 +27,12 @@ maxint = MaxInt ...@@ -27,10 +27,12 @@ maxint = MaxInt
modules = SysModules modules = SysModules
py3kwarning = False py3kwarning = False
warnoptions = [] warnoptions = []
# TODO: Support actual byteorder
byteorder = 'little'
stdin = NewFileFromFD(Stdin.Fd()) stdin = NewFileFromFD(Stdin.Fd())
stdout = NewFileFromFD(Stdout.Fd()) stdout = NewFileFromFD(Stdout.Fd())
stderr = NewFileFromFD(Stderr.Fd()) stderr = NewFileFromFD(Stderr.Fd())
class _Flags(object): class _Flags(object):
......
# Copyright 2016 Google Inc. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import md5
import _md5
# md5 test
assert _md5.new("").hexdigest() == 'd41d8cd98f00b204e9800998ecf8427e'
assert _md5.new("hello").hexdigest() == '5d41402abc4b2a76b9719d911017c592'
assert md5.new("").hexdigest() == 'd41d8cd98f00b204e9800998ecf8427e'
assert md5.new("hello").hexdigest() == '5d41402abc4b2a76b9719d911017c592'
# Copyright 2016 Google Inc. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import _struct as struct
# struct test
A = 0x67452301
B = 0xefcdab89
C = 0x98badcfe
D = 0x10325476
expected = '\x01#Eg\x89\xab\xcd\xef\xfe\xdc\xba\x98vT2\x10'
assert struct.pack("<IIII", A, B, C, D) == expected
#!/usr/bin/env python
# -*- coding: iso-8859-1 -*-
# Note that PyPy contains also a built-in module 'md5' which will hide
# this one if compiled in.
"""A sample implementation of MD5 in pure Python.
This is an implementation of the MD5 hash function, as specified by
RFC 1321, in pure Python. It was implemented using Bruce Schneier's
excellent book "Applied Cryptography", 2nd ed., 1996.
Surely this is not meant to compete with the existing implementation
of the Python standard library (written in C). Rather, it should be
seen as a Python complement that is more readable than C and can be
used more conveniently for learning and experimenting purposes in
the field of cryptography.
This module tries very hard to follow the API of the existing Python
standard library's "md5" module, but although it seems to work fine,
it has not been extensively tested! (But note that there is a test
module, test_md5py.py, that compares this Python implementation with
the C one of the Python standard library.
BEWARE: this comes with no guarantee whatsoever about fitness and/or
other properties! Specifically, do not use this in any production
code! License is Python License!
Special thanks to Aurelian Coman who fixed some nasty bugs!
Dinu C. Gherman
"""
__date__ = '2004-11-17'
__version__ = 0.91 # Modernised by J. Hall�n and L. Creighton for Pypy
__metaclass__ = type # or genrpy won't work
import _struct as struct
import copy
# ======================================================================
# Bit-Manipulation helpers
# ======================================================================
def _bytelist2long(list):
"Transform a list of characters into a list of longs."
imax = len(list) // 4
hl = [0] * imax
j = 0
i = 0
while i < imax:
b0 = ord(list[j])
b1 = ord(list[j + 1]) << 8
b2 = ord(list[j + 2]) << 16
b3 = ord(list[j + 3]) << 24
hl[i] = b0 | b1 | b2 | b3
i = i + 1
j = j + 4
return hl
def _rotateLeft(x, n):
"Rotate x (32 bit) left n bits circularly."
return (x << n) | (x >> (32 - n))
# ======================================================================
# The real MD5 meat...
#
# Implemented after "Applied Cryptography", 2nd ed., 1996,
# pp. 436-441 by Bruce Schneier.
# ======================================================================
# F, G, H and I are basic MD5 functions.
def F(x, y, z):
return (x & y) | ((~x) & z)
def G(x, y, z):
return (x & z) | (y & (~z))
def H(x, y, z):
return x ^ y ^ z
def I(x, y, z):
return y ^ (x | (~z))
def XX(func, a, b, c, d, x, s, ac):
"""Wrapper for call distribution to functions F, G, H and I.
This replaces functions FF, GG, HH and II from "Appl. Crypto."
Rotation is separate from addition to prevent recomputation
(now summed-up in one function).
"""
res = 0
res = res + a + func(b, c, d)
res = res + x
res = res + ac
res = res & 0xffffffff
res = _rotateLeft(res, s)
res = res & 0xffffffff
res = res + b
return res & 0xffffffff
class MD5Type(object):
"An implementation of the MD5 hash function in pure Python."
digest_size = digestsize = 16
block_size = 64
def __init__(self):
"Initialisation."
# Initial message length in bits(!).
self.length = 0
self.count = [0, 0]
# Initial empty message as a sequence of bytes (8 bit characters).
self.input = []
# Call a separate init function, that can be used repeatedly
# to start from scratch on the same object.
self.init()
def init(self):
"Initialize the message-digest and set all fields to zero.code"
self.length = 0
self.count = [0, 0]
self.input = []
# Load magic initialization constants.
self.A = 0x67452301
self.B = 0xefcdab89
self.C = 0x98badcfe
self.D = 0x10325476
def _transform(self, inp):
"""Basic MD5 step transforming the digest based on the input.
Note that if the Mysterious Constants are arranged backwards
in little-endian order and decrypted with the DES they produce
OCCULT MESSAGES!
"""
a, b, c, d = A, B, C, D = self.A, self.B, self.C, self.D
# Round 1.
S11, S12, S13, S14 = 7, 12, 17, 22
a = XX(F, a, b, c, d, inp[0], S11, 0xD76AA478) # 1
d = XX(F, d, a, b, c, inp[1], S12, 0xE8C7B756) # 2
c = XX(F, c, d, a, b, inp[2], S13, 0x242070DB) # 3
b = XX(F, b, c, d, a, inp[3], S14, 0xC1BDCEEE) # 4
a = XX(F, a, b, c, d, inp[4], S11, 0xF57C0FAF) # 5
d = XX(F, d, a, b, c, inp[5], S12, 0x4787C62A) # 6
c = XX(F, c, d, a, b, inp[6], S13, 0xA8304613) # 7
b = XX(F, b, c, d, a, inp[7], S14, 0xFD469501) # 8
a = XX(F, a, b, c, d, inp[8], S11, 0x698098D8) # 9
d = XX(F, d, a, b, c, inp[9], S12, 0x8B44F7AF) # 10
c = XX(F, c, d, a, b, inp[10], S13, 0xFFFF5BB1) # 11
b = XX(F, b, c, d, a, inp[11], S14, 0x895CD7BE) # 12
a = XX(F, a, b, c, d, inp[12], S11, 0x6B901122) # 13
d = XX(F, d, a, b, c, inp[13], S12, 0xFD987193) # 14
c = XX(F, c, d, a, b, inp[14], S13, 0xA679438E) # 15
b = XX(F, b, c, d, a, inp[15], S14, 0x49B40821) # 16
# Round 2.
S21, S22, S23, S24 = 5, 9, 14, 20
a = XX(G, a, b, c, d, inp[1], S21, 0xF61E2562) # 17
d = XX(G, d, a, b, c, inp[6], S22, 0xC040B340) # 18
c = XX(G, c, d, a, b, inp[11], S23, 0x265E5A51) # 19
b = XX(G, b, c, d, a, inp[0], S24, 0xE9B6C7AA) # 20
a = XX(G, a, b, c, d, inp[5], S21, 0xD62F105D) # 21
d = XX(G, d, a, b, c, inp[10], S22, 0x02441453) # 22
c = XX(G, c, d, a, b, inp[15], S23, 0xD8A1E681) # 23
b = XX(G, b, c, d, a, inp[4], S24, 0xE7D3FBC8) # 24
a = XX(G, a, b, c, d, inp[9], S21, 0x21E1CDE6) # 25
d = XX(G, d, a, b, c, inp[14], S22, 0xC33707D6) # 26
c = XX(G, c, d, a, b, inp[3], S23, 0xF4D50D87) # 27
b = XX(G, b, c, d, a, inp[8], S24, 0x455A14ED) # 28
a = XX(G, a, b, c, d, inp[13], S21, 0xA9E3E905) # 29
d = XX(G, d, a, b, c, inp[2], S22, 0xFCEFA3F8) # 30
c = XX(G, c, d, a, b, inp[7], S23, 0x676F02D9) # 31
b = XX(G, b, c, d, a, inp[12], S24, 0x8D2A4C8A) # 32
# Round 3.
S31, S32, S33, S34 = 4, 11, 16, 23
a = XX(H, a, b, c, d, inp[5], S31, 0xFFFA3942) # 33
d = XX(H, d, a, b, c, inp[8], S32, 0x8771F681) # 34
c = XX(H, c, d, a, b, inp[11], S33, 0x6D9D6122) # 35
b = XX(H, b, c, d, a, inp[14], S34, 0xFDE5380C) # 36
a = XX(H, a, b, c, d, inp[1], S31, 0xA4BEEA44) # 37
d = XX(H, d, a, b, c, inp[4], S32, 0x4BDECFA9) # 38
c = XX(H, c, d, a, b, inp[7], S33, 0xF6BB4B60) # 39
b = XX(H, b, c, d, a, inp[10], S34, 0xBEBFBC70) # 40
a = XX(H, a, b, c, d, inp[13], S31, 0x289B7EC6) # 41
d = XX(H, d, a, b, c, inp[0], S32, 0xEAA127FA) # 42
c = XX(H, c, d, a, b, inp[3], S33, 0xD4EF3085) # 43
b = XX(H, b, c, d, a, inp[6], S34, 0x04881D05) # 44
a = XX(H, a, b, c, d, inp[9], S31, 0xD9D4D039) # 45
d = XX(H, d, a, b, c, inp[12], S32, 0xE6DB99E5) # 46
c = XX(H, c, d, a, b, inp[15], S33, 0x1FA27CF8) # 47
b = XX(H, b, c, d, a, inp[2], S34, 0xC4AC5665) # 48
# Round 4.
S41, S42, S43, S44 = 6, 10, 15, 21
a = XX(I, a, b, c, d, inp[0], S41, 0xF4292244) # 49
d = XX(I, d, a, b, c, inp[7], S42, 0x432AFF97) # 50
c = XX(I, c, d, a, b, inp[14], S43, 0xAB9423A7) # 51
b = XX(I, b, c, d, a, inp[5], S44, 0xFC93A039) # 52
a = XX(I, a, b, c, d, inp[12], S41, 0x655B59C3) # 53
d = XX(I, d, a, b, c, inp[3], S42, 0x8F0CCC92) # 54
c = XX(I, c, d, a, b, inp[10], S43, 0xFFEFF47D) # 55
b = XX(I, b, c, d, a, inp[1], S44, 0x85845DD1) # 56
a = XX(I, a, b, c, d, inp[8], S41, 0x6FA87E4F) # 57
d = XX(I, d, a, b, c, inp[15], S42, 0xFE2CE6E0) # 58
c = XX(I, c, d, a, b, inp[6], S43, 0xA3014314) # 59
b = XX(I, b, c, d, a, inp[13], S44, 0x4E0811A1) # 60
a = XX(I, a, b, c, d, inp[4], S41, 0xF7537E82) # 61
d = XX(I, d, a, b, c, inp[11], S42, 0xBD3AF235) # 62
c = XX(I, c, d, a, b, inp[2], S43, 0x2AD7D2BB) # 63
b = XX(I, b, c, d, a, inp[9], S44, 0xEB86D391) # 64
A = (A + a) & 0xffffffff
B = (B + b) & 0xffffffff
C = (C + c) & 0xffffffff
D = (D + d) & 0xffffffff
self.A, self.B, self.C, self.D = A, B, C, D
# Down from here all methods follow the Python Standard Library
# API of the md5 module.
def update(self, inBuf):
"""Add to the current message.
Update the md5 object with the string arg. Repeated calls
are equivalent to a single call with the concatenation of all
the arguments, i.e. m.update(a); m.update(b) is equivalent
to m.update(a+b).
The hash is immediately calculated for all full blocks. The final
calculation is made in digest(). This allows us to keep an
intermediate value for the hash, so that we only need to make
minimal recalculation if we call update() to add moredata to
the hashed string.
"""
leninBuf = len(inBuf)
# Compute number of bytes mod 64.
index = (self.count[0] >> 3) & 0x3F
# Update number of bits.
self.count[0] = self.count[0] + (leninBuf << 3)
if self.count[0] < (leninBuf << 3):
self.count[1] = self.count[1] + 1
self.count[1] = self.count[1] + (leninBuf >> 29)
partLen = 64 - index
if leninBuf >= partLen:
self.input[index:] = list(inBuf[:partLen])
self._transform(_bytelist2long(self.input))
i = partLen
while i + 63 < leninBuf:
self._transform(_bytelist2long(list(inBuf[i:i + 64])))
i = i + 64
else:
self.input = list(inBuf[i:leninBuf])
else:
i = 0
self.input = self.input + list(inBuf)
def digest(self):
"""Terminate the message-digest computation and return digest.
Return the digest of the strings passed to the update()
method so far. This is a 16-byte string which may contain
non-ASCII characters, including null bytes.
"""
A = self.A
B = self.B
C = self.C
D = self.D
input = [] + self.input
count = [] + self.count
index = (self.count[0] >> 3) & 0x3f
if index < 56:
padLen = 56 - index
else:
padLen = 120 - index
padding = [b'\200'] + [b'\000'] * 63
self.update(padding[:padLen])
# Append length (before padding).
bits = _bytelist2long(self.input[:56]) + count
self._transform(bits)
# Store state in digest.
digest = struct.pack("<IIII", self.A, self.B, self.C, self.D)
self.A = A
self.B = B
self.C = C
self.D = D
self.input = input
self.count = count
return digest
def hexdigest(self):
"""Terminate and return digest in HEX form.
Like digest() except the digest is returned as a string of
length 32, containing only hexadecimal digits. This may be
used to exchange the value safely in email or other non-
binary environments.
"""
return ''.join([('0' + hex(ord(c))[2:])[-2:] for c in self.digest()])
def copy(self):
"""Return a clone object.
Return a copy ('clone') of the md5 object. This can be used
to efficiently compute the digests of strings that share
a common initial substring.
"""
if 0: # set this to 1 to make the flow space crash
return copy.deepcopy(self)
clone = self.__class__()
clone.length = self.length
clone.count = [] + self.count[:]
clone.input = [] + self.input
clone.A = self.A
clone.B = self.B
clone.C = self.C
clone.D = self.D
return clone
# ======================================================================
# Mimic Python top-level functions from standard library API
# for consistency with the _md5 module of the standard library.
# ======================================================================
digest_size = 16
def new(arg=None):
"""Return a new md5 crypto object.
If arg is present, the method call update(arg) is made.
"""
crypto = MD5Type()
if arg:
crypto.update(arg)
return crypto
#
# This module is a pure Python version of pypy.module.struct.
# It is only imported if the vastly faster pypy.module.struct is not
# compiled in. For now we keep this version for reference and
# because pypy.module.struct is not ootype-backend-friendly yet.
#
"""Functions to convert between Python values and C structs.
Python strings are used to hold the data representing the C struct
and also as format strings to describe the layout of data in the C struct.
The optional first format char indicates byte order, size and alignment:
@: native order, size & alignment (default)
=: native order, std. size & alignment
<: little-endian, std. size & alignment
>: big-endian, std. size & alignment
!: same as >
The remaining chars indicate types of args and must match exactly;
these can be preceded by a decimal repeat count:
x: pad byte (no data);
c:char;
b:signed byte;
B:unsigned byte;
h:short;
H:unsigned short;
i:int;
I:unsigned int;
l:long;
L:unsigned long;
f:float;
d:double.
Special cases (preceding decimal count indicates length):
s:string (array of char); p: pascal string (with count byte).
Special case (only available in native format):
P:an integer type that is wide enough to hold a pointer.
Special case (not in native mode unless 'long long' in platform C):
q:long long;
Q:unsigned long long
Whitespace between formats is ignored.
The variable struct.error is an exception raised on errors."""
import math
import sys
# TODO: XXX Find a way to get information on native sizes and alignments
class StructError(Exception):
pass
error = StructError
bytes = str
def unpack_int(data, index, size, le):
_bytes = [b for b in data[index:index + size]]
if le == 'little':
_bytes.reverse()
number = 0
for b in _bytes:
number = number << 8 | b
return int(number)
def unpack_signed_int(data, index, size, le):
number = unpack_int(data, index, size, le)
max = (1 << (size * 8))
if number > (1 << (size * 8 - 1)) - 1:
number = int(-1 * (max - number))
return number
INFINITY = 1e200 * 1e200
NAN = INFINITY / INFINITY
def unpack_char(data, index, size, le):
return data[index:index + size]
def pack_int(number, size, le):
x = number
res = []
for i in range(size):
res.append(x & 0xff)
x = x >> 8
if le == 'big':
res.reverse()
return ''.join(chr(x) for x in res)
def pack_signed_int(number, size, le):
if not isinstance(number, int):
raise StructError("argument for i,I,l,L,q,Q,h,H must be integer")
if number > (1 << (8 * size - 1)) - 1 or number < -1 * (1 << (8 * size - 1)):
raise OverflowError("Number:%i too large to convert" % number)
return pack_int(number, size, le)
def pack_unsigned_int(number, size, le):
if not isinstance(number, int):
raise StructError("argument for i,I,l,L,q,Q,h,H must be integer")
if number < 0:
raise TypeError("can't convert negative long to unsigned")
if number > (1 << (8 * size)) - 1:
raise OverflowError("Number:%i too large to convert" % number)
return pack_int(number, size, le)
def pack_char(char, size, le):
return str(char)
def isinf(x):
return x != 0.0 and x / 2 == x
def isnan(v):
return v != v * 1.0 or (v == 1.0 and v == 2.0)
def pack_float(x, size, le):
unsigned = float_pack(x, size)
result = []
for i in range(8):
result.append((unsigned >> (i * 8)) & 0xFF)
if le == "big":
result.reverse()
return ''.join(chr(x) for x in result)
def unpack_float(data, index, size, le):
binary = [data[i] for i in range(index, index + 8)]
if le == "big":
binary.reverse()
unsigned = 0
for i in range(8):
unsigned |= binary[i] << (i * 8)
return float_unpack(unsigned, size, le)
def round_to_nearest(x):
"""Python 3 style round: round a float x to the nearest int, but
unlike the builtin Python 2.x round function:
- return an int, not a float
- do round-half-to-even, not round-half-away-from-zero.
We assume that x is finite and nonnegative; except wrong results
if you use this for negative x.
"""
int_part = int(x)
frac_part = x - int_part
if frac_part > 0.5 or frac_part == 0.5 and int_part & 1 == 1:
int_part += 1
return int_part
def float_unpack(Q, size, le):
"""Convert a 32-bit or 64-bit integer created
by float_pack into a Python float."""
if size == 8:
MIN_EXP = -1021 # = sys.float_info.min_exp
MAX_EXP = 1024 # = sys.float_info.max_exp
MANT_DIG = 53 # = sys.float_info.mant_dig
BITS = 64
elif size == 4:
MIN_EXP = -125 # C's FLT_MIN_EXP
MAX_EXP = 128 # FLT_MAX_EXP
MANT_DIG = 24 # FLT_MANT_DIG
BITS = 32
else:
raise ValueError("invalid size value")
if Q >> BITS:
raise ValueError("input out of range")
# extract pieces
sign = Q >> BITS - 1
exp = (Q & ((1 << BITS - 1) - (1 << MANT_DIG - 1))) >> MANT_DIG - 1
mant = Q & ((1 << MANT_DIG - 1) - 1)
if exp == MAX_EXP - MIN_EXP + 2:
# nan or infinity
result = float('nan') if mant else float('inf')
elif exp == 0:
# subnormal or zero
result = math.ldexp(float(mant), MIN_EXP - MANT_DIG)
else:
# normal
mant += 1 << MANT_DIG - 1
result = math.ldexp(float(mant), exp + MIN_EXP - MANT_DIG - 1)
return -result if sign else result
def float_pack(x, size):
"""Convert a Python float x into a 64-bit unsigned integer
with the same byte representation."""
if size == 8:
MIN_EXP = -1021 # = sys.float_info.min_exp
MAX_EXP = 1024 # = sys.float_info.max_exp
MANT_DIG = 53 # = sys.float_info.mant_dig
BITS = 64
elif size == 4:
MIN_EXP = -125 # C's FLT_MIN_EXP
MAX_EXP = 128 # FLT_MAX_EXP
MANT_DIG = 24 # FLT_MANT_DIG
BITS = 32
else:
raise ValueError("invalid size value")
sign = math.copysign(1.0, x) < 0.0
if math.isinf(x):
mant = 0
exp = MAX_EXP - MIN_EXP + 2
elif math.isnan(x):
mant = 1 << (MANT_DIG - 2) # other values possible
exp = MAX_EXP - MIN_EXP + 2
elif x == 0.0:
mant = 0
exp = 0
else:
m, e = math.frexp(abs(x)) # abs(x) == m * 2**e
exp = e - (MIN_EXP - 1)
if exp > 0:
# Normal case.
mant = round_to_nearest(m * (1 << MANT_DIG))
mant -= 1 << MANT_DIG - 1
else:
# Subnormal case.
if exp + MANT_DIG - 1 >= 0:
mant = round_to_nearest(m * (1 << exp + MANT_DIG - 1))
else:
mant = 0
exp = 0
# Special case: rounding produced a MANT_DIG-bit mantissa.
assert 0 <= mant <= 1 << MANT_DIG - 1
if mant == 1 << MANT_DIG - 1:
mant = 0
exp += 1
# Raise on overflow (in some circumstances, may want to return
# infinity instead).
if exp >= MAX_EXP - MIN_EXP + 2:
raise OverflowError("float too large to pack in this format")
# check constraints
assert 0 <= mant < 1 << MANT_DIG - 1
assert 0 <= exp <= MAX_EXP - MIN_EXP + 2
assert 0 <= sign <= 1
return ((sign << BITS - 1) | (exp << MANT_DIG - 1)) | mant
big_endian_format = {
'x': {'size': 1, 'alignment': 0, 'pack': None, 'unpack': None},
'b': {'size': 1, 'alignment': 0, 'pack': pack_signed_int, 'unpack': unpack_signed_int},
'B': {'size': 1, 'alignment': 0, 'pack': pack_unsigned_int, 'unpack': unpack_int},
'c': {'size': 1, 'alignment': 0, 'pack': pack_char, 'unpack': unpack_char},
's': {'size': 1, 'alignment': 0, 'pack': None, 'unpack': None},
'p': {'size': 1, 'alignment': 0, 'pack': None, 'unpack': None},
'h': {'size': 2, 'alignment': 0, 'pack': pack_signed_int, 'unpack': unpack_signed_int},
'H': {'size': 2, 'alignment': 0, 'pack': pack_unsigned_int, 'unpack': unpack_int},
'i': {'size': 4, 'alignment': 0, 'pack': pack_signed_int, 'unpack': unpack_signed_int},
'I': {'size': 4, 'alignment': 0, 'pack': pack_unsigned_int, 'unpack': unpack_int},
'l': {'size': 4, 'alignment': 0, 'pack': pack_signed_int, 'unpack': unpack_signed_int},
'L': {'size': 4, 'alignment': 0, 'pack': pack_unsigned_int, 'unpack': unpack_int},
'q': {'size': 8, 'alignment': 0, 'pack': pack_signed_int, 'unpack': unpack_signed_int},
'Q': {'size': 8, 'alignment': 0, 'pack': pack_unsigned_int, 'unpack': unpack_int},
'f': {'size': 4, 'alignment': 0, 'pack': pack_float, 'unpack': unpack_float},
'd': {'size': 8, 'alignment': 0, 'pack': pack_float, 'unpack': unpack_float},
}
default = big_endian_format
formatmode = {'<': (default, 'little'),
'>': (default, 'big'),
'!': (default, 'big'),
'=': (default, sys.byteorder),
'@': (default, sys.byteorder)
}
def getmode(fmt):
try:
formatdef, endianness = formatmode[fmt[0]]
index = 1
except (IndexError, KeyError):
formatdef, endianness = formatmode['@']
index = 0
return formatdef, endianness, index
def getNum(fmt, i):
num = None
cur = fmt[i]
while ('0' <= cur) and (cur <= '9'):
if num == None:
num = int(cur)
else:
num = 10 * num + int(cur)
i += 1
cur = fmt[i]
return num, i
def calcsize(fmt):
"""calcsize(fmt) -> int
Return size of C struct described by format string fmt.
See struct.__doc__ for more on format strings."""
formatdef, endianness, i = getmode(fmt)
num = 0
result = 0
while i < len(fmt):
num, i = getNum(fmt, i)
cur = fmt[i]
try:
format = formatdef[cur]
except KeyError:
raise StructError("%s is not a valid format" % cur)
if num != None:
result += num * format['size']
else:
result += format['size']
num = 0
i += 1
return result
def pack(fmt, *args):
"""pack(fmt, v1, v2, ...) -> string
Return string containing values v1, v2, ... packed according to fmt.
See struct.__doc__ for more on format strings."""
formatdef, endianness, i = getmode(fmt)
args = list(args)
n_args = len(args)
result = []
while i < len(fmt):
num, i = getNum(fmt, i)
cur = fmt[i]
try:
format = formatdef[cur]
except KeyError:
raise StructError("%s is not a valid format" % cur)
if num == None:
num_s = 0
num = 1
else:
num_s = num
if cur == 'x':
result += [b'\0' * num]
elif cur == 's':
if isinstance(args[0], bytes):
padding = num - len(args[0])
result += [args[0][:num] + b'\0' * padding]
args.pop(0)
else:
raise StructError("arg for string format not a string")
elif cur == 'p':
if isinstance(args[0], bytes):
padding = num - len(args[0]) - 1
if padding > 0:
result += [bytes([len(args[0])]) + args[0]
[:num - 1] + b'\0' * padding]
else:
if num < 255:
result += [bytes([num - 1]) + args[0][:num - 1]]
else:
result += [bytes([255]) + args[0][:num - 1]]
args.pop(0)
else:
raise StructError("arg for string format not a string")
else:
if len(args) < num:
raise StructError("insufficient arguments to pack")
for var in args[:num]:
result += [format['pack'](var, format['size'], endianness)]
args = args[num:]
num = None
i += 1
if len(args) != 0:
raise StructError("too many arguments for pack format")
return b''.join(result)
def unpack(fmt, data):
"""unpack(fmt, string) -> (v1, v2, ...)
Unpack the string, containing packed C structure data, according
to fmt. Requires len(string)==calcsize(fmt).
See struct.__doc__ for more on format strings."""
formatdef, endianness, i = getmode(fmt)
j = 0
num = 0
result = []
length = calcsize(fmt)
if length != len(data):
raise StructError("unpack str size does not match format")
while i < len(fmt):
num, i = getNum(fmt, i)
cur = fmt[i]
i += 1
try:
format = formatdef[cur]
except KeyError:
raise StructError("%s is not a valid format" % cur)
if not num:
num = 1
if cur == 'x':
j += num
elif cur == 's':
result.append(data[j:j + num])
j += num
elif cur == 'p':
n = data[j]
if n >= num:
n = num - 1
result.append(data[j + 1:j + n + 1])
j += num
else:
for n in range(num):
result += [format['unpack'](data, j, format['size'], endianness)]
j += format['size']
return tuple(result)
def pack_into(fmt, buf, offset, *args):
data = pack(fmt, *args)
buffer(buf)[offset:offset + len(data)] = data
def unpack_from(fmt, buf, offset=0):
size = calcsize(fmt)
data = buffer(buf)[offset:offset + size]
if len(data) != size:
raise error("unpack_from requires a buffer of at least %d bytes"
% (size,))
return unpack(fmt, data)
def _clearcache():
"Clear the internal cache."
# No cache in this implementation
# Copyright 2016 Google Inc. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""MD5 message digest algorithm."""
import _md5
new = _md5.new
md5 = _md5.new
digest_size = _md5.digest_size
blocksize = 1
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment