import zlib, struct, bz2, os, sys from xml.dom.minidom import parseString def getByte(f): return struct.unpack("H",f.read(2))[0]; def getSWord(f): return struct.unpack(">h",f.read(2))[0]; def getDWord(f): return struct.unpack(">I",f.read(4))[0]; def getSDWord(f): return struct.unpack(">i",f.read(4))[0]; def getQWord(f): return struct.unpack(">Q",f.read(8))[0]; def getDouble(f): return struct.unpack(">d",f.read(8))[0]; """ struct xar_header { uint32_t magic; uint16_t size; uint16_t version; uint64_t toc_length_compressed; uint64_t toc_length_uncompressed; uint32_t cksum_alg; }; """ def getChildNodes(node, tagname): return [c for c in node.childNodes if ((c.nodeType==c.ELEMENT_NODE) and (c.tagName==tagname))] def getChildNode(node, tagname): return getChildNodes(node, tagname)[0] def domtext(node, subnode): n1 = getChildNode(node, subnode) for n2 in n1.childNodes: if n2.nodeType == n2.TEXT_NODE: return n2.data def domint(node, subnode): return int(domtext(node, subnode)) def getattr(node, subnode, attrname): subn = node.getElementsByTagName(subnode)[0] attr = subn.getAttribute(attrname) return attr class XarFile: def handleFile(self, fil, dirname): name = domtext(fil, "name") type = domtext(fil, "type") print "Name: %s"%name print "Type: %s"%type if type == "file": dtn = getChildNode(fil, "data") offset = domint(dtn, "offset") length = domint(dtn, "length") enc = getattr(dtn, "encoding", "style") self._file.seek(self.start_offset+offset) data = self._file.read(length) if enc=="application/x-bzip2": try: data = bz2.decompress(data) except: print "Error decompressing %s! Writing as-is"%name elif enc!="application/octet-stream": raise Exception("Unknown encoding: %s!"%enc) file(dirname+'/'+name, "wb").write(data) elif type == "directory": newdir = dirname+'/'+name try: os.makedirs(newdir) except: pass files = getChildNodes(fil, "file") for fil2 in files: #print fil self.handleFile(fil2, newdir) def walk_toc(self, toc_, dirname): dom = parseString(toc_) toc = dom.getElementsByTagName("toc")[0] files = getChildNodes(toc, "file") for fil in files: #print fil self.handleFile(fil, dirname) def doXar(self, fname, dirname): f = file(fname,"rb") if f.read(4)!='xar!': print "bad header!" return size = getWord(f) ver = getWord(f) tocu = getQWord(f) tocc = getQWord(f) f.seek(size) toc = zlib.decompress(f.read(tocc)) #f.seek(size+tocu) self.start_offset = size+tocu #print toc self._file = f try: os.makedirs(dirname) except: pass self.walk_toc(toc, dirname) #return toc, (size+tocu) xar = XarFile() xar.doXar(sys.argv[1],sys.argv[2])