Added LF to CR-LF conversion, and warnings
This commit is contained in:
parent
5f289a0bef
commit
9b34c5119f
5 changed files with 126 additions and 32 deletions
|
@ -1,13 +1,17 @@
|
||||||
Changelog
|
Changelog
|
||||||
|
|
||||||
|
???:
|
||||||
|
- Added LF to CR-LF conversion for *.xml.append, *.xml, and *.txt
|
||||||
|
- Added a Validate warning for text files with LF line endings
|
||||||
|
|
||||||
1.0:
|
1.0:
|
||||||
- Changed mod list to a table with checkboxes
|
- Changed mod list to a table with checkboxes
|
||||||
- Instead of extracting to temp, mod data is transferred directly into dats
|
- Instead of extracting to temp, mod data is transferred directly into dats
|
||||||
- Added a GUI progress bar during patching
|
- Added a GUI progress bar during patching
|
||||||
- Added a Validate warning for paths with non-ASCII chars
|
- Added a Validate warning for paths with non-ASCII chars
|
||||||
|
- Added support for windows-1252 ANSI and UTF-16 text in mods
|
||||||
|
|
||||||
Changes shared with Grognaks Mod Manager 1.8:
|
Changes shared with Grognaks Mod Manager 1.8:
|
||||||
- Added support for windows-1252 ANSI and UTF-16 text in mods
|
|
||||||
- Added periodic updates to the catalog of mod metadata
|
- Added periodic updates to the catalog of mod metadata
|
||||||
- Added ini setting: update_catalog
|
- Added ini setting: update_catalog
|
||||||
- Added a log warning during patching if a mod gets clobbered
|
- Added a log warning during patching if a mod gets clobbered
|
||||||
|
|
|
@ -30,17 +30,22 @@ The Append Extension
|
||||||
to your pleasure by writing an event of the same name. Whenever multiple
|
to your pleasure by writing an event of the same name. Whenever multiple
|
||||||
tags share the same name, only the last one counts.
|
tags share the same name, only the last one counts.
|
||||||
|
|
||||||
|
When you're not overriding something, try to use unique names, so that
|
||||||
|
it won't clobber another mod and vice versa.
|
||||||
|
|
||||||
|
|
||||||
General
|
General
|
||||||
|
|
||||||
When developing a mod, save your text files as ANSI/ASCII, or UTF-8.
|
When developing a mod, save your text files as ANSI/ASCII, or UTF-8.
|
||||||
UTF-16 is tolerated. If all else fails, Slipstream will try decoding
|
Slipstream will tolerate UTF-16 and Windows-1252 ANSI.
|
||||||
text as Windows-1252 ANSI.
|
|
||||||
|
|
||||||
Unless you're overriding something, try to use unique names in your xml
|
Dos style (CR-LF) line endings are preferred. The game only partially
|
||||||
so that it won't clobber another mod and vice versa. File and directory
|
accepts the unix style (LF): fine for xml, crashing for layout.txt.
|
||||||
names must be plain ASCII (no accents). That restriction isn't confirmed
|
Slipstream will convert both to CR-LF as it patches.
|
||||||
for the game, but the mod manager enforces it just to be safe.
|
|
||||||
|
File and directory names must be plain ASCII (no accents). That
|
||||||
|
restriction isn't confirmed for the game, but the mod manager enforces
|
||||||
|
it just to be safe.
|
||||||
|
|
||||||
Images should be 32bit PNGs (24bit color + 8bit alpha transparency).
|
Images should be 32bit PNGs (24bit color + 8bit alpha transparency).
|
||||||
Things that *should* be opaque rectangles like backgrounds may vary,
|
Things that *should* be opaque rectangles like backgrounds may vary,
|
||||||
|
|
|
@ -26,7 +26,7 @@ public class FTLModManager {
|
||||||
private static final Logger log = LogManager.getLogger(FTLModManager.class);
|
private static final Logger log = LogManager.getLogger(FTLModManager.class);
|
||||||
|
|
||||||
private static final String APP_NAME = "Slipstream Mod Manager";
|
private static final String APP_NAME = "Slipstream Mod Manager";
|
||||||
private static final ComparableVersion APP_VERSION = new ComparableVersion( "1.0" );
|
private static final ComparableVersion APP_VERSION = new ComparableVersion( "???" );
|
||||||
private static final String APP_URL = "http://www.ftlgame.com/forum/viewtopic.php?f=12&t=17102";
|
private static final String APP_URL = "http://www.ftlgame.com/forum/viewtopic.php?f=12&t=17102";
|
||||||
private static final String APP_AUTHOR = "Vhati";
|
private static final String APP_AUTHOR = "Vhati";
|
||||||
|
|
||||||
|
@ -34,8 +34,8 @@ public class FTLModManager {
|
||||||
public static void main( String[] args ) {
|
public static void main( String[] args ) {
|
||||||
|
|
||||||
log.debug( String.format( "%s v%s", APP_NAME, APP_VERSION ) );
|
log.debug( String.format( "%s v%s", APP_NAME, APP_VERSION ) );
|
||||||
log.debug( System.getProperty("os.name") +" "+ System.getProperty("os.version") +" "+ System.getProperty("os.arch") );
|
log.debug( String.format( "%s %s", System.getProperty("os.name"), System.getProperty("os.version") ) );
|
||||||
log.debug( System.getProperty("java.vm.name") +", "+ System.getProperty("java.version") );
|
log.debug( String.format( "%s, %s, %s", System.getProperty("java.vm.name"), System.getProperty("java.version"), System.getProperty("os.arch") ) );
|
||||||
|
|
||||||
|
|
||||||
File configFile = new File( "modman.cfg" );
|
File configFile = new File( "modman.cfg" );
|
||||||
|
@ -154,7 +154,9 @@ public class FTLModManager {
|
||||||
configComments += " update_catalog - If true, periodically download descriptions for the latest mods. If invalid, you'll be prompted.\n";
|
configComments += " update_catalog - If true, periodically download descriptions for the latest mods. If invalid, you'll be prompted.\n";
|
||||||
configComments += " use_default_ui - If true, no attempt will be made to resemble a native GUI. Default: false.\n";
|
configComments += " use_default_ui - If true, no attempt will be made to resemble a native GUI. Default: false.\n";
|
||||||
|
|
||||||
config.store( new OutputStreamWriter( out, "UTF-8" ), configComments );
|
OutputStreamWriter writer = new OutputStreamWriter( out, "UTF-8" );
|
||||||
|
config.store( writer, configComments );
|
||||||
|
writer.flush();
|
||||||
}
|
}
|
||||||
catch ( IOException e ) {
|
catch ( IOException e ) {
|
||||||
log.error( "Error saving config to "+ configFile.getPath(), e );
|
log.error( "Error saving config to "+ configFile.getPath(), e );
|
||||||
|
|
|
@ -233,6 +233,21 @@ public class ModPatchThread extends Thread {
|
||||||
moddedItems.add( innerPath );
|
moddedItems.add( innerPath );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if ( fileName.endsWith( ".xml" ) || fileName.endsWith( ".txt" ) ) {
|
||||||
|
String innerPath = checkCase( item.getName(), knownPaths, knownPathsLower );
|
||||||
|
|
||||||
|
// Normalize line endings for other text files to CR-LF.
|
||||||
|
InputStream fixedStream = ModUtilities.setLineEndings( zis, "\r\n", modFile.getName()+":"+parentPath+fileName );
|
||||||
|
|
||||||
|
if ( !moddedItems.contains(innerPath) )
|
||||||
|
moddedItems.add( innerPath );
|
||||||
|
else
|
||||||
|
log.warn( String.format( "Clobbering earlier mods: %s", innerPath ) );
|
||||||
|
|
||||||
|
if ( ftlP.contains( innerPath ) )
|
||||||
|
ftlP.remove( innerPath );
|
||||||
|
ftlP.add( innerPath, fixedStream );
|
||||||
|
}
|
||||||
else {
|
else {
|
||||||
String innerPath = checkCase( item.getName(), knownPaths, knownPathsLower );
|
String innerPath = checkCase( item.getName(), knownPaths, knownPathsLower );
|
||||||
|
|
||||||
|
|
|
@ -112,8 +112,17 @@ public class ModUtilities {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Determine the original line endings.
|
||||||
|
int eol = DecodeResult.EOL_NONE;
|
||||||
|
Matcher m = Pattern.compile( "(\r(?!\n))|((?<!\r)\n)|(\r\n)" ).matcher( result );
|
||||||
|
if ( m.find() ) {
|
||||||
|
if ( m.group(3) != null ) eol = DecodeResult.EOL_CRLF;
|
||||||
|
else if ( m.group(2) != null ) eol = DecodeResult.EOL_LF;
|
||||||
|
else if ( m.group(1) != null ) eol = DecodeResult.EOL_CR;
|
||||||
|
}
|
||||||
|
|
||||||
result = result.replaceAll( "\r(?!\n)|\r\n", "\n" );
|
result = result.replaceAll( "\r(?!\n)|\r\n", "\n" );
|
||||||
return new DecodeResult( result, encoding, bom );
|
return new DecodeResult( result, encoding, eol, bom );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -126,6 +135,8 @@ public class ModUtilities {
|
||||||
* The returned stream is a ByteArrayInputStream
|
* The returned stream is a ByteArrayInputStream
|
||||||
* which doesn't need closing.
|
* which doesn't need closing.
|
||||||
*
|
*
|
||||||
|
* The result will be UTF-8 with CR-LF line endings.
|
||||||
|
*
|
||||||
* The description arguments identify the streams for log messages.
|
* The description arguments identify the streams for log messages.
|
||||||
*/
|
*/
|
||||||
public static InputStream appendXMLFile( InputStream srcStream, InputStream dstStream, String srcDescription, String dstDescription ) throws IOException {
|
public static InputStream appendXMLFile( InputStream srcStream, InputStream dstStream, String srcDescription, String dstDescription ) throws IOException {
|
||||||
|
@ -137,20 +148,50 @@ public class ModUtilities {
|
||||||
String dstText = decodeText( dstStream, dstDescription ).text;
|
String dstText = decodeText( dstStream, dstDescription ).text;
|
||||||
dstText = xmlDeclPtn.matcher(dstText).replaceFirst( "" );
|
dstText = xmlDeclPtn.matcher(dstText).replaceFirst( "" );
|
||||||
|
|
||||||
|
StringBuilder buf = new StringBuilder( srcText.length() +100+ dstText.length() );
|
||||||
|
buf.append( "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n" );
|
||||||
|
buf.append( dstText );
|
||||||
|
buf.append( "\n\n<!-- Appended by GMM -->\n\n" );
|
||||||
|
buf.append( srcText );
|
||||||
|
buf.append( "\n" );
|
||||||
|
|
||||||
|
String mergedString = Pattern.compile("\n").matcher( buf ).replaceAll("\r\n");
|
||||||
|
|
||||||
ByteArrayOutputStream tmpData = new ByteArrayOutputStream();
|
ByteArrayOutputStream tmpData = new ByteArrayOutputStream();
|
||||||
BufferedWriter bw = new BufferedWriter( new OutputStreamWriter( tmpData, "UTF-8" ) );
|
BufferedWriter bw = new BufferedWriter( new OutputStreamWriter( tmpData, "UTF-8" ) );
|
||||||
|
bw.write( mergedString );
|
||||||
bw.write( "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n" );
|
|
||||||
bw.write( dstText );
|
|
||||||
bw.write( "\n\n<!-- Appended by GMM -->\n\n");
|
|
||||||
bw.write( srcText );
|
|
||||||
bw.write( "\n" );
|
|
||||||
bw.flush();
|
bw.flush();
|
||||||
|
|
||||||
InputStream result = new ByteArrayInputStream( tmpData.toByteArray() );
|
InputStream result = new ByteArrayInputStream( tmpData.toByteArray() );
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calls decodeText() on a stream, replaces line endings, and re-encodes.
|
||||||
|
*
|
||||||
|
* The returned stream is a ByteArrayInputStream
|
||||||
|
* which doesn't need closing.
|
||||||
|
*
|
||||||
|
* The result will be UTF-8 with the desired line endings.
|
||||||
|
*
|
||||||
|
* The description argument identifies the stream for log messages.
|
||||||
|
*/
|
||||||
|
public static InputStream setLineEndings( InputStream srcStream, String eol, String srcDescription ) throws IOException {
|
||||||
|
// decodeText() returns a LF string.
|
||||||
|
String srcText = decodeText( srcStream, srcDescription ).text;
|
||||||
|
String fixedText = Pattern.compile("\n").matcher( srcText ).replaceAll( Matcher.quoteReplacement(eol) );
|
||||||
|
|
||||||
|
ByteArrayOutputStream tmpData = new ByteArrayOutputStream();
|
||||||
|
BufferedWriter bw = new BufferedWriter( new OutputStreamWriter( tmpData, "UTF-8" ) );
|
||||||
|
bw.write( fixedText );
|
||||||
|
bw.flush();
|
||||||
|
|
||||||
|
InputStream result = new ByteArrayInputStream( tmpData.toByteArray() );
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks a mod file for common problems.
|
* Checks a mod file for common problems.
|
||||||
*
|
*
|
||||||
|
@ -215,7 +256,7 @@ public class ModUtilities {
|
||||||
) );
|
) );
|
||||||
modValid = false;
|
modValid = false;
|
||||||
}
|
}
|
||||||
else if ( innerPath.endsWith( ".png" ) ) {
|
else if ( innerPath.endsWith( "[.]png" ) ) {
|
||||||
try {
|
try {
|
||||||
PngReader pngr = new PngReader( zis );
|
PngReader pngr = new PngReader( zis );
|
||||||
|
|
||||||
|
@ -249,9 +290,7 @@ public class ModUtilities {
|
||||||
modValid = false;
|
modValid = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if ( innerPath.matches( "^.*(?:.xml.append|.append.xml|.xml)$" ) ) {
|
else if ( innerPath.matches( "^.*(?:[.]xml[.]append|[.]append[.]xml|[.]xml|[.]txt)$" ) ) {
|
||||||
if ( innerPath.matches( "^.*(?:.xml.append|.append.xml)$" ) )
|
|
||||||
seenAppend = true;
|
|
||||||
|
|
||||||
DecodeResult decodeResult = ModUtilities.decodeText( zis, modFile.getName()+":"+innerPath );
|
DecodeResult decodeResult = ModUtilities.decodeText( zis, modFile.getName()+":"+innerPath );
|
||||||
|
|
||||||
|
@ -263,6 +302,15 @@ public class ModUtilities {
|
||||||
modValid = false;
|
modValid = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ( decodeResult.eol != DecodeResult.EOL_CRLF &&
|
||||||
|
decodeResult.eol != DecodeResult.EOL_NONE ) {
|
||||||
|
pendingMsgs.add( new ReportMessage(
|
||||||
|
ReportMessage.ERROR,
|
||||||
|
String.format( "%s line endings (CR-LF is safest)", decodeResult.getEOLName() )
|
||||||
|
) );
|
||||||
|
modValid = false;
|
||||||
|
}
|
||||||
|
|
||||||
List<Pattern> oddCharPtns = new ArrayList<Pattern>();
|
List<Pattern> oddCharPtns = new ArrayList<Pattern>();
|
||||||
Map<Pattern,String> oddCharSuggestions = new HashMap<Pattern,String>();
|
Map<Pattern,String> oddCharSuggestions = new HashMap<Pattern,String>();
|
||||||
Map<Pattern,List<Character>> oddCharLists = new HashMap<Pattern,List<Character>>();
|
Map<Pattern,List<Character>> oddCharLists = new HashMap<Pattern,List<Character>>();
|
||||||
|
@ -310,17 +358,22 @@ public class ModUtilities {
|
||||||
|
|
||||||
// TODO: Nag if there are chars FTL can't show.
|
// TODO: Nag if there are chars FTL can't show.
|
||||||
|
|
||||||
Report xmlReport = validateModXML( decodeResult.text, formatter );
|
if ( innerPath.matches( "^.*(?:[.]xml[.]append|[.]append[.]xml|[.]xml)$" ) ) {
|
||||||
|
if ( innerPath.matches( "^.*(?:[.]xml[.]append|[.]append[.]xml)$" ) )
|
||||||
|
seenAppend = true;
|
||||||
|
|
||||||
if ( xmlReport.text.length() > 0 ) {
|
Report xmlReport = validateModXML( decodeResult.text, formatter );
|
||||||
pendingMsgs.add( new ReportMessage(
|
|
||||||
ReportMessage.NESTED_BLOCK,
|
if ( xmlReport.text.length() > 0 ) {
|
||||||
xmlReport.text
|
pendingMsgs.add( new ReportMessage(
|
||||||
) );
|
ReportMessage.NESTED_BLOCK,
|
||||||
|
xmlReport.text
|
||||||
|
) );
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( xmlReport.outcome == false )
|
||||||
|
modValid = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( xmlReport.outcome == false )
|
|
||||||
modValid = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( !pendingMsgs.isEmpty() ) {
|
if ( !pendingMsgs.isEmpty() ) {
|
||||||
|
@ -644,17 +697,32 @@ public class ModUtilities {
|
||||||
*
|
*
|
||||||
* text - The decoded string.
|
* text - The decoded string.
|
||||||
* encoding - The encoding used.
|
* encoding - The encoding used.
|
||||||
|
* eol - A constant describing the original line endings.
|
||||||
* bom - The BOM bytes found, or null.
|
* bom - The BOM bytes found, or null.
|
||||||
*/
|
*/
|
||||||
public static class DecodeResult {
|
public static class DecodeResult {
|
||||||
|
public static final int EOL_NONE = 0;
|
||||||
|
public static final int EOL_CRLF = 1;
|
||||||
|
public static final int EOL_LF = 2;
|
||||||
|
public static final int EOL_CR = 3;
|
||||||
|
|
||||||
public final String text;
|
public final String text;
|
||||||
public final String encoding;
|
public final String encoding;
|
||||||
|
public final int eol;
|
||||||
public final byte[] bom;
|
public final byte[] bom;
|
||||||
|
|
||||||
public DecodeResult( String text, String encoding, byte[] bom ) {
|
public DecodeResult( String text, String encoding, int eol, byte[] bom ) {
|
||||||
this.text = text;
|
this.text = text;
|
||||||
this.encoding = encoding;
|
this.encoding = encoding;
|
||||||
|
this.eol = eol;
|
||||||
this.bom = bom;
|
this.bom = bom;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getEOLName() {
|
||||||
|
if ( eol == EOL_CRLF ) return "CR-LF";
|
||||||
|
if ( eol == EOL_LF ) return "LF";
|
||||||
|
if ( eol == EOL_CR ) return "CR";
|
||||||
|
return "None";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue