All Downloads are FREE. Search and download functionalities are using the official Maven repository.

jetbrick.template.parser.ast.AstText Maven / Gradle / Ivy

There is a newer version: 2.1.10
Show newest version
/**
 * Copyright 2013-2016 Guoqiang Chen, Shanghai, China. All rights reserved.
 *
 *   Author: Guoqiang Chen
 *    Email: [email protected]
 *   WebURL: https://github.com/subchen
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package jetbrick.template.parser.ast;

import java.io.IOException;
import java.nio.charset.Charset;
import jetbrick.bean.FieldInfo;
import jetbrick.bean.KlassInfo;
import jetbrick.template.runtime.*;
import jetbrick.util.JdkUtils;

public final class AstText extends AstStatement {
    private String text;
    private volatile TextEncoder encoder;
    private int line;

    public AstText(String text, int line) {
        this.text = text;
        this.line = line;
    }

    public String getText() {
        return text;
    }

    public int getLine() {
        return line;
    }

    // --------------------------------------------------------------------
    protected boolean isEmpty() {
        return text == null || text.length() == 0;
    }

    protected void trimDirectiveWhitespaces(boolean trimLeft, boolean trimRight, boolean keepLeftNewLine) {
        if (text == null || text.length() == 0) {
            return;
        }

        int len = text.length();

        int lpos = 0;
        boolean trimedNewLine = false; // 是否删除了一个 new line
        if (trimLeft) {
            for (int i = 0; i < len; i++) {
                char c = text.charAt(i);
                if (c == ' ' || c == '\t') {
                    continue;
                } else if (c == '\r') {
                    if (keepLeftNewLine) {
                        lpos = i;
                        break;
                    } else {
                        trimedNewLine = true;
                        int n = i + 1;
                        if (n < len && text.charAt(n) == '\n') {
                            lpos = n + 1; // window: \r\n
                        } else {
                            lpos = n; // mac: \r
                        }
                        break;
                    }
                } else if (c == '\n') {
                    if (keepLeftNewLine) {
                        lpos = i;
                    } else {
                        trimedNewLine = true;
                        lpos = i + 1; // linux: \n
                    }
                    break;
                } else {
                    break;
                }
            }
        }

        int rpos = len;
        if (trimRight) {
            for (int i = len - 1; i >= 0; i--) {
                char c = text.charAt(i);
                if (c == ' ' || c == '\t') {
                    continue;
                } else if (c == '\n' || c == '\r') {
                    rpos = i + 1;
                    break;
                } else {
                    break;
                }
            }
        }

        if (lpos < rpos) {
            text = text.substring(lpos, rpos);
        } else {
            text = null;
        }

        if (trimedNewLine) {
            line++;
        }
    }

    protected void trimDirectiveComments(boolean trimLeft, boolean trimRight, String prefix, String suffix) {
        if (text == null || text.length() == 0) {
            return;
        }

        int text_len = text.length();
        int prefix_len = prefix.length();
        int suffix_len = suffix.length();

        int lpos = 0;
        if (trimLeft) {
            for (int i = 0; i < text_len; i++) {
                char c = text.charAt(i);
                if (c == ' ' || c == '\t' || c == '\r' || c == '\n') {
                    continue;
                } else {
                    boolean matched = true;
                    int j = 0;
                    while (i < text_len && j < suffix_len) {
                        if (text.charAt(i) != suffix.charAt(j)) {
                            matched = false;
                            break;
                        }
                        i++;
                        j++;
                    }
                    if (matched) {
                        lpos = i;
                    }
                    break;
                }
            }
        }

        int rpos = text_len;
        if (trimRight) {
            for (int i = text_len - 1; i >= 0; i--) {
                char c = text.charAt(i);
                if (c == ' ' || c == '\t' || c == '\r' || c == '\n') {
                    continue;
                } else {
                    boolean matched = true;
                    int j = prefix_len - 1;
                    while (i >= 0 && j >= 0) {
                        if (text.charAt(i) != prefix.charAt(j)) {
                            matched = false;
                            break;
                        }
                        i--;
                        j--;
                    }
                    if (matched) {
                        rpos = i + 1;
                    }
                    break;
                }
            }
        }

        if (lpos < rpos) {
            text = text.substring(lpos, rpos);
        } else {
            text = null;
        }
    }

    protected void trimLastNewLine() {
        if (text == null || text.length() == 0) {
            return;
        }

        int length = text.length();
        if (text.charAt(length - 1) == '\n') {
            length--;
            if (length > 0 && text.charAt(length - 1) == '\r') {
                length--;
            }
        }
        text = text.substring(0, length);
    }

    // --------------------------------------------------------------------

    @Override
    public void execute(InterpretContext ctx) throws InterpretException {
        JetWriter os = ctx.getWriter();

        if (encoder == null) {
            synchronized (this) {
                // double check
                if (encoder == null) {
                    if (os.isStreaming()) {
                        encoder = new ByteArrayEncoder(text, os.getCharset());
                    } else {
                        if (JdkUtils.IS_AT_LEAST_JAVA_7) {
                            encoder = new Jdk7CharArrayEncoder(text);
                        } else {
                            encoder = new Jdk6CharArrayEncoder(text);
                        }
                    }
                    text = null; // free
                }
            }
        }

        try {
            encoder.writeTo(os);
        } catch (IOException e) {
            throw new IllegalStateException(e);
        }
    }

    @Override
    public String toString() {
        return text;
    }

    // --------------------------------------------------------------------

    static interface TextEncoder {
        public void writeTo(JetWriter os) throws IOException;
    }

    static final class ByteArrayEncoder implements TextEncoder {
        private final byte[] bytes;

        public ByteArrayEncoder(String text, Charset charset) {
            this.bytes = text.getBytes(charset);
        }

        @Override
        public void writeTo(JetWriter os) throws IOException {
            os.print(bytes, 0, bytes.length);
        }
    }

    // 从 JDK7 开始,String.class 不在提供 offset 和 count
    static final KlassInfo KLASS_STRING = KlassInfo.create(String.class);
    static final FieldInfo FIELD_STRING_VALUE = KLASS_STRING.getDeclaredField("value");
    static final FieldInfo FIELD_STRING_OFFSET = KLASS_STRING.getDeclaredField("offset");
    static final FieldInfo FIELD_STRING_COUNT = KLASS_STRING.getDeclaredField("count");

    static final class Jdk7CharArrayEncoder implements TextEncoder {
        final char[] chars;

        public Jdk7CharArrayEncoder(String text) {
            this.chars = (char[]) FIELD_STRING_VALUE.get(text);
        }

        @Override
        public void writeTo(JetWriter os) throws IOException {
            os.print(chars, 0, chars.length);
        }
    }

    static final class Jdk6CharArrayEncoder implements TextEncoder {
        final char[] chars;
        final int offset;
        final int count;

        public Jdk6CharArrayEncoder(String text) {
            this.chars = (char[]) FIELD_STRING_VALUE.get(text);
            this.offset = (Integer) FIELD_STRING_OFFSET.get(text);
            this.count = (Integer) FIELD_STRING_COUNT.get(text);
        }

        @Override
        public void writeTo(JetWriter os) throws IOException {
            os.print(chars, offset, count);
        }
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy