triplea-game / triplea

TripleA is a turn based strategy game and board game engine, similar to Axis & Allies or Risk.
https://triplea-game.org/
GNU General Public License v3.0
1.34k stars 398 forks source link

2.6.89: FileUtils#readContents:184 - java.nio.charset.MalformedInputException #9028

Closed tripleabuilderbot closed 3 years ago

tripleabuilderbot commented 3 years ago

User Description

The notes for this game works fine in 2.5 yet cannot display if their code is pasted inside a blank "270BC_Wars.notes.html"

Here are some lines of the start and end of them:

            <html>
            <body>
            <table width=&quot;0px&quot;border=&quot;0&quot;bgcolor=&quot;776644&quot;style=&quot;text-align:center;font-size:20px&quot;>
            <tr>
            <th><img title=&quot;270BC Wars&quot; src=&quot;Title.png&quot;/>
            </th>
            </tr>
            <tr>
            <td>
            <div style=&quot;text-align:center&quot;>
            <p>
            </p><p><b>Version 1.0.0.0.0.0+</b>
            </p><p>
            </p><p><b>Game by Cernel</b>
            </p><p>for TripleA 2.6
            </p><p>
            </p><p>Modified from &quot;270BC&quot; version 1.7
            </p><p>
            <div style=&quot;font-size:16px;font-style:italic&quot;>Mistress of Italy, Rome, looking over the sea, discovers herself engaged in the inexorable struggle for survival against the might of Carthage, encroaching on Africa and Spain, and the islands nearby, as far as the columns of Hercules, the end of the World.
            </p><p>In Greece, the royal hegemony of Macedonia is bitterly challenged by a warring coalition of free cities and leagues, from Sicily, in the west, to Asia, in the east.
            </p><p>Across what remains of what was taken by Alexander, what had begun as a spate of civil conflicts conflated into a dynastic strife between the new realms of Egypt and Syria.
            </p><p>Beyond the Hellenistic world, the ascendancy of Parthia looms on the horizon, eager to champion the resurgence of Persian supremacy to her former greatness.
            </p><p>Meanwhile, hailing from unknown lands, the tribes of Numidia are swarming out of the wilds of Libya, their savage want for slaves and violent desire for booty, unquenchable.
            </p><p>'Tis a clash of civilizations: for either side, the other side is to be eliminated.
            </div>
            </p><p>
            </p><p>
            </div>

...

            <div style=&quot;text-align:center;text-indent:0px;color:#990000;background-color:000000&quot;>CREDITS
            </p><p>
            </div>
            <div style=&quot;text-align:center;text-indent:0px&quot;>
            </p><p>
            </p><p>Original 270BC map and game by: Doctor Che.
            </p><p>Original 270BC game modified by: Veqryn, Cernel, redrum.
            </p><p>Original 270BC map details and decorations, &quot;TripleA Ancient&quot; image, units images, territory names images, territory values images, dice images by: Hepps.
            </p><p>
            </p><p>
            </p><p><img src=&quot;TripleA_ancient.png&quot; height=&quot;400&quot; width=&quot;400&quot;/> </p><p>
            </p>
            </div>
            </div>
            </td>
            </tr>
            </table>
            </body>
            </html>

Log Message

Error reading file: C:\Users\001\triplea\downloadedMaps\270bc_wars\map\games\270BC_Wars.notes.html, Input length = 1

TripleA Version

2.6.89

Java Version

11.0.9.1

Operating System

Windows 10

Stack Trace

Exception: java.nio.charset.MalformedInputExceptionInput length = 1
java.lang.Exception
    at java.base/java.lang.StringCoding.throwMalformed(StringCoding.java:685)
    at java.base/java.lang.StringCoding.decodeUTF8_0(StringCoding.java:872)
    at java.base/java.lang.StringCoding.newStringNoRepl1(StringCoding.java:1005)
    at java.base/java.lang.StringCoding.newStringNoRepl(StringCoding.java:990)
    at java.base/java.lang.System$2.newStringNoRepl(System.java:2197)
    at java.base/java.nio.file.Files.readString(Files.java:3286)
    at java.base/java.nio.file.Files.readString(Files.java:3242)
    at org.triplea.io.FileUtils.readContents(FileUtils.java:184)
    at org.triplea.map.game.notes.GameNotes.loadGameNotes(GameNotes.java:31)
    at games.strategy.engine.framework.map.file.system.loader.DownloadedMap.readGameNotes(DownloadedMap.java:74)
    at games.strategy.engine.framework.ui.DefaultGameChooserEntry.readGameNotes(DefaultGameChooserEntry.java:42)
    at java.base/java.util.Optional.map(Optional.java:265)
    at games.strategy.engine.framework.ui.GameChooser.lambda$chooseGame$4(GameChooser.java:156)
    at java.desktop/javax.swing.JList.fireSelectionValueChanged(JList.java:1804)
    at java.desktop/javax.swing.JList$ListSelectionHandler.valueChanged(JList.java:1818)
    at java.desktop/javax.swing.DefaultListSelectionModel.fireValueChanged(DefaultListSelectionModel.java:219)
    at java.desktop/javax.swing.DefaultListSelectionModel.fireValueChanged(DefaultListSelectionModel.java:186)
    at java.desktop/javax.swing.DefaultListSelectionModel.setValueIsAdjusting(DefaultListSelectionModel.java:723)
    at java.desktop/javax.swing.JList.setValueIsAdjusting(JList.java:2152)
    at java.desktop/javax.swing.plaf.basic.BasicListUI$Handler.mouseReleased(BasicListUI.java:2958)
    at java.desktop/java.awt.AWTEventMulticaster.mouseReleased(AWTEventMulticaster.java:298)
    at java.desktop/java.awt.AWTEventMulticaster.mouseReleased(AWTEventMulticaster.java:297)
    at java.desktop/java.awt.AWTEventMulticaster.mouseReleased(AWTEventMulticaster.java:297)
    at java.desktop/java.awt.Component.processMouseEvent(Component.java:6635)
    at java.desktop/javax.swing.JComponent.processMouseEvent(JComponent.java:3342)
    at java.desktop/java.awt.Component.processEvent(Component.java:6400)
    at java.desktop/java.awt.Container.processEvent(Container.java:2263)
    at java.desktop/java.awt.Component.dispatchEventImpl(Component.java:5011)
    at java.desktop/java.awt.Container.dispatchEventImpl(Container.java:2321)
    at java.desktop/java.awt.Component.dispatchEvent(Component.java:4843)
    at java.desktop/java.awt.LightweightDispatcher.retargetMouseEvent(Container.java:4918)
    at java.desktop/java.awt.LightweightDispatcher.processMouseEvent(Container.java:4547)
    at java.desktop/java.awt.LightweightDispatcher.dispatchEvent(Container.java:4488)
    at java.desktop/java.awt.Container.dispatchEventImpl(Container.java:2307)
    at java.desktop/java.awt.Window.dispatchEventImpl(Window.java:2772)
    at java.desktop/java.awt.Component.dispatchEvent(Component.java:4843)
    at java.desktop/java.awt.EventQueue.dispatchEventImpl(EventQueue.java:772)
    at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:721)
    at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:715)
    at java.base/java.security.AccessController.doPrivileged(Native Method)
    at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:85)
    at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:95)
    at java.desktop/java.awt.EventQueue$5.run(EventQueue.java:745)
    at java.desktop/java.awt.EventQueue$5.run(EventQueue.java:743)
    at java.base/java.security.AccessController.doPrivileged(Native Method)
    at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:85)
    at java.desktop/java.awt.EventQueue.dispatchEvent(EventQueue.java:742)
    at java.desktop/java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:203)
    at java.desktop/java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:124)
    at java.desktop/java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:117)
    at java.desktop/java.awt.WaitDispatchSupport$2.run(WaitDispatchSupport.java:190)
    at java.desktop/java.awt.WaitDispatchSupport$4.run(WaitDispatchSupport.java:235)
    at java.desktop/java.awt.WaitDispatchSupport$4.run(WaitDispatchSupport.java:233)
    at java.base/java.security.AccessController.doPrivileged(Native Method)
    at java.desktop/java.awt.WaitDispatchSupport.enter(WaitDispatchSupport.java:233)
    at java.desktop/java.awt.Dialog.show(Dialog.java:1070)
    at java.desktop/java.awt.Component.show(Component.java:1716)
    at java.desktop/java.awt.Component.setVisible(Component.java:1663)
    at java.desktop/java.awt.Window.setVisible(Window.java:1031)
    at java.desktop/java.awt.Dialog.setVisible(Dialog.java:1005)
    at games.strategy.engine.framework.ui.GameChooser.chooseGame(GameChooser.java:178)
    at games.strategy.engine.framework.startup.ui.panels.main.game.selector.GameSelectorPanel.selectGameFile(GameSelectorPanel.java:384)
    at games.strategy.engine.framework.startup.ui.panels.main.game.selector.GameSelectorPanel.lambda$new$0(GameSelectorPanel.java:165)
    at java.desktop/javax.swing.AbstractButton.fireActionPerformed(AbstractButton.java:1967)
    at java.desktop/javax.swing.AbstractButton$Handler.actionPerformed(AbstractButton.java:2308)
    at java.desktop/javax.swing.DefaultButtonModel.fireActionPerformed(DefaultButtonModel.java:405)
    at java.desktop/javax.swing.DefaultButtonModel.setPressed(DefaultButtonModel.java:262)
    at java.desktop/javax.swing.plaf.basic.BasicButtonListener.mouseReleased(BasicButtonListener.java:279)
    at org.pushingpixels.substance.internal.utils.RolloverButtonListener.mouseReleased(RolloverButtonListener.java:108)
    at java.desktop/java.awt.AWTEventMulticaster.mouseReleased(AWTEventMulticaster.java:297)
    at java.desktop/java.awt.Component.processMouseEvent(Component.java:6635)
    at java.desktop/javax.swing.JComponent.processMouseEvent(JComponent.java:3342)
    at java.desktop/java.awt.Component.processEvent(Component.java:6400)
    at java.desktop/java.awt.Container.processEvent(Container.java:2263)
    at java.desktop/java.awt.Component.dispatchEventImpl(Component.java:5011)
    at java.desktop/java.awt.Container.dispatchEventImpl(Container.java:2321)
    at java.desktop/java.awt.Component.dispatchEvent(Component.java:4843)
    at java.desktop/java.awt.LightweightDispatcher.retargetMouseEvent(Container.java:4918)
    at java.desktop/java.awt.LightweightDispatcher.processMouseEvent(Container.java:4547)
    at java.desktop/java.awt.LightweightDispatcher.dispatchEvent(Container.java:4488)
    at java.desktop/java.awt.Container.dispatchEventImpl(Container.java:2307)
    at java.desktop/java.awt.Window.dispatchEventImpl(Window.java:2772)
    at java.desktop/java.awt.Component.dispatchEvent(Component.java:4843)
    at java.desktop/java.awt.EventQueue.dispatchEventImpl(EventQueue.java:772)
    at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:721)
    at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:715)
    at java.base/java.security.AccessController.doPrivileged(Native Method)
    at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:85)
    at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:95)
    at java.desktop/java.awt.EventQueue$5.run(EventQueue.java:745)
    at java.desktop/java.awt.EventQueue$5.run(EventQueue.java:743)
    at java.base/java.security.AccessController.doPrivileged(Native Method)
    at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:85)
    at java.desktop/java.awt.EventQueue.dispatchEvent(EventQueue.java:742)
    at java.desktop/java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:203)
    at java.desktop/java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:124)
    at java.desktop/java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:113)
    at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:109)
    at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:101)
    at java.desktop/java.awt.EventDispatchThread.run(EventDispatchThread.java:90)
Cernelius commented 3 years ago

The problem persists after I change all &quot; to ".

Cernelius commented 3 years ago

As far as myself goes, I got around this issue by first downloading a map and then swapping the map's game file with the one I want, before the program would create the notes file from the game file, so to have the program creating the notes file out of that.

So I'm fine, even though I still cannot understand what was wrong (when I just manually created the notes file myself instead of letting the program do it).

By the way, I had to add back the line breaks (talking about the useless line breaks in the file, which are ignored by the program upon visualizing the notes, not any code creating line breaks) because the program didn't port them to the newly created notes file.

DanVanAtta commented 3 years ago

@Cernelius could you attach the file that was generating this problem?

Cernelius commented 3 years ago

@Cernelius could you attach the file that was generating this problem?

I don't have it any longer, but this problem is the same if I try manually to create the notes file starting from the 270BC Wars game currently in the repository.

270BC_Wars.notes.html.txt

(It's a "txt" file because the correct extension could not be uploaded herein, so you need to change it to the correct format.)

DanVanAtta commented 3 years ago

I was able to repro. It looks like the file encoding is ISO-8859. How exactly did you create that game notes file @Cernelius, which application did you use? Did you specify an encoding when saving it?

Cernelius commented 3 years ago

As I said:

their code is pasted inside a blank "270BC_Wars.notes.html"

Meaning that I simply take the "270BC_Wars.notes.html" generated by the program, delete everything which is in it and paste what I want (which doesn't work).

DanVanAtta commented 3 years ago

Which application are you using to open the file and to paste new contents? Which application are you doing the 'copy' from?

Cernelius commented 3 years ago

I think I used http://www.jedit.org/, but I may have used Windows Notepad instead.

Cernelius commented 3 years ago

My jEdit is at version 5.5. I see the latest stable version of it is apparently 5.6.0 instead.

DanVanAtta commented 3 years ago

There are ISO-8859-1 characters in that file, when rendered in Java Swing it looks like the characters will simply not be there. If converting to UTF-8, the characters will potentially be converted to unknown character symbols. Ideally files are saved in UTF-8, it should be an option in the text editor how the file is saved.

With that said, we can add fallback encoding options to read the additional encoding types.

Example, the NBSP below: Screenshot from 2021-03-14 18-57-22

Cernelius commented 3 years ago

There are ISO-8859-1 characters in that file, when rendered in Java Swing it looks like the characters will simply not be there. If converting to UTF-8, the characters will potentially be converted to unknown character symbols. Ideally files are saved in UTF-8, it should be an option in the text editor how the file is saved.

With that said, we can add fallback encoding options to read the additional encoding types.

Example, the NBSP below: Screenshot from 2021-03-14 18-57-22

I don't understand what those characters are and how you can find that "NBSP" in there. As I said, I just took the game notes of the "270BC Wars" game currently in the repository and copy-pasted them, adding nothing else. As you can see in this screenshot, there is nothing but a space where you are pointing at: https://raw.githubusercontent.com/triplea-maps/270bc_wars/master/map/games/270BC_Wars.xml 20210315_01

And all works fine for the "xml" file. Only the "html" files has such problems. So it cannot be because of characters created by the program which java swing cannot see, because I create "xml" files with the same editor to be read by the program, unless the editor creates them for "html" files but not for "xml" files.

Cernelius commented 3 years ago

And, as I said

I'm fine, even though I still cannot understand what was wrong

because, so far at least, if I just let the program create the "html" files, and then I edit them pasting nothing from other files, I'm not having any problems. The problems are only if I copy-paste from the "xml" file to the "html" file (which is something I don't need to do after the game notes I want are already in the "html" file).

So, unless I'm missing something, nothing of this should be a problem any longer once past this phase of moving the game notes out of the "xml".

Are there any plans massively to remove all game notes from the "xml" after releasing 2.6 or will useless and increasingly outdated copies of the game notes now in the "html" files be kept within the "xml" game files too?

DanVanAtta commented 3 years ago

The copy/paste into the file, or when you saved it, or a combination of the two, converted the files encoding from ASCII text to ISO-8859. Look for an encoding option when saving the file if there is one.

Notice the below shows the encoding:

dan@dan-xps:~/triplea/downloadedMaps/270bc_wars/map/games$ file *
270BC_Wars.notes.html: HTML document, ISO-8859 text, with very long lines, with CRLF line terminators
270BC_Wars.xml:        XML 1.0 document, ASCII text, with very long lines

For reference and comparison:

dan@dan-xps:~/triplea/downloadedMaps/world_at_war/map/games$ file *
WAW40.notes.html:        HTML document, ASCII text, with very long lines
WAW40.xml:               XML 1.0 document, ASCII text, with very long lines
World_At_War.notes.html: HTML document, ASCII text, with very long lines
World_At_War.xml:        XML 1.0 document, ASCII text, with very long lines

Are there any plans massively to remove all game notes from the "xml" after releasing 2.6 or will useless and increasingly outdated copies of the game notes now in the "html" files be kept within the "xml" game files too?

No plans to do a bulk removal, but once 2.6 is launched the expectation is for those XML elements to no longer be maintained and perhaps eventually pruned.

Cernelius commented 3 years ago

You know that pruning those has no hard compatibility issues right? The "notes" property is optional, so removing it just leaves a game with no notes.

I'm not a fan of this thing of possibly huge game notes remaining indefinitely in two places (Obviously, I've already removed them from whithin the "xml" file for my `270_bc_wars" map I intend to update on the first of April.). Moreover, it can be confusing with users in 2.5 and lower looking at one game notes and users in 2.6 and higher looking at an other ones (Rather better the ones in 2.5 and lower see no notes at all.). I'm under the impression many users stay without updating TripleA for over a year if not forced by compatibility breakages or major problems.

By the way, the problem I've pointed out of all line breaks being eliminated is not much of a problem for me (I've recreated the line breaks rapidly), but I can see it being generally a substantial issue in the moment you open the notes file to read it and everything is on a single line (Say, for example, you need to fix something in the notes of Civil War and all the notes are a single line.).

Cernelius commented 3 years ago

Previously you said "UTF-8" and now you say "ASCII". Are they the same thing?

Anyways, I've no idea on how to get those information or how to configure jEdit to save in "ASCII".

Cernelius commented 3 years ago

This is what jEdit has to say:

Character Encodings
A character encoding is a mapping from a set of characters to their on-disk representation. jEdit can use any encoding supported by the Java platform.
Buffers in memory are always stored in UTF-16 encoding, which means each character is mapped to an integer between 0 and 65535. UTF-16 is the native encoding supported by Java, and has a large enough range of characters to support most modern languages.
When a buffer is loaded, it is converted from its on-disk representation to UTF-16 using a specified encoding.
The default encoding, used to load files for which no other encoding is specified, can be set in the Encodings pane of the Utilities> Options dialog box; see the section called “The Encodings Pane”. Unless you change this setting, it will be your operating system's native encoding, for example MacRoman on the MacOS, windows-1252 on Windows, and ISO-8859-1 on Unix.
An encoding can be explicitly set when opening a file in the file system browser's Commands>Encoding menu.
Note that there is no general way to auto-detect the encoding used by a file, however jEdit supports "encoding detectors", of which there are some provided in the core, and others may be provided by plugins through the services api. From the encodings option pane the section called “The Encodings Pane”, you can customize which ones are used, and the order they are tried. Here are some of the encoding detectors recognized by jEdit:
BOM: UTF-16 and UTF-8Y files are auto-detected, because they begin with a certain fixed character sequence. Note that plain UTF-8 does not mandate a specific header, and thus cannot be auto-detected, unless the file in question is an XML file.
XML-PI: Encodings used in XML files with an XML PI like the following are auto-detected:
<?xml version="1.0" encoding="UTF-8">
html: Encodings specified in HTML files with a content= attribute in a meta element may be auto-detected:
<html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"> 
python: Python has its own way of specifying encoding at the top of a file.
# -*- coding: utf-8 -*-                
buffer-local-property: Enable buffer-local properties' syntax (see the section called “Buffer-Local Properties”) at the top of the file to specify encoding.
#  :encoding=ISO-8859-1:

The encoding that will be used to save the current buffer is shown in the status bar, and can be changed in the Utilities>Buffer Options dialog box. Note that changing this setting has no effect on the buffer's contents; if you opened a file with the wrong encoding and got garbage, you will need to reload it. File>Reload with Encoding is an easy way.
If a file is opened without an explicit encoding specified and it appears in the recent file list, jEdit will use the encoding last used when working with that file; otherwise the default encoding will be used.

Commonly Used Encodings
While the world is slowly converging on UTF-8 and UTF-16 encodings for storing text, a wide range of older encodings are still in widespread use and Java supports most of them.
The simplest character encoding still in use is ASCII, or “American Standard Code for Information Interchange”. ASCII encodes Latin letters used in English, in addition to numbers and a range of punctuation characters. Each ASCII character consists of 7 bits, there is a limit of 128 distinct characters, which makes it unsuitable for anything other than English text. jEdit will load and save files as ASCII if the US-ASCII encoding is used.
Because ASCII is unsuitable for international use, most operating systems use an 8-bit extension of ASCII, with the first 128 values mapped to the ASCII characters, and the rest used to encode accents, umlauts, and various more esoteric used typographical marks. The three major operating systems all extend ASCII in a different way. Files written by Macintosh programs can be read using the MacRoman encoding; Windows text files are usually stored as windows-1252. In the Unix world, the 8859_1 character encoding has found widespread usage.
On Windows, various other encodings, referred to as code pages and identified by number, are used to store non-English text. The corresponding Java encoding name is windows- followed by the code page number, for example windows-850.
Many common cross-platform international character sets are also supported; KOI8_R for Russian text, Big5 and GBK for Chinese, and SJIS for Japanese.

Notice that it says

The default encoding, used to load files for which no other encoding is specified, can be set in the Encodings pane of the Utilities> Options dialog box; see the section called “The Encodings Pane”. Unless you change this setting, it will be your operating system's native encoding, for example MacRoman on the MacOS, windows-1252 on Windows, and ISO-8859-1 on Unix.

I'm on Windows and you say that the file I saved has been turned into ISO-8859, which is what should happen in Unix not in Windows. My guess is that the editor sees there are Unix characters, so it goes for ISO-8859 even though I'm on Windows.

Definitely nothing problematic is happening by just opening the file with jEdit and saving it since I did this many times. This problem does not happen if I let the "html" file be created, and then I open and modify it with jEdit by writing myself. It happens only if I let the "html" file be created and copy something from the "xml" file and then open the "html" file and paste into it.

Cernelius commented 3 years ago

Maybe it would be better not using any fallback and, instead, forcing all TripleA files to have the same encoding, documenting it for map-makers and having an error giving good information on how to make the file work?

For example, what should be better set in this for working with TripleA files? 20210315_02

Any suggestions?

Cernelius commented 3 years ago

By the way, I think a gaming program should not go ahead like this creating any map files, thus substantially changing the maps. Anything like this belongs to map-updating utilities for map-makers, not for any users.

As far as the program goes, I believe it should either simply display no game notes for old maps or (if backward support is preferred) keep supporting the old game notes within the "xml" file as a fall back if no notes file is found.

Moreover, I wonder if such a thing (not displaying the game notes anymore for old maps unless updated) should be considered compatibility breaking and the current TripleA should rather be versioned 3.0.