/** Parses an @ rule, stopping at a matching brace pair, or ;. */ private void parseAtRule() throws IOException { // PENDING: make this more effecient. boolean done = false; boolean isImport = (tokenBufferLength == 7 && tokenBuffer[0] == '@' && tokenBuffer[1] == 'i' && tokenBuffer[2] == 'm' && tokenBuffer[3] == 'p' && tokenBuffer[4] == 'o' && tokenBuffer[5] == 'r' && tokenBuffer[6] == 't'); unitBuffer.setLength(0); while (!done) { int nextToken = nextToken(';'); switch (nextToken) { case IDENTIFIER: if (tokenBufferLength > 0 && tokenBuffer[tokenBufferLength - 1] == ';') { --tokenBufferLength; done = true; } if (tokenBufferLength > 0) { if (unitBuffer.length() > 0 && readWS) { unitBuffer.append(' '); } unitBuffer.append(tokenBuffer, 0, tokenBufferLength); } break; case BRACE_OPEN: if (unitBuffer.length() > 0 && readWS) { unitBuffer.append(' '); } unitBuffer.append(charMapping[nextToken]); parseTillClosed(nextToken); done = true; // Skip a tailing ';', not really to spec. { int nextChar = readWS(); if (nextChar != -1 && nextChar != ';') { pushChar(nextChar); } } break; case BRACKET_OPEN: case PAREN_OPEN: unitBuffer.append(charMapping[nextToken]); parseTillClosed(nextToken); break; case BRACKET_CLOSE: case BRACE_CLOSE: case PAREN_CLOSE: throw new RuntimeException("Unexpected close in @ rule"); case END: done = true; break; } } if (isImport && !encounteredRuleSet) { callback.handleImport(unitBuffer.toString()); } }