src/java.base/share/classes/java/lang/StringLatin1.java
changeset 54728 6188582d58b5
parent 51714 975d3636a2f9
child 54971 4285b4d13471
--- a/src/java.base/share/classes/java/lang/StringLatin1.java	Mon May 06 18:01:01 2019 -0400
+++ b/src/java.base/share/classes/java/lang/StringLatin1.java	Mon May 06 18:07:55 2019 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2019, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -42,6 +42,14 @@
 
 final class StringLatin1 {
 
+    /**
+     * The maximum size of array to allocate (unless necessary).
+     * Some VMs reserve some header words in an array.
+     * Attempts to allocate larger arrays may result in
+     * OutOfMemoryError: Requested array size exceeds VM limit
+     */
+    private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
+
     public static char charAt(byte[] value, int index) {
         if (index < 0 || index >= value.length) {
             throw new StringIndexOutOfBoundsException(index);
@@ -304,7 +312,7 @@
             }
             if (i < len) {
                 if (canEncode(newChar)) {
-                    byte buf[] = new byte[len];
+                    byte[] buf = StringConcatHelper.newArray(len);
                     for (int j = 0; j < i; j++) {    // TBD arraycopy?
                         buf[j] = value[j];
                     }
@@ -330,6 +338,64 @@
         return null; // for string to return this;
     }
 
+    public static String replace(byte[] value, int valLen, byte[] targ,
+                                 int targLen, byte[] repl, int replLen)
+    {
+        assert targLen > 0;
+        int i, j, p = 0;
+        if (valLen == 0 || (i = indexOf(value, valLen, targ, targLen, 0)) < 0) {
+            return null; // for string to return this;
+        }
+
+        // find and store indices of substrings to replace
+        int[] pos = new int[16];
+        pos[0] = i;
+        i += targLen;
+        while ((j = indexOf(value, valLen, targ, targLen, i)) > 0) {
+            if (++p == pos.length) {
+                int cap = p + (p >> 1);
+                // overflow-conscious code
+                if (cap - MAX_ARRAY_SIZE > 0) {
+                    if (p == MAX_ARRAY_SIZE) {
+                        throw new OutOfMemoryError();
+                    }
+                    cap = MAX_ARRAY_SIZE;
+                }
+                pos = Arrays.copyOf(pos, cap);
+            }
+            pos[p] = j;
+            i = j + targLen;
+        }
+
+        int resultLen;
+        try {
+            resultLen = Math.addExact(valLen,
+                    Math.multiplyExact(++p, replLen - targLen));
+        } catch (ArithmeticException ignored) {
+            throw new OutOfMemoryError();
+        }
+        if (resultLen == 0) {
+            return "";
+        }
+
+        byte[] result = StringConcatHelper.newArray(resultLen);
+        int posFrom = 0, posTo = 0;
+        for (int q = 0; q < p; ++q) {
+            int nextPos = pos[q];
+            while (posFrom < nextPos) {
+                result[posTo++] = value[posFrom++];
+            }
+            posFrom += targLen;
+            for (int k = 0; k < replLen; ++k) {
+                result[posTo++] = repl[k];
+            }
+        }
+        while (posFrom < valLen) {
+            result[posTo++] = value[posFrom++];
+        }
+        return new String(result, LATIN1);
+    }
+
     // case insensitive
     public static boolean regionMatchesCI(byte[] value, int toffset,
                                           byte[] other, int ooffset, int len) {