/*
* [FixPads.java]
*
* Summary: Methods to fix pads and other such files for projects.
*
* Copyright: (c) 2009-2017 Roedy Green, Canadian Mind Products, http://mindprod.com
*
* Licence: This software may be copied and used freely for any purpose but military.
* http://mindprod.com/contact/nonmil.html
*
* Requires: JDK 1.8+
*
* Created with: JetBrains IntelliJ IDEA IDE http://www.jetbrains.com/idea/
*
* Version History:
* 1.0 2007-05-12 initial version.
* 1.1 2009-09-02 simplify code to use common code for both pml and xml files.
*/
package com.mindprod.zzz;
import com.mindprod.common18.Localise;
import com.mindprod.fastcat.FastCat;
import com.mindprod.hunkio.HunkIO;
import java.io.File;
import java.io.IOException;
import java.text.DecimalFormat;
import static com.mindprod.zzz.PADType.PAD311;
import static java.lang.System.*;
/**
* Methods to fix pads and other such files for projects.
*
* pad.xml *.cml *.pml all use CrLf line separators.
*
* @author Roedy Green, Canadian Mind Products
* @version 1.2 2010-01-29 deal with ! being chopped from pml file names.
* @see CrossCheckProject
* @since 2007-05-12
*/
class FixPads extends ProjectInfo
{
// declarations
/**
* maximum size of zip we expect to distribute in bytes.
*/
private static final int MAX_ZIP_SIZE = 20 * ( 1024 * 1024 ) /* 20 megabytes */;
/**
* where generated list of all pads is. Inserted into each pad in the section.
* Generated by Prices.Prices. with CrLf line endings.
*/
private static final String ALLPADS_FILE = "E:\\mindprod\\pad\\allpads.txt";
private static final String ASP_TEXT = /* withouth */
"Y\n" +
"Y\n" +
"07607\n";
/**
* OS_SUPPORT string that PAD 3.01 specifies
*/
private static final String CORRECT_OS_SUPPORT = "Java,Linux,Mac OS X,Unix,Win2000,Win7 x32,Win7 x64,WinServer," +
"WinVista,WinVista x64,WinXP";
/**
* text of the end user licence agreement.
*/
private static final String EULA_TEXT = Localise.localise( "This program is for non-military use only.\n" +
"For details on what that licencing restriction means " +
"and why I restricted this software that way, " +
"see http://mindprod.com/contact/nonmil.html\n" +
"If you incorporate any of my code in your programs, " +
"they too must be marked for non-military use only.\n" +
"However it is not your responsibility to enforce that" +
" restriction.\n" );
/**
* fragment to handle extension without lead/trail tags.
*/
private static final String NEWSFEED_TEXT = Localise.localise(
"http://mindprod.com/rss/jgloss.xml\n" +
"RSS 2.0\n" +
"Canadian Mind Products\n" +
"http://mindprod.com\n" +
"Roedy\n" +
"Green\n" +
"inquiry@mindprod.com\n" +
"English\n" +
"Canadian Mind Products | Java Glossary\n" +
"Glossary of Java terms, sample Java code, " +
"Java and Internet lore.\n" +
"Glossary of Java terms, sample Java code, and general Java and Internet lore" +
".\n" +
"For non-military use only.\n" +
"News about updates of free software with full source written in Java, C, C++ and ASM.\n" +
"Also coding example programs and coding snippets.\n" +
"News\n"
);
/**
* fragment to handle link to PADmap ,without lead and trail tags
*/
private static final String PADMAP_TEXT = Localise.localise(
"Y\n" +
"\n" +
"Link to plain text file containing ALL the mindprod.com PAD URLs\n" +
"\n" +
"1.0\n" +
"http://www.padmaps.org/padmap.htm\n" +
"Company\n" +
// Allpads.txt contains both PAD 3.11 and PAD 4.0 pads.
"http://mindprod.com/pad/allpads.txt\n"
);
/**
* allPads list of urls, etx of allpads.txt,
* list of there set of mindprod PAD urls to embed in each PAD we send out into the world.
* Contains both PAD 3.11 and PAD 4.0 pads.
*/
private static final String PADRING_TEXT_LIST_OF_URLS;
/**
* padtube extension, c.f. PADRING, PADMAPS
*/
private static final String PADTUBE_TEXT = Localise.localise(
"Y\n" +
"Allows publishers to link PAD files to their PADTube publisher accounts" +
".\n" +
"1.0\n" +
"http://www.padtube.com/pad/extensions/PADTube.htm\n" +
"Company\n" +
"Y\n" +
"^[yYnN]\\Z\n" +
"Y, y, N, or n\n" +
"mindprod\n" +
"^[a-zA-Z0-9_.]{6,32}\\Z\n" +
"Alphanumeric with underscore allowed 6-32 " +
"characters\n" +
"http://www.padtube.com\n"
);
/**
* standard header for a PAD file
*/
private static final String PAD_HEADER = Localise.localise( "\n" +
"\n" +
"\n" +
"3.11\n" +
"PADGen 3.1.1.50 http://www.padgen" +
".org\n" +
"Portable Application Description, " +
"or PAD for short,\n" +
"is a data set that is used by shareware authors to " +
"disseminate information to anyone interested in " +
"their software products.\n" +
"To find out more go to http://pad.asp-software" +
".org\n" +
"\n" );
/**
* description of the site as a whole goes inside
*/
private static final String SITE_TEXT = Localise.localise(
"Y\n" +
"1.0\n" +
"http://Submit-Everywhere.com/extensions/Site.htm\n" +
"This PAD extension allows you to add your site info into your PAD file.\n" +
"This info can be used by site submission software or by web directories themselves.\n" +
"Canadian Mind Products\n" +
"http://mindprod.com/products.html\n" +
"CMP's purpose is to stand up for the rights of plants and animals. Java, " +
"Computer Buyer glossaries.\n" +
"CMP's purpose is to stand up for the rights of plants and animals. Animals also " +
"includes cetacea, humans, gay people, atheists, war victims and invertebrates. CMP attempts to inculcate" +
" planetary consciousness - concern for the planet as a whole.\n" +
"CMP's purpose is to stand up for the rights of plants and animals. Animals also " +
"includes cetacea, humans, gay people, atheists, war victims and invertebrates. CMP attempts to inculcate" +
" planetary consciousness - concern for the planet as a whole. A subgoal is to teach people to use " +
"computers effectively, particularly with the Java computer language.\n" +
"inquiry@mindprod.com\n" +
"Roedy\n" +
"Green\n" +
"Roedy Green, Canadian Mind Products, Java Glossary, Computer Buyers' Glossary, " +
"Gay Glossary, Java, glossary, gay, roedy, CMP, Consolidated Moose Pasture, " +
"terminology\n" /** 200 char limit */
);
/**
* \r \n line separator usend in PadFiles to make them Windows compatible. Leave as \n, will change to \r\n
*/
private static final String _NL = com.mindprod.common18.Localise.localise( "\n" );
/**
* XML information about company
*/
private static final String companyPadInfo = getCompanyPadInfo();
/**
* format for PAD
*/
private static final DecimalFormat padMBFormat = new DecimalFormat( "#####0.00" );
// /declarations
static
{
// temp variable needed since Java worries that exception could happen after ap assigned.
String ap;
try
{
ap = HunkIO.readEntireFile( new File( ALLPADS_FILE ) ); // already has \r\n
}
catch ( IOException e )
{
err.println();
e.printStackTrace( err );
err.println( "static: Unable to access allPads.pad" );
err.println();
ap = null;
}
// has embedded crLf after each line.
PADRING_TEXT_LIST_OF_URLS = ap;
}
/**
* Copy constructor
*
* @param pi Copy constructor to extend class
*/
@SuppressWarnings( { "SameParameterValue" } )
FixPads( ProjectInfo pi )
{
super( pi );
}
// methods
/**
* Check that PAD starts and ends as expected. Does not repair, as failure could be symptoms of serious damage.
*
* @param shouldStartWidth String PAD file should start with including any control chars. Case sensitive.
* @param shouldEndWith String PAD file should end with including any control chars. Case sensitive
* @param padFile which pad file to patch, the mother or the distributed.
*/
private static void checkPADIntact( String shouldStartWidth, String shouldEndWith, final File padFile )
{
try
{
if ( !padFile.exists() )
{
err.println( "checkPADIntact missing padFile " + padFile.toString() );
return;
}
final String big = HunkIO.readEntireFile( padFile ).trim();
if ( !big.startsWith( shouldStartWidth ) )
{
err.println( "checkPADIntact missing " + shouldStartWidth + " : " + padFile.toString() );
return;
}
if ( !big.endsWith( shouldEndWith ) )
{
err.println( "checkPADIntact missing " + shouldEndWith + " : " + padFile.toString() );
}
}
catch ( IOException e )
{
err.println();
e.printStackTrace( err );
err.println( "checkPADIntact: Unable to access: " + padFile.toString() );
err.println();
}
}// /method
/**
* refresh ... to point to list of other pads.
*
* @param padFile which pad file to patch, the mother or the distributed.
* @param tag start tag tag block to eliminate.
*/
private static void eliminateBlockInPadFile( final File padFile, final String tag )
{
// presume hasZip
try
{
if ( !padFile.exists() )
{
err.println( "eliminateBlockInPadFile: missing padFile: " + padFile.toString() );
return;
}
final String original = HunkIO.readEntireFile( padFile );
String big = original;
final String startTag = "<" + tag + ">";
final String endTag = "" + tag + ">";
int start;
while ( ( start = big.indexOf( startTag ) ) >= 0 )
{
// get rid of all old copies of the block
final int end = big.indexOf( endTag, start + startTag.length() );
if ( end < 0 )
{
err.println( "eliminateBlockInPadFile: missing end tag " + endTag + " in: " + padFile.toString() );
return;
}
final FastCat sb = new FastCat( 3 );
// if we don't also remove some NLs, there will be a blank line where we removed text.
sb.append( big.substring( 0, start ).trim() );
sb.append( _NL );
sb.append( big.substring( end + endTag.length() ).trim() );
big = sb.toString();
}
if ( !big.equals( original ) )
{
HunkIO.writeEntireFile( padFile, big );
}
}
catch ( IOException e )
{
err.println();
e.printStackTrace( err );
err.println( "eliminateBlockInPadFile: Unable to access: " + padFile.toString() );
err.println();
}
}// /method
/**
* fix affiliate tags i.e. stuff in ..
*
* @param padFile which pad file to patch, the mother or the distributed.
*/
private static void fixASPInPadFile( final File padFile )
{
// we are patching PML not XML so insert befor not
replaceBlockInPadFile( padFile, "ASP", ASP_TEXT, "/PADGEN_PML" );
}// /method
/**
* remove any affiliate tags i.e. stuff in ..
*
* @param padFile which pad file to patch, the mother or the distributed.
*/
private static void fixAffiliatesInPadFile( final File padFile )
{
eliminateBlockInPadFile( padFile, "Affiliates" );
}// /method
/**
* refresh ... to a standard
*
* @param padFile which pad file to patch, the mother or the distributed.
*/
private static void fixEulaInPadFile( final File padFile )
{
// already localised
replaceBlockInPadFile( padFile, "EULA", EULA_TEXT, "/Permissions" );
}// /method
/**
* correct PADGen removing OSes that support Java
*
* @param padFile which pad file to patch, the mother or the distributed.
*/
private static void fixProgramOSInPadFile( final File padFile )
{
try
{
String text = HunkIO.readEntireFile( padFile, HunkIO.UTF8 );
int start = text.indexOf( "" );
if ( start < 0 )
{
err.println( "fixProgramOSInPadFile: missing tag in " + padFile.toString() );
return;
}
start += "".length();
final int end = text.indexOf( "", start );
if ( end < 0 )
{
err.println( "fixProgramOSInPadFile: missing tag in " + padFile.toString() );
return;
}
// leave non-Java as is. Patch Java to a standard set.
final String oldOsSupport = text.substring( start, end );
if ( oldOsSupport.contains( "Java" ) )
{
replaceBlockInPadFile( padFile,
"Program_OS_Support",
Localise.localise( CORRECT_OS_SUPPORT ),
"Program_Language" );
}
}
catch ( IOException e )
{
err.println();
e.printStackTrace( err );
err.println( "fixProgramOSInPadFile: Unable to access " + padFile.toString() );
err.println();
}
}// /method
/**
* get company info to construct xxx.xml pad file from *.cml and *.pml file
*
* @return localised company info
*/
private static String getCompanyPadInfo()
{
File cmlFile = new File( "C:/Users/Roedy/Documents/PADGen/canadian_mind_products/canadian_mind_products.cml" );
try
{
String cmlContents = HunkIO.readEntireFile( cmlFile );
// we don't need lead crap
//
//
// PADGen 3.1.0.41
// need starting at
// or trailing
int begin = cmlContents.indexOf( "" );
if ( begin < 0 )
{
err.println( "cmlFile corrupted " + cmlFile.toString() );
return "";
}
int end = cmlContents.lastIndexOf( "" );
if ( end < 0 )
{
err.println( "cmlFile corrupted " + cmlFile.toString() );
return "";
}
return cmlContents.substring( begin, end ).trim() + _NL;
}
catch ( IOException e )
{
err.println();
e.printStackTrace( err );
err.println( "getCompanyPadInfo: Unable to access " + cmlFile.toString() );
err.println();
return "";
}
}// /method
/**
* refresh/insert text between two tags in the PAD.
*
* @param padFile which pad file to patch, the mother or the distributed.
* @param tag Tag block to insert without <> or lead /
* @param replacementText block without surrounding ... to replace current block inside tags.
* Includes CrLf line breaks.
* @param justBeforeTag insert this block just before this tag without <> with possible lead / e.g.
* "/XML_DIZ_INFO"
*/
private static void replaceBlockInPadFile( final File padFile, final String tag, final String replacementText,
String justBeforeTag )
{
// presume hasZip
try
{
if ( !padFile.exists() )
{
err.println( "replaceBlockInPadFile missing padFile " + padFile.toString() );
return;
}
final String original = HunkIO.readEntireFile( padFile );
String big = original;
final String startTag = "<" + tag + ">";
final String endTag = "" + tag + ">";
justBeforeTag = "<" + justBeforeTag + ">";
int start;
while ( ( start = big.indexOf( startTag ) ) >= 0 )
{
// get rid of all old copies of the block everything from ...
final int end = big.indexOf( endTag, start + startTag.length() );
if ( end < 0 )
{
err.println( "replaceBlockInPadFile: missing end tag " + endTag + " in: " + padFile.toString() );
return;
}
big = big.substring( 0, start ).trim() + big.substring( end + endTag.length() ).trim();
}
// insert just before final etc tag.
final int insertAt = big.lastIndexOf( justBeforeTag );
if ( insertAt < 0 )
{
err.println( "replaceBlockInPadFile: Missing " + justBeforeTag + " in: " + padFile.toString() );
return;
}
final FastCat sb = new FastCat( 7 );
sb.append( big.substring( 0, insertAt ) );
sb.append( _NL );
sb.append( startTag );
sb.append( replacementText );
sb.append( endTag );
sb.append( _NL );
sb.append( big.substring( insertAt ) );
big = sb.toString();
if ( !big.equals( original ) )
{
HunkIO.writeEntireFile( padFile, big );
}
}
catch ( IOException e )
{
err.println();
e.printStackTrace( err );
err.println( "replaceBlockInPadFile: Unable to access: " + padFile.toString() );
err.println();
}
}// /method
/**
* construct xxx.xml pad file from *.cml and *.pml file. Requires PADGen
* includes extensions
*/
private void constructPadFile()
{
final FastCat sb = new FastCat( 35 );
sb.append( PAD_HEADER );
// include company info from *.cml file
sb.append( companyPadInfo ); // already localised
// site extension
sb.append( "" );
sb.append( _NL );
sb.append( SITE_TEXT ); // already localised
sb.append( "" );
sb.append( _NL );
// include guts from *.pml
sb.append( getAppPadInfo() ); // already localised
// extension NewsFeed
sb.append( "" );
sb.append( _NL );
sb.append( NEWSFEED_TEXT ); // already localised
sb.append( "" );
sb.append( _NL );
// extensions PADmap
sb.append( "" );
sb.append( _NL );
sb.append( PADMAP_TEXT ); // already localised
sb.append( "" );
sb.append( _NL );
// extension PADRING
sb.append( "" );
sb.append( _NL );
sb.append( PADRING_TEXT_LIST_OF_URLS ); // already localised
sb.append( "" );
sb.append( _NL );
sb.append( "" );
sb.append( _NL );
sb.append( PADTUBE_TEXT ); // already localised
sb.append( "" );
sb.append( _NL );
sb.append( "" );
sb.append( _NL );
final File xmlFile = getPADXmlFile();
try
{
// already localised
HunkIO.writeEntireFile( xmlFile, sb.toString(), HunkIO.UTF8 );
}
catch ( IOException e )
{
err.println();
e.printStackTrace( err );
err.println( "constructPadFile: Unable to create: " + xmlFile.toString() );
err.println();
}
}// /method
/**
* repair/update files for project, rather than regenerate them.
* Repair PML, not XML version.
*/
void fixAllPads()
{
if ( padType == PAD311 )
{
// for PAD 3.10 only, rebild pad from various pieces
final File pmlFile = getPADPmlFile();
// there might be space or not before ?>
checkPADIntact( "", pmlFile );
// we fix up the PADGen masters, not just the generated *.xml
fixAffiliatesInPadFile( pmlFile );
fixASPInPadFile( pmlFile );
fixProgramOSInPadFile( pmlFile );
fixZipSizeInPadFile( pmlFile );
fixEulaInPadFile( pmlFile );
constructPadFile();
// no longer support pad.html
}
}// /method
/**
* make sure correct version and release exists in pad *.xml
*
* @param padFile which pad file to patch, the mother or the distributed.
*/
private void fixZipSizeInPadFile( final File padFile )
{
final File distribFile = new File( "E:/mindprod/zips/" + projectLower + versionTimesTen + ".zip" );
if ( !distribFile.exists() )
{
err.println( "fixZipSizeInPadFile: missing distributable " + distribFile.toString() );
return;
}
// round to near nearest even multiple so published number stays reasonably stable
// to avoid unnecessary Subversion commits or PAD file update emails.
final long zipSizeInBytes = distribFile.length();
if ( !padFile.exists() )
{
err.println( "fixZipSizeInPadFile: missing padFile " + padFile.toString() );
return;
}
try
{
final String text = HunkIO.readEntireFile( padFile, HunkIO.UTF8 );
final int pbStart = text.indexOf( "" );
if ( pbStart < 0 )
{
err.println( "fixZipSizeInPadFile: missing " );
return;
}
final int pbEnd = text.indexOf( "", pbStart + "".length() );
if ( pbEnd < 0 )
{
err.println( "fixZipSizeInPadFile: missing " );
return;
}
final int pkStart = text.indexOf( "", pbEnd + "".length() );
if ( pkStart < 0 )
{
err.println( "fixZipSizeInPadFile: missing " );
return;
}
final int pkEnd = text.indexOf( "", pkStart + "".length() );
if ( pkEnd < 0 )
{
err.println( "fixZipSizeInPadFile: missing " );
return;
}
final int pmStart = text.indexOf( "", pkEnd + "".length() );
if ( pmStart < 0 )
{
err.println( "fixZipSizeInPadFile: missing " );
return;
}
final int pmEnd = text.indexOf( "", pbStart + "".length() );
if ( pmEnd < 0 )
{
err.println( "fixZipSizeInPadFile: missing " );
return;
}
// found all the pieces, build a new section file from the pieces
final FastCat sb = new FastCat( 7 );
sb.append( text.substring( 0, pbStart + "".length() ) );
sb.append( zipSizeInBytes / 1024 * 1024 /* truncated to nearest k */ );
sb.append( text.substring( pbEnd, pkStart + "".length() ) );
sb.append( zipSizeInBytes / 1024 ); // truncated to K
sb.append( text.substring( pkEnd, pmStart + "".length() ) );
sb.append( padMBFormat.format( zipSizeInBytes / 1048576d )/* rounded MB with two fractional digits */ );
sb.append( text.substring( pmEnd ) );
HunkIO.writeEntireFile( padFile, sb.toString(), HunkIO.UTF8 ); // already localised
}
catch ( IOException e )
{
err.println();
e.printStackTrace( err );
err.println( "fixZipSizeInPadFile: Unable to access " + padFile.toString() );
err.println();
}
}// /method
/**
* get company info to construct xxx.xml pad file from *.cml and *.pml file
*
* @return get the body of the pad file, the info about the program
*/
private String getAppPadInfo()
{
final File pmlFile = getPADPmlFile();
try
{
String pmlContents = HunkIO.readEntireFile( pmlFile );
//
//
// PADGen 3.1.0.41
// or
// starting with
// don't need trailing
int begin = pmlContents.indexOf( "" );
if ( begin < 0 )
{
err.println( "pmlFile corrupted " + pmlFile.toString() );
return "";
}
int end = pmlContents.lastIndexOf( "" );
if ( end < 0 )
{
err.println( "pmlFile corrupted " + pmlFile.toString() );
return "";
}
return pmlContents.substring( begin, end ).trim() + _NL;
}
catch ( IOException e )
{
err.println();
e.printStackTrace( err );
err.println( "getAppPadInfo: Unable to access " + pmlFile.toString() );
err.println();
return "";
}
}// /method
// /methods
}