diff --git a/windows/src/developer/Makefile b/windows/src/developer/Makefile index 305867d869..cd56b60e4b 100644 --- a/windows/src/developer/Makefile +++ b/windows/src/developer/Makefile @@ -3,7 +3,7 @@ # -TARGETS=kmcmpdll kmcomp kmanalyze kmconvert tike samples setup inst +TARGETS=kmcmpdll kmcomp kmanalyze kmconvert tike samples setup inst kmdecomp MANIFESTS=kmcomp tike setup CLEANS=clean-developer @@ -19,6 +19,10 @@ kmcmpdll: cd $(ROOT)\src\developer\kmcmpdll $(MAKE) $(TARGET) +kmdecomp: + cd $(ROOT)\src\developer\kmdecomp + $(MAKE) $(TARGET) + kmcomp: kmcmpdll cd $(ROOT)\src\developer\kmcomp $(MAKE) $(TARGET) diff --git a/windows/src/developer/history.md b/windows/src/developer/history.md index 234b453403..efd53c26ed 100644 --- a/windows/src/developer/history.md +++ b/windows/src/developer/history.md @@ -2,6 +2,7 @@ ## 13.0 alpha * Start version 13.0 +* Feature: Add unsupported kmdecomp decompiler utility (#2419) ## 2019-11-18 12.0.55 stable * Bug Fix: Some keyboards were incorrectly marked as mobile-capable (#2334) diff --git a/windows/src/developer/inst/kmdev.wxs b/windows/src/developer/inst/kmdev.wxs index bb285d5237..823460b18e 100644 --- a/windows/src/developer/inst/kmdev.wxs +++ b/windows/src/developer/inst/kmdev.wxs @@ -166,6 +166,14 @@ + + + + + + + + diff --git a/windows/src/developer/kmdecomp/Makefile b/windows/src/developer/kmdecomp/Makefile new file mode 100644 index 0000000000..4fa5b3ef8e --- /dev/null +++ b/windows/src/developer/kmdecomp/Makefile @@ -0,0 +1,28 @@ +# +# kmdecomp Makefile +# + +!include ..\..\Defines.mak + + +build: version.res dirs + $(MSBUILD) kmdecomp.sln $(MSBUILD_BUILD) /p:Platform=Win32 + $(COPY) $(WIN32_TARGET_PATH)\kmdecomp.exe $(PROGRAM)\developer + $(COPY) $(WIN32_TARGET_PATH)\kmdecomp.pdb $(DEBUGPATH)\developer + +clean: def-clean + $(MSBUILD) kmdecomp.sln $(MSBUILD_CLEAN) + +signcode: + $(SIGNCODE) /d "Keyman Developer Decompiler" $(PROGRAM)\developer\kmdecomp.exe + +backup: + $(WZZIP) $(BUILD)\developer\kmdecomp.zip $(BACKUPDEFAULTS) $(PROGRAM)\developer\kmdecomp.exe + +test-manifest: + @rem This target needed as dependency for KMDECOMP + +install: + $(COPY) $(PROGRAM)\developer\kmdecomp.exe "$(INSTALLPATH_KEYMANDEVELOPER)\kmdecomp.exe" + +!include ..\..\Target.mak diff --git a/windows/src/support/kmdecomp/crc32.cpp b/windows/src/developer/kmdecomp/crc32.cpp similarity index 100% rename from windows/src/support/kmdecomp/crc32.cpp rename to windows/src/developer/kmdecomp/crc32.cpp diff --git a/windows/src/support/kmdecomp/kmdecomp.cpp b/windows/src/developer/kmdecomp/kmdecomp.cpp similarity index 95% rename from windows/src/support/kmdecomp/kmdecomp.cpp rename to windows/src/developer/kmdecomp/kmdecomp.cpp index 4d9d5a46db..b7fa693687 100644 --- a/windows/src/support/kmdecomp/kmdecomp.cpp +++ b/windows/src/developer/kmdecomp/kmdecomp.cpp @@ -57,9 +57,9 @@ int main(int argc, char *argv[]) if(!LoadKeyboard(argv[1], &kbd, &lpBitmap, &cbBitmap)) return 2; - _splitpath(argv[1], drive, dir, filename, NULL); - _makepath(buf, drive, dir, filename, ".kmn"); - _makepath(buf2, drive, dir, filename, ".bmp"); + _splitpath_s(argv[1], drive, _MAX_DRIVE, dir, _MAX_DIR, filename, _MAX_FNAME, NULL, 0); + _makepath_s(buf, _MAX_PATH, drive, dir, filename, ".kmn"); + _makepath_s(buf2, _MAX_PATH, drive, dir, filename, ".bmp"); int n = SaveKeyboardSource(kbd, lpBitmap, cbBitmap, buf, buf2); diff --git a/windows/src/developer/kmdecomp/kmdecomp.md b/windows/src/developer/kmdecomp/kmdecomp.md new file mode 100644 index 0000000000..7a7bbc3ca6 --- /dev/null +++ b/windows/src/developer/kmdecomp/kmdecomp.md @@ -0,0 +1,9 @@ +# kmdecomp Keyman Decompiler + +This unsupported utility decompiles a Keyman .kmx keyboard. +It will produce a .kmn source file and optionally a .ico or +.bmp image. The source file may not contain symbols and will +include optimisations that were made by the compiler such as +expanding `any()` rules in key components into multiple rules. + +Usage: kmdecomp diff --git a/windows/src/support/kmdecomp/kmdecomp.sln b/windows/src/developer/kmdecomp/kmdecomp.sln similarity index 100% rename from windows/src/support/kmdecomp/kmdecomp.sln rename to windows/src/developer/kmdecomp/kmdecomp.sln diff --git a/windows/src/support/kmdecomp/kmdecomp.vcxproj b/windows/src/developer/kmdecomp/kmdecomp.vcxproj similarity index 87% rename from windows/src/support/kmdecomp/kmdecomp.vcxproj rename to windows/src/developer/kmdecomp/kmdecomp.vcxproj index efea591be5..11433424c0 100644 --- a/windows/src/support/kmdecomp/kmdecomp.vcxproj +++ b/windows/src/developer/kmdecomp/kmdecomp.vcxproj @@ -41,11 +41,8 @@ <_ProjectFileVersion>10.0.30319.1 - .\Debug\ - .\Debug\ + $(Platform)\$(Configuration)\ true - .\Release\ - .\Release\ false AllRules.ruleset @@ -54,6 +51,13 @@ + + $(SolutionDir)$(Platform)\$(Configuration)\ + $(Platform)\$(Configuration)\ + + + $(SolutionDir)$(Platform)\$(Configuration)\ + .\Debug/kmdecomp.tlb @@ -64,13 +68,8 @@ Disabled ..\..\global\inc;..\..\resellers;%(AdditionalIncludeDirectories) WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) - true EnableFastChecks MultiThreadedDebug - .\Debug/kmdecomp.pch - .\Debug/ - .\Debug/ - .\Debug/ Level3 true EditAndContinue @@ -80,10 +79,8 @@ 0x0c09 - .\Debug/kmdecomp.exe true true - .\Debug/kmdecomp.pdb Console MachineX86 true @@ -107,10 +104,6 @@ true MultiThreaded true - .\Release/kmdecomp.pch - .\Release/ - .\Release/ - .\Release/ Level3 true true @@ -120,9 +113,7 @@ 0x0c09 - .\Release/kmdecomp.exe true - .\Release/kmdecomp.pdb Console MachineX86 true @@ -152,6 +143,9 @@ %(PreprocessorDefinitions) + + + diff --git a/windows/src/support/kmdecomp/kmdecomp.vcxproj.filters b/windows/src/developer/kmdecomp/kmdecomp.vcxproj.filters similarity index 89% rename from windows/src/support/kmdecomp/kmdecomp.vcxproj.filters rename to windows/src/developer/kmdecomp/kmdecomp.vcxproj.filters index ed410a7c7b..20bb3504a7 100644 --- a/windows/src/support/kmdecomp/kmdecomp.vcxproj.filters +++ b/windows/src/developer/kmdecomp/kmdecomp.vcxproj.filters @@ -25,4 +25,9 @@ Source Files + + + Source Files + + \ No newline at end of file diff --git a/windows/src/support/kmdecomp/savekeyboard.cpp b/windows/src/developer/kmdecomp/savekeyboard.cpp similarity index 83% rename from windows/src/support/kmdecomp/savekeyboard.cpp rename to windows/src/developer/kmdecomp/savekeyboard.cpp index 9465269500..74bc135147 100644 --- a/windows/src/support/kmdecomp/savekeyboard.cpp +++ b/windows/src/developer/kmdecomp/savekeyboard.cpp @@ -43,9 +43,9 @@ void SaveBitmapFile(LPBYTE lpBitmap, DWORD cbBitmap, char *bmpfile); LPKEYBOARD g_kbd; -PWCHAR wcscat2(PWCHAR c1, const PWCHAR c2) +PWCHAR wcscat2(PWCHAR c1, size_t sz, const PWCHAR c2) { - wcscat(c1, c2); + wcscat_s(c1, sz, c2); return wcschr(c1, 0); } @@ -134,23 +134,23 @@ PWCHAR flagstr(int flag) { static WCHAR buf[256]; *buf = 0; - if(flag & LCTRLFLAG) wcscat2(buf, L"LCTRL "); - if(flag & RCTRLFLAG) wcscat2(buf, L"RCTRL "); - if(flag & LALTFLAG) wcscat2(buf, L"LALT "); - if(flag & RALTFLAG) wcscat2(buf, L"RALT "); - if(flag & K_SHIFTFLAG) wcscat2(buf, L"SHIFT "); - if(flag & K_CTRLFLAG) wcscat2(buf, L"CTRL "); - if(flag & K_ALTFLAG) wcscat2(buf, L"ALT "); - if(flag & CAPITALFLAG) wcscat2(buf, L"CAPS "); - if(flag & NOTCAPITALFLAG) wcscat2(buf, L"NCAPS "); - if(flag & NUMLOCKFLAG) wcscat2(buf, L"NUM "); - if(flag & NOTNUMLOCKFLAG) wcscat2(buf, L"NNUM "); - if(flag & SCROLLFLAG) wcscat2(buf, L"SCROLL "); - if(flag & NOTSCROLLFLAG) wcscat2(buf, L"NSCROLL "); + if(flag & LCTRLFLAG) wcscat2(buf, _countof(buf), L"LCTRL "); + if(flag & RCTRLFLAG) wcscat2(buf, _countof(buf), L"RCTRL "); + if(flag & LALTFLAG) wcscat2(buf, _countof(buf), L"LALT "); + if(flag & RALTFLAG) wcscat2(buf, _countof(buf), L"RALT "); + if(flag & K_SHIFTFLAG) wcscat2(buf, _countof(buf), L"SHIFT "); + if(flag & K_CTRLFLAG) wcscat2(buf, _countof(buf), L"CTRL "); + if(flag & K_ALTFLAG) wcscat2(buf, _countof(buf), L"ALT "); + if(flag & CAPITALFLAG) wcscat2(buf, _countof(buf), L"CAPS "); + if(flag & NOTCAPITALFLAG) wcscat2(buf, _countof(buf), L"NCAPS "); + if(flag & NUMLOCKFLAG) wcscat2(buf, _countof(buf), L"NUM "); + if(flag & NOTNUMLOCKFLAG) wcscat2(buf, _countof(buf), L"NNUM "); + if(flag & SCROLLFLAG) wcscat2(buf, _countof(buf), L"SCROLL "); + if(flag & NOTSCROLLFLAG) wcscat2(buf, _countof(buf), L"NSCROLL "); return buf; } -PWCHAR GetVKeyName(LPKEY key) // I3438 +PCWCHAR GetVKeyName(LPKEY key) // I3438 { static WCHAR buf[100]; if(key->Key <= VK__MAX) @@ -187,9 +187,10 @@ PWCHAR ifvalue(WCHAR ch) return L"="; } +#define BUFSIZE 512 PWCHAR ExtString(PWCHAR str) { - static WCHAR buf[2][512], bufpointer = 0; // allows for multiple strings in one printf + static WCHAR buf[2][BUFSIZE], bufpointer = 0; // allows for multiple strings in one printf // dodgy hack? PWCHAR p; @@ -203,7 +204,7 @@ PWCHAR ExtString(PWCHAR str) if(*str == UC_SENTINEL) { str++; - if(inquotes) p = wcscat2(p, L"\" "); + if(inquotes) p = wcscat2(p, BUFSIZE, L"\" "); inquotes = 0; switch(*str) { @@ -219,10 +220,10 @@ PWCHAR ExtString(PWCHAR str) p = wcschr(p, 0); break; case CODE_CONTEXT: - p = wcscat2(p, L"context "); + p = wcscat2(p, BUFSIZE, L"context "); break; case CODE_NUL: - p = wcscat2(p, L"nul "); + p = wcscat2(p, BUFSIZE, L"nul "); break; case CODE_USE: str++; @@ -230,10 +231,10 @@ PWCHAR ExtString(PWCHAR str) p = wcschr(p, 0); break; case CODE_RETURN: - p = wcscat2(p, L"return "); + p = wcscat2(p, BUFSIZE, L"return "); break; case CODE_BEEP: - p = wcscat2(p, L"beep "); + p = wcscat2(p, BUFSIZE, L"beep "); break; case CODE_DEADKEY: str++; @@ -257,13 +258,13 @@ PWCHAR ExtString(PWCHAR str) p = wcschr(p, 0); break; case CODE_SWITCH: - p = wcscat2(p, L"switch "); + p = wcscat2(p, BUFSIZE, L"switch "); break; case CODE_KEY: - p = wcscat2(p, L"key "); + p = wcscat2(p, BUFSIZE, L"key "); break; case CODE_CLEARCONTEXT: - p = wcscat2(p, L"clearcontext "); + p = wcscat2(p, BUFSIZE, L"clearcontext "); break; case CODE_CALL: str++; @@ -321,7 +322,7 @@ PWCHAR ExtString(PWCHAR str) break; default: - p = wcscat2(p, L"unknown() "); + p = wcscat2(p, BUFSIZE, L"unknown() "); break; } } @@ -329,13 +330,13 @@ PWCHAR ExtString(PWCHAR str) { if(*str == L'"') { - if(inquotes) p = wcscat2(p, L"\" "); + if(inquotes) p = wcscat2(p, BUFSIZE, L"\" "); inquotes = 0; - p = wcscat2(p, L"'\"' "); + p = wcscat2(p, BUFSIZE, L"'\"' "); } else if(*str < 32) { - if(inquotes) p = wcscat2(p, L"\" "); + if(inquotes) p = wcscat2(p, BUFSIZE, L"\" "); inquotes = 0; wsprintfW(p, L"x%x ", *str); p = wcschr(p, 0); @@ -345,7 +346,7 @@ PWCHAR ExtString(PWCHAR str) if(!inquotes) { inquotes = 1; - p = wcscat2(p, L"\""); + p = wcscat2(p, BUFSIZE, L"\""); } *p++ = *str; *p = 0; @@ -353,7 +354,7 @@ PWCHAR ExtString(PWCHAR str) } } - if(inquotes) p = wcscat2(p, L"\" "); + if(inquotes) p = wcscat2(p, BUFSIZE, L"\" "); return buf[bufpointer]; } @@ -376,10 +377,12 @@ int SaveKeyboardSource(LPKEYBOARD kbd, LPBYTE lpBitmap, DWORD cbBitmap, char *fi g_kbd = kbd; - fp = fopen(filename, "wb"); - fwrite(UTF16Sig, 2, 1, fp); + if (fopen_s(&fp, filename, "wb") != 0) { + Err("Unable to create output file."); + return 3; + } - if(!fp) { Err("Unable to create output file."); return 3; } + fwrite(UTF16Sig, 2, 1, fp); wsprintfW(buf, L"c Keyboard created by KMDECOMP\n"); wr(fp, buf); wsprintfW(buf, L"c\n"); wr(fp, buf); @@ -450,7 +453,9 @@ int SaveKeyboardSource(LPKEYBOARD kbd, LPBYTE lpBitmap, DWORD cbBitmap, char *fi void SaveBitmapFile(LPBYTE lpBitmap, DWORD cbBitmap, char *bmpfile) { - FILE * fp = fopen(bmpfile, "wb"); - fwrite(lpBitmap, cbBitmap, 1, fp); - fclose(fp); + FILE *fp; + if (fopen_s(&fp, bmpfile, "wb") == 0) { + fwrite(lpBitmap, cbBitmap, 1, fp); + fclose(fp); + } } diff --git a/windows/src/developer/kmdecomp/version.in b/windows/src/developer/kmdecomp/version.in new file mode 100644 index 0000000000..5ed1ddfa85 --- /dev/null +++ b/windows/src/developer/kmdecomp/version.in @@ -0,0 +1,30 @@ +1 VERSIONINFO + FILEVERSION $VERSIONNUM + PRODUCTVERSION $VERSIONNUM + FILEFLAGSMASK 0x3fL + FILEFLAGS 0x0L + FILEOS 0x4L + FILETYPE 0x2L + FILESUBTYPE 0x0L + BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "0C0904E4" + BEGIN + VALUE "CompanyName", "SIL International\0" + VALUE "FileDescription", "Keyman decompiler\0" + VALUE "FileVersion", "$VERSION\0" + VALUE "InternalName", "KMDECOMP\0" + VALUE "LegalCopyright", " SIL International\0" + VALUE "LegalTrademarks", "\0" + VALUE "OriginalFilename", "KMDECOMP.EXE\0" + VALUE "ProductName", "Keyman Developer\0" + VALUE "ProductVersion", "$VERSION\0" + VALUE "Comments", "\0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0xc09, 1252 + END + END