diff options
author | James Ahlborn <jtahlborn@yahoo.com> | 2013-10-11 01:43:24 +0000 |
---|---|---|
committer | James Ahlborn <jtahlborn@yahoo.com> | 2013-10-11 01:43:24 +0000 |
commit | bcbcda7563428dff2820ec142e05a31f342eb293 (patch) | |
tree | 8781839e58ffc52895615cfc6d1d8d42755f6b71 /src/main/java/com/healthmarketscience/jackcess/impl/PropertyMaps.java | |
parent | 1adb6ea69dc29d01e080b059d625a27a8f3e75c0 (diff) | |
download | jackcess-bcbcda7563428dff2820ec142e05a31f342eb293.tar.gz jackcess-bcbcda7563428dff2820ec142e05a31f342eb293.zip |
Add support for modifying properties
git-svn-id: https://svn.code.sf.net/p/jackcess/code/jackcess/trunk@816 f203690c-595d-4dc9-a70b-905162fa7fd2
Diffstat (limited to 'src/main/java/com/healthmarketscience/jackcess/impl/PropertyMaps.java')
-rw-r--r-- | src/main/java/com/healthmarketscience/jackcess/impl/PropertyMaps.java | 171 |
1 files changed, 147 insertions, 24 deletions
diff --git a/src/main/java/com/healthmarketscience/jackcess/impl/PropertyMaps.java b/src/main/java/com/healthmarketscience/jackcess/impl/PropertyMaps.java index b0d5567..b3e345b 100644 --- a/src/main/java/com/healthmarketscience/jackcess/impl/PropertyMaps.java +++ b/src/main/java/com/healthmarketscience/jackcess/impl/PropertyMaps.java @@ -25,11 +25,13 @@ import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import java.util.LinkedHashMap; +import java.util.LinkedHashSet; import java.util.List; import java.util.Map; +import java.util.Set; -import com.healthmarketscience.jackcess.PropertyMap; import com.healthmarketscience.jackcess.DataType; +import com.healthmarketscience.jackcess.PropertyMap; /** * Collection of PropertyMap instances read from a single property data block. @@ -50,9 +52,11 @@ public class PropertyMaps implements Iterable<PropertyMapImpl> private final Map<String,PropertyMapImpl> _maps = new LinkedHashMap<String,PropertyMapImpl>(); private final int _objectId; + private final Handler _handler; - public PropertyMaps(int objectId) { + public PropertyMaps(int objectId, Handler handler) { _objectId = objectId; + _handler = handler; } public int getObjectId() { @@ -91,24 +95,20 @@ public class PropertyMaps implements Iterable<PropertyMapImpl> String lookupName = DatabaseImpl.toLookupName(name); PropertyMapImpl map = _maps.get(lookupName); if(map == null) { - map = new PropertyMapImpl(name, type); + map = new PropertyMapImpl(name, type, this); _maps.put(lookupName, map); } return map; } - /** - * Adds the given PropertyMap to this group. - */ - public void put(PropertyMapImpl map) { - String mapName = DatabaseImpl.toLookupName(map.getName()); - _maps.put(mapName, map.merge(_maps.get(mapName))); - } - public Iterator<PropertyMapImpl> iterator() { return _maps.values().iterator(); } + public byte[] write() throws IOException { + return _handler.write(this); + } + @Override public String toString() { return CustomToStringStyle.builder(this) @@ -138,14 +138,12 @@ public class PropertyMaps implements Iterable<PropertyMapImpl> public PropertyMaps read(byte[] propBytes, int objectId) throws IOException { - - PropertyMaps maps = new PropertyMaps(objectId); + PropertyMaps maps = new PropertyMaps(objectId, this); if((propBytes == null) || (propBytes.length == 0)) { return maps; } - ByteBuffer bb = ByteBuffer.wrap(propBytes) - .order(PageChannel.DEFAULT_BYTE_ORDER); + ByteBuffer bb = PageChannel.wrap(propBytes); // check for known header boolean knownType = false; @@ -176,7 +174,7 @@ public class PropertyMaps implements Iterable<PropertyMapImpl> if(type == PROPERTY_NAME_LIST) { propNames = readPropertyNames(bbBlock); } else { - maps.put(readPropertyValues(bbBlock, propNames, type)); + readPropertyValues(bbBlock, propNames, type, maps); } bb.position(endPos); @@ -186,6 +184,58 @@ public class PropertyMaps implements Iterable<PropertyMapImpl> } /** + * @return a byte[] encoded from the given PropertyMaps instance + */ + public byte[] write(PropertyMaps maps) + throws IOException + { + if(maps == null) { + return null; + } + + ByteArrayBuilder bab = new ByteArrayBuilder(); + + bab.put(_database.getFormat().PROPERTY_MAP_TYPE); + + // grab the property names from all the maps + Set<String> propNames = new LinkedHashSet<String>(); + for(PropertyMapImpl propMap : maps) { + for(PropertyMap.Property prop : propMap) { + propNames.add(prop.getName()); + } + } + + // write the full set of property names + writeBlock(null, propNames, PROPERTY_NAME_LIST, bab); + + // write all the map values + for(PropertyMapImpl propMap : maps) { + writeBlock(propMap, propNames, propMap.getType(), bab); + } + + return bab.toArray(); + } + + private void writeBlock( + PropertyMapImpl propMap, Set<String> propNames, + short blockType, ByteArrayBuilder bab) + throws IOException + { + int blockStartPos = bab.position(); + bab.reserveInt() + .putShort(blockType); + + if(blockType == PROPERTY_NAME_LIST) { + writePropertyNames(propNames, bab); + } else { + writePropertyValues(propMap, propNames, bab); + } + + int len = bab.position() - blockStartPos; + bab.putInt(blockStartPos, len); + } + + /** * @return the property names parsed from the given data chunk */ private List<String> readPropertyNames(ByteBuffer bbBlock) { @@ -196,12 +246,20 @@ public class PropertyMaps implements Iterable<PropertyMapImpl> return names; } + private void writePropertyNames(Set<String> propNames, + ByteArrayBuilder bab) { + for(String propName : propNames) { + writePropName(propName, bab); + } + } + /** * @return the PropertyMap created from the values parsed from the given * data chunk combined with the given property names */ private PropertyMapImpl readPropertyValues( - ByteBuffer bbBlock, List<String> propNames, short blockType) + ByteBuffer bbBlock, List<String> propNames, short blockType, + PropertyMaps maps) throws IOException { String mapName = DEFAULT_NAME; @@ -217,12 +275,12 @@ public class PropertyMaps implements Iterable<PropertyMapImpl> bbBlock.position(endPos); } - PropertyMapImpl map = new PropertyMapImpl(mapName, blockType); + PropertyMapImpl map = maps.get(mapName, blockType); // read the values while(bbBlock.hasRemaining()) { - int valLen = bbBlock.getShort(); + int valLen = bbBlock.getShort(); int endPos = bbBlock.position() + valLen - 2; byte flag = bbBlock.get(); DataType dataType = DataType.fromByte(bbBlock.get()); @@ -230,7 +288,7 @@ public class PropertyMaps implements Iterable<PropertyMapImpl> int dataSize = bbBlock.getShort(); String propName = propNames.get(nameIdx); - PropColumn col = getColumn(dataType, propName, dataSize); + PropColumn col = getColumn(dataType, propName, dataSize, null); byte[] data = ByteUtil.getBytes(bbBlock, dataSize); Object value = col.read(data); @@ -243,6 +301,54 @@ public class PropertyMaps implements Iterable<PropertyMapImpl> return map; } + private void writePropertyValues( + PropertyMapImpl propMap, Set<String> propNames, ByteArrayBuilder bab) + throws IOException + { + // write the map name, if any + String mapName = propMap.getName(); + int blockStartPos = bab.position(); + bab.reserveInt(); + writePropName(mapName, bab); + int len = bab.position() - blockStartPos; + bab.putInt(blockStartPos, len); + + // write the map values + int nameIdx = 0; + for(String propName : propNames) { + + PropertyMapImpl.PropertyImpl prop = (PropertyMapImpl.PropertyImpl) + propMap.get(propName); + + if(prop != null) { + + Object value = prop.getValue(); + if(value != null) { + + int valStartPos = bab.position(); + bab.reserveShort(); + + bab.put(prop.getFlag()); + bab.put(prop.getType().getValue()); + bab.putShort((short)nameIdx); + + PropColumn col = getColumn(prop.getType(), propName, -1, value); + + ByteBuffer data = col.write( + value, _database.getFormat().MAX_ROW_SIZE); + + bab.putShort((short)data.remaining()); + bab.put(data); + + len = bab.position() - valStartPos; + bab.putShort(valStartPos, (short)len); + } + } + + ++nameIdx; + } + } + /** * Reads a property name from the given data block */ @@ -253,13 +359,25 @@ public class PropertyMaps implements Iterable<PropertyMapImpl> } /** + * Writes a property name to the given data block + */ + private void writePropName(String propName, ByteArrayBuilder bab) { + ByteBuffer textBuf = ColumnImpl.encodeUncompressedText( + propName, _database.getCharset()); + bab.putShort((short)textBuf.remaining()); + bab.put(textBuf); + } + + /** * Gets a PropColumn capable of reading/writing a property of the given * DataType */ private PropColumn getColumn(DataType dataType, String propName, - int dataSize) { + int dataSize, Object value) + throws IOException + { - if(isPseudoGuidColumn(dataType, propName, dataSize)) { + if(isPseudoGuidColumn(dataType, propName, dataSize, value)) { dataType = DataType.GUID; } @@ -278,16 +396,21 @@ public class PropertyMaps implements Iterable<PropertyMapImpl> // create column with ability to read/write the given data type col = ((colType == DataType.BOOLEAN) ? new BooleanPropColumn() : new PropColumn(colType)); + + _columns.put(dataType, col); } return col; } private static boolean isPseudoGuidColumn( - DataType dataType, String propName, int dataSize) { + DataType dataType, String propName, int dataSize, Object value) + throws IOException + { // guids seem to be marked as "binary" fields return((dataType == DataType.BINARY) && - (dataSize == DataType.GUID.getFixedSize()) && + ((dataSize == DataType.GUID.getFixedSize()) || + ((dataSize == -1) && ColumnImpl.isGUIDValue(value))) && PropertyMap.GUID_PROP.equalsIgnoreCase(propName)); } |