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 @SuppressWarnings("javadoc")
  26 public final class StringNode extends Node implements StringType {
  27 
  28     private static final int NODE_STR_MARGIN = 16;
  29     private static final int NODE_STR_BUF_SIZE = 24;
  30 
  31     public char[] chars;
  32     public int p;
  33     public int end;
  34 
  35     public int flag;
  36 
  37     public StringNode() {
  38         this(NODE_STR_BUF_SIZE);
  39     }
  40 
  41     private StringNode(int size) {
  42         this.chars = new char[size];
  43         this.p = 0;
  44         this.end = 0;
  45     }
  46 
  47     public StringNode(final char[] chars, final int p, final int end) {
  48         this.chars = chars;
  49         this.p = p;
  50         this.end = end;
  51         setShared();
  52     }
  53 
  54     public StringNode(final char c) {
  55         this();
  56         chars[end++] = c;
  57     }
  58 
  59     /**
  60      * Create a new empty StringNode.
  61      */
  62     public static StringNode createEmpty() {
  63         return new StringNode(0);
  64     }
  65 
  66     /* Ensure there is ahead bytes available in node's buffer
  67      * (assumes that the node is not shared)
  68      */
  69     public void ensure(final int ahead) {
  70         final int len = (end - p) + ahead;
  71         if (len >= chars.length) {
  72             final char[] tmp = new char[len + NODE_STR_MARGIN];
  73             System.arraycopy(chars, p, tmp, 0, end - p);
  74             chars = tmp;
  75         }
  76     }
  77 
  78     /* COW and/or ensure there is ahead bytes available in node's buffer
  79      */
  80     private void modifyEnsure(final int ahead) {
  81         if (isShared()) {
  82             final int len = (end - p) + ahead;
  83             final char[] tmp = new char[len + NODE_STR_MARGIN];
  84             System.arraycopy(chars, p, tmp, 0, end - p);
  85             chars = tmp;
  86             end -= p;
  87             p = 0;
  88             clearShared();
  89         } else {
  90             ensure(ahead);
  91         }
  92     }
  93 
  94     @Override
  95     public int getType() {
  96         return STR;
  97     }
  98 
  99     @Override
 100     public String getName() {
 101         return "String";
 102     }
 103 
 104     @Override
 105     public String toString(final int level) {
 106         final StringBuilder value = new StringBuilder();
 107         value.append("\n  bytes: '");
 108         for (int i=p; i<end; i++) {
 109             if (chars[i] >= 0x20 && chars[i] < 0x7f) {
 110                 value.append(chars[i]);
 111             } else {
 112                 value.append(String.format("[0x%04x]", (int)chars[i]));
 113             }
 114         }
 115         value.append("'");
 116         return value.toString();
 117     }
 118 
 119     public int length() {
 120         return end - p;
 121     }
 122 
 123     public StringNode splitLastChar() {
 124         StringNode n = null;
 125 
 126         if (end > p) {
 127             final int prev = EncodingHelper.prevCharHead(p, end);
 128             if (prev != -1 && prev > p) { /* can be splitted. */
 129                 n = new StringNode(chars, prev, end);
 130                 if (isRaw()) n.setRaw();
 131                 end = prev;
 132             }
 133         }
 134         return n;
 135     }
 136 
 137     public boolean canBeSplit() {
 138         return end > p && 1 < (end - p);
 139     }
 140 
 141     public void set(final char[] chars, final int p, final int end) {
 142         this.chars = chars;
 143         this.p = p;
 144         this.end = end;
 145         setShared();
 146     }
 147 
 148     public void cat(final char[] cat, final int catP, final int catEnd) {
 149         final int len = catEnd - catP;
 150         modifyEnsure(len);
 151         System.arraycopy(cat, catP, chars, end, len);
 152         end += len;
 153     }
 154 
 155     public void cat(final char c) {
 156         modifyEnsure(1);
 157         chars[end++] = c;
 158     }
 159 
 160     public void catCode(final int code) {
 161         cat((char)code);
 162     }
 163 
 164     public void clear() {
 165         if (chars.length > NODE_STR_BUF_SIZE) chars = new char[NODE_STR_BUF_SIZE];
 166         flag = 0;
 167         p = end = 0;
 168     }
 169 
 170     public void setRaw() {
 171         flag |= NSTR_RAW;
 172     }
 173 
 174     public void clearRaw() {
 175         flag &= ~NSTR_RAW;
 176     }
 177 
 178     public boolean isRaw() {
 179         return (flag & NSTR_RAW) != 0;
 180     }
 181 
 182     public void setAmbig() {
 183         flag |= NSTR_AMBIG;
 184     }
 185 
 186     public void clearAmbig() {
 187         flag &= ~NSTR_AMBIG;
 188     }
 189 
 190     public boolean isAmbig() {
 191         return (flag & NSTR_AMBIG) != 0;
 192     }
 193 
 194     public void setDontGetOptInfo() {
 195         flag |= NSTR_DONT_GET_OPT_INFO;
 196     }
 197 
 198     public void clearDontGetOptInfo() {
 199         flag &= ~NSTR_DONT_GET_OPT_INFO;
 200     }
 201 
 202     public boolean isDontGetOptInfo() {
 203         return (flag & NSTR_DONT_GET_OPT_INFO) != 0;
 204     }
 205 
 206     public void setShared() {
 207         flag |= NSTR_SHARED;
 208     }
 209 
 210     public void clearShared() {
 211         flag &= ~NSTR_SHARED;
 212     }
 213 
 214     public boolean isShared() {
 215         return (flag & NSTR_SHARED) != 0;
 216     }
 217 }