1 /*
   2  * Permission is hereby granted, free of charge, to any person obtaining a copy of
   3  * this software and associated documentation files (the "Software"), to deal in
   4  * the Software without restriction, including without limitation the rights to
   5  * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
   6  * of the Software, and to permit persons to whom the Software is furnished to do
   7  * so, subject to the following conditions:
   8  *
   9  * The above copyright notice and this permission notice shall be included in all
  10  * copies or substantial portions of the Software.
  11  *
  12  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  13  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  14  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  15  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  16  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  17  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  18  * SOFTWARE.
  19  */
  20 package jdk.nashorn.internal.runtime.regexp.joni.ast;
  21 
  22 import jdk.nashorn.internal.runtime.regexp.joni.EncodingHelper;
  23 import jdk.nashorn.internal.runtime.regexp.joni.constants.StringType;
  24 
  25 public final class StringNode extends Node implements StringType {
  26 
  27     private static final int NODE_STR_MARGIN = 16;
  28     private static final int NODE_STR_BUF_SIZE = 24;
  29     public static final StringNode EMPTY = new StringNode(null, Integer.MAX_VALUE, Integer.MAX_VALUE);
  30 
  31     public char[] chars;
  32     public int p;
  33     public int end;
  34 
  35     public int flag;
  36 
  37     public StringNode() {
  38         this.chars = new char[NODE_STR_BUF_SIZE];
  39     }
  40 
  41     public StringNode(char[] chars, int p, int end) {
  42         this.chars = chars;
  43         this.p = p;
  44         this.end = end;
  45         setShared();
  46     }
  47 
  48     public StringNode(char c) {
  49         this();
  50         chars[end++] = c;
  51     }
  52 
  53     /* Ensure there is ahead bytes available in node's buffer
  54      * (assumes that the node is not shared)
  55      */
  56     public void ensure(int ahead) {
  57         int len = (end - p) + ahead;
  58         if (len >= chars.length) {
  59             char[] tmp = new char[len + NODE_STR_MARGIN];
  60             System.arraycopy(chars, p, tmp, 0, end - p);
  61             chars = tmp;
  62         }
  63     }
  64 
  65     /* COW and/or ensure there is ahead bytes available in node's buffer
  66      */
  67     private void modifyEnsure(int ahead) {
  68         if (isShared()) {
  69             int len = (end - p) + ahead;
  70             char[] tmp = new char[len + NODE_STR_MARGIN];
  71             System.arraycopy(chars, p, tmp, 0, end - p);
  72             chars = tmp;
  73             end = end - p;
  74             p = 0;
  75             clearShared();
  76         } else {
  77             ensure(ahead);
  78         }
  79     }
  80 
  81     @Override
  82     public int getType() {
  83         return STR;
  84     }
  85 
  86     @Override
  87     public String getName() {
  88         return "String";
  89     }
  90 
  91     @Override
  92     public String toString(int level) {
  93         StringBuilder value = new StringBuilder();
  94         value.append("\n  bytes: '");
  95         for (int i=p; i<end; i++) {
  96             if (chars[i] >= 0x20 && chars[i] < 0x7f) {
  97                 value.append(chars[i]);
  98             } else {
  99                 value.append(String.format("[0x%04x]", chars[i]));
 100             }
 101         }
 102         value.append("'");
 103         return value.toString();
 104     }
 105 
 106     public int length() {
 107         return end - p;
 108     }
 109 
 110     public StringNode splitLastChar() {
 111         StringNode n = null;
 112 
 113         if (end > p) {
 114             int prev = EncodingHelper.prevCharHead(p, end);
 115             if (prev != -1 && prev > p) { /* can be splitted. */
 116                 n = new StringNode(chars, prev, end);
 117                 if (isRaw()) n.setRaw();
 118                 end = prev;
 119             }
 120         }
 121         return n;
 122     }
 123 
 124     public boolean canBeSplit() {
 125         if (end > p) {
 126             return 1 < (end - p);
 127         }
 128         return false;
 129     }
 130 
 131     public void set(char[] chars, int p, int end) {
 132         this.chars = chars;
 133         this.p = p;
 134         this.end = end;
 135         setShared();
 136     }
 137 
 138     public void cat(char[] cat, int catP, int catEnd) {
 139         int len = catEnd - catP;
 140         modifyEnsure(len);
 141         System.arraycopy(cat, catP, chars, end, len);
 142         end += len;
 143     }
 144 
 145     public void cat(char c) {
 146         modifyEnsure(1);
 147         chars[end++] = c;
 148     }
 149 
 150     public void catCode(int code) {
 151         cat((char)code);
 152     }
 153 
 154     public void clear() {
 155         if (chars.length > NODE_STR_BUF_SIZE) chars = new char[NODE_STR_BUF_SIZE];
 156         flag = 0;
 157         p = end = 0;
 158     }
 159 
 160     public void setRaw() {
 161         flag |= NSTR_RAW;
 162     }
 163 
 164     public void clearRaw() {
 165         flag &= ~NSTR_RAW;
 166     }
 167 
 168     public boolean isRaw() {
 169         return (flag & NSTR_RAW) != 0;
 170     }
 171 
 172     public void setAmbig() {
 173         flag |= NSTR_AMBIG;
 174     }
 175 
 176     public void clearAmbig() {
 177         flag &= ~NSTR_AMBIG;
 178     }
 179 
 180     public boolean isAmbig() {
 181         return (flag & NSTR_AMBIG) != 0;
 182     }
 183 
 184     public void setDontGetOptInfo() {
 185         flag |= NSTR_DONT_GET_OPT_INFO;
 186     }
 187 
 188     public void clearDontGetOptInfo() {
 189         flag &= ~NSTR_DONT_GET_OPT_INFO;
 190     }
 191 
 192     public boolean isDontGetOptInfo() {
 193         return (flag & NSTR_DONT_GET_OPT_INFO) != 0;
 194     }
 195 
 196     public void setShared() {
 197         flag |= NSTR_SHARED;
 198     }
 199 
 200     public void clearShared() {
 201         flag &= ~NSTR_SHARED;
 202     }
 203 
 204     public boolean isShared() {
 205         return (flag & NSTR_SHARED) != 0;
 206     }
 207 }