def convert_to_iterators(expr, vars, pad=0): """Solve all children in expr and return a list of iterators. Each iterator is expanded or repeated so they are all the same length. """ max_length = 0 iterators = [] # Expand each child into a list. for child in expr.children: val = solve(child, vars).value if repeated.isrepeating(val) and not number.isnumber(val): val = convert_to_list(expr, val) if len(val) > max_length: max_length = len(val) # This is a scalar - at least of length 1. else: max_length = max(max_length, 1) iterators.append(val) # Pad all iterator lists to be the same length. for i, item in enumerate(iterators): # Repeat scalar values. if not isinstance(item, list): iterators[i] = [item] * max_length # Extend short lists to the required length elif len(item) < max_length: item.extend([pad] * (max_length - len(item))) return iterators
def solve_quotient(expr, vars): iterators = convert_to_iterators(expr, vars, pad=0) # Add each element individually. result = [] for elements in zip(*iterators): total = None for element in elements: if number.isnumber(element): if total is None: total = element else: # Division by 0. if eq.eq(element, 0): total = None break total = number.quotient(total, element) # If we encounter a non-number we swallow the error and # return None. This could happen for example if one of the # columns in the select returns NoneObject() or something # which is not a number. else: total = None break result.append(total) return Result(result, ())
def solve_sum(expr, vars): """Handle numerical operators. We can mix scalars and repeated elements freely. The result is always repeated. Scalars are turned into repeated lists of the scalar while repeated values are turned into lists padded with the pad element to the longest list we operate on. Examples: # Scalars are expanded to repeat themselves. [1, 2] + 4 -> [1, 2] + [4, 4] -> [5, 6] # Lists are padded [1, 2] + [1, 2, 3] -> [1, 2, 0] + [1, 2, 3] -> [2, 4, 3] # Subselects are expanded if they contain a single column. select hex(offset), hexdump from dump( offset: (-0x20 + ( select _EPROCESS.obj_offset from pslist(proc_regex: "svchost"))), rows: 5 ) """ iterators = convert_to_iterators(expr, vars, pad=0) # Add each element individually. result = [] for elements in zip(*iterators): total = 0 for element in elements: if number.isnumber(element): total = number.sum(element, total) # If we encounter a non-number we swallow the error and # return None. This could happen for example if one of the # columns in the select returns NoneObject() or something # which is not a number. else: total = None break result.append(total) return Result(result, ())