View Javadoc
1   /*
2    * Copyright (C) 2013 4th Line GmbH, Switzerland
3    *
4    * The contents of this file are subject to the terms of either the GNU
5    * Lesser General Public License Version 2 or later ("LGPL") or the
6    * Common Development and Distribution License Version 1 or later
7    * ("CDDL") (collectively, the "License"). You may not use this file
8    * except in compliance with the License. See LICENSE.txt for more
9    * information.
10   *
11   * This program is distributed in the hope that it will be useful,
12   * but WITHOUT ANY WARRANTY; without even the implied warranty of
13   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
14   */
15  
16  package org.fourthline.cling.model.types;
17  
18  import java.util.logging.Logger;
19  
20  /**
21   * A crude solution for unsigned "non-negative" types in UPnP, not usable for any arithmetic.
22   *
23   * @author Christian Bauer
24   */
25  public abstract class UnsignedVariableInteger {
26  
27      final private static Logger log = Logger.getLogger(UnsignedVariableInteger.class.getName());
28  
29      public enum Bits {
30          EIGHT(0xffL),
31          SIXTEEN(0xffffL),
32          TWENTYFOUR(0xffffffL),
33          THIRTYTWO(0xffffffffL);
34  
35          private long maxValue;
36  
37          Bits(long maxValue) {
38              this.maxValue = maxValue;
39          }
40  
41          public long getMaxValue() {
42              return maxValue;
43          }
44      }
45  
46      protected long value;
47  
48      protected UnsignedVariableInteger() {
49      }
50  
51      public UnsignedVariableInteger(long value) throws NumberFormatException {
52          setValue(value);
53      }
54  
55      public UnsignedVariableInteger(String s) throws NumberFormatException {
56          if (s.startsWith("-")) {
57              // Don't throw exception, just cut it!
58              // TODO: UPNP VIOLATION: Twonky Player returns "-1" as the track number
59              log.warning("Invalid negative integer value '" + s + "', assuming value 0!");
60              s = "0";
61          }
62          setValue(Long.parseLong(s.trim()));
63      }
64  
65      protected UnsignedVariableInteger setValue(long value) {
66          isInRange(value);
67          this.value = value;
68          return this;
69      }
70  
71      public Long getValue() {
72          return value;
73      }
74  
75      public void isInRange(long value) throws NumberFormatException {
76          if (value < getMinValue() || value > getBits().getMaxValue()) {
77              throw new NumberFormatException("Value must be between " + getMinValue() + " and " + getBits().getMaxValue() + ": " + value);
78          }
79      }
80  
81      public int getMinValue() {
82          return 0;
83      }
84  
85      public abstract Bits getBits();
86  
87      public UnsignedVariableInteger increment(boolean rolloverToOne) {
88          if (value + 1 > getBits().getMaxValue()) {
89              value = rolloverToOne ? 1 : 0;
90          } else {
91              value++;
92          }
93          return this;
94      }
95  
96      @Override
97      public boolean equals(Object o) {
98          if (this == o) return true;
99          if (o == null || getClass() != o.getClass()) return false;
100 
101         UnsignedVariableInteger that = (UnsignedVariableInteger) o;
102 
103         if (value != that.value) return false;
104 
105         return true;
106     }
107 
108     @Override
109     public int hashCode() {
110         return (int) (value ^ (value >>> 32));
111     }
112 
113     @Override
114     public String toString() {
115         return Long.toString(value);
116     }
117 
118 }