11from itertools import cycle
22from pathlib import Path
33
4+ from loguru import logger
5+
46
57class Eco2 :
68 header = (
@@ -11,12 +13,14 @@ class Eco2:
1113 (256 , 'Desc' ),
1214 (19 , 'Make time' ),
1315 (19 , 'Edit time' ),
14- (8 , 'unknown ' ),
16+ (8 , 'password ' ),
1517 )
1618 key = (172 , 41 , 85 , 66 )
1719 header_encoding = 'EUC-KR'
1820 value_encoding = 'UTF-8'
21+ header_ext = '.header'
1922 value_ext = '.xml'
23+ ds = '</DS>'
2024
2125 @classmethod
2226 def decrypt_bytes (cls , data : bytes ):
@@ -57,13 +61,11 @@ def _decode_header(cls, data: bytes):
5761 def _print_header_info (cls , header : bytes ):
5862 header_dict = cls ._decode_header (header )
5963
60- print ('Header info:' )
61-
6264 for key , value in header_dict .items ():
63- if key == 'unknown ' :
65+ if key == 'password ' :
6466 continue
6567
66- print ( f' { key :10s} : { value } ' )
68+ logger . info ( '[HEADER] { :10s}: {}' , key , value )
6769
6870 @classmethod
6971 def _write_value (cls , path : Path , value : str ):
@@ -75,78 +77,82 @@ def _read_value(cls, path: Path):
7577 return path .read_text (encoding = cls .value_encoding ).replace ('\n ' , '\r \n ' )
7678
7779 @classmethod
78- def _decrypt_eco2_data (cls , data : bytes ):
79- decrypted = cls .decrypt_bytes (data )
80+ def _decrypt (cls , data : bytes , decrypt : bool ):
81+ if decrypt :
82+ data = cls .decrypt_bytes (data )
83+
8084 hl = cls .header_length ()
85+ header_bytes = data [:hl ]
86+ value_bytes = data [hl :]
8187
82- header_bytes = decrypted [:hl ]
83- value_bytes = decrypted [hl :]
84- value = value_bytes .decode ()
88+ try :
89+ value = value_bytes .decode (cls .value_encoding )
90+ except ValueError :
91+ # 케이스 설정 부분 (<DS>...</DS>)만 추출하고
92+ # 결과부 (<DSR>...</DSR>)은 버림
93+ logger .debug ('ECO2 파일의 결과부 (DSR)를 제외합니다.' )
94+ value = value_bytes .decode (cls .value_encoding , 'replace' )
95+
96+ if cls .ds not in value :
97+ raise ValueError ('인코딩 에러' )
98+
99+ value = value [:(value .find (cls .ds ) + len (cls .ds ))]
85100
86101 return header_bytes , value
87102
88103 @classmethod
89- def decrypt (cls , path , save_dir = None , header_name = None , value_name = None ):
104+ def decrypt (cls , path , header_path = None , value_path = None ):
90105 path = Path (path )
91- save_dir = path .parent if save_dir is None else Path (save_dir )
92- if not save_dir .exists ():
93- raise FileNotFoundError (save_dir )
94106
95- if header_name is None :
96- header_name = 'header'
97- if value_name is None :
98- value_name = path .stem
107+ if header_path is None :
108+ header_path = path .with_suffix (cls .header_ext )
109+ else :
110+ header_path = Path (header_path )
111+
112+ if value_path is None :
113+ value_path = path .with_suffix (cls .value_ext )
114+ else :
115+ value_path = Path (value_path )
99116
100- data = path .read_bytes ()
101- bheader , value = cls ._decrypt_eco2_data (data )
117+ logger .info ('Input: {}' , path )
118+ logger .debug ('Header: {}' , header_path )
119+ logger .debug ('Value: {}' , value_path )
102120
103- cls ._print_header_info (bheader )
121+ data = path .read_bytes ()
122+ decrypt = (path .suffix == '.eco' )
123+ try :
124+ header , value = cls ._decrypt (data = data , decrypt = decrypt )
125+ except ValueError :
126+ header , value = cls ._decrypt (data = data , decrypt = (not decrypt ))
104127
105- header_path = save_dir .joinpath (header_name )
106- header_path .write_bytes (bheader )
128+ cls ._print_header_info (header )
107129
108- value_path = save_dir . joinpath ( value_name + cls . value_ext )
130+ header_path . write_bytes ( header )
109131 cls ._write_value (path = value_path , value = value )
110132
111133 @classmethod
112- def _encrypt (cls , header : bytes , value_path : str , save_path : Path ):
113- value = cls ._read_value (path = value_path )
114- bvalue = value .encode (cls .value_encoding )
115- encrypted = cls .encrypt_bytes (header + bvalue )
134+ def _encrypt (cls , header : bytes , value : bytes , save_path : Path ):
135+ encrypted = cls .encrypt_bytes (header + value )
116136 save_path .write_bytes (encrypted )
117137
118138 @classmethod
119139 def encrypt (cls , header_path , value_path , save_path = None ):
120- if save_path is None :
121- save_path = 'output.eco'
122-
123140 header_path = Path (header_path )
124141 value_path = Path (value_path )
125- save_path = Path (save_path )
126142
127- header = header_path .read_bytes ()
128- cls ._print_header_info (header )
143+ if save_path :
144+ save_path = Path (save_path )
145+ else :
146+ save_path = value_path .with_suffix ('.eco' )
129147
130- cls ._encrypt (header = header , value_path = value_path , save_path = save_path )
131-
132- @classmethod
133- def encrypt_dir (cls , header_path , value_path , save_dir = None ):
134- header_path = Path (header_path )
135- value_path = Path (value_path )
148+ logger .info ('Value: {}' , value_path )
149+ logger .info ('Header: {}' , header_path )
150+ logger .debug ('Output: {}' , save_path )
136151
137152 header = header_path .read_bytes ()
138153 cls ._print_header_info (header )
139154
140- save_dir = value_path if save_dir is None else Path (save_dir )
141- if not save_dir .is_dir ():
142- save_dir = save_dir .parent
143-
144- if value_path .is_dir ():
145- vps = value_path .glob (f'*{ cls .value_ext } ' )
146- else :
147- vps = [value_path ]
155+ value = cls ._read_value (path = value_path )
156+ value_bytes = value .encode (cls .value_encoding )
148157
149- for vp in vps :
150- cls ._encrypt (header = header ,
151- value_path = vp ,
152- save_path = save_dir .joinpath (f'{ vp .stem } .eco' ))
158+ cls ._encrypt (header = header , value = value_bytes , save_path = save_path )
0 commit comments