Commit graph

172 commits

Author SHA1 Message Date
Robert Müller f24d755bb2 Add windows_utf8_to_wide and windows_wide_to_utf8
To convert between UTF-8 encoded strings and wide character strings used with the Windows API.

The functions use `std::wstring` and `std::string`, to simplify the usage and support arguments with arbitrary length.

Also add some tests for the functions.
2023-05-02 19:58:23 +02:00
Robert Müller ebb2e4253d Port line input and IME support from 0.7
Port the line input (UI edit boxes, chat, console) and Input Method Editor (IME) support from upstream. Closes #4397.

General
------------------------------

Fix issues with the text input. Closes #4346. Closes #4524.

Word skipping (when holding Ctrl) is overhauled to be consistent with the Windows / Firefox experience that I took as reference.

Improve usability by not blinking (i.e. always rendering) the caret shortly after is has been moved.

UI text input
------------------------------

Fix inconsistent mouse-based left and right scrolling (closes #4347).

Support smooth left and right scrolling.

Chat
------------------------------

Support keyboard-based text selection of the chat input.

Mouse-based selection could be support in the future when we decide to add something like an ingame UI cursor.

Support smooth up and down scrolling of the chat input, removing the old hack that offsets the input string to simulate scrolling.

Console
------------------------------

Also support mouse-based text selection of the command input.

Only text from either the command input or the console log can be selected at the same time. This ensures that Ctrl+C will always copy the text that is currently visually selected in the console.

Check for Ctrl+C input event in event handler instead of in render function, to hopefully fix the issue that copying does not work sometimes (closes #5974 until further notice).

When Ctrl+C is used to copy text from the console log, the selection is cleared. This should make it more clear when text was copied from the log.

Fix an issue that was preventing the console log selection from being cleared, when all log lines are selected.

Remove Ctrl+A/E hotkeys that move cursor to beginning/end respectively. Ctrl+A now selectes all text like for all other inputs. Home and End keys can still be used to go the beginning and end.

Remove Ctrl+U/K hotkeys that clear everything before/after the cursor respectively. Hold shift and use Home/End to select everything instead.

IME support
------------------------------

Render list of IME candidates in the client on Windows, so the candidate list can also be viewed in fullscreen mode. There is no API available to retrieve a candidate list on the other operating systems.

Improve composition rendering by underlining the composition text instead of putting it in square brackets.

Track active input globally to properly activate and deactivate IME through the SDL functions.

Closes #1030. Closes #1008.

Password rendering
------------------------------

Fix rendering of passwords containing unicode. Instead of rendering one star character for each UTF-8 `char`, render on star for every unicode codepoint.

Show the composition text also for passwords. Without seeing the composition text it's hard to type a password containing those characters. The candidate window exposes the composition anyway. If you don't want to expose your password this way, e.g. while streaming, you could:

1. Use a latin password and switch off the IME for the password input with the IME hotkey.
2. Blank your screen with an external program while you are streaming and entering passwords.
3. Use binds to authenticate in rcon or to set the server browser password.

Refactoring
------------------------------

Move all text input logic and general rendering to `CLineInput`.

A `CLineInput` is associated with a particular `char` buffer given as a pointer either in the constructor or with `SetBuffer`. The maximum byte size of the buffer must also be specified. The maximum length in unicode codepoints can also be specified separately (e.g. on upstream, name are limited by the number of unicode codepoints instead).

Add `CLineInputBuffered`, which is a `CLineInput` that own a `char` buffer of a fixed size, which is specified as a template argument. As `CLineInput` does not own a buffer anymore, this reduces duplicate code for line inputs that need their own buffer.

Add `CLineInputNumber` which has additional convenience functions to consider the text as an `int` or `float`, to reduce duplicate code in those cases. In the future we could also add an input filter function so that only numbers can be entered in the number input.

Add `CLineInput::SetClipboardLineCallback` to handle the case that multiple lines of text are pasted into a lineinput. This reduces duplicate code, as this behavior was previously implemented separately for chat and console. The behavior is also fixed to be consistent with the console on Windows, so the first line being pasted edits the current input text and then sends it instead of being sent on its own without the existing input text.

Add `CalcFontSizeAndBoundingBox` to UI to reduce duplicate code. Expose `CalcAlignedCursorPos` as static member function to reuse it for line input.

Dispatch input events to UI inputs through the event handler instead of storing them in a duplicate buffer.

Use `size_t` for line input cursor position, length etc. and for `str_utf8_stats`.

Add `IButtonColorFunction` to UI to describe a functions that defines colors for the Default, Active and Hovered states of UI elements. Add some default button color functions. Use button color function to reduce duplicate code in scrollbar rendering.

Use `vec2` instead of two `floats` to represent the mouse positions in the text renderer.

Remove `CaretPosition` again, as it does not calculate the correct Y position near line breaks due to the wrapping being different when not rendering the entire string. Instead, calculate the exact caret position when rending a text container and store the caret position in the text cursor for later use.

IME usage guide (Windows)
------------------------------

1. Install the respective language and the Microsoft-IME keyboard (e.g. for Chinese, Japanese or Korean).
2. Launch the game (or a text editor to first try out the IME). Note that Windows may track the input language separately for every application. You can change this in the Windows input settings so the input language is changed globally.
2. Switch the input language using the hotkey Windows+Space or another hotkey that you configured in the Windows input settings (Alt+Shift is the default, but you should consider disabling it, to avoid accidentally changing the input language while playing).
3. Switch from Latin/English input mode to the respective asian input mode.
   - Chinese: Use Ctrl+Space to switch between English and Chinese input mode. You can change this hotkey in the IME's settings.
   - Japanese: Use Ctrl+Space to switch between Alphanumeric and Hiragana/Katakana input mode. You can change this hotkey in the IME's settings.
   - Korean: Use Right Alt to switch between English and Hangul input mode. You cannot change this hotkey as of yet.
   - Note that the input mode is also tracked per application, but there is no setting to change this behavior as far as I know, so you'll need to switch for every application separately.
4. Start typing. The underlined text is the current composition text. While a composition is active, you can only edit the composition text. Confirm the composition with Space or by selecting a candidate from the candidate list with the arrow keys. Cancel the composition with Escape or by using Backspace to delete the composition text. Note that not all languages offer a candidate list.

SDL version-specific issues
------------------------------

- 2.26.5, 2.24.2, 2.0.22: IME candidates work. But there are minor bugs when moving the composition cursor.
- 2.0.18, 2.0.20: IME candidates work.
- 2.0.16 (our current version): IME candidates cannot be determined with Windows API. Windows tries to draw the composition window like before, so this does not work in fullscreen mode.
- 2.0.8 (upstream 0.7): IME candidates work. But this SDL version is too old for us.
2023-04-23 15:00:29 +02:00
Robert Müller aa0ad18f1b Refactor net_set_blocking and net_set_non_blocking
Reduce duplicate code by using loop and by merging implementation of `net_set_blocking` and `net_set_non_blocking`.
2023-03-25 15:36:50 +01:00
Dennis Felsing 5252667204 Round by millisecond, not centisecond (fixes #6453)
Some servers seem to allow times with millisecond precision, official
DDNet doesn't, so never noticed this issue.
2023-03-23 09:47:48 +01:00
Robert Müller 413227a5c1 Add os_locale_str to get user locale
This function determines the preferred user locale setting.
2023-03-21 21:17:40 +01:00
Robert Müller d0fe1087db Add str_format_v with va_list argument
So the string formatting can be reused in other places. Passing variadic arguments directly to another function is not possible.

The function must have a different name, as overloading `str_format` would cause the wrong function to be called when passing the `va_list`. The same naming with suffix `_v` is used for the logging functions.
2023-03-19 11:48:39 +01:00
Robert Müller 3996ee01a7 Close process handle on Windows after process is killed
Prevent leak of process handle. Keep the handle open if the process could not be killed, so killing can be attempted again.
2023-03-10 18:02:39 +01:00
Robert Müller a76fb9b99a Replace all usages of C standard headers with C++ headers 2023-03-01 19:26:51 +01:00
Robert Müller 18cfbb53f9 Use size_t for mem_* function size parameters 2023-02-19 12:48:54 +01:00
Robert Müller d4809fa9a8 Change mem_has_null return type to bool 2023-02-19 12:48:54 +01:00
Robert Müller cb6de6a384 Group and order mem_* function implementations 2023-02-19 12:48:53 +01:00
Robert Müller 3173aeec6a Simplify io_write_newline error handling
Instead of returning the number of bytes written, which are platform specific, return `true` on success and `false` on failure, so no platform specific code is required when checking the result.
2023-02-18 14:13:55 +01:00
Robert Müller 64081ad3e4 Add static assert to ensure correct size of int and unsigned
We assume in various places, especially when using `bytes_be_to_uint` and `uint_to_bytes_be`, that `int` and `unsigned` are 4 bytes in size.
2023-02-04 01:24:03 +01:00
Robert Müller 218e6f7985 Remove bytes_be_to_int and int_to_bytes_be
Use `bytes_be_to_uint` and `uint_to_bytes_be` instead.

As casting between `int` and `unsigned` preserves the bit representation of the value, it's not necessary to apply additional tricks to convert between `char` arrays and `int`.
2023-02-04 01:24:03 +01:00
bors[bot] e0315f528e
Merge #6313
6313: Use `str_copy` instead of `str_format`, minor fixes and refactoring r=Chairn a=Robyt3



## Checklist

- [ ] Tested the change ingame
- [ ] Provided screenshots if it is a visual change
- [ ] Tested in combination with possibly related configuration options
- [ ] Written a unit test (especially base/) or added coverage to integration test
- [ ] Considered possible null pointers and out of bounds array indexing
- [ ] Changed no physics that affect existing maps
- [ ] Tested the change with [ASan+UBSan or valgrind's memcheck](https://github.com/ddnet/ddnet/#using-addresssanitizer--undefinedbehavioursanitizer-or-valgrinds-memcheck) (optional)


Co-authored-by: Robert Müller <robytemueller@gmail.com>
2023-01-28 16:17:47 +00:00
Robert Müller 52aa8ac22a Use str_copy instead of str_format
Using `str_format` without format arguments is equivalent to `str_copy`, but using the latter is more efficient and readable.

As `str_format` also returns the result `str_utf8_fix_truncation`, i.e. the potentially truncated string length, the return value is also added to `str_copy` so existing invocations don't need to be adjusted.
2023-01-28 16:37:33 +01:00
Dennis Felsing ccc6cd59de Only use pthread_attr_set_qos_class_np if it's available
Noticed in nixOS that DDNet package is marked as broken on Darwin for this reason:
https://github.com/NixOS/nixpkgs/blob/master/pkgs/games/ddnet/default.nix
2023-01-26 15:42:46 +01:00
bors[bot] b8e7160555
Merge #6299
6299: Show error message when downloaded map cannot be saved r=def- a=Robyt3

Check if deleting the old map file or renaming the temporary downloaded map fails. If so, show an error message which indicates that the user should delete the map file manually.

Sometimes downloaded map files seem to end up with wrong permissions, ownership or with read-only flag set, which makes the client unable to delete them.

![screenshot_2023-01-22_17-19-12](https://user-images.githubusercontent.com/23437060/213927019-ff49cb72-f60a-4c1a-b48b-d34e40d1420e.png)

Closes #5825.

## Checklist

- [X] Tested the change ingame
- [ ] Provided screenshots if it is a visual change
- [ ] Tested in combination with possibly related configuration options
- [ ] Written a unit test (especially base/) or added coverage to integration test
- [ ] Considered possible null pointers and out of bounds array indexing
- [ ] Changed no physics that affect existing maps
- [ ] Tested the change with [ASan+UBSan or valgrind's memcheck](https://github.com/ddnet/ddnet/#using-addresssanitizer--undefinedbehavioursanitizer-or-valgrinds-memcheck) (optional)


Co-authored-by: Robert Müller <robytemueller@gmail.com>
2023-01-23 11:41:51 +00:00
Robert Müller b67a1f5ce5 Add fs_is_file to check if a given path is file 2023-01-22 17:22:11 +01:00
Robert Müller f7d3052170 Export windows_format_system_message utility on Windows
Declare the function in `system.h`, so we can use it in other platform-specific components.
2023-01-20 22:53:00 +01:00
Robert Müller 0e59b84718 Add str_hex_cstyle to print bytes as a C style array
This function converts data to a C style array string presentation.
2023-01-18 17:29:23 +01:00
heinrich5991 e62293e56c Remove remaining extern "C" from codebase
This might require rebuilding the antibot
2023-01-09 17:58:38 +01:00
bors[bot] 29bf49ae31
Merge #6217
6217: Register application separately to specify its displayed name r=def- a=Robyt3

Follow-up from #6199.

Adding version information to the executable (#6203) doesn't result in the name being shown in the Windows settings. There is a separate registry key where applications can register a readable name.

See: https://learn.microsoft.com/en-us/windows/win32/shell/app-registration

## Checklist

- [X] Tested the change ingame
- [ ] Provided screenshots if it is a visual change
- [ ] Tested in combination with possibly related configuration options
- [ ] Written a unit test (especially base/) or added coverage to integration test
- [ ] Considered possible null pointers and out of bounds array indexing
- [ ] Changed no physics that affect existing maps
- [ ] Tested the change with [ASan+UBSan or valgrind's memcheck](https://github.com/ddnet/ddnet/#using-addresssanitizer--undefinedbehavioursanitizer-or-valgrinds-memcheck) (optional)


Co-authored-by: Robert Müller <robytemueller@gmail.com>
2023-01-02 21:55:37 +00:00
Chairn 8b3dfaf2d0 Add some more test to str_comp_filenames and restore old behavior 2023-01-02 21:20:49 +01:00
Robert Müller 179e3b1c4c Register application separately to specify its displayed name
The application itself must also be registered in a separate registry key, so its displayed name can be set.

See: https://learn.microsoft.com/en-us/windows/win32/shell/app-registration
2023-01-02 17:35:16 +01:00
Robert Müller a0df1ebfc0 Fix updated not being set correctly when deleting shell class 2023-01-02 15:29:43 +01:00
Robert Müller f3eeddf8bd Fix some registry keys not being closed if values are unchanged 2023-01-02 15:29:42 +01:00
bors[bot] b252f2e344
Merge #6199
6199: Register protocol and file extensions on client launch on Windows r=def- a=Robyt3

When launching the client on Windows, associate the protocol `ddnet` and the file extensions `.map` and `.demo` with the client executable.

See #6072.

## Checklist

- [X] Tested the change ingame
- [ ] Provided screenshots if it is a visual change
- [ ] Tested in combination with possibly related configuration options
- [ ] Written a unit test (especially base/) or added coverage to integration test
- [ ] Considered possible null pointers and out of bounds array indexing
- [ ] Changed no physics that affect existing maps
- [ ] Tested the change with [ASan+UBSan or valgrind's memcheck](https://github.com/ddnet/ddnet/#using-addresssanitizer--undefinedbehavioursanitizer-or-valgrinds-memcheck) (optional)


Co-authored-by: Robert Müller <robytemueller@gmail.com>
2023-01-02 12:58:15 +00:00
def c6339055b7 Address comment from https://github.com/ddnet/ddnet/pull/6206/
@Chairn
2022-12-31 00:16:30 +01:00
Chairn 2847d0f6d0 Added some test cases that were failing under new version 2022-12-30 01:11:57 +01:00
Chairn ed58668931 Remove possible overflow in str_comp_filenames (fixes #6204) 2022-12-30 00:29:19 +01:00
Robert Müller 3b73107100 Add shell_unregister to delete protocol/file extension handlers
This function removes the registry keys that are created with `shell_register_protocol` and `shell_register_extension`.

According to the Microsoft documentation, only the keys for the program IDs should be deleted.
The keys that associate the file extensions with the program IDs should be kept, as Windows will automatically ignore the value if the program ID does not exist.

See: https://learn.microsoft.com/en-us/windows/win32/shell/fa-file-types#deleting-registry-information-during-uninstallation
2022-12-29 18:03:08 +01:00
Robert Müller 8a3a8974d0 Add shell_update to notify system to update shell
The `shell_update` function notifies the system when the shell needs to be updated due to a changed protocol or file association.

An output parameter is added to the `shell_register_protocol` and `shell_register_extension` functions, to determine whether the shell needs to be updated after calling the functions.
We only check whether the application path and program association were changed, instead of checking whether any key or value was changed, as this reduces the amount of necessary checks and we assume that the other values are not externally changed.

Because updating the shell is a potentially expensive operation, this should only be done when necessary and only once after registering all protocols and extensions.
2022-12-29 18:02:48 +01:00
Robert Müller 4e130a29e4 Add shell_register_extension to register file extension on Windows
This function register a file extension on Windows by creating the necessary registry keys and values.

The file extension is only registered for the current user in the registry key `HKEY_CURRENT_USER\SOFTWARE\Classes`, so admin privileges are not required.

Windows does not allow changing the default file extension handler programatically. When the user opens a file for which a new file extension handler exists, a dialog is shown that allows the user to change the default handler.
2022-12-29 18:01:42 +01:00
Robert Müller 7294ce5cf6 Add shell_register_protocol to register protocol handler on Windows
This function registers a protocol handler on Windows by creating the necessary registry keys and values.

The handler is only registered for the current user in the registry key `HKEY_CURRENT_USER\SOFTWARE\Classes`, so admin privileges are not required.
2022-12-29 18:01:40 +01:00
heinrich5991 042f892f40 Allow translations to reorder string substitutions
This is supported on Windows
(https://docs.microsoft.com/en-us/cpp/c-runtime-library/printf-p-positional-parameters)
and on POSIX, so basically everywhere.

Add some tests to verify that the target system does indeed support
these positional parameters.

(cherry picked from commit ddd2b93190)
2022-12-25 21:45:26 +01:00
bors[bot] cf6e89c319
Merge #6035
6035: Fix various issues reported by cppcheck static analyser r=def- a=Robyt3

After generating `compile_commands.json` with cmake, I ran [cppcheck](https://cppcheck.sourceforge.io/) like this:

```
cppcheck --project=compile_commands.json -DWIN64 --suppressions-list=cppcheck.supp --enable=all 2>cppcheck.log
```

With these suppressions in `cppcheck.supp`:

```
cstyleCast
useStlAlgorithm
unusedFunction
variableScope
noExplicitConstructor
useInitializationList
noConstructor
uninitMemberVar
uninitMemberVarPrivate
uninitDerivedMemberVar
uninitStructMember
uninitvar
shadowFunction
memleakOnRealloc
internalAstError
virtualCallInConstructor
unknownMacro
noOperatorEq
noCopyConstructor
```

Many of these occur too often or are false positives. 

Here is a list of all remaining non-suppressed issues reported by cppcheck: [cppcheck.log](https://github.com/ddnet/ddnet/files/9997663/cppcheck.log)

And here is a list of all remaining issues including the suppressed ones: [cppcheck_all.log](https://github.com/ddnet/ddnet/files/9997662/cppcheck_all.log)

I couldn't get cppcheck's command line argument to ignore the external folders to work correctly, so I manually removed those entries from the files.

## Checklist

- [ ] Tested the change ingame
- [ ] Provided screenshots if it is a visual change
- [ ] Tested in combination with possibly related configuration options
- [ ] Written a unit test (especially base/) or added coverage to integration test
- [ ] Considered possible null pointers and out of bounds array indexing
- [ ] Changed no physics that affect existing maps
- [ ] Tested the change with [ASan+UBSan or valgrind's memcheck](https://github.com/ddnet/ddnet/#using-addresssanitizer--undefinedbehavioursanitizer-or-valgrinds-memcheck) (optional)


Co-authored-by: Robert Müller <robytemueller@gmail.com>
2022-12-05 20:00:07 +00:00
Zwelf a7bc593725 Make semaphore wait handle EINTR
from `man sem_wait`:

    EINTR  The call was interrupted by a signal handler; see signal(7).
2022-12-05 16:48:10 +01:00
Robert Müller 98706d79d4 Mark parameters as const when possible
According to cppchecker's `constParameter` error:

```
src\engine\gfx\image_manipulation.cpp:7:58: style: Parameter 'pSrc' can be declared as pointer to const [constParameter]
static void Dilate(int w, int h, int BPP, unsigned char *pSrc, unsigned char *pDest, unsigned char AlphaThreshold = TW_DILATE_ALPHA_THRESHOLD)
                                                         ^
src\engine\gfx\image_manipulation.cpp:58:67: style: Parameter 'pSrc' can be declared as pointer to const [constParameter]
static void CopyColorValues(int w, int h, int BPP, unsigned char *pSrc, unsigned char *pDest)
                                                                  ^

src\engine\shared\network_conn.cpp:241:42: style: Parameter 'Addr' can be declared as reference to const [constParameter]
void CNetConnection::DirectInit(NETADDR &Addr, SECURITY_TOKEN SecurityToken, SECURITY_TOKEN Token, bool Sixup)
                                         ^

src\base\system.cpp:4060:71: style: Parameter 'random' can be declared as pointer to const [constParameter]
void generate_password(char *buffer, unsigned length, unsigned short *random, unsigned random_length)
                                                                      ^

src\engine\client\backend\vulkan\backend_vulkan.cpp:263:38: style: Parameter 'AllocatedMemory' can be declared as reference to const [constParameter]
  void Free(SMemoryHeapQueueElement &AllocatedMemory)
                                     ^
src\engine\client\backend\vulkan\backend_vulkan.cpp:1708:47: style: Parameter 'ImgExtent' can be declared as reference to const [constParameter]
 static size_t ImageMipLevelCount(VkExtent3D &ImgExtent)
                                              ^
src\engine\client\backend\vulkan\backend_vulkan.cpp:2801:29: style: Parameter 'Image' can be declared as reference to const [constParameter]
 void ImageBarrier(VkImage &Image, size_t MipMapBase, size_t MipMapCount, size_t LayerBase, size_t LayerCount, VkFormat Format, VkImageLayout OldLayout, VkImageLayout NewLayout)
                            ^
src\engine\client\backend\vulkan\backend_vulkan.cpp:6495:46: style: Parameter 'ExecBuffer' can be declared as reference to const [constParameter]
 void Cmd_Clear(SRenderCommandExecuteBuffer &ExecBuffer, const CCommandBuffer::SCommand_Clear *pCommand)
                                             ^

src\game\client\components\skins.cpp:83:72: style: Parameter 'pImg' can be declared as pointer to const [constParameter]
static void CheckMetrics(CSkin::SSkinMetricVariable &Metrics, uint8_t *pImg, int ImgWidth, int ImgX, int ImgY, int CheckWidth, int CheckHeight)
                                                                       ^

src\game\client\prediction\entities\character.h:106:37: style: Parameter 'pNewInput' can be declared as pointer to const [constParameter]
 void SetInput(CNetObj_PlayerInput *pNewInput)
                                    ^

src\game\client\prediction\gameworld.cpp:245:106: style: Parameter 'pNotThis' can be declared as pointer to const [constParameter]
CCharacter *CGameWorld::IntersectCharacter(vec2 Pos0, vec2 Pos1, float Radius, vec2 &NewPos, CCharacter *pNotThis, int CollideWith, class CCharacter *pThisOnly)
                                                                                                         ^
src\game\client\prediction\gameworld.cpp:245:151: style: Parameter 'pThisOnly' can be declared as pointer to const [constParameter]
CCharacter *CGameWorld::IntersectCharacter(vec2 Pos0, vec2 Pos1, float Radius, vec2 &NewPos, CCharacter *pNotThis, int CollideWith, class CCharacter *pThisOnly)
                                                                                                                                                      ^
src\game\client\prediction\gameworld.cpp:283:116: style: Parameter 'pNotThis' can be declared as pointer to const [constParameter]
std::list<class CCharacter *> CGameWorld::IntersectedCharacters(vec2 Pos0, vec2 Pos1, float Radius, class CEntity *pNotThis)
                                                                                                                   ^

src\game\client\ui.cpp:522:180: style: Parameter 'pReadCursor' can be declared as pointer to const [constParameter]
void CUI::DoLabel(CUIElement::SUIElementRect &RectEl, const CUIRect *pRect, const char *pText, float Size, int Align, const SLabelProperties &LabelProps, int StrLen, CTextCursor *pReadCursor)
                                                                                                                                                                                   ^

src\game\client\ui_scrollregion.cpp:23:86: style: Parameter 'pParams' can be declared as pointer to const [constParameter]
void CScrollRegion::Begin(CUIRect *pClipRect, vec2 *pOutOffset, CScrollRegionParams *pParams)
                                                                                     ^

src\game\server\scoreworker.h:239:29: style: Parameter 'aTimeCp' can be declared as const array [constParameter]
 void Set(float Time, float aTimeCp[NUM_CHECKPOINTS])
                            ^

src\game\server\score.cpp:135:80: style: Parameter 'aTimeCp' can be declared as const array [constParameter]
void CScore::SaveScore(int ClientID, float Time, const char *pTimestamp, float aTimeCp[NUM_CHECKPOINTS], bool NotEligible)
                                                                               ^

src\game\server\teeinfo.cpp:40:57: style: Parameter 'pUseCustomColors' can be declared as pointer to const [constParameter]
CTeeInfo::CTeeInfo(const char *apSkinPartNames[6], int *pUseCustomColors, int *pSkinPartColors)
                                                        ^
src\game\server\teeinfo.cpp:40:80: style: Parameter 'pSkinPartColors' can be declared as pointer to const [constParameter]
CTeeInfo::CTeeInfo(const char *apSkinPartNames[6], int *pUseCustomColors, int *pSkinPartColors)
                                                                               ^
```
2022-11-29 23:32:31 +01:00
Robert Müller e134e4e488 Remove redundant conditions (always either true or false)
According to cppcheck's `knownConditionTrueFalse` error:

```
src\base\system.cpp:1776:11: style: The comparison 'bytes == 0' is always true. [knownConditionTrueFalse]
 if(bytes == 0 && sock->ipv4sock >= 0)
          ^
src\base\system.cpp:1742:14: note: 'bytes' is assigned value '0' here.
 int bytes = 0;
             ^
src\base\system.cpp:1776:11: note: The comparison 'bytes == 0' is always true.
 if(bytes == 0 && sock->ipv4sock >= 0)
          ^

src\game\editor\io.cpp:887:33: style: Condition 'pSoundsItem->m_Version>=1' is always true [knownConditionTrueFalse]
      if(pSoundsItem->m_Version >= 1)
                                ^
src\game\editor\io.cpp:874:33: note: Assuming that condition 'pSoundsItem->m_Version<1' is not redundant
      if(pSoundsItem->m_Version < 1 || pSoundsItem->m_Version > CMapItemLayerSounds::CURRENT_VERSION)
                                ^
src\game\editor\io.cpp:887:33: note: Condition 'pSoundsItem->m_Version>=1' is always true
      if(pSoundsItem->m_Version >= 1)
                                ^
src\game\editor\io.cpp:914:33: style: Condition 'pSoundsItem->m_Version>=1' is always true [knownConditionTrueFalse]
      if(pSoundsItem->m_Version >= 1)
                                ^
src\game\editor\io.cpp:901:33: note: Assuming that condition 'pSoundsItem->m_Version<1' is not redundant
      if(pSoundsItem->m_Version < 1 || pSoundsItem->m_Version > CMapItemLayerSounds::CURRENT_VERSION)
                                ^
src\game\editor\io.cpp:914:33: note: Condition 'pSoundsItem->m_Version>=1' is always true
      if(pSoundsItem->m_Version >= 1)
                                ^

src\engine\client\backend\opengl\backend_opengl.cpp:207:68: style: Condition '*pStr=='\0'' is always false [knownConditionTrueFalse]
   else if(LastWasNumber && (*pStr == '.' || *pStr == ' ' || *pStr == '\0'))
                                                                   ^

src\game\client\components\maplayers.cpp:851:110: style: Condition 'DoTextureCoords' is always true [knownConditionTrueFalse]
        mem_copy_special(pUploadData + sizeof(vec2), pTmpTileTexCoords, sizeof(vec3), vtmpTiles.size() * 4, (DoTextureCoords ? (sizeof(vec2)) : 0));
                                                                                                             ^
src\game\client\components\maplayers.cpp:849:11: note: Assuming that condition 'DoTextureCoords' is not redundant
       if(DoTextureCoords)
          ^

src\game\client\components\maplayers.cpp:851:110: note: Condition 'DoTextureCoords' is always true
        mem_copy_special(pUploadData + sizeof(vec2), pTmpTileTexCoords, sizeof(vec3), vtmpTiles.size() * 4, (DoTextureCoords ? (sizeof(vec2)) : 0));
                                                                                                             ^

src\game\client\prediction\gameworld.cpp:567:5: style: Condition 'm_pParent' is always true [knownConditionTrueFalse]
 if(m_pParent && m_pParent->m_pChild && m_pParent->m_pChild != this)
    ^

src\game\client\components\menu_background.cpp:271:7: style: Condition 'NeedImageLoading' is always true [knownConditionTrueFalse]
   if(NeedImageLoading)
      ^
src\game\client\components\menu_background.cpp:268:23: note: Assignment 'NeedImageLoading=true', assigned value is 1
   NeedImageLoading = true;
                      ^
src\game\client\components\menu_background.cpp:271:7: note: Condition 'NeedImageLoading' is always true
   if(NeedImageLoading)
      ^

src\game\editor\editor.cpp:4991:6: style: Condition 'pEnvelope' is always true [knownConditionTrueFalse]
  if(pEnvelope)
     ^
```
2022-11-29 23:32:26 +01:00
Robert Müller 6501ae9b9d Add checks for remaining WideCharToMultiByte usages in system
Converting wide-char (UTF-16) to multi-byte (UTF-8) takes 1-2 wide-chars from the input and transforms them to 1-4 bytes, so having `char` and `WCHAR` buffers with equal static lengths means that this function can fail due to insufficient buffer sizes when the user has folder or files with very long names (many unicode codepoints).
Therefore checks are added that allow only the error `ERROR_INSUFFICIENT_BUFFER` when `WideCharToMultiByte` fails, which is expected on very long paths, as these would also lead to further errors later in the code. The respective functions will now fail with a return and ignore files that have too long names.
This could only completely be fixed using dynamically sized buffers for all paths, which seems like too much work and overhead.
Other errors are not expected and hence caught by the assertions, as those would indicate programming errors like wrong arguments being passed.

Reference: https://learn.microsoft.com/en-us/windows/win32/api/stringapiset/nf-stringapiset-widechartomultibyte
2022-10-29 21:17:48 +02:00
Robert Müller 6c30fb6f5a Remove duplicate buffer from fs_listdir functions
The second buffer was previously used when calling `fs_is_dir` explicity, but it has become from obsolete from #4657 by using the flag `FILE_ATTRIBUTE_DIRECTORY` instead.
2022-10-29 21:17:48 +02:00
Robert Müller 8bde109acb Use dynamic size for formatted Windows system messages
Extract `windows_format_system_message` and allocate appropriate buffer for the formatted system error messages, so messages of any length can be displayed.

The flag `FORMAT_MESSAGE_ALLOCATE_BUFFER` is used so `FormatMessageW` allocates the buffer which must later be freed with `LocalFree`.

The flag `FORMAT_MESSAGE_MAX_WIDTH_MASK` is also added so the formatted message will not contain any line breaks at the end, which would make log messages less readable.

Reference: https://learn.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-formatmessagew
2022-10-29 21:17:47 +02:00
Robert Müller a1c1a8f972 Add assertions for all MultiByteToWideChar usages in system
Converting multi-byte (UTF-8) to wide-char (UTF-16) take 1-4 bytes from the input and transforms them to 1-2 wide-chars, so having `char` and `WCHAR` buffers with equal lengths should mean that this function can't fail due to insufficient buffer sizes, unless a path that's already too long for Windows is being used internally.
Other errors are also not expected, as those would indicate programming errors like wrong arguments being passed.

The maximum length for paths in the Win32 API is 260 characters. This limitation can be lifted in Windows 10, but it must be done explicitly (opt-in) both in the Windows Registry by the user and in the application's manifest by us.

References:

- https://learn.microsoft.com/en-us/windows/win32/api/stringapiset/nf-stringapiset-multibytetowidechar
- https://learn.microsoft.com/en-us/windows/win32/fileio/maximum-file-path-limitation?tabs=registry
2022-10-29 21:17:47 +02:00
Robert Müller 5c11937543 Use fegetenv/fesetenv instead of _control87 on Windows
As `_control87` doesn't seem to be available for some MinGW compilers.

Closes #5969.
2022-10-23 10:59:53 +02:00
Robert Müller c4cf26ea81 Replace atol usages with str_toint, as type is int anyway
As `atol` does not provide any way to detect errors and can cause undefined behavior on errors, i.e. when the result cannot be represented as a `long`.

The `atol` function was only used in `priv_net_extract` for parsing the port, which is an `int` and not a `long`, so the existing `str_toint` is used instead.

References:

- https://wiki.sei.cmu.edu/confluence/display/c/ERR07-C.+Prefer+functions+that+support+error+checking+over+equivalent+functions+that+don%27t
- https://pubs.opengroup.org/onlinepubs/9699919799/functions/atol.html
2022-10-20 20:54:01 +02:00
Robert Müller 1469e88a79 Replace atof usages with strtod (str_tofloat wrapper)
As `atof` does not provide any way to detect errors and can cause undefined behavior on errors, i.e. when the result cannot be represented as a `float`.

References:

- https://wiki.sei.cmu.edu/confluence/display/c/ERR07-C.+Prefer+functions+that+support+error+checking+over+equivalent+functions+that+don%27t
- https://pubs.opengroup.org/onlinepubs/9699919799/functions/atof.html
2022-10-20 20:30:12 +02:00
Robert Müller 6b043bf3b2 Replace atoi usages with strtol (str_toint wrapper)
As `atoi` does not provide any way to detect errors and can cause undefined behavior on errors, i.e. when the result cannot be represented as an `int`.

References:

- https://wiki.sei.cmu.edu/confluence/display/c/ERR07-C.+Prefer+functions+that+support+error+checking+over+equivalent+functions+that+don%27t
- https://pubs.opengroup.org/onlinepubs/9699919799/functions/atoi.html
2022-10-20 20:30:11 +02:00
Robert Müller 25e6eed0e8 Fix compilation with VS2022 with exception handling enabled
By moving the calling convention `APIENTRY`, which expands to `__stdcall`, inside the parenthesis.

```
Severity	Code	Description	Project	File	Line	Suppression State
Error	C2143	syntax error: missing ')' before '('	engine-shared	src\base\system.cpp	4242
Warning	C4229	anachronism used: modifiers on data are ignored	engine-shared	src\base\system.cpp	4242
Error	C2059	syntax error: ')'	engine-shared	src\base\system.cpp	4242
Error	C2059	syntax error: ')'	engine-shared	src\base\system.cpp	4242
Error	C3536	'exception_log_file_path_func': cannot be used before it is initialized	engine-shared	src\base\system.cpp	4246
Error	C2446	'==': no conversion from 'nullptr' to 'int'	engine-shared	src\base\system.cpp	4246
Error	C2064	term does not evaluate to a function taking 1 arguments	engine-shared	src\base\system.cpp	4249
```
2022-10-16 18:16:58 +02:00
bors[bot] bd3b4f2d50
Merge #5942
5942: Support unicode with ExcHndl, use upstream module offsets, handle errors r=def- a=Robyt3

Update Dr. Mingw (ExcHndl) to 0.9.8.

Use the new `ExcHndlSetLogFileNameW` function to set the exception log file name using wide characters, to support paths containing unicode.

It's not necessary to call `ExcHndlInit` explicitly after loading `exchndl.dll`, as the `DllMain` will already initialize the exception handler when the DLL is loaded. Module offsets are supported by upstream ExcHndl now, so we don't need to provide our own version that supplies the module offset to `ExcHndlInit` anymore. Upstream ExcHndl will also resolve the source code lines for addresses automatically, when the executable is build with debug information.

Handle the cases that the exception handling module cannot be loaded and that the `ExcHndlSetLogFileNameW` function cannot be found in the module.

Update `scripts/parse_drmingw.sh`:

- Parse both old and new module offsets.
- Use tabs instead of spaces consistently.
- Reset the ANSI color after printing colored messages.

Closes #5877.

Needs https://github.com/ddnet/ddnet-libs/pull/34.

Example crash logs:

- [crash_debug_old.RTP.txt](https://github.com/ddnet/ddnet/files/9768008/crash_debug_old.RTP.txt)
- [crash_debug_new.RTP.txt](https://github.com/ddnet/ddnet/files/9768011/crash_debug_new.RTP.txt)
- [crash_release_old.RTP.txt](https://github.com/ddnet/ddnet/files/9768010/crash_release_old.RTP.txt)
- [crash_release_new.RTP.txt](https://github.com/ddnet/ddnet/files/9768009/crash_release_new.RTP.txt)

## Checklist

- [X] Tested the change ingame
- [ ] Provided screenshots if it is a visual change
- [ ] Tested in combination with possibly related configuration options
- [ ] Written a unit test (especially base/) or added coverage to integration test
- [ ] Considered possible null pointers and out of bounds array indexing
- [ ] Changed no physics that affect existing maps
- [ ] Tested the change with [ASan+UBSan or valgrind's memcheck](https://github.com/ddnet/ddnet/#using-addresssanitizer--undefinedbehavioursanitizer-or-valgrinds-memcheck) (optional)


Co-authored-by: Robert Müller <robytemueller@gmail.com>
2022-10-12 21:44:43 +00:00