• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

nulab / zxcvbn4j / #141

pending completion
#141

push

github-actions

web-flow
Merge pull request #135 from manchilop/master

Added feedback messages translated into Spanish

1392 of 1507 relevant lines covered (92.37%)

0.92 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

88.33
/src/main/java/com/nulabinc/zxcvbn/WipeableString.java
1
package com.nulabinc.zxcvbn;
2

3
import java.nio.CharBuffer;
4
import java.util.Arrays;
5

6
/**
7
 * A character sequence with many attributes of Strings, but that can have its content wiped.
8
 */
9
public class WipeableString implements CharSequence {
1✔
10

11
    private char[] content;
12
    private int hash = 0;
1✔
13
    private boolean wiped = false;
1✔
14

15
    /**
16
     * Creates a new wipeable string, copying the content from the specified source.
17
     */
18
    public WipeableString(CharSequence source) {
1✔
19
        this.content = new char[source.length()];
1✔
20
        for (int n = 0; n < content.length; n++) {
1✔
21
            content[n] = source.charAt(n);
1✔
22
        }
23
    }
1✔
24

25
    /**
26
     * Creates a new wipeable string, copying the content from the specified source.
27
     */
28
    public WipeableString(char[] source) {
1✔
29
        this.content = Arrays.copyOf(source,source.length);
1✔
30
    }
1✔
31

32
    @Override
33
    public int length() {
34
        return content == null ? 0 : content.length;
1✔
35
    }
36

37
    @Override
38
    public char charAt(int index) {
39
        return content[index];
1✔
40
    }
41

42
    @Override
43
    public WipeableString subSequence(int start, int end) {
44
        return new WipeableString(Arrays.copyOfRange(content,start,end));
1✔
45
    }
46

47
    /**
48
     * Wipe the content of the wipeable string.
49
     *
50
     * Overwrites the content buffer with spaces, then replaces the buffer with an empty one.
51
     */
52
    public void wipe() {
53
        Arrays.fill(content,' ');
1✔
54
        hash = 0;
1✔
55
        content = new char[0];
1✔
56
        wiped = true;
1✔
57
    }
1✔
58

59
    /**
60
     * Returns a new wipeable string with the specified content forced into lower case.
61
     */
62
    public static WipeableString lowerCase(CharSequence source) {
63
        assert source != null;
1✔
64
        char[] chars = new char[source.length()];
1✔
65
        for (int n = 0; n < source.length(); n++) {
1✔
66
            chars[n] = Character.toLowerCase(source.charAt(n));
1✔
67
        }
68
        return new WipeableString(chars);
1✔
69
    }
70

71
    /**
72
     * Returns a new wipeable string with the specified content but with the order of the characters reversed.
73
     */
74
    public static WipeableString reversed(CharSequence source) {
75
        assert source != null;
1✔
76
        int length = source.length();
1✔
77
        char[] chars = new char[length];
1✔
78
        for (int n = 0; n < source.length(); n++) {
1✔
79
            chars[n] = source.charAt(length-n-1);
1✔
80
        }
81
        return new WipeableString(chars);
1✔
82
    }
83

84
    /**
85
     * Returns a copy of a portion of a character sequence as a wipeable string.
86
     */
87
    public static WipeableString copy(CharSequence source, int start, int end) {
88
        return new WipeableString(source.subSequence(start,end));
1✔
89
    }
90

91
    /**
92
     * Returns the position of the first match of the specified character (indexed from 0).
93
     */
94
    public int indexOf(char character) {
95
        for (int n = 0; n < content.length; n++) {
1✔
96
            if (content[n] == character) {
1✔
97
                return n;
1✔
98
            }
99
        }
100
        return -1;
1✔
101
    }
102

103
    /**
104
     * Returns the nth Unicode code point.
105
     */
106
    public int codePointAt(int index) {
107
        // Copy the implementation from String
108
        if ((index < 0) || (index >= content.length)) {
1✔
109
            throw new StringIndexOutOfBoundsException(index);
×
110
        }
111
        return Character.codePointAt(content, index, content.length);
1✔
112
    }
113

114
    /**
115
     * Returns true if the wipeable string has been wiped.
116
     */
117
    public boolean isWiped() {
118
        return this.wiped;
×
119
    }
120

121
    /**
122
     * Returns a copy of the content as a char array.
123
     */
124
    public char[] charArray() {
125
        return Arrays.copyOf(content,content.length);
1✔
126
    }
127

128
    /**
129
     * Trims whitespace from a CharSequence.
130
     *
131
     * If there is no trailing whitespace then the original value is returned.
132
     * If there is trailing whitespace then the content (without that trailing
133
     * whitespace) is copied into a new WipeableString.
134
     */
135
    static CharSequence trimTrailingWhitespace(CharSequence s) {
136
        if (!Character.isWhitespace(s.charAt(s.length()-1))) {
1✔
137
            return s;
1✔
138
        }
139

140
        int length = s.length();
1✔
141

142
        while (length > 0 && Character.isWhitespace(s.charAt(length-1))) {
1✔
143
            length--;
1✔
144
        }
145

146
        return WipeableString.copy(s,0,length);
1✔
147
    }
148

149

150
    /**
151
     * A version of Integer.parse(String) that accepts CharSequence as parameter.
152
     */
153
    public static int parseInt(CharSequence s) throws NumberFormatException {
154
        return parseInt(s,10);
1✔
155
    }
156

157
    /**
158
     * A version of Integer.parse(String) that accepts CharSequence as parameter.
159
     */
160
    public static int parseInt(CharSequence s, int radix) throws NumberFormatException {
161
        if (s == null) {
1✔
162
            throw new NumberFormatException("null");
×
163
        }
164

165
        s = trimTrailingWhitespace(s);
1✔
166

167
        if (radix < Character.MIN_RADIX) {
1✔
168
            throw new NumberFormatException("radix " + radix +
×
169
                    " less than Character.MIN_RADIX");
170
        }
171

172
        if (radix > Character.MAX_RADIX) {
1✔
173
            throw new NumberFormatException("radix " + radix +
×
174
                    " greater than Character.MAX_RADIX");
175
        }
176

177
        int result = 0;
1✔
178
        boolean negative = false;
1✔
179
        int i = 0, len = s.length();
1✔
180
        int limit = -Integer.MAX_VALUE;
1✔
181
        int multmin;
182
        int digit;
183

184
        if (len > 0) {
1✔
185
            char firstChar = s.charAt(0);
1✔
186
            if (firstChar < '0') { // Possible leading "+" or "-"
1✔
187
                if (firstChar == '-') {
1✔
188
                    negative = true;
1✔
189
                    limit = Integer.MIN_VALUE;
1✔
190
                } else if (firstChar != '+')
1✔
191
                    throw new NumberFormatException("For input string: \"" + s + "\"");
×
192

193
                if (len == 1) // Cannot have lone "+" or "-"
1✔
194
                    throw new NumberFormatException("For input string: \"" + s + "\"");
×
195
                i++;
1✔
196
            }
197
            multmin = limit / radix;
1✔
198
            while (i < len) {
1✔
199
                // Accumulating negatively avoids surprises near MAX_VALUE
200
                digit = Character.digit(s.charAt(i++),radix);
1✔
201
                if (digit < 0) {
1✔
202
                    throw new NumberFormatException("For input string: \"" + s + "\"");
×
203
                }
204
                if (result < multmin) {
1✔
205
                    throw new NumberFormatException("For input string: \"" + s + "\"");
×
206
                }
207
                result *= radix;
1✔
208
                if (result < limit + digit) {
1✔
209
                    throw new NumberFormatException("For input string: \"" + s + "\"");
×
210
                }
211
                result -= digit;
1✔
212
            }
213
        } else {
1✔
214
            throw new NumberFormatException("For input string: \"" + s + "\"");
×
215
        }
216
        return negative ? result : -result;
1✔
217
    }
218

219
    @Override
220
    public String toString() {
221
        return new String(content);
1✔
222
    }
223

224
    @Override
225
    public int hashCode() {
226
        // Reproduce the same hash as String
227
        int h = hash;
1✔
228
        if (h == 0 && content.length > 0) {
1✔
229
            char val[] = content;
1✔
230

231
            for (int i = 0; i < content.length; i++) {
1✔
232
                h = 31 * h + val[i];
1✔
233
            }
234
            hash = h;
1✔
235
        }
236
        return h;
1✔
237
    }
238

239

240
    @Override
241
    public boolean equals(Object obj) {
242
        // Use an algorithm that matches any CharSequence (including Strings) with identical content.
243
        if (obj == null) {
1✔
244
            return false;
×
245
        }
246
        if (obj == this) {
1✔
247
            return true;
×
248
        }
249
        if (obj instanceof CharSequence) {
1✔
250
            CharSequence other = (CharSequence)obj;
1✔
251
            if (other.length() != length()) {
1✔
252
                return false;
1✔
253
            }
254
            for (int n = 0; n < length(); n++) {
1✔
255
                if (charAt(n) != other.charAt(n)) {
1✔
256
                    return false;
1✔
257
                }
258
            }
259
            return true;
1✔
260
        }
261
        return false;
×
262
    }
263

264
    /**
265
     * Wipes the content of the specified character sequence if possible.
266
     *
267
     * The following types can be wiped...
268
     *   WipeableString
269
     *   StringBuilder
270
     *   StringBuffer
271
     *   CharBuffer (if not readOnly)
272
     */
273
    public static void wipeIfPossible(CharSequence text) {
274
        if (text == null) return;
1✔
275
        if (text instanceof WipeableString) {
1✔
276
            ((WipeableString)text).wipe();
1✔
277
        } else if (text instanceof StringBuilder) {
1✔
278
            for (int n = 0; n < text.length(); n++) {
1✔
279
                ((StringBuilder) text).setCharAt(n, ' ');
1✔
280
            }
281
            ((StringBuilder) text).setLength(0);
1✔
282
        } else if (text instanceof StringBuffer) {
1✔
283
            for (int n = 0; n < text.length(); n++) {
1✔
284
                ((StringBuffer) text).setCharAt(n, ' ');
1✔
285
            }
286
            ((StringBuffer) text).setLength(0);
1✔
287
        }  else if (text instanceof CharBuffer) {
1✔
288
            if (!((CharBuffer)text).isReadOnly()) {
1✔
289
                for (int n = 0; n < text.length(); n++) {
1✔
290
                    ((CharBuffer) text).put(n, ' ');
1✔
291
                }
292
            }
293
        }
294

295
    }
1✔
296

297
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc