WebCore/wml/WMLVariables.cpp
changeset 0 4f2f89ce4247
equal deleted inserted replaced
-1:000000000000 0:4f2f89ce4247
       
     1 /**
       
     2  * Copyright (C) 2008 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/)
       
     3  *
       
     4  * This library is free software; you can redistribute it and/or
       
     5  * modify it under the terms of the GNU Library General Public
       
     6  * License as published by the Free Software Foundation; either
       
     7  * version 2 of the License, or (at your option) any later version.
       
     8  *
       
     9  * This library is distributed in the hope that it will be useful,
       
    10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
       
    11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
       
    12  * Library General Public License for more details.
       
    13  *
       
    14  * You should have received a copy of the GNU Library General Public License
       
    15  * along with this library; see the file COPYING.LIB.  If not, write to
       
    16  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
       
    17  * Boston, MA 02110-1301, USA.
       
    18  *
       
    19  */
       
    20 
       
    21 #include "config.h"
       
    22 
       
    23 #if ENABLE(WML)
       
    24 #include "WMLVariables.h"
       
    25 
       
    26 #include "WMLDocument.h"
       
    27 #include <wtf/ASCIICType.h>
       
    28 
       
    29 namespace WebCore {
       
    30 
       
    31 // WML variables specification, excluding the
       
    32 // pre-WML 1.0 deprecated variable syntax
       
    33 //
       
    34 // varname = ("_" | alpha) ("_" | alpha | digit)* 
       
    35 // conv = ":" ("e" ("scape")? | "n" ("oesc")? | "u" ("nesc")?)
       
    36 // var = ("$" varname) | ("$(" varname (conv)? ")")
       
    37 
       
    38 static bool isValidFirstVariableNameCharacter(const UChar& character)
       
    39 {
       
    40     return WTF::isASCIIAlpha(character)
       
    41            || character == '_';
       
    42 }
       
    43 
       
    44 static bool isValidVariableNameCharacter(const UChar& character)
       
    45 {
       
    46     return WTF::isASCIIAlpha(character)
       
    47            || WTF::isASCIIDigit(character)
       
    48            || character == '_';
       
    49 }
       
    50 
       
    51 static bool isValidVariableEscapingModeString(const String& mode, WMLVariableEscapingMode& escapeMode)
       
    52 {
       
    53     if (mode == "e" || mode == "escape")
       
    54         escapeMode = WMLVariableEscapingEscape; 
       
    55     else if (mode == "u" || mode == "unesc")
       
    56         escapeMode = WMLVariableEscapingUnescape;
       
    57     else if (mode == "n" || mode == "noesc")
       
    58         escapeMode = WMLVariableEscapingNone;
       
    59     else
       
    60         return false;
       
    61 
       
    62     return true;
       
    63 }
       
    64 
       
    65 bool isValidVariableName(const String& name)
       
    66 {
       
    67     if (name.isEmpty())
       
    68         return false;
       
    69 
       
    70     const UChar* characters = name.characters();
       
    71     if (!isValidFirstVariableNameCharacter(characters[0]))
       
    72         return false;
       
    73 
       
    74     unsigned length = name.length();
       
    75     for (unsigned i = 1; i < length; ++i) {
       
    76         if (!isValidVariableNameCharacter(characters[i]))
       
    77             return false;
       
    78     }
       
    79 
       
    80     return true;
       
    81 }
       
    82 
       
    83 bool containsVariableReference(const String& text, bool& isValid)
       
    84 {
       
    85     isValid = true;
       
    86     bool foundReference = false;
       
    87     bool finished = false;
       
    88     int currentPosition = 0;
       
    89     const UChar* characters = text.characters();
       
    90 
       
    91     while (!finished) {
       
    92         // Find beginning of variable reference
       
    93         int referenceStartPosition = text.find('$', currentPosition);
       
    94         if (referenceStartPosition == -1) {
       
    95             finished = true;
       
    96             break;
       
    97         }
       
    98 
       
    99         foundReference = true;
       
   100 
       
   101         int nameStartPosition = referenceStartPosition + 1;
       
   102         int nameEndPosition = -1;
       
   103 
       
   104         if (characters[nameStartPosition] == '(') {
       
   105             // If the input string contains an open brace, a close brace must exist as well
       
   106             nameEndPosition = text.find(')', nameStartPosition + 1);
       
   107             if (nameEndPosition == -1) {
       
   108                 finished = true;
       
   109                 isValid = false;
       
   110                 break;
       
   111             }
       
   112 
       
   113             ++nameStartPosition;
       
   114         } else {
       
   115             int length = text.length();
       
   116             for (nameEndPosition = nameStartPosition; nameEndPosition < length; ++nameEndPosition) {
       
   117                 if (!isValidVariableNameCharacter(text[nameEndPosition]))
       
   118                     break;
       
   119             }
       
   120         }
       
   121 
       
   122         if (nameEndPosition < nameStartPosition) {
       
   123             finished = true;
       
   124             isValid = false;
       
   125             break;
       
   126         }
       
   127     
       
   128         // Eventually split of conversion string, and check its syntax afterwards
       
   129         String conversionString;
       
   130         String variableName = text.substring(nameStartPosition, nameEndPosition - nameStartPosition);
       
   131 
       
   132         int conversionStringStart = variableName.find(':');
       
   133         if (conversionStringStart != -1) {
       
   134             conversionString = variableName.substring(conversionStringStart + 1, variableName.length() - (conversionStringStart + 1));
       
   135             variableName = variableName.left(conversionStringStart);
       
   136         }
       
   137 
       
   138         isValid = isValidVariableName(variableName);
       
   139         if (!isValid) {
       
   140             finished = true;
       
   141             break;
       
   142         }
       
   143 
       
   144         if (!conversionString.isEmpty()) {
       
   145             isValid = isValidVariableName(conversionString);
       
   146             if (!isValid) {
       
   147                 finished = true;
       
   148                 break;
       
   149             }
       
   150 
       
   151             WMLVariableEscapingMode escapeMode = WMLVariableEscapingNone;
       
   152             isValid = isValidVariableEscapingModeString(conversionString, escapeMode);
       
   153             if (!isValid) {
       
   154                 finished = true;
       
   155                 break;
       
   156             }
       
   157         }
       
   158 
       
   159         currentPosition = nameEndPosition;
       
   160     }
       
   161 
       
   162     return foundReference;
       
   163 }
       
   164 
       
   165 String substituteVariableReferences(const String& reference, Document* document, WMLVariableEscapingMode escapeMode)
       
   166 {
       
   167     ASSERT(document);
       
   168 
       
   169     if (reference.isEmpty())
       
   170         return reference;
       
   171 
       
   172     WMLPageState* pageState = wmlPageStateForDocument(document);
       
   173     if (!pageState)
       
   174         return reference;
       
   175 
       
   176     bool isValid = true; 
       
   177     String remainingInput = reference;
       
   178     String result;
       
   179 
       
   180     while (!remainingInput.isEmpty()) {
       
   181         ASSERT(isValid);
       
   182 
       
   183         int start = remainingInput.find("$");
       
   184         if (start == -1) {
       
   185             // Consume all remaining characters, as there's nothing more to substitute
       
   186             result += remainingInput;
       
   187             break;
       
   188         }
       
   189 
       
   190         // Consume all characters until the variable reference beginning
       
   191         result += remainingInput.left(start);
       
   192         remainingInput.remove(0, start);
       
   193 
       
   194         // Transform adjacent dollar signs into a single dollar sign as string literal
       
   195         if (remainingInput[1] == '$') {
       
   196             result += "$";
       
   197             remainingInput.remove(0, 2);
       
   198             continue;
       
   199         }
       
   200 
       
   201         String variableName;
       
   202         String conversionMode;
       
   203 
       
   204         if (remainingInput[1] == '(') {
       
   205             int referenceEndPosition = remainingInput.find(")");
       
   206             if (referenceEndPosition == -1) {
       
   207                 isValid = false;
       
   208                 break;
       
   209             }
       
   210 
       
   211             variableName = remainingInput.substring(2, referenceEndPosition - 2);
       
   212             remainingInput.remove(0, referenceEndPosition + 1);
       
   213 
       
   214             // Determine variable conversion mode string
       
   215             int pos = variableName.find(':');
       
   216             if (pos != -1) {
       
   217                 conversionMode = variableName.substring(pos + 1, variableName.length() - (pos + 1));
       
   218                 variableName = variableName.left(pos);
       
   219             }
       
   220         } else {
       
   221             int length = remainingInput.length();
       
   222             int referenceEndPosition = 1;
       
   223 
       
   224             for (; referenceEndPosition < length; ++referenceEndPosition) {
       
   225                 if (!isValidVariableNameCharacter(remainingInput[referenceEndPosition]))
       
   226                     break;
       
   227             }
       
   228 
       
   229             variableName = remainingInput.substring(1, referenceEndPosition - 1);
       
   230             remainingInput.remove(0, referenceEndPosition);
       
   231         }
       
   232 
       
   233         isValid = isValidVariableName(variableName);
       
   234         if (!isValid)
       
   235             break;
       
   236 
       
   237         ASSERT(!variableName.isEmpty());
       
   238 
       
   239         String variableValue = pageState->getVariable(variableName);
       
   240         if (variableValue.isEmpty())
       
   241             continue;
       
   242 
       
   243         if (containsVariableReference(variableValue, isValid)) {
       
   244             if (!isValid)
       
   245                 break;
       
   246 
       
   247             variableValue = substituteVariableReferences(variableValue, document, escapeMode);
       
   248             continue;
       
   249         }
       
   250 
       
   251         if (!conversionMode.isEmpty()) {
       
   252             // Override default escape mode, if desired
       
   253             WMLVariableEscapingMode specifiedEscapeMode = WMLVariableEscapingNone; 
       
   254             if ((isValid = isValidVariableEscapingModeString(conversionMode, specifiedEscapeMode)))
       
   255                 escapeMode = specifiedEscapeMode;
       
   256 
       
   257             if (!isValid)
       
   258                 break;
       
   259         }
       
   260 
       
   261         switch (escapeMode) {
       
   262         case WMLVariableEscapingNone:
       
   263             break;
       
   264         case WMLVariableEscapingEscape:
       
   265             variableValue = encodeWithURLEscapeSequences(variableValue); 
       
   266             break;
       
   267         case WMLVariableEscapingUnescape:
       
   268             variableValue = decodeURLEscapeSequences(variableValue);
       
   269             break;
       
   270         }
       
   271 
       
   272         result += variableValue;
       
   273         ASSERT(isValid);
       
   274     }
       
   275 
       
   276     if (!isValid) {
       
   277         reportWMLError(document, WMLErrorInvalidVariableReference);
       
   278         return reference;
       
   279     }
       
   280 
       
   281     return result;
       
   282 }
       
   283 
       
   284 }
       
   285 
       
   286 #endif