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