Start line:  
End line:  

Snippet Preview

Snippet HTML Code

Stack Overflow Questions
  /*
   * Copyright (c) 2015 Mozilla Foundation
   *
   * Permission is hereby granted, free of charge, to any person obtaining a
   * copy of this software and associated documentation files (the "Software"),
   * to deal in the Software without restriction, including without limitation
   * the rights to use, copy, modify, merge, publish, distribute, sublicense,
   * and/or sell copies of the Software, and to permit persons to whom the
   * Software is furnished to do so, subject to the following conditions:
  *
  * The above copyright notice and this permission notice shall be included in
  * all copies or substantial portions of the Software.
  *
  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  * DEALINGS IN THE SOFTWARE.
  */
 
 package nu.validator.datatype;
 
 import java.util.Set;
 
 
 public class SourceSizeList extends AbstractDatatype {
 
     private static enum State {
         IN_SIZE, AFTER_SLASH, IN_COMMENT, IN_COMMENT_AFTER_ASTERISK
     }
 
     private static final int CLIP_LIMIT = 25;
 
     private static final Set<StringLENGTH_UNITS = new LinkedHashSet<String>();
 
     private static final StringBuilder VALID_UNITS = new StringBuilder();
 
     private static CssParser cssParser = new CssParser();
 
     static {
         /* font-relative lengths */
         .add("em");
         .add("ex");
         .add("ch");
         .add("rem");
         /* viewport-percentage lengths */
         .add("vw");
         .add("vh");
         .add("vmin");
         .add("vmax");
         /* absolute lengths */
         .add("cm");
         .add("mm");
         .add("q");
         .add("in");
         .add("pc");
         .add("pt");
         .add("px");
 
         for (CharSequence units : ) {
             .append(" \u201c" + units + "\u201d,");
         }
         .setLength(.length() - 1);
     }
 
     private static final CssNumberToken CSS_NUMBER_TOKEN = .;
 
     private static final MediaCondition MEDIA_CONDITION = .;
 
     public static final SourceSizeList THE_INSTANCE = new SourceSizeList();
 
     protected SourceSizeList() {
         super();
     }
 
     @Override public void checkValid(CharSequence literal)
             throws DatatypeException {
         if (literal.length() == 0) {
             err("Must not be empty.");
         }
         int offset = 0;
         boolean isFirst = true;
         String currentChunk;
         StringBuilder unparsedSize = new StringBuilder();
         StringBuilder extract = new StringBuilder();
         for (int i = 0; i < literal.length(); i++) {
             char c = literal.charAt(i);
             extract.append(c);
             if (',' == c) {
                 currentChunk = literal.subSequence(offseti).toString();
                 checkForInvalidComments(currentChunkextract);
                 unparsedSize.append(currentChunk);
                 unparsedSize = removeComments(unparsedSizeextract);
                checkSize(unparsedSizeliteralextractisFirstfalse);
                isFirst = false;
                unparsedSize.setLength(0);
                offset = i + 1;
            }
        }
        currentChunk = literal.subSequence(offsetliteral.length()).toString();
        checkForInvalidComments(currentChunkextract);
        unparsedSize.append(currentChunk);
        unparsedSize = removeComments(unparsedSizeextract);
        checkSize(unparsedSizeliteralextractisFirsttrue);
    }
    private void checkSize(StringBuilder unparsedSizeCharSequence literal,
            StringBuilder extractboolean isFirstboolean isLast)
            throws DatatypeException {
        String size;
        trimWhitespace(unparsedSize);
        if (unparsedSize.length() == 0) {
            errEmpty(isFirstisLastextract);
            return;
        }
        try {
            .tokenize(unparsedSize.toString());
            if ('(' == unparsedSize.codePointAt(0)) {
                .parseARule("@media " + unparsedSize.toString()
                        + " {}");
            } else {
                .parseARule(".foo { width: " + unparsedSize.toString()
                        + " }");
            }
        } catch (ParseException e) {
            errCssParseError(e.getMessage(), unparsedSizeextract);
        }
        if (')' == unparsedSize.charAt(unparsedSize.length() - 1)) {
            checkCalc(unparsedSizeextractisLast);
            return;
        }
        int sizeValueStart = lastSpaceIndex(unparsedSize);
        size = unparsedSize.substring(lastSpaceIndex(unparsedSize),
                unparsedSize.length());
        try {
            if (Float.parseFloat(size) == 0) {
                return;
            }
        } catch (NumberFormatException e) {
        }
        String units = getUnits(size);
        String num = size.substring(0, size.length() - units.length());
        boolean sizeIsLessThanZero = false;
        try {
            .checkValid(num);
            if (Float.parseFloat(num) < 0) {
                sizeIsLessThanZero = true;
            }
        } catch (DatatypeException e) {
            errFromOtherDatatype(e.getMessage(), extract);
        } catch (NumberFormatException e) {
            errNotNumber(numextract);
        }
        if (sizeIsLessThanZero) {
            errNotPositive(sizeextract);
        }
        if (!.contains(units)) {
            errNotUnits(unitsextract);
        }
        unparsedSize.setLength(sizeValueStart);
        trimTrailingWhitespace(unparsedSize);
        if (unparsedSize.length() == 0) {
            if (!isLast) {
                errNoMediaCondition(unparsedSizeextract);
            }
            return;
        }
        try {
            .checkValid(unparsedSize);
        } catch (DatatypeException e) {
            errFromOtherDatatype(e.getMessage(), extract);
        }
    }
    private void checkCalc(StringBuilder sbCharSequence extract,
            boolean isLastthrows DatatypeException {
        int firstParenPosition = sb.length() - 1;
        int unMatchedParenCount = 1;
        while (unMatchedParenCount > 0) {
            if (firstParenPosition == 0) {
                errMismatchedParens(sbextract);
            }
            char c = sb.charAt(--firstParenPosition);
            if ('(' == c) {
                unMatchedParenCount--;
            } else if (')' == c) {
                unMatchedParenCount++;
            }
        }
        int CALC_START = firstParenPosition - "calc".length(); // readability
        boolean hasCalc = CALC_START > -1
                && "calc".equals(toAsciiLowerCase(sb.subSequence(CALC_START,
                        firstParenPosition)));
        boolean startsWithCalc = hasCalc && CALC_START == 0;
        boolean hasWhitespaceThenCalc = hasCalc && CALC_START > 0
                && isWhitespace(sb.charAt(CALC_START - 1));
        if (!isLast && startsWithCalc) {
            errNoMediaCondition(sbextract);
        }
        if (startsWithCalc || hasWhitespaceThenCalc) {
            sb.setLength(CALC_START);
            trimTrailingWhitespace(sb);
        } else {
            errNotNumber(sbextract);
        }
    }
    private void checkForInvalidComments(String currentChunk,
            StringBuilder extractthrows DatatypeException {
        if (currentChunk.contains("+/")) {
            errNotNumber("+/"extract);
        }
        if (currentChunk.contains("-/")) {
            errNotNumber("-/"extract);
        }
        for (String units : ) {
            if (currentChunk.contains("/" + units)) {
                errNotUnits("/" + unitsextract);
            }
        }
    }
    private StringBuilder removeComments(StringBuilder sbCharSequence extract)
            throws DatatypeException {
        if (sb.indexOf("/*") == -1) {
            return sb;
        }
        StringBuilder sb2 = new StringBuilder();
        State state = .;
        for (int i = 0; i < sb.length(); i++) {
            char c = sb.charAt(i);
            switch (state) {
                case :
                    if ('/' == sb.charAt(i)) {
                        sb2.append('/');
                        state = .;
                        continue;
                    } else {
                        sb2.append(c);
                        continue;
                    }
                case :
                    if ('*' == sb.charAt(i)) {
                        sb2.setLength(sb2.length() - 1);
                        state = .;
                        continue;
                    } else {
                        sb2.append(c);
                        continue;
                    }
                case :
                    if ('*' == sb.charAt(i)) {
                        state = .;
                        continue;
                    } else {
                        continue;
                    }
                case :
                    if ('/' == sb.charAt(i)) {
                        state = .;
                        continue;
                    } else {
                        continue;
                    }
            }
        }
        if (state == .
                || state == .) {
            trimWhitespace(sb);
            errUnclosedComment(sbextract);
        }
        return sb2;
    }
    private int lastSpaceIndex(StringBuilder sb) {
        for (int i = sb.length(); i > 0; i--) {
            char c = sb.charAt(i - 1);
            if (isWhitespace(c)) {
                return i;
            }
        }
        return 0;
    }
    private void trimWhitespace(StringBuilder sb) {
        trimTrailingWhitespace(sb);
        trimLeadingWhitespace(sb);
    }
    private void trimTrailingWhitespace(StringBuilder sb) {
        for (int i = sb.length(); i > 0; i--) {
            if (isWhitespace(sb.charAt(i - 1))) {
                sb.setLength(i - 1);
            } else {
                return;
            }
        }
    }
    private void trimLeadingWhitespace(StringBuilder sb) {
        for (int i = 0; i < sb.length(); i++) {
            if (!isWhitespace(sb.charAt(i))) {
                sb.delete(0, i);
                return;
            }
        }
    }
    private String getUnits(String val) {
        for (int i = val.length(); i > 0; i--) {
            char c = val.charAt(i - 1);
            if ((c >= '0' && c <= '9')) {
                return val.substring(ival.length());
            }
        }
        return "";
    }
    private void err(String messagethrows DatatypeException {
        throw newDatatypeException(message);
    }
    private void errCssParseError(CharSequence msgCharSequence sourceSize,
            CharSequence extractthrows DatatypeException {
        err(msg + " while parsing " + code(sourceSize) + " at " + clip(extract));
    }
    private void errFromOtherDatatype(CharSequence msgCharSequence extract)
            throws DatatypeException {
        err(msg.subSequence(0, msg.length() - 1) + " at " + clip(extract) + ".");
    }
    private void errEmpty(boolean isFirstboolean isLastCharSequence extract)
            throws DatatypeException {
        if (isFirst) {
            if (isLast) {
                err("Must contain one or more source sizes.");
            } else {
                err("Starts with empty source size.");
            }
        } else {
            err("Empty source size at " + clip(extract) + ".");
        }
    }
    private void errNoMediaCondition(CharSequence sourceSize,
            CharSequence extractthrows DatatypeException {
        err("Expected media condition before " + code(sourceSize) + " at "
                + clip(extract) + ".");
    }
    private void errNotPositive(CharSequence sizeCharSequence extract)
            throws DatatypeException {
        err("Expected positive size value but found " + code(size) + " at "
                + clip(extract) + ".");
    }
    private void errNotNumber(CharSequence numCharSequence extract)
            throws DatatypeException {
        err("Expected number but found " + code(num) + " at " + clip(extract)
                + ".");
    }
    private void errNotUnits(CharSequence unitsStringBuilder extract)
            throws DatatypeException {
        String msg = "Expected units (one of" +  + ") but found ";
        if ("".equals(units)) {
            msg += "no units";
        } else {
            msg += code(units);
        }
        msg += " at " + clip(extract) + ".";
        err(msg);
    }
    private void errMismatchedParens(CharSequence csCharSequence extract)
            throws DatatypeException {
        err("Mismatched parentheses in " + clip(extract) + ".");
    }
    private void errUnclosedComment(CharSequence csCharSequence extract)
            throws DatatypeException {
        err("Unclosed comment in " + code(cs) + " at " + clip(extract) + ".");
    }
    private CharSequence clip(CharSequence cs) {
        int len = cs.length();
        if (len > ) {
            cs = "\u2026" + cs.subSequence(len - len);
        }
        return code(cs);
    }
    private CharSequence code(CharSequence cs) {
        return "\u201c" + cs + "\u201d";
    }
    @Override public String getName() {
        return "source size list";
    }
New to GrepCode? Check out our FAQ X