1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.myfaces.trinidad.convert;
20
21 import java.awt.Color;
22
23 import java.text.FieldPosition;
24 import java.text.ParsePosition;
25
26 import org.apache.myfaces.trinidad.logging.TrinidadLogger;
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68 class RGBColorFormat extends ColorFormat
69 {
70
71
72
73
74
75 public RGBColorFormat(
76 String pattern)
77 {
78 if (pattern == null)
79 throw new IllegalArgumentException();
80
81 _pattern = pattern;
82 }
83
84
85
86
87 @Override
88 public Object parseObject(
89 String text,
90 ParsePosition pos)
91 {
92
93 if (text == null)
94 return null;
95
96 int start = pos.getIndex();
97 int oldStart = start;
98
99 boolean inQuote = false;
100 char prevCh = 0;
101 int count = 0;
102 int interQuoteCount = 1;
103 int[] rgba = new int[_FIELD_COUNT];
104 rgba[_ALPHA_FIELD] = 255;
105
106 for (int i=0; i < _pattern.length(); i++)
107 {
108 char ch = _pattern.charAt(i);
109
110 if (inQuote)
111 {
112 if (ch == '\'')
113 {
114
115 inQuote = false;
116
117
118 if (count == 0)
119 {
120 if (start >= text.length() || ch != text.charAt(start))
121 {
122 pos.setIndex(oldStart);
123 pos.setErrorIndex(start);
124 return null;
125 }
126 start++;
127 }
128 count = 0;
129 interQuoteCount = 0;
130 }
131 else
132 {
133
134 if (start >= text.length() || ch != text.charAt(start))
135 {
136
137
138
139 pos.setIndex(oldStart);
140 pos.setErrorIndex(start);
141 return null;
142 }
143 count++;
144 start++;
145 }
146 }
147 else
148 {
149 if (ch == '\'')
150 {
151 inQuote = true;
152 if (count > 0)
153 {
154 int startOffset = start;
155 start = _subParse(rgba, text, start, prevCh, count);
156 if (start < 0)
157 {
158 pos.setIndex(oldStart);
159 pos.setErrorIndex(startOffset);
160 return null;
161 }
162 count = 0;
163 }
164
165 if (interQuoteCount == 0)
166 {
167
168
169
170 int startOffset = start;
171 if (start >= text.length() || ch != text.charAt(start))
172 {
173 pos.setIndex(oldStart);
174 pos.setErrorIndex(startOffset);
175 return null;
176 }
177 start++;
178 count = 1;
179 }
180 }
181 else if (ch >= 'a' && ch <= 'z' || ch >= 'A' && ch <= 'Z')
182 {
183
184 if (ch != prevCh && count > 0)
185 {
186 int startOffset = start;
187 start = _subParse(rgba, text, start, prevCh, count);
188 if (start < 0)
189 {
190 pos.setIndex(oldStart);
191 pos.setErrorIndex(startOffset);
192 return null;
193 }
194 prevCh = ch;
195 count = 1;
196 }
197 else
198 {
199 if (ch != prevCh)
200 prevCh = ch;
201 count++;
202 }
203 }
204 else if (count > 0)
205 {
206
207
208 int startOffset = start;
209 start = _subParse(rgba, text, start, prevCh, count);
210 if ( start < 0 )
211 {
212 pos.setIndex(oldStart);
213 pos.setErrorIndex(startOffset);
214 return null;
215 }
216 if (start >= text.length() || ch != text.charAt(start))
217 {
218
219
220 pos.setIndex(oldStart);
221 pos.setErrorIndex(start);
222 return null;
223 }
224 start++;
225 count = 0;
226 prevCh = 0;
227 }
228 else
229 {
230 if (start >= text.length() || ch != text.charAt(start))
231 {
232
233
234 pos.setIndex(oldStart);
235 pos.setErrorIndex(start);
236 return null;
237 }
238 start++;
239 }
240
241 interQuoteCount++;
242 }
243 }
244
245 if (count > 0)
246 {
247 int startOffset = start;
248 start = _subParse(rgba, text, start, prevCh, count);
249 if (start < 0)
250 {
251 pos.setIndex(oldStart);
252 pos.setErrorIndex(startOffset);
253 return null;
254 }
255 }
256
257 pos.setIndex(start);
258
259 return new Color(rgba[_RED_FIELD],
260 rgba[_GREEN_FIELD],
261 rgba[_BLUE_FIELD],
262 rgba[_ALPHA_FIELD]);
263
264 }
265
266 @Override
267 public StringBuffer format(
268 Color color,
269 StringBuffer toAppendTo,
270 FieldPosition pos)
271 {
272
273 pos.setBeginIndex(0);
274 pos.setEndIndex(0);
275
276
277 if (color == null)
278 return toAppendTo;
279
280 boolean inQuote = false;
281 char prevCh = 0;
282 int count = 0;
283 for (int i=0; i < _pattern.length(); ++i)
284 {
285 char ch = _pattern.charAt(i);
286
287
288 if (ch != prevCh && count > 0)
289 {
290 toAppendTo = _subFormat(color, prevCh, count, toAppendTo);
291 count = 0;
292 }
293 if (ch == '\'')
294 {
295
296
297 if ((i+1) < _pattern.length() &&
298 _pattern.charAt(i+1) == '\'')
299 {
300 toAppendTo.append('\'');
301 ++i;
302 }
303 else
304 {
305 inQuote = !inQuote;
306 }
307 }
308 else if (!inQuote &&
309 (ch >= 'a' && ch <= 'z' || ch >= 'A' && ch <= 'Z'))
310 {
311
312
313 prevCh = ch;
314 ++count;
315 }
316 else
317 {
318
319 toAppendTo.append(ch);
320 }
321 }
322
323 if (count > 0)
324 {
325 toAppendTo = _subFormat(color, prevCh, count, toAppendTo);
326 }
327
328 return toAppendTo;
329 }
330
331 public int length()
332 {
333 int size = 0;
334 boolean inQuote = false;
335 char prevCh = 0;
336 int count = 0;
337 for (int i=0; i < _pattern.length(); ++i)
338 {
339 char ch = _pattern.charAt(i);
340
341
342 if (ch != prevCh && count > 0)
343 {
344 size += _subLength(prevCh);
345 count = 0;
346 }
347 if (ch == '\'')
348 {
349
350
351 if ((i+1) < _pattern.length() &&
352 _pattern.charAt(i+1) == '\'')
353 {
354 size++;
355 ++i;
356 }
357 else
358 {
359 inQuote = !inQuote;
360 }
361 }
362 else if (!inQuote &&
363 (ch >= 'a' && ch <= 'z' || ch >= 'A' && ch <= 'Z'))
364 {
365
366
367 prevCh = ch;
368 ++count;
369 }
370 else
371 {
372
373 size++;
374 }
375 }
376
377 if (count > 0)
378 {
379 size += _subLength(prevCh);
380 }
381
382 return size;
383 }
384
385
386 private int _subLength(
387 char ch)
388 {
389 switch (ch)
390 {
391 case 'r':
392 case 'g':
393 case 'b':
394 case 'a':
395 return 3;
396 case 'R':
397 case 'G':
398 case 'B':
399 case 'A':
400 return 2;
401 default:
402 throw new IllegalArgumentException(_LOG.getMessage(
403 "ILLEGAL_PATTERN_CHARACTER", ch));
404 }
405 }
406
407
408 private int _subParse(
409 int[] rgba,
410 String text,
411 int start,
412 char ch,
413 int count)
414 {
415 switch (ch)
416 {
417 case 'r':
418 return _subParseDecimal(rgba, _RED_FIELD, text, start, count);
419 case 'g':
420 return _subParseDecimal(rgba, _GREEN_FIELD, text, start, count);
421 case 'b':
422 return _subParseDecimal(rgba, _BLUE_FIELD, text, start, count);
423 case 'a':
424 return _subParseDecimal(rgba, _ALPHA_FIELD, text, start, count);
425 case 'R':
426 return _subParseHex(rgba, _RED_FIELD, text, start, count);
427 case 'G':
428 return _subParseHex(rgba, _GREEN_FIELD, text, start, count);
429 case 'B':
430 return _subParseHex(rgba, _BLUE_FIELD, text, start, count);
431 case 'A':
432 return _subParseHex(rgba, _ALPHA_FIELD, text, start, count);
433 default:
434 throw new IllegalArgumentException(_LOG.getMessage(
435 "ILLEGAL_PATTERN_CHARACTER", ch));
436 }
437 }
438
439 private int _subParseDecimal(
440 int[] rgba,
441 int field,
442 String text,
443 int start,
444 int count)
445 {
446 return _subParseBase(rgba, field, text, start, count, 3, 10);
447 }
448
449 private int _subParseHex(
450 int[] rgba,
451 int field,
452 String text,
453 int start,
454 int count)
455 {
456 return _subParseBase(rgba, field, text, start, count, 2, 16);
457 }
458
459 private int _subParseBase(
460 int[] rgba,
461 int field,
462 String text,
463 int start,
464 int minDigits,
465 int maxDigits,
466 int base)
467 {
468 int length = text.length();
469 int atLeast = start + minDigits;
470
471
472 if (atLeast > length)
473 return -start;
474
475 int index;
476 int end = Math.min(length, start + maxDigits);
477 int value = 0;
478
479 for(index=start; index < end; index++)
480 {
481 int digit = Character.digit(text.charAt(index), base);
482
483 if (digit == -1)
484 {
485
486 if (index < atLeast)
487 return -start;
488 else
489 break;
490 }
491
492 value *= base;
493 value += digit;
494 }
495
496 rgba[field] = value;
497
498 return index;
499 }
500
501
502 private StringBuffer _subFormat(
503 Color color,
504 char ch,
505 int count,
506 StringBuffer toAppendTo) throws IllegalArgumentException
507 {
508 switch (ch)
509 {
510 case 'r':
511 return _subFormatDecimal(color.getRed(), count, toAppendTo);
512 case 'g':
513 return _subFormatDecimal(color.getGreen(), count, toAppendTo);
514 case 'b':
515 return _subFormatDecimal(color.getBlue(), count, toAppendTo);
516 case 'a':
517 return _subFormatDecimal(color.getAlpha(), count, toAppendTo);
518 case 'R':
519 return _subFormatHex(color.getRed(), count, toAppendTo);
520 case 'G':
521 return _subFormatHex(color.getGreen(), count, toAppendTo);
522 case 'B':
523 return _subFormatHex(color.getBlue(), count, toAppendTo);
524 case 'A':
525 return _subFormatHex(color.getAlpha(), count, toAppendTo);
526 default:
527 throw new IllegalArgumentException(_LOG.getMessage(
528 "ILLEGAL_PATTERN_CHARACTER", ch));
529 }
530 }
531
532 private StringBuffer _subFormatDecimal(
533 int value,
534 int minDigits,
535 StringBuffer toAppendTo)
536 {
537 _prefixZeros(value, 10, minDigits, toAppendTo);
538 toAppendTo.append(value);
539 return toAppendTo;
540 }
541
542 private StringBuffer _subFormatHex(
543 int value,
544 int minDigits,
545 StringBuffer toAppendTo)
546 {
547 String hexString = Integer.toHexString(value);
548 int digits = hexString.length();
549
550 for (int i=0; i < minDigits - digits; i++)
551 toAppendTo.append('0');
552
553 toAppendTo.append(Integer.toHexString(value).toUpperCase());
554
555 return toAppendTo;
556 }
557
558 private StringBuffer _prefixZeros(
559 int value,
560 int base,
561 int minDigits,
562 StringBuffer toAppendTo)
563 {
564 if (value >= 0)
565 {
566 int digits = (value > 0)
567 ? (int)Math.ceil(Math.log(value) / Math.log(base))
568 : 1;
569 while (minDigits > 0 && digits < minDigits)
570 {
571 toAppendTo.append('0');
572 minDigits--;
573 }
574 }
575 return toAppendTo;
576 }
577
578 private String _pattern;
579
580 private static final int _RED_FIELD = 0;
581 private static final int _GREEN_FIELD = 1;
582 private static final int _BLUE_FIELD = 2;
583 private static final int _ALPHA_FIELD = 3;
584 private static final int _FIELD_COUNT = 4;
585
586 private static final TrinidadLogger _LOG = TrinidadLogger.createTrinidadLogger(RGBColorFormat.class);
587 private static final long serialVersionUID = 1L;
588 }