/** Constructs a new empty sound container. */
  protected SoundData() {
    _header = new byte[8];
    _data = new byte[0];

    LittleEndian.putShort(_header, 2, (short) getRecordType());
    LittleEndian.putInt(_header, 4, _data.length);
  }
  /**
   * Sets the anchor (the bounding box rectangle) of this shape. All coordinates should be expressed
   * in Master units (576 dpi).
   *
   * @param anchor new anchor
   */
  public void setAnchor(java.awt.Rectangle anchor) {

    EscherContainerRecord spContainer =
        (EscherContainerRecord) _escherContainer.getChildRecords().get(0);

    EscherClientAnchorRecord clientAnchor =
        (EscherClientAnchorRecord) getEscherChild(spContainer, EscherClientAnchorRecord.RECORD_ID);
    // hack. internal variable EscherClientAnchorRecord.shortRecord can be
    // initialized only in fillFields(). We need to set shortRecord=false;
    byte[] header = new byte[16];
    LittleEndian.putUShort(header, 0, 0);
    LittleEndian.putUShort(header, 2, 0);
    LittleEndian.putInt(header, 4, 8);
    clientAnchor.fillFields(header, 0, null);

    clientAnchor.setFlag((short) (anchor.y * MASTER_DPI / POINT_DPI));
    clientAnchor.setCol1((short) (anchor.x * MASTER_DPI / POINT_DPI));
    clientAnchor.setDx1((short) ((anchor.width + anchor.x) * MASTER_DPI / POINT_DPI));
    clientAnchor.setRow1((short) ((anchor.height + anchor.y) * MASTER_DPI / POINT_DPI));

    EscherSpgrRecord spgr =
        (EscherSpgrRecord) getEscherChild(spContainer, EscherSpgrRecord.RECORD_ID);

    spgr.setRectX1(anchor.x * MASTER_DPI / POINT_DPI);
    spgr.setRectY1(anchor.y * MASTER_DPI / POINT_DPI);
    spgr.setRectX2((anchor.x + anchor.width) * MASTER_DPI / POINT_DPI);
    spgr.setRectY2((anchor.y + anchor.height) * MASTER_DPI / POINT_DPI);
  }
 public void serialize(byte[] data, int offset) {
   LittleEndian.putShort(data, 0x0 + offset, field_1_rgf);
   LittleEndian.putShort(data, 0x2 + offset, field_2_unused);
   field_3_brcTop.serialize(data, 0x4 + offset);
   field_4_brcLeft.serialize(data, 0x8 + offset);
   field_5_brcBottom.serialize(data, 0xc + offset);
   field_6_brcRight.serialize(data, 0x10 + offset);
 }
 protected void fillFields(byte[] data, int offset) {
   field_1_rgf = LittleEndian.getShort(data, 0x0 + offset);
   field_2_unused = LittleEndian.getShort(data, 0x2 + offset);
   field_3_brcTop = new BorderCode(data, 0x4 + offset);
   field_4_brcLeft = new BorderCode(data, 0x8 + offset);
   field_5_brcBottom = new BorderCode(data, 0xc + offset);
   field_6_brcRight = new BorderCode(data, 0x10 + offset);
 }
  /** Create a new TextHeader Atom, for an unknown type of text */
  public TextHeaderAtom() {
    _header = new byte[8];
    LittleEndian.putUShort(_header, 0, 0);
    LittleEndian.putUShort(_header, 2, (int) _type);
    LittleEndian.putInt(_header, 4, 4);

    textType = OTHER_TYPE;
  }
  public int serialize(int offset, byte[] data, EscherSerializationListener listener) {
    listener.beforeRecordSerialize(offset, getRecordId(), this);

    int pos = offset;
    LittleEndian.putShort(data, pos, getOptions());
    pos += 2;
    LittleEndian.putShort(data, pos, getRecordId());
    pos += 2;
    int remainingBytes = getRecordSize() - 8;
    LittleEndian.putInt(data, pos, remainingBytes);
    pos += 4;

    LittleEndian.putInt(data, pos, field_1_shapeIdMax);
    pos += 4;
    LittleEndian.putInt(data, pos, getNumIdClusters());
    pos += 4;
    LittleEndian.putInt(data, pos, field_3_numShapesSaved);
    pos += 4;
    LittleEndian.putInt(data, pos, field_4_drawingsSaved);
    pos += 4;
    for (int i = 0; i < field_5_fileIdClusters.length; i++) {
      LittleEndian.putInt(data, pos, field_5_fileIdClusters[i].field_1_drawingGroupId);
      pos += 4;
      LittleEndian.putInt(data, pos, field_5_fileIdClusters[i].field_2_numShapeIdsUsed);
      pos += 4;
    }

    listener.afterRecordSerialize(pos, getRecordId(), getRecordSize(), this);
    return getRecordSize();
  }
  static void write(Sttb sttb, HWPFOutputStream tableStream) throws IOException {
    final int headerSize = sttb.cDataLength == 2 ? 6 : 8;

    byte[] header = new byte[headerSize];
    LittleEndian.putShort(header, 0, (short) 0xffff);

    if (sttb.data == null || sttb.data.length == 0) {
      if (sttb.cDataLength == 4) {
        LittleEndian.putInt(header, 2, 0);
        LittleEndian.putUShort(header, 6, sttb.cbExtra);
        tableStream.write(header);
        return;
      }

      LittleEndian.putUShort(header, 2, 0);
      LittleEndian.putUShort(header, 4, sttb.cbExtra);
      tableStream.write(header);
      return;
    }

    if (sttb.cDataLength == 4) {
      LittleEndian.putInt(header, 2, sttb.data.length);
      LittleEndian.putUShort(header, 6, sttb.cbExtra);
      tableStream.write(header);
    } else {
      LittleEndian.putUShort(header, 2, sttb.data.length);
      LittleEndian.putUShort(header, 4, sttb.cbExtra);
      tableStream.write(header);
    }

    for (int i = 0; i < sttb.data.length; i++) {
      String entry = sttb.data[i];
      if (entry == null) {
        // is it correct?
        tableStream.write(new byte[] {-1, 0});
        continue;
      }

      byte[] buf = new byte[entry.length() * 2 + sttb.cbExtra + 2];

      LittleEndian.putShort(buf, 0, (short) entry.length());
      StringUtil.putUnicodeLE(entry, buf, 2);

      if (sttb.extraData != null && i < sttb.extraData.length && sttb.extraData[i] != null)
        System.arraycopy(
            sttb.extraData[i],
            0,
            buf,
            entry.length() * 2,
            Math.min(sttb.extraData[i].length, sttb.cbExtra));

      tableStream.write(buf);
    }
  }
  public int serialize(int offset, byte[] data, EscherSerializationListener listener) {
    listener.beforeRecordSerialize(offset, getRecordId(), this);

    LittleEndian.putShort(data, offset, getOptions());
    LittleEndian.putShort(data, offset + 2, getRecordId());

    System.arraycopy(field_pictureData, 0, data, offset + 4, field_pictureData.length);

    listener.afterRecordSerialize(
        offset + 4 + field_pictureData.length, getRecordId(), field_pictureData.length + 4, this);
    return field_pictureData.length + 4;
  }
  public int serialize(int offset, byte[] data, EscherSerializationListener listener) {
    listener.beforeRecordSerialize(offset, getRecordId(), this);

    if (remainingData == null) remainingData = new byte[0];
    LittleEndian.putShort(data, offset, getOptions());
    LittleEndian.putShort(data, offset + 2, getRecordId());
    LittleEndian.putInt(data, offset + 4, remainingData.length);
    System.arraycopy(remainingData, 0, data, offset + 8, remainingData.length);
    int pos = offset + 8 + remainingData.length;

    listener.afterRecordSerialize(pos, getRecordId(), pos - offset, this);
    return pos - offset;
  }
  /**
   * Gets the chpx for the character run at index in this fkp.
   *
   * @param index The index of the chpx to get.
   * @return a chpx grpprl.
   */
  protected byte[] getGrpprl(int index) {
    int chpxOffset = 2 * LittleEndian.getUnsignedByte(_fkp, _offset + (((_crun + 1) * 4) + index));

    // optimization if offset == 0 use "Normal" style
    if (chpxOffset == 0) {
      return new byte[0];
    }

    int size = LittleEndian.getUnsignedByte(_fkp, _offset + chpxOffset);

    byte[] chpx = new byte[size];

    System.arraycopy(_fkp, _offset + ++chpxOffset, chpx, 0, size);
    return chpx;
  }
  /**
   * Gets the papx grpprl for the paragraph at index in this fkp.
   *
   * @param index The index of the papx to get.
   * @return a papx grpprl.
   */
  protected byte[] getGrpprl(int index) {
    int papxOffset =
        2
            * LittleEndian.getUnsignedByte(
                _fkp, _offset + (((_crun + 1) * FC_SIZE) + (index * BX_SIZE)));
    int size = 2 * LittleEndian.getUnsignedByte(_fkp, _offset + papxOffset);
    if (size == 0) {
      size = 2 * LittleEndian.getUnsignedByte(_fkp, _offset + ++papxOffset);
    } else {
      size--;
    }

    byte[] papx = new byte[size];
    System.arraycopy(_fkp, _offset + ++papxOffset, papx, 0, size);
    return papx;
  }
 /**
  * Writes a eight-byte value to an output stream.
  *
  * @param out The stream to write to.
  * @param n The value to write.
  * @exception IOException if an I/O error occurs
  * @return The number of bytes written to the output stream.
  */
 public static int writeToStream(final OutputStream out, final long n) throws IOException {
   final int l = LittleEndian.LONG_SIZE;
   final byte[] buffer = new byte[l];
   LittleEndian.putLong(buffer, 0, n);
   out.write(buffer, 0, l);
   return l;
 }
 /**
  * Writes a two-byte value (short) to an output stream.
  *
  * @param out The stream to write to.
  * @param n The value to write.
  * @return The number of bytes that have been written.
  * @exception IOException if an I/O error occurs
  */
 public static int writeToStream(final OutputStream out, final short n) throws IOException {
   final int length = LittleEndian.SHORT_SIZE;
   byte[] buffer = new byte[length];
   LittleEndian.putShort(buffer, 0, n); // FIXME: unsigned
   out.write(buffer, 0, length);
   return length;
 }
 /**
  * Writes a double value value to an output stream.
  *
  * @param out The stream to write to.
  * @param n The value to write.
  * @exception IOException if an I/O error occurs
  * @return The number of bytes written to the output stream.
  */
 public static int writeToStream(final OutputStream out, final double n) throws IOException {
   final int l = LittleEndian.DOUBLE_SIZE;
   final byte[] buffer = new byte[l];
   LittleEndian.putDouble(buffer, 0, n);
   out.write(buffer, 0, l);
   return l;
 }
  public QuillContents(DirectoryNode baseDir) throws IOException {
    super(baseDir, PATH);

    // Now parse the first 512 bytes, and produce
    //  all our bits

    // Check first 8 bytes
    String f8 = new String(data, 0, 8);
    if (!f8.equals("CHNKINK ")) {
      throw new IllegalArgumentException("Expecting 'CHNKINK ' but was '" + f8 + "'");
    }
    // Ignore the next 24, for now at least

    // Now, parse all our QC Bits
    bits = new QCBit[20];
    for (int i = 0; i < 20; i++) {
      int offset = 0x20 + i * 24;
      if (data[offset] == 0x18 && data[offset + 1] == 0x00) {
        // Has some data
        String thingType = new String(data, offset + 2, 4);
        int optA = LittleEndian.getUShort(data, offset + 6);
        int optB = LittleEndian.getUShort(data, offset + 8);
        int optC = LittleEndian.getUShort(data, offset + 10);
        String bitType = new String(data, offset + 12, 4);
        int from = (int) LittleEndian.getUInt(data, offset + 16);
        int len = (int) LittleEndian.getUInt(data, offset + 20);

        byte[] bitData = new byte[len];
        System.arraycopy(data, from, bitData, 0, len);

        // Create
        if (bitType.equals("TEXT")) {
          bits[i] = new QCTextBit(thingType, bitType, bitData);
        } else if (bitType.equals("PLC ")) {
          bits[i] = QCPLCBit.createQCPLCBit(thingType, bitType, bitData);
        } else {
          bits[i] = new UnknownQCBit(thingType, bitType, bitData);
        }
        bits[i].setOptA(optA);
        bits[i].setOptB(optB);
        bits[i].setOptC(optC);
        bits[i].setDataOffset(from);
      } else {
        // Doesn't have data
      }
    }
  }
Exemple #16
0
 /**
  * Gets the locator for the corresponding {@link org.apache.poi.hssf.record.SharedFormulaRecord},
  * {@link org.apache.poi.hssf.record.ArrayRecord} or {@link
  * org.apache.poi.hssf.record.TableRecord} if this formula belongs to such a grouping. The {@link
  * CellReference} returned by this method will match the top left corner of the range of that
  * grouping. The return value is usually not the same as the location of the cell containing this
  * formula.
  *
  * @return the firstRow & firstColumn of an array formula or shared formula that this formula
  *     belongs to. <code>null</code> if this formula is not part of an array or shared formula.
  */
 public CellReference getExpReference() {
   byte[] data = _byteEncoding;
   if (data.length != 5) {
     // tExp and tTbl are always 5 bytes long, and the only ptg in the formula
     return null;
   }
   switch (data[0]) {
     case ExpPtg.sid:
       break;
     case TblPtg.sid:
       break;
     default:
       return null;
   }
   int firstRow = LittleEndian.getUShort(data, 1);
   int firstColumn = LittleEndian.getUShort(data, 3);
   return new CellReference(firstRow, firstColumn);
 }
  /**
   * Create a new holder for a boring record with children, but with position dependent
   * characteristics
   */
  protected DummyPositionSensitiveRecordWithChildren(byte[] source, int start, int len) {
    // Just grab the header, not the whole contents
    _header = new byte[8];
    System.arraycopy(source, start, _header, 0, 8);
    _type = LittleEndian.getUShort(_header, 2);

    // Find our children
    _children = Record.findChildRecords(source, start + 8, len - 8);
  }
 public int fillFields(byte[] data, int offset, EscherRecordFactory recordFactory) {
   int bytesRemaining = readHeader(data, offset);
   int pos = offset + 8;
   int size = 0;
   field_1_rectX1 = LittleEndian.getInt(data, pos + size);
   size += 4;
   field_2_rectY1 = LittleEndian.getInt(data, pos + size);
   size += 4;
   field_3_rectX2 = LittleEndian.getInt(data, pos + size);
   size += 4;
   field_4_rectY2 = LittleEndian.getInt(data, pos + size);
   size += 4;
   bytesRemaining -= size;
   if (bytesRemaining != 0)
     throw new RecordFormatException("Expected no remaining bytes but got " + bytesRemaining);
   //        remainingData  =  new byte[bytesRemaining];
   //        System.arraycopy( data, pos + size, remainingData, 0, bytesRemaining );
   return 8 + size + bytesRemaining;
 }
  /**
   * Convert the supplied java Date into a SystemTime struct, and write it into the supplied byte
   * array.
   */
  public static void storeDate(Date date, byte[] dest, int offset) {
    Calendar cal = new GregorianCalendar();
    cal.setTime(date);

    LittleEndian.putShort(dest, offset + 0, (short) cal.get(Calendar.YEAR));
    LittleEndian.putShort(dest, offset + 2, (short) (cal.get(Calendar.MONTH) + 1));
    LittleEndian.putShort(dest, offset + 4, (short) (cal.get(Calendar.DAY_OF_WEEK) - 1));
    LittleEndian.putShort(dest, offset + 6, (short) cal.get(Calendar.DAY_OF_MONTH));
    LittleEndian.putShort(dest, offset + 8, (short) cal.get(Calendar.HOUR_OF_DAY));
    LittleEndian.putShort(dest, offset + 10, (short) cal.get(Calendar.MINUTE));
    LittleEndian.putShort(dest, offset + 12, (short) cal.get(Calendar.SECOND));
    LittleEndian.putShort(dest, offset + 14, (short) cal.get(Calendar.MILLISECOND));
  }
  private static int findText(byte[] tableStream, int complexOffset, ArrayList<WordTextPiece> text)
      throws IOException {
    // actual text
    int pos = complexOffset;
    int multiple = 2;
    // skips through the prms before we reach the piece table. These contain
    // data
    // for actual fast saved files
    while (tableStream[pos] == 1) {
      pos++;
      int skip = LittleEndian.getShort(tableStream, pos);
      pos += 2 + skip;
    }
    if (tableStream[pos] != 2) {
      throw new IOException("corrupted Word file");
    } else {
      // parse out the text pieces
      int pieceTableSize = LittleEndian.getInt(tableStream, ++pos);
      pos += 4;
      int pieces = (pieceTableSize - 4) / 12;
      for (int x = 0; x < pieces; x++) {
        int filePos = LittleEndian.getInt(tableStream, pos + ((pieces + 1) * 4) + (x * 8) + 2);
        boolean unicode = false;
        if ((filePos & 0x40000000) == 0) {
          unicode = true;
        } else {
          unicode = false;
          multiple = 1;
          filePos &= ~(0x40000000); // gives me FC in doc stream
          filePos /= 2;
        }
        int totLength =
            LittleEndian.getInt(tableStream, pos + (x + 1) * 4)
                - LittleEndian.getInt(tableStream, pos + (x * 4));

        WordTextPiece piece = new WordTextPiece(filePos, totLength, unicode);
        text.add(piece);
      }
    }
    return multiple;
  }
  public void testWrite() {
    HSSFWorkbook workbook = new HSSFWorkbook();
    HSSFSheet sheet = workbook.createSheet();
    CFRuleRecord rr = CFRuleRecord.create(sheet, ComparisonOperator.BETWEEN, "5", "10");

    PatternFormatting patternFormatting = new PatternFormatting();
    patternFormatting.setFillPattern(PatternFormatting.BRICKS);
    rr.setPatternFormatting(patternFormatting);

    byte[] data = rr.serialize();
    assertEquals(26, data.length);
    assertEquals(3, LittleEndian.getShort(data, 6));
    assertEquals(3, LittleEndian.getShort(data, 8));

    int flags = LittleEndian.getInt(data, 10);
    assertEquals("unused flags should be 111", 0x00380000, flags & 0x00380000);
    assertEquals(
        "undocumented flags should be 0000", 0, flags & 0x03C00000); // Otherwise Excel gets unhappy
    // check all remaining flag bits (some are not well understood yet)
    assertEquals(0x203FFFFF, flags);
  }
 public int fillFields(byte[] data, int offset, EscherRecordFactory recordFactory) {
   int bytesRemaining = readHeader(data, offset);
   int pos = offset + 8;
   int size = 0;
   field_1_shapeIdMax = LittleEndian.getInt(data, pos + size);
   size += 4;
   LittleEndian.getInt(data, pos + size);
   size += 4; // field_2_numIdClusters
   field_3_numShapesSaved = LittleEndian.getInt(data, pos + size);
   size += 4;
   field_4_drawingsSaved = LittleEndian.getInt(data, pos + size);
   size += 4;
   field_5_fileIdClusters =
       new FileIdCluster[(bytesRemaining - size) / 8]; // Can't rely on field_2_numIdClusters
   for (int i = 0; i < field_5_fileIdClusters.length; i++) {
     field_5_fileIdClusters[i] =
         new FileIdCluster(
             LittleEndian.getInt(data, pos + size), LittleEndian.getInt(data, pos + size + 4));
     maxDgId = Math.max(maxDgId, field_5_fileIdClusters[i].getDrawingGroupId());
     size += 8;
   }
   bytesRemaining -= size;
   if (bytesRemaining != 0)
     throw new RecordFormatException(
         "Expecting no remaining data but got " + bytesRemaining + " byte(s).");
   return 8 + size + bytesRemaining;
 }
Exemple #23
0
  public int serialize(int offset, byte[] data) {
    int pos = 0;

    LittleEndian.putShort(data, 0 + offset, sid);
    LittleEndian.putShort(data, 2 + offset, (short) (getRecordSize() - 4));

    LittleEndian.putShort(data, 4 + offset + pos, field_1_categoryDataType);
    LittleEndian.putShort(data, 6 + offset + pos, field_2_valuesDataType);
    LittleEndian.putShort(data, 8 + offset + pos, field_3_numCategories);
    LittleEndian.putShort(data, 10 + offset + pos, field_4_numValues);
    LittleEndian.putShort(data, 12 + offset + pos, field_5_bubbleSeriesType);
    LittleEndian.putShort(data, 14 + offset + pos, field_6_numBubbleValues);

    return getRecordSize();
  }
Exemple #24
0
 void writeTo(byte mainStream[], int offset, HWPFOutputStream tableStream) throws IOException {
   int length = _fields.length / 2;
   LittleEndian.putShort(mainStream, offset, (short) length);
   offset += 2;
   for (int x = 0; x < length; x++) {
     UnhandledDataStructure ds = (UnhandledDataStructure) _unknownMap.get(Integer.valueOf(x));
     if (ds != null) {
       _fields[x * 2] = tableStream.getOffset();
       LittleEndian.putInt(mainStream, offset, tableStream.getOffset());
       offset += 4;
       byte buf[] = ds.getBuf();
       tableStream.write(buf);
       _fields[x * 2 + 1] = buf.length;
       LittleEndian.putInt(mainStream, offset, buf.length);
       offset += 4;
     } else {
       LittleEndian.putInt(mainStream, offset, _fields[x * 2]);
       offset += 4;
       LittleEndian.putInt(mainStream, offset, _fields[x * 2 + 1]);
       offset += 4;
     }
   }
 }
Exemple #25
0
 protected void fillFields(byte[] data, int offset) {
   field_1_iStartAt = LittleEndian.getInt(data, 0x0 + offset);
   field_2_nfc = data[0x4 + offset];
   field_3_info = data[0x5 + offset];
   field_4_rgbxchNums = LittleEndian.getByteArray(data, 0x6 + offset, 9);
   field_5_ixchFollow = data[0xf + offset];
   field_6_dxaIndentSav = LittleEndian.getInt(data, 0x10 + offset);
   field_7_unused2 = LittleEndian.getInt(data, 0x14 + offset);
   field_8_cbGrpprlChpx = LittleEndian.getUByte(data, 0x18 + offset);
   field_9_cbGrpprlPapx = LittleEndian.getUByte(data, 0x19 + offset);
   field_10_ilvlRestartLim = LittleEndian.getUByte(data, 0x1a + offset);
   field_11_grfhic = new Grfhic(data, 0x1b + offset);
 }
Exemple #26
0
 public NativeHeader(byte data[], int offset) {
   int type = (int) LittleEndian.getUInt(data, offset);
   offset += 4;
   if (type != 1) {
     throw new HSLFException("Invalid EMF picture");
   }
   // ignore header size
   offset += 4;
   int left = LittleEndian.getInt(data, offset);
   offset += 4;
   int top = LittleEndian.getInt(data, offset);
   offset += 4;
   int right = LittleEndian.getInt(data, offset);
   offset += 4;
   int bottom = LittleEndian.getInt(data, offset);
   offset += 4;
   deviceBounds = new Rectangle(left, top, right - left, bottom - top);
   // ignore frame bounds
   offset += 16;
   String signature = new String(data, offset, EMF_SIGNATURE.length(), LocaleUtil.CHARSET_1252);
   if (!EMF_SIGNATURE.equals(signature)) {
     throw new HSLFException("Invalid EMF picture");
   }
 }
Exemple #27
0
 public FIBFieldHandler(
     byte mainStream[],
     int startOffset,
     byte tableStream[],
     HashSet offsetList,
     boolean areKnown) {
   _unknownMap = new HashMap();
   int numFields = LittleEndian.getShort(mainStream, startOffset);
   int offset = startOffset + 2;
   _fields = new int[numFields * 2];
   for (int x = 0; x < numFields; x++) {
     int fieldOffset = x * 8 + offset;
     int dsOffset = LittleEndian.getInt(mainStream, fieldOffset);
     fieldOffset += 4;
     int dsSize = LittleEndian.getInt(mainStream, fieldOffset);
     if (offsetList.contains(Integer.valueOf(x)) ^ areKnown && dsSize > 0)
       if (dsOffset + dsSize > tableStream.length) {
         log.log(
             POILogger.WARN,
             (new StringBuilder())
                 .append("Unhandled data structure points to outside the buffer. offset = ")
                 .append(dsOffset)
                 .append(", length = ")
                 .append(dsSize)
                 .append(", buffer length = ")
                 .append(tableStream.length)
                 .toString());
       } else {
         UnhandledDataStructure unhandled =
             new UnhandledDataStructure(tableStream, dsOffset, dsSize);
         _unknownMap.put(Integer.valueOf(x), unhandled);
       }
     _fields[x * 2] = dsOffset;
     _fields[x * 2 + 1] = dsSize;
   }
 }
  /** Get the date found in the byte array, as a java Data object */
  public static Date getDate(byte[] data, int offset) {
    Calendar cal = new GregorianCalendar();

    cal.set(Calendar.YEAR, LittleEndian.getShort(data, offset));
    cal.set(Calendar.MONTH, LittleEndian.getShort(data, offset + 2) - 1);
    // Not actually needed - can be found from day of month
    // cal.set(Calendar.DAY_OF_WEEK,  LittleEndian.getShort(data,offset+4)+1);
    cal.set(Calendar.DAY_OF_MONTH, LittleEndian.getShort(data, offset + 6));
    cal.set(Calendar.HOUR_OF_DAY, LittleEndian.getShort(data, offset + 8));
    cal.set(Calendar.MINUTE, LittleEndian.getShort(data, offset + 10));
    cal.set(Calendar.SECOND, LittleEndian.getShort(data, offset + 12));
    cal.set(Calendar.MILLISECOND, LittleEndian.getShort(data, offset + 14));

    return cal.getTime();
  }
 public int serialize(int offset, byte[] data, EscherSerializationListener listener) {
   listener.beforeRecordSerialize(offset, getRecordId(), this);
   LittleEndian.putShort(data, offset, getOptions());
   LittleEndian.putShort(data, offset + 2, getRecordId());
   int remainingBytes = 16;
   LittleEndian.putInt(data, offset + 4, remainingBytes);
   LittleEndian.putInt(data, offset + 8, field_1_rectX1);
   LittleEndian.putInt(data, offset + 12, field_2_rectY1);
   LittleEndian.putInt(data, offset + 16, field_3_rectX2);
   LittleEndian.putInt(data, offset + 20, field_4_rectY2);
   //        System.arraycopy( remainingData, 0, data, offset + 26, remainingData.length );
   //        int pos = offset + 8 + 18 + remainingData.length;
   listener.afterRecordSerialize(
       offset + getRecordSize(), getRecordId(), offset + getRecordSize(), this);
   return 8 + 16;
 }
  /** For the TextHeader Atom */
  protected TextHeaderAtom(byte[] source, int start, int len) {
    // Sanity Checking - we're always 12 bytes long
    if (len < 12) {
      len = 12;
      if (source.length - start < 12) {
        throw new RuntimeException(
            "Not enough data to form a TextHeaderAtom (always 12 bytes long) - found "
                + (source.length - start));
      }
    }

    // Get the header
    _header = new byte[8];
    System.arraycopy(source, start, _header, 0, 8);

    // Grab the type
    textType = LittleEndian.getInt(source, start + 8);
  }