GithubHelp home page GithubHelp logo

mete0r / pyhwp Goto Github PK

View Code? Open in Web Editor NEW
250.0 18.0 59.0 4.47 MB

.hwp file format v5 parser in python

Home Page: http://pythonhosted.org/pyhwp

License: Other

Python 45.86% Shell 0.62% XSLT 10.20% Makefile 0.37% HTML 12.85% CSS 30.10%

pyhwp's Introduction

pyhwp

HWP Document Format v5 parser & processor.

Features

  • Analyze and extract internal streams out from a HWP Document Format v5 file
  • (Experimental) Conversion to OpenDocument format (.odt) or plain text (.txt)

Installation

from pypi:

virtualenv pyhwp
pyhwp/bin/pip install --pre pyhwp  # Install pyhwp into a virtualenv directory

Or:

pip install --user --pre pyhwp  # Install pyhwp into user's home directory

Requirements

Documentation & Development

Contributors

Maintainer: mete0r

License

Copyright (C) 2010-2023 mete0r <https://github.com/mete0r>

http://www.gnu.org/graphics/agplv3-155x51.png

GNU Affero General Public License v3.0 (text version)

This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.

You should have received a copy of the GNU Affero General Public License along with this program. If not, see <http://www.gnu.org/licenses/>.

Disclosure

This program has been developed in accordance with a public document named "HWP Binary Specification 1.1" published by Hancom Inc.

pyhwp's People

Contributors

mete0r avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

pyhwp's Issues

그림 파일 읽어오기

그림 파일이 임베드된 hwp를 OXT를 통해 libreoffice에서 읽어오면, 그림이 제대로 읽히지 않음.

oxt/doc/references.txt 중에서 인용:

분석 1

ODT 패키지를 로딩할 때, 패키지에 포함된 그림 파일들을 바로 이어서 로딩하거나, LoadOnDemand 할 수 있음.
SvXMLImport::ResolveGraphicObjectURL(url, loadondemand) 참조.

그런데 SdXMLGraphicObjectShapeContext::StartElement()는 (line 2388 부근에서) SvXMLImport::ResolveGraphicObjectURL을 호출할 때 SvXMLImport::IsGraphicLoadOnDemandSupported()를 호출하는데, SvXMLImport는 기본값으로 true를 반환하며, SwXMLImport도 마찬가지인 듯 하다.

그래서 패키지를 처음 로딩할 때 이미지가 로딩되지 않고, 이후에 UI에서 on demand로 이미지를 로딩하는 듯 하다.
(sdr::contact::ViewObjectContactOfGraphic::doAsynchGraphicLoading()에서부터 추적)

그런데 실제로는 load on demand 과정에서 실패하는데, Storage에서 그림 스트림을 얻어내는 과정에서 실패한다.
(comphelper::OStorageHelper::GetStreamAtPackageURL()에서부터 추적)

일단 패키지 Storage가 (hwp에서 odt로 변환한) 임시 파일에 기반해 있기 때문에 추후 on demand 과정에서는 이 파일이 이미 사라졌기 때문이 아닌가 추측해볼 수 있는데, hwp5file_convert_to_odtpkg_file()에서 임시파일 대신 특정한 위치에 고정된 파일을 만들어서 실험해봤을 때도 역시 그림 스트림을 얻어내는데서 실패하는 것으로 보아, 다른 이유일 수도 있음.

분석 2

on demand 로딩을 포기하고 content.xml을 로딩하면서 그림들도 함께 로딩되도록 하면, 그림들이 제대로 로딩되는 것을
확인할 수 있다:

  • com.sun.star.comp.Writer.XMLOasisContentImporter를 초기화할 때, 필터 인자로 graphic resolver를 다음처럼 초기화하여 넘겨준다.
    createInstanceWithArguments('com.sun.star.comp.Svx.GraphicImportHelper', (storage,))

  • 그리고 디버거상에서 SvXMLImporter::initialize()를 수행한 뒤, mbIsGraphicLoadOnDemandSupported = false로 강제로 설정한 뒤 진행하면 그림들이 제대로 로딩됨을 확인할 수 있다.

    그런데 문제는 SvXMLImporter::mbIsGraphicLoadOnDemandSupported는 처음에 true로 설정된 뒤, 바뀌지 않는다는 것이다. 위처럼 디버거 상에서 강제로 false로 설정해주지 않는 한, SvXMLImporter::ResolveGraphicObjectURL(url, loadondemand)는 늘 두번째 인자를 true로 불리게 된다. (SdXMLGraphicObjectShapeContext::StartElement()의 라인 2388 부근)

other_formats 대신 alt_formats

  • 더 적절한 이름 (alternative formats, 대안형)
  • 현재는 stream 대안형만을 지원하는데, storage 대안형도 지원

Storage/Stream 인터페이스 재편

Storage/Stream 인터페이스 재편

Closable:

  • close()

Readable extends Closable:

  • read([n])

Stream:

  • open() : Readable 반환

Storage:

  • __iter__() : 소속 아이템들의 이름 iterable 반환
  • __getitem__(name) : 이름으로 소속 아이템 반환. 아이템은 Storage이거나 Stream

옛한글 한양PUA코드 처리

hwp5.x 파일은 옛한글을 한양PUA코드로 인코딩하고 있음.

http://groups.google.com/group/libhwp/browse_thread/thread/6c457684491292b9 에 따르면 1. 한양PUA코드는 표준이 아니고, 2. (아마도) 한양PUA코드는 한양 폰트에만 사용가능한 것 같음. 따라서 옛한글을 표현하기 위한 표준적인 스킴을 찾아야 할 듯.

옛한글을 표현하기 위한 표준적인 스킴의 예로는 첫가끝 코드가 있는 듯 함. 1. KTUG에서 이를 사용하고 있음. 2. 위의 쓰레드에서 류창우님이 언급함.

첫가끝 코드 외의 다른 표준적인 스킴이 있는지 여부는 좀 더 알아봐야 하며, 각 스킴이 최종적인 렌더링(odf, html 등)에 적합한지 여부를 따져봐야 할 것임.

릴리즈 버젼 업 스크립트

릴리즈 시 다음 세 군데를 고쳐야함

  • VERSION (파이썬 패키지 버젼)
  • setup.pyversion 인자(파이썬 패키지 버젼) (by versioneer.py)
  • doc/conf.pyversion/release (파이썬 패키지 버젼)
  • stdeb.cfg 에서 Forced-Upstream-Version (데비안 패키지 버젼)
  • oxt/description.xml<version> 태그 변경

이 작업을 자동화하는 스크립트가 있으면 좋겠다

  • 단일 인자로 파이썬 패키지 버젼을 받는 방법 (데비안 패키지 버젼은 자동으로 변환됨)
  • 인자로 파이썬 패키지 버젼, 데비안 패키지 버젼 두개를 받는 방법
  • 기존에 적혀있는 버젼보다 낮은(오래된) 버젼이 입력된 경우 에러를 반환해야

xmlformat

recordstream, binmodel, xmlmodel의 출력 스트림을 표준화된 XML로 변환 출력

  • 구조체, 리스트 등을 표현하기 위한 표준화된 XML 표현법을 정의해야 한다.

hwp5 포맷이 아닌 경우 적절한 처리

현재 hwp5.filestructure.File은 주어진 피일을 OLE 복합문서로 간주하여 열 뿐, 아닐 경우 OleFile이 발생시키는 예외를 그대로 전파한다. OLE 복합 문서가 아닌 경우 적절한 예외를 발생시켜야 한다. 이는 사용자가 3.0 버젼 포맷의 문서를 열려 시도할 때 중요하다.

더불어 OLE 복합문서이기는 하지만 hwp 5.0 버젼 포맷이 아닌 경우에도 적절한 처리를 해야 한다.

계층 간 역할 조정 및 xmlmodel/xmlout 계층 분리

현재 model, xml 계층의 성격이 모호하고, 역할이 혼재 되어있다.

model 계층은 다음과 같은 문제점을 갖는다:

  • 크게는 hwp5 바이너리의 구조를 따르면서도, inline_extended_controls 등의 임의적인 구조 변경이 가해지고 있다.
  • 결과물을 XML로 출력할 때, Struct, ARRAY 타입 등 복잡한 데이터 형의 속성을 XML 성격에 맞게 표현하고 있지 못함.

xml 계층의 성격 또한 모호하다:

  • 처음에는 단지 model 계층의 결과물을 XML로 표현하는 역할로 시작하였으나, 지금은 쉬운 XSLT 변환을 위한 구조 변경 또한 포함하고 있다.

따라서 계층들의 역할을 다음과 같이 조정한다:

  • binmodel 계층은 record 계층의 결과물을 적절한 데이터 타입으로 파싱하는 것으로 역할을 한정한다. 따라서 이 계층의 출력 스트림은
    hwp5 바이너리 레코드 계층 구조를 그대로 반영한다.
  • xmlmodel 계층은 쉬운 XSLT 변환을 위한 구조적 변경을 담당하며, 이 계층의 결과물로 각종 XSLT 변환이 이루어진다. 이 계층은 binmodel의 출력 스트림에 inline_extended_controls, wrap_section 등의 필터를 적용한다.
  • xmlout 계층은 (model, attributes) 스트림 파이프의 끝에서 입력 스트림을 실제 XML로 변환한다. record, binmodel, xmlmodel의 출력 결과에 대해 통일된 XML 표현 방식을 제공한다. Struct, ARRAY 타입 등 복잡한 데이터 형에 대한 XML 표현 정의는 이 계층에서 이루어진다.

make setuptools script working

스크립트가 해야하는 일

  • python 버젼 체크 (2.3 지원이 목표이나, 최근 itertools 사용으로 점검 필요)
  • 의존 모듈 설치 (e.g. OleFileIO_PL)
  • hwpdump, hwp2html, hwpview 실행 스크립트 생성

OXT testbed

libreoffice 내부에서 실행 가능한 테스트 환경

  • libreoffice 내부에서 테스트 러너가 실행되어야 함
  • pyhwp의 테스트스윗 + 및 OXT에 특화된 테스트스윗
  • libreoffice 외부에서 테스트를 구동하면, uno 인터페이스를 통해 libreoffice 내부의 테스트 러너가 실행, 결과를 받아볼 수 있어야 함
  • (optional) libreoffice 내부에서 특정 UI 요소를 통해 테스트를 구동하고 결과를 확인할 수 있어야 함

ODT 변환 시 원문에 없는 공백이 띄엄띄엄 나타남

개요

ODT 변환 시 중간 중간에 공백 문자들이 들어가는 현상이 발생한다.

원인

현재 odt-content.xsl의 xsl:output/@indent가 yes로 되어있다. 따라서 text:span 요소들의 끝에서 늘 line-break가 일어나고 indentation을 위한 공백문자들이 들어가는데, 이것들이 공백문자로 표시됨.

Columns support

다단 지원

Section - Page - Paragraph - Line으로 이어지는 View Model Hierarchy에서 Page와 Paragraph 사이에 들어가야 함:
Section - Page - (Column) - Paragraph - Line

파일 포맷 덤퍼

문맥 감지 가능하고 필드 별로 값/헥스 덤프가 가능한 덤퍼

ODT XSL regression test framework

ODT XSL 변환에 대한 회귀 테스트가 필요하다. 그런데 XSL 변환은 문서 전체를 입력/출력하므로, 테스트 입력으로 pyhwp XML 문서를 이용해야 한다. 그러나 pyhwp XML을 테스트 작성자가 직접 작성하기는 어려우므로, hwp 파일로부터 생성해야한다. 또한 쉬운 검증을 위해, 출력 odt 파일로부터 styles/content를 추출하여 xpath로 접근 가능한 결과물을 생성해야 한다.

이러한 과정을 자동화할 구조틀이 마련되어야 한다.

binmodel 개편

  • binary 데이터로부터 primitive 타입(int, float, str, list/tuple, dict)으로만 구성된 모델로 변환
  • binary model specification 정보를 자동으로 생성할 수 있어야
    • 버젼, 조건절 정보 포함

Matrix의 XSL 변환 점검

translate/rotate/scale matrix를 XSL 변환에서 쉽게 사용할 수 있도록 변경

각 행렬을 하나의 속성으로 표현하며 그 내용에는 현재 괄호와 쉼표를 사용하고 있는데, XSLT에선 사용하기 불편하다. 다음의 대안들을 고려한다:

  • 행과 열을 모두 독립된 요소/속성으로 분리
  • 행렬을 하나의 요소로 표현하고, 각 행을 하나의 속성으로, 각 속성은 행의 열을 공백으로 join (혹은 행과 열을 바꿈)
  • translate/rotate/scale을 행렬 대신 파라미터로 표현

(CRITICAL) Incomplete Pagination

pagination을 위해 편법으로 레벨0 문단의 LINE_SEG의 offsetY가 감소하는 순간을 포착하고 있음. 따라서 레벨>0인 문단 (예: 테이블 내부)에서 페이지가 바뀌는 경우 감지하지 못함.

가장 첫번째로 생각나는 방법은 라인에서부터 레벨>0 문단, 테이블 셀 등등을 경유하여 레벨0 문단까지 모든 높이 값을 계산하는 것.

make them unit-testable

tests/에 unittest들이 있지만 사실 대부분 샘플 파일 없이는 동작 불가능한 functional test들임.
unittest 가능하게 하려면 각 데이터/뷰 모델들을 독립적으로 생성하는 것이 가능해져야(쉬워져야) 함. 현재 pagination 전략이 미완성이라 모델링이 매우 유동적인만큼 각 모델들에는 파서가 생성하는데 필요한 인터페이스들만 대충 넣어놨는데, 모델링이 완성되면 제대로된 인터페이스를 갖춰주어야.

document object model

record stream(s)로부터 생성되는 document 객체 모델을 확정한다.

document 객체 모델은 파일에 담긴 정보만을 그대로 반영하며, pagination 등 추가적인 분석이 필요한 정보는 담지 않는다.

데비안 패키징 (.deb) 자동화

http://pypi.python.org/pypi/stdeb 를 사용. buildout recipe으로 만들면 좋을 것. 다음의 문제를 먼저 해결해야 함

OleFileIO_PL 의존성 문제

  • 현재 pyhwp는 파이썬 패키지 OleFileIO_PL 에 의존성을 가짐.
  • 현재 우분투에는(적어도 11.10 이하에서는) 이에 해당하는 데비안 패키지가 없음
  • 따라서 OleFileIO_PL 의 데비안 패키지 python-olefileio-pl 을 함께 생성해야 함

alpha 버젼 태그 문제

xsltproc, xmllint, xmllint --relaxng 에 대한 일반화

여러 구현체를 선택적으로 사용할 수 있어야

  • lxml 을 이용한 구현체
  • 외부 프로그램 xsltproc, xmllint 를 사용한 구현체
  • oxt라면, libreoffice의 내부 컴포넌트를 이용하는 구현체를 생각해볼 수 있음. 특히 oxt는 olestorage로 내부 구현체를 추가적으로 사용할 수 있을 것임 완료.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.