logo
HWPJS
  • 가이드
  • API
  • 명세서
  • 로드맵
  • 백로그
    명세서
    HWP 자료형 (Types)
    HWP 3.0 / HWPML 형식
    HWP 5.0
    배포용 문서 형식
    한글 문서 파일 형식 - 수식
    차트 형식
    Previous page명세서Next pageHWP 3.0 / HWPML 형식

    #HWP 자료형 (Types)

    HWP 5.0 스펙 문서의 "표 1: 자료형"에 정의된 모든 자료형을 Rust 타입으로 매핑한 것입니다.

    #개요

    hwp-core 라이브러리는 HWP 파일을 파싱할 때 스펙 문서의 자료형을 그대로 사용합니다. 이는 스펙 문서와 코드의 1:1 매핑을 유지하여 유지보수성을 높이기 위함입니다.

    모든 자료형 정의는 crates/hwp-core/src/types.rs에 위치합니다.

    #JSON 직렬화 타입

    HWP 자료형이 JSON으로 직렬화될 때의 타입은 다음과 같습니다:

    Rust 타입JSON 타입예시
    BYTEnumber0, 255
    WORDnumber0, 65535
    DWORDnumber0, 4294967295
    WCHARnumber0, 65535
    HWPUNITnumber7200, 14400
    SHWPUNITnumber-7200, 14400
    COLORREFnumber16711680 (0x00FF0000 = 빨간색)
    UINT8, UINT16, UINT32number0, 255, 65535, 4294967295
    INT8, INT16, INT32number-128, -32768, -2147483648
    HWPUNIT16number-32768, 32767
    Vec<u8> (BYTE stream)array of number[0, 1, 2, ...]
    Stringstring"HWP Document File"

    특수 직렬화:

    • HWPUNIT, SHWPUNIT, COLORREF는 구조체이지만 JSON에서는 숫자로 직렬화됩니다.
    • FileHeader.version은 문자열로 직렬화됩니다 (예: "5.0.3.0").
    • FileHeader.document_flags와 FileHeader.license_flags는 문자열 배열로 직렬화됩니다 (예: ["compressed", "encrypted"]).

    #기본 자료형

    #BYTE

    스펙 문서 매핑: 표 1 - BYTE

    • 길이: 1 바이트
    • 부호: 없음
    • 범위: 0~255
    • Rust 타입: u8
    • 설명: 부호 없는 한 바이트
    pub type BYTE = u8;

    #WORD

    스펙 문서 매핑: 표 1 - WORD

    • 길이: 2 바이트
    • 부호: 없음
    • Rust 타입: u16
    • 설명: 16비트 컴파일러에서 'unsigned int'에 해당
    pub type WORD = u16;

    #DWORD

    스펙 문서 매핑: 표 1 - DWORD

    • 길이: 4 바이트
    • 부호: 없음
    • Rust 타입: u32
    • 설명: 16비트 컴파일러에서 'unsigned long'에 해당
    pub type DWORD = u32;

    #WCHAR

    스펙 문서 매핑: 표 1 - WCHAR

    • 길이: 2 바이트
    • 부호: 없음
    • Rust 타입: u16
    • 설명: 한글의 기본 코드로 유니코드 기반 문자. 한글의 내부 코드로 표현된 문자 한 글자. 한글, 영문, 한자를 비롯해 모든 문자가 2 바이트의 일정한 길이를 가진다.
    pub type WCHAR = u16;

    #부호 있는 정수형

    #INT8

    스펙 문서 매핑: 표 1 - INT8

    • 길이: 1 바이트
    • 부호: 있음
    • Rust 타입: i8
    • 설명: 'signed_int8'에 해당
    pub type INT8 = i8;

    #INT16

    스펙 문서 매핑: 표 1 - INT16

    • 길이: 2 바이트
    • 부호: 있음
    • Rust 타입: i16
    • 설명: 'signed_int16'에 해당
    pub type INT16 = i16;

    #INT32

    스펙 문서 매핑: 표 1 - INT32

    • 길이: 4 바이트
    • 부호: 있음
    • Rust 타입: i32
    • 설명: 'signed_int32'에 해당
    pub type INT32 = i32;

    #부호 없는 정수형

    #UINT8

    스펙 문서 매핑: 표 1 - UINT8

    • 길이: 1 바이트
    • 부호: 없음
    • Rust 타입: u8
    • 설명: 'unsigned_int8'에 해당
    pub type UINT8 = u8;

    #UINT16

    스펙 문서 매핑: 표 1 - UINT16

    • 길이: 2 바이트
    • 부호: 없음
    • Rust 타입: u16
    • 설명: 'unsigned_int16'에 해당
    pub type UINT16 = u16;

    #UINT32 / UINT

    스펙 문서 매핑: 표 1 - UINT32(=UINT)

    • 길이: 4 바이트
    • 부호: 없음
    • Rust 타입: u32
    • 설명: 'unsigned_int32'에 해당. UINT는 UINT32와 동일
    pub type UINT32 = u32;
    pub type UINT = UINT32;

    #HWP 특수 자료형

    #HWPUNIT

    스펙 문서 매핑: 표 1 - HWPUNIT

    • 길이: 4 바이트
    • 부호: 없음
    • Rust 타입: HWPUNIT (구조체)
    • 설명: 1/7200인치로 표현된 한글 내부 단위. 문자의 크기, 그림의 크기, 용지 여백 등 문서 구성 요소의 크기를 표현

    사용 예시:

    • 가로 2인치 x 세로 1인치 그림 → 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

    #SHWPUNIT

    스펙 문서 매핑: 표 1 - SHWPUNIT

    • 길이: 4 바이트
    • 부호: 있음
    • Rust 타입: SHWPUNIT (구조체)
    • 설명: 1/7200인치로 표현된 한글 내부 단위 (부호 있는 버전). HWPUNIT의 부호 있는 버전

    메서드:

    • 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);

    #HWPUNIT16

    스펙 문서 매핑: 표 1 - HWPUNIT16

    • 길이: 2 바이트
    • 부호: 있음
    • Rust 타입: i16
    • 설명: INT16과 같음
    pub type HWPUNIT16 = i16;

    #COLORREF

    스펙 문서 매핑: 표 1 - COLORREF

    • 길이: 4 바이트
    • 부호: 없음
    • Rust 타입: COLORREF (구조체)
    • 설명: RGB값(0x00bbggrr)을 십진수로 표시
      • rr: red 1 byte
      • gg: green 1 byte
      • bb: 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

    #기타

    #BYTE stream

    스펙 문서 매핑: 표 1 - BYTE stream

    • 길이: 가변
    • 설명: 일련의 BYTE로 구성됨. 본문 내에서 다른 구조를 참조할 경우에 사용됨.

    Rust에서는 Vec<u8> 또는 &[u8]로 표현됩니다.

    #자료형 매핑 표

    스펙 문서 자료형Rust 타입길이부호설명
    BYTEu81없음부호 없는 한 바이트(0~255)
    WORDu162없음16비트 unsigned int
    DWORDu324없음32비트 unsigned long
    WCHARu162없음유니코드 기반 문자
    HWPUNITHWPUNIT4없음1/7200인치 단위
    SHWPUNITSHWPUNIT4있음1/7200인치 단위 (signed)
    UINT8u81없음unsigned int8
    UINT16u162없음unsigned int16
    UINT32u324없음unsigned int32
    UINTu324없음UINT32와 동일
    INT8i81있음signed int8
    INT16i162있음signed int16
    INT32i324있음signed int32
    HWPUNIT16i162있음INT16과 같음
    COLORREFCOLORREF4없음RGB 값 (0x00bbggrr)
    BYTE streamVec<u8> / &[u8]가변없음일련의 BYTE

    #사용 원칙

    1. 스펙 문서와 1:1 매핑: 스펙 문서의 자료형 이름을 그대로 사용
    2. 타입 안전성: 도메인 특화 타입(HWPUNIT, COLORREF 등)은 구조체로 정의하여 타입 안전성 확보
    3. 유지보수성: 스펙 문서 변경 시 타입 정의만 수정하면 컴파일러가 영향 범위 자동 감지

    #플래그 상수

    #Document Flags

    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"]
    }

    #License Flags

    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"]
    }

    #제어 문자 파라미터

    #InlineControlParam

    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)
    • 설명: 탭의 너비를 1/7200인치 단위로 표현
    • 파싱: 파라미터의 첫 4바이트를 UINT32로 읽어서 HWPUNIT으로 변환
    • JSON 예시:
    {
      "inline_control_params": [
        [16, { "width": 4000 }]
      ]
    }

    #chid: Option<String>

    • 제어 문자: FIELD_END (0x04), TITLE_MARK (0x08), 기타 INLINE 타입
    • 설명: 스펙 문서에 명시되지 않은 식별자. 정확한 의미는 알 수 없음
    • 파싱: 파라미터의 첫 4바이트를 ASCII 문자열로 읽기 시도 (0x20-0x7E 범위의 바이트만 허용)
    • 주의사항:
      • 스펙 문서에 파라미터 구조가 명시되지 않아 정확한 의미를 알 수 없음
      • ASCII로 읽을 수 있는 경우에만 chid 값이 설정됨
      • 바이너리 데이터는 JSON으로 표현할 수 없으므로 저장하지 않음
    • JSON 예시:
    {
      "inline_control_params": [
        [65, { "chid": "klh" }]
      ]
    }

    참고:

    • JSON으로 표현 가능한 의미 있는 값만 저장됩니다
    • 바이너리 데이터는 저장하지 않습니다
    • width와 chid는 제어 문자 타입에 따라 하나만 설정됩니다

    #컨트롤 헤더 데이터 구조

    #FootnoteEndnote

    각주/미주 컨트롤 헤더의 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)

    참고:

    • 스펙 문서에서는 "쓰레기 값이나 불필요한 업데이트를 줄이기 위해 8 byte를 serialize한다"고 명시되어 있지만, 실제 데이터에는 각주/미주 번호 등 유용한 정보가 포함되어 있습니다.
    • 각주 참조 위치(본문)에서 사용되는 번호 정보입니다.

    #HeaderFooter

    머리말/꼬리말 컨트롤 헤더의 데이터 구조입니다.

    스펙 문서 매핑: 표 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:

    • 최소 4바이트: applyPage (속성) 필수
    • 8바이트 이상: textWidth 읽기
    • 12바이트 이상: textHeight 읽기
    • 13바이트 이상: text_ref 읽기
    • 14바이트 이상: number_ref 읽기

    데이터가 없는 필드는 기본값(0)을 사용합니다.

    #ColumnDefinition

    단 정의 컨트롤 헤더의 데이터 구조입니다.

    스펙 문서 매핑: 표 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-31
    • divider_line_type: 단 구분선 종류
    • divider_line_thickness: 단 구분선 굵기
    • divider_line_color: 단 구분선 색상 (COLORREF)

    참고:

    • equal_width가 true이면 column_widths는 빈 배열입니다.
    • attribute_high는 속성의 상위 16비트로, 스펙 문서에 명시되지 않은 추가 속성 정보를 포함할 수 있습니다.

    #참고

    • 스펙 문서: HWP 5.0 명세서 - 표 1: 자료형
    • 소스 코드: crates/hwp-core/src/types.rs
    • 플래그 상수: crates/hwp-core/src/fileheader.rs의 document_flags, license_flags 모듈
    • 제어 문자: crates/hwp-core/src/document/bodytext/control_char.rs
    • 컨트롤 헤더: crates/hwp-core/src/document/bodytext/ctrl_header.rs