mirror of
https://git.code.sf.net/p/quake/quakeforge
synced 2025-03-22 02:11:19 +00:00
Create a python version of qfplist.
I've decided to use property lists to define mdl control scripts. Some names will probably get changed, and I still need to write code for writing a plist, but the hard part is pretty much done :)
This commit is contained in:
parent
561484842c
commit
68bf0108fb
1 changed files with 208 additions and 0 deletions
208
tools/io_mesh_qfmdl/qfplist.py
Normal file
208
tools/io_mesh_qfmdl/qfplist.py
Normal file
|
@ -0,0 +1,208 @@
|
|||
# vim:ts=4:et
|
||||
# ##### BEGIN GPL LICENSE BLOCK #####
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
# as published by the Free Software Foundation; either version 2
|
||||
# of the License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software Foundation,
|
||||
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
#
|
||||
# ##### END GPL LICENSE BLOCK #####
|
||||
|
||||
# <pep8 compliant>
|
||||
|
||||
quotables = ("0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||
+ "abcdefghijklmnopqrstuvwxyz!#$%&*+-./:?@|~_^")
|
||||
|
||||
class pldata:
|
||||
def __init__(self, src):
|
||||
self.src = src
|
||||
self.pos = 0;
|
||||
self.end = len (self.src)
|
||||
self.error = None
|
||||
self.line = 1
|
||||
def skip_space(self):
|
||||
while self.pos < self.end:
|
||||
c = self.src[self.pos]
|
||||
if not c.isspace():
|
||||
if c == '/' and self.pos < self.end - 1: #comments
|
||||
if self.src[self.pos + 1] == '/': # // coment
|
||||
self.pos += 2
|
||||
while self.pos < self.end:
|
||||
c = self.src[self.pos]
|
||||
if c == '\n':
|
||||
break
|
||||
self.pos += 1
|
||||
if self.pos >= self.end:
|
||||
self.error = "Reached end of string in comment"
|
||||
return False
|
||||
elif self.src[self.pos + 1] == '*': # /* comment */
|
||||
self.pos += 2
|
||||
while self.pos < self.end:
|
||||
c = self.src[self.pos]
|
||||
if c == '\n':
|
||||
self.line += 1
|
||||
elif (c == '*' and self.pos < self.end - 1
|
||||
and self.src[self.pos + 1] == '/'):
|
||||
self.pos += 1
|
||||
break
|
||||
self.pos += 1
|
||||
if self.pos >= self.end:
|
||||
self.error = "Reached end of string in comment"
|
||||
return False
|
||||
else:
|
||||
return True
|
||||
else:
|
||||
return True
|
||||
if c == '\n':
|
||||
self.line += 1
|
||||
self.pos += 1
|
||||
self.error = "Reached end of string"
|
||||
def parse_quoted_string(self):
|
||||
long_string = False
|
||||
escaped = 0
|
||||
shrink = 0
|
||||
hexa = False
|
||||
self.pos += 1
|
||||
start = self.pos
|
||||
if (self.pos < self.end - 1 and self.src[self.pos] == '"'
|
||||
and self.src[self.pos + 1] == '"'):
|
||||
self.pos += 2
|
||||
long_string = True
|
||||
start += 2
|
||||
while self.pos < self.end:
|
||||
c = self.src[self.pos]
|
||||
if escaped:
|
||||
if escaped == 1 and c == '0':
|
||||
escaped += 1
|
||||
hexa = False
|
||||
elif escaped > 1:
|
||||
if escaped == 2 and c == 'x':
|
||||
hexa = True
|
||||
shring += 1
|
||||
escaped += 1
|
||||
elif hex and c.isxdigit():
|
||||
shrink += 1
|
||||
escaped += 1
|
||||
elif c in range(0, 8):
|
||||
shrink += 1
|
||||
escaped += 1
|
||||
else:
|
||||
self.pos -= 1
|
||||
escaped = 0
|
||||
else:
|
||||
escaped = 0
|
||||
else:
|
||||
if c == '\\':
|
||||
escaped = 1
|
||||
shrink += 1
|
||||
elif (c == '"'
|
||||
and (not long_string
|
||||
or (self.pos < self.end - 2
|
||||
and self.src[self.pos + 1] == '"'
|
||||
and self.src[self.pos + 2] == '"'))):
|
||||
break
|
||||
if c == '\n':
|
||||
self.line += 1
|
||||
self.pos += 1
|
||||
if self.pos >= self.end:
|
||||
self.error = "Reached end of string while parsing quoted string"
|
||||
return None
|
||||
if self.pos - start - shrink == 0:
|
||||
return ""
|
||||
s = self.src[start:self.pos]
|
||||
self.pos += 1
|
||||
if long_string:
|
||||
self.pos += 2
|
||||
return eval('"""' + s + '"""')
|
||||
def parse_unquoted_string(self):
|
||||
start = self.pos
|
||||
while self.pos < self.end:
|
||||
if self.src[self.pos] not in quotables:
|
||||
break
|
||||
self.pos += 1
|
||||
return self.src[start:self.pos]
|
||||
def parse_data(self):
|
||||
self.pos += 1
|
||||
start = self.pos
|
||||
nibbles = 0
|
||||
while self.pos < self.end:
|
||||
if self.src[self.pos].isxdigit:
|
||||
nibbles += 1
|
||||
self.pos += 1
|
||||
continue
|
||||
if self.src[self.pos] == '>':
|
||||
if nibbles & 1:
|
||||
self.error = "invalid data, missing nibble"
|
||||
return None
|
||||
s = self.src[start:self.pos]
|
||||
self.pos += 1
|
||||
return binascii.a2b_hex(s)
|
||||
self.error = "invalid character in data"
|
||||
return None
|
||||
self.error = "Reached end of string while parsing data"
|
||||
return None
|
||||
def parse(self):
|
||||
if not self.skip_space():
|
||||
return None
|
||||
if self.src[self.pos] == '{':
|
||||
item = {}
|
||||
self.pos += 1
|
||||
while self.skip_space() and self.src[self.pos] != '}':
|
||||
key = self.parse()
|
||||
if key == None:
|
||||
return None
|
||||
if type(key) != str:
|
||||
self.error = "Key is not a string"
|
||||
return None
|
||||
if not self.skip_space():
|
||||
return None
|
||||
if self.src[self.pos] != '=':
|
||||
self.error = "Unexpected character (expected '=')"
|
||||
return None
|
||||
self.pos += 1
|
||||
value = self.parse()
|
||||
if not value:
|
||||
return None
|
||||
if self.src[self.pos] == ';':
|
||||
self.pos += 1
|
||||
elif self.src[self.pos] != '}':
|
||||
self.error = "Unexpected character (wanted ';' or '}')"
|
||||
return None
|
||||
item[key] = value
|
||||
if self.pos >= self.end:
|
||||
self.error = "Unexpected end of string when parsing dictionary"
|
||||
return None
|
||||
self.pos += 1
|
||||
return item
|
||||
elif self.src[self.pos] == '(':
|
||||
item = []
|
||||
self.pos += 1
|
||||
while self.skip_space() and self.src[self.pos] != ')':
|
||||
value = self.parse()
|
||||
if value == None:
|
||||
return None
|
||||
if not self.skip_space():
|
||||
return None
|
||||
if self.src[self.pos] == ',':
|
||||
self.pos += 1
|
||||
elif self.src[self.pos] != ')':
|
||||
self.error = "Unexpected character (wanted ',' or ')')"
|
||||
return None
|
||||
item.append(value)
|
||||
self.pos += 1
|
||||
return item
|
||||
elif self.src[self.pos] == '<':
|
||||
return self.parse_data()
|
||||
elif self.src[self.pos] == '"':
|
||||
return self.parse_quoted_string()
|
||||
else:
|
||||
return self.parse_unquoted_string()
|
Loading…
Reference in a new issue