| 84 | |
| 85 | |
| 86 | class Reader: |
| 87 | # A fairly literal translation of the marshal reader. |
| 88 | |
| 89 | def __init__(self, data: bytes): |
| 90 | self.data: bytes = data |
| 91 | self.end: int = len(self.data) |
| 92 | self.pos: int = 0 |
| 93 | self.refs: list[Any] = [] |
| 94 | self.level: int = 0 |
| 95 | |
| 96 | def r_string(self, n: int) -> bytes: |
| 97 | assert 0 <= n <= self.end - self.pos |
| 98 | buf = self.data[self.pos : self.pos + n] |
| 99 | self.pos += n |
| 100 | return buf |
| 101 | |
| 102 | def r_byte(self) -> int: |
| 103 | buf = self.r_string(1) |
| 104 | return buf[0] |
| 105 | |
| 106 | def r_short(self) -> int: |
| 107 | buf = self.r_string(2) |
| 108 | x = buf[0] |
| 109 | x |= buf[1] << 8 |
| 110 | x |= -(x & (1<<15)) # Sign-extend |
| 111 | return x |
| 112 | |
| 113 | def r_long(self) -> int: |
| 114 | buf = self.r_string(4) |
| 115 | x = buf[0] |
| 116 | x |= buf[1] << 8 |
| 117 | x |= buf[2] << 16 |
| 118 | x |= buf[3] << 24 |
| 119 | x |= -(x & (1<<31)) # Sign-extend |
| 120 | return x |
| 121 | |
| 122 | def r_long64(self) -> int: |
| 123 | buf = self.r_string(8) |
| 124 | x = buf[0] |
| 125 | x |= buf[1] << 8 |
| 126 | x |= buf[2] << 16 |
| 127 | x |= buf[3] << 24 |
| 128 | x |= buf[4] << 32 |
| 129 | x |= buf[5] << 40 |
| 130 | x |= buf[6] << 48 |
| 131 | x |= buf[7] << 56 |
| 132 | x |= -(x & (1<<63)) # Sign-extend |
| 133 | return x |
| 134 | |
| 135 | def r_PyLong(self) -> int: |
| 136 | n = self.r_long() |
| 137 | size = abs(n) |
| 138 | x = 0 |
| 139 | # Pray this is right |
| 140 | for i in range(size): |
| 141 | x |= self.r_short() << i*15 |
| 142 | if n < 0: |
| 143 | x = -x |