1/*
2 * Copyright (C) 2010 Google Inc.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.google.clearsilver.jsilver.data;
18
19
20/**
21 * Static methods for converting stuff in a ClearSilver compatible way.
22 */
23public class TypeConverter {
24  private TypeConverter() {}
25
26  private static final String ZERO = "0";
27  private static final String ONE = "1";
28
29  /**
30   * Determines if the given data node exists in a ClearSilver compatible way.
31   */
32  public static boolean exists(Data data) {
33    return data != null && data.getValue() != null;
34  }
35
36  /**
37   * Helper method to safely convert an arbitrary data instance (including null) into a valid
38   * (non-null) string representation.
39   */
40  public static String asString(Data data) {
41    // Non-existent variables become the empty string
42    // (the data instance will return null to us)
43    String value = data != null ? data.getValue() : null;
44    return value != null ? value : "";
45  }
46
47  /**
48   * Parses a non-null string in a ClearSilver compatible way.
49   *
50   * The is the underlying parsing function which can fail for badly formatted strings. It is really
51   * important that anyone doing parsing of strings calls this function (rather than doing it
52   * themselves).
53   *
54   * This is an area where JSilver and ClearSilver have some notable differences. ClearSilver relies
55   * on the template compiler to parse strings in the template and a different parser at runtime for
56   * HDF values. JSilver uses the same code for both cases.
57   *
58   * In ClearSilver HDF: Numbers are parsed sequentially and partial results are returned when an
59   * invalid character is reached. This means that {@code "123abc"} parses to {@code 123}.
60   *
61   * Additionally, ClearSilver doesn't do hex in HDF values, so {@code "a.b=0x123"} will just
62   * resolve to {@code 0}.
63   *
64   * In ClearSilver templates: Hex is supported, including negative values.
65   *
66   * In JSilver: A string must be a complete, valid numeric value for parsing. This means {@code
67   * "123abc"} is invalid and will default to {@code 0}.
68   *
69   * In JSilver: Positive hex values are supported for both HDF and templates but negative values
70   * aren't. This means a template containing something like "<?cs if:foo == -0xff ?>" will parse
71   * correctly but fail to render.
72   *
73   * @throws NumberFormatException is the string is badly formatted
74   */
75  public static int parseNumber(String value) throws NumberFormatException {
76    // NOTE: This is likely to be one of the areas we will want to optimize
77    // for speed eventually.
78    if (value.startsWith("0x") || value.startsWith("0X")) {
79      return Integer.parseInt(value.substring(2), 16);
80    } else {
81      return Integer.parseInt(value);
82    }
83  }
84
85  /**
86   * Parses and returns the given string as an integer in a ClearSilver compatible way.
87   */
88  public static int asNumber(String value) {
89    if (value == null || value.isEmpty()) {
90      return 0;
91    }
92    // fast detection for common constants to avoid parsing common values
93    // TODO: Maybe push this down into parseNumber ??
94    if (value.equals(ONE)) {
95      return 1;
96    }
97    if (value.equals(ZERO)) {
98      return 0;
99    }
100    try {
101      return parseNumber(value);
102    } catch (NumberFormatException e) {
103      return 0;
104    }
105  }
106
107  /**
108   * Helper method to safely convert an arbitrary data instance (including null) into a valid
109   * integer representation.
110   */
111  public static int asNumber(Data data) {
112    // Non-existent variables become zero
113    return data != null ? data.getIntValue() : 0;
114  }
115
116  /**
117   * Parses and returns the given string as a boolean in a ClearSilver compatible way.
118   */
119  public static boolean asBoolean(String value) {
120    if (value == null || value.isEmpty()) {
121      return false;
122    }
123    // fast detection for common constants to avoid parsing common values
124    if (value.equals(ONE)) {
125      return true;
126    }
127    if (value.equals(ZERO)) {
128      return false;
129    }
130
131    // fast detection of any string not starting with '0'
132    if (value.charAt(0) != '0') {
133      return true;
134    }
135
136    try {
137      return parseNumber(value) != 0;
138    } catch (NumberFormatException e) {
139      // Unlike number parsing, we return a positive value when the
140      // string is badly formatted (it's what clearsilver does).
141      return true;
142    }
143  }
144
145  /**
146   * Helper method to safely convert an arbitrary data instance (including null) into a valid
147   * boolean representation.
148   */
149  public static boolean asBoolean(Data data) {
150    // Non-existent variables become false
151    return data != null ? data.getBooleanValue() : false;
152  }
153}
154