diff --git a/developer/src/kmcmplib/include/kmcmplibapi.h b/developer/src/kmcmplib/include/kmcmplibapi.h index 4054d81e81..5c2ae46fda 100644 --- a/developer/src/kmcmplib/include/kmcmplibapi.h +++ b/developer/src/kmcmplib/include/kmcmplibapi.h @@ -36,7 +36,7 @@ struct KMCMP_COMPILER_RESULT { }; // TODO: parameters in UTF-8 -typedef int (*kmcmp_CompilerMessageProc)(int line, uint32_t dwMsgCode, char* szText, void* context); +typedef int (*kmcmp_CompilerMessageProc)(int line, uint32_t dwMsgCode, const char* szText, void* context); // parameters in UTF-8 // TODO typical usage: @@ -48,7 +48,7 @@ typedef int (*kmcmp_CompilerMessageProc)(int line, uint32_t dwMsgCode, char* szT // delete[] buf; // return error; // } -typedef bool (*kmcmp_LoadFileProc)(char* loadFilename, char* baseFilename, void* buffer, int* bufferSize); +typedef bool (*kmcmp_LoadFileProc)(const char* loadFilename, const char* baseFilename, void* buffer, int* bufferSize, void* context); // Parameters in UTF-8 EXTERN bool kmcmp_CompileKeyboard( diff --git a/developer/src/kmcmplib/src/Compiler.cpp b/developer/src/kmcmplib/src/Compiler.cpp index b09e36cbc1..8e0f94cb29 100644 --- a/developer/src/kmcmplib/src/Compiler.cpp +++ b/developer/src/kmcmplib/src/Compiler.cpp @@ -94,6 +94,9 @@ #include "CasedKeys.h" #include #include +#include +#include + #include "CheckFilenameConsistency.h" #include "UnreachableRules.h" #include "CheckForDuplicates.h" @@ -230,6 +233,8 @@ enum LinePrefixType { lptNone, lptKeymanAndKeymanWeb, lptKeymanWebOnly, lptKeyma /* Compile target */ kmcmp_CompilerMessageProc msgproc = NULL; +kmcmp_LoadFileProc loadfileproc = NULL; + void* msgprocContext = NULL; int kmcmp::currentLine = 0; @@ -3068,7 +3073,7 @@ KMX_DWORD WriteCompiledKeyboard(PFILE_KEYBOARD fk, KMX_BYTE**data, size_t& dataS return CERR_None; } -KMX_DWORD ReadLine(FILE* fp_in , PKMX_WCHAR wstr, KMX_BOOL PreProcess) +KMX_DWORD ReadLine(KMX_BYTE* infile, int sz, int& offset, PKMX_WCHAR wstr, KMX_BOOL PreProcess) { KMX_DWORD len; PKMX_WCHAR p; @@ -3076,21 +3081,26 @@ KMX_DWORD ReadLine(FILE* fp_in , PKMX_WCHAR wstr, KMX_BOOL PreProcess) KMX_DWORD n; KMX_WCHAR currentQuotes = 0; KMX_WCHAR str[LINESIZE + 3]; - len = (KMX_DWORD)fread( str , 1 ,LINESIZE * 2,fp_in); - if (ferror(fp_in) ) return CERR_CannotReadInfile; + + if(offset >= sz) { + return CERR_EndOfFile; + } + + len = offset + LINESIZE*2 > sz ? sz-offset : LINESIZE*2; + memcpy(str, infile+offset, len); + offset += len; len /= 2; - str[len] = 0; auto cur = ftell(fp_in); - fseek(fp_in, 0, SEEK_END); - auto fsize = ftell(fp_in); - fseek(fp_in, cur, SEEK_SET); + str[len] = 0; - if (cur == fsize) + if(offset == sz) { + // \r\n is still added here even though Linux doesn`t use \r. + // This is to ensure to still have a working windows-only-version + u16ncat(str, u"\r\n", _countof(str)); // I3481 // Always a "\r\n" to the EOF, avoids funny bugs + } - // \r\n is still added here even though Linux doesn`t use \r. - // This is to ensure to still have a working windows-only-version - u16ncat(str, u"\r\n", _countof(str)); // I3481 // Always a "\r\n" to the EOF, avoids funny bugs - - if (len == 0) return CERR_EndOfFile; + if (len == 0) { + return CERR_EndOfFile; + } // neccessary to add this block for using on non-windows platforms (removes all \r for platforms that use \n instead of \r\n) for (p = str, n = 0; n < len; n++, p++) { @@ -3172,9 +3182,13 @@ KMX_DWORD ReadLine(FILE* fp_in , PKMX_WCHAR wstr, KMX_BOOL PreProcess) return (PreProcess ? CERR_None : CERR_LineTooLong); } - if (*p == L'\n') kmcmp::currentLine++; + kmcmp::currentLine++; - fseek(fp_in, -(int)(len * 2 - (int)(p - str) * 2 - 2), SEEK_CUR); + offset -= (int)(len * 2 - (int)(p - str) * 2 - 2); + if(offset >= sz) { + // If we've appended a \n, we can go past EOF + offset = sz; + } p--; while (p >= str && iswspace(*p)) p--; @@ -3427,81 +3441,39 @@ KMX_BOOL kmcmp::IsValidCallStore(PFILE_STORE fs) return i == 1; } -FILE* CreateTempFile() -{ - return tmpfile(); -} - /////////////////// -FILE* UTF16TempFromUTF8(FILE* fp_in , KMX_BOOL hasPreamble) -{ - FILE *fp_out = CreateTempFile(); - if(fp_out == NULL) // I3228 // I3510 - { - fclose(fp_in); - return NULL; //return INVALID_HANDLE_VALUE; _S2 can I exchange that? +bool hasPreamble(std::u16string result) { + return result.size() > 0 && result[0] == 0xFEFF; +} + +bool UTF16TempFromUTF8(KMX_BYTE* infile, int sz, KMX_BYTE** tempfile, int *sz16) { + if(sz == 0) { + return FALSE; } - PKMX_BYTE buf, p; - PKMX_WCHAR outbuf, poutbuf; - KMX_DWORD len; - KMX_DWORD len2; - KMX_WCHAR prolog = 0xFEFF; - fwrite(&prolog,2, 1, fp_out); + std::u16string result; - fseek(fp_in, 0, SEEK_END); - len = (KMX_DWORD)ftell(fp_in); - fseek(fp_in, 0, SEEK_SET); - if (hasPreamble) { - fseek( fp_in,3,SEEK_SET); // Cut off UTF-8 marker - len -= 3; + try { + std::wstring_convert, char16_t> converter; + result = converter.from_bytes((char*)infile, (char*)infile+sz-1); + } catch(std::range_error e) { + std::wstring_convert, char16_t> converter; + result = converter.from_bytes((char*)infile, (char*)infile+sz-1); } - buf = new KMX_BYTE[len + 1]; // null terminated - outbuf = new KMX_WCHAR[len + 1]; + if(hasPreamble(result)) { + *sz16 = result.size() * 2 - 1; + *tempfile = new KMX_BYTE[*sz16]; + memcpy(*tempfile, result.c_str() + 2, *sz16); - len2= (KMX_DWORD)fread(buf,1,len,fp_in); - if (len2) { - buf[len2] = 0; - p = buf; - poutbuf = outbuf; - if (hasPreamble) { - // We have a preamble, so we attempt to read as UTF-8 and allow conversion errors to be filtered. This is not great for a - // compiler but matches existing behaviour -- in future versions we may not do lenient conversion. - ConvertUTF8toUTF16(&p, &buf[len2], (UTF16 **)&poutbuf, (const UTF16 *)&outbuf[len], lenientConversion); - fwrite(outbuf, (KMX_DWORD)(poutbuf - outbuf) * 2 , 1, fp_out); - } - else { - // No preamble, so we attempt to read as strict UTF-8 and fall back to ANSI if that fails - ConversionResult cr = ConvertUTF8toUTF16(&p, &buf[len2], (UTF16 **)&poutbuf, (const UTF16 *)&outbuf[len], strictConversion); - if (cr == sourceIllegal) { - // Not a valid UTF-8 file, so fall back to ANSI - // AddCompileError(CHINT_NonUnicodeFile); - // note, while this message is defined, for now we will not emit it - // because we don't support HINT/INFO messages yet and we don't want - // this to cause a blocking compile at this stage - // do strtowstr only when no invalid characters are found - if( p==0){ - poutbuf = strtowstr((PKMX_STR)buf); - fwrite(poutbuf, (KMX_DWORD)u16len(poutbuf) * 2 , 1, fp_out); - delete[] poutbuf; - } - else - AddCompileError(CERR_InvalidCharacter); - } - - else { - fwrite(outbuf, (KMX_DWORD)(poutbuf - outbuf) * 2 , 1, fp_out); - } - } } - fclose( fp_in); - delete[] buf; - delete[] outbuf; - fseek( fp_out,2,SEEK_SET); - return fp_out; + *sz16 = result.size() * 2; + *tempfile = new KMX_BYTE[*sz16]; + memcpy(*tempfile, result.c_str(), *sz16); + + return TRUE; } PFILE_STORE FindSystemStore(PFILE_KEYBOARD fk, KMX_DWORD dwSystemID) diff --git a/developer/src/kmcmplib/src/CompilerInterfaces.cpp b/developer/src/kmcmplib/src/CompilerInterfaces.cpp index 71e1e895f2..fd297f4332 100644 --- a/developer/src/kmcmplib/src/CompilerInterfaces.cpp +++ b/developer/src/kmcmplib/src/CompilerInterfaces.cpp @@ -11,14 +11,14 @@ #include "../../../../common/windows/cpp/include/ConvertUTF.h" #include "../../../../common/windows/cpp/include/keymanversion.h" -bool CompileKeyboardHandle(FILE* fp_in, PFILE_KEYBOARD fk); +bool CompileKeyboardHandle(KMX_BYTE* infile, int sz, PFILE_KEYBOARD fk); #ifdef __EMSCRIPTEN__ /* WASM interface for compiler message callback */ -EM_JS(int, wasm_msgproc, (int line, int msgcode, char* text, char* context), { +EM_JS(int, wasm_msgproc, (int line, int msgcode, const char* text, char* context), { const proc = globalThis[UTF8ToString(context)]; if(!proc || typeof proc != 'function') { console.log(`[${line}: ${msgcode}: ${UTF8ToString(text)}]`); @@ -28,7 +28,21 @@ EM_JS(int, wasm_msgproc, (int line, int msgcode, char* text, char* context), { } }); -int wasm_CompilerMessageProc(int line, uint32_t dwMsgCode, char* szText, void* context) { +EM_JS(bool, wasm_loadfileproc, (const char* filename, const char* baseFilename, void* buffer, int* bufferSize, char* context), { + const proc = globalThis[UTF8ToString(context)]; + if(!proc || typeof proc != 'function') { + return 0; + } else { + return proc(UTF8ToString(filename), UTF8ToString(baseFilename), buffer, bufferSize); + } +}); + +bool wasm_LoadFileProc(const char* filename, const char* baseFilename, void* buffer, int* bufferSize, void* context) { + char* msgProc = static_cast(context); + return wasm_loadfileproc(filename, baseFilename, buffer, bufferSize, msgProc); +} + +int wasm_CompilerMessageProc(int line, uint32_t dwMsgCode, const char* szText, void* context) { char* msgProc = static_cast(context); return wasm_msgproc(line, dwMsgCode, szText, msgProc); } @@ -61,7 +75,7 @@ WASM_COMPILER_RESULT kmcmp_wasm_compile(std::string pszInfile, const KMCMP_COMPI pszInfile.c_str(), options, wasm_CompilerMessageProc, - nullptr, //wasm_LoadFileProc, + wasm_LoadFileProc, intf.messageCallback.c_str(), kr ); @@ -116,8 +130,6 @@ EXTERN bool kmcmp_CompileKeyboard( KMCMP_COMPILER_RESULT& result ) { - FILE* fp_in = NULL; - KMX_CHAR str[260]; FILE_KEYBOARD fk; kmcmp::FSaveDebug = options.saveDebug; // I3681 @@ -126,7 +138,7 @@ EXTERN bool kmcmp_CompileKeyboard( kmcmp::FShouldAddCompilerVersion = options.shouldAddCompilerVersion; kmcmp::CompileTarget = options.target; - if (!messageProc || !pszInfile) { // TODO: add loadFileProc + if (!messageProc || !loadFileProc || !pszInfile) { AddCompileError(CERR_BadCallParams); return FALSE; } @@ -142,43 +154,58 @@ EXTERN bool kmcmp_CompileKeyboard( } msgproc = messageProc; - //TODO: loadfileproc = loadFileProc; + loadfileproc = loadFileProc; msgprocContext = (void*)procContext; kmcmp::currentLine = 0; kmcmp::nErrors = 0; - fp_in = Open_File(pszInfile, "rb"); - - if (fp_in == NULL) { + int sz; + if(!loadFileProc(pszInfile, "", nullptr, &sz, msgprocContext)) { AddCompileError(CERR_InfileNotExist); return FALSE; } - // Transfer the file to a memory stream for processing UTF-8 or ANSI to UTF-16? - // What about really large files? Transfer to a temp file... - if (!fread(str, 1, 3, fp_in)) { - fclose(fp_in); + if(sz < 3) { + // Technically, a 3 byte file can never be a valid .kmn, so we can shortcut + // here and avoid testing outside memory bounds for looking at BOM AddCompileError(CERR_CannotReadInfile); return FALSE; } - fseek(fp_in, 0, SEEK_SET); - if (str[0] == UTF8Sig[0] && str[1] == UTF8Sig[1] && str[2] == UTF8Sig[2]) - fp_in = UTF16TempFromUTF8(fp_in, TRUE); - else if (str[0] == UTF16Sig[0] && str[1] == UTF16Sig[1]) - fseek(fp_in, 2, SEEK_SET); - else - fp_in = UTF16TempFromUTF8(fp_in, FALSE); - if (fp_in == NULL) { - AddCompileError(CERR_CannotCreateTempfile); + KMX_BYTE* infile = new KMX_BYTE[sz]; + if(!infile) { + AddCompileError(CERR_CannotAllocateMemory); + return FALSE; + } + if(!loadFileProc(pszInfile, "", infile, &sz, msgprocContext)) { + delete[] infile; + AddCompileError(CERR_CannotReadInfile); return FALSE; } + int offset = 0; + if(infile[0] == (KMX_BYTE) UTF16Sig[0] && infile[1] == (KMX_BYTE) UTF16Sig[1]) { + // UTF-16 source file + offset = 2; + } else { + // UTF-8 source file + KMX_BYTE* infile16; + int sz16; + if(!UTF16TempFromUTF8(infile, sz, &infile16, &sz16)) { + delete[] infile; + AddCompileError(CERR_CannotCreateTempfile); + return FALSE; + } + delete[] infile; + infile = infile16; + sz = sz16; + } + kmcmp::CodeConstants = new kmcmp::NamedCodeConstants; - bool success = CompileKeyboardHandle(fp_in, &fk); + bool success = CompileKeyboardHandle(infile+offset, sz-offset, &fk); delete kmcmp::CodeConstants; - fclose(fp_in); + delete[] infile; if (kmcmp::nErrors > 0 || !success) { return FALSE; @@ -204,7 +231,7 @@ EXTERN bool kmcmp_CompileKeyboard( return TRUE; } -bool CompileKeyboardHandle(FILE* fp_in, PFILE_KEYBOARD fk) +bool CompileKeyboardHandle(KMX_BYTE* infile, int sz, PFILE_KEYBOARD fk) { PKMX_WCHAR str, p; @@ -263,8 +290,10 @@ bool CompileKeyboardHandle(FILE* fp_in, PFILE_KEYBOARD fk) AddStore(fk, TSS_CUSTOMKEYMANEDITION, u"0"); AddStore(fk, TSS_CUSTOMKEYMANEDITIONNAME, u"Keyman"); + int offset = 0; + // must preprocess for group and store names -> this isn't really necessary, but never mind! - while ((msg = ReadLine(fp_in, str, TRUE)) == CERR_None) + while ((msg = ReadLine(infile, sz, offset, str, TRUE)) == CERR_None) { p = str; switch (LineTokenType(&p)) @@ -301,7 +330,7 @@ bool CompileKeyboardHandle(FILE* fp_in, PFILE_KEYBOARD fk) return FALSE; } - fseek( fp_in,2,SEEK_SET); + offset = 0; kmcmp::currentLine = 0; /* Reindex the list of codeconstants after stores added */ @@ -309,7 +338,7 @@ bool CompileKeyboardHandle(FILE* fp_in, PFILE_KEYBOARD fk) kmcmp::CodeConstants->reindex(); /* ReadLine will automatically skip over $Keyman lines, and parse wrapped lines */ - while ((msg = ReadLine(fp_in, str, FALSE)) == CERR_None) + while ((msg = ReadLine(infile, sz, offset, str, FALSE)) == CERR_None) { msg = ParseLine(fk, str); if (msg != CERR_None) { diff --git a/developer/src/kmcmplib/src/compfile.h b/developer/src/kmcmplib/src/compfile.h index 595d1fecec..7c262be090 100644 --- a/developer/src/kmcmplib/src/compfile.h +++ b/developer/src/kmcmplib/src/compfile.h @@ -197,33 +197,4 @@ struct COMPILEMESSAGES { typedef COMPILEMESSAGES *PCOMPILEMESSAGES; -/* -struct TVersion -{ - //int MinVersion; // 0x0500 usually - //int CompilerVersion[4]; - //int MinCompilerVersion[4]; - int KeyboardVersion; // 0x0500 usually -}; - -extern TVersion FVersionInfo; -*/ - -/* -#define bstrcpy(c,d) (LPBYTE)strcpy((LPSTR)(c),(LPSTR)(d)) -#define bstrlen(c) strlen((LPSTR)(c)) -#define bstrcmp(c,d) strcmp((LPSTR)(c),(LPSTR)(d)) -#define bstrncmp(c,d,n) strncmp((LPSTR)(c),(LPSTR)(d),(n)) -#define bstrnicmp(c,d,n) strnicmp((LPSTR)(c),(LPSTR)(d),(n)) -#define bstricmp(c,d) stricmp((LPSTR)(c),(LPSTR)(d)) -#define bstrchr(c,ch) (LPBYTE)strchr((LPSTR)(c),(char)ch) -#define bstrncpy(c,d,n) (LPBYTE)strncpy((LPSTR)(c),(LPSTR)(d),(n)) -#define bstrtok(c,d) (LPBYTE)strtok((LPSTR)(c),(LPSTR)(d)) -#define bstrcat(c,d) (LPBYTE)strcat((LPSTR)(c),(LPSTR)(d)) -#define bstrncat(c,d,n) (LPBYTE)strncat((LPSTR)(c),(LPSTR)(d),(n)) -#define bstrrev(c) (LPBYTE)strrev((LPSTR)(c)) -#define batoi(c) atoi((LPSTR)(c)) -#define bstrtol(c,d,n) strtol((LPSTR)(c),(LPSTR *)(d),(n)) -*/ - #endif // _COMPFILE_H diff --git a/developer/src/kmcmplib/src/kmcmplib.h b/developer/src/kmcmplib/src/kmcmplib.h index 78e945ee0d..70718f98bc 100644 --- a/developer/src/kmcmplib/src/kmcmplib.h +++ b/developer/src/kmcmplib/src/kmcmplib.h @@ -24,6 +24,7 @@ namespace kmcmp { } extern kmcmp_CompilerMessageProc msgproc; +extern kmcmp_LoadFileProc loadfileproc; extern void* msgprocContext; extern KMX_BOOL AWarnDeprecatedCode_GLOBAL_LIB; @@ -40,10 +41,10 @@ KMX_BOOL AddCompileError(KMX_DWORD msg); PKMX_WCHAR strtowstr(PKMX_STR in); PFILE_STORE FindSystemStore(PFILE_KEYBOARD fk, KMX_DWORD dwSystemID); -FILE* UTF16TempFromUTF8(FILE* fp_in , KMX_BOOL hasPreamble); +bool UTF16TempFromUTF8(KMX_BYTE* infile, int sz, KMX_BYTE** tempfile, int *sz16); KMX_DWORD WriteCompiledKeyboard(PFILE_KEYBOARD fk, KMX_BYTE**data, size_t& dataSize); KMX_DWORD AddStore(PFILE_KEYBOARD fk, KMX_DWORD SystemID, const KMX_WCHAR * str, KMX_DWORD *dwStoreID= NULL); -KMX_DWORD ReadLine(FILE* fp_in , PKMX_WCHAR wstr, KMX_BOOL PreProcess); +KMX_DWORD ReadLine(KMX_BYTE* infile, int sz, int& offset, PKMX_WCHAR wstr, KMX_BOOL PreProcess); KMX_DWORD ParseLine(PFILE_KEYBOARD fk, PKMX_WCHAR str); KMX_DWORD ProcessGroupLine(PFILE_KEYBOARD fk, PKMX_WCHAR p); KMX_DWORD ProcessGroupFinish(PFILE_KEYBOARD fk); diff --git a/developer/src/kmcmplib/src/meson.build b/developer/src/kmcmplib/src/meson.build index 8264c3d28e..727d6831e6 100644 --- a/developer/src/kmcmplib/src/meson.build +++ b/developer/src/kmcmplib/src/meson.build @@ -7,6 +7,7 @@ # TODO: is this required? It should be Keyman Core only defns += ['-DKMN_KBP_EXPORTING'] version_res = [] +lib_links = [] if cpp_compiler.get_id() == 'gcc' or cpp_compiler.get_id() == 'clang' warns += [ @@ -24,12 +25,13 @@ endif name_suffix = [] if cpp_compiler.get_id() == 'emscripten' - links += ['-lnodefs.js', '-sMODULARIZE', '-sEXPORT_ES6', '--whole-archive', '--bind', '-sEXPORTED_RUNTIME_METHODS=[\'UTF8ToString\']'] + lib_links = ['--whole-archive', '--bind', '-sMODULARIZE', '-sEXPORT_ES6'] + links += ['-lnodefs.js', '--bind', '-sEXPORTED_RUNTIME_METHODS=[\'UTF8ToString\']'] # tests are building as ES6 so we need to declare the file extension # note that meson currently struggles with the sanitycheckc_cross.exe # program, because it has a hard coded extension (.exe) which is not # valid for node programs in module mode. - name_suffix = '.mjs' + # name_suffix = '.mjs' endif icu = subproject('icu-for-uset', default_options: [ 'default_library=static', 'cpp_std=c++17', 'warning_level=0', 'werror=false']) @@ -63,7 +65,7 @@ lib = library('kmcmplib', version_res, cpp_args: defns + warns + flags, - link_args: links, + link_args: links + lib_links, version: meson.project_version(), include_directories: inc, install: true, diff --git a/developer/src/kmcmplib/tests/api-test.cpp b/developer/src/kmcmplib/tests/api-test.cpp index 4bb0276a79..b347773220 100644 --- a/developer/src/kmcmplib/tests/api-test.cpp +++ b/developer/src/kmcmplib/tests/api-test.cpp @@ -18,13 +18,14 @@ #include #include "../src/compfile.h" #include +#include "../src/filesystem.h" void setup(); -void test_kmcmp_CompileKeyboard(); +void test_kmcmp_CompileKeyboard(char *kmn_file); std::vector error_vec; -int msgproc(int line, uint32_t dwMsgCode, char* szText, void* context) { +int msgproc(int line, uint32_t dwMsgCode, const char* szText, void* context) { error_vec.push_back(dwMsgCode); const char*t = "unknown"; switch(dwMsgCode & 0xF000) { @@ -37,9 +38,42 @@ int msgproc(int line, uint32_t dwMsgCode, char* szText, void* context) { return 1; } +bool loadfileProc(const char* filename, const char* baseFilename, void* data, int* size, void* context) { + FILE* fp = Open_File(filename, "rb"); + if(!fp) { + return false; + } + + if(!data) { + // return size + if(fseek(fp, 0, SEEK_END) != 0) { + fclose(fp); + return false; + } + *size = ftell(fp); + if(*size == -1L) { + fclose(fp); + return false; + } + } else { + // return data + if(fread(data, 1, *size, fp) != *size) { + fclose(fp); + return false; + } + } + fclose(fp); + return true; +} + int main(int argc, char *argv[]) { + if(argc < 1) { + puts("Usage: api-test "); + puts("Warning: blank_keyboard will be overwritten"); + return 1; + } setup(); - test_kmcmp_CompileKeyboard(); + test_kmcmp_CompileKeyboard(argv[1]); return 0; } @@ -48,13 +82,9 @@ void setup() { error_vec.clear(); } -void test_kmcmp_CompileKeyboard() { - char kmn_file[L_tmpnam], kmx_file[L_tmpnam]; - tmpnam(kmn_file); - tmpnam(kmx_file); - +void test_kmcmp_CompileKeyboard(char *kmn_file) { // Create an empty file - FILE *fp = fopen(kmn_file, "w"); + FILE *fp = Open_File(kmn_file, "wb"); fclose(fp); // It should fail when a zero-byte file is passed in @@ -65,7 +95,7 @@ void test_kmcmp_CompileKeyboard() { options.warnDeprecatedCode = true; options.shouldAddCompilerVersion = false; options.target = CKF_KEYMAN; - assert(!kmcmp_CompileKeyboard(kmn_file, options, msgproc, nullptr, nullptr, result)); + assert(!kmcmp_CompileKeyboard(kmn_file, options, msgproc, loadfileProc, nullptr, result)); assert(error_vec.size() == 1); assert(error_vec[0] == CERR_CannotReadInfile); diff --git a/developer/src/kmcmplib/tests/kmcompxtest.cpp b/developer/src/kmcmplib/tests/kmcompxtest.cpp index 87d9e53cf7..c5d189798b 100644 --- a/developer/src/kmcmplib/tests/kmcompxtest.cpp +++ b/developer/src/kmcmplib/tests/kmcompxtest.cpp @@ -13,6 +13,7 @@ #include #include #include +#include "../src/filesystem.h" #ifdef _MSC_VER #else @@ -28,7 +29,7 @@ vector < int > error_vec; #define CERR_WARNING 0x00002000 #define CERR_HINT 0x00001000 -int msgproc(int line, uint32_t dwMsgCode, char* szText, void* context) +int msgproc(int line, uint32_t dwMsgCode, const char* szText, void* context) { error_vec.push_back(dwMsgCode); const char*t = "unknown"; @@ -42,6 +43,34 @@ int msgproc(int line, uint32_t dwMsgCode, char* szText, void* context) return 1; } +bool loadfileProc(const char* filename, const char* baseFilename, void* data, int* size, void* context) { + FILE* fp = Open_File(filename, "rb"); + if(!fp) { + return false; + } + + if(!data) { + // return size + if(fseek(fp, 0, SEEK_END) != 0) { + fclose(fp); + return false; + } + *size = ftell(fp); + if(*size == -1L) { + fclose(fp); + return false; + } + } else { + // return data + if(fread(data, 1, *size, fp) != *size) { + fclose(fp); + return false; + } + } + fclose(fp); + return true; +} + #include "../src/filesystem.h" int main(int argc, char *argv[]) @@ -79,7 +108,7 @@ int main(int argc, char *argv[]) options.shouldAddCompilerVersion = false; options.target = CKF_KEYMAN; - if(kmcmp_CompileKeyboard(kmn_file, options, msgproc, nullptr, nullptr, result)) { + if(kmcmp_CompileKeyboard(kmn_file, options, msgproc, loadfileProc, nullptr, result)) { char* testname = strrchr( (char*) kmn_file, '/') + 1; if(strncmp(testname, pfirst5, 5) == 0){ return __LINE__; // exit code: CERR_ in Name + no Error found diff --git a/developer/src/kmcmplib/tests/meson.build b/developer/src/kmcmplib/tests/meson.build index 49924f2d78..2468ac53b1 100644 --- a/developer/src/kmcmplib/tests/meson.build +++ b/developer/src/kmcmplib/tests/meson.build @@ -113,10 +113,10 @@ apitest = executable('api-test', 'api-test.cpp', name_suffix: name_suffix, link_args: links + tests_flags, objects: lib.extract_all_objects(), - dependencies: icuuc_dep, + dependencies: icuuc_dep ) -test('api-test', apitest) +test('api-test', apitest, args: [output_path / 'blank_keyboard.kmx']) usetapitest = executable('uset-api-test', 'uset-api-test.cpp', cpp_args: defns,