Skip to content

Commit

Permalink
feat(parser): strict 옵션 추가
Browse files Browse the repository at this point in the history
  • Loading branch information
hahnlee committed May 17, 2024
1 parent d536fd8 commit 9f9d5a8
Show file tree
Hide file tree
Showing 14 changed files with 60 additions and 22 deletions.
3 changes: 3 additions & 0 deletions packages/parser/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,4 +26,7 @@ export * from './constants/ctrl-id.js'
export * from './models/document.js'
export * from './models/controls/page-definition.js'

// type export only
export type * from './types/parser.js'

export * from './parse.js'
7 changes: 5 additions & 2 deletions packages/parser/src/models/controls/common-properties.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import type { HWPRecord } from '../record.js'
import { SectionTagID } from '../../constants/tag-id.js'
import type { HWPVersion } from '../version.js'
import { ParagraphList } from './paragraph-list.js'
import type { ParseOptions } from '../../types/parser.js'

/**
* 개체 공통 속성
Expand Down Expand Up @@ -112,6 +113,7 @@ export class CommonProperties {
record: HWPRecord,
iterator: PeekableIterator<HWPRecord>,
version: HWPVersion,
options: ParseOptions,
) {
const reader = new ByteReader(record.data)
const ctrlId = reader.readUInt32()
Expand Down Expand Up @@ -185,7 +187,7 @@ export class CommonProperties {

const caption =
iterator.peek().id === SectionTagID.HWPTAG_LIST_HEADER
? Caption.fromRecords(iterator, version)
? Caption.fromRecords(iterator, version, options)
: undefined

return new CommonProperties(
Expand Down Expand Up @@ -404,14 +406,15 @@ export class Caption {
static fromRecords(
iterator: PeekableIterator<HWPRecord>,
version: HWPVersion,
options: ParseOptions,
) {
const record = iterator.next()
if (record.id !== SectionTagID.HWPTAG_LIST_HEADER) {
throw new Error('Caption: Record has wrong ID')
}

const reader = new ByteReader(record.data)
const paragraphs = ParagraphList.fromReader(reader, iterator, version)
const paragraphs = ParagraphList.fromReader(reader, iterator, version, options)

const attribute = reader.readUInt32()
const align = mapCaptionAlign(getBitValue(attribute, 0, 1))
Expand Down
6 changes: 4 additions & 2 deletions packages/parser/src/models/controls/content.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
*/

import { CommonCtrlID, OtherCtrlID } from '../../constants/ctrl-id.js'
import type { ParseOptions } from '../../types/parser.js'
import type { PeekableIterator } from '../../utils/generator.js'
import type { HWPRecord } from '../record.js'
import { HWPVersion } from '../version.js'
Expand All @@ -36,14 +37,15 @@ export function parseControl(
current: HWPRecord,
iterator: PeekableIterator<HWPRecord>,
version: HWPVersion,
options: ParseOptions,
): ControlContent {
switch (ctrlId) {
case OtherCtrlID.Section:
return SectionControl.fromRecord(current, iterator, version)
case CommonCtrlID.Table:
return TableControl.fromRecord(current, iterator, version)
return TableControl.fromRecord(current, iterator, version, options)
case CommonCtrlID.GenShapeObject:
return GenShapeObjectControl.fromRecord(current, iterator, version)
return GenShapeObjectControl.fromRecord(current, iterator, version, options)
default:
return UnknownControl.fromRecord(current, iterator)
}
Expand Down
4 changes: 3 additions & 1 deletion packages/parser/src/models/controls/draw-text.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { SectionTagID } from '../../constants/tag-id.js'
import type { ParseOptions } from '../../types/parser.js'
import { ByteReader } from '../../utils/byte-reader.js'
import type { PeekableIterator } from '../../utils/generator.js'
import type { HWPRecord } from '../record.js'
Expand Down Expand Up @@ -27,14 +28,15 @@ export class DrawText {
static fromRecords(
records: PeekableIterator<HWPRecord>,
version: HWPVersion,
options: ParseOptions,
) {
const record = records.next()
if (record.id !== SectionTagID.HWPTAG_LIST_HEADER) {
throw new Error('BodyText: DrawText: Record has wrong ID')
}

const reader = new ByteReader(record.data)
const paragraphs = ParagraphList.fromReader(reader, records, version)
const paragraphs = ParagraphList.fromReader(reader, records, version, options)

const marginLeft = reader.readUInt16()
const marginRight = reader.readUInt16()
Expand Down
4 changes: 3 additions & 1 deletion packages/parser/src/models/controls/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,15 @@ import type { HWPRecord } from '../record.js'
import { SectionTagID } from '../../constants/tag-id.js'
import { type ControlContent, parseControl } from './content.js'
import { HWPVersion } from '../version.js'
import type { ParseOptions } from '../../types/parser.js'

export class Control {
constructor(public id: number, public content: ControlContent) {}

static fromRecords(
iterator: PeekableIterator<HWPRecord>,
version: HWPVersion,
options: ParseOptions,
) {
const current = iterator.next()
if (current.id !== SectionTagID.HWPTAG_CTRL_HEADER) {
Expand All @@ -36,7 +38,7 @@ export class Control {
const reader = new ByteReader(current.data)
const id = reader.readUInt32()

const content = parseControl(id, current, iterator, version)
const content = parseControl(id, current, iterator, version, options)

return new Control(id, content)
}
Expand Down
4 changes: 3 additions & 1 deletion packages/parser/src/models/controls/paragraph-list.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import type { PeekableIterator } from '../../utils/generator.js'
import type { HWPRecord } from '../record.js'
import type { HWPVersion } from '../version.js'
import { Paragraph } from '../paragraph.js'
import type { ParseOptions } from '../../types/parser.js'

/**
* 문단 리스트
Expand All @@ -33,13 +34,14 @@ export class ParagraphList {
reader: ByteReader,
iterator: PeekableIterator<HWPRecord>,
version: HWPVersion,
options: ParseOptions,
) {
const header = ParagraphListHeader.fromReader(reader)

// NOTE: 나머지 속성은 사용처에서 파싱해야함
const paragraphs: Paragraph[] = []
for (let i = 0; i < header.count; i++) {
paragraphs.push(Paragraph.fromRecord(iterator, version))
paragraphs.push(Paragraph.fromRecord(iterator, version, options))
}

return new ParagraphList(header, paragraphs)
Expand Down
3 changes: 3 additions & 0 deletions packages/parser/src/models/controls/shapes/picture.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
*/

import { SectionTagID } from '../../../constants/tag-id.js'
import type { ParseOptions } from '../../../types/parser.js'
import { getBitValue, getFlag } from '../../../utils/bit-utils.js'
import { ByteReader } from '../../../utils/byte-reader.js'
import type { PeekableIterator } from '../../../utils/generator.js'
Expand Down Expand Up @@ -49,11 +50,13 @@ export class PictureControl {
record: HWPRecord,
iterator: PeekableIterator<HWPRecord>,
version: HWPVersion,
options: ParseOptions,
) {
const commonProperties = CommonProperties.fromRecord(
record,
iterator,
version,
options,
)
const elementProperties = ElementProperties.fromRecords(iterator, false)
const content = PictureRecord.fromRecords(iterator)
Expand Down
5 changes: 4 additions & 1 deletion packages/parser/src/models/controls/shapes/shape.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
*/

import { SectionTagID } from '../../../constants/tag-id.js'
import type { ParseOptions } from '../../../types/parser.js'
import type { PeekableIterator } from '../../../utils/generator.js'
import type { HWPRecord } from '../../record.js'
import type { HWPVersion } from '../../version.js'
Expand Down Expand Up @@ -42,18 +43,20 @@ export class GenShapeObjectControl {
record: HWPRecord,
iterator: PeekableIterator<HWPRecord>,
version: HWPVersion,
options: ParseOptions,
) {
const commonProperties = CommonProperties.fromRecord(
record,
iterator,
version,
options,
)

const elementProperties = ElementProperties.fromRecords(iterator, true)

const drawText =
iterator.peek().id === SectionTagID.HWPTAG_LIST_HEADER
? DrawText.fromRecords(iterator, version)
? DrawText.fromRecords(iterator, version, options)
: null

const content = parseContent(elementProperties, record, iterator)
Expand Down
8 changes: 6 additions & 2 deletions packages/parser/src/models/controls/table.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import { HWPVersion } from '../version.js'
import { CommonProperties } from './common-properties.js'
import { SectionTagID } from '../../constants/tag-id.js'
import { ParagraphList } from './paragraph-list.js'
import type { ParseOptions } from '../../types/parser.js'

export class TableControl {
constructor(
Expand All @@ -35,11 +36,13 @@ export class TableControl {
record: HWPRecord,
iterator: PeekableIterator<HWPRecord>,
version: HWPVersion,
options: ParseOptions,
) {
const commonProperties = CommonProperties.fromRecord(
record,
iterator,
version,
options,
)

const next = iterator.next()
Expand All @@ -54,7 +57,7 @@ export class TableControl {
)

for (let i = 0; i < cellCount; i++) {
cells.push(Cell.fromRecords(iterator, version))
cells.push(Cell.fromRecords(iterator, version, options))
}

return new TableControl(commonProperties, tableRecord, cells)
Expand Down Expand Up @@ -209,14 +212,15 @@ export class Cell {
static fromRecords(
iterator: PeekableIterator<HWPRecord>,
version: HWPVersion,
options: ParseOptions,
) {
const record = iterator.next()
if (record.id !== SectionTagID.HWPTAG_LIST_HEADER) {
throw new Error('BodyText: Cell: Record has wrong ID')
}

const reader = new ByteReader(record.data)
const paragraphs = ParagraphList.fromReader(reader, iterator, version)
const paragraphs = ParagraphList.fromReader(reader, iterator, version, options)

const column = reader.readUInt16()
const row = reader.readUInt16()
Expand Down
8 changes: 5 additions & 3 deletions packages/parser/src/models/document.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,13 @@
*/

import { find, read } from 'cfb'
import { inflate } from 'pako'

import { DocInfo } from './doc-info/doc-info.js'
import { HWPHeader } from './header.js'
import { Section } from './section.js'
import { BinData } from './bin-data.js'
import { inflate } from 'pako'
import type { ParseOptions } from '../types/parser.js'

export class HWPDocument {
constructor(
Expand All @@ -29,7 +31,7 @@ export class HWPDocument {
public binDataList: BinData[],
) {}

static fromBytes(buffer: Uint8Array) {
static fromBytes(buffer: Uint8Array, options: ParseOptions) {
const container = read(buffer, {
type: 'array',
})
Expand All @@ -45,7 +47,7 @@ export class HWPDocument {
if (!entry) {
throw new Error('Section not exist')
}
sections.push(Section.fromEntry(entry, header))
sections.push(Section.fromEntry(entry, header, options))
}

const binDataList: BinData[] = []
Expand Down
6 changes: 4 additions & 2 deletions packages/parser/src/models/paragraph.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import { CharList } from './char-list.js'
import { collectChildren } from '../utils/record.js'
import { RangeTag } from './range-tag.js'
import { CharShape } from './char-shape.js'
import type { ParseOptions } from '../types/parser.js'

export class Paragraph {
constructor(
Expand All @@ -40,6 +41,7 @@ export class Paragraph {
static fromRecord(
iterator: PeekableIterator<HWPRecord>,
version: HWPVersion,
options: ParseOptions,
) {
const current = iterator.next()
const header = ParagraphHeader.fromRecord(current, version)
Expand Down Expand Up @@ -98,11 +100,11 @@ export class Paragraph {

const controls: Control[] = chars
.extendedControls()
.map(() => Control.fromRecords(iterator, version))
.map(() => Control.fromRecords(iterator, version, options))

const unknown = collectChildren(iterator, current.level)

if (unknown.length > 0) {
if (options.strict && unknown.length > 0) {
throw new Error('BodyText: Paragraph: Unknown records')
}

Expand Down
11 changes: 6 additions & 5 deletions packages/parser/src/models/section.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,27 +21,28 @@ import type { HWPHeader } from './header.js'
import { Paragraph } from './paragraph.js'
import { ByteReader } from '../utils/byte-reader.js'
import { PeekableIterator } from '../utils/generator.js'
import type { ParseOptions } from '../types/parser.js'

export class Section {
constructor(public paragraphs: Paragraph[]) {}

static fromEntry(entry: CFB$Entry, header: HWPHeader): Section {
static fromEntry(entry: CFB$Entry, header: HWPHeader, options: ParseOptions): Section {
const content = Uint8Array.from(entry.content)

if (header.flags.compressed) {
const decoded = inflate(content, { windowBits: -15 })
return Section.fromBuffer(decoded.buffer, header)
return Section.fromBuffer(decoded.buffer, header, options)
}

return Section.fromBuffer(content.buffer, header)
return Section.fromBuffer(content.buffer, header, options)
}

static fromBuffer(buffer: ArrayBuffer, header: HWPHeader): Section {
static fromBuffer(buffer: ArrayBuffer, header: HWPHeader, options: ParseOptions): Section {
const reader = new ByteReader(buffer)
const records = new PeekableIterator(reader.records())
const paragraphs: Paragraph[] = []
while (!records.isDone()) {
paragraphs.push(Paragraph.fromRecord(records, header.version))
paragraphs.push(Paragraph.fromRecord(records, header.version, options))
}
return new Section(paragraphs)
}
Expand Down
10 changes: 8 additions & 2 deletions packages/parser/src/parse.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,15 @@
*/

import { HWPDocument } from './models/document.js'
import type { ParseOptions } from './types/parser.js'

export function parse(buffer: Uint8Array | ArrayBuffer): HWPDocument {
return HWPDocument.fromBytes(convertTypedArray(buffer))
export function parse(
buffer: Uint8Array | ArrayBuffer,
{ strict = true }: Partial<ParseOptions> = {},
): HWPDocument {
return HWPDocument.fromBytes(convertTypedArray(buffer), {
strict,
})
}

function convertTypedArray(data: Uint8Array | ArrayBuffer): Uint8Array {
Expand Down
3 changes: 3 additions & 0 deletions packages/parser/src/types/parser.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export interface ParseOptions {
strict: boolean
}

0 comments on commit 9f9d5a8

Please sign in to comment.