/*
* Part of the CCNx Java Library.
*
* Copyright (C) 2008, 2009, 2011 Palo Alto Research Center, Inc.
*
* 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., 51 Franklin Street,
* Fifth Floor, Boston, MA 02110-1301 USA.
*/
package org.ccnx.ccn.impl.encoding;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Iterator;
import java.util.Set;
import java.util.TreeMap;
import org.ccnx.ccn.impl.support.Log;
import org.ccnx.ccn.io.content.ContentEncodingException;
import org.ccnx.ccn.profiles.VersioningProfile;
import org.ccnx.ccn.protocol.CCNTime;
/**
* An implementation of XMLEncoder for the Binary (ccnb) codec.
*
* @see BinaryXMLCodec
* @see XMLEncoder
*/
public class BinaryXMLEncoder extends GenericXMLEncoder implements XMLEncoder {
/**
* Create a BinaryXMLEncoder initialized with the default dictionary obtained
* from BinaryXMLDictionary#getDefaultDictionary().
*/
public BinaryXMLEncoder() {
super();
}
/**
* Create a BinaryXMLEncoder initialized with a specified dictionary.
* @param dictionary the dictionary to use, if null the default dictionary is used.
*/
public BinaryXMLEncoder(XMLDictionary dictionary) {
super(dictionary);
}
public void beginEncoding(OutputStream ostream) throws ContentEncodingException {
if (null == ostream)
throw new IllegalArgumentException("BinaryXMLEncoder: output stream cannot be null!");
_ostream = ostream;
}
public void endEncoding() throws ContentEncodingException {
try {
_ostream.flush();
} catch (IOException e) {
throw new ContentEncodingException(e.getMessage(), e);
}
}
public void writeUString(String utf8Content) throws ContentEncodingException {
try {
BinaryXMLCodec.encodeUString(_ostream, utf8Content);
} catch (IOException e) {
throw new ContentEncodingException(e.getMessage(), e);
}
}
public void writeBlob(byte [] binaryContent) throws ContentEncodingException {
try {
BinaryXMLCodec.encodeBlob(_ostream, binaryContent);
} catch (IOException e) {
throw new ContentEncodingException(e.getMessage(), e);
}
}
public void writeBlob(byte [] binaryContent, int offset, int length) throws ContentEncodingException {
try {
BinaryXMLCodec.encodeBlob(_ostream, binaryContent, offset, length);
} catch (IOException e) {
throw new ContentEncodingException(e.getMessage(), e);
}
}
/**
* Compact binary encoding of time, same as used for versions.
* @see VersioningProfile
*/
public void writeDateTime(String tag, CCNTime dateTime) throws ContentEncodingException {
writeElement(tag, dateTime.toBinaryTime());
}
/**
* Compact binary encoding of time, same as used for versions.
* @see VersioningProfile
*/
public void writeDateTime(long tag, CCNTime dateTime) throws ContentEncodingException {
writeElement(tag, dateTime.toBinaryTime());
}
public void writeStartElement(String tag, TreeMap<String,String> attributes) throws ContentEncodingException {
try {
Long dictionaryVal = stringToTag(tag);
if (null == dictionaryVal) {
Log.info(Log.FAC_ENCODING, "Unexpected: tag found that is not in our dictionary: " + tag);
// not in dictionary
// compressed format wants length of tag represented as length-1
// to save that extra bit, as tag cannot be 0 length.
// encodeUString knows to do that.
BinaryXMLCodec.encodeUString(_ostream, tag, BinaryXMLCodec.XML_TAG);
} else {
BinaryXMLCodec.encodeTypeAndVal(BinaryXMLCodec.XML_DTAG, dictionaryVal, _ostream);
}
if (null != attributes) {
writeAttributes(attributes);
}
} catch (IOException e) {
throw new ContentEncodingException(e.getMessage(),e);
}
}
public void writeStartElement(long tag, TreeMap<String,String> attributes) throws ContentEncodingException {
try {
BinaryXMLCodec.encodeTypeAndVal(BinaryXMLCodec.XML_DTAG, tag, _ostream);
if (null != attributes) {
writeAttributes(attributes);
}
} catch (IOException e) {
throw new ContentEncodingException(e.getMessage(),e);
}
}
public void writeAttributes(TreeMap<String,String> attributes) throws IOException {
if (null == attributes) {
return;
}
// the keySet of a TreeMap is sorted.
Set<String> keySet = attributes.keySet();
Iterator<String> it = keySet.iterator();
while (it.hasNext()) {
String strAttr = it.next();
String strValue = attributes.get(strAttr);
Long dictionaryAttr = stringToTag(strAttr);
if (null == dictionaryAttr) {
// not in dictionary, encode as attr
// compressed format wants length of tag represented as length-1
// to save that extra bit, as tag cannot be 0 length.
// encodeUString knows to do that.
BinaryXMLCodec.encodeUString(_ostream, strAttr, BinaryXMLCodec.XML_ATTR);
} else {
BinaryXMLCodec.encodeTypeAndVal(BinaryXMLCodec.XML_DATTR, dictionaryAttr, _ostream);
}
// Write value
BinaryXMLCodec.encodeUString(_ostream, strValue);
}
}
public void writeEndElement() throws ContentEncodingException {
try {
_ostream.write(BinaryXMLCodec.XML_CLOSE);
} catch (IOException e) {
throw new ContentEncodingException(e.getMessage(),e);
}
}
}