Rust에서 손상된 PDF 복구 — XREF 테이블을 처음부터 재구축
Source: Dev.to
문제
일부 PDF는 내용이 없어서가 아니라, 내용을 찾는 위치를 알려주는 인덱스가 손상되어 열리지 않습니다.
그 인덱스가 XREF 테이블이며, 이를 다시 만들 수 있습니다.
XREF 테이블의 모습
xref
0 6
0000000000 65535 f
0000000009 00000 n
0000000058 00000 n
0000000115 00000 n
0000000266 00000 n
0000000496 00000 n
리더가 PDF를 열면 먼저 이 테이블을 읽습니다. 테이블이 없거나 손상되면 PDF가 “열리지 않음” 상태가 됩니다. 내용 객체는 파일에 그대로 존재하므로, 이를 찾아 인덱스를 재구성하면 됩니다.
Rust에서 XREF 테이블 재구성
pub fn rebuild_xref(data: &[u8]) -> Result {
// lopdf can attempt recovery on malformed files
let doc = Document::load_mem(data)
.or_else(|_| recover_document(data))?;
Ok(doc)
}
객체 스캔
pub fn recover_document(data: &[u8]) -> Result {
// Scan the raw bytes for object markers
// Pattern: "N 0 obj" where N is the object number
let mut offsets: Vec = Vec::new();
let obj_pattern = b" 0 obj";
for (i, window) in data.windows(obj_pattern.len()).enumerate() {
if window == obj_pattern {
// Walk back to find the object number
if let Some(num) = extract_obj_num(data, i) {
offsets.push((num, 0, i - num.to_string().len()));
}
}
}
// Reconstruct document from found objects
rebuild_from_offsets(data, offsets)
}
재구성이 도움이 되는 전형적인 상황
- 저장 중 전원 손실 등으로 PDF가 중간에 끊긴 경우
- XREF 체인이 깨진 증분 업데이트가 포함된 PDF
- 오래된 파일에서 XREF를 수동으로 잘못 편집한 경우
- 구조가 잘못된 스캔 출력물
내용 스트림 자체가 손상되어 페이지 데이터가 사라진 경우에는 XREF 재구성으로는 도움이 되지 않습니다. 구조적 복구는 객체가 존재하지만 인덱스가 깨졌을 때만 효과가 있습니다.
제가 테스트한 “열리지 않는” PDF의 약 80 %는 XREF 문제였습니다. 내용은 정상이며, 새로운 인덱스만 필요합니다.
참고 자료
- Hiyoko PDF Vault – https://hiyokoko.gumroad.com/l/HiyokoPDFVault
- Twitter:
@hiyoyok