def parse_length(self): raw_bytes = self.data[12:13] raw_num = bytes_to_uint(raw_bytes, self.byte_order) firstb, secondb = raw_num // 16, raw_num % 16 if secondb != 0 or firstb < 5 or firstb > 15: raise InvalidFieldValue() self.length = firstb * 4
def parse_first_byte(self): raw_bytes = self.data[:1] raw_num = bytes_to_uint(raw_bytes, self.byte_order) firstb, secondb = raw_num // 16, raw_num % 16 if firstb not in [4, 6]: raise InvalidFieldValue() self.version = firstb self.length = secondb * 4
def parse_scenario(self, raw_city_data): """ Parses the scenario information. Args: raw_city_data (bytes): Raw data to parse scenario information out of. """ raw_text = raw_city_data["TEXT"] raw_scenario = raw_city_data["SCEN"] picture = raw_city_data["PICT"] for entry in raw_text: string_id = entry[: 4] raw_string = entry[4 :].decode('ASCII').replace('\r', '\n') if string_id == b'\x80\x00\x00\x00': self.scenario_text = raw_string elif string_id == b'\x81\x00\x00\x00': self.scenario_descriptive_text = raw_string else: print(f"Found unknown TEXT block in input file.\nid: {string_id}, contents: \"{raw_string}\"") if self.debug: print(f"Scenario:\nShort text: {self.scenario_text}\nDescriptive Text:{self.scenario_descriptive_text}") conditions = {} offset = 4 for k, v in self._contents.items(): conditions[k] = bytes_to_uint(raw_scenario[offset : offset + v]) offset += v if self.debug: print(f"Conditions: {conditions}") self.scenario_condition = conditions header = picture[0 : 4] if header != bytearray(b'\x80\x00\x00\x00'): print("Scenario PICT parsing failed.") # todo: exception? # Why is the endianness different here? It just is. row_length = unpack('<H', picture[4 : 6])[0] # x dimension of image. row_count = unpack('<H', picture[6 : 8])[0] # y dimension of image. image_data = [] picture_data = picture[8 : ] if self.debug: print(f"Scenario PICT, {row_length}x{row_count} pixels:") for row_idx in range(0, row_count): row_start = row_idx * (row_length + 1) row = [x for x in picture_data[row_start : row_start + row_length + 1]] if row[-1] not in (0, 255): row = [0] * row_length else: row = row[ : -1] image_data.append(row) # In case the PICT isn't 65x65, like in MALIBU.SCN if row_count > 65: image_data = image_data[: 65] if self.debug: for idx, r in enumerate(image_data): print(f"{idx}:\n{r}") self.scenario_pict = image_data
def parse_answers(self, start_pos): pos = start_pos for I in range(0, self.answers_rss): raw_data_length = self.data[pos+10:pos+12] data_length = bytes_to_uint(raw_data_length, self.byte_order) answer_length = 12 + data_length self.answers.append({ 'name': self.data[pos:pos+2], 'type': self.data[pos+2:pos+4], 'class': self.data[pos+4:pos+6], 'time_to_live': self.data[pos+6:pos+10], 'data': self.data[pos+12:pos+answer_length], }) pos += answer_length return pos
def parse_answers(self, start_pos): pos = start_pos for I in range(0, self.answers_rss): raw_data_length = self.data[pos + 10:pos + 12] data_length = bytes_to_uint(raw_data_length, self.byte_order) answer_length = 12 + data_length self.answers.append({ 'name': self.data[pos:pos + 2], 'type': self.data[pos + 2:pos + 4], 'class': self.data[pos + 4:pos + 6], 'time_to_live': self.data[pos + 6:pos + 10], 'data': self.data[pos + 12:pos + answer_length], }) pos += answer_length return pos
def parse_captured_size(self): raw_bytes = self.header[12:16] self.seconds = bytes_to_uint(raw_bytes, self.byte_order)
def parse_saved_size(self): raw_bytes = self.header[8:12] self.saved_size = bytes_to_uint(raw_bytes, self.byte_order)
def parse_total(self): raw_bytes = self.data[2:4] raw_num = bytes_to_uint(raw_bytes, self.byte_order) if raw_num < 20 or raw_num > 65535: return InvalidFieldValue() self.total = raw_num
def parse_answers_rss(self): raw_bytes = self.data[6:8] self.answers_rss = bytes_to_uint(raw_bytes, self.byte_order)
def parse_data_length(self): raw_bytes = self.data[4:6] self.data_length = bytes_to_uint(raw_bytes, self.byte_order)
def parse_source_port(self): raw_bytes = self.data[:2] self.source_port = bytes_to_uint(raw_bytes, self.byte_order)
def parse_protocol(self): raw_bytes = self.data[9:10] self.protocol = bytes_to_uint(raw_bytes, self.byte_order)
def parse_questions(self): raw_bytes = self.data[4:6] self.questions = bytes_to_uint(raw_bytes, self.byte_order)
def parse_destination_port(self): raw_bytes = self.data[2:4] self.destination_port = bytes_to_uint(raw_bytes, self.byte_order)
def parse_link_layer_type(self): raw_bytes = self.header[20:24] self.link_layer_type = bytes_to_uint(raw_bytes, self.byte_order)
def parse_time_offset(self): raw_bytes = self.header[8:12] self.time_offset = bytes_to_uint(raw_bytes, self.byte_order)
def parse_snapshot_length(self): raw_bytes = self.header[16:20] self.snapshot_length = bytes_to_uint(raw_bytes, self.byte_order)
def parse_scenario(self, raw_city_data): """ Parses the scenario information. Args: raw_city_data (bytes): Raw data to parse scenario information out of. """ self.is_scenario = True raw_text = raw_city_data["TEXT"] raw_scenario = raw_city_data["SCEN"] picture = raw_city_data["PICT"] for entry in raw_text: string_id = entry[:4] raw_string = entry[4:].decode('ASCII').replace('\r', '\n') if string_id == b'\x80\x00\x00\x00': self.scenario_text = raw_string elif string_id == b'\x81\x00\x00\x00': self.scenario_descriptive_text = raw_string else: print( f"Found unknown TEXT block in input file.\nid: {string_id}, contents: \"{raw_string}\"" ) if self.debug: print( f"Scenario:\nShort text: {self.scenario_text}\nDescriptive Text:{self.scenario_descriptive_text}" ) conditions = {} offset = 4 contents = collections.OrderedDict(( ("disaster_type", 2), ("distater_x_location", 1), ("disaster_y_location", 1), ("time_limit_months", 2), ("city_size_goal", 4), ("residential_goal", 4), ("commercial_goal", 4), ("industrial_goal", 4), ("cash_flow_goal-bonds", 4), ("land_value_goal", 4), ("pollution_limit", 4), ("traffic_limit", 4), ("crime_limit", 4), ("build_item_one", 1), ("build_item_two", 1), ("item_one_tiles", 2), ("item_two_tiles", 2), )) for k, v in contents.items(): conditions[k] = bytes_to_uint(raw_scenario[offset:offset + v]) offset += v if self.debug: print(f"Conditions: {conditions}") self.scenario_condition = conditions header = picture[0:4] if header != bytearray(b'\x80\x00\x00\x00'): print("Scenario PICT parsing failed.") # todo: exception? # Why is the endianness different here? It just is. row_length = unpack('<H', picture[4:6])[0] # x dimension of image. row_count = unpack('<H', picture[6:8])[0] # y dimension of image. image_data = [] picture_data = picture[8:] if self.debug: print(f"Scenario PICT, {row_length}x{row_count} pixels:") for row_idx in range(0, row_count): row_start = row_idx * (row_length + 1) row = [ x for x in picture_data[row_start:row_start + row_length + 1] ] if row[-1] != 255: row = [0] * row_length else: row = row[:-1] image_data.append(row) if self.debug: for idx, r in enumerate(image_data): print(f"{idx}:\n{r}") self.scenario_pict = image_data