├── .gitignore ├── README.TXT ├── crvskkserv.sln └── crvskkserv ├── app.ico ├── crvskkserv.cpp ├── crvskkserv.h ├── crvskkserv.manifest ├── crvskkserv.rc ├── crvskkserv.vcxproj ├── crvskkserv.vcxproj.filters ├── eucjis2004.cpp ├── eucjis2004.h ├── eucjis2004table.cpp ├── eucjis2004table.h ├── eucjp.cpp ├── eucjp.h ├── eucjptable.cpp ├── eucjptable.h ├── pch.cpp ├── pch.h ├── picojson.h ├── resource.h ├── search_dictionary.cpp ├── search_google_cgiapi.cpp ├── search_skkserv.cpp ├── server.cpp ├── utf8.cpp └── utf8.h /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | ## 4 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore 5 | 6 | # User-specific files 7 | *.rsuser 8 | *.suo 9 | *.user 10 | *.userosscache 11 | *.sln.docstates 12 | 13 | # User-specific files (MonoDevelop/Xamarin Studio) 14 | *.userprefs 15 | 16 | # Mono auto generated files 17 | mono_crash.* 18 | 19 | # Build results 20 | [Dd]ebug/ 21 | [Dd]ebugPublic/ 22 | [Rr]elease/ 23 | [Rr]eleases/ 24 | [Bb]uild/ 25 | x64/ 26 | x86/ 27 | [Ww][Ii][Nn]32/ 28 | [Aa][Rr][Mm]/ 29 | [Aa][Rr][Mm]64/ 30 | [Aa][Rr][Mm]64[Ee][Cc]/ 31 | bld/ 32 | [Bb]in/ 33 | [Oo]bj/ 34 | [Oo]ut/ 35 | [Ll]og/ 36 | [Ll]ogs/ 37 | 38 | # Visual Studio 2015/2017 cache/options directory 39 | .vs/ 40 | # Uncomment if you have tasks that create the project's static files in wwwroot 41 | #wwwroot/ 42 | 43 | # Visual Studio 2017 auto generated files 44 | Generated\ Files/ 45 | 46 | # MSTest test Results 47 | [Tt]est[Rr]esult*/ 48 | [Bb]uild[Ll]og.* 49 | 50 | # NUnit 51 | *.VisualState.xml 52 | TestResult.xml 53 | nunit-*.xml 54 | 55 | # Build Results of an ATL Project 56 | [Dd]ebugPS/ 57 | [Rr]eleasePS/ 58 | dlldata.c 59 | 60 | # Benchmark Results 61 | BenchmarkDotNet.Artifacts/ 62 | 63 | # .NET Core 64 | project.lock.json 65 | project.fragment.lock.json 66 | artifacts/ 67 | 68 | # ASP.NET Scaffolding 69 | ScaffoldingReadMe.txt 70 | 71 | # StyleCop 72 | StyleCopReport.xml 73 | 74 | # Files built by Visual Studio 75 | *_i.c 76 | *_p.c 77 | *_h.h 78 | *.ilk 79 | *.meta 80 | *.obj 81 | *.iobj 82 | *.pch 83 | *.pdb 84 | *.ipdb 85 | *.pgc 86 | *.pgd 87 | *.rsp 88 | *.sbr 89 | *.tlb 90 | *.tli 91 | *.tlh 92 | *.tmp 93 | *.tmp_proj 94 | *_wpftmp.csproj 95 | *.log 96 | *.vspscc 97 | *.vssscc 98 | .builds 99 | *.pidb 100 | *.svclog 101 | *.scc 102 | 103 | # Chutzpah Test files 104 | _Chutzpah* 105 | 106 | # Visual C++ cache files 107 | ipch/ 108 | *.aps 109 | *.ncb 110 | *.opendb 111 | *.opensdf 112 | *.sdf 113 | *.cachefile 114 | *.VC.db 115 | *.VC.VC.opendb 116 | 117 | # Visual Studio profiler 118 | *.psess 119 | *.vsp 120 | *.vspx 121 | *.sap 122 | 123 | # Visual Studio Trace Files 124 | *.e2e 125 | 126 | # TFS 2012 Local Workspace 127 | $tf/ 128 | 129 | # Guidance Automation Toolkit 130 | *.gpState 131 | 132 | # ReSharper is a .NET coding add-in 133 | _ReSharper*/ 134 | *.[Rr]e[Ss]harper 135 | *.DotSettings.user 136 | 137 | # TeamCity is a build add-in 138 | _TeamCity* 139 | 140 | # DotCover is a Code Coverage Tool 141 | *.dotCover 142 | 143 | # AxoCover is a Code Coverage Tool 144 | .axoCover/* 145 | !.axoCover/settings.json 146 | 147 | # Coverlet is a free, cross platform Code Coverage Tool 148 | coverage*.json 149 | coverage*.xml 150 | coverage*.info 151 | 152 | # Visual Studio code coverage results 153 | *.coverage 154 | *.coveragexml 155 | 156 | # NCrunch 157 | _NCrunch_* 158 | .*crunch*.local.xml 159 | nCrunchTemp_* 160 | 161 | # MightyMoose 162 | *.mm.* 163 | AutoTest.Net/ 164 | 165 | # Web workbench (sass) 166 | .sass-cache/ 167 | 168 | # Installshield output folder 169 | [Ee]xpress/ 170 | 171 | # DocProject is a documentation generator add-in 172 | DocProject/buildhelp/ 173 | DocProject/Help/*.HxT 174 | DocProject/Help/*.HxC 175 | DocProject/Help/*.hhc 176 | DocProject/Help/*.hhk 177 | DocProject/Help/*.hhp 178 | DocProject/Help/Html2 179 | DocProject/Help/html 180 | 181 | # Click-Once directory 182 | publish/ 183 | 184 | # Publish Web Output 185 | *.[Pp]ublish.xml 186 | *.azurePubxml 187 | # Note: Comment the next line if you want to checkin your web deploy settings, 188 | # but database connection strings (with potential passwords) will be unencrypted 189 | *.pubxml 190 | *.publishproj 191 | 192 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 193 | # checkin your Azure Web App publish settings, but sensitive information contained 194 | # in these scripts will be unencrypted 195 | PublishScripts/ 196 | 197 | # NuGet Packages 198 | *.nupkg 199 | # NuGet Symbol Packages 200 | *.snupkg 201 | # The packages folder can be ignored because of Package Restore 202 | **/[Pp]ackages/* 203 | # except build/, which is used as an MSBuild target. 204 | !**/[Pp]ackages/build/ 205 | # Uncomment if necessary however generally it will be regenerated when needed 206 | #!**/[Pp]ackages/repositories.config 207 | # NuGet v3's project.json files produces more ignorable files 208 | *.nuget.props 209 | *.nuget.targets 210 | 211 | # Microsoft Azure Build Output 212 | csx/ 213 | *.build.csdef 214 | 215 | # Microsoft Azure Emulator 216 | ecf/ 217 | rcf/ 218 | 219 | # Windows Store app package directories and files 220 | AppPackages/ 221 | BundleArtifacts/ 222 | Package.StoreAssociation.xml 223 | _pkginfo.txt 224 | *.appx 225 | *.appxbundle 226 | *.appxupload 227 | 228 | # Visual Studio cache files 229 | # files ending in .cache can be ignored 230 | *.[Cc]ache 231 | # but keep track of directories ending in .cache 232 | !?*.[Cc]ache/ 233 | 234 | # Others 235 | ClientBin/ 236 | ~$* 237 | *~ 238 | *.dbmdl 239 | *.dbproj.schemaview 240 | *.jfm 241 | *.pfx 242 | *.publishsettings 243 | orleans.codegen.cs 244 | 245 | # Including strong name files can present a security risk 246 | # (https://github.com/github/gitignore/pull/2483#issue-259490424) 247 | #*.snk 248 | 249 | # Since there are multiple workflows, uncomment next line to ignore bower_components 250 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 251 | #bower_components/ 252 | 253 | # RIA/Silverlight projects 254 | Generated_Code/ 255 | 256 | # Backup & report files from converting an old project file 257 | # to a newer Visual Studio version. Backup files are not needed, 258 | # because we have git ;-) 259 | _UpgradeReport_Files/ 260 | Backup*/ 261 | UpgradeLog*.XML 262 | UpgradeLog*.htm 263 | ServiceFabricBackup/ 264 | *.rptproj.bak 265 | 266 | # SQL Server files 267 | *.mdf 268 | *.ldf 269 | *.ndf 270 | 271 | # Business Intelligence projects 272 | *.rdl.data 273 | *.bim.layout 274 | *.bim_*.settings 275 | *.rptproj.rsuser 276 | *- [Bb]ackup.rdl 277 | *- [Bb]ackup ([0-9]).rdl 278 | *- [Bb]ackup ([0-9][0-9]).rdl 279 | 280 | # Microsoft Fakes 281 | FakesAssemblies/ 282 | 283 | # GhostDoc plugin setting file 284 | *.GhostDoc.xml 285 | 286 | # Node.js Tools for Visual Studio 287 | .ntvs_analysis.dat 288 | node_modules/ 289 | 290 | # Visual Studio 6 build log 291 | *.plg 292 | 293 | # Visual Studio 6 workspace options file 294 | *.opt 295 | 296 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) 297 | *.vbw 298 | 299 | # Visual Studio LightSwitch build output 300 | **/*.HTMLClient/GeneratedArtifacts 301 | **/*.DesktopClient/GeneratedArtifacts 302 | **/*.DesktopClient/ModelManifest.xml 303 | **/*.Server/GeneratedArtifacts 304 | **/*.Server/ModelManifest.xml 305 | _Pvt_Extensions 306 | 307 | # Paket dependency manager 308 | .paket/paket.exe 309 | paket-files/ 310 | 311 | # FAKE - F# Make 312 | .fake/ 313 | 314 | # CodeRush personal settings 315 | .cr/personal 316 | 317 | # Python Tools for Visual Studio (PTVS) 318 | __pycache__/ 319 | *.pyc 320 | 321 | # Cake - Uncomment if you are using it 322 | # tools/** 323 | # !tools/packages.config 324 | 325 | # Tabs Studio 326 | *.tss 327 | 328 | # Telerik's JustMock configuration file 329 | *.jmconfig 330 | 331 | # BizTalk build output 332 | *.btp.cs 333 | *.btm.cs 334 | *.odx.cs 335 | *.xsd.cs 336 | 337 | # OpenCover UI analysis results 338 | OpenCover/ 339 | 340 | # Azure Stream Analytics local run output 341 | ASALocalRun/ 342 | 343 | # MSBuild Binary and Structured Log 344 | *.binlog 345 | 346 | # NVidia Nsight GPU debugger configuration file 347 | *.nvuser 348 | 349 | # MFractors (Xamarin productivity tool) working folder 350 | .mfractor/ 351 | 352 | # Local History for Visual Studio 353 | .localhistory/ 354 | 355 | # BeatPulse healthcheck temp database 356 | healthchecksdb 357 | 358 | # Backup folder for Package Reference Convert tool in Visual Studio 2017 359 | MigrationBackup/ 360 | 361 | # Ionide (cross platform F# VS Code tools) working folder 362 | .ionide/ 363 | 364 | # Fody - auto-generated XML schema 365 | FodyWeavers.xsd 366 | 367 | # Backup files 368 | *.BAK 369 | *.bak 370 | -------------------------------------------------------------------------------- /README.TXT: -------------------------------------------------------------------------------- 1 |  2 | ------------------------------------------------------------------------------- 3 | 4 | crvskkserv 2.5.6 5 | 6 | ------------------------------------------------------------------------------- 7 | 8 | SKK辞書サーバです。 9 | 10 | 適当な場所に置いて実行して下さい。 11 | 12 | タスクトレイのアイコンから設定ダイアログを開き、ポートと辞書を設定して下さい。 13 | 辞書の最大数は64個です。 14 | 15 | 辞書は、SKK辞書ファイル、SKK辞書サーバ、Google CGI API for Japanese Input に 16 | 対応しています。 17 | https://www.google.co.jp/ime/cgiapi.html 18 | 19 | 改行LFでEUC-JIS-2004やEUC-JP、UTF-8(BOMなし)等ASCIIと互換性のある文字コードの 20 | SKK辞書ファイルが使用できます。 21 | 22 | SKK辞書の文字コード変換は行っていないので、クライアント側のSKK辞書サーバ通信に 23 | 使用する文字コードとSKK辞書ファイルの文字コードを揃える必要があります。 24 | 25 | SKK辞書サーバ通信は、IPv4、IPv6に対応しています。 26 | 27 | Google CGI APIの「見出し語の検索除外条件」設定は、おそらく送りあり(と思われる) 28 | 見出し語を除外する正規表現がデフォルトとなっています。 29 | Visual C++ 2022 の正規表現で、文法はECMAScriptを使用しています。 30 | https://docs.microsoft.com/en-us/cpp/standard-library/regular-expressions-cpp?view=msvc-170 31 | 32 | Google CGI APIの設定でクライアントの文字コードをEUC-JIS-2004にしたとき、 33 | UTF-8からEUC-JIS-2004に変換できない文字を含む候補はEUC-JPにフォールバックされます。 34 | EUC-JPにも変換できないときは候補から除外されます。 35 | 36 | 37 | プロトコル 38 | 39 | "0" 40 | 41 | 切断 42 | 応答なし 43 | 44 | "1<見出し語> " 45 | 46 | 辞書検索 47 | 応答 : 検索結果 "1/<候補 1>/<候補 2>/ … /<候補 n>\n" 48 | または 検索結果なし "4\n" 49 | 50 | "2" 51 | 52 | バージョン番号取得 53 | 応答 : "crvskkserv/.. " 54 | (本家skkservでは、".. ") 55 | 56 | "3" 57 | 58 | ホスト名取得 59 | 応答 : "/:/ " 60 | (本家skkservでは、":: " または 61 | "::: … :: ") 62 | 63 | "4<見出し語> " 64 | 65 | サーバーコンプリーション 66 | 応答 : 検索結果なし "4\n" 67 | 68 | その他 69 | 70 | 応答なし 71 | 72 | 73 | ------------------------------------------------------------------------------- 74 | 75 | LICENSE 76 | 77 | ------------------------------------------------------------------------------- 78 | 79 | crvskkserv 80 | 81 | The MIT License 82 | 83 | Copyright (C) 2012-2022 SASAKI Nobuyuki 84 | 85 | Permission is hereby granted, free of charge, to any person obtaining a 86 | copy of this software and associated documentation files (the "Software"), 87 | to deal in the Software without restriction, including without limitation 88 | the rights to use, copy, modify, merge, publish, distribute, sublicense, 89 | and/or sell copies of the Software, and to permit persons to whom the 90 | Software is furnished to do so, subject to the following conditions: 91 | 92 | The above copyright notice and this permission notice shall be included in 93 | all copies or substantial portions of the Software. 94 | 95 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 96 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 97 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 98 | THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 99 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 100 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 101 | DEALINGS IN THE SOFTWARE. 102 | 103 | ------------------------------------------------------------------------------- 104 | 105 | EUC-JIS-2004 (JIS X 0213:2004 Appendix 3) vs Unicode mapping table 106 | 107 | Date: 3 May 2009 108 | License: 109 | Copyright (C) 2001 earthian@tama.or.jp, All Rights Reserved. 110 | Copyright (C) 2001 I'O, All Rights Reserved. 111 | Copyright (C) 2006, 2009 Project X0213, All Rights Reserved. 112 | You can use, modify, distribute this table freely. 113 | 114 | ------------------------------------------------------------------------------- 115 | 116 | JIS X 0208 (1990) to Unicode 117 | © 2015 Unicode®, Inc. 118 | 119 | JIS X 0212 (1990) to Unicode 120 | © 2015 Unicode®, Inc. 121 | 122 | COPYRIGHT AND PERMISSION NOTICE 123 | 124 | Copyright © 1991-2021 Unicode, Inc. All rights reserved. 125 | Distributed under the Terms of Use in https://www.unicode.org/copyright.html. 126 | 127 | Permission is hereby granted, free of charge, to any person obtaining 128 | a copy of the Unicode data files and any associated documentation 129 | (the "Data Files") or Unicode software and any associated documentation 130 | (the "Software") to deal in the Data Files or Software 131 | without restriction, including without limitation the rights to use, 132 | copy, modify, merge, publish, distribute, and/or sell copies of 133 | the Data Files or Software, and to permit persons to whom the Data Files 134 | or Software are furnished to do so, provided that either 135 | (a) this copyright and permission notice appear with all copies 136 | of the Data Files or Software, or 137 | (b) this copyright and permission notice appear in associated 138 | Documentation. 139 | 140 | THE DATA FILES AND SOFTWARE ARE PROVIDED "AS IS", WITHOUT WARRANTY OF 141 | ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE 142 | WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 143 | NONINFRINGEMENT OF THIRD PARTY RIGHTS. 144 | IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN THIS 145 | NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL 146 | DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, 147 | DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 148 | TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 149 | PERFORMANCE OF THE DATA FILES OR SOFTWARE. 150 | 151 | Except as contained in this notice, the name of a copyright holder 152 | shall not be used in advertising or otherwise to promote the sale, 153 | use or other dealings in these Data Files or Software without prior 154 | written authorization of the copyright holder. 155 | 156 | ------------------------------------------------------------------------------- 157 | 158 | PicoJSON 159 | 160 | The BSD 2-Clause License 161 | 162 | Copyright 2009-2010 Cybozu Labs, Inc. 163 | Copyright 2011-2014 Kazuho Oku 164 | All rights reserved. 165 | 166 | Redistribution and use in source and binary forms, with or without 167 | modification, are permitted provided that the following conditions are met: 168 | 169 | 1. Redistributions of source code must retain the above copyright notice, 170 | this list of conditions and the following disclaimer. 171 | 172 | 2. Redistributions in binary form must reproduce the above copyright notice, 173 | this list of conditions and the following disclaimer in the documentation 174 | and/or other materials provided with the distribution. 175 | 176 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 177 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 178 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 179 | ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 180 | LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 181 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 182 | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 183 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 184 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 185 | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 186 | POSSIBILITY OF SUCH DAMAGE. 187 | 188 | ------------------------------------------------------------------------------- 189 | -------------------------------------------------------------------------------- /crvskkserv.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 17 4 | VisualStudioVersion = 17.3.32804.467 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "crvskkserv", "crvskkserv\crvskkserv.vcxproj", "{EE56E58B-C54E-425C-A0AF-292B4653B1F0}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|x64 = Debug|x64 11 | Debug|x86 = Debug|x86 12 | Release|x64 = Release|x64 13 | Release|x86 = Release|x86 14 | EndGlobalSection 15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 16 | {EE56E58B-C54E-425C-A0AF-292B4653B1F0}.Debug|x64.ActiveCfg = Debug|x64 17 | {EE56E58B-C54E-425C-A0AF-292B4653B1F0}.Debug|x64.Build.0 = Debug|x64 18 | {EE56E58B-C54E-425C-A0AF-292B4653B1F0}.Debug|x86.ActiveCfg = Debug|Win32 19 | {EE56E58B-C54E-425C-A0AF-292B4653B1F0}.Debug|x86.Build.0 = Debug|Win32 20 | {EE56E58B-C54E-425C-A0AF-292B4653B1F0}.Release|x64.ActiveCfg = Release|x64 21 | {EE56E58B-C54E-425C-A0AF-292B4653B1F0}.Release|x64.Build.0 = Release|x64 22 | {EE56E58B-C54E-425C-A0AF-292B4653B1F0}.Release|x86.ActiveCfg = Release|Win32 23 | {EE56E58B-C54E-425C-A0AF-292B4653B1F0}.Release|x86.Build.0 = Release|Win32 24 | EndGlobalSection 25 | GlobalSection(SolutionProperties) = preSolution 26 | HideSolutionNode = FALSE 27 | EndGlobalSection 28 | GlobalSection(ExtensibilityGlobals) = postSolution 29 | SolutionGuid = {77834FB2-D0C0-411E-88B9-0EF4B38BE404} 30 | EndGlobalSection 31 | EndGlobal 32 | -------------------------------------------------------------------------------- /crvskkserv/app.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nathancorvussolis/crvskkserv/236345406c9a96f58d44840802dab57295e5a1d2/crvskkserv/app.ico -------------------------------------------------------------------------------- /crvskkserv/crvskkserv.cpp: -------------------------------------------------------------------------------- 1 |  2 | #include "crvskkserv.h" 3 | #include "resource.h" 4 | 5 | #define MAX_DICNUM 64 6 | LPCWSTR title = APP_TITLE; 7 | LPCSTR resver = RES_VER; 8 | HINSTANCE hInst; 9 | NOTIFYICONDATAW nid; 10 | BOOL bDlgShowed = FALSE; 11 | WCHAR ini[MAX_PATH]; 12 | WCHAR serv_port[6]; 13 | BOOL serv_loopback = TRUE; 14 | WCHAR googlecgiapi_url_prefix[INTERNET_MAX_URL_LENGTH]; 15 | WCHAR googlecgiapi_url_suffix[INTERNET_MAX_URL_LENGTH]; 16 | SERVINFO servinfo[FD_SETSIZE]; 17 | HANDLE hThread[FD_SETSIZE]; 18 | int servinfonum; 19 | VDICINFO vdicinfo; 20 | LPCWSTR inikey_port = L"port"; 21 | LPCWSTR inikey_loopback = L"loopback"; 22 | LPCWSTR inikey_googlecgiapi_url_prefix = L"googlecgiapi_url_prefix"; 23 | LPCWSTR inikey_googlecgiapi_url_suffix = L"googlecgiapi_url_suffix"; 24 | LPCWSTR inikey_dic = L"dic-"; 25 | CONST WCHAR inival_svr_sep = L'/'; 26 | LPCWSTR inival_def_googlecgiapi_url_prefix = L"https://www.google.com/transliterate?langpair=ja-Hira|ja&text="; 27 | LPCWSTR inival_def_googlecgiapi_url_suffix = L","; 28 | LPCWSTR inival_def_port = L"1178"; 29 | LPCWSTR inival_def_timeout = L"1000"; 30 | LPCWSTR inival_def_googlecgiapi_filter = L"[^A-Za-z0-9]+[a-z]"; 31 | LPCWSTR inival_def_googlecgiapi_annotation = L"G"; 32 | LPCWSTR inival_googlecgiapi_encoding_euc = L"euc"; 33 | LPCWSTR inival_googlecgiapi_encoding_utf8 = L"utf-8"; 34 | LPCSTR EntriesAri = ";; okuri-ari entries.\n"; 35 | LPCSTR EntriesNasi = ";; okuri-nasi entries.\n"; 36 | LPCWSTR modeRB = L"rb"; 37 | LPCWSTR modeWB = L"wb"; 38 | 39 | void GetIniFileName(LPWSTR ini, size_t len); 40 | LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); 41 | 42 | int APIENTRY wWinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, _In_ LPWSTR lpCmdLine, _In_ int nCmdShow) 43 | { 44 | UNREFERENCED_PARAMETER(hPrevInstance); 45 | UNREFERENCED_PARAMETER(lpCmdLine); 46 | 47 | MSG msg; 48 | WNDCLASSEXW wcex = {}; 49 | HWND hWnd; 50 | WSADATA wsaData; 51 | int wsa = -1; 52 | INITCOMMONCONTROLSEX icex = {}; 53 | 54 | _wsetlocale(LC_ALL, L"ja-JP"); 55 | 56 | icex.dwSize = sizeof(INITCOMMONCONTROLSEX); 57 | icex.dwICC = ICC_LISTVIEW_CLASSES; 58 | InitCommonControlsEx(&icex); 59 | 60 | wsa = WSAStartup(WINSOCK_VERSION, &wsaData); 61 | switch (wsa) 62 | { 63 | case 0: 64 | //success 65 | break; 66 | case WSASYSNOTREADY: 67 | case WSAVERNOTSUPPORTED: 68 | case WSAEINPROGRESS: 69 | case WSAEPROCLIM: 70 | case WSAEFAULT: 71 | default: 72 | //error 73 | break; 74 | } 75 | 76 | GetIniFileName(ini, _countof(ini)); 77 | 78 | hInst = hInstance; 79 | 80 | wcex.cbSize = sizeof(WNDCLASSEX); 81 | 82 | wcex.style = CS_HREDRAW | CS_VREDRAW; 83 | wcex.lpfnWndProc = WndProc; 84 | wcex.cbClsExtra = 0; 85 | wcex.cbWndExtra = 0; 86 | wcex.hInstance = hInstance; 87 | wcex.hIcon = LoadIconW(hInstance, MAKEINTRESOURCE(IDI_CRVSKKSERV)); 88 | wcex.hCursor = LoadCursorW(nullptr, IDC_ARROW); 89 | wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1); 90 | wcex.lpszMenuName = nullptr; 91 | wcex.lpszClassName = title; 92 | wcex.hIconSm = LoadIconW(wcex.hInstance, MAKEINTRESOURCE(IDI_CRVSKKSERV)); 93 | 94 | RegisterClassExW(&wcex); 95 | 96 | hWnd = CreateWindowW(title, title, WS_OVERLAPPEDWINDOW, 0, 0, 320, 200, nullptr, nullptr, hInstance, nullptr); 97 | 98 | if (!hWnd) 99 | { 100 | return 0; 101 | } 102 | 103 | //ShowWindow(hWnd, nCmdShow); 104 | //UpdateWindow(hWnd); 105 | 106 | while (GetMessageW(&msg, nullptr, 0, 0)) 107 | { 108 | TranslateMessage(&msg); 109 | DispatchMessageW(&msg); 110 | } 111 | 112 | WSACleanup(); 113 | 114 | return (int)msg.wParam; 115 | } 116 | 117 | void GetIniFileName(LPWSTR inifile, size_t len) 118 | { 119 | WCHAR drive[_MAX_DRIVE] = {}; 120 | WCHAR dir[_MAX_DIR] = {}; 121 | WCHAR fname[_MAX_FNAME] = {}; 122 | WCHAR ext[_MAX_EXT] = {}; 123 | 124 | GetModuleFileNameW(nullptr, inifile, (DWORD)len); 125 | _wsplitpath_s(inifile, drive, dir, fname, ext); 126 | _wmakepath_s(inifile, len, drive, dir, fname, L"ini"); 127 | } 128 | 129 | void AddTaskbarIcon(HWND hWnd) 130 | { 131 | ZeroMemory(&nid, sizeof(nid)); 132 | nid.cbSize = sizeof(nid); 133 | nid.hWnd = hWnd; 134 | nid.hIcon = LoadIconW(hInst, MAKEINTRESOURCE(IDI_CRVSKKSERV)); 135 | nid.uFlags = NIF_ICON | NIF_TIP | NIF_MESSAGE; 136 | nid.uCallbackMessage = WM_TASKBARICON_0; 137 | wcscpy_s(nid.szTip, title); 138 | if (!Shell_NotifyIconW(NIM_ADD, &nid)) 139 | { 140 | Sleep(100); 141 | } 142 | } 143 | 144 | void init_server() 145 | { 146 | int i; 147 | DICINFO dicinfo; 148 | WCHAR key[8]; 149 | WCHAR dicpath[MAX_PATH]; 150 | 151 | GetPrivateProfileStringW(title, inikey_googlecgiapi_url_prefix, inival_def_googlecgiapi_url_prefix, 152 | googlecgiapi_url_prefix, _countof(googlecgiapi_url_prefix), ini); 153 | GetPrivateProfileStringW(title, inikey_googlecgiapi_url_suffix, inival_def_googlecgiapi_url_suffix, 154 | googlecgiapi_url_suffix, _countof(googlecgiapi_url_suffix), ini); 155 | 156 | GetPrivateProfileStringW(title, inikey_port, L"", serv_port, _countof(serv_port), ini); 157 | serv_loopback = GetPrivateProfileIntW(title, inikey_loopback, 1, ini); 158 | 159 | for (i = 1; i <= MAX_DICNUM; i++) 160 | { 161 | _snwprintf_s(key, _TRUNCATE, L"%s%d", inikey_dic, i); 162 | GetPrivateProfileStringW(title, key, L"", dicpath, _countof(dicpath), ini); 163 | if (dicpath[0] != L'\0') 164 | { 165 | dicinfo.path = dicpath; 166 | dicinfo.pos.clear(); 167 | dicinfo.pos.shrink_to_fit(); 168 | dicinfo.sock = INVALID_SOCKET; 169 | if (wcsncmp(dicpath, INIVAL_SKKSERV, wcslen(INIVAL_SKKSERV)) == 0) 170 | { 171 | connect_skkserv(dicinfo); 172 | } 173 | else if (wcsncmp(dicpath, INIVAL_GOOGLECGIAPI, wcslen(INIVAL_GOOGLECGIAPI)) == 0) 174 | { 175 | } 176 | else 177 | { 178 | init_search_dictionary(dicinfo); 179 | } 180 | vdicinfo.push_back(dicinfo); 181 | } 182 | } 183 | 184 | if (serv_port[0] == L'\0') 185 | { 186 | return; 187 | } 188 | 189 | for (i = 0; i < FD_SETSIZE; i++) 190 | { 191 | servinfo[i].live = FALSE; 192 | servinfo[i].sock = INVALID_SOCKET; 193 | } 194 | 195 | servinfonum = make_serv_sock(servinfo, _countof(servinfo)); 196 | 197 | for (i = 0; i < servinfonum; i++) 198 | { 199 | _beginthread(listen_thread, 0, &servinfo[i]); 200 | } 201 | } 202 | 203 | void term_server() 204 | { 205 | int i; 206 | VDICINFO::iterator vdicinfo_itr; 207 | 208 | for (i = 0; i < servinfonum; i++) 209 | { 210 | disconnect(servinfo[i].sock); 211 | } 212 | for (i = 0; i < servinfonum; i++) 213 | { 214 | while (servinfo[i].live) 215 | { 216 | Sleep(10); 217 | } 218 | } 219 | 220 | for (vdicinfo_itr = vdicinfo.begin(); vdicinfo_itr != vdicinfo.end(); vdicinfo_itr++) 221 | { 222 | disconnect(vdicinfo_itr->sock); 223 | } 224 | vdicinfo.clear(); 225 | } 226 | 227 | INT_PTR CALLBACK DlgProcSKKServ(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) 228 | { 229 | static HWND hPDlg; 230 | HWND hWndListView; 231 | LVITEMW item = {}; 232 | int index, count; 233 | WCHAR path[MAX_PATH]; 234 | WCHAR host[256]; 235 | WCHAR port[6]; 236 | WCHAR timeout[8]; 237 | 238 | switch (message) 239 | { 240 | case WM_INITDIALOG: 241 | hPDlg = (HWND)lParam; 242 | SetForegroundWindow(hDlg); 243 | 244 | SetDlgItemTextW(hDlg, IDC_EDIT_SKKSRV_PORT, inival_def_port); 245 | SetDlgItemTextW(hDlg, IDC_EDIT_SKKSRV_TIMEOUT, inival_def_timeout); 246 | return (INT_PTR)TRUE; 247 | 248 | case WM_COMMAND: 249 | switch (LOWORD(wParam)) 250 | { 251 | case IDOK: 252 | GetDlgItemTextW(hDlg, IDC_EDIT_SKKSRV_HOST, host, _countof(host)); 253 | GetDlgItemTextW(hDlg, IDC_EDIT_SKKSRV_PORT, port, _countof(port)); 254 | GetDlgItemTextW(hDlg, IDC_EDIT_SKKSRV_TIMEOUT, timeout, _countof(timeout)); 255 | _snwprintf_s(path, _TRUNCATE, L"%s%c%s%c%s%c%s%c", INIVAL_SKKSERV, 256 | INIVAL_SVR_SEP, host, INIVAL_SVR_SEP, port, INIVAL_SVR_SEP, timeout, INIVAL_SVR_SEP); 257 | 258 | hWndListView = GetDlgItem(hPDlg, IDC_LIST_SKK_DIC); 259 | index = ListView_GetNextItem(hWndListView, -1, LVNI_SELECTED); 260 | count = ListView_GetItemCount(hWndListView); 261 | if (index == -1) 262 | { 263 | index = count; 264 | } 265 | else 266 | { 267 | ++index; 268 | } 269 | item.mask = LVIF_TEXT; 270 | item.pszText = path; 271 | item.iItem = index; 272 | item.iSubItem = 0; 273 | ListView_InsertItem(hWndListView, &item); 274 | ListView_SetItemState(hWndListView, index, LVIS_FOCUSED | LVIS_SELECTED, 0x000F); 275 | ListView_SetColumnWidth(hWndListView, 0, LVSCW_AUTOSIZE); 276 | ListView_EnsureVisible(hWndListView, index, FALSE); 277 | 278 | if (ListView_GetItemCount(hWndListView) >= MAX_DICNUM) 279 | { 280 | EnableWindow(GetDlgItem(hPDlg, IDC_BUTTON_SKK_DIC_ADD), FALSE); 281 | EnableWindow(GetDlgItem(hPDlg, IDC_BUTTON_SKKSERV_ADD), FALSE); 282 | EnableWindow(GetDlgItem(hPDlg, IDC_BUTTON_GOOGLECGIAPI_ADD), FALSE); 283 | } 284 | 285 | EndDialog(hDlg, 0); 286 | break; 287 | 288 | case IDCANCEL: 289 | EndDialog(hDlg, 0); 290 | break; 291 | 292 | default: 293 | break; 294 | } 295 | return (INT_PTR)TRUE; 296 | 297 | case WM_CLOSE: 298 | case WM_DESTROY: 299 | EndDialog(hDlg, 0); 300 | return (INT_PTR)TRUE; 301 | 302 | default: 303 | break; 304 | } 305 | 306 | return (INT_PTR)FALSE; 307 | } 308 | 309 | INT_PTR CALLBACK DlgProcGoogleCGIAPI(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) 310 | { 311 | static HWND hPDlg; 312 | HWND hWndListView; 313 | LVITEMW item = {}; 314 | int index, count; 315 | WCHAR path[MAX_PATH]; 316 | WCHAR encoding[8]; 317 | WCHAR filter[256]; 318 | WCHAR comment[256]; 319 | WCHAR timeout[8]; 320 | 321 | switch (message) 322 | { 323 | case WM_INITDIALOG: 324 | hPDlg = (HWND)lParam; 325 | SetForegroundWindow(hDlg); 326 | 327 | SetDlgItemTextW(hDlg, IDC_EDIT_GOOGLECGIAPI_FILTER, inival_def_googlecgiapi_filter); 328 | SetDlgItemTextW(hDlg, IDC_EDIT_GOOGLECGIAPI_ANNOTATION, inival_def_googlecgiapi_annotation); 329 | SetDlgItemTextW(hDlg, IDC_EDIT_GOOGLECGIAPI_TIMEOUT, inival_def_timeout); 330 | CheckDlgButton(hDlg, IDC_RADIO_GOOGLECGIAPI_EUC, BST_CHECKED); 331 | return (INT_PTR)TRUE; 332 | 333 | case WM_COMMAND: 334 | switch (LOWORD(wParam)) 335 | { 336 | case IDOK: 337 | wcscpy_s(encoding, inival_googlecgiapi_encoding_euc); 338 | if (IsDlgButtonChecked(hDlg, IDC_RADIO_GOOGLECGIAPI_UTF8) == BST_CHECKED) 339 | { 340 | wcscpy_s(encoding, inival_googlecgiapi_encoding_utf8); 341 | } 342 | GetDlgItemTextW(hDlg, IDC_EDIT_GOOGLECGIAPI_FILTER, filter, _countof(filter)); 343 | GetDlgItemTextW(hDlg, IDC_EDIT_GOOGLECGIAPI_ANNOTATION, comment, _countof(comment)); 344 | for (index = 0; index < _countof(comment) && comment[index] != L'\0'; index++) 345 | { 346 | if (comment[index] == L'/' || comment[index] == L';') 347 | { 348 | comment[index] = L'\x20'; 349 | } 350 | } 351 | GetDlgItemTextW(hDlg, IDC_EDIT_GOOGLECGIAPI_TIMEOUT, timeout, _countof(timeout)); 352 | _snwprintf_s(path, _TRUNCATE, L"%s%c%s%c%s%c%s%c%s%c", INIVAL_GOOGLECGIAPI, INIVAL_SVR_SEP, 353 | filter, INIVAL_SVR_SEP, comment, INIVAL_SVR_SEP, timeout, INIVAL_SVR_SEP, encoding, INIVAL_SVR_SEP); 354 | 355 | hWndListView = GetDlgItem(hPDlg, IDC_LIST_SKK_DIC); 356 | index = ListView_GetNextItem(hWndListView, -1, LVNI_SELECTED); 357 | count = ListView_GetItemCount(hWndListView); 358 | if (index == -1) 359 | { 360 | index = count; 361 | } 362 | else 363 | { 364 | ++index; 365 | } 366 | item.mask = LVIF_TEXT; 367 | item.pszText = path; 368 | item.iItem = index; 369 | item.iSubItem = 0; 370 | ListView_InsertItem(hWndListView, &item); 371 | ListView_SetItemState(hWndListView, index, LVIS_FOCUSED | LVIS_SELECTED, 0x000F); 372 | ListView_SetColumnWidth(hWndListView, 0, LVSCW_AUTOSIZE); 373 | ListView_EnsureVisible(hWndListView, index, FALSE); 374 | 375 | if (ListView_GetItemCount(hWndListView) >= MAX_DICNUM) 376 | { 377 | EnableWindow(GetDlgItem(hPDlg, IDC_BUTTON_SKK_DIC_ADD), FALSE); 378 | EnableWindow(GetDlgItem(hPDlg, IDC_BUTTON_SKKSERV_ADD), FALSE); 379 | EnableWindow(GetDlgItem(hPDlg, IDC_BUTTON_GOOGLECGIAPI_ADD), FALSE); 380 | } 381 | 382 | EndDialog(hDlg, 0); 383 | break; 384 | 385 | case IDCANCEL: 386 | EndDialog(hDlg, 0); 387 | break; 388 | 389 | default: 390 | break; 391 | } 392 | return (INT_PTR)TRUE; 393 | 394 | case WM_CLOSE: 395 | case WM_DESTROY: 396 | EndDialog(hDlg, 0); 397 | return (INT_PTR)TRUE; 398 | 399 | default: 400 | break; 401 | } 402 | 403 | return (INT_PTR)FALSE; 404 | } 405 | 406 | INT_PTR CALLBACK DlgProcConfig(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) 407 | { 408 | HWND hWndListView; 409 | LV_COLUMNW lvc = {}; 410 | LVITEMW item = {}; 411 | OPENFILENAMEW ofn; 412 | WCHAR path[MAX_PATH] = {}; 413 | WCHAR pathBak[MAX_PATH] = {}; 414 | int index, count; 415 | VDICINFO::iterator vdicinfo_itr; 416 | WCHAR key[8]; 417 | FILE *fp; 418 | 419 | switch (message) 420 | { 421 | case WM_INITDIALOG: 422 | SetForegroundWindow(hDlg); 423 | 424 | if (serv_port[0] == L'\0') 425 | { 426 | wcscpy_s(serv_port, inival_def_port); 427 | } 428 | SetDlgItemTextW(hDlg, IDC_EDIT_SERV_PORT, serv_port); 429 | 430 | CheckDlgButton(hDlg, IDC_CHECKBOX_SERV_LOOPBACK, (serv_loopback ? BST_CHECKED : BST_UNCHECKED)); 431 | 432 | hWndListView = GetDlgItem(hDlg, IDC_LIST_SKK_DIC); 433 | ListView_SetExtendedListViewStyle(hWndListView, LVS_EX_FULLROWSELECT); 434 | 435 | lvc.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM; 436 | lvc.fmt = LVCFMT_CENTER; 437 | lvc.iSubItem = 0; 438 | lvc.cx = 220; 439 | lvc.pszText = L""; 440 | ListView_InsertColumn(hWndListView, 0, &lvc); 441 | 442 | index = 0; 443 | for (vdicinfo_itr = vdicinfo.begin(); vdicinfo_itr != vdicinfo.end(); vdicinfo_itr++) 444 | { 445 | item.mask = LVIF_TEXT; 446 | item.pszText = (LPWSTR)vdicinfo_itr->path.c_str(); 447 | item.iItem = index; 448 | item.iSubItem = 0; 449 | ListView_InsertItem(hWndListView, &item); 450 | index++; 451 | } 452 | 453 | ListView_SetColumnWidth(hWndListView, 0, LVSCW_AUTOSIZE); 454 | 455 | if (ListView_GetItemCount(hWndListView) >= MAX_DICNUM) 456 | { 457 | EnableWindow(GetDlgItem(hDlg, IDC_BUTTON_SKK_DIC_ADD), FALSE); 458 | EnableWindow(GetDlgItem(hDlg, IDC_BUTTON_SKKSERV_ADD), FALSE); 459 | EnableWindow(GetDlgItem(hDlg, IDC_BUTTON_GOOGLECGIAPI_ADD), FALSE); 460 | } 461 | return (INT_PTR)TRUE; 462 | 463 | case WM_DPICHANGED: 464 | hWndListView = GetDlgItem(hDlg, IDC_LIST_SKK_DIC); 465 | ListView_SetColumnWidth(hWndListView, 0, LVSCW_AUTOSIZE); 466 | return (INT_PTR)TRUE; 467 | 468 | case WM_COMMAND: 469 | hWndListView = GetDlgItem(hDlg, IDC_LIST_SKK_DIC); 470 | 471 | switch (LOWORD(wParam)) 472 | { 473 | case IDOK: 474 | _wfopen_s(&fp, ini, modeWB); 475 | if (fp != nullptr) 476 | { 477 | fwrite("\xFF\xFE", 2, 1, fp); 478 | fclose(fp); 479 | } 480 | 481 | GetDlgItemTextW(hDlg, IDC_EDIT_SERV_PORT, serv_port, _countof(serv_port)); 482 | WritePrivateProfileStringW(title, inikey_port, serv_port, ini); 483 | 484 | (IsDlgButtonChecked(hDlg, IDC_CHECKBOX_SERV_LOOPBACK) == BST_CHECKED) ? 485 | (serv_loopback = TRUE) : (serv_loopback = FALSE); 486 | _snwprintf_s(key, _TRUNCATE, L"%d", serv_loopback); 487 | WritePrivateProfileStringW(title, inikey_loopback, key, ini); 488 | 489 | WritePrivateProfileStringW(title, inikey_googlecgiapi_url_prefix, googlecgiapi_url_prefix, ini); 490 | WritePrivateProfileStringW(title, inikey_googlecgiapi_url_suffix, googlecgiapi_url_suffix, ini); 491 | 492 | count = ListView_GetItemCount(hWndListView); 493 | for (index = 0; index < MAX_DICNUM && index < count; index++) 494 | { 495 | _snwprintf_s(key, _TRUNCATE, L"%s%d", inikey_dic, index + 1); 496 | ListView_GetItemText(hWndListView, index, 0, path, _countof(path)); 497 | WritePrivateProfileStringW(title, key, path, ini); 498 | } 499 | 500 | EndDialog(hDlg, 0); 501 | term_server(); 502 | init_server(); 503 | break; 504 | 505 | case IDCANCEL: 506 | EndDialog(hDlg, 0); 507 | break; 508 | 509 | case IDC_BUTTON_SKK_DIC_UP: 510 | index = ListView_GetNextItem(hWndListView, -1, LVNI_SELECTED); 511 | if (index > 0) 512 | { 513 | ListView_GetItemText(hWndListView, index - 1, 0, pathBak, _countof(pathBak)); 514 | ListView_GetItemText(hWndListView, index, 0, path, _countof(path)); 515 | ListView_SetItemText(hWndListView, index - 1, 0, path); 516 | ListView_SetItemText(hWndListView, index, 0, pathBak); 517 | ListView_SetItemState(hWndListView, index - 1, LVIS_FOCUSED | LVIS_SELECTED, 0x000F); 518 | ListView_EnsureVisible(hWndListView, index - 1, FALSE); 519 | } 520 | return (INT_PTR)TRUE; 521 | 522 | case IDC_BUTTON_SKK_DIC_DOWN: 523 | index = ListView_GetNextItem(hWndListView, -1, LVNI_SELECTED); 524 | count = ListView_GetItemCount(hWndListView); 525 | if (index >= 0 && index < count - 1) 526 | { 527 | ListView_GetItemText(hWndListView, index + 1, 0, pathBak, _countof(pathBak)); 528 | ListView_GetItemText(hWndListView, index, 0, path, _countof(path)); 529 | ListView_SetItemText(hWndListView, index + 1, 0, path); 530 | ListView_SetItemText(hWndListView, index, 0, pathBak); 531 | ListView_SetItemState(hWndListView, index + 1, LVIS_FOCUSED | LVIS_SELECTED, 0x000F); 532 | ListView_EnsureVisible(hWndListView, index + 1, FALSE); 533 | } 534 | return (INT_PTR)TRUE; 535 | 536 | case IDC_BUTTON_SKK_DIC_ADD: 537 | path[0] = L'\0'; 538 | ZeroMemory(&ofn, sizeof(OPENFILENAMEW)); 539 | ofn.lStructSize = sizeof(OPENFILENAMEW); 540 | ofn.hwndOwner = hDlg; 541 | ofn.lpstrFile = path; 542 | ofn.nMaxFile = MAX_PATH; 543 | ofn.lpstrTitle = L"ファイル追加"; 544 | ofn.Flags = OFN_FILEMUSTEXIST; 545 | if (GetOpenFileNameW(&ofn) != 0) 546 | { 547 | index = ListView_GetNextItem(hWndListView, -1, LVNI_SELECTED); 548 | count = ListView_GetItemCount(hWndListView); 549 | if (index == -1) 550 | { 551 | index = count; 552 | } 553 | else 554 | { 555 | ++index; 556 | } 557 | item.mask = LVIF_TEXT; 558 | item.pszText = path; 559 | item.iItem = index; 560 | item.iSubItem = 0; 561 | ListView_InsertItem(hWndListView, &item); 562 | ListView_SetItemState(hWndListView, index, LVIS_FOCUSED | LVIS_SELECTED, 0x000F); 563 | ListView_SetColumnWidth(hWndListView, 0, LVSCW_AUTOSIZE); 564 | ListView_EnsureVisible(hWndListView, index, FALSE); 565 | 566 | if (ListView_GetItemCount(hWndListView) >= MAX_DICNUM) 567 | { 568 | EnableWindow(GetDlgItem(hDlg, IDC_BUTTON_SKK_DIC_ADD), FALSE); 569 | EnableWindow(GetDlgItem(hDlg, IDC_BUTTON_SKKSERV_ADD), FALSE); 570 | EnableWindow(GetDlgItem(hDlg, IDC_BUTTON_GOOGLECGIAPI_ADD), FALSE); 571 | } 572 | } 573 | return (INT_PTR)TRUE; 574 | 575 | case IDC_BUTTON_SKKSERV_ADD: 576 | DialogBoxParamW(hInst, MAKEINTRESOURCE(IDD_DIALOG_SKKSRV), hDlg, DlgProcSKKServ, (LPARAM)hDlg); 577 | return (INT_PTR)TRUE; 578 | 579 | case IDC_BUTTON_GOOGLECGIAPI_ADD: 580 | DialogBoxParamW(hInst, MAKEINTRESOURCE(IDD_DIALOG_GOOGLECGIAPI), hDlg, DlgProcGoogleCGIAPI, (LPARAM)hDlg); 581 | return (INT_PTR)TRUE; 582 | 583 | case IDC_BUTTON_SKK_DIC_DEL: 584 | index = ListView_GetNextItem(hWndListView, -1, LVNI_SELECTED); 585 | if (index != -1) 586 | { 587 | ListView_DeleteItem(hWndListView, index); 588 | ListView_SetColumnWidth(hWndListView, 0, LVSCW_AUTOSIZE); 589 | 590 | if (ListView_GetItemCount(hWndListView) < MAX_DICNUM) 591 | { 592 | EnableWindow(GetDlgItem(hDlg, IDC_BUTTON_SKK_DIC_ADD), TRUE); 593 | EnableWindow(GetDlgItem(hDlg, IDC_BUTTON_SKKSERV_ADD), TRUE); 594 | EnableWindow(GetDlgItem(hDlg, IDC_BUTTON_GOOGLECGIAPI_ADD), TRUE); 595 | } 596 | } 597 | return (INT_PTR)TRUE; 598 | 599 | default: 600 | break; 601 | } 602 | break; 603 | 604 | case WM_CLOSE: 605 | case WM_DESTROY: 606 | EndDialog(hDlg, 0); 607 | return (INT_PTR)TRUE; 608 | 609 | default: 610 | break; 611 | } 612 | 613 | return (INT_PTR)FALSE; 614 | } 615 | 616 | LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) 617 | { 618 | static UINT s_uTaskbarRestart; 619 | HMENU hMenu; 620 | HMENU hSubMenu; 621 | POINT pt; 622 | 623 | switch (message) 624 | { 625 | case WM_CREATE: 626 | s_uTaskbarRestart = RegisterWindowMessageW(L"TaskbarCreated"); 627 | init_server(); 628 | AddTaskbarIcon(hWnd); 629 | break; 630 | 631 | case WM_COMMAND: 632 | switch (LOWORD(wParam)) 633 | { 634 | case IDM_CONFIG: 635 | if (!bDlgShowed) 636 | { 637 | bDlgShowed = TRUE; 638 | DialogBoxW(hInst, MAKEINTRESOURCE(IDD_DIALOG_CONFIG), hWnd, DlgProcConfig); 639 | bDlgShowed = FALSE; 640 | } 641 | else 642 | { 643 | SetForegroundWindow(hWnd); 644 | } 645 | break; 646 | case IDM_EXIT: 647 | DestroyWindow(hWnd); 648 | break; 649 | default: 650 | break; 651 | } 652 | break; 653 | 654 | case WM_TASKBARICON_0: 655 | switch (lParam) 656 | { 657 | case WM_LBUTTONDOWN: 658 | if (!bDlgShowed) 659 | { 660 | bDlgShowed = TRUE; 661 | DialogBoxW(hInst, MAKEINTRESOURCE(IDD_DIALOG_CONFIG), hWnd, DlgProcConfig); 662 | bDlgShowed = FALSE; 663 | } 664 | else 665 | { 666 | SetForegroundWindow(hWnd); 667 | } 668 | break; 669 | case WM_RBUTTONDOWN: 670 | hMenu = LoadMenuW(hInst, MAKEINTRESOURCE(IDR_MENU)); 671 | if (hMenu) 672 | { 673 | GetCursorPos(&pt); 674 | SetForegroundWindow(hWnd); 675 | hSubMenu = GetSubMenu(hMenu, 0); 676 | if (hSubMenu) 677 | { 678 | TrackPopupMenu(hSubMenu, TPM_LEFTALIGN | TPM_BOTTOMALIGN | TPM_RIGHTBUTTON, 679 | pt.x, pt.y, 0, hWnd, nullptr); 680 | } 681 | DestroyMenu(hMenu); 682 | } 683 | break; 684 | default: 685 | break; 686 | } 687 | break; 688 | 689 | case WM_DESTROY: 690 | Shell_NotifyIconW(NIM_DELETE, &nid); 691 | term_server(); 692 | PostQuitMessage(0); 693 | return 0; 694 | 695 | default: 696 | if (message == s_uTaskbarRestart) 697 | { 698 | AddTaskbarIcon(hWnd); 699 | } 700 | break; 701 | } 702 | 703 | return DefWindowProcW(hWnd, message, wParam, lParam); 704 | } 705 | -------------------------------------------------------------------------------- /crvskkserv/crvskkserv.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #define RC_PRODUCT "crvskkserv" 4 | #define RC_VERSION "2.5.6" 5 | #define RC_VERSION_D 2,5,6,0 6 | #define RC_TITLE "crvskkserv (ver. 2.5.6)" 7 | #define RC_AUTHOR "nathancorvussolis" 8 | 9 | #define APP_TITLE L"crvskkserv" 10 | #define APP_VERSION L"2.5.1" 11 | 12 | #define RES_VER RC_PRODUCT "/" RC_VERSION " " 13 | 14 | #define REQ_END '0' 15 | #define REQ_KEY '1' 16 | #define REQ_VER '2' 17 | #define REQ_HST '3' 18 | #define REQ_CMP '4' 19 | 20 | #define REP_ERROR '0' 21 | #define REP_FOUND '1' 22 | #define REP_NOT_FOUND '4' 23 | 24 | #define INIVAL_SKKSERV L"skkserv" 25 | #define INIVAL_GOOGLECGIAPI L"googlecgiapi" 26 | #define INIVAL_SVR_SEP L'/' 27 | 28 | #define DICBUFSIZE 0x200 29 | #define RBUFSIZE 0x800 30 | 31 | #define WM_TASKBARICON_0 (WM_USER + 1) 32 | 33 | typedef struct _SERVINFO { 34 | BOOL live; 35 | SOCKET sock; 36 | } SERVINFO; 37 | 38 | typedef std::pair PAIR; 39 | typedef std::map MAP; 40 | 41 | typedef std::vector POS; 42 | typedef struct _DICINFO { 43 | std::wstring path; 44 | POS pos; 45 | SOCKET sock{}; 46 | } DICINFO; 47 | typedef std::vector VDICINFO; 48 | 49 | extern LPCSTR EntriesAri; 50 | extern LPCSTR EntriesNasi; 51 | extern LPCWSTR modeRB; 52 | extern LPCWSTR modeWB; 53 | 54 | extern LPCWSTR title; 55 | extern LPCSTR resver; 56 | extern WCHAR serv_port[]; 57 | extern BOOL serv_loopback; 58 | extern WCHAR googlecgiapi_url_prefix[]; 59 | extern WCHAR googlecgiapi_url_suffix[]; 60 | extern VDICINFO vdicinfo; 61 | 62 | extern LPCWSTR inival_def_timeout; 63 | extern LPCWSTR inival_googlecgiapi_encoding_euc; 64 | extern LPCWSTR inival_googlecgiapi_encoding_utf8; 65 | 66 | // server 67 | int make_serv_sock(SERVINFO *servinfo, int servinfonum); 68 | void disconnect(SOCKET &sock); 69 | void comm(SOCKET &sock); 70 | void comm_thread(void *p); 71 | void listen_thread(void *p); 72 | 73 | // search_dictionary 74 | void init_search_dictionary(DICINFO &dicinfo); 75 | void search_dictionary(DICINFO &dicinfo, const std::string &key, std::string &s); 76 | 77 | // search_skkserv 78 | void search_skkserv(DICINFO &dicinfo, const std::string &key, std::string &s); 79 | void connect_skkserv(DICINFO &dicinfo); 80 | BOOL get_skkserv_version(SOCKET &sock); 81 | 82 | // search_google_cgiapi 83 | void search_google_cgiapi(DICINFO &dicinfo, const std::string &key, std::string &s); 84 | -------------------------------------------------------------------------------- /crvskkserv/crvskkserv.manifest: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | True 34 | PerMonitorV2 35 | 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /crvskkserv/crvskkserv.rc: -------------------------------------------------------------------------------- 1 |  2 | #include "resource.h" 3 | #include "crvskkserv.h" 4 | 5 | #define APSTUDIO_READONLY_SYMBOLS 6 | #define APSTUDIO_HIDDEN_SYMBOLS 7 | #include 8 | #include 9 | #undef APSTUDIO_HIDDEN_SYMBOLS 10 | #undef APSTUDIO_READONLY_SYMBOLS 11 | 12 | VS_VERSION_INFO VERSIONINFO 13 | FILEVERSION RC_VERSION_D 14 | PRODUCTVERSION RC_VERSION_D 15 | FILEFLAGSMASK VS_FFI_FILEFLAGSMASK 16 | #ifndef _DEBUG 17 | FILEFLAGS 0x00000000L 18 | #else 19 | FILEFLAGS VS_FF_DEBUG 20 | #endif 21 | FILEOS VOS_NT_WINDOWS32 22 | FILETYPE VFT_APP 23 | FILESUBTYPE VFT2_UNKNOWN 24 | { 25 | BLOCK "StringFileInfo" 26 | { 27 | BLOCK "000004B0" 28 | { 29 | VALUE "FileDescription", RC_PRODUCT 30 | VALUE "FileVersion", RC_VERSION 31 | VALUE "LegalCopyright", "© 2012 " RC_AUTHOR 32 | VALUE "ProductName", RC_PRODUCT 33 | VALUE "ProductVersion", RC_VERSION 34 | } 35 | } 36 | BLOCK "VarFileInfo" 37 | { 38 | VALUE "Translation", 0x0000, 1200 39 | } 40 | } 41 | 42 | IDI_CRVSKKSERV ICON "app.ico" 43 | 44 | IDR_MENU MENU 45 | { 46 | POPUP "" 47 | { 48 | MENUITEM "設定", IDM_CONFIG 49 | MENUITEM SEPARATOR 50 | MENUITEM "終了", IDM_EXIT 51 | } 52 | } 53 | 54 | IDD_DIALOG_CONFIG DIALOG 0, 0, 266, 196 55 | STYLE DS_3DLOOK | DS_CENTER | DS_MODALFRAME | DS_SHELLFONT | WS_CAPTION | WS_VISIBLE | WS_POPUP | WS_SYSMENU 56 | CAPTION RC_TITLE 57 | FONT 10, "MS Gothic" 58 | { 59 | GROUPBOX "設定", IDC_STATIC, 4, 4, 258, 188 60 | 61 | LTEXT "ポート", IDC_STATIC, 14, 20, 24, 8, SS_LEFT 62 | EDITTEXT IDC_EDIT_SERV_PORT, 52, 18, 32, 12, ES_AUTOHSCROLL 63 | AUTOCHECKBOX "ループバックのみ", IDC_CHECKBOX_SERV_LOOPBACK, 120, 20, 80, 8 64 | 65 | CONTROL "", IDC_LIST_SKK_DIC, WC_LISTVIEW, WS_TABSTOP | WS_BORDER | LVS_ALIGNLEFT | LVS_SHOWSELALWAYS | LVS_SINGLESEL | LVS_REPORT | LVS_NOCOLUMNHEADER, 14, 35, 238, 88 66 | PUSHBUTTON "↑", IDC_BUTTON_SKK_DIC_UP, 15, 130, 16, 14, BS_CENTER 67 | PUSHBUTTON "↓", IDC_BUTTON_SKK_DIC_DOWN, 35, 130, 16, 14, BS_CENTER 68 | PUSHBUTTON "ファイル追加", IDC_BUTTON_SKK_DIC_ADD, 60, 130, 80, 14, BS_CENTER 69 | PUSHBUTTON "skkserv追加", IDC_BUTTON_SKKSERV_ADD, 60, 150, 80, 14, BS_CENTER 70 | PUSHBUTTON "GoogleCGIAPI追加", IDC_BUTTON_GOOGLECGIAPI_ADD, 60, 170, 80, 14, BS_CENTER 71 | PUSHBUTTON "削除", IDC_BUTTON_SKK_DIC_DEL, 210, 130, 40, 14, BS_CENTER 72 | 73 | PUSHBUTTON "OK", IDOK, 160, 170, 40, 14 74 | PUSHBUTTON "Cancel", IDCANCEL, 210, 170, 40, 14 75 | } 76 | 77 | IDD_DIALOG_SKKSRV DIALOG 0, 0, 266, 98 78 | STYLE DS_3DLOOK | DS_CENTER | DS_MODALFRAME | DS_SHELLFONT | WS_CAPTION | WS_VISIBLE | WS_POPUP | WS_SYSMENU 79 | CAPTION "skkserv追加" 80 | FONT 10, "MS Gothic" 81 | { 82 | GROUPBOX "skkserv", IDC_STATIC, 4, 4, 258, 62 83 | 84 | LTEXT "ホスト", IDC_STATIC, 15, 20, 30, 8, SS_LEFT 85 | EDITTEXT IDC_EDIT_SKKSRV_HOST, 50, 18, 200, 12, ES_AUTOHSCROLL 86 | LTEXT "ポート", IDC_STATIC, 15, 35, 30, 8, SS_LEFT 87 | EDITTEXT IDC_EDIT_SKKSRV_PORT, 50, 33, 30, 12, ES_AUTOHSCROLL 88 | LTEXT "タイムアウト", IDC_STATIC, 130, 35, 50, 8, SS_LEFT 89 | EDITTEXT IDC_EDIT_SKKSRV_TIMEOUT, 185, 33, 30, 12, ES_AUTOHSCROLL 90 | LTEXT "(msec)", IDC_STATIC, 220, 35, 25, 8, SS_LEFT 91 | 92 | PUSHBUTTON "OK", IDOK, 160, 75, 40, 14 93 | PUSHBUTTON "Cancel", IDCANCEL, 210, 75, 40, 14 94 | } 95 | 96 | IDD_DIALOG_GOOGLECGIAPI DIALOG 0, 0, 266, 98 97 | STYLE DS_3DLOOK | DS_CENTER | DS_MODALFRAME | DS_SHELLFONT | WS_CAPTION | WS_VISIBLE | WS_POPUP | WS_SYSMENU 98 | CAPTION "GoogleCGIAPI追加" 99 | FONT 10, "MS Gothic" 100 | { 101 | GROUPBOX "Google CGI API for Japanese Input", IDC_STATIC, 4, 4, 258, 62 102 | 103 | LTEXT "見出し語の検索除外条件", IDC_STATIC, 15, 20, 90, 8, SS_LEFT 104 | EDITTEXT IDC_EDIT_GOOGLECGIAPI_FILTER, 110, 18, 135, 12, ES_AUTOHSCROLL 105 | LTEXT "注釈", IDC_STATIC, 15, 35, 20, 8, SS_LEFT 106 | EDITTEXT IDC_EDIT_GOOGLECGIAPI_ANNOTATION, 40, 33, 80, 12, ES_AUTOHSCROLL 107 | LTEXT "タイムアウト", IDC_STATIC, 130, 35, 50, 8, SS_LEFT 108 | EDITTEXT IDC_EDIT_GOOGLECGIAPI_TIMEOUT, 185, 33, 30, 12, ES_AUTOHSCROLL 109 | LTEXT "(msec)", IDC_STATIC, 220, 35, 25, 8, SS_LEFT 110 | LTEXT "クライアントの文字コード", IDC_STATIC, 15, 50, 120, 8, SS_LEFT 111 | AUTORADIOBUTTON "EUC-JIS-2004", IDC_RADIO_GOOGLECGIAPI_EUC, 140, 50, 60, 8 112 | AUTORADIOBUTTON "UTF-8", IDC_RADIO_GOOGLECGIAPI_UTF8, 210, 50, 32, 8 113 | 114 | PUSHBUTTON "OK", IDOK, 160, 75, 40, 14 115 | PUSHBUTTON "Cancel", IDCANCEL, 210, 75, 40, 14 116 | } 117 | -------------------------------------------------------------------------------- /crvskkserv/crvskkserv.vcxproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Debug 10 | x64 11 | 12 | 13 | Release 14 | Win32 15 | 16 | 17 | Release 18 | x64 19 | 20 | 21 | 22 | {EE56E58B-C54E-425C-A0AF-292B4653B1F0} 23 | Win32Proj 24 | crvskkserv 25 | 10.0 26 | 27 | 28 | 29 | Application 30 | true 31 | v143 32 | Unicode 33 | 34 | 35 | Application 36 | true 37 | v143 38 | Unicode 39 | 40 | 41 | Application 42 | false 43 | v143 44 | true 45 | Unicode 46 | 47 | 48 | Application 49 | false 50 | v143 51 | true 52 | Unicode 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | true 72 | $(SolutionDir)$(Platform)\$(Configuration)\ 73 | $(Platform)\$(Configuration)\ 74 | 75 | 76 | true 77 | $(SolutionDir)$(Platform)\$(Configuration)\ 78 | $(Platform)\$(Configuration)\ 79 | 80 | 81 | false 82 | $(SolutionDir)$(Platform)\$(Configuration)\ 83 | $(Platform)\$(Configuration)\ 84 | 85 | 86 | false 87 | $(SolutionDir)$(Platform)\$(Configuration)\ 88 | $(Platform)\$(Configuration)\ 89 | 90 | 91 | 92 | Use 93 | Level3 94 | Disabled 95 | WIN32;_DEBUG;_WINDOWS;%(PreprocessorDefinitions) 96 | true 97 | pch.h;%(ForcedIncludeFiles) 98 | pch.h 99 | true 100 | 101 | 102 | Windows 103 | true 104 | ws2_32.lib;wininet.lib;comctl32.lib;%(AdditionalDependencies) 105 | 106 | 107 | crvskkserv.manifest %(AdditionalManifestFiles) 108 | 109 | 110 | 0x0411 111 | /c 65001 112 | 113 | 114 | 115 | 116 | Use 117 | Level3 118 | Disabled 119 | WIN32;_DEBUG;_WINDOWS;%(PreprocessorDefinitions) 120 | true 121 | pch.h;%(ForcedIncludeFiles) 122 | pch.h 123 | true 124 | 125 | 126 | Windows 127 | true 128 | ws2_32.lib;wininet.lib;comctl32.lib;%(AdditionalDependencies) 129 | 130 | 131 | crvskkserv.manifest %(AdditionalManifestFiles) 132 | 133 | 134 | 0x0411 135 | /c 65001 136 | 137 | 138 | 139 | 140 | Level3 141 | Use 142 | MaxSpeed 143 | true 144 | true 145 | WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions) 146 | true 147 | pch.h;%(ForcedIncludeFiles) 148 | MultiThreaded 149 | Guard 150 | pch.h 151 | true 152 | 153 | 154 | Windows 155 | true 156 | true 157 | ws2_32.lib;wininet.lib;comctl32.lib;%(AdditionalDependencies) 158 | No 159 | UseLinkTimeCodeGeneration 160 | true 161 | 162 | 163 | crvskkserv.manifest %(AdditionalManifestFiles) 164 | 165 | 166 | 0x0411 167 | /c 65001 168 | 169 | 170 | 171 | 172 | Level3 173 | Use 174 | MaxSpeed 175 | true 176 | true 177 | WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions) 178 | true 179 | pch.h;%(ForcedIncludeFiles) 180 | MultiThreaded 181 | Guard 182 | pch.h 183 | true 184 | 185 | 186 | Windows 187 | true 188 | true 189 | ws2_32.lib;wininet.lib;comctl32.lib;%(AdditionalDependencies) 190 | No 191 | UseLinkTimeCodeGeneration 192 | true 193 | 194 | 195 | crvskkserv.manifest %(AdditionalManifestFiles) 196 | 197 | 198 | 0x0411 199 | /c 65001 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | Create 225 | Create 226 | Create 227 | Create 228 | 229 | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 | 240 | 241 | 242 | 243 | 244 | 245 | 246 | -------------------------------------------------------------------------------- /crvskkserv/crvskkserv.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hh;hpp;hxx;hm;inl;inc;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | 18 | 19 | Header Files 20 | 21 | 22 | Header Files 23 | 24 | 25 | Header Files 26 | 27 | 28 | Header Files 29 | 30 | 31 | Header Files 32 | 33 | 34 | Header Files 35 | 36 | 37 | Header Files 38 | 39 | 40 | Header Files 41 | 42 | 43 | Header Files 44 | 45 | 46 | 47 | 48 | Source Files 49 | 50 | 51 | Source Files 52 | 53 | 54 | Source Files 55 | 56 | 57 | Source Files 58 | 59 | 60 | Source Files 61 | 62 | 63 | Source Files 64 | 65 | 66 | Source Files 67 | 68 | 69 | Source Files 70 | 71 | 72 | Source Files 73 | 74 | 75 | Source Files 76 | 77 | 78 | Source Files 79 | 80 | 81 | 82 | 83 | Resource Files 84 | 85 | 86 | 87 | 88 | Resource Files 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | Resource Files 97 | 98 | 99 | -------------------------------------------------------------------------------- /crvskkserv/eucjis2004.cpp: -------------------------------------------------------------------------------- 1 |  2 | #include "eucjis2004table.h" 3 | 4 | /* EUC-JIS-2004 5 | 0x00.. 0x7F ASCII 6 | 0xA1**.. 0xFE** JIS X 0213 Plane 1 7 | 0x8E**.. 0x8E** JIS X 0201 HALFWIDTH KATAKANA 8 | 0x8FA1**..0x8FFE** JIS X 0213 Plane 2 9 | (** : 0xA1..0xFE) 10 | */ 11 | 12 | /* UTF-16 surrogate pair 13 | U = WWWWWyyyyyyxxxxxxxxxx Unicode Code Point (U+10000..U+10FFFF) 14 | U' = wwwwyyyyyyxxxxxxxxxx Unicode Code Point - 0x10000 (ex. U+10FFFF -> 0xFFFFF(20bit)) 15 | W1 = 110110wwwwyyyyyy 1st : D800..DBFF (use upper 10bit) 16 | W2 = 110111xxxxxxxxxx 2nd : DC00..DFFF (use lower 10bit) 17 | */ 18 | 19 | #define SURROGATEPAIR_UCPMAX 0x10FFFF 20 | #define SURROGATEPAIR_UCPMIN 0x10000 21 | #define SURROGATEPAIR_MASK 0xFC00 22 | #define SURROGATEPAIR_HIGH_MASK 0xD800 23 | #define SURROGATEPAIR_LOW_MASK 0xDC00 24 | #define SURROGATEPAIR_SEPBIT 10 25 | #define SURROGATEPAIR_SEPMASK 0x3FF 26 | 27 | // Unicode Code PointをUTF-16へ変換 28 | 29 | size_t UcpToWideChar(UCSCHAR ucp, PWCHAR first, PWCHAR second) 30 | { 31 | size_t ret = 0; 32 | 33 | if (first == nullptr || second == nullptr) 34 | { 35 | return 0; 36 | } 37 | 38 | *first = L'\0'; 39 | *second = L'\0'; 40 | 41 | if (ucp < SURROGATEPAIR_UCPMIN) 42 | { 43 | *first = (WCHAR)ucp; 44 | *second = L'\0'; 45 | ret = 1; 46 | } 47 | else if (ucp <= SURROGATEPAIR_UCPMAX) // surrogate pair 48 | { 49 | *first = (WCHAR)(SURROGATEPAIR_HIGH_MASK | ((ucp - SURROGATEPAIR_UCPMIN) >> SURROGATEPAIR_SEPBIT)); 50 | *second = (WCHAR)(SURROGATEPAIR_LOW_MASK | ((ucp - SURROGATEPAIR_UCPMIN) & SURROGATEPAIR_SEPMASK)); 51 | ret = 2; 52 | } 53 | 54 | return ret; 55 | } 56 | 57 | // EUC 1文字分をUnicode Code Pointへ変換 58 | 59 | size_t EucJis2004ToUcp(LPCSTR src, size_t srcsize, PUCSCHAR ucp1, PUCSCHAR ucp2) 60 | { 61 | CONST CHAR as = 0x00; 62 | CONST CHAR ae = 0x7F; 63 | CONST CHAR ss2 = (CHAR)0x8E; 64 | CONST CHAR ss3 = (CHAR)0x8F; 65 | CONST CHAR ejd = (CHAR)0x80; 66 | CONST CHAR ejs = 0x21; 67 | CONST CHAR eje = 0x7E; 68 | CHAR ej[2] = {}; 69 | size_t srcused = 0; 70 | 71 | if (src == nullptr || srcsize == 0 || ucp1 == nullptr || ucp2 == nullptr) 72 | { 73 | return 0; 74 | } 75 | 76 | *ucp1 = 0; 77 | *ucp2 = 0; 78 | 79 | if (as <= src[0] && src[0] <= ae) // ASCII 80 | { 81 | *ucp1 = src[0]; 82 | *ucp2 = 0; 83 | srcused = 1; 84 | } 85 | else 86 | { 87 | switch (src[0]) 88 | { 89 | case ss3: // JIS X 0213 第二面 90 | if (srcsize < 3) 91 | { 92 | break; 93 | } 94 | 95 | ej[0] = 0; 96 | ej[1] = 0; 97 | 98 | if ((UCHAR)src[1] >= (UCHAR)ejd) 99 | { 100 | ej[0] = (CHAR)((UCHAR)src[1] - (UCHAR)ejd); 101 | } 102 | 103 | if ((UCHAR)src[2] >= (UCHAR)ejd) 104 | { 105 | ej[1] = (CHAR)((UCHAR)src[2] - (UCHAR)ejd); 106 | } 107 | 108 | if ((ej[0] >= ejs && ej[0] <= eje) && (ej[1] >= ejs && ej[1] <= eje)) 109 | { 110 | *ucp1 = 0; 111 | if (euc2i[ej[0] - ejs] != 0 && euc2i[ej[0] - ejs] <= ROW2NUM) 112 | { 113 | *ucp1 = euc2[euc2i[ej[0] - ejs] - 1][ej[1] - ejs]; 114 | } 115 | *ucp2 = 0; 116 | srcused = 3; 117 | } 118 | break; 119 | 120 | case ss2: // JIS X 0201 片仮名 121 | if (srcsize < 2) 122 | { 123 | break; 124 | } 125 | 126 | ej[0] = 0; 127 | 128 | if ((UCHAR)src[1] >= (UCHAR)ejd) 129 | { 130 | ej[0] = (CHAR)((UCHAR)src[1] - (UCHAR)ejd); 131 | } 132 | 133 | if (ej[0] >= ejs && ej[0] <= eje) 134 | { 135 | *ucp1 = eucK[ej[0] - ejs]; 136 | *ucp2 = 0; 137 | srcused = 2; 138 | } 139 | break; 140 | 141 | default: // JIS X 0213 第一面 142 | if (srcsize < 2) 143 | { 144 | break; 145 | } 146 | 147 | ej[0] = 0; 148 | ej[1] = 0; 149 | 150 | if ((UCHAR)src[0] >= (UCHAR)ejd) 151 | { 152 | ej[0] = (CHAR)((UCHAR)src[0] - (UCHAR)ejd); 153 | } 154 | 155 | if ((UCHAR)src[1] >= (UCHAR)ejd) 156 | { 157 | ej[1] = (CHAR)((UCHAR)src[1] - (UCHAR)ejd); 158 | } 159 | 160 | if ((ej[0] >= ejs && ej[0] <= eje) && (ej[1] >= ejs && ej[1] <= eje)) 161 | { 162 | USHORT euc = ((USHORT)ej[0] << 8) | (USHORT)ej[1] | 0x8080; 163 | 164 | // 結合文字 165 | for (int i = 0; i < CMBCHARNUM; i++) 166 | { 167 | if (euccmb[i].euc == euc) 168 | { 169 | *ucp1 = euccmb[i].ucp[0]; 170 | *ucp2 = euccmb[i].ucp[1]; 171 | srcused = 2; 172 | break; 173 | } 174 | } 175 | 176 | if (srcused != 0) 177 | { 178 | break; 179 | } 180 | 181 | *ucp1 = euc1[ej[0] - ejs][ej[1] - ejs]; 182 | *ucp2 = 0; 183 | srcused = 2; 184 | } 185 | break; 186 | } 187 | } 188 | 189 | return srcused; 190 | } 191 | 192 | // 終端NULLを付加 193 | 194 | void AddNullWideChar(size_t *srcsize, size_t si, LPWSTR dst, size_t *dstsize, size_t di) 195 | { 196 | if (srcsize != nullptr) 197 | { 198 | *srcsize = si; 199 | } 200 | *dstsize = di + 1; 201 | if (dst != nullptr) 202 | { 203 | *(dst + di) = L'\0'; 204 | } 205 | } 206 | 207 | // EUC-JIS-2004をUTF-16へ変換 208 | 209 | BOOL EucJis2004ToWideChar(LPCSTR src, size_t *srcsize, LPWSTR dst, size_t *dstsize) 210 | { 211 | size_t si = 0, di = 0, ss = -1; 212 | UCSCHAR ucp[2] = {}; 213 | WCHAR utf16[2][2] = {}; 214 | size_t utf16num[2] = {}; 215 | 216 | if (dstsize == nullptr) 217 | { 218 | return FALSE; 219 | } 220 | 221 | if (dst == nullptr) 222 | { 223 | *dstsize = (size_t)-1; 224 | } 225 | 226 | if (src == nullptr) 227 | { 228 | *dstsize = 0; 229 | return FALSE; 230 | } 231 | 232 | if (srcsize != nullptr) 233 | { 234 | ss = *srcsize; 235 | } 236 | 237 | for (si = 0; ; si++) 238 | { 239 | if ((ss <= si) || (*(src + si) == '\0')) 240 | { 241 | break; 242 | } 243 | 244 | // EUC-JIS-2004からUnicode Code Pointへ変換 245 | size_t used = EucJis2004ToUcp(src + si, ss - si, &ucp[0], &ucp[1]); 246 | if ((ucp[0] == 0) || (used == 0)) 247 | { 248 | AddNullWideChar(srcsize, si, dst, dstsize, di); 249 | return FALSE; 250 | } 251 | si += used - 1; 252 | 253 | // Unicode Code PointからUTF-16へ変換 254 | for (int i = 0; i < 2; i++) 255 | { 256 | utf16num[i] = 0; 257 | if (ucp[i] != 0) 258 | { 259 | utf16num[i] = UcpToWideChar(ucp[i], &utf16[i][0], &utf16[i][1]); 260 | } 261 | } 262 | 263 | if (*dstsize <= di + utf16num[0] + utf16num[1]) // limit 264 | { 265 | AddNullWideChar(srcsize, si, dst, dstsize, di); 266 | return FALSE; 267 | } 268 | 269 | for (int i = 0; i < 2; i++) 270 | { 271 | if (dst != nullptr) 272 | { 273 | for (int j = 0; j < (int)utf16num[i] && j < 2; j++) 274 | { 275 | *(dst + di + j) = utf16[i][j]; 276 | } 277 | } 278 | di += utf16num[i]; 279 | } 280 | } 281 | 282 | AddNullWideChar(srcsize, si, dst, dstsize, di); 283 | return TRUE; 284 | } 285 | 286 | // 終端NULLを付加 287 | 288 | void AddNullMultiByte(size_t *srcsize, size_t si, LPSTR dst, size_t *dstsize, size_t di) 289 | { 290 | if (srcsize != nullptr) 291 | { 292 | *srcsize = si; 293 | } 294 | *dstsize = di + 1; 295 | if (dst != nullptr) 296 | { 297 | *(dst + di) = '\0'; 298 | } 299 | } 300 | 301 | // UTF-16をEUC-JIS-2004へ変換 302 | 303 | BOOL WideCharToEucJis2004(LPCWSTR src, size_t *srcsize, LPSTR dst, size_t *dstsize) 304 | { 305 | CONST CHAR ss2 = (CHAR)0x8E; 306 | CONST CHAR ss3 = (CHAR)0x8F; 307 | CONST CHAR ejd = (CHAR)0x80; 308 | CONST CHAR ejs = 0x21; 309 | size_t si = 0, di = 0, ss = -1; 310 | WCHAR first, second; 311 | UCSCHAR ucp; 312 | BOOL exist; 313 | 314 | if (dstsize == nullptr) 315 | { 316 | return FALSE; 317 | } 318 | 319 | if (dst == nullptr) 320 | { 321 | *dstsize = (size_t)-1; 322 | } 323 | 324 | if (src == nullptr) 325 | { 326 | *dstsize = 0; 327 | return FALSE; 328 | } 329 | 330 | if (srcsize != nullptr) 331 | { 332 | ss = *srcsize; 333 | } 334 | 335 | for (si = 0; ; si++) 336 | { 337 | if ((ss <= si) || (*(src + si) == L'\0')) 338 | { 339 | break; 340 | } 341 | 342 | if (*(src + si) <= L'\x7F') // ASCII 343 | { 344 | if (*dstsize <= di + 1) // limit 345 | { 346 | AddNullMultiByte(srcsize, si, dst, dstsize, di); 347 | return FALSE; 348 | } 349 | if (dst != nullptr) 350 | { 351 | *(dst + di) = (CHAR)*(src + si); 352 | } 353 | ++di; 354 | } 355 | else 356 | { 357 | exist = FALSE; 358 | 359 | first = *(src + si); 360 | if (si + 1 < ss) 361 | { 362 | second = *(src + si + 1); 363 | } 364 | else 365 | { 366 | second = 0; 367 | } 368 | 369 | if ((first >= SURROGATEPAIR_HIGH_MASK && first <= (SURROGATEPAIR_HIGH_MASK | SURROGATEPAIR_SEPMASK)) && 370 | (second >= SURROGATEPAIR_LOW_MASK && second <= (SURROGATEPAIR_LOW_MASK | SURROGATEPAIR_SEPMASK))) 371 | { 372 | ucp = SURROGATEPAIR_UCPMIN + 373 | ((((UCSCHAR)first & SURROGATEPAIR_SEPMASK) << SURROGATEPAIR_SEPBIT) | 374 | ((UCSCHAR)second & SURROGATEPAIR_SEPMASK)); 375 | } 376 | else 377 | { 378 | ucp = first; 379 | } 380 | 381 | // 互換性 382 | if (!exist) 383 | { 384 | for (int i = 0; i < CMPEUCNUM; i++) 385 | { 386 | if (ucp == euccmp[i].ucp) 387 | { 388 | if (*dstsize <= di + 2) // limit 389 | { 390 | AddNullMultiByte(srcsize, si, dst, dstsize, di); 391 | return FALSE; 392 | } 393 | if (dst != nullptr) 394 | { 395 | *(dst + di) = (CHAR)(euccmp[i].euc >> 8); 396 | *(dst + di + 1) = (CHAR)(euccmp[i].euc & 0xFF); 397 | } 398 | di += 2; 399 | if (ucp != first) // surrogate pair 400 | { 401 | si++; 402 | } 403 | exist = TRUE; 404 | break; 405 | } 406 | } 407 | } 408 | 409 | // 結合文字 410 | if (!exist) 411 | { 412 | for (int i = 0; i < CMBCHARNUM; i++) 413 | { 414 | if (first == euccmb[i].ucp[0] && second == euccmb[i].ucp[1]) 415 | { 416 | if (*dstsize <= di + 2) // limit 417 | { 418 | AddNullMultiByte(srcsize, si, dst, dstsize, di); 419 | return FALSE; 420 | } 421 | if (dst != nullptr) 422 | { 423 | *(dst + di) = euccmb[i].euc >> 8; 424 | *(dst + di + 1) = euccmb[i].euc & 0xFF; 425 | } 426 | di += 2; 427 | if (ucp != first) // surrogate pair, unused actually 428 | { 429 | si++; 430 | } 431 | si++; 432 | exist = TRUE; 433 | break; 434 | } 435 | } 436 | } 437 | 438 | // JIS X 0213 第一面 439 | if (!exist) 440 | { 441 | for (int i = 0; i < ROWNUM; i++) 442 | { 443 | for (int j = 0; j < CELLNUM; j++) 444 | { 445 | if (ucp == euc1[i][j]) 446 | { 447 | if (*dstsize <= di + 2) // limit 448 | { 449 | AddNullMultiByte(srcsize, si, dst, dstsize, di); 450 | return FALSE; 451 | } 452 | if (dst != nullptr) 453 | { 454 | *(dst + di) = (CHAR)((UCHAR)(ejs + i) + (UCHAR)ejd); 455 | *(dst + di + 1) = (CHAR)((UCHAR)(ejs + j) + (UCHAR)ejd); 456 | } 457 | di += 2; 458 | if (ucp != first) // surrogate pair 459 | { 460 | si++; 461 | } 462 | exist = TRUE; 463 | break; 464 | } 465 | } 466 | 467 | if (exist) 468 | { 469 | break; 470 | } 471 | } 472 | } 473 | 474 | // JIS X 0213 第二面 475 | if (!exist) 476 | { 477 | for (int i = 0; i < ROWNUM; i++) 478 | { 479 | for (int j = 0; j < CELLNUM; j++) 480 | { 481 | if (euc2i[i] != 0 && euc2i[i] <= ROW2NUM && 482 | ucp == euc2[euc2i[i] - 1][j]) 483 | { 484 | if (*dstsize <= di + 3) // limit 485 | { 486 | AddNullMultiByte(srcsize, si, dst, dstsize, di); 487 | return FALSE; 488 | } 489 | if (dst != nullptr) 490 | { 491 | *(dst + di) = ss3; 492 | *(dst + di + 1) = (CHAR)((UCHAR)(ejs + i) + (UCHAR)ejd); 493 | *(dst + di + 2) = (CHAR)((UCHAR)(ejs + j) + (UCHAR)ejd); 494 | } 495 | di += 3; 496 | if (ucp != first) // surrogate pair 497 | { 498 | si++; 499 | } 500 | exist = TRUE; 501 | break; 502 | } 503 | } 504 | 505 | if (exist) 506 | { 507 | break; 508 | } 509 | } 510 | } 511 | 512 | // JIS X 0201 片仮名 513 | if (!exist) 514 | { 515 | for (int i = 0; i < ANKNUM; i++) 516 | { 517 | if (ucp == eucK[i]) 518 | { 519 | if (*dstsize <= di + 2) // limit 520 | { 521 | AddNullMultiByte(srcsize, si, dst, dstsize, di); 522 | return FALSE; 523 | } 524 | if (dst != nullptr) 525 | { 526 | *(dst + di) = ss2; 527 | *(dst + di + 1) = (CHAR)((UCHAR)(ejs + i) + (UCHAR)ejd); 528 | } 529 | di += 2; 530 | exist = TRUE; 531 | break; 532 | } 533 | } 534 | } 535 | 536 | if (!exist) 537 | { 538 | AddNullMultiByte(srcsize, si, dst, dstsize, di); 539 | return FALSE; 540 | } 541 | } 542 | } 543 | 544 | AddNullMultiByte(srcsize, si, dst, dstsize, di); 545 | return TRUE; 546 | } 547 | 548 | std::wstring eucjis2004_string_to_wstring(const std::string &s) 549 | { 550 | std::wstring ret; 551 | size_t len; 552 | 553 | BOOL b = EucJis2004ToWideChar(s.c_str(), nullptr, nullptr, &len); 554 | if (b && len > 0) 555 | { 556 | try 557 | { 558 | LPWSTR wcs = new WCHAR[len]; 559 | if (EucJis2004ToWideChar(s.c_str(), nullptr, wcs, &len)) 560 | { 561 | ret = wcs; 562 | } 563 | delete[] wcs; 564 | } 565 | catch (...) 566 | { 567 | } 568 | } 569 | 570 | return ret; 571 | } 572 | 573 | std::string wstring_to_eucjis2004_string(const std::wstring &s) 574 | { 575 | std::string ret; 576 | size_t len; 577 | 578 | BOOL b = WideCharToEucJis2004(s.c_str(), nullptr, nullptr, &len); 579 | if (b && len > 0) 580 | { 581 | try 582 | { 583 | LPSTR euc = new CHAR[len]; 584 | if (WideCharToEucJis2004(s.c_str(), nullptr, euc, &len)) 585 | { 586 | ret = euc; 587 | } 588 | delete[] euc; 589 | } 590 | catch (...) 591 | { 592 | } 593 | } 594 | 595 | return ret; 596 | } 597 | -------------------------------------------------------------------------------- /crvskkserv/eucjis2004.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // Unicode Code PointをUTF-16へ変換 4 | // 戻り値 5 | // 0 : ucpがU+10FFFFより大きい 6 | // firstまたはsecondがnullptr 7 | // 1 : BMP内 8 | // 2 : BMP外 9 | // 引数 10 | // ucp : Unicode符号位置 11 | // first : BMPの文字または上位サロゲート 12 | // second : 下位サロゲート 13 | size_t UcpToWideChar(UCSCHAR ucp, PWCHAR first, PWCHAR second); 14 | 15 | // EUC 1文字分をUnicode Code Pointへ変換 16 | // 戻り値 17 | // 変換に使用されたサイズ(char単位) 18 | // 引数 19 | // src : 変換元のEUC-JIS-2004文字列 20 | // srcsize : 変換元のEUC-JIS-2004文字列のサイズ 21 | // ucp1 : Unicode符号位置1つ目 22 | // ucp2 : Unicode符号位置2つ目(結合文字がある場合、なければ0) 23 | size_t EucJis2004ToUcp(LPCSTR src, size_t srcsize, PUCSCHAR ucp1, PUCSCHAR ucp2); 24 | 25 | // EUC-JIS-2004をUTF-16へ変換 26 | // 戻り値 27 | // TRUE : 成功 28 | // FALSE : 失敗 29 | // 引数 30 | // src : 変換元のEUC-JIS-2004文字列 31 | // nullptrのとき戻り値はFALSEになる 32 | // srcsize : nullptrのときsrcの終端NULLまで変換する 33 | // nullptr以外のとき指定されたサイズまたはsrcの終端NULLの短いほうまで変換する 34 | // 変換に使用されたサイズ(char単位)が戻る 35 | // dst : 変換先のUTF-16LE文字列バッファ 36 | // nullptrは許容される 37 | // dstsize : dstのサイズ 38 | // 変換結果の終端NULLを含むサイズ(wchar_t単位)が戻る 39 | // nullptrのとき戻り値はFALSEになる 40 | BOOL EucJis2004ToWideChar(LPCSTR src, size_t *srcsize, LPWSTR dst, size_t *dstsize); 41 | 42 | // UTF-16をEUC-JIS-2004へ変換 43 | // 戻り値 44 | // TRUE : 成功 45 | // FALSE : 失敗 46 | // 引数 47 | // src : 変換元のUTF-16LE文字列 48 | // nullptrのとき戻り値はFALSEになる 49 | // srcsize : nullptrのときsrcの終端NULLまで変換する 50 | // nullptr以外のとき指定されたサイズまたはsrcの終端NULLの短いほうまで変換する 51 | // 変換に使用されたサイズ(wchar_t単位)が戻る 52 | // dst : 変換先のEUC-JIS-2004文字列バッファ 53 | // nullptrは許容される 54 | // dstsize : dstのサイズ 55 | // 変換結果の終端NULLを含むサイズ(char単位)が戻る 56 | // nullptrのとき戻り値はFALSEになる 57 | BOOL WideCharToEucJis2004(LPCWSTR src, size_t *srcsize, LPSTR dst, size_t *dstsize); 58 | 59 | void AddNullWideChar(size_t *srcsize, size_t si, LPWSTR dst, size_t *dstsize, size_t di); 60 | void AddNullMultiByte(size_t *srcsize, size_t si, LPSTR dst, size_t *dstsize, size_t di); 61 | 62 | std::wstring eucjis2004_string_to_wstring(const std::string &s); 63 | std::string wstring_to_eucjis2004_string(const std::wstring &s); 64 | -------------------------------------------------------------------------------- /crvskkserv/eucjis2004table.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #define CMBCHARNUM 25 // Unicode結合文字 4 | #define ROWNUM 94 // 区 5 | #define CELLNUM 94 // 点 6 | #define ANKNUM 94 // JIS X 0201 片仮名 7 | #define ROW2NUM 26 // JIS X 0213 第二面 区数 8 | #define CMPEUCNUM 2 // Unicode -> EUC-JIS-2004 互換性 9 | 10 | // Unicode結合文字 11 | typedef struct { 12 | USHORT euc; 13 | UCSCHAR ucp[2]; 14 | } EUCCMB; 15 | 16 | // Unicode互換性 17 | typedef struct { 18 | USHORT euc; 19 | UCSCHAR ucp; 20 | } EUCCMP; 21 | 22 | // 変換テーブル 23 | 24 | // Unicode結合文字 25 | extern const EUCCMB euccmb[CMBCHARNUM]; 26 | // JIS X 0213 第一面 27 | extern const UCSCHAR euc1[ROWNUM][CELLNUM]; 28 | // JIS X 0201 片仮名 29 | extern const UCSCHAR eucK[ANKNUM]; 30 | // JIS X 0213 第二面 31 | extern const BYTE euc2i[ROWNUM]; 32 | // JIS X 0213 第二面 33 | extern const UCSCHAR euc2[ROW2NUM][CELLNUM]; 34 | // Unicode -> EUC-JIS-2004 互換性 35 | extern const EUCCMP euccmp[CMPEUCNUM]; 36 | -------------------------------------------------------------------------------- /crvskkserv/eucjp.cpp: -------------------------------------------------------------------------------- 1 |  2 | #include "eucjptable.h" 3 | #include "eucjis2004.h" 4 | 5 | /* EUC-JP 6 | 0x00.. 0x7F ASCII 7 | 0xA1**.. 0xFE** JIS X 0208 8 | 0x8E**.. 0x8E** JIS X 0201 HALFWIDTH KATAKANA 9 | 0x8FA1**..0x8FFE** JIS X 0212 10 | (** : 0xA1..0xFE) 11 | */ 12 | 13 | // EUC 1文字分をUnicode Code Pointへ変換 14 | 15 | size_t EucJPToUcp(LPCSTR src, size_t srcsize, PUCSCHAR ucp1, PUCSCHAR ucp2) 16 | { 17 | CONST CHAR as = 0x00; 18 | CONST CHAR ae = 0x7F; 19 | CONST CHAR ss2 = (CHAR)0x8E; 20 | CONST CHAR ss3 = (CHAR)0x8F; 21 | CONST CHAR ejd = (CHAR)0x80; 22 | CONST CHAR ejs = 0x21; 23 | CONST CHAR eje = 0x7E; 24 | CHAR ej[2] = {}; 25 | size_t srcused = 0; 26 | 27 | if (src == nullptr || srcsize == 0 || ucp1 == nullptr || ucp2 == nullptr) 28 | { 29 | return 0; 30 | } 31 | 32 | *ucp1 = 0; 33 | *ucp2 = 0; 34 | 35 | if (as <= src[0] && src[0] <= ae) // ASCII 36 | { 37 | *ucp1 = src[0]; 38 | *ucp2 = 0; 39 | srcused = 1; 40 | } 41 | else 42 | { 43 | switch (src[0]) 44 | { 45 | case ss3: // JIS X 0212 46 | if (srcsize < 3) 47 | { 48 | break; 49 | } 50 | 51 | ej[0] = 0; 52 | ej[1] = 0; 53 | 54 | if ((UCHAR)src[1] >= (UCHAR)ejd) 55 | { 56 | ej[0] = (CHAR)((UCHAR)src[1] - (UCHAR)ejd); 57 | } 58 | 59 | if ((UCHAR)src[2] >= (UCHAR)ejd) 60 | { 61 | ej[1] = (CHAR)((UCHAR)src[2] - (UCHAR)ejd); 62 | } 63 | 64 | if ((ej[0] >= ejs && ej[0] <= eje) && (ej[1] >= ejs && ej[1] <= eje)) 65 | { 66 | *ucp1 = 0; 67 | if (euc0212i[ej[0] - ejs] != 0 && euc0212i[ej[0] - ejs] <= ROW0212NUM) 68 | { 69 | *ucp1 = euc0212[euc0212i[ej[0] - ejs] - 1][ej[1] - ejs]; 70 | } 71 | *ucp2 = 0; 72 | srcused = 3; 73 | } 74 | break; 75 | 76 | case ss2: // JIS X 0201 片仮名 77 | if (srcsize < 2) 78 | { 79 | break; 80 | } 81 | 82 | ej[0] = 0; 83 | 84 | if ((UCHAR)src[1] >= (UCHAR)ejd) 85 | { 86 | ej[0] = (CHAR)((UCHAR)src[1] - (UCHAR)ejd); 87 | } 88 | 89 | if (ej[0] >= ejs && ej[0] <= eje) 90 | { 91 | *ucp1 = eucK[ej[0] - ejs]; 92 | *ucp2 = 0; 93 | srcused = 2; 94 | } 95 | break; 96 | 97 | default: // JIS X 0208 98 | if (srcsize < 2) 99 | { 100 | break; 101 | } 102 | 103 | ej[0] = 0; 104 | ej[1] = 0; 105 | 106 | if ((UCHAR)src[0] >= (UCHAR)ejd) 107 | { 108 | ej[0] = (CHAR)((UCHAR)src[0] - (UCHAR)ejd); 109 | } 110 | 111 | if ((UCHAR)src[1] >= (UCHAR)ejd) 112 | { 113 | ej[1] = (CHAR)((UCHAR)src[1] - (UCHAR)ejd); 114 | } 115 | 116 | if ((ej[0] >= ejs && ej[0] <= eje) && (ej[1] >= ejs && ej[1] <= eje)) 117 | { 118 | *ucp1 = 0; 119 | CHAR ku = ej[0] - ejs + 1; 120 | CHAR ten = ej[1] - ejs + 1; 121 | if ((jisx0208e[ku - 1][(ten - (ten % 16)) / 16] & (0x0001 << (ten % 16))) != 0) 122 | { 123 | *ucp1 = euc1[ej[0] - ejs][ej[1] - ejs]; 124 | } 125 | *ucp2 = 0; 126 | srcused = 2; 127 | } 128 | break; 129 | } 130 | } 131 | 132 | return srcused; 133 | } 134 | 135 | // EUC-JPをUTF-16へ変換 136 | 137 | BOOL EucJPToWideChar(LPCSTR src, size_t *srcsize, LPWSTR dst, size_t *dstsize) 138 | { 139 | size_t si = 0, di = 0, ss = -1; 140 | UCSCHAR ucp[2] = {}; 141 | WCHAR utf16[2][2] = {}; 142 | size_t utf16num[2] = {}; 143 | 144 | if (dstsize == nullptr) 145 | { 146 | return FALSE; 147 | } 148 | 149 | if (dst == nullptr) 150 | { 151 | *dstsize = (size_t)-1; 152 | } 153 | 154 | if (src == nullptr) 155 | { 156 | *dstsize = 0; 157 | return FALSE; 158 | } 159 | 160 | if (srcsize != nullptr) 161 | { 162 | ss = *srcsize; 163 | } 164 | 165 | for (si = 0; ; si++) 166 | { 167 | if ((ss <= si) || (*(src + si) == '\0')) 168 | { 169 | break; 170 | } 171 | 172 | // EUC-JPからUnicode Code Pointへ変換 173 | size_t used = EucJPToUcp(src + si, ss - si, &ucp[0], &ucp[1]); 174 | if ((ucp[0] == 0) || (used == 0)) 175 | { 176 | AddNullWideChar(srcsize, si, dst, dstsize, di); 177 | return FALSE; 178 | } 179 | si += used - 1; 180 | 181 | // Unicode Code PointからUTF-16へ変換 182 | for (int i = 0; i < 2; i++) 183 | { 184 | utf16num[i] = 0; 185 | if (ucp[i] != 0) 186 | { 187 | utf16num[i] = UcpToWideChar(ucp[i], &utf16[i][0], &utf16[i][1]); 188 | } 189 | } 190 | 191 | if (*dstsize <= di + utf16num[0] + utf16num[1]) // limit 192 | { 193 | AddNullWideChar(srcsize, si, dst, dstsize, di); 194 | return FALSE; 195 | } 196 | 197 | for (int i = 0; i < 2; i++) 198 | { 199 | if (dst != nullptr) 200 | { 201 | for (int j = 0; j < (int)utf16num[i] && j < 2; j++) 202 | { 203 | *(dst + di + j) = utf16[i][j]; 204 | } 205 | } 206 | di += utf16num[i]; 207 | } 208 | } 209 | 210 | AddNullWideChar(srcsize, si, dst, dstsize, di); 211 | return TRUE; 212 | } 213 | 214 | // UTF-16をEUC-JPへ変換 215 | 216 | BOOL WideCharToEucJP(LPCWSTR src, size_t *srcsize, LPSTR dst, size_t *dstsize) 217 | { 218 | CONST CHAR ss2 = (CHAR)0x8E; 219 | CONST CHAR ss3 = (CHAR)0x8F; 220 | CONST CHAR ejd = (CHAR)0x80; 221 | CONST CHAR ejs = 0x21; 222 | size_t si = 0, di = 0, ss = -1; 223 | UCSCHAR ucp; 224 | BOOL exist; 225 | 226 | if (dstsize == nullptr) 227 | { 228 | return FALSE; 229 | } 230 | 231 | if (dst == nullptr) 232 | { 233 | *dstsize = (size_t)-1; 234 | } 235 | 236 | if (src == nullptr) 237 | { 238 | *dstsize = 0; 239 | return FALSE; 240 | } 241 | 242 | if (srcsize != nullptr) 243 | { 244 | ss = *srcsize; 245 | } 246 | 247 | for (si = 0; ; si++) 248 | { 249 | if ((ss <= si) || (*(src + si) == L'\0')) 250 | { 251 | break; 252 | } 253 | 254 | if (*(src + si) <= L'\x7F') // ASCII 255 | { 256 | if (*dstsize <= di + 1) // limit 257 | { 258 | AddNullMultiByte(srcsize, si, dst, dstsize, di); 259 | return FALSE; 260 | } 261 | if (dst != nullptr) 262 | { 263 | *(dst + di) = (CHAR) * (src + si); 264 | } 265 | ++di; 266 | } 267 | else 268 | { 269 | exist = FALSE; 270 | 271 | // surrogate pair なし 272 | ucp = *(src + si); 273 | 274 | // 互換性 275 | if (!exist) 276 | { 277 | for (int i = 0; i < CMPEUCJPNUM; i++) 278 | { 279 | if (ucp == eucjpcmp[i].ucp) 280 | { 281 | if (*dstsize <= di + 2) // limit 282 | { 283 | AddNullMultiByte(srcsize, si, dst, dstsize, di); 284 | return FALSE; 285 | } 286 | if (dst != nullptr) 287 | { 288 | *(dst + di) = (CHAR)(eucjpcmp[i].euc >> 8); 289 | *(dst + di + 1) = (CHAR)(eucjpcmp[i].euc & 0xFF); 290 | } 291 | di += 2; 292 | exist = TRUE; 293 | break; 294 | } 295 | } 296 | } 297 | 298 | // JIS X 0218 299 | if (!exist) 300 | { 301 | for (int i = 0; i < ROWNUM; i++) 302 | { 303 | for (int j = 0; j < CELLNUM; j++) 304 | { 305 | CHAR ku = i + 1; 306 | CHAR ten = j + 1; 307 | if ((jisx0208e[ku - 1][(ten - (ten % 16)) / 16] & (0x0001 << (ten % 16))) != 0 && 308 | ucp == euc1[i][j]) 309 | { 310 | if (*dstsize <= di + 2) // limit 311 | { 312 | AddNullMultiByte(srcsize, si, dst, dstsize, di); 313 | return FALSE; 314 | } 315 | if (dst != nullptr) 316 | { 317 | *(dst + di) = (CHAR)((UCHAR)(ejs + i) + (UCHAR)ejd); 318 | *(dst + di + 1) = (CHAR)((UCHAR)(ejs + j) + (UCHAR)ejd); 319 | } 320 | di += 2; 321 | exist = TRUE; 322 | break; 323 | } 324 | } 325 | 326 | if (exist) 327 | { 328 | break; 329 | } 330 | } 331 | } 332 | 333 | // JIS X 0212 334 | if (!exist) 335 | { 336 | for (int i = 0; i < ROWNUM; i++) 337 | { 338 | for (int j = 0; j < CELLNUM; j++) 339 | { 340 | if (euc0212i[i] != 0 && euc0212i[i] <= ROW0212NUM && 341 | ucp == euc0212[euc0212i[i] - 1][j]) 342 | { 343 | if (*dstsize <= di + 3) // limit 344 | { 345 | AddNullMultiByte(srcsize, si, dst, dstsize, di); 346 | return FALSE; 347 | } 348 | if (dst != nullptr) 349 | { 350 | *(dst + di) = ss3; 351 | *(dst + di + 1) = (CHAR)((UCHAR)(ejs + i) + (UCHAR)ejd); 352 | *(dst + di + 2) = (CHAR)((UCHAR)(ejs + j) + (UCHAR)ejd); 353 | } 354 | di += 3; 355 | exist = TRUE; 356 | break; 357 | } 358 | } 359 | 360 | if (exist) 361 | { 362 | break; 363 | } 364 | } 365 | } 366 | 367 | // JIS X 0201 片仮名 368 | if (!exist) 369 | { 370 | for (int i = 0; i < ANKNUM; i++) 371 | { 372 | if (ucp == eucK[i]) 373 | { 374 | if (*dstsize <= di + 2) // limit 375 | { 376 | AddNullMultiByte(srcsize, si, dst, dstsize, di); 377 | return FALSE; 378 | } 379 | if (dst != nullptr) 380 | { 381 | *(dst + di) = ss2; 382 | *(dst + di + 1) = (CHAR)((UCHAR)(ejs + i) + (UCHAR)ejd); 383 | } 384 | di += 2; 385 | exist = TRUE; 386 | break; 387 | } 388 | } 389 | } 390 | 391 | if (!exist) 392 | { 393 | AddNullMultiByte(srcsize, si, dst, dstsize, di); 394 | return FALSE; 395 | } 396 | } 397 | } 398 | 399 | AddNullMultiByte(srcsize, si, dst, dstsize, di); 400 | return TRUE; 401 | } 402 | 403 | std::wstring eucjp_string_to_wstring(const std::string &s) 404 | { 405 | std::wstring ret; 406 | size_t len; 407 | 408 | BOOL b = EucJPToWideChar(s.c_str(), nullptr, nullptr, &len); 409 | if (b && len > 0) 410 | { 411 | try 412 | { 413 | LPWSTR wcs = new WCHAR[len]; 414 | if (EucJPToWideChar(s.c_str(), nullptr, wcs, &len)) 415 | { 416 | ret = wcs; 417 | } 418 | delete[] wcs; 419 | } 420 | catch (...) 421 | { 422 | } 423 | } 424 | 425 | return ret; 426 | } 427 | 428 | std::string wstring_to_eucjp_string(const std::wstring &s) 429 | { 430 | std::string ret; 431 | size_t len; 432 | 433 | BOOL b = WideCharToEucJP(s.c_str(), nullptr, nullptr, &len); 434 | if (b && len > 0) 435 | { 436 | try 437 | { 438 | LPSTR euc = new CHAR[len]; 439 | if (WideCharToEucJP(s.c_str(), nullptr, euc, &len)) 440 | { 441 | ret = euc; 442 | } 443 | delete[] euc; 444 | } 445 | catch (...) 446 | { 447 | } 448 | } 449 | 450 | return ret; 451 | } 452 | -------------------------------------------------------------------------------- /crvskkserv/eucjp.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // EUC 1文字分をUnicode Code Pointへ変換 4 | // 戻り値 5 | // 変換に使用されたサイズ(char単位) 6 | // 引数 7 | // src : 変換元のEUC-JP文字列 8 | // srcsize : 変換元のEUC-JP文字列のサイズ 9 | // ucp1 : Unicode符号位置1つ目 10 | // ucp2 : Unicode符号位置2つ目(結合文字がある場合、なければ0) 11 | size_t EucJPToUcp(LPCSTR src, size_t srcsize, PUCSCHAR ucp1, PUCSCHAR ucp2); 12 | 13 | // EUC-JPをUTF-16へ変換 14 | // 戻り値 15 | // TRUE : 成功 16 | // FALSE : 失敗 17 | // 引数 18 | // src : 変換元のEUC-JP文字列 19 | // nullptrのとき戻り値はFALSEになる 20 | // srcsize : nullptrのときsrcの終端NULLまで変換する 21 | // nullptr以外のとき指定されたサイズまたはsrcの終端NULLの短いほうまで変換する 22 | // 変換に使用されたサイズ(char単位)が戻る 23 | // dst : 変換先のUTF-16LE文字列バッファ 24 | // nullptrは許容される 25 | // dstsize : dstのサイズ 26 | // 変換結果の終端NULLを含むサイズ(wchar_t単位)が戻る 27 | // nullptrのとき戻り値はFALSEになる 28 | BOOL EucJPToWideChar(LPCSTR src, size_t *srcsize, LPWSTR dst, size_t *dstsize); 29 | 30 | // UTF-16をEUC-JPへ変換 31 | // 戻り値 32 | // TRUE : 成功 33 | // FALSE : 失敗 34 | // 引数 35 | // src : 変換元のUTF-16LE文字列 36 | // nullptrのとき戻り値はFALSEになる 37 | // srcsize : nullptrのときsrcの終端NULLまで変換する 38 | // nullptr以外のとき指定されたサイズまたはsrcの終端NULLの短いほうまで変換する 39 | // 変換に使用されたサイズ(wchar_t単位)が戻る 40 | // dst : 変換先のEUC-JP文字列バッファ 41 | // nullptrは許容される 42 | // dstsize : dstのサイズ 43 | // 変換結果の終端NULLを含むサイズ(char単位)が戻る 44 | // nullptrのとき戻り値はFALSEになる 45 | BOOL WideCharToEucJP(LPCWSTR src, size_t *srcsize, LPSTR dst, size_t *dstsize); 46 | 47 | std::wstring eucjp_string_to_wstring(const std::string &s); 48 | std::string wstring_to_eucjp_string(const std::wstring &s); 49 | -------------------------------------------------------------------------------- /crvskkserv/eucjptable.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "eucjis2004table.h" 4 | 5 | #define ROW0212NUM 68 // JIS X 0212 区数 6 | #define COLNUM 6 // JIS X 0208 有効区点要素数 (区数+2)/16 7 | #define CMPEUCJPNUM 9 // Unicode -> EUC-JP 互換性 8 | 9 | //変換テーブル 10 | 11 | // JIS X 0208 有効区点 12 | extern const USHORT jisx0208e[ROWNUM][COLNUM]; 13 | // JIS X 0212 インデックス 14 | extern const BYTE euc0212i[ROWNUM]; 15 | // JIS X 0212 16 | extern const UCSCHAR euc0212[ROW0212NUM][CELLNUM]; 17 | // Unicode -> EUC-JP 互換性 18 | extern const EUCCMP eucjpcmp[CMPEUCJPNUM]; 19 | -------------------------------------------------------------------------------- /crvskkserv/pch.cpp: -------------------------------------------------------------------------------- 1 |  -------------------------------------------------------------------------------- /crvskkserv/pch.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #define WIN32_LEAN_AND_MEAN 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | -------------------------------------------------------------------------------- /crvskkserv/picojson.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2009-2010 Cybozu Labs, Inc. 3 | * Copyright 2011-2014 Kazuho Oku 4 | * All rights reserved. 5 | * 6 | * Redistribution and use in source and binary forms, with or without 7 | * modification, are permitted provided that the following conditions are met: 8 | * 9 | * 1. Redistributions of source code must retain the above copyright notice, 10 | * this list of conditions and the following disclaimer. 11 | * 12 | * 2. Redistributions in binary form must reproduce the above copyright notice, 13 | * this list of conditions and the following disclaimer in the documentation 14 | * and/or other materials provided with the distribution. 15 | * 16 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 17 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 20 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 21 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 22 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 23 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 24 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 25 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26 | * POSSIBILITY OF SUCH DAMAGE. 27 | */ 28 | #ifndef picojson_h 29 | #define picojson_h 30 | 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | #include 40 | #include 41 | #include 42 | #include 43 | #include 44 | 45 | // for isnan/isinf 46 | #if __cplusplus >= 201103L 47 | #include 48 | #else 49 | extern "C" { 50 | #ifdef _MSC_VER 51 | #include 52 | #elif defined(__INTEL_COMPILER) 53 | #include 54 | #else 55 | #include 56 | #endif 57 | } 58 | #endif 59 | 60 | #ifndef PICOJSON_USE_RVALUE_REFERENCE 61 | #if (defined(__cpp_rvalue_references) && __cpp_rvalue_references >= 200610) || (defined(_MSC_VER) && _MSC_VER >= 1600) 62 | #define PICOJSON_USE_RVALUE_REFERENCE 1 63 | #else 64 | #define PICOJSON_USE_RVALUE_REFERENCE 0 65 | #endif 66 | #endif // PICOJSON_USE_RVALUE_REFERENCE 67 | 68 | #ifndef PICOJSON_NOEXCEPT 69 | #if PICOJSON_USE_RVALUE_REFERENCE 70 | #define PICOJSON_NOEXCEPT noexcept 71 | #else 72 | #define PICOJSON_NOEXCEPT throw() 73 | #endif 74 | #endif 75 | 76 | // experimental support for int64_t (see README.mkdn for detail) 77 | #ifdef PICOJSON_USE_INT64 78 | #define __STDC_FORMAT_MACROS 79 | #include 80 | #if __cplusplus >= 201103L 81 | #include 82 | #else 83 | extern "C" { 84 | #include 85 | } 86 | #endif 87 | #endif 88 | 89 | // to disable the use of localeconv(3), set PICOJSON_USE_LOCALE to 0 90 | #ifndef PICOJSON_USE_LOCALE 91 | #define PICOJSON_USE_LOCALE 1 92 | #endif 93 | #if PICOJSON_USE_LOCALE 94 | extern "C" { 95 | #include 96 | } 97 | #endif 98 | 99 | #ifndef PICOJSON_ASSERT 100 | #define PICOJSON_ASSERT(e) \ 101 | do { \ 102 | if (!(e)) \ 103 | throw std::runtime_error(#e); \ 104 | } while (0) 105 | #endif 106 | 107 | #ifdef _MSC_VER 108 | #define SNPRINTF _snprintf_s 109 | #pragma warning(push) 110 | #pragma warning(disable : 4244) // conversion from int to char 111 | #pragma warning(disable : 4127) // conditional expression is constant 112 | #pragma warning(disable : 4702) // unreachable code 113 | #pragma warning(disable : 4706) // assignment within conditional expression 114 | #else 115 | #define SNPRINTF snprintf 116 | #endif 117 | 118 | namespace picojson { 119 | 120 | enum { 121 | null_type, 122 | boolean_type, 123 | number_type, 124 | string_type, 125 | array_type, 126 | object_type 127 | #ifdef PICOJSON_USE_INT64 128 | , 129 | int64_type 130 | #endif 131 | }; 132 | 133 | enum { INDENT_WIDTH = 2, DEFAULT_MAX_DEPTHS = 100 }; 134 | 135 | struct null {}; 136 | 137 | class value { 138 | public: 139 | typedef std::vector array; 140 | typedef std::map object; 141 | union _storage { 142 | bool boolean_; 143 | double number_; 144 | #ifdef PICOJSON_USE_INT64 145 | int64_t int64_; 146 | #endif 147 | std::string *string_; 148 | array *array_; 149 | object *object_; 150 | }; 151 | 152 | protected: 153 | int type_; 154 | _storage u_; 155 | 156 | public: 157 | value(); 158 | value(int type, bool); 159 | explicit value(bool b); 160 | #ifdef PICOJSON_USE_INT64 161 | explicit value(int64_t i); 162 | #endif 163 | explicit value(double n); 164 | explicit value(const std::string &s); 165 | explicit value(const array &a); 166 | explicit value(const object &o); 167 | #if PICOJSON_USE_RVALUE_REFERENCE 168 | explicit value(std::string &&s); 169 | explicit value(array &&a); 170 | explicit value(object &&o); 171 | #endif 172 | explicit value(const char *s); 173 | value(const char *s, size_t len); 174 | ~value(); 175 | value(const value &x); 176 | value &operator=(const value &x); 177 | #if PICOJSON_USE_RVALUE_REFERENCE 178 | value(value &&x) PICOJSON_NOEXCEPT; 179 | value &operator=(value &&x) PICOJSON_NOEXCEPT; 180 | #endif 181 | void swap(value &x) PICOJSON_NOEXCEPT; 182 | template bool is() const; 183 | template const T &get() const; 184 | template T &get(); 185 | template void set(const T &); 186 | #if PICOJSON_USE_RVALUE_REFERENCE 187 | template void set(T &&); 188 | #endif 189 | bool evaluate_as_boolean() const; 190 | const value &get(const size_t idx) const; 191 | const value &get(const std::string &key) const; 192 | value &get(const size_t idx); 193 | value &get(const std::string &key); 194 | 195 | bool contains(const size_t idx) const; 196 | bool contains(const std::string &key) const; 197 | std::string to_str() const; 198 | template void serialize(Iter os, bool prettify = false) const; 199 | std::string serialize(bool prettify = false) const; 200 | 201 | private: 202 | template value(const T *); // intentionally defined to block implicit conversion of pointer to bool 203 | template static void _indent(Iter os, int indent); 204 | template void _serialize(Iter os, int indent) const; 205 | std::string _serialize(int indent) const; 206 | void clear(); 207 | }; 208 | 209 | typedef value::array array; 210 | typedef value::object object; 211 | 212 | inline value::value() : type_(null_type), u_() { 213 | } 214 | 215 | inline value::value(int type, bool) : type_(type), u_() { 216 | switch (type) { 217 | #define INIT(p, v) \ 218 | case p##type: \ 219 | u_.p = v; \ 220 | break 221 | INIT(boolean_, false); 222 | INIT(number_, 0.0); 223 | #ifdef PICOJSON_USE_INT64 224 | INIT(int64_, 0); 225 | #endif 226 | INIT(string_, new std::string()); 227 | INIT(array_, new array()); 228 | INIT(object_, new object()); 229 | #undef INIT 230 | default: 231 | break; 232 | } 233 | } 234 | 235 | inline value::value(bool b) : type_(boolean_type), u_() { 236 | u_.boolean_ = b; 237 | } 238 | 239 | #ifdef PICOJSON_USE_INT64 240 | inline value::value(int64_t i) : type_(int64_type), u_() { 241 | u_.int64_ = i; 242 | } 243 | #endif 244 | 245 | inline value::value(double n) : type_(number_type), u_() { 246 | if ( 247 | #ifdef _MSC_VER 248 | !_finite(n) 249 | #elif __cplusplus >= 201103L 250 | std::isnan(n) || std::isinf(n) 251 | #else 252 | isnan(n) || isinf(n) 253 | #endif 254 | ) { 255 | throw std::overflow_error(""); 256 | } 257 | u_.number_ = n; 258 | } 259 | 260 | inline value::value(const std::string &s) : type_(string_type), u_() { 261 | u_.string_ = new std::string(s); 262 | } 263 | 264 | inline value::value(const array &a) : type_(array_type), u_() { 265 | u_.array_ = new array(a); 266 | } 267 | 268 | inline value::value(const object &o) : type_(object_type), u_() { 269 | u_.object_ = new object(o); 270 | } 271 | 272 | #if PICOJSON_USE_RVALUE_REFERENCE 273 | inline value::value(std::string &&s) : type_(string_type), u_() { 274 | u_.string_ = new std::string(std::move(s)); 275 | } 276 | 277 | inline value::value(array &&a) : type_(array_type), u_() { 278 | u_.array_ = new array(std::move(a)); 279 | } 280 | 281 | inline value::value(object &&o) : type_(object_type), u_() { 282 | u_.object_ = new object(std::move(o)); 283 | } 284 | #endif 285 | 286 | inline value::value(const char *s) : type_(string_type), u_() { 287 | u_.string_ = new std::string(s); 288 | } 289 | 290 | inline value::value(const char *s, size_t len) : type_(string_type), u_() { 291 | u_.string_ = new std::string(s, len); 292 | } 293 | 294 | inline void value::clear() { 295 | switch (type_) { 296 | #define DEINIT(p) \ 297 | case p##type: \ 298 | delete u_.p; \ 299 | break 300 | DEINIT(string_); 301 | DEINIT(array_); 302 | DEINIT(object_); 303 | #undef DEINIT 304 | default: 305 | break; 306 | } 307 | } 308 | 309 | inline value::~value() { 310 | clear(); 311 | } 312 | 313 | inline value::value(const value &x) : type_(x.type_), u_() { 314 | switch (type_) { 315 | #define INIT(p, v) \ 316 | case p##type: \ 317 | u_.p = v; \ 318 | break 319 | INIT(string_, new std::string(*x.u_.string_)); 320 | INIT(array_, new array(*x.u_.array_)); 321 | INIT(object_, new object(*x.u_.object_)); 322 | #undef INIT 323 | default: 324 | u_ = x.u_; 325 | break; 326 | } 327 | } 328 | 329 | inline value &value::operator=(const value &x) { 330 | if (this != &x) { 331 | value t(x); 332 | swap(t); 333 | } 334 | return *this; 335 | } 336 | 337 | #if PICOJSON_USE_RVALUE_REFERENCE 338 | inline value::value(value &&x) PICOJSON_NOEXCEPT : type_(null_type), u_() { 339 | swap(x); 340 | } 341 | inline value &value::operator=(value &&x) PICOJSON_NOEXCEPT { 342 | swap(x); 343 | return *this; 344 | } 345 | #endif 346 | inline void value::swap(value &x) PICOJSON_NOEXCEPT { 347 | std::swap(type_, x.type_); 348 | std::swap(u_, x.u_); 349 | } 350 | 351 | #define IS(ctype, jtype) \ 352 | template <> inline bool value::is() const { \ 353 | return type_ == jtype##_type; \ 354 | } 355 | IS(null, null) 356 | IS(bool, boolean) 357 | #ifdef PICOJSON_USE_INT64 358 | IS(int64_t, int64) 359 | #endif 360 | IS(std::string, string) 361 | IS(array, array) 362 | IS(object, object) 363 | #undef IS 364 | template <> inline bool value::is() const { 365 | return type_ == number_type 366 | #ifdef PICOJSON_USE_INT64 367 | || type_ == int64_type 368 | #endif 369 | ; 370 | } 371 | 372 | #define GET(ctype, var) \ 373 | template <> inline const ctype &value::get() const { \ 374 | PICOJSON_ASSERT("type mismatch! call is() before get()" && is()); \ 375 | return var; \ 376 | } \ 377 | template <> inline ctype &value::get() { \ 378 | PICOJSON_ASSERT("type mismatch! call is() before get()" && is()); \ 379 | return var; \ 380 | } 381 | GET(bool, u_.boolean_) 382 | GET(std::string, *u_.string_) 383 | GET(array, *u_.array_) 384 | GET(object, *u_.object_) 385 | #ifdef PICOJSON_USE_INT64 386 | GET(double, 387 | (type_ == int64_type && (const_cast(this)->type_ = number_type, (const_cast(this)->u_.number_ = u_.int64_)), 388 | u_.number_)) 389 | GET(int64_t, u_.int64_) 390 | #else 391 | GET(double, u_.number_) 392 | #endif 393 | #undef GET 394 | 395 | #define SET(ctype, jtype, setter) \ 396 | template <> inline void value::set(const ctype &_val) { \ 397 | clear(); \ 398 | type_ = jtype##_type; \ 399 | setter \ 400 | } 401 | SET(bool, boolean, u_.boolean_ = _val;) 402 | SET(std::string, string, u_.string_ = new std::string(_val);) 403 | SET(array, array, u_.array_ = new array(_val);) 404 | SET(object, object, u_.object_ = new object(_val);) 405 | SET(double, number, u_.number_ = _val;) 406 | #ifdef PICOJSON_USE_INT64 407 | SET(int64_t, int64, u_.int64_ = _val;) 408 | #endif 409 | #undef SET 410 | 411 | #if PICOJSON_USE_RVALUE_REFERENCE 412 | #define MOVESET(ctype, jtype, setter) \ 413 | template <> inline void value::set(ctype && _val) { \ 414 | clear(); \ 415 | type_ = jtype##_type; \ 416 | setter \ 417 | } 418 | MOVESET(std::string, string, u_.string_ = new std::string(std::move(_val));) 419 | MOVESET(array, array, u_.array_ = new array(std::move(_val));) 420 | MOVESET(object, object, u_.object_ = new object(std::move(_val));) 421 | #undef MOVESET 422 | #endif 423 | 424 | inline bool value::evaluate_as_boolean() const { 425 | switch (type_) { 426 | case null_type: 427 | return false; 428 | case boolean_type: 429 | return u_.boolean_; 430 | case number_type: 431 | return u_.number_ != 0; 432 | #ifdef PICOJSON_USE_INT64 433 | case int64_type: 434 | return u_.int64_ != 0; 435 | #endif 436 | case string_type: 437 | return !u_.string_->empty(); 438 | default: 439 | return true; 440 | } 441 | } 442 | 443 | inline const value &value::get(const size_t idx) const { 444 | static value s_null; 445 | PICOJSON_ASSERT(is()); 446 | return idx < u_.array_->size() ? (*u_.array_)[idx] : s_null; 447 | } 448 | 449 | inline value &value::get(const size_t idx) { 450 | static value s_null; 451 | PICOJSON_ASSERT(is()); 452 | return idx < u_.array_->size() ? (*u_.array_)[idx] : s_null; 453 | } 454 | 455 | inline const value &value::get(const std::string &key) const { 456 | static value s_null; 457 | PICOJSON_ASSERT(is()); 458 | object::const_iterator i = u_.object_->find(key); 459 | return i != u_.object_->end() ? i->second : s_null; 460 | } 461 | 462 | inline value &value::get(const std::string &key) { 463 | static value s_null; 464 | PICOJSON_ASSERT(is()); 465 | object::iterator i = u_.object_->find(key); 466 | return i != u_.object_->end() ? i->second : s_null; 467 | } 468 | 469 | inline bool value::contains(const size_t idx) const { 470 | PICOJSON_ASSERT(is()); 471 | return idx < u_.array_->size(); 472 | } 473 | 474 | inline bool value::contains(const std::string &key) const { 475 | PICOJSON_ASSERT(is()); 476 | object::const_iterator i = u_.object_->find(key); 477 | return i != u_.object_->end(); 478 | } 479 | 480 | inline std::string value::to_str() const { 481 | switch (type_) { 482 | case null_type: 483 | return "null"; 484 | case boolean_type: 485 | return u_.boolean_ ? "true" : "false"; 486 | #ifdef PICOJSON_USE_INT64 487 | case int64_type: { 488 | char buf[sizeof("-9223372036854775808")]; 489 | SNPRINTF(buf, sizeof(buf), "%" PRId64, u_.int64_); 490 | return buf; 491 | } 492 | #endif 493 | case number_type: { 494 | char buf[256]; 495 | double tmp; 496 | SNPRINTF(buf, sizeof(buf), fabs(u_.number_) < (1ULL << 53) && modf(u_.number_, &tmp) == 0 ? "%.f" : "%.17g", u_.number_); 497 | #if PICOJSON_USE_LOCALE 498 | char *decimal_point = localeconv()->decimal_point; 499 | if (strcmp(decimal_point, ".") != 0) { 500 | size_t decimal_point_len = strlen(decimal_point); 501 | for (char *p = buf; *p != '\0'; ++p) { 502 | if (strncmp(p, decimal_point, decimal_point_len) == 0) { 503 | return std::string(buf, p) + "." + (p + decimal_point_len); 504 | } 505 | } 506 | } 507 | #endif 508 | return buf; 509 | } 510 | case string_type: 511 | return *u_.string_; 512 | case array_type: 513 | return "array"; 514 | case object_type: 515 | return "object"; 516 | default: 517 | PICOJSON_ASSERT(0); 518 | #ifdef _MSC_VER 519 | __assume(0); 520 | #endif 521 | } 522 | return std::string(); 523 | } 524 | 525 | template void copy(const std::string &s, Iter oi) { 526 | std::copy(s.begin(), s.end(), oi); 527 | } 528 | 529 | template struct serialize_str_char { 530 | Iter oi; 531 | void operator()(char c) { 532 | switch (c) { 533 | #define MAP(val, sym) \ 534 | case val: \ 535 | copy(sym, oi); \ 536 | break 537 | MAP('"', "\\\""); 538 | MAP('\\', "\\\\"); 539 | MAP('/', "\\/"); 540 | MAP('\b', "\\b"); 541 | MAP('\f', "\\f"); 542 | MAP('\n', "\\n"); 543 | MAP('\r', "\\r"); 544 | MAP('\t', "\\t"); 545 | #undef MAP 546 | default: 547 | if (static_cast(c) < 0x20 || c == 0x7f) { 548 | char buf[7]; 549 | SNPRINTF(buf, sizeof(buf), "\\u%04x", c & 0xff); 550 | copy(buf, buf + 6, oi); 551 | } else { 552 | *oi++ = c; 553 | } 554 | break; 555 | } 556 | } 557 | }; 558 | 559 | template void serialize_str(const std::string &s, Iter oi) { 560 | *oi++ = '"'; 561 | serialize_str_char process_char = {oi}; 562 | std::for_each(s.begin(), s.end(), process_char); 563 | *oi++ = '"'; 564 | } 565 | 566 | template void value::serialize(Iter oi, bool prettify) const { 567 | return _serialize(oi, prettify ? 0 : -1); 568 | } 569 | 570 | inline std::string value::serialize(bool prettify) const { 571 | return _serialize(prettify ? 0 : -1); 572 | } 573 | 574 | template void value::_indent(Iter oi, int indent) { 575 | *oi++ = '\n'; 576 | for (int i = 0; i < indent * INDENT_WIDTH; ++i) { 577 | *oi++ = ' '; 578 | } 579 | } 580 | 581 | template void value::_serialize(Iter oi, int indent) const { 582 | switch (type_) { 583 | case string_type: 584 | serialize_str(*u_.string_, oi); 585 | break; 586 | case array_type: { 587 | *oi++ = '['; 588 | if (indent != -1) { 589 | ++indent; 590 | } 591 | for (array::const_iterator i = u_.array_->begin(); i != u_.array_->end(); ++i) { 592 | if (i != u_.array_->begin()) { 593 | *oi++ = ','; 594 | } 595 | if (indent != -1) { 596 | _indent(oi, indent); 597 | } 598 | i->_serialize(oi, indent); 599 | } 600 | if (indent != -1) { 601 | --indent; 602 | if (!u_.array_->empty()) { 603 | _indent(oi, indent); 604 | } 605 | } 606 | *oi++ = ']'; 607 | break; 608 | } 609 | case object_type: { 610 | *oi++ = '{'; 611 | if (indent != -1) { 612 | ++indent; 613 | } 614 | for (object::const_iterator i = u_.object_->begin(); i != u_.object_->end(); ++i) { 615 | if (i != u_.object_->begin()) { 616 | *oi++ = ','; 617 | } 618 | if (indent != -1) { 619 | _indent(oi, indent); 620 | } 621 | serialize_str(i->first, oi); 622 | *oi++ = ':'; 623 | if (indent != -1) { 624 | *oi++ = ' '; 625 | } 626 | i->second._serialize(oi, indent); 627 | } 628 | if (indent != -1) { 629 | --indent; 630 | if (!u_.object_->empty()) { 631 | _indent(oi, indent); 632 | } 633 | } 634 | *oi++ = '}'; 635 | break; 636 | } 637 | default: 638 | copy(to_str(), oi); 639 | break; 640 | } 641 | if (indent == 0) { 642 | *oi++ = '\n'; 643 | } 644 | } 645 | 646 | inline std::string value::_serialize(int indent) const { 647 | std::string s; 648 | _serialize(std::back_inserter(s), indent); 649 | return s; 650 | } 651 | 652 | template class input { 653 | protected: 654 | Iter cur_, end_; 655 | bool consumed_; 656 | int line_; 657 | 658 | public: 659 | input(const Iter &first, const Iter &last) : cur_(first), end_(last), consumed_(false), line_(1) { 660 | } 661 | int getc() { 662 | if (consumed_) { 663 | if (*cur_ == '\n') { 664 | ++line_; 665 | } 666 | ++cur_; 667 | } 668 | if (cur_ == end_) { 669 | consumed_ = false; 670 | return -1; 671 | } 672 | consumed_ = true; 673 | return *cur_ & 0xff; 674 | } 675 | void ungetc() { 676 | consumed_ = false; 677 | } 678 | Iter cur() const { 679 | if (consumed_) { 680 | input *self = const_cast *>(this); 681 | self->consumed_ = false; 682 | ++self->cur_; 683 | } 684 | return cur_; 685 | } 686 | int line() const { 687 | return line_; 688 | } 689 | void skip_ws() { 690 | while (1) { 691 | int ch = getc(); 692 | if (!(ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r')) { 693 | ungetc(); 694 | break; 695 | } 696 | } 697 | } 698 | bool expect(const int expected) { 699 | skip_ws(); 700 | if (getc() != expected) { 701 | ungetc(); 702 | return false; 703 | } 704 | return true; 705 | } 706 | bool match(const std::string &pattern) { 707 | for (std::string::const_iterator pi(pattern.begin()); pi != pattern.end(); ++pi) { 708 | if (getc() != *pi) { 709 | ungetc(); 710 | return false; 711 | } 712 | } 713 | return true; 714 | } 715 | }; 716 | 717 | template inline int _parse_quadhex(input &in) { 718 | int uni_ch = 0, hex; 719 | for (int i = 0; i < 4; i++) { 720 | if ((hex = in.getc()) == -1) { 721 | return -1; 722 | } 723 | if ('0' <= hex && hex <= '9') { 724 | hex -= '0'; 725 | } else if ('A' <= hex && hex <= 'F') { 726 | hex -= 'A' - 0xa; 727 | } else if ('a' <= hex && hex <= 'f') { 728 | hex -= 'a' - 0xa; 729 | } else { 730 | in.ungetc(); 731 | return -1; 732 | } 733 | uni_ch = uni_ch * 16 + hex; 734 | } 735 | return uni_ch; 736 | } 737 | 738 | template inline bool _parse_codepoint(String &out, input &in) { 739 | int uni_ch; 740 | if ((uni_ch = _parse_quadhex(in)) == -1) { 741 | return false; 742 | } 743 | if (0xd800 <= uni_ch && uni_ch <= 0xdfff) { 744 | if (0xdc00 <= uni_ch) { 745 | // a second 16-bit of a surrogate pair appeared 746 | return false; 747 | } 748 | // first 16-bit of surrogate pair, get the next one 749 | if (in.getc() != '\\' || in.getc() != 'u') { 750 | in.ungetc(); 751 | return false; 752 | } 753 | int second = _parse_quadhex(in); 754 | if (!(0xdc00 <= second && second <= 0xdfff)) { 755 | return false; 756 | } 757 | uni_ch = ((uni_ch - 0xd800) << 10) | ((second - 0xdc00) & 0x3ff); 758 | uni_ch += 0x10000; 759 | } 760 | if (uni_ch < 0x80) { 761 | out.push_back(static_cast(uni_ch)); 762 | } else { 763 | if (uni_ch < 0x800) { 764 | out.push_back(static_cast(0xc0 | (uni_ch >> 6))); 765 | } else { 766 | if (uni_ch < 0x10000) { 767 | out.push_back(static_cast(0xe0 | (uni_ch >> 12))); 768 | } else { 769 | out.push_back(static_cast(0xf0 | (uni_ch >> 18))); 770 | out.push_back(static_cast(0x80 | ((uni_ch >> 12) & 0x3f))); 771 | } 772 | out.push_back(static_cast(0x80 | ((uni_ch >> 6) & 0x3f))); 773 | } 774 | out.push_back(static_cast(0x80 | (uni_ch & 0x3f))); 775 | } 776 | return true; 777 | } 778 | 779 | template inline bool _parse_string(String &out, input &in) { 780 | while (1) { 781 | int ch = in.getc(); 782 | if (ch < ' ') { 783 | in.ungetc(); 784 | return false; 785 | } else if (ch == '"') { 786 | return true; 787 | } else if (ch == '\\') { 788 | if ((ch = in.getc()) == -1) { 789 | return false; 790 | } 791 | switch (ch) { 792 | #define MAP(sym, val) \ 793 | case sym: \ 794 | out.push_back(val); \ 795 | break 796 | MAP('"', '\"'); 797 | MAP('\\', '\\'); 798 | MAP('/', '/'); 799 | MAP('b', '\b'); 800 | MAP('f', '\f'); 801 | MAP('n', '\n'); 802 | MAP('r', '\r'); 803 | MAP('t', '\t'); 804 | #undef MAP 805 | case 'u': 806 | if (!_parse_codepoint(out, in)) { 807 | return false; 808 | } 809 | break; 810 | default: 811 | return false; 812 | } 813 | } else { 814 | out.push_back(static_cast(ch)); 815 | } 816 | } 817 | return false; 818 | } 819 | 820 | template inline bool _parse_array(Context &ctx, input &in) { 821 | if (!ctx.parse_array_start()) { 822 | return false; 823 | } 824 | size_t idx = 0; 825 | if (in.expect(']')) { 826 | return ctx.parse_array_stop(idx); 827 | } 828 | do { 829 | if (!ctx.parse_array_item(in, idx)) { 830 | return false; 831 | } 832 | idx++; 833 | } while (in.expect(',')); 834 | return in.expect(']') && ctx.parse_array_stop(idx); 835 | } 836 | 837 | template inline bool _parse_object(Context &ctx, input &in) { 838 | if (!ctx.parse_object_start()) { 839 | return false; 840 | } 841 | if (in.expect('}')) { 842 | return ctx.parse_object_stop(); 843 | } 844 | do { 845 | std::string key; 846 | if (!in.expect('"') || !_parse_string(key, in) || !in.expect(':')) { 847 | return false; 848 | } 849 | if (!ctx.parse_object_item(in, key)) { 850 | return false; 851 | } 852 | } while (in.expect(',')); 853 | return in.expect('}') && ctx.parse_object_stop(); 854 | } 855 | 856 | template inline std::string _parse_number(input &in) { 857 | std::string num_str; 858 | while (1) { 859 | int ch = in.getc(); 860 | if (('0' <= ch && ch <= '9') || ch == '+' || ch == '-' || ch == 'e' || ch == 'E') { 861 | num_str.push_back(static_cast(ch)); 862 | } else if (ch == '.') { 863 | #if PICOJSON_USE_LOCALE 864 | num_str += localeconv()->decimal_point; 865 | #else 866 | num_str.push_back('.'); 867 | #endif 868 | } else { 869 | in.ungetc(); 870 | break; 871 | } 872 | } 873 | return num_str; 874 | } 875 | 876 | template inline bool _parse(Context &ctx, input &in) { 877 | in.skip_ws(); 878 | int ch = in.getc(); 879 | switch (ch) { 880 | #define IS(ch, text, op) \ 881 | case ch: \ 882 | if (in.match(text) && op) { \ 883 | return true; \ 884 | } else { \ 885 | return false; \ 886 | } 887 | IS('n', "ull", ctx.set_null()); 888 | IS('f', "alse", ctx.set_bool(false)); 889 | IS('t', "rue", ctx.set_bool(true)); 890 | #undef IS 891 | case '"': 892 | return ctx.parse_string(in); 893 | case '[': 894 | return _parse_array(ctx, in); 895 | case '{': 896 | return _parse_object(ctx, in); 897 | default: 898 | if (('0' <= ch && ch <= '9') || ch == '-') { 899 | double f; 900 | char *endp; 901 | in.ungetc(); 902 | std::string num_str(_parse_number(in)); 903 | if (num_str.empty()) { 904 | return false; 905 | } 906 | #ifdef PICOJSON_USE_INT64 907 | { 908 | errno = 0; 909 | intmax_t ival = strtoimax(num_str.c_str(), &endp, 10); 910 | if (errno == 0 && std::numeric_limits::min() <= ival && ival <= std::numeric_limits::max() && 911 | endp == num_str.c_str() + num_str.size()) { 912 | ctx.set_int64(ival); 913 | return true; 914 | } 915 | } 916 | #endif 917 | f = strtod(num_str.c_str(), &endp); 918 | if (endp == num_str.c_str() + num_str.size()) { 919 | ctx.set_number(f); 920 | return true; 921 | } 922 | return false; 923 | } 924 | break; 925 | } 926 | in.ungetc(); 927 | return false; 928 | } 929 | 930 | class deny_parse_context { 931 | public: 932 | bool set_null() { 933 | return false; 934 | } 935 | bool set_bool(bool) { 936 | return false; 937 | } 938 | #ifdef PICOJSON_USE_INT64 939 | bool set_int64(int64_t) { 940 | return false; 941 | } 942 | #endif 943 | bool set_number(double) { 944 | return false; 945 | } 946 | template bool parse_string(input &) { 947 | return false; 948 | } 949 | bool parse_array_start() { 950 | return false; 951 | } 952 | template bool parse_array_item(input &, size_t) { 953 | return false; 954 | } 955 | bool parse_array_stop(size_t) { 956 | return false; 957 | } 958 | bool parse_object_start() { 959 | return false; 960 | } 961 | template bool parse_object_item(input &, const std::string &) { 962 | return false; 963 | } 964 | }; 965 | 966 | class default_parse_context { 967 | protected: 968 | value *out_; 969 | size_t depths_; 970 | 971 | public: 972 | default_parse_context(value *out, size_t depths = DEFAULT_MAX_DEPTHS) : out_(out), depths_(depths) { 973 | } 974 | bool set_null() { 975 | *out_ = value(); 976 | return true; 977 | } 978 | bool set_bool(bool b) { 979 | *out_ = value(b); 980 | return true; 981 | } 982 | #ifdef PICOJSON_USE_INT64 983 | bool set_int64(int64_t i) { 984 | *out_ = value(i); 985 | return true; 986 | } 987 | #endif 988 | bool set_number(double f) { 989 | *out_ = value(f); 990 | return true; 991 | } 992 | template bool parse_string(input &in) { 993 | *out_ = value(string_type, false); 994 | return _parse_string(out_->get(), in); 995 | } 996 | bool parse_array_start() { 997 | if (depths_ == 0) 998 | return false; 999 | --depths_; 1000 | *out_ = value(array_type, false); 1001 | return true; 1002 | } 1003 | template bool parse_array_item(input &in, size_t) { 1004 | array &a = out_->get(); 1005 | a.push_back(value()); 1006 | default_parse_context ctx(&a.back(), depths_); 1007 | return _parse(ctx, in); 1008 | } 1009 | bool parse_array_stop(size_t) { 1010 | ++depths_; 1011 | return true; 1012 | } 1013 | bool parse_object_start() { 1014 | if (depths_ == 0) 1015 | return false; 1016 | *out_ = value(object_type, false); 1017 | return true; 1018 | } 1019 | template bool parse_object_item(input &in, const std::string &key) { 1020 | object &o = out_->get(); 1021 | default_parse_context ctx(&o[key], depths_); 1022 | return _parse(ctx, in); 1023 | } 1024 | bool parse_object_stop() { 1025 | ++depths_; 1026 | return true; 1027 | } 1028 | 1029 | private: 1030 | default_parse_context(const default_parse_context &); 1031 | default_parse_context &operator=(const default_parse_context &); 1032 | }; 1033 | 1034 | class null_parse_context { 1035 | protected: 1036 | size_t depths_; 1037 | 1038 | public: 1039 | struct dummy_str { 1040 | void push_back(int) { 1041 | } 1042 | }; 1043 | 1044 | public: 1045 | null_parse_context(size_t depths = DEFAULT_MAX_DEPTHS) : depths_(depths) { 1046 | } 1047 | bool set_null() { 1048 | return true; 1049 | } 1050 | bool set_bool(bool) { 1051 | return true; 1052 | } 1053 | #ifdef PICOJSON_USE_INT64 1054 | bool set_int64(int64_t) { 1055 | return true; 1056 | } 1057 | #endif 1058 | bool set_number(double) { 1059 | return true; 1060 | } 1061 | template bool parse_string(input &in) { 1062 | dummy_str s; 1063 | return _parse_string(s, in); 1064 | } 1065 | bool parse_array_start() { 1066 | if (depths_ == 0) 1067 | return false; 1068 | --depths_; 1069 | return true; 1070 | } 1071 | template bool parse_array_item(input &in, size_t) { 1072 | return _parse(*this, in); 1073 | } 1074 | bool parse_array_stop(size_t) { 1075 | ++depths_; 1076 | return true; 1077 | } 1078 | bool parse_object_start() { 1079 | if (depths_ == 0) 1080 | return false; 1081 | --depths_; 1082 | return true; 1083 | } 1084 | template bool parse_object_item(input &in, const std::string &) { 1085 | ++depths_; 1086 | return _parse(*this, in); 1087 | } 1088 | bool parse_object_stop() { 1089 | return true; 1090 | } 1091 | 1092 | private: 1093 | null_parse_context(const null_parse_context &); 1094 | null_parse_context &operator=(const null_parse_context &); 1095 | }; 1096 | 1097 | // obsolete, use the version below 1098 | template inline std::string parse(value &out, Iter &pos, const Iter &last) { 1099 | std::string err; 1100 | pos = parse(out, pos, last, &err); 1101 | return err; 1102 | } 1103 | 1104 | template inline Iter _parse(Context &ctx, const Iter &first, const Iter &last, std::string *err) { 1105 | input in(first, last); 1106 | if (!_parse(ctx, in) && err != NULL) { 1107 | char buf[64]; 1108 | SNPRINTF(buf, sizeof(buf), "syntax error at line %d near: ", in.line()); 1109 | *err = buf; 1110 | while (1) { 1111 | int ch = in.getc(); 1112 | if (ch == -1 || ch == '\n') { 1113 | break; 1114 | } else if (ch >= ' ') { 1115 | err->push_back(static_cast(ch)); 1116 | } 1117 | } 1118 | } 1119 | return in.cur(); 1120 | } 1121 | 1122 | template inline Iter parse(value &out, const Iter &first, const Iter &last, std::string *err) { 1123 | default_parse_context ctx(&out); 1124 | return _parse(ctx, first, last, err); 1125 | } 1126 | 1127 | inline std::string parse(value &out, const std::string &s) { 1128 | std::string err; 1129 | parse(out, s.begin(), s.end(), &err); 1130 | return err; 1131 | } 1132 | 1133 | inline std::string parse(value &out, std::istream &is) { 1134 | std::string err; 1135 | parse(out, std::istreambuf_iterator(is.rdbuf()), std::istreambuf_iterator(), &err); 1136 | return err; 1137 | } 1138 | 1139 | template struct last_error_t { static std::string s; }; 1140 | template std::string last_error_t::s; 1141 | 1142 | inline void set_last_error(const std::string &s) { 1143 | last_error_t::s = s; 1144 | } 1145 | 1146 | inline const std::string &get_last_error() { 1147 | return last_error_t::s; 1148 | } 1149 | 1150 | inline bool operator==(const value &x, const value &y) { 1151 | if (x.is()) 1152 | return y.is(); 1153 | #define PICOJSON_CMP(type) \ 1154 | if (x.is()) \ 1155 | return y.is() && x.get() == y.get() 1156 | PICOJSON_CMP(bool); 1157 | PICOJSON_CMP(double); 1158 | PICOJSON_CMP(std::string); 1159 | PICOJSON_CMP(array); 1160 | PICOJSON_CMP(object); 1161 | #undef PICOJSON_CMP 1162 | PICOJSON_ASSERT(0); 1163 | #ifdef _MSC_VER 1164 | __assume(0); 1165 | #endif 1166 | return false; 1167 | } 1168 | 1169 | inline bool operator!=(const value &x, const value &y) { 1170 | return !(x == y); 1171 | } 1172 | } 1173 | 1174 | #if !PICOJSON_USE_RVALUE_REFERENCE 1175 | namespace std { 1176 | template <> inline void swap(picojson::value &x, picojson::value &y) { 1177 | x.swap(y); 1178 | } 1179 | } 1180 | #endif 1181 | 1182 | inline std::istream &operator>>(std::istream &is, picojson::value &x) { 1183 | picojson::set_last_error(std::string()); 1184 | const std::string err(picojson::parse(x, is)); 1185 | if (!err.empty()) { 1186 | picojson::set_last_error(err); 1187 | is.setstate(std::ios::failbit); 1188 | } 1189 | return is; 1190 | } 1191 | 1192 | inline std::ostream &operator<<(std::ostream &os, const picojson::value &x) { 1193 | x.serialize(std::ostream_iterator(os)); 1194 | return os; 1195 | } 1196 | #ifdef _MSC_VER 1197 | #pragma warning(pop) 1198 | #endif 1199 | 1200 | #endif 1201 | -------------------------------------------------------------------------------- /crvskkserv/resource.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #ifndef IDC_STATIC 4 | #define IDC_STATIC (-1) 5 | #endif 6 | 7 | #define IDI_CRVSKKSERV 1 8 | 9 | #define IDR_MENU 10 10 | #define IDM_CONFIG 11 11 | #define IDM_EXIT 12 12 | 13 | #define IDD_DIALOG_CONFIG 100 14 | #define IDC_EDIT_SERV_PORT 111 15 | #define IDC_CHECKBOX_SERV_LOOPBACK 112 16 | #define IDC_LIST_SKK_DIC 121 17 | #define IDC_BUTTON_SKK_DIC_ADD 122 18 | #define IDC_BUTTON_SKKSERV_ADD 123 19 | #define IDC_BUTTON_GOOGLECGIAPI_ADD 124 20 | #define IDC_BUTTON_SKK_DIC_DEL 125 21 | #define IDC_BUTTON_SKK_DIC_UP 131 22 | #define IDC_BUTTON_SKK_DIC_DOWN 132 23 | 24 | #define IDD_DIALOG_SKKSRV 200 25 | #define IDC_EDIT_SKKSRV_HOST 211 26 | #define IDC_EDIT_SKKSRV_PORT 212 27 | #define IDC_EDIT_SKKSRV_TIMEOUT 213 28 | 29 | #define IDD_DIALOG_GOOGLECGIAPI 300 30 | #define IDC_EDIT_GOOGLECGIAPI_FILTER 311 31 | #define IDC_EDIT_GOOGLECGIAPI_ANNOTATION 312 32 | #define IDC_EDIT_GOOGLECGIAPI_TIMEOUT 313 33 | #define IDC_RADIO_GOOGLECGIAPI_EUC 314 34 | #define IDC_RADIO_GOOGLECGIAPI_UTF8 315 35 | -------------------------------------------------------------------------------- /crvskkserv/search_dictionary.cpp: -------------------------------------------------------------------------------- 1 |  2 | #include "crvskkserv.h" 3 | 4 | void init_search_dictionary(DICINFO &dicinfo) 5 | { 6 | CHAR buf[DICBUFSIZE]; 7 | std::string sbuf; 8 | int okuri = 0; // default okuri-nasi 9 | MAP map; 10 | 11 | FILE *fpdic = nullptr; 12 | _wfopen_s(&fpdic, dicinfo.path.c_str(), modeRB); 13 | if (fpdic == nullptr) 14 | { 15 | return; 16 | } 17 | 18 | long pos = ftell(fpdic); 19 | 20 | while (true) 21 | { 22 | sbuf.clear(); 23 | 24 | while (fgets(buf, sizeof(buf), fpdic) != nullptr) 25 | { 26 | sbuf += buf; 27 | 28 | if (!sbuf.empty() && sbuf.back() == '\n') 29 | { 30 | break; 31 | } 32 | } 33 | 34 | if (ferror(fpdic) != 0) 35 | { 36 | fclose(fpdic); 37 | return; 38 | } 39 | 40 | if (sbuf.empty()) 41 | { 42 | break; 43 | } 44 | 45 | if (sbuf.compare(EntriesAri) == 0) 46 | { 47 | okuri = 1; 48 | } 49 | else if (sbuf.compare(EntriesNasi) == 0) 50 | { 51 | okuri = 0; 52 | } 53 | else if (okuri != -1) 54 | { 55 | size_t pidx = sbuf.find("\x20/"); 56 | if (pidx != std::string::npos && pidx <= sbuf.size()) 57 | { 58 | map.insert(PAIR(sbuf.substr(0, pidx), pos)); 59 | } 60 | } 61 | 62 | pos = ftell(fpdic); 63 | } 64 | 65 | fclose(fpdic); 66 | 67 | dicinfo.pos.clear(); 68 | for (auto map_itr = map.begin(); map_itr != map.end(); map_itr++) 69 | { 70 | dicinfo.pos.push_back(map_itr->second); 71 | } 72 | } 73 | 74 | void search_dictionary(DICINFO &dicinfo, const std::string &key, std::string &s) 75 | { 76 | CHAR buf[DICBUFSIZE]; 77 | std::string ckey, sbuf, kbuf, cbuf; 78 | 79 | FILE *fpdic = nullptr; 80 | _wfopen_s(&fpdic, dicinfo.path.c_str(), modeRB); 81 | if (fpdic == nullptr) 82 | { 83 | return; 84 | } 85 | 86 | ckey = key + "\x20"; 87 | 88 | long left = 0; 89 | long right = (long)dicinfo.pos.size() - 1; 90 | 91 | while (left <= right) 92 | { 93 | long mid = left + (right - left) / 2; 94 | long pos = dicinfo.pos[mid]; 95 | fseek(fpdic, pos, SEEK_SET); 96 | 97 | sbuf.clear(); 98 | kbuf.clear(); 99 | cbuf.clear(); 100 | 101 | while (fgets(buf, _countof(buf), fpdic) != nullptr) 102 | { 103 | sbuf += buf; 104 | 105 | if (!sbuf.empty() && sbuf.back() == '\n') 106 | { 107 | break; 108 | } 109 | } 110 | 111 | if (ferror(fpdic) != 0) 112 | { 113 | fclose(fpdic); 114 | return; 115 | } 116 | 117 | if (sbuf.empty()) 118 | { 119 | break; 120 | } 121 | 122 | // LF 123 | if (sbuf.back() != '\n') 124 | { 125 | sbuf.push_back('\n'); 126 | } 127 | 128 | size_t cidx = sbuf.find("\x20/"); 129 | if (cidx != std::wstring::npos && cidx < sbuf.size()) 130 | { 131 | kbuf = sbuf.substr(0, cidx + 1); 132 | cbuf = sbuf.substr(cidx + 1); 133 | } 134 | 135 | int cmpkey = ckey.compare(kbuf); 136 | if (cmpkey == 0) 137 | { 138 | s = cbuf; 139 | break; 140 | } 141 | else if (cmpkey > 0) 142 | { 143 | left = mid + 1; 144 | } 145 | else 146 | { 147 | right = mid - 1; 148 | } 149 | } 150 | 151 | fclose(fpdic); 152 | } 153 | -------------------------------------------------------------------------------- /crvskkserv/search_google_cgiapi.cpp: -------------------------------------------------------------------------------- 1 |  2 | #include "crvskkserv.h" 3 | #include "eucjis2004.h" 4 | #include "eucjp.h" 5 | #include "utf8.h" 6 | #include "picojson.h" 7 | 8 | // https://www.google.co.jp/ime/cgiapi.html 9 | 10 | LPCWSTR useragent = L"Mozilla/5.0 (compatible; " APP_TITLE L"/" APP_VERSION L")"; 11 | 12 | void split_google_cgiapi_path(DICINFO &dicinfo, std::wstring &filter, std::wstring &comment, std::wstring &timeout, std::wstring &encoding) 13 | { 14 | size_t is, ie; 15 | 16 | is = 0; 17 | ie = dicinfo.path.find_first_of(INIVAL_GOOGLECGIAPI, is); 18 | is = ie + 1; 19 | ie = dicinfo.path.find_first_of(INIVAL_SVR_SEP, is); 20 | is = ie + 1; 21 | ie = dicinfo.path.find_first_of(INIVAL_SVR_SEP, is); 22 | filter = dicinfo.path.substr(is, ie - is); 23 | is = ie + 1; 24 | ie = dicinfo.path.find_first_of(INIVAL_SVR_SEP, is); 25 | comment = dicinfo.path.substr(is, ie - is); 26 | is = ie + 1; 27 | ie = dicinfo.path.find_first_of(INIVAL_SVR_SEP, is); 28 | timeout = dicinfo.path.substr(is, ie - is); 29 | is = ie + 1; 30 | ie = dicinfo.path.find_first_of(INIVAL_SVR_SEP, is); 31 | encoding = dicinfo.path.substr(is, ie - is); 32 | } 33 | 34 | void search_google_cgiapi(DICINFO &dicinfo, const std::string &key, std::string &s) 35 | { 36 | WCHAR url[INTERNET_MAX_URL_LENGTH]; 37 | std::wstring filter, annotation, timeout, encoding; 38 | std::wstring wkey; 39 | std::string ckey; 40 | 41 | //接続情報取得 42 | split_google_cgiapi_path(dicinfo, filter, annotation, timeout, encoding); 43 | 44 | //文字コードチェック、UTF-8変換 45 | if (encoding == inival_googlecgiapi_encoding_euc) 46 | { 47 | wkey = eucjis2004_string_to_wstring(key); 48 | if (wkey.empty()) 49 | { 50 | return; 51 | } 52 | ckey = wstring_to_utf8_string(wkey); 53 | } 54 | else if (encoding == inival_googlecgiapi_encoding_utf8) 55 | { 56 | ckey = key; 57 | wkey = utf8_string_to_wstring(ckey); 58 | if (wkey.empty()) 59 | { 60 | return; 61 | } 62 | } 63 | else 64 | { 65 | return; 66 | } 67 | 68 | //検索除外 69 | try 70 | { 71 | if (std::regex_match(wkey, std::wregex(filter))) 72 | { 73 | return; 74 | } 75 | } 76 | catch (...) 77 | { 78 | return; 79 | } 80 | 81 | DWORD dwTimeout = wcstoul(timeout.c_str(), nullptr, 0); 82 | if (dwTimeout == 0 || dwTimeout == ULONG_MAX) 83 | { 84 | dwTimeout = wcstoul(inival_def_timeout, nullptr, 0); 85 | } 86 | 87 | { 88 | _snwprintf_s(url, _TRUNCATE, L"%s", googlecgiapi_url_prefix); 89 | 90 | WCHAR pe[4]; 91 | 92 | for (size_t i = 0; i < ckey.size(); i++) 93 | { 94 | _snwprintf_s(pe, _TRUNCATE, L"%%%02X", (BYTE)ckey[i]); 95 | wcsncat_s(url, pe, _TRUNCATE); 96 | } 97 | 98 | std::string suffix = wstring_to_utf8_string(std::wstring(googlecgiapi_url_suffix)); 99 | for (size_t i = 0; i < suffix.size(); i++) 100 | { 101 | _snwprintf_s(pe, _TRUNCATE, L"%%%02X", (BYTE)suffix[i]); 102 | wcsncat_s(url, pe, _TRUNCATE); 103 | } 104 | } 105 | 106 | std::string res; 107 | 108 | HINTERNET hInet = InternetOpenW(useragent, INTERNET_OPEN_TYPE_PRECONFIG, nullptr, nullptr, 0); 109 | if (hInet != nullptr) 110 | { 111 | InternetSetOptionW(hInet, INTERNET_OPTION_CONNECT_TIMEOUT, &dwTimeout, sizeof(dwTimeout)); 112 | InternetSetOptionW(hInet, INTERNET_OPTION_SEND_TIMEOUT, &dwTimeout, sizeof(dwTimeout)); 113 | InternetSetOptionW(hInet, INTERNET_OPTION_RECEIVE_TIMEOUT, &dwTimeout, sizeof(dwTimeout)); 114 | 115 | HINTERNET hUrl = InternetOpenUrlW(hInet, url, nullptr, 0, 0, 0); 116 | if (hUrl != nullptr) 117 | { 118 | CHAR rbuf[RBUFSIZE]; 119 | 120 | while (true) 121 | { 122 | DWORD bytesRead = 0; 123 | ZeroMemory(rbuf, sizeof(rbuf)); 124 | BOOL retRead = InternetReadFile(hUrl, rbuf, sizeof(rbuf) - 1, &bytesRead); 125 | if (retRead) 126 | { 127 | if (bytesRead == 0) break; 128 | } 129 | else 130 | { 131 | InternetCloseHandle(hUrl); 132 | InternetCloseHandle(hInet); 133 | return; 134 | } 135 | 136 | res.append(rbuf, bytesRead); 137 | } 138 | InternetCloseHandle(hUrl); 139 | } 140 | InternetCloseHandle(hInet); 141 | } 142 | 143 | std::vector vws; 144 | 145 | // Example 146 | // [["こうし",["講師","格子","行使","公私","こうし"]]] 147 | 148 | picojson::value json_value; 149 | const std::string json_err = picojson::parse(json_value, res); 150 | 151 | if (json_err.empty()) 152 | { 153 | if (json_value.is()) 154 | { 155 | const picojson::array &json_array_1 = json_value.get(); 156 | 157 | for (const auto &json_value_1 : json_array_1) 158 | { 159 | if (json_value_1.is()) 160 | { 161 | const picojson::array &json_array_2 = json_value_1.get(); 162 | 163 | bool key_hit = false; 164 | 165 | for (const auto &json_value_2 : json_array_2) 166 | { 167 | if (json_value_2.is()) 168 | { 169 | // key 170 | key_hit = (json_value_2.get() == wstring_to_utf8_string(wkey)); 171 | } 172 | else if (json_value_2.is()) 173 | { 174 | const picojson::array &json_array_3 = json_value_2.get(); 175 | 176 | for (const auto &json_value_3 : json_array_3) 177 | { 178 | if (key_hit && json_value_3.is()) 179 | { 180 | // entry 181 | vws.push_back(utf8_string_to_wstring(json_value_3.get())); 182 | } 183 | } 184 | } 185 | } 186 | } 187 | } 188 | } 189 | } 190 | 191 | std::wregex wreg; 192 | std::wstring wfmt; 193 | std::wsmatch wres; 194 | 195 | std::wstring ws = L"/"; 196 | for (std::wstring &c : vws) 197 | { 198 | // 制御文字 199 | wreg = L"[\\x00-\\x19]"; 200 | wfmt = L""; 201 | c = std::regex_replace(c, wreg, wfmt); 202 | 203 | if (c.find_first_of(L"/") != std::wstring::npos || 204 | c.find_first_of(L";") != std::wstring::npos) 205 | { 206 | wreg = L"/"; 207 | wfmt = L"\\057"; 208 | c = std::regex_replace(c, wreg, wfmt); 209 | wreg = L";"; 210 | wfmt = L"\\073"; 211 | c = std::regex_replace(c, wreg, wfmt); 212 | 213 | c = L"(concat \"" + c + L"\")"; 214 | } 215 | 216 | ws += c; 217 | if (!annotation.empty()) 218 | { 219 | ws += L";" + annotation; 220 | } 221 | ws += L"/"; 222 | } 223 | ws += L"\n"; 224 | 225 | std::wstring ws_tmp = ws; 226 | wreg = L"/[^/]+"; 227 | while (std::regex_search(ws_tmp, wres, wreg)) 228 | { 229 | if (encoding == inival_googlecgiapi_encoding_euc) 230 | { 231 | std::string c = wstring_to_eucjis2004_string(wres.str()); 232 | if (c.empty()) 233 | { 234 | c = wstring_to_eucjp_string(wres.str()); 235 | } 236 | s += c; 237 | } 238 | else if (encoding == inival_googlecgiapi_encoding_utf8) 239 | { 240 | s += wstring_to_utf8_string(wres.str()); 241 | } 242 | ws_tmp = wres.suffix(); 243 | } 244 | } 245 | -------------------------------------------------------------------------------- /crvskkserv/search_skkserv.cpp: -------------------------------------------------------------------------------- 1 |  2 | #include "crvskkserv.h" 3 | 4 | void search_skkserv(DICINFO &dicinfo, const std::string &key, std::string &s) 5 | { 6 | std::string res, ckey; 7 | CHAR rbuf[RBUFSIZE]; 8 | int n; 9 | 10 | if (dicinfo.sock == INVALID_SOCKET) 11 | { 12 | connect_skkserv(dicinfo); 13 | } 14 | 15 | if (!get_skkserv_version(dicinfo.sock)) 16 | { 17 | return; 18 | } 19 | 20 | ckey.push_back(REQ_KEY); 21 | ckey += key + "\x20"; 22 | if (send(dicinfo.sock, ckey.c_str(), (int)ckey.size(), 0) == SOCKET_ERROR) 23 | { 24 | disconnect(dicinfo.sock); 25 | return; 26 | } 27 | 28 | while (true) 29 | { 30 | ZeroMemory(rbuf, sizeof(rbuf)); 31 | n = recv(dicinfo.sock, rbuf, sizeof(rbuf) - 1, 0); 32 | if (n == SOCKET_ERROR || n <= 0) 33 | { 34 | disconnect(dicinfo.sock); 35 | return; 36 | } 37 | 38 | res.append(rbuf); 39 | 40 | if (n <= _countof(rbuf) && rbuf[n - 1] == '\n') 41 | { 42 | break; 43 | } 44 | } 45 | 46 | if (res.size() > 2 && res.front() == REP_FOUND) 47 | { 48 | s = res.substr(1); 49 | } 50 | } 51 | 52 | void split_skkserv_path(DICINFO &dicinfo, std::wstring &host, std::wstring &port, std::wstring &timeout) 53 | { 54 | size_t is, ie; 55 | 56 | is = 0; 57 | ie = dicinfo.path.find_first_of(INIVAL_SKKSERV, is); 58 | is = ie + 1; 59 | ie = dicinfo.path.find_first_of(INIVAL_SVR_SEP, is); 60 | is = ie + 1; 61 | ie = dicinfo.path.find_first_of(INIVAL_SVR_SEP, is); 62 | host = dicinfo.path.substr(is, ie - is); 63 | is = ie + 1; 64 | ie = dicinfo.path.find_first_of(INIVAL_SVR_SEP, is); 65 | port = dicinfo.path.substr(is, ie - is); 66 | is = ie + 1; 67 | ie = dicinfo.path.find_first_of(INIVAL_SVR_SEP, is); 68 | timeout = dicinfo.path.substr(is, ie - is); 69 | } 70 | 71 | void connect_skkserv(DICINFO &dicinfo) 72 | { 73 | ADDRINFOW aiwHints; 74 | ADDRINFOW *paiwResult; 75 | ADDRINFOW *paiw; 76 | u_long mode; 77 | timeval tv = {}; 78 | fd_set fdw = {}, fde = {}; 79 | std::wstring host, port, timeout; 80 | DWORD dwTimeout; 81 | 82 | split_skkserv_path(dicinfo, host, port, timeout); 83 | 84 | dwTimeout = wcstoul(timeout.c_str(), nullptr, 0); 85 | if (dwTimeout == 0 || dwTimeout == ULONG_MAX) 86 | { 87 | dwTimeout = wcstoul(inival_def_timeout, nullptr, 0); 88 | } 89 | 90 | ZeroMemory(&aiwHints, sizeof(aiwHints)); 91 | aiwHints.ai_family = AF_UNSPEC; 92 | aiwHints.ai_socktype = SOCK_STREAM; 93 | aiwHints.ai_protocol = IPPROTO_TCP; 94 | 95 | if (GetAddrInfoW(host.c_str(), port.c_str(), &aiwHints, &paiwResult) != 0) 96 | { 97 | return; 98 | } 99 | 100 | for (paiw = paiwResult; paiw != nullptr; paiw = paiw->ai_next) 101 | { 102 | dicinfo.sock = socket(paiw->ai_family, paiw->ai_socktype, paiw->ai_protocol); 103 | if (dicinfo.sock == INVALID_SOCKET) 104 | { 105 | continue; 106 | } 107 | 108 | if (setsockopt(dicinfo.sock, SOL_SOCKET, SO_SNDTIMEO, (const char *)&dwTimeout, sizeof(dwTimeout)) == SOCKET_ERROR) 109 | { 110 | closesocket(dicinfo.sock); 111 | dicinfo.sock = INVALID_SOCKET; 112 | continue; 113 | } 114 | if (setsockopt(dicinfo.sock, SOL_SOCKET, SO_RCVTIMEO, (const char *)&dwTimeout, sizeof(dwTimeout)) == SOCKET_ERROR) 115 | { 116 | closesocket(dicinfo.sock); 117 | dicinfo.sock = INVALID_SOCKET; 118 | continue; 119 | } 120 | 121 | mode = 1; 122 | ioctlsocket(dicinfo.sock, FIONBIO, &mode); 123 | 124 | if (connect(dicinfo.sock, paiw->ai_addr, (int)paiw->ai_addrlen) == SOCKET_ERROR) 125 | { 126 | if (WSAGetLastError() != WSAEWOULDBLOCK) 127 | { 128 | closesocket(dicinfo.sock); 129 | dicinfo.sock = INVALID_SOCKET; 130 | continue; 131 | } 132 | } 133 | 134 | mode = 0; 135 | ioctlsocket(dicinfo.sock, FIONBIO, &mode); 136 | 137 | tv.tv_sec = dwTimeout / 1000; 138 | tv.tv_usec = (dwTimeout % 1000) * 1000; 139 | 140 | FD_ZERO(&fdw); 141 | FD_ZERO(&fde); 142 | FD_SET(dicinfo.sock, &fdw); 143 | FD_SET(dicinfo.sock, &fde); 144 | 145 | select(0, nullptr, &fdw, &fde, &tv); 146 | if (FD_ISSET(dicinfo.sock, &fdw)) 147 | { 148 | break; 149 | } 150 | 151 | disconnect(dicinfo.sock); 152 | } 153 | 154 | FreeAddrInfoW(paiwResult); 155 | } 156 | 157 | BOOL get_skkserv_version(SOCKET &sock) 158 | { 159 | BOOL bRet = TRUE; 160 | int n; 161 | CHAR rbuf[RBUFSIZE]; 162 | CHAR sbuf = REQ_VER; 163 | std::string res; 164 | 165 | if (send(sock, &sbuf, 1, 0) == SOCKET_ERROR) 166 | { 167 | disconnect(sock); 168 | bRet = FALSE; 169 | } 170 | else 171 | { 172 | while (true) 173 | { 174 | ZeroMemory(rbuf, sizeof(rbuf)); 175 | n = recv(sock, rbuf, sizeof(rbuf) - 1, 0); 176 | if (n == SOCKET_ERROR || n <= 0) 177 | { 178 | disconnect(sock); 179 | bRet = FALSE; 180 | break; 181 | } 182 | 183 | if (rbuf[n - 1] == '\x20') 184 | { 185 | break; 186 | } 187 | } 188 | } 189 | 190 | return bRet; 191 | } 192 | -------------------------------------------------------------------------------- /crvskkserv/server.cpp: -------------------------------------------------------------------------------- 1 |  2 | #include "crvskkserv.h" 3 | #include "utf8.h" 4 | 5 | int make_serv_sock(SERVINFO *servinfo, int servinfonum) 6 | { 7 | ADDRINFOW aiwHints; 8 | ADDRINFOW *paiwResult; 9 | ADDRINFOW *paiw; 10 | int i; 11 | BOOL use = TRUE; 12 | 13 | ZeroMemory(&aiwHints, sizeof(aiwHints)); 14 | if (!serv_loopback) 15 | { 16 | aiwHints.ai_flags = AI_PASSIVE; 17 | } 18 | aiwHints.ai_family = AF_UNSPEC; 19 | aiwHints.ai_socktype = SOCK_STREAM; 20 | aiwHints.ai_protocol = IPPROTO_TCP; 21 | 22 | if (GetAddrInfoW(nullptr, serv_port, &aiwHints, &paiwResult) != 0) 23 | { 24 | return 0; 25 | } 26 | 27 | for (i = 0, paiw = paiwResult; (i < servinfonum) && (paiw != nullptr); paiw = paiw->ai_next) 28 | { 29 | servinfo[i].sock = socket(paiw->ai_family, paiw->ai_socktype, paiw->ai_protocol); 30 | if (servinfo[i].sock == INVALID_SOCKET) 31 | { 32 | continue; 33 | } 34 | 35 | if (setsockopt(servinfo[i].sock, SOL_SOCKET, SO_REUSEADDR, 36 | (const char *)&use, sizeof(use)) == SOCKET_ERROR) 37 | { 38 | disconnect(servinfo[i].sock); 39 | continue; 40 | } 41 | 42 | if (bind(servinfo[i].sock, paiw->ai_addr, (int)paiw->ai_addrlen) == SOCKET_ERROR) 43 | { 44 | disconnect(servinfo[i].sock); 45 | continue; 46 | } 47 | 48 | if (listen(servinfo[i].sock, 1) == SOCKET_ERROR) 49 | { 50 | disconnect(servinfo[i].sock); 51 | continue; 52 | } 53 | 54 | servinfo[i].live = TRUE; 55 | i++; 56 | } 57 | 58 | FreeAddrInfoW(paiwResult); 59 | return i; 60 | } 61 | 62 | void disconnect(SOCKET &sock) 63 | { 64 | if (sock != INVALID_SOCKET) 65 | { 66 | shutdown(sock, SD_BOTH); 67 | closesocket(sock); 68 | sock = INVALID_SOCKET; 69 | } 70 | } 71 | 72 | void comm(SOCKET &sock) 73 | { 74 | CHAR rbuf[RBUFSIZE]; 75 | std::string sbuf, ckey, s, res; 76 | int i, n; 77 | BOOL recvflag = TRUE; 78 | 79 | while (recvflag) 80 | { 81 | ZeroMemory(rbuf, sizeof(rbuf)); 82 | n = recv(sock, rbuf, sizeof(rbuf) - 1, 0); 83 | if (n == SOCKET_ERROR || n <= 0) 84 | { 85 | disconnect(sock); 86 | return; 87 | } 88 | 89 | sbuf += rbuf; 90 | 91 | if (sbuf.empty()) 92 | { 93 | disconnect(sock); 94 | return; 95 | } 96 | 97 | switch (sbuf.front()) 98 | { 99 | case REQ_KEY: 100 | case REQ_CMP: 101 | if (rbuf[n - 1] == '\x20') 102 | { 103 | recvflag = FALSE; 104 | } 105 | break; 106 | case REQ_END: 107 | case REQ_VER: 108 | case REQ_HST: 109 | default: 110 | recvflag = FALSE; 111 | break; 112 | } 113 | } 114 | 115 | switch (sbuf.front()) 116 | { 117 | case REQ_END: 118 | disconnect(sock); 119 | return; 120 | break; 121 | 122 | case REQ_KEY: 123 | if (sbuf.size() > 2) 124 | { 125 | ckey = sbuf.substr(1, sbuf.size() - 2); 126 | n = (int)vdicinfo.size(); 127 | for (i = 0; i < n; i++) 128 | { 129 | s.clear(); 130 | 131 | if (vdicinfo[i].path.compare(0, wcslen(INIVAL_SKKSERV), INIVAL_SKKSERV) == 0) 132 | { 133 | search_skkserv(vdicinfo[i], ckey, s); 134 | } 135 | else if (vdicinfo[i].path.compare(0, wcslen(INIVAL_GOOGLECGIAPI), INIVAL_GOOGLECGIAPI) == 0) 136 | { 137 | search_google_cgiapi(vdicinfo[i], ckey, s); 138 | } 139 | else 140 | { 141 | search_dictionary(vdicinfo[i], ckey, s); 142 | } 143 | 144 | if (!s.empty()) 145 | { 146 | if (res.size() >= 2) 147 | { 148 | res.pop_back(); // '\n' 149 | res.pop_back(); // '/' 150 | } 151 | res += s; 152 | } 153 | } 154 | } 155 | 156 | if (res.empty()) 157 | { 158 | res.push_back(REP_NOT_FOUND); 159 | res.push_back('\n'); 160 | } 161 | else 162 | { 163 | res.insert(res.begin(), REP_FOUND); 164 | } 165 | break; 166 | 167 | case REQ_VER: 168 | res = resver; 169 | break; 170 | 171 | case REQ_HST: 172 | { 173 | CHAR host[NI_MAXHOST]; 174 | SOCKADDR_STORAGE sa = {}; 175 | int len = sizeof(sa); 176 | if (getsockname(sock, (LPSOCKADDR)&sa, &len) == 0) 177 | { 178 | if (getnameinfo((LPSOCKADDR)&sa, len, host, _countof(host), nullptr, 0, NI_NAMEREQD) == 0) 179 | { 180 | res += host; 181 | res += "/"; 182 | } 183 | if (getnameinfo((LPSOCKADDR)&sa, len, host, _countof(host), nullptr, 0, NI_NUMERICHOST) == 0) 184 | { 185 | if (sa.ss_family == AF_INET6) res += "["; 186 | res += host; 187 | if (sa.ss_family == AF_INET6) res += "]"; 188 | res += ":"; 189 | res += WCTOU8(serv_port); 190 | res += "/\x20"; 191 | } 192 | } 193 | } 194 | break; 195 | 196 | case REQ_CMP: 197 | res.push_back(REP_NOT_FOUND); 198 | res.push_back('\n'); 199 | break; 200 | 201 | default: 202 | return; 203 | break; 204 | } 205 | 206 | if (send(sock, res.c_str(), (int)res.size(), 0) == SOCKET_ERROR) 207 | { 208 | disconnect(sock); 209 | return; 210 | } 211 | } 212 | 213 | void comm_thread(void *p) 214 | { 215 | SERVINFO *pcinfo = (SERVINFO *)p; 216 | 217 | while (true) 218 | { 219 | comm(pcinfo->sock); 220 | if (pcinfo->sock == INVALID_SOCKET) 221 | { 222 | pcinfo->live = FALSE; 223 | break; 224 | } 225 | } 226 | } 227 | 228 | void listen_thread(void *p) 229 | { 230 | SERVINFO *pservinfo = (SERVINFO *)p; 231 | SERVINFO cinfo[FD_SETSIZE] = {}; 232 | SOCKADDR_STORAGE sockaddr = {}; 233 | int i, sockaddrlen; 234 | 235 | for (i = 0; i < FD_SETSIZE; i++) 236 | { 237 | cinfo[i].live = FALSE; 238 | cinfo[i].sock = INVALID_SOCKET; 239 | } 240 | 241 | while (true) 242 | { 243 | for (i = 0; i < FD_SETSIZE; i++) 244 | { 245 | if (cinfo[i].sock == INVALID_SOCKET) 246 | { 247 | break; 248 | } 249 | } 250 | if (i == FD_SETSIZE) 251 | { 252 | Sleep(100); 253 | continue; 254 | } 255 | 256 | sockaddrlen = sizeof(sockaddr); 257 | cinfo[i].sock = accept(pservinfo->sock, (LPSOCKADDR)&sockaddr, &sockaddrlen); 258 | if (cinfo[i].sock == INVALID_SOCKET) 259 | { 260 | disconnect(pservinfo->sock); 261 | for (i = 0; i < FD_SETSIZE; i++) 262 | { 263 | disconnect(cinfo[i].sock); 264 | } 265 | for (i = 0; i < FD_SETSIZE; i++) 266 | { 267 | while (cinfo[i].live) 268 | { 269 | Sleep(10); 270 | } 271 | } 272 | pservinfo->live = FALSE; 273 | break; 274 | } 275 | else 276 | { 277 | cinfo[i].live = TRUE; 278 | _beginthread(comm_thread, 0, &cinfo[i]); 279 | } 280 | } 281 | } 282 | -------------------------------------------------------------------------------- /crvskkserv/utf8.cpp: -------------------------------------------------------------------------------- 1 |  2 | std::string wstring_to_utf8_string(const std::wstring &s) 3 | { 4 | std::string ret; 5 | 6 | int len = WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, s.c_str(), -1, nullptr, 0, nullptr, nullptr); 7 | if (len > 0) 8 | { 9 | try 10 | { 11 | LPSTR utf8 = new CHAR[len]; 12 | if (WideCharToMultiByte(CP_UTF8, 0, s.c_str(), -1, utf8, len, nullptr, nullptr) > 0) 13 | { 14 | ret = utf8; 15 | } 16 | delete[] utf8; 17 | } 18 | catch (...) 19 | { 20 | } 21 | } 22 | 23 | return ret; 24 | } 25 | 26 | std::wstring utf8_string_to_wstring(const std::string &s) 27 | { 28 | std::wstring ret; 29 | 30 | int len = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, s.c_str(), -1, nullptr, 0); 31 | if (len > 0) 32 | { 33 | try 34 | { 35 | LPWSTR wcs = new WCHAR[len]; 36 | if (MultiByteToWideChar(CP_UTF8, 0, s.c_str(), -1, wcs, len) > 0) 37 | { 38 | ret = wcs; 39 | } 40 | delete[] wcs; 41 | } 42 | catch (...) 43 | { 44 | } 45 | } 46 | 47 | return ret; 48 | } 49 | -------------------------------------------------------------------------------- /crvskkserv/utf8.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | std::string wstring_to_utf8_string(const std::wstring &s); 4 | std::wstring utf8_string_to_wstring(const std::string &s); 5 | 6 | #define WCTOU8(w) wstring_to_utf8_string(w).c_str() 7 | #define U8TOWC(u) utf8_string_to_wstring(u).c_str() 8 | --------------------------------------------------------------------------------