Skip to content

Commit 141f92d

Browse files
committed
First commit
1 parent 5159df0 commit 141f92d

7 files changed

Lines changed: 446 additions & 0 deletions

File tree

.gitignore

Lines changed: 143 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,143 @@
1+
# Byte-compiled / optimized / DLL files
2+
__pycache__/
3+
*.py[cod]
4+
*$py.class
5+
6+
# C extensions
7+
*.so
8+
9+
# Distribution / packaging
10+
.Python
11+
build/
12+
develop-eggs/
13+
dist/
14+
downloads/
15+
eggs/
16+
.eggs/
17+
lib/
18+
lib64/
19+
parts/
20+
sdist/
21+
var/
22+
wheels/
23+
share/python-wheels/
24+
*.egg-info/
25+
.installed.cfg
26+
*.egg
27+
MANIFEST
28+
29+
# PyInstaller
30+
# Usually these files are written by a python script from a template
31+
# before PyInstaller builds the exe, so as to inject date/other infos into it.
32+
*.manifest
33+
*.spec
34+
35+
# Installer logs
36+
pip-log.txt
37+
pip-delete-this-directory.txt
38+
39+
# Unit test / coverage reports
40+
htmlcov/
41+
.tox/
42+
.nox/
43+
.coverage
44+
.coverage.*
45+
.cache
46+
nosetests.xml
47+
coverage.xml
48+
*.cover
49+
*.py,cover
50+
.hypothesis/
51+
.pytest_cache/
52+
cover/
53+
54+
# Translations
55+
*.mo
56+
*.pot
57+
58+
# Django stuff:
59+
*.log
60+
local_settings.py
61+
db.sqlite3
62+
db.sqlite3-journal
63+
64+
# Flask stuff:
65+
instance/
66+
.webassets-cache
67+
68+
# Scrapy stuff:
69+
.scrapy
70+
71+
# Sphinx documentation
72+
docs/_build/
73+
74+
# PyBuilder
75+
.pybuilder/
76+
target/
77+
78+
# Jupyter Notebook
79+
.ipynb_checkpoints
80+
81+
# IPython
82+
profile_default/
83+
ipython_config.py
84+
85+
# pyenv
86+
# For a library or package, you might want to ignore these files since the code is
87+
# intended to run in multiple environments; otherwise, check them in:
88+
# .python-version
89+
90+
# pipenv
91+
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
92+
# However, in case of collaboration, if having platform-specific dependencies or dependencies
93+
# having no cross-platform support, pipenv may install dependencies that don't work, or not
94+
# install all needed dependencies.
95+
#Pipfile.lock
96+
97+
# PEP 582; used by e.g. github.com/David-OConnor/pyflow
98+
__pypackages__/
99+
100+
# Celery stuff
101+
celerybeat-schedule
102+
celerybeat.pid
103+
104+
# SageMath parsed files
105+
*.sage.py
106+
107+
# Environments
108+
.env
109+
.venv
110+
env/
111+
venv/
112+
ENV/
113+
env.bak/
114+
venv.bak/
115+
116+
# Spyder project settings
117+
.spyderproject
118+
.spyproject
119+
120+
# Rope project settings
121+
.ropeproject
122+
123+
# mkdocs documentation
124+
/site
125+
126+
# mypy
127+
.mypy_cache/
128+
.dmypy.json
129+
dmypy.json
130+
131+
# Pyre type checker
132+
.pyre/
133+
134+
# pytype static type analyzer
135+
.pytype/
136+
137+
# Cython debug symbols
138+
cython_debug/
139+
140+
# project
141+
tests/data/
142+
.vscode/
143+
*.cs

ECO2/cli.py

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
import click
2+
3+
from eco2 import Eco2
4+
5+
6+
@click.group()
7+
def cli():
8+
pass
9+
10+
11+
@cli.command()
12+
@click.argument('eco')
13+
@click.option('-s',
14+
'--savedir',
15+
help=('해석한 header와 value 파일의 저장 경로. '
16+
'미설정 시 eco 파일과 동일 경로에 저장.'))
17+
@click.option('-h',
18+
'--header',
19+
default='header',
20+
help='header 파일 이름. 미설정 시 `header`로 지정.')
21+
@click.option('-v',
22+
'--value',
23+
help=('value 파일 이름. '
24+
'미설정 시 eco 파일과 동일 이름으로 저장.'))
25+
def decrypt(eco, savedir, header, value):
26+
"""
27+
\b
28+
eco 파일을 해석해서 header와 value 파일로 나눠 저장.
29+
header: eco의 버전, 생성 날짜 등 정보를 담은 바이너리 파일.
30+
value: 해석 설정 정보를 담은 xml 파일.
31+
32+
\b
33+
Argument:
34+
ECO: 해석할 eco 파일 경로
35+
"""
36+
Eco2.decrypt(path=eco,
37+
save_dir=savedir,
38+
header_name=header,
39+
value_name=value)
40+
41+
42+
@cli.command()
43+
@click.argument('header')
44+
@click.argument('value')
45+
@click.option('-s',
46+
'--savedir',
47+
help=('해석한 header와 value 파일의 저장 경로. '
48+
'미설정 시 eco 파일과 동일 경로에 저장.'))
49+
def encrypt(header, value, savedir):
50+
"""
51+
header와 value를 암호화해서 eco 파일로 변환
52+
53+
\b
54+
Arguments:
55+
HEADER: header 파일 경로.
56+
VALUE : value 파일 경로. 폴더 경로를 지정하면 해당 폴더에 존재하는 모든 .xml 파일을 변환.
57+
"""
58+
Eco2.encrypt_dir(header_path=header, value_path=value, save_dir=savedir)
59+
60+
61+
if __name__ == '__main__':
62+
cli()

ECO2/cx_setup.py

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
from cx_Freeze import Executable
2+
from cx_Freeze import setup
3+
4+
if __name__ == '__main__':
5+
options = {
6+
'build_exe': {
7+
'optimize':
8+
1,
9+
'excludes': [
10+
'email', 'html', 'http', 'logging', 'tkinter', 'unittest'
11+
]
12+
}
13+
}
14+
15+
executables = [
16+
Executable(script=r'ECO2\cli.py', target_name='ECO2'),
17+
]
18+
19+
setup(name='ECO2',
20+
version='0.1',
21+
description='ECO2',
22+
options=options,
23+
executables=executables)

ECO2/eco2.py

Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
from itertools import cycle
2+
from pathlib import Path
3+
from typing import Union
4+
5+
6+
class Eco2:
7+
header = (
8+
(2, 'SF_type'),
9+
(10, 'UI_version'),
10+
(10, 'LG_version'),
11+
(100, 'name'),
12+
(256, 'desc'),
13+
(19, 'make_time'),
14+
(19, 'edit_time'),
15+
(8, 'unknown'),
16+
)
17+
key = (172, 41, 85, 66)
18+
encoding = 'UTF-8'
19+
value_ext = '.xml'
20+
21+
@classmethod
22+
def decrypt_bytes(cls, data: bytes):
23+
return bytes((d ^ k for d, k in zip(data, cycle(cls.key))))
24+
25+
@classmethod
26+
def encrypt_bytes(cls, data: bytes):
27+
return cls.decrypt_bytes(data)
28+
29+
@classmethod
30+
def header_length(cls):
31+
return sum([x[0] for x in cls.header])
32+
33+
@staticmethod
34+
def _decode_chunk(b: bytes, length: int):
35+
data = b[:length]
36+
bnext = b[length:]
37+
38+
return data, bnext
39+
40+
@classmethod
41+
def _decode_header(cls, data: bytes):
42+
header = {}
43+
b = data
44+
for length, name in cls.header:
45+
value, b = cls._decode_chunk(b=b, length=length)
46+
header[name] = value
47+
48+
return header
49+
50+
@classmethod
51+
def _decrypt_eco2_data(cls, data: bytes):
52+
decrypted = cls.decrypt_bytes(data)
53+
hl = cls.header_length()
54+
55+
header_bytes = decrypted[:hl]
56+
value_bytes = decrypted[hl:]
57+
value = value_bytes.decode()
58+
59+
return header_bytes, value
60+
61+
@classmethod
62+
def _write_value(cls, path: Path, value: str):
63+
path.write_text(value.replace('\r\n', '\n'), encoding=cls.encoding)
64+
65+
@classmethod
66+
def _read_value(cls, path: Path):
67+
return path.read_text(encoding=cls.encoding).replace('\n', '\r\n')
68+
69+
@classmethod
70+
def decrypt(cls,
71+
path: Union[str, Path],
72+
save_dir=None,
73+
header_name=None,
74+
value_name=None):
75+
path = Path(path)
76+
save_dir = path.parent if save_dir is None else Path(save_dir)
77+
if not save_dir.exists():
78+
raise FileNotFoundError(save_dir)
79+
80+
if header_name is None:
81+
header_name = 'header'
82+
if value_name is None:
83+
value_name = path.stem
84+
85+
data = path.read_bytes()
86+
bheader, value = cls._decrypt_eco2_data(data)
87+
88+
header_path = save_dir.joinpath(header_name)
89+
header_path.write_bytes(bheader)
90+
91+
value_path = save_dir.joinpath(value_name + cls.value_ext)
92+
cls._write_value(path=value_path, value=value)
93+
94+
@classmethod
95+
def encrypt(cls, header_path, value_path, save_path=None):
96+
if save_path is None:
97+
save_path = 'output.eco'
98+
99+
header_path = Path(header_path)
100+
value_path = Path(value_path)
101+
save_path = Path(save_path)
102+
103+
bheader = header_path.read_bytes()
104+
105+
value = cls._read_value(path=value_path)
106+
bvalue = value.encode()
107+
108+
data = bheader + bvalue
109+
encrypted = cls.encrypt_bytes(data)
110+
111+
save_path.write_bytes(encrypted)
112+
113+
@classmethod
114+
def encrypt_dir(cls, header_path, value_path, save_dir=None):
115+
header_path = Path(header_path)
116+
value_path = Path(value_path)
117+
118+
save_dir = value_path if save_dir is None else Path(save_dir)
119+
if not save_dir.is_dir():
120+
save_dir = save_dir.parent
121+
122+
if value_path.is_dir():
123+
vps = value_path.glob(f'*{cls.value_ext}')
124+
else:
125+
vps = [value_path]
126+
127+
for vp in vps:
128+
cls.encrypt(header_path=header_path,
129+
value_path=vp,
130+
save_path=save_dir.joinpath(f'{vp.stem}.eco'))

README.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# ECO2
2+
3+
효율등급인증 평가프로그램 ECO2의 저장 파일 (`.eco`) 해석

0 commit comments

Comments
 (0)