1# Copyright (C) 2021-2022 Intel Corporation.
2#
3# SPDX-License-Identifier: BSD-3-Clause
4#
5
6import logging
7
8from .exception import *
9from .grammar import AML_EXT_OP_PREFIX
10
11class Stream:
12    def print_binary(self, base):
13        acc = f"[{hex(base):>8s}/{hex(len(self.data)):>8s}]"
14        converted = ""
15        for i in range(base, base + 16):
16            code = self.data[i]
17            acc += " %02x" % code
18            if code >= 0x20 and code <= 0x7E:
19                converted += chr(code)
20            else:
21                converted += "."
22            if i > base and ((i - base) % 4) == 3:
23                acc += " "
24                converted += " "
25        acc += f"    '{converted}'"
26        logging.debug(acc)
27
28    def __init__(self, data):
29        self.data = data
30        self.current = 0
31        self.scopes = [len(data)]
32
33    def peek_integer(self, count):
34        if self.current + count > self.scopes[-1]:
35            raise ScopeMismatch
36        ret = 0
37        for i in range(0, count):
38            ret += (self.data[self.current + i] << (i * 8))
39        return ret
40
41    def get_integer(self, count):
42        if self.current + count > self.scopes[-1]:
43            raise ScopeMismatch
44        ret = self.peek_integer(count)
45        self.current += count
46        return ret
47
48    def get_char(self):
49        if self.current + 1 > self.scopes[-1]:
50            raise ScopeMismatch
51        ret = chr(self.data[self.current])
52        self.current += 1
53        return ret
54
55    def peek_opcode(self):
56        opcode = self.peek_integer(1)
57        if opcode == AML_EXT_OP_PREFIX:
58            opcode = self.peek_integer(2)
59            return (opcode, 2)
60        return (opcode, 1)
61
62    def get_opcode(self):
63        opcode = self.get_integer(1)
64        if opcode == AML_EXT_OP_PREFIX:
65            opcode += (self.get_integer(1) << 8)
66            return (opcode, 2)
67        return (opcode, 1)
68
69    def get_fixed_length_string(self, count):
70        if self.current + count > self.scopes[-1]:
71            raise ScopeMismatch
72        ret = self.data[self.current : self.current + count].decode("latin-1")
73        self.current += count
74        return ret
75
76    def get_string(self):
77        null = self.data.find(0x00, self.current)
78        assert null >= 0
79        if null + 1 > self.scopes[-1]:
80            raise ScopeMismatch
81        ret = self.data[self.current:null].decode("latin-1")
82        self.current = null + 1
83        return ret
84
85    def get_buffer(self):
86        cur = self.current
87        self.current = self.scopes[-1]
88        return self.data[cur:self.current]
89
90    def seek(self, offset, absolute=False):
91        if absolute:
92            self.current = offset
93        else:
94            self.current += offset
95
96    def at_end(self):
97        return self.current == self.scopes[-1]
98
99    def push_scope(self, size):
100        self.scopes.append(self.current + size)
101
102    def pop_scope(self, force=False):
103        if not force and not self.at_end():
104            raise ScopeMismatch
105        self.scopes.pop()
106
107    def reset(self):
108        self.current = 0
109        self.scopes = [len(self.data)]
110
111    def dump(self):
112        self.print_binary(self.current - 48)
113        self.print_binary(self.current - 32)
114        self.print_binary(self.current - 16)
115        self.print_binary(self.current)
116