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   
   21   package org.apache.poi.hslf.record;
   22   
   23   import java.io;
   24   import org.apache.poi.poifs.filesystem;
   25   import org.apache.poi.util.LittleEndian;
   26   import org.apache.poi.util.StringUtil;
   27   import org.apache.poi.hslf.exceptions.CorruptPowerPointFileException;
   28   
   29   
   30   /**
   31    * This is a special kind of Atom, becauase it doesn't live inside the
   32    *  PowerPoint document. Instead, it lives in a seperate stream in the
   33    *  document. As such, it has to be treaded specially
   34    *
   35    * @author Nick Burch
   36    */
   37   
   38   public class CurrentUserAtom
   39   {
   40   	/** Standard Atom header */
   41   	public static final byte[] atomHeader = new byte[] { 0, 0, -10, 15 };
   42   	/** The Powerpoint magic numer */
   43   	public static final byte[] magicNumber = new byte[] { 95, -64, -111, -29 };
   44   	/** The Powerpoint 97 version, major and minor numbers */
   45   	public static final byte[] ppt97FileVer = new byte[] { 8, 00, -13, 03, 03, 00 };
   46   
   47   	/** The version, major and minor numbers */
   48   	private int docFinalVersionA;
   49   	private int docFinalVersionB;
   50   	private byte docMajorNo;
   51   	private byte docMinorNo;
   52   
   53   	/** The Offset into the file for the current edit */
   54       private long currentEditOffset;
   55   	/** The Username of the last person to edit the file */
   56   	private String lastEditUser;
   57   	/** The document release version */
   58   	private long releaseVersion;
   59   
   60   	/** Only correct after reading in or writing out */
   61   	private byte[] _contents;
   62   
   63   
   64   	/* ********************* getter/setter follows *********************** */
   65   
   66   	public int  getDocFinalVersionA() { return docFinalVersionA; }
   67   	public int  getDocFinalVersionB() { return docFinalVersionB; }
   68   	public byte getDocMajorNo()       { return docMajorNo; }
   69   	public byte getDocMinorNo()       { return docMinorNo; }
   70   
   71   	public long getReleaseVersion()  { return releaseVersion; }
   72   	public void setReleaseVersion(long rv) { releaseVersion = rv; }
   73   
   74   	/** Points to the UserEditAtom */
   75   	public long getCurrentEditOffset() { return currentEditOffset; }
   76   	public void setCurrentEditOffset(long id ) { currentEditOffset = id; }
   77   
   78   	public String getLastEditUsername() { return lastEditUser; }
   79   	public void setLastEditUsername(String u) { lastEditUser = u; }
   80   
   81   
   82   	/* ********************* real code follows *************************** */
   83   
   84   	/**
   85   	 * Create a new Current User Atom
   86   	 */
   87   	public CurrentUserAtom() {
   88   		_contents = new byte[0];
   89   		throw new RuntimeException("Creation support for Current User Atom not complete");
   90   	}
   91   
   92   	/** 
   93   	 * Find the Current User in the filesystem, and create from that
   94   	 */
   95   	public CurrentUserAtom(POIFSFileSystem fs) throws IOException {
   96   		this(fs.getRoot());
   97   	}
   98   	/** 
   99   	 * Find the Current User in the filesystem, and create from that
  100   	 */
  101   	public CurrentUserAtom(DirectoryNode dir) throws IOException {
  102   		// Decide how big it is
  103   		DocumentEntry docProps =
  104   			(DocumentEntry)dir.getEntry("Current User");
  105   		_contents = new byte[docProps.getSize()];
  106   
  107   		// Check it's big enough - if it's not at least 28 bytes long, then
  108   		//  the record is corrupt
  109   		if(_contents.length < 28) {
  110   			throw new CorruptPowerPointFileException("The Current User stream must be at least 28 bytes long, but was only " + _contents.length);
  111   		}
  112   
  113   		// Grab the contents
  114   		InputStream in = dir.createDocumentInputStream("Current User");
  115   		in.read(_contents);
  116   
  117   		// Set everything up
  118   		init();
  119   	}
  120   
  121   	/** 
  122   	 * Create things from the bytes
  123   	 */
  124   	public CurrentUserAtom(byte[] b) {
  125   		_contents = b;
  126   		init();
  127   	}
  128   
  129   	/**
  130   	 * Actually do the creation from a block of bytes
  131   	 */
  132   	private void init() {
  133   		// Grab the edit offset
  134   		currentEditOffset = LittleEndian.getUInt(_contents,16);
  135   
  136   		// Grab the versions
  137   		docFinalVersionA = LittleEndian.getUShort(_contents,20);
  138   		docFinalVersionB = LittleEndian.getUShort(_contents,22);
  139   		docMajorNo = _contents[24];
  140   		docMinorNo = _contents[25];
  141   
  142   		// Get the username length
  143   		long usernameLen = LittleEndian.getUShort(_contents,20);
  144   		if(usernameLen > 512) {
  145   			// Handle the case of it being garbage
  146   			System.err.println("Warning - invalid username length " + usernameLen + " found, treating as if there was no username set");
  147   			usernameLen = 0;
  148   		}
  149   
  150   		// Now we know the length of the username, 
  151   		//  use this to grab the revision
  152   		if(_contents.length >= 28+(int)usernameLen + 4) {
  153   			releaseVersion = LittleEndian.getUInt(_contents,28+(int)usernameLen);
  154   		} else {
  155   			// No revision given, as not enough data. Odd
  156   			releaseVersion = 0;
  157   		}
  158   
  159   		// Grab the unicode username, if stored
  160   		int start = 28+(int)usernameLen+4;
  161   		int len = 2*(int)usernameLen;
  162   
  163   		if(_contents.length >= start+len) {
  164   			byte[] textBytes = new byte[len];
  165   			System.arraycopy(_contents,start,textBytes,0,len);
  166   			lastEditUser = StringUtil.getFromUnicodeLE(textBytes);
  167   		} else {
  168   			// Fake from the 8 bit version
  169   			byte[] textBytes = new byte[(int)usernameLen];
  170   			System.arraycopy(_contents,28,textBytes,0,(int)usernameLen);
  171   			lastEditUser = StringUtil.getFromCompressedUnicode(textBytes,0,(int)usernameLen);
  172   		}
  173   	}
  174   
  175   
  176   	/**
  177   	 * Writes ourselves back out
  178   	 */
  179   	public void writeOut(OutputStream out) throws IOException {
  180   		// Decide on the size
  181   		//  8 = atom header
  182   		//  20 = up to name
  183   		//  4 = revision
  184   		//  3 * len = ascii + unicode
  185   		int size = 8 + 20 + 4 + (3 * lastEditUser.length());
  186   		_contents = new byte[size];
  187   
  188   		// First we have a 8 byte atom header
  189   		System.arraycopy(atomHeader,0,_contents,0,4);	
  190   		// Size is 20+user len + revision len(4)
  191   		int atomSize = 20+4+lastEditUser.length();
  192   		LittleEndian.putInt(_contents,4,atomSize);
  193   
  194   		// Now we have the size of the details, which is 20
  195   		LittleEndian.putInt(_contents,8,20);
  196   
  197   		// Now the ppt magic number (4 bytes)
  198   		System.arraycopy(magicNumber,0,_contents,12,4);
  199   
  200   		// Now the current edit offset
  201   		LittleEndian.putInt(_contents,16,(int)currentEditOffset);
  202   
  203   		// Now the file versions, 2+2+1+1
  204   		LittleEndian.putShort(_contents,20,(short)docFinalVersionA);
  205   		LittleEndian.putShort(_contents,22,(short)docFinalVersionB);
  206   		_contents[24] = docMajorNo;
  207   		_contents[25] = docMinorNo;
  208   
  209   		// 2 bytes blank
  210   		_contents[26] = 0;
  211   		_contents[27] = 0;
  212   
  213   		// username in bytes in us ascii
  214   		byte[] asciiUN = new byte[lastEditUser.length()];
  215   		StringUtil.putCompressedUnicode(lastEditUser,asciiUN,0);
  216   		System.arraycopy(asciiUN,0,_contents,28,asciiUN.length);
  217   
  218   		// 4 byte release version
  219   		LittleEndian.putInt(_contents,28+asciiUN.length,(int)releaseVersion);
  220   
  221   		// username in unicode
  222   		byte [] ucUN = new byte[lastEditUser.length()*2];
  223   		StringUtil.putUnicodeLE(lastEditUser,ucUN,0);
  224   		System.arraycopy(ucUN,0,_contents,28+asciiUN.length+4,ucUN.length);
  225   
  226   		// Write out
  227   		out.write(_contents);
  228   	}
  229   
  230   	/**
  231   	 * Writes ourselves back out to a filesystem
  232   	 */
  233   	public void writeToFS(POIFSFileSystem fs) throws IOException {
  234   		// Grab contents
  235   		ByteArrayOutputStream baos = new ByteArrayOutputStream();
  236   		writeOut(baos);
  237   		ByteArrayInputStream bais = 
  238   			new ByteArrayInputStream(baos.toByteArray());
  239   
  240   		// Write out
  241   		fs.createDocument(bais,"Current User");
  242   	}
  243   }

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