diff options
author | James Ahlborn <jtahlborn@yahoo.com> | 2014-12-04 01:17:26 +0000 |
---|---|---|
committer | James Ahlborn <jtahlborn@yahoo.com> | 2014-12-04 01:17:26 +0000 |
commit | d327ceb55eef6e222749346e2c20c7e5dfd08041 (patch) | |
tree | d8e5c186306570a001c5608fe51d00c7534ef535 /src | |
parent | e6e0208c973f6a67e8d4593aa665133a6d7e7f03 (diff) | |
download | jackcess-d327ceb55eef6e222749346e2c20c7e5dfd08041.tar.gz jackcess-d327ceb55eef6e222749346e2c20c7e5dfd08041.zip |
Better validation of identifier names (disallow invalid characters according to access naming rules)
git-svn-id: https://svn.code.sf.net/p/jackcess/code/jackcess/trunk@902 f203690c-595d-4dc9-a70b-905162fa7fd2
Diffstat (limited to 'src')
6 files changed, 79 insertions, 9 deletions
diff --git a/src/changes/changes.xml b/src/changes/changes.xml index 5137378..d128dc3 100644 --- a/src/changes/changes.xml +++ b/src/changes/changes.xml @@ -14,6 +14,10 @@ <action dev="jahlborn" type="fix" system="SourceForge2Patches" issue="18"> Don't double quote already quoted identifiers. </action> + <action dev="jahlborn" type="update"> + Better validation of identifier names (disallow invalid characters + according to Access naming rules). + </action> </release> <release version="2.0.7" date="2014-11-22"> <action dev="jahlborn" type="fix" system="SourceForge2" issue="111"> diff --git a/src/main/java/com/healthmarketscience/jackcess/IndexBuilder.java b/src/main/java/com/healthmarketscience/jackcess/IndexBuilder.java index 26c2c85..4a55205 100644 --- a/src/main/java/com/healthmarketscience/jackcess/IndexBuilder.java +++ b/src/main/java/com/healthmarketscience/jackcess/IndexBuilder.java @@ -24,8 +24,10 @@ import java.util.HashSet; import java.util.List; import java.util.Set; +import com.healthmarketscience.jackcess.impl.DatabaseImpl; import com.healthmarketscience.jackcess.impl.IndexData; import com.healthmarketscience.jackcess.impl.IndexImpl; +import com.healthmarketscience.jackcess.impl.JetFormat; /** * Builder style class for constructing an {@link Index}. See {@link @@ -133,7 +135,11 @@ public class IndexBuilder return this; } - public void validate(Set<String> tableColNames) { + public void validate(Set<String> tableColNames, JetFormat format) { + + DatabaseImpl.validateIdentifierName( + getName(), format.MAX_INDEX_NAME_LENGTH, "index"); + if(getColumns().isEmpty()) { throw new IllegalArgumentException("index " + getName() + " has no columns"); diff --git a/src/main/java/com/healthmarketscience/jackcess/impl/DatabaseImpl.java b/src/main/java/com/healthmarketscience/jackcess/impl/DatabaseImpl.java index 548833b..2afd394 100644 --- a/src/main/java/com/healthmarketscience/jackcess/impl/DatabaseImpl.java +++ b/src/main/java/com/healthmarketscience/jackcess/impl/DatabaseImpl.java @@ -56,6 +56,7 @@ import java.util.NoSuchElementException; import java.util.Set; import java.util.TimeZone; import java.util.TreeSet; +import java.util.regex.Pattern; import com.healthmarketscience.jackcess.ColumnBuilder; import com.healthmarketscience.jackcess.Cursor; @@ -248,7 +249,10 @@ public class DatabaseImpl implements Database /** the columns to read when getting object propertyes */ private static Collection<String> SYSTEM_CATALOG_PROPS_COLUMNS = new HashSet<String>(Arrays.asList(CAT_COL_ID, CAT_COL_PROPS)); - + + /** regex matching characters which are invalid in identifier names */ + private static final Pattern INVALID_IDENTIFIER_CHARS = + Pattern.compile("[\\p{Cntrl}.!`\\]\\[]"); /** the File of the database */ private final File _file; @@ -960,8 +964,8 @@ public class DatabaseImpl implements Database } validateIdentifierName(name, getFormat().MAX_TABLE_NAME_LENGTH, "table"); - validateIdentifierName(linkedDbName, DataType.MEMO.getMaxSize(), - "linked database"); + validateName(linkedDbName, DataType.MEMO.getMaxSize(), + "linked database"); validateIdentifierName(linkedTableName, getFormat().MAX_TABLE_NAME_LENGTH, "linked table"); @@ -1481,22 +1485,61 @@ public class DatabaseImpl implements Database /** * Validates an identifier name. + * + * Names of fields, controls, and objects in Microsoft Access: + * <ul> + * <li>Can include any combination of letters, numbers, spaces, and special + * characters except a period (.), an exclamation point (!), an accent + * grave (`), and brackets ([ ]).</li> + * <li>Can't begin with leading spaces.</li> + * <li>Can't include control characters (ASCII values 0 through 31).</li> + * </ul> + * * @usage _advanced_method_ */ public static void validateIdentifierName(String name, int maxLength, String identifierType) { - if((name == null) || (name.trim().length() == 0)) { + // basic name validation + validateName(name, maxLength, identifierType); + + // additional identifier validation + if(INVALID_IDENTIFIER_CHARS.matcher(name).find()) { throw new IllegalArgumentException( - identifierType + " must have non-empty name"); + identifierType + " name contains invalid characters"); + } + + // cannot start with spaces + if(name.charAt(0) == ' ') { + throw new IllegalArgumentException( + identifierType + " name cannot start with a space character"); + } + } + + /** + * Validates a name. + */ + private static void validateName(String name, int maxLength, String nameType) + { + if(isBlank(name)) { + throw new IllegalArgumentException( + nameType + " must have non-blank name"); } if(name.length() > maxLength) { throw new IllegalArgumentException( - identifierType + " name is longer than max length of " + maxLength + + nameType + " name is longer than max length of " + maxLength + ": " + name); } } + + /** + * Returns {@code true} if the given string is {@code null} or all blank + * space, {@code false} otherwise. + */ + public static boolean isBlank(String name) { + return((name == null) || (name.trim().length() == 0)); + } @Override public String toString() { diff --git a/src/main/java/com/healthmarketscience/jackcess/impl/JetFormat.java b/src/main/java/com/healthmarketscience/jackcess/impl/JetFormat.java index fcb39bd..4c915e3 100644 --- a/src/main/java/com/healthmarketscience/jackcess/impl/JetFormat.java +++ b/src/main/java/com/healthmarketscience/jackcess/impl/JetFormat.java @@ -264,6 +264,7 @@ public abstract class JetFormat { public final int USAGE_MAP_TABLE_BYTE_LENGTH; public final int MAX_COLUMNS_PER_TABLE; + public final int MAX_INDEXES_PER_TABLE; public final int MAX_TABLE_NAME_LENGTH; public final int MAX_COLUMN_NAME_LENGTH; public final int MAX_INDEX_NAME_LENGTH; @@ -399,6 +400,7 @@ public abstract class JetFormat { USAGE_MAP_TABLE_BYTE_LENGTH = defineUsageMapTableByteLength(); MAX_COLUMNS_PER_TABLE = defineMaxColumnsPerTable(); + MAX_INDEXES_PER_TABLE = defineMaxIndexesPerTable(); MAX_TABLE_NAME_LENGTH = defineMaxTableNameLength(); MAX_COLUMN_NAME_LENGTH = defineMaxColumnNameLength(); MAX_INDEX_NAME_LENGTH = defineMaxIndexNameLength(); @@ -502,6 +504,7 @@ public abstract class JetFormat { protected abstract int defineUsageMapTableByteLength(); protected abstract int defineMaxColumnsPerTable(); + protected abstract int defineMaxIndexesPerTable(); protected abstract int defineMaxTableNameLength(); protected abstract int defineMaxColumnNameLength(); protected abstract int defineMaxIndexNameLength(); @@ -710,6 +713,9 @@ public abstract class JetFormat { protected int defineMaxColumnsPerTable() { return 255; } @Override + protected int defineMaxIndexesPerTable() { return 32; } + + @Override protected int defineMaxTableNameLength() { return 64; } @Override @@ -938,6 +944,9 @@ public abstract class JetFormat { @Override protected int defineMaxColumnsPerTable() { return 255; } + + @Override + protected int defineMaxIndexesPerTable() { return 32; } @Override protected int defineMaxTableNameLength() { return 64; } diff --git a/src/main/java/com/healthmarketscience/jackcess/impl/TableCreator.java b/src/main/java/com/healthmarketscience/jackcess/impl/TableCreator.java index 8828ac2..c720654 100644 --- a/src/main/java/com/healthmarketscience/jackcess/impl/TableCreator.java +++ b/src/main/java/com/healthmarketscience/jackcess/impl/TableCreator.java @@ -231,11 +231,18 @@ class TableCreator } if(hasIndexes()) { + + if(_indexes.size() > getFormat().MAX_INDEXES_PER_TABLE) { + throw new IllegalArgumentException( + "Cannot create table with more than " + + getFormat().MAX_INDEXES_PER_TABLE + " indexes"); + } + // now, validate the indexes Set<String> idxNames = new HashSet<String>(); boolean foundPk = false; for(IndexBuilder index : _indexes) { - index.validate(colNames); + index.validate(colNames, getFormat()); if(!idxNames.add(index.getName().toUpperCase())) { throw new IllegalArgumentException("duplicate index name: " + index.getName()); diff --git a/src/main/java/com/healthmarketscience/jackcess/util/ImportUtil.java b/src/main/java/com/healthmarketscience/jackcess/util/ImportUtil.java index ebeb480..4899d38 100644 --- a/src/main/java/com/healthmarketscience/jackcess/util/ImportUtil.java +++ b/src/main/java/com/healthmarketscience/jackcess/util/ImportUtil.java @@ -47,6 +47,7 @@ import com.healthmarketscience.jackcess.Database; import com.healthmarketscience.jackcess.Table; import com.healthmarketscience.jackcess.TableBuilder; import com.healthmarketscience.jackcess.impl.ByteUtil; +import com.healthmarketscience.jackcess.impl.DatabaseImpl; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; @@ -451,7 +452,7 @@ public class ImportUtil throws IOException { String line = in.readLine(); - if (line == null || line.trim().length() == 0) { + if(DatabaseImpl.isBlank(line)) { return null; } |