/*
* Copyright (C) 2014-2015, VistaTEC or third-party contributors as indicated
* by the @author tags or express copyright attribution statements applied by
* the authors. All third-party contributions are distributed under license by
* VistaTEC.
*
* This file is part of Ocelot.
*
* Ocelot is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Ocelot 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 program. If not, write to:
*
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301
* USA
*
* Also, see the full LGPL text here: <http://www.gnu.org/copyleft/lesser.html>
*/
package com.vistatec.ocelot.xliff.okapi;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.Iterator;
import javax.xml.namespace.QName;
import javax.xml.stream.XMLEventReader;
import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.events.Attribute;
import javax.xml.stream.events.StartElement;
import javax.xml.stream.events.XMLEvent;
import org.apache.commons.io.ByteOrderMark;
import org.apache.commons.io.input.BOMInputStream;
import com.vistatec.ocelot.config.UserProvenance;
import com.vistatec.ocelot.events.api.OcelotEventQueue;
import com.vistatec.ocelot.xliff.XLIFFFactory;
import com.vistatec.ocelot.xliff.XLIFFParser;
import com.vistatec.ocelot.xliff.XLIFFVersion;
import com.vistatec.ocelot.xliff.XLIFFWriter;
/**
* Detect which XLIFF parser version to use for the XLIFF file.
*/
public class OkapiXLIFFFactory implements XLIFFFactory {
@Override
public XLIFFVersion detectXLIFFVersion(File detectVersion) throws IOException, XMLStreamException {
try (BOMInputStream bomInputStream = new BOMInputStream(new FileInputStream(detectVersion),
ByteOrderMark.UTF_8, ByteOrderMark.UTF_16BE, ByteOrderMark.UTF_16LE,
ByteOrderMark.UTF_32BE, ByteOrderMark.UTF_32LE)) {
String bom = "UTF-8";
if (bomInputStream.hasBOM()) {
bom = bomInputStream.getBOMCharsetName();
}
XMLInputFactory xml = XMLInputFactory.newInstance();
XMLEventReader reader = xml.createXMLEventReader(bomInputStream, bom);
while (reader.hasNext()) {
XMLEvent event = reader.nextEvent();
switch (event.getEventType()) {
case XMLEvent.START_ELEMENT:
StartElement startElement = (StartElement) event;
String localPart = startElement.getName().getLocalPart();
if (localPart.equals("xliff")) {
@SuppressWarnings("unchecked")
Iterator<Attribute> attrs = startElement.getAttributes();
while (attrs.hasNext()) {
Attribute attr = attrs.next();
if (isXliffVersionAttributeName(attr.getName())) {
String value = attr.getValue();
reader.close();
if ("2.0".equals(value)) {
return XLIFFVersion.XLIFF20;
} else {
return XLIFFVersion.XLIFF12;
}
}
}
}
break;
default:
break;
}
}
throw new IllegalStateException("Could not detect XLIFF version");
}
}
// The XLIFF spec is unclear on whether @version is namespaced. My assumption
// is no, it is not namespaced, but just in case other implementations disagree,
// we'll be permissive.
private boolean isXliffVersionAttributeName(QName name) {
if (!"version".equals(name.getLocalPart())) return false;
String ns = name.getNamespaceURI();
return (ns == null || "".equals(ns) ||
"urn:oasis:names:tc:xliff:document:1.2".equals(ns) ||
"urn:oasis:names:tc:xliff:document:2.0".equals(ns));
}
@Override
public XLIFFParser newXLIFFParser(XLIFFVersion version) throws IOException, XMLStreamException {
switch (version) {
case XLIFF12:
return new OkapiXLIFF12Parser();
case XLIFF20:
return new OkapiXLIFF20Parser();
}
throw new IllegalStateException();
}
@Override
public XLIFFWriter newXLIFFWriter(XLIFFParser parser,
UserProvenance userProvenance, OcelotEventQueue eventQueue) {
if (parser instanceof OkapiXLIFF12Parser) {
return new OkapiXLIFF12Writer((OkapiXLIFF12Parser) parser, userProvenance, eventQueue);
} else if (parser instanceof OkapiXLIFF20Parser) {
return new OkapiXLIFF20Writer((OkapiXLIFF20Parser) parser, userProvenance, eventQueue);
} else {
throw new IllegalArgumentException("Unrecognized XLIFF parser version!");
}
}
}