📄 cssparser.java
字号:
if (tokenBufferLength > 0) { unitBuffer.append(tokenBuffer, 0, tokenBufferLength); } break; case BRACKET_OPEN: case BRACE_OPEN: case PAREN_OPEN: if (unitBuffer.length() > 0 && readWS) { unitBuffer.append(' '); } unitBuffer.append(charMapping[nextToken]); startBlock(nextToken); break; case BRACKET_CLOSE: case BRACE_CLOSE: case PAREN_CLOSE: if (unitBuffer.length() > 0 && readWS) { unitBuffer.append(' '); } unitBuffer.append(charMapping[nextToken]); endBlock(nextToken); if (!inBlock()) { done = true; } break; case END: // Prematurely hit end. throw new RuntimeException("Unclosed block"); } } } /** * Fetches the next token. */ private int nextToken(char idChar) throws IOException { readWS = false; int nextChar = readWS(); switch (nextChar) { case '\'': readTill('\''); if (tokenBufferLength > 0) { tokenBufferLength--; } return IDENTIFIER; case '"': readTill('"'); if (tokenBufferLength > 0) { tokenBufferLength--; } return IDENTIFIER; case '[': return BRACKET_OPEN; case ']': return BRACKET_CLOSE; case '{': return BRACE_OPEN; case '}': return BRACE_CLOSE; case '(': return PAREN_OPEN; case ')': return PAREN_CLOSE; case -1: return END; default: pushChar(nextChar); getIdentifier(idChar); return IDENTIFIER; } } /** * Gets an identifier, returning true if the length of the string is greater than 0, * stopping when <code>stopChar</code>, whitespace, or one of {}()[] is * hit. */ // NOTE: this could be combined with readTill, as they contain somewhat // similiar functionality. private boolean getIdentifier(char stopChar) throws IOException { boolean lastWasEscape = false; boolean done = false; int escapeCount = 0; int escapeChar = 0; int nextChar; int intStopChar = (int)stopChar; // 1 for '\', 2 for valid escape char [0-9a-fA-F], 3 for // stop character (white space, ()[]{}) 0 otherwise short type; int escapeOffset = 0; tokenBufferLength = 0; while (!done) { nextChar = readChar(); switch (nextChar) { case '\\': type = 1; break; case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': type = 2; escapeOffset = nextChar - '0'; break; case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': type = 2; escapeOffset = nextChar - 'a' + 10; break; case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': type = 2; escapeOffset = nextChar - 'A' + 10; break; case '\'': case '"': case '[': case ']': case '{': case '}': case '(': case ')': case ' ': case '\n': case '\t': case '\r': type = 3; break; case '/': type = 4; break; case -1: // Reached the end done = true; type = 0; break; default: type = 0; break; } if (lastWasEscape) { if (type == 2) { // Continue with escape. escapeChar = escapeChar * 16 + escapeOffset; if (++escapeCount == 4) { lastWasEscape = false; append((char)escapeChar); } } else { // no longer escaped lastWasEscape = false; if (escapeCount > 0) { append((char)escapeChar); // Make this simpler, reprocess the character. pushChar(nextChar); } else if (!done) { append((char)nextChar); } } } else if (!done) { if (type == 1) { lastWasEscape = true; escapeChar = escapeCount = 0; } else if (type == 3) { done = true; pushChar(nextChar); } else if (type == 4) { // Potential comment nextChar = readChar(); if (nextChar == '*') { done = true; readComment(); readWS = true; } else { append('/'); if (nextChar == -1) { done = true; } else { pushChar(nextChar); } } } else { append((char)nextChar); if (nextChar == intStopChar) { done = true; } } } } return (tokenBufferLength > 0); } /** * Reads till a <code>stopChar</code> is encountered, escaping characters * as necessary. */ private void readTill(char stopChar) throws IOException { boolean lastWasEscape = false; int escapeCount = 0; int escapeChar = 0; int nextChar; boolean done = false; int intStopChar = (int)stopChar; // 1 for '\', 2 for valid escape char [0-9a-fA-F], 0 otherwise short type; int escapeOffset = 0; tokenBufferLength = 0; while (!done) { nextChar = readChar(); switch (nextChar) { case '\\': type = 1; break; case '0': case '1': case '2': case '3': case '4':case '5': case '6': case '7': case '8': case '9': type = 2; escapeOffset = nextChar - '0'; break; case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': type = 2; escapeOffset = nextChar - 'a' + 10; break; case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': type = 2; escapeOffset = nextChar - 'A' + 10; break; case -1: // Prematurely reached the end! throw new RuntimeException("Unclosed " + stopChar); default: type = 0; break; } if (lastWasEscape) { if (type == 2) { // Continue with escape. escapeChar = escapeChar * 16 + escapeOffset; if (++escapeCount == 4) { lastWasEscape = false; append((char)escapeChar); } } else { // no longer escaped if (escapeCount > 0) { append((char)escapeChar); if (type == 1) { lastWasEscape = true; escapeChar = escapeCount = 0; } else { if (nextChar == intStopChar) { done = true; } append((char)nextChar); lastWasEscape = false; } } else { append((char)nextChar); lastWasEscape = false; } } } else if (type == 1) { lastWasEscape = true; escapeChar = escapeCount = 0; } else { if (nextChar == intStopChar) { done = true; } append((char)nextChar); } } } private void append(char character) { if (tokenBufferLength == tokenBuffer.length) { char[] newBuffer = new char[tokenBuffer.length * 2]; System.arraycopy(tokenBuffer, 0, newBuffer, 0, tokenBuffer.length); tokenBuffer = newBuffer; } tokenBuffer[tokenBufferLength++] = character; } /** * Parses a comment block. */ private void readComment() throws IOException { int nextChar; for(;;) { nextChar = readChar(); switch (nextChar) { case -1: throw new RuntimeException("Unclosed comment"); case '*': nextChar = readChar(); if (nextChar == '/') { return; } else if (nextChar == -1) { throw new RuntimeException("Unclosed comment"); } else { pushChar(nextChar); } break; default: break; } } } /** * Called when a block start is encountered ({[. */ private void startBlock(int startToken) { if (stackCount == unitStack.length) { int[] newUS = new int[stackCount * 2]; System.arraycopy(unitStack, 0, newUS, 0, stackCount); unitStack = newUS; } unitStack[stackCount++] = startToken; } /** * Called when an end block is encountered )]} */ private void endBlock(int endToken) { int startToken; switch (endToken) { case BRACKET_CLOSE: startToken = BRACKET_OPEN; break; case BRACE_CLOSE: startToken = BRACE_OPEN; break; case PAREN_CLOSE: startToken = PAREN_OPEN; break; default: // Will never happen. startToken = -1; break; } if (stackCount > 0 && unitStack[stackCount - 1] == startToken) { stackCount--; } else { // Invalid state, should do something. throw new RuntimeException("Unmatched block"); } } /** * @return true if currently in a block. */ private boolean inBlock() { return (stackCount > 0); } /** * Skips any white space, returning the character after the white space. */ private int readWS() throws IOException { int nextChar; while ((nextChar = readChar()) != -1 && Character.isWhitespace((char)nextChar)) { readWS = true; } return nextChar; } /** * Reads a character from the stream. */ private int readChar() throws IOException { if (didPushChar) { didPushChar = false; return pushedChar; } return reader.read(); // Uncomment the following to do case insensitive parsing. /* if (retValue != -1) { return (int)Character.toLowerCase((char)retValue); } return retValue; */ } /** * Supports one character look ahead, this will throw if called twice * in a row. */ private void pushChar(int tempChar) { if (didPushChar) { // Should never happen. throw new RuntimeException("Can not handle look ahead of more than one character"); } didPushChar = true; pushedChar = tempChar; }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -