Skip to content

text 생성과 markdown 생성 기능을 추가합니다.#237

Closed
nameofSEOKWONHONG wants to merge 18 commits into
edwardkim:develfrom
nameofSEOKWONHONG:main
Closed

text 생성과 markdown 생성 기능을 추가합니다.#237
nameofSEOKWONHONG wants to merge 18 commits into
edwardkim:develfrom
nameofSEOKWONHONG:main

Conversation

@nameofSEOKWONHONG

Copy link
Copy Markdown
Contributor

변경 요약

text 생성과 markdown 생성 기능을 추가합니다.

./rhwp export-text "E:\workspace\rhwp\samples\20250130-hongbo_saved.hwp"
./rhwp export-markdown "E:\workspace\rhwp\samples\20250130-hongbo_saved.hwp"

관련 이슈

closes #

테스트

  • cargo test 통과
  • cargo clippy -- -D warnings 통과
  • 관련 샘플 파일로 SVG 내보내기 확인
  • 웹(WASM) 렌더링 확인 (해당하는 경우)

스크린샷

edwardkim and others added 18 commits April 13, 2026 21:58
Release v0.7.2: VS Code 컨텍스트 메뉴 + 한컴 단축키 + 커맨드 팔레트 + 양식 컨트롤
Release v0.7.2: npm 패키지 배포 준비 — @rhwp/core + @rhwp/editor + VS Code 0.7.2
Windows 환경에서 cfb 크레이트 동작 시 발생하는 역슬래시(\) 경로 구분자 문제를 슬래시(/) 단위로 일일이 변경하여 모든 OS 환경에서 일관된 경로를 보장하도록 함.
Problem
-------
HwpxReader::read_file and read_file_bytes called read_to_string /
read_to_end directly on zip::ZipFile readers with no size ceiling.
ZIP allows extreme compression ratios, so a few-KB .hwpx can claim a
single section.xml entry that expands to multi-GB — OOMing the host.
Any downstream (CLI, WASM, browser extension, VS Code) inherits the
risk since all of them funnel through parse_hwpx → HwpxReader.

Fix
---
Introduce a small read_limited(reader, max) helper using Read::take
so we never allocate past max+1 bytes. Apply:

  - MAX_XML_SIZE     = 32 MB  for text entries (section/header/hpf)
  - MAX_BINDATA_SIZE = 64 MB  for binary entries (images, fonts)

Real-world Korean government HWPX (보도자료·법령·판례) stays well under
these, so legitimate files are unaffected. Over-limit entries surface
as HwpxError::ZipError with "decompression bomb" in the message —
callers see a clean parse error instead of a crash.

Rationale for thresholds
------------------------
MDM (https://github.com/seunghan91/markdown-media) has been running
the same 32/64 MB caps in production across ~500 real HWPX fixtures
with zero false positives; see MDM commit a94b459 for the original
application of this pattern across HWP/HWPX/PDF parser paths.

Tests
-----
Five unit tests in parser::hwpx::reader:
  - under / at / over cap boundary for read_limited
  - a synthetic zip-bomb entry (MAX_XML_SIZE + 1 bytes of 'A',
    compressed to <1 MB) is rejected with ZipError

Full suite: 789 passed, 0 failed (baseline + 5 new).

No public API change: HwpxError variants unchanged, method signatures
unchanged. MAX_XML_SIZE / MAX_BINDATA_SIZE are exposed as pub const
so integrators can read the current caps.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Problem
-------
parser/hwpx/header.rs:293 treats any shape != "NONE" | "3D" as a real
strikethrough:

    cs.strikethrough = !matches!(val.as_str(), "NONE" | "3D");

This is a blacklist of known placeholders. It is correct for the 3D
case Hancom emits today, but fails open: any future placeholder value
Hancom adds (e.g. "4D", "Ghost", internal experiments) will be
misinterpreted as a real strike line, and entire body-text paragraphs
will render with strikethrough.

Fix
---
Flip the predicate to a whitelist of OWPML LineSym2 values that shape.rs
already recognises (SOLID, DASH, DOT, DASH_DOT, DASH_DOT_DOT, LONG_DASH,
CIRCLE, DOUBLE_SLIM, SLIM_THICK, THICK_SLIM, SLIM_THICK_SLIM, WAVE,
DOUBLE_WAVE — 13 entries, same set as the enum mapping immediately
below). Unknown values — including NONE, 3D, and any future Hancom
placeholder — are fail-closed to no-strike.

Extracted into a `pub(crate) fn is_real_strike_shape(&str) -> bool`
so the predicate is independently testable and can be reused if other
parsers (e.g. underline, which has the same blacklist risk) adopt the
same approach later.

Evidence
--------
MDM (https://github.com/seunghan91/markdown-media) hit the exact same
bug earlier this month. Hancom's HWPX exporter writes <hh:strikeout
shape="3D"/> as a placeholder default on body-text charPr definitions.
Treating "anything but NONE" as strike caused press-release bodies
(e.g. "251113 벤처투자 보도자료") to render wrapped in ~~...~~.

Our fix (MDM commit ae15dd8) moved to the whitelist approach and
verified across 21 MOIS HWPX fixtures: zero false strikes remained.
The same logic fits rhwp one-for-one, so we're upstreaming it.

Tests
-----
Five new unit tests in parser::hwpx::header::tests:
  - all 13 valid OWPML LineSym2 shapes → true
  - "NONE" → false
  - "3D" → false (the original bug)
  - fail-closed cases: "4D", "Ghost", "", "solid" (case-sensitive)

Full suite: 789 passed, 0 failed.

No behaviour change for files Hancom currently emits — the set of
shapes that produce strike=true is identical to the old blacklist
path for every value shape.rs knows about. The only difference is
forward-compatibility: unknown future placeholders no longer get
mis-rendered as strike.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…eparator

fix(parser): Windows 환경의 CFB 경로 구분자 오류 수정
…otection

fix(hwpx): cap ZIP entry decompression to defeat zip bombs
…-whitelist

refactor(hwpx): whitelist strikeout shapes instead of blacklist
Release v0.7.3 (라이브러리) / v0.2.0 (확장)
Hotfix v0.2.1 (확장): 매뉴얼 §5.1 누락 버전 보강
라이브러리/확장 이원화 정책에 따라 버전 표기 정리:
- 라이브러리 v0.7.3 (Cargo, npm/core, npm/editor, vscode, studio)
- 확장 v0.2.1 (chrome, safari) — Chrome Web Store / Edge Add-ons 심사 진행 중

문서 갱신:
- README.md / README_EN.md / rhwp-chrome/README.md: 변경 이력 + 향후 예정 + 외부 기여자 6명 누적 명시
- mydocs/orders/20260419.md: v0.2.1 표기로 일관성 정리
- mydocs/plans/task_m100_196.md, working/stage3, report: v0.2.1 표기

스토어 등록 정보 (mydocs/feedback/, mydocs/release/):
- kor_desc_0.2.1.md, eng_desc_0.2.1.md: 한국어/영어 마켓 설명 (HWPX 베타 안내 + 기여자 + PR 번호)
- cert_notes_0.2.1.md: 심사용 Notes for certification (1986 chars)
- add_desc_02.md: 변경 사항 추가용 텍스트
- release_notes_v0.7.3.md: GitHub Release 노트

다음 사이클: v0.7.5 통일 (라이브러리 + 확장 단일 버전 정책)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
docs + CodeQL fix: v0.7.3 회고 보고서 + build.mjs alert edwardkim#16 fix
2026-04-21 oosmetrics.com 독창성(originality) 지표에서 rhwp 가
WebAssembly · Editors 두 카테고리 Top 2 달성.

- README.md · README_EN.md 상단에 별도 줄로 성과 배지 2개 추가
- 기술 배지(CI/Demo/npm/VSCode/License/Rust/WASM) 와 시각 분리

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
한글판 README.md 와 영문판 README_EN.md 의 섹션 구조·내용을 1:1 일치시킴.

주요 변경:
- Roadmap + Milestones 섹션을 상단(로드맵/이정표 위치) 으로 이동
- v0.5.0 ~ v0.7.x 이정표에 v0.2.1 사이클 전체 반영 (Chrome/Edge 심사 통과, PR edwardkim#213/edwardkim#215/edwardkim#221/edwardkim#169/edwardkim#209/edwardkim#214/edwardkim#224/edwardkim#181)
- rhwp-firefox (v0.1.1 AMO 준비) + rhwp-safari (v0.2.1) 섹션 추가
- 기여자 감사 목록 확장: @seo-rii, @planet6897, @yl-star7 추가 (9명)
- Features: OLE/Chart/EMF native rendering 항목 추가 (edwardkim#221)
- Project Structure: src/emf/, src/ooxml_chart/, rhwp-firefox/, rhwp-shared/ 반영
- Trademark 섹션 신규 (한글판 동일 위치)
- AI 페어 프로그래밍 섹션: Git Workflow / Task Workflow / Debugging Protocol / Documentation Rules 완전 반영
- 로드맵 링크를 mydocs/eng/report/rhwp-milestone.md 로 보정
- 테스트 수치 783 → 935

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
특정 상용 제품 기여 의사 전달을 계기로, 프로젝트 문서의 경쟁 비교 · 성능 비교 ·
렌더링 분석 문맥에서 해당 제품명을 일반화 표현으로 교체.

변경 원칙:
- A (사용자 인용, report/x_hwp_viewer_voices.md): 원문 보존, 건드리지 않음
- B (프로젝트 문서 비교·주장): "일부 상용 제품" / "a commercial web office" / "일부 상용 웹오피스"
- C (archives 포함): "경쟁사" → "일부 상용 제품" 적용
- D (영문판): 한글판과 동일하게 동시 수정

대상 파일 (21):
- mydocs/tech/: project_vision, webgian_replacement_strategy, canvas_rendering_analysis,
  font_metrics_size_comparison, incremental_relayout_design, direct_printing_guideline
- mydocs/manual/hyper_waterfall_docs_guide.md
- mydocs/plans/archives/: task_124, task_126
- mydocs/working/archives/: task_123_report, task_125_step1234_done
- mydocs/eng/ 영문판 10개 (한글판 1:1 대응)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@nameofSEOKWONHONG

Copy link
Copy Markdown
Contributor Author

@edwardkim

main에서 devel로 잘 못 병합 요청 되었습니다.
취소될 경우 devel에서 다시 요청 드리도록 하겠습니다.
감사합니다.

@edwardkim

Copy link
Copy Markdown
Owner

안녕하세요 🙏

@nameofSEOKWONHONG 님, 이미 상황을 인지하시고 정중하게 알려주셔서 감사합니다. 말씀하신 대로 처리 도와드리겠습니다.

먼저 꼭 말씀드리고 싶은 것

기능 자체는 정말 환영하는 기여입니다:

  • rhwp export-text — HWP에서 순수 텍스트 추출
  • rhwp export-markdown — HWP → 마크다운 변환

이 두 기능은 rhwp를 AI 파이프라인의 입력으로 쓸 때 반드시 필요한 기능입니다. Claude/GPT에 HWP 내용을 전달하거나, HWP 문서를 블로그/위키에 통합할 때 곧바로 활용됩니다. 제가 보기엔 rhwp의 출력 채널을 한 단계 확장하는 귀중한 기여입니다.

현재 PR 처리

말씀하신 대로 이번 PR은 close하겠습니다. base를 main으로 요청하신 것이 원인이어서, 재작업이 필요합니다.

재제출 시 참고해주세요

Fork에서 작업하실 때 도움이 될 만한 체크리스트입니다:

1. Fork를 최신 upstream과 동기화

# upstream 등록 (최초 1회)
git remote add upstream https://github.com/edwardkim/rhwp.git
git fetch upstream

# Fork의 main을 upstream/main과 맞춤
git checkout main
git merge upstream/main
git push origin main

# 작업은 upstream/devel 기준으로 — feature 브랜치 생성
git checkout upstream/devel
git checkout -b feature/export-text-markdown

2. 본인 작업만 담은 커밋

이번 PR에는 이미 merge된 다른 PR의 커밋(#134, #135, #152, #153, #154, #200, #201, #203 등)이 17개나 포함되어 diff가 커졌습니다. 깨끗한 feature 브랜치에서 작업하시면 본인 커밋만 1~3개로 정리됩니다.

3. base는 devel

PR 생성 시 반드시 edwardkim:devel 로 대상을 설정해주세요. main은 릴리즈 전용 브랜치입니다.

4. Clippy 미통과

체크리스트에 cargo clippy -- -D warnings 통과로 체크되어 있으나 실제 CI는 실패했습니다. src/ios_ffi.rs의 경고는 다른 PR에서 유입된 것이므로, 최신 devel로 rebase하시면 해결됩니다. 재제출 전에 로컬에서 cargo clippy -- -D warnings를 직접 실행해서 통과 확인 부탁드립니다.

5. 관련 이슈 등록 (권장)

rhwp는 Hyper-Waterfall 방법론에 따라 Issue 등록 → 수행·구현 계획서 → 구현 → PR 순서를 따릅니다. 재제출 전에:

gh issue create --repo edwardkim/rhwp \
  --title "export-text / export-markdown CLI 명령 추가" \
  --body "HWP 문서를 텍스트/마크다운으로 내보내는 CLI 명령..." \
  --milestone "v1.0.0"

PR body의 closes #{이슈번호}로 자동 연결되어 merge 시 이슈가 닫힙니다.


기다리고 있겠습니다

이 기능 정말 필요한 기여입니다. 재제출해주시면 꼼꼼하게 리뷰해드리겠습니다. 혹시 재작업 과정에서 막히시는 부분이 있으면 언제든 코멘트 남겨주세요. 🙏

감사합니다.

— 메인테이너 드림

@edwardkim

Copy link
Copy Markdown
Owner

요청대로 close 처리합니다. devel 대상 새 PR로 재제출 부탁드립니다. 감사합니다! 🙏

@edwardkim edwardkim closed this Apr 22, 2026
edwardkim added a commit that referenced this pull request Apr 22, 2026
- mydocs/pr/archives/pr_237_review.md: base 브랜치 오류 분석 (Fork main → upstream devel)
- mydocs/pr/archives/pr_237_report.md: 작성자 자진 취소 + 정중한 close, 재제출 가이드

기여자 @nameofSEOKWONHONG 의 export-text/export-markdown 기능은 환영 기여.
PR 구조 정리 후 재제출 대기.
edwardkim added a commit that referenced this pull request Apr 22, 2026
기여자 @planet6897 이 PR #235에 포함해 제출한 기존 섹션(Task #229 Fix / #240)은
그대로 보존하고, 오늘의 메인테이너 활동을 별도 섹션으로 추가:

- PR #234 (close, 재제출 요청) / #235 (merge) / #237 (작성자 자진 취소) 처리 요약
- mydocs/pr/ 폴더 체계 신설 + CLAUDE.md/CONTRIBUTING.md 규칙 보완
- 트러블슈팅 hwp_letter_spacing_compensation.md 추가
- Task #157 시작 (재현 확인, LAYOUT_OVERFLOW 4건 관측)
nameofSEOKWONHONG pushed a commit to nameofSEOKWONHONG/rhwp that referenced this pull request Apr 24, 2026
edwardkim pushed a commit to nameofSEOKWONHONG/rhwp that referenced this pull request Apr 26, 2026
edwardkim added a commit to nameofSEOKWONHONG/rhwp that referenced this pull request Apr 26, 2026
작성자 산출물의 보고서 내부 링크가 feature_*.md 패턴이었으나 실제
파일명은 task_m100_237*.md 로 작성됨. 메인테이너 측에서 링크 정정.

A2 (page_count == 0 가드) 는 작성자가 본인 PR 본문에서 "미구현"
이라 자가 보고했으나 실제 코드 (src/main.rs:545, 665) 에는 이미
early return 가드가 있어 underflow 발생 가능성 없음 — 추가 수정
불필요.

closes edwardkim#237

Co-Authored-By: SEOKWON HONG <nameofSEOKWONHONG@users.noreply.github.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
edwardkim added a commit that referenced this pull request Apr 26, 2026
edwardkim added a commit that referenced this pull request Apr 26, 2026
@nameofSEOKWONHONG 의 PR 인수 (작업지시자 결정 — 작성자 응답 3d+).
cherry-pick + A1 보강 (보고서 링크) + admin merge (commit da55552).

A2 (page_count == 0 가드) 는 점검 결과 이미 정상 (early return) —
추가 수정 불필요.

Co-Authored-By: SEOKWON HONG <nameofSEOKWONHONG@users.noreply.github.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants