/******************************************************************************* * Copyright (c) 2016 Weasis Team and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Nicolas Roduit - initial API and implementation *******************************************************************************/ package org.weasis.dicom.explorer.wado; import java.io.IOException; import java.io.InputStream; import java.io.InterruptedIOException; import org.weasis.core.api.gui.task.SeriesProgressMonitor; import org.weasis.core.api.media.data.Series; public class DicomSeriesProgressMonitor extends SeriesProgressMonitor { private volatile boolean wadoRequest; private volatile byte[] header; public DicomSeriesProgressMonitor(final Series series, InputStream in, boolean wadoRequest) { super(series, in); this.wadoRequest = wadoRequest; if (wadoRequest) { header = new byte[512]; } } @Override public int read(byte[] b) throws IOException { int nr = super.read(b); if (wadoRequest) { /* * header.length (512) is an empirical value: 132 is the magic number position + something to be sure to get * Transfer Syntax UID (0x0002, 0x0010) */ if (nread < header.length) { System.arraycopy(b, 0, header, nread - nr, nr); } else { wadoRequest = false; int length = header.length - (nread - nr); System.arraycopy(b, 0, header, nread - nr, length); readMetaInfo(this, header); header = null; } } return nr; } @Override public int read(byte[] b, int off, int len) throws IOException { int nr = super.read(b, off, len); if (wadoRequest) { if (nread < header.length) { System.arraycopy(b, off, header, nread - nr, nr); } else { wadoRequest = false; int length = header.length - (nread - nr); System.arraycopy(b, off, header, nread - nr, length); readMetaInfo(this, header); header = null; } } return nr; } public static void readMetaInfo(DicomSeriesProgressMonitor progress, byte[] b) throws IOException { if (b == null) { return; } int byteOffset; if (b.length > 132 && "DICM".equals(new String(b, 128, 4))) { //$NON-NLS-1$ byteOffset = 132; } else { InterruptedIOException exc = new InterruptedIOException("Not a DICOM file"); //$NON-NLS-1$ exc.bytesTransferred = progress.nread; progress.series.setFileSize(progress.series.getFileSize() - progress.nread); progress.nread = 0; throw exc; } int endByteOffset = b.length - 1; while (byteOffset < endByteOffset) { int group = extractUnsigned16(b, byteOffset); int element = extractUnsigned16(b, byteOffset + 2); byteOffset += 4; if ((group == 0x0002 && element > 0x0010) || group > 0x0002) { break; } byte[] vr = { b[byteOffset], b[byteOffset + 1] }; byteOffset += 2; int vl; if (isShortValueLengthVR(vr)) { vl = extractUnsigned16(b, byteOffset); byteOffset += 2; } else { // 2 reserved bytes // cast to int (should not be a big number in meta information) vl = (int) extractUnsigned32(b, byteOffset + 2); byteOffset += 6; } // (0x0002, 0x0010) Transfer Syntax UID if (element == 0x0010 && vl != 0 && byteOffset + vl < b.length) { String tsuid = new String(b, byteOffset, vl); if (!DicomManager.getInstance().containsImageioCodec(tsuid)) { InterruptedIOException exc = new InterruptedIOException("No image decoder found for the syntax " + tsuid); //$NON-NLS-1$ exc.bytesTransferred = Integer.MIN_VALUE; progress.series.setFileSize(progress.series.getFileSize() - progress.nread); progress.nread = 0; throw exc; } break; } byteOffset += vl; } } static int extractUnsigned16(byte[] b, int offset) { if (offset + 1 >= b.length) { return 0; } int v1 = b[offset] & 0xff; int v2 = b[offset + 1] & 0xff; return (v2 << 8) | v1; } static long extractUnsigned32(byte[] b, int offset) { if (offset + 4 >= b.length) { return 0; } long v1 = ((long) b[offset]) & 0xff; long v2 = ((long) b[offset + 1]) & 0xff; long v3 = ((long) b[offset + 2]) & 0xff; long v4 = ((long) b[offset + 3]) & 0xff; return (((((v4 << 8) | v3) << 8) | v2) << 8) | v1; } static final boolean isShortValueLengthVR(byte[] vr) { return vr[0] == 'A' && (vr[1] == 'E' || vr[1] == 'S' || vr[1] == 'T') || vr[0] == 'C' && vr[1] == 'S' || vr[0] == 'D' && (vr[1] == 'A' || vr[1] == 'S' || vr[1] == 'T') || vr[0] == 'F' && (vr[1] == 'D' || vr[1] == 'L') || vr[0] == 'I' && vr[1] == 'S' || vr[0] == 'L' && (vr[1] == 'O' || vr[1] == 'T') || vr[0] == 'P' && vr[1] == 'N' || vr[0] == 'S' && (vr[1] == 'H' || vr[1] == 'L' || vr[1] == 'S' || vr[1] == 'T') || vr[0] == 'T' && vr[1] == 'M' || vr[0] == 'U' && (vr[1] == 'I' || vr[1] == 'L' || vr[1] == 'S'); } }