/*************************************************************************
*
* OpenOffice.org - a multi-platform office productivity suite
*
* $RCSfile: HelpLinker.java,v $
*
* $Revision: 1.13 $
*
* last change: $Author: kz $ $Date: 2006/01/05 14:45:47 $
*
* The Contents of this file are made available subject to
* the terms of GNU Lesser General Public License Version 2.1.
*
*
* GNU Lesser General Public License Version 2.1
* =============================================
* Copyright 2005 by Sun Microsystems, Inc.
* 901 San Antonio Road, Palo Alto, CA 94303, USA
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License version 2.1, as published by the Free Software Foundation.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
* MA 02111-1307 USA
*
************************************************************************/
/**************************************************************************
TODO
**************************************************************************
*************************************************************************/
package com.sun.star.help;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.UnsupportedEncodingException;
import java.net.URL;
import java.net.URLEncoder;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.StringTokenizer;
import java.util.jar.JarEntry;
import java.util.jar.JarOutputStream;
import java.util.zip.CRC32;
import com.sleepycat.db.Db;
import com.sleepycat.db.DbException;
import com.sleepycat.db.Dbt;
import com.sun.xmlsearch.util.PrefixTranslator;
import com.sun.xmlsearch.xml.indexer.XmlIndexBuilder;
class HelpLinker {
public static int locCount = 0, totCount = 0;
public static void main(String[] args) {
HelpCompiler.initURLHandler();
Hashtable additionalFiles = new Hashtable();
HashSet helpFiles = new HashSet();
String sourceRoot = null;
String embeddStylesheet = null;
String indexStylesheet = null;
String outputFile = null;
String module = null;
String lang = null;
String hid = null;
if (args.length > 0 && args[0].startsWith("@")) {
// try {
// Thread.sleep(100000);
// } catch (InterruptedException e1) {
// // TODO Auto-generated catch block
// e1.printStackTrace();
// }
try {
String fName = args[0].substring(1);
FileReader fileReader = new FileReader(fName);
StringBuffer strBuf = new StringBuffer();
int n = 0;
char[] c = new char[1024];
while ((n = fileReader.read(c, 0, 1024)) != -1)
strBuf.append(c, 0, n);
String str = strBuf.toString();
StringTokenizer strTokenizer = new StringTokenizer(str);
n = 0;
String[] stringList = new String[strTokenizer.countTokens()];
while (strTokenizer.hasMoreElements())
stringList[n++] = strTokenizer.nextToken();
args = stringList;
} catch (Exception e) {
e.printStackTrace();
System.exit(1);
}
}
int i = 0;
while (i < args.length) {
if (args[i].equals("-src")) {
++i;
if (i >= args.length) {
System.err.println("sourceroot missing");
System.exit(1);
}
sourceRoot = args[i];
} else if (args[i].equals("-sty")) {
++i;
if (i >= args.length) {
System.err.println("embeddingStylesheet missing");
System.exit(1);
}
embeddStylesheet = args[i];
} else if (args[i].equals("-idx")) {
++i;
if (i >= args.length) {
System.err.println("indexstylesheet missing");
System.exit(1);
}
indexStylesheet = args[i];
} else if (args[i].equals("-o")) {
++i;
if (i >= args.length) {
System.err.println("outputfilename missing");
System.exit(1);
}
outputFile = args[i];
} else if (args[i].equals("-mod")) {
++i;
if (i >= args.length) {
System.err.println("module name missing");
System.exit(1);
}
module = args[i];
} else if (args[i].equals("-lang")) {
++i;
if (i >= args.length) {
System.err.println("language name missing");
System.exit(1);
}
lang = args[i];
} else if (args[i].equals("-hid")) {
++i;
if (i >= args.length) {
System.err.println("hid list missing");
System.exit(1);
}
hid = args[i];
} else if (args[i].equals("-add")) {
String addFile, addFileUnderPath;
++i;
if (i >= args.length) {
System.err.println("pathname missing");
System.exit(1);
}
addFileUnderPath = args[i];
++i;
if (i >= args.length) {
System.err.println("pathname missing");
System.exit(1);
}
addFile = args[i];
if (addFileUnderPath.length() != 0 && addFile.length() != 0)
additionalFiles.put(addFileUnderPath, addFile);
} else {
String adding = args[i];
helpFiles.add(adding);
}
++i;
}
if (indexStylesheet == null) {
System.err.println("no index file given");
System.exit(1);
}
if (embeddStylesheet == null) {
System.err.println("no embedding resolving file given");
System.exit(1);
}
if (sourceRoot == null) {
System.err.println("no sourceroot given");
System.exit(1);
}
if (outputFile == null) {
System.err.println("no output file given");
System.exit(1);
}
if (module == null) {
System.err.println("module missing");
System.exit(1);
}
if (lang == null) {
System.err.println("language missing");
System.exit(1);
}
if (hid == null) {
System.err.println("hid list missing");
System.exit(1);
}
try {
new HelpLinker(
sourceRoot,
embeddStylesheet,
indexStylesheet,
outputFile,
module,
lang,
hid,
helpFiles,
additionalFiles)
.link();
System.out.println(
"number of local fetches: "
+ locCount);
System.out.println(
"total number of fetches: "
+ totCount);
} catch (Exception e) {
e.printStackTrace();
System.exit(1);
}
}
private JarOutputStream jarOutputStream;
private Hashtable additionalFiles;
private HashSet helpFiles;
private String sourceRoot, embeddStylesheet, indexStylesheet;
private String outputFile;
private String module;
private String lang;
private String hid;
private Hashtable hidlistTranslation = new Hashtable();
private HelpURLStreamHandlerFactory _urlHandler = null;
private String indexDirParentName = null;
private File indexDirFile = null;
private boolean init = true;
private XmlIndexBuilder xmlIndexBuilder = null;
void initXMLIndexBuilder() throws Exception {
// Create indexDirectory, if not existent
File indexDirParentFile = File.createTempFile("temp", ".dir");
indexDirParentName = indexDirParentFile.getAbsolutePath();
indexDirParentFile.delete();
indexDirParentFile.mkdir();
String indexDirName =
indexDirParentName + File.separator + module.toLowerCase() + ".idx";
indexDirFile = new File(indexDirName);
if (indexDirFile.exists() && indexDirFile.isFile())
indexDirFile.delete();
if (!indexDirFile.exists())
indexDirFile.mkdir();
xmlIndexBuilder = new XmlIndexBuilder(indexDirName);
String[] translations = { "vnd.sun.star.help://", "#HLP#" };
PrefixTranslator translator =
PrefixTranslator.makePrefixTranslator(translations);
xmlIndexBuilder.setPrefixTranslator(translator);
String defaultXSL =
"<xsl:stylesheet version=\"1.0\" xmlns:xsl=\"http://www.w3.org/1999/XSL/Transform\">"
+ "<xsl:template match=\"*|/\"/>"
+ "</xsl:stylesheet>";
createFileFromBytes("default.xsl", defaultXSL.getBytes("UTF8"));
xmlIndexBuilder.clearIndex(); // Build index from scratch
xmlIndexBuilder.setTransformLocation(indexDirParentName);
}
private void createFileFromBytes(String fileName, byte[] defaultXSL)
throws IOException {
File defaultXSLFile =
new File(indexDirParentName + File.separator + fileName);
defaultXSLFile.createNewFile();
FileOutputStream fos = new FileOutputStream(defaultXSLFile);
fos.write(defaultXSL);
fos.close();
}
void closeXMLIndexBuilder() throws Exception {
xmlIndexBuilder.close();
}
private static boolean removeTempDirectory(String dirName) {
// recursively remove directory
File dir = new File(dirName);
File[] list = dir.listFiles();
for (int i = 0; i < list.length; i++) {
if (list[i].isDirectory()) {
if (!removeTempDirectory(dirName
+ File.separator
+ list[i].getName()))
return false;
} else {
if (!list[i].delete())
return false;
}
}
if (!dir.delete())
return false;
return true;
}
/**
*
*/
private void link() throws Exception {
// Determine the outputstream
String outputTmpFile = outputFile + ".tmp";
File outTmpFile = new File(outputTmpFile);
outTmpFile.createNewFile();
FileOutputStream os = null;
try {
os = new FileOutputStream(outTmpFile);
} catch (FileNotFoundException e) {
}
if (os == null)
System.exit(1);
try {
jarOutputStream = new JarOutputStream(os);
} catch (IOException e) {
e.printStackTrace();
System.exit(1);
}
// do the work here
// continue with introduction of the overall process thing into the
// here all hzip files will be worked on
String appl = module.toLowerCase();
if (appl.startsWith("s"))
appl = appl.substring(1);
File helpTextFile = File.createTempFile("helptext", ".ht");
helpTextFile.deleteOnExit();
String helpTextFileName = helpTextFile.getAbsolutePath();
Db helpText = new Db(null, 0);
helpText.open(null,helpTextFileName, null, Db.DB_BTREE, Db.DB_TRUNCATE, 0644);
File dbBaseFile = File.createTempFile("database", "db");
dbBaseFile.deleteOnExit();
String dbBaseFileName = dbBaseFile.getAbsolutePath();
Db dbBase = new Db(null, 0);
dbBase.open(null,dbBaseFileName, null, Db.DB_BTREE, Db.DB_TRUNCATE, 0644);
File keyWordFile = File.createTempFile("keybase", "key");
keyWordFile.deleteOnExit();
String keyWordFileName = keyWordFile.getAbsolutePath();
Db keyWord = new Db(null, 0);
keyWord.open(null,keyWordFileName, null, Db.DB_BTREE, Db.DB_TRUNCATE, 0644);
HelpKeyword helpKeyword = new HelpKeyword();
// now input the hid.lst and store it into a hashmap
FileReader fileReader = new FileReader(hid);
StringBuffer strBuf = new StringBuffer();
int n = 0;
char[] c = new char[1024];
while ((n = fileReader.read(c, 0, 1024)) != -1)
strBuf.append(c, 0, n);
String str = strBuf.toString();
StringTokenizer strTokenizer = new StringTokenizer(str);
while (strTokenizer.hasMoreTokens()) {
String key = strTokenizer.nextToken();
String data = strTokenizer.nextToken();
hidlistTranslation.put(
key.toUpperCase().replace(':', '_'),
data.trim());
}
// lastly, initialize the indexBuilder
if (!helpFiles.isEmpty())
initXMLIndexBuilder();
// here we start our loop over the hzip files.
Iterator iter = helpFiles.iterator();
while (iter.hasNext()) {
// process one file
// streamTable contains the streams in the hzip file
//Hashtable streamTable = new Hashtable();
Hashtable streamTable1 = new Hashtable();
String xhpFileName = (String) iter.next();
if (!xhpFileName.endsWith(".xhp")) {
// only work on .xhp - files
System.err.println(
"ERROR: input list entry '"
+ xhpFileName
+ "' has the wrong extension (only files with extension .xhp "
+ "are accepted)");
continue;
}
HelpCompiler hc =
new HelpCompiler(
streamTable1,
xhpFileName,
sourceRoot + File.separator + lang + File.separator,
embeddStylesheet,
module,
lang);
try {
boolean success = hc.compile();
if (!success) {
System.err.println(
"\nERROR: compiling help particle '"
+ xhpFileName
+ "' for language '"
+ lang
+ "' failed!");
System.exit(1);
}
} catch (UnsupportedEncodingException e) {
System.err.println(
"\nERROR: unsupported Encoding Exception'"
+ "': "
+ e.getMessage());
System.exit(1);
}
// Read the document core data
byte[] byStr = (byte[]) streamTable1.get("document/id");
String documentBaseId = null;
if (byStr != null) {
documentBaseId = new String(byStr, "UTF8");
} else {
System.err.println("corrupt compileroutput");
System.exit(1);
}
String documentPath =
new String(
((byte[]) streamTable1.get("document/path")),
"UTF8");
if (documentPath.startsWith("/"))
documentPath = documentPath.substring(1);
String documentJarfile =
new String(
((byte[]) streamTable1.get("document/module")),
"UTF8")
+ ".jar";
byte[] byteStream = (byte[]) streamTable1.get("document/title");
String documentTitle = null;
if (byteStream != null)
documentTitle = new String(byteStream, "UTF8");
else
documentTitle = "<notitle>";
byte[] fileB = documentPath.getBytes("UTF8");
byte[] jarfileB = documentJarfile.getBytes("UTF8");
byte[] titleB = documentTitle.getBytes("UTF8");
// add once this as its own id.
addBookmark(dbBase, documentPath, fileB, null, jarfileB, titleB);
if (init) {
FileInputStream indexXSLFile =
new FileInputStream(indexStylesheet);
int read = 0;
byte[] bytes = new byte[2048];
ByteArrayOutputStream baos = new ByteArrayOutputStream();
while ((read = indexXSLFile.read(bytes, 0, 2048)) != -1)
baos.write(bytes, 0, read);
createFileFromBytes("index.xsl", baos.toByteArray());
xmlIndexBuilder.init("index");
init = false;
}
// first the database *.db
// ByteArrayInputStream bais = null;
// ObjectInputStream ois = null;
Object baos = streamTable1.get(appl + "/hidlist");
if (baos == null)
baos = streamTable1.get("default/hidlist");
if (baos != null) {
HashSet hidlist = (HashSet) baos;
// now iterate over all elements of the hidlist
Iterator hidListIter = hidlist.iterator();
while (hidListIter.hasNext()) {
String hid = (String) hidListIter.next();
byte[] anchorB = null;
int index = hid.lastIndexOf('#');
if (index != -1) {
anchorB = hid.substring(1 + index).getBytes("UTF8");
hid = hid.substring(0, index);
}
addBookmark(dbBase, hid, fileB, anchorB, jarfileB, titleB);
}
}
// now the keywords
baos = streamTable1.get(appl + "/keywords");
if (baos == null)
baos = streamTable1.get("default/keywords");
if (baos != null) {
Hashtable anchorToLL = (Hashtable) baos;
Enumeration enumer = anchorToLL.keys();
String fakedHid = URLEncoder.encode(documentPath);
while (enumer.hasMoreElements()) {
String anchor = (String) enumer.nextElement();
addBookmark(
dbBase,
documentPath,
fileB,
anchor.getBytes("UTF8"),
jarfileB,
titleB);
String totalId = fakedHid + "#" + anchor;
// System.err.println(hzipFileName);
LinkedList ll = (LinkedList) anchorToLL.get(anchor);
Iterator llIter = ll.iterator();
while (llIter.hasNext())
helpKeyword.insert((String) llIter.next(), totalId);
}
}
// and last the helptexts
baos = streamTable1.get(appl + "/helptexts");
if (baos == null)
baos = streamTable1.get("default/helptexts");
if (baos != null) {
Hashtable helpTextHash = (Hashtable) baos;
Enumeration helpTextIter = helpTextHash.keys();
while (helpTextIter.hasMoreElements()) {
String helpTextId = (String) helpTextIter.nextElement();
String helpTextText = (String) helpTextHash.get(helpTextId);
String tHid =
(String) hidlistTranslation.get(
helpTextId.toUpperCase().replace(':', '_'));
if (tHid != null)
helpTextId = tHid;
helpTextId = URLEncoder.encode(helpTextId);
Dbt keyDbt = new Dbt(helpTextId.getBytes("UTF8"));
Dbt textDbt = new Dbt(helpTextText.getBytes("UTF8"));
helpText.put(null, keyDbt, textDbt, 0);
}
}
// now the indexing
// and last the helptexts
baos = (byte[]) streamTable1.get(appl + "/text");
if (baos == null)
baos = (byte[]) streamTable1.get("default/text");
if (baos != null) {
byte[] bytes = (byte[]) baos;
HelpURLStreamHandlerFactory.setMode(bytes);
xmlIndexBuilder.indexDocument(
new URL(
"vnd.sun.star.help://"
+ module.toLowerCase()
+ "/"
+ URLEncoder.encode(documentPath)),
"");
}
} // while loop over hzip files ending
helpText.close(0);
dbBase.close(0);
helpKeyword.dump(keyWord);
keyWord.close(0);
if (!helpFiles.isEmpty())
closeXMLIndexBuilder();
// now copy the databases into memory, so we will be able to add it to the outputfile
String mod = module.toLowerCase();
copyFileToJarfile(helpTextFileName, null, mod + ".ht");
copyFileToJarfile(dbBaseFileName, null, mod + ".db");
copyFileToJarfile(keyWordFileName, null, mod + ".key");
// delete temporary files
helpTextFile.delete();
dbBaseFile.delete();
keyWordFile.delete();
if (indexDirFile != null) {
File[] indexFiles = indexDirFile.listFiles();
for (int k = 0; k < indexFiles.length; ++k)
copyFileToJarfile(
indexFiles[k].getAbsolutePath(),
mod + ".idx",
indexFiles[k].getName());
}
/////////////////////////////////////////////////////////////////////////
// last, all files which should be copied into the jarFile
/////////////////////////////////////////////////////////////////////////
Enumeration enumer = additionalFiles.keys();
while (enumer.hasMoreElements()) {
String additionalFileKey = (String) enumer.nextElement();
String additionalFileName =
(String) additionalFiles.get(additionalFileKey);
copyFileToJarfile(additionalFileName, null, additionalFileKey);
}
/////////////////////////////////////////////////////////////////////////
/// close the zipfile
/////////////////////////////////////////////////////////////////////////
try {
jarOutputStream.close();
} catch (IOException e1) {
}
/////////////////////////////////////////////////////////////////////////
/// rename to final name
/////////////////////////////////////////////////////////////////////////
File outFile = new File(outputFile);
if ( outFile.exists() ) {
if ( !outFile.delete() ) {
System.err.println(
"can't delete file '"
+ outputFile
+ "'");
System.exit(1);
}
}
if ( !outTmpFile.renameTo(outFile) ) {
System.err.println(
"can't rename file '"
+ outputTmpFile
+ "'");
System.exit(1);
}
/////////////////////////////////////////////////////////////////////////
/// remove temprary directory for index creation
/////////////////////////////////////////////////////////////////////////
if (!helpFiles.isEmpty()) {
if (!removeTempDirectory(indexDirParentName)) {
System.err.println(
"can't remove temporary directory '"
+ indexDirParentName
+ "'");
System.exit(1);
}
}
}
private void copyFileToJarfile(
String fileName,
String directory,
String name)
throws IOException {
// now copy the databases into memory, so we will be able to add it to the outputfile
int n = 0;
FileInputStream filInputStream = new FileInputStream(fileName);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
byte[] b = new byte[1024];
while ((n = filInputStream.read(b)) != -1)
baos.write(b, 0, n);
filInputStream.close();
addEntryToJarFile(directory, name, baos.toByteArray());
}
private void addBookmark(
Db dbBase,
String hid,
byte[] fileB,
byte[] anchorB,
byte[] jarfileB,
byte[] titleB)
throws DbException, UnsupportedEncodingException {
String translatedHid =
(String) hidlistTranslation.get(
hid.toUpperCase().replace(':', '_'));
if (translatedHid != null)
hid = translatedHid;
hid = URLEncoder.encode(hid);
Dbt key = new Dbt(hid.getBytes("UTF8"));
int fileLen = fileB.length;
if (anchorB != null)
fileLen += (1 + anchorB.length);
int dataLen = 1 + fileLen + 1 + jarfileB.length + 1 + titleB.length;
byte[] dataB = new byte[dataLen];
int i = 0;
dataB[i++] = (byte) fileLen;
for (int j = 0; j < fileB.length; ++j)
dataB[i++] = fileB[j];
if (anchorB != null) {
dataB[i++] = '#';
for (int j = 0; j < anchorB.length; ++j)
dataB[i++] = anchorB[j];
}
dataB[i++] = (byte) jarfileB.length;
for (int j = 0; j < jarfileB.length; ++j)
dataB[i++] = jarfileB[j];
dataB[i++] = (byte) titleB.length;
for (int j = 0; j < titleB.length; ++j)
dataB[i++] = titleB[j];
Dbt data = new Dbt(dataB);
dbBase.put(null, key, data, 0);
}
private void addEntryToJarFile(
String prefix,
String entryName,
byte[] bytesToAdd) {
if (bytesToAdd == null)
return;
try {
CRC32 crc = new CRC32();
crc.update(bytesToAdd);
JarEntry ze =
new JarEntry(
prefix != null ? prefix + "/" + entryName : entryName);
ze.setCrc(crc.getValue());
ze.setSize(bytesToAdd.length);
ze.setMethod(JarEntry.DEFLATED);
jarOutputStream.putNextEntry(ze);
if (bytesToAdd.length > 0)
jarOutputStream.write(bytesToAdd);
jarOutputStream.closeEntry();
} catch (IOException e) {
e.printStackTrace();
System.exit(1);
}
}
/**
* @param outputFile
* @param module
* @param lang
* @param hid
* @param helpFiles
* @param additionalFiles
*/
private HelpURLStreamHandlerFactory urlHandler = null;
public HelpLinker(
String sourceRoot,
String embeddStylesheet,
String indexStylesheet,
String outputFile,
String module,
String lang,
String hid,
HashSet helpFiles,
Hashtable additionalFiles) {
this.sourceRoot = sourceRoot;
this.embeddStylesheet = embeddStylesheet;
this.indexStylesheet = indexStylesheet;
this.outputFile = outputFile;
this.module = module;
this.lang = lang;
this.hid = hid;
this.helpFiles = helpFiles;
this.additionalFiles = additionalFiles;
}
}
// vnd.sun.star.help://swriter/52821?Language=en-US&System=UNIX