VCard format: correctly co/decode escaped values
[jvcard.git] / src / be / nikiroo / jvcard / Data.java
CommitLineData
a3b510ab
NR
1package be.nikiroo.jvcard;
2
3import java.security.InvalidParameterException;
aecb3399 4import java.util.LinkedList;
a3b510ab
NR
5import java.util.List;
6
78e4af97
NR
7/**
8 * A data is a piece of information present in a {@link Contact}. It is
9 * basically a key/value pair with optional types and an optional group name.
10 *
11 * @author niki
12 *
13 */
26d2bd05 14public class Data extends BaseClass<TypeInfo> {
78e4af97
NR
15 public enum DataPart {
16 FN_FAMILY, FN_GIVEN, FN_ADDITIONAL, // Name
17 FN_PRE, FN_POST, // Pre/Post
18 BDAY_YYYY, BDAY_MM, BDAY_DD, // BDay
19 ADR_PBOX, ADR_EXTENDED, ADR_STREET, ADR_CITY, ADR_REGION, ADR_POSTAL_CODE, ADR_COUNTRY
20 // Address
21 }
22
a3b510ab
NR
23 private String name;
24 private String value;
25 private String group;
26 private int b64; // -1 = no, 0 = still not ordered, the rest is order
a3b510ab 27
78e4af97
NR
28 /**
29 * Create a new {@link Data} with the given values.
30 *
31 * @param types
32 * the types of this {@link Data}
33 * @param name
1c03abaf 34 * its name (<b>MUST NOT</b> be NULL)
78e4af97 35 * @param value
1c03abaf 36 * its value (<b>MUST NOT</b> be NULL)
78e4af97 37 * @param group
1c03abaf 38 * its group if any (or NULL if none)
78e4af97 39 */
a3b510ab 40 public Data(List<TypeInfo> types, String name, String value, String group) {
26d2bd05 41 super(types);
a3b510ab 42
1c03abaf
NR
43 this.name = name.toUpperCase();
44 this.value = value.toString(); // crash NOW if null
a3b510ab
NR
45 this.group = group;
46
47 b64 = -1;
26d2bd05 48 for (TypeInfo type : this) {
a3b510ab
NR
49 if (type.getName().equals("ENCODING")
50 && type.getValue().equals("b")) {
51 b64 = 0;
52 break;
53 }
54 }
55 }
56
78e4af97
NR
57 /**
58 * Return the name of this {@link Data}
59 *
60 * @return the name
61 */
a3b510ab
NR
62 public String getName() {
63 return name;
64 }
65
78e4af97
NR
66 /**
67 * Return the value of this {@link Data}
68 *
69 * @return the value
70 */
a3b510ab 71 public String getValue() {
aecb3399
NR
72 return unescape(value);
73 }
74
75 /**
76 * Return the RAW value of this {@link Data}
77 *
78 * @return the RAW value
79 */
80 public String getRawValue() {
a3b510ab
NR
81 return value;
82 }
83
78e4af97
NR
84 /**
85 * Change the value of this {@link Data}
86 *
87 * @param value
88 * the new value
89 */
bcb54330 90 public void setValue(String value) {
aecb3399
NR
91 value = escape(value);
92
bcb54330
NR
93 if ((value == null && this.value != null)
94 || (value != null && !value.equals(this.value))) {
95 this.value = value;
96 setDirty();
97 }
98 }
99
aecb3399
NR
100 /**
101 * Return the {@link List} of comma-listed values from this {@link Data}.
102 *
103 * @return the {@link List} of values
104 */
105 public List<String> getValues() {
106 return getList(',');
107 }
108
109 /**
110 * Set the {@link List} of comma-listed values from this {@link Data}.
111 *
112 * @param values
113 * the {@link List} of values
114 */
115 public void setValues(List<String> values) {
116 setList(values, ',');
117 }
118
119 /**
120 * Return the {@link List} of semi-column-listed fields from this
121 * {@link Data}.
122 *
123 * @return the {@link List} of values
124 */
125 public List<String> getFields() {
126 return getList(';');
127 }
128
129 /**
130 * Set the {@link List} of comma-listed values from this {@link Data}.
131 *
132 * @param values
133 * the {@link List} of values
134 */
135 public void setFields(List<String> values) {
136 setList(values, ';');
137 }
138
78e4af97
NR
139 /**
140 * Return the group of this {@link Data}
141 *
142 * @return the group
143 */
a3b510ab
NR
144 public String getGroup() {
145 return group;
146 }
147
176a8327
NR
148 /**
149 * Change the group of this {@link Data}
150 *
151 * @param group
152 * the new group
153 */
154 public void setGroup(String group) {
155 if ((group == null && this.group != null)
156 || (group != null && !group.equals(this.group))) {
157 this.group = group;
158 setDirty();
159 }
160 }
161
78e4af97
NR
162 /**
163 * Return the bkey number of this {@link Data} or -1 if it is not binary.
164 *
165 * @return the bkey or -1
166 */
a3b510ab
NR
167 public int getB64Key() {
168 return b64;
169 }
170
aecb3399
NR
171 /**
172 * Check if this {@link Data} is binary
173 *
174 * @return TRUE if it is
175 */
176 public boolean isBinary() {
177 return b64 >= 0;
178 }
179
180 /**
181 * Check if this {@link Data} has the "preferred" flag.
182 *
183 * @return TRUE if it has
184 */
185 public boolean isPreferred() {
186 for (TypeInfo type : this) {
187 if (type.getName().equals("TYPE") && type.getValue().equals("pref")) {
188 return true;
189 }
190 }
191
192 return false;
193 }
194
78e4af97
NR
195 /**
196 * Change the bkey of this {@link Data}
197 *
198 * @param i
199 * the new bkey
200 *
201 * @throw InvalidParameterException if the {@link Data} is not binary or if
202 * it is but you try to set a negative bkey
203 */
a3b510ab
NR
204 void resetB64Key(int i) {
205 if (!isBinary())
206 throw new InvalidParameterException(
207 "Cannot add a BKey on a non-binary object");
208 if (i < 0)
209 throw new InvalidParameterException(
210 "Cannot remove the BKey on a binary object");
211
212 b64 = i;
213 }
214
78e4af97 215 /**
aecb3399
NR
216 * Return the {@link List} of sep-listed values from this {@link String}
217 * data.
78e4af97 218 *
aecb3399
NR
219 * @param value
220 * the data
221 *
222 * @param the
223 * separator
224 *
225 * @return the {@link List} of values
78e4af97 226 */
aecb3399
NR
227 private List<String> getList(char sep) {
228 List<String> rep = new LinkedList<String>();
229
230 if (value != null && value.length() > 0) {
231 int last = 0;
232 for (int i = 0; i < value.length(); i++) {
233 if (value.charAt(i) == sep
234 && (i == 0 || value.charAt(i - 1) != '\\')) {
235 rep.add(value.substring(last, i - last));
236 }
237 }
238
239 rep.add(value.substring(last));
240 }
241
242 return rep;
a3b510ab 243 }
e253bd50 244
3634193b 245 /**
aecb3399
NR
246 * Create the {@link String}-encoded {@link List} of sep-listed values from
247 * the given values.
3634193b 248 *
aecb3399
NR
249 * @param values
250 * the {@link List} of values
251 *
252 * @param sep
253 * the separator
254 *
255 * @return the {@link String}
3634193b 256 */
aecb3399
NR
257 private void setList(List<String> values, char sep) {
258 StringBuilder builder = new StringBuilder();
259 boolean first = true;
260 for (String value : values) {
261 if (!first)
262 builder.append(sep);
263
264 builder.append(escape(value));
265
266 first = false;
3634193b
NR
267 }
268
aecb3399 269 value = builder.toString();
3634193b
NR
270 }
271
e253bd50
NR
272 @Override
273 public String getId() {
274 return "" + name;
275 }
276
277 @Override
278 public String getState() {
e4444b0b 279 return ("" + name + value + group).replace(' ', '_');
e253bd50 280 }
a3b510ab 281}