Skip to content

Commit

Permalink
feat: control 새 구조 변경
Browse files Browse the repository at this point in the history
  • Loading branch information
hahnlee committed Apr 11, 2024
1 parent 8c0be72 commit 357b9da
Show file tree
Hide file tree
Showing 40 changed files with 3,655 additions and 1,540 deletions.
4 changes: 0 additions & 4 deletions packages/parser/src/__tests__/parse.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,9 +39,5 @@ describe('parse', () => {

it('should be collect page size', () => {
assert.strictEqual(hwpDocument.sections.length, 1)

// A4 width / height
assert.strictEqual(hwpDocument.sections[0].width, 59528)
assert.strictEqual(hwpDocument.sections[0].height, 84188)
})
})
3 changes: 2 additions & 1 deletion packages/parser/src/constants/ctrl-id.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,11 +37,12 @@ export enum CommonCtrlID {
Curve = makeCtrlID('$', 'c', 'u', 'r'),
Equation = makeCtrlID('e', 'q', 'e', 'd'),
Picture = makeCtrlID('$', 'p', 'i', 'c'),
Container = makeCtrlID('$', 'c', 'o', 'n'),
OLE = makeCtrlID('$', 'o', 'l', 'e'),
Connected = makeCtrlID('$', 'c', 'o', 'n'),

// NOTE: (@hahnlee) 공개된 문서에서 자세히 설명되어 있지는 않으나, 개채요소 설명에 따라 GenShapeObject로 추측됨
GenShapeObject = makeCtrlID('g', 's', 'o', ' ')
GenShapeObject = makeCtrlID('g', 's', 'o', ' '),
}

export enum OtherCtrlID {
Expand Down
37 changes: 20 additions & 17 deletions packages/parser/src/doc-info-parser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,12 @@ import { getRGB, getFlag, getBitValue } from './utils/bit-utils.js'
import { BorderFill } from './models/doc-info/border-fill.js'
import { HWPRecord } from './models/record.js'
import { Panose } from './models/doc-info/panose.js'
import { parseRecordTree } from './parse-record.js'
import { HWPHeader } from './models/header.js'
import { PeekableIterator } from './utils/generator.js'
import { collectChildren } from './utils/record.js'

export class DocInfoParser {
private record: HWPRecord
private reader: ByteReader

private result = new DocInfo()

Expand All @@ -43,12 +44,12 @@ export class DocInfoParser {

constructor(header: HWPHeader, data: Uint8Array, container: CFB$Container) {
this.header = header
this.record = parseRecordTree(data)
this.reader = new ByteReader(data.buffer)
this.container = container
}

visitDocumentProperties(record: HWPRecord) {
const reader = new ByteReader(record.payload)
const reader = new ByteReader(record.data)
this.result.sectionSize = reader.readUInt16()

this.result.startingIndex.page = reader.readUInt16()
Expand All @@ -64,7 +65,7 @@ export class DocInfoParser {
}

visitCharShape(record: HWPRecord) {
const reader = new ByteReader(record.payload)
const reader = new ByteReader(record.data)

const charShape = new CharShape(
[
Expand Down Expand Up @@ -122,19 +123,19 @@ export class DocInfoParser {
reader.readUInt32(),
)

if (record.size > 68) {
if (record.data.byteLength > 68) {
charShape.fontBackgroundId = reader.readUInt16()
}

if (record.size > 70) {
if (record.data.byteLength > 70) {
charShape.underLineColor = getRGB(reader.readInt32())
}

this.result.charShapes.push(charShape)
}

visitFaceName(record: HWPRecord) {
const reader = new ByteReader(record.payload)
const reader = new ByteReader(record.data)
const attribute = reader.readUInt8()
const hasAlternative = getFlag(attribute, 7)
const hasAttribute = getFlag(attribute, 6)
Expand Down Expand Up @@ -172,7 +173,7 @@ export class DocInfoParser {
}

visitBinData(record: HWPRecord) {
const reader = new ByteReader(record.payload)
const reader = new ByteReader(record.data)
// TODO: (@hahnlee) parse properties
const attribute = reader.readUInt16()

Expand Down Expand Up @@ -201,7 +202,7 @@ export class DocInfoParser {
}

visitBorderFill(record: HWPRecord) {
const reader = new ByteReader(record.payload)
const reader = new ByteReader(record.data)

const borderFill = new BorderFill(
reader.readUInt16(),
Expand Down Expand Up @@ -239,7 +240,7 @@ export class DocInfoParser {
}

visitParagraphShape(record: HWPRecord) {
const reader = new ByteReader(record.payload)
const reader = new ByteReader(record.data)
const attribute = reader.readUInt32()

const shape = new ParagraphShape()
Expand All @@ -248,21 +249,21 @@ export class DocInfoParser {
}

visitCompatibleDocument(record: HWPRecord) {
const reader = new ByteReader(record.payload)
const reader = new ByteReader(record.data)
this.result.compatibleDocument = reader.readUInt32()
}

visitLayoutCompatibility(record: HWPRecord) {
const reader = new ByteReader(record.payload)
const reader = new ByteReader(record.data)
this.result.layoutCompatibility.char = reader.readUInt32()
this.result.layoutCompatibility.paragraph = reader.readUInt32()
this.result.layoutCompatibility.section = reader.readUInt32()
this.result.layoutCompatibility.object = reader.readUInt32()
this.result.layoutCompatibility.field = reader.readUInt32()
}

private visit = (record: HWPRecord) => {
switch (record.tagID) {
private visit = (record: HWPRecord, iterator: PeekableIterator<HWPRecord>) => {
switch (record.id) {
case DocInfoTagID.HWPTAG_DOCUMENT_PROPERTIES: {
this.visitDocumentProperties(record)
break
Expand Down Expand Up @@ -307,11 +308,13 @@ export class DocInfoParser {
break
}

record.children.forEach(this.visit)
collectChildren(iterator, record.level).forEach(record => this.visit(record, iterator))
}

parse() {
this.record.children.forEach(this.visit)
const iterator = new PeekableIterator(this.reader.records())
const record = iterator.next()
this.visit(record, iterator)
return this.result
}
}
2 changes: 1 addition & 1 deletion packages/parser/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ export * from './models/controls/table.js'
export * from './models/paragraph-list.js'
export * from './constants/ctrl-id.js'
export * from './models/document.js'
export * from './utils/control-util.js'
export * from './models/controls/page-definition.js'
export * from './types/color.js'

export * from './parse.js'
74 changes: 74 additions & 0 deletions packages/parser/src/models/char-list.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
/**
* Copyright Han Lee <hanlee.dev@gmail.com> and other contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

import {
type HWPChar,
CharControl,
CharControls,
ExtendedControl,
readChar,
} from './char.js'
import type { HWPRecord } from './record.js'
import { SectionTagID } from '../constants/tag-id.js'
import { ByteReader } from '../utils/byte-reader.js'

export class CharList {
constructor(private chars: HWPChar[]) {}

static empty() {
return new CharList([new CharControl(CharControls.ParaBreak)])
}

static fromRecord(record: HWPRecord, count: number) {
if (record.id !== SectionTagID.HWPTAG_PARA_TEXT) {
throw new Error('BodyText: CharList: Record has wrong ID')
}

const reader = new ByteReader(record.data)

const chars: HWPChar[] = []
let i = 0
while (i < count) {
const char = readChar(reader)
i += char.bytes
chars.push(char)
}

if (!reader.isEOF()) {
throw new Error('BodyText: CharList: Reader is not EOF')
}

return new CharList(chars)
}

*[Symbol.iterator]() {
for (const char of this.chars) {
yield char
}
}

get length() {
return this.chars.length
}

extendedControls() {
return this.chars.filter((char) => char instanceof ExtendedControl)
}

toString() {
return this.chars.map((char) => char.toString()).join('')
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,27 +14,20 @@
* limitations under the License.
*/

import { ByteReader } from './utils/byte-reader.js'
import { HWPRecord } from './models/record.js'
import type { ByteReader } from '../utils/byte-reader.js'

export function parseRecordTree(data: Uint8Array): HWPRecord {
const reader = new ByteReader(data.buffer)
export class CharShape {
constructor(
/** 글자 모양이 바뀌는 시작 위치 */
public startPosition: number,
/** 글자 모양 ID */
public shapeId: number,
) {}

const root = new HWPRecord(0, 0, 0)
static fromReader(reader: ByteReader) {
const startPosition = reader.readUInt32()
const shapeId = reader.readUInt32()

while (!reader.isEOF()) {
const [tagID, level, size] = reader.readRecord()

let parent: HWPRecord = root

const payload = reader.read(size)

for (let i = 0; i < level; i += 1) {
parent = parent.children.slice(-1).pop()!
}

parent.children.push(new HWPRecord(tagID, size, parent.tagID, payload))
return new CharShape(startPosition, shapeId)
}

return root
}
Loading

0 comments on commit 357b9da

Please sign in to comment.