티스토리 뷰
한글 테이블 레코드 분석
구분 |
2018(예상) |
2017 |
2016 |
2015 |
Orange 7.0 |
20 |
9 |
8 |
7 |
Orange Ade |
4 |
1 |
1 |
1 |
Trusted Orange |
4 |
1 |
1 |
1 |
총액 |
28 |
11 |
10 |
9 |
위와 같은 표가 한글파일로 생성을 했을때 만들어지는 본문의 문단레코드 바이너리는 아래와 같다.
42 00 60 01 문단 헤더
09 00 00 00 00 08 00 00 0E 00 00 00 01 00 00 00 01 00 00 00 00 00
43 04 20 01 문단의 텍스트
0B 00 20 6C 62 74 00 00 00 00 00 00 00 00 0B 00 0D 00
44 04 80 00 문단의 글자 모양
00 00 00 00 01 00 00 00
45 04 40 02 문단의 레이아웃
00 00 00 00 92 3B 00 00 76 1D 00 00 76 1D 00 00 0B 19 00 00 58 02 00 00 00 00 00 00 18 A6 00 00 00 00 06 00
47 04 C0 02 컨트롤 헤더
20 6C 62 74 11 23 2A 08 00 00 00 00 00 00 00 00 14 A6 00 00 40 1B 00 00 01 00 00 00 1B 01 1B 01 1B 01 1B 01 EB 0D F7 67 00 00 00 00
4D 08 00 02 표 개체
06 00 00 04 05 00 05 00 00 00 FE 01 FE 01 8D 00 8D 00 05 00 05 00 05 00 05 00 05 00 02 00 00 00
---------- 여기서부터는 각 셀의 텍스트 정보를 담는 문단 리스트 ( 셀의 갯수만큼 반복됨 ) ----------
48 08 E0 02 리스트 헤더
01 00 00 00 20 00 00 04 00 00 00 00 01 00 01 00 FC 22 00 00 38 07 00 00 FE 01 FE 01 8D 00 8D 00 02 00 FC 22 00 00 00 00 00 00 00 00 00 00
42 08 60 01
03 00 00 80 00 00 00 00 0F 00 00 00 01 00 00 00 01 00 00 00 00 00
43 0C 60 00
6C AD 84 BD 0D 00 44 0C 80 00 00 00 00 00 01 00 00 00
45 0C 40 02
00 00 00 00 00 00 00 00 E8 03 00 00 E8 03 00 00 52 03 00 00 58 02 00 00 00 00 00 00 00 1F 00 00 00 00 06 00
---------------------- 반복 ----------------------
표 개체를 알아보기전에 조금더 위의 바이너리 형태를 구조화 시켜보면
- HWPTAG_PARA_HEADER
- HWPTAG_PARA_TEXT
- HWPTAG_PARA_CHAR_SHAPE
- HWPTAG_PARA_LINE_SEG
- HWPTAG_CTRL_HEADER
- HWPTAG_TABLE
- HWPTAG_LIST_HEADER ( 셀의 수만큼 반복 )
- HWPTAG_PARA_HEADER
- HWPTAG_PARA_TEXT
- HWPTAG_PARA_CHAR_SHAPE
- HWPTAG_PARA_LINE_SEG
이번 포스팅에서 알아볼 내용은 표개체 레코드이다.
표개체 레코드는 4D 08 00 02의 바이너리 값을 갖는데
이중 4D는 TAG_ID 값, 02은 LEVEL, 00 02는 해당 레코드의 데이타 사이즈값이다.
이건 눈대중으로 대충 값을 본거이니 제대로 확인을 하고싶다면 bit단위로 끊어서 파싱하길 바란다.(지금은 눈 대중으로 바이트 단위로 파싱)
자료형 |
길이 |
설명 |
BYTE stream |
N |
개체 공통 속성 |
BYTE stream |
N2 |
표 개체 속성 |
BYTE stream |
N3 |
셀 리스트 셀 Size * 셀 개수 |
전체 길이 |
가변 |
N + N2 + N3 |
위의 표는 표 개체가 문단에 쓰여질때 갖는 형태이다.
N = HWPTAG_CTRL_HEADER
N2 = HWPTAG_TABLE
N3 = HWPTAG_LIST_HEADER
그러면 컨트롤 헤더부터 뜯어보도록 하자.
47 04 C0 02 컨트롤 헤더
20 6C 62 74 11 23 2A 08 00 00 00 00 00 00 00 00 14 A6 00 00 40 1B 00 00 01 00 00 00 1B 01 1B 01 1B 01 1B 01 EB 0D F7 67 00 00 00 00
HEADER
TAG_ID = 47
LEVEL = 2
SIZE = 2C(44)
DATA
20 6C 62 74
- 컨트롤 ID 'T', 'B', 'L', ' '의 값을 갖고 있다. (4 BYTE)
11 23 2A 08 00 00 00 00 00 00 00 00 14 A6 00 00 40 1B 00 00 01 00 00 00 1B 01 1B 01 1B 01 1B 01 EB 0D F7 67 00 00 00 00
- 개체 공통 속성 값이다.
한글 문서에 이 컨트롤 헤더의 용도는 Extended type 의 컨트롤 종류를 나타내는 식별기호 32비트 id가 사용된다고 나와있다.
컨트롤 코드가 큰 범주를 나타내는 식별기호라고 한다면 컨트롤 id는 세부 분류를 나타내는 식별 기호인 셈이다.
예를 들어 단 정의 컨트롤 id는 MAKE_4CHID('c', 'o',' l', 'd')와 같은 형식으로 정의된다.
자 이쯤되면 컨트롤 헤더가 어떠한 용도로 사용되는지 이해는 된거 같으니 다음 레코드인 표 개체(HWPTAG_TABLE) 레코드를 분석 해보자.
4D 08 00 02 표 개체
06 00 00 04 05 00 05 00 00 00 FE 01 FE 01 8D 00 8D 00 05 00 05 00 05 00 05 00 05 00 02 00 00 00
자료형 |
길이 |
설명 |
UINT32 |
2 |
속성 |
UINT16 |
2 |
줄의 갯수 |
UINT16 |
2 |
칸의 갯수 |
HWPUINT16 |
2 |
셀 스페이싱 |
BYTE stream |
8 |
안쪽 여백 정보 |
BYTE satream |
2*n |
Row |
UINT16 |
2 |
Border Fill ID |
UINT16 |
2 |
Valid Zone Info Size |
BYTE satream |
2 |
영역 속성 |
전체 길이 |
가변 |
22 + (2*row) + (10*zone) |
( 표 개체 속성 )
HEADER
TAG_ID = 4D
LEVEL = 3
SIZE = 20(32)
DATA
06 00 00 04 = 속성 값 (67108870)
05 00 = 줄의 갯수
05 00 = 칸의 갯수
00 00 = 셀스페이싱 0
FE 01 = 안쪽 여백 정보 왼쪽 510
FE 01 = 오른쪽 510
8D 00 = 위쪽 141
8D 00 = 아래쪽 141
05 00 = RowSize
05 00 = RowSize
05 00 = RowSize
05 00 = RowSize
05 00 = RowSize
02 00 = Border Fill (채우기 정보)
00 00 = ZoneInfo
HWPTAG_TABLE 레코드의 정보를 뜯어보면 해당 테이블에 대한 정보가 저장되어있는것을 확인 할 수 있다.
바이너리 값을 보았을때 위의 테이블 정보는 5행 5열의 테이블이며 표의 여백정보를 확인 할 수있다.
그렇다면 셀안에 들어가는 정보는 어디에 저장되는것일까?
위에 표에서도 설명되었지만 다음 레코드에서 셀의 정보가 저장된다.
48 08 E0 02 리스트 헤더
01 00 00 00 20 00 00 04 00 00 00 00 01 00 01 00 FC 22 00 00 38 07 00 00 FE 01 FE 01 8D 00 8D 00 02 00 FC 22 00 00 00 00 00 00 00 00 00 00
자료형 |
길이 |
설명 |
BYTE stream |
n |
문단 리스트 헤더 |
BYTE stream |
26 |
셀 속성 |
전체 길이 |
가변 |
26+n byte |
( 셀 리스트 )
자료형 |
길이 |
설명 |
|||
INT16 |
2 |
문단 수 |
|||
UINT32 | 4 | 속성 ( 자세한건 한글 도큐먼트 참조 ) |
|||
전체 길이 |
6 |
|
( 문단 리스트 헤더 )
자료형 |
길이 |
설명 |
UINT16 |
2 |
셀 주소 (COL) |
UINT16 |
2 |
셀 주소 (ROW) |
UINT16 |
2 |
열의 병합 개수 |
UINT16 |
2 |
행의 병합 개수 |
HWPUINT |
4 |
셀의 폭 |
HWPUINT |
4 |
셀의 높이 |
HWPUINT16 array[4] |
2*4 |
셀4방향 여백 |
UINT16 |
2 |
테두리/배경 아이디 |
전체 길이 |
26 |
|
( 셀 속성 )
HEADER
TAG_ID = 48
LEVEL = 3
SIZE = 40(64)
DATA
01 00 00 00 = 문단 수
20 00 00 04 = 속성
00 00 = 셀 주소 열
00 00 = 셀 주소 행
01 00 = 열의 병합 개수
01 00 = 행의 병합 개수
FC 22 00 00 = 셀의 폭 WIDTH
38 07 00 00 = 셀의 높이 HEIGHT
FE 01 = 왼쪽 마진
FE 01 = 오른쪽 마진
8D 00 = 위쪽 마진
8D 00 = 아래쪽 마진
02 00 = 채우기 아이디
FC 22 = 필드 이름
00 00 00 00 00 00 00 00 00 00 = 알려지지 않은 바이트
위와 같이 분석이 되는데 셋팅해야할 값이 너무나 많다.
0행 0열의 셀의 정보를 뜯어본 값이다.
이후로는 문단의 정보가 들어가게 되는데 해당 셀의 텍스트 문단에 대한 정보이다.
42 08 60 01
03 00 00 80 00 00 00 00 0F 00 00 00 01 00 00 00 01 00 00 00 00 00
43 0C 60 00
6C AD 84 BD 0D 00 44 0C 80 00 00 00 00 00 01 00 00 00
45 0C 40 02
00 00 00 00 00 00 00 00 E8 03 00 00 E8 03 00 00 52 03 00 00 58 02 00 00 00 00 00 00 00 1F 00 00 00 00 06 00
위의 레코드들에 대한 설명은 생략하겠다.
이렇게 셀리스트가 다 끝날때까지 반복이 된다.
'JAVA' 카테고리의 다른 글
IntelliJ 스프링부트 그래들로 생성하기 (0) | 2018.12.31 |
---|---|
[JAVA] JDBC를 이용한 DB 연결하기 (MYSQL) (0) | 2018.08.13 |
[JAVA] Hwp 한글 문서 Section Stream 분석하기 (빈문서 분석) (1) | 2018.04.01 |
[JAVA] hwp 한글 문서 내부 구조 알아보기 (5) | 2018.03.11 |
[JAVA] hwp 한글 파일 파싱하기 (준비단계) (0) | 2018.02.22 |
- Total
- Today
- Yesterday
- JNI 시그니처
- 위대한 쇼맨 ost
- 폴더선택다이얼로그
- 대항해시대 넷마블 런처
- 데스큐어
- 대항해시대
- 대항해시대 다클
- JNI SIGNITURE
- 빈파일
- 구글 클라우드 플랫폼
- 정보처리기사 실기 후기
- React.js
- Linux
- EACCES: permission denied
- 합격 후기
- 위대한 쇼맨
- lxd
- JNI
- 대항해시대 런처
- 정보처리기사 2018 2회
- 대항해시대 로그인
- HTTPie
- vite.js
- 다클 빈
- 위대한 쇼맨 후기
- JNI INVOKE
- 대항해시대 다음 런처
- 다클 코드
- 정처기 실기
- OSI 7Layer
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | |||
5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 |