안녕하세요.



공기어때팀입니다. 

5월 1일에 공기어때 버전업이 있었습니다. 

현재 최신 버전은 1.0.3 v 입니다.

꼭 마켓에서 업데이트를 받아주세요!




업데이트 내용


1) GPS 탐색 기능 개선 

- 기존 GPS 탐색 소스를 새롭게 작성하여 GPS탐색 소요 시간을 단축시켰습니다.

- GPS 탐색 시간 감소로 로딩시간이 줄어들었으니 좀더 쾌적하게 이용하실수 있습니다.


2) Update 오류 수정

- 기존 마켓 버전 체크하는 방식이 변경되어 실행시 업데이트 다이얼로그가 출력되는 이슈가 있었습니다.

- 이젠 업데이트 체크 방식을 바꿔 해당 버그를 수정했습니다.



이상 업데이트 내용에 대한 소개를 마치겠습니다.

미세먼지가 심한 요즘 외출시 꼭 마스크를 착용하셔서 건강 챙기시길 바랍니다.

감사합니다~!


OS 재설치후 윈도우즈 업데이트를 받을려는데 이게 진행이 안되는 현상을 겪었습니다.


재부팅도 해보고 이것저것 해봤는데도 안되기에 구글에 검색해보니 윈도우즈 업데이트 문제 해결사를 다운로드 받으라고 하더군요.


해결사가 진단한 내용은 '잠재적인 Windows 업데이트 데이터베이스 오류가 검색됨' 이였습니다.



1. 업데이트  데이터베이스 오류 해결



그래서 직접 고쳐보자 해서 구글링해보니 MSDN에 이렇게 답변이 되어있네요.


1. CMD 우클릭 관리자 권환으로 실행


2. DISM.exe /Online /Cleanuup-image /Scanhealth 입력


3. 실행 결과 확인


4. 재부팅


사실 저는 이렇게해서도 자동으로 윈도우즈가 업데이트를 하지 못했습니다.



2. 클린 부팅


그래서 또 구글링을 했는데 그 방법은 클린 부팅을 함으로써 외부프로그램이 윈도우즈 업데이트에 간섭을 못하도록 함이였는데요.


1. msconfig 실행


2. 서비스 -> 모든  microsoft 서비스 숨기기 -> 모두 사용안함


3. 시작프로그램 -> 작업 관리자 열기 -> 시작프로그램 - >  의심되는 프로그램을 사용안함시키거나 모두 사용안함시키세요

(저같은경우 안랩의 보안프로그램이 문제였던거같습니다.)


4. 재시작 후 윈도우즈 업데이트 확인




저같은 경우에는 백신프로그램이 영향을 주고 있엇던거 같습니다.


실행중인 백신프로그램을 전부 사용안함시킨 다음 클린부팅 시키니 정상적으로 업데이트가 되네요 ^^!



한글 테이블 레코드 분석




한글 문서에 생성되는 표를 바이너리값으로 파싱하는걸 포스팅해보려고한다.
기본적으로 압축이 풀린 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 


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

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




섹션 스트림 분석하기 빈문서 분석




섹션 스트림은 바디스토리지 내에 존재하는 스트림이다.

기본적으로 레코드 형식이며, 압축이 되기도 한다.

이번 포스팅에서는 빈 도큐먼트를 파싱하는 과정을 담아보려고 한다.


섹션 스트림을 분석하기 위해서는 한글과 컴퓨터에서 제공하는 도큐먼트를 먼저 정독해야한다.


TagID 

SIZE 

LEVEL 

설명

 HWPTAG_PARA_HEADER

22 

 0 

문단 헤더 

 HWPTAG_PARA_TEXT

가변

 1 

text 정보

 HWPTAG_PARA_CHAR_SHAPE

가변

 1 

글자 모양 

 HWPTAG_PARA_LINE_SEG

가변

1

글자 레이아웃 

 HWPTAG_PARA_RANGE_TAG

가변

1

영역 태그 

 HWPTAG_CTRL_HEADER

 1 

 컨트롤 헤더

 HWPTAG_LIST_HEADER

 2 

 문단 리스트 헤더

 HWPTAG_PAGE_DEF 

40 

 2 

 용지 설정

 HWPTAG_FOOTNOTE_SHAPE

30 

 2 

각주/미주 모양 

 HWPTAG_PAGE_BORDER_FILL 

14 

 2 

쪽 테두리/배경 

 HWPTAG_SHAPE_COMPONENT 

 2 

개체 

 HWPTAG_TABLE 

가변

 2 

 표 개체

 ... (기타 그리기 개채)

가변

 

 

 HWPTAG_CTRL_DATA

가변

3

 

 ... (기타 레코드) 

 

 

 

(필자는 초반에 나오는 이 표를 보지 못해서 각각의 레코드들을 전부 읽어 레벨을 기록했다. -_-;)



위의 표는 Section Stream에서 본문 정보를 담고있는 레코드들을 추려서 표로 정리해본것이다.


포스팅을 하기 앞서 문단이란 무엇인지 알고 가야한다.

한글문서에서의 문단은 '엔터'로 기준을 나눌 수 있다.


첫번째줄 두번째줄이 엔터로 나뉘어서 작성이 되면 2개의 문단으로 인식한다.

한줄에 엔터없이 2번째줄까지 작성되어 내려가게 되면 그건 1개의 문단이다.


섹션의 첫 문단에는 구역 정의 레코드들이 들어가기 때문에 중간 중간의 문단 레코드들보다 필요한 사이즈가 크다. 

첫번째 문단 정보에는 ~ 레코드들이 들어간다.

그다음 문단 부터는 헤더, 텍스트, 글자모양, 글자 위치 정보의 레코드들이 하나의 문단 정보를 이루어 작성된다.



첫번째 문단

 

 두번재 문단

 

 3번째 문단

 

 header + text + shape + line + range_sahpe+ ctrl header + footnote+ border fill + etc

 

 HEADER

 TEXT

 CHAR_SHAPE

 LINE_SEG

 

 HEADER

 TEXT

 CHAR_SHAPE

 LINE_SEG

 

 +

 +

 

 

 

 

 

 

 


위에 표는 스트림에 작성되는 텍스트 헤더들을 표로 정리해본것이다.

첫번재 문단 정보에는 기본적인 텍스트( 테이블도 될수 있음) 정보들이 들어가며 추가적으로 각주/미주 정보라던지, 용지 설정 정보, 각주/미주 모양의 정보와 같은 부수적인 레코드들이 같이 붙는 형태이다.

두번째 문단 부터는 해당 문단에 작성된 텍스트 정보만 작성이 된다. 비교적 첫번째 문단에 비해 담기는 정보가 작다.






이번 포스팅에서는 한글문서가 어떤형식으로 파일구조를 갖고 있고 

어떻게 바이트단위로 박혀있는지 확인 해보는 시간을 갖기 위해 글을 써보았다.



한글 문서는 Compound File (OLE2) 구조를 갖는다.

스토리지와 스트림 형태를 띄고 있는데, 스토리지는 폴더, 스트림은 파일이라고 이해하면 쉽다.

Root 밑에는 여러개의 스토리지와 스트림이 존재한다. 

아래의 표는 hwp 파일이 갖고있는 구조를 표로 표현한것이다.



 

 이름

길이 

레코드 

압축 / 압축화 

 파일 인식 정보

FileHeader (Stream)

고정 

 

 

 문서 정보

DocInfo  (Stream)

고정 

true 

true 

본문 

BodyText (Storage)

- Section0   (Stream)

가변 

true 

true 

문서요약 

\005HwpSummaryInformation  (Stream) 

고정 


 

바이너리 데이타 

BinData  (Storage)

- BinaryData0   (Stream)

- ...   (Stream)

가변 

 

true 

미리보기 텍스트 

PrvText  (Stream)

고정 

 

 

미리보기 이미지 

PrvImage  (Stream)

가변 

 

 

문서 옵션 

DocOptioin  (Storage)

- _LnkDoc  (Stream)

- DrmLicense  (Stream)

- ...

가변 

 

 

스트립트 

Script  (Storage)

- DefaultScript  (Stream)

- JScriptVersion  (Stream)

- ...

가변 

 

 

 XML 템플릿

XML Template (Storage)

- Schema   (Stream)

- Instance  (Stream)

- ...

가변 

 

 

문서 이력 관리 

DocHistroy  (Storage)

- VersionLog0  (Stream)

- VersionLog1  (Stream)

- ...

가변 

true 

 

true 



(ssviewer로 본 한글파일 내부의 구조)

각 스토리지와 스트림의 정보는 한글과 컴퓨터에서 제공하는 문서를 참고하면 이해하기 쉽다.



간단하게 파일 인식 정보를 갖고있는 FileHeaer 스트림을 뜯어보면 아래와 같은 구조를 갖고 있다.




FileHeaer은 256바이트의 고정된 길이를 갖는 스트림이다.

사진에 첨부한 FileHeader 스트림의 Binary값을 확인해보면 

초기 32바이트에는 한글 문서 형식을 알리는 시그니처 문구가 박혀있는것을 확인할 수 있다.


그다음 4바이트 크기로 한글 문서의 버전을 확인 할 수 있다. 

바이너리 뷰어로 해당 스트림을 열어보면 5.0.3.0 버전이 찍힌걸 볼 수있다.


그다음 4바이트는 파일헤더의 속성을 갖는 비트들이다. 0비트부터 11비트는 각각의 문서 속성 정보를 갖고있다.

그 이후 나머지 216바이트는 예약 바이트들로 0의 값으로 초기화되어 있는 형태를 확인할 수 있다.




한글 문서중 제일 파악하기가 쉬운게 파일헤더 스트림이다.

고정 길이를 갖고 있기에 256바이트 중에 

처음 32바이트는 시그니처, 

그다음 4바이트는 파일의 버전, 

그다음 4비트는 속성 정보,

나머지 216바이트는 예약비트로 파싱할때 비교적 수월하다.

암호화도 안되있기 때문에 그냥 가져와 바이트단위로 짜르면 한글문서의 정보를 가져올 수 있다.





다른 스트림도 이러면 좋겠지만 가변적인 길이를 갖는 스트림도 많고 압축/암호화도 걸린게 많기 때문에 

다른 스트림을 파싱하거나 렌더링할때에는 쉽게 되지는 않을꺼같다.




몇몇 스트림들은 레코드형식(헤더와 데이터의 결합)으로 구성되어있기도 하며, 

MSDN의 프로퍼티 셋 형식을 취한 스트림도 있다.




대표적인 예로 \005HwpSummaryInformation 스트림이 MSDN의 프로퍼티셋 형식을 갖고 있다.

Summary Information에 대한 자세한 설명은 MSDN을 참고

The Summary Information Property Set

The DocumentSummaryInformation and UserDefined Property Set

(한글 공식 문서의 설명)


SumamryInformation 은 MSDN의 프로퍼티셋 형식을 따른다.

해당 정보는 아래의 URL에 설명되어있다.


https://msdn.microsoft.com/ko-kr/library/windows/desktop/aa380376%28v=vs.85%29.aspx?f=255&MSPPError=-2147217396


HwpSummaryInformation 정보를 가져오기 위해서는 바이트 단위로 짜르는것 보다는

Apache POI API에서 제공하는 프로퍼티 ID단위로 값을 가져오면 된다.

이 부분은 추 후 포스팅을 통해 값을 가져와보도록 하겠다.









마지막으로 설명하는 내용은 레코드 형식의 데이터다.


(한글의 데이터 레코드 구조)


논리적으로 연관된 데이터들을 헤더 정보와 함께 저장하는 방식을 데이터 레코드라고 한다.

레코드 구조를 가지는 스트림은 연속된 여러 개의 레코드로 구성된다. 데이터 레코드는 헤더와 데이터로 구성되며 각 헤더 정보를 활용하여 전체 논리적 구조를 생성하게 된다.

레코드의 헤더에는 데이터 확장에 대비한 정보를 가지고 있다. 따라서 이후에 ᄒᆞᆫ글의 기능이 확장되어 레코드에 데이터가 추가되는 경우에도 하위 버전의 ᄒᆞᆫ글이 상위 버전의 ᄒᆞᆫ글 문서를 읽을 수 있도록 하위 호환성이 보장된다.



Tag ID : 레코드가 나타내는 데이터의 종류를 나타내는 태그이다. Tag ID에는 10 비트가 사용되므로 0x000 - 0x3FF까지 가능하다.

0x000 - 0x00F = 일반 레코드 태그가 아닌 특별한 용도로 사용한다.

0x010 - 0x1FF = 글에 의해 내부용으로 예약된 영역(HWPTAG_BEGIN = 0x010)

0x200 - 0x3FF = 외부 어플리케이션이 사용할 수 있는 영역


Level : 대부분 하나의 오브젝트는 여러 개의 레코드로 구성되는 것이 일반적이기 때문에 하나의 레코드가 아닌 "논리적으로 연관된 연속된 레코드"라는 개념이 필요하다. 레벨은 이와 같이 연관된 레코드의 논리적인 묶음을 표현하기 위한 정보이다. 스트림을 구성하는 모든 레코드는 계층 구조로 표현할 수 있는데, 레벨은 바로 이 계층 구조에서의 depth를 나타낸다.


Size : 데이터 영역의 길이를 바이트 단위로 나타낸다. 12개의 비트가 모두 1일 때는 데이터 영역의 길이가 4095 바이트 이상인 경우로, 이때는 레코드 헤더에 연이어 길이를 나타내는 DWORD가 추가된다. , 4095 바이트 이상의 데이터일 때 레코드는 다음과 같이 표현된다.

(한글 문서파일형식에서 발췌)



대표적으로 DocInfo스트림과 Body 스토리지 내부의 Section 스트림에서 데이터 레코드형식을 취하고 있다.

TagID의 0x010에 HWP TAG 아이디를 넣음으로써 해당 레코드가 어떤 데이터를 갖고 있는지 구분할 수 있다.


현제 필자는 HwpLib 라이브러리를 통해 한글문서를 파싱, 렌더링 하는 부분을 분석중이다.

바이너리 데이터를 읽고 쓰는것이 익숙하지 않아 하루에도 머리가 여러번 쪼개지는 고통을 받고 있다.ㅋㅋ ㅜㅜ

빨리 이 과제를 마무리 짓고 싶다. ㅜㅜ




















  1. 지나가던 바밤바 2018.03.21 21:26 신고

    분석끝나면 예제샘플 올려주시나여?

회사 수습 연구원으로 진행하게될 과제이다.

Java로 .hwp파일을 파싱 후 렌더링하기까지가 숙제(과제)이다. 


처음에는 low레벨까지 내려가 binary형태에서 부터 파싱을 해야 하나 싶어서 걱정이 많았는데

자비로우신 팀장님께서 결과만 나오면 일단 된다고 하셨기에 갓구글님께 도움을 요청했다.


http://www.hancom.com/etc/hwpDownload.do 

(한글 문서 파일 구조 5.0 도큐먼트)


처음에 70페이지 가까이된 한글 문서 파일 구조를 던져주실때 식겁했는데

다행스럽게도 


https://github.com/neolord0/hwplib

누군가가 만들어주신 라이브러리가 존재했다.


한글과 컴퓨터(한컴)에서 만든 워드프로세서 "한글"의 파일에 대한 라이브러리입니다.

본 라이브러리는 JAVA로 구현되었으며, 한글 파일의 하부 구조인 Microsoft Compound File의 부분은 Apache-POI의 POIFS File System을 사용하여 처리합니다. 본 라이브러리는 한글과컴퓨터의 한글 문서 파일(.hwp) 공개 문서를 참고하여 개발하였습니다. 한컴에서 제공하는 문서(HWP 5.0)는 아래URL에서 받을 수 있습니다.

http://www.hancom.com/etc/hwpDownload.do?gnb0=269&gnb1=271&gnb0=101&gnb1=140



github에 올라온 프로젝트 소개글이다.

처음에 소스 분석을 하겠다고 처음부터 쭉 따라갔는데 왠 아파치 poi 라이브러리가 나오길래 막막했었다.

알고보니 아파치 poi 라이브러니는 마이크로소프트사의 워드 포맷형식을 지원하는 라이브러리였다.


여기서 생긴 의문이 

그렇다면 한글의 .hwp파일은 MicroSoft의 word 형식이랑 같다는것인가?

hwp나 word는 같은 Compound File Binary Format 이였던것이다.

한글은 XML기반으로도 파일이 제공된다고 팀장님이 알려주셨다.

CFBF, OLE라고도 불리는 이 형태는 하단의 블로그에서 자세하게 설명해준다.

http://www.reversenote.info/ole-file-format/



이제 위의 라이브러리를 통해 1차 목표인 한글파일 읽어들여

콘솔창에 띄우는 결과물을 만들어낼 생각이다.

이미 만들어져있기에 거기까진 어렵지 않지만 그냥 가져다가만 쓰면 개인과제에 의미가 없어보여서

최대한 라이브러리를 뜯어보아서 어떤형식으로 .hwp파일을 파싱하는지 공부해보려고 한다.








주어진 리스트가 정렬이 되어있다는 가정하에서는 

이진 검색(binary search)를 사용하는게 매우 효율적인 방법이란다.


소스를 보니 재귀호출을 사용하여 검색이 진행된다.

(JAVA 프로그래밍 면접 이렇게 준비한다 - 73P)



public class BinarySearch {

public static boolean binarySearch(final List<Integer> numbers, Integer value) {

if(numbers==null || numbers.isEmpty()) // 전달받은 numbers 리스트가 null이거나 비워져있는지 확인

return false;

Integer comparsion = numbers.get(numbers.size() / 2); //  리스트 크기 반띵하여 원소 위치의 값을 추출

if(value.equals(comparsion)) {   

return true;

}

if(value<comparsion) {

return binarySearch(numbers.subList(0, numbers.size() / 2), value);

} else {

return binarySearch(numbers.subList(numbers.size() / 2 + 1, numbers.size()), value);

}

}

public static void main(String[] args) {

List<Integer> list = new ArrayList<>();

list.add(1);

list.add(4);

list.add(5);

list.add(9);

list.add(14); // 정렬하기 귀찮아서 삽입할때 순서대로 삽입시켰다.



System.out.println(binarySearch(list, 9)); // 삽입된 리스트와, 찾고하자는 밸류값을 파라메터로 던진다.

}

}


소스가 어렵지 않아 쉽게 이해할 수 있었다.



java언어 개발시 필요한 jdk를 설치와 환경변수까지 

설정해보는 포스팅을 해보겠습니다.





1. JDK 설치파일 다운받기




오라클 홈페이지로 접속합니다.

http://www.oracle.com/technetwork/java/javase/downloads/index.html






JAVA 9버전이 릴리즈 되며 JDK 9.0.1을 확인 할 수 있내요.

저는 팀원과 개발환경을 맞추기 위해 JDK 1.8 버전으로 진행하기로 했습니다.

원하시는 버전에 해당하는 JDK DOWNLOAD 버튼을 눌러주세요

(저는 1.8 버전으로 진행하겠습니다)


상단의 라이센스사용 동의에 체크를 해주셔야 다운로드가 가능합니다.

설치하시는 컴퓨터의 운영체제에 맞는 버전을 클릭하여 다운로드하세요







2. 설치하기




인스톨 파일을 실행하여 설치를 진행합니다.

설치과정은 어려움이 없으니 천천히 다음 단계로 넘어가면서 진행하세요.






이렇게 설치가 마무리 되었습니다.

이제 환경변수를 설정해볼까요?






3. 환경변수 설정




제어판->시스템 및 보안->시스템

혹은

내 PC 우클릭 -> 속성


시스템창을 연뒤 고급 시스켐 설정을 클릭합니다.






환경변수 버튼을 클릭합니다.





시스템 변수의 '새로 만들기'를 클릭합니다.





변수 이름을 JAVA_HOME

변수 값을 JDK 설치경로로 잡습니다.

JDK를 기본 설정으로 설치하시면 C:\Program Files\Java\jdk1.8.0_151 

(9버전을 받으신분은 실제 디렉토리에 가셔서 버전을 확인하세요)





확인 버튼을 누른뒤 

시스템 다이얼에 Path를 클릭후 '편집' 버튼을 누릅니다.





'새로 만들기' 버튼을 클릭하신 뒤





%JAVA_HOME%\bin을 입력합니다.

jdk 버전업을 하게되더라도

아까 설정한 JAVA_HOME 디렉토리만 바꿔주시면

다른 설정 안건들이셔도 되요.








4. 설치 확인



이로써 JDK 설치가 끝났습니다.

이제 환경변수가 제대로 먹히는지 확인해봐야겠죠?


윈도우 -> cmd를 검색하셔서

커맨드창을 뛰웁니다.


자바 명령어를 통해 설치된 jdk 버전을 확인해봅시다


커맨드창에서

java -version을 입력하면

아래의 화면처럼 버전정보가 뜨게됩니다.

그럼 성공~









  1. lyasee 2017.11.21 00:32 신고

    감사합니다!

  2. 루지루지 2017.11.21 00:43 신고

    이거 꼭해야되요?

+ Recent posts

티스토리 툴바