/*******************************************************************************
* Copyright (c) 2011, 2013 Wind River Systems, Inc. and others. All rights reserved.
* This program and the accompanying materials are made available under the terms
* of the Eclipse Public License v1.0 which accompanies this distribution, and is
* available at http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Wind River Systems - initial API and implementation
*******************************************************************************/
package org.eclipse.tcf.te.ui.controls.validator;
import java.math.BigInteger;
import org.eclipse.core.runtime.Assert;
/**
* Validator for hex values.
*/
public class HexValidator extends RegexValidator {
/**
* Allows entering decimal numbers.
*/
public static final int ATTR_ALLOW_DECIMAL = 4;
/**
* Enables negative decimal numbers. Has effect only if {@link #ATTR_ALLOW_DECIMAL}
* is set as well.
*/
public static final int ATTR_ALLOW_NEGATIVE_DECIMAL = 8;
/**
* Enables negative hexadecimal numbers.
*/
public static final int ATTR_ALLOW_NEGATIVE_HEX = 16;
// next attribute should start with 2^5
// keys for error messages
public static final String ERROR_INVALID_VALUE_RANGE = "HexValidator_Error_InvalidValueRange"; //$NON-NLS-1$
// regular expressions
protected static final String HEX_REGEX = "@NEGATIVE@(0(x|X)[0-9a-fA-F]{@BYTES_MIN@,@BYTES_MAX@})|0"; //$NON-NLS-1$
protected static final String NUMBER_REGEX = "@NEGATIVE@([0-9]*)"; //$NON-NLS-1$
private int minBytes = 0;
private int maxBytes = 8;
private boolean isHex = false;
private boolean isDecimal = false;
/**
* Constructor.
* @param attributes
*/
public HexValidator(int attributes, int minBytes, int maxBytes) {
super(attributes, getRegEx(attributes, minBytes, maxBytes));
this.minBytes = minBytes;
this.maxBytes = maxBytes;
}
/**
* Constructor.
* @param attributes
*/
public HexValidator(int attributes, int bytes) {
super(attributes, getRegEx(attributes, bytes, bytes));
this.minBytes = bytes;
this.maxBytes = bytes;
}
/*
* Static method to generate regular expression for constructor super call.
*/
private static String getRegEx(int attributes, int minBytes, int maxBytes) {
String regex = (isAttribute(ATTR_ALLOW_DECIMAL, attributes)
? NUMBER_REGEX.replaceAll("@NEGATIVE@", isAttribute(ATTR_ALLOW_NEGATIVE_DECIMAL, attributes) ? "-?" : "") + "|" //$NON-NLS-1$//$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
: "") + HEX_REGEX; //$NON-NLS-1$
regex = regex.replaceAll("@NEGATIVE@", isAttribute(ATTR_ALLOW_NEGATIVE_HEX, attributes) ? "-?" : ""); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
regex = regex.replaceAll("@BYTES_MIN@", "" + minBytes); //$NON-NLS-1$ //$NON-NLS-2$
regex = regex.replaceAll("@BYTES_MAX@", "" + maxBytes); //$NON-NLS-1$ //$NON-NLS-2$
return regex;
}
/**
* Adjust the values for minimum bytes and maximum byte allowed.
*
* @param minBytes The minimum number of bytes. Must be non-negative.
* @param maxBytes The maximum number of bytes. Must be non-negative.
*/
public void setBounds(int minBytes, int maxBytes) {
Assert.isTrue(minBytes >= 0 && maxBytes >= 0 && minBytes <= maxBytes);
setRegularExpression(getRegEx(getAttributes(), minBytes, maxBytes));
this.minBytes = minBytes;
this.maxBytes = maxBytes;
}
/**
* Returns if the validator is currently working in hex mode.
*
* @return <code>true</code> if in hex mode, <code>false</code> otherwise.
*/
public boolean isHex() {
return isHex;
}
/**
* Returns if the validator is currently working in decimal mode.
*
* @return <code>true</code> if in decimal mode, <code>false</code> otherwise.
*/
public boolean isDecimal() {
return isDecimal;
}
/* (non-Javadoc)
* @see org.eclipse.tcf.te.ui.controls.validator.RegexValidator#isValid(java.lang.String)
*/
@Override
public boolean isValid(String newText) {
isHex = false;
isDecimal = false;
boolean valid = super.isValid(newText);
if (valid) {
String hexRegex = HEX_REGEX;
hexRegex = hexRegex.replaceAll("@NEGATIVE@", isAttribute(ATTR_ALLOW_NEGATIVE_HEX) ? "-?" : ""); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
hexRegex = hexRegex.replaceAll("@BYTES_MIN@", "" + minBytes); //$NON-NLS-1$ //$NON-NLS-2$
hexRegex = hexRegex.replaceAll("@BYTES_MAX@", "" + maxBytes); //$NON-NLS-1$ //$NON-NLS-2$
String numberRegex = NUMBER_REGEX;
numberRegex = numberRegex.replaceAll("@NEGATIVE@", isAttribute(ATTR_ALLOW_NEGATIVE_DECIMAL) ? "-?" : ""); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
isHex = newText.matches(hexRegex);
isDecimal = newText.matches(numberRegex);
}
if (valid && isAttribute(ATTR_ALLOW_DECIMAL) && isDecimal()) {
BigInteger min = minBytes > 1 ? BigInteger.valueOf(16).pow(minBytes-1) : BigInteger.ZERO;
BigInteger max = BigInteger.valueOf(16).pow(maxBytes);
BigInteger value = !"".equals(newText) ? decode(newText) : BigInteger.ZERO; //$NON-NLS-1$
if (value == null || value.abs().compareTo(min) < 0 || value.abs().compareTo(max) > 0) {
setMessage(getMessageText(ERROR_INVALID_VALUE_RANGE), getMessageTextType(ERROR_INVALID_VALUE_RANGE, ERROR));
valid = getMessageType() != ERROR;
}
}
return valid;
}
/**
* Decodes a given string into a <code>BigInteger</code> representation.
*
* @param value The value to decode. Must not be <code>null</code>!
* @return The big integer representation or <code>null</code> if the decoding failed.
*/
public final static BigInteger decode(String value) {
Assert.isNotNull(value);
BigInteger result = null;
try {
if (value.trim().toUpperCase().startsWith("0X")) { //$NON-NLS-1$
// we have to cut away the leading 0x.
result = new BigInteger(value.substring(2), 16);
} else {
result = new BigInteger(value, 10);
}
} catch (NumberFormatException e) { /* ignored on purpose */
}
return result;
}
}