1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 /*
24  *
25  /*
26  * XLIFFWriter.java
27  *
28  *
29  */
30 
31 package com.sun.star.tooling.converter;
32 
33 import java.io.*;
34 import java.util.*;
35 
36 import com.sun.star.tooling.DirtyTags.DirtyTagWrapper;
37 import com.sun.star.tooling.languageResolver.LanguageResolver;
38 import com.sun.star.tooling.languageResolver.LanguageResolver.LanguageResolvingException;
39 
40 /**
41  * Write the Data to a wellformed XLIFF File
42  *
43  * @author Christian Schmidt
44  */
45 public class XLIFFWriter extends DataWriter {
46 
47 	/**
48 	 * An array holding the keys of the HashMap containing the source language string
49 	 */
50 	private final static String[] sourceLineNames = { "Project", "SourceFile",
51 			"Dummy", "ResType", "GID", "LID", "HID", "Platform", "Width",
52 			"SourceLanguageID", "SourceText", "SourceHText", "SourceQText",
53 			"SourceTitle", "TimeStamp" };
54     /**
55      * An array holding the keys of the HashMap containing the target language string
56      */
57 	private final static String[] targetLineNames = { "Project", "SourceFile",
58 			"Dummy", "ResType", "GID", "LID", "HID", "Platform", "Width",
59 			"TargetLanguageID", "TargetText", "TargetHText", "TargetQText",
60 			"TargetTitle", "TimeStamp" };
61     /**
62      * An array holding the keys of the HashMap containing the source and target language string
63      */
64 	private final static String[] outLineNames = { "BlockNr", "Project",
65 			"SourceFile", "Dummy", "ResType", "GID", "LID", "HID", "Platform",
66 			"Width", "SourceLanguageID", "SourceText", "SourceHText",
67 			"SourceQText", "SourceTitle", "TargetLanguageID", "TargetText",
68 			"TargetHText", "TargetQText", "TargetTitle", "TimeStamp" };
69     /**
70      * An Map holding the source and target content
71      */
72 	private final Map data = new ExtMap(outLineNames, null);
73 
74 
75 	/**
76 	 * Indicates if this is the first Transunit to write
77 	 */
78 	boolean isFirst = true;
79 
80     LanguageResolver languageResolver;
81 
82 
83 	/**
84 	 * Create a new Instance of XLIFFWriter
85 	 *
86 	 * @param bos the Buffered Output Stream to write to
87 	 * @param charset the charset to use
88 	 * @throws IOException
89 	 */
XLIFFWriter(BufferedOutputStream bos, String charset)90 	public XLIFFWriter(BufferedOutputStream bos, String charset)
91 			throws IOException {
92 		super(bos, charset);
93 		this.languageResolver =new LanguageResolver();
94 
95 
96 	}
97 
98 	/* (non-Javadoc)
99 	 * @see com.sun.star.tooling.converter.DataWriter#getDatafrom(com.sun.star.tooling.converter.DataHandler)
100 	 */
getDatafrom(DataHandler handler)101 	public void getDatafrom(DataHandler handler) throws java.io.IOException {
102 		handler.putDataTo(this.data);
103 	}
104 
105 	/**
106      * check if the item is an empty String
107      *
108 	 * @param item the string to check
109 	 * @return true if it is not empty, false if it is empty
110 	 */
isUsed(String item)111 	private final boolean isUsed(String item) {
112 		if (!"".equals(item))
113 			return true;
114 		return false;
115 	}
116 
117 	/**
118      * Replaces all characters that mustn't be in XLIFF PCdata
119      *
120 	 * @param string the string to check
121 	 * @return the checked string with all characters replaced
122 	 * @throws java.io.IOException
123 	 */
xmlString( final String string)124 	private final String xmlString( final String string) throws java.io.IOException {
125 		if (string == null)
126 			return string; // ""
127 		String str = string;
128 //		str = str.replaceAll("&", "&");
129 //		str = str.replaceAll("<", "&lt;");
130 //		str = str.replaceAll(">", "&gt;");
131 //		str = str.replaceAll("\"", "&quot;");
132 //		str = str.replaceAll("'", "&apos;");
133 		 for(int i=0;i<str.length();i++){
134     		 if(str.charAt(i)=='&'){
135         		 str=str.substring(0, i)+"&amp;"+str.substring(i+1);
136                  continue;
137     		 }
138 
139     		 if(str.charAt(i)=='<'){
140         		 str=str.substring(0, i)+"&lt;"+str.substring(i+1);
141                  continue;
142     		 }
143 
144     		 if(str.charAt(i)=='>'){
145         		 str=str.substring(0, i)+"&gt;"+str.substring(i+1);
146         		 continue;
147              }
148 
149     		 if(str.charAt(i)=='"'){
150         		 str=str.substring(0, i)+"&quot;"+str.substring(i+1);
151         		 continue;
152              }
153 
154     		 if(str.charAt(i)=='\''){
155         		 str=str.substring(0, i)+"&apos;"+str.substring(i+1);
156         		 continue;
157              }
158 		 }
159 
160 		return str;
161 	}
162 
163 	/* (non-Javadoc)
164 	 * @see java.io.Writer#close()
165 	 */
close()166 	public void close() throws IOException {
167 		this.writeTrailer();
168 
169 		super.close();
170 	}
171 
172 	/* (non-Javadoc)
173 	 * @see com.sun.star.tooling.converter.DataWriter#writeData()
174 	 */
writeData()175 	public void writeData() throws IOException {
176 		if (isFirst) {
177 
178 			writeHeader();
179 			isFirst = false;
180 		}
181         try{
182             writeTransUnit();
183         }catch(DirtyTagWrapper.TagWrapperException e){
184 
185         }
186 	}
187 
188 	/**
189      * Write the XLIFFFiles header
190      *
191 	 * @throws IOException
192 	 */
writeHeader()193 	private void writeHeader() throws IOException {
194 
195 		this.write(getHeader());
196 	}
197 
198 	/**
199      * Write the XLIFFFiles Trailer
200      *
201 	 * @throws IOException
202 	 */
writeTrailer()203 	private void writeTrailer() throws IOException {
204 		this.write(getTrailer());
205 	}
206 
207 	/**
208      * Write the next TransUnit
209      *
210 	 * @throws IOException
211 	 */
writeTransUnit()212 	private void writeTransUnit() throws IOException, DirtyTagWrapper.TagWrapperException {
213 		try{
214             StringBuffer writeBuffer = new StringBuffer(1000);
215 
216     		StringBuffer allLinesEnd = new StringBuffer(200);
217     		String sRessource = "";
218     		int parts = 0;
219     		if (data == null) {
220     			OutputHandler.out("error");// TBD Exception
221     		}
222 
223     		if (!(this.data.get("SourceText").equals("") || this.data.get(
224     				"SourceText").equals(" "))) {
225     			parts++;
226     		}
227     		// if(!(this.data.get("SourceHText").equals("")||this.data.get("SourceHText").equals("
228     		// "))){
229     		// parts++;
230     		// }
231     		if (!(this.data.get("SourceQText").equals("") || this.data.get(
232     				"SourceQText").equals(" "))) {
233     			parts++;
234     		}
235     		if (!(this.data.get("SourceTitle").equals("") || this.data.get(
236     				"SourceTitle").equals(" "))) {
237     			parts++;
238     		}
239     		if (!(this.data.get("SourceText").equals("") || this.data.get(
240     				"SourceText").equals(" "))) {
241     			sRessource = "res"; // normal TEXT source
242 
243     			allLinesEnd
244     					.append("\t\t\t\t<context-group name=\"StarOffice Attributes\">\n");
245 
246     			if (isUsed((String) this.data.get("ResType")))
247     				allLinesEnd
248     						.append("\t\t\t\t\t<context context-type=\"DBType\">"
249     								+ xmlString((String) this.data.get("ResType"))
250     								+ "</context>\n");
251     			if (isUsed((String) this.data.get("Project")))
252     				allLinesEnd
253     						.append("\t\t\t\t\t<context context-type=\"Project\">"
254     								+ xmlString((String) this.data.get("Project"))
255     								+ "</context>\n");
256     			if (isUsed((String) this.data.get("SourceFile")))
257     				allLinesEnd
258     						.append("\t\t\t\t\t<context context-type=\"Filename\">"
259     								+ xmlString((String) this.data
260     										.get("SourceFile")) + "</context>\n");
261     			if (isUsed((String) this.data.get("SourceHText")))
262     				allLinesEnd
263     						.append("\t\t\t\t\t<context context-type=\"SourceHelpText\">"
264     								+ xmlString((String) this.data
265     										.get("SourceHText")) + "</context>\n");
266     			if (isUsed((String) this.data.get("TargetHText")))
267     				allLinesEnd
268     						.append("\t\t\t\t\t<context context-type=\"TargetHelpText\">"
269     								+ xmlString((String) this.data
270     										.get("TargetHText")) + "</context>\n");
271     			if (isUsed((String) this.data.get("ResType")))
272     				allLinesEnd.append("\t\t\t\t\t<context context-type=\"Type\">"
273     						+ xmlString((String) this.data.get("ResType"))
274     						+ "</context>\n");
275     			if (isUsed((String) this.data.get("GID")))
276     				allLinesEnd.append("\t\t\t\t\t<context context-type=\"GID\">"
277     						+ xmlString((String) this.data.get("GID"))
278     						+ "</context>\n");
279     			if (isUsed((String) this.data.get("LID")))
280     				allLinesEnd.append("\t\t\t\t\t<context context-type=\"LID\">"
281     						+ xmlString((String) this.data.get("LID"))
282     						+ "</context>\n");
283     			if (isUsed((String) this.data.get("HID")))
284     				allLinesEnd.append("\t\t\t\t\t<context context-type=\"HID\">"
285     						+ xmlString((String) this.data.get("HID"))
286     						+ "</context>\n");
287     			if (isUsed((String) this.data.get("Platform")))
288     				allLinesEnd
289     						.append("\t\t\t\t\t<context context-type=\"Platform\">"
290     								+ xmlString((String) this.data.get("Platform"))
291     								+ "</context>\n");
292     			if (isUsed((String) this.data.get("Width")))
293     				allLinesEnd.append("\t\t\t\t\t<context context-type=\"Width\">"
294     						+ xmlString((String) this.data.get("Width"))
295     						+ "</context>\n");
296     			allLinesEnd.append("\t\t\t\t</context-group>\n"
297     					+ "\t\t\t</trans-unit>\n");
298 
299     			writeBuffer.append("\t\t\t<trans-unit id=\""
300     					+ this.data.get("BlockNr") + ":" + parts + "\" restype=\""
301     					+ sRessource + "\" translate=\"yes\">\n");
302     			if (isUsed((String) this.data.get("SourceText")))
303     				writeBuffer.append("\t\t\t\t<source xml:lang=\""
304     						+ languageResolver.getRFCFromISO((String)this.data.get("SourceLanguageID")) + "\">"
305     						+ DirtyTagWrapper.wrapString((String) this.data.get("SourceText"))
306     						+ "</source>\n");
307 
308     			if (isUsed((String) this.data.get("TargetText")))
309     				writeBuffer
310     						.append("\t\t\t\t<target state=\"to_translate\" xml:lang=\""
311     								+ languageResolver.getRFCFromISO((String)this.data.get("TargetLanguageID"))
312     								+ "\">"
313     								+DirtyTagWrapper.wrapString((String) this.data
314     										.get("TargetText")) + "</target>\n");
315     			writeBuffer.append(allLinesEnd);
316     			Converter.countLine();
317 
318     		}
319     		// if(!(this.data.get("SourceHText").equals("")||this.data.get("SourceHText").equals("
320     		// "))){
321     		// sRessource="res-Help"; //Source is Help
322     		// //sLineNumber=String.valueOf(iLineNumber);//
323     		// writeBuffer.append("\t\t<trans-unit
324     		// id=\""+this.data.get("BlockNr")+":"+parts+"\"
325     		// restype=\""+sRessource+"\" translate=\"yes\">\n");//always translate
326     		// if(isUsed((String)this.data.get("SourceHText")))
327     		// writeBuffer.append("\t\t\t<source
328     		// xml:lang=\""+this.data.get("SourceLanguageID")+"\">"+xmlString((String)this.data.get("SourceHText"))+"</source>\n");
329     		// if(isUsed((String)this.data.get("TargetHText")))
330     		// writeBuffer.append("\t\t\t<target state=\"to_translate\"
331     		// xml:lang=\""+this.data.get("TargetLanguageID")+"\">"+xmlString((String)this.data.get("TargetHText"))+"</target>\n");
332     		// writeBuffer.append(allLinesEnd);
333     		// Converter.countLine();
334     		// }
335 
336     		if (!(this.data.get("SourceQText").equals("") || this.data.get(
337     				"SourceQText").equals(" "))) {
338     			sRessource = "res-QuickHelp"; // Source is OuickHelp
339     			// sLineNumber=String.valueOf(iLineNumber);//
340     			writeBuffer.append("\t\t\t<trans-unit id=\""
341     					+ this.data.get("BlockNr") + ":" + parts + "\" restype=\""
342     					+ sRessource + "\" translate=\"yes\">\n");// always translate
343     			if (isUsed((String) this.data.get("SourceQText")))
344     				writeBuffer.append("\t\t\t\t<source xml:lang=\""
345     						+ languageResolver.getRFCFromISO((String)this.data.get("SourceLanguageID")) + "\">"
346     						+ DirtyTagWrapper.wrapString((String) this.data.get("SourceQText"))
347     						+ "</source>\n");
348     			if (isUsed((String) this.data.get("TargetQText")))
349     				writeBuffer
350     						.append("\t\t\t\t<target state=\"to_translate\" xml:lang=\""
351     								+ languageResolver.getRFCFromISO((String)this.data.get("TargetLanguageID"))
352     								+ "\">"
353     								+ DirtyTagWrapper.wrapString((String) this.data
354     										.get("TargetQText")) + "</target>\n");
355     			writeBuffer.append(allLinesEnd);
356     			Converter.countLine();
357     		}
358 
359     		if (!(this.data.get("SourceTitle").equals("") || this.data.get(
360     				"SourceTitle").equals(" "))) {
361     			sRessource = "res-Title"; // Source is Title
362 
363     			writeBuffer.append("\t\t\t<trans-unit id=\""
364     					+ this.data.get("BlockNr") + ":" + parts + "\" restype=\""
365     					+ sRessource + "\" translate=\"yes\">\n");// always translate
366     			if (isUsed((String) this.data.get("SourceTitle")))
367     				writeBuffer.append("\t\t\t\t<source xml:lang=\""
368     						+ languageResolver.getRFCFromISO((String)this.data.get("SourceLanguageID")) + "\">"
369     						+ DirtyTagWrapper.wrapString((String) this.data.get("SourceTitle"))
370     						+ "</source>\n");
371     			if (isUsed((String) this.data.get("TargetTitle")))
372     				writeBuffer
373     						.append("\t\t\t\t<target state=\"to_translate\" xml:lang=\""
374     								+ languageResolver.getRFCFromISO((String)this.data.get("TargetLanguageID"))
375     								+ "\">"
376     								+ DirtyTagWrapper.wrapString((String) this.data
377     										.get("TargetTitle")) + "</target>\n");
378     			writeBuffer.append(allLinesEnd);
379     			Converter.countLine();
380     		}
381     		this.write(writeBuffer.toString());
382         }catch(Exception e){
383             OutputHandler.log(e.getMessage());
384         }
385 	}
386 
387 	/**
388      * Create the XLIFFFiles Header
389      *
390 	 * @return the header as string
391 	 * @throws java.io.UnsupportedEncodingException
392 	 */
getHeader()393 	private String getHeader() throws java.io.UnsupportedEncodingException {
394 		return new String(
395 				(getProcessingInstructionTag() + getDTDLine()
396 						+ openVersionLine() + openFileLine() + getHeaderTag() + openBodyTag())
397 						.getBytes(), "UTF8");
398 
399 	}
400 
401 	/**
402      * Create the XLIFFFiles Trailer
403      *
404 	 * @return the trailer as string
405 	 */
getTrailer()406 	private String getTrailer() {
407 		return closeBodyTag() + closeFileLine() + closeVersionLine();
408 	}
409 
410 	/**
411      * Create the Processing Instruction Tag used by this XLIFFFile
412 	 * @return the Processing Instruction Tag used by this XLIFFFile
413 	 */
getProcessingInstructionTag()414 	private String getProcessingInstructionTag() {
415 		String sPITagStart = "<?";
416 		String sPIName = "xml ";
417 		String sPIVersion = "version=\"1.0\" ";
418 		String sPIEncoding = "encoding=\"UTF-8\"";
419 		String sPITagEnd = "?>";
420 		return sPITagStart + sPIName + sPIVersion + sPIEncoding
421 				+ /* sPIStandalone+ */sPITagEnd + '\n';
422 	}
423 
424 	/**
425      * Create the line holding the DTD referenced by this XLIFFFile
426 	 * @return a string holding the DTD referenced by this XLIFFFile
427 	 */
getDTDLine()428 	private String getDTDLine() {
429 		String sDTDTagStart = "<!DOCTYPE ";
430 		String sDTDType = "xliff ";
431 		String sDTDSource = "PUBLIC \"-//XLIFF//DTD XLIFF//EN\" \"http://www.oasis-open.org/committees/xliff/documents/xliff.dtd\">";// http://www.oasis-open.org/committees/xliff/documents/
432 		String sDTSTagEnd = ">";
433 		return sDTDTagStart + sDTDType + sDTDSource + '\n';
434 	}
435 
436 	/**
437      * Create the beginning of the line holding the version of this XIFFFile
438      *
439 	 * @return a string  with the beginning of the line holding the version of this XIFFFile
440 	 */
openVersionLine()441 	private String openVersionLine() {
442 		return "<xliff version=\"1.0\">\n";
443 	}
444     /**
445      * Create the ending of the line holding the version of this XIFFFile
446      *
447      * @return a string  with the ending of the line holding the version of this XIFFFile
448      */
closeVersionLine()449 	private String closeVersionLine() {
450 		return "</xliff>";
451 	}
452     /**
453      * Create the beginning of the line holding the file tag of this XIFFFile
454      *
455      * @return a string  with the beginning of the file tag of this XIFFFile
456      */
openFileLine()457 	private String openFileLine() {
458 
459             String FileTagStart = "\t<file";
460     		String FileDataType = " datatype=\"STAROFFICE\"";
461     		String FileDate = " date=\"" + this.data.get("TimeStamp") + "\"";
462     		String FileOriginal = " original=\"" + this.data.get("SourceFile")
463     				+ "\"";
464             String FileSourceLanguage="";
465             String FileTargetLanguage="";
466     		try {
467                 FileSourceLanguage = " source-language=\""
468                 		+ languageResolver.getRFCFromISO((String)this.data.get("SourceLanguageID")) + "\" ";
469                 FileTargetLanguage = " target-language=\""
470                 		+ languageResolver.getRFCFromISO((String)this.data.get("TargetLanguageID")) + "\" ";
471             } catch (LanguageResolvingException e) {
472                 OutputHandler.out(e.getMessage());
473             }
474     		String FileTagEnd = ">";
475     		return FileTagStart + FileDataType + FileDate + FileOriginal
476 				+ FileSourceLanguage + FileTargetLanguage + FileTagEnd;
477 
478 	}
479     /**
480      * Create the ending of the line holding the file tag of this XIFFFile
481      *
482      * @return a string  with the ending of the file tag of this XIFFFile
483      */
closeFileLine()484 	private String closeFileLine() {
485 		return "\t</file>";
486 	}
487     /**
488      * Create a String  containing the header tag
489      * @return the String  containing the header tag
490      */
getHeaderTag()491 	private String getHeaderTag() {
492 		return "<header></header>\n";
493 	}
494     /**
495      * Create the begining of the line holding the body tag of this XIFFFile
496      *
497      * @return a string  with the begining of the body tag of this XIFFFile
498      */
openBodyTag()499 	private String openBodyTag() {
500 		return "\t\t<body>\n";
501 	}
502     /**
503      * Create the ending of the line holding the body tag of this XIFFFile
504      *
505      * @return a string  with the ending of the body tag of this XIFFFile
506      */
closeBodyTag()507 	private String closeBodyTag() {
508 		return "\t\t</body>";
509 	}
510 
511 	/*
512 	 * (non-Javadoc)
513 	 *
514 	 * @see com.sun.star.tooling.converter.DataWriter#writeData(java.util.Map[])
515 	 */
writeData(Map[] data)516 	protected void writeData(Map[] data) throws IOException {
517 		// TODO Auto-generated method stub
518 
519 	}
520 
521 	/*
522 	 * (non-Javadoc)
523 	 *
524 	 * @see com.sun.star.tooling.converter.DataWriter#getDataFrom(com.sun.star.tooling.converter.DataHandler)
525 	 */
getDataFrom(DataHandler handler)526 	protected void getDataFrom(DataHandler handler) {	}
527 
528 }
529