[brailleblaster] Re: Example of Executing a Command-line program from Java

  • From: "qubit" <lauraeaves@xxxxxxxxx>
  • To: <brailleblaster@xxxxxxxxxxxxx>
  • Date: Thu, 16 Dec 2010 14:05:46 -0600

Hi John --
have you tested it? It looks good actually.
I am glad to hear your server is back up.  If I had had access to linux I 
probably would have used a different approach, as I would have had occasion 
to test my code.
More as time goes on.
Thanks.
--le

----- Original Message ----- 
From: "John J. Boyer" <john.boyer@xxxxxxxxxxxxxxxxx>
To: <brailleblaster@xxxxxxxxxxxxx>
Sent: Thursday, December 16, 2010 8:51 AM
Subject: [brailleblaster] Example of Executing a Command-line program from 
Java


First, my server is back up. We're tying up the loose ends.

Below is the Odt2Braille.java class from the odt2braille plugin for
OpenOffi e. It calls xml2brl with RunTime.exec We could easily modify it
to call file2brl

Because of the server problems I haven't yet read the tutorial that
Susan suggested. What do you think of the following? Search for the word
execute to find the method that does the actual work.

----------------------

/**
 *  odt2braille - Braille authoring in OpenOffice.org.
 *
 *  Copyright (c) 2010 by DocArch <http://www.docarch.be>.
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

package be.docarch.odt2braille;

import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.BufferedWriter;
import java.io.Writer;
import java.io.FileWriter;
import java.util.logging.Logger;
import java.util.logging.Level;
import java.io.File;
import java.util.ArrayList;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.Element;
import org.w3c.dom.DOMImplementation;
import org.w3c.dom.ProcessingInstruction;
import java.io.FileInputStream;
import org.apache.commons.io.IOUtils;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.Locale;
import java.util.ResourceBundle;
import javax.xml.namespace.NamespaceContext;
import net.sf.saxon.TransformerFactoryImpl;
import javax.xml.transform.Transformer;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;
import javax.xml.transform.OutputKeys;

import javax.xml.parsers.ParserConfigurationException;
import java.io.IOException;
import org.xml.sax.SAXException;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerException;

import com.versusoft.packages.jodl.OdtUtils;
import org_pef_text.AbstractTable;
import org_pef_text.TableFactory;
import org_pef_text.TableFactory.TableType;


/**
 * This class provides a way to convert a flat .odt file to a
 * <a 
href="http://www.daisy.org/projects/braille/braille_workarea/pef.html";>.pef 
(portable embosser format)</a> file.
 * The conversion is done according to previously defined braille {@link 
Settings}.
 * <code>liblouisxml</code> is used for the actual transcription to braille.
 * A {@link Checker} checks the resulting braille document for possible 
accessibility issues.
 *
 * @see <a 
href="http://code.google.com/p/liblouisxml/";><code>liblouisxml</code></a>
 * @author Bert Frees
 */
public class Odt2Braille {

    private final static Logger logger = 
Logger.getLogger("be.docarch.odt2braille.addone");
    private static NamespaceContext namespace = new 
Odt2BrailleNamespaceContext();

    private final static boolean IS_WINDOWS = 
System.getProperty("os.name").toLowerCase().contains("windows");
    private static final String LIBLOUIS_EXEC_NAME = "xml2brl";
    private final static String LIBLOUIS_EXEC_EXT = IS_WINDOWS?".exe":"";

    private static final String TMP_NAME = "odt2braille";
    private final static String DAISY_EXT = ".xml";
    private final static String BRAILLE_EXT = ".txt";
    private final static String CONFIG_EXT = ".cfg";

    public enum TranscribersNote { IMAGES_NOT_REPRODUCED };

    public enum VolumeType { NORMAL,
                             PRELIMINARY,
                             SUPPLEMENTARY,
                             NONE };

    private static String L10N_statusIndicatorStep = null;

    private String liblouisDirUrl = null;
    private String brailleUrl = null;
    private String daisyUrl = null;

    private File brailleFile = null;
    private File daisyFile = null;
    private File stylesFile = null;
    private File chardefsFile = null;
    private File tempChardefsFile = null;

    private Odt2Daisy odt2daisy;
    private Settings settings = null;
    private StatusIndicator statusIndicator = null;
    private Checker checker = null;

    private ArrayList configurationList = new ArrayList();

    AbstractTable liblouisTable = new 
TableFactory().newTable(TableType.LIBLOUIS);

    /**
     * Creates a new <code>Odt2Braille</code> instance.
     * The {@link Locale} for the user interface is set to the default 
value.
     *
     * @param flatOdtFile       The "flat XML" .odt file.
     *                          This single file is the concatenation of all 
XML files in a normal .odt file.
     * @param liblouisDirUrl    The URL of the <code>liblouis</code> 
executable.
     * @param settings          The <code>Settings</code> that determine how 
the conversion is done.
     * @param statusIndicator   The <code>StatusIndicator</code> that will 
be used.
     * @param checker           The <code>Checker</code> that will check the 
braille document for possible accessibility issues.
     * @param odtLocale         The <code>Locale</code> for the document.
     */
    public Odt2Braille(File flatOdtFile,
                       String liblouisDirUrl,
                       Settings settings,
                       StatusIndicator statusIndicator,
                       Checker checker,
                       Locale odtLocale)
                throws IOException,
                       ParserConfigurationException,
                       SAXException,
                       TransformerConfigurationException,
                       TransformerException{

        this(flatOdtFile, liblouisDirUrl, settings, statusIndicator, 
checker, odtLocale, Locale.getDefault());

    }

    /**
     * Creates a new <code>Odt2Braille</code> instance.
     *
     * @param flatOdtFile       The "flat XML" .odt file.
     *                          This single file is the concatenation of all 
XML files in a normal .odt file.
     * @param liblouisDirUrl    The URL of the liblouis executable. liblouis 
is used for the actual transcription to braille.
     * @param statusIndicator   The <code>StatusIndicator</code> that will 
be used.
     * @param settings          The <code>Settings</code> that determine how 
the conversion is done.
     * @param checker           The <code>Checker</code> that will check the 
braille document for possible accessibility issues.
     * @param odtLocale         The <code>Locale</code> for the document.
     * @param oooLocale         The <code>Locale</code> for the user 
interface.
     */
    public Odt2Braille(File flatOdtFile,
                       String liblouisDirUrl,
                       Settings settings,
                       StatusIndicator statusIndicator,
                       Checker checker,
                       Locale odtLocale,
                       Locale oooLocale)
                throws IOException,
                       ParserConfigurationException,
                       SAXException,
                       TransformerConfigurationException,
                       TransformerException {

        logger.entering("Odt2Braille", "<init>");

        this.settings = settings;
        this.liblouisDirUrl = liblouisDirUrl;
        this.statusIndicator = statusIndicator;
        this.checker = checker;

        L10N_statusIndicatorStep = 
ResourceBundle.getBundle("be/docarch/odt2braille/l10n/Bundle", 
oooLocale).getString("statusIndicatorStep");

        // Request temporary liblouisxml braille file
        brailleFile = File.createTempFile(TMP_NAME,BRAILLE_EXT);
        brailleFile.deleteOnExit();
        brailleUrl = brailleFile.getAbsolutePath();

        // Request temporary daisy xml file
        daisyFile = File.createTempFile(TMP_NAME,DAISY_EXT);
        daisyFile.deleteOnExit();
        daisyUrl = daisyFile.getAbsolutePath();

        // Create odt2daisy
        odt2daisy = new Odt2Daisy(flatOdtFile, settings, 
this.statusIndicator, odtLocale, oooLocale);
        odt2daisy.preProcessing();

        chardefsFile = new File(liblouisDirUrl + "share"    + 
System.getProperty("file.separator")
                                               + "liblouis" + 
System.getProperty("file.separator")
                                               + "tables"   + 
System.getProperty("file.separator")
                                               + "_chardefs.cti");
        tempChardefsFile = File.createTempFile(TMP_NAME, ".xml");
        tempChardefsFile.deleteOnExit();
        stylesFile = File.createTempFile(TMP_NAME,CONFIG_EXT);
        stylesFile.deleteOnExit();
        createStylesFile();

    }

    private void createStylesFile() throws IOException {

        logger.entering("Odt2Braille", "createStylesFile");

        // Create temporary styles file

        Writer bufferedWriter = new BufferedWriter(new 
FileWriter(stylesFile));
        String sep = System.getProperty("line.separator");
        String s = null;

        // Paragraphs

        s = "firstLineIndent " + (settings.getFirstLineMargin("paragraph") - 
settings.getRunoversMargin("paragraph")) + sep
          + "leftMargin "      + settings.getRunoversMargin("paragraph") + 
sep
          + "linesBefore "     + settings.getLinesAbove("paragraph") + sep
          + "linesAfter "      + settings.getLinesBelow("paragraph") + sep
          + "format "          + 
(settings.getCentered("paragraph")?"centered":"leftJustified") + sep;
        bufferedWriter.write("style para" + sep + s);

        // Headings

        for (int i=1;i<=4;i++) {
            s = "firstLineIndent " + (settings.getFirstLineMargin("heading" 
+ i) - settings.getRunoversMargin("heading" + i)) + sep
              + "leftMargin "      + settings.getRunoversMargin("heading" + 
i) + sep
              + "linesBefore "     + 0 + sep
              + "linesAfter "      + 0 + sep
              + "format "          + (settings.getCentered("heading" + 
i)?"centered":"leftJustified") + sep;
            bufferedWriter.write("style heading" + i + sep + s);
            bufferedWriter.write("style dummyheading" + i + sep + s);
            s = "linesBefore "     + settings.getLinesAbove("heading" + i) + 
sep
              + "linesAfter "      + settings.getLinesBelow("heading" + i) + 
sep;
            bufferedWriter.write("style heading" + i + "container" + sep + 
s);
        }

        // Lists

        for (int i=1;i<=10;i++) {
            s = "linesBefore "     + settings.getLinesAbove("list" + i) + 
sep
              + "linesAfter "      + settings.getLinesBelow("list" + i) + 
sep;
            bufferedWriter.write("style list" + i + sep + s);
            s = "linesAfter "      + settings.getLinesBetween("list" + i) + 
sep;
            bufferedWriter.write("style li" + i + sep + s);
            s = "firstLineIndent " + (settings.getFirstLineMargin("list" + 
i) - settings.getRunoversMargin("list" + i)) + sep
              + "leftMargin "      + settings.getRunoversMargin("list" + i) 
+ sep
              + "format "          + (settings.getCentered("list" + 
i)?"centered":"leftJustified") + sep;
            bufferedWriter.write("style listitem" + i + sep + s);
        }

        for (int i=2;i<=10;i++) {
            s = "linesBefore "     + settings.getLinesAbove("list" + i) + 
sep;
            bufferedWriter.write("style lastlist" + i + sep + s);
        }

        // Tables

        s = "linesBefore "     + settings.getLinesAbove("table") + sep
          + "linesAfter "      + settings.getLinesBelow("table") + sep;
        bufferedWriter.write("style tablenoborder" + sep + s);
        bufferedWriter.write("style lasttablerow" + sep);

        if (settings.stairstepTableIsEnabled()) {

            for (int i=1;i<=10;i++) {
                s = "firstLineIndent " + 
(settings.getFirstLineMargin("table" + i) - 
settings.getRunoversMargin("table" + i)) + sep
                  + "leftMargin "      + settings.getRunoversMargin("table" 
+ i) + sep
                  + "format "          + (settings.getCentered("table" + 
i)?"centered":"leftJustified") + sep;
                bufferedWriter.write("style tablecolumn" + i + sep + s);
            }

            s = "";
        } else {
            s = "firstLineIndent " + (settings.getFirstLineMargin("table") - 
settings.getRunoversMargin("table")) + sep
              + "leftMargin "      + settings.getRunoversMargin("table") + 
sep
              + "format "          + 
(settings.getCentered("table")?"centered":"leftJustified") + sep;
            bufferedWriter.write(s);
        }

        s += "linesAfter "      + settings.getLinesBetween("table") + sep;
        bufferedWriter.write("style tablerow" + sep + s);

        // Pagenumbers

        bufferedWriter.write("style document"    + sep + 
"braillePageNumberFormat " + (settings.getBraillePageNumbers()?"normal": 
"blank")  + sep);
        bufferedWriter.write("style preliminary" + sep + 
"braillePageNumberFormat " + 
(settings.getBraillePageNumbers()?settings.getPreliminaryPageFormat():"blank") 
+ sep);

        // Table of contents

        s = "firstLineIndent " + (settings.getFirstLineMargin("heading1") - 
settings.getRunoversMargin("heading1")) + sep
          + "leftMargin "      + settings.getRunoversMargin("heading1") + 
sep
          + "linesBefore "     + settings.getLinesAbove("heading1") + sep
          + "linesAfter "      + settings.getLinesBelow("heading1") + sep
          + "format "          + 
(settings.getCentered("heading1")?"centered":"leftJustified") + sep;
        bufferedWriter.write("style contentsheader" + sep + s);

        for (int i=1;i<=4;i++) {
            s = "firstLineIndent " + (settings.getFirstLineMargin("toc" + 
i) - settings.getRunoversMargin("toc" + i)) + sep
              + "leftMargin "      + settings.getRunoversMargin("toc" + i) + 
sep
              /* + "linesAfter "       + settings.getLinesBetween("toc") + 
sep */
              + "format "          + "contents" + sep;
            bufferedWriter.write("style contents" + i + sep + s);
        }

        bufferedWriter.close();

        logger.exiting("Odt2Braille", "createStylesFile");

    }

    private void createChardefsFile(File daisyFile) throws IOException,
                                                           
TransformerConfigurationException,
                                                           TransformerException 
{

        logger.entering("Odt2Braille", "createChardefsFile");

        File newChardefsFile = File.createTempFile(TMP_NAME, ".cti");
        TransformerFactoryImpl tFactory = new 
net.sf.saxon.TransformerFactoryImpl();
        Transformer unicodeBlocksTransformer = tFactory.newTransformer(new 
StreamSource(getClass().getResource("/be/docarch/odt2braille/unicodeblocks.xsl").toString()));
        Writer bufferedWriter = new BufferedWriter(new 
FileWriter(newChardefsFile));

        unicodeBlocksTransformer.setOutputProperty(OutputKeys.ENCODING, 
"UTF-8");
        unicodeBlocksTransformer.setOutputProperty(OutputKeys.METHOD, 
"xml");
        unicodeBlocksTransformer.setOutputProperty(OutputKeys.INDENT, 
"yes");
        
unicodeBlocksTransformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount";,
 
"3");
        unicodeBlocksTransformer.transform(new StreamSource(daisyFile), new 
StreamResult(tempChardefsFile));

        bufferedWriter.write("include 
_chardefs_unicode_BRAILLE_PATTERNS.cti"   + 
System.getProperty("line.separator")  // First table should be 
BRAILLE_PATTERNS
                           + "include _chardefs_unicode_BASIC_LATIN.cti" 
+ System.getProperty("line.separator")
                           + "include 
_chardefs_unicode_LATIN_1_SUPPLEMENT.cti" + 
System.getProperty("line.separator")
                           + "include 
_chardefs_unicode_PRIVATE_USE_AREA.cti"   + 
System.getProperty("line.separator"));

        String s = null;
        for (int i=1; 
i<=XPathUtils.evaluateNumber(tempChardefsFile.toURL().openStream(), 
"count(/unicodeblocks/block)"); i++) {
            s = 
XPathUtils.evaluateString(tempChardefsFile.toURL().openStream(), 
"/unicodeblocks/block[" + i + "]/@name");
            if (s != null) {
                s = "include _chardefs_unicode_" + s + ".cti";
                bufferedWriter.write(s + 
System.getProperty("line.separator"));
                logger.log(Level.INFO, s);
            }
        }

        bufferedWriter.close();
        if (chardefsFile.exists()) { chardefsFile.delete(); }
        newChardefsFile.renameTo(chardefsFile);

        logger.exiting("Odt2Braille", "createChardefsFile");

    }

    /**
     * Converts the flat .odt filt to a .pef file according to the braille 
settings.
     *
     * This function
     * <ul>
     * <li>makes calls to {@link Odt2Daisy}.<code>convertAsDTBook</code> to 
convert the .odt file to multiple DAISY-like xml files,</li>
     * <li>uses <code>liblouisxml</code> to translate these files into 
braille, and</li>
     * <li>recombines these braille files into one single .pef file.</li>
     * </ul>
     *
     * First, the document <i>body</i> is processed and split in volumes, 
then the <i>page ranges</i> are calculated
     * and finally the <i>preliminary pages</i> of each volume are processed 
and inserted at the right places.
     * The checker checks the DAISY-like files and the volume lengths.
     *
     * When a multi-volume feature is added to liblouisxml, this procedure 
of pef-creation might be simplified a lot.
     *
     * @param pefUrl  The URL of the .pef file.
     */
    public boolean makePEF(String pefUrl)
                    throws IOException,
                           ParserConfigurationException,
                           TransformerConfigurationException,
                           TransformerException,
                           InterruptedException,
                           LiblouisException {

        logger.entering("Odt2Braille", "makePEF");

        VolumeType[] volumeTypes = new 
VolumeType[(settings.preliminaryVolumeEnabled?1:0) +
                                                  
Math.max(1,settings.NUMBER_OF_VOLUMES) 
+
                                                  
settings.NUMBER_OF_SUPPLEMENTS];
        ArrayList<SpecialSymbol> specialSymbolsList = 
settings.getSpecialSymbolsList();

        DocumentBuilderFactory docFactory;
        DocumentBuilder docBuilder;
        Document document;
        Element headElement;
        Element dcElement;
        Element bodyElement;
        Element[] volumeElements = new Element[volumeTypes.length];
        Element sectionElement;
        Element pageElement;
        Element rowElement;
        Node node;
        ProcessingInstruction pi;
        BufferedReader bufferedReader = null;
        FileInputStream fileInputStream = null;
        InputStreamReader inputStreamReader = null;
        String brfInput = null;
        String line = null;

        int lineCount;
        int pageCount;
        int volumeCount;
        boolean cont;
        Matcher matcher;
        char ch;

        int volumeNr;
        boolean extractpprangemode;
        boolean allVolumes;
        boolean body;
        boolean front;
        int beginPage;
        int endPage;
        int prelPages;

        int[] bodyPageCount = new int[volumeTypes.length];
        int[] preliminaryPageCount = new int[volumeTypes.length];
        String[] beginPrintPages = new String[volumeTypes.length];
        String[] endPrintPages = new String[volumeTypes.length];
        boolean[][] specialSymbolsPresent = new 
boolean[volumeTypes.length][specialSymbolsList.size()];
        boolean[][] transcribersNotesEnabled = new 
boolean[volumeTypes.length][TranscribersNote.values().length];

        // Initialization

        for (int i=1;i<=volumeTypes.length;i++) {
            if (i-(settings.preliminaryVolumeEnabled?1:0)==0) {
                volumeTypes[i-1] = VolumeType.PRELIMINARY;
            } else if (i-(settings.preliminaryVolumeEnabled?1:0) > 
Math.max(1,settings.NUMBER_OF_VOLUMES)) {
                volumeTypes[i-1] = VolumeType.SUPPLEMENTARY;
            } else {
                volumeTypes[i-1] = VolumeType.NORMAL;
            }
            bodyPageCount[i-1] = 0;
            preliminaryPageCount[i-1] = 0;
            for (int j=1;j<=specialSymbolsPresent[0].length;j++) {
                specialSymbolsPresent[i-1][j-1] = false;
            }
            for (int j=1;j<=TranscribersNote.values().length;j++) {
                transcribersNotesEnabled[i-1][j-1] = false;
            }
        }

        try {

            docFactory = DocumentBuilderFactory.newInstance();
            docFactory.setValidating(false);
            docBuilder = docFactory.newDocumentBuilder();
            DOMImplementation impl = docBuilder.getDOMImplementation();

            document = 
impl.createDocument("http://www.daisy.org/ns/2008/pef";, "pef", null);
            Element root = document.getDocumentElement();
            root.setAttributeNS(null,"version","2008-1");

            headElement = 
document.createElementNS("http://www.daisy.org/ns/2008/pef","head";);
            headElement.setAttributeNS("http://www.w3.org/2000/xmlns/";, 
"xmlns:dc", "http://purl.org/dc/elements/1.1/";);
            dcElement = 
document.createElementNS("http://purl.org/dc/elements/1.1/","dc:identifier";);
            node = document.createTextNode("00001");
            dcElement.appendChild(node);
            headElement.appendChild(dcElement);
            dcElement = 
document.createElementNS("http://purl.org/dc/elements/1.1/","dc:format";);
            node = document.createTextNode("application/x-pef+xml");
            dcElement.appendChild(node);
            headElement.appendChild(dcElement);

            root.appendChild(headElement);

            // BODY: Split into volumes and extract page ranges

            allVolumes = true; // all volumes
            body = true;   // only body
            front = false; // no front
            beginPage = 1;
            endPage = 0;   // not relevant
            prelPages = 0;  // not relevant
            volumeNr = 0;  // not relevant
            extractpprangemode = false;

            if (!odt2daisy.convertAsDTBook(daisyUrl, allVolumes, volumeNr, 
VolumeType.NONE, body, front, beginPage, endPage, prelPages, null, null, 
null, null)) {
                return false;
            }
            checker.checkDaisyFile(daisyFile);
            configureLiblouisxml(extractpprangemode, beginPage);
            runLiblouisxml();

            fileInputStream = new FileInputStream(brailleFile);
            inputStreamReader = new 
InputStreamReader(fileInputStream,"UTF-8");
            bufferedReader = new BufferedReader(inputStreamReader);

            statusIndicator.setSteps(1 + 
(settings.PRELIMINARY_PAGES_PRESENT?volumeElements.length:0));
            statusIndicator.reset();
            statusIndicator.setStatus(L10N_statusIndicatorStep);

            for (volumeCount = 1;volumeCount <= 
volumeElements.length;volumeCount++) {

                logger.log(Level.INFO,"Processing body of volume " + 
volumeCount + "/" + volumeElements.length);

                volumeElements[volumeCount-1] = 
document.createElementNS("http://www.daisy.org/ns/2008/pef","volume";);
                
volumeElements[volumeCount-1].setAttributeNS(null,"cols",String.valueOf(settings.getNumberOfCellsPerLine()));
                
volumeElements[volumeCount-1].setAttributeNS(null,"rows",String.valueOf(settings.getNumberOfLinesPerPage()));
                volumeElements[volumeCount-1].setAttributeNS(null,"rowgap","0");
                
volumeElements[volumeCount-1].setAttributeNS(null,"duplex",settings.isDuplex()?"true":"false");

                if (volumeTypes[volumeCount-1] == VolumeType.PRELIMINARY) {

                    bodyPageCount[volumeCount-1] = 0;

                } else {

                    sectionElement = 
document.createElementNS("http://www.daisy.org/ns/2008/pef","section";);

                    cont = true;
                    pageCount = 1;

                    while (cont) {

                        pageElement = 
document.createElementNS("http://www.daisy.org/ns/2008/pef","page";);

                        lineCount = 1;

                        while (lineCount <= 
settings.getNumberOfLinesPerPage()) {

                            line = bufferedReader.readLine();
                            /* WINDOWS */ bufferedReader.readLine();
                            if (line.contains("\uE000")) {
                                line = line.replaceAll("\uE000"," ");
                                cont = false;
                                bodyPageCount[volumeCount-1] = pageCount;
                            }
                            line = line.replaceAll("\u00a0", " ");
                            rowElement = 
document.createElementNS("http://www.daisy.org/ns/2008/pef","row";);
                            node = 
document.createTextNode(liblouisTable.toBraille(line));
                            rowElement.appendChild(node);
                            pageElement.appendChild(rowElement);

                            lineCount++;

                        }
                        sectionElement.appendChild(pageElement);
                        bufferedReader.skip(1); // skip '\f'
                        pageCount++;

                    }
                    volumeElements[volumeCount-1].appendChild(sectionElement);

                }
            }

            statusIndicator.increment();

            if (bufferedReader != null) {
                bufferedReader.close();
                inputStreamReader.close();
                fileInputStream.close();
            }

            // Print page ranges

            String s;
            volumeNr = 0;
            for (volumeCount = 1;volumeCount <= 
specialSymbolsPresent.length;volumeCount++) {
                if (volumeTypes[volumeCount-1]!=VolumeType.PRELIMINARY) {
                    volumeNr++;

                    if 
(XPathUtils.evaluateBoolean(daisyFile.toURL().openStream(),
                                        "//dtb:div[@class='volume'][" + 
volumeNr + "]/dtb:div[@class='not-in-volume']" +
                                        
"/following::*[not(self::dtb:pagebreak)][1][self::dtb:pagenum]", 
namespace)) {
                        s = 
XPathUtils.evaluateString(daisyFile.toURL().openStream(),
                                        "//dtb:div[@class='volume'][" + 
volumeNr + "]/dtb:div[@class='not-in-volume']" +
                                        
"/following::*[not(self::dtb:pagebreak)][1][self::dtb:pagenum]", 
namespace);
                    } else {
                        s = 
XPathUtils.evaluateString(daisyFile.toURL().openStream(),
                                        "//dtb:div[@class='volume'][" + 
volumeNr + "]/dtb:div[@class='not-in-volume']" +
                                        
"/following::*[1]/preceding::dtb:pagenum[1]", 
namespace);
                    }
                    if (s.equals("")){
                        if (settings.mergeUnnumberedPages) {
                            s = 
XPathUtils.evaluateString(daisyFile.toURL().openStream(),
                                        "//dtb:div[@class='volume'][" + 
volumeNr + "]/dtb:div[@class='not-in-volume']" +
                                        
"/following::*[1]/preceding::dtb:pagenum[text()][1]", 
namespace);
                        } else {
                            s = 
XPathUtils.evaluateString(daisyFile.toURL().openStream(),
                                        "//dtb:div[@class='volume'][" + 
volumeNr + "]" +
                                        "//dtb:pagenum[text() and 
not(ancestor::dtb:div[@class='not-in-volume'])][1]", namespace);
                        }
                    }
                    if (!s.equals("")){
                        beginPrintPages[volumeCount-1] = s;
                        s = 
XPathUtils.evaluateString(daisyFile.toURL().openStream(),
                                        "//dtb:div[@class='volume'][" + 
volumeNr + "]" +
                                        "//dtb:pagenum[text() and 
not(ancestor::dtb:div[@class='not-in-volume'])][last()]", namespace);
                        if (!(s.equals("") || 
s.equals(beginPrintPages[volumeCount-1]))) {
                            endPrintPages[volumeCount-1] = s;
                        }
                    }
                }
            }

            // LIST OF SPECIAL SYMBOLS: Determine which symbols to display

            if (settings.specialSymbolsListEnabled) {

                volumeNr = 0;
                for (volumeCount = 1;volumeCount <= 
specialSymbolsPresent.length;volumeCount++) {
                    if (volumeTypes[volumeCount-1]!=VolumeType.PRELIMINARY) 
{ volumeNr++; }
                    for (int 
i=0;i<specialSymbolsPresent[volumeCount-1].length;i++) {
                        switch (specialSymbolsList.get(i).getMode()) {
                            case NEVER:
                                break;
                            case ALWAYS:
                                specialSymbolsPresent[volumeCount-1][i] = 
true;
                                break;
                            case FIRST_VOLUME:
                                if (volumeCount == 1) { 
specialSymbolsPresent[volumeCount-1][i] = true; }
                                break;
                            case IF_PRESENT_IN_VOLUME:
                                if 
(volumeTypes[volumeCount-1]!=VolumeType.PRELIMINARY) {
                                    switch 
(specialSymbolsList.get(i).getType()) {
                                        case NOTE_REFERENCE_INDICATOR:
                                            
specialSymbolsPresent[volumeCount-1][i] 
= XPathUtils.evaluateBoolean(daisyFile.toURL().openStream(),
                                                "//dtb:div[@class='volume'][" 
+ volumeNr + "]//dtb:note[@class='footnote' or 
@class='endnote']",namespace);
                                            break;
                                        case TRANSCRIBERS_NOTE_INDICATOR:
                                            
specialSymbolsPresent[volumeCount-1][i] 
= XPathUtils.evaluateBoolean(daisyFile.toURL().openStream(),
                                                "//dtb:div[@class='volume'][" 
+ volumeNr + "]//dtb:div[@class='tn']/dtb:note",namespace);
                                            break;
                                        case ITALIC_INDICATOR:
                                            
specialSymbolsPresent[volumeCount-1][i] 
= XPathUtils.evaluateBoolean(daisyFile.toURL().openStream(),
                                                "//dtb:div[@class='volume'][" 
+ volumeNr + "]//dtb:em[not(@class='reset')]",namespace);
                                            break;
                                        case BOLDFACE_INDICATOR:
                                            
specialSymbolsPresent[volumeCount-1][i] 
= XPathUtils.evaluateBoolean(daisyFile.toURL().openStream(),
                                                "//dtb:div[@class='volume'][" 
+ volumeNr + "]//dtb:strong[not(@class='reset')]",namespace);
                                            break;
                                        case ELLIPSIS:
                                            
specialSymbolsPresent[volumeCount-1][i] 
= XPathUtils.evaluateBoolean(daisyFile.toURL().openStream(),
                                                "//dtb:div[@class='volume'][" 
+ volumeNr + "]//dtb:flag[@class='ellipsis']",namespace);
                                            break;
                                        case DOUBLE_DASH:
                                            
specialSymbolsPresent[volumeCount-1][i] 
= XPathUtils.evaluateBoolean(daisyFile.toURL().openStream(),
                                                "//dtb:div[@class='volume'][" 
+ volumeNr + "]//dtb:flag[@class='double-dash']",namespace);
                                            break;
                                        default:
                                    }
                                }
                                break;
                        }
                    }
                }
            }

            // TRANSCRIBER'S NOTE PAGES: Determine which notes to display

            if (settings.transcribersNotesPageEnabled) {

                for (volumeCount = 1;volumeCount <= 
transcribersNotesEnabled.length;volumeCount++) {

                    TranscribersNote[] transcribersNoteValues = 
TranscribersNote.values();

                    if (volumeTypes[volumeCount-1]!=VolumeType.PRELIMINARY) 
{
                        for (int i=0;i<transcribersNoteValues.length;i++) {
                            switch (transcribersNoteValues[i]) {

                                case IMAGES_NOT_REPRODUCED:
                                    transcribersNotesEnabled[volumeCount-1][i] 
= XPathUtils.evaluateBoolean(daisyFile.toURL().openStream(),
                                        "//dtb:div[@class='volume'][" + 
volumeCount + "]//dtb:div[@class='image']",namespace);
                                    break;
                                default:
                                    transcribersNotesEnabled[volumeCount-1][i] 
= false;
                            }
                        }
                    }
                }
            }

            // PRELIMINARY PAGES: Insert PP sections before body of volumes 
1,2,3,...

            if (settings.PRELIMINARY_PAGES_PRESENT) {

                beginPage = 0;
                endPage = 0;

                for (volumeCount = 1;volumeCount <= 
volumeElements.length;volumeCount++) {

                    logger.log(Level.INFO,"Processing preliminary pages of 
volume " + volumeCount + "/" + volumeElements.length);

                    sectionElement = 
document.createElementNS("http://www.daisy.org/ns/2008/pef","section";);

                    if (volumeCount > 1 && 
volumeTypes[volumeCount-1]==volumeTypes[volumeCount-2]) {
                        volumeNr ++;
                    } else {
                        volumeNr = 1;
                    }

                    allVolumes = false;
                    front = true;
                    body = (settings.tableOfContentEnabled && 
volumeTypes[volumeCount-1]!=VolumeType.SUPPLEMENTARY);
                    beginPage = endPage+1;
                    endPage = endPage + bodyPageCount[volumeCount-1];

                    // Determine page range

                    extractpprangemode = true;
                    prelPages = 0;  // not relevant

                    if (!odt2daisy.convertAsDTBook(daisyUrl, allVolumes, 
volumeNr, volumeTypes[volumeCount-1], body, front, beginPage, endPage, 
prelPages,
                                                   
beginPrintPages[volumeCount-1], 
endPrintPages[volumeCount-1],
                                                   
specialSymbolsPresent[volumeCount-1],transcribersNotesEnabled[volumeCount-1])) 
{
                        return false;
                    }
                    configureLiblouisxml(extractpprangemode, 
body?beginPage:1);
                    runLiblouisxml();

                    fileInputStream = new FileInputStream(brailleFile);
                    inputStreamReader = new 
InputStreamReader(fileInputStream,"UTF-8");
                    brfInput = IOUtils.toString(inputStreamReader);

                    matcher = 
Pattern.compile("(\f|\uE000)").matcher(brfInput);
                    pageCount = 1;

                    while (matcher.find()) {
                        ch = brfInput.charAt(matcher.start());
                        if (ch=='\f') {
                            pageCount ++;
                        } else {
                            if (settings.tableOfContentEnabled && 
volumeTypes[volumeCount-1]!=VolumeType.SUPPLEMENTARY) {
                                pageCount --;
                            }
                            break;
                        }
                    }

                    if (inputStreamReader != null) {
                        inputStreamReader.close();
                        fileInputStream.close();
                    }

                    // Extract preliminary pages

                    extractpprangemode = false;
                    prelPages = pageCount;
                    preliminaryPageCount[volumeCount-1] = prelPages;

                    if (!odt2daisy.convertAsDTBook(daisyUrl, allVolumes, 
volumeNr, volumeTypes[volumeCount-1], body, front, beginPage, endPage, 
prelPages,
                                                   
beginPrintPages[volumeCount-1], 
endPrintPages[volumeCount-1],
                                                   
specialSymbolsPresent[volumeCount-1],transcribersNotesEnabled[volumeCount-1])) 
{
                        return false;
                    }
                    checker.checkDaisyFile(daisyFile);
                    configureLiblouisxml(extractpprangemode, 
body?beginPage:1);
                    runLiblouisxml();

                    fileInputStream = new FileInputStream(brailleFile);
                    inputStreamReader = new 
InputStreamReader(fileInputStream,"UTF-8");
                    bufferedReader = new BufferedReader(inputStreamReader);

                    pageCount = 1;
                    while (pageCount <= prelPages) {

                        pageElement = 
document.createElementNS("http://www.daisy.org/ns/2008/pef","page";);

                        lineCount = 1;

                        while (lineCount <= 
settings.getNumberOfLinesPerPage()) {

                            line = bufferedReader.readLine();
                            /* WINDOWS */ bufferedReader.readLine();
                            line = line.replaceAll("\u00a0", " ");
                            rowElement = 
document.createElementNS("http://www.daisy.org/ns/2008/pef","row";);
                            node = 
document.createTextNode(liblouisTable.toBraille(line));
                            rowElement.appendChild(node);
                            pageElement.appendChild(rowElement);

                            lineCount++;

                        }
                        sectionElement.appendChild(pageElement);
                        bufferedReader.skip(1);
                        pageCount ++;
                    }

                    volumeElements[volumeCount-1].insertBefore(sectionElement, 
volumeElements[volumeCount-1].getFirstChild());

                    if ((!settings.tableOfContentEnabled || 
volumeTypes[volumeCount-1]==VolumeType.SUPPLEMENTARY) && 
!settings.volumeInfoEnabled && volumeCount>1) {
                        for 
(volumeCount=volumeCount+1;volumeCount<=volumeElements.length;volumeCount++) 
{
                            
volumeElements[volumeCount-1].insertBefore(sectionElement.cloneNode(true), 
volumeElements[volumeCount-1].getFirstChild());
                        }
                        break;
                    }

                    statusIndicator.increment();

                    if (bufferedReader != null) {
                        bufferedReader.close();
                        inputStreamReader.close();
                        fileInputStream.close();
                    }
                }

                statusIndicator.finish(true);

            }

            checker.checkVolumeLengths(bodyPageCount, preliminaryPageCount, 
volumeTypes);

            bodyElement = 
document.createElementNS("http://www.daisy.org/ns/2008/pef","body";);

            for (volumeCount = 
1;volumeCount<=volumeElements.length;volumeCount++) {
                bodyElement.appendChild(volumeElements[volumeCount-1]);
            }

            root.appendChild(bodyElement);

            pi = 
(ProcessingInstruction)document.createProcessingInstruction(
                    "xml-stylesheet","type='text/css' href='pef.css'");
            document.insertBefore(pi, document.getFirstChild());

            OdtUtils.saveDOM(document, pefUrl);

            logger.exiting("Odt2Braille","makePEF");

            return true;

        } finally {
            statusIndicator.finish(false);
            if (bufferedReader != null) {
                bufferedReader.close();
                inputStreamReader.close();
                fileInputStream.close();
            }
        }

    }

    /**
     * Execute the <code>xml2brl</code> program.
     * An xml-file is translated to a braille file.
     * Before executing, <code>liblouisxml</code> has to be configured.
     *
     * @see <a 
href="http://code.google.com/p/liblouisxml/";><code>liblouisxml</code></a>
     */
    private void runLiblouisxml() throws IOException,
                                         InterruptedException,
                                         LiblouisException {

        logger.entering("Odt2Braille","runLiblouisxml");

        Process process;
        Runtime runtime = Runtime.getRuntime();
        String exec_cmd[] = new String[configurationList.size()];

        configurationList.toArray(exec_cmd);

        int i;
        String message = null;
        String line = null;
        String errors = "";

        message = "liblouis:  ";
        for (i=0;i<exec_cmd.length;i++) {
            message += "\n               " + exec_cmd[i];
        }

        logger.log(Level.INFO,message);

        process = runtime.exec(exec_cmd);
        if (process.waitFor() != 0) {
            throw new LiblouisException("liblouisxml did not terminate 
correctly");
        }
        InputStream stderr = process.getErrorStream();
        InputStreamReader isr = new InputStreamReader(stderr);
        BufferedReader br = new BufferedReader(isr);

        while ((line = br.readLine()) != null) {
            errors += line + "\n";
        }

        if (isr != null) {
            isr.close();
            stderr.close();
        }

        logger.exiting("Odt2Braille","runLiblouisxml");

        if (!errors.equals("")) {
            throw new LiblouisException("liblouisxml error:  " + errors);
        }

    }

    /**
     * Configure the <code>xml2brl</code> program.
     * @see <a 
href="http://code.google.com/p/liblouisxml/";><code>liblouisxml</code></a>
     * <ul>
     * <li><code>literaryTextTable</code>, <code>printPages</code>, 
<code>cellsPerLine</code> and <code>linesPerPage</code>
     * are set according to the braille settings.</li>
     * <li>Depending on <code>extractpprangemode</code>, an additional 
semantic-action file is added to <code>semanticFiles</code>.</li>
     * <li><code>beginningPageNumber</code> is set to 
<code>beginPage</code>.</li>
     * </ul>
     *
     * @param   extractpprangemode  <code>true</code> if the braille output 
will be used to extract the page range of the preliminary section.
     * @param   beginPage           The first braille page number after this 
table of contents.
     *                              If no table of contents is rendered, 
<code>beginPage</code> is just the first braille page number.
     */
    private void configureLiblouisxml(boolean extractpprangemode,
                                      int beginPage)
                               throws TransformerConfigurationException,
                                      TransformerException,
                                      IOException {

        logger.entering("Odt2Braille","configureLiblouisxml");

        configurationList.clear();

        String math = settings.getMath().name().toLowerCase();

        String translationTable = "__" + 
settings.getTranslationTable(settings.getMainLanguage()) + "-g" + 
settings.getGrade(settings.getMainLanguage()) + ".ctb";
        String configFiles = stylesFile.getAbsolutePath() + "," +
                             "_config.cfg," +
                             "_styles.cfg";
        String semanticFiles = "_main.sem," +
                              
(extractpprangemode?"_extractpprangemode.sem,":"") 
+
                              
(settings.stairstepTableIsEnabled()?"_stairsteptable.sem,":"") 
+
                              "_" + math + ".sem";
        String mathTable = "__" + math + ".ctb";
        String editTables = "_edit_" + math + ".ctb";

        configurationList.add("\"" + liblouisDirUrl + "bin" + 
System.getProperty("file.separator") + LIBLOUIS_EXEC_NAME + 
LIBLOUIS_EXEC_EXT + "\"");
        configurationList.add("-f");
        configurationList.add(configFiles);

        configurationList.add("-C" + "literaryTextTable="            + 
translationTable);
        configurationList.add("-C" + "semanticFiles="                + 
semanticFiles);
        configurationList.add("-C" + "mathtextTable="                + 
translationTable);
        configurationList.add("-C" + "mathexprTable="                + 
mathTable);
        configurationList.add("-C" + "editTable="                    + 
editTables);
        configurationList.add("-C" + "lineFill="                     + 
liblouisTable.toText(settings.getLineFillSymbol()));
        configurationList.add("-C" + "beginningPageNumber="          + 
beginPage);
        configurationList.add("-C" + "cellsPerLine="                 + 
Integer.toString(settings.getNumberOfCellsPerLine()));
        configurationList.add("-C" + "linesPerPage="                 + 
Integer.toString(settings.getNumberOfLinesPerPage()));
        configurationList.add("-C" + "hyphenate="                    + 
(settings.getHyphenate()?"yes":"no"));
        configurationList.add("-C" + "printPages="                   + 
(settings.getPrintPageNumbers()?"yes":"no"));
        configurationList.add("-C" + "pageSeparator="                + 
(settings.getPageSeparator()?"yes":"no"));
        configurationList.add("-C" + "pageSeparatorNumber="          + 
(settings.getPageSeparatorNumber()?"yes":"no"));
        configurationList.add("-C" + "ignoreEmptyPages="             + 
(settings.getIgnoreEmptyPages()?"yes":"no"));
        configurationList.add("-C" + "continuePages="                + 
(settings.getContinuePages()?"yes":"no"));
        configurationList.add("-C" + "mergeUnnumberedPages="         + 
(settings.getMergeUnnumberedPages()?"yes":"no"));
        configurationList.add("-C" + "pageNumberTopSeparateLine="    + 
(settings.getPageNumberAtTopOnSeparateLine()?"yes":"no"));
        configurationList.add("-C" + "pageNumberBottomSeparateLine=" + 
(settings.getPageNumberAtBottomOnSeparateLine()?"yes":"no"));
        configurationList.add("-C" + "printPageNumberRange="         + 
(settings.getPrintPageNumberRange()?"yes":"no"));
        configurationList.add("-C" + "printPageNumberAt="            + 
settings.getPrintPageNumberAt());
        configurationList.add("-C" + "braillePageNumberAt="          + 
settings.getBraillePageNumberAt());

        configurationList.add("\"" + daisyUrl   + "\"");
        configurationList.add("\"" + brailleUrl + "\"");

        createChardefsFile(daisyFile);

        logger.exiting("Odt2Braille","configureLiblouisxml");

    }
}

-- 
John J. Boyer; President, Chief Software Developer
Abilitiessoft, Inc.
http://www.abilitiessoft.com
Madison, Wisconsin USA
Developing software for people with disabilities



Other related posts: