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