Package org.dcm4che3.io

Source Code of org.dcm4che3.io.SAXWriter

/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is part of dcm4che, an implementation of DICOM(TM) in
* Java(TM), hosted at https://github.com/gunterze/dcm4che.
*
* The Initial Developer of the Original Code is
* Agfa Healthcare.
* Portions created by the Initial Developer are Copyright (C) 2011
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* See @authors listed below
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */

package org.dcm4che3.io;

import java.io.IOException;

import org.dcm4che3.data.Tag;
import org.dcm4che3.data.Attributes;
import org.dcm4che3.data.BulkData;
import org.dcm4che3.data.ElementDictionary;
import org.dcm4che3.data.Fragments;
import org.dcm4che3.data.PersonName;
import org.dcm4che3.data.Sequence;
import org.dcm4che3.data.SpecificCharacterSet;
import org.dcm4che3.data.VR;
import org.dcm4che3.data.Value;
import org.dcm4che3.io.DicomInputStream.IncludeBulkData;
import org.dcm4che3.util.Base64;
import org.dcm4che3.util.ByteUtils;
import org.dcm4che3.util.TagUtils;
import org.xml.sax.ContentHandler;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.AttributesImpl;

/**
* @author Gunter Zeilinger <gunterze@gmail.com>
*/
public class SAXWriter implements DicomInputHandler {

    private static final String NAMESPACE = "http://dicom.nema.org/PS3.19/models/NativeDICOM";
    private static final int BASE64_CHUNK_LENGTH = 256 * 3;
    private static final int BUFFER_LENGTH = 256 * 4;
   
    private boolean includeKeyword = true;
    private String namespace = "";

    private final ContentHandler ch;
    private final AttributesImpl atts = new AttributesImpl();
    private final char[] buffer = new char[BUFFER_LENGTH];

    public SAXWriter(ContentHandler ch) {
        this.ch = ch;
    }

    public final boolean isIncludeKeyword() {
        return includeKeyword;
    }

    public final void setIncludeKeyword(boolean includeKeyword) {
        this.includeKeyword = includeKeyword;
    }

    public final boolean isIncludeNamespaceDeclaration() {
        return namespace == NAMESPACE;
    }

    public final void setIncludeNamespaceDeclaration(boolean includeNameSpaceDeclaration) {
        this.namespace = includeNameSpaceDeclaration ? NAMESPACE : "";
    }

    public void write(Attributes attrs) throws SAXException {
        startDocument();
        writeItem(attrs);
        endDocument();
    }

    private void writeItem(final Attributes item) throws SAXException {
        final SpecificCharacterSet cs = item.getSpecificCharacterSet();
        try {
            item.accept(new Attributes.Visitor(){

                @Override
                public boolean visit(Attributes attrs, int tag, VR vr, Object value)
                        throws Exception {
                     writeAttribute(tag, vr, value, cs, item);
                     return true;
                }},
                false);
        } catch (SAXException e) {
            throw e;
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }


    @Override
    public void startDataset(DicomInputStream dis) throws IOException {
        try {
            startDocument();
        } catch (SAXException e) {
            throw new IOException(e);
        }
    }

    @Override
    public void endDataset(DicomInputStream dis) throws IOException {
        try {
            endDocument();
        } catch (SAXException e) {
            throw new IOException(e);
        }
    }

    private void startDocument() throws SAXException {
        ch.startDocument();
        startElement("NativeDicomModel", "xml-space", "preserved");
    }

    private void endDocument() throws SAXException {
        endElement("NativeDicomModel");
        ch.endDocument();
    }

    private void startElement(String name, String attrName, int attrValue)
            throws SAXException {
        startElement(name, attrName, Integer.toString(attrValue));
    }

    private void startElement(String name, String attrName, String attrValue)
            throws SAXException {
        addAttribute(attrName, attrValue);
        startElement(name);
    }

    private void startElement(String name) throws SAXException {
        ch.startElement(namespace, name, name, atts);
        atts.clear();
    }

    private void endElement(String name) throws SAXException {
        ch.endElement(namespace, name, name);
    }

    private void addAttribute(String name, String value) {
        atts.addAttribute(namespace, name, name, "NMTOKEN", value);
    }

    private void writeAttribute(int tag, VR vr, Object value,
            SpecificCharacterSet cs, Attributes attrs) throws SAXException {
        if (TagUtils.isGroupLength(tag) || TagUtils.isPrivateCreator(tag))
            return;

        String privateCreator = attrs.getPrivateCreator(tag);
        addAttributes(tag, vr, privateCreator);
        startElement("DicomAttribute");
        if (value instanceof Value)
            writeAttribute((Value) value, attrs.bigEndian());
        else if (!vr.isInlineBinary()) {
            writeValues(vr, value, attrs.bigEndian(),
                    attrs.getSpecificCharacterSet(vr));
        } else if (value instanceof byte[]) {
            writeInlineBinary(attrs.bigEndian()
                    ? vr.toggleEndian((byte[]) value, true)
                    : (byte[]) value);
        } else
            throw new IllegalArgumentException("vr: " + vr + ", value class: "
                    + value.getClass());
        endElement("DicomAttribute");
    }

    private void writeAttribute(Value value, boolean bigEndian)
            throws SAXException {
        if (value.isEmpty())
            return;

        if (value instanceof Sequence) {
            Sequence seq = (Sequence) value;
            int number = 0;
            for (Attributes item : seq) {
                startElement("Item", "number", ++number);
                writeItem(item);
                endElement("Item");
            }
        } else if (value instanceof Fragments) {
            Fragments frags = (Fragments) value;
            int number = 0;
            for (Object frag : frags) {
                ++number;
                if (frag instanceof Value && ((Value) frag).isEmpty())
                    continue;
                startElement("DataFragment", "number", number);
                if (frag instanceof BulkData)
                    writeBulkData((BulkData) frag);
                else {
                    byte[] b = (byte[]) frag;
                    if (bigEndian)
                        frags.vr().toggleEndian(b, true);
                    writeInlineBinary(b);
                }
                endElement("DataFragment");
            }
        } else if (value instanceof BulkData) {
            writeBulkData((BulkData) value);
        }
    }

    @Override
    public void readValue(DicomInputStream dis, Attributes attrs)
            throws IOException {
        int tag = dis.tag();
        VR vr = dis.vr();
        int len = dis.length();
        if (TagUtils.isGroupLength(tag) || TagUtils.isPrivateCreator(tag)) {
            dis.readValue(dis, attrs);
        } else if (dis.getIncludeBulkData() == IncludeBulkData.NO
                && dis.isBulkData(attrs)) {
            if (len == -1)
                dis.readValue(dis, attrs);
            else
                dis.skipFully(len);
        } else try {
            String privateCreator = attrs.getPrivateCreator(tag);
            addAttributes(tag, vr, privateCreator);
            startElement("DicomAttribute");
            if (vr == VR.SQ || len == -1) {
                dis.readValue(dis, attrs);
            } else if (len > 0) {
                if (dis.getIncludeBulkData() ==  IncludeBulkData.URI
                        && dis.isBulkData(attrs)) {
                    writeBulkData(dis.createBulkData());
                } else {
                    byte[] b = dis.readValue();
                    if (tag == Tag.TransferSyntaxUID
                            || tag == Tag.SpecificCharacterSet)
                        attrs.setBytes(tag, vr, b);
                    if (vr.isInlineBinary())
                        writeInlineBinary(dis.bigEndian()
                                ? vr.toggleEndian(b, false)
                                : b);
                    else
                        writeValues(vr, b, dis.bigEndian(),
                                attrs.getSpecificCharacterSet(vr));
                 }
            }
            endElement("DicomAttribute");
        } catch (SAXException e) {
            throw new IOException(e);
        }
    }

    private void addAttributes(int tag, VR vr, String privateCreator) {
        if (privateCreator != null)
            tag &= 0xffff00ff;
        if (includeKeyword) {
            String keyword = ElementDictionary.keywordOf(tag, privateCreator);
            if (keyword != null && !keyword.isEmpty())
                addAttribute("keyword", keyword);
        }
        addAttribute("tag", TagUtils.toHexString(tag));
        if (privateCreator != null)
            addAttribute("privateCreator", privateCreator);
        addAttribute("vr", vr.name());
    }

    @Override
    public void readValue(DicomInputStream dis, Sequence seq)
            throws IOException {
        try {
            startElement("Item", "number", seq.size() + 1);
            dis.readValue(dis, seq);
            endElement("Item");
        } catch (SAXException e) {
            throw new IOException(e);
        }
    }

    @Override
    public void readValue(DicomInputStream dis, Fragments frags)
            throws IOException {
        int len = dis.length();
        if (dis.getIncludeBulkData() == IncludeBulkData.NO
                && dis.isBulkDataFragment(frags)) {
            dis.skipFully(len);
        } else try {
            frags.add(ByteUtils.EMPTY_BYTES); // increment size
            if (len > 0) {
                startElement("DataFragment", "number", frags.size());
                if (dis.getIncludeBulkData() == IncludeBulkData.URI
                        && dis.isBulkDataFragment(frags)) {
                    writeBulkData(dis.createBulkData());
                } else {
                    byte[] b = dis.readValue();
                    if (dis.bigEndian())
                        frags.vr().toggleEndian(b, false);
                    writeInlineBinary(b);
                }
                endElement("DataFragment");
            }
        } catch (SAXException e) {
            throw new IOException(e);
        }
    }

    private void writeValues(VR vr, Object val, boolean bigEndian,
            SpecificCharacterSet cs) throws SAXException {
        if (vr.isStringType())
            val = vr.toStrings(val, bigEndian, cs);
        int vm = vr.vmOf(val);
        for (int i = 0; i < vm; i++) {
            String s = vr.toString(val, bigEndian, i, null);
            addAttribute("number", Integer.toString(i + 1));
            if (vr == VR.PN) {
                PersonName pn = new PersonName(s, true);
                startElement("PersonName");
                writePNGroup("Alphabetic", pn, PersonName.Group.Alphabetic);
                writePNGroup("Ideographic", pn, PersonName.Group.Ideographic);
                writePNGroup("Phonetic", pn, PersonName.Group.Phonetic);
                endElement("PersonName");
            } else {
                writeElement("Value", s);
            }
        }
    }

    private void writeInlineBinary(byte[] b) throws SAXException {
        startElement("InlineBinary");
        char[] buf = buffer;
        for (int off = 0; off < b.length;) {
            int len = Math.min(b.length - off, BASE64_CHUNK_LENGTH);
            Base64.encode(b, off, len, buf, 0);
            ch.characters(buf, 0, (len * 4 / 3 + 3) & ~3);
            off += len;
        }
        endElement("InlineBinary");
    }

    private void writeBulkData(BulkData bulkData)
            throws SAXException {
        if (bulkData.uuid != null)
            addAttribute("uuid", bulkData.uuid);
        if (bulkData.uri != null)
            addAttribute("uri", bulkData.uri);
        startElement("BulkData");
        endElement("BulkData");
    }

    private void writeElement(String qname, String s) throws SAXException {
        if (s != null) {
            startElement(qname);
            char[] buf = buffer;
            for (int off = 0, totlen = s.length(); off < totlen;) {
                int len = Math.min(totlen - off, buf.length);
                s.getChars(off, off += len, buf, 0);
                ch.characters(buf, 0, len);
            }
            endElement(qname);
        }
    }

    private void writePNGroup(String qname, PersonName pn,
            PersonName.Group group) throws SAXException {
        if (pn.contains(group)) {
            startElement(qname);
            writeElement("FamilyName",
                    pn.get(group, PersonName.Component.FamilyName));
            writeElement("GivenName",
                    pn.get(group, PersonName.Component.GivenName));
            writeElement("MiddleName",
                    pn.get(group, PersonName.Component.MiddleName));
            writeElement("NamePrefix",
                    pn.get(group, PersonName.Component.NamePrefix));
            writeElement("NameSuffix",
                    pn.get(group, PersonName.Component.NameSuffix));
            endElement(qname);
        }
    }

}
TOP

Related Classes of org.dcm4che3.io.SAXWriter

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.