Skip to content

Commit

Permalink
Add feature parsing docinfo (#5)
Browse files Browse the repository at this point in the history
* add bin data model

* add lint workflow

* Work with DocInfo

* add noori test (thanks to hwp.js)

* parse ParaShape

* add TODO
  • Loading branch information
sboh1214 authored Oct 1, 2020
1 parent bb570f5 commit eb5277d
Show file tree
Hide file tree
Showing 32 changed files with 640 additions and 151 deletions.
13 changes: 13 additions & 0 deletions .github/workflows/Lint.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
name: Lint

on: [ push, pull_request ]

jobs:
lint:
name: Lint
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v2
- name: GitHub Action for SwiftLint
uses: norio-nomura/[email protected]
18 changes: 18 additions & 0 deletions .swiftlint.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
excluded:
- Carthage
- Pods

line_length: 100

disabled_rules:
- todo

type_body_length:
warning: 300
error: 400

file_length:
warning: 500
error: 1000

reporter: "xcode" # reporter type (xcode, json, csv, checkstyle, junit, html, emoji, sonarqube, markdown, github-actions-logging)
16 changes: 0 additions & 16 deletions .swiftpm/xcode/xcshareddata/xcschemes/HwpKit.xcscheme
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,6 @@
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
<PreActions>
<ExecutionAction
ActionType = "Xcode.IDEStandardExecutionActionsCore.ExecutionActionType.ShellScriptAction">
<ActionContent
title = "Run Script"
scriptText = "# Type a script or drag a script file from your workspace to insert its path.&#10;if which swiftlint &gt;/dev/null; then&#10; say &quot;Pre build scripts running.&quot;&#10; exec &gt; &quot;${PROJECT_DIR}/prebuild.log&quot; 2&gt;&amp;1&#10; echo &quot;Starting build scheme Pre-actions&quot;&#10; &quot;${PROJECT_DIR}/Build-Phases/That_pre-action_script.sh&quot;&#10; echo `swiftlint autocorrect`&#10; echo `swiftlint`&#10;else&#10; echo &quot;warning: SwiftLint not installed, download from https://github.com/realm/SwiftLint&quot;&#10;fi&#10;">
</ActionContent>
</ExecutionAction>
</PreActions>
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
Expand Down Expand Up @@ -68,13 +59,6 @@
BlueprintName = "HwpKit"
ReferencedContainer = "container:">
</BuildableReference>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "HwpKitTests"
BuildableName = "HwpKitTests"
BlueprintName = "HwpKitTests"
ReferencedContainer = "container:">
</BuildableReference>
</CodeCoverageTargets>
<Testables>
<TestableReference
Expand Down
9 changes: 6 additions & 3 deletions Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@ let package = Package(
name: "HwpKit",
platforms: [.macOS(.v10_11), .iOS(.v9), .tvOS(.v9), .watchOS(.v2)],
products: [
// Products define the executables and libraries a package produces, and make them visible to other packages.
// Products define the executables and libraries a package produces,
// and make them visible to other packages.
.library(
name: "HwpKit",
targets: ["HwpKit"]
Expand All @@ -26,8 +27,10 @@ let package = Package(
)
],
targets: [
// Targets are the basic building blocks of a package. A target can define a module or a test suite.
// Targets can depend on other targets in this package, and on products in packages this package depends on.
// Targets are the basic building blocks of a package.
// A target can define a module or a test suite.
// Targets can depend on other targets in this package,
// and on products in packages this package depends on.
.target(
name: "HwpKit",
dependencies: ["OLEKit", "DataCompression"]
Expand Down
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,10 @@
![Test](https://github.com/sboh1214/HwpKit/workflows/Test/badge.svg)
![Coverage](https://github.com/sboh1214/HwpKit/workflows/Coverage/badge.svg)
![Documentation](https://github.com/sboh1214/HwpKit/workflows/Documentation/badge.svg)
![Lint](https://github.com/sboh1214/HwpKit/workflows/Lint/badge.svg)
[![codecov](https://codecov.io/gh/sboh1214/HwpKit/branch/master/graph/badge.svg)](https://codecov.io/gh/sboh1214/HwpKit)

HWP file reader.
Swift Package for Reading & Writing HWP File

## Install

Expand Down
23 changes: 23 additions & 0 deletions Sources/HwpKit/Enums/HwpBorderType.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
/**테두리선 종류*/
public enum HwpBorderType: Int {
/**실선*/
case line
/**긴 점선*/
case longDotLine
/**점선*/
case dotLine
/**-.-.-.-.*/
/**-..-..-..*/
/**Dash보다 긴 선분의 반복*/
/**Dot보다 큰 동그라미의 반복*/
/**2중선*/
/**가는선 + 굵은선 2중선*/
/**굵은선 + 가는선 2중선*/
/**가는선 + 굵은선 + 가는선 3중선*/
/**물결*/
/**물결 2중선*/
/**두꺼운 3D*/
/**두꺼운 3D(광원 반대)*/
/**3D 단선*/
/**3D 단선(광원 반대)*/
}
7 changes: 7 additions & 0 deletions Sources/HwpKit/Enums/HwpStreamName.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
public enum HwpStreamName: String {
case fileHeader = "FileHeader"
case docInfo = "DocInfo"
case summary = "\005HwpSummaryInformation"
case previewText = "PrvText"
case previewImage = "PrvImage"
}
File renamed without changes.
56 changes: 8 additions & 48 deletions Sources/HwpKit/HwpFile.swift
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
import Foundation
import OLEKit
import DataCompression

public class HwpFile {
public let fileHeader: HwpFileHeader
public let docInfo: HwpDocInfo
public let previewText: HwpPreviewText

public init(filePath: String) throws {
let ole: OLEFile
do {
Expand All @@ -15,57 +14,18 @@ public class HwpFile {
throw HwpError.invalidFilePath(path: filePath)
}
let streams = Dictionary(uniqueKeysWithValues: ole.root.children.map { ($0.name, $0 ) })
let test = Test(ole, streams)

fileHeader = try HwpFileHeader(test.getDataFromStream(.fileHeader, false))

docInfo = try HwpDocInfo(test.getDataFromStream(.docInfo, fileHeader.isCompressed))

let reader = StreamReader(ole, streams)

fileHeader = try HwpFileHeader(reader.getDataFromStream(.fileHeader, false))

let docInfoData = try reader.getDataFromStream(.docInfo, fileHeader.isCompressed)
docInfo = try HwpDocInfo(docInfoData, fileHeader.version)

guard let previewTextStream = streams[HwpStreamName.previewText.rawValue] else {
throw HwpError.streamDoesNotExist(name: HwpStreamName.previewText)
}
let previewTextReader = try ole.stream(previewTextStream)
previewText = try HwpPreviewText(previewTextReader.readDataToEnd())
}


}

fileprivate struct Test {
private let ole: OLEFile
private let streams: [String: DirectoryEntry]

init(_ ole: OLEFile, _ streams: [String: DirectoryEntry]) {
self.ole = ole
self.streams = streams
}

fileprivate func getDataFromStream(_ streamName: HwpStreamName, _ isCompressed: Bool) throws -> Data {
guard let stream = streams[streamName.rawValue] else {
throw HwpError.streamDoesNotExist(name: streamName)
}
let reader = try ole.stream(stream)
let data = reader.readDataToEnd()
if isCompressed {
if #available(OSX 10.15, *) {
return try (data as NSData).decompressed(using: .zlib) as Data
} else {
guard let decompressedData = data.decompress(withAlgorithm: .zlib) else {
throw HwpError.streamDecompressFailed(name: streamName)
}
return decompressedData
}

} else {
return data
}
}
}

public enum HwpStreamName: String {
case fileHeader = "FileHeader"
case docInfo = "DocInfo"
case summary = "\005HwpSummaryInformation"
case previewText = "PrvText"
case previewImage = "PrvImage"
}
12 changes: 6 additions & 6 deletions Sources/HwpKit/Models/Document Properties/HwpCaratLocation.swift
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
import Foundation

public struct HwpCaratLocation: HwpData {
let listId: UInt32
let paragraphId: UInt32
let charIndex: UInt32
public let listId: UInt32
public let paragraphId: UInt32
public let charIndex: UInt32

init(_ data: Data) {
var reader = DataReader(data)
listId = reader.readUInt32()
paragraphId = reader.readUInt32()
charIndex = reader.readUInt32()
listId = reader.read(UInt32.self)
paragraphId = reader.read(UInt32.self)
charIndex = reader.read(UInt32.self)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ public struct HwpDocumentProperties: HwpData {

init(_ data: Data) {
var reader = DataReader(data)
sectionSize = reader.readUInt16()
sectionSize = reader.read(UInt16.self)
startingIndex = HwpStartingIndex(reader.readBytes(12))
caratLocation = HwpCaratLocation(reader.readBytes(12))
}
Expand Down
12 changes: 6 additions & 6 deletions Sources/HwpKit/Models/Document Properties/HwpStartingIndex.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,11 @@ public struct HwpStartingIndex: HwpData {

init(_ data: Data) {
var reader = DataReader(data)
page = reader.readUInt16()
footnote = reader.readUInt16()
endnote = reader.readUInt16()
picture = reader.readUInt16()
table = reader.readUInt16()
equation = reader.readUInt16()
page = reader.read(UInt16.self)
footnote = reader.read(UInt16.self)
endnote = reader.read(UInt16.self)
picture = reader.read(UInt16.self)
table = reader.read(UInt16.self)
equation = reader.read(UInt16.self)
}
}
57 changes: 57 additions & 0 deletions Sources/HwpKit/Models/HwpBinData.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import Foundation

/**
그림, OLE 등의 바이너리 데이터 아이템에 대한 정보

Tag ID : HWPTAG_BIN_DATA
*/
public struct HwpBinData: HwpData {
/**속성 -> type*/
public let type: HwpBinDataType

// TODO 속성 파싱

/**Type이 "LINK"일 때, 연결 파일의 절대 경로 길이*/
var absolutePathLength: WORD?
/**Type이 "LINK"일 때, 연결 파일의 절대 경로*/
public var absolutePath: [WCHAR]?
/**Type이 "LINK"일 때, 연결 파일의 상대 경로 길이*/
var relativePathLength: WORD?
/**Type이 "LINK"일 때, 연결 파일의 상대 경로*/
public var relativePath: [WCHAR]?

/**Type이 "EMBEDDING"이거나 "STORAGE"일 때, BINDATASTORAGE에 저장된 바이너리 데이터의 아이디*/
public var streamId: UInt16?
/**Type이 "EMBEDDING"일 때, 바이너리 데이터의 형식 이름의 길이*/
public var extensionLength: WORD?
/**
Type이 "EMBEDDING"일 때 extension("." 제외)

그림의 경우 jpg, bmp, gif
OLE의 경우 ole
*/
public var extensionName: [WCHAR]?

init(_ data: Data) throws {
var reader = DataReader(data)
let property = reader.read(UInt16.self)
type = HwpBinDataType(rawValue: getBitValue(Int(property), 0, 3))!

if type == HwpBinDataType.link {
absolutePathLength = reader.read(WORD.self)
absolutePath = reader.read(WCHAR.self, Int(absolutePathLength!))
relativePathLength = reader.read(WORD.self)
relativePath = reader.read(WCHAR.self, Int(relativePathLength!))
} else {
streamId = reader.read(UInt16.self)
extensionLength = reader.read(WORD.self)
extensionName = reader.read(WCHAR.self, Int(extensionLength!))
}
}
}

public enum HwpBinDataType: Int, Codable {
case link = 0x0
case embedding = 0x1
case storage = 0x2
}
24 changes: 24 additions & 0 deletions Sources/HwpKit/Models/HwpBorderFill.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import Foundation

public struct HwpBorderFill: HwpData {
public let property: UInt16
public let borderType: [UInt8]
public let borderThickness: [UInt8]
public let borderColor: [HwpColor]
public let diagonalType: UInt8
public let diagonalThickness: UInt8
public let diagonalColor: HwpColor
public let fillInfo: [BYTE]

init(_ data: Data) throws {
var reader = DataReader(data)
property = reader.read(UInt16.self)
borderType = reader.readBytes(4).bytes
borderThickness = reader.readBytes(4).bytes
borderColor = reader.read(UInt32.self, 4).map {HwpColor($0)}
diagonalType = reader.read(UInt8.self)
diagonalThickness = reader.read(UInt8.self)
diagonalColor = HwpColor(reader.read(UInt32.self))
fillInfo = reader.readToEnd().bytes
}
}
Loading

0 comments on commit eb5277d

Please sign in to comment.