Save This Page
Home » poi-src-3.2-FINAL-20081019 » org.apache » poi » hslf » record » [javadoc | source]
    1   
    2   /* ====================================================================
    3      Licensed to the Apache Software Foundation (ASF) under one or more
    4      contributor license agreements.  See the NOTICE file distributed with
    5      this work for additional information regarding copyright ownership.
    6      The ASF licenses this file to You under the Apache License, Version 2.0
    7      (the "License"); you may not use this file except in compliance with
    8      the License.  You may obtain a copy of the License at
    9   
   10          http://www.apache.org/licenses/LICENSE-2.0
   11   
   12      Unless required by applicable law or agreed to in writing, software
   13      distributed under the License is distributed on an "AS IS" BASIS,
   14      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   15      See the License for the specific language governing permissions and
   16      limitations under the License.
   17   ==================================================================== */
   18           
   19   
   20   package org.apache.poi.hslf.record;
   21   
   22   import java.io.ByteArrayOutputStream;
   23   import java.io.IOException;
   24   import java.io.OutputStream;
   25   import java.util.Iterator;
   26   import java.util.LinkedList;
   27   
   28   import org.apache.poi.hslf.model.textproperties.AlignmentTextProp;
   29   import org.apache.poi.hslf.model.textproperties.CharFlagsTextProp;
   30   import org.apache.poi.hslf.model.textproperties.ParagraphFlagsTextProp;
   31   import org.apache.poi.hslf.model.textproperties.TextProp;
   32   import org.apache.poi.hslf.model.textproperties.TextPropCollection;
   33   import org.apache.poi.util.LittleEndian;
   34   import org.apache.poi.util.POILogger;
   35   
   36   /**
   37    * A StyleTextPropAtom (type 4001). Holds basic character properties 
   38    *  (bold, italic, underline, font size etc) and paragraph properties
   39    *  (alignment, line spacing etc) for the block of text (TextBytesAtom
   40    *  or TextCharsAtom) that this record follows.
   41    * You will find two lists within this class.
   42    *  1 - Paragraph style list (paragraphStyles)
   43    *  2 - Character style list (charStyles)
   44    * Both are lists of TextPropCollections. These define how many characters
   45    *  the style applies to, and what style elements make up the style (another
   46    *  list, this time of TextProps). Each TextProp has a value, which somehow
   47    *  encapsulates a property of the style
   48    *
   49    * @author Nick Burch
   50    * @author Yegor Kozlov
   51    */
   52   
   53   public class StyleTextPropAtom extends RecordAtom
   54   {
   55   	private byte[] _header;
   56   	private static long _type = 4001l;
   57   	private byte[] reserved;
   58   
   59   	private byte[] rawContents; // Holds the contents between write-outs
   60   
   61   	/** 
   62   	 * Only set to true once setParentTextSize(int) is called.
   63   	 * Until then, no stylings will have been decoded
   64   	 */
   65   	private boolean initialised = false;
   66   
   67   	/** 
   68   	 * The list of all the different paragraph stylings we code for.
   69   	 * Each entry is a TextPropCollection, which tells you how many
   70   	 *  Characters the paragraph covers, and also contains the TextProps
   71   	 *  that actually define the styling of the paragraph.
   72   	 */
   73   	private LinkedList paragraphStyles;
   74   	public LinkedList getParagraphStyles() { return paragraphStyles; }
   75   	/**
   76   	 * Updates the link list of TextPropCollections which make up the
   77   	 *  paragraph stylings
   78   	 */
   79   	public void setParagraphStyles(LinkedList ps) { paragraphStyles = ps; }
   80   	/** 
   81   	 * The list of all the different character stylings we code for.
   82   	 * Each entry is a TextPropCollection, which tells you how many
   83   	 *  Characters the character styling covers, and also contains the 
   84   	 *  TextProps that actually define the styling of the characters.
   85   	 */
   86   	private LinkedList charStyles;
   87   	public LinkedList getCharacterStyles() { return charStyles; }
   88   	/**
   89   	 * Updates the link list of TextPropCollections which make up the
   90   	 *  character stylings
   91   	 */
   92   	public void setCharacterStyles(LinkedList cs) { charStyles = cs; }
   93   	
   94   	/**
   95   	 * Returns how many characters the paragraph's
   96   	 *  TextPropCollections cover.
   97   	 * (May be one or two more than the underlying text does,
   98   	 *  due to having extra characters meaning something
   99   	 *  special to powerpoint)
  100   	 */
  101   	public int getParagraphTextLengthCovered() {
  102   		return getCharactersCovered(paragraphStyles);
  103   	}
  104   	/**
  105   	 * Returns how many characters the character's
  106   	 *  TextPropCollections cover.
  107   	 * (May be one or two more than the underlying text does,
  108   	 *  due to having extra characters meaning something
  109   	 *  special to powerpoint)
  110   	 */
  111   	public int getCharacterTextLengthCovered() {
  112   		return getCharactersCovered(charStyles);
  113   	}
  114   	private int getCharactersCovered(LinkedList styles) {
  115   		int length = 0;
  116   		Iterator it = styles.iterator();
  117   		while(it.hasNext()) {
  118   			TextPropCollection tpc =
  119   				(TextPropCollection)it.next();
  120   			length += tpc.getCharactersCovered();
  121   		}
  122   		return length;
  123   	}
  124   
  125   	/** All the different kinds of paragraph properties we might handle */
  126   	public static TextProp[] paragraphTextPropTypes = new TextProp[] {
  127   				new ParagraphFlagsTextProp(),
  128                   new TextProp(2, 0x80, "bullet.char"),
  129   				new TextProp(2, 0x10, "bullet.font"),
  130                   new TextProp(2, 0x40, "bullet.size"),
  131   				new TextProp(4, 0x20, "bullet.color"),
  132                   new AlignmentTextProp(),
  133                   new TextProp(2, 0x100, "text.offset"),
  134   				new TextProp(2, 0x200, "para_unknown_2"),
  135                   new TextProp(2, 0x400, "bullet.offset"),
  136   				new TextProp(2, 0x1000, "linespacing"),
  137   				new TextProp(2, 0x2000, "spacebefore"),
  138   				new TextProp(2, 0x4000, "spaceafter"),
  139   				new TextProp(2, 0x8000, "para_unknown_4"),
  140   				new TextProp(2, 0x10000, "para_unknown_5"),
  141   				new TextProp(2, 0xA0000, "para_unknown_6"),
  142   				new TextProp(2, 0x200000, "para_unknown_7")
  143   	};
  144   	/** All the different kinds of character properties we might handle */
  145   	public static TextProp[] characterTextPropTypes = new TextProp[] {
  146   				new CharFlagsTextProp(),
  147   				new TextProp(2, 0x10000, "font.index"),
  148                   new TextProp(2, 0x200000, "asian_or_complex"),
  149                   new TextProp(2, 0x400000, "char_unknown_2"),
  150                   new TextProp(2, 0x800000, "symbol"),
  151   				new TextProp(2, 0x20000, "font.size"),
  152   				new TextProp(4, 0x40000, "font.color"),
  153   				new TextProp(2, 0x80000, "superscript"),
  154   				new TextProp(2, 0x100000, "char_unknown_1"),
  155   				new TextProp(2, 0x1000000, "char_unknown_3"),
  156   				new TextProp(2, 0x2000000, "char_unknown_4"),
  157   				new TextProp(2, 0x4000000, "char_unknown_5"),
  158   				new TextProp(2, 0x8000000, "char_unknown_6"),
  159   				new TextProp(2, 0x10000000, "char_unknown_7"),
  160   				new TextProp(2, 0x20000000, "char_unknown_8"),
  161   				new TextProp(2, 0x40000000, "char_unknown_9"),
  162   				new TextProp(2, 0x80000000, "char_unknown_10"),
  163   	};
  164   
  165   	/* *************** record code follows ********************** */
  166   
  167   	/** 
  168   	 * For the Text Style Properties (StyleTextProp) Atom
  169   	 */
  170   	public StyleTextPropAtom(byte[] source, int start, int len) {
  171   		// Sanity Checking - we're always at least 8+10 bytes long
  172   		if(len < 18) {
  173   			len = 18;
  174   			if(source.length - start < 18) {
  175   				throw new RuntimeException("Not enough data to form a StyleTextPropAtom (min size 18 bytes long) - found " + (source.length - start));
  176   			}
  177   		}
  178   
  179   		// Get the header
  180   		_header = new byte[8];
  181   		System.arraycopy(source,start,_header,0,8);
  182   
  183   		// Save the contents of the atom, until we're asked to go and
  184   		//  decode them (via a call to setParentTextSize(int)
  185   		rawContents = new byte[len-8];
  186   		System.arraycopy(source,start+8,rawContents,0,rawContents.length);
  187   		reserved = new byte[0];
  188   
  189   		// Set empty linked lists, ready for when they call setParentTextSize
  190   		paragraphStyles = new LinkedList();
  191   		charStyles = new LinkedList();
  192   	}
  193   
  194   
  195   	/** 
  196   	 * A new set of text style properties for some text without any.
  197   	 */
  198   	public StyleTextPropAtom(int parentTextSize) {
  199   		_header = new byte[8];
  200   		rawContents = new byte[0];
  201   		reserved = new byte[0];
  202   
  203   		// Set our type
  204   		LittleEndian.putInt(_header,2,(short)_type);
  205   		// Our initial size is 10
  206   		LittleEndian.putInt(_header,4,10);
  207   
  208   		// Set empty paragraph and character styles
  209   		paragraphStyles = new LinkedList();
  210   		charStyles = new LinkedList();
  211   
  212   		TextPropCollection defaultParagraphTextProps = 
  213   			new TextPropCollection(parentTextSize, (short)0);
  214   		paragraphStyles.add(defaultParagraphTextProps);
  215   
  216   		TextPropCollection defaultCharacterTextProps = 
  217   			new TextPropCollection(parentTextSize);
  218   		charStyles.add(defaultCharacterTextProps);
  219   
  220   		// Set us as now initialised
  221   		initialised = true;
  222   	}
  223   
  224   
  225   	/**
  226   	 * We are of type 4001
  227   	 */
  228   	public long getRecordType() { return _type; }
  229   
  230   
  231   	/**
  232   	 * Write the contents of the record back, so it can be written
  233   	 *  to disk
  234   	 */
  235   	public void writeOut(OutputStream out) throws IOException {
  236   		// First thing to do is update the raw bytes of the contents, based
  237   		//  on the properties
  238   		updateRawContents();
  239   
  240   		// Now ensure that the header size is correct
  241   		int newSize = rawContents.length + reserved.length;
  242   		LittleEndian.putInt(_header,4,newSize);
  243   
  244   		// Write out the (new) header
  245   		out.write(_header);
  246   
  247   		// Write out the styles
  248   		out.write(rawContents);
  249   
  250   		// Write out any extra bits
  251   		out.write(reserved);
  252   	}
  253   
  254   
  255   	/**
  256   	 * Tell us how much text the parent TextCharsAtom or TextBytesAtom
  257   	 *  contains, so we can go ahead and initialise ourselves.
  258   	 */
  259   	public void setParentTextSize(int size) {
  260   		int pos = 0;
  261   		int textHandled = 0;
  262   
  263   		// While we have text in need of paragraph stylings, go ahead and
  264   		// grok the contents as paragraph formatting data
  265           int prsize = size;
  266   		while(pos < rawContents.length && textHandled < prsize) {
  267   			// First up, fetch the number of characters this applies to
  268   			int textLen = LittleEndian.getInt(rawContents,pos);
  269   			textHandled += textLen;
  270   			pos += 4;
  271   
  272   			// Fetch the 2 byte value that is safe to ignore as 0
  273   			short paraIgn = LittleEndian.getShort(rawContents,pos);
  274   			pos += 2;
  275   
  276   			// Grab the 4 byte value that tells us what properties follow
  277   			int paraFlags = LittleEndian.getInt(rawContents,pos);
  278   			pos += 4;
  279   
  280   			// Now make sense of those properties
  281   			TextPropCollection thisCollection = new TextPropCollection(textLen, paraIgn);
  282   			int plSize = thisCollection.buildTextPropList(
  283   					paraFlags, paragraphTextPropTypes, rawContents, pos);
  284   			pos += plSize;
  285   
  286   			// Save this properties set
  287   			paragraphStyles.add(thisCollection);
  288   
  289               // Handle extra 1 paragraph styles at the end
  290               if(pos < rawContents.length && textHandled == size) {
  291                   prsize++;
  292               }
  293   
  294   		}
  295           if (rawContents.length > 0 && textHandled != (size+1)){
  296               logger.log(POILogger.WARN, "Problem reading paragraph style runs: textHandled = " + textHandled + ", text.size+1 = " + (size+1));
  297           }
  298   
  299   		// Now do the character stylings
  300   		textHandled = 0;
  301           int chsize = size;
  302   		while(pos < rawContents.length && textHandled < chsize) {
  303   			// First up, fetch the number of characters this applies to
  304   			int textLen = LittleEndian.getInt(rawContents,pos);
  305   			textHandled += textLen;
  306   			pos += 4;
  307   
  308   			// There is no 2 byte value
  309   			short no_val = -1;
  310   
  311   			// Grab the 4 byte value that tells us what properties follow
  312   			int charFlags = LittleEndian.getInt(rawContents,pos);
  313   			pos += 4;
  314   
  315   			// Now make sense of those properties
  316   			// (Assuming we actually have some)
  317   			TextPropCollection thisCollection = new TextPropCollection(textLen, no_val);
  318   			int chSize = thisCollection.buildTextPropList(
  319   					charFlags, characterTextPropTypes, rawContents, pos);
  320   			pos += chSize;
  321   
  322   			// Save this properties set
  323   			charStyles.add(thisCollection);
  324   			
  325   			// Handle extra 1 char styles at the end
  326   			if(pos < rawContents.length && textHandled == size) {
  327   				chsize++;
  328   			}
  329   		}
  330           if (rawContents.length > 0 && textHandled != (size+1)){
  331               logger.log(POILogger.WARN, "Problem reading character style runs: textHandled = " + textHandled + ", text.size+1 = " + (size+1));
  332           }
  333   
  334   		// Handle anything left over
  335   		if(pos < rawContents.length) {
  336   			reserved = new byte[rawContents.length-pos];
  337   			System.arraycopy(rawContents,pos,reserved,0,reserved.length);
  338   		}
  339   
  340   		initialised = true;
  341   	}
  342   
  343   
  344   	/**
  345   	 * Updates the cache of the raw contents. Serialised the styles out.
  346   	 */
  347   	private void updateRawContents() throws IOException {
  348   		if(!initialised) {
  349   			// We haven't groked the styles since creation, so just stick
  350   			// with what we found
  351   			return;
  352   		}
  353   
  354   		ByteArrayOutputStream baos = new ByteArrayOutputStream();
  355   
  356   		// First up, we need to serialise the paragraph properties
  357   		for(int i=0; i<paragraphStyles.size(); i++) {
  358   			TextPropCollection tpc = (TextPropCollection)paragraphStyles.get(i);
  359   			tpc.writeOut(baos);
  360   		}
  361   
  362   		// Now, we do the character ones
  363   		for(int i=0; i<charStyles.size(); i++) {
  364   			TextPropCollection tpc = (TextPropCollection)charStyles.get(i);
  365   			tpc.writeOut(baos);
  366   		}
  367   
  368   		rawContents	= baos.toByteArray();
  369   	}
  370   	
  371   	/**
  372   	 * Create a new Paragraph TextPropCollection, and add it to the list
  373   	 * @param charactersCovered The number of characters this TextPropCollection will cover
  374   	 * @return the new TextPropCollection, which will then be in the list
  375   	 */
  376   	public TextPropCollection addParagraphTextPropCollection(int charactersCovered) {
  377   		TextPropCollection tpc = new TextPropCollection(charactersCovered, (short)0);
  378   		paragraphStyles.add(tpc);
  379   		return tpc;
  380   	}
  381   	/**
  382   	 * Create a new Character TextPropCollection, and add it to the list
  383   	 * @param charactersCovered The number of characters this TextPropCollection will cover
  384   	 * @return the new TextPropCollection, which will then be in the list
  385   	 */
  386   	public TextPropCollection addCharacterTextPropCollection(int charactersCovered) {
  387   		TextPropCollection tpc = new TextPropCollection(charactersCovered);
  388   		charStyles.add(tpc);
  389   		return tpc;
  390   	}
  391   	
  392   /* ************************************************************************ */
  393   
  394   
  395   	/**
  396        * Dump the record content into <code>StringBuffer</code>
  397        *
  398        * @return the string representation of the record data
  399        */
  400       public String toString(){
  401           StringBuffer out = new StringBuffer();
  402           out.append("Paragraph properties\n");
  403           for (Iterator it1 = getParagraphStyles().iterator(); it1.hasNext();) {
  404               TextPropCollection pr = (TextPropCollection)it1.next();
  405               out.append("  chars covered: " + pr.getCharactersCovered() + "\n");
  406               for (Iterator it2 = pr.getTextPropList().iterator(); it2.hasNext(); ) {
  407                   TextProp p = (TextProp)it2.next();
  408                   out.append("    " + p.getName() + " = " + p.getValue() + "\n");
  409               }
  410           }
  411   
  412           out.append("Character properties\n");
  413           for (Iterator it1 = getCharacterStyles().iterator(); it1.hasNext();) {
  414               TextPropCollection pr = (TextPropCollection)it1.next();
  415               out.append("  chars covered: " + pr.getCharactersCovered() + "\n");
  416               for (Iterator it2 = pr.getTextPropList().iterator(); it2.hasNext(); ) {
  417                   TextProp p = (TextProp)it2.next();
  418                   out.append("    " + p.getName() + " = " + p.getValue() + "\n");
  419               }
  420           }
  421   
  422           return out.toString();
  423       }
  424   }

Save This Page
Home » poi-src-3.2-FINAL-20081019 » org.apache » poi » hslf » record » [javadoc | source]