package jxl.biff.drawing; import common.Assert; import common.Logger; import java.io.IOException; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import jxl.biff.ByteData; import jxl.read.biff.Record; import jxl.write.biff.File; public class DrawingGroup implements EscherStream { private static Logger logger = Logger.getLogger(DrawingGroup.class); private byte[] drawingData; private EscherContainer escherData; private BStoreContainer bstoreContainer; private boolean initialized; private ArrayList drawings; private int numBlips; private int numCharts; private int drawingGroupId; private boolean drawingsOmitted; private Origin origin; private HashMap imageFiles; private int maxObjectId; private int maxShapeId; public DrawingGroup(Origin o) { this.origin = o; this.initialized = (o == Origin.WRITE); this.drawings = new ArrayList(); this.imageFiles = new HashMap(); this.drawingsOmitted = false; this.maxObjectId = 1; this.maxShapeId = 1024; } public DrawingGroup(DrawingGroup dg) { this.drawingData = dg.drawingData; this.escherData = dg.escherData; this.bstoreContainer = dg.bstoreContainer; this.initialized = dg.initialized; this.drawingData = dg.drawingData; this.escherData = dg.escherData; this.bstoreContainer = dg.bstoreContainer; this.numBlips = dg.numBlips; this.numCharts = dg.numCharts; this.drawingGroupId = dg.drawingGroupId; this.drawingsOmitted = dg.drawingsOmitted; this.origin = dg.origin; this.imageFiles = (HashMap)dg.imageFiles.clone(); this.maxObjectId = dg.maxObjectId; this.maxShapeId = dg.maxShapeId; this.drawings = new ArrayList(); } public void add(MsoDrawingGroupRecord mso) { addData(mso.getData()); } public void add(Record cont) { addData(cont.getData()); } private void addData(byte[] msodata) { if (this.drawingData == null) { this.drawingData = new byte[msodata.length]; System.arraycopy(msodata, 0, this.drawingData, 0, msodata.length); return; } byte[] newdata = new byte[this.drawingData.length + msodata.length]; System.arraycopy(this.drawingData, 0, newdata, 0, this.drawingData.length); System.arraycopy(msodata, 0, newdata, this.drawingData.length, msodata.length); this.drawingData = newdata; } final void addDrawing(DrawingGroupObject d) { this.drawings.add(d); this.maxObjectId = Math.max(this.maxObjectId, d.getObjectId()); this.maxShapeId = Math.max(this.maxShapeId, d.getShapeId()); } public void add(Chart c) { this.numCharts++; } public void add(DrawingGroupObject d) { if (this.origin == Origin.READ) { this.origin = Origin.READ_WRITE; BStoreContainer bsc = getBStoreContainer(); Dgg dgg = (Dgg)this.escherData.getChildren()[0]; this.drawingGroupId = (dgg.getCluster(1)).drawingGroupId - this.numBlips - 1; this.numBlips = (bsc != null) ? bsc.getNumBlips() : 0; if (bsc != null) Assert.verify((this.numBlips == bsc.getNumBlips())); } if (!(d instanceof Drawing)) { this.maxObjectId++; this.maxShapeId++; d.setDrawingGroup(this); d.setObjectId(this.maxObjectId, this.numBlips + 1, this.maxShapeId); if (this.drawings.size() > this.maxObjectId) logger.warn("drawings length " + this.drawings.size() + " exceeds the max object id " + this.maxObjectId); return; } Drawing drawing = (Drawing)d; Drawing refImage = (Drawing)this.imageFiles.get(d.getImageFilePath()); if (refImage == null) { this.maxObjectId++; this.maxShapeId++; this.drawings.add(drawing); drawing.setDrawingGroup(this); drawing.setObjectId(this.maxObjectId, this.numBlips + 1, this.maxShapeId); this.numBlips++; this.imageFiles.put(drawing.getImageFilePath(), drawing); } else { refImage.setReferenceCount(refImage.getReferenceCount() + 1); drawing.setDrawingGroup(this); drawing.setObjectId(refImage.getObjectId(), refImage.getBlipId(), refImage.getShapeId()); } } public void remove(DrawingGroupObject d) { if (getBStoreContainer() == null) return; if (this.origin == Origin.READ) { this.origin = Origin.READ_WRITE; this.numBlips = getBStoreContainer().getNumBlips(); Dgg dgg = (Dgg)this.escherData.getChildren()[0]; this.drawingGroupId = (dgg.getCluster(1)).drawingGroupId - this.numBlips - 1; } EscherRecord[] children = getBStoreContainer().getChildren(); BlipStoreEntry bse = (BlipStoreEntry)children[d.getBlipId() - 1]; bse.dereference(); if (bse.getReferenceCount() == 0) { getBStoreContainer().remove(bse); for (Iterator i = this.drawings.iterator(); i.hasNext(); ) { DrawingGroupObject drawing = i.next(); if (drawing.getBlipId() > d.getBlipId()) drawing.setObjectId(drawing.getObjectId(), drawing.getBlipId() - 1, drawing.getShapeId()); } this.numBlips--; } } private void initialize() { EscherRecordData er = new EscherRecordData(this, 0); Assert.verify(er.isContainer()); this.escherData = new EscherContainer(er); Assert.verify((this.escherData.getLength() == this.drawingData.length)); Assert.verify((this.escherData.getType() == EscherRecordType.DGG_CONTAINER)); this.initialized = true; } private BStoreContainer getBStoreContainer() { if (this.bstoreContainer == null) { if (!this.initialized) initialize(); EscherRecord[] children = this.escherData.getChildren(); if (children.length > 1 && children[1].getType() == EscherRecordType.BSTORE_CONTAINER) this.bstoreContainer = (BStoreContainer)children[1]; } return this.bstoreContainer; } public byte[] getData() { return this.drawingData; } public void write(File outputFile) throws IOException { if (this.origin == Origin.WRITE) { DggContainer dggContainer = new DggContainer(); Dgg dgg = new Dgg(this.numBlips + this.numCharts + 1, this.numBlips); dgg.addCluster(1, 0); dgg.addCluster(this.numBlips + 1, 0); dggContainer.add(dgg); int drawingsAdded = 0; BStoreContainer bstoreCont = new BStoreContainer(); for (Iterator i = this.drawings.iterator(); i.hasNext(); ) { Object o = i.next(); if (o instanceof Drawing) { Drawing d = (Drawing)o; BlipStoreEntry bse = new BlipStoreEntry(d); bstoreCont.add(bse); drawingsAdded++; } } if (drawingsAdded > 0) { bstoreCont.setNumBlips(drawingsAdded); dggContainer.add(bstoreCont); } Opt opt = new Opt(); dggContainer.add(opt); SplitMenuColors splitMenuColors = new SplitMenuColors(); dggContainer.add(splitMenuColors); this.drawingData = dggContainer.getData(); } else if (this.origin == Origin.READ_WRITE) { DggContainer dggContainer = new DggContainer(); Dgg dgg = new Dgg(this.numBlips + this.numCharts + 1, this.numBlips); dgg.addCluster(1, 0); dgg.addCluster(this.drawingGroupId + this.numBlips + 1, 0); dggContainer.add(dgg); BStoreContainer bstoreCont = new BStoreContainer(); bstoreCont.setNumBlips(this.numBlips); BStoreContainer readBStoreContainer = getBStoreContainer(); if (readBStoreContainer != null) { EscherRecord[] children = readBStoreContainer.getChildren(); for (int j = 0; j < children.length; j++) { BlipStoreEntry bse = (BlipStoreEntry)children[j]; bstoreCont.add(bse); } } for (Iterator i = this.drawings.iterator(); i.hasNext(); ) { DrawingGroupObject dgo = i.next(); if (dgo instanceof Drawing) { Drawing d = (Drawing)dgo; if (d.getOrigin() != Origin.READ) { BlipStoreEntry bse = new BlipStoreEntry(d); bstoreCont.add(bse); } } } dggContainer.add(bstoreCont); Opt opt = new Opt(); opt.addProperty(191, false, false, 524296); opt.addProperty(385, false, false, 134217737); opt.addProperty(448, false, false, 134217792); dggContainer.add(opt); SplitMenuColors splitMenuColors = new SplitMenuColors(); dggContainer.add(splitMenuColors); this.drawingData = dggContainer.getData(); } MsoDrawingGroupRecord msodg = new MsoDrawingGroupRecord(this.drawingData); outputFile.write((ByteData)msodg); } final int getNumberOfBlips() { return this.numBlips; } byte[] getImageData(int blipId) { this.numBlips = getBStoreContainer().getNumBlips(); Assert.verify((blipId <= this.numBlips)); Assert.verify((this.origin == Origin.READ || this.origin == Origin.READ_WRITE)); EscherRecord[] children = getBStoreContainer().getChildren(); BlipStoreEntry bse = (BlipStoreEntry)children[blipId - 1]; return bse.getImageData(); } public void setDrawingsOmitted(MsoDrawingRecord mso, ObjRecord obj) { this.drawingsOmitted = true; if (obj != null) this.maxObjectId = Math.max(this.maxObjectId, obj.getObjectId()); } public boolean hasDrawingsOmitted() { return this.drawingsOmitted; } public void updateData(DrawingGroup dg) { this.drawingsOmitted = dg.drawingsOmitted; this.maxObjectId = dg.maxObjectId; this.maxShapeId = dg.maxShapeId; } }