Added tolerance of optional FTL 1.6.1 root tags when patching
This commit is contained in:
parent
8f8d2072a9
commit
a5383766ef
3 changed files with 101 additions and 40 deletions
|
@ -39,6 +39,12 @@ The Append Extension
|
||||||
When you're not overriding something, try to use unique names, so that
|
When you're not overriding something, try to use unique names, so that
|
||||||
it won't clobber another mod and vice versa.
|
it won't clobber another mod and vice versa.
|
||||||
|
|
||||||
|
FTL 1.6.1 introduced <FTL>...</FTL> root tags wrapping XML files. If present,
|
||||||
|
Slipstream will remove them, append, and put them back afterward. Special
|
||||||
|
tags (see "Advanced XML" below) will be unaware of them. Mod files are not
|
||||||
|
required to include these root tags, though they can. Slipstream will remove
|
||||||
|
those as well.
|
||||||
|
|
||||||
|
|
||||||
General
|
General
|
||||||
|
|
||||||
|
|
|
@ -35,7 +35,9 @@ import net.vhati.modmanager.core.SloppyXMLParser;
|
||||||
|
|
||||||
import ar.com.hjg.pngj.PngReader;
|
import ar.com.hjg.pngj.PngReader;
|
||||||
|
|
||||||
|
import org.jdom2.Content;
|
||||||
import org.jdom2.Document;
|
import org.jdom2.Document;
|
||||||
|
import org.jdom2.Element;
|
||||||
import org.jdom2.JDOMException;
|
import org.jdom2.JDOMException;
|
||||||
import org.jdom2.input.JDOMParseException;
|
import org.jdom2.input.JDOMParseException;
|
||||||
import org.jdom2.input.SAXBuilder;
|
import org.jdom2.input.SAXBuilder;
|
||||||
|
@ -85,7 +87,7 @@ public class ModUtilities {
|
||||||
byte[] buf = new byte[4096];
|
byte[] buf = new byte[4096];
|
||||||
int len;
|
int len;
|
||||||
ByteArrayOutputStream tmpData = new ByteArrayOutputStream();
|
ByteArrayOutputStream tmpData = new ByteArrayOutputStream();
|
||||||
while ( (len = is.read(buf)) >= 0 ) {
|
while ( (len = is.read( buf )) >= 0 ) {
|
||||||
tmpData.write( buf, 0, len );
|
tmpData.write( buf, 0, len );
|
||||||
}
|
}
|
||||||
byte[] allBytes = tmpData.toByteArray();
|
byte[] allBytes = tmpData.toByteArray();
|
||||||
|
@ -166,6 +168,10 @@ public class ModUtilities {
|
||||||
* tacked on as-is. Any xml declaration tags will be scrubbed from both
|
* tacked on as-is. Any xml declaration tags will be scrubbed from both
|
||||||
* streams, and a new one will be prepended.
|
* streams, and a new one will be prepended.
|
||||||
*
|
*
|
||||||
|
* If the mainStream had <FTL> tags (introduced in FTL 1.6.1), they
|
||||||
|
* will be scrubbed, and new ones will be added after appending. If
|
||||||
|
* appendStream has those tags, they will be scrubbed.
|
||||||
|
*
|
||||||
* The two InputStreams are read, and the combined result is returned as a
|
* The two InputStreams are read, and the combined result is returned as a
|
||||||
* new third InputStream.
|
* new third InputStream.
|
||||||
*
|
*
|
||||||
|
@ -182,13 +188,27 @@ public class ModUtilities {
|
||||||
* the source of new content to append as the first argument).
|
* the source of new content to append as the first argument).
|
||||||
*/
|
*/
|
||||||
public static InputStream appendXMLFile( InputStream mainStream, InputStream appendStream, String encoding, String mainDescription, String appendDescription ) throws IOException {
|
public static InputStream appendXMLFile( InputStream mainStream, InputStream appendStream, String encoding, String mainDescription, String appendDescription ) throws IOException {
|
||||||
Pattern xmlDeclPtn = Pattern.compile( "<[?]xml [^>]*?[?]>\n*" );
|
// XML declaration, or root FTL tags.
|
||||||
|
Pattern comboPtn = Pattern.compile( "(<[?]xml [^>]*?[?]>\n*)|(</?FTL>)" );
|
||||||
|
Matcher m = null;
|
||||||
|
boolean mainHadRootTags = false;
|
||||||
|
|
||||||
String mainText = decodeText( mainStream, mainDescription ).text;
|
String mainText = decodeText( mainStream, mainDescription ).text;
|
||||||
mainText = xmlDeclPtn.matcher( mainText ).replaceFirst( "" );
|
StringBuffer mainBuf = new StringBuffer( mainText.length() );
|
||||||
|
m = comboPtn.matcher( mainText );
|
||||||
|
while ( m.find() ) {
|
||||||
|
if ( m.group( 2 ) != null ) mainHadRootTags = true;
|
||||||
|
m.appendReplacement( mainBuf, "" );
|
||||||
|
}
|
||||||
|
m.appendTail( mainBuf );
|
||||||
|
|
||||||
String appendText = decodeText( appendStream, appendDescription ).text;
|
String appendText = decodeText( appendStream, appendDescription ).text;
|
||||||
appendText = xmlDeclPtn.matcher( appendText ).replaceFirst( "" );
|
StringBuffer appendBuf = new StringBuffer( appendText.length() );
|
||||||
|
m = comboPtn.matcher( appendText );
|
||||||
|
while ( m.find() ) {
|
||||||
|
m.appendReplacement( appendBuf, "" );
|
||||||
|
}
|
||||||
|
m.appendTail( appendBuf );
|
||||||
|
|
||||||
// Concatenate, filtering the stream to standardize newlines and encode.
|
// Concatenate, filtering the stream to standardize newlines and encode.
|
||||||
//
|
//
|
||||||
|
@ -197,10 +217,12 @@ public class ModUtilities {
|
||||||
Writer writer = new EOLWriter( new OutputStreamWriter( tmpData, encoder ), "\r\n" );
|
Writer writer = new EOLWriter( new OutputStreamWriter( tmpData, encoder ), "\r\n" );
|
||||||
|
|
||||||
writer.append( "<?xml version=\"1.0\" encoding=\""+ encoding +"\"?>\n" );
|
writer.append( "<?xml version=\"1.0\" encoding=\""+ encoding +"\"?>\n" );
|
||||||
writer.append( mainText );
|
if ( mainHadRootTags ) writer.append( "<FTL>\n" );
|
||||||
|
writer.append( mainBuf );
|
||||||
writer.append( "\n\n<!-- Appended by Slipstream -->\n\n" );
|
writer.append( "\n\n<!-- Appended by Slipstream -->\n\n" );
|
||||||
writer.append( appendText );
|
writer.append( appendBuf );
|
||||||
writer.append( "\n" );
|
writer.append( "\n" );
|
||||||
|
if ( mainHadRootTags ) writer.append( "</FTL>\n" );
|
||||||
writer.flush();
|
writer.flush();
|
||||||
InputStream result = new ByteArrayInputStream( tmpData.toByteArray() );
|
InputStream result = new ByteArrayInputStream( tmpData.toByteArray() );
|
||||||
|
|
||||||
|
@ -211,6 +233,10 @@ public class ModUtilities {
|
||||||
/**
|
/**
|
||||||
* Appends and modifies mainStream, using content from appendStream.
|
* Appends and modifies mainStream, using content from appendStream.
|
||||||
*
|
*
|
||||||
|
* If the mainStream had <FTL> tags (introduced in FTL 1.6.1), they
|
||||||
|
* will be scrubbed, and new ones will be added after appending. If
|
||||||
|
* appendStream has those tags, they will be scrubbed.
|
||||||
|
*
|
||||||
* The two InputStreams are read, and the combined result
|
* The two InputStreams are read, and the combined result
|
||||||
* is returned as a new third InputStream.
|
* is returned as a new third InputStream.
|
||||||
*
|
*
|
||||||
|
@ -227,19 +253,43 @@ public class ModUtilities {
|
||||||
* @see net.vhati.modmanager.core.SloppyXMLOutputProcessor
|
* @see net.vhati.modmanager.core.SloppyXMLOutputProcessor
|
||||||
*/
|
*/
|
||||||
public static InputStream patchXMLFile( InputStream mainStream, InputStream appendStream, String encoding, boolean globalPanic, String mainDescription, String appendDescription ) throws IOException, JDOMException {
|
public static InputStream patchXMLFile( InputStream mainStream, InputStream appendStream, String encoding, boolean globalPanic, String mainDescription, String appendDescription ) throws IOException, JDOMException {
|
||||||
Pattern xmlDeclPtn = Pattern.compile( "<[?]xml [^>]*?[?]>\n*" );
|
// XML declaration, or root FTL tags.
|
||||||
|
Pattern comboPtn = Pattern.compile( "(<[?]xml [^>]*?[?]>\n*)|(</?FTL>)" );
|
||||||
|
Matcher m = null;
|
||||||
|
boolean mainHadRootTags = false;
|
||||||
|
String wrapperOpenTag = "<wrapper xmlns:mod='mod' xmlns:mod-append='mod-append' xmlns:mod-overwrite='mod-overwrite'>";
|
||||||
|
String wrapperCloseTag = "</wrapper>";
|
||||||
|
StringBuffer buf = null;
|
||||||
|
|
||||||
String mainText = decodeText( mainStream, mainDescription ).text;
|
String mainText = decodeText( mainStream, mainDescription ).text;
|
||||||
mainText = xmlDeclPtn.matcher( mainText ).replaceFirst( "" );
|
buf = new StringBuffer( wrapperOpenTag.length() + mainText.length() + wrapperCloseTag.length() );
|
||||||
mainText = "<wrapper xmlns:mod='mod' xmlns:mod-append='mod-append' xmlns:mod-overwrite='mod-overwrite'>"+ mainText +"</wrapper>";
|
buf.append( wrapperOpenTag );
|
||||||
Document mainDoc = parseStrictOrSloppyXML( mainText, mainDescription+" (wrapped)" );
|
m = comboPtn.matcher( mainText );
|
||||||
|
while ( m.find() ) {
|
||||||
|
if ( m.group( 2 ) != null ) mainHadRootTags = true;
|
||||||
|
m.appendReplacement( buf, "" );
|
||||||
|
}
|
||||||
|
m.appendTail( buf );
|
||||||
|
buf.append( wrapperCloseTag );
|
||||||
mainText = null;
|
mainText = null;
|
||||||
|
Document mainDoc = parseStrictOrSloppyXML( buf, mainDescription+" (wrapped)" );
|
||||||
|
buf.setLength( 0 );
|
||||||
|
|
||||||
String appendText = decodeText( appendStream, appendDescription ).text;
|
String appendText = decodeText( appendStream, appendDescription ).text;
|
||||||
appendText = xmlDeclPtn.matcher( appendText ).replaceFirst( "" );
|
buf.ensureCapacity( wrapperOpenTag.length() + appendText.length() + wrapperCloseTag.length() );
|
||||||
appendText = "<wrapper xmlns:mod='mod' xmlns:mod-append='mod-append' xmlns:mod-overwrite='mod-overwrite'>"+ appendText +"</wrapper>";
|
buf.append( wrapperOpenTag );
|
||||||
Document appendDoc = parseStrictOrSloppyXML( appendText, appendDescription+" (wrapped)" );
|
m = comboPtn.matcher( appendText );
|
||||||
|
while ( m.find() ) {
|
||||||
|
m.appendReplacement( buf, "" );
|
||||||
|
}
|
||||||
|
m.appendTail( buf );
|
||||||
|
buf.append( wrapperCloseTag );
|
||||||
appendText = null;
|
appendText = null;
|
||||||
|
Document appendDoc = parseStrictOrSloppyXML( buf, appendDescription+" (wrapped)" );
|
||||||
|
buf.setLength( 0 );
|
||||||
|
|
||||||
|
buf.trimToSize(); // Free the buffer.
|
||||||
|
buf = null;
|
||||||
|
|
||||||
XMLPatcher patcher = new XMLPatcher();
|
XMLPatcher patcher = new XMLPatcher();
|
||||||
patcher.setGlobalPanic( globalPanic );
|
patcher.setGlobalPanic( globalPanic );
|
||||||
|
@ -247,6 +297,20 @@ public class ModUtilities {
|
||||||
mainDoc = null;
|
mainDoc = null;
|
||||||
appendDoc = null;
|
appendDoc = null;
|
||||||
|
|
||||||
|
// Add FTL tags and move all content inside them.
|
||||||
|
// Collect live getContent() results in an Arraylist to avoid
|
||||||
|
// ConcurrentModificationException when detaching in the loop.
|
||||||
|
if ( mainHadRootTags ) {
|
||||||
|
Element mergedRoot = mergedDoc.getRootElement();
|
||||||
|
Element ftlNode = new Element( "FTL" );
|
||||||
|
List<Content> mergedContentList = new ArrayList<Content>( mergedRoot.getContent() );
|
||||||
|
for ( Content c : mergedContentList ) { //
|
||||||
|
c.detach();
|
||||||
|
}
|
||||||
|
ftlNode.addContent( mergedContentList );
|
||||||
|
mergedRoot.addContent( ftlNode );
|
||||||
|
}
|
||||||
|
|
||||||
// Bake XML into text, filtering the stream to standardize newlines and encode.
|
// Bake XML into text, filtering the stream to standardize newlines and encode.
|
||||||
// TODO: sloppyPrint() needs EOL normalizing!?
|
// TODO: sloppyPrint() needs EOL normalizing!?
|
||||||
//
|
//
|
||||||
|
@ -704,7 +768,7 @@ public class ModUtilities {
|
||||||
"<!-- No other dashes should touch. -->"
|
"<!-- No other dashes should touch. -->"
|
||||||
) );
|
) );
|
||||||
}
|
}
|
||||||
m.appendReplacement( dstBuf, m.quoteReplacement(m.group( 2 ).replaceAll( "[^\n]", "" )) ); // Strip comments, but preserve line count.
|
m.appendReplacement( dstBuf, m.quoteReplacement( m.group( 2 ).replaceAll( "[^\n]", "" ) ) ); // Strip comments, but preserve line count.
|
||||||
}
|
}
|
||||||
m.appendTail( dstBuf );
|
m.appendTail( dstBuf );
|
||||||
tmpBuf = srcBuf; srcBuf = dstBuf; dstBuf = tmpBuf; dstBuf.setLength( 0 );
|
tmpBuf = srcBuf; srcBuf = dstBuf; dstBuf = tmpBuf; dstBuf.setLength( 0 );
|
||||||
|
@ -718,7 +782,7 @@ public class ModUtilities {
|
||||||
ReportMessage.ERROR,
|
ReportMessage.ERROR,
|
||||||
"<"+ m.group( 1 ) +"...>...</"+ m.group( 4 ) +">"
|
"<"+ m.group( 1 ) +"...>...</"+ m.group( 4 ) +">"
|
||||||
) );
|
) );
|
||||||
m.appendReplacement( dstBuf, m.quoteReplacement("<"+ m.group( 1 ) + m.group( 2 ) +">"+ m.group( 3 ) +"</"+ m.group( 1 ) +">") );
|
m.appendReplacement( dstBuf, m.quoteReplacement( "<"+ m.group( 1 ) + m.group( 2 ) +">"+ m.group( 3 ) +"</"+ m.group( 1 ) +">" ) );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
m.appendTail( dstBuf );
|
m.appendTail( dstBuf );
|
||||||
|
@ -744,7 +808,7 @@ public class ModUtilities {
|
||||||
ReportMessage.ERROR,
|
ReportMessage.ERROR,
|
||||||
"<sectorDescription>...</sectorDescrption>"
|
"<sectorDescription>...</sectorDescrption>"
|
||||||
) );
|
) );
|
||||||
m.appendReplacement( dstBuf, m.quoteReplacement(m.group(1) +"</sectorDescription>") );
|
m.appendReplacement( dstBuf, m.quoteReplacement( m.group( 1 ) +"</sectorDescription>" ) );
|
||||||
}
|
}
|
||||||
m.appendTail( dstBuf );
|
m.appendTail( dstBuf );
|
||||||
tmpBuf = srcBuf; srcBuf = dstBuf; dstBuf = tmpBuf; dstBuf.setLength( 0 );
|
tmpBuf = srcBuf; srcBuf = dstBuf; dstBuf = tmpBuf; dstBuf.setLength( 0 );
|
||||||
|
|
|
@ -11,6 +11,7 @@ import java.awt.event.FocusEvent;
|
||||||
import java.awt.event.InputEvent;
|
import java.awt.event.InputEvent;
|
||||||
import java.awt.event.KeyEvent;
|
import java.awt.event.KeyEvent;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
import java.io.ByteArrayInputStream;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.FileNotFoundException;
|
import java.io.FileNotFoundException;
|
||||||
|
@ -63,7 +64,6 @@ import net.vhati.modmanager.core.SloppyXMLOutputProcessor;
|
||||||
import net.vhati.modmanager.core.XMLPatcher;
|
import net.vhati.modmanager.core.XMLPatcher;
|
||||||
import net.vhati.modmanager.ui.ClipboardMenuMouseListener;
|
import net.vhati.modmanager.ui.ClipboardMenuMouseListener;
|
||||||
|
|
||||||
import org.jdom2.Document;
|
|
||||||
import org.jdom2.JDOMException;
|
import org.jdom2.JDOMException;
|
||||||
|
|
||||||
|
|
||||||
|
@ -73,7 +73,7 @@ import org.jdom2.JDOMException;
|
||||||
public class ModXMLSandbox extends JFrame implements ActionListener {
|
public class ModXMLSandbox extends JFrame implements ActionListener {
|
||||||
|
|
||||||
private UndoManager undoManager = new UndoManager();
|
private UndoManager undoManager = new UndoManager();
|
||||||
private Document mainDoc = null;
|
private String mainText = null;
|
||||||
|
|
||||||
private File datsDir;
|
private File datsDir;
|
||||||
|
|
||||||
|
@ -344,17 +344,11 @@ public class ModXMLSandbox extends JFrame implements ActionListener {
|
||||||
if ( innerPath == null ) return;
|
if ( innerPath == null ) return;
|
||||||
|
|
||||||
is = pack.getInputStream( innerPath );
|
is = pack.getInputStream( innerPath );
|
||||||
String mainText = ModUtilities.decodeText( is, pack.getName()+":"+innerPath ).text;
|
InputStream rebuiltStream = ModUtilities.rebuildXMLFile( is, "windows-1252", pack.getName()+":"+innerPath );
|
||||||
|
String rebuiltText = ModUtilities.decodeText( rebuiltStream, "Sandbox Main XML" ).text;
|
||||||
is.close();
|
is.close();
|
||||||
|
|
||||||
mainText = mainText.replaceFirst( "<[?]xml [^>]*?[?]>", "" );
|
mainArea.setText( rebuiltText );
|
||||||
mainText = "<wrapper xmlns:mod='mod' xmlns:mod-append='mod-append' xmlns:mod-overwrite='mod-overwrite'>"+ mainText +"</wrapper>";
|
|
||||||
mainDoc = ModUtilities.parseStrictOrSloppyXML( mainText, "Sandbox Main XML" );
|
|
||||||
|
|
||||||
StringWriter writer = new StringWriter();
|
|
||||||
SloppyXMLOutputProcessor.sloppyPrint( mainDoc, writer, null );
|
|
||||||
String displayedText = writer.toString().replaceAll( "\r(?!\n)|(?<!\r)\n|\r\n", "\n" ); // sloppyPrint needs normalizing!?
|
|
||||||
mainArea.setText( displayedText );
|
|
||||||
mainArea.setCaretPosition( 0 );
|
mainArea.setCaretPosition( 0 );
|
||||||
areasPane.setSelectedComponent( mainScroll );
|
areasPane.setSelectedComponent( mainScroll );
|
||||||
resultArea.setText( "" );
|
resultArea.setText( "" );
|
||||||
|
@ -378,29 +372,26 @@ public class ModXMLSandbox extends JFrame implements ActionListener {
|
||||||
|
|
||||||
|
|
||||||
private void patch() {
|
private void patch() {
|
||||||
if ( mainDoc == null ) return;
|
String mainText = mainArea.getText();
|
||||||
|
if ( mainText.length() == 0 ) return;
|
||||||
|
|
||||||
messageArea.setText( "" );
|
messageArea.setText( "" );
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
InputStream mainStream = new ByteArrayInputStream( mainText.getBytes( "UTF-8" ) );
|
||||||
|
|
||||||
String appendText = appendArea.getText();
|
String appendText = appendArea.getText();
|
||||||
appendText = appendText.replaceFirst( "<[?]xml [^>]*?[?]>", "" );
|
InputStream appendStream = new ByteArrayInputStream( appendText.getBytes( "UTF-8" ) );
|
||||||
appendText = "<wrapper xmlns:mod='mod' xmlns:mod-append='mod-append' xmlns:mod-overwrite='mod-overwrite'>"+ appendText +"</wrapper>";
|
|
||||||
Document appendDoc = ModUtilities.parseStrictOrSloppyXML( appendText, "Sandbox Append XML" );
|
|
||||||
|
|
||||||
XMLPatcher patcher = new XMLPatcher();
|
InputStream resultStream = ModUtilities.patchXMLFile( mainStream, appendStream, "windows-1252", false, "Sandbox Main XML", "Sandbox Append XML" );
|
||||||
patcher.setGlobalPanic( false );
|
String resultText = ModUtilities.decodeText( resultStream, "Sandbox Result XML" ).text;
|
||||||
Document resultDoc = patcher.patch( mainDoc, appendDoc );
|
|
||||||
|
|
||||||
StringWriter writer = new StringWriter();
|
resultArea.setText( resultText );
|
||||||
SloppyXMLOutputProcessor.sloppyPrint( resultDoc, writer, null );
|
|
||||||
String displayedText = writer.toString().replaceAll( "\r(?!\n)|(?<!\r)\n|\r\n", "\n" ); // sloppyPrint needs normalizing!?
|
|
||||||
resultArea.setText( displayedText );
|
|
||||||
resultArea.setCaretPosition( 0 );
|
resultArea.setCaretPosition( 0 );
|
||||||
areasPane.setSelectedComponent( resultScroll );
|
areasPane.setSelectedComponent( resultScroll );
|
||||||
}
|
}
|
||||||
catch ( Exception f ) {
|
catch ( Exception e ) {
|
||||||
messageArea.setText( f.getMessage() );
|
messageArea.setText( e.toString() );
|
||||||
messageArea.setCaretPosition( 0 );
|
messageArea.setCaretPosition( 0 );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue