pycrate/pycrate_csn1/utils.py

180 lines
5.1 KiB
Python

# -*- coding: UTF-8 -*-
#/**
# * Software Name : pycrate
# * Version : 0.4
# *
# * Copyright 2017. Benoit Michau. ANSSI.
# *
# * This library is free software; you can redistribute it and/or
# * modify it under the terms of the GNU Lesser General Public
# * License as published by the Free Software Foundation; either
# * version 2.1 of the License, or (at your option) any later version.
# *
# * This library 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
# * Lesser General Public License for more details.
# *
# * You should have received a copy of the GNU Lesser General Public
# * License along with this library; if not, write to the Free Software
# * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
# * MA 02110-1301 USA
# *
# *--------------------------------------------------------
# * File Name : pycrate_csn1/utils.py
# * Created : 2017-06-12
# * Authors : Benoit Michau
# *--------------------------------------------------------
#*/
import re
from pycrate_core.elt import Element
from pycrate_core.utils import *
from pycrate_core.utils import TYPE_UINT as _TYPE_UINT
#------------------------------------------------------------------------------#
# CSN.1 errors
#------------------------------------------------------------------------------#
def csnlog(msg):
'''
customizable logging function for the whole csn1 part
'''
log(msg)
# generic CSN.1 error
class CSN1Err(PycrateErr):
pass
class CSN1InvalidValueErr(CSN1Err):
pass
class CSN1NoCharErr(CSN1Err):
pass
#------------------------------------------------------------------------------#
# text processing
#------------------------------------------------------------------------------#
def scan_for_comments(text=''):
"""
returns a list of 2-tuple (start offset, end offset) for each CSN.1 comment
found in text
"""
ret = []
cur = 0
next = text.find('--')
while next >= 0:
cur += next
# start of comment
start = cur
# move cursor forward to reach the end of comment
cur += 2
# exception for line full of ------------------ sh*t
#while text[cur:1+cur] == '-':
# cur += 1
while True:
# move 1 by 1 and find an end-of-comment or end-of-file
if text[cur:1+cur] == '\n' or cur >= len(text):
comment = False
ret.append((start, cur))
cur += 1
break
#elif text[cur:2+cur] == '--':
# comment = False
# cur += 2
# ret.append((start, cur))
# break
else:
cur += 1
# find the next comment
next = text[cur:].find('--')
return ret
def clean_text(text=''):
"""
processes text to:
remove CSN.1 comments
replace tab with space
remove duplicated spaces
"""
# remove comments
comments = scan_for_comments(text)
if comments:
# get the complementary text to comments, to get the text containing
# the actual definitions
start, defins = 0, []
for (so, eo) in comments:
defins.append( text[start:so] )
start = eo
defins.append( text[start:len(text)] )
text = ''.join(defins)
#
# replace tab and \xa0 with space
text = text.replace('\t', ' ').replace('\xa0', ' ')
# remove duplicated CR
text = re.sub('\n{2,}', '\n', text)
# remove duplicated spaces
text = re.sub(' {2,}', ' ', text)
#
return text
def pythonize_name(name=''):
"""
pythonize CSN.1 object name
"""
# remove any trailing special chars
name = re.sub('[-/\.\s]{1,}$', '', name)
# change space(s) and special character(s) to a single underscore
name = re.sub('[-/\.\s]{1,}', '_', name)
# do not let name starts with a numeric char
if name and name[0] in '0123456789':
name = '_' + name
return name.lower()
#------------------------------------------------------------------------------#
# CSN.1 tokens
#------------------------------------------------------------------------------#
_RE_NAME = '[0-9a-zA-Z_ \-/\.]{1,}'
_RE_VAL = 'val\s{0,}\(\s{0,}(%s)\s{0,}\)' % _RE_NAME
SYNT_RE_NAME = re.compile('<\s{0,}(%s)\s{0,}>' % _RE_NAME)
SYNT_RE_VALUE = re.compile('([01\s]{1,})|([LH\s]{1,})|(null)')
SYNT_RE_NOSTR = re.compile('=\s{0,}<\s{0,}no\s{1,}string\s{0,}>')
# {iteration / length} arithmetic expression
TOK_UINT = 1
TOK_REF = 2
TOK_ADD = 3
TOK_SUB = 4
TOK_MUL = 5
TOK_OPEN = 6
TOK_CLOS = 7
def arithm_get_expr(m):
return m.group()
#------------------------------------------------------------------------------#
# value conversion
#------------------------------------------------------------------------------#
CSN1T_UINT = _TYPE_UINT
CSN1T_BSTR = 20
def bitstr_to_uint(bitstr):
return int(bitstr, 2)
def uint_to_bitstr(uint, bl):
bs = bin(uint)[2:]
if len(bs) < bl:
return (bl-len(bs)) * '0' + bs
else:
return bs