Vassal fails to extract HTML help item with content beyond the HTML file to the temp folder

When a HTML help item’s content folder has more than just the one single HTML file in it (i.e. when it has images, CSS, etc), Vassal encounters an error when the user selects that help item and Vassal tries to extract it to the temporary folder from which it is actually opened by the browser.

When the HTML help item’s content folder only has a single HTML file, it works fine.

This is in at least v3.6.6, v3.6.5, and v3.6.4. It looks like others have encountered this before, here:

I did try @uckelman’s suggestion at that thread, but it didn’t change any behavior for me.

I haven’t yet tried the workaround reported by @ddandres at that thread, mainly because, even if it worked for me, it would be kinda bothersome to integrate that workaround into my module’s build scripts. I guess I’d resort to that in extremis, but I’m hoping this might be a small enough bug that it could be fixed in a near-term release.

Here’s the error in the log, with stack trace:

2022-04-24 17:35:25,586 [8208-AWT-EventQueue-0] ERROR VASSAL.build.module.documentation.BrowserHelpFile - File not found in data archive: help/Rules
java.nio.file.NoSuchFileException: C:\Users\William\AppData\Local\Temp\vassal_8683132257841982334\VASSAL\help\Rules\images\Christian_Cannon_1-0.png
	at java.base/sun.nio.fs.WindowsException.translateToIOException(WindowsException.java:85)
	at java.base/sun.nio.fs.WindowsException.rethrowAsIOException(WindowsException.java:103)
	at java.base/sun.nio.fs.WindowsException.rethrowAsIOException(WindowsException.java:108)
	at java.base/sun.nio.fs.WindowsFileSystemProvider.newByteChannel(WindowsFileSystemProvider.java:236)
	at java.base/java.nio.file.spi.FileSystemProvider.newOutputStream(FileSystemProvider.java:484)
	at java.base/java.nio.file.Files.newOutputStream(Files.java:228)
	at VASSAL.build.module.documentation.BrowserHelpFile.internalExtractContents(BrowserHelpFile.java:165)
	at VASSAL.build.module.documentation.BrowserHelpFile.extractContents(BrowserHelpFile.java:123)
	at VASSAL.build.module.documentation.BrowserHelpFile.launch(BrowserHelpFile.java:103)
	at VASSAL.build.module.documentation.BrowserHelpFile$1.actionPerformed(BrowserHelpFile.java:96)
	at java.desktop/javax.swing.AbstractButton.fireActionPerformed(AbstractButton.java:1972)
	at java.desktop/javax.swing.AbstractButton$Handler.actionPerformed(AbstractButton.java:2313)
	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.AbstractButton.doClick(AbstractButton.java:374)
	at java.desktop/javax.swing.plaf.basic.BasicMenuItemUI.doClick(BasicMenuItemUI.java:1028)
	at java.desktop/javax.swing.plaf.basic.BasicMenuItemUI$Handler.mouseReleased(BasicMenuItemUI.java:1072)
	at java.desktop/java.awt.Component.processMouseEvent(Component.java:6626)
	at java.desktop/javax.swing.JComponent.processMouseEvent(JComponent.java:3389)
	at java.desktop/java.awt.Component.processEvent(Component.java:6391)
	at java.desktop/java.awt.Container.processEvent(Container.java:2266)
	at java.desktop/java.awt.Component.dispatchEventImpl(Component.java:5001)
	at java.desktop/java.awt.Container.dispatchEventImpl(Container.java:2324)
	at java.desktop/java.awt.Component.dispatchEvent(Component.java:4833)
	at java.desktop/java.awt.LightweightDispatcher.retargetMouseEvent(Container.java:4948)
	at java.desktop/java.awt.LightweightDispatcher.processMouseEvent(Container.java:4575)
	at java.desktop/java.awt.LightweightDispatcher.dispatchEvent(Container.java:4516)
	at java.desktop/java.awt.Container.dispatchEventImpl(Container.java:2310)
	at java.desktop/java.awt.Window.dispatchEventImpl(Window.java:2780)
	at java.desktop/java.awt.Component.dispatchEvent(Component.java:4833)
	at java.desktop/java.awt.EventQueue.dispatchEventImpl(EventQueue.java:773)
	at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:722)
	at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:716)
	at java.base/java.security.AccessController.doPrivileged(AccessController.java:399)
	at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:86)
	at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:97)
	at java.desktop/java.awt.EventQueue$5.run(EventQueue.java:746)
	at java.desktop/java.awt.EventQueue$5.run(EventQueue.java:744)
	at java.base/java.security.AccessController.doPrivileged(AccessController.java:399)
	at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:86)
	at java.desktop/java.awt.EventQueue.dispatchEvent(EventQueue.java:743)
	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)

Can anyone reproduce this? Or not reproduce this? Either response is welcome.

If I understand what you are doing correctly, I think you can use PDF files for this purpose. I have not used HTML files for this, but PDFs have always worked for me…I’d also suggest that it may actually be the superior option. If you’ve ever tried to do HTML emails, you know how painful it can be to deal with “non-mainstream” browser software.

We’d need to see the module to investigate the problem.

I didn’t see a way to attach directly on this thread, so here’s an issue comment in my module repo with a barebones VMOD that reproduces the bug:

While creating this minimal repro, I discovered that the bug only occurs when there’s a subfolder in the content folder. If the content folder is flat, the bug does not appear. This is great for me in the short-term, as it offers a workaround.

Thanks for the suggestion, especially one from experience. I’ve heard second-hand of the perils of HTML emails, thank goodness my job hasn’t required that of me! :sweat_smile:

I settled on a way to easily (well, relatively easily) generate high-quality HTML using pandoc, i.e. using a markdown input file written with pandoc’s dialect of markdown. When I encountered this bug, I experimented with pandoc’s PDF output format, which was good but not as good as the HTML output. There were a few alignment and page-break oddities as well, which turned me off in the end.

But I found a workaround for the bug, simply flattening my HTML help item’s content file/folder structure. Once there are no subfolders and everything’s top-level, all’s well.

1 Like

I’m glad everything worked out. Thanks for detailing your solutions. I’m sure others will benefit.

Mark “solved”?

1 Like

It looks like the image URL is wrong in test_with_image.html in the case where the image is in a subdirectory. You have

<img src="128px-Altenau_Etteln.jpg" alt="Altenau river">

but the image is in images/.

Yep, sorry I missed that, the src attribute value in that one is incorrect. Unfortunately, correcting it doesn’t change the behavior of Vassal here at all. (If it did, that would be extremely strange. Unless Vassal is directly or indirectly diving into the HTML and examining elements and attributes as part of its extraction logic? Using the stack trace in Vassal’s error log, I glanced at what I think is the relevant code on Vassal’s github, and it doesn’t seem to dive into the HTML like that.)

Also, you can try a bad img src attribute value in the flat content example. Vassal doesn’t fail in that case. The HTML simply renders with the standard broken image link icon where the image would be.

It works for me when I correct the image URL.

Yes, this is indeed what Vassal is doing for images referenced in the <img> tag.

There is no ‘extraction’ of the Help files in the module as such, the Help content is read directly out of the unzipped module file, so any links to other files need to have a full path from the top of the zip file to the location of the target file.

If you create a folder named Help and then create a folder within that named howto, then a file named ‘demo.png’ that exists in help/howto that you want to reference in your HTML, then that will need to be referenced as help/howto/demo.png. There is no ‘current’ directory concept.

Note that this makes your development more complex because the file references that work in Vassal probably won’t work in an extracted copy of your HTML and vice versa.

The change we made to the <img> tag processing means that if you just reference demo.png as <img src="demo.png">, then if Vassal can’t find the image, it will go and look in the images folder for it.

This allows you to reference existing images that your module uses just by using <img src="demo.png"> instead of <img src="images/demo.png">

Flattening everything to the top level works because it takes the directory path issues out of the picture.

I have not tried referencing CSS etc. but providing full path names from the top of the vmod structure should work. Just remember that the HTML renderer built into Java that Vassal uses is truly ancient, you are looking at about HTML 2 level support.

Brent.

2 Likes

This mystified me a bit, so I rebuilt the whole test.vmod file from scratch, this time with the correct src attribute values all around, and with this fresh vmod I can still reproduce the bug in the UI and the error message in the Vassal log file.

When I ended up reproducing it again this way, I was a bit more mystified. What could be the difference between what we each did? So, then I remembered the unzip-rezip workaround mentioned by the other poster in the comment linked at the top of this thread. I figured maybe this is what caused it to work for you, but before I made any claims here, I had to sanity check it for myself on my end. I followed his steps using the vmod I had just recreated from scratch, unzipping first the vmod, then the help item, then rezipping the help item (with no modifications), and finally rezipping the vmod. And there it was, the buggy behavior was gone, and the help item in question actually successfully opened. No error in the log file. Interestingly (or maybe not, I am no expert in the zip archive format), the rezipped help item was slightly larger than the original.

Here’s another github comment with two attached vmod files, one from before the rezip and one from after:

Hope this helps.

The files inside the help folder are zip files. This really should not work at all, we don’t support this.

@Brent_Easton You’re confusing the HTML support in Swing elements with the support for help files displayed by a browser (via the BrowserSupport class). Displaying HTML in Swing is indeed very limited (HTML3 and no CSS) while for the help files, you can use anything a modern browser can display (HTML5 + CSS3) because it’s a browser displaying those, not Swing.

We do. That’s what BrowserSupport does for bundling up all the files for each Help entry. I no longer remember why we did that—it might even predate us—but it’s definitely there.

1 Like

Holy shit Batman!

After 20 years I still get surprised.

Ah, sorry, that’s BrowserHelpFile which does the actual unpacking. It’s a thing Rodney added in 2007, according to the log. I had forgotten that it made these internal ZIPs myself until I looked at the code.

1 Like