1
#! /usr/bin/env python3
3
# ***** BEGIN GPL LICENSE BLOCK *****
5
# This program is free software; you can redistribute it and/or
6
# modify it under the terms of the GNU General Public License
7
# as published by the Free Software Foundation; either version 2
8
# of the License, or (at your option) any later version.
10
# This program is distributed in the hope that it will be useful,
11
# but WITHOUT ANY WARRANTY; without even the implied warranty of
12
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
# GNU General Public License for more details.
15
# You should have received a copy of the GNU General Public License
16
# along with this program; if not, write to the Free Software Foundation,
17
# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19
# ***** END GPL LICENCE BLOCK *****
21
######################################################
27
# Creates a browsable DNA output to HTML.
33
# v0.1 (12-05-2009) - migration of original source code to python.
34
# Added code to support blender 2.5 branch
35
# v0.2 (25-05-2009) - integrated with BlendFileReader.py
38
# blender build executable
42
# dna.css (will only be created when not existing)
45
# ./blender -P BlendFileDnaExporter.py
48
# 1: write blend file with SDNA info
49
# 2: read blend header from blend file
50
# 3: seek DNA1 file-block
51
# 4: read dna record from blend file
52
# 5: close and eventually delete temp blend file
53
# 6: export dna to html and css
56
######################################################
60
import getopt # command line arguments handling
61
from string import Template # strings completion
66
log = logging.getLogger("BlendFileDnaExporter")
68
if '--dna-debug' in sys.argv:
69
logging.basicConfig(level=logging.DEBUG)
71
logging.basicConfig(level=logging.INFO)
76
DNACatalog is a catalog of all information in the DNA1 file-block
79
def __init__(self, catalog, bpy_module = None):
80
self.Catalog = catalog
83
def WriteToHTML(self, handle):
85
dna_html_template = """
86
<!DOCTYPE html PUBLIC -//W3C//DTD HTML 4.01 Transitional//EN http://www.w3.org/TR/html4/loose.dtd>
89
<link rel="stylesheet" type="text/css" href="dna.css" media="screen, print" />
90
<meta http-equiv="Content-Type" content="text/html"; charset="ISO-8859-1" />
91
<title>The mystery of the blend</title>
95
Blender ${version}<br/>
96
Internal SDNA structures
98
Architecture: ${bitness} ${endianness}<br/>
99
Build revision: <a href="https://svn.blender.org/svnroot/bf-blender/!svn/bc/${revision}/trunk/">${revision}</a><br/>
100
File format reference: <a href="mystery_of_the_blend.html">The mystery of the blend</a> by Jeroen Bakker<br/>
101
<h1>Index of blender structures</h1>
102
<ul class=multicolumn>
109
header = self.Catalog.Header
112
# ${version} and ${revision}
114
version = '.'.join(map(str, bpy.app.version))
115
revision = bpy.app.build_revision[:-1]
117
version = str(header.Version)
121
if header.PointerSize == 8:
127
if header.LittleEndianness:
128
endianess= 'Little endianness'
130
endianess= 'Big endianness'
133
log.debug("Creating structs index")
135
list_item = '<li class="multicolumn">({0}) <a href="#{1}">{1}</a></li>\n'
137
for structure in self.Catalog.Structs:
138
structs_list += list_item.format(structureIndex, structure.Type.Name)
142
log.debug("Creating structs content")
144
for structure in self.Catalog.Structs:
145
log.debug(structure.Type.Name)
146
structs_content += self.Structure(structure)
152
endianness = endianess,
153
structs_list = structs_list,
154
structs_content = structs_content
157
dna_html = Template(dna_html_template).substitute(d)
158
dna_html = self.format(dna_html)
159
handle.write(dna_html)
161
def Structure(self, structure):
162
struct_table_template = """
163
<table><a name="${struct_name}"></a>
164
<caption><a href="#${struct_name}">${struct_name}</a></caption>
179
<label>Total size: ${size} bytes</label><br/>
180
<label>(<a href="#top">top</a>)</label><br/>"""
183
struct_name = structure.Type.Name,
184
fields = self.StructureFields(structure, None, 0),
185
size = str(structure.Type.Size)
188
struct_table = Template(struct_table_template).substitute(d)
191
def StructureFields(self, structure, parentReference, offset):
193
for field in structure.Fields:
194
fields += self.StructureField(field, structure, parentReference, offset)
195
offset += field.Size(self.Catalog.Header)
198
def StructureField(self, field, structure, parentReference, offset):
199
structure_field_template = """
201
<td>${reference}</td>
209
if field.Type.Structure == None or field.Name.IsPointer():
212
reference = field.Name.AsReference(parentReference)
215
if parentReference != None:
216
struct = '<a href="#{0}">{0}</a>'.format(structure.Type.Name)
218
struct = structure.Type.Name
221
type = field.Type.Name
224
name = field.Name.Name
230
size = field.Size(self.Catalog.Header)
233
reference = reference,
241
structure_field = Template(structure_field_template).substitute(d)
243
elif field.Type.Structure != None:
244
reference = field.Name.AsReference(parentReference)
245
structure_field = self.StructureFields(field.Type.Structure, reference, offset)
247
return structure_field
249
def indent(self, input, dent, startswith = ''):
252
for line in input.split('\n'):
254
output += line[dent:] + '\n' # unindent of a desired amount
256
for line in input.split('\n'):
257
output += line.lstrip() + '\n' # remove indentation completely
259
for line in input.split('\n'):
260
output += ' '* dent + line + '\n'
263
def format(self, input):
265
'\n<!DOCTYPE':'<!DOCTYPE',
267
'<a name' :'\n<a name',
272
'<tbody>\n' :'<tbody>'
274
output = self.indent(input, 0)
275
for key, value in diff.items():
276
output = output.replace(key, value)
279
def WriteToCSS(self, handle):
281
Write the Cascading stylesheet template to the handle
282
It is expected that the handle is a Filehandle
285
@CHARSET "ISO-8859-1";
288
font-family: verdana;
298
page-break-before: always;
302
background-color: #D3D3D3;
309
background-color: #EBEBEB;
319
border-color: #000000;
320
border-collapse: collapse;
322
margin: 20px 3% 10px;
330
background-color: #000000;
342
border-color: #a0a0a0;
367
text-decoration:none;
372
text-decoration:underline;
376
css = self.indent(css, 0)
382
print("\nUsage: \n\tblender2.5 -b -P BlendFileDnaExporter_25.py [-- [options]]")
384
print("\t--dna-keep-blend: doesn't delete the produced blend file DNA export to html")
385
print("\t--dna-debug: sets the logging level to DEBUG (lots of additional info)")
386
print("\t--dna-versioned saves version informations in the html and blend filenames")
387
print("\t--dna-overwrite-css overwrite dna.css, useful when modifying css in the script")
389
print("\tdefault: % blender2.5 -b -P BlendFileDnaExporter_25.py")
390
print("\twith options: % blender2.5 -b -P BlendFileDnaExporter_25.py -- --dna-keep-blend --dna-debug\n")
393
######################################################
395
######################################################
402
bpy = __import__('bpy')
405
if '--dna-versioned' in sys.argv:
406
blender_version = '_'.join(map(str, bpy.app.version))
407
filename = 'dna-{0}-{1}_endian-{2}-r{3}'.format(sys.arch, sys.byteorder, blender_version, bpy.app.build_revision[2:-1])
410
dir = os.path.dirname(__file__)
411
Path_Blend = os.path.join(dir, filename + '.blend') # temporary blend file
412
Path_HTML = os.path.join(dir, filename + '.html') # output html file
413
Path_CSS = os.path.join(dir, 'dna.css') # output css file
415
# create a blend file for dna parsing
416
if not os.path.exists(Path_Blend):
417
log.info("1: write temp blend file with SDNA info")
418
log.info(" saving to: " + Path_Blend)
420
bpy.ops.wm.save_as_mainfile(filepath = Path_Blend, copy = True, compress = False)
422
log.error("Filename {0} does not exist and can't be created... quitting".format(Path_Blend))
425
log.info("1: found blend file with SDNA info")
426
log.info(" " + Path_Blend)
428
# read blend header from blend file
429
log.info("2: read file:")
431
if not dir in sys.path:
433
import BlendFileReader
435
handle = BlendFileReader.openBlendFile(Path_Blend)
436
blendfile = BlendFileReader.BlendFile(handle)
437
catalog = DNACatalogHTML(blendfile.Catalog, bpy)
443
if '--dna-keep-blend' in sys.argv:
444
# keep the blend, useful for studying hexdumps
445
log.info("5: closing blend file:")
446
log.info(" {0}".format(Path_Blend))
449
log.info("5: close and delete temp blend:")
450
log.info(" {0}".format(Path_Blend))
451
os.remove(Path_Blend)
453
# export dna to xhtml
454
log.info("6: export sdna to xhtml file")
455
handleHTML = open(Path_HTML, "w")
456
catalog.WriteToHTML(handleHTML)
459
# only write the css when doesn't exist or at explicit request
460
if not os.path.exists(Path_CSS) or '--dna-overwrite-css' in sys.argv:
461
handleCSS = open(Path_CSS, "w")
462
catalog.WriteToCSS(handleCSS)
466
if not bpy.app.background:
467
log.info("7: quit blender")
468
bpy.ops.wm.exit_blender()
471
log.warning(" skipping, not running in Blender")
476
if __name__ == '__main__':