Sonar fixes - type: bugs / severity: major

git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1871064 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Andreas Beeker 2019-12-08 23:29:50 +00:00
parent 82156bc63c
commit 0f29ae8e4d
18 changed files with 376 additions and 371 deletions

View File

@ -685,8 +685,8 @@ public class AddDimensionedImage {
if(sheet instanceof HSSFSheet) {
// Next, from the columns width, calculate how many co-ordinate
// positons there are per millimetre
coordinatePositionsPerMM = ConvertImageUnits.TOTAL_COLUMN_COORDINATE_POSITIONS /
colWidthMM;
coordinatePositionsPerMM = (colWidthMM == 0) ? 0
: ConvertImageUnits.TOTAL_COLUMN_COORDINATE_POSITIONS / colWidthMM;
// From this figure, determine how many co-ordinat positions to
// inset the left hand or bottom edge of the image.
inset = (int)(coordinatePositionsPerMM * overlapMM);
@ -784,8 +784,8 @@ public class AddDimensionedImage {
}
if(sheet instanceof HSSFSheet) {
rowCoordinatesPerMM = ConvertImageUnits.TOTAL_ROW_COORDINATE_POSITIONS /
rowHeightMM;
rowCoordinatesPerMM = (rowHeightMM == 0) ? 0
: ConvertImageUnits.TOTAL_ROW_COORDINATE_POSITIONS / rowHeightMM;
inset = (int)(overlapMM * rowCoordinatesPerMM);
}
else {

View File

@ -17,15 +17,26 @@
package org.apache.poi.ss.examples;
import org.apache.poi.xssf.usermodel.*;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import java.util.Map;
import java.util.HashMap;
import java.util.Calendar;
import java.io.FileOutputStream;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.HashMap;
import java.util.Map;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.BorderStyle;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.CellStyle;
import org.apache.poi.ss.usermodel.DataFormat;
import org.apache.poi.ss.usermodel.FillPatternType;
import org.apache.poi.ss.usermodel.Font;
import org.apache.poi.ss.usermodel.HorizontalAlignment;
import org.apache.poi.ss.usermodel.IndexedColors;
import org.apache.poi.ss.usermodel.PrintSetup;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
/**
* A business plan demo
@ -36,8 +47,6 @@ import java.text.SimpleDateFormat;
*/
public class BusinessPlan {
private static SimpleDateFormat fmt = new SimpleDateFormat("dd-MMM");
private static final String[] titles = {
"ID", "Project Name", "Owner", "Days", "Start", "End"};
@ -84,6 +93,8 @@ public class BusinessPlan {
if(args.length > 0 && args[0].equals("-xls")) wb = new HSSFWorkbook();
else wb = new XSSFWorkbook();
final SimpleDateFormat fmt = new SimpleDateFormat("dd-MMM");
Map<String, CellStyle> styles = createStyles(wb);
Sheet sheet = wb.createSheet("Business Plan");
@ -201,7 +212,7 @@ public class BusinessPlan {
FileOutputStream out = new FileOutputStream(file);
wb.write(out);
out.close();
wb.close();
}
@ -315,7 +326,7 @@ public class BusinessPlan {
private static CellStyle createBorderedStyle(Workbook wb){
BorderStyle thin = BorderStyle.THIN;
short black = IndexedColors.BLACK.getIndex();
CellStyle style = wb.createCellStyle();
style.setBorderRight(thin);
style.setRightBorderColor(black);

View File

@ -17,6 +17,8 @@
package org.apache.poi.hssf.record;
import java.util.Objects;
import org.apache.poi.util.BitField;
import org.apache.poi.util.BitFieldFactory;
import org.apache.poi.util.HexDump;
@ -30,7 +32,8 @@ import org.apache.poi.util.StringUtil;
* REFERENCE: PG 315 Microsoft Excel 97 Developer's Kit (ISBN: 1-57231-498-2)
*/
public final class FontRecord extends StandardRecord {
public final static short sid = 0x0031; // docs are wrong (0x231 Microsoft Support site article Q184647)
// docs are wrong (0x231 Microsoft Support site article Q184647)
public final static short sid = 0x0031;
public final static short SS_NONE = 0;
public final static short SS_SUPER = 1;
public final static short SS_SUB = 2;
@ -39,7 +42,8 @@ public final class FontRecord extends StandardRecord {
public final static byte U_DOUBLE = 2;
public final static byte U_SINGLE_ACCOUNTING = 0x21;
public final static byte U_DOUBLE_ACCOUNTING = 0x22;
private short field_1_font_height; // in units of .05 of a point
// in units of .05 of a point
private short field_1_font_height;
private short field_2_attributes;
// 0 0x01 - Reserved bit must be 0
@ -359,24 +363,22 @@ public final class FontRecord extends StandardRecord {
}
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("[FONT]\n");
sb.append(" .fontheight = ").append(HexDump.shortToHex(getFontHeight())).append("\n");
sb.append(" .attributes = ").append(HexDump.shortToHex(getAttributes())).append("\n");
sb.append(" .italic = ").append(isItalic()).append("\n");
sb.append(" .strikout = ").append(isStruckout()).append("\n");
sb.append(" .macoutlined= ").append(isMacoutlined()).append("\n");
sb.append(" .macshadowed= ").append(isMacshadowed()).append("\n");
sb.append(" .colorpalette = ").append(HexDump.shortToHex(getColorPaletteIndex())).append("\n");
sb.append(" .boldweight = ").append(HexDump.shortToHex(getBoldWeight())).append("\n");
sb.append(" .supersubscript= ").append(HexDump.shortToHex(getSuperSubScript())).append("\n");
sb.append(" .underline = ").append(HexDump.byteToHex(getUnderline())).append("\n");
sb.append(" .family = ").append(HexDump.byteToHex(getFamily())).append("\n");
sb.append(" .charset = ").append(HexDump.byteToHex(getCharset())).append("\n");
sb.append(" .fontname = ").append(getFontName()).append("\n");
sb.append("[/FONT]\n");
return sb.toString();
return
"[FONT]\n" +
" .fontheight = " + HexDump.shortToHex(getFontHeight()) + "\n" +
" .attributes = " + HexDump.shortToHex(getAttributes()) + "\n" +
" .italic = " + isItalic() + "\n" +
" .strikout = " + isStruckout() + "\n" +
" .macoutlined= " + isMacoutlined() + "\n" +
" .macshadowed= " + isMacshadowed() + "\n" +
" .colorpalette = " + HexDump.shortToHex(getColorPaletteIndex()) + "\n" +
" .boldweight = " + HexDump.shortToHex(getBoldWeight()) + "\n" +
" .supersubscript= " + HexDump.shortToHex(getSuperSubScript()) + "\n" +
" .underline = " + HexDump.byteToHex(getUnderline()) + "\n" +
" .family = " + HexDump.byteToHex(getFamily()) + "\n" +
" .charset = " + HexDump.byteToHex(getCharset()) + "\n" +
" .fontname = " + getFontName() + "\n" +
"[/FONT]\n";
}
public void serialize(LittleEndianOutput out) {
@ -421,7 +423,7 @@ public final class FontRecord extends StandardRecord {
* Clones all the font style information from another
* FontRecord, onto this one. This
* will then hold all the same font style options.
*
*
* @param source the record to clone the properties from
*/
public void cloneStyleFrom(FontRecord source) {
@ -464,12 +466,13 @@ public final class FontRecord extends StandardRecord {
* for exact contents, because normally the
* font record's position makes a big
* difference too.
*
*
* @param other the record to compare with
*
*
* @return true, if the properties match
*/
public boolean sameProperties(FontRecord other) {
return
field_1_font_height == other.field_1_font_height &&
field_2_attributes == other.field_2_attributes &&
@ -480,15 +483,11 @@ public final class FontRecord extends StandardRecord {
field_7_family == other.field_7_family &&
field_8_charset == other.field_8_charset &&
field_9_zero == other.field_9_zero &&
stringEquals(this.field_11_font_name, other.field_11_font_name)
Objects.equals(this.field_11_font_name, other.field_11_font_name)
;
}
public boolean equals(Object o) {
return (o instanceof FontRecord) ? sameProperties((FontRecord)o) : false;
}
private static boolean stringEquals(String s1, String s2) {
return (s1 == s2 || (s1 != null && s1.equals(s2)));
return (o instanceof FontRecord) && sameProperties((FontRecord) o);
}
}

View File

@ -108,7 +108,7 @@ public final class HSSFCellStyle implements CellStyle {
}
// we keep the cached data in ThreadLocal members in order to
// avoid multi-threading issues when different workbooks are accessed in
// avoid multi-threading issues when different workbooks are accessed in
// multiple threads at the same time
private static final ThreadLocal<Short> lastDateFormat = new ThreadLocal<Short>() {
@Override
@ -264,7 +264,7 @@ public final class HSSFCellStyle implements CellStyle {
public void setQuotePrefixed(boolean quotePrefix) {
_format.set123Prefix(quotePrefix);
}
/**
* Is "Quote Prefix" or "123 Prefix" enabled for the cell?
*/
@ -272,7 +272,7 @@ public final class HSSFCellStyle implements CellStyle {
public boolean getQuotePrefixed() {
return _format.get123Prefix();
}
/**
* set the type of horizontal alignment for the cell
* @param align - the type of alignment
@ -340,8 +340,8 @@ public final class HSSFCellStyle implements CellStyle {
/**
* set the degree of rotation for the text in the cell
*
* Note: HSSF uses values from -90 to 90 degrees, whereas XSSF
* uses values from 0 to 180 degrees. The implementations of this method will map between these two value-ranges
* Note: HSSF uses values from -90 to 90 degrees, whereas XSSF
* uses values from 0 to 180 degrees. The implementations of this method will map between these two value-ranges
* accordingly, however the corresponding getter is returning values in the range mandated by the current type
* of Excel file-format that this CellStyle is applied to.
*
@ -352,7 +352,7 @@ public final class HSSFCellStyle implements CellStyle {
{
if (rotation == 0xff) {
// Special cases for vertically aligned text
}
}
else if ((rotation < 0)&&(rotation >= -90)) {
//Take care of the funny 4th quadrant issue
//The 4th quadrant (-1 to -90) is stored as (91 to 180)
@ -407,7 +407,7 @@ public final class HSSFCellStyle implements CellStyle {
{
return _format.getIndent();
}
/**
* set the type of border to use for the left border of the cell
* @param border type
@ -575,7 +575,7 @@ public final class HSSFCellStyle implements CellStyle {
{
return _format.getBottomBorderPaletteIdx();
}
/**
* setting to one fills the cell with the foreground color... No idea about
* other values
@ -674,7 +674,7 @@ public final class HSSFCellStyle implements CellStyle {
}
return result;
}
@Override
public HSSFColor getFillBackgroundColorColor() {
HSSFPalette pallette = new HSSFPalette(
@ -769,7 +769,7 @@ public final class HSSFCellStyle implements CellStyle {
public boolean getShrinkToFit() {
return _format.getShrinkToFit();
}
/**
* Get the reading order, for RTL/LTR ordering of
* the text.
@ -792,7 +792,7 @@ public final class HSSFCellStyle implements CellStyle {
public void setReadingOrder(short order) {
_format.setReadingOrder(order);
}
/**
* Verifies that this style belongs to the supplied Workbook.
* Will throw an exception if it belongs to a different one.
@ -836,9 +836,9 @@ public final class HSSFCellStyle implements CellStyle {
if(_workbook != source._workbook) {
lastDateFormat.set(Short.MIN_VALUE);
lastFormats.set(null);
getDataFormatStringCache.set(null);
lastFormats.remove();
getDataFormatStringCache.remove();
// Then we need to clone the format string,
// and update the format record for this
short fmt = (short)_workbook.createFormat(source.getDataFormatString() );
@ -894,5 +894,5 @@ public final class HSSFCellStyle implements CellStyle {
}
return false;
}
}

View File

@ -21,10 +21,7 @@ import java.io.IOException;
import java.io.InputStream;
import java.security.GeneralSecurityException;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.ShortBufferException;
import org.apache.poi.EncryptedDocumentException;
import org.apache.poi.util.IOUtils;
@ -82,7 +79,7 @@ public abstract class ChunkedCipherInputStream extends LittleEndianInputStream {
@Override
public int read() throws IOException {
byte[] b = { 0 };
return (read(b) == 1) ? b[0] : -1;
return (read(b) == 1) ? (b[0] & 0xFF) : -1;
}
// do not implement! -> recursion
@ -222,7 +219,7 @@ public abstract class ChunkedCipherInputStream extends LittleEndianInputStream {
/**
* Used when BIFF header fields (sid, size) are being read. The internal
* {@link Cipher} instance must step even when unencrypted bytes are read
*
*
*/
@Override
public void readPlain(byte[] b, int off, int len) {
@ -236,7 +233,7 @@ public abstract class ChunkedCipherInputStream extends LittleEndianInputStream {
readBytes = read(b, off, len, true);
total += Math.max(0, readBytes);
} while (readBytes > -1 && total < len);
if (total < len) {
throw new EOFException("buffer underrun");
}

View File

@ -16,7 +16,7 @@
==================================================================== */
package org.apache.poi.poifs.crypt;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.security.DigestException;
import java.security.GeneralSecurityException;
import java.security.Key;
@ -44,59 +44,62 @@ import org.apache.poi.util.StringUtil;
* Helper functions used for standard and agile encryption
*/
@Internal
public class CryptoFunctions {
public final class CryptoFunctions {
//arbitrarily selected; may need to increase
private static final int MAX_RECORD_LENGTH = 100_000;
private CryptoFunctions() {
}
/**
* <p><cite>2.3.4.7 ECMA-376 Document Encryption Key Generation (Standard Encryption)<br>
* 2.3.4.11 Encryption Key Generation (Agile Encryption)</cite></p>
*
*
* <p>The encryption key for ECMA-376 document encryption [ECMA-376] using agile
* encryption MUST be generated by using the following method, which is derived from PKCS #5:
* <a href="https://www.ietf.org/rfc/rfc2898.txt">Password-Based Cryptography Version 2.0 [RFC2898]</a>.</p>
*
*
* <p>Let H() be a hashing algorithm as determined by the PasswordKeyEncryptor.hashAlgorithm
* element, H_n be the hash data of the n-th iteration, and a plus sign (+) represent concatenation.
* The password MUST be provided as an array of Unicode characters. Limitations on the length of the
* password and the characters used by the password are implementation-dependent.
* The initial password hash is generated as follows:</p>
*
*
*
*
* <pre>H_0 = H(salt + password)</pre>
*
*
* <p>The salt used MUST be generated randomly. The salt MUST be stored in the
* PasswordKeyEncryptor.saltValue element contained within the \EncryptionInfo stream as
* specified in section 2.3.4.10. The hash is then iterated by using the following approach:</p>
*
*
* <pre>H_n = H(iterator + H_n-1)</pre>
*
*
* <p>where iterator is an unsigned 32-bit value that is initially set to 0x00000000 and then incremented
* monotonically on each iteration until PasswordKey.spinCount iterations have been performed.
* The value of iterator on the last iteration MUST be one less than PasswordKey.spinCount.</p>
*
*
* <p>For POI, H_final will be calculated by {@link #generateKey(byte[],HashAlgorithm,byte[],int)}</p>
*
* @param password
* @param hashAlgorithm
* @param salt
* @param spinCount
* @param password the password
* @param hashAlgorithm the hash algorithm
* @param salt the initial salt value
* @param spinCount the repetition count
* @return the hashed password
*/
public static byte[] hashPassword(String password, HashAlgorithm hashAlgorithm, byte[] salt, int spinCount) {
return hashPassword(password, hashAlgorithm, salt, spinCount, true);
}
/**
* Generalized method for read and write protection hash generation.
* The difference is, read protection uses the order iterator then hash in the hash loop, whereas write protection
* uses first the last hash value and then the current iterator value
*
* @param password
* @param hashAlgorithm
* @param salt
* @param spinCount
* @param password the pasword
* @param hashAlgorithm the hash algorighm
* @param salt the initial salt value
* @param spinCount the repetition count
* @param iteratorFirst if true, the iterator is hashed before the n-1 hash value,
* if false the n-1 hash value is applied first
* @return the hashed password
@ -107,16 +110,16 @@ public class CryptoFunctions {
if (password == null) {
password = Decryptor.DEFAULT_PASSWORD;
}
MessageDigest hashAlg = getMessageDigest(hashAlgorithm);
hashAlg.update(salt);
byte[] hash = hashAlg.digest(StringUtil.getToUnicodeLE(password));
byte[] iterator = new byte[LittleEndianConsts.INT_SIZE];
byte[] first = (iteratorFirst ? iterator : hash);
byte[] second = (iteratorFirst ? hash : iterator);
try {
for (int i = 0; i < spinCount; i++) {
LittleEndian.putInt(iterator, 0, i);
@ -128,13 +131,13 @@ public class CryptoFunctions {
} catch (DigestException e) {
throw new EncryptedDocumentException("error in password hashing");
}
return hash;
}
}
/**
* <p><cite>2.3.4.12 Initialization Vector Generation (Agile Encryption)</cite></p>
*
*
* <p>Initialization vectors are used in all cases for agile encryption. An initialization vector MUST be
* generated by using the following method, where H() is a hash function that MUST be the same as
* specified in section 2.3.4.11 and a plus sign (+) represents concatenation:</p>
@ -147,7 +150,7 @@ public class CryptoFunctions {
* corresponding to the cipherAlgorithm attribute, pad the array of bytes by appending 0x36 until
* the array is blockSize bytes. If the array of bytes is larger than blockSize bytes, truncate the
* array to blockSize bytes.</li>
* </ul>
* </ul>
**/
public static byte[] generateIv(HashAlgorithm hashAlgorithm, byte[] salt, byte[] blockKey, int blockSize) {
byte[] iv = salt;
@ -161,23 +164,23 @@ public class CryptoFunctions {
/**
* <p><cite>2.3.4.11 Encryption Key Generation (Agile Encryption)</cite></p>
*
*
* <p>The final hash data that is used for an encryption key is then generated by using the following
* method:</p>
*
*
* <pre>H_final = H(H_n + blockKey)</pre>
*
*
* <p>where blockKey represents an array of bytes used to prevent two different blocks from encrypting
* to the same cipher text.</p>
*
*
* <p>If the size of the resulting H_final is smaller than that of PasswordKeyEncryptor.keyBits, the key
* MUST be padded by appending bytes with a value of 0x36. If the hash value is larger in size than
* PasswordKeyEncryptor.keyBits, the key is obtained by truncating the hash value.</p>
* PasswordKeyEncryptor.keyBits, the key is obtained by truncating the hash value.</p>
*
* @param passwordHash
* @param hashAlgorithm
* @param blockKey
* @param keySize
* @param passwordHash the hashed password byte
* @param hashAlgorithm the hash algorithm
* @param blockKey the block key
* @param keySize the key size
* @return intermediate key
*/
public static byte[] generateKey(byte[] passwordHash, HashAlgorithm hashAlgorithm, byte[] blockKey, int keySize) {
@ -198,9 +201,8 @@ public class CryptoFunctions {
* @param vec the initialization vector (IV), can be null
* @param cipherMode Cipher.DECRYPT_MODE or Cipher.ENCRYPT_MODE
* @return the requested cipher
* @throws GeneralSecurityException
* @throws EncryptedDocumentException if the initialization failed or if an algorithm was specified,
* which depends on a missing bouncy castle provider
* which depends on a missing bouncy castle provider
*/
public static Cipher getCipher(SecretKey key, CipherAlgorithm cipherAlgorithm, ChainingMode chain, byte[] vec, int cipherMode) {
return getCipher(key, cipherAlgorithm, chain, vec, cipherMode, null);
@ -218,14 +220,13 @@ public class CryptoFunctions {
* @param cipherMode Cipher.DECRYPT_MODE or Cipher.ENCRYPT_MODE
* @param padding the padding (null = NOPADDING, ANSIX923Padding, PKCS5Padding, PKCS7Padding, ISO10126Padding, ...)
* @return the requested cipher
* @throws GeneralSecurityException
* @throws EncryptedDocumentException if the initialization failed or if an algorithm was specified,
* which depends on a missing bouncy castle provider
* which depends on a missing bouncy castle provider
*/
public static Cipher getCipher(Key key, CipherAlgorithm cipherAlgorithm, ChainingMode chain, byte[] vec, int cipherMode, String padding) {
int keySizeInBytes = key.getEncoded().length;
if (padding == null) padding = "NoPadding";
try {
// Ensure the JCE policies files allow for this sized key
if (Cipher.getMaxAllowedKeyLength(cipherAlgorithm.jceId) < keySizeInBytes*8) {
@ -241,7 +242,7 @@ public class CryptoFunctions {
} else {
cipher = Cipher.getInstance(cipherAlgorithm.jceId + "/" + chain.jceId + "/" + padding);
}
if (vec == null) {
cipher.init(cipherMode, key);
} else {
@ -257,10 +258,10 @@ public class CryptoFunctions {
} catch (GeneralSecurityException e) {
throw new EncryptedDocumentException(e);
}
}
}
/**
* Returns a new byte array with a truncated to the given size.
* Returns a new byte array with a truncated to the given size.
* If the hash has less then size bytes, it will be filled with 0x36-bytes
*
* @param hash the to be truncated/filled hash byte array
@ -272,7 +273,7 @@ public class CryptoFunctions {
}
/**
* Returns a new byte array with a truncated to the given size.
* Returns a new byte array with a truncated to the given size.
* If the hash has less then size bytes, it will be filled with 0-bytes
*
* @param hash the to be truncated/filled hash byte array
@ -282,16 +283,16 @@ public class CryptoFunctions {
public static byte[] getBlock0(byte[] hash, int size) {
return getBlockX(hash, size, (byte)0);
}
private static byte[] getBlockX(byte[] hash, int size, byte fill) {
if (hash.length == size) return hash;
byte[] result = IOUtils.safelyAllocate(size, MAX_RECORD_LENGTH);
Arrays.fill(result, fill);
System.arraycopy(hash, 0, result, 0, Math.min(result.length, hash.length));
return result;
}
public static MessageDigest getMessageDigest(HashAlgorithm hashAlgorithm) {
try {
if (hashAlgorithm.needsBouncyCastle) {
@ -304,7 +305,7 @@ public class CryptoFunctions {
throw new EncryptedDocumentException("hash algo not supported", e);
}
}
public static Mac getMac(HashAlgorithm hashAlgorithm) {
try {
if (hashAlgorithm.needsBouncyCastle) {
@ -323,7 +324,7 @@ public class CryptoFunctions {
if (Security.getProvider("BC") != null) {
return;
}
try {
ClassLoader cl = CryptoFunctions.class.getClassLoader();
String bcProviderName = "org.bouncycastle.jce.provider.BouncyCastleProvider";
@ -370,7 +371,7 @@ public class CryptoFunctions {
* @see <a href="http://msdn.microsoft.com/en-us/library/dd926947.aspx">2.3.7.1 Binary Document Password Verifier Derivation Method 1</a>
* @see <a href="http://msdn.microsoft.com/en-us/library/dd905229.aspx">2.3.7.4 Binary Document Password Verifier Derivation Method 2</a>
* @see <a href="http://www.ecma-international.org/news/TC45_current_work/Office Open XML Part 4 - Markup Language Reference.pdf">Part 4 - Markup Language Reference - Ecma International - 3.2.12 fileSharing</a>
*
*
* @param password the password
* @return the verifier (actually a short value)
*/
@ -380,7 +381,7 @@ public class CryptoFunctions {
}
byte[] arrByteChars = toAnsiPassword(password);
// SET Verifier TO 0x0000
short verifier = 0;
@ -391,27 +392,27 @@ public class CryptoFunctions {
verifier = rotateLeftBase15Bit(verifier);
verifier ^= arrByteChars[i];
}
// as we haven't prepended the password length into the input array
// we need to do it now separately ...
verifier = rotateLeftBase15Bit(verifier);
verifier ^= arrByteChars.length;
// RETURN Verifier BITWISE XOR 0xCE4B
verifier ^= 0xCE4B; // (0x8000 | ('N' << 8) | 'K')
}
return verifier & 0xFFFF;
}
/**
* This method generates the xor verifier for word documents &lt; 2007 (method 2).
* Its output will be used as password input for the newer word generations which
* utilize a real hashing algorithm like sha1.
*
*
* @param password the password
* @return the hashed password
*
*
* @see <a href="http://msdn.microsoft.com/en-us/library/dd905229.aspx">2.3.7.4 Binary Document Password Verifier Derivation Method 2</a>
* @see <a href="http://blogs.msdn.com/b/vsod/archive/2010/04/05/how-to-set-the-editing-restrictions-in-word-using-open-xml-sdk-2-0.aspx">How to set the editing restrictions in Word using Open XML SDK 2.0</a>
* @see <a href="http://www.aspose.com/blogs/aspose-blogs/vladimir-averkin/archive/2007/08/20/funny-how-the-new-powerful-cryptography-implemented-in-word-2007-turns-it-into-a-perfect-tool-for-document-password-removal.html">Funny: How the new powerful cryptography implemented in Word 2007 turns it into a perfect tool for document password removal.</a>
@ -425,42 +426,43 @@ public class CryptoFunctions {
byte[] generatedKey = new byte[4];
//Maximum length of the password is 15 chars.
final int maxPasswordLength = 15;
final int maxPasswordLength = 15;
if (!password.isEmpty()) {
// Truncate the password to 15 characters
password = password.substring(0, Math.min(password.length(), maxPasswordLength));
byte[] arrByteChars = toAnsiPassword(password);
// Compute the high-order word of the new key:
// --> Initialize from the initial code array (see below), depending on the passwords length.
// --> Initialize from the initial code array (see below), depending on the passwords length.
int highOrderWord = INITIAL_CODE_ARRAY[arrByteChars.length - 1];
// --> For each character in the password:
// --> For every bit in the character, starting with the least significant and progressing to (but excluding)
// the most significant, if the bit is set, XOR the keys high-order word with the corresponding word from
// --> For every bit in the character, starting with the least significant and progressing to (but excluding)
// the most significant, if the bit is set, XOR the keys high-order word with the corresponding word from
// the Encryption Matrix
for (int i = 0; i < arrByteChars.length; i++) {
int tmp = maxPasswordLength - arrByteChars.length + i;
for (int intBit = 0; intBit < 7; intBit++) {
if ((arrByteChars[i] & (0x0001 << intBit)) != 0) {
highOrderWord ^= ENCRYPTION_MATRIX[tmp][intBit];
int line = maxPasswordLength - arrByteChars.length;
for (byte ch : arrByteChars) {
for (int xor : ENCRYPTION_MATRIX[line++]) {
if ((ch & 1) == 1) {
highOrderWord ^= xor;
}
ch >>>= 1;
}
}
// Compute the low-order word of the new key:
int verifier = createXorVerifier1(password);
// The byte order of the result shall be reversed [password "Example": 0x64CEED7E becomes 7EEDCE64],
// and that value shall be hashed as defined by the attribute values.
LittleEndian.putShort(generatedKey, 0, (short)verifier);
LittleEndian.putShort(generatedKey, 2, (short)highOrderWord);
}
return LittleEndian.getInt(generatedKey);
}
@ -471,16 +473,16 @@ public class CryptoFunctions {
int hashedPassword = createXorVerifier2(password);
return String.format(Locale.ROOT, "%1$08X", hashedPassword);
}
/**
* Convenience function which returns the reversed xored-hashed password for further
* Convenience function which returns the reversed xored-hashed password for further
* processing in word documents 2007 and newer, which utilize a real hashing algorithm like sha1.
*/
public static String xorHashPasswordReversed(String password) {
int hashedPassword = createXorVerifier2(password);
return String.format(Locale.ROOT, "%1$02X%2$02X%3$02X%4$02X"
, ( hashedPassword >>> 0 ) & 0xFF
, (hashedPassword) & 0xFF
, ( hashedPassword >>> 8 ) & 0xFF
, ( hashedPassword >>> 16 ) & 0xFF
, ( hashedPassword >>> 24 ) & 0xFF
@ -492,7 +494,7 @@ public class CryptoFunctions {
*
* @see <a href="http://msdn.microsoft.com/en-us/library/dd924704.aspx">2.3.7.2 Binary Document XOR Array Initialization Method 1</a>
* @see <a href="http://msdn.microsoft.com/en-us/library/dd905229.aspx">2.3.7.4 Binary Document Password Verifier Derivation Method 2</a>
*
*
* @param password the password
* @return the xor key
*/
@ -503,7 +505,7 @@ public class CryptoFunctions {
}
/**
* Creates an byte array for xor obfuscation (method 1)
* Creates an byte array for xor obfuscation (method 1)
*
* @see <a href="http://msdn.microsoft.com/en-us/library/dd924704.aspx">2.3.7.2 Binary Document XOR Array Initialization Method 1</a>
* @see <a href="http://docs.libreoffice.org/oox/html/binarycodec_8cxx_source.html">Libre Office implementation</a>
@ -515,17 +517,17 @@ public class CryptoFunctions {
if (password.length() > 15) {
password = password.substring(0, 15);
}
byte[] passBytes = password.getBytes(Charset.forName("ASCII"));
byte[] passBytes = password.getBytes(StandardCharsets.US_ASCII);
// this code is based on the libre office implementation.
// The MS-OFFCRYPTO misses some infos about the various rotation sizes
// The MS-OFFCRYPTO misses some infos about the various rotation sizes
byte[] obfuscationArray = new byte[16];
System.arraycopy(passBytes, 0, obfuscationArray, 0, passBytes.length);
System.arraycopy(PAD_ARRAY, 0, obfuscationArray, passBytes.length, PAD_ARRAY.length-passBytes.length+1);
int xorKey = createXorKey1(password);
// rotation of key values is application dependent - Excel = 2 / Word = 7
// rotation of key values is application dependent - Excel = 2 / Word = 7
int nRotateSize = 2;
byte[] baseKeyLE = {(byte) (xorKey & 0xFF), (byte) ((xorKey >>> 8) & 0xFF)};
@ -533,26 +535,26 @@ public class CryptoFunctions {
obfuscationArray[i] ^= baseKeyLE[i&1];
obfuscationArray[i] = rotateLeft(obfuscationArray[i], nRotateSize);
}
return obfuscationArray;
}
/**
* The provided Unicode password string is converted to a ANSI string
*
* @param password the password
* @return the ansi bytes
*
*
* @see <a href="http://www.ecma-international.org/news/TC45_current_work/Office%20Open%20XML%20Part%204%20-%20Markup%20Language%20Reference.pdf">Part 4 - Markup Language Reference - Ecma International - section 3.2.29 (workbookProtection)</a>
*/
private static byte[] toAnsiPassword(String password) {
// TODO: charset conversion (see ecma spec)
// TODO: charset conversion (see ecma spec)
// Get the single-byte values by iterating through the Unicode characters.
// For each character, if the low byte is not equal to 0, take it.
// Otherwise, take the high byte.
byte[] arrByteChars = new byte[password.length()];
for (int i = 0; i < password.length(); i++) {
int intTemp = password.charAt(i);
byte lowByte = (byte)(intTemp & 0xFF);
@ -562,11 +564,11 @@ public class CryptoFunctions {
return arrByteChars;
}
private static byte rotateLeft(byte bits, int shift) {
return (byte)(((bits & 0xff) << shift) | ((bits & 0xff) >>> (8 - shift)));
}
private static short rotateLeftBase15Bit(short verifier) {
/*
* IF (Verifier BITWISE AND 0x4000) is 0x0000

View File

@ -27,19 +27,19 @@ import org.apache.poi.util.Internal;
/**
* A seekable InputStream, which is used to decrypt/extract the document entries
* within the encrypted stream
* within the encrypted stream
*/
@Internal
/* package */ class CryptoAPIDocumentInputStream extends ByteArrayInputStream {
private Cipher cipher;
private final CryptoAPIDecryptor decryptor;
private byte[] oneByte = {0};
public void seek(int newpos) {
if (newpos > count) {
throw new ArrayIndexOutOfBoundsException(newpos);
}
this.pos = newpos;
mark = newpos;
}
@ -60,7 +60,7 @@ import org.apache.poi.util.Internal;
} catch (ShortBufferException e) {
throw new EncryptedDocumentException(e);
}
return oneByte[0];
return oneByte[0] & 0xFF;
}
@Override

View File

@ -37,21 +37,21 @@ import org.apache.poi.util.Internal;
this.encryptor = encryptor;
cipher = encryptor.initCipherForBlock(null, 0);
}
public byte[] getBuf() {
return buf;
}
public void setSize(int count) {
this.count = count;
}
public void setBlock(int block) throws GeneralSecurityException {
encryptor.initCipherForBlock(cipher, block);
}
@Override
public void write(int b) {
public synchronized void write(int b) {
try {
oneByte[0] = (byte)b;
cipher.update(oneByte, 0, 1, oneByte, 0);
@ -62,7 +62,7 @@ import org.apache.poi.util.Internal;
}
@Override
public void write(byte[] b, int off, int len) {
public synchronized void write(byte[] b, int off, int len) {
try {
cipher.update(b, off, len, b, off);
super.write(b, off, len);

View File

@ -68,9 +68,9 @@ public final class DocumentInputStream extends InputStream implements LittleEndi
/**
* Create an InputStream from the specified DocumentEntry
*
*
* @param document the DocumentEntry to be read
*
*
* @exception IOException if the DocumentEntry cannot be opened (like, maybe it has
* been deleted?)
*/
@ -91,7 +91,7 @@ public final class DocumentInputStream extends InputStream implements LittleEndi
DocumentNode doc = (DocumentNode)document;
DocumentProperty property = (DocumentProperty)doc.getProperty();
_document = new POIFSDocument(
property,
property,
((DirectoryNode)doc.getParent()).getFileSystem()
);
_data = _document.getBlockIterator();
@ -99,7 +99,7 @@ public final class DocumentInputStream extends InputStream implements LittleEndi
/**
* Create an InputStream from the specified Document
*
*
* @param document the Document to be read
*/
public DocumentInputStream(POIFSDocument document) {
@ -146,7 +146,7 @@ public final class DocumentInputStream extends InputStream implements LittleEndi
}
@Override
public void mark(int ignoredReadlimit) {
public synchronized void mark(int ignoredReadlimit) {
_marked_offset = _current_offset;
_marked_offset_count = Math.max(0, _current_block_count - 1);
}
@ -159,13 +159,7 @@ public final class DocumentInputStream extends InputStream implements LittleEndi
}
byte[] b = new byte[1];
int result = read(b, 0, 1);
if(result >= 0) {
if(b[0] < 0) {
return b[0]+256;
}
return b[0];
}
return result;
return (result == EOF) ? EOF : (b[0] & 0xFF);
}
@Override
@ -199,7 +193,7 @@ public final class DocumentInputStream extends InputStream implements LittleEndi
* method repositions the stream to its beginning.
*/
@Override
public void reset() {
public synchronized void reset() {
// Special case for reset to the start
if(_marked_offset == 0 && _marked_offset_count == 0) {
_current_block_count = _marked_offset_count;
@ -216,15 +210,15 @@ public final class DocumentInputStream extends InputStream implements LittleEndi
_buffer = _data.next();
_current_offset += _buffer.remaining();
}
_current_block_count = _marked_offset_count;
// Do we need to position within it?
if(_current_offset != _marked_offset) {
// Grab the right block
_buffer = _data.next();
_current_block_count++;
// Skip to the right place in it
// (It should be positioned already at the start of the block,
// we need to move further inside the block)
@ -250,9 +244,9 @@ public final class DocumentInputStream extends InputStream implements LittleEndi
} else if (new_offset > _document_size) {
new_offset = _document_size;
}
long rval = new_offset - _current_offset;
// TODO Do this better
byte[] skip = IOUtils.safelyAllocate(rval, Integer.MAX_VALUE);
readFully(skip);
@ -298,7 +292,7 @@ public final class DocumentInputStream extends InputStream implements LittleEndi
_current_block_count++;
_buffer = _data.next();
}
int limit = Math.min(len-read, _buffer.remaining());
_buffer.get(buf, off+read, limit);
_current_offset += limit;

View File

@ -47,17 +47,21 @@ public class DrawFactory {
* This is a fallback, for operations where usercode can't set a graphics context.
* Preferably use the rendering hint {@link Drawable#DRAW_FACTORY} to set the factory.
*
* @param factory the custom factory
* @param factory the custom factory or {@code null} to reset/remove the default factory
*/
@SuppressWarnings("unused")
public static void setDefaultFactory(DrawFactory factory) {
defaultFactory.set(factory);
if (factory == null) {
defaultFactory.remove();
} else {
defaultFactory.set(factory);
}
}
/**
* Returns the DrawFactory, preferably via a graphics instance.
* If graphics is null, the current thread local is checked or
* if it is not set, a new factory is created.
* if it is not set, a new factory is created.
*
* @param graphics the current graphics context or null
* @return the draw factory
@ -112,7 +116,7 @@ public class DrawFactory {
} else if (shape.getClass().isAnnotationPresent(DrawNotImplemented.class)) {
return new DrawNothing(shape);
}
throw new IllegalArgumentException("Unsupported shape type: "+shape.getClass());
}
@ -139,11 +143,11 @@ public class DrawFactory {
public DrawConnectorShape getDrawable(ConnectorShape<?,?> shape) {
return new DrawConnectorShape(shape);
}
public DrawTableShape getDrawable(TableShape<?,?> shape) {
return new DrawTableShape(shape);
}
public DrawTextShape getDrawable(TextShape<?,?> shape) {
return new DrawTextShape(shape);
}
@ -151,15 +155,15 @@ public class DrawFactory {
public DrawGroupShape getDrawable(GroupShape<?,?> shape) {
return new DrawGroupShape(shape);
}
public DrawPictureShape getDrawable(PictureShape<?,?> shape) {
return new DrawPictureShape(shape);
}
public DrawGraphicalFrame getDrawable(GraphicalFrame<?,?> shape) {
return new DrawGraphicalFrame(shape);
}
public DrawTextParagraph getDrawable(TextParagraph<?,?,?> paragraph) {
return new DrawTextParagraph(paragraph);
}
@ -167,12 +171,12 @@ public class DrawFactory {
public DrawBackground getDrawable(Background<?,?> shape) {
return new DrawBackground(shape);
}
@SuppressWarnings("WeakerAccess")
public DrawTextFragment getTextFragment(TextLayout layout, AttributedString str) {
return new DrawTextFragment(layout, str);
}
public DrawPaint getPaint(PlaceableShape<?,?> shape) {
return new DrawPaint(shape);
}
@ -183,7 +187,7 @@ public class DrawFactory {
*
* @param graphics the graphics context to draw to
* @param shape the shape
* @param bounds the bounds within the graphics context to draw to
* @param bounds the bounds within the graphics context to draw to
*/
public void drawShape(Graphics2D graphics, Shape<?,?> shape, Rectangle2D bounds) {
Rectangle2D shapeBounds = shape.getAnchor();
@ -202,7 +206,7 @@ public class DrawFactory {
tx.translate(-shapeBounds.getCenterX(), -shapeBounds.getCenterY());
}
graphics.setRenderingHint(Drawable.GROUP_TRANSFORM, tx);
Drawable d = getDrawable(shape);
d.applyTransform(graphics);
d.draw(graphics);
@ -210,7 +214,7 @@ public class DrawFactory {
graphics.setRenderingHint(Drawable.GROUP_TRANSFORM, txg);
}
}
/**
* Return a FontManager, either registered beforehand or a default implementation

View File

@ -60,56 +60,52 @@ public class DrawShape implements Drawable {
return;
}
final PlaceableShape<?,?> ps = (PlaceableShape<?,?>)shape;
final boolean isHSLF = isHSLF(shape);
final Rectangle2D anchor = getAnchor(graphics, (PlaceableShape<?,?>)shape);
if (anchor == null) {
return;
}
final Rectangle2D anchor = getAnchor(graphics, ps);
char[] cmds = isHSLF ? new char[]{'h', 'v', 'r'} : new char[]{'r', 'h', 'v'};
for (char ch : cmds) {
switch (ch) {
case 'h':
//flip horizontal
if (ps.getFlipHorizontal()) {
graphics.translate(anchor.getX() + anchor.getWidth(), anchor.getY());
graphics.scale(-1, 1);
graphics.translate(-anchor.getX(), -anchor.getY());
}
break;
case 'v':
//flip vertical
if (ps.getFlipVertical()) {
graphics.translate(anchor.getX(), anchor.getY() + anchor.getHeight());
graphics.scale(1, -1);
graphics.translate(-anchor.getX(), -anchor.getY());
}
break;
case 'r':
// rotation
double rotation = ps.getRotation();
if (rotation != 0.) {
// PowerPoint rotates shapes relative to the geometric center
double centerX = anchor.getCenterX();
double centerY = anchor.getCenterY();
// transformation is applied reversed ...
graphics.translate(centerX, centerY);
graphics.rotate(Math.toRadians(rotation));
graphics.translate(-centerX, -centerY);
}
break;
default:
throw new RuntimeException("unexpected transform code " + ch);
}
if (isHSLF(shape)) {
flipHorizontal(graphics, anchor);
flipVertical(graphics, anchor);
rotate(graphics, anchor);
} else {
rotate(graphics, anchor);
flipHorizontal(graphics, anchor);
flipVertical(graphics, anchor);
}
}
private static double safeScale(double dim1, double dim2) {
if (dim1 == 0.) {
return 1;
private void flipHorizontal(Graphics2D graphics, Rectangle2D anchor) {
assert(shape instanceof PlaceableShape && anchor != null);
if (((PlaceableShape<?,?>)shape).getFlipHorizontal()) {
graphics.translate(anchor.getX() + anchor.getWidth(), anchor.getY());
graphics.scale(-1, 1);
graphics.translate(-anchor.getX(), -anchor.getY());
}
return (dim2 == 0.) ? 1 : dim1/dim2;
}
private void flipVertical(Graphics2D graphics, Rectangle2D anchor) {
assert(shape instanceof PlaceableShape && anchor != null);
if (((PlaceableShape<?,?>)shape).getFlipVertical()) {
graphics.translate(anchor.getX(), anchor.getY() + anchor.getHeight());
graphics.scale(1, -1);
graphics.translate(-anchor.getX(), -anchor.getY());
}
}
private void rotate(Graphics2D graphics, Rectangle2D anchor) {
assert(shape instanceof PlaceableShape && anchor != null);
double rotation = ((PlaceableShape<?,?>)shape).getRotation();
if (rotation != 0.) {
// PowerPoint rotates shapes relative to the geometric center
graphics.rotate(Math.toRadians(rotation), anchor.getCenterX(), anchor.getCenterY());
}
}
private static double safeScale(double dim1, double dim2) {
return (dim1 == 0. || dim2 == 0.) ? 1 : dim1/dim2;
}
@Override
@ -160,15 +156,11 @@ public class DrawShape implements Drawable {
// this handling is only based on try and error ... not sure why h/xslf is handled differently.
if (!isHSLF) {
txs2.translate(centerX, centerY);
txs2.quadrantRotate(1);
txs2.translate(-centerX, -centerY);
txs2.quadrantRotate(1, centerX, centerY);
txs2.concatenate(tx);
}
txs2.translate(centerX, centerY);
txs2.quadrantRotate(3);
txs2.translate(-centerX, -centerY);
txs2.quadrantRotate(3, centerX, centerY);
if (isHSLF) {
txs2.concatenate(tx);

View File

@ -18,9 +18,11 @@
package org.apache.poi.ss.formula.functions;
import org.apache.poi.ss.formula.OperationEvaluationContext;
import org.apache.poi.ss.formula.eval.*;
import java.math.BigDecimal;
import org.apache.poi.ss.formula.eval.ErrorEval;
import org.apache.poi.ss.formula.eval.EvaluationException;
import org.apache.poi.ss.formula.eval.NumberEval;
import org.apache.poi.ss.formula.eval.OperandResolver;
import org.apache.poi.ss.formula.eval.ValueEval;
/**
* Implementation for Excel DELTA() function.<p>
@ -46,33 +48,20 @@ public final class Delta extends Fixed2ArgFunction implements FreeRefFunction {
private final static NumberEval ZERO = new NumberEval(0);
public ValueEval evaluate(int srcRowIndex, int srcColumnIndex, ValueEval arg1, ValueEval arg2) {
ValueEval veText1;
try {
veText1 = OperandResolver.getSingleValue(arg1, srcRowIndex, srcColumnIndex);
Double number1 = evaluateValue(arg1, srcRowIndex, srcColumnIndex);
if (number1 == null) {
return ErrorEval.VALUE_INVALID;
}
Double number2 = evaluateValue(arg2, srcRowIndex, srcColumnIndex);
if (number2 == null) {
return ErrorEval.VALUE_INVALID;
}
return (number1.compareTo(number2) == 0) ? ONE : ZERO;
} catch (EvaluationException e) {
return e.getErrorEval();
}
String strText1 = OperandResolver.coerceValueToString(veText1);
Double number1 = OperandResolver.parseDouble(strText1);
if (number1 == null) {
return ErrorEval.VALUE_INVALID;
}
ValueEval veText2;
try {
veText2 = OperandResolver.getSingleValue(arg2, srcRowIndex, srcColumnIndex);
} catch (EvaluationException e) {
return e.getErrorEval();
}
String strText2 = OperandResolver.coerceValueToString(veText2);
Double number2 = OperandResolver.parseDouble(strText2);
if (number2 == null) {
return ErrorEval.VALUE_INVALID;
}
int result = new BigDecimal(number1.doubleValue()).compareTo(new BigDecimal(number2.doubleValue()));
return result == 0 ? ONE : ZERO;
}
public ValueEval evaluate(ValueEval[] args, OperationEvaluationContext ec) {
@ -82,4 +71,10 @@ public final class Delta extends Fixed2ArgFunction implements FreeRefFunction {
return ErrorEval.VALUE_INVALID;
}
private static Double evaluateValue(ValueEval arg, int srcRowIndex, int srcColumnIndex) throws EvaluationException {
ValueEval veText = OperandResolver.getSingleValue(arg, srcRowIndex, srcColumnIndex);
String strText1 = OperandResolver.coerceValueToString(veText);
return OperandResolver.parseDouble(strText1);
}
}

View File

@ -64,7 +64,8 @@ public final class Fixed implements Function1Arg, Function2Arg, Function3Arg {
}
return ErrorEval.VALUE_INVALID;
}
@SuppressWarnings("squid:S2111")
private ValueEval fixed(
ValueEval numberParam, ValueEval placesParam,
ValueEval skipThousandsSeparatorParam,
@ -85,16 +86,16 @@ public final class Fixed implements Function1Arg, Function2Arg, Function3Arg {
Boolean skipThousandsSeparator =
OperandResolver.coerceValueToBoolean(
skipThousandsSeparatorValueEval, false);
// Round number to respective places.
number = number.setScale(places, RoundingMode.HALF_UP);
// Format number conditionally using a thousands separator.
NumberFormat nf = NumberFormat.getNumberInstance(Locale.US);
DecimalFormat formatter = (DecimalFormat)nf;
formatter.setGroupingUsed(!(skipThousandsSeparator != null && skipThousandsSeparator));
formatter.setMinimumFractionDigits(places >= 0 ? places : 0);
formatter.setMaximumFractionDigits(places >= 0 ? places : 0);
formatter.setMinimumFractionDigits(Math.max(places, 0));
formatter.setMaximumFractionDigits(Math.max(places, 0));
String numberString = formatter.format(number.doubleValue());
// Return the result as a StringEval.

View File

@ -31,6 +31,8 @@ import org.apache.poi.ss.formula.eval.ValueEval;
* @see <a href="http://office.microsoft.com/en-us/excel-help/irr-HP005209146.aspx">Excel IRR</a>
*/
public final class Irr implements Function {
private static final int MAX_ITERATION_COUNT = 20;
private static final double ABSOLUTE_ACCURACY = 1E-7;
public ValueEval evaluate(final ValueEval[] args, final int srcRowIndex, final int srcColumnIndex) {
@ -89,27 +91,24 @@ public final class Irr implements Function {
* http://en.wikipedia.org/wiki/Newton%27s_method</a>
*/
public static double irr(double[] values, double guess) {
final int maxIterationCount = 20;
final double absoluteAccuracy = 1E-7;
double x0 = guess;
double x1;
int i = 0;
while (i < maxIterationCount) {
for (int i = 0; i < MAX_ITERATION_COUNT; i++) {
// the value of the function (NPV) and its derivate can be calculated in the same loop
final double factor = 1.0 + x0;
int k = 0;
double fValue = values[k];
double denominator = factor;
if (denominator == 0) {
return Double.NaN;
}
double fValue = values[0];
double fDerivative = 0;
for (double denominator = factor; ++k < values.length; ) {
for (int k = 1; k < values.length; k++) {
final double value = values[k];
fValue += value / denominator;
denominator *= factor;
if (denominator == 0) {
return Double.NaN;
}
fDerivative -= k * value / denominator;
}
@ -117,14 +116,13 @@ public final class Irr implements Function {
if (fDerivative == 0) {
return Double.NaN;
}
x1 = x0 - fValue/fDerivative;
double x1 = x0 - fValue/fDerivative;
if (Math.abs(x1 - x0) <= absoluteAccuracy) {
if (Math.abs(x1 - x0) <= ABSOLUTE_ACCURACY) {
return x1;
}
x0 = x1;
++i;
}
// maximum number of iterations is exceeded
return Double.NaN;

View File

@ -16,7 +16,7 @@
2012 - Alfresco Software, Ltd.
Alfresco Software has modified source of this file
The details of changes as svn diff can be found in svn at location root/projects/3rd-party/src
The details of changes as svn diff can be found in svn at location root/projects/3rd-party/src
==================================================================== */
package org.apache.poi.ss.usermodel;
@ -111,12 +111,12 @@ import org.apache.poi.util.POILogger;
* <p>
* Some formats are automatically "localized" by Excel, eg show as mm/dd/yyyy when
* loaded in Excel in some Locales but as dd/mm/yyyy in others. These are always
* returned in the "default" (US) format, as stored in the file.
* Some format strings request an alternate locale, eg
* returned in the "default" (US) format, as stored in the file.
* Some format strings request an alternate locale, eg
* <code>[$-809]d/m/yy h:mm AM/PM</code> which explicitly requests UK locale.
* These locale directives are (currently) ignored.
* You can use {@link DateFormatConverter} to do some of this localisation if
* you need it.
* you need it.
*/
public class DataFormatter implements Observer {
private static final String defaultFractionWholePartFormat = "#";
@ -129,13 +129,13 @@ public class DataFormatter implements Observer {
/** Pattern to find "AM/PM" marker */
private static final Pattern amPmPattern = Pattern.compile("(([AP])[M/P]*)", Pattern.CASE_INSENSITIVE);
/** Pattern to find formats with condition ranges e.g. [>=100] */
private static final Pattern rangeConditionalPattern = Pattern.compile(".*\\[\\s*(>|>=|<|<=|=)\\s*[0-9]*\\.*[0-9].*");
/**
/**
* A regex to find locale patterns like [$$-1009] and [$?-452].
* Note that we don't currently process these into locales
* Note that we don't currently process these into locales
*/
private static final Pattern localePatternGroup = Pattern.compile("(\\[\\$[^-\\]]*-[0-9A-Z]+])");
@ -144,14 +144,14 @@ public class DataFormatter implements Observer {
* Allowed colours are: Black, Blue, Cyan, Green,
* Magenta, Red, White, Yellow, "Color n" (1<=n<=56)
*/
private static final Pattern colorPattern =
private static final Pattern colorPattern =
Pattern.compile("(\\[BLACK])|(\\[BLUE])|(\\[CYAN])|(\\[GREEN])|" +
"(\\[MAGENTA])|(\\[RED])|(\\[WHITE])|(\\[YELLOW])|" +
"(\\[COLOR\\s*\\d])|(\\[COLOR\\s*[0-5]\\d])", Pattern.CASE_INSENSITIVE);
/**
* A regex to identify a fraction pattern.
* This requires that replaceAll("\\?", "#") has already been called
* This requires that replaceAll("\\?", "#") has already been called
*/
private static final Pattern fractionPattern = Pattern.compile("(?:([#\\d]+)\\s+)?(#+)\\s*/\\s*([#\\d]+)");
@ -162,10 +162,10 @@ public class DataFormatter implements Observer {
/**
* A regex to detect if an alternate grouping character is used
* in a numeric format
* in a numeric format
*/
private static final Pattern alternateGrouping = Pattern.compile("([#0]([^.#0])[#0]{3})");
/**
* Cells formatted with a date or time format and which contain invalid date or time values
* show 255 pound signs ("#").
@ -191,7 +191,7 @@ public class DataFormatter implements Observer {
* A default date format, if no date format was given
*/
private DateFormat defaultDateformat;
/** <em>General</em> format for numbers. */
private Format generalNumberFormat;
@ -208,10 +208,10 @@ public class DataFormatter implements Observer {
/** stores the locale valid it the last formatting call */
private Locale locale;
/** stores if the locale should change according to {@link LocaleUtil#getUserLocale()} */
private boolean localeIsAdapting;
private class LocaleChangeObservable extends Observable {
void checkForLocaleChange() {
checkForLocaleChange(LocaleUtil.getUserLocale());
@ -223,13 +223,13 @@ public class DataFormatter implements Observer {
notifyObservers(newLocale);
}
}
/** the Observable to notify, when the locale has been changed */
private final LocaleChangeObservable localeChangedObservable = new LocaleChangeObservable();
/** For logging any problems we find */
private static POILogger logger = POILogFactory.getLogger(DataFormatter.class);
/**
* Creates a formatter using the {@link Locale#getDefault() default locale}.
*/
@ -281,7 +281,7 @@ public class DataFormatter implements Observer {
/**
* Return a Format for the given cell if one exists, otherwise try to
* create one. This method will return <code>null</code> if the any of the
* create one. This method will return <code>null</code> if any of the
* following is true:
* <ul>
* <li>the cell's style is null</li>
@ -294,9 +294,9 @@ public class DataFormatter implements Observer {
*/
private Format getFormat(Cell cell, ConditionalFormattingEvaluator cfEvaluator) {
if (cell == null) return null;
ExcelNumberFormat numFmt = ExcelNumberFormat.from(cell, cfEvaluator);
if ( numFmt == null) {
return null;
}
@ -316,25 +316,25 @@ public class DataFormatter implements Observer {
}
return false;
}
private Format getFormat(double cellValue, int formatIndex, String formatStrIn, boolean use1904Windowing) {
localeChangedObservable.checkForLocaleChange();
// Might be better to separate out the n p and z formats, falling back to p when n and z are not set.
// That however would require other code to be re factored.
// String[] formatBits = formatStrIn.split(";");
// int i = cellValue > 0.0 ? 0 : cellValue < 0.0 ? 1 : 2;
// int i = cellValue > 0.0 ? 0 : cellValue < 0.0 ? 1 : 2;
// String formatStr = (i < formatBits.length) ? formatBits[i] : formatBits[0];
String formatStr = formatStrIn;
// Excel supports 2+ part conditional data formats, eg positive/negative/zero,
// or (>1000),(>0),(0),(negative). As Java doesn't handle these kinds
// of different formats for different ranges, just +ve/-ve, we need to
// of different formats for different ranges, just +ve/-ve, we need to
// handle these ourselves in a special way.
// For now, if we detect 2+ parts, we call out to CellFormat to handle it
// TODO Going forward, we should really merge the logic between the two classes
if (formatStr.contains(";") &&
if (formatStr.contains(";") &&
(formatStr.indexOf(';') != formatStr.lastIndexOf(';')
|| rangeConditionalPattern.matcher(formatStr).matches()
) ) {
@ -343,8 +343,8 @@ public class DataFormatter implements Observer {
CellFormat cfmt = CellFormat.getInstance(locale, formatStr);
// CellFormat requires callers to identify date vs not, so do so
Object cellValueO = Double.valueOf(cellValue);
if (DateUtil.isADateFormat(formatIndex, formatStr) &&
// don't try to handle Date value 0, let a 3 or 4-part format take care of it
if (DateUtil.isADateFormat(formatIndex, formatStr) &&
// don't try to handle Date value 0, let a 3 or 4-part format take care of it
((Double)cellValueO).doubleValue() != 0.0) {
cellValueO = DateUtil.getJavaDate(cellValue, use1904Windowing);
}
@ -354,23 +354,23 @@ public class DataFormatter implements Observer {
logger.log(POILogger.WARN, "Formatting failed for format " + formatStr + ", falling back", e);
}
}
// Excel's # with value 0 will output empty where Java will output 0. This hack removes the # from the format.
if (emulateCSV && cellValue == 0.0 && formatStr.contains("#") && !formatStr.contains("0")) {
formatStr = formatStr.replaceAll("#", "");
}
// See if we already have it cached
Format format = formats.get(formatStr);
if (format != null) {
return format;
}
// Is it one of the special built in types, General or @?
if ("General".equalsIgnoreCase(formatStr) || "@".equals(formatStr)) {
return generalNumberFormat;
}
// Build a formatter, and cache it
format = createFormat(cellValue, formatIndex, formatStr);
formats.put(formatStr, format);
@ -393,14 +393,14 @@ public class DataFormatter implements Observer {
private Format createFormat(double cellValue, int formatIndex, String sFormat) {
localeChangedObservable.checkForLocaleChange();
String formatStr = sFormat;
// Remove colour formatting if present
Matcher colourM = colorPattern.matcher(formatStr);
while(colourM.find()) {
String colour = colourM.group();
// Paranoid replacement...
int at = formatStr.indexOf(colour);
if(at == -1) break;
@ -431,7 +431,7 @@ public class DataFormatter implements Observer {
if(formatStr == null || formatStr.trim().length() == 0) {
return getDefaultFormat(cellValue);
}
if ("General".equalsIgnoreCase(formatStr) || "@".equals(formatStr)) {
return generalNumberFormat;
}
@ -455,12 +455,12 @@ public class DataFormatter implements Observer {
return new FractionFormat(wholePart, fractionMatcher.group(3));
}
}
// Strip custom text in quotes and escaped characters for now as it can cause performance problems in fractions.
//String strippedFormatStr = formatStr.replaceAll("\\\\ ", " ").replaceAll("\\\\.", "").replaceAll("\"[^\"]*\"", " ").replaceAll("\\?", "#");
return new FractionFormat(defaultFractionWholePartFormat, defaultFractionFractionPartFormat);
}
if (numPattern.matcher(formatStr).find()) {
return createNumberFormat(formatStr, cellValue);
}
@ -471,8 +471,8 @@ public class DataFormatter implements Observer {
// TODO - when does this occur?
return null;
}
private Format createDateFormat(String pFormatStr, double cellValue) {
String formatStr = pFormatStr;
@ -480,7 +480,7 @@ public class DataFormatter implements Observer {
formatStr = formatStr.replaceAll("\\\\,",",");
formatStr = formatStr.replaceAll("\\\\\\.","."); // . is a special regexp char
formatStr = formatStr.replaceAll("\\\\ "," ");
formatStr = formatStr.replaceAll("\\\\/","/"); // weird: m\\/d\\/yyyy
formatStr = formatStr.replaceAll("\\\\/","/"); // weird: m\\/d\\/yyyy
formatStr = formatStr.replaceAll(";@", "");
formatStr = formatStr.replaceAll("\"/\"", "/"); // "/" is escaped for no reason in: mm"/"dd"/"yyyy
formatStr = formatStr.replace("\"\"", "'"); // replace Excel quoting with Java style quoting
@ -675,7 +675,7 @@ public class DataFormatter implements Observer {
}
}
// Now, handle the other aspects like
// Now, handle the other aspects like
// quoting and scientific notation
for(int i = 0; i < sb.length(); i++) {
char c = sb.charAt(i);
@ -748,7 +748,7 @@ public class DataFormatter implements Observer {
private Format createNumberFormat(String formatStr, double cellValue) {
String format = cleanFormatForNumber(formatStr);
DecimalFormatSymbols symbols = decimalSymbols;
// Do we need to change the grouping character?
// eg for a format like #'##0 which wants 12'345 not 12,345
Matcher agm = alternateGrouping.matcher(format);
@ -766,7 +766,7 @@ public class DataFormatter implements Observer {
format = format.replace(oldPart, newPart);
}
}
try {
return new InternalDecimalFormatWithScale(format, symbols);
} catch(IllegalArgumentException iae) {
@ -787,7 +787,7 @@ public class DataFormatter implements Observer {
}
private Format getDefaultFormat(double cellValue) {
localeChangedObservable.checkForLocaleChange();
// for numeric cells try user supplied default
if (defaultNumFormat != null) {
return defaultNumFormat;
@ -826,6 +826,16 @@ public class DataFormatter implements Observer {
return null;
}
Format dateFormat = getFormat(cell, cfEvaluator);
if (dateFormat == null) {
if (defaultDateformat == null) {
DateFormatSymbols sym = DateFormatSymbols.getInstance(LocaleUtil.getUserLocale());
SimpleDateFormat sdf = new SimpleDateFormat("EEE MMM dd HH:mm:ss zzz yyyy", sym);
sdf.setTimeZone(LocaleUtil.getUserTimeZone());
dateFormat = sdf;
} else {
dateFormat = defaultNumFormat;
}
}
synchronized (dateFormat) {
if(dateFormat instanceof ExcelStyleDateFormatter) {
// Hint about the raw excel value
@ -846,7 +856,7 @@ public class DataFormatter implements Observer {
* <p>
* Format comes from either the highest priority conditional format rule with a
* specified format, or from the cell style.
*
*
* @param cell The cell
* @param cfEvaluator if available, or null
* @return a formatted number string
@ -879,7 +889,7 @@ public class DataFormatter implements Observer {
*/
public String formatRawCellContents(double value, int formatIndex, String formatString, boolean use1904Windowing) {
localeChangedObservable.checkForLocaleChange();
// Is it a date?
if(DateUtil.isADateFormat(formatIndex,formatString)) {
if(DateUtil.isValidExcelDate(value)) {
@ -896,13 +906,13 @@ public class DataFormatter implements Observer {
return invalidDateTimeString;
}
}
// else Number
Format numberFormat = getFormat(value, formatIndex, formatString, use1904Windowing);
if (numberFormat == null) {
return String.valueOf(value);
}
// When formatting 'value', double to text to BigDecimal produces more
// accurate results than double to Double in JDK8 (as compared to
// previous versions). However, if the value contains E notation, this
@ -960,7 +970,7 @@ public class DataFormatter implements Observer {
public String formatCellValue(Cell cell, FormulaEvaluator evaluator) {
return formatCellValue(cell, evaluator, null);
}
/**
* <p>
* Returns the formatted value of a cell as a <tt>String</tt> regardless
@ -990,7 +1000,7 @@ public class DataFormatter implements Observer {
*/
public String formatCellValue(Cell cell, FormulaEvaluator evaluator, ConditionalFormattingEvaluator cfEvaluator) {
localeChangedObservable.checkForLocaleChange();
if (cell == null) {
return "";
}
@ -1077,9 +1087,9 @@ public class DataFormatter implements Observer {
result.setParseIntegerOnly(true);
return result;
}
/**
* Enables excel style rounding mode (round half up) on the
* Enables excel style rounding mode (round half up) on the
* Decimal Format given.
*/
public static void setExcelStyleRoundingMode(DecimalFormat format) {
@ -1119,16 +1129,16 @@ public class DataFormatter implements Observer {
if (!(localeObj instanceof Locale)) return;
Locale newLocale = (Locale)localeObj;
if (!localeIsAdapting || newLocale.equals(locale)) return;
locale = newLocale;
dateSymbols = DateFormatSymbols.getInstance(locale);
decimalSymbols = DecimalFormatSymbols.getInstance(locale);
generalNumberFormat = new ExcelGeneralNumberFormat(locale);
// taken from Date.toString()
defaultDateformat = new SimpleDateFormat("EEE MMM dd HH:mm:ss zzz yyyy", dateSymbols);
defaultDateformat.setTimeZone(LocaleUtil.getUserTimeZone());
defaultDateformat.setTimeZone(LocaleUtil.getUserTimeZone());
// init built-in formats
@ -1262,10 +1272,10 @@ public class DataFormatter implements Observer {
return df.parseObject(source, pos);
}
}
/**
* Format class that does nothing and always returns a constant string.
*
@ -1294,7 +1304,7 @@ public class DataFormatter implements Observer {
}
/**
* Workaround until we merge {@link DataFormatter} with {@link CellFormat}.
* Constant, non-cachable wrapper around a {@link CellFormatResult}
* Constant, non-cachable wrapper around a {@link CellFormatResult}
*/
@SuppressWarnings("serial")
private final class CellFormatResultWrapper extends Format {

View File

@ -16,7 +16,7 @@
2012 - Alfresco Software, Ltd.
Alfresco Software has modified source of this file
The details of changes as svn diff can be found in svn at location root/projects/3rd-party/src
The details of changes as svn diff can be found in svn at location root/projects/3rd-party/src
==================================================================== */
package org.apache.poi.ss.usermodel;
@ -55,6 +55,7 @@ public class ExcelGeneralNumberFormat extends Format {
DataFormatter.setExcelStyleRoundingMode(decimalFormat);
}
@SuppressWarnings("squid:S2111")
public StringBuffer format(Object number, StringBuffer toAppendTo, FieldPosition pos) {
final double value;
if (number instanceof Number) {

View File

@ -31,11 +31,11 @@ import org.apache.poi.util.POILogger;
/**
* <p>Format class that handles Excel style fractions, such as "# #/#" and "#/###"</p>
*
*
* <p>As of this writing, this is still not 100% accurate, but it does a reasonable job
* of trying to mimic Excel's fraction calculations. It does not currently
* maintain Excel's spacing.</p>
*
*
* <p>This class relies on a method lifted nearly verbatim from org.apache.math.fraction.
* If further uses for Commons Math are found, we will consider adding it as a dependency.
* For now, we have in-lined the one method to keep things simple.</p>
@ -43,7 +43,7 @@ import org.apache.poi.util.POILogger;
@SuppressWarnings("serial")
public class FractionFormat extends Format {
private static final POILogger LOGGER = POILogFactory.getLogger(FractionFormat.class);
private static final POILogger LOGGER = POILogFactory.getLogger(FractionFormat.class);
private static final Pattern DENOM_FORMAT_PATTERN = Pattern.compile("(?:(#+)|(\\d+))");
//this was chosen to match the earlier limitation of max denom power
@ -78,7 +78,7 @@ public class FractionFormat extends Format {
try{
tmpExact = Integer.parseInt(m.group(2));
//if the denom is 0, fall back to the default: tmpExact=100
if (tmpExact == 0){
tmpExact = -1;
}
@ -104,10 +104,11 @@ public class FractionFormat extends Format {
maxDenom = tmpMax;
}
@SuppressWarnings("squid:S2111")
public String format(Number num) {
final BigDecimal doubleValue = new BigDecimal(num.doubleValue());
final boolean isNeg = doubleValue.compareTo(BigDecimal.ZERO) < 0;
final BigDecimal absValue = doubleValue.abs();
@ -117,7 +118,7 @@ public class FractionFormat extends Format {
if (wholePart.add(decPart).compareTo(BigDecimal.ZERO) == 0) {
return "0";
}
// if the absolute value is smaller than 1 over the exact or maxDenom
// you can stop here and return "0"
// reciprocal is result of an int devision ... and so it's nearly always 0
@ -125,10 +126,10 @@ public class FractionFormat extends Format {
// if (absDoubleValue < reciprocal) {
// return "0";
// }
//this is necessary to prevent overflow in the maxDenom calculation
if (decPart.compareTo(BigDecimal.ZERO) == 0){
StringBuilder sb = new StringBuilder();
if (isNeg){
sb.append("-");
@ -136,7 +137,7 @@ public class FractionFormat extends Format {
sb.append(wholePart);
return sb.toString();
}
final SimpleFraction fract;
try {
//this should be the case because of the constructor
@ -151,12 +152,12 @@ public class FractionFormat extends Format {
}
StringBuilder sb = new StringBuilder();
//now format the results
if (isNeg){
sb.append("-");
}
//if whole part has to go into the numerator
if (wholePartFormatString == null || wholePartFormatString.isEmpty()){
final int fden = fract.getDenominator();
@ -165,8 +166,8 @@ public class FractionFormat extends Format {
sb.append(trueNum.toBigInteger()).append("/").append(fden);
return sb.toString();
}
//short circuit if fraction is 0 or 1
if (fract.getNumerator() == 0){
sb.append(wholePart);
@ -190,5 +191,5 @@ public class FractionFormat extends Format {
public Object parseObject(String source, ParsePosition pos) {
throw new NotImplementedException("Reverse parsing not supported");
}
}

View File

@ -820,7 +820,7 @@ public class HemfPlusDraw {
}
}
@SuppressWarnings("squid:S2111")
static double round10(double d) {
return new BigDecimal(d).setScale(10, RoundingMode.HALF_UP).doubleValue();
}