한글 테이블 레코드 분석




한글 문서에 생성되는 표를 바이너리값으로 파싱하는걸 포스팅해보려고한다.
기본적으로 압축이 풀린 Section Stream을 바이너리 뷰어로 읽었다는 가정하에 시작한다.


구분 

2018(예상) 

2017 

2016 

2015 

Orange 7.0 

20 

Orange Ade 

Trusted Orange 

총액 

28 

11 

10 


위와 같은 표가 한글파일로 생성을 했을때 만들어지는 본문의 문단레코드 바이너리는 아래와 같다.






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 


---------------------- 반복 ----------------------






표 개체를 알아보기전에 조금더 위의 바이너리 형태를 구조화 시켜보면

  1. HWPTAG_PARA_HEADER
  2. HWPTAG_PARA_TEXT
  3. HWPTAG_PARA_CHAR_SHAPE
  4. HWPTAG_PARA_LINE_SEG
  5. HWPTAG_CTRL_HEADER
  6. HWPTAG_TABLE
  7. HWPTAG_LIST_HEADER         ( 셀의 수만큼 반복 )
    1. HWPTAG_PARA_HEADER
    2. HWPTAG_PARA_TEXT
    3. HWPTAG_PARA_CHAR_SHAPE
    4. 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 

문단 리스트 헤더 

BYTE stream

26 

셀 속성 

전체 길이

가변 

26+n byte 

( 셀 리스트 )




 자료형

길이 

설명 

 INT16

문단 수 

 UINT32

속성 ( 자세한건 한글 도큐먼트 참조 )

 전체 길이

 

( 문단 리스트 헤더 )

 



자료형 

길이 

설명 

 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 


위의 레코드들에 대한 설명은 생략하겠다.

이렇게 셀리스트가 다 끝날때까지 반복이 된다.




Posted by 루우지