diff --git a/LICENSE b/LICENSE index 422570d..341c30b 100644 --- a/LICENSE +++ b/LICENSE @@ -1,339 +1,166 @@ -GNU GENERAL PUBLIC LICENSE - Version 2, June 1991 + GNU LESSER GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 - Copyright (C) 1989, 1991 Free Software Foundation, Inc., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Copyright (C) 2007 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. - Preamble - - The licenses for most software are designed to take away your -freedom to share and change it. By contrast, the GNU General Public -License is intended to guarantee your freedom to share and change free -software--to make sure the software is free for all its users. This -General Public License applies to most of the Free Software -Foundation's software and to any other program whose authors commit to -using it. (Some other Free Software Foundation software is covered by -the GNU Lesser General Public License instead.) You can apply it to -your programs, too. - - When we speak of free software, we are referring to freedom, not -price. Our General Public Licenses are designed to make sure that you -have the freedom to distribute copies of free software (and charge for -this service if you wish), that you receive source code or can get it -if you want it, that you can change the software or use pieces of it -in new free programs; and that you know you can do these things. - - To protect your rights, we need to make restrictions that forbid -anyone to deny you these rights or to ask you to surrender the rights. -These restrictions translate to certain responsibilities for you if you -distribute copies of the software, or if you modify it. - - For example, if you distribute copies of such a program, whether -gratis or for a fee, you must give the recipients all the rights that -you have. You must make sure that they, too, receive or can get the -source code. And you must show them these terms so they know their -rights. - - We protect your rights with two steps: (1) copyright the software, and -(2) offer you this license which gives you legal permission to copy, -distribute and/or modify the software. - - Also, for each author's protection and ours, we want to make certain -that everyone understands that there is no warranty for this free -software. If the software is modified by someone else and passed on, we -want its recipients to know that what they have is not the original, so -that any problems introduced by others will not reflect on the original -authors' reputations. - - Finally, any free program is threatened constantly by software -patents. We wish to avoid the danger that redistributors of a free -program will individually obtain patent licenses, in effect making the -program proprietary. To prevent this, we have made it clear that any -patent must be licensed for everyone's free use or not licensed at all. - - The precise terms and conditions for copying, distribution and -modification follow. - - GNU GENERAL PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. This License applies to any program or other work which contains -a notice placed by the copyright holder saying it may be distributed -under the terms of this General Public License. The "Program", below, -refers to any such program or work, and a "work based on the Program" -means either the Program or any derivative work under copyright law: -that is to say, a work containing the Program or a portion of it, -either verbatim or with modifications and/or translated into another -language. (Hereinafter, translation is included without limitation in -the term "modification".) Each licensee is addressed as "you". - -Activities other than copying, distribution and modification are not -covered by this License; they are outside its scope. The act of -running the Program is not restricted, and the output from the Program -is covered only if its contents constitute a work based on the -Program (independent of having been made by running the Program). -Whether that is true depends on what the Program does. - - 1. You may copy and distribute verbatim copies of the Program's -source code as you receive it, in any medium, provided that you -conspicuously and appropriately publish on each copy an appropriate -copyright notice and disclaimer of warranty; keep intact all the -notices that refer to this License and to the absence of any warranty; -and give any other recipients of the Program a copy of this License -along with the Program. - -You may charge a fee for the physical act of transferring a copy, and -you may at your option offer warranty protection in exchange for a fee. - - 2. You may modify your copy or copies of the Program or any portion -of it, thus forming a work based on the Program, and copy and -distribute such modifications or work under the terms of Section 1 -above, provided that you also meet all of these conditions: - - a) You must cause the modified files to carry prominent notices - stating that you changed the files and the date of any change. - - b) You must cause any work that you distribute or publish, that in - whole or in part contains or is derived from the Program or any - part thereof, to be licensed as a whole at no charge to all third - parties under the terms of this License. - - c) If the modified program normally reads commands interactively - when run, you must cause it, when started running for such - interactive use in the most ordinary way, to print or display an - announcement including an appropriate copyright notice and a - notice that there is no warranty (or else, saying that you provide - a warranty) and that users may redistribute the program under - these conditions, and telling the user how to view a copy of this - License. (Exception: if the Program itself is interactive but - does not normally print such an announcement, your work based on - the Program is not required to print an announcement.) - -These requirements apply to the modified work as a whole. If -identifiable sections of that work are not derived from the Program, -and can be reasonably considered independent and separate works in -themselves, then this License, and its terms, do not apply to those -sections when you distribute them as separate works. But when you -distribute the same sections as part of a whole which is a work based -on the Program, the distribution of the whole must be on the terms of -this License, whose permissions for other licensees extend to the -entire whole, and thus to each and every part regardless of who wrote it. - -Thus, it is not the intent of this section to claim rights or contest -your rights to work written entirely by you; rather, the intent is to -exercise the right to control the distribution of derivative or -collective works based on the Program. - -In addition, mere aggregation of another work not based on the Program -with the Program (or with a work based on the Program) on a volume of -a storage or distribution medium does not bring the other work under -the scope of this License. - - 3. You may copy and distribute the Program (or a work based on it, -under Section 2) in object code or executable form under the terms of -Sections 1 and 2 above provided that you also do one of the following: - - a) Accompany it with the complete corresponding machine-readable - source code, which must be distributed under the terms of Sections - 1 and 2 above on a medium customarily used for software interchange; or, - - b) Accompany it with a written offer, valid for at least three - years, to give any third party, for a charge no more than your - cost of physically performing source distribution, a complete - machine-readable copy of the corresponding source code, to be - distributed under the terms of Sections 1 and 2 above on a medium - customarily used for software interchange; or, - - c) Accompany it with the information you received as to the offer - to distribute corresponding source code. (This alternative is - allowed only for noncommercial distribution and only if you - received the program in object code or executable form with such - an offer, in accord with Subsection b above.) - -The source code for a work means the preferred form of the work for -making modifications to it. For an executable work, complete source -code means all the source code for all modules it contains, plus any -associated interface definition files, plus the scripts used to -control compilation and installation of the executable. However, as a -special exception, the source code distributed need not include -anything that is normally distributed (in either source or binary -form) with the major components (compiler, kernel, and so on) of the -operating system on which the executable runs, unless that component -itself accompanies the executable. - -If distribution of executable or object code is made by offering -access to copy from a designated place, then offering equivalent -access to copy the source code from the same place counts as -distribution of the source code, even though third parties are not -compelled to copy the source along with the object code. - - 4. You may not copy, modify, sublicense, or distribute the Program -except as expressly provided under this License. Any attempt -otherwise to copy, modify, sublicense or distribute the Program is -void, and will automatically terminate your rights under this License. -However, parties who have received copies, or rights, from you under -this License will not have their licenses terminated so long as such -parties remain in full compliance. - - 5. You are not required to accept this License, since you have not -signed it. However, nothing else grants you permission to modify or -distribute the Program or its derivative works. These actions are -prohibited by law if you do not accept this License. Therefore, by -modifying or distributing the Program (or any work based on the -Program), you indicate your acceptance of this License to do so, and -all its terms and conditions for copying, distributing or modifying -the Program or works based on it. - - 6. Each time you redistribute the Program (or any work based on the -Program), the recipient automatically receives a license from the -original licensor to copy, distribute or modify the Program subject to -these terms and conditions. You may not impose any further -restrictions on the recipients' exercise of the rights granted herein. -You are not responsible for enforcing compliance by third parties to -this License. - - 7. If, as a consequence of a court judgment or allegation of patent -infringement or for any other reason (not limited to patent issues), -conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot -distribute so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you -may not distribute the Program at all. For example, if a patent -license would not permit royalty-free redistribution of the Program by -all those who receive copies directly or indirectly through you, then -the only way you could satisfy both it and this License would be to -refrain entirely from distribution of the Program. - -If any portion of this section is held invalid or unenforceable under -any particular circumstance, the balance of the section is intended to -apply and the section as a whole is intended to apply in other -circumstances. - -It is not the purpose of this section to induce you to infringe any -patents or other property right claims or to contest validity of any -such claims; this section has the sole purpose of protecting the -integrity of the free software distribution system, which is -implemented by public license practices. Many people have made -generous contributions to the wide range of software distributed -through that system in reliance on consistent application of that -system; it is up to the author/donor to decide if he or she is willing -to distribute software through any other system and a licensee cannot -impose that choice. - -This section is intended to make thoroughly clear what is believed to -be a consequence of the rest of this License. - - 8. If the distribution and/or use of the Program is restricted in -certain countries either by patents or by copyrighted interfaces, the -original copyright holder who places the Program under this License -may add an explicit geographical distribution limitation excluding -those countries, so that distribution is permitted only in or among -countries not thus excluded. In such case, this License incorporates -the limitation as if written in the body of this License. - - 9. The Free Software Foundation may publish revised and/or new versions -of the General Public License from time to time. Such new versions will -be similar in spirit to the present version, but may differ in detail to -address new problems or concerns. - -Each version is given a distinguishing version number. If the Program -specifies a version number of this License which applies to it and "any -later version", you have the option of following the terms and conditions -either of that version or of any later version published by the Free -Software Foundation. If the Program does not specify a version number of -this License, you may choose any version ever published by the Free Software -Foundation. - - 10. If you wish to incorporate parts of the Program into other free -programs whose distribution conditions are different, write to the author -to ask for permission. For software which is copyrighted by the Free -Software Foundation, write to the Free Software Foundation; we sometimes -make exceptions for this. Our decision will be guided by the two goals -of preserving the free status of all derivatives of our free software and -of promoting the sharing and reuse of software generally. - - NO WARRANTY - - 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY -FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN -OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES -PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED -OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS -TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE -PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, -REPAIR OR CORRECTION. - - 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR -REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, -INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING -OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED -TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY -YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER -PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE -POSSIBILITY OF SUCH DAMAGES. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Programs - - If you develop a new program, and you want it to be of the greatest -possible use to the public, the best way to achieve this is to make it -free software which everyone can redistribute and change under these terms. - - To do so, attach the following notices to the program. It is safest -to attach them to the start of each source file to most effectively -convey the exclusion of warranty; and each file should have at least -the "copyright" line and a pointer to where the full notice is found. - - modified jexcelApi library - Copyright (C) 2013 loginus - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License along - with this program; if not, write to the Free Software Foundation, Inc., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - -Also add information on how to contact you by electronic and paper mail. - -If the program is interactive, make it output a short notice like this -when it starts in an interactive mode: - - Gnomovision version 69, Copyright (C) year name of author - Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. - This is free software, and you are welcome to redistribute it - under certain conditions; type `show c' for details. - -The hypothetical commands `show w' and `show c' should show the appropriate -parts of the General Public License. Of course, the commands you use may -be called something other than `show w' and `show c'; they could even be -mouse-clicks or menu items--whatever suits your program. - -You should also get your employer (if you work as a programmer) or your -school, if any, to sign a "copyright disclaimer" for the program, if -necessary. Here is a sample; alter the names: - - Yoyodyne, Inc., hereby disclaims all copyright interest in the program - `Gnomovision' (which makes passes at compilers) written by James Hacker. - - {signature of Ty Coon}, 1 April 1989 - Ty Coon, President of Vice - -This General Public License does not permit incorporating your program into -proprietary programs. If your program is a subroutine library, you may -consider it more useful to permit linking proprietary applications with the -library. If this is what you want to do, use the GNU Lesser General -Public License instead of this License. + + This version of the GNU Lesser General Public License incorporates +the terms and conditions of version 3 of the GNU General Public +License, supplemented by the additional permissions listed below. + + 0. Additional Definitions. + + As used herein, "this License" refers to version 3 of the GNU Lesser +General Public License, and the "GNU GPL" refers to version 3 of the GNU +General Public License. + + "The Library" refers to a covered work governed by this License, +other than an Application or a Combined Work as defined below. + + An "Application" is any work that makes use of an interface provided +by the Library, but which is not otherwise based on the Library. +Defining a subclass of a class defined by the Library is deemed a mode +of using an interface provided by the Library. + + A "Combined Work" is a work produced by combining or linking an +Application with the Library. The particular version of the Library +with which the Combined Work was made is also called the "Linked +Version". + + The "Minimal Corresponding Source" for a Combined Work means the +Corresponding Source for the Combined Work, excluding any source code +for portions of the Combined Work that, considered in isolation, are +based on the Application, and not on the Linked Version. + + The "Corresponding Application Code" for a Combined Work means the +object code and/or source code for the Application, including any data +and utility programs needed for reproducing the Combined Work from the +Application, but excluding the System Libraries of the Combined Work. + + 1. Exception to Section 3 of the GNU GPL. + + You may convey a covered work under sections 3 and 4 of this License +without being bound by section 3 of the GNU GPL. + + 2. Conveying Modified Versions. + + If you modify a copy of the Library, and, in your modifications, a +facility refers to a function or data to be supplied by an Application +that uses the facility (other than as an argument passed when the +facility is invoked), then you may convey a copy of the modified +version: + + a) under this License, provided that you make a good faith effort to + ensure that, in the event an Application does not supply the + function or data, the facility still operates, and performs + whatever part of its purpose remains meaningful, or + + b) under the GNU GPL, with none of the additional permissions of + this License applicable to that copy. + + 3. Object Code Incorporating Material from Library Header Files. + + The object code form of an Application may incorporate material from +a header file that is part of the Library. You may convey such object +code under terms of your choice, provided that, if the incorporated +material is not limited to numerical parameters, data structure +layouts and accessors, or small macros, inline functions and templates +(ten or fewer lines in length), you do both of the following: + + a) Give prominent notice with each copy of the object code that the + Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the object code with a copy of the GNU GPL and this license + document. + + 4. Combined Works. + + You may convey a Combined Work under terms of your choice that, +taken together, effectively do not restrict modification of the +portions of the Library contained in the Combined Work and reverse +engineering for debugging such modifications, if you also do each of +the following: + + a) Give prominent notice with each copy of the Combined Work that + the Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the Combined Work with a copy of the GNU GPL and this license + document. + + c) For a Combined Work that displays copyright notices during + execution, include the copyright notice for the Library among + these notices, as well as a reference directing the user to the + copies of the GNU GPL and this license document. + + d) Do one of the following: + + 0) Convey the Minimal Corresponding Source under the terms of this + License, and the Corresponding Application Code in a form + suitable for, and under terms that permit, the user to + recombine or relink the Application with a modified version of + the Linked Version to produce a modified Combined Work, in the + manner specified by section 6 of the GNU GPL for conveying + Corresponding Source. + + 1) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (a) uses at run time + a copy of the Library already present on the user's computer + system, and (b) will operate properly with a modified version + of the Library that is interface-compatible with the Linked + Version. + + e) Provide Installation Information, but only if you would otherwise + be required to provide such information under section 6 of the + GNU GPL, and only to the extent that such information is + necessary to install and execute a modified version of the + Combined Work produced by recombining or relinking the + Application with a modified version of the Linked Version. (If + you use option 4d0, the Installation Information must accompany + the Minimal Corresponding Source and Corresponding Application + Code. If you use option 4d1, you must provide the Installation + Information in the manner specified by section 6 of the GNU GPL + for conveying Corresponding Source.) + + 5. Combined Libraries. + + You may place library facilities that are a work based on the +Library side by side in a single library together with other library +facilities that are not Applications and are not covered by this +License, and convey such a combined library under terms of your +choice, if you do both of the following: + + a) Accompany the combined library with a copy of the same work based + on the Library, uncombined with any other library facilities, + conveyed under the terms of this License. + + b) Give prominent notice with the combined library that part of it + is a work based on the Library, and explaining where to find the + accompanying uncombined form of the same work. + + 6. Revised Versions of the GNU Lesser General Public License. + + The Free Software Foundation may publish revised and/or new versions +of the GNU Lesser General Public License from time to time. Such new +versions will be similar in spirit to the present version, but may +differ in detail to address new problems or concerns. + + Each version is given a distinguishing version number. If the +Library as you received it specifies that a certain numbered version +of the GNU Lesser General Public License "or any later version" +applies to it, you have the option of following the terms and +conditions either of that published version or of any later version +published by the Free Software Foundation. If the Library as you +received it does not specify a version number of the GNU Lesser +General Public License, you may choose any version of the GNU Lesser +General Public License ever published by the Free Software Foundation. + + If the Library as you received it specifies that a proxy can decide +whether future versions of the GNU Lesser General Public License shall +apply, that proxy's public statement of acceptance of any version is +permanent authorization for you to choose that version for the +Library. + diff --git a/resources/functions_de.properties b/resources/functions_de.properties index c43f930..2f4b2f0 100644 --- a/resources/functions_de.properties +++ b/resources/functions_de.properties @@ -275,7 +275,6 @@ tanh=TANHYP tdist=TVERT terminate=KANAL.SCHLIESSEN text=TEXT -text=BOX TEXTFELD textref=TEXTPOS time=ZEIT timevalue=ZEITWERT diff --git a/src/jxl/Cell.java b/src/jxl/Cell.java index d44dcec..b5a26e3 100644 --- a/src/jxl/Cell.java +++ b/src/jxl/Cell.java @@ -41,6 +41,10 @@ public interface Cell */ public int getColumn(); + public default CellCoordinate getCoordinate() { + return new CellCoordinate(getColumn(), getRow()); + } + /** * Returns the content type of this cell * diff --git a/src/jxl/CellCoordinate.java b/src/jxl/CellCoordinate.java new file mode 100644 index 0000000..9eebc7d --- /dev/null +++ b/src/jxl/CellCoordinate.java @@ -0,0 +1,59 @@ + +package jxl; + +/** + * created 30.05.2020 + * @author jan + */ +public class CellCoordinate implements Comparable { + + private final int column; + private final int row; + + public CellCoordinate(int column, int row) { + this.column = column; + this.row = row; + } + + public int getColumn() { + return column; + } + + public int getRow() { + return row; + } + + @Override + public int hashCode() { + int hash = 7; + hash = 37 * hash + this.column; + hash = 37 * hash + this.row; + return hash; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + return compareTo((CellCoordinate) obj) == 0; + } + + @Override + public int compareTo(CellCoordinate that) { + int rowDiff = Integer.compare(this.row, that.row); + if (rowDiff != 0) + return rowDiff; + else + return Integer.compare(this.column, that.column); + } + + @Override + public String toString() { + return "Coord(" + column + "," + row + ')'; + } + +} diff --git a/src/jxl/CellLocation.java b/src/jxl/CellLocation.java new file mode 100644 index 0000000..1857462 --- /dev/null +++ b/src/jxl/CellLocation.java @@ -0,0 +1,61 @@ +package jxl; + +import java.util.*; +import jxl.write.*; + +/** + * This class describes the locatation of a cell whithin a workbook. + * It realizes the value object pattern. + * + * created 2020-01-05 + * @author jan + */ +public class CellLocation { + + private final WritableSheet sheet; + private final int column, row; + + public CellLocation(WritableSheet sheet, int column, int row) { + this.sheet = sheet; + this.column = column; + this.row = row; + } + + public WritableSheet getSheet() { + return sheet; + } + + public int getColumn() { + return column; + } + + public int getRow() { + return row; + } + + @Override + public int hashCode() { + int hash = 7; + hash = 37 * hash + Objects.hashCode(this.sheet); + hash = 37 * hash + this.column; + hash = 37 * hash + this.row; + return hash; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + final CellLocation other = (CellLocation) obj; + if (this.column != other.column) + return false; + if (this.row != other.row) + return false; + return Objects.equals(this.sheet, other.sheet); + } + +} diff --git a/src/jxl/CellType.java b/src/jxl/CellType.java index d64249e..f2c9a29 100644 --- a/src/jxl/CellType.java +++ b/src/jxl/CellType.java @@ -22,70 +22,33 @@ /** * An enumeration type listing the available content types for a cell */ -public final class CellType -{ - - /** - * The text description of this cell type - */ - private String description; - - /** - * Private constructor - * @param desc the description of this type - */ - private CellType(String desc) - { +public enum CellType { + + // An empty cell can still contain formatting information and comments + EMPTY("Empty"), + LABEL("Label"), + NUMBER("Number"), + BOOLEAN("Boolean"), + ERROR("Error"), + NUMBER_FORMULA("Numerical Formula"), + DATE_FORMULA("Date Formula"), + STRING_FORMULA("String Formula"), + BOOLEAN_FORMULA("Boolean Formula"), + FORMULA_ERROR("Formula Error"), + DATE("Date"); + + private final String description; + + private CellType(String desc) { description = desc; } - /** - * Returns a string description of this cell - * - * @return the string description for this type - */ + @Override public String toString() { return description; } - /** - * An empty cell can still contain formatting information and comments - */ - public static final CellType EMPTY = new CellType("Empty"); - /** - */ - public static final CellType LABEL = new CellType("Label"); - /** - */ - public static final CellType NUMBER = new CellType("Number"); - /** - */ - public static final CellType BOOLEAN = new CellType("Boolean"); - /** - */ - public static final CellType ERROR = new CellType("Error"); - /** - */ - public static final CellType NUMBER_FORMULA = - new CellType("Numerical Formula"); - /** - */ - public static final CellType DATE_FORMULA = new CellType("Date Formula"); - /** - */ - public static final CellType STRING_FORMULA = new CellType("String Formula"); - /** - */ - public static final CellType BOOLEAN_FORMULA = - new CellType("Boolean Formula"); - /** - */ - public static final CellType FORMULA_ERROR = new CellType("Formula Error"); - /** - */ - public static final CellType DATE = new CellType("Date"); - } diff --git a/src/jxl/Hyperlink.java b/src/jxl/Hyperlink.java index dea0a8a..3b1316e 100644 --- a/src/jxl/Hyperlink.java +++ b/src/jxl/Hyperlink.java @@ -19,8 +19,8 @@ package jxl; -import java.io.File; import java.net.URL; +import java.nio.file.Path; /** * Hyperlink information. Only URLs or file links are supported @@ -102,6 +102,6 @@ public interface Hyperlink * * @return the file, or NULL if this hyperlink is not a file */ - public File getFile(); + public Path getFile(); } diff --git a/src/jxl/Image.java b/src/jxl/Image.java index 9625cf5..c06a7a7 100644 --- a/src/jxl/Image.java +++ b/src/jxl/Image.java @@ -19,10 +19,9 @@ package jxl; +import java.nio.file.Path; import jxl.common.LengthUnit; -import java.io.File; - /** * Accessor functions for an image */ @@ -61,7 +60,7 @@ public interface Image * * @return the file which the image references */ - public File getImageFile(); + public Path getImageFile(); /** * Accessor for the image data diff --git a/src/jxl/Sheet.java b/src/jxl/Sheet.java index 42887b7..12ce85f 100644 --- a/src/jxl/Sheet.java +++ b/src/jxl/Sheet.java @@ -19,8 +19,10 @@ package jxl; +import java.util.List; import java.util.regex.Pattern; import jxl.format.CellFormat; +import jxl.read.biff.*; /** * Represents a sheet within a workbook. Provides a handle to the individual @@ -89,22 +91,6 @@ public interface Sheet */ public String getName(); - /** - * Determines whether the sheet is hidden - * - * @return whether or not the sheet is hidden - * @deprecated in favour of the getSettings() method - */ - public boolean isHidden(); - - /** - * Determines whether the sheet is protected - * - * @return whether or not the sheet is protected - * @deprecated in favour of the getSettings() method - */ - public boolean isProtected(); - /** * Gets the cell whose contents match the string passed in. * If no match is found, then null is returned. The search is performed @@ -121,7 +107,7 @@ public interface Sheet * If no match is found, then null is returned. The search is performed * on a row by row basis, so the lower the row number, the more * efficiently the algorithm will perform - * + * * @param contents the string to match * @param firstCol the first column within the range * @param firstRow the first row of the range @@ -130,11 +116,11 @@ public interface Sheet * @param reverse indicates whether to perform a reverse search or not * @return the Cell whose contents match the parameter, null if not found */ - public Cell findCell(String contents, - int firstCol, - int firstRow, - int lastCol, - int lastRow, + public Cell findCell(String contents, + int firstCol, + int firstRow, + int lastCol, + int lastRow, boolean reverse); /** @@ -142,7 +128,7 @@ public Cell findCell(String contents, * If no match is found, then null is returned. The search is performed * on a row by row basis, so the lower the row number, the more * efficiently the algorithm will perform - * + * * @param pattern the regular expression string to match * @param firstCol the first column within the range * @param firstRow the first row of the rang @@ -151,11 +137,11 @@ public Cell findCell(String contents, * @param reverse indicates whether to perform a reverse search or not * @return the Cell whose contents match the parameter, null if not found */ - public Cell findCell(Pattern pattern, - int firstCol, + public Cell findCell(Pattern pattern, + int firstCol, int firstRow, - int lastCol, - int lastRow, + int lastCol, + int lastRow, boolean reverse); /** @@ -182,9 +168,9 @@ public Cell findCell(Pattern pattern, /** * Gets the cells which have been merged on this sheet * - * @return an array of range objects + * @return a List of range objects */ - public Range[] getMergedCells(); + public List getMergedCells(); /** * Gets the settings used on a particular sheet @@ -260,14 +246,14 @@ public Cell findCell(Pattern pattern, * * @return the page breaks on this sheet */ - public int[] getRowPageBreaks(); + public IHorizontalPageBreaks getRowPageBreaks(); /** * Accessor for the page breaks on this sheet * * @return the page breaks on this sheet */ - public int[] getColumnPageBreaks(); + public IVerticalPageBreaks getColumnPageBreaks(); } diff --git a/src/jxl/SheetSettings.java b/src/jxl/SheetSettings.java index d40e9fe..c65a0a7 100644 --- a/src/jxl/SheetSettings.java +++ b/src/jxl/SheetSettings.java @@ -38,7 +38,7 @@ public final class SheetSettings * The page orientation */ private PageOrientation orientation; - + /** * The page order */ @@ -228,7 +228,7 @@ public final class SheetSettings private boolean recalculateFormulasBeforeSave; /** - * The magnification factor for use during page break preview mode (in + * The magnification factor for use during page break preview mode (in * percent) */ private int pageBreakPreviewMagnification; @@ -241,7 +241,7 @@ public final class SheetSettings /** * The print area */ - private Range printArea; + private SheetRangeImpl printArea; /** * The print row titles @@ -252,7 +252,7 @@ public final class SheetSettings * The print column titles */ private Range printTitlesCol; - + /** * A handle to the sheet - used internally for ranges */ @@ -380,7 +380,7 @@ public SheetSettings(SheetSettings copy, Sheet s) copy.getPrintArea().getBottomRight().getColumn(), copy.getPrintArea().getBottomRight().getRow()); } - + if (copy.printTitlesRow != null) { printTitlesRow = new SheetRangeImpl @@ -389,7 +389,7 @@ public SheetSettings(SheetSettings copy, Sheet s) copy.getPrintTitlesRow().getTopLeft().getRow(), copy.getPrintTitlesRow().getBottomRight().getColumn(), copy.getPrintTitlesRow().getBottomRight().getRow()); - } + } if (copy.printTitlesCol != null) { @@ -399,7 +399,7 @@ public SheetSettings(SheetSettings copy, Sheet s) copy.getPrintTitlesCol().getTopLeft().getRow(), copy.getPrintTitlesCol().getBottomRight().getColumn(), copy.getPrintTitlesCol().getBottomRight().getRow()); - } + } } /** @@ -424,20 +424,20 @@ public PageOrientation getOrientation() /** * Accessor for the order - * + * * @return */ - public PageOrder getPageOrder() + public PageOrder getPageOrder() { return pageOrder; } /** * Sets the page order for printing this sheet - * + * * @param order */ - public void setPageOrder(PageOrder order) + public void setPageOrder(PageOrder order) { this.pageOrder = order; } @@ -1259,12 +1259,12 @@ public boolean getRecalculateFormulasBeforeSave() * @param lastCol the last column of the print area * @param lastRow the last row of the print area */ - public void setPrintArea(int firstCol, - int firstRow, + public void setPrintArea(int firstCol, + int firstRow, int lastCol, int lastRow) { - printArea = new SheetRangeImpl(sheet, firstCol, firstRow, + printArea = new SheetRangeImpl(sheet, firstCol, firstRow, lastCol, lastRow); } @@ -1286,8 +1286,8 @@ public Range getPrintArea() * @param firstCol the first column of the print column titles * @param lastCol the last column of the print column titles */ - public void setPrintTitles(int firstRow, - int lastRow, + public void setPrintTitles(int firstRow, + int lastRow, int firstCol, int lastCol) { @@ -1301,26 +1301,26 @@ public void setPrintTitles(int firstRow, * @param firstRow the first row of the print titles * @param lastRow the last row of the print titles */ - public void setPrintTitlesRow(int firstRow, + public void setPrintTitlesRow(int firstRow, int lastRow) { - printTitlesRow = new SheetRangeImpl(sheet, 0, firstRow, + printTitlesRow = new SheetRangeImpl(sheet, 0, firstRow, 255, lastRow); } - + /** * Sets the print column titles for this sheet * * @param firstRow the first row of the print titles * @param lastRow the last row of the print titles */ - public void setPrintTitlesCol(int firstCol, + public void setPrintTitlesCol(int firstCol, int lastCol) { - printTitlesCol = new SheetRangeImpl(sheet, firstCol, 0, + printTitlesCol = new SheetRangeImpl(sheet, firstCol, 0, lastCol, 65535); } - + /** * Accessor for the print row titles * @@ -1330,15 +1330,36 @@ public Range getPrintTitlesRow() { return printTitlesRow; } - + /** * Accessor for the print column titles * - * @return the print column titles, or NULL if one is not defined for this + * @return the print column titles, or NULL if one is not defined for this * sheet */ public Range getPrintTitlesCol() { return printTitlesCol; } + + public void insertRowInPrintArea(int row) { + if (printArea != null) + printArea.insertRow(row); + } + + public void removeRowFromPrintArea(int row) { + if (printArea != null) + printArea.removeRow(row); + } + + public void insertColumnInPrintArea(int col) { + if (printArea != null) + printArea.insertColumn(col); + } + + public void removeColumnFromPrintArea(int col) { + if (printArea != null) + printArea.removeColumn(col); + } + } diff --git a/src/jxl/Workbook.java b/src/jxl/Workbook.java index d57ed35..cd2d653 100644 --- a/src/jxl/Workbook.java +++ b/src/jxl/Workbook.java @@ -19,16 +19,11 @@ package jxl; -import java.io.FileInputStream; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; - -import jxl.read.biff.BiffException; +import java.io.*; +import java.nio.file.*; +import java.util.*; +import jxl.read.biff.*; import jxl.read.biff.File; -import jxl.read.biff.PasswordException; -import jxl.read.biff.WorkbookParser; import jxl.write.WritableWorkbook; import jxl.write.biff.WritableWorkbookImpl; @@ -36,7 +31,7 @@ * Represents a Workbook. Contains the various factory methods and provides * a variety of accessors which provide access to the work sheets. */ -public abstract class Workbook +public abstract class Workbook implements Closeable { /** * The current version of the software @@ -54,16 +49,16 @@ protected Workbook() * Gets the sheets within this workbook. Use of this method for * large worksheets can cause performance problems. * - * @return an array of the individual sheets + * @return a list of the individual sheets */ - public abstract Sheet[] getSheets(); + public abstract List getSheets(); /** * Gets the sheet names * - * @return an array of strings containing the sheet names + * @return a list of strings containing the sheet names */ - public abstract String[] getSheetNames(); + public abstract List getSheetNames(); /** * Gets the specified sheet within this workbook @@ -75,7 +70,7 @@ protected Workbook() * * @param index the zero based index of the reQuired sheet * @return The sheet specified by the index - * @exception IndexOutOfBoundException when index refers to a non-existent + * @throws IndexOutOfBoundsException when index refers to a non-existent * sheet */ public abstract Sheet getSheet(int index) @@ -182,6 +177,7 @@ public static String getVersion() * Closes this workbook, and frees makes any memory allocated available * for garbage collection */ + @Override public abstract void close(); /** @@ -192,7 +188,7 @@ public static String getVersion() * @param file the excel 97 spreadsheet to parse * @return a workbook instance */ - public static Workbook getWorkbook(java.io.File file) + public static Workbook getWorkbook(Path file) throws IOException, BiffException { return getWorkbook(file, new WorkbookSettings()); @@ -207,36 +203,15 @@ public static Workbook getWorkbook(java.io.File file) * @param ws the settings for the workbook * @return a workbook instance */ - public static Workbook getWorkbook(java.io.File file, WorkbookSettings ws) - throws IOException, BiffException - { - FileInputStream fis = new FileInputStream(file); - - // Always close down the input stream, regardless of whether or not the - // file can be parsed. Thanks to Steve Hahn for this - File dataFile = null; - - try - { - dataFile = new File(fis, ws); + public static Workbook getWorkbook(Path file, WorkbookSettings ws) + throws IOException, BiffException { + try (InputStream fis = Files.newInputStream(file)) { + File dataFile = new File(fis, ws); + Workbook workbook = new WorkbookParser(dataFile, ws); + workbook.parse(); + + return workbook; } - catch (IOException e) - { - fis.close(); - throw e; - } - catch (BiffException e) - { - fis.close(); - throw e; - } - - fis.close(); - - Workbook workbook = new WorkbookParser(dataFile, ws); - workbook.parse(); - - return workbook; } /** @@ -280,7 +255,7 @@ public static Workbook getWorkbook(InputStream is, WorkbookSettings ws) * @return a writable workbook * @exception IOException */ - public static WritableWorkbook createWorkbook(java.io.File file) + public static WritableWorkbook createWorkbook(Path file) throws IOException { return createWorkbook(file, new WorkbookSettings()); @@ -294,11 +269,11 @@ public static WritableWorkbook createWorkbook(java.io.File file) * @return a writable workbook * @exception IOException */ - public static WritableWorkbook createWorkbook(java.io.File file, + public static WritableWorkbook createWorkbook(Path file, WorkbookSettings ws) throws IOException { - FileOutputStream fos = new FileOutputStream(file); + OutputStream fos = Files.newOutputStream(file); WritableWorkbook w = new WritableWorkbookImpl(fos, true, ws); return w; } @@ -313,7 +288,7 @@ public static WritableWorkbook createWorkbook(java.io.File file, * @return a writable workbook * @exception IOException */ - public static WritableWorkbook createWorkbook(java.io.File file, + public static WritableWorkbook createWorkbook(Path file, Workbook in) throws IOException { @@ -329,13 +304,14 @@ public static WritableWorkbook createWorkbook(java.io.File file, * @param in the workbook to copy * @param ws the configuration for this workbook * @return a writable workbook + * @throws IOException */ - public static WritableWorkbook createWorkbook(java.io.File file, + public static WritableWorkbook createWorkbook(Path file, Workbook in, WorkbookSettings ws) throws IOException { - FileOutputStream fos = new FileOutputStream(file); + OutputStream fos = Files.newOutputStream(file); WritableWorkbook w = new WritableWorkbookImpl(fos, in, true, ws); return w; } @@ -412,8 +388,3 @@ public static WritableWorkbook createWorkbook(OutputStream os, return w; } } - - - - - diff --git a/src/jxl/WorkbookSettings.java b/src/jxl/WorkbookSettings.java index 0587bf5..3f2dea0 100644 --- a/src/jxl/WorkbookSettings.java +++ b/src/jxl/WorkbookSettings.java @@ -19,14 +19,11 @@ package jxl; -import java.io.File; -import java.util.HashMap; -import java.util.Locale; - -import jxl.common.Logger; - +import java.nio.file.*; +import java.util.*; import jxl.biff.CountryCode; import jxl.biff.formula.FunctionNames; +import jxl.common.Logger; /** * This is a bean which client applications may use to set various advanced @@ -138,7 +135,7 @@ public final class WorkbookSettings * The directory for used for the temporary file during write. If this * is NULL, the default system directory is used */ - private File temporaryFileDuringWriteDirectory; + private Path temporaryFileDuringWriteDirectory; /** * The locale. Normally this is the same as the system locale, but there @@ -181,7 +178,7 @@ public final class WorkbookSettings /** * A hash map of function names keyed on locale */ - private HashMap localeFunctionNames; + private HashMap localeFunctionNames; /** * Flag to indicate whether all external data and pivot stuff should @@ -225,8 +222,10 @@ public final class WorkbookSettings */ private int hideobj; - private Integer startColumnCount; - private Integer startRowCount; + private boolean windowHidden = false; + + private int startColumnCount; + private int startRowCount; /** * The HIDEOBJ record stores options selected in the Options dialog,View tab. @@ -256,7 +255,7 @@ public WorkbookSettings() { initialFileSize = DEFAULT_INITIAL_FILE_SIZE; arrayGrowSize = DEFAULT_ARRAY_GROW_SIZE; - localeFunctionNames = new HashMap(); + localeFunctionNames = new HashMap<>(); excelDisplayLanguage = CountryCode.USA.getCode(); excelRegionalSettings = CountryCode.UK.getCode(); refreshAll = false; @@ -289,9 +288,7 @@ public WorkbookSettings() System.getProperty("jxl.temporaryfileduringwritedirectory"); if (tempdir != null) - { - temporaryFileDuringWriteDirectory = new File(tempdir); - } + temporaryFileDuringWriteDirectory = Paths.get(tempdir); encoding = System.getProperty("file.encoding"); } @@ -310,7 +307,7 @@ public WorkbookSettings() } else { - locale = new Locale(System.getProperty("jxl.lang"), + locale = Locale.of(System.getProperty("jxl.lang"), System.getProperty("jxl.country")); } @@ -573,7 +570,7 @@ public FunctionNames getFunctionNames() { if (functionNames == null) { - functionNames = (FunctionNames) localeFunctionNames.get(locale); + functionNames = localeFunctionNames.get(locale); // have not previously accessed function names for this locale, // so create a brand new one and add it to the list @@ -741,8 +738,7 @@ public boolean getUseTemporaryFileDuringWrite() * this flag involves an assessment of the trade-offs between memory usage * and performance * - * @return TRUE if a temporary is file is used during writing, - * FALSE otherwise + * @param temp */ public void setUseTemporaryFileDuringWrite(boolean temp) { @@ -758,7 +754,7 @@ public void setUseTemporaryFileDuringWrite(boolean temp) * * @param dir the directory to which temporary files should be written */ - public void setTemporaryFileDuringWriteDirectory(File dir) + public void setTemporaryFileDuringWriteDirectory(Path dir) { temporaryFileDuringWriteDirectory = dir; } @@ -772,7 +768,7 @@ public void setTemporaryFileDuringWriteDirectory(File dir) * @return the temporary directory used during write, or NULL if it is * not set */ - public File getTemporaryFileDuringWriteDirectory() + public Path getTemporaryFileDuringWriteDirectory() { return temporaryFileDuringWriteDirectory; } @@ -837,7 +833,7 @@ public void setExcel9File(boolean excel9file) } /** - * @return the windowprotected + * @return the windowProtected */ public boolean getWindowProtected() { @@ -845,9 +841,9 @@ public boolean getWindowProtected() } /** - * @param windowprotected the windowprotected to set + * @param windowProtected the windowProtected to set */ - public void setWindowProtected(boolean windowprotected) + public void setWindowProtected(boolean windowProtected) { this.windowProtected = windowProtected; } @@ -892,19 +888,27 @@ public void setWriteAccess(String writeAccess) this.writeAccess = writeAccess; } - public Integer getStartColumnCount() { + public boolean isWindowHidden() { + return windowHidden; + } + + public void setWindowHidden(boolean windowHidden) { + this.windowHidden = windowHidden; + } + + public int getStartColumnCount() { return startColumnCount; } - public void setStartColumnCount(Integer startColumnCount) { + public void setStartColumnCount(int startColumnCount) { this.startColumnCount = startColumnCount; } - public Integer getStartRowCount() { + public int getStartRowCount() { return startRowCount; } - public void setStartRowCount(Integer startRowCount) { + public void setStartRowCount(int startRowCount) { this.startRowCount = startRowCount; } } diff --git a/src/jxl/biff/BaseCellFeatures.java b/src/jxl/biff/BaseCellFeatures.java index eb94932..2f9d288 100644 --- a/src/jxl/biff/BaseCellFeatures.java +++ b/src/jxl/biff/BaseCellFeatures.java @@ -54,7 +54,7 @@ public class BaseCellFeatures * The comment height in cells */ private double commentHeight; - + /** * A handle to the drawing object */ @@ -97,11 +97,11 @@ public class BaseCellFeatures // Validation conditions protected static class ValidationCondition { - private DVParser.Condition condition; - + private final DVParser.Condition condition; + private static ValidationCondition[] types = new ValidationCondition[0]; - - ValidationCondition(DVParser.Condition c) + + ValidationCondition(DVParser.Condition c) { condition = c; ValidationCondition[] oldtypes = types; @@ -116,21 +116,21 @@ public DVParser.Condition getCondition() } } - public static final ValidationCondition BETWEEN = + public static final ValidationCondition BETWEEN = new ValidationCondition(DVParser.BETWEEN); - public static final ValidationCondition NOT_BETWEEN = + public static final ValidationCondition NOT_BETWEEN = new ValidationCondition(DVParser.NOT_BETWEEN); - public static final ValidationCondition EQUAL = + public static final ValidationCondition EQUAL = new ValidationCondition(DVParser.EQUAL); - public static final ValidationCondition NOT_EQUAL = + public static final ValidationCondition NOT_EQUAL = new ValidationCondition(DVParser.NOT_EQUAL); - public static final ValidationCondition GREATER_THAN = + public static final ValidationCondition GREATER_THAN = new ValidationCondition(DVParser.GREATER_THAN); - public static final ValidationCondition LESS_THAN = + public static final ValidationCondition LESS_THAN = new ValidationCondition(DVParser.LESS_THAN); - public static final ValidationCondition GREATER_EQUAL = + public static final ValidationCondition GREATER_EQUAL = new ValidationCondition(DVParser.GREATER_EQUAL); - public static final ValidationCondition LESS_EQUAL = + public static final ValidationCondition LESS_EQUAL = new ValidationCondition(DVParser.LESS_EQUAL); /** @@ -152,7 +152,7 @@ public BaseCellFeatures(BaseCellFeatures cf) commentWidth = cf.commentWidth; commentHeight = cf.commentHeight; - // The data validation stuff. + // The data validation stuff. dropDown = cf.dropDown; dataValidation = cf.dataValidation; @@ -188,7 +188,7 @@ public double getCommentHeight() return commentHeight; } - /** + /** * Called by the cell when the features are added * * @param wc the writable cell @@ -196,7 +196,7 @@ public double getCommentHeight() public final void setWritableCell(CellValue wc) { writableCell = wc; - } + } /** * Internal method to set the cell comment. Used when reading @@ -283,8 +283,8 @@ public void removeDataValidation() DVParser dvp = getDVParser(); if (dvp.extendedCellsValidation()) { - logger.warn("Cannot remove data validation from " + - CellReferenceHelper.getCellReference(writableCell) + + logger.warn("Cannot remove data validation from " + + CellReferenceHelper.getCellReference(writableCell) + " as it is part of the shared reference " + CellReferenceHelper.getCellReference(dvp.getFirstColumn(), dvp.getFirstRow()) + @@ -348,18 +348,18 @@ public String getDataValidationList() } /** - * The list of items to validate for this cell. For each object in the + * The list of items to validate for this cell. For each object in the * collection, the toString() method will be called and the data entered * will be validated against that string * * @param c the list of valid values */ - public void setDataValidationList(Collection c) + public void setDataValidationList(Collection c) { if (dataValidation && getDVParser().extendedCellsValidation()) { - logger.warn("Cannot set data validation on " + - CellReferenceHelper.getCellReference(writableCell) + + logger.warn("Cannot set data validation on " + + CellReferenceHelper.getCellReference(writableCell) + " as it is part of a shared data validation"); return; } @@ -378,8 +378,8 @@ public void setDataValidationRange(int col1, int r1, int col2, int r2) { if (dataValidation && getDVParser().extendedCellsValidation()) { - logger.warn("Cannot set data validation on " + - CellReferenceHelper.getCellReference(writableCell) + + logger.warn("Cannot set data validation on " + + CellReferenceHelper.getCellReference(writableCell) + " as it is part of a shared data validation"); return; } @@ -396,8 +396,8 @@ public void setDataValidationRange(String namedRange) { if (dataValidation && getDVParser().extendedCellsValidation()) { - logger.warn("Cannot set data validation on " + - CellReferenceHelper.getCellReference(writableCell) + + logger.warn("Cannot set data validation on " + + CellReferenceHelper.getCellReference(writableCell) + " as it is part of a shared data validation"); return; } @@ -414,8 +414,8 @@ public void setNumberValidation(double val, ValidationCondition c) { if (dataValidation && getDVParser().extendedCellsValidation()) { - logger.warn("Cannot set data validation on " + - CellReferenceHelper.getCellReference(writableCell) + + logger.warn("Cannot set data validation on " + + CellReferenceHelper.getCellReference(writableCell) + " as it is part of a shared data validation"); return; } @@ -425,13 +425,13 @@ public void setNumberValidation(double val, ValidationCondition c) dataValidation = true; } - public void setNumberValidation(double val1, double val2, + public void setNumberValidation(double val1, double val2, ValidationCondition c) { if (dataValidation && getDVParser().extendedCellsValidation()) { - logger.warn("Cannot set data validation on " + - CellReferenceHelper.getCellReference(writableCell) + + logger.warn("Cannot set data validation on " + + CellReferenceHelper.getCellReference(writableCell) + " as it is part of a shared data validation"); return; } @@ -514,8 +514,8 @@ public void shareDataValidation(BaseCellFeatures source) { if (dataValidation) { - logger.warn("Attempting to share a data validation on cell " + - CellReferenceHelper.getCellReference(writableCell) + + logger.warn("Attempting to share a data validation on cell " + + CellReferenceHelper.getCellReference(writableCell) + " which already has a data validation"); return; } @@ -529,7 +529,7 @@ public void shareDataValidation(BaseCellFeatures source) /** * Gets the range of cells to which the data validation applies. If the - * validation applies to just this cell, this will be reflected in the + * validation applies to just this cell, this will be reflected in the * returned range * * @return the range to which the same validation extends, or NULL if this @@ -541,7 +541,7 @@ public Range getSharedDataValidationRange() { return null; } - + DVParser dvp = getDVParser(); return new SheetRangeImpl(writableCell.getSheet(), diff --git a/src/jxl/biff/BuiltInFormat.java b/src/jxl/biff/BuiltInFormat.java index 4d7355c..45feb4d 100644 --- a/src/jxl/biff/BuiltInFormat.java +++ b/src/jxl/biff/BuiltInFormat.java @@ -19,6 +19,7 @@ package jxl.biff; +import java.util.List; import jxl.format.Format; /** @@ -34,12 +35,12 @@ final class BuiltInFormat implements Format, DisplayFormat /** * The excel format string */ - private String formatString; + private final String formatString; /** * The index */ - private int formatIndex; + private final int formatIndex; /** * Constructor @@ -107,70 +108,64 @@ public boolean isBuiltIn() * * @return TRUE if the two built in formats are equal, FALSE otherwise */ - public boolean equals(Object o) - { + @Override + public boolean equals(Object o) { if (o == this) - { return true; - } - if (!(o instanceof BuiltInFormat)) - { - return false; - } + if (o instanceof BuiltInFormat bif) + return (formatIndex == bif.formatIndex); + + return false; + } - BuiltInFormat bif = (BuiltInFormat) o; - return (formatIndex == bif.formatIndex); + @Override + public int hashCode() { + int hash = 3; + hash = 59 * hash + this.formatIndex; + return hash; } /** * The list of built in formats */ - public static BuiltInFormat[] builtIns = new BuiltInFormat[0x32]; - - // Populate the built ins - static - { - builtIns[0x0] = new BuiltInFormat("", 0); - builtIns[0x1] = new BuiltInFormat("0", 1); - builtIns[0x2] = new BuiltInFormat("0.00", 2); - builtIns[0x3] = new BuiltInFormat("#,##0", 3); - builtIns[0x4] = new BuiltInFormat("#,##0.00", 4); - builtIns[0x5] = new BuiltInFormat("($#,##0_);($#,##0)", 5); - builtIns[0x6] = new BuiltInFormat("($#,##0_);[Red]($#,##0)", 6); - builtIns[0x7] = new BuiltInFormat("($#,##0_);[Red]($#,##0)", 7); - builtIns[0x8] = new BuiltInFormat("($#,##0.00_);[Red]($#,##0.00)", 8); - builtIns[0x9] = new BuiltInFormat("0%", 9); - builtIns[0xa] = new BuiltInFormat("0.00%", 10); - builtIns[0xb] = new BuiltInFormat("0.00E+00", 11); - builtIns[0xc] = new BuiltInFormat("# ?/?", 12); - builtIns[0xd] = new BuiltInFormat("# ??/??", 13); - builtIns[0xe] = new BuiltInFormat("dd/mm/yyyy", 14); - builtIns[0xf] = new BuiltInFormat("d-mmm-yy", 15); - builtIns[0x10] = new BuiltInFormat("d-mmm", 16); - builtIns[0x11] = new BuiltInFormat("mmm-yy", 17); - builtIns[0x12] = new BuiltInFormat("h:mm AM/PM", 18); - builtIns[0x13] = new BuiltInFormat("h:mm:ss AM/PM", 19); - builtIns[0x14] = new BuiltInFormat("h:mm", 20); - builtIns[0x15] = new BuiltInFormat("h:mm:ss", 21); - builtIns[0x16] = new BuiltInFormat("m/d/yy h:mm", 22); - builtIns[0x25] = new BuiltInFormat("(#,##0_);(#,##0)", 0x25); - builtIns[0x26] = new BuiltInFormat("(#,##0_);[Red](#,##0)", 0x26); - builtIns[0x27] = new BuiltInFormat("(#,##0.00_);(#,##0.00)", 0x27); - builtIns[0x28] = new BuiltInFormat("(#,##0.00_);[Red](#,##0.00)", 0x28); - builtIns[0x29] = new BuiltInFormat - ("_(*#,##0_);_(*(#,##0);_(*\"-\"_);(@_)", 0x29); - builtIns[0x2a] = new BuiltInFormat - ("_($*#,##0_);_($*(#,##0);_($*\"-\"_);(@_)", 0x2a); - builtIns[0x2b] = new BuiltInFormat - ("_(* #,##0.00_);_(* (#,##0.00);_(* \"-\"??_);(@_)", 0x2b); - builtIns[0x2c] = new BuiltInFormat - ("_($* #,##0.00_);_($* (#,##0.00);_($* \"-\"??_);(@_)", 0x2c); - builtIns[0x2d] = new BuiltInFormat("mm:ss", 0x2d); - builtIns[0x2e] = new BuiltInFormat("[h]mm:ss", 0x2e); - builtIns[0x2f] = new BuiltInFormat("mm:ss.0", 0x2f); - builtIns[0x30] = new BuiltInFormat("##0.0E+0", 0x30); - builtIns[0x31] = new BuiltInFormat("@", 0x31); - } + public static final List builtIns = List.of( + new BuiltInFormat("", 0), + new BuiltInFormat("0", 1), + new BuiltInFormat("0.00", 2), + new BuiltInFormat("#,##0", 3), + new BuiltInFormat("#,##0.00", 4), + new BuiltInFormat("($#,##0_);($#,##0)", 5), + new BuiltInFormat("($#,##0_);[Red]($#,##0)", 6), + new BuiltInFormat("($#,##0_);[Red]($#,##0)", 7), + new BuiltInFormat("($#,##0.00_);[Red]($#,##0.00)", 8), + new BuiltInFormat("0%", 9), + new BuiltInFormat("0.00%", 10), + new BuiltInFormat("0.00E+00", 11), + new BuiltInFormat("# ?/?", 12), + new BuiltInFormat("# ??/??", 13), + new BuiltInFormat("dd/mm/yyyy", 14), + new BuiltInFormat("d-mmm-yy", 15), + new BuiltInFormat("d-mmm", 16), + new BuiltInFormat("mmm-yy", 17), + new BuiltInFormat("h:mm AM/PM", 18), + new BuiltInFormat("h:mm:ss AM/PM", 19), + new BuiltInFormat("h:mm", 20), + new BuiltInFormat("h:mm:ss", 21), + new BuiltInFormat("m/d/yy h:mm", 22), + new BuiltInFormat("(#,##0_);(#,##0)", 0x25), + new BuiltInFormat("(#,##0_);[Red](#,##0)", 0x26), + new BuiltInFormat("(#,##0.00_);(#,##0.00)", 0x27), + new BuiltInFormat("(#,##0.00_);[Red](#,##0.00)", 0x28), + new BuiltInFormat("_(*#,##0_);_(*(#,##0);_(*\"-\"_);(@_)", 0x29), + new BuiltInFormat("_($*#,##0_);_($*(#,##0);_($*\"-\"_);(@_)", 0x2a), + new BuiltInFormat("_(* #,##0.00_);_(* (#,##0.00);_(* \"-\"??_);(@_)", 0x2b), + new BuiltInFormat("_($* #,##0.00_);_($* (#,##0.00);_($* \"-\"??_);(@_)", 0x2c), + new BuiltInFormat("mm:ss", 0x2d), + new BuiltInFormat("[h]mm:ss", 0x2e), + new BuiltInFormat("mm:ss.0", 0x2f), + new BuiltInFormat("##0.0E+0", 0x30), + new BuiltInFormat("@", 0x31) + ); } diff --git a/src/jxl/biff/ByteArray.java b/src/jxl/biff/ByteArray.java deleted file mode 100644 index 2aaa326..0000000 --- a/src/jxl/biff/ByteArray.java +++ /dev/null @@ -1,117 +0,0 @@ -/********************************************************************* -* -* Copyright (C) 2005 Andrew Khan -* -* This library is free software; you can redistribute it and/or -* modify it under the terms of the GNU Lesser General Public -* License as published by the Free Software Foundation; either -* version 2.1 of the License, or (at your option) any later version. -* -* This library is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -* Lesser General Public License for more details. -* -* You should have received a copy of the GNU Lesser General Public -* License along with this library; if not, write to the Free Software -* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -***************************************************************************/ - -package jxl.biff; - -/** - * A growable array of bytes - */ -public class ByteArray -{ - /** - * The array grow size - */ - private int growSize; - - /** - * The current array - */ - private byte[] bytes; - - /** - * The current position - */ - private int pos; - - // The default grow size - private final static int defaultGrowSize = 1024; - - /** - * Constructor - */ - public ByteArray() - { - this(defaultGrowSize); - } - - /** - * Constructor - * - * @param gs - */ - public ByteArray(int gs) - { - growSize = gs; - bytes = new byte[defaultGrowSize]; - pos = 0; - } - - /** - * Adds a byte onto the array - * - * @param b the byte - */ - public void add(byte b) - { - checkSize(1); - bytes[pos] = b; - pos++; - } - - /** - * Adds an array of bytes onto the array - * - * @param b the array of bytes - */ - public void add(byte[] b) - { - checkSize(b.length); - System.arraycopy(b, 0, bytes, pos, b.length); - pos += b.length; - } - - /** - * Gets the complete array - * - * @return the array - */ - public byte[] getBytes() - { - byte[] returnArray = new byte[pos]; - System.arraycopy(bytes, 0, returnArray, 0, pos); - return returnArray; - } - - /** - * Checks to see if there is sufficient space left on the array. If not, - * then it grows the array - * - * @param sz the amount of bytes to add - */ - private void checkSize(int sz) - { - while (pos + sz >= bytes.length) - { - // Grow the array - byte[] newArray = new byte[bytes.length + growSize]; - System.arraycopy(bytes, 0, newArray, 0, pos); - bytes = newArray; - } - } -} diff --git a/src/jxl/biff/ConditionalFormat.java b/src/jxl/biff/ConditionalFormat.java index c34360c..84fcfcf 100644 --- a/src/jxl/biff/ConditionalFormat.java +++ b/src/jxl/biff/ConditionalFormat.java @@ -23,8 +23,6 @@ import java.util.ArrayList; import java.util.Iterator; -import jxl.WorkbookSettings; -import jxl.biff.formula.ExternalSheet; import jxl.write.biff.File; /** @@ -36,12 +34,12 @@ public class ConditionalFormat /** * The range of the format */ - private ConditionalFormatRangeRecord range; + private final ConditionalFormatRangeRecord range; /** * The format conditions */ - private ArrayList conditions; + private final ArrayList conditions = new ArrayList<>(); /** * Constructor @@ -49,7 +47,6 @@ public class ConditionalFormat public ConditionalFormat(ConditionalFormatRangeRecord cfrr) { range = cfrr; - conditions = new ArrayList(); } /** @@ -63,7 +60,7 @@ public void addCondition(ConditionalFormatRecord cond) } /** - * Inserts a blank column into this spreadsheet. If the column is out of + * Inserts a blank column into this spreadsheet. If the column is out of * range of the columns in the sheet, then no action is taken * * @param col the column to insert @@ -85,7 +82,7 @@ public void removeColumn(int col) } /** - * Removes a row from this spreadsheet. If the row is out of + * Removes a row from this spreadsheet. If the row is out of * range of the columns in the sheet, then no action is taken * * @param row the row to remove @@ -108,18 +105,15 @@ public void insertRow(int row) /** * Writes out the data validation - * - * @exception IOException + * + * @exception IOException * @param outputFile the output file */ public void write(File outputFile) throws IOException { outputFile.write(range); - for (Iterator i = conditions.iterator(); i.hasNext();) - { - ConditionalFormatRecord cfr = (ConditionalFormatRecord) i.next(); + for (ConditionalFormatRecord cfr : conditions) outputFile.write(cfr); - } } } diff --git a/src/jxl/biff/DVParser.java b/src/jxl/biff/DVParser.java index bc99e90..e15c9d4 100644 --- a/src/jxl/biff/DVParser.java +++ b/src/jxl/biff/DVParser.java @@ -45,14 +45,14 @@ public class DVParser private static Logger logger = Logger.getLogger(DVParser.class); // DV Type - public static class DVType + public static class DVType { - private int value; - private String desc; - + private final int value; + private final String desc; + private static DVType[] types = new DVType[0]; - - DVType(int v, String d) + + DVType(int v, String d) { value = v; desc = d; @@ -75,7 +75,7 @@ static DVType getType(int v) return found; } - public int getValue() + public int getValue() { return value; } @@ -89,11 +89,11 @@ public String getDescription() // Error Style public static class ErrorStyle { - private int value; - + private final int value; + private static ErrorStyle[] types = new ErrorStyle[0]; - - ErrorStyle(int v) + + ErrorStyle(int v) { value = v; ErrorStyle[] oldtypes = types; @@ -115,7 +115,7 @@ static ErrorStyle getErrorStyle(int v) return found; } - public int getValue() + public int getValue() { return value; } @@ -124,12 +124,12 @@ public int getValue() // Conditions public static class Condition { - private int value; - private MessageFormat format; - + private final int value; + private final MessageFormat format; + private static Condition[] types = new Condition[0]; - - Condition(int v, String pattern) + + Condition(int v, String pattern) { value = v; format = new MessageFormat(pattern); @@ -152,7 +152,7 @@ static Condition getCondition(int v) return found; } - public int getValue() + public int getValue() { return value; } @@ -180,7 +180,7 @@ public String getConditionString(String s1, String s2) // The conditions public static final Condition BETWEEN = new Condition(0, "{0} <= x <= {1}"); - public static final Condition NOT_BETWEEN = + public static final Condition NOT_BETWEEN = new Condition(1, "!({0} <= x <= {1}"); public static final Condition EQUAL = new Condition(2, "x == {0}"); public static final Condition NOT_EQUAL = new Condition(3, "x != {0}"); @@ -320,8 +320,8 @@ public String getConditionString(String s1, String s2) /** * Constructor */ - public DVParser(byte[] data, - ExternalSheet es, + public DVParser(byte[] data, + ExternalSheet es, WorkbookMethods nt, WorkbookSettings ws) { @@ -354,7 +354,7 @@ public DVParser(byte[] data, } else if (length > 0) { - promptTitle = StringHelper.getUnicodeString(data, length, pos + 3); + promptTitle = StringHelper.getUnicodeString(data, pos + 3, length); pos += length * 2 + 3; } else @@ -370,7 +370,7 @@ else if (length > 0) } else if (length > 0) { - errorTitle = StringHelper.getUnicodeString(data, length, pos + 3); + errorTitle = StringHelper.getUnicodeString(data, pos + 3, length); pos += length * 2 + 3; } else @@ -386,7 +386,7 @@ else if (length > 0) } else if (length > 0) { - promptText = StringHelper.getUnicodeString(data, length, pos + 3); + promptText = StringHelper.getUnicodeString(data, pos + 3, length); pos += length * 2 + 3; } else @@ -402,7 +402,7 @@ else if (length > 0) } else if (length > 0) { - errorText = StringHelper.getUnicodeString(data, length, pos + 3); + errorText = StringHelper.getUnicodeString(data, pos + 3, length); pos += length * 2 + 3; } else @@ -434,13 +434,13 @@ else if (length > 0) column2 = IntegerHelper.getInt(data[pos], data[pos+1]); pos += 2; - extendedCellsValidation = (row1 == row2 && column1 == column2) ? + extendedCellsValidation = (row1 == row2 && column1 == column2) ? false : true; // Do the formulas try { - // First, create a temporary blank cell for any formula relative + // First, create a temporary blank cell for any formula relative // references EmptyCell tmprt = new EmptyCell(column1, row1); @@ -448,7 +448,7 @@ else if (length > 0) { byte[] tokens = new byte[formula1Length]; System.arraycopy(data, formula1Pos, tokens, 0, formula1Length); - formula1 = new FormulaParser(tokens, tmprt, es, nt,ws, + formula1 = new FormulaParser(tokens, tmprt, es, nt,ws, ParseContext.DATA_VALIDATION); formula1.parse(); } @@ -457,15 +457,15 @@ else if (length > 0) { byte[] tokens = new byte[formula2Length]; System.arraycopy(data, formula2Pos, tokens, 0, formula2Length); - formula2 = new FormulaParser(tokens, tmprt, es, nt, ws, + formula2 = new FormulaParser(tokens, tmprt, es, nt, ws, ParseContext.DATA_VALIDATION); formula2.parse(); } } catch (FormulaException e) { - logger.warn(e.getMessage() + " for cells " + - CellReferenceHelper.getCellReference(column1, row1)+ "-" + + logger.warn(e.getMessage() + " for cells " + + CellReferenceHelper.getCellReference(column1, row1)+ "-" + CellReferenceHelper.getCellReference(column2, row2)); } } @@ -473,14 +473,14 @@ else if (length > 0) /** * Constructor called when creating a data validation from the API */ - public DVParser(Collection strings) + public DVParser(Collection strings) { copied = false; type = LIST; errorStyle = STOP; condition = BETWEEN; extendedCellsValidation = false; - + // the options stringListGiven = true; emptyCellsAllowed = true; @@ -492,20 +492,20 @@ public DVParser(Collection strings) errorTitle = "\0"; promptText = "\0"; errorText = "\0"; - if (strings.size() == 0) + if (strings.isEmpty()) { logger.warn("no validation strings - ignoring"); } - Iterator i = strings.iterator(); - StringBuffer formulaString = new StringBuffer(); + Iterator i = strings.iterator(); + StringBuilder formulaString = new StringBuilder(); - formulaString.append(i.next().toString()); + formulaString.append(i.next()); while (i.hasNext()) { formulaString.append('\0'); formulaString.append(' '); - formulaString.append(i.next().toString()); + formulaString.append(i.next()); } // If the formula string exceeds @@ -514,7 +514,7 @@ public DVParser(Collection strings) { logger.warn("Validation list exceeds maximum number of characters - " + "truncating"); - formulaString.delete(MAX_VALIDATION_LIST_LENGTH, + formulaString.delete(MAX_VALIDATION_LIST_LENGTH, formulaString.length()); } @@ -543,7 +543,7 @@ public DVParser(String namedRange) suppressArrow = false; showPrompt = true; showError = true; - + promptTitle = "\0"; errorTitle = "\0"; promptText = "\0"; @@ -557,7 +557,7 @@ public DVParser(String namedRange) errorStyle = STOP; condition = BETWEEN; extendedCellsValidation = false; - + // the options stringListGiven = false; emptyCellsAllowed = true; @@ -582,7 +582,7 @@ public DVParser(int c1, int r1, int c2, int r2) errorStyle = STOP; condition = BETWEEN; extendedCellsValidation = false; - + // the options stringListGiven = false; emptyCellsAllowed = true; @@ -611,7 +611,7 @@ public DVParser(double val1, double val2, Condition c) errorStyle = STOP; condition = c; extendedCellsValidation = false; - + // the options stringListGiven = false; emptyCellsAllowed = true; @@ -667,7 +667,7 @@ public DVParser(DVParser copy) try { formula1String = copy.formula1.getFormula(); - formula2String = (copy.formula2 != null) ? + formula2String = (copy.formula2 != null) ? copy.formula2.getFormula() : null; } catch (FormulaException e) @@ -686,7 +686,7 @@ public byte[] getData() // Compute the length of the data byte[] f1Bytes = formula1 != null ? formula1.getBytes() : new byte[0]; byte[] f2Bytes = formula2 != null ? formula2.getBytes() : new byte[0]; - int dataLength = + int dataLength = 4 + // the options promptTitle.length() * 2 + 3 + // the prompt title errorTitle.length() * 2 + 3 + // the error title @@ -708,12 +708,12 @@ public byte[] getData() options |= errorStyle.getValue() << 4; options |= condition.getValue() << 20; - if (stringListGiven) + if (stringListGiven) { options |= STRING_LIST_GIVEN_MASK; } - if (emptyCellsAllowed) + if (emptyCellsAllowed) { options |= EMPTY_CELLS_ALLOWED_MASK; } @@ -736,7 +736,7 @@ public byte[] getData() // The text IntegerHelper.getFourBytes(options, data, pos); pos += 4; - + IntegerHelper.getTwoBytes(promptTitle.length(), data, pos); pos += 2; @@ -783,7 +783,7 @@ public byte[] getData() // Formula 2 IntegerHelper.getTwoBytes(f2Bytes.length, data, pos); pos += 4; - + System.arraycopy(f2Bytes, 0, data, pos, f2Bytes.length); pos += f2Bytes.length; @@ -973,16 +973,16 @@ String getValidationFormula() throws FormulaException String s1 = formula1.getFormula(); String s2 = formula2 != null ? formula2.getFormula() : null; - return condition.getConditionString(s1, s2) + + return condition.getConditionString(s1, s2) + "; x " + type.getDescription(); } /** * Called by the cell value when the cell features are added to the sheet */ - public void setCell(int col, - int row, - ExternalSheet es, + public void setCell(int col, + int row, + ExternalSheet es, WorkbookMethods nt, WorkbookSettings ws) throws FormulaException { @@ -1000,14 +1000,14 @@ public void setCell(int col, column2 = col; formula1 = new FormulaParser(formula1String, - es, nt, ws, + es, nt, ws, ParseContext.DATA_VALIDATION); formula1.parse(); if (formula2String != null) { formula2 = new FormulaParser(formula2String, - es, nt, ws, + es, nt, ws, ParseContext.DATA_VALIDATION); formula2.parse(); } diff --git a/src/jxl/biff/DataValidation.java b/src/jxl/biff/DataValidation.java index 0d1b029..b862be6 100644 --- a/src/jxl/biff/DataValidation.java +++ b/src/jxl/biff/DataValidation.java @@ -43,7 +43,7 @@ public class DataValidation */ private static Logger logger = Logger.getLogger(DataValidation.class); - /** + /** * The data validity list */ private DataValidityListRecord validityList; @@ -51,7 +51,7 @@ public class DataValidation /** * The list of data validity (DV) records */ - private ArrayList validitySettings; + private ArrayList validitySettings; /** * Handle to the workbook @@ -88,7 +88,7 @@ public class DataValidation public DataValidation(DataValidityListRecord dvlr) { validityList = dvlr; - validitySettings = new ArrayList(validityList.getNumberOfSettings()); + validitySettings = new ArrayList<>(validityList.getNumberOfSettings()); copied = false; } @@ -97,13 +97,13 @@ public DataValidation(DataValidityListRecord dvlr) */ public DataValidation(int objId, ExternalSheet es, - WorkbookMethods wm, + WorkbookMethods wm, WorkbookSettings ws ) { workbook = wm; externalSheet = es; workbookSettings = ws; - validitySettings = new ArrayList(); + validitySettings = new ArrayList<>(); comboBoxObjectId = objId; copied = false; } @@ -113,7 +113,7 @@ public DataValidation(int objId, */ public DataValidation(DataValidation dv, ExternalSheet es, - WorkbookMethods wm, + WorkbookMethods wm, WorkbookSettings ws ) { workbook = wm; @@ -122,16 +122,11 @@ public DataValidation(DataValidation dv, copied = true; validityList = new DataValidityListRecord(dv.getDataValidityList()); - validitySettings = new ArrayList(); + validitySettings = new ArrayList<>(); DataValiditySettingsRecord[] settings = dv.getDataValiditySettings(); - for (int i = 0; i < settings.length ; i++) - { - validitySettings.add(new DataValiditySettingsRecord(settings[i], - externalSheet, - workbook, - workbookSettings)); - } + for (DataValiditySettingsRecord setting : settings) + validitySettings.add(new DataValiditySettingsRecord(setting, externalSheet, workbook, workbookSettings)); } /** @@ -163,14 +158,13 @@ public DataValidityListRecord getDataValidityList() */ public DataValiditySettingsRecord[] getDataValiditySettings() { - DataValiditySettingsRecord[] dvlr = new DataValiditySettingsRecord[0]; - return (DataValiditySettingsRecord[]) validitySettings.toArray(dvlr); + return validitySettings.toArray(DataValiditySettingsRecord[]::new); } /** * Writes out the data validation - * - * @exception IOException + * + * @exception IOException * @param outputFile the output file */ public void write(File outputFile) throws IOException @@ -179,14 +173,14 @@ public void write(File outputFile) throws IOException { logger.warn("Maximum number of data validations exceeded - " + "truncating..."); - validitySettings = new ArrayList + validitySettings = new ArrayList<> (validitySettings.subList(0, MAX_NO_OF_VALIDITY_SETTINGS - 1)); Assert.verify(validitySettings.size() <= MAX_NO_OF_VALIDITY_SETTINGS); } if (validityList == null) { - DValParser dvp = new DValParser(comboBoxObjectId, + DValParser dvp = new DValParser(comboBoxObjectId, validitySettings.size()); validityList = new DataValidityListRecord(dvp); } @@ -197,12 +191,9 @@ public void write(File outputFile) throws IOException } outputFile.write(validityList); - - for (Iterator i = validitySettings.iterator(); i.hasNext() ; ) - { - DataValiditySettingsRecord dvsr = (DataValiditySettingsRecord) i.next(); + + for (DataValiditySettingsRecord dvsr : validitySettings) outputFile.write(dvsr); - } } /** @@ -212,11 +203,8 @@ public void write(File outputFile) throws IOException */ public void insertRow(int row) { - for (Iterator i = validitySettings.iterator(); i.hasNext() ; ) - { - DataValiditySettingsRecord dv = (DataValiditySettingsRecord) i.next(); + for (DataValiditySettingsRecord dv : validitySettings) dv.insertRow(row); - } } /** @@ -226,9 +214,8 @@ public void insertRow(int row) */ public void removeRow(int row) { - for (Iterator i = validitySettings.iterator(); i.hasNext() ; ) - { - DataValiditySettingsRecord dv = (DataValiditySettingsRecord) i.next(); + for (Iterator i = validitySettings.iterator(); i.hasNext() ; ) { + DataValiditySettingsRecord dv = i.next(); if (dv.getFirstRow() == row && dv.getLastRow() == row) { @@ -249,11 +236,8 @@ public void removeRow(int row) */ public void insertColumn(int col) { - for (Iterator i = validitySettings.iterator(); i.hasNext() ; ) - { - DataValiditySettingsRecord dv = (DataValiditySettingsRecord) i.next(); + for (DataValiditySettingsRecord dv : validitySettings) dv.insertColumn(col); - } } /** @@ -263,10 +247,10 @@ public void insertColumn(int col) */ public void removeColumn(int col) { - for (Iterator i = validitySettings.iterator(); i.hasNext() ; ) + for (Iterator i = validitySettings.iterator(); i.hasNext() ; ) { - DataValiditySettingsRecord dv = (DataValiditySettingsRecord) i.next(); - + DataValiditySettingsRecord dv = i.next(); + if (dv.getFirstColumn() == col && dv.getLastColumn() == col) { i.remove(); @@ -287,10 +271,10 @@ public void removeColumn(int col) */ public void removeDataValidation (int col, int row) { - for (Iterator i = validitySettings.iterator(); i.hasNext() ; ) + for (Iterator i = validitySettings.iterator(); i.hasNext() ; ) { - DataValiditySettingsRecord dv = (DataValiditySettingsRecord) i.next(); - + DataValiditySettingsRecord dv = i.next(); + if (dv.getFirstColumn() == col && dv.getLastColumn() == col && dv.getFirstRow() == row && dv.getLastRow() == row) { @@ -307,13 +291,13 @@ public void removeDataValidation (int col, int row) * @param col1 the first column * @param row1 the first row */ - public void removeSharedDataValidation (int col1, int row1, + public void removeSharedDataValidation (int col1, int row1, int col2, int row2) { - for (Iterator i = validitySettings.iterator(); i.hasNext() ; ) + for (Iterator i = validitySettings.iterator(); i.hasNext() ; ) { - DataValiditySettingsRecord dv = (DataValiditySettingsRecord) i.next(); - + DataValiditySettingsRecord dv = i.next(); + if (dv.getFirstColumn() == col1 && dv.getLastColumn() == col2 && dv.getFirstRow() == row1 && dv.getLastRow() == row2) { @@ -332,9 +316,9 @@ public DataValiditySettingsRecord getDataValiditySettings(int col, int row) { boolean found = false; DataValiditySettingsRecord foundRecord = null; - for (Iterator i = validitySettings.iterator(); i.hasNext() && !found;) + for (Iterator i = validitySettings.iterator(); i.hasNext() && !found;) { - DataValiditySettingsRecord dvsr = (DataValiditySettingsRecord) i.next(); + DataValiditySettingsRecord dvsr = i.next(); if (dvsr.getFirstColumn() == col && dvsr.getFirstRow() == row) { found = true; diff --git a/src/jxl/biff/EmptyCell.java b/src/jxl/biff/EmptyCell.java index f78029e..d0685e2 100644 --- a/src/jxl/biff/EmptyCell.java +++ b/src/jxl/biff/EmptyCell.java @@ -19,8 +19,7 @@ package jxl.biff; -import jxl.CellFeatures; -import jxl.CellType; +import jxl.*; import jxl.format.Alignment; import jxl.format.CellFormat; import jxl.format.Border; @@ -35,14 +34,8 @@ */ public class EmptyCell implements WritableCell { - /** - * The row of this empty cell - */ - private int row; - /** - * The column number of this empty cell - */ - private int col; + + private final CellCoordinate coord; /** * Constructs an empty cell at the specified position @@ -52,8 +45,11 @@ public class EmptyCell implements WritableCell */ public EmptyCell(int c, int r) { - row = r; - col = c; + this(new CellCoordinate(c, r)); + } + + public EmptyCell(CellCoordinate coord) { + this.coord = coord; } /** @@ -61,9 +57,10 @@ public EmptyCell(int c, int r) * * @return the row number of this cell */ + @Override public int getRow() { - return row; + return coord.getRow(); } /** @@ -71,9 +68,10 @@ public int getRow() * * @return the column number of this cell */ + @Override public int getColumn() { - return col; + return coord.getColumn(); } /** @@ -81,6 +79,7 @@ public int getColumn() * * @return the content type for this cell */ + @Override public CellType getType() { return CellType.EMPTY; @@ -91,6 +90,7 @@ public CellType getType() * * @return an empty string */ + @Override public String getContents() { return ""; @@ -101,6 +101,7 @@ public String getContents() * * @return the format applied to this cell */ + @Override public CellFormat getCellFormat() { return null; @@ -151,6 +152,7 @@ public void setBorder(Border border, BorderLineStyle line) * Dummy override * @param cf dummy */ + @Override public void setCellFormat(CellFormat cf) { } @@ -158,8 +160,8 @@ public void setCellFormat(CellFormat cf) /** * Dummy override * @param cf dummy - * @deprecated */ + @Deprecated public void setCellFormat(jxl.CellFormat cf) { } @@ -170,6 +172,7 @@ public void setCellFormat(jxl.CellFormat cf) * * @return TRUE if this cell is hidden, FALSE otherwise */ + @Override public boolean isHidden() { return false; @@ -182,6 +185,7 @@ public boolean isHidden() * @param r the row which the new cell will occupy * @return a copy of this cell, which can then be added to the sheet */ + @Override public WritableCell copyTo(int c, int r) { return new EmptyCell(c, r); @@ -192,6 +196,7 @@ public WritableCell copyTo(int c, int r) * * @return the cell features or NULL if this cell doesn't have any */ + @Override public CellFeatures getCellFeatures() { return null; @@ -202,6 +207,7 @@ public CellFeatures getCellFeatures() * * @return the cell features or NULL if this cell doesn't have any */ + @Override public WritableCellFeatures getWritableCellFeatures() { return null; @@ -210,6 +216,7 @@ public WritableCellFeatures getWritableCellFeatures() /** * Accessor for the cell features */ + @Override public void setCellFeatures(WritableCellFeatures wcf) { } diff --git a/src/jxl/biff/EncodedURLHelper.java b/src/jxl/biff/EncodedURLHelper.java index 53247db..08ddc8f 100644 --- a/src/jxl/biff/EncodedURLHelper.java +++ b/src/jxl/biff/EncodedURLHelper.java @@ -1,142 +1,117 @@ /********************************************************************* -* -* Copyright (C) 2005 Andrew Khan -* -* This library is free software; you can redistribute it and/or -* modify it under the terms of the GNU Lesser General Public -* License as published by the Free Software Foundation; either -* version 2.1 of the License, or (at your option) any later version. -* -* This library is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -* Lesser General Public License for more details. -* -* You should have received a copy of the GNU Lesser General Public -* License along with this library; if not, write to the Free Software -* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -***************************************************************************/ - + * + * Copyright (C) 2005 Andrew Khan + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + ***************************************************************************/ package jxl.biff; -import jxl.common.Logger; - import jxl.WorkbookSettings; /** * Helper to get the Microsoft encoded URL from the given string */ -public class EncodedURLHelper -{ - /** - * The logger - */ - private static Logger logger = Logger.getLogger(EncodedURLHelper.class); +public class EncodedURLHelper { // The control codes - private static byte msDosDriveLetter = 0x01; - private static byte sameDrive = 0x02; - private static byte endOfSubdirectory = 0x03; - private static byte parentDirectory = 0x04; - private static byte unencodedUrl = 0x05; - - public static byte[] getEncodedURL(String s, WorkbookSettings ws) - { + private static final char MS_DOS_DRIVE_LETTER = 0x01; + private static final char SAME_DRIVE = 0x02; + private static final char END_OF_SUBDIRECTORY = 0x03; + private static final char PARENT_DIRECTORY = 0x04; + private static final char UNENCODED_URL = 0x05; + + public static byte[] getEncodedURL(String s, WorkbookSettings ws) { if (s.startsWith("http:")) - { return getURL(s, ws); - } else - { return getFile(s, ws); - } } - private static byte[] getFile(String s, WorkbookSettings ws) - { - ByteArray byteArray = new ByteArray(); + private static byte[] getFile(String s, WorkbookSettings ws) { + StringBuilder sb = new StringBuilder(); int pos = 0; - if (s.charAt(1) == ':') - { + if (s.charAt(1) == ':') { // we have a drive letter - byteArray.add(msDosDriveLetter); - byteArray.add((byte) s.charAt(0)); + sb.append(MS_DOS_DRIVE_LETTER); + sb.append(s.charAt(0)); pos = 2; - } - else if (s.charAt(pos) == '\\' || - s.charAt(pos) == '/') - { - byteArray.add(sameDrive); - } + } else if ((s.charAt(0) == '\\' && s.charAt(1) == '\\') + || (s.charAt(0) == '/' && s.charAt(1) == '/')) { + sb.append(MS_DOS_DRIVE_LETTER); + sb.append('@'); + pos = 2; + } else if (s.charAt(pos) == '\\' + || s.charAt(pos) == '/') + sb.append(SAME_DRIVE); - while (s.charAt(pos) == '\\' || - s.charAt(pos) == '/') - { + while (s.charAt(pos) == '\\' + || s.charAt(pos) == '/') pos++; - } - while (pos < s.length()) - { + while (pos < s.length()) { int nextSepIndex1 = s.indexOf('/', pos); int nextSepIndex2 = s.indexOf('\\', pos); int nextSepIndex = 0; - String nextFileNameComponent = null; + String nextFileNameComponent; if (nextSepIndex1 != -1 && nextSepIndex2 != -1) - { // choose the smallest (ie. nearest) separator nextSepIndex = Math.min(nextSepIndex1, nextSepIndex2); - } else if (nextSepIndex1 == -1 || nextSepIndex2 == -1) - { // chose the maximum separator nextSepIndex = Math.max(nextSepIndex1, nextSepIndex2); - } - if (nextSepIndex == -1) - { + if (nextSepIndex == -1) { // no more separators nextFileNameComponent = s.substring(pos); pos = s.length(); - } - else - { + } else { nextFileNameComponent = s.substring(pos, nextSepIndex); pos = nextSepIndex + 1; } - if (nextFileNameComponent.equals(".")) - { - // current directory - do nothing - } - else if (nextFileNameComponent.equals("..")) - { - // parent directory - byteArray.add(parentDirectory); - } - else - { - // add the filename component - byteArray.add(StringHelper.getBytes(nextFileNameComponent, - ws)); - } + switch (nextFileNameComponent) { + case ".": + // current directory - do nothing + break; - if (pos < s.length()) - { - byteArray.add(endOfSubdirectory); + case "..": + // parent directory + sb.append(PARENT_DIRECTORY); + break; + + default: + // append the filename component + sb.append(nextFileNameComponent); + if (pos < s.length()) + sb.append(END_OF_SUBDIRECTORY); + break; } + } - return byteArray.getBytes(); + return StringHelper.getBytes(sb.toString(), ws); } - - private static byte[] getURL(String s, WorkbookSettings ws) - { - ByteArray byteArray = new ByteArray(); - byteArray.add(unencodedUrl); - byteArray.add((byte) s.length()); - byteArray.add(StringHelper.getBytes(s, ws)); - return byteArray.getBytes(); + + private static byte[] getURL(String s, WorkbookSettings ws) { + StringBuilder sb = new StringBuilder(s.length() + 2); + sb.append(UNENCODED_URL); + sb.append((char) s.length()); + sb.append(s); + return StringHelper.getBytes(sb.toString(), ws); } + } diff --git a/src/jxl/biff/FontRecord.java b/src/jxl/biff/FontRecord.java index 4c74ffc..03996e8 100644 --- a/src/jxl/biff/FontRecord.java +++ b/src/jxl/biff/FontRecord.java @@ -168,7 +168,7 @@ public FontRecord(Record t, WorkbookSettings ws) } else if (data[15] == 1) { - name = StringHelper.getUnicodeString(data, numChars, 16); + name = StringHelper.getUnicodeString(data, 16, numChars); } else { @@ -222,7 +222,7 @@ public FontRecord(Record t, WorkbookSettings ws, Biff7 dummy) protected FontRecord(Font f) { super(Type.FONT); - + Assert.verify(f != null); pointHeight = f.getPointSize(); diff --git a/src/jxl/biff/Fonts.java b/src/jxl/biff/Fonts.java index 8516eb1..1aa5386 100644 --- a/src/jxl/biff/Fonts.java +++ b/src/jxl/biff/Fonts.java @@ -35,21 +35,13 @@ public class Fonts /** * The list of fonts */ - private ArrayList fonts; + private ArrayList fonts = new ArrayList<>(); /** * The default number of fonts */ private static final int numDefaultFonts = 4; - /** - * Constructor - */ - public Fonts() - { - fonts = new ArrayList(); - } - /** * Adds a font record to this workbook. If the FontRecord passed in has not * been initialized, then its font index is determined based upon the size @@ -86,11 +78,9 @@ public FontRecord getFont(int index) { // remember to allow for the fact that font index 4 is not used if (index > 4) - { index--; - } - return (FontRecord) fonts.get(index); + return fonts.get(index); } /** @@ -101,14 +91,8 @@ public FontRecord getFont(int index) */ public void write(File outputFile) throws IOException { - Iterator i = fonts.iterator(); - - FontRecord font = null; - while (i.hasNext()) - { - font = (FontRecord) i.next(); + for (FontRecord font : fonts) outputFile.write(font); - } } /** @@ -121,32 +105,30 @@ IndexMapping rationalize() IndexMapping mapping = new IndexMapping(fonts.size() + 1); // allow for skipping record 4 - ArrayList newfonts = new ArrayList(); + ArrayList newfonts = new ArrayList<>(); FontRecord fr = null; int numremoved = 0; // Preserve the default fonts for (int i = 0; i < numDefaultFonts; i++) { - fr = (FontRecord) fonts.get(i); + fr = fonts.get(i); newfonts.add(fr); mapping.setMapping(fr.getFontIndex(), fr.getFontIndex()); } // Now do the rest - Iterator it = null; - FontRecord fr2 = null; boolean duplicate = false; for (int i = numDefaultFonts; i < fonts.size(); i++) { - fr = (FontRecord) fonts.get(i); + fr = fonts.get(i); // Compare to all the fonts currently on the list duplicate = false; - it = newfonts.iterator(); + Iterator it = newfonts.iterator(); while (it.hasNext() && !duplicate) { - fr2 = (FontRecord) it.next(); + FontRecord fr2 = it.next(); if (fr.equals(fr2)) { duplicate = true; @@ -167,10 +149,10 @@ IndexMapping rationalize() } // Iterate through the remaining fonts, updating all the font indices - it = newfonts.iterator(); + Iterator it = newfonts.iterator(); while (it.hasNext()) { - fr = (FontRecord) it.next(); + fr = it.next(); fr.initialize(mapping.getNewIndex(fr.getFontIndex())); } diff --git a/src/jxl/biff/FormatRecord.java b/src/jxl/biff/FormatRecord.java index 0b4fb6c..cf526be 100644 --- a/src/jxl/biff/FormatRecord.java +++ b/src/jxl/biff/FormatRecord.java @@ -23,6 +23,7 @@ import java.text.DecimalFormat; import java.text.NumberFormat; import java.text.SimpleDateFormat; +import java.util.*; import jxl.common.Logger; @@ -46,11 +47,6 @@ public class FormatRecord extends WritableRecordData */ private boolean initialized; - /** - * The raw data - */ - private byte[] data; - /** * The index code */ @@ -79,8 +75,7 @@ public class FormatRecord extends WritableRecordData /** * The date strings to look for */ - private static String[] dateStrings = new String[] - { + private static final Set DATE_STRINGS = Set.of( "dd", "mm", "yy", @@ -88,11 +83,11 @@ public class FormatRecord extends WritableRecordData "ss", "m/", "/d" - }; + ); // Type to distinguish between biff7 and biff8 - private static class BiffType - { + public static final class BiffType { + private BiffType() { } } public static final BiffType biff8 = new BiffType(); @@ -141,62 +136,36 @@ protected FormatRecord(FormatRecord fr) * Constructs this object from the raw data. Used when reading in a * format record * - * @param t the raw data + * @param r the raw data * @param ws the workbook settings * @param biffType biff type dummy overload */ - public FormatRecord(Record t, WorkbookSettings ws, BiffType biffType) + public FormatRecord(Record r, WorkbookSettings ws, BiffType biffType) { - super(t); + super(r); - byte[] data = getRecord().getData(); + byte[] data = r.getData(); 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 - { + formatString = StringHelper.readBiff8String(data, 2); + else { int numchars = data[2]; byte[] chars = new byte[numchars]; System.arraycopy(data, 3, chars, 0, chars.length); formatString = new String(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.toUpperCase()) != -1) - { - date = true; - break; - } - } + date = DATE_STRINGS.stream() + .anyMatch(dateFormat -> + formatString.contains(dateFormat) || + formatString.contains(dateFormat.toUpperCase())); // See if this is number format - look for the # or 0 characters - if (!date) - { - if (formatString.indexOf('#') != -1 || - formatString.indexOf('0') != -1 ) - { - number = true; - } - } + number = (!date) + && (formatString.contains("#") || formatString.contains("0") ); } /** @@ -204,9 +173,10 @@ public FormatRecord(Record t, WorkbookSettings ws, BiffType biffType) * * @return the raw data */ + @Override public byte[] getData() { - data = new byte[formatString.length() * 2 + 3 + 2]; + byte[] data = new byte[formatString.length() * 2 + 3 + 2]; IntegerHelper.getTwoBytes(indexCode, data, 0); IntegerHelper.getTwoBytes(formatString.length(), data, 2); @@ -397,7 +367,7 @@ public final DateFormat getDateFormat() fmt = sb.toString(); - // If the date format starts with anything inside square brackets then + // If the date format starts with anything inside square brackets then // filter tham out if (fmt.charAt(0) == '[') { @@ -407,7 +377,7 @@ public final DateFormat getDateFormat() fmt = fmt.substring(end+1); } } - + // Get rid of some spurious characters that can creep in fmt = replace(fmt, ";@", ""); diff --git a/src/jxl/biff/FormattingRecords.java b/src/jxl/biff/FormattingRecords.java index 373c223..11c4c8e 100644 --- a/src/jxl/biff/FormattingRecords.java +++ b/src/jxl/biff/FormattingRecords.java @@ -47,17 +47,17 @@ public class FormattingRecords * A hash map of FormatRecords, for random access retrieval when reading * in a spreadsheet */ - private HashMap formats; + private final HashMap formats = new HashMap<>(10); /** * A list of formats, used when writing out a spreadsheet */ - private ArrayList formatsList; + private ArrayList formatsList; /** * The list of extended format records */ - private ArrayList xfRecords; + private ArrayList xfRecords; /** * The next available index number for custom format records @@ -67,7 +67,7 @@ public class FormattingRecords /** * A handle to the available fonts */ - private Fonts fonts; + private final Fonts fonts; /** * The colour palette @@ -98,9 +98,8 @@ public class FormattingRecords */ public FormattingRecords(Fonts f) { - xfRecords = new ArrayList(10); - formats = new HashMap(10); - formatsList = new ArrayList(10); + xfRecords = new ArrayList<>(10); + formatsList = new ArrayList<>(10); fonts = f; nextCustomIndexNumber = customFormatStartIndex; } @@ -178,7 +177,7 @@ public final void addFormat(DisplayFormat fr) if (!fr.isBuiltIn()) { formatsList.add(fr); - formats.put(new Integer(fr.getFormatIndex()), fr); + formats.put(fr.getFormatIndex(), fr); } } @@ -192,7 +191,7 @@ public final void addFormat(DisplayFormat fr) */ public final boolean isDate(int pos) { - XFRecord xfr = (XFRecord) xfRecords.get(pos); + XFRecord xfr = xfRecords.get(pos); if (xfr.isDate()) { @@ -200,7 +199,7 @@ public final boolean isDate(int pos) } FormatRecord fr = (FormatRecord) - formats.get(new Integer(xfr.getFormatRecord())); + formats.get(xfr.getFormatRecord()); return fr == null ? false : fr.isDate(); } @@ -214,7 +213,7 @@ public final boolean isDate(int pos) */ public final DateFormat getDateFormat(int pos) { - XFRecord xfr = (XFRecord) xfRecords.get(pos); + XFRecord xfr = xfRecords.get(pos); if (xfr.isDate()) { @@ -222,7 +221,7 @@ public final DateFormat getDateFormat(int pos) } FormatRecord fr = (FormatRecord) - formats.get(new Integer(xfr.getFormatRecord())); + formats.get(xfr.getFormatRecord()); if (fr == null) { @@ -241,15 +240,15 @@ public final DateFormat getDateFormat(int pos) */ public final NumberFormat getNumberFormat(int pos) { - XFRecord xfr = (XFRecord) xfRecords.get(pos); - + XFRecord xfr = xfRecords.get(pos); + if (xfr.isNumber()) { return xfr.getNumberFormat(); } FormatRecord fr = (FormatRecord) - formats.get(new Integer(xfr.getFormatRecord())); + formats.get(xfr.getFormatRecord()); if (fr == null) { @@ -267,8 +266,7 @@ public final NumberFormat getNumberFormat(int pos) */ FormatRecord getFormatRecord(int index) { - return (FormatRecord) - formats.get(new Integer(index)); + return (FormatRecord) formats.get(index); } /** * Writes out all the format records and the XF records @@ -278,23 +276,12 @@ FormatRecord getFormatRecord(int index) */ public void write(File outputFile) throws IOException { - // Write out all the formats - Iterator i = formatsList.iterator(); - FormatRecord fr = null; - while (i.hasNext()) - { - fr = (FormatRecord) i.next(); - outputFile.write(fr); - } + for (DisplayFormat fr : formatsList) + outputFile.write((FormatRecord) fr); // Write out the styles - i = xfRecords.iterator(); - XFRecord xfr = null; - while (i.hasNext()) - { - xfr = (XFRecord) i.next(); + for (XFRecord xfr : xfRecords) outputFile.write(xfr); - } // Write out the style records BuiltInStyle style = new BuiltInStyle(0x10, 3); @@ -335,7 +322,7 @@ protected final Fonts getFonts() */ public final XFRecord getXFRecord(int index) { - return (XFRecord) xfRecords.get(index); + return xfRecords.get(index); } /** @@ -375,20 +362,14 @@ public IndexMapping rationalize(IndexMapping fontMapping, // Update the index codes for the XF records using the format // mapping and the font mapping // at the same time - XFRecord xfr = null; - for (Iterator it = xfRecords.iterator(); it.hasNext();) - { - xfr = (XFRecord) it.next(); - + for (XFRecord xfr : xfRecords) { if (xfr.getFormatRecord() >= customFormatStartIndex) - { xfr.setFormatIndex(formatMapping.getNewIndex(xfr.getFormatRecord())); - } xfr.setFontIndex(fontMapping.getNewIndex(xfr.getFontIndex())); } - ArrayList newrecords = new ArrayList(minXFRecords); + ArrayList newrecords = new ArrayList<>(minXFRecords); IndexMapping mapping = new IndexMapping(xfRecords.size()); int numremoved = 0; @@ -410,14 +391,13 @@ public IndexMapping rationalize(IndexMapping fontMapping, // Iterate through the old list for (int i = minXFRecords; i < xfRecords.size(); i++) { - XFRecord xf = (XFRecord) xfRecords.get(i); + XFRecord xf = xfRecords.get(i); // Compare against formats already on the list boolean duplicate = false; - for (Iterator it = newrecords.iterator(); - it.hasNext() && !duplicate;) + for (Iterator it = newrecords.iterator(); it.hasNext() && !duplicate;) { - XFRecord xf2 = (XFRecord) it.next(); + XFRecord xf2 = it.next(); if (xf2.equals(xf)) { duplicate = true; @@ -437,11 +417,8 @@ public IndexMapping rationalize(IndexMapping fontMapping, // It is sufficient to merely change the xf index field on all XFRecords // In this case, CellValues which refer to defunct format records // will nevertheless be written out with the correct index number - for (Iterator i = xfRecords.iterator(); i.hasNext();) - { - XFRecord xf = (XFRecord) i.next(); + for (XFRecord xf : xfRecords) xf.rationalize(mapping); - } // Set the new list xfRecords = newrecords; @@ -459,27 +436,27 @@ public IndexMapping rationalize(IndexMapping fontMapping, */ public IndexMapping rationalizeDisplayFormats() { - ArrayList newformats = new ArrayList(); + ArrayList newformats = new ArrayList<>(); int numremoved = 0; IndexMapping mapping = new IndexMapping(nextCustomIndexNumber); // Iterate through the old list - Iterator i = formatsList.iterator(); + Iterator i = formatsList.iterator(); DisplayFormat df = null; DisplayFormat df2 = null; boolean duplicate = false; while (i.hasNext()) { - df = (DisplayFormat) i.next(); + df = i.next(); Assert.verify(!df.isBuiltIn()); // Compare against formats already on the list - Iterator i2 = newformats.iterator(); + Iterator i2 = newformats.iterator(); duplicate = false; while (i2.hasNext() && !duplicate) { - df2 = (DisplayFormat) i2.next(); + df2 = i2.next(); if (df2.equals(df)) { duplicate = true; @@ -512,7 +489,7 @@ public IndexMapping rationalizeDisplayFormats() while (i.hasNext()) { - df = (DisplayFormat) i.next(); + df = i.next(); df.initialize(mapping.getNewIndex(df.getFormatIndex())); } diff --git a/src/jxl/biff/SheetRangeImpl.java b/src/jxl/biff/SheetRangeImpl.java index 1290a9f..1f833a4 100644 --- a/src/jxl/biff/SheetRangeImpl.java +++ b/src/jxl/biff/SheetRangeImpl.java @@ -219,19 +219,13 @@ public void insertRow(int r) public void insertColumn(int c) { if (c > column2) - { return; - } if (c <= column1) - { column1++; - } if (c <= column2) - { column2++; - } } /** @@ -242,19 +236,13 @@ public void insertColumn(int c) public void removeRow(int r) { if (r > row2) - { return; - } if (r < row1) - { row1--; - } - if (r < row2) - { + if (r <= row2 && row2 > 0) row2--; - } } /** @@ -265,19 +253,13 @@ public void removeRow(int r) public void removeColumn(int c) { if (c > column2) - { return; - } if (c < column1) - { column1--; - } - if (c < column2) - { + if (c <= column2 && column2 > 0) column2--; - } } /** @@ -285,6 +267,7 @@ public void removeColumn(int c) * * @return the hash code */ + @Override public int hashCode() { return 0xffff ^ row1 ^ row2 ^ column1 ^ column2; @@ -296,6 +279,7 @@ public int hashCode() * @param o the object to compare * @return TRUE if the two objects are the same, FALSE otherwise */ + @Override public boolean equals(Object o) { if (o == this) diff --git a/src/jxl/biff/StringHelper.java b/src/jxl/biff/StringHelper.java index f496321..1d274cb 100644 --- a/src/jxl/biff/StringHelper.java +++ b/src/jxl/biff/StringHelper.java @@ -39,7 +39,7 @@ public final class StringHelper // Due to a a Sun bug in some versions of JVM 1.4, the UnicodeLittle // encoding doesn't always work. Making this a public static field // enables client code access to this (but in an undocumented and - // unsupported fashion). Suggested alternative values for this + // unsupported fashion). Suggested alternative values for this // are "UTF-16LE" or "UnicodeLittleUnmarked" public static String UNICODE_ENCODING = "UnicodeLittle"; @@ -127,6 +127,20 @@ public static void getBytes(String s, byte[] d, int pos) System.arraycopy(b, 0, d, pos, b.length); } +/** + * Gets the ASCII bytes from the specified string and places them in the + * array at the specified position + * + * @param pos the position at which to place the converted data + * @param s the string to convert + * @param d the byte array which will contain the converted string data + */ + public static void getBytes(String s, byte[] d, int pos, WorkbookSettings ws) + { + byte[] b = getBytes(s, ws); + System.arraycopy(b, 0, d, pos, b.length); + } + /** * Inserts the unicode byte representation of the specified string into the * array passed in @@ -173,20 +187,82 @@ public static String getString(byte[] d, int length, int pos, } } + public static String readBiff8String(byte[] data) { + return readBiff8String(data, 0); + } + + public static String readBiff8String(byte[] data, int offset) { + int numberOfChars = IntegerHelper.getInt(data[offset], data[offset+1]); + + if (numberOfChars == 0) + return ""; + + int optionFlags = data[offset+2]; + boolean compressedUFT16 = (optionFlags & 0x01) == 0; + boolean containsAsianPhoneticSettings = ((optionFlags & 0x04) != 0); + boolean containsRichTextSettings = ((optionFlags & 0x08) != 0); + + int start = 3; + if (containsRichTextSettings) { + int numberOfRtRuns = IntegerHelper.getInt(data[offset+start], data[offset+start+1]); + start += 2; + } + + if (containsAsianPhoneticSettings) { + int phoneticSize = IntegerHelper.getInt(data[offset+start], data[offset+start+1], data[offset+start+2], data[offset+start+3]); + start += 4; + } + + if (compressedUFT16) + return getCompressedUnicodeString(data, offset+start, numberOfChars); + else + return getUnicodeString(data, offset+start, numberOfChars); + } + + public static String readShortBiff8String(byte[] data) { + int length = data.length; + boolean compressedUFT16 = (data[0] & 0x01) == 0; + if (compressedUFT16) + return getCompressedUnicodeString(data, 1, length - 1); + else + return getUnicodeString(data, 1, (length-1) / 2); + } + + + /** + * Gets a string from the data array when compressed + * + * A compressed string, omits the high bytes of all characters, if they are + * all zero. See "The Microsoft Excel File Format" + * Chapter 2.5.3 Unicode Strings (BIFF8). + * + * @param d The byte data + * @param length The number of characters to be converted into a string + * @param start The start position of the string + * @return the string built up from the unicode characters + */ + public static String getCompressedUnicodeString(byte[] d, int start, int length) { + byte[] b = new byte[length * 2]; + for (int i = 0; i < length; i++) + b[i*2] = d[i + start]; + + return getUnicodeString(b, 0, length); + } + /** * Gets a string from the data array * - * @param pos The start position of the string + * @param start The start position of the string * @param length The number of characters to be converted into a string * @param d The byte data * @return the string built up from the unicode characters */ - public static String getUnicodeString(byte[] d, int length, int pos) + public static String getUnicodeString(byte[] d, int start, int length) { try { byte[] b = new byte[length * 2]; - System.arraycopy(d, pos, b, 0, length * 2); + System.arraycopy(d, start, b, 0, length * 2); return new String(b, UNICODE_ENCODING); } catch (UnsupportedEncodingException e) @@ -197,7 +273,7 @@ public static String getUnicodeString(byte[] d, int length, int pos) } /** - * Replaces all instances of search with replace in the input. + * Replaces all instances of search with replace in the input. * Even though later versions of java can use string.replace() * this is included Java 1.2 compatibility * @@ -206,8 +282,8 @@ public static String getUnicodeString(byte[] d, int length, int pos) * @param replace the java equivalent * @return the input string with the specified substring replaced */ - public static final String replace(String input, - String search, + public static final String replace(String input, + String search, String replace) { String fmtstr = input; diff --git a/src/jxl/biff/Type.java b/src/jxl/biff/Type.java index ec820a8..fa969f3 100644 --- a/src/jxl/biff/Type.java +++ b/src/jxl/biff/Type.java @@ -20,76 +20,151 @@ package jxl.biff; /** - * An enumeration class which contains the biff types + * An enumeration class which contains the biff types */ -public final class Type +public enum Type { + BOF(0x809), + EOF(0x0a), + BOUNDSHEET(0x85), + SUPBOOK(0x1ae), + EXTERNSHEET(0x17), + DIMENSION(0x200), + BLANK(0x201), + MULBLANK(0xbe), + ROW(0x208), + NOTE(0x1c), + TXO(0x1b6), + RK (0x7e), + RK2 (0x27e), + MULRK (0xbd), + INDEX(0x20b), + DBCELL(0xd7), + SST(0xfc), + COLINFO(0x7d), + EXTSST(0xff), + CONTINUE(0x3c), + LABEL(0x204), + RSTRING(0xd6), + LABELSST(0xfd), + NUMBER(0x203), + NAME(0x18), + TABID(0x13d), + ARRAY(0x221), + STRING(0x207), + FORMULA(0x406), + FORMULA2(0x6), + SHAREDFORMULA(0x4bc), + FORMAT(0x41e), + XF(0xe0), + BOOLERR(0x205), + INTERFACEHDR(0xe1), + SAVERECALC(0x5f), + INTERFACEEND(0xe2), + XCT(0x59), + CRN(0x5a), + DEFCOLWIDTH(0x55), + DEFAULTROWHEIGHT(0x225), + WRITEACCESS(0x5c), + WSBOOL(0x81), + CODEPAGE(0x42), + DSF(0x161), + FNGROUPCOUNT(0x9c), + FILTERMODE(0x9b), + AUTOFILTERINFO(0x9d), + AUTOFILTER(0x9e), + COUNTRY(0x8c), + PROTECT(0x12), + SCENPROTECT(0xdd), + OBJPROTECT(0x63), + PRINTHEADERS(0x2a), + HEADER(0x14), + FOOTER(0x15), + HCENTER(0x83), + VCENTER(0x84), + FILEPASS(0x2f), + SETUP(0xa1), + PRINTGRIDLINES(0x2b), + GRIDSET(0x82), + GUTS(0x80), + WINDOWPROTECT(0x19), + PROT4REV(0x1af), + PROT4REVPASS(0x1bc), + PASSWORD(0x13), + REFRESHALL(0x1b7), + WINDOW1(0x3d), + WINDOW2(0x23e), + BACKUP(0x40), + HIDEOBJ(0x8d), + NINETEENFOUR(0x22), + PRECISION(0xe), + BOOKBOOL(0xda), + FONT(0x31), + MMS(0xc1), + CALCMODE(0x0d), + CALCCOUNT(0x0c), + REFMODE(0x0f), + TEMPLATE(0x60), + OBJPROJ(0xd3), + DELTA(0x10), + MERGEDCELLS(0xe5), + ITERATION(0x11), + STYLE(0x293), + USESELFS(0x160), + VERTICALPAGEBREAKS(0x1a), + HORIZONTALPAGEBREAKS(0x1b), + SELECTION(0x1d), + HLINK(0x1b8), + OBJ(0x5d), + MSODRAWING(0xec), + MSODRAWINGGROUP(0xeb), + LEFTMARGIN(0x26), + RIGHTMARGIN(0x27), + TOPMARGIN(0x28), + BOTTOMMARGIN(0x29), + EXTERNNAME(0x23), + PALETTE(0x92), + PLS(0x4d), + SCL(0xa0), + PANE(0x41), + WEIRD1(0xef), + SORT(0x90), + CONDFMT(0x1b0), + CF(0x1b1), + DV(0x1be), + DVAL(0x1b2), + BUTTONPROPERTYSET(0x1ba), + EXCEL9FILE(0x1c0), + + // Chart types + FONTX(0x1026), + IFMT(0x104e), + FBI(0x1060), + ALRUNS(0x1050), + SERIES(0x1003), + SERIESLIST(0x1016), + SBASEREF(0x1048), + UNKNOWN(0xffff), + + // Pivot stuff + + // Unknown types + U1C0(0x1c0), + U1C1(0x1c1); + /** * The biff value for this type */ public final int value; - /** - * An array of all types - */ - private static Type[] types = new Type[0]; /** * Constructor - * Sets the biff value and adds this type to the array of all types * * @param v the biff code for the type */ private Type(int v) { value = v; - - // Add to the list of available types - Type[] newTypes = new Type[types.length + 1]; - System.arraycopy(types, 0, newTypes, 0, types.length); - newTypes[types.length] = this; - types = newTypes; - } - - private static class ArbitraryType {}; - private static ArbitraryType arbitrary = new ArbitraryType(); - - /** - * Constructor used for the creation of arbitrary types - */ - private Type(int v, ArbitraryType arb) - { - value = v; - } - - /** - * Standard hash code method - * @return the hash code - */ - public int hashCode() - { - return value; - } - - /** - * Standard equals method - * @param o the object to compare - * @return TRUE if the objects are equal, FALSE otherwise - */ - public boolean equals(Object o) - { - if (o == this) - { - return true; - } - - if (!(o instanceof Type)) - { - return false; - } - - Type t = (Type) o; - - return value == t.value; } /** @@ -99,404 +174,11 @@ public boolean equals(Object o) */ public static Type getType(int v) { - for (int i = 0; i < types.length; i++) - { - if (types[i].value == v) - { - return types[i]; - } - } + for (Type t : values()) + if (t.value == v) + return t; return UNKNOWN; } - /** - * Used to create an arbitrary record type. This method is only - * used during bespoke debugging process. The creation of an - * arbitrary type does not add it to the static list of known types - */ - public static Type createType(int v) - { - return new Type(v, arbitrary); - } - - /** - */ - public static final Type BOF = new Type(0x809); - /** - */ - public static final Type EOF = new Type(0x0a); - /** - */ - public static final Type BOUNDSHEET = new Type(0x85); - /** - */ - public static final Type SUPBOOK = new Type(0x1ae); - /** - */ - public static final Type EXTERNSHEET = new Type(0x17); - /** - */ - public static final Type DIMENSION = new Type(0x200); - /** - */ - public static final Type BLANK = new Type(0x201); - /** - */ - public static final Type MULBLANK = new Type(0xbe); - /** - */ - public static final Type ROW = new Type(0x208); - /** - */ - public static final Type NOTE = new Type(0x1c); - /** - */ - public static final Type TXO = new Type(0x1b6); - /** - */ - public static final Type RK = new Type(0x7e); - /** - */ - public static final Type RK2 = new Type(0x27e); - /** - */ - public static final Type MULRK = new Type(0xbd); - /** - */ - public static final Type INDEX = new Type(0x20b); - /** - */ - public static final Type DBCELL = new Type(0xd7); - /** - */ - public static final Type SST = new Type(0xfc); - /** - */ - public static final Type COLINFO = new Type(0x7d); - /** - */ - public static final Type EXTSST = new Type(0xff); - /** - */ - public static final Type CONTINUE = new Type(0x3c); - /** - */ - public static final Type LABEL = new Type(0x204); - /** - */ - public static final Type RSTRING = new Type(0xd6); - /** - */ - public static final Type LABELSST = new Type(0xfd); - /** - */ - public static final Type NUMBER = new Type(0x203); - /** - */ - public static final Type NAME = new Type(0x18); - /** - */ - public static final Type TABID = new Type(0x13d); - /** - */ - public static final Type ARRAY = new Type(0x221); - /** - */ - public static final Type STRING = new Type(0x207); - /** - */ - public static final Type FORMULA = new Type(0x406); - /** - */ - public static final Type FORMULA2 = new Type(0x6); - /** - */ - public static final Type SHAREDFORMULA = new Type(0x4bc); - /** - */ - public static final Type FORMAT = new Type(0x41e); - /** - */ - public static final Type XF = new Type(0xe0); - /** - */ - public static final Type BOOLERR = new Type(0x205); - /** - */ - public static final Type INTERFACEHDR = new Type(0xe1); - /** - */ - public static final Type SAVERECALC = new Type(0x5f); - /** - */ - public static final Type INTERFACEEND = new Type(0xe2); - /** - */ - public static final Type XCT = new Type(0x59); - /** - */ - public static final Type CRN = new Type(0x5a); - /** - */ - public static final Type DEFCOLWIDTH = new Type(0x55); - /** - */ - public static final Type DEFAULTROWHEIGHT = new Type(0x225); - /** - */ - public static final Type WRITEACCESS = new Type(0x5c); - /** - */ - public static final Type WSBOOL = new Type(0x81); - /** - */ - public static final Type CODEPAGE = new Type(0x42); - /** - */ - public static final Type DSF = new Type(0x161); - /** - */ - public static final Type FNGROUPCOUNT = new Type(0x9c); - /** - */ - public static final Type FILTERMODE = new Type(0x9b); - /** - */ - public static final Type AUTOFILTERINFO = new Type(0x9d); - /** - */ - public static final Type AUTOFILTER = new Type(0x9e); - /** - */ - public static final Type COUNTRY = new Type(0x8c); - /** - */ - public static final Type PROTECT = new Type(0x12); - /** - */ - public static final Type SCENPROTECT = new Type(0xdd); - /** - */ - public static final Type OBJPROTECT = new Type(0x63); - /** - */ - public static final Type PRINTHEADERS = new Type(0x2a); - /** - */ - public static final Type HEADER = new Type(0x14); - /** - */ - public static final Type FOOTER = new Type(0x15); - /** - */ - public static final Type HCENTER = new Type(0x83); - /** - */ - public static final Type VCENTER = new Type(0x84); - /** - */ - public static final Type FILEPASS = new Type(0x2f); - /** - */ - public static final Type SETUP = new Type(0xa1); - /** - */ - public static final Type PRINTGRIDLINES = new Type(0x2b); - /** - */ - public static final Type GRIDSET = new Type(0x82); - /** - */ - public static final Type GUTS = new Type(0x80); - /** - */ - public static final Type WINDOWPROTECT = new Type(0x19); - /** - */ - public static final Type PROT4REV = new Type(0x1af); - /** - */ - public static final Type PROT4REVPASS = new Type(0x1bc); - /** - */ - public static final Type PASSWORD = new Type(0x13); - /** - */ - public static final Type REFRESHALL = new Type(0x1b7); - /** - */ - public static final Type WINDOW1 = new Type(0x3d); - /** - */ - public static final Type WINDOW2 = new Type(0x23e); - /** - */ - public static final Type BACKUP = new Type(0x40); - /** - */ - public static final Type HIDEOBJ = new Type(0x8d); - /** - */ - public static final Type NINETEENFOUR = new Type(0x22); - /** - */ - public static final Type PRECISION = new Type(0xe); - /** - */ - public static final Type BOOKBOOL = new Type(0xda); - /** - */ - public static final Type FONT = new Type(0x31); - /** - */ - public static final Type MMS = new Type(0xc1); - /** - */ - public static final Type CALCMODE = new Type(0x0d); - /** - */ - public static final Type CALCCOUNT = new Type(0x0c); - /** - */ - public static final Type REFMODE = new Type(0x0f); - /** - */ - public static final Type TEMPLATE = new Type(0x60); - /** - */ - public static final Type OBJPROJ = new Type(0xd3); - /** - */ - public static final Type DELTA = new Type(0x10); - /** - */ - public static final Type MERGEDCELLS = new Type(0xe5); - /** - */ - public static final Type ITERATION = new Type(0x11); - /** - */ - public static final Type STYLE = new Type(0x293); - /** - */ - public static final Type USESELFS = new Type(0x160); - /** - */ - public static final Type VERTICALPAGEBREAKS = new Type(0x1a); - /** - */ - public static final Type HORIZONTALPAGEBREAKS = new Type(0x1b); - /** - */ - public static final Type SELECTION = new Type(0x1d); - /** - */ - public static final Type HLINK = new Type(0x1b8); - /** - */ - public static final Type OBJ = new Type(0x5d); - /** - */ - public static final Type MSODRAWING = new Type(0xec); - /** - */ - public static final Type MSODRAWINGGROUP = new Type(0xeb); - /** - */ - public static final Type LEFTMARGIN = new Type(0x26); - /** - */ - public static final Type RIGHTMARGIN = new Type(0x27); - /** - */ - public static final Type TOPMARGIN = new Type(0x28); - /** - */ - public static final Type BOTTOMMARGIN = new Type(0x29); - /** - */ - public static final Type EXTERNNAME = new Type(0x23); - /** - */ - public static final Type PALETTE = new Type(0x92); - /** - */ - public static final Type PLS = new Type(0x4d); - /** - */ - public static final Type SCL = new Type(0xa0); - /** - */ - public static final Type PANE = new Type(0x41); - /** - */ - public static final Type WEIRD1 = new Type(0xef); - /** - */ - public static final Type SORT = new Type(0x90); - /** - */ - public static final Type CONDFMT = new Type(0x1b0); - /** - */ - public static final Type CF = new Type(0x1b1); - /** - */ - public static final Type DV = new Type(0x1be); - /** - */ - public static final Type DVAL = new Type(0x1b2); - /** - */ - public static final Type BUTTONPROPERTYSET = new Type(0x1ba); - /** - * - */ - public static final Type EXCEL9FILE = new Type(0x1c0); - - // Chart types - /** - */ - public static final Type FONTX = new Type(0x1026); - /** - */ - public static final Type IFMT = new Type(0x104e); - /** - */ - public static final Type FBI = new Type(0x1060); - /** - */ - public static final Type ALRUNS = new Type(0x1050); - /** - */ - public static final Type SERIES = new Type(0x1003); - /** - */ - public static final Type SERIESLIST = new Type(0x1016); - /** - */ - public static final Type SBASEREF = new Type(0x1048); - /** - */ - public static final Type UNKNOWN = new Type(0xffff); - - // Pivot stuff - /** - */ - // public static final Type R = new Type(0xffff); - - // Unknown types - public static final Type U1C0 = new Type(0x1c0); - public static final Type U1C1 = new Type(0x1c1); - -} - - - - - - - - - +} \ No newline at end of file diff --git a/src/jxl/biff/Version.java b/src/jxl/biff/Version.java new file mode 100644 index 0000000..dd6392f --- /dev/null +++ b/src/jxl/biff/Version.java @@ -0,0 +1,16 @@ +package jxl.biff; + +/** + * created 2020-05-30 + * @author jan + */ +public enum Version { + BIFF2 { @Override String getExcelVersion() { return "Excel 2.x"; } }, + BIFF3 { @Override String getExcelVersion() { return "Excel 3.0"; } }, + BIFF4 { @Override String getExcelVersion() { return "Excel 4.0"; } }, + BIFF5 { @Override String getExcelVersion() { return "Excel 5.0"; } }, + BIFF7 { @Override String getExcelVersion() { return "Excel 95/7.0"; } }, + BIFF8 { @Override String getExcelVersion() { return "Excel 97-2003/8-11"; } }; + + abstract String getExcelVersion(); +} diff --git a/src/jxl/biff/WorkspaceInformationRecord.java b/src/jxl/biff/WorkspaceInformationRecord.java index 06a6296..154409b 100644 --- a/src/jxl/biff/WorkspaceInformationRecord.java +++ b/src/jxl/biff/WorkspaceInformationRecord.java @@ -19,7 +19,6 @@ package jxl.biff; -import jxl.common.Logger; import jxl.read.biff.Record; /** @@ -27,9 +26,6 @@ */ public class WorkspaceInformationRecord extends WritableRecordData { - // the logger - private static Logger logger = - Logger.getLogger(WorkspaceInformationRecord.class); /** * The options byte @@ -69,9 +65,9 @@ public WorkspaceInformationRecord(Record t) byte[] data = getRecord().getData(); wsoptions = IntegerHelper.getInt(data[0], data[1]); - fitToPages = (wsoptions | FIT_TO_PAGES) != 0; - rowOutlines = (wsoptions | SHOW_ROW_OUTLINE_SYMBOLS) != 0; - columnOutlines = (wsoptions | SHOW_COLUMN_OUTLINE_SYMBOLS) != 0; + fitToPages = (wsoptions & FIT_TO_PAGES) != 0; + rowOutlines = (wsoptions & SHOW_ROW_OUTLINE_SYMBOLS) != 0; + columnOutlines = (wsoptions & SHOW_COLUMN_OUTLINE_SYMBOLS) != 0; } /** diff --git a/src/jxl/biff/XFRecord.java b/src/jxl/biff/XFRecord.java index c8fe9fa..3afd04f 100644 --- a/src/jxl/biff/XFRecord.java +++ b/src/jxl/biff/XFRecord.java @@ -233,7 +233,7 @@ public class XFRecord extends WritableRecordData implements CellFormat */ private FormattingRecords formattingRecords; - /** + /** * Constants for the used attributes */ private static final int USE_FONT = 0x4; @@ -383,7 +383,7 @@ public XFRecord(Record t, WorkbookSettings ws, BiffType bt) { number = true; DecimalFormat df = (DecimalFormat) javaNumberFormats[i].clone(); - DecimalFormatSymbols symbols = + DecimalFormatSymbols symbols = new DecimalFormatSymbols(ws.getLocale()); df.setDecimalFormatSymbols(symbols); numberFormat = df; @@ -443,7 +443,7 @@ public XFRecord(FontRecord fnt, DisplayFormat form) backgroundColour = Colour.DEFAULT_BACKGROUND; indentation = 0; shrinkToFit = false; - usedAttributes = (byte) (USE_FONT | USE_FORMAT | + usedAttributes = (byte) (USE_FONT | USE_FORMAT | USE_BACKGROUND | USE_ALIGNMENT | USE_BORDER); // This will be set by the initialize method and the subclass respectively @@ -763,9 +763,7 @@ public byte[] getData() data[8] = (byte) options; if (biffType == biff8) - { - data[9] = (byte) usedAttributes; - } + data[9] = usedAttributes; return data; } @@ -869,7 +867,7 @@ public Alignment getAlignment() * * @return the indentation */ - public int getIndentation() + public int getIndentation() { if (!formatInfoInitialized) { @@ -1056,8 +1054,8 @@ public boolean getWrap() protected void setXFBorder(Border b, BorderLineStyle ls, Colour c) { Assert.verify(!initialized); - - if (c == Colour.BLACK || c == Colour.UNKNOWN) + + if (c == Colour.BLACK || c == Colour.UNKNOWN) { c = Colour.PALETTE_BLACK; } @@ -1183,7 +1181,7 @@ else if (border == Border.BOTTOM) return bottomBorderColour; } - return Colour.BLACK; + return Colour.BLACK; } @@ -1345,15 +1343,10 @@ public Font getFont() private void initializeFormatInformation() { // Initialize the cell format string - if (formatIndex < BuiltInFormat.builtIns.length && - BuiltInFormat.builtIns[formatIndex] != null) - { - excelFormat = BuiltInFormat.builtIns[formatIndex]; - } + if (formatIndex < BuiltInFormat.builtIns.size()) + excelFormat = BuiltInFormat.builtIns.get(formatIndex); else - { excelFormat = formattingRecords.getFormatRecord(formatIndex); - } // Initialize the font font = formattingRecords.getFonts().getFont(fontIndex); @@ -1427,7 +1420,7 @@ private void initializeFormatInformation() topBorderColour = Colour.getInternalColour(borderColourMask & 0x7f); bottomBorderColour = Colour.getInternalColour ((borderColourMask & 0x3f80) >> 7); - + if (biffType == biff8) { // Get the background pattern. This is the six most significant bits @@ -1588,7 +1581,7 @@ public boolean equals(Object o) if (initialized && xfr.initialized) { - // Both formats are initialized, so it is sufficient to just do + // Both formats are initialized, so it is sufficient to just do // shallow equals on font, format objects, // since we are testing for the presence of clones anwyay // Use indices rather than objects because of the rationalization @@ -1669,7 +1662,7 @@ void rationalize(IndexMapping xfMapping) } /** - * Sets the font object with a workbook specific clone. Called from + * Sets the font object with a workbook specific clone. Called from * the CellValue object when the font has been identified as a statically * shared font * Also called to superimpose a HyperlinkFont on an existing label cell @@ -1679,7 +1672,7 @@ public void setFont(FontRecord f) // This style cannot be initialized, otherwise it would mean it would // have been initialized with shared font // However, sometimes (when setting a row or column format) an initialized - // XFRecord may have its font overridden by the column/row + // XFRecord may have its font overridden by the column/row font = f; } diff --git a/src/jxl/biff/drawing/Button.java b/src/jxl/biff/drawing/Button.java index 73ee0a9..ebb7870 100644 --- a/src/jxl/biff/drawing/Button.java +++ b/src/jxl/biff/drawing/Button.java @@ -20,6 +20,7 @@ package jxl.biff.drawing; import java.io.IOException; +import java.util.*; import jxl.common.Assert; import jxl.common.Logger; @@ -806,7 +807,7 @@ public String getText() else { commentText = StringHelper.getUnicodeString - (td, (td.length - 1) / 2, 1); + (td, 1, (td.length - 1) / 2); } } @@ -818,8 +819,21 @@ public String getText() * * @return the hash code */ - public int hashCode() + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + final Button other = (Button) obj; + return Objects.equals(this.commentText, other.commentText); + } + + @Override + public int hashCode() { return commentText.hashCode(); } diff --git a/src/jxl/biff/drawing/Comment.java b/src/jxl/biff/drawing/Comment.java index 71428c7..393e3ce 100644 --- a/src/jxl/biff/drawing/Comment.java +++ b/src/jxl/biff/drawing/Comment.java @@ -1,730 +1,278 @@ -/********************************************************************* -* -* Copyright (C) 2002 Andrew Khan -* -* This library is free software; you can redistribute it and/or -* modify it under the terms of the GNU Lesser General Public -* License as published by the Free Software Foundation; either -* version 2.1 of the License, or (at your option) any later version. -* -* This library is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -* Lesser General Public License for more details. -* -* You should have received a copy of the GNU Lesser General Public -* License along with this library; if not, write to the Free Software -* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -***************************************************************************/ - package jxl.biff.drawing; -import java.io.IOException; - -import jxl.common.Assert; -import jxl.common.Logger; - -import jxl.WorkbookSettings; -import jxl.biff.ContinueRecord; -import jxl.biff.IntegerHelper; -import jxl.biff.StringHelper; +import java.io.*; +import jxl.biff.*; +import jxl.write.biff.*; import jxl.write.biff.File; /** - * Contains the various biff records used to insert a cell note into a - * worksheet + * created 29.05.2020 + * @author jan */ -public class Comment implements DrawingGroupObject -{ - /** - * The logger - */ - private static Logger logger = Logger.getLogger(Comment.class); - - /** - * The spContainer that was read in - */ - private EscherContainer readSpContainer; - - /** - * The spContainer that was generated - */ - private EscherContainer spContainer; - - /** - * The MsoDrawingRecord associated with the drawing - */ - private MsoDrawingRecord msoDrawingRecord; - - /** - * The ObjRecord associated with the drawing - */ - private ObjRecord objRecord; - - /** - * Initialized flag - */ - private boolean initialized = false; - - /** - * The object id, assigned by the drawing group - */ - private int objectId; - - /** - * The blip id - */ - private int blipId; - - /** - * The shape id - */ - private int shapeId; - - /** - * The column - */ - private int column; - - /** - * The row position of the image - */ - private int row; +public interface Comment extends DrawingGroupObject { /** - * The width of the image in cells - */ - private double width; - - /** - * The height of the image in cells - */ - private double height; - - /** - * The number of places this drawing is referenced - */ - private int referenceCount; - - /** - * The top level escher container - */ - private EscherContainer escherData; - - /** - * Where this image came from (read, written or a copy) - */ - private Origin origin; - - /** - * The drawing group for all the images - */ - private DrawingGroup drawingGroup; - - /** - * The drawing data - */ - private DrawingData drawingData; - - /** - * The type of this drawing object - */ - private ShapeType type; - - /** - * The drawing position on the sheet - */ - private int drawingNumber; - - /** - * An mso drawing record, which sometimes appears - */ - private MsoDrawingRecord mso; - - /** - * The text object record + * Adds an mso record to this object + * + * @param d the mso record */ - private TextObjectRecord txo; + void addMso(MsoDrawingRecord d); /** - * The note record + * Accessor for the blip id + * + * @return the blip id */ - private NoteRecord note; + int getBlipId(); /** - * Text data from the first continue record + * Accessor for the column + * + * @return the column */ - private ContinueRecord text; + int getColumn(); /** - * Formatting data from the second continue record + * Accessor for the drawing group + * + * @return the drawing group */ - private ContinueRecord formatting; + DrawingGroup getDrawingGroup(); /** - * The comment text + * Accessor for the height of this drawing + * + * @return the number of rows spanned by this image */ - private String commentText; + double getHeight(); /** - * The workbook settings + * Accessor for the image data + * + * @return the image data */ - private WorkbookSettings workbookSettings; + byte[] getImageBytes(); /** - * Constructor used when reading images + * Accessor for the image data * - * @param msorec the drawing record - * @param obj the object record - * @param dd the drawing data for all drawings on this sheet - * @param dg the drawing group - * @param ws the workbook settings - */ - public Comment(MsoDrawingRecord msorec, ObjRecord obj, DrawingData dd, - DrawingGroup dg, WorkbookSettings ws) - { - drawingGroup = dg; - msoDrawingRecord = msorec; - drawingData = dd; - objRecord = obj; - initialized = false; - workbookSettings = ws; - origin = Origin.READ; - drawingData.addData(msoDrawingRecord.getData()); - drawingNumber = drawingData.getNumDrawings() - 1; - drawingGroup.addDrawing(this); - - Assert.verify(msoDrawingRecord != null && objRecord != null); - - if (!initialized) - { - initialize(); - } - } - - /** - * Copy constructor used to copy drawings from read to write - * - * @param dgo the drawing group object - * @param dg the drawing group - * @param ws the workbook settings - */ - /*protected*/ public Comment(DrawingGroupObject dgo, - DrawingGroup dg, - WorkbookSettings ws) - { - Comment d = (Comment) dgo; - Assert.verify(d.origin == Origin.READ); - msoDrawingRecord = d.msoDrawingRecord; - objRecord = d.objRecord; - initialized = false; - origin = Origin.READ; - drawingData = d.drawingData; - drawingGroup = dg; - drawingNumber = d.drawingNumber; - drawingGroup.addDrawing(this); - mso = d.mso; - txo = d.txo; - text = d.text; - formatting = d.formatting; - note = d.note; - width = d.width; - height = d.height; - workbookSettings = ws; - } - - /** - * Constructor invoked when writing the images - * - * @param txt the comment text - * @param c the column - * @param r the row - */ - public Comment(String txt, int c, int r) - { - initialized = true; - origin = Origin.WRITE; - column = c; - row = r; - referenceCount = 1; - type = ShapeType.TEXT_BOX; - commentText = txt; - width = 3; - height = 4; - } - - /** - * Initializes the member variables from the Escher stream data - */ - private void initialize() - { - readSpContainer = drawingData.getSpContainer(drawingNumber); - Assert.verify(readSpContainer != null); - - EscherRecord[] children = readSpContainer.getChildren(); - - Sp sp = (Sp) readSpContainer.getChildren()[0]; - objectId = objRecord.getObjectId(); - shapeId = sp.getShapeId(); - type = ShapeType.getType(sp.getShapeType()); - - if (type == ShapeType.UNKNOWN) - { - logger.warn("Unknown shape type"); - } - - ClientAnchor clientAnchor = null; - for (int i = 0; i < children.length && clientAnchor == null; i++) - { - if (children[i].getType() == EscherRecordType.CLIENT_ANCHOR) - { - clientAnchor = (ClientAnchor) children[i]; - } - } - - if (clientAnchor == null) - { - logger.warn("client anchor not found"); - } - else - { - column = (int) clientAnchor.getX1() - 1; - row = (int) clientAnchor.getY1() + 1; - width = clientAnchor.getX2() - clientAnchor.getX1(); - height = clientAnchor.getY2() - clientAnchor.getY1(); - } - - initialized = true; - } - + * @return the image data + */ + byte[] getImageData(); /** - * Sets the object id. Invoked by the drawing group when the object is - * added to id + * Accessor for the image file path. Normally this is the absolute path + * of a file on the directory system, but if this drawing was constructed + * using an byte[] then the blip id is returned * - * @param objid the object id - * @param bip the blip id - * @param sid the shape id + * @return the image file path, or the blip id */ - public final void setObjectId(int objid, int bip, int sid) - { - objectId = objid; - blipId = bip; - shapeId = sid; - - if (origin == Origin.READ) - { - origin = Origin.READ_WRITE; - } - } + String getImageFilePath(); /** - * Accessor for the object id + * Gets the drawing record which was read in * - * @return the object id + * @return the drawing record */ - public final int getObjectId() - { - if (!initialized) - { - initialize(); - } - - return objectId; - } + MsoDrawingRecord getMsoDrawingRecord(); /** - * Accessor for the shape id + * Accessor for the object id * * @return the object id */ - public final int getShapeId() - { - if (!initialized) - { - initialize(); - } - - return shapeId; - } + int getObjectId(); /** - * Accessor for the blip id + * Gets the origin of this drawing * - * @return the blip id + * @return where this drawing came from */ - public final int getBlipId() - { - if (!initialized) - { - initialize(); - } - - return blipId; - } + Origin getOrigin(); /** - * Gets the drawing record which was read in + * Accessor for the reference count on this drawing * - * @return the drawing record + * @return the reference count */ - public MsoDrawingRecord getMsoDrawingRecord() - { - return msoDrawingRecord; - } + int getReferenceCount(); /** - * Creates the main Sp container for the drawing + * Accessor for the row * - * @return the SP container + * @return the row */ - public EscherContainer getSpContainer() - { - if (!initialized) - { - initialize(); - } - - if (origin == Origin.READ) - { - return getReadSpContainer(); - } - - if (spContainer == null) - { - spContainer = new SpContainer(); - Sp sp = new Sp(type, shapeId, 2560); - spContainer.add(sp); - Opt opt = new Opt(); - opt.addProperty(344, false, false, 0); // ? - opt.addProperty(385, false, false, 134217808); // fill colour - opt.addProperty(387, false, false, 134217808); // background colour - opt.addProperty(959, false, false, 131074); // hide - spContainer.add(opt); - - ClientAnchor clientAnchor = new ClientAnchor(column + 1.3, - Math.max(0, row - 0.6), - column + 1.3 + width, - row + height, - 0x1); - - spContainer.add(clientAnchor); - - ClientData clientData = new ClientData(); - spContainer.add(clientData); - - ClientTextBox clientTextBox = new ClientTextBox(); - spContainer.add(clientTextBox); - } - - return spContainer; - } + int getRow(); /** - * Sets the drawing group for this drawing. Called by the drawing group - * when this drawing is added to it + * Accessor for the shape id * - * @param dg the drawing group + * @return the object id */ - public void setDrawingGroup(DrawingGroup dg) - { - drawingGroup = dg; - } + @Override + int getShapeId(); /** - * Accessor for the drawing group + * Creates the main Sp container for the drawing * - * @return the drawing group + * @return the SP container */ - public DrawingGroup getDrawingGroup() - { - return drawingGroup; - } + @Override + EscherContainer getSpContainer(); /** - * Gets the origin of this drawing + * Accessor for the comment text * - * @return where this drawing came from + * @return the comment text */ - public Origin getOrigin() - { - return origin; - } + String getText(); /** - * Accessor for the reference count on this drawing + * Accessor for the type * - * @return the reference count + * @return the type */ - public int getReferenceCount() - { - return referenceCount; - } + @Override + ShapeType getType(); /** - * Sets the new reference count on the drawing + * Accessor for the width of this drawing * - * @param r the new reference count + * @return the number of columns spanned by this image */ - public void setReferenceCount(int r) - { - referenceCount = r; - } + @Override + double getWidth(); /** * Accessor for the column of this drawing * * @return the column */ - public double getX() - { - if (!initialized) - { - initialize(); - } - return column; - } - - /** - * Sets the column position of this drawing. Used when inserting/removing - * columns from the spreadsheet - * - * @param x the column - */ - public void setX(double x) - { - if (origin == Origin.READ) - { - if (!initialized) - { - initialize(); - } - origin = Origin.READ_WRITE; - } - - column = (int) x; - } + @Override + double getX(); /** * Accessor for the row of this drawing * * @return the row */ - public double getY() - { - if (!initialized) - { - initialize(); - } - - return row; - } + @Override + double getY(); /** - * Accessor for the row of the drawing - * - * @param y the row - */ - public void setY(double y) - { - if (origin == Origin.READ) - { - if (!initialized) - { - initialize(); - } - origin = Origin.READ_WRITE; - } - - row = (int) y; - } - - - /** - * Accessor for the width of this drawing + * Accessor for the first drawing on the sheet. This is used when + * copying unmodified sheets to indicate that this drawing contains + * the first time Escher gubbins * - * @return the number of columns spanned by this image + * @return TRUE if this MSORecord is the first drawing on the sheet */ - public double getWidth() - { - if (!initialized) - { - initialize(); - } - - return width; - } + @Override + boolean isFirst(); /** - * Accessor for the width + * Queries whether this object is a form object. Form objects have their + * drawings records spread over several records and require special handling * - * @param w the number of columns to span + * @return TRUE if this is a form object, FALSE otherwise */ - public void setWidth(double w) - { - if (origin == Origin.READ) - { - if (!initialized) - { - initialize(); - } - origin = Origin.READ_WRITE; - } - - width = w; - } + @Override + boolean isFormObject(); /** - * Accessor for the height of this drawing + * Called when the comment text is changed during the sheet copy process * - * @return the number of rows spanned by this image + * @param t the new text */ - public double getHeight() - { - if (!initialized) - { - initialize(); - } - - return height; - } + void setCommentText(String t); /** - * Accessor for the height of this drawing + * Sets the drawing group for this drawing. Called by the drawing group + * when this drawing is added to it * - * @param h the number of rows spanned by this image + * @param dg the drawing group */ - public void setHeight(double h) - { - if (origin == Origin.READ) - { - if (!initialized) - { - initialize(); - } - origin = Origin.READ_WRITE; - } - - height = h; - } - + @Override + void setDrawingGroup(DrawingGroup dg); /** - * Gets the SpContainer that was read in + * Sets the formatting * - * @return the read sp container + * @param t the formatting record */ - private EscherContainer getReadSpContainer() - { - if (!initialized) - { - initialize(); - } - - return readSpContainer; - } + void setFormatting(ContinueRecord t); /** - * Accessor for the image data + * Accessor for the height of this drawing * - * @return the image data + * @param h the number of rows spanned by this image */ - public byte[] getImageData() - { - Assert.verify(origin == Origin.READ || origin == Origin.READ_WRITE); - - if (!initialized) - { - initialize(); - } - - return drawingGroup.getImageData(blipId); - } + @Override + void setHeight(double h); /** - * Accessor for the type + * Sets the note object * - * @return the type + * @param t the note record */ - public ShapeType getType() - { - return type; - } + void setNote(NoteRecord t); /** - * Sets the text object + * Sets the object id. Invoked by the drawing group when the object is + * added to id * - * @param t the text object + * @param objid the object id + * @param bip the blip id + * @param sid the shape id */ - public void setTextObject(TextObjectRecord t) - { - txo = t; - } + @Override + void setObjectId(int objid, int bip, int sid); /** - * Sets the note object + * Sets the new reference count on the drawing * - * @param t the note record + * @param r the new reference count */ - public void setNote(NoteRecord t) - { - note = t; - } + @Override + void setReferenceCount(int r); /** * Sets the text data * * @param t the text data */ - public void setText(ContinueRecord t) - { - text = t; - } + void setText(ContinueRecord t); /** - * Sets the formatting + * Sets the text object * - * @param t the formatting record + * @param t the text object */ - public void setFormatting(ContinueRecord t) - { - formatting = t; - } + void setTextObject(TextObjectRecord t); /** - * Accessor for the image data + * Accessor for the width * - * @return the image data + * @param w the number of columns to span */ - public byte[] getImageBytes() - { - Assert.verify(false); - return null; - } + @Override + void setWidth(double w); /** - * Accessor for the image file path. Normally this is the absolute path - * of a file on the directory system, but if this drawing was constructed - * using an byte[] then the blip id is returned + * Sets the column position of this drawing. Used when inserting/removing + * columns from the spreadsheet * - * @return the image file path, or the blip id + * @param x the column */ - public String getImageFilePath() - { - Assert.verify(false); - return null; - } + @Override + void setX(double x); /** - * Adds an mso record to this object + * Accessor for the row of the drawing * - * @param d the mso record + * @param y the row */ - public void addMso(MsoDrawingRecord d) - { - mso = d; - drawingData.addRawData(mso.getData()); - } + @Override + void setY(double y); /** * Writes out the additional comment records @@ -732,62 +280,8 @@ public void addMso(MsoDrawingRecord d) * @param outputFile the output file * @exception IOException */ - public void writeAdditionalRecords(File outputFile) throws IOException - { - if (origin == Origin.READ) - { - outputFile.write(objRecord); - - if (mso != null) - { - outputFile.write(mso); - } - outputFile.write(txo); - outputFile.write(text); - if (formatting != null) - { - outputFile.write(formatting); - } - return; - } - - // Create the obj record - ObjRecord objrec = new ObjRecord(objectId, - ObjRecord.EXCELNOTE); - - outputFile.write(objrec); - - // Create the mso data record. Write the text box record again, - // although it is already included in the SpContainer - ClientTextBox textBox = new ClientTextBox(); - MsoDrawingRecord msod = new MsoDrawingRecord(textBox.getData()); - outputFile.write(msod); - - TextObjectRecord txorec = new TextObjectRecord(getText()); - outputFile.write(txorec); - - // Data for the first continue record - byte[] textData = new byte[commentText.length() * 2 + 1]; - textData[0] = 0x1; // unicode indicator - StringHelper.getUnicodeBytes(commentText, textData, 1); - //StringHelper.getBytes(commentText, textData, 1); - ContinueRecord textContinue = new ContinueRecord(textData); - outputFile.write(textContinue); - - // Data for the formatting runs - - byte[] frData = new byte[16]; - - // First txo run (the user) - IntegerHelper.getTwoBytes(0, frData, 0); // index to the first character - IntegerHelper.getTwoBytes(0, frData, 2); // index to the font(default) - // Mandatory last txo run - IntegerHelper.getTwoBytes(commentText.length(), frData, 8); - IntegerHelper.getTwoBytes(0, frData, 10); // index to the font(default) - - ContinueRecord frContinue = new ContinueRecord(frData); - outputFile.write(frContinue); - } + @Override + void writeAdditionalRecords(File outputFile) throws IOException; /** * Writes any records that need to be written after all the drawing group @@ -797,114 +291,7 @@ public void writeAdditionalRecords(File outputFile) throws IOException * @param outputFile the output file * @exception IOException */ - public void writeTailRecords(File outputFile) throws IOException - { - if (origin == Origin.READ) - { - outputFile.write(note); - return; - } - - // The note record - NoteRecord noteRecord = new NoteRecord(column, row, objectId); - outputFile.write(noteRecord); - } - - /** - * Accessor for the row - * - * @return the row - */ - public int getRow() - { - return note.getRow(); - } - - /** - * Accessor for the column - * - * @return the column - */ - public int getColumn() - { - return note.getColumn(); - } - - /** - * Accessor for the comment text - * - * @return the comment text - */ - public String getText() - { - if (commentText == null) - { - Assert.verify(text != null); - - byte[] td = text.getData(); - if (td[0] == 0) - { - commentText = StringHelper.getString - (td, td.length - 1, 1, workbookSettings); - } - else - { - commentText = StringHelper.getUnicodeString - (td, (td.length - 1) / 2, 1); - } - } - - return commentText; - } - - /** - * Hashing algorithm - * - * @return the hash code - */ - public int hashCode() - { - return commentText.hashCode(); - } - - /** - * Called when the comment text is changed during the sheet copy process - * - * @param t the new text - */ - public void setCommentText(String t) - { - commentText = t; - - if (origin == Origin.READ) - { - origin = Origin.READ_WRITE; - } - } - - /** - * Accessor for the first drawing on the sheet. This is used when - * copying unmodified sheets to indicate that this drawing contains - * the first time Escher gubbins - * - * @return TRUE if this MSORecord is the first drawing on the sheet - */ - public boolean isFirst() - { - return msoDrawingRecord.isFirst(); - } + @Override + void writeTailRecords(File outputFile) throws IOException; - /** - * Queries whether this object is a form object. Form objects have their - * drawings records spread over several records and require special handling - * - * @return TRUE if this is a form object, FALSE otherwise - */ - public boolean isFormObject() - { - return true; - } } - - - diff --git a/src/jxl/biff/drawing/CommentBiff7.java b/src/jxl/biff/drawing/CommentBiff7.java new file mode 100644 index 0000000..94fd663 --- /dev/null +++ b/src/jxl/biff/drawing/CommentBiff7.java @@ -0,0 +1,65 @@ + +package jxl.biff.drawing; + +import jxl.*; +import jxl.biff.*; +import jxl.common.*; + +/** + * created 29.05.2020 + * @author jan + */ +public class CommentBiff7 extends CommentBiff8 { + + /** + * The workbook settings + */ + private final WorkbookSettings workbookSettings; + + public CommentBiff7( + MsoDrawingRecord msorec, + ObjRecord obj, + DrawingData dd, + DrawingGroup dg, + WorkbookSettings workbookSettings) { + super(msorec, obj, dd, dg); + this.workbookSettings = workbookSettings; + } + + public CommentBiff7( + DrawingGroupObject dgo, + DrawingGroup dg, + WorkbookSettings workbookSettings) { + super(dgo, dg); + this.workbookSettings = workbookSettings; + } + + public CommentBiff7( + String txt, int c, int r, WorkbookSettings workbookSettings) { + super(txt, c, r); + this.workbookSettings = workbookSettings; + } + + @Override + public String getText() { + if (commentText == null) + { + Assert.verify(text != null); + + byte[] td = text.getData(); + if (td[0] == 0) + { + commentText = StringHelper.getString + (td, td.length - 1, 1, workbookSettings); + } + else + { + commentText = StringHelper.getUnicodeString + (td, 1, (td.length - 1) / 2); + } + } + + return commentText; + } + +} diff --git a/src/jxl/biff/drawing/CommentBiff8.java b/src/jxl/biff/drawing/CommentBiff8.java new file mode 100644 index 0000000..8fd58fe --- /dev/null +++ b/src/jxl/biff/drawing/CommentBiff8.java @@ -0,0 +1,937 @@ +/********************************************************************* +* +* Copyright (C) 2002 Andrew Khan +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License as published by the Free Software Foundation; either +* version 2.1 of the License, or (at your option) any later version. +* +* This library is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public +* License along with this library; if not, write to the Free Software +* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +***************************************************************************/ + +package jxl.biff.drawing; + +import java.io.IOException; +import java.util.*; + +import jxl.common.Assert; +import jxl.common.Logger; + +import jxl.biff.ContinueRecord; +import jxl.biff.IntegerHelper; +import jxl.biff.StringHelper; +import jxl.write.biff.File; + +/** + * Contains the various biff records used to insert a cell note into a + * worksheet + */ +public class CommentBiff8 implements Comment +{ + /** + * The logger + */ + private static Logger logger = Logger.getLogger(CommentBiff8.class); + + /** + * The spContainer that was read in + */ + private EscherContainer readSpContainer; + + /** + * The spContainer that was generated + */ + private EscherContainer spContainer; + + /** + * The MsoDrawingRecord associated with the drawing + */ + private MsoDrawingRecord msoDrawingRecord; + + /** + * The ObjRecord associated with the drawing + */ + private ObjRecord objRecord; + + /** + * Initialized flag + */ + private boolean initialized = false; + + /** + * The object id, assigned by the drawing group + */ + private int objectId; + + /** + * The blip id + */ + private int blipId; + + /** + * The shape id + */ + private int shapeId; + + /** + * The column + */ + private int column; + + /** + * The row position of the image + */ + private int row; + + /** + * The width of the image in cells + */ + private double width; + + /** + * The height of the image in cells + */ + private double height; + + /** + * The number of places this drawing is referenced + */ + private int referenceCount; + + /** + * The top level escher container + */ + private EscherContainer escherData; + + /** + * Where this image came from (read, written or a copy) + */ + private Origin origin; + + /** + * The drawing group for all the images + */ + private DrawingGroup drawingGroup; + + /** + * The drawing data + */ + private DrawingData drawingData; + + /** + * The type of this drawing object + */ + private ShapeType type; + + /** + * The drawing position on the sheet + */ + private int drawingNumber; + + /** + * An mso drawing record, which sometimes appears + */ + private MsoDrawingRecord mso; + + /** + * The text object record + */ + private TextObjectRecord txo; + + /** + * The note record + */ + private NoteRecord note; + + /** + * Text data from the first continue record + */ + protected ContinueRecord text; + + /** + * Formatting data from the second continue record + */ + private ContinueRecord formatting; + + /** + * The comment text + */ + protected String commentText; + + /** + * Constructor used when reading images + * + * @param msorec the drawing record + * @param obj the object record + * @param dd the drawing data for all drawings on this sheet + * @param dg the drawing group + * @param ws the workbook settings + */ + public CommentBiff8(MsoDrawingRecord msorec, ObjRecord obj, DrawingData dd, + DrawingGroup dg) + { + drawingGroup = dg; + msoDrawingRecord = msorec; + drawingData = dd; + objRecord = obj; + initialized = false; + origin = Origin.READ; + drawingData.addData(msoDrawingRecord.getData()); + drawingNumber = drawingData.getNumDrawings() - 1; + drawingGroup.addDrawing(this); + + Assert.verify(msoDrawingRecord != null && objRecord != null); + + if (!initialized) + { + initialize(); + } + } + + /** + * Copy constructor used to copy drawings from read to write + * + * @param dgo the drawing group object + * @param dg the drawing group + * @param ws the workbook settings + */ + /*protected*/ public CommentBiff8(DrawingGroupObject dgo, + DrawingGroup dg) + { + CommentBiff8 d = (CommentBiff8) dgo; + Assert.verify(d.origin == Origin.READ); + msoDrawingRecord = d.msoDrawingRecord; + objRecord = d.objRecord; + initialized = false; + origin = Origin.READ; + drawingData = d.drawingData; + drawingGroup = dg; + drawingNumber = d.drawingNumber; + drawingGroup.addDrawing(this); + mso = d.mso; + txo = d.txo; + text = d.text; + formatting = d.formatting; + note = d.note; + width = d.width; + height = d.height; + } + + /** + * Constructor invoked when writing the images + * + * @param txt the comment text + * @param c the column + * @param r the row + */ + public CommentBiff8(String txt, int c, int r) + { + initialized = true; + origin = Origin.WRITE; + column = c; + row = r; + referenceCount = 1; + type = ShapeType.TEXT_BOX; + commentText = txt; + width = 3; + height = 4; + } + + /** + * Initializes the member variables from the Escher stream data + */ + private void initialize() + { + readSpContainer = drawingData.getSpContainer(drawingNumber); + Assert.verify(readSpContainer != null); + + EscherRecord[] children = readSpContainer.getChildren(); + + Sp sp = (Sp) readSpContainer.getChildren()[0]; + objectId = objRecord.getObjectId(); + shapeId = sp.getShapeId(); + type = ShapeType.getType(sp.getShapeType()); + + if (type == ShapeType.UNKNOWN) + { + logger.warn("Unknown shape type"); + } + + ClientAnchor clientAnchor = null; + for (int i = 0; i < children.length && clientAnchor == null; i++) + { + if (children[i].getType() == EscherRecordType.CLIENT_ANCHOR) + { + clientAnchor = (ClientAnchor) children[i]; + } + } + + if (clientAnchor == null) + { + logger.warn("client anchor not found"); + } + else + { + column = (int) clientAnchor.getX1() - 1; + row = (int) clientAnchor.getY1() + 1; + width = clientAnchor.getX2() - clientAnchor.getX1(); + height = clientAnchor.getY2() - clientAnchor.getY1(); + } + + initialized = true; + } + + + /** + * Sets the object id. Invoked by the drawing group when the object is + * added to id + * + * @param objid the object id + * @param bip the blip id + * @param sid the shape id + */ + @Override + public final void setObjectId(int objid, int bip, int sid) + { + objectId = objid; + blipId = bip; + shapeId = sid; + + if (origin == Origin.READ) + { + origin = Origin.READ_WRITE; + } + } + + /** + * Accessor for the object id + * + * @return the object id + */ + @Override + public final int getObjectId() + { + if (!initialized) + { + initialize(); + } + + return objectId; + } + + /** + * Accessor for the shape id + * + * @return the object id + */ + @Override + public final int getShapeId() + { + if (!initialized) + { + initialize(); + } + + return shapeId; + } + + /** + * Accessor for the blip id + * + * @return the blip id + */ + @Override + public final int getBlipId() + { + if (!initialized) + { + initialize(); + } + + return blipId; + } + + /** + * Gets the drawing record which was read in + * + * @return the drawing record + */ + @Override + public MsoDrawingRecord getMsoDrawingRecord() + { + return msoDrawingRecord; + } + + /** + * Creates the main Sp container for the drawing + * + * @return the SP container + */ + @Override + public EscherContainer getSpContainer() + { + if (!initialized) + { + initialize(); + } + + if (origin == Origin.READ) + { + return getReadSpContainer(); + } + + if (spContainer == null) + { + spContainer = new SpContainer(); + Sp sp = new Sp(type, shapeId, 2560); + spContainer.add(sp); + Opt opt = new Opt(); + opt.addProperty(344, false, false, 0); // ? + opt.addProperty(385, false, false, 134217808); // fill colour + opt.addProperty(387, false, false, 134217808); // background colour + opt.addProperty(959, false, false, 131074); // hide + spContainer.add(opt); + + ClientAnchor clientAnchor = new ClientAnchor(column + 1.3, + Math.max(0, row - 0.6), + column + 1.3 + width, + row + height, + 0x1); + + spContainer.add(clientAnchor); + + ClientData clientData = new ClientData(); + spContainer.add(clientData); + + ClientTextBox clientTextBox = new ClientTextBox(); + spContainer.add(clientTextBox); + } + + return spContainer; + } + + /** + * Sets the drawing group for this drawing. Called by the drawing group + * when this drawing is added to it + * + * @param dg the drawing group + */ + @Override + public void setDrawingGroup(DrawingGroup dg) + { + drawingGroup = dg; + } + + /** + * Accessor for the drawing group + * + * @return the drawing group + */ + @Override + public DrawingGroup getDrawingGroup() + { + return drawingGroup; + } + + /** + * Gets the origin of this drawing + * + * @return where this drawing came from + */ + @Override + public Origin getOrigin() + { + return origin; + } + + /** + * Accessor for the reference count on this drawing + * + * @return the reference count + */ + @Override + public int getReferenceCount() + { + return referenceCount; + } + + /** + * Sets the new reference count on the drawing + * + * @param r the new reference count + */ + @Override + public void setReferenceCount(int r) + { + referenceCount = r; + } + + /** + * Accessor for the column of this drawing + * + * @return the column + */ + @Override + public double getX() + { + if (!initialized) + { + initialize(); + } + return column; + } + + /** + * Sets the column position of this drawing. Used when inserting/removing + * columns from the spreadsheet + * + * @param x the column + */ + @Override + public void setX(double x) + { + if (origin == Origin.READ) + { + if (!initialized) + { + initialize(); + } + origin = Origin.READ_WRITE; + } + + column = (int) x; + } + + /** + * Accessor for the row of this drawing + * + * @return the row + */ + @Override + public double getY() + { + if (!initialized) + { + initialize(); + } + + return row; + } + + /** + * Accessor for the row of the drawing + * + * @param y the row + */ + @Override + public void setY(double y) + { + if (origin == Origin.READ) + { + if (!initialized) + { + initialize(); + } + origin = Origin.READ_WRITE; + } + + row = (int) y; + } + + + /** + * Accessor for the width of this drawing + * + * @return the number of columns spanned by this image + */ + @Override + public double getWidth() + { + if (!initialized) + { + initialize(); + } + + return width; + } + + /** + * Accessor for the width + * + * @param w the number of columns to span + */ + @Override + public void setWidth(double w) + { + if (origin == Origin.READ) + { + if (!initialized) + { + initialize(); + } + origin = Origin.READ_WRITE; + } + + width = w; + } + + /** + * Accessor for the height of this drawing + * + * @return the number of rows spanned by this image + */ + @Override + public double getHeight() + { + if (!initialized) + { + initialize(); + } + + return height; + } + + /** + * Accessor for the height of this drawing + * + * @param h the number of rows spanned by this image + */ + @Override + public void setHeight(double h) + { + if (origin == Origin.READ) + { + if (!initialized) + { + initialize(); + } + origin = Origin.READ_WRITE; + } + + height = h; + } + + + /** + * Gets the SpContainer that was read in + * + * @return the read sp container + */ + private EscherContainer getReadSpContainer() + { + if (!initialized) + { + initialize(); + } + + return readSpContainer; + } + + /** + * Accessor for the image data + * + * @return the image data + */ + @Override + public byte[] getImageData() + { + Assert.verify(origin == Origin.READ || origin == Origin.READ_WRITE); + + if (!initialized) + { + initialize(); + } + + return drawingGroup.getImageData(blipId); + } + + /** + * Accessor for the type + * + * @return the type + */ + @Override + public ShapeType getType() + { + return type; + } + + /** + * Sets the text object + * + * @param t the text object + */ + @Override + public void setTextObject(TextObjectRecord t) + { + txo = t; + } + + /** + * Sets the note object + * + * @param t the note record + */ + @Override + public void setNote(NoteRecord t) + { + note = t; + } + + /** + * Sets the text data + * + * @param t the text data + */ + @Override + public void setText(ContinueRecord t) + { + text = t; + } + + /** + * Sets the formatting + * + * @param t the formatting record + */ + @Override + public void setFormatting(ContinueRecord t) + { + formatting = t; + } + + /** + * Accessor for the image data + * + * @return the image data + */ + @Override + public byte[] getImageBytes() + { + Assert.verify(false); + return null; + } + + /** + * Accessor for the image file path. Normally this is the absolute path + * of a file on the directory system, but if this drawing was constructed + * using an byte[] then the blip id is returned + * + * @return the image file path, or the blip id + */ + @Override + public String getImageFilePath() + { + Assert.verify(false); + return null; + } + + /** + * Adds an mso record to this object + * + * @param d the mso record + */ + @Override + public void addMso(MsoDrawingRecord d) + { + mso = d; + drawingData.addRawData(mso.getData()); + } + + /** + * Writes out the additional comment records + * + * @param outputFile the output file + * @exception IOException + */ + @Override + public void writeAdditionalRecords(File outputFile) throws IOException + { + if (origin == Origin.READ) + { + outputFile.write(objRecord); + + if (mso != null) + { + outputFile.write(mso); + } + outputFile.write(txo); + outputFile.write(text); + if (formatting != null) + { + outputFile.write(formatting); + } + return; + } + + // Create the obj record + ObjRecord objrec = new ObjRecord(objectId, + ObjRecord.EXCELNOTE); + + outputFile.write(objrec); + + // Create the mso data record. Write the text box record again, + // although it is already included in the SpContainer + ClientTextBox textBox = new ClientTextBox(); + MsoDrawingRecord msod = new MsoDrawingRecord(textBox.getData()); + outputFile.write(msod); + + TextObjectRecord txorec = new TextObjectRecord(getText()); + outputFile.write(txorec); + + // Data for the first continue record + byte[] textData = new byte[commentText.length() * 2 + 1]; + textData[0] = 0x1; // unicode indicator + StringHelper.getUnicodeBytes(commentText, textData, 1); + //StringHelper.getBytes(commentText, textData, 1); + ContinueRecord textContinue = new ContinueRecord(textData); + outputFile.write(textContinue); + + // Data for the formatting runs + + byte[] frData = new byte[16]; + + // First txo run (the user) + IntegerHelper.getTwoBytes(0, frData, 0); // index to the first character + IntegerHelper.getTwoBytes(0, frData, 2); // index to the font(default) + // Mandatory last txo run + IntegerHelper.getTwoBytes(commentText.length(), frData, 8); + IntegerHelper.getTwoBytes(0, frData, 10); // index to the font(default) + + ContinueRecord frContinue = new ContinueRecord(frData); + outputFile.write(frContinue); + } + + /** + * Writes any records that need to be written after all the drawing group + * objects have been written + * Writes out all the note records + * + * @param outputFile the output file + * @exception IOException + */ + @Override + public void writeTailRecords(File outputFile) throws IOException + { + if (origin == Origin.READ) + { + outputFile.write(note); + return; + } + + // The note record + NoteRecord noteRecord = new NoteRecord(column, row, objectId); + outputFile.write(noteRecord); + } + + /** + * Accessor for the row + * + * @return the row + */ + @Override + public int getRow() + { + return note.getRow(); + } + + /** + * Accessor for the column + * + * @return the column + */ + @Override + public int getColumn() + { + return note.getColumn(); + } + + /** + * Accessor for the comment text + * + * @return the comment text + */ + @Override + public String getText() + { + if (commentText == null) + commentText = StringHelper.readShortBiff8String(text.getData()); + + return commentText; + } + + /** + * Hashing algorithm + * + * @return the hash code + */ + @Override + public boolean equals(Object obj) + { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + final CommentBiff8 other = (CommentBiff8) obj; + return Objects.equals(this.commentText, other.commentText); + } + + @Override + public int hashCode() { + return commentText.hashCode(); + } + + /** + * Called when the comment text is changed during the sheet copy process + * + * @param t the new text + */ + @Override + public void setCommentText(String t) + { + commentText = t; + + if (origin == Origin.READ) + { + origin = Origin.READ_WRITE; + } + } + + /** + * Accessor for the first drawing on the sheet. This is used when + * copying unmodified sheets to indicate that this drawing contains + * the first time Escher gubbins + * + * @return TRUE if this MSORecord is the first drawing on the sheet + */ + @Override + public boolean isFirst() + { + return msoDrawingRecord.isFirst(); + } + + /** + * Queries whether this object is a form object. Form objects have their + * drawings records spread over several records and require special handling + * + * @return TRUE if this is a form object, FALSE otherwise + */ + @Override + public boolean isFormObject() + { + return true; + } +} + + + diff --git a/src/jxl/biff/drawing/Dgg.java b/src/jxl/biff/drawing/Dgg.java index c34eeb0..713dba0 100644 --- a/src/jxl/biff/drawing/Dgg.java +++ b/src/jxl/biff/drawing/Dgg.java @@ -63,7 +63,7 @@ class Dgg extends EscherAtom /** * The clusters */ - private ArrayList clusters; + private final ArrayList clusters = new ArrayList<>(); /** * The cluster structure @@ -101,7 +101,6 @@ static final class Cluster public Dgg(EscherRecordData erd) { super(erd); - clusters = new ArrayList(); byte[] bytes = getBytes(); maxShapeId = IntegerHelper.getInt (bytes[0], bytes[1], bytes[2], bytes[3]); @@ -134,7 +133,6 @@ public Dgg(int numShapes, int numDrawings) super(EscherRecordType.DGG); shapesSaved = numShapes; drawingsSaved = numDrawings; - clusters = new ArrayList(); } /** diff --git a/src/jxl/biff/drawing/Drawing.java b/src/jxl/biff/drawing/Drawing.java index e42c32d..f9e7536 100644 --- a/src/jxl/biff/drawing/Drawing.java +++ b/src/jxl/biff/drawing/Drawing.java @@ -19,8 +19,8 @@ package jxl.biff.drawing; -import java.io.FileInputStream; -import java.io.IOException; +import java.io.*; +import java.nio.file.*; import jxl.common.Assert; import jxl.common.Logger; @@ -67,7 +67,7 @@ public class Drawing implements DrawingGroupObject, Image /** * The file containing the image */ - private java.io.File imageFile; + private Path imageFile; /** * The raw image data, used instead of an image file @@ -277,7 +277,7 @@ public Drawing(double x, double y, double w, double h, - java.io.File image) + Path image) { imageFile = image; initialized = true; @@ -341,20 +341,16 @@ private void initialize() Opt opt = (Opt) readSpContainer.getChildren()[1]; if (opt.getProperty(260) != null) - { blipId = opt.getProperty(260).value; - } if (opt.getProperty(261) != null) - { - imageFile = new java.io.File(opt.getProperty(261).stringValue); - } + imageFile = Paths.get(cutTailingZeros(opt.getProperty(261).stringValue)); else { if (type == ShapeType.PICTURE_FRAME) { logger.warn("no filename property for drawing"); - imageFile = new java.io.File(Integer.toString(blipId)); + imageFile = Paths.get(Integer.toString(blipId)); } } @@ -389,12 +385,19 @@ private void initialize() initialized = true; } + private String cutTailingZeros(String s) { + while ((! s.isEmpty()) + && s.codePointAt(s.length() - 1) == '\0') + s = s.substring(0, s.length() - 1); + return s; + } + /** * Accessor for the image file * * @return the image file */ - public java.io.File getImageFile() + public Path getImageFile() { return imageFile; } @@ -414,7 +417,7 @@ public String getImageFilePath() return blipId != 0 ? Integer.toString(blipId) : "__new__image__"; } - return imageFile.getPath(); + return imageFile.toString(); } /** @@ -517,7 +520,7 @@ public EscherContainer getSpContainer() if (type == ShapeType.PICTURE_FRAME) { - String filePath = imageFile != null ? imageFile.getPath() : ""; + String filePath = imageFile != null ? imageFile.toString() : ""; opt.addProperty(261, true, true, filePath.length() * 2, filePath); opt.addProperty(447, false, false, 65536); opt.addProperty(959, false, false, 524288); @@ -774,10 +777,10 @@ public byte[] getImageBytes() throws IOException return imageData; } - byte[] data = new byte[(int) imageFile.length()]; - FileInputStream fis = new FileInputStream(imageFile); - fis.read(data, 0, data.length); - fis.close(); + byte[] data = new byte[(int) Files.size(imageFile)]; + try (InputStream fis = Files.newInputStream(imageFile)) { + fis.read(data, 0, data.length); + } return data; } diff --git a/src/jxl/biff/drawing/Drawing2.java b/src/jxl/biff/drawing/Drawing2.java index 90e5086..94d3d8d 100644 --- a/src/jxl/biff/drawing/Drawing2.java +++ b/src/jxl/biff/drawing/Drawing2.java @@ -19,8 +19,8 @@ package jxl.biff.drawing; -import java.io.FileInputStream; -import java.io.IOException; +import java.io.*; +import java.nio.file.*; import jxl.common.Assert; import jxl.common.Logger; @@ -58,7 +58,7 @@ public class Drawing2 implements DrawingGroupObject /** * The file containing the image */ - private java.io.File imageFile; + private Path imageFile; /** * The raw image data, used instead of an image file @@ -193,7 +193,7 @@ public Drawing2(double x, double y, double w, double h, - java.io.File image) + Path image) { imageFile = image; initialized = true; @@ -574,11 +574,7 @@ public byte[] getImageBytes() throws IOException return imageData; } - byte[] data = new byte[(int) imageFile.length()]; - FileInputStream fis = new FileInputStream(imageFile); - fis.read(data, 0, data.length); - fis.close(); - return data; + return Files.readAllBytes(imageFile); } /** diff --git a/src/jxl/biff/drawing/DrawingData.java b/src/jxl/biff/drawing/DrawingData.java index 5fba437..05e20a7 100644 --- a/src/jxl/biff/drawing/DrawingData.java +++ b/src/jxl/biff/drawing/DrawingData.java @@ -76,7 +76,6 @@ private void initialize() EscherContainer dgContainer = new EscherContainer(er); EscherRecord[] children = dgContainer.getChildren(); - children = dgContainer.getChildren(); // Dg dg = (Dg) children[0]; EscherContainer spgrContainer = null; @@ -112,10 +111,10 @@ private void initialize() else { // Go through the hierarchy and dig out all the Sp containers - ArrayList sps = new ArrayList(); + ArrayList sps = new ArrayList<>(); getSpContainers(spgrContainer, sps); spContainers = new EscherRecord[sps.size()]; - spContainers = (EscherRecord[]) sps.toArray(spContainers); + spContainers = sps.toArray(spContainers); } initialized = true; @@ -127,25 +126,17 @@ private void initialize() * @param spgrContainer the spgr container * @param sps the list of sp records */ - private void getSpContainers(EscherContainer spgrContainer, ArrayList sps) + private void getSpContainers(EscherContainer spgrContainer, ArrayList sps) { EscherRecord[] spgrChildren = spgrContainer.getChildren(); - for (int i = 0; i < spgrChildren.length; i++) - { - if (spgrChildren[i].getType() == EscherRecordType.SP_CONTAINER) - { - sps.add(spgrChildren[i]); - } - else if (spgrChildren[i].getType() == EscherRecordType.SPGR_CONTAINER) - { - getSpContainers((EscherContainer) spgrChildren[i], sps); - } + for (EscherRecord children : spgrChildren) + if (children.getType() == EscherRecordType.SP_CONTAINER) + sps.add(children); + else if (children.getType() == EscherRecordType.SPGR_CONTAINER) + getSpContainers((EscherContainer) children, sps); else - { logger.warn("Spgr Containers contains a record other than Sp/Spgr " + - "containers"); - } - } + "containers"); } /** diff --git a/src/jxl/biff/drawing/DrawingGroup.java b/src/jxl/biff/drawing/DrawingGroup.java index 723f051..8692e67 100644 --- a/src/jxl/biff/drawing/DrawingGroup.java +++ b/src/jxl/biff/drawing/DrawingGroup.java @@ -22,7 +22,6 @@ import java.io.IOException; import java.util.ArrayList; import java.util.HashMap; -import java.util.Iterator; import jxl.common.Assert; import jxl.common.Logger; @@ -64,7 +63,7 @@ public class DrawingGroup implements EscherStream /** * The list of user added drawings */ - private ArrayList drawings; + private final ArrayList drawings; /** * The number of blips @@ -96,7 +95,7 @@ public class DrawingGroup implements EscherStream * A hash map of images keyed on the file path, containing the * reference count */ - private HashMap imageFiles; + private final HashMap imageFiles; /** * A count of the next available object id @@ -116,9 +115,9 @@ public class DrawingGroup implements EscherStream public DrawingGroup(Origin o) { origin = o; - initialized = o == Origin.WRITE ? true : false; - drawings = new ArrayList(); - imageFiles = new HashMap(); + initialized = o == Origin.WRITE; + drawings = new ArrayList<>(); + imageFiles = new HashMap<>(); drawingsOmitted = false; maxObjectId = 1; maxShapeId = 1024; @@ -132,6 +131,7 @@ public DrawingGroup(Origin o) * * @param dg the drawing group to copy */ + @SuppressWarnings("unchecked") public DrawingGroup(DrawingGroup dg) { drawingData = dg.drawingData; @@ -146,13 +146,13 @@ public DrawingGroup(DrawingGroup dg) drawingGroupId = dg.drawingGroupId; drawingsOmitted = dg.drawingsOmitted; origin = dg.origin; - imageFiles = (HashMap) dg.imageFiles.clone(); + imageFiles = (HashMap) dg.imageFiles.clone(); maxObjectId = dg.maxObjectId; maxShapeId = dg.maxShapeId; // Create this as empty, because all drawings will get added later // as part of the sheet copy process - drawings = new ArrayList(); + drawings = new ArrayList<>(); } /** @@ -264,8 +264,7 @@ public void add(DrawingGroupObject d) Drawing drawing = (Drawing) d; // See if this is referenced elsewhere - Drawing refImage = - (Drawing) imageFiles.get(d.getImageFilePath()); + Drawing refImage = imageFiles.get(d.getImageFilePath()); if (refImage == null) { @@ -326,17 +325,13 @@ public void remove(DrawingGroupObject d) getBStoreContainer().remove(bse); // Adjust blipId on the other blips - for (Iterator i = drawings.iterator(); i.hasNext();) - { - DrawingGroupObject drawing = (DrawingGroupObject) i.next(); - + for (DrawingGroupObject drawing : drawings) if (drawing.getBlipId() > d.getBlipId()) { drawing.setObjectId(drawing.getObjectId(), - drawing.getBlipId() - 1, - drawing.getShapeId()); + drawing.getBlipId() - 1, + drawing.getShapeId()); } - } numBlips--; } @@ -418,18 +413,14 @@ public void write(File outputFile) throws IOException BStoreContainer bstoreCont = new BStoreContainer(); // Create a blip entry for each drawing - for (Iterator i = drawings.iterator(); i.hasNext();) - { - Object o = i.next(); - if (o instanceof Drawing) + for (DrawingGroupObject o : drawings) + if (o instanceof Drawing d) { - Drawing d = (Drawing) o; BlipStoreEntry bse = new BlipStoreEntry(d); bstoreCont.add(bse); drawingsAdded++; } - } if (drawingsAdded > 0) { bstoreCont.setNumBlips(drawingsAdded); @@ -465,27 +456,22 @@ else if (origin == Origin.READ_WRITE) if (readBStoreContainer != null) { EscherRecord[] children = readBStoreContainer.getChildren(); - for (int i = 0; i < children.length; i++) - { - BlipStoreEntry bse = (BlipStoreEntry) children[i]; + for (EscherRecord children1 : children) { + BlipStoreEntry bse = (BlipStoreEntry) children1; bstoreCont.add(bse); } } // Create a blip entry for each drawing that has been added - for (Iterator i = drawings.iterator(); i.hasNext();) - { - DrawingGroupObject dgo = (DrawingGroupObject) i.next(); - if (dgo instanceof Drawing) + for (DrawingGroupObject dgo : drawings) + if (dgo instanceof Drawing d) { - Drawing d = (Drawing) dgo; if (d.getOrigin() == Origin.WRITE) { BlipStoreEntry bse = new BlipStoreEntry(d); bstoreCont.add(bse); } } - } dggContainer.add(bstoreCont); diff --git a/src/jxl/biff/drawing/EscherContainer.java b/src/jxl/biff/drawing/EscherContainer.java index 262810e..d3bc123 100644 --- a/src/jxl/biff/drawing/EscherContainer.java +++ b/src/jxl/biff/drawing/EscherContainer.java @@ -22,19 +22,12 @@ import java.util.ArrayList; import java.util.Iterator; -import jxl.common.Logger; - /** * An escher container. This record may contain other escher containers or * atoms */ class EscherContainer extends EscherRecord { - /** - * The logger - */ - private static Logger logger = Logger.getLogger(EscherContainer.class); - /** * Initialized flag */ @@ -44,7 +37,7 @@ class EscherContainer extends EscherRecord /** * The children of this container */ - private ArrayList children; + private final ArrayList children = new ArrayList<>(); /** * Constructor @@ -55,7 +48,6 @@ public EscherContainer(EscherRecordData erd) { super(erd); initialized = false; - children = new ArrayList(); } /** @@ -67,7 +59,6 @@ protected EscherContainer(EscherRecordType type) { super(type); setContainer(true); - children = new ArrayList(); } /** @@ -115,7 +106,7 @@ private void initialize() int curpos = getPos() + HEADER_LENGTH; int endpos = Math.min(getPos() + getLength(), getStreamLength()); - EscherRecord newRecord = null; + EscherRecord newRecord; while (curpos < endpos) { @@ -191,6 +182,7 @@ else if (type == EscherRecordType.CLIENT_TEXT_BOX) * * @return the binary data */ + @Override byte[] getData() { if (!initialized) @@ -199,9 +191,7 @@ byte[] getData() } byte[] data = new byte[0]; - for (Iterator i = children.iterator(); i.hasNext();) - { - EscherRecord er = (EscherRecord) i.next(); + for (EscherRecord er : children) { byte[] childData = er.getData(); if (childData != null) diff --git a/src/jxl/biff/drawing/EscherRecord.java b/src/jxl/biff/drawing/EscherRecord.java index 7a3c6ef..2147e96 100644 --- a/src/jxl/biff/drawing/EscherRecord.java +++ b/src/jxl/biff/drawing/EscherRecord.java @@ -19,8 +19,6 @@ package jxl.biff.drawing; -import jxl.common.Logger; - /** * The base class for all escher records. This class contains * the jxl.common.header data and is basically a wrapper for the EscherRecordData @@ -28,15 +26,10 @@ */ abstract class EscherRecord { - /** - * The logger - */ - private static Logger logger = Logger.getLogger(EscherRecord.class); - /** * The escher data */ - private EscherRecordData data; + private final EscherRecordData data; //protected EscherRecordData data; /** diff --git a/src/jxl/biff/drawing/EscherRecordData.java b/src/jxl/biff/drawing/EscherRecordData.java index 2b217ca..37c99c2 100644 --- a/src/jxl/biff/drawing/EscherRecordData.java +++ b/src/jxl/biff/drawing/EscherRecordData.java @@ -19,8 +19,6 @@ package jxl.biff.drawing; -import jxl.common.Logger; - import jxl.biff.IntegerHelper; @@ -28,12 +26,7 @@ * A single record from an Escher stream. Basically this a container for * the header data for each Escher record */ -final class EscherRecordData -{ - /** - * The logger - */ - private static Logger logger = Logger.getLogger(EscherRecordData.class); +final class EscherRecordData { /** * The byte position of this record in the escher stream @@ -53,7 +46,7 @@ final class EscherRecordData /** * The record id */ - private int recordId; + private final int recordId; /** * The length of the record, excluding the 8 byte header @@ -111,14 +104,7 @@ public EscherRecordData(EscherStream dg, int p) length = IntegerHelper.getInt(data[pos + 4], data[pos + 5], data[pos + 6], data[pos + 7]); - if (version == 0x0f) - { - container = true; - } - else - { - container = false; - } + container = version == 0x0f; } /** diff --git a/src/jxl/biff/drawing/Opt.java b/src/jxl/biff/drawing/Opt.java index 00568f1..78ddec7 100644 --- a/src/jxl/biff/drawing/Opt.java +++ b/src/jxl/biff/drawing/Opt.java @@ -20,22 +20,13 @@ package jxl.biff.drawing; import java.util.ArrayList; -import java.util.Iterator; - -import jxl.common.Logger; - -import jxl.biff.IntegerHelper; -import jxl.biff.StringHelper; +import jxl.biff.*; /** * An options record in the escher stream */ class Opt extends EscherAtom { - /** - * The logger - */ - private static Logger logger = Logger.getLogger(Opt.class); /** * The binary data @@ -50,7 +41,7 @@ class Opt extends EscherAtom /** * The list of properties */ - private ArrayList properties; + private final ArrayList properties = new ArrayList<>(); /** * Properties enumeration inner class @@ -71,7 +62,7 @@ final static class Property * @param co complex flag * @param v the value */ - public Property(int i, boolean bl, boolean co, int v) + Property(int i, boolean bl, boolean co, int v) { id = i; blipId = bl; @@ -103,7 +94,7 @@ public Property(int i, boolean bl, boolean co, int v, String s) * * @param erd the escher record data */ - public Opt(EscherRecordData erd) + Opt(EscherRecordData erd) { super(erd); numProperties = getInstance(); @@ -115,7 +106,6 @@ public Opt(EscherRecordData erd) */ private void readProperties() { - properties = new ArrayList(); int pos = 0; byte[] bytes = getBytes(); @@ -133,25 +123,21 @@ private void readProperties() properties.add(p); } - for (Iterator i = properties.iterator(); i.hasNext();) - { - Property p = (Property) i.next(); + for (Property p : properties) if (p.complex) { - p.stringValue = StringHelper.getUnicodeString(bytes, p.value / 2, - pos); + p.stringValue = StringHelper.getUnicodeString(bytes, + pos, p.value / 2); pos += p.value; } - } } /** * Constructor */ - public Opt() + Opt() { super(EscherRecordType.OPT); - properties = new ArrayList(); setVersion(3); } @@ -160,6 +146,7 @@ public Opt() * * @return the binary data */ + @Override byte[] getData() { numProperties = properties.size(); @@ -169,9 +156,7 @@ byte[] getData() int pos = 0; // Add in the root data - for (Iterator i = properties.iterator(); i.hasNext();) - { - Property p = (Property) i.next(); + for (Property p : properties) { int val = p.id & 0x3fff; if (p.blipId) @@ -190,19 +175,15 @@ byte[] getData() } // Add in any complex data - for (Iterator i = properties.iterator(); i.hasNext();) - { - Property p = (Property) i.next(); - + for (Property p : properties) if (p.complex && p.stringValue != null) { byte[] newData = - new byte[data.length + p.stringValue.length() * 2]; + new byte[data.length + p.stringValue.length() * 2]; System.arraycopy(data, 0, newData, 0, data.length); StringHelper.getUnicodeBytes(p.stringValue, newData, data.length); data = newData; } - } return setHeaderData(data); } @@ -217,8 +198,7 @@ byte[] getData() */ void addProperty(int id, boolean blip, boolean complex, int val) { - Property p = new Property(id, blip, complex, val); - properties.add(p); + properties.add(new Property(id, blip, complex, val)); } /** @@ -232,8 +212,7 @@ void addProperty(int id, boolean blip, boolean complex, int val) */ void addProperty(int id, boolean blip, boolean complex, int val, String s) { - Property p = new Property(id, blip, complex, val, s); - properties.add(p); + properties.add(new Property(id, blip, complex, val, s)); } /** @@ -244,16 +223,10 @@ void addProperty(int id, boolean blip, boolean complex, int val, String s) */ Property getProperty(int id) { - boolean found = false; - Property p = null; - for (Iterator i = properties.iterator(); i.hasNext() && !found;) - { - p = (Property) i.next(); + for (Property p : properties) if (p.id == id) - { - found = true; - } - } - return found ? p : null; + return p; + + return null; } } diff --git a/src/jxl/biff/drawing/PNGReader.java b/src/jxl/biff/drawing/PNGReader.java index c71e1d8..49b45f7 100644 --- a/src/jxl/biff/drawing/PNGReader.java +++ b/src/jxl/biff/drawing/PNGReader.java @@ -19,8 +19,7 @@ package jxl.biff.drawing; -import java.io.File; -import java.io.FileInputStream; +import java.nio.file.*; import java.util.Arrays; public class PNGReader @@ -138,15 +137,9 @@ public static void main(String args[]) { try { - File f = new File(args[0]); - int size = (int) f.length(); + Path f = Paths.get(args[0]); - byte[] data = new byte[size]; - - FileInputStream fis = new FileInputStream(f); - fis.read(data); - fis.close(); - PNGReader reader = new PNGReader(data); + PNGReader reader = new PNGReader(Files.readAllBytes(f)); reader.read(); } catch (Throwable t) diff --git a/src/jxl/biff/drawing/SheetDrawingWriter.java b/src/jxl/biff/drawing/SheetDrawingWriter.java index 1198a93..55abfb2 100644 --- a/src/jxl/biff/drawing/SheetDrawingWriter.java +++ b/src/jxl/biff/drawing/SheetDrawingWriter.java @@ -23,7 +23,6 @@ import java.util.ArrayList; import java.util.Iterator; -import jxl.common.Logger; import jxl.WorkbookSettings; import jxl.biff.IntegerHelper; @@ -35,15 +34,11 @@ */ public class SheetDrawingWriter { - /** - * The logger - */ - private static Logger logger = Logger.getLogger(SheetDrawingWriter.class); /** * The drawings on the sheet */ - private ArrayList drawings; + private ArrayList drawings; /** * Flag indicating whether the drawings on the sheet were modified @@ -76,7 +71,7 @@ public SheetDrawingWriter(WorkbookSettings ws) * @param dr the list of drawings * @param mod flag indicating whether the drawings have been tampered with */ - public void setDrawings(ArrayList dr, boolean mod) + public void setDrawings(ArrayList dr, boolean mod) { drawings = dr; drawingsModified = mod; @@ -92,7 +87,7 @@ public void setDrawings(ArrayList dr, boolean mod) public void write(File outputFile) throws IOException { // If there are no drawings or charts on this sheet then exit - if (drawings.size() == 0 && charts.length == 0) + if (drawings.isEmpty() && charts.length == 0) { return; } @@ -101,20 +96,18 @@ public void write(File outputFile) throws IOException boolean modified = drawingsModified; int numImages = drawings.size(); - for (Iterator i = drawings.iterator(); i.hasNext() && !modified;) + for (Iterator i = drawings.iterator(); i.hasNext() && !modified;) { - DrawingGroupObject d = (DrawingGroupObject) i.next(); + DrawingGroupObject d = i.next(); if (d.getOrigin() != Origin.READ) - { modified = true; - } } // If the drawing order has been muddled at all, then we'll need // to regenerate the Escher drawing data if (numImages > 0 && !modified) { - DrawingGroupObject d2 = (DrawingGroupObject) drawings.get(0); + DrawingGroupObject d2 = drawings.get(0); if (!d2.isFirst()) { modified = true; @@ -146,7 +139,7 @@ public void write(File outputFile) throws IOException // and store in an array for (int i = 0; i < numImages; i++) { - DrawingGroupObject drawing = (DrawingGroupObject) drawings.get(i); + DrawingGroupObject drawing = drawings.get(i); EscherContainer spc = drawing.getSpContainer(); @@ -224,7 +217,7 @@ public void write(File outputFile) throws IOException // test hack for form objects, to remove the ClientTextBox record // from the end of the SpContainer if (numImages > 0 && - ((DrawingGroupObject) drawings.get(0)).isFormObject()) + drawings.get(0).isFormObject()) { byte[] msodata2 = new byte[firstMsoData.length - 8]; System.arraycopy(firstMsoData, 0, msodata2, 0, msodata2.length); @@ -236,7 +229,7 @@ public void write(File outputFile) throws IOException if (numImages > 0) { - DrawingGroupObject firstDrawing = (DrawingGroupObject) drawings.get(0); + DrawingGroupObject firstDrawing = drawings.get(0); firstDrawing.writeAdditionalRecords(outputFile); } else @@ -255,8 +248,7 @@ public void write(File outputFile) throws IOException // test hack for form objects, to remove the ClientTextBox record // from the end of the SpContainer - if (i < numImages && - ((DrawingGroupObject) drawings.get(i)).isFormObject()) + if (i < numImages && drawings.get(i).isFormObject()) { byte[] bytes2 = new byte[bytes.length - 8]; System.arraycopy(bytes, 0, bytes2, 0, bytes2.length); @@ -269,7 +261,7 @@ public void write(File outputFile) throws IOException if (i < numImages) { // Write anything else the object needs - DrawingGroupObject d = (DrawingGroupObject) drawings.get(i); + DrawingGroupObject d = drawings.get(i); d.writeAdditionalRecords(outputFile); } else @@ -282,11 +274,8 @@ public void write(File outputFile) throws IOException } // Write any tail records that need to be written - for (Iterator i = drawings.iterator(); i.hasNext();) - { - DrawingGroupObject dgo2 = (DrawingGroupObject) i.next(); + for (DrawingGroupObject dgo2 : drawings) dgo2.writeTailRecords(outputFile); - } } /** @@ -297,45 +286,37 @@ public void write(File outputFile) throws IOException */ private void writeUnmodified(File outputFile) throws IOException { - if (charts.length == 0 && drawings.size() == 0) + if (charts.length == 0 && drawings.isEmpty()) { // No drawings or charts return; } - else if (charts.length == 0 && drawings.size() != 0) + else if (charts.length == 0 && !drawings.isEmpty()) { // If there are no charts, then write out the drawings and return - for (Iterator i = drawings.iterator(); i.hasNext();) - { - DrawingGroupObject d = (DrawingGroupObject) i.next(); + for (DrawingGroupObject d : drawings) { outputFile.write(d.getMsoDrawingRecord()); d.writeAdditionalRecords(outputFile); } - for (Iterator i = drawings.iterator(); i.hasNext();) - { - DrawingGroupObject d = (DrawingGroupObject) i.next(); + for (DrawingGroupObject d : drawings) d.writeTailRecords(outputFile); - } + return; } - else if (drawings.size() == 0 && charts.length != 0) + else if (drawings.isEmpty() && charts.length != 0) { // If there are no drawings, then write out the charts and return - Chart curChart = null; - for (int i = 0; i < charts.length; i++) - { - curChart = charts[i]; + for (Chart chart : charts) { + Chart curChart = chart; if (curChart.getMsoDrawingRecord() != null) { outputFile.write(curChart.getMsoDrawingRecord()); } - if (curChart.getObjRecord() != null) { outputFile.write(curChart.getObjRecord()); } - outputFile.write(curChart); } @@ -354,7 +335,7 @@ else if (drawings.size() == 0 && charts.length != 0) for (int i = 0; i < numDrawings; i++) { - DrawingGroupObject d = (DrawingGroupObject) drawings.get(i); + DrawingGroupObject d = drawings.get(i); spContainers[i] = d.getSpContainer(); if (i > 0) @@ -423,7 +404,7 @@ else if (drawings.size() == 0 && charts.length != 0) MsoDrawingRecord msoDrawingRecord = new MsoDrawingRecord(firstMsoData); outputFile.write(msoDrawingRecord); - DrawingGroupObject dgo = (DrawingGroupObject) drawings.get(0); + DrawingGroupObject dgo = drawings.get(0); dgo.writeAdditionalRecords(outputFile); // Now do all the others @@ -446,7 +427,7 @@ else if (drawings.size() == 0 && charts.length != 0) if (i < numDrawings) { - dgo = (DrawingGroupObject) drawings.get(i); + dgo = drawings.get(i); dgo.writeAdditionalRecords(outputFile); } else @@ -459,11 +440,8 @@ else if (drawings.size() == 0 && charts.length != 0) } // Write any tail records that need to be written - for (Iterator i = drawings.iterator(); i.hasNext();) - { - DrawingGroupObject dgo2 = (DrawingGroupObject) i.next(); + for (DrawingGroupObject dgo2 : drawings) dgo2.writeTailRecords(outputFile); - } } /** diff --git a/src/jxl/biff/formula/Area.java b/src/jxl/biff/formula/Area.java index 039834f..1e4feea 100644 --- a/src/jxl/biff/formula/Area.java +++ b/src/jxl/biff/formula/Area.java @@ -188,8 +188,8 @@ public void getString(StringBuffer buf) byte[] getBytes() { byte[] data = new byte[9]; - data[0] = !useAlternateCode() ? Token.AREA.getCode() : - Token.AREA.getCode2(); + data[0] = !useAlternateCode() ? Token.AREA.getReferenceCode() : + Token.AREA.getValueCode(); IntegerHelper.getTwoBytes(rowFirst, data, 1); IntegerHelper.getTwoBytes(rowLast, data, 3); diff --git a/src/jxl/biff/formula/Area3d.java b/src/jxl/biff/formula/Area3d.java index a8b224e..69a09cb 100644 --- a/src/jxl/biff/formula/Area3d.java +++ b/src/jxl/biff/formula/Area3d.java @@ -228,7 +228,7 @@ public void getString(StringBuffer buf) byte[] getBytes() { byte[] data = new byte[11]; - data[0] = Token.AREA3D.getCode(); + data[0] = Token.AREA3D.getReferenceCode(); IntegerHelper.getTwoBytes(sheet, data, 1); diff --git a/src/jxl/biff/formula/Attribute.java b/src/jxl/biff/formula/Attribute.java index d28df6a..266c67d 100644 --- a/src/jxl/biff/formula/Attribute.java +++ b/src/jxl/biff/formula/Attribute.java @@ -50,7 +50,7 @@ class Attribute extends Operator implements ParsedThing /** * The workbook settings */ - private WorkbookSettings settings; + private final WorkbookSettings settings; private static final int SUM_MASK = 0x10; private static final int IF_MASK = 0x02; @@ -183,18 +183,13 @@ public boolean isChoose() * * @param s the token stack */ - public void getOperands(Stack s) + @Override + public void getOperands(Stack s) { if ((options & SUM_MASK) != 0) - { - ParseItem o1 = (ParseItem) s.pop(); - add(o1); - } + add(s.pop()); else if ((options & IF_MASK) != 0) - { - ParseItem o1 = (ParseItem) s.pop(); - add(o1); - } + add(s.pop()); } /** @@ -260,7 +255,7 @@ byte[] getBytes() // Add on the operator byte byte[] newdata = new byte[data.length + 4]; System.arraycopy(data, 0, newdata, 0, data.length); - newdata[data.length] = Token.ATTRIBUTE.getCode(); + newdata[data.length] = Token.ATTRIBUTE.getReferenceCode(); newdata[data.length + 1] = SUM_MASK; data = newdata; } @@ -294,7 +289,7 @@ private byte[] getIf() byte[] newdata = new byte[data.length + 4]; System.arraycopy(data, 0, newdata, 0, data.length); data = newdata; - data[pos] = Token.ATTRIBUTE.getCode(); + data[pos] = Token.ATTRIBUTE.getReferenceCode(); data[pos + 1] = 0x2; falseOffsetPos = pos + 2; @@ -310,7 +305,7 @@ private byte[] getIf() newdata = new byte[data.length + 4]; System.arraycopy(data, 0, newdata, 0, data.length); data = newdata; - data[pos] = Token.ATTRIBUTE.getCode(); + data[pos] = Token.ATTRIBUTE.getReferenceCode(); data[pos + 1] = 0x8; gotoEndPos = pos + 2; @@ -333,7 +328,7 @@ private byte[] getIf() newdata = new byte[data.length + 4]; System.arraycopy(data, 0, newdata, 0, data.length); data = newdata; - data[pos] = Token.ATTRIBUTE.getCode(); + data[pos] = Token.ATTRIBUTE.getReferenceCode(); data[pos + 1] = 0x8; data[pos + 2] = 0x3; } @@ -343,7 +338,7 @@ private byte[] getIf() newdata = new byte[data.length + 4]; System.arraycopy(data, 0, newdata, 0, data.length); data = newdata; - data[pos] = Token.FUNCTIONVARARG.getCode(); + data[pos] = Token.FUNCTIONVARARG.getReferenceCode(); data[pos + 1] = (byte) numArgs; data[pos + 2] = 1; data[pos + 3] = 0; // indicates the end of the expression @@ -395,10 +390,8 @@ public void adjustRelativeCellReferences(int colAdjust, int rowAdjust) operands = getOperands(); } - for (int i = 0; i < operands.length; i++) - { - operands[i].adjustRelativeCellReferences(colAdjust, rowAdjust); - } + for (ParseItem operand : operands) + operand.adjustRelativeCellReferences(colAdjust, rowAdjust); } /** @@ -424,10 +417,8 @@ void columnInserted(int sheetIndex, int col, boolean currentSheet) operands = getOperands(); } - for (int i = 0; i < operands.length; i++) - { - operands[i].columnInserted(sheetIndex, col, currentSheet); - } + for (ParseItem operand : operands) + operand.columnInserted(sheetIndex, col, currentSheet); } /** @@ -453,10 +444,8 @@ void columnRemoved(int sheetIndex, int col, boolean currentSheet) operands = getOperands(); } - for (int i = 0; i < operands.length; i++) - { - operands[i].columnRemoved(sheetIndex, col, currentSheet); - } + for (ParseItem operand : operands) + operand.columnRemoved(sheetIndex, col, currentSheet); } /** @@ -482,10 +471,8 @@ void rowInserted(int sheetIndex, int row, boolean currentSheet) operands = getOperands(); } - for (int i = 0; i < operands.length; i++) - { - operands[i].rowInserted(sheetIndex, row, currentSheet); - } + for (ParseItem operand : operands) + operand.rowInserted(sheetIndex, row, currentSheet); } /** @@ -511,10 +498,8 @@ void rowRemoved(int sheetIndex, int row, boolean currentSheet) operands = getOperands(); } - for (int i = 0; i < operands.length; i++) - { - operands[i].rowRemoved(sheetIndex, row, currentSheet); - } + for (ParseItem operand : operands) + operand.rowRemoved(sheetIndex, row, currentSheet); } /** @@ -535,10 +520,8 @@ void handleImportedCellReferences() operands = getOperands(); } - for (int i = 0; i < operands.length; i++) - { - operands[i].handleImportedCellReferences(); - } + for (ParseItem operand : operands) + operand.handleImportedCellReferences(); } } diff --git a/src/jxl/biff/formula/BinaryOperator.java b/src/jxl/biff/formula/BinaryOperator.java index 92796f7..f5dee58 100644 --- a/src/jxl/biff/formula/BinaryOperator.java +++ b/src/jxl/biff/formula/BinaryOperator.java @@ -28,9 +28,6 @@ */ abstract class BinaryOperator extends Operator implements ParsedThing { - // The logger - private static final Logger logger = Logger.getLogger(BinaryOperator.class); - /** * Constructor */ @@ -55,13 +52,10 @@ public int read(byte[] data, int pos) * * @param s the token stack */ - public void getOperands(Stack s) + public void getOperands(Stack s) { - ParseItem o1 = (ParseItem) s.pop(); - ParseItem o2 = (ParseItem) s.pop(); - - add(o1); - add(o2); + add(s.pop()); + add(s.pop()); } /** @@ -185,7 +179,7 @@ byte[] getBytes() // Add on the operator byte byte[] newdata = new byte[data.length + 1]; System.arraycopy(data, 0, newdata, 0, data.length); - newdata[data.length] = getToken().getCode(); + newdata[data.length] = getToken().getReferenceCode(); return newdata; } diff --git a/src/jxl/biff/formula/BooleanValue.java b/src/jxl/biff/formula/BooleanValue.java index 08970d5..5e16b05 100644 --- a/src/jxl/biff/formula/BooleanValue.java +++ b/src/jxl/biff/formula/BooleanValue.java @@ -69,7 +69,7 @@ public int read(byte[] data, int pos) byte[] getBytes() { byte[] data = new byte[2]; - data[0] = Token.BOOL.getCode(); + data[0] = Token.BOOL.getReferenceCode(); data[1] = (byte) (value == true ? 1 : 0); return data; @@ -83,7 +83,7 @@ byte[] getBytes() */ public void getString(StringBuffer buf) { - buf.append((new Boolean(value)).toString()); + buf.append((Boolean.toString(value))); } /** diff --git a/src/jxl/biff/formula/BuiltInFunction.java b/src/jxl/biff/formula/BuiltInFunction.java index b3243ef..dd640c4 100644 --- a/src/jxl/biff/formula/BuiltInFunction.java +++ b/src/jxl/biff/formula/BuiltInFunction.java @@ -32,10 +32,6 @@ */ class BuiltInFunction extends Operator implements ParsedThing { - /** - * The logger - */ - private static Logger logger = Logger.getLogger(BuiltInFunction.class); /** * The function @@ -45,7 +41,7 @@ class BuiltInFunction extends Operator implements ParsedThing /** * The workbook settings */ - private WorkbookSettings settings; + private final WorkbookSettings settings; /** * Constructor @@ -88,22 +84,16 @@ public int read(byte[] data, int pos) * * @param s the token stack */ - public void getOperands(Stack s) + public void getOperands(Stack s) { // parameters are in the correct order, god damn them ParseItem[] items = new ParseItem[function.getNumArgs()]; // modified in 2.4.3 for (int i = function.getNumArgs() - 1; i >= 0; i--) - { - ParseItem pi = (ParseItem) s.pop(); - - items[i] = pi; - } + items[i] = s.pop(); for (int i = 0; i < function.getNumArgs(); i++) - { add(items[i]); - } } /** @@ -144,12 +134,8 @@ public void getString(StringBuffer buf) */ public void adjustRelativeCellReferences(int colAdjust, int rowAdjust) { - ParseItem[] operands = getOperands(); - - for (int i = 0; i < operands.length; i++) - { - operands[i].adjustRelativeCellReferences(colAdjust, rowAdjust); - } + for (ParseItem operand : getOperands()) + operand.adjustRelativeCellReferences(colAdjust, rowAdjust); } /** @@ -164,11 +150,8 @@ public void adjustRelativeCellReferences(int colAdjust, int rowAdjust) */ void columnInserted(int sheetIndex, int col, boolean currentSheet) { - ParseItem[] operands = getOperands(); - for (int i = 0; i < operands.length; i++) - { - operands[i].columnInserted(sheetIndex, col, currentSheet); - } + for (ParseItem operand : getOperands()) + operand.columnInserted(sheetIndex, col, currentSheet); } /** @@ -183,11 +166,8 @@ void columnInserted(int sheetIndex, int col, boolean currentSheet) */ void columnRemoved(int sheetIndex, int col, boolean currentSheet) { - ParseItem[] operands = getOperands(); - for (int i = 0; i < operands.length; i++) - { - operands[i].columnRemoved(sheetIndex, col, currentSheet); - } + for (ParseItem operand : getOperands()) + operand.columnRemoved(sheetIndex, col, currentSheet); } @@ -203,11 +183,8 @@ void columnRemoved(int sheetIndex, int col, boolean currentSheet) */ void rowInserted(int sheetIndex, int row, boolean currentSheet) { - ParseItem[] operands = getOperands(); - for (int i = 0; i < operands.length; i++) - { - operands[i].rowInserted(sheetIndex, row, currentSheet); - } + for (ParseItem operand : getOperands()) + operand.rowInserted(sheetIndex, row, currentSheet); } /** @@ -222,11 +199,8 @@ void rowInserted(int sheetIndex, int row, boolean currentSheet) */ void rowRemoved(int sheetIndex, int row, boolean currentSheet) { - ParseItem[] operands = getOperands(); - for (int i = 0; i < operands.length; i++) - { - operands[i].rowRemoved(sheetIndex, row, currentSheet); - } + for (ParseItem operand : getOperands()) + operand.rowRemoved(sheetIndex, row, currentSheet); } /** @@ -236,11 +210,8 @@ void rowRemoved(int sheetIndex, int row, boolean currentSheet) */ void handleImportedCellReferences() { - ParseItem[] operands = getOperands(); - for (int i = 0 ; i < operands.length ; i++) - { - operands[i].handleImportedCellReferences(); - } + for (ParseItem operand : getOperands()) + operand.handleImportedCellReferences(); } /** @@ -254,10 +225,8 @@ byte[] getBytes() ParseItem[] operands = getOperands(); byte[] data = new byte[0]; - for (int i = 0; i < operands.length; i++) - { - byte[] opdata = operands[i].getBytes(); - + for (ParseItem operand : operands) { + byte[] opdata = operand.getBytes(); // Grow the array byte[] newdata = new byte[data.length + opdata.length]; System.arraycopy(data, 0, newdata, 0, data.length); @@ -268,8 +237,8 @@ byte[] getBytes() // Add on the operator byte byte[] newdata = new byte[data.length + 3]; System.arraycopy(data, 0, newdata, 0, data.length); - newdata[data.length] = !useAlternateCode() ? Token.FUNCTION.getCode() : - Token.FUNCTION.getCode2(); + newdata[data.length] = !useAlternateCode() ? Token.FUNCTION.getReferenceCode() : + Token.FUNCTION.getValueCode(); IntegerHelper.getTwoBytes(function.getCode(), newdata, data.length + 1); return newdata; diff --git a/src/jxl/biff/formula/CellReference.java b/src/jxl/biff/formula/CellReference.java index 7b79391..0937521 100644 --- a/src/jxl/biff/formula/CellReference.java +++ b/src/jxl/biff/formula/CellReference.java @@ -149,8 +149,8 @@ public void getString(StringBuffer buf) byte[] getBytes() { byte[] data = new byte[5]; - data[0] = !useAlternateCode() ? Token.REF.getCode() : - Token.REF.getCode2(); + data[0] = !useAlternateCode() ? Token.REF.getReferenceCode() : + Token.REF.getValueCode(); IntegerHelper.getTwoBytes(row, data, 1); diff --git a/src/jxl/biff/formula/CellReference3d.java b/src/jxl/biff/formula/CellReference3d.java index 87e1a9b..5dda86c 100644 --- a/src/jxl/biff/formula/CellReference3d.java +++ b/src/jxl/biff/formula/CellReference3d.java @@ -180,7 +180,7 @@ public void getString(StringBuffer buf) byte[] getBytes() { byte[] data = new byte[7]; - data[0] = Token.REF3D.getCode(); + data[0] = Token.REF3D.getReferenceCode(); IntegerHelper.getTwoBytes(sheet, data, 1); IntegerHelper.getTwoBytes(row, data, 3); diff --git a/src/jxl/biff/formula/CellReferenceError.java b/src/jxl/biff/formula/CellReferenceError.java index 67c7eaa..a029784 100644 --- a/src/jxl/biff/formula/CellReferenceError.java +++ b/src/jxl/biff/formula/CellReferenceError.java @@ -70,7 +70,7 @@ public void getString(StringBuffer buf) byte[] getBytes() { byte[] data = new byte[5]; - data[0] = Token.REFERR.getCode(); + data[0] = Token.REFERR.getReferenceCode(); // bytes 1-5 are unused diff --git a/src/jxl/biff/formula/DoubleValue.java b/src/jxl/biff/formula/DoubleValue.java index 1e216b0..b650fc6 100644 --- a/src/jxl/biff/formula/DoubleValue.java +++ b/src/jxl/biff/formula/DoubleValue.java @@ -47,7 +47,7 @@ public DoubleValue() /** * Constructor - invoked when writing an integer value that's out - * of range for a short + of range for a short * * @param v the double value */ @@ -96,7 +96,7 @@ public int read(byte[] data, int pos) byte[] getBytes() { byte[] data = new byte[9]; - data[0] = Token.DOUBLE.getCode(); + data[0] = Token.DOUBLE.getReferenceCode(); DoubleHelper.getIEEEBytes(value, data, 1); diff --git a/src/jxl/biff/formula/ErrorConstant.java b/src/jxl/biff/formula/ErrorConstant.java index 1434dc7..b4cc26e 100644 --- a/src/jxl/biff/formula/ErrorConstant.java +++ b/src/jxl/biff/formula/ErrorConstant.java @@ -70,7 +70,7 @@ public int read(byte[] data, int pos) byte[] getBytes() { byte[] data = new byte[2]; - data[0] = Token.ERR.getCode(); + data[0] = Token.ERR.getReferenceCode(); data[1] = (byte) error.getCode(); return data; diff --git a/src/jxl/biff/formula/FunctionNames.java b/src/jxl/biff/formula/FunctionNames.java index 3f78dde..60dffb4 100644 --- a/src/jxl/biff/formula/FunctionNames.java +++ b/src/jxl/biff/formula/FunctionNames.java @@ -32,22 +32,18 @@ */ public class FunctionNames { - /** - * The logger class - */ - private static Logger logger = Logger.getLogger(FunctionNames.class); /** * A hash mapping keyed on the function and returning its locale specific * name */ - private HashMap names; + private final HashMap names = new HashMap<>(Function.getFunctions().length); /** * A hash mapping keyed on the locale specific name and returning the * function */ - private HashMap functions; + private final HashMap functions = new HashMap<>(Function.getFunctions().length); /** * Constructor @@ -57,21 +53,11 @@ public class FunctionNames public FunctionNames(Locale l) { ResourceBundle rb = ResourceBundle.getBundle("functions", l); - Function[] allfunctions = Function.getFunctions(); - names = new HashMap(allfunctions.length); - functions = new HashMap(allfunctions.length); // Iterate through all the functions, adding them to the hash maps - Function f = null; - String n = null; - String propname = null; - for (int i = 0; i < allfunctions.length; i++) - { - f = allfunctions[i]; - propname = f.getPropertyName(); - - n = propname.length() != 0 ? rb.getString(propname) : null; - + for (Function f : Function.getFunctions()) { + String propname = f.getPropertyName(); + String n = propname.length() != 0 ? rb.getString(propname) : null; if (n != null) { names.put(f, n); @@ -86,9 +72,8 @@ public FunctionNames(Locale l) * @param s the string * @return the function */ - Function getFunction(String s) - { - return (Function) functions.get(s); + Function getFunction(String s) { + return functions.get(s); } /** @@ -97,8 +82,7 @@ Function getFunction(String s) * @param f the function * @return the string */ - String getName(Function f) - { - return (String) names.get(f); + String getName(Function f) { + return names.get(f); } } diff --git a/src/jxl/biff/formula/IntegerValue.java b/src/jxl/biff/formula/IntegerValue.java index 933eae5..211f7fe 100644 --- a/src/jxl/biff/formula/IntegerValue.java +++ b/src/jxl/biff/formula/IntegerValue.java @@ -92,7 +92,7 @@ public int read(byte[] data, int pos) byte[] getBytes() { byte[] data = new byte[3]; - data[0] = Token.INTEGER.getCode(); + data[0] = Token.INTEGER.getReferenceCode(); IntegerHelper.getTwoBytes((int) value, data, 1); diff --git a/src/jxl/biff/formula/MissingArg.java b/src/jxl/biff/formula/MissingArg.java index 2c7b426..256543d 100644 --- a/src/jxl/biff/formula/MissingArg.java +++ b/src/jxl/biff/formula/MissingArg.java @@ -52,7 +52,7 @@ public int read(byte[] data, int pos) byte[] getBytes() { byte[] data = new byte[1]; - data[0] = Token.MISSING_ARG.getCode(); + data[0] = Token.MISSING_ARG.getReferenceCode(); return data; } diff --git a/src/jxl/biff/formula/NameRange.java b/src/jxl/biff/formula/NameRange.java index d956ab8..fea09b7 100644 --- a/src/jxl/biff/formula/NameRange.java +++ b/src/jxl/biff/formula/NameRange.java @@ -20,7 +20,6 @@ package jxl.biff.formula; import jxl.common.Assert; -import jxl.common.Logger; import jxl.biff.IntegerHelper; import jxl.biff.NameRangeException; @@ -31,21 +30,17 @@ */ class NameRange extends Operand implements ParsedThing { - /** - * The logger - */ - private static Logger logger = Logger.getLogger(NameRange.class); /** * A handle to the name table */ - private WorkbookMethods nameTable; + private final WorkbookMethods nameTable; /** * The string name */ private String name; - + /** * The index into the name table */ @@ -62,7 +57,7 @@ public NameRange(WorkbookMethods nt) /** * Constructor when parsing a string via the api - * + * * @param nm the name string * @param nt the name table */ @@ -81,21 +76,22 @@ public NameRange(String nm, WorkbookMethods nt) throws FormulaException index += 1; // indexes are 1-based } - /** + /** * Reads the ptg data from the array starting at the specified position * * @param data the RPN array * @param pos the current position in the array, excluding the ptg identifier * @return the number of bytes read */ - public int read(byte[] data, int pos) throws FormulaException + @Override + public int read(byte[] data, int pos) throws FormulaException { try { index = IntegerHelper.getInt(data[pos], data[pos+1]); name = nameTable.getName(index - 1); // ilbl is 1-based - + return 4; } catch (NameRangeException e) @@ -109,15 +105,16 @@ public int read(byte[] data, int pos) throws FormulaException * * @return the bytes applicable to this formula */ + @Override byte[] getBytes() { byte[] data = new byte[5]; - data[0] = Token.NAMED_RANGE.getValueCode(); - + data[0] = Token.NAME.getValueCode(); + if (getParseContext() == ParseContext.DATA_VALIDATION) { - data[0] = Token.NAMED_RANGE.getReferenceCode(); + data[0] = Token.NAME.getReferenceCode(); } IntegerHelper.getTwoBytes(index, data, 1); @@ -128,9 +125,10 @@ byte[] getBytes() /** * Abstract method implementation to get the string equivalent of this * token - * + * * @param buf the string to append to */ + @Override public void getString(StringBuffer buf) { buf.append(name); @@ -142,6 +140,7 @@ public void getString(StringBuffer buf) * cell references to another sheet are warned appropriately * Flags the formula as invalid */ + @Override void handleImportedCellReferences() { setInvalid(); diff --git a/src/jxl/biff/formula/Operator.java b/src/jxl/biff/formula/Operator.java index a6ecbc7..0aaec73 100644 --- a/src/jxl/biff/formula/Operator.java +++ b/src/jxl/biff/formula/Operator.java @@ -40,16 +40,14 @@ public Operator() { operands = new ParseItem[0]; } - + /** * Tells the operands to use the alternate code */ protected void setOperandAlternateCode() { - for (int i = 0 ; i < operands.length ; i++) - { - operands[i].setAlternateCode(); - } + for (ParseItem operand : operands) + operand.setAlternateCode(); } /** @@ -66,10 +64,10 @@ protected void add(ParseItem n) operands = newOperands; } - /** - * Gets the operands for this operator from the stack + /** + * Gets the operands for this operator from the stack */ - public abstract void getOperands(Stack s); + public abstract void getOperands(Stack s); /** * Gets the operands ie. the children of the node @@ -80,7 +78,7 @@ protected ParseItem[] getOperands() } /** - * Gets the precedence for this operator. Operator precedents run from + * Gets the precedence for this operator. Operator precedents run from * 1 to 5, one being the highest, 5 being the lowest * * @return the operator precedence diff --git a/src/jxl/biff/formula/Parenthesis.java b/src/jxl/biff/formula/Parenthesis.java index 0e011eb..38b4d6d 100644 --- a/src/jxl/biff/formula/Parenthesis.java +++ b/src/jxl/biff/formula/Parenthesis.java @@ -26,14 +26,14 @@ */ class Parenthesis extends Operator implements ParsedThing { - /** + /** * Constructor */ public Parenthesis() { } - /** + /** * Reads the ptg data from the array starting at the specified position * * @param data the RPN array @@ -45,14 +45,12 @@ public int read(byte[] data, int pos) return 0; } - /** + /** * Gets the operands for this operator from the stack */ - public void getOperands(Stack s) + public void getOperands(Stack s) { - ParseItem pi = (ParseItem) s.pop(); - - add(pi); + add(s.pop()); } public void getString(StringBuffer buf) @@ -175,13 +173,13 @@ byte[] getBytes() // Add on the operator byte byte[] newdata = new byte[data.length + 1]; System.arraycopy(data, 0, newdata, 0, data.length); - newdata[data.length] = getToken().getCode(); + newdata[data.length] = getToken().getReferenceCode(); return newdata; } /** - * Gets the precedence for this operator. Operator precedents run from + * Gets the precedence for this operator. Operator precedents run from * 1 to 5, one being the highest, 5 being the lowest * * @return the operator precedence diff --git a/src/jxl/biff/formula/ParseContext.java b/src/jxl/biff/formula/ParseContext.java index 5cbac82..4f2b36d 100644 --- a/src/jxl/biff/formula/ParseContext.java +++ b/src/jxl/biff/formula/ParseContext.java @@ -22,15 +22,7 @@ /** * Enumeration type for the context in which this formula is being parsed */ -public class ParseContext -{ - public static ParseContext DEFAULT = new ParseContext(); - public static ParseContext DATA_VALIDATION = new ParseContext(); - - /** - * Private constructor - */ - private ParseContext() - { - } +public enum ParseContext { + DEFAULT, + DATA_VALIDATION } diff --git a/src/jxl/biff/formula/ParseItem.java b/src/jxl/biff/formula/ParseItem.java index db24751..db35445 100644 --- a/src/jxl/biff/formula/ParseItem.java +++ b/src/jxl/biff/formula/ParseItem.java @@ -26,9 +26,6 @@ */ abstract class ParseItem { - // The logger - private static Logger logger = Logger.getLogger(ParseItem.class); - /** * The parent of this parse item */ diff --git a/src/jxl/biff/formula/RangeSeparator.java b/src/jxl/biff/formula/RangeSeparator.java index 27f1551..9c58398 100644 --- a/src/jxl/biff/formula/RangeSeparator.java +++ b/src/jxl/biff/formula/RangeSeparator.java @@ -78,7 +78,7 @@ byte[] getBytes() System.arraycopy(funcBytes, 0, bytes, 3, funcBytes.length); // Indicate the mem func - bytes[0] = Token.MEM_FUNC.getCode(); + bytes[0] = Token.MEM_FUNC.getReferenceCode(); IntegerHelper.getTwoBytes(funcBytes.length, bytes, 1); return bytes; diff --git a/src/jxl/biff/formula/SharedFormulaArea.java b/src/jxl/biff/formula/SharedFormulaArea.java index 6cb783c..d403e5e 100644 --- a/src/jxl/biff/formula/SharedFormulaArea.java +++ b/src/jxl/biff/formula/SharedFormulaArea.java @@ -83,7 +83,7 @@ int getLastRow() */ public int read(byte[] data, int pos) { - // Preserve signage on column and row values, because they will + // Preserve signage on column and row value, because they will // probably be relative rowFirst = IntegerHelper.getShort(data[pos], data[pos+1]); @@ -139,7 +139,7 @@ public void getString(StringBuffer buf) byte[] getBytes() { byte[] data = new byte[9]; - data[0] = Token.AREA.getCode(); + data[0] = Token.AREA.getReferenceCode(); // Use absolute references for columns, so don't bother about // the col relative/row relative bits diff --git a/src/jxl/biff/formula/SharedFormulaCellReference.java b/src/jxl/biff/formula/SharedFormulaCellReference.java index e473ee9..a8f2073 100644 --- a/src/jxl/biff/formula/SharedFormulaCellReference.java +++ b/src/jxl/biff/formula/SharedFormulaCellReference.java @@ -80,7 +80,7 @@ public SharedFormulaCellReference(Cell rt) */ public int read(byte[] data, int pos) { - // Preserve signage on column and row values, because they will + // Preserve signage on column and row value, because they will // probably be relative row = IntegerHelper.getShort(data[pos], data[pos+1]); @@ -126,7 +126,7 @@ public void getString(StringBuffer buf) byte[] getBytes() { byte[] data = new byte[5]; - data[0] = Token.REF.getCode(); + data[0] = Token.REF.getReferenceCode(); IntegerHelper.getTwoBytes(row, data, 1); diff --git a/src/jxl/biff/formula/StringFormulaParser.java b/src/jxl/biff/formula/StringFormulaParser.java index 3ab5164..9df03d5 100644 --- a/src/jxl/biff/formula/StringFormulaParser.java +++ b/src/jxl/biff/formula/StringFormulaParser.java @@ -59,7 +59,7 @@ class StringFormulaParser implements Parser * The stack argument used when parsing a function in order to * pass multiple arguments back to the calling method */ - private Stack arguments; + private Stack arguments; /** * The workbook settings @@ -79,16 +79,16 @@ class StringFormulaParser implements Parser /** * The parse context */ - private ParseContext parseContext; + private final ParseContext parseContext; /** * Constructor * @param f * @param ws */ - public StringFormulaParser(String f, - ExternalSheet es, - WorkbookMethods nt, + public StringFormulaParser(String f, + ExternalSheet es, + WorkbookMethods nt, WorkbookSettings ws, ParseContext pc) { @@ -106,11 +106,8 @@ public StringFormulaParser(String f, */ public void parse() throws FormulaException { - ArrayList tokens = getTokens(); - - Iterator i = tokens.iterator(); - - root = parseCurrent(i); + ArrayList tokens = getTokens(); + root = parseCurrent(tokens.iterator()); } /** @@ -121,38 +118,36 @@ public void parse() throws FormulaException * @return the root node of the current parse stack * @exception FormulaException if an error occurs */ - private ParseItem parseCurrent(Iterator i) throws FormulaException + private ParseItem parseCurrent(Iterator i) throws FormulaException { - Stack stack = new Stack(); - Stack operators = new Stack(); - Stack args = null; // we usually don't need this + Stack stack = new Stack<>(); + Stack operators = new Stack<>(); + Stack args = null; // we usually don't need this boolean parenthesesClosed = false; ParseItem lastParseItem = null; - + while (i.hasNext() && !parenthesesClosed) { - ParseItem pi = (ParseItem) i.next(); + ParseItem pi = i.next(); pi.setParseContext(parseContext); - if (pi instanceof Operand) + if (pi instanceof Operand operand) { - handleOperand((Operand) pi, stack); + handleOperand(operand, stack); } - else if (pi instanceof StringFunction) + else if (pi instanceof StringFunction stringFunction) { - handleFunction((StringFunction) pi, i, stack); + handleFunction(stringFunction, i, stack); } - else if (pi instanceof Operator) + else if (pi instanceof Operator op) { - Operator op = (Operator) pi; - + // See if the operator is a binary or unary operator // It is a unary operator either if the stack is empty, or if // the last thing off the stack was another operator - if (op instanceof StringOperator) + if (op instanceof StringOperator sop) { - StringOperator sop = (StringOperator) op; if (stack.isEmpty() || lastParseItem instanceof Operator) { op = sop.getUnaryOperator(); @@ -170,9 +165,9 @@ else if (pi instanceof Operator) } else { - Operator operator = (Operator) operators.peek(); + Operator operator = operators.peek(); - // If the last operator has a higher precedence then add this to + // If the last operator has a higher precedence then add this to // the operator stack and wait if (op.getPrecedence() < operator.getPrecedence()) { @@ -185,7 +180,7 @@ else if (op.getPrecedence() == operator.getPrecedence() && // unary operator the operand isn't available yet, so put it on // the stack operators.push(op); - } + } else { // The operator is of a lower precedence so we can sort out @@ -202,17 +197,17 @@ else if (pi instanceof ArgumentSeparator) // Clean up any remaining items on this stack while (!operators.isEmpty()) { - Operator o = (Operator) operators.pop(); + Operator o = operators.pop(); o.getOperands(stack); stack.push(o); } - + // Add it to the argument stack. Create the argument stack // if necessary. Items will be stored on the argument stack in // reverse order if (args == null) { - args = new Stack(); + args = new Stack<>(); } args.push(stack.pop()); @@ -230,18 +225,18 @@ else if (pi instanceof CloseParentheses) { parenthesesClosed = true; } - + lastParseItem = pi; } while (!operators.isEmpty()) { - Operator o = (Operator) operators.pop(); + Operator o = operators.pop(); o.getOperands(stack); stack.push(o); } - ParseItem rt = !stack.empty()? (ParseItem) stack.pop():null; + ParseItem rt = !stack.empty() ? stack.pop() : null; // if the argument stack is not null, then add it to that stack // as well for good measure @@ -254,7 +249,7 @@ else if (pi instanceof CloseParentheses) if (!stack.empty() || !operators.empty() ) { - logger.warn("Formula " + formula + + logger.warn("Formula " + formula + " has a non-empty parse stack"); } @@ -267,9 +262,9 @@ else if (pi instanceof CloseParentheses) * @return the list of tokens * @exception FormulaException if an error occurs */ - private ArrayList getTokens() throws FormulaException + private ArrayList getTokens() throws FormulaException { - ArrayList tokens = new ArrayList(); + ArrayList tokens = new ArrayList<>(); StringReader sr = new StringReader(formula); Yylex lex = new Yylex(sr); @@ -293,7 +288,7 @@ private ArrayList getTokens() throws FormulaException throw new FormulaException(FormulaException.LEXICAL_ERROR, formula + " at char " + lex.getPos()); } - + return tokens; } @@ -321,12 +316,12 @@ public String getFormula() public byte[] getBytes() { byte[] bytes = root.getBytes(); - + if (root.isVolatile()) { byte[] newBytes = new byte[bytes.length + 4]; System.arraycopy(bytes, 0, newBytes, 4, bytes.length); - newBytes[0] = Token.ATTRIBUTE.getCode(); + newBytes[0] = Token.ATTRIBUTE.getReferenceCode(); newBytes[1] = (byte) 0x1; bytes = newBytes; } @@ -342,11 +337,11 @@ public byte[] getBytes() * @param stack the parse tree stack * @exception FormulaException if an error occurs */ - private void handleFunction(StringFunction sf, Iterator i, - Stack stack) + private void handleFunction(StringFunction sf, Iterator i, + Stack stack) throws FormulaException { - ParseItem pi2 = parseCurrent(i); + ParseItem pi2 = parseCurrent(i); // If the function is unknown, then throw an error if (sf.getFunction(settings) == Function.UNKNOWN) @@ -369,23 +364,23 @@ private void handleFunction(StringFunction sf, Iterator i, { // this is handled by an attribute Attribute a = new Attribute(sf, settings); - + // Add in the if conditions as a var arg function in // the correct order VariableArgFunction vaf = new VariableArgFunction(settings); int numargs = arguments.size(); for (int j = 0 ; j < numargs; j++) { - ParseItem pi3 = (ParseItem) arguments.get(j); + ParseItem pi3 = arguments.get(j); vaf.add(pi3); } - + a.setIfConditions(vaf); stack.push(a); return; } - // Function cannot be optimized. See if it is a variable argument + // Function cannot be optimized. See if it is a variable argument // function or not if (sf.getFunction(settings).getNumArgs() == 0xff) { @@ -411,18 +406,16 @@ private void handleFunction(StringFunction sf, Iterator i, int numargs = arguments.size(); VariableArgFunction vaf = new VariableArgFunction (sf.getFunction(settings), numargs, settings); - + ParseItem[] args = new ParseItem[numargs]; for (int j = 0 ; j < numargs; j++) { - ParseItem pi3 = (ParseItem) arguments.pop(); + ParseItem pi3 = arguments.pop(); args[numargs-j-1] = pi3; } - for (int j = 0 ; j < args.length ; j++) - { - vaf.add(args[j]); - } + for (ParseItem arg : args) + vaf.add(arg); stack.push(vaf); arguments.clear(); arguments = null; @@ -431,9 +424,9 @@ private void handleFunction(StringFunction sf, Iterator i, } // Function is a standard built in function - BuiltInFunction bif = new BuiltInFunction(sf.getFunction(settings), + BuiltInFunction bif = new BuiltInFunction(sf.getFunction(settings), settings); - + int numargs = sf.getFunction(settings).getNumArgs(); if (numargs == 1) { @@ -447,12 +440,12 @@ private void handleFunction(StringFunction sf, Iterator i, { throw new FormulaException(FormulaException.INCORRECT_ARGUMENTS); } - // multiple arguments so go to the arguments stack. + // multiple arguments so go to the arguments stack. // Unlike the variable argument function, the args are // stored in reverse order for (int j = 0; j < numargs ; j++) { - ParseItem pi3 = (ParseItem) arguments.get(j); + ParseItem pi3 = arguments.get(j); bif.add(pi3); } } @@ -537,7 +530,7 @@ public void rowRemoved(int sheetIndex, int row, boolean currentSheet) * @param o operand * @param stack stack */ - private void handleOperand(Operand o, Stack stack) + private void handleOperand(Operand o, Stack stack) { if (!(o instanceof IntegerValue)) { @@ -545,9 +538,8 @@ private void handleOperand(Operand o, Stack stack) return; } - if (o instanceof IntegerValue) + if (o instanceof IntegerValue iv) { - IntegerValue iv = (IntegerValue) o; if (!iv.isOutOfRange()) { stack.push(iv); @@ -555,7 +547,7 @@ private void handleOperand(Operand o, Stack stack) else { // convert to a double - DoubleValue dv = new DoubleValue(iv.getValue()); + DoubleValue dv = new DoubleValue(iv.getValue()); stack.push(dv); } } diff --git a/src/jxl/biff/formula/StringOperator.java b/src/jxl/biff/formula/StringOperator.java index 755b7e2..13ee54d 100644 --- a/src/jxl/biff/formula/StringOperator.java +++ b/src/jxl/biff/formula/StringOperator.java @@ -39,11 +39,11 @@ protected StringOperator() super(); } - /** + /** * Gets the operands for this operator from the stack. Does nothing * here */ - public void getOperands(Stack s) + public void getOperands(Stack s) { Assert.verify(false); } @@ -69,7 +69,7 @@ byte[] getBytes() Assert.verify(false); return null; } - + /** * Gets the string representation of this item */ diff --git a/src/jxl/biff/formula/StringValue.java b/src/jxl/biff/formula/StringValue.java index 98d9d1a..b0dc936 100644 --- a/src/jxl/biff/formula/StringValue.java +++ b/src/jxl/biff/formula/StringValue.java @@ -84,7 +84,7 @@ public int read(byte[] data, int pos) } else { - value = StringHelper.getUnicodeString(data, length, pos+2); + value = StringHelper.getUnicodeString(data, pos+2, length); consumed += length * 2; } @@ -99,7 +99,7 @@ public int read(byte[] data, int pos) byte[] getBytes() { byte[] data = new byte[value.length() * 2 + 3]; - data[0] = Token.STRING.getCode(); + data[0] = Token.STRING.getReferenceCode(); data[1] = (byte) (value.length()); data[2] = 0x01; StringHelper.getUnicodeBytes(value, data, 3); diff --git a/src/jxl/biff/formula/SubExpression.java b/src/jxl/biff/formula/SubExpression.java index fc57b42..d782c78 100644 --- a/src/jxl/biff/formula/SubExpression.java +++ b/src/jxl/biff/formula/SubExpression.java @@ -45,7 +45,7 @@ protected SubExpression() { } - /** + /** * Reads the ptg data from the array starting at the specified position * * @param data the RPN array @@ -58,10 +58,10 @@ public int read(byte[] data, int pos) return 2; } - /** + /** * Gets the operands for this operator from the stack */ - public void getOperands(Stack s) + public void getOperands(Stack s) { } @@ -79,7 +79,7 @@ byte[] getBytes() /** - * Gets the precedence for this operator. Operator precedents run from + * Gets the precedence for this operator. Operator precedents run from * 1 to 5, one being the highest, 5 being the lowest * * @return the operator precedence diff --git a/src/jxl/biff/formula/Token.java b/src/jxl/biff/formula/Token.java index b8fee45..1e74b10 100644 --- a/src/jxl/biff/formula/Token.java +++ b/src/jxl/biff/formula/Token.java @@ -19,202 +19,160 @@ package jxl.biff.formula; -import java.util.HashMap; +import java.util.*; /** * An enumeration detailing the Excel parsed tokens * A particular token may be associated with more than one token code */ -class Token -{ - /** - * The array of values which apply to this token - */ - public final int[] value; +enum Token { + + // Binary Operators + ADD (0x3), + SUBTRACT (0x4), + MULTIPLY (0x5), + DIVIDE (0x6), + POWER (0x7), + CONCAT (0x8), + LESS_THAN (0x9), + LESS_EQUAL (0xa), + EQUAL (0xb), + GREATER_EQUAL(0xc), + GREATER_THAN (0xd), + NOT_EQUAL (0xe), + INTERSECTION (0xf), + UNION (0x10), + RANGE (0x11), + + // Unary Operators + UNARY_PLUS (0x12), + UNARY_MINUS (0x13), + PERCENT (0x14), + + // Constant Operands + MISSING_ARG (0x16), + STRING (0x17), + ERR (0x1c), + BOOL (0x1d), + INTEGER (0x1e), + DOUBLE (0x1f), + ARRAY (0x20, 0x40, 0x60), // the reference class 0x20 never appears in an excel formula + + // Operands + NAME (0x23, 0x43, 0x63), //need 0x23 for data validation references + REF (0x24, 0x44, 0x64), + AREA (0x25, 0x45, 0x65), + MEM_AREA (0x26, 0x46, 0x66), + MEM_ERR (0x27, 0x47, 0x67), + REFERR (0x2a, 0x4a, 0x6a), + AREA_ERR (0x2b, 0x4b, 0x6b), + REF_N (0x2c, 0x4c, 0x6c), + AREA_N (0x2d, 0x4d, 0x6d), + NAME_X (0x39, 0x59, 0x79), // local name of explicit sheet or external name + REF3D (0x3a, 0x5a, 0x7a), + AREA3D (0x3b, 0x5b, 0x7b), + REF_ERR_3D (0x3c, 0x5c, 0x7c), + AREA_ERR_3D (0x3d, 0x5d, 0x7d), + + // Function operators + FUNCTION (0x21, 0x41, 0x61), + FUNCTIONVARARG (0x22, 0x42, 0x62), + MACROCOMMAND (0x38, 0x58, 0x78), // BIFF2,BIFF3 + + // Control + EXP (0x1), + TBL (0x2), + PARENTHESIS (0x15), + NLR (0x18), // BIFF8, extended parsed thing + ATTRIBUTE (0x19), + SHEET (0x1A), // BIFF2-4, deleted + END_SHEET (0x1B), // BIFF2-4, deleted + MEM_NO_MEM (0x28, 0x48, 0x68), + MEM_FUNC (0x29, 0x49, 0x69), + MEM_AREA_N (0x2e, 0x4e, 0x6e), + MEM_NO_MEM_N(0x2f, 0x4f, 0x6f), + + // Unknown token + UNKNOWN (0); /** - * All available tokens, keyed on value + * The array of values which apply to this token */ - private static HashMap tokens = new HashMap(20); + private final byte[] values; /** * Constructor * Sets the token value and adds this token to the array of all token * - * @param v the biff code for the token + * @param reference the biff code for the token */ - private Token(int v) - { - value = new int[] {v}; - - tokens.put(new Integer(v), this); + private Token(int reference) { + values = new byte[] {(byte) reference}; } /** * Constructor * Sets the token value and adds this token to the array of all token * - * @param v the biff code for the token + * @param reference the biff code for the token + * @param value the biff code for the token + * @param array the biff code for the token */ - private Token(int v1, int v2) - { - value = new int[] {v1, v2}; - - tokens.put(new Integer(v1), this); - tokens.put(new Integer(v2), this); + private Token(int reference, int value, int array) { + this.values = new byte[] {(byte) reference, (byte) value, (byte) array}; } /** - * Constructor - * Sets the token value and adds this token to the array of all token + * Gets the reference token code for the specified token. This is always + * the first on the list * - * @param v the biff code for the token - */ - private Token(int v1, int v2, int v3) - { - value = new int[] {v1, v2, v3}; - - tokens.put(new Integer(v1), this); - tokens.put(new Integer(v2), this); - tokens.put(new Integer(v3), this); - } - - /** - * Constructor - * Sets the token value and adds this token to the array of all token + * @return the token code. This is the first item in the array * - * @param v the biff code for the token + * TODO: used in DATA_VALIDATION = getReferenceCode = ! alternateCode */ - private Token(int v1, int v2, int v3, int v4) - { - value = new int[] {v1, v2, v3, v4}; - - tokens.put(new Integer(v1), this); - tokens.put(new Integer(v2), this); - tokens.put(new Integer(v3), this); - tokens.put(new Integer(v4), this); + public byte getReferenceCode() { + return values[0]; } /** - * Constructor - * Sets the token value and adds this token to the array of all token + * Gets the value token code for the specified token. This is always + * the second item on the list * - * @param v the biff code for the token - */ - private Token(int v1, int v2, int v3, int v4, int v5) - { - value = new int[] {v1, v2, v3, v4, v5}; - - tokens.put(new Integer(v1), this); - tokens.put(new Integer(v2), this); - tokens.put(new Integer(v3), this); - tokens.put(new Integer(v4), this); - tokens.put(new Integer(v5), this); - } - - /** - * Gets the token code for the specified token - * - * @return the token code. This is the first item in the array - */ - public byte getCode() - { - return (byte) value[0]; - } - - /** - * Gets the reference token code for the specified token. This is always - * the first on the list - * - * @return the token code. This is the first item in the array + * @return the token code + * + * TODO: used in DEFAULT = getValueCode = alternateCode */ - public byte getReferenceCode() - { - return (byte) value[0]; + public byte getValueCode() { + return values.length > 1 ? values[1] : values[0]; } /** - * Gets the an alternative token code for the specified token - * Used for certain types of volatile function - * + * Gets the array token code for the specified token. This is always + * the third item on the list + * * @return the token code */ - public byte getCode2() - { - return (byte) (value.length > 0 ? value[1] : value[0]); + public byte getArrayCode() { + return values.length > 2 ? values[2] : getValueCode(); } /** - * Gets the value token code for the specified token. This is always - * the second item on the list - * - * @return the token code + * All available tokens, keyed on value */ - public byte getValueCode() - { - return (byte) (value.length > 0 ? value[1] : value[0]); + private static final Map TOKENS = new HashMap<>(100); + + static { + Arrays.stream(Token.values()) + .peek(t -> TOKENS.put(t.getReferenceCode(), t)) + .peek(t -> TOKENS.put(t.getValueCode(), t)) + .forEach(t -> TOKENS.put(t.getArrayCode(), t)); } /** - * Gets the type object from its integer value + * Gets the type object from its byte value */ - public static Token getToken(int v) - { - Token t = (Token) tokens.get(new Integer(v)); - - return t != null ? t : UNKNOWN; + public static Token getToken(byte v) { + return TOKENS.getOrDefault(v, UNKNOWN); } - // Operands - public static final Token REF = new Token(0x44, 0x24, 0x64); - public static final Token REF3D = new Token(0x5a, 0x3a, 0x7a); - public static final Token MISSING_ARG = new Token(0x16); - public static final Token STRING = new Token(0x17); - public static final Token ERR = new Token(0x1c); - public static final Token BOOL = new Token(0x1d); - public static final Token INTEGER = new Token(0x1e); - public static final Token DOUBLE = new Token(0x1f); - public static final Token REFERR = new Token(0x2a, 0x4a, 0x6a); - public static final Token REFV = new Token(0x2c, 0x4c, 0x6c); - public static final Token AREAV = new Token(0x2d, 0x4d, 0x6d); - public static final Token MEM_AREA = new Token(0x26, 0x46, 0x66); - public static final Token AREA = new Token(0x25, 0x65, 0x45); - public static final Token NAMED_RANGE = new Token(0x23, 0x43, 0x63); - //need 0x23 for data validation references - public static final Token NAME = new Token(0x39, 0x59); - public static final Token AREA3D = new Token(0x3b, 0x5b); - - // Unary Operators - public static final Token UNARY_PLUS = new Token(0x12); - public static final Token UNARY_MINUS = new Token(0x13); - public static final Token PERCENT = new Token(0x14); - public static final Token PARENTHESIS = new Token(0x15); - - // Binary Operators - public static final Token ADD = new Token(0x3); - public static final Token SUBTRACT = new Token(0x4); - public static final Token MULTIPLY = new Token(0x5); - public static final Token DIVIDE = new Token(0x6); - public static final Token POWER = new Token(0x7); - public static final Token CONCAT = new Token(0x8); - public static final Token LESS_THAN = new Token(0x9); - public static final Token LESS_EQUAL = new Token(0xa); - public static final Token EQUAL = new Token(0xb); - public static final Token GREATER_EQUAL = new Token(0xc); - public static final Token GREATER_THAN = new Token(0xd); - public static final Token NOT_EQUAL = new Token(0xe); - public static final Token UNION = new Token(0x10); - public static final Token RANGE = new Token(0x11); - - // Functions - public static final Token FUNCTION = new Token(0x41, 0x21, 0x61); - public static final Token FUNCTIONVARARG = new Token(0x42, 0x22, 0x62); - - // Control - public static final Token ATTRIBUTE = new Token(0x19); - public static final Token MEM_FUNC = new Token(0x29, 0x49, 0x69); - - // Unknown token - public static final Token UNKNOWN = new Token(0xffff); -} - +} \ No newline at end of file diff --git a/src/jxl/biff/formula/TokenFormulaParser.java b/src/jxl/biff/formula/TokenFormulaParser.java index e299a3c..158f1b8 100644 --- a/src/jxl/biff/formula/TokenFormulaParser.java +++ b/src/jxl/biff/formula/TokenFormulaParser.java @@ -22,7 +22,6 @@ import java.util.Stack; import jxl.common.Assert; -import jxl.common.Logger; import jxl.Cell; import jxl.WorkbookSettings; @@ -33,21 +32,16 @@ */ class TokenFormulaParser implements Parser { - /** - * The logger - */ - private static Logger logger = Logger.getLogger(TokenFormulaParser.class); - /** * The Excel ptgs */ - private byte[] tokenData; + private final byte[] tokenData; /** * The cell containing the formula. This is used in order to determine * relative cell values */ - private Cell relativeTo; + private final Cell relativeTo; /** * The current position within the array @@ -62,35 +56,35 @@ class TokenFormulaParser implements Parser /** * The hash table of items that have been parsed */ - private Stack tokenStack; + private Stack tokenStack = new Stack<>(); /** * A reference to the workbook which holds the external sheet * information */ - private ExternalSheet workbook; + private final ExternalSheet workbook; /** * A reference to the name table */ - private WorkbookMethods nameTable; + private final WorkbookMethods nameTable; /** * The workbook settings */ - private WorkbookSettings settings; + private final WorkbookSettings settings; /** * The parse context */ - private ParseContext parseContext; + private final ParseContext parseContext; /** * Constructor */ - public TokenFormulaParser(byte[] data, - Cell c, - ExternalSheet es, + public TokenFormulaParser(byte[] data, + Cell c, + ExternalSheet es, WorkbookMethods nt, WorkbookSettings ws, ParseContext pc) @@ -100,10 +94,9 @@ public TokenFormulaParser(byte[] data, relativeTo = c; workbook = es; nameTable = nt; - tokenStack = new Stack(); settings = ws; parseContext = pc; - + Assert.verify(nameTable != null); } @@ -113,13 +106,14 @@ public TokenFormulaParser(byte[] data, * * @exception FormulaException */ + @Override public void parse() throws FormulaException { parseSubExpression(tokenData.length); // Finally, there should be one thing left on the stack. Get that // and add it to the root node - root = (ParseItem) tokenStack.pop(); + root = tokenStack.pop(); Assert.verify(tokenStack.empty()); @@ -134,289 +128,231 @@ public void parse() throws FormulaException */ private void parseSubExpression(int len) throws FormulaException { - int tokenVal = 0; - Token t = null; - + // Indicates that we are parsing the incredibly complicated and // hacky if construct that MS saw fit to include, the gits - Stack ifStack = new Stack(); + Stack ifStack = new Stack<>(); // The end position of the sub-expression int endpos = pos + len; while (pos < endpos) { - tokenVal = tokenData[pos]; + byte tokenVal = tokenData[pos]; pos++; - t = Token.getToken(tokenVal); + switch (Token.getToken(tokenVal)) { + case UNKNOWN -> throw new FormulaException(FormulaException.UNRECOGNIZED_TOKEN, tokenVal); - if (t == Token.UNKNOWN) - { - throw new FormulaException - (FormulaException.UNRECOGNIZED_TOKEN, tokenVal); - } - - Assert.verify(t != Token.UNKNOWN); - - // Operands - if (t == Token.REF) - { - CellReference cr = new CellReference(relativeTo); - pos += cr.read(tokenData, pos); - tokenStack.push(cr); - } - else if (t == Token.REFERR) - { - CellReferenceError cr = new CellReferenceError(); - pos += cr.read(tokenData, pos); - tokenStack.push(cr); - } - else if (t == Token.ERR) - { - ErrorConstant ec = new ErrorConstant(); - pos += ec.read(tokenData, pos); - tokenStack.push(ec); - } - else if (t == Token.REFV) - { - SharedFormulaCellReference cr = - new SharedFormulaCellReference(relativeTo); - pos += cr.read(tokenData, pos); - tokenStack.push(cr); - } - else if (t == Token.REF3D) - { - CellReference3d cr = new CellReference3d(relativeTo, workbook); - pos += cr.read(tokenData, pos); - tokenStack.push(cr); - } - else if (t == Token.AREA) - { - Area a = new Area(); - pos += a.read(tokenData, pos); - tokenStack.push(a); - } - else if (t == Token.AREAV) - { - SharedFormulaArea a = new SharedFormulaArea(relativeTo); - pos += a.read(tokenData, pos); - tokenStack.push(a); - } - else if (t == Token.AREA3D) - { - Area3d a = new Area3d(workbook); - pos += a.read(tokenData, pos); - tokenStack.push(a); - } - else if (t == Token.NAME) - { - Name n = new Name(); - pos += n.read(tokenData, pos); - n.setParseContext(parseContext); - tokenStack.push(n); - } - else if (t == Token.NAMED_RANGE) - { - NameRange nr = new NameRange(nameTable); - pos += nr.read(tokenData, pos); - nr.setParseContext(parseContext); - tokenStack.push(nr); - } - else if (t == Token.INTEGER) - { - IntegerValue i = new IntegerValue(); - pos += i.read(tokenData, pos); - tokenStack.push(i); - } - else if (t == Token.DOUBLE) - { - DoubleValue d = new DoubleValue(); - pos += d.read(tokenData, pos); - tokenStack.push(d); - } - else if (t == Token.BOOL) - { - BooleanValue bv = new BooleanValue(); - pos += bv.read(tokenData, pos); - tokenStack.push(bv); - } - else if (t == Token.STRING) - { - StringValue sv = new StringValue(settings); - pos += sv.read(tokenData, pos); - tokenStack.push(sv); - } - else if (t == Token.MISSING_ARG) - { - MissingArg ma = new MissingArg(); - pos += ma.read(tokenData, pos); - tokenStack.push(ma); - } - - // Unary Operators - else if (t == Token.UNARY_PLUS) - { - UnaryPlus up = new UnaryPlus(); - pos += up.read(tokenData, pos); - addOperator(up); - } - else if (t == Token.UNARY_MINUS) - { - UnaryMinus um = new UnaryMinus(); - pos += um.read(tokenData, pos); - addOperator(um); - } - else if (t == Token.PERCENT) - { - Percent p = new Percent(); - pos += p.read(tokenData, pos); - addOperator(p); - } - - // Binary Operators - else if (t == Token.SUBTRACT) - { - Subtract s = new Subtract(); - pos += s.read(tokenData, pos); - addOperator(s); - } - else if (t == Token.ADD) - { - Add s = new Add(); - pos += s.read(tokenData, pos); - addOperator(s); - } - else if (t == Token.MULTIPLY) - { - Multiply s = new Multiply(); - pos += s.read(tokenData, pos); - addOperator(s); - } - else if (t == Token.DIVIDE) - { - Divide s = new Divide(); - pos += s.read(tokenData, pos); - addOperator(s); - } - else if (t == Token.CONCAT) - { - Concatenate c = new Concatenate(); - pos += c.read(tokenData, pos); - addOperator(c); - } - else if (t == Token.POWER) - { - Power p = new Power(); - pos += p.read(tokenData, pos); - addOperator(p); - } - else if (t == Token.LESS_THAN) - { - LessThan lt = new LessThan(); - pos += lt.read(tokenData, pos); - addOperator(lt); - } - else if (t == Token.LESS_EQUAL) - { - LessEqual lte = new LessEqual(); - pos += lte.read(tokenData, pos); - addOperator(lte); - } - else if (t == Token.GREATER_THAN) - { - GreaterThan gt = new GreaterThan(); - pos += gt.read(tokenData, pos); - addOperator(gt); - } - else if (t == Token.GREATER_EQUAL) - { - GreaterEqual gte = new GreaterEqual(); - pos += gte.read(tokenData, pos); - addOperator(gte); - } - else if (t == Token.NOT_EQUAL) - { - NotEqual ne = new NotEqual(); - pos += ne.read(tokenData, pos); - addOperator(ne); - } - else if (t == Token.EQUAL) - { - Equal e = new Equal(); - pos += e.read(tokenData, pos); - addOperator(e); - } - else if (t == Token.PARENTHESIS) - { - Parenthesis p = new Parenthesis(); - pos += p.read(tokenData, pos); - addOperator(p); - } + // Operands + case REF -> { + CellReference cr = new CellReference(relativeTo); + pos += cr.read(tokenData, pos); + tokenStack.push(cr); + } + case REFERR -> { + CellReferenceError cr = new CellReferenceError(); + pos += cr.read(tokenData, pos); + tokenStack.push(cr); + } + case ERR -> { + ErrorConstant ec = new ErrorConstant(); + pos += ec.read(tokenData, pos); + tokenStack.push(ec); + } + case REF_N -> { + SharedFormulaCellReference cr = new SharedFormulaCellReference(relativeTo); + pos += cr.read(tokenData, pos); + tokenStack.push(cr); + } + case REF3D -> { + CellReference3d cr = new CellReference3d(relativeTo, workbook); + pos += cr.read(tokenData, pos); + tokenStack.push(cr); + } + case AREA -> { + Area a = new Area(); + pos += a.read(tokenData, pos); + tokenStack.push(a); + } + case AREA_N -> { + SharedFormulaArea a = new SharedFormulaArea(relativeTo); + pos += a.read(tokenData, pos); + tokenStack.push(a); + } + case AREA3D -> { + Area3d a = new Area3d(workbook); + pos += a.read(tokenData, pos); + tokenStack.push(a); + } + case NAME_X -> { + Name n = new Name(); + pos += n.read(tokenData, pos); + n.setParseContext(parseContext); + tokenStack.push(n); + } + case NAME -> { + NameRange nr = new NameRange(nameTable); + pos += nr.read(tokenData, pos); + nr.setParseContext(parseContext); + tokenStack.push(nr); + } + case INTEGER -> { + IntegerValue i = new IntegerValue(); + pos += i.read(tokenData, pos); + tokenStack.push(i); + } + case DOUBLE -> { + DoubleValue d = new DoubleValue(); + pos += d.read(tokenData, pos); + tokenStack.push(d); + } + case BOOL -> { + BooleanValue bv = new BooleanValue(); + pos += bv.read(tokenData, pos); + tokenStack.push(bv); + } + case STRING -> { + StringValue sv = new StringValue(settings); + pos += sv.read(tokenData, pos); + tokenStack.push(sv); + } + case MISSING_ARG -> { + MissingArg ma = new MissingArg(); + pos += ma.read(tokenData, pos); + tokenStack.push(ma); + } - // Functions - else if (t == Token.ATTRIBUTE) - { - Attribute a = new Attribute(settings); - pos += a.read(tokenData, pos); + // Unary Operators + case UNARY_PLUS -> { + UnaryPlus up = new UnaryPlus(); + pos += up.read(tokenData, pos); + addOperator(up); + } + case UNARY_MINUS -> { + UnaryMinus um = new UnaryMinus(); + pos += um.read(tokenData, pos); + addOperator(um); + } + case PERCENT -> { + Percent p = new Percent(); + pos += p.read(tokenData, pos); + addOperator(p); + } - if (a.isSum()) - { - addOperator(a); + // Binary Operators + case SUBTRACT -> { + Subtract s = new Subtract(); + pos += s.read(tokenData, pos); + addOperator(s); } - else if (a.isIf()) - { - // Add it to a special stack for ifs - ifStack.push(a); + case ADD -> { + Add s = new Add(); + pos += s.read(tokenData, pos); + addOperator(s); + } + case MULTIPLY -> { + Multiply s = new Multiply(); + pos += s.read(tokenData, pos); + addOperator(s); + } + case DIVIDE -> { + Divide s = new Divide(); + pos += s.read(tokenData, pos); + addOperator(s); + } + case CONCAT -> { + Concatenate c = new Concatenate(); + pos += c.read(tokenData, pos); + addOperator(c); + } + case POWER -> { + Power p = new Power(); + pos += p.read(tokenData, pos); + addOperator(p); + } + case LESS_THAN -> { + LessThan lt = new LessThan(); + pos += lt.read(tokenData, pos); + addOperator(lt); + } + case LESS_EQUAL -> { + LessEqual lte = new LessEqual(); + pos += lte.read(tokenData, pos); + addOperator(lte); + } + case GREATER_THAN -> { + GreaterThan gt = new GreaterThan(); + pos += gt.read(tokenData, pos); + addOperator(gt); + } + case GREATER_EQUAL -> { + GreaterEqual gte = new GreaterEqual(); + pos += gte.read(tokenData, pos); + addOperator(gte); + } + case NOT_EQUAL -> { + NotEqual ne = new NotEqual(); + pos += ne.read(tokenData, pos); + addOperator(ne); + } + case EQUAL -> { + Equal e = new Equal(); + pos += e.read(tokenData, pos); + addOperator(e); + } + case PARENTHESIS -> { + Parenthesis p = new Parenthesis(); + pos += p.read(tokenData, pos); + addOperator(p); } - } - else if (t == Token.FUNCTION) - { - BuiltInFunction bif = new BuiltInFunction(settings); - pos += bif.read(tokenData, pos); - addOperator(bif); - } - else if (t == Token.FUNCTIONVARARG) - { - VariableArgFunction vaf = new VariableArgFunction(settings); - pos += vaf.read(tokenData, pos); - - if (vaf.getFunction() != Function.ATTRIBUTE) - { - addOperator(vaf); - } - else - { - // This is part of an IF function. Get the operands, but then - // add it to the top of the if stack - vaf.getOperands(tokenStack); - - Attribute ifattr = null; - if (ifStack.empty()) + // Functions + case ATTRIBUTE -> { + Attribute a = new Attribute(settings); + pos += a.read(tokenData, pos); + if (a.isSum()) + addOperator(a); + else if (a.isIf()) + // Add it to a special stack for ifs + ifStack.push(a); + } + case FUNCTION -> { + BuiltInFunction bif = new BuiltInFunction(settings); + pos += bif.read(tokenData, pos); + addOperator(bif); + } + case FUNCTIONVARARG -> { + VariableArgFunction vaf = new VariableArgFunction(settings); + pos += vaf.read(tokenData, pos); + if (vaf.getFunction() != Function.ATTRIBUTE) { - ifattr = new Attribute(settings); + addOperator(vaf); } else { - ifattr = (Attribute) ifStack.pop(); + // This is part of an IF function. Get the operands, but then + // add it to the top of the if stack + vaf.getOperands(tokenStack); + + Attribute ifattr = ifStack.empty() + ? new Attribute(settings) + : ifStack.pop(); + + ifattr.setIfConditions(vaf); + tokenStack.push(ifattr); } - - ifattr.setIfConditions(vaf); - tokenStack.push(ifattr); } - } - // Other things - else if (t == Token.MEM_FUNC) - { - MemFunc memFunc = new MemFunc(); - handleMemoryFunction(memFunc); - } - else if (t == Token.MEM_AREA) - { - MemArea memArea = new MemArea(); - handleMemoryFunction(memArea); + // Other things + case MEM_FUNC -> { + MemFunc memFunc = new MemFunc(); + handleMemoryFunction(memFunc); + } + case MEM_AREA -> { + MemArea memArea = new MemArea(); + handleMemoryFunction(memArea); + } } } } @@ -424,14 +360,14 @@ else if (t == Token.MEM_AREA) /** * Handles a memory function */ - private void handleMemoryFunction(SubExpression subxp) + private void handleMemoryFunction(SubExpression subxp) throws FormulaException { pos += subxp.read(tokenData, pos); // Create new tokenStack for the sub expression - Stack oldStack = tokenStack; - tokenStack = new Stack(); + Stack oldStack = tokenStack; + tokenStack = new Stack<>(); parseSubExpression(subxp.getLength()); @@ -439,12 +375,12 @@ private void handleMemoryFunction(SubExpression subxp) int i = 0; while (!tokenStack.isEmpty()) { - subexpr[i] = (ParseItem) tokenStack.pop(); + subexpr[i] = tokenStack.pop(); i++; } subxp.setSubExpression(subexpr); - + tokenStack = oldStack; tokenStack.push(subxp); } @@ -465,6 +401,7 @@ private void addOperator(Operator o) /** * Gets the formula as a string */ + @Override public String getFormula() { StringBuffer sb = new StringBuffer(); @@ -479,6 +416,7 @@ public String getFormula() * @param colAdjust the amount to add on to each relative cell reference * @param rowAdjust the amount to add on to each relative row reference */ + @Override public void adjustRelativeCellReferences(int colAdjust, int rowAdjust) { root.adjustRelativeCellReferences(colAdjust, rowAdjust); @@ -490,6 +428,7 @@ public void adjustRelativeCellReferences(int colAdjust, int rowAdjust) * * @return the bytes in RPN */ + @Override public byte[] getBytes() { return root.getBytes(); @@ -505,6 +444,7 @@ public byte[] getBytes() * @param currentSheet TRUE if this formula is on the sheet in which the * column was inserted, FALSE otherwise */ + @Override public void columnInserted(int sheetIndex, int col, boolean currentSheet) { root.columnInserted(sheetIndex, col, currentSheet); @@ -519,6 +459,7 @@ public void columnInserted(int sheetIndex, int col, boolean currentSheet) * @param currentSheet TRUE if this formula is on the sheet in which the * column was inserted, FALSE otherwise */ + @Override public void columnRemoved(int sheetIndex, int col, boolean currentSheet) { root.columnRemoved(sheetIndex, col, currentSheet); @@ -534,6 +475,7 @@ public void columnRemoved(int sheetIndex, int col, boolean currentSheet) * @param currentSheet TRUE if this formula is on the sheet in which the * column was inserted, FALSE otherwise */ + @Override public void rowInserted(int sheetIndex, int row, boolean currentSheet) { root.rowInserted(sheetIndex, row, currentSheet); @@ -549,6 +491,7 @@ public void rowInserted(int sheetIndex, int row, boolean currentSheet) * @param currentSheet TRUE if this formula is on the sheet in which the * column was inserted, FALSE otherwise */ + @Override public void rowRemoved(int sheetIndex, int row, boolean currentSheet) { root.rowRemoved(sheetIndex, row, currentSheet); @@ -560,6 +503,7 @@ public void rowRemoved(int sheetIndex, int row, boolean currentSheet) * * @return TRUE if the formula is valid import, FALSE otherwise */ + @Override public boolean handleImportedCellReferences() { root.handleImportedCellReferences(); diff --git a/src/jxl/biff/formula/UnaryOperator.java b/src/jxl/biff/formula/UnaryOperator.java index 6945c4f..b9082ae 100644 --- a/src/jxl/biff/formula/UnaryOperator.java +++ b/src/jxl/biff/formula/UnaryOperator.java @@ -26,14 +26,14 @@ */ abstract class UnaryOperator extends Operator implements ParsedThing { - /** + /** * Constructor */ public UnaryOperator() { } - /** + /** * Reads the ptg data from the array starting at the specified position * * @param data the RPN array @@ -45,14 +45,12 @@ public int read(byte[] data, int pos) return 0; } - /** + /** * Gets the operands for this operator from the stack */ - public void getOperands(Stack s) + public void getOperands(Stack s) { - ParseItem o1 = (ParseItem) s.pop(); - - add(o1); + add(s.pop()); } /** @@ -158,7 +156,7 @@ byte[] getBytes() // Add on the operator byte byte[] newdata = new byte[data.length + 1]; System.arraycopy(data, 0, newdata, 0, data.length); - newdata[data.length] = getToken().getCode(); + newdata[data.length] = getToken().getReferenceCode(); return newdata; } diff --git a/src/jxl/biff/formula/VariableArgFunction.java b/src/jxl/biff/formula/VariableArgFunction.java index 2f8fd54..a2d3e08 100644 --- a/src/jxl/biff/formula/VariableArgFunction.java +++ b/src/jxl/biff/formula/VariableArgFunction.java @@ -56,9 +56,9 @@ class VariableArgFunction extends Operator implements ParsedThing /** * The workbooks settings */ - private WorkbookSettings settings; + private final WorkbookSettings settings; - /** + /** * Constructor */ public VariableArgFunction(WorkbookSettings ws) @@ -81,7 +81,7 @@ public VariableArgFunction(Function f, int a, WorkbookSettings ws) settings = ws; } - /** + /** * Reads the ptg data from the array starting at the specified position * * @param data the RPN array @@ -104,18 +104,17 @@ public int read(byte[] data, int pos) throws FormulaException return 3; } - /** + /** * Gets the operands for this operator from the stack */ - public void getOperands(Stack s) + public void getOperands(Stack s) { // parameters are in the correct order, god damn them ParseItem[] items = new ParseItem[arguments]; for (int i = arguments - 1; i >= 0 ; i--) { - ParseItem pi = (ParseItem) s.pop(); - + ParseItem pi = s.pop(); items[i] = pi; } @@ -129,7 +128,7 @@ public void getString(StringBuffer buf) { buf.append(function.getName(settings)); buf.append('('); - + if (arguments > 0) { ParseItem[] operands = getOperands(); @@ -137,7 +136,7 @@ public void getString(StringBuffer buf) { // arguments are in the same order they were specified operands[0].getString(buf); - + for (int i = 1; i < arguments; i++) { buf.append(','); @@ -149,7 +148,7 @@ public void getString(StringBuffer buf) // arguments are stored in the reverse order to which they // were specified, so iterate through them backwards operands[arguments - 1].getString(buf); - + for (int i = arguments - 2; i >= 0 ; i--) { buf.append(','); @@ -170,12 +169,8 @@ public void getString(StringBuffer buf) */ public void adjustRelativeCellReferences(int colAdjust, int rowAdjust) { - ParseItem[] operands = getOperands(); - - for (int i = 0 ; i < operands.length ; i++) - { - operands[i].adjustRelativeCellReferences(colAdjust, rowAdjust); - } + for (ParseItem operand : getOperands()) + operand.adjustRelativeCellReferences(colAdjust, rowAdjust); } /** @@ -190,11 +185,8 @@ public void adjustRelativeCellReferences(int colAdjust, int rowAdjust) */ void columnInserted(int sheetIndex, int col, boolean currentSheet) { - ParseItem[] operands = getOperands(); - for (int i = 0 ; i < operands.length ; i++) - { - operands[i].columnInserted(sheetIndex, col, currentSheet); - } + for (ParseItem operand : getOperands()) + operand.columnInserted(sheetIndex, col, currentSheet); } /** @@ -209,11 +201,8 @@ void columnInserted(int sheetIndex, int col, boolean currentSheet) */ void columnRemoved(int sheetIndex, int col, boolean currentSheet) { - ParseItem[] operands = getOperands(); - for (int i = 0 ; i < operands.length ; i++) - { - operands[i].columnRemoved(sheetIndex, col, currentSheet); - } + for (ParseItem operand : getOperands()) + operand.columnRemoved(sheetIndex, col, currentSheet); } /** @@ -228,11 +217,8 @@ void columnRemoved(int sheetIndex, int col, boolean currentSheet) */ void rowInserted(int sheetIndex, int row, boolean currentSheet) { - ParseItem[] operands = getOperands(); - for (int i = 0 ; i < operands.length ; i++) - { - operands[i].rowInserted(sheetIndex, row, currentSheet); - } + for (ParseItem operand : getOperands()) + operand.rowInserted(sheetIndex, row, currentSheet); } /** @@ -247,11 +233,8 @@ void rowInserted(int sheetIndex, int row, boolean currentSheet) */ void rowRemoved(int sheetIndex, int row, boolean currentSheet) { - ParseItem[] operands = getOperands(); - for (int i = 0 ; i < operands.length ; i++) - { - operands[i].rowRemoved(sheetIndex, row, currentSheet); - } + for (ParseItem operand : getOperands()) + operand.rowRemoved(sheetIndex, row, currentSheet); } /** @@ -261,11 +244,8 @@ void rowRemoved(int sheetIndex, int row, boolean currentSheet) */ void handleImportedCellReferences() { - ParseItem[] operands = getOperands(); - for (int i = 0 ; i < operands.length ; i++) - { - operands[i].handleImportedCellReferences(); - } + for (ParseItem operand : getOperands()) + operand.handleImportedCellReferences(); } /** @@ -286,13 +266,10 @@ byte[] getBytes() handleSpecialCases(); // Get the data for the operands - in the correct order - ParseItem[] operands = getOperands(); byte[] data = new byte[0]; - for (int i = 0 ; i < operands.length ; i++) - { - byte[] opdata = operands[i].getBytes(); - + for (ParseItem operand : getOperands()) { + byte[] opdata = operand.getBytes(); // Grow the array byte[] newdata = new byte[data.length + opdata.length]; System.arraycopy(data, 0, newdata, 0, data.length); @@ -303,8 +280,8 @@ byte[] getBytes() // Add on the operator byte byte[] newdata = new byte[data.length + 4]; System.arraycopy(data, 0, newdata, 0, data.length); - newdata[data.length] = !useAlternateCode() ? - Token.FUNCTIONVARARG.getCode() : Token.FUNCTIONVARARG.getCode2() ; + newdata[data.length] = !useAlternateCode() ? + Token.FUNCTIONVARARG.getReferenceCode() : Token.FUNCTIONVARARG.getValueCode() ; newdata[data.length+1] = (byte) arguments; IntegerHelper.getTwoBytes(function.getCode(), newdata, data.length+2); @@ -312,7 +289,7 @@ byte[] getBytes() } /** - * Gets the precedence for this operator. Operator precedents run from + * Gets the precedence for this operator. Operator precedents run from * 1 to 5, one being the highest, 5 being the lowest * * @return the operator precedence @@ -333,7 +310,7 @@ private void handleSpecialCases() { // Get the data for the operands - in reverse order ParseItem[] operands = getOperands(); - + for (int i = operands.length - 1 ; i >= 0 ; i--) { if (operands[i] instanceof Area) @@ -344,5 +321,5 @@ private void handleSpecialCases() } } } - + diff --git a/src/jxl/common/Logger.java b/src/jxl/common/Logger.java index 7935d1c..994acc2 100644 --- a/src/jxl/common/Logger.java +++ b/src/jxl/common/Logger.java @@ -19,11 +19,11 @@ package jxl.common; -import java.security.AccessControlException; +import java.lang.reflect.InvocationTargetException; /** - * Abstract wrapper class for the logging interface of choice. - * The methods declared here are the same as those for the log4j + * Abstract wrapper class for the logging interface of choice. + * The methods declared here are the same as those for the log4j */ public abstract class Logger { @@ -35,7 +35,7 @@ public abstract class Logger /** * Factory method to return the logger */ - public static final Logger getLogger(Class cl) + public static final Logger getLogger(Class cl) { if (logger == null) { @@ -51,9 +51,7 @@ public static final Logger getLogger(Class cl) private synchronized static void initializeLogger() { if (logger != null) - { return; - } String loggerName = jxl.common.log.LoggerName.NAME; @@ -64,34 +62,16 @@ private synchronized static void initializeLogger() if (loggerName == null) { - // Get the logger name from the compiled in logger + // Get the logger name from the compiled in logger loggerName = jxl.common.log.LoggerName.NAME; } - logger = (Logger) Class.forName(loggerName).newInstance(); - } - catch(IllegalAccessException e) - { - logger = new jxl.common.log.SimpleLogger(); - logger.warn("Could not instantiate logger " + loggerName + - " using default"); - } - catch(InstantiationException e) - { - logger = new jxl.common.log.SimpleLogger(); - logger.warn("Could not instantiate logger " + loggerName + - " using default"); - } - catch (AccessControlException e) - { - logger = new jxl.common.log.SimpleLogger(); - logger.warn("Could not instantiate logger " + loggerName + - " using default"); + logger = (Logger) Class.forName(loggerName).getDeclaredConstructor().newInstance(); } - catch(ClassNotFoundException e) + catch(IllegalAccessException | InstantiationException | ClassNotFoundException | NoSuchMethodException | SecurityException | IllegalArgumentException | InvocationTargetException e) { logger = new jxl.common.log.SimpleLogger(); - logger.warn("Could not instantiate logger " + loggerName + + logger.warn("Could not instantiate logger " + loggerName + " using default"); } } @@ -156,10 +136,10 @@ protected Logger() /** * Accessor to the logger implementation */ - protected abstract Logger getLoggerImpl(Class cl); + protected abstract Logger getLoggerImpl(Class cl); /** - * Empty implementation of the suppressWarnings. Subclasses may + * Empty implementation of the suppressWarnings. Subclasses may * or may not override this method. This method is included * primarily for backwards support of the jxl.nowarnings property, and * is used only by the SimpleLogger diff --git a/src/jxl/common/log/Log4JLogger.java b/src/jxl/common/log/Log4JLogger.java index 1f943f5..0ce8673 100644 --- a/src/jxl/common/log/Log4JLogger.java +++ b/src/jxl/common/log/Log4JLogger.java @@ -19,7 +19,8 @@ package jxl.common.log; -import org.apache.log4j.Logger; +import java.util.logging.*; + /** * A logger which uses the log4j library from jakarta. Each instance @@ -33,7 +34,7 @@ public class Log4JLogger extends jxl.common.Logger private Logger log4jLogger; /** - * Default constructor. This constructor is + * Default constructor. This constructor is */ public Log4JLogger() { @@ -55,7 +56,7 @@ private Log4JLogger(Logger l) */ public void debug(Object message) { - log4jLogger.debug(message); + log4jLogger.getAnonymousLogger().log(Level.INFO, message.toString()); } /** @@ -63,7 +64,7 @@ public void debug(Object message) */ public void debug(Object message, Throwable t) { - log4jLogger.debug(message, t); + log4jLogger.getAnonymousLogger().log(Level.INFO, message.toString(), t); } /** @@ -71,7 +72,7 @@ public void debug(Object message, Throwable t) */ public void error(Object message) { - log4jLogger.error(message); + log4jLogger.getAnonymousLogger().log(Level.WARNING, message.toString()); } /** @@ -79,7 +80,7 @@ public void error(Object message) */ public void error(Object message, Throwable t) { - log4jLogger.error(message, t); + log4jLogger.getAnonymousLogger().log(Level.WARNING, message.toString(), t); } /** @@ -87,7 +88,7 @@ public void error(Object message, Throwable t) */ public void fatal(Object message) { - log4jLogger.fatal(message); + log4jLogger.getAnonymousLogger().log(Level.SEVERE, message.toString()); } /** @@ -95,7 +96,7 @@ public void fatal(Object message) */ public void fatal(Object message, Throwable t) { - log4jLogger.fatal(message,t); + log4jLogger.getAnonymousLogger().log(Level.SEVERE, message.toString(), t); } /** @@ -103,7 +104,7 @@ public void fatal(Object message, Throwable t) */ public void info(Object message) { - log4jLogger.info(message); + log4jLogger.getAnonymousLogger().log(Level.INFO, message.toString()); } /** @@ -112,7 +113,7 @@ public void info(Object message) public void info(Object message, Throwable t) { - log4jLogger.info(message, t); + log4jLogger.getAnonymousLogger().log(Level.INFO, message.toString(), t); } /** @@ -120,7 +121,7 @@ public void info(Object message, Throwable t) */ public void warn(Object message) { - log4jLogger.warn(message); + log4jLogger.getAnonymousLogger().log(Level.WARNING, message.toString()); } /** @@ -128,15 +129,14 @@ public void warn(Object message) */ public void warn(Object message, Throwable t) { - log4jLogger.warn(message, t); + log4jLogger.getAnonymousLogger().log(Level.WARNING, message.toString(), t); } /** * Accessor to the logger implementation */ - protected jxl.common.Logger getLoggerImpl(Class cl) + protected jxl.common.Logger getLoggerImpl(Class cl) { - Logger l = Logger.getLogger(cl); - return new Log4JLogger(l); + return new Log4JLogger(); } } diff --git a/src/jxl/common/log/Log4jLoggerName.java b/src/jxl/common/log/Log4jLoggerName.java deleted file mode 100644 index 9245e76..0000000 --- a/src/jxl/common/log/Log4jLoggerName.java +++ /dev/null @@ -1,30 +0,0 @@ -/********************************************************************* -* -* Copyright (C) 2003 Andrew Khan -* -* This library is free software; you can redistribute it and/or -* modify it under the terms of the GNU Lesser General Public -* License as published by the Free Software Foundation; either -* version 2.1 of the License, or (at your option) any later version. -* -* This library is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -* Lesser General Public License for more details. -* -* You should have received a copy of the GNU Lesser General Public -* License along with this library; if not, write to the Free Software -* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -***************************************************************************/ - -package jxl.common.log; - -/** - * Static structure containing the class name of the logger. This may - * be overwritten at build time if loggers other than the default, - * no-dependency logger are required - */ -public class LoggerName -{ - public final static String NAME=jxl.common.log.Log4JLogger.class.getName(); -} diff --git a/src/jxl/common/log/SimpleLogger.java b/src/jxl/common/log/SimpleLogger.java index 8e7b3f4..e5f67bb 100644 --- a/src/jxl/common/log/SimpleLogger.java +++ b/src/jxl/common/log/SimpleLogger.java @@ -154,17 +154,17 @@ public void warn(Object message, Throwable t) /** * Accessor to the logger implementation */ - protected Logger getLoggerImpl(Class c) + protected Logger getLoggerImpl(Class c) { return this; } /** * Overrides the method in the base class to suppress warnings - it can - * be set using the system property jxl.nowarnings. + * be set using the system property jxl.nowarnings. * This method was originally present in the WorkbookSettings bean, * but has been moved to the logger class. This means it is now present - * when the JVM is initialized, and subsequent to change it on + * when the JVM is initialized, and subsequent to change it on * a Workbook by Workbook basis will prove fruitless * * @param w suppression flag diff --git a/src/jxl/common/log/SimpleLoggerName.java b/src/jxl/common/log/SimpleLoggerName.java deleted file mode 100644 index 8086c11..0000000 --- a/src/jxl/common/log/SimpleLoggerName.java +++ /dev/null @@ -1,30 +0,0 @@ -/********************************************************************* -* -* Copyright (C) 2003 Andrew Khan -* -* This library is free software; you can redistribute it and/or -* modify it under the terms of the GNU Lesser General Public -* License as published by the Free Software Foundation; either -* version 2.1 of the License, or (at your option) any later version. -* -* This library is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -* Lesser General Public License for more details. -* -* You should have received a copy of the GNU Lesser General Public -* License along with this library; if not, write to the Free Software -* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -***************************************************************************/ - -package jxl.common.log; - -/** - * Static structure containing the class name of the logger. This may - * be overwritten at build time if loggers other than the default, - * no-dependency logger are required - */ -public class LoggerName -{ - public final static String NAME=jxl.common.log.SimpleLogger.class.getName(); -} diff --git a/src/jxl/demo/BiffDump.java b/src/jxl/demo/BiffDump.java index f0511b0..bd89156 100644 --- a/src/jxl/demo/BiffDump.java +++ b/src/jxl/demo/BiffDump.java @@ -20,11 +20,8 @@ package jxl.demo; -import java.io.BufferedWriter; -import java.io.FileInputStream; -import java.io.IOException; -import java.io.OutputStream; -import java.io.OutputStreamWriter; +import java.io.*; +import java.nio.file.*; import java.util.HashMap; @@ -43,7 +40,7 @@ class BiffDump private BufferedWriter writer; private BiffRecordReader reader; - private HashMap recordNames; + private HashMap recordNames; private int xfIndex; private int fontIndex; @@ -59,20 +56,20 @@ class BiffDump * @exception IOException * @exception BiffException */ - public BiffDump(java.io.File file, OutputStream os) + public BiffDump(Path file, OutputStream os) throws IOException, BiffException { writer = new BufferedWriter(new OutputStreamWriter(os)); - FileInputStream fis = new FileInputStream(file); - File f = new File(fis, new WorkbookSettings()); - reader = new BiffRecordReader(f); - - buildNameHash(); - dump(); - - writer.flush(); - writer.close(); - fis.close(); + try (InputStream fis = Files.newInputStream(file)) { + File f = new File(fis, new WorkbookSettings()); + reader = new BiffRecordReader(f); + + buildNameHash(); + dump(); + + writer.flush(); + writer.close(); + } } /** @@ -80,7 +77,7 @@ public BiffDump(java.io.File file, OutputStream os) */ private void buildNameHash() { - recordNames = new HashMap(50); + recordNames = new HashMap<>(50); recordNames.put(Type.BOF, "BOF"); recordNames.put(Type.EOF, "EOF"); @@ -204,11 +201,10 @@ private void buildNameHash() */ private void dump() throws IOException { - Record r = null; boolean cont = true; while (reader.hasNext() && cont) { - r = reader.next(); + Record r = reader.next(); cont = writeRecord(r); } } diff --git a/src/jxl/demo/Demo.java b/src/jxl/demo/Demo.java index 2630e2e..1773c1c 100644 --- a/src/jxl/demo/Demo.java +++ b/src/jxl/demo/Demo.java @@ -19,16 +19,11 @@ package jxl.demo; -import java.io.File; -import java.io.FileOutputStream; -import java.io.OutputStream; - +import java.io.*; +import java.nio.file.Paths; +import jxl.*; import jxl.common.Logger; -import jxl.Cell; -import jxl.Range; -import jxl.Workbook; - /** * The main demo class which interprets the command line switches in order * to determine how to call the demo programs @@ -230,35 +225,35 @@ else if (readwrite) } else if (formulas) { - Workbook w = Workbook.getWorkbook(new File(file)); + Workbook w = Workbook.getWorkbook(Paths.get(file)); Formulas f = new Formulas(w, System.out, encoding); w.close(); } else if (features) { - Workbook w = Workbook.getWorkbook(new File(file)); + Workbook w = Workbook.getWorkbook(Paths.get(file)); Features f = new Features(w, System.out, encoding); w.close(); } else if (escher) { - Workbook w = Workbook.getWorkbook(new File(file)); + Workbook w = Workbook.getWorkbook(Paths.get(file)); Escher f = new Escher(w, System.out, encoding); w.close(); } else if (escherdg) { - Workbook w = Workbook.getWorkbook(new File(file)); + Workbook w = Workbook.getWorkbook(Paths.get(file)); EscherDrawingGroup f = new EscherDrawingGroup(w, System.out, encoding); w.close(); } else if (biffdump) { - BiffDump bd = new BiffDump(new File(file), System.out); + BiffDump bd = new BiffDump(Paths.get(file), System.out); } else if (jxlversion) { - WriteAccess bd = new WriteAccess(new File(file)); + WriteAccess bd = new WriteAccess(Paths.get(file)); } else if (propertysets) { @@ -267,13 +262,13 @@ else if (propertysets) { os = new FileOutputStream(outputFile); } - PropertySetsReader psr = new PropertySetsReader(new File(file), + PropertySetsReader psr = new PropertySetsReader(Paths.get(file), propertySet, os); } else { - Workbook w = Workbook.getWorkbook(new File(file)); + Workbook w = Workbook.getWorkbook(Paths.get(file)); // findTest(w); diff --git a/src/jxl/demo/Formulas.java b/src/jxl/demo/Formulas.java index 0408f1b..2589953 100644 --- a/src/jxl/demo/Formulas.java +++ b/src/jxl/demo/Formulas.java @@ -48,7 +48,7 @@ public class Formulas * * @param w The workbook to interrogate * @param out The output stream to which the CSV values are written - * @param encoding The encoding used by the output stream. Null or + * @param encoding The encoding used by the output stream. Null or * unrecognized values cause the encoding to default to UTF8 * @exception java.io.IOException */ @@ -60,73 +60,61 @@ public Formulas(Workbook w, OutputStream out, String encoding) encoding = "UTF8"; } - try - { - OutputStreamWriter osw = new OutputStreamWriter(out, encoding); - BufferedWriter bw = new BufferedWriter(osw); + ArrayList parseErrors = new ArrayList<>(); + try { + try (BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(out, encoding))) { + for (int sheet = 0; sheet < w.getNumberOfSheets(); sheet++) + { + Sheet s = w.getSheet(sheet); - ArrayList parseErrors = new ArrayList(); - - for (int sheet = 0; sheet < w.getNumberOfSheets(); sheet++) - { - Sheet s = w.getSheet(sheet); + bw.write(s.getName()); + bw.newLine(); - bw.write(s.getName()); - bw.newLine(); - - Cell[] row = null; - Cell c = null; - - for (int i = 0 ; i < s.getRows() ; i++) - { - row = s.getRow(i); - for (int j = 0; j < row.length; j++) + for (int i = 0 ; i < s.getRows() ; i++) { - c = row[j]; - if (c.getType() == CellType.NUMBER_FORMULA || - c.getType() == CellType.STRING_FORMULA || - c.getType() == CellType.BOOLEAN_FORMULA || - c.getType() == CellType.DATE_FORMULA || - c.getType() == CellType.FORMULA_ERROR) - { - FormulaCell nfc = (FormulaCell) c; - StringBuffer sb = new StringBuffer(); - CellReferenceHelper.getCellReference - (c.getColumn(), c.getRow(), sb); + Cell[] row = s.getRow(i); - try + for (Cell c : row) + if (c.getType() == CellType.NUMBER_FORMULA || + c.getType() == CellType.STRING_FORMULA || + c.getType() == CellType.BOOLEAN_FORMULA || + c.getType() == CellType.DATE_FORMULA || + c.getType() == CellType.FORMULA_ERROR) { - bw.write("Formula in " + sb.toString() + - " value: " + c.getContents()); - bw.flush(); - bw.write(" formula: " + nfc.getFormula()); - bw.flush(); - bw.newLine(); - } - catch (FormulaException e) - { - bw.newLine(); - parseErrors.add(s.getName() + '!' + - sb.toString() + ": " + e.getMessage()); + FormulaCell nfc = (FormulaCell) c; + StringBuffer sb = new StringBuffer(); + CellReferenceHelper.getCellReference + (c.getColumn(), c.getRow(), sb); + + try + { + bw.write("Formula in " + sb.toString() + + " value: " + c.getContents()); + bw.flush(); + bw.write(" formula: " + nfc.getFormula()); + bw.flush(); + bw.newLine(); + } + catch (FormulaException e) + { + bw.newLine(); + parseErrors.add(s.getName() + '!' + + sb.toString() + ": " + e.getMessage()); + } } - } } } + bw.flush(); } - bw.flush(); - bw.close(); - if (parseErrors.size() > 0) + if (!parseErrors.isEmpty()) { System.err.println(); System.err.println("There were " + parseErrors.size() + " errors"); - Iterator i = parseErrors.iterator(); - while (i.hasNext()) - { - System.err.println(i.next()); - } + for (String err : parseErrors) + System.err.println(err); } } catch (UnsupportedEncodingException e) diff --git a/src/jxl/demo/PropertySetsReader.java b/src/jxl/demo/PropertySetsReader.java index e228c18..c6bc6d6 100644 --- a/src/jxl/demo/PropertySetsReader.java +++ b/src/jxl/demo/PropertySetsReader.java @@ -19,11 +19,8 @@ package jxl.demo; -import java.io.BufferedWriter; -import java.io.FileInputStream; -import java.io.IOException; -import java.io.OutputStream; -import java.io.OutputStreamWriter; +import java.io.*; +import java.nio.file.*; import jxl.WorkbookSettings; import jxl.biff.BaseCompoundFile; @@ -48,12 +45,12 @@ class PropertySetsReader * @exception IOException * @exception BiffException */ - public PropertySetsReader(java.io.File file, String propertySet, + public PropertySetsReader(Path file, String propertySet, OutputStream os) throws IOException, BiffException { writer = new BufferedWriter(new OutputStreamWriter(os)); - FileInputStream fis = new FileInputStream(file); + InputStream fis = Files.newInputStream(file); int initialFileSize = 1024*1024; // 1mb int arrayGrowSize = 1024*1024;// 1mb diff --git a/src/jxl/demo/ReadWrite.java b/src/jxl/demo/ReadWrite.java index 6cad459..1a1425f 100644 --- a/src/jxl/demo/ReadWrite.java +++ b/src/jxl/demo/ReadWrite.java @@ -19,10 +19,10 @@ package jxl.demo; -import java.io.File; import java.io.IOException; import java.net.MalformedURLException; import java.net.URL; +import java.nio.file.*; import java.util.ArrayList; import java.util.Calendar; import java.util.Date; @@ -75,32 +75,32 @@ public class ReadWrite /** * The spreadsheet to read in */ - private File inputWorkbook; + private Path inputWorkbook; /** * The spreadsheet to output */ - private File outputWorkbook; + private Path outputWorkbook; /** * Constructor - * - * @param output - * @param input + * + * @param output + * @param input */ public ReadWrite(String input, String output) { - inputWorkbook = new File(input); - outputWorkbook = new File(output); + inputWorkbook = Paths.get(input); + outputWorkbook = Paths.get(output); logger.setSuppressWarnings(Boolean.getBoolean("jxl.nowarnings")); - logger.info("Input file: " + input); + logger.info("Input file: " + input); logger.info("Output file: " + output); } /** * Reads in the inputFile and creates a writable copy of it called outputFile - * - * @exception IOException - * @exception BiffException + * + * @exception IOException + * @exception BiffException */ public void readWrite() throws IOException, BiffException, WriteException { @@ -108,30 +108,27 @@ public void readWrite() throws IOException, BiffException, WriteException Workbook w1 = Workbook.getWorkbook(inputWorkbook); logger.info("Copying..."); - WritableWorkbook w2 = Workbook.createWorkbook(outputWorkbook, w1); + try (WritableWorkbook w2 = Workbook.createWorkbook(outputWorkbook, w1)) { + if (inputWorkbook.getFileName().toString().equals("jxlrwtest.xls")) + modify(w2); - if (inputWorkbook.getName().equals("jxlrwtest.xls")) - { - modify(w2); + w2.write(); } - - w2.write(); - w2.close(); logger.info("Done"); } /** * If the inputFile was the test spreadsheet, then it modifies certain fields * of the writable copy - * - * @param w + * + * @param w */ private void modify(WritableWorkbook w) throws WriteException { logger.info("Modifying..."); WritableSheet sheet = w.getSheet("modified"); - + WritableCell cell = null; CellFormat cf = null; Label l = null; @@ -139,8 +136,8 @@ private void modify(WritableWorkbook w) throws WriteException // Change the format of cell B4 to be emboldened cell = sheet.getWritableCell(1,3); - WritableFont bold = new WritableFont(WritableFont.ARIAL, - WritableFont.DEFAULT_POINT_SIZE, + WritableFont bold = new WritableFont(WritableFont.ARIAL, + WritableFont.DEFAULT_POINT_SIZE, WritableFont.BOLD); cf = new WritableCellFormat(bold); cell.setCellFormat(cf); @@ -175,13 +172,13 @@ private void modify(WritableWorkbook w) throws WriteException cf = new WritableCellFormat(sevendps); cell.setCellFormat(cf); - + // Change cell B11 to display in the format 1e4 cell = sheet.getWritableCell(1,10); NumberFormat exp4 = new NumberFormat("0.####E0"); cf = new WritableCellFormat(exp4); cell.setCellFormat(cf); - + // Change cell B12 to be normal display cell = sheet.getWritableCell(1,11); cell.setCellFormat(WritableWorkbook.NORMAL_STYLE); @@ -224,7 +221,7 @@ private void modify(WritableWorkbook w) throws WriteException dt.setDate(d); } - // Change the value in B23 to be 6.8. This should recalculate the + // Change the value in B23 to be 6.8. This should recalculate the // formula cell = sheet.getWritableCell(1,22); if (cell.getType() == CellType.NUMBER) @@ -278,11 +275,11 @@ private void modify(WritableWorkbook w) throws WriteException } else if (wh.getColumn() == 1 && wh.getRow() == 40) { - wh.setFile(new File("../jexcelapi/docs/overview-summary.html")); + wh.setFile(Paths.get("../jexcelapi/docs/overview-summary.html")); } else if (wh.getColumn() == 1 && wh.getRow() == 41) { - wh.setFile(new File("d:/home/jexcelapi/docs/jxl/package-summary.html")); + wh.setFile(Paths.get("d:/home/jexcelapi/docs/jxl/package-summary.html")); } else if (wh.getColumn() == 1 && wh.getRow() == 44) { @@ -290,7 +287,7 @@ else if (wh.getColumn() == 1 && wh.getRow() == 44) sheet.removeHyperlink(wh); } } - + // Change the background of cell F31 from blue to red WritableCell c = sheet.getWritableCell(5,30); WritableCellFormat newFormat = new WritableCellFormat(c.getCellFormat()); @@ -304,7 +301,7 @@ else if (wh.getColumn() == 1 && wh.getRow() == 44) // Modify the chart data Number n = (Number) sheet.getWritableCell(0, 70); n.setValue(9); - + n = (Number) sheet.getWritableCell(0, 71); n.setValue(10); @@ -375,7 +372,7 @@ else if (wh.getColumn() == 1 && wh.getRow() == 44) label = new Label(0,101, "A brand new formula"); sheet.addCell(label); - + Formula formula = new Formula(1, 101, "SUM(B94:B96)"); sheet.addCell(formula); @@ -389,8 +386,8 @@ else if (wh.getColumn() == 1 && wh.getRow() == 44) WritableImage wi = sheet.getImage(1); sheet.removeImage(wi); - wi = new WritableImage(1, 116, 2, 9, - new File("resources/littlemoretonhall.png")); + wi = new WritableImage(1, 116, 2, 9, + Paths.get("resources/littlemoretonhall.png")); sheet.addImage(wi); // Add a list data validations @@ -399,7 +396,7 @@ else if (wh.getColumn() == 1 && wh.getRow() == 44) Blank b = new Blank(1, 151); wcf = new WritableCellFeatures(); - ArrayList al = new ArrayList(); + ArrayList al = new ArrayList<>(); al.add("The Fellowship of the Ring"); al.add("The Two Towers"); al.add("The Return of the King"); @@ -435,7 +432,7 @@ else if (wh.getColumn() == 1 && wh.getRow() == 44) Range r = wcf.getSharedDataValidationRange(); Cell botright = r.getBottomRight(); sheet.removeSharedDataValidation(cell); - al = new ArrayList(); + al = new ArrayList<>(); al.add("Stanley Featherstonehaugh Ukridge"); al.add("Major Plank"); al.add("Earl of Ickenham"); @@ -445,7 +442,7 @@ else if (wh.getColumn() == 1 && wh.getRow() == 44) al.add("Bingo Little"); wcf.setDataValidationList(al); cell.setCellFeatures(wcf); - sheet.applySharedDataValidation(cell, + sheet.applySharedDataValidation(cell, botright.getColumn() - cell.getColumn(), 1);//botright.getRow() - cell.getRow()); } diff --git a/src/jxl/demo/Write.java b/src/jxl/demo/Write.java index 8796d2c..8d47be3 100644 --- a/src/jxl/demo/Write.java +++ b/src/jxl/demo/Write.java @@ -19,51 +19,20 @@ package jxl.demo; -import java.io.File; -import java.io.IOException; -import java.net.MalformedURLException; -import java.net.URL; +import java.io.*; +import java.net.*; +import java.nio.file.*; import java.text.SimpleDateFormat; -import java.util.ArrayList; -import java.util.Calendar; -import java.util.Date; -import java.util.Locale; -import java.util.TimeZone; - -import jxl.CellReferenceHelper; -import jxl.CellView; -import jxl.HeaderFooter; -import jxl.Range; -import jxl.Workbook; -import jxl.WorkbookSettings; +import java.util.*; +import jxl.*; +import jxl.format.*; import jxl.format.Alignment; import jxl.format.Border; import jxl.format.BorderLineStyle; import jxl.format.Colour; -import jxl.format.Orientation; -import jxl.format.PageOrder; -import jxl.format.PageOrientation; -import jxl.format.PaperSize; -import jxl.format.ScriptStyle; -import jxl.format.UnderlineStyle; -import jxl.write.Blank; +import jxl.write.*; import jxl.write.Boolean; -import jxl.write.DateFormat; -import jxl.write.DateFormats; -import jxl.write.DateTime; -import jxl.write.Formula; -import jxl.write.Label; import jxl.write.Number; -import jxl.write.NumberFormat; -import jxl.write.NumberFormats; -import jxl.write.WritableCellFeatures; -import jxl.write.WritableCellFormat; -import jxl.write.WritableFont; -import jxl.write.WritableHyperlink; -import jxl.write.WritableImage; -import jxl.write.WritableSheet; -import jxl.write.WritableWorkbook; -import jxl.write.WriteException; /** @@ -85,8 +54,8 @@ public class Write /** * Constructor - * - * @param fn + * + * @param fn */ public Write(String fn) { @@ -95,15 +64,15 @@ public Write(String fn) /** * Uses the JExcelAPI to create a spreadsheet - * + * * @exception IOException * @exception WriteException */ public void write() throws IOException, WriteException { WorkbookSettings ws = new WorkbookSettings(); - ws.setLocale(new Locale("en", "EN")); - workbook = Workbook.createWorkbook(new File(filename), ws); + ws.setLocale(Locale.of("en", "EN")); + workbook = Workbook.createWorkbook(Paths.get(filename), ws); WritableSheet s2 = workbook.createSheet("Number Formats", 0); @@ -138,11 +107,11 @@ public void write() throws IOException, WriteException workbook.write(); workbook.close(); } - + /** * Writes out a sheet containing the various numerical formats - * - * @param s + * + * @param s */ private void writeNumberFormatSheet(WritableSheet s) throws WriteException { @@ -185,7 +154,7 @@ private void writeNumberFormatSheet(WritableSheet s) throws WriteException n = new Number(2,2,-3.1415926535, cf2); s.addCell(n); - l = new Label(0,3,"+/- Pi - custom 3dps", + l = new Label(0,3,"+/- Pi - custom 3dps", wrappedText); s.addCell(l); @@ -197,7 +166,7 @@ private void writeNumberFormatSheet(WritableSheet s) throws WriteException n = new Number(2,3,-3.1415926535, dp3cell); s.addCell(n); - l = new Label(0,4,"+/- Pi - custom &3.14", + l = new Label(0,4,"+/- Pi - custom &3.14", wrappedText); s.addCell(l); @@ -209,7 +178,7 @@ private void writeNumberFormatSheet(WritableSheet s) throws WriteException n = new Number(2,4,-3.1415926535, pounddp2cell); s.addCell(n); - l = new Label(0,5,"+/- Pi - custom Text #.### Text", + l = new Label(0,5,"+/- Pi - custom Text #.### Text", wrappedText); s.addCell(l); @@ -306,7 +275,7 @@ private void writeNumberFormatSheet(WritableSheet s) throws WriteException WritableCellFormat cuspercentf = new WritableCellFormat(cuspercent); n = new Number(5, 9, 3.14159265, cuspercentf); s.addCell(n); - + // Booleans l = new Label(0,10, "Boolean - TRUE"); @@ -330,8 +299,8 @@ private void writeNumberFormatSheet(WritableSheet s) throws WriteException l = new Label(4, 21, "UK Pound"); s.addCell(l); - NumberFormat poundCurrency = - new NumberFormat(NumberFormat.CURRENCY_POUND + " #,###.00", + NumberFormat poundCurrency = + new NumberFormat(NumberFormat.CURRENCY_POUND + " #,###.00", NumberFormat.COMPLEX_FORMAT); WritableCellFormat poundFormat = new WritableCellFormat(poundCurrency); n = new Number(5, 21, 12345, poundFormat); @@ -339,40 +308,40 @@ private void writeNumberFormatSheet(WritableSheet s) throws WriteException l = new Label(4, 22, "Euro 1"); s.addCell(l); - NumberFormat euroPrefixCurrency = - new NumberFormat(NumberFormat.CURRENCY_EURO_PREFIX + " #,###.00", + NumberFormat euroPrefixCurrency = + new NumberFormat(NumberFormat.CURRENCY_EURO_PREFIX + " #,###.00", NumberFormat.COMPLEX_FORMAT); - WritableCellFormat euroPrefixFormat = + WritableCellFormat euroPrefixFormat = new WritableCellFormat(euroPrefixCurrency); n = new Number(5, 22, 12345, euroPrefixFormat); s.addCell(n); l = new Label(4, 23, "Euro 2"); s.addCell(l); - NumberFormat euroSuffixCurrency = - new NumberFormat("#,###.00" + NumberFormat.CURRENCY_EURO_SUFFIX, + NumberFormat euroSuffixCurrency = + new NumberFormat("#,###.00" + NumberFormat.CURRENCY_EURO_SUFFIX, NumberFormat.COMPLEX_FORMAT); - WritableCellFormat euroSuffixFormat = + WritableCellFormat euroSuffixFormat = new WritableCellFormat(euroSuffixCurrency); n = new Number(5, 23, 12345, euroSuffixFormat); s.addCell(n); l = new Label(4, 24, "Dollar"); s.addCell(l); - NumberFormat dollarCurrency = - new NumberFormat(NumberFormat.CURRENCY_DOLLAR + " #,###.00", + NumberFormat dollarCurrency = + new NumberFormat(NumberFormat.CURRENCY_DOLLAR + " #,###.00", NumberFormat.COMPLEX_FORMAT); - WritableCellFormat dollarFormat = + WritableCellFormat dollarFormat = new WritableCellFormat(dollarCurrency); n = new Number(5, 24, 12345, dollarFormat); s.addCell(n); l = new Label(4, 25, "Japanese Yen"); s.addCell(l); - NumberFormat japaneseYenCurrency = - new NumberFormat(NumberFormat.CURRENCY_JAPANESE_YEN + " #,###.00", + NumberFormat japaneseYenCurrency = + new NumberFormat(NumberFormat.CURRENCY_JAPANESE_YEN + " #,###.00", NumberFormat.COMPLEX_FORMAT); - WritableCellFormat japaneseYenFormat = + WritableCellFormat japaneseYenFormat = new WritableCellFormat(japaneseYenCurrency); n = new Number(5, 25, 12345, japaneseYenFormat); s.addCell(n); @@ -383,7 +352,7 @@ private void writeNumberFormatSheet(WritableSheet s) throws WriteException l = new Label(4,32, "One digit fraction format", wrappedText); s.addCell(l); - WritableCellFormat fraction1digitformat = + WritableCellFormat fraction1digitformat = new WritableCellFormat(NumberFormats.FRACTION_ONE_DIGIT); n = new Number(5, 32, 3.18279, fraction1digitformat); s.addCell(n); @@ -391,7 +360,7 @@ private void writeNumberFormatSheet(WritableSheet s) throws WriteException l = new Label(4,33, "Two digit fraction format", wrappedText); s.addCell(l); - WritableCellFormat fraction2digitformat = + WritableCellFormat fraction2digitformat = new WritableCellFormat(NumberFormats.FRACTION_TWO_DIGITS); n = new Number(5, 33, 3.18279, fraction2digitformat); s.addCell(n); @@ -399,10 +368,10 @@ private void writeNumberFormatSheet(WritableSheet s) throws WriteException l = new Label(4,34, "Three digit fraction format (improper)", wrappedText); s.addCell(l); - NumberFormat fraction3digit1 = - new NumberFormat(NumberFormat.FRACTION_THREE_DIGITS, + NumberFormat fraction3digit1 = + new NumberFormat(NumberFormat.FRACTION_THREE_DIGITS, NumberFormat.COMPLEX_FORMAT); - WritableCellFormat fraction3digitformat1 = + WritableCellFormat fraction3digitformat1 = new WritableCellFormat(fraction3digit1); n = new Number(5, 34, 3.18927, fraction3digitformat1); s.addCell(n); @@ -410,14 +379,14 @@ private void writeNumberFormatSheet(WritableSheet s) throws WriteException l = new Label(4,35, "Three digit fraction format (proper)", wrappedText); s.addCell(l); - NumberFormat fraction3digit2 = - new NumberFormat("# " + NumberFormat.FRACTION_THREE_DIGITS, + NumberFormat fraction3digit2 = + new NumberFormat("# " + NumberFormat.FRACTION_THREE_DIGITS, NumberFormat.COMPLEX_FORMAT); - WritableCellFormat fraction3digitformat2 = + WritableCellFormat fraction3digitformat2 = new WritableCellFormat(fraction3digit2); n = new Number(5, 35, 3.18927, fraction3digitformat2); s.addCell(n); - + // Lots of numbers for (int row = 0; row < 100; row++) { @@ -441,8 +410,8 @@ private void writeNumberFormatSheet(WritableSheet s) throws WriteException /** * Adds cells to the specified sheet which test the various date formats - * - * @param s + * + * @param s */ private void writeDateFormatSheet(WritableSheet s) throws WriteException { @@ -498,7 +467,7 @@ private void writeDateFormatSheet(WritableSheet s) throws WriteException wrappedText); s.addCell(l); - l = new Label(0,1,"Built in formats", + l = new Label(0,1,"Built in formats", wrappedText); s.addCell(l); @@ -569,7 +538,7 @@ private void writeDateFormatSheet(WritableSheet s) throws WriteException dt = new DateTime(3, 3, date, cf1, DateTime.GMT); s.addCell(dt); - + df = new DateFormat("hh:mm"); cf1 = new WritableCellFormat(df); l = new Label(2, 4, "hh:mm"); @@ -734,8 +703,8 @@ private void writeDateFormatSheet(WritableSheet s) throws WriteException /** * Adds cells to the specified sheet which test the various label formatting * styles, such as different fonts, different sizes and bold, underline etc. - * - * @param s1 + * + * @param s1 */ private void writeLabelFormatSheet(WritableSheet s1) throws WriteException { @@ -830,7 +799,7 @@ private void writeLabelFormatSheet(WritableSheet s1) throws WriteException s1.addCell(lr); WritableFont arial10ptUnderline = new WritableFont - (WritableFont.ARIAL, + (WritableFont.ARIAL, WritableFont.DEFAULT_POINT_SIZE, WritableFont.NO_BOLD, false, @@ -841,7 +810,7 @@ private void writeLabelFormatSheet(WritableSheet s1) throws WriteException s1.addCell(lr); WritableFont arial10ptDoubleUnderline = new WritableFont - (WritableFont.ARIAL, + (WritableFont.ARIAL, WritableFont.DEFAULT_POINT_SIZE, WritableFont.NO_BOLD, false, @@ -852,7 +821,7 @@ private void writeLabelFormatSheet(WritableSheet s1) throws WriteException s1.addCell(lr); WritableFont arial10ptSingleAcc = new WritableFont - (WritableFont.ARIAL, + (WritableFont.ARIAL, WritableFont.DEFAULT_POINT_SIZE, WritableFont.NO_BOLD, false, @@ -863,7 +832,7 @@ private void writeLabelFormatSheet(WritableSheet s1) throws WriteException s1.addCell(lr); WritableFont arial10ptDoubleAcc = new WritableFont - (WritableFont.ARIAL, + (WritableFont.ARIAL, WritableFont.DEFAULT_POINT_SIZE, WritableFont.NO_BOLD, false, @@ -892,7 +861,7 @@ private void writeLabelFormatSheet(WritableSheet s1) throws WriteException UnderlineStyle.SINGLE); WritableCellFormat arialBoldItalicUnderline = new WritableCellFormat (arial18ptBoldItalicUnderline); - lr = new Label(6,13, "Arial 18 Bold Italic Underline", + lr = new Label(6,13, "Arial 18 Bold Italic Underline", arialBoldItalicUnderline); s1.addCell(lr); @@ -928,7 +897,7 @@ private void writeLabelFormatSheet(WritableSheet s1) throws WriteException lr = new Label(0, 17, "Colours"); s1.addCell(lr); - WritableFont red = new WritableFont(WritableFont.ARIAL, + WritableFont red = new WritableFont(WritableFont.ARIAL, WritableFont.DEFAULT_POINT_SIZE, WritableFont.NO_BOLD, false, @@ -938,7 +907,7 @@ private void writeLabelFormatSheet(WritableSheet s1) throws WriteException lr = new Label(2, 17, "Red", redFormat); s1.addCell(lr); - WritableFont blue = new WritableFont(WritableFont.ARIAL, + WritableFont blue = new WritableFont(WritableFont.ARIAL, WritableFont.DEFAULT_POINT_SIZE, WritableFont.NO_BOLD, false, @@ -954,14 +923,14 @@ private void writeLabelFormatSheet(WritableSheet s1) throws WriteException limeFormat.setWrap(true); lr = new Label(4, 18, "Modified palette - was lime, now red", limeFormat); s1.addCell(lr); - + WritableCellFormat greyBackground = new WritableCellFormat(); greyBackground.setWrap(true); greyBackground.setBackground(Colour.GRAY_50); lr = new Label(2, 19, "Grey background", greyBackground); s1.addCell(lr); - WritableFont yellow = new WritableFont(WritableFont.ARIAL, + WritableFont yellow = new WritableFont(WritableFont.ARIAL, WritableFont.DEFAULT_POINT_SIZE, WritableFont.NO_BOLD, false, @@ -986,10 +955,10 @@ private void writeLabelFormatSheet(WritableSheet s1) throws WriteException lr = new Label(2, 22, null); s1.addCell(lr); - lr = new Label(0, 24, + lr = new Label(0, 24, "A very long label, more than 255 characters\012" + "Rejoice O shores\012" + - "Sing O bells\012" + + "Sing O bells\012" + "But I with mournful tread\012" + "Walk the deck my captain lies\012" + "Fallen cold and dead\012"+ @@ -997,21 +966,21 @@ private void writeLabelFormatSheet(WritableSheet s1) throws WriteException "With a shower of rain. We stopped in the Colonnade\012" + "A very long label, more than 255 characters\012" + "Rejoice O shores\012" + - "Sing O bells\012" + + "Sing O bells\012" + "But I with mournful tread\012" + "Walk the deck my captain lies\012" + "Fallen cold and dead\012"+ "Summer surprised, coming over the Starnbergersee\012" + "With a shower of rain. We stopped in the Colonnade\012" + "A very long label, more than 255 characters\012" + "Rejoice O shores\012" + - "Sing O bells\012" + + "Sing O bells\012" + "But I with mournful tread\012" + "Walk the deck my captain lies\012" + "Fallen cold and dead\012"+ "Summer surprised, coming over the Starnbergersee\012" + "With a shower of rain. We stopped in the Colonnade\012" + "A very long label, more than 255 characters\012" + "Rejoice O shores\012" + - "Sing O bells\012" + + "Sing O bells\012" + "But I with mournful tread\012" + "Walk the deck my captain lies\012" + "Fallen cold and dead\012"+ @@ -1025,7 +994,7 @@ private void writeLabelFormatSheet(WritableSheet s1) throws WriteException vertical.setOrientation(Orientation.VERTICAL); lr = new Label(0, 26, "Vertical orientation", vertical); s1.addCell(lr); - + WritableCellFormat plus_90 = new WritableCellFormat(); plus_90.setOrientation(Orientation.PLUS_90); @@ -1051,7 +1020,7 @@ private void writeLabelFormatSheet(WritableSheet s1) throws WriteException { Label l = new Label(0, 30, "Hyperlink to home page"); s1.addCell(l); - + URL url = new URL("http://www.andykhan.com/jexcelapi"); WritableHyperlink wh = new WritableHyperlink(0, 30, 8, 31, url); s1.addHyperlink(wh); @@ -1063,19 +1032,19 @@ private void writeLabelFormatSheet(WritableSheet s1) throws WriteException l = new Label(4, 2, "File hyperlink to documentation"); s1.addCell(l); - File file = new File("../jexcelapi/docs/index.html"); - wh = new WritableHyperlink(0, 32, 8, 32, file, + Path file = Paths.get("../jexcelapi/docs/index.html"); + wh = new WritableHyperlink(0, 32, 8, 32, file, "JExcelApi Documentation"); s1.addHyperlink(wh); // Add a hyperlink to another cell on this sheet - wh = new WritableHyperlink(0, 34, 8, 34, + wh = new WritableHyperlink(0, 34, 8, 34, "Link to another cell", s1, 0, 180, 1, 181); s1.addHyperlink(wh); - file = new File("\\\\localhost\\file.txt"); + file = Paths.get("\\\\localhost\\file.txt"); wh = new WritableHyperlink(0, 36, 8, 36, file); s1.addHyperlink(wh); @@ -1125,12 +1094,12 @@ private void writeLabelFormatSheet(WritableSheet s1) throws WriteException Label l5 = new Label(7, 17, "this label won't appear"); s1.addCell(l5); - s1.mergeCells(5, 16, 8, 18); + s1.mergeCells(5, 16, 8, 18); s1.mergeCells(5, 19, 6, 24); s1.mergeCells(6, 18, 10, 19); */ - + WritableFont courier10ptFont = new WritableFont(WritableFont.COURIER, 10); WritableCellFormat courier10pt = new WritableCellFormat(courier10ptFont); l = new Label(0, 49, "Courier fonts", courier10pt); @@ -1141,7 +1110,7 @@ private void writeLabelFormatSheet(WritableSheet s1) throws WriteException l = new Label(0, 50, "Tahoma fonts", tahoma12pt); s1.addCell(l); - WritableFont.FontName wingdingsFont = + WritableFont.FontName wingdingsFont = WritableFont.createFont("Wingdings 2"); WritableFont wingdings210ptFont = new WritableFont(wingdingsFont, 10); WritableCellFormat wingdings210pt = new WritableCellFormat @@ -1154,7 +1123,7 @@ private void writeLabelFormatSheet(WritableSheet s1) throws WriteException l = new Label(3,53, "Shrunk to fit", shrinkToFit); s1.addCell(l); - l = new Label(3,55, "Some long wrapped text in a merged cell", + l = new Label(3,55, "Some long wrapped text in a merged cell", arial12format); s1.addCell(l); s1.mergeCells(3,55,4,55); @@ -1165,7 +1134,7 @@ private void writeLabelFormatSheet(WritableSheet s1) throws WriteException l.setCellFeatures(cellFeatures); s1.addCell(l); - l = new Label(0, 59, + l = new Label(0, 59, "A cell with a long comment"); cellFeatures = new WritableCellFeatures(); cellFeatures.setComment("a very long cell comment indeed that won't " + @@ -1182,10 +1151,10 @@ private void writeLabelFormatSheet(WritableSheet s1) throws WriteException l = new Label(0, 63, "Data validation: list"); s1.addCell(l); - + Blank b = new Blank(1,63); cellFeatures = new WritableCellFeatures(); - ArrayList al = new ArrayList(); + ArrayList al = new ArrayList<>(); al.add("bagpuss"); al.add("clangers"); al.add("ivor the engine"); @@ -1196,7 +1165,7 @@ private void writeLabelFormatSheet(WritableSheet s1) throws WriteException l = new Label(0, 64, "Data validation: number > 4.5"); s1.addCell(l); - + b = new Blank(1,64); cellFeatures = new WritableCellFeatures(); cellFeatures.setNumberValidation(4.5, WritableCellFeatures.GREATER_THAN); @@ -1205,7 +1174,7 @@ private void writeLabelFormatSheet(WritableSheet s1) throws WriteException l = new Label(0, 65, "Data validation: named range"); s1.addCell(l); - + l = new Label(4, 65, "tiger"); s1.addCell(l); l = new Label(5, 65, "sword"); @@ -1232,7 +1201,7 @@ private void writeLabelFormatSheet(WritableSheet s1) throws WriteException l = new Label(0, 66, "Block of cells B67-F71 with data validation"); s1.addCell(l); - al = new ArrayList(); + al = new ArrayList<>(); al.add("Achilles"); al.add("Agamemnon"); al.add("Hector"); @@ -1261,7 +1230,7 @@ private void writeLabelFormatSheet(WritableSheet s1) throws WriteException /** * Adds cells to the specified sheet which test the various border * styles - * + * * @param s */ private void writeBordersSheet(WritableSheet s) throws WriteException @@ -1272,7 +1241,7 @@ private void writeBordersSheet(WritableSheet s) throws WriteException s.setColumnView(2, 15); s.setColumnView(4, 15); WritableCellFormat thickLeft = new WritableCellFormat(); - thickLeft.setBorder(Border.LEFT, BorderLineStyle.THICK); + thickLeft.setBorder(Border.LEFT, BorderLineStyle.THICK); Label lr = new Label(1,0, "Thick left", thickLeft); s.addCell(lr); @@ -1413,7 +1382,7 @@ private void writeLabelsSheet(WritableSheet ws) throws WriteException // Add some labels to column 5 for autosizing Label l6 = new Label(5, 2, "A column for autosizing", wcf2); ws.addCell(l6); - l6 = new Label(5, 4, "Another label, longer this time and " + + l6 = new Label(5, 4, "Another label, longer this time and " + "in a different font"); ws.addCell(l6); @@ -1430,13 +1399,13 @@ private void writeFormulaSheet(WritableSheet ws) throws WriteException // Add some cells to manipulate Number nc = new Number(0,0,15); ws.addCell(nc); - + nc = new Number(0,1,16); ws.addCell(nc); nc = new Number(0,2,10); ws.addCell(nc); - + nc = new Number(0,3, 12); ws.addCell(nc); @@ -1642,7 +1611,7 @@ private void writeFormulaSheet(WritableSheet ws) throws WriteException l = new Label(3, 35, "IF(((F1=\"Not Found\")*(F2=\"Not Found\")*(F3=\"\")*(F4=\"\")*(F5=\"\")),1,0)"); ws.addCell(l); - f = new Formula(2, 36, + f = new Formula(2, 36, "HYPERLINK(\"http://www.amazon.co.uk/exec/obidos/ASIN/0571058086qid=1099836249/sr=1-3/ref=sr_1_11_3/202-6017285-1620664\", \"Long hyperlink\")"); ws.addCell(f); @@ -1694,7 +1663,7 @@ private void writeFormulaSheet(WritableSheet ws) throws WriteException ws.addCell(f); l = new Label(3, 45, "formulavalue+5"); ws.addCell(l); - + // Errors /* f = new Formula(2, 25, "PLOP(15)"); // unknown function @@ -1723,14 +1692,14 @@ private void writeImageSheet(WritableSheet ws) throws WriteException ws.addCell(l); WritableImage wi = new WritableImage - (0, 3, 5, 7, new File("resources/wealdanddownland.png")); + (0, 3, 5, 7, Paths.get("resources/wealdanddownland.png")); ws.addImage(wi); l = new Label(0, 12, "Merchant Adventurers Hall, York"); ws.addCell(l); - wi = new WritableImage(5, 12, 4, 10, - new File("resources/merchantadventurers.png")); + wi = new WritableImage(5, 12, 4, 10, + Paths.get("resources/merchantadventurers.png")); ws.addImage(wi); // An unsupported file type diff --git a/src/jxl/demo/WriteAccess.java b/src/jxl/demo/WriteAccess.java index dd975e8..c3a8d43 100644 --- a/src/jxl/demo/WriteAccess.java +++ b/src/jxl/demo/WriteAccess.java @@ -19,8 +19,8 @@ package jxl.demo; -import java.io.FileInputStream; -import java.io.IOException; +import java.io.*; +import java.nio.file.*; import jxl.WorkbookSettings; import jxl.biff.StringHelper; @@ -37,11 +37,11 @@ class WriteAccess { private BiffRecordReader reader; - public WriteAccess(java.io.File file) + public WriteAccess(Path file) throws IOException, BiffException { WorkbookSettings ws = new WorkbookSettings(); - FileInputStream fis = new FileInputStream(file); + InputStream fis = Files.newInputStream(file); File f = new File(fis, ws); reader = new BiffRecordReader(f); diff --git a/src/jxl/format/PaperSize.java b/src/jxl/format/PaperSize.java old mode 100644 new mode 100755 diff --git a/src/jxl/read/biff/BOFRecord.java b/src/jxl/read/biff/BOFRecord.java index 23cb577..4c934db 100644 --- a/src/jxl/read/biff/BOFRecord.java +++ b/src/jxl/read/biff/BOFRecord.java @@ -19,10 +19,10 @@ package jxl.read.biff; +import jxl.biff.*; +import static jxl.biff.Version.*; import jxl.common.Logger; -import jxl.biff.IntegerHelper; -import jxl.biff.RecordData; /** * A Beginning Of File record, found at the commencement of all substreams @@ -102,6 +102,29 @@ public boolean isBiff7() return version == Biff7; } + public Version getVersion() { + switch (version) { + case Biff7: return BIFF7; + case Biff8: return BIFF8; + default: return BIFF5; + } + + /* + * Note of the IBM Client Access Data Transfer about the differences + * of BIFF5 and BIFF7 since there is no difference in the BOF-Version + * information: + * + * BIFF7 is an extension of the BIFF5 file format supported on earlier + * versions of data transfer. BIFF5 and BIFF7 support have both been + * expanded to allow multiple sheets to be written to an Excel workbook. + * To take advantage of this new functionality, select BIFF5 or BIFF7 + * for the PC file type, then select Details and then Create extra + * sheets when first sheet overflows. Only 16,384 records are allowed + * per sheet and overflow sheets are created as necessary. This option + * is turned OFF by default for the BIFF5 file type. The option is + * turned ON by default for the BIFF7 file type. + */ + } /** * Interrogates this substream to see if it represents the commencement of diff --git a/src/jxl/read/biff/BooleanFormulaRecord.java b/src/jxl/read/biff/BooleanFormulaRecord.java index 5ffcaa4..10a8d8c 100644 --- a/src/jxl/read/biff/BooleanFormulaRecord.java +++ b/src/jxl/read/biff/BooleanFormulaRecord.java @@ -108,8 +108,7 @@ public boolean getValue() */ public String getContents() { - // return Boolean.toString(value) - only available in 1.4 or later - return (new Boolean(value)).toString(); + return Boolean.toString(value); } /** diff --git a/src/jxl/read/biff/BooleanRecord.java b/src/jxl/read/biff/BooleanRecord.java index 0fbdb5c..81b66ef 100644 --- a/src/jxl/read/biff/BooleanRecord.java +++ b/src/jxl/read/biff/BooleanRecord.java @@ -97,8 +97,7 @@ public String getContents() { Assert.verify(!isError()); - // return Boolean.toString(value) - only available in 1.4 or later - return (new Boolean(value)).toString(); + return Boolean.toString(value); } /** diff --git a/src/jxl/read/biff/BoundsheetRecord.java b/src/jxl/read/biff/BoundsheetRecord.java index 1286eb0..1b976bd 100644 --- a/src/jxl/read/biff/BoundsheetRecord.java +++ b/src/jxl/read/biff/BoundsheetRecord.java @@ -32,23 +32,23 @@ class BoundsheetRecord extends RecordData /** * The offset into the sheet */ - private int offset; + private final int offset; /** * The type of sheet this is */ - private byte typeFlag; + private final byte typeFlag; /** * The visibility flag */ - private byte visibilityFlag; + private final byte visibilityFlag; /** * The length of the worksheet name */ - private int length; + private final int length; /** * The worksheet name */ - private String name; + private final String name; /** * Dummy indicators for overloading the constructor @@ -83,7 +83,7 @@ public BoundsheetRecord(Record t, WorkbookSettings s) // little endian Unicode encoding byte[] bytes = new byte[length * 2]; System.arraycopy(data, 8, bytes, 0, length * 2); - name = StringHelper.getUnicodeString(bytes, length, 0); + name = StringHelper.getUnicodeString(bytes, 0, length); } } diff --git a/src/jxl/read/biff/CompoundFile.java b/src/jxl/read/biff/CompoundFile.java index 22fc543..616db74 100644 --- a/src/jxl/read/biff/CompoundFile.java +++ b/src/jxl/read/biff/CompoundFile.java @@ -79,18 +79,18 @@ public final class CompoundFile extends BaseCompoundFile /** * The chain of blocks which comprise the big block depot */ - private int[] bigBlockDepotBlocks; + private final int[] bigBlockDepotBlocks; /** * The list of property sets */ - private ArrayList propertySets; + private final ArrayList propertySets; /** * The workbook settings */ - private WorkbookSettings settings; + private final WorkbookSettings settings; - /** + /** * The property storage root entry */ private PropertyStorage rootEntryPropertyStorage; @@ -117,7 +117,7 @@ public CompoundFile(byte[] d, WorkbookSettings ws) throws BiffException } } - propertySets = new ArrayList(); + propertySets = new ArrayList<>(); numBigBlockDepotBlocks = IntegerHelper.getInt (data[NUM_BIG_BLOCK_DEPOT_BLOCKS_POS], data[NUM_BIG_BLOCK_DEPOT_BLOCKS_POS + 1], @@ -252,9 +252,9 @@ private void readSmallBlockDepot() throws BiffException sbdBlock = bigBlockChain[sbdBlock]; } - if (blockCount > bigBlockChain.length) + if (blockCount > bigBlockChain.length) { - // Attempted to read more blocks than the block chain contains entries + // Attempted to read more blocks than the block chain contains entries // for. This indicates a loop in the chain throw new BiffException(BiffException.corruptFileFormat); } @@ -281,14 +281,14 @@ private void readPropertySets() if (ps.type == ROOT_ENTRY_PS_TYPE) { ps.name = ROOT_ENTRY_NAME; - logger.warn("Property storage name for " + ps.type + + logger.warn("Property storage name for " + ps.type + " is empty - setting to " + ROOT_ENTRY_NAME); - } + } else { if (ps.size != 0) { - logger.warn("Property storage type " + ps.type + + logger.warn("Property storage type " + ps.type + " is non-empty and has no associated name"); } } @@ -303,7 +303,7 @@ private void readPropertySets() if (rootEntryPropertyStorage == null) { - rootEntryPropertyStorage = (PropertyStorage) propertySets.get(0); + rootEntryPropertyStorage = propertySets.get(0); } } @@ -316,7 +316,7 @@ private void readPropertySets() */ public byte[] getStream(String streamName) throws BiffException { - PropertyStorage ps = findPropertyStorage(streamName, + PropertyStorage ps = findPropertyStorage(streamName, rootEntryPropertyStorage); // Property set can't be found from the direct hierarchy, so just @@ -361,7 +361,7 @@ public byte[] getStream(int psIndex) throws BiffException } /** - * Recursively searches the property storages in hierarchy order + * Recursively searches the property storages in hierarchy order * for the appropriate name. This is the public version which is * invoked from the writable version * when copying a sheet with addition property sets. @@ -372,10 +372,10 @@ public PropertyStorage findPropertyStorage(String name) } /** - * Recursively searches the property storages in hierarchy order + * Recursively searches the property storages in hierarchy order * for the appropriate name. */ - private PropertyStorage findPropertyStorage(String name, + private PropertyStorage findPropertyStorage(String name, PropertyStorage base) { if (base.child == -1) @@ -398,7 +398,7 @@ private PropertyStorage findPropertyStorage(String name, if (prev.name.equalsIgnoreCase(name)) { return prev; - } + } } // Find the next property storages on the same level @@ -409,7 +409,7 @@ private PropertyStorage findPropertyStorage(String name, if (next.name.equalsIgnoreCase(name)) { return next; - } + } } return findPropertyStorage(name, child); @@ -426,20 +426,16 @@ private PropertyStorage getPropertyStorage(String name) throws BiffException { // Find the workbook property - Iterator i = propertySets.iterator(); boolean found = false; boolean multiple = false; PropertyStorage ps = null; - while (i.hasNext()) - { - PropertyStorage ps2 = (PropertyStorage) i.next(); + for (PropertyStorage ps2 : propertySets) if (ps2.name.equalsIgnoreCase(name)) { - multiple = found == true ? true : false; + multiple = found; found = true; ps = ps2; } - } if (multiple) { @@ -461,7 +457,7 @@ private PropertyStorage getPropertyStorage(String name) */ private PropertyStorage getPropertyStorage(int index) { - return (PropertyStorage) propertySets.get(index); + return propertySets.get(index); } /** @@ -537,9 +533,9 @@ private byte[] getSmallBlockStream(PropertyStorage ps) } } - if (blockCount > smallBlockChain.length) + if (blockCount > smallBlockChain.length) { - // Attempted to read more blocks than the block chain contains entries + // Attempted to read more blocks than the block chain contains entries // for. This indicates a loop in the chain throw new BiffException(BiffException.corruptFileFormat); } @@ -577,9 +573,9 @@ private byte[] readData(int bl) throws BiffException block = bigBlockChain[block]; } - if (blockCount > bigBlockChain.length) + if (blockCount > bigBlockChain.length) { - // Attempted to read more blocks than the block chain contains entries + // Attempted to read more blocks than the block chain contains entries // for. This indicates a loop in the chain throw new BiffException(BiffException.corruptFileFormat); } @@ -597,7 +593,7 @@ public int getNumberOfPropertySets() } /** - * Gets the property set. Invoked when copying worksheets with macros. + * Gets the property set. Invoked when copying worksheets with macros. * Simply calls the private counterpart * * @param ps the property set name diff --git a/src/jxl/read/biff/DateFormulaRecord.java b/src/jxl/read/biff/DateFormulaRecord.java index d7c8fb6..cbcb3c7 100644 --- a/src/jxl/read/biff/DateFormulaRecord.java +++ b/src/jxl/read/biff/DateFormulaRecord.java @@ -45,17 +45,17 @@ class DateFormulaRecord extends DateRecord /** * A handle to the class needed to access external sheets */ - private ExternalSheet externalSheet; + private final ExternalSheet externalSheet; /** * A handle to the name table */ - private WorkbookMethods nameTable; + private final WorkbookMethods nameTable; /** * The raw data */ - private byte[] data; + private final byte[] data; /** * Constructs this object from the raw data @@ -83,6 +83,7 @@ public DateFormulaRecord(NumberFormulaRecord t, FormattingRecords fr, * * @return The cell type */ + @Override public CellType getType() { return CellType.DATE_FORMULA; @@ -94,6 +95,7 @@ public CellType getType() * * @return the raw record data */ + @Override public byte[] getFormulaData() throws FormulaException { if (!getSheet().getWorkbookBof().isBiff8()) @@ -111,6 +113,7 @@ public byte[] getFormulaData() throws FormulaException * @return the formula as an excel string * @exception FormulaException */ + @Override public String getFormula() throws FormulaException { // Note that the standard information was lopped off by the NumberFormula diff --git a/src/jxl/read/biff/DateRecord.java b/src/jxl/read/biff/DateRecord.java index d189ec3..72febc3 100644 --- a/src/jxl/read/biff/DateRecord.java +++ b/src/jxl/read/biff/DateRecord.java @@ -21,8 +21,8 @@ import java.text.DateFormat; import java.text.SimpleDateFormat; -import java.util.Date; -import java.util.TimeZone; +import java.time.*; +import java.util.*; import jxl.common.Assert; import jxl.common.Logger; @@ -179,10 +179,6 @@ public DateRecord(NumberCell num, numValue += 1; } - // Get rid of any timezone adjustments - we are not interested - // in automatic adjustments - format.setTimeZone(gmtZone); - // Convert this to the number of days since 01 Jan 1970 int offsetDays = nf ? utcOffsetDays1904 : utcOffsetDays; double utcDays = numValue - offsetDays; @@ -192,7 +188,11 @@ public DateRecord(NumberCell num, // to a rounding feature of Excel (contributed by Jurgen long utcValue = Math.round(utcDays * secondsInADay) * msInASecond; - date = new Date(utcValue); + // Get the current calender, strip timezone information + Date d = new Date(utcValue); + + LocalDateTime ldt = LocalDateTime.ofInstant(d.toInstant(), ZoneOffset.UTC); + date = Date.from(ldt.atZone(ZoneId.systemDefault()).toInstant()); } /** diff --git a/src/jxl/read/biff/ExternalNameRecord.java b/src/jxl/read/biff/ExternalNameRecord.java index 73cba40..3b5a84b 100644 --- a/src/jxl/read/biff/ExternalNameRecord.java +++ b/src/jxl/read/biff/ExternalNameRecord.java @@ -76,7 +76,7 @@ public class ExternalNameRecord extends RecordData if (unicode) { - name = StringHelper.getUnicodeString(data, length, 8); + name = StringHelper.getUnicodeString(data, 8, length); } else { diff --git a/src/jxl/read/biff/File.java b/src/jxl/read/biff/File.java index bfc7dc5..1aa708b 100644 --- a/src/jxl/read/biff/File.java +++ b/src/jxl/read/biff/File.java @@ -19,7 +19,6 @@ package jxl.read.biff; -import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.InterruptedIOException; diff --git a/src/jxl/read/biff/FooterRecord.java b/src/jxl/read/biff/FooterRecord.java index 05da0d9..89f766c 100644 --- a/src/jxl/read/biff/FooterRecord.java +++ b/src/jxl/read/biff/FooterRecord.java @@ -46,28 +46,11 @@ private static class Biff7 {}; * @param t the record data * @param ws the workbook settings */ - FooterRecord(Record t, WorkbookSettings ws) + FooterRecord(Record t) { super(t); - byte[] data = getRecord().getData(); - - if (data.length == 0) - { - return; - } - - int chars = IntegerHelper.getInt(data[0], data[1]); - - boolean unicode = data[2] == 1; - - if (unicode) - { - footer = StringHelper.getUnicodeString(data, chars, 3); - } - else - { - footer = StringHelper.getString(data, chars, 3, ws); - } + if (t.getData().length > 0) + footer = StringHelper.readBiff8String(t.getData()); } /** diff --git a/src/jxl/read/biff/FormulaRecord.java b/src/jxl/read/biff/FormulaRecord.java index 5494dbc..4f913dd 100644 --- a/src/jxl/read/biff/FormulaRecord.java +++ b/src/jxl/read/biff/FormulaRecord.java @@ -35,15 +35,11 @@ */ class FormulaRecord extends CellValue { - /** - * The logger - */ - private static Logger logger = Logger.getLogger(FormulaRecord.class); /** * The "real" formula record - will be either a string a or a number */ - private CellValue formula; + private final CellValue formula; /** * Flag to indicate whether this is a shared formula @@ -77,11 +73,12 @@ public FormulaRecord(Record t, ExternalSheet es, WorkbookMethods nt, SheetImpl si, - WorkbookSettings ws) + WorkbookSettings ws, + boolean isBiff8) { super(t, fr, si); - byte[] data = getRecord().getData(); + byte[] data = t.getData(); shared = false; @@ -95,13 +92,13 @@ public FormulaRecord(Record t, { // It is a shared string formula formula = new SharedStringFormulaRecord - (t, excelFile, fr, es, nt, si, ws); + (t, excelFile, fr, es, nt, si); } else if (data[6] == 3 && data[12] == -1 && data[13] == -1) { // We have a string which evaluates to null formula = new SharedStringFormulaRecord - (t, excelFile, fr, es, nt, si, + (t, excelFile, fr, es, nt, si, SharedStringFormulaRecord.EMPTY_STRING); } else if (data[6] == 2 && @@ -110,14 +107,14 @@ else if (data[6] == 2 && { // The cell is in error int errorCode = data[8]; - formula = new SharedErrorFormulaRecord(t, excelFile, errorCode, + formula = new SharedErrorFormulaRecord(t, excelFile, errorCode, fr, es, nt, si); } else if (data[6] == 1 && data[12] == -1 && data[13] == -1) { - boolean value = data[8] == 1 ? true : false; + boolean value = data[8] == 1; formula = new SharedBooleanFormulaRecord (t, excelFile, value, fr, es, nt, si); } @@ -139,7 +136,9 @@ else if (data[6] == 1 && if (data[6] == 0 && data[12] == -1 && data[13] == -1) { // we have a string - formula = new StringFormulaRecord(t, excelFile, fr, es, nt, si, ws); + formula = isBiff8 + ? new StringFormulaRecordBiff8(t, excelFile, fr, es, nt, si) + : new StringFormulaRecordBiff7(t, excelFile, fr, es, nt, si, ws); } else if (data[6] == 1 && data[12] == -1 && @@ -159,7 +158,9 @@ else if (data[6] == 2 && else if (data[6] == 3 && data[12] == -1 && data[13] == -1) { // we have a string which evaluates to null - formula = new StringFormulaRecord(t, fr, es, nt, si); + formula = isBiff8 + ? new StringFormulaRecordBiff8(t, fr, es, nt, si) + : new StringFormulaRecordBiff7(t, fr, es, nt, si); } else { @@ -190,10 +191,11 @@ public FormulaRecord(Record t, WorkbookMethods nt, IgnoreSharedFormula i, SheetImpl si, - WorkbookSettings ws) + WorkbookSettings ws, + boolean isBiff8) { super(t, fr, si); - byte[] data = getRecord().getData(); + byte[] data = t.getData(); shared = false; @@ -202,7 +204,9 @@ public FormulaRecord(Record t, if (data[6] == 0 && data[12] == -1 && data[13] == -1) { // we have a string - formula = new StringFormulaRecord(t, excelFile, fr, es, nt, si, ws); + formula = isBiff8 + ? new StringFormulaRecordBiff8(t, excelFile, fr, es, nt, si) + : new StringFormulaRecordBiff7(t, excelFile, fr, es, nt, si, ws); } else if (data[6] == 1 && data[12] == -1 && @@ -231,6 +235,7 @@ else if (data[6] == 2 && * * @return The numerical value of the formula as a string */ + @Override public String getContents() { Assert.verify(false); @@ -242,6 +247,7 @@ public String getContents() * * @return The cell type */ + @Override public CellType getType() { Assert.verify(false); diff --git a/src/jxl/read/biff/HeaderRecord.java b/src/jxl/read/biff/HeaderRecord.java index 835e3f0..4d0504b 100644 --- a/src/jxl/read/biff/HeaderRecord.java +++ b/src/jxl/read/biff/HeaderRecord.java @@ -53,28 +53,11 @@ private static class Biff7 {}; * @param t the record data * @param ws the workbook settings */ - HeaderRecord(Record t, WorkbookSettings ws) + HeaderRecord(Record t) { super(t); - byte[] data = getRecord().getData(); - - if (data.length == 0) - { - return; - } - - int chars = IntegerHelper.getInt(data[0], data[1]); - - boolean unicode = data[2] == 1; - - if (unicode) - { - header = StringHelper.getUnicodeString(data, chars, 3); - } - else - { - header = StringHelper.getString(data, chars, 3, ws); - } + if (t.getData().length > 0) + header = StringHelper.readBiff8String(t.getData()); } /** diff --git a/src/jxl/read/biff/HorizontalPageBreaksRecord.java b/src/jxl/read/biff/HorizontalPageBreaksRecord.java index fef60b9..872397f 100644 --- a/src/jxl/read/biff/HorizontalPageBreaksRecord.java +++ b/src/jxl/read/biff/HorizontalPageBreaksRecord.java @@ -19,33 +19,30 @@ package jxl.read.biff; -import jxl.common.Logger; - -import jxl.biff.IntegerHelper; -import jxl.biff.RecordData; +import java.util.*; +import java.util.stream.Collectors; +import jxl.biff.*; /** * Contains the cell dimensions of this worksheet */ -class HorizontalPageBreaksRecord extends RecordData -{ - /** - * The logger - */ - private final Logger logger = Logger.getLogger - (HorizontalPageBreaksRecord.class); +public class HorizontalPageBreaksRecord extends RecordData implements IHorizontalPageBreaks { /** * The row page breaks */ - private int[] rowBreaks; + private final List rowBreaks = new ArrayList<>(); /** * Dummy indicators for overloading the constructor */ private static class Biff7 {}; - public static Biff7 biff7 = new Biff7(); + public final static Biff7 biff7 = new Biff7(); + public HorizontalPageBreaksRecord() { + super(Type.HORIZONTALPAGEBREAKS); + } + /** * Constructs the dimensions from the raw data * @@ -56,14 +53,15 @@ public HorizontalPageBreaksRecord(Record t) super(t); byte[] data = t.getData(); - int numbreaks = IntegerHelper.getInt(data[0], data[1]); int pos = 2; - rowBreaks = new int[numbreaks]; for (int i = 0; i < numbreaks; i++) { - rowBreaks[i] = IntegerHelper.getInt(data[pos], data[pos + 1]); + rowBreaks.add(new RowIndex( + IntegerHelper.getInt(data[pos], data[pos + 1]), + IntegerHelper.getInt(data[pos + 2], data[pos + 3]), + IntegerHelper.getInt(data[pos + 4], data[pos + 5]))); pos += 6; } } @@ -81,10 +79,12 @@ public HorizontalPageBreaksRecord(Record t, Biff7 biff7) byte[] data = t.getData(); int numbreaks = IntegerHelper.getInt(data[0], data[1]); int pos = 2; - rowBreaks = new int[numbreaks]; for (int i = 0; i < numbreaks; i++) { - rowBreaks[i] = IntegerHelper.getInt(data[pos], data[pos + 1]); + rowBreaks.add(new RowIndex( + IntegerHelper.getInt(data[pos], data[pos + 1]), + 0, + 0xffff)); pos += 2; } } @@ -94,15 +94,12 @@ public HorizontalPageBreaksRecord(Record t, Biff7 biff7) * * @return the row breaks on the current sheet */ - public int[] getRowBreaks() + @Override + public List getRowBreaks() { - return rowBreaks; + return rowBreaks.stream() + .map(RowIndex::getFirstRowBelowBreak) + .collect(Collectors.toList()); } + } - - - - - - - diff --git a/src/jxl/read/biff/HyperlinkRecord.java b/src/jxl/read/biff/HyperlinkRecord.java index 7b1d214..d12edb7 100644 --- a/src/jxl/read/biff/HyperlinkRecord.java +++ b/src/jxl/read/biff/HyperlinkRecord.java @@ -19,21 +19,12 @@ package jxl.read.biff; -import java.io.File; -import java.net.MalformedURLException; -import java.net.URL; - -import jxl.common.Logger; - +import java.net.*; +import java.nio.file.*; +import jxl.*; import jxl.CellReferenceHelper; -import jxl.Hyperlink; -import jxl.Range; -import jxl.Sheet; -import jxl.WorkbookSettings; -import jxl.biff.IntegerHelper; -import jxl.biff.RecordData; -import jxl.biff.SheetRangeImpl; -import jxl.biff.StringHelper; +import jxl.biff.*; +import jxl.common.Logger; /** * A number record. This is stored as 8 bytes, as opposed to the @@ -71,7 +62,7 @@ public class HyperlinkRecord extends RecordData implements Hyperlink /** * The local file referred to by this hyperlink */ - private File file; + private Path file; /** * The location in this workbook referred to by this hyperlink @@ -188,8 +179,8 @@ else if ((options & 0x08) != 0) data[startpos + 2], data[startpos + 3]); - urlString = StringHelper.getUnicodeString(data, bytes / 2 - 1, - startpos + 4); + urlString = StringHelper.getUnicodeString(data, + startpos + 4, bytes / 2 - 1); url = new URL(urlString); } catch (MalformedURLException e) @@ -198,7 +189,7 @@ else if ((options & 0x08) != 0) try { linkType = fileLink; - file = new File(urlString); + file = Paths.get(urlString); } catch (Exception e3) { @@ -263,19 +254,19 @@ else if (linkType == fileLink) sb.append(fileName); - file = new File(sb.toString()); + file = Paths.get(sb.toString()); } catch (Throwable e) { logger.warn("Exception when parsing file " + e.getClass().getName() + "."); - file = new File("."); + file = Paths.get("."); } } else if (linkType == workbookLink) { int chars = IntegerHelper.getInt(data[32], data[33], data[34], data[35]); - location = StringHelper.getUnicodeString(data, chars - 1, 36); + location = StringHelper.getUnicodeString(data, 36, chars - 1); } else { @@ -370,7 +361,7 @@ public URL getURL() * * @return the file, or NULL if this hyperlink is not a file */ - public File getFile() + public Path getFile() { return file; } diff --git a/src/jxl/read/biff/IHorizontalPageBreaks.java b/src/jxl/read/biff/IHorizontalPageBreaks.java new file mode 100644 index 0000000..25c977e --- /dev/null +++ b/src/jxl/read/biff/IHorizontalPageBreaks.java @@ -0,0 +1,56 @@ +package jxl.read.biff; + +import java.util.List; + +/** + * created 2015-03-04 + * @author Jan Schlößin + */ +public interface IHorizontalPageBreaks { + + public static class RowIndex { + private int firstRowBelowBreak; + private final int firstColumn; + private final int lastColumn; + + public RowIndex(int firstRowBelowBreak, int firstColumn, int lastColumn) { + this.firstRowBelowBreak = firstRowBelowBreak; + this.firstColumn = firstColumn; + this.lastColumn = lastColumn; + } + + public int getFirstRowBelowBreak() { + return firstRowBelowBreak; + } + + public void setFirstRowBelowBreak(int firstRowBelowBreak) { + this.firstRowBelowBreak = firstRowBelowBreak; + } + + public int getFirstColumn() { + return firstColumn; + } + + public int getLastColumn() { + return lastColumn; + } + + public RowIndex withFirstRowBelowBreak(int i) { + return new RowIndex(i, firstColumn, lastColumn); + } + + @Override + public String toString() { + return "RowBreaks: {" + firstRowBelowBreak + ", first=" + firstColumn + ", last=" + lastColumn + '}'; + } + + } + + /** + * Gets the row breaks + * + * @return the row breaks on the current sheet + */ + List getRowBreaks(); + +} diff --git a/src/jxl/read/biff/IVerticalPageBreaks.java b/src/jxl/read/biff/IVerticalPageBreaks.java new file mode 100644 index 0000000..e631c9a --- /dev/null +++ b/src/jxl/read/biff/IVerticalPageBreaks.java @@ -0,0 +1,51 @@ +package jxl.read.biff; + +import java.util.List; + +/** + * created 2015-03-04 + * @author Jan Schlößin + */ +public interface IVerticalPageBreaks { + + public static class ColumnIndex { + private final int firstColumnFollowingBreak; + private final int firstRow; + private final int lastRow; + + public ColumnIndex(int firstRowBelowBreak, int firstRow, int lastRow) { + this.firstColumnFollowingBreak = firstRowBelowBreak; + this.firstRow = firstRow; + this.lastRow = lastRow; + } + + public int getFirstColumnFollowingBreak() { + return firstColumnFollowingBreak; + } + + public int getFirstRow() { + return firstRow; + } + + public int getLastRow() { + return lastRow; + } + + public ColumnIndex withFirstColumnFollowingBreak(int i) { + return new ColumnIndex(i, firstRow, lastRow); + } + + @Override + public String toString() { + return "ColumnBreaks: {" + firstColumnFollowingBreak + ", first=" + firstRow + ", last=" + lastRow + '}'; + } + } + + /** + * Gets the row breaks + * + * @return the row breaks on the current sheet + */ + List getColumnBreaks(); + +} diff --git a/src/jxl/read/biff/LabelRecord.java b/src/jxl/read/biff/LabelRecord.java index 6aceda3..fb3c328 100644 --- a/src/jxl/read/biff/LabelRecord.java +++ b/src/jxl/read/biff/LabelRecord.java @@ -31,15 +31,11 @@ */ class LabelRecord extends CellValue implements LabelCell { - /** - * The length of the label in characters - */ - private int length; /** * The label */ - private String string; + private final String string; /** * Dummy indicators for overloading the constructor @@ -50,43 +46,33 @@ private static class Biff7 {}; /** * Constructs this object from the raw data * - * @param t the raw data + * @param r the raw data * @param fr the formatting records * @param si the sheet * @param ws the workbook settings */ - public LabelRecord(Record t, FormattingRecords fr, - SheetImpl si, WorkbookSettings ws) + public LabelRecord(Record r, FormattingRecords fr, SheetImpl si) { - super(t, fr, si); - byte[] data = getRecord().getData(); - length = IntegerHelper.getInt(data[6], data[7]); - - if (data[8] == 0x0) - { - string = StringHelper.getString(data, length, 9, ws); - } - else - { - string = StringHelper.getUnicodeString(data, length, 9); - } + super(r, fr, si); + byte[] data = r.getData(); + string = StringHelper.readBiff8String(data, 6); } /** * Constructs this object from the raw data * - * @param t the raw data + * @param r the raw data * @param fr the formatting records * @param si the sheet * @param ws the workbook settings * @param dummy dummy overload to indicate a biff 7 workbook */ - public LabelRecord(Record t, FormattingRecords fr, SheetImpl si, + public LabelRecord(Record r, FormattingRecords fr, SheetImpl si, WorkbookSettings ws, Biff7 dummy) { - super(t, fr, si); - byte[] data = getRecord().getData(); - length = IntegerHelper.getInt(data[6], data[7]); + super(r, fr, si); + byte[] data = r.getData(); + int length = IntegerHelper.getInt(data[6], data[7]); string = StringHelper.getString(data, length, 8, ws); } @@ -96,6 +82,7 @@ public LabelRecord(Record t, FormattingRecords fr, SheetImpl si, * * @return the label */ + @Override public String getString() { return string; @@ -106,6 +93,7 @@ public String getString() * * @return the label */ + @Override public String getContents() { return string; @@ -116,6 +104,7 @@ public String getContents() * * @return the cell type */ + @Override public CellType getType() { return CellType.LABEL; diff --git a/src/jxl/read/biff/MergedCellsRecord.java b/src/jxl/read/biff/MergedCellsRecord.java index 580c288..e4b9a72 100644 --- a/src/jxl/read/biff/MergedCellsRecord.java +++ b/src/jxl/read/biff/MergedCellsRecord.java @@ -19,6 +19,7 @@ package jxl.read.biff; +import java.util.*; import jxl.Range; import jxl.Sheet; import jxl.biff.IntegerHelper; @@ -33,7 +34,7 @@ public class MergedCellsRecord extends RecordData /** * The ranges of the cells merged on this sheet */ - private Range[] ranges; + private final List ranges; /** * Constructs this object from the raw data @@ -48,27 +49,22 @@ public class MergedCellsRecord extends RecordData byte[] data = getRecord().getData(); int numRanges = IntegerHelper.getInt(data[0], data[1]); - - ranges = new Range[numRanges]; - - int pos = 2; - int firstRow = 0; - int lastRow = 0; - int firstCol = 0; - int lastCol = 0; - + Range rangesArray[] = new Range[numRanges]; + int pos = 2; for (int i = 0; i < numRanges; i++) { - firstRow = IntegerHelper.getInt(data[pos], data[pos + 1]); - lastRow = IntegerHelper.getInt(data[pos + 2], data[pos + 3]); - firstCol = IntegerHelper.getInt(data[pos + 4], data[pos + 5]); - lastCol = IntegerHelper.getInt(data[pos + 6], data[pos + 7]); + int firstRow = IntegerHelper.getInt(data[pos], data[pos + 1]); + int lastRow = IntegerHelper.getInt(data[pos + 2], data[pos + 3]); + int firstCol = IntegerHelper.getInt(data[pos + 4], data[pos + 5]); + int lastCol = IntegerHelper.getInt(data[pos + 6], data[pos + 7]); - ranges[i] = new SheetRangeImpl(s, firstCol, firstRow, + rangesArray[i] = new SheetRangeImpl(s, firstCol, firstRow, lastCol, lastRow); pos += 8; } + + ranges = List.of(rangesArray); } /** @@ -76,7 +72,7 @@ public class MergedCellsRecord extends RecordData * * @return the ranges of cells which have been merged */ - public Range[] getRanges() + public List getRanges() { return ranges; } diff --git a/src/jxl/read/biff/MulBlankCell.java b/src/jxl/read/biff/MulBlankCell.java index 981d058..a04e23d 100644 --- a/src/jxl/read/biff/MulBlankCell.java +++ b/src/jxl/read/biff/MulBlankCell.java @@ -19,11 +19,9 @@ package jxl.read.biff; +import jxl.*; import jxl.common.Logger; -import jxl.Cell; -import jxl.CellFeatures; -import jxl.CellType; import jxl.biff.FormattingRecords; import jxl.format.CellFormat; @@ -100,6 +98,19 @@ public MulBlankCell(int r, int c, initialized = false; } + public MulBlankCell(CellCoordinate coord, + int xfi, + FormattingRecords fr, + SheetImpl si) + { + row = coord.getRow(); + column = coord.getColumn(); + xfIndex = xfi; + formattingRecords = fr; + sheet = si; + initialized = false; + } + /** * Accessor for the row * diff --git a/src/jxl/read/biff/NameRecord.java b/src/jxl/read/biff/NameRecord.java index dff4aef..695211b 100644 --- a/src/jxl/read/biff/NameRecord.java +++ b/src/jxl/read/biff/NameRecord.java @@ -19,16 +19,10 @@ package jxl.read.biff; -import java.util.ArrayList; - -import jxl.common.Assert; -import jxl.common.Logger; - +import java.util.*; import jxl.WorkbookSettings; -import jxl.biff.BuiltInName; -import jxl.biff.IntegerHelper; -import jxl.biff.RecordData; -import jxl.biff.StringHelper; +import jxl.biff.*; +import jxl.common.*; /** * Holds an excel name record, and the details of the cells/ranges it refers @@ -36,82 +30,81 @@ */ public class NameRecord extends RecordData { + /** + * Dummy indicators for overloading the constructor + */ + private static class Biff7 {}; + public static Biff7 biff7 = new Biff7(); + /** * The logger */ private static Logger logger = Logger.getLogger(NameRecord.class); + // Constants which refer to the name type + private static final int commandMacro = 0xc; + private static final int builtIn = 0x20; + + // Constants which refer to the parse tokens after the string + private static final int cellReference = 0x3a; + private static final int areaReference = 0x3b; + private static final int subExpression = 0x29; + private static final int union = 0x10; + /** * The name */ private String name; - + /** * The built in name */ private BuiltInName builtInName; - + /** * The 0-based index in the name table */ private int index; - /** + /** * The 0-based index sheet reference for a record name * 0 is for a global reference */ private int sheetRef = 0; - + /** * Indicates whether this is a biff8 name record. Used during copying */ private boolean isbiff8; - - /** - * Dummy indicators for overloading the constructor - */ - private static class Biff7 {}; - public static Biff7 biff7 = new Biff7(); - - // Constants which refer to the name type - private static final int commandMacro = 0xc; - private static final int builtIn = 0x20; - - // Constants which refer to the parse tokens after the string - private static final int cellReference = 0x3a; - private static final int areaReference = 0x3b; - private static final int subExpression = 0x29; - private static final int union = 0x10; - + /** * A nested class to hold range information */ - public class NameRange - { + public class NameRange { /** * The first column */ - private int columnFirst; + private final int columnFirst; /** * The first row */ - private int rowFirst; + private final int rowFirst; /** * The last column */ - private int columnLast; + private final int columnLast; /** * The last row */ - private int rowLast; + private final int rowLast; /** * The first sheet */ - private int externalSheet; + private final int externalSheet; /** * Constructor @@ -122,8 +115,7 @@ public class NameRange * @param c2 the last column * @param r2 the last row */ - NameRange(int s1, int c1, int r1, int c2, int r2) - { + NameRange(int s1, int c1, int r1, int c2, int r2) { columnFirst = c1; rowFirst = r1; columnLast = c2; @@ -136,8 +128,7 @@ public class NameRange * * @return the index of the first column */ - public int getFirstColumn() - { + public int getFirstColumn() { return columnFirst; } @@ -146,8 +137,7 @@ public int getFirstColumn() * * @return the index of the first row */ - public int getFirstRow() - { + public int getFirstRow() { return rowFirst; } @@ -156,8 +146,7 @@ public int getFirstRow() * * @return the index of the last column */ - public int getLastColumn() - { + public int getLastColumn() { return columnLast; } @@ -166,8 +155,7 @@ public int getLastColumn() * * @return the index of the last row */ - public int getLastRow() - { + public int getLastRow() { return rowLast; } @@ -176,8 +164,7 @@ public int getLastRow() * * @return the index of the external sheet */ - public int getExternalSheet() - { + public int getExternalSheet() { return externalSheet; } } @@ -185,7 +172,7 @@ public int getExternalSheet() /** * The ranges referenced by this name */ - private ArrayList ranges; + private final List ranges = new ArrayList<>(); /** * Constructs this object from the raw data @@ -194,40 +181,34 @@ public int getExternalSheet() * @param ws the workbook settings * @param ind the index in the name table */ - NameRecord(Record t, WorkbookSettings ws, int ind) - { + NameRecord(Record t, WorkbookSettings ws, int ind) { super(t); index = ind; isbiff8 = true; - try - { - ranges = new ArrayList(); - + try { byte[] data = getRecord().getData(); int option = IntegerHelper.getInt(data[0], data[1]); int length = data[3]; + int sizeOfFormula = data[4]; sheetRef = IntegerHelper.getInt(data[8],data[9]); if ((option & builtIn) != 0) - { builtInName = BuiltInName.getBuiltInName(data[15]); - } else - { name = StringHelper.getString(data, length, 15, ws); - } if ((option & commandMacro) != 0) - { // This is a command macro, so it has no cell references return; - } + + if (sizeOfFormula == 0) +// logger.warn("This name has no cell references: " + name); + return; int pos = length + 15; - if (data[pos] == cellReference) - { + if (data[pos] == cellReference) { int sheet = IntegerHelper.getInt(data[pos + 1], data[pos + 2]); int row = IntegerHelper.getInt(data[pos + 3], data[pos + 4]); int columnMask = IntegerHelper.getInt(data[pos + 5], data[pos + 6]); @@ -238,107 +219,71 @@ public int getExternalSheet() NameRange r = new NameRange(sheet, column, row, column, row); ranges.add(r); - } - else if (data[pos] == areaReference) - { - int sheet1 = 0; - int r1 = 0; - int columnMask = 0; - int c1 = 0; - int r2 = 0; - int c2 = 0; - NameRange range = null; - - while (pos < data.length) - { - sheet1 = IntegerHelper.getInt(data[pos + 1], data[pos + 2]); - r1 = IntegerHelper.getInt(data[pos + 3], data[pos + 4]); - r2 = IntegerHelper.getInt(data[pos + 5], data[pos + 6]); - - columnMask = IntegerHelper.getInt(data[pos + 7], data[pos + 8]); - c1 = columnMask & 0xff; + } else if (data[pos] == areaReference) { + while (pos < data.length) { + int sheet1 = IntegerHelper.getInt(data[pos + 1], data[pos + 2]); + int r1 = IntegerHelper.getInt(data[pos + 3], data[pos + 4]); + int r2 = IntegerHelper.getInt(data[pos + 5], data[pos + 6]); + + int columnMask = IntegerHelper.getInt(data[pos + 7], data[pos + 8]); + int c1 = columnMask & 0xff; // Check that we are not dealing with offsets Assert.verify((columnMask & 0xc0000) == 0); columnMask = IntegerHelper.getInt(data[pos + 9], data[pos + 10]); - c2 = columnMask & 0xff; + int c2 = columnMask & 0xff; // Check that we are not dealing with offsets Assert.verify((columnMask & 0xc0000) == 0); - range = new NameRange(sheet1, c1, r1, c2, r2); - ranges.add(range); + ranges.add(new NameRange(sheet1, c1, r1, c2, r2)); pos += 11; } - } - else if (data[pos] == subExpression) - { - int sheet1 = 0; - int r1 = 0; - int columnMask = 0; - int c1 = 0; - int r2 = 0; - int c2 = 0; - NameRange range = null; - + } else if (data[pos] == subExpression) { // Consume unnecessary parsed tokens if (pos < data.length && data[pos] != cellReference && - data[pos] != areaReference) - { + data[pos] != areaReference) { if (data[pos] == subExpression) - { pos += 3; - } else if (data[pos] == union) - { pos += 1; - } } - while (pos < data.length) - { - sheet1 = IntegerHelper.getInt(data[pos + 1], data[pos + 2]); - r1 = IntegerHelper.getInt(data[pos + 3], data[pos + 4]); - r2 = IntegerHelper.getInt(data[pos + 5], data[pos + 6]); + while (pos < data.length) { + int sheet1 = IntegerHelper.getInt(data[pos + 1], data[pos + 2]); + int r1 = IntegerHelper.getInt(data[pos + 3], data[pos + 4]); + int r2 = IntegerHelper.getInt(data[pos + 5], data[pos + 6]); - columnMask = IntegerHelper.getInt(data[pos + 7], data[pos + 8]); - c1 = columnMask & 0xff; + int columnMask = IntegerHelper.getInt(data[pos + 7], data[pos + 8]); + int c1 = columnMask & 0xff; // Check that we are not dealing with offsets Assert.verify((columnMask & 0xc0000) == 0); columnMask = IntegerHelper.getInt(data[pos + 9], data[pos + 10]); - c2 = columnMask & 0xff; + int c2 = columnMask & 0xff; // Check that we are not dealing with offsets Assert.verify((columnMask & 0xc0000) == 0); - range = new NameRange(sheet1, c1, r1, c2, r2); - ranges.add(range); + ranges.add(new NameRange(sheet1, c1, r1, c2, r2)); pos += 11; // Consume unnecessary parsed tokens if (pos < data.length && data[pos] != cellReference && - data[pos] != areaReference) - { + data[pos] != areaReference) { if (data[pos] == subExpression) - { pos += 3; - } else if (data[pos] == union) - { pos += 1; - } } } - } - else - { + } else { String n = name != null ? name : builtInName.getName(); logger.warn("Cannot read name ranges for " + n + " - setting to empty"); @@ -346,8 +291,7 @@ else if (data[pos] == union) ranges.add(range); } } - catch (Throwable t1) - { + catch (Throwable t1) { // Generate a warning // Names are really a nice to have, and we don't want to halt the // reading process for functionality that probably won't be used @@ -364,15 +308,12 @@ else if (data[pos] == union) * @param ind the index in the name table * @param dummy dummy parameter to indicate a biff7 workbook */ - NameRecord(Record t, WorkbookSettings ws, int ind, Biff7 dummy) - { + NameRecord(Record t, WorkbookSettings ws, int ind, Biff7 dummy) { super(t); index = ind; isbiff8 = false; - try - { - ranges = new ArrayList(); + try { byte[] data = getRecord().getData(); int length = data[3]; sheetRef = IntegerHelper.getInt(data[8], data[9]); @@ -381,102 +322,65 @@ else if (data[pos] == union) int pos = length + 14; if (pos >= data.length) - { // There appears to be nothing after the name, so return return; - } - if (data[pos] == cellReference) - { + if (data[pos] == cellReference) { int sheet = IntegerHelper.getInt(data[pos + 11], data[pos + 12]); int row = IntegerHelper.getInt(data[pos + 15], data[pos + 16]); int column = data[pos + 17]; NameRange r = new NameRange(sheet, column, row, column, row); ranges.add(r); - } - else if (data[pos] == areaReference) - { - int sheet1 = 0; - int r1 = 0; - int c1 = 0; - int r2 = 0; - int c2 = 0; - NameRange range = null; - - while (pos < data.length) - { - sheet1 = IntegerHelper.getInt(data[pos + 11], data[pos + 12]); - r1 = IntegerHelper.getInt(data[pos + 15], data[pos + 16]); - r2 = IntegerHelper.getInt(data[pos + 17], data[pos + 18]); - - c1 = data[pos + 19]; - c2 = data[pos + 20]; - - range = new NameRange(sheet1, c1, r1, c2, r2); - ranges.add(range); + } else if (data[pos] == areaReference) { + + while (pos < data.length) { + int sheet1 = IntegerHelper.getInt(data[pos + 11], data[pos + 12]); + int r1 = IntegerHelper.getInt(data[pos + 15], data[pos + 16]); + int r2 = IntegerHelper.getInt(data[pos + 17], data[pos + 18]); + + int c1 = data[pos + 19]; + int c2 = data[pos + 20]; + + ranges.add(new NameRange(sheet1, c1, r1, c2, r2)); pos += 21; } - } - else if (data[pos] == subExpression) - { - int sheet1 = 0; - int sheet2 = 0; - int r1 = 0; - int c1 = 0; - int r2 = 0; - int c2 = 0; - NameRange range = null; - + } else if (data[pos] == subExpression) { // Consume unnecessary parsed tokens if (pos < data.length && data[pos] != cellReference && - data[pos] != areaReference) - { + data[pos] != areaReference) { if (data[pos] == subExpression) - { pos += 3; - } else if (data[pos] == union) - { pos += 1; - } } - while (pos < data.length) - { - sheet1 = IntegerHelper.getInt(data[pos + 11], data[pos + 12]); - r1 = IntegerHelper.getInt(data[pos + 15], data[pos + 16]); - r2 = IntegerHelper.getInt(data[pos + 17], data[pos + 18]); + while (pos < data.length) { + int sheet1 = IntegerHelper.getInt(data[pos + 11], data[pos + 12]); + int r1 = IntegerHelper.getInt(data[pos + 15], data[pos + 16]); + int r2 = IntegerHelper.getInt(data[pos + 17], data[pos + 18]); - c1 = data[pos + 19]; - c2 = data[pos + 20]; + int c1 = data[pos + 19]; + int c2 = data[pos + 20]; - range = new NameRange(sheet1, c1, r1, c2, r2); - ranges.add(range); + ranges.add(new NameRange(sheet1, c1, r1, c2, r2)); pos += 21; // Consume unnecessary parsed tokens if (pos < data.length && data[pos] != cellReference && - data[pos] != areaReference) - { + data[pos] != areaReference) { if (data[pos] == subExpression) - { pos += 3; - } else if (data[pos] == union) - { pos += 1; - } } } } - } - catch (Throwable t1) - { + } catch (Throwable t1) { // Generate a warning // Names are really a nice to have, and we don't want to halt the // reading process for functionality that probably won't be used @@ -490,8 +394,7 @@ else if (data[pos] == union) * * @return the strings */ - public String getName() - { + public String getName() { return name; } @@ -500,8 +403,7 @@ public String getName() * * @return the built in name */ - public BuiltInName getBuiltInName() - { + public BuiltInName getBuiltInName() { return builtInName; } @@ -511,10 +413,8 @@ public BuiltInName getBuiltInName() * * @return the ranges */ - public NameRange[] getRanges() - { - NameRange[] nr = new NameRange[ranges.size()]; - return (NameRange[]) ranges.toArray(nr); + public NameRange[] getRanges() { + return ranges.toArray(new NameRange[ranges.size()]); } /** @@ -522,8 +422,7 @@ public NameRange[] getRanges() * * @return the 0-based index into the name table */ - int getIndex() - { + int getIndex() { return index; } @@ -533,8 +432,7 @@ int getIndex() * * @return the sheet reference for name formula */ - public int getSheetRef() - { + public int getSheetRef() { return sheetRef; } @@ -542,8 +440,7 @@ public int getSheetRef() * Set the index sheet reference for a record name * 0 is for a global reference */ - public void setSheetRef(int i) - { + public void setSheetRef(int i) { sheetRef = i; } @@ -552,8 +449,7 @@ public void setSheetRef(int i) * * @return the raw data */ - public byte[] getData() - { + public byte[] getData() { return getRecord().getData(); } @@ -562,8 +458,7 @@ public byte[] getData() * * @return TRUE if this is a biff8 name record, FALSE otherwise */ - public boolean isBiff8() - { + public boolean isBiff8() { return isbiff8; } @@ -572,9 +467,7 @@ public boolean isBiff8() * * @return TRUE if this is a global name, FALSE otherwise */ - public boolean isGlobal() - { + public boolean isGlobal() { return sheetRef == 0; } } - diff --git a/src/jxl/read/biff/Record.java b/src/jxl/read/biff/Record.java index e78319f..4141167 100644 --- a/src/jxl/read/biff/Record.java +++ b/src/jxl/read/biff/Record.java @@ -20,27 +20,19 @@ package jxl.read.biff; import java.util.ArrayList; - -import jxl.common.Logger; - -import jxl.biff.IntegerHelper; -import jxl.biff.Type; +import jxl.biff.*; /** * A container for the raw record data within a biff file */ -public final class Record +public class Record { - /** - * The logger - */ - private static final Logger logger = Logger.getLogger(Record.class); /** * The excel biff code */ - private int code; + private final int code; /** * The data type */ @@ -48,15 +40,15 @@ public final class Record /** * The length of this record */ - private int length; + private final int length; /** * A pointer to the beginning of the actual data */ - private int dataPos; + private final int dataPos; /** * A handle to the excel 97 file */ - private File file; + private final File file; /** * The raw data within this record */ @@ -65,7 +57,7 @@ public final class Record /** * Any continue records */ - private ArrayList continueRecords; + private ArrayList continueRecords; /** * Constructor @@ -85,6 +77,15 @@ public final class Record type = Type.getType(code); } + protected Record(byte[] header, byte [] data) { + code = IntegerHelper.getInt(header[0], header[1]); + length = IntegerHelper.getInt(header[2], header[3]); + dataPos = 0; + file = null; + type = Type.getType(code); + this.data = data; + } + /** * Gets the biff type * @@ -124,7 +125,7 @@ public byte[] getData() byte[][] contData = new byte[continueRecords.size()][]; for (int i = 0; i < continueRecords.size(); i++) { - Record r = (Record) continueRecords.get(i); + Record r = continueRecords.get(i); contData[i] = r.getData(); byte[] d2 = contData[i]; size += d2.length; @@ -133,9 +134,7 @@ public byte[] getData() byte[] d3 = new byte[data.length + size]; System.arraycopy(data, 0, d3, 0, data.length); int pos = data.length; - for (int i = 0; i < contData.length; i++) - { - byte[] d2 = contData[i]; + for (byte[] d2 : contData) { System.arraycopy(d2, 0, d3, pos, d2.length); pos += d2.length; } @@ -175,9 +174,7 @@ void setType(Type t) public void addContinueRecord(Record d) { if (continueRecords == null) - { - continueRecords = new ArrayList(); - } + continueRecords = new ArrayList<>(); continueRecords.add(d); } diff --git a/src/jxl/read/biff/SSTRecord.java b/src/jxl/read/biff/SSTRecord.java index da76bc2..e781aff 100644 --- a/src/jxl/read/biff/SSTRecord.java +++ b/src/jxl/read/biff/SSTRecord.java @@ -75,9 +75,8 @@ private static class BooleanHolder * * @param t the raw data * @param continuations the continuations - * @param ws the workbook settings */ - public SSTRecord(Record t, Record[] continuations, WorkbookSettings ws) + public SSTRecord(Record t, Record[] continuations) { super(t); @@ -120,7 +119,7 @@ public SSTRecord(Record t, Record[] continuations, WorkbookSettings ws) data[6], data[7]); strings = new String[uniqueStrings]; - readStrings(data, 8, ws); + readStrings(data, 8); } /** @@ -128,15 +127,13 @@ public SSTRecord(Record t, Record[] continuations, WorkbookSettings ws) * * @param data the raw data * @param offset the offset - * @param ws the workbook settings */ - private void readStrings(byte[] data, int offset, WorkbookSettings ws) + private void readStrings(byte[] data, int offset) { int pos = offset; int numChars; byte optionFlags; String s = null; - boolean asciiEncoding = false; boolean richString = false; boolean extendedString = false; int formattingRuns = 0; @@ -172,22 +169,18 @@ private void readStrings(byte[] data, int offset, WorkbookSettings ws) } // See if string is ASCII (compressed) or unicode - asciiEncoding = ((optionFlags & 0x01) == 0); + boolean compressedUTF16 = ((optionFlags & 0x01) == 0); ByteArrayHolder bah = new ByteArrayHolder(); BooleanHolder bh = new BooleanHolder(); - bh.value = asciiEncoding; + bh.value = compressedUTF16; pos += getChars(data, bah, pos, bh, numChars); - asciiEncoding = bh.value; + compressedUTF16 = bh.value; - if (asciiEncoding) - { - s = StringHelper.getString(bah.bytes, numChars, 0, ws); - } + if (compressedUTF16) + s = StringHelper.getCompressedUnicodeString(bah.bytes, 0, numChars); else - { - s = StringHelper.getUnicodeString(bah.bytes, numChars, 0); - } + s = StringHelper.getUnicodeString(bah.bytes, 0, numChars); strings[i] = s; diff --git a/src/jxl/read/biff/SharedBooleanFormulaRecord.java b/src/jxl/read/biff/SharedBooleanFormulaRecord.java index 7a24da7..dc0f380 100644 --- a/src/jxl/read/biff/SharedBooleanFormulaRecord.java +++ b/src/jxl/read/biff/SharedBooleanFormulaRecord.java @@ -43,7 +43,7 @@ public class SharedBooleanFormulaRecord extends BaseSharedFormulaRecord /** * The logger */ - private static Logger logger = + private static Logger logger = Logger.getLogger(SharedBooleanFormulaRecord.class); /** @@ -95,8 +95,7 @@ public boolean getValue() */ public String getContents() { - // return Boolean.toString(value) - only available in 1.4 or later - return (new Boolean(value)).toString(); + return Boolean.toString(value); } /** diff --git a/src/jxl/read/biff/SharedFormulaRecord.java b/src/jxl/read/biff/SharedFormulaRecord.java index 72a6228..1e97bc1 100644 --- a/src/jxl/read/biff/SharedFormulaRecord.java +++ b/src/jxl/read/biff/SharedFormulaRecord.java @@ -69,7 +69,7 @@ class SharedFormulaRecord /** * The rest of the cells comprising this shared formula */ - private ArrayList formulas; + private final ArrayList formulas = new ArrayList<>(); /** * The token data @@ -110,8 +110,6 @@ public SharedFormulaRecord(Record t, BaseSharedFormulaRecord fr, firstCol = data[4] & 0xff; lastCol = data[5] & 0xff; - formulas = new ArrayList(); - templateFormula = fr; tokens = new byte[data.length - 10]; @@ -126,13 +124,13 @@ public SharedFormulaRecord(Record t, BaseSharedFormulaRecord fr, * @return TRUE if the formulas was added, FALSE otherwise */ public boolean add(BaseSharedFormulaRecord fr) - { + { boolean added = false; int r = fr.getRow(); - if (r >= firstRow && r <= lastRow) + if (r >= firstRow && r <= lastRow) { int c = fr.getColumn(); - if (c >= firstCol && c <= lastCol) + if (c >= firstCol && c <= lastCol) { formulas.add(fr); added = true; @@ -153,7 +151,6 @@ public boolean add(BaseSharedFormulaRecord fr) */ Cell[] getFormulas(FormattingRecords fr, boolean nf) { - Cell[] sfs = new Cell[formulas.size() + 1]; // This can happen if there are many identical formulas in the // sheet and excel has not sliced and diced them exclusively @@ -181,13 +178,13 @@ Cell[] getFormulas(FormattingRecords fr, boolean nf) } } + Cell[] sfs = new Cell[formulas.size() + 1]; sfs[0] = templateFormula; - BaseSharedFormulaRecord f = null; for (int i = 0; i < formulas.size(); i++) { - f = (BaseSharedFormulaRecord) formulas.get(i); + BaseSharedFormulaRecord f = formulas.get(i); // See if the formula evaluates to date if (f.getType() == CellType.NUMBER_FORMULA) @@ -201,7 +198,7 @@ Cell[] getFormulas(FormattingRecords fr, boolean nf) } else { - ;// snfr.setNumberFormat(templateNumberFormat); + // snfr.setNumberFormat(templateNumberFormat); } } diff --git a/src/jxl/read/biff/SharedStringFormulaRecord.java b/src/jxl/read/biff/SharedStringFormulaRecord.java index 438b9f2..c410ed3 100644 --- a/src/jxl/read/biff/SharedStringFormulaRecord.java +++ b/src/jxl/read/biff/SharedStringFormulaRecord.java @@ -43,16 +43,11 @@ public class SharedStringFormulaRecord extends BaseSharedFormulaRecord implements LabelCell, FormulaData, StringFormulaCell { - /** - * The logger - */ - private static Logger logger = Logger.getLogger - (SharedStringFormulaRecord.class); /** * The value of this string formula */ - private String value; + private final String value; // Dummy value for overloading the constructor when the string evaluates // to null @@ -75,8 +70,7 @@ public SharedStringFormulaRecord(Record t, FormattingRecords fr, ExternalSheet es, WorkbookMethods nt, - SheetImpl si, - WorkbookSettings ws) + SheetImpl si) { super(t, fr, es, nt, si, excelFile.getPos()); int pos = excelFile.getPos(); @@ -104,44 +98,13 @@ public SharedStringFormulaRecord(Record t, nextRecord = excelFile.next(); // move the pointer within the data byte[] d = new byte[stringData.length + nextRecord.getLength() - 1]; System.arraycopy(stringData, 0, d, 0, stringData.length); - System.arraycopy(nextRecord.getData(), 1, d, + System.arraycopy(nextRecord.getData(), 1, d, stringData.length, nextRecord.getLength() - 1); stringData = d; nextRecord = excelFile.peek(); } - int chars = IntegerHelper.getInt(stringData[0], stringData[1]); - - boolean unicode = false; - int startpos = 3; - if (stringData.length == chars + 2) - { - // String might only consist of a one byte length indicator, instead - // of the more normal 2 - startpos = 2; - unicode = false; - } - else if (stringData[2] == 0x1) - { - // unicode string, two byte length indicator - startpos = 3; - unicode = true; - } - else - { - // ascii string, two byte length indicator - startpos = 3; - unicode = false; - } - - if (!unicode) - { - value = StringHelper.getString(stringData, chars, startpos, ws); - } - else - { - value = StringHelper.getUnicodeString(stringData, chars, startpos); - } + value = StringHelper.readBiff8String(stringData); // Restore the position in the excel file, to enable the SHRFMLA // record to be picked up @@ -177,6 +140,7 @@ public SharedStringFormulaRecord(Record t, * * @return the value */ + @Override public String getString() { return value; @@ -187,6 +151,7 @@ public String getString() * * @return the value as a string */ + @Override public String getContents() { return value; @@ -197,6 +162,7 @@ public String getContents() * * @return the cell type */ + @Override public CellType getType() { return CellType.STRING_FORMULA; @@ -209,6 +175,7 @@ public CellType getType() * @return the raw record data * @exception FormulaException */ + @Override public byte[] getFormulaData() throws FormulaException { if (!getSheet().getWorkbookBof().isBiff8()) diff --git a/src/jxl/read/biff/SheetImpl.java b/src/jxl/read/biff/SheetImpl.java index 533ea5b..0d23f19 100644 --- a/src/jxl/read/biff/SheetImpl.java +++ b/src/jxl/read/biff/SheetImpl.java @@ -19,37 +19,13 @@ package jxl.read.biff; -import java.util.ArrayList; -import java.util.Iterator; +import java.util.*; import java.util.regex.Pattern; -import jxl.common.Logger; -import jxl.common.Assert; - -import jxl.Cell; -import jxl.CellType; -import jxl.CellView; -import jxl.Hyperlink; -import jxl.Image; -import jxl.LabelCell; -import jxl.Range; -import jxl.Sheet; -import jxl.SheetSettings; -import jxl.WorkbookSettings; -import jxl.biff.BuiltInName; -import jxl.biff.AutoFilter; -import jxl.biff.CellFinder; +import jxl.*; +import jxl.biff.*; import jxl.biff.CellReferenceHelper; -import jxl.biff.ConditionalFormat; -import jxl.biff.DataValidation; -import jxl.biff.EmptyCell; -import jxl.biff.FormattingRecords; -import jxl.biff.Type; -import jxl.biff.WorkspaceInformationRecord; -import jxl.biff.drawing.Chart; -import jxl.biff.drawing.Drawing; -import jxl.biff.drawing.DrawingData; -import jxl.biff.drawing.DrawingGroupObject; +import jxl.biff.drawing.*; import jxl.format.CellFormat; /** @@ -62,34 +38,29 @@ */ public class SheetImpl implements Sheet { - /** - * The logger - */ - private static Logger logger = Logger.getLogger(SheetImpl.class); - /** * The excel file */ - private File excelFile; + private final File excelFile; /** * A handle to the shared string table */ - private SSTRecord sharedStrings; + private final SSTRecord sharedStrings; /** * A handle to the sheet BOF record, which indicates the stream type */ - private BOFRecord sheetBof; + private final BOFRecord sheetBof; /** * A handle to the workbook BOF record, which indicates the stream type */ - private BOFRecord workbookBof; + private final BOFRecord workbookBof; /** * A handle to the formatting records */ - private FormattingRecords formattingRecords; + private final FormattingRecords formattingRecords; /** * The name of this sheet @@ -109,7 +80,7 @@ public class SheetImpl implements Sheet /** * The cells */ - private Cell[][] cells; + private final Map cells = new HashMap<>(); /** * The start position in the stream of this sheet @@ -129,39 +100,39 @@ public class SheetImpl implements Sheet /** * The list of non-default row properties */ - private ArrayList rowProperties; + private List rowProperties; /** * An array of column info records. They are held this way before * they are transferred to the more convenient array */ - private ArrayList columnInfosArray; + private List columnInfosArray; /** * A list of shared formula groups */ - private ArrayList sharedFormulas; + private final List sharedFormulas; /** * A list of hyperlinks on this page */ - private ArrayList hyperlinks; + private List hyperlinks; /** * A list of charts on this page */ - private ArrayList charts; + private List charts; /** * A list of drawings on this page */ - private ArrayList drawings; + private List drawings; /** * A list of drawings (as opposed to comments/validation/charts) on this * page */ - private ArrayList images; + private List images; /** * A list of data validations on this page @@ -171,7 +142,7 @@ public class SheetImpl implements Sheet /** * A list of merged cells on this page */ - private Range[] mergedCells; + private List mergedCells; /** * Indicates whether the columnInfos array has been initialized @@ -186,7 +157,7 @@ public class SheetImpl implements Sheet /** * Indicates whether or not the dates are based around the 1904 date system */ - private boolean nineteenFour; + private final boolean nineteenFour; /** * The workspace options @@ -216,12 +187,12 @@ public class SheetImpl implements Sheet /** * The horizontal page breaks contained on this sheet */ - private int[] rowBreaks; + private HorizontalPageBreaksRecord rowBreaks; /** * The vertical page breaks contained on this sheet */ - private int[] columnBreaks; + private VerticalPageBreaksRecord columnBreaks; /** * The maximum row outline level @@ -236,12 +207,12 @@ public class SheetImpl implements Sheet /** * The list of local names for this sheet */ - private ArrayList localNames; + private List localNames; /** * The list of conditional formats for this sheet */ - private ArrayList conditionalFormats; + private List conditionalFormats; /** * The autofilter information @@ -252,12 +223,12 @@ public class SheetImpl implements Sheet * A handle to the workbook which contains this sheet. Some of the records * need this in order to reference external sheets */ - private WorkbookParser workbook; + private final WorkbookParser workbook; /** * A handle to the workbook settings */ - private WorkbookSettings workbookSettings; + private final WorkbookSettings workbookSettings; /** * Constructor @@ -285,10 +256,10 @@ public class SheetImpl implements Sheet formattingRecords = fr; sheetBof = sb; workbookBof = wb; - columnInfosArray = new ArrayList(); - sharedFormulas = new ArrayList(); - hyperlinks = new ArrayList(); - rowProperties = new ArrayList(10); + columnInfosArray = new ArrayList<>(); + sharedFormulas = new ArrayList<>(); + hyperlinks = new ArrayList<>(); + rowProperties = new ArrayList<>(10); columnInfosInitialized = false; rowRecordsInitialized = false; nineteenFour = nf; @@ -304,12 +275,11 @@ public class SheetImpl implements Sheet startPosition -= (sheetBof.getLength() + 4); } - Record r = null; int bofs = 1; while (bofs >= 1) { - r = f.next(); + Record r = f.next(); // use this form for quick performance if (r.getCode() == Type.EOF.value) @@ -331,6 +301,7 @@ public class SheetImpl implements Sheet * @param loc the cell reference * @return the cell at the specified co-ordinates */ + @Override public Cell getCell(String loc) { return getCell(CellReferenceHelper.getColumn(loc), @@ -344,24 +315,15 @@ public Cell getCell(String loc) * @param column the column number * @return the cell at the specified co-ordinates */ + @Override public Cell getCell(int column, int row) { // just in case this has been cleared, but something else holds // a reference to it - if (cells == null) - { + if (cells.isEmpty()) readSheet(); - } - Cell c = cells[row][column]; - - if (c == null) - { - c = new EmptyCell(column, row); - cells[row][column] = c; - } - - return c; + return cells.computeIfAbsent(new CellCoordinate(column, row), EmptyCell::new); } /** @@ -373,6 +335,7 @@ public Cell getCell(int column, int row) * @param contents the string to match * @return the Cell whose contents match the paramter, null if not found */ + @Override public Cell findCell(String contents) { CellFinder cellFinder = new CellFinder(this); @@ -384,7 +347,7 @@ public Cell findCell(String contents) * If no match is found, then null is returned. The search is performed * on a row by row basis, so the lower the row number, the more * efficiently the algorithm will perform - * + * * @param contents the string to match * @param firstCol the first column within the range * @param firstRow the first row of the range @@ -393,19 +356,20 @@ public Cell findCell(String contents) * @param reverse indicates whether to perform a reverse search or not * @return the Cell whose contents match the parameter, null if not found */ - public Cell findCell(String contents, - int firstCol, - int firstRow, - int lastCol, - int lastRow, + @Override + public Cell findCell(String contents, + int firstCol, + int firstRow, + int lastCol, + int lastRow, boolean reverse) { CellFinder cellFinder = new CellFinder(this); return cellFinder.findCell(contents, - firstCol, - firstRow, + firstCol, + firstRow, lastCol, - lastRow, + lastRow, reverse); } @@ -414,7 +378,7 @@ public Cell findCell(String contents, * If no match is found, then null is returned. The search is performed * on a row by row basis, so the lower the row number, the more * efficiently the algorithm will perform - * + * * @param pattern the regular expression string to match * @param firstCol the first column within the range * @param firstRow the first row of the range @@ -423,19 +387,20 @@ public Cell findCell(String contents, * @param reverse indicates whether to perform a reverse search or not * @return the Cell whose contents match the parameter, null if not found */ - public Cell findCell(Pattern pattern, - int firstCol, - int firstRow, - int lastCol, - int lastRow, + @Override + public Cell findCell(Pattern pattern, + int firstCol, + int firstRow, + int lastCol, + int lastRow, boolean reverse) { CellFinder cellFinder = new CellFinder(this); return cellFinder.findCell(pattern, - firstCol, - firstRow, + firstCol, + firstRow, lastCol, - lastRow, + lastRow, reverse); } @@ -451,6 +416,7 @@ public Cell findCell(Pattern pattern, * @param contents the string to match * @return the Cell whose contents match the paramter, null if not found */ + @Override public LabelCell findLabelCell(String contents) { CellFinder cellFinder = new CellFinder(this); @@ -462,14 +428,13 @@ public LabelCell findLabelCell(String contents) * * @return the number of rows in this sheet */ + @Override public int getRows() { // just in case this has been cleared, but something else holds // a reference to it - if (cells == null) - { + if (cells.isEmpty()) readSheet(); - } return numRows; } @@ -479,14 +444,13 @@ public int getRows() * * @return the number of columns in this sheet */ + @Override public int getColumns() { // just in case this has been cleared, but something else holds // a reference to it - if (cells == null) - { + if (cells.isEmpty()) readSheet(); - } return numCols; } @@ -498,29 +462,19 @@ public int getColumns() * @param row the rows whose cells are to be returned * @return the cells on the given row */ + @Override public Cell[] getRow(int row) { // just in case this has been cleared, but something else holds // a reference to it - if (cells == null) - { + if (cells.isEmpty()) readSheet(); - } - // Find the last non-null cell - boolean found = false; - int col = numCols - 1; - while (col >= 0 && !found) - { - if (cells[row][col] != null) - { - found = true; - } - else - { - col--; - } - } + int col = cells.keySet().stream() + .filter(coord -> coord.getRow() == row) + .mapToInt(CellCoordinate::getColumn) + .max() + .orElse(-1); // Only create entries for non-null cells Cell[] c = new Cell[col + 1]; @@ -539,29 +493,19 @@ public Cell[] getRow(int row) * @param col the column whose cells are to be returned * @return the cells on the specified column */ + @Override public Cell[] getColumn(int col) { // just in case this has been cleared, but something else holds // a reference to it - if (cells == null) - { + if (cells.isEmpty()) readSheet(); - } - // Find the last non-null cell - boolean found = false; - int row = numRows - 1; - while (row >= 0 && !found) - { - if (cells[row][col] != null) - { - found = true; - } - else - { - row--; - } - } + int row = cells.keySet().stream() + .filter(coord -> coord.getColumn() == col) + .mapToInt(CellCoordinate::getRow) + .max() + .orElse(-1); // Only create entries for non-null cells Cell[] c = new Cell[row + 1]; @@ -578,6 +522,7 @@ public Cell[] getColumn(int col) * * @return the name of the sheet */ + @Override public String getName() { return name; @@ -593,17 +538,6 @@ final void setName(String s) name = s; } - /** - * Determines whether the sheet is hidden - * - * @return whether or not the sheet is hidden - * @deprecated in favour of the getSettings function - */ - public boolean isHidden() - { - return hidden; - } - /** * Gets the column info record for the specified column. If no * column is specified, null is returned @@ -616,12 +550,7 @@ public ColumnInfoRecord getColumnInfo(int col) if (!columnInfosInitialized) { // Initialize the array - Iterator i = columnInfosArray.iterator(); - ColumnInfoRecord cir = null; - while (i.hasNext()) - { - cir = (ColumnInfoRecord) i.next(); - + for (ColumnInfoRecord cir : columnInfosArray) { int startcol = Math.max(0, cir.getStartColumn()); int endcol = Math.min(columnInfos.length - 1, cir.getEndColumn()); @@ -650,13 +579,7 @@ public ColumnInfoRecord getColumnInfo(int col) public ColumnInfoRecord[] getColumnInfos() { // Just chuck all the column infos we have into an array - ColumnInfoRecord[] infos = new ColumnInfoRecord[columnInfosArray.size()]; - for (int i = 0; i < columnInfosArray.size(); i++) - { - infos[i] = (ColumnInfoRecord) columnInfosArray.get(i); - } - - return infos; + return columnInfosArray.toArray(ColumnInfoRecord[]::new); } /** @@ -675,7 +598,7 @@ final void setHidden(boolean h) */ final void clear() { - cells = null; + cells.clear(); mergedCells = null; columnInfosArray.clear(); sharedFormulas.clear(); @@ -693,17 +616,6 @@ final void clear() */ final void readSheet() { - // If this sheet contains only a chart, then set everything to - // empty and do not bother parsing the sheet - // Thanks to steve.brophy for spotting this - if (!sheetBof.isWorksheet()) - { - numRows = 0; - numCols = 0; - cells = new Cell[0][0]; - // return; - } - SheetReader reader = new SheetReader(excelFile, sharedStrings, formattingRecords, @@ -718,7 +630,7 @@ final void readSheet() // Take stuff that was read in numRows = reader.getNumRows(); numCols = reader.getNumCols(); - cells = reader.getCells(); + cells.putAll(reader.getCells()); rowProperties = reader.getRowProperties(); columnInfosArray = reader.getColumnInfosArray(); hyperlinks = reader.getHyperlinks(); @@ -738,17 +650,14 @@ final void readSheet() maxRowOutlineLevel = reader.getMaxRowOutlineLevel(); maxColumnOutlineLevel = reader.getMaxColumnOutlineLevel(); - reader = null; - if (!workbookSettings.getGCDisabled()) { System.gc(); } - if (columnInfosArray.size() > 0) + if (!columnInfosArray.isEmpty()) { - ColumnInfoRecord cir = (ColumnInfoRecord) - columnInfosArray.get(columnInfosArray.size() - 1); + ColumnInfoRecord cir = columnInfosArray.get(columnInfosArray.size() - 1); columnInfos = new ColumnInfoRecord[cir.getEndColumn() + 1]; } else @@ -759,9 +668,7 @@ final void readSheet() // Add any local names if (localNames != null) { - for (Iterator it = localNames.iterator(); it.hasNext() ;) - { - NameRecord nr = (NameRecord) it.next(); + for (NameRecord nr : localNames) { if (nr.getBuiltInName() == BuiltInName.PRINT_AREA) { if(nr.getRanges().length > 0) @@ -775,25 +682,22 @@ final void readSheet() } else if (nr.getBuiltInName() == BuiltInName.PRINT_TITLES) { - // There can be 1 or 2 entries. + // There can be 1 or 2 entries. // Row entries have hardwired column entries (first and last // possible column) - // Column entries have hardwired row entries (first and last + // Column entries have hardwired row entries (first and last // possible row) - for (int i = 0 ; i < nr.getRanges().length ; i++) - { - NameRecord.NameRange rng = nr.getRanges()[i]; + for (NameRecord.NameRange rng : nr.getRanges()) if (rng.getFirstColumn() == 0 && rng.getLastColumn() == 255) { settings.setPrintTitlesRow(rng.getFirstRow(), - rng.getLastRow()); + rng.getLastRow()); } else { settings.setPrintTitlesCol(rng.getFirstColumn(), - rng.getLastColumn()); + rng.getLastColumn()); } - } } } } @@ -804,29 +708,22 @@ else if (nr.getBuiltInName() == BuiltInName.PRINT_TITLES) * * @return an array of hyperlinks */ + @Override public Hyperlink[] getHyperlinks() { - Hyperlink[] hl = new Hyperlink[hyperlinks.size()]; - - for (int i = 0; i < hyperlinks.size(); i++) - { - hl[i] = (Hyperlink) hyperlinks.get(i); - } - - return hl; + return hyperlinks.toArray(Hyperlink[]::new); } /** * Gets the cells which have been merged on this sheet * - * @return an array of range objects + * @return a List of range objects */ - public Range[] getMergedCells() + @Override + public List getMergedCells() { if (mergedCells == null) - { - return new Range[0]; - } + return List.of(); return mergedCells; } @@ -836,15 +733,8 @@ public Range[] getMergedCells() * * @return an array of row properties */ - public RowRecord[] getRowProperties() - { - RowRecord[] rp = new RowRecord[rowProperties.size()]; - for (int i = 0; i < rp.length; i++) - { - rp[i] = (RowRecord) rowProperties.get(i); - } - - return rp; + public RowRecord[] getRowProperties() { + return rowProperties.toArray(RowRecord[]::new); } /** @@ -869,18 +759,11 @@ RowRecord getRowInfo(int r) if (!rowRecordsInitialized) { rowRecords = new RowRecord[getRows()]; - Iterator i = rowProperties.iterator(); - int rownum = 0; - RowRecord rr = null; - while (i.hasNext()) - { - rr = (RowRecord) i.next(); - rownum = rr.getRowNumber(); + for (RowRecord rr : rowProperties) { + int rownum = rr.getRowNumber(); if (rownum < rowRecords.length) - { rowRecords[rownum] = rr; - } } rowRecordsInitialized = true; @@ -894,7 +777,8 @@ RowRecord getRowInfo(int r) * * @return the explicit row breaks */ - public final int[] getRowPageBreaks() + @Override + public final IHorizontalPageBreaks getRowPageBreaks() { return rowBreaks; } @@ -904,7 +788,8 @@ public final int[] getRowPageBreaks() * * @return the explicit row breaks */ - public final int[] getColumnPageBreaks() + @Override + public final IVerticalPageBreaks getColumnPageBreaks() { return columnBreaks; } @@ -916,13 +801,7 @@ public final int[] getColumnPageBreaks() */ public final Chart[] getCharts() { - Chart[] ch = new Chart[charts.size()]; - - for (int i = 0; i < ch.length; i++) - { - ch[i] = (Chart) charts.get(i); - } - return ch; + return charts.toArray(Chart[]::new); } /** @@ -932,20 +811,7 @@ public final Chart[] getCharts() */ public final DrawingGroupObject[] getDrawings() { - DrawingGroupObject[] dr = new DrawingGroupObject[drawings.size()]; - dr = (DrawingGroupObject[]) drawings.toArray(dr); - return dr; - } - - /** - * Determines whether the sheet is protected - * - * @return whether or not the sheet is protected - * @deprecated in favour of the getSettings() api - */ - public boolean isProtected() - { - return settings.isProtected(); + return drawings.toArray(DrawingGroupObject[]::new); } /** @@ -964,6 +830,7 @@ public WorkspaceInformationRecord getWorkspaceOptions() * * @return the settings for this sheet */ + @Override public SheetSettings getSettings() { return settings; @@ -987,6 +854,7 @@ public WorkbookParser getWorkbook() * @return the column format, or NULL if the column has no specific format * @deprecated use getColumnView instead */ + @Override public CellFormat getColumnFormat(int col) { CellView cv = getColumnView(col); @@ -1000,6 +868,7 @@ public CellFormat getColumnFormat(int col) * @return the column width, or the default width if the column has no * specified format */ + @Override public int getColumnWidth(int col) { return getColumnView(col).getSize() / 256; @@ -1012,6 +881,7 @@ public int getColumnWidth(int col) * @return the column format, or the default format if no override is specified */ + @Override public CellView getColumnView(int col) { ColumnInfoRecord cir = getColumnInfo(col); @@ -1041,6 +911,7 @@ public CellView getColumnView(int col) * specified format * @deprecated use getRowView instead */ + @Override public int getRowHeight(int row) { return getRowView(row).getDimension(); @@ -1053,6 +924,7 @@ public int getRowHeight(int row) * @return the row format, or the default format if no override is specified */ + @Override public CellView getRowView(int row) { RowRecord rr = getRowInfo(row); @@ -1126,6 +998,7 @@ public ButtonPropertySetRecord getButtonPropertySet() * * @return the number of images on this sheet */ + @Override public int getNumberOfImages() { if (images == null) @@ -1142,6 +1015,7 @@ public int getNumberOfImages() * @param i the 0 based image number * @return the image at the specified position */ + @Override public Image getDrawing(int i) { if (images == null) @@ -1149,7 +1023,7 @@ public Image getDrawing(int i) initializeImages(); } - return (Image) images.get(i); + return images.get(i); } /** @@ -1162,16 +1036,12 @@ private void initializeImages() return; } - images = new ArrayList(); + images = new ArrayList<>(); DrawingGroupObject[] dgos = getDrawings(); - for (int i = 0; i < dgos.length; i++) - { - if (dgos[i] instanceof Drawing) - { - images.add(dgos[i]); - } - } + for (DrawingGroupObject dgo : dgos) + if (dgo instanceof Drawing) + images.add((Image) dgo); } /** @@ -1201,7 +1071,7 @@ void addLocalName(NameRecord nr) { if (localNames == null) { - localNames = new ArrayList(); + localNames = new ArrayList<>(); } localNames.add(nr); @@ -1214,9 +1084,9 @@ void addLocalName(NameRecord nr) */ public ConditionalFormat[] getConditionalFormats() { - ConditionalFormat[] formats = + ConditionalFormat[] formats = new ConditionalFormat[conditionalFormats.size()]; - formats = (ConditionalFormat[]) conditionalFormats.toArray(formats); + formats = conditionalFormats.toArray(formats); return formats; } @@ -1230,22 +1100,22 @@ public AutoFilter getAutoFilter() return autoFilter; } - /** + /** * Accessor for the maximum column outline level. Used during a copy * * @return the maximum column outline level, or 0 if no outlines/groups */ - public int getMaxColumnOutlineLevel() + public int getMaxColumnOutlineLevel() { return maxColumnOutlineLevel; } - /** + /** * Accessor for the maximum row outline level. Used during a copy * * @return the maximum row outline level, or 0 if no outlines/groups */ - public int getMaxRowOutlineLevel() + public int getMaxRowOutlineLevel() { return maxRowOutlineLevel; } diff --git a/src/jxl/read/biff/SheetReader.java b/src/jxl/read/biff/SheetReader.java index 3832e55..3851a86 100644 --- a/src/jxl/read/biff/SheetReader.java +++ b/src/jxl/read/biff/SheetReader.java @@ -19,53 +19,15 @@ package jxl.read.biff; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.Iterator; - -import jxl.common.Assert; -import jxl.common.Logger; - -import jxl.Cell; -import jxl.CellFeatures; +import java.util.*; +import jxl.*; import jxl.CellReferenceHelper; -import jxl.CellType; -import jxl.DateCell; import jxl.HeaderFooter; -import jxl.Range; -import jxl.SheetSettings; -import jxl.WorkbookSettings; -import jxl.biff.AutoFilter; -import jxl.biff.AutoFilterInfoRecord; -import jxl.biff.AutoFilterRecord; -import jxl.biff.ConditionalFormat; -import jxl.biff.ConditionalFormatRangeRecord; -import jxl.biff.ConditionalFormatRecord; -import jxl.biff.ContinueRecord; -import jxl.biff.DataValidation; -import jxl.biff.DataValidityListRecord; -import jxl.biff.DataValiditySettingsRecord; -import jxl.biff.FilterModeRecord; -import jxl.biff.FormattingRecords; -import jxl.biff.Type; -import jxl.biff.WorkspaceInformationRecord; -import jxl.biff.drawing.Button; -import jxl.biff.drawing.Chart; -import jxl.biff.drawing.CheckBox; -import jxl.biff.drawing.ComboBox; -import jxl.biff.drawing.Comment; -import jxl.biff.drawing.Drawing; -import jxl.biff.drawing.Drawing2; -import jxl.biff.drawing.DrawingData; -import jxl.biff.drawing.DrawingDataException; -import jxl.biff.drawing.MsoDrawingRecord; -import jxl.biff.drawing.NoteRecord; -import jxl.biff.drawing.ObjRecord; -import jxl.biff.drawing.TextObjectRecord; +import jxl.biff.*; +import jxl.biff.drawing.*; import jxl.biff.formula.FormulaException; -import jxl.format.PageOrder; -import jxl.format.PageOrientation; -import jxl.format.PaperSize; +import jxl.common.*; +import jxl.format.*; /** * Reads the sheet. This functionality was originally part of the @@ -77,32 +39,32 @@ final class SheetReader /** * The logger */ - private static Logger logger = Logger.getLogger(SheetReader.class); + private static final Logger LOGGER = Logger.getLogger(SheetReader.class); /** * The excel file */ - private File excelFile; + private final File excelFile; /** * A handle to the shared string table */ - private SSTRecord sharedStrings; + private final SSTRecord sharedStrings; /** * A handle to the sheet BOF record, which indicates the stream type */ - private BOFRecord sheetBof; + private final BOFRecord sheetBof; /** * A handle to the workbook BOF record, which indicates the stream type */ - private BOFRecord workbookBof; + private final BOFRecord workbookBof; /** * A handle to the formatting records */ - private FormattingRecords formattingRecords; + private final FormattingRecords formattingRecords; /** * The number of rows @@ -117,43 +79,38 @@ final class SheetReader /** * The cells */ - private Cell[][] cells; - - /** - * Any cells which are out of the defined bounds - */ - private ArrayList outOfBoundsCells; + private final Map cells = new HashMap<>(); /** * The start position in the stream of this sheet */ - private int startPosition; + private final int startPosition; /** * The list of non-default row properties */ - private ArrayList rowProperties; + private final List rowProperties = new ArrayList<>(10); /** * An array of column info records. They are held this way before * they are transferred to the more convenient array */ - private ArrayList columnInfosArray; + private final List columnInfosArray = new ArrayList<>(); /** * A list of shared formula groups */ - private ArrayList sharedFormulas; + private final List sharedFormulas = new ArrayList<>(); /** * A list of hyperlinks on this page */ - private ArrayList hyperlinks; + private final List hyperlinks = new ArrayList<>(); /** * The list of conditional formats on this page */ - private ArrayList conditionalFormats; + private final List conditionalFormats = new ArrayList<>(); /** * The autofilter information @@ -163,7 +120,7 @@ final class SheetReader /** * A list of merged cells on this page */ - private Range[] mergedCells; + private final List mergedCells = new ArrayList<>(); /** * The list of data validations on this page @@ -173,12 +130,12 @@ final class SheetReader /** * The list of charts on this page */ - private ArrayList charts; + private final List charts = new ArrayList<>(); /** * The list of drawings on this page */ - private ArrayList drawings; + private final List drawings = new ArrayList<>(); /** * The drawing data for the drawings @@ -188,7 +145,7 @@ final class SheetReader /** * Indicates whether or not the dates are based around the 1904 date system */ - private boolean nineteenFour; + private final boolean nineteenFour; /** * The PLS print record @@ -208,12 +165,12 @@ final class SheetReader /** * The horizontal page breaks contained on this sheet */ - private int[] rowBreaks; + private HorizontalPageBreaksRecord rowBreaks = new HorizontalPageBreaksRecord(); /** * The vertical page breaks contained on this sheet */ - private int[] columnBreaks; + private VerticalPageBreaksRecord columnBreaks = new VerticalPageBreaksRecord(); /** * The maximum row outline level @@ -228,23 +185,23 @@ final class SheetReader /** * The sheet settings */ - private SheetSettings settings; + private final SheetSettings settings; /** * The workbook settings */ - private WorkbookSettings workbookSettings; + private final WorkbookSettings workbookSettings; /** * A handle to the workbook which contains this sheet. Some of the records * need this in order to reference external sheets */ - private WorkbookParser workbook; + private final WorkbookParser workbook; /** * A handle to the sheet */ - private SheetImpl sheet; + private final SheetImpl sheet; /** * Constructor @@ -275,14 +232,6 @@ final class SheetReader formattingRecords = fr; sheetBof = sb; workbookBof = wb; - columnInfosArray = new ArrayList(); - sharedFormulas = new ArrayList(); - hyperlinks = new ArrayList(); - conditionalFormats = new ArrayList(); - rowProperties = new ArrayList(10); - charts = new ArrayList(); - drawings = new ArrayList(); - outOfBoundsCells = new ArrayList(); nineteenFour = nf; workbook = wp; startPosition = sp; @@ -298,31 +247,15 @@ final class SheetReader */ private void addCell(Cell cell) { - // Sometimes multiple cells (eg. MULBLANK) can exceed the - // column/row boundaries. Ignore these - if (cell.getRow() < numRows && cell.getColumn() < numCols) - { - if (cells[cell.getRow()][cell.getColumn()] != null) - { - StringBuffer sb = new StringBuffer(); - CellReferenceHelper.getCellReference - (cell.getColumn(), cell.getRow(), sb); - logger.warn("Cell " + sb.toString() + - " already contains data"); - } - cells[cell.getRow()][cell.getColumn()] = cell; - } - else + jxl.CellCoordinate coord = cell.getCoordinate(); + if (cells.put(coord, cell) != null) { - outOfBoundsCells.add(cell); - /* - logger.warn("Cell " + - CellReferenceHelper.getCellReference - (cell.getColumn(), cell.getRow()) + - " exceeds defined cell boundaries in Dimension record " + - "(" + numCols + "x" + numRows + ")"); - */ + StringBuffer sb = new StringBuffer(); + CellReferenceHelper.getCellReference(cell.getColumn(), cell.getRow(), sb); + LOGGER.warn("Cell " + sb.toString() + " already contains data"); } + numRows = Math.max(numRows, cell.getRow() + 1); + numCols = Math.max(numCols, cell.getColumn() + 1); } /** @@ -330,7 +263,6 @@ private void addCell(Cell cell) */ final void read() { - Record r = null; BaseSharedFormulaRecord sharedFormula = null; boolean sharedFormulaAdded = false; @@ -354,851 +286,655 @@ final void read() // A handle to window2 record Window2Record window2Record = null; - // A handle to printgridlines record - PrintGridLinesRecord printGridLinesRecord = null; - - // A handle to printheaders record - PrintHeadersRecord printHeadersRecord = null; - // Hash map of comments, indexed on objectId. As each corresponding // note record is encountered, these are removed from the array - HashMap comments = new HashMap(); + HashMap comments = new HashMap<>(); // A list of object ids - used for cross referencing - ArrayList objectIds = new ArrayList(); + ArrayList objectIds = new ArrayList<>(); // A handle to a continue record read in ContinueRecord continueRecord = null; - boolean first = true; + boolean first = true; while (cont) { - r = excelFile.next(); + Record r = excelFile.next(); Type type = r.getType(); if (type == Type.UNKNOWN && r.getCode() == 0) { - logger.warn("Biff code zero found"); + LOGGER.warn("Biff code zero found"); // Try a dimension record if (r.getLength() == 0xa) { - logger.warn("Biff code zero found - trying a dimension record."); + LOGGER.warn("Biff code zero found - trying a dimension record."); r.setType(Type.DIMENSION); } else { - logger.warn("Biff code zero found - Ignoring."); + LOGGER.warn("Biff code zero found - Ignoring."); } } if (first && type != Type.DIMENSION) { numRows = workbookSettings.getStartRowCount(); numCols = workbookSettings.getStartColumnCount(); - cells = new Cell[numRows][numCols]; first = false; } - if (type == Type.DIMENSION) - { - DimensionRecord dr = null; - - if (workbookBof.isBiff8()) - { - dr = new DimensionRecord(r); - } - else - { - dr = new DimensionRecord(r, DimensionRecord.biff7); - } - numRows = dr.getNumberOfRows(); - numCols = dr.getNumberOfColumns(); - cells = new Cell[numRows][numCols]; - } - else if (type == Type.LABELSST) - { - LabelSSTRecord label = new LabelSSTRecord(r, - sharedStrings, - formattingRecords, - sheet); - addCell(label); - } - else if (type == Type.RK || type == Type.RK2) - { - RKRecord rkr = new RKRecord(r, formattingRecords, sheet); + switch (type) { + case DIMENSION: + DimensionRecord dr = workbookBof.isBiff8() + ? new DimensionRecord(r) + : new DimensionRecord(r, DimensionRecord.biff7); + numRows = dr.getNumberOfRows(); + numCols = dr.getNumberOfColumns(); + break; + + case LABELSST: + addCell(new LabelSSTRecord(r, + sharedStrings, + formattingRecords, + sheet)); + break; + + case RK: + case RK2: + RKRecord rkr = new RKRecord(r, formattingRecords, sheet); + if (formattingRecords.isDate(rkr.getXFIndex())) { + DateCell dc = new DateRecord(rkr, rkr.getXFIndex(), formattingRecords, nineteenFour, sheet); + addCell(dc); + } else + addCell(rkr); + break; - if (formattingRecords.isDate(rkr.getXFIndex())) - { - DateCell dc = new DateRecord - (rkr, rkr.getXFIndex(), formattingRecords, nineteenFour, sheet); - addCell(dc); - } - else - { - addCell(rkr); - } - } - else if (type == Type.HLINK) - { - HyperlinkRecord hr = new HyperlinkRecord(r, sheet, workbookSettings); - hyperlinks.add(hr); - } - else if (type == Type.MERGEDCELLS) - { - MergedCellsRecord mc = new MergedCellsRecord(r, sheet); - if (mergedCells == null) - { - mergedCells = mc.getRanges(); + case HLINK: { + HyperlinkRecord hr = new HyperlinkRecord(r, sheet, workbookSettings); + hyperlinks.add(hr); + break; } - else - { - Range[] newMergedCells = - new Range[mergedCells.length + mc.getRanges().length]; - System.arraycopy(mergedCells, 0, newMergedCells, 0, - mergedCells.length); - System.arraycopy(mc.getRanges(), - 0, - newMergedCells, mergedCells.length, - mc.getRanges().length); - mergedCells = newMergedCells; - } - } - else if (type == Type.MULRK) - { - MulRKRecord mulrk = new MulRKRecord(r); - - // Get the individual cell records from the multiple record - int num = mulrk.getNumberOfColumns(); - int ixf = 0; - for (int i = 0; i < num; i++) - { - ixf = mulrk.getXFIndex(i); - NumberValue nv = new NumberValue - (mulrk.getRow(), - mulrk.getFirstColumn() + i, - RKHelper.getDouble(mulrk.getRKNumber(i)), - ixf, - formattingRecords, - sheet); + case MERGEDCELLS: + MergedCellsRecord mc = new MergedCellsRecord(r, sheet); + mergedCells.addAll(mc.getRanges()); + break; - - if (formattingRecords.isDate(ixf)) - { - DateCell dc = new DateRecord(nv, - ixf, - formattingRecords, - nineteenFour, - sheet); - addCell(dc); - } - else - { - nv.setNumberFormat(formattingRecords.getNumberFormat(ixf)); - addCell(nv); + case MULRK: { + MulRKRecord mulrk = new MulRKRecord(r); + // Get the individual cell records from the multiple record + int num = mulrk.getNumberOfColumns(); + for (int i = 0; i < num; i++) { + int ixf = mulrk.getXFIndex(i); + + NumberValue nv = new NumberValue(mulrk.getRow(), + mulrk.getFirstColumn() + i, + RKHelper.getDouble(mulrk.getRKNumber(i)), + ixf, + formattingRecords, + sheet); + + if (formattingRecords.isDate(ixf)) { + DateCell dc = new DateRecord(nv, + ixf, + formattingRecords, + nineteenFour, + sheet); + addCell(dc); + } else { + nv.setNumberFormat(formattingRecords.getNumberFormat(ixf)); + addCell(nv); + } } } - } - else if (type == Type.NUMBER) - { - NumberRecord nr = new NumberRecord(r, formattingRecords, sheet); + break; - if (formattingRecords.isDate(nr.getXFIndex())) - { - DateCell dc = new DateRecord(nr, - nr.getXFIndex(), - formattingRecords, - nineteenFour, sheet); - addCell(dc); - } - else - { - addCell(nr); + case NUMBER: { + NumberRecord nr = new NumberRecord(r, formattingRecords, sheet); + if (formattingRecords.isDate(nr.getXFIndex())) { + DateCell dc = new DateRecord(nr, + nr.getXFIndex(), + formattingRecords, + nineteenFour, sheet); + addCell(dc); + } else + addCell(nr); + } + break; + + case BOOLERR: { + BooleanRecord br = new BooleanRecord(r, formattingRecords, sheet); + if (br.isError()) { + ErrorRecord er = new ErrorRecord(br.getRecord(), formattingRecords, + sheet); + addCell(er); + } else + addCell(br); + break; + } + + case PRINTGRIDLINES: + // A handle to printgridlines record + PrintGridLinesRecord printGridLinesRecord = new PrintGridLinesRecord(r); + settings.setPrintGridLines(printGridLinesRecord.getPrintGridLines()); + break; + + case PRINTHEADERS: + // A handle to printheaders record + PrintHeadersRecord printHeadersRecord = new PrintHeadersRecord(r); + settings.setPrintHeaders(printHeadersRecord.getPrintHeaders()); + break; + + case WINDOW2: + window2Record = workbookBof.isBiff8() + ? new Window2Record(r) + : new Window2Record(r, Window2Record.biff7); + settings.setShowGridLines(window2Record.getShowGridLines()); + settings.setDisplayZeroValues(window2Record.getDisplayZeroValues()); + settings.setSelected(true); + settings.setPageBreakPreviewMode(window2Record.isPageBreakPreview()); + break; + + case PANE: { + PaneRecord pr = new PaneRecord(r); + if (window2Record != null + && window2Record.getFrozen()) { + settings.setVerticalFreeze(pr.getRowsVisible()); + settings.setHorizontalFreeze(pr.getColumnsVisible()); + } + break; } - } - else if (type == Type.BOOLERR) - { - BooleanRecord br = new BooleanRecord(r, formattingRecords, sheet); - if (br.isError()) - { - ErrorRecord er = new ErrorRecord(br.getRecord(), formattingRecords, - sheet); - addCell(er); - } - else - { - addCell(br); - } - } - else if (type == Type.PRINTGRIDLINES) - { - printGridLinesRecord = new PrintGridLinesRecord(r); - settings.setPrintGridLines(printGridLinesRecord.getPrintGridLines()); - } - else if (type == Type.PRINTHEADERS) - { - printHeadersRecord = new PrintHeadersRecord(r); - settings.setPrintHeaders(printHeadersRecord.getPrintHeaders()); - } - else if (type == Type.WINDOW2) - { - window2Record = null; + case CONTINUE: + // don't know what this is for, but keep hold of it anyway + continueRecord = new ContinueRecord(r); + break; - if (workbookBof.isBiff8()) - { - window2Record = new Window2Record(r); - } - else - { - window2Record = new Window2Record(r, Window2Record.biff7); - } + case NOTE: + if (!workbookSettings.getDrawingsDisabled()) { + NoteRecord nr = new NoteRecord(r); - settings.setShowGridLines(window2Record.getShowGridLines()); - settings.setDisplayZeroValues(window2Record.getDisplayZeroValues()); - settings.setSelected(true); - settings.setPageBreakPreviewMode(window2Record.isPageBreakPreview()); - } - else if (type == Type.PANE) - { - PaneRecord pr = new PaneRecord(r); + // Get the comment for the object id + Comment comment = comments.remove(nr.getObjectId()); - if (window2Record != null && - window2Record.getFrozen()) - { - settings.setVerticalFreeze(pr.getRowsVisible()); - settings.setHorizontalFreeze(pr.getColumnsVisible()); - } - } - else if (type == Type.CONTINUE) - { - // don't know what this is for, but keep hold of it anyway - continueRecord = new ContinueRecord(r); - } - else if (type == Type.NOTE) - { - if (!workbookSettings.getDrawingsDisabled()) - { - NoteRecord nr = new NoteRecord(r); + if (comment == null) + LOGGER.warn(" cannot find comment for note id " + + nr.getObjectId() + "...ignoring"); + else { + comment.setNote(nr); - // Get the comment for the object id - Comment comment = (Comment) comments.remove - (new Integer(nr.getObjectId())); + drawings.add(comment); - if (comment == null) - { - logger.warn(" cannot find comment for note id " + - nr.getObjectId() + "...ignoring"); + addCellComment(comment.getColumn(), + comment.getRow(), + comment.getText(), + comment.getWidth(), + comment.getHeight()); + } } - else - { - comment.setNote(nr); + break; - drawings.add(comment); + case ARRAY: + break; - addCellComment(comment.getColumn(), - comment.getRow(), - comment.getText(), - comment.getWidth(), - comment.getHeight()); - } + case PROTECT: { + ProtectRecord pr = new ProtectRecord(r); + settings.setProtected(pr.isProtected()); + break; } - } - else if (type == Type.ARRAY) - { - ; - } - else if (type == Type.PROTECT) - { - ProtectRecord pr = new ProtectRecord(r); - settings.setProtected(pr.isProtected()); - } - else if (type == Type.SHAREDFORMULA) - { - if (sharedFormula == null) - { - logger.warn("Shared template formula is null - " + - "trying most recent formula template"); - SharedFormulaRecord lastSharedFormula = - (SharedFormulaRecord) sharedFormulas.get(sharedFormulas.size() - 1); - - if (lastSharedFormula != null) - { - sharedFormula = lastSharedFormula.getTemplateFormula(); - } - } - - SharedFormulaRecord sfr = new SharedFormulaRecord - (r, sharedFormula, workbook, workbook, sheet); - sharedFormulas.add(sfr); - sharedFormula = null; - } - else if (type == Type.FORMULA || type == Type.FORMULA2) - { - FormulaRecord fr = new FormulaRecord(r, - excelFile, - formattingRecords, - workbook, - workbook, - sheet, - workbookSettings); - - if (fr.isShared()) - { - BaseSharedFormulaRecord prevSharedFormula = sharedFormula; - sharedFormula = (BaseSharedFormulaRecord) fr.getFormula(); - // See if it fits in any of the shared formulas - sharedFormulaAdded = addToSharedFormulas(sharedFormula); + case SHAREDFORMULA: + if (sharedFormula == null) { + LOGGER.warn("Shared template formula is null - " + + "trying most recent formula template"); + SharedFormulaRecord lastSharedFormula + = sharedFormulas.get(sharedFormulas.size() - 1); - if (sharedFormulaAdded) - { - sharedFormula = prevSharedFormula; - } - - // If we still haven't added the previous base shared formula, - // revert it to an ordinary formula and add it to the cell - if (!sharedFormulaAdded && prevSharedFormula != null) - { - // Do nothing. It's possible for the biff file to contain the - // record sequence - // FORMULA-SHRFMLA-FORMULA-SHRFMLA-FORMULA-FORMULA-FORMULA - // ie. it first lists all the formula templates, then it - // lists all the individual formulas - addCell(revertSharedFormula(prevSharedFormula)); + if (lastSharedFormula != null) + sharedFormula = lastSharedFormula.getTemplateFormula(); } - } - else - { - Cell cell = fr.getFormula(); - try - { - // See if the formula evaluates to date - if (fr.getFormula().getType() == CellType.NUMBER_FORMULA) - { - NumberFormulaRecord nfr = (NumberFormulaRecord) fr.getFormula(); - if (formattingRecords.isDate(nfr.getXFIndex())) - { - cell = new DateFormulaRecord(nfr, - formattingRecords, - workbook, - workbook, - nineteenFour, - sheet); + SharedFormulaRecord sfr = new SharedFormulaRecord(r, sharedFormula, workbook, workbook, sheet); + sharedFormulas.add(sfr); + sharedFormula = null; + break; + + case FORMULA: + case FORMULA2: { + FormulaRecord fr = new FormulaRecord(r, + excelFile, + formattingRecords, + workbook, + workbook, + sheet, + workbookSettings, + workbook.getWorkbookBof().isBiff8()); + if (fr.isShared()) { + BaseSharedFormulaRecord prevSharedFormula = sharedFormula; + sharedFormula = (BaseSharedFormulaRecord) fr.getFormula(); + + // See if it fits in any of the shared formulas + sharedFormulaAdded = addToSharedFormulas(sharedFormula); + + if (sharedFormulaAdded) + sharedFormula = prevSharedFormula; + + // If we still haven't added the previous base shared formula, + // revert it to an ordinary formula and add it to the cell + if (!sharedFormulaAdded && prevSharedFormula != null) + // Do nothing. It's possible for the biff file to contain the + // record sequence + // FORMULA-SHRFMLA-FORMULA-SHRFMLA-FORMULA-FORMULA-FORMULA + // ie. it first lists all the formula templates, then it + // lists all the individual formulas + addCell(revertSharedFormula(prevSharedFormula)); + } else { + Cell cell = fr.getFormula(); + try { + // See if the formula evaluates to date + if (fr.getFormula().getType() == CellType.NUMBER_FORMULA) { + NumberFormulaRecord nfr = (NumberFormulaRecord) fr.getFormula(); + if (formattingRecords.isDate(nfr.getXFIndex())) + cell = new DateFormulaRecord(nfr, + formattingRecords, + workbook, + workbook, + nineteenFour, + sheet); } - } - - addCell(cell); - } - catch (FormulaException e) - { - // Something has gone wrong trying to read the formula data eg. it - // might be unsupported biff7 data - logger.warn - (CellReferenceHelper.getCellReference - (cell.getColumn(), cell.getRow()) + " " + e.getMessage()); - } - } - } - else if (type == Type.LABEL) - { - LabelRecord lr = null; - - if (workbookBof.isBiff8()) - { - lr = new LabelRecord(r, formattingRecords, sheet, workbookSettings); - } - else - { - lr = new LabelRecord(r, formattingRecords, sheet, workbookSettings, - LabelRecord.biff7); - } - addCell(lr); - } - else if (type == Type.RSTRING) - { - RStringRecord lr = null; - - // RString records are obsolete in biff 8 - Assert.verify(!workbookBof.isBiff8()); - lr = new RStringRecord(r, formattingRecords, - sheet, workbookSettings, - RStringRecord.biff7); - addCell(lr); - } - else if (type == Type.NAME) - { - ; - } - else if (type == Type.PASSWORD) - { - PasswordRecord pr = new PasswordRecord(r); - settings.setPasswordHash(pr.getPasswordHash()); - } - else if (type == Type.ROW) - { - RowRecord rr = new RowRecord(r); - - // See if the row has anything funny about it - if (!rr.isDefaultHeight() || - !rr.matchesDefaultFontHeight() || - rr.isCollapsed() || - rr.hasDefaultFormat() || - rr.getOutlineLevel() != 0) - { - rowProperties.add(rr); - } - } - else if (type == Type.BLANK) - { - if (!workbookSettings.getIgnoreBlanks()) - { - BlankCell bc = new BlankCell(r, formattingRecords, sheet); - addCell(bc); - } - } - else if (type == Type.MULBLANK) - { - if (!workbookSettings.getIgnoreBlanks()) - { - MulBlankRecord mulblank = new MulBlankRecord(r); - // Get the individual cell records from the multiple record - int num = mulblank.getNumberOfColumns(); - - for (int i = 0; i < num; i++) - { - int ixf = mulblank.getXFIndex(i); - - MulBlankCell mbc = new MulBlankCell - (mulblank.getRow(), - mulblank.getFirstColumn() + i, - ixf, - formattingRecords, - sheet); - - addCell(mbc); - } - } - } - else if (type == Type.SCL) - { - SCLRecord scl = new SCLRecord(r); - settings.setZoomFactor(scl.getZoomFactor()); - } - else if (type == Type.COLINFO) - { - ColumnInfoRecord cir = new ColumnInfoRecord(r); - columnInfosArray.add(cir); - } - else if (type == Type.HEADER) - { - HeaderRecord hr = null; - if (workbookBof.isBiff8()) - { - hr = new HeaderRecord(r, workbookSettings); - } - else - { - hr = new HeaderRecord(r, workbookSettings, HeaderRecord.biff7); - } - - HeaderFooter header = new HeaderFooter(hr.getHeader()); - settings.setHeader(header); - } - else if (type == Type.FOOTER) - { - FooterRecord fr = null; - if (workbookBof.isBiff8()) - { - fr = new FooterRecord(r, workbookSettings); - } - else - { - fr = new FooterRecord(r, workbookSettings, FooterRecord.biff7); - } - - HeaderFooter footer = new HeaderFooter(fr.getFooter()); - settings.setFooter(footer); - } - else if (type == Type.SETUP) - { - SetupRecord sr = new SetupRecord(r); - - // If the setup record has its not initialized bit set, then - // use the sheet settings default values - if (sr.getInitialized()) - { - if (sr.isPortrait()) - { - settings.setOrientation(PageOrientation.PORTRAIT); + addCell(cell); + } catch (FormulaException e) { + // Something has gone wrong trying to read the formula data eg. it + // might be unsupported biff7 data + LOGGER.warn(CellReferenceHelper + .getCellReference(cell.getColumn(), cell.getRow()) + " " + e + .getMessage()); + } } - else - { - settings.setOrientation(PageOrientation.LANDSCAPE); + break; + } + + case LABEL: + addCell(workbookBof.isBiff8() + ? new LabelRecord(r, formattingRecords, sheet) + : new LabelRecord(r, formattingRecords, sheet, workbookSettings, + LabelRecord.biff7)); + break; + + case RSTRING: + // RString records are obsolete in biff 8 + Assert.verify(!workbookBof.isBiff8()); + RStringRecord lr = new RStringRecord(r, formattingRecords, + sheet, workbookSettings, + RStringRecord.biff7); + addCell(lr); + break; + + case NAME: + break; + + case PASSWORD: { + PasswordRecord pr = new PasswordRecord(r); + settings.setPasswordHash(pr.getPasswordHash()); + break; + } + + case ROW: + RowRecord rr = new RowRecord(r); + // See if the row has anything funny about it + if (!rr.isDefaultHeight() + || !rr.matchesDefaultFontHeight() + || rr.isCollapsed() + || rr.hasDefaultFormat() + || rr.getOutlineLevel() != 0) + rowProperties.add(rr); + break; + + case BLANK: + if (!workbookSettings.getIgnoreBlanks()) + addCell(new BlankCell(r, formattingRecords, sheet)); + break; + + case MULBLANK: + if (!workbookSettings.getIgnoreBlanks()) { + MulBlankRecord mulblank = new MulBlankRecord(r); + + // Get the individual cell records from the multiple record + int num = mulblank.getNumberOfColumns(); + + for (int i = 0; i < num; i++) { + int ixf = mulblank.getXFIndex(i); + + MulBlankCell mbc = new MulBlankCell(mulblank.getRow(), + mulblank.getFirstColumn() + i, + ixf, + formattingRecords, + sheet); + + addCell(mbc); + } } - if (sr.isRightDown()) - { + break; + + case SCL: + SCLRecord scl = new SCLRecord(r); + settings.setZoomFactor(scl.getZoomFactor()); + break; + + case COLINFO: + ColumnInfoRecord cir = new ColumnInfoRecord(r); + columnInfosArray.add(cir); + break; + + case HEADER: { + HeaderRecord hr = workbookBof.isBiff8() + ? new HeaderRecord(r) + : new HeaderRecord(r, workbookSettings, HeaderRecord.biff7); + HeaderFooter header = new HeaderFooter(hr.getHeader()); + settings.setHeader(header); + break; + } + + case FOOTER: { + FooterRecord fr = workbookBof.isBiff8() + ? new FooterRecord(r) + : new FooterRecord(r, workbookSettings, FooterRecord.biff7); + HeaderFooter footer = new HeaderFooter(fr.getFooter()); + settings.setFooter(footer); + break; + } + + case SETUP: + SetupRecord sr = new SetupRecord(r); + // If the setup record has its not initialized bit set, then + // use the sheet settings default values + if (sr.getInitialized()) { + if (sr.isPortrait()) + settings.setOrientation(PageOrientation.PORTRAIT); + else + settings.setOrientation(PageOrientation.LANDSCAPE); + if (sr.isRightDown()) settings.setPageOrder(PageOrder.RIGHT_THEN_DOWN); - } - else - { + else settings.setPageOrder(PageOrder.DOWN_THEN_RIGHT); + settings.setPaperSize(PaperSize.getPaperSize(sr.getPaperSize())); + settings.setHeaderMargin(sr.getHeaderMargin()); + settings.setFooterMargin(sr.getFooterMargin()); + settings.setScaleFactor(sr.getScaleFactor()); + settings.setPageStart(sr.getPageStart()); + settings.setFitWidth(sr.getFitWidth()); + settings.setFitHeight(sr.getFitHeight()); + settings.setHorizontalPrintResolution(sr + .getHorizontalPrintResolution()); + settings.setVerticalPrintResolution(sr.getVerticalPrintResolution()); + settings.setCopies(sr.getCopies()); + + if (workspaceOptions != null) + settings.setFitToPages(workspaceOptions.getFitToPages()); } - settings.setPaperSize(PaperSize.getPaperSize(sr.getPaperSize())); - settings.setHeaderMargin(sr.getHeaderMargin()); - settings.setFooterMargin(sr.getFooterMargin()); - settings.setScaleFactor(sr.getScaleFactor()); - settings.setPageStart(sr.getPageStart()); - settings.setFitWidth(sr.getFitWidth()); - settings.setFitHeight(sr.getFitHeight()); - settings.setHorizontalPrintResolution - (sr.getHorizontalPrintResolution()); - settings.setVerticalPrintResolution(sr.getVerticalPrintResolution()); - settings.setCopies(sr.getCopies()); - - if (workspaceOptions != null) - { - settings.setFitToPages(workspaceOptions.getFitToPages()); - } - } - } - else if (type == Type.WSBOOL) - { - workspaceOptions = new WorkspaceInformationRecord(r); - } - else if (type == Type.DEFCOLWIDTH) - { - DefaultColumnWidthRecord dcwr = new DefaultColumnWidthRecord(r); - settings.setDefaultColumnWidth(dcwr.getWidth()); - } - else if (type == Type.DEFAULTROWHEIGHT) - { - DefaultRowHeightRecord drhr = new DefaultRowHeightRecord(r); - if (drhr.getHeight() != 0) - { - settings.setDefaultRowHeight(drhr.getHeight()); - } - } - else if (type == Type.CONDFMT) - { - ConditionalFormatRangeRecord cfrr = - new ConditionalFormatRangeRecord(r); - condFormat = new ConditionalFormat(cfrr); - conditionalFormats.add(condFormat); - } - else if (type == Type.CF) - { - ConditionalFormatRecord cfr = new ConditionalFormatRecord(r); - condFormat.addCondition(cfr); - } - else if (type == Type.FILTERMODE) - { - filterMode = new FilterModeRecord(r); - } - else if (type == Type.AUTOFILTERINFO) - { - autoFilterInfo = new AutoFilterInfoRecord(r); - } - else if (type == Type.AUTOFILTER) - { - if (!workbookSettings.getAutoFilterDisabled()) - { - AutoFilterRecord af = new AutoFilterRecord(r); + break; + + case WSBOOL: + workspaceOptions = new WorkspaceInformationRecord(r); + break; + + case DEFCOLWIDTH: + DefaultColumnWidthRecord dcwr = new DefaultColumnWidthRecord(r); + settings.setDefaultColumnWidth(dcwr.getWidth()); + break; + + case DEFAULTROWHEIGHT: + DefaultRowHeightRecord drhr = new DefaultRowHeightRecord(r); + if (drhr.getHeight() != 0) + settings.setDefaultRowHeight(drhr.getHeight()); + break; + + case CONDFMT: + ConditionalFormatRangeRecord cfrr + = new ConditionalFormatRangeRecord(r); + condFormat = new ConditionalFormat(cfrr); + conditionalFormats.add(condFormat); + break; + + case CF: + ConditionalFormatRecord cfr = new ConditionalFormatRecord(r); + condFormat.addCondition(cfr); + break; + + case FILTERMODE: + filterMode = new FilterModeRecord(r); + break; + + case AUTOFILTERINFO: + autoFilterInfo = new AutoFilterInfoRecord(r); + break; + + case AUTOFILTER: + if (!workbookSettings.getAutoFilterDisabled()) { + AutoFilterRecord af = new AutoFilterRecord(r); + + if (autoFilter == null) { + autoFilter = new AutoFilter(filterMode, autoFilterInfo); + filterMode = null; + autoFilterInfo = null; + } - if (autoFilter == null) - { - autoFilter = new AutoFilter(filterMode, autoFilterInfo); - filterMode = null; - autoFilterInfo = null; + autoFilter.add(af); } - - autoFilter.add(af); - } - } - else if (type == Type.LEFTMARGIN) - { - MarginRecord m = new LeftMarginRecord(r); - settings.setLeftMargin(m.getMargin()); - } - else if (type == Type.RIGHTMARGIN) - { - MarginRecord m = new RightMarginRecord(r); - settings.setRightMargin(m.getMargin()); - } - else if (type == Type.TOPMARGIN) - { - MarginRecord m = new TopMarginRecord(r); - settings.setTopMargin(m.getMargin()); - } - else if (type == Type.BOTTOMMARGIN) - { - MarginRecord m = new BottomMarginRecord(r); - settings.setBottomMargin(m.getMargin()); - } - else if (type == Type.HORIZONTALPAGEBREAKS) - { - HorizontalPageBreaksRecord dr = null; - - if (workbookBof.isBiff8()) - { - dr = new HorizontalPageBreaksRecord(r); - } - else - { - dr = new HorizontalPageBreaksRecord - (r, HorizontalPageBreaksRecord.biff7); - } - rowBreaks = dr.getRowBreaks(); - } - else if (type == Type.VERTICALPAGEBREAKS) - { - VerticalPageBreaksRecord dr = null; - - if (workbookBof.isBiff8()) - { - dr = new VerticalPageBreaksRecord(r); - } - else - { - dr = new VerticalPageBreaksRecord - (r, VerticalPageBreaksRecord.biff7); - } - columnBreaks = dr.getColumnBreaks(); - } - else if (type == Type.PLS) - { - plsRecord = new PLSRecord(r); - - // Check for Continue records - while (excelFile.peek().getType() == Type.CONTINUE) - { - r.addContinueRecord(excelFile.next()); - } - } - else if (type == Type.DVAL) - { - if (!workbookSettings.getCellValidationDisabled()) - { - DataValidityListRecord dvlr = new DataValidityListRecord(r); - if (dvlr.getObjectId() == -1) - { - if (msoRecord != null && objRecord == null) - { - // there is a drop down associated with this data validation - if (drawingData == null) - { - drawingData = new DrawingData(); - } - - Drawing2 d2 = new Drawing2(msoRecord, drawingData, - workbook.getDrawingGroup()); - drawings.add(d2); - msoRecord = null; - + break; + + case LEFTMARGIN: { + MarginRecord m = new LeftMarginRecord(r); + settings.setLeftMargin(m.getMargin()); + break; + } + + case RIGHTMARGIN: { + MarginRecord m = new RightMarginRecord(r); + settings.setRightMargin(m.getMargin()); + break; + } + + case TOPMARGIN: { + MarginRecord m = new TopMarginRecord(r); + settings.setTopMargin(m.getMargin()); + break; + } + + case BOTTOMMARGIN: { + MarginRecord m = new BottomMarginRecord(r); + settings.setBottomMargin(m.getMargin()); + break; + } + + case HORIZONTALPAGEBREAKS: + rowBreaks = workbookBof.isBiff8() + ? new HorizontalPageBreaksRecord(r) + : new HorizontalPageBreaksRecord(r, HorizontalPageBreaksRecord.biff7); + break; + + case VERTICALPAGEBREAKS: + columnBreaks = workbookBof.isBiff8() + ? new VerticalPageBreaksRecord(r) + : new VerticalPageBreaksRecord(r, VerticalPageBreaksRecord.biff7); + break; + + case PLS: + plsRecord = new PLSRecord(r); + // Check for Continue records + while (excelFile.peek().getType() == Type.CONTINUE) + r.addContinueRecord(excelFile.next()); + break; + + case DVAL: + if (!workbookSettings.getCellValidationDisabled()) { + DataValidityListRecord dvlr = new DataValidityListRecord(r); + if (dvlr.getObjectId() == -1) + if (msoRecord != null && objRecord == null) { + // there is a drop down associated with this data validation + if (drawingData == null) + drawingData = new DrawingData(); + + Drawing2 d2 = new Drawing2(msoRecord, drawingData, + workbook.getDrawingGroup()); + drawings.add(d2); + msoRecord = null; + + dataValidation = new DataValidation(dvlr); + } else + // no drop down + dataValidation = new DataValidation(dvlr); + else if (objectIds.contains(dvlr.getObjectId())) dataValidation = new DataValidation(dvlr); - } else - { - // no drop down - dataValidation = new DataValidation(dvlr); - } - } - else if (objectIds.contains(new Integer(dvlr.getObjectId()))) - { - dataValidation = new DataValidation(dvlr); - } - else - { - logger.warn("object id " + dvlr.getObjectId() + " referenced " + - " by data validity list record not found - ignoring"); - } - } - } - else if (type == Type.HCENTER) - { - CentreRecord hr = new CentreRecord(r); - settings.setHorizontalCentre(hr.isCentre()); - } - else if (type == Type.VCENTER) - { - CentreRecord vc = new CentreRecord(r); - settings.setVerticalCentre(vc.isCentre()); - } - else if (type == Type.DV) - { - if (!workbookSettings.getCellValidationDisabled()) - { - DataValiditySettingsRecord dvsr = - new DataValiditySettingsRecord(r, - workbook, - workbook, - workbook.getSettings()); - if (dataValidation != null) - { - dataValidation.add(dvsr); - addCellValidation(dvsr.getFirstColumn(), - dvsr.getFirstRow(), - dvsr.getLastColumn(), - dvsr.getLastRow(), - dvsr); - } - else - { - logger.warn("cannot add data validity settings"); - } - } - } - else if (type == Type.OBJ) - { - objRecord = new ObjRecord(r); - - if (!workbookSettings.getDrawingsDisabled()) - { - // sometimes excel writes out continue records instead of drawing - // records, so forcibly hack the stashed continue record into - // a drawing record - if (msoRecord == null && continueRecord != null) - { - logger.warn("Cannot find drawing record - using continue record"); - msoRecord = new MsoDrawingRecord(continueRecord.getRecord()); - continueRecord = null; - } - handleObjectRecord(objRecord, msoRecord, comments); - objectIds.add(new Integer(objRecord.getObjectId())); - } - - // Save chart handling until the chart BOF record appears - if (objRecord.getType() != ObjRecord.CHART) - { - objRecord = null; - msoRecord = null; - } - } - else if (type == Type.MSODRAWING) - { - if (!workbookSettings.getDrawingsDisabled()) - { - if (msoRecord != null) - { - // For form controls, a rogue MSODRAWING record can crop up - // after the main one. Add these into the drawing data - drawingData.addRawData(msoRecord.getData()); + LOGGER.warn("object id " + dvlr.getObjectId() + " referenced " + + " by data validity list record not found - ignoring"); } - msoRecord = new MsoDrawingRecord(r); - - if (firstMsoRecord) - { - msoRecord.setFirst(); - firstMsoRecord = false; + break; + + case HCENTER: { + CentreRecord hr = new CentreRecord(r); + settings.setHorizontalCentre(hr.isCentre()); + break; + } + + case VCENTER: + CentreRecord vc = new CentreRecord(r); + settings.setVerticalCentre(vc.isCentre()); + break; + + case DV: + if (!workbookSettings.getCellValidationDisabled()) { + DataValiditySettingsRecord dvsr + = new DataValiditySettingsRecord(r, + workbook, + workbook, + workbook.getSettings()); + if (dataValidation != null) { + dataValidation.add(dvsr); + addCellValidation(dvsr.getFirstColumn(), + dvsr.getFirstRow(), + dvsr.getLastColumn(), + dvsr.getLastRow(), + dvsr); + } else + LOGGER.warn("cannot add data validity settings"); } - } - } - else if (type == Type.BUTTONPROPERTYSET) - { - buttonPropertySet = new ButtonPropertySetRecord(r); - } - else if (type == Type.CALCMODE) - { - CalcModeRecord cmr = new CalcModeRecord(r); - settings.setAutomaticFormulaCalculation(cmr.isAutomatic()); - } - else if (type == Type.SAVERECALC) - { - SaveRecalcRecord cmr = new SaveRecalcRecord(r); - settings.setRecalculateFormulasBeforeSave(cmr.getRecalculateOnSave()); - } - else if (type == Type.GUTS) - { - GuttersRecord gr = new GuttersRecord(r); - maxRowOutlineLevel = - gr.getRowOutlineLevel() > 0 ? gr.getRowOutlineLevel() - 1 : 0; - maxColumnOutlineLevel = - gr.getColumnOutlineLevel() > 0 ? gr.getRowOutlineLevel() - 1 : 0; - } - else if (type == Type.BOF) - { - BOFRecord br = new BOFRecord(r); - Assert.verify(!br.isWorksheet()); - - int startpos = excelFile.getPos() - r.getLength() - 4; - - // Skip to the end of the nested bof - // Thanks to Rohit for spotting this - Record r2 = excelFile.next(); - while (r2.getCode() != Type.EOF.value) - { - r2 = excelFile.next(); - } - - if (br.isChart()) - { - if (!workbook.getWorkbookBof().isBiff8()) - { - logger.warn("only biff8 charts are supported"); + break; + + case OBJ: + objRecord = new ObjRecord(r); + if (!workbookSettings.getDrawingsDisabled()) { + // sometimes excel writes out continue records instead of drawing + // records, so forcibly hack the stashed continue record into + // a drawing record + if (msoRecord == null && continueRecord != null) { + LOGGER.warn("Cannot find drawing record - using continue record"); + msoRecord = new MsoDrawingRecord(continueRecord.getRecord()); + continueRecord = null; + } + handleObjectRecord(objRecord, msoRecord, comments); + objectIds.add(objRecord.getObjectId()); + } // Save chart handling until the chart BOF record appears + if (objRecord.getType() != ObjRecord.CHART) { + objRecord = null; + msoRecord = null; } - else - { - if (drawingData == null) - { - drawingData = new DrawingData(); + break; + + case MSODRAWING: + if (!workbookSettings.getDrawingsDisabled()) { + if (msoRecord != null) + // For form controls, a rogue MSODRAWING record can crop up + // after the main one. Add these into the drawing data + drawingData.addRawData(msoRecord.getData()); + msoRecord = new MsoDrawingRecord(r); + + if (firstMsoRecord) { + msoRecord.setFirst(); + firstMsoRecord = false; } + } + break; + + case BUTTONPROPERTYSET: + buttonPropertySet = new ButtonPropertySetRecord(r); + break; + + case CALCMODE: { + CalcModeRecord cmr = new CalcModeRecord(r); + settings.setAutomaticFormulaCalculation(cmr.isAutomatic()); + break; + } + + case SAVERECALC: { + SaveRecalcRecord cmr = new SaveRecalcRecord(r); + settings.setRecalculateFormulasBeforeSave(cmr.getRecalculateOnSave()); + break; + } + + case GUTS: + GuttersRecord gr = new GuttersRecord(r); + maxRowOutlineLevel + = gr.getRowOutlineLevel() > 0 ? gr.getRowOutlineLevel() - 1 : 0; + maxColumnOutlineLevel + = gr.getColumnOutlineLevel() > 0 ? gr.getRowOutlineLevel() - 1 : 0; + break; + + case BOF: { + BOFRecord br = new BOFRecord(r); + Assert.verify(!br.isWorksheet()); + int startpos = excelFile.getPos() - r.getLength() - 4; + // Skip to the end of the nested bof + // Thanks to Rohit for spotting this + Record r2 = excelFile.next(); + while (r2.getCode() != Type.EOF.value) + r2 = excelFile.next(); + if (br.isChart()) { + if (!workbook.getWorkbookBof().isBiff8()) + LOGGER.warn("only biff8 charts are supported"); + else { + if (drawingData == null) + drawingData = new DrawingData(); - if (!workbookSettings.getDrawingsDisabled()) - { - Chart chart = new Chart(msoRecord, objRecord, drawingData, - startpos, excelFile.getPos(), - excelFile, workbookSettings); - charts.add(chart); + if (!workbookSettings.getDrawingsDisabled()) { + Chart chart = new Chart(msoRecord, objRecord, drawingData, + startpos, excelFile.getPos(), + excelFile, workbookSettings); + charts.add(chart); - if (workbook.getDrawingGroup() != null) - { - workbook.getDrawingGroup().add(chart); + if (workbook.getDrawingGroup() != null) + workbook.getDrawingGroup().add(chart); } } - } - // Reset the drawing records - msoRecord = null; - objRecord = null; + // Reset the drawing records + msoRecord = null; + objRecord = null; + } // If this worksheet is just a chart, then the EOF reached + // represents the end of the sheet as well as the end of the chart + if (sheetBof.isChart()) + cont = false; + break; } - // If this worksheet is just a chart, then the EOF reached - // represents the end of the sheet as well as the end of the chart - if (sheetBof.isChart()) - { + case EOF: cont = false; - } - } - else if (type == Type.EOF) - { - cont = false; + break; } } // Restore the file to its accurate position excelFile.restorePos(); - // Add any out of bounds cells - if (outOfBoundsCells.size() > 0) - { - handleOutOfBoundsCells(); - } - // Add all the shared formulas to the sheet as individual formulas - Iterator i = sharedFormulas.iterator(); - - while (i.hasNext()) - { - SharedFormulaRecord sfr = (SharedFormulaRecord) i.next(); - + for (SharedFormulaRecord sfr : sharedFormulas) { Cell[] sfnr = sfr.getFormulas(formattingRecords, nineteenFour); - for (int sf = 0; sf < sfnr.length; sf++) - { - addCell(sfnr[sf]); - } + for (Cell cell : sfnr) + addCell(cell); } // If the last base shared formula wasn't added to the sheet, then @@ -1218,7 +954,7 @@ else if (type == Type.EOF) // Check that the comments hash is empty if (!comments.isEmpty()) { - logger.warn("Not all comments have a corresponding Note record"); + LOGGER.warn("Not all comments have a corresponding Note record"); } } @@ -1232,13 +968,9 @@ else if (type == Type.EOF) private boolean addToSharedFormulas(BaseSharedFormulaRecord fr) { boolean added = false; - SharedFormulaRecord sfr = null; for (int i=0, size=sharedFormulas.size(); i getCells() { - return cells; + return Collections.unmodifiableMap(cells); } /** @@ -1338,7 +1071,7 @@ final Cell[][] getCells() * * @return the row properties */ - final ArrayList getRowProperties() + final List getRowProperties() { return rowProperties; } @@ -1348,7 +1081,7 @@ final ArrayList getRowProperties() * * @return the column information */ - final ArrayList getColumnInfosArray() + final List getColumnInfosArray() { return columnInfosArray; } @@ -1358,7 +1091,7 @@ final ArrayList getColumnInfosArray() * * @return the hyperlinks */ - final ArrayList getHyperlinks() + final List getHyperlinks() { return hyperlinks; } @@ -1368,7 +1101,7 @@ final ArrayList getHyperlinks() * * @return the conditional formatting */ - final ArrayList getConditionalFormats() + final List getConditionalFormats() { return conditionalFormats; } @@ -1388,7 +1121,7 @@ final AutoFilter getAutoFilter() * * @return the charts */ - final ArrayList getCharts() + final List getCharts() { return charts; } @@ -1398,7 +1131,7 @@ final ArrayList getCharts() * * @return the drawings */ - final ArrayList getDrawings() + final List getDrawings() { return drawings; } @@ -1418,7 +1151,7 @@ final DataValidation getDataValidation() * * @return the ranges */ - final Range[] getMergedCells() + final List getMergedCells() { return mergedCells; } @@ -1438,7 +1171,7 @@ final SheetSettings getSettings() * * @return the row breaks */ - final int[] getRowBreaks() + final HorizontalPageBreaksRecord getRowBreaks() { return rowBreaks; } @@ -1448,7 +1181,7 @@ final int[] getRowBreaks() * * @return the column breaks */ - final int[] getColumnBreaks() + final VerticalPageBreaksRecord getColumnBreaks() { return columnBreaks; } @@ -1498,23 +1231,13 @@ private void addCellComment(int col, double width, double height) { - Cell c = cells[row][col]; - if (c == null) - { - logger.warn("Cell at " + CellReferenceHelper.getCellReference(col, row) + - " not present - adding a blank"); - MulBlankCell mbc = new MulBlankCell(row, - col, - 0, - formattingRecords, - sheet); - CellFeatures cf = new CellFeatures(); - cf.setReadComment(text, width, height); - mbc.setCellFeatures(cf); - addCell(mbc); - - return; - } + Cell c = cells.computeIfAbsent( + new CellCoordinate(col, row), + coord -> new MulBlankCell( + coord, + 0, + formattingRecords, + sheet)); if (c instanceof CellFeaturesAccessor) { @@ -1531,7 +1254,7 @@ private void addCellComment(int col, } else { - logger.warn("Not able to add comment to cell type " + + LOGGER.warn("Not able to add comment to cell type " + c.getClass().getName() + " at " + CellReferenceHelper.getCellReference(col, row)); } @@ -1556,15 +1279,9 @@ private void addCellValidation(int col1, { for (int col = col1; col <= col2; col++) { - Cell c = null; + Cell c = cells.get(new CellCoordinate(col, row)); - if (cells.length > row && cells[row].length > col) - { - c = cells[row][col]; - } - - if (c == null) - { + if (c == null) { MulBlankCell mbc = new MulBlankCell(row, col, 0, @@ -1574,9 +1291,8 @@ private void addCellValidation(int col1, cf.setValidationSettings(dvsr); mbc.setCellFeatures(cf); addCell(mbc); - } - else if (c instanceof CellFeaturesAccessor) - { // Check to see if the cell already contains a comment + } else if (c instanceof CellFeaturesAccessor) { + // Check to see if the cell already contains a comment CellFeaturesAccessor cv = (CellFeaturesAccessor) c; CellFeatures cf = cv.getCellFeatures(); @@ -1590,7 +1306,7 @@ else if (c instanceof CellFeaturesAccessor) } else { - logger.warn("Not able to add comment to cell type " + + LOGGER.warn("Not able to add comment to cell type " + c.getClass().getName() + " at " + CellReferenceHelper.getCellReference(col, row)); } @@ -1607,11 +1323,11 @@ else if (c instanceof CellFeaturesAccessor) */ private void handleObjectRecord(ObjRecord objRecord, MsoDrawingRecord msoRecord, - HashMap comments) + HashMap comments) { if (msoRecord == null) { - logger.warn("Object record is not associated with a drawing " + + LOGGER.warn("Object record is not associated with a drawing " + " record - ignoring"); return; } @@ -1643,7 +1359,12 @@ private void handleObjectRecord(ObjRecord objRecord, drawingData = new DrawingData(); } - Comment comment = new Comment(msoRecord, + Comment comment = workbookBof.isBiff8() + ? new CommentBiff8(msoRecord, + objRecord, + drawingData, + workbook.getDrawingGroup()) + : new CommentBiff7(msoRecord, objRecord, drawingData, workbook.getDrawingGroup(), @@ -1674,7 +1395,7 @@ private void handleObjectRecord(ObjRecord objRecord, comment.setFormatting(formatting); } - comments.put(new Integer(comment.getObjectId()), comment); + comments.put(comment.getObjectId(), comment); return; } @@ -1794,7 +1515,7 @@ private void handleObjectRecord(ObjRecord objRecord, // Non-supported types which have multiple record types if (objRecord.getType() == ObjRecord.TEXT) { - logger.warn(objRecord.getType() + " Object on sheet \"" + + LOGGER.warn(objRecord.getType() + " Object on sheet \"" + sheet.getName() + "\" not supported - omitting"); @@ -1831,7 +1552,7 @@ private void handleObjectRecord(ObjRecord objRecord, // Handle other types if (objRecord.getType() != ObjRecord.CHART) { - logger.warn(objRecord.getType() + " Object on sheet \"" + + LOGGER.warn(objRecord.getType() + " Object on sheet \"" + sheet.getName() + "\" not supported - omitting"); @@ -1849,12 +1570,11 @@ private void handleObjectRecord(ObjRecord objRecord, objRecord); } - return; } } catch (DrawingDataException e) { - logger.warn(e.getMessage() + + LOGGER.warn(e.getMessage() + "...disabling drawings for the remainder of the workbook"); workbookSettings.setDrawingsDisabled(true); } @@ -1868,67 +1588,6 @@ DrawingData getDrawingData() return drawingData; } - /** - * Handle any cells which fall outside of the bounds specified within - * the dimension record - */ - private void handleOutOfBoundsCells() - { - int resizedRows = numRows; - int resizedCols = numCols; - - // First, determine the new bounds - for (Iterator i = outOfBoundsCells.iterator() ; i.hasNext() ;) - { - Cell cell = (Cell) i.next(); - resizedRows = Math.max(resizedRows, cell.getRow() + 1); - resizedCols = Math.max(resizedCols, cell.getColumn() + 1); - } - - // There used to be a warning here about exceeding the sheet dimensions, - // but removed it when I added the ability to perform data validation - // on entire rows or columns - in which case it would blow out any - // existing dimensions - - // Resize the columns, if necessary - if (resizedCols > numCols) - { - for (int r = 0 ; r < numRows ; r++) - { - Cell[] newRow = new Cell[resizedCols]; - Cell[] oldRow = cells[r]; - System.arraycopy(oldRow, 0, newRow, 0, oldRow.length); - cells[r] = newRow; - } - } - - // Resize the rows, if necessary - if (resizedRows > numRows) - { - Cell[][] newCells = new Cell[resizedRows][]; - System.arraycopy(cells, 0, newCells, 0, cells.length); - cells = newCells; - - // Create the new rows - for (int i = numRows; i < resizedRows; i++) - { - newCells[i] = new Cell[resizedCols]; - } - } - - numRows = resizedRows; - numCols = resizedCols; - - // Now add all the out of bounds cells into the new cells - for (Iterator i = outOfBoundsCells.iterator(); i.hasNext(); ) - { - Cell cell = (Cell) i.next(); - addCell(cell); - } - - outOfBoundsCells.clear(); - } - /** * Accessor for the maximum column outline level * diff --git a/src/jxl/read/biff/SortRecord.java b/src/jxl/read/biff/SortRecord.java index 7d6358b..d9f9f3f 100644 --- a/src/jxl/read/biff/SortRecord.java +++ b/src/jxl/read/biff/SortRecord.java @@ -72,7 +72,7 @@ public SortRecord(Record r) } else { - col1Name = StringHelper.getUnicodeString(data, col1Size, curPos); + col1Name = StringHelper.getUnicodeString(data, curPos, col1Size); curPos += col1Size * 2; } @@ -85,7 +85,7 @@ public SortRecord(Record r) } else { - col2Name = StringHelper.getUnicodeString(data, col2Size, curPos); + col2Name = StringHelper.getUnicodeString(data, curPos, col2Size); curPos += col2Size * 2; } } @@ -102,7 +102,7 @@ public SortRecord(Record r) } else { - col3Name = StringHelper.getUnicodeString(data, col3Size, curPos); + col3Name = StringHelper.getUnicodeString(data, curPos, col3Size); curPos += col3Size * 2; } } diff --git a/src/jxl/read/biff/StringFormulaRecord.java b/src/jxl/read/biff/StringFormulaRecord.java index 804a5d5..3c5d573 100644 --- a/src/jxl/read/biff/StringFormulaRecord.java +++ b/src/jxl/read/biff/StringFormulaRecord.java @@ -20,48 +20,31 @@ package jxl.read.biff; import jxl.common.Assert; -import jxl.common.Logger; - - -import jxl.CellType; -import jxl.LabelCell; -import jxl.StringFormulaCell; -import jxl.WorkbookSettings; -import jxl.biff.FormattingRecords; -import jxl.biff.FormulaData; -import jxl.biff.IntegerHelper; -import jxl.biff.StringHelper; -import jxl.biff.Type; -import jxl.biff.WorkbookMethods; -import jxl.biff.formula.ExternalSheet; -import jxl.biff.formula.FormulaException; -import jxl.biff.formula.FormulaParser; +import jxl.*; +import jxl.biff.*; +import jxl.biff.formula.*; /** * A string formula's last calculated value */ -class StringFormulaRecord extends CellValue +abstract class StringFormulaRecord extends CellValue implements LabelCell, FormulaData, StringFormulaCell { - /** - * The logger - */ - private static Logger logger = Logger.getLogger(StringFormulaRecord.class); /** * The last calculated value of the formula */ - private String value; + protected String value; /** * A handle to the class needed to access external sheets */ - private ExternalSheet externalSheet; + private final ExternalSheet externalSheet; /** * A handle to the name table */ - private WorkbookMethods nameTable; + private final WorkbookMethods nameTable; /** * The formula as an excel string @@ -71,7 +54,9 @@ class StringFormulaRecord extends CellValue /** * The raw data */ - private byte[] data; + private final byte[] data; + + protected byte[] stringData; /** * Constructs this object from the raw data. We need to use the excelFile @@ -83,21 +68,19 @@ class StringFormulaRecord extends CellValue * @param es the external sheet records * @param nt the workbook * @param si the sheet impl - * @param ws the workbook settings */ - public StringFormulaRecord(Record t, File excelFile, + protected StringFormulaRecord(Record t, File excelFile, FormattingRecords fr, ExternalSheet es, WorkbookMethods nt, - SheetImpl si, - WorkbookSettings ws) + SheetImpl si) { super(t, fr, si); externalSheet = es; nameTable = nt; - data = getRecord().getData(); + data = t.getData(); int pos = excelFile.getPos(); @@ -112,7 +95,7 @@ public StringFormulaRecord(Record t, File excelFile, count++; } Assert.verify(count < 4, " @ " + pos); - byte[] stringData = nextRecord.getData(); + stringData = nextRecord.getData(); // Read in any continuation records nextRecord = excelFile.peek(); @@ -121,12 +104,11 @@ public StringFormulaRecord(Record t, File excelFile, nextRecord = excelFile.next(); // move the pointer within the data byte[] d = new byte[stringData.length + nextRecord.getLength() - 1]; System.arraycopy(stringData, 0, d, 0, stringData.length); - System.arraycopy(nextRecord.getData(), 1, d, + System.arraycopy(nextRecord.getData(), 1, d, stringData.length, nextRecord.getLength() - 1); stringData = d; nextRecord = excelFile.peek(); } - readString(stringData, ws); } /** @@ -140,7 +122,7 @@ public StringFormulaRecord(Record t, File excelFile, * @param si the sheet impl * @param ws the workbook settings */ - public StringFormulaRecord(Record t, + protected StringFormulaRecord(Record t, FormattingRecords fr, ExternalSheet es, WorkbookMethods nt, @@ -151,75 +133,16 @@ public StringFormulaRecord(Record t, externalSheet = es; nameTable = nt; - data = getRecord().getData(); + data = t.getData(); value = ""; } - - /** - * Reads in the string - * - * @param d the data - * @param ws the workbook settings - */ - private void readString(byte[] d, WorkbookSettings ws) - { - int pos = 0; - int chars = IntegerHelper.getInt(d[0], d[1]); - - if (chars == 0) - { - value=""; - return; - } - pos += 2; - int optionFlags = d[pos]; - pos++; - - if ((optionFlags & 0xf) != optionFlags) - { - // Uh oh - looks like a plain old string, not unicode - // Recalculate all the positions - pos = 0; - chars = IntegerHelper.getInt(d[0], (byte) 0); - optionFlags = d[1]; - pos = 2; - } - - // See if it is an extended string - boolean extendedString = ((optionFlags & 0x04) != 0); - - // See if string contains formatting information - boolean richString = ((optionFlags & 0x08) != 0); - - if (richString) - { - pos += 2; - } - - if (extendedString) - { - pos += 4; - } - - // See if string is ASCII (compressed) or unicode - boolean asciiEncoding = ((optionFlags & 0x01) == 0); - - if (asciiEncoding) - { - value = StringHelper.getString(d, chars, pos, ws); - } - else - { - value = StringHelper.getUnicodeString(d, chars, pos); - } - } - /** * Interface method which returns the value * * @return the last calculated value of the formula */ + @Override public String getContents() { return value; @@ -230,6 +153,7 @@ public String getContents() * * @return the last calculated value of the formula */ + @Override public String getString() { return value; @@ -240,6 +164,7 @@ public String getString() * * @return The cell type */ + @Override public CellType getType() { return CellType.STRING_FORMULA; @@ -251,6 +176,7 @@ public CellType getType() * * @return the raw record data */ + @Override public byte[] getFormulaData() throws FormulaException { if (!getSheet().getWorkbook().getWorkbookBof().isBiff8()) @@ -271,6 +197,7 @@ public byte[] getFormulaData() throws FormulaException * @return the formula as an excel string * @exception FormulaException */ + @Override public String getFormula() throws FormulaException { if (formulaString == null) @@ -287,4 +214,4 @@ public String getFormula() throws FormulaException return formulaString; } -} +} \ No newline at end of file diff --git a/src/jxl/read/biff/StringFormulaRecordBiff7.java b/src/jxl/read/biff/StringFormulaRecordBiff7.java new file mode 100644 index 0000000..bbe0431 --- /dev/null +++ b/src/jxl/read/biff/StringFormulaRecordBiff7.java @@ -0,0 +1,73 @@ + +package jxl.read.biff; + +import jxl.*; +import jxl.biff.*; +import jxl.biff.formula.*; + +/** + * created 29.05.2020 + * @author jan + */ +public class StringFormulaRecordBiff7 extends StringFormulaRecord { + + public StringFormulaRecordBiff7(Record t, File excelFile, + FormattingRecords fr, ExternalSheet es, WorkbookMethods nt, + SheetImpl si, WorkbookSettings ws) { + super(t, excelFile, fr, es, nt, si); + value = readString(stringData, ws); + } + + public StringFormulaRecordBiff7(Record t, FormattingRecords fr, + ExternalSheet es, WorkbookMethods nt, SheetImpl si) { + super(t, fr, es, nt, si); + } + + /** + * Reads in the string + * + * @param d the data + * @param ws the workbook settings + */ + private String readString(byte[] d, WorkbookSettings ws) + { + int pos = 0; + int chars = IntegerHelper.getInt(d[0], d[1]); + + if (chars == 0) + return ""; + + pos += 2; + int optionFlags = d[pos]; + pos++; + + if ((optionFlags & 0xf) != optionFlags) + { + // Uh oh - looks like a plain old string, not unicode + // Recalculate all the positions + chars = IntegerHelper.getInt(d[0], (byte) 0); + optionFlags = d[1]; + pos = 2; + } + + // See if it is an extended string + boolean extendedString = ((optionFlags & 0x04) != 0); + + // See if string contains formatting information + boolean richString = ((optionFlags & 0x08) != 0); + + if (richString) + pos += 2; + + if (extendedString) + pos += 4; + + // See if string is ASCII (compressed) or unicode + boolean asciiEncoding = ((optionFlags & 0x01) == 0); + + if (asciiEncoding) + return StringHelper.getString(d, chars, pos, ws); + else + return StringHelper.getUnicodeString(d, pos, chars); + } +} diff --git a/src/jxl/read/biff/StringFormulaRecordBiff8.java b/src/jxl/read/biff/StringFormulaRecordBiff8.java new file mode 100644 index 0000000..a8ddfae --- /dev/null +++ b/src/jxl/read/biff/StringFormulaRecordBiff8.java @@ -0,0 +1,34 @@ +package jxl.read.biff; + +import jxl.biff.*; +import jxl.biff.formula.*; + +/** + * created 29.05.2020 + * @author jan + */ +public class StringFormulaRecordBiff8 extends StringFormulaRecord { + + public StringFormulaRecordBiff8(Record t, File excelFile, + FormattingRecords fr, ExternalSheet es, WorkbookMethods nt, + SheetImpl si) { + super(t, excelFile, fr, es, nt, si); + value = readString(stringData); + } + + public StringFormulaRecordBiff8(Record t, FormattingRecords fr, + ExternalSheet es, WorkbookMethods nt, SheetImpl si) { + super(t, fr, es, nt, si); + } + + /** + * Reads in the string + * + * @param d the data + * @param ws the workbook settings + */ + private String readString(byte[] d) + { + return StringHelper.readBiff8String(d); + } +} diff --git a/src/jxl/read/biff/SupbookRecord.java b/src/jxl/read/biff/SupbookRecord.java index 3df52c4..480d33a 100644 --- a/src/jxl/read/biff/SupbookRecord.java +++ b/src/jxl/read/biff/SupbookRecord.java @@ -153,7 +153,7 @@ private void readExternal(byte[] data, WorkbookSettings ws) pos = 7; if (encoding == 0) { - fileName = StringHelper.getUnicodeString(data, ln, pos); + fileName = StringHelper.getUnicodeString(data, pos, ln); pos += ln * 2; } else @@ -166,20 +166,7 @@ private void readExternal(byte[] data, WorkbookSettings ws) sheetNames = new String[numSheets]; for (int i = 0; i < sheetNames.length; i++) - { - ln = IntegerHelper.getInt(data[pos], data[pos + 1]); - - if (data[pos + 2] == 0x0) - { - sheetNames[i] = StringHelper.getString(data, ln, pos + 3, ws); - pos += ln + 3; - } - else if (data[pos + 2] == 0x1) - { - sheetNames[i] = StringHelper.getUnicodeString(data, ln, pos + 3); - pos += ln * 2 + 3; - } - } + sheetNames[i] = StringHelper.readBiff8String(data, pos); } /** diff --git a/src/jxl/read/biff/VerticalPageBreaksRecord.java b/src/jxl/read/biff/VerticalPageBreaksRecord.java index 62c3ec0..d8f1433 100644 --- a/src/jxl/read/biff/VerticalPageBreaksRecord.java +++ b/src/jxl/read/biff/VerticalPageBreaksRecord.java @@ -19,33 +19,29 @@ package jxl.read.biff; -import jxl.common.Logger; - -import jxl.biff.IntegerHelper; -import jxl.biff.RecordData; +import java.util.*; +import java.util.stream.Collectors; +import jxl.biff.*; /** * Contains the cell dimensions of this worksheet */ -class VerticalPageBreaksRecord extends RecordData -{ - /** - * The logger - */ - private final Logger logger = Logger.getLogger - (VerticalPageBreaksRecord.class); +public class VerticalPageBreaksRecord extends RecordData implements IVerticalPageBreaks { /** * The row page breaks */ - private int[] columnBreaks; + private final List columnBreaks = new ArrayList<>(); /** * Dummy indicators for overloading the constructor */ private static class Biff7 {}; - public static Biff7 biff7 = new Biff7(); + public static final Biff7 biff7 = new Biff7(); + public VerticalPageBreaksRecord() { + super(Type.VERTICALPAGEBREAKS); + } /** * Constructs the dimensions from the raw data * @@ -59,11 +55,13 @@ public VerticalPageBreaksRecord(Record t) int numbreaks = IntegerHelper.getInt(data[0], data[1]); int pos = 2; - columnBreaks = new int[numbreaks]; for (int i = 0; i < numbreaks; i++) { - columnBreaks[i] = IntegerHelper.getInt(data[pos], data[pos + 1]); + columnBreaks.add(new ColumnIndex( + IntegerHelper.getInt(data[pos], data[pos + 1]), + IntegerHelper.getInt(data[pos + 2], data[pos + 3]), + IntegerHelper.getInt(data[pos + 4], data[pos + 5]))); pos += 6; } } @@ -81,10 +79,12 @@ public VerticalPageBreaksRecord(Record t, Biff7 biff7) byte[] data = t.getData(); int numbreaks = IntegerHelper.getInt(data[0], data[1]); int pos = 2; - columnBreaks = new int[numbreaks]; for (int i = 0; i < numbreaks; i++) { - columnBreaks[i] = IntegerHelper.getInt(data[pos], data[pos + 1]); + columnBreaks.add(new ColumnIndex( + IntegerHelper.getInt(data[pos], data[pos + 1]), + 0, + 0xffff)); pos += 2; } } @@ -94,15 +94,12 @@ public VerticalPageBreaksRecord(Record t, Biff7 biff7) * * @return the row breaks on the current sheet */ - public int[] getColumnBreaks() + @Override + public List getColumnBreaks() { - return columnBreaks; + return columnBreaks.stream() + .map(ColumnIndex::getFirstColumnFollowingBreak) + .collect(Collectors.toList()); } -} - - - - - - +} diff --git a/src/jxl/read/biff/WorkbookParser.java b/src/jxl/read/biff/WorkbookParser.java index c097f74..9bf91eb 100644 --- a/src/jxl/read/biff/WorkbookParser.java +++ b/src/jxl/read/biff/WorkbookParser.java @@ -19,9 +19,9 @@ package jxl.read.biff; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.Iterator; +import java.nio.file.*; +import java.util.*; +import static java.util.stream.Collectors.toList; import jxl.common.Assert; import jxl.common.Logger; @@ -62,41 +62,47 @@ public class WorkbookParser extends Workbook /** * The logger */ - private static Logger logger = Logger.getLogger(WorkbookParser.class); + private static final Logger LOGGER = Logger.getLogger(WorkbookParser.class); /** * The excel file */ - private File excelFile; + private final File excelFile; + /** * The number of open bofs */ private int bofs; + /** * Indicates whether or not the dates are based around the 1904 date system */ private boolean nineteenFour; + /** * The shared string table */ private SSTRecord sharedStrings; + /** * The names of all the worksheets */ - private ArrayList boundsheets; + private final List boundsheets = new ArrayList<>(10); + /** - * The xf records + * The fonts used by this workbook */ - private FormattingRecords formattingRecords; + private final Fonts fonts = new Fonts(); + /** - * The fonts used by this workbook + * The xf records */ - private Fonts fonts; + private final FormattingRecords formattingRecords = new FormattingRecords(fonts); /** * The sheets contained in this workbook */ - private ArrayList sheets; + private final List sheets = new ArrayList<>(10); /** * The last sheet accessed @@ -106,22 +112,22 @@ public class WorkbookParser extends Workbook /** * The index of the last sheet retrieved */ - private int lastSheetIndex; + private int lastSheetIndex = -1; /** * The named records found in this workbook */ - private HashMap namedRecords; + private final Map namedRecords = new HashMap<>(); /** * The list of named records */ - private ArrayList nameTable; + private List nameTable; /** * The list of add in functions */ - private ArrayList addInFunctions; + private List addInFunctions; /** * The external sheet record. Used by formulas, and names @@ -131,7 +137,7 @@ public class WorkbookParser extends Workbook /** * The list of supporting workbooks - used by formulas */ - private ArrayList supbooks; + private final List supbooks = new ArrayList<>(10); /** * The bof record for this workbook @@ -151,17 +157,17 @@ public class WorkbookParser extends Workbook /** * Workbook protected flag */ - private boolean wbProtected; + private boolean wbProtected = false; /** * Contains macros flag */ - private boolean containsMacros; + private boolean containsMacros = false; /** * The workbook settings */ - private WorkbookSettings settings; + private final WorkbookSettings settings; /** * The drawings contained in this workbook @@ -174,7 +180,7 @@ public class WorkbookParser extends Workbook */ private CountryRecord countryRecord; - private ArrayList xctRecords; + private final List xctRecords = new ArrayList<>(10); /** * Constructs this object from the raw excel data @@ -186,17 +192,7 @@ public WorkbookParser(File f, WorkbookSettings s) { super(); excelFile = f; - boundsheets = new ArrayList(10); - fonts = new Fonts(); - formattingRecords = new FormattingRecords(fonts); - sheets = new ArrayList(10); - supbooks = new ArrayList(10); - namedRecords = new HashMap(); - lastSheetIndex = -1; - wbProtected = false; - containsMacros = false; settings = s; - xctRecords = new ArrayList(10); } /** @@ -205,12 +201,12 @@ public WorkbookParser(File f, WorkbookSettings s) * very large worksheets can cause performance and out of memory problems. * Use the alternative method getSheet() to retrieve each sheet individually * - * @return an array of the individual sheets + * @return a list of the individual sheets */ - public Sheet[] getSheets() + @Override + public List getSheets() { - Sheet[] sheetArray = new Sheet[getNumberOfSheets()]; - return (Sheet[]) sheets.toArray(sheetArray); + return Collections.unmodifiableList(sheets); } /** @@ -220,6 +216,7 @@ public Sheet[] getSheets() * @param index the zero based index of the required sheet * @return The sheet specified by the index */ + @Override public Sheet getReadSheet(int index) { return getSheet(index); @@ -231,6 +228,7 @@ public Sheet getReadSheet(int index) * @param index the zero based index of the required sheet * @return The sheet specified by the index */ + @Override public Sheet getSheet(int index) { // First see if the last sheet index is the same as this sheet index. @@ -252,7 +250,7 @@ public Sheet getSheet(int index) } } - lastSheet = (SheetImpl) sheets.get(index); + lastSheet = sheets.get(index); lastSheetIndex = index; lastSheet.readSheet(); @@ -265,17 +263,17 @@ public Sheet getSheet(int index) * @param name the sheet name * @return The sheet with the specified name, or null if it is not found */ + @Override public Sheet getSheet(String name) { // Iterate through the boundsheet records int pos = 0; boolean found = false; - Iterator i = boundsheets.iterator(); - BoundsheetRecord br = null; + Iterator i = boundsheets.iterator(); while (i.hasNext() && !found) { - br = (BoundsheetRecord) i.next(); + BoundsheetRecord br = i.next(); if (br.getName().equals(name)) { @@ -293,20 +291,14 @@ public Sheet getSheet(String name) /** * Gets the sheet names * - * @return an array of strings containing the sheet names + * @return a list of strings containing the sheet names */ - public String[] getSheetNames() + @Override + public List getSheetNames() { - String[] names = new String[boundsheets.size()]; - - BoundsheetRecord br = null; - for (int i = 0; i < names.length; i++) - { - br = (BoundsheetRecord) boundsheets.get(i); - names[i] = br.getName(); - } - - return names; + return boundsheets.stream() + .map(BoundsheetRecord::getName) + .collect(toList()); } @@ -318,6 +310,7 @@ public String[] getSheetNames() * @param index the external sheet reference * @return the actual sheet index */ + @Override public int getExternalSheetIndex(int index) { // For biff7, the whole external reference thing works differently @@ -342,6 +335,7 @@ public int getExternalSheetIndex(int index) * @param index the external sheet reference * @return the actual sheet index */ + @Override public int getLastExternalSheetIndex(int index) { // For biff7, the whole external reference thing works differently @@ -364,24 +358,25 @@ public int getLastExternalSheetIndex(int index) * @param index the external sheet index * @return the name of the external sheet */ + @Override public String getExternalSheetName(int index) { // For biff7, the whole external reference thing works differently // Hopefully for our purposes sheet references will all be local if (workbookBof.isBiff7()) { - BoundsheetRecord br = (BoundsheetRecord) boundsheets.get(index); + BoundsheetRecord br = boundsheets.get(index); return br.getName(); } int supbookIndex = externSheet.getSupbookIndex(index); - SupbookRecord sr = (SupbookRecord) supbooks.get(supbookIndex); + SupbookRecord sr = supbooks.get(supbookIndex); int firstTab = externSheet.getFirstTabIndex(index); int lastTab = externSheet.getLastTabIndex(index); - String firstTabName = ""; - String lastTabName = ""; + String firstTabName; + String lastTabName; if (sr.getType() == SupbookRecord.INTERNAL) { @@ -392,41 +387,41 @@ public String getExternalSheetName(int index) } else { - BoundsheetRecord br = (BoundsheetRecord) boundsheets.get(firstTab); + BoundsheetRecord br = boundsheets.get(firstTab); firstTabName = br.getName(); } - + if (lastTab==65535) { lastTabName = "#REF"; } else { - BoundsheetRecord br = (BoundsheetRecord) boundsheets.get(lastTab); + BoundsheetRecord br = boundsheets.get(lastTab); lastTabName = br.getName(); } - String sheetName = (firstTab == lastTab) ? firstTabName : + String sheetName = (firstTab == lastTab) ? firstTabName : firstTabName + ':' + lastTabName; // if the sheet name contains apostrophes then escape them sheetName = sheetName.indexOf('\'') == -1 ? sheetName : StringHelper.replace(sheetName, "\'", "\'\'"); - + // if the sheet name contains spaces, then enclose in quotes - return sheetName.indexOf(' ') == -1 ? sheetName : + return sheetName.indexOf(' ') == -1 ? sheetName : '\'' + sheetName + '\''; } else if (sr.getType() == SupbookRecord.EXTERNAL) { // External reference - get the sheet name from the supbook record - StringBuffer sb = new StringBuffer(); - java.io.File fl = new java.io.File(sr.getFileName()); + StringBuilder sb = new StringBuilder(); + Path fl = Paths.get(sr.getFileName()); sb.append("'"); - sb.append(fl.getAbsolutePath()); + sb.append(fl.toAbsolutePath().getParent().toString()); sb.append("["); - sb.append(fl.getName()); + sb.append(fl.getFileName()); sb.append("]"); sb.append((firstTab == 65535) ? "#REF" : sr.getSheetName(firstTab)); if (lastTab != firstTab) @@ -438,7 +433,7 @@ else if (sr.getType() == SupbookRecord.EXTERNAL) } // An unknown supbook - return unkown - logger.warn("Unknown Supbook 3"); + LOGGER.warn("Unknown Supbook 3"); return "[UNKNOWN]"; } @@ -454,13 +449,13 @@ public String getLastExternalSheetName(int index) // Hopefully for our purposes sheet references will all be local if (workbookBof.isBiff7()) { - BoundsheetRecord br = (BoundsheetRecord) boundsheets.get(index); + BoundsheetRecord br = boundsheets.get(index); return br.getName(); } int supbookIndex = externSheet.getSupbookIndex(index); - SupbookRecord sr = (SupbookRecord) supbooks.get(supbookIndex); + SupbookRecord sr = supbooks.get(supbookIndex); int lastTab = externSheet.getLastTabIndex(index); @@ -473,19 +468,19 @@ public String getLastExternalSheetName(int index) } else { - BoundsheetRecord br = (BoundsheetRecord) boundsheets.get(lastTab); + BoundsheetRecord br = boundsheets.get(lastTab); return br.getName(); } } else if (sr.getType() == SupbookRecord.EXTERNAL) { // External reference - get the sheet name from the supbook record - StringBuffer sb = new StringBuffer(); - java.io.File fl = new java.io.File(sr.getFileName()); + StringBuilder sb = new StringBuilder(); + Path fl = Paths.get(sr.getFileName()); sb.append("'"); - sb.append(fl.getAbsolutePath()); + sb.append(fl.toAbsolutePath().getParent().toString()); sb.append("["); - sb.append(fl.getName()); + sb.append(fl.getFileName()); sb.append("]"); sb.append((lastTab == 65535) ? "#REF" : sr.getSheetName(lastTab)); sb.append("'"); @@ -493,7 +488,7 @@ else if (sr.getType() == SupbookRecord.EXTERNAL) } // An unknown supbook - return unkown - logger.warn("Unknown Supbook 4"); + LOGGER.warn("Unknown Supbook 4"); return "[UNKNOWN]"; } @@ -502,6 +497,7 @@ else if (sr.getType() == SupbookRecord.EXTERNAL) * * @return the number of sheets in this workbook */ + @Override public int getNumberOfSheets() { return sheets.size(); @@ -511,6 +507,7 @@ public int getNumberOfSheets() * Closes this workbook, and frees makes any memory allocated available * for garbage collection */ + @Override public void close() { if (lastSheet != null) @@ -530,7 +527,7 @@ public void close() * * @param s the sheet to add */ - final void addSheet(Sheet s) + private void addSheet(SheetImpl s) { sheets.add(s); } @@ -541,6 +538,7 @@ final void addSheet(Sheet s) * @exception BiffException * @exception PasswordException if the workbook is password protected */ + @Override protected void parse() throws BiffException, PasswordException { Record r = null; @@ -558,273 +556,206 @@ protected void parse() throws BiffException, PasswordException { throw new BiffException(BiffException.expectedGlobals); } - ArrayList continueRecords = new ArrayList(); - ArrayList localNames = new ArrayList(); - nameTable = new ArrayList(); - addInFunctions = new ArrayList(); + List continueRecords = new ArrayList<>(); + List localNames = new ArrayList<>(); + nameTable = new ArrayList<>(); + addInFunctions = new ArrayList<>(); // Skip to the first worksheet while (bofs == 1) { r = excelFile.next(); - if (r.getType() == Type.SST) - { - continueRecords.clear(); - Record nextrec = excelFile.peek(); - while (nextrec.getType() == Type.CONTINUE) - { - continueRecords.add(excelFile.next()); - nextrec = excelFile.peek(); + switch (r.getType()) { + case SST: { + // BIFF8 only + continueRecords.clear(); + Record nextrec = excelFile.peek(); + while (nextrec.getType() == Type.CONTINUE) { + continueRecords.add(excelFile.next()); + nextrec = excelFile.peek(); + } + Record[] records = continueRecords.toArray(new Record[continueRecords + .size()]); + sharedStrings = new SSTRecord(r, records); + break; } - // cast the array - Record[] records = new Record[continueRecords.size()]; - records = (Record[]) continueRecords.toArray(records); - - sharedStrings = new SSTRecord(r, records, settings); - } - else if (r.getType() == Type.FILEPASS) - { - throw new PasswordException(); - } - else if (r.getType() == Type.NAME) - { - NameRecord nr = null; - - if (bof.isBiff8()) - { - nr = new NameRecord(r, settings, nameTable.size()); - + case FILEPASS: + throw new PasswordException(); + + case NAME: { + NameRecord nr = bof.isBiff8() + ? new NameRecord(r, settings, nameTable.size()) + : new NameRecord(r, settings, nameTable.size(), NameRecord.biff7); + // Add all local and global names to the name table in order to + // preserve the indexing + nameTable.add(nr); + if (nr.isGlobal()) + namedRecords.put(nr.getName(), nr); + else + localNames.add(nr); + break; } - else - { - nr = new NameRecord(r, settings, nameTable.size(), - NameRecord.biff7); + + case FONT: { + FontRecord fr = bof.isBiff8() + ? new FontRecord(r, settings) + : new FontRecord(r, settings, FontRecord.biff7); + fonts.addFont(fr); + break; } - // Add all local and global names to the name table in order to - // preserve the indexing - nameTable.add(nr); + case PALETTE: + PaletteRecord palette = new PaletteRecord(r); + formattingRecords.setPalette(palette); + break; - if (nr.isGlobal()) - { - namedRecords.put(nr.getName(), nr); - } - else - { - localNames.add(nr); + case NINETEENFOUR: { + NineteenFourRecord nr = new NineteenFourRecord(r); + nineteenFour = nr.is1904(); + break; } - } - else if (r.getType() == Type.FONT) - { - FontRecord fr = null; - if (bof.isBiff8()) - { - fr = new FontRecord(r, settings); - } - else - { - fr = new FontRecord(r, settings, FontRecord.biff7); - } - fonts.addFont(fr); - } - else if (r.getType() == Type.PALETTE) - { - PaletteRecord palette = new PaletteRecord(r); - formattingRecords.setPalette(palette); - } - else if (r.getType() == Type.NINETEENFOUR) - { - NineteenFourRecord nr = new NineteenFourRecord(r); - nineteenFour = nr.is1904(); - } - else if (r.getType() == Type.FORMAT) - { - FormatRecord fr = null; - if (bof.isBiff8()) - { - fr = new FormatRecord(r, settings, FormatRecord.biff8); - } - else - { - fr = new FormatRecord(r, settings, FormatRecord.biff7); - } - try - { - formattingRecords.addFormat(fr); - } - catch (NumFormatRecordsException e) - { - // This should not happen. Bomb out - Assert.verify(false, e.getMessage()); - } - } - else if (r.getType() == Type.XF) - { - XFRecord xfr = null; - if (bof.isBiff8()) - { - xfr = new XFRecord(r, settings, XFRecord.biff8); - } - else - { - xfr = new XFRecord(r, settings, XFRecord.biff7); + case FORMAT: { + FormatRecord fr = bof.isBiff8() + ? new FormatRecord(r, settings, FormatRecord.biff8) + : new FormatRecord(r, settings, FormatRecord.biff7); + try { + formattingRecords.addFormat(fr); + } catch (NumFormatRecordsException e) { + // This should not happen. Bomb out + Assert.verify(false, e.getMessage()); + } + break; } - try - { - formattingRecords.addStyle(xfr); - } - catch (NumFormatRecordsException e) - { - // This should not happen. Bomb out - Assert.verify(false, e.getMessage()); - } - } - else if (r.getType() == Type.BOUNDSHEET) - { - BoundsheetRecord br = null; + case XF: + XFRecord xfr = bof.isBiff8() + ? new XFRecord(r, settings, XFRecord.biff8) + : new XFRecord(r, settings, XFRecord.biff7); + try { + formattingRecords.addStyle(xfr); + } catch (NumFormatRecordsException e) { + // This should not happen. Bomb out + Assert.verify(false, e.getMessage()); + } + break; + + case BOUNDSHEET: + BoundsheetRecord br = bof.isBiff8() + ? new BoundsheetRecord(r, settings) + : new BoundsheetRecord(r, BoundsheetRecord.biff7); + + if (br.isSheet()) + boundsheets.add(br); + else if (br.isChart() && !settings.getDrawingsDisabled()) + boundsheets.add(br); + break; + + case EXTERNSHEET: + if (bof.isBiff8()) + externSheet = new ExternalSheetRecord(r, settings); + else + externSheet = new ExternalSheetRecord(r, settings, + ExternalSheetRecord.biff7); + break; + + case XCT: + xctRecords.add(new XCTRecord(r)); + break; + + case CODEPAGE: + CodepageRecord cr = new CodepageRecord(r); + settings.setCharacterSet(cr.getCharacterSet()); + break; + + case SUPBOOK: { + Record nextrec = excelFile.peek(); + while (nextrec.getType() == Type.CONTINUE) { + r.addContinueRecord(excelFile.next()); + nextrec = excelFile.peek(); + } + supbooks.add(new SupbookRecord(r, settings)); + break; - if (bof.isBiff8()) - { - br = new BoundsheetRecord(r, settings); - } - else - { - br = new BoundsheetRecord(r, BoundsheetRecord.biff7); } + case EXTERNNAME: + ExternalNameRecord enr = new ExternalNameRecord(r, settings); + if (enr.isAddInFunction()) + addInFunctions.add(enr.getName()); + break; + + case PROTECT: + ProtectRecord pr = new ProtectRecord(r); + wbProtected = pr.isProtected(); + break; + + case OBJPROJ: + containsMacros = true; + break; + + case COUNTRY: + countryRecord = new CountryRecord(r); + break; + + case MSODRAWINGGROUP: + if (!settings.getDrawingsDisabled()) { + msoDrawingGroup = new MsoDrawingGroupRecord(r); + + if (drawingGroup == null) + drawingGroup = new DrawingGroup(Origin.READ); + + drawingGroup.add(msoDrawingGroup); + + Record nextrec = excelFile.peek(); + while (nextrec.getType() == Type.CONTINUE) { + drawingGroup.add(excelFile.next()); + nextrec = excelFile.peek(); + } + } + break; - if (br.isSheet()) - { - boundsheets.add(br); - } - else if (br.isChart() && !settings.getDrawingsDisabled()) - { - boundsheets.add(br); - } - } - else if (r.getType() == Type.EXTERNSHEET) - { - if (bof.isBiff8()) - { - externSheet = new ExternalSheetRecord(r, settings); - } - else - { - externSheet = new ExternalSheetRecord(r, settings, - ExternalSheetRecord.biff7); - } - } - else if (r.getType() == Type.XCT) - { - XCTRecord xctr = new XCTRecord(r); - xctRecords.add(xctr); - } - else if (r.getType() == Type.CODEPAGE) - { - CodepageRecord cr = new CodepageRecord(r); - settings.setCharacterSet(cr.getCharacterSet()); - } - else if (r.getType() == Type.SUPBOOK) - { - Record nextrec = excelFile.peek(); - while (nextrec.getType() == Type.CONTINUE) - { - r.addContinueRecord(excelFile.next()); - nextrec = excelFile.peek(); - } + case BUTTONPROPERTYSET: + buttonPropertySet = new ButtonPropertySetRecord(r); + break; - SupbookRecord sr = new SupbookRecord(r, settings); - supbooks.add(sr); - } - else if (r.getType() == Type.EXTERNNAME) - { - ExternalNameRecord enr = new ExternalNameRecord(r, settings); + case EOF: + bofs--; + break; - if (enr.isAddInFunction()) - { - addInFunctions.add(enr.getName()); + case REFRESHALL: { + RefreshAllRecord rfm = new RefreshAllRecord(r); + settings.setRefreshAll(rfm.getRefreshAll()); + break; } - } - else if (r.getType() == Type.PROTECT) - { - ProtectRecord pr = new ProtectRecord(r); - wbProtected = pr.isProtected(); - } - else if (r.getType() == Type.OBJPROJ) - { - containsMacros = true; - } - else if (r.getType() == Type.COUNTRY) - { - countryRecord = new CountryRecord(r); - } - else if (r.getType() == Type.MSODRAWINGGROUP) - { - if (!settings.getDrawingsDisabled()) - { - msoDrawingGroup = new MsoDrawingGroupRecord(r); - - if (drawingGroup == null) - { - drawingGroup = new DrawingGroup(Origin.READ); - } - drawingGroup.add(msoDrawingGroup); - - Record nextrec = excelFile.peek(); - while (nextrec.getType() == Type.CONTINUE) - { - drawingGroup.add(excelFile.next()); - nextrec = excelFile.peek(); - } + case TEMPLATE: { + TemplateRecord rfm = new TemplateRecord(r); + settings.setTemplate(rfm.getTemplate()); + break; } - } - else if (r.getType() == Type.BUTTONPROPERTYSET) - { - buttonPropertySet = new ButtonPropertySetRecord(r); - } - else if (r.getType() == Type.EOF) - { - bofs--; - } - else if (r.getType() == Type.REFRESHALL) - { - RefreshAllRecord rfm = new RefreshAllRecord(r); - settings.setRefreshAll(rfm.getRefreshAll()); - } - else if (r.getType() == Type.TEMPLATE) - { - TemplateRecord rfm = new TemplateRecord(r); - settings.setTemplate(rfm.getTemplate()); - } - else if (r.getType() == Type.EXCEL9FILE) - { - Excel9FileRecord e9f = new Excel9FileRecord(r); - settings.setExcel9File(e9f.getExcel9File()); - } - else if (r.getType() == Type.WINDOWPROTECT) - { - WindowProtectedRecord winp = new WindowProtectedRecord(r); - settings.setWindowProtected(winp.getWindowProtected()); - } - else if (r.getType() == Type.HIDEOBJ) - { - HideobjRecord hobj = new HideobjRecord(r); - settings.setHideobj(hobj.getHideMode()); - } - else if (r.getType() == Type.WRITEACCESS) - { - WriteAccessRecord war = new WriteAccessRecord(r, bof.isBiff8(), - settings); - settings.setWriteAccess(war.getWriteAccess()); - } - else - { - // logger.info("Unsupported record type: " + - // Integer.toHexString(r.getCode())+"h"); + + case EXCEL9FILE: + Excel9FileRecord e9f = new Excel9FileRecord(r); + settings.setExcel9File(e9f.getExcel9File()); + break; + + case WINDOWPROTECT: + WindowProtectedRecord winp = new WindowProtectedRecord(r); + settings.setWindowProtected(winp.getWindowProtected()); + break; + + case HIDEOBJ: + HideobjRecord hobj = new HideobjRecord(r); + settings.setHideobj(hobj.getHideMode()); + break; + + case WRITEACCESS: + WriteAccessRecord war = new WriteAccessRecord(r, bof.isBiff8(), + settings); + settings.setWriteAccess(war.getWriteAccess()); + break; } } @@ -858,8 +789,8 @@ else if (r.getType() == Type.WRITEACCESS) nineteenFour, this); - BoundsheetRecord br = (BoundsheetRecord) boundsheets.get - (getNumberOfSheets()); + BoundsheetRecord br = boundsheets.get + (getNumberOfSheets()); s.setName(br.getName()); s.setHidden(br.isHidden()); addSheet(s); @@ -875,15 +806,15 @@ else if (bof.isChart()) nineteenFour, this); - BoundsheetRecord br = (BoundsheetRecord) boundsheets.get - (getNumberOfSheets()); + BoundsheetRecord br = boundsheets.get + (getNumberOfSheets()); s.setName(br.getName()); s.setHidden(br.isHidden()); addSheet(s); } else { - logger.warn("BOF is unrecognized"); + LOGGER.warn("BOF is unrecognized"); while (excelFile.hasNext() && r.getType() != Type.EOF) @@ -910,23 +841,19 @@ else if (bof.isChart()) } // Add all the local names to the specific sheets - for (Iterator it = localNames.iterator() ; it.hasNext() ;) - { - NameRecord nr = (NameRecord) it.next(); - + for (NameRecord nr : localNames) if (nr.getBuiltInName() == null) { - logger.warn("Usage of a local non-builtin name"); - } - else if (nr.getBuiltInName() == BuiltInName.PRINT_AREA || - nr.getBuiltInName() == BuiltInName.PRINT_TITLES) + LOGGER.warn("Usage of a local non-builtin name: " + nr.getName()); + } + else if (nr.getBuiltInName() == BuiltInName.PRINT_AREA || + nr.getBuiltInName() == BuiltInName.PRINT_TITLES) { // appears to use the internal tab number rather than the // external sheet index - SheetImpl s = (SheetImpl) sheets.get(nr.getSheetRef() - 1); + SheetImpl s = sheets.get(nr.getSheetRef() - 1); s.addLocalName(nr); } - } } /** @@ -968,10 +895,9 @@ public MsoDrawingGroupRecord getMsoDrawingGroupRecord() * * @return the supbook records */ - public SupbookRecord[] getSupbookRecords() + public List getSupbookRecords() { - SupbookRecord[] sr = new SupbookRecord[supbooks.size()]; - return (SupbookRecord[]) supbooks.toArray(sr); + return Collections.unmodifiableList(supbooks); } /** @@ -980,10 +906,9 @@ public SupbookRecord[] getSupbookRecords() * * @return the array of names */ - public NameRecord[] getNameRecords() + public List getNameRecords() { - NameRecord[] na = new NameRecord[nameTable.size()]; - return (NameRecord[]) nameTable.toArray(na); + return Collections.unmodifiableList(nameTable); } /** @@ -997,7 +922,7 @@ public Fonts getFonts() } /** - * Returns the cell for the specified location eg. "Sheet1!A4". + * Returns the cell for the specified location eg. "Sheet1!A4". * This is identical to using the CellReferenceHelper with its * associated performance overheads, consequently it should * be use sparingly @@ -1005,9 +930,10 @@ public Fonts getFonts() * @param loc the cell to retrieve * @return the cell at the specified location */ + @Override public Cell getCell(String loc) { - Sheet s = getSheet(CellReferenceHelper.getSheet(loc)); + Sheet s = getSheet(CellReferenceHelper.getSheet(loc)); return s.getCell(loc); } @@ -1020,9 +946,10 @@ public Cell getCell(String loc) * @return the cell in the top left of the range if found, NULL * otherwise */ + @Override public Cell findCellByName(String name) { - NameRecord nr = (NameRecord) namedRecords.get(name); + NameRecord nr = namedRecords.get(name); if (nr == null) { @@ -1042,7 +969,7 @@ public Cell findCellByName(String name) { return new EmptyCell(col, row); } - + Cell cell = s.getCell(col, row); return cell; @@ -1062,9 +989,10 @@ public Cell findCellByName(String name) * @param name the name to find * @return the range of cells */ + @Override public Range[] findByName(String name) { - NameRecord nr = (NameRecord) namedRecords.get(name); + NameRecord nr = namedRecords.get(name); if (nr == null) { @@ -1095,13 +1023,10 @@ public Range[] findByName(String name) * * @return the list of named cells within the workbook */ + @Override public String[] getRangeNames() { - Object[] keys = namedRecords.keySet().toArray(); - String[] names = new String[keys.length]; - System.arraycopy(keys, 0, names, 0, keys.length); - - return names; + return namedRecords.keySet().toArray(new String[namedRecords.size()]); } /** @@ -1110,6 +1035,7 @@ public String[] getRangeNames() * * @return the BOF record */ + @Override public BOFRecord getWorkbookBof() { return workbookBof; @@ -1120,6 +1046,7 @@ public BOFRecord getWorkbookBof() * * @return whether or not the sheet is protected */ + @Override public boolean isProtected() { return wbProtected; @@ -1141,6 +1068,7 @@ public WorkbookSettings getSettings() * @param sheetName the sheet name to look for * @return the external sheet index */ + @Override public int getExternalSheetIndex(String sheetName) { return 0; @@ -1152,6 +1080,7 @@ public int getExternalSheetIndex(String sheetName) * @param sheetName the sheet name to look for * @return the external sheet index */ + @Override public int getLastExternalSheetIndex(String sheetName) { return 0; @@ -1164,14 +1093,13 @@ public int getLastExternalSheetIndex(String sheetName) * @return the name of the cell * @exception NameRangeException */ + @Override public String getName(int index) throws NameRangeException { - // Assert.verify(index >= 0 && index < nameTable.size()); if (index < 0 || index >= nameTable.size()) - { throw new NameRangeException(); - } - return ((NameRecord) nameTable.get(index)).getName(); + + return nameTable.get(index).getName(); } /** @@ -1180,9 +1108,10 @@ public String getName(int index) throws NameRangeException * @param name the name to search for * @return the index in the name table */ + @Override public int getNameIndex(String name) { - NameRecord nr = (NameRecord) namedRecords.get(name); + NameRecord nr = namedRecords.get(name); return nr != null ? nr.getIndex() : 0; } @@ -1244,12 +1173,11 @@ public CountryRecord getCountryRecord() /** * Accessor for addin function names * - * @return list of add in function names + * @return immutable list of add in function names */ - public String[] getAddInFunctionNames() + public List getAddInFunctionNames() { - String[] addins = new String[0]; - return (String[]) addInFunctions.toArray(addins); + return Collections.unmodifiableList(addInFunctions); } /** @@ -1264,9 +1192,9 @@ public int getIndex(Sheet sheet) int index = -1; int pos = 0; - for (Iterator i = boundsheets.iterator() ; i.hasNext() && index == -1 ;) + for (Iterator i = boundsheets.iterator() ; i.hasNext() && index == -1 ;) { - BoundsheetRecord br = (BoundsheetRecord) i.next(); + BoundsheetRecord br = i.next(); if (br.getName().equals(name)) { @@ -1281,16 +1209,13 @@ public int getIndex(Sheet sheet) return index; } - public XCTRecord[] getXCTRecords() + /** + * + * @return immutable list af XCTRecords + */ + public List getXCTRecords() { - XCTRecord[] xctr = new XCTRecord[0]; - return (XCTRecord[]) xctRecords.toArray(xctr); + return Collections.unmodifiableList(xctRecords); } -} - - - - - - +} \ No newline at end of file diff --git a/src/jxl/read/biff/WriteAccessRecord.java b/src/jxl/read/biff/WriteAccessRecord.java index df9d6ff..20a5709 100644 --- a/src/jxl/read/biff/WriteAccessRecord.java +++ b/src/jxl/read/biff/WriteAccessRecord.java @@ -47,7 +47,7 @@ public WriteAccessRecord(Record t, boolean isBiff8, WorkbookSettings ws) byte[] data = t.getData(); if (isBiff8) { - wauser= StringHelper.getUnicodeString(data, 112/2, 0); + wauser= StringHelper.getUnicodeString(data, 0, 112/2); } else { diff --git a/src/jxl/write/NumberFormat.java b/src/jxl/write/NumberFormat.java old mode 100644 new mode 100755 diff --git a/src/jxl/write/WritableCellFeatures.java b/src/jxl/write/WritableCellFeatures.java index 3694872..31cbf70 100644 --- a/src/jxl/write/WritableCellFeatures.java +++ b/src/jxl/write/WritableCellFeatures.java @@ -111,7 +111,7 @@ public void removeDataValidation() * * @param c the list of valid values */ - public void setDataValidationList(Collection c) + public void setDataValidationList(Collection c) { super.setDataValidationList(c); } @@ -133,7 +133,7 @@ public void setDataValidationRange(int col1, int row1, int col2, int row2) * Sets the data validation based upon a named range. If the namedRange * is an empty string ("") then the cell is effectively made read only * - * @param namedRange the workbook named range defining the validation + * @param namedRange the workbook named range defining the validation * boundaries */ public void setDataValidationRange(String namedRange) diff --git a/src/jxl/write/WritableHyperlink.java b/src/jxl/write/WritableHyperlink.java index 3806cab..689a596 100644 --- a/src/jxl/write/WritableHyperlink.java +++ b/src/jxl/write/WritableHyperlink.java @@ -19,8 +19,8 @@ package jxl.write; -import java.io.File; import java.net.URL; +import java.nio.file.Path; import jxl.Hyperlink; import jxl.write.biff.HyperlinkRecord; @@ -95,7 +95,7 @@ public WritableHyperlink(int col, * @param row the row containing this hyperlink * @param file the hyperlink */ - public WritableHyperlink(int col, int row, File file) + public WritableHyperlink(int col, int row, Path file) { this(col, row, col, row, file, null); } @@ -108,7 +108,7 @@ public WritableHyperlink(int col, int row, File file) * @param file the hyperlink * @param desc the hyperlink description */ - public WritableHyperlink(int col, int row, File file, String desc) + public WritableHyperlink(int col, int row, Path file, String desc) { this(col, row, col, row, file, desc); } @@ -123,7 +123,7 @@ public WritableHyperlink(int col, int row, File file, String desc) * @param file the hyperlink */ public WritableHyperlink(int col, int row, int lastcol, int lastrow, - File file) + Path file) { super(col, row, lastcol, lastrow, file, null); } @@ -142,7 +142,7 @@ public WritableHyperlink(int col, int row, int lastcol, int lastrow, - File file, + Path file, String desc) { super(col, row, lastcol, lastrow, file, desc); @@ -210,7 +210,7 @@ public void setURL(URL url) * * @param file the file */ - public void setFile(File file) + public void setFile(Path file) { super.setFile(file); } diff --git a/src/jxl/write/WritableImage.java b/src/jxl/write/WritableImage.java index 5c86c0e..1fdad64 100644 --- a/src/jxl/write/WritableImage.java +++ b/src/jxl/write/WritableImage.java @@ -19,11 +19,8 @@ package jxl.write; -import java.io.File; - -import jxl.biff.drawing.Drawing; -import jxl.biff.drawing.DrawingGroup; -import jxl.biff.drawing.DrawingGroupObject; +import java.nio.file.Path; +import jxl.biff.drawing.*; /** * Allows an image to be created, or an existing image to be manipulated @@ -68,7 +65,7 @@ public class WritableImage extends Drawing */ public WritableImage(double x, double y, double width, double height, - File image) + Path image) { super(x, y, width, height, image); } @@ -191,7 +188,7 @@ public void setHeight(double c) * * @return the file which the image references */ - public File getImageFile() + public Path getImageFile() { return super.getImageFile(); } diff --git a/src/jxl/write/WritableSheet.java b/src/jxl/write/WritableSheet.java index 52b2f6d..2658cee 100644 --- a/src/jxl/write/WritableSheet.java +++ b/src/jxl/write/WritableSheet.java @@ -19,12 +19,9 @@ package jxl.write; -import jxl.CellView; -import jxl.Range; -import jxl.Sheet; +import jxl.*; +import jxl.format.*; import jxl.format.CellFormat; -import jxl.format.PageOrientation; -import jxl.format.PaperSize; import jxl.write.biff.RowsExceededException; /** @@ -42,7 +39,7 @@ public interface WritableSheet extends Sheet * class of RowsExceededException * * @param cell the cell to add - * @exception jxl.write..WriteException + * @exception jxl.write.WriteException * @exception jxl.write.biff.RowsExceededException */ public void addCell(WritableCell cell) @@ -53,20 +50,6 @@ public void addCell(WritableCell cell) * @param name the name of the sheet */ public void setName(String name); - /** - * Indicates whether or not this sheet is hidden - * - * @param hidden hidden flag - * @deprecated use the SheetSettings bean instead - */ - public void setHidden(boolean hidden); - /** - * Indicates whether or not this sheet is protected - * - * @param prot Protected flag - * @deprecated use the SheetSettings bean instead - */ - public void setProtected(boolean prot); /** * Sets the width of the column on this sheet, in characters. This causes @@ -79,18 +62,6 @@ public void addCell(WritableCell cell) */ public void setColumnView(int col, int width); - /** - * Sets the width and style of every cell in the specified column. - * If the columns specified already has view information associated - * with it, then it is replaced by the new data - * - * @param col the column to be formatted - * @param format the format of every cell in the column - * @param width the width of the column, in characters - * @deprecated Use the CellView bean instead - */ - public void setColumnView(int col, int width, CellFormat format); - /** * Sets the view for this column * @@ -119,18 +90,6 @@ public void setRowView(int row, int height) public void setRowView(int row, boolean collapsed) throws RowsExceededException; - /** - * Sets the height of the specified row, as well as its collapse status - * - * @param row the row to be formatted - * @param height the row height in 1/20th of a point - * @param collapsed indicates whether the row is collapsed - * @exception jxl.write.biff.RowsExceededException - */ - public void setRowView(int row, int height, - boolean collapsed) - throws RowsExceededException; - /** * Sets the view for this column * @@ -171,12 +130,13 @@ public void setRowView(int row, int height, public WritableHyperlink[] getWritableHyperlinks(); /** - * Inserts a blank row into this spreadsheet. If the row is out of range + * Inserts a blank row into this spreadsheet. If the row is out of range * of the rows in the sheet, then no action is taken * * @param row the row to insert + * @throws jxl.write.biff.RowsExceededException */ - public void insertRow(int row); + public void insertRow(int row) throws RowsExceededException; /** * Inserts a blank column into this spreadsheet. If the column is out of @@ -217,7 +177,7 @@ public void setRowView(int row, int height, public Range mergeCells(int col1, int row1, int col2, int row2) throws WriteException, RowsExceededException; - /** + /** * Sets a row grouping * * @param row1 the first row of the group @@ -229,7 +189,7 @@ public Range mergeCells(int col1, int row1, int col2, int row2) public void setRowGroup(int row1, int row2, boolean collapsed) throws WriteException, RowsExceededException; - /** + /** * Unsets a row grouping * * @param row1 the first row to unset @@ -240,7 +200,7 @@ public void setRowGroup(int row1, int row2, boolean collapsed) public void unsetRowGroup(int row1, int row2) throws WriteException, RowsExceededException; - /** + /** * Sets a column grouping * * @param col1 the first column of the group @@ -252,7 +212,7 @@ public void unsetRowGroup(int row1, int row2) public void setColumnGroup(int col1, int col2, boolean collapsed) throws WriteException, RowsExceededException; - /** + /** * Unsets a column grouping * * @param col1 the first column to unset @@ -262,7 +222,7 @@ public void setColumnGroup(int col1, int col2, boolean collapsed) */ public void unsetColumnGroup(int col1, int col2) throws WriteException, RowsExceededException; - + /** * Unmerges the specified cells. The Range passed in should be one that * has been previously returned as a result of the getMergedCells method @@ -366,7 +326,7 @@ public void setPageSetup(PageOrientation p, PaperSize ps, * @param row the row to break at */ public void addRowPageBreak(int row); - + /** * Forces a page break at the specified column * @@ -386,6 +346,7 @@ public void setPageSetup(PageOrientation p, PaperSize ps, * * @return the number of images on this sheet */ + @Override public int getNumberOfImages(); /** @@ -406,7 +367,7 @@ public void setPageSetup(PageOrientation p, PaperSize ps, public void removeImage(WritableImage wi); /** - * Extend the data validation contained in the specified cell across and + * Extend the data validation contained in the specified cell across and * downwards. * NOTE: The source cell (top left) must have been added to the sheet prior * to this method being called @@ -414,12 +375,12 @@ public void setPageSetup(PageOrientation p, PaperSize ps, * @param col the number of cells accross to apply this data validation * @param row the number of cells downwards to apply this data validation */ - public void applySharedDataValidation(WritableCell cell, int col, int row) + public void applySharedDataValidation(WritableCell cell, int col, int row) throws WriteException; /** - * Remove the shared data validation from multiple cells. The cell passed - * in is the top left cell. The data validation is removed from this + * Remove the shared data validation from multiple cells. The cell passed + * in is the top left cell. The data validation is removed from this * cell and all cells which share the same validation. * * @param cell the top left cell containing the shared data validation diff --git a/src/jxl/write/WritableWorkbook.java b/src/jxl/write/WritableWorkbook.java index 88ccbea..18a6116 100644 --- a/src/jxl/write/WritableWorkbook.java +++ b/src/jxl/write/WritableWorkbook.java @@ -19,18 +19,18 @@ package jxl.write; -import java.io.IOException; +import java.io.*; +import java.nio.file.Path; +import java.util.*; -import jxl.Range; -import jxl.Sheet; -import jxl.Workbook; +import jxl.*; import jxl.format.Colour; import jxl.format.UnderlineStyle; /** * A writable workbook */ -public abstract class WritableWorkbook +public abstract class WritableWorkbook implements Closeable { // Globally available stuff @@ -66,7 +66,7 @@ public abstract class WritableWorkbook /** * A cell format used to hide the cell contents */ - public static final WritableCellFormat HIDDEN_STYLE = + public static final WritableCellFormat HIDDEN_STYLE = new WritableCellFormat(new DateFormat(";;;")); /** @@ -133,10 +133,10 @@ public abstract WritableSheet getSheet(int index) * for garbage collection. Also closes the underlying output stream * if necessary. * - * @exception IOException - * @exception WriteException + * @throws IOException */ - public abstract void close() throws IOException, WriteException; + @Override + public abstract void close() throws IOException; /** * Creates, and returns a worksheet at the specified position @@ -161,7 +161,7 @@ public abstract WritableSheet getSheet(int index) * @param sheet the sheet (from another workbook) to merge into this one * @return the new sheet */ - public abstract WritableSheet importSheet(String name, int index, Sheet s); + public abstract WritableSheet importSheet(String name, int index, Sheet sheet); /** * Copy sheet within the same workbook. The sheet specified is copied to @@ -237,6 +237,19 @@ public void copy(Workbook w) // Was an abstract method - leave the method body blank } + /** + * Gets the location from this workbook. If the name refers to a + * range of cells, then the location on the top left is returned. If + * the name cannot be found, null is returned + * + * @param name of the cell/range to search for + * @return the cell in the top left of the range if found, NULL + * otherwise + * @throws NoSuchElementException when a range with the name could + * not be found. + */ + public abstract CellLocation findCellLocationByName(String name) throws NoSuchElementException; + /** * Gets the named cell from this workbook. The name refers to a * range of cells, then the cell on the top left is returned. If @@ -269,10 +282,10 @@ public void copy(Workbook w) * * @return the list of named cells within the workbook */ - public abstract String[] getRangeNames(); + public abstract Set getRangeNames(); /** - * Removes the specified named range from the workbook. Note that + * Removes the specified named range from the workbook. Note that * removing a name could cause formulas which use that name to * calculate their results incorrectly * @@ -305,6 +318,6 @@ public abstract void addNameArea(String name, * @param fileName the file name * @exception IOException */ - public abstract void setOutputFile(java.io.File fileName) + public abstract void setOutputFile(Path fileName) throws IOException; } diff --git a/src/jxl/write/biff/ArbitraryRecord.java b/src/jxl/write/biff/ArbitraryRecord.java index 16acc53..5cf7419 100644 --- a/src/jxl/write/biff/ArbitraryRecord.java +++ b/src/jxl/write/biff/ArbitraryRecord.java @@ -19,10 +19,10 @@ package jxl.write.biff; +import jxl.biff.*; +import static jxl.biff.Type.UNKNOWN; import jxl.common.Logger; -import jxl.biff.Type; -import jxl.biff.WritableRecordData; /** * Writes out some arbitrary record data. Used during the debug process @@ -47,7 +47,7 @@ class ArbitraryRecord extends WritableRecordData */ public ArbitraryRecord(int type, byte[] d) { - super(Type.createType(type)); + super(UNKNOWN); data = d; logger.warn("ArbitraryRecord of type " + type + " created"); @@ -55,7 +55,7 @@ public ArbitraryRecord(int type, byte[] d) /** * Retrieves the data to be written to the binary file - * + * * @return the binary data */ public byte[] getData() diff --git a/src/jxl/write/biff/BooleanRecord.java b/src/jxl/write/biff/BooleanRecord.java index 2303568..94e40e3 100644 --- a/src/jxl/write/biff/BooleanRecord.java +++ b/src/jxl/write/biff/BooleanRecord.java @@ -32,14 +32,14 @@ public abstract class BooleanRecord extends CellValue { /** - * The boolean value of this cell. If this cell represents an error, + * The boolean value of this cell. If this cell represents an error, * this will be false */ private boolean value; /** * Constructor invoked by the user API - * + * * @param c the column * @param r the row * @param val the value @@ -53,7 +53,7 @@ protected BooleanRecord(int c, int r, boolean val) /** * Overloaded constructor invoked from the API, which takes a cell * format - * + * * @param c the column * @param r the row * @param val the value @@ -67,7 +67,7 @@ protected BooleanRecord(int c, int r, boolean val, CellFormat st) /** * Constructor used when copying a workbook - * + * * @param nc the number to copy */ protected BooleanRecord(BooleanCell nc) @@ -78,7 +78,7 @@ protected BooleanRecord(BooleanCell nc) /** * Copy constructor - * + * * @param c the column * @param r the row * @param br the record to copy @@ -90,7 +90,7 @@ protected BooleanRecord(int c, int r, BooleanRecord br) } /** - * Interface method which Gets the boolean value stored in this cell. If + * Interface method which Gets the boolean value stored in this cell. If * this cell contains an error, then returns FALSE. Always query this cell * type using the accessor method isError() prior to calling this method * @@ -101,21 +101,20 @@ public boolean getValue() { return value; } - + /** * Returns the numerical value as a string - * + * * @return The numerical value of the formula as a string */ public String getContents() { - // return Boolean.toString(value) - only available in 1.4 or later - return (new Boolean(value)).toString(); + return Boolean.toString(value); } /** * Returns the cell type - * + * * @return The cell type */ public CellType getType() @@ -125,7 +124,7 @@ public CellType getType() /** * Sets the value - * + * * @param val the boolean value */ protected void setValue(boolean val) @@ -135,7 +134,7 @@ protected void setValue(boolean val) /** * Gets the binary data for output to file - * + * * @return the binary data */ public byte[] getData() diff --git a/src/jxl/write/biff/CellValue.java b/src/jxl/write/biff/CellValue.java index 8b2b3fc..3c7791b 100644 --- a/src/jxl/write/biff/CellValue.java +++ b/src/jxl/write/biff/CellValue.java @@ -26,8 +26,6 @@ import jxl.CellFeatures; import jxl.CellReferenceHelper; import jxl.Sheet; -import jxl.biff.DataValidation; -import jxl.biff.DataValiditySettingsRecord; import jxl.biff.DVParser; import jxl.biff.FormattingRecords; import jxl.biff.IntegerHelper; @@ -35,8 +33,7 @@ import jxl.biff.Type; import jxl.biff.WritableRecordData; import jxl.biff.XFRecord; -import jxl.biff.drawing.ComboBox; -import jxl.biff.drawing.Comment; +import jxl.biff.drawing.*; import jxl.format.CellFormat; import jxl.write.WritableCell; import jxl.write.WritableCellFeatures; @@ -44,19 +41,19 @@ /** * Abstract class which stores the jxl.common.data used for cells, such - * as row, column and formatting information. + * as row, column and formatting information. * Any record which directly represents the contents of a cell, such * as labels and numbers, are derived from this class * data store */ -public abstract class CellValue extends WritableRecordData +public abstract class CellValue extends WritableRecordData implements WritableCell { /** * The logger */ private static Logger logger = Logger.getLogger(CellValue.class); - + /** * The row in the worksheet at which this cell is located */ @@ -71,7 +68,7 @@ public abstract class CellValue extends WritableRecordData * The format applied to this cell */ private XFRecord format; - + /** * A handle to the formatting records, used in case we want * to change the format of the cell once it has been added @@ -103,7 +100,7 @@ public abstract class CellValue extends WritableRecordData /** * Constructor used when building writable cells from the Java API - * + * * @param c the column * @param t the type indicator * @param r the row @@ -115,9 +112,9 @@ protected CellValue(Type t, int c, int r) } /** - * Constructor used when creating a writable cell from a read-only cell + * Constructor used when creating a writable cell from a read-only cell * (when copying a workbook) - * + * * @param c the cell to clone * @param t the type of this cell */ @@ -127,7 +124,7 @@ protected CellValue(Type t, Cell c) copied = true; format = (XFRecord) c.getCellFormat(); - + if (c.getCellFeatures() != null) { features = new WritableCellFeatures(c.getCellFeatures()); @@ -136,9 +133,9 @@ protected CellValue(Type t, Cell c) } /** - * Overloaded constructor used when building writable cells from the + * Overloaded constructor used when building writable cells from the * Java API which also takes a format - * + * * @param c the column * @param t the cell type * @param r the row @@ -155,8 +152,8 @@ protected CellValue(Type t, int c, int r, CellFormat st) } /** - * Copy constructor - * + * Copy constructor + * * @param c the column * @param t the cell type * @param r the row @@ -169,7 +166,7 @@ protected CellValue(Type t, int c, int r, CellValue cv) column = c; format = cv.format; referenced = false; - copied = false; // used during a deep copy, so the cell features need + copied = false; // used during a deep copy, so the cell features need // to be added again if (cv.features != null) @@ -181,7 +178,7 @@ protected CellValue(Type t, int c, int r, CellValue cv) /** * An API function which sets the format to apply to this cell - * + * * @param cf the format to apply to this cell */ public void setCellFormat(CellFormat cf) @@ -196,7 +193,7 @@ public void setCellFormat(CellFormat cf) return; } - // The cell has already been added to the spreadsheet, so the + // The cell has already been added to the spreadsheet, so the // formattingRecords reference must be initialized Assert.verify(formattingRecords != null); @@ -205,7 +202,7 @@ public void setCellFormat(CellFormat cf) /** * Returns the row number of this cell - * + * * @return the row number of this cell */ public int getRow() @@ -215,7 +212,7 @@ public int getRow() /** * Returns the column number of this cell - * + * * @return the column number of this cell */ public int getColumn() @@ -232,7 +229,7 @@ public int getColumn() public boolean isHidden() { ColumnInfoRecord cir = sheet.getColumnInfo(column); - + if (cir != null && cir.getWidth() == 0) { return true; @@ -250,7 +247,7 @@ public boolean isHidden() /** * Gets the data to write to the output file - * + * * @return the binary data */ public byte[] getData() @@ -267,12 +264,12 @@ public byte[] getData() * that this object is already added to the worksheet * This method also verifies that the associated formats and formats * have been initialized correctly - * + * * @param fr the formatting records * @param ss the shared strings used within the workbook * @param s the sheet this is being added to */ - void setCellDetails(FormattingRecords fr, SharedStrings ss, + void setCellDetails(FormattingRecords fr, SharedStrings ss, WritableSheetImpl s) { referenced = true; @@ -286,7 +283,7 @@ void setCellDetails(FormattingRecords fr, SharedStrings ss, /** * Internal method to see if this cell is referenced within the workbook. * Once this has been placed in the workbook, it becomes immutable - * + * * @return TRUE if this cell has been added to a sheet, FALSE otherwise */ final boolean isReferenced() @@ -296,7 +293,7 @@ final boolean isReferenced() /** * Gets the internal index of the formatting record - * + * * @return the index of the format record */ final int getXFIndex() @@ -306,7 +303,7 @@ final int getXFIndex() /** * API method which gets the format applied to this cell - * + * * @return the format for this cell */ public CellFormat getCellFormat() @@ -315,7 +312,7 @@ public CellFormat getCellFormat() } /** - * Increments the row of this cell by one. Invoked by the sheet when + * Increments the row of this cell by one. Invoked by the sheet when * inserting rows */ void incrementRow() @@ -334,7 +331,7 @@ void incrementRow() } /** - * Decrements the row of this cell by one. Invoked by the sheet when + * Decrements the row of this cell by one. Invoked by the sheet when * removing rows */ void decrementRow() @@ -358,7 +355,7 @@ void decrementRow() } /** - * Increments the column of this cell by one. Invoked by the sheet when + * Increments the column of this cell by one. Invoked by the sheet when * inserting columns */ void incrementColumn() @@ -378,7 +375,7 @@ void incrementColumn() } /** - * Decrements the column of this cell by one. Invoked by the sheet when + * Decrements the column of this cell by one. Invoked by the sheet when * removing columns */ void decrementColumn() @@ -468,7 +465,7 @@ private void addCellFormat() format = styles.getFormat(format); try - { + { if (!format.isInitialized()) { formattingRecords.addStyle(format); @@ -509,10 +506,10 @@ public WritableCellFeatures getWritableCellFeatures() */ public void setCellFeatures(WritableCellFeatures cf) { - if (features != null) + if (features != null) { - logger.warn("current cell features for " + - CellReferenceHelper.getCellReference(this) + + logger.warn("current cell features for " + + CellReferenceHelper.getCellReference(this) + " not null - overwriting"); // Check to see if the features include a shared data validation @@ -521,8 +518,8 @@ public void setCellFeatures(WritableCellFeatures cf) features.getDVParser().extendedCellsValidation()) { DVParser dvp = features.getDVParser(); - logger.warn("Cannot add cell features to " + - CellReferenceHelper.getCellReference(this) + + logger.warn("Cannot add cell features to " + + CellReferenceHelper.getCellReference(this) + " because it is part of the shared cell validation " + "group " + CellReferenceHelper.getCellReference(dvp.getFirstColumn(), @@ -546,8 +543,8 @@ public void setCellFeatures(WritableCellFeatures cf) } /** - * Handles any addition cell features, such as comments or data - * validation. Called internally from this class when a cell is + * Handles any addition cell features, such as comments or data + * validation. Called internally from this class when a cell is * added to the workbook, and also externally from BaseCellFeatures * following a call to setComment */ @@ -567,11 +564,12 @@ public final void addCellFeatures() if (features.getComment() != null) { - Comment comment = new Comment(features.getComment(), - column, row); + Comment comment = sheet.getWorkbook().getWorkbookBof().isBiff8() + ? new CommentBiff8(features.getComment(), column, row) + : new CommentBiff7(features.getComment(), column, row, sheet.getWorkbook().getSettings()); comment.setWidth(features.getCommentWidth()); comment.setHeight(features.getCommentHeight()); - sheet.addDrawing(comment); + sheet.addDrawing(comment); sheet.getWorkbook().addDrawing(comment); features.setCommentDrawing(comment); } @@ -580,9 +578,9 @@ public final void addCellFeatures() { try { - features.getDVParser().setCell(column, - row, - sheet.getWorkbook(), + features.getDVParser().setCell(column, + row, + sheet.getWorkbook(), sheet.getWorkbook(), sheet.getWorkbookSettings()); } @@ -596,7 +594,7 @@ public final void addCellFeatures() { return; } - + // Get the combo box drawing object for list validations if (sheet.getComboBox() == null) { @@ -614,7 +612,7 @@ public final void addCellFeatures() } /** - * Internal function invoked by WritableSheetImpl called when shared data + * Internal function invoked by WritableSheetImpl called when shared data * validation is removed */ public final void removeCellFeatures() diff --git a/src/jxl/write/biff/CompoundFile.java b/src/jxl/write/biff/CompoundFile.java index ac5789f..0ce497e 100644 --- a/src/jxl/write/biff/CompoundFile.java +++ b/src/jxl/write/biff/CompoundFile.java @@ -34,7 +34,7 @@ /** * Writes out a compound file - * + * * Header block is -1 * Excel data is e..n (where e is the head extension blocks, normally 0 and * n is at least 8) @@ -151,12 +151,12 @@ final class CompoundFile extends BaseCompoundFile /** * The list of additional, non standard property sets names */ - private ArrayList additionalPropertySets; + private ArrayList additionalPropertySets; /** * The map of standard property sets, keyed on name */ - private HashMap standardPropertySets; + private HashMap standardPropertySets; /** * Structure used to store the property set and the data @@ -192,14 +192,14 @@ private static final class ReadPropertyStorage /** * Constructor - * + * * @param l the length of the data * @param os the output stream to write to * @param data the excel data * @param rcf the read compound */ - public CompoundFile(ExcelDataOutput data, int l, OutputStream os, - jxl.read.biff.CompoundFile rcf) + public CompoundFile(ExcelDataOutput data, int l, OutputStream os, + jxl.read.biff.CompoundFile rcf) throws CopyAdditionalPropertySetsException, IOException { super(); @@ -209,7 +209,7 @@ public CompoundFile(ExcelDataOutput data, int l, OutputStream os, readAdditionalPropertySets(rcf); numRootEntryBlocks = 1; - numPropertySets = 4 + + numPropertySets = 4 + (additionalPropertySets != null ? additionalPropertySets.size() : 0); @@ -236,7 +236,7 @@ public CompoundFile(ExcelDataOutput data, int l, OutputStream os, { requiredSize = blocks * BIG_BLOCK_SIZE; } - + out = os; @@ -246,7 +246,7 @@ public CompoundFile(ExcelDataOutput data, int l, OutputStream os, int blockChainLength = (BIG_BLOCK_SIZE - BIG_BLOCK_DEPOT_BLOCKS_POS)/4; - int startTotalBlocks = excelDataBlocks + + int startTotalBlocks = excelDataBlocks + 8 + // summary block 8 + // document information additionalPropertyBlocks + @@ -257,14 +257,14 @@ public CompoundFile(ExcelDataOutput data, int l, OutputStream os, int totalBlocks = startTotalBlocks + numBigBlockDepotBlocks; // Calculate the number of BBD blocks needed to hold this info - numBigBlockDepotBlocks = (int) Math.ceil( (double) totalBlocks / + numBigBlockDepotBlocks = (int) Math.ceil( (double) totalBlocks / (double) (BIG_BLOCK_SIZE/4)); // Does this affect the total? totalBlocks = startTotalBlocks + numBigBlockDepotBlocks; // And recalculate - numBigBlockDepotBlocks = (int) Math.ceil( (double) totalBlocks / + numBigBlockDepotBlocks = (int) Math.ceil( (double) totalBlocks / (double) (BIG_BLOCK_SIZE/4)); // Does this affect the total? @@ -286,15 +286,15 @@ public CompoundFile(ExcelDataOutput data, int l, OutputStream os, // Modify the total number of blocks required and recalculate the // the number of bbd blocks - totalBlocks = startTotalBlocks + - numExtensionBlocks + + totalBlocks = startTotalBlocks + + numExtensionBlocks + numBigBlockDepotBlocks; - numBigBlockDepotBlocks = (int) Math.ceil( (double) totalBlocks / + numBigBlockDepotBlocks = (int) Math.ceil( (double) totalBlocks / (double) (BIG_BLOCK_SIZE/4)); // The final total - totalBlocks = startTotalBlocks + - numExtensionBlocks + + totalBlocks = startTotalBlocks + + numExtensionBlocks + numBigBlockDepotBlocks; } else @@ -311,8 +311,8 @@ public CompoundFile(ExcelDataOutput data, int l, OutputStream os, sbdStartBlock = -2; if (additionalPropertySets != null && numSmallBlockDepotBlocks != 0) { - sbdStartBlock = excelDataStartBlock + - excelDataBlocks + + sbdStartBlock = excelDataStartBlock + + excelDataBlocks + additionalPropertyBlocks + 16; } @@ -320,12 +320,12 @@ public CompoundFile(ExcelDataOutput data, int l, OutputStream os, // Set the sbd chain start block to be after the excel data and the // small block depot sbdStartBlockChain = -2; - + if (sbdStartBlock != -2) { sbdStartBlockChain = sbdStartBlock + numSmallBlockDepotBlocks; } - + // Set the bbd start block to be after all the excel data if (sbdStartBlockChain != -2) { @@ -335,7 +335,7 @@ public CompoundFile(ExcelDataOutput data, int l, OutputStream os, else { bbdStartBlock = excelDataStartBlock + - excelDataBlocks + + excelDataBlocks + additionalPropertyBlocks + 16; } @@ -347,7 +347,7 @@ public CompoundFile(ExcelDataOutput data, int l, OutputStream os, if (totalBlocks != rootStartBlock + numRootEntryBlocks) { - logger.warn("Root start block and total blocks are inconsistent " + + logger.warn("Root start block and total blocks are inconsistent " + " generated file may be corrupt"); logger.warn("RootStartBlock " + rootStartBlock + " totalBlocks " + totalBlocks); } @@ -361,7 +361,7 @@ public CompoundFile(ExcelDataOutput data, int l, OutputStream os, * @exception IOException */ private void readAdditionalPropertySets - (jxl.read.biff.CompoundFile readCompoundFile) + (jxl.read.biff.CompoundFile readCompoundFile) throws CopyAdditionalPropertySetsException, IOException { if (readCompoundFile == null) @@ -369,12 +369,12 @@ public CompoundFile(ExcelDataOutput data, int l, OutputStream os, return; } - additionalPropertySets = new ArrayList(); - standardPropertySets = new HashMap(); + additionalPropertySets = new ArrayList<>(); + standardPropertySets = new HashMap<>(); int blocksRequired = 0; int numPropertySets = readCompoundFile.getNumberOfPropertySets(); - + for (int i = 0 ; i < numPropertySets ; i++) { PropertyStorage ps = readCompoundFile.getPropertySet(i); @@ -446,8 +446,8 @@ public CompoundFile(ExcelDataOutput data, int l, OutputStream os, /** * Writes out the excel file in OLE compound file format - * - * @exception IOException + * + * @exception IOException */ public void write() throws IOException { @@ -460,7 +460,7 @@ public void write() throws IOException writeSmallBlockDepotChain(); writeBigBlockDepot(); writePropertySets(); - + // Don't flush or close the stream - this is handled by the enclosing File // object } @@ -475,9 +475,7 @@ private void writeAdditionalPropertySets() throws IOException return; } - for (Iterator i = additionalPropertySets.iterator(); i.hasNext() ;) - { - ReadPropertyStorage rps = (ReadPropertyStorage) i.next(); + for (ReadPropertyStorage rps : additionalPropertySets) { byte[] data = rps.data; if (data.length > SMALL_BLOCK_THRESHOLD) @@ -486,7 +484,7 @@ private void writeAdditionalPropertySets() throws IOException int requiredSize = numBlocks * BIG_BLOCK_SIZE; out.write(data, 0, data.length); - + byte[] padding = new byte[requiredSize - data.length]; out.write(padding, 0, padding.length); } @@ -496,9 +494,9 @@ private void writeAdditionalPropertySets() throws IOException /** * Writes out the excel data, padding it out with empty bytes as * necessary - * Also write out empty - * - * @exception IOException + * Also write out empty + * + * @exception IOException */ private void writeExcelData() throws IOException { @@ -510,8 +508,8 @@ private void writeExcelData() throws IOException /** * Write out the document summary data. This is just blank - * - * @exception IOException + * + * @exception IOException */ private void writeDocumentSummaryData() throws IOException { @@ -523,8 +521,8 @@ private void writeDocumentSummaryData() throws IOException /** * Write out the summary data. This is just blank - * - * @exception IOException + * + * @exception IOException */ private void writeSummaryData() throws IOException { @@ -536,8 +534,8 @@ private void writeSummaryData() throws IOException /** * Writes the compound file header - * - * @exception IOException + * + * @exception IOException */ private void writeHeader() throws IOException { @@ -558,54 +556,54 @@ private void writeHeader() throws IOException headerBlock[0x39] = 0x10; // Set the number of BBD blocks - IntegerHelper.getFourBytes(numBigBlockDepotBlocks, - headerBlock, - NUM_BIG_BLOCK_DEPOT_BLOCKS_POS); + IntegerHelper.getFourBytes(numBigBlockDepotBlocks, + headerBlock, + NUM_BIG_BLOCK_DEPOT_BLOCKS_POS); - // Set the small block depot chain + // Set the small block depot chain IntegerHelper.getFourBytes(sbdStartBlockChain, headerBlock, SMALL_BLOCK_DEPOT_BLOCK_POS); - // Set the number of blocks in the small block depot chain + // Set the number of blocks in the small block depot chain IntegerHelper.getFourBytes(numSmallBlockDepotChainBlocks, headerBlock, NUM_SMALL_BLOCK_DEPOT_BLOCKS_POS); - // Set the extension block + // Set the extension block IntegerHelper.getFourBytes(extensionBlock, headerBlock, EXTENSION_BLOCK_POS); // Set the number of extension blocks to be the number of BBD blocks - 1 IntegerHelper.getFourBytes(numExtensionBlocks, - headerBlock, + headerBlock, NUM_EXTENSION_BLOCK_POS); - + // Set the root start block IntegerHelper.getFourBytes(rootStartBlock, headerBlock, ROOT_START_BLOCK_POS); - // Set the block numbers for the BBD. Set the BBD running + // Set the block numbers for the BBD. Set the BBD running // after the excel data and summary information int pos = BIG_BLOCK_DEPOT_BLOCKS_POS; // See how many blocks fit into the header - int blocksToWrite = Math.min(numBigBlockDepotBlocks, - (BIG_BLOCK_SIZE - + int blocksToWrite = Math.min(numBigBlockDepotBlocks, + (BIG_BLOCK_SIZE - BIG_BLOCK_DEPOT_BLOCKS_POS)/4); int blocksWritten = 0; for (int i = 0 ; i < blocksToWrite; i++) { - IntegerHelper.getFourBytes(bbdStartBlock + i, + IntegerHelper.getFourBytes(bbdStartBlock + i, headerBlock, pos); pos += 4; blocksWritten++; } - + // Pad out the rest of the header with blanks for (int i = pos; i < BIG_BLOCK_SIZE; i++) { @@ -619,12 +617,12 @@ private void writeHeader() throws IOException for (int extBlock = 0; extBlock < numExtensionBlocks; extBlock++) { - blocksToWrite = Math.min(numBigBlockDepotBlocks - blocksWritten, + blocksToWrite = Math.min(numBigBlockDepotBlocks - blocksWritten, BIG_BLOCK_SIZE/4 -1); for(int j = 0 ; j < blocksToWrite; j++) { - IntegerHelper.getFourBytes(bbdStartBlock + blocksWritten + j, + IntegerHelper.getFourBytes(bbdStartBlock + blocksWritten + j, extensionBlockData, pos); pos += 4; @@ -633,7 +631,7 @@ private void writeHeader() throws IOException blocksWritten += blocksToWrite; // Indicate the next block, or the termination of the chain - int nextBlock = (blocksWritten == numBigBlockDepotBlocks) ? + int nextBlock = (blocksWritten == numBigBlockDepotBlocks) ? -2 : extBlock+1 ; IntegerHelper.getFourBytes(nextBlock, extensionBlockData, pos); pos +=4; @@ -654,8 +652,8 @@ private void writeHeader() throws IOException /** * Checks that the data can fit into the current BBD block. If not, * then it moves on to the next block - * - * @exception IOException + * + * @exception IOException */ private void checkBbdPos() throws IOException { @@ -663,7 +661,7 @@ private void checkBbdPos() throws IOException { // Write out the extension block. This will simply be the next block out.write(bigBlockDepot); - + // Create a new block bigBlockDepot = new byte[BIG_BLOCK_SIZE]; bbdPos = 0; @@ -677,12 +675,12 @@ private void checkBbdPos() throws IOException * @param numBlocks the number of blocks in the chain * @exception IOException */ - private void writeBlockChain(int startBlock, int numBlocks) + private void writeBlockChain(int startBlock, int numBlocks) throws IOException { int blocksToWrite = numBlocks - 1; int blockNumber = startBlock + 1; - + while (blocksToWrite > 0) { int bbdBlocks = Math.min(blocksToWrite, (BIG_BLOCK_SIZE - bbdPos)/4); @@ -693,12 +691,12 @@ private void writeBlockChain(int startBlock, int numBlocks) bbdPos +=4 ; blockNumber++; } - + blocksToWrite -= bbdBlocks; checkBbdPos(); } - // Write the end of the block chain + // Write the end of the block chain IntegerHelper.getFourBytes(-2, bigBlockDepot, bbdPos); bbdPos += 4; checkBbdPos(); @@ -717,9 +715,7 @@ private void writeAdditionalPropertySetBlockChains() throws IOException } int blockNumber = excelDataStartBlock + excelDataBlocks + 16; - for (Iterator i = additionalPropertySets.iterator(); i.hasNext() ; ) - { - ReadPropertyStorage rps = (ReadPropertyStorage) i.next(); + for (ReadPropertyStorage rps : additionalPropertySets) if (rps.data.length > SMALL_BLOCK_THRESHOLD) { int numBlocks = getBigBlocksRequired(rps.data.length); @@ -727,9 +723,8 @@ private void writeAdditionalPropertySetBlockChains() throws IOException writeBlockChain(blockNumber, numBlocks); blockNumber += numBlocks; } - } } - + /** * Writes out the chains for the small block depot */ @@ -740,25 +735,22 @@ private void writeSmallBlockDepotChain() throws IOException return; } - byte[] smallBlockDepotChain = + byte[] smallBlockDepotChain = new byte[numSmallBlockDepotChainBlocks * BIG_BLOCK_SIZE]; int pos = 0; int sbdBlockNumber = 1; - for (Iterator i = additionalPropertySets.iterator(); i.hasNext() ; ) - { - ReadPropertyStorage rps = (ReadPropertyStorage) i.next(); - + for (ReadPropertyStorage rps : additionalPropertySets) if (rps.data.length <= SMALL_BLOCK_THRESHOLD && - rps.data.length != 0) + rps.data.length != 0) { int numSmallBlocks = getSmallBlocksRequired(rps.data.length); for (int j = 0 ; j < numSmallBlocks - 1 ; j++) { - IntegerHelper.getFourBytes(sbdBlockNumber, - smallBlockDepotChain, - pos); + IntegerHelper.getFourBytes(sbdBlockNumber, + smallBlockDepotChain, + pos); pos += 4; sbdBlockNumber++; } @@ -768,7 +760,6 @@ private void writeSmallBlockDepotChain() throws IOException pos += 4; sbdBlockNumber++; } - } out.write(smallBlockDepotChain); } @@ -785,15 +776,12 @@ private void writeSmallBlockDepot() throws IOException return; } - byte[] smallBlockDepot = + byte[] smallBlockDepot = new byte[numSmallBlockDepotBlocks * BIG_BLOCK_SIZE]; int pos = 0; - for (Iterator i = additionalPropertySets.iterator() ; i.hasNext() ; ) - { - ReadPropertyStorage rps = (ReadPropertyStorage) i.next(); - + for (ReadPropertyStorage rps : additionalPropertySets) if (rps.data.length <= SMALL_BLOCK_THRESHOLD) { int smallBlocks = getSmallBlocksRequired(rps.data.length); @@ -801,15 +789,14 @@ private void writeSmallBlockDepot() throws IOException System.arraycopy(rps.data, 0, smallBlockDepot, pos, rps.data.length); pos += length; } - } out.write(smallBlockDepot); } /** * Writes out the Big Block Depot - * - * @exception IOException + * + * @exception IOException */ private void writeBigBlockDepot() throws IOException { @@ -827,12 +814,12 @@ private void writeBigBlockDepot() throws IOException } writeBlockChain(excelDataStartBlock, excelDataBlocks); - + // The excel data has been written. Now write out the rest of it // Write the block chain for the summary information - int summaryInfoBlock = excelDataStartBlock + - excelDataBlocks + + int summaryInfoBlock = excelDataStartBlock + + excelDataBlocks + additionalPropertyBlocks; for (int i = summaryInfoBlock; i < summaryInfoBlock + 7; i++) @@ -840,7 +827,7 @@ private void writeBigBlockDepot() throws IOException IntegerHelper.getFourBytes(i + 1, bigBlockDepot, bbdPos); bbdPos +=4 ; checkBbdPos(); - } + } // Write the end of the block chain for the summary info block IntegerHelper.getFourBytes(-2, bigBlockDepot, bbdPos); @@ -853,7 +840,7 @@ private void writeBigBlockDepot() throws IOException IntegerHelper.getFourBytes(i + 1, bigBlockDepot, bbdPos); bbdPos +=4 ; checkBbdPos(); - } + } // Write the end of the block chain for the document summary IntegerHelper.getFourBytes(-2, bigBlockDepot, bbdPos); @@ -872,7 +859,7 @@ private void writeBigBlockDepot() throws IOException writeBlockChain(sbdStartBlockChain, numSmallBlockDepotChainBlocks); } - // The Big Block Depot immediately follows. Denote these as a special + // The Big Block Depot immediately follows. Denote these as a special // block for (int i = 0; i < numBigBlockDepotBlocks; i++) { @@ -896,7 +883,7 @@ private void writeBigBlockDepot() throws IOException } /** - * Calculates the number of big blocks required to store data of the + * Calculates the number of big blocks required to store data of the * specified length * * @param length the length of the data @@ -905,12 +892,12 @@ private void writeBigBlockDepot() throws IOException private int getBigBlocksRequired(int length) { int blocks = length / BIG_BLOCK_SIZE; - + return (length % BIG_BLOCK_SIZE > 0 )? blocks + 1 : blocks; } /** - * Calculates the number of small blocks required to store data of the + * Calculates the number of small blocks required to store data of the * specified length * * @param length the length of the data @@ -919,14 +906,14 @@ private int getBigBlocksRequired(int length) private int getSmallBlocksRequired(int length) { int blocks = length / SMALL_BLOCK_SIZE; - + return (length % SMALL_BLOCK_SIZE > 0 )? blocks + 1 : blocks; } /** * Writes out the property sets - * - * @exception IOException + * + * @exception IOException */ private void writePropertySets() throws IOException { @@ -939,12 +926,11 @@ private void writePropertySets() throws IOException if (additionalPropertySets != null) { mappings = new int[numPropertySets]; - + // Map the standard ones to the first four for (int i = 0 ; i < STANDARD_PROPERTY_SETS.length ; i++) { - ReadPropertyStorage rps = (ReadPropertyStorage) - standardPropertySets.get(STANDARD_PROPERTY_SETS[i]); + ReadPropertyStorage rps = standardPropertySets.get(STANDARD_PROPERTY_SETS[i]); if (rps != null) { @@ -952,16 +938,14 @@ private void writePropertySets() throws IOException } else { - logger.warn("Standard property set " + STANDARD_PROPERTY_SETS[i] + + logger.warn("Standard property set " + STANDARD_PROPERTY_SETS[i] + " not present in source file"); } } // Now go through the original ones int newMapping = STANDARD_PROPERTY_SETS.length; - for (Iterator i = additionalPropertySets.iterator(); i.hasNext(); ) - { - ReadPropertyStorage rps = (ReadPropertyStorage) i.next(); + for (ReadPropertyStorage rps : additionalPropertySets) { mappings[rps.number] = newMapping; newMapping++; } @@ -973,7 +957,7 @@ private void writePropertySets() throws IOException // Compute the size of the root property set int size = 0; - + if (additionalPropertySets != null) { // Workbook @@ -984,23 +968,20 @@ private void writePropertySets() throws IOException size += getBigBlocksRequired(SMALL_BLOCK_THRESHOLD) * BIG_BLOCK_SIZE; // Additional property sets - for (Iterator i = additionalPropertySets.iterator(); i.hasNext(); ) - { - ReadPropertyStorage rps = (ReadPropertyStorage) i.next(); + for (ReadPropertyStorage rps : additionalPropertySets) if (rps.propertyStorage.type != 1) { if (rps.propertyStorage.size >= SMALL_BLOCK_THRESHOLD) { - size += getBigBlocksRequired(rps.propertyStorage.size) * - BIG_BLOCK_SIZE; + size += getBigBlocksRequired(rps.propertyStorage.size) * + BIG_BLOCK_SIZE; } else { - size += getSmallBlocksRequired(rps.propertyStorage.size) * - SMALL_BLOCK_SIZE; + size += getSmallBlocksRequired(rps.propertyStorage.size) * + SMALL_BLOCK_SIZE; } } - } } // Set the root entry property set @@ -1015,14 +996,13 @@ private void writePropertySets() throws IOException child = 1; if (additionalPropertySets != null) { - ReadPropertyStorage rps = (ReadPropertyStorage) - standardPropertySets.get(ROOT_ENTRY_NAME); + ReadPropertyStorage rps = standardPropertySets.get(ROOT_ENTRY_NAME); child = mappings[rps.propertyStorage.child]; } ps.setChild(child); - System.arraycopy(ps.data, 0, - propertySetStorage, pos, + System.arraycopy(ps.data, 0, + propertySetStorage, pos, PROPERTY_STORAGE_BLOCK_SIZE); pos += PROPERTY_STORAGE_BLOCK_SIZE; @@ -1035,17 +1015,16 @@ private void writePropertySets() throws IOException ps.setSize(requiredSize); // always use a big block stream - none of that messing around // with small blocks - + previous = 3; next = -1; if (additionalPropertySets != null) { - ReadPropertyStorage rps = (ReadPropertyStorage) - standardPropertySets.get(WORKBOOK_NAME); - previous = rps.propertyStorage.previous != -1 ? + ReadPropertyStorage rps = standardPropertySets.get(WORKBOOK_NAME); + previous = rps.propertyStorage.previous != -1 ? mappings[rps.propertyStorage.previous] : -1; - next = rps.propertyStorage.next != -1 ? + next = rps.propertyStorage.next != -1 ? mappings[rps.propertyStorage.next] : -1 ; } @@ -1053,8 +1032,8 @@ private void writePropertySets() throws IOException ps.setNext(next); ps.setChild(-1); - System.arraycopy(ps.data, 0, - propertySetStorage, pos, + System.arraycopy(ps.data, 0, + propertySetStorage, pos, PROPERTY_STORAGE_BLOCK_SIZE); pos += PROPERTY_STORAGE_BLOCK_SIZE; @@ -1069,8 +1048,7 @@ private void writePropertySets() throws IOException if (additionalPropertySets != null) { - ReadPropertyStorage rps = (ReadPropertyStorage) - standardPropertySets.get(SUMMARY_INFORMATION_NAME); + ReadPropertyStorage rps = standardPropertySets.get(SUMMARY_INFORMATION_NAME); if (rps != null) { @@ -1085,8 +1063,8 @@ private void writePropertySets() throws IOException ps.setNext(next); ps.setChild(-1); - System.arraycopy(ps.data, 0, - propertySetStorage, pos, + System.arraycopy(ps.data, 0, + propertySetStorage, pos, PROPERTY_STORAGE_BLOCK_SIZE); pos += PROPERTY_STORAGE_BLOCK_SIZE; @@ -1099,8 +1077,8 @@ private void writePropertySets() throws IOException ps.setNext(-1); ps.setChild(-1); - System.arraycopy(ps.data, 0, - propertySetStorage, pos, + System.arraycopy(ps.data, 0, + propertySetStorage, pos, PROPERTY_STORAGE_BLOCK_SIZE); pos += PROPERTY_STORAGE_BLOCK_SIZE; @@ -1112,16 +1090,13 @@ private void writePropertySets() throws IOException out.write(propertySetStorage); return; } - + int bigBlock = excelDataStartBlock + excelDataBlocks + 16; int smallBlock = 0; - for (Iterator i = additionalPropertySets.iterator() ; i.hasNext(); ) - { - ReadPropertyStorage rps = (ReadPropertyStorage) i.next(); - - int block = rps.data.length > SMALL_BLOCK_THRESHOLD ? - bigBlock : smallBlock; + for (ReadPropertyStorage rps : additionalPropertySets) { + int block = rps.data.length > SMALL_BLOCK_THRESHOLD ? + bigBlock : smallBlock; ps = new PropertyStorage(rps.propertyStorage.name); ps.setType(rps.propertyStorage.type); @@ -1129,20 +1104,20 @@ private void writePropertySets() throws IOException ps.setSize(rps.propertyStorage.size); // ps.setColour(rps.propertyStorage.colour); - previous = rps.propertyStorage.previous != -1 ? - mappings[rps.propertyStorage.previous] : -1; - next = rps.propertyStorage.next != -1 ? - mappings[rps.propertyStorage.next] : -1; - child = rps.propertyStorage.child != -1 ? - mappings[rps.propertyStorage.child] : -1; + previous = rps.propertyStorage.previous != -1 ? + mappings[rps.propertyStorage.previous] : -1; + next = rps.propertyStorage.next != -1 ? + mappings[rps.propertyStorage.next] : -1; + child = rps.propertyStorage.child != -1 ? + mappings[rps.propertyStorage.child] : -1; ps.setPrevious(previous); ps.setNext(next); ps.setChild(child); - System.arraycopy(ps.data, 0, - propertySetStorage, pos, - PROPERTY_STORAGE_BLOCK_SIZE); + System.arraycopy(ps.data, 0, + propertySetStorage, pos, + PROPERTY_STORAGE_BLOCK_SIZE); pos += PROPERTY_STORAGE_BLOCK_SIZE; if (rps.data.length > SMALL_BLOCK_THRESHOLD) diff --git a/src/jxl/write/biff/DBCellRecord.java b/src/jxl/write/biff/DBCellRecord.java index b3aa1d8..ac81c96 100644 --- a/src/jxl/write/biff/DBCellRecord.java +++ b/src/jxl/write/biff/DBCellRecord.java @@ -27,7 +27,7 @@ import jxl.biff.WritableRecordData; /** - * Indexes the first row record of the block and each individual cell. + * Indexes the first row record of the block and each individual cell. * This is invoked by the sheets write process */ class DBCellRecord extends WritableRecordData @@ -35,7 +35,7 @@ class DBCellRecord extends WritableRecordData /** * The file position of the first Row record in this block */ - private int rowPos; + private final int rowPos; /** * The position of the start of the next cell after the first row. This @@ -46,7 +46,7 @@ class DBCellRecord extends WritableRecordData /** * The list of all cell positions in this block */ - private ArrayList cellRowPositions; + private final ArrayList cellRowPositions = new ArrayList<>(10); /** * The position of this record in the file. Vital for calculating offsets @@ -55,19 +55,18 @@ class DBCellRecord extends WritableRecordData /** * Constructor - * + * * @param rp the position of this row */ public DBCellRecord(int rp) { super(Type.DBCELL); rowPos = rp; - cellRowPositions = new ArrayList(10); } /** * Sets the offset of this cell record within the sheet stream - * + * * @param pos the offset */ void setCellOffset(int pos) @@ -77,17 +76,17 @@ void setCellOffset(int pos) /** * Adds a cell - * - * @param pos + * + * @param pos */ void addCellRowPosition(int pos) { - cellRowPositions.add(new Integer(pos)); + cellRowPositions.add(pos); } /** * Sets the position of this cell within the sheet stream - * + * * @param pos the position */ void setPosition(int pos) @@ -97,7 +96,7 @@ void setPosition(int pos) /** * Gets the binary data for this cell record - * + * * @return the binary data */ protected byte[] getData() @@ -110,10 +109,7 @@ protected byte[] getData() // Now add in all the cell offsets int pos = 4; int lastCellPos = cellOffset; - Iterator i = cellRowPositions.iterator(); - while (i.hasNext()) - { - int cellPos = ((Integer) i.next()).intValue(); + for (int cellPos : cellRowPositions) { IntegerHelper.getTwoBytes(cellPos - lastCellPos, data, pos); lastCellPos = cellPos; pos += 2; diff --git a/src/jxl/write/biff/DateRecord.java b/src/jxl/write/biff/DateRecord.java index c115e5e..f5c54ad 100644 --- a/src/jxl/write/biff/DateRecord.java +++ b/src/jxl/write/biff/DateRecord.java @@ -23,8 +23,6 @@ import java.util.Calendar; import java.util.Date; -import jxl.common.Logger; - import jxl.CellType; import jxl.DateCell; import jxl.biff.DoubleHelper; @@ -38,10 +36,6 @@ */ public abstract class DateRecord extends CellValue { - /** - * The logger - */ - private static Logger logger = Logger.getLogger(DateRecord.class); /** * The excel value of the date @@ -161,7 +155,7 @@ protected DateRecord(int c, int r, Date d, CellFormat st, boolean tim) super(Type.NUMBER, c, r, st); date = d; time = tim; - calculateValue(false); + calculateValue(true); } /** @@ -174,7 +168,7 @@ protected DateRecord(DateCell dc) super(Type.NUMBER, dc); date = dc.getDate(); time = dc.isTime(); - calculateValue(false); + calculateValue(true); } /** @@ -238,7 +232,7 @@ private void calculateValue(boolean adjust) // If this refers to a time, then get rid of the integer part if (time) { - value = value - (int) value; + value -= (int) value; } } diff --git a/src/jxl/write/biff/ExternalSheetRecord.java b/src/jxl/write/biff/ExternalSheetRecord.java index ad0c077..f94c5d3 100644 --- a/src/jxl/write/biff/ExternalSheetRecord.java +++ b/src/jxl/write/biff/ExternalSheetRecord.java @@ -40,7 +40,7 @@ class ExternalSheetRecord extends WritableRecordData /** * The list of XTI structures */ - private ArrayList xtis; + private final ArrayList xtis; /** * An XTI structure @@ -97,19 +97,18 @@ void sheetRemoved(int index) /** * Constructor - * + * * @param esf the external sheet record to copy */ public ExternalSheetRecord(jxl.read.biff.ExternalSheetRecord esf) { super(Type.EXTERNSHEET); - xtis = new ArrayList(esf.getNumRecords()); - XTI xti = null; + xtis = new ArrayList<>(esf.getNumRecords()); for (int i = 0 ; i < esf.getNumRecords(); i++) { - xti = new XTI(esf.getSupbookIndex(i), - esf.getFirstTabIndex(i), + XTI xti = new XTI(esf.getSupbookIndex(i), + esf.getFirstTabIndex(i), esf.getLastTabIndex(i)); xtis.add(xti); } @@ -121,7 +120,7 @@ public ExternalSheetRecord(jxl.read.biff.ExternalSheetRecord esf) public ExternalSheetRecord() { super(Type.EXTERNSHEET); - xtis = new ArrayList(); + xtis = new ArrayList<>(); } /** @@ -132,13 +131,12 @@ public ExternalSheetRecord() */ int getIndex(int supbookind, int sheetind) { - Iterator i = xtis.iterator(); - XTI xti = null; + Iterator i = xtis.iterator(); boolean found = false; int pos = 0; while (i.hasNext() && !found) { - xti = (XTI) i.next(); + XTI xti = i.next(); if (xti.supbookIndex == supbookind && xti.firstTab == sheetind) @@ -153,7 +151,7 @@ int getIndex(int supbookind, int sheetind) if (!found) { - xti = new XTI(supbookind, sheetind, sheetind); + XTI xti = new XTI(supbookind, sheetind, sheetind); xtis.add(xti); pos = xtis.size() - 1; } @@ -163,7 +161,7 @@ int getIndex(int supbookind, int sheetind) /** * Gets the binary data for output to file - * + * * @return the binary data */ public byte[] getData() @@ -174,51 +172,47 @@ public byte[] getData() IntegerHelper.getTwoBytes(xtis.size(), data, 0); pos += 2; - Iterator i = xtis.iterator(); - XTI xti = null; - while (i.hasNext()) - { - xti = (XTI) i.next(); + for (XTI xti : xtis) { IntegerHelper.getTwoBytes(xti.supbookIndex, data, pos); IntegerHelper.getTwoBytes(xti.firstTab, data, pos+2); IntegerHelper.getTwoBytes(xti.lastTab, data, pos+4); pos +=6 ; } - + return data; } /** * Gets the supbook index for the specified external sheet - * + * * @param the index of the supbook record - * @return the supbook index + * @return the supbook index */ public int getSupbookIndex(int index) { - return ((XTI) xtis.get(index)).supbookIndex; + return xtis.get(index).supbookIndex; } /** * Gets the first tab index for the specified external sheet - * + * * @param the index of the supbook record * @return the first tab index */ public int getFirstTabIndex(int index) { - return ((XTI) xtis.get(index)).firstTab; + return xtis.get(index).firstTab; } /** * Gets the last tab index for the specified external sheet - * + * * @param the index of the supbook record * @return the last tab index */ public int getLastTabIndex(int index) { - return ((XTI) xtis.get(index)).lastTab; + return xtis.get(index).lastTab; } /** @@ -227,12 +221,8 @@ public int getLastTabIndex(int index) */ void sheetInserted(int index) { - XTI xti = null; - for (Iterator i = xtis.iterator(); i.hasNext() ; ) - { - xti = (XTI) i.next(); + for (XTI xti : xtis) xti.sheetInserted(index); - } } /** @@ -241,12 +231,8 @@ void sheetInserted(int index) */ void sheetRemoved(int index) { - XTI xti = null; - for (Iterator i = xtis.iterator(); i.hasNext() ; ) - { - xti = (XTI) i.next(); + for (XTI xti : xtis) xti.sheetRemoved(index); - } } } diff --git a/src/jxl/write/biff/FileDataOutput.java b/src/jxl/write/biff/FileDataOutput.java index 165bb5a..ea37f63 100644 --- a/src/jxl/write/biff/FileDataOutput.java +++ b/src/jxl/write/biff/FileDataOutput.java @@ -19,11 +19,8 @@ package jxl.write.biff; -import java.io.OutputStream; -import java.io.IOException; -import java.io.File; -import java.io.RandomAccessFile; - +import java.io.*; +import java.nio.file.*; import jxl.common.Logger; /** @@ -32,18 +29,16 @@ */ class FileDataOutput implements ExcelDataOutput { - // The logger - private static Logger logger = Logger.getLogger(FileDataOutput.class); /** * The temporary file */ - private File temporaryFile; + private final Path temporaryFile; /** * The excel data */ - private RandomAccessFile data; + private final RandomAccessFile data; /** * Constructor @@ -51,11 +46,11 @@ class FileDataOutput implements ExcelDataOutput * @param tmpdir the temporary directory used to write files. If this is * NULL then the sytem temporary directory will be used */ - public FileDataOutput(File tmpdir) throws IOException + public FileDataOutput(Path tmpdir) throws IOException { - temporaryFile = File.createTempFile("jxl",".tmp", tmpdir); - temporaryFile.deleteOnExit(); - data = new RandomAccessFile(temporaryFile, "rw"); + temporaryFile = Files.createTempFile(tmpdir,"jxl",".tmp"); + temporaryFile.toFile().deleteOnExit(); + data = new RandomAccessFile(temporaryFile.toFile(), "rw"); } /** @@ -74,6 +69,7 @@ public void write(byte[] bytes) throws IOException * * @return the position within the file */ + @Override public int getPosition() throws IOException { // As all excel data structures are four bytes anyway, it's ok to @@ -98,6 +94,7 @@ public void setData(byte[] newdata, int pos) throws IOException /** * Writes the data to the output stream */ + @Override public void writeData(OutputStream out) throws IOException { byte[] buffer = new byte[1024]; @@ -112,12 +109,13 @@ public void writeData(OutputStream out) throws IOException /** * Called when the final compound file has been written */ + @Override public void close() throws IOException { data.close(); // Explicitly delete the temporary file, since sometimes it is the case // that a single process may be generating multiple different excel files - temporaryFile.delete(); + Files.delete(temporaryFile); } } diff --git a/src/jxl/write/biff/HorizontalPageBreaksRecord.java b/src/jxl/write/biff/HorizontalPageBreaksRecord.java index 521fc95..d9b92df 100644 --- a/src/jxl/write/biff/HorizontalPageBreaksRecord.java +++ b/src/jxl/write/biff/HorizontalPageBreaksRecord.java @@ -19,30 +19,30 @@ package jxl.write.biff; -import jxl.biff.IntegerHelper; -import jxl.biff.Type; -import jxl.biff.WritableRecordData; +import java.io.IOException; +import java.util.*; +import java.util.stream.Collectors; +import jxl.biff.*; +import jxl.read.biff.IHorizontalPageBreaks; /** * Contains the list of explicit horizontal page breaks on the current sheet */ -class HorizontalPageBreaksRecord extends WritableRecordData -{ +class HorizontalPageBreaksRecord extends WritableRecordData implements IHorizontalPageBreaks { + /** * The row breaks */ - private int[] rowBreaks; + private List rowBreaks = new ArrayList<>(); /** * Constructor * * @param break the row breaks */ - public HorizontalPageBreaksRecord(int[] breaks) + HorizontalPageBreaksRecord() { super(Type.HORIZONTALPAGEBREAKS); - - rowBreaks = breaks; } /** @@ -50,23 +50,82 @@ public HorizontalPageBreaksRecord(int[] breaks) * * @return the binary data */ + @Override public byte[] getData() { - byte[] data = new byte[rowBreaks.length * 6 + 2]; + byte[] data = new byte[rowBreaks.size() * 6 + 2]; // The number of breaks on the list - IntegerHelper.getTwoBytes(rowBreaks.length, data, 0); + IntegerHelper.getTwoBytes(rowBreaks.size(), data, 0); int pos = 2; - for (int i = 0; i < rowBreaks.length; i++) - { - IntegerHelper.getTwoBytes(rowBreaks[i], data, pos); - IntegerHelper.getTwoBytes(0xff, data, pos+4); + for (RowIndex rb : rowBreaks) { + IntegerHelper.getTwoBytes(rb.getFirstRowBelowBreak(), data, pos); + IntegerHelper.getTwoBytes(rb.getFirstColumn(), data, pos+2); + IntegerHelper.getTwoBytes(rb.getLastColumn(), data, pos+4); pos += 6; } return data; } -} + @Override + public List getRowBreaks() { + return rowBreaks.stream() + .map(RowIndex::getFirstRowBelowBreak) + .collect(Collectors.toList()); + } + + void setRowBreaks(IHorizontalPageBreaks breaks) { + rowBreaks = breaks.getRowBreaks().stream() + .map(i -> rowToRowIndex(i)) + .collect(Collectors.toList()); + } + + void clear() { + rowBreaks.clear(); + } + + void addBreak(int row) { + // First check that the row is not already present + Iterator i = rowBreaks.iterator(); + + while (i.hasNext()) + if (i.next().getFirstRowBelowBreak() == row) + return; + + rowBreaks.add(rowToRowIndex(row)); + } + + private RowIndex rowToRowIndex(int col) { + return new RowIndex(col, 0, 0xffff); + } + + void insertRow(int row) { + ListIterator ri = rowBreaks.listIterator(); + while (ri.hasNext()) + { + RowIndex val = ri.next(); + if (val.getFirstRowBelowBreak() >= row) + ri.set(val.withFirstRowBelowBreak(val.getFirstRowBelowBreak()+1)); + } + } + void removeRow(int row) { + ListIterator ri = rowBreaks.listIterator(); + while (ri.hasNext()) + { + RowIndex val = ri.next(); + if (val.getFirstRowBelowBreak() == row) + ri.remove(); + else if (val.getFirstRowBelowBreak() > row) + ri.set(val.withFirstRowBelowBreak(val.getFirstRowBelowBreak()-1)); + } + } + + void write(File outputFile) throws IOException { + if (rowBreaks.size() > 0) + outputFile.write(this); + } + +} diff --git a/src/jxl/write/biff/HyperlinkRecord.java b/src/jxl/write/biff/HyperlinkRecord.java index 04c3b3f..0106b0d 100644 --- a/src/jxl/write/biff/HyperlinkRecord.java +++ b/src/jxl/write/biff/HyperlinkRecord.java @@ -22,6 +22,7 @@ import java.io.File; import java.net.URL; import java.net.MalformedURLException; +import java.nio.file.Path; import java.util.ArrayList; import jxl.common.Assert; @@ -78,7 +79,7 @@ public class HyperlinkRecord extends WritableRecordData /** * The local file referred to by this hyperlink */ - private File file; + private Path file; /** * The location in this workbook referred to by this hyperlink @@ -216,7 +217,7 @@ private void copyWritableHyperlink(Hyperlink hl, WritableSheet s) if (h.file != null) { - file = new File(h.file.getPath()); + file = h.file; } location = h.location; @@ -272,7 +273,7 @@ protected HyperlinkRecord(int col, int row, * @param desc the description */ protected HyperlinkRecord(int col, int row, int lastcol, int lastrow, - File file, String desc) + Path file, String desc) { super(Type.HLINK); @@ -285,7 +286,7 @@ protected HyperlinkRecord(int col, int row, int lastcol, int lastrow, this.file = file; - if (file.getPath().startsWith("\\\\")) + if (file.toString().startsWith("\\\\")) { linkType = uncLink; } @@ -429,7 +430,7 @@ public URL getURL() * * @return the file, or NULL if this hyperlink is not a file */ - public File getFile() + public Path getFile() { return file; } @@ -617,7 +618,7 @@ public void setURL(URL url) * * @param file the file */ - public void setFile(File file) + public void setFile(Path file) { linkType = fileLink; url = null; @@ -943,7 +944,7 @@ private byte[] getURLData(byte[] cd) */ private byte[] getUNCData(byte[] cd) { - String uncString = file.getPath(); + String uncString = file.toString(); byte[] d = new byte[cd.length + uncString.length() * 2 + 2 + 4]; System.arraycopy(cd, 0, d, 0, cd.length); @@ -969,12 +970,12 @@ private byte[] getUNCData(byte[] cd) private byte[] getFileData(byte[] cd) { // Build up the directory hierarchy in reverse order - ArrayList path = new ArrayList(); - ArrayList shortFileName = new ArrayList(); - path.add(file.getName()); - shortFileName.add(getShortName(file.getName())); + ArrayList path = new ArrayList<>(); + ArrayList shortFileName = new ArrayList<>(); + path.add(file.toFile().getName()); + shortFileName.add(getShortName(file.toFile().getName())); - File parent = file.getParentFile(); + File parent = file.toFile().getParentFile(); while (parent != null) { path.add(parent.getName()); @@ -990,7 +991,7 @@ private byte[] getFileData(byte[] cd) while (upDir) { - String s = (String) path.get(pos); + String s = path.get(pos); if (s.equals("..")) { upLevelCount++; @@ -1005,12 +1006,12 @@ private byte[] getFileData(byte[] cd) pos--; } - StringBuffer filePathSB = new StringBuffer(); - StringBuffer shortFilePathSB = new StringBuffer(); + StringBuilder filePathSB = new StringBuilder(); + StringBuilder shortFilePathSB = new StringBuilder(); - if (file.getPath().charAt(1)==':') + if (file.toFile().getPath().charAt(1)==':') { - char driveLetter = file.getPath().charAt(0); + char driveLetter = file.toFile().getPath().charAt(0); if (driveLetter != 'C' && driveLetter != 'c') { filePathSB.append(driveLetter); @@ -1022,8 +1023,8 @@ private byte[] getFileData(byte[] cd) for (int i = path.size() - 1; i >= 0 ; i--) { - filePathSB.append((String)path.get(i)); - shortFilePathSB.append((String)shortFileName.get(i)); + filePathSB.append(path.get(i)); + shortFilePathSB.append(shortFileName.get(i)); if (i != 0) { diff --git a/src/jxl/write/biff/MergedCells.java b/src/jxl/write/biff/MergedCells.java index 88ce88d..525fbc1 100644 --- a/src/jxl/write/biff/MergedCells.java +++ b/src/jxl/write/biff/MergedCells.java @@ -20,8 +20,7 @@ package jxl.write.biff; import java.io.IOException; -import java.util.ArrayList; -import java.util.Iterator; +import java.util.*; import jxl.common.Assert; import jxl.common.Logger; @@ -44,19 +43,19 @@ class MergedCells /** * The logger */ - private static Logger logger = Logger.getLogger(MergedCells.class); + private static final Logger logger = Logger.getLogger(MergedCells.class); /** * The list of merged cells */ - private ArrayList ranges; + private List ranges = new ArrayList<>(); /** * The sheet containing the cells */ - private WritableSheet sheet; + private final WritableSheet sheet; - /** + /** * The maximum number of ranges per sheet */ private static final int maxRangesPerSheet = 1020; @@ -66,7 +65,6 @@ class MergedCells */ public MergedCells(WritableSheet ws) { - ranges = new ArrayList(); sheet = ws; } @@ -76,7 +74,7 @@ public MergedCells(WritableSheet ws) * * @param range the range to add */ - void add(Range r) + void add(SheetRangeImpl r) { ranges.add(r); } @@ -87,13 +85,8 @@ void add(Range r) void insertRow(int row) { // Adjust any merged cells - SheetRangeImpl sr = null; - Iterator i = ranges.iterator(); - while (i.hasNext()) - { - sr = (SheetRangeImpl) i.next(); + for (SheetRangeImpl sr : ranges) sr.insertRow(row); - } } /** @@ -101,13 +94,8 @@ void insertRow(int row) */ void insertColumn(int col) { - SheetRangeImpl sr = null; - Iterator i = ranges.iterator(); - while (i.hasNext()) - { - sr = (SheetRangeImpl) i.next(); + for (SheetRangeImpl sr : ranges) sr.insertColumn(col); - } } /** @@ -115,11 +103,10 @@ void insertColumn(int col) */ void removeColumn(int col) { - SheetRangeImpl sr = null; - Iterator i = ranges.iterator(); + Iterator i = ranges.iterator(); while (i.hasNext()) { - sr = (SheetRangeImpl) i.next(); + SheetRangeImpl sr = i.next(); if (sr.getTopLeft().getColumn() == col && sr.getBottomRight().getColumn() == col) { @@ -139,11 +126,10 @@ void removeColumn(int col) */ void removeRow(int row) { - SheetRangeImpl sr = null; - Iterator i = ranges.iterator(); + Iterator i = ranges.iterator(); while (i.hasNext()) { - sr = (SheetRangeImpl) i.next(); + SheetRangeImpl sr = i.next(); if (sr.getTopLeft().getRow() == row && sr.getBottomRight().getRow() == row) { @@ -161,18 +147,11 @@ void removeRow(int row) /** * Gets the cells which have been merged on this sheet * - * @return an array of range objects + * @return an unmodifiable view of range objects */ - Range[] getMergedCells() + List getMergedCells() { - Range[] cells = new Range[ranges.size()]; - - for (int i=0; i < cells.length; i++) - { - cells[i] = (Range) ranges.get(i); - } - - return cells; + return Collections.unmodifiableList(ranges); } /** @@ -184,7 +163,7 @@ Range[] getMergedCells() void unmergeCells(Range r) { int index = ranges.indexOf(r); - + if (index != -1) { ranges.remove(index); @@ -196,29 +175,25 @@ void unmergeCells(Range r) */ private void checkIntersections() { - ArrayList newcells = new ArrayList(ranges.size()); - - for (Iterator mci = ranges.iterator(); mci.hasNext() ; ) - { - SheetRangeImpl r = (SheetRangeImpl) mci.next(); + ArrayList newcells = new ArrayList<>(ranges.size()); + for (SheetRangeImpl r : ranges) { // Check that the range doesn't intersect with any existing range - Iterator i = newcells.iterator(); - SheetRangeImpl range = null; + Iterator i = newcells.iterator(); boolean intersects = false; while (i.hasNext() && !intersects) { - range = (SheetRangeImpl) i.next(); - + SheetRangeImpl range = i.next(); + if (range.intersects(r)) { logger.warn("Could not merge cells " + r + - " as they clash with an existing set of merged cells."); + " as they clash with an existing set of merged cells."); intersects = true; } } - + if (!intersects) { newcells.add(r); @@ -233,15 +208,11 @@ private void checkIntersections() * contains more than one item of data */ private void checkRanges() - { + { try { - SheetRangeImpl range = null; - // Check all the ranges to make sure they only contain one entry - for (int i = 0; i < ranges.size(); i++) - { - range = (SheetRangeImpl) ranges.get(i); + for (SheetRangeImpl range : ranges) { // Get the cell in the top left Cell tl = range.getTopLeft(); @@ -261,9 +232,9 @@ private void checkRanges() } else { - logger.warn("Range " + range + - " contains more than one data cell. " + - "Setting the other cells to blank."); + logger.warn("Range " + range + + " contains more than one data cell. " + + "Setting the other cells to blank."); Blank b = new Blank(c, r); sheet.addCell(b); } @@ -281,12 +252,10 @@ private void checkRanges() void write(File outputFile) throws IOException { - if (ranges.size() == 0) - { + if (ranges.isEmpty()) return; - } - WorkbookSettings ws = + WorkbookSettings ws = ( (WritableSheetImpl) sheet).getWorkbookSettings(); if (!ws.getMergedCellCheckingDisabled()) @@ -311,7 +280,7 @@ void write(File outputFile) throws IOException { int numranges = Math.min(maxRangesPerSheet, ranges.size() - pos); - ArrayList cells = new ArrayList(numranges); + ArrayList cells = new ArrayList<>(numranges); for (int j = 0 ; j < numranges ; j++) { cells.add(ranges.get(pos+j)); diff --git a/src/jxl/write/biff/MergedCellsRecord.java b/src/jxl/write/biff/MergedCellsRecord.java index f24d3ca..253e041 100644 --- a/src/jxl/write/biff/MergedCellsRecord.java +++ b/src/jxl/write/biff/MergedCellsRecord.java @@ -19,16 +19,14 @@ package jxl.write.biff; -import java.util.ArrayList; +import java.util.List; import jxl.Cell; import jxl.Range; -import jxl.biff.IntegerHelper; -import jxl.biff.Type; -import jxl.biff.WritableRecordData; +import jxl.biff.*; /** - * A number record. This is stored as 8 bytes, as opposed to the + * A number record. This is stored as 8 bytes, as opposed to the * 4 byte RK record */ public class MergedCellsRecord extends WritableRecordData @@ -36,14 +34,14 @@ public class MergedCellsRecord extends WritableRecordData /** * The ranges of all the cells which are merged on this sheet */ - private ArrayList ranges; + private List ranges; /** * Constructs a merged cell record * - * @param ws the sheet containing the merged cells + * @param mc the merged cells */ - protected MergedCellsRecord(ArrayList mc) + protected MergedCellsRecord(List mc) { super(Type.MERGEDCELLS); @@ -52,9 +50,10 @@ protected MergedCellsRecord(ArrayList mc) /** * Gets the raw data for output to file - * + * * @return the data to write to file */ + @Override public byte[] getData() { byte[] data = new byte[ranges.size() * 8 + 2]; @@ -71,7 +70,7 @@ public byte[] getData() // Set the various cell records Cell tl = range.getTopLeft(); Cell br = range.getBottomRight(); - + IntegerHelper.getTwoBytes(tl.getRow(), data, pos); IntegerHelper.getTwoBytes(br.getRow(), data, pos+2); IntegerHelper.getTwoBytes(tl.getColumn(), data, pos+4); diff --git a/src/jxl/write/biff/MulRKRecord.java b/src/jxl/write/biff/MulRKRecord.java index 7f83eb0..4ba64ac 100644 --- a/src/jxl/write/biff/MulRKRecord.java +++ b/src/jxl/write/biff/MulRKRecord.java @@ -34,34 +34,34 @@ class MulRKRecord extends WritableRecordData /** * The row containing these numbers */ - private int row; + private final int row; /** * The first column these rk number occur on */ - private int colFirst; + private final int colFirst; /** * The last column these rk number occur on */ - private int colLast; + private final int colLast; /** * The array of rk numbers */ - private int[] rknumbers; + private final int[] rknumbers; /** * The array of xf indices */ - private int[] xfIndices; + private final int[] xfIndices; /** * Constructs the rk numbers from the integer cells - * + * * @param numbers A list of jxl.write.Number objects */ - public MulRKRecord(List numbers) + public MulRKRecord(List numbers) { super(Type.MULRK); - row = ((Number)numbers.get(0)).getRow(); - colFirst = ((Number)numbers.get(0)).getColumn(); + row = numbers.get(0).getRow(); + colFirst = numbers.get(0).getColumn(); colLast = colFirst + numbers.size() - 1; rknumbers = new int[numbers.size()]; @@ -69,14 +69,14 @@ public MulRKRecord(List numbers) for (int i = 0; i < numbers.size(); i++) { - rknumbers[i] = (int) ((Number)numbers.get(i)).getValue(); + rknumbers[i] = (int) numbers.get(i).getValue(); xfIndices[i] = ( (CellValue) numbers.get(i)).getXFIndex(); } } /** * Gets the binary data for output to file - * + * * @return the binary data */ public byte[] getData() @@ -94,7 +94,7 @@ public byte[] getData() for (int i = 0; i < rknumbers.length; i++) { IntegerHelper.getTwoBytes(xfIndices[i], data, pos); - + // To represent an int as an Excel RK value, we have to // undergo some outrageous jiggery pokery, as follows: diff --git a/src/jxl/write/biff/NameRecord.java b/src/jxl/write/biff/NameRecord.java index ef335d8..87896a2 100644 --- a/src/jxl/write/biff/NameRecord.java +++ b/src/jxl/write/biff/NameRecord.java @@ -19,13 +19,9 @@ package jxl.write.biff; -import jxl.common.Logger; - -import jxl.biff.BuiltInName; -import jxl.biff.IntegerHelper; -import jxl.biff.StringHelper; -import jxl.biff.Type; -import jxl.biff.WritableRecordData; +import java.util.Objects; +import jxl.WorkbookSettings; +import jxl.biff.*; /** * A name record. Simply takes the binary data from the name @@ -33,8 +29,6 @@ */ class NameRecord extends WritableRecordData { - // The logger - private static Logger logger = Logger.getLogger(NameRecord.class); /** * The binary data for output to file */ @@ -54,7 +48,7 @@ class NameRecord extends WritableRecordData * The index into the name table */ private int index; - + /** * The 0-based index sheet reference for a record name * 0 is for a global reference @@ -66,7 +60,7 @@ class NameRecord extends WritableRecordData */ private boolean modified; - /** + /** * A nested class to hold range information */ static class NameRange @@ -85,14 +79,14 @@ static class NameRange rowLast = nr.getLastRow(); externalSheet = nr.getExternalSheet(); } - + /** * Create a new range for the name record. */ - NameRange(int extSheet, - int theStartRow, + NameRange(int extSheet, + int theStartRow, int theEndRow, - int theStartCol, + int theStartCol, int theEndCol) { columnFirst = theStartCol; @@ -107,7 +101,7 @@ static class NameRange int getLastColumn() {return columnLast;} int getLastRow() {return rowLast;} int getExternalSheet() { return externalSheet;} - + void incrementFirstRow() { rowFirst++ ; } void incrementLastRow() { rowLast++ ; } void decrementFirstRow() { rowFirst-- ; } @@ -126,10 +120,10 @@ byte[] getData() // Starting row IntegerHelper.getTwoBytes(rowFirst, d, 2); - + // End row IntegerHelper.getTwoBytes(rowLast, d, 4); - + // Start column IntegerHelper.getTwoBytes(columnFirst & 0xff, d, 6); @@ -154,17 +148,24 @@ byte[] getData() // An empty range private static final NameRange EMPTY_RANGE = new NameRange(0,0,0,0,0); + private final WorkbookSettings settings; + /** * Constructor - used when copying sheets * - * @param index the index into the name table + * @param ws the workbook settings + * @param ind the index into the name table */ - public NameRecord(jxl.read.biff.NameRecord sr, int ind) + public NameRecord(jxl.read.biff.NameRecord sr, int ind, WorkbookSettings ws) { super(Type.NAME); data = sr.getData(); - name = sr.getName(); + + if (sr.getBuiltInName() != null) + builtInName = sr.getBuiltInName(); + else + name = sr.getName(); sheetRef = sr.getSheetRef(); index = ind; modified = false; @@ -176,11 +177,12 @@ public NameRecord(jxl.read.biff.NameRecord sr, int ind) { ranges[i] = new NameRange(r[i]); } + settings = ws; } /** * Create a new name record with the given information. - * + * * @param theName Name to be created. * @param theIndex Index of this name. * @param extSheet External sheet index this name refers to. @@ -190,34 +192,36 @@ public NameRecord(jxl.read.biff.NameRecord sr, int ind) * @param theEndCol Last column this name refers to. * @param global TRUE if this is a global name */ - NameRecord(String theName, - int theIndex, - int extSheet, - int theStartRow, - int theEndRow, - int theStartCol, + NameRecord(String theName, + int theIndex, + int extSheet, + int theStartRow, + int theEndRow, + int theStartCol, int theEndCol, boolean global) - { + { super(Type.NAME); + Objects.requireNonNull(theName); name = theName; index = theIndex; sheetRef = global ? 0 : index+1; // 0 indicates a global name, otherwise // the 1-based index of the sheet ranges = new NameRange[1]; - ranges[0] = new NameRange(extSheet, - theStartRow, - theEndRow, - theStartCol, + ranges[0] = new NameRange(extSheet, + theStartRow, + theEndRow, + theStartCol, theEndCol); modified = true; + settings = null; } /** * Create a new name record with the given information. - * + * * @param theName Name to be created. * @param theIndex Index of this name. * @param extSheet External sheet index this name refers to. @@ -227,33 +231,35 @@ public NameRecord(jxl.read.biff.NameRecord sr, int ind) * @param theEndCol Last column this name refers to. * @param global TRUE if this is a global name */ - NameRecord(BuiltInName theName, - int theIndex, - int extSheet, - int theStartRow, - int theEndRow, - int theStartCol, + NameRecord(BuiltInName theName, + int theIndex, + int extSheet, + int theStartRow, + int theEndRow, + int theStartCol, int theEndCol, boolean global) - { + { super(Type.NAME); + Objects.requireNonNull(theName); builtInName = theName; index = theIndex; sheetRef = global ? 0 : index + 1; // 0 indicates a global name, otherwise // the 1-based index of the sheet ranges = new NameRange[1]; - ranges[0] = new NameRange(extSheet, - theStartRow, - theEndRow, - theStartCol, + ranges[0] = new NameRange(extSheet, + theStartRow, + theEndRow, + theStartCol, theEndCol); + settings = null; } /** * Create a new name record with the given information for 2-range entities. - * + * * @param theName Name to be created. * @param theIndex Index of this name. * @param extSheet External sheet index this name refers to. @@ -264,43 +270,45 @@ public NameRecord(jxl.read.biff.NameRecord sr, int ind) * @param theStartRow2 First row this name refers to (2nd instance). * @param theEndRow2 Last row this name refers to (2nd instance). * @param theStartCol2 First column this name refers to (2nd instance). - * @param theEndCol2 Last column this name refers to (2nd instance). + * @param theEndCol2 Last column this name refers to (2nd instance). * @param global TRUE if this is a global name */ - NameRecord(BuiltInName theName, - int theIndex, - int extSheet, - int theStartRow, - int theEndRow, - int theStartCol, + NameRecord(BuiltInName theName, + int theIndex, + int extSheet, + int theStartRow, + int theEndRow, + int theStartCol, int theEndCol, - int theStartRow2, - int theEndRow2, - int theStartCol2, + int theStartRow2, + int theEndRow2, + int theStartCol2, int theEndCol2, boolean global) - { + { super(Type.NAME); + Objects.requireNonNull(theName); builtInName = theName; index = theIndex; sheetRef = global ? 0 : index + 1; // 0 indicates a global name, otherwise // the 1-based index of the sheet ranges = new NameRange[2]; - ranges[0] = new NameRange(extSheet, - theStartRow, - theEndRow, - theStartCol, + ranges[0] = new NameRange(extSheet, + theStartRow, + theEndRow, + theStartCol, theEndCol); - ranges[1] = new NameRange(extSheet, - theStartRow2, - theEndRow2, - theStartCol2, - theEndCol2); + ranges[1] = new NameRange(extSheet, + theStartRow2, + theEndRow2, + theStartCol2, + theEndCol2); + settings = null; } - - + + /** * Gets the binary data for output to file * @@ -319,7 +327,7 @@ public byte[] getData() final byte AREA_REFERENCE = 0x3b; int detailLength; - + if (ranges.length > 1) { detailLength = (ranges.length * AREA_RANGE_LENGTH) + 4; @@ -329,7 +337,7 @@ public byte[] getData() detailLength = AREA_RANGE_LENGTH; } - int length = NAME_HEADER_LENGTH + detailLength; + int length = NAME_HEADER_LENGTH + detailLength; length += builtInName != null ? 1 : name.length(); data = new byte[length]; @@ -352,7 +360,7 @@ public byte[] getData() } else { - data[3] = (byte) name.length(); + data[3] = (byte) name.length(); } // Size of the definitions @@ -362,8 +370,8 @@ public byte[] getData() IntegerHelper.getTwoBytes(sheetRef, data, 6); IntegerHelper.getTwoBytes(sheetRef, data, 8); - // Byte 10-13 are optional lengths [0,0,0,0] - // Byte 14 is length of name which is not used. + // Byte 10-13 are optional lengths [0,0,0,0] + // Byte 14 is length of name which is not used. // The name if (builtInName != null) @@ -372,14 +380,17 @@ public byte[] getData() } else { - StringHelper.getBytes(name, data, 15); + if (settings == null) + StringHelper.getBytes(name, data, 15); + else + StringHelper.getBytes(name, data, 15, settings); } // The actual range definition. int pos = builtInName != null ? 16 : name.length() + 15; - // If there are multiple ranges for the name, we must specify a - // subExpression type rather than areaReference and then put out + // If there are multiple ranges for the name, we must specify a + // subExpression type rather than areaReference and then put out // multiple areaReference entries with an end byte. if (ranges.length > 1) { @@ -391,7 +402,7 @@ public byte[] getData() for (int i = 0 ; i < ranges.length ; i++) { data[pos++] = areaReference; - rd = ranges[i].getData(); + rd = ranges[i].getData(); System.arraycopy(rd, 0, data, pos, rd.length); pos += rd.length; } @@ -411,7 +422,7 @@ public byte[] getData() } /** - * Accessor for the name + * Accessor for the name * * @return the name */ @@ -429,7 +440,7 @@ public int getIndex() { return index; } - + /** * The 0-based index sheet reference for a record name * 0 is for a global reference @@ -440,7 +451,7 @@ public int getSheetRef() { return sheetRef; } - + /** * Set the index sheet reference for a record name * 0 is for a global reference @@ -462,7 +473,7 @@ public NameRange[] getRanges() } /** - * Called when a row is inserted on the + * Called when a row is inserted on the * * @param sheetIndex the sheet index on which the column was inserted * @param row the column number which was inserted @@ -539,7 +550,7 @@ boolean rowRemoved(int sheetIndex, int row) { return true; } - + // otherwise just remove the empty ones NameRange[] newRanges = new NameRange[ranges.length - emptyRanges]; for (int i = 0 ; i < ranges.length ; i++) @@ -571,7 +582,7 @@ boolean columnRemoved(int sheetIndex, int col) continue; // shame on me - this is no better than a goto } - if (col == ranges[i].getFirstColumn() && col == + if (col == ranges[i].getFirstColumn() && col == ranges[i].getLastColumn()) { // remove the range @@ -605,7 +616,7 @@ boolean columnRemoved(int sheetIndex, int col) { return true; } - + // otherwise just remove the empty ones NameRange[] newRanges = new NameRange[ranges.length - emptyRanges]; for (int i = 0 ; i < ranges.length ; i++) @@ -623,7 +634,7 @@ boolean columnRemoved(int sheetIndex, int col) /** - * Called when a row is inserted on the + * Called when a row is inserted on the * * @param sheetIndex the sheet index on which the column was inserted * @param col the column number which was inserted @@ -651,5 +662,9 @@ void columnInserted(int sheetIndex, int col) } } + public BuiltInName getBuiltInName() { + return builtInName; + } + } diff --git a/src/jxl/write/biff/RowRecord.java b/src/jxl/write/biff/RowRecord.java index baf0260..d970c2e 100644 --- a/src/jxl/write/biff/RowRecord.java +++ b/src/jxl/write/biff/RowRecord.java @@ -22,12 +22,12 @@ import java.io.IOException; import java.util.ArrayList; import java.util.Iterator; +import java.util.List; import jxl.common.Logger; import jxl.CellType; import jxl.SheetSettings; -import jxl.WorkbookSettings; import jxl.biff.CellReferenceHelper; import jxl.biff.IndexMapping; import jxl.biff.IntegerHelper; @@ -48,10 +48,6 @@ class RowRecord extends WritableRecordData */ private static final Logger logger = Logger.getLogger(RowRecord.class); - /** - * The binary data - */ - private byte[] data; /** * The cells which comprise this row */ @@ -91,46 +87,46 @@ class RowRecord extends WritableRecordData /** * The amount to grow the cells array by */ - private static final int growSize = 10; + private static final int GROW_SIZE = 10; /** * The maximum integer value that can be squeezed into 30 bits */ - private static final int maxRKValue = 0x1fffffff; + private static final int MAX_RK_VALUE = 0x1fffffff; /** * The minimum integer value that can be squeezed into 30 bits */ - private static final int minRKValue = -0x20000000; + private static final int MIN_RK_VALUE = -0x20000000; /** * Indicates that the row is default height */ - private static int defaultHeightIndicator = 0xff; + private static final int DEFAULT_HEIGHT_INDICATOR = 0xff; /** * The maximum number of columns */ - private static int maxColumns = 256; + private static final int MAX_COLUMNS = 256; - /** + /** * The outline level of the row */ private int outlineLevel; - /** + /** * Is this the icon indicator row of a group? */ private boolean groupStart; - + /** * A handle back to the sheet */ - private WritableSheet sheet; + private final WritableSheet sheet; /** * Constructs an empty row which has the specified row number - * + * * @param rn the row number of this row */ public RowRecord(int rn, WritableSheet ws) @@ -139,7 +135,7 @@ public RowRecord(int rn, WritableSheet ws) rowNumber = rn; cells = new CellValue[0]; numColumns = 0; - rowHeight = defaultHeightIndicator; + rowHeight = DEFAULT_HEIGHT_INDICATOR; collapsed = false; matchesDefFontHeight = true; sheet = ws; @@ -147,7 +143,7 @@ public RowRecord(int rn, WritableSheet ws) /** * Sets the height of this row - * + * * @param h the row height */ public void setRowHeight(int h) @@ -175,10 +171,10 @@ public void setRowHeight(int h) * @param gs the group start * @param xf the xfrecord for the row (NULL if no default is set) */ - void setRowDetails(int height, - boolean mdfh, - boolean col, - int ol, + void setRowDetails(int height, + boolean mdfh, + boolean col, + int ol, boolean gs, XFRecord xfr) { @@ -187,7 +183,7 @@ void setRowDetails(int height, matchesDefFontHeight = mdfh; outlineLevel = ol; groupStart = gs; - + if (xfr != null) { defaultFormat = true; @@ -205,10 +201,10 @@ public void setCollapsed(boolean c) { collapsed = c; } - + /** * Gets the row number of this row - * + * * @return the row number */ public int getRowNumber() @@ -218,18 +214,18 @@ public int getRowNumber() /** * Adds a cell to this row, growing the array of cells as required - * + * * @param cv the cell to add */ public void addCell(CellValue cv) { int col = cv.getColumn(); - if (col >= maxColumns) + if (col >= MAX_COLUMNS) { - logger.warn("Could not add cell at " + - CellReferenceHelper.getCellReference(cv.getRow(), - cv.getColumn()) + + logger.warn("Could not add cell at " + + CellReferenceHelper.getCellReference(cv.getRow(), + cv.getColumn()) + " because it exceeds the maximum column limit"); return; } @@ -238,9 +234,8 @@ public void addCell(CellValue cv) if (col >= cells.length) { CellValue[] oldCells = cells; - cells = new CellValue[Math.max(oldCells.length + growSize, col+1)]; + cells = new CellValue[Math.max(oldCells.length + GROW_SIZE, col+1)]; System.arraycopy(oldCells, 0, cells, 0, oldCells.length); - oldCells = null; } // Remove any cell features from the cell being replaced @@ -269,7 +264,7 @@ public void addCell(CellValue cv) /** * Removes a cell from this row - * + * * @param col the column at which to remove the cell */ public void removeCell(int col) @@ -285,8 +280,8 @@ public void removeCell(int col) /** * Writes out the row information data (but not the individual cells) - * - * @exception IOException + * + * @exception IOException * @param outputFile the output file */ public void write(File outputFile) throws IOException @@ -298,21 +293,20 @@ public void write(File outputFile) throws IOException * Writes out all the cells in this row. If more than three integer * values occur consecutively, then a MulRK record is used to group the * numbers - * - * @exception IOException + * + * @exception IOException * @param outputFile the output file */ - public void writeCells(File outputFile) + public void writeCells(File outputFile) throws IOException { // This is the list for integer values - ArrayList integerValues = new ArrayList(); - boolean integerValue = false; + List integerValues = new ArrayList<>(); // Write out all the records for (int i = 0; i < numColumns; i++) { - integerValue = false; + boolean integerValue = false; if (cells[i] != null) { // See if this cell is a 30-bit integer value (without additional @@ -320,9 +314,9 @@ public void writeCells(File outputFile) if (cells[i].getType() == CellType.NUMBER) { Number nc = (Number) cells[i]; - if (nc.getValue() == (int) nc.getValue() && - nc.getValue() < maxRKValue && - nc.getValue() > minRKValue && + if (nc.getValue() == (int) nc.getValue() && + nc.getValue() < MAX_RK_VALUE && + nc.getValue() > MIN_RK_VALUE && nc.getCellFeatures() == null) { integerValue = true; @@ -332,7 +326,7 @@ public void writeCells(File outputFile) if (integerValue) { // This cell is an integer, add it to the list - integerValues.add(cells[i]); + integerValues.add((Number) cells[i]); } else { @@ -357,7 +351,7 @@ public void writeCells(File outputFile) writeIntegerValues(integerValues, outputFile); } } - + // All done. Write out any remaining integer values writeIntegerValues(integerValues, outputFile); } @@ -365,15 +359,15 @@ public void writeCells(File outputFile) /** * Writes out the list of integer values. If there are more than three, * a MulRK record is used, otherwise a sequence of Numbers is used - * - * @exception IOException + * + * @exception IOException * @param outputFile the output file * @param integerValues the array of integer values */ - private void writeIntegerValues(ArrayList integerValues, File outputFile) + private void writeIntegerValues(List integerValues, File outputFile) throws IOException { - if (integerValues.size() == 0) + if (integerValues.isEmpty()) { return; } @@ -387,10 +381,10 @@ private void writeIntegerValues(ArrayList integerValues, File outputFile) else { // Write out as number records - Iterator i = integerValues.iterator(); + Iterator i = integerValues.iterator(); while (i.hasNext()) { - outputFile.write((CellValue) i.next()); + outputFile.write(i.next()); } } @@ -400,24 +394,25 @@ private void writeIntegerValues(ArrayList integerValues, File outputFile) /** * Gets the row data to output to file - * + * * @return the binary data */ + @Override public byte[] getData() { // Write out the row record byte[] data = new byte[16]; // If the default row height has been changed in the sheet settings, - // then we need to set the rowHeight on this row explicitly, as + // then we need to set the rowHeight on this row explicitly, as // specifying the "match default" flag doesn't work int rh = rowHeight; - if (sheet.getSettings().getDefaultRowHeight() != + if (sheet.getSettings().getDefaultRowHeight() != SheetSettings.DEFAULT_DEFAULT_ROW_HEIGHT) { // the default row height has been changed. If this row does not // have a specific row height set on it, then set it to the default - if (rh == defaultHeightIndicator) + if (rh == DEFAULT_HEIGHT_INDICATOR) { rh = sheet.getSettings().getDefaultRowHeight(); } @@ -451,13 +446,13 @@ public byte[] getData() } IntegerHelper.getFourBytes(options, data, 12); - + return data; } /** * Gets the maximum column value which occurs in this row - * + * * @return the maximum column value */ public int getMaxColumn() @@ -467,9 +462,9 @@ public int getMaxColumn() /** * Gets the cell which occurs at the specified column value - * + * * @param col the colun for which to return the cell - * @return the cell value at the specified position, or null if the column + * @return the cell value at the specified position, or null if the column * is invalid */ public CellValue getCell(int col) @@ -478,36 +473,28 @@ public CellValue getCell(int col) } /** - * Increments the row of this cell by one. Invoked by the sheet when + * Increments the row of this cell by one. Invoked by the sheet when * inserting rows */ void incrementRow() { rowNumber++; - for (int i = 0; i < cells.length; i++) - { - if (cells[i] != null) - { - cells[i].incrementRow(); - } - } + for (CellValue cell : cells) + if (cell != null) + cell.incrementRow(); } /** - * Decrements the row of this cell by one. Invoked by the sheet when + * Decrements the row of this cell by one. Invoked by the sheet when * removing rows */ void decrementRow() { rowNumber--; - for (int i = 0; i < cells.length; i++) - { - if (cells[i] != null) - { - cells[i].decrementRow(); - } - } + for (CellValue cell : cells) + if (cell != null) + cell.decrementRow(); } /** @@ -530,7 +517,7 @@ void insertColumn(int col) if (numColumns >= cells.length - 1) { - cells = new CellValue[oldCells.length + growSize]; + cells = new CellValue[oldCells.length + GROW_SIZE]; } else { @@ -539,7 +526,7 @@ void insertColumn(int col) // Copy in everything up to the new column System.arraycopy(oldCells, 0, cells, 0, col); - + // Copy in the remaining cells System.arraycopy(oldCells, col, cells, col+1, numColumns - col); @@ -553,7 +540,7 @@ void insertColumn(int col) } // Adjust the maximum column record - numColumns = Math.min(numColumns+1, maxColumns); + numColumns = Math.min(numColumns+1, MAX_COLUMNS); } /** @@ -577,7 +564,7 @@ void removeColumn(int col) // Copy in everything up to the column System.arraycopy(oldCells, 0, cells, 0, col); - + // Copy in the remaining cells after the column System.arraycopy(oldCells, col + 1, cells, col, numColumns - (col+1)); @@ -601,7 +588,7 @@ void removeColumn(int col) */ public boolean isDefaultHeight() { - return rowHeight == defaultHeightIndicator; + return rowHeight == DEFAULT_HEIGHT_INDICATOR; } /** @@ -667,40 +654,40 @@ boolean matchesDefaultFontHeight() return matchesDefFontHeight; } - /** + /** * Accessor for the column's outline level * * @return the column's outline level */ - public int getOutlineLevel() + public int getOutlineLevel() { return outlineLevel; } - /** + /** * Accessor for row's groupStart state * * @return the row's groupStart state */ - public boolean getGroupStart() + public boolean getGroupStart() { return groupStart; } - /** + /** * Increments the row's outline level. This is how groups are made as well */ - public void incrementOutlineLevel() + public void incrementOutlineLevel() { outlineLevel++; } - /** - * Decrements the row's outline level. This removes it from a grouping + /** + * Decrements the row's outline level. This removes it from a grouping * level. If * all outline levels are gone the uncollapse the row. */ - public void decrementOutlineLevel() + public void decrementOutlineLevel() { if (0 < outlineLevel) { @@ -713,12 +700,12 @@ public void decrementOutlineLevel() } } - /** + /** * Sets the row's outline level * * @param level the row's outline level */ - public void setOutlineLevel(int level) + public void setOutlineLevel(int level) { outlineLevel = level; } @@ -728,7 +715,7 @@ public void setOutlineLevel(int level) * * @param value the group start state */ - public void setGroupStart(boolean value) + public void setGroupStart(boolean value) { groupStart = value; } diff --git a/src/jxl/write/biff/SSTContinueRecord.java b/src/jxl/write/biff/SSTContinueRecord.java index 1e17f11..ffbd735 100644 --- a/src/jxl/write/biff/SSTContinueRecord.java +++ b/src/jxl/write/biff/SSTContinueRecord.java @@ -20,7 +20,6 @@ package jxl.write.biff; import java.util.ArrayList; -import java.util.Iterator; import jxl.biff.IntegerHelper; import jxl.biff.StringHelper; @@ -48,11 +47,11 @@ class SSTContinueRecord extends WritableRecordData /** * The list of strings */ - private ArrayList strings; + private final ArrayList strings = new ArrayList<>(50); /** * The list of string lengths */ - private ArrayList stringLengths; + private final ArrayList stringLengths = new ArrayList<>(50); /** * The binary data */ @@ -65,8 +64,8 @@ class SSTContinueRecord extends WritableRecordData /** * The maximum amount of bytes available for the SST record */ - private static int maxBytes = 8228 - // max length - 4; // standard biff record stuff + private static final int maxBytes = 8228 - // max length + 4; // standard biff record stuff /** * Constructor @@ -79,8 +78,6 @@ public SSTContinueRecord() super(Type.CONTINUE); byteCount = 0; - strings = new ArrayList(50); - stringLengths = new ArrayList(50); } /** @@ -95,16 +92,9 @@ public int setFirstString(String s, boolean b) includeLength = b; firstStringLength = s.length(); - int bytes = 0; - - if (!includeLength) - { - bytes = s.length() * 2 + 1; - } - else - { - bytes = s.length() * 2 + 3; - } + int bytes = includeLength + ? s.length() * 2 + 3 + : s.length() * 2 + 1; if (bytes <= maxBytes) { @@ -115,7 +105,7 @@ public int setFirstString(String s, boolean b) // Calculate the number of characters we can add // The bytes variable will always be an odd number - int charsAvailable = includeLength ? (maxBytes - 4) / 2 : + int charsAvailable = includeLength ? (maxBytes - 4) / 2 : (maxBytes - 2) / 2; // Add what part of the string we can @@ -154,7 +144,7 @@ public int add(String s) return s.length(); } - stringLengths.add(new Integer(s.length())); + stringLengths.add(s.length()); if (bytes + byteCount < maxBytes) { @@ -178,14 +168,14 @@ public int add(String s) /** * Gets the binary data for output to file - * + * * @return the binary data */ public byte[] getData() { data = new byte[byteCount]; - int pos = 0; + int pos; // Write out the first string if (includeLength) @@ -205,21 +195,16 @@ public byte[] getData() pos += firstString.length() * 2; // Now write out the remainder of the strings - Iterator i = strings.iterator(); - String s = null; - int length = 0; int count = 0; - while (i.hasNext()) - { - s = (String) i.next(); - length = ( (Integer) stringLengths.get(count)).intValue(); + for (String s : strings) { + int length = stringLengths.get(count); IntegerHelper.getTwoBytes(length, data, pos); data[pos+2] = 0x01; StringHelper.getUnicodeBytes(s, data, pos+3); pos += s.length() * 2 + 3; count++; } - + return data; } } diff --git a/src/jxl/write/biff/SSTRecord.java b/src/jxl/write/biff/SSTRecord.java index 0de1b1d..eda94aa 100644 --- a/src/jxl/write/biff/SSTRecord.java +++ b/src/jxl/write/biff/SSTRecord.java @@ -20,7 +20,6 @@ package jxl.write.biff; import java.util.ArrayList; -import java.util.Iterator; import jxl.biff.IntegerHelper; import jxl.biff.StringHelper; @@ -28,26 +27,26 @@ import jxl.biff.WritableRecordData; /** - * A shared string table record. + * A shared string table record. */ class SSTRecord extends WritableRecordData { /** * The number of string references in the workbook */ - private int numReferences; + private final int numReferences; /** * The number of strings in this table */ - private int numStrings; + private final int numStrings; /** * The list of strings */ - private ArrayList strings; + private final ArrayList strings = new ArrayList<>(50); /** * The list of string lengths */ - private ArrayList stringLengths; + private final ArrayList stringLengths = new ArrayList<>(50); /** * The binary data */ @@ -55,7 +54,7 @@ class SSTRecord extends WritableRecordData /** * The count of bytes needed so far to contain this record */ - private int byteCount; + private int byteCount = 0; /** * The maximum amount of bytes available for the SST record @@ -76,9 +75,6 @@ public SSTRecord(int numRefs, int s) numReferences = numRefs; numStrings = s; - byteCount = 0; - strings = new ArrayList(50); - stringLengths = new ArrayList(50); } /** @@ -101,7 +97,7 @@ public int add(String s) // value in order to force the creation of a continue record } - stringLengths.add(new Integer(s.length())); + stringLengths.add(s.length()); if (bytes + byteCount < maxBytes) { @@ -135,7 +131,7 @@ public int getOffset() /** * Gets the binary data for output to file - * + * * @return the binary data */ public byte[] getData() @@ -147,20 +143,15 @@ public byte[] getData() int pos = 8; int count = 0; - Iterator i = strings.iterator(); - String s = null; - int length = 0; - while (i.hasNext()) - { - s = (String) i.next(); - length = ( (Integer) stringLengths.get(count)).intValue(); + for (String s : strings) { + int length = stringLengths.get(count); IntegerHelper.getTwoBytes(length, data, pos); - data[pos+2] = 0x01; + data[pos+2] = 0x01; // uncompressed 16 bit values StringHelper.getUnicodeBytes(s, data, pos+3); pos += s.length() * 2 + 3; count++; } - + return data; } } diff --git a/src/jxl/write/biff/SharedStrings.java b/src/jxl/write/biff/SharedStrings.java index 6a07051..216d885 100644 --- a/src/jxl/write/biff/SharedStrings.java +++ b/src/jxl/write/biff/SharedStrings.java @@ -33,12 +33,12 @@ class SharedStrings /** * All the strings in the spreadsheet, keyed on the string itself */ - private HashMap strings; + private final HashMap strings = new HashMap<>(100); /** * Contains the same strings, held in a list */ - private ArrayList stringList; + private final ArrayList stringList = new ArrayList<>(100); /** * The total occurrence of strings in the workbook @@ -50,8 +50,6 @@ class SharedStrings */ public SharedStrings() { - strings = new HashMap(100); - stringList = new ArrayList(100); totalOccurrences = 0; } @@ -65,18 +63,17 @@ public SharedStrings() */ public int getIndex(String s) { - Integer i = (Integer) strings.get(s); + Integer i = strings.get(s); - if (i == null) - { - i = new Integer(strings.size()); + if (i == null) { + i = strings.size(); strings.put(s, i); stringList.add(s); } totalOccurrences++; - return i.intValue(); + return i; } /** @@ -87,7 +84,7 @@ public int getIndex(String s) */ public String get(int i) { - return (String) stringList.get(i); + return stringList.get(i); } /** @@ -106,11 +103,11 @@ public void write(File outputFile) throws IOException ExtendedSSTRecord extsst = new ExtendedSSTRecord(stringList.size()); int bucketSize = extsst.getNumberOfStringsPerBucket(); - Iterator i = stringList.iterator(); + Iterator i = stringList.iterator(); int stringIndex = 0; while (i.hasNext() && charsLeft == 0) { - curString = (String) i.next(); + curString = i.next(); // offset + header bytes int relativePosition = sst.getOffset() + 4; charsLeft = sst.add(curString); @@ -131,7 +128,7 @@ public void write(File outputFile) throws IOException // Carry on looping through the array until all the strings are done while (i.hasNext()) { - curString = (String) i.next(); + curString = i.next(); int relativePosition = cont.getOffset() + 4; charsLeft = cont.add(curString); if ((stringIndex % bucketSize) == 0) { diff --git a/src/jxl/write/biff/SheetCopier.java b/src/jxl/write/biff/SheetCopier.java index 60fa707..691e6c3 100644 --- a/src/jxl/write/biff/SheetCopier.java +++ b/src/jxl/write/biff/SheetCopier.java @@ -19,11 +19,7 @@ package jxl.write.biff; -import java.util.Arrays; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.TreeSet; -import java.util.Iterator; +import java.util.*; import jxl.common.Assert; import jxl.common.Logger; @@ -31,16 +27,12 @@ import jxl.BooleanCell; import jxl.Cell; import jxl.CellType; -import jxl.CellView; import jxl.DateCell; -import jxl.HeaderFooter; import jxl.Hyperlink; -import jxl.Image; import jxl.LabelCell; import jxl.NumberCell; import jxl.Range; import jxl.Sheet; -import jxl.SheetSettings; import jxl.WorkbookSettings; import jxl.biff.AutoFilter; import jxl.biff.CellReferenceHelper; @@ -48,14 +40,11 @@ import jxl.biff.DataValidation; import jxl.biff.FormattingRecords; import jxl.biff.FormulaData; -import jxl.biff.IndexMapping; import jxl.biff.NumFormatRecordsException; import jxl.biff.SheetRangeImpl; import jxl.biff.XFRecord; import jxl.biff.drawing.Chart; -import jxl.biff.drawing.CheckBox; import jxl.biff.drawing.ComboBox; -import jxl.biff.drawing.Drawing; import jxl.biff.drawing.DrawingGroupObject; import jxl.format.CellFormat; import jxl.biff.formula.FormulaException; @@ -70,7 +59,6 @@ import jxl.write.Number; import jxl.write.WritableCell; import jxl.write.WritableCellFormat; -import jxl.write.WritableFont; import jxl.write.WritableHyperlink; import jxl.write.WritableImage; import jxl.write.WritableSheet; @@ -78,30 +66,30 @@ import jxl.write.WriteException; /** - * A transient utility object used to copy sheets. This + * A transient utility object used to copy sheets. This * functionality has been farmed out to a different class * in order to reduce the bloat of the WritableSheetImpl */ class SheetCopier { - private static Logger logger = Logger.getLogger(SheetCopier.class); + private static final Logger LOGGER = Logger.getLogger(SheetCopier.class); - private SheetImpl fromSheet; - private WritableSheetImpl toSheet; - private WorkbookSettings workbookSettings; + private final SheetImpl fromSheet; + private final WritableSheetImpl toSheet; + private final WorkbookSettings workbookSettings; // Objects used by the sheet - private TreeSet columnFormats; + private TreeSet columnFormats; private FormattingRecords formatRecords; - private ArrayList hyperlinks; + private ArrayList hyperlinks; private MergedCells mergedCells; - private ArrayList rowBreaks; - private ArrayList columnBreaks; + private final HorizontalPageBreaksRecord rowBreaks; + private final VerticalPageBreaksRecord columnBreaks; private SheetWriter sheetWriter; - private ArrayList drawings; - private ArrayList images; - private ArrayList conditionalFormats; - private ArrayList validatedCells; + private ArrayList drawings; + private ArrayList images; + private ArrayList conditionalFormats; + private ArrayList validatedCells; private AutoFilter autoFilter; private DataValidation dataValidation; private ComboBox comboBox; @@ -113,19 +101,22 @@ class SheetCopier private int maxColumnOutlineLevel; // Objects used to maintain state during the copy process - private HashMap xfRecords; - private HashMap fonts; - private HashMap formats; + private HashMap xfRecords; + private HashMap fonts; + private HashMap formats; - public SheetCopier(Sheet f, WritableSheet t) - { + public SheetCopier(Sheet f, WritableSheet t, + HorizontalPageBreaksRecord rb, + VerticalPageBreaksRecord cb) { fromSheet = (SheetImpl) f; toSheet = (WritableSheetImpl) t; workbookSettings = toSheet.getWorkbook().getSettings(); chartOnly = false; + rowBreaks = rb; + columnBreaks = cb; } - void setColumnFormats(TreeSet cf) + void setColumnFormats(TreeSet cf) { columnFormats = cf; } @@ -135,7 +126,7 @@ void setFormatRecords(FormattingRecords fr) formatRecords = fr; } - void setHyperlinks(ArrayList h) + void setHyperlinks(ArrayList h) { hyperlinks = h; } @@ -145,37 +136,27 @@ void setMergedCells(MergedCells mc) mergedCells = mc; } - void setRowBreaks(ArrayList rb) - { - rowBreaks = rb; - } - - void setColumnBreaks(ArrayList cb) - { - columnBreaks = cb; - } - void setSheetWriter(SheetWriter sw) { sheetWriter = sw; } - void setDrawings(ArrayList d) + void setDrawings(ArrayList d) { drawings = d; } - void setImages(ArrayList i) + void setImages(ArrayList i) { images = i; } - void setConditionalFormats(ArrayList cf) + void setConditionalFormats(ArrayList cf) { conditionalFormats = cf; } - void setValidatedCells(ArrayList vc) + void setValidatedCells(ArrayList vc) { validatedCells = vc; } @@ -221,52 +202,41 @@ public void copySheet() // Copy the column info records jxl.read.biff.ColumnInfoRecord[] readCirs = fromSheet.getColumnInfos(); - for (int i = 0 ; i < readCirs.length; i++) - { - jxl.read.biff.ColumnInfoRecord rcir = readCirs[i]; - for (int j = rcir.getStartColumn(); j <= rcir.getEndColumn() ; j++) + for (jxl.read.biff.ColumnInfoRecord rcir : readCirs) + for (int j = rcir.getStartColumn(); j <= rcir.getEndColumn() ; j++) { - ColumnInfoRecord cir = new ColumnInfoRecord(rcir, j, - formatRecords); + ColumnInfoRecord cir = new ColumnInfoRecord(rcir, j, + formatRecords); cir.setHidden(rcir.getHidden()); columnFormats.add(cir); } - } // Copy the hyperlinks - Hyperlink[] hls = fromSheet.getHyperlinks(); - for (int i = 0 ; i < hls.length; i++) - { - WritableHyperlink hr = new WritableHyperlink - (hls[i], toSheet); + for (Hyperlink hl : fromSheet.getHyperlinks()) { + WritableHyperlink hr = new WritableHyperlink(hl, toSheet); hyperlinks.add(hr); } // Copy the merged cells - Range[] merged = fromSheet.getMergedCells(); - - for (int i = 0; i < merged.length; i++) - { - mergedCells.add(new SheetRangeImpl((SheetRangeImpl)merged[i], toSheet)); - } + for (Range range : fromSheet.getMergedCells()) + mergedCells.add(new SheetRangeImpl((SheetRangeImpl) range, toSheet)); // Copy the row properties try { jxl.read.biff.RowRecord[] rowprops = fromSheet.getRowProperties(); - for (int i = 0; i < rowprops.length; i++) - { - RowRecord rr = toSheet.getRowRecord(rowprops[i].getRowNumber()); - XFRecord format = rowprops[i].hasDefaultFormat() ? - formatRecords.getXFRecord(rowprops[i].getXFIndex()) : null; - rr.setRowDetails(rowprops[i].getRowHeight(), - rowprops[i].matchesDefaultFontHeight(), - rowprops[i].isCollapsed(), - rowprops[i].getOutlineLevel(), - rowprops[i].getGroupStart(), + for (jxl.read.biff.RowRecord rowprop : rowprops) { + RowRecord rr = toSheet.getRowRecord(rowprop.getRowNumber()); + XFRecord format = rowprop.hasDefaultFormat() ? + formatRecords.getXFRecord(rowprop.getXFIndex()) : null; + rr.setRowDetails(rowprop.getRowHeight(), + rowprop.matchesDefaultFontHeight(), + rowprop.isCollapsed(), + rowprop.getOutlineLevel(), + rowprop.getGroupStart(), format); - numRows = Math.max(numRows, rowprops[i].getRowNumber() + 1); + numRows = Math.max(numRows, rowprop.getRowNumber() + 1); } } catch (RowsExceededException e) @@ -281,90 +251,63 @@ public void copySheet() // sheetWriter.setFooter(new FooterRecord(si.getFooter())); // Copy the page breaks - int[] rowbreaks = fromSheet.getRowPageBreaks(); - - if (rowbreaks != null) - { - for (int i = 0; i < rowbreaks.length; i++) - { - rowBreaks.add(new Integer(rowbreaks[i])); - } - } - - int[] columnbreaks = fromSheet.getColumnPageBreaks(); - - if (columnbreaks != null) - { - for (int i = 0; i < columnbreaks.length; i++) - { - columnBreaks.add(new Integer(columnbreaks[i])); - } - } + rowBreaks.setRowBreaks(fromSheet.getRowPageBreaks()); + columnBreaks.setColumnBreaks(fromSheet.getColumnPageBreaks()); // Copy the charts sheetWriter.setCharts(fromSheet.getCharts()); // Copy the drawings DrawingGroupObject[] dr = fromSheet.getDrawings(); - for (int i = 0 ; i < dr.length ; i++) - { - if (dr[i] instanceof jxl.biff.drawing.Drawing) - { + for (DrawingGroupObject dgo : dr) + if (dgo instanceof jxl.biff.drawing.Drawing) { WritableImage wi = new WritableImage - (dr[i], toSheet.getWorkbook().getDrawingGroup()); + (dgo, toSheet.getWorkbook().getDrawingGroup()); drawings.add(wi); images.add(wi); } - else if (dr[i] instanceof jxl.biff.drawing.Comment) - { - jxl.biff.drawing.Comment c = - new jxl.biff.drawing.Comment(dr[i], - toSheet.getWorkbook().getDrawingGroup(), - workbookSettings); + else if (dgo instanceof jxl.biff.drawing.Comment) { + jxl.biff.drawing.Comment c = dgo instanceof jxl.biff.drawing.CommentBiff7 + ? new jxl.biff.drawing.CommentBiff7(dgo, toSheet.getWorkbook().getDrawingGroup(), workbookSettings) + : new jxl.biff.drawing.CommentBiff8(dgo, toSheet.getWorkbook().getDrawingGroup()); drawings.add(c); - // Set up the reference on the cell value - CellValue cv = (CellValue) toSheet.getWritableCell(c.getColumn(), - c.getRow()); + CellValue cv = (CellValue) toSheet.getWritableCell(c.getColumn(), + c.getRow()); Assert.verify(cv.getCellFeatures() != null); cv.getWritableCellFeatures().setCommentDrawing(c); } - else if (dr[i] instanceof jxl.biff.drawing.Button) - { - jxl.biff.drawing.Button b = - new jxl.biff.drawing.Button - (dr[i], - toSheet.getWorkbook().getDrawingGroup(), - workbookSettings); + else if (dgo instanceof jxl.biff.drawing.Button) { + jxl.biff.drawing.Button b = + new jxl.biff.drawing.Button + (dgo, + toSheet.getWorkbook().getDrawingGroup(), + workbookSettings); drawings.add(b); } - else if (dr[i] instanceof jxl.biff.drawing.ComboBox) - { - jxl.biff.drawing.ComboBox cb = - new jxl.biff.drawing.ComboBox - (dr[i], - toSheet.getWorkbook().getDrawingGroup(), - workbookSettings); + else if (dgo instanceof jxl.biff.drawing.ComboBox) { + jxl.biff.drawing.ComboBox cb = + new jxl.biff.drawing.ComboBox + (dgo, + toSheet.getWorkbook().getDrawingGroup(), + workbookSettings); drawings.add(cb); } - else if (dr[i] instanceof jxl.biff.drawing.CheckBox) - { - jxl.biff.drawing.CheckBox cb = - new jxl.biff.drawing.CheckBox - (dr[i], - toSheet.getWorkbook().getDrawingGroup(), - workbookSettings); + else if (dgo instanceof jxl.biff.drawing.CheckBox) { + jxl.biff.drawing.CheckBox cb = + new jxl.biff.drawing.CheckBox + (dgo, + toSheet.getWorkbook().getDrawingGroup(), + workbookSettings); drawings.add(cb); } - } - // Copy the data validations DataValidation rdv = fromSheet.getDataValidation(); if (rdv != null) { - dataValidation = new DataValidation(rdv, - toSheet.getWorkbook(), + dataValidation = new DataValidation(rdv, + toSheet.getWorkbook(), toSheet.getWorkbook(), workbookSettings); int objid = dataValidation.getComboBoxObjectId(); @@ -379,10 +322,7 @@ else if (dr[i] instanceof jxl.biff.drawing.CheckBox) ConditionalFormat[] cf = fromSheet.getConditionalFormats(); if (cf.length > 0) { - for (int i = 0; i < cf.length ; i++) - { - conditionalFormats.add(cf[i]); - } + conditionalFormats.addAll(Arrays.asList(cf)); } // Get the autofilter @@ -403,7 +343,7 @@ else if (dr[i] instanceof jxl.biff.drawing.CheckBox) { if (fromSheet.getWorkbookBof().isBiff7()) { - logger.warn("Cannot copy Biff7 print settings record - ignoring"); + LOGGER.warn("Cannot copy Biff7 print settings record - ignoring"); } else { @@ -457,15 +397,15 @@ public void copyWritableSheet() for (int i = 0; i < copyRows.length ; i++) { row = copyRows[i]; - + if (row != null && (!row.isDefaultHeight() || row.isCollapsed())) { RowRecord rr = getRowRecord(i); - rr.setRowDetails(row.getRowHeight(), + rr.setRowDetails(row.getRowHeight(), row.matchesDefaultFontHeight(), - row.isCollapsed(), + row.isCollapsed(), row.getStyle()); } } @@ -487,13 +427,13 @@ public void copyWritableSheet() DataValidation rdv = fromWritableSheet.dataValidation; if (rdv != null) { - dataValidation = new DataValidation(rdv, + dataValidation = new DataValidation(rdv, + workbook, workbook, - workbook, workbookSettings); } - // Copy the charts + // Copy the charts sheetWriter.setCharts(fromWritableSheet.getCharts()); // Copy the drawings @@ -502,7 +442,7 @@ public void copyWritableSheet() { if (dr[i] instanceof jxl.biff.drawing.Drawing) { - WritableImage wi = new WritableImage(dr[i], + WritableImage wi = new WritableImage(dr[i], workbook.getDrawingGroup()); drawings.add(wi); images.add(wi); @@ -528,30 +468,28 @@ public void copyWritableSheet() (fromWritableSheet.buttonPropertySet); } */ - } + } /** * Imports a sheet from a different workbook, doing a deep copy */ public void importSheet() { - xfRecords = new HashMap(); - fonts = new HashMap(); - formats = new HashMap(); + xfRecords = new HashMap<>(); + fonts = new HashMap<>(); + formats = new HashMap<>(); deepCopyCells(); // Copy the column info records jxl.read.biff.ColumnInfoRecord[] readCirs = fromSheet.getColumnInfos(); - for (int i = 0 ; i < readCirs.length; i++) - { - jxl.read.biff.ColumnInfoRecord rcir = readCirs[i]; - for (int j = rcir.getStartColumn(); j <= rcir.getEndColumn() ; j++) + for (jxl.read.biff.ColumnInfoRecord rcir : readCirs) + for (int j = rcir.getStartColumn(); j <= rcir.getEndColumn() ; j++) { ColumnInfoRecord cir = new ColumnInfoRecord(rcir, j); int xfIndex = cir.getXfIndex(); - XFRecord cf = (WritableCellFormat) xfRecords.get(new Integer(xfIndex)); + XFRecord cf = xfRecords.get(xfIndex); if (cf == null) { @@ -563,39 +501,29 @@ public void importSheet() cir.setHidden(rcir.getHidden()); columnFormats.add(cir); } - } // Copy the hyperlinks - Hyperlink[] hls = fromSheet.getHyperlinks(); - for (int i = 0 ; i < hls.length; i++) - { - WritableHyperlink hr = new WritableHyperlink - (hls[i], toSheet); + for (Hyperlink hl : fromSheet.getHyperlinks()) { + WritableHyperlink hr = new WritableHyperlink(hl, toSheet); hyperlinks.add(hr); } // Copy the merged cells - Range[] merged = fromSheet.getMergedCells(); - - for (int i = 0; i < merged.length; i++) - { - mergedCells.add(new SheetRangeImpl((SheetRangeImpl)merged[i], toSheet)); - } + for (Range range : fromSheet.getMergedCells()) + mergedCells.add(new SheetRangeImpl((SheetRangeImpl) range, toSheet)); // Copy the row properties try { jxl.read.biff.RowRecord[] rowprops = fromSheet.getRowProperties(); - for (int i = 0; i < rowprops.length; i++) - { - RowRecord rr = toSheet.getRowRecord(rowprops[i].getRowNumber()); + for (jxl.read.biff.RowRecord rowprop : rowprops) { + RowRecord rr = toSheet.getRowRecord(rowprop.getRowNumber()); XFRecord format = null; - jxl.read.biff.RowRecord rowrec = rowprops[i]; + jxl.read.biff.RowRecord rowrec = rowprop; if (rowrec.hasDefaultFormat()) { - format = (WritableCellFormat) - xfRecords.get(new Integer(rowrec.getXFIndex())); + format = xfRecords.get(rowrec.getXFIndex()); if (format == null) { @@ -604,14 +532,13 @@ public void importSheet() WritableCellFormat wcf = copyCellFormat(readFormat); } } - - rr.setRowDetails(rowrec.getRowHeight(), - rowrec.matchesDefaultFontHeight(), - rowrec.isCollapsed(), - rowrec.getOutlineLevel(), - rowrec.getGroupStart(), - format); - numRows = Math.max(numRows, rowprops[i].getRowNumber() + 1); + rr.setRowDetails(rowrec.getRowHeight(), + rowrec.matchesDefaultFontHeight(), + rowrec.isCollapsed(), + rowrec.getOutlineLevel(), + rowrec.getGroupStart(), + format); + numRows = Math.max(numRows, rowprop.getRowNumber() + 1); } } catch (RowsExceededException e) @@ -626,31 +553,14 @@ public void importSheet() // sheetWriter.setFooter(new FooterRecord(si.getFooter())); // Copy the page breaks - int[] rowbreaks = fromSheet.getRowPageBreaks(); - - if (rowbreaks != null) - { - for (int i = 0; i < rowbreaks.length; i++) - { - rowBreaks.add(new Integer(rowbreaks[i])); - } - } - - int[] columnbreaks = fromSheet.getColumnPageBreaks(); - - if (columnbreaks != null) - { - for (int i = 0; i < columnbreaks.length; i++) - { - columnBreaks.add(new Integer(columnbreaks[i])); - } - } + rowBreaks.setRowBreaks(fromSheet.getRowPageBreaks()); + columnBreaks.setColumnBreaks(fromSheet.getColumnPageBreaks()); // Copy the charts Chart[] fromCharts = fromSheet.getCharts(); if (fromCharts != null && fromCharts.length > 0) { - logger.warn("Importing of charts is not supported"); + LOGGER.warn("Importing of charts is not supported"); /* sheetWriter.setCharts(fromSheet.getCharts()); IndexMapping xfMapping = new IndexMapping(200); @@ -691,64 +601,45 @@ public void importSheet() // Make sure the destination workbook has a drawing group // created in it - if (dr.length > 0 && + if (dr.length > 0 && toSheet.getWorkbook().getDrawingGroup() == null) { toSheet.getWorkbook().createDrawingGroup(); } - for (int i = 0 ; i < dr.length ; i++) - { - if (dr[i] instanceof jxl.biff.drawing.Drawing) - { - WritableImage wi = new WritableImage - (dr[i].getX(), dr[i].getY(), - dr[i].getWidth(), dr[i].getHeight(), - dr[i].getImageData()); + for (DrawingGroupObject dgo : dr) + if (dgo instanceof jxl.biff.drawing.Drawing) { + WritableImage wi = new WritableImage(dgo.getX(), dgo.getY(), dgo.getWidth(), dgo.getHeight(), dgo.getImageData()); toSheet.getWorkbook().addDrawing(wi); drawings.add(wi); images.add(wi); } - else if (dr[i] instanceof jxl.biff.drawing.Comment) - { - jxl.biff.drawing.Comment c = - new jxl.biff.drawing.Comment(dr[i], - toSheet.getWorkbook().getDrawingGroup(), - workbookSettings); + else if (dgo instanceof jxl.biff.drawing.Comment) { + jxl.biff.drawing.Comment c = dgo instanceof jxl.biff.drawing.CommentBiff7 + ? new jxl.biff.drawing.CommentBiff7(dgo, toSheet.getWorkbook().getDrawingGroup(), workbookSettings) + : new jxl.biff.drawing.CommentBiff8(dgo, toSheet.getWorkbook().getDrawingGroup()); drawings.add(c); - // Set up the reference on the cell value - CellValue cv = (CellValue) toSheet.getWritableCell(c.getColumn(), - c.getRow()); + CellValue cv = (CellValue) toSheet.getWritableCell(c.getColumn(), + c.getRow()); Assert.verify(cv.getCellFeatures() != null); cv.getWritableCellFeatures().setCommentDrawing(c); } - else if (dr[i] instanceof jxl.biff.drawing.Button) - { - jxl.biff.drawing.Button b = - new jxl.biff.drawing.Button - (dr[i], - toSheet.getWorkbook().getDrawingGroup(), - workbookSettings); + else if (dgo instanceof jxl.biff.drawing.Button) { + jxl.biff.drawing.Button b = new jxl.biff.drawing.Button(dgo, toSheet.getWorkbook().getDrawingGroup(), workbookSettings); drawings.add(b); } - else if (dr[i] instanceof jxl.biff.drawing.ComboBox) - { - jxl.biff.drawing.ComboBox cb = - new jxl.biff.drawing.ComboBox - (dr[i], - toSheet.getWorkbook().getDrawingGroup(), - workbookSettings); + else if (dgo instanceof jxl.biff.drawing.ComboBox) { + jxl.biff.drawing.ComboBox cb = new jxl.biff.drawing.ComboBox(dgo, toSheet.getWorkbook().getDrawingGroup(), workbookSettings); drawings.add(cb); } - } // Copy the data validations DataValidation rdv = fromSheet.getDataValidation(); if (rdv != null) { - dataValidation = new DataValidation(rdv, - toSheet.getWorkbook(), + dataValidation = new DataValidation(rdv, + toSheet.getWorkbook(), toSheet.getWorkbook(), workbookSettings); int objid = dataValidation.getComboBoxObjectId(); @@ -773,7 +664,7 @@ else if (dr[i] instanceof jxl.biff.drawing.ComboBox) { if (fromSheet.getWorkbookBof().isBiff7()) { - logger.warn("Cannot copy Biff7 print settings record - ignoring"); + LOGGER.warn("Cannot copy Biff7 print settings record - ignoring"); } else { @@ -798,64 +689,31 @@ else if (dr[i] instanceof jxl.biff.drawing.ComboBox) /** * Performs a shallow copy of the specified cell */ - private WritableCell shallowCopyCell(Cell cell) - { - CellType ct = cell.getType(); - WritableCell newCell = null; + private WritableCell shallowCopyCell(Cell cell) { + return switch (cell.getType()) { + case LABEL -> new Label((LabelCell) cell); + case NUMBER -> new Number((NumberCell) cell); + case DATE -> new DateTime((DateCell) cell); + case BOOLEAN -> new Boolean((BooleanCell) cell); + case NUMBER_FORMULA -> new ReadNumberFormulaRecord((FormulaData) cell); + case STRING_FORMULA -> new ReadStringFormulaRecord((FormulaData) cell); + case BOOLEAN_FORMULA -> new ReadBooleanFormulaRecord((FormulaData) cell); + case DATE_FORMULA -> new ReadDateFormulaRecord((FormulaData) cell); + case FORMULA_ERROR -> new ReadErrorFormulaRecord((FormulaData) cell); + case EMPTY -> (cell.getCellFormat() != null) + // It is a blank cell, rather than an empty cell, so + // it may have formatting information, so + // it must be copied + ? new Blank(cell) + : null; + case ERROR -> null; + }; - if (ct == CellType.LABEL) - { - newCell = new Label((LabelCell) cell); - } - else if (ct == CellType.NUMBER) - { - newCell = new Number((NumberCell) cell); - } - else if (ct == CellType.DATE) - { - newCell = new DateTime((DateCell) cell); - } - else if (ct == CellType.BOOLEAN) - { - newCell = new Boolean((BooleanCell) cell); - } - else if (ct == CellType.NUMBER_FORMULA) - { - newCell = new ReadNumberFormulaRecord((FormulaData) cell); - } - else if (ct == CellType.STRING_FORMULA) - { - newCell = new ReadStringFormulaRecord((FormulaData) cell); - } - else if( ct == CellType.BOOLEAN_FORMULA) - { - newCell = new ReadBooleanFormulaRecord((FormulaData) cell); - } - else if (ct == CellType.DATE_FORMULA) - { - newCell = new ReadDateFormulaRecord((FormulaData) cell); - } - else if(ct == CellType.FORMULA_ERROR) - { - newCell = new ReadErrorFormulaRecord((FormulaData) cell); - } - else if (ct == CellType.EMPTY) - { - if (cell.getCellFormat() != null) - { - // It is a blank cell, rather than an empty cell, so - // it may have formatting information, so - // it must be copied - newCell = new Blank(cell); - } - } - - return newCell; } - /** + /** * Performs a deep copy of the specified cell, handling the cell format - * + * * @param cell the cell to copy */ private WritableCell deepCopyCell(Cell cell) @@ -874,13 +732,13 @@ private WritableCell deepCopyCell(Cell cell) (fromSheet.getWorkbook(), fromSheet.getWorkbook(), workbookSettings); - + if (crossSheetReference) { try { - logger.warn("Formula " + rfr.getFormula() + - " in cell " + + LOGGER.warn("Formula " + rfr.getFormula() + + " in cell " + CellReferenceHelper.getCellReference(cell.getColumn(), cell.getRow()) + " cannot be imported because it references another " + @@ -888,12 +746,12 @@ private WritableCell deepCopyCell(Cell cell) } catch (FormulaException e) { - logger.warn("Formula in cell " + + LOGGER.warn("Formula in cell " + CellReferenceHelper.getCellReference(cell.getColumn(), cell.getRow()) + " cannot be imported: " + e.getMessage()); } - + // Create a new error formula and add it instead c = new Formula(cell.getColumn(), cell.getRow(), "\"ERROR\""); } @@ -902,8 +760,7 @@ private WritableCell deepCopyCell(Cell cell) // Copy the cell format CellFormat cf = c.getCellFormat(); int index = ( (XFRecord) cf).getXFIndex(); - WritableCellFormat wcf = (WritableCellFormat) - xfRecords.get(new Integer(index)); + WritableCellFormat wcf = xfRecords.get(index); if (wcf == null) { @@ -915,24 +772,19 @@ private WritableCell deepCopyCell(Cell cell) return c; } - /** + /** * Perform a shallow copy of the cells from the specified sheet into this one */ void shallowCopyCells() { // Copy the cells int cells = fromSheet.getRows(); - Cell[] row = null; - Cell cell = null; for (int i = 0; i < cells; i++) { - row = fromSheet.getRow(i); + Cell[] row = fromSheet.getRow(i); - for (int j = 0; j < row.length; j++) - { - cell = row[j]; + for (Cell cell : row) { WritableCell c = shallowCopyCell(cell); - // Encase the calls to addCell in a try-catch block // These should not generate any errors, because we are // copying from an existing spreadsheet. In the event of @@ -945,9 +797,9 @@ void shallowCopyCells() toSheet.addCell(c); // Cell.setCellFeatures short circuits when the cell is copied, - // so make sure the copy logic handles the validated cells + // so make sure the copy logic handles the validated cells if (c.getCellFeatures() != null && - c.getCellFeatures().hasDataValidation()) + c.getCellFeatures().hasDataValidation()) { validatedCells.add(c); } @@ -962,24 +814,19 @@ void shallowCopyCells() numRows = toSheet.getRows(); } - /** + /** * Perform a deep copy of the cells from the specified sheet into this one */ void deepCopyCells() { // Copy the cells - int cells = fromSheet.getRows(); - Cell[] row = null; - Cell cell = null; - for (int i = 0; i < cells; i++) + int rowCount = fromSheet.getRows(); + for (int i = 0; i < rowCount; i++) { - row = fromSheet.getRow(i); + Cell[] row = fromSheet.getRow(i); - for (int j = 0; j < row.length; j++) - { - cell = row[j]; + for (Cell cell : row) { WritableCell c = deepCopyCell(cell); - // Encase the calls to addCell in a try-catch block // These should not generate any errors, because we are // copying from an existing spreadsheet. In the event of @@ -993,8 +840,8 @@ void deepCopyCells() // Cell.setCellFeatures short circuits when the cell is copied, // so make sure the copy logic handles the validated cells - if (c.getCellFeatures() != null & - c.getCellFeatures().hasDataValidation()) + if (c.getCellFeatures() != null && + c.getCellFeatures().hasDataValidation()) { validatedCells.add(c); } @@ -1027,19 +874,19 @@ private WritableCellFormat copyCellFormat(CellFormat cf) // Maintain the local list of formats int xfIndex = xfr.getXFIndex(); - xfRecords.put(new Integer(xfIndex), f); + xfRecords.put(xfIndex, f); int fontIndex = xfr.getFontIndex(); - fonts.put(new Integer(fontIndex), new Integer(f.getFontIndex())); + fonts.put(fontIndex, f.getFontIndex()); int formatIndex = xfr.getFormatRecord(); - formats.put(new Integer(formatIndex), new Integer(f.getFormatRecord())); + formats.put(formatIndex, f.getFormatRecord()); return f; } catch (NumFormatRecordsException e) { - logger.warn("Maximum number of format records exceeded. Using " + + LOGGER.warn("Maximum number of format records exceeded. Using " + "default format."); return WritableWorkbook.NORMAL_STYLE; @@ -1051,39 +898,31 @@ private WritableCellFormat copyCellFormat(CellFormat cf) */ private void importNames() { - WorkbookParser fromWorkbook = (WorkbookParser) fromSheet.getWorkbook(); + WorkbookParser fromWorkbook = fromSheet.getWorkbook(); WritableWorkbook toWorkbook = toSheet.getWorkbook(); int fromSheetIndex = fromWorkbook.getIndex(fromSheet); - NameRecord[] nameRecords = fromWorkbook.getNameRecords(); - String[] names = toWorkbook.getRangeNames(); + List nameRecords = fromWorkbook.getNameRecords(); + var rangeNames = toWorkbook.getRangeNames(); - for (int i = 0 ; i < nameRecords.length ;i++) - { - NameRecord.NameRange[] nameRanges = nameRecords[i].getRanges(); - - for (int j = 0; j < nameRanges.length; j++) - { - int nameSheetIndex = fromWorkbook.getExternalSheetIndex - (nameRanges[j].getExternalSheet()); + for (var nameRecord : nameRecords) { + NameRecord.NameRange[] nameRanges = nameRecord.getRanges(); - if (fromSheetIndex == nameSheetIndex) - { - String name = nameRecords[i].getName(); - if (Arrays.binarySearch(names, name) < 0) - { - toWorkbook.addNameArea(name, - toSheet, - nameRanges[j].getFirstColumn(), - nameRanges[j].getFirstRow(), - nameRanges[j].getLastColumn(), - nameRanges[j].getLastRow()); - } + for (NameRecord.NameRange nameRange : nameRanges) { + int nameSheetIndex = fromWorkbook.getExternalSheetIndex(nameRange.getExternalSheet()); + + if (fromSheetIndex == nameSheetIndex) { + String name = nameRecord.getName(); + if (rangeNames.contains(name)) + LOGGER.warn("Named range " + name + + " is already present in the destination workbook"); else - { - logger.warn("Named range " + name + - " is already present in the destination workbook"); - } - + toWorkbook.addNameArea( + name, + toSheet, + nameRange.getFirstColumn(), + nameRange.getFirstRow(), + nameRange.getLastColumn(), + nameRange.getLastRow()); } } } @@ -1100,22 +939,22 @@ int getRows() return numRows; } - /** + /** * Accessor for the maximum column outline level * * @return the maximum column outline level, or 0 if no outlines/groups */ - public int getMaxColumnOutlineLevel() + public int getMaxColumnOutlineLevel() { return maxColumnOutlineLevel; } - /** + /** * Accessor for the maximum row outline level * * @return the maximum row outline level, or 0 if no outlines/groups */ - public int getMaxRowOutlineLevel() + public int getMaxRowOutlineLevel() { return maxRowOutlineLevel; } diff --git a/src/jxl/write/biff/SheetWriter.java b/src/jxl/write/biff/SheetWriter.java index e8eddd2..f753b04 100644 --- a/src/jxl/write/biff/SheetWriter.java +++ b/src/jxl/write/biff/SheetWriter.java @@ -20,16 +20,13 @@ package jxl.write.biff; import java.io.IOException; -import java.util.ArrayList; -import java.util.Iterator; -import java.util.TreeSet; +import java.util.*; import jxl.common.Assert; import jxl.common.Logger; import jxl.Cell; import jxl.CellFeatures; -import jxl.CellReferenceHelper; import jxl.Range; import jxl.SheetSettings; import jxl.WorkbookSettings; @@ -37,19 +34,15 @@ import jxl.biff.ConditionalFormat; import jxl.biff.DataValidation; import jxl.biff.DataValiditySettingsRecord; -import jxl.biff.DVParser; import jxl.biff.WorkspaceInformationRecord; import jxl.biff.XFRecord; -import jxl.biff.drawing.Chart; -import jxl.biff.drawing.SheetDrawingWriter; -import jxl.biff.formula.FormulaException; +import jxl.biff.drawing.*; import jxl.format.Border; import jxl.format.BorderLineStyle; import jxl.format.Colour; import jxl.write.Blank; import jxl.write.WritableCell; import jxl.write.WritableCellFormat; -import jxl.write.WritableHyperlink; import jxl.write.WriteException; /** @@ -63,12 +56,12 @@ final class SheetWriter /** * The logger */ - private static Logger logger = Logger.getLogger(SheetWriter.class); - + private static final Logger logger = Logger.getLogger(SheetWriter.class); + /** * A handle to the output file which the binary data is written to */ - private File outputFile; + private final File outputFile; /** * The rows within this sheet @@ -100,23 +93,23 @@ final class SheetWriter /** * The settings for the workbook */ - private WorkbookSettings workbookSettings; + private final WorkbookSettings workbookSettings; /** * Array of row page breaks */ - private ArrayList rowBreaks; + private HorizontalPageBreaksRecord rowBreaks; /** * Array of column page breaks */ - private ArrayList columnBreaks; + private VerticalPageBreaksRecord columnBreaks; /** * Array of hyperlinks */ - private ArrayList hyperlinks; + private ArrayList hyperlinks; /** * Array of conditional formats */ - private ArrayList conditionalFormats; + private ArrayList conditionalFormats; /** * The autofilter info */ @@ -124,7 +117,7 @@ final class SheetWriter /** * Array of validated cells */ - private ArrayList validatedCells; + private ArrayList validatedCells; /** * The data validation validations */ @@ -149,15 +142,15 @@ final class SheetWriter * The workspace options */ private WorkspaceInformationRecord workspaceOptions; - /** + /** * The column format overrides */ - private TreeSet columnFormats; + private TreeSet columnFormats; /** * The list of drawings */ - private SheetDrawingWriter drawingWriter; + private final SheetDrawingWriter drawingWriter; /** * Flag indicates that this sheet contains just a chart, and nothing @@ -179,7 +172,7 @@ final class SheetWriter * A handle back to the writable sheet, in order for this class * to invoke the get accessor methods */ - private WritableSheetImpl sheet; + private final WritableSheetImpl sheet; /** @@ -187,7 +180,7 @@ final class SheetWriter * * @param of the output file */ - public SheetWriter(File of, + SheetWriter(File of, WritableSheetImpl wsi, WorkbookSettings ws) { @@ -204,8 +197,8 @@ public SheetWriter(File of, * information then writes out each row in turn. * Once all the rows have been written out, it retrospectively adjusts * the offset references in the file - * - * @exception IOException + * + * @exception IOException */ public void write() throws IOException { @@ -229,7 +222,7 @@ public void write() throws IOException } int indexPos = outputFile.getPos(); - + // Write the index record out now in order to serve as a place holder // The bof passed in is the bof of the workbook, not this sheet IndexRecord indexRecord = new IndexRecord(0, numRows, numBlocks); @@ -251,7 +244,7 @@ public void write() throws IOException RefModeRecord rmr = new RefModeRecord(); outputFile.write(rmr); - + IterationRecord itr = new IterationRecord(false); outputFile.write(itr); @@ -260,7 +253,7 @@ public void write() throws IOException SaveRecalcRecord srr = new SaveRecalcRecord (settings.getRecalculateFormulasBeforeSave()); - outputFile.write(srr); + outputFile.write(srr); PrintHeadersRecord phr = new PrintHeadersRecord (settings.getPrintHeaders()); @@ -280,8 +273,8 @@ public void write() throws IOException outputFile.write(gutr); DefaultRowHeightRecord drhr = new DefaultRowHeightRecord - (settings.getDefaultRowHeight(), - settings.getDefaultRowHeight() != + (settings.getDefaultRowHeight(), + settings.getDefaultRowHeight() != SheetSettings.DEFAULT_DEFAULT_ROW_HEIGHT); outputFile.write(drhr); @@ -298,37 +291,14 @@ public void write() throws IOException workspaceOptions.setFitToPages(settings.getFitToPages()); outputFile.write(workspaceOptions); - if (rowBreaks.size() > 0) - { - int[] rb = new int[rowBreaks.size()]; - - for (int i = 0; i < rb.length; i++) - { - rb[i] = ( (Integer) rowBreaks.get(i)).intValue(); - } + rowBreaks.write(outputFile); + columnBreaks.write(outputFile); - HorizontalPageBreaksRecord hpbr = new HorizontalPageBreaksRecord(rb); - outputFile.write(hpbr); - } + HeaderRecord hRecord = new HeaderRecord(settings.getHeader().toString()); + outputFile.write(hRecord); - if (columnBreaks.size() > 0) - { - int[] rb = new int[columnBreaks.size()]; - - for (int i = 0; i < rb.length; i++) - { - rb[i] = ( (Integer) columnBreaks.get(i)).intValue(); - } - - VerticalPageBreaksRecord hpbr = new VerticalPageBreaksRecord(rb); - outputFile.write(hpbr); - } - - HeaderRecord header = new HeaderRecord(settings.getHeader().toString()); - outputFile.write(header); - - FooterRecord footer = new FooterRecord(settings.getFooter().toString()); - outputFile.write(footer); + FooterRecord fRecord = new FooterRecord(settings.getFooter().toString()); + outputFile.write(fRecord); HorizontalCentreRecord hcr = new HorizontalCentreRecord (settings.isHorizontalCentre()); @@ -397,22 +367,18 @@ else if (settings.getPasswordHash() != 0) } indexRecord.setDataStartPosition(outputFile.getPos()); - DefaultColumnWidth dcw = + DefaultColumnWidth dcw = new DefaultColumnWidth(settings.getDefaultColumnWidth()); outputFile.write(dcw); - + // Get a handle to the normal styles - WritableCellFormat normalStyle = + WritableCellFormat normalStyle = sheet.getWorkbook().getStyles().getNormalStyle(); - WritableCellFormat defaultDateFormat = + WritableCellFormat defaultDateFormat = sheet.getWorkbook().getStyles().getDefaultDateFormat(); // Write out all the column formats - ColumnInfoRecord cir = null; - for (Iterator colit = columnFormats.iterator(); colit.hasNext() ; ) - { - cir = (ColumnInfoRecord) colit.next(); - + for (ColumnInfoRecord cir : columnFormats) { // Writing out the column info with index 0x100 causes excel to crash if (cir.getColumn() < 0x100) { @@ -420,23 +386,19 @@ else if (settings.getPasswordHash() != 0) } XFRecord xfr = cir.getCellFormat(); - + if (xfr != normalStyle && cir.getColumn() < 0x100) { // Make this the format for every cell in the column Cell[] cells = getColumn(cir.getColumn()); - for (int i = 0; i < cells.length; i++) - { - if (cells[i] != null && - (cells[i].getCellFormat() == normalStyle || - cells[i].getCellFormat() == defaultDateFormat)) - { + for (Cell cell : cells) + if (cell != null + && (cell.getCellFormat() == normalStyle + || cell.getCellFormat() == defaultDateFormat)) // The cell has no overriding format specified, so // set it to the column default - ((WritableCell) cells[i]).setCellFormat(xfr); - } - } + ((WritableCell) cell).setCellFormat(xfr); } } @@ -483,13 +445,13 @@ else if (settings.getPasswordHash() != 0) // Now set the current file position in the index record indexRecord.addBlockPosition(outputFile.getPos()); - + // Set the position of the file pointer and write out the DBCell // record dbcell.setPosition(outputFile.getPos()); outputFile.write(dbcell); } - + // Do the drawings and charts if enabled if (!workbookSettings.getDrawingsDisabled()) { @@ -533,8 +495,8 @@ else if (settings.getPasswordHash() != 0) settings.getVerticalFreeze() != 0) { sr = new SelectionRecord - (SelectionRecord.lowerRight, - settings.getHorizontalFreeze(), + (SelectionRecord.lowerRight, + settings.getHorizontalFreeze(), settings.getVerticalFreeze()); outputFile.write(sr); } @@ -544,7 +506,7 @@ else if (settings.getPasswordHash() != 0) } else { - // No frozen panes - just write out the selection record for the + // No frozen panes - just write out the selection record for the // whole sheet SelectionRecord sr = new SelectionRecord (SelectionRecord.upperLeft, 0, 0); @@ -562,13 +524,8 @@ else if (settings.getPasswordHash() != 0) mergedCells.write(outputFile); // Write out all the hyperlinks - Iterator hi = hyperlinks.iterator(); - WritableHyperlink hlr = null; - while (hi.hasNext()) - { - hlr = (WritableHyperlink) hi.next(); - outputFile.write(hlr); - } + for (HyperlinkRecord hi : hyperlinks) + outputFile.write(hi); if (buttonPropertySet != null) { @@ -584,11 +541,8 @@ else if (settings.getPasswordHash() != 0) // Write out the conditional formats if (conditionalFormats != null && conditionalFormats.size() > 0) { - for (Iterator i = conditionalFormats.iterator() ; i.hasNext() ; ) - { - ConditionalFormat cf = (ConditionalFormat) i.next(); + for (ConditionalFormat cf : conditionalFormats) cf.write(outputFile); - } } EOFRecord eof = new EOFRecord(); @@ -625,12 +579,12 @@ final FooterRecord getFooter() * * @param rws the rows in the spreadsheet */ - void setWriteData(RowRecord[] rws, - ArrayList rb, - ArrayList cb, - ArrayList hl, + void setWriteData(RowRecord[] rws, + HorizontalPageBreaksRecord rb, + VerticalPageBreaksRecord cb, + ArrayList hl, MergedCells mc, - TreeSet cf, + TreeSet cf, int mrol, int mcol) { @@ -645,7 +599,7 @@ void setWriteData(RowRecord[] rws, } /** - * Sets the dimensions of this spreadsheet. This method must be called + * Sets the dimensions of this spreadsheet. This method must be called * immediately prior to writing * * @param rws the number of rows @@ -660,7 +614,7 @@ void setDimensions(int rws, int cls) /** * Sets the sheet settings for this particular sheet. Must be * called immediately prior to writing - * + * * @param sr the sheet settings */ void setSettings(SheetSettings sr) @@ -708,7 +662,7 @@ void setCharts(Chart[] ch) * @param dr the list of drawings * @param mod a modified flag */ - void setDrawings(ArrayList dr, boolean mod) + void setDrawings(ArrayList dr, boolean mod) { drawingWriter.setDrawings(dr, mod); } @@ -731,17 +685,14 @@ Chart[] getCharts() */ void checkMergedBorders() { - Range[] mcells = mergedCells.getMergedCells(); - ArrayList borderFormats = new ArrayList(); - for (int mci = 0 ; mci < mcells.length ; mci++) - { - Range range = mcells[mci]; + ArrayList borderFormats = new ArrayList<>(); + for (var range : mergedCells.getMergedCells()) { Cell topLeft = range.getTopLeft(); XFRecord tlformat = (XFRecord) topLeft.getCellFormat(); - if (tlformat != null && - tlformat.hasBorders() == true && - !tlformat.isRead()) + if (tlformat != null && + tlformat.hasBorders() == true && + !tlformat.isRead()) { try { @@ -749,31 +700,31 @@ void checkMergedBorders() Cell bottomRight = range.getBottomRight(); cf1.setBorder(Border.ALL, BorderLineStyle.NONE, Colour.BLACK); - cf1.setBorder(Border.LEFT, - tlformat.getBorderLine(Border.LEFT), - tlformat.getBorderColour(Border.LEFT)); - cf1.setBorder(Border.TOP, - tlformat.getBorderLine(Border.TOP), - tlformat.getBorderColour(Border.TOP)); + cf1.setBorder(Border.LEFT, + tlformat.getBorderLine(Border.LEFT), + tlformat.getBorderColour(Border.LEFT)); + cf1.setBorder(Border.TOP, + tlformat.getBorderLine(Border.TOP), + tlformat.getBorderColour(Border.TOP)); if (topLeft.getRow() == bottomRight.getRow()) { - cf1.setBorder(Border.BOTTOM, - tlformat.getBorderLine(Border.BOTTOM), - tlformat.getBorderColour(Border.BOTTOM)); + cf1.setBorder(Border.BOTTOM, + tlformat.getBorderLine(Border.BOTTOM), + tlformat.getBorderColour(Border.BOTTOM)); } if (topLeft.getColumn() == bottomRight.getColumn()) { - cf1.setBorder(Border.RIGHT, - tlformat.getBorderLine(Border.RIGHT), - tlformat.getBorderColour(Border.RIGHT)); + cf1.setBorder(Border.RIGHT, + tlformat.getBorderLine(Border.RIGHT), + tlformat.getBorderColour(Border.RIGHT)); } int index = borderFormats.indexOf(cf1); if (index != -1) { - cf1 = (CellXFRecord) borderFormats.get(index); + cf1 = borderFormats.get(index); } else { @@ -789,25 +740,25 @@ void checkMergedBorders() { CellXFRecord cf2 = new CellXFRecord(tlformat); cf2.setBorder(Border.ALL, BorderLineStyle.NONE, Colour.BLACK); - cf2.setBorder(Border.LEFT, - tlformat.getBorderLine(Border.LEFT), - tlformat.getBorderColour(Border.LEFT)); - cf2.setBorder(Border.BOTTOM, - tlformat.getBorderLine(Border.BOTTOM), - tlformat.getBorderColour(Border.BOTTOM)); - + cf2.setBorder(Border.LEFT, + tlformat.getBorderLine(Border.LEFT), + tlformat.getBorderColour(Border.LEFT)); + cf2.setBorder(Border.BOTTOM, + tlformat.getBorderLine(Border.BOTTOM), + tlformat.getBorderColour(Border.BOTTOM)); + index = borderFormats.indexOf(cf2); if (index != -1) { - cf2 = (CellXFRecord) borderFormats.get(index); + cf2 = borderFormats.get(index); } else { borderFormats.add(cf2); } - sheet.addCell(new Blank(topLeft.getColumn(), - bottomRight.getRow(), cf2)); + sheet.addCell(new Blank(topLeft.getColumn(), + bottomRight.getRow(), cf2)); } // Handle the cells down the left hand side (and along the @@ -816,21 +767,21 @@ void checkMergedBorders() { CellXFRecord cf3 = new CellXFRecord(tlformat); cf3.setBorder(Border.ALL, BorderLineStyle.NONE, Colour.BLACK); - cf3.setBorder(Border.LEFT, - tlformat.getBorderLine(Border.LEFT), - tlformat.getBorderColour(Border.LEFT)); + cf3.setBorder(Border.LEFT, + tlformat.getBorderLine(Border.LEFT), + tlformat.getBorderColour(Border.LEFT)); if (topLeft.getColumn() == bottomRight.getColumn()) { - cf3.setBorder(Border.RIGHT, - tlformat.getBorderLine(Border.RIGHT), - tlformat.getBorderColour(Border.RIGHT)); + cf3.setBorder(Border.RIGHT, + tlformat.getBorderLine(Border.RIGHT), + tlformat.getBorderColour(Border.RIGHT)); } index = borderFormats.indexOf(cf3); if (index != -1) { - cf3 = (CellXFRecord) borderFormats.get(index); + cf3 = borderFormats.get(index); } else { @@ -849,149 +800,149 @@ void checkMergedBorders() // Handle the corner cell CellXFRecord cf6 = new CellXFRecord(tlformat); cf6.setBorder(Border.ALL, BorderLineStyle.NONE, Colour.BLACK); - cf6.setBorder(Border.RIGHT, - tlformat.getBorderLine(Border.RIGHT), - tlformat.getBorderColour(Border.RIGHT)); - cf6.setBorder(Border.TOP, - tlformat.getBorderLine(Border.TOP), - tlformat.getBorderColour(Border.TOP)); + cf6.setBorder(Border.RIGHT, + tlformat.getBorderLine(Border.RIGHT), + tlformat.getBorderColour(Border.RIGHT)); + cf6.setBorder(Border.TOP, + tlformat.getBorderLine(Border.TOP), + tlformat.getBorderColour(Border.TOP)); index = borderFormats.indexOf(cf6); if (index != -1) { - cf6 = (CellXFRecord) borderFormats.get(index); + cf6 = borderFormats.get(index); } else { borderFormats.add(cf6); } - - sheet.addCell(new Blank(bottomRight.getColumn(), - topLeft.getRow(), cf6)); + + sheet.addCell(new Blank(bottomRight.getColumn(), + topLeft.getRow(), cf6)); } // Handle the cells along the right - for (int i = topLeft.getRow() + 1; - i < bottomRight.getRow() ;i++) + for (int i = topLeft.getRow() + 1; + i < bottomRight.getRow() ;i++) { CellXFRecord cf7 = new CellXFRecord(tlformat); cf7.setBorder(Border.ALL, BorderLineStyle.NONE, Colour.BLACK); - cf7.setBorder(Border.RIGHT, - tlformat.getBorderLine(Border.RIGHT), - tlformat.getBorderColour(Border.RIGHT)); + cf7.setBorder(Border.RIGHT, + tlformat.getBorderLine(Border.RIGHT), + tlformat.getBorderColour(Border.RIGHT)); index = borderFormats.indexOf(cf7); if (index != -1) { - cf7 = (CellXFRecord) borderFormats.get(index); + cf7 = borderFormats.get(index); } else { borderFormats.add(cf7); } - + sheet.addCell(new Blank(bottomRight.getColumn(), i, cf7)); } // Handle the cells along the top, and along the bottom too - for (int i = topLeft.getColumn() + 1; - i < bottomRight.getColumn() ;i++) + for (int i = topLeft.getColumn() + 1; + i < bottomRight.getColumn() ;i++) { CellXFRecord cf8 = new CellXFRecord(tlformat); cf8.setBorder(Border.ALL, BorderLineStyle.NONE, Colour.BLACK); - cf8.setBorder(Border.TOP, - tlformat.getBorderLine(Border.TOP), - tlformat.getBorderColour(Border.TOP)); - + cf8.setBorder(Border.TOP, + tlformat.getBorderLine(Border.TOP), + tlformat.getBorderColour(Border.TOP)); + if (topLeft.getRow() == bottomRight.getRow()) { - cf8.setBorder(Border.BOTTOM, - tlformat.getBorderLine(Border.BOTTOM), - tlformat.getBorderColour(Border.BOTTOM)); + cf8.setBorder(Border.BOTTOM, + tlformat.getBorderLine(Border.BOTTOM), + tlformat.getBorderColour(Border.BOTTOM)); } index = borderFormats.indexOf(cf8); if (index != -1) { - cf8 = (CellXFRecord) borderFormats.get(index); + cf8 = borderFormats.get(index); } else { borderFormats.add(cf8); } - + sheet.addCell(new Blank(i, topLeft.getRow(), cf8)); } } // Handle the bottom right corner if (bottomRight.getColumn() > topLeft.getColumn() || - bottomRight.getRow() > topLeft.getRow()) + bottomRight.getRow() > topLeft.getRow()) { // Handle the corner cell CellXFRecord cf4 = new CellXFRecord(tlformat); cf4.setBorder(Border.ALL, BorderLineStyle.NONE, Colour.BLACK); - cf4.setBorder(Border.RIGHT, - tlformat.getBorderLine(Border.RIGHT), - tlformat.getBorderColour(Border.RIGHT)); - cf4.setBorder(Border.BOTTOM, - tlformat.getBorderLine(Border.BOTTOM), - tlformat.getBorderColour(Border.BOTTOM)); + cf4.setBorder(Border.RIGHT, + tlformat.getBorderLine(Border.RIGHT), + tlformat.getBorderColour(Border.RIGHT)); + cf4.setBorder(Border.BOTTOM, + tlformat.getBorderLine(Border.BOTTOM), + tlformat.getBorderColour(Border.BOTTOM)); if (bottomRight.getRow() == topLeft.getRow()) { - cf4.setBorder(Border.TOP, - tlformat.getBorderLine(Border.TOP), - tlformat.getBorderColour(Border.TOP)); + cf4.setBorder(Border.TOP, + tlformat.getBorderLine(Border.TOP), + tlformat.getBorderColour(Border.TOP)); } if (bottomRight.getColumn() == topLeft.getColumn()) { - cf4.setBorder(Border.LEFT, - tlformat.getBorderLine(Border.LEFT), - tlformat.getBorderColour(Border.LEFT)); + cf4.setBorder(Border.LEFT, + tlformat.getBorderLine(Border.LEFT), + tlformat.getBorderColour(Border.LEFT)); } index = borderFormats.indexOf(cf4); if (index != -1) { - cf4 = (CellXFRecord) borderFormats.get(index); + cf4 = borderFormats.get(index); } else { borderFormats.add(cf4); } - sheet.addCell(new Blank(bottomRight.getColumn(), - bottomRight.getRow(), cf4)); + sheet.addCell(new Blank(bottomRight.getColumn(), + bottomRight.getRow(), cf4)); // Handle the cells along the bottom (and along the top // as well, if appropriate) - for (int i = topLeft.getColumn() + 1; - i < bottomRight.getColumn() ;i++) + for (int i = topLeft.getColumn() + 1; + i < bottomRight.getColumn() ;i++) { CellXFRecord cf5 = new CellXFRecord(tlformat); cf5.setBorder(Border.ALL, BorderLineStyle.NONE, Colour.BLACK); - cf5.setBorder(Border.BOTTOM, - tlformat.getBorderLine(Border.BOTTOM), - tlformat.getBorderColour(Border.BOTTOM)); + cf5.setBorder(Border.BOTTOM, + tlformat.getBorderLine(Border.BOTTOM), + tlformat.getBorderColour(Border.BOTTOM)); if (topLeft.getRow() == bottomRight.getRow()) { - cf5.setBorder(Border.TOP, - tlformat.getBorderLine(Border.TOP), - tlformat.getBorderColour(Border.TOP)); + cf5.setBorder(Border.TOP, + tlformat.getBorderLine(Border.TOP), + tlformat.getBorderColour(Border.TOP)); } index = borderFormats.indexOf(cf5); if (index != -1) { - cf5 = (CellXFRecord) borderFormats.get(index); + cf5 = borderFormats.get(index); } else { borderFormats.add(cf5); } - + sheet.addCell(new Blank(i, bottomRight.getRow(), cf5)); } } @@ -999,7 +950,7 @@ void checkMergedBorders() catch (WriteException e) { // just log e.toString(), not the whole stack trace - logger.warn(e.toString()); + logger.warn(e.toString()); } } } @@ -1074,7 +1025,7 @@ void setButtonPropertySet(ButtonPropertySetRecord bps) * @param dv the read-in list of data validations * @param vc the api manipulated set of data validations */ - void setDataValidation(DataValidation dv, ArrayList vc) + void setDataValidation(DataValidation dv, ArrayList vc) { dataValidation = dv; validatedCells = vc; @@ -1085,7 +1036,7 @@ void setDataValidation(DataValidation dv, ArrayList vc) * * @param cf the conditonal formats */ - void setConditionalFormats(ArrayList cf) + void setConditionalFormats(ArrayList cf) { conditionalFormats = cf; } @@ -1105,12 +1056,12 @@ void setAutoFilter(AutoFilter af) */ private void writeDataValidation() throws IOException { - if (dataValidation != null && validatedCells.size() == 0) + if (dataValidation != null && validatedCells.isEmpty()) { // the only data validations are those read in - this should // never be the case now that shared data validations add // to the validatedCells list - dataValidation.write(outputFile); + dataValidation.write(outputFile); return; } @@ -1118,7 +1069,7 @@ private void writeDataValidation() throws IOException { // the only data validations are those which have been added by the // write API. Need to sort out the combo box id - int comboBoxId = sheet.getComboBox() != null ? + int comboBoxId = sheet.getComboBox() != null ? sheet.getComboBox().getObjectId() : DataValidation.DEFAULT_OBJECT_ID; dataValidation = new DataValidation(comboBoxId, sheet.getWorkbook(), @@ -1126,7 +1077,7 @@ private void writeDataValidation() throws IOException workbookSettings); } - for (Iterator i = validatedCells.iterator(); i.hasNext(); ) + for (Iterator i = validatedCells.iterator(); i.hasNext(); ) { CellValue cv = (CellValue) i.next(); CellFeatures cf = cv.getCellFeatures(); @@ -1139,18 +1090,18 @@ private void writeDataValidation() throws IOException if (!cf.getDVParser().extendedCellsValidation()) { // DVParser is specific for a single cell validation - just add it - DataValiditySettingsRecord dvsr = + DataValiditySettingsRecord dvsr = new DataValiditySettingsRecord(cf.getDVParser()); dataValidation.add(dvsr); } else { // Only add the DVParser once for shared validations - // only add it if it is the top left cell + // only add it if it is the top left cell if (cv.getColumn() == cf.getDVParser().getFirstColumn() && cv.getRow() == cf.getDVParser().getFirstRow()) { - DataValiditySettingsRecord dvsr = + DataValiditySettingsRecord dvsr = new DataValiditySettingsRecord(cf.getDVParser()); dataValidation.add(dvsr); } @@ -1166,7 +1117,7 @@ private void writeDataValidation() throws IOException { CellValue cv = (CellValue) i.next(); CellFeatures cf = cv.getCellFeatures(); - DataValiditySettingsRecord dvsr = + DataValiditySettingsRecord dvsr = new DataValiditySettingsRecord(cf.getDVParser()); dataValidation.add(dvsr); } diff --git a/src/jxl/write/biff/StringRecord.java b/src/jxl/write/biff/StringRecord.java index bcc2d68..0e62534 100644 --- a/src/jxl/write/biff/StringRecord.java +++ b/src/jxl/write/biff/StringRecord.java @@ -33,7 +33,7 @@ class StringRecord extends WritableRecordData /** * The string value */ - private String value; + private final String value; /** * Constructor @@ -47,9 +47,10 @@ public StringRecord(String val) /** * The binary data to be written out - * + * * @return the binary data */ + @Override public byte[] getData() { byte[] data = new byte[value.length() * 2 + 3]; diff --git a/src/jxl/write/biff/VerticalPageBreaksRecord.java b/src/jxl/write/biff/VerticalPageBreaksRecord.java index f7e09a7..33f7e95 100644 --- a/src/jxl/write/biff/VerticalPageBreaksRecord.java +++ b/src/jxl/write/biff/VerticalPageBreaksRecord.java @@ -19,30 +19,30 @@ package jxl.write.biff; -import jxl.biff.IntegerHelper; -import jxl.biff.Type; -import jxl.biff.WritableRecordData; +import java.io.IOException; +import java.util.*; +import java.util.stream.Collectors; +import jxl.biff.*; +import jxl.read.biff.IVerticalPageBreaks; /** * Contains the list of explicit horizontal page breaks on the current sheet */ -class VerticalPageBreaksRecord extends WritableRecordData -{ +class VerticalPageBreaksRecord extends WritableRecordData implements IVerticalPageBreaks { + /** * The row breaks */ - private int[] columnBreaks; + private List columnBreaks = new ArrayList<>(); /** * Constructor * * @param break the row breaks */ - public VerticalPageBreaksRecord(int[] breaks) + VerticalPageBreaksRecord() { super(Type.VERTICALPAGEBREAKS); - - columnBreaks = breaks; } /** @@ -50,23 +50,82 @@ public VerticalPageBreaksRecord(int[] breaks) * * @return the binary data */ + @Override public byte[] getData() { - byte[] data = new byte[columnBreaks.length * 6 + 2]; + byte[] data = new byte[columnBreaks.size() * 6 + 2]; // The number of breaks on the list - IntegerHelper.getTwoBytes(columnBreaks.length, data, 0); + IntegerHelper.getTwoBytes(columnBreaks.size(), data, 0); int pos = 2; - for (int i = 0; i < columnBreaks.length; i++) - { - IntegerHelper.getTwoBytes(columnBreaks[i], data, pos); - IntegerHelper.getTwoBytes(0xff, data, pos+4); + for (ColumnIndex cb : columnBreaks) { + IntegerHelper.getTwoBytes(cb.getFirstColumnFollowingBreak(), data, pos); + IntegerHelper.getTwoBytes(cb.getFirstRow(), data, pos+2); + IntegerHelper.getTwoBytes(cb.getLastRow(), data, pos+4); pos += 6; } return data; } -} + @Override + public List getColumnBreaks() { + return columnBreaks.stream() + .map(ColumnIndex::getFirstColumnFollowingBreak) + .collect(Collectors.toList()); + } + + void setColumnBreaks(IVerticalPageBreaks breaks) { + columnBreaks = breaks.getColumnBreaks().stream() + .map(i -> colToColumnIndex(i)) + .collect(Collectors.toList()); + } + + void clear() { + columnBreaks.clear(); + } + + void addBreak(int col) { + // First check that the row is not already present + Iterator i = columnBreaks.iterator(); + + while (i.hasNext()) + if (i.next().getFirstColumnFollowingBreak() == col) + return; + + columnBreaks.add(colToColumnIndex(col)); + } + private ColumnIndex colToColumnIndex(int col) { + return new ColumnIndex(col, 0, 0xffff); + } + + void insertColumn(int col) { + ListIterator ri = columnBreaks.listIterator(); + while (ri.hasNext()) + { + ColumnIndex val = ri.next(); + if (val.getFirstColumnFollowingBreak() >= col) + ri.set(val.withFirstColumnFollowingBreak(val.getFirstColumnFollowingBreak()+1)); + } + } + + void removeColumn(int col) { + ListIterator ri = columnBreaks.listIterator(); + while (ri.hasNext()) + { + ColumnIndex val = ri.next(); + if (val.getFirstColumnFollowingBreak() == col) + ri.remove(); + else if (val.getFirstColumnFollowingBreak() > col) + ri.set(val.withFirstColumnFollowingBreak(val.getFirstColumnFollowingBreak()-1)); + } + } + + void write(File outputFile) throws IOException { + if (columnBreaks.size() > 0) + outputFile.write(this); + } + +} diff --git a/src/jxl/write/biff/Window1Record.java b/src/jxl/write/biff/Window1Record.java old mode 100644 new mode 100755 index 900e2a7..52b7eab --- a/src/jxl/write/biff/Window1Record.java +++ b/src/jxl/write/biff/Window1Record.java @@ -1,6 +1,6 @@ /********************************************************************* * -* Copyright (C) 2002 Andrew Khan +* Copyright (C) 2012 Jan Schloessin * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -19,56 +19,82 @@ package jxl.write.biff; -import jxl.biff.IntegerHelper; -import jxl.biff.Type; -import jxl.biff.WritableRecordData; +import jxl.biff.*; /** * Contains workbook level windowing attributes */ class Window1Record extends WritableRecordData { + private int horizontalPositionOfDocumentWindow; + private int verticalPositionOfDocumentWindow; + private int widthOfDocumentWindow; + private int heightOfDocumentWindow; + private boolean windowHidden; + private boolean windowMinimized; + private boolean horizontalScrollBarVisible; + private boolean verticalScrollBarVisible; + private boolean worksheetTabBarVisible; + private int selectedSheet; + private int firstVisibleTab; + private int numberOfSelectedWorkSheets; + private int widthOfWorksheetTabBar; + /** - * The binary data - */ - private byte[] data; - - /** - * The selected sheet + * Constructor for compatibility with initial version from Andrew Khan */ - private int selectedSheet; + Window1Record(int selectedSheet) + { + this(360, 270, 14940, 9150, false, false, true, true, true, + selectedSheet, 0, 1, 600); + } /** - * Constructor + * Assignment Constructor + * + * @param horizontalPositionOfDocumentWindow Horizontal position of the document window (in twips = 1/20 of a point) + * @param verticalPositionOfDocumentWindow Vertical position of the document window (in twips = 1/20 of a point) + * @param widthOfDocumentWindow Width of the document window (in twips = 1/20 of a point) + * @param heightOfDocumentWindow Height of the document window (in twips = 1/20 of a point) + * @param windowHidden true when window is hidden, false when window is visible + * @param windowMinimized true when window is minimized, false when window is open + * @param horizontalScrollBarVisible true when horizontal scroll bar is visible, false when horizontal scroll bar hidden + * @param verticalScrollBarVisible true when vertical scroll bar visible, false when vertical scroll bar hidden + * @param worksheetTabBarVisible true when worksheet tab bar visible, false when worksheet tab bar hidden + * @param selectedSheet Index to active (displayed) worksheet + * @param firstVisibleTab Index of first visible tab in the worksheet tab bar + * @param numberOfSelectedWorkSheets Number of selected worksheets (highlighted in the worksheet tab bar) + * @param widthOfWorksheetTabBar Width of worksheet tab bar (in 1/1000 of window width). The remaining space is used by the horizontal scrollbar. */ - public Window1Record(int selSheet) - { + Window1Record( + int horizontalPositionOfDocumentWindow, + int verticalPositionOfDocumentWindow, + int widthOfDocumentWindow, + int heightOfDocumentWindow, + boolean windowHidden, + boolean windowMinimized, + boolean horizontalScrollBarVisible, + boolean verticalScrollBarVisible, + boolean worksheetTabBarVisible, + int selectedSheet, + int firstVisibleTab, + int numberOfSelectedWorkSheets, + int widthOfWorksheetTabBar) { super(Type.WINDOW1); - - selectedSheet = selSheet; - - // hard code the data in for now - data = new byte[] - {(byte) 0x68, - (byte) 0x1, - (byte) 0xe, - (byte) 0x1, - (byte) 0x5c, - (byte) 0x3a, - (byte) 0xbe, - (byte) 0x23, - (byte) 0x38, - (byte) 0, - (byte) 0, - (byte) 0, - (byte) 0, - (byte) 0, - (byte) 0x1, - (byte) 0, - (byte) 0x58, - (byte) 0x2 }; - IntegerHelper.getTwoBytes(selectedSheet, data, 10); + this.horizontalPositionOfDocumentWindow = horizontalPositionOfDocumentWindow; + this.verticalPositionOfDocumentWindow = verticalPositionOfDocumentWindow; + this.widthOfDocumentWindow = widthOfDocumentWindow; + this.heightOfDocumentWindow = heightOfDocumentWindow; + this.windowHidden = windowHidden; + this.windowMinimized = windowMinimized; + this.horizontalScrollBarVisible = horizontalScrollBarVisible; + this.verticalScrollBarVisible = verticalScrollBarVisible; + this.worksheetTabBarVisible = worksheetTabBarVisible; + this.selectedSheet = selectedSheet; + this.firstVisibleTab = firstVisibleTab; + this.numberOfSelectedWorkSheets = numberOfSelectedWorkSheets; + this.widthOfWorksheetTabBar = widthOfWorksheetTabBar; } /** @@ -76,8 +102,216 @@ public Window1Record(int selSheet) * * @return the binary data */ + @Override public byte[] getData() { + byte[] data = new byte[18]; + IntegerHelper.getTwoBytes(horizontalPositionOfDocumentWindow, data, 0); + IntegerHelper.getTwoBytes(verticalPositionOfDocumentWindow, data, 2); + IntegerHelper.getTwoBytes(widthOfDocumentWindow, data, 4); + IntegerHelper.getTwoBytes(heightOfDocumentWindow, data, 6); + + int optionFlag = 0; + if (windowHidden) + optionFlag |= 0x01; + if (windowMinimized) + optionFlag |= 0x02; + if (horizontalScrollBarVisible) + optionFlag |= 0x08; + if (verticalScrollBarVisible) + optionFlag |= 0x10; + if (worksheetTabBarVisible) + optionFlag |= 0x20; + IntegerHelper.getTwoBytes(optionFlag, data, 8); + + IntegerHelper.getTwoBytes(selectedSheet, data, 10); + IntegerHelper.getTwoBytes(firstVisibleTab, data, 12); + IntegerHelper.getTwoBytes(numberOfSelectedWorkSheets, data, 14); + IntegerHelper.getTwoBytes(widthOfWorksheetTabBar, data, 16); + return data; } + + /** + * @return the horizontal position of the document window (in twips = 1/20 of a point) + */ + int getHorizontalPositionOfDocumentWindow() { + return horizontalPositionOfDocumentWindow; + } + + /** + * @param horizontalPositionOfDocumentWindow Horizontal position of the document window (in twips = 1/20 of a point) + */ + void setHorizontalPositionOfDocumentWindow(int horizontalPositionOfDocumentWindow) { + this.horizontalPositionOfDocumentWindow = horizontalPositionOfDocumentWindow; + } + + /** + * @return the vertical position of the document window (in twips = 1/20 of a point) + */ + int getVerticalPositionOfDocumentWindow() { + return verticalPositionOfDocumentWindow; + } + + /** + * @param verticalPositionOfDocumentWindow Vertical position of the document window (in twips = 1/20 of a point) + */ + void setVerticalPositionOfDocumentWindow(int verticalPositionOfDocumentWindow) { + this.verticalPositionOfDocumentWindow = verticalPositionOfDocumentWindow; + } + + /** + * @return the width of the document window (in twips = 1/20 of a point) + */ + int getWidthOfDocumentWindow() { + return widthOfDocumentWindow; + } + + /** + * @param widthOfDocumentWindow Width of the document window (in twips = 1/20 of a point) + */ + void setWidthOfDocumentWindow(int widthOfDocumentWindow) { + this.widthOfDocumentWindow = widthOfDocumentWindow; + } + + /** + * @return the height of the document window (in twips = 1/20 of a point) + */ + int getHeightOfDocumentWindow() { + return heightOfDocumentWindow; + } + + /** + * @param heightOfDocumentWindow Height of the document window (in twips = 1/20 of a point) + */ + void setHeightOfDocumentWindow(int heightOfDocumentWindow) { + this.heightOfDocumentWindow = heightOfDocumentWindow; + } + + /** + * @return return true when window is hidden, false when window is visible + */ + boolean isWindowHidden() { + return windowHidden; + } + + /** + * @param windowHidden true when window is hidden, false when window is visible + */ + void setWindowHidden(boolean windowHidden) { + this.windowHidden = windowHidden; + } + + /** + * @return true when window is minimized, false when window is open + */ + boolean isWindowMinimized() { + return windowMinimized; + } + + /** + * @param windowMinimized true when window is minimized, false when window is open + */ + void setWindowMinimized(boolean windowMinimized) { + this.windowMinimized = windowMinimized; + } + + /** + * @return true when horizontal scroll bar is visible, false when horizontal scroll bar hidden + */ + boolean isHorizontalScrollBarVisible() { + return horizontalScrollBarVisible; + } + + /** + * @param horizontalScrollBarVisible true when horizontal scroll bar is visible, false when horizontal scroll bar hidden + */ + void setHorizontalScrollBarVisible(boolean horizontalScrollBarVisible) { + this.horizontalScrollBarVisible = horizontalScrollBarVisible; + } + + /** + * @return true when vertical scroll bar visible, false when vertical scroll bar hidden + */ + boolean isVerticalScrollBarVisible() { + return verticalScrollBarVisible; + } + + /** + * @param verticalScrollBarVisible true when vertical scroll bar visible, false when vertical scroll bar hidden + */ + void setVerticalScrollBarVisible(boolean verticalScrollBarVisible) { + this.verticalScrollBarVisible = verticalScrollBarVisible; + } + + /** + * @return true when worksheet tab bar visible, false when worksheet tab bar hidden + */ + boolean isWorksheetTabBarVisible() { + return worksheetTabBarVisible; + } + + /** + * @param worksheetTabBarVisible true when worksheet tab bar visible, false when worksheet tab bar hidden + */ + void setWorksheetTabBarVisible(boolean worksheetTabBarVisible) { + this.worksheetTabBarVisible = worksheetTabBarVisible; + } + + /** + * @return the index to active (displayed) worksheet + */ + int getSelectedSheet() { + return selectedSheet; + } + + /** + * @param selectedSheet Index to active (displayed) worksheet + */ + void setSelectedSheet(int selectedSheet) { + this.selectedSheet = selectedSheet; + } + + /** + * @return the index of first visible tab in the worksheet tab bar + */ + int getFirstVisibleTab() { + return firstVisibleTab; + } + + /** + * @param firstVisibleTab Index of first visible tab in the worksheet tab bar + */ + void setFirstVisibleTab(int firstVisibleTab) { + this.firstVisibleTab = firstVisibleTab; + } + + /** + * @return the number of selected worksheets (highlighted in the worksheet tab bar) + */ + int getNumberOfSelectedWorkSheets() { + return numberOfSelectedWorkSheets; + } + + /** + * @param numberOfSelectedWorkSheets Number of selected worksheets (highlighted in the worksheet tab bar) + */ + void setNumberOfSelectedWorkSheets(int numberOfSelectedWorkSheets) { + this.numberOfSelectedWorkSheets = numberOfSelectedWorkSheets; + } + + /** + * @return Width of worksheet tab bar (in 1/1000 of window width). + */ + int getWidthOfWorksheetTabBar() { + return widthOfWorksheetTabBar; + } + + /** + * @param widthOfWorksheetTabBar Width of worksheet tab bar (in 1/1000 of window width). The remaining space is used by the horizontal scrollbar. + */ + void setWidthOfWorksheetTabBar(int widthOfWorksheetTabBar) { + this.widthOfWorksheetTabBar = widthOfWorksheetTabBar; + } + } diff --git a/src/jxl/write/biff/Window2Record.java b/src/jxl/write/biff/Window2Record.java index 5ba93e3..be27c7f 100644 --- a/src/jxl/write/biff/Window2Record.java +++ b/src/jxl/write/biff/Window2Record.java @@ -37,7 +37,7 @@ class Window2Record extends WritableRecordData /** * Constructor */ - public Window2Record(SheetSettings settings) + Window2Record(SheetSettings settings) { super(Type.WINDOW2); @@ -99,6 +99,7 @@ public Window2Record(SheetSettings settings) * * @return the binary data */ + @Override public byte[] getData() { return data; diff --git a/src/jxl/write/biff/WritableSheetCopier.java b/src/jxl/write/biff/WritableSheetCopier.java index fe9ac29..97fb163 100644 --- a/src/jxl/write/biff/WritableSheetCopier.java +++ b/src/jxl/write/biff/WritableSheetCopier.java @@ -19,11 +19,7 @@ package jxl.write.biff; -import java.util.Arrays; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.TreeSet; -import java.util.Iterator; +import java.util.*; import jxl.common.Assert; import jxl.common.Logger; @@ -31,37 +27,22 @@ import jxl.BooleanCell; import jxl.Cell; import jxl.CellType; -import jxl.CellView; import jxl.DateCell; -import jxl.HeaderFooter; -import jxl.Hyperlink; -import jxl.Image; import jxl.LabelCell; import jxl.NumberCell; import jxl.Range; -import jxl.Sheet; -import jxl.SheetSettings; import jxl.WorkbookSettings; -import jxl.biff.AutoFilter; import jxl.biff.CellReferenceHelper; -import jxl.biff.ConditionalFormat; import jxl.biff.DataValidation; import jxl.biff.FormattingRecords; import jxl.biff.FormulaData; -import jxl.biff.IndexMapping; import jxl.biff.NumFormatRecordsException; import jxl.biff.SheetRangeImpl; import jxl.biff.WorkspaceInformationRecord; import jxl.biff.XFRecord; -import jxl.biff.drawing.Chart; -import jxl.biff.drawing.ComboBox; -import jxl.biff.drawing.Drawing; import jxl.biff.drawing.DrawingGroupObject; import jxl.format.CellFormat; import jxl.biff.formula.FormulaException; -import jxl.read.biff.SheetImpl; -import jxl.read.biff.NameRecord; -import jxl.read.biff.WorkbookParser; import jxl.write.Blank; import jxl.write.Boolean; import jxl.write.DateTime; @@ -70,7 +51,6 @@ import jxl.write.Number; import jxl.write.WritableCell; import jxl.write.WritableCellFormat; -import jxl.write.WritableFont; import jxl.write.WritableHyperlink; import jxl.write.WritableImage; import jxl.write.WritableSheet; @@ -78,7 +58,7 @@ import jxl.write.WriteException; /** - * A transient utility object used to copy sheets. This + * A transient utility object used to copy sheets. This * functionality has been farmed out to a different class * in order to reduce the bloat of the WritableSheetImpl */ @@ -86,34 +66,34 @@ class WritableSheetCopier { private static Logger logger = Logger.getLogger(SheetCopier.class); - private WritableSheetImpl fromSheet; - private WritableSheetImpl toSheet; - private WorkbookSettings workbookSettings; + private final WritableSheetImpl fromSheet; + private final WritableSheetImpl toSheet; + private final WorkbookSettings workbookSettings; // Objects used by the sheet - private TreeSet fromColumnFormats; - private TreeSet toColumnFormats; + private TreeSet fromColumnFormats; + private TreeSet toColumnFormats; private MergedCells fromMergedCells; private MergedCells toMergedCells; private RowRecord[] fromRows; - private ArrayList fromRowBreaks; - private ArrayList fromColumnBreaks; - private ArrayList toRowBreaks; - private ArrayList toColumnBreaks; + private HorizontalPageBreaksRecord fromRowBreaks; + private VerticalPageBreaksRecord fromColumnBreaks; + private HorizontalPageBreaksRecord toRowBreaks; + private VerticalPageBreaksRecord toColumnBreaks; private DataValidation fromDataValidation; private DataValidation toDataValidation; private SheetWriter sheetWriter; - private ArrayList fromDrawings; - private ArrayList toDrawings; - private ArrayList toImages; + private ArrayList fromDrawings; + private ArrayList toDrawings; + private ArrayList toImages; private WorkspaceInformationRecord fromWorkspaceOptions; private PLSRecord fromPLSRecord; private PLSRecord toPLSRecord; private ButtonPropertySetRecord fromButtonPropertySet; private ButtonPropertySetRecord toButtonPropertySet; - private ArrayList fromHyperlinks; - private ArrayList toHyperlinks; - private ArrayList validatedCells; + private ArrayList fromHyperlinks; + private ArrayList toHyperlinks; + private ArrayList validatedCells; private int numRows; private int maxRowOutlineLevel; private int maxColumnOutlineLevel; @@ -125,9 +105,9 @@ class WritableSheetCopier // Objects used to maintain state during the copy process - private HashMap xfRecords; - private HashMap fonts; - private HashMap formats; + private HashMap xfRecords; + private HashMap fonts; + private HashMap formats; public WritableSheetCopier(WritableSheet f, WritableSheet t) { @@ -137,7 +117,7 @@ public WritableSheetCopier(WritableSheet f, WritableSheet t) chartOnly = false; } - void setColumnFormats(TreeSet fcf, TreeSet tcf) + void setColumnFormats(TreeSet fcf, TreeSet tcf) { fromColumnFormats = fcf; toColumnFormats = tcf; @@ -154,31 +134,31 @@ void setRows(RowRecord[] r) fromRows = r; } - void setValidatedCells(ArrayList vc) + void setValidatedCells(ArrayList vc) { validatedCells = vc; } - void setRowBreaks(ArrayList frb, ArrayList trb) + void setRowBreaks(HorizontalPageBreaksRecord frb, HorizontalPageBreaksRecord trb) { fromRowBreaks = frb; toRowBreaks = trb; } - void setColumnBreaks(ArrayList fcb, ArrayList tcb) + void setColumnBreaks(VerticalPageBreaksRecord fcb, VerticalPageBreaksRecord tcb) { fromColumnBreaks = fcb; toColumnBreaks = tcb; } - void setDrawings(ArrayList fd, ArrayList td, ArrayList ti) + void setDrawings(ArrayList fd, ArrayList td, ArrayList ti) { fromDrawings = fd; toDrawings = td; toImages = ti; } - void setHyperlinks(ArrayList fh, ArrayList th) + void setHyperlinks(ArrayList fh, ArrayList th) { fromHyperlinks = fh; toHyperlinks = th; @@ -237,39 +217,27 @@ ButtonPropertySetRecord getButtonPropertySet() public void copySheet() { shallowCopyCells(); - // Copy the column formats - Iterator cfit = fromColumnFormats.iterator(); - while (cfit.hasNext()) - { - ColumnInfoRecord cv = new ColumnInfoRecord - ((ColumnInfoRecord) cfit.next()); - toColumnFormats.add(cv); - } - // Copy the merged cells - Range[] merged = fromMergedCells.getMergedCells(); + for (ColumnInfoRecord toCopy : fromColumnFormats) + toColumnFormats.add(new ColumnInfoRecord(toCopy)); - for (int i = 0; i < merged.length; i++) - { - toMergedCells.add(new SheetRangeImpl((SheetRangeImpl)merged[i], - toSheet)); - } + // Copy the merged cells + for (var range : fromMergedCells.getMergedCells()) + toMergedCells.add(new SheetRangeImpl(range, toSheet)); try { - RowRecord row = null; - RowRecord newRow = null; for (int i = 0; i < fromRows.length ; i++) { - row = fromRows[i]; - + RowRecord row = fromRows[i]; + if (row != null && (!row.isDefaultHeight() || row.isCollapsed())) { - newRow = toSheet.getRowRecord(i); - newRow.setRowDetails(row.getRowHeight(), + RowRecord newRow = toSheet.getRowRecord(i); + newRow.setRowDetails(row.getRowHeight(), row.matchesDefaultFontHeight(), row.isCollapsed(), row.getOutlineLevel(), @@ -286,16 +254,16 @@ public void copySheet() } // Copy the horizontal page breaks - toRowBreaks = new ArrayList(fromRowBreaks); + toRowBreaks.setRowBreaks(fromRowBreaks); // Copy the vertical page breaks - toColumnBreaks = new ArrayList(fromColumnBreaks); + toColumnBreaks.setColumnBreaks(fromColumnBreaks); // Copy the data validations if (fromDataValidation != null) { toDataValidation = new DataValidation - (fromDataValidation, + (fromDataValidation, toSheet.getWorkbook(), toSheet.getWorkbook(), toSheet.getWorkbook().getSettings()); @@ -305,21 +273,17 @@ public void copySheet() sheetWriter.setCharts(fromSheet.getCharts()); // Copy the drawings - for (Iterator i = fromDrawings.iterator(); i.hasNext(); ) - { - Object o = i.next(); - if (o instanceof jxl.biff.drawing.Drawing) - { + for (DrawingGroupObject o : fromDrawings) + if (o instanceof jxl.biff.drawing.Drawing drawing) { WritableImage wi = new WritableImage - ((jxl.biff.drawing.Drawing) o, - toSheet.getWorkbook().getDrawingGroup()); + (drawing, + toSheet.getWorkbook().getDrawingGroup()); toDrawings.add(wi); toImages.add(wi); } - // Not necessary to copy the comments, as they will be handled by - // the deep copy of the individual cells - } + // Not necessary to copy the comments, as they will be handled by + // the deep copy of the individual cells // Copy the workspace options sheetWriter.setWorkspaceOptions(fromWorkspaceOptions); @@ -337,75 +301,38 @@ public void copySheet() } // Copy the hyperlinks - for (Iterator i = fromHyperlinks.iterator(); i.hasNext();) - { - WritableHyperlink hr = new WritableHyperlink - ((WritableHyperlink) i.next(), toSheet); - toHyperlinks.add(hr); - } + for (WritableHyperlink toCopy : fromHyperlinks) + toHyperlinks.add(new WritableHyperlink(toCopy, toSheet)); + } /** * Performs a shallow copy of the specified cell */ - private WritableCell shallowCopyCell(Cell cell) - { - CellType ct = cell.getType(); - WritableCell newCell = null; - - if (ct == CellType.LABEL) - { - newCell = new Label((LabelCell) cell); - } - else if (ct == CellType.NUMBER) - { - newCell = new Number((NumberCell) cell); - } - else if (ct == CellType.DATE) - { - newCell = new DateTime((DateCell) cell); - } - else if (ct == CellType.BOOLEAN) - { - newCell = new Boolean((BooleanCell) cell); - } - else if (ct == CellType.NUMBER_FORMULA) - { - newCell = new ReadNumberFormulaRecord((FormulaData) cell); - } - else if (ct == CellType.STRING_FORMULA) - { - newCell = new ReadStringFormulaRecord((FormulaData) cell); - } - else if( ct == CellType.BOOLEAN_FORMULA) - { - newCell = new ReadBooleanFormulaRecord((FormulaData) cell); - } - else if (ct == CellType.DATE_FORMULA) - { - newCell = new ReadDateFormulaRecord((FormulaData) cell); - } - else if(ct == CellType.FORMULA_ERROR) - { - newCell = new ReadErrorFormulaRecord((FormulaData) cell); - } - else if (ct == CellType.EMPTY) - { - if (cell.getCellFormat() != null) - { - // It is a blank cell, rather than an empty cell, so - // it may have formatting information, so - // it must be copied - newCell = new Blank(cell); - } - } - - return newCell; + private WritableCell shallowCopyCell(Cell cell) { + return switch (cell.getType()) { + case LABEL -> new Label((LabelCell) cell); + case NUMBER -> new Number((NumberCell) cell); + case DATE -> new DateTime((DateCell) cell); + case BOOLEAN -> new Boolean((BooleanCell) cell); + case NUMBER_FORMULA -> new ReadNumberFormulaRecord((FormulaData) cell); + case STRING_FORMULA -> new ReadStringFormulaRecord((FormulaData) cell); + case BOOLEAN_FORMULA -> new ReadBooleanFormulaRecord((FormulaData) cell); + case DATE_FORMULA -> new ReadDateFormulaRecord((FormulaData) cell); + case FORMULA_ERROR -> new ReadErrorFormulaRecord((FormulaData) cell); + case EMPTY -> (cell.getCellFormat() != null) + // It is a blank cell, rather than an empty cell, so + // it may have formatting information, so + // it must be copied + ? new Blank(cell) + : null; + case ERROR -> null; + }; } - /** + /** * Performs a deep copy of the specified cell, handling the cell format - * + * * @param cell the cell to copy */ private WritableCell deepCopyCell(Cell cell) @@ -417,20 +344,19 @@ private WritableCell deepCopyCell(Cell cell) return c; } - if (c instanceof ReadFormulaRecord) + if (c instanceof ReadFormulaRecord rfr) { - ReadFormulaRecord rfr = (ReadFormulaRecord) c; boolean crossSheetReference = !rfr.handleImportedCellReferences (fromSheet.getWorkbook(), fromSheet.getWorkbook(), workbookSettings); - + if (crossSheetReference) { try { logger.warn("Formula " + rfr.getFormula() + - " in cell " + + " in cell " + CellReferenceHelper.getCellReference(cell.getColumn(), cell.getRow()) + " cannot be imported because it references another " + @@ -438,12 +364,12 @@ private WritableCell deepCopyCell(Cell cell) } catch (FormulaException e) { - logger.warn("Formula in cell " + + logger.warn("Formula in cell " + CellReferenceHelper.getCellReference(cell.getColumn(), cell.getRow()) + " cannot be imported: " + e.getMessage()); } - + // Create a new error formula and add it instead c = new Formula(cell.getColumn(), cell.getRow(), "\"ERROR\""); } @@ -452,35 +378,26 @@ private WritableCell deepCopyCell(Cell cell) // Copy the cell format CellFormat cf = c.getCellFormat(); int index = ( (XFRecord) cf).getXFIndex(); - WritableCellFormat wcf = (WritableCellFormat) - xfRecords.get(new Integer(index)); + WritableCellFormat wcf = xfRecords.get(index); if (wcf == null) - { wcf = copyCellFormat(cf); - } c.setCellFormat(wcf); return c; } - /** + /** * Perform a shallow copy of the cells from the specified sheet into this one */ void shallowCopyCells() { // Copy the cells - int cells = fromSheet.getRows(); - Cell[] row = null; - Cell cell = null; - for (int i = 0; i < cells; i++) - { - row = fromSheet.getRow(i); + for (int i = 0; i < fromSheet.getRows(); i++) { + Cell[] row = fromSheet.getRow(i); - for (int j = 0; j < row.length; j++) - { - cell = row[j]; + for (Cell cell : row) { WritableCell c = shallowCopyCell(cell); // Encase the calls to addCell in a try-catch block @@ -493,11 +410,11 @@ void shallowCopyCells() if (c != null) { toSheet.addCell(c); - + // Cell.setCellFeatures short circuits when the cell is copied, - // so make sure the copy logic handles the validated cells + // so make sure the copy logic handles the validated cells if (c.getCellFeatures() != null & - c.getCellFeatures().hasDataValidation()) + c.getCellFeatures().hasDataValidation()) { validatedCells.add(c); } @@ -512,52 +429,6 @@ void shallowCopyCells() numRows = toSheet.getRows(); } - /** - * Perform a deep copy of the cells from the specified sheet into this one - */ - void deepCopyCells() - { - // Copy the cells - int cells = fromSheet.getRows(); - Cell[] row = null; - Cell cell = null; - for (int i = 0; i < cells; i++) - { - row = fromSheet.getRow(i); - - for (int j = 0; j < row.length; j++) - { - cell = row[j]; - WritableCell c = deepCopyCell(cell); - - // Encase the calls to addCell in a try-catch block - // These should not generate any errors, because we are - // copying from an existing spreadsheet. In the event of - // errors, catch the exception and then bomb out with an - // assertion - try - { - if (c != null) - { - toSheet.addCell(c); - - // Cell.setCellFeatures short circuits when the cell is copied, - // so make sure the copy logic handles the validated cells - if (c.getCellFeatures() != null & - c.getCellFeatures().hasDataValidation()) - { - validatedCells.add(c); - } - } - } - catch (WriteException e) - { - Assert.verify(false); - } - } - } - } - /** * Returns an initialized copy of the cell format * @@ -577,13 +448,13 @@ private WritableCellFormat copyCellFormat(CellFormat cf) // Maintain the local list of formats int xfIndex = xfr.getXFIndex(); - xfRecords.put(new Integer(xfIndex), f); + xfRecords.put(xfIndex, f); int fontIndex = xfr.getFontIndex(); - fonts.put(new Integer(fontIndex), new Integer(f.getFontIndex())); + fonts.put(fontIndex, f.getFontIndex()); int formatIndex = xfr.getFormatRecord(); - formats.put(new Integer(formatIndex), new Integer(f.getFormatRecord())); + formats.put(formatIndex, f.getFormatRecord()); return f; } @@ -597,22 +468,22 @@ private WritableCellFormat copyCellFormat(CellFormat cf) } - /** + /** * Accessor for the maximum column outline level * * @return the maximum column outline level, or 0 if no outlines/groups */ - public int getMaxColumnOutlineLevel() + public int getMaxColumnOutlineLevel() { return maxColumnOutlineLevel; } - /** + /** * Accessor for the maximum row outline level * * @return the maximum row outline level, or 0 if no outlines/groups */ - public int getMaxRowOutlineLevel() + public int getMaxRowOutlineLevel() { return maxRowOutlineLevel; } diff --git a/src/jxl/write/biff/WritableSheetImpl.java b/src/jxl/write/biff/WritableSheetImpl.java index fc9cf0c..466f012 100644 --- a/src/jxl/write/biff/WritableSheetImpl.java +++ b/src/jxl/write/biff/WritableSheetImpl.java @@ -20,67 +20,21 @@ package jxl.write.biff; import java.io.IOException; -import java.util.ArrayList; -import java.util.Comparator; -import java.util.Iterator; -import java.util.TreeSet; +import static java.lang.Math.max; +import java.nio.file.Path; +import java.util.*; import java.util.regex.Pattern; - -import jxl.common.Assert; -import jxl.common.Logger; - -import jxl.BooleanCell; -import jxl.Cell; -import jxl.CellFeatures; +import jxl.*; import jxl.CellReferenceHelper; -import jxl.CellType; -import jxl.CellView; -import jxl.DateCell; import jxl.HeaderFooter; -import jxl.Hyperlink; -import jxl.Image; -import jxl.LabelCell; -import jxl.NumberCell; -import jxl.Range; -import jxl.Sheet; -import jxl.SheetSettings; -import jxl.WorkbookSettings; -import jxl.biff.AutoFilter; -import jxl.biff.BuiltInName; -import jxl.biff.CellFinder; -import jxl.biff.ConditionalFormat; -import jxl.biff.DataValidation; -import jxl.biff.DVParser; -import jxl.biff.EmptyCell; -import jxl.biff.FormattingRecords; -import jxl.biff.FormulaData; -import jxl.biff.IndexMapping; -import jxl.biff.NumFormatRecordsException; -import jxl.biff.SheetRangeImpl; -import jxl.biff.WorkspaceInformationRecord; -import jxl.biff.XFRecord; -import jxl.biff.drawing.Chart; -import jxl.biff.drawing.ComboBox; -import jxl.biff.drawing.Drawing; -import jxl.biff.drawing.DrawingGroupObject; +import jxl.biff.*; +import jxl.biff.drawing.*; +import jxl.common.*; +import jxl.format.*; import jxl.format.CellFormat; import jxl.format.Font; -import jxl.format.PageOrientation; -import jxl.format.PaperSize; -import jxl.write.Blank; -import jxl.write.Boolean; -import jxl.write.DateTime; -import jxl.write.Label; -import jxl.write.Number; -import jxl.write.WritableCell; -import jxl.write.WritableCellFeatures; -import jxl.write.WritableCellFormat; -import jxl.write.WritableFont; -import jxl.write.WritableHyperlink; -import jxl.write.WritableImage; -import jxl.write.WritableSheet; -import jxl.write.WritableWorkbook; -import jxl.write.WriteException; +import jxl.read.biff.*; +import jxl.write.*; /** * A writable sheet. This class contains implementation of all the @@ -91,8 +45,8 @@ class WritableSheetImpl implements WritableSheet /** * The logger */ - private static Logger logger = Logger.getLogger(WritableSheetImpl.class); - + private static final Logger logger = Logger.getLogger(WritableSheetImpl.class); + /** * The name of this sheet */ @@ -100,39 +54,39 @@ class WritableSheetImpl implements WritableSheet /** * A handle to the output file which the binary data is written to */ - private File outputFile; + private final File outputFile; /** * The rows within this sheet */ - private RowRecord[] rows; + private final List rows; /** * A handle to workbook format records */ - private FormattingRecords formatRecords; + private final FormattingRecords formatRecords; /** * A handle to the shared strings used by this workbook */ - private SharedStrings sharedStrings; + private final SharedStrings sharedStrings; /** * The list of non-default column formats */ - private TreeSet columnFormats; + private final TreeSet columnFormats; /** * The list of autosized columns */ - private TreeSet autosizedColumns; + private TreeSet autosizedColumns; /** * The list of hyperlinks */ - private ArrayList hyperlinks; + private final ArrayList hyperlinks; /** * The list of merged ranged */ - private MergedCells mergedCells; + private final MergedCells mergedCells; /** * A number of rows. This is a count of the maximum row number + 1 @@ -168,27 +122,27 @@ class WritableSheetImpl implements WritableSheet /** * Array of row page breaks */ - private ArrayList rowBreaks; + private final HorizontalPageBreaksRecord rowBreaks = new HorizontalPageBreaksRecord(); /** * Array of column page breaks */ - private ArrayList columnBreaks; + private final VerticalPageBreaksRecord columnBreaks = new VerticalPageBreaksRecord(); /** * The drawings on this sheet */ - private ArrayList drawings; + private final ArrayList drawings; /** * The images on this sheet. This is a subset of the drawings list */ - private ArrayList images; + private final ArrayList images; /** * The conditional formats on this sheet */ - private ArrayList conditionalFormats; + private final ArrayList conditionalFormats; /** * The autofilter @@ -199,7 +153,7 @@ class WritableSheetImpl implements WritableSheet * The writable cells on this sheet which may have validation added * to them */ - private ArrayList validatedCells; + private final ArrayList validatedCells; /** * The combo box object used for list validations on this sheet @@ -230,38 +184,33 @@ class WritableSheetImpl implements WritableSheet /** * The sheet writer engine */ - private SheetWriter sheetWriter; + private final SheetWriter sheetWriter; /** * The settings for the workbook */ - private WorkbookSettings workbookSettings; + private final WorkbookSettings workbookSettings; /** * The workbook */ - private WritableWorkbookImpl workbook; - - /** - * The amount by which to grow the rows array - */ - private final static int rowGrowSize = 10; + private final WritableWorkbookImpl workbook; /** * The maximum number of rows excel allows in a worksheet */ - private final static int numRowsPerSheet = 65536; + final static int MAX_ROWS_PER_SHEET = 65536; /** * The maximum number of characters permissible for a sheet name - */ + */ private final static int maxSheetNameLength = 31; /** * The illegal characters for a sheet name */ - private final static char[] illegalSheetNameCharacters = - new char[] {'*', ':', '?', '\\'}; + private final static char[] illegalSheetNameCharacters = + new char[] {'*', ':', '?', '\\'}; /** * The supported file types @@ -271,14 +220,15 @@ class WritableSheetImpl implements WritableSheet /** * The comparator for column info record */ - private static class ColumnInfoComparator implements Comparator + private static class ColumnInfoComparator implements Comparator { /** * Equals method - * + * * @param o the object to compare * @return TRUE if equal, FALSE otherwise */ + @Override public boolean equals(Object o) { return o == this; @@ -286,11 +236,12 @@ public boolean equals(Object o) /** * Comparison function for to ColumnInfoRecords - * + * * @param o2 first object to compare * @param o1 second object to compare * @return the result of the comparison */ + @Override public int compare(Object o1, Object o2) { if (o1 == o2) @@ -300,7 +251,7 @@ public int compare(Object o1, Object o2) Assert.verify(o1 instanceof ColumnInfoRecord); Assert.verify(o2 instanceof ColumnInfoRecord); - + ColumnInfoRecord ci1 = (ColumnInfoRecord) o1; ColumnInfoRecord ci2 = (ColumnInfoRecord) o2; @@ -310,7 +261,7 @@ public int compare(Object o1, Object o2) /** * Constructor - * + * * @param fr the formatting records used by the workbook * @param of the output file to write the binary data * @param f the fonts used by the workbook @@ -318,16 +269,16 @@ public int compare(Object o1, Object o2) * @param ss the shared strings used by the workbook * @param ws the workbook settings */ - public WritableSheetImpl(String n, - File of, - FormattingRecords fr, + WritableSheetImpl(String n, + File of, + FormattingRecords fr, SharedStrings ss, WorkbookSettings ws, WritableWorkbookImpl ww) { name = validateName(n); outputFile = of; - rows = new RowRecord[0]; + rows = new ArrayList<>(); numRows = 0; numColumns = 0; chartOnly = false; @@ -337,21 +288,19 @@ public WritableSheetImpl(String n, sharedStrings = ss; workbookSettings = ws; drawingsModified = false; - columnFormats = new TreeSet(new ColumnInfoComparator()); - autosizedColumns = new TreeSet(); - hyperlinks = new ArrayList(); + columnFormats = new TreeSet<>(new ColumnInfoComparator<>()); + autosizedColumns = new TreeSet<>(); + hyperlinks = new ArrayList<>(); mergedCells = new MergedCells(this); - rowBreaks = new ArrayList(); - columnBreaks = new ArrayList(); - drawings = new ArrayList(); - images = new ArrayList(); - conditionalFormats = new ArrayList(); - validatedCells = new ArrayList(); + drawings = new ArrayList<>(); + images = new ArrayList<>(); + conditionalFormats = new ArrayList<>(); + validatedCells = new ArrayList<>(); settings = new SheetSettings(this); sheetWriter = new SheetWriter(outputFile, - this, + this, workbookSettings); } @@ -362,6 +311,7 @@ public WritableSheetImpl(String n, * @param loc the cell reference * @return the cell at the specified co-ordinates */ + @Override public Cell getCell(String loc) { return getCell(CellReferenceHelper.getColumn(loc), @@ -370,11 +320,12 @@ public Cell getCell(String loc) /** * Returns the cell specified at this row and at this column - * + * * @param column the column number * @param row the row number * @return the cell at the specified co-ordinates */ + @Override public Cell getCell(int column, int row) { return getWritableCell(column, row); @@ -390,6 +341,7 @@ public Cell getCell(int column, int row) * @param loc the cell reference * @return the cell at the specified co-ordinates */ + @Override public WritableCell getWritableCell(String loc) { return getWritableCell(CellReferenceHelper.getColumn(loc), @@ -398,33 +350,35 @@ public WritableCell getWritableCell(String loc) /** * Returns the cell specified at this row and at this column - * + * * @param column the column number * @param row the row number * @return the cell at the specified co-ordinates */ + @Override public WritableCell getWritableCell(int column, int row) { WritableCell c = null; - if (row < rows.length && rows[row] != null) + if (row < rows.size() && rows.get(row) != null) { - c = rows[row].getCell(column); + c = rows.get(row).getCell(column); } if (c == null) { c = new EmptyCell(column, row); } - + return c; } /** * Returns the number of rows in this sheet - * + * * @return the number of rows in this sheet */ + @Override public int getRows() { return numRows; @@ -432,9 +386,10 @@ public int getRows() /** * Returns the number of columns in this sheet - * + * * @return the number of columns in this sheet */ + @Override public int getColumns() { return numColumns; @@ -449,6 +404,7 @@ public int getColumns() * @param contents the string to match * @return the Cell whose contents match the paramter, null if not found */ + @Override public Cell findCell(String contents) { CellFinder cellFinder = new CellFinder(this); @@ -460,7 +416,7 @@ public Cell findCell(String contents) * If no match is found, then null is returned. The search is performed * on a row by row basis, so the lower the row number, the more * efficiently the algorithm will perform - * + * * @param contents the string to match * @param firstCol the first column within the range * @param firstRow the first row of the range @@ -469,19 +425,20 @@ public Cell findCell(String contents) * @param reverse indicates whether to perform a reverse search or not * @return the Cell whose contents match the parameter, null if not found */ - public Cell findCell(String contents, - int firstCol, - int firstRow, - int lastCol, - int lastRow, + @Override + public Cell findCell(String contents, + int firstCol, + int firstRow, + int lastCol, + int lastRow, boolean reverse) { CellFinder cellFinder = new CellFinder(this); return cellFinder.findCell(contents, - firstCol, - firstRow, + firstCol, + firstRow, lastCol, - lastRow, + lastRow, reverse); } @@ -490,7 +447,7 @@ public Cell findCell(String contents, * If no match is found, then null is returned. The search is performed * on a row by row basis, so the lower the row number, the more * efficiently the algorithm will perform - * + * * @param pattern the regular expression string to match * @param firstCol the first column within the range * @param firstRow the first row of the range @@ -499,19 +456,20 @@ public Cell findCell(String contents, * @param reverse indicates whether to perform a reverse search or not * @return the Cell whose contents match the parameter, null if not found */ - public Cell findCell(Pattern pattern, - int firstCol, - int firstRow, - int lastCol, - int lastRow, + @Override + public Cell findCell(Pattern pattern, + int firstCol, + int firstRow, + int lastCol, + int lastRow, boolean reverse) { CellFinder cellFinder = new CellFinder(this); return cellFinder.findCell(pattern, - firstCol, - firstRow, + firstCol, + firstRow, lastCol, - lastRow, + lastRow, reverse); } @@ -523,10 +481,11 @@ public Cell findCell(Pattern pattern, * from the findCell methods in that only cells with labels are * queried - all numerical cells are ignored. This should therefore * improve performance. - * + * * @param contents the string to match * @return the Cell whose contents match the paramter, null if not found */ + @Override public LabelCell findLabelCell(String contents) { CellFinder cellFinder = new CellFinder(this); @@ -535,10 +494,11 @@ public LabelCell findLabelCell(String contents) /** * Gets all the cells on the specified row - * + * * @param row the rows whose cells are to be returned * @return the cells on the given row */ + @Override public Cell[] getRow(int row) { // Find the last non-null cell @@ -568,10 +528,11 @@ public Cell[] getRow(int row) /** * Gets all the cells on the specified column - * + * * @param col the column whose cells are to be returned * @return the cells on the specified column */ + @Override public Cell[] getColumn(int col) { // Find the last non-null cell @@ -602,9 +563,10 @@ public Cell[] getColumn(int col) /** * Gets the name of this sheet - * + * * @return the name of the sheet */ + @Override public String getName() { return name; @@ -616,46 +578,41 @@ public String getName() * * @param row the row to insert */ - public void insertRow(int row) + @Override + public void insertRow(int row) throws RowsExceededException { - if (row < 0 || row >= numRows) - { + if (numRows >= MAX_ROWS_PER_SHEET) + throw new RowsExceededException(); + + if (row < 0) return; - } - // Create a new array to hold the new rows. Grow it if need be - RowRecord[] oldRows = rows; + // drawings are not tracked by numRows and have to be managed outside of + // the RowRecords + for (DrawingGroupObject dgo : drawings) + if (dgo.getY() >= row) + if (dgo.getY() + dgo.getHeight() + 1 < MAX_ROWS_PER_SHEET) + dgo.setY(dgo.getY() + 1); - if (numRows == rows.length) - { - rows = new RowRecord[oldRows.length + rowGrowSize]; - } - else - { - rows = new RowRecord[oldRows.length]; - } + if (row >= numRows) + return; - // Copy in everything up to the new row - System.arraycopy(oldRows, 0, rows, 0, row); - - // Copy in the remaining rows - System.arraycopy(oldRows, row, rows, row+1, numRows - row); + rows.add(row, null); // Increment all the internal row number by one for (int i = row+1; i <= numRows; i++) { - if (rows[i] != null) + if (rows.get(i) != null) { - rows[i].incrementRow(); + rows.get(i).incrementRow(); } } // Adjust any hyperlinks - HyperlinkRecord hr = null; - Iterator i = hyperlinks.iterator(); + Iterator i = hyperlinks.iterator(); while (i.hasNext()) { - hr = (HyperlinkRecord) i.next(); + HyperlinkRecord hr = i.next(); hr.insertRow(row); } @@ -667,7 +624,7 @@ public void insertRow(int row) if (validatedCells != null && validatedCells.size() > 0) { - for (Iterator vci = validatedCells.iterator(); vci.hasNext();) + for (Iterator vci = validatedCells.iterator(); vci.hasNext();) { CellValue cv = (CellValue) vci.next(); CellFeatures cf = cv.getCellFeatures(); @@ -682,45 +639,31 @@ public void insertRow(int row) mergedCells.insertRow(row); // Adjust any page breaks - ArrayList newRowBreaks = new ArrayList(); - Iterator ri = rowBreaks.iterator(); - while (ri.hasNext()) - { - int val = ( (Integer) ri.next()).intValue(); - if (val >= row) - { - val++; - } - - newRowBreaks.add(new Integer(val)); - } - rowBreaks = newRowBreaks; + rowBreaks.insertRow(row); // Adjust any conditional formats - for (Iterator cfit = conditionalFormats.iterator(); cfit.hasNext() ;) - { - ConditionalFormat cf = (ConditionalFormat) cfit.next(); + for (ConditionalFormat cf : conditionalFormats) cf.insertRow(row); - } // Handle interested cell references on the main workbook if (workbookSettings.getFormulaAdjust()) - { workbook.rowInserted(this, row); - } + + settings.insertRowInPrintArea(row); // Adjust the maximum row record numRows++; } /** - * Inserts a blank column into this spreadsheet. If the column is out of - * range of the columns in the sheet, then no action is taken. If the + * Inserts a blank column into this spreadsheet. If the column is out of + * range of the columns in the sheet, then no action is taken. If the * max column on the sheet has been reached, then the last column entry * gets dropped * * @param col the column to insert */ + @Override public void insertColumn(int col) { if (col < 0 || col >= numColumns) @@ -731,45 +674,41 @@ public void insertColumn(int col) // Iterate through all the row records adding in the column for (int i = 0 ; i < numRows ; i++) { - if (rows[i] != null) + if (rows.get(i) != null) { - rows[i].insertColumn(col); + rows.get(i).insertColumn(col); } } - // Adjust any hyperlinks - HyperlinkRecord hr = null; - Iterator i = hyperlinks.iterator(); - while (i.hasNext()) - { - hr = (HyperlinkRecord) i.next(); + for (HyperlinkRecord hr : hyperlinks) hr.insertColumn(col); - } - // Iterate through the column views, incrementing the column number - i = columnFormats.iterator(); - while (i.hasNext()) { - ColumnInfoRecord cir = (ColumnInfoRecord) i.next(); - - if (cir.getColumn() >= col) + // Iterate through the column views, incrementing the column number + Iterator i = columnFormats.iterator(); + while (i.hasNext()) { - cir.incrementColumn(); + ColumnInfoRecord cir = i.next(); + + if (cir.getColumn() >= col) + { + cir.incrementColumn(); + } } } // Iterate through the autosized columns, incrementing the column number if (autosizedColumns.size() > 0) { - TreeSet newAutosized = new TreeSet(); - i = autosizedColumns.iterator(); + TreeSet newAutosized = new TreeSet<>(); + Iterator i = autosizedColumns.iterator(); while (i.hasNext()) { - Integer colnumber = (Integer) i.next(); + Integer colnumber = i.next(); - if (colnumber.intValue() >= col) + if (colnumber >= col) { - newAutosized.add(new Integer(colnumber.intValue() + 1)); + newAutosized.add(colnumber + 1); } else { @@ -787,14 +726,10 @@ public void insertColumn(int col) if (validatedCells != null && validatedCells.size() > 0) { - for (Iterator vci = validatedCells.iterator(); vci.hasNext();) - { - CellValue cv = (CellValue) vci.next(); + for (WritableCell cv : validatedCells) { CellFeatures cf = cv.getCellFeatures(); if (cf.getDVParser() != null) - { cf.getDVParser().insertColumn(col); - } } } @@ -802,26 +737,11 @@ public void insertColumn(int col) mergedCells.insertColumn(col); // Adjust any page breaks - ArrayList newColumnBreaks = new ArrayList(); - Iterator ri = columnBreaks.iterator(); - while (ri.hasNext()) - { - int val = ( (Integer) ri.next()).intValue(); - if (val >= col) - { - val++; - } - - newColumnBreaks.add(new Integer(val)); - } - columnBreaks = newColumnBreaks; + columnBreaks.insertColumn(col); // Adjust any conditional formats - for (Iterator cfit = conditionalFormats.iterator(); cfit.hasNext() ;) - { - ConditionalFormat cf = (ConditionalFormat) cfit.next(); + for (ConditionalFormat cf : conditionalFormats) cf.insertColumn(col); - } // Handle interested cell references on the main workbook if (workbookSettings.getFormulaAdjust()) @@ -829,7 +749,14 @@ public void insertColumn(int col) workbook.columnInserted(this, col); } + settings.insertColumnInPrintArea(col); + numColumns++; + + for (DrawingGroupObject dgo : drawings) + if (dgo.getX() >= col) + dgo.setX(dgo.getX() + 1); + } /** @@ -838,6 +765,7 @@ public void insertColumn(int col) * * @param col the column to remove */ + @Override public void removeColumn(int col) { if (col < 0 || col >= numColumns) @@ -848,29 +776,30 @@ public void removeColumn(int col) // Iterate through all the row records removing the column for (int i = 0 ; i < numRows ; i++) { - if (rows[i] != null) + if (rows.get(i) != null) { - rows[i].removeColumn(col); + rows.get(i).removeColumn(col); } } - // Adjust any hyperlinks - HyperlinkRecord hr = null; - Iterator i = hyperlinks.iterator(); - while (i.hasNext()) { - hr = (HyperlinkRecord) i.next(); - - if (hr.getColumn() == col && - hr.getLastColumn() == col) - { - // The row with the hyperlink on has been removed, so get - // rid of it from the list - i.remove(); - } - else + // Adjust any hyperlinks + Iterator i = hyperlinks.iterator(); + while (i.hasNext()) { - hr.removeColumn(col); + HyperlinkRecord hr = i.next(); + + if (hr.getColumn() == col && + hr.getLastColumn() == col) + { + // The row with the hyperlink on has been removed, so get + // rid of it from the list + i.remove(); + } + else + { + hr.removeColumn(col); + } } } @@ -882,14 +811,10 @@ public void removeColumn(int col) if (validatedCells != null && validatedCells.size() > 0) { - for (Iterator vci = validatedCells.iterator(); vci.hasNext();) - { - CellValue cv = (CellValue) vci.next(); + for (WritableCell cv : validatedCells) { CellFeatures cf = cv.getCellFeatures(); if (cf.getDVParser() != null) - { cf.getDVParser().removeColumn(col); - } } } @@ -897,79 +822,50 @@ public void removeColumn(int col) mergedCells.removeColumn(col); // Adjust any page breaks - ArrayList newColumnBreaks = new ArrayList(); - Iterator ri = columnBreaks.iterator(); - while (ri.hasNext()) - { - int val = ( (Integer) ri.next()).intValue(); + columnBreaks.removeColumn(col); - if (val != col) - { - if (val > col) - { - val--; - } - - newColumnBreaks.add(new Integer(val)); - } - } - - columnBreaks = newColumnBreaks; - - - // Iterate through the column views, decrementing the column number - i = columnFormats.iterator(); - ColumnInfoRecord removeColumn = null; - while (i.hasNext()) { - ColumnInfoRecord cir = (ColumnInfoRecord) i.next(); - - if (cir.getColumn() == col) - { - removeColumn = cir; - } - else if (cir.getColumn() > col) + // Iterate through the column views, decrementing the column number + Iterator i = columnFormats.iterator(); + ColumnInfoRecord removeColumn = null; + while (i.hasNext()) { - cir.decrementColumn(); + ColumnInfoRecord cir = i.next(); + + if (cir.getColumn() == col) + removeColumn = cir; + else if (cir.getColumn() > col) + cir.decrementColumn(); } - } - if (removeColumn != null) - { - columnFormats.remove(removeColumn); + if (removeColumn != null) + columnFormats.remove(removeColumn); } // Iterate through the autosized columns, decrementing the column number if (autosizedColumns.size() > 0) { - TreeSet newAutosized = new TreeSet(); - i = autosizedColumns.iterator(); + TreeSet newAutosized = new TreeSet<>(); + Iterator i = autosizedColumns.iterator(); while (i.hasNext()) { - Integer colnumber = (Integer) i.next(); + Integer colnumber = i.next(); - if (colnumber.intValue() == col) + if (colnumber == col) { // do nothing } - else if (colnumber.intValue() > col) - { - newAutosized.add(new Integer(colnumber.intValue() - 1)); - } + else if (colnumber > col) + newAutosized.add(colnumber - 1); else - { newAutosized.add(colnumber); - } } autosizedColumns = newAutosized; } // Adjust any conditional formats - for (Iterator cfit = conditionalFormats.iterator(); cfit.hasNext() ;) - { - ConditionalFormat cf = (ConditionalFormat) cfit.next(); + for (ConditionalFormat cf : conditionalFormats) cf.removeColumn(col); - } // Handle interested cell references on the main workbook if (workbookSettings.getFormulaAdjust()) @@ -977,66 +873,64 @@ else if (colnumber.intValue() > col) workbook.columnRemoved(this, col); } + settings.removeColumnFromPrintArea(col); + numColumns--; + + for (DrawingGroupObject dgo : drawings) + if (dgo.getX() >= col) + dgo.setX(max(dgo.getX() - 1, 0)); } /** - * Removes a row from this spreadsheet. If the row is out of + * Removes a row from this spreadsheet. If the row is out of * range of the columns in the sheet, then no action is taken * * @param row the row to remove */ + @Override public void removeRow(int row) { - if (row < 0 || row >= numRows) + if (row < 0) + return; + + // drawings are not tracked by numRows and have to be managed outside of + // the RowRecords + for (DrawingGroupObject dgo : drawings) + if (dgo.getY() >= row) + if (dgo.getY() + dgo.getHeight() - 1 >= 0) + dgo.setY(dgo.getY() - 1); + + if (row >= numRows) { // Call rowRemoved anyway, to adjust the named cells if (workbookSettings.getFormulaAdjust()) - { workbook.rowRemoved(this, row); - } return; } - // Create a new array to hold the new rows. Grow it if need be - RowRecord[] oldRows = rows; - - rows = new RowRecord[oldRows.length]; - - // Copy in everything up to the row to be removed - System.arraycopy(oldRows, 0, rows, 0, row); - - // Copy in the remaining rows - System.arraycopy(oldRows, row + 1, rows, row, numRows - (row + 1)); + rows.remove(row); // Decrement all the internal row numbers by one - for (int i = row; i < numRows; i++) - { - if (rows[i] != null) - { - rows[i].decrementRow(); - } - } + rows.stream() + .skip(row) + .filter(Objects::nonNull) + .forEach(RowRecord::decrementRow); // Adjust any hyperlinks - HyperlinkRecord hr = null; - Iterator i = hyperlinks.iterator(); + Iterator i = hyperlinks.iterator(); while (i.hasNext()) { - hr = (HyperlinkRecord) i.next(); + HyperlinkRecord hr = i.next(); if (hr.getRow() == row && hr.getLastRow() == row) - { // The row with the hyperlink on has been removed, so get // rid of it from the list i.remove(); - } else - { hr.removeRow(row); - } } // Adjust any data validations @@ -1047,14 +941,10 @@ public void removeRow(int row) if (validatedCells != null && validatedCells.size() > 0) { - for (Iterator vci = validatedCells.iterator(); vci.hasNext();) - { - CellValue cv = (CellValue) vci.next(); + for (WritableCell cv : validatedCells) { CellFeatures cf = cv.getCellFeatures(); if (cf.getDVParser() != null) - { cf.getDVParser().removeRow(row); - } } } @@ -1062,31 +952,11 @@ public void removeRow(int row) mergedCells.removeRow(row); // Adjust any page breaks - ArrayList newRowBreaks = new ArrayList(); - Iterator ri = rowBreaks.iterator(); - while (ri.hasNext()) - { - int val = ( (Integer) ri.next()).intValue(); - - if (val != row) - { - if (val > row) - { - val--; - } - - newRowBreaks.add(new Integer(val)); - } - } - - rowBreaks = newRowBreaks; + rowBreaks.removeRow(row); // Adjust any conditional formats - for (Iterator cfit = conditionalFormats.iterator(); cfit.hasNext() ;) - { - ConditionalFormat cf = (ConditionalFormat) cfit.next(); + for (ConditionalFormat cf : conditionalFormats) cf.removeRow(row); - } // Handle interested cell references on the main workbook if (workbookSettings.getFormulaAdjust()) @@ -1094,58 +964,49 @@ public void removeRow(int row) workbook.rowRemoved(this, row); } - // Adjust any drawings - /* - if (drawings != null) - { - for (Iterator drawingIt = drawings.iterator() ; drawingIt.hasNext() ; ) - { - DrawingGroupObject dgo = (DrawingGroupObject) drawingIt.next(); - dgo.removeRow(row); - } - } - */ + settings.removeRowFromPrintArea(row); // Adjust the maximum row record numRows--; + + for (DrawingGroupObject dgo : drawings) + if (dgo.getY() >= row) + dgo.setY(max(dgo.getY() - 1, 0)); } /** - * Adds the cell to this sheet. If the cell has already been added to + * Adds the cell to this sheet. If the cell has already been added to * this sheet or another sheet, a WriteException is thrown. If the * position to be occupied by this cell is already taken, the incumbent * cell is replaced. - * The cell is then marked as referenced, and its formatting information + * The cell is then marked as referenced, and its formatting information * registered with the list of formatting records updated if necessary * The RowsExceededException may be caught if client code wishes to * explicitly trap the case where too many rows have been written * to the current sheet. If this behaviour is not desired, it is * sufficient simply to handle the WriteException, since this is a base * class of RowsExceededException - * - * @exception WriteException + * + * @exception WriteException * @exception RowsExceededException * @param cell the cell to add */ - public void addCell(WritableCell cell) + @Override + public void addCell(WritableCell cell) throws WriteException, RowsExceededException { if (cell.getType() == CellType.EMPTY) - { - if (cell != null && cell.getCellFormat() == null) - { - // return if it's a blank cell with no particular cell formatting - // information + if (cell.getCellFormat() == null) { + // remove blank cells with no particular cell formatting + removeCell(cell.getRow(), cell.getColumn()); + return; } - } - + CellValue cv = (CellValue) cell; if (cv.isReferenced()) - { throw new JxlWriteException(JxlWriteException.cellReferenced); - } int row = cell.getRow(); RowRecord rowrec = getRowRecord(row); @@ -1159,12 +1020,12 @@ public void addCell(WritableCell cell) // Check for shared data validations, but only if the cell being added // has a data validation if (cell.getCellFeatures() != null && - cell.getCellFeatures().hasDataValidation() && + cell.getCellFeatures().hasDataValidation() && curSharedValidation) { DVParser dvp = curcell.getCellFeatures().getDVParser(); - logger.warn("Cannot add cell at " + - CellReferenceHelper.getCellReference(cv) + + logger.warn("Cannot add cell at " + + CellReferenceHelper.getCellReference(cv) + " because it is part of the shared cell validation group " + CellReferenceHelper.getCellReference(dvp.getFirstColumn(), dvp.getFirstRow()) + @@ -1178,7 +1039,7 @@ public void addCell(WritableCell cell) if (curSharedValidation) { WritableCellFeatures wcf = cell.getWritableCellFeatures(); - + if (wcf == null) { wcf = new WritableCellFeatures(); @@ -1199,38 +1060,31 @@ public void addCell(WritableCell cell) cv.setCellDetails(formatRecords, sharedStrings, this); } - /** + /** * Gets the row record at the specified row number, growing the * array as needs dictate - * + * * @param row the row number we are interested in * @return the row record at the specified row * @exception RowsExceededException */ RowRecord getRowRecord(int row) throws RowsExceededException { - if (row >= numRowsPerSheet) + if (row >= MAX_ROWS_PER_SHEET) { throw new RowsExceededException(); } // Grow the array of rows if needs be - // Thanks to Brendan for spotting the flaw in merely adding on the - // grow size - if (row >= rows.length) - { - RowRecord[] oldRows = rows; - rows = new RowRecord[Math.max(oldRows.length + rowGrowSize, row+1)]; - System.arraycopy(oldRows, 0, rows, 0, oldRows.length); - oldRows = null; - } + while (row >= rows.size()) + rows.add(null); - RowRecord rowrec = rows[row]; + RowRecord rowrec = rows.get(row); if (rowrec == null) { rowrec = new RowRecord(row, this); - rows[row] = rowrec; + rows.set(row, rowrec); } return rowrec; @@ -1238,18 +1092,18 @@ RowRecord getRowRecord(int row) throws RowsExceededException /** * Gets the row record for the specified row - * + * * @param r the row * @return the row record */ RowRecord getRowInfo(int r) { - if (r < 0 || r > rows.length) + if (r < 0 || r > rows.size()) { return null; } - return rows[r]; + return rows.get(r); } /** @@ -1260,86 +1114,42 @@ RowRecord getRowInfo(int r) */ ColumnInfoRecord getColumnInfo(int c) { - Iterator i = columnFormats.iterator(); + Iterator i = columnFormats.iterator(); ColumnInfoRecord cir = null; boolean stop = false; while (i.hasNext() && !stop) { - cir = (ColumnInfoRecord) i.next(); + cir = i.next(); if (cir.getColumn() >= c) - { - stop = true; - } + stop = true; } if (!stop) - { return null; - } return cir.getColumn() == c ? cir : null; } /** * Sets the name of this worksheet - * + * * @param n the name of this sheet */ + @Override public void setName(String n) { name = n; } - /** - * Sets the hidden status of this sheet - * - * @param h the hiden flag - * @deprecated Use the settings bean instead - */ - public void setHidden(boolean h) - { - settings.setHidden(h); - } - - /** - * Indicates whether or not this sheet is protected - * - * @param prot protected flag - * @deprecated Use the settings bean instead - */ - public void setProtected(boolean prot) - { - settings.setProtected(prot); - } - - /** - * Sets this sheet as selected - * @deprecated Use the settings bean - */ - public void setSelected() - { - settings.setSelected(); - } - - /** - * Retrieves the hidden status of this sheet - * - * @return TRUE if hidden, FALSE otherwise - * @deprecated Use the sheet settings bean instead - */ - public boolean isHidden() - { - return settings.isHidden(); - } - /** * Sets the width (in characters) for a particular column in this sheet - * + * * @param col the column whose width to set * @param width the width of the column in characters */ + @Override public void setColumnView(int col, int width) { CellView cv = new CellView(); @@ -1348,27 +1158,12 @@ public void setColumnView(int col, int width) } /** - * Sets the width (in characters) and format options for a - * particular column in this sheet - * - * @param col the column to set - * @param width the width in characters - * @param format the formt details for the column - */ - public void setColumnView(int col, int width, CellFormat format) - { - CellView cv = new CellView(); - cv.setSize(width * 256); - cv.setFormat(format); - setColumnView(col, cv); - } - - /** * Sets the view for this column * * @param col the column on which to set the view * @param view the view to set */ + @Override public void setColumnView(int col, CellView view) { XFRecord xfr = (XFRecord) view.getFormat(); @@ -1384,27 +1179,23 @@ public void setColumnView(int col, CellView view) { formatRecords.addStyle(xfr); } - + int width = view.depUsed() ? view.getDimension() * 256 : view.getSize(); if (view.isAutosize()) { - autosizedColumns.add(new Integer(col)); + autosizedColumns.add(col); } - ColumnInfoRecord cir = new ColumnInfoRecord(col, - width, + ColumnInfoRecord cir = new ColumnInfoRecord(col, + width, xfr); if (view.isHidden()) - { cir.setHidden(true); - } if (!columnFormats.contains(cir)) - { columnFormats.add(cir); - } else { columnFormats.remove(cir); @@ -1419,13 +1210,10 @@ public void setColumnView(int col, CellView view) ColumnInfoRecord cir = new ColumnInfoRecord (col, view.getDimension()*256, WritableWorkbook.NORMAL_STYLE); if (!columnFormats.contains(cir)) - { columnFormats.add(cir); - } } } - /** * Sets the height of the specified row, as well as its collapse status * @@ -1434,6 +1222,7 @@ public void setColumnView(int col, CellView view) * @exception RowsExceededException * @deprecated use the override which takes a CellView object */ + @Override public void setRowView(int row, int height) throws RowsExceededException { CellView cv = new CellView(); @@ -1450,6 +1239,7 @@ public void setRowView(int row, int height) throws RowsExceededException * @exception jxl.write.biff.RowsExceededException * @deprecated use the override which takes a CellView object */ + @Override public void setRowView(int row, boolean collapsed) throws RowsExceededException { @@ -1458,26 +1248,6 @@ public void setRowView(int row, boolean collapsed) setRowView(row, cv); } - /** - * Sets the height of the specified row, as well as its collapse status - * - * @param row the row to be formatted - * @param height the row height in 1/20th of a point - * @param collapsed indicates whether the row is collapsed - * @param zeroHeight indicates that the row has zero height - * @exception RowsExceededException - * @deprecated use the override which takes a CellView object - */ - public void setRowView(int row, int height, - boolean collapsed) - throws RowsExceededException - { - CellView cv = new CellView(); - cv.setSize(height); - cv.setHidden(collapsed); - setRowView(row, cv); - } - /** * Sets the view for this column * @@ -1485,6 +1255,7 @@ public void setRowView(int row, int height, * @param view the view to set * @exception RowsExceededException */ + @Override public void setRowView(int row, CellView view) throws RowsExceededException { RowRecord rowrec = getRowRecord(row); @@ -1519,11 +1290,11 @@ public void setRowView(int row, CellView view) throws RowsExceededException } /** - * Writes out this sheet. This functionality is delegated off to the + * Writes out this sheet. This functionality is delegated off to the * SheetWriter class in order to reduce the bloated nature of this source * file * - * @exception IOException + * @exception IOException */ public void write() throws IOException { @@ -1538,11 +1309,11 @@ public void write() throws IOException autosizeColumns(); } - sheetWriter.setWriteData(rows, - rowBreaks, + sheetWriter.setWriteData(rows.toArray(RowRecord[]::new), + rowBreaks, columnBreaks, - hyperlinks, - mergedCells, + hyperlinks, + mergedCells, columnFormats, maxRowOutlineLevel, maxColumnOutlineLevel); @@ -1554,13 +1325,13 @@ public void write() throws IOException sheetWriter.setDataValidation(dataValidation, validatedCells); sheetWriter.setConditionalFormats(conditionalFormats); sheetWriter.setAutoFilter(autoFilter); - + sheetWriter.write(); } /** * Copies the specified sheet, row by row and cell by cell - * + * * @param s the sheet to copy */ void copy(Sheet s) @@ -1568,13 +1339,11 @@ void copy(Sheet s) // Copy the settings settings = new SheetSettings(s.getSettings(), this); - SheetCopier si = new SheetCopier(s, this); + SheetCopier si = new SheetCopier(s, this, rowBreaks, columnBreaks); si.setColumnFormats(columnFormats); si.setFormatRecords(formatRecords); si.setHyperlinks(hyperlinks); si.setMergedCells(mergedCells); - si.setRowBreaks(rowBreaks); - si.setColumnBreaks(columnBreaks); si.setSheetWriter(sheetWriter); si.setDrawings(drawings); si.setImages(images); @@ -1596,7 +1365,7 @@ void copy(Sheet s) /** * Copies the specified sheet, row by row and cell by cell - * + * * @param s the sheet to copy */ void copy(WritableSheet s) @@ -1607,7 +1376,7 @@ void copy(WritableSheet s) WritableSheetCopier sc = new WritableSheetCopier(s, this); sc.setColumnFormats(si.columnFormats, columnFormats); sc.setMergedCells(si.mergedCells, mergedCells); - sc.setRows(si.rows); + sc.setRows(si.rows.toArray(RowRecord[]::new)); sc.setRowBreaks(si.rowBreaks, rowBreaks); sc.setColumnBreaks(si.columnBreaks, columnBreaks); sc.setDataValidation(si.dataValidation); @@ -1645,30 +1414,19 @@ final FooterRecord getFooter() { return sheetWriter.getFooter(); } - /** - * Determines whether the sheet is protected - * - * @return whether or not the sheet is protected - * @deprecated Use the SheetSettings bean instead - */ - public boolean isProtected() - { - return settings.isProtected(); - } /** * Gets the hyperlinks on this sheet * * @return an array of hyperlinks */ + @Override public Hyperlink[] getHyperlinks() { Hyperlink[] hl = new Hyperlink[hyperlinks.size()]; for (int i = 0; i < hyperlinks.size(); i++) - { - hl[i] = (Hyperlink) hyperlinks.get(i); - } + hl[i] = hyperlinks.get(i); return hl; } @@ -1678,9 +1436,12 @@ public Hyperlink[] getHyperlinks() * * @return an array of range objects */ - public Range[] getMergedCells() + @Override + public List getMergedCells() { - return mergedCells.getMergedCells(); + @SuppressWarnings("unchecked") + List m = (List) (List) mergedCells.getMergedCells(); + return m; } /** @@ -1688,30 +1449,30 @@ public Range[] getMergedCells() * * @return an array of hyperlinks */ + @Override public WritableHyperlink[] getWritableHyperlinks() { WritableHyperlink[] hl = new WritableHyperlink[hyperlinks.size()]; for (int i = 0; i < hyperlinks.size(); i++) - { - hl[i] = (WritableHyperlink) hyperlinks.get(i); - } + hl[i] = hyperlinks.get(i); return hl; } /** * Removes the specified hyperlink. Note that if you merely set the - * cell contents to be an Empty cell, then the cells containing the + * cell contents to be an Empty cell, then the cells containing the * hyperlink will still be active. The contents of the cell which * activate the hyperlink are removed. - * The hyperlink passed in must be a hyperlink retrieved using the + * The hyperlink passed in must be a hyperlink retrieved using the * getHyperlinks method * * @param h the hyperlink to remove. * @param preserveLabel if TRUE preserves the label contents, if FALSE * removes them */ + @Override public void removeHyperlink(WritableHyperlink h) { removeHyperlink(h, false); @@ -1719,18 +1480,19 @@ public void removeHyperlink(WritableHyperlink h) /** * Removes the specified hyperlink. Note that if you merely set the - * cell contents to be an Empty cell, then the cells containing the + * cell contents to be an Empty cell, then the cells containing the * hyperlink will still be active. - * If the preserveLabel field is set, the cell contents of the + * If the preserveLabel field is set, the cell contents of the * hyperlink are preserved, although the hyperlink is deactivated. If * this value is FALSE, the cell contents are removed - * The hyperlink passed in must be a hyperlink retrieved using the + * The hyperlink passed in must be a hyperlink retrieved using the * getHyperlinks method * * @param h the hyperlink to remove. * @param preserveLabel if TRUE preserves the label contents, if FALSE * removes them */ + @Override public void removeHyperlink(WritableHyperlink h, boolean preserveLabel) { // Remove the hyperlink @@ -1740,19 +1502,20 @@ public void removeHyperlink(WritableHyperlink h, boolean preserveLabel) { // Set the cell contents for the hyperlink - including any formatting // information - to be empty - Assert.verify(rows.length > h.getRow() && rows[h.getRow()] != null); - rows[h.getRow()].removeCell(h.getColumn()); + Assert.verify(rows.size() > h.getRow() && rows.get(h.getRow()) != null); + rows.get(h.getRow()).removeCell(h.getColumn()); } } /** * Adds the specified hyperlink - * + * * @param the hyperlink * @exception WriteException * @exception RowsExceededException */ - public void addHyperlink(WritableHyperlink h) + @Override + public void addHyperlink(WritableHyperlink h) throws WriteException, RowsExceededException { // First set the label on the sheet @@ -1763,30 +1526,20 @@ public void addHyperlink(WritableHyperlink h) { String cnts = ( (HyperlinkRecord) h).getContents(); if (cnts == null) - { - contents = h.getFile().getPath(); - } + contents = h.getFile().toString(); else - { contents = cnts; - } } else if (h.isURL()) { String cnts = ( (HyperlinkRecord) h).getContents(); if (cnts == null) - { contents = h.getURL().toString(); - } else - { contents=cnts; - } } else if (h.isLocation()) - { contents = ( (HyperlinkRecord) h).getContents(); - } // If the cell type is a label, then preserve the cell contents // and most of the format (apart from the font) @@ -1802,33 +1555,25 @@ else if (h.isLocation()) } else { - Label l = new Label(h.getColumn(), h.getRow(), contents, + Label l = new Label(h.getColumn(), h.getRow(), contents, WritableWorkbook.HYPERLINK_STYLE); addCell(l); } - + // Set all other cells within range to be empty for (int i = h.getRow(); i <= h.getLastRow(); i++) - { for (int j = h.getColumn(); j <= h.getLastColumn(); j++) - { if (i != h.getRow() && j != h.getColumn()) - { // Set the cell to be empty - if (rows.length < h.getLastColumn() && rows[i] != null) - { - rows[i].removeCell(j); - } - } - } - } + if (rows.size() < h.getLastColumn() && rows.get(i) != null) + rows.get(i).removeCell(j); ((HyperlinkRecord) h).initialize(this); hyperlinks.add(h); } /** - * Merges the specified cells. Any clashes or intersections between + * Merges the specified cells. Any clashes or intersections between * merged cells are resolved when the spreadsheet is written out * * @param col1 the column number of the top left cell @@ -1836,9 +1581,10 @@ else if (h.isLocation()) * @param col2 the column number of the bottom right cell * @param row2 the row number of the bottom right cell * @return the Range object representing the merged cells - * @exception jxl.write..WriteException + * @exception jxl.write.WriteException * @exception jxl.write.biff.RowsExceededException */ + @Override public Range mergeCells(int col1, int row1, int col2, int row2) throws WriteException, RowsExceededException { @@ -1861,7 +1607,7 @@ public Range mergeCells(int col1, int row1, int col2, int row2) return range; } - /** + /** * Sets a row grouping * * @param row1 the first row of the group @@ -1870,28 +1616,29 @@ public Range mergeCells(int col1, int row1, int col2, int row2) * @exception WriteException * @exception RowsExceededException */ - public void setRowGroup(int row1, int row2, - boolean collapsed) - throws WriteException, RowsExceededException + @Override + public void setRowGroup(int row1, int row2, + boolean collapsed) + throws WriteException, RowsExceededException { if (row2 < row1) { - logger.warn("Cannot merge cells - top and bottom rows incorrectly " + + logger.warn("Cannot merge cells - top and bottom rows incorrectly " + "specified"); } - for (int i = row1; i <= row2; i++) + for (int i = row1; i <= row2; i++) { RowRecord row = getRowRecord(i); numRows = Math.max(i+1, numRows); row.incrementOutlineLevel(); row.setCollapsed(collapsed); - maxRowOutlineLevel = Math.max(maxRowOutlineLevel, + maxRowOutlineLevel = Math.max(maxRowOutlineLevel, row.getOutlineLevel()); } } - /** + /** * Unsets a row grouping * * @param row1 the first row to unset @@ -1899,8 +1646,9 @@ public void setRowGroup(int row1, int row2, * @exception WriteException * @exception RowsExceededException */ - public void unsetRowGroup(int row1, int row2) - throws WriteException, RowsExceededException + @Override + public void unsetRowGroup(int row1, int row2) + throws WriteException, RowsExceededException { if (row2 < row1) { @@ -1911,26 +1659,26 @@ public void unsetRowGroup(int row1, int row2) // Make sure the spreadsheet is up to size if (row2 >= numRows) { - logger.warn("" + row2 + + logger.warn("" + row2 + " is greater than the sheet bounds"); row2 = numRows - 1; } - for (int i = row1; i <= row2; i++) + for (int i = row1; i <= row2; i++) { - rows[i].decrementOutlineLevel(); + rows.get(i).decrementOutlineLevel(); } // Recalculate the max outline level maxRowOutlineLevel = 0; - for (int i = rows.length; i-- > 0; ) + for (int i = rows.size(); i-- > 0; ) { - maxRowOutlineLevel = Math.max(maxRowOutlineLevel, - rows[i].getOutlineLevel()); + maxRowOutlineLevel = Math.max(maxRowOutlineLevel, + rows.get(i).getOutlineLevel()); } } - /** + /** * Sets a column grouping * * @param col1 the first column of the group @@ -1939,8 +1687,9 @@ public void unsetRowGroup(int row1, int row2) * @exception WriteException * @exception RowsExceededException */ - public void setColumnGroup(int col1, int col2, boolean collapsed) - throws WriteException, RowsExceededException + @Override + public void setColumnGroup(int col1, int col2, boolean collapsed) + throws WriteException, RowsExceededException { if (col2 < col1) { @@ -1948,7 +1697,7 @@ public void setColumnGroup(int col1, int col2, boolean collapsed) "specified"); } - for (int i = col1; i <= col2; i++) + for (int i = col1; i <= col2; i++) { ColumnInfoRecord cir = getColumnInfo(i); @@ -1962,12 +1711,12 @@ public void setColumnGroup(int col1, int col2, boolean collapsed) cir.incrementOutlineLevel(); cir.setCollapsed(collapsed); - maxColumnOutlineLevel = Math.max(maxColumnOutlineLevel, + maxColumnOutlineLevel = Math.max(maxColumnOutlineLevel, cir.getOutlineLevel()); } } - /** + /** * Unsets a column grouping * * @param col1 the first column to unset @@ -1975,8 +1724,9 @@ public void setColumnGroup(int col1, int col2, boolean collapsed) * @exception WriteException * @exception RowsExceededException */ - public void unsetColumnGroup(int col1, int col2) - throws WriteException, RowsExceededException + @Override + public void unsetColumnGroup(int col1, int col2) + throws WriteException, RowsExceededException { if (col2 < col1) { @@ -1984,18 +1734,18 @@ public void unsetColumnGroup(int col1, int col2) "specified"); } - for (int i = col1; i <= col2; i++) + for (int i = col1; i <= col2; i++) { ColumnInfoRecord cir = getColumnInfo(i); cir.decrementOutlineLevel(); } - + // Recalculate the max outline level maxColumnOutlineLevel = 0; - for (Iterator it = columnFormats.iterator(); it.hasNext(); ) + for (Iterator it = columnFormats.iterator(); it.hasNext(); ) { - ColumnInfoRecord cir = (ColumnInfoRecord)it.next(); - maxColumnOutlineLevel = Math.max(maxColumnOutlineLevel, + ColumnInfoRecord cir = it.next(); + maxColumnOutlineLevel = Math.max(maxColumnOutlineLevel, cir.getOutlineLevel()); } } @@ -2006,6 +1756,7 @@ public void unsetColumnGroup(int col1, int col2) * * @param r the range of cells to unmerge */ + @Override public void unmergeCells(Range r) { mergedCells.unmergeCells(r); @@ -2019,6 +1770,7 @@ public void unmergeCells(Range r) * @param r the print header to print on the right hand side * @deprecated Use the sheet settings bean */ + @Override public void setHeader(String l, String c, String r) { HeaderFooter header = new HeaderFooter(); @@ -2036,6 +1788,7 @@ public void setHeader(String l, String c, String r) * @param r the print header to print on the right hand side * @deprecated Use the sheet settings bean */ + @Override public void setFooter(String l, String c, String r) { HeaderFooter footer = new HeaderFooter(); @@ -2051,6 +1804,7 @@ public void setFooter(String l, String c, String r) * @param p the page orientation * @deprecated Use the SheetSettings bean */ + @Override public void setPageSetup(PageOrientation p) { settings.setOrientation(p); @@ -2064,6 +1818,7 @@ public void setPageSetup(PageOrientation p) * @param fm the footer margin, in inches * @deprecated Use the SheetSettings bean */ + @Override public void setPageSetup(PageOrientation p, double hm, double fm) { settings.setOrientation(p); @@ -2080,7 +1835,8 @@ public void setPageSetup(PageOrientation p, double hm, double fm) * @param fm the footer margin, in inches * @deprecated Use the SheetSettings bean */ - public void setPageSetup(PageOrientation p, PaperSize ps, + @Override + public void setPageSetup(PageOrientation p, PaperSize ps, double hm, double fm) { settings.setPaperSize(ps); @@ -2089,11 +1845,12 @@ public void setPageSetup(PageOrientation p, PaperSize ps, settings.setFooterMargin(fm); } - /** + /** * Gets the settings for this sheet * * @return the page settings bean */ + @Override public SheetSettings getSettings() { return settings; @@ -2109,52 +1866,24 @@ WorkbookSettings getWorkbookSettings() /** * Forces a page break at the specified row - * + * * @param row the row to break at */ + @Override public void addRowPageBreak(int row) { - // First check that the row is not already present - Iterator i = rowBreaks.iterator(); - boolean found = false; - - while (i.hasNext() && !found) - { - if (( (Integer) i.next()).intValue() == row) - { - found = true; - } - } - - if (!found) - { - rowBreaks.add(new Integer(row)); - } + rowBreaks.addBreak(row); } /** * Forces a page break at the specified column - * + * * @param col the column to break at */ + @Override public void addColumnPageBreak(int col) { - // First check that the row is not already present - Iterator i = columnBreaks.iterator(); - boolean found = false; - - while (i.hasNext() && !found) - { - if (( (Integer) i.next()).intValue() == col) - { - found = true; - } - } - - if (!found) - { - columnBreaks.add(new Integer(col)); - } + columnBreaks.addBreak(col); } /** @@ -2175,23 +1904,23 @@ Chart[] getCharts() private DrawingGroupObject[] getDrawings() { DrawingGroupObject[] dr = new DrawingGroupObject[drawings.size()]; - dr = (DrawingGroupObject[]) drawings.toArray(dr); + dr = drawings.toArray(dr); return dr; } /** * Check all the merged cells for borders. Although in an OO sense the - * logic should belong in this class, in order to reduce the bloated + * logic should belong in this class, in order to reduce the bloated * nature of the source code for this object this logic has been delegated * to the SheetWriter */ void checkMergedBorders() { - sheetWriter.setWriteData(rows, - rowBreaks, + sheetWriter.setWriteData(rows.toArray(RowRecord[]::new), + rowBreaks, columnBreaks, - hyperlinks, - mergedCells, + hyperlinks, + mergedCells, columnFormats, maxRowOutlineLevel, maxColumnOutlineLevel); @@ -2215,32 +1944,23 @@ private WorkspaceInformationRecord getWorkspaceOptions() * @param fontMapping the index mapping for fonts * @param formatMapping the index mapping for formats */ - void rationalize(IndexMapping xfMapping, - IndexMapping fontMapping, + void rationalize(IndexMapping xfMapping, + IndexMapping fontMapping, IndexMapping formatMapping) { // Rationalize the column formats - for (Iterator i = columnFormats.iterator() ; i.hasNext() ;) - { - ColumnInfoRecord cir = (ColumnInfoRecord) i.next(); + for (ColumnInfoRecord cir : columnFormats) cir.rationalize(xfMapping); - } // Rationalize the row formats - for (int i = 0; i < rows.length ; i++) - { - if (rows[i] != null) - { - rows[i].rationalize(xfMapping); - } - } + for (RowRecord row : rows) + if (row != null) + row.rationalize(xfMapping); // Rationalize any data that appears on the charts Chart[] charts = getCharts(); - for (int c = 0; c < charts.length; c++) - { - charts[c].rationalize(xfMapping, fontMapping, formatMapping); - } + for (Chart chart : charts) + chart.rationalize(xfMapping, fontMapping, formatMapping); } /** @@ -2259,6 +1979,7 @@ WritableWorkbookImpl getWorkbook() * @return the column format, or NULL if the column has no specific format * @deprecated Use getColumnView instead */ + @Override public CellFormat getColumnFormat(int col) { return getColumnView(col).getFormat(); @@ -2272,6 +1993,7 @@ public CellFormat getColumnFormat(int col) * specified format * @deprecated Use getColumnView instead */ + @Override public int getColumnWidth(int col) { return getColumnView(col).getDimension(); @@ -2285,6 +2007,7 @@ public int getColumnWidth(int col) * specified format * @deprecated Use getRowView instead */ + @Override public int getRowHeight(int row) { return getRowView(row).getDimension(); @@ -2292,7 +2015,7 @@ public int getRowHeight(int row) /** * Accessor for the chart only method - * + * * @return TRUE if this is a chart only, FALSE otherwise */ boolean isChartOnly() @@ -2307,6 +2030,7 @@ boolean isChartOnly() * @return the row format, or the default format if no override is specified */ + @Override public CellView getRowView(int row) { CellView cv = new CellView(); @@ -2315,15 +2039,13 @@ public CellView getRowView(int row) { RowRecord rr = getRowRecord(row); - if (rr == null || rr.isDefaultHeight()) + if (rr.isDefaultHeight()) { cv.setDimension(settings.getDefaultRowHeight()); cv.setSize(settings.getDefaultRowHeight()); } else if (rr.isCollapsed()) - { cv.setHidden(true); - } else { cv.setDimension(rr.getRowHeight()); @@ -2347,6 +2069,7 @@ else if (rr.isCollapsed()) * @return the column format, or the default format if no override is specified */ + @Override public CellView getColumnView(int col) { ColumnInfoRecord cir = getColumnInfo(col); @@ -2373,19 +2096,20 @@ public CellView getColumnView(int col) * * @param image the image to add */ + @Override public void addImage(WritableImage image) { boolean supported = false; - java.io.File imageFile = image.getImageFile(); + Path imageFile = image.getImageFile(); String fileType = "?"; if (imageFile != null) { - String fileName = imageFile.getName(); + String fileName = imageFile.getFileName().toString(); int fileTypeIndex = fileName.lastIndexOf('.'); - fileType = fileTypeIndex != -1 ? + fileType = fileTypeIndex != -1 ? fileName.substring(fileTypeIndex+1) : ""; - + for (int i = 0 ; i < imageTypes.length && !supported ; i++) { if (fileType.equalsIgnoreCase(imageTypes[i])) @@ -2407,7 +2131,7 @@ public void addImage(WritableImage image) } else { - StringBuffer message = new StringBuffer("Image type "); + StringBuilder message = new StringBuilder("Image type "); message.append(fileType); message.append(" not supported. Supported types are "); message.append(imageTypes[0]); @@ -2425,6 +2149,7 @@ public void addImage(WritableImage image) * * @return the number of images on this sheet */ + @Override public int getNumberOfImages() { return images.size(); @@ -2436,9 +2161,10 @@ public int getNumberOfImages() * @param i the 0-based image index number * @return the image with the specified index number */ + @Override public WritableImage getImage(int i) { - return (WritableImage) images.get(i); + return images.get(i); } /** @@ -2449,7 +2175,7 @@ public WritableImage getImage(int i) */ public Image getDrawing(int i) { - return (Image) images.get(i); + return images.get(i); } /** @@ -2458,6 +2184,7 @@ public Image getDrawing(int i) * * @param wi the image to remove */ + @Override public void removeImage(WritableImage wi) { drawings.remove(wi); @@ -2488,7 +2215,7 @@ private String validateName(String n) String newname = n.replace(illegalSheetNameCharacters[i], '@'); if (n != newname) { - logger.warn(illegalSheetNameCharacters[i] + + logger.warn(illegalSheetNameCharacters[i] + " is not a valid character within a sheet name - replacing"); } n = newname; @@ -2541,7 +2268,7 @@ void removeDataValidation(CellValue cv) if (!result) { - logger.warn("Could not remove validated cell " + + logger.warn("Could not remove validated cell " + CellReferenceHelper.getCellReference(cv)); } } @@ -2552,15 +2279,10 @@ void removeDataValidation(CellValue cv) * * @return the page breaks on this sheet */ - public int[] getRowPageBreaks() + @Override + public IHorizontalPageBreaks getRowPageBreaks() { - int[] rb = new int[rowBreaks.size()]; - int pos = 0; - for (Iterator i = rowBreaks.iterator(); i.hasNext() ; pos++) - { - rb[pos] = ( (Integer) i.next()).intValue(); - } - return rb; + return rowBreaks; } /** @@ -2568,15 +2290,10 @@ public int[] getRowPageBreaks() * * @return the page breaks on this sheet */ - public int[] getColumnPageBreaks() + @Override + public IVerticalPageBreaks getColumnPageBreaks() { - int[] rb = new int[columnBreaks.size()]; - int pos = 0; - for (Iterator i = columnBreaks.iterator(); i.hasNext() ; pos++) - { - rb[pos] = ( (Integer) i.next()).intValue(); - } - return rb; + return columnBreaks; } /** @@ -2623,11 +2340,11 @@ public DataValidation getDataValidation() */ private void autosizeColumns() { - Iterator i = autosizedColumns.iterator(); + Iterator i = autosizedColumns.iterator(); while (i.hasNext()) { - Integer col = (Integer) i.next(); - autosizeColumn(col.intValue()); + Integer col = i.next(); + autosizeColumn(col); } } @@ -2646,22 +2363,22 @@ private void autosizeColumn(int col) for (int i = 0 ; i < numRows; i++) { Cell cell = null; - if (rows[i] != null) + if (rows.get(i) != null) { - cell = rows[i].getCell(col); + cell = rows.get(i).getCell(col); } if (cell != null) { String contents = cell.getContents(); Font font = cell.getCellFormat().getFont(); - + Font activeFont = font.equals(defaultFont) ? columnFont : font; int pointSize = activeFont.getPointSize(); int numChars = contents.length(); - if (activeFont.isItalic() || + if (activeFont.isItalic() || activeFont.getBoldWeight() > 400) // magic value for normal bold { numChars += 2; @@ -2671,10 +2388,10 @@ private void autosizeColumn(int col) maxWidth = Math.max(maxWidth, points * 256); } } - cir.setWidth((int) (maxWidth / defaultFont.getPointSize())); + cir.setWidth(maxWidth / defaultFont.getPointSize()); } - /** + /** * Imports a sheet from a different workbook * * @param s the sheet to import @@ -2684,13 +2401,11 @@ void importSheet(Sheet s) // Copy the settings settings = new SheetSettings(s.getSettings(), this); - SheetCopier si = new SheetCopier(s, this); + SheetCopier si = new SheetCopier(s, this, rowBreaks, columnBreaks); si.setColumnFormats(columnFormats); si.setFormatRecords(formatRecords); si.setHyperlinks(hyperlinks); si.setMergedCells(mergedCells); - si.setRowBreaks(rowBreaks); - si.setColumnBreaks(columnBreaks); si.setSheetWriter(sheetWriter); si.setDrawings(drawings); si.setImages(images); @@ -2709,14 +2424,15 @@ void importSheet(Sheet s) } /** - * Extend the data validation contained in the specified cell across and + * Extend the data validation contained in the specified cell across and * downwards * * @param c the number of cells accross to apply this data validation * @param r the number of cells downwards to apply this data validation */ - public void applySharedDataValidation(WritableCell c, - int extraCols, + @Override + public void applySharedDataValidation(WritableCell c, + int extraCols, int extraRows) throws WriteException { @@ -2725,8 +2441,8 @@ public void applySharedDataValidation(WritableCell c, !c.getWritableCellFeatures().hasDataValidation()) { logger.warn("Cannot extend data validation for " + - CellReferenceHelper.getCellReference(c.getColumn(), - c.getRow()) + + CellReferenceHelper.getCellReference(c.getColumn(), + c.getRow()) + " as it has no data validation"); return; } @@ -2738,9 +2454,9 @@ public void applySharedDataValidation(WritableCell c, int endRow = Math.min(numRows - 1, startRow + extraRows); for (int y = startRow; y <= endRow; y++) { - if (rows[y] != null) + if (rows.get(y) != null) { - int endCol = Math.min(rows[y].getMaxColumn() -1, + int endCol = Math.min(rows.get(y).getMaxColumn() -1, startColumn + extraCols); for (int x = startColumn; x <= endCol; x++) { @@ -2750,7 +2466,7 @@ public void applySharedDataValidation(WritableCell c, continue; // continue statements - they're no better than gotos } - WritableCell c2 = rows[y].getCell(x); + WritableCell c2 = rows.get(y).getCell(x); // Check that the target cell does not have any data validation if (c2 != null && @@ -2760,7 +2476,7 @@ public void applySharedDataValidation(WritableCell c, logger.warn("Cannot apply data validation from " + CellReferenceHelper.getCellReference(startColumn, startRow) + - " to " + + " to " + CellReferenceHelper.getCellReference (startColumn + extraCols, startRow + extraRows) + @@ -2775,7 +2491,7 @@ public void applySharedDataValidation(WritableCell c, // Extend the range on the source data validation WritableCellFeatures sourceDataValidation = c.getWritableCellFeatures(); - sourceDataValidation.getDVParser().extendCellValidation(extraCols, + sourceDataValidation.getDVParser().extendCellValidation(extraCols, extraRows); // Go through all the additional cells and add the data validation cell @@ -2791,7 +2507,7 @@ public void applySharedDataValidation(WritableCell c, } WritableCell c2 = rowrec.getCell(x); - + // Check that the target cell does not have any data validation if (c2 == null) { @@ -2822,12 +2538,13 @@ public void applySharedDataValidation(WritableCell c, } /** - * Remove the shared data validation from multiple cells. The cell passed - * in is the top left cell. The data validation is removed from this + * Remove the shared data validation from multiple cells. The cell passed + * in is the top left cell. The data validation is removed from this * cell and all cells which share the same validation. * * @param cell the top left cell containing the shared data validation */ + @Override public void removeSharedDataValidation(WritableCell cell) throws WriteException { @@ -2839,7 +2556,7 @@ public void removeSharedDataValidation(WritableCell cell) } DVParser dvp = wcf.getDVParser(); - + // If the cell is not part of an extended validation, then simply call // the atomic remove validation from the cell features if (!dvp.extendedCellsValidation()) @@ -2872,8 +2589,8 @@ public void removeSharedDataValidation(WritableCell cell) { for (int x = dvp.getFirstColumn(); x <= dvp.getLastColumn(); x++) { - CellValue c2 = (CellValue) rows[y].getCell(x); - + CellValue c2 = rows.get(y).getCell(x); + // It's possible that some cells in the shared data range might // be null eg. in the event of an insertRow or insertColumn if (c2 != null) @@ -2894,4 +2611,13 @@ public void removeSharedDataValidation(WritableCell cell) dvp.getLastRow()); } } + + private void removeCell(int row, int column) throws RowsExceededException { + if (row >= rows.size()) + return; + + RowRecord rowrec = getRowRecord(row); + rowrec.removeCell(column); + } + } diff --git a/src/jxl/write/biff/WritableWorkbookImpl.java b/src/jxl/write/biff/WritableWorkbookImpl.java index 27408e8..f0038a5 100644 --- a/src/jxl/write/biff/WritableWorkbookImpl.java +++ b/src/jxl/write/biff/WritableWorkbookImpl.java @@ -19,69 +19,51 @@ package jxl.write.biff; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.OutputStream; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.Iterator; - -import jxl.common.Assert; -import jxl.common.Logger; - -import jxl.Range; -import jxl.Sheet; -import jxl.Workbook; -import jxl.WorkbookSettings; -import jxl.biff.BuiltInName; +import java.io.*; +import java.nio.file.*; +import java.util.*; +import static java.util.Optional.empty; +import static java.util.Optional.of; +import static java.util.stream.Collectors.toSet; +import jxl.*; +import jxl.biff.*; import jxl.biff.CellReferenceHelper; -import jxl.biff.CountryCode; -import jxl.biff.Fonts; -import jxl.biff.FormattingRecords; -import jxl.biff.IndexMapping; -import jxl.biff.IntegerHelper; -import jxl.biff.RangeImpl; -import jxl.biff.WorkbookMethods; -import jxl.biff.XCTRecord; -import jxl.biff.drawing.Drawing; -import jxl.biff.drawing.DrawingGroup; -import jxl.biff.drawing.DrawingGroupObject; -import jxl.biff.drawing.Origin; +import jxl.biff.drawing.*; import jxl.biff.formula.ExternalSheet; +import jxl.common.*; +import jxl.format.*; import jxl.format.Colour; -import jxl.format.RGB; +import static jxl.read.biff.SupbookRecord.*; import jxl.read.biff.WorkbookParser; -import jxl.write.WritableCell; -import jxl.write.WritableSheet; -import jxl.write.WritableWorkbook; +import jxl.write.*; /** * A writable workbook */ -public class WritableWorkbookImpl extends WritableWorkbook +public class WritableWorkbookImpl extends WritableWorkbook implements ExternalSheet, WorkbookMethods { /** * The logger */ - private static Logger logger = Logger.getLogger(WritableWorkbookImpl.class); + private static final Logger LOGGER = Logger.getLogger(WritableWorkbookImpl.class); /** * The list of formats available within this workbook */ - private FormattingRecords formatRecords; + private final FormattingRecords formatRecords; /** * The output file to write the workbook to */ - private File outputFile; + private final File outputFile; /** * The list of sheets within this workbook */ - private ArrayList sheets; + private final List sheets = new ArrayList<>(); /** * The list of fonts available within this workbook */ - private Fonts fonts; + private final Fonts fonts; /** * The list of external sheets, used by cell references in formulas */ @@ -90,29 +72,29 @@ public class WritableWorkbookImpl extends WritableWorkbook /** * The supbook records */ - private ArrayList supbooks; + private ArrayList supbooks; /** * The name records */ - private ArrayList names; + private final List names = new ArrayList<>(); /** * A lookup hash map of the name records */ - private HashMap nameRecords; + private final Map nameRecords = new HashMap<>(); /** * The shared strings used by this workbook */ - private SharedStrings sharedStrings; + private final SharedStrings sharedStrings = new SharedStrings(); /** * Indicates whether or not the output stream should be closed. This * depends on whether this Workbook was created with an output stream, * or a flat file (flat file closes the stream */ - private boolean closeStream; + private final boolean closeStream; /** * The workbook protection flag @@ -122,13 +104,13 @@ public class WritableWorkbookImpl extends WritableWorkbook /** * The settings for the workbook */ - private WorkbookSettings settings; + private final WorkbookSettings settings; /** - * The list of cells for the entire workbook which need to be updated + * The list of cells for the entire workbook which need to be updated * following a row/column insert or remove */ - private ArrayList rcirCells; + private final List rcirCells = new ArrayList<>(); /** * The drawing group @@ -138,7 +120,7 @@ public class WritableWorkbookImpl extends WritableWorkbook /** * The jxl.common.workbook styles */ - private Styles styles; + private final Styles styles = new Styles(); /** * Contains macros flag @@ -156,21 +138,22 @@ public class WritableWorkbookImpl extends WritableWorkbook private CountryRecord countryRecord; // synchronizer object for static unitiatialization - private static Object SYNCHRONIZER = new Object(); + private static final Object SYNCHRONIZER = new Object(); + /** * The names of any add in functions */ - private String[] addInFunctionNames; + private final List addInFunctionNames; /** * The XCT records */ - private XCTRecord[] xctRecords; + private final List xctRecords; /** * Constructor. Writes the workbook direct to the existing output stream - * - * @exception IOException + * + * @exception IOException * @param os the output stream * @param cs TRUE if the workbook should close the output stream, FALSE * @param ws the configuration for this workbook @@ -181,18 +164,13 @@ public WritableWorkbookImpl(OutputStream os, boolean cs, WorkbookSettings ws) { super(); outputFile = new File(os, ws, null); - sheets = new ArrayList(); - sharedStrings = new SharedStrings(); - nameRecords = new HashMap(); closeStream = cs; wbProtected = false; containsMacros = false; settings = ws; - rcirCells = new ArrayList(); - styles = new Styles(); // Reset the statically declared styles. These are no longer needed - // because the Styles class will intercept all calls within + // because the Styles class will intercept all calls within // CellValue.setCellDetails and if it detects a standard format, then it // will return a clone. In short, the static cell values will // never get initialized anyway. Still, just to be extra sure... @@ -206,19 +184,20 @@ public WritableWorkbookImpl(OutputStream os, boolean cs, WorkbookSettings ws) DateRecord.defaultDateFormat.uninitialize(); } - WritableFonts wf = new WritableFonts(this); - fonts = wf; + fonts = new WritableFonts(this); - WritableFormattingRecords wfr = new WritableFormattingRecords(fonts, + WritableFormattingRecords wfr = new WritableFormattingRecords(fonts, styles); formatRecords = wfr; + addInFunctionNames = new ArrayList<>(); + xctRecords = new ArrayList<>(); } /** * A pseudo copy constructor. Takes the handles to the font and formatting * records - * - * @exception IOException + * + * @exception IOException * @param w the workbook to copy * @param os the output stream to write the data to * @param cs TRUE if the workbook should close the output stream, FALSE @@ -233,7 +212,7 @@ public WritableWorkbookImpl(OutputStream os, WorkbookParser wp = (WorkbookParser) w; // Reset the statically declared styles. These are no longer needed - // because the Styles class will intercept all calls within + // because the Styles class will intercept all calls within // CellValue.setCellDetails and if it detects a standard format, then it // will return a clone. In short, the static cell values will // never get initialized anyway. Still, just to be extra sure... @@ -248,15 +227,10 @@ public WritableWorkbookImpl(OutputStream os, } closeStream = cs; - sheets = new ArrayList(); - sharedStrings = new SharedStrings(); - nameRecords = new HashMap(); fonts = wp.getFonts(); formatRecords = wp.getFormattingRecords(); wbProtected = false; settings = ws; - rcirCells = new ArrayList(); - styles = new Styles(); outputFile = new File(os, ws, wp.getCompoundFile()); containsMacros = false; @@ -283,22 +257,22 @@ public WritableWorkbookImpl(OutputStream os, externSheet = new ExternalSheetRecord(wp.getExternalSheetRecord()); // Get the associated supbooks - jxl.read.biff.SupbookRecord[] readsr = wp.getSupbookRecords(); - supbooks = new ArrayList(readsr.length); + List readsr = wp.getSupbookRecords(); + supbooks = new ArrayList<>(readsr.size()); - for (int i = 0; i < readsr.length; i++) + for (int i = 0; i < readsr.size(); i++) { - jxl.read.biff.SupbookRecord readSupbook = readsr[i]; - if (readSupbook.getType() == readSupbook.INTERNAL || - readSupbook.getType() == readSupbook.EXTERNAL) + jxl.read.biff.SupbookRecord readSupbook = readsr.get(i); + if (readSupbook.getType() == INTERNAL || + readSupbook.getType() == EXTERNAL) { supbooks.add(new SupbookRecord(readSupbook, settings)); } else { - if (readSupbook.getType() != readSupbook.ADDIN) + if (readSupbook.getType() != ADDIN) { - logger.warn("unsupported supbook type - ignoring"); + LOGGER.warn("unsupported supbook type - ignoring"); } } } @@ -321,28 +295,27 @@ public WritableWorkbookImpl(OutputStream os, // Copy any names if (!settings.getNamesDisabled()) { - jxl.read.biff.NameRecord[] na = wp.getNameRecords(); - names = new ArrayList(na.length); - - for (int i = 0; i < na.length; i++) + List na = wp.getNameRecords(); + + for (int i = 0; i < na.size(); i++) { - if (na[i].isBiff8()) + jxl.read.biff.NameRecord nr = na.get(i); + if (nr.isBiff8()) { - NameRecord n = new NameRecord(na[i], i); + NameRecord n = new NameRecord(nr, i, settings); names.add(n); - String name = n.getName(); - nameRecords.put(name, n); + nameRecords.put(n.getName(), n); } else { - logger.warn("Cannot copy Biff7 name records - ignoring"); + LOGGER.warn("Cannot copy Biff7 name records - ignoring"); } } } - + copyWorkbook(w); - // The copy process may have caused some critical fields in the + // The copy process may have caused some critical fields in the // read drawing group to change. Make sure these updates are reflected // in the writable drawing group if (drawingGroup != null) @@ -354,13 +327,14 @@ public WritableWorkbookImpl(OutputStream os, /** * Gets the sheets within this workbook. Use of this method for * large worksheets can cause performance problems. - * + * * @return an array of the individual sheets */ + @Override public WritableSheet[] getSheets() { WritableSheet[] sheetArray = new WritableSheet[getNumberOfSheets()]; - + for (int i = 0 ; i < getNumberOfSheets() ; i++) { sheetArray[i] = getSheet(i); @@ -373,6 +347,7 @@ public WritableSheet[] getSheets() * * @return an array of strings containing the sheet names */ + @Override public String[] getSheetNames() { String[] sheetNames = new String[getNumberOfSheets()]; @@ -386,12 +361,13 @@ public String[] getSheetNames() } /** - * Interface method from WorkbookMethods - gets the specified + * Interface method from WorkbookMethods - gets the specified * sheet within this workbook * * @param index the zero based index of the required sheet * @return The sheet specified by the index */ + @Override public Sheet getReadSheet(int index) { return getSheet(index); @@ -399,32 +375,34 @@ public Sheet getReadSheet(int index) /** * Gets the specified sheet within this workbook - * + * * @param index the zero based index of the reQuired sheet * @return The sheet specified by the index */ + @Override public WritableSheet getSheet(int index) { - return (WritableSheet) sheets.get(index); + return sheets.get(index); } /** * Gets the sheet with the specified name from within this workbook - * + * * @param name the sheet name * @return The sheet with the specified name, or null if it is not found */ + @Override public WritableSheet getSheet(String name) { // Iterate through the boundsheet records boolean found = false; - Iterator i = sheets.iterator(); + Iterator i = sheets.iterator(); WritableSheet s = null; while (i.hasNext() && !found) { - s = (WritableSheet) i.next(); - + s = i.next(); + if (s.getName().equals(name)) { found = true; @@ -436,9 +414,10 @@ public WritableSheet getSheet(String name) /** * Returns the number of sheets in this workbook - * + * * @return the number of sheets in this workbook */ + @Override public int getNumberOfSheets() { return sheets.size(); @@ -447,13 +426,17 @@ public int getNumberOfSheets() /** * Closes this workbook, and frees makes any memory allocated available * for garbage collection - * - * @exception IOException - * @exception JxlWriteException + * + * @exception IOException */ - public void close() throws IOException, JxlWriteException + @Override + public void close() throws IOException { - outputFile.close(closeStream); + try { + outputFile.close(closeStream); + } catch (JxlWriteException ex) { + throw new IOException(ex); + } } /** @@ -464,9 +447,10 @@ public void close() throws IOException, JxlWriteException * @param fileName the file name * @exception IOException */ - public void setOutputFile(java.io.File fileName) throws IOException + @Override + public void setOutputFile(Path fileName) throws IOException { - FileOutputStream fos = new FileOutputStream(fileName); + OutputStream fos = Files.newOutputStream(fileName); outputFile.setOutputFile(fos); } @@ -478,14 +462,14 @@ public void setOutputFile(java.io.File fileName) throws IOException * @param index * @param handleRefs flag indicating whether or not to handle external * sheet references - * @return + * @return */ - private WritableSheet createSheet(String name, int index, + private WritableSheetImpl createSheet(String name, int index, boolean handleRefs) { - WritableSheet w = new WritableSheetImpl(name, - outputFile, - formatRecords, + WritableSheetImpl w = new WritableSheetImpl(name, + outputFile, + formatRecords, sharedStrings, settings, this); @@ -514,7 +498,7 @@ else if (index > sheets.size()) if (supbooks != null && supbooks.size() > 0) { - SupbookRecord supbook = (SupbookRecord) supbooks.get(0); + SupbookRecord supbook = supbooks.get(0); if (supbook.getType() == SupbookRecord.INTERNAL) { supbook.adjustInternal(sheets.size()); @@ -528,11 +512,12 @@ else if (index > sheets.size()) * Creates a new sheet within the workbook, at the specified position. * The new sheet is inserted at the specified position, or prepended/appended * to the list of sheets if the index specified is somehow inappropriate - * + * * @param name the name of the new sheet * @param index the index at which to add the sheet * @return the created sheet */ + @Override public WritableSheet createSheet(String name, int index) { return createSheet(name, index, true); @@ -542,9 +527,10 @@ public WritableSheet createSheet(String name, int index) * Removes a sheet from this workbook, the other sheets indices being * altered accordingly. If the sheet referenced by the index * does not exist, then no action is taken. - * + * * @param index the index of the sheet to remove */ + @Override public void removeSheet(int index) { int pos = index; @@ -570,23 +556,21 @@ else if (index >= sheets.size()) if (supbooks != null && supbooks.size() > 0) { - SupbookRecord supbook = (SupbookRecord) supbooks.get(0); + SupbookRecord supbook = supbooks.get(0); if (supbook.getType() == SupbookRecord.INTERNAL) { supbook.adjustInternal(sheets.size()); } } - if (names != null && names.size() > 0) + if (names.size() > 0) { - for (int i=0; i< names.size();i++) - { - NameRecord n = (NameRecord) names.get(i); + for (NameRecord n : names) { int oldRef = n.getSheetRef(); if(oldRef == (pos+1)) { n.setSheetRef(0); // make a global name reference - } + } else if (oldRef > (pos+1)) { if(oldRef < 1) @@ -602,22 +586,23 @@ else if (oldRef > (pos+1)) /** * Moves the specified sheet within this workbook to another index * position. - * + * * @param fromIndex the zero based index of the reQuired sheet * @param toIndex the zero based index of the reQuired sheet * @return the sheet that has been moved */ + @Override public WritableSheet moveSheet(int fromIndex, int toIndex) { - // Handle dodgy index + // Handle dodgy index fromIndex = Math.max(fromIndex, 0); fromIndex = Math.min(fromIndex, sheets.size() - 1); toIndex = Math.max(toIndex, 0); toIndex = Math.min(toIndex, sheets.size() - 1); - WritableSheet sheet= (WritableSheet)sheets.remove(fromIndex); + WritableSheetImpl sheet= sheets.remove(fromIndex); sheets.add(toIndex, sheet); - + return sheet; } @@ -625,76 +610,21 @@ public WritableSheet moveSheet(int fromIndex, int toIndex) * Writes out this sheet to the output file. First it writes out * the standard workbook information required by excel, before calling * the write method on each sheet individually - * - * @exception IOException + * + * @exception IOException */ + @Override public void write() throws IOException { // Perform some preliminary sheet check before we start writing out // the workbook - WritableSheetImpl wsi = null; - for (int i = 0; i < getNumberOfSheets(); i++) + for (WritableSheetImpl wsi : sheets) { - wsi = (WritableSheetImpl) getSheet(i); - // Check the merged records. This has to be done before the // globals are written out because some more XF formats might be created wsi.checkMergedBorders(); - - // Check to see if there are any predefined names - Range range = wsi.getSettings().getPrintArea(); - if (range != null) - { - addNameArea(BuiltInName.PRINT_AREA, - wsi, - range.getTopLeft().getColumn(), - range.getTopLeft().getRow(), - range.getBottomRight().getColumn(), - range.getBottomRight().getRow(), - false); - } - - // Check to see if print titles by row were set - Range rangeR = wsi.getSettings().getPrintTitlesRow(); - Range rangeC = wsi.getSettings().getPrintTitlesCol(); - if (rangeR != null && rangeC != null) - { - addNameArea(BuiltInName.PRINT_TITLES, - wsi, - rangeR.getTopLeft().getColumn(), - rangeR.getTopLeft().getRow(), - rangeR.getBottomRight().getColumn(), - rangeR.getBottomRight().getRow(), - rangeC.getTopLeft().getColumn(), - rangeC.getTopLeft().getRow(), - rangeC.getBottomRight().getColumn(), - rangeC.getBottomRight().getRow(), - false); - } - // Check to see if print titles by row were set - else if (rangeR != null) - { - addNameArea(BuiltInName.PRINT_TITLES, - wsi, - rangeR.getTopLeft().getColumn(), - rangeR.getTopLeft().getRow(), - rangeR.getBottomRight().getColumn(), - rangeR.getBottomRight().getRow(), - false); - } - // Check to see if print titles by column were set - else if (rangeC != null) - { - addNameArea(BuiltInName.PRINT_TITLES, - wsi, - rangeC.getTopLeft().getColumn(), - rangeC.getTopLeft().getRow(), - rangeC.getBottomRight().getColumn(), - rangeC.getBottomRight().getRow(), - false); - } } - + // Rationalize all the XF and number formats if (!settings.getRationalizationDisabled()) { @@ -777,11 +707,11 @@ else if (rangeC != null) // If no sheet is identified as being selected, then select // the first one boolean sheetSelected = false; - WritableSheetImpl wsheet = null; + WritableSheetImpl wsheet; int selectedSheetIndex = 0; for (int i = 0 ; i < getNumberOfSheets() && !sheetSelected ; i++) { - wsheet = (WritableSheetImpl) getSheet(i); + wsheet = sheets.get(i); if (wsheet.getSettings().isSelected()) { sheetSelected = true; @@ -797,6 +727,7 @@ else if (rangeC != null) } Window1Record w1r = new Window1Record(selectedSheetIndex); + w1r.setWindowHidden(settings.isWindowHidden()); outputFile.write(w1r); BackupRecord bkr = new BackupRecord(false); @@ -804,7 +735,7 @@ else if (rangeC != null) HideobjRecord ho = new HideobjRecord(settings.getHideobj()); outputFile.write(ho); - + NineteenFourRecord nf = new NineteenFourRecord(false); outputFile.write(nf); @@ -832,99 +763,98 @@ else if (rangeC != null) // Write out the uses elfs record UsesElfsRecord uer = new UsesElfsRecord(); outputFile.write(uer); - + // Write out the boundsheet records. Keep a handle to each one's // position so we can write in the stream offset later int[] boundsheetPos = new int[getNumberOfSheets()]; - Sheet sheet = null; - for (int i = 0; i < getNumberOfSheets(); i++) - { - boundsheetPos[i] = outputFile.getPos(); - sheet = getSheet(i); + int number = 0; + for (WritableSheetImpl sheet : sheets) { + boundsheetPos[number++] = outputFile.getPos(); BoundsheetRecord br = new BoundsheetRecord(sheet.getName()); if (sheet.getSettings().isHidden()) - { br.setHidden(); - } - if ( ( (WritableSheetImpl) sheets.get(i)).isChartOnly()) - { + if ( sheet.isChartOnly()) br.setChartOnly(); - } outputFile.write(br); } if (countryRecord == null) { - CountryCode lang = + CountryCode lang = CountryCode.getCountryCode(settings.getExcelDisplayLanguage()); if (lang == CountryCode.UNKNOWN) { - logger.warn("Unknown country code " + - settings.getExcelDisplayLanguage() + + LOGGER.warn("Unknown country code " + + settings.getExcelDisplayLanguage() + " using " + CountryCode.USA.getCode()); lang = CountryCode.USA; } - CountryCode region = + CountryCode region = CountryCode.getCountryCode(settings.getExcelRegionalSettings()); countryRecord = new CountryRecord(lang, region); if (region == CountryCode.UNKNOWN) { - logger.warn("Unknown country code " + - settings.getExcelDisplayLanguage() + + LOGGER.warn("Unknown country code " + + settings.getExcelDisplayLanguage() + " using " + CountryCode.UK.getCode()); region = CountryCode.UK; } } outputFile.write(countryRecord); - - // Write out the names of any add in functions - if (addInFunctionNames != null && addInFunctionNames.length > 0) - { - // Write out the supbook record - // SupbookRecord supbook = new SupbookRecord(); - // outputFile.write(supbook); - for (int i = 0 ; i < addInFunctionNames.length; i++) - { - ExternalNameRecord enr = new ExternalNameRecord(addInFunctionNames[i]); - outputFile.write(enr); - } - } + // Write out the supbook record + // SupbookRecord supbook = new SupbookRecord(); + // outputFile.write(supbook); - if (xctRecords != null) - { - for (int i = 0 ; i < xctRecords.length; i++) - { - outputFile.write(xctRecords[i]); - } - } + // Write out the names of any add in functions + for (String name : addInFunctionNames) + outputFile.write(new ExternalNameRecord(name)); + + for (XCTRecord xctRecord : xctRecords) + outputFile.write(xctRecord); // Write out the external sheet record, if it exists if (externSheet != null) { //Write out all the supbook records - for (int i = 0; i < supbooks.size() ; i++) - { - SupbookRecord supbook = (SupbookRecord) supbooks.get(i); + for (SupbookRecord supbook : supbooks) outputFile.write(supbook); - } outputFile.write(externSheet); } + Map printAreas = getPrintAreas(sheets); + Map printTitles = getPrintTitles(sheets); // Write out the names, if any exists - if (names != null) - { - for (int i = 0 ; i < names.size() ; i++) - { - NameRecord n = (NameRecord) names.get(i); - outputFile.write(n); + for (NameRecord n : names) { + // insert print area names in the original order to retain references to name table indices + if (BuiltInName.PRINT_AREA.equals(n.getBuiltInName())) { + var printArea = printAreas.remove(n.getIndex()); + outputFile.write(printArea); + continue; + } + + // insert print title names in the original order to retain references to name table indices + if (BuiltInName.PRINT_TITLES.equals(n.getBuiltInName())) { + var printTitle = printTitles.remove(n.getIndex()); + outputFile.write(printTitle); + continue; } + + outputFile.write(n); } - + + Set remainingPrintAreas = printAreas.keySet(); + while (! remainingPrintAreas.isEmpty()) + outputFile.write(printAreas.remove(remainingPrintAreas.iterator().next())); + + Set remainingPrintTitles = printTitles.keySet(); + while (! remainingPrintTitles.isEmpty()) + outputFile.write(printTitles.remove(remainingPrintTitles.iterator().next())); + // Write out the mso drawing group, if it exists if (drawingGroup != null) { @@ -951,23 +881,100 @@ else if (rangeC != null) } } + private Map getPrintAreas(List sheets) throws IOException { + Map printAreas = new HashMap<>(); + + // Check to see if there are any predefined names + for (var wsi : sheets) { + Range range = wsi.getSettings().getPrintArea(); + if (range != null) { + var printArea = createNameRecord( + BuiltInName.PRINT_AREA, + wsi, + range.getTopLeft().getColumn(), + range.getTopLeft().getRow(), + range.getBottomRight().getColumn(), + range.getBottomRight().getRow(), + false); + printAreas.put(printArea.getIndex(), printArea); + } + } + + return printAreas; + } + + private Map getPrintTitles(List sheets) throws IOException { + Map printTitles = new HashMap<>(); + for (var wsi : sheets) { + var mayBePrintTitle = getPrintTitles(wsi); + if (mayBePrintTitle.isPresent()) + printTitles.put(mayBePrintTitle.orElseThrow().getIndex(), mayBePrintTitle.orElseThrow()); + } + + return printTitles; + } + + private Optional getPrintTitles(WritableSheetImpl wsi) { + // Check to see if print titles by row were set + Range rangeR = wsi.getSettings().getPrintTitlesRow(); + Range rangeC = wsi.getSettings().getPrintTitlesCol(); + if (rangeR != null && rangeC != null) { + return of(createNameRecord( + BuiltInName.PRINT_TITLES, + wsi, + rangeR.getTopLeft().getColumn(), + rangeR.getTopLeft().getRow(), + rangeR.getBottomRight().getColumn(), + rangeR.getBottomRight().getRow(), + rangeC.getTopLeft().getColumn(), + rangeC.getTopLeft().getRow(), + rangeC.getBottomRight().getColumn(), + rangeC.getBottomRight().getRow(), + false)); + } + + // Check to see if print titles by row were set + else if (rangeR != null) { + return of(createNameRecord( + BuiltInName.PRINT_TITLES, + wsi, + rangeR.getTopLeft().getColumn(), + rangeR.getTopLeft().getRow(), + rangeR.getBottomRight().getColumn(), + rangeR.getBottomRight().getRow(), + false)); + } + + // Check to see if print titles by column were set + else if (rangeC != null) { + return of(createNameRecord( + BuiltInName.PRINT_TITLES, + wsi, + rangeC.getTopLeft().getColumn(), + rangeC.getTopLeft().getRow(), + rangeC.getBottomRight().getColumn(), + rangeC.getBottomRight().getRow(), + false)); + } + + return empty(); + } + /** - * Produces a writable copy of the workbook passed in by - * creating copies of each sheet in the specified workbook and adding + * Produces a writable copy of the workbook passed in by + * creating copies of each sheet in the specified workbook and adding * them to its own record - * + * * @param w the workbook to copy */ private void copyWorkbook(Workbook w) { int numSheets = w.getNumberOfSheets(); wbProtected = w.isProtected(); - Sheet s = null; - WritableSheetImpl ws = null; for (int i = 0 ; i < numSheets; i++) { - s = w.getSheet(i); - ws = (WritableSheetImpl) createSheet(s.getName(),i, false); + Sheet s = w.getSheet(i); + WritableSheetImpl ws = createSheet(s.getName(),i, false); ws.copy(s); } } @@ -980,6 +987,7 @@ private void copyWorkbook(Workbook w) * @param name the name of the new sheet * @param index the position of the new sheet */ + @Override public void copySheet(int s, String name, int index) { WritableSheet sheet = getSheet(s); @@ -995,6 +1003,7 @@ public void copySheet(int s, String name, int index) * @param name the name of the new sheet * @param index the position of the new sheet */ + @Override public void copySheet(String s, String name, int index) { WritableSheet sheet = getSheet(s); @@ -1004,9 +1013,10 @@ public void copySheet(String s, String name, int index) /** * Indicates whether or not this workbook is protected - * + * * @param prot protected flag */ + @Override public void setProtected(boolean prot) { wbProtected = prot; @@ -1020,15 +1030,11 @@ private void rationalize() { IndexMapping fontMapping = formatRecords.rationalizeFonts(); IndexMapping formatMapping = formatRecords.rationalizeDisplayFormats(); - IndexMapping xfMapping = formatRecords.rationalize(fontMapping, + IndexMapping xfMapping = formatRecords.rationalize(fontMapping, formatMapping); - WritableSheetImpl wsi = null; - for (int i = 0; i < sheets.size(); i++) - { - wsi = (WritableSheetImpl) sheets.get(i); + for (WritableSheetImpl wsi : sheets) wsi.rationalize(xfMapping, fontMapping, formatMapping); - } } /** @@ -1039,18 +1045,15 @@ private void rationalize() */ private int getInternalSheetIndex(String name) { - int index = -1; - String[] names = getSheetNames(); - for (int i = 0 ; i < names.length; i++) - { - if (name.equals(names[i])) - { - index = i; - break; - } + int index = 0; + for (String sheetName : getSheetNames()) { + if (name.equals(sheetName)) + return index; + + index++; } - return index; + return -1; } /** @@ -1059,13 +1062,14 @@ private int getInternalSheetIndex(String name) * @param index the external sheet index * @return the name of the external sheet */ + @Override public String getExternalSheetName(int index) { int supbookIndex = externSheet.getSupbookIndex(index); - SupbookRecord sr = (SupbookRecord) supbooks.get(supbookIndex); - + SupbookRecord sr = supbooks.get(supbookIndex); + int firstTab = externSheet.getFirstTabIndex(index); - + if (sr.getType() == SupbookRecord.INTERNAL) { // It's an internal reference - get the name from the sheets list @@ -1078,9 +1082,9 @@ else if (sr.getType() == SupbookRecord.EXTERNAL) String name = sr.getFileName() + sr.getSheetName(firstTab); return name; } - + // An unknown supbook - return unkown - logger.warn("Unknown Supbook 1"); + LOGGER.warn("Unknown Supbook 1"); return "[UNKNOWN]"; } @@ -1093,10 +1097,10 @@ else if (sr.getType() == SupbookRecord.EXTERNAL) public String getLastExternalSheetName(int index) { int supbookIndex = externSheet.getSupbookIndex(index); - SupbookRecord sr = (SupbookRecord) supbooks.get(supbookIndex); - + SupbookRecord sr = supbooks.get(supbookIndex); + int lastTab = externSheet.getLastTabIndex(index); - + if (sr.getType() == SupbookRecord.INTERNAL) { // It's an internal reference - get the name from the sheets list @@ -1108,9 +1112,9 @@ else if (sr.getType() == SupbookRecord.EXTERNAL) { Assert.verify(false); } - + // An unknown supbook - return unkown - logger.warn("Unknown Supbook 2"); + LOGGER.warn("Unknown Supbook 2"); return "[UNKNOWN]"; } @@ -1118,8 +1122,9 @@ else if (sr.getType() == SupbookRecord.EXTERNAL) * Parsing of formulas is only supported for a subset of the available * biff version, so we need to test to see if this version is acceptable * - * @return the BOF record, which + * @return the BOF record, which */ + @Override public jxl.read.biff.BOFRecord getWorkbookBof() { return null; @@ -1127,17 +1132,16 @@ public jxl.read.biff.BOFRecord getWorkbookBof() /** - * Gets the index of the external sheet for the name + * Gets the index of the external sheet with index * - * @param sheetName + * @param index * @return the sheet index of the external sheet index */ + @Override public int getExternalSheetIndex(int index) { if (externSheet == null) - { return index; - } Assert.verify(externSheet != null); @@ -1147,17 +1151,16 @@ public int getExternalSheetIndex(int index) } /** - * Gets the index of the external sheet for the name + * Gets the index of the external sheet with index * - * @param sheetName + * @param index * @return the sheet index of the external sheet index */ + @Override public int getLastExternalSheetIndex(int index) { if (externSheet == null) - { return index; - } Assert.verify(externSheet != null); @@ -1169,28 +1172,28 @@ public int getLastExternalSheetIndex(int index) /** * Gets the external sheet index for the sheet name * - * @param sheetName + * @param sheetName * @return the sheet index or -1 if the sheet could not be found */ + @Override public int getExternalSheetIndex(String sheetName) { if (externSheet == null) { externSheet = new ExternalSheetRecord(); - supbooks = new ArrayList(); + supbooks = new ArrayList<>(); supbooks.add(new SupbookRecord(getNumberOfSheets(), settings)); } // Iterate through the sheets records boolean found = false; - Iterator i = sheets.iterator(); + Iterator i = sheets.iterator(); int sheetpos = 0; - WritableSheetImpl s = null; while (i.hasNext() && !found) { - s = (WritableSheetImpl) i.next(); - + WritableSheetImpl s = i.next(); + if (s.getName().equals(sheetName)) { found = true; @@ -1205,29 +1208,29 @@ public int getExternalSheetIndex(String sheetName) { // Check that the supbook record at position zero is internal and // contains all the sheets - SupbookRecord supbook = (SupbookRecord) supbooks.get(0); + SupbookRecord supbook = supbooks.get(0); if (supbook.getType() != SupbookRecord.INTERNAL || supbook.getNumberOfSheets() != getNumberOfSheets()) { - logger.warn("Cannot find sheet " + sheetName + " in supbook record"); + LOGGER.warn("Cannot find sheet " + sheetName + " in supbook record"); } - + return externSheet.getIndex(0, sheetpos); } // Check for square brackets int closeSquareBracketsIndex = sheetName.lastIndexOf(']'); int openSquareBracketsIndex = sheetName.lastIndexOf('['); - + if (closeSquareBracketsIndex == -1 || openSquareBracketsIndex == -1) { - logger.warn("Square brackets"); + LOGGER.warn("Square brackets"); return -1; } String worksheetName = sheetName.substring(closeSquareBracketsIndex+1); - String workbookName = sheetName.substring(openSquareBracketsIndex+1, + String workbookName = sheetName.substring(openSquareBracketsIndex+1, closeSquareBracketsIndex); String path = sheetName.substring(0, openSquareBracketsIndex); String fileName = path + workbookName; @@ -1237,7 +1240,7 @@ public int getExternalSheetIndex(String sheetName) int supbookIndex = -1; for (int ind = 0; ind < supbooks.size() && !supbookFound ; ind++) { - externalSupbook = (SupbookRecord) supbooks.get(ind); + externalSupbook = supbooks.get(ind); if (externalSupbook.getType() == SupbookRecord.EXTERNAL && externalSupbook.getFileName().equals(fileName)) { @@ -1252,7 +1255,7 @@ public int getExternalSheetIndex(String sheetName) supbookIndex = supbooks.size(); supbooks.add(externalSupbook); } - + int sheetIndex = externalSupbook.getSheetIndex(worksheetName); return externSheet.getIndex(supbookIndex, sheetIndex); @@ -1260,36 +1263,32 @@ public int getExternalSheetIndex(String sheetName) /** * Gets the last external sheet index for the sheet name - * @param sheetName + * @param sheetName * @return the sheet index or -1 if the sheet could not be found */ + @Override public int getLastExternalSheetIndex(String sheetName) { if (externSheet == null) { externSheet = new ExternalSheetRecord(); - supbooks = new ArrayList(); + supbooks = new ArrayList<>(); supbooks.add(new SupbookRecord(getNumberOfSheets(), settings)); } // Iterate through the sheets records boolean found = false; - Iterator i = sheets.iterator(); + Iterator i = sheets.iterator(); int sheetpos = 0; - WritableSheetImpl s = null; while (i.hasNext() && !found) { - s = (WritableSheetImpl) i.next(); - + WritableSheetImpl s = i.next(); + if (s.getName().equals(sheetName)) - { found = true; - } else - { sheetpos++; - } } if (!found) @@ -1299,7 +1298,7 @@ public int getLastExternalSheetIndex(String sheetName) // Check that the supbook record at position zero is internal and contains // all the sheets - SupbookRecord supbook = (SupbookRecord) supbooks.get(0); + SupbookRecord supbook = supbooks.get(0); Assert.verify(supbook.getType() == SupbookRecord.INTERNAL && supbook.getNumberOfSheets() == getNumberOfSheets()); @@ -1314,6 +1313,7 @@ public int getLastExternalSheetIndex(String sheetName) * @param g the green portion to set (0-255) * @param b the blue portion to set (0-255) */ + @Override public void setColourRGB(Colour c, int r, int g, int b) { formatRecords.setColourRGB(c,r,g,b); @@ -1322,6 +1322,7 @@ public void setColourRGB(Colour c, int r, int g, int b) /** * Accessor for the RGB value for the specified colour * + * @param c colour * @return the RGB for the specified colour */ public RGB getColourRGB(Colour c) @@ -1334,23 +1335,27 @@ public RGB getColourRGB(Colour c) * * @param index the index into the name table * @return the name of the cell + * @throws NameRangeException */ - public String getName(int index) + @Override + public String getName(int index) throws NameRangeException { - Assert.verify(index >= 0 && index < names.size()); - NameRecord n = (NameRecord) names.get(index); - return n.getName(); + if (! (index >= 0 && index < names.size())) + throw new NameRangeException(); + + return names.get(index).getName(); } /** * Gets the index of the name record for the name * - * @param name + * @param name * @return the index in the name table */ + @Override public int getNameIndex(String name) { - NameRecord nr = (NameRecord) nameRecords.get(name); + NameRecord nr = nameRecords.get(name); return nr != null ? nr.getIndex() : -1; } @@ -1375,21 +1380,12 @@ void addRCIRCell(CellValue cv) void columnInserted(WritableSheetImpl s, int col) { int externalSheetIndex = getExternalSheetIndex(s.getName()); - for (Iterator i = rcirCells.iterator() ; i.hasNext() ;) - { - CellValue cv = (CellValue) i.next(); + for (CellValue cv : rcirCells) cv.columnInserted(s, externalSheetIndex, col); - } // Adjust any named cells - if (names != null) - { - for (Iterator i = names.iterator(); i.hasNext() ;) - { - NameRecord nameRecord = (NameRecord) i.next(); - nameRecord.columnInserted(externalSheetIndex, col); - } - } + for (NameRecord nameRecord : names) + nameRecord.columnInserted(externalSheetIndex, col); } /** @@ -1402,37 +1398,15 @@ void columnInserted(WritableSheetImpl s, int col) void columnRemoved(WritableSheetImpl s, int col) { int externalSheetIndex = getExternalSheetIndex(s.getName()); - for (Iterator i = rcirCells.iterator() ; i.hasNext() ;) - { - CellValue cv = (CellValue) i.next(); + for (CellValue cv : rcirCells) cv.columnRemoved(s, externalSheetIndex, col); - } // Adjust any named cells - ArrayList removedNames = new ArrayList(); - if (names != null) - { - for (Iterator i = names.iterator(); i.hasNext() ;) - { - NameRecord nameRecord = (NameRecord) i.next(); - boolean removeName = nameRecord.columnRemoved(externalSheetIndex, - col); - - if (removeName) - { - removedNames.add(nameRecord); - } - } - - // Remove any names which have been deleted - for (Iterator i = removedNames.iterator(); i.hasNext() ;) - { - NameRecord nameRecord = (NameRecord) i.next(); - boolean removed = names.remove(nameRecord); - Assert.verify(removed, "Could not remove name " + - nameRecord.getName()); - } - } + ArrayList removedNames = new ArrayList<>(); + for (NameRecord nameRecord : names) + if (nameRecord.columnRemoved(externalSheetIndex, col)) + removedNames.add(nameRecord); + names.removeAll(removedNames); } /** @@ -1445,23 +1419,14 @@ void columnRemoved(WritableSheetImpl s, int col) void rowInserted(WritableSheetImpl s, int row) { int externalSheetIndex = getExternalSheetIndex(s.getName()); - + // Adjust the row infos - for (Iterator i = rcirCells.iterator() ; i.hasNext() ;) - { - CellValue cv = (CellValue) i.next(); + for (CellValue cv : rcirCells) cv.rowInserted(s, externalSheetIndex, row); - } // Adjust any named cells - if (names != null) - { - for (Iterator i = names.iterator(); i.hasNext() ;) - { - NameRecord nameRecord = (NameRecord) i.next(); - nameRecord.rowInserted(externalSheetIndex, row); - } - } + for (NameRecord nameRecord : names) + nameRecord.rowInserted(externalSheetIndex, row); } /** @@ -1474,36 +1439,33 @@ void rowInserted(WritableSheetImpl s, int row) void rowRemoved(WritableSheetImpl s, int row) { int externalSheetIndex = getExternalSheetIndex(s.getName()); - for (Iterator i = rcirCells.iterator() ; i.hasNext() ;) - { - CellValue cv = (CellValue) i.next(); + for (CellValue cv : rcirCells) cv.rowRemoved(s, externalSheetIndex, row); - } // Adjust any named cells - ArrayList removedNames = new ArrayList(); - if (names != null) - { - for (Iterator i = names.iterator(); i.hasNext() ;) - { - NameRecord nameRecord = (NameRecord) i.next(); - boolean removeName = nameRecord.rowRemoved(externalSheetIndex, row); + ArrayList removedNames = new ArrayList<>(); + for (NameRecord nameRecord : names) + if (nameRecord.rowRemoved(externalSheetIndex, row)) + removedNames.add(nameRecord); + // Remove any names which have been deleted + names.removeAll(removedNames); + } - if (removeName) - { - removedNames.add(nameRecord); - } - } + @Override + public CellLocation findCellLocationByName(String name) throws NoSuchElementException { + NameRecord nr = nameRecords.get(name); - // Remove any names which have been deleted - for (Iterator i = removedNames.iterator(); i.hasNext() ;) - { - NameRecord nameRecord = (NameRecord) i.next(); - boolean removed = names.remove(nameRecord); - Assert.verify(removed, "Could not remove name " + - nameRecord.getName()); - } - } + if (nr == null) + throw new NoSuchElementException("The range named " + name + " was not found."); + + NameRecord.NameRange[] ranges = nr.getRanges(); + + // Go and retrieve the first cell in the first range + int sheetIndex = getExternalSheetIndex(ranges[0].getExternalSheet()); + return new CellLocation( + getSheet(sheetIndex), + ranges[0].getFirstColumn(), + ranges[0].getFirstRow()); } /** @@ -1511,47 +1473,39 @@ void rowRemoved(WritableSheetImpl s, int row) * range of cells, then the cell on the top left is returned. If * the name cannot be found, null is returned * - * @param the name of the cell/range to search for + * @param name of the cell/range to search for * @return the cell in the top left of the range if found, NULL * otherwise */ + @Override public WritableCell findCellByName(String name) { - NameRecord nr = (NameRecord) nameRecords.get(name); - - if (nr == null) - { + try { + CellLocation cl = findCellLocationByName(name); + return cl.getSheet().getWritableCell(cl.getColumn(), cl.getRow()); + } catch (NoSuchElementException ex) { return null; } - - NameRecord.NameRange[] ranges = nr.getRanges(); - - // Go and retrieve the first cell in the first range - int sheetIndex = getExternalSheetIndex(ranges[0].getExternalSheet()); - WritableSheet s = getSheet(sheetIndex); - WritableCell cell = s.getWritableCell(ranges[0].getFirstColumn(), - ranges[0].getFirstRow()); - - return cell; } /** * Gets the named range from this workbook. The Range object returns * contains all the cells from the top left to the bottom right - * of the range. + * of the range. * If the named range comprises an adjacent range, * the Range[] will contain one object; for non-adjacent * ranges, it is necessary to return an array of length greater than - * one. + * one. * If the named range contains a single cell, the top left and * bottom right cell will be the same cell * - * @param the name of the cell/range to search for + * @param name of the cell/range to search for * @return the range of cells */ + @Override public Range[] findByName(String name) { - NameRecord nr = (NameRecord) nameRecords.get(name); + NameRecord nr = nameRecords.get(name); if (nr == null) { @@ -1565,7 +1519,7 @@ public Range[] findByName(String name) for (int i = 0; i < ranges.length ; i++) { cellRanges[i] = new RangeImpl - (this, + (this, getExternalSheetIndex(ranges[i].getExternalSheet()), ranges[i].getFirstColumn(), ranges[i].getFirstRow(), @@ -1636,21 +1590,11 @@ DrawingGroup createDrawingGroup() * * @return the list of named cells within the workbook */ - public String[] getRangeNames() - { - if (names == null) - { - return new String[0]; - } - - String[] n = new String[names.size()]; - for (int i = 0 ; i < names.size() ; i++) - { - NameRecord nr = (NameRecord) names.get(i); - n[i] = nr.getName(); - } - - return n; + @Override + public Set getRangeNames() { + return names.stream() + .map(NameRecord::getName) + .collect(toSet()); } /** @@ -1658,21 +1602,18 @@ public String[] getRangeNames() * * @param name the name to remove */ + @Override public void removeRangeName(String name) { int pos = 0; boolean found = false; - for (Iterator i = names.iterator(); i.hasNext() && !found ;) + for (Iterator i = names.iterator(); i.hasNext() && !found ;) { - NameRecord nr = (NameRecord) i.next(); - if (nr.getName().equals(name)) - { + NameRecord nr = i.next(); + if (name.equals(nr.getName())) found = true; - } else - { pos++; - } } // Remove the name from the list of names and the associated hashmap @@ -1683,7 +1624,7 @@ public void removeRangeName(String name) names.remove(pos); if (nameRecords.remove(name) == null) { - logger.warn("Could not remove " + name + " from index lookups"); + LOGGER.warn("Could not remove " + name + " from index lookups"); } } } @@ -1700,7 +1641,7 @@ Styles getStyles() /** * Add new named area to this workbook with the given information. - * + * * @param name name to be created. * @param sheet sheet containing the name * @param firstCol first column this name refers to. @@ -1708,10 +1649,11 @@ Styles getStyles() * @param lastCol last column this name refers to. * @param lastRow last row this name refers to. */ - public void addNameArea(String name, + @Override + public void addNameArea(String name, WritableSheet sheet, - int firstCol, - int firstRow, + int firstCol, + int firstRow, int lastCol, int lastRow) { @@ -1720,94 +1662,69 @@ public void addNameArea(String name, /** * Add new named area to this workbook with the given information. - * + * * @param name name to be created. * @param sheet sheet containing the name * @param firstCol first column this name refers to. * @param firstRow first row this name refers to. * @param lastCol last column this name refers to. * @param lastRow last row this name refers to. - * @param global TRUE if this is a global name, FALSE if this is tied to + * @param global TRUE if this is a global name, FALSE if this is tied to * the sheet */ - void addNameArea(String name, + void addNameArea(String name, WritableSheet sheet, - int firstCol, - int firstRow, + int firstCol, + int firstRow, int lastCol, int lastRow, boolean global) { - if (names == null) - { - names = new ArrayList(); - } - int externalSheetIndex = getExternalSheetIndex(sheet.getName()); // Create a new name record. - NameRecord nr = - new NameRecord(name, + NameRecord nr = + new NameRecord(name, names.size(), - externalSheetIndex, - firstRow, lastRow, - firstCol, lastCol, + externalSheetIndex, + firstRow, lastRow, + firstCol, lastCol, global); - + + // avoid name collisions + removeRangeName(name); + // Add new name to name array. names.add(nr); - + // Add new name to name hash table. nameRecords.put(name, nr); } /** - * Add new named area to this workbook with the given information. - * * @param name name to be created. * @param sheet sheet containing the name * @param firstCol first column this name refers to. * @param firstRow first row this name refers to. * @param lastCol last column this name refers to. * @param lastRow last row this name refers to. - * @param global TRUE if this is a global name, FALSE if this is tied to + * @param global TRUE if this is a global name, FALSE if this is tied to * the sheet */ - void addNameArea(BuiltInName name, - WritableSheet sheet, - int firstCol, - int firstRow, - int lastCol, - int lastRow, - boolean global) - { - if (names == null) - { - names = new ArrayList(); - } - + private NameRecord createNameRecord( + BuiltInName name, WritableSheet sheet, int firstCol, int firstRow, int lastCol, int lastRow, boolean global) { int index = getInternalSheetIndex(sheet.getName()); int externalSheetIndex = getExternalSheetIndex(sheet.getName()); - // Create a new name record. - NameRecord nr = - new NameRecord(name, - index, - externalSheetIndex, - firstRow, lastRow, - firstCol, lastCol, - global); - - // Add new name to name array. - names.add(nr); - - // Add new name to name hash table. - nameRecords.put(name, nr); + return new NameRecord(name, + index, + externalSheetIndex, + firstRow, lastRow, + firstCol, lastCol, + global); } /** - * Add new named area to this workbook with the given information. - * * @param name name to be created. * @param sheet sheet containing the name * @param firstCol first column this name refers to. @@ -1818,47 +1735,23 @@ void addNameArea(BuiltInName name, * @param firstRow2 first row this name refers to. * @param lastCol2 last column this name refers to. * @param lastRow2 last row this name refers to. - * @param global TRUE if this is a global name, FALSE if this is tied to + * @param global TRUE if this is a global name, FALSE if this is tied to * the sheet */ - void addNameArea(BuiltInName name, - WritableSheet sheet, - int firstCol, - int firstRow, - int lastCol, - int lastRow, - int firstCol2, - int firstRow2, - int lastCol2, - int lastRow2, - boolean global) - { - if (names == null) - { - names = new ArrayList(); - } - + private NameRecord createNameRecord(BuiltInName name, WritableSheet sheet, int firstCol, int firstRow, int lastCol, int lastRow, int firstCol2, int firstRow2, int lastCol2, int lastRow2, boolean global) { int index = getInternalSheetIndex(sheet.getName()); int externalSheetIndex = getExternalSheetIndex(sheet.getName()); - // Create a new name record. - NameRecord nr = - new NameRecord(name, - index, - externalSheetIndex, - firstRow2, lastRow2, - firstCol2, lastCol2, - firstRow, lastRow, - firstCol, lastCol, - global); - - // Add new name to name array. - names.add(nr); - - // Add new name to name hash table. - nameRecords.put(name, nr); - } - + return new NameRecord(name, + index, + externalSheetIndex, + firstRow2, lastRow2, + firstCol2, lastCol2, + firstRow, lastRow, + firstCol, lastCol, + global); + } + /** * Accessor for the workbook settings */ @@ -1868,7 +1761,7 @@ WorkbookSettings getSettings() } /** - * Returns the cell for the specified location eg. "Sheet1!A4". + * Returns the cell for the specified location eg. "Sheet1!A4". * This is identical to using the CellReferenceHelper with its * associated performance overheads, consequently it should * be use sparingly @@ -1876,9 +1769,10 @@ WorkbookSettings getSettings() * @param loc the cell to retrieve * @return the cell at the specified location */ + @Override public WritableCell getWritableCell(String loc) { - WritableSheet s = getSheet(CellReferenceHelper.getSheet(loc)); + WritableSheet s = getSheet(CellReferenceHelper.getSheet(loc)); return s.getWritableCell(loc); } @@ -1891,6 +1785,7 @@ public WritableCell getWritableCell(String loc) * @param sheet the sheet (from another workbook) to merge into this one * @return the new sheet */ + @Override public WritableSheet importSheet(String name, int index, Sheet sheet) { WritableSheet ws = createSheet(name, index); diff --git a/src/jxl/write/biff/WriteAccessRecord.java b/src/jxl/write/biff/WriteAccessRecord.java index 28971f3..21ad686 100644 --- a/src/jxl/write/biff/WriteAccessRecord.java +++ b/src/jxl/write/biff/WriteAccessRecord.java @@ -56,7 +56,7 @@ public WriteAccessRecord(String userName) userName : authorString + " v" + Workbook.getVersion(); - StringHelper.getBytes(astring, data, 0); + StringHelper.getUnicodeBytes(astring, data, 0); // Pad out the record with space characters for (int i = astring.length() ; i < data.length ;i++) diff --git a/src/module-info.java b/src/module-info.java new file mode 100644 index 0000000..4eedd9d --- /dev/null +++ b/src/module-info.java @@ -0,0 +1,8 @@ +module Jxl { + requires java.logging; + + exports jxl; + exports jxl.read.biff; + exports jxl.write; + exports jxl.write.biff; +} diff --git a/test/jxl/DateCellTest.java b/test/jxl/DateCellTest.java new file mode 100644 index 0000000..6d741f3 --- /dev/null +++ b/test/jxl/DateCellTest.java @@ -0,0 +1,64 @@ +package jxl; + +import java.io.IOException; +import java.nio.file.*; +import java.util.*; +import jxl.read.biff.BiffException; +import jxl.write.*; +import static org.junit.Assert.*; +import org.junit.Test; + +/** + * created 2015-08-26 + * @author jan + */ +public class DateCellTest { + + @Test + public void testDateWritingAndRewriting() throws IOException, WriteException, BiffException { + Date summer = new GregorianCalendar(2015, 8, 26, 17, 15, 39).getTime(); + Date winter = new GregorianCalendar(2015, 1, 26, 17, 15, 39).getTime(); + Path file = Files.createTempFile("test_", ".xls"); + try (WritableWorkbook wb = Workbook.createWorkbook(file)) { + WritableSheet sheet = wb.createSheet("test", 0); + sheet.addCell(new DateTime(0, 0, summer, new WritableCellFormat(DateFormats.FORMAT9))); + sheet.addCell(new DateTime(0, 1, winter, new WritableCellFormat(DateFormats.FORMAT9))); + wb.write(); + assertEquals(CellType.DATE, sheet.getCell(0, 0).getType()); + assertEquals(summer, ((DateCell) sheet.getCell(0, 0)).getDate()); + assertEquals(summer.toString(), sheet.getCell(0, 0).getContents()); + assertEquals(winter, ((DateCell) sheet.getCell(0, 1)).getDate()); + assertEquals(winter.toString(), sheet.getCell(0, 1).getContents()); + } + Path file2 = Files.createTempFile("test2_", ".xls"); + try (Workbook wb = Workbook.getWorkbook(file); + WritableWorkbook wwb = Workbook.createWorkbook(file2, wb)) { + { + Sheet sheet = wb.getSheet(0); + assertEquals(CellType.DATE, sheet.getCell(0, 0).getType()); + assertEquals(summer, ((DateCell) sheet.getCell(0, 0)).getDate()); + assertEquals("9/26/15 17:15", sheet.getCell(0, 0).getContents()); + assertEquals(winter, ((DateCell) sheet.getCell(0, 1)).getDate()); + assertEquals("2/26/15 17:15", sheet.getCell(0, 1).getContents()); + } + { + WritableSheet sheet = wwb.getSheet(0); + assertEquals(CellType.DATE, sheet.getCell(0, 0).getType()); + assertEquals(summer, ((DateCell) sheet.getCell(0, 0)).getDate()); + assertEquals(summer.toString(), sheet.getCell(0, 0).getContents()); + assertEquals(winter, ((DateCell) sheet.getCell(0, 1)).getDate()); + assertEquals(winter.toString(), sheet.getCell(0, 1).getContents()); + } + wwb.write(); + } + try (Workbook wb = Workbook.getWorkbook(file2)) { + Sheet sheet = wb.getSheet(0); + assertEquals(CellType.DATE, sheet.getCell(0, 0).getType()); + assertEquals(summer, ((DateCell) sheet.getCell(0, 0)).getDate()); + assertEquals("9/26/15 17:15", sheet.getCell(0, 0).getContents()); + assertEquals(winter, ((DateCell) sheet.getCell(0, 1)).getDate()); + assertEquals("2/26/15 17:15", sheet.getCell(0, 1).getContents()); + } + } + +} diff --git a/test/jxl/PrintAreaTest.java b/test/jxl/PrintAreaTest.java new file mode 100644 index 0000000..7dd2804 --- /dev/null +++ b/test/jxl/PrintAreaTest.java @@ -0,0 +1,126 @@ +package jxl; + +import java.io.*; +import java.net.*; +import java.nio.file.*; +import java.util.Arrays; +import java.util.stream.Stream; +import static jxl.Workbook.getWorkbook; +import jxl.read.biff.*; +import jxl.write.*; +import jxl.write.biff.RowsExceededException; +import static org.hamcrest.core.Is.is; +import static org.junit.Assert.assertThat; +import org.junit.Test; + +/** + * created 2021-01-30 + * @author jan + */ +public class PrintAreaTest { + + @Test + public void insertRow() throws IOException, BiffException, RowsExceededException { + Path source = Path.of(URI.create(getClass().getResource("/testdata/printArea.xls").toString())); + Path destination = Files.createTempFile("test", ".xls"); + try ( + Workbook wb = getWorkbook(source); + WritableWorkbook ww = Workbook.createWorkbook(destination, wb) + ) { + WritableSheet sheet = ww.getSheet(0); + assertThat(sheet.getSettings().getPrintArea().getTopLeft().getRow(), is(0)); + assertThat(sheet.getSettings().getPrintArea().getBottomRight().getRow(), is(1)); + sheet.insertRow(2); + assertThat(sheet.getSettings().getPrintArea().getTopLeft().getRow(), is(0)); + assertThat(sheet.getSettings().getPrintArea().getBottomRight().getRow(), is(1)); + sheet.insertRow(1); + assertThat(sheet.getSettings().getPrintArea().getTopLeft().getRow(), is(0)); + assertThat(sheet.getSettings().getPrintArea().getBottomRight().getRow(), is(2)); + sheet.insertRow(0); + assertThat(sheet.getSettings().getPrintArea().getTopLeft().getRow(), is(1)); + assertThat(sheet.getSettings().getPrintArea().getBottomRight().getRow(), is(3)); + + ww.write(); + } + Files.delete(destination); + } + + @Test + public void removeRow() throws IOException, BiffException, RowsExceededException { + Path source = Path.of(URI.create(getClass().getResource("/testdata/printArea.xls").toString())); + Path destination = Files.createTempFile("test", ".xls"); + try ( + Workbook wb = getWorkbook(source); + WritableWorkbook ww = Workbook.createWorkbook(destination, wb) + ) { + WritableSheet sheet = ww.getSheet(0); + assertThat(sheet.getSettings().getPrintArea().getTopLeft().getRow(), is(0)); + assertThat(sheet.getSettings().getPrintArea().getBottomRight().getRow(), is(1)); + sheet.removeRow(2); + assertThat(sheet.getSettings().getPrintArea().getTopLeft().getRow(), is(0)); + assertThat(sheet.getSettings().getPrintArea().getBottomRight().getRow(), is(1)); + sheet.removeRow(1); + assertThat(sheet.getSettings().getPrintArea().getTopLeft().getRow(), is(0)); + assertThat(sheet.getSettings().getPrintArea().getBottomRight().getRow(), is(0)); + sheet.removeRow(0); + assertThat(sheet.getSettings().getPrintArea().getTopLeft().getRow(), is(0)); + assertThat(sheet.getSettings().getPrintArea().getBottomRight().getRow(), is(0)); + + ww.write(); + } + Files.delete(destination); + } + + @Test + public void insertColumn() throws IOException, BiffException, RowsExceededException { + Path source = Path.of(URI.create(getClass().getResource("/testdata/printArea.xls").toString())); + Path destination = Files.createTempFile("test", ".xls"); + try ( + Workbook wb = getWorkbook(source); + WritableWorkbook ww = Workbook.createWorkbook(destination, wb) + ) { + WritableSheet sheet = ww.getSheet(0); + assertThat(sheet.getSettings().getPrintArea().getTopLeft().getColumn(), is(0)); + assertThat(sheet.getSettings().getPrintArea().getBottomRight().getColumn(), is(1)); + sheet.insertColumn(2); + assertThat(sheet.getSettings().getPrintArea().getTopLeft().getColumn(), is(0)); + assertThat(sheet.getSettings().getPrintArea().getBottomRight().getColumn(), is(1)); + sheet.insertColumn(1); + assertThat(sheet.getSettings().getPrintArea().getTopLeft().getColumn(), is(0)); + assertThat(sheet.getSettings().getPrintArea().getBottomRight().getColumn(), is(2)); + sheet.insertColumn(0); + assertThat(sheet.getSettings().getPrintArea().getTopLeft().getColumn(), is(1)); + assertThat(sheet.getSettings().getPrintArea().getBottomRight().getColumn(), is(3)); + + ww.write(); + } + Files.delete(destination); + } + + @Test + public void removeColumn() throws IOException, BiffException, RowsExceededException { + Path source = Path.of(URI.create(getClass().getResource("/testdata/printArea.xls").toString())); + Path destination = Files.createTempFile("test", ".xls"); + try ( + Workbook wb = getWorkbook(source); + WritableWorkbook ww = Workbook.createWorkbook(destination, wb) + ) { + WritableSheet sheet = ww.getSheet(0); + assertThat(sheet.getSettings().getPrintArea().getTopLeft().getColumn(), is(0)); + assertThat(sheet.getSettings().getPrintArea().getBottomRight().getColumn(), is(1)); + sheet.removeColumn(2); + assertThat(sheet.getSettings().getPrintArea().getTopLeft().getColumn(), is(0)); + assertThat(sheet.getSettings().getPrintArea().getBottomRight().getColumn(), is(1)); + sheet.removeColumn(1); + assertThat(sheet.getSettings().getPrintArea().getTopLeft().getColumn(), is(0)); + assertThat(sheet.getSettings().getPrintArea().getBottomRight().getColumn(), is(0)); + sheet.removeColumn(0); + assertThat(sheet.getSettings().getPrintArea().getTopLeft().getColumn(), is(0)); + assertThat(sheet.getSettings().getPrintArea().getBottomRight().getColumn(), is(0)); + + ww.write(); + } + Files.delete(destination); + } + +} diff --git a/test/jxl/RangeNameOrderTest.java b/test/jxl/RangeNameOrderTest.java new file mode 100644 index 0000000..0a7fa5a --- /dev/null +++ b/test/jxl/RangeNameOrderTest.java @@ -0,0 +1,50 @@ + +package jxl; + +import java.io.IOException; +import java.net.URI; +import java.nio.file.*; +import java.util.List; +import static java.util.stream.Collectors.toList; +import static jxl.Workbook.getWorkbook; +import jxl.read.biff.*; +import jxl.write.*; +import static org.junit.Assert.*; +import org.junit.Test; + +/** + * created 08.07.2021 + * @author jan + */ +public class RangeNameOrderTest { + + @Test + public void afterWriting_RecordNameOrderIsSame() throws IOException, BiffException { + Path origRangeNameWithPrintArea = Path.of(URI.create(getClass().getResource("/testdata/printAreaAndNamedRanges.xls").toString())); + Path tempFile = Files.createTempFile("test", ".xls"); + List origRecordNames; + try (Workbook wb = getWorkbook(origRangeNameWithPrintArea); + WritableWorkbook ww = Workbook.createWorkbook(tempFile, wb)) { + origRecordNames = recordNames((WorkbookParser) wb); + ww.write(); + } + + List writtenRecordNames; + try (Workbook wb = getWorkbook(tempFile)) { + writtenRecordNames = recordNames((WorkbookParser) wb); + } + + // the ranges are referenced in formulas as index in the name table + // so the order have to be stable within reading and writing + // even in respect of print area. + assertEquals(origRecordNames, writtenRecordNames); + Files.delete(tempFile); + } + + private List recordNames(WorkbookParser wb) { + return wb.getNameRecords().stream() + .map(record -> record.getName() == null ? record.getBuiltInName().getName() : record.getName()) + .collect(toList()); + } + +} diff --git a/test/jxl/biff/EncodedURLHelperTest.java b/test/jxl/biff/EncodedURLHelperTest.java new file mode 100644 index 0000000..16160d7 --- /dev/null +++ b/test/jxl/biff/EncodedURLHelperTest.java @@ -0,0 +1,46 @@ +package jxl.biff; + +import jxl.*; +import static jxl.biff.EncodedURLHelper.getEncodedURL; +import org.junit.Test; +import static org.junit.Assert.*; +import static org.hamcrest.core.Is.is; + +/** + * 2019-12-23 + * @author jan + */ +public class EncodedURLHelperTest { + + @Test + public void testBiff4W_Biff8Encoding() { + assertThat(getEncodedURL("[ext.xls]Sheet1", new WorkbookSettings()), is(convertFileName("\01[ext.xls]Sheet1"))); + assertThat(getEncodedURL("sub\\[ext.xls]Sheet1", new WorkbookSettings()), is(convertFileName("\01sub\03[ext.xls]Sheet1"))); + assertThat(getEncodedURL("\\[ext.xls]Sheet1", new WorkbookSettings()), is(convertFileName("\01\02[ext.xls]Sheet1"))); + assertThat(getEncodedURL("\\sub\\[ext.xls]Sheet1", new WorkbookSettings()), is(convertFileName("\01\02sub\03[ext.xls]Sheet1"))); + assertThat(getEncodedURL("\\sub\\sub2\\[ext.xls]Sheet1", new WorkbookSettings()), is(convertFileName("\01\02sub\03sub2\03[ext.xls]Sheet1"))); + assertThat(getEncodedURL("..\\sub\\[ext.xls]Sheet1", new WorkbookSettings()), is(convertFileName("\01\04sub\03[ext.xls]Sheet1"))); + assertThat(getEncodedURL("D:\\sub\\[ext.xls]Sheet1", new WorkbookSettings()), is(convertFileName("\01\01Dsub\03[ext.xls]Sheet1"))); + assertThat(getEncodedURL("D:sub\\[ext.xls]Sheet1", new WorkbookSettings()), is(convertFileName("\01\01Dsub\03[ext.xls]Sheet1"))); + assertThat(getEncodedURL("\\\\pc\\sub\\[ext.xls]Sheet1", new WorkbookSettings()), is(convertFileName("\01\01@pc\03sub\03[ext.xls]Sheet1"))); + assertThat(getEncodedURL("http://www.example.org/[ext.xls]Sheet1", new WorkbookSettings()), is(convertFileName("\01\05\u0026http://www.example.org/[ext.xls]Sheet1"))); + } + + @Test + public void testBiff2_Biff4Encoding() { + assertThat(getEncodedURL("ext.xls", new WorkbookSettings()), is(convertFileName("\01ext.xls"))); + assertThat(getEncodedURL("sub\\ext.xls", new WorkbookSettings()), is(convertFileName("\01sub\03ext.xls"))); + assertThat(getEncodedURL("\\ext.xls", new WorkbookSettings()), is(convertFileName("\01\02ext.xls"))); + assertThat(getEncodedURL("\\sub\\ext.xls", new WorkbookSettings()), is(convertFileName("\01\02sub\03ext.xls"))); + assertThat(getEncodedURL("\\sub\\sub2\\ext.xls", new WorkbookSettings()), is(convertFileName("\01\02sub\03sub2\03ext.xls"))); + assertThat(getEncodedURL("..\\sub\\ext.xls", new WorkbookSettings()), is(convertFileName("\01\04sub\03ext.xls"))); + assertThat(getEncodedURL("D:\\sub\\ext.xls", new WorkbookSettings()), is(convertFileName("\01\01Dsub\03ext.xls"))); + assertThat(getEncodedURL("\\\\pc\\sub\\ext.xls", new WorkbookSettings()), is(convertFileName("\01\01@pc\03sub\03ext.xls"))); + assertThat(getEncodedURL("http://www.example.org/ext.xls", new WorkbookSettings()), is(convertFileName("\01\05\u001ehttp://www.example.org/ext.xls"))); + } + + private byte[] convertFileName(String filename) { + return filename.substring(1).getBytes(); + } + +} diff --git a/test/jxl/biff/StringHelperTest.java b/test/jxl/biff/StringHelperTest.java new file mode 100644 index 0000000..c049c49 --- /dev/null +++ b/test/jxl/biff/StringHelperTest.java @@ -0,0 +1,119 @@ +package jxl.biff; + +import java.io.*; +import java.net.*; +import java.nio.file.*; +import jxl.*; +import static jxl.Workbook.getWorkbook; +import jxl.biff.formula.*; +import jxl.read.biff.*; +import jxl.write.*; +import static org.hamcrest.core.Is.is; +import org.junit.Test; +import static org.junit.Assert.*; + +/** + * created 2020-05-22 + * @author jan + */ +public class StringHelperTest { + + @Test + public void testReadingOfBiff8String() { + int[] öĂ = new int[] { + 2, 0, // length + 1, // uncompressed + 0xf6, 0, // ö + 2, 1 // Ă + }; + + assertThat(StringHelper.readBiff8String(toBytes(öĂ)), is("öĂ")); + } + + @Test + public void testReadingOfCompressedBiff8String() { + int[] öäüß = new int[] { + 4, 0, // length + 0, // compressed + 0xf6, // ö + 0xe4, // ä + 0xfc, // ü + 0xdf // ß + }; + + assertThat(StringHelper.readBiff8String(toBytes(öäüß)), is("öäüß")); + } + + @Test + public void testReadingOfShortBiff8String() { + int[] öĂ = new int[] { + 1, // uncompressed + 0xf6, 0, // ö + 2, 1 // Ă + }; + + assertThat(StringHelper.readShortBiff8String(toBytes(öĂ)), is("öĂ")); + } + + @Test + public void testReadingOfShortCompressedBiff8String() { + int[] öäüß = new int[] { + 0, // compressed + 0xf6, // ö + 0xe4, // ä + 0xfc, // ü + 0xdf // ß + }; + + assertThat(StringHelper.readShortBiff8String(toBytes(öäüß)), is("öäüß")); + } + + private byte[] toBytes(int[] ints) { + byte[] bytes = new byte[ints.length]; + for (var i = 0; i < ints.length; i++) + bytes[i] = (byte) ints[i]; + + return bytes; + } + + @Test + public void testUtf16InComments() throws IOException, BiffException { + Path source = Path.of(URI.create(getClass().getResource("/testdata/utf16InComments.xls").toString())); + Path destination = Files.createTempFile("test", ".xls"); + try ( + Workbook wb = getWorkbook(source); + WritableWorkbook ww = Workbook.createWorkbook(destination, wb) + ) { + Sheet s = wb.getSheet(0); + assertThat(s.getCell(0, 0).getCellFeatures().getComment(), is("äöüß")); + assertThat(s.getCell(0, 1).getCellFeatures().getComment(), is("Ă")); + + ww.write(); + WritableSheet ws = ww.getSheet(0); + assertThat(ws.getCell(0, 0).getCellFeatures().getComment(), is("äöüß")); + assertThat(ws.getCell(0, 1).getCellFeatures().getComment(), is("Ă")); + } + Files.delete(destination); + } + + @Test + public void testUft16InFormulas() throws IOException, BiffException, FormulaException { + Path source = Path.of(URI.create(getClass().getResource("/testdata/utf16InFormulas.xls").toString())); + Path destination = Files.createTempFile("test", ".xls"); + try ( + Workbook wb = getWorkbook(source); + WritableWorkbook ww = Workbook.createWorkbook(destination, wb) + ) { + Sheet s = wb.getSheet(0); + assertThat(((StringFormulaCell) s.getCell(0, 0)).getString(), is("öäüß")); + assertThat(((StringFormulaCell) s.getCell(0, 1)).getString(), is("Ă")); + + ww.write(); + WritableSheet ws = ww.getSheet(0); + assertThat(((StringFormulaCell) ws.getCell(0, 0)).getString(), is("öäüß")); + assertThat(((StringFormulaCell) ws.getCell(0, 1)).getString(), is("Ă")); + } + Files.delete(destination); + } + +} diff --git a/test/jxl/biff/formula/TokenTest.java b/test/jxl/biff/formula/TokenTest.java new file mode 100644 index 0000000..80138d2 --- /dev/null +++ b/test/jxl/biff/formula/TokenTest.java @@ -0,0 +1,145 @@ +package jxl.biff.formula; + +import static jxl.biff.formula.Token.*; +import org.junit.Test; +import static org.junit.Assert.*; + +/** + * + * @author jan + */ +public class TokenTest { + + @Test + public void testPresentsOfAllDocumented() { + assertEquals(UNKNOWN, Token.getToken((byte) 0x00)); + assertEquals(EXP, Token.getToken((byte) 0x01)); + assertEquals(TBL, Token.getToken((byte) 0x02)); + assertEquals(ADD, Token.getToken((byte) 0x03)); + assertEquals(SUBTRACT, Token.getToken((byte) 0x04)); + assertEquals(MULTIPLY, Token.getToken((byte) 0x05)); + assertEquals(DIVIDE, Token.getToken((byte) 0x06)); + assertEquals(POWER, Token.getToken((byte) 0x07)); + assertEquals(CONCAT, Token.getToken((byte) 0x08)); + assertEquals(LESS_THAN, Token.getToken((byte) 0x09)); + assertEquals(LESS_EQUAL, Token.getToken((byte) 0x0A)); + assertEquals(EQUAL, Token.getToken((byte) 0x0B)); + assertEquals(GREATER_EQUAL, Token.getToken((byte) 0x0C)); + assertEquals(GREATER_THAN, Token.getToken((byte) 0x0D)); + assertEquals(NOT_EQUAL, Token.getToken((byte) 0x0E)); + assertEquals(INTERSECTION, Token.getToken((byte) 0x0F)); + assertEquals(UNION, Token.getToken((byte) 0x10)); + assertEquals(RANGE, Token.getToken((byte) 0x11)); + assertEquals(UNARY_PLUS, Token.getToken((byte) 0x12)); + assertEquals(UNARY_MINUS, Token.getToken((byte) 0x13)); + assertEquals(PERCENT, Token.getToken((byte) 0x14)); + assertEquals(PARENTHESIS, Token.getToken((byte) 0x15)); + assertEquals(MISSING_ARG, Token.getToken((byte) 0x16)); + assertEquals(STRING, Token.getToken((byte) 0x17)); + assertEquals(NLR, Token.getToken((byte) 0x18)); + assertEquals(ATTRIBUTE, Token.getToken((byte) 0x19)); + assertEquals(SHEET, Token.getToken((byte) 0x1A)); + assertEquals(END_SHEET, Token.getToken((byte) 0x1B)); + assertEquals(ERR, Token.getToken((byte) 0x1C)); + assertEquals(BOOL, Token.getToken((byte) 0x1D)); + assertEquals(INTEGER, Token.getToken((byte) 0x1E)); + assertEquals(DOUBLE, Token.getToken((byte) 0x1F)); + assertEquals(ARRAY, Token.getToken((byte) 0x20)); + assertEquals(FUNCTION, Token.getToken((byte) 0x21)); + assertEquals(FUNCTIONVARARG, Token.getToken((byte) 0x22)); + assertEquals(NAME, Token.getToken((byte) 0x23)); + assertEquals(REF, Token.getToken((byte) 0x24)); + assertEquals(AREA, Token.getToken((byte) 0x25)); + assertEquals(MEM_AREA, Token.getToken((byte) 0x26)); + assertEquals(MEM_ERR, Token.getToken((byte) 0x27)); + assertEquals(MEM_NO_MEM, Token.getToken((byte) 0x28)); + assertEquals(MEM_FUNC, Token.getToken((byte) 0x29)); + assertEquals(REFERR, Token.getToken((byte) 0x2A)); + assertEquals(AREA_ERR, Token.getToken((byte) 0x2B)); + assertEquals(REF_N, Token.getToken((byte) 0x2C)); + assertEquals(AREA_N, Token.getToken((byte) 0x2D)); + assertEquals(MEM_AREA_N, Token.getToken((byte) 0x2E)); + assertEquals(MEM_NO_MEM_N, Token.getToken((byte) 0x2F)); + assertEquals(UNKNOWN, Token.getToken((byte) 0x30)); + assertEquals(UNKNOWN, Token.getToken((byte) 0x31)); + assertEquals(UNKNOWN, Token.getToken((byte) 0x32)); + assertEquals(UNKNOWN, Token.getToken((byte) 0x33)); + assertEquals(UNKNOWN, Token.getToken((byte) 0x34)); + assertEquals(UNKNOWN, Token.getToken((byte) 0x35)); + assertEquals(UNKNOWN, Token.getToken((byte) 0x36)); + assertEquals(UNKNOWN, Token.getToken((byte) 0x37)); + assertEquals(MACROCOMMAND, Token.getToken((byte) 0x38)); + assertEquals(NAME_X, Token.getToken((byte) 0x39)); + assertEquals(REF3D, Token.getToken((byte) 0x3A)); + assertEquals(AREA3D, Token.getToken((byte) 0x3B)); + assertEquals(REF_ERR_3D, Token.getToken((byte) 0x3C)); + assertEquals(AREA_ERR_3D, Token.getToken((byte) 0x3D)); + assertEquals(UNKNOWN, Token.getToken((byte) 0x3E)); + assertEquals(UNKNOWN, Token.getToken((byte) 0x3F)); + assertEquals(ARRAY, Token.getToken((byte) 0x40)); + assertEquals(FUNCTION, Token.getToken((byte) 0x41)); + assertEquals(FUNCTIONVARARG, Token.getToken((byte) 0x42)); + assertEquals(NAME, Token.getToken((byte) 0x43)); + assertEquals(REF, Token.getToken((byte) 0x44)); + assertEquals(AREA, Token.getToken((byte) 0x45)); + assertEquals(MEM_AREA, Token.getToken((byte) 0x46)); + assertEquals(MEM_ERR, Token.getToken((byte) 0x47)); + assertEquals(MEM_NO_MEM, Token.getToken((byte) 0x48)); + assertEquals(MEM_FUNC, Token.getToken((byte) 0x49)); + assertEquals(REFERR, Token.getToken((byte) 0x4A)); + assertEquals(AREA_ERR, Token.getToken((byte) 0x4B)); + assertEquals(REF_N, Token.getToken((byte) 0x4C)); + assertEquals(AREA_N, Token.getToken((byte) 0x4D)); + assertEquals(MEM_AREA_N, Token.getToken((byte) 0x4E)); + assertEquals(MEM_NO_MEM_N, Token.getToken((byte) 0x4F)); + assertEquals(UNKNOWN, Token.getToken((byte) 0x50)); + assertEquals(UNKNOWN, Token.getToken((byte) 0x51)); + assertEquals(UNKNOWN, Token.getToken((byte) 0x52)); + assertEquals(UNKNOWN, Token.getToken((byte) 0x53)); + assertEquals(UNKNOWN, Token.getToken((byte) 0x54)); + assertEquals(UNKNOWN, Token.getToken((byte) 0x55)); + assertEquals(UNKNOWN, Token.getToken((byte) 0x56)); + assertEquals(UNKNOWN, Token.getToken((byte) 0x57)); + assertEquals(MACROCOMMAND, Token.getToken((byte) 0x58)); + assertEquals(NAME_X, Token.getToken((byte) 0x59)); + assertEquals(REF3D, Token.getToken((byte) 0x5A)); + assertEquals(AREA3D, Token.getToken((byte) 0x5B)); + assertEquals(REF_ERR_3D, Token.getToken((byte) 0x5C)); + assertEquals(AREA_ERR_3D, Token.getToken((byte) 0x5D)); + assertEquals(UNKNOWN, Token.getToken((byte) 0x5E)); + assertEquals(UNKNOWN, Token.getToken((byte) 0x5F)); + assertEquals(ARRAY, Token.getToken((byte) 0x60)); + assertEquals(FUNCTION, Token.getToken((byte) 0x61)); + assertEquals(FUNCTIONVARARG, Token.getToken((byte) 0x62)); + assertEquals(NAME, Token.getToken((byte) 0x63)); + assertEquals(REF, Token.getToken((byte) 0x64)); + assertEquals(AREA, Token.getToken((byte) 0x65)); + assertEquals(MEM_AREA, Token.getToken((byte) 0x66)); + assertEquals(MEM_ERR, Token.getToken((byte) 0x67)); + assertEquals(MEM_NO_MEM, Token.getToken((byte) 0x68)); + assertEquals(MEM_FUNC, Token.getToken((byte) 0x69)); + assertEquals(REFERR, Token.getToken((byte) 0x6A)); + assertEquals(AREA_ERR, Token.getToken((byte) 0x6B)); + assertEquals(REF_N, Token.getToken((byte) 0x6C)); + assertEquals(AREA_N, Token.getToken((byte) 0x6D)); + assertEquals(MEM_AREA_N, Token.getToken((byte) 0x6E)); + assertEquals(MEM_NO_MEM_N, Token.getToken((byte) 0x6F)); + assertEquals(UNKNOWN, Token.getToken((byte) 0x70)); + assertEquals(UNKNOWN, Token.getToken((byte) 0x71)); + assertEquals(UNKNOWN, Token.getToken((byte) 0x72)); + assertEquals(UNKNOWN, Token.getToken((byte) 0x73)); + assertEquals(UNKNOWN, Token.getToken((byte) 0x74)); + assertEquals(UNKNOWN, Token.getToken((byte) 0x75)); + assertEquals(UNKNOWN, Token.getToken((byte) 0x76)); + assertEquals(UNKNOWN, Token.getToken((byte) 0x77)); + assertEquals(MACROCOMMAND, Token.getToken((byte) 0x78)); + assertEquals(NAME_X, Token.getToken((byte) 0x79)); + assertEquals(REF3D, Token.getToken((byte) 0x7A)); + assertEquals(AREA3D, Token.getToken((byte) 0x7B)); + assertEquals(REF_ERR_3D, Token.getToken((byte) 0x7C)); + assertEquals(AREA_ERR_3D, Token.getToken((byte) 0x7D)); + assertEquals(UNKNOWN, Token.getToken((byte) 0x7E)); + assertEquals(UNKNOWN, Token.getToken((byte) 0x7F)); + } + +} diff --git a/test/jxl/read/biff/HorizontalPageBreaksRecordTest.java b/test/jxl/read/biff/HorizontalPageBreaksRecordTest.java new file mode 100644 index 0000000..c6fd171 --- /dev/null +++ b/test/jxl/read/biff/HorizontalPageBreaksRecordTest.java @@ -0,0 +1,37 @@ +package jxl.read.biff; + +import static jxl.biff.Type.HORIZONTALPAGEBREAKS; +import static jxl.read.biff.HorizontalPageBreaksRecord.biff7; +import static org.junit.Assert.*; +import org.junit.Test; + +/** + * created 2015-03-08 + * @author Jan Schlößin + */ +public class HorizontalPageBreaksRecordTest { + + public static final Record biff8HorizontalPageBreakRecord = new TestRecord( + new byte[]{(byte) HORIZONTALPAGEBREAKS.value, 0, 14, 0}, + new byte[]{2, 0, 13, 0, 0, 0, (byte) 255, (byte) 255, 18, 0, 0, 0, (byte) 255, (byte) 255}); + public static final HorizontalPageBreaksRecord biff8pb = new HorizontalPageBreaksRecord(biff8HorizontalPageBreakRecord); + + @Test + public void testCreationFromBiff7() { + Record r = new TestRecord( + new byte[]{(byte) HORIZONTALPAGEBREAKS.value, 0, 14, 0}, + new byte[]{2, 0, 13, 0, 18, 0}); + HorizontalPageBreaksRecord pb = new HorizontalPageBreaksRecord(r, biff7); + assertEquals(2, pb.getRowBreaks().size()); + assertEquals(13, (int) pb.getRowBreaks().get(0)); + assertEquals(18, (int) pb.getRowBreaks().get(1)); + } + + @Test + public void testCreationFromBiff8() { + assertEquals(2, biff8pb.getRowBreaks().size()); + assertEquals(13, (int) biff8pb.getRowBreaks().get(0)); + assertEquals(18, (int) biff8pb.getRowBreaks().get(1)); + } + +} diff --git a/test/jxl/read/biff/TestRecord.java b/test/jxl/read/biff/TestRecord.java new file mode 100644 index 0000000..0895d94 --- /dev/null +++ b/test/jxl/read/biff/TestRecord.java @@ -0,0 +1,14 @@ + +package jxl.read.biff; + +/** + * created 08.03.2015 + * @author jan + */ +public class TestRecord extends Record { + + public TestRecord(byte [] header, byte [] data) { + super(header, data); + } + +} diff --git a/test/jxl/read/biff/VerticalPageBreaksRecordTest.java b/test/jxl/read/biff/VerticalPageBreaksRecordTest.java new file mode 100644 index 0000000..b9ea7d0 --- /dev/null +++ b/test/jxl/read/biff/VerticalPageBreaksRecordTest.java @@ -0,0 +1,37 @@ +package jxl.read.biff; + +import static jxl.biff.Type.VERTICALPAGEBREAKS; +import static jxl.read.biff.VerticalPageBreaksRecord.biff7; +import static org.junit.Assert.*; +import org.junit.Test; + +/** + * created 2015-03-08 + * @author Jan Schlößin + */ +public class VerticalPageBreaksRecordTest { + public static final Record biff8VerticalPageBreakRecord = new TestRecord( + new byte[]{(byte) VERTICALPAGEBREAKS.value, 0, 14, 0}, + new byte[]{2, 0, 2, 0, 0, 0, (byte) 255, (byte) 255, 8, 0, 0, 0, (byte) 255, (byte) 255}); + public static final VerticalPageBreaksRecord biff8pb = new VerticalPageBreaksRecord(biff8VerticalPageBreakRecord); + + @Test + public void testCreationFromBiff7() { + Record r = new TestRecord( + new byte[]{(byte) VERTICALPAGEBREAKS.value, 0, 14, 0}, + new byte[]{2, 0, 2, 0, 8, 0}); + VerticalPageBreaksRecord pb = new VerticalPageBreaksRecord(r, biff7); + + assertEquals(2, pb.getColumnBreaks().size()); + assertEquals(2, (int) pb.getColumnBreaks().get(0)); + assertEquals(8, (int) pb.getColumnBreaks().get(1)); + } + + @Test + public void testCreationFromBiff8() { + assertEquals(2, biff8pb.getColumnBreaks().size()); + assertEquals(2, (int) biff8pb.getColumnBreaks().get(0)); + assertEquals(8, (int) biff8pb.getColumnBreaks().get(1)); + } + +} diff --git a/test/jxl/write/biff/HorizontalPageBreaksRecordTest.java b/test/jxl/write/biff/HorizontalPageBreaksRecordTest.java new file mode 100644 index 0000000..910b3ac --- /dev/null +++ b/test/jxl/write/biff/HorizontalPageBreaksRecordTest.java @@ -0,0 +1,113 @@ +package jxl.write.biff; + +import java.io.IOException; +import java.nio.file.*; +import java.util.List; +import jxl.*; +import jxl.biff.FormattingRecords; +import static jxl.biff.Type.HORIZONTALPAGEBREAKS; +import jxl.read.biff.BiffException; +import static jxl.read.biff.HorizontalPageBreaksRecordTest.biff8pb; +import jxl.write.*; +import static org.junit.Assert.*; +import org.junit.Test; + +/** + * created 2015-03-08 + * @author Jan Schlößin + */ +public class HorizontalPageBreaksRecordTest { + + @Test + public void testCreationOfBiff8() { + int [] pageBreaks = new int[] {13, 18}; + HorizontalPageBreaksRecord wpb = new HorizontalPageBreaksRecord(); + wpb.setRowBreaks(biff8pb); + assertArrayEquals(new byte[]{(byte) HORIZONTALPAGEBREAKS.value, 0, 14, 0, 2, 0, 13, 0, 0, 0, (byte) 255, (byte) 255, 18, 0, 0, 0, (byte) 255, (byte) 255}, + wpb.getBytes()); + } + + @Test + public void testInsertionOfRowBreaks() { + WritableSheetImpl w = new WritableSheetImpl("a", null, null, null, null, null); + assertTrue(w.getRowPageBreaks().getRowBreaks().isEmpty()); + w.addRowPageBreak(5); + assertEquals(5, (int) w.getRowPageBreaks().getRowBreaks().get(0)); + } + + @Test + public void testDoubleInsertionOfRowBreaks() { + WritableSheetImpl w = new WritableSheetImpl("a", null, null, null, null, null); + w.addRowPageBreak(5); + assertEquals(1, w.getRowPageBreaks().getRowBreaks().size()); + w.addRowPageBreak(5); + assertEquals(1, w.getRowPageBreaks().getRowBreaks().size()); + } + + @Test + public void testInsertionOfRow() throws WriteException, IOException { + WritableSheetImpl w = new WritableSheetImpl("[a]", null, new FormattingRecords(null), new SharedStrings(), new WorkbookSettings(), new WritableWorkbookImpl(Files.newOutputStream(Files.createTempFile(null, null)), true, new WorkbookSettings())); + w.addCell(new Blank(10, 10)); + w.addRowPageBreak(5); + w.addRowPageBreak(6); + w.insertRow(6); + assertArrayEquals(new Integer[] {5,7}, w.getRowPageBreaks().getRowBreaks().toArray()); + w.insertRow(0); + assertArrayEquals(new Integer[] {6,8}, w.getRowPageBreaks().getRowBreaks().toArray()); + } + + @Test + public void testRemovalOfRow() throws WriteException, IOException { + WritableSheetImpl w = new WritableSheetImpl("[a]", null, new FormattingRecords(null), new SharedStrings(), new WorkbookSettings(), new WritableWorkbookImpl(Files.newOutputStream(Files.createTempFile(null, null)), true, new WorkbookSettings())); + w.addCell(new Blank(10, 10)); + w.addRowPageBreak(6); + w.addRowPageBreak(8); + w.removeRow(0); + assertArrayEquals(new Integer[] {5,7}, w.getRowPageBreaks().getRowBreaks().toArray()); + w.removeRow(6); + assertArrayEquals(new Integer[] {5,6}, w.getRowPageBreaks().getRowBreaks().toArray()); + w.removeRow(6); + assertArrayEquals(new Integer[] {5}, w.getRowPageBreaks().getRowBreaks().toArray()); + } + + @Test + public void testIntegration_CopyOfWorkbookWithRowBreak() throws WriteException, IOException, BiffException { + Path tempSource = Files.createTempFile(null, ".xls"); + try (WritableWorkbook wwb = Workbook.createWorkbook(tempSource)) { + WritableSheet sheet = wwb.createSheet("test", 0); + sheet.addRowPageBreak(6); + wwb.write(); + } + Path tempDest = Files.createTempFile(null, ".xls"); + try (Workbook wb = Workbook.getWorkbook(tempSource); + WritableWorkbook wwb = Workbook.createWorkbook(tempDest, wb)) { + + List breaks = wwb.getSheet(0).getRowPageBreaks().getRowBreaks(); + assertEquals(1, breaks.size()); + assertEquals(6, breaks.get(0).intValue()); + + wwb.write(); + } + + Files.deleteIfExists(tempSource); + Files.deleteIfExists(tempDest); + } + + @Test + public void testIntegration_CopyOfWorkbookWithoutRowBreak() throws WriteException, IOException, BiffException { + Path tempSource = Files.createTempFile(null, ".xls"); + try (WritableWorkbook wwb = Workbook.createWorkbook(tempSource)) { + wwb.createSheet("test", 0); + wwb.write(); + } + Path tempDest = Files.createTempFile(null, ".xls"); + try (Workbook wb = Workbook.getWorkbook(tempSource); + WritableWorkbook wwb = Workbook.createWorkbook(tempDest, wb)) { + wwb.write(); + } + + Files.deleteIfExists(tempSource); + Files.deleteIfExists(tempDest); + } + +} diff --git a/test/jxl/write/biff/VerticalPageBreaksRecordTest.java b/test/jxl/write/biff/VerticalPageBreaksRecordTest.java new file mode 100644 index 0000000..6c9c92a --- /dev/null +++ b/test/jxl/write/biff/VerticalPageBreaksRecordTest.java @@ -0,0 +1,112 @@ +package jxl.write.biff; + +import java.io.IOException; +import java.nio.file.*; +import java.util.List; +import jxl.*; +import jxl.biff.FormattingRecords; +import static jxl.biff.Type.VERTICALPAGEBREAKS; +import jxl.read.biff.BiffException; +import static jxl.read.biff.VerticalPageBreaksRecordTest.biff8pb; +import jxl.write.*; +import static org.junit.Assert.*; +import org.junit.Test; + +/** + * created 2015-03-08 + * @author Jan Schlößin + */ +public class VerticalPageBreaksRecordTest { + + @Test + public void testCreationOfBiff8() { + VerticalPageBreaksRecord wpb = new VerticalPageBreaksRecord(); + wpb.setColumnBreaks(biff8pb); + assertArrayEquals(new byte[]{(byte) VERTICALPAGEBREAKS.value, 0, 14, 0, 2, 0, 2, 0, 0, 0, (byte) 255, (byte) 255, 8, 0, 0, 0, (byte) 255, (byte) 255}, + wpb.getBytes()); + } + + @Test + public void testInsertionOfColumnBreaks() { + WritableSheetImpl w = new WritableSheetImpl("a", null, null, null, null, null); + assertTrue(w.getColumnPageBreaks().getColumnBreaks().isEmpty()); + w.addColumnPageBreak(5); + assertEquals(5, (int) w.getColumnPageBreaks().getColumnBreaks().get(0)); + } + + @Test + public void testDoubleInsertionOfColumnBreaks() { + WritableSheetImpl w = new WritableSheetImpl("a", null, null, null, null, null); + w.addColumnPageBreak(5); + assertEquals(1, w.getColumnPageBreaks().getColumnBreaks().size()); + w.addColumnPageBreak(5); + assertEquals(1, w.getColumnPageBreaks().getColumnBreaks().size()); + } + + @Test + public void testInsertionOfColumn() throws WriteException, IOException { + WritableSheetImpl w = new WritableSheetImpl("[a]", null, new FormattingRecords(null), new SharedStrings(), new WorkbookSettings(), new WritableWorkbookImpl(Files.newOutputStream(Files.createTempFile(null, null)), true, new WorkbookSettings())); + w.addCell(new Blank(10, 10)); + w.addColumnPageBreak(5); + w.addColumnPageBreak(6); + w.insertColumn(6); + assertArrayEquals(new Integer[] {5,7}, w.getColumnPageBreaks().getColumnBreaks().toArray()); + w.insertColumn(0); + assertArrayEquals(new Integer[] {6,8}, w.getColumnPageBreaks().getColumnBreaks().toArray()); + } + + @Test + public void testRemovalOfColumn() throws WriteException, IOException { + WritableSheetImpl w = new WritableSheetImpl("[a]", null, new FormattingRecords(null), new SharedStrings(), new WorkbookSettings(), new WritableWorkbookImpl(Files.newOutputStream(Files.createTempFile(null, null)), true, new WorkbookSettings())); + w.addCell(new Blank(10, 10)); + w.addColumnPageBreak(6); + w.addColumnPageBreak(8); + w.removeColumn(0); + assertArrayEquals(new Integer[] {5,7}, w.getColumnPageBreaks().getColumnBreaks().toArray()); + w.removeColumn(6); + assertArrayEquals(new Integer[] {5,6}, w.getColumnPageBreaks().getColumnBreaks().toArray()); + w.removeColumn(6); + assertArrayEquals(new Integer[] {5}, w.getColumnPageBreaks().getColumnBreaks().toArray()); + } + + @Test + public void testIntegration_CopyOfWorkbookWithColumnBreak() throws WriteException, IOException, BiffException { + Path tempSource = Files.createTempFile(null, ".xls"); + try (WritableWorkbook wwb = Workbook.createWorkbook(tempSource)) { + WritableSheet sheet = wwb.createSheet("test", 0); + sheet.addColumnPageBreak(6); + wwb.write(); + } + Path tempDest = Files.createTempFile(null, ".xls"); + try (Workbook wb = Workbook.getWorkbook(tempSource); + WritableWorkbook wwb = Workbook.createWorkbook(tempDest, wb)) { + + List breaks = wwb.getSheet(0).getColumnPageBreaks().getColumnBreaks(); + assertEquals(1, breaks.size()); + assertEquals(6, breaks.get(0).intValue()); + + wwb.write(); + } + + Files.deleteIfExists(tempSource); + Files.deleteIfExists(tempDest); + } + + @Test + public void testIntegration_CopyOfWorkbookWithoutColumnBreak() throws WriteException, IOException, BiffException { + Path tempSource = Files.createTempFile(null, ".xls"); + try (WritableWorkbook wwb = Workbook.createWorkbook(tempSource)) { + wwb.createSheet("test", 0); + wwb.write(); + } + Path tempDest = Files.createTempFile(null, ".xls"); + try (Workbook wb = Workbook.getWorkbook(tempSource); + WritableWorkbook wwb = Workbook.createWorkbook(tempDest, wb)) { + wwb.write(); + } + + Files.deleteIfExists(tempSource); + Files.deleteIfExists(tempDest); + } + +} diff --git a/test/jxl/write/biff/WritableSheetImplTest.java b/test/jxl/write/biff/WritableSheetImplTest.java new file mode 100644 index 0000000..1196cb7 --- /dev/null +++ b/test/jxl/write/biff/WritableSheetImplTest.java @@ -0,0 +1,154 @@ +package jxl.write.biff; + +import java.io.IOException; +import java.nio.file.*; +import jxl.*; +import jxl.biff.EmptyCell; +import jxl.write.*; +import static org.hamcrest.core.Is.is; +import org.junit.*; +import static org.junit.Assert.*; + +/** + * created 2015-08-20 + * @author jan + */ +public class WritableSheetImplTest { + + private Path tempFile; + private WritableWorkbook workbook; + private WritableSheet sheet; + + @Before + public void setUp() throws IOException { + tempFile = Files.createTempFile(null, ".xls"); + workbook = Workbook.createWorkbook(tempFile); + sheet = workbook.createSheet("a", 0); + } + + @After + public void tearDown() throws IOException { + sheet = null; + workbook.write(); + workbook.close(); + workbook = null; + Files.delete(tempFile); + tempFile = null; + } + + @Test + public void testAddingAnEmptyCell() throws WriteException, IOException { + sheet.addCell(new Label(0, 0, "test")); + assertEquals("test", sheet.getCell(0, 0).getContents()); + sheet.addCell(new EmptyCell(0, 0)); + assertEquals(CellType.EMPTY, sheet.getCell(0, 0).getType()); + } + + @Test + public void addingALine_MovesFollowingCellsDown() throws IOException, WriteException { + Label label = new Label(0, 0, "content"); + sheet.addCell(label); + assertThat(label.getRow(), is(0)); + sheet.insertRow(0); + assertThat(label.getRow(), is(1)); + } + + @Test + public void addingALineInAnAlmostFullSheet_MovesCellsToTheLastRow() throws IOException, WriteException { + Label label = new Label(0, WritableSheetImpl.MAX_ROWS_PER_SHEET-2, "content"); + sheet.addCell(label); + assertThat(label.getRow(), is(WritableSheetImpl.MAX_ROWS_PER_SHEET-2)); + sheet.insertRow(0); + assertThat(label.getRow(), is(WritableSheetImpl.MAX_ROWS_PER_SHEET-1)); + } + + @Test + public void addingALine_DoesntTouchTheCellsAbove() throws IOException, WriteException { + Label label = new Label(0, 0, "content"); + sheet.addCell(label); + assertThat(label.getRow(), is(0)); + sheet.insertRow(1); + assertThat(label.getRow(), is(0)); + } + + @Test(expected = RowsExceededException.class) + public void addingALineToAFullSheet_ThrowsException() throws IOException, WriteException { + Label label = new Label(0, WritableSheetImpl.MAX_ROWS_PER_SHEET - 1, "content"); + sheet.addCell(label); + sheet.insertRow(0); + } + + @Test + public void removingALine_MovesFollowingCellsUp() throws IOException, WriteException { + Label label = new Label(0, 1, "content"); + sheet.addCell(label); + assertThat(label.getRow(), is(1)); + sheet.removeRow(0); + assertThat(label.getRow(), is(0)); + } + + @Test + public void removingALine_DoesntTouchTheCellsAbove() throws WriteException { + Label label = new Label(0, 0, "content"); + sheet.addCell(label); + assertThat(label.getRow(), is(0)); + sheet.addCell(new Label(0, 2, "beneath")); + sheet.removeRow(1); + assertThat(label.getRow(), is(0)); + } + + @Test + public void addingALine_MovesFollowingImagesDown() throws RowsExceededException, InterruptedException { + WritableImage image = new WritableImage(0, 0, 1, 1, new byte[] {}); + sheet.addImage(image); + assertThat(image.getY(), is(0d)); + sheet.insertRow(0); + assertThat(image.getY(), is(1d)); + } + + @Test + public void addingALine_AndAnImageIsAlmostAtTheBottom_MovesImagesDown() throws RowsExceededException { + WritableImage image = new WritableImage(0, WritableSheetImpl.MAX_ROWS_PER_SHEET - 3, 1, 1, new byte[] {}); + sheet.addImage(image); + assertThat(image.getY(), is(WritableSheetImpl.MAX_ROWS_PER_SHEET - 3d)); + sheet.insertRow(0); + assertThat(image.getY(), is(WritableSheetImpl.MAX_ROWS_PER_SHEET - 2d)); + } + + @Test + public void addingALine_DoesntTouchTheImagesAbove() throws IOException, WriteException { + WritableImage image = new WritableImage(0, 0, 1, 1, new byte[] {}); + sheet.addImage(image); + assertThat(image.getY(), is(0d)); + sheet.insertRow(1); + assertThat(image.getY(), is(0d)); + } + + @Test + public void addingALine_AndAnImageIsAtTheSheetBottom_TheImageWillNotBeMoved() throws RowsExceededException, WriteException { + WritableImage image = new WritableImage(0, WritableSheetImpl.MAX_ROWS_PER_SHEET - 2, 1, 1, new byte[] {}); + sheet.addImage(image); + assertThat(image.getY(), is(WritableSheetImpl.MAX_ROWS_PER_SHEET - 2d)); + sheet.insertRow(0); + assertThat(image.getY(), is(WritableSheetImpl.MAX_ROWS_PER_SHEET - 2d)); + } + + @Test + public void removingALine_MovesFollowingImagesUp() throws IOException, WriteException { + WritableImage image = new WritableImage(0, 1, 1, 1, new byte[] {}); + sheet.addImage(image); + assertThat(image.getY(), is(1d)); + sheet.removeRow(0); + assertThat(image.getY(), is(0d)); + } + + @Test + public void removingALine_DoesntTouchTheImagesAbove() throws WriteException { + WritableImage image = new WritableImage(0, 0, 1, 1, new byte[] {}); + sheet.addImage(image); + assertThat(image.getRow(), is(0d)); + sheet.removeRow(1); + assertThat(image.getRow(), is(0d)); + } + +} diff --git a/test/testdata/printArea.xls b/test/testdata/printArea.xls new file mode 100644 index 0000000..d2fcefb Binary files /dev/null and b/test/testdata/printArea.xls differ diff --git a/test/testdata/printAreaAndNamedRanges.xls b/test/testdata/printAreaAndNamedRanges.xls new file mode 100644 index 0000000..aca8b19 Binary files /dev/null and b/test/testdata/printAreaAndNamedRanges.xls differ diff --git a/test/testdata/utf16InComments.xls b/test/testdata/utf16InComments.xls new file mode 100644 index 0000000..4c64daa Binary files /dev/null and b/test/testdata/utf16InComments.xls differ diff --git a/test/testdata/utf16InFormulas.xls b/test/testdata/utf16InFormulas.xls new file mode 100644 index 0000000..c376e57 Binary files /dev/null and b/test/testdata/utf16InFormulas.xls differ