All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.digidoc4j.ddoc.factory.SAXDigiDocFactory Maven / Gradle / Ivy

Go to download

DDoc4J is Java Library for validating DDOC documents. It's not recommended to use it directly but rather through DigiDoc4J's API.

The newest version!
package org.digidoc4j.ddoc.factory;

import org.digidoc4j.ddoc.*;
import org.digidoc4j.ddoc.utils.ConfigManager;
import org.digidoc4j.ddoc.utils.ConvertUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;

import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import java.io.*;
import java.security.MessageDigest;
import java.util.*;

/**
 * SAX implementation of DigiDocFactory
 * Provides methods for reading a DigiDoc file
 * @author  Veiko Sinivee
 * @version 1.0
 */
public class SAXDigiDocFactory
        extends DefaultHandler
        implements DigiDocFactory
{
    private Stack m_tags;
    private SignedDoc m_doc;
    private Signature m_sig;
    private String m_strSigValTs, m_strSigAndRefsTs;
    private StringBuffer m_sbCollectChars;
    private StringBuffer m_sbCollectItem;
    private StringBuffer m_sbCollectSignature;
    private boolean m_bCollectDigest;
    private String m_xmlnsAttr;
    /** This mode means collect SAX events into xml data
     * and is used to collect all ,  and
     *  content. Also servers as level of
     * embedded DigiDoc files. Initially it should be 0. If
     * we start collecting data then it's 1 and if we find
     * another SignedDoc inside a DataFile then it will be incremented
     * in order to know which is the correct  tag to leave
     * the collect mode
     */
    private int m_nCollectMode;
    private long nMaxBdocFilCached;
    /** log4j logger */
    private Logger m_logger = LoggerFactory.getLogger(SAXDigiDocFactory.class);
    /** calculation of digest */
    private MessageDigest m_digest, m_altDigest;
    /** temp output stream used to cache DataFile content */
    private FileOutputStream m_dfCacheOutStream;
    private String m_tempDir;
    /** name of file being loaded */
    private String m_fileName, m_sigComment;
    private String m_nsDsPref, m_nsXadesPref, m_nsAsicPref;
    private List m_errs;
    private XmlElemInfo m_elemRoot, m_elemCurrent;

    /**
     * Creates new SAXDigiDocFactory
     * and initializes the variables
     */
    public SAXDigiDocFactory() {
        m_tags = new Stack();
        m_doc = null;
        m_sig = null;
        m_sbCollectSignature = null;
        m_xmlnsAttr = null;
        m_nsAsicPref = null;
        m_sbCollectItem = null;
        m_digest = null;
        m_altDigest = null;
        m_bCollectDigest = false;
        m_dfCacheOutStream = null;
        m_tempDir = null;
        m_errs = null;
        m_elemRoot = null;
        m_elemCurrent = null;
        nMaxBdocFilCached = ConfigManager.instance().
                getLongProperty("DIGIDOC_MAX_DATAFILE_CACHED", Long.MAX_VALUE);
    }

    /**
     * Helper method to update sha1 digest with some data
     * @param data
     */
    private void updateDigest(byte[] data)
    {
        try {
            // if not inited yet then initialize digest
            if(m_digest == null)
                m_digest = MessageDigest.getInstance("SHA-1");
            m_digest.update(data);
        } catch(Exception ex) {
            m_logger.error("Error calculating digest: " + ex);
            //ex.printStackTrace();
        }
    }

    /**
     * Helper method to update alternate sha1 digest with some data
     * @param data
     */
    private void updateAltDigest(byte[] data)
    {
        try {
            // if not inited yet then initialize digest
            if(m_altDigest == null)
                m_altDigest = MessageDigest.getInstance("SHA-1");
            m_altDigest.update(data);
        } catch(Exception ex) {
            m_logger.error("Error calculating digest: " + ex);
            //ex.printStackTrace();
        }
    }

    /**
     * Set temp dir used to cache data files.
     * @param s directory name
     */
    public void setTempDir(String s) {
        m_tempDir = s;
    }

    /**
     * Helper method to calculate the digest result and
     * reset digest
     * @return sha-1 digest value
     */
    private byte[] getDigest()
    {
        byte [] digest = null;
        try {
            // if not inited yet then initialize digest
            digest = m_digest.digest();
            m_digest = null; // reset for next calculation
        } catch(Exception ex) {
            m_logger.error("Error calculating digest: " + ex);
            //ex.printStackTrace();
        }
        return digest;
    }

    /**
     * Helper method to calculate the alternate digest result and
     * reset digest
     * @return sha-1 digest value
     */
    private byte[] getAltDigest()
    {
        byte [] digest = null;
        try {
            // if not inited yet then initialize digest
            digest = m_altDigest.digest();
            m_altDigest = null; // reset for next calculation
        } catch(Exception ex) {
            m_logger.error("Error calculating digest: " + ex);
            //ex.printStackTrace();
        }
        return digest;
    }

    /**
     * initializes the implementation class
     */
    public void init() throws DigiDocException {
    }

    private void handleError(Exception err)
            throws DigiDocException
    {
        if(m_logger.isDebugEnabled())
            m_logger.debug("Handle err: " + err + " list: " + (m_errs != null));
        err.printStackTrace();

        DigiDocException err1 = null;
        if(err instanceof SAXDigiDocException) {
            err1 = ((SAXDigiDocException)err).getDigiDocException();
        } else if(err instanceof DigiDocException) {
            err1 = (DigiDocException)err;
            err1.printStackTrace();
            if(err1.getNestedException() != null)
                err1.getNestedException().printStackTrace();
        } else
            err1 = new DigiDocException(DigiDocException.ERR_PARSE_XML, "Invalid xml file!", err);

        if(m_errs != null)
            m_errs.add(err1);
        else
            throw err1;
    }

    private void handleSAXError(Exception err)
            throws SAXDigiDocException
    {
        if(m_logger.isDebugEnabled()) {
            m_logger.debug("Handle sa err: " + err + " list: " + (m_errs != null));
            m_logger.debug("Trace: " + ConvertUtils.getTrace(err));
        }
        DigiDocException err1 = null;
        SAXDigiDocException err2 = null;
        if(err instanceof SAXDigiDocException) {
            err1 = ((SAXDigiDocException)err).getDigiDocException();
            err2 = (SAXDigiDocException)err;
        } else if(err instanceof DigiDocException) {
            err1 = (DigiDocException)err;
            err2 = new SAXDigiDocException(err.getMessage());
            err2.setNestedException(err);
        } else {
            err1 = new DigiDocException(0, err.getMessage(), null);
            err2 = new SAXDigiDocException(err.getMessage());
            err2.setNestedException(err);
        }
        if(m_errs != null)
            m_errs.add(err1);
        else
            throw err2;
    }


    /**
     * Reads in a DDoc file. One of fname or isSdoc must be given.
     * @param fname signed doc filename
     * @param isSdoc opened stream with DigiDoc data
     * The user must open and close it.
     * @param errs list of errors to fill with parsing errors. If given
     * then attempt is made to continue parsing on errors and return them in this list.
     * If not given (null) then the first error found will be thrown.
     * @return signed document object if successfully parsed
     */
    private SignedDoc readSignedDocOfType(String fname, InputStream isSdoc, List errs)
            throws DigiDocException
    {
        // Use an instance of ourselves as the SAX event handler
        SAXDigiDocFactory handler = this;
        m_errs = errs;
        DigiDocVerifyFactory.initProvider();
        SAXParserFactory factory = SAXParserFactory.newInstance();
        if(m_logger.isDebugEnabled())
            m_logger.debug("Start reading ddoc " + ((fname != null) ? "from file: " + fname : "from stream"));
        if(fname == null && isSdoc == null) {
            throw new DigiDocException(DigiDocException.ERR_READ_FILE, "No input file", null);
        }
        if(fname != null) {
            File inFile = new File(fname);
            if(!inFile.canRead() || inFile.length() == 0) {
                throw new DigiDocException(DigiDocException.ERR_READ_FILE, "Empty or unreadable input file", null);
            }
        }
        try {
            factory.setFeature("http://xml.org/sax/features/external-general-entities", false);
            factory.setFeature("http://xml.org/sax/features/external-parameter-entities", false);

            if(m_logger.isDebugEnabled())
                m_logger.debug("Reading ddoc: " + fname + " file: " + m_fileName);
            m_fileName = fname;
            SAXParser saxParser = factory.newSAXParser();
            if(fname != null)
                saxParser.parse(new SignatureInputStream(new FileInputStream(fname)), this);
            else if(isSdoc != null)
                saxParser.parse(new SignatureInputStream(isSdoc), this);
        } catch(org.xml.sax.SAXParseException ex) {
            m_logger.error("SAX Error: " + ex);
            handleError(ex);
        } catch (Exception ex) {
            m_logger.error("Error reading3: " + ex);
            ex.printStackTrace();
			/*if(ex instanceof DigiDocException){
				DigiDocException dex = (DigiDocException)ex;
				m_logger.error("Dex: " + ex);
				if(dex.getNestedException() != null) {
					dex.getNestedException().printStackTrace();
					m_logger.error("Trace: ");
				}
			}*/
            handleError(ex);
        }
        boolean bErrList = (errs != null);
        if(errs == null)
            errs = new ArrayList();
        if(m_doc == null) {
            m_logger.error("Error reading4: doc == null");
            handleError(new DigiDocException(DigiDocException.ERR_DIGIDOC_BADXML,
                    "This document is not in ddoc format", null));
        }
        if(!bErrList && errs.size() > 0) { // if error list was not used then we have to throw exception. So we will throw the first one since we can only do it once
            DigiDocException ex = (DigiDocException)errs.get(0);
            throw ex;
        }
        return m_doc;
    }



    /**
     * Reads in a DDoc file
     * @param fname filename
     * @return signed document object if successfully parsed
     */
    public SignedDoc readSignedDoc(String fname)
            throws DigiDocException
    {
        return readSignedDocOfType(fname, null, null);
    }

    /**
     * Reads in a DDoc from stream.
     * @param is opened stream with DDoc data
     * The user must open and close it.
     * @return signed document object if successfully parsed
     * @deprecated use readSignedDocFromStreamOfType(InputStream is, List lerr)
     */
    public SignedDoc readSignedDocFromStream(InputStream is)
            throws DigiDocException
    {
        return readSignedDocOfType(null, is, null);
    }

    /**
     * Reads in a DDoc file
     * @param fname filename
     * @param lerr list of errors to be filled. If not null then no exceptions are thrown
     * but returned in this array
     * @return signed document object if successfully parsed
     */
    public SignedDoc readSignedDoc(String fname, List lerr)
            throws DigiDocException
    {
        return readSignedDocOfType(fname, null, lerr);
    }

    /**
     * Reads in a DigiDoc or BDOC from stream. In case of BDOC a Zip stream will be
     * constructed to read this input stream. In case of ddoc a normal saxparsing stream
     * will be used.
     * @param is opened stream with DigiDoc/BDOC data
     * The user must open and close it.
     * @param lerr list of errors to be filled. If not null then no exceptions are thrown
     * but returned in this array
     * @return signed document object if successfully parsed
     */
    public SignedDoc readSignedDocFromStream(InputStream is, List lerr)
            throws DigiDocException
    {
        return readSignedDocOfType(null, is, lerr);
    }

    /**
     * Reads in a DigiDoc file
     * @param digiSigStream opened stream with Signature data
     * The user must open and close it.
     * @return signed document object if successfully parsed
     */
    public Signature readSignature(InputStream digiSigStream)
            throws DigiDocException
    {
        try {
            SAXParserFactory factory = SAXParserFactory.newInstance();
            factory.setFeature("http://xml.org/sax/features/external-general-entities", false);
            factory.setFeature("http://xml.org/sax/features/external-parameter-entities", false);
            SAXParser saxParser = factory.newSAXParser();
            saxParser.parse(digiSigStream, this);
        } catch (SAXDigiDocException ex) {
            throw ex.getDigiDocException();
        } catch (Exception ex) {
            DigiDocException.handleException(ex, DigiDocException.ERR_PARSE_XML);
        }
        if (m_sig == null)
            throw new DigiDocException(DigiDocException.ERR_DIGIDOC_FORMAT,
                    "This document is not in signature format", null);
        return m_sig;
    }

    /**
     * Helper method to canonicalize a piece of xml
     * @param xml data to be canonicalized
     * @return canonicalized xml
     */
    private String canonicalizeXml(String xml) {
        try {
            CanonicalizationFactory canFac = ConfigManager.
                    instance().getCanonicalizationFactory();
            byte[] tmp = canFac.canonicalize(xml.getBytes("UTF-8"),
                    SignedDoc.CANONICALIZATION_METHOD_20010315);
            return new String(tmp, "UTF-8");
        } catch(Exception ex) {
            m_logger.error("Canonicalizing exception: " + ex);
        }
        return null;
    }

    public Signature getLastSignature() {
        if(m_doc != null)
            return m_doc.getLastSignature();
        else
            return m_sig;
    }

    /**
     * Start Document handler
     */
    public void startDocument() throws SAXException {
        m_nCollectMode = 0;
        m_xmlnsAttr = null;
        m_dfCacheOutStream = null;
        m_nsDsPref = null;
        m_nsXadesPref = null;
        m_nsAsicPref = null;
    }

    private void findCertIDandCertValueTypes(Signature sig)
    {
        if(m_logger.isDebugEnabled() && sig != null)
            m_logger.debug("Sig: " + sig.getId() + " certids: " + sig.countCertIDs());
        for(int i = 0; (sig != null) && (i < sig.countCertIDs()); i++) {
            CertID cid = sig.getCertID(i);
            if(cid != null && cid.getType() == CertID.CERTID_TYPE_UNKNOWN) {
                if(m_logger.isDebugEnabled())
                    m_logger.debug("CertId: " + cid.getId() + " type: " + cid.getType() + " nr: " + cid.getSerial());
                CertValue cval = sig.findCertValueWithSerial(cid.getSerial());
                if(cval != null) {
                    String cn = null;
                    try {
                        cn = SignedDoc.
                                getCommonName(cval.getCert().getSubjectDN().getName());
                        if(m_logger.isDebugEnabled() && cid != null)
                            m_logger.debug("CertId type: " + cid.getType() + " nr: " + cid.getSerial() + " cval: " + cval.getId() + " CN: " + cn);
                        if(ConvertUtils.isKnownOCSPCert(cn)) {
                            if(m_logger.isInfoEnabled())
                                m_logger.debug("Cert: " + cn + " is OCSP responders cert");
                            cid.setType(CertID.CERTID_TYPE_RESPONDER);
                            cval.setType(CertValue.CERTVAL_TYPE_RESPONDER);
                        }
                        if(ConvertUtils.isKnownTSACert(cn)) {
                            if(m_logger.isDebugEnabled())
                                m_logger.debug("Cert: " + cn + " is TSA cert");
                            cid.setType(CertID.CERTID_TYPE_TSA);
                            cval.setType(CertValue.CERTVAL_TYPE_TSA);
                            if(m_logger.isDebugEnabled())
                                m_logger.debug("CertId: " + cid.getId() + " type: " + cid.getType() + " nr: " + cid.getSerial());
                        }
                    } catch(DigiDocException ex) {
                        m_logger.error("Error setting type on certid or certval: " + cn);
                    }
                }
            }

        } // for i < sig.countCertIDs()
        if(m_logger.isDebugEnabled())
            m_logger.debug("Sig: " + sig.getId() + " certvals: " + sig.countCertValues());
        for(int i = 0; (sig != null) && (i < sig.countCertValues()); i++) {
            CertValue cval = sig.getCertValue(i);
            if(m_logger.isDebugEnabled() && cval != null)
                m_logger.debug("CertValue: " + cval.getId() + " type: " + cval.getType());
            if(cval.getType() == CertValue.CERTVAL_TYPE_UNKNOWN) {
                String cn = null;
                try {
                    cn = SignedDoc.
                            getCommonName(cval.getCert().getSubjectDN().getName());
                    if(ConvertUtils.isKnownOCSPCert(cn)) {
                        if(m_logger.isDebugEnabled())
                            m_logger.debug("Cert: " + cn + " is OCSP responders cert");
                        cval.setType(CertValue.CERTVAL_TYPE_RESPONDER);
                    }
                    if(ConvertUtils.isKnownTSACert(cn)) {
                        if(m_logger.isDebugEnabled())
                            m_logger.debug("Cert: " + cn + " is TSA cert");
                        cval.setType(CertValue.CERTVAL_TYPE_TSA);
                    }
                } catch(DigiDocException ex) {
                    m_logger.error("Error setting type on certid or certval: " + cn);
                }
            }
        }
    }

    /**
     * End Document handler
     */
    public void endDocument()
            throws SAXException
    {
    }


    private String findNsPrefForUri(Attributes attrs, String uri)
    {
        for(int i = 0; i < attrs.getLength(); i++) {
            String key = attrs.getQName(i);
            String val = attrs.getValue(i);
            if(val.equals(uri)) {
                int p = key.indexOf(':');
                if(p > 0)
                    return key.substring(p+1);
                else
                    return null;
            }
        }
        return null;
    }

    private String findAttrValueByName(Attributes attrs, String aName)
    {
        for(int i = 0; i < attrs.getLength(); i++) {
            String key = attrs.getQName(i);
            if (key.equalsIgnoreCase(aName)) {
                return attrs.getValue(i);
            }
        }
        return null;
    }

    /**
     * Start Element handler
     * @param namespaceURI namespace URI
     * @param lName local name
     * @param qName qualified name
     * @param attrs attributes
     */
    public void startElement(String namespaceURI, String lName, String qName, Attributes attrs)
            throws SAXDigiDocException
    {
        if(m_logger.isDebugEnabled())
            m_logger.debug("Start Element: "	+ qName + " lname: "  + lName + " uri: " + namespaceURI);
        String tag = qName;
        if(tag.indexOf(':') != -1) {
            tag = qName.substring(qName.indexOf(':') + 1);
            if(m_nsDsPref == null) {
                m_nsDsPref = findNsPrefForUri(attrs, xmlnsDs);
                if(m_logger.isDebugEnabled())
                    m_logger.debug("Element: " + qName + " xmldsig pref: " + ((m_nsDsPref != null) ? m_nsDsPref : "NULL"));
            }
            if(m_nsXadesPref == null) {
                m_nsXadesPref = findNsPrefForUri(attrs, xmlnsEtsi);
                if(m_logger.isDebugEnabled())
                    m_logger.debug("Element: " + qName + " xades pref: " + ((m_nsXadesPref != null) ? m_nsXadesPref : "NULL"));
            }
            if(m_nsAsicPref == null) {
                m_nsAsicPref = findNsPrefForUri(attrs, xmlnsAsic);
                if(m_logger.isDebugEnabled())
                    m_logger.debug("Element: " + qName + " asic pref: " + ((m_nsAsicPref != null) ? m_nsAsicPref : "NULL"));
            }
        }
        // record elements found
        XmlElemInfo e = new XmlElemInfo(tag, findAttrValueByName(attrs, "id"),
                (tag.equals("XAdESSignatures") || tag.equals("SignedDoc")) ? null : m_elemCurrent);
        //  and  cannot be child of another element, must be root elements
        if(m_elemCurrent != null && !tag.equals("XAdESSignatures") && !tag.equals("SignedDoc"))
            m_elemCurrent.addChild(e);
        m_elemCurrent = e;
        if(m_elemRoot == null || tag.equals("XAdESSignatures") || tag.equals("SignedDoc"))
            m_elemRoot = e;
        DigiDocException exv = DigiDocStructureValidator.validateElementPath(m_elemCurrent);
        if(exv != null)
            handleSAXError(exv);

        m_tags.push(tag);
        if(tag.equals("SigningTime") ||
                tag.equals("IssuerSerial") ||
                tag.equals("X509SerialNumber") ||
                tag.equals("X509IssuerName") ||
                tag.equals("ClaimedRole") ||
                tag.equals("City") ||
                tag.equals("StateOrProvince") ||
                tag.equals("CountryName") ||
                tag.equals("PostalCode") ||
                tag.equals("SignatureValue") ||
                tag.equals("DigestValue") ||
                //qName.equals("EncapsulatedX509Certificate") ||
                tag.equals("IssuerSerial") ||
                (tag.equals("ResponderID")) ||
                tag.equals("X509SerialNumber") ||
                tag.equals("ProducedAt") ||
                tag.equals("EncapsulatedTimeStamp") ||
                tag.equals("Identifier") ||
                tag.equals("SPURI") ||
                tag.equals("NonceAlgorithm") ||
                tag.equals("MimeType") ||
                tag.equals("EncapsulatedOCSPValue") ) {
            if(m_logger.isDebugEnabled())
                m_logger.debug("Start collecting tag: " + tag);
            m_sbCollectItem = new StringBuffer();
        }

        // 
        // Prepare CertValue object
        if(tag.equals("X509Certificate")) {
            Signature sig = getLastSignature();
            CertValue cval = null;
            try {
                if (m_logger.isDebugEnabled())
                    m_logger.debug("Adding signers cert to: " + sig.getId());
                cval = sig.getOrCreateCertValueOfType(CertValue.CERTVAL_TYPE_SIGNER);
            } catch(DigiDocException ex) {
                handleSAXError(ex);
            }
            m_sbCollectItem = new StringBuffer();
        }
        // 
        // Prepare CertValue object and record it's id
        if(tag.equals("EncapsulatedX509Certificate")) {
            Signature sig = getLastSignature();
            String id = null;
            for(int i = 0; i < attrs.getLength(); i++) {
                String key = attrs.getQName(i);
                if (key.equalsIgnoreCase("Id")) {
                    id = attrs.getValue(i);
                }
            }
            CertValue cval = new CertValue();
            if(id != null) {
                cval.setId(id);
                try {
                    if(id.indexOf("RESPONDER_CERT") != -1 ||
                            id.indexOf("RESPONDER-CERT") != -1)
                        cval.setType(CertValue.CERTVAL_TYPE_RESPONDER);
                } catch(DigiDocException ex) {
                    handleSAXError(ex);
                }
            }
            if(m_logger.isDebugEnabled() && cval != null)
                m_logger.debug("Adding cval " + cval.getId() + " type: " + cval.getType() + " to: " + sig.getId());
            sig.addCertValue(cval);
            m_sbCollectItem = new StringBuffer();
        }
        // the following elements switch collect mode
        // in and out
        // 
        boolean bDfDdoc13Bad = false;
        if(tag.equals("DataFile")) {
            String ContentType = null, Filename = null, Id = null, MimeType = null, Size = null, DigestType = null, Codepage = null;
            byte[] DigestValue = null;
            m_digest = null; // init to null
            if (m_doc != null &&
                    m_doc.getFormat().equals(SignedDoc.FORMAT_DIGIDOC_XML) &&
                    m_doc.getVersion().equals(SignedDoc.VERSION_1_3)) {
                m_xmlnsAttr = SignedDoc.xmlns_digidoc13;
                bDfDdoc13Bad = true; // possible case for ddoc 1.3 invalid namespace problem
            } else
                m_xmlnsAttr = null;
            ArrayList dfAttrs = new ArrayList();
            for (int i = 0; i < attrs.getLength(); i++) {
                String key = attrs.getQName(i);
                if (key.equals("ContentType")) {
                    ContentType = attrs.getValue(i);
                } else if (key.equals("Filename")) {
                    Filename = attrs.getValue(i);
                    if(Filename.indexOf('/') != -1 || Filename.indexOf('\\') != -1) {
                        DigiDocException ex = new DigiDocException(DigiDocException.ERR_DF_NAME, "Failed to parse DataFile name. Invalid file name!", null);
                        handleSAXError(ex);
                    }
                } else if (key.equals("Id")) {
                    Id = attrs.getValue(i);
                } else if (key.equals("MimeType")) {
                    MimeType = attrs.getValue(i);
                } else if (key.equals("Size")) {
                    Size = attrs.getValue(i);
                } else if (key.equals("DigestType")) {
                    DigestType = attrs.getValue(i);
                } else if (key.equals("Codepage")) {
                    Codepage = attrs.getValue(i);
                } else if (key.equals("DigestValue")) {
                    DigestValue = Base64Util.decode(attrs.getValue(i));
                } else {
                    try {
                        if (!key.equals("xmlns")) {
                            DataFileAttribute attr = new DataFileAttribute(key, attrs.getValue(i));
                            dfAttrs.add(attr);
                        } else {
                            bDfDdoc13Bad = false; // nope, this one has it's own xmlns
                        }
                    } catch (DigiDocException ex) {
                        handleSAXError(ex);
                    }
                } // else
            } // for
            if(m_nCollectMode == 0) {
                try {
                    DataFile df = new DataFile(Id, ContentType, Filename, MimeType, m_doc);
                    m_dfCacheOutStream = null; // default is don't use cache file
                    if (Size != null)
                        df.setSize(Long.parseLong(Size));
                    if (DigestValue != null) {
                        if(m_doc.getFormat().equals(SignedDoc.FORMAT_SK_XML))
                            df.setAltDigest(DigestValue);
                        if(ContentType != null && ContentType.equals(DataFile.CONTENT_HASHCODE))
                            df.setDigestValue(DigestValue);
                    }
                    if (Codepage != null)
                        df.setInitialCodepage(Codepage);
                    for (int i = 0; i < dfAttrs.size(); i++)
                        df.addAttribute((DataFileAttribute) dfAttrs.get(i));
                    // enable caching if requested
                    if(m_tempDir != null) {
                        File fCache = new File(m_tempDir + File.separator + df.getFileName());
                        if(m_logger.isDebugEnabled())
                            m_logger.debug("Parser temp DF: " + Id + " size: " + df.getSize() +
                                    " cache-file: " + fCache.getAbsolutePath());
                        m_dfCacheOutStream = new FileOutputStream(fCache);
                        df.setCacheFile(fCache);
                    } else if(df.schouldUseTempFile()) {
                        File fCache = df.createCacheFile();
                        if(m_logger.isDebugEnabled())
                            m_logger.debug("Df-temp DF: " + Id + " size: " + df.getSize() +
                                    " cache-file: " + fCache.getAbsolutePath());
                        df.setCacheFile(fCache);
                        m_dfCacheOutStream = new FileOutputStream(fCache);
                    }
                    m_doc.addDataFile(df);
                } catch (IOException ex) {
                    handleSAXError(ex);
                } catch (DigiDocException ex) {
                    handleSAXError(ex);
                }
            }
            m_nCollectMode++;
            // try to anticipate how much memory we need for collecting this 
            try {
                if(Size != null) {
                    int nSize = Integer.parseInt(Size);
                    if(!ContentType.equals(DataFile.CONTENT_HASHCODE)) {
                        if(ContentType.equals(DataFile.CONTENT_EMBEDDED_BASE64)) {
                            nSize *= 2;
                            m_bCollectDigest = true;
                            if(m_logger.isDebugEnabled())
                                m_logger.debug("Start collecting digest");
                        }
                        if(m_doc.getFormat().equals(SignedDoc.FORMAT_SK_XML))
                            m_bCollectDigest = false;
                        if(m_logger.isDebugEnabled())
                            m_logger.debug("Allocating buf: " + nSize + " Element: "	+ qName + " lname: "  + lName + " uri: " + namespaceURI);
                        if(m_dfCacheOutStream == null) // if we use temp files then we don't cache in memory
                            m_sbCollectChars = new StringBuffer(nSize);
                    }
                }
            } catch(Exception ex) {
                m_logger.error("Error: " + ex);
            }
        }

        //
        if(tag.equals("SignedInfo")) {
            if (m_nCollectMode == 0) {
                try {
                    if (m_doc != null &&
                            (m_doc.getVersion().equals(SignedDoc.VERSION_1_3) ||
                                    m_doc.getFormat().equals(SignedDoc.FORMAT_SK_XML)))
                        m_xmlnsAttr = null;
                    else
                        m_xmlnsAttr = SignedDoc.xmlns_xmldsig;
                    Signature sig = getLastSignature();
                    SignedInfo si = new SignedInfo(sig);
                    if(sig != null) {
                        sig.setSignedInfo(si);
                        String Id = attrs.getValue("Id");
                        if(Id != null)
                            si.setId(Id);
                    }
                } catch (DigiDocException ex) {
                    handleSAXError(ex);
                }
            }
            m_nCollectMode++;
            m_sbCollectChars = new StringBuffer(1024);
        }
        // 
        if(tag.equals("SignedProperties")) {
            String Id = attrs.getValue("Id");
            String Target = attrs.getValue("Target");
            if (m_nCollectMode == 0) {
                try {
                    if(m_doc != null &&
                            (m_doc.getVersion().equals(SignedDoc.VERSION_1_3)))
                        m_xmlnsAttr = null;
                    else
                        m_xmlnsAttr = SignedDoc.xmlns_xmldsig;
                    Signature sig = getLastSignature();
                    SignedProperties sp = new SignedProperties(sig);
                    sp.setId(Id);
                    if(Target != null)
                        sp.setTarget(Target);
                    sig.setSignedProperties(sp);
                } catch (DigiDocException ex) {
                    handleSAXError(ex);
                }
            }
            m_nCollectMode++;
            m_sbCollectChars = new StringBuffer(2048);
        }
        // 
        if(tag.equals("XAdESSignatures") && m_nCollectMode == 0) {
            if (m_logger.isDebugEnabled())
                m_logger.debug("Start collecting ");
            m_sbCollectSignature = new StringBuffer();
        }
        // 
        if(tag.equals("Signature") && m_nCollectMode == 0) {
            if (m_logger.isDebugEnabled())
                m_logger.debug("Start collecting ");
            if(m_doc == null) {
                DigiDocException ex = new DigiDocException(DigiDocException.ERR_PARSE_XML, "Invalid signature format. Missing signed container root element.", null);
                handleSAXError(ex); // now stop parsing
                SAXDigiDocException sex1 = new SAXDigiDocException("Invalid signature format. Missing signed container root element.");
                throw sex1;
            }
            String str1 = attrs.getValue("Id");
            Signature sig = null;
            // in case of ddoc-s try find existing signature.
            // to support libc++ buggy implementation with non-unique id atributes
            if(m_doc != null)
                sig = m_doc.findSignatureById(str1);
            if(sig == null || (sig.getId() != null && !sig.getId().equals(str1))) {
                if (m_logger.isDebugEnabled())
                    m_logger.debug("Create signature: " + str1);
                if(m_doc != null) {
                    sig = new Signature(m_doc);
                    try {
                        sig.setId(str1);
                    } catch (DigiDocException ex) {
                        handleSAXError(ex);
                    }
                    sig.setPath(m_fileName);
                    sig.setComment(m_sigComment);
                    String sProfile = m_doc.findSignatureProfile(m_fileName);
                    if(sProfile == null)
                        sProfile = m_doc.findSignatureProfile(sig.getId());
                    if(sProfile != null)
                        sig.setProfile(sProfile);
					/*if(sProfile == null &&
							(m_doc.getFormat().equals(SignedDoc.FORMAT_DIGIDOC_XML) ||
									m_doc.getFormat().equals(SignedDoc.FORMAT_SK_XML)))
						sig.setProfile(SignedDoc.PROFILE_TM);*/
                    m_doc.addSignature(sig);
                    if (m_logger.isDebugEnabled())
                        m_logger.debug("Sig1: " + m_fileName + " profile: " + sProfile + " doc: " + ((m_doc != null) ? "OK" : "NULL"));
                } else {
                    m_sig = new Signature(null);
                    m_sig.setPath(m_fileName);
                    m_sig.setComment(m_sigComment);
                    String sProfile = null;
                    if(m_doc != null && m_fileName != null)
                        sProfile = m_doc.findSignatureProfile(m_fileName);
                    if(sProfile != null)
                        m_sig.setProfile(sProfile);
                    if (m_logger.isDebugEnabled())
                        m_logger.debug("Sig2: " + m_fileName + " profile: " + sProfile);
                    sig = m_sig;
                }
            }
            if(m_sbCollectSignature == null)
                m_sbCollectSignature = new StringBuffer();
        }
        // 
        if(tag.equals("SignatureValue") && m_nCollectMode == 0) {
            m_strSigValTs = null;
            m_nCollectMode++;
            m_sbCollectChars = new StringBuffer(1024);
        }
        // collect  data
        if(m_sbCollectSignature != null) {
            m_sbCollectSignature.append("<");
            m_sbCollectSignature.append(qName);
            for (int i = 0; i < attrs.getLength(); i++) {
                m_sbCollectSignature.append(" ");
                m_sbCollectSignature.append(attrs.getQName(i));
                m_sbCollectSignature.append("=\"");
                String s = attrs.getValue(i);
                s = s.replaceAll("&", "&");
                m_sbCollectSignature.append(s);
                m_sbCollectSignature.append("\"");
            }
            m_sbCollectSignature.append(">");
        }
        // if we just switched to collect-mode
        // collect SAX event data to original XML data
        // for  we don't collect the begin and
        // end tags unless this an embedded 
        if(m_nCollectMode > 0 || m_sbCollectChars != null) {
            StringBuffer sb = new StringBuffer();
            String sDfTagBad = null;
            sb.append("<");
            sb.append(qName);
            for (int i = 0; i < attrs.getLength(); i++) {
                if(attrs.getQName(i).equals("xmlns")) {
                    m_xmlnsAttr = null; // allready have it from document
                    bDfDdoc13Bad = false;
                }
                sb.append(" ");
                sb.append(attrs.getQName(i));
                sb.append("=\"");
                if(m_logger.isDebugEnabled())
                    m_logger.debug("Attr: " + attrs.getQName(i) + " =\'" + attrs.getValue(i) + "\'");

                if(!m_doc.getFormat().equals(SignedDoc.FORMAT_SK_XML)) {
                    sb.append(ConvertUtils.escapeXmlSymbols(attrs.getValue(i)));
                } else {
                    String sv = attrs.getValue(i);
                    if(attrs.getQName(i).equals("DigestValue") && sv.endsWith(" "))
                        sv = sv.replaceAll(" ", "\n");
                    sb.append(sv);
                }
                sb.append("\"");
            }
            if(bDfDdoc13Bad)
                sDfTagBad = sb.toString() + ">";
            if (m_xmlnsAttr != null) {
                sb.append(" xmlns=\"" + m_xmlnsAttr + "\"");
                m_xmlnsAttr = null;
            }
            sb.append(">");
            //canonicalize & calculate digest over DataFile begin-tag without content
            if(tag.equals("DataFile") && m_nCollectMode == 1) {
                String strCan = null;
                if(!m_doc.getFormat().equals(SignedDoc.FORMAT_SK_XML)) {
                    strCan = sb.toString() + "";
                    strCan = canonicalizeXml(strCan);
                    strCan = strCan.substring(0, strCan.length() - 11);
                    if(m_logger.isDebugEnabled())
                        m_logger.debug("Canonicalized: \'" + strCan + "\'");
                    if(sDfTagBad != null) {
                        strCan = sDfTagBad + "";
                        strCan = canonicalizeXml(strCan);
                        sDfTagBad = strCan.substring(0, strCan.length() - 11);
                        if(m_logger.isDebugEnabled())
                            m_logger.debug("Canonicalized alternative: \'" + sDfTagBad + "\'");
                    }
                    try {
                        updateDigest(ConvertUtils.str2data(strCan));
                        if(sDfTagBad != null)
                            updateAltDigest(ConvertUtils.str2data(sDfTagBad));
                    } catch (DigiDocException ex) {
                        handleSAXError(ex);
                    }
                }
            } // we don't collect  begin and end - tags and we don't collect if we use temp files
            else {
                if(m_sbCollectChars != null)
                    m_sbCollectChars.append(sb.toString());
                try {
                    if(m_dfCacheOutStream != null)
                        m_dfCacheOutStream.write(ConvertUtils.str2data(sb.toString()));
                } catch (IOException ex) {
                    handleSAXError(ex);
                } catch (DigiDocException ex) {
                    handleSAXError(ex);
                }
            }
        }

        // the following stuff is used also on level 1
        // because it can be part of SignedInfo or SignedProperties
        if(m_nCollectMode == 1)  {
            // 
            if(tag.equals("CanonicalizationMethod")) {
                String Algorithm = attrs.getValue("Algorithm");
                try {
                    Signature sig = getLastSignature();
                    SignedInfo si = sig.getSignedInfo();
                    si.setCanonicalizationMethod(Algorithm);
                } catch (DigiDocException ex) {
                    handleSAXError(ex);
                }
            }
            // 
            if(tag.equals("SignatureMethod")) {
                String Algorithm = attrs.getValue("Algorithm");
                try {
                    Signature sig = getLastSignature();
                    SignedInfo si = sig.getSignedInfo();
                    si.setSignatureMethod(Algorithm);
                } catch (DigiDocException ex) {
                    handleSAXError(ex);
                }
            }
            // 
            if(tag.equals("Reference")) {
                String URI = attrs.getValue("URI");
                try {
                    Signature sig = getLastSignature();
                    SignedInfo si = sig.getSignedInfo();
                    Reference ref = new Reference(si);
                    String Id = attrs.getValue("Id");
                    if(Id != null)
                        ref.setId(Id);
                    if (URI==null) {
                        DigiDocException ex = new DigiDocException(DigiDocException.ERR_DATA_FILE_ATTR_VALUE,"URI Attribute value is required", null);
                        handleSAXError(ex);
                    } else {
                      ref.setUri(ConvertUtils.unescapeXmlSymbols(ConvertUtils.uriDecode(URI)));
                    }
                    String sType = attrs.getValue("Type");
                    if(sType != null)
                        ref.setType(sType);
                    si.addReference(ref);
                } catch (DigiDocException ex) {
                    handleSAXError(ex);
                }
            }
            // 
            if(tag.equals("X509SerialNumber") && m_doc != null
                    && m_doc.getFormat().equals(SignedDoc.FORMAT_DIGIDOC_XML))
            {
                String sXmlns = attrs.getValue("xmlns");
                if(sXmlns == null || !sXmlns.equals(SignedDoc.xmlns_xmldsig)) {
                    if(m_logger.isDebugEnabled())
                        m_logger.debug("X509SerialNumber has none or invalid namespace: " + sXmlns);
                    DigiDocException ex = new DigiDocException(DigiDocException.ERR_ISSUER_XMLNS, "X509SerialNumber has none or invalid namespace: " + sXmlns, null);
                    handleSAXError(ex);
                }
            }
            // 
            if(tag.equals("X509IssuerName") && m_doc != null
                    && m_doc.getFormat().equals(SignedDoc.FORMAT_DIGIDOC_XML))
            {
                String sXmlns = attrs.getValue("xmlns");
                if(sXmlns == null || !sXmlns.equals(SignedDoc.xmlns_xmldsig)) {
                    if(m_logger.isDebugEnabled())
                        m_logger.debug("X509IssuerName has none or invalid namespace: " + sXmlns);
                    DigiDocException ex = new DigiDocException(DigiDocException.ERR_ISSUER_XMLNS, "X509IssuerName has none or invalid namespace: " + sXmlns, null);
                    handleSAXError(ex);
                }
            }
            // 
            if(tag.equals("SignatureProductionPlace")) {
                try {
                    Signature sig = getLastSignature();
                    SignedProperties sp = sig.getSignedProperties();
                    SignatureProductionPlace spp =
                            new SignatureProductionPlace();
                    sp.setSignatureProductionPlace(spp);
                } catch (DigiDocException ex) {
                    handleSAXError(ex);
                }
            }
        }
        // the following is collected anyway independent of collect mode
        // 
        if(tag.equals("SignatureValue")) {
            String Id = attrs.getValue("Id");
            try {
                Signature sig = getLastSignature();
                SignatureValue sv = new SignatureValue(sig, Id);
            } catch (DigiDocException ex) {
                handleSAXError(ex);
            }
        }
        // 
        if(tag.equals("OCSPRef")) {
            OcspRef orf = new OcspRef();
            Signature sig = getLastSignature();
            UnsignedProperties usp = sig.getUnsignedProperties();
            CompleteRevocationRefs rrefs = usp.getCompleteRevocationRefs();
            rrefs.addOcspRef(orf);
        }
        // 
        if(tag.equals("DigestMethod")) {
            String Algorithm = attrs.getValue("Algorithm");
            try {
                if(m_tags.search("Reference") != -1) {
                    Signature sig = getLastSignature();
                    SignedInfo si = sig.getSignedInfo();
                    Reference ref = si.getLastReference();
                    ref.setDigestAlgorithm(Algorithm);
                } else if(m_tags.search("SigningCertificate") != -1) {
                    Signature sig = getLastSignature();
                    CertID cid = sig.getOrCreateCertIdOfType(CertID.CERTID_TYPE_SIGNER);
                    cid.setDigestAlgorithm(Algorithm);
                } else if(m_tags.search("CompleteCertificateRefs") != -1) {
                    Signature sig = getLastSignature();
                    CertID cid = sig.getLastCertId(); // initially set to unknown type !
                    cid.setDigestAlgorithm(Algorithm);
                } else if(m_tags.search("CompleteRevocationRefs") != -1) {
                    Signature sig = getLastSignature();
                    UnsignedProperties up = sig.getUnsignedProperties();
                    CompleteRevocationRefs rrefs = up.getCompleteRevocationRefs();
                    OcspRef orf = rrefs.getLastOcspRef();
                    if(orf != null)
                        orf.setDigestAlgorithm(Algorithm);
                } else if(m_tags.search("SigPolicyHash") != -1) {
                    Signature sig = getLastSignature();
                    SignedProperties sp = sig.getSignedProperties();
                    SignaturePolicyIdentifier spi = sp.getSignaturePolicyIdentifier();
                    SignaturePolicyId sppi = spi.getSignaturePolicyId();
                    sppi.setDigestAlgorithm(Algorithm);
                }
            } catch (DigiDocException ex) {
                handleSAXError(ex);
            }
        }
        // 
        if(tag.equals("Cert")) {
            String id = attrs.getValue("Id");
            try {
                Signature sig = getLastSignature();
                if(m_tags.search("SigningCertificate") != -1) {
                    CertID cid = sig.getOrCreateCertIdOfType(CertID.CERTID_TYPE_SIGNER);
                    if(id != null)
                        cid.setId(id);
                }
                if(m_tags.search("CompleteCertificateRefs") != -1) {
                    //CertID cid = new CertID();
                    CertID cid = sig.getOrCreateCertIdOfType(CertID.CERTID_TYPE_RESPONDER);
                    if(id != null)
                        cid.setId(id);
                    sig.addCertID(cid);
                }
            } catch (DigiDocException ex) {
                handleSAXError(ex);
            }
        }
        // 
        if(tag.equals("AllDataObjectsTimeStamp")) {
            String id = attrs.getValue("Id");
            try {
                Signature sig = getLastSignature();
                TimestampInfo ts = new TimestampInfo(id, TimestampInfo.TIMESTAMP_TYPE_ALL_DATA_OBJECTS);
                sig.addTimestampInfo(ts);
            } catch (DigiDocException ex) {
                handleSAXError(ex);
            }
        }
        // 
        if(tag.equals("IndividualDataObjectsTimeStamp")) {
            String id = attrs.getValue("Id");
            try {
                Signature sig = getLastSignature();
                TimestampInfo ts = new TimestampInfo(id, TimestampInfo.TIMESTAMP_TYPE_INDIVIDUAL_DATA_OBJECTS);
                sig.addTimestampInfo(ts);
            } catch (DigiDocException ex) {
                handleSAXError(ex);
            }
        }
        // 
        if(tag.equals("SignatureTimeStamp")) {
            String id = attrs.getValue("Id");
            try {
                Signature sig = getLastSignature();
                TimestampInfo ts = new TimestampInfo(id, TimestampInfo.TIMESTAMP_TYPE_SIGNATURE);
                sig.addTimestampInfo(ts);
            } catch (DigiDocException ex) {
                handleSAXError(ex);
            }
        }
        // 
        if(tag.equals("SigAndRefsTimeStamp")) {
            String id = attrs.getValue("Id");
            try {
                Signature sig = getLastSignature();
                TimestampInfo ts = new TimestampInfo(id, TimestampInfo.TIMESTAMP_TYPE_SIG_AND_REFS);
                sig.addTimestampInfo(ts);
            } catch (DigiDocException ex) {
                handleSAXError(ex);
            }
        }
        // 
        if(tag.equals("RefsOnlyTimeStamp")) {
            String id = attrs.getValue("Id");
            try {
                Signature sig = getLastSignature();
                TimestampInfo ts = new TimestampInfo(id, TimestampInfo.TIMESTAMP_TYPE_REFS_ONLY);
                sig.addTimestampInfo(ts);
            } catch (DigiDocException ex) {
                handleSAXError(ex);
            }
        }
        // 
        if(tag.equals("ArchiveTimeStamp")) {
            String id = attrs.getValue("Id");
            try {
                Signature sig = getLastSignature();
                TimestampInfo ts = new TimestampInfo(id, TimestampInfo.TIMESTAMP_TYPE_ARCHIVE);
                sig.addTimestampInfo(ts);
            } catch (DigiDocException ex) {
                handleSAXError(ex);
            }
        }
        // 
        if(tag.equals("Include")) {
            String uri = attrs.getValue("URI");
            try {
                Signature sig = getLastSignature();
                TimestampInfo ts = sig.getLastTimestampInfo();
                IncludeInfo inc = new IncludeInfo(uri);
                ts.addIncludeInfo(inc);
            } catch (DigiDocException ex) {
                handleSAXError(ex);
            }
        }
        // 
        if(tag.equals("CompleteCertificateRefs")) {
            String Target = attrs.getValue("Target");
            try {
                Signature sig = getLastSignature();
                UnsignedProperties up = sig.getUnsignedProperties();
                CompleteCertificateRefs crefs =
                        new CompleteCertificateRefs();
                up.setCompleteCertificateRefs(crefs);
                crefs.setUnsignedProperties(up);
            } catch (DigiDocException ex) {
                handleSAXError(ex);
            }
        }
        // 
        if(tag.equals("CompleteRevocationRefs")) {
            try {
                Signature sig = getLastSignature();
                UnsignedProperties up = sig.getUnsignedProperties();
                CompleteRevocationRefs rrefs = new CompleteRevocationRefs();
                up.setCompleteRevocationRefs(rrefs);
                rrefs.setUnsignedProperties(up);
            } catch (DigiDocException ex) {
                handleSAXError(ex);
            }
        }
        // 
        if(tag.equals("OCSPIdentifier")) {
            String URI = attrs.getValue("URI");
            try {
                Signature sig = getLastSignature();
                UnsignedProperties up = sig.getUnsignedProperties();
                CompleteRevocationRefs rrefs = up.getCompleteRevocationRefs();
                OcspRef orf = rrefs.getLastOcspRef();
                orf.setUri(URI);
            } catch (DigiDocException ex) {
                handleSAXError(ex);
            }
        }
        // 
        if(tag.equals("SignaturePolicyIdentifier")) {
            try {
                Signature sig = getLastSignature();
                SignedProperties sp = sig.getSignedProperties();
                SignaturePolicyIdentifier spid = sp.getSignaturePolicyIdentifier();
                if(spid == null) {
                    spid = new SignaturePolicyIdentifier(null);
                    sp.setSignaturePolicyIdentifier(spid);
                }
            } catch (DigiDocException ex) {
                handleSAXError(ex);
            }
        }
        // 
        if(tag.equals("SignaturePolicyId")) {
            try {
                Signature sig = getLastSignature();
                SignedProperties sp = sig.getSignedProperties();
                SignaturePolicyIdentifier spid = sp.getSignaturePolicyIdentifier();
                if(spid == null) {
                    spid = new SignaturePolicyIdentifier(null);
                    sp.setSignaturePolicyIdentifier(spid);
                }
                SignaturePolicyId spi = spid.getSignaturePolicyId();
                if(spi == null) {
                    spi = new SignaturePolicyId(null);
                    spid.setSignaturePolicyId(spi);
                }
            } catch (DigiDocException ex) {
                handleSAXError(ex);
            }
        }
        // 
        // cannot handle alone because we need mandatory Identifier value
        // 
        if(tag.equals("Identifier")) {
            try {
                Signature sig = getLastSignature();
                SignedProperties sp = sig.getSignedProperties();
                SignaturePolicyIdentifier spid = sp.getSignaturePolicyIdentifier();
                if(spid == null) {
                    spid = new SignaturePolicyIdentifier(null);
                    sp.setSignaturePolicyIdentifier(spid);
                }
                SignaturePolicyId spi = spid.getSignaturePolicyId();
                if(spi == null) {
                    spi = new SignaturePolicyId(null);
                    spid.setSignaturePolicyId(spi);
                }
                String sQualifier = attrs.getValue("Qualifier");
                Identifier id = new Identifier(sQualifier);
                ObjectIdentifier oi = spi.getSigPolicyId();
                if(oi == null)
                    oi = new ObjectIdentifier(id);
                else
                    oi.setIdentifier(id);
                spi.setSigPolicyId(oi);
            } catch (DigiDocException ex) {
                handleSAXError(ex);
            }
        }
        // 
        if(tag.equals("SigPolicyQualifier")) {
            try {
                Signature sig = getLastSignature();
                SignedProperties sp = sig.getSignedProperties();
                SignaturePolicyIdentifier spid = sp.getSignaturePolicyIdentifier();
                if(spid == null) {
                    spid = new SignaturePolicyIdentifier(null);
                    sp.setSignaturePolicyIdentifier(spid);
                }
                SignaturePolicyId spi = spid.getSignaturePolicyId();
                if(spi == null) {
                    spi = new SignaturePolicyId(null);
                    spid.setSignaturePolicyId(spi);
                }
                SigPolicyQualifier spq = new SigPolicyQualifier();
                spi.addSigPolicyQualifier(spq);
            } catch (DigiDocException ex) {
                handleSAXError(ex);
            }
        }

        // 
        if(tag.equals("DataObjectFormat")) {
            Signature sig = getLastSignature();
            try {
                if(sig != null) {
                    SignedProperties sp = sig.getSignedProperties();
                    if(sp != null) {
                        SignedDataObjectProperties sdps = sp.getSignedDataObjectProperties();
                        if(sdps == null) {
                            sdps = new SignedDataObjectProperties();
                            sp.setSignedDataObjectProperties(sdps);
                        }
                        String sObjectReference = attrs.getValue("ObjectReference");
                        DataObjectFormat dof = new DataObjectFormat(sObjectReference);
                        sdps.addDataObjectFormat(dof);
                    }
                }
            } catch (DigiDocException ex) {
                handleSAXError(ex);
            }
        }
        //  - give error?
        if(tag.equals("NonceAlgorithm")) {

        }
        // the following stuff is ignored in collect mode
        // because it can only be the content of a higher element
        if(m_nCollectMode == 0) {
            // 
            if(tag.equals("SignedDoc")) {
                String format = null, version = null;
                for(int i = 0; i < attrs.getLength(); i++) {
                    String key = attrs.getQName(i);
                    if(key.equals("format"))
                        format = attrs.getValue(i);
                    if(key.equals("version"))
                        version = attrs.getValue(i);
                }
                try {
                    m_doc = new SignedDoc();
                    m_doc.setFormat(format);
                    m_doc.setVersion(version);
                    if(format != null && (format.equals(SignedDoc.FORMAT_SK_XML) || format.equals(SignedDoc.FORMAT_DIGIDOC_XML))) {
                        m_doc.setProfile(SignedDoc.PROFILE_TM); // in ddoc format we used only TM
                    }
                } catch (DigiDocException ex) {
                    handleSAXError(ex);
                }
            }
            // 
			/*if(qName.equals("Signature")) {
				String Id = attrs.getValue("Id");
				try {
					Signature sig = new Signature(m_doc);
					if(Id != null)
						sig.setId(Id);
					m_doc.addSignature(sig);
				} catch (DigiDocException ex) {
					handleSAXError(ex);
				}
			}*/
            // 
            if(tag.equals("KeyInfo")) {
                try {
                    KeyInfo ki = new KeyInfo();
                    String Id = attrs.getValue("Id");
                    if(Id != null)
                        ki.setId(Id);
                    Signature sig = getLastSignature();
                    sig.setKeyInfo(ki);
                    ki.setSignature(sig);
                } catch (DigiDocException ex) {
                    handleSAXError(ex);
                }
            }
            // 
            if(tag.equals("UnsignedProperties")) {
                String Target = attrs.getValue("Target");
                try {
                    Signature sig = getLastSignature();
                    UnsignedProperties up = new UnsignedProperties(sig);
                    sig.setUnsignedProperties(up);
                } catch (DigiDocException ex) {
                    handleSAXError(ex);
                }
            }
            // 
            if(tag.equals("EncapsulatedOCSPValue")) {
                String Id = attrs.getValue("Id");
                Signature sig = getLastSignature();
                UnsignedProperties up = sig.getUnsignedProperties();
                Notary not = new Notary();
                if(Id != null)
                    not.setId(Id);
                not.setId(Id);
                up.addNotary(not);
                if(sig.getProfile() == null &&
                        (m_doc.getFormat().equals(SignedDoc.FORMAT_DIGIDOC_XML) ||
                                m_doc.getFormat().equals(SignedDoc.FORMAT_SK_XML)))
                    sig.setProfile(SignedDoc.PROFILE_TM);
            }
        } // if(m_nCollectMode == 0)
    }

    private static final String xmlnsEtsi = "http://uri.etsi.org/01903/v1.3.2#";
    private static final String xmlnsDs = "http://www.w3.org/2000/09/xmldsig#";
    private static final String xmlnsAsic = "http://uri.etsi.org/02918/v1.2.1#";
    //private static final String xmlnsNonce = "http://www.sk.ee/repository/NonceAlgorithm";

    private TreeSet collectNamespaces(String sCanInfo, TreeSet tsOtherAttr)
    {
        TreeSet ts = new TreeSet();
        // find element header
        int p1 = -1, p2 = -1;
        p1 = sCanInfo.indexOf('>');
        if(p1 != -1) {
            String sHdr = sCanInfo.substring(0, p1);
            if(m_logger.isDebugEnabled())
                m_logger.debug("Header: " + sHdr);
            String[] toks = sHdr.split(" ");
            for(int i = 0; (toks != null) && (i < toks.length); i++) {
                String tok = toks[i];
                if(tok != null && tok.trim().length() > 0 && tok.charAt(0) != '<') {
                    if(tok.indexOf("xmlns") != -1)
                        ts.add(tok);
                    else
                        tsOtherAttr.add(tok);
                }
            }
        }
        return ts;
    }

    private void addNamespaceIfMissing(TreeSet ts, String ns, String pref)
    {
        boolean bF = false;
        Iterator iNs = ts.iterator();
        while(iNs.hasNext()) {
            String s = (String)iNs.next();
            if(s != null && s.indexOf(ns) != -1) {
                bF = true;
                break;
            }
        }
        if(!bF) {
            StringBuffer sb = new StringBuffer("xmlns");
            if(pref != null) {
                sb.append(":");
                sb.append(pref);
            }
            sb.append("=\"");
            sb.append(ns);
            sb.append("\"");
            ts.add(sb.toString());
        }
    }

    /**
     * End Element handler
     * @param namespaceURI namespace URI
     * @param lName local name
     * @param qName qualified name
     */
    public void endElement(String namespaceURI, String sName, String qName)
            throws SAXException
    {
        if(m_logger.isDebugEnabled())
            m_logger.debug("End Element: " + qName + " collect: " + m_nCollectMode);
        // remove last tag from stack
        String tag = qName;
        String nsPref = null;
        if(tag.indexOf(':') != -1) {
            tag = qName.substring(qName.indexOf(':') + 1);
            nsPref = qName.substring(0, qName.indexOf(':'));
        }
        if(m_elemCurrent != null)
            m_elemCurrent = m_elemCurrent.getParent();
        String currTag = (String) m_tags.pop();
        // collect SAX event data to original XML data
        // for  we don't collect the begin and
        // end tags unless this an embedded 
        StringBuffer sb = null;
        if (m_nCollectMode > 0
                && (!tag.equals("DataFile") || m_nCollectMode > 1)) {
            sb = new StringBuffer();
            sb.append("");
        }
        if (m_sbCollectSignature != null) {
            m_sbCollectSignature.append("");
        }
        // if we do cache in mem
        if(m_sbCollectChars != null && sb != null)
            m_sbCollectChars.append(sb.toString());

        // 
        if(tag.equals("DataFile")) {
            m_nCollectMode--;
            if (m_nCollectMode == 0) {
                // close DataFile cache if necessary
                try {
                    if(m_dfCacheOutStream != null) {
                        if(sb != null)
                            m_dfCacheOutStream.write(ConvertUtils.str2data(sb.toString()));
                        m_dfCacheOutStream.close();
                        m_dfCacheOutStream = null;
                    }
                } catch (IOException ex) {
                    handleSAXError(ex);
                } catch (DigiDocException ex) {
                    handleSAXError(ex);
                }

                DataFile df = m_doc.getLastDataFile();
                if(df != null && df.getContentType().equals(DataFile.CONTENT_EMBEDDED_BASE64)) {
                    try {
                        if(m_doc.getFormat().equals(SignedDoc.FORMAT_SK_XML)) {
                            String sDf = null;
                            if(m_sbCollectChars != null) {
                                sDf = m_sbCollectChars.toString();
                                setDataFileBodyAsData(df);
                                m_sbCollectChars = null;
                            } else if(df.getDfCacheFile() != null) {
                                byte[] data = null;
                                try {
                                    data = SignedDoc.readFile(df.getDfCacheFile());
                                    sDf = new String(data);
                                } catch(Exception ex) {
                                    m_logger.error("Error reading cache file: " + df.getDfCacheFile() + " - " + ex);
                                }
                            }
                            if(sDf != null) {
                                byte[] bDf = Base64Util.decode(sDf);
                                updateDigest(bDf);
                            }
                            df.setDigest(getDigest());
                            if(m_logger.isDebugEnabled())
                                m_logger.debug("Digest: " + df.getId() + " - " + Base64Util.encode(df.getDigest()) + " size: " + df.getSize());
                        } else {
                            if(m_logger.isDebugEnabled())
                                m_logger.debug("DF: " + df.getId() + " cache-file: " + df.getDfCacheFile());
                            if(df.getDfCacheFile() == null) {
                                setDataFileBodyAsData(df);
                            }
                            // calc digest over end tag
                            updateDigest("".getBytes());
                            //df.setDigestType(SignedDoc.SHA1_DIGEST_TYPE);
                            df.setDigest(getDigest());
                            //df.setDigestValue(df.getDigest());
                            if(m_logger.isDebugEnabled())
                                m_logger.debug("Digest: " + df.getId() + " - " + Base64Util.encode(df.getDigest()) + " size: " + df.getSize());
                        }
                        if(m_altDigest != null) {
                            //calc digest over end tag
                            updateAltDigest(ConvertUtils.str2data(""));
                            //df.setDigestType(SignedDoc.SHA1_DIGEST_TYPE);
                            df.setAltDigest(getAltDigest());
                            //df.setDigestValue(df.getDigest());
                        }
                        m_sbCollectChars = null; // stop collecting
                    } catch (DigiDocException ex) {
                        handleSAXError(ex);
                    }
                    // this would throw away whitespace so calculate digest before it
                    //df.setBody(Base64Util.decode(m_sbCollectChars.toString()));
                }
                m_bCollectDigest = false;
            }
        }
        // 
        if(tag.equals("SignedInfo")) {
            if(m_nCollectMode > 0) m_nCollectMode--;
            // calculate digest over the original
            // XML form of SignedInfo block and save it
            try {
                Signature sig = getLastSignature();
                SignedInfo si = sig.getSignedInfo();
                String sSigInf = m_sbCollectChars.toString();
                if(m_logger.isDebugEnabled())
                    m_logger.debug("SigInf:\n------\n" + sSigInf + "\n------\n");
                //debugWriteFile("SigInfo1.xml", m_sbCollectChars.toString());
                byte[] bCanSI = null;
                if(m_doc.getFormat().equals(SignedDoc.FORMAT_SK_XML)) {
                    bCanSI = sSigInf.getBytes();
                } else {
                    CanonicalizationFactory canFac = ConfigManager.instance().getCanonicalizationFactory();
                    if(si.getCanonicalizationMethod().equals(SignedDoc.CANONICALIZATION_METHOD_2010_10_EXC))
                        bCanSI = canFac.canonicalize(ConvertUtils.str2data(sSigInf, "UTF-8"), SignedDoc.CANONICALIZATION_METHOD_2010_10_EXC);
                    else
                        bCanSI = canFac.canonicalize(ConvertUtils.str2data(sSigInf, "UTF-8"), SignedDoc.CANONICALIZATION_METHOD_20010315);
                }
                si.setOrigDigest(SignedDoc.digestOfType(bCanSI, SignedDoc.SHA1_DIGEST_TYPE));
                if(m_logger.isDebugEnabled())
                    m_logger.debug("SigInf:\n------\n" + new String(bCanSI) + "\n------\nHASH: " + Base64Util.encode(si.getOrigDigest()));

                m_sbCollectChars = null; // stop collecting
                //debugWriteFile("SigInfo2.xml", si.toString());
            } catch (DigiDocException ex) {
                handleSAXError(ex);
            }
        }
        // 
        if(tag.equals("SignedProperties")) {
            if(m_nCollectMode > 0) m_nCollectMode--;
            // calculate digest over the original
            // XML form of SignedInfo block and save it
            //debugWriteFile("SigProps-orig.xml", m_sbCollectChars.toString());
            try {
                Signature sig = getLastSignature();
                SignedInfo si = sig.getSignedInfo();
                SignedProperties sp = sig.getSignedProperties();
                String sigProp = m_sbCollectChars.toString();
                //debugWriteFile("SigProp1.xml", sigProp);
                byte[] bSigProp = ConvertUtils.str2data(sigProp, "UTF-8");
                byte[] bDig0 = SignedDoc.digestOfType(bSigProp, SignedDoc.SHA1_DIGEST_TYPE);
                if(m_logger.isDebugEnabled())
                    m_logger.debug("SigProp0:\n------\n" + sigProp + "\n------" + " len: " +
                            sigProp.length() + " sha1 HASH0: " + Base64Util.encode(bDig0));
                CanonicalizationFactory canFac = ConfigManager.instance().getCanonicalizationFactory();
                byte[] bCanProp = null;
                if(si.getCanonicalizationMethod().equals(SignedDoc.CANONICALIZATION_METHOD_2010_10_EXC))
                    bCanProp = canFac.canonicalize(bSigProp, SignedDoc.CANONICALIZATION_METHOD_2010_10_EXC);
                else
                    bCanProp = canFac.canonicalize(bSigProp, SignedDoc.CANONICALIZATION_METHOD_20010315);
                if(m_logger.isDebugEnabled())
                    m_logger.debug("SigProp can:\n------\n" + new String(bCanProp, "UTF-8") + "\n------" + " len: " + bCanProp.length);
                m_sbCollectChars = null; // stop collecting
                CertID cid = sig.getCertIdOfType(CertID.CERTID_TYPE_SIGNER);
                if(cid != null) {
                    if(cid.getId() != null)
                        sp.setCertId(cid.getId());
                    else if(!sig.getSignedDoc().getVersion().equals(SignedDoc.VERSION_1_3))
                        sp.setCertId(sig.getId() + "-CERTINFO");
                    sp.setCertSerial(cid.getSerial());
                    sp.setCertDigestAlgorithm(cid.getDigestAlgorithm());
                    if(cid.getDigestValue() != null)
                        sp.setCertDigestValue(cid.getDigestValue());
                    if(m_logger.isDebugEnabled())
                        m_logger.debug("CID: " + cid.getId() + " ser: " + cid.getSerial() + " alg: " + cid.getDigestAlgorithm());
                }
                if(m_doc.getFormat().equals(SignedDoc.FORMAT_DIGIDOC_XML) ||
                        m_doc.getFormat().equals(SignedDoc.FORMAT_SK_XML)) {
                    String sDigType1 = ConfigManager.digAlg2Type(sp.getCertDigestAlgorithm());
                    if(sDigType1 != null)
                        sp.setOrigDigest(SignedDoc.digestOfType(bCanProp, sDigType1));
                    if(m_logger.isDebugEnabled())
                        m_logger.debug("SigProp2:\n------\n" + new String(bCanProp) + "\n------\n"  +
                                " len: " + bCanProp.length + " digtype: " + sDigType1 + " HASH: " + Base64Util.encode(sp.getOrigDigest()));
                }
            } catch (DigiDocException ex) {
                handleSAXError(ex);
            } catch(UnsupportedEncodingException ex) {
                handleSAXError(ex);
            }
        }
        // 
        if(tag.equals("SignatureValue")) {
            if(m_nCollectMode > 0) m_nCollectMode--;
            m_strSigValTs = m_sbCollectChars.toString();
            m_sbCollectChars = null; // stop collecting
        }
        // 
        if(tag.equals("CompleteRevocationRefs")) {
            if(m_nCollectMode > 0) m_nCollectMode--;
            if(m_sbCollectChars != null)
                m_strSigAndRefsTs = m_strSigValTs + m_sbCollectChars.toString();
            m_sbCollectChars = null; // stop collecting
        }
        // 
        if(tag.equals("Signature")) {
            if (m_nCollectMode == 0) {
                if (m_logger.isDebugEnabled())
                    m_logger.debug("End collecting ");
                try {
                    Signature sig = getLastSignature();
                    //if (m_logger.isDebugEnabled())
                    //	m_logger.debug("Set sig content:\n---\n" + m_sbCollectSignature.toString() + "\n---\n");
                    if (m_sbCollectSignature != null) {
                        sig.setOrigContent(ConvertUtils.str2data(m_sbCollectSignature.toString(), "UTF-8"));
                        //if (m_logger.isDebugEnabled())
                        //	m_logger.debug("SIG orig content set: " + sig.getId() + " len: " + ((sig.getOrigContent() == null) ? 0 : sig.getOrigContent().length));
                        //debugWriteFile("SIG-" + sig.getId() + ".txt", m_sbCollectSignature.toString());
                        m_sbCollectSignature = null; // reset collecting
                    }
                } catch (DigiDocException ex) {
                    handleSAXError(ex);
                }
            }
        }
        // 
        if(tag.equals("XAdESSignatures")) {
            if (m_nCollectMode == 0) {
                if (m_logger.isDebugEnabled())
                    m_logger.debug("End collecting ");
                try {
                    Signature sig = getLastSignature();
                    //if (m_logger.isDebugEnabled())
                    //	m_logger.debug("Set sig content:\n---\n" + m_sbCollectSignature.toString() + "\n---\n");
                    if (m_sbCollectSignature != null) {
                        sig.setOrigContent(ConvertUtils.str2data(m_sbCollectSignature.toString(), "UTF-8"));
                        //if (m_logger.isDebugEnabled())
                        //	m_logger.debug("SIG orig content set: " + sig.getId() + " len: " + ((sig.getOrigContent() == null) ? 0 : sig.getOrigContent().length));
                        //debugWriteFile("SIG-" + sig.getId() + ".txt", m_sbCollectSignature.toString());
                        m_sbCollectSignature = null; // reset collecting
                    }
                } catch (DigiDocException ex) {
                    handleSAXError(ex);
                }
            }
        }
        // 
        if(tag.equals("SignatureTimeStamp")) {
            if (m_logger.isDebugEnabled())
                m_logger.debug("End collecting ");
            try {
                Signature sig = getLastSignature();
                TimestampInfo ts = sig.getTimestampInfoOfType(TimestampInfo.TIMESTAMP_TYPE_SIGNATURE);
                if(ts != null && m_strSigValTs != null) {
                    CanonicalizationFactory canFac = ConfigManager.instance().getCanonicalizationFactory();
                    byte[] bCanXml = canFac.canonicalize(ConvertUtils.str2data(m_strSigValTs, "UTF-8"),
                            SignedDoc.CANONICALIZATION_METHOD_20010315);
                    //TODO: other diges types for timestamps?
                    byte[] hash = SignedDoc.digest(bCanXml);
                    if(m_logger.isDebugEnabled())
                        m_logger.debug("SigValTS \n---\n" + new String(bCanXml) + "\n---\nHASH: " + Base64Util.encode(hash));
                    //debugWriteFile("SigProp2.xml", new String(bCanProp));
                    ts.setHash(hash);
                }
            } catch (DigiDocException ex) {
                handleSAXError(ex);
            }
        }
        // 
        if(tag.equals("SigAndRefsTimeStamp")) {
            if (m_logger.isDebugEnabled())
                m_logger.debug("End collecting ");
            try {
                Signature sig = getLastSignature();
                TimestampInfo ts = sig.getTimestampInfoOfType(TimestampInfo.TIMESTAMP_TYPE_SIG_AND_REFS);
                if(ts != null && m_strSigAndRefsTs != null) {
                    String canXml = "" + m_strSigAndRefsTs + "";
                    CanonicalizationFactory canFac = ConfigManager.instance().getCanonicalizationFactory();
                    byte[] bCanXml = canFac.canonicalize(ConvertUtils.str2data(canXml, "UTF-8"),
                            SignedDoc.CANONICALIZATION_METHOD_20010315);
                    canXml = new String(bCanXml, "UTF-8");
                    canXml = canXml.substring(3, canXml.length() - 4);
                    //TODO: other diges types for timestamps?
                    byte[] hash = SignedDoc.digest(ConvertUtils.str2data(canXml, "UTF-8"));
                    if(m_logger.isDebugEnabled())
                        m_logger.debug("SigAndRefsTimeStamp \n---\n" + canXml + "\n---\n" + Base64Util.encode(hash));
                    //debugWriteFile("SigProp2.xml", new String(bCanProp));
                    ts.setHash(hash);
                }
            } catch (DigiDocException ex) {
                handleSAXError(ex);
            } catch(Exception ex) {
                handleSAXError(ex);
            }
        }
        // the following stuff is used also in
        // collect mode level 1 because it can be part
        // of SignedInfo or SignedProperties
        if (m_nCollectMode == 1) {
            // 
            if(tag.equals("SigningTime")) {
                try {
                    Signature sig = getLastSignature();
                    SignedProperties sp = sig.getSignedProperties();
                    sp.setSigningTime(ConvertUtils.string2date(m_sbCollectItem.toString(), m_doc));
                    m_sbCollectItem = null; // stop collecting
                } catch (DigiDocException ex) {
                    handleSAXError(ex);
                }
            }
            // 
            if(tag.equals("ClaimedRole")) {
                Signature sig = getLastSignature();
                SignedProperties sp = sig.getSignedProperties();
                sp.addClaimedRole(m_sbCollectItem.toString());
                m_sbCollectItem = null; // stop collecting
            }
            // 
            if(tag.equals("City")) {
                Signature sig = getLastSignature();
                SignedProperties sp = sig.getSignedProperties();
                SignatureProductionPlace spp = sp.getSignatureProductionPlace();
                spp.setCity(m_sbCollectItem.toString());
                m_sbCollectItem = null; // stop collecting
            }
            // 
            if(tag.equals("StateOrProvince")) {
                Signature sig = getLastSignature();
                SignedProperties sp = sig.getSignedProperties();
                SignatureProductionPlace spp = sp.getSignatureProductionPlace();
                spp.setStateOrProvince(m_sbCollectItem.toString());
                m_sbCollectItem = null; // stop collecting
            }
            // 
            if(tag.equals("CountryName")) {
                Signature sig = getLastSignature();
                SignedProperties sp = sig.getSignedProperties();
                SignatureProductionPlace spp = sp.getSignatureProductionPlace();
                spp.setCountryName(m_sbCollectItem.toString());
                m_sbCollectItem = null; // stop collecting
            }
            // 
            if(tag.equals("PostalCode")) {
                Signature sig = getLastSignature();
                SignedProperties sp = sig.getSignedProperties();
                SignatureProductionPlace spp = sp.getSignatureProductionPlace();
                spp.setPostalCode(m_sbCollectItem.toString());
                m_sbCollectItem = null; // stop collecting
            }

        } // level 1
        // the following is collected on any level
        // 
        if(tag.equals("DigestValue")) {
            try {
                if(m_tags.search("Reference") != -1) {
                    Signature sig = getLastSignature();
                    SignedInfo si = sig.getSignedInfo();
                    Reference ref = si.getLastReference();
                    ref.setDigestValue(Base64Util.decode(m_sbCollectItem.toString()));
                    m_sbCollectItem = null; // stop collecting
                } else if(m_tags.search("SigningCertificate") != -1) {
                    Signature sig = getLastSignature();
                    SignedProperties sp = sig.getSignedProperties();
                    sp.setCertDigestValue(Base64Util.decode(m_sbCollectItem.toString()));
                    CertID cid = sig.getCertIdOfType(CertID.CERTID_TYPE_SIGNER);
                    if(cid != null)
                        cid.setDigestValue(Base64Util.decode(m_sbCollectItem.toString()));
                    m_sbCollectItem = null; // stop collecting
                } else if(m_tags.search("CompleteCertificateRefs") != -1) {
                    Signature sig = getLastSignature();
                    UnsignedProperties up = sig.getUnsignedProperties();
                    CompleteCertificateRefs crefs = up.getCompleteCertificateRefs();
                    CertID cid = crefs.getLastCertId();
                    if(cid != null)
                        cid.setDigestValue(Base64Util.decode(m_sbCollectItem.toString()));
                    if(m_logger.isDebugEnabled())
                        m_logger.debug("CertID: " + cid.getId() + " digest: " + m_sbCollectItem.toString());
                    m_sbCollectItem = null; // stop collecting
                } else if(m_tags.search("CompleteRevocationRefs") != -1) {
                    Signature sig = getLastSignature();
                    UnsignedProperties up = sig.getUnsignedProperties();
                    CompleteRevocationRefs rrefs = up.getCompleteRevocationRefs();
                    //if(rrefs.getDigestValue() == null) // ignore sub and root ca ocsp digests
                    OcspRef orf = rrefs.getLastOcspRef();
                    orf.setDigestValue(Base64Util.decode(m_sbCollectItem.toString()));
                    if(m_logger.isDebugEnabled())
                        m_logger.debug("Revoc ref: " + m_sbCollectItem.toString());
                    m_sbCollectItem = null; // stop collecting
                } else if(m_tags.search("SigPolicyHash") != -1) {
                    Signature sig = getLastSignature();
                    SignedProperties sp = sig.getSignedProperties();
                    SignaturePolicyIdentifier spi = sp.getSignaturePolicyIdentifier();
                    SignaturePolicyId sppi = spi.getSignaturePolicyId();
                    sppi.setDigestValue(Base64Util.decode(m_sbCollectItem.toString()));
                    if(m_logger.isDebugEnabled())
                        m_logger.debug("SignaturePolicyId hash: " + m_sbCollectItem.toString());
                    m_sbCollectItem = null; // stop collecting
                }
            } catch(DigiDocException ex) {
                handleSAXError(ex);
            }
        }
        // 
        if(tag.equals("IssuerSerial") && m_doc != null
                && !m_doc.getVersion().equals(SignedDoc.VERSION_1_3)) {
            try {
                Signature sig = getLastSignature();
                CertID cid = sig.getLastCertId();
                if(m_logger.isDebugEnabled())
                    m_logger.debug("X509SerialNumber 0: " + m_sbCollectItem.toString());
                if(cid != null)
                    cid.setSerial(ConvertUtils.string2bigint(m_sbCollectItem.toString()));
                m_sbCollectItem = null; // stop collecting
            } catch (DigiDocException ex) {
                handleSAXError(ex);
            }
        }
        // 
        if(tag.equals("X509SerialNumber") && m_doc != null
                && (m_doc.getVersion().equals(SignedDoc.VERSION_1_3))) {
            try {
                Signature sig = getLastSignature();
                CertID cid = sig.getLastCertId();
                if(m_logger.isDebugEnabled())
                    m_logger.debug("X509SerialNumber: " + m_sbCollectItem.toString());
                if(cid != null)
                    cid.setSerial(ConvertUtils.string2bigint(m_sbCollectItem.toString()));
                if(m_logger.isDebugEnabled())
                    m_logger.debug("X509SerialNumber: " + cid.getSerial() + " type: " + cid.getType());
                m_sbCollectItem = null; // stop collecting
            } catch (DigiDocException ex) {
                handleSAXError(ex);
            }
        }
        // 
        if(tag.equals("X509IssuerName") && m_doc != null
                && (m_doc.getVersion().equals(SignedDoc.VERSION_1_3))) {
            try {
                Signature sig = getLastSignature();
                CertID cid = sig.getLastCertId();
                String s = m_sbCollectItem.toString();
                if(cid != null)
                    cid.setIssuer(s);
                if(m_logger.isDebugEnabled() && cid != null)
                    m_logger.debug("X509IssuerName: " + s + " type: " + cid.getType() + " nr: " + cid.getSerial());
                m_sbCollectItem = null; // stop collecting
            } catch (DigiDocException ex) {
                handleSAXError(ex);
            }
        }
        // 
        if(tag.equals("ResponderID")) {
            try {
                Signature sig = getLastSignature();
                UnsignedProperties up = sig.getUnsignedProperties();
                CompleteRevocationRefs rrefs = up.getCompleteRevocationRefs();
                if(m_logger.isDebugEnabled())
                    m_logger.debug("ResponderID: " + m_sbCollectItem.toString());
                OcspRef orf = rrefs.getLastOcspRef();
                orf.setResponderId(m_sbCollectItem.toString());
                m_sbCollectItem = null; // stop collecting
            } catch (DigiDocException ex) {
                handleSAXError(ex);
            }
        }
        // 
        if(tag.equals("ProducedAt")) {
            try {
                Signature sig = getLastSignature();
                UnsignedProperties up = sig.getUnsignedProperties();
                CompleteRevocationRefs rrefs = up.getCompleteRevocationRefs();
                OcspRef orf = rrefs.getLastOcspRef();
                orf.setProducedAt(ConvertUtils.string2date(m_sbCollectItem.toString(), m_doc));
                m_sbCollectItem = null; // stop collecting
            } catch (DigiDocException ex) {
                handleSAXError(ex);
            }
        }

        // the following stuff is ignored in collect mode
        // because it can only be the content of a higher element
        //if (m_nCollectMode == 0) {
        // 
        if(tag.equals("SignatureValue")) {
            try {
                Signature sig = getLastSignature();
                SignatureValue sv = sig.getSignatureValue();
                //debugWriteFile("SigVal.txt", m_sbCollectItem.toString());
                if(m_sbCollectItem != null && m_sbCollectItem.length() > 0)
                    sig.setSignatureValue(Base64Util.decode(m_sbCollectItem.toString().trim()));
                //sv.setValue(Base64Util.decode(m_sbCollectItem.toString().trim()));
                if(m_logger.isDebugEnabled())
                    m_logger.debug("SIGVAL mode: " + m_nCollectMode + ":\n--\n" + (m_sbCollectItem != null ? m_sbCollectItem.toString() : "NULL") +
                            "\n---\n len: " + ((sv.getValue() != null) ? sv.getValue().length : 0));
                m_sbCollectItem = null; // stop collecting
            } catch (DigiDocException ex) {
                handleSAXError(ex);
            }
        }
        // 
        if(tag.equals("X509Certificate")) {
            try {
                Signature sig = getLastSignature();
                CertValue cval = sig.getLastCertValue();
                cval.setCert(SignedDoc.readCertificate(Base64Util.decode(m_sbCollectItem.toString())));
                m_sbCollectItem = null; // stop collecting
            } catch (DigiDocException ex) {
                handleSAXError(ex);
            }
        }
        // 
        if(tag.equals("EncapsulatedX509Certificate")) {
            try {
                Signature sig = getLastSignature();
                CertValue cval = sig.getLastCertValue();
                cval.setCert(SignedDoc.readCertificate(Base64Util.decode(m_sbCollectItem.toString())));
                m_sbCollectItem = null; // stop collecting
            } catch (DigiDocException ex) {
                handleSAXError(ex);
            }
        }
        // 
        if(tag.equals("EncapsulatedOCSPValue")) {
            try {
                Signature sig = getLastSignature();
                // first we have to find correct certid and certvalue types
                findCertIDandCertValueTypes(sig);
                UnsignedProperties up = sig.getUnsignedProperties();
                Notary not = up.getLastNotary();
                //if(m_logger.isDebugEnabled())
                //	m_logger.debug("Notary: " + not.getId() + " resp: " + m_sbCollectItem.toString());
                not.setOcspResponseData(Base64Util.decode(m_sbCollectItem.toString()));
                NotaryFactory notFac = ConfigManager.instance().getNotaryFactory();
                notFac.parseAndVerifyResponse(sig, not);
                // in 1.1 we had bad OCPS digest
                if (m_doc != null && m_doc.getFormat().equals(SignedDoc.FORMAT_DIGIDOC_XML) && m_doc.getVersion().equals(SignedDoc.VERSION_1_1)) {
                    CompleteRevocationRefs rrefs = up.getCompleteRevocationRefs();
                    OcspRef orf = rrefs.getLastOcspRef();
                    orf.setDigestValue(SignedDoc.digestOfType(not.getOcspResponseData(), SignedDoc.SHA1_DIGEST_TYPE));
                }
                m_sbCollectItem = null; // stop collecting
            } catch (Exception ex) {
                handleSAXError(ex);
            }
        }
        // 
        if(tag.equals("SPURI")) {
            //try {
            Signature sig = getLastSignature();
            if(sig != null) {
                SignedProperties sp = sig.getSignedProperties();
                if(sp != null) {
                    SignaturePolicyIdentifier spid = sp.getSignaturePolicyIdentifier();
                    if(spid != null) {
                        SignaturePolicyId spi = spid.getSignaturePolicyId();
                        if(spi != null)
                            spi.addSigPolicyQualifier(new SpUri(m_sbCollectItem.toString().trim()));
                    }
                }
            }
            m_sbCollectItem = null; // stop collecting
			/*} catch (DigiDocException ex) {
				handleSAXError(ex);
			}*/
        }
        // 
        if(tag.equals("MimeType")) {
            try {
                Signature sig = getLastSignature();
                if(sig != null) {
                    SignedProperties sp = sig.getSignedProperties();
                    if(sp != null) {
                        SignedDataObjectProperties sdps = sp.getSignedDataObjectProperties();
                        DataObjectFormat dof = sdps.getLastDataObjectFormat();
                        if(dof != null) {
                            dof.setMimeType(m_sbCollectItem.toString());
                            Reference ref = sig.getSignedInfo().getReferenceForDataObjectFormat(dof);
                            if(ref != null) {
                                for(int d = 0; d < sig.getSignedDoc().countDataFiles(); d++) {
                                    DataFile df = sig.getSignedDoc().getDataFile(d);
                                    if(df.getFileName() != null && df.getFileName().length() > 1 &&
                                            ref.getUri() != null && ref.getUri().length() > 1) {
                                        // normalize uri and filename
                                        String sFileName = df.getFileName();
                                        if(sFileName.charAt(0) == '/')
                                            sFileName = sFileName.substring(1);
                                        String sUri = ref.getUri();
                                        if(sUri.charAt(0) == '/')
                                            sUri = sUri.substring(1);
                                        if(sFileName.equals(sUri)) {
                                            df.setMimeType(m_sbCollectItem.toString());
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
                m_sbCollectItem = null; // stop collecting
            } catch (DigiDocException ex) {
                handleSAXError(ex);
            }
        }

        //} // if(m_nCollectMode == 0)
    }

    private void setDataFileBodyAsData(DataFile df) throws DigiDocException {
        long nSize = df.getSize();
        byte[] b = Base64Util.decode(m_sbCollectChars.toString());
        if(m_logger.isDebugEnabled())
            m_logger.debug("DF: " + df.getId() + " orig-size: " + nSize + " new size: " + b.length);
        if(nSize == 0) nSize = b.length;
        df.setBodyAsData(ConvertUtils.str2data(m_sbCollectChars.toString(), "UTF-8"), true, nSize);
    }

    /**
     * SAX characters event handler
     * @param buf received bytes array
     * @param offset offset to the array
     * @param len length of data
     */
    public void characters(char buf[], int offset, int len)
            throws SAXException
    {
        String s = new String(buf, offset, len);
        // just collect the data since it could
        // be on many lines and be processed in many events
        if (s != null) {
            if (m_sbCollectItem != null) {
                m_sbCollectItem.append(s);
                //if(m_logger.isDebugEnabled())
                //	m_logger.debug("IN:\n---\n" + s + "\n---\nCollected:\n---\n" + m_sbCollectItem.toString() + "\n---\n");
            }
            if (m_sbCollectChars != null) {
                m_sbCollectChars.append(ConvertUtils.escapeTextNode(s));
            }
            if (m_sbCollectSignature != null)
                m_sbCollectSignature.append(ConvertUtils.escapeTextNode(s));
            if(m_digest != null && m_bCollectDigest)
                updateDigest(s.getBytes());
            if(m_altDigest != null && m_bCollectDigest)
                updateAltDigest(s.getBytes());
            try {
                if(m_dfCacheOutStream != null)
                    m_dfCacheOutStream.write(ConvertUtils.str2data(s));
            } catch(DigiDocException ex) {
                handleSAXError(ex);
            } catch(IOException ex) {
                handleSAXError(ex);
            }
        }
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy