| CODENOTIFIER | HelpYou are not signed inSign in |
Project: Flanderra
Revision: 18
Author: pcherkas
Date: 02 Aug 2008 18:10:13
Changes:1. developed SWFIO
2. dtd for structure files
3. developed support for custom shapes
| ... | ...@@ -0,0 +1,46 @@ | |
| 1 | fillStyles.fillStyleCount=0 | |
| 2 | lineStyles.linestyle[0].color.green=0 | |
| 3 | lineStyles.linestyle[0].color.red=0 | |
| 4 | lineStyles.linestyle[0].color.blue=0 | |
| 5 | lineStyles.linestyle[0].width=20 | |
| 6 | lineStyles.lineStyleCount=1 | |
| 7 | shapeRecords.shapeRecord.3.vertLineFlag=true | |
| 8 | shapeRecords.shapeRecord.3.straightFlag=true | |
| 9 | shapeRecords.shapeRecord.3.deltaY=-2320 | |
| 10 | shapeRecords.shapeRecord.3.numBits=11 | |
| 11 | shapeRecords.shapeRecord.3.generalLineFlag=false | |
| 12 | shapeRecords.shapeRecord.3.typeFlag=true | |
| 13 | shapeRecords.shapeRecord.1.vertLineFlag=true | |
| 14 | shapeRecords.shapeRecord.1.straightFlag=true | |
| 15 | shapeRecords.shapeRecord.1.deltaY=2320 | |
| 16 | shapeRecords.shapeRecord.1.numBits=11 | |
| 17 | shapeRecords.shapeRecord.1.generalLineFlag=false | |
| 18 | shapeRecords.shapeRecord.1.typeFlag=true | |
| 19 | shapeRecords.shapeRecord.5.endOfShape=0 | |
| 20 | shapeRecords.shapeRecord.5.typeFlag=false | |
| 21 | shapeRecords.shapeRecord.5.shapeRecordName=ENDSHAPERECORD | |
| 22 | shapeRecords.shapeRecord.2.deltaX=-2880 | |
| 23 | shapeRecords.shapeRecord.2.vertLineFlag=false | |
| 24 | shapeRecords.shapeRecord.2.straightFlag=true | |
| 25 | shapeRecords.shapeRecord.2.numBits=11 | |
| 26 | shapeRecords.shapeRecord.2.generalLineFlag=false | |
| 27 | shapeRecords.shapeRecord.2.typeFlag=true | |
| 28 | shapeRecords.shapeRecord.4.deltaX=2880 | |
| 29 | shapeRecords.shapeRecord.4.vertLineFlag=false | |
| 30 | shapeRecords.shapeRecord.4.straightFlag=true | |
| 31 | shapeRecords.shapeRecord.4.numBits=11 | |
| 32 | shapeRecords.shapeRecord.4.generalLineFlag=false | |
| 33 | shapeRecords.shapeRecord.4.typeFlag=true | |
| 34 | shapeRecords.shapeRecord.0.moveBits=14 | |
| 35 | shapeRecords.shapeRecord.0.stateMoveTo=true | |
| 36 | shapeRecords.shapeRecord.0.lineStyle=1 | |
| 37 | shapeRecords.shapeRecord.0.stateFillStyle1=false | |
| 38 | shapeRecords.shapeRecord.0.moveDeltaX=4900 | |
| 39 | shapeRecords.shapeRecord.0.typeFlag=false | |
| 40 | shapeRecords.shapeRecord.0.moveDeltaY=1680 | |
| 41 | shapeRecords.shapeRecord.0.stateLineStyle=true | |
| 42 | shapeRecords.shapeRecord.0.shapeRecordName=STYLECHANGERECORD | |
| 43 | shapeRecords.shapeRecord.0.stateFillStyle0=false | |
| 44 | shapeRecords.shapeRecord.0.stateNewStyles=false | |
| 45 | numLineBits=1 | |
| 46 | shapeVersion=1 | |
| 0 | 47 | \ No newline at end of file |
| ... | ...@@ -0,0 +1,91 @@ | |
| 1 | swf.zipContent=false | |
| 2 | swf.version=3 | |
| 3 | swf.fileLength=79 | |
| 4 | swf.sizes.xmax=11000 | |
| 5 | swf.sizes.ymin=0 | |
| 6 | swf.sizes.xmin=0 | |
| 7 | swf.sizes.nbits=15 | |
| 8 | swf.sizes.ymax=8000 | |
| 9 | swf.frameRate=12.0 | |
| 10 | swf.frameCount=1 | |
| 11 | swf.tags.0.tagCode=9 | |
| 12 | swf.tags.0.tagName=SetBackgroundColor | |
| 13 | swf.tags.0.isSupported=true | |
| 14 | swf.tags.0.tagLength=3 | |
| 15 | swf.tags.0.tagData=FF FF FF | |
| 16 | swf.tags.0.backgroundColor.green=255 | |
| 17 | swf.tags.0.backgroundColor.red=255 | |
| 18 | swf.tags.0.backgroundColor.blue=255 | |
| 19 | swf.tags.1.tagCode=2 | |
| 20 | swf.tags.1.tagName=DefineShape | |
| 21 | swf.tags.1.isSupported=true | |
| 22 | swf.tags.1.tagLength=35 | |
| 23 | swf.tags.1.tagData=01 00 70 FB 49 97 0D 0C 7D 50 00 01 14 00 00 00 00 01 25 C9 92 0D 21 ED 48 87 65 30 3B 6D E1 D8 B4 00 00 | |
| 24 | swf.tags.1.shapeId=1 | |
| 25 | swf.tags.1.shapeBounds.xmax=4910 | |
| 26 | swf.tags.1.shapeBounds.ymin=1670 | |
| 27 | swf.tags.1.shapeBounds.xmin=2010 | |
| 28 | swf.tags.1.shapeBounds.nbits=14 | |
| 29 | swf.tags.1.shapeBounds.ymax=4010 | |
| 30 | swf.tags.1.shape.numFillBits=0 | |
| 31 | swf.tags.1.shape.fillStyles.fillStyleCount=0 | |
| 32 | swf.tags.1.shape.lineStyles.linestyle[0].color.green=0 | |
| 33 | swf.tags.1.shape.lineStyles.linestyle[0].color.red=0 | |
| 34 | swf.tags.1.shape.lineStyles.linestyle[0].color.blue=0 | |
| 35 | swf.tags.1.shape.lineStyles.linestyle[0].width=20 | |
| 36 | swf.tags.1.shape.lineStyles.lineStyleCount=1 | |
| 37 | swf.tags.1.shape.shapeRecords.shapeRecord.3.vertLineFlag=true | |
| 38 | swf.tags.1.shape.shapeRecords.shapeRecord.3.straightFlag=true | |
| 39 | swf.tags.1.shape.shapeRecords.shapeRecord.3.deltaY=-2320 | |
| 40 | swf.tags.1.shape.shapeRecords.shapeRecord.3.numBits=11 | |
| 41 | swf.tags.1.shape.shapeRecords.shapeRecord.3.generalLineFlag=false | |
| 42 | swf.tags.1.shape.shapeRecords.shapeRecord.3.typeFlag=true | |
| 43 | swf.tags.1.shape.shapeRecords.shapeRecord.1.vertLineFlag=true | |
| 44 | swf.tags.1.shape.shapeRecords.shapeRecord.1.straightFlag=true | |
| 45 | swf.tags.1.shape.shapeRecords.shapeRecord.1.deltaY=2320 | |
| 46 | swf.tags.1.shape.shapeRecords.shapeRecord.1.numBits=11 | |
| 47 | swf.tags.1.shape.shapeRecords.shapeRecord.1.generalLineFlag=false | |
| 48 | swf.tags.1.shape.shapeRecords.shapeRecord.1.typeFlag=true | |
| 49 | swf.tags.1.shape.shapeRecords.shapeRecord.5.endOfShape=0 | |
| 50 | swf.tags.1.shape.shapeRecords.shapeRecord.5.typeFlag=false | |
| 51 | swf.tags.1.shape.shapeRecords.shapeRecord.5.shapeRecordName=ENDSHAPERECORD | |
| 52 | swf.tags.1.shape.shapeRecords.shapeRecord.2.deltaX=-2880 | |
| 53 | swf.tags.1.shape.shapeRecords.shapeRecord.2.vertLineFlag=false | |
| 54 | swf.tags.1.shape.shapeRecords.shapeRecord.2.straightFlag=true | |
| 55 | swf.tags.1.shape.shapeRecords.shapeRecord.2.numBits=11 | |
| 56 | swf.tags.1.shape.shapeRecords.shapeRecord.2.generalLineFlag=false | |
| 57 | swf.tags.1.shape.shapeRecords.shapeRecord.2.typeFlag=true | |
| 58 | swf.tags.1.shape.shapeRecords.shapeRecord.4.deltaX=2880 | |
| 59 | swf.tags.1.shape.shapeRecords.shapeRecord.4.vertLineFlag=false | |
| 60 | swf.tags.1.shape.shapeRecords.shapeRecord.4.straightFlag=true | |
| 61 | swf.tags.1.shape.shapeRecords.shapeRecord.4.numBits=11 | |
| 62 | swf.tags.1.shape.shapeRecords.shapeRecord.4.generalLineFlag=false | |
| 63 | swf.tags.1.shape.shapeRecords.shapeRecord.4.typeFlag=true | |
| 64 | swf.tags.1.shape.shapeRecords.shapeRecord.0.moveBits=14 | |
| 65 | swf.tags.1.shape.shapeRecords.shapeRecord.0.stateMoveTo=true | |
| 66 | swf.tags.1.shape.shapeRecords.shapeRecord.0.lineStyle=1 | |
| 67 | swf.tags.1.shape.shapeRecords.shapeRecord.0.stateFillStyle1=false | |
| 68 | swf.tags.1.shape.shapeRecords.shapeRecord.0.moveDeltaX=4900 | |
| 69 | swf.tags.1.shape.shapeRecords.shapeRecord.0.typeFlag=false | |
| 70 | swf.tags.1.shape.shapeRecords.shapeRecord.0.moveDeltaY=1680 | |
| 71 | swf.tags.1.shape.shapeRecords.shapeRecord.0.stateLineStyle=true | |
| 72 | swf.tags.1.shape.shapeRecords.shapeRecord.0.shapeRecordName=STYLECHANGERECORD | |
| 73 | swf.tags.1.shape.shapeRecords.shapeRecord.0.stateFillStyle0=false | |
| 74 | swf.tags.1.shape.shapeRecords.shapeRecord.0.stateNewStyles=false | |
| 75 | swf.tags.1.shape.numLineBits=1 | |
| 76 | swf.tags.1.shapeVersion=1 | |
| 77 | swf.tags.2.tagCode=26 | |
| 78 | swf.tags.2.tagName=PlaceObject2 | |
| 79 | swf.tags.2.isSupported=false | |
| 80 | swf.tags.2.tagLength=6 | |
| 81 | swf.tags.2.tagData=06 01 00 01 00 00 | |
| 82 | swf.tags.3.tagCode=1 | |
| 83 | swf.tags.3.tagName=ShowFrame | |
| 84 | swf.tags.3.isSupported=true | |
| 85 | swf.tags.3.tagLength=0 | |
| 86 | swf.tags.3.tagData= | |
| 87 | swf.tags.4.tagCode=0 | |
| 88 | swf.tags.4.tagName=End | |
| 89 | swf.tags.4.isSupported=true | |
| 90 | swf.tags.4.tagLength=0 | |
| 91 | swf.tags.4.tagData= | |
| 0 | 92 | \ No newline at end of file |
| ... | ...@@ -0,0 +1,197 @@ | |
| 1 | package com.flanderra.commons.struct.custom.swf; | |
| 2 | ||
| 3 | import static com.flanderra.commons.utils.BitUtils.bitsFixed88; | |
| 4 | import static com.flanderra.commons.utils.BitUtils.bitsUI16; | |
| 5 | import static com.flanderra.commons.utils.BitUtils.bitsUI32; | |
| 6 | import static com.flanderra.commons.utils.BitUtils.bitsUI8; | |
| 7 | import static com.flanderra.commons.utils.BitUtils.bytesToBits; | |
| 8 | import static com.flanderra.commons.utils.BitUtils.concat; | |
| 9 | import static com.flanderra.commons.utils.BitUtils.hex; | |
| 10 | import static com.flanderra.commons.utils.BitUtils.parseUI32; | |
| 11 | import static com.flanderra.commons.utils.TypeUtils.toDouble; | |
| 12 | import static com.flanderra.commons.utils.TypeUtils.toLong; | |
| 13 | ||
| 14 | import java.io.ByteArrayInputStream; | |
| 15 | import java.io.ByteArrayOutputStream; | |
| 16 | import java.io.IOException; | |
| 17 | import java.io.InputStream; | |
| 18 | import java.text.MessageFormat; | |
| 19 | import java.util.ArrayList; | |
| 20 | import java.util.BitSet; | |
| 21 | import java.util.LinkedHashMap; | |
| 22 | import java.util.List; | |
| 23 | import java.util.Map; | |
| 24 | import java.util.zip.InflaterInputStream; | |
| 25 | ||
| 26 | import org.apache.commons.logging.Log; | |
| 27 | import org.apache.commons.logging.LogFactory; | |
| 28 | ||
| 29 | import com.flanderra.commons.struct.StructureConstants; | |
| 30 | import com.flanderra.commons.struct.StructureFormat; | |
| 31 | import com.flanderra.commons.struct.StructureFormatEntry; | |
| 32 | import com.flanderra.commons.struct.StructureFormatIOUtils; | |
| 33 | import com.flanderra.commons.struct.StructureFormatUtils; | |
| 34 | import com.flanderra.commons.struct.custom.ICustomStructureFormat; | |
| 35 | import com.flanderra.commons.utils.BitInputStream; | |
| 36 | import com.flanderra.commons.utils.BitUtils; | |
| 37 | import com.sun.corba.se.spi.orbutil.fsm.Input; | |
| 38 | ||
| 39 | public class SwfImpl implements ICustomStructureFormat, StructureConstants { | |
| 40 | private static Log logger = LogFactory.getLog(SwfImpl.class); | |
| 41 | ||
| 42 | public Object[] format(Map<String, Object> context) { | |
| 43 | logger.debug("start generating SWF..."); | |
| 44 | BitSet result; | |
| 45 | int offset; | |
| 46 | List<Map<String, Object>> tags = (List<Map<String, Object>>) context.get("tags"); | |
| 47 | BitSet bsTags = new BitSet(); | |
| 48 | int lenTags = 0; | |
| 49 | logger.debug(MessageFormat.format("assembling all {0} tag(s)", tags.size())); | |
| 50 | for (int i = 0; i < tags.size(); i++) { | |
| 51 | Map<String, Object> tag = tags.get(i); | |
| 52 | Object[] tagsRes = null; | |
| 53 | if(tag.get("isSupported")!=null && tag.get("isSupported").toString().equals("false")){ | |
| 54 | tagsRes = StructureFormatIOUtils.formatUnsupportedTag(tag); | |
| 55 | } else { | |
| 56 | StructureFormat tagType = StructureFormatUtils.typeForName((String) tag.get("tagName")); | |
| 57 | tagsRes = StructureFormatIOUtils.formatTag(tagType, tag); | |
| 58 | } | |
| 59 | bsTags = concat(bsTags, (BitSet) tagsRes[0], lenTags, (Integer) tagsRes[1]); | |
| 60 | lenTags += (Integer) tagsRes[1]; | |
| 61 | } | |
| 62 | lenTags = (lenTags % 8 == 0) ? (lenTags / 8) : (lenTags / 8 + 1); | |
| 63 | logger.debug(MessageFormat.format("all tags {0} assembled yet, total length of tags is {1} bytes", tags.size(), lenTags)); | |
| 64 | StructureFormatEntry bounds = new StructureFormatEntry(); | |
| 65 | bounds.setName("frameSize"); | |
| 66 | bounds.setType("RECT"); | |
| 67 | Object[] rectRes = StructureFormatIOUtils.formatStructureEntry(context.get("sizes"), (Map<String, Object>) context | |
| 68 | .get("sizes"), bounds); | |
| 69 | BitSet bsRect = (BitSet) rectRes[0]; | |
| 70 | int lenRect = (Integer) rectRes[1]; | |
| 71 | lenRect = (lenRect % 8 == 0) ? (lenRect / 8) : (lenRect / 8 + 1); | |
| 72 | ||
| 73 | logger.debug(MessageFormat.format("the length of framesize RECT is {0} bytes", lenRect)); | |
| 74 | double frameRate = toDouble(context.get("frameRate")); | |
| 75 | long frameCount = toLong(context.get("frameCount")); | |
| 76 | long version = toLong(context.get("version")); | |
| 77 | int totalLength = lenRect + lenTags + 12; | |
| 78 | logger.debug(MessageFormat.format( | |
| 79 | "the total content length is 12 bytes + {0} bytes framesizes RECT + {1} bytes length of all tag(s) = {2} ", lenRect, | |
| 80 | lenTags, totalLength)); | |
| 81 | if (context.get("zipContent").toString().equalsIgnoreCase("1")) { | |
| 82 | logger.debug("zipContent = 1, the file prolog is CWS, needs deflating"); | |
| 83 | result = bytesToBits(PROLOG_CWS); | |
| 84 | } else { | |
| 85 | logger.debug("zipContent = 0, the file prolog is FWS"); | |
| 86 | result = bytesToBits(PROLOG_FWS); | |
| 87 | } | |
| 88 | offset = 24; | |
| 89 | logger.debug(MessageFormat.format("SWF version is {0}", version)); | |
| 90 | result = concat(result, bitsUI8(version), offset, 8); | |
| 91 | offset += 8; | |
| 92 | logger.debug(MessageFormat.format("SWF total length is {0}", totalLength)); | |
| 93 | result = concat(result, bitsUI32(totalLength), offset, 32); | |
| 94 | offset += 32; | |
| 95 | logger.debug(MessageFormat.format("SWF bounds are {0}", hex(bsRect, lenRect * 8))); | |
| 96 | result = concat(result, bsRect, offset, lenRect * 8); | |
| 97 | offset += lenRect * 8; | |
| 98 | logger.debug(MessageFormat.format("SWF frameRate is {0}", frameRate)); | |
| 99 | result = concat(result, bitsFixed88(frameRate), offset, 16); | |
| 100 | offset += 16; | |
| 101 | logger.debug(MessageFormat.format("SWF frameCount is {0}", frameCount)); | |
| 102 | result = concat(result, bitsUI16(frameCount), offset, 16); | |
| 103 | offset += 16; | |
| 104 | result = concat(result, bsTags, offset, lenTags * 8); | |
| 105 | offset += lenTags * 8; | |
| 106 | logger.debug("finished generating SWF..."); | |
| 107 | return new Object[] { result, offset }; | |
| 108 | } | |
| 109 | ||
| 110 | public Map<String, Object> parse(Map<String, Object> context, BitInputStream bis) { | |
| 111 | try { | |
| 112 | InputStream is = bis.getInputStream(); | |
| 113 | Map<String, Object> result = new LinkedHashMap<String, Object>(); | |
| 114 | byte[] head = new byte[4]; | |
| 115 | is.read(head); | |
| 116 | ||
| 117 | boolean zipContent = head[0] == 67; | |
| 118 | result.put("zipContent", head[0] == 67); | |
| 119 | result.put("version", head[3]); | |
| 120 | head[0] = 0x46; | |
| 121 | byte[] lengthBytes = new byte[4]; | |
| 122 | is.read(lengthBytes); | |
| 123 | long fileLength = parseUI32(lengthBytes); | |
| 124 | result.put("fileLength", fileLength); | |
| 125 | InputStream swfUnzippedInputStream = null; | |
| 126 | if (zipContent) { | |
| 127 | int i = 0; | |
| 128 | swfUnzippedInputStream = new InflaterInputStream(is); | |
| 129 | } else { | |
| 130 | swfUnzippedInputStream = is; | |
| 131 | } | |
| 132 | ||
| 133 | BitInputStream bitInputStream = new BitInputStream(swfUnzippedInputStream); | |
| 134 | ||
| 135 | Map sizeRect = StructureFormatIOUtils.parseCompoundType("RECT", "sizes", new LinkedHashMap(), bitInputStream); | |
| 136 | result.put("sizes", sizeRect); | |
| 137 | byte[] frameDelay = new byte[] { bitInputStream.read(), bitInputStream.read() }; | |
| 138 | result.put("frameRate", BitUtils.parseFixed88(frameDelay)); | |
| 139 | byte[] frameCount = new byte[] { bitInputStream.read(), bitInputStream.read() }; | |
| 140 | result.put("frameCount", BitUtils.parseUI16(frameCount)); | |
| 141 | boolean finished = false; | |
| 142 | List tags = new ArrayList(); | |
| 143 | while (!finished) { | |
| 144 | try { | |
| 145 | Map tagContents = new LinkedHashMap(); | |
| 146 | byte[] tagHeaderBytes = new byte[] { bitInputStream.read(), bitInputStream.read() }; | |
| 147 | if (tagHeaderBytes[0] == -1 && tagHeaderBytes[1] == -1) { | |
| 148 | break; | |
| 149 | } | |
| 150 | // if (tagHeaderBytes[0] == 0 && tagHeaderBytes[1] == 0) { | |
| 151 | // break; | |
| 152 | // } | |
| 153 | BitSet tagHeaderBits = BitUtils.bytesToBits(tagHeaderBytes); | |
| 154 | tagHeaderBits = BitUtils.flipBytes(tagHeaderBits, 2); | |
| 155 | long tagCode = BitUtils.parseUBArray(BitUtils.sub(tagHeaderBits, 0, 9), 10); | |
| 156 | long tagLength = BitUtils.parseUBArray(BitUtils.sub(tagHeaderBits, 10, 15), 6); | |
| 157 | if (tagLength == 0x3f) { | |
| 158 | tagLength = BitUtils.parseSI32(new byte[] { bitInputStream.read(), bitInputStream.read(), bitInputStream.read(), | |
| 159 | bitInputStream.read() }); | |
| 160 | } | |
| 161 | String tagName = StructureFormatUtils.tagNameForCode((int) tagCode); | |
| 162 | ByteArrayOutputStream tagContentBaos = new ByteArrayOutputStream((int) (tagLength)); | |
| 163 | for (int i = 0; i < tagLength; i++) { | |
| 164 | tagContentBaos.write(bitInputStream.read()); | |
| 165 | } | |
| 166 | boolean supported = StructureFormatUtils.isSupportedStructure(tagName); | |
| 167 | tagContents.put("tagCode", new Long(tagCode)); | |
| 168 | tagContents.put("tagName", tagName); | |
| 169 | tagContents.put("isSupported", supported); | |
| 170 | tagContents.put("tagLength", new Long(tagLength)); | |
| 171 | tagContents.put("tagData", hex(tagContentBaos.toByteArray())); | |
| 172 | if (supported) { | |
| 173 | InputStream tagInputStream = new ByteArrayInputStream(tagContentBaos.toByteArray()); | |
| 174 | BitInputStream tagBitInputStream = new BitInputStream(tagInputStream); | |
| 175 | tagContents.putAll(StructureFormatIOUtils.parseCompoundType(tagName, "tag".concat(tagName), result, tagBitInputStream)); | |
| 176 | } | |
| 177 | if ((tags.size() > 2)) { | |
| 178 | String prevTagName = (String) ((Map) tags.get(tags.size() - 1)).get("tagName"); | |
| 179 | String prevPrevTagName = (String) ((Map) tags.get(tags.size() - 2)).get("tagName"); | |
| 180 | if (prevTagName != null && prevPrevTagName != null && prevTagName.equals("End") && prevPrevTagName.equals("End")) { | |
| 181 | finished = true; | |
| 182 | } | |
| 183 | } | |
| 184 | tags.add(tagContents); | |
| 185 | } catch (Throwable e) { | |
| 186 | logger.error("exception while parsing swf", e); | |
| 187 | finished = true; | |
| 188 | } | |
| 189 | } | |
| 190 | result.put("tags", tags); | |
| 191 | return result; | |
| 192 | } catch (IOException e) { | |
| 193 | logger.error(e); | |
| 194 | throw new RuntimeException(e); | |
| 195 | } | |
| 196 | } | |
| 197 | } |
| ... | ...@@ -0,0 +1,262 @@ | |
| 1 | package com.flanderra.commons.struct.custom.shapes; | |
| 2 | ||
| 3 | import java.io.IOException; | |
| 4 | import java.util.BitSet; | |
| 5 | import java.util.HashMap; | |
| 6 | import java.util.Map; | |
| 7 | ||
| 8 | import com.flanderra.commons.struct.StructureFormatIOUtils; | |
| 9 | import com.flanderra.commons.struct.custom.ICustomStructureFormat; | |
| 10 | import com.flanderra.commons.utils.BitInputStream; | |
| 11 | import com.flanderra.commons.utils.BitUtils; | |
| 12 | import com.flanderra.commons.utils.TypeUtils; | |
| 13 | ||
| 14 | public class ShapeWithStyleImpl implements ICustomStructureFormat { | |
| 15 | ||
| 16 | public Object[] format(Map<String, Object> context) { | |
| 17 | BitSet resultBits = new BitSet(); | |
| 18 | Integer resultLen = 0; | |
| 19 | ||
| 20 | Map<String, Object> fillStylesContext = (Map<String, Object>) context.get("fillStyles"); | |
| 21 | Object[] fillStyles = formatFillStyles(fillStylesContext); | |
| 22 | BitSet fillStylesBitSet = (BitSet) fillStyles[0]; | |
| 23 | Integer fillStylesLen = (Integer) fillStyles[1]; | |
| 24 | resultBits = BitUtils.concat(resultBits, fillStylesBitSet, resultLen, fillStylesLen); | |
| 25 | resultLen += fillStylesLen; | |
| 26 | ||
| 27 | Map<String, Object> lineStylesContext = (Map<String, Object>) context.get("lineStyles"); | |
| 28 | Object[] lineStyles = formatLineStyles(lineStylesContext); | |
| 29 | BitSet lineStylesBitSet = (BitSet) lineStyles[0]; | |
| 30 | Integer lineStylesLen = (Integer) lineStyles[1]; | |
| 31 | resultBits = BitUtils.concat(resultBits, lineStylesBitSet, resultLen, lineStylesLen); | |
| 32 | resultLen += lineStylesLen; | |
| 33 | ||
| 34 | Long numFillBitsLong = TypeUtils.toLong(context.get("numFillBits")); | |
| 35 | BitSet numFillBits = BitUtils.bitsUBArray(numFillBitsLong, 4); | |
| 36 | resultBits = BitUtils.concat(resultBits, numFillBits, resultLen, 4); | |
| 37 | resultLen += 4; | |
| 38 | ||
| 39 | Long numLineBitsLong = TypeUtils.toLong(context.get("numLineBits")); | |
| 40 | BitSet numLineBits = BitUtils.bitsUBArray(numLineBitsLong, 4); | |
| 41 | resultBits = BitUtils.concat(resultBits, numLineBits, resultLen, 4); | |
| 42 | resultLen += 4; | |
| 43 | ||
| 44 | Map<String, Object> shapeRecordsContext = (Map<String, Object>) context.get("shapeRecords"); | |
| 45 | Object[] shapeRecords = formatShapeRecords(shapeRecordsContext); | |
| 46 | BitSet shapeRecordsBitSet = (BitSet) shapeRecords[0]; | |
| 47 | Integer shapeRecordsLen = (Integer) shapeRecords[1]; | |
| 48 | resultBits = BitUtils.concat(resultBits, shapeRecordsBitSet, resultLen, shapeRecordsLen); | |
| 49 | resultLen += shapeRecordsLen; | |
| 50 | ||
| 51 | return new Object[] { resultBits, resultLen }; | |
| 52 | } | |
| 53 | ||
| 54 | private Object[] formatShapeRecords(Map<String, Object> context) { | |
| 55 | BitSet resultBits = new BitSet(); | |
| 56 | Integer resultLen = 0; | |
| 57 | //TODO | |
| 58 | return new Object[] { resultBits, resultLen }; | |
| 59 | } | |
| 60 | ||
| 61 | private Object[] formatLineStyles(Map<String, Object> context) { | |
| 62 | BitSet resultBits = new BitSet(); | |
| 63 | Integer resultLen = 0; | |
| 64 | //TODO | |
| 65 | return new Object[] { resultBits, resultLen }; | |
| 66 | } | |
| 67 | ||
| 68 | private Object[] formatFillStyles(Map<String, Object> context) { | |
| 69 | BitSet resultBits = new BitSet(); | |
| 70 | Integer resultLen = 0; | |
| 71 | //TODO | |
| 72 | return new Object[] { resultBits, resultLen }; | |
| 73 | } | |
| 74 | ||
| 75 | public Map<String, Object> parse(Map<String, Object> context, BitInputStream bis) { | |
| 76 | try { | |
| 77 | Map<String, Object> result = new HashMap<String, Object>(); | |
| 78 | ||
| 79 | Map<String, Object> fillStyleArray; | |
| 80 | fillStyleArray = parseFillStyleArray(context, bis); | |
| 81 | result.put("fillStyles", fillStyleArray); | |
| 82 | ||
| 83 | Map<String, Object> lineStyleArray = parseLineStyleArray(context, bis); | |
| 84 | result.put("lineStyles", lineStyleArray); | |
| 85 | ||
| 86 | long numFillBits = BitUtils.parseUBArray(bis.readNext(4), 4); | |
| 87 | result.put("numFillBits", numFillBits); | |
| 88 | ||
| 89 | long numLineBits = BitUtils.parseUBArray(bis.readNext(4), 4); | |
| 90 | result.put("numLineBits", numLineBits); | |
| 91 | ||
| 92 | Map<String, Object> shapeRecords = parseShapeRecords(context, bis); | |
| 93 | result.put("shapeRecords", shapeRecords); | |
| 94 | ||
| 95 | return result; | |
| 96 | } catch (IOException e) { | |
| 97 | throw new RuntimeException(e); | |
| 98 | } | |
| 99 | } | |
| 100 | ||
| 101 | private Map<String, Object> parseFillStyleArray(Map<String, Object> context, BitInputStream bis) throws IOException { | |
| 102 | Map<String, Object> result = new HashMap<String, Object>(); | |
| 103 | long fillStyleCount = BitUtils.parseUI8(new byte[] { bis.read() }); | |
| 104 | if (fillStyleCount == 0xFF) { | |
| 105 | fillStyleCount = BitUtils.parseUI16(new byte[] { bis.read(), bis.read() }); | |
| 106 | } | |
| 107 | result.put("fillStyleCount", fillStyleCount); | |
| 108 | context.put("fillBits", (long) BitUtils.calculateMaxBitCountUI(new long[] { fillStyleCount })); | |
| 109 | for (int i = 0; i < fillStyleCount; i++) { | |
| 110 | String fillstyleName = "fillstyle[" + i + "]"; | |
| 111 | Map<String, Object> fillstyle = StructureFormatIOUtils.parseCompoundType("FILLSTYLE", fillstyleName, context, bis); | |
| 112 | result.put(fillstyleName, fillstyle); | |
| 113 | } | |
| 114 | return result; | |
| 115 | } | |
| 116 | ||
| 117 | private Map<String, Object> parseLineStyleArray(Map<String, Object> context, BitInputStream bis) throws IOException { | |
| 118 | Map<String, Object> result = new HashMap<String, Object>(); | |
| 119 | long lineStyleCount = BitUtils.parseUI8(new byte[] { bis.read() }); | |
| 120 | if (lineStyleCount == 0xFF) { | |
| 121 | lineStyleCount = BitUtils.parseUI16(new byte[] { bis.read(), bis.read() }); | |
| 122 | } | |
| 123 | result.put("lineStyleCount", lineStyleCount); | |
| 124 | context.put("lineBits", (long) BitUtils.calculateMaxBitCountUI(new long[] { lineStyleCount })); | |
| 125 | long shapeVersion = (Integer) context.get("shapeVersion"); | |
| 126 | for (int i = 0; i < lineStyleCount; i++) { | |
| 127 | String linestyleName = "linestyle[" + i + "]"; | |
| 128 | Map<String, Object> linestyle = null; | |
| 129 | ; | |
| 130 | if (shapeVersion == 4) { | |
| 131 | linestyle = StructureFormatIOUtils.parseCompoundType("LINESTYLE2", linestyleName, context, bis); | |
| 132 | } else { | |
| 133 | linestyle = StructureFormatIOUtils.parseCompoundType("LINESTYLE", linestyleName, context, bis); | |
| 134 | } | |
| 135 | result.put(linestyleName, linestyle); | |
| 136 | } | |
| 137 | return result; | |
| 138 | } | |
| 139 | ||
| 140 | private Map<String, Object> parseShapeRecords(Map<String, Object> context, BitInputStream bis) throws IOException { | |
| 141 | Map<String, Object> result = new HashMap<String, Object>(); | |
| 142 | boolean endShapeRecordReached = false; | |
| 143 | ||
| 144 | for (int shapeRecordIndex = 0; !endShapeRecordReached; shapeRecordIndex++) { | |
| 145 | Map<String, Object> shapeRecord = new HashMap<String, Object>(); | |
| 146 | Long typeFlag = (Long) StructureFormatIOUtils.parseElementaryType("UB[1]", "typeFlag", context, bis); | |
| 147 | ||
| 148 | shapeRecord.put("typeFlag", typeFlag == 1); | |
| 149 | if (typeFlag == 1) { | |
| 150 | // STRAIGHTEDGERECORD or CURVEDEDGERECORD | |
| 151 | Long straightFlag = (Long) StructureFormatIOUtils.parseElementaryType("UB[1]", "straightFlag", context, bis); | |
| 152 | shapeRecord.put("straightFlag", straightFlag == 1); | |
| 153 | if (straightFlag == 1) { | |
| 154 | // STRAIGHTEDGERECORD | |
| 155 | Long numBits = (Long) StructureFormatIOUtils.parseElementaryType("UB[4]", "numBits", context, bis); | |
| 156 | shapeRecord.put("numBits", numBits); | |
| 157 | Long generalLineFlag = (Long) StructureFormatIOUtils.parseElementaryType("UB[1]", "generalLineFlag", context, bis); | |
| 158 | shapeRecord.put("generalLineFlag", generalLineFlag == 1); | |
| 159 | Long vertLineFlag = -1L; | |
| 160 | if (generalLineFlag == 0) { | |
| 161 | vertLineFlag = (Long) StructureFormatIOUtils.parseElementaryType("UB[1]", "vertLineFlag ", context, bis); | |
| 162 | shapeRecord.put("vertLineFlag", vertLineFlag == 1); | |
| 163 | } | |
| 164 | if (generalLineFlag == 1 || vertLineFlag == 0) { | |
| 165 | Long deltaX = (Long) StructureFormatIOUtils.parseElementaryType("SB[" + (numBits + 2) + "]", "deltaX ", context, | |
| 166 | bis); | |
| 167 | shapeRecord.put("deltaX", deltaX); | |
| 168 | } | |
| 169 | if (generalLineFlag == 1 || vertLineFlag == 1) { | |
| 170 | Long deltaY = (Long) StructureFormatIOUtils.parseElementaryType("SB[" + (numBits + 2) + "]", "deltaY ", context, | |
| 171 | bis); | |
| 172 | shapeRecord.put("deltaY", deltaY); | |
| 173 | } | |
| 174 | } else { | |
| 175 | // CURVEDEDGERECORD | |
| 176 | Long numBits = (Long) StructureFormatIOUtils.parseElementaryType("UB[4]", "numBits", context, bis); | |
| 177 | shapeRecord.put("numBits", numBits); | |
| 178 | Long controlDeltaX = (Long) StructureFormatIOUtils.parseElementaryType("SB[" + (numBits + 2) + "]", "controlDeltaX ", | |
| 179 | context, bis); | |
| 180 | shapeRecord.put("controlDeltaX", controlDeltaX); | |
| 181 | Long controlDeltaY = (Long) StructureFormatIOUtils.parseElementaryType("SB[" + (numBits + 2) + "]", "controlDeltaY ", | |
| 182 | context, bis); | |
| 183 | shapeRecord.put("controlDeltaY", controlDeltaY); | |
| 184 | ||
| 185 | Long anchorDeltaX = (Long) StructureFormatIOUtils.parseElementaryType("SB[" + (numBits + 2) + "]", "anchorDeltaX ", | |
| 186 | context, bis); | |
| 187 | shapeRecord.put("anchorDeltaX", controlDeltaX); | |
| 188 | Long anchorDeltaY = (Long) StructureFormatIOUtils.parseElementaryType("SB[" + (numBits + 2) + "]", "anchorDeltaY ", | |
| 189 | context, bis); | |
| 190 | shapeRecord.put("anchorDeltaY", anchorDeltaY); | |
| 191 | } | |
| 192 | } else { | |
| 193 | // ENDSHAPERECORD or STYLECHANGERECORD | |
| 194 | Long stateNewStyles = (Long) StructureFormatIOUtils.parseElementaryType("UB[1]", "stateNewStyles", context, bis); | |
| 195 | Long stateLineStyle = (Long) StructureFormatIOUtils.parseElementaryType("UB[1]", "stateLineStyle", context, bis); | |
| 196 | Long stateFillStyle1 = (Long) StructureFormatIOUtils.parseElementaryType("UB[1]", "stateFillStyle1", context, bis); | |
| 197 | Long stateFillStyle0 = (Long) StructureFormatIOUtils.parseElementaryType("UB[1]", "stateFillStyle0", context, bis); | |
| 198 | Long stateMoveTo = (Long) StructureFormatIOUtils.parseElementaryType("UB[1]", "stateMoveTo", context, bis); | |
| 199 | if ((stateNewStyles + stateLineStyle + stateFillStyle1 + stateFillStyle0 + stateMoveTo) == 0) { | |
| 200 | // ENDSHAPERECORD | |
| 201 | shapeRecord.put("shapeRecordName", "ENDSHAPERECORD"); | |
| 202 | shapeRecord.put("endOfShape", 0); | |
| 203 | endShapeRecordReached = true; | |
| 204 | } else { | |
| 205 | // STYLECHANGERECORD | |
| 206 | shapeRecord.put("shapeRecordName", "STYLECHANGERECORD"); | |
| 207 | shapeRecord.put("stateNewStyles", stateNewStyles == 1); | |
| 208 | shapeRecord.put("stateLineStyle", stateLineStyle == 1); | |
| 209 | shapeRecord.put("stateFillStyle1", stateFillStyle1 == 1); | |
| 210 | shapeRecord.put("stateFillStyle0", stateFillStyle0 == 1); | |
| 211 | shapeRecord.put("stateMoveTo", stateMoveTo == 1); | |
| 212 | if (stateMoveTo == 1) { | |
| 213 | Long moveBits = (Long) StructureFormatIOUtils.parseElementaryType("UB[5]", "stateMoveTo", context, bis); | |
| 214 | shapeRecord.put("moveBits", moveBits); | |
| 215 | Long moveDeltaX = (Long) StructureFormatIOUtils.parseElementaryType("SB[" + moveBits + "]", "moveDeltaX", context, | |
| 216 | bis); | |
| 217 | shapeRecord.put("moveDeltaX", moveDeltaX); | |
| 218 | Long moveDeltaY = (Long) StructureFormatIOUtils.parseElementaryType("SB[" + moveBits + "]", "moveDeltaY", context, | |
| 219 | bis); | |
| 220 | shapeRecord.put("moveDeltaY", moveDeltaY); | |
| 221 | } | |
| 222 | ||
| 223 | Long fillBits = (Long) context.get("fillBits"); | |
| 224 | Long lineBits = (Long) context.get("lineBits"); | |
| 225 | ||
| 226 | if (stateFillStyle0 == 1) { | |
| 227 | Long fillStyle0 = (Long) StructureFormatIOUtils.parseElementaryType("UB[" + fillBits + "]", "fillStyle0", context, | |
| 228 | bis); | |
| 229 | shapeRecord.put("fillStyle0", fillStyle0); | |
| 230 | } | |
| 231 | ||
| 232 | if (stateFillStyle1 == 1) { | |
| 233 | Long fillStyle1 = (Long) StructureFormatIOUtils.parseElementaryType("UB[" + fillBits + "]", "fillStyle1", context, | |
| 234 | bis); | |
| 235 | shapeRecord.put("fillStyle1", fillStyle1); | |
| 236 | } | |
| 237 | ||
| 238 | if (stateLineStyle == 1) { | |
| 239 | Long lineStyle = (Long) StructureFormatIOUtils.parseElementaryType("UB[" + lineBits + "]", "lineStyle", context, | |
| 240 | bis); | |
| 241 | shapeRecord.put("lineStyle", lineStyle); | |
| 242 | } | |
| 243 | ||
| 244 | if (stateNewStyles == 1) { | |
| 245 | Map<String, Object> fillStyles = parseFillStyleArray(context, bis); | |
| 246 | shapeRecord.put("fillStyles", fillStyles); | |
| 247 | Map<String, Object> lineStyles = parseLineStyleArray(context, bis); | |
| 248 | shapeRecord.put("lineStyles", fillStyles); | |
| 249 | Long numFillBits = (Long) StructureFormatIOUtils.parseElementaryType("UB[4]", "numFillBits", context, bis); | |
| 250 | shapeRecord.put("numFillBits", numFillBits); | |
| 251 | Long numLineBits = (Long) StructureFormatIOUtils.parseElementaryType("UB[4]", "numLineBits", context, bis); | |
| 252 | shapeRecord.put("numLineBits", numLineBits); | |
| 253 | } | |
| 254 | ||
| 255 | } | |
| 256 | } | |
| 257 | result.put("shapeRecord." + shapeRecordIndex, shapeRecord); | |
| 258 | } | |
| 259 | return result; | |
| 260 | } | |
| 261 | ||
| 262 | } |