Categories
scripting softimage tutorials

How to read an XSIADDON file in Python

Ever wondered what’s the deal with *.xsiaddon files? What are they?

Well, they’re good ol’ XML with a bit of metadata and the files embedded in them are compressed with the zlib library and base64 encoded for safe plaintext storage.

How would we parse such a file? Check this out:

import os
import zlib
import base64
import xml.etree.ElementTree as ET
from pprint import pprint as pp

tmpDir = os.environ['TMP']
xsiaddonPath = r'C:\path\to\something.xsiaddon'

tree = ET.parse(xsiaddonPath) # Load file

# Get the root element ('xsi_file')
root = tree.getroot()
addonInfo = {
    'version':        root.find('AddonVersion').text,
    'title':          root.find('Title').text,
    'author':         root.find('AuthorName').text,
    'email':          root.find('AuthorEMail').text,
    'url':            root.find('URL').text,
    'desc':           root.find('Description').text,
    'usage':          root.find('Usage').text,
    'installDirName': root.find('InstallDir').text,
    'madeInVersion':  root.attrib['xsi_version']
}
pp(addonInfo) # pretty print :)

# Now let's loop through all the files embedded in it:
addonFiles = root.findall('AddonItem')
for item in addonFiles:
    fileName = item.attrib['filename']
    relativeExtractionPath = item.attrib.setdefault('destination','\\')
    fileCategory = item.attrib['type'] # SPDLs, Others, etc.

    # XSIADDON ATTACHMENTS ARE BASE64-ENCODED STRINGS
    # OF ZLIB-COMPRESSED DATA, but ONLY AFTER THE 12TH BYTE.
    # 
    # In Halfdan's own words:
    # "They're compressed using zlib but they don't have the
    #  gzip headers. The compression starts at the 12th byte.
    #  The first 12 bytes contain a textural representation
    #  of the size (+pad)."
    # 
    decoded = base64.b64decode(item.text)
    data = zlib.decompress( decoded[12:] )

    fileInfo = {
        'filename':  fileName,
        'filesize':  len(data),
        'extractTo': relativeExtractionPath,
        'category':  fileCategory,
    }
    pp(fileInfo)

    # For demonstration sake, invent a temporary filepath:
    filePath = os.path.normpath(tmpDir+'\\'+fileName)

    # Write our file to disk:
    f = open(filePath, 'wb')
    f.write(data)
    f.close()

    print "Extracted %s to: %s" % (fileName, filePath)

print ( "Gee wiz, %s! That xsiaddon had %s file(s). --> %s" 
% (os.environ['USERNAME'], len(addonFiles), xsiaddonPath) )

# Mission accomplished.

Easy as that! šŸ˜€

One reply on “How to read an XSIADDON file in Python”

Leave a Reply