This commit is contained in:
.[d]. 2022-02-21 16:49:47 -06:00
parent 64457efc5c
commit 7509104ca3
2 changed files with 251 additions and 129 deletions

View File

@ -33,13 +33,14 @@ MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMNs. -hMMMMMMMMMMMMMMMMMMMMMMMMM
MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMdyymMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
```
```
cp437 ansi parsing - this will be integrated into bots like krylon/maple/g1mp when finished.
dr1p4ns1 v1.2 - cp437 ansi parsing - this logic will be rolled into bots like krylon/maple/g1mp
```
## prerequisites
- `apt install python3`
## usage - main file
```
running 'python3 dr1p4ns1.py' will batch process all the {ans,asc} files in the ansiscii directory
running 'python3 dr1p4ns1.py /path/to/ansi/files' will load all the .ans files in that directory
```
## test data and debugging
- running `python3 test.py` will present table data and create an ansi file for testing
@ -47,18 +48,11 @@ running 'python3 dr1p4ns1.py' will batch process all the {ans,asc} files in the
```d=dr1p4ns1(ansifile=_FILE_,width=80,debug=False)```
## files overview
```
/access.log - after usage the files laded or with error are logged into this file
/dr1p4ns1.py - main file, reads 'work.ans' and attempts to parse and display
/ansiscii/ - storing the ansi and ascii graphics in this subdirectory while testing
/test.py - used to generate test ansi file and presents table data
/test.ans - thie file is created after running test.py to contain controlled test data
/ansiscii/ - storing the ansi and ascii graphics in this subdirectory while testing
/ansiscii/work.ans - this ansi file is loaded by 'dr1p4ns1.py', this is the logic testing
/ansiscii/work.asc - escape codes/colors stripped in text for test referencing
```
## main files of interest
- dr1p4ns1.py
- work.ans
- work.asc
- test.py
- test.ans
```

View File

@ -2,7 +2,7 @@
#################################################################################################### #######################
from glob import glob
from time import sleep
import os
import sys,tty,os,termios
"""MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM #######################
MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMh+MMMMMMMMMMMMMMhsMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM #######################
MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMm/ oMMMMMMMMMMMMMMm +NMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM #######################
@ -81,7 +81,7 @@ class dr1p4ns1:
'm': 'color',
'R': 'report_cursor_position'}
############################################################################################################ LOOKUP TABLE
asc_table="""
asc_table="""\
ⁿΘΓΣαστΩδΦεµ÷ óúу\
ßφ·±¬¼í½\
\
@ -90,10 +90,24 @@ class dr1p4ns1:
for r in (('\n',''),(' ','')):
asc_table=asc_table.replace(*r)
############################################################################################################ LOOKUP TABLE
asc_table_full="""\
\x00§\
\_!"#$%&\'()*+,-./0123456789:;<=>\
?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^\
_`abcdefghijklmnopqrstuvwxyz{|}~\
ÇüéâäàåçêëèïîìÄÅÉæÆôöòûùÿÖÜ¢£¥\
ƒáíóúñѪº¿¬½¼¡«»\
\
ɑϐᴦᴨơµᴛɸϴΩẟ±÷°·ⁿ²\
ÿ"""
##################################################################################################### ASCII TABLE CLEANUP
for r in ((' ',''),('\_',' ')):
asc_table_full=asc_table_full.replace(*r)
############################################################################################################ LOOKUP TABLE
asc2uni=dict(zip([i for i in range(128,256)],[ord(c) for c in asc_table]))
############################################################################################################ LOOKUP TABLE
asc2chr=dict(zip([i for i in range(128,256)],[c for c in asc_table]))
############################################################################################################ LOOKUP TABLE
############################################################################################################ LOOKUP TABLE
rgb2irc = { 52: '16', 94: '17', 100: '18', 58: '19',
22: '20', 29: '21', 23: '22', 24: '23',
17: '24', 54: '25', 53: '26', 89: '27',
@ -122,10 +136,12 @@ class dr1p4ns1:
self.height=height
self.filename=ansifile
self.openansi(ansifile)
self.openascii()
#self.openascii()
self.code='\x1b[0m'
self.cmps=[]
print("\x1bc\x1b[1;31m[ DR1P ]\x1b[0m\n")
self.op=[]
self.optype=[]
self.sauce_found=False
self.boot()
######################################################################################################### FILE OPERATIONS
def fifo(self,s):
@ -194,9 +210,6 @@ class dr1p4ns1:
print(f"{hex(16 * _)[2:].zfill(8)} {thehex[_]} {theasc[_]}")
############################################################################################################### DEBUGGING
def hexdump(self):
if self.DEBUG:
print("\n\x1b[1;31m[ HEXDUMP ]\x1b[0m\n")
self.printhex()
self.codes=[]
code_start=0
code_end=0
@ -216,25 +229,173 @@ class dr1p4ns1:
code_end=i+1
code=self.ansifile[code_start:code_end]
self.codes.append([code,code_start,code_end])
############################################################################################################### DEBUGGING
def codedump(self):
xpos_old=0
xpos_new=0
self.codes=[]
code_start=0
code_end=0
code_state=False
for i,_ in enumerate(self.ansifile):
if code_state==False:
if _ == '\x1b':
code_state=True
code_start=i
elif _ == '\x1a':
self.op.append(self.ansifile[code_end:i])
code=self.ansifile[i:]
self.codes.append([code,i,len(self.ansifile)])
if code[1:6].upper()=="SAUCE":
self.getsauce(code[1:])
else:
if 64 <= ord(_) <= 126:
try:
if _ in self.commands:
code_state=False
code_end=i+1
code=self.ansifile[code_start:code_end]
self.codes.append([code,code_start,code_end])
xpos_new=code_start
distance=xpos_new-xpos_old
if not distance == 0:
nonop=self.ansifile[xpos_old:xpos_old+distance]
self.op.append(nonop)
self.optype.append(1)
self.op.append(code)
xpos_old=code_end
if self.commands[_] == 'color':
self.optype.append(2)
elif self.commands[_] == 'forward':
self.optype.append(3)
else:
self.optype.append(0)
except Exception as e:
print(f'error: {e}')
if not self.sauce_found:
code=self.ansifile[i:]
#################################################################################################################### TOOL
def processdump(self):
offset=0
offsets=[]
processed=[]
uniqued=[]
uniques=[]
processing=''
for i,_optype in enumerate(self.optype):
if _optype==2:
processing+=self.op[i]
offset+=len(self.op[i])
elif _optype==3:
count=int(self.op[i].split('[')[1].split('C')[0])
processing+=' '*count
elif _optype==1:
processing+=self.op[i]
_bseq='\r\n'
_xpos=processing.find(_bseq)
distance=0
while not processing.find(_bseq) == -1:
_xpos=processing.find(_bseq)
if not _xpos == -1:
uniques.append(_bseq)
uniques.append(_xpos)
if len(self.stripcodes(processing[:_xpos])) >= 80: distance=80
gaps=self.width-len(self.stripcodes(processing)[distance:].split('\r\n')[0])
processing=processing.replace(_bseq,chr(32)*gaps,1)
if len(processing)-offset > self.width:
trailing_size=0
while len(processing)-offset > self.width:
deconcatenate=processing[0:self.width+offset]
if deconcatenate.endswith('m'):
if not deconcatenate.rfind('\x1b')==-1:
trailing_size=len(deconcatenate[deconcatenate.rfind('\x1b'):])
deconcatenate=deconcatenate[:deconcatenate.rfind('\x1b')]
processed.append(deconcatenate)
if len(uniques) < 2:
uniqued.append('')
else:
uniqued.append(uniques)
uniqued.append(uniques)
uniques=[]
offsets.append(offset)
processing=processing.replace(deconcatenate,'',1)
offset=0+trailing_size
if len(processing) > 0:
gaps=int(80-len(self.stripcodes(processing)))
processing+=chr(32)*gaps
processed.append(processing)
processed_colors=[]; last_colors=''; color_fg=''; color_bg=''; color_set='';
for y,__ in enumerate(processed):
code_start=0; code_end=0; code_state=False; codes=[];
for x,_ in enumerate(__):
if not code_state:
if _ =='\x1b':
code_start = x
code_state = True
else:
if _ in self.commands:
if self.commands[_] == 'color':
code_end = x+1
code_state = False
codes.append(__[code_start:code_end])
for code in codes:
for _ in code.replace('m','').split('[')[1].split(';'):
if 0 <= int(_) <= 9:
color_set=_
if 30 <= int(_) <= 39:
color_fg=_
if 40 <= int(_) <= 49:
color_bg=_
colors=f"{color_set}"
processed_colors.append(colors)
# last_processed_color_set=0
# for i,_ in enumerate(processed):
# line=''
# if last_processed_color_set:
# line+='\x1b[1m'
# if int(processed_colors[i]):
# line+=f'{_}\x1b[0m'
# else:
# line+=f'{_}'
# last_processed_color_set=int(processed_colors[i])
# for r in (('\x16',chr(9644)),('\x15','\u00A7')):
# line=line.replace(*r)
# print(line+f" - {str(i).zfill(3)}")
for _ in processed:
line=_
for r in (('\x16',chr(9644)),('\x15','\u00A7')):
line=line.replace(*r)
print(line)
#################################################################################################################### TOOL
def getsauce(self,sauce):
self.sauce=sauce
self.sauce_found=True
self.width=ord(self.sauce[96])
self.height=ord(self.sauce[98])
offset=len("SAUCE")
self.sauce_version=str(int(self.sauce[offset:offset+2].strip()))
offset+=2
self.sauce_title=self.sauce[offset:offset+35].strip()
offset+=35
self.sauce_title=self.sauce[offset:offset+20].strip()
offset+=20
self.sauce_group=self.sauce[offset:offset+20].strip()
offset+=20
self.sauce_date=self.sauce[offset:offset+8].strip()
offset+=8
# SAUCE_PASS='\x1b[1;31m[ SAUCE INFO FOUND ] - X: {} Y: {}\x1b[0m\n'
# SAUCE_FAIL='\x1b[1;31m[ NO SAUCE INFO FOUND ]\x1b[0m\n'
# if self.sauce_found==True:
# print(SAUCE_PASS.format(self.width,self.height))
# else:
# print(SAUCE_FAIL.format(self))
#################################################################################################################### TOOL
def findall(self,s,w):
return [i for i in range(len(s)) if s.startswith(w, i)]
#################################################################################################################### TOOL
def getsauce(self):
SPASS='\x1b[1;31m[ SAUCE INFO FOUND ] - X: {} Y: {} - FILE: {}\x1b[0m\n'
SFAIL='\x1b[1;31m[ NO SAUCE INFO FOUND ] - FILE: {}\x1b[0m\n'
try:
if self.ansifile[-129:][0] == '\x1a' \
and self.ansifile[-128:][:5] == 'SAUCE':
self.ansifile_xwidth=ord(self.ansifile[-128:][96])
self.ansifile_yheight=ord(self.ansifile[-128:][98])
self.width=self.ansifile_xwidth
self.height=self.ansifile_yheight
print(SPASS.format(self.width,self.height,self.filename))
else:
print(SFAIL.format(self.filename))
except:
print(SFAIL.format(self.filename))
############################################################################################################### DEBUGGING
def cmpans(self,s1,s2,n1=0,n2=0):
_s1=''; _s2=''; _sn1=''; _sn2=''
@ -300,104 +461,71 @@ class dr1p4ns1:
return {v: k for k, v in d.items()}
########################################################################################################## CLASS MAIN - 4
def boot(self):
self.getsauce()
self.hexdump()
op=[]
fb=self.ansifile
xnew=0
xold=0
for _ in self.codes:
xnew=_[1]
distance=xnew-xold
if not distance == 0:
gap=fb[xold:xold+distance]
op.append(gap)
op.append(_[0])
xold=_[2]
optype=[]
for i,_op in enumerate(op):
if _op.startswith('\x1b'):
if _op.endswith('m'):
optype.append(2)
elif _op.endswith('C'):
optype.append(3)
else:
optype.append(0)
elif _op.startswith('\x1a'):
optype.append(4)
if self.DEBUG:
print("\n\x1b[1;31m[ HEXDUMP ]\x1b[0m\n")
self.printhex()
self.codedump()
self.processdump()
#############################################################################################################################
def getkey():
old_settings = termios.tcgetattr(sys.stdin)
tty.setcbreak(sys.stdin.fileno())
try:
while True:
b = os.read(sys.stdin.fileno(), 3).decode()
if len(b) == 3:
k = ord(b[2])
else:
optype.append(1)
offset=0
offsets=[]
processed=[]
uniqued=[]
uniques=[]
processing=''
for i,_optype in enumerate(optype):
if _optype==2:
processing+=op[i]
offset+=len(op[i])
elif _optype==3:
count=int(op[i].split('[')[1].split('C')[0])
processing+=' '*count
elif _optype==1:
processing+=op[i]
_bseq='\r\n'
_xpos=processing.find(_bseq)
if not _xpos == -1:
uniques.append(_bseq)
uniques.append(_xpos)
processing=processing.replace(_bseq,'',1)
gaps=self.width-len(self.stripcodes(processing))
processing+=' '*int(gaps)
if len(processing)-offset > self.width:
while len(processing)-offset > self.width:
deconcatenate=processing[0:self.width+offset]
processed.append(deconcatenate)
if len(uniques) < 2:
uniqued.append('')
else:
uniqued.append(uniques)
uniqued.append(uniques)
uniques=[]
offsets.append(offset)
processing=processing.replace(deconcatenate,'',1)
offset=0
# if self.DEBUG:
# print("\n\x1b[1;31m[ COMPARE LINE AGAINST REFERENCE ]\x1b[0m\n")
# _r=self.reference.strip().splitlines()
# for i,_ in enumerate(processed):
# s1=_r[i]
# s2=_
# self.cmpans(s1=s1,s2=s2,n1=0,n2=self.width)
# if i >= 128:
# break
# for i,_ in enumerate(self.cmps):
# print(_+f' - {str(i).zfill(4)}')
# if self.DEBUG:
# print("\n \x1b[1;31m[ PROCESSED ANSI ]\x1b[0m\n")
for i,_ in enumerate(processed):
print(_)
k = ord(b)
key_mapping = {
27: 'esc',
67: 'right',
68: 'left',
113: 'q',
120: 'x'
}
return key_mapping.get(k, chr(k))
finally:
termios.tcsetattr(sys.stdin, termios.TCSADRAIN, old_settings)
################################################################################################################### ENTRY - 1
if __name__ == "__main__":
if len(sys.argv) > 1:
PATH=''
if sys.argv[1]=='.':
PATH=os.getcwd()
files=glob(PATH+"/*.ans")
files+=glob(PATH+"/*.ANS")
else:
files=glob(sys.argv[1]+"/*.ans")
files+=glob(sys.argv[1]+"/*.ANS")
else:
files=glob('ansiscii/*.ans')
files+=glob('ansiscii/*.ANS')
if len(files)==0:
print('ERROR: NO ANSI FILES IN THE PATH SPECIFIED',end='')
sys.exit(1)
index=0
d=dr1p4ns1(ansifile=files[index],width=80,debug=False)
try:
os.remove('access.log')
except:
pass
files=glob('ansiscii/*.ans')
files+=glob('ansiscii/*.ANS')
for _FILE_ in files:
print(f'\n[ LOADING FILE ] - {_FILE_}\n')
try:
d=dr1p4ns1(ansifile=_FILE_,width=80,debug=False)
f=open('access.log','a')
f.write(f'LOADED: {_FILE_}\n')
f.close()
except Exception as e:
print(f'[ ERROR WITH FILE: {_FILE_} ] - {e}')
f=open('access.log','a')
f.write(f'FAILED: {_FILE_} - {e}\n')
f.close()
del(d)
sleep(5)
while True:
B='\x1b[1;94m'; C='\x1b[1;94m'; S='\x1b[1;36m'; M='\x1b[1;92m'; E='\x1b[0m'
msg=f"{B}[ {C}DR1P {B}] {S}- {B}[ {C}q{S}: {M}quit{S}, {C}left{S}: {M}previous{S}, {C}right{S}: {M}next {B}] {S}- {C}filename{S}: {M}"
msg+=f"{d.filename}{E}"
print(msg)
k = getkey()
if k == 'left':
index-=1
if index < 0: index=len(files)-1
d=dr1p4ns1(ansifile=files[index],width=80,debug=False)
if k == 'right':
index+=1
if index >= len(files): index=0
d=dr1p4ns1(ansifile=files[index],width=80,debug=False)
if k == 'esc' or k == 'q' or k == 'x':
quit()
except (KeyboardInterrupt, SystemExit):
os.system('stty sane')
######################################################################################################################### EOF