001/* ***** BEGIN LICENSE BLOCK ***** 002 * Version: MPL 1.1/GPL 2.0/LGPL 2.1 003 * 004 * The contents of this file are subject to the Mozilla Public License Version 005 * 1.1 (the "License"); you may not use this file except in compliance with 006 * the License. You may obtain a copy of the License at 007 * http://www.mozilla.org/MPL/ 008 * 009 * Software distributed under the License is distributed on an "AS IS" basis, 010 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License 011 * for the specific language governing rights and limitations under the 012 * License. 013 * 014 * The Original Code is part of dcm4che, an implementation of DICOM(TM) in 015 * Java(TM), hosted at https://github.com/gunterze/dcm4che. 016 * 017 * The Initial Developer of the Original Code is 018 * Agfa Healthcare. 019 * Portions created by the Initial Developer are Copyright (C) 2011 020 * the Initial Developer. All Rights Reserved. 021 * 022 * Contributor(s): 023 * See @authors listed below 024 * 025 * Alternatively, the contents of this file may be used under the terms of 026 * either the GNU General Public License Version 2 or later (the "GPL"), or 027 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), 028 * in which case the provisions of the GPL or the LGPL are applicable instead 029 * of those above. If you wish to allow use of your version of this file only 030 * under the terms of either the GPL or the LGPL, and not to allow others to 031 * use your version of this file under the terms of the MPL, indicate your 032 * decision by deleting the provisions above and replace them with the notice 033 * and other provisions required by the GPL or the LGPL. If you do not delete 034 * the provisions above, a recipient may use your version of this file under 035 * the terms of any one of the MPL, the GPL or the LGPL. 036 * 037 * ***** END LICENSE BLOCK ***** */ 038 039package org.dcm4che3.data; 040 041import java.util.Date; 042import java.util.TimeZone; 043 044import org.dcm4che3.util.ByteUtils; 045import org.dcm4che3.util.StringUtils; 046import org.dcm4che3.util.TagUtils; 047 048/** 049 * @author Gunter Zeilinger <gunterze@gmail.com> 050 */ 051enum BinaryValueType implements ValueType { 052 BYTE(1, 1) { 053 054 @Override 055 public byte[] toggleEndian(byte[] b, boolean preserve) { 056 return b; 057 } 058 059 @Override 060 protected int toInt(byte[] b, int off, boolean bigEndian) { 061 return b[off]; 062 } 063 064 @Override 065 protected byte[] toBytes(int i, byte[] b, int off, boolean bigEndian) { 066 b[off] = (byte) i; 067 return b; 068 } 069 }, 070 SHORT(2, 2) { 071 072 @Override 073 public boolean isIntValue() { 074 return true; 075 } 076 077 @Override 078 public byte[] toggleEndian(byte[] b, boolean preserve) { 079 return ByteUtils.swapShorts(preserve ? b.clone() : b, 0, b.length); 080 } 081 082 @Override 083 protected int toInt(byte[] b, int off, boolean bigEndian) { 084 return ByteUtils.bytesToShort(b, off, bigEndian); 085 } 086 087 @Override 088 protected byte[] toBytes(int i, byte[] b, int off, boolean bigEndian) { 089 return ByteUtils.shortToBytes(i, b, off, bigEndian); 090 } 091 }, 092 USHORT(2, 2) { 093 094 @Override 095 public boolean isIntValue() { 096 return true; 097 } 098 099 @Override 100 public byte[] toggleEndian(byte[] b, boolean preserve) { 101 return ByteUtils.swapShorts(preserve ? b.clone() : b, 0, b.length); 102 } 103 104 @Override 105 protected int toInt(byte[] b, int off, boolean bigEndian) { 106 return ByteUtils.bytesToUShort(b, off, bigEndian); 107 } 108 109 @Override 110 protected byte[] toBytes(int i, byte[] b, int off, boolean bigEndian) { 111 return ByteUtils.shortToBytes(i, b, off, bigEndian); 112 } 113 }, 114 INT(4, 4) { 115 116 @Override 117 public boolean isIntValue() { 118 return true; 119 } 120 121 @Override 122 public byte[] toggleEndian(byte[] b, boolean preserve) { 123 return ByteUtils.swapInts(preserve ? b.clone() : b, 0, b.length); 124 } 125 126 @Override 127 protected int toInt(byte[] b, int off, boolean bigEndian) { 128 return ByteUtils.bytesToInt(b, off, bigEndian); 129 } 130 131 @Override 132 protected byte[] toBytes(int i, byte[] b, int off, boolean bigEndian) { 133 return ByteUtils.intToBytes(i, b, off, bigEndian); 134 } 135 }, 136 TAG(4, 2) { 137 138 @Override 139 public byte[] toggleEndian(byte[] b, boolean preserve) { 140 return ByteUtils.swapShorts(preserve ? b.clone() : b, 0, b.length); 141 } 142 143 @Override 144 protected String toString(byte[] b, int off, boolean bigEndian) { 145 return TagUtils.toHexString(toInt(b, off, bigEndian)); 146 } 147 148 @Override 149 protected int toInt(byte[] b, int off, boolean bigEndian) { 150 return ByteUtils.bytesToTag(b, off, bigEndian); 151 } 152 153 @Override 154 protected byte[] toBytes(String s, byte[] b, int off, boolean bigEndian) { 155 return toBytes(Integer.parseInt(s, 16), b, off, bigEndian); 156 } 157 158 @Override 159 protected byte[] toBytes(int i, byte[] b, int off, boolean bigEndian) { 160 return ByteUtils.tagToBytes(i, b, off, bigEndian); 161 } 162 }, 163 FLOAT(4, 4) { 164 165 @Override 166 public byte[] toggleEndian(byte[] b, boolean preserve) { 167 return ByteUtils.swapInts(preserve ? b.clone() : b, 0, b.length); 168 } 169 170 @Override 171 protected String toString(byte[] b, int off, boolean bigEndian) { 172 return StringUtils 173 .formatDS(ByteUtils.bytesToFloat(b, off, bigEndian)); 174 } 175 176 @Override 177 protected float toFloat(byte[] b, int off, boolean bigEndian) { 178 return ByteUtils.bytesToFloat(b, off, bigEndian); 179 } 180 181 @Override 182 protected double toDouble(byte[] b, int off, boolean bigEndian) { 183 return ByteUtils.bytesToFloat(b, off, bigEndian); 184 } 185 186 @Override 187 protected byte[] toBytes(String s, byte[] b, int off, boolean bigEndian) { 188 return toBytes(Float.parseFloat(s), b, off, bigEndian); 189 } 190 191 @Override 192 protected byte[] toBytes(float f, byte[] b, int off, boolean bigEndian) { 193 return ByteUtils.floatToBytes(f, b, off, bigEndian); 194 } 195 196 @Override 197 protected byte[] toBytes(double d, byte[] b, int off, 198 boolean bigEndian) { 199 return ByteUtils.floatToBytes((float) d, b, off, bigEndian); 200 } 201 }, 202 DOUBLE(8, 8) { 203 204 @Override 205 public byte[] toggleEndian(byte[] b, boolean preserve) { 206 return ByteUtils.swapLongs(preserve ? b.clone() : b, 0, b.length); 207 } 208 209 @Override 210 protected String toString(byte[] b, int off, boolean bigEndian) { 211 return StringUtils 212 .formatDS(ByteUtils.bytesToDouble(b, off, bigEndian)); 213 } 214 215 @Override 216 protected float toFloat(byte[] b, int off, boolean bigEndian) { 217 return (float) ByteUtils.bytesToDouble(b, off, bigEndian); 218 } 219 220 @Override 221 protected double toDouble(byte[] b, int off, boolean bigEndian) { 222 return ByteUtils.bytesToDouble(b, off, bigEndian); 223 } 224 225 @Override 226 protected byte[] toBytes(String s, byte[] b, int off, 227 boolean bigEndian) { 228 return toBytes(Double.parseDouble(s), b, off, bigEndian); 229 } 230 231 @Override 232 protected byte[] toBytes(float f, byte[] b, int off, 233 boolean bigEndian) { 234 return ByteUtils.doubleToBytes(f, b, off, bigEndian); 235 } 236 237 @Override 238 protected byte[] toBytes(double d, byte[] b, int off, 239 boolean bigEndian) { 240 return ByteUtils.doubleToBytes(d, b, off, bigEndian); 241 } 242 }; 243 244 final int numBytes; 245 final int numEndianBytes; 246 247 private BinaryValueType(int numBytes, int numEndianBytes) { 248 this.numBytes = numBytes; 249 this.numEndianBytes = numEndianBytes; 250 } 251 252 @Override 253 public boolean isIntValue() { 254 return false; 255 } 256 257 @Override 258 public boolean isStringValue() { 259 return false; 260 } 261 262 @Override 263 public boolean useSpecificCharacterSet() { 264 return false; 265 } 266 267 @Override 268 public boolean isTemporalType() { 269 return false; 270 } 271 272 @Override 273 public int numEndianBytes() { 274 return numEndianBytes; 275 } 276 277 protected String toString(byte[] b, int off, boolean bigEndian) { 278 return Integer.toString(toInt(b, off, bigEndian)); 279 } 280 281 protected int toInt(byte[] b, int off, boolean bigEndian) { 282 throw new UnsupportedOperationException(); 283 } 284 285 protected float toFloat(byte[] b, int off, boolean bigEndian) { 286 throw new UnsupportedOperationException(); 287 } 288 289 protected double toDouble(byte[] b, int off, boolean bigEndian) { 290 throw new UnsupportedOperationException(); 291 } 292 293 protected byte[] toBytes(String s, byte[] b, int off, boolean bigEndian) { 294 return toBytes(StringUtils.parseIS(s), b, off, bigEndian); 295 } 296 297 protected byte[] toBytes(int i, byte[] b, int off, boolean bigEndian) { 298 throw new UnsupportedOperationException(); 299 } 300 301 protected byte[] toBytes(float f, byte[] b, int off, boolean bigEndian) { 302 throw new UnsupportedOperationException(); 303 } 304 305 protected byte[] toBytes(double d, byte[] b, int off, boolean bigEndian) { 306 throw new UnsupportedOperationException(); 307 } 308 309 @Override 310 public byte[] toBytes(Object val, SpecificCharacterSet cs) { 311 if (val instanceof byte[]) 312 return (byte[]) val; 313 314 throw new UnsupportedOperationException(); 315 } 316 317 @Override 318 public String toString(Object val, boolean bigEndian, int valueIndex, 319 String defVal) { 320 if (!(val instanceof byte[])) 321 throw new UnsupportedOperationException(); 322 323 byte[] b = (byte[]) val; 324 int len = b.length; 325 int off = valueIndex * numBytes; 326 return off + numBytes <= len 327 ? toString(b, off, bigEndian) 328 : defVal; 329 } 330 331 private void checkLength(int len) { 332 if (len % numBytes != 0) 333 throw new IllegalArgumentException("length: " + len); 334 } 335 336 @Override 337 public Object toStrings(Object val, boolean bigEndian, 338 SpecificCharacterSet cs) { 339 if (!(val instanceof byte[])) 340 throw new UnsupportedOperationException(); 341 342 byte[] b = (byte[]) val; 343 int len = b.length; 344 checkLength(len); 345 if (len == numBytes) 346 return toString(b, 0, bigEndian); 347 348 String[] ss = new String[len / numBytes]; 349 for (int i = 0, off = 0; i < ss.length; i++, off += numBytes) 350 ss[i] = toString(b, off, bigEndian); 351 return ss; 352 } 353 354 @Override 355 public int toInt(Object val, boolean bigEndian, int valueIndex, 356 int defVal) { 357 if (!(val instanceof byte[])) 358 throw new UnsupportedOperationException(); 359 360 byte[] b = (byte[]) val; 361 int len = b.length; 362 int off = valueIndex * numBytes; 363 return off + numBytes <= len 364 ? toInt(b, off, bigEndian) 365 : defVal; 366 } 367 368 @Override 369 public int[] toInts(Object val, boolean bigEndian) { 370 if (!(val instanceof byte[])) 371 throw new UnsupportedOperationException(); 372 373 byte[] b = (byte[]) val; 374 int len = b.length; 375 checkLength(len); 376 int[] is = new int[len / numBytes]; 377 for (int i = 0, off = 0; i < is.length; i++, off += numBytes) 378 is[i] = toInt(b, off, bigEndian); 379 return is; 380 } 381 382 @Override 383 public float toFloat(Object val, boolean bigEndian, int valueIndex, 384 float defVal) { 385 if (!(val instanceof byte[])) 386 throw new UnsupportedOperationException(); 387 388 byte[] b = (byte[]) val; 389 int len = b.length; 390 int off = valueIndex * numBytes; 391 return off + numBytes <= len 392 ? toFloat(b, off, bigEndian) 393 : defVal; 394 } 395 396 @Override 397 public float[] toFloats(Object val, boolean bigEndian) { 398 if (!(val instanceof byte[])) 399 throw new UnsupportedOperationException(); 400 401 byte[] b = (byte[]) val; 402 int len = b.length; 403 checkLength(len); 404 float[] fs = new float[len / numBytes]; 405 for (int i = 0, off = 0; i < fs.length; i++, off += numBytes) 406 fs[i] = toFloat(b, off, bigEndian); 407 return fs; 408 } 409 410 @Override 411 public double toDouble(Object val, boolean bigEndian, int valueIndex, 412 double defVal) { 413 if (!(val instanceof byte[])) 414 throw new UnsupportedOperationException(); 415 416 byte[] b = (byte[]) val; 417 int len = b.length; 418 int off = valueIndex * numBytes; 419 return off + numBytes <= len 420 ? toDouble(b, off, bigEndian) 421 : defVal; 422 } 423 424 @Override 425 public double[] toDoubles(Object val, boolean bigEndian) { 426 if (!(val instanceof byte[])) 427 throw new UnsupportedOperationException(); 428 429 byte[] b = (byte[]) val; 430 int len = b.length; 431 checkLength(len); 432 double[] ds = new double[len / numBytes]; 433 for (int i = 0, off = 0; i < ds.length; i++, off += numBytes) 434 ds[i] = toDouble(b, off, bigEndian); 435 return ds; 436 } 437 438 @Override 439 public Date toDate(Object val, TimeZone tz, int valueIndex, boolean ceil, 440 Date defVal, DatePrecision precision) { 441 throw new UnsupportedOperationException(); 442 } 443 444 @Override 445 public Date[] toDate(Object val, TimeZone tz, boolean ceil, 446 DatePrecisions precisions) { 447 throw new UnsupportedOperationException(); 448 } 449 450 @Override 451 public Object toValue(byte[] b) { 452 return b != null && b.length > 0 ? b : Value.NULL; 453 } 454 455 @Override 456 public Object toValue(String s, boolean bigEndian) { 457 if (s == null || s.isEmpty()) 458 return Value.NULL; 459 460 return toBytes(s, new byte[numBytes], 0, bigEndian); 461 } 462 463 @Override 464 public Object toValue(String[] ss, boolean bigEndian) { 465 if (ss == null || ss.length == 0) 466 return Value.NULL; 467 468 if (ss.length == 1) 469 return toValue(ss[0], bigEndian); 470 471 byte[] b = new byte[ss.length * numBytes]; 472 for (int i = 0, off = 0; i < ss.length; i++, off += numBytes) 473 toBytes(ss[i], b, off, bigEndian); 474 475 return b; 476 } 477 478 @Override 479 public Object toValue(int[] is, boolean bigEndian) { 480 if (is == null || is.length == 0) 481 return Value.NULL; 482 483 byte[] b = new byte[is.length * numBytes]; 484 for (int i = 0, off = 0; i < is.length; i++, off += numBytes) 485 toBytes(is[i], b, off, bigEndian); 486 487 return b; 488 } 489 490 @Override 491 public Object toValue(float[] fs, boolean bigEndian) { 492 if (fs == null || fs.length == 0) 493 return Value.NULL; 494 495 byte[] b = new byte[fs.length * numBytes]; 496 for (int i = 0, off = 0; i < fs.length; i++, off += numBytes) 497 toBytes(fs[i], b, off, bigEndian); 498 499 return b; 500 } 501 502 @Override 503 public Object toValue(double[] ds, boolean bigEndian) { 504 if (ds == null || ds.length == 0) 505 return Value.NULL; 506 507 byte[] b = new byte[ds.length * numBytes]; 508 for (int i = 0, off = 0; i < ds.length; i++, off += numBytes) 509 toBytes(ds[i], b, off, bigEndian); 510 511 return b; 512 } 513 514 @Override 515 public Object toValue(Date[] ds, TimeZone tz, DatePrecision precision) { 516 throw new UnsupportedOperationException(); 517 } 518 519 @Override 520 public boolean prompt(Object val, boolean bigEndian, 521 SpecificCharacterSet cs, int maxChars, StringBuilder sb) { 522 if (val instanceof byte[]) 523 return prompt((byte[]) val, bigEndian, maxChars, sb); 524 525 return StringValueType.prompt(val.toString(), maxChars, sb); 526 } 527 528 private boolean prompt(byte[] b, boolean bigEndian, int maxChars, 529 StringBuilder sb) { 530 int maxLength = sb.length() + maxChars; 531 for (int i = b.length / numBytes, off = 0; i-- > 0; off += numBytes) { 532 sb.append(toString(b, off, bigEndian)); 533 if (sb.length() > maxLength) { 534 sb.setLength(maxLength+1); 535 return false; 536 } 537 if (i > 0) 538 sb.append('\\'); 539 } 540 return true; 541 } 542 543 @Override 544 public int vmOf(Object val) { 545 if (val instanceof byte[]) { 546 return ((byte[]) val).length / numBytes; 547 } 548 throw new UnsupportedOperationException(); 549 } 550 551}