├── .gitattributes
├── .gitignore
├── HwpSharp.sln
├── LICENSE
├── README.md
├── global.json
├── src
└── HwpSharp
│ ├── Common
│ ├── Exceptions.cs
│ ├── IBodyText.cs
│ ├── IDocumentInformation.cs
│ ├── IFileHeader.cs
│ ├── IHwpDocument.cs
│ └── ISummaryInformation.cs
│ ├── Hwp5
│ ├── BodyText
│ │ ├── BodyText.cs
│ │ ├── DataRecords
│ │ │ ├── ParagraphHeader.cs
│ │ │ └── ParagraphText.cs
│ │ └── Section.cs
│ ├── Document.cs
│ ├── DocumentInformation
│ │ ├── DataRecords
│ │ │ ├── BinData.cs
│ │ │ ├── BorderFill.cs
│ │ │ ├── DocumentProperty.cs
│ │ │ ├── FaceName.cs
│ │ │ └── IdMapping.cs
│ │ └── DocumentInformation.cs
│ ├── FileHeader.cs
│ ├── HwpType
│ │ ├── DataRecord.cs
│ │ ├── DataTypes.cs
│ │ └── TagEnum.cs
│ └── SummaryInformation.cs
│ ├── HwpReader.cs
│ ├── HwpSharp.xproj
│ └── project.json
└── test
├── HwpSharp.Tests.Console
├── HwpSharp.Tests.Console.xproj
├── Program.cs
└── project.json
├── HwpSharp.Tests
├── Hwp5
│ ├── BodyTextTest.cs
│ ├── DocumentInformationTest.cs
│ ├── DocumentTest.cs
│ └── FileHeaderTest.cs
├── HwpSharp.Tests.xproj
└── project.json
└── case
├── CompoundFile.xls
├── Hwp3File.hwp
├── Hwp5
├── BlogForm_BookReview.hwp
├── BlogForm_MovieReview.hwp
├── BlogForm_Recipe.hwp
├── BookReview.hwp
├── Hyper(hwp2010).hwp
├── KTX.hwp
├── NewYear_s_Day.hwp
├── Textmail.hwp
├── Worldcup_FIFA2010_32.hwp
├── borderfill.hwp
├── calendar_monthly.hwp
├── calendar_year.hwp
├── classical_literature.hwp
├── distribution.hwp
├── english.hwp
├── interview.hwp
├── multisection.hwp
├── request.hwp
├── shortcut.hwp
├── sungeo.hwp
└── treatise sample.hwp
└── PdfFile.pdf
/.gitattributes:
--------------------------------------------------------------------------------
1 | ###############################################################################
2 | # Set default behavior to automatically normalize line endings.
3 | ###############################################################################
4 | * text=auto
5 |
6 | ###############################################################################
7 | # Set default behavior for command prompt diff.
8 | #
9 | # This is need for earlier builds of msysgit that does not have it on by
10 | # default for csharp files.
11 | # Note: This is only used by command line
12 | ###############################################################################
13 | #*.cs diff=csharp
14 |
15 | ###############################################################################
16 | # Set the merge driver for project and solution files
17 | #
18 | # Merging from the command prompt will add diff markers to the files if there
19 | # are conflicts (Merging from VS is not affected by the settings below, in VS
20 | # the diff markers are never inserted). Diff markers may cause the following
21 | # file extensions to fail to load in VS. An alternative would be to treat
22 | # these files as binary and thus will always conflict and require user
23 | # intervention with every merge. To do so, just uncomment the entries below
24 | ###############################################################################
25 | #*.sln merge=binary
26 | #*.csproj merge=binary
27 | #*.vbproj merge=binary
28 | #*.vcxproj merge=binary
29 | #*.vcproj merge=binary
30 | #*.dbproj merge=binary
31 | #*.fsproj merge=binary
32 | #*.lsproj merge=binary
33 | #*.wixproj merge=binary
34 | #*.modelproj merge=binary
35 | #*.sqlproj merge=binary
36 | #*.wwaproj merge=binary
37 |
38 | ###############################################################################
39 | # behavior for image files
40 | #
41 | # image files are treated as binary by default.
42 | ###############################################################################
43 | #*.jpg binary
44 | #*.png binary
45 | #*.gif binary
46 |
47 | ###############################################################################
48 | # diff behavior for common document formats
49 | #
50 | # Convert binary document formats to text before diffing them. This feature
51 | # is only available from the command line. Turn it on by uncommenting the
52 | # entries below.
53 | ###############################################################################
54 | #*.doc diff=astextplain
55 | #*.DOC diff=astextplain
56 | #*.docx diff=astextplain
57 | #*.DOCX diff=astextplain
58 | #*.dot diff=astextplain
59 | #*.DOT diff=astextplain
60 | #*.pdf diff=astextplain
61 | #*.PDF diff=astextplain
62 | #*.rtf diff=astextplain
63 | #*.RTF diff=astextplain
64 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | ## Ignore Visual Studio temporary files, build results, and
2 | ## files generated by popular Visual Studio add-ons.
3 |
4 | # User-specific files
5 | *.suo
6 | *.user
7 | *.sln.docstates
8 |
9 | # Build results
10 | [Dd]ebug/
11 | [Dd]ebugPublic/
12 | [Rr]elease/
13 | x64/
14 | build/
15 | bld/
16 | [Bb]in/
17 | [Oo]bj/
18 |
19 | # Roslyn cache directories
20 | *.ide/
21 |
22 | # MSTest test Results
23 | [Tt]est[Rr]esult*/
24 | [Bb]uild[Ll]og.*
25 |
26 | #NUNIT
27 | *.VisualState.xml
28 | TestResult.xml
29 |
30 | # Build Results of an ATL Project
31 | [Dd]ebugPS/
32 | [Rr]eleasePS/
33 | dlldata.c
34 |
35 | *_i.c
36 | *_p.c
37 | *_i.h
38 | *.ilk
39 | *.meta
40 | *.obj
41 | *.pch
42 | *.pdb
43 | *.pgc
44 | *.pgd
45 | *.rsp
46 | *.sbr
47 | *.tlb
48 | *.tli
49 | *.tlh
50 | *.tmp
51 | *.tmp_proj
52 | *.log
53 | *.vspscc
54 | *.vssscc
55 | .builds
56 | *.pidb
57 | *.svclog
58 | *.scc
59 |
60 | # Chutzpah Test files
61 | _Chutzpah*
62 |
63 | # Visual C++ cache files
64 | ipch/
65 | *.aps
66 | *.ncb
67 | *.opensdf
68 | *.sdf
69 | *.cachefile
70 |
71 | # Visual Studio profiler
72 | *.psess
73 | *.vsp
74 | *.vspx
75 |
76 | # TFS 2012 Local Workspace
77 | $tf/
78 |
79 | # Guidance Automation Toolkit
80 | *.gpState
81 |
82 | # ReSharper is a .NET coding add-in
83 | _ReSharper*/
84 | *.[Rr]e[Ss]harper
85 | *.DotSettings.user
86 |
87 | # JustCode is a .NET coding addin-in
88 | .JustCode
89 |
90 | # TeamCity is a build add-in
91 | _TeamCity*
92 |
93 | # DotCover is a Code Coverage Tool
94 | *.dotCover
95 |
96 | # NCrunch
97 | _NCrunch_*
98 | .*crunch*.local.xml
99 |
100 | # MightyMoose
101 | *.mm.*
102 | AutoTest.Net/
103 |
104 | # Web workbench (sass)
105 | .sass-cache/
106 |
107 | # Installshield output folder
108 | [Ee]xpress/
109 |
110 | # DocProject is a documentation generator add-in
111 | DocProject/buildhelp/
112 | DocProject/Help/*.HxT
113 | DocProject/Help/*.HxC
114 | DocProject/Help/*.hhc
115 | DocProject/Help/*.hhk
116 | DocProject/Help/*.hhp
117 | DocProject/Help/Html2
118 | DocProject/Help/html
119 |
120 | # Click-Once directory
121 | publish/
122 |
123 | # Publish Web Output
124 | *.[Pp]ublish.xml
125 | *.azurePubxml
126 | ## TODO: Comment the next line if you want to checkin your
127 | ## web deploy settings but do note that will include unencrypted
128 | ## passwords
129 | #*.pubxml
130 |
131 | # NuGet Packages Directory
132 | packages/*
133 | ## TODO: If the tool you use requires repositories.config
134 | ## uncomment the next line
135 | #!packages/repositories.config
136 |
137 | # Enable "build/" folder in the NuGet Packages folder since
138 | # NuGet packages use it for MSBuild targets.
139 | # This line needs to be after the ignore of the build folder
140 | # (and the packages folder if the line above has been uncommented)
141 | !packages/build/
142 |
143 | # Windows Azure Build Output
144 | csx/
145 | *.build.csdef
146 |
147 | # Windows Store app package directory
148 | AppPackages/
149 |
150 | # Others
151 | sql/
152 | *.Cache
153 | ClientBin/
154 | [Ss]tyle[Cc]op.*
155 | ~$*
156 | *~
157 | *.dbmdl
158 | *.dbproj.schemaview
159 | *.pfx
160 | *.publishsettings
161 | node_modules/
162 | bower_components/
163 |
164 | # RIA/Silverlight projects
165 | Generated_Code/
166 |
167 | # Backup & report files from converting an old project file
168 | # to a newer Visual Studio version. Backup files are not needed,
169 | # because we have git ;-)
170 | _UpgradeReport_Files/
171 | Backup*/
172 | UpgradeLog*.XML
173 | UpgradeLog*.htm
174 |
175 | # SQL Server files
176 | *.mdf
177 | *.ldf
178 |
179 | # Business Intelligence projects
180 | *.rdl.data
181 | *.bim.layout
182 | *.bim_*.settings
183 |
184 | # Microsoft Fakes
185 | FakesAssemblies/
186 |
187 | # LightSwitch generated files
188 | GeneratedArtifacts/
189 | _Pvt_Extensions/
190 | ModelManifest.xml
191 |
192 | # ASP.NET 5 generated files
193 | *.lock.json
--------------------------------------------------------------------------------
/HwpSharp.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio 14
4 | VisualStudioVersion = 14.0.23107.0
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{6DA16CB8-1D96-4C11-AC54-5210A16E8AD6}"
7 | EndProject
8 | Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "HwpSharp", "src\HwpSharp\HwpSharp.xproj", "{E8AB29C7-8222-4EC8-BFF2-06C1C119ABEA}"
9 | EndProject
10 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{99B07E9B-510B-4884-B486-042DC09B333E}"
11 | EndProject
12 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{4264F4F8-94A3-4C22-8579-8EB85B7EA473}"
13 | ProjectSection(SolutionItems) = preProject
14 | global.json = global.json
15 | EndProjectSection
16 | EndProject
17 | Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "HwpSharp.Tests", "test\HwpSharp.Tests\HwpSharp.Tests.xproj", "{07196994-8FEF-417A-9144-05135AA6497A}"
18 | EndProject
19 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "case", "case", "{C1C298A2-EFDC-406B-A9B3-FC671F8EDD76}"
20 | ProjectSection(SolutionItems) = preProject
21 | test\case\CompoundFile.xls = test\case\CompoundFile.xls
22 | test\case\Hwp3File.hwp = test\case\Hwp3File.hwp
23 | test\case\PdfFile.pdf = test\case\PdfFile.pdf
24 | EndProjectSection
25 | EndProject
26 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Hwp5", "Hwp5", "{8D356E47-AFA9-4915-B50A-A5AB3573ED0A}"
27 | ProjectSection(SolutionItems) = preProject
28 | test\case\Hwp5\BlogForm_BookReview.hwp = test\case\Hwp5\BlogForm_BookReview.hwp
29 | test\case\Hwp5\BlogForm_MovieReview.hwp = test\case\Hwp5\BlogForm_MovieReview.hwp
30 | test\case\Hwp5\BlogForm_Recipe.hwp = test\case\Hwp5\BlogForm_Recipe.hwp
31 | test\case\Hwp5\BookReview.hwp = test\case\Hwp5\BookReview.hwp
32 | test\case\Hwp5\calendar_monthly.hwp = test\case\Hwp5\calendar_monthly.hwp
33 | test\case\Hwp5\calendar_year.hwp = test\case\Hwp5\calendar_year.hwp
34 | test\case\Hwp5\classical_literature.hwp = test\case\Hwp5\classical_literature.hwp
35 | test\case\Hwp5\english.hwp = test\case\Hwp5\english.hwp
36 | test\case\Hwp5\Hyper(hwp2010).hwp = test\case\Hwp5\Hyper(hwp2010).hwp
37 | test\case\Hwp5\interview.hwp = test\case\Hwp5\interview.hwp
38 | test\case\Hwp5\KTX.hwp = test\case\Hwp5\KTX.hwp
39 | test\case\Hwp5\multisection.hwp = test\case\Hwp5\multisection.hwp
40 | test\case\Hwp5\NewYear_s_Day.hwp = test\case\Hwp5\NewYear_s_Day.hwp
41 | test\case\Hwp5\request.hwp = test\case\Hwp5\request.hwp
42 | test\case\Hwp5\shortcut.hwp = test\case\Hwp5\shortcut.hwp
43 | test\case\Hwp5\sungeo.hwp = test\case\Hwp5\sungeo.hwp
44 | test\case\Hwp5\Textmail.hwp = test\case\Hwp5\Textmail.hwp
45 | test\case\Hwp5\treatise sample.hwp = test\case\Hwp5\treatise sample.hwp
46 | test\case\Hwp5\Worldcup_FIFA2010_32.hwp = test\case\Hwp5\Worldcup_FIFA2010_32.hwp
47 | EndProjectSection
48 | EndProject
49 | Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "HwpSharp.Tests.Console", "test\HwpSharp.Tests.Console\HwpSharp.Tests.Console.xproj", "{D0E23E50-7881-4442-8E44-73300A7F6D9F}"
50 | EndProject
51 | Global
52 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
53 | Debug|Any CPU = Debug|Any CPU
54 | Release|Any CPU = Release|Any CPU
55 | EndGlobalSection
56 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
57 | {E8AB29C7-8222-4EC8-BFF2-06C1C119ABEA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
58 | {E8AB29C7-8222-4EC8-BFF2-06C1C119ABEA}.Debug|Any CPU.Build.0 = Debug|Any CPU
59 | {E8AB29C7-8222-4EC8-BFF2-06C1C119ABEA}.Release|Any CPU.ActiveCfg = Release|Any CPU
60 | {E8AB29C7-8222-4EC8-BFF2-06C1C119ABEA}.Release|Any CPU.Build.0 = Release|Any CPU
61 | {07196994-8FEF-417A-9144-05135AA6497A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
62 | {07196994-8FEF-417A-9144-05135AA6497A}.Debug|Any CPU.Build.0 = Debug|Any CPU
63 | {07196994-8FEF-417A-9144-05135AA6497A}.Release|Any CPU.ActiveCfg = Release|Any CPU
64 | {07196994-8FEF-417A-9144-05135AA6497A}.Release|Any CPU.Build.0 = Release|Any CPU
65 | {D0E23E50-7881-4442-8E44-73300A7F6D9F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
66 | {D0E23E50-7881-4442-8E44-73300A7F6D9F}.Debug|Any CPU.Build.0 = Debug|Any CPU
67 | {D0E23E50-7881-4442-8E44-73300A7F6D9F}.Release|Any CPU.ActiveCfg = Release|Any CPU
68 | {D0E23E50-7881-4442-8E44-73300A7F6D9F}.Release|Any CPU.Build.0 = Release|Any CPU
69 | EndGlobalSection
70 | GlobalSection(SolutionProperties) = preSolution
71 | HideSolutionNode = FALSE
72 | EndGlobalSection
73 | GlobalSection(NestedProjects) = preSolution
74 | {E8AB29C7-8222-4EC8-BFF2-06C1C119ABEA} = {6DA16CB8-1D96-4C11-AC54-5210A16E8AD6}
75 | {07196994-8FEF-417A-9144-05135AA6497A} = {99B07E9B-510B-4884-B486-042DC09B333E}
76 | {C1C298A2-EFDC-406B-A9B3-FC671F8EDD76} = {99B07E9B-510B-4884-B486-042DC09B333E}
77 | {8D356E47-AFA9-4915-B50A-A5AB3573ED0A} = {C1C298A2-EFDC-406B-A9B3-FC671F8EDD76}
78 | {D0E23E50-7881-4442-8E44-73300A7F6D9F} = {99B07E9B-510B-4884-B486-042DC09B333E}
79 | EndGlobalSection
80 | EndGlobal
81 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2015 Yoon SeungYong
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
23 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # hwpSharp
2 | C# Library for hwp document
3 |
--------------------------------------------------------------------------------
/global.json:
--------------------------------------------------------------------------------
1 | {
2 | "projects": [ "src", "test" ]
3 | }
--------------------------------------------------------------------------------
/src/HwpSharp/Common/Exceptions.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Threading.Tasks;
5 |
6 | namespace HwpSharp.Common
7 | {
8 | ///
9 | /// The exception that is thrown when a file or stream does not contains a HWP document, or HwpSharp cannot recognized a HWP document.
10 | ///
11 | public class HwpFileFormatException : Exception
12 | {
13 | ///
14 | /// Initializes a new instance of the class.
15 | ///
16 | public HwpFileFormatException()
17 | {
18 | }
19 |
20 | ///
21 | /// Initializes a new instance of the class with a specified error message.
22 | ///
23 | /// The message that describes the error.
24 | public HwpFileFormatException(string message)
25 | : base(message)
26 | {
27 | }
28 |
29 | ///
30 | /// Initializes a new instance of the class with a specified error message and a reference to the inner exception that is the cause of this exception.
31 | ///
32 | /// The message that describes the error.
33 | /// The exception that is the cause of the current exception.
34 | public HwpFileFormatException(string message, Exception innerException)
35 | : base(message, innerException)
36 | {
37 | }
38 | }
39 |
40 | ///
41 | /// The exception that is thrown when hwpSharp does not support this type of HWP document.
42 | ///
43 | public class HwpUnsupportedFormatException : Exception
44 | {
45 | ///
46 | /// Initializes a new instance of the class.
47 | ///
48 | public HwpUnsupportedFormatException()
49 | {
50 | }
51 |
52 | ///
53 | /// Initializes a new instance of the class with a specified error message.
54 | ///
55 | /// The message that describes the error.
56 | public HwpUnsupportedFormatException(string message)
57 | : base(message)
58 | {
59 | }
60 |
61 | ///
62 | /// Initializes a new instance of the class with a specified error message and a reference to the inner exception that is the cause of this exception.
63 | ///
64 | /// The message that describes the error.
65 | /// The exception that is the cause of the current exception.
66 | public HwpUnsupportedFormatException(string message, Exception innerException)
67 | : base(message, innerException)
68 | {
69 | }
70 | }
71 |
72 | ///
73 | /// The exception that is thrown when hwpSharp read a corrupted file.
74 | ///
75 | public class HwpCorruptedException : Exception
76 | {
77 | ///
78 | /// Initializes a new instance of the class.
79 | ///
80 | public HwpCorruptedException()
81 | {
82 | }
83 |
84 | ///
85 | /// Initializes a new instance of the class with a specified error message.
86 | ///
87 | /// The message that describes the error.
88 | public HwpCorruptedException(string message)
89 | : base(message)
90 | {
91 | }
92 |
93 | ///
94 | /// Initializes a new instance of the class with a specified error message and a reference to the inner exception that is the cause of this exception.
95 | ///
96 | /// The message that describes the error.
97 | /// The exception that is the cause of the current exception.
98 | public HwpCorruptedException(string message, Exception innerException)
99 | : base(message, innerException)
100 | {
101 | }
102 | }
103 |
104 | ///
105 | /// The exception that is thrown when hwpSharp read a corrupted data record from stream.
106 | ///
107 | public class HwpCorruptedDataRecordException : HwpCorruptedException
108 | {
109 | ///
110 | /// Initializes a new instance of the class.
111 | ///
112 | public HwpCorruptedDataRecordException()
113 | {
114 | }
115 |
116 | ///
117 | /// Initializes a new instance of the class with a specified error message.
118 | ///
119 | /// The message that describes the error.
120 | public HwpCorruptedDataRecordException(string message)
121 | : base(message)
122 | {
123 | }
124 |
125 | ///
126 | /// Initializes a new instance of the class with a specified error message and a reference to the inner exception that is the cause of this exception.
127 | ///
128 | /// The message that describes the error.
129 | /// The exception that is the cause of the current exception.
130 | public HwpCorruptedDataRecordException(string message, Exception innerException)
131 | : base(message, innerException)
132 | {
133 | }
134 | }
135 |
136 | ///
137 | /// The exception that is thrown when hwpSharp read a corrupted body text.
138 | ///
139 | public class HwpCorruptedBodyTextException : HwpCorruptedException
140 | {
141 | ///
142 | /// Initializes a new instance of the class.
143 | ///
144 | public HwpCorruptedBodyTextException()
145 | {
146 | }
147 |
148 | ///
149 | /// Initializes a new instance of the class with a specified error message.
150 | ///
151 | /// The message that describes the error.
152 | public HwpCorruptedBodyTextException(string message)
153 | : base(message)
154 | {
155 | }
156 |
157 | ///
158 | /// Initializes a new instance of the class with a specified error message and a reference to the inner exception that is the cause of this exception.
159 | ///
160 | /// The message that describes the error.
161 | /// The exception that is the cause of the current exception.
162 | public HwpCorruptedBodyTextException(string message, Exception innerException)
163 | : base(message, innerException)
164 | {
165 | }
166 | }
167 |
168 | public class HwpDataRecordConstructorException : Exception
169 | {
170 | }
171 |
172 | public class HwpUnsupportedProperty : Exception
173 | {
174 | }
175 | }
176 |
--------------------------------------------------------------------------------
/src/HwpSharp/Common/IBodyText.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Threading.Tasks;
5 |
6 | namespace HwpSharp.Common
7 | {
8 | ///
9 | /// Represents a body text.
10 | ///
11 | public interface IBodyText
12 | {
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/src/HwpSharp/Common/IDocumentInformation.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Threading.Tasks;
5 |
6 | namespace HwpSharp.Common
7 | {
8 | ///
9 | /// Represents a hwp document information.
10 | ///
11 | public interface IDocumentInformation
12 | {
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/src/HwpSharp/Common/IFileHeader.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Threading.Tasks;
5 |
6 | namespace HwpSharp.Common
7 | {
8 | ///
9 | /// Represents a file recognition header.
10 | ///
11 | public interface IFileHeader
12 | {
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/src/HwpSharp/Common/IHwpDocument.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Threading.Tasks;
5 |
6 | namespace HwpSharp.Common
7 | {
8 | ///
9 | /// Represents a Hwp document.
10 | ///
11 | public interface IHwpDocument
12 | {
13 | ///
14 | /// Represents the version of Hwp document.
15 | ///
16 | string HwpVersion { get; }
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/src/HwpSharp/Common/ISummaryInformation.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Threading.Tasks;
5 |
6 | namespace HwpSharp.Common
7 | {
8 | ///
9 | /// Represents a hwp summary information.
10 | ///
11 | public interface ISummaryInformation
12 | {
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/src/HwpSharp/Hwp5/BodyText/BodyText.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using HwpSharp.Common;
3 | using OpenMcdf;
4 |
5 | namespace HwpSharp.Hwp5.BodyText
6 | {
7 | ///
8 | /// Represents a hwp 5.0 body text.
9 | ///
10 | public class BodyText : IBodyText
11 | {
12 | public DocumentInformation.DocumentInformation DocumentInformation { get; private set; }
13 |
14 | public List Sections { get; }
15 |
16 | public BodyText(DocumentInformation.DocumentInformation docInfo)
17 | {
18 | DocumentInformation = docInfo;
19 | Sections = new List();
20 | }
21 |
22 | internal BodyText(CFStorage storage, DocumentInformation.DocumentInformation docInfo)
23 | {
24 | DocumentInformation = docInfo;
25 | Sections = new List();
26 |
27 | for (var i = 0; i < docInfo.DocumentProperty.SectionCount; ++i)
28 | {
29 | CFStream stream;
30 | try
31 | {
32 | stream = storage.GetStream($"Section{i}");
33 | }
34 | catch (CFItemNotFound exception)
35 | {
36 | throw new HwpCorruptedBodyTextException("The document does not have some sections. File may be corrupted.", exception);
37 | }
38 |
39 | var section = new Section(stream, docInfo);
40 |
41 | Sections.Add(section);
42 | }
43 | }
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/src/HwpSharp/Hwp5/BodyText/DataRecords/ParagraphHeader.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using HwpSharp.Hwp5.HwpType;
3 |
4 | namespace HwpSharp.Hwp5.BodyText.DataRecords
5 | {
6 | public class ParagraphHeader : DataRecord
7 | {
8 | public const uint ParagraphHeaderTagId = HwpTagBegin + 50;
9 |
10 | [Flags]
11 | public enum ColumnKind : byte
12 | {
13 | None = 0x00,
14 | Area = 0x01,
15 | MultiColumn = 0x02,
16 | Page = 0x04,
17 | Column = 0x08
18 | }
19 |
20 | public HwpType.UInt32 Length { get; set; }
21 | public HwpType.UInt32 ControlMask { get; set; }
22 | public HwpType.UInt16 ParagraphShapeId { get; set; }
23 | public UInt8 ParagraphStyleId { get; set; }
24 | public ColumnKind ColumnType { get; set; }
25 | public HwpType.UInt16 CharacterShapeCount { get; set; }
26 | public HwpType.UInt16 ParagraphRangeCount { get; set; }
27 | public HwpType.UInt16 LineAlignCount { get; set; }
28 | public HwpType.UInt32 ParagraphId { get; set; }
29 | public HwpType.UInt16 HistoryMergeParagraphFlag { get; set; }
30 |
31 | public ParagraphHeader(uint level, byte[] bytes,
32 | DocumentInformation.DocumentInformation docInfo = null)
33 | : base(ParagraphHeaderTagId, level, (uint) bytes.Length)
34 | {
35 | Length = bytes.ToUInt32();
36 | if ((Length & 0x80000000u) != 0)
37 | {
38 | Length &= 0x7fffffffu;
39 | }
40 |
41 | ControlMask = bytes.ToUInt32(4);
42 |
43 | ParagraphShapeId = bytes.ToUInt16(8);
44 |
45 | ParagraphStyleId = bytes[10];
46 |
47 | ColumnKind columnKind;
48 | if (!Enum.TryParse(bytes[11].ToString(), out columnKind))
49 | {
50 | columnKind = ColumnKind.None;
51 | }
52 | ColumnType = columnKind;
53 |
54 | CharacterShapeCount = bytes.ToUInt16(12);
55 |
56 | ParagraphRangeCount = bytes.ToUInt16(14);
57 |
58 | LineAlignCount = bytes.ToUInt16(16);
59 |
60 | ParagraphId = bytes.ToUInt32(18);
61 |
62 | if (bytes.Length >= 24)
63 | {
64 | HistoryMergeParagraphFlag = bytes.ToUInt16(22);
65 | }
66 | }
67 | }
68 | }
69 |
--------------------------------------------------------------------------------
/src/HwpSharp/Hwp5/BodyText/DataRecords/ParagraphText.cs:
--------------------------------------------------------------------------------
1 | using System.Text;
2 | using HwpSharp.Hwp5.HwpType;
3 |
4 | namespace HwpSharp.Hwp5.BodyText.DataRecords
5 | {
6 | public class ParagraphText : DataRecord
7 | {
8 | public const uint ParagraphTextTagId = HwpTagBegin + 51;
9 | public string Text { get; set; }
10 |
11 | public ParagraphText(uint level, byte[] bytes, DocumentInformation.DocumentInformation _ = null)
12 | : base(ParagraphTextTagId, level, (uint) bytes.Length)
13 | {
14 | Text = Encoding.Unicode.GetString(bytes);
15 | }
16 | }
17 | }
--------------------------------------------------------------------------------
/src/HwpSharp/Hwp5/BodyText/Section.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Threading.Tasks;
5 | using HwpSharp.Hwp5.BodyText.DataRecords;
6 | using HwpSharp.Hwp5.HwpType;
7 | using OpenMcdf;
8 |
9 | namespace HwpSharp.Hwp5.BodyText
10 | {
11 | public class Section
12 | {
13 | public DocumentInformation.DocumentInformation DocumentInformation { get; private set; }
14 |
15 | public List DataRecords { get; }
16 |
17 | public Section(DocumentInformation.DocumentInformation docInfo)
18 | {
19 | DocumentInformation = docInfo;
20 | DataRecords = new List();
21 | }
22 |
23 | internal Section(CFStream stream, DocumentInformation.DocumentInformation docInfo)
24 | {
25 | DocumentInformation = docInfo;
26 |
27 | var bytes = Document.GetRawBytesFromStream(stream, docInfo.FileHeader);
28 | DataRecords = new List(DataRecord.GetRecordsFromBytes(bytes, docInfo));
29 | }
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/src/HwpSharp/Hwp5/Document.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.IO;
3 | using System.IO.Compression;
4 | using HwpSharp.Common;
5 | using HwpSharp.Hwp5.BodyText;
6 | using OpenMcdf;
7 |
8 | namespace HwpSharp.Hwp5
9 | {
10 | ///
11 | /// Represents a hwp 5.0 document.
12 | ///
13 | public class Document : IHwpDocument
14 | {
15 | ///
16 | /// This document is a HWP 5.0 document.
17 | ///
18 | public string HwpVersion => "5.0";
19 |
20 | ///
21 | /// Gets a file recognition header of this document.
22 | ///
23 | public FileHeader FileHeader { get; private set; }
24 |
25 | ///
26 | /// Gets a document information of this document.
27 | ///
28 | public DocumentInformation.DocumentInformation DocumentInformation { get; private set; }
29 |
30 | ///
31 | /// Gets a body text of this document.
32 | ///
33 | public BodyText.BodyText BodyText { get; private set; }
34 |
35 | ///
36 | /// Gets a summary information of this document.
37 | ///
38 | public SummaryInformation SummaryInformation
39 | {
40 | get { throw new NotImplementedException(); }
41 | private set { throw new NotImplementedException(); }
42 | }
43 |
44 | internal Document(CompoundFile compoundFile)
45 | {
46 | Load(compoundFile);
47 | }
48 |
49 | private void Load(CompoundFile compoundFile)
50 | {
51 | FileHeader = LoadFileHeader(compoundFile);
52 | DocumentInformation = LoadDocumentInformation(compoundFile);
53 | BodyText = LoadBodyText(compoundFile);
54 | }
55 |
56 | private BodyText.BodyText LoadBodyText(CompoundFile compoundFile)
57 | {
58 | CFStorage storage;
59 | try
60 | {
61 | storage = compoundFile.RootStorage.GetStorage("BodyText");
62 | }
63 | catch (CFItemNotFound exception)
64 | {
65 | throw new HwpFileFormatException("Specified document does not have any BodyText fields.", exception);
66 | }
67 |
68 | var bodyText = new BodyText.BodyText(storage, DocumentInformation);
69 |
70 | return bodyText;
71 | }
72 |
73 | private DocumentInformation.DocumentInformation LoadDocumentInformation(CompoundFile compoundFile)
74 | {
75 | CFStream stream;
76 | try
77 | {
78 | stream = compoundFile.RootStorage.GetStream("DocInfo");
79 | }
80 | catch (CFItemNotFound exception)
81 | {
82 | throw new HwpFileFormatException("Specified document does not have a DocInfo field.", exception);
83 | }
84 |
85 | var docInfo = new DocumentInformation.DocumentInformation(stream, FileHeader);
86 |
87 | return docInfo;
88 | }
89 |
90 | private static FileHeader LoadFileHeader(CompoundFile compoundFile)
91 | {
92 | CFStream stream;
93 | try
94 | {
95 | stream = compoundFile.RootStorage.GetStream("FileHeader");
96 | }
97 | catch (CFItemNotFound exception)
98 | {
99 | throw new HwpFileFormatException("Specified document does not have a FileHeader field.", exception);
100 | }
101 |
102 | var fileHeader = new FileHeader(stream);
103 |
104 | return fileHeader;
105 | }
106 |
107 | ///
108 | /// Creates a instance from a .
109 | ///
110 | /// A stream which contains a hwp 5 document.
111 | public Document(Stream stream)
112 | {
113 | if (stream == null)
114 | {
115 | throw new ArgumentNullException(nameof(stream));
116 | }
117 |
118 | try
119 | {
120 | using (var compoundFile = new CompoundFile(stream, CFSUpdateMode.Update, CFSConfiguration.EraseFreeSectors | CFSConfiguration.SectorRecycle))
121 | {
122 | Load(compoundFile);
123 | }
124 | }
125 | catch(CFFileFormatException exception)
126 | {
127 | throw new HwpFileFormatException("Specified document is not a hwp 5 document format.", exception);
128 | }
129 | }
130 |
131 | ///
132 | /// Creates a instance from a file.
133 | ///
134 | /// A file name of a hwp 5 document.
135 | public Document(string filename)
136 | {
137 | if (string.IsNullOrWhiteSpace(filename))
138 | {
139 | throw new ArgumentNullException(nameof(filename));
140 | }
141 |
142 | try
143 | {
144 | using (var compoundFile = new CompoundFile(filename, CFSUpdateMode.Update, CFSConfiguration.EraseFreeSectors | CFSConfiguration.SectorRecycle))
145 | {
146 | Load(compoundFile);
147 | }
148 | }
149 | catch (CFFileFormatException exception)
150 | {
151 | throw new HwpFileFormatException("Specified document is not a hwp 5 document format.", exception);
152 | }
153 | }
154 |
155 | internal static byte[] GetRawBytesFromStream(CFStream stream, FileHeader fileHeader)
156 | {
157 | var streamBytes = stream.GetData();
158 |
159 | if (fileHeader.PasswordEncrypted)
160 | {
161 | throw new HwpUnsupportedFormatException("Does not support a password encrypted document.");
162 | }
163 |
164 | if (fileHeader.Compressed)
165 | {
166 | using (var dataStream = new MemoryStream(streamBytes, false))
167 | {
168 | using (var zipStream = new DeflateStream(dataStream, CompressionMode.Decompress))
169 | {
170 | using (var decStream = new MemoryStream())
171 | {
172 | zipStream.CopyTo(decStream);
173 |
174 | streamBytes = decStream.ToArray();
175 | }
176 | }
177 | }
178 | }
179 |
180 | return streamBytes;
181 | }
182 | }
183 | }
184 |
--------------------------------------------------------------------------------
/src/HwpSharp/Hwp5/DocumentInformation/DataRecords/BinData.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Diagnostics;
3 | using System.Text;
4 | using HwpSharp.Common;
5 | using HwpSharp.Hwp5.HwpType;
6 | using UInt16 = HwpSharp.Hwp5.HwpType.UInt16;
7 |
8 | namespace HwpSharp.Hwp5.DocumentInformation.DataRecords
9 | {
10 | public class BinData : DataRecord
11 | {
12 | public const uint BinDataTagId = HwpTagBegin + 2;
13 |
14 | public enum TypeProperty : byte
15 | {
16 | Link = 0,
17 | Enbedding = 1,
18 | Storage = 2,
19 | }
20 |
21 | public enum CompressionProperty : byte
22 | {
23 | StorageDefault = 0,
24 | Compress = 1,
25 | NotCompress = 2,
26 | }
27 |
28 | public enum StateProperty : byte
29 | {
30 | Never = 0,
31 | Success = 1,
32 | Failed = 2,
33 | Ignored = 3,
34 | }
35 |
36 | [DebuggerDisplay("Type={Type}, Compression={Compression}, State={State}")]
37 | public struct BinDataProperty
38 | {
39 | public TypeProperty Type { get; }
40 |
41 | public CompressionProperty Compression { get; }
42 |
43 | public StateProperty State { get; }
44 |
45 | public BinDataProperty(UInt16 value)
46 | {
47 | TypeProperty type;
48 | Type = Enum.TryParse($"{value & 0x7}", out type) ? type : TypeProperty.Link;
49 |
50 | CompressionProperty compression;
51 | Compression = Enum.TryParse($"{(value >> 4) & 0x3}", out compression)
52 | ? compression
53 | : CompressionProperty.StorageDefault;
54 |
55 | StateProperty state;
56 | State = Enum.TryParse($"{(value >> 8) & 0x3}", out state) ? state : StateProperty.Never;
57 | }
58 |
59 | public BinDataProperty(TypeProperty type, CompressionProperty compression, StateProperty state)
60 | {
61 | Type = type;
62 | Compression = compression;
63 | State = state;
64 | }
65 |
66 | public static implicit operator UInt16(BinDataProperty binData)
67 | {
68 | return
69 | (UInt16)
70 | (((ushort) binData.State << 8) + ((ushort) binData.Compression << 4) + (ushort) binData.Type);
71 | }
72 | }
73 |
74 | public BinDataProperty Property { get; }
75 |
76 | private readonly string _linkFileAbsolutePath;
77 | public string LinkFileAbsolutePath
78 | {
79 | get
80 | {
81 | if (Property.Type != TypeProperty.Link)
82 | {
83 | throw new HwpUnsupportedProperty();
84 | }
85 | return _linkFileAbsolutePath;
86 | }
87 | }
88 |
89 | private readonly string _linkFileRelativePath;
90 | public string LinkFileRelativePath
91 | {
92 | get
93 | {
94 | if (Property.Type != TypeProperty.Link)
95 | {
96 | throw new HwpUnsupportedProperty();
97 | }
98 | return _linkFileRelativePath;
99 | }
100 | }
101 |
102 | private readonly UInt16 _binaryDataId;
103 | public UInt16 BinaryDataId
104 | {
105 | get
106 | {
107 | if (Property.Type != TypeProperty.Enbedding && Property.Type != TypeProperty.Storage)
108 | {
109 | throw new HwpUnsupportedProperty();
110 | }
111 | return _binaryDataId;
112 | }
113 | }
114 |
115 | private readonly string _binaryDataExtension;
116 | public string BinaryDataExtension
117 | {
118 | get
119 | {
120 | if (Property.Type != TypeProperty.Enbedding)
121 | {
122 | throw new HwpUnsupportedProperty();
123 | }
124 | return _binaryDataExtension;
125 | }
126 | }
127 |
128 | public BinData(uint level, byte[] bytes, DocumentInformation _ = null)
129 | : base(BinDataTagId, level, (uint) bytes.Length)
130 | {
131 | var pos = 0;
132 | Property = new BinDataProperty(bytes.ToUInt16());
133 | pos += 2;
134 |
135 | if (Property.Type == TypeProperty.Link)
136 | {
137 | var absolutePathLenth = bytes.ToWord(pos);
138 | pos += 2;
139 |
140 | _linkFileAbsolutePath = Encoding.Unicode.GetString(bytes, pos, 2*absolutePathLenth);
141 | pos += 2*absolutePathLenth;
142 |
143 | var relativePathLength = bytes.ToWord(pos);
144 | pos += 2;
145 |
146 | _linkFileRelativePath = Encoding.Unicode.GetString(bytes, pos, 2*relativePathLength);
147 | pos += 2*relativePathLength;
148 | }
149 |
150 | if (Property.Type == TypeProperty.Enbedding || Property.Type == TypeProperty.Storage)
151 | {
152 | _binaryDataId = bytes.ToUInt16(pos);
153 | pos += 2;
154 | }
155 |
156 | if (Property.Type == TypeProperty.Enbedding)
157 | {
158 | var extensionLength = bytes.ToWord(pos);
159 | pos += 2;
160 |
161 | _binaryDataExtension = Encoding.Unicode.GetString(bytes, pos, 2*extensionLength);
162 | pos += 2*extensionLength;
163 | }
164 | }
165 | }
166 | }
167 |
--------------------------------------------------------------------------------
/src/HwpSharp/Hwp5/DocumentInformation/DataRecords/BorderFill.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Diagnostics;
4 | using System.Diagnostics.CodeAnalysis;
5 | using System.Linq;
6 | using System.Threading.Tasks;
7 | using HwpSharp.Common;
8 | using HwpSharp.Hwp5.HwpType;
9 | using Byte = HwpSharp.Hwp5.HwpType.Byte;
10 | using Int16 = HwpSharp.Hwp5.HwpType.Int16;
11 | using Int32 = HwpSharp.Hwp5.HwpType.Int32;
12 | using UInt16 = HwpSharp.Hwp5.HwpType.UInt16;
13 |
14 | namespace HwpSharp.Hwp5.DocumentInformation.DataRecords
15 | {
16 | public class BorderFill : DataRecord
17 | {
18 | public const uint BorderFillTagId = HwpTagBegin + 4;
19 |
20 | [DebuggerDisplay("Type = {Type}")]
21 | public struct BorderProperty
22 | {
23 | public enum DiagonalType
24 | {
25 | None,
26 | Slash,
27 | BackSlash,
28 | Cross,
29 | Center,
30 | }
31 |
32 | public enum SlashDiagonal : ushort
33 | {
34 | None = 0,
35 | Slash = (1 << 3),
36 | SlashTop = SlashBottom + (1 << 10),
37 | SlashRight = SlashLeft + (1 << 10),
38 | SlashBottom = (1 << 2) + Slash,
39 | SlashLeft = Slash + (1 << 4),
40 | SlashCrooked = Slash + (1 << 8),
41 | }
42 |
43 | public enum BackSlashDiagonal : ushort
44 | {
45 | None = 0,
46 | BackSlash = (1 << 6),
47 | BackSlashTop = BackSlashBottom + (1 << 12),
48 | BackSlashLeft = BackSlashRight + (1 << 12),
49 | BackSlashBottom = (1 << 5) + BackSlash,
50 | BackSlashRight = BackSlash + (1 << 7),
51 | BackSlashCrooked = BackSlash + (1 << 10),
52 | }
53 |
54 | public enum CenterLine : ushort
55 | {
56 | None = 0,
57 | HorizontalCenter = (1 << 8) + (1 << 13),
58 | VerticalCenter = (1 << 9) + (1 << 13),
59 | CrossCenter = (1 << 8) + (1 << 9) + (1 << 13),
60 | }
61 |
62 | public bool CubeEffect { get; }
63 |
64 | public bool ShadeEffect { get; }
65 |
66 | public DiagonalType Type { get; }
67 |
68 | public SlashDiagonal SlashDiagonalType { get; }
69 |
70 | public BackSlashDiagonal BackSlashDiagonalType { get; }
71 |
72 | public CenterLine CenterLineType { get; }
73 |
74 | internal BorderProperty(UInt16 property)
75 | {
76 | CubeEffect = (property & 1) != 0;
77 |
78 | ShadeEffect = (property & 2) != 0;
79 |
80 | SlashDiagonal slash;
81 | SlashDiagonalType = Enum.TryParse($"{property & 0x091C}", out slash) ? slash : SlashDiagonal.None;
82 |
83 | BackSlashDiagonal backSlash;
84 | BackSlashDiagonalType = Enum.TryParse($"{property & 0x14E0}", out backSlash)
85 | ? backSlash
86 | : BackSlashDiagonal.None;
87 |
88 | CenterLine center;
89 | CenterLineType = Enum.TryParse($"{property & 0x2300}", out center) ? center : CenterLine.None;
90 |
91 | if (center != CenterLine.None)
92 | {
93 | Type = DiagonalType.Center;
94 | }
95 | else if (slash != SlashDiagonal.None && backSlash != BackSlashDiagonal.None)
96 | {
97 | Type = DiagonalType.Cross;
98 | }
99 | else if (slash != SlashDiagonal.None)
100 | {
101 | Type = DiagonalType.Slash;
102 | }
103 | else if (backSlash != BackSlashDiagonal.None)
104 | {
105 | Type = DiagonalType.BackSlash;
106 | }
107 | else
108 | {
109 | Type = DiagonalType.None;
110 | }
111 | }
112 |
113 | public BorderProperty(bool cubeEffect = false, bool shadeEffect = false,
114 | DiagonalType type = DiagonalType.None, SlashDiagonal slash = SlashDiagonal.None,
115 | BackSlashDiagonal backSlash = BackSlashDiagonal.None, CenterLine center = CenterLine.None)
116 | {
117 | CubeEffect = cubeEffect;
118 | ShadeEffect = shadeEffect;
119 | Type = type;
120 | SlashDiagonalType = slash;
121 | BackSlashDiagonalType = backSlash;
122 | CenterLineType = center;
123 | }
124 | }
125 |
126 | [SuppressMessage("ReSharper", "InconsistentNaming")]
127 | public enum Weight : byte
128 | {
129 | Mm0_1 = 0,
130 | Mm0_12 = 1,
131 | Mm0_15 = 2,
132 | Mm0_2 = 3,
133 | Mm0_25 = 4,
134 | Mm0_3 = 5,
135 | Mm0_4 = 6,
136 | Mm0_5 = 7,
137 | Mm0_6 = 8,
138 | Mm0_7 = 9,
139 | Mm1_0 = 10,
140 | Mm1_5 = 11,
141 | Mm2_0 = 12,
142 | Mm3_0 = 13,
143 | Mm4_0 = 14,
144 | Mm5_0 = 15,
145 | }
146 |
147 | [DebuggerDisplay("Type = {Type}, Weight = {Weight}, Color = {Color}")]
148 | public struct Border
149 | {
150 | public enum LineType : byte
151 | {
152 | None = 0,
153 | Solid = 1,
154 | Dash = 2,
155 | Dot = 3,
156 | DashDot = 4,
157 | DashDotDot = 5,
158 | LongDash = 6,
159 | Circle = 7,
160 | DoubleLine = 8,
161 | ThinThick = 9,
162 | ThickThin = 10,
163 | ThinThickThin = 11,
164 | Wave = 12,
165 | DoubleWave = 13,
166 | Thick3D = 14,
167 | Thick3DInverse = 15,
168 | Solid3D = 16,
169 | Solid3DInverse = 17,
170 | }
171 |
172 | public LineType Type { get; }
173 |
174 | public Weight Weight { get; }
175 |
176 | public Color Color { get; }
177 |
178 | internal Border(UInt8 type, UInt8 weight, Color color)
179 | {
180 | LineType lineType;
181 | Type = Enum.TryParse($"{type}", out lineType) ? lineType : LineType.Solid;
182 |
183 | Weight weightValue;
184 | Weight = Enum.TryParse($"{weight}", out weightValue) ? weightValue : Weight.Mm0_1;
185 |
186 | Color = color;
187 | }
188 |
189 | public Border(LineType type = LineType.Solid, Weight weight = Weight.Mm0_1, Color color = default(Color))
190 | {
191 | Type = type;
192 | Weight = weight;
193 | Color = color;
194 | }
195 | }
196 |
197 | [DebuggerDisplay("Type = {Type}, Weight = {Weight}, Color = {Color}")]
198 | public struct Diagonal
199 | {
200 | public enum DiagonalType : byte
201 | {
202 | Slash = 0,
203 | BackSlash = 1,
204 | CrookedSlash = 2,
205 | }
206 |
207 | public DiagonalType Type { get; }
208 |
209 | public Weight Weight { get; }
210 |
211 | public Color Color { get; }
212 |
213 | internal Diagonal(UInt8 type, UInt8 weight, Color color)
214 | {
215 | DiagonalType diagonal;
216 | Type = Enum.TryParse($"{type}", out diagonal) ? diagonal : DiagonalType.Slash;
217 |
218 | Weight weightValue;
219 | Weight = Enum.TryParse($"{weight}", out weightValue) ? weightValue : Weight.Mm0_1;
220 |
221 | Color = color;
222 | }
223 |
224 | public Diagonal(DiagonalType type = DiagonalType.Slash, Weight weight = Weight.Mm0_1, Color color = default(Color))
225 | {
226 | Type = type;
227 | Weight = weight;
228 | Color = color;
229 | }
230 | }
231 |
232 | public struct Fill
233 | {
234 | [Flags]
235 | public enum FillType
236 | {
237 | None = 0,
238 | Solid = 1,
239 | Image = 2,
240 | Gradation = 4,
241 | }
242 |
243 | [DebuggerDisplay("Background = {Background}, Foreground = {Foreground}, Pattern = {Pattern}")]
244 | public struct SolidFill
245 | {
246 | public enum PatternType
247 | {
248 | None = 0,
249 | Horizontal = 1,
250 | Vertical = 2,
251 | BackSlash = 3,
252 | Slash = 4,
253 | Plus = 5,
254 | Cross = 6,
255 | }
256 |
257 | public Color Background { get; }
258 |
259 | public Color Foreground { get; }
260 |
261 | public PatternType Pattern { get; }
262 |
263 | internal SolidFill(Color background, Color foreground, Int32 pattern)
264 | {
265 | Background = background;
266 |
267 | Foreground = foreground;
268 |
269 | PatternType type;
270 | Pattern = Enum.TryParse($"{pattern}", out type) ? type : PatternType.None;
271 | }
272 |
273 | public SolidFill(Color background = default(Color), Color foreground = default(Color),
274 | PatternType pattern = PatternType.None)
275 | {
276 | Background = background;
277 | Foreground = foreground;
278 | Pattern = pattern;
279 | }
280 | }
281 |
282 | public struct GradationFill
283 | {
284 | public enum GradationType
285 | {
286 | None = 0,
287 | Stripe = 1,
288 | Circular = 2,
289 | Cone = 3,
290 | Square = 4,
291 | }
292 |
293 | public struct GradationColor
294 | {
295 | public Int32? Position { get; }
296 |
297 | public Color Color { get; }
298 |
299 | public GradationColor(Int32? position, Color color)
300 | {
301 | Position = position;
302 | Color = color;
303 | }
304 | }
305 |
306 | public GradationType Type { get; }
307 |
308 | public Int16 Degree { get; }
309 |
310 | public Int16 CenterX { get; }
311 |
312 | public Int16 CenterY { get; }
313 |
314 | public Int16 Blur { get; }
315 |
316 | public IList Colors { get; }
317 |
318 | internal GradationFill(byte[] bytes, int pos = 0)
319 | {
320 | GradationType type;
321 | Type = Enum.TryParse($"{bytes.ToInt16(pos)}", out type) ? type : GradationType.None;
322 | pos += 2;
323 |
324 | Degree = bytes.ToInt16(pos);
325 | pos += 2;
326 |
327 | CenterX = bytes.ToInt16(pos);
328 | pos += 2;
329 |
330 | CenterY = bytes.ToInt16(pos);
331 | pos += 2;
332 |
333 | Blur = bytes.ToInt16(pos);
334 | pos += 2;
335 |
336 | var num = bytes.ToInt16(pos);
337 | pos += 2;
338 | Colors = new List();
339 |
340 | List positions = null;
341 | if (num > 2)
342 | {
343 | positions = new List();
344 | for (var i = 0; i < num; i++)
345 | {
346 | positions.Add(bytes.ToInt32(pos));
347 | pos += 4;
348 | }
349 | }
350 |
351 | for (var i = 0; i < num; i++)
352 | {
353 | Colors.Add(new GradationColor(positions?[i], bytes.ToColor(pos)));
354 | pos += 4;
355 | }
356 | }
357 |
358 | public GradationFill(GradationType type = GradationType.None, Int16 degree = default(Int16),
359 | Int16 centerX = default(Int16), Int16 centerY = default(Int16), Int16 blur = default(Int16),
360 | IEnumerable colors = null)
361 | {
362 | Type = type;
363 | Degree = degree;
364 | CenterX = centerX;
365 | CenterY = centerY;
366 | Blur = blur;
367 | Colors = colors?.ToList() ?? new List();
368 | }
369 | }
370 |
371 | public struct ImageFill
372 | {
373 | public enum ImageFillType : byte
374 | {
375 | Tile = 0,
376 | TileTop = 1,
377 | TileBottom = 2,
378 | TileLeft = 3,
379 | TileRight = 4,
380 | Fit = 5,
381 | CenterCenter = 6,
382 | CenterTop = 7,
383 | CenterBottom = 8,
384 | LeftCenter = 9,
385 | LeftTop = 10,
386 | LeftBottom = 11,
387 | RightCenter = 12,
388 | RightTop = 13,
389 | RightBottom = 14,
390 | None = 15,
391 | }
392 |
393 | public struct Image
394 | {
395 | [Flags]
396 | public enum ImageEffect
397 | {
398 | None = 0,
399 | Grayscale = 1,
400 | BlackWhite = 2,
401 | Pattern = 4,
402 | }
403 |
404 | public Int8 Brightness { get; }
405 |
406 | public Int8 Contrast { get; }
407 |
408 | public ImageEffect Effect { get; }
409 |
410 | public UInt16 BinItemId { get; }
411 |
412 | internal Image(Int8 brightness, Int8 contrast, Byte effect, UInt16 binItemId)
413 | {
414 | Brightness = brightness;
415 | Contrast = contrast;
416 |
417 | ImageEffect imageEffect;
418 | Effect = Enum.TryParse($"{effect}", out imageEffect) ? imageEffect : ImageEffect.None;
419 |
420 | BinItemId = binItemId;
421 | }
422 |
423 | public Image(Int8 brightness, Int8 contrast, ImageEffect effect, UInt16 binItemId)
424 | {
425 | Brightness = brightness;
426 | Contrast = contrast;
427 | Effect = effect;
428 | BinItemId = binItemId;
429 | }
430 | }
431 |
432 | public ImageFillType Type { get; }
433 |
434 | public Image ImageData { get; }
435 |
436 | public DWord AdditionalGradationSize { get; }
437 |
438 | public Byte GradationCenter { get; }
439 |
440 | public ImageFill(ImageFillType type, Image image, DWord gradationSize, Byte gradationCenter)
441 | {
442 | Type = type;
443 | ImageData = image;
444 | AdditionalGradationSize = gradationSize;
445 | GradationCenter = gradationCenter;
446 | }
447 | }
448 |
449 | public FillType Type { get; }
450 |
451 | private readonly SolidFill _solid;
452 | public SolidFill Solid
453 | {
454 | get
455 | {
456 | if (!Type.HasFlag(FillType.Solid))
457 | {
458 | throw new HwpUnsupportedProperty();
459 | }
460 | return _solid;
461 | }
462 | }
463 |
464 | private readonly GradationFill _gradation;
465 | public GradationFill Gradation
466 | {
467 | get
468 | {
469 | if (!Type.HasFlag(FillType.Gradation))
470 | {
471 | throw new HwpUnsupportedProperty();
472 | }
473 | return _gradation;
474 | }
475 | }
476 |
477 | private readonly ImageFill _image;
478 | public ImageFill Image
479 | {
480 | get
481 | {
482 | if (!Type.HasFlag(FillType.Image))
483 | {
484 | throw new HwpUnsupportedProperty();
485 | }
486 | return _image;
487 | }
488 | }
489 |
490 | public byte[] AdditionalFill { get; }
491 | }
492 |
493 |
494 | public BorderProperty Property { get; }
495 |
496 | public Border Left { get; }
497 |
498 | public Border Right { get; }
499 |
500 | public Border Top { get; }
501 |
502 | public Border Bottom { get; }
503 |
504 | public Diagonal DiagonalProperty { get; }
505 |
506 | public BorderFill(uint level, byte[] bytes, DocumentInformation _ = null)
507 | : base(BorderFillTagId, level, (uint) bytes.Length)
508 | {
509 | var pos = 0;
510 |
511 | Property = new BorderProperty(bytes.ToUInt16());
512 | pos += 2;
513 |
514 | Left = new Border(bytes[pos], bytes[pos + 1], bytes.ToColor(pos + 2));
515 | pos += 6;
516 |
517 | Right = new Border(bytes[pos], bytes[pos + 1], bytes.ToColor(pos + 2));
518 | pos += 6;
519 |
520 | Top = new Border(bytes[pos], bytes[pos + 1], bytes.ToColor(pos + 2));
521 | pos += 6;
522 |
523 | Bottom = new Border(bytes[pos], bytes[pos + 1], bytes.ToColor(pos + 2));
524 | pos += 6;
525 |
526 | DiagonalProperty = new Diagonal(bytes[pos], bytes[pos + 1], bytes[pos + 2]);
527 | pos += 6;
528 | }
529 | }
530 | }
531 |
--------------------------------------------------------------------------------
/src/HwpSharp/Hwp5/DocumentInformation/DataRecords/DocumentProperty.cs:
--------------------------------------------------------------------------------
1 | using HwpSharp.Hwp5.HwpType;
2 |
3 | namespace HwpSharp.Hwp5.DocumentInformation.DataRecords
4 | {
5 | public class DocumentProperty : DataRecord
6 | {
7 | public const uint DocumentPropertiesTagId = HwpTagBegin;
8 |
9 | public UInt16 SectionCount { get; set; }
10 | public UInt16 StartPageNumber { get; set; }
11 | public UInt16 StartFootNoteNumber { get; set; }
12 | public UInt16 StartEndNoteNumber { get; set; }
13 | public UInt16 StartPictureNumber { get; set; }
14 | public UInt16 StartTableNumber { get; set; }
15 | public UInt16 StartEquationNumber { get; set; }
16 | public UInt32 ListId { get; set; }
17 | public UInt32 ParagraphId { get; set; }
18 | public UInt32 CharacterUnitPosition { get; set; }
19 |
20 | public DocumentProperty(uint level, byte[] bytes, DocumentInformation _ = null)
21 | : base(DocumentPropertiesTagId, level, (uint) bytes.Length)
22 | {
23 | SectionCount = bytes.ToUInt16();
24 | StartPageNumber = bytes.ToUInt16(2);
25 | StartFootNoteNumber = bytes.ToUInt16(4);
26 | StartEndNoteNumber = bytes.ToUInt16(6);
27 | StartPictureNumber = bytes.ToUInt16(8);
28 | StartTableNumber = bytes.ToUInt16(10);
29 | StartEquationNumber = bytes.ToUInt16(12);
30 | ListId = bytes.ToUInt32(14);
31 | ParagraphId = bytes.ToUInt32(18);
32 | CharacterUnitPosition = bytes.ToUInt32(22);
33 | }
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/src/HwpSharp/Hwp5/DocumentInformation/DataRecords/FaceName.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Diagnostics;
3 | using System.Text;
4 | using HwpSharp.Common;
5 | using HwpSharp.Hwp5.HwpType;
6 | using Byte = HwpSharp.Hwp5.HwpType.Byte;
7 |
8 | namespace HwpSharp.Hwp5.DocumentInformation.DataRecords
9 | {
10 | public class FaceName : DataRecord
11 | {
12 | // 파일 형식 문서에 내용이 빠진 부분은 다음을 참조함
13 | // https://github.com/mete0r/pyhwp/tree/develop/pyhwp/hwp5/binmodel/tagid19_face_name.py
14 |
15 | public const uint FaceNameTagId = HwpTagBegin + 3;
16 |
17 | [Flags]
18 | public enum FontProperty : byte
19 | {
20 | Unknown = 0x0,
21 | Ttf = 0x1,
22 | Hft = 0x2,
23 | DefaultFont = 0x20,
24 | FaceStyle = 0x40,
25 | AlternativeFont = 0x80,
26 | }
27 |
28 | public enum AlternativeFont : byte
29 | {
30 | Unknown = 0,
31 | Ttf = 1,
32 | Hft = 2,
33 | }
34 |
35 | public struct FaceStyle
36 | {
37 | public enum FamilyType : byte
38 | {
39 | Any = 0,
40 | None = 1,
41 | TextDisplay = 2,
42 | Script = 3,
43 | Decorative = 4,
44 | Pictorial = 5,
45 | }
46 |
47 | public enum SerifStyle : byte
48 | {
49 | Any = 0,
50 | None = 1,
51 | Cove = 2,
52 | ObtuseCove = 3,
53 | SquareCove = 4,
54 | ObtuseSquareCove = 5,
55 | Square = 6,
56 | Thin = 7,
57 | Bone = 8,
58 | Exaggerated = 9,
59 | Triangle = 10,
60 | NormalSans = 11,
61 | ObtuseSans = 12,
62 | PerpSans = 13,
63 | Flared = 14,
64 | Rounded = 15,
65 | }
66 |
67 | public enum Weight : byte
68 | {
69 | Any = 0,
70 | None = 1,
71 | VeryLight = 2,
72 | Light = 3,
73 | Thin = 4,
74 | Book = 5,
75 | Medium = 6,
76 | Demi = 7,
77 | Bold = 8,
78 | Heavy = 9,
79 | Black = 10,
80 | Nord = 11,
81 | }
82 |
83 | public enum Proportion : byte
84 | {
85 | Any = 0,
86 | None = 1,
87 | OldStyle = 2,
88 | Modern = 3,
89 | EvenWidth = 4,
90 | Expanded = 5,
91 | Condensed = 6,
92 | VeryExpanded = 7,
93 | VeryCondensed = 8,
94 | Monospaced = 9,
95 | }
96 |
97 | public enum Contrast : byte
98 | {
99 | Any = 0,
100 | None = 1,
101 | NoContrast = 2,
102 | VeryLow = 3,
103 | Low = 4,
104 | MediumLow = 5,
105 | Medium = 6,
106 | MediumHigh = 7,
107 | High = 8,
108 | VeryHigh = 9,
109 | }
110 |
111 | public enum StrokeVariation : byte
112 | {
113 | Any = 0,
114 | None = 1,
115 | GradualDiagonal = 2,
116 | GradualTranspositonal = 3,
117 | GradualVertical = 4,
118 | GradualHorizontal = 5,
119 | RapidVertial = 6,
120 | RapidHorizontal = 7,
121 | InstantVertical = 8,
122 | }
123 |
124 | public enum ArmStyle : byte
125 | {
126 | Any = 0,
127 | None = 1,
128 | StraightHorizontal = 2,
129 | StraightWedge = 3,
130 | StraightVertical = 4,
131 | StraightSigleSerif = 5,
132 | StraightDoubleSerif = 6,
133 | BentHorizontal = 7,
134 | BentWedge = 8,
135 | BentVertical = 9,
136 | BentSingleSerif = 10,
137 | BentDoubleSerif = 11,
138 | }
139 |
140 | public enum LetterForm : byte
141 | {
142 | Any = 0,
143 | None = 1,
144 | NormalContact = 2,
145 | NormalWeighted = 3,
146 | NormalBoxed = 4,
147 | NormalFlattened = 5,
148 | NormalRounded = 6,
149 | NormalOffCenter = 7,
150 | NormalSquare = 8,
151 | ObliqueContact = 9,
152 | ObliqueWeighted = 10,
153 | ObliqueBoxed = 11,
154 | ObliqueFlattened = 12,
155 | ObliqueRounded = 13,
156 | ObliqueOffCenter = 14,
157 | ObliqueSquare = 15,
158 | }
159 |
160 | public enum MiddleLine : byte
161 | {
162 | Any = 0,
163 | None = 1,
164 | StandardTrimmed = 2,
165 | StandardPointed = 3,
166 | StandardSerifed = 4,
167 | HighTrimmed = 5,
168 | HighPointed = 6,
169 | HighSerifed = 7,
170 | ConstantTrimmed = 8,
171 | ConstantPointed = 9,
172 | ConstantSerifed = 10,
173 | LowTrimmed = 11,
174 | LowPointed = 12,
175 | LowSerifed = 13,
176 | }
177 |
178 | public enum XHeight : byte
179 | {
180 | Any = 0,
181 | None = 1,
182 | ConstantSmall = 2,
183 | ConstantStandard = 3,
184 | ConstantLarge = 4,
185 | DuckingSmall = 5,
186 | DuckingStandard = 6,
187 | DuckingLarge = 7,
188 | }
189 |
190 | public FamilyType FamilyTypeValue { get; }
191 |
192 | public SerifStyle SerifStyleValue { get; }
193 |
194 | public Weight WeightValue { get; }
195 |
196 | public Proportion ProportionValue { get; }
197 |
198 | public Contrast ContrastValue { get; }
199 |
200 | public StrokeVariation StrokeVariationValue { get; }
201 |
202 | public ArmStyle ArmStyleValue { get; }
203 |
204 | public LetterForm LetterFormValue { get; }
205 |
206 | public MiddleLine MiddleLineValue { get; }
207 |
208 | public XHeight XHeightValue { get; }
209 |
210 | public FaceStyle(FamilyType familyType = FamilyType.Any, SerifStyle serifStyle = SerifStyle.Any,
211 | Weight weight = Weight.Any, Proportion proportion = Proportion.Any, Contrast contrast = Contrast.Any,
212 | StrokeVariation strokeVariation = StrokeVariation.Any, ArmStyle armStyle = ArmStyle.Any,
213 | LetterForm letterForm = LetterForm.Any, MiddleLine middleLine = MiddleLine.Any,
214 | XHeight xHeight = XHeight.Any)
215 | {
216 | FamilyTypeValue = familyType;
217 | SerifStyleValue = serifStyle;
218 | WeightValue = weight;
219 | ProportionValue = proportion;
220 | ContrastValue = contrast;
221 | StrokeVariationValue = strokeVariation;
222 | ArmStyleValue = armStyle;
223 | LetterFormValue = letterForm;
224 | MiddleLineValue = middleLine;
225 | XHeightValue = xHeight;
226 | }
227 | }
228 |
229 | public FontProperty Property { get; }
230 |
231 | public string FontName { get; }
232 |
233 | private readonly AlternativeFont _alternativeFontType;
234 |
235 | public AlternativeFont AlternativeFontType
236 | {
237 | get
238 | {
239 | if (!Property.HasFlag(FontProperty.AlternativeFont))
240 | {
241 | throw new HwpUnsupportedProperty();
242 | }
243 | return _alternativeFontType;
244 | }
245 | }
246 |
247 | private readonly string _alternativeFontName;
248 |
249 | public string AlternativeFontName
250 | {
251 | get
252 | {
253 | if (!Property.HasFlag(FontProperty.AlternativeFont))
254 | {
255 | throw new HwpUnsupportedProperty();
256 | }
257 | return _alternativeFontName;
258 | }
259 | }
260 |
261 | private readonly FaceStyle _faceStyle;
262 |
263 | public FaceStyle FaceStyleValue
264 | {
265 | get
266 | {
267 | if (!Property.HasFlag(FontProperty.FaceStyle))
268 | {
269 | throw new HwpUnsupportedProperty();
270 | }
271 | return _faceStyle;
272 | }
273 | }
274 |
275 | private readonly string _defaultFontName;
276 |
277 | public string DefaultFontName
278 | {
279 | get
280 | {
281 | if (!Property.HasFlag(FontProperty.DefaultFont))
282 | {
283 | throw new HwpUnsupportedProperty();
284 | }
285 | return _defaultFontName;
286 | }
287 | }
288 |
289 | public FaceName(uint level, byte[] bytes, DocumentInformation _ = null)
290 | : base(FaceNameTagId, level, (uint) bytes.Length)
291 | {
292 | var pos = 0;
293 |
294 | FontProperty property;
295 | Property = Enum.TryParse($"{bytes[pos]}", out property) ? property : FontProperty.Unknown;
296 | pos += 1;
297 |
298 | var nameLength = bytes.ToWord(pos);
299 | pos += 2;
300 |
301 | FontName = Encoding.Unicode.GetString(bytes, pos, 2*nameLength);
302 | pos += 2*nameLength;
303 |
304 | if (property.HasFlag(FontProperty.AlternativeFont))
305 | {
306 | AlternativeFont alternative;
307 | _alternativeFontType = Enum.TryParse($"{bytes[pos]}", out alternative)
308 | ? alternative
309 | : AlternativeFont.Unknown;
310 | pos += 1;
311 |
312 | var alternativeLength = bytes.ToWord(pos);
313 | pos += 2;
314 |
315 | _alternativeFontName = Encoding.Unicode.GetString(bytes, pos, 2*alternativeLength);
316 | pos += 2*alternativeLength;
317 | }
318 |
319 | if (property.HasFlag(FontProperty.FaceStyle))
320 | {
321 |
322 | FaceStyle.FamilyType familyType;
323 | familyType = Enum.TryParse($"{bytes[pos++]}", out familyType) ? familyType : FaceStyle.FamilyType.Any;
324 |
325 | FaceStyle.SerifStyle serifStyle;
326 | serifStyle = Enum.TryParse($"{bytes[pos++]}", out serifStyle) ? serifStyle : FaceStyle.SerifStyle.Any;
327 |
328 | FaceStyle.Weight weight;
329 | weight = Enum.TryParse($"{bytes[pos++]}", out weight) ? weight : FaceStyle.Weight.Any;
330 |
331 | FaceStyle.Proportion proportion;
332 | proportion = Enum.TryParse($"{bytes[pos++]}", out proportion) ? proportion : FaceStyle.Proportion.Any;
333 |
334 | FaceStyle.Contrast contrast;
335 | contrast = Enum.TryParse($"{bytes[pos++]}", out contrast) ? contrast : FaceStyle.Contrast.Any;
336 |
337 | FaceStyle.StrokeVariation strokeVariation;
338 | strokeVariation = Enum.TryParse($"{bytes[pos++]}", out strokeVariation)
339 | ? strokeVariation
340 | : FaceStyle.StrokeVariation.Any;
341 |
342 | FaceStyle.ArmStyle armStyle;
343 | armStyle = Enum.TryParse($"{bytes[pos++]}", out armStyle) ? armStyle : FaceStyle.ArmStyle.Any;
344 |
345 | FaceStyle.LetterForm letterForm;
346 | letterForm = Enum.TryParse($"{bytes[pos++]}", out letterForm) ? letterForm : FaceStyle.LetterForm.Any;
347 |
348 | FaceStyle.MiddleLine middleLine;
349 | middleLine = Enum.TryParse($"{bytes[pos++]}", out middleLine) ? middleLine : FaceStyle.MiddleLine.Any;
350 |
351 | FaceStyle.XHeight xHeight;
352 | xHeight = Enum.TryParse($"{bytes[pos++]}", out xHeight) ? xHeight : FaceStyle.XHeight.Any;
353 |
354 | _faceStyle = new FaceStyle(familyType, serifStyle, weight, proportion, contrast, strokeVariation,
355 | armStyle, letterForm, middleLine, xHeight);
356 | }
357 |
358 | if (property.HasFlag(FontProperty.DefaultFont))
359 | {
360 | var defaultLength = bytes.ToWord(pos);
361 | pos += 2;
362 |
363 | _defaultFontName = Encoding.Unicode.GetString(bytes, pos, 2*defaultLength);
364 | pos += 2*defaultLength;
365 | }
366 | }
367 | }
368 | }
369 |
--------------------------------------------------------------------------------
/src/HwpSharp/Hwp5/DocumentInformation/DataRecords/IdMapping.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using HwpSharp.Hwp5.HwpType;
4 | using Int32 = HwpSharp.Hwp5.HwpType.Int32;
5 |
6 | namespace HwpSharp.Hwp5.DocumentInformation.DataRecords
7 | {
8 | public class IdMapping : DataRecord
9 | {
10 | public const uint IdMappingsTagId = HwpTagBegin + 1;
11 |
12 | public Int32[] IdMappingCounts { get; }
13 |
14 | public Int32 BinaryDataCount => IdMappingCounts[0];
15 |
16 | public Int32 KoreanFontCount => IdMappingCounts[1];
17 |
18 | public Int32 EnglishFontCount => IdMappingCounts[2];
19 |
20 | public Int32 ChineseFontCount => IdMappingCounts[3];
21 |
22 | public Int32 JapaneseFontCount => IdMappingCounts[4];
23 |
24 | public Int32 OtherFontCount => IdMappingCounts[5];
25 |
26 | public Int32 SymbolFontCount => IdMappingCounts[6];
27 |
28 | public Int32 UserFontCount => IdMappingCounts[7];
29 |
30 | public Int32 BorderBackgroundCount => IdMappingCounts[8];
31 |
32 | public Int32 CharacterShapeCount => IdMappingCounts[9];
33 |
34 | public Int32 TabDefinitionCount => IdMappingCounts[10];
35 |
36 | public Int32 ParagraphNumberCount => IdMappingCounts[11];
37 |
38 | public Int32 ListHeaderTableCount => IdMappingCounts[12];
39 |
40 | public Int32 ParagraphShapeCount => IdMappingCounts[13];
41 |
42 | public Int32 StyleCount => IdMappingCounts[14];
43 |
44 | public Int32 MemoShapeCount
45 | {
46 | get
47 | {
48 | if (IdMappingCounts.Length < 15)
49 | {
50 | throw new NotSupportedException();
51 | }
52 |
53 | return IdMappingCounts[15];
54 | }
55 | }
56 |
57 | public Int32 TrackChangeCount
58 | {
59 | get
60 | {
61 | if (IdMappingCounts.Length < 16)
62 | {
63 | throw new NotSupportedException();
64 | }
65 |
66 | return IdMappingCounts[16];
67 | }
68 | }
69 |
70 | public Int32 TrackChangeUserCount
71 | {
72 | get
73 | {
74 | if (IdMappingCounts.Length < 17)
75 | {
76 | throw new NotSupportedException();
77 | }
78 |
79 | return IdMappingCounts[17];
80 | }
81 | }
82 |
83 | public IdMapping(uint level, byte[] bytes, DocumentInformation _ = null)
84 | : base(IdMappingsTagId, level, (uint) bytes.Length)
85 | {
86 | var mappings = new List();
87 | for (var pos = 0; pos < bytes.Length; pos += 4)
88 | {
89 | mappings.Add(bytes.ToInt32(pos));
90 | }
91 | IdMappingCounts = mappings.ToArray();
92 | }
93 | }
94 | }
95 |
--------------------------------------------------------------------------------
/src/HwpSharp/Hwp5/DocumentInformation/DocumentInformation.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using HwpSharp.Common;
5 | using HwpSharp.Hwp5.DocumentInformation.DataRecords;
6 | using HwpSharp.Hwp5.HwpType;
7 | using OpenMcdf;
8 |
9 | namespace HwpSharp.Hwp5.DocumentInformation
10 | {
11 | ///
12 | /// Represents a hwp 5.0 document information.
13 | ///
14 | public class DocumentInformation : IDocumentInformation
15 | {
16 | public IList DataRecords { get; }
17 |
18 | public FileHeader FileHeader { get; }
19 |
20 | public DocumentProperty DocumentProperty { get; }
21 |
22 | public IdMapping IdMappings { get; }
23 |
24 | ///
25 | /// Creates a blank instance with specified file header.
26 | ///
27 | /// Hwp 5 file header
28 | public DocumentInformation(FileHeader fileHeader)
29 | {
30 | FileHeader = fileHeader;
31 | }
32 |
33 | internal DocumentInformation(CFStream stream, FileHeader fileHeader)
34 | {
35 | FileHeader = fileHeader;
36 |
37 | var bytes = Document.GetRawBytesFromStream(stream, fileHeader);
38 |
39 | var records = DataRecord.GetRecordsFromBytes(bytes);
40 |
41 | try
42 | {
43 | DataRecords = records as IList ?? records.ToList();
44 | DocumentProperty = (DocumentProperty) DataRecords.Single(r => r.TagId == DocumentProperty.DocumentPropertiesTagId);
45 | IdMappings = (IdMapping) DataRecords.Single(r => r.TagId == IdMapping.IdMappingsTagId);
46 | }
47 | catch (InvalidOperationException exception)
48 | {
49 | throw new HwpFileFormatException(
50 | "This document does not contains a document property data record or contains more than one document property data record.",
51 | exception);
52 | }
53 | }
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/src/HwpSharp/Hwp5/FileHeader.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Linq;
3 | using HwpSharp.Common;
4 | using OpenMcdf;
5 |
6 | namespace HwpSharp.Hwp5
7 | {
8 | ///
9 | /// Represents a hwp 5.0 file header.
10 | ///
11 | public class FileHeader : IFileHeader
12 | {
13 | private const int SignatureLength = 32;
14 | private static readonly byte[] SignatureBytes =
15 | {
16 | 0x48, 0x57, 0x50, 0x20, 0x44, 0x6f, 0x63, 0x75,
17 | 0x6d, 0x65, 0x6e, 0x74, 0x20, 0x46, 0x69, 0x6c,
18 | 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
19 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
20 | }; // "HWP Document File"
21 |
22 | private const int VersionLength = 4;
23 | private const int AttributeLength = 4;
24 |
25 | ///
26 | /// Gets or sets the document file version.
27 | ///
28 | public Version FileVersion { get; set; }
29 |
30 | ///
31 | /// Gets or sets the compressed attribute.
32 | ///
33 | public bool Compressed { get; set; }
34 |
35 | ///
36 | /// Gets or sets the encryption attribute.
37 | ///
38 | public bool PasswordEncrypted { get; set; }
39 |
40 | ///
41 | /// Gets or sets the published document attribute.
42 | ///
43 | public bool Published { get; set; }
44 |
45 | ///
46 | /// Gets or sets whether the document has scripts.
47 | ///
48 | public bool HasScript { get; set; }
49 |
50 | ///
51 | /// Gets or sets the DRM secure attribute.
52 | ///
53 | public bool DrmSecured { get; set; }
54 |
55 | ///
56 | /// Gets or sets whether the document has XML template storages.
57 | ///
58 | public bool HasXmlTemplateStorage { get; set; }
59 |
60 | ///
61 | /// Gets or sets whether the document history is managed.
62 | ///
63 | public bool HasHistory { get; set; }
64 |
65 | ///
66 | /// Gets or sets whether the document has a digital sign.
67 | ///
68 | public bool HasSign { get; set; }
69 |
70 | ///
71 | /// Gets or sets the certificate encryption attribute.
72 | ///
73 | public bool CertificateEncrypted { get; set; }
74 |
75 | ///
76 | /// Gets or sets whether the additional certificate is stored.
77 | ///
78 | public bool CertificateReserved { get; set; }
79 |
80 | ///
81 | /// Gets or sets whether the document is encrypted with certificate and DRM.
82 | ///
83 | public bool CertificateDrmSecured { get; set; }
84 |
85 | ///
86 | /// Gets or sets the CCL document attribute.
87 | ///
88 | public bool CclDocumented { get; set; }
89 |
90 | ///
91 | /// Creates a instance with a blank setting.
92 | ///
93 | public FileHeader()
94 | {
95 | FileVersion = new Version(5, 0, 0, 0);
96 | }
97 |
98 | internal FileHeader(CFStream stream)
99 | {
100 | SetFileHeader(stream);
101 | }
102 |
103 | internal void SetFileHeader(CFStream stream)
104 | {
105 | ParseSignature(stream);
106 | ParseFileVersion(stream);
107 | ParseAttribute(stream);
108 | }
109 |
110 | private void ParseAttribute(CFStream stream)
111 | {
112 | var attributes = new byte[AttributeLength];
113 | var readCount = stream.Read(attributes, 36, AttributeLength);
114 |
115 | if (readCount != AttributeLength)
116 | {
117 | throw new HwpFileFormatException("File attribute field is corrupted. File may be corrupted.");
118 | }
119 |
120 | Compressed = (attributes[0] & 0x1u) != 0;
121 | PasswordEncrypted = (attributes[0] & 0x2u) != 0;
122 | Published = (attributes[0] & 0x4u) != 0;
123 | HasScript = (attributes[0] & 0x8u) != 0;
124 | DrmSecured = (attributes[0] & 0x10u) != 0;
125 | HasXmlTemplateStorage = (attributes[0] & 0x20u) != 0;
126 | HasHistory = (attributes[0] & 0x40u) != 0;
127 | HasSign = (attributes[0] & 0x80u) != 0;
128 | CertificateEncrypted = (attributes[1] & 0x1u) != 0;
129 | CertificateReserved = (attributes[1] & 0x2u) != 0;
130 | CertificateDrmSecured = (attributes[1] & 0x4u) != 0;
131 | CclDocumented = (attributes[1] & 0x8u) != 0;
132 | }
133 |
134 | private void ParseFileVersion(CFStream stream)
135 | {
136 | var versionBytes = new byte[VersionLength];
137 | var readCount = stream.Read(versionBytes, 32, VersionLength);
138 |
139 | if (readCount != VersionLength)
140 | {
141 | throw new HwpFileFormatException("File does not have a version field. File may be corrupted.");
142 | }
143 |
144 | FileVersion = new Version(versionBytes[3], versionBytes[2], versionBytes[1], versionBytes[0]);
145 |
146 | if (FileVersion.Major != 5 || FileVersion.Minor != 0)
147 | {
148 | throw new HwpFileFormatException($"File version '{FileVersion}' is not imcompatible.");
149 | }
150 | }
151 |
152 | private static void ParseSignature(CFStream stream)
153 | {
154 | var signature = new byte[SignatureLength];
155 | var readCount = stream.Read(signature, 0, SignatureLength);
156 |
157 | if (readCount != SignatureLength || !SignatureBytes.SequenceEqual(signature))
158 | {
159 | throw new HwpFileFormatException("Signature is not matched. File may be corrupted.");
160 | }
161 | }
162 | }
163 | }
164 |
--------------------------------------------------------------------------------
/src/HwpSharp/Hwp5/HwpType/DataRecord.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using HwpSharp.Common;
5 | using HwpSharp.Hwp5.BodyText.DataRecords;
6 | using HwpSharp.Hwp5.DocumentInformation.DataRecords;
7 |
8 | namespace HwpSharp.Hwp5.HwpType
9 | {
10 | ///
11 | /// Represents a data record of hwp 5 document.
12 | ///
13 | public abstract class DataRecord
14 | {
15 | internal const int HwpTagBegin = 0x10;
16 |
17 | ///
18 | /// Gets the tag id of data record.
19 | ///
20 | public uint TagId { get; internal set; }
21 |
22 | ///
23 | /// Gets the level of data record.
24 | ///
25 | public uint Level { get; internal set; }
26 |
27 | ///
28 | /// Gets the size of data record.
29 | ///
30 | public DWord Size { get; internal set; }
31 |
32 | protected DataRecord(uint tagId, uint level, DWord size)
33 | {
34 | TagId = tagId;
35 | Level = level;
36 | Size = size;
37 | }
38 |
39 | internal static IEnumerable GetRecordsFromBytes(byte[] bytes, DocumentInformation.DocumentInformation docInfo = null)
40 | {
41 | var records = new List();
42 |
43 | var pos = 0;
44 | while (pos < bytes.Length)
45 | {
46 | var header = bytes.ToDWord(pos);
47 | pos += 4;
48 |
49 | var tagId = header & 0x3FF;
50 | var level = (header >> 10) & 0x3FF;
51 | var size = header >> 20;
52 | if (size == 0xfff)
53 | {
54 | size = bytes.ToDWord(pos);
55 | pos += 4;
56 | }
57 |
58 | var recordBytes = bytes.Skip(pos).Take((int) size).ToArray();
59 | pos += (int) size;
60 | var record = DataRecordFactory.Create(tagId, level, recordBytes, docInfo);
61 |
62 | if (record != null)
63 | {
64 | records.Add(record);
65 | }
66 | }
67 |
68 | return records;
69 | }
70 | }
71 |
72 | public static class DataRecordFactory
73 | {
74 | private static readonly Dictionary DataRecordTypes = new Dictionary
75 | {
76 | {DocumentProperty.DocumentPropertiesTagId, typeof (DocumentProperty)},
77 | {IdMapping.IdMappingsTagId, typeof (IdMapping)},
78 | {BinData.BinDataTagId, typeof (BinData)},
79 | {FaceName.FaceNameTagId, typeof (FaceName)},
80 | {BorderFill.BorderFillTagId, typeof (BorderFill)},
81 |
82 | {ParagraphHeader.ParagraphHeaderTagId, typeof (ParagraphHeader)},
83 | {ParagraphText.ParagraphTextTagId, typeof (ParagraphText)},
84 | };
85 |
86 | public static void RegisterType(uint tagId, Type type)
87 | {
88 | DataRecordTypes[tagId] = type;
89 | }
90 |
91 | public static DataRecord Create(uint tagId, uint level, byte[] data, DocumentInformation.DocumentInformation docInfo = null)
92 | {
93 | if (!DataRecordTypes.ContainsKey(tagId))
94 | {
95 | return new DataRecordImpl(tagId, level, data);
96 | }
97 |
98 | var ctor =
99 | DataRecordTypes[tagId].GetConstructor(new[]
100 | {typeof (uint), typeof (byte[]), typeof (DocumentInformation.DocumentInformation)});
101 | if (ctor == null)
102 | {
103 | throw new HwpDataRecordConstructorException();
104 | }
105 | return ctor.Invoke(new object[] {level, data, docInfo}) as DataRecord;
106 | }
107 | }
108 |
109 | internal class DataRecordImpl : DataRecord
110 | {
111 | public byte[] Data { get; private set; }
112 |
113 | public DataRecordImpl(uint tagId, uint level, byte[] data = null)
114 | : base(tagId, level, (uint) (data?.Length ?? 0))
115 | {
116 | Data = data;
117 | }
118 | }
119 | }
120 |
--------------------------------------------------------------------------------
/src/HwpSharp/Hwp5/HwpType/DataTypes.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Diagnostics;
4 | using System.Linq;
5 |
6 | namespace HwpSharp.Hwp5.HwpType
7 | {
8 | ///
9 | /// Unsigned 1 byte (0-255).
10 | ///
11 | [DebuggerDisplay("{_value}")]
12 | [DebuggerTypeProxy(typeof(byte))]
13 | public struct Byte
14 | {
15 | private readonly byte _value;
16 |
17 | private Byte(byte value)
18 | {
19 | _value = value;
20 | }
21 |
22 | ///
23 | /// Implicitly converts a to a .
24 | ///
25 | /// The to convert.
26 | /// A new with the specified value.
27 | public static implicit operator Byte(byte value)
28 | {
29 | return new Byte(value);
30 | }
31 |
32 | ///
33 | /// Implicitly converts a to a .
34 | ///
35 | /// The to convert.
36 | /// A that is the specified 's value.
37 | public static implicit operator byte(Byte value)
38 | {
39 | return value._value;
40 | }
41 |
42 | public override string ToString()
43 | {
44 | return _value.ToString();
45 | }
46 | }
47 |
48 | ///
49 | /// 'unsigned int' on the 16bit compiler.
50 | ///
51 | [DebuggerDisplay("{_value}")]
52 | [DebuggerTypeProxy(typeof(ushort))]
53 | public struct Word
54 | {
55 | private readonly ushort _value;
56 |
57 | private Word(ushort value)
58 | {
59 | _value = value;
60 | }
61 |
62 | ///
63 | /// Implicitly converts a to a .
64 | ///
65 | /// The to convert.
66 | /// A new with the specified value.
67 | public static implicit operator Word(ushort value)
68 | {
69 | return new Word(value);
70 | }
71 |
72 | ///
73 | /// Implicitly converts a to a .
74 | ///
75 | /// The to convert.
76 | /// A that is the specified 's value.
77 | public static implicit operator ushort(Word value)
78 | {
79 | return value._value;
80 | }
81 |
82 | public override string ToString()
83 | {
84 | return _value.ToString();
85 | }
86 | }
87 |
88 | ///
89 | /// 'unsigned long' on the 16bit compiler.
90 | ///
91 | [DebuggerDisplay("{_value}")]
92 | [DebuggerTypeProxy(typeof(uint))]
93 | public struct DWord
94 | {
95 | private readonly uint _value;
96 |
97 | private DWord(uint value)
98 | {
99 | _value = value;
100 | }
101 |
102 | ///
103 | /// Implicitly converts a to a .
104 | ///
105 | /// The to convert.
106 | /// A new with the specified value.
107 | public static implicit operator DWord(uint value)
108 | {
109 | return new DWord(value);
110 | }
111 |
112 | ///
113 | /// Implicitly converts a to a .
114 | ///
115 | /// The to convert.
116 | /// A that is the specified 's value.
117 | public static implicit operator uint(DWord value)
118 | {
119 | return value._value;
120 | }
121 |
122 | public override string ToString()
123 | {
124 | return _value.ToString();
125 | }
126 | }
127 |
128 | ///
129 | /// Unicode based character, default code in HWP.
130 | ///
131 | [DebuggerDisplay("{_value}")]
132 | [DebuggerTypeProxy(typeof(char))]
133 | public struct WChar
134 | {
135 | private readonly char _value;
136 |
137 | private WChar(char value)
138 | {
139 | _value = value;
140 | }
141 |
142 | ///
143 | /// Implicitly converts a to a .
144 | ///
145 | /// The to convert.
146 | /// A new with the specified value.
147 | public static implicit operator WChar(char value)
148 | {
149 | return new WChar(value);
150 | }
151 |
152 | ///
153 | /// Implicitly converts a to a .
154 | ///
155 | /// The to convert.
156 | /// A that is the specified 's value.
157 | public static implicit operator char(WChar value)
158 | {
159 | return value._value;
160 | }
161 |
162 | public override string ToString()
163 | {
164 | return _value.ToString();
165 | }
166 | }
167 |
168 | ///
169 | /// HWP internal unit, represented as 1/1700 inch.
170 | ///
171 | [DebuggerDisplay("{_value}")]
172 | [DebuggerTypeProxy(typeof(uint))]
173 | public struct HwpUnit
174 | {
175 | private readonly uint _value;
176 |
177 | private HwpUnit(uint value)
178 | {
179 | _value = value;
180 | }
181 |
182 | ///
183 | /// Implicitly converts a to a .
184 | ///
185 | /// The to convert.
186 | /// A new with the specified value.
187 | public static implicit operator HwpUnit(uint value)
188 | {
189 | return new HwpUnit(value);
190 | }
191 |
192 | ///
193 | /// Implicitly converts a to a .
194 | ///
195 | /// The to convert.
196 | /// A that is the specified 's value.
197 | public static implicit operator uint(HwpUnit value)
198 | {
199 | return value._value;
200 | }
201 |
202 | public override string ToString()
203 | {
204 | return _value.ToString();
205 | }
206 | }
207 |
208 | ///
209 | /// HWP internal unit, represented as 1/1700 inch with sign.
210 | ///
211 | [DebuggerDisplay("{_value}")]
212 | [DebuggerTypeProxy(typeof(int))]
213 | public struct SHwpUnit
214 | {
215 | private readonly int _value;
216 |
217 | private SHwpUnit(int value)
218 | {
219 | _value = value;
220 | }
221 |
222 | ///
223 | /// Implicitly converts a to a .
224 | ///
225 | /// The to convert.
226 | /// A new with the specified value.
227 | public static implicit operator SHwpUnit(int value)
228 | {
229 | return new SHwpUnit(value);
230 | }
231 |
232 | ///
233 | /// Implicitly converts a to a .
234 | ///
235 | /// The to convert.
236 | /// A that is the specified 's value.
237 | public static implicit operator int(SHwpUnit value)
238 | {
239 | return value._value;
240 | }
241 |
242 | public override string ToString()
243 | {
244 | return _value.ToString();
245 | }
246 | }
247 |
248 | ///
249 | /// 'unsigned __int8'
250 | ///
251 | [DebuggerDisplay("{_value}")]
252 | [DebuggerTypeProxy(typeof(byte))]
253 | public struct UInt8
254 | {
255 | private readonly byte _value;
256 |
257 | private UInt8(byte value)
258 | {
259 | _value = value;
260 | }
261 |
262 | ///
263 | /// Implicitly converts a to a .
264 | ///
265 | /// The to convert.
266 | /// A new with the specified value.
267 | public static implicit operator UInt8(byte value)
268 | {
269 | return new UInt8(value);
270 | }
271 |
272 | ///
273 | /// Implicitly converts a to a .
274 | ///
275 | /// The to convert.
276 | /// A that is the specified 's value.
277 | public static implicit operator byte(UInt8 value)
278 | {
279 | return value._value;
280 | }
281 |
282 | public override string ToString()
283 | {
284 | return _value.ToString();
285 | }
286 | }
287 |
288 | ///
289 | /// 'unsigned __int16'
290 | ///
291 | [DebuggerDisplay("{_value}")]
292 | [DebuggerTypeProxy(typeof(ushort))]
293 | public struct UInt16
294 | {
295 | private readonly ushort _value;
296 |
297 | private UInt16(ushort value)
298 | {
299 | _value = value;
300 | }
301 |
302 | ///
303 | /// Implicitly converts a to a .
304 | ///
305 | /// The to convert.
306 | /// A new with the specified value.
307 | public static implicit operator UInt16(ushort value)
308 | {
309 | return new UInt16(value);
310 | }
311 |
312 | ///
313 | /// Implicitly converts a to a .
314 | ///
315 | /// The to convert.
316 | /// A that is the specified 's value.
317 | public static implicit operator ushort(UInt16 value)
318 | {
319 | return value._value;
320 | }
321 |
322 | public override string ToString()
323 | {
324 | return _value.ToString();
325 | }
326 | }
327 |
328 | ///
329 | /// 'unsigned __int32'
330 | ///
331 | [DebuggerDisplay("{_value}")]
332 | [DebuggerTypeProxy(typeof(uint))]
333 | public struct UInt32
334 | {
335 | private readonly uint _value;
336 |
337 | private UInt32(uint value)
338 | {
339 | _value = value;
340 | }
341 |
342 | ///
343 | /// Implicitly converts a to a .
344 | ///
345 | /// The to convert.
346 | /// A new with the specified value.
347 | public static implicit operator UInt32(uint value)
348 | {
349 | return new UInt32(value);
350 | }
351 |
352 | ///
353 | /// Implicitly converts a to a .
354 | ///
355 | /// The to convert.
356 | /// A that is the specified 's value.
357 | public static implicit operator uint(UInt32 value)
358 | {
359 | return value._value;
360 | }
361 |
362 | public override string ToString()
363 | {
364 | return _value.ToString();
365 | }
366 | }
367 |
368 | ///
369 | /// 'signed __int8'
370 | ///
371 | [DebuggerDisplay("{_value}")]
372 | [DebuggerTypeProxy(typeof(sbyte))]
373 | public struct Int8
374 | {
375 | private readonly sbyte _value;
376 |
377 | private Int8(sbyte value)
378 | {
379 | _value = value;
380 | }
381 |
382 | ///
383 | /// Implicitly converts a to a .
384 | ///
385 | /// The to convert.
386 | /// A new with the specified value.
387 | public static implicit operator Int8(sbyte value)
388 | {
389 | return new Int8(value);
390 | }
391 |
392 | ///
393 | /// Implicitly converts a to a .
394 | ///
395 | /// The to convert.
396 | /// A that is the specified 's value.
397 | public static implicit operator sbyte(Int8 value)
398 | {
399 | return value._value;
400 | }
401 |
402 | public override string ToString()
403 | {
404 | return _value.ToString();
405 | }
406 | }
407 |
408 | ///
409 | /// 'signed __int16'
410 | ///
411 | [DebuggerDisplay("{_value}")]
412 | [DebuggerTypeProxy(typeof(short))]
413 | public struct Int16
414 | {
415 | private readonly short _value;
416 |
417 | private Int16(short value)
418 | {
419 | _value = value;
420 | }
421 |
422 | ///
423 | /// Implicitly converts a to a .
424 | ///
425 | /// The to convert.
426 | /// A new with the specified value.
427 | public static implicit operator Int16(short value)
428 | {
429 | return new Int16(value);
430 | }
431 |
432 | ///
433 | /// Implicitly converts a to a .
434 | ///
435 | /// The to convert.
436 | /// A that is the specified 's value.
437 | public static implicit operator short(Int16 value)
438 | {
439 | return value._value;
440 | }
441 |
442 | public override string ToString()
443 | {
444 | return _value.ToString();
445 | }
446 | }
447 |
448 | ///
449 | /// 'signed __int32'
450 | ///
451 | [DebuggerDisplay("{_value}")]
452 | [DebuggerTypeProxy(typeof(int))]
453 | public struct Int32
454 | {
455 | private readonly int _value;
456 |
457 | private Int32(int value)
458 | {
459 | _value = value;
460 | }
461 |
462 | ///
463 | /// Implicitly converts a to a .
464 | ///
465 | /// The to convert.
466 | /// A new with the specified value.
467 | public static implicit operator Int32(int value)
468 | {
469 | return new Int32(value);
470 | }
471 |
472 | ///
473 | /// Implicitly converts a to a .
474 | ///
475 | /// The to convert.
476 | /// A that is the specified 's value.
477 | public static implicit operator int(Int32 value)
478 | {
479 | return value._value;
480 | }
481 |
482 | public override string ToString()
483 | {
484 | return _value.ToString();
485 | }
486 | }
487 |
488 | ///
489 | /// Same as INT16
490 | ///
491 | [DebuggerDisplay("{_value}")]
492 | [DebuggerTypeProxy(typeof(short))]
493 | public struct HwpUnit16
494 | {
495 | private readonly short _value;
496 |
497 | private HwpUnit16(short value)
498 | {
499 | _value = value;
500 | }
501 |
502 | ///
503 | /// Implicitly converts a to a .
504 | ///
505 | /// The to convert.
506 | /// A new with the specified value.
507 | public static implicit operator HwpUnit16(short value)
508 | {
509 | return new HwpUnit16(value);
510 | }
511 |
512 | ///
513 | /// Implicitly converts a to a .
514 | ///
515 | /// The to convert.
516 | /// A that is the specified 's value.
517 | public static implicit operator short(HwpUnit16 value)
518 | {
519 | return value._value;
520 | }
521 |
522 | public override string ToString()
523 | {
524 | return _value.ToString();
525 | }
526 | }
527 |
528 | ///
529 | /// Represents RGB value(0x00bbggrr) as decimal.
530 | ///
531 | [DebuggerDisplay("({Red}, {Green}, {Blue})")]
532 | public struct Color
533 | {
534 | public byte Red { get; }
535 | public byte Green { get; }
536 | public byte Blue { get; }
537 |
538 | private Color(uint value)
539 | {
540 | Red = (byte) (value & 0xff);
541 | Green = (byte) ((value >> 8) & 0xff);
542 | Blue = (byte) ((value >> 16) & 0xff);
543 | }
544 |
545 | public Color(byte r, byte g, byte b)
546 | {
547 | Red = r;
548 | Green = g;
549 | Blue = b;
550 | }
551 |
552 | ///
553 | /// Implicitly converts a to a .
554 | ///
555 | /// The to convert.
556 | /// A new with the specified value.
557 | public static implicit operator Color(uint value)
558 | {
559 | return new Color(value);
560 | }
561 |
562 | ///
563 | /// Implicitly converts a to a .
564 | ///
565 | /// The to convert.
566 | /// A that is the specified 's value.
567 | public static implicit operator uint(Color value)
568 | {
569 | return value.Red + value.Green*0x100u + value.Blue*0x10000u;
570 | }
571 |
572 | public override string ToString()
573 | {
574 | return $"({Red}, {Green}, {Blue})";
575 | }
576 | }
577 |
578 | public static class ByteArrayConverter
579 | {
580 | public static Word ToWord(this IEnumerable bytes, int offset = 0)
581 | {
582 | var arr = bytes.Skip(offset).Take(2).ToArray();
583 | if (arr.Length < 2)
584 | {
585 | throw new ArgumentOutOfRangeException(nameof(bytes), "Word needs at least 2 bytes.");
586 | }
587 |
588 | return (ushort) (arr[0] + arr[1]*0x100u);
589 | }
590 |
591 | public static DWord ToDWord(this IEnumerable bytes, int offset = 0)
592 | {
593 | var arr = bytes.Skip(offset).Take(4).ToArray();
594 | if (arr.Length < 4)
595 | {
596 | throw new ArgumentOutOfRangeException(nameof(bytes), "DWord needs at least 4 bytes.");
597 | }
598 |
599 | return arr[0] + arr[1]*0x100u + arr[2]*0x10000u + arr[3]*0x1000000u;
600 | }
601 |
602 | public static WChar ToWChar(this IEnumerable bytes, int offset = 0)
603 | {
604 | var arr = bytes.Skip(offset).Take(2).ToArray();
605 | if (arr.Length < 2)
606 | {
607 | throw new ArgumentOutOfRangeException(nameof(bytes), "WChar needs at least 2 bytes.");
608 | }
609 |
610 | return (char) (arr[0] + arr[1]*0x100u);
611 | }
612 |
613 | public static HwpUnit ToHwpUnit(this IEnumerable bytes, int offset = 0)
614 | {
615 | var arr = bytes.Skip(offset).Take(4).ToArray();
616 | if (arr.Length < 4)
617 | {
618 | throw new ArgumentOutOfRangeException(nameof(bytes), "HwpUnit needs at least 4 bytes.");
619 | }
620 |
621 | return arr[0] + arr[1]*0x100u + arr[2]*0x10000u + arr[3]*0x1000000u;
622 | }
623 |
624 | public static SHwpUnit ToSHwpUnit(this IEnumerable bytes, int offset = 0)
625 | {
626 | var arr = bytes.Skip(offset).Take(4).ToArray();
627 | if (arr.Length < 4)
628 | {
629 | throw new ArgumentOutOfRangeException(nameof(bytes), "SHwpUnit needs at least 4 bytes.");
630 | }
631 |
632 | return arr[0] + arr[1]*0x100 + arr[2]*0x10000 + arr[3]*0x1000000;
633 | }
634 |
635 | public static UInt16 ToUInt16(this IEnumerable bytes, int offset = 0)
636 | {
637 | var arr = bytes.Skip(offset).Take(2).ToArray();
638 | if (arr.Length < 2)
639 | {
640 | throw new ArgumentOutOfRangeException(nameof(bytes), "UInt16 needs at least 2 bytes.");
641 | }
642 |
643 | return (ushort) (arr[0] + arr[1]*0x100u);
644 | }
645 |
646 | public static UInt32 ToUInt32(this IEnumerable bytes, int offset = 0)
647 | {
648 | var arr = bytes.Skip(offset).Take(4).ToArray();
649 | if (arr.Length < 4)
650 | {
651 | throw new ArgumentOutOfRangeException(nameof(bytes), "UInt32 needs at least 4 bytes.");
652 | }
653 |
654 | return arr[0] + arr[1]*0x100u + arr[2]*0x10000u + arr[3]*0x1000000u;
655 | }
656 |
657 | public static Int16 ToInt16(this IEnumerable bytes, int offset = 0)
658 | {
659 | var arr = bytes.Skip(offset).Take(2).ToArray();
660 | if (arr.Length < 2)
661 | {
662 | throw new ArgumentOutOfRangeException(nameof(bytes), "Int16 needs at least 2 bytes.");
663 | }
664 |
665 | return (short) (arr[0] + arr[1]*0x100);
666 | }
667 |
668 | public static Int32 ToInt32(this IEnumerable bytes, int offset = 0)
669 | {
670 | var arr = bytes.Skip(offset).Take(4).ToArray();
671 | if (arr.Length < 4)
672 | {
673 | throw new ArgumentOutOfRangeException(nameof(bytes), "Int32 needs at least 4 bytes.");
674 | }
675 |
676 | return arr[0] + arr[1]*0x100 + arr[2]*0x10000 + arr[3]*0x1000000;
677 | }
678 |
679 | public static HwpUnit16 ToHwpUnit16(this IEnumerable bytes, int offset = 0)
680 | {
681 | var arr = bytes.Skip(offset).Take(2).ToArray();
682 | if (arr.Length < 2)
683 | {
684 | throw new ArgumentOutOfRangeException(nameof(bytes), "HwpUnit16 needs at least 2 bytes.");
685 | }
686 |
687 | return (short) (arr[0] + arr[1]*0x100);
688 | }
689 |
690 | public static Color ToColor(this IEnumerable bytes, int offset = 0)
691 | {
692 | var arr = bytes.Skip(offset).Take(4).ToArray();
693 | if (arr.Length < 4)
694 | {
695 | throw new ArgumentOutOfRangeException(nameof(bytes), "Color needs at least 4 bytes.");
696 | }
697 |
698 | return new Color(arr[0], arr[1], arr[2]);
699 | }
700 | }
701 | }
--------------------------------------------------------------------------------
/src/HwpSharp/Hwp5/HwpType/TagEnum.cs:
--------------------------------------------------------------------------------
1 | namespace HwpSharp.Hwp5.HwpType
2 | {
3 | ///
4 | /// Specifies a tag ID of a hwp 5 data record.
5 | ///
6 | public enum TagEnum
7 | {
8 | Unknown = -1,
9 |
10 | #region DocInfo
11 |
12 | ///
13 | /// Document property.
14 | ///
15 | DocumentProperties = DataRecord.HwpTagBegin,
16 | IdMappings = DataRecord.HwpTagBegin + 1,
17 | BinDate = DataRecord.HwpTagBegin + 2,
18 | FaceName = DataRecord.HwpTagBegin + 3,
19 | BorderFill = DataRecord.HwpTagBegin + 4,
20 | CharShape = DataRecord.HwpTagBegin + 5,
21 | TabDef = DataRecord.HwpTagBegin + 6,
22 | Numbering = DataRecord.HwpTagBegin + 7,
23 | Bullet = DataRecord.HwpTagBegin + 8,
24 | ParaShape = DataRecord.HwpTagBegin + 9,
25 | Style = DataRecord.HwpTagBegin + 10,
26 | DocData = DataRecord.HwpTagBegin + 11,
27 | DistributeDocData = DataRecord.HwpTagBegin + 12,
28 | CompatibleDocument = DataRecord.HwpTagBegin + 14,
29 | LayoutCompatibility = DataRecord.HwpTagBegin + 15,
30 | TrackChange = DataRecord.HwpTagBegin + 16,
31 | MemoShape = DataRecord.HwpTagBegin + 76,
32 | ForbiddenChar = DataRecord.HwpTagBegin + 78,
33 | TrackChangeShape = DataRecord.HwpTagBegin + 80,
34 | TrackChangeAuthor = DataRecord.HwpTagBegin + 81,
35 | #endregion
36 |
37 | #region BodyText
38 | ParagraphHeader = DataRecord.HwpTagBegin + 50,
39 | ParagraphText = DataRecord.HwpTagBegin + 51,
40 | ParagraphCharacterShape = DataRecord.HwpTagBegin + 52,
41 | ParagraphLineSegment = DataRecord.HwpTagBegin + 53,
42 | ParagraphRangeTag = DataRecord.HwpTagBegin + 54,
43 | ControlHeader = DataRecord.HwpTagBegin + 55,
44 | ListHeader = DataRecord.HwpTagBegin + 56,
45 | PageDefinition = DataRecord.HwpTagBegin + 57,
46 | FootnoteShape = DataRecord.HwpTagBegin + 58,
47 | PageBorderFill = DataRecord.HwpTagBegin + 59,
48 | ShapeComponent = DataRecord.HwpTagBegin + 60,
49 | Table = DataRecord.HwpTagBegin + 61,
50 | ShapeComponentLine = DataRecord.HwpTagBegin + 62,
51 | ShapeComponentRectangle = DataRecord.HwpTagBegin + 63,
52 | ShapeComponentEllipse = DataRecord.HwpTagBegin + 64,
53 | ShapeComponentArc = DataRecord.HwpTagBegin + 65,
54 | ShapeComponentPolygon = DataRecord.HwpTagBegin + 66,
55 | ShapeComponentCurve = DataRecord.HwpTagBegin + 67,
56 | ShapeComponentOle = DataRecord.HwpTagBegin + 68,
57 | ShapeComponentPicture = DataRecord.HwpTagBegin + 69,
58 | ShapeComponentContainer = DataRecord.HwpTagBegin + 70,
59 | ControlData = DataRecord.HwpTagBegin + 71,
60 | Equation = DataRecord.HwpTagBegin + 72,
61 | ShapeComponentTextArt = DataRecord.HwpTagBegin + 74,
62 | FormObject = DataRecord.HwpTagBegin + 75,
63 | MemoList = DataRecord.HwpTagBegin + 77,
64 | ChartData = DataRecord.HwpTagBegin + 79,
65 | VideoData = DataRecord.HwpTagBegin + 82,
66 | ShapeComponentUnknown = DataRecord.HwpTagBegin + 99
67 | #endregion
68 | }
69 | }
70 |
--------------------------------------------------------------------------------
/src/HwpSharp/Hwp5/SummaryInformation.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Threading.Tasks;
5 | using HwpSharp.Common;
6 |
7 | namespace HwpSharp.Hwp5
8 | {
9 | ///
10 | /// Represents a hwp 5.0 summary information.
11 | ///
12 | public class SummaryInformation : ISummaryInformation
13 | {
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/src/HwpSharp/HwpReader.cs:
--------------------------------------------------------------------------------
1 | using System.IO;
2 | using System.Linq;
3 | using HwpSharp.Common;
4 | using HwpSharp.Hwp5;
5 |
6 | namespace HwpSharp
7 | {
8 | ///
9 | /// Represents a Hwp document reader.
10 | ///
11 | public static class HwpReader
12 | {
13 | private static class Signature
14 | {
15 | public static readonly byte[] Hwp3 =
16 | {
17 | 0x48, 0x57, 0x50, 0x20, 0x44, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x20, 0x46, 0x69, 0x6c,
18 | 0x65, 0x20, 0x56, 0x33, 0x2e, 0x30, 0x30, 0x20, 0x1a, 0x01, 0x02, 0x03, 0x04, 0x05
19 | };
20 |
21 | public static readonly byte[] CompoundFile =
22 | {
23 | 0xd0, 0xcf, 0x11, 0xe0, 0xa1, 0xb1, 0x1a, 0xe1
24 | };
25 | }
26 |
27 | private static class FileType
28 | {
29 | public const string Hwp3 = @"HWP 3.0";
30 | public const string CompoundFile = @"Compound File";
31 | }
32 |
33 | ///
34 | /// Returns a from a hwp document file.
35 | ///
36 | /// Path to a hwp document.
37 | /// instance.
38 | public static IHwpDocument Read(string filename)
39 | {
40 | using (var stream = new FileStream(filename, FileMode.Open, FileAccess.Read, FileShare.Read))
41 | {
42 | return Read(stream);
43 | }
44 | }
45 |
46 | ///
47 | /// Returns a from a stream.
48 | ///
49 | /// Stream of a hwp document.
50 | /// instance.
51 | public static IHwpDocument Read(Stream stream)
52 | {
53 | var fileType = GetFileType(stream);
54 | if (fileType == FileType.CompoundFile)
55 | {
56 | return new Document(stream);
57 | }
58 | throw new HwpFileFormatException("File type is imcompatible.");
59 | }
60 |
61 | private static string GetFileType(Stream stream)
62 | {
63 | var memoryStream = ReadFromStream(stream);
64 |
65 | if (IsHwp30Format(memoryStream))
66 | {
67 | return FileType.Hwp3;
68 | }
69 |
70 | if (IsCompoundFileFormat(memoryStream))
71 | {
72 | return FileType.CompoundFile;
73 | }
74 |
75 | throw new HwpFileFormatException("File type is unknown.");
76 | }
77 |
78 | private static MemoryStream ReadFromStream(Stream stream)
79 | {
80 | try
81 | {
82 | var memoryStream = new MemoryStream();
83 | while (true)
84 | {
85 | var buf = new byte[8192];
86 | var read = stream.Read(buf, 0, buf.Length);
87 | if (read > 0)
88 | {
89 | memoryStream.Write(buf, 0, read);
90 | }
91 | else
92 | {
93 | break;
94 | }
95 | }
96 | memoryStream.Position = 0;
97 | return memoryStream;
98 | }
99 | finally
100 | {
101 | stream.Close();
102 | }
103 | }
104 |
105 | private static bool IsHwp30Format(Stream stream)
106 | {
107 | var read = 0;
108 | try
109 | {
110 | var firstBytes = new byte[30];
111 | read = stream.Read(firstBytes, 0, 30);
112 | return Signature.Hwp3.SequenceEqual(firstBytes);
113 | }
114 | finally
115 | {
116 | if (read > 0)
117 | {
118 | stream.Seek(-read, SeekOrigin.Current);
119 | }
120 | }
121 | }
122 |
123 | private static bool IsCompoundFileFormat(Stream stream)
124 | {
125 | var read = 0;
126 | try
127 | {
128 | var firstBytes = new byte[8];
129 | read = stream.Read(firstBytes, 0, 8);
130 |
131 | return Signature.CompoundFile.SequenceEqual(firstBytes);
132 | }
133 | finally
134 | {
135 | if (read > 0)
136 | {
137 | stream.Seek(-read, SeekOrigin.Current);
138 | }
139 | }
140 | }
141 | }
142 | }
--------------------------------------------------------------------------------
/src/HwpSharp/HwpSharp.xproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | 14.0
5 | $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)
6 |
7 |
8 |
9 | e8ab29c7-8222-4ec8-bff2-06c1c119abea
10 | HwpSharp
11 | ..\artifacts\obj\$(MSBuildProjectName)
12 | .\bin\
13 |
14 |
15 | HwpSharp
16 |
17 |
18 | 2.0
19 |
20 |
21 | True
22 |
23 |
24 |
--------------------------------------------------------------------------------
/src/HwpSharp/project.json:
--------------------------------------------------------------------------------
1 | {
2 | "authors": [ "Yoon SeungYong" ],
3 | "dependencies": {
4 | "OpenMcdf": "2.0.5739.40493"
5 | },
6 | "description": "C# Library for HWP documents",
7 | "frameworks": {
8 | "net45": {
9 | "frameworkAssemblies": {
10 | "System": "4.0.0.0",
11 | "System.Runtime": "4.0.0.0",
12 | "System.Collections": "4.0.0.0",
13 | "System.Linq": "4.0.0.0"
14 | }
15 | }
16 | },
17 | "packOptions": {
18 | "licenseUrl": "https://raw.githubusercontent.com/forcom/HwpSharp/master/LICENSE",
19 | "projectUrl": "https://github.com/forcom/HwpSharp",
20 | "tags": [ "" ]
21 | },
22 | "version": "1.0.0-*"
23 | }
24 |
--------------------------------------------------------------------------------
/test/HwpSharp.Tests.Console/HwpSharp.Tests.Console.xproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | 14.0
5 | $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)
6 |
7 |
8 |
9 | d0e23e50-7881-4442-8e44-73300a7f6d9f
10 | HwpSharp.Tests.Console
11 | ..\..\artifacts\obj\$(MSBuildProjectName)
12 | .\bin\
13 |
14 |
15 | 2.0
16 |
17 |
18 |
--------------------------------------------------------------------------------
/test/HwpSharp.Tests.Console/Program.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 | using HwpSharp.Hwp5;
7 | using HwpSharp.Hwp5.BodyText.DataRecords;
8 |
9 | namespace HwpSharp.Tests.Console
10 | {
11 | public class Program
12 | {
13 | public static void Main(string[] args)
14 | {
15 | var doc = new Document(@"..\case\Hwp5\distribution.hwp");
16 | foreach (var section in doc.BodyText.Sections)
17 | {
18 | if (section == null)
19 | continue;
20 | foreach (var record in section.DataRecords)
21 | {
22 | if (record?.TagId != ParagraphText.ParagraphTextTagId)
23 | continue;
24 | System.Console.WriteLine(((ParagraphText) record)?.Text);
25 | }
26 | }
27 | }
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/test/HwpSharp.Tests.Console/project.json:
--------------------------------------------------------------------------------
1 | {
2 | "version": "1.0.0-*",
3 | "description": "HwpSharp.Tests.Console Console Application",
4 | "authors": [ "Y" ],
5 | "tags": [ "" ],
6 | "projectUrl": "",
7 | "licenseUrl": "",
8 |
9 | "dependencies": {
10 | "HwpSharp": "1.0.0-*"
11 | },
12 |
13 | "commands": {
14 | "HwpSharp.Tests.Console": "HwpSharp.Tests.Console"
15 | },
16 |
17 | "buildOptions": {
18 | "emitEntryPoint": true
19 | },
20 | "frameworks": {
21 | "net451": { }
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/test/HwpSharp.Tests/Hwp5/BodyTextTest.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Threading.Tasks;
5 | using HwpSharp.Hwp5;
6 | using HwpSharp.Hwp5.BodyText.DataRecords;
7 | using HwpSharp.Hwp5.HwpType;
8 | using Xunit;
9 |
10 | namespace HwpSharp.Tests.Hwp5
11 | {
12 | public class BodyTextTest
13 | {
14 | [Theory]
15 | // [InlineData(@"../../../../../case/Hwp5/BlogForm_BookReview.hwp", null)]
16 | // [InlineData(@"../../../../../case/Hwp5/BlogForm_MovieReview.hwp", null)]
17 | // [InlineData(@"../../../../../case/Hwp5/BlogForm_Recipe.hwp", null)]
18 | // [InlineData(@"../../../../../case/Hwp5/BookReview.hwp", null)]
19 | // [InlineData(@"../../../../../case/Hwp5/calendar_monthly.hwp", null)]
20 | // [InlineData(@"../../../../../case/Hwp5/calendar_year.hwp", null)]
21 | // [InlineData(@"../../../../../case/Hwp5/classical_literature.hwp", null)]
22 | // [InlineData(@"../../../../../case/Hwp5/english.hwp", null)]
23 | // [InlineData(@"../../../../../case/Hwp5/Hyper(hwp2010).hwp", null)]
24 | // [InlineData(@"../../../../../case/Hwp5/interview.hwp", null)]
25 | // [InlineData(@"../../../../../case/Hwp5/KTX.hwp", null)]
26 | // [InlineData(@"../../../../../case/Hwp5/NewYear_s_Day.hwp", null)]
27 | // [InlineData(@"../../../../../case/Hwp5/request.hwp", null)]
28 | // [InlineData(@"../../../../../case/Hwp5/shortcut.hwp", null)]
29 | // [InlineData(@"../../../../../case/Hwp5/sungeo.hwp", null)]
30 | // [InlineData(@"../../../../../case/Hwp5/Textmail.hwp", null)]
31 | // [InlineData(@"../../../../../case/Hwp5/treatise sample.hwp", null)]
32 | // [InlineData(@"../../../../../case/Hwp5/Worldcup_FIFA2010_32.hwp", null)]
33 | [InlineData(@"../../../../../case/Hwp5/multisection.hwp", "\u0002\u6364\u7365\0\0\0\0\u0002\u0002\u6c64\u636f\0\0\0\0\u0002\u0015\u6e70\u7067\0\0\0\0\u0015MultiSection 01\r")]
34 | public void ParagraphText_NormalHwp5Document(string filename, string expectedBodyText)
35 | {
36 | var document = new Document(filename);
37 |
38 | var paragraph =
39 | document.BodyText.Sections[0].DataRecords.Where(
40 | record => record.TagId == ParagraphText.ParagraphTextTagId)
41 | .Cast()
42 | .Aggregate("", (x, y) => x + y?.Text);
43 | Assert.Equal(expectedBodyText, paragraph);
44 | }
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/test/HwpSharp.Tests/Hwp5/DocumentInformationTest.cs:
--------------------------------------------------------------------------------
1 | using HwpSharp.Hwp5;
2 | using Xunit;
3 |
4 | namespace HwpSharp.Tests.Hwp5
5 | {
6 | public class DocumentInformationTest
7 | {
8 | [Theory]
9 | [InlineData(@"../../../../../case/Hwp5/BlogForm_BookReview.hwp", 1, 1)]
10 | [InlineData(@"../../../../../case/Hwp5/BlogForm_MovieReview.hwp", 1, 1)]
11 | [InlineData(@"../../../../../case/Hwp5/BlogForm_Recipe.hwp", 1, 1)]
12 | [InlineData(@"../../../../../case/Hwp5/BookReview.hwp", 2, 1)]
13 | [InlineData(@"../../../../../case/Hwp5/calendar_monthly.hwp", 1, 1)]
14 | [InlineData(@"../../../../../case/Hwp5/calendar_year.hwp", 1, 1)]
15 | [InlineData(@"../../../../../case/Hwp5/classical_literature.hwp", 1, 1)]
16 | [InlineData(@"../../../../../case/Hwp5/english.hwp", 1, 1)]
17 | [InlineData(@"../../../../../case/Hwp5/Hyper(hwp2010).hwp", 1, 1)]
18 | [InlineData(@"../../../../../case/Hwp5/interview.hwp", 2, 1)]
19 | [InlineData(@"../../../../../case/Hwp5/KTX.hwp", 1, 1)]
20 | [InlineData(@"../../../../../case/Hwp5/NewYear_s_Day.hwp", 1, 1)]
21 | [InlineData(@"../../../../../case/Hwp5/request.hwp", 1, 1)]
22 | [InlineData(@"../../../../../case/Hwp5/shortcut.hwp", 1, 1)]
23 | [InlineData(@"../../../../../case/Hwp5/sungeo.hwp", 13, 1)]
24 | [InlineData(@"../../../../../case/Hwp5/Textmail.hwp", 1, 1)]
25 | [InlineData(@"../../../../../case/Hwp5/treatise sample.hwp", 1, 1)]
26 | [InlineData(@"../../../../../case/Hwp5/Worldcup_FIFA2010_32.hwp", 1, 1)]
27 | [InlineData(@"../../../../../case/Hwp5/multisection.hwp", 3, 1)]
28 | public void DocumentProperty_NormalHwp5Document(string filename, ushort expectedSectionCount, ushort expectedStartPageNumber)
29 | {
30 | var document = new Document(filename);
31 |
32 | Assert.Equal(expectedSectionCount, (ushort) document.DocumentInformation.DocumentProperty.SectionCount);
33 | Assert.Equal(expectedStartPageNumber, (ushort) document.DocumentInformation.DocumentProperty.StartPageNumber);
34 | }
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/test/HwpSharp.Tests/Hwp5/DocumentTest.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.IO;
3 | using HwpSharp.Common;
4 | using HwpSharp.Hwp5;
5 | using Xunit;
6 |
7 | namespace HwpSharp.Tests.Hwp5
8 | {
9 | public class DocumentTest
10 | {
11 | [Theory]
12 | [InlineData(@"../../../../../case/CompoundFile.xls", typeof(HwpFileFormatException), "Specified document does not have a FileHeader field.")]
13 | [InlineData(@"../../../../../case/Hwp3File.hwp", typeof(HwpFileFormatException), "Specified document is not a hwp 5 document format.")]
14 | [InlineData(@"../../../../../case/PdfFile.pdf", typeof(HwpFileFormatException), "Specified document is not a hwp 5 document format.")]
15 | [InlineData(null, typeof(ArgumentNullException), "Value cannot be null.")]
16 | [InlineData(@"Non-Exist Document", typeof(FileNotFoundException), "Could not find file")]
17 | public void ConstructorWithFileName_AbnormalHwp5Document(string filename, Type expectedException, string expectedMessage)
18 | {
19 | var ex = Record.Exception(() =>
20 | {
21 | new Document(filename);
22 | });
23 |
24 | Assert.IsType(expectedException, ex);
25 | Assert.StartsWith(expectedMessage, ex.Message);
26 | }
27 |
28 | [Theory]
29 | [InlineData(@"../../../../../case/CompoundFile.xls", typeof(HwpFileFormatException), "Specified document does not have a FileHeader field.")]
30 | [InlineData(@"../../../../../case/Hwp3File.hwp", typeof(HwpFileFormatException), "Specified document is not a hwp 5 document format.")]
31 | [InlineData(@"../../../../../case/PdfFile.pdf", typeof(HwpFileFormatException), "Specified document is not a hwp 5 document format.")]
32 | [InlineData(null, typeof(ArgumentNullException), "Value cannot be null.")]
33 | public void ConstructorWithStream_AbnormalHwp5Document(string filename, Type expectedException, string expectedMessage)
34 | {
35 | var ex = Record.Exception(() =>
36 | {
37 | var stream = filename != null ? new FileStream(filename, FileMode.Open, FileAccess.Read, FileShare.ReadWrite) : null;
38 | new Document(stream);
39 | });
40 |
41 | Assert.IsType(expectedException, ex);
42 | Assert.StartsWith(expectedMessage, ex.Message);
43 | }
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/test/HwpSharp.Tests/Hwp5/FileHeaderTest.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.CodeDom;
3 | using System.Collections.Generic;
4 | using System.Linq;
5 | using System.Linq.Expressions;
6 | using System.Threading.Tasks;
7 | using HwpSharp.Common;
8 | using HwpSharp.Hwp5;
9 | using Xunit;
10 |
11 | namespace HwpSharp.Tests.Hwp5
12 | {
13 | public class FileHeaderTest
14 | {
15 | [Theory]
16 | [InlineData(@"../../../../../case/Hwp5/BlogForm_BookReview.hwp", "5.0.3.0")]
17 | [InlineData(@"../../../../../case/Hwp5/BlogForm_MovieReview.hwp", "5.0.3.0")]
18 | [InlineData(@"../../../../../case/Hwp5/BlogForm_Recipe.hwp", "5.0.3.0")]
19 | [InlineData(@"../../../../../case/Hwp5/BookReview.hwp", "5.0.3.0")]
20 | [InlineData(@"../../../../../case/Hwp5/calendar_monthly.hwp", "5.0.3.0")]
21 | [InlineData(@"../../../../../case/Hwp5/calendar_year.hwp", "5.0.3.0")]
22 | [InlineData(@"../../../../../case/Hwp5/classical_literature.hwp", "5.0.3.0")]
23 | [InlineData(@"../../../../../case/Hwp5/english.hwp", "5.0.3.2")]
24 | [InlineData(@"../../../../../case/Hwp5/Hyper(hwp2010).hwp", "5.0.3.3")]
25 | [InlineData(@"../../../../../case/Hwp5/interview.hwp", "5.0.3.0")]
26 | [InlineData(@"../../../../../case/Hwp5/KTX.hwp", "5.0.3.0")]
27 | [InlineData(@"../../../../../case/Hwp5/NewYear_s_Day.hwp", "5.0.3.2")]
28 | [InlineData(@"../../../../../case/Hwp5/request.hwp", "5.0.3.2")]
29 | [InlineData(@"../../../../../case/Hwp5/shortcut.hwp", "5.0.3.0")]
30 | [InlineData(@"../../../../../case/Hwp5/sungeo.hwp", "5.0.3.0")]
31 | [InlineData(@"../../../../../case/Hwp5/Textmail.hwp", "5.0.3.0")]
32 | [InlineData(@"../../../../../case/Hwp5/treatise sample.hwp", "5.0.3.0")]
33 | [InlineData(@"../../../../../case/Hwp5/Worldcup_FIFA2010_32.hwp", "5.0.3.0")]
34 | public void Version_NormalHwp5Document(string filename, string expected)
35 | {
36 | var document = new Document(filename);
37 |
38 | Assert.Equal(expected, document.FileHeader.FileVersion.ToString());
39 | }
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/test/HwpSharp.Tests/HwpSharp.Tests.xproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | 14.0
5 | $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)
6 |
7 |
8 |
9 | 07196994-8fef-417a-9144-05135aa6497a
10 | HwpSharp.Tests
11 | ..\..\artifacts\obj\$(MSBuildProjectName)
12 | .\bin\
13 |
14 |
15 | HwpSharp.Tests
16 |
17 |
18 | 2.0
19 |
20 |
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/test/HwpSharp.Tests/project.json:
--------------------------------------------------------------------------------
1 | {
2 | "authors": [ "Yoon SeungYong" ],
3 | "testRunner": "xunit",
4 | "dependencies": {
5 | "HwpSharp": "1.0.0-*",
6 | "xunit": "2.2.0-beta2-build3300",
7 | "dotnet-test-xunit": "2.2.0-preview2-build1029"
8 | },
9 | "description": "",
10 | "frameworks": {
11 | "net451": {
12 | "dependencies": {
13 | "Microsoft.NETCore.Platforms": "1.0.1"
14 | }
15 | }
16 | },
17 | "version": "1.0.0-*"
18 | }
--------------------------------------------------------------------------------
/test/case/CompoundFile.xls:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/forcom/HwpSharp/c3b617ec53e0a9344c183d19b0dd351ee0fca215/test/case/CompoundFile.xls
--------------------------------------------------------------------------------
/test/case/Hwp3File.hwp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/forcom/HwpSharp/c3b617ec53e0a9344c183d19b0dd351ee0fca215/test/case/Hwp3File.hwp
--------------------------------------------------------------------------------
/test/case/Hwp5/BlogForm_BookReview.hwp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/forcom/HwpSharp/c3b617ec53e0a9344c183d19b0dd351ee0fca215/test/case/Hwp5/BlogForm_BookReview.hwp
--------------------------------------------------------------------------------
/test/case/Hwp5/BlogForm_MovieReview.hwp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/forcom/HwpSharp/c3b617ec53e0a9344c183d19b0dd351ee0fca215/test/case/Hwp5/BlogForm_MovieReview.hwp
--------------------------------------------------------------------------------
/test/case/Hwp5/BlogForm_Recipe.hwp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/forcom/HwpSharp/c3b617ec53e0a9344c183d19b0dd351ee0fca215/test/case/Hwp5/BlogForm_Recipe.hwp
--------------------------------------------------------------------------------
/test/case/Hwp5/BookReview.hwp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/forcom/HwpSharp/c3b617ec53e0a9344c183d19b0dd351ee0fca215/test/case/Hwp5/BookReview.hwp
--------------------------------------------------------------------------------
/test/case/Hwp5/Hyper(hwp2010).hwp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/forcom/HwpSharp/c3b617ec53e0a9344c183d19b0dd351ee0fca215/test/case/Hwp5/Hyper(hwp2010).hwp
--------------------------------------------------------------------------------
/test/case/Hwp5/KTX.hwp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/forcom/HwpSharp/c3b617ec53e0a9344c183d19b0dd351ee0fca215/test/case/Hwp5/KTX.hwp
--------------------------------------------------------------------------------
/test/case/Hwp5/NewYear_s_Day.hwp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/forcom/HwpSharp/c3b617ec53e0a9344c183d19b0dd351ee0fca215/test/case/Hwp5/NewYear_s_Day.hwp
--------------------------------------------------------------------------------
/test/case/Hwp5/Textmail.hwp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/forcom/HwpSharp/c3b617ec53e0a9344c183d19b0dd351ee0fca215/test/case/Hwp5/Textmail.hwp
--------------------------------------------------------------------------------
/test/case/Hwp5/Worldcup_FIFA2010_32.hwp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/forcom/HwpSharp/c3b617ec53e0a9344c183d19b0dd351ee0fca215/test/case/Hwp5/Worldcup_FIFA2010_32.hwp
--------------------------------------------------------------------------------
/test/case/Hwp5/borderfill.hwp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/forcom/HwpSharp/c3b617ec53e0a9344c183d19b0dd351ee0fca215/test/case/Hwp5/borderfill.hwp
--------------------------------------------------------------------------------
/test/case/Hwp5/calendar_monthly.hwp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/forcom/HwpSharp/c3b617ec53e0a9344c183d19b0dd351ee0fca215/test/case/Hwp5/calendar_monthly.hwp
--------------------------------------------------------------------------------
/test/case/Hwp5/calendar_year.hwp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/forcom/HwpSharp/c3b617ec53e0a9344c183d19b0dd351ee0fca215/test/case/Hwp5/calendar_year.hwp
--------------------------------------------------------------------------------
/test/case/Hwp5/classical_literature.hwp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/forcom/HwpSharp/c3b617ec53e0a9344c183d19b0dd351ee0fca215/test/case/Hwp5/classical_literature.hwp
--------------------------------------------------------------------------------
/test/case/Hwp5/distribution.hwp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/forcom/HwpSharp/c3b617ec53e0a9344c183d19b0dd351ee0fca215/test/case/Hwp5/distribution.hwp
--------------------------------------------------------------------------------
/test/case/Hwp5/english.hwp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/forcom/HwpSharp/c3b617ec53e0a9344c183d19b0dd351ee0fca215/test/case/Hwp5/english.hwp
--------------------------------------------------------------------------------
/test/case/Hwp5/interview.hwp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/forcom/HwpSharp/c3b617ec53e0a9344c183d19b0dd351ee0fca215/test/case/Hwp5/interview.hwp
--------------------------------------------------------------------------------
/test/case/Hwp5/multisection.hwp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/forcom/HwpSharp/c3b617ec53e0a9344c183d19b0dd351ee0fca215/test/case/Hwp5/multisection.hwp
--------------------------------------------------------------------------------
/test/case/Hwp5/request.hwp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/forcom/HwpSharp/c3b617ec53e0a9344c183d19b0dd351ee0fca215/test/case/Hwp5/request.hwp
--------------------------------------------------------------------------------
/test/case/Hwp5/shortcut.hwp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/forcom/HwpSharp/c3b617ec53e0a9344c183d19b0dd351ee0fca215/test/case/Hwp5/shortcut.hwp
--------------------------------------------------------------------------------
/test/case/Hwp5/sungeo.hwp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/forcom/HwpSharp/c3b617ec53e0a9344c183d19b0dd351ee0fca215/test/case/Hwp5/sungeo.hwp
--------------------------------------------------------------------------------
/test/case/Hwp5/treatise sample.hwp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/forcom/HwpSharp/c3b617ec53e0a9344c183d19b0dd351ee0fca215/test/case/Hwp5/treatise sample.hwp
--------------------------------------------------------------------------------
/test/case/PdfFile.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/forcom/HwpSharp/c3b617ec53e0a9344c183d19b0dd351ee0fca215/test/case/PdfFile.pdf
--------------------------------------------------------------------------------