HWP 5.0 스펙 문서의 "표 1: 자료형"에 정의된 모든 자료형을 Rust 타입으로 매핑한 것입니다.
hwp-core 라이브러리는 HWP 파일을 파싱할 때 스펙 문서의 자료형을 그대로 사용합니다. 이는 스펙 문서와 코드의 1:1 매핑을 유지하여 유지보수성을 높이기 위함입니다.
모든 자료형 정의는 crates/hwp-core/src/types.rs에 위치합니다.
HWP 자료형이 JSON으로 직렬화될 때의 타입은 다음과 같습니다:
| Rust 타입 | JSON 타입 | 예시 |
|---|---|---|
BYTE | number | 0, 255 |
WORD | number | 0, 65535 |
DWORD | number | 0, 4294967295 |
WCHAR | number | 0, 65535 |
HWPUNIT | number | 7200, 14400 |
SHWPUNIT | number | -7200, 14400 |
COLORREF | number | 16711680 (0x00FF0000 = 빨간색) |
UINT8, UINT16, UINT32 | number | 0, 255, 65535, 4294967295 |
INT8, INT16, INT32 | number | -128, -32768, -2147483648 |
HWPUNIT16 | number | -32768, 32767 |
Vec<u8> (BYTE stream) | array of number | [0, 1, 2, ...] |
String | string | "HWP Document File" |
특수 직렬화:
HWPUNIT, SHWPUNIT, COLORREF는 구조체이지만 JSON에서는 숫자로 직렬화됩니다.FileHeader.version은 문자열로 직렬화됩니다 (예: "5.0.3.0").FileHeader.document_flags와 FileHeader.license_flags는 문자열 배열로 직렬화됩니다 (예: ["compressed", "encrypted"]).스펙 문서 매핑: 표 1 - BYTE
u8pub type BYTE = u8;스펙 문서 매핑: 표 1 - WORD
u16pub type WORD = u16;스펙 문서 매핑: 표 1 - DWORD
u32pub type DWORD = u32;스펙 문서 매핑: 표 1 - WCHAR
u16pub type WCHAR = u16;스펙 문서 매핑: 표 1 - INT8
i8pub type INT8 = i8;스펙 문서 매핑: 표 1 - INT16
i16pub type INT16 = i16;스펙 문서 매핑: 표 1 - INT32
i32pub type INT32 = i32;스펙 문서 매핑: 표 1 - UINT8
u8pub type UINT8 = u8;스펙 문서 매핑: 표 1 - UINT16
u16pub type UINT16 = u16;스펙 문서 매핑: 표 1 - UINT32(=UINT)
u32pub type UINT32 = u32;
pub type UINT = UINT32;스펙 문서 매핑: 표 1 - HWPUNIT
HWPUNIT (구조체)사용 예시:
HWPUNIT(14400) x HWPUNIT(7200)메서드:
to_inches() -> f64: 인치 단위로 변환from_inches(inches: f64) -> Self: 인치 단위에서 생성value() -> u32: 내부 값 반환#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
pub struct HWPUNIT(pub u32);
// 사용 예시
let width = HWPUNIT::from_inches(2.0); // 2인치
let inches = width.to_inches(); // 2.0스펙 문서 매핑: 표 1 - SHWPUNIT
SHWPUNIT (구조체)메서드:
to_inches() -> f64: 인치 단위로 변환from_inches(inches: f64) -> Self: 인치 단위에서 생성value() -> i32: 내부 값 반환#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
pub struct SHWPUNIT(pub i32);스펙 문서 매핑: 표 1 - HWPUNIT16
i16pub type HWPUNIT16 = i16;스펙 문서 매핑: 표 1 - COLORREF
COLORREF (구조체)rr: red 1 bytegg: green 1 bytebb: blue 1 byte메서드:
rgb(r: u8, g: u8, b: u8) -> Self: RGB 값으로 생성r() -> u8: Red 값 추출g() -> u8: Green 값 추출b() -> u8: Blue 값 추출value() -> u32: 내부 값 반환#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub struct COLORREF(pub u32);
// 사용 예시
let red = COLORREF::rgb(255, 0, 0); // 빨간색
let r = red.r(); // 255
let g = red.g(); // 0
let b = red.b(); // 0스펙 문서 매핑: 표 1 - BYTE stream
Rust에서는 Vec<u8> 또는 &[u8]로 표현됩니다.
| 스펙 문서 자료형 | Rust 타입 | 길이 | 부호 | 설명 |
|---|---|---|---|---|
| BYTE | u8 | 1 | 없음 | 부호 없는 한 바이트(0~255) |
| WORD | u16 | 2 | 없음 | 16비트 unsigned int |
| DWORD | u32 | 4 | 없음 | 32비트 unsigned long |
| WCHAR | u16 | 2 | 없음 | 유니코드 기반 문자 |
| HWPUNIT | HWPUNIT | 4 | 없음 | 1/7200인치 단위 |
| SHWPUNIT | SHWPUNIT | 4 | 있음 | 1/7200인치 단위 (signed) |
| UINT8 | u8 | 1 | 없음 | unsigned int8 |
| UINT16 | u16 | 2 | 없음 | unsigned int16 |
| UINT32 | u32 | 4 | 없음 | unsigned int32 |
| UINT | u32 | 4 | 없음 | UINT32와 동일 |
| INT8 | i8 | 1 | 있음 | signed int8 |
| INT16 | i16 | 2 | 있음 | signed int16 |
| INT32 | i32 | 4 | 있음 | signed int32 |
| HWPUNIT16 | i16 | 2 | 있음 | INT16과 같음 |
| COLORREF | COLORREF | 4 | 없음 | RGB 값 (0x00bbggrr) |
| BYTE stream | Vec<u8> / &[u8] | 가변 | 없음 | 일련의 BYTE |
HWPUNIT, COLORREF 등)은 구조체로 정의하여 타입 안전성 확보FileHeader.document_flags는 비트 플래그로, JSON에서는 활성화된 플래그의 상수 문자열 배열로 직렬화됩니다.
스펙 문서 매핑: 표 3 - 속성 (첫 번째 DWORD)
| 비트 | 상수 | 설명 |
|---|---|---|
| 0 | "compressed" | 압축 여부 |
| 1 | "encrypted" | 암호 설정 여부 |
| 2 | "distribution" | 배포용 문서 여부 |
| 3 | "script" | 스크립트 저장 여부 |
| 4 | "drm" | DRM 보안 문서 여부 |
| 5 | "xml_template" | XMLTemplate 스토리지 존재 여부 |
| 6 | "history" | 문서 이력 관리 존재 여부 |
| 7 | "electronic_signature" | 전자 서명 정보 존재 여부 |
| 8 | "certificate_encryption" | 공인 인증서 암호화 여부 |
| 9 | "signature_preview" | 전자 서명 예비 저장 여부 |
| 10 | "certificate_drm" | 공인 인증서 DRM 보안 문서 여부 |
| 11 | "ccl" | CCL 문서 여부 |
| 12 | "mobile_optimized" | 모바일 최적화 여부 |
| 13 | "privacy_security" | 개인 정보 보안 문서 여부 |
| 14 | "track_change" | 변경 추적 문서 여부 |
| 15 | "kogl" | 공공누리(KOGL) 저작권 문서 |
| 16 | "video_control" | 비디오 컨트롤 포함 여부 |
| 17 | "table_of_contents" | 차례 필드 컨트롤 포함 여부 |
JSON 예시:
{
"document_flags": ["compressed"]
}FileHeader.license_flags는 비트 플래그로, JSON에서는 활성화된 플래그의 상수 문자열 배열로 직렬화됩니다.
스펙 문서 매핑: 표 3 - 속성 (두 번째 DWORD)
| 비트 | 상수 | 설명 |
|---|---|---|
| 0 | "ccl_kogl" | CCL, 공공누리 라이선스 정보 |
| 1 | "copy_restricted" | 복제 제한 여부 |
| 2 | "copy_allowed_same_condition" | 동일 조건 하에 복제 허가 여부 (복제 제한인 경우 무시) |
JSON 예시:
{
"license_flags": ["ccl_kogl", "copy_restricted"]
}INLINE 타입 제어 문자는 제어 문자 코드(2 bytes) 이후에 12 bytes의 파라미터 데이터를 가집니다. 이 파라미터는 제어 문자 타입에 따라 다른 의미를 가집니다.
스펙 문서 매핑: 표 6 - 제어 문자 (INLINE 타입)
구조:
pub struct InlineControlParam {
pub width: Option<HWPUNIT>, // TAB 제어 문자용
pub chid: Option<String>, // 기타 INLINE 제어 문자용
}width: Option<HWPUNIT>TAB (0x09){
"inline_control_params": [
[16, { "width": 4000 }]
]
}chid: Option<String>FIELD_END (0x04), TITLE_MARK (0x08), 기타 INLINE 타입chid 값이 설정됨{
"inline_control_params": [
[65, { "chid": "klh" }]
]
}참고:
width와 chid는 제어 문자 타입에 따라 하나만 설정됩니다각주/미주 컨트롤 헤더의 8바이트 데이터 구조입니다.
스펙 문서 매핑: 표 4.3.10.4 - 각주/미주
구조:
pub struct FootnoteEndnote {
pub number: UINT8, // 각주/미주 번호
pub reserved: [UINT8; 5], // 예약 영역 (5 bytes)
pub attribute: UINT8, // 속성 또는 플래그
pub reserved2: UINT8, // 예약 영역
}JSON 예시:
{
"data_type": "footnote_endnote",
"number": 1,
"reserved": [0, 0, 0, 0, 0],
"attribute": 41,
"reserved2": 0
}필드 설명:
number: 각주/미주 번호 (첫 번째 바이트)reserved: 예약 영역 (바이트 1-5)attribute: 속성 또는 플래그 (바이트 6, 현재 41)reserved2: 예약 영역 (바이트 7)참고:
머리말/꼬리말 컨트롤 헤더의 데이터 구조입니다.
스펙 문서 매핑: 표 140 - 머리말/꼬리말, 표 141 - 머리말/꼬리말 속성
구조:
pub struct HeaderFooter {
pub attribute: HeaderFooterAttribute, // 속성 (표 141 참조)
pub text_width: HWPUNIT, // 텍스트 영역의 폭
pub text_height: HWPUNIT, // 텍스트 영역의 높이
pub text_ref: UINT8, // 각 비트가 해당 레벨의 텍스트에 대한 참조를 했는지 여부
pub number_ref: UINT8, // 각 비트가 해당 레벨의 번호에 대한 참조를 했는지 여부
}
pub struct HeaderFooterAttribute {
pub apply_page: ApplyPage, // 머리말이 적용될 범위(페이지 종류)
}
pub enum ApplyPage {
Both, // 양쪽
EvenOnly, // 짝수 쪽만
OddOnly, // 홀수 쪽만
}JSON 예시:
{
"data_type": "header_footer",
"attribute": {
"apply_page": "both"
},
"text_width": 42520,
"text_height": 0,
"text_ref": 0,
"number_ref": 0
}필드 설명:
attribute.apply_page: 머리말이 적용될 범위(페이지 종류)
both: 양쪽 페이지에 적용even_only: 짝수 쪽에만 적용odd_only: 홀수 쪽에만 적용text_width: 텍스트 영역의 폭 (HWPUNIT)text_height: 텍스트 영역의 높이 (HWPUNIT)text_ref: 각 비트가 해당 레벨의 텍스트에 대한 참조를 했는지 여부 (BYTE)number_ref: 각 비트가 해당 레벨의 번호에 대한 참조를 했는지 여부 (BYTE)참고:
text_ref와 number_ref는 각 비트가 해당 레벨(문서 레벨, 구역 레벨 등)의 텍스트/번호에 대한 참조를 했는지 여부를 나타냅니다.가변 길이 처리 / 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:
applyPage (속성) 필수textWidth 읽기textHeight 읽기text_ref 읽기number_ref 읽기데이터가 없는 필드는 기본값(0)을 사용합니다.
단 정의 컨트롤 헤더의 데이터 구조입니다.
스펙 문서 매핑: 표 138 - 단 정의, 표 139 - 단 정의 속성
구조:
pub struct ColumnDefinition {
pub attribute: ColumnDefinitionAttribute,
pub column_spacing: HWPUNIT16,
pub column_widths: Vec<HWPUNIT16>,
pub attribute_high: UINT16,
pub divider_line_type: UINT8,
pub divider_line_thickness: UINT8,
pub divider_line_color: UINT32,
}
pub struct ColumnDefinitionAttribute {
pub column_type: ColumnType, // 단 종류
pub column_count: UINT8, // 단 개수
pub column_direction: ColumnDirection, // 단 방향 지정
pub equal_width: bool, // 단 너비 동일하게 여부
}JSON 예시:
{
"data_type": "column_definition",
"attribute": {
"column_type": "normal",
"column_count": 1,
"column_direction": "left",
"equal_width": true
},
"column_spacing": 0,
"column_widths": [],
"attribute_high": 0,
"divider_line_type": 0,
"divider_line_thickness": 0,
"divider_line_color": 0
}필드 설명:
attribute.column_type: 단 종류 (normal, distributed, parallel)attribute.column_count: 단 개수 (1-255)attribute.column_direction: 단 방향 지정 (left, right, both)attribute.equal_width: 단 너비 동일하게 여부 (bit 12)column_spacing: 단 사이 간격 (HWPUNIT16)column_widths: 단 너비 배열 (단 너비가 동일하지 않을 때만)attribute_high: 속성의 bit 16-31divider_line_type: 단 구분선 종류divider_line_thickness: 단 구분선 굵기divider_line_color: 단 구분선 색상 (COLORREF)참고:
equal_width가 true이면 column_widths는 빈 배열입니다.attribute_high는 속성의 상위 16비트로, 스펙 문서에 명시되지 않은 추가 속성 정보를 포함할 수 있습니다.crates/hwp-core/src/types.rscrates/hwp-core/src/fileheader.rs의 document_flags, license_flags 모듈crates/hwp-core/src/document/bodytext/control_char.rscrates/hwp-core/src/document/bodytext/ctrl_header.rs