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}