From 8318bf98f3e1a6cebd40a78966f9ad7d539bb3bd Mon Sep 17 00:00:00 2001 From: Seungbin Oh Date: Mon, 5 Oct 2020 10:35:34 +0900 Subject: [PATCH 1/7] Parse Section --> Paragraph --> CharText --- .swiftlint.yml | 1 + README.md | 3 + Sources/HwpKit/Enums/HwpCharType.swift | 7 +++ Sources/HwpKit/Enums/HwpStreamName.swift | 1 + Sources/HwpKit/Enums/HwpTag.swift | 38 ++++++------ Sources/HwpKit/HwpFile.swift | 7 ++- .../HwpCaratLocation.swift | 0 .../HwpDocumentProperties.swift | 0 .../HwpStartingIndex.swift | 0 .../DocInfo}/HwpBinData.swift | 0 .../DocInfo}/HwpBorderFill.swift | 0 .../DocInfo}/HwpCharShape.swift | 0 .../DocInfo}/HwpFaceName.swift | 0 .../DocInfo}/HwpParaShape.swift | 16 ++--- .../DocInfo}/HwpVersion.swift | 0 Sources/HwpKit/Model/Section/HwpChar.swift | 6 ++ .../HwpKit/Model/Section/HwpParaHeader.swift | 54 ++++++++++++++++ .../HwpKit/Model/Section/HwpParaText.swift | 26 ++++++++ .../HwpKit/Model/Section/HwpParagraph.swift | 16 +++++ Sources/HwpKit/Streams/HwpDocInfo.swift | 18 +++--- Sources/HwpKit/Streams/HwpSection.swift | 24 +++++--- Sources/HwpKit/Streams/HwpSummary.swift | 2 +- Sources/HwpKit/Utils/DataReader.swift | 2 +- Sources/HwpKit/Utils/HwpColor.swift | 18 +++--- Sources/HwpKit/Utils/HwpData.swift | 8 +++ Sources/HwpKit/Utils/HwpDataWithVersion.swift | 5 -- Sources/HwpKit/Utils/HwpRecord.swift | 3 +- Sources/HwpKit/Utils/HwpTreeRecord.swift | 61 +++++++++++++++++++ Sources/HwpKit/Utils/StreamReader.swift | 13 +++- Tests/HwpKitTests/Basic/NooriTests.swift | 26 ++++---- Tests/LinuxMain.swift | 1 - 31 files changed, 278 insertions(+), 78 deletions(-) create mode 100644 Sources/HwpKit/Enums/HwpCharType.swift rename Sources/HwpKit/{Models => Model/DocInfo}/Document Properties/HwpCaratLocation.swift (100%) rename Sources/HwpKit/{Models => Model/DocInfo}/Document Properties/HwpDocumentProperties.swift (100%) rename Sources/HwpKit/{Models => Model/DocInfo}/Document Properties/HwpStartingIndex.swift (100%) rename Sources/HwpKit/{Models => Model/DocInfo}/HwpBinData.swift (100%) rename Sources/HwpKit/{Models => Model/DocInfo}/HwpBorderFill.swift (100%) rename Sources/HwpKit/{Models => Model/DocInfo}/HwpCharShape.swift (100%) rename Sources/HwpKit/{Models => Model/DocInfo}/HwpFaceName.swift (100%) rename Sources/HwpKit/{Models => Model/DocInfo}/HwpParaShape.swift (89%) rename Sources/HwpKit/{Models => Model/DocInfo}/HwpVersion.swift (100%) create mode 100644 Sources/HwpKit/Model/Section/HwpChar.swift create mode 100644 Sources/HwpKit/Model/Section/HwpParaHeader.swift create mode 100644 Sources/HwpKit/Model/Section/HwpParaText.swift create mode 100644 Sources/HwpKit/Model/Section/HwpParagraph.swift delete mode 100644 Sources/HwpKit/Utils/HwpDataWithVersion.swift create mode 100644 Sources/HwpKit/Utils/HwpTreeRecord.swift diff --git a/.swiftlint.yml b/.swiftlint.yml index be49a56..f585148 100644 --- a/.swiftlint.yml +++ b/.swiftlint.yml @@ -1,6 +1,7 @@ excluded: - Carthage - Pods + - .build line_length: 100 diff --git a/README.md b/README.md index 236e155..d30ddf5 100644 --- a/README.md +++ b/README.md @@ -8,6 +8,9 @@ ![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) +[![Quality Gate Status](https://sonarcloud.io/api/project_badges/measure?project=sboh1214_HwpKit&metric=alert_status)](https://sonarcloud.io/dashboard?id=sboh1214_HwpKit) +[![CodeFactor](https://www.codefactor.io/repository/github/sboh1214/hwpkit/badge)](https://www.codefactor.io/repository/github/sboh1214/hwpkit) + Swift Package for Reading & Writing HWP File ## Install diff --git a/Sources/HwpKit/Enums/HwpCharType.swift b/Sources/HwpKit/Enums/HwpCharType.swift new file mode 100644 index 0000000..102553f --- /dev/null +++ b/Sources/HwpKit/Enums/HwpCharType.swift @@ -0,0 +1,7 @@ +import Foundation + +public enum HwpCharType:String, Codable { + case char + case inline + case extended +} diff --git a/Sources/HwpKit/Enums/HwpStreamName.swift b/Sources/HwpKit/Enums/HwpStreamName.swift index eb0361d..b4d7c6e 100644 --- a/Sources/HwpKit/Enums/HwpStreamName.swift +++ b/Sources/HwpKit/Enums/HwpStreamName.swift @@ -1,6 +1,7 @@ public enum HwpStreamName: String { case fileHeader = "FileHeader" case docInfo = "DocInfo" + case bodyText = "BodyText" case summary = "\005HwpSummaryInformation" case previewText = "PrvText" case previewImage = "PrvImage" diff --git a/Sources/HwpKit/Enums/HwpTag.swift b/Sources/HwpKit/Enums/HwpTag.swift index f49b416..e3c527c 100644 --- a/Sources/HwpKit/Enums/HwpTag.swift +++ b/Sources/HwpKit/Enums/HwpTag.swift @@ -1,21 +1,19 @@ -// swiftlint:disable identifier_name - let BEGIN: UInt32 = 0x10 /** ’문서 정보’의 데이터 레코드 */ final class HwpDocInfoTag { - static let DOCUMENT_PROPERTIES: UInt32 = BEGIN - static let ID_MAPPINGS: UInt32 = BEGIN + 1 - static let BIN_DATA: UInt32 = BEGIN + 2 - static let FACE_NAME: UInt32 = BEGIN + 3 - static let BORDER_FILL: UInt32 = BEGIN + 4 - static let CHAR_SHAPE: UInt32 = BEGIN + 5 - static let TAB_DEF: UInt32 = BEGIN + 6 + static let documentProperties: UInt32 = BEGIN + static let idMappings: UInt32 = BEGIN + 1 + static let binData: UInt32 = BEGIN + 2 + static let faceName: UInt32 = BEGIN + 3 + static let borderFill: UInt32 = BEGIN + 4 + static let charShape: UInt32 = BEGIN + 5 + static let tabDef: UInt32 = BEGIN + 6 static let NUMBERING: UInt32 = BEGIN + 7 static let BULLET: UInt32 = BEGIN + 8 - static let PARA_SHAPE: UInt32 = BEGIN + 9 + static let paraShape: UInt32 = BEGIN + 9 static let STYLE: UInt32 = BEGIN + 10 static let DOC_DATA: UInt32 = BEGIN + 11 static let DISTRIBUTE_DOC_DATA: UInt32 = BEGIN + 12 @@ -33,18 +31,18 @@ final class HwpDocInfoTag { ‘본문’의 데이터 레코드 */ final class HwpSectionTag { - static let PARA_HEADER: UInt32 = BEGIN + 50 - static let PARA_TEXT: UInt32 = BEGIN + 51 - static let PARA_CHAR_SHAPE: UInt32 = BEGIN + 52 - static let PARA_LINE_SEG: UInt32 = BEGIN + 53 - static let PARA_RANGE_TAG: UInt32 = BEGIN + 54 - static let CTRL_HEADER: UInt32 = BEGIN + 55 - static let LIST_HEADER: UInt32 = BEGIN + 56 - static let PAGE_DEF: UInt32 = BEGIN + 57 - static let FOOTNOTE_SHAPE: UInt32 = BEGIN + 58 + static let paraHeader: UInt32 = BEGIN + 50 + static let paraText: UInt32 = BEGIN + 51 + static let paraCharShape: UInt32 = BEGIN + 52 + static let paraLineSeg: UInt32 = BEGIN + 53 + static let paraRangeTag: UInt32 = BEGIN + 54 + static let ctrlHeader: UInt32 = BEGIN + 55 + static let listHeader: UInt32 = BEGIN + 56 + static let pageDef: UInt32 = BEGIN + 57 + static let footnoteShape: UInt32 = BEGIN + 58 static let PAGE_BORDER_FILL: UInt32 = BEGIN + 59 static let SHAPE_COMPONENT: UInt32 = BEGIN + 60 - static let TABLE: UInt32 = BEGIN + 61 + static let table: UInt32 = BEGIN + 61 static let SHAPE_COMPONENT_LINE: UInt32 = BEGIN + 62 static let SHAPE_COMPONENT_RECTANGLE: UInt32 = BEGIN + 63 static let SHAPE_COMPONENT_ELLIPSE: UInt32 = BEGIN + 64 diff --git a/Sources/HwpKit/HwpFile.swift b/Sources/HwpKit/HwpFile.swift index dcc88a2..6c0fa8a 100644 --- a/Sources/HwpKit/HwpFile.swift +++ b/Sources/HwpKit/HwpFile.swift @@ -5,6 +5,7 @@ public class HwpFile { public let fileHeader: HwpFileHeader public let docInfo: HwpDocInfo public let previewText: HwpPreviewText + public let sectionArray: [HwpSection] public init(filePath: String) throws { let ole: OLEFile @@ -16,11 +17,15 @@ public class HwpFile { let streams = Dictionary(uniqueKeysWithValues: ole.root.children.map { ($0.name, $0 ) }) let reader = StreamReader(ole, streams) - fileHeader = try HwpFileHeader(reader.getDataFromStream(.fileHeader, false)) + let fileHeader = try HwpFileHeader(reader.getDataFromStream(.fileHeader, false)) + self.fileHeader = fileHeader let docInfoData = try reader.getDataFromStream(.docInfo, fileHeader.isCompressed) docInfo = try HwpDocInfo(docInfoData, fileHeader.version) + sectionArray = try reader.getDataFromStorage(.bodyText, fileHeader.isCompressed) + .map {try HwpSection($0, fileHeader.version)} + guard let previewTextStream = streams[HwpStreamName.previewText.rawValue] else { throw HwpError.streamDoesNotExist(name: HwpStreamName.previewText) } diff --git a/Sources/HwpKit/Models/Document Properties/HwpCaratLocation.swift b/Sources/HwpKit/Model/DocInfo/Document Properties/HwpCaratLocation.swift similarity index 100% rename from Sources/HwpKit/Models/Document Properties/HwpCaratLocation.swift rename to Sources/HwpKit/Model/DocInfo/Document Properties/HwpCaratLocation.swift diff --git a/Sources/HwpKit/Models/Document Properties/HwpDocumentProperties.swift b/Sources/HwpKit/Model/DocInfo/Document Properties/HwpDocumentProperties.swift similarity index 100% rename from Sources/HwpKit/Models/Document Properties/HwpDocumentProperties.swift rename to Sources/HwpKit/Model/DocInfo/Document Properties/HwpDocumentProperties.swift diff --git a/Sources/HwpKit/Models/Document Properties/HwpStartingIndex.swift b/Sources/HwpKit/Model/DocInfo/Document Properties/HwpStartingIndex.swift similarity index 100% rename from Sources/HwpKit/Models/Document Properties/HwpStartingIndex.swift rename to Sources/HwpKit/Model/DocInfo/Document Properties/HwpStartingIndex.swift diff --git a/Sources/HwpKit/Models/HwpBinData.swift b/Sources/HwpKit/Model/DocInfo/HwpBinData.swift similarity index 100% rename from Sources/HwpKit/Models/HwpBinData.swift rename to Sources/HwpKit/Model/DocInfo/HwpBinData.swift diff --git a/Sources/HwpKit/Models/HwpBorderFill.swift b/Sources/HwpKit/Model/DocInfo/HwpBorderFill.swift similarity index 100% rename from Sources/HwpKit/Models/HwpBorderFill.swift rename to Sources/HwpKit/Model/DocInfo/HwpBorderFill.swift diff --git a/Sources/HwpKit/Models/HwpCharShape.swift b/Sources/HwpKit/Model/DocInfo/HwpCharShape.swift similarity index 100% rename from Sources/HwpKit/Models/HwpCharShape.swift rename to Sources/HwpKit/Model/DocInfo/HwpCharShape.swift diff --git a/Sources/HwpKit/Models/HwpFaceName.swift b/Sources/HwpKit/Model/DocInfo/HwpFaceName.swift similarity index 100% rename from Sources/HwpKit/Models/HwpFaceName.swift rename to Sources/HwpKit/Model/DocInfo/HwpFaceName.swift diff --git a/Sources/HwpKit/Models/HwpParaShape.swift b/Sources/HwpKit/Model/DocInfo/HwpParaShape.swift similarity index 89% rename from Sources/HwpKit/Models/HwpParaShape.swift rename to Sources/HwpKit/Model/DocInfo/HwpParaShape.swift index dc83e96..15ce0de 100644 --- a/Sources/HwpKit/Models/HwpParaShape.swift +++ b/Sources/HwpKit/Model/DocInfo/HwpParaShape.swift @@ -7,7 +7,7 @@ import Foundation */ public struct HwpParaShape: HwpDataWithVersion { /**속성 1*/ - public let property1:UInt32 + public let property1: UInt32 /**왼쪽 여백*/ public let marginLeft: Int32 /**오른쪽 여백*/ @@ -19,7 +19,7 @@ public struct HwpParaShape: HwpDataWithVersion { /**문단 간격 아래*/ public let paragraphSpacingBottom: Int32 /**줄 간격. 한글 2007 이하 버전(5.0.2.5 버전 미만)에서 사용.*/ - public let lineSpacing:Int32 + public let lineSpacing: Int32 /**탭 정의 아이디(TabDef ID) 참조 값*/ public let tabDefId: UInt16 /**번호 문단 ID(Numbering ID) 또는 글머리표 문단 모양 ID(Bullet ID) 참조 값*/ @@ -35,12 +35,12 @@ public struct HwpParaShape: HwpDataWithVersion { /**문단 테두리 아래쪽 간격*/ public let borderSpacingBottom: Int16 /**속성 2(표 40 참조) (5.0.1.7 버전 이상)*/ - public var property2: UInt32? = nil + public var property2: UInt32? /**속성 3(표 41 참조) (5.0.2.5 버전 이상)*/ - public var property3: UInt32? = nil + public var property3: UInt32? /**줄 간격(5.0.2.5 버전 이상)*/ - public var lineSpacing2: UInt32? = nil - + public var lineSpacing2: UInt32? + init(_ data: Data, _ version: HwpVersion) throws { var reader = DataReader(data) defer { @@ -60,10 +60,10 @@ public struct HwpParaShape: HwpDataWithVersion { borderSpacingRight = reader.read(Int16.self) borderSpacingTop = reader.read(Int16.self) borderSpacingBottom = reader.read(Int16.self) - if version >= HwpVersion(5,0,1,7) { + if version >= HwpVersion(5, 0, 1, 7) { property2 = reader.read(UInt32.self) } - if version >= HwpVersion(5,0,2,5) { + if version >= HwpVersion(5, 0, 2, 5) { property3 = reader.read(UInt32.self) lineSpacing2 = reader.read(UInt32.self) } diff --git a/Sources/HwpKit/Models/HwpVersion.swift b/Sources/HwpKit/Model/DocInfo/HwpVersion.swift similarity index 100% rename from Sources/HwpKit/Models/HwpVersion.swift rename to Sources/HwpKit/Model/DocInfo/HwpVersion.swift diff --git a/Sources/HwpKit/Model/Section/HwpChar.swift b/Sources/HwpKit/Model/Section/HwpChar.swift new file mode 100644 index 0000000..0e2838f --- /dev/null +++ b/Sources/HwpKit/Model/Section/HwpChar.swift @@ -0,0 +1,6 @@ +import Foundation + +public struct HwpChar: Codable { + let type: HwpCharType + let value: WCHAR +} diff --git a/Sources/HwpKit/Model/Section/HwpParaHeader.swift b/Sources/HwpKit/Model/Section/HwpParaHeader.swift new file mode 100644 index 0000000..ecaeb8d --- /dev/null +++ b/Sources/HwpKit/Model/Section/HwpParaHeader.swift @@ -0,0 +1,54 @@ +import Foundation + +public struct HwpParaHeader: HwpDataWithVersion { + /**if (nchars & 0x80000000) { nchars &= 0x7fffffff;}*/ + public let isLastInList: Bool + /**text(=chars)*/ + public let charCount: UInt32 + /** + control mask + + (UINT32)(1<= HwpVersion(5, 0, 3, 2) { + isTraceChange = reader.read(UInt16.self) + } + } +} diff --git a/Sources/HwpKit/Model/Section/HwpParaText.swift b/Sources/HwpKit/Model/Section/HwpParaText.swift new file mode 100644 index 0000000..35721fc --- /dev/null +++ b/Sources/HwpKit/Model/Section/HwpParaText.swift @@ -0,0 +1,26 @@ +import Foundation + +public struct HwpParaText: HwpData { + var charArray: [HwpChar] + + init(_ data: Data) throws { + var reader = DataReader(data) + var array = [HwpChar]() + while !reader.isEOF() { + let char = reader.read(WCHAR.self) + switch char { + case 0,1,13: + array.append(HwpChar(type: .char, value: char)) + case 4...9, 19...20: + array.append(HwpChar(type: .inline, value: char)) + reader.readBytes(14) + case 1...3, 11...12, 14...18, 21...23: + array.append(HwpChar(type: .extended, value: char)) + reader.readBytes(14) + default: + array.append(HwpChar(type: .char, value: char)) + } + } + charArray = array + } +} diff --git a/Sources/HwpKit/Model/Section/HwpParagraph.swift b/Sources/HwpKit/Model/Section/HwpParagraph.swift new file mode 100644 index 0000000..996b019 --- /dev/null +++ b/Sources/HwpKit/Model/Section/HwpParagraph.swift @@ -0,0 +1,16 @@ +import Foundation + +public struct HwpParagraph: HwpRecordWithVersion { + public let paraHeader: HwpParaHeader + public var paraText: HwpParaText? = nil + + init(_ record: HwpTreeRecord, _ version: HwpVersion) throws { + paraHeader = try HwpParaHeader(record.payload, version) + + if let paraText = record.children + .first(where: {$0.tagId == HwpSectionTag.paraText}) + { + self.paraText = try HwpParaText(paraText.payload) + } + } +} diff --git a/Sources/HwpKit/Streams/HwpDocInfo.swift b/Sources/HwpKit/Streams/HwpDocInfo.swift index a264be1..10fe107 100644 --- a/Sources/HwpKit/Streams/HwpDocInfo.swift +++ b/Sources/HwpKit/Streams/HwpDocInfo.swift @@ -23,33 +23,33 @@ public struct HwpDocInfo: HwpDataWithVersion { // TODO HWPTAG_LAYOUT_COMPATIBILITY init(_ data: Data, _ version: HwpVersion) throws { - let records = try parseRecordTree(data: data) + let records = try parseRecordArray(data: data) guard let documentProperties = records - .first(where: {$0.tagId == HwpDocInfoTag.DOCUMENT_PROPERTIES}) + .first(where: {$0.tagId == HwpDocInfoTag.documentProperties}) else { - throw HwpError.recordDoesNotExist(tag: HwpDocInfoTag.DOCUMENT_PROPERTIES) + throw HwpError.recordDoesNotExist(tag: HwpDocInfoTag.documentProperties) } self.documentProperties = HwpDocInfo.visitDocumentPropertes(documentProperties) binDataArray = try records - .filter {$0.tagId == HwpDocInfoTag.BIN_DATA} + .filter {$0.tagId == HwpDocInfoTag.binData} .map {try HwpBinData($0.payload)} faceNameArray = try records - .filter {$0.tagId == HwpDocInfoTag.FACE_NAME} + .filter {$0.tagId == HwpDocInfoTag.faceName} .map {try HwpFaceName($0.payload)} borderFillArray = try records - .filter {$0.tagId == HwpDocInfoTag.BORDER_FILL} + .filter {$0.tagId == HwpDocInfoTag.borderFill} .map {try HwpBorderFill($0.payload)} charShapeArray = try records - .filter {$0.tagId == HwpDocInfoTag.CHAR_SHAPE} + .filter {$0.tagId == HwpDocInfoTag.charShape} .map {try HwpCharShape($0.payload, version)} - + paraShapeArray = try records - .filter {$0.tagId == HwpDocInfoTag.PARA_SHAPE} + .filter {$0.tagId == HwpDocInfoTag.paraShape} .map {try HwpParaShape($0.payload, version)} } diff --git a/Sources/HwpKit/Streams/HwpSection.swift b/Sources/HwpKit/Streams/HwpSection.swift index 940d647..b849ac3 100644 --- a/Sources/HwpKit/Streams/HwpSection.swift +++ b/Sources/HwpKit/Streams/HwpSection.swift @@ -1,10 +1,16 @@ -struct HwpSection { - let width: Int = 0 - let height: Int = 0 - let paddingLeft: Int = 0 - let paddingRight: Int = 0 - let paddingTop: Int = 0 - let paddingBottom: Int = 0 - let headerPadding: Int = 0 - let footerPadding: Int = 0 +import Foundation + +/** + 본문 + */ +public struct HwpSection: HwpDataWithVersion { + public var paragraph: [HwpParagraph] + + init(_ data: Data, _ version: HwpVersion) throws { + let records = parseTreeRecord(data: data) + paragraph = try records.children.map {record in + precondition(record.tagId == HwpSectionTag.paraHeader) + return try HwpParagraph(record, version) + } + } } diff --git a/Sources/HwpKit/Streams/HwpSummary.swift b/Sources/HwpKit/Streams/HwpSummary.swift index ac52a07..c17a194 100644 --- a/Sources/HwpKit/Streams/HwpSummary.swift +++ b/Sources/HwpKit/Streams/HwpSummary.swift @@ -3,7 +3,7 @@ import Foundation /** 문서 요약 - \005HwpSummaryInfomation 스트림에는 한글 메뉴의 “파일-문서 정보-문서 요약”에서 입력한 내 용이 저장된다. + \005HwpSummaryInfomation 스트림에는 한글 메뉴의 “파일-문서 정보-문서 요약”에서 입력한 내용이 저장된다. */ struct HwpSummary { let title: String diff --git a/Sources/HwpKit/Utils/DataReader.swift b/Sources/HwpKit/Utils/DataReader.swift index 624e3e5..9680a62 100644 --- a/Sources/HwpKit/Utils/DataReader.swift +++ b/Sources/HwpKit/Utils/DataReader.swift @@ -12,7 +12,7 @@ struct DataReader { return offset == data.count } - mutating func readBytes(_ length: Int) -> Data { + @discardableResult mutating func readBytes(_ length: Int) -> Data { precondition(offset + length < data.count + 1) defer { offset += length diff --git a/Sources/HwpKit/Utils/HwpColor.swift b/Sources/HwpKit/Utils/HwpColor.swift index 95ee191..cdbfa2e 100644 --- a/Sources/HwpKit/Utils/HwpColor.swift +++ b/Sources/HwpKit/Utils/HwpColor.swift @@ -2,21 +2,21 @@ import Foundation public struct HwpColor: Codable, Equatable { // swiftlint:disable identifier_name - public let r: Int - public let g: Int - public let b: Int + public let red: Int + public let green: Int + public let blue: Int // swiftlint:enable identifier_name public init(_ data: UInt32) { - r = getBitValue(Int(data), 0, 7) - g = getBitValue(Int(data), 0, 7) - b = getBitValue(Int(data), 0, 7) + red = getBitValue(Int(data), 0, 7) + green = getBitValue(Int(data), 0, 7) + blue = getBitValue(Int(data), 0, 7) } public init(_ red: Int, _ green: Int, _ blue: Int) { - self.r = red - self.g = green - self.b = blue + self.red = red + self.green = green + self.blue = blue } } diff --git a/Sources/HwpKit/Utils/HwpData.swift b/Sources/HwpKit/Utils/HwpData.swift index 7c27fc6..f9c163e 100644 --- a/Sources/HwpKit/Utils/HwpData.swift +++ b/Sources/HwpKit/Utils/HwpData.swift @@ -3,3 +3,11 @@ import Foundation protocol HwpData: Codable { init(_ data: Data) throws } + +protocol HwpDataWithVersion: Codable { + init(_ data: Data, _ version: HwpVersion) throws +} + +protocol HwpRecordWithVersion: Codable { + init(_ record: HwpTreeRecord, _ version: HwpVersion) throws +} diff --git a/Sources/HwpKit/Utils/HwpDataWithVersion.swift b/Sources/HwpKit/Utils/HwpDataWithVersion.swift deleted file mode 100644 index 9e3f393..0000000 --- a/Sources/HwpKit/Utils/HwpDataWithVersion.swift +++ /dev/null @@ -1,5 +0,0 @@ -import Foundation - -protocol HwpDataWithVersion: Codable { - init(_ data: Data, _ version: HwpVersion) throws -} diff --git a/Sources/HwpKit/Utils/HwpRecord.swift b/Sources/HwpKit/Utils/HwpRecord.swift index 847ebd8..e60851e 100644 --- a/Sources/HwpKit/Utils/HwpRecord.swift +++ b/Sources/HwpKit/Utils/HwpRecord.swift @@ -26,7 +26,7 @@ struct HwpRecord { let payload: Data } -func parseRecordTree(data: Data) throws -> [HwpRecord] { +func parseRecordArray(data: Data) throws -> [HwpRecord] { var records = [HwpRecord]() var reader = DataReader(data) @@ -39,7 +39,6 @@ func parseRecordTree(data: Data) throws -> [HwpRecord] { if size == 0xFFF { size = reader.read(UInt32.self) } - print(tagId, level, size) let payload = reader.readBytes(Int(size)) let current = HwpRecord(tagId: tagId, level: level, payload: payload) diff --git a/Sources/HwpKit/Utils/HwpTreeRecord.swift b/Sources/HwpKit/Utils/HwpTreeRecord.swift new file mode 100644 index 0000000..743ce74 --- /dev/null +++ b/Sources/HwpKit/Utils/HwpTreeRecord.swift @@ -0,0 +1,61 @@ +import Foundation + +/** + 데이터 레코드 구조 + + 논리적으로 연관된 데이터들을 헤더 정보와 함께 저장하는 방식을 데이터 레코드라고 한다. + 레코드 구조를 가지는 스트림은 연속된 여러 개의 레코드로 구성된다. 데이터 레코드는 헤더와 데이터로 구성되며 각 헤더 정보를 활용하여 전체 논리적 구조를 생성하게 된다. + 레코드의 헤더에는 데이터 확장에 대비한 정보를 가지고 있다. + 따라서 이후에 한글의 기능이 확장되어 레코드에 데이터가 추가되는 경우에도 하위 버전의 한글이 상위 버전의 한글 문서를 읽을 수 있도록 하위 호환성이 보장된다. + */ +class HwpTreeRecord { + /** + 레코드가 나타내는 데이터의 종류를 나타내는 태그이다. Tag ID에는 10 비트가 사용되므 로 0x000 - 0x3FF까지 가능하다. + - 0x000 - 0x00F = 일반 레코드 태그가 아닌 특별한 용도로 사용한다. + - 0x010 - 0x1FF = 한글에 의해 내부용으로 예약된 영역(HWPTAG_BEGIN = 0x010) + - 0x200 - 0x3FF = 외부 어플리케이션이 사용할 수 있는 영역 + */ + let tagId: UInt32 + /** + 연관된 레코드의 논리적인 묶음을 표현하기 위한 정보 + + 대부분 하나의 오브젝트는 여러 개의 레코드로 구성되는 것이 일반적이기 때문에 + 하나의 레코드가 아닌 "논리적으로 연관된 연속된 레코드"라는 개념이 필요하다. + 스트림을 구성하는 모든 레코드는 계층 구조로 표현할 수 있는데, 레벨은 바로 이 계층 구조에서의 depth를 나타낸다. + */ + let level: UInt32 + let payload: Data + var children: [HwpTreeRecord] + + init(tagId: UInt32, level: UInt32, payload: Data) { + self.tagId = tagId + self.level = level + self.payload = payload + self.children = [HwpTreeRecord]() + } +} + +func parseTreeRecord(data: Data) -> HwpTreeRecord { + var reader = DataReader(data) + let root = HwpTreeRecord(tagId: 0, level: 0, payload: Data()) + + while !reader.isEOF() { + let value = reader.read(UInt32.self) + let tagId = value & 0x3FF + let level = (value >> 10) & 0x3FF + var size = (value >> 20) & 0xFFF + if size == 0xFFF { + size = reader.read(UInt32.self) + } + let payload = reader.readBytes(Int(size)) + + var parent = root + + for _ in 0.. [Data] { + guard let storage = streams[streamName.rawValue] else { + throw HwpError.streamDoesNotExist(name: streamName) + } + return try storage.children.map { try readData($0, isCompressed) } + } + + private func readData(_ stream: DirectoryEntry, _ isCompressed: Bool) throws -> Data { let reader = try ole.stream(stream) let data = reader.readDataToEnd() if isCompressed { guard let decompressedData = data.decompress(withAlgorithm: .zlib) else { - throw HwpError.streamDecompressFailed(name: streamName) + throw HwpError.streamDecompressFailed(name: HwpStreamName(rawValue: stream.name)!) } return decompressedData } else { diff --git a/Tests/HwpKitTests/Basic/NooriTests.swift b/Tests/HwpKitTests/Basic/NooriTests.swift index ffe3722..a6789f8 100644 --- a/Tests/HwpKitTests/Basic/NooriTests.swift +++ b/Tests/HwpKitTests/Basic/NooriTests.swift @@ -63,25 +63,25 @@ final class NooriTests: XCTestCase { let border = hwp.docInfo.borderFillArray XCTAssertEqual(border[0].borderColor[0], HwpColor(0, 0, 0)) } - + func testCharShape() throws { let hwp = try openHwp() let char = hwp.docInfo.charShapeArray XCTAssertEqual(char[0].property, 0) - XCTAssertEqual(char[0].faceColor, HwpColor(0,0,0)) + XCTAssertEqual(char[0].faceColor, HwpColor(0, 0, 0)) XCTAssertEqual(char[0].borderFillId, 2) - XCTAssertEqual(char[0].faceId, [5,5,5,5,5,5,5]) - XCTAssertEqual(char[0].faceLocation, [0,0,0,0,0,0,0]) + XCTAssertEqual(char[0].faceId, [5, 5, 5, 5, 5, 5, 5]) + XCTAssertEqual(char[0].faceLocation, [0, 0, 0, 0, 0, 0, 0]) XCTAssertEqual(char[0].faceRelativeSize, Array(repeating: 100, count: 7)) XCTAssertEqual(char[0].faceScaleX, Array(repeating: 100, count: 7)) - XCTAssertEqual(char[0].shadeColor, HwpColor(255,255,255)) - XCTAssertEqual(char[0].shadowColor, HwpColor(178,178,178)) - XCTAssertEqual(char[0].underlineColor, HwpColor(0,0,0)) - XCTAssertEqual(char[0].strikethroughColor!, HwpColor(0,0,0)) - + XCTAssertEqual(char[0].shadeColor, HwpColor(255, 255, 255)) + XCTAssertEqual(char[0].shadowColor, HwpColor(178, 178, 178)) + XCTAssertEqual(char[0].underlineColor, HwpColor(0, 0, 0)) + XCTAssertEqual(char[0].strikethroughColor!, HwpColor(0, 0, 0)) + XCTAssertEqual(char[58].property, 2) } - + func testTabDef() throws { let hwp = try openHwp() let shape = hwp.docInfo.paraShapeArray @@ -93,6 +93,10 @@ final class NooriTests: XCTestCase { ("testSectionSize", testSectionSize), ("testStartingIndex", testStartingIndex), ("testCaratLocation", testCaratLocation), - ("testBinData", testBinData) + ("testBinData", testBinData), + ("testFaceName", testFaceName), + ("testBorderFill", testBorderFill), + ("testCharShape", testCharShape), + ("testTabDef", testTabDef) ] } diff --git a/Tests/LinuxMain.swift b/Tests/LinuxMain.swift index cf4f8b8..521339c 100644 --- a/Tests/LinuxMain.swift +++ b/Tests/LinuxMain.swift @@ -1,5 +1,4 @@ import XCTest - import HwpKitTests var tests = [XCTestCaseEntry]() From af9cd3a01264913b53b9ec8010106f8a22ecb0bc Mon Sep 17 00:00:00 2001 From: Seungbin Oh Date: Mon, 5 Oct 2020 11:04:55 +0900 Subject: [PATCH 2/7] Parse ParaCharShape --- .../Model/Section/HwpParaCharShape.swift | 24 ++++++++++++++++++ .../HwpKit/Model/Section/HwpParagraph.swift | 7 +++++ .../{Basic => Blank}/BlankTests.swift | 0 Tests/HwpKitTests/{Basic => Blank}/blank.hwp | Bin .../NooriDocInfoTests.swift} | 2 +- .../HwpKitTests/Noori/NooriSectionTests.swift | 21 +++++++++++++++ Tests/HwpKitTests/{Basic => Noori}/noori.hwp | Bin Tests/HwpKitTests/XCTestManifests.swift | 2 ++ 8 files changed, 55 insertions(+), 1 deletion(-) create mode 100644 Sources/HwpKit/Model/Section/HwpParaCharShape.swift rename Tests/HwpKitTests/{Basic => Blank}/BlankTests.swift (100%) rename Tests/HwpKitTests/{Basic => Blank}/blank.hwp (100%) rename Tests/HwpKitTests/{Basic/NooriTests.swift => Noori/NooriDocInfoTests.swift} (98%) create mode 100644 Tests/HwpKitTests/Noori/NooriSectionTests.swift rename Tests/HwpKitTests/{Basic => Noori}/noori.hwp (100%) diff --git a/Sources/HwpKit/Model/Section/HwpParaCharShape.swift b/Sources/HwpKit/Model/Section/HwpParaCharShape.swift new file mode 100644 index 0000000..eb50610 --- /dev/null +++ b/Sources/HwpKit/Model/Section/HwpParaCharShape.swift @@ -0,0 +1,24 @@ +import Foundation + +public struct HwpParaCharShape: HwpData { + /**글자 모양이 바뀌는 시작 위치*/ + public var startingIndex: [UInt32] + /**글자 모양 ID*/ + public var shapeId: [UInt32] + + init(_ data: Data) throws { + var reader = DataReader(data) + defer { + precondition(reader.isEOF()) + } + + var startingIndex = [UInt32]() + var shapeId = [UInt32]() + while !reader.isEOF() { + startingIndex.append(reader.read(UInt32.self)) + shapeId.append(reader.read(UInt32.self)) + } + self.startingIndex = startingIndex + self.shapeId = shapeId + } +} diff --git a/Sources/HwpKit/Model/Section/HwpParagraph.swift b/Sources/HwpKit/Model/Section/HwpParagraph.swift index 996b019..442f8c1 100644 --- a/Sources/HwpKit/Model/Section/HwpParagraph.swift +++ b/Sources/HwpKit/Model/Section/HwpParagraph.swift @@ -3,6 +3,7 @@ import Foundation public struct HwpParagraph: HwpRecordWithVersion { public let paraHeader: HwpParaHeader public var paraText: HwpParaText? = nil + public var paraCharShape: HwpParaCharShape? = nil init(_ record: HwpTreeRecord, _ version: HwpVersion) throws { paraHeader = try HwpParaHeader(record.payload, version) @@ -12,5 +13,11 @@ public struct HwpParagraph: HwpRecordWithVersion { { self.paraText = try HwpParaText(paraText.payload) } + + if let paraCharShape = record.children + .first(where: {$0.tagId == HwpSectionTag.paraCharShape}) + { + self.paraCharShape = try HwpParaCharShape(paraCharShape.payload) + } } } diff --git a/Tests/HwpKitTests/Basic/BlankTests.swift b/Tests/HwpKitTests/Blank/BlankTests.swift similarity index 100% rename from Tests/HwpKitTests/Basic/BlankTests.swift rename to Tests/HwpKitTests/Blank/BlankTests.swift diff --git a/Tests/HwpKitTests/Basic/blank.hwp b/Tests/HwpKitTests/Blank/blank.hwp similarity index 100% rename from Tests/HwpKitTests/Basic/blank.hwp rename to Tests/HwpKitTests/Blank/blank.hwp diff --git a/Tests/HwpKitTests/Basic/NooriTests.swift b/Tests/HwpKitTests/Noori/NooriDocInfoTests.swift similarity index 98% rename from Tests/HwpKitTests/Basic/NooriTests.swift rename to Tests/HwpKitTests/Noori/NooriDocInfoTests.swift index a6789f8..68c49b4 100644 --- a/Tests/HwpKitTests/Basic/NooriTests.swift +++ b/Tests/HwpKitTests/Noori/NooriDocInfoTests.swift @@ -1,7 +1,7 @@ import HwpKit import XCTest -final class NooriTests: XCTestCase { +final class NooriDocInfoTests: XCTestCase { func openHwp() throws -> HwpFile { let url = URL(fileURLWithPath: #file) .deletingLastPathComponent() diff --git a/Tests/HwpKitTests/Noori/NooriSectionTests.swift b/Tests/HwpKitTests/Noori/NooriSectionTests.swift new file mode 100644 index 0000000..0cb410d --- /dev/null +++ b/Tests/HwpKitTests/Noori/NooriSectionTests.swift @@ -0,0 +1,21 @@ +import HwpKit +import XCTest + +final class NooriSectionTests: XCTestCase { + func openHwp() throws -> HwpFile { + let url = URL(fileURLWithPath: #file) + .deletingLastPathComponent() + .appendingPathComponent("noori.hwp") + return try HwpFile(filePath: url.path) + } + + func testSectionSize() throws { + let hwp = try openHwp() + XCTAssertEqual(hwp.docInfo.documentProperties.sectionSize, 1) + } + + static var allTests = [ + ("testSectionSize", testSectionSize) + ] +} + diff --git a/Tests/HwpKitTests/Basic/noori.hwp b/Tests/HwpKitTests/Noori/noori.hwp similarity index 100% rename from Tests/HwpKitTests/Basic/noori.hwp rename to Tests/HwpKitTests/Noori/noori.hwp diff --git a/Tests/HwpKitTests/XCTestManifests.swift b/Tests/HwpKitTests/XCTestManifests.swift index 360d9ae..22834bb 100644 --- a/Tests/HwpKitTests/XCTestManifests.swift +++ b/Tests/HwpKitTests/XCTestManifests.swift @@ -4,6 +4,8 @@ import XCTest public func allTests() -> [XCTestCaseEntry] { [ testCase(BasicTests.allTests), + testCase(NooriDocInfoTests.allTests), + testCase(NooriSectionTests.allTests), testCase(VersionTests.allTests), testCase(HwpUtilTests.allTests) ] From 4aaf1f0a88cea1a771bc5a16806cb519a57017eb Mon Sep 17 00:00:00 2001 From: Seungbin Oh Date: Mon, 5 Oct 2020 14:00:20 +0900 Subject: [PATCH 3/7] Parse ParaLineSeg in Section --- Sources/HwpKit/Model/Section/HwpChar.swift | 4 +- .../Model/Section/HwpParaCharShape.swift | 5 ++ .../HwpKit/Model/Section/HwpParaHeader.swift | 6 ++ .../HwpKit/Model/Section/HwpParaLineSeg.swift | 57 +++++++++++++++++++ .../HwpKit/Model/Section/HwpParaText.swift | 10 +++- .../HwpKit/Model/Section/HwpParagraph.swift | 6 ++ .../HwpKitTests/Noori/NooriSectionTests.swift | 53 +++++++++++++++-- 7 files changed, 133 insertions(+), 8 deletions(-) create mode 100644 Sources/HwpKit/Model/Section/HwpParaLineSeg.swift diff --git a/Sources/HwpKit/Model/Section/HwpChar.swift b/Sources/HwpKit/Model/Section/HwpChar.swift index 0e2838f..428f881 100644 --- a/Sources/HwpKit/Model/Section/HwpChar.swift +++ b/Sources/HwpKit/Model/Section/HwpChar.swift @@ -1,6 +1,6 @@ import Foundation public struct HwpChar: Codable { - let type: HwpCharType - let value: WCHAR + public let type: HwpCharType + public let value: WCHAR } diff --git a/Sources/HwpKit/Model/Section/HwpParaCharShape.swift b/Sources/HwpKit/Model/Section/HwpParaCharShape.swift index eb50610..327d729 100644 --- a/Sources/HwpKit/Model/Section/HwpParaCharShape.swift +++ b/Sources/HwpKit/Model/Section/HwpParaCharShape.swift @@ -1,5 +1,10 @@ import Foundation +/** + 문단의 글자 모양 + + Tag ID : HWPTAG_PARA_CHAR_SHAPE + */ public struct HwpParaCharShape: HwpData { /**글자 모양이 바뀌는 시작 위치*/ public var startingIndex: [UInt32] diff --git a/Sources/HwpKit/Model/Section/HwpParaHeader.swift b/Sources/HwpKit/Model/Section/HwpParaHeader.swift index ecaeb8d..3a680a8 100644 --- a/Sources/HwpKit/Model/Section/HwpParaHeader.swift +++ b/Sources/HwpKit/Model/Section/HwpParaHeader.swift @@ -1,5 +1,11 @@ import Foundation +/** + 문단 헤더 + + Tag ID : HWPTAG_PARA_HEADER + 텍스트의 수가 1 이상이면 문자 수만큼 텍스트를 로드하고 그렇지 않을 경우 PARA_BREAK로 문단을 생성한다. + */ public struct HwpParaHeader: HwpDataWithVersion { /**if (nchars & 0x80000000) { nchars &= 0x7fffffff;}*/ public let isLastInList: Bool diff --git a/Sources/HwpKit/Model/Section/HwpParaLineSeg.swift b/Sources/HwpKit/Model/Section/HwpParaLineSeg.swift new file mode 100644 index 0000000..ab0583f --- /dev/null +++ b/Sources/HwpKit/Model/Section/HwpParaLineSeg.swift @@ -0,0 +1,57 @@ +import Foundation + +/** + 문단의 레이아웃 + + Tag ID : HWPTAG_PARA_LINE_SEG + 문단의 각 줄을 출력할 때 사용한 Cache 정보이며, 문단 정보의 ‘각 줄에 대한 align에 대한 정보 수’만큼 반복한다. + */ +public struct HwpParaLineSeg: HwpData{ + /**텍스트 시작 위치*/ + public let textStartingIndex: UInt32 + /**줄의 세로 위치*/ + public let lineLocation: Int32 + /**줄의 높이*/ + public let lineHeight: Int32 + /**텍스트 부분의 높이*/ + public let textHeight: Int32 + /**줄의 세로 위치에서 베이스라인까지 거리*/ + public let baselineDistance: Int32 + /**줄간격*/ + public let lineSpacing: Int32 + /**컬럼에서의 시작 위치*/ + public let startingLocation: Int32 + /**세그먼트의 폭*/ + public let width: Int32 + /** + 태그 + - bit 0 : 페이지의 첫 줄인지 여부 + - bit 1 : 컬럼의 첫 줄인지 여부 + - bit 16 : 텍스트가 배열되지 않은 빈 세그먼 트인지 여부 + - bit 17 : 줄의 첫 세그먼트인지 여부 + - bit 18 : 줄의 마지막 세그먼트인지 여부 + - bit 19 : 줄의 마지막에 auto-hyphenation이 수행되었는지 여부. + - bit 20 : indentation 적용 + - bit 21 : 문단 머리 모양 적용 + - bit 31 : 구현상의 편의를 위한 property + */ + public let property: UInt32 + + init(_ data: Data) throws { + var reader = DataReader(data) + print(data.count) + defer { + // precondition(reader.isEOF()) + } + + textStartingIndex = reader.read(UInt32.self) + lineLocation = reader.read(Int32.self) + lineHeight = reader.read(Int32.self) + textHeight = reader.read(Int32.self) + baselineDistance = reader.read(Int32.self) + lineSpacing = reader.read(Int32.self) + startingLocation = reader.read(Int32.self) + width = reader.read(Int32.self) + property = reader.read(UInt32.self) + } +} diff --git a/Sources/HwpKit/Model/Section/HwpParaText.swift b/Sources/HwpKit/Model/Section/HwpParaText.swift index 35721fc..7fbbf13 100644 --- a/Sources/HwpKit/Model/Section/HwpParaText.swift +++ b/Sources/HwpKit/Model/Section/HwpParaText.swift @@ -1,7 +1,15 @@ import Foundation +/** + 문단의 텍스트 + + Tag ID : HWPTAG_PARA_TEXT + 문단은 최소 하나의 문자 Shape buffer가 존재하며, 첫 번째 pos가 반드시 0이어야 한다. + 텍스트 문자 Shape 레코드를 글자 모양 정보 수(Character Shapes)만큼 읽는다. + */ public struct HwpParaText: HwpData { - var charArray: [HwpChar] + /**문자수만큼의 텍스트*/ + public var charArray: [HwpChar] init(_ data: Data) throws { var reader = DataReader(data) diff --git a/Sources/HwpKit/Model/Section/HwpParagraph.swift b/Sources/HwpKit/Model/Section/HwpParagraph.swift index 442f8c1..14fe2c0 100644 --- a/Sources/HwpKit/Model/Section/HwpParagraph.swift +++ b/Sources/HwpKit/Model/Section/HwpParagraph.swift @@ -4,6 +4,8 @@ public struct HwpParagraph: HwpRecordWithVersion { public let paraHeader: HwpParaHeader public var paraText: HwpParaText? = nil public var paraCharShape: HwpParaCharShape? = nil + + public var paraLineSeg: [HwpParaLineSeg]? = nil init(_ record: HwpTreeRecord, _ version: HwpVersion) throws { paraHeader = try HwpParaHeader(record.payload, version) @@ -19,5 +21,9 @@ public struct HwpParagraph: HwpRecordWithVersion { { self.paraCharShape = try HwpParaCharShape(paraCharShape.payload) } + + paraLineSeg = try record.children + .filter {$0.tagId == HwpSectionTag.paraLineSeg} + .map {try HwpParaLineSeg($0.payload)} } } diff --git a/Tests/HwpKitTests/Noori/NooriSectionTests.swift b/Tests/HwpKitTests/Noori/NooriSectionTests.swift index 0cb410d..50bb5ce 100644 --- a/Tests/HwpKitTests/Noori/NooriSectionTests.swift +++ b/Tests/HwpKitTests/Noori/NooriSectionTests.swift @@ -8,14 +8,57 @@ final class NooriSectionTests: XCTestCase { .appendingPathComponent("noori.hwp") return try HwpFile(filePath: url.path) } - - func testSectionSize() throws { + + func testParagraph() throws { let hwp = try openHwp() - XCTAssertEqual(hwp.docInfo.documentProperties.sectionSize, 1) + for index in 0...20 { + XCTAssertNotNil(hwp.sectionArray[0].paragraph[index]) + } } - + + func testParaText() throws { + let hwp = try openHwp() + let text = hwp.sectionArray[0].paragraph[0].paraText + XCTAssertEqual(text!.charArray[0].type, .extended) + XCTAssertEqual(text!.charArray[3].type, .char) + + XCTAssertEqual(text!.charArray[0].value, 2) + XCTAssertEqual(text!.charArray[2].value, 11) + XCTAssertEqual(text!.charArray[3].value, 13) + + XCTAssertNil(hwp.sectionArray[0].paragraph[15].paraText) + XCTAssertNil(hwp.sectionArray[0].paragraph[16].paraText) + XCTAssertNil(hwp.sectionArray[0].paragraph[17].paraText) + } + + func testParaCharShape() throws { + let hwp = try openHwp() + XCTAssertEqual(hwp.sectionArray[0].paragraph[0].paraCharShape?.startingIndex[0], 0) + XCTAssertEqual(hwp.sectionArray[0].paragraph[0].paraCharShape?.shapeId[0], 19) + XCTAssertEqual(hwp.sectionArray[0].paragraph[20].paraCharShape?.startingIndex[0], 0) + XCTAssertEqual(hwp.sectionArray[0].paragraph[20].paraCharShape?.shapeId[0], 30) + } + + func testParaLineSeg() throws { + let hwp = try openHwp() + let seg0 = hwp.sectionArray[0].paragraph[0].paraLineSeg![0] + XCTAssertEqual(seg0.textStartingIndex, 0) + XCTAssertEqual(seg0.lineLocation, 0) + XCTAssertEqual(seg0.lineHeight, 6134) + XCTAssertEqual(seg0.textHeight, 6134) + XCTAssertEqual(seg0.baselineDistance, 5214) + XCTAssertEqual(seg0.lineSpacing, 840) + XCTAssertEqual(seg0.startingLocation, 0) + XCTAssertEqual(seg0.width, 48188) + + XCTAssertNotNil(hwp.sectionArray[0].paragraph[20].paraLineSeg![0]) + } + static var allTests = [ - ("testSectionSize", testSectionSize) + ("testParagraph",testParagraph), + ("testParaText", testParaText), + ("testParaCharShape",testParaCharShape), + ("testParaLineSeg",testParaLineSeg) ] } From 731f7919cafbe5f8ea3a1ed0e9737ad3ade82766 Mon Sep 17 00:00:00 2001 From: Seungbin Oh Date: Mon, 5 Oct 2020 15:03:34 +0900 Subject: [PATCH 4/7] Parse HwpParaRangeTag in Section --- Sources/HwpKit/Enums/HwpCharType.swift | 2 +- Sources/HwpKit/Enums/HwpTag.swift | 8 ++--- .../Model/Section/HwpParaCharShape.swift | 4 +-- .../HwpKit/Model/Section/HwpParaLineSeg.swift | 6 ++-- .../Model/Section/HwpParaRangeTag.swift | 31 +++++++++++++++++++ .../HwpKit/Model/Section/HwpParaText.swift | 4 +-- .../HwpKit/Model/Section/HwpParagraph.swift | 25 ++++++++------- Sources/HwpKit/Utils/HwpColor.swift | 2 -- .../HwpKitTests/Noori/NooriSectionTests.swift | 23 +++++++------- 9 files changed, 68 insertions(+), 37 deletions(-) create mode 100644 Sources/HwpKit/Model/Section/HwpParaRangeTag.swift diff --git a/Sources/HwpKit/Enums/HwpCharType.swift b/Sources/HwpKit/Enums/HwpCharType.swift index 102553f..aaa31d3 100644 --- a/Sources/HwpKit/Enums/HwpCharType.swift +++ b/Sources/HwpKit/Enums/HwpCharType.swift @@ -1,6 +1,6 @@ import Foundation -public enum HwpCharType:String, Codable { +public enum HwpCharType: String, Codable { case char case inline case extended diff --git a/Sources/HwpKit/Enums/HwpTag.swift b/Sources/HwpKit/Enums/HwpTag.swift index e3c527c..9b420b8 100644 --- a/Sources/HwpKit/Enums/HwpTag.swift +++ b/Sources/HwpKit/Enums/HwpTag.swift @@ -11,11 +11,11 @@ final class HwpDocInfoTag { static let borderFill: UInt32 = BEGIN + 4 static let charShape: UInt32 = BEGIN + 5 static let tabDef: UInt32 = BEGIN + 6 - static let NUMBERING: UInt32 = BEGIN + 7 - static let BULLET: UInt32 = BEGIN + 8 + static let numbering: UInt32 = BEGIN + 7 + static let bullet: UInt32 = BEGIN + 8 static let paraShape: UInt32 = BEGIN + 9 - static let STYLE: UInt32 = BEGIN + 10 - static let DOC_DATA: UInt32 = BEGIN + 11 + static let style: UInt32 = BEGIN + 10 + static let docData: UInt32 = BEGIN + 11 static let DISTRIBUTE_DOC_DATA: UInt32 = BEGIN + 12 static let RESERVED: UInt32 = BEGIN + 13 static let COMPATIBLE_DOCUMENT: UInt32 = BEGIN + 14 diff --git a/Sources/HwpKit/Model/Section/HwpParaCharShape.swift b/Sources/HwpKit/Model/Section/HwpParaCharShape.swift index 327d729..333d2bd 100644 --- a/Sources/HwpKit/Model/Section/HwpParaCharShape.swift +++ b/Sources/HwpKit/Model/Section/HwpParaCharShape.swift @@ -10,13 +10,13 @@ public struct HwpParaCharShape: HwpData { public var startingIndex: [UInt32] /**글자 모양 ID*/ public var shapeId: [UInt32] - + init(_ data: Data) throws { var reader = DataReader(data) defer { precondition(reader.isEOF()) } - + var startingIndex = [UInt32]() var shapeId = [UInt32]() while !reader.isEOF() { diff --git a/Sources/HwpKit/Model/Section/HwpParaLineSeg.swift b/Sources/HwpKit/Model/Section/HwpParaLineSeg.swift index ab0583f..4d6c8c9 100644 --- a/Sources/HwpKit/Model/Section/HwpParaLineSeg.swift +++ b/Sources/HwpKit/Model/Section/HwpParaLineSeg.swift @@ -6,7 +6,7 @@ import Foundation Tag ID : HWPTAG_PARA_LINE_SEG 문단의 각 줄을 출력할 때 사용한 Cache 정보이며, 문단 정보의 ‘각 줄에 대한 align에 대한 정보 수’만큼 반복한다. */ -public struct HwpParaLineSeg: HwpData{ +public struct HwpParaLineSeg: HwpData { /**텍스트 시작 위치*/ public let textStartingIndex: UInt32 /**줄의 세로 위치*/ @@ -36,14 +36,14 @@ public struct HwpParaLineSeg: HwpData{ - bit 31 : 구현상의 편의를 위한 property */ public let property: UInt32 - + init(_ data: Data) throws { var reader = DataReader(data) print(data.count) defer { // precondition(reader.isEOF()) } - + textStartingIndex = reader.read(UInt32.self) lineLocation = reader.read(Int32.self) lineHeight = reader.read(Int32.self) diff --git a/Sources/HwpKit/Model/Section/HwpParaRangeTag.swift b/Sources/HwpKit/Model/Section/HwpParaRangeTag.swift new file mode 100644 index 0000000..7a5a045 --- /dev/null +++ b/Sources/HwpKit/Model/Section/HwpParaRangeTag.swift @@ -0,0 +1,31 @@ +import Foundation + +/** + 문단의 영역 태그 + + range tag 정보를 정보 수만큼 읽어 온다. range tag는 텍스트의 일정 영역을 마킹하는 용도로 사용되 며, 글자 모양과는 달리 각 영역은 서로 겹칠 수 있다.(형광펜, 교정 부호 등) + Tag ID : HWPTAG_PARA_RANGE_TAG + */ +public struct HwpParaRangeTag: HwpData { + /**영역 시작*/ + public let start: UInt32 + /**영역 끝*/ + public let end: UInt32 + /** + 태그(종류 + 데이터) + + 상위 8비트가 종류를 하위 24비트가 종류별로 다른 설명을 부여할 수 있는 임의의 데이터를 나타낸다. + */ + public let tag: UInt32 + + init(_ data: Data) throws { + var reader = DataReader(data) + defer { + precondition(reader.isEOF()) + } + + start = reader.read(UInt32.self) + end = reader.read(UInt32.self) + tag = reader.read(UInt32.self) + } +} diff --git a/Sources/HwpKit/Model/Section/HwpParaText.swift b/Sources/HwpKit/Model/Section/HwpParaText.swift index 7fbbf13..56bd650 100644 --- a/Sources/HwpKit/Model/Section/HwpParaText.swift +++ b/Sources/HwpKit/Model/Section/HwpParaText.swift @@ -10,14 +10,14 @@ import Foundation public struct HwpParaText: HwpData { /**문자수만큼의 텍스트*/ public var charArray: [HwpChar] - + init(_ data: Data) throws { var reader = DataReader(data) var array = [HwpChar]() while !reader.isEOF() { let char = reader.read(WCHAR.self) switch char { - case 0,1,13: + case 0, 1, 13: array.append(HwpChar(type: .char, value: char)) case 4...9, 19...20: array.append(HwpChar(type: .inline, value: char)) diff --git a/Sources/HwpKit/Model/Section/HwpParagraph.swift b/Sources/HwpKit/Model/Section/HwpParagraph.swift index 14fe2c0..7ece5f6 100644 --- a/Sources/HwpKit/Model/Section/HwpParagraph.swift +++ b/Sources/HwpKit/Model/Section/HwpParagraph.swift @@ -2,28 +2,31 @@ import Foundation public struct HwpParagraph: HwpRecordWithVersion { public let paraHeader: HwpParaHeader - public var paraText: HwpParaText? = nil - public var paraCharShape: HwpParaCharShape? = nil - - public var paraLineSeg: [HwpParaLineSeg]? = nil + public var paraText: HwpParaText? + public var paraCharShape: HwpParaCharShape? + + public var paraLineSeg: [HwpParaLineSeg]? + public var paraRangeTag: [HwpParaRangeTag]? init(_ record: HwpTreeRecord, _ version: HwpVersion) throws { paraHeader = try HwpParaHeader(record.payload, version) - + if let paraText = record.children - .first(where: {$0.tagId == HwpSectionTag.paraText}) - { + .first(where: {$0.tagId == HwpSectionTag.paraText}) { self.paraText = try HwpParaText(paraText.payload) } - + if let paraCharShape = record.children - .first(where: {$0.tagId == HwpSectionTag.paraCharShape}) - { + .first(where: {$0.tagId == HwpSectionTag.paraCharShape}) { self.paraCharShape = try HwpParaCharShape(paraCharShape.payload) } - + paraLineSeg = try record.children .filter {$0.tagId == HwpSectionTag.paraLineSeg} .map {try HwpParaLineSeg($0.payload)} + + paraRangeTag = try record.children + .filter {$0.tagId == HwpSectionTag.paraRangeTag} + .map {try HwpParaRangeTag($0.payload)} } } diff --git a/Sources/HwpKit/Utils/HwpColor.swift b/Sources/HwpKit/Utils/HwpColor.swift index cdbfa2e..0ef6aba 100644 --- a/Sources/HwpKit/Utils/HwpColor.swift +++ b/Sources/HwpKit/Utils/HwpColor.swift @@ -1,11 +1,9 @@ import Foundation public struct HwpColor: Codable, Equatable { - // swiftlint:disable identifier_name public let red: Int public let green: Int public let blue: Int - // swiftlint:enable identifier_name public init(_ data: UInt32) { red = getBitValue(Int(data), 0, 7) diff --git a/Tests/HwpKitTests/Noori/NooriSectionTests.swift b/Tests/HwpKitTests/Noori/NooriSectionTests.swift index 50bb5ce..c7e49de 100644 --- a/Tests/HwpKitTests/Noori/NooriSectionTests.swift +++ b/Tests/HwpKitTests/Noori/NooriSectionTests.swift @@ -8,29 +8,29 @@ final class NooriSectionTests: XCTestCase { .appendingPathComponent("noori.hwp") return try HwpFile(filePath: url.path) } - + func testParagraph() throws { let hwp = try openHwp() for index in 0...20 { XCTAssertNotNil(hwp.sectionArray[0].paragraph[index]) } } - + func testParaText() throws { let hwp = try openHwp() let text = hwp.sectionArray[0].paragraph[0].paraText XCTAssertEqual(text!.charArray[0].type, .extended) XCTAssertEqual(text!.charArray[3].type, .char) - + XCTAssertEqual(text!.charArray[0].value, 2) XCTAssertEqual(text!.charArray[2].value, 11) XCTAssertEqual(text!.charArray[3].value, 13) - + XCTAssertNil(hwp.sectionArray[0].paragraph[15].paraText) XCTAssertNil(hwp.sectionArray[0].paragraph[16].paraText) XCTAssertNil(hwp.sectionArray[0].paragraph[17].paraText) } - + func testParaCharShape() throws { let hwp = try openHwp() XCTAssertEqual(hwp.sectionArray[0].paragraph[0].paraCharShape?.startingIndex[0], 0) @@ -38,7 +38,7 @@ final class NooriSectionTests: XCTestCase { XCTAssertEqual(hwp.sectionArray[0].paragraph[20].paraCharShape?.startingIndex[0], 0) XCTAssertEqual(hwp.sectionArray[0].paragraph[20].paraCharShape?.shapeId[0], 30) } - + func testParaLineSeg() throws { let hwp = try openHwp() let seg0 = hwp.sectionArray[0].paragraph[0].paraLineSeg![0] @@ -50,15 +50,14 @@ final class NooriSectionTests: XCTestCase { XCTAssertEqual(seg0.lineSpacing, 840) XCTAssertEqual(seg0.startingLocation, 0) XCTAssertEqual(seg0.width, 48188) - + XCTAssertNotNil(hwp.sectionArray[0].paragraph[20].paraLineSeg![0]) } - + static var allTests = [ - ("testParagraph",testParagraph), + ("testParagraph", testParagraph), ("testParaText", testParaText), - ("testParaCharShape",testParaCharShape), - ("testParaLineSeg",testParaLineSeg) + ("testParaCharShape", testParaCharShape), + ("testParaLineSeg", testParaLineSeg) ] } - From e1078f6bbbffffaf5e1c91804bf7e0070474dd81 Mon Sep 17 00:00:00 2001 From: Seungbin Oh Date: Tue, 6 Oct 2020 12:08:37 +0900 Subject: [PATCH 5/7] Parse HwpCtrlHeader and HwpListHeader --- .../HwpKit/Model/Section/HwpCtrlHeader.swift | 16 ++++++++++++ .../HwpKit/Model/Section/HwpListHeader.swift | 26 +++++++++++++++++++ .../HwpKit/Model/Section/HwpParagraph.swift | 18 ++++++++++--- .../HwpKitTests/Noori/NooriDocInfoTests.swift | 8 +++++- .../HwpKitTests/Noori/NooriSectionTests.swift | 4 +-- 5 files changed, 65 insertions(+), 7 deletions(-) create mode 100644 Sources/HwpKit/Model/Section/HwpCtrlHeader.swift create mode 100644 Sources/HwpKit/Model/Section/HwpListHeader.swift diff --git a/Sources/HwpKit/Model/Section/HwpCtrlHeader.swift b/Sources/HwpKit/Model/Section/HwpCtrlHeader.swift new file mode 100644 index 0000000..ab398fe --- /dev/null +++ b/Sources/HwpKit/Model/Section/HwpCtrlHeader.swift @@ -0,0 +1,16 @@ +import Foundation + +/** + 컨트롤 헤더 + + 컨트롤 문자가 존재하면 컨트롤 문자로부터 존재하는 컨트롤 정보를 생성한다. + Tag ID : HWPTAG_CTRL_HEADER + */ +public struct HwpCtrlHeader: HwpData { + public let id: UInt32 + + init(_ data: Data) throws { + var reader = DataReader(data) + id = reader.read(UInt32.self) + } +} diff --git a/Sources/HwpKit/Model/Section/HwpListHeader.swift b/Sources/HwpKit/Model/Section/HwpListHeader.swift new file mode 100644 index 0000000..c774dcf --- /dev/null +++ b/Sources/HwpKit/Model/Section/HwpListHeader.swift @@ -0,0 +1,26 @@ +import Foundation + +/** + 문단 리스트 헤더 + + Tag ID : HWPTAG_LIST_HEADER + */ +public struct HwpListHeader: HwpData { + /** + 문단 수 + + 한글문서에선 Int16으로 되어있으나 대부분의 경우 Int32 으로 읽어야 문제가 없다 + */ + public let paragraphCount: Int32 + public let property: UInt32 + + init(_ data: Data) throws { + var reader = DataReader(data) + defer { + precondition(reader.isEOF()) + } + + paragraphCount = reader.read(Int32.self) + property = reader.read(UInt32.self) + } +} diff --git a/Sources/HwpKit/Model/Section/HwpParagraph.swift b/Sources/HwpKit/Model/Section/HwpParagraph.swift index 7ece5f6..d1b0000 100644 --- a/Sources/HwpKit/Model/Section/HwpParagraph.swift +++ b/Sources/HwpKit/Model/Section/HwpParagraph.swift @@ -5,8 +5,10 @@ public struct HwpParagraph: HwpRecordWithVersion { public var paraText: HwpParaText? public var paraCharShape: HwpParaCharShape? - public var paraLineSeg: [HwpParaLineSeg]? - public var paraRangeTag: [HwpParaRangeTag]? + public var paraLineSegArray: [HwpParaLineSeg]? + public var paraRangeTagArray: [HwpParaRangeTag]? + public var ctrlHeaderArray: [HwpCtrlHeader]? + public var listHeaderArray: [HwpListHeader]? init(_ record: HwpTreeRecord, _ version: HwpVersion) throws { paraHeader = try HwpParaHeader(record.payload, version) @@ -21,12 +23,20 @@ public struct HwpParagraph: HwpRecordWithVersion { self.paraCharShape = try HwpParaCharShape(paraCharShape.payload) } - paraLineSeg = try record.children + paraLineSegArray = try record.children .filter {$0.tagId == HwpSectionTag.paraLineSeg} .map {try HwpParaLineSeg($0.payload)} - paraRangeTag = try record.children + paraRangeTagArray = try record.children .filter {$0.tagId == HwpSectionTag.paraRangeTag} .map {try HwpParaRangeTag($0.payload)} + + ctrlHeaderArray = try record.children + .filter {$0.tagId == HwpSectionTag.ctrlHeader} + .map {try HwpCtrlHeader($0.payload)} + + listHeaderArray = try record.children + .filter {$0.tagId == HwpSectionTag.listHeader} + .map { try HwpListHeader($0.payload)} } } diff --git a/Tests/HwpKitTests/Noori/NooriDocInfoTests.swift b/Tests/HwpKitTests/Noori/NooriDocInfoTests.swift index 68c49b4..482671d 100644 --- a/Tests/HwpKitTests/Noori/NooriDocInfoTests.swift +++ b/Tests/HwpKitTests/Noori/NooriDocInfoTests.swift @@ -89,6 +89,11 @@ final class NooriDocInfoTests: XCTestCase { XCTAssertEqual(shape[46].property1, 268) } + func testCtrlHeader() throws { + let hwp = try openHwp() + XCTAssertEqual(hwp.sectionArray[0].paragraph[2].ctrlHeaderArray![0].id, 1885826672) + } + static var allTests = [ ("testSectionSize", testSectionSize), ("testStartingIndex", testStartingIndex), @@ -97,6 +102,7 @@ final class NooriDocInfoTests: XCTestCase { ("testFaceName", testFaceName), ("testBorderFill", testBorderFill), ("testCharShape", testCharShape), - ("testTabDef", testTabDef) + ("testTabDef", testTabDef), + ("testCtrlHeader", testCtrlHeader) ] } diff --git a/Tests/HwpKitTests/Noori/NooriSectionTests.swift b/Tests/HwpKitTests/Noori/NooriSectionTests.swift index c7e49de..820a3fb 100644 --- a/Tests/HwpKitTests/Noori/NooriSectionTests.swift +++ b/Tests/HwpKitTests/Noori/NooriSectionTests.swift @@ -41,7 +41,7 @@ final class NooriSectionTests: XCTestCase { func testParaLineSeg() throws { let hwp = try openHwp() - let seg0 = hwp.sectionArray[0].paragraph[0].paraLineSeg![0] + let seg0 = hwp.sectionArray[0].paragraph[0].paraLineSegArray![0] XCTAssertEqual(seg0.textStartingIndex, 0) XCTAssertEqual(seg0.lineLocation, 0) XCTAssertEqual(seg0.lineHeight, 6134) @@ -51,7 +51,7 @@ final class NooriSectionTests: XCTestCase { XCTAssertEqual(seg0.startingLocation, 0) XCTAssertEqual(seg0.width, 48188) - XCTAssertNotNil(hwp.sectionArray[0].paragraph[20].paraLineSeg![0]) + XCTAssertNotNil(hwp.sectionArray[0].paragraph[20].paraLineSegArray![0]) } static var allTests = [ From 007f55d38981cb4ad1ec6c3f9a5e1b785821fc35 Mon Sep 17 00:00:00 2001 From: Seungbin Oh Date: Tue, 6 Oct 2020 12:20:20 +0900 Subject: [PATCH 6/7] fix lint violations --- Sources/HwpKit/Enums/HwpTag.swift | 60 +++++++++---------- .../HwpKit/Model/Section/HwpCtrlHeader.swift | 4 +- .../Model/Section/HwpParaRangeTag.swift | 3 +- .../HwpKitTests/Noori/NooriDocInfoTests.swift | 2 +- 4 files changed, 35 insertions(+), 34 deletions(-) diff --git a/Sources/HwpKit/Enums/HwpTag.swift b/Sources/HwpKit/Enums/HwpTag.swift index 9b420b8..7149831 100644 --- a/Sources/HwpKit/Enums/HwpTag.swift +++ b/Sources/HwpKit/Enums/HwpTag.swift @@ -16,15 +16,15 @@ final class HwpDocInfoTag { static let paraShape: UInt32 = BEGIN + 9 static let style: UInt32 = BEGIN + 10 static let docData: UInt32 = BEGIN + 11 - static let DISTRIBUTE_DOC_DATA: UInt32 = BEGIN + 12 - static let RESERVED: UInt32 = BEGIN + 13 - static let COMPATIBLE_DOCUMENT: UInt32 = BEGIN + 14 - static let LAYOUT_COMPATIBILITY: UInt32 = BEGIN + 15 - static let TRACKCHANGE: UInt32 = BEGIN + 16 - static let MEMO_SHAPE: UInt32 = BEGIN + 76 - static let FORBIDDEN_CHAR: UInt32 = BEGIN + 78 - static let TRACK_CHANGE: UInt32 = BEGIN + 80 - static let TRACK_CHANGE_AUTHOR: UInt32 = BEGIN + 81 + static let distributeDocData: UInt32 = BEGIN + 12 + static let reserved: UInt32 = BEGIN + 13 + static let compatibleDocument: UInt32 = BEGIN + 14 + static let layoutCompatibility: UInt32 = BEGIN + 15 + static let trackChange: UInt32 = BEGIN + 16 + static let memoShape: UInt32 = BEGIN + 76 + static let forbiddenChar: UInt32 = BEGIN + 78 + static let trackChangeContent: UInt32 = BEGIN + 80 + static let trackChangeAuthor: UInt32 = BEGIN + 81 } /** @@ -40,26 +40,26 @@ final class HwpSectionTag { static let listHeader: UInt32 = BEGIN + 56 static let pageDef: UInt32 = BEGIN + 57 static let footnoteShape: UInt32 = BEGIN + 58 - static let PAGE_BORDER_FILL: UInt32 = BEGIN + 59 - static let SHAPE_COMPONENT: UInt32 = BEGIN + 60 + static let pageBorderFill: UInt32 = BEGIN + 59 + static let shapeComponent: UInt32 = BEGIN + 60 static let table: UInt32 = BEGIN + 61 - static let SHAPE_COMPONENT_LINE: UInt32 = BEGIN + 62 - static let SHAPE_COMPONENT_RECTANGLE: UInt32 = BEGIN + 63 - static let SHAPE_COMPONENT_ELLIPSE: UInt32 = BEGIN + 64 - static let SHAPE_COMPONENT_ARC: UInt32 = BEGIN + 65 - static let SHAPE_COMPONENT_POLYGON: UInt32 = BEGIN + 66 - static let SHAPE_COMPONENT_CURVE: UInt32 = BEGIN + 67 - static let SHAPE_COMPONENT_OLE: UInt32 = BEGIN + 68 - static let SHAPE_COMPONENT_PICTURE: UInt32 = BEGIN + 69 - static let SHAPE_COMPONENT_CONTAINER: UInt32 = BEGIN + 70 - static let CTRL_DATA: UInt32 = BEGIN + 71 - static let EQEDIT: UInt32 = BEGIN + 72 - static let RESERVED: UInt32 = BEGIN + 73 - static let SHAPE_COMPONENT_TEXTART: UInt32 = BEGIN + 74 - static let FORM_OBJECT: UInt32 = BEGIN + 75 - static let MEMO_SHAPE: UInt32 = BEGIN + 76 - static let MEMO_LIST: UInt32 = BEGIN + 77 - static let CHART_DATA: UInt32 = BEGIN + 79 - static let VIDEO_DATA: UInt32 = BEGIN + 82 - static let SHAPE_COMPONENT_UNKNOWN: UInt32 = BEGIN + 99 + static let shapeComponentLine: UInt32 = BEGIN + 62 + static let shapeComponentRectangle: UInt32 = BEGIN + 63 + static let shapeComponentEllipse: UInt32 = BEGIN + 64 + static let shapeComponentArc: UInt32 = BEGIN + 65 + static let shapeComponentPolygon: UInt32 = BEGIN + 66 + static let shapeComponentCurve: UInt32 = BEGIN + 67 + static let shapeComponentOle: UInt32 = BEGIN + 68 + static let shapeComponentPicture: UInt32 = BEGIN + 69 + static let shapeComponentContainer: UInt32 = BEGIN + 70 + static let ctrlData: UInt32 = BEGIN + 71 + static let eqEdit: UInt32 = BEGIN + 72 + static let reserved: UInt32 = BEGIN + 73 + static let shapeComponentTextart: UInt32 = BEGIN + 74 + static let formObject: UInt32 = BEGIN + 75 + static let memoShape: UInt32 = BEGIN + 76 + static let memoList: UInt32 = BEGIN + 77 + static let chartData: UInt32 = BEGIN + 79 + static let videoData: UInt32 = BEGIN + 82 + static let shapeComponentUnknown: UInt32 = BEGIN + 99 } diff --git a/Sources/HwpKit/Model/Section/HwpCtrlHeader.swift b/Sources/HwpKit/Model/Section/HwpCtrlHeader.swift index ab398fe..6b9dd62 100644 --- a/Sources/HwpKit/Model/Section/HwpCtrlHeader.swift +++ b/Sources/HwpKit/Model/Section/HwpCtrlHeader.swift @@ -7,10 +7,10 @@ import Foundation Tag ID : HWPTAG_CTRL_HEADER */ public struct HwpCtrlHeader: HwpData { - public let id: UInt32 + public let ctrlId: UInt32 init(_ data: Data) throws { var reader = DataReader(data) - id = reader.read(UInt32.self) + ctrlId = reader.read(UInt32.self) } } diff --git a/Sources/HwpKit/Model/Section/HwpParaRangeTag.swift b/Sources/HwpKit/Model/Section/HwpParaRangeTag.swift index 7a5a045..6a8cd1a 100644 --- a/Sources/HwpKit/Model/Section/HwpParaRangeTag.swift +++ b/Sources/HwpKit/Model/Section/HwpParaRangeTag.swift @@ -3,7 +3,8 @@ import Foundation /** 문단의 영역 태그 - range tag 정보를 정보 수만큼 읽어 온다. range tag는 텍스트의 일정 영역을 마킹하는 용도로 사용되 며, 글자 모양과는 달리 각 영역은 서로 겹칠 수 있다.(형광펜, 교정 부호 등) + range tag 정보를 정보 수만큼 읽어 온다. range tag는 텍스트의 일정 영역을 마킹하는 용도로 사용되며, + 글자 모양과는 달리 각 영역은 서로 겹칠 수 있다.(형광펜, 교정 부호 등) Tag ID : HWPTAG_PARA_RANGE_TAG */ public struct HwpParaRangeTag: HwpData { diff --git a/Tests/HwpKitTests/Noori/NooriDocInfoTests.swift b/Tests/HwpKitTests/Noori/NooriDocInfoTests.swift index 482671d..338426a 100644 --- a/Tests/HwpKitTests/Noori/NooriDocInfoTests.swift +++ b/Tests/HwpKitTests/Noori/NooriDocInfoTests.swift @@ -91,7 +91,7 @@ final class NooriDocInfoTests: XCTestCase { func testCtrlHeader() throws { let hwp = try openHwp() - XCTAssertEqual(hwp.sectionArray[0].paragraph[2].ctrlHeaderArray![0].id, 1885826672) + XCTAssertEqual(hwp.sectionArray[0].paragraph[2].ctrlHeaderArray![0].ctrlId, 1885826672) } static var allTests = [ From b9b527386bb4201b683d9e2ca44ee0d1ba41e249 Mon Sep 17 00:00:00 2001 From: Seungbin Oh Date: Tue, 6 Oct 2020 13:49:08 +0900 Subject: [PATCH 7/7] delete print --- Sources/HwpKit/Model/Section/HwpParaLineSeg.swift | 1 - 1 file changed, 1 deletion(-) diff --git a/Sources/HwpKit/Model/Section/HwpParaLineSeg.swift b/Sources/HwpKit/Model/Section/HwpParaLineSeg.swift index 4d6c8c9..7ad1329 100644 --- a/Sources/HwpKit/Model/Section/HwpParaLineSeg.swift +++ b/Sources/HwpKit/Model/Section/HwpParaLineSeg.swift @@ -39,7 +39,6 @@ public struct HwpParaLineSeg: HwpData { init(_ data: Data) throws { var reader = DataReader(data) - print(data.count) defer { // precondition(reader.isEOF()) }