HWP 5.0
revision 1.3: 20181108
차례
- 저작권 - 페이지 1
- 본 문서에 대하여 - 페이지 2
- I. 한글 5.0 파일 구조 - 페이지 3
- 1. 개요 - 페이지 5
- 2. 자료형 설명 - 페이지 6
- 3. 한글 파일 구조 - 페이지 7
- 3.1. 한글 파일 구조 요약 - 페이지 7
- 3.2. 스토리지 별 저장 정보 - 페이지 7
- 3.2.1. 파일 인식 정보 - 페이지 7
- 3.2.2. 문서 정보 - 페이지 8
- 3.2.3. 본문 - 페이지 9
- 3.2.4. 문서 요약 - 페이지 12
- 3.2.5. 바이너리 데이터 - 페이지 12
- 3.2.6. 미리보기 텍스트 - 페이지 12
- 3.2.7. 미리보기 이미지 - 페이지 13
- 3.2.8. 문서 옵션 - 페이지 13
- 3.2.9. 스크립트 - 페이지 13
- 3.2.10. XML 템플릿 - 페이지 13
- 3.2.11. 문서 이력 관리 - 페이지 14
- 3.2.12. 참고문헌 - 페이지 15
- 4. 데이터 레코드 - 페이지 16
- 4.1. 데이터 레코드 구조 - 페이지 16
- 4.2. '문서 정보'의 데이터 레코드 - 페이지 17
- 4.2.1. 문서 속성 - 페이지 17
- 4.2.2. 아이디 매핑 헤더 - 페이지 17
- 4.2.3. 바이너리 데이터 - 페이지 18
- 4.2.4. 글꼴 - 페이지 20
- 4.2.5. 테두리/배경 - 페이지 21
- 4.2.6. 글자 모양 - 페이지 24
- 4.2.7. 탭 정의 - 페이지 26
- 4.2.8. 문단 번호 - 페이지 26
- 4.2.9. 글머리표 - 페이지 27
- 4.2.10. 문단 모양 - 페이지 28
- 4.2.11. 스타일(문단 스타일) - 페이지 29
- 4.2.12. 문서 임의의 데이터 - 페이지 30
- 4.2.13. 배포용 문서 데이터 - 페이지 31
- 4.2.14. 호환 문서 - 페이지 32
- 4.2.15. 레이아웃 호환성 - 페이지 32
- 4.3. '본문'의 데이터 레코드 - 페이지 33
- 4.3.1. 문단 헤더 Tag ID : HWPTAG_PARA_HEADER - 페이지 33
- 4.3.2. 문단의 텍스트 - 페이지 34
- 4.3.3. 문단의 글자 모양 - 페이지 34
- 4.3.4. 문단의 레이아웃 - 페이지 35
- 4.3.5. 문단의 영역 태그 - 페이지 35
- 4.3.6. 컨트롤 헤더 - 페이지 35
- 4.3.7. 문단 리스트 헤더 - 페이지 36
- 4.3.8. 컨트롤 임의의 데이터 - 페이지 36
- 4.3.9. 개체 공통 속성을 포함하는 컨트롤(개체 컨트롤) - 페이지 36
- 4.3.9.1. 표 개체 - 페이지 39
- 4.3.9.2. 그리기 개체(선, 사각형, 타원, 호, 다각형, 곡선) - 페이지 40
- 4.3.9.2.1. 개체 요소 - 페이지 40
- 4.3.9.2.2. 선 개체 - 페이지 42
- 4.3.9.2.3. 사각형 개체 - 페이지 43
- 4.3.9.2.4. 타원 개체 - 페이지 43
- 4.3.9.2.5. 다각형 개체 - 페이지 45
- 4.3.9.2.6. 호 개체 - 페이지 45
- 4.3.9.2.7. 곡선 개체 - 페이지 45
- 4.3.9.3. 흔글 수식 개체 - 페이지 46
- 4.3.9.4. 그림 개체(HWPTAG_SHAPE_COMPONENT_PICTURE) - 페이지 46
- 4.3.9.5. OLE 개체(HWPTAG_SHAPE_COMPONENT_OLE) - 페이지 49
- 4.3.9.6. 차트 개체 - 페이지 50
- 4.3.9.7. 묶음 개체(HWPTAG_SHAPE_COMPONENT_CONTAINER) - 페이지 51
- 4.3.9.8. 동영상 개체(HWPTAG_VIDEO_TDATA) - 페이지 51
- 4.3.10. 개체 이외의 컨트롤 - 페이지 52
- 4.3.10.1. 구역 정의 - 페이지 53
- 4.3.10.1.1. 용지 설정 - 페이지 54
- 4.3.10.1.2. 각주/미주 모양 - 페이지 55
- 4.3.10.1.3. 쪽 테두리/배경 - 페이지 56
- 4.3.10.2. 단 정의 - 페이지 56
- 4.3.10.3. 머리말/꼬리말 - 페이지 57
- 4.3.10.4. 각주/미주 - 페이지 57
- 4.3.10.5. 자동 번호 - 페이지 58
- 4.3.10.6. 새 번호 지정 - 페이지 58
- 4.3.10.7. 감추기 - 페이지 58
- 4.3.10.8. 홀/짝수 조정 - 페이지 59
- 4.3.10.9. 쪽 번호 위치 - 페이지 59
- 4.3.10.10. 찾아보기 표식 - 페이지 59
- 4.3.10.11. 책갈피 - 페이지 60
- 4.3.10.12. 글자 겹침 - 페이지 60
- 4.3.10.13. 덧말 - 페이지 60
- 4.3.10.14. 숨은 설명 - 페이지 60
- 4.3.10.15. 필드 시작 - 페이지 61
- 4.3.10.1. 구역 정의 - 페이지 53
- 4.4. 문서 이력 관리 - 페이지 62
- 4.4.1. 문서 이력 관리란 - 페이지 62
- 4.4.2. 문서 이력 관리 레코드 정보 - 페이지 62
- 4.4.2.1. 히스토리 아이템 정보 시작 - 페이지 62
- 4.4.2.2. 히스토리 아이템 정보 끝 - 페이지 62
- 4.4.2.3. 히스토리 아이템 버전 - 페이지 63
- 4.4.2.4. 히스토리 날짜 - 페이지 63
- 4.4.2.5. 히스토리 작성자 - 페이지 63
- 4.4.2.6. 히스토리 설명 - 페이지 63
- 4.4.2.7. 비교 정보 - 페이지 63
- 4.4.2.8. 가장 마지막 최근 문서 - 페이지 63
- 변경 사항 이력 - 페이지 65
저작권
(주)한글과컴퓨터(이하 '한컴')는 문서 형식의 개방성과 표준화에 대하여 적극 찬성합니다. 한컴은 한글 97의 문서 형식을 무상으로 지원한 바 있으며, 한글 2002~2010 문서의 XML 형식은 HWPML에 대해서도 문서 형식을 공개한 바 있습니다. 개방형 문서 표준화 및 코드 관련 위원회에도 적극적으로 참여하여 파일 형식의 표준화와 개방성을 위해 노력해 왔습니다. 이러한 결과로 HWPML 스펙이 OWPML란 이름으로 한국산업표준(KS X 6101:2011)으로 제정되었습니다. 또한, 한컴오피스에서 기록물 장기보존 표준 포맷인 PDF/A-1의 지원과 ISO 국제 문서 형식인 ODF와 OOXML 파일 형식의 불러오기와 저장하기를 적극적으로 지원하였습니다.
본 문서를 열람하고자 하는 자라면 누구에게나 제공되는 것이며, 본 문서를 열람하는 것 외에 복사, 배포, 게재 및 본 문서에 기재되어 있는 내용을 사용하고자 하는 자는 한글과컴퓨터의 본 저작권을 충분히 인식하고 동의하여야 합니다.
본 문서를 누구나 열람, 복사, 배포, 게재 및 사용을 자유롭게 할 수 있습니다. 다만, 배포는 원 내용이 일체 수정되지 않은 원본 또는 복사본으로 제한됩니다. 원본 및 복사본은 한컴에서 제공하는 스펙의 최신 버전을 포함하고 있어야 합니다.
한컴은 한컴오피스 한글 문서 파일(.hwp) 공개 문서에 따라 얻은 결과물을 기초로 또 다른 독점적, 배타적 권리를 취득하고 이를 (주)한글과컴퓨터를 상대로 행사하고자 하는 자를 상대로는 적극적으로 권리행사를 할 수도 있습니다.
그리고, 본 문서 및 본 문서에 기재된 내용을 참고하여 개발한 결과물에 대한 모든 저작권은 결과물을 개발한 개인 또는 단체에 있을 것입니다. 그러나 반드시 개발 결과물에 "본 제품은 한글과컴퓨터의 한글 문서 파일(.hwp) 공개 문서를 참고하여 개발하였습니다."라고 제품 내 사용자 인터페이스, 매뉴얼, 도움말 및 소스에 모두 기재하여야 하며 제품이 이러한 구성물이 없을 시에는 존재하는 구성물에만 기재합니다. 한컴은 본 문서 및 본 문서에 기재된 내용을 참고하여 개발한 결과물에 대해서 어떠한 정확성, 진실성도 보증하지 아니합니다.
본 문서에 대하여
본 문서는 한글 워드 프로세서의 파일 저장 형식 중, 한글 2002 이후 제품에서 사용되는 한글 문서 파일 형식 5.0에 관하여 설명한다.
본 문서는 한글 문서 파일 형식 5.0의 주요한 자료 형식 및 파일 구조, 레코드 구조에 대해서 설명한다.
한글 문서 수식, 차트, 배포용 문서, 한글 문서 파일 형식 3.0, HWPML에 관해서는 별도의 문서에서 설명한다.
I. 한글 5.0 파일 구조
1. 개요
한글 문서 파일은 사용자가 지정하지 않는 한 기본적으로 .HWP 확장자를 사용한다.
이 파일에 저장되는 내용은 사용자가 입력한 문서의 텍스트와 글자 모양 정보뿐만 아니라 편집 시 사용한 글꼴 정보와 용지 종류, 여백 정보 등 다양한 조판 설정 정보도 포함된다.
한글 문서 파일 형식 5.0은 2000년 10월 이후 출시된 한글 제품군(예: 한글 워디안, 한글 2002, 한글 2005, 한글 2007, 한글 2010, 한글 2014, 한글 2018)에서 생성된다. 전체적인 구조는 동일하지만 추가된 정보로 인해 약간의 차이가 있을 수 있다.
한글 문서 파일 형식 5.0은 파일 크기를 최소화하기 위해 압축을 사용한다. 압축된 문서 파일의 기본 정보 저장 부분은 압축되지 않으며, 사용자가 입력한 본문 텍스트와 이미지 관련 데이터만 압축된다.
한글은 문서 파일 압축을 위해 zlib.org의 zlib을 사용한다. zlib은 소스 코드가 공개된 오픈소스 소프트웨어이다. zlib License에 따라 동작하며, 소스 코드를 자유롭게 사용할 수 있고 파생 작품에 대해서는 소스 코드 공개를 요구하지 않는다. 자세한 내용은 zlib에 포함된 라이선스 문서를 참조하라.
한글 문서 파일 형식 5.0의 구조는 Windows Compound Files를 기반으로 하며, 문자 인코딩은 ISO-10646 표준을 따른다. 대부분의 문자 정보는 Unicode(UTF-16LE) 형식으로 전송 및 저장된다.
참고: Compound Files에 접근하는 방법은 OLE 관련 문서나 MSDN의 StgOpenStorage(), IStorage::Open() 등의 함수를 참조하라.
2. 자료형 설명
앞으로 계속되는 설명에서 한글의 문서 파일에 저장되는 정보는 아래 표에 설명하는 자료형을 이용해 표현한다.
자료형에서 한 바이트는 8 비트로 표현되며, 두 바이트 이상의 길이를 가지는 자료형은 최하위 바이트가 가장 먼저 저장되고, 최상위 바이트가 가장 나중에 저장되는 리틀 엔디언(Little-endian) 형태이다.
파일에 저장되는 자료가 배열(array)일 때는 '자료형 array[개수]'와 같이 표현한다. 예를 들어 10개의 원소를 갖는 word 배열이면 'word array[10]'과 같이 표현한다.
표 1: 자료형
WCHAR는 한글의 내부 코드로 표현된 문자 한 글자를 표현하는 자료형이다. 한글의 내부 코드는 한글, 영문, 한자를 비롯해 모든 문자가 2 바이트의 일정한 길이를 가진다.
HWPUNIT과 SHWPUNIT는 문자의 크기, 그림의 크기, 용지 여백 등, 문서를 구성하는 요소들의 크기를 표현하기 위한 자료형이다. 문서 출력 장치의 해상도는 가변적이기 때문에, 크기 정보를 점(도트)의 수로 표현할 수는 없다. 따라서 일정한 단위를 기준으로 해야 하는데, 한글에서는 1/7200인치를 기본 단위로 사용한다. 예를 들어 [가로 2인치 x 세로 1인치]짜리 그림의 크기를 HWPUNIT 형으로 표현하면 각각 14400 x 7200이 된다.
3. 한글 파일 구조
3.1. 한글 파일 구조 요약
한글 문서 파일은 복합 파일(Compound File) 구조를 가지며, 내부적으로 스토리지(Storage)와 스트림(Stream)으로 구성된다. 스트림에는 바이너리 또는 레코드 구조의 데이터가 저장되며, 압축/암호화될 수 있다.
표 2: 전체 구조
압축된 문서 파일은 '파일 인식 정보'의 '압축' 플래그를 확인하여 압축을 풀고 처리해야 한다. 이후 설명은 압축이 풀린 상태의 파일을 기준으로 한다.
'문서정보', '본문', '문서 이력 관리'에 사용되는 '레코드 구조'는 '데이터 레코드' 섹션에서 상세히 설명된다.
3.2. 스토리지 별 저장 정보
3.2.1. 파일 인식 정보
한글의 문서 파일이라는 것을 나타내기 위해 '파일 인식 정보'가 저장된다. FileHeader 스트림에 저장되는 데이터는 다음과 같다.
표 3: 파일 인식 정보
3.2.2. 문서 정보
문서 내에서 공통으로 사용되는 글꼴, 글자 속성, 문단 속성, 탭, 스타일 등의 상세 정보가 저장된다. 이 정보는 DocInfo 스트림에 저장된다.
DocInfo 스트림에 저장되는 데이터는 다음과 같다.
표 4: 문서 정보
각 상세 정보는 '<문서 정보>의 데이터 레코드' 섹션에서 상세히 설명된다.
3.2.3. 본문
문서의 본문에 해당하는 문단, 표, 그리기 개체 등의 내용이 저장되는 곳이다.
BodyText 스토리지는 Section%d 스트림으로 나뉘며, %d는 구역 번호를 나타낸다. 구역의 개수는 문서 정보의 문서 속성에 저장된다.
각 구역의 첫 번째 문단에는 구역 정의 레코드가 저장되고, 각 단 설정의 첫 번째 문단에는 단 정의 레코드가 저장된다.
각 구역의 가장 마지막에는 확장 기본 쪽(마지막 쪽, 임의 쪽) 관련 정보가 저장되고, 마지막 구역의 가장 마지막에는 메모 관련 정보가 저장된다.
Section 스트림에 저장되는 데이터는 문단(문단의 리스트)으로 구성되며, 다음 문단 정보가 반복된다.
표 5: 본문
문서 파일에서 문단 내용을 읽다가 제어 문자를 발견하면, 문서를 읽는 쪽에서는 제어 문자 종류에 따라 읽어 들이거나 건너 뛰어 다음 데이터의 시작 위치까지 파일 포인터를 옮기기 위한 적절한 처리를 수행해야 한다. 제어 문자 가운데는 또 다른 문단 리스트를 포함하는 경우도 있기 때문에, 제어 문자를 일반 문자처럼 처리하면 문서 파일을 정상적으로 읽을 수 없다.
표, 각주 등과 같은 문단 리스트를 포함하는 컨트롤 문자들은 독자적인 문단 리스트를 가진다. 해당 리스트들은 아래와 같은 리스트 헤더 정보를 포함한다. 실제 문단들은 그 다음에 serialize 된다.
문단 내에서 컨트롤은 세 가지 형식에 따라 다음과 같은 차이가 있다.
문자 컨트롤
부가정보 없이 문자 하나로 표현되는 제어 문자이다. (3번째 ch)
인라인 컨트롤
부가정보가 12 바이트(6 WCHAR) 이내에서 표현될 수 있는 제어 문자이다. info에 부가정보를 다 넣지 못하는 경우는 확장 컨트롤로 대체된다. (3~9까지 8개의 ch)
확장 컨트롤
제어 문자는 포인터를 가지고 있고, 포인터가 가리키는 곳에 실제 오브젝트가 존재하는 제어 문자이다. (3~9까지 8개의 ch)
↓ (포인터가 가리키는 위치)
Control Object Instance
본 문서에 부가 설명 없이 '컨트롤' 또는 '제어 문자'라고 하면 바로 이 확장 컨트롤을 지칭하는 것이다.
표 6: 제어 문자
3.2.4. 문서 요약
\005HwpSummaryInformation 스트림에는 한글 메뉴의 "파일 - 문서 정보 - 문서 요약"에서 입력한 내용이 저장된다.
Summary Information에 대한 자세한 설명은 MSDN을 참고:
- The Summary Information Property Set
- The DocumentSummaryInformation and UserDefined Property Set
표 7: 문서 요약
3.2.5. 바이너리 데이터
BinData 스토리지에는 그림이나 OLE 개체와 같이 문서에 첨부된 바이너리 데이터가 각각의 스트림으로 저장된다.
압축: 표 2에 따르면 BinData 스토리지의 스트림은 압축되어 저장됩니다. 실제 구현에서는 CFB에서 스트림을 읽은 후 압축 해제가 필요합니다.
- 압축 형식: raw deflate (zlib의 deflate 알고리즘, windowBits: -15)
- 압축 해제 방법: zlib의
decompress(..., -15)또는 동등한 함수 사용 - 레거시 구현 참고:
- hwpjs.js:
pako.inflate(data.content, { windowBits: -15 }) - pyhwp:
zlib.decompress(compressed_data, -15)
- hwpjs.js:
⚠️ 실제 구현 시 주의사항 (Implementation Notes)
스펙 문서에는 BinData 스토리지 내 스트림의 정확한 경로 형식이 명시되어 있지 않습니다.
실제 구현에서는 표 17의 HWPTAG_BIN_DATA 레코드를 사용하여 스트림을 찾습니다:
- EMBEDDING 타입:
binary_data_id와extension정보를 사용
- 스트림 이름:
BIN{id:04X}(16진수 4자리, 대문자)- 시도하는 경로:
BinData/BIN{id:04X},Root Entry/BinData/BIN{id:04X},BIN{id:04X}BinData/BIN{id:04X}.{extension},Root Entry/BinData/BIN{id:04X}.{extension}(표 17의 extension 정보 사용)- STORAGE 타입:
binary_data_id만 사용 (extension 없음)
- 스트림 이름:
BIN{id:04X}- 시도하는 경로:
BinData/BIN{id:04X},Root Entry/BinData/BIN{id:04X},BIN{id:04X}- LINK 타입: BinData 스토리지에 저장되지 않으므로 건너뜀
표 17의
extension필드는 EMBEDDING 타입일 때 바이너리 데이터의 형식 정보를 제공하며, 이를 활용하여 스트림 경로를 구성할 수 있습니다.압축 해제: CFB에서 스트림을 읽은 후, raw deflate 형식으로 압축 해제해야 합니다. 압축 해제 실패 시 원본 데이터를 사용하거나 에러를 처리해야 합니다.
3.2.6. 미리보기 텍스트
PrvText 스트림에는 미리보기 텍스트가 유니코드 문자열로 저장된다.
3.2.7. 미리보기 이미지
PrvImage 스트림에는 미리보기 이미지가 BMP 또는 GIF 형식으로 저장된다.
3.2.8. 문서 옵션
DocOptions 스토리지에는 연결 문서, 배포용 문서, 공인인증서 DRM, 전자 서명 관련 정보가 각각의 스트림으로 저장된다.
_LinkDoc스트림: 연결된 문서의 경로가 저장된다.DrmLicense스트림: DRM Packaging의 Version 정의가 저장된다.DrmRootSect스트림: 암호화 알고리즘이 저장된다.CertDrmHeader스트림: DRM Packaging의 Version 정의가 저장된다.CertDrmInfo스트림: 공인인증서 DRM 정보가 저장된다.DigitalSignature스트림: 전자 서명 정보가 저장된다.PublicKeyInfo스트림: 공개 키 정보가 저장된다.
3.2.9. 스크립트
Scripts 스토리지에는 Script 코드를 저장한다.
JScriptVersion 스트림에는 Script Version이 저장된다.
표 8: 스크립트 버전
DefaultJScript 스트림에는 Script 헤더, 소스, Pre 소스, Post 소스가 저장된다.
표 9: 스크립트
3.2.10. XML 템플릿
XMLTemplate 스토리지에는 XML Template 정보를 저장한다.
_SchemaName 스트림에는 Schema 이름 문자열이 저장된다.
표 10: Schema 이름 정보
Schema 스트림에는 Schema 문자열이 저장된다.
표 11: Schema 길이 정보
Instance 스트림에는 Instance 문자열이 저장된다.
표 12: Instance 정보
3.2.11. 문서 이력 관리
한글 메뉴의 "파일 - 문서 이력 관리"에서 표시 및 생성되는 문서의 이력 정보를 저장하는 장소이다.
문서 이력 정보의 각각의 아이템은 "히스토리" 혹은 "히스토리 아이템"이라 하며 한글 Compound 구조 내에서 각 아이템은 "DocHistory"라는 스토리지 내부에 VersionLog%d(%d는 버전) 이름의 스트림으로 저장된다. 또한, 각각 아이템은 압축, 암호화되어 저장된다.
이력 정보 데이터를 "DocHistory"라는 새로운 스토리지로 저장한다. DocHistory 스토리지에 이력 정보 아이템은 추후 추가 정보가 저장되었을 때 하위 호환성을 위하여 다음의 구조로 저장한다.
버전 정보 스토리지 구조:
히스토리 아이템 스트림 구조:
레코드 구성:
RECORD_HEADER
RECORD_DATA (RD)
3.2.12. 참고문헌
Bibliography 스토리지에는 참고문헌 정보가 .XML 파일 형태로 저장한다.
4. 데이터 레코드
4.1. 데이터 레코드 구조
데이터 레코드는 논리적으로 관련된 데이터를 헤더 정보와 함께 저장하는 방법이다. 레코드 구조를 가진 스트림은 여러 개의 연속된 레코드로 구성된다.
데이터 레코드는 헤더와 데이터로 구성되며, 헤더 정보를 이용하여 전체적인 논리 구조를 만들 수 있다. 레코드 헤더에는 데이터 확장을 위한 정보가 포함되어 있어, 한글 문서의 이전 버전에서도 데이터가 추가된 레코드를 읽을 수 있도록 하여 하위 호환성을 보장한다.
그림 45: 레코드 구조
레코드 헤더의 크기는 32bits이고 TagID(10bits), Level(10bits), Size(12bits)로 구성된다.
Tag ID:
- 레코드가 나타내는 데이터의 종류를 나타낸다.
- 10비트를 사용하므로 0x000부터 0x3FF까지의 값을 가질 수 있다.
- 0x000 - 0x00F: 특수 목적으로 사용되며, 일반적인 레코드 태그로 사용되지 않는다.
- 0x010 - 0x1FF: 한글 내부 사용을 위해 예약되어 있다 (HWPTAG_BEGIN = 0x010).
- 0x200 - 0x3FF: 외부 응용 프로그램이 사용할 수 있는 영역이다.
Level:
- 대부분의 객체는 여러 개의 레코드로 구성되므로, "논리적으로 관련된 연속된 레코드"라는 개념이 필요하다.
- Level은 이러한 논리적 그룹핑을 나타내는 정보를 제공한다.
- 스트림을 구성하는 모든 레코드는 계층 구조로 표현할 수 있으며, Level은 이 계층 구조에서의 깊이를 나타낸다.
Size:
- 데이터 영역의 길이를 바이트 단위로 나타낸다.
- 12비트가 모두 1인 경우(즉, 0xFFF)는 데이터 영역의 길이가 4095바이트 이상임을 나타낸다.
- 이 경우(데이터가 4095바이트를 초과하는 경우) 레코드 헤더 바로 다음에 길이를 나타내는 DWORD가 추가된다.
그림 46: 확장 데이터 레코드 구조
4.2. '문서 정보'의 데이터 레코드
'문서 정보('DocInfo')'에서 사용되는 데이터 레코드는 다음과 같다.
표 13: 문서 정보의 데이터 레코드
4.2.1. 문서 속성
Tag ID: HWPTAG_DOCUMENT_PROPERTIES
표 14: 문서 속성
⚠️ 실제 구현 시 주의사항 (Implementation Notes)
첫 번째 UINT32 필드인 **"문서 내 캐럿의 위치 정보"**는 실제로 존재하지 않습니다.
4.2.2. 아이디 매핑 헤더
Tag ID: HWPTAG_ID_MAPPINGS
표 15: 아이디 매핑 헤더
표 16: 아이디 매핑 개수 인덱스
4.2.3. 바이너리 데이터
Tag ID: HWPTAG_BIN_DATA
표 17: 바이너리 데이터
표 18: 바이너리 데이터 속성
4.2.4. 글꼴
Tag ID: HWPTAG_FACE_NAME
표 19: 글꼴
표 20: 글꼴 속성
표 21: 대체 글꼴 유형
표 22: 글꼴 유형 정보
4.2.5. 테두리/배경
Tag ID: HWPTAG_BORDER_FILL
표 23: 테두리/배경 속성
표 24: 테두리/배경 속성
표 25: 테두리선 종류
표 26: 테두리선 굵기
표 27: 대각선 종류
표 28: 채우기 정보
표 29: 채우기 무늬 종류
표 30: 그러데이션 유형
표 31: 이미지 채우기 유형
표 32: 그림 정보
4.2.6. 글자 모양
Tag ID: HWPTAG_CHAR_SHAPE
표 33: 글자 모양
표 34: 글꼴에 대한 언어
표 35: 글자 모양 속성
4.2.7. 탭 정의
Tag ID: HWPTAG_TAB_DEF
표 36: 탭 정의
표 37: 탭 정의 속성
4.2.8. 문단 번호
Tag ID: HWPTAG_NUMBERING
표 38: 문단 번호
참고: 표 38은 각 수준(1~7)의 기본 정보를 나타냅니다. 실제 바이너리 구조에서는 표 38의 8바이트 구조와 표 39의 가변 데이터가 각 수준마다 연속적으로 배치됩니다.
표 39: 문단 머리 정보
**실제 바이너리 구조
표 38과 표 39는 구조를 설명하기 위해 분리되어 있지만, 실제 HWP 파일에서는 각 수준(1~7)마다 다음 구조가 연속적으로 반복됩니다:
각 수준(1~7)마다 반복:
- 표 38 구조 (8바이트):
- UINT 속성 (4바이트)
- HWPUNIT16 너비 보정값 (2바이트)
- HWPUNIT16 본문과의 거리 (2바이트)
- UINT 글자 모양 아이디 참조 (4바이트)
- 표 39 가변 데이터:
- WORD 번호 형식 길이 (len) (2바이트)
- WCHAR array[len] 번호 형식 문자열 (2×len 바이트, UTF-16LE)
- UINT16 시작 번호 (2바이트)
- UINT 수준별 시작번호 (4바이트, 5.0.2.5 이상, 옵션)
확장 번호 형식 (수준 8~10, 3회 반복):
- WORD 확장 번호 형식 길이 (len) (2바이트)
- WCHAR array[len] 확장 번호 형식 문자열 (2×len 바이트, UTF-16LE)
주의사항 / Important Notes:
-
format_string 해석 / format_string Interpretation:
format_string이 **빈 문자열("")**인 경우: 기본 형식을 사용하여 번호를 표시합니다.format_string이 **null 문자("\u0000")**만 포함하는 경우: 번호를 표시하지 않고 텍스트만 표시합니다.- 이 동작은 스펙 문서에 명시되어 있지 않지만, 실제 HWP 파일의 동작을 기반으로 합니다.
-
확장 레벨(8
10) 결정 방법 / Extended Level (810) Determination:paragraph_level이 6 (bit 25-27 = 6)이고line_spacing이 7 이상인 경우, 확장 레벨(8~10)로 판단합니다.- 확장 레벨의 실제 레벨을 결정할 때는
para_style_id를 사용하여 스타일 이름에서 레벨을 추출합니다.- 예: 스타일 이름이 "개요 8"이면 레벨 8, "개요 9"이면 레벨 9, "개요 10"이면 레벨 10
- 스타일 이름에서 레벨을 추출할 수 없는 경우,
line_spacing + 1을 레벨로 사용합니다. extended_levels배열 범위를 벗어나는 경우 (예: 레벨 10인데extended_levels에 2개만 있는 경우), 넘버링 없이 텍스트만 표시합니다.- 이 동작은 스펙 문서에 명시되어 있지 않지만, 실제 HWP 파일의 동작을 기반으로 합니다.
표 40: 문단 머리 정보 속성
표 41: 문단 번호 형식
4.2.9. 글머리표
Tag ID: HWPTAG_BULLET
표 42: 글머리표
4.2.10. 문단 모양
Tag ID: HWPTAG_PARA_SHAPE
표 43: 문단 모양
표 44: 문단 모양 속성1
표 45: 문단 모양 속성2
표 46: 줄 간격 종류
한글 2007 이하 버전:
- bit 0-1: 줄 간격 종류
- 0: 글자에 따라(%)
- 1: 고정값
- 2: 여백만 지정
5.0.2.5 버전 이상:
- bit 0-4: 줄 간격 종류
- 0: 글자에 따라
- 1: 고정값
- 2: 여백만 지정
- 3: 최소값
4.2.11. 스타일(문단 스타일)
Tag ID: HWPTAG_STYLE
표 47: 스타일
표 48: 스타일 종류
4.2.12. 문서 임의의 데이터
라벨 문서인지 여부나 인쇄 대화상자의 정보를 저장한다.
Tag ID: HWPTAG_DOC_DATA
표 49: 문서 임의의 데이터
파라미터 아이템의 개수만큼 아이템 데이터를 얻는다.
표 50: 파라미터 셋
표 51: 파라미터 아이템
표 52: 파라미터 아이템 종류
4.2.13. 배포용 문서 데이터
배포용 문서에서는 모든 스트림에 배포용 문서 데이터가 들어간다.
Tag ID: HWPTAG_DISTRIBUTE_DOC_DATA
표 53: 배포용 문서 데이터
4.2.14. 호환 문서
Tag ID: HWPTAG_COMPATIBLE_DOCUMENT
표 54: 호환 문서
표 55: 대상 프로그램
4.2.15. 레이아웃 호환성
Tag ID: HWPTAG_LAYOUT_COMPATIBILITY
표 56: 레이아웃 호환성
4.3. '본문'의 데이터 레코드
본문에서 사용되는 데이터 레코드는 다음과 같다.
표 57: 본문의 데이터 레코드
4.3.1. 문단 헤더
Tag ID: HWPTAG_PARA_HEADER
표 58: 문단 헤더
표 59: 단 나누기 종류
주의 / Warning:
column_divide_type속성은 페이지 구분을 위한 신뢰할 수 있는 지표가 아닙니다.실제 HWP 파일에서 페이지 나누기는 다음과 같은 경우에 발생할 수 있습니다:
- 명시적 페이지 나누기:
column_divide_type에Page(0x04)가 포함된 경우- 암시적 페이지 나누기: 여러 줄바꿈으로 페이지가 채워져 자동으로 새 페이지가 생성되는 경우
- 암시적 페이지 나누기의 경우
column_divide_type이 빈 배열([])일 수 있으며, 이 경우 페이지 구분을 위해 다른 방법이 필요합니다.따라서 레거시 라이브러리들(ruby-hwp, hwpjs.js)은
column_divide_type대신LineSegmentInfo의vertical_position값을 기반으로 페이지를 구분합니다:
vertical_position이 0으로 리셋되거나 이전 문단의vertical_position보다 작아지면 새 페이지로 간주합니다.
- If
vertical_positionresets to 0 or becomes smaller than the previous paragraph'svertical_position, it is considered a new page.vertical_position이 페이지 콘텐츠 영역 높이를 초과하면 새 페이지로 간주합니다. 2. Ifvertical_positionexceeds the page content area height, it is considered a new page.이 구현도 동일한 방식을 사용합니다. This implementation uses the same approach.
레벨별 사용 / Usage by Level
참고 / Note: 아래 내용은 공식 스펙 문서에 명시되지 않았지만, 실제 HWP 파일과 레거시 구현(libhwp, hwp-rs, pyhwp, hwpjs.js, ruby-hwp)에서 확인된 동작입니다.
-
Level 0: 본문의 문단 헤더 (일반적인 사용)
- Section의 최상위 레벨에서 나타나며, 문단의 시작을 나타냅니다.
-
Level 1 이상: 컨트롤 헤더 내부의 문단 헤더
- 각주/미주(
fn,en), 머리말/꼬리말(head,foot) 등의 컨트롤 헤더 내부에 직접 나타날 수 있습니다. - 이러한 경우 PARA_HEADER는 해당 컨트롤 헤더의 자식 레코드로 처리되며, 컨트롤 헤더 내부의 문단 내용을 나타냅니다.
- 각주/미주(
-
SHAPE_COMPONENT 내부: LIST_HEADER 다음의 PARA_HEADER
- SHAPE_COMPONENT(개체 요소) 내부에서 LIST_HEADER 다음에 PARA_HEADER가 나타날 수 있습니다 (글상자 텍스트).
- 이러한 경우 PARA_HEADER는 LIST_HEADER의 형제 레코드로 나타나며, LIST_HEADER의
paragraphs필드에 포함되어야 합니다.
4.3.2. 문단의 텍스트
Tag ID: HWPTAG_PARA_TEXT
텍스트의 수가 1 이상이면 문자 수만큼 텍스트를 로드하고 그렇지 않을 경우 PARA_BREAK로 문단을 생성한다.
표 60: 문단 텍스트
문단은 최소 하나의 문자 Shape buffer가 존재하며, 첫 번째 pos가 반드시 0이어야 한다. 예를 들어 문자길이 40자 짜리 문단이 10자씩 4가지 다른 글자 모양으로 구성되어 있다면 buffer는 다음과 같다.
그림 47: 문단 버퍼 구조
텍스트 문자 Shape 레코드를 글자 모양 정보 수(Character Shapes)만큼 읽는다.
4.3.3. 문단의 글자 모양
Tag ID: HWPTAG_PARA_CHAR_SHAPE
표 61: 문단의 글자 모양
4.3.4. 문단의 레이아웃
문단의 각 줄을 출력할 때 사용한 Cache 정보이며, 문단 정보의 '각 줄에 대한 align에 대한 정보 수'만큼 반복한다.
Tag ID: HWPTAG_PARA_LINE_SEG
표 62: 문단의 레이아웃
주의 / Warning: 태그 필드의 bit 0 (
is_first_line_of_page)은 실제 HWP 파일에서 신뢰할 수 없는 값입니다.실제 HWP 파일을 분석한 결과, 대부분의 경우
is_first_line_of_page가false로 설정되어 있어 페이지 구분에 사용할 수 없습니다. 레거시 라이브러리들(ruby-hwp, hwpjs.js)도 이 플래그를 사용하지 않고vertical_position값만을 기반으로 페이지를 구분합니다.따라서 페이지 구분을 위해서는
vertical_position값을 사용해야 합니다 (자세한 내용은 표 59: 단 나누기 종류 참조).
4.3.5. 문단의 영역 태그
range tag 정보를 정보 수만큼 읽어 온다. range tag는 텍스트의 일정 영역을 마킹하는 용도로 사용되며. 글자 모양과는 달리 각 영역은 서로 겹칠 수 있다.(형광펜, 교정 부호 등)
Tag ID: HWPTAG_PARA_RANGE_TAG
표 63: 문단의 영역 태그
4.3.6. 컨트롤 헤더
컨트롤 문자가 존재하면 컨트롤 문자로부터 존재하는 컨트롤 정보를 생성한다.
Tag ID: HWPTAG_CTRL_HEADER
표 64: 컨트롤 헤더
컨트롤 ID 파싱 주의사항 / Control ID Parsing Notes
본 라이브러리는 실제 HWP 파일 파싱 시 다음과 같은 커스텀 로직을 사용합니다:
This library uses the following custom logic when parsing actual HWP files:
바이트 순서 / Byte Order
HWP 파일에서 컨트롤 ID는 4바이트 UINT32 값으로 저장되며, 바이트를 리버스해서 읽어야 올바른 문자열을 얻을 수 있습니다. 레거시 라이브러리들(pyhwp, hwp.js)과 동일하게 바이트를 리버스해서 읽습니다:
In HWP files, control IDs are stored as 4-byte UINT32 values, and bytes must be read in reverse order to obtain the correct string. Legacy libraries (pyhwp, hwp.js) read bytes in reverse order:
pyhwp 방식:
Rust 구현:
예시 / Example
-
파일에 저장된 바이트:
[0x20, 0x6C, 0x62, 0x74](little-endian) -
리버스 후:
[0x74, 0x62, 0x6C, 0x20]="tbl "(테이블 컨트롤) -
리버스하지 않으면:
[0x20, 0x6C, 0x62, 0x74]=" lbt"(잘못된 파싱) -
Bytes stored in file:
[0x20, 0x6C, 0x62, 0x74](little-endian) -
After reverse:
[0x74, 0x62, 0x6C, 0x20]="tbl "(table control) -
Without reverse:
[0x20, 0x6C, 0x62, 0x74]=" lbt"(incorrect parsing)
공백 포함 분기 처리 / Branching with Spaces
컨트롤 ID는 공백을 포함할 수 있으므로, 분기 처리 시 공백까지 포함해서 비교해야 합니다.
Control IDs can include spaces, so branching logic must compare including spaces.
주요 컨트롤 ID / Common Control IDs
"tbl "- 테이블 컨트롤 / Table control"gso "- 일반 그리기 개체 / General shape object"cold"- 단 정의 / Column definition"head"- 머리말 / Header"foot"- 꼬리말 / Footer
구현 예시 / Implementation Example
주의: trim_end()를 사용하면 공백이 제거되어 "tbl "가 "tbl"로 변환되므로, 분기 처리 시 매칭되지 않을 수 있습니다.
Note: Using trim_end() removes spaces, converting "tbl " to "tbl", which may cause branching to fail.
4.3.7. 문단 리스트 헤더
Tag ID: HWPTAG_LIST_HEADER
표 65: 문단 리스트 헤더
파싱 주의사항 / Parsing Notes
실제 HWP 파일에서는 표 65와 다른 구조로 저장될 수 있습니다. 일부 구현체(pyhwp 등)에서는 다음과 같이 파싱합니다:
따라서 ListHeader를 파싱할 때는 실제 데이터 구조를 확인하여 올바른 offset을 사용해야 합니다. 특히 표 셀(TableCell)의 경우 ListHeader 이후에 셀 속성(표 80)이 이어지므로, ListHeader의 실제 크기를 정확히 파악하는 것이 중요합니다.
In actual HWP files, the structure may differ from Table 65. Some implementations (e.g., pyhwp) parse it as follows:
Therefore, when parsing ListHeader, the actual data structure should be verified to use the correct offset. Especially for table cells (TableCell), since cell attributes (Table 80) follow after ListHeader, it is important to accurately determine the actual size of ListHeader.
표 65-1: 문단 리스트 헤더 속성
4.3.8. 컨트롤 임의의 데이터
컨트롤의 필드 이름이나 하이퍼링크 정보를 저장한다.
Tag ID: HWPTAG_CTRL_DATA
표 66: 컨트롤 임의의 데이터
4.3.9. 개체 공통 속성을 포함하는 컨트롤(개체 컨트롤)
extended type의 컨트롤은 종류를 나타내는 식별 기호로 32 비트 ID가 사용된다. 컨트롤 코드가 큰 범주를 나타내는 식별 기호라고 한다면, 컨트롤 ID는 세부 분류를 나타내는 식별 기호인 셈이다.
예를 들어 단 정의 컨트롤 ID는 MAKE_4CHID('c', 'o', 'T', 'd') 같은 형식으로 정의한다.
표 67: 개체 공통 속성을 포함하는 컨트롤과 컨트롤ID
표 68: 개체 공통 속성
표 69: 개체 공통 속성
구현 주의사항 (DIFFSPEC) / Implementation Notes (DIFFSPEC)
스펙 문서 표 69에서는 offset_y와 offset_x가 HWPUNIT (unsigned)로 명시되어 있지만, 실제 HWP 파일에서는 SHWPUNIT (signed)로 파싱해야 합니다.
이유:
- 오프셋 값은 기준점보다 위나 왼쪽에 위치할 수 있어 음수 값이 필요합니다.
- 예:
0xFFFFF9ED(4294964461 as u32) =-835(as i32) = 약 -0.116인치
레거시 구현 참고:
- pyhwp:
SHWPUNIT을 사용하고# DIFFSPEC주석으로 표시 - hwpjs.js:
getUint32를 사용하지만, 이는 잘못된 구현일 수 있음
따라서 본 라이브러리는 offset_y와 offset_x를 INT32로 읽어 SHWPUNIT으로 변환합니다.
파싱 주의사항 / Parsing Notes
본 라이브러리는 실제 HWP 파일 파싱 시 parse_object_common 함수가 컨트롤 ID 이후의 데이터만 파싱하므로, 최소 40바이트가 필요합니다. 표 69의 전체 길이는 컨트롤 ID(4바이트)를 포함한 46 + (2×len) 바이트이지만, 컨트롤 ID를 제외하면 42 + (2×len) 바이트입니다.
구조 분석:
- 필수 필드 (컨트롤 ID 제외): attribute(4) + offset_y(4) + offset_x(4) + width(4) + height(4) + z_order(4) + margin(8) + instance_id(4) + page_divide(4) = 40바이트
- 선택적 필드: description_len(2) + description(2×len)
따라서 40바이트는 유효한 크기입니다 (page_divide까지 포함, description 없음). 일부 파일에서는 40바이트만 있을 수 있으며, 42바이트 이상일 때는 description이 포함될 수 있습니다.
표 70: 개체 공통 속성
표 71: 캡션 리스트
표 72: 캡션
표 73: 캡션 속성
4.3.9.1. 표 개체
Tag ID: HWPTAG_TABLE
표 74: 표 개체
표 75: 표 개체 속성
표 76: 표 속성의 속성
표 77: 안쪽 여백 정보
표 78: 영역 속성
표 79: 셀 리스트
파싱 주의사항 / Parsing Notes
표 65에 명시된 ListHeader는 6바이트이지만, 실제 구현에서는 8바이트일 수 있습니다 (UINT16 + UINT16 + UINT32). 따라서 셀 속성(표 80)을 파싱할 때는 ListHeader의 실제 크기를 확인하여 올바른 offset(6 또는 8바이트)을 사용해야 합니다.
Table 65 specifies ListHeader as 6 bytes, but actual implementations may use 8 bytes (UINT16 + UINT16 + UINT32). Therefore, when parsing cell attributes (Table 80), the actual size of ListHeader should be verified to use the correct offset (6 or 8 bytes).
표 80: 셀 속성
4.3.9.2. 그리기 개체(선, 사각형, 타원, 호, 다각형, 곡선)
모든 그리기 개체에 대한 serialization은 우선 base인 그리기 개체 공통 속성을 serialize한 다음 자신이 가지고 있는 개체 요소 속성을 serialize한다.
표 81: 그리기 개체 공통 속성
####### 4.3.9.2.1. 개체 요소
Tag ID: HWPTAG_SHAPE_COMPONENT (GenShapeObject일 경우 id가 두 번 기록됨)
표 82: 개체 요소 속성
참고사항 / Notes
실제 HWP 파일에서는 모든 SHAPE_COMPONENT 레코드에서 개체 컨트롤 ID가 두 번 기록됩니다. pyhwp, hwp.js도 항상 두 번째 ID를 읽고 있습니다.
표 83: 개체 요소 속성
표 84: Rendering 정보
각 matrix는 원소가 double로 표현되는 3X3 matrix로 구현된다. 마지막 줄(row)은 항상 0, 0, 1이기 때문에 실제 serialization에서는 마지막 줄은 빠진다. 저장되는 정보는 다음과 같다.
표 85: matrix 정보
표 86: 테두리 선 정보
표 87: 테두리 선 정보 속성
표 88: Outline style
표 89: 그리기 개체 글상자용 텍스트 정보
표 90: 그리기 개체 글상자용 텍스트 속성
####### 4.3.9.2.2. 선 개체
Tag ID: HWPTAG_SHAPE_COMPONENT_LINE
구현 상태
- 구현 완료
- 테스트 파일(
noori.hwp)에 SHAPE_COMPONENT_LINE 레코드가 없어 실제 파일로 테스트되지 않음
표 91: 선 개체
표 92: 선 개체 속성
####### 4.3.9.2.3. 사각형 개체
Tag ID: HWPTAG_SHAPE_COMPONENT_RECTANGLE
구현 상태
- 구현 완료
- 테스트 파일(
noori.hwp)에 SHAPE_COMPONENT_RECTANGLE 레코드가 없어 실제 파일로 테스트되지 않음
표 93: 사각형 개체
표 94: 사각형 개체 속성
####### 4.3.9.2.4. 타원 개체
Tag ID: HWPTAG_SHAPE_COMPONENT_ELLIPSE
구현 상태
- 구현 완료
- 테스트 파일(
noori.hwp)에 SHAPE_COMPONENT_ELLIPSE 레코드가 없어 실제 파일로 테스트되지 않음
표 95: 타원 개체
표 96: 타원 개체 속성
표 97: 타원/호 개체 속성의 속성
####### 4.3.9.2.5. 다각형 개체
Tag ID: HWPTAG_SHAPE_COMPONENT_POLYGON
표 98: 다각형 개체
표 99: 다각형 개체 속성
####### 4.3.9.2.6. 호 개체
Tag ID: HWPTAG_SHAPE_COMPONENT_ARC
표 100: 호 개체
표 101: 호 개체 속성
####### 4.3.9.2.7. 곡선 개체
Tag ID: HWPTAG_SHAPE_COMPONENT_CURVE
표 102: 곡선 개체
표 103: 곡선 개체 속성
4.3.9.3. 호글 수식 개체
Tag ID: HWPTAG_EQEDIT
표 104: 수식 개체
표 105: 수식 개체 속성
*호글 수식 스크립트는 EQN 스크립트 호환이며 자세한 스펙은 뒤에 추가
4.3.9.4. 그림 개체(HWPTAG_SHAPE_COMPONENT_PICTURE)
Tag ID: HWPTAG_SHAPE_COMPONENT_PICTURE
구현 참고사항 / Implementation Notes
레벨 정보 / Level Information
스펙 문서 표 5에서는 HWPTAG_SHAPE_COMPONENT와 HWPTAG_SHAPE_COMPONENT_PICTURE 모두 레벨 1로 표시되어 있습니다. 하지만 실제 HWP 파일에서는 두 가지 경우가 모두 가능합니다:
- 레벨 1 (형제 관계):
SHAPE_COMPONENT와SHAPE_COMPONENT_PICTURE가 같은 레벨 형제로 나타나는 경우 - 레벨 3 (부모-자식 관계):
SHAPE_COMPONENT_PICTURE가SHAPE_COMPONENT의 자식(level 3)으로 파싱되는 경우
이는 스펙 문서 표 106에서 SHAPE_COMPONENT_PICTURE가 SHAPE_COMPONENT와 동일한 "개체 요소 공통 속성(표 83)"을 포함하기 때문에, 실제 바이너리 구조에서 SHAPE_COMPONENT_PICTURE가 SHAPE_COMPONENT의 자식으로 중첩될 수 있기 때문입니다.
파서 구현 / Parser Implementation
파서 구현 시 SHAPE_COMPONENT의 children을 재귀적으로 처리하도록 구현해야 합니다. SHAPE_COMPONENT에 children 필드를 추가하여, SHAPE_COMPONENT_PICTURE가 자식으로 올 경우 이를 포함할 수 있도록 해야 합니다. 이렇게 하면 레벨 1과 레벨 3 두 경우 모두 올바르게 처리할 수 있습니다.
표 106: 그림 개체
표 107: 그림 개체 속성
표 108: 그림 효과 속성
표 109: 그림자 효과 속성
표 110: 네온 효과 속성
표 111: 부드러운 가장자리 효과 속성
표 112: 반사 효과 속성
표 113: 색상 속성
표 114: 색상 효과 속성
표 115: 색상 효과 종류
표 116: 그림 추가 속성
4.3.9.5. OLE 개체(HWPTAG_SHAPE_COMPONENT_OLE)
Tag ID: HWPTAG_SHAPE_COMPONENT_OLE
구현 상태
- 구현 완료
- 테스트 파일(
noori.hwp)에 SHAPE_COMPONENT_OLE 레코드가 없어 실제 파일로 테스트되지 않음
표 117: OLE 개체
표 118: OLE 개체 속성
표 119: OLE 개체 속성의 속성
⚠️ 실제 구현 시 주의사항 (Implementation Notes)
표 119에서 bit 16-21은 "개체 종류"를 나타낸다고 명시되어 있으나, 실제로 속성 필드는 UINT16 (16비트) 타입입니다.
UINT16은 16비트이므로 bit 16-21은 이 필드에 존재하지 않습니다. 실제 구현에서는:
- bit 0-7: drawing aspect
- bit 8: has moniker
- bit 9-15: baseline
만약 "개체 종류" 정보가 필요하다면, 이후 데이터 필드에서 별도로 읽어야 할 수 있습니다.
4.3.9.6. 차트 개체
차트 개체는 본문에 OLE 개체로 저장되며, 그 내용은 OLE Compound file에 저장된다.
차트 파일의 최상위 스토리지는 "Contents" 또는 "OOXMLChartContents" 스트림이 될 수 있다.
구버전 한글(한글 Neo) 차트는 "Contents" 스트림만 사용한다.
한글 2018은 OOXML 차트를 지원하며, "OOXMLChartContents"와 "Contents" 스트림 모두에 저장한다.
한글 2018에서 차트의 "Contents" 스트림은 OOXML 차트를 구버전 한글 Neo 형식으로 변환하기 위한 백업 데이터 역할을 한다.
"Contents" 스트림의 내용은 첨부 파일("한글문서파일형식_차트_revision1.2_원본.hwp")을 참조한다.
"OOXMLChartContents" 스트림은 MS OOXML 차트 저장용이며, 최상위 요소는 "chartSpace"이다. 그 내용은 ISO/IEC 29500 또는 ECMA 376의 DrawingML Chart 섹션을 참조한다.
4.3.9.7. 묶음 개체(HWPTAG_SHAPE_COMPONENT_CONTAINER)
Tag ID: HWPTAG_SHAPE_COMPONENT_CONTAINER
구현 상태
- 구현 완료
- 테스트 파일(
noori.hwp)에 SHAPE_COMPONENT_CONTAINER 레코드가 없어 실제 파일로 테스트되지 않음
표 120: 묶음 개체
표 121: 묶음 개체 속성
4.3.9.8. 동영상 개체(HWPTAG_VIDEO_TDATA)
Tag ID: HWPTAG_VIDEO_DATA
표 122: 동영상 개체
표 123: 동영상 개체 속성
표 124: 동영상 타입
표 125: 로컬 동영상 속성
표 126: 웹 동영상 속성
4.3.10. 개체 이외의 컨트롤
HWPTAG_CTRL_HEAD부터 시작하며 ctrlid로 각 개체를 확인할 수 있다.
특징 컨트롤은 정보 이외의 문단 리스트를 가질 수 있다.
개체 컨트롤 ID / Object Control IDs
개체 공통 속성(Object Common Properties)을 가지는 컨트롤 ID들입니다. 이들은 표 127에 포함되지 않지만 중요한 컨트롤 ID입니다.
표 127: 개체 이외의 컨트롤과 컨트롤 ID
표 128: 필드 컨트롤 ID
4.3.10.1. 구역 정의
Tag ID: MAKE_4CHID('s', 'e', 'c', 'd')
표 129: 구역 정의
표 130: 구역 정의 속성
####### 4.3.10.1.1. 용지 설정
Tag ID: HWPTAG_PAGE_DEF
표 131: 용지 설정
표 132: 용지 설정 속성
####### 4.3.10.1.2. 각주/미주 모양
Tag ID: HWPTAG_FOOTNOTE_SHAPE
표 133: 각주/미주 모양
표 134: 각주/미주 모양 속성
####### 4.3.10.1.3. 쪽 테두리/배경
Tag ID: HWPTAG_PAGE_BORDER_FILL
표 135: 쪽 테두리/배경
표 136: 쪽 테두리/배경 속성
표 137: 바탕쪽 정보
4.3.10.2. 단 정의
Tag ID: MAKE_4CHID('c', 'o', 'l', 'd')
표 138: 단 정의
표 139: 단 정의 속성
4.3.10.3. 머리말/꼬리말
Tag ID: MAKE_4CHID('h', 'e', 'a', 'd')
문단 리스트를 포함한다.
표 140: 머리말/꼬리말
참고: 가변 길이 처리 / Note: Variable length handling
스펙 문서에는 14바이트로 명시되어 있지만, 실제 파일에서는 가변 길이일 수 있습니다. 레거시 라이브러리들(libhwp, hwpjs.js)의 구현을 보면 다음과 같이 처리합니다:
-
libhwp: 레코드 헤더의 크기(
header.size)와 현재까지 읽은 바이트 수(readAfterHeader)를 비교하여 가변 길이를 처리합니다.applyPage(4바이트)는 항상 읽습니다.if (!sr.isEndOfRecord())또는if (sr.header.size > sr.readAfterHeader)로 체크하여 추가 필드를 읽습니다.
-
hwpjs.js: 주석에 "이때는 사이즈가 8로 아무것도 없음"이라고 명시되어 있어, 컨트롤 ID(4바이트) + 데이터(4바이트) = 8바이트인 경우도 있습니다.
현재 구현의 가변 길이 처리 기준 / Current implementation's variable length handling criteria:
- 최소 4바이트:
applyPage(속성) 필수 - 8바이트 이상:
textWidth읽기 - 12바이트 이상:
textHeight읽기 - 13바이트 이상:
text_ref읽기 - 14바이트 이상:
number_ref읽기
데이터가 없는 필드는 기본값(0)을 사용합니다.
표 141: 머리말/꼬리말 속성
4.3.10.4. 각주/미주
Tag ID: MAKE_4CHID('f', 'o', 'o', 't')
각주/미주는 문단 리스트 외에 속성을 갖지 않는다. 하지만 쓰레기 값이나 불필요한 업데이트를 줄이기 위해 8 byte를 serialize한다.
참고: 실제 구현에서는 다음과 같이 구분하여 사용됩니다:
MAKE_4CHID('f', 'o', 'o', 't')="foot"- 꼬리말 (Footer)MAKE_4CHID('f', 'n', ' ', ' ')="fn "- 각주 (Footnote, 공백 포함)MAKE_4CHID('e', 'n', ' ', ' ')="en "- 미주 (Endnote, 공백 포함)
레거시 라이브러리들(pyhwp, ruby-hwp, hwplib)도 이 구분을 따릅니다.
4.3.10.5. 자동 번호
Tag ID: MAKE_4CHID('a', 'u', 't', 'n')
표 142: 자동 번호
표 143: 자동 번호 속성
4.3.10.6. 새 번호 지정
Tag ID: MAKE_4CHID('n', 'e', 'w', 'n')
표 144: 새 번호 지정
4.3.10.7. 감추기
Tag ID: MAKE_4CHID('p', 'g', 'h', 'd')
표 145: 감추기
4.3.10.8. 홀/짝수 조정
Tag ID: MAKE_4CHID('p', 'g', 'a', 'd')
표 146: 홀/짝수 조정
4.3.10.9. 쪽 번호 위치
Tag ID: MAKE_4CHID('p', 'g', 'n', 'o')
표 147: 쪽 번호 위치
표 148: 쪽 번호 위치 속성
4.3.10.10. 찾아보기 표식
Tag ID: MAKE_4CHID('b', 'k', 'm', 'k')
표 149: 찾아보기 표식
4.3.10.11. 책갈피
Tag ID: HWPTAG_CTRL_DATA
책갈피 컨트롤은 '책갈피 이름'만 정보로 가지고 있으며, 임의의 컨트롤 데이터 HWPTAG_CTRL_DATA로 기록된다.
4.3.10.12. 글자 겹침
Tag ID: MAKE_4CHID('o', 'v', 'e', 'r')
표 150: 글자 겹침
4.3.10.13. 덧말
Tag ID: MAKE_4CHID('c', 'm', 't', 't')
표 151: 덧말
4.3.10.14. 숨은 설명
Tag ID: MAKE_4CHID('h', 'i', 'd', 'e')
문단 리스트만 포함한다. (숨은 설명 데이터는 문서 보안 수준에 따라 무효화될 수 있다.)
4.3.10.15. 필드 시작
Tag ID: MAKE_4CHID('%', '%', '%', '%')
표 152: 필드
표 153: 필드 속성
4.4. 문서 이력 관리
문서 이력 관리에서 사용되는 데이터 레코드는 다음과 같다.
4.4.1. 문서 이력 관리란
한글의 "문서 이력 관리 정보"는 한글 2005(버전 6.5.0.724)와 문서 형식 버전 Doc 5.0.1.7부터 지원된다.
"파일 - 문서 이력 관리" 메뉴에서 표시되고 생성되는 문서 이력 정보가 저장되는 곳이다. 한글 2005부터 2007까지는 이 기능이 '버전 비교(파일 - 버전 비교)'라고 불렸다.
문서 이력 정보의 각 항목은 "히스토리" 또는 "히스토리 아이템"이라고 불리며, 한글 Compound 구조 내부의 "DocHistory"라는 이름의 스토리지 안에 VersionLog%d(%d는 버전을 나타냄)라는 이름의 스트림으로 저장된다. 이 항목들은 압축되고 암호화된다.
히스토리 정보 데이터는 "DocHistory"라는 새로운 스토리지에 저장된다.
4.4.2. 문서 이력 관리 레코드 정보
4.4.2.1. 히스토리 아이템 정보 시작
Tag ID: HISTORY_RECORD_TYPE_STAG (0x10)
표 154: 히스토리 아이템 정보 시작
flag: 이 flag는 각 아이템에 포함된 레코드를 나타낸다:
HISTORY_INFO_FLAG_VERSION (0x01): Version 존재HISTORY_INFO_FLAG_DATE (0x02): Date 존재HISTORY_INFO_FLAG_WRITER (0x04): Writer 존재HISTORY_INFO_FLAG_DESCRIPTION (0x08): Description 존재HISTORY_INFO_FLAG_DIFFDATA (0x10): Diff Data 존재HISTORY_INFO_FLAG_LASTDOCDATA: 최근 문서 존재 (기록되지 않음, 선택적)HISTORY_INFO_FLAG_LOCK (0x40): 현재 History Item Lock 상태
option: 버전 정보와 관련된 공통 옵션:
HWPVERSION_AUTOSAVE (0x00000001): 문서 저장 시 자동 저장
4.4.2.2. 히스토리 아이템 정보 끝
Tag ID: HISTORY_RECORD_TYPE_ETAG (0x11)
표 155: 히스토리 아이템 정보 끝
4.4.2.3. 히스토리 아이템 버전
Tag ID: HISTORY_RECORD_TYPE_VERSION (0x20)
표 156: 히스토리 아이템 버전
4.4.2.4. 히스토리 날짜
Tag ID: HISTORY_RECORD_TYPE_DATE (0x21)
표 157: 히스토리 날짜
4.4.2.5. 히스토리 작성자
Tag ID: HISTORY_RECORD_TYPE_WRITER (0x22)
표 158: 히스토리 작성자
4.4.2.6. 히스토리 설명
Tag ID: HISTORY_RECORD_TYPE_DESCRIPTION (0x23)
표 159: 히스토리 설명
4.4.2.7. 비교 정보
Tag ID: HISTORY_RECORD_TYPE_DIFFDATA (0x30)
표 160: 비교 정보
4.4.2.8. 가장 마지막 최근 문서
Tag ID: HISTORY_RECORD_TYPE_LASTDOCDATA (0x31)
표 161: 가장 마지막 최근 문서
히스토리 아이템 저장 시 시작은 HISTORY_RECORD_TYPE_STAG 레코드로 시작하며, 아이템 내용의 끝은 HISTORY_RECORD_TYPE_ETAG 레코드로 종료한다.
변경 사항 이력
revision 1.3: 20181108
- 참고 문헌
- 차트 개체
- 동영상 개체
- 그림 추가 속성
- 파일 인식 정보 추가
- 수식 개체 속성 추가
- 글머리표 추가
- 필드 컨트롤 ID 추가
- 개체 공통 속성 수정
- 문단번호 수정
- 내용 중 일부 오타 수정
revision 1.2: 20141009
- 한글 문서 파일 구조 파트별로 구성
- 5.0 일부 상세 내용 추가
- 내용 중 일부 오타 수정
- 3.0, HWPML 제외
revision 1.1: 20110124
- 저작권 내용 수정
- 내용 중 일부 오타 수정
revision 1.0: 20100701
- 한글 문서 파일 형식 공개
한글 문서 파일 구조 5.0
발행처 (주)한글과컴퓨터
주소:
- (우) 463-400
- 경기도 성남시 분당구 대왕판교로
- 644번길 49 한컴타워 10층
- 전화: (031) 627-7000
- 팩스: (031) 627-7709