Package org.dcm4che3.net

Source Code of org.dcm4che3.net.PDUEncoder

/* ***** 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.net;

import java.io.EOFException;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

import org.dcm4che3.data.Tag;
import org.dcm4che3.data.UID;
import org.dcm4che3.data.Attributes;
import org.dcm4che3.io.DicomOutputStream;
import org.dcm4che3.net.pdu.AAbort;
import org.dcm4che3.net.pdu.AAssociateAC;
import org.dcm4che3.net.pdu.AAssociateRJ;
import org.dcm4che3.net.pdu.AAssociateRQ;
import org.dcm4che3.net.pdu.AAssociateRQAC;
import org.dcm4che3.net.pdu.CommonExtendedNegotiation;
import org.dcm4che3.net.pdu.ExtendedNegotiation;
import org.dcm4che3.net.pdu.PresentationContext;
import org.dcm4che3.net.pdu.RoleSelection;
import org.dcm4che3.net.pdu.UserIdentityAC;
import org.dcm4che3.net.pdu.UserIdentityRQ;

/**
* @author Gunter Zeilinger <gunterze@gmail.com>
*
*/
class PDUEncoder extends PDVOutputStream {

    private Association as;
    private OutputStream out;
    private byte[] buf = new byte[Connection.DEF_MAX_PDU_LENGTH + 6];
    private int pos;
    private int pdvpcid;
    private int pdvcmd;
    private int pdvpos;
    private int maxpdulen;
    private Thread th;
    private Object dimseLock = new Object();

    public PDUEncoder(Association as, OutputStream out) {
        this.as = as;
        this.out = out;
    }

    public void write(AAssociateRQ rq) throws IOException {
        encode(rq, PDUType.A_ASSOCIATE_RQ, ItemType.RQ_PRES_CONTEXT);
        writePDU(pos - 6);
    }

    public void write(AAssociateAC ac) throws IOException {
        encode(ac, PDUType.A_ASSOCIATE_AC, ItemType.AC_PRES_CONTEXT);
        writePDU(pos - 6);
    }

    public void write(AAssociateRJ rj) throws IOException {
        write(PDUType.A_ASSOCIATE_RJ, rj.getResult(), rj.getSource(),
                rj.getReason());
    }

    public void writeAReleaseRQ() throws IOException {
        write(PDUType.A_RELEASE_RQ, 0, 0, 0);
    }

    public void writeAReleaseRP() throws IOException {
        write(PDUType.A_RELEASE_RP, 0, 0, 0);
    }

    public void write(AAbort aa) throws IOException {
        write(PDUType.A_ABORT, 0, aa.getSource(), aa.getReason());
    }

    private synchronized void write(int pdutype, int result, int source,
            int reason) throws IOException {
        byte[] b = {
                (byte) pdutype,
                0,
                0, 0, 0, 4, // pdulen
                0,
                (byte) result,
                (byte) source,
                (byte) reason
        };
        out.write(b);
        out.flush();
    }

    private synchronized void writePDU(int pdulen) throws IOException {
        try {
            out.write(buf, 0, 6 + pdulen);
            out.flush();
        } catch (IOException e) {
            as.onIOException(e);
            throw e;
        }
        pdvpos = 6;
        pos = 12;
    }

    private void encode(AAssociateRQAC rqac, int pduType, int pcItemType) {
        rqac.checkCallingAET();
        rqac.checkCalledAET();

        int pdulen = rqac.length();
        if (buf.length < 6 + pdulen)
            buf = new byte[6 + pdulen];
        pos = 0;
        put(pduType);
        put(0);
        putInt(pdulen);
        putShort(rqac.getProtocolVersion());
        put(0);
        put(0);
        encodeAET(rqac.getCalledAET());
        encodeAET(rqac.getCallingAET());
        put(rqac.getReservedBytes(), 0, 32);
        encodeStringItem(ItemType.APP_CONTEXT, rqac.getApplicationContext());
        for (PresentationContext pc : rqac.getPresentationContexts())
            encode(pc, pcItemType);
        encodeUserInfo(rqac);
    }

    private void put(int ch) {
        buf[pos++] = (byte) ch;
    }

    private void put(byte[] b) {
        put(b, 0, b.length);
    }

    private void put(byte[] b, int off, int len) {
        System.arraycopy(b, off, buf, pos, len);
        pos += len;
    }

    private void putShort(int v) {
        buf[pos++] = (byte) (v >> 8);
        buf[pos++] = (byte) v;
    }

    private void putInt(int v) {
        buf[pos++] = (byte) (v >> 24);
        buf[pos++] = (byte) (v >> 16);
        buf[pos++] = (byte) (v >> 8);
        buf[pos++] = (byte) v;
    }

    @SuppressWarnings("deprecation")
    private void putString(String s) {
        int len = s.length();
        s.getBytes(0, len, buf, pos);
        pos += len;
    }

    private void encode(byte[] b) {
        putShort(b.length);
        put(b, 0, b.length);
    }

    private void encode(String s) {
        putShort(s.length());
        putString(s);
    }

    private void encodeAET(String aet) {
        int endpos = pos + 16;
        putString(aet);
        while (pos < endpos)
            put(0x20);
    }

    private void encodeItemHeader(int type, int len) {
        put(type);
        put(0);
        putShort(len);
    }

    private void encodeStringItem(int type, String s) {
        if (s == null)
            return;

        encodeItemHeader(type, s.length());
        putString(s);
    }

    private void encode(PresentationContext pc, int pcItemType) {
        encodeItemHeader(pcItemType, pc.length());
        put(pc.getPCID());
        put(0);
        put(pc.getResult());
        put(0);
        encodeStringItem(ItemType.ABSTRACT_SYNTAX, pc.getAbstractSyntax());
        for (String ts : pc.getTransferSyntaxes())
            encodeStringItem(ItemType.TRANSFER_SYNTAX, ts);
    }

    private void encodeUserInfo(AAssociateRQAC rqac) {
        encodeItemHeader(ItemType.USER_INFO, rqac.userInfoLength());
        encodeMaxPDULength(rqac.getMaxPDULength());
        encodeStringItem(ItemType.IMPL_CLASS_UID, rqac.getImplClassUID());
        if (rqac.isAsyncOps())
            encodeAsyncOpsWindow(rqac);
        for (RoleSelection rs : rqac.getRoleSelections())
            encode(rs);
        encodeStringItem(ItemType.IMPL_VERSION_NAME, rqac.getImplVersionName());
        for (ExtendedNegotiation extNeg : rqac.getExtendedNegotiations())
            encode(extNeg);
        for (CommonExtendedNegotiation extNeg :
                rqac.getCommonExtendedNegotiations())
            encode(extNeg);
        encode(rqac.getUserIdentityRQ());
        encode(rqac.getUserIdentityAC());
    }

    private void encodeMaxPDULength(int maxPDULength) {
        encodeItemHeader(ItemType.MAX_PDU_LENGTH, 4);
        putInt(maxPDULength);
    }

    private void encodeAsyncOpsWindow(AAssociateRQAC rqac) {
        encodeItemHeader(ItemType.ASYNC_OPS_WINDOW, 4);
        putShort(rqac.getMaxOpsInvoked());
        putShort(rqac.getMaxOpsPerformed());
    }

    private void encode(RoleSelection rs) {
        encodeItemHeader(ItemType.ROLE_SELECTION, rs.length());
        encode(rs.getSOPClassUID());
        put(rs.isSCU() ? 1 : 0);
        put(rs.isSCP() ? 1 : 0);
    }

    private void encode(ExtendedNegotiation extNeg) {
        encodeItemHeader(ItemType.EXT_NEG, extNeg.length());
        encode(extNeg.getSOPClassUID());
        put(extNeg.getInformation());
    }

    private void encode(CommonExtendedNegotiation extNeg) {
        encodeItemHeader(ItemType.COMMON_EXT_NEG, extNeg.length());
        encode(extNeg.getSOPClassUID());
        encode(extNeg.getServiceClassUID());
        putShort(extNeg.getRelatedGeneralSOPClassUIDsLength());
        for (String cuid : extNeg.getRelatedGeneralSOPClassUIDs())
            encode(cuid);
    }

    private void encode(UserIdentityRQ userIdentity) {
        if (userIdentity == null)
            return;

        encodeItemHeader(ItemType.RQ_USER_IDENTITY, userIdentity.length());
        put(userIdentity.getType());
        put(userIdentity.isPositiveResponseRequested() ? 1 : 0);
        encode(userIdentity.getPrimaryField());
        encode(userIdentity.getSecondaryField());
    }

    private void encode(UserIdentityAC userIdentity) {
        if (userIdentity == null)
            return;

        encodeItemHeader(ItemType.AC_USER_IDENTITY, userIdentity.length());
        encode(userIdentity.getServerResponse());
    }

    @Override
    public void write(int b) throws IOException {
        checkThread();
        flushPDataTF();
        put(b);
    }

    @Override
    public void write(byte[] b, int off, int len) throws IOException {
        checkThread();
        int pos = off;
        int remaining = len;
        while (remaining > 0) {
            flushPDataTF();
            int write = Math.min(remaining, free());
            put(b, pos, write);
            pos += write;
            remaining -= write;
        }
    }

    @Override
    public void close() {
        checkThread();
        encodePDVHeader(PDVType.LAST);
    }

    @Override
    public void copyFrom(InputStream in, int len) throws IOException {
        checkThread();
        int remaining = len;
        while (remaining > 0) {
            flushPDataTF();
            int copy = in.read(buf, pos, Math.min(remaining, free()));
            if (copy == -1)
                throw new EOFException();
            pos += copy;
            remaining -= copy;
        }
    }

    @Override
    public void copyFrom(InputStream in) throws IOException {
        checkThread();
        for (;;) {
            flushPDataTF();
            int copy = in.read(buf, pos, free());
            if (copy == -1)
                return;
            pos += copy;
        }
    }

    private void checkThread() {
        if (th != Thread.currentThread())
            throw new IllegalStateException("Entered by wrong thread");
    }

    private int free() {
        return maxpdulen + 6 - pos;
    }

    private void flushPDataTF() throws IOException {
        if (free() > 0)
            return;
        encodePDVHeader(PDVType.PENDING);
        as.writePDataTF();
    }

    private void encodePDVHeader(int last) {
        final int endpos = pos;
        final int pdvlen = endpos - pdvpos - 4;
        pos = pdvpos;
        putInt(pdvlen);
        put(pdvpcid);
        put(pdvcmd | last);
        pos = endpos;
        Association.LOG.trace("{} << PDV[len={}, pcid={}, mch={}]",
                new Object[] { as, pdvlen, pdvpcid, (pdvcmd | last) });
    }

    public void writePDataTF() throws IOException {
        int pdulen = pos - 6;
        pos = 0;
        put(PDUType.P_DATA_TF);
        put(0);
        putInt(pdulen);
        Association.LOG.trace("{} << P-DATA-TF[len={}]",
                new Object[] { as, pdulen });
        writePDU(pdulen);
    }

    public void writeDIMSE(PresentationContext pc, Attributes cmd,
            DataWriter dataWriter) throws IOException {
        synchronized (dimseLock) {
            int pcid = pc.getPCID();
            String tsuid = pc.getTransferSyntax();
            if (Dimse.LOG.isInfoEnabled()) {
                Dimse dimse = Dimse.valueOf(cmd.getInt(Tag.CommandField, -1));
                Dimse.LOG.info("{} << {}", as, dimse.toString(cmd, pcid, tsuid));
                Dimse.LOG.debug("Command:\n{}", cmd);
                if (dataWriter instanceof DataWriterAdapter)
                    Dimse.LOG.debug("Dataset:\n{}",
                            ((DataWriterAdapter) dataWriter).getDataset());
            }
            this.th = Thread.currentThread();
            maxpdulen = as.getMaxPDULengthSend();
            if (buf.length < maxpdulen + 6)
                buf = new byte[maxpdulen + 6];

            pdvpcid = pcid;
            pdvcmd = PDVType.COMMAND;
            DicomOutputStream cmdout =
                new DicomOutputStream(this, UID.ImplicitVRLittleEndian);
            cmdout.writeCommand(cmd);
            cmdout.close();
            if (dataWriter != null) {
                if (!as.isPackPDV()) {
                    as.writePDataTF();
                } else {
                    pdvpos = pos;
                    pos += 6;
                }
                pdvcmd = PDVType.DATA;
                dataWriter.writeTo(this, tsuid);
                close();
            }
            as.writePDataTF();
            this.th = null;
        }
    }
}
TOP

Related Classes of org.dcm4che3.net.PDUEncoder

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.