목차

What is HWP

The file extension HWP, HWPX is word processor file type which is developed by Hancom.

Like DOC or DOCX, the HWP files has its own specification. But, hwp is very like DOC, and hwpx is very similar to DOCX in view of file specification. For example, hwp uses Microsoft compound file like DOC, and hwpx uses zip like DOCX.

So, If you can analysis DOC, you can analysis HWP. Actually, the hwplib uses APACHE-POI who manipulate Microsoft WORD.

In this article, I will show you how to manipulate hwp file by using hwplib.

The Gosohae app uses this technique.

hwplib

Hwplib is a library that can read and write hwp file. Hwplib was made by 박성균(Park.sung.kyun).

The maven repository is

[[https://mvnrepository.com/artifact/kr.dogfoot/hwplib/|https://mvnrepository.com/artifact/kr.dogfoot/hwplib/]]

You can add dependency is android project by typing this in gradle.kts

  // https://mvnrepository.com/artifact/kr.dogfoot/hwplib
  implementation("kr.dogfoot:hwplib:1.1.8")

You can find many source file in source files.

HWP File

First, you must make “ClickHere(누름틀)” Field in HWP File.

By Ctrl + K + E, You can make “ClickHere” Field. and by Ctrl + N + K, You can modify that Field.

This is a sample hwp file which make “ClickHere” Field.

evadeinvestigator.hwp

You can save file inside your app by locating file in [res] →[ raw] folder

res raw folder

Sample File

This is sample file of hwp manipulation

"HWPPage.kt"
package com.dklaw.goso3.pdfPages
 
import android.content.Context
import android.os.Environment
import android.widget.Toast
import com.dklaw.goso3.R
import com.dklaw.goso3.database.CriminalSue
import com.dklaw.goso3.database.PlaintiffContact
import com.dklaw.goso3.pages.EvadeObject
import com.dklaw.goso3.pages.EvadeReason
import com.dklaw.goso3.pages.NoticeMethod
import com.dklaw.goso3.pages.getJsonEvadeObject
import com.dklaw.goso3.pages.getJsonEvadeReason
import com.dklaw.goso3.pages.getJsonNoticeMethod
import kr.dogfoot.hwplib.`object`.HWPFile
import kr.dogfoot.hwplib.reader.HWPReader
import kr.dogfoot.hwplib.tool.objectfinder.FieldFinder
import kr.dogfoot.hwplib.writer.HWPWriter
import org.json.JSONObject
import java.io.File
import java.io.FileOutputStream
import java.io.IOException
import java.text.SimpleDateFormat
import java.time.Instant
import java.util.Date
import java.util.Locale
 
 
@Throws(IOException::class)
fun generateHWPPageEvadeInvestigator(context: Context, sueItem : CriminalSue, plaintiffInfo : PlaintiffContact, evadeObject: EvadeObject,
                                     evadeReason: EvadeReason, noticeMethod: NoticeMethod) {
 
    try {
        val hwpFile : HWPFile = HWPReader.fromInputStream(context.resources.openRawResource(R.raw.evadeinvestigator))
 
        // JSON 엘리먼트 가져오기
        val jsonElementObject = JSONObject(sueItem.jsonElements)  // Json Elements 데이터 가져와서 JSON으로 변환
 
        val textName = ArrayList<String>()
        textName.add(plaintiffInfo.pName)
 
        val textIncidentTitle = ArrayList<String>()
        textIncidentTitle.add(sueItem.incidentTitle)
 
        val jsonEvadeObject = getJsonEvadeObject(jsonElementObject)
        val textPosition = ArrayList<String>()
        textPosition.add(jsonEvadeObject.position)
 
 
        FieldFinder.setClickHereText(hwpFile, "name", textName)
        FieldFinder.setClickHereText(hwpFile, "position", textPosition)
        FieldFinder.setClickHereText(hwpFile, "socialNumber", arrayListOf(plaintiffInfo.socialNumber))
        FieldFinder.setClickHereText(hwpFile, "phone", arrayListOf(plaintiffInfo.pPhoneNumber))
        FieldFinder.setClickHereText(hwpFile, "address", arrayListOf(plaintiffInfo.pAddress))
        FieldFinder.setClickHereText(hwpFile, "incidentTitle", textIncidentTitle)
        FieldFinder.setClickHereText(hwpFile, "department", arrayListOf(jsonEvadeObject.department))
        FieldFinder.setClickHereText(hwpFile, "investigatorName", arrayListOf(jsonEvadeObject.name))
 
        // 기피 이유
        var reason = ""
        val jsonEvadeReason = getJsonEvadeReason(jsonElementObject)
        if (jsonEvadeReason.victim)  reason += "□ 수사관이 사건의 피해자임"
        if (jsonEvadeReason.relative) reason += "\n□ 수사관이 피의자·피해자와 친족이거나 친족관계에 있음"
        if (jsonEvadeReason.sponsor) reason += "\n□ 수사관이 피의자·피해자의 법정대리인 또는 후견감독인임"
        if (jsonEvadeReason.contact) reason += "\n□ 수사관이 청탁전화를 수신하는 등 피의자·피해자와 공무 외 접촉하여 공정성을 해하였음"
        if (jsonEvadeReason.insult) reason += "\n□ 수사관이 모욕적 언행, 욕설, 가혹행위 등 인권을 침해함"
        if (jsonEvadeReason.interfefe) reason += "\n□ 조사과정의 변호인 참여 등 신청인의 방어권을 보장하지 못함"
        if (jsonEvadeReason.lazy) reason += "\n□ 사건 접수 후 30일 이상 아무런 수사 진행사항이 없음"
        if (jsonEvadeReason.etc) reason += "\n□ 기타 불공평한 수사를 할 염려가 있다고 볼만한 객관적·구체적 사정이 있음"
 
        FieldFinder.setClickHereText(hwpFile, "evadeReason", arrayListOf(reason))
 
        FieldFinder.setClickHereText(hwpFile, "reasonDetail", arrayListOf(sueItem.reason))
 
        // 통지방법
        val jsonNoticeMethod = getJsonNoticeMethod(jsonElementObject)
        var noticeMethod = ""
        if (jsonNoticeMethod.document) noticeMethod += "서면"
        if (jsonNoticeMethod.phone) noticeMethod += " 전화"
        if (jsonNoticeMethod.sms) noticeMethod += " 문자메시지"
        if (jsonNoticeMethod.etc) noticeMethod += " 기타 : ${jsonNoticeMethod.etcDetail}"
 
        FieldFinder.setClickHereText(hwpFile, "noticeMethod", arrayListOf(noticeMethod))
 
        // 날짜 등
        FieldFinder.setClickHereText(hwpFile, "date", arrayListOf(SimpleDateFormat("yyyy년 MM 월 dd일", Locale.KOREAN).format(sueItem.modifiedAt)))
        FieldFinder.setClickHereText(hwpFile, "name2", textName)
        FieldFinder.setClickHereText(hwpFile, "jurisdiction", arrayListOf(sueItem.policeStation + "장") )
 
        val dir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS)
        val file = File(dir, "수사관기피신청서"+ "_" + SimpleDateFormat("yyyyMMdd", Locale.KOREAN).format(
            Date.from(Instant.now()))+".hwp")
        val fos = FileOutputStream(file)
        HWPWriter.toStream(hwpFile, fos)
        fos.close()
 
            // on below line we are displaying a toast message as PDF file generated..
            Toast.makeText(context, "HWP 파일이 다운로드 폴더에 저장되었습니다.", Toast.LENGTH_SHORT).show()
    } catch (e: Exception) {
        // below line is used
        // to handle error
        e.printStackTrace()
 
        // on below line we are displaying a toast message as fail to generate PDF
        Toast.makeText(context, "HWP 파일 작성에 실패했습니다.", Toast.LENGTH_SHORT).show()
    }
}