diff --git a/skel_common/readme_changelog.txt b/skel_common/readme_changelog.txt index a6da97b..f9aa89a 100644 --- a/skel_common/readme_changelog.txt +++ b/skel_common/readme_changelog.txt @@ -14,6 +14,7 @@ Changelog - Added a Validate warning for junk files named '.dropbox' - Added a check during patching to skip junk files - Added an error popup when the jar is double-clicked +- Added *.xml.rawappend suffix to preserve whitespace in 'misc.xml' - Minor optimizations to reduce memory usage 1.4: diff --git a/skel_common/readme_modders.txt b/skel_common/readme_modders.txt index 694ad08..835430e 100644 --- a/skel_common/readme_modders.txt +++ b/skel_common/readme_modders.txt @@ -197,6 +197,22 @@ Advanced XML edit in the wake of earlier ones. +Raw Appending + + FTL is quirky. Occasionally you may need to include non-standard XML in a + mod without elaborate parsing. For instance, "misc.xml" defines phrases + for localization, which may begin/end with a space. Normally, this + whitespace would be trimmed away, leading to ugly results in-game. + + If your mod has a file named "misc.xml.rawappend", the content of that + file will be tacked onto the end of "misc.xml". Line-endings and encoding + will be standardized, but Slipstream will make no attempt to + (mis)understand the tags of either file. + + You can still override existing tags by adding your own with the same + name attribute. + + Commandline Running Slipstream from a prompt can speed up development... diff --git a/src/main/java/net/vhati/modmanager/core/ModPatchThread.java b/src/main/java/net/vhati/modmanager/core/ModPatchThread.java index 7e2f0ea..7039eaa 100644 --- a/src/main/java/net/vhati/modmanager/core/ModPatchThread.java +++ b/src/main/java/net/vhati/modmanager/core/ModPatchThread.java @@ -249,8 +249,36 @@ public class ModPatchThread extends Thread { catch ( IOException e ) {} } - if ( !moddedItems.contains(innerPath) ) + if ( !moddedItems.contains(innerPath) ) { moddedItems.add( innerPath ); + } + } + } + else if ( fileName.endsWith( ".xml.rawappend" ) || fileName.endsWith( ".rawappend.xml" ) ) { + innerPath = parentPath + fileName.replaceAll( "[.](?:xml[.]rawappend|rawappend[.]xml)$", ".xml" ); + innerPath = checkCase( innerPath, knownPaths, knownPathsLower ); + + if ( !ftlP.contains( innerPath ) ) { + log.warn( String.format( "Non-existent innerPath wasn't raw appended: %s", innerPath ) ); + } + else { + log.warn( String.format( "Appending xml as raw text: %s", innerPath ) ); + InputStream mainStream = null; + try { + mainStream = ftlP.getInputStream(innerPath); + InputStream mergedStream = ModUtilities.appendXMLFile( mainStream, zis, "windows-1252", ftlP.getName()+":"+innerPath, modFile.getName()+":"+parentPath+fileName ); + mainStream.close(); + ftlP.remove( innerPath ); + ftlP.add( innerPath, mergedStream ); + } + finally { + try {if ( mainStream != null ) mainStream.close();} + catch ( IOException e ) {} + } + + if ( !moddedItems.contains(innerPath) ) { + moddedItems.add( innerPath ); + } } } else if ( fileName.endsWith( ".xml" ) ) { @@ -258,10 +286,11 @@ public class ModPatchThread extends Thread { InputStream fixedStream = ModUtilities.rebuildXMLFile( zis, "windows-1252", modFile.getName()+":"+parentPath+fileName ); - if ( !moddedItems.contains(innerPath) ) + if ( !moddedItems.contains(innerPath) ) { moddedItems.add( innerPath ); - else + } else { log.warn( String.format( "Clobbering earlier mods: %s", innerPath ) ); + } if ( ftlP.contains( innerPath ) ) ftlP.remove( innerPath ); @@ -277,10 +306,11 @@ public class ModPatchThread extends Thread { InputStream fixedStream = ModUtilities.encodeText( fixedText, "windows-1252", modFile.getName()+":"+parentPath+fileName+" (with new EOL)" ); - if ( !moddedItems.contains(innerPath) ) + if ( !moddedItems.contains(innerPath) ) { moddedItems.add( innerPath ); - else + } else { log.warn( String.format( "Clobbering earlier mods: %s", innerPath ) ); + } if ( ftlP.contains( innerPath ) ) ftlP.remove( innerPath ); @@ -289,10 +319,11 @@ public class ModPatchThread extends Thread { else { innerPath = checkCase( innerPath, knownPaths, knownPathsLower ); - if ( !moddedItems.contains(innerPath) ) + if ( !moddedItems.contains(innerPath) ) { moddedItems.add( innerPath ); - else + } else { log.warn( String.format( "Clobbering earlier mods: %s", innerPath ) ); + } if ( ftlP.contains( innerPath ) ) ftlP.remove( innerPath ); diff --git a/src/main/java/net/vhati/modmanager/core/ModUtilities.java b/src/main/java/net/vhati/modmanager/core/ModUtilities.java index e6b107a..73ded52 100644 --- a/src/main/java/net/vhati/modmanager/core/ModUtilities.java +++ b/src/main/java/net/vhati/modmanager/core/ModUtilities.java @@ -159,29 +159,36 @@ public class ModUtilities { /** - * Semi-intelligently appends XML from one file (src) onto another (dst). - * Note: This is how patching used to work prior to SMM 1.2. + * Semi-intelligently appends mainStream, with content from appendStream. + * Note: This is similar to how patching used to work prior to SMM 1.2. * - * The two InputStreams are read, and the combined result - * is returned as a new third InputStream. + * XML parsing/tidying does NOT take place. The new content is basically + * tacked on as-is. Any xml declaration tags will be scrubbed from both + * streams, and a new one will be prepended. * - * The returned stream is a ByteArrayInputStream - * which doesn't need closing. + * The two InputStreams are read, and the combined result is returned as a + * new third InputStream. + * + * The returned stream is a ByteArrayInputStream which doesn't need + * closing. * * The result will have CR-LF line endings and the desired encoding. - * Note: FTL stubbornly assumes all XML is in windows-1252 encoding, - * even on Linux. + * Note: FTL stubbornly assumes all XML is in windows-1252 encoding, even + * on Linux. * * The description arguments identify the streams for log messages. + * + * Note: SMM 1.5 changed the order of arguments (previous releases took + * the source of new content to append as the first argument). */ - public static InputStream appendXMLFile( InputStream srcStream, InputStream dstStream, String encoding, String srcDescription, String dstDescription ) throws IOException { + public static InputStream appendXMLFile( InputStream mainStream, InputStream appendStream, String encoding, String mainDescription, String appendDescription ) throws IOException { Pattern xmlDeclPtn = Pattern.compile( "<[?]xml [^>]*?[?]>\n*" ); - String srcText = decodeText( srcStream, srcDescription ).text; - srcText = xmlDeclPtn.matcher(srcText).replaceFirst( "" ); + String mainText = decodeText( mainStream, mainDescription ).text; + mainText = xmlDeclPtn.matcher(mainText).replaceFirst( "" ); - String dstText = decodeText( dstStream, dstDescription ).text; - dstText = xmlDeclPtn.matcher(dstText).replaceFirst( "" ); + String appendText = decodeText( appendStream, appendDescription ).text; + appendText = xmlDeclPtn.matcher(appendText).replaceFirst( "" ); // Concatenate, filtering the stream to standardize newlines and encode. // @@ -190,9 +197,9 @@ public class ModUtilities { Writer writer = new EOLWriter( new OutputStreamWriter( tmpData, encoder ), "\r\n" ); writer.append( "\n" ); - writer.append( dstText ); + writer.append( mainText ); writer.append( "\n\n\n\n" ); - writer.append( srcText ); + writer.append( appendText ); writer.append( "\n" ); writer.flush(); InputStream result = new ByteArrayInputStream( tmpData.toByteArray() );