/// <summary> Constructs a property set /// /// </summary> /// <param name="d">the bytes /// </param> public PropertyStorage(BaseCompoundFile enclosingInstance, sbyte[] d) { InitBlock(enclosingInstance); data = d; int nameSize = IntegerHelper.getInt(data[NExcel.Biff.BaseCompoundFile.SIZE_OF_NAME_POS], data[NExcel.Biff.BaseCompoundFile.SIZE_OF_NAME_POS + 1]); type = data[NExcel.Biff.BaseCompoundFile.TYPE_POS]; startBlock = IntegerHelper.getInt(data[NExcel.Biff.BaseCompoundFile.START_BLOCK_POS], data[NExcel.Biff.BaseCompoundFile.START_BLOCK_POS + 1], data[NExcel.Biff.BaseCompoundFile.START_BLOCK_POS + 2], data[NExcel.Biff.BaseCompoundFile.START_BLOCK_POS + 3]); size = IntegerHelper.getInt(data[NExcel.Biff.BaseCompoundFile.SIZE_POS], data[NExcel.Biff.BaseCompoundFile.SIZE_POS + 1], data[NExcel.Biff.BaseCompoundFile.SIZE_POS + 2], data[NExcel.Biff.BaseCompoundFile.SIZE_POS + 3]); int chars = 0; if (nameSize > 2) { chars = (nameSize - 1) / 2; } System.Text.StringBuilder n = new System.Text.StringBuilder(""); for (int i = 0; i < chars; i++) { n.Append((char)data[i * 2]); } name = n.ToString(); }
/// <summary> Accessor for the binary data - used when copying /// /// </summary> /// <returns> the binary data /// </returns> public override sbyte[] getData() { // Palette was read in, but has not been changed if (read && !dirty) { return(getRecord().Data); } sbyte[] data = new sbyte[numColours * 4 + 2]; int pos = 0; // Set the number of records IntegerHelper.getTwoBytes(numColours, data, pos); // Set the rgb content for (int i = 0; i < numColours; i++) { pos = i * 4 + 2; data[pos] = (sbyte)rgbColours[i].red; data[pos + 1] = (sbyte)rgbColours[i].green; data[pos + 2] = (sbyte)rgbColours[i].blue; } return(data); }
/// <summary> Used when writing out records. This portion of the method handles the /// biff code and the .Length of the record and appends on the data retrieved /// from the subclasses /// /// </summary> /// <returns> the full record data to be written out to the compound file /// </returns> public sbyte[] getBytes() { sbyte[] data = getData(); int dataLength = data.Length; // Don't the call the automatic continuation code for now // Assert.verify(dataLength <= maxRecordLength - 4); // If the bytes .Length is greater than the max record .Length // then split out the data set into continue records if (data.Length > maxRecordLength - 4) { dataLength = maxRecordLength - 4; data = handleContinueRecords(data); } sbyte[] bytes = new sbyte[data.Length + 4]; Array.Copy(data, 0, bytes, 4, data.Length); IntegerHelper.getTwoBytes(Code, bytes, 0); IntegerHelper.getTwoBytes(dataLength, bytes, 2); return(bytes); }
/// <summary> Constructs this object from the raw data. Used when reading in a /// format record /// /// </summary> /// <param name="t">the raw data /// </param> /// <param name="ws">the workbook settings /// </param> /// <param name="dummy">dummy overload /// </param> public FontRecord(Record t, WorkbookSettings ws, Biff7 dummy) : base(t) { sbyte[] data = getRecord().Data; pointHeight = IntegerHelper.getInt(data[0], data[1]) / EXCEL_UNITS_PER_POINT; colourIndex = IntegerHelper.getInt(data[4], data[5]); boldWeight = IntegerHelper.getInt(data[6], data[7]); scriptStyle = IntegerHelper.getInt(data[8], data[9]); underlineStyle = data[10]; fontFamily = data[11]; initialized = false; if ((data[2] & 0x02) != 0) { italic = true; } if ((data[2] & 0x08) != 0) { struckout = true; } int numChars = data[14]; name = StringHelper.getString(data, numChars, 15, ws); }
/// <summary> Gets the binary data for output to file /// /// </summary> /// <returns> the binary data /// </returns> public override sbyte[] getData() { sbyte[] data = new sbyte[2]; // Hard code in the information for now IntegerHelper.getTwoBytes(wsoptions, data, 0); return(data); }
/// <summary> Constructs this object from the raw data /// /// </summary> /// <param name="t">the raw data /// </param> /// <param name="bt">the biff type /// </param> public XFRecord(Record t, BiffType bt) : base(t) { biffType = bt; sbyte[] data = getRecord().Data; fontIndex = IntegerHelper.getInt(data[0], data[1]); formatIndex = IntegerHelper.getInt(data[2], data[3]); date = false; number = false; // Compare against the date formats for (int i = 0; i < dateFormats.Length; i++) { if (formatIndex == dateFormats[i]) { date = true; dateFormat = langDateFormats[i]; } } // Compare against the number formats for (int i = 0; i < numberFormats.Length; i++) { if (formatIndex == numberFormats[i]) { number = true; numberFormat = langNumberFormats[i]; } } // Initialize the parent format and the type int cellAttributes = IntegerHelper.getInt(data[4], data[5]); parentFormat = (cellAttributes & 0xfff0) >> 4; int formatType = cellAttributes & 0x4; xfFormatType = formatType == 0?cell:style; locked = ((cellAttributes & 0x1) != 0); hidden = ((cellAttributes & 0x2) != 0); if (xfFormatType == cell && (parentFormat & 0xfff) == 0xfff) { // Something is screwy with the parent format - set to zero parentFormat = 0; logger.warn("Invalid parent format found - ignoring"); } initialized = false; read = true; formatInfoInitialized = false; copied = false; }
/// <summary> Used to get the data when writing out the format record /// /// </summary> /// <returns> the raw data /// </returns> public override sbyte[] getData() { data = new sbyte[formatString.Length * 2 + 3 + 2]; IntegerHelper.getTwoBytes(indexCode, data, 0); IntegerHelper.getTwoBytes(formatString.Length, data, 2); data[4] = (sbyte)1; // unicode indicator StringHelper.getUnicodeBytes(formatString, data, 5); return(data); }
/// <summary> Constructs this object from the raw data. Used when reading in a /// format record /// /// </summary> /// <param name="t">the raw data /// </param> /// <param name="ws">the workbook settings /// </param> /// <param name="biffType">biff type dummy overload /// </param> public FormatRecord(Record t, WorkbookSettings ws, BiffType biffType) : base(t) { sbyte[] data = getRecord().Data; indexCode = IntegerHelper.getInt(data[0], data[1]); initialized = true; if (biffType == biff8) { int numchars = IntegerHelper.getInt(data[2], data[3]); if (data[4] == 0) { formatString = StringHelper.getString(data, numchars, 5, ws); } else { formatString = StringHelper.getUnicodeString(data, numchars, 5); } } else { int numchars = data[2]; sbyte[] chars = new sbyte[numchars]; Array.Copy(data, 3, chars, 0, chars.Length); formatString = new string(NExcelUtils.Byte.ToCharArray(NExcelUtils.Byte.ToByteArray(chars))); } date = false; number = false; // First see if this is a date format for (int i = 0; i < dateStrings.Length; i++) { string dateString = dateStrings[i]; if (formatString.IndexOf(dateString) != -1 || formatString.IndexOf(dateString.ToUpper()) != -1) { date = true; break; } } // See if this is number format - look for the # or 0 characters if (!date) { if (formatString.IndexOf((System.Char) '#') != -1 || formatString.IndexOf((System.Char) '0') != -1) { number = true; } } }
/// <summary> Gets the byte data for writing out /// /// </summary> /// <returns> the raw data /// </returns> public override sbyte[] getData() { sbyte[] data = new sbyte[16 + name.Length * 2]; // Excel expects font heights in 1/20ths of a point IntegerHelper.getTwoBytes(pointHeight * EXCEL_UNITS_PER_POINT, data, 0); // Set the font attributes to be zero for now if (italic) { data[2] |= 0x2; } if (struckout) { data[2] |= 0x08; } // Set the index to the colour palette IntegerHelper.getTwoBytes(colourIndex, data, 4); // Bold style IntegerHelper.getTwoBytes(boldWeight, data, 6); // Script style IntegerHelper.getTwoBytes(scriptStyle, data, 8); // Underline style data[10] = (sbyte)underlineStyle; // Set the font family to be 0 data[11] = fontFamily; // Set the character set to be zero data[12] = characterSet; // Set the reserved bit to be zero data[13] = 0; // Set the .Length of the font name data[14] = (sbyte)name.Length; data[15] = (sbyte)1; // Copy in the string StringHelper.getUnicodeBytes(name, data, 16); return(data); }
/// <summary> Constructs an empty property set. Used when writing the file /// /// </summary> /// <param name="name">the property storage name /// </param> public PropertyStorage(BaseCompoundFile enclosingInstance, string name) { InitBlock(enclosingInstance); data = new sbyte[NExcel.Biff.BaseCompoundFile.PROPERTY_STORAGE_BLOCK_SIZE]; Assert.verify(name.Length < 32); IntegerHelper.getTwoBytes((name.Length + 1) * 2, data, NExcel.Biff.BaseCompoundFile.SIZE_OF_NAME_POS); // add one to the name .Length to allow for the null character at // the end for (int i = 0; i < name.Length; i++) { data[i * 2] = (sbyte)name[i]; } }
/// <summary> Abstract method implementation to get the raw byte data ready to write out /// /// </summary> /// <returns> The byte data /// </returns> public override sbyte[] getData() { sbyte[] data = new sbyte[4]; IntegerHelper.getTwoBytes(xfIndex, data, 0); // Set the built in bit data[1] |= (sbyte)-0x80; data[2] = (sbyte)styleNumber; // Set the outline level data[3] = (sbyte)-0x01; return(data); }
/// <summary> Initialize the record data</summary> private void initialize() { sbyte[] data = getRecord().Data; int numrecords = IntegerHelper.getInt(data[0], data[1]); for (int i = 0; i < numrecords; i++) { int pos = i * 4 + 2; int red = IntegerHelper.getInt(data[pos], (sbyte)0); int green = IntegerHelper.getInt(data[pos + 1], (sbyte)0); int blue = IntegerHelper.getInt(data[pos + 2], (sbyte)0); rgbColours[i] = new RGB(red, green, blue); } initialized = true; }
/// <summary> Gets the IEEE value from the byte array passed in /// /// </summary> /// <param name="pos">the position in the data block which contains the double value /// </param> /// <param name="data">the data block containing the raw bytes /// </param> /// <returns> the double value converted from the raw data /// </returns> public static double getIEEEDouble(sbyte[] data, int pos) { int num1 = IntegerHelper.getInt(data[pos], data[pos + 1], data[pos + 2], data[pos + 3]); int num2 = IntegerHelper.getInt(data[pos + 4], data[pos + 5], data[pos + 6], data[pos + 7]); // Long.parseLong doesn't like the sign bit, so have to extract this // information and put it in at the end. (Acknowledgment: thanks // to Ruben for pointing this out) bool negative = ((((long)num2) & 0x80000000) != 0); // Thanks to Lyle for the following improved IEEE double processing long val = ((num2 & 0x7fffffff) * 0x100000000L) + (num1 < 0?0x100000000L + num1:num1); double Value = BitConverter.Int64BitsToDouble(val); if (negative) { Value = -Value; } return(Value); }
/// <summary> Constructs this object from the raw data. Used when reading in a /// format record /// /// </summary> /// <param name="t">the raw data /// </param> /// <param name="ws">the workbook settings /// </param> public FontRecord(Record t, WorkbookSettings ws) : base(t) { sbyte[] data = getRecord().Data; pointHeight = IntegerHelper.getInt(data[0], data[1]) / EXCEL_UNITS_PER_POINT; colourIndex = IntegerHelper.getInt(data[4], data[5]); boldWeight = IntegerHelper.getInt(data[6], data[7]); scriptStyle = IntegerHelper.getInt(data[8], data[9]); underlineStyle = data[10]; fontFamily = data[11]; characterSet = data[12]; initialized = false; if ((data[2] & 0x02) != 0) { italic = true; } if ((data[2] & 0x08) != 0) { struckout = true; } int numChars = data[14]; if (data[15] == 0) { name = StringHelper.getString(data, numChars, 16, ws); } else if (data[15] == 1) { name = StringHelper.getUnicodeString(data, numChars, 16); } else { // Some font names don't have the unicode indicator name = StringHelper.getString(data, numChars, 15, ws); } }
/// <summary> The number of bytes for this record exceeds the maximum record /// .Length, so a continue is required /// </summary> /// <param name="data">the raw data /// </param> /// <returns> the continued data /// </returns> private sbyte[] handleContinueRecords(sbyte[] data) { // Deduce the number of continue records int continuedData = data.Length - maxRecordLength - 4; int numContinueRecords = continuedData / (maxRecordLength - 4) + 1; // Create the new byte array, allowing for the continue records // code and .Length sbyte[] newdata = new sbyte[data.Length + numContinueRecords * 4]; // Copy the bona fide record data into the beginning of the super // record Array.Copy(data, 0, newdata, 0, maxRecordLength - 4); int oldarraypos = maxRecordLength - 4; int newarraypos = maxRecordLength - 4; // Now handle all the continue records for (int i = 0; i < numContinueRecords; i++) { // The number of bytes to add into the new array int length = System.Math.Min(data.Length - oldarraypos, maxRecordLength - 4); // Add in the continue record code IntegerHelper.getTwoBytes(NExcel.Biff.Type.CONTINUE.Value, newdata, newarraypos); IntegerHelper.getTwoBytes(length, newdata, newarraypos + 2); // Copy in as much as the new data as possible Array.Copy(data, oldarraypos, newdata, newarraypos + 4, length); // Update the position counters oldarraypos += length; newarraypos += length + 4; } return(newdata); }
/// <summary> Constructs this object from the raw data /// /// </summary> /// <param name="t">the raw data /// </param> public WorkspaceInformationRecord(Record t) : base(t) { sbyte[] data = getRecord().Data; wsoptions = IntegerHelper.getInt(data[0], data[1]); }
/// <summary> Converts the various fields into binary data. If this object has /// been read from an Excel file rather than being requested by a user (ie. /// if the read flag is TRUE) then /// no processing takes place and the raw data is simply returned. /// /// </summary> /// <returns> the raw data for writing /// </returns> public override sbyte[] getData() { // Format rationalization process means that we always want to // regenerate the format info - even if the spreadsheet was // read in if (!formatInfoInitialized) { initializeFormatInformation(); } sbyte[] data = new sbyte[20]; IntegerHelper.getTwoBytes(fontIndex, data, 0); IntegerHelper.getTwoBytes(formatIndex, data, 2); // Do the cell attributes int cellAttributes = 0; if (this.Locked) { cellAttributes |= 0x01; } if (Hidden) { cellAttributes |= 0x02; } if (xfFormatType == style) { cellAttributes |= 0x04; parentFormat = 0xffff; } cellAttributes |= (parentFormat << 4); IntegerHelper.getTwoBytes(cellAttributes, data, 4); int alignMask = align.Value; if (wrap) { alignMask |= 0x08; } alignMask |= (valign.Value << 4); alignMask |= (orientation.Value << 8); IntegerHelper.getTwoBytes(alignMask, data, 6); // Set the borders int borderMask = leftBorder.Value; borderMask |= (rightBorder.Value << 4); borderMask |= (topBorder.Value << 8); borderMask |= (bottomBorder.Value << 12); IntegerHelper.getTwoBytes(borderMask, data, 10); // Set the border palette information if border mask is non zero // Hard code the colours to be black if (borderMask != 0) { sbyte lc = (sbyte)leftBorderColour.Value; sbyte rc = (sbyte)rightBorderColour.Value; sbyte tc = (sbyte)topBorderColour.Value; sbyte bc = (sbyte)bottomBorderColour.Value; data[12] = (sbyte)((lc & 0x7f) | ((rc & 0x01) << 7)); data[13] = (sbyte)((rc & 0x7f) >> 1); data[14] = (sbyte)((tc & 0x7f) | ((bc & 0x01) << 7)); data[15] = (sbyte)((bc & 0x7f) >> 1); } // Set the background pattern IntegerHelper.getTwoBytes(pattern.Value, data, 16); // Set the colour palette int colourPaletteMask = backgroundColour.Value; colourPaletteMask |= (0x40 << 7); IntegerHelper.getTwoBytes(colourPaletteMask, data, 18); // Set the cell options if (shrinkToFit) { options |= 0x10; } else { options &= 0xffef; } IntegerHelper.getTwoBytes(options, data, 8); return(data); }
/// <summary> Initializes the internal format information from the data read in</summary> private void initializeFormatInformation() { // Initialize the cell format string if (formatIndex < BuiltInFormat.builtIns.Length && BuiltInFormat.builtIns[formatIndex] != null) { excelFormat = BuiltInFormat.builtIns[formatIndex]; } else { excelFormat = formattingRecords.getFormatRecord(formatIndex); } // Initialize the font font = formattingRecords.Fonts.getFont(fontIndex); // Initialize the cell format data from the binary record sbyte[] data = getRecord().Data; // Get the parent record int cellAttributes = IntegerHelper.getInt(data[4], data[5]); parentFormat = (cellAttributes & 0xfff0) >> 4; int formatType = cellAttributes & 0x4; xfFormatType = formatType == 0?cell:style; locked = ((cellAttributes & 0x1) != 0); hidden = ((cellAttributes & 0x2) != 0); if (xfFormatType == cell && (parentFormat & 0xfff) == 0xfff) { // Something is screwy with the parent format - set to zero parentFormat = 0; logger.warn("Invalid parent format found - ignoring"); } int alignMask = IntegerHelper.getInt(data[6], data[7]); // Get the wrap if ((alignMask & 0x08) != 0) { wrap = true; } // Get the horizontal alignment align = Alignment.getAlignment(alignMask & 0x7); // Get the vertical alignment valign = VerticalAlignment.getAlignment((alignMask >> 4) & 0x7); // Get the orientation orientation = Orientation.getOrientation((alignMask >> 8) & 0xff); int attr = IntegerHelper.getInt(data[8], data[9]); // Get the shrink to fit flag shrinkToFit = (attr & 0x10) != 0; // Get the used attribute if (biffType == biff8) { usedAttributes = data[9]; } // Get the borders int borderMask = IntegerHelper.getInt(data[10], data[11]); leftBorder = BorderLineStyle.getStyle(borderMask & 0x7); rightBorder = BorderLineStyle.getStyle((borderMask >> 4) & 0x7); topBorder = BorderLineStyle.getStyle((borderMask >> 8) & 0x7); bottomBorder = BorderLineStyle.getStyle((borderMask >> 12) & 0x7); int borderColourMask = IntegerHelper.getInt(data[12], data[13]); leftBorderColour = Colour.getInternalColour(borderColourMask & 0x7f); rightBorderColour = Colour.getInternalColour((borderColourMask & 0x3f80) >> 7); borderColourMask = IntegerHelper.getInt(data[14], data[15]); topBorderColour = Colour.getInternalColour(borderColourMask & 0x7f); bottomBorderColour = Colour.getInternalColour((borderColourMask & 0x3f80) >> 7); if (biffType == biff8) { // Get the background pattern int patternVal = IntegerHelper.getInt(data[16], data[17]); pattern = Pattern.getPattern(patternVal); // Get the background colour int colourPaletteMask = IntegerHelper.getInt(data[18], data[19]); backgroundColour = Colour.getInternalColour(colourPaletteMask & 0x3f); if (backgroundColour == Colour.UNKNOWN || backgroundColour == Colour.DEFAULT_BACKGROUND1) { backgroundColour = Colour.DEFAULT_BACKGROUND; } } else { pattern = Pattern.NONE; backgroundColour = Colour.DEFAULT_BACKGROUND; } // Set the lazy initialization flag formatInfoInitialized = true; }