Added tolerance of optional FTL 1.6.1 root tags when patching

This commit is contained in:
Vhati 2017-12-05 22:42:31 -05:00
parent 8f8d2072a9
commit a5383766ef
3 changed files with 101 additions and 40 deletions

View file

@ -35,7 +35,9 @@ import net.vhati.modmanager.core.SloppyXMLParser;
import ar.com.hjg.pngj.PngReader;
import org.jdom2.Content;
import org.jdom2.Document;
import org.jdom2.Element;
import org.jdom2.JDOMException;
import org.jdom2.input.JDOMParseException;
import org.jdom2.input.SAXBuilder;
@ -85,7 +87,7 @@ public class ModUtilities {
byte[] buf = new byte[4096];
int len;
ByteArrayOutputStream tmpData = new ByteArrayOutputStream();
while ( (len = is.read(buf)) >= 0 ) {
while ( (len = is.read( buf )) >= 0 ) {
tmpData.write( buf, 0, len );
}
byte[] allBytes = tmpData.toByteArray();
@ -166,6 +168,10 @@ public class ModUtilities {
* tacked on as-is. Any xml declaration tags will be scrubbed from both
* 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
* new third InputStream.
*
@ -182,13 +188,27 @@ public class ModUtilities {
* 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 {
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;
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;
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.
//
@ -197,10 +217,12 @@ public class ModUtilities {
Writer writer = new EOLWriter( new OutputStreamWriter( tmpData, encoder ), "\r\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( appendText );
writer.append( appendBuf );
writer.append( "\n" );
if ( mainHadRootTags ) writer.append( "</FTL>\n" );
writer.flush();
InputStream result = new ByteArrayInputStream( tmpData.toByteArray() );
@ -211,6 +233,10 @@ public class ModUtilities {
/**
* Appends and modifies mainStream, using content from appendStream.
*
* If the mainStream had &lt;FTL&gt; 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 new third InputStream.
*
@ -227,19 +253,43 @@ public class ModUtilities {
* @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 {
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;
mainText = xmlDeclPtn.matcher( mainText ).replaceFirst( "" );
mainText = "<wrapper xmlns:mod='mod' xmlns:mod-append='mod-append' xmlns:mod-overwrite='mod-overwrite'>"+ mainText +"</wrapper>";
Document mainDoc = parseStrictOrSloppyXML( mainText, mainDescription+" (wrapped)" );
buf = new StringBuffer( wrapperOpenTag.length() + mainText.length() + wrapperCloseTag.length() );
buf.append( wrapperOpenTag );
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;
Document mainDoc = parseStrictOrSloppyXML( buf, mainDescription+" (wrapped)" );
buf.setLength( 0 );
String appendText = decodeText( appendStream, appendDescription ).text;
appendText = xmlDeclPtn.matcher( appendText ).replaceFirst( "" );
appendText = "<wrapper xmlns:mod='mod' xmlns:mod-append='mod-append' xmlns:mod-overwrite='mod-overwrite'>"+ appendText +"</wrapper>";
Document appendDoc = parseStrictOrSloppyXML( appendText, appendDescription+" (wrapped)" );
buf.ensureCapacity( wrapperOpenTag.length() + appendText.length() + wrapperCloseTag.length() );
buf.append( wrapperOpenTag );
m = comboPtn.matcher( appendText );
while ( m.find() ) {
m.appendReplacement( buf, "" );
}
m.appendTail( buf );
buf.append( wrapperCloseTag );
appendText = null;
Document appendDoc = parseStrictOrSloppyXML( buf, appendDescription+" (wrapped)" );
buf.setLength( 0 );
buf.trimToSize(); // Free the buffer.
buf = null;
XMLPatcher patcher = new XMLPatcher();
patcher.setGlobalPanic( globalPanic );
@ -247,6 +297,20 @@ public class ModUtilities {
mainDoc = 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.
// TODO: sloppyPrint() needs EOL normalizing!?
//
@ -704,7 +768,7 @@ public class ModUtilities {
"<!-- 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 );
tmpBuf = srcBuf; srcBuf = dstBuf; dstBuf = tmpBuf; dstBuf.setLength( 0 );
@ -718,7 +782,7 @@ public class ModUtilities {
ReportMessage.ERROR,
"<"+ 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 );
@ -744,7 +808,7 @@ public class ModUtilities {
ReportMessage.ERROR,
"<sectorDescription>...</sectorDescrption>"
) );
m.appendReplacement( dstBuf, m.quoteReplacement(m.group(1) +"</sectorDescription>") );
m.appendReplacement( dstBuf, m.quoteReplacement( m.group( 1 ) +"</sectorDescription>" ) );
}
m.appendTail( dstBuf );
tmpBuf = srcBuf; srcBuf = dstBuf; dstBuf = tmpBuf; dstBuf.setLength( 0 );

View file

@ -11,6 +11,7 @@ import java.awt.event.FocusEvent;
import java.awt.event.InputEvent;
import java.awt.event.KeyEvent;
import java.io.File;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.io.IOException;
import java.io.FileNotFoundException;
@ -63,7 +64,6 @@ import net.vhati.modmanager.core.SloppyXMLOutputProcessor;
import net.vhati.modmanager.core.XMLPatcher;
import net.vhati.modmanager.ui.ClipboardMenuMouseListener;
import org.jdom2.Document;
import org.jdom2.JDOMException;
@ -73,7 +73,7 @@ import org.jdom2.JDOMException;
public class ModXMLSandbox extends JFrame implements ActionListener {
private UndoManager undoManager = new UndoManager();
private Document mainDoc = null;
private String mainText = null;
private File datsDir;
@ -344,17 +344,11 @@ public class ModXMLSandbox extends JFrame implements ActionListener {
if ( innerPath == null ) return;
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();
mainText = mainText.replaceFirst( "<[?]xml [^>]*?[?]>", "" );
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.setText( rebuiltText );
mainArea.setCaretPosition( 0 );
areasPane.setSelectedComponent( mainScroll );
resultArea.setText( "" );
@ -378,29 +372,26 @@ public class ModXMLSandbox extends JFrame implements ActionListener {
private void patch() {
if ( mainDoc == null ) return;
String mainText = mainArea.getText();
if ( mainText.length() == 0 ) return;
messageArea.setText( "" );
try {
InputStream mainStream = new ByteArrayInputStream( mainText.getBytes( "UTF-8" ) );
String appendText = appendArea.getText();
appendText = appendText.replaceFirst( "<[?]xml [^>]*?[?]>", "" );
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" );
InputStream appendStream = new ByteArrayInputStream( appendText.getBytes( "UTF-8" ) );
XMLPatcher patcher = new XMLPatcher();
patcher.setGlobalPanic( false );
Document resultDoc = patcher.patch( mainDoc, appendDoc );
InputStream resultStream = ModUtilities.patchXMLFile( mainStream, appendStream, "windows-1252", false, "Sandbox Main XML", "Sandbox Append XML" );
String resultText = ModUtilities.decodeText( resultStream, "Sandbox Result XML" ).text;
StringWriter writer = new StringWriter();
SloppyXMLOutputProcessor.sloppyPrint( resultDoc, writer, null );
String displayedText = writer.toString().replaceAll( "\r(?!\n)|(?<!\r)\n|\r\n", "\n" ); // sloppyPrint needs normalizing!?
resultArea.setText( displayedText );
resultArea.setText( resultText );
resultArea.setCaretPosition( 0 );
areasPane.setSelectedComponent( resultScroll );
}
catch ( Exception f ) {
messageArea.setText( f.getMessage() );
catch ( Exception e ) {
messageArea.setText( e.toString() );
messageArea.setCaretPosition( 0 );
}
}