|
|
@@ -30,9 +30,8 @@ package com.healthmarketscience.jackcess; |
|
|
|
import java.io.File; |
|
|
|
import java.lang.reflect.Field; |
|
|
|
import java.nio.ByteBuffer; |
|
|
|
import java.util.ArrayList; |
|
|
|
import java.util.Arrays; |
|
|
|
import java.util.HashMap; |
|
|
|
import java.util.List; |
|
|
|
import java.util.Map; |
|
|
|
import java.util.TreeMap; |
|
|
|
import java.util.regex.Matcher; |
|
|
@@ -96,7 +95,8 @@ public class IndexCodesTest extends TestCase { |
|
|
|
} finally { |
|
|
|
if(!success) { |
|
|
|
System.out.println("CurPos: " + curPos); |
|
|
|
System.out.println("Value: " + row); |
|
|
|
System.out.println("Value: " + row + ": " + |
|
|
|
toUnicodeStr(row.get("data"))); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
@@ -171,6 +171,118 @@ public class IndexCodesTest extends TestCase { |
|
|
|
db.close(); |
|
|
|
} |
|
|
|
|
|
|
|
public void x_testWriteAllCodesMdb() throws Exception |
|
|
|
{ |
|
|
|
Database db = create(true); |
|
|
|
|
|
|
|
// Table t = new TableBuilder("Table1") |
|
|
|
// .addColumn(new ColumnBuilder("key", DataType.TEXT).toColumn()) |
|
|
|
// .addColumn(new ColumnBuilder("data", DataType.TEXT).toColumn()) |
|
|
|
// .toTable(db); |
|
|
|
|
|
|
|
// for(int i = 0; i <= 0xFFFF; ++i) { |
|
|
|
// // skip non-char chars |
|
|
|
// char c = (char)i; |
|
|
|
// if(Character.isHighSurrogate(c) || Character.isLowSurrogate(c)) { |
|
|
|
// continue; |
|
|
|
// } |
|
|
|
// String key = toUnicodeStr(c); |
|
|
|
// String str = "AA" + c + "AA"; |
|
|
|
// t.addRow(key, str); |
|
|
|
// } |
|
|
|
|
|
|
|
Table t = new TableBuilder("Table5") |
|
|
|
.addColumn(new ColumnBuilder("name", DataType.TEXT).toColumn()) |
|
|
|
.addColumn(new ColumnBuilder("data", DataType.TEXT).toColumn()) |
|
|
|
.toTable(db); |
|
|
|
|
|
|
|
char c = (char)0x3041; // crazy 7F 02 ... A0 |
|
|
|
char c2 = (char)0x30A2; // crazy 7F 02 ... |
|
|
|
char c3 = (char)0x2045; // inat 27 ... 1C |
|
|
|
char c4 = (char)0x3043; // crazy 7F 03 ... A0 |
|
|
|
char c5 = (char)0x3046; // crazy 7F 04 ... |
|
|
|
char c6 = (char)0x30F6; // crazy 7F 0D ... A0 |
|
|
|
char c7 = (char)0x3099; // unprint 03 |
|
|
|
char c8 = (char)0x0041; // A |
|
|
|
char c9 = (char)0x002D; // - (unprint) |
|
|
|
char c10 = (char)0x20E1; // unprint F2 |
|
|
|
char c11 = (char)0x309A; // unprint 04 |
|
|
|
char c12 = (char)0x01C4; // (long extra) |
|
|
|
char c13 = (char)0x005F; // _ (long inline) |
|
|
|
char c14 = (char)0xFFFE; // removed |
|
|
|
|
|
|
|
char[] cs = new char[]{c7, c8, c3, c12, c13, c14, c, c2, c9}; |
|
|
|
addCombos(t, 0, "", cs, 5); |
|
|
|
|
|
|
|
// t = new TableBuilder("Table2") |
|
|
|
// .addColumn(new ColumnBuilder("data", DataType.TEXT).toColumn()) |
|
|
|
// .toTable(db); |
|
|
|
|
|
|
|
// writeChars(0x0000, t); |
|
|
|
|
|
|
|
// t = new TableBuilder("Table3") |
|
|
|
// .addColumn(new ColumnBuilder("data", DataType.TEXT).toColumn()) |
|
|
|
// .toTable(db); |
|
|
|
|
|
|
|
// writeChars(0x0400, t); |
|
|
|
|
|
|
|
|
|
|
|
db.close(); |
|
|
|
} |
|
|
|
|
|
|
|
public void x_testReadAllCodesMdb() throws Exception |
|
|
|
{ |
|
|
|
// Database db = openCopy(new File("/data2/jackcess_test/testAllIndexCodes.mdb")); |
|
|
|
// Database db = openCopy(new File("/data2/jackcess_test/testAllIndexCodes_orig.mdb")); |
|
|
|
// Database db = openCopy(new File("/data2/jackcess_test/testSomeMoreCodes.mdb")); |
|
|
|
Database db = openCopy(new File("/data2/jackcess_test/testStillMoreCodes.mdb")); |
|
|
|
Table t = db.getTable("Table5"); |
|
|
|
|
|
|
|
Index ind = t.getIndexes().iterator().next(); |
|
|
|
ind.initialize(); |
|
|
|
|
|
|
|
System.out.println("Ind " + ind); |
|
|
|
|
|
|
|
Cursor cursor = Cursor.createIndexCursor(t, ind); |
|
|
|
while(cursor.moveToNextRow()) { |
|
|
|
System.out.println("======="); |
|
|
|
String entryStr = |
|
|
|
entryToString(cursor.getSavepoint().getCurrentPosition()); |
|
|
|
System.out.println("Entry Bytes: " + entryStr); |
|
|
|
System.out.println("Value: " + cursor.getCurrentRow() + "; " + |
|
|
|
toUnicodeStr(cursor.getCurrentRow().get("data"))); |
|
|
|
} |
|
|
|
|
|
|
|
db.close(); |
|
|
|
} |
|
|
|
|
|
|
|
private int addCombos(Table t, int rowNum, String s, char[] cs, int len) |
|
|
|
throws Exception |
|
|
|
{ |
|
|
|
if(s.length() >= len) { |
|
|
|
return rowNum; |
|
|
|
} |
|
|
|
|
|
|
|
for(int i = 0; i < cs.length; ++i) { |
|
|
|
String name = "row" + (rowNum++); |
|
|
|
String ss = s + cs[i]; |
|
|
|
t.addRow(name, ss); |
|
|
|
rowNum = addCombos(t, rowNum, ss, cs, len); |
|
|
|
} |
|
|
|
|
|
|
|
return rowNum; |
|
|
|
} |
|
|
|
|
|
|
|
private void writeChars(int hibyte, Table t) throws Exception |
|
|
|
{ |
|
|
|
char other = (char)(hibyte | 0x41); |
|
|
|
for(int i = 0; i < 0xFF; ++i) { |
|
|
|
char c = (char)(hibyte | i); |
|
|
|
String str = "" + other + c + other; |
|
|
|
t.addRow(str); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
public void x_testReadIsoMdb() throws Exception |
|
|
|
{ |
|
|
|
// Database db = open(new File("/tmp/test_ind.mdb")); |
|
|
@@ -195,25 +307,28 @@ public class IndexCodesTest extends TestCase { |
|
|
|
|
|
|
|
public void x_testReverseIsoMdb() throws Exception |
|
|
|
{ |
|
|
|
// Database db = open(new File("/tmp/test_ind.mdb")); |
|
|
|
Database db = open(new File("/tmp/test_ind2.mdb")); |
|
|
|
// Database db = open(new File("/tmp/databaseTest14366_ind.mdb")); |
|
|
|
// Database db = open(new File("/tmp/databaseTest56165_ind.mdb")); |
|
|
|
// Database db = open(new File("/tmp/databaseTest53970_ind.mdb")); |
|
|
|
Database db = open(new File("/data2/jackcess_test/testAllIndexCodes3.mdb")); |
|
|
|
|
|
|
|
Table t = db.getTable("Table1"); |
|
|
|
Index index = t.getIndex("B"); |
|
|
|
Index index = t.getIndexes().iterator().next(); |
|
|
|
index.initialize(); |
|
|
|
System.out.println("Ind " + index); |
|
|
|
|
|
|
|
Pattern inlinePat = Pattern.compile("7F 4A 4A (.*)4A 4A 01 00"); |
|
|
|
Pattern unprintPat = Pattern.compile("01 01 01 80 (.+) 06 (.+) 00"); |
|
|
|
Pattern unprint2Pat = Pattern.compile("4A 4A 4A 4A 01 02 (.+) 00"); |
|
|
|
Pattern inatPat = Pattern.compile("7F 4A 4A (.*)4A 4A 01 02 02 (.+) 00"); |
|
|
|
Pattern inat2Pat = Pattern.compile("7F 4A 4A (.*)4A 4A 01 (02 02 (.+))?01 01 (.*)FF 02 80 FF 80 00"); |
|
|
|
|
|
|
|
Map<Character,String[]> inlineCodes = new TreeMap<Character,String[]>(); |
|
|
|
Map<Character,String[]> unprintCodes = new TreeMap<Character,String[]>(); |
|
|
|
Map<Character,String[]> unprint2Codes = new TreeMap<Character,String[]>(); |
|
|
|
Map<Character,String[]> inatInlineCodes = new TreeMap<Character,String[]>(); |
|
|
|
Map<Character,String[]> inatExtraCodes = new TreeMap<Character,String[]>(); |
|
|
|
Map<Character,String[]> inat2Codes = new TreeMap<Character,String[]>(); |
|
|
|
Map<Character,String[]> inat2ExtraCodes = new TreeMap<Character,String[]>(); |
|
|
|
Map<Character,String[]> inat2CrazyCodes = new TreeMap<Character,String[]>(); |
|
|
|
|
|
|
|
|
|
|
|
Cursor cursor = Cursor.createIndexCursor(t, index); |
|
|
|
while(cursor.moveToNextRow()) { |
|
|
@@ -224,14 +339,15 @@ public class IndexCodesTest extends TestCase { |
|
|
|
String entryStr = entryToString(savepoint.getCurrentPosition()); |
|
|
|
|
|
|
|
Map<String,Object> row = cursor.getCurrentRow(); |
|
|
|
String value = (String)row.get("B"); |
|
|
|
String value = (String)row.get("data"); |
|
|
|
String key = (String)row.get("key"); |
|
|
|
char c = value.charAt(2); |
|
|
|
System.out.println("======="); |
|
|
|
System.out.println("RowId: " + |
|
|
|
savepoint.getCurrentPosition().getRowId()); |
|
|
|
System.out.println("Entry: " + entryStr); |
|
|
|
// System.out.println("Row: " + row); |
|
|
|
System.out.println("Value: " + value); |
|
|
|
System.out.println("Value: (" + key + ")" + value); |
|
|
|
System.out.println("Char: " + c + ", " + (int)c + ", " + |
|
|
|
toUnicodeStr(c)); |
|
|
|
|
|
|
@@ -244,7 +360,7 @@ public class IndexCodesTest extends TestCase { |
|
|
|
m.find(); |
|
|
|
handleInlineEntry(m.group(1), c, inlineCodes); |
|
|
|
|
|
|
|
} else if(entryStr.contains("01 01 01")) { |
|
|
|
} else if(entryStr.contains("01 01 01 80")) { |
|
|
|
|
|
|
|
// handle most unprintable codes |
|
|
|
type = "UNPRINTABLE"; |
|
|
@@ -252,7 +368,8 @@ public class IndexCodesTest extends TestCase { |
|
|
|
m.find(); |
|
|
|
handleUnprintableEntry(m.group(2), c, unprintCodes); |
|
|
|
|
|
|
|
} else if(entryStr.contains("01 02 02")) { |
|
|
|
} else if(entryStr.contains("01 02 02") && |
|
|
|
!entryStr.contains("FF 02 80 FF 80")) { |
|
|
|
|
|
|
|
// handle chars w/ symbols |
|
|
|
type = "CHAR_WITH_SYMBOL"; |
|
|
@@ -261,6 +378,23 @@ public class IndexCodesTest extends TestCase { |
|
|
|
handleInternationalEntry(m.group(1), m.group(2), c, |
|
|
|
inatInlineCodes, inatExtraCodes); |
|
|
|
|
|
|
|
} else if(entryStr.contains("4A 4A 4A 4A 01 02")) { |
|
|
|
|
|
|
|
// handle chars w/ symbols |
|
|
|
type = "UNPRINTABLE_2"; |
|
|
|
Matcher m = unprint2Pat.matcher(entryStr); |
|
|
|
m.find(); |
|
|
|
handleUnprintable2Entry(m.group(1), c, unprint2Codes); |
|
|
|
|
|
|
|
} else if(entryStr.contains("FF 02 80 FF 80")) { |
|
|
|
|
|
|
|
type = "CRAZY_INAT"; |
|
|
|
Matcher m = inat2Pat.matcher(entryStr); |
|
|
|
m.find(); |
|
|
|
handleInternational2Entry(m.group(1), m.group(3), m.group(4), c, |
|
|
|
inat2Codes, inat2ExtraCodes, |
|
|
|
inat2CrazyCodes); |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
throw new RuntimeException("unhandled " + entryStr); |
|
|
@@ -269,52 +403,94 @@ public class IndexCodesTest extends TestCase { |
|
|
|
System.out.println("Type: " + type); |
|
|
|
} |
|
|
|
|
|
|
|
// System.out.println("Normal " + inlineCodes); |
|
|
|
// System.out.println("Unprintable " + unprintCodes); |
|
|
|
// System.out.println("International " + inatCodes); |
|
|
|
System.out.println("\n***INLINE"); |
|
|
|
for(Map.Entry<Character,String[]> e : inlineCodes.entrySet()) { |
|
|
|
System.out.println( |
|
|
|
generateCodeString("registerCodes", e.getKey(), e.getValue(), |
|
|
|
null)); |
|
|
|
} |
|
|
|
System.out.println("\n***UNPRINTABLE"); |
|
|
|
for(Map.Entry<Character,String[]> e : unprintCodes.entrySet()) { |
|
|
|
System.out.println( |
|
|
|
generateCodeString("registerUnprintableCodes", |
|
|
|
e.getKey(), e.getValue(), null)); |
|
|
|
} |
|
|
|
System.out.println("\n***INTERNATIONAL"); |
|
|
|
for(Map.Entry<Character,String[]> e : inatInlineCodes.entrySet()) { |
|
|
|
|
|
|
|
System.out.println( |
|
|
|
generateCodeString("registerInternationalCodes", |
|
|
|
e.getKey(), e.getValue(), |
|
|
|
inatExtraCodes.get(e.getKey()))); |
|
|
|
System.out.println("\n***CODES"); |
|
|
|
for(int i = 0; i <= 0xFFFF; ++i) { |
|
|
|
|
|
|
|
if(i == 256) { |
|
|
|
System.out.println("\n***EXTENDED CODES"); |
|
|
|
} |
|
|
|
|
|
|
|
// skip non-char chars |
|
|
|
char c = (char)i; |
|
|
|
if(Character.isHighSurrogate(c) || Character.isLowSurrogate(c)) { |
|
|
|
continue; |
|
|
|
} |
|
|
|
|
|
|
|
if(c == (char)0xFFFE) { |
|
|
|
// this gets replaced with FFFD, treat it the same |
|
|
|
c = (char)0xFFFD; |
|
|
|
} |
|
|
|
|
|
|
|
Character cc = c; |
|
|
|
String[] chars = inlineCodes.get(cc); |
|
|
|
if(chars != null) { |
|
|
|
if((chars.length == 1) && (chars[0].length() == 0)) { |
|
|
|
System.out.println("X"); |
|
|
|
} else { |
|
|
|
System.out.println("S" + toByteString(chars)); |
|
|
|
} |
|
|
|
continue; |
|
|
|
} |
|
|
|
|
|
|
|
chars = inatInlineCodes.get(cc); |
|
|
|
if(chars != null) { |
|
|
|
String[] extra = inatExtraCodes.get(cc); |
|
|
|
System.out.println("I" + toByteString(chars) + "," + |
|
|
|
toByteString(extra)); |
|
|
|
continue; |
|
|
|
} |
|
|
|
|
|
|
|
chars = unprintCodes.get(cc); |
|
|
|
if(chars != null) { |
|
|
|
System.out.println("U" + toByteString(chars)); |
|
|
|
continue; |
|
|
|
} |
|
|
|
|
|
|
|
chars = unprint2Codes.get(cc); |
|
|
|
if(chars != null) { |
|
|
|
if(chars.length > 1) { |
|
|
|
throw new RuntimeException("long unprint codes"); |
|
|
|
} |
|
|
|
int val = Integer.parseInt(chars[0], 16) - 2; |
|
|
|
String valStr = ByteUtil.toHexString(new byte[]{(byte)val}).trim(); |
|
|
|
System.out.println("P" + valStr); |
|
|
|
continue; |
|
|
|
} |
|
|
|
|
|
|
|
chars = inat2Codes.get(cc); |
|
|
|
if(chars != null) { |
|
|
|
String [] crazyCodes = inat2CrazyCodes.get(cc); |
|
|
|
String crazyCode = ""; |
|
|
|
if(crazyCodes != null) { |
|
|
|
if((crazyCodes.length != 1) || !"A0".equals(crazyCodes[0])) { |
|
|
|
throw new RuntimeException("CC " + Arrays.asList(crazyCodes)); |
|
|
|
} |
|
|
|
crazyCode = "1"; |
|
|
|
} |
|
|
|
|
|
|
|
String[] extra = inat2ExtraCodes.get(cc); |
|
|
|
System.out.println("Z" + toByteString(chars) + "," + |
|
|
|
toByteString(extra) + "," + |
|
|
|
crazyCode); |
|
|
|
continue; |
|
|
|
} |
|
|
|
|
|
|
|
throw new RuntimeException("Unhandled char " + toUnicodeStr(c)); |
|
|
|
} |
|
|
|
System.out.println("\n***END CODES"); |
|
|
|
|
|
|
|
db.close(); |
|
|
|
} |
|
|
|
|
|
|
|
private static String generateCodeString(String methodName, |
|
|
|
char c, |
|
|
|
String[] charStrs1, |
|
|
|
String[] charStrs2) |
|
|
|
private static String toByteString(String[] chars) |
|
|
|
{ |
|
|
|
StringBuilder builder = new StringBuilder() |
|
|
|
.append(methodName).append("('").append(toUnicodeStr(c)) |
|
|
|
.append("', new byte[]{") |
|
|
|
.append(join(charStrs1, ", ", "(byte)0x")) |
|
|
|
.append("}"); |
|
|
|
if(charStrs2 != null) { |
|
|
|
builder.append(",\nnew byte[]{") |
|
|
|
.append(join(charStrs2, ", ", "(byte)0x")) |
|
|
|
.append("}"); |
|
|
|
String str = join(chars, "", ""); |
|
|
|
if(str.length() > 0 && str.charAt(0) == '0') { |
|
|
|
str = str.substring(1); |
|
|
|
} |
|
|
|
builder.append(");"); |
|
|
|
return builder.toString(); |
|
|
|
return str; |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
private static void handleInlineEntry( |
|
|
|
String entryCodes, char c, Map<Character,String[]> inlineCodes) |
|
|
|
throws Exception |
|
|
@@ -329,6 +505,13 @@ public class IndexCodesTest extends TestCase { |
|
|
|
unprintCodes.put(c, entryCodes.trim().split(" ")); |
|
|
|
} |
|
|
|
|
|
|
|
private static void handleUnprintable2Entry( |
|
|
|
String entryCodes, char c, Map<Character,String[]> unprintCodes) |
|
|
|
throws Exception |
|
|
|
{ |
|
|
|
unprintCodes.put(c, entryCodes.trim().split(" ")); |
|
|
|
} |
|
|
|
|
|
|
|
private static void handleInternationalEntry( |
|
|
|
String inlineCodes, String entryCodes, char c, |
|
|
|
Map<Character,String[]> inatInlineCodes, |
|
|
@@ -338,8 +521,32 @@ public class IndexCodesTest extends TestCase { |
|
|
|
inatInlineCodes.put(c, inlineCodes.trim().split(" ")); |
|
|
|
inatExtraCodes.put(c, entryCodes.trim().split(" ")); |
|
|
|
} |
|
|
|
|
|
|
|
private static void handleInternational2Entry( |
|
|
|
String inlineCodes, String entryCodes, String crazyCodes, char c, |
|
|
|
Map<Character,String[]> inatInlineCodes, |
|
|
|
Map<Character,String[]> inatExtraCodes, |
|
|
|
Map<Character,String[]> inatCrazyCodes) |
|
|
|
throws Exception |
|
|
|
{ |
|
|
|
inatInlineCodes.put(c, inlineCodes.trim().split(" ")); |
|
|
|
if(entryCodes != null) { |
|
|
|
inatExtraCodes.put(c, entryCodes.trim().split(" ")); |
|
|
|
} |
|
|
|
if((crazyCodes != null) && (crazyCodes.length() > 0)) { |
|
|
|
inatCrazyCodes.put(c, crazyCodes.trim().split(" ")); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
private static String toUnicodeStr(Object obj) throws Exception { |
|
|
|
StringBuilder sb = new StringBuilder(); |
|
|
|
for(char c : obj.toString().toCharArray()) { |
|
|
|
sb.append(toUnicodeStr(c)).append(" "); |
|
|
|
} |
|
|
|
return sb.toString(); |
|
|
|
} |
|
|
|
|
|
|
|
private static String toUnicodeStr(char c) { |
|
|
|
private static String toUnicodeStr(char c) throws Exception { |
|
|
|
String specialStr = SPECIAL_CHARS.get(c); |
|
|
|
if(specialStr != null) { |
|
|
|
return specialStr; |
|
|
@@ -353,6 +560,9 @@ public class IndexCodesTest extends TestCase { |
|
|
|
} |
|
|
|
|
|
|
|
private static String join(String[] strs, String joinStr, String prefixStr) { |
|
|
|
if(strs == null) { |
|
|
|
return ""; |
|
|
|
} |
|
|
|
StringBuilder builder = new StringBuilder(); |
|
|
|
for(int i = 0; i < strs.length; ++i) { |
|
|
|
if(strs[i].length() == 0) { |