def exportBinBlocksXMLTree(self): """ Export the file data into BIN files with XML glue """ elem = self.exportXMLRoot() for ident, block in self.blocks.items(): if (self.po.verbose > 0): print("{}: Writing BIN block {}".format(self.src_fname, ident)) subelem = block.exportXMLTree(simple_bin=True) elem.append(subelem) ET.pretty_element_tree_heap(elem) return elem
def exportXMLTree(self): """ Export the file data into XML tree """ elem = self.exportXMLRoot() for ident, block in self.blocks.items(): if (self.po.verbose > 0): print("{}: Writing block {}".format(self.src_fname, ident)) subelem = block.exportXMLTree() elem.append(subelem) ET.pretty_element_tree_heap(elem) return elem
def exportXMLOrder(self, elem): if self.order_names is None: return order_elem = ET.SubElement(elem,"SpecialOrder") comment_elem = ET.Comment(" {:s} ".format("Provides information on how items were ordered in the RSRC file")) order_elem.append(comment_elem) if self.order_names is not None: subelem = ET.SubElement(order_elem,"Names") for blockref in self.order_names: pretty_ident = getPrettyStrFromRsrcType(blockref[0]) blkref_elem = ET.Element(pretty_ident) blkref_elem.set("Index", str(blockref[1])) subelem.append(blkref_elem) pass
def exportXMLRoot(self): """ Creates root of the XML export tree """ ver = self.getFileVersion() elem = ET.Element('RSRC') elem.set("FormatVersion", "{:d}".format(self.fmtver)) rsrc_type_id = getRsrcTypeForFileType(self.ftype) elem.set("Type", rsrc_type_id.decode('ascii')) elem.set("Encoding", self.textEncoding) if self.ftype == FILE_FMT_TYPE.LLB or isSmallerVersion(ver, 7, 0, 0): dataset_int1 = self.binflsthead.dataset_int1 else: dataset_int1 = None if dataset_int1 is not None: elem.set("Int1", "0x{:08X}".format(dataset_int1)) # The value is verified to be used in LV6.0.1, unused in LV8.6 if self.ftype == FILE_FMT_TYPE.LLB or isSmallerVersion(ver, 7, 0, 0): dataset_int2 = self.binflsthead.dataset_int2 else: dataset_int2 = None if dataset_int2 is not None: elem.set("Int2", "0x{:08X}".format(dataset_int2)) return elem
def exportXML(self, obj_elem, fname_base): obj_elem.set("Ident", getPrettyStrFromRsrcType(self.ident)) obj_elem.set("TpIdent", self.tpident.decode(encoding='ascii')) for text_val in self.content: subelem = ET.SubElement(obj_elem,"String") pretty_string = text_val.decode(self.vi.textEncoding) subelem.text = pretty_string pass
def exportXML(self, obj_elem, fname_base): obj_elem.set("Ident", getPrettyStrFromRsrcType(self.ident)) obj_elem.set("TpVal", "{:d}".format(self.tpval)) if self.canZeroFill: obj_elem.set("ZeroFill", "True") for text_val in self.content: subelem = ET.SubElement(obj_elem,"String") pretty_string = text_val.decode(self.vi.textEncoding) subelem.text = pretty_string pass
def exportXML(self, obj_elem, fname_base): obj_elem.tag = type(self).__name__ obj_elem.set("HasVarItem2", "{:d}".format(self.hasvaritem2)) if self.hasvaritem2 != 0: obj_elem.set("VarType2", "{:d}".format(self.vartype2)) # Check whether we want to store version auto_ver = self.vi.getFileVersion() if all(self.version[k] == auto_ver[k] for k in ('major','minor','bugfix','stage','build','flags')): autoVersion = True else: autoVersion = False if autoVersion: obj_elem.set("Version", "{:s}".format("auto")) else: subelem = ET.SubElement(obj_elem,"Version") subelem.set("Major", "{:d}".format(self.version['major'])) subelem.set("Minor", "{:d}".format(self.version['minor'])) subelem.set("Bugfix", "{:d}".format(self.version['bugfix'])) subelem.set("Stage", "{:s}".format(self.version['stage_text'])) subelem.set("Build", "{:d}".format(self.version['build'])) subelem.set("Flags", "0x{:X}".format(self.version['flags'])) idx = -1 for clientTD in self.clients2: if clientTD.index != -1: continue idx += 1 fname_cli = "{:s}_{:04d}".format(fname_base, idx) subelem = ET.SubElement(obj_elem,"DataType") subelem.set("Index", str(idx)) subelem.set("Type", stringFromValEnumOrInt(LVdatatype.TD_FULL_TYPE, clientTD.nested.otype)) clientTD.nested.exportXML(subelem, fname_cli) clientTD.nested.exportXMLFinish(subelem) if len(self.attrs) > 0: attrs_elem = ET.SubElement(obj_elem,"Attributes") for attrib in self.attrs: subelem = ET.SubElement(attrs_elem,"Object") subelem.set("Name", attrib.name.decode(encoding=self.vi.textEncoding)) attrib.value.exportXML(subelem, fname_base) if self.allowFillValue and self.hasvaritem2 and len(self.datafill) > 0: df_elem = ET.SubElement(obj_elem,"DataFill") for df in self.datafill: df_subelem = ET.SubElement(df_elem, df.getXMLTagName()) df.exportXML(df_subelem, fname_base) pass
def exportXMLRoot(self): """ Creates root of the XML export tree """ elem = ET.Element('RSRC') rsrc_type_id = getRsrcTypeForFileType(self.ftype) elem.set("Type", rsrc_type_id.decode('ascii')) elem.set("Encoding", self.textEncoding) if self.ftype == FILE_FMT_TYPE.LLB: dataset_int1 = self.binflsthead.dataset_int1 else: dataset_int1 = None if dataset_int1 is not None: elem.set("Int1", "0x{:08X}".format(dataset_int1)) if self.ftype == FILE_FMT_TYPE.LLB: dataset_int2 = self.binflsthead.dataset_int2 else: dataset_int2 = None if dataset_int2 is not None: elem.set("Int2", "0x{:08X}".format(dataset_int2)) return elem
def main(): """ Main executable function. Its task is to parse command line options and call a function which performs requested command. """ # Parse command line options parser = argparse.ArgumentParser(description=__doc__) parser.add_argument('-i', '--rsrc', '--vi', default="", type=str, help="name of the LabView RSRC file, VI or other") parser.add_argument('-m', '--xml', default="", type=str, help="name of the main XML file of extracted VI dataset;" \ "default is RSRC file name with extension changed to xml") parser.add_argument( '-v', '--verbose', action='count', default=0, help="increases verbosity level; max level is set by -vvv") parser.add_argument( '-t', '--textcp', default="mac_roman", type=str, help= "Text encoding used while loading VI file (default is \"%(default)s\")" ) parser.add_argument('--raw-connectors', action='store_true', help="extract all connectors into raw binary files instead of pure XML" \ " (works only with --extract command)") parser.add_argument('--print-map', choices=["RSRC","VCTP","DFDS"], help="print map for whole file (RSRC) or section (VCTP,DFDS);" \ " the map contains offsets at which things are within the file;" \ " for sections which are compressed within RSRC file, specific" \ " offsets can only be assigned after dumping it to bin") parser.add_argument('--keep-names', action='store_true', help="extract files to names indicated by RSRC content" \ " (works with --extract and --dump commands; useful for LLBs)") subparser = parser.add_mutually_exclusive_group(required=True) subparser.add_argument('-l', '--list', action='store_true', help="list content of RSRC file") subparser.add_argument('-d', '--dump', action='store_true', help="dump items from RSRC file into XML and BINs, with minimal" \ " parsing of the data inside") subparser.add_argument('-x', '--extract', action='store_true', help="extract content of RSRC file into XMLs, parsing all blocks" \ " which structure is known") subparser.add_argument('-c', '--create', action='store_true', help="create RSRC file using information from XMLs") subparser.add_argument('-n', '--info', action='store_true', help="print general information about RSRC file") subparser.add_argument('-p', '--password', default=None, type=str, help="change password and re-compute checksums within RSRC file;" \ " save changes in-place, to the RSRC file") subparser.add_argument('--version', action='version', version="%(prog)s {version} by {author}".format( version=__version__, author=__author__), help="display version information and exit") po = parser.parse_args() po.typedesc_list_limit = 4095 po.array_data_limit = (2**28) - 1 # Store base name - without path and extension if len(po.xml) > 0: po.filebase = os.path.splitext(os.path.basename(po.xml))[0] elif len(po.rsrc) > 0: po.filebase = os.path.splitext(os.path.basename(po.rsrc))[0] else: raise FileNotFoundError( "Input file was not provided neither as RSRC or XML.") if po.list: if len(po.rsrc) == 0: raise FileNotFoundError( "Only RSRC file listing is currently supported.") if (po.verbose > 0): print("{}: Starting file parse for RSRC listing".format(po.rsrc)) with open(po.rsrc, "rb") as rsrc_fh: vi = VI(po, rsrc_fh=rsrc_fh, text_encoding=po.textcp) print("{}\t{}".format("ident", "content")) for ident, block in vi.blocks.items(): pretty_ident = block.ident.decode(encoding='UTF-8') print("{}\t{}".format(pretty_ident, str(block))) elif po.dump: if len(po.xml) == 0: po.xml = po.filebase + ".xml" if len(po.rsrc) == 0: po.rsrc = getExistingRSRCFileWithBase(po.filebase) if len(po.rsrc) == 0: raise FileNotFoundError( "No supported RSRC file was found despite checking all extensions." ) if (po.verbose > 0): print("{}: Starting file parse for RSRC dumping".format(po.rsrc)) with open(po.rsrc, "rb") as rsrc_fh: vi = VI(po, rsrc_fh=rsrc_fh, text_encoding=po.textcp) root = vi.exportBinBlocksXMLTree() if po.print_map is not None: vi.printRSRCMap() if (po.verbose > 0): print("{}: Writing binding XML".format(po.xml)) tree = ET.ElementTree(root) with open(po.xml, "wb") as xml_fh: tree.write(xml_fh, encoding='utf-8', xml_declaration=True) elif po.extract: if len(po.xml) == 0: po.xml = po.filebase + ".xml" if len(po.rsrc) == 0: po.rsrc = getExistingRSRCFileWithBase(po.filebase) if len(po.rsrc) == 0: raise FileNotFoundError( "No supported RSRC file was found despite checking all extensions." ) if (po.verbose > 0): print("{}: Starting file parse for RSRC extraction".format( po.rsrc)) with open(po.rsrc, "rb") as rsrc_fh: vi = VI(po, rsrc_fh=rsrc_fh, text_encoding=po.textcp) root = vi.exportXMLTree() if po.print_map is not None: vi.printRSRCMap() if (po.verbose > 0): print("{}: Writing binding XML".format(po.xml)) tree = ET.ElementTree(root) with open(po.xml, "wb") as xml_fh: tree.write(xml_fh, encoding='utf-8', xml_declaration=True) elif po.create: if len(po.xml) == 0: po.xml = po.filebase + ".xml" if (po.verbose > 0): print("{}: Starting file parse for RSRC creation".format(po.rsrc)) tree = ET.parse(po.xml) vi = VI(po, xml_root=tree.getroot(), text_encoding=po.textcp) if len(po.rsrc) == 0: po.rsrc = po.filebase + "." + getFileExtByType(vi.ftype) with open(po.rsrc, "wb") as rsrc_fh: vi.saveRSRC(rsrc_fh) elif po.password is not None: if len(po.rsrc) == 0: raise FileNotFoundError( "Only RSRC file password change is currently supported.") if (po.verbose > 0): print("{}: Starting file parse for password change".format( po.rsrc)) with open(po.rsrc, "rb") as rsrc_fh: vi = VI(po, rsrc_fh=rsrc_fh, text_encoding=po.textcp) vi.forceCompleteReadRSRC() BDPW = vi.get_or_raise('BDPW') if BDPW is not None: print("{:s}: Previous password data".format(po.rsrc)) print(" password md5: {:s}".format(BDPW.password_md5.hex())) print(" hash_1 : {:s}".format(BDPW.hash_1.hex())) print(" hash_2 : {:s}".format(BDPW.hash_2.hex())) password_md5 = BDPW.password_md5 BDPW = vi.setNewPassword(password_text=po.password) if BDPW is not None: print("{:s}: New password data".format(po.rsrc)) print(" password md5: {:s}".format(BDPW.password_md5.hex())) print(" hash_1 : {:s}".format(BDPW.hash_1.hex())) print(" hash_2 : {:s}".format(BDPW.hash_2.hex())) with open(po.rsrc, "wb") as rsrc_fh: vi.saveRSRC(rsrc_fh) else: raise NotImplementedError('Unsupported command.')