1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package com.healthmarketscience.jackcess.impl;
18
19 import java.io.IOException;
20 import java.time.LocalDateTime;
21 import java.util.Date;
22 import java.util.HashMap;
23 import java.util.Iterator;
24 import java.util.LinkedHashMap;
25 import java.util.Map;
26
27 import com.healthmarketscience.jackcess.DataType;
28 import com.healthmarketscience.jackcess.PropertyMap;
29
30
31
32
33
34
35 public class PropertyMapImpl implements PropertyMap
36 {
37
38
39
40 static final byte DDL_FLAG = (byte)0x01;
41
42
43
44
45 static final byte SKIP_HANDLER_FLAG = (byte)0x80;
46
47
48 private static final Map<String,PropDef> DEFAULT_TYPES =
49 new HashMap<>();
50
51 static {
52
53 addDefault(ACCESS_VERSION_PROP, DataType.TEXT, false);
54 addDefault(BUILD_PROP, DataType.LONG, false);
55 addDefault(PROJ_VER_PROP, DataType.INT, false);
56 addDefault(HAS_OFFLINE_LISTS_PROP, DataType.INT, false);
57 addDefault(ANSI_QUERY_MODE_PROP, DataType.LONG, true);
58 addDefault(AUTO_COMPACT_PROP, DataType.LONG, true);
59 addDefault(TRACK_NAME_AUTO_CORRECT_PROP, DataType.LONG, true);
60 addDefault(PERFORM_NAME_AUTO_CORRECT_PROP, DataType.LONG, true);
61 addDefault(CHECK_TRUNCATED_NUM_FIELDS_PROP, DataType.LONG, true);
62 addDefault(PICTURE_STORAGE_FORMAT_PROP, DataType.LONG, true);
63 addDefault(THEME_RESOURCE_NAME_PROP, DataType.TEXT, true);
64 addDefault(THEMED_FORM_CONTROLS_PROP, DataType.LONG, false);
65 addDefault(SHOW_DOCUMENT_TABS_PROP, DataType.BOOLEAN, true);
66 addDefault(USE_MDI_MODE_PROP, DataType.BYTE, true);
67 addDefault(WEB_DESIGN_MODE_PROP, DataType.BYTE, true);
68 addDefault(DESIGN_WITH_DATA_PROP, DataType.BOOLEAN, true);
69 addDefault(ALLOW_BUILT_IN_TOOLBARS_PROP, DataType.BOOLEAN, true);
70 addDefault(ALLOW_DATASHEET_SCHEMA_PROP, DataType.BOOLEAN, true);
71 addDefault(ALLOW_FULL_MENUS_PROP, DataType.BOOLEAN, true);
72 addDefault(ALLOW_SHORTCUT_MENUS_PROP, DataType.BOOLEAN, true);
73 addDefault(ALLOW_SPECIAL_KEYS_PROP, DataType.BOOLEAN, true);
74 addDefault(ALLOW_TOOLBAR_CHANGES_PROP, DataType.BOOLEAN, true);
75 addDefault(START_UP_SHOW_DB_WINDOW_PROP, DataType.BOOLEAN, true);
76 addDefault(START_UP_SHOW_STATUS_BAR_PROP, DataType.BOOLEAN, true);
77 addDefault(USE_APP_ICON_FOR_FRM_RPT_PROP, DataType.BOOLEAN, true);
78 addDefault(NAV_PANE_CATEGORY_PROP, DataType.LONG, true);
79 addDefault(NAV_PANE_CLOSED_PROP, DataType.LONG, true);
80 addDefault(NAV_PANE_SORT_BY_PROP, DataType.LONG, true);
81 addDefault(NAV_PANE_VIEW_BY_PROP, DataType.LONG, true);
82 addDefault(NAV_PANE_WIDTH_PROP, DataType.LONG, true);
83 addDefault(NAV_PANE_SEARCH_BAR_PROP, DataType.LONG, true);
84 addDefault(SHOW_VALUES_LIMIT_PROP, DataType.LONG, true);
85 addDefault(SHOW_VALUES_IN_INDEXED_PROP, DataType.LONG, true);
86 addDefault(SHOW_VALUES_IN_NON_INDEXED_PROP, DataType.LONG, true);
87 addDefault(SHOW_VALUES_IN_REMOTE_PROP, DataType.LONG, true);
88 addDefault(REPLICATE_PROJECT_PROP, DataType.BOOLEAN, false);
89 addDefault(TITLE_PROP, DataType.TEXT, false);
90 addDefault(AUTHOR_PROP, DataType.TEXT, false);
91 addDefault(COMPANY_PROP, DataType.TEXT, false);
92
93
94 addDefault(DEFAULT_VALUE_PROP, DataType.MEMO, true);
95 addDefault(REQUIRED_PROP, DataType.BOOLEAN, true);
96 addDefault(ALLOW_ZERO_LEN_PROP, DataType.BOOLEAN, true);
97 addDefault(DECIMAL_PLACES_PROP, DataType.BYTE, true);
98 addDefault(FORMAT_PROP, DataType.TEXT, true);
99 addDefault(INPUT_MASK_PROP, DataType.TEXT, true);
100 addDefault(CAPTION_PROP, DataType.MEMO, true);
101 addDefault(VALIDATION_RULE_PROP, DataType.TEXT, true);
102 addDefault(VALIDATION_TEXT_PROP, DataType.TEXT, true);
103 addDefault(GUID_PROP, DataType.BINARY, true);
104 addDefault(DESCRIPTION_PROP, DataType.TEXT, true);
105 addDefault(RESULT_TYPE_PROP, DataType.BYTE, true);
106 addDefault(EXPRESSION_PROP, DataType.MEMO, true);
107 addDefault(ALLOW_MULTI_VALUE_PROP, DataType.BOOLEAN, true);
108 addDefault(ROW_SOURCE_TYPE_PROP, DataType.TEXT, true);
109 addDefault(ROW_SOURCE_PROP, DataType.MEMO, true);
110 addDefault(BOUND_COLUMN_PROP, DataType.INT, true);
111 addDefault(COLUMN_COUNT_PROP, DataType.INT, true);
112 addDefault(COLUMN_WIDTHS_PROP, DataType.TEXT, true);
113 addDefault(LIMIT_TO_LIST_PROP, DataType.BOOLEAN, true);
114 addDefault(DISPLAY_CONTROL_PROP, DataType.INT, true);
115 addDefault(TEXT_FORMAT_PROP, DataType.BYTE, true);
116 addDefault(IME_MODE_PROP, DataType.BYTE, true);
117 addDefault(IME_SENTENCE_MODE_PROP, DataType.BYTE, true);
118 addDefault(UNICODE_COMPRESSION_PROP, DataType.BOOLEAN, true);
119 addDefault(APPEND_ONLY_PROP, DataType.BOOLEAN, true);
120 addDefault(TEXT_ALIGN_PROP, DataType.BYTE, false);
121 addDefault(AGGREGATE_TYPE_PROP, DataType.LONG, false);
122 addDefault(CURRENCY_LCID_PROP, DataType.LONG, false);
123 addDefault(COLUMN_HIDDEN_PROP, DataType.BOOLEAN, false);
124 addDefault(COLUMN_ORDER_PROP, DataType.INT, false);
125 addDefault(COLUMN_WIDTH_PROP, DataType.INT, false);
126
127
128 addDefault(NAME_MAP_PROP, DataType.OLE, false);
129 addDefault(DEFAULT_VIEW_PROP, DataType.BYTE, false);
130 addDefault(ORIENTATION_PROP, DataType.BYTE, true);
131 addDefault(ORDER_BY_ON_PROP, DataType.BOOLEAN, false);
132 addDefault(ORDER_BY_ON_LOAD_PROP, DataType.BOOLEAN, false);
133 addDefault(FILTER_ON_LOAD_PROP, DataType.BOOLEAN, false);
134 addDefault(TOTALS_ROW_PROP, DataType.BOOLEAN, false);
135 addDefault(HIDE_NEW_FIELD_PROP, DataType.BOOLEAN, false);
136 addDefault(PUBLISH_TO_WEB_PROP, DataType.BYTE, false);
137 addDefault(READ_ONLY_WHEN_DISCONNECTED_PROP, DataType.BOOLEAN, false);
138 addDefault(DISPLAY_VIEWS_ON_SHAREPOINT_PROP, DataType.BYTE, false);
139 addDefault(BACK_TINT_PROP, DataType.FLOAT, false);
140 addDefault(BACK_SHADE_PROP, DataType.FLOAT, false);
141 addDefault(ALTERNATE_BACK_TINT_PROP, DataType.FLOAT, false);
142 addDefault(ALTERNATE_BACK_SHADE_PROP, DataType.FLOAT, false);
143 addDefault(ALTERNATE_BACK_THEME_COLOR_INDEX_PROP, DataType.LONG, false);
144 addDefault(DATASHEET_FORE_THEME_COLOR_INDEX_PROP, DataType.LONG, false);
145 addDefault(DATASHEET_GRIDLINES_THEME_COLOR_INDEX_PROP, DataType.LONG, false);
146 addDefault(THEME_FONT_INDEX_PROP, DataType.LONG, false);
147 addDefault(QUERY_NAME_MAP_PROP, DataType.OLE, false);
148 addDefault(ODBC_TIMEOUT_PROP, DataType.INT, true);
149 addDefault(RECORD_LOCKS_PROP, DataType.BYTE, true);
150 addDefault(RECORDSET_TYPE_PROP, DataType.BYTE, true);
151 addDefault(USE_TRANSACTION_PROP, DataType.BOOLEAN, true);
152 addDefault(FAIL_ON_ERROR_PROP, DataType.BOOLEAN, true);
153 addDefault(LOG_MESSAGES_PROP, DataType.BOOLEAN, true);
154 }
155
156 private static void addDefault(String name, DataType type, boolean isDdl) {
157 DEFAULT_TYPES.put(name, new PropDef(type, isDdl));
158 }
159
160 private final String _mapName;
161 private final short _mapType;
162 private final Map<String,Property> _props =
163 new LinkedHashMap<>();
164 private final PropertyMaps _owner;
165
166 public PropertyMapImpl(String name, short type, PropertyMaps owner) {
167 _mapName = name;
168 _mapType = type;
169 _owner = owner;
170 }
171
172 @Override
173 public String getName() {
174 return _mapName;
175 }
176
177 public short getType() {
178 return _mapType;
179 }
180
181 public PropertyMaps getOwner() {
182 return _owner;
183 }
184
185 @Override
186 public int getSize() {
187 return _props.size();
188 }
189
190 @Override
191 public boolean isEmpty() {
192 return _props.isEmpty();
193 }
194
195 @Override
196 public Property get(String name) {
197 return _props.get(DatabaseImpl.toLookupName(name));
198 }
199
200 @Override
201 public Object getValue(String name) {
202 return getValue(name, null);
203 }
204
205 @Override
206 public Object getValue(String name, Object defaultValue) {
207 Property prop = get(name);
208 Object value = defaultValue;
209 if((prop != null) && (prop.getValue() != null)) {
210 value = prop.getValue();
211 }
212 return value;
213 }
214
215 @Override
216 public PropertyImpl put(String name, Object value) {
217 return put(name, null, value, false);
218 }
219
220 @Override
221 public PropertyImpl put(String name, DataType type, Object value) {
222 return put(name, type, value, false);
223 }
224
225 @Override
226 public void putAll(Iterable<? extends Property> props) {
227 if(props == null) {
228 return;
229 }
230
231 for(Property prop : props) {
232 put(prop);
233 }
234 }
235
236 public PropertyImpl put(Property prop) {
237 if(prop instanceof PropertyImpl) {
238
239
240 PropertyImpl propImpl = (PropertyImpl)prop;
241 return putStored(propImpl.getName(), propImpl.getType(),
242 propImpl.getValue(), propImpl.getFlags());
243 }
244 return put(prop.getName(), prop.getType(), prop.getValue(),
245 toFlags(prop.isDdl(), prop.isSkipHandler()));
246 }
247
248
249
250
251 @Override
252 public PropertyImpl put(String name, DataType type, Object value,
253 boolean isDdl) {
254 return put(name, type, value, toFlags(isDdl, false));
255 }
256
257 @Override
258 public PropertyImpl put(String name, DataType type, Object value,
259 boolean isDdl, boolean isSkipHandler) {
260 return put(name, type, value, toFlags(isDdl, isSkipHandler));
261 }
262
263
264
265
266
267 PropertyImpl put(String name, DataType type, Object value, byte flags) {
268 PropertyImpl prop = (PropertyImpl)createProperty(name, type, value, flags);
269 _props.put(DatabaseImpl.toLookupName(name), prop);
270 return prop;
271 }
272
273
274
275
276
277 PropertyImpl putStored(String name, DataType type, Object value,
278 byte flags) {
279 PropertyImpl prop = new PropertyImpl(name, type, value, flags);
280 _props.put(DatabaseImpl.toLookupName(name), prop);
281 return prop;
282 }
283
284 @Override
285 public PropertyImpl remove(String name) {
286 return (PropertyImpl)_props.remove(DatabaseImpl.toLookupName(name));
287 }
288
289 @Override
290 public Iterator<Property> iterator() {
291 return _props.values().iterator();
292 }
293
294 @Override
295 public void save() throws IOException {
296 getOwner().save();
297 }
298
299 @Override
300 public String toString() {
301 return toString(this);
302 }
303
304 public static String toString(PropertyMap map) {
305 StringBuilder sb = new StringBuilder();
306 sb.append(PropertyMaps.DEFAULT_NAME.equals(map.getName()) ?
307 "<DEFAULT>" : map.getName())
308 .append(" {");
309 for(Iterator<Property> iter = map.iterator(); iter.hasNext(); ) {
310 sb.append(iter.next());
311 if(iter.hasNext()) {
312 sb.append(",");
313 }
314 }
315 sb.append("}");
316 return sb.toString();
317 }
318
319 public static Property createProperty(String name, DataType type, Object value) {
320 return createProperty(name, type, value, false);
321 }
322
323 public static Property createProperty(String name, DataType type,
324 Object value, boolean isDdl) {
325 return createProperty(name, type, value, toFlags(isDdl, false));
326 }
327
328 public static Property createProperty(String name, DataType type,
329 Object value, boolean isDdl,
330 boolean isSkipHandler) {
331 return createProperty(name, type, value, toFlags(isDdl, isSkipHandler));
332 }
333
334 static Property createProperty(String name, DataType type,
335 Object value, byte flags) {
336
337 PropDef pd = DEFAULT_TYPES.get(name);
338
339 if(value instanceof PropertyMap.EnumValue) {
340
341 value = ((PropertyMap.EnumValue)value).getValue();
342 }
343
344 if(pd != null) {
345
346 type = ((type == null) ? pd._type : type);
347 if(pd._isDdl) {
348 flags |= DDL_FLAG;
349 }
350 } else if(type == null) {
351
352 if(value instanceof String) {
353 type = DataType.TEXT;
354 } else if(value instanceof Boolean) {
355 type = DataType.BOOLEAN;
356 } else if(value instanceof Byte) {
357 type = DataType.BYTE;
358 } else if(value instanceof Short) {
359 type = DataType.INT;
360 } else if(value instanceof Integer) {
361 type = DataType.LONG;
362 } else if(value instanceof Float) {
363 type = DataType.FLOAT;
364 } else if(value instanceof Double) {
365 type = DataType.DOUBLE;
366 } else if((value instanceof Date) || (value instanceof LocalDateTime)) {
367 type = DataType.SHORT_DATE_TIME;
368 } else if(value instanceof byte[]) {
369 type = DataType.OLE;
370 } else if(value instanceof Long) {
371 type = DataType.BIG_INT;
372 } else {
373 throw new IllegalArgumentException(
374 "Could not determine type for property " + name +
375 " with value " + value);
376 }
377 }
378
379 return new PropertyImpl(name, type, value, flags);
380 }
381
382 private static byte toFlags(boolean isDdl, boolean isSkipHandler) {
383 return (byte)((isDdl ? DDL_FLAG : 0) |
384 (isSkipHandler ? SKIP_HANDLER_FLAG : 0));
385 }
386
387
388
389
390 static final class PropertyImpl implements PropertyMap.Property
391 {
392 private final String _name;
393 private final DataType _type;
394
395 private final byte _flags;
396 private Object _value;
397
398 private PropertyImpl(String name, DataType type, Object value,
399 byte flags) {
400 _name = name;
401 _type = type;
402 _flags = flags;
403 _value = value;
404 }
405
406 @Override
407 public String getName() {
408 return _name;
409 }
410
411 @Override
412 public DataType getType() {
413 return _type;
414 }
415
416 @Override
417 public Object getValue() {
418 return _value;
419 }
420
421 @Override
422 public void setValue(Object newValue) {
423 _value = newValue;
424 }
425
426 @Override
427 public boolean isDdl() {
428 return ((_flags & DDL_FLAG) != 0);
429 }
430
431 @Override
432 public boolean isSkipHandler() {
433 return ((_flags & SKIP_HANDLER_FLAG) != 0);
434 }
435
436
437
438
439
440
441 byte getFlags() {
442 return _flags;
443 }
444
445 @Override
446 public String toString() {
447 Object val = getValue();
448 if(val instanceof byte[]) {
449 val = ByteUtil.toHexString((byte[])val);
450 }
451 String flagStr = (isDdl() ? ":ddl" : "") +
452 (isSkipHandler() ? ":nohandler" : "");
453 return getName() + "[" + getType() + flagStr + "]=" + val;
454 }
455 }
456
457
458
459
460 private static final class PropDef
461 {
462 private final DataType _type;
463 private final boolean _isDdl;
464
465 private PropDef(DataType type, boolean isDdl) {
466 _type = type;
467 _isDdl = isDdl;
468 }
469 }
470 }