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.StringUtils; 045 046/** 047 * @author Gunter Zeilinger <gunterze@gmail.com> 048 */ 049enum StringValueType implements ValueType { 050 ASCII("\\", null), 051 STRING("\\", null){ 052 053 @Override 054 public boolean useSpecificCharacterSet() { 055 return true; 056 } 057 058 @Override 059 protected SpecificCharacterSet cs(SpecificCharacterSet cs) { 060 return cs; 061 } 062 }, 063 TEXT("\t\n\f\r", null) { 064 065 @Override 066 public boolean useSpecificCharacterSet() { 067 return true; 068 } 069 070 @Override 071 protected SpecificCharacterSet cs(SpecificCharacterSet cs) { 072 return cs; 073 } 074 075 @Override 076 protected Object splitAndTrim(String s, SpecificCharacterSet cs) { 077 return cs.toText(StringUtils.trimTrailing(s)); 078 } 079 }, 080 UR(null, null) { 081 082 @Override 083 protected Object splitAndTrim(String s, SpecificCharacterSet cs) { 084 return StringUtils.trimTrailing(s); 085 } 086 }, 087 DA("\\", TemporalType.DA), 088 DT("\\", TemporalType.DT), 089 TM("\\", TemporalType.TM), 090 PN("^=\\", null){ 091 092 @Override 093 public boolean useSpecificCharacterSet() { 094 return true; 095 } 096 097 @Override 098 protected SpecificCharacterSet cs(SpecificCharacterSet cs) { 099 return cs; 100 } 101 }, 102 DS("\\", null) { 103 104 @Override 105 public byte[] toBytes(Object val, SpecificCharacterSet cs) { 106 107 if (val instanceof double[]) 108 val = toStrings((double[]) val); 109 return super.toBytes(val, cs); 110 } 111 112 @Override 113 public String toString(Object val, boolean bigEndian, int valueIndex, 114 String defVal) { 115 116 if (val instanceof double[]) { 117 double[] ds = (double[]) val; 118 return (valueIndex < ds.length 119 && !Double.isNaN(ds[valueIndex])) 120 ? StringUtils.formatDS(ds[valueIndex]) 121 : defVal; 122 } 123 return super.toString(val, bigEndian, valueIndex, defVal); 124 } 125 126 @Override 127 public Object toStrings(Object val, boolean bigEndian, 128 SpecificCharacterSet cs) { 129 130 return (val instanceof double[]) 131 ? toStrings((double[]) val) 132 : super.toStrings(val, bigEndian, cs); 133 } 134 135 private Object toStrings(double[] ds) { 136 if (ds.length == 1) 137 return StringUtils.formatDS(ds[0]); 138 139 String[] ss = new String[ds.length]; 140 for (int i = 0; i < ds.length; i++) 141 ss[i] = !Double.isNaN(ds[i]) ? StringUtils.formatDS(ds[i]) : ""; 142 143 return ss; 144 } 145 146 @Override 147 public float toFloat(Object val, boolean bigEndian, int valueIndex, 148 float defVal) { 149 double[] ds = (double[]) val; 150 return valueIndex < ds.length && !Double.isNaN(ds[valueIndex]) 151 ? (float) ds[valueIndex] 152 : defVal; 153 } 154 155 @Override 156 public float[] toFloats(Object val, boolean bigEndian) { 157 double[] ds = (double[]) val; 158 float[] fs = new float[ds.length]; 159 for (int i = 0; i < fs.length; i++) 160 fs[i] = (float) ds[i]; 161 return fs; 162 } 163 164 @Override 165 public double toDouble(Object val, boolean bigEndian, int valueIndex, 166 double defVal) { 167 double[] ds = (double[]) val; 168 return valueIndex < ds.length && !Double.isNaN(ds[valueIndex]) 169 ? ds[valueIndex] 170 : defVal; 171 } 172 173 @Override 174 public double[] toDoubles(Object val, boolean bigEndian) { 175 return (double[]) val; 176 } 177 178 @Override 179 public Object toValue(float[] fs, boolean bigEndian) { 180 if (fs == null || fs.length == 0) 181 return Value.NULL; 182 183 if (fs.length == 1) 184 return StringUtils.formatDS(fs[0]); 185 186 String[] ss = new String[fs.length]; 187 for (int i = 0; i < fs.length; i++) 188 ss[i] = StringUtils.formatDS(fs[i]); 189 return ss; 190 } 191 192 @Override 193 public Object toValue(double[] ds, boolean bigEndian) { 194 if (ds == null || ds.length == 0) 195 return Value.NULL; 196 197 return ds; 198 } 199 200 @Override 201 public boolean prompt(Object val, boolean bigEndian, 202 SpecificCharacterSet cs, int maxChars, StringBuilder sb) { 203 if (val instanceof double[]) 204 val = toStrings((double[]) val); 205 return super.prompt(val, bigEndian, cs, maxChars, sb); 206 } 207 }, 208 IS("\\", null) { 209 210 @Override 211 public boolean isIntValue() { 212 return true; 213 } 214 215 @Override 216 public byte[] toBytes(Object val, SpecificCharacterSet cs) { 217 218 if (val instanceof int[]) 219 val = toStrings((int[]) val); 220 return super.toBytes(val, cs); 221 } 222 223 @Override 224 public String toString(Object val, boolean bigEndian, int valueIndex, 225 String defVal) { 226 227 if (val instanceof int[]) { 228 int[] is = (int[]) val; 229 return (valueIndex < is.length 230 && is[valueIndex] != Integer.MIN_VALUE) 231 ? Integer.toString(is[valueIndex]) 232 : defVal; 233 } 234 return super.toString(val, bigEndian, valueIndex, defVal); 235 } 236 237 @Override 238 public Object toStrings(Object val, boolean bigEndian, 239 SpecificCharacterSet cs) { 240 241 return (val instanceof int[]) 242 ? toStrings((int[]) val) 243 : super.toStrings(val, bigEndian, cs); 244 } 245 246 private Object toStrings(int[] is) { 247 if (is.length == 1) 248 return Integer.toString(is[0]); 249 250 String[] ss = new String[is.length]; 251 for (int i = 0; i < is.length; i++) 252 ss[i] = is[i] != Integer.MIN_VALUE ? Integer.toString(is[i]) : ""; 253 254 return ss; 255 } 256 257 @Override 258 public int toInt(Object val, boolean bigEndian, int valueIndex, 259 int defVal) { 260 int[] is = (int[]) val; 261 return valueIndex < is.length && is[valueIndex] != Integer.MIN_VALUE 262 ? is[valueIndex] 263 : defVal; 264 } 265 266 @Override 267 public int[] toInts(Object val, boolean bigEndian) { 268 return (int[]) val; 269 } 270 271 @Override 272 public Object toValue(int[] is, boolean bigEndian) { 273 if (is == null || is.length == 0) 274 return Value.NULL; 275 276 return is; 277 } 278 279 @Override 280 public boolean prompt(Object val, boolean bigEndian, 281 SpecificCharacterSet cs, int maxChars, StringBuilder sb) { 282 if (val instanceof int[]) 283 val = toStrings((int[]) val); 284 return super.prompt(val, bigEndian, cs, maxChars, sb); 285 } 286 }; 287 288 final String delimiters; 289 final TemporalType temporalType; 290 291 StringValueType(String delimiters, TemporalType temperalType) { 292 this.delimiters = delimiters; 293 this.temporalType = temperalType; 294 } 295 296 @Override 297 public boolean isStringValue() { 298 return true; 299 } 300 301 @Override 302 public boolean isIntValue() { 303 return false; 304 } 305 306 @Override 307 public boolean isTemporalType() { 308 return temporalType != null; 309 } 310 311 @Override 312 public int numEndianBytes() { 313 return 1; 314 } 315 316 @Override 317 public byte[] toggleEndian(byte[] b, boolean preserve) { 318 return b; 319 } 320 321 @Override 322 public boolean useSpecificCharacterSet() { 323 return false; 324 } 325 326 protected SpecificCharacterSet cs(SpecificCharacterSet cs) { 327 return SpecificCharacterSet.ASCII; 328 } 329 330 @Override 331 public byte[] toBytes(Object val, SpecificCharacterSet cs) { 332 333 if (val instanceof byte[]) 334 return (byte[]) val; 335 336 if (val instanceof String) 337 return cs(cs).encode((String) val, delimiters); 338 339 if (val instanceof String[]) 340 return cs(cs).encode( 341 StringUtils.concat((String[]) val, '\\'), delimiters); 342 343 throw new UnsupportedOperationException(); 344 } 345 346 @Override 347 public String toString(Object val, boolean bigEndian, int valueIndex, 348 String defVal) { 349 350 if (val instanceof String) 351 return (String) (valueIndex == 0 ? val : defVal); 352 353 if (val instanceof String[]) { 354 String[] ss = (String[]) val; 355 return (valueIndex < ss.length && ss[valueIndex] != null && !ss[valueIndex].isEmpty()) 356 ? ss[valueIndex] 357 : defVal; 358 } 359 360 throw new UnsupportedOperationException(); 361 } 362 363 @Override 364 public Object toStrings(Object val, boolean bigEndian, 365 SpecificCharacterSet cs) { 366 367 if (val instanceof byte[]) { 368 return splitAndTrim(cs(cs).decode((byte[]) val), cs); 369 } 370 371 if (val instanceof String 372 || val instanceof String[]) 373 return val; 374 375 throw new UnsupportedOperationException(); 376 } 377 378 protected Object splitAndTrim(String s, SpecificCharacterSet cs) { 379 return StringUtils.splitAndTrim(s, '\\'); 380 } 381 382 @Override 383 public int toInt(Object val, boolean bigEndian, int valueIndex, 384 int defVal) { 385 throw new UnsupportedOperationException(); 386 } 387 388 @Override 389 public int[] toInts(Object val, boolean bigEndian) { 390 throw new UnsupportedOperationException(); 391 } 392 393 @Override 394 public float toFloat(Object val, boolean bigEndian, int valueIndex, 395 float defVal) { 396 throw new UnsupportedOperationException(); 397 } 398 399 @Override 400 public float[] toFloats(Object val, boolean bigEndian) { 401 throw new UnsupportedOperationException(); 402 } 403 404 @Override 405 public double toDouble(Object val, boolean bigEndian, int valueIndex, 406 double defVal) { 407 throw new UnsupportedOperationException(); 408 } 409 410 @Override 411 public double[] toDoubles(Object val, boolean bigEndian) { 412 throw new UnsupportedOperationException(); 413 } 414 415 416 @Override 417 public Date toDate(Object val, TimeZone tz, int valueIndex, boolean ceil, 418 Date defVal, DatePrecision precision) { 419 if (temporalType == null) 420 throw new UnsupportedOperationException(); 421 422 if (val instanceof String) { 423 return valueIndex == 0 424 ? temporalType.parse(tz, (String) val, ceil, precision) 425 : defVal; 426 } 427 if (val instanceof String[]) { 428 String[] ss = (String[]) val; 429 return (valueIndex < ss.length && ss[valueIndex] != null) 430 ? temporalType.parse(tz, ss[valueIndex], ceil, precision) 431 : defVal; 432 } 433 throw new UnsupportedOperationException(); 434 } 435 436 @Override 437 public Date[] toDate(Object val, TimeZone tz, boolean ceil, 438 DatePrecisions precisions) { 439 if (temporalType == null) 440 throw new UnsupportedOperationException(); 441 442 if (val instanceof String) { 443 precisions.precisions = new DatePrecision[1]; 444 return new Date[] { temporalType.parse(tz, (String) val, ceil, 445 precisions.precisions[0] = new DatePrecision()) }; 446 } 447 if (val instanceof String[]) { 448 String[] ss = (String[]) val; 449 Date[] is = new Date[ss.length]; 450 precisions.precisions = new DatePrecision[ss.length]; 451 for (int i = 0; i < is.length; i++) { 452 if (ss[i] != null) { 453 is[i] = temporalType.parse(tz, ss[i], ceil, 454 precisions.precisions[i] = new DatePrecision()); 455 } 456 } 457 return is; 458 } 459 throw new UnsupportedOperationException(); 460 } 461 462 @Override 463 public Object toValue(byte[] b) { 464 return b != null && b.length > 0 ? b : Value.NULL; 465 } 466 467 @Override 468 public Object toValue(String s, boolean bigEndian) { 469 if (s == null || s.isEmpty()) 470 return Value.NULL; 471 472 return s; 473 } 474 475 @Override 476 public Object toValue(String[] ss, boolean bigEndian) { 477 if (ss == null || ss.length == 0) 478 return Value.NULL; 479 480 if (ss.length == 1) 481 return toValue(ss[0], bigEndian); 482 483 return ss; 484 } 485 486 @Override 487 public Object toValue(int[] is, boolean bigEndian) { 488 throw new UnsupportedOperationException(); 489 } 490 491 @Override 492 public Object toValue(float[] fs, boolean bigEndian) { 493 throw new UnsupportedOperationException(); 494 } 495 496 @Override 497 public Object toValue(double[] ds, boolean bigEndian) { 498 throw new UnsupportedOperationException(); 499 } 500 501 @Override 502 public Object toValue(Date[] ds, TimeZone tz, DatePrecision precision) { 503 if (temporalType == null) 504 throw new UnsupportedOperationException(); 505 506 if (ds == null || ds.length == 0) 507 return Value.NULL; 508 509 if (ds.length == 1) 510 return temporalType.format(tz, ds[0], precision); 511 512 String[] ss = new String[ds.length]; 513 for (int i = 0; i < ss.length; i++) { 514 ss[i] = temporalType.format(tz, ds[i], precision); 515 } 516 return ss; 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(cs(cs).decode((byte[]) val), maxChars, sb); 524 525 if (val instanceof String) 526 return prompt((String) val, maxChars, sb); 527 528 if (val instanceof String[]) 529 return prompt((String[]) val, maxChars, sb); 530 531 return prompt(val.toString(), maxChars, sb); 532 } 533 534 static boolean prompt(String s, int maxChars, StringBuilder sb) { 535 int maxLength = sb.length() + maxChars; 536 sb.append(s.trim()); 537 if (sb.length() > maxLength) { 538 sb.setLength(maxLength+1); 539 return false; 540 } 541 return true; 542 } 543 544 static boolean prompt(String[] ss, int maxChars, 545 StringBuilder sb) { 546 int maxLength = sb.length() + maxChars; 547 for (String s : ss) { 548 if (s != null) 549 sb.append(s); 550 if (sb.length() > maxLength) { 551 sb.setLength(maxLength+1); 552 return false; 553 } 554 sb.append('\\'); 555 } 556 sb.setLength(sb.length()-1); 557 return true; 558 } 559 560 @Override 561 public int vmOf(Object val) { 562 if (val instanceof String) 563 return 1; 564 565 if (val instanceof String[]) { 566 String[] ss = (String[]) val; 567 return ss.length; 568 } 569 570 throw new UnsupportedOperationException(); 571 } 572}