Skip to content

Commit 41a696c

Browse files
Hybrid Machineclaude
andcommitted
fix: address PR #101 review comments
- win32_profile.mm: guard nSize==0 underflow in GetPrivateProfileStringW; implement NULL lpString delete semantics in WritePrivateProfileStringW per Win32 API contract - nppm_handler.mm: use bounded wcsncpy instead of wcscpy in NPPM_GETFULLPATHFROMBUFFERID to prevent buffer overflow - winuser.h: SendInput stub returns nInputs (success) instead of 0 (failure) so callers don't disable features - winbase.h/tchar.h: deduplicate safe CRT shims (_wfopen_s, _itow_s, _snwprintf_s) — single definition in winbase.h behind SHIM_HAS_SAFE_CRT guard - compare-plus-host-inventory.md: update status to reflect Phase 1 implementations (all Tier 1 messages now implemented) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 06ebeb4 commit 41a696c

6 files changed

Lines changed: 55 additions & 59 deletions

File tree

Lines changed: 22 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,42 +1,43 @@
11
# ComparePlus Host-Surface Inventory
22

3-
Generated as part of Phase 0, Issue #100.
3+
Generated as part of Phase 0, Issue #100. Updated after Phase 1 implementation.
44

5-
## Tier 1: Blocks Basic Compare (MUST implement first)
5+
## Tier 1: Blocks Basic Compare
66

77
| Message | Used In | Host Status |
88
|---------|---------|-------------|
9-
| `NPPM_GETCURRENTBUFFERID` | NppHelpers.h:473 | **NOT IMPLEMENTED** |
10-
| `NPPM_GETPOSFROMBUFFERID` | NppHelpers.h:459,466; NppHelpers.cpp:302 | **NOT IMPLEMENTED** |
11-
| `NPPM_GETBUFFERIDFROMPOS` | NppHelpers.cpp:508,516 | **NOT IMPLEMENTED** |
12-
| `NPPM_GETFULLPATHFROMBUFFERID` | Compare.h:77; NppHelpers.cpp:509,511,517,519; Compare.cpp:1135 | **NOT IMPLEMENTED** |
13-
| `NPPM_DOOPEN` | Compare.cpp:2983 | **NOT IMPLEMENTED** |
14-
| `NPPM_SWITCHTOFILE` | Compare.cpp:5108,5113 | **NOT IMPLEMENTED** |
15-
| `NPPM_SETBUFFERLANGTYPE` | Compare.cpp (createTempFile) | **NOT IMPLEMENTED** |
16-
| `NPPM_GETBUFFERLANGTYPE` | Compare.cpp (createTempFile) | **NOT IMPLEMENTED** |
17-
| `NPPN_BUFFERACTIVATED` | Compare.cpp (onBufferActivated) | **NOT EMITTED** |
9+
| `NPPM_GETCURRENTBUFFERID` | NppHelpers.h:473 | **IMPLEMENTED** (nppm_handler.mm) |
10+
| `NPPM_GETPOSFROMBUFFERID` | NppHelpers.h:459,466; NppHelpers.cpp:302 | **IMPLEMENTED** (nppm_handler.mm) |
11+
| `NPPM_GETBUFFERIDFROMPOS` | NppHelpers.cpp:508,516 | **IMPLEMENTED** (nppm_handler.mm) |
12+
| `NPPM_GETFULLPATHFROMBUFFERID` | Compare.h:77; NppHelpers.cpp:509,511,517,519; Compare.cpp:1135 | **IMPLEMENTED** (nppm_handler.mm) |
13+
| `NPPM_DOOPEN` | Compare.cpp:2983 | **IMPLEMENTED** (nppm_handler.mm) |
14+
| `NPPM_SWITCHTOFILE` | Compare.cpp:5108,5113 | **IMPLEMENTED** (nppm_handler.mm) |
15+
| `NPPM_SETBUFFERLANGTYPE` | Compare.cpp (createTempFile) | **IMPLEMENTED** (nppm_handler.mm) |
16+
| `NPPM_GETBUFFERLANGTYPE` | Compare.cpp (createTempFile) | **IMPLEMENTED** (nppm_handler.mm) |
17+
| `NPPN_BUFFERACTIVATED` | Compare.cpp (onBufferActivated) | **EMITTED** (document_manager.mm) |
1818

1919
## Tier 2: Blocks UI/Toolbar
2020

2121
| Message | Used In | Host Status |
2222
|---------|---------|-------------|
2323
| `NPPM_ADDTOOLBARICON_FORDARKMODE` | Compare.cpp (onToolBarReady) | **NOT IMPLEMENTED** |
2424
| `NPPM_HIDETABBAR` | Compare.cpp (5 calls) | **NOT IMPLEMENTED** |
25-
| `NPPM_GETMENUHANDLE` | Compare.cpp (NppState, 8 calls) | **NOT IMPLEMENTED** |
25+
| `NPPM_GETMENUHANDLE` | Compare.cpp (NppState, 8 calls) | **IMPLEMENTED** (nppm_handler.mm) |
2626
| `NPPM_DMMREGASDCKDLG` | NavDialog.cpp | **NOT IMPLEMENTED** |
2727
| `NPPM_DMMSHOW` / `NPPM_DMMHIDE` | NavDialog.cpp | **NOT IMPLEMENTED** |
28-
| `NPPN_TBMODIFICATION` | Compare.cpp (onToolBarReady) | **NOT EMITTED** |
29-
| `NPPN_BEFORESHUTDOWN` | Compare.cpp (onBeforeShutdown) | **NOT EMITTED** |
28+
| `NPPN_TBMODIFICATION` | Compare.cpp (onToolBarReady) | **EMITTED** (app_delegate.mm) |
29+
| `NPPN_BEFORESHUTDOWN` | Compare.cpp (onBeforeShutdown) | **EMITTED** (app_delegate.mm) |
3030

3131
## Tier 3: Polish
3232

3333
| Message | Used In | Host Status |
3434
|---------|---------|-------------|
3535
| `NPPM_SETSTATUSBAR` | Compare.cpp (setStatus) | **NOT IMPLEMENTED** |
36-
| `NPPM_ADDSCNMODIFIEDFLAGS` | Compare.cpp (onNppReady) | **NOT IMPLEMENTED** |
36+
| `NPPM_ADDSCNMODIFIEDFLAGS` | Compare.cpp (onNppReady) | **IMPLEMENTED** (no-op, host forwards all SCN_MODIFIED) |
3737
| `NPPM_GETLINENUMBERWIDTHMODE` | Compare.cpp (NppState) | **NOT IMPLEMENTED** |
3838
| `NPPM_SETLINENUMBERWIDTHMODE` | Compare.cpp (3 calls) | **NOT IMPLEMENTED** |
3939
| `NPPM_GETCURRENTCMDLINE` | Compare.cpp (checkCmdLine) | **NOT IMPLEMENTED** |
40+
| `NPPM_GETCURRENTNATIVELANGENCODING` | NppHelpers.h | **IMPLEMENTED** (nppm_handler.mm, returns UTF-8) |
4041
| `NPPN_GLOBALMODIFIED` | Compare.cpp | **NOT EMITTED** |
4142
| `NPPN_DARKMODECHANGED` | Compare.cpp | **NOT EMITTED** |
4243
| `NPPN_WORDSTYLESUPDATED` | Compare.cpp | **NOT EMITTED** |
@@ -46,6 +47,10 @@ Generated as part of Phase 0, Issue #100.
4647
NPPM: GETCURRENTSCINTILLA, GETCURRENTLANGTYPE, SETCURRENTLANGTYPE, GETCURRENTVIEW,
4748
GETNBOPENFILES, MENUCOMMAND, SETMENUITEMCHECK, GETPLUGINSCONFIGDIR, GETNPPVERSION,
4849
ALLOCATECMDID, ALLOCATEMARKER, ALLOCATEINDICATOR, GETFULLCURRENTPATH, GETFILENAME,
49-
GETCURRENTDIRECTORY, GETNAMEPART, GETEXTPART, GETCURRENTWORD, GETCURRENTLINE, GETCURRENTCOLUMN
50+
GETCURRENTDIRECTORY, GETNAMEPART, GETEXTPART, GETCURRENTWORD, GETCURRENTLINE, GETCURRENTCOLUMN,
51+
GETCURRENTBUFFERID, GETPOSFROMBUFFERID, GETBUFFERIDFROMPOS, GETFULLPATHFROMBUFFERID,
52+
DOOPEN, SWITCHTOFILE, SETBUFFERLANGTYPE, GETBUFFERLANGTYPE, GETMENUHANDLE,
53+
GETCURRENTNATIVELANGENCODING, ADDSCNMODIFIEDFLAGS
5054

51-
NPPN: NPPN_READY, NPPN_SHUTDOWN, NPPN_LANGCHANGED, NPPN_FILEBEFORECLOSE, NPPN_FILESAVED
55+
NPPN: NPPN_READY, NPPN_SHUTDOWN, NPPN_LANGCHANGED, NPPN_FILEBEFORECLOSE, NPPN_FILESAVED,
56+
NPPN_FILEOPENED, NPPN_FILECLOSED, NPPN_BUFFERACTIVATED, NPPN_BEFORESHUTDOWN, NPPN_TBMODIFICATION

macos/platform/nppm_handler.mm

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -256,7 +256,8 @@ LRESULT handleNppmMessage(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
256256
if (!lParam)
257257
return static_cast<LRESULT>(path.size());
258258
wchar_t* buf = reinterpret_cast<wchar_t*>(lParam);
259-
wcscpy(buf, path.c_str());
259+
wcsncpy(buf, path.c_str(), MAX_PATH - 1);
260+
buf[MAX_PATH - 1] = L'\0';
260261
return static_cast<LRESULT>(path.size());
261262
}
262263

macos/shim/include/tchar.h

Lines changed: 2 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -167,36 +167,8 @@ inline int swprintf_s(wchar_t* buf, size_t count, const wchar_t* fmt, ...) {
167167
#define _vsnwprintf vswprintf
168168
#define sscanf_s sscanf
169169

170-
// _snwprintf_s: safe variant of _snwprintf
171-
inline int _snwprintf_s(wchar_t* buf, size_t sizeOfBuffer, size_t count, const wchar_t* fmt, ...) {
172-
(void)count;
173-
va_list args;
174-
va_start(args, fmt);
175-
int r = vswprintf(buf, sizeOfBuffer, fmt, args);
176-
va_end(args);
177-
return r;
178-
}
179-
180-
// _itow_s: safe variant of _itow
181-
inline errno_t _itow_s(int value, wchar_t* buf, size_t sizeInWords, int radix) {
182-
if (!buf || sizeInWords == 0) return EINVAL;
183-
if (radix == 10)
184-
swprintf(buf, sizeInWords, L"%d", value);
185-
else if (radix == 16)
186-
swprintf(buf, sizeInWords, L"%x", value);
187-
else if (radix == 8)
188-
swprintf(buf, sizeInWords, L"%o", value);
189-
else
190-
buf[0] = L'\0';
191-
return 0;
192-
}
193-
194-
// _wfopen_s: safe variant of _wfopen
195-
inline errno_t _wfopen_s(FILE** pFile, const wchar_t* filename, const wchar_t* mode) {
196-
if (!pFile) return EINVAL;
197-
*pFile = _wfopen(filename, mode);
198-
return (*pFile) ? 0 : errno;
199-
}
170+
// _snwprintf_s, _itow_s, _wfopen_s are defined in winbase.h (included via windows.h).
171+
// Guarded by SHIM_HAS_SAFE_CRT to prevent duplicate definitions.
200172

201173
// memcpy_s / memmove_s
202174
#include <cstring>

macos/shim/include/winbase.h

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1169,8 +1169,11 @@ DWORD GetPrivateProfileStringW(LPCWSTR lpAppName, LPCWSTR lpKeyName, LPCWSTR lpD
11691169
BOOL WritePrivateProfileStringW(LPCWSTR lpAppName, LPCWSTR lpKeyName, LPCWSTR lpString, LPCWSTR lpFileName);
11701170

11711171
// ============================================================
1172-
// MSVC CRT safe string functions (not in tchar.h for non-tchar code)
1172+
// MSVC CRT safe string functions — single canonical definition.
1173+
// tchar.h defers to these via SHIM_HAS_SAFE_CRT guard.
11731174
// ============================================================
1175+
#ifndef SHIM_HAS_SAFE_CRT
1176+
#define SHIM_HAS_SAFE_CRT
11741177

11751178
#include <cerrno>
11761179
#include <cstdarg>
@@ -1211,3 +1214,5 @@ inline int _snwprintf_s(wchar_t* buf, size_t sizeOfBuffer, size_t count, const w
12111214
va_end(args);
12121215
return r;
12131216
}
1217+
1218+
#endif // SHIM_HAS_SAFE_CRT

macos/shim/include/winuser.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1979,6 +1979,8 @@ struct INPUT
19791979

19801980
inline UINT SendInput(UINT nInputs, INPUT* pInputs, int cbSize)
19811981
{
1982-
(void)nInputs; (void)pInputs; (void)cbSize;
1983-
return 0; // Stub — no input simulation on macOS
1982+
(void)pInputs; (void)cbSize;
1983+
// No-op on macOS — return nInputs to indicate "success" so callers
1984+
// don't treat it as failure and disable features.
1985+
return nInputs;
19841986
}

macos/shim/src/win32_profile.mm

Lines changed: 19 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -141,16 +141,16 @@ DWORD GetPrivateProfileStringW(LPCWSTR lpAppName, LPCWSTR lpKeyName, LPCWSTR lpD
141141
value = lpDefault ? wideToUtf8(lpDefault) : "";
142142
}
143143

144+
if (!lpReturnedString || nSize == 0)
145+
return 0;
146+
144147
NSString* nsValue = [NSString stringWithUTF8String:value.c_str()];
145148
NSData* data = [nsValue dataUsingEncoding:NSUTF32LittleEndianStringEncoding];
146149
size_t wcharCount = data.length / sizeof(wchar_t);
147150
size_t copyLen = (wcharCount < nSize) ? wcharCount : (nSize - 1);
148151

149-
if (lpReturnedString && nSize > 0)
150-
{
151-
memcpy(lpReturnedString, data.bytes, copyLen * sizeof(wchar_t));
152-
lpReturnedString[copyLen] = L'\0';
153-
}
152+
memcpy(lpReturnedString, data.bytes, copyLen * sizeof(wchar_t));
153+
lpReturnedString[copyLen] = L'\0';
154154

155155
return static_cast<DWORD>(copyLen);
156156
}
@@ -161,11 +161,22 @@ BOOL WritePrivateProfileStringW(LPCWSTR lpAppName, LPCWSTR lpKeyName, LPCWSTR lp
161161
@autoreleasepool {
162162
std::string path = wideToUtf8(lpFileName);
163163
std::string section = wideToUtf8(lpAppName);
164-
std::string key = wideToUtf8(lpKeyName);
165-
std::string value = lpString ? wideToUtf8(lpString) : "";
166164

167165
IniMap ini = parseIniFile(path);
168-
ini[section][key] = value;
166+
167+
// Win32 contract: NULL lpString deletes the key (or section if lpKeyName is also NULL)
168+
if (!lpString)
169+
{
170+
if (!lpKeyName)
171+
ini.erase(section);
172+
else
173+
ini[section].erase(wideToUtf8(lpKeyName));
174+
}
175+
else
176+
{
177+
std::string key = wideToUtf8(lpKeyName);
178+
ini[section][key] = wideToUtf8(lpString);
179+
}
169180

170181
return writeIniFile(path, ini) ? TRUE : FALSE;
171182
}

0 commit comments

Comments
 (0)