예제 #1
0
  /** Dumps messages to the given output stream, returning the highest message level seen. */
  static MessageLevel dumpMessages(MessageQueue mq, MessageContext mc, Appendable out) {
    MessageLevel maxLevel = MessageLevel.values()[0];
    for (Message m : mq.getMessages()) {
      MessageLevel level = m.getMessageLevel();
      if (maxLevel.compareTo(level) < 0) {
        maxLevel = level;
      }
    }
    MessageLevel ignoreLevel = null;
    if (maxLevel.compareTo(MessageLevel.LINT) < 0) {
      // If there's only checkpoints, be quiet.
      ignoreLevel = MessageLevel.LOG;
    }
    try {
      for (Message m : mq.getMessages()) {
        MessageLevel level = m.getMessageLevel();
        if (ignoreLevel != null && level.compareTo(ignoreLevel) <= 0) {
          continue;
        }
        out.append(level.name() + ": ");
        m.format(mc, out);
        out.append("\n");

        if (maxLevel.compareTo(level) < 0) {
          maxLevel = level;
        }
      }
    } catch (IOException ex) {
      ex.printStackTrace();
    }
    return maxLevel;
  }
예제 #2
0
  /**
   * @param containingHtmlElement the name of the HTML element containing el. If the HTML element is
   *     contained inside a template construct then this name may differ from el's immediate parent.
   */
  private void inspectElement(JobEnvelope source, Element el, ElKey containingHtmlElement) {
    ElKey elKey = ElKey.forElement(el);

    // Recurse early so that ihtml:dynamic elements have been parsed before we
    // process the attributes element list.
    for (Node child : Nodes.childrenOf(el)) {
      inspect(source, child, elKey);
    }

    // For each attribute allowed on this element type, ensure that
    // (1) If it is not specified, and its default value is not allowed, then
    //     it is added with a known safe value.
    // (2) Its value is rewritten as appropriate.
    // We don't have to worry about disallowed attributes since those will
    // not be present in scriptsPerNode.  The TemplateSanitizer should have
    // stripped those out.  The TemplateSanitizer should also have stripped out
    // disallowed elements.
    if (!htmlSchema.isElementAllowed(elKey)) {
      return;
    }

    HTML.Element elInfo = htmlSchema.lookupElement(elKey);
    List<HTML.Attribute> attrs = elInfo.getAttributes();
    if (attrs != null) {
      for (HTML.Attribute a : attrs) {
        AttribKey attrKey = a.getKey();
        if (!htmlSchema.isAttributeAllowed(attrKey)) {
          continue;
        }
        Attr attr = null;
        String aUri = attrKey.ns.uri;
        String aName = attrKey.localName;
        Attr unsafe = el.getAttributeNodeNS(aUri, aName);
        if (unsafe != null && a.getValueCriterion().accept(unsafe.getValue())) {
          attr = unsafe;
        } else if ((a.getDefaultValue() != null
                && !a.getValueCriterion().accept(a.getDefaultValue()))
            || !a.isOptional()) {
          attr = el.getOwnerDocument().createAttributeNS(aUri, aName);
          String safeValue;
          if (a.getType() == HTML.Attribute.Type.URI) {
            safeValue = "" + Nodes.getFilePositionFor(el).source().getUri();
          } else {
            safeValue = a.getSafeValue();
          }
          if (safeValue == null) {
            mq.addMessage(
                IhtmlMessageType.MISSING_ATTRIB, Nodes.getFilePositionFor(el), elKey, attrKey);
            continue;
          }
          attr.setNodeValue(safeValue);
          el.setAttributeNodeNS(attr);
        }
        if (attr != null) {
          inspectHtmlAttribute(source, attr, a);
        }
      }
    }
    scriptsPerNode.put(el, null);
  }
예제 #3
0
 /**
  * Examines the HTML document and writes messages about problematic portions to the message queue
  * passed to the constructor.
  */
 private void inspect() {
   if (!mq.hasMessageAtLevel(MessageLevel.FATAL_ERROR)) {
     for (IhtmlRoot ihtmlRoot : ihtmlRoots) {
       HtmlEmbeddedContentFinder finder =
           new HtmlEmbeddedContentFinder(htmlSchema, ihtmlRoot.baseUri, mq, mc);
       for (EmbeddedContent c : finder.findEmbeddedContent(ihtmlRoot.root)) {
         Node src = c.getSource();
         if (src instanceof Attr) {
           embeddedContent.put((Attr) src, c);
         }
       }
       inspect(ihtmlRoot.source, ihtmlRoot.root, ElKey.forHtmlElement("div"));
     }
   }
 }
예제 #4
0
 private boolean parseInputs(Collection<URI> inputs, PluginCompiler pluginc) {
   boolean parsePassed = true;
   for (URI input : inputs) {
     try {
       ParseTreeNode parseTree = parseInput(input);
       if (null != parseTree) {
         pluginc.addInput(new AncestorChain<ParseTreeNode>(parseTree));
       }
     } catch (ParseException ex) {
       ex.toMessageQueue(mq);
       parsePassed = false;
     } catch (IOException ex) {
       mq.addMessage(MessageType.IO_ERROR, MessagePart.Factory.valueOf(ex.toString()));
       parsePassed = false;
     }
   }
   return parsePassed;
 }
예제 #5
0
  private void produce() throws ParseException {
    if (null != pending) {
      return;
    }
    if (cp.isEmpty()) {
      return;
    }

    char[] buf = cp.getBuffer();
    final int start = cp.getOffset();
    int limit = cp.getLimit();
    int end = start + 1;

    CssTokenType type;
    char ch = buf[start];

    int identEnd;
    if (CssLexer.isSpaceChar(ch)) {
      // [ \t\r\n\f]+        S

      end = parseWhitespace(buf, end, limit);
      type = CssTokenType.SPACE;
    } else if (ch == '/') {
      if (end < limit && buf[end] == '*') {
        // \/\*[^*]*\*+([^/*][^*]*\*+)*\/    /* ignore comments */
        int state = 0; // 0 - start, 1 - in comment, 2 - saw, 3 - done
        do {
          if (end == limit) {
            break;
          }
          ch = buf[end];
          switch (state) {
            case 0:
              state = 1;
              break;
            case 1:
              if (ch == '*') {
                state = 2;
              }
              break;
            case 2:
              if (ch == '/') {
                state = 3;
              } else if (ch != '*') {
                state = 1;
              }
              break;
          }
          ++end;
        } while (state != 3);
        if (state != 3) {
          throw new ParseException(
              new Message(
                  MessageType.UNTERMINATED_COMMENT_TOKEN, cp.filePositionForOffsets(start, end)));
        }
        type = CssTokenType.COMMENT;
      } else if (end < limit && buf[end] == '/') {
        do {
          if (++end == limit) {
            break;
          }
          ch = buf[end];
          // Line comment does not contain the newline character that ends it
          // since we don't want to break \r\n sequences across two tokens,
          // and for consistency with JavaScript conventions which exclude the
          // newline from the line comment token.
          if (ch == '\r' || ch == '\n') {
            break;
          }
        } while (true);
        type = CssTokenType.COMMENT;
        FilePosition commentPos = cp.filePositionForOffsets(start, end);
        mq.addMessage(MessageType.INVALID_CSS_COMMENT, commentPos);
      } else {
        //               *yytext
        type = CssTokenType.PUNCTUATION;
      }
    } else if ('~' == ch || '|' == ch) {
      if (end < limit && '=' == buf[end]) {
        // "~="          INCLUDES
        // "|="          DASHMATCH
        ++end;
      } else {
        //        .      *yytext
      }
      type = CssTokenType.PUNCTUATION;

    } else if (ch == '\'' || ch == '"') {
      end = parseString(cp, start);
      type = CssTokenType.STRING;

    } else if (ch == '@') {

      identEnd = parseIdent(cp, end);
      if (identEnd != -1) {
        // "@import"       IMPORT_SYM
        // "@page"         PAGE_SYM
        // "@media"        MEDIA_SYM
        // "@font-face"    FONT_FACE_SYM
        // "@charset "      CHARSET_SYM
        // "@"{ident}      ATKEYWORD
        type = CssTokenType.SYMBOL;
        end = identEnd;
        // In http://www.w3.org/TR/CSS21/grammar.html, the CHARSET_SYM is
        // allowed to match only "@charset "
        if ((end - start) == 8 && parseMatch(cp, start, "@charset ") > 0) {
          ++end;
        }
      } else {
        //        .        *yytext
        type = CssTokenType.PUNCTUATION;
      }
    } else if (ch == '!') {
      // "!{w}important" IMPORTANT_SYM
      // handled by token joining at a later pass

      //          .      *yytext

      type = CssTokenType.PUNCTUATION;
    } else if (ch == '#') {
      int nameEnd = parseName(cp, end);
      if (nameEnd >= 0) {
        // "#"{name}       HASH
        type = CssTokenType.HASH;
        end = nameEnd;
      } else {
        //          .      *yytext
        type = CssTokenType.PUNCTUATION;
      }

    } else if (ch == '<' || ch == '-') {
      // "<!--"          CDO
      // "-->"           CDC

      int tailEnd = parseMatch(cp, end, ch == '<' ? "!--" : "->");
      if (tailEnd >= 0) {
        end = tailEnd;
      }
      type = CssTokenType.PUNCTUATION;

    } else if ((ch >= '0' && ch <= '9') || '.' == ch) {
      // {num}em         EMS
      // {num}ex         EXS
      // {num}px         LENGTH
      // {num}cm         LENGTH
      // {num}mm         LENGTH
      // {num}in         LENGTH
      // {num}pt         LENGTH
      // {num}pc         LENGTH
      // {num}deg        ANGLE
      // {num}rad        ANGLE
      // {num}grad       ANGLE
      // {num}ms         TIME
      // {num}s          TIME
      // {num}Hz         FREQ
      // {num}kHz        FREQ
      // {num}{ident}    DIMEN
      // {num}%          PERCENTAGE
      // {num}           NUMBER
      boolean isNum;
      if ('.' == ch) {
        int numEnd = parseInt(cp, end);
        isNum = numEnd >= 0;
        if (isNum) {
          end = numEnd;
        }
      } else {
        isNum = true;
        end = parseNum(cp, start);
      }

      if (isNum) {
        identEnd = parseIdent(cp, end);
        if (identEnd >= 0) {
          end = identEnd;
        } else if (end < limit && '%' == buf[end]) {
          ++end;
        }
        type = CssTokenType.QUANTITY;
      } else {
        // lone .
        //          .      *yytext
        type = CssTokenType.PUNCTUATION;
      }

    } else if ((identEnd = parseIdent(cp, start)) >= 0) {
      end = identEnd;
      if (end - start == 1 && 'U' == ch && end < limit && '+' == buf[end]) {
        // U\+{range}      UNICODERANGE
        // U\+{h}{1,6}-{h}{1,6}    UNICODERANGE
        // range         \?{1,6}|{h}(\?{0,5}|{h}(\?{0,4}|{h}\
        //               (\?{0,3}|{h}(\?{0,2}|{h}(\??|{h})))))

        type = CssTokenType.UNICODE_RANGE;
        ++end;
        end = parseRange(cp, end);
      } else if (end < limit && '(' == buf[end]) {
        ++end;
        if (end - start == 4 && parseMatch(cp, start, "url(") >= 0) {
          // "url("{w}{string}{w}")" URI
          // "url("{w}{url}{w}")"    URI
          end = parseWhitespace(buf, end, limit);
          int stringEnd = parseString(cp, end);
          int uriEnd = stringEnd < 0 ? parseUri(cp, end) : -1;
          if (stringEnd < 0 && uriEnd < 0) {
            throw new ParseException(
                new Message(
                    MessageType.EXPECTED_TOKEN,
                    cp.filePositionForOffsets(end, end),
                    MessagePart.Factory.valueOf("{url}"),
                    toMessagePart(cp, end)));
          }
          end = stringEnd >= 0 ? stringEnd : uriEnd;
          end = parseWhitespace(buf, end, limit);
          if (end == limit || ')' != buf[end]) {
            throw new ParseException(
                new Message(
                    MessageType.EXPECTED_TOKEN,
                    cp.filePositionForOffsets(end, end),
                    MessagePart.Factory.valueOf(")"),
                    toMessagePart(cp, end)));
          }
          ++end;
          type = CssTokenType.URI;
        } else {
          // {ident}"("      FUNCTION
          type = CssTokenType.FUNCTION;
        }
      } else {
        // {ident}         IDENT
        type = CssTokenType.IDENT;
      }

    } else if (ch == '$' && allowSubstitutions) {
      // ${<javascript tokens>}

      if (end < limit && buf[end] != '{') {
        type = CssTokenType.PUNCTUATION;
      } else {
        // 0 - non string
        // 1 - quoted string
        // 2 - saw \ in string
        // 3 - saw close paren
        int state = 0;
        // number of parenthetical blocks entered and not exited
        int nOpen = 0;
        char delim = 0;
        do {
          if (end == limit) {
            break;
          }
          ch = buf[end];
          switch (state) {
            case 0:
              if (ch == '"' || ch == '\'') {
                delim = ch;
                state = 1;
              } else if (ch == '{') {
                ++nOpen;
              } else if (ch == '}') {
                if (--nOpen == 0) {
                  state = 3;
                }
              }
              break;
            case 1:
              if (ch == delim) {
                state = 0;
              } else if (ch == '\\') {
                state = 2;
              }
              break;
            case 2:
              state = 1;
              break;
          }
          ++end;
        } while (state != 3);
        if (state != 3) {
          throw new ParseException(
              new Message(
                  MessageType.UNTERMINATED_STRING_TOKEN, cp.filePositionForOffsets(start, end)));
        }

        identEnd = parseIdent(cp, end);
        if (identEnd >= 0) {
          end = identEnd;
        } else if (end != limit && '%' == buf[end]) {
          ++end;
        }

        type = CssTokenType.SUBSTITUTION;
      }
    } else {
      //          .      *yytext
      type = CssTokenType.PUNCTUATION;
    }
    assert end > start;
    pending = Token.instance(cp.toString(start, end), type, cp.filePositionForOffsets(start, end));
    cp.consumeTo(end);
  }