결함 요약
`src/renderer/layout/utils.rs:13-25` 의 `find_bin_data` 함수에 잘못된 가드가 추가되어, storage_id ≠ 인덱스인 모든 hwp 파일에서 이미지가 잘못 매칭 됨.
증상
`samples/hwpspec.hwp` 1 페이지의 페이지 표지 이미지가 다른 이미지로 보임
의도된 페이지 표지 (159×247.6mm 의 PNG) 대신 16×13 픽셀의 작은 PNG 가 페이지 전체로 늘려져 렌더링
본 결함은 2026-02-17 의 트러블슈팅 `bin_data_id_index_mapping.md` 와 동일 패턴 — 한 번 정정한 결함이 재발
회귀 origin
해당 커밋이 HWPX 차트의 sparse id (60000+N) 처리를 위해 fallback 을 추가했으나, 가드 `c.id == bin_data_id` 가 일반 HWP 그림의 정상 케이스도 거르는 부작용 발생.
결함 코드
```rust
// src/renderer/layout/utils.rs:13-25 (현재)
pub(crate) fn find_bin_data<'a>(bin_data_content: &'a [BinDataContent], bin_data_id: u16) -> Option<&'a BinDataContent> {
if bin_data_id == 0 {
return None;
}
// 1-indexed 순번으로 먼저 조회 (기존 동작 유지)
if let Some(c) = bin_data_content.get((bin_data_id - 1) as usize) {
if c.id == bin_data_id { // ← 결함: c.id 는 storage_id, bin_data_id 는 인덱스
return Some(c);
}
}
// 실패 시 id 필드로 직접 검색 (HWPX 차트처럼 sparse id 사용 시)
bin_data_content.iter().find(|c| c.id == bin_data_id) // ← 트러블슈팅 #2026-02-17 에서 정정한 그 결함 패턴
}
```
매핑 분석 (hwpspec.hwp)
그림 컨트롤 `bin_data_id`
DocInfo BIN_DATA 인덱스 (1-based)
storage_id
실제 파일
1 (페이지 표지)
1
0x000C = 12
BIN000C.png (1137 bytes — 진짜 표지)
14 (다음 표지)
14
0x000D = 13
BIN000D.bmp (132472 bytes)
`bin_data_id=1` 검색:
인덱스 `(1-1)=0` → `bin_data_content[0]` = (storage_id=12, BIN000C.png)
가드 `c.id (=12) == bin_data_id (=1)` 불일치 → 첫 단계 실패
fallback `iter().find(|c| c.id == 1)` → storage_id=1 인 `BIN0001.bmp` (104 bytes 깨진 데이터) 매칭
16×13 작은 이미지가 페이지 전체로 늘려져 렌더링
정정 방향 — 옵션 B (권장)
가드를 제거하고, 인덱스 범위 밖일 때만 sparse id (HWPX 차트 등) fallback 작동:
```rust
pub(crate) fn find_bin_data<'a>(bin_data_content: &'a [BinDataContent], bin_data_id: u16) -> Option<&'a BinDataContent> {
if bin_data_id == 0 {
return None;
}
// 1-indexed 순번으로 BinDataContent 배열 접근 (storage_id 가드 제거)
if let Some(c) = bin_data_content.get((bin_data_id - 1) as usize) {
return Some(c);
}
// 인덱스 범위 밖 (HWPX 차트 sparse id 60000+N 등) — id 직접 검색
bin_data_content.iter().find(|c| c.id == bin_data_id)
}
```
정정 효과
일반 hwp 그림 (`bin_data_id` ≤ `bin_data_content.len()`): 1-indexed 인덱스 매칭 — 트러블슈팅 #2026-02-17 정정과 동일 동작
HWPX 차트 (`bin_data_id = 60000+N`, 인덱스 범위 밖): fallback 으로 id 직접 검색 — Task 차트/OLE 개체 렌더링 지원 #195 의 의도 보존
영향 범위
모든 `find_bin_data` 호출 지점 (10+ 곳, 자동 정정)
`renderer/layout.rs` (페이지 배경, 일반 그림 등 5+ 곳)
`renderer/layout/{table_layout, table_cell_content, picture_footnote, shape_layout, paragraph_layout}.rs`
WASM API (rhwp-studio, rhwp-vscode 등) 도 같은 함수 경유 — 자동 적용
회귀 검증
검증
기대
`samples/hwpspec.hwp` 1 페이지 페이지 배경
16×13 → 페이지 표지 정상
다른 일반 hwp 샘플 (k-water-rfp, exam_eng 등)
무회귀 (대부분 storage_id == 인덱스 라 영향 없음)
HWPX 차트 샘플
차트 정상 (sparse id 경로)
`cargo test --lib`
회귀 없음
트러블슈팅 갱신
`mydocs/troubleshootings/bin_data_id_index_mapping.md` 에 본 회귀 정황 + 정정 사유 추가:
2026-02-17: 최초 정정 (storage_id 검색 → 인덱스 검색)
2026-04-20: Task 차트/OLE 개체 렌더링 지원 #195 에서 fallback 추가 → 가드 결함 도입
2026-04-28: 본 task 로 재정정 (가드 제거 + sparse id 분기)
처리 절차
CLAUDE.md 의 하이퍼-워터폴 절차로 진행. 단일 파일 수정 + 회귀 테스트 추가.
결함 요약
`src/renderer/layout/utils.rs:13-25` 의 `find_bin_data` 함수에 잘못된 가드가 추가되어, storage_id ≠ 인덱스인 모든 hwp 파일에서 이미지가 잘못 매칭 됨.
증상
회귀 origin
해당 커밋이 HWPX 차트의 sparse id (60000+N) 처리를 위해 fallback 을 추가했으나, 가드 `c.id == bin_data_id` 가 일반 HWP 그림의 정상 케이스도 거르는 부작용 발생.
결함 코드
```rust
// src/renderer/layout/utils.rs:13-25 (현재)
pub(crate) fn find_bin_data<'a>(bin_data_content: &'a [BinDataContent], bin_data_id: u16) -> Option<&'a BinDataContent> {
if bin_data_id == 0 {
return None;
}
// 1-indexed 순번으로 먼저 조회 (기존 동작 유지)
if let Some(c) = bin_data_content.get((bin_data_id - 1) as usize) {
if c.id == bin_data_id { // ← 결함: c.id 는 storage_id, bin_data_id 는 인덱스
return Some(c);
}
}
// 실패 시 id 필드로 직접 검색 (HWPX 차트처럼 sparse id 사용 시)
bin_data_content.iter().find(|c| c.id == bin_data_id) // ← 트러블슈팅 #2026-02-17 에서 정정한 그 결함 패턴
}
```
매핑 분석 (hwpspec.hwp)
`bin_data_id=1` 검색:
정정 방향 — 옵션 B (권장)
가드를 제거하고, 인덱스 범위 밖일 때만 sparse id (HWPX 차트 등) fallback 작동:
```rust
pub(crate) fn find_bin_data<'a>(bin_data_content: &'a [BinDataContent], bin_data_id: u16) -> Option<&'a BinDataContent> {
if bin_data_id == 0 {
return None;
}
// 1-indexed 순번으로 BinDataContent 배열 접근 (storage_id 가드 제거)
if let Some(c) = bin_data_content.get((bin_data_id - 1) as usize) {
return Some(c);
}
// 인덱스 범위 밖 (HWPX 차트 sparse id 60000+N 등) — id 직접 검색
bin_data_content.iter().find(|c| c.id == bin_data_id)
}
```
정정 효과
영향 범위
회귀 검증
트러블슈팅 갱신
`mydocs/troubleshootings/bin_data_id_index_mapping.md` 에 본 회귀 정황 + 정정 사유 추가:
처리 절차
CLAUDE.md 의 하이퍼-워터폴 절차로 진행. 단일 파일 수정 + 회귀 테스트 추가.