mabe02/lanterna

StringIndexOutOfBoundsException in CJK character handling

schuettec opened this issue · 3 comments

Hi, nice library, thanks for that work!
I got a StringIndexOutOfBoundsException in one of my applications. I tried to build an SSCCE but I cannot reproduce the bug in a short example. In my application I use two nested panels, basically a BorderLayout as parent and a GridLayout in a child component. When showing a message dialog using

    new MessageDialogBuilder().setTitle(title)
        .setText(errorMessage)
        .addButton(MessageDialogButton.OK)
        .build()
        .showDialog(gui);

the following exception occurs:

java.lang.StringIndexOutOfBoundsException: String index out of range: 84
	at java.base/java.lang.StringLatin1.charAt(StringLatin1.java:48)
	at java.base/java.lang.String.charAt(String.java:711)
	at com.googlecode.lanterna.TerminalTextUtils.getStringCharacterIndex(TerminalTextUtils.java:230)
	at com.googlecode.lanterna.TerminalTextUtils.getWordWrappedText(TerminalTextUtils.java:323)
	at com.googlecode.lanterna.gui2.Label$1.drawComponent(Label.java:259)
	at com.googlecode.lanterna.gui2.Label$1.drawComponent(Label.java:234)
	at com.googlecode.lanterna.gui2.AbstractComponent.draw(AbstractComponent.java:239)
	at com.googlecode.lanterna.gui2.Panel$DefaultPanelRenderer.drawComponent(Panel.java:273)
	at com.googlecode.lanterna.gui2.Panel$DefaultPanelRenderer.drawComponent(Panel.java:229)
	at com.googlecode.lanterna.gui2.AbstractComponent.draw(AbstractComponent.java:239)
	at com.googlecode.lanterna.gui2.AbstractBasePane$ContentHolder$1.drawComponent(AbstractBasePane.java:474)
	at com.googlecode.lanterna.gui2.AbstractBasePane$ContentHolder$1.drawComponent(AbstractBasePane.java:451)
	at com.googlecode.lanterna.gui2.AbstractComponent.draw(AbstractComponent.java:239)
	at com.googlecode.lanterna.gui2.AbstractBasePane.draw(AbstractBasePane.java:85)
	at com.googlecode.lanterna.gui2.AbstractWindow.draw(AbstractWindow.java:130)
	at com.googlecode.lanterna.gui2.MultiWindowTextGUI.drawGUI(MultiWindowTextGUI.java:275)
	at com.googlecode.lanterna.gui2.AbstractTextGUI.updateScreen(AbstractTextGUI.java:120)
	at com.googlecode.lanterna.gui2.MultiWindowTextGUI.updateScreen(MultiWindowTextGUI.java:236)
	at com.googlecode.lanterna.gui2.AbstractTextGUIThread.processEventsAndUpdate(AbstractTextGUIThread.java:85)
	at com.googlecode.lanterna.gui2.MultiWindowTextGUI.waitForWindowToClose(MultiWindowTextGUI.java:508)
	at com.googlecode.lanterna.gui2.AbstractWindow.waitUntilClosed(AbstractWindow.java:322)
	at com.googlecode.lanterna.gui2.dialogs.DialogWindow.showDialog(DialogWindow.java:54)
	at com.googlecode.lanterna.gui2.dialogs.MessageDialog.showDialog(MessageDialog.java:78)
	at com.schuettec.morpheus.standalone.client.plugin.MorpheusTerminalClient.showError(MorpheusTerminalClient.java:277)
	at com.schuettec.morpheus.standalone.client.plugin.MorpheusTerminalClient.showError(MorpheusTerminalClient.java:266)
	at com.schuettec.morpheus.standalone.client.plugin.MorpheusTerminalClient.showError(MorpheusTerminalClient.java:262)
	at com.schuettec.morpheus.standalone.client.plugin.MorpheusTerminalClient.showError(MorpheusTerminalClient.java:271)
	at com.schuettec.morpheus.standalone.client.plugin.MorpheusTerminalClient.showErrorAndReturnToLogin(MorpheusTerminalClient.java:246)
	at com.schuettec.morpheus.standalone.client.plugin.MorpheusTerminalClient$1.run(MorpheusTerminalClient.java:138)
	at com.googlecode.lanterna.gui2.Button.lambda$new$0(Button.java:71)
	at com.googlecode.lanterna.gui2.Button.triggerActions(Button.java:95)
	at com.googlecode.lanterna.gui2.Button.handleKeyStroke(Button.java:87)
	at com.googlecode.lanterna.gui2.AbstractInteractableComponent.handleInput(AbstractInteractableComponent.java:145)
	at com.googlecode.lanterna.gui2.AbstractBasePane.doHandleInput(AbstractBasePane.java:167)
	at com.googlecode.lanterna.gui2.AbstractBasePane.handleInput(AbstractBasePane.java:103)
	at com.googlecode.lanterna.gui2.AbstractWindow.handleInput(AbstractWindow.java:135)
	at com.googlecode.lanterna.gui2.MultiWindowTextGUI.handleInput(MultiWindowTextGUI.java:365)
	at com.googlecode.lanterna.gui2.AbstractTextGUI.processInput(AbstractTextGUI.java:94)
	at com.googlecode.lanterna.gui2.AbstractTextGUIThread.processEventsAndUpdate(AbstractTextGUIThread.java:77)
	at com.googlecode.lanterna.gui2.MultiWindowTextGUI.waitForWindowToClose(MultiWindowTextGUI.java:508)
	at com.googlecode.lanterna.gui2.AbstractWindow.waitUntilClosed(AbstractWindow.java:322)
	at com.googlecode.lanterna.gui2.MultiWindowTextGUI.addWindowAndWait(MultiWindowTextGUI.java:484)
	at com.schuettec.morpheus.standalone.client.plugin.MorpheusTerminalClient.run(MorpheusTerminalClient.java:103)
	at java.base/java.lang.Thread.run(Thread.java:832)

I tried to analyse the problem: The string that is processed in method TerminalTextUtils.getStringCharacterIndex(TerminalTextUtils.java:230) has a length of 83. The method TerminalTextUtils.getWordWrappedText(TerminalTextUtils.java:323) in the parent stack frame uses some width of a component, so maxWidth is 86. The loop in TerminalTextUtils.getStringCharacterIndex(TerminalTextUtils.java:230) overruns the string length.

This might be a simple bug I think.

After fiddling around I found out that the error occurs if the terminal window is not big enough to display the message dialog box.
I put a stacktrace in the message dialog and it exceeds the window width.

What can I do?

avl42 commented

Hi, I figured out that the error came from an invalid layout data: BorderLayout settings were passed into a GridLayout.
I think the API should prevent such errors with an exception but this seems only to happen if the actual layout becomes visible.

The above exception is a consequence of this. I will close this one.