Spreadsheet-ParseExcel-0.66/ 000755 000765 000024 00000000000 14543415026 016012 5 ustar 00John staff 000000 000000 Spreadsheet-ParseExcel-0.66/Changes 000644 000765 000024 00000051512 14543414510 017306 0 ustar 00John staff 000000 000000 Revision history for Perl module Spreadsheet::ParseExcel.
0.66 December 29 2023
! Fix for CVE-2023-7101
https://github.com/runrig/spreadsheet-parseexcel/issues/33
0.65 March 15 2014
! Merge support for accessing hyperlink data
0.64 March 11 2014
! RT #47072 (ExcelLocaltime rounding)
http://rt.cpan.org/Public/Bug/Display.html?id=47072
! RT #93142 (date format w/commas)
http://rt.cpan.org/Public/Bug/Display.html?id=93142
! RT #93651 (Update metadata)
http://rt.cpan.org/Public/Bug/Display.html?id=93651
0.63 March 7 2014
! RT #12946 (IO::Wrap)
http://rt.cpan.org/Public/Bug/Display.html?id=12946
! RT #93065 (auto color)
http://rt.cpan.org/Public/Bug/Display.html?id=93065
0.62
! Fix test 46 skip_all plan logic.
From CPAN testers.
! RT #52830 (0x00 general fmt) && fix test.
http://rt.cpan.org/Public/Bug/Display.html?id=52830
! RT #93138 (undefined value as ARRAY)
http://rt.cpan.org/Public/Bug/Display.html?id=93138
0.61
! RT #93500 (Red Cell formats)
http://rt.cpan.org/Public/Bug/Display.html?id=93500
+ RT #93379 (tab color)
http://rt.cpan.org/Public/Bug/Display.html?id=93379
+ RT #93393 (active worksheet)
http://rt.cpan.org/Public/Bug/Display.html?id=93393
! Fix RT #93425 (color from workbook leaks)
http://rt.cpan.org/Public/Bug/Display.html?id=93425
+ RT #93367 (hidden rows/columns)
http://rt.cpan.org/Public/Bug/Display.html?id=93367
! Fix RT #93065 (black is white)
http://rt.cpan.org/Public/Bug/Display.html?id=93065
! Fix RT #62593 (?)(merge from apla/master).
http://rt.cpan.org/Public/Bug/Display.html?id=62593
0.60 February 26 2014
+ Fix RT #43250
http://rt.cpan.org/Public/Bug/Display.html?id=43250
0.59 April 6 2011
+ Patch for decryption of default encrypted workbooks from
Alexey Mazurin.
! Fix for invalid formatting of text cell that are numeric.
http://rt.cpan.org/Public/Bug/Display.html?id=62073
0.58 September 17 2010
! Fix for text cells formatted with a leading apostrophe.
http://rt.cpan.org/Public/Bug/Display.html?id=61299
! Documentation fixes. Thanks to Dan Dascalescu
Fix RT #61320 (typos)
http://rt.cpan.org/Public/Bug/Display.html?id=61320
! Fix for currency locales in format strings.
Reported by wjaguar.
http://rt.cpan.org/Public/Bug/Display.html?id=60547
! Fix for incomplete SETUP records.
Reported by M.C. Deurloo.
0.57 January 24 2010
! Added fix for reading formatted data from Excel 4 files.
! Added example programs, a_simple_parser.pl and
display_text_table.pl.
! Removed Build.PL from README. Thanks Ed Avis.
https://rt.cpan.org/Ticket/Display.html?id=52670
0.56 November 9 2009
+ Added error() and error_code() error handling routines.
This allows encrypted files to be ignored.
Added t/10_error_codes.t for the above methods.
http://rt.cpan.org/Public/Bug/Display.html?id=51033
http://rt.cpan.org/Public/Bug/Display.html?id=47978
! Made version 0.19 of OLE::Storage_Lite a prerequisite to avoid
issues when writing OLE header in SaveParser.
! Changed Parse() method name to parse() for consistency with the
rest of the API. The older method name is still supported but
not documented.
0.55 August 25 2009
+ Refactored Cell.pm documentation and method names and added
regression suite, t/06_regression.t.
! Added float comparison test to avoid false failing tests on
64bit systems.
0.54 August 25 2009
! Fix for height/width of hidden rows/columns with additional.
tests in 05_regression.t. Thanks to Greger Leijonhufvud.
http://rt.cpan.org/Public/Bug/Display.html?id=48450
! Fix for mal-formed Print_Title Name block.
Reported by Marc Elser.
0.53 August 24 2009
+ Made perl 5.8.0 a requirement for proper Unicode handling.
! Fixed minor int2col() bug thanks to David Black.
Added 28_int2col.t test for above.
http://rt.cpan.org/Public/Bug/Display.html?id=48967
+ Refactored Workbook API and docs.
0.52 August 21 2009
+ Added new FmtJapan module and tests written by Goro Fuji.
! Fixed bug in ExcelFmt() date handling where conversion to weekday
and month names wasn't handled correctly.
Add extra tests to 21_number_format_user.t for above.
! Fixed bug when checking $Config{useperlio}.
Reported by kbates and H.Merijn Brand.
http://rt.cpan.org/Public/Bug/Display.html?id=28861
! Fixed bug where CellHandler variables weren't scoped to package.
Reported by pomoxp.
http://rt.cpan.org/Public/Bug/Display.html?id=43250
+ Added tests for ExcelLocaltime() and LocaltimeExcel().
26_localtime2excel.t and 27_localtime2excel.t.
+ Refactored SaveParser docs. Work still ongoing.
0.51 August 19 2009
! Added fix for incorrectly skipped charts. Thanks Guntram Blohm.
https://rt.cpan.org/Ticket/Display.html?id=44009
! Added fix for locale [$-ddd] strings in number formats.
Reported by Jeff Mitchell.
https://rt.cpan.org/Ticket/Display.html?id=43638
! Added fix for multiple dots in number formats.
Thanks to Father Chrysostomos.
http://rt.cpan.org/Public/Bug/Display.html?id=45502
! Added fix to make half way rounding behave like Excel.
Thanks to Joshua Megerman.
http://rt.cpan.org/Public/Bug/Display.html?id=45626
! Added checks for valid dates in Utility::ExcelFmt.
Reported by Alan James.
http://rt.cpan.org/Public/Bug/Display.html?id=48831
0.50 August 18 2009
+ Refactored Worksheet interface and documentation.
Added 04_regression.t and 05_regression.t to test above changes.
! Fixed column units conversion.
Added 24_row_col_sizes.t for above change.
! Fixed RK number conversion. The existing code was the source of several
RT bugs and portability issues. Added 25_decode_rk_numbers.t testcase.
0.49 January 24 2009
! Added Text::CSV_XS to xls2csv() function to handle embedded commas
in csv data. Reported by Fredrik Linde.
http://rt.cpan.org/Public/Bug/Display.html?id=41337
+ Rewrote Utility.pm documentation.
- Removed wantarray from ExcelFmt() and the unused and undocumented
feature of returning the result and a format color in a list context.
The older mechanism is still available but now requires an explicit flag.
0.48 January 23 2009
! Fixed bug where numbers with uppercase formats such as MM/DD/YY
were ignored. Applies to files created by OpenOffice.org and
some international versions of Excel. Added tests for above.
http://rt.cpan.org/Public/Bug/Display.html?id=20526
http://rt.cpan.org/Public/Bug/Display.html?id=31206
http://rt.cpan.org/Public/Bug/Display.html?id=40307
! Removed undocumented and counter-intuitive use of overload on SheetNo in
Worksheet.pm.
http://rt.cpan.org/Public/Bug/Display.html?id=14278
0.47 January 22 2009
! Fixed bug where multiple embedded charts on a worksheet caused the
worksheet order to be lost and data to get overwritten.
Reported by Steven Martin and others.
http://rt.cpan.org/Public/Bug/Display.html?id=13365
0.46 January 18 2009
! Heavily refactored the ExcelFmt() function for maintainability and
fixed several bugs, in particular for 12 hour clock times.
Added test cases for above.
! Removed use of $& match variables from ExcelFmt.
Reported by Aaron Wigley.
http://rt.cpan.org/Public/Bug/Display.html?id=42425
! Replaced lvalue substr() in ExcelFmt () with 4-arg substr()
for efficiency. Reported by Goro Fuji.
http://rt.cpan.org/Public/Bug/Display.html?id=42518
! Removed spurious t/examples dir from Makefile.PL and removed
unused t/lib dir. Reported by Peter (Stig) Edwards.
http://rt.cpan.org/Public/Bug/Display.html?id=42442
0.45 January 13 2009
! Fixed failed parsing of large (8-16k) Unicode strings.
Reported by Graham Stead and Moka.
http://rt.cpan.org/Public/Bug/Display.html?id=41813
http://rt.cpan.org/Public/Bug/Display.html?id=35678
! Fixed critical bug where data rows could be ignored.
Reported and isolated by Peter (Stig) Edwards.
http://rt.cpan.org/Public/Bug/Display.html?id=30677
0.44 January 8 2009
! Fix for OpenOffice.org GENERAL format.
http://rt.cpan.org/Public/Bug/Display.html?id=7206
Thanks to Niko Tyni and the Debian Perl team
+ Perltidyed source and added standard headers and Pod sections
to all modules.
0.43 January 7 2009
+ Restructured and rewrote the main documentation. This is the start of
a general refactoring.
+ Added worksheets() Workbook method to iterate over the Worksheet objects.
+ Added unformatted() method to get a Cell's unformatted value.
+ Renamed public methods RowRange(), ColRange() and Cell() to row_range(),
col_range() and get_cell(). Old methods are still available.
! Turned on compatibility_mode() by default in SaveParser to avoid SP3
problems.
! Fixed minor SaveParser bug with font rotation.
http://rt.cpan.org/Public/Bug/Display.html?id=41626
0.42 January 1 2009
+ Fix for world writeable files in distro to allow PAUSE indexing.
0.41 October 24 2008
+ Changed maintainership to John McNamara.
! Fixed bug when parsing RK numbers (generally ints or small floats).
http://rt.cpan.org/Public/Bug/Display.html?id=39892
! Changed margin units to inches to (cleanly) avoid undef warning in
SaveParser.
0.33 2008.09.07
- Default format for formatted dates changed from 'm-d-yy' to 'yyyy-mm-dd'
- Numeric fields with date-formats now promote to Date
- Added docs about date type 14 problem
- skip another test when prereq is missing
- split Spreadsheet::ParseExcel::SaveParser into packages
- split Spreadsheet::ParseExcel into packages
0.32 2007.05.05
- Remove the memory_leak test as well as it still fails.
0.31 2007.05.03
- Require IO::Scalar always as OLE::Storage_Lite needs it but does not prereq it
- disable some of the tests that don't yet work on 64 bit due to number precision
in order to allow automatic installation
0.30 2007.03.31
- add some more tests
- add test to see memory leak using Proc::ProcessTable
- Start using Scalar::Util qw(weaken) to (hopefully) avoid memory leak
- It seems we did not check correctly if PERLIO is available in Makefile.PL
now it is the same test we do in the code itself.
- Flag1904 renamed to Flg1904 in documentation (Chad) RT #24293
0.29 2007.03.30
- clean up basic.t to skip tests that need additional and missing module
- No more need for IO::Scalar if PERLIO is available (H.Merijn Brand)
0.28 Wed Jan 7, 2007
- Documentation update
- Add t/parse.t
- Add sample/parse.pl
- fix some syntax errors in the sub-modules
0.27 Wed Jan 3, 2007
- See changes in the 0.27_XX versions
0.27_03 Thu Nov 2, 2006
- Officially receive maintainership (Gabor Szabo)
- slight code cleanup
- more sample test
0.27_02
- Fixing another warning:
Character in 'c' format wrapped in pack
http://rt.cpan.org/Ticket/Display.html?id=18063
(Grant Stevens)
- More test, enable use of Devel::Cover
0.27_01 Mon Sep 11, 2006
- Moving test.pl to t/ and using Test::More
- Add tests running (some of the) sample files
- Add 'use warnings', remove prototypes
- Fix the warning in Spreadsheet::ParseExcel::FmtDefault
Character in "C" format wrapped at .../Spreadsheet/ParseExcel/FmtDefault.pm line 68.
http://rt.cpan.org/Public/Bug/Display.html?id=7376
(Slaven Rezić and others)
0.2603 Mon May 30, 2004
- Mod SaveParser : Apply a path from Eduardo J
adding Protect feature
(Thank you, Eduardo J for patch)
- Mod ParseExcel : Apply a path from C. Jon Larsen
adding GetContent
(Thank you, C. Jon Larsen)
0.2602 Mon Jul 15, 2002
- Fix SaveParser : Mod hidden support(with 0 column width)
(Thank you, HIROSHIGE,Shigeru for report)
0.2601 Sat Jul 13, 2002
Thank you for Peter Marschall for PATCH.
- Mod ParseExcel : Add new methods
- Mod SaveParser : Add new methods
- Mod ParseExcel : Mod subHeader, subFooter
(Thank you, RT? for report)
- Mod SaveParser : Add hidden support
(Thank you, HIROSHIGE,Shigeru for report)
- Add new sample : Add dmpEx_2xml.pl
(Thank you, Khalid EZZARAOUI for new code)
0.26 Sat Jun 1, 2002
Thank you for Peter Marschall.
- Mod ParseExcel : Add new interface
- Mod SaveParser : Add new interface
0.25 Fri May 10, 2002
- Mod ParseExcel : Fix For SaveParser
- Mod SaveParser : Add Create
Add page setting
Add some documents
0.2407 Mon Apr 24, 2002
- Mod Utility : Fix Numeric format
(Thank you, Jeff Shaffer for report)
Fix MakeBun
- Mod ParseExcel : Fix Continue (COTINUE with no header)
(Thank you, Tuneyosi Fukusima for report)
: Add {Val} in sample :-)
(Thank you, Ernst Kloppenburg for suggestion)
0.2406 Mon Apr 8, 2002
- Mod Utility : Fix $sNUMEXP
(Thank you for Xavier Catteau for patch)
Add col2int int2col sheetRef xls2csv
(Thank you for Xavier Catteau for patch)
- Mod ParseExcel : Add file contents
- Mod SaveParser : Mod AddCell
0.2405 Tue Jan 29, 2002
- Mod FmtDefault : Fix 0x01 (='0') format
(Thank you Marc Pohl for report)
- Mod ParseExcel : Mod Parse Fh of CGI.pm and GLOB ref.
(Thank you Nicholas Hamlin and Abe Daisuke for reports)
Fix PrintArea detection
(Thank you Todd A. Green for patch)
Add custom palette support
(Thank you Florian Pflug for patch)
Fix _SetDimension prototype
(Thank you David Dyck for patch)
- Mod SaveParser : Mod return value of SaveParser
(Thank you Iceman for patch)
- Mod Utility : Mod $iAftP manipulation
(Thank you Stanislav Sukholet for patch)
0.2404 Tue Jul 24 7:30:00 2001 - Tue Dec 4 11:00:00 2001
- Mod ParseExcel : Mod _SwapForUnicode for a string with odd length
(Thank you, Mikhail Turenko)
: Add GLOB reference support
(Thank you, coral.)
: Fix/Add Font name Unicode judge
(Thank you, Mikhail Turenko, Alex Edelman)
- Mod Utility : Fix Backslash problem
(Thank you, Bruno Wolff III. And sorry for TOO LATE)
: Fix add number expressions
(Thank you, Jing Zhao)
0.2403 Tue Jul 24 7:30:00 2001
- Mod FmtUnicode, FmtJapan, FmtJapan2 : Fix NL
(Thank you, Jeremy Smartt)
0.2402 Thu Jul 12 20:30:00 2001
- Mod Utility, FmtDefault :Fix format error
(Thank you, Kevin Ko)
- Mod Utility :Mod for Japanese sign(triangle)
0.2401 Mon Jul 9 19:00:00 2001
- Mod FmtUnicode :Mod alphanumeric in BIG5
(Thank you, Kevin Ko)
Sorry, it is not effective (ToT)
0.24 Wed Jul 5 06:30:00 2001
- Mod ParseExcel :Add OO style callback
(Thank you, Ilya Sterin)
- Add sample/Ilya.pl :-)
- Mod ParseExcel : Mod use FmtDefault for PDK
(Thank you, Maxime Alechine)
0.2301 Tue Jun 26 8:00:00 2001
- Mod FmtDefault
:Fix not convert undefined or '' string
0.23 Thu Jun 21 21:00:00 2001
- Mod ParseExcel, FmtUnicode, FmtJapan, FmtJapan2 :
:Fix Unicode Latin1 adapt
(Thank you, Seiko Yamamura and Sadahiro)
- Mod ParseExcel : my(undef) -> my($undef1) ...
(Thank you, Alex)
0.22.3 Thu May 16 8:00:00 2001
- Mod FmtUnicode : Fix code undefined
- Mod ParseExcel : Fix Marged area (row>255)
(Thank you, Dmitriy Litovchin)
0.22.2 Thu May 16 8:00:00 2001
- Mod ParseExcel : Fix Hidden RowHeight, ColWidht
(Thank you, Maxim Ovchinnikov)
0.22.1 Wed May 14 20:35:00 2001
- Mod ParseExcel : Fix Continue (COTINUE with no header)
(Thank you, Steve Sapovits)
: Fix ignore Graph sheet
(Thank you, Joel Defarge )
- Mod Utility : Fix eval at Conditiona-Format
(Thank you, Alok K. Dhir)
0.22 Sat May 5 19:00:00 2001
- Add SaveParser : For DBD::Excel
0.21.2 Tue May 1 7:00:00 2001
- Fix ParseExcel : MergedArea
(Thank you, Bradley M. Handy )
0.21.1 Sat Apr 29 14:00:00 2001
- Add ParseExcel : Rich text information support
(Thank you, Vladimir Igrevsky)
0.21 Sat Apr 24 18:00:00 2001
- Mod ParseExcel : Add New Feature for CellHandler
(Thank you, Jeff Clark)
- Mod ParseExcel, FmtDefault, FmtJapan, Utility:
: Expanding format information to support
(Supported by Nippon-RAD OP Division)
0.20.2 Wed Apr 18 9:00:00 2001
- Fix Utility : ExcelFmt (For Number format)
(Thank you, Jeff Clark)
0.20.1 Sun Apr 11 9:00:00 2001
- Fix FmtJapan, FmtJapan2 : TxtFmt
- Fix FmtDefault : ValFmt (for 'String' format')
(Thank you, Fukusima, Tuneyosi)
0.20 Mon Mar 30 20:00:00 2001
- Fix ParseExcel.pm : RK int minus
(Thank you, Morten Sickel)
- Mod ParseExcel.pm : Fix Font number but not complete
(Thank you, Vladimir Igrevsky)
- Fix ParseExcel.pm : _convBIFF8 non conversion (LABEL, String...)
(Thank you, Fukusima, Tuneyosi)
- Add pod : Limitaion with Spreadsheet::WriteExcel.pm
(Thank you, Venkataramana Mokkapati)
0.19 Mon Mar 26 12:00:00 2001
- Fix Utility.pm :Month short name
(Thank you, Morten Sickel)
- Fix Utility.pm :Formatting Error
(Thank you, yusuf_najuddin)
- Fix FmtJapan2.pm: CP932Excel.map readable check
(Thank you, Kawasaki)
0.18 Sat Mar 18 16:00:00 2001
- Fix Excel4 file support
- Fix subLabel (Unicode)
(Thank you, yusuf_najmuddin)
0.17 Wed Mar 12 9:00:00 2001
- Fix Utility.pm for Number format
- Fix FmtJapan2.pm to use FmtJapan
(Thank you, Kawasaki)
- Fix Utility.pm for Number format (not Numeric)
(Thank you, John Dawson)
- Fix Format string with Chinese Character (in Excel95)
0.16 Wed Mar 7 22:00:00 2001
- Fix Format String
- Avoding warnings
(Thank you Jimmy Sieben and Daniel Berger)
0.15 Wed Mar 6 10:00:00 2001
- Fix RK number
(Thank you Jimmy Sieben)
- Modify many internal functions!!
- Add Spreadsheet::ParseExcel::Utity for formatting!
0.13 Sat Feb 21 20:40:00 2001
- Support Pps 'BOOK' (not 'Book') with OLE::Storage_Lite 0.07
(Thank you, Punam Chordia )
- Modify Makefile.PL (define OLE::Storage_Lite Version)
(Thank you, Aldo Calpini)
- Fix Conetinue ASCII-Unicode pattern
(Thank you, Tim Wills)
- Add FmtUnicode sample :dmpExU.pl (Sorry and thank you, Mike Goblin)
0.12 Sat Feb 5 11:00:00 2001
- Support Excel4 file (Thank you, Jeff Haferman and herbert )
- Add reference of scalar and IO::File object support in Parse
(Thank you, Jeff Haferman)
- Fix Continue SST (Thank you, Gennadiy)
- Delete VBAMacros from sample/Excel/Test97j.xls and Test97.xls
avoiding virus check.
(Thank you, Alfred Nathaniel)
- Fix weekday of ExcelLocaltime
0.11 Sat Jan 26 14:00:00 2001
- Skip 0xEF to EOF(0x0A) (Thank you, Phil DiFalco)
0.10 Mon Jan 15 12:00:00 2001
- Fix _subString, _subFormula (Thank you, Ilter Cekic and Mike Edwards)
0.09 Sat Dec 15 12:00:00 2000
- Fix Month name of FmtDefault.pm (Thank you, Michael Edwards)
- Add FmtJapan2.pm
- Fix Slightly Bug
0.08 Sat Nov 25 12:00:00 2000
- Fix RString, PackedString BUGS (Thank you, Kim Namsuk)
- Fix undefined function _subDefColW (Thank you, Hirofumi Morisada)
0.07 Sat Nov 18 12:00:00 2000
- Change to use OLE::Storage_Lite
- Fix RString, PackedString BUGS (Thank you, Hirofumi Morisada)
- Fix and Add Formula String (Thank you, Michael Edwards)
0.05 Mon Oct 2 03:14:04 2000
- original version
Spreadsheet-ParseExcel-0.66/MANIFEST 000644 000765 000024 00000005340 14543415026 017145 0 ustar 00John staff 000000 000000 CP932Excel.map
Changes
MANIFEST
Makefile.PL
README
README_Japan.htm
META.yml
t/00_basic.t
t/01_parse.t
t/02_parse-dates.t
t/03_regression.t
t/04_regression.t
t/05_regression.t
t/06_regression.t
t/07_cell_handler.t
t/10_error_codes.t
t/11_encryption.t
t/20_number_format_default.t
t/21_number_format_user.t
t/22_number_format_datetime.t
t/23_number_format_time.t
t/24_row_col_sizes.t
t/25_decode_rk_numbers.t
t/26_localtime2excel.t
t/27_localtime2excel.t
t/28_int2col.t
t/29_active_sheet.t
t/30_sst_01.t
t/32_charts.t
t/41_test95-97j.t
t/42_test95-97j-2.t
t/43_test2000J.t
t/44_oem.t
t/45_oem-2.t
t/46_save_parser.t
t/47_hyperlinks.t
t/90_pod.t
t/91_minimumversion.t
t/92_meta.t
t/excel_files/Dates.xls
t/excel_files/Dates1904.xls
t/excel_files/Test2000J.xls
t/excel_files/Test95.xls
t/excel_files/Test95J.xls
t/excel_files/Test97J.xls
t/excel_files/TestEncoding.xls
t/excel_files/chart1.xls
t/excel_files/chart2.xls
t/excel_files/chart3.xls
t/excel_files/chart4.xls
t/excel_files/encrypted.xls
t/excel_files/long_string1.xls
t/excel_files/long_string2.xls
t/excel_files/long_string3.xls
t/excel_files/long_string4.xls
t/excel_files/long_string5.xls
t/excel_files/long_string6.xls
t/excel_files/long_string7.xls
t/excel_files/long_string8.xls
t/excel_files/pers-encrypted-RC4-pass-11.xls
t/excel_files/pers-encrypted-def-pass-QwErTyUiOp.xls
t/excel_files/pers-protected.xls
t/excel_files/worksheet_01.xls
t/excel_files/TestActiveSheet.xls
lib/Spreadsheet/ParseExcel.pm
lib/Spreadsheet/ParseExcel/Cell.pm
lib/Spreadsheet/ParseExcel/Dump.pm
lib/Spreadsheet/ParseExcel/FmtDefault.pm
lib/Spreadsheet/ParseExcel/FmtJapan.pm
lib/Spreadsheet/ParseExcel/FmtJapan2.pm
lib/Spreadsheet/ParseExcel/FmtUnicode.pm
lib/Spreadsheet/ParseExcel/Font.pm
lib/Spreadsheet/ParseExcel/Format.pm
lib/Spreadsheet/ParseExcel/SaveParser.pm
lib/Spreadsheet/ParseExcel/SaveParser/Workbook.pm
lib/Spreadsheet/ParseExcel/SaveParser/Worksheet.pm
lib/Spreadsheet/ParseExcel/Utility.pm
lib/Spreadsheet/ParseExcel/Workbook.pm
lib/Spreadsheet/ParseExcel/Worksheet.pm
examples/a_simple_parser.pl
examples/display_text_table.pl
sample/Excel/AuthorK.xls
sample/Excel/AuthorK95.xls
sample/Excel/FmtTest.xls
sample/Excel/Rich.xls
sample/Excel/Test1904.xls
sample/Excel/Test1904_95.xls
sample/Excel/Test95.xls
sample/Excel/Test95J.xls
sample/Excel/Test97.xls
sample/Excel/Test97J.xls
sample/Excel/oem.xls
sample/README
sample/chkFmt.pl
sample/chkInfo.pl
sample/dmpEx.pl
sample/dmpExU.pl
sample/dmpExH.pl
sample/dmpExHJ.pl
sample/dmpExJ.pl
sample/dmpExR.pl
sample/Ilya.pl
sample/sample.pl
sample/sampleOEM.pl
sample/sample_j.pl
sample/smpFile.pl
sample/xls2csv.pl
sample/iftest.pl
sample/iftestj.pl
sample/dmpEx_2xml.pl
sample/parse.pl
META.json Module JSON meta-data (added by MakeMaker)
Spreadsheet-ParseExcel-0.66/t/ 000755 000765 000024 00000000000 14543415025 016254 5 ustar 00John staff 000000 000000 Spreadsheet-ParseExcel-0.66/README 000644 000765 000024 00000003657 14543412610 016701 0 ustar 00John staff 000000 000000 NAME
Spreadsheet::ParseExcel - Extract information from Excel file.
DESCRIPTION
This module allows you to extract information from Excel file.
This module can handle files in Excel95, 97 and 2000 format.
The module will work on the majority of Windows, UNIX and
Macintosh platforms.
REQUIREMENT
This module requires these modules:
OLE::Storage_Lite
Jcode.pm (if you are using FmtJapan, or FmtJapan2)
Unicode::Map (if you are using FmtJapan2 or FmtUnicode)
IO::Scalar (if PERLIO is not available)
Spreadsheet::WriteExcel (to use Spreadsheet::ParseExcel::SaveParser)
INSTALLATION
The module can be installed using the standard Perl procedure:
perl Makefile.PL
make
make test
make install # You may need to be root
make clean # or make realclean
or using CPAN.pm or CPANPLUS.pm
cpan Spreadsheet::ParseExcel
Windows users without a working "make" can get nmake from:
ftp://ftp.microsoft.com/Softlib/MSLFILES/nmake15.exe
For FmtJapan2
If you use FmtJapan2, you must do following actions:
(1) Copy "CP932Excel.map" included with this distribution to an
applicatable directry.
(2) To add "CP932Excel" as map name, append following lines to
REGISTRY in the Unicode::Map hierarchy
(changing map directy to applicatable directry):
name: CP932Excel
srcURL: $SrcUnicode/VENDORS/MICSFT/WINDOWS/CP932.TXT
src: $DestUnicode/VENDORS/MICSFT/WINDOWS/CP932.TXT
map: (which you copied directry)/CP932Excel.map
# Don't remove this line
AUTHOR
Maintainer 0.60+: Douglas Wilson dougw@cpan.org
Maintainer 0.40-0.59: John McNamara jmcnamara@cpan.org
Maintainer 0.27-0.33: Gabor Szabo szabgab@cpan.org
Original author: Kawai Takanori (Hippo2000) kwitknr@cpan.org
SUPPORT
Please check the "KNOWN PROBLEMS" section in the manual page
for Spreadsheet::ParseExcel.
Spreadsheet-ParseExcel-0.66/README_Japan.htm 000644 000765 000024 00000013406 11247565351 020603 0 ustar 00John staff 000000 000000
Speadsheet::ParseExcel.pm - 0.2405
by 繧ŵ (Hippo2000)
Changes
Υ⥸塼ϡޤСǤ
MicrosoftҤExcelեWindowsʳΥץåȥեǤ
Ф褦ˤ⥸塼Ǥ
ưǧ
DOS/V WindowsNT ver.4.0 Perl5.005
DOS/V TurboLinux ver.6.0 Perl5.005
Sun Sparc Solaris 2.6 Perl5.005
DOS/V Vine Linux 2.0 Perl5.005
Macintosh JPerlFreeBSDǤưƤȤݡȤƤޤ
¾δĶǼ¹Ԥ줿ϡƤ
ưƤưʤƤ⡢Ϥꤤޤ <(__)>
ñʳǧ(testǥ쥯ȥ
sampleǥ쥯ȥ˰ʲΥե뤬äƤޤ
sample.pl ñʥƥȥץȡSpreadsheet::ParseExcel::FmtDefaultѡ
sample_j.pl ñʥƥȥץȡSpreadsheet::ParseExcel::FmtJapanѡɤꤷƽϡ
res_sample sample.plμ¹Է
res_sample_jsample_j.plμ¹Է(euc)
dmpEx.pl : ExcelեƤɽSpreadsheet::ParseExcel::FmtDefaultѡ
dmpExj.pl : ExcelեƤɽSpreadsheet::ParseExcel::FmtJapanѡ
ñˤΥ⥸塼ưǧǤСdmpExj.plˤä
ꤷExcelեƤɽ뤳ȤǤޤ
ex.
# perl -I.. dmpExj.pl Excel/Test97.xls euc
-I..פϡƥǥ쥯ȥˤSpreadsheet::ParseExcel.pmѤ뤿˻ꤷޤ
Excel/Test97.xlsפоݤȤʤե̾
eucפϴϤȤʸɤǤeucsjisjisʤ
Jcode.pmƱǤ
ȡ
OLE::Storage_Liteȡ뤵Ƥɬפޤ
Spreadsheet::ParseExcel::FmtJapanѤ硢Jcode.pmɬפȤޤ¾Υ⥸塼ɬפȤޤ
Spreadsheet::ParseExcel::FmtJapan2Ѥ硢Jcode.pmUnicode::MapɬפȤޤ
PerlɸŪʥȡˤʤޤΥ⥸塼뼫ΤPerlΤߤǺƤΤǡԡǤưޤ
perl Makefile.PL
make
make test
make install (rootˤʤäơ
FmtJapan2Τ
¸ʸб뤿FmtJapan20.09Ʊޤ
Ѥ뤿ˤUnicode::Mapȡ뤹ۤʲμ礬ɬפˤʤޤ
(1) Ʊ"CP932Excel.map"Ŭڤʥǥ쥯ȥ˥ԡޤ
(2) "CP932Excel"ޥå̾Ȥɲä뤿ˡUnicode::MapؤˤREGISTRY˰ʲιԤɲäޤ
mapΥǥ쥯ȥ̾Ŭڤʥǥ쥯ȥ̾ˤƤ
name: CP932Excel
srcURL: $SrcUnicode/VENDORS/MICSFT/WINDOWS/CP932.TXT
src: $DestUnicode/VENDORS/MICSFT/WINDOWS/CP932.TXT
map: (ԡΥǥ쥯ȥ)/CP932Excel.map
# Don't remove this line
Ȥ
use strict;
use Spreadsheet::ParseExcel;
my $oExcel = new Spreadsheet::ParseExcel;
my $oBook = $oExcel->Parse('Excel/Test97.xls');
#ޤܸбǤ
use strict;
use Spreadsheet::ParseExcel;
use Spreadsheet::ParseExcel::FmtJapan;
my $oExcel = new Spreadsheet::ParseExcel;
my $oFmtJ = Spreadsheet::ParseExcel::FmtJapan->new(Code => 'euc'); #sjisjisʤɤΥ
my $oBook = $oExcel->Parse('Excel/Test97.xls', $oFmtJ);
#μФ
my($iR, $iC, $oWkS, $oWkC);
print "FILE :", $oBook->{File} , "\n";
print "COUNT :", $oBook->{SheetCount} , "\n";
print "AUTHOR:", $oBook->{Author} , "\n";
for(my $iSheet=0; $iSheet < $oBook->{SheetCount} ; $iSheet++) {
$oWkS = $oBook->{Worksheet}[$iSheet];
print "--------- SHEET:", $oWkS->{Name}, "\n";
for(my $iR = $oWkS->{MinRow} ;
defined $oWkS->{MaxRow} && $iR <= $oWkS->{MaxRow} ; $iR++) {
for(my $iC = $oWkS->{MinCol} ;
defined $oWkS->{MaxCol} && $iC <= $oWkS->{MaxCol} ; $iC++) {
$oWkC = $oWkS->{Cells}[$iR][$iC];
print "( $iR , $iC ) =>", $oWkC->Value, "\n" if($oWkC);
}
}
}
Х
ǤäExce97 ǥ٥åѡ åȡפޤ
Hirofumi Morisada˴ադǤ
Excel97/2000¸硢FmtJapanǤϵ¸ʸ()IʤɡˤˤʤäƤޤޤ
FmtJapan2ǤϰбƤĤǤ
ޤƥȤȤǤƤޤȤꤢưǤ礦 <(__)>
TurboLinux Version 6ǺƤΤǡ¾δĶǤɤʤΤȤƤⵤ
ʤޤ
SolarisǤưǧƤ餤ޤʤޤԶ礬ꤽǤ
ȡХݡȤԤƤޤ 繧ŵkwitknr@cpn.org
ʤ㤤ʤȡ
ƥȡ
ɥȤ
Ϥؤб (^_^) Spreadsheet::WriteExcelȤäƤΤ
줫ޤ뤴ȰĤƤͤϤޤ(^^)
ռ
Ⱦüʾ֤Ǽռ⤢äΤǤϤޤʲΥץࡢ
⥸塼ͤˤƤޤ
xlHtml
OLE::Storage
herbert (OLE::StorageƱġ
Spreadsheet::WriteExcel
SolarisΥǥХåȻϩवʤСΩޤǤ(cloudy˴ա
ǸˤExcel2000Υեޤ
Hirofumi MorisadaξʸΥХȯ뤳ȤǤޤ
ơExcel97ǥ٥åѡåȡפɤ⤢꤬Ȥޤ
¾ưХݡȤադǤ
Spreadsheet-ParseExcel-0.66/examples/ 000755 000765 000024 00000000000 14543415025 017627 5 ustar 00John staff 000000 000000 Spreadsheet-ParseExcel-0.66/META.yml 000644 000765 000024 00000001577 14543415025 017274 0 ustar 00John staff 000000 000000 ---
abstract: 'Read information from an Excel file.'
author:
- 'John McNamara (jmcnamara@cpan.org)'
build_requires:
ExtUtils::MakeMaker: '0'
configure_requires:
ExtUtils::MakeMaker: '0'
dynamic_config: 1
generated_by: 'ExtUtils::MakeMaker version 7.62, CPAN::Meta::Converter version 2.150010'
license: perl
meta-spec:
url: http://module-build.sourceforge.net/META-spec-v1.4.html
version: '1.4'
name: Spreadsheet-ParseExcel
no_index:
directory:
- t
- inc
requires:
Crypt::RC4: '0'
Digest::Perl::MD5: '0'
IO::File: '0'
IO::Scalar: '0'
OLE::Storage_Lite: '0.19'
Scalar::Util: '0'
resources:
bugtracker: http://github.com/jmcnamara/spreadsheet-parseexcel/issues
homepage: http://github.com/jmcnamara/spreadsheet-parseexcel/
repository: http://github.com/jmcnamara/spreadsheet-parseexcel
version: '0.66'
x_serialization_backend: 'CPAN::Meta::YAML version 0.018'
Spreadsheet-ParseExcel-0.66/sample/ 000755 000765 000024 00000000000 14543415025 017272 5 ustar 00John staff 000000 000000 Spreadsheet-ParseExcel-0.66/lib/ 000755 000765 000024 00000000000 14543415025 016557 5 ustar 00John staff 000000 000000 Spreadsheet-ParseExcel-0.66/Makefile.PL 000644 000765 000024 00000002164 14543413376 017775 0 ustar 00John staff 000000 000000 #!/usr/bin/perl -w
use strict;
use warnings;
use ExtUtils::MakeMaker;
use 5.008;
my %deps = (
'OLE::Storage_Lite' => 0.19,
'IO::File' => 0,
'Scalar::Util' => 0,
'IO::Scalar' => 0,
'Crypt::RC4' => 0,
'Digest::Perl::MD5' => 0,
);
my %resources = (
homepage => 'http://github.com/jmcnamara/spreadsheet-parseexcel/',
repository => 'http://github.com/jmcnamara/spreadsheet-parseexcel',
bugtracker => 'http://github.com/jmcnamara/spreadsheet-parseexcel/issues',
);
my %params = (
'AUTHOR' => 'John McNamara (jmcnamara@cpan.org)',
'NAME' => 'Spreadsheet::ParseExcel',
'ABSTRACT' => 'Read information from an Excel file.',
'VERSION_FROM' => 'lib/Spreadsheet/ParseExcel.pm',
'LICENSE' => 'perl',
'EXE_FILES' => [],
'INSTALLDIRS' => 'site',
'PL_FILES' => {},
'PREREQ_PM' => \%deps,
'NEEDS_LINKING' => 0,
'test' => { TESTS => 't/*.t' }
);
if ( $ExtUtils::MakeMaker::VERSION ge '6.46' ) {
$params{META_MERGE} = { resources => \%resources };
}
WriteMakefile(%params);
Spreadsheet-ParseExcel-0.66/CP932Excel.map 000644 000765 000024 00000050122 11247565351 020237 0 ustar 00John staff 000000 000000 ' 0 ??a ?@0 00 @ >?000N00 <^"%\ & % 0;=[]
0
- "`"f""4&B&@ 2!
&&%%%%%%%%%%% ;0!!!0"""""*")"'!!" "" "#"""a"R"j""=""5"+!+ 0&o&m&j %
O
`!ASS0A?@?00!@p0Q6> % %%%%%%%,%$%4%<%%%%%%%#%3%+%;%K% %/%(%7%?%%0%%%8%B@$`
!`_3I33"3M33'3363Q3W3
3&3#3+3J3;3333~3{00!3!!221293~3}3|"."""^NUZ?Tac(Y"uzP`cn%efhW'ebq[Y{}b}b|[^c fhHgONO
OMOPIVY7YZ\ `aapfipuOupy}}cUzS;NNWxN Xn8z2(/QASpTTVY_m-?@bpTS[pSo\zNxn&VUk;YSmftVBNKOSU[0_qf fhl8lm)t[vzN4[`muv`iSQ}WX0YD[^`(cclopqqYqs?~v`[XielZu%QY.Ye__bej*k'ksV,\l{Q\KahvraNYOSx`in)zONSNOUO=OOsRSV YZ[[yfggkLlpksyyz<{wfV)NO\brYu;NOVXJX^_`*``babbe9?@AffhmwppuLv}uQRYT[]ahimxWrmlWgRVT^bdh<h8ksrxzkki[f\i}Mc{ j+}jh
o_RrU`pbm;nn[DN9Sij:h*Q\zV[(h"1|RtN~OQ[R
RR]UX*Y[[[^r^y`aacacebghShk>kSlWo"ooEtuvwz{|!}6fQe(N8T+\]svLw<\TXOOSqUVhWYG[ [\^^~_cg:eeghh?@j_^0kll}uyH[cz } _w<NP}Q Y[b/bdk:ruyGpcT TUhTjXpx'guSt[PNNENOST8[_`%eQ}g=lBlrlpxtzvz{}|}fer[S\E]bbcn Z1oyZNNOOPQGzQqQSTS!SSUX\_7_J`/`P`mceYjKlrrwNWZNQ\-fim\@fiushP|PRWG]&ek#k=t4yy{K}_9TN]P6SS:rswQwa^UzzPv[GN2j\Q\H?@czltazq|h~phQlRTSfyAOPRQDUSW-sWYQ_b_`uavagacd:elfohBnufz=|}L}~KkJcf}RbdohAPk lzoTzt}P@#gNP9P&PeQ|R8RcUWXZ^aabcrij)r}rs.xxo}ywcuzUxQCSS^{_&nnss}C7 PNNPST|VY[d]^_'b8eEgnVr|N7gNNO
SHTIT>Z/__`hjtZxwN^NO|OPPQIQlRRRSST?@TUWQWY}[T[][]]]^x^^^_`RaLbbce;ffCfgmh!hil_m*min/nu2vxlz?|}}}^}T*RLauqx?M};R[RSTXboj_QKR;TJVz@w`sDo pu_`rkdNVWdXZZ`haffh9hmu}:nBNOPSU]o]]gltsxPWP^c+PPQg TX^Y[_ibMch=ksnp}rxx&yme}0 RdW(gPjQWB*X:iT]WxO\RJTd>f(ggz{V}"/h\{9SQR7?@[bddg-kvcLvfRN PS\q`dech_qsu#{~xefkNNO:OR:SSUVXYYY[P\M^^+_`ce/[\eeegkb}k{lsEyIy|}}+^ifkoNO<OQP[W[aHcfBk!nlr>tuxy:3lP_X+z[NSWY1Z[`nou[ {Prg\aJ~Q\chfeqny>}nPR\:gSp|r5L+[_1`N;S[bKg1krsz.kRQSTj[cj9} VSTh?@[\1]Oabm2yy}B~MFrt/1KlNOOQESA_bglAnsc~&SY[my]~.|X~qQSO\f%wzQ_eiokm}nodv}]uQRb@ffn^}rfRSYs^_`UdPQRS SGSTUFU1VYhYZ<[\\\\^^^_pbbbccwfff-fvg~hjj5lmn nXq<q&qguwx]yyeyz{|}9I]<Tsaf~N
NNNWQRpWX4X["^8`dgagVmDruszcr V1W?@bi
kq~TwrU\;O8OOUZ [[_aNc/efKhimxmu3uwy^y}3:2NNRXuX\u\=N
cm{%bVS}T9W^%cl4pwa|pBTt^]]iepgcngIiodz[Np,u]f/QR6RY_`'be?etffthhkcnrruv|VXRYez^-`befgwzM|M~>
d_xRbcdBb-z{}vINQHSCS`[\\]b&bGdhh4lmEmgo\qNq}ez{}?@~Jz9nxwRMUo8q6Qhy~U|VLXQ\cffiZruuyyVy|} }D4;a PRuSSP UXYOr=[\dS``c\cc?c}def]iioqNuvz|}}aIXlpmPXa5 OPtRGSs`ocIg_n,O\^e}SRQvc[X[k\
d
gQ\NYY*lpQU>XY`bSg5iU@(OSX[\^/_` aKb4fln .NSY'{,Lnp'SSUD[bXbblot"8o8QS?@SOFTYj1]zh7rHj=N9SXVWfbcekNmn[pwz{}=[VX_>efjku7P$wW0_`efzl`uznE{u\z{Q}yz6Zw@N-N[_bf<glkw;Njp&s*WNQFQU[^^3^__5_k_acfgonrRu:w:t9xvwRcWvglssm%XiiuXZhciOCo,g&}Ti?opWjX[,},r*T
NONP\PuRCTHX$[^^^^_`bc:chl@xyz}GD?@-ldXdeunv{inT_dMDQxXkY)\U^m~u[pOkou0QNTX5XWY\`_eg\n!v{Mx%x:R^WYt`PQZQ}QR UXTXXYW[\]`bd-gqhChhvmnompoq_Suyw{I{T{R|}qR0ciFv-0PRTX\admwzS\S?__mrywcy{krhjaQzi4\J[IpVx\o`eflZATQf
YHQNMQpXczKib~uwSWi`l]N\<_Sy^eNsQe?@Y\?NY_oyyb[qs+q^t_c{dq|NC^NKWV`o}
3]bdgwlm>t6x4ZFuO^bceWgovrL)MP
WZh}isqdrXjyw)O/ReSZbglv}{|6fo r~Q{xr{{Hj^auQu`QkbnvzOpb{OVzXYO4R$SJSS^d,egl>lNrHrsuT~A,{qic=fiujvxCS*SQT&Y^_|`bIbybekluvxy}w^j|8P\>_gkt5w ?@;gzS9u_f_<_ub{F<hgYZ}v~,O_jjl7otyhhUy^cuy(-T_lem\p;eOtN
NWY+Zf[Q^^`bvew}efnmnr6{&P\tDOdkfaj\iSzWORo_^Eg
yym_bUlNriRT;VtXabnqYn||}e^NOuQuX@^c^s_
gN&=[|sPXvVxR%w{POY rG{}MORZ)_OWcUkiu+zBRXaUb
fk|?P#OSTFX1YI[\\])^bcge>eg?@llpx2~+*JlNONPRVWJY^=_b?fgghQ}! ~2T ,SPS\Xdg4rgwfzFRlkX ^LYTg,Qv}dixTWYf'gkTi^UggRh]NOSbg+lO~mNabno+Tsg*E]{\[nJzY|lw RY"q!r_w'aiZZQT
T}fvYr]nQMh}}bdxj!Y[_ksv}Q2g(vgbR\$b;|~UO`}SN_QYr:6_%wS_y}3VgSa alvR?@8U/OQQ*RS[^}`acg gngms6u1yPJYNOYN?P^|Y[^ccdfiJimnqu(z I!
e}
a~bk2}lmtmge<m}a=jNqSu]Pko-R)T\egNhttux_szNcueRmAnt uYxk|zOane\NNPN!Q[ehmsvBwz|o|uR}P+Sgmqt3*Wt`XAm}/^NO6OQR]`sy<4
bfktRRp^`Kao#qI|>}o3@#,TBojp2RZA^_gi|imjorbr{~KQmy2P-Tqkj`gNNkhi n~xU^_NNN*N1N6N<N?NBNVNXNNkN_
NNNNNNNNNNNNNNNNO OZO0O[O]OWOGOvOOOO{OiOpOOoOOQOOOOOOOOOPP(PP*P%POOP!P)P,OOPPPCPGgPUPPPHPZPVPlPxPPPPP?@PPPPPPPPPPPQ QQQQQQ!Q:Q7Q<Q;Q?QRQLQTQbzQiQnQQVQQQQQQQQQQQQQQQQQQQUQQ}QQQRRRRR'R*R.R3R9RORDRKR^RTRjRtRiRsRR}RRRRqRRRRRRRRRRRRRRRSSu8S
SSSSS#S/S1S3S8S@SFSENSISMQS^SiSnYS{SwSSSSSSSSS|SfqSSSSTT=T@T,T<T.T6T)TTNTTuTT_TqTwTpTT{TTvTTTTTTTTTTT?@TTTTTTTUUTTTTTU9U@UcULU.U\UEUVU8U3U]UUTUUU{U~UUUU|UUUUUUUUUUUVUVUUVUVNVPqV4V6V2V8}VkVdV/VlVjVVVVVVVVVVVVVVVVVVVVVVW VWW WWW
WWWUWW&W7WNW;W@WOWiWWWaWWWWWWWWWWWWX
WWXXXXrX!XbXKXpkXRX=XyXXXXXXXXXXXXXXXXXXXXXXXYY
YYhY%Y,Y2Y8Y>zYUYPYNYZYXYbY`YgYlYi?@YxYYO^OYYYYYYYZ%ZZZZ ZZ@ZlZIZ5ZbZjZZZZZZZZZZZZ[[[[2Z[*[6[>[C[E[@[Q[U[Z[e[i[p[s[u[xe[z[}[[[[[[[[[[[[[[[[[\\\
\\ \"\(\8\A\F\N\S\P\O[q\l\nNb\v\y\\\Y\\\\\\\\\\\\\]\]]]]\]]]]]"]]]]L]R]N]K]l]s]v]]]]]]]]]]]]]]]]]]]]^^^^^^6^D^C^@^N^W^T^_^b^d^G^u^z^^^^^^?@^^^^^^^^^^^^^^__ _]_\____)_-_8_A_H_L_N_/_Q_V_Y_a_m_s_w____________________`_`!``}```)``1```+`&``:`Z`A`j`w`_`J`F`M`c`C`d`B`l`k`Y````````````````_````aMaa`a ``aa!``a
aGa>a(a'aJa?a<a,a4a=aBaDasawaXakataoaeaqa_a]aSauaaaaaaaaaaaaaaaaaaayaaaaaaaaaab bb
bbb?@bb!b*b.b0b2bAbNb^bcb[b`bhb|bbb~bbbbbbbbbbbdbbbbbbbbcbbc'ccbbcPc>cMdcOcccccvcccccck}cicccccccccdd4ddd&d6edd(ddgdodvdNe*ddddddddddddddd dbdde,dddde deeee$e#e+e4e7e6e8uKeHeVeUeMeXe^e]erexeeeeeeeeeeeeeeegrf
fegsf5f4ffOfDfIfAf^f]fdfgf_fbfpffffffffffff?@ffffff?fffffgggg&8g.g?g6gAg8g7gFg^g`gYgcggpgg|gjgggggggggggggggggggggjhhFh)h@hMh2hN}hh+hYhchwhhhhhhhhjhhthhhihh~ihihi"i&hihhhhi6iihhi%hhhi(i*ii#i!hiyiwi\ixikiTi~ini9iti=iYi0iai^i]iijiiiiiiii[iiiiij.iiiiiiijjik
iiijijijij
jjj#jjDjjrj6jxjGjbjYjfjHj8j"jjjjj?@jjjjjjjjjjjjjjkjkk1kk8k7vk9kGkCkIkPkYkTk[k_kakxkkkkkkkkkkkkkkkkkkkkkkk}llll$l#l^lUlbljllllll~lhlslllllllllllllllllmMm6m+m=m8mm5m3mmmcmmdmZmymYmmommnn
mmmmmmmmmmmmmmmmmn-nnn.nnrn_n>n#nkn+nvnMnnCn:nNn$nnn8nnnnnnnnnnnnnnnoAopLnnno?no1no2n?@o>onoozoxooooo[oomoo|oXoooofooooooooooooooop popppoppotpppp0p>p2pQpcppppppppppp}pq pqqqeqUqqfqbqLqVqlqqqqqqqqqqqqqqqqqqqqr
rrr(r-r,r0r2r;r?rFrKrXrtr~rrrrrrrrrrrrrrrrrrPss
ssss4s/s)s%s>sNsWsjshspsxsus{szsssssssstttot%st2t:tUt?t_tYtAt\titptctjtvt~tttttts?@tttttttttuuuuuu
uuuu&u,u<uDuMuJuIu[uFuZuiudugukumuxuvuutuuuuuuuuuuuuuuuuuuuuuuu}uvuuuvv
v vv'v v$v4v0v;vGvFv\vXvavhvgvlvpvrvvvxv|vvvvvvvvvvvvvvvvvvvv/vwwww)w$ww%ww7wGwZwhwkw[weww~wywwwwwwwwwwwwwwwwwwwxxy&x y*xExxtxx|xxxxxxxxxxxxxxx?@xxxxyyyyy,y+y@y`yWy_yZyUySyzyyyyKyyyyyyyyyyzz
zz zyz1z;z>z7zCzWzIzazizpzyz}zzzzzzzz}zzzzzzzzzzzzzzzz{{{
{{3{{{5{({6{P{z{{M{{L{E{u{e{t{g{p{l{n{{{{{{{{{{]{{{{{{{{{||{{|`| ||{{||
{|#|'|*||7|+|=|L|C|T|O|@|P|X|_|d|V|e|l|u|||||||||||||||||||||;|||||}?@}}}}
}E}K}.}2}?}5}F}s}V}N}r}h}n}O}c}}}[}}}}}}}}}}}~=}}}}}}}}}}}}}~~
~#~!~~1~~ ~~"~F~f~;~5~9~C~7}~2~:~g~]~V~^~Y~y~j~i~|~{~}~}~~~~~~~~~8:ELPUTX_hgxq!(?;JFRXZ_bhsrpvy}Q )#/K?@F>SQqnet_
)+83@YX]Z_d}bhj.qw~ 5421@9PE/+#|su
" 8m*<ZwkniF,oy5b!,@cXH?@AKUmw~
"0?MNUT_gq#}
4?7;%)`_xLNtWhnYScj
"!169';DBRY^bk~u}r
C%*AD;68L`^?@fdmjotw~%6A[RFH|mlb} 3&+>(ALONIV[Zk_lot}:A?HLNPUblxz|b
NgmqsB504J?@GILPHYd`*cUvr|
&3;9EB>LIFNW\}b!
'659OI>VX^hovr}bH20JVXceisr,^WEIdH?KPZD.?@"#:5;\`|nV6+5!:ARD[`b^j)puw}Z|~}o!(.BLOKw\^]_frlM
$*09=DFHBI\`dfhRkqy|zOz8$!7=FOKko?@qts !$ ,.=BIEPKQLU+7EB@C}>UM[W_bedikj"%'.2DCOMQXt:
.%$!0G2F>Z`gvx *&#DA?>FH?@]dQPYrozuy}a%v!,>JRTc_fljwrvX/iYtdQq?@~HOpf1hf_EN(NNO OO9OVOOOOOP@P"OPPFPpPBPPPQJQdQQQRRRRRS SS$SrSSSTTTTUWYWeWWW}XXYYSY[Y]YcYY[V[u/[[\\\\]']S]B]m]]_!_4_g__`]````a `aa7a0abbcd`ddeNf ff;f f.ff$fefWfYfsfffffg)gfghRghhDhihiij0jkjFjsj~jjkl?l\llolmmmommmmmmn9n\n'n<noooppp(ppqqq\qFqqr?@rs$swssssstst&t*t)t.tbttuuovvvvvwFRx!xNxdxzy0yyzzz{}H}\}}}~RGbHSYmk 7y"Sv#$g&'
:@<NYQ9gw'%!(pW1EH)3;CMOQUWe*',Nur pk-
!p Spreadsheet-ParseExcel-0.66/META.json 000644 000765 000024 00000002634 14543415026 017440 0 ustar 00John staff 000000 000000 {
"abstract" : "Read information from an Excel file.",
"author" : [
"John McNamara (jmcnamara@cpan.org)"
],
"dynamic_config" : 1,
"generated_by" : "ExtUtils::MakeMaker version 7.62, CPAN::Meta::Converter version 2.150010",
"license" : [
"perl_5"
],
"meta-spec" : {
"url" : "http://search.cpan.org/perldoc?CPAN::Meta::Spec",
"version" : 2
},
"name" : "Spreadsheet-ParseExcel",
"no_index" : {
"directory" : [
"t",
"inc"
]
},
"prereqs" : {
"build" : {
"requires" : {
"ExtUtils::MakeMaker" : "0"
}
},
"configure" : {
"requires" : {
"ExtUtils::MakeMaker" : "0"
}
},
"runtime" : {
"requires" : {
"Crypt::RC4" : "0",
"Digest::Perl::MD5" : "0",
"IO::File" : "0",
"IO::Scalar" : "0",
"OLE::Storage_Lite" : "0.19",
"Scalar::Util" : "0"
}
}
},
"release_status" : "stable",
"resources" : {
"bugtracker" : {
"web" : "http://github.com/jmcnamara/spreadsheet-parseexcel/issues"
},
"homepage" : "http://github.com/jmcnamara/spreadsheet-parseexcel/",
"repository" : {
"url" : "http://github.com/jmcnamara/spreadsheet-parseexcel"
}
},
"version" : "0.66",
"x_serialization_backend" : "JSON::PP version 4.06"
}
Spreadsheet-ParseExcel-0.66/lib/Spreadsheet/ 000755 000765 000024 00000000000 14543415025 021026 5 ustar 00John staff 000000 000000 Spreadsheet-ParseExcel-0.66/lib/Spreadsheet/ParseExcel/ 000755 000765 000024 00000000000 14543415025 023061 5 ustar 00John staff 000000 000000 Spreadsheet-ParseExcel-0.66/lib/Spreadsheet/ParseExcel.pm 000644 000765 000024 00000337741 14543414145 023440 0 ustar 00John staff 000000 000000 package Spreadsheet::ParseExcel;
##############################################################################
#
# Spreadsheet::ParseExcel - Extract information from an Excel file.
#
# Copyright (c) 2014 Douglas Wilson
# Copyright (c) 2009-2013 John McNamara
# Copyright (c) 2006-2008 Gabor Szabo
# Copyright (c) 2000-2008 Takanori Kawai
#
# perltidy with standard settings.
#
# Documentation after __END__
#
use strict;
use warnings;
use 5.008;
use OLE::Storage_Lite;
use File::Basename qw(fileparse);
use IO::File;
use Config;
use Crypt::RC4;
use Digest::Perl::MD5;
our $VERSION = '0.66';
use Spreadsheet::ParseExcel::Workbook;
use Spreadsheet::ParseExcel::Worksheet;
use Spreadsheet::ParseExcel::Font;
use Spreadsheet::ParseExcel::Format;
use Spreadsheet::ParseExcel::Cell;
use Spreadsheet::ParseExcel::FmtDefault;
my $currentbook;
my @aColor = (
'000000', # 0x00
'FFFFFF', 'FFFFFF', 'FFFFFF', 'FFFFFF',
'FFFFFF', 'FFFFFF', 'FFFFFF', '000000', # 0x08
'FFFFFF', 'FF0000', '00FF00', '0000FF',
'FFFF00', 'FF00FF', '00FFFF', '800000', # 0x10
'008000', '000080', '808000', '800080',
'008080', 'C0C0C0', '808080', '9999FF', # 0x18
'993366', 'FFFFCC', 'CCFFFF', '660066',
'FF8080', '0066CC', 'CCCCFF', '000080', # 0x20
'FF00FF', 'FFFF00', '00FFFF', '800080',
'800000', '008080', '0000FF', '00CCFF', # 0x28
'CCFFFF', 'CCFFCC', 'FFFF99', '99CCFF',
'FF99CC', 'CC99FF', 'FFCC99', '3366FF', # 0x30
'33CCCC', '99CC00', 'FFCC00', 'FF9900',
'FF6600', '666699', '969696', '003366', # 0x38
'339966', '003300', '333300', '993300',
'993366', '333399', '333333', '000000' # 0x40
);
use constant verExcel95 => 0x500;
use constant verExcel97 => 0x600;
use constant verBIFF2 => 0x00;
use constant verBIFF3 => 0x02;
use constant verBIFF4 => 0x04;
use constant verBIFF5 => 0x08;
use constant verBIFF8 => 0x18;
use constant MS_BIFF_CRYPTO_NONE => 0;
use constant MS_BIFF_CRYPTO_XOR => 1;
use constant MS_BIFF_CRYPTO_RC4 => 2;
use constant sizeof_BIFF_8_FILEPASS => ( 6 + 3 * 16 );
use constant REKEY_BLOCK => 0x400;
# Error code for some of the common parsing errors.
use constant ErrorNone => 0;
use constant ErrorNoFile => 1;
use constant ErrorNoExcelData => 2;
use constant ErrorFileEncrypted => 3;
# Color index for the 'auto' color
use constant AutoColor => 64;
our %error_strings = (
ErrorNone, '', # 0
ErrorNoFile, 'File not found', # 1
ErrorNoExcelData, 'No Excel data found in file', # 2
ErrorFileEncrypted, 'File is encrypted', # 3
);
our %ProcTbl = (
#Develpers' Kit P291
0x14 => \&_subHeader, # Header
0x15 => \&_subFooter, # Footer
0x18 => \&_subName, # NAME(?)
0x1A => \&_subVPageBreak, # Vertical Page Break
0x1B => \&_subHPageBreak, # Horizontal Page Break
0x22 => \&_subFlg1904, # 1904 Flag
0x26 => \&_subMargin, # Left Margin
0x27 => \&_subMargin, # Right Margin
0x28 => \&_subMargin, # Top Margin
0x29 => \&_subMargin, # Bottom Margin
0x2A => \&_subPrintHeaders, # Print Headers
0x2B => \&_subPrintGridlines, # Print Gridlines
0x3C => \&_subContinue, # Continue
0x3D => \&_subWindow1, # Window1
0x43 => \&_subXF, # XF for Excel < 4.
0x0443 => \&_subXF, # XF for Excel = 4.
0x862 => \&_subSheetLayout, # Sheet Layout
0x1B8 => \&_subHyperlink, # HYPERLINK
#Develpers' Kit P292
0x55 => \&_subDefColWidth, # Consider
0x5C => \&_subWriteAccess, # WRITEACCESS
0x7D => \&_subColInfo, # Colinfo
0x7E => \&_subRK, # RK
0x81 => \&_subWSBOOL, # WSBOOL
0x83 => \&_subHcenter, # HCENTER
0x84 => \&_subVcenter, # VCENTER
0x85 => \&_subBoundSheet, # BoundSheet
0x92 => \&_subPalette, # Palette, fgp
0x99 => \&_subStandardWidth, # Standard Col
#Develpers' Kit P293
0xA1 => \&_subSETUP, # SETUP
0xBD => \&_subMulRK, # MULRK
0xBE => \&_subMulBlank, # MULBLANK
0xD6 => \&_subRString, # RString
#Develpers' Kit P294
0xE0 => \&_subXF, # ExTended Format
0xE5 => \&_subMergeArea, # MergeArea (Not Documented)
0xFC => \&_subSST, # Shared String Table
0xFD => \&_subLabelSST, # Label SST
#Develpers' Kit P295
0x201 => \&_subBlank, # Blank
0x202 => \&_subInteger, # Integer(Not Documented)
0x203 => \&_subNumber, # Number
0x204 => \&_subLabel, # Label
0x205 => \&_subBoolErr, # BoolErr
0x207 => \&_subString, # STRING
0x208 => \&_subRow, # RowData
0x221 => \&_subArray, # Array (Consider)
0x225 => \&_subDefaultRowHeight, # Consider
0x31 => \&_subFont, # Font
0x231 => \&_subFont, # Font
0x27E => \&_subRK, # RK
0x41E => \&_subFormat, # Format
0x06 => \&_subFormula, # Formula
0x406 => \&_subFormula, # Formula
0x009 => \&_subBOF, # BOF(BIFF2)
0x209 => \&_subBOF, # BOF(BIFF3)
0x409 => \&_subBOF, # BOF(BIFF4)
0x809 => \&_subBOF, # BOF(BIFF5-8)
);
our $BIGENDIAN;
our $PREFUNC;
our $_use_perlio;
#------------------------------------------------------------------------------
# Spreadsheet::ParseExcel->new
#------------------------------------------------------------------------------
sub new {
my ( $class, %hParam ) = @_;
if ( not defined $_use_perlio ) {
if ( exists $Config{useperlio}
&& defined $Config{useperlio}
&& $Config{useperlio} eq "define" )
{
$_use_perlio = 1;
}
else {
$_use_perlio = 0;
require IO::Scalar;
import IO::Scalar;
}
}
# Check ENDIAN(Little: Intel etc. BIG: Sparc etc)
$BIGENDIAN =
( defined $hParam{Endian} ) ? $hParam{Endian}
: ( unpack( "H08", pack( "L", 2 ) ) eq '02000000' ) ? 0
: 1;
my $self = {};
bless $self, $class;
$self->{GetContent} = \&_subGetContent;
if ( $hParam{EventHandlers} ) {
$self->SetEventHandlers( $hParam{EventHandlers} );
}
else {
$self->SetEventHandlers( \%ProcTbl );
}
if ( $hParam{AddHandlers} ) {
foreach my $sKey ( keys( %{ $hParam{AddHandlers} } ) ) {
$self->SetEventHandler( $sKey, $hParam{AddHandlers}->{$sKey} );
}
}
$self->{CellHandler} = $hParam{CellHandler};
$self->{NotSetCell} = $hParam{NotSetCell};
$self->{Object} = $hParam{Object};
if ( defined $hParam{Password} ) {
$self->{Password} = $hParam{Password};
}
else {
$self->{Password} = 'VelvetSweatshop';
}
$self->{_error_status} = ErrorNone;
return $self;
}
#------------------------------------------------------------------------------
# Spreadsheet::ParseExcel->SetEventHandler
#------------------------------------------------------------------------------
sub SetEventHandler {
my ( $self, $key, $sub_ref ) = @_;
$self->{FuncTbl}->{$key} = $sub_ref;
}
#------------------------------------------------------------------------------
# Spreadsheet::ParseExcel->SetEventHandlers
#------------------------------------------------------------------------------
sub SetEventHandlers {
my ( $self, $rhTbl ) = @_;
$self->{FuncTbl} = undef;
foreach my $sKey ( keys %$rhTbl ) {
$self->{FuncTbl}->{$sKey} = $rhTbl->{$sKey};
}
}
#------------------------------------------------------------------------------
# Decryption routines
# based on sources of gnumeric (ms-biff.c ms-excel-read.c)
#------------------------------------------------------------------------------
sub md5state {
my ( $md5 ) = @_;
my $s = '';
for ( my $i = 0 ; $i < 4 ; $i++ ) {
my $v = $md5->{_state}[$i];
$s .= chr( $v & 0xff );
$s .= chr( ( $v >> 8 ) & 0xff );
$s .= chr( ( $v >> 16 ) & 0xff );
$s .= chr( ( $v >> 24 ) & 0xff );
}
return $s;
}
sub MakeKey {
my ( $block, $key, $valContext ) = @_;
my $pwarray = "\0" x 64;
substr( $pwarray, 0, 5 ) = substr( $valContext, 0, 5 );
substr( $pwarray, 5, 1 ) = chr( $block & 0xff );
substr( $pwarray, 6, 1 ) = chr( ( $block >> 8 ) & 0xff );
substr( $pwarray, 7, 1 ) = chr( ( $block >> 16 ) & 0xff );
substr( $pwarray, 8, 1 ) = chr( ( $block >> 24 ) & 0xff );
substr( $pwarray, 9, 1 ) = "\x80";
substr( $pwarray, 56, 1 ) = "\x48";
my $md5 = Digest::Perl::MD5->new();
$md5->add( $pwarray );
my $s = md5state( $md5 );
${$key} = Crypt::RC4->new( $s );
}
sub VerifyPassword {
my ( $password, $docid, $salt_data, $hashedsalt_data, $valContext ) = @_;
my $pwarray = "\0" x 64;
my $i;
my $md5 = Digest::Perl::MD5->new();
for ( $i = 0 ; $i < length( $password ) ; $i++ ) {
my $o = ord( substr( $password, $i, 1 ) );
substr( $pwarray, 2 * $i, 1 ) = chr( $o & 0xff );
substr( $pwarray, 2 * $i + 1, 1 ) = chr( ( $o >> 8 ) & 0xff );
}
substr( $pwarray, 2 * $i, 1 ) = chr( 0x80 );
substr( $pwarray, 56, 1 ) = chr( ( $i << 4 ) & 0xff );
$md5->add( $pwarray );
my $mdContext1 = md5state( $md5 );
my $offset = 0;
my $keyoffset = 0;
my $tocopy = 5;
$md5->reset;
while ( $offset != 16 ) {
if ( ( 64 - $offset ) < 5 ) {
$tocopy = 64 - $offset;
}
substr( $pwarray, $offset, $tocopy ) =
substr( $mdContext1, $keyoffset, $tocopy );
$offset += $tocopy;
if ( $offset == 64 ) {
$md5->add( $pwarray );
$keyoffset = $tocopy;
$tocopy = 5 - $tocopy;
$offset = 0;
next;
}
$keyoffset = 0;
$tocopy = 5;
substr( $pwarray, $offset, 16 ) = $docid;
$offset += 16;
}
substr( $pwarray, 16, 1 ) = "\x80";
substr( $pwarray, 17, 47 ) = "\0" x 47;
substr( $pwarray, 56, 1 ) = "\x80";
substr( $pwarray, 57, 1 ) = "\x0a";
$md5->add( $pwarray );
${$valContext} = md5state( $md5 );
my $key;
MakeKey( 0, \$key, ${$valContext} );
my $salt = $key->RC4( $salt_data );
my $hashedsalt = $key->RC4( $hashedsalt_data );
$salt .= "\x80" . "\0" x 47;
substr( $salt, 56, 1 ) = "\x80";
$md5->reset;
$md5->add( $salt );
my $mdContext2 = md5state( $md5 );
return ( $mdContext2 eq $hashedsalt );
}
sub SkipBytes {
my ( $q, $start, $count ) = @_;
my $scratch = "\0" x REKEY_BLOCK;
my $block;
$block = int( ( $start + $count ) / REKEY_BLOCK );
if ( $block != $q->{block} ) {
MakeKey( $q->{block} = $block, \$q->{rc4_key}, $q->{md5_ctxt} );
$count = ( $start + $count ) % REKEY_BLOCK;
}
$q->{rc4_key}->RC4( substr( $scratch, 0, $count ) );
return 1;
}
sub SetDecrypt {
my ( $q, $version, $password ) = @_;
if ( $q->{opcode} != 0x2f ) {
return 0;
}
if ( $password eq '' ) {
return 0;
}
# TODO old versions decryption
#if (version < MS_BIFF_V8 || q->data[0] == 0)
# return ms_biff_pre_biff8_query_set_decrypt (q, password);
if ( $q->{length} != sizeof_BIFF_8_FILEPASS ) {
return 0;
}
unless (
VerifyPassword(
$password,
substr( $q->{data}, 6, 16 ),
substr( $q->{data}, 22, 16 ),
substr( $q->{data}, 38, 16 ),
\$q->{md5_ctxt}
)
)
{
return 0;
}
$q->{encryption} = MS_BIFF_CRYPTO_RC4;
$q->{block} = -1;
# The first record after FILEPASS seems to be unencrypted
$q->{dont_decrypt_next_record} = 1;
# Pretend to decrypt the entire stream up till this point, it was
# encrypted, but do it anyway to keep the rc4 state in sync
SkipBytes( $q, 0, $q->{streamPos} );
return 1;
}
sub InitStream {
my ( $stream_data ) = @_;
my %q;
$q{opcode} = 0;
$q{length} = 0;
$q{data} = '';
$q{stream} = $stream_data; # data stream
$q{streamLen} = length( $stream_data ); # stream length
$q{streamPos} = 0; # stream position
$q{encryption} = 0;
$q{xor_key} = '';
$q{rc4_key} = '';
$q{md5_ctxt} = '';
$q{block} = 0;
$q{dont_decrypt_next_record} = 0;
return \%q;
}
sub QueryNext {
my ( $q ) = @_;
if ( $q->{streamPos} + 4 >= $q->{streamLen} ) {
return 0;
}
my $data = substr( $q->{stream}, $q->{streamPos}, 4 );
( $q->{opcode}, $q->{length} ) = unpack( 'v2', $data );
# No biff record should be larger than around 20,000.
if ( $q->{length} >= 20000 ) {
return 0;
}
if ( $q->{length} > 0 ) {
$q->{data} = substr( $q->{stream}, $q->{streamPos} + 4, $q->{length} );
}
else {
$q->{data} = undef;
$q->{dont_decrypt_next_record} = 1;
}
if ( $q->{encryption} == MS_BIFF_CRYPTO_RC4 ) {
if ( $q->{dont_decrypt_next_record} ) {
SkipBytes( $q, $q->{streamPos}, 4 + $q->{length} );
$q->{dont_decrypt_next_record} = 0;
}
else {
my $pos = $q->{streamPos};
my $data = $q->{data};
my $len = $q->{length};
my $res = '';
# Pretend to decrypt header.
SkipBytes( $q, $pos, 4 );
$pos += 4;
while ( $q->{block} != int( ( $pos + $len ) / REKEY_BLOCK ) ) {
my $step = REKEY_BLOCK - ( $pos % REKEY_BLOCK );
$res .= $q->{rc4_key}->RC4( substr( $data, 0, $step ) );
$data = substr( $data, $step );
$pos += $step;
$len -= $step;
MakeKey( ++$q->{block}, \$q->{rc4_key}, $q->{md5_ctxt} );
}
$res .= $q->{rc4_key}->RC4( substr( $data, 0, $len ) );
$q->{data} = $res;
}
}
elsif ( $q->{encryption} == MS_BIFF_CRYPTO_XOR ) {
# not implemented
return 0;
}
elsif ( $q->{encryption} == MS_BIFF_CRYPTO_NONE ) {
}
$q->{streamPos} += 4 + $q->{length};
return 1;
}
###############################################################################
#
# Parse()
#
# Parse the Excel file and convert it into a tree of objects..
#
sub parse {
my ( $self, $source, $formatter ) = @_;
my $workbook = Spreadsheet::ParseExcel::Workbook->new();
$currentbook = $workbook;
$workbook->{SheetCount} = 0;
$workbook->{CellHandler} = $self->{CellHandler};
$workbook->{NotSetCell} = $self->{NotSetCell};
$workbook->{Object} = $self->{Object};
$workbook->{aColor} = [ @aColor ];
my ( $biff_data, $data_length ) = $self->_get_content( $source, $workbook );
return undef if not $biff_data;
if ( $formatter ) {
$workbook->{FmtClass} = $formatter;
}
else {
$workbook->{FmtClass} = Spreadsheet::ParseExcel::FmtDefault->new();
}
# Parse the BIFF data.
my $stream = InitStream( $biff_data );
while ( QueryNext( $stream ) ) {
my $record = $stream->{opcode};
my $record_length = $stream->{length};
my $record_header = $stream->{data};
# If the file contains a FILEPASS record we assume that it is encrypted
# and cannot be parsed.
if ( $record == 0x002F ) {
unless ( SetDecrypt( $stream, '', $self->{Password} ) ) {
$self->{_error_status} = ErrorFileEncrypted;
return undef;
}
}
# Special case of a formula String with no string.
if ( $workbook->{_PrevPos}
&& ( defined $self->{FuncTbl}->{$record} )
&& ( $record != 0x207 ) )
{
my $iPos = $workbook->{_PrevPos};
$workbook->{_PrevPos} = undef;
my ( $row, $col, $format_index ) = @$iPos;
_NewCell(
$workbook, $row, $col,
Kind => 'Formula String',
Val => '',
FormatNo => $format_index,
Format => $workbook->{Format}[$format_index],
Numeric => 0,
Code => undef,
Book => $workbook,
);
}
# If the BIFF record matches 0x0*09 then it is a BOF record.
# We reset the _skip_chart flag to ensure we check the sheet type.
if ( ( $record & 0xF0FF ) == 0x09 ) {
$workbook->{_skip_chart} = 0;
}
if ( defined $self->{FuncTbl}->{$record} && !$workbook->{_skip_chart} )
{
$self->{FuncTbl}->{$record}
->( $workbook, $record, $record_length, $record_header );
}
$PREFUNC = $record if ( $record != 0x3C ); #Not Continue
last if defined $workbook->{_ParseAbort};
}
foreach my $worksheet (@{$workbook->{Worksheet}} ) {
# Install hyperlinks into each cell
# Range is undocumented for user; allows reuse of data
if ($worksheet->{HyperLinks}) {
foreach my $link (@{$worksheet->{HyperLinks}}) {
for( my $row = $link->[3]; $row <= $link->[4]; $row++ ) {
for( my $col = $link->[5]; $col <= $link->[6]; $col++ ) {
$worksheet->{Cells}[$row][$col]{Hyperlink} = $link;
}
}
}
}
}
return $workbook;
}
###############################################################################
#
# _get_content()
#
# Get the Excel BIFF content from the file or filehandle.
#
sub _get_content {
my ( $self, $source, $workbook ) = @_;
my ( $biff_data, $data_length );
# Reset the error status in case method is called more than once.
$self->{_error_status} = ErrorNone;
my $ref = ref($source);
if ( $ref ) {
if ( $ref eq 'SCALAR' ) {
# Specified by a scalar buffer.
( $biff_data, $data_length ) = $self->{GetContent}->( $source );
}
elsif ( $ref eq 'ARRAY' ) {
# Specified by file content
$workbook->{File} = undef;
my $sData = join( '', @$source );
( $biff_data, $data_length ) = $self->{GetContent}->( \$sData );
}
else {
# Assume filehandle
# For CGI.pm (Light FileHandle)
my $sBuff = '';
if ( eval { binmode( $source ) } ) {
my $sWk;
while ( read( $source, $sWk, 4096 ) ) {
$sBuff .= $sWk;
}
}
else {
# Assume IO::Wrap or some other filehandle-like OO-only object
my $sWk;
# IO::Wrap does not implement binmode
eval { $source->binmode() };
while ( $source->read( $sWk, 4096 ) ) {
$sBuff .= $sWk;
}
}
( $biff_data, $data_length ) = $self->{GetContent}->( \$sBuff );
}
}
else {
# Specified by filename .
$workbook->{File} = $source;
if ( !-e $source ) {
$self->{_error_status} = ErrorNoFile;
return undef;
}
( $biff_data, $data_length ) = $self->{GetContent}->( $source );
}
# If the read was successful return the data.
if ( $data_length ) {
return ( $biff_data, $data_length );
}
else {
$self->{_error_status} = ErrorNoExcelData;
return undef;
}
}
#------------------------------------------------------------------------------
# _subGetContent (for Spreadsheet::ParseExcel)
#------------------------------------------------------------------------------
sub _subGetContent {
my ( $sFile ) = @_;
my $oOl = OLE::Storage_Lite->new( $sFile );
return ( undef, undef ) unless ( $oOl );
my @aRes = $oOl->getPpsSearch(
[
OLE::Storage_Lite::Asc2Ucs( 'Book' ),
OLE::Storage_Lite::Asc2Ucs( 'Workbook' )
],
1, 1
);
return ( undef, undef ) if ( $#aRes < 0 );
#Hack from Herbert
if ( $aRes[0]->{Data} ) {
return ( $aRes[0]->{Data}, length( $aRes[0]->{Data} ) );
}
#Same as OLE::Storage_Lite
my $oIo;
#1. $sFile is Ref of scalar
if ( ref( $sFile ) eq 'SCALAR' ) {
if ( $_use_perlio ) {
open $oIo, "<", \$sFile;
}
else {
$oIo = IO::Scalar->new;
$oIo->open( $sFile );
}
}
#2. $sFile is a IO::Handle object
elsif ( UNIVERSAL::isa( $sFile, 'IO::Handle' ) ) {
$oIo = $sFile;
binmode( $oIo );
}
#3. $sFile is a simple filename string
elsif ( !ref( $sFile ) ) {
$oIo = IO::File->new;
$oIo->open( "<$sFile" ) || return undef;
binmode( $oIo );
}
my $sWk;
my $sBuff = '';
while ( $oIo->read( $sWk, 4096 ) ) { #4_096 has no special meanings
$sBuff .= $sWk;
}
$oIo->close();
#Not Excel file (simple method)
return ( undef, undef ) if ( substr( $sBuff, 0, 1 ) ne "\x09" );
return ( $sBuff, length( $sBuff ) );
}
#------------------------------------------------------------------------------
# _subBOF (for Spreadsheet::ParseExcel) Developers' Kit : P303
#------------------------------------------------------------------------------
sub _subBOF {
my ( $oBook, $bOp, $bLen, $sWk ) = @_;
my ( $iVer, $iDt ) = unpack( "v2", $sWk );
#Workbook Global
if ( $iDt == 0x0005 ) {
$oBook->{Version} = unpack( "v", $sWk );
$oBook->{BIFFVersion} =
( $oBook->{Version} == verExcel95 ) ? verBIFF5 : verBIFF8;
$oBook->{_CurSheet} = undef;
$oBook->{_CurSheet_} = -1;
}
#Worksheet or Dialogsheet
elsif ( $iDt != 0x0020 ) { #if($iDt == 0x0010)
if ( defined $oBook->{_CurSheet_} ) {
$oBook->{_CurSheet} = $oBook->{_CurSheet_} + 1;
$oBook->{_CurSheet_}++;
(
$oBook->{Worksheet}[ $oBook->{_CurSheet} ]->{SheetVersion},
$oBook->{Worksheet}[ $oBook->{_CurSheet} ]->{SheetType},
)
= unpack( "v2", $sWk )
if ( length( $sWk ) > 4 );
}
else {
$oBook->{BIFFVersion} = int( $bOp / 0x100 );
if ( ( $oBook->{BIFFVersion} == verBIFF2 )
|| ( $oBook->{BIFFVersion} == verBIFF3 )
|| ( $oBook->{BIFFVersion} == verBIFF4 ) )
{
$oBook->{Version} = $oBook->{BIFFVersion};
$oBook->{_CurSheet} = 0;
$oBook->{Worksheet}[ $oBook->{SheetCount} ] =
Spreadsheet::ParseExcel::Worksheet->new(
_Name => '',
Name => '',
_Book => $oBook,
_SheetNo => $oBook->{SheetCount},
);
$oBook->{SheetCount}++;
}
}
}
else {
# Set flag to ignore all chart records until we reach another BOF.
$oBook->{_skip_chart} = 1;
}
}
#------------------------------------------------------------------------------
# _subBlank (for Spreadsheet::ParseExcel) DK:P303
#------------------------------------------------------------------------------
sub _subBlank {
my ( $oBook, $bOp, $bLen, $sWk ) = @_;
my ( $iR, $iC, $iF ) = unpack( "v3", $sWk );
_NewCell(
$oBook, $iR, $iC,
Kind => 'BLANK',
Val => '',
FormatNo => $iF,
Format => $oBook->{Format}[$iF],
Numeric => 0,
Code => undef,
Book => $oBook,
);
#2.MaxRow, MaxCol, MinRow, MinCol
_SetDimension( $oBook, $iR, $iC, $iC );
}
#------------------------------------------------------------------------------
# _subInteger (for Spreadsheet::ParseExcel) Not in DK
#------------------------------------------------------------------------------
sub _subInteger {
my ( $oBook, $bOp, $bLen, $sWk ) = @_;
my ( $iR, $iC, $iF, $sTxt, $sDum );
( $iR, $iC, $iF, $sDum, $sTxt ) = unpack( "v3cv", $sWk );
_NewCell(
$oBook, $iR, $iC,
Kind => 'INTEGER',
Val => $sTxt,
FormatNo => $iF,
Format => $oBook->{Format}[$iF],
Numeric => 0,
Code => undef,
Book => $oBook,
);
#2.MaxRow, MaxCol, MinRow, MinCol
_SetDimension( $oBook, $iR, $iC, $iC );
}
#------------------------------------------------------------------------------
# _subNumber (for Spreadsheet::ParseExcel) : DK: P354
#------------------------------------------------------------------------------
sub _subNumber {
my ( $oBook, $bOp, $bLen, $sWk ) = @_;
my ( $iR, $iC, $iF ) = unpack( "v3", $sWk );
my $dVal = _convDval( substr( $sWk, 6, 8 ) );
_NewCell(
$oBook, $iR, $iC,
Kind => 'Number',
Val => $dVal,
FormatNo => $iF,
Format => $oBook->{Format}[$iF],
Numeric => 1,
Code => undef,
Book => $oBook,
);
#2.MaxRow, MaxCol, MinRow, MinCol
_SetDimension( $oBook, $iR, $iC, $iC );
}
#------------------------------------------------------------------------------
# _convDval (for Spreadsheet::ParseExcel)
#------------------------------------------------------------------------------
sub _convDval {
my ( $sWk ) = @_;
return
unpack( "d",
( $BIGENDIAN ) ? pack( "c8", reverse( unpack( "c8", $sWk ) ) ) : $sWk );
}
#------------------------------------------------------------------------------
# _subRString (for Spreadsheet::ParseExcel) DK:P405
#------------------------------------------------------------------------------
sub _subRString {
my ( $oBook, $bOp, $bLen, $sWk ) = @_;
my ( $iR, $iC, $iF, $iL, $sTxt );
( $iR, $iC, $iF, $iL ) = unpack( "v4", $sWk );
$sTxt = substr( $sWk, 8, $iL );
#Has STRUN
if ( length( $sWk ) > ( 8 + $iL ) ) {
_NewCell(
$oBook, $iR, $iC,
Kind => 'RString',
Val => $sTxt,
FormatNo => $iF,
Format => $oBook->{Format}[$iF],
Numeric => 0,
Code => '_native_', #undef,
Book => $oBook,
Rich => substr( $sWk, ( 8 + $iL ) + 1 ),
);
}
else {
_NewCell(
$oBook, $iR, $iC,
Kind => 'RString',
Val => $sTxt,
FormatNo => $iF,
Format => $oBook->{Format}[$iF],
Numeric => 0,
Code => '_native_',
Book => $oBook,
);
}
#2.MaxRow, MaxCol, MinRow, MinCol
_SetDimension( $oBook, $iR, $iC, $iC );
}
#------------------------------------------------------------------------------
# _subBoolErr (for Spreadsheet::ParseExcel) DK:P306
#------------------------------------------------------------------------------
sub _subBoolErr {
my ( $oBook, $bOp, $bLen, $sWk ) = @_;
my ( $iR, $iC, $iF ) = unpack( "v3", $sWk );
my ( $iVal, $iFlg ) = unpack( "cc", substr( $sWk, 6, 2 ) );
my $sTxt = DecodeBoolErr( $iVal, $iFlg );
_NewCell(
$oBook, $iR, $iC,
Kind => 'BoolError',
Val => $sTxt,
FormatNo => $iF,
Format => $oBook->{Format}[$iF],
Numeric => 0,
Code => undef,
Book => $oBook,
);
#2.MaxRow, MaxCol, MinRow, MinCol
_SetDimension( $oBook, $iR, $iC, $iC );
}
###############################################################################
#
# _subRK()
#
# Decode the RK BIFF record.
#
sub _subRK {
my ( $workbook, $biff_number, $length, $data ) = @_;
my ( $row, $col, $format_index, $rk_number ) = unpack( 'vvvV', $data );
my $number = _decode_rk_number( $rk_number );
_NewCell(
$workbook, $row, $col,
Kind => 'RK',
Val => $number,
FormatNo => $format_index,
Format => $workbook->{Format}->[$format_index],
Numeric => 1,
Code => undef,
Book => $workbook,
);
# Store the max and min row/col values.
_SetDimension( $workbook, $row, $col, $col );
}
#------------------------------------------------------------------------------
# _subArray (for Spreadsheet::ParseExcel) DK:P297
#------------------------------------------------------------------------------
sub _subArray {
my ( $oBook, $bOp, $bLen, $sWk ) = @_;
my ( $iBR, $iER, $iBC, $iEC ) = unpack( "v2c2", $sWk );
}
#------------------------------------------------------------------------------
# _subFormula (for Spreadsheet::ParseExcel) DK:P336
#------------------------------------------------------------------------------
sub _subFormula {
my ( $oBook, $bOp, $bLen, $sWk ) = @_;
my ( $iR, $iC, $iF ) = unpack( "v3", $sWk );
my ( $iFlg ) = unpack( "v", substr( $sWk, 12, 2 ) );
if ( $iFlg == 0xFFFF ) {
my ( $iKind ) = unpack( "c", substr( $sWk, 6, 1 ) );
my ( $iVal ) = unpack( "c", substr( $sWk, 8, 1 ) );
if ( ( $iKind == 1 ) or ( $iKind == 2 ) ) {
my $sTxt =
( $iKind == 1 )
? DecodeBoolErr( $iVal, 0 )
: DecodeBoolErr( $iVal, 1 );
_NewCell(
$oBook, $iR, $iC,
Kind => 'Formula Bool',
Val => $sTxt,
FormatNo => $iF,
Format => $oBook->{Format}[$iF],
Numeric => 0,
Code => undef,
Book => $oBook,
);
}
else { # Result (Reserve Only)
$oBook->{_PrevPos} = [ $iR, $iC, $iF ];
}
}
else {
my $dVal = _convDval( substr( $sWk, 6, 8 ) );
_NewCell(
$oBook, $iR, $iC,
Kind => 'Formula Number',
Val => $dVal,
FormatNo => $iF,
Format => $oBook->{Format}[$iF],
Numeric => 1,
Code => undef,
Book => $oBook,
);
}
#2.MaxRow, MaxCol, MinRow, MinCol
_SetDimension( $oBook, $iR, $iC, $iC );
}
#------------------------------------------------------------------------------
# _subString (for Spreadsheet::ParseExcel) DK:P414
#------------------------------------------------------------------------------
sub _subString {
my ( $oBook, $bOp, $bLen, $sWk ) = @_;
#Position (not enough for ARRAY)
my $iPos = $oBook->{_PrevPos};
return undef unless ( $iPos );
$oBook->{_PrevPos} = undef;
my ( $iR, $iC, $iF ) = @$iPos;
my ( $iLen, $sTxt, $sCode );
if ( $oBook->{BIFFVersion} == verBIFF8 ) {
my ( $raBuff, $iLen ) = _convBIFF8String( $oBook, $sWk, 1 );
$sTxt = $raBuff->[0];
$sCode = ( $raBuff->[1] ) ? 'ucs2' : undef;
}
elsif ( $oBook->{BIFFVersion} == verBIFF5 ) {
$sCode = '_native_';
$iLen = unpack( "v", $sWk );
$sTxt = substr( $sWk, 2, $iLen );
}
else {
$sCode = '_native_';
$iLen = unpack( "c", $sWk );
$sTxt = substr( $sWk, 1, $iLen );
}
_NewCell(
$oBook, $iR, $iC,
Kind => 'String',
Val => $sTxt,
FormatNo => $iF,
Format => $oBook->{Format}[$iF],
Numeric => 0,
Code => $sCode,
Book => $oBook,
);
#2.MaxRow, MaxCol, MinRow, MinCol
_SetDimension( $oBook, $iR, $iC, $iC );
}
#------------------------------------------------------------------------------
# _subLabel (for Spreadsheet::ParseExcel) DK:P344
#------------------------------------------------------------------------------
sub _subLabel {
my ( $oBook, $bOp, $bLen, $sWk ) = @_;
my ( $iR, $iC, $iF ) = unpack( "v3", $sWk );
my ( $sLbl, $sCode );
#BIFF8
if ( $oBook->{BIFFVersion} >= verBIFF8 ) {
my ( $raBuff, $iLen, $iStPos, $iLenS ) =
_convBIFF8String( $oBook, substr( $sWk, 6 ), 1 );
$sLbl = $raBuff->[0];
$sCode = ( $raBuff->[1] ) ? 'ucs2' : undef;
}
#Before BIFF8
else {
$sLbl = substr( $sWk, 8 );
$sCode = '_native_';
}
_NewCell(
$oBook, $iR, $iC,
Kind => 'Label',
Val => $sLbl,
FormatNo => $iF,
Format => $oBook->{Format}[$iF],
Numeric => 0,
Code => $sCode,
Book => $oBook,
);
#2.MaxRow, MaxCol, MinRow, MinCol
_SetDimension( $oBook, $iR, $iC, $iC );
}
###############################################################################
#
# _subMulRK()
#
# Decode the Multiple RK BIFF record.
#
sub _subMulRK {
my ( $workbook, $biff_number, $length, $data ) = @_;
# JMN: I don't know why this is here.
return if $workbook->{SheetCount} <= 0;
my ( $row, $first_col ) = unpack( "v2", $data );
my $last_col = unpack( "v", substr( $data, length( $data ) - 2, 2 ) );
# Iterate over the RK array and decode the data.
my $pos = 4;
for my $col ( $first_col .. $last_col ) {
my $data = substr( $data, $pos, 6 );
my ( $format_index, $rk_number ) = unpack 'vV', $data;
my $number = _decode_rk_number( $rk_number );
_NewCell(
$workbook, $row, $col,
Kind => 'MulRK',
Val => $number,
FormatNo => $format_index,
Format => $workbook->{Format}->[$format_index],
Numeric => 1,
Code => undef,
Book => $workbook,
);
$pos += 6;
}
# Store the max and min row/col values.
_SetDimension( $workbook, $row, $first_col, $last_col );
}
#------------------------------------------------------------------------------
# _subMulBlank (for Spreadsheet::ParseExcel) DK:P349
#------------------------------------------------------------------------------
sub _subMulBlank {
my ( $oBook, $bOp, $bLen, $sWk ) = @_;
my ( $iR, $iSc ) = unpack( "v2", $sWk );
my $iEc = unpack( "v", substr( $sWk, length( $sWk ) - 2, 2 ) );
my $iPos = 4;
for ( my $iC = $iSc ; $iC <= $iEc ; $iC++ ) {
my $iF = unpack( 'v', substr( $sWk, $iPos, 2 ) );
_NewCell(
$oBook, $iR, $iC,
Kind => 'MulBlank',
Val => '',
FormatNo => $iF,
Format => $oBook->{Format}[$iF],
Numeric => 0,
Code => undef,
Book => $oBook,
);
$iPos += 2;
}
#2.MaxRow, MaxCol, MinRow, MinCol
_SetDimension( $oBook, $iR, $iSc, $iEc );
}
#------------------------------------------------------------------------------
# _subLabelSST (for Spreadsheet::ParseExcel) DK: P345
#------------------------------------------------------------------------------
sub _subLabelSST {
my ( $oBook, $bOp, $bLen, $sWk ) = @_;
my ( $iR, $iC, $iF, $iIdx ) = unpack( 'v3V', $sWk );
_NewCell(
$oBook, $iR, $iC,
Kind => 'PackedIdx',
Val => $oBook->{PkgStr}[$iIdx]->{Text},
FormatNo => $iF,
Format => $oBook->{Format}[$iF],
Numeric => 0,
Code => ( $oBook->{PkgStr}[$iIdx]->{Unicode} ) ? 'ucs2' : undef,
Book => $oBook,
Rich => $oBook->{PkgStr}[$iIdx]->{Rich},
);
#2.MaxRow, MaxCol, MinRow, MinCol
_SetDimension( $oBook, $iR, $iC, $iC );
}
#------------------------------------------------------------------------------
# _subFlg1904 (for Spreadsheet::ParseExcel) DK:P296
#------------------------------------------------------------------------------
sub _subFlg1904 {
my ( $oBook, $bOp, $bLen, $sWk ) = @_;
$oBook->{Flg1904} = unpack( "v", $sWk );
}
#------------------------------------------------------------------------------
# _subRow (for Spreadsheet::ParseExcel) DK:P403
#------------------------------------------------------------------------------
sub _subRow {
my ( $oBook, $bOp, $bLen, $sWk ) = @_;
return undef unless ( defined $oBook->{_CurSheet} );
#0. Get Worksheet info (MaxRow, MaxCol, MinRow, MinCol)
my ( $iR, $iSc, $iEc, $iHght, $undef1, $undef2, $iGr, $iXf ) =
unpack( "v8", $sWk );
$iEc--;
if ( $iGr & 0x20 ) {
$oBook->{Worksheet}[ $oBook->{_CurSheet} ]->{RowHidden}[$iR] = 1;
}
$oBook->{Worksheet}[ $oBook->{_CurSheet} ]->{RowHeight}[$iR] = $iHght / 20;
#2.MaxRow, MaxCol, MinRow, MinCol
_SetDimension( $oBook, $iR, $iSc, $iEc );
}
#------------------------------------------------------------------------------
# _SetDimension (for Spreadsheet::ParseExcel)
#------------------------------------------------------------------------------
sub _SetDimension {
my ( $oBook, $iR, $iSc, $iEc ) = @_;
return undef unless ( defined $oBook->{_CurSheet} );
#2.MaxRow, MaxCol, MinRow, MinCol
#2.1 MinRow
$oBook->{Worksheet}[ $oBook->{_CurSheet} ]->{MinRow} = $iR
unless ( defined $oBook->{Worksheet}[ $oBook->{_CurSheet} ]->{MinRow} )
and ( $oBook->{Worksheet}[ $oBook->{_CurSheet} ]->{MinRow} <= $iR );
#2.2 MaxRow
$oBook->{Worksheet}[ $oBook->{_CurSheet} ]->{MaxRow} = $iR
unless ( defined $oBook->{Worksheet}[ $oBook->{_CurSheet} ]->{MaxRow} )
and ( $oBook->{Worksheet}[ $oBook->{_CurSheet} ]->{MaxRow} > $iR );
#2.3 MinCol
$oBook->{Worksheet}[ $oBook->{_CurSheet} ]->{MinCol} = $iSc
unless ( defined $oBook->{Worksheet}[ $oBook->{_CurSheet} ]->{MinCol} )
and ( $oBook->{Worksheet}[ $oBook->{_CurSheet} ]->{MinCol} <= $iSc );
#2.4 MaxCol
$oBook->{Worksheet}[ $oBook->{_CurSheet} ]->{MaxCol} = $iEc
unless ( defined $oBook->{Worksheet}[ $oBook->{_CurSheet} ]->{MaxCol} )
and ( $oBook->{Worksheet}[ $oBook->{_CurSheet} ]->{MaxCol} > $iEc );
}
#------------------------------------------------------------------------------
# _subDefaultRowHeight (for Spreadsheet::ParseExcel) DK: P318
#------------------------------------------------------------------------------
sub _subDefaultRowHeight {
my ( $oBook, $bOp, $bLen, $sWk ) = @_;
return undef unless ( defined $oBook->{_CurSheet} );
#1. RowHeight
my ( $iDum, $iHght ) = unpack( "v2", $sWk );
$oBook->{Worksheet}[ $oBook->{_CurSheet} ]->{DefRowHeight} = $iHght / 20;
}
#------------------------------------------------------------------------------
# _subStandardWidth(for Spreadsheet::ParseExcel) DK:P413
#------------------------------------------------------------------------------
sub _subStandardWidth {
my ( $oBook, $bOp, $bLen, $sWk ) = @_;
my $iW = unpack( "v", $sWk );
$oBook->{StandardWidth} = _convert_col_width( $oBook, $iW );
}
###############################################################################
#
# _subDefColWidth()
#
# Read the DEFCOLWIDTH Biff record. This gives the width in terms of chars
# and is different from the width in the COLINFO record.
#
sub _subDefColWidth {
my ( $self, $record, $length, $data ) = @_;
my $width = unpack 'v', $data;
# Adjustment for default Arial 10 width.
$width = 8.43 if $width == 8;
$self->{Worksheet}->[ $self->{_CurSheet} ]->{DefColWidth} = $width;
}
###############################################################################
#
# _convert_col_width()
#
# Converts from the internal Excel column width units to user units seen in the
# interface. It is first necessary to convert the internal width to pixels and
# then to user units. The conversion is specific to a default font of Arial 10.
# TODO, the conversion should be extended to other fonts and sizes.
#
sub _convert_col_width {
my $self = shift;
my $excel_width = shift;
# Convert from Excel units to pixels (rounded up).
my $pixels = int( 0.5 + $excel_width * 7 / 256 );
# Convert from pixels to user units.
# The conversion is different for columns <= 1 user unit (12 pixels).
my $user_width;
if ( $pixels <= 12 ) {
$user_width = $pixels / 12;
}
else {
$user_width = ( $pixels - 5 ) / 7;
}
# Round up to 2 decimal places.
$user_width = int( $user_width * 100 + 0.5 ) / 100;
return $user_width;
}
#------------------------------------------------------------------------------
# _subColInfo (for Spreadsheet::ParseExcel) DK:P309
#------------------------------------------------------------------------------
sub _subColInfo {
my ( $oBook, $bOp, $bLen, $sWk ) = @_;
return undef unless defined $oBook->{_CurSheet};
my ( $iSc, $iEc, $iW, $iXF, $iGr ) = unpack( "v5", $sWk );
for ( my $i = $iSc ; $i <= $iEc ; $i++ ) {
$oBook->{Worksheet}[ $oBook->{_CurSheet} ]->{ColWidth}[$i] =
_convert_col_width( $oBook, $iW );
$oBook->{Worksheet}[ $oBook->{_CurSheet} ]->{ColFmtNo}[$i] = $iXF;
if ( $iGr & 0x01 ) {
$oBook->{Worksheet}[ $oBook->{_CurSheet} ]->{ColHidden}[$i] = 1;
}
}
}
#------------------------------------------------------------------------------
# _subWindow1 Window information P 273
#------------------------------------------------------------------------------
sub _subWindow1 {
my ( $workbook, $op, $len, $wk ) = @_;
return if ( $workbook->{BIFFVersion} <= verBIFF4() );
my (
$hpos, $vpos, $width,
$height, $options, $active,
$firsttab, $numselected, $tabbarwidth
) = unpack( "v9", $wk );
$workbook->{ActiveSheet} = $active;
}
#------------------------------------------------------------------------------
# _subSheetLayout OpenOffice 5.96 (P207)
#------------------------------------------------------------------------------
sub _subSheetLayout {
my ( $workbook, $op, $len, $wk ) = @_;
my @unused;
(
my $rc,
@unused[ 1 .. 10 ],
@unused[ 11 .. 14 ],
my $color, @unused[ 15, 16 ]
) = unpack( "vC10C4vC2", $wk );
return unless ( $rc == 0x0862 );
$workbook->{Worksheet}[ $workbook->{_CurSheet} ]->{TabColor} = $color;
}
#------------------------------------------------------------------------------
# _subHyperlink OpenOffice 5.96 (P182)
#
# Also see: http://msdn.microsoft.com/en-us/library/gg615407(v=office.14).aspx
#------------------------------------------------------------------------------
# Helper: Extract a GID, returns as text string
sub _getguid {
my( $wk ) = @_;
my( $text, $guidl, $guids1, $guids2, @guidb );
( $guidl, $guids1, $guids2, @guidb[0..7] ) = unpack( 'Vv2C8', $wk );
$text = sprintf( '%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X', $guidl, $guids1, $guids2, @guidb);
return $text;
}
# Helper: Extract a counted (16-bit) unicode string, returns string,
# updates $offset
# $zterm == 1 if string is null-terminated.
# $bc if length is in bytes (not chars)
sub _getustr {
my( $wk, $offset, $zterm, $bc ) = @_;
my $len = unpack( 'V', substr( $wk, $offset ) );
$offset += 4;
if( $bc ) {
$len /= 2;
}
$len -= $zterm;
my $text = join( '', map { chr $_ } unpack( "v$len", substr( $wk, $offset ) ) );
$text =~ s/\0.*\z// if( $zterm );
$_[1] = ( $offset += ($len + $zterm) *2 );
return $text;
}
# HYPERLINK record
sub _subHyperlink {
my ( $workbook, $op, $len, $wk ) = @_;
# REF
my( $srow, $erow, $scol, $ecol ) = unpack( 'v4', $wk );
my $guid = _getguid( substr( $wk, 8 ) );
return unless( $guid eq '79EAC9D0-BAF9-11CE-8C82-00AA004BA90B' );
my( $stmvers, $flags ) = unpack( 'VV', substr( $wk, 24 ) );
return if( $flags & 0x60 || $stmvers != 2 );
my $offset = 32;
my( $desc,$frame, $link, $mark );
if( ($flags & 0x14) == 0x14 ) {
$desc = _getustr( $wk, $offset, 1, 0 );
}
if( $flags & 0x80 ) {
$frame = _getustr( $wk, $offset, 1, 0 );
}
$link = '';
if( $flags & 0x100 ) {
# UNC path
$link = 'file:///' . _getustr( $wk, $offset, 1, 0 );
} elsif( $flags & 0x1 ) {
# Has link (URI)
$guid = _getguid( substr( $wk, $offset ) );
$offset += 16;
if( $guid eq '79EAC9E0-BAF9-11CE-8C82-00AA004BA90B' ) {
# URI
$link = _getustr( $wk, $offset, 1, 1 );
} elsif( $guid eq '00000303-0000-0000-C000-000000000046' ) {
# Local file
$link = 'file:///';
# !($flags & 2) = 'relative path'
if( !($flags & 0x2) ) {
my $file = $workbook->{File};
if( defined $file && length $file ) {
$link .= (fileparse($file))[1];
}
else {
$link .= '%REL%'
}
}
my $dirn = unpack( 'v', substr( $wk, $offset ) );
$offset += 2;
$link .= '..\\' x $dirn;
my $namelen = unpack( 'V', substr( $wk, $offset ) );
$offset += 4;
my $name = unpack( 'Z*', substr( $wk, $offset ) );
$offset += $namelen;
$offset += 24;
my $size = unpack( 'V', substr( $wk, $offset ) );
$offset += 4;
if( $size ) {
my $xlen = unpack( 'V', substr( $wk, $offset ) ) / 2;
$name = join( '', map { chr $_} unpack( "v$xlen", substr( $wk, $offset+4+2) ) );
$offset += $size;
}
$link .= $name;
} else {
return;
}
}
# Text mark (Fragment identifier)
if( $flags & 0x8 ) {
# Cellrefs contain reserved characters, so url-encode
my $fragment = _getustr( $wk, $offset, 1 );
$fragment =~ s/([^\w.~-])/sprintf( '%%%02X', ord( $1 ) )/gems;
$link .= '#' . $fragment;
}
# Update loop at end of parse() if this changes
push @{ $workbook->{Worksheet}[ $workbook->{_CurSheet} ]->{HyperLinks} }, [
$desc, $link, $frame, $srow, $erow, $scol, $ecol ];
}
#------------------------------------------------------------------------------
# _subSST (for Spreadsheet::ParseExcel) DK:P413
#------------------------------------------------------------------------------
sub _subSST {
my ( $oBook, $bOp, $bLen, $sWk ) = @_;
_subStrWk( $oBook, substr( $sWk, 8 ) );
}
#------------------------------------------------------------------------------
# _subContinue (for Spreadsheet::ParseExcel) DK:P311
#------------------------------------------------------------------------------
sub _subContinue {
my ( $oBook, $bOp, $bLen, $sWk ) = @_;
#if(defined $self->{FuncTbl}->{$bOp}) {
# $self->{FuncTbl}->{$PREFUNC}->($oBook, $bOp, $bLen, $sWk);
#}
_subStrWk( $oBook, $sWk, 1 ) if ( $PREFUNC == 0xFC );
}
#------------------------------------------------------------------------------
# _subWriteAccess (for Spreadsheet::ParseExcel) DK:P451
#------------------------------------------------------------------------------
sub _subWriteAccess {
my ( $oBook, $bOp, $bLen, $sWk ) = @_;
return if ( defined $oBook->{_Author} );
#BIFF8
if ( $oBook->{BIFFVersion} >= verBIFF8 ) {
$oBook->{Author} = _convBIFF8String( $oBook, $sWk );
}
#Before BIFF8
else {
my ( $iLen ) = unpack( "c", $sWk );
$oBook->{Author} =
$oBook->{FmtClass}->TextFmt( substr( $sWk, 1, $iLen ), '_native_' );
}
}
#------------------------------------------------------------------------------
# _convBIFF8String (for Spreadsheet::ParseExcel)
#------------------------------------------------------------------------------
sub _convBIFF8String {
my ( $oBook, $sWk, $iCnvFlg ) = @_;
my ( $iLen, $iFlg ) = unpack( "vc", $sWk );
my ( $iHigh, $iExt, $iRich ) = ( $iFlg & 0x01, $iFlg & 0x04, $iFlg & 0x08 );
my ( $iStPos, $iExtCnt, $iRichCnt, $sStr );
#2. Rich and Ext
if ( $iRich && $iExt ) {
$iStPos = 9;
( $iRichCnt, $iExtCnt ) = unpack( 'vV', substr( $sWk, 3, 6 ) );
}
elsif ( $iRich ) { #Only Rich
$iStPos = 5;
$iRichCnt = unpack( 'v', substr( $sWk, 3, 2 ) );
$iExtCnt = 0;
}
elsif ( $iExt ) { #Only Ext
$iStPos = 7;
$iRichCnt = 0;
$iExtCnt = unpack( 'V', substr( $sWk, 3, 4 ) );
}
else { #Nothing Special
$iStPos = 3;
$iExtCnt = 0;
$iRichCnt = 0;
}
#3.Get String
if ( $iHigh ) { #Compressed
$iLen *= 2;
$sStr = substr( $sWk, $iStPos, $iLen );
_SwapForUnicode( \$sStr );
$sStr = $oBook->{FmtClass}->TextFmt( $sStr, 'ucs2' )
unless ( $iCnvFlg );
}
else { #Not Compressed
$sStr = substr( $sWk, $iStPos, $iLen );
$sStr = $oBook->{FmtClass}->TextFmt( $sStr, undef ) unless ( $iCnvFlg );
}
#4. return
if ( wantarray ) {
#4.1 Get Rich and Ext
if ( length( $sWk ) < $iStPos + $iLen + $iRichCnt * 4 + $iExtCnt ) {
return (
[ undef, $iHigh, undef, undef ],
$iStPos + $iLen + $iRichCnt * 4 + $iExtCnt,
$iStPos, $iLen
);
}
else {
return (
[
$sStr,
$iHigh,
substr( $sWk, $iStPos + $iLen, $iRichCnt * 4 ),
substr( $sWk, $iStPos + $iLen + $iRichCnt * 4, $iExtCnt )
],
$iStPos + $iLen + $iRichCnt * 4 + $iExtCnt,
$iStPos, $iLen
);
}
}
else {
return $sStr;
}
}
#------------------------------------------------------------------------------
# _subXF (for Spreadsheet::ParseExcel) DK:P453
#------------------------------------------------------------------------------
sub _subXF {
my ( $oBook, $bOp, $bLen, $sWk ) = @_;
my ( $iFnt, $iIdx );
my (
$iLock, $iHidden, $iStyle, $i123, $iAlH, $iWrap,
$iAlV, $iJustL, $iRotate, $iInd, $iShrink, $iMerge,
$iReadDir, $iBdrD, $iBdrSL, $iBdrSR, $iBdrST, $iBdrSB,
$iBdrSD, $iBdrCL, $iBdrCR, $iBdrCT, $iBdrCB, $iBdrCD,
$iFillP, $iFillCF, $iFillCB
);
if ( $oBook->{BIFFVersion} == verBIFF4 ) {
# Minimal support for Excel 4. We just get the font and format indices
# so that the cell data value can be formatted.
( $iFnt, $iIdx, ) = unpack( "CC", $sWk );
}
elsif ( $oBook->{BIFFVersion} == verBIFF8 ) {
my ( $iGen, $iAlign, $iGen2, $iBdr1, $iBdr2, $iBdr3, $iPtn );
( $iFnt, $iIdx, $iGen, $iAlign, $iGen2, $iBdr1, $iBdr2, $iBdr3, $iPtn )
= unpack( "v7Vv", $sWk );
$iLock = ( $iGen & 0x01 ) ? 1 : 0;
$iHidden = ( $iGen & 0x02 ) ? 1 : 0;
$iStyle = ( $iGen & 0x04 ) ? 1 : 0;
$i123 = ( $iGen & 0x08 ) ? 1 : 0;
$iAlH = ( $iAlign & 0x07 );
$iWrap = ( $iAlign & 0x08 ) ? 1 : 0;
$iAlV = ( $iAlign & 0x70 ) / 0x10;
$iJustL = ( $iAlign & 0x80 ) ? 1 : 0;
$iRotate = ( ( $iAlign & 0xFF00 ) / 0x100 ) & 0x00FF;
$iRotate = 90 if ( $iRotate == 255 );
$iRotate = 90 - $iRotate if ( $iRotate > 90 );
$iInd = ( $iGen2 & 0x0F );
$iShrink = ( $iGen2 & 0x10 ) ? 1 : 0;
$iMerge = ( $iGen2 & 0x20 ) ? 1 : 0;
$iReadDir = ( ( $iGen2 & 0xC0 ) / 0x40 ) & 0x03;
$iBdrSL = $iBdr1 & 0x0F;
$iBdrSR = ( ( $iBdr1 & 0xF0 ) / 0x10 ) & 0x0F;
$iBdrST = ( ( $iBdr1 & 0xF00 ) / 0x100 ) & 0x0F;
$iBdrSB = ( ( $iBdr1 & 0xF000 ) / 0x1000 ) & 0x0F;
$iBdrCL = ( ( $iBdr2 & 0x7F ) ) & 0x7F;
$iBdrCR = ( ( $iBdr2 & 0x3F80 ) / 0x80 ) & 0x7F;
$iBdrD = ( ( $iBdr2 & 0xC000 ) / 0x4000 ) & 0x3;
$iBdrCT = ( ( $iBdr3 & 0x7F ) ) & 0x7F;
$iBdrCB = ( ( $iBdr3 & 0x3F80 ) / 0x80 ) & 0x7F;
$iBdrCD = ( ( $iBdr3 & 0x1FC000 ) / 0x4000 ) & 0x7F;
$iBdrSD = ( ( $iBdr3 & 0x1E00000 ) / 0x200000 ) & 0xF;
$iFillP = ( ( $iBdr3 & 0xFC000000 ) / 0x4000000 ) & 0x3F;
$iFillCF = ( $iPtn & 0x7F );
$iFillCB = ( ( $iPtn & 0x3F80 ) / 0x80 ) & 0x7F;
}
else {
my ( $iGen, $iAlign, $iPtn, $iPtn2, $iBdr1, $iBdr2 );
( $iFnt, $iIdx, $iGen, $iAlign, $iPtn, $iPtn2, $iBdr1, $iBdr2 ) =
unpack( "v8", $sWk );
$iLock = ( $iGen & 0x01 ) ? 1 : 0;
$iHidden = ( $iGen & 0x02 ) ? 1 : 0;
$iStyle = ( $iGen & 0x04 ) ? 1 : 0;
$i123 = ( $iGen & 0x08 ) ? 1 : 0;
$iAlH = ( $iAlign & 0x07 );
$iWrap = ( $iAlign & 0x08 ) ? 1 : 0;
$iAlV = ( $iAlign & 0x70 ) / 0x10;
$iJustL = ( $iAlign & 0x80 ) ? 1 : 0;
$iRotate = ( ( $iAlign & 0x300 ) / 0x100 ) & 0x3;
$iFillCF = ( $iPtn & 0x7F );
$iFillCB = ( ( $iPtn & 0x1F80 ) / 0x80 ) & 0x7F;
$iFillP = ( $iPtn2 & 0x3F );
$iBdrSB = ( ( $iPtn2 & 0x1C0 ) / 0x40 ) & 0x7;
$iBdrCB = ( ( $iPtn2 & 0xFE00 ) / 0x200 ) & 0x7F;
$iBdrST = ( $iBdr1 & 0x07 );
$iBdrSL = ( ( $iBdr1 & 0x38 ) / 0x8 ) & 0x07;
$iBdrSR = ( ( $iBdr1 & 0x1C0 ) / 0x40 ) & 0x07;
$iBdrCT = ( ( $iBdr1 & 0xFE00 ) / 0x200 ) & 0x7F;
$iBdrCL = ( $iBdr2 & 0x7F ) & 0x7F;
$iBdrCR = ( ( $iBdr2 & 0x3F80 ) / 0x80 ) & 0x7F;
}
push @{ $oBook->{Format} }, Spreadsheet::ParseExcel::Format->new(
FontNo => $iFnt,
Font => $oBook->{Font}[$iFnt],
FmtIdx => $iIdx,
Lock => $iLock,
Hidden => $iHidden,
Style => $iStyle,
Key123 => $i123,
AlignH => $iAlH,
Wrap => $iWrap,
AlignV => $iAlV,
JustLast => $iJustL,
Rotate => $iRotate,
Indent => $iInd,
Shrink => $iShrink,
Merge => $iMerge,
ReadDir => $iReadDir,
BdrStyle => [ $iBdrSL, $iBdrSR, $iBdrST, $iBdrSB ],
BdrColor => [ $iBdrCL, $iBdrCR, $iBdrCT, $iBdrCB ],
BdrDiag => [ $iBdrD, $iBdrSD, $iBdrCD ],
Fill => [ $iFillP, $iFillCF, $iFillCB ],
);
}
#------------------------------------------------------------------------------
# _subFormat (for Spreadsheet::ParseExcel) DK: P336
#------------------------------------------------------------------------------
sub _subFormat {
my ( $oBook, $bOp, $bLen, $sWk ) = @_;
my $sFmt;
if ( $oBook->{BIFFVersion} <= verBIFF5 ) {
$sFmt = substr( $sWk, 3, unpack( 'c', substr( $sWk, 2, 1 ) ) );
$sFmt = $oBook->{FmtClass}->TextFmt( $sFmt, '_native_' );
}
else {
$sFmt = _convBIFF8String( $oBook, substr( $sWk, 2 ) );
}
my $format_index = unpack( 'v', substr( $sWk, 0, 2 ) );
# Excel 4 and earlier used an index of 0 to indicate that a built-in format
# that was stored implicitly.
if ( $oBook->{BIFFVersion} <= verBIFF4 && $format_index == 0 ) {
$format_index = keys %{ $oBook->{FormatStr} };
}
$oBook->{FormatStr}->{$format_index} = $sFmt;
}
#------------------------------------------------------------------------------
# _subPalette (for Spreadsheet::ParseExcel) DK: P393
#------------------------------------------------------------------------------
sub _subPalette {
my ( $oBook, $bOp, $bLen, $sWk ) = @_;
for ( my $i = 0 ; $i < unpack( 'v', $sWk ) ; $i++ ) {
# push @aColor, unpack('H6', substr($sWk, $i*4+2));
$oBook->{aColor}[ $i + 8 ] = unpack( 'H6', substr( $sWk, $i * 4 + 2 ) );
}
}
#------------------------------------------------------------------------------
# _subFont (for Spreadsheet::ParseExcel) DK:P333
#------------------------------------------------------------------------------
sub _subFont {
my ( $oBook, $bOp, $bLen, $sWk ) = @_;
my ( $iHeight, $iAttr, $iCIdx, $iBold, $iSuper, $iUnderline, $sFntName );
my ( $bBold, $bItalic, $bUnderline, $bStrikeout );
if ( $oBook->{BIFFVersion} == verBIFF8 ) {
( $iHeight, $iAttr, $iCIdx, $iBold, $iSuper, $iUnderline ) =
unpack( "v5c", $sWk );
my ( $iSize, $iHigh ) = unpack( 'cc', substr( $sWk, 14, 2 ) );
if ( $iHigh ) {
$sFntName = substr( $sWk, 16, $iSize * 2 );
_SwapForUnicode( \$sFntName );
$sFntName = $oBook->{FmtClass}->TextFmt( $sFntName, 'ucs2' );
}
else {
$sFntName = substr( $sWk, 16, $iSize );
$sFntName = $oBook->{FmtClass}->TextFmt( $sFntName, '_native_' );
}
$bBold = ( $iBold >= 0x2BC ) ? 1 : 0;
$bItalic = ( $iAttr & 0x02 ) ? 1 : 0;
$bStrikeout = ( $iAttr & 0x08 ) ? 1 : 0;
$bUnderline = ( $iUnderline ) ? 1 : 0;
}
elsif ( $oBook->{BIFFVersion} == verBIFF5 ) {
( $iHeight, $iAttr, $iCIdx, $iBold, $iSuper, $iUnderline ) =
unpack( "v5c", $sWk );
$sFntName =
$oBook->{FmtClass}
->TextFmt( substr( $sWk, 15, unpack( "c", substr( $sWk, 14, 1 ) ) ),
'_native_' );
$bBold = ( $iBold >= 0x2BC ) ? 1 : 0;
$bItalic = ( $iAttr & 0x02 ) ? 1 : 0;
$bStrikeout = ( $iAttr & 0x08 ) ? 1 : 0;
$bUnderline = ( $iUnderline ) ? 1 : 0;
}
else {
( $iHeight, $iAttr ) = unpack( "v2", $sWk );
$iCIdx = undef;
$iSuper = 0;
$bBold = ( $iAttr & 0x01 ) ? 1 : 0;
$bItalic = ( $iAttr & 0x02 ) ? 1 : 0;
$bUnderline = ( $iAttr & 0x04 ) ? 1 : 0;
$bStrikeout = ( $iAttr & 0x08 ) ? 1 : 0;
$sFntName = substr( $sWk, 5, unpack( "c", substr( $sWk, 4, 1 ) ) );
}
push @{ $oBook->{Font} }, Spreadsheet::ParseExcel::Font->new(
Height => $iHeight / 20.0,
Attr => $iAttr,
Color => $iCIdx,
Super => $iSuper,
UnderlineStyle => $iUnderline,
Name => $sFntName,
Bold => $bBold,
Italic => $bItalic,
Underline => $bUnderline,
Strikeout => $bStrikeout,
);
#Skip Font[4]
push @{ $oBook->{Font} }, {} if ( scalar( @{ $oBook->{Font} } ) == 4 );
}
#------------------------------------------------------------------------------
# _subBoundSheet (for Spreadsheet::ParseExcel): DK: P307
#------------------------------------------------------------------------------
sub _subBoundSheet {
my ( $oBook, $bOp, $bLen, $sWk ) = @_;
my ( $iPos, $iGr, $iKind ) = unpack( "Lc2", $sWk );
$iKind &= 0x0F;
return if ( ( $iKind != 0x00 ) && ( $iKind != 0x01 ) );
if ( $oBook->{BIFFVersion} >= verBIFF8 ) {
my ( $iSize, $iUni ) = unpack( "cc", substr( $sWk, 6, 2 ) );
my $sWsName = substr( $sWk, 8 );
if ( $iUni & 0x01 ) {
_SwapForUnicode( \$sWsName );
$sWsName = $oBook->{FmtClass}->TextFmt( $sWsName, 'ucs2' );
}
$oBook->{Worksheet}[ $oBook->{SheetCount} ] =
Spreadsheet::ParseExcel::Worksheet->new(
Name => $sWsName,
Kind => $iKind,
_Pos => $iPos,
_Book => $oBook,
_SheetNo => $oBook->{SheetCount},
SheetHidden => $iGr & 0x03
);
}
else {
$oBook->{Worksheet}[ $oBook->{SheetCount} ] =
Spreadsheet::ParseExcel::Worksheet->new(
Name =>
$oBook->{FmtClass}->TextFmt( substr( $sWk, 7 ), '_native_' ),
Kind => $iKind,
_Pos => $iPos,
_Book => $oBook,
_SheetNo => $oBook->{SheetCount},
SheetHidden => $iGr & 0x03
);
}
$oBook->{SheetCount}++;
}
#------------------------------------------------------------------------------
# _subHeader (for Spreadsheet::ParseExcel) DK: P340
#------------------------------------------------------------------------------
sub _subHeader {
my ( $oBook, $bOp, $bLen, $sWk ) = @_;
return undef unless ( defined $oBook->{_CurSheet} );
my $sW;
if ( !defined $sWk ) {
$oBook->{Worksheet}[ $oBook->{_CurSheet} ]->{Header} = undef;
return;
}
#BIFF8
if ( $oBook->{BIFFVersion} >= verBIFF8 ) {
$sW = _convBIFF8String( $oBook, $sWk );
$oBook->{Worksheet}[ $oBook->{_CurSheet} ]->{Header} =
( $sW eq "\x00" ) ? undef : $sW;
}
#Before BIFF8
else {
my ( $iLen ) = unpack( "c", $sWk );
$sW =
$oBook->{FmtClass}->TextFmt( substr( $sWk, 1, $iLen ), '_native_' );
$oBook->{Worksheet}[ $oBook->{_CurSheet} ]->{Header} =
( $sW eq "\x00\x00\x00" ) ? undef : $sW;
}
}
#------------------------------------------------------------------------------
# _subFooter (for Spreadsheet::ParseExcel) DK: P335
#------------------------------------------------------------------------------
sub _subFooter {
my ( $oBook, $bOp, $bLen, $sWk ) = @_;
return undef unless ( defined $oBook->{_CurSheet} );
my $sW;
if ( !defined $sWk ) {
$oBook->{Worksheet}[ $oBook->{_CurSheet} ]->{Footer} = undef;
return;
}
#BIFF8
if ( $oBook->{BIFFVersion} >= verBIFF8 ) {
$sW = _convBIFF8String( $oBook, $sWk );
$oBook->{Worksheet}[ $oBook->{_CurSheet} ]->{Footer} =
( $sW eq "\x00" ) ? undef : $sW;
}
#Before BIFF8
else {
my ( $iLen ) = unpack( "c", $sWk );
$sW =
$oBook->{FmtClass}->TextFmt( substr( $sWk, 1, $iLen ), '_native_' );
$oBook->{Worksheet}[ $oBook->{_CurSheet} ]->{Footer} =
( $sW eq "\x00\x00\x00" ) ? undef : $sW;
}
}
#------------------------------------------------------------------------------
# _subHPageBreak (for Spreadsheet::ParseExcel) DK: P341
#------------------------------------------------------------------------------
sub _subHPageBreak {
my ( $oBook, $bOp, $bLen, $sWk ) = @_;
my @aBreak;
my $iCnt = unpack( "v", $sWk );
return undef unless ( defined $oBook->{_CurSheet} );
#BIFF8
if ( $oBook->{BIFFVersion} >= verBIFF8 ) {
for ( my $i = 0 ; $i < $iCnt ; $i++ ) {
my ( $iRow, $iColB, $iColE ) =
unpack( 'v3', substr( $sWk, 2 + $i * 6, 6 ) );
# push @aBreak, [$iRow, $iColB, $iColE];
push @aBreak, $iRow;
}
}
#Before BIFF8
else {
for ( my $i = 0 ; $i < $iCnt ; $i++ ) {
my ( $iRow ) = unpack( 'v', substr( $sWk, 2 + $i * 2, 2 ) );
push @aBreak, $iRow;
# push @aBreak, [$iRow, 0, 255];
}
}
@aBreak = sort { $a <=> $b } @aBreak;
$oBook->{Worksheet}[ $oBook->{_CurSheet} ]->{HPageBreak} = \@aBreak;
}
#------------------------------------------------------------------------------
# _subVPageBreak (for Spreadsheet::ParseExcel) DK: P447
#------------------------------------------------------------------------------
sub _subVPageBreak {
my ( $oBook, $bOp, $bLen, $sWk ) = @_;
return undef unless ( defined $oBook->{_CurSheet} );
my @aBreak;
my $iCnt = unpack( "v", $sWk );
#BIFF8
if ( $oBook->{BIFFVersion} >= verBIFF8 ) {
for ( my $i = 0 ; $i < $iCnt ; $i++ ) {
my ( $iCol, $iRowB, $iRowE ) =
unpack( 'v3', substr( $sWk, 2 + $i * 6, 6 ) );
push @aBreak, $iCol;
# push @aBreak, [$iCol, $iRowB, $iRowE];
}
}
#Before BIFF8
else {
for ( my $i = 0 ; $i < $iCnt ; $i++ ) {
my ( $iCol ) = unpack( 'v', substr( $sWk, 2 + $i * 2, 2 ) );
push @aBreak, $iCol;
# push @aBreak, [$iCol, 0, 65535];
}
}
@aBreak = sort { $a <=> $b } @aBreak;
$oBook->{Worksheet}[ $oBook->{_CurSheet} ]->{VPageBreak} = \@aBreak;
}
#------------------------------------------------------------------------------
# _subMargin (for Spreadsheet::ParseExcel) DK: P306, 345, 400, 440
#------------------------------------------------------------------------------
sub _subMargin {
my ( $oBook, $bOp, $bLen, $sWk ) = @_;
return undef unless ( defined $oBook->{_CurSheet} );
# The "Mergin" options are a workaround for a backward compatible typo.
my $dWk = _convDval( substr( $sWk, 0, 8 ) );
if ( $bOp == 0x26 ) {
$oBook->{Worksheet}[ $oBook->{_CurSheet} ]->{LeftMergin} = $dWk;
$oBook->{Worksheet}[ $oBook->{_CurSheet} ]->{LeftMargin} = $dWk;
}
elsif ( $bOp == 0x27 ) {
$oBook->{Worksheet}[ $oBook->{_CurSheet} ]->{RightMergin} = $dWk;
$oBook->{Worksheet}[ $oBook->{_CurSheet} ]->{RightMargin} = $dWk;
}
elsif ( $bOp == 0x28 ) {
$oBook->{Worksheet}[ $oBook->{_CurSheet} ]->{TopMergin} = $dWk;
$oBook->{Worksheet}[ $oBook->{_CurSheet} ]->{TopMargin} = $dWk;
}
elsif ( $bOp == 0x29 ) {
$oBook->{Worksheet}[ $oBook->{_CurSheet} ]->{BottomMergin} = $dWk;
$oBook->{Worksheet}[ $oBook->{_CurSheet} ]->{BottomMargin} = $dWk;
}
}
#------------------------------------------------------------------------------
# _subHcenter (for Spreadsheet::ParseExcel) DK: P340
#------------------------------------------------------------------------------
sub _subHcenter {
my ( $oBook, $bOp, $bLen, $sWk ) = @_;
return undef unless ( defined $oBook->{_CurSheet} );
my $iWk = unpack( "v", $sWk );
$oBook->{Worksheet}[ $oBook->{_CurSheet} ]->{HCenter} = $iWk;
}
#------------------------------------------------------------------------------
# _subVcenter (for Spreadsheet::ParseExcel) DK: P447
#------------------------------------------------------------------------------
sub _subVcenter {
my ( $oBook, $bOp, $bLen, $sWk ) = @_;
return undef unless ( defined $oBook->{_CurSheet} );
my $iWk = unpack( "v", $sWk );
$oBook->{Worksheet}[ $oBook->{_CurSheet} ]->{VCenter} = $iWk;
}
#------------------------------------------------------------------------------
# _subPrintGridlines (for Spreadsheet::ParseExcel) DK: P397
#------------------------------------------------------------------------------
sub _subPrintGridlines {
my ( $oBook, $bOp, $bLen, $sWk ) = @_;
return undef unless ( defined $oBook->{_CurSheet} );
my $iWk = unpack( "v", $sWk );
$oBook->{Worksheet}[ $oBook->{_CurSheet} ]->{PrintGrid} = $iWk;
}
#------------------------------------------------------------------------------
# _subPrintHeaders (for Spreadsheet::ParseExcel) DK: P397
#------------------------------------------------------------------------------
sub _subPrintHeaders {
my ( $oBook, $bOp, $bLen, $sWk ) = @_;
return undef unless ( defined $oBook->{_CurSheet} );
my $iWk = unpack( "v", $sWk );
$oBook->{Worksheet}[ $oBook->{_CurSheet} ]->{PrintHeaders} = $iWk;
}
#------------------------------------------------------------------------------
# _subSETUP (for Spreadsheet::ParseExcel) DK: P409
#------------------------------------------------------------------------------
sub _subSETUP {
my ( $oBook, $bOp, $bLen, $sWk ) = @_;
return undef unless ( defined $oBook->{_CurSheet} );
# Workaround for some apps and older Excels that don't write a
# complete SETUP record.
return undef if $bLen != 34;
my $oWkS = $oBook->{Worksheet}[ $oBook->{_CurSheet} ];
my $iGrBit;
(
$oWkS->{PaperSize}, $oWkS->{Scale}, $oWkS->{PageStart},
$oWkS->{FitWidth}, $oWkS->{FitHeight}, $iGrBit,
$oWkS->{Res}, $oWkS->{VRes},
) = unpack( 'v8', $sWk );
$oWkS->{HeaderMargin} = _convDval( substr( $sWk, 16, 8 ) );
$oWkS->{FooterMargin} = _convDval( substr( $sWk, 24, 8 ) );
$oWkS->{Copis} = unpack( 'v2', substr( $sWk, 32, 2 ) );
$oWkS->{LeftToRight} = ( ( $iGrBit & 0x01 ) ? 1 : 0 );
$oWkS->{Landscape} = ( ( $iGrBit & 0x02 ) ? 1 : 0 );
$oWkS->{NoPls} = ( ( $iGrBit & 0x04 ) ? 1 : 0 );
$oWkS->{NoColor} = ( ( $iGrBit & 0x08 ) ? 1 : 0 );
$oWkS->{Draft} = ( ( $iGrBit & 0x10 ) ? 1 : 0 );
$oWkS->{Notes} = ( ( $iGrBit & 0x20 ) ? 1 : 0 );
$oWkS->{NoOrient} = ( ( $iGrBit & 0x40 ) ? 1 : 0 );
$oWkS->{UsePage} = ( ( $iGrBit & 0x80 ) ? 1 : 0 );
# The NoPls flag indicates that the values have not been taken from an
# actual printer and thus may not be accurate.
# Set default scale if NoPls otherwise it may be an invalid value of 0XFF.
$oWkS->{Scale} = 100 if $oWkS->{NoPls};
# Workaround for a backward compatible typo.
$oWkS->{HeaderMergin} = $oWkS->{HeaderMargin};
$oWkS->{FooterMergin} = $oWkS->{FooterMargin};
}
#------------------------------------------------------------------------------
# _subName (for Spreadsheet::ParseExcel) DK: P350
#------------------------------------------------------------------------------
sub _subName {
my ( $oBook, $bOp, $bLen, $sWk ) = @_;
my (
$iGrBit, $cKey, $cCh, $iCce, $ixAls,
$iTab, $cchCust, $cchDsc, $cchHep, $cchStatus
) = unpack( 'vc2v3c4', $sWk );
#Builtin Name + Length == 1
if ( ( $iGrBit & 0x20 ) && ( $cCh == 1 ) ) {
#BIFF8
if ( $oBook->{BIFFVersion} >= verBIFF8 ) {
my $iName = unpack( 'n', substr( $sWk, 14 ) );
my $iSheet = unpack( 'v', substr( $sWk, 8 ) ) - 1;
# Workaround for mal-formed Excel workbooks where Print_Title is
# set as Global (i.e. itab = 0). Note, this will have to be
# treated differently when we get around to handling global names.
return undef if $iSheet == -1;
if ( $iName == 6 ) { #PrintArea
my ( $iSheetW, $raArea ) = _ParseNameArea( substr( $sWk, 16 ) );
$oBook->{PrintArea}[$iSheet] = $raArea;
}
elsif ( $iName == 7 ) { #Title
my ( $iSheetW, $raArea ) = _ParseNameArea( substr( $sWk, 16 ) );
my @aTtlR = ();
my @aTtlC = ();
foreach my $raI ( @$raArea ) {
if ( $raI->[3] == 0xFF ) { #Row Title
push @aTtlR, [ $raI->[0], $raI->[2] ];
}
else { #Col Title
push @aTtlC, [ $raI->[1], $raI->[3] ];
}
}
$oBook->{PrintTitle}[$iSheet] =
{ Row => \@aTtlR, Column => \@aTtlC };
}
}
else {
my $iName = unpack( 'c', substr( $sWk, 14 ) );
if ( $iName == 6 ) { #PrintArea
my ( $iSheet, $raArea ) =
_ParseNameArea95( substr( $sWk, 15 ) );
$oBook->{PrintArea}[$iSheet] = $raArea;
}
elsif ( $iName == 7 ) { #Title
my ( $iSheet, $raArea ) =
_ParseNameArea95( substr( $sWk, 15 ) );
my @aTtlR = ();
my @aTtlC = ();
foreach my $raI ( @$raArea ) {
if ( $raI->[3] == 0xFF ) { #Row Title
push @aTtlR, [ $raI->[0], $raI->[2] ];
}
else { #Col Title
push @aTtlC, [ $raI->[1], $raI->[3] ];
}
}
$oBook->{PrintTitle}[$iSheet] =
{ Row => \@aTtlR, Column => \@aTtlC };
}
}
}
}
#------------------------------------------------------------------------------
# ParseNameArea (for Spreadsheet::ParseExcel) DK: 494 (ptgAread3d)
#------------------------------------------------------------------------------
sub _ParseNameArea {
my ( $sObj ) = @_;
my ( $iOp );
my @aRes = ();
$iOp = unpack( 'C', $sObj );
my $iSheet;
if ( $iOp == 0x3b ) {
my ( $iWkS, $iRs, $iRe, $iCs, $iCe ) =
unpack( 'v5', substr( $sObj, 1 ) );
$iSheet = $iWkS;
push @aRes, [ $iRs, $iCs, $iRe, $iCe ];
}
elsif ( $iOp == 0x29 ) {
my $iLen = unpack( 'v', substr( $sObj, 1, 2 ) );
my $iSt = 0;
while ( $iSt < $iLen ) {
my ( $iOpW, $iWkS, $iRs, $iRe, $iCs, $iCe ) =
unpack( 'cv5', substr( $sObj, $iSt + 3, 11 ) );
if ( $iOpW == 0x3b ) {
$iSheet = $iWkS;
push @aRes, [ $iRs, $iCs, $iRe, $iCe ];
}
if ( $iSt == 0 ) {
$iSt += 11;
}
else {
$iSt += 12; #Skip 1 byte;
}
}
}
return ( $iSheet, \@aRes );
}
#------------------------------------------------------------------------------
# ParseNameArea95 (for Spreadsheet::ParseExcel) DK: 494 (ptgAread3d)
#------------------------------------------------------------------------------
sub _ParseNameArea95 {
my ( $sObj ) = @_;
my ( $iOp );
my @aRes = ();
$iOp = unpack( 'C', $sObj );
my $iSheet;
if ( $iOp == 0x3b ) {
$iSheet = unpack( 'v', substr( $sObj, 11, 2 ) );
my ( $iRs, $iRe, $iCs, $iCe ) =
unpack( 'v2C2', substr( $sObj, 15, 6 ) );
push @aRes, [ $iRs, $iCs, $iRe, $iCe ];
}
elsif ( $iOp == 0x29 ) {
my $iLen = unpack( 'v', substr( $sObj, 1, 2 ) );
my $iSt = 0;
while ( $iSt < $iLen ) {
my $iOpW = unpack( 'c', substr( $sObj, $iSt + 3, 6 ) );
$iSheet = unpack( 'v', substr( $sObj, $iSt + 14, 2 ) );
my ( $iRs, $iRe, $iCs, $iCe ) =
unpack( 'v2C2', substr( $sObj, $iSt + 18, 6 ) );
push @aRes, [ $iRs, $iCs, $iRe, $iCe ] if ( $iOpW == 0x3b );
if ( $iSt == 0 ) {
$iSt += 21;
}
else {
$iSt += 22; #Skip 1 byte;
}
}
}
return ( $iSheet, \@aRes );
}
#------------------------------------------------------------------------------
# _subBOOL (for Spreadsheet::ParseExcel) DK: P452
#------------------------------------------------------------------------------
sub _subWSBOOL {
my ( $oBook, $bOp, $bLen, $sWk ) = @_;
return undef unless ( defined $oBook->{_CurSheet} );
$oBook->{Worksheet}[ $oBook->{_CurSheet} ]->{PageFit} =
( ( unpack( 'v', $sWk ) & 0x100 ) ? 1 : 0 );
}
#------------------------------------------------------------------------------
# _subMergeArea (for Spreadsheet::ParseExcel) DK: (Not)
#------------------------------------------------------------------------------
sub _subMergeArea {
my ( $oBook, $bOp, $bLen, $sWk ) = @_;
return undef unless ( defined $oBook->{_CurSheet} );
my $iCnt = unpack( "v", $sWk );
my $oWkS = $oBook->{Worksheet}[ $oBook->{_CurSheet} ];
$oWkS->{MergedArea} = [] unless ( defined $oWkS->{MergedArea} );
for ( my $i = 0 ; $i < $iCnt ; $i++ ) {
my ( $iRs, $iRe, $iCs, $iCe ) =
unpack( 'v4', substr( $sWk, $i * 8 + 2, 8 ) );
for ( my $iR = $iRs ; $iR <= $iRe ; $iR++ ) {
for ( my $iC = $iCs ; $iC <= $iCe ; $iC++ ) {
$oWkS->{Cells}[$iR][$iC]->{Merged} = 1
if ( defined $oWkS->{Cells}[$iR][$iC] );
}
}
push @{ $oWkS->{MergedArea} }, [ $iRs, $iCs, $iRe, $iCe ];
}
}
#------------------------------------------------------------------------------
# DecodeBoolErr (for Spreadsheet::ParseExcel) DK: P306
#------------------------------------------------------------------------------
sub DecodeBoolErr {
my ( $iVal, $iFlg ) = @_;
if ( $iFlg ) { # ERROR
if ( $iVal == 0x00 ) {
return "#NULL!";
}
elsif ( $iVal == 0x07 ) {
return "#DIV/0!";
}
elsif ( $iVal == 0x0F ) {
return "#VALUE!";
}
elsif ( $iVal == 0x17 ) {
return "#REF!";
}
elsif ( $iVal == 0x1D ) {
return "#NAME?";
}
elsif ( $iVal == 0x24 ) {
return "#NUM!";
}
elsif ( $iVal == 0x2A ) {
return "#N/A!";
}
else {
return "#ERR";
}
}
else {
return ( $iVal ) ? "TRUE" : "FALSE";
}
}
###############################################################################
#
# _decode_rk_number()
#
# Convert an encoded RK number into a real number. The RK encoding is
# explained in some detail in the MS docs. It is a way of storing applicable
# ints and doubles in 32bits (30 data + 2 info bits) in order to save space.
#
sub _decode_rk_number {
my $rk_number = shift;
my $number;
# Check the main RK type.
if ( $rk_number & 0x02 ) {
# RK Type 2 and 4, a packed integer.
# Shift off the info bits.
$number = $rk_number >> 2;
# Convert from unsigned to signed if required.
$number -= 0x40000000 if $number & 0x20000000;
}
else {
# RK Type 1 and 3, a truncated IEEE Double.
# Pack the RK number into the high 30 bits of an IEEE double.
$number = pack "VV", 0x0000, $rk_number & 0xFFFFFFFC;
# Reverse the packed IEEE double on big-endian machines.
$number = reverse $number if $BIGENDIAN;
# Unpack the number.
$number = unpack "d", $number;
}
# RK Types 3 and 4 were multiplied by 100 prior to encoding.
$number /= 100 if $rk_number & 0x01;
return $number;
}
###############################################################################
#
# _subStrWk()
#
# Extract the workbook strings from the SST (Shared String Table) record and
# any following CONTINUE records.
#
# The workbook strings are initially contained in the SST block but may also
# occupy one or more CONTINUE blocks. Reading the CONTINUE blocks is made a
# little tricky by the fact that they can contain an additional initial byte
# if a string is continued from a previous block.
#
# Parsing is further complicated by the fact that the continued section of the
# string may have a different encoding (ASCII or UTF-8) from the previous
# section. Excel does this to save space.
#
sub _subStrWk {
my ( $self, $biff_data, $is_continue ) = @_;
if ( $is_continue ) {
# We are reading a CONTINUE record.
if ( $self->{_buffer} eq '' ) {
# A CONTINUE block with no previous SST.
$self->{_buffer} .= $biff_data;
}
elsif ( !defined $self->{_string_continued} ) {
# The CONTINUE block starts with a new (non-continued) string.
# Strip the Grbit byte and store the string data.
$self->{_buffer} .= substr $biff_data, 1;
}
else {
# A CONTINUE block that starts with a continued string.
# The first byte (Grbit) of the CONTINUE record indicates if (0)
# the continued string section is single bytes or (1) double bytes.
my $grbit = ord $biff_data;
my ( $str_position, $str_length ) = @{ $self->{_previous_info} };
my $buff_length = length $self->{_buffer};
if ( $buff_length >= ( $str_position + $str_length ) ) {
# Not in a string.
$self->{_buffer} .= $biff_data;
}
elsif ( ( $self->{_string_continued} & 0x01 ) == ( $grbit & 0x01 ) )
{
# Same encoding as the previous block of the string.
$self->{_buffer} .= substr( $biff_data, 1 );
}
else {
# Different encoding to the previous block of the string.
if ( $grbit & 0x01 ) {
# Current block is UTF-16, previous was ASCII.
my ( undef, $cch ) = unpack 'vc', $self->{_buffer};
substr( $self->{_buffer}, 2, 1 ) = pack( 'C', $cch | 0x01 );
# Convert the previous ASCII, single character, portion of
# the string into a double character UTF-16 string by
# inserting zero bytes.
for (
my $i = ( $buff_length - $str_position ) ;
$i >= 1 ;
$i--
)
{
substr( $self->{_buffer}, $str_position + $i, 0 ) =
"\x00";
}
}
else {
# Current block is ASCII, previous was UTF-16.
# Convert the current ASCII, single character, portion of
# the string into a double character UTF-16 string by
# inserting null bytes.
my $change_length =
( $str_position + $str_length ) - $buff_length;
# Length of the current CONTINUE record data.
my $biff_length = length $biff_data;
# Restrict the portion to be changed to the current block
# if the string extends over more than one block.
if ( $change_length > ( $biff_length - 1 ) * 2 ) {
$change_length = ( $biff_length - 1 ) * 2;
}
# Insert the null bytes.
for ( my $i = ( $change_length / 2 ) ; $i >= 1 ; $i-- ) {
substr( $biff_data, $i + 1, 0 ) = "\x00";
}
}
# Strip the Grbit byte and store the string data.
$self->{_buffer} .= substr $biff_data, 1;
}
}
}
else {
# Not a CONTINUE block therefore an SST block.
$self->{_buffer} .= $biff_data;
}
# Reset the state variables.
$self->{_string_continued} = undef;
$self->{_previous_info} = undef;
# Extract out any full strings from the current buffer leaving behind a
# partial string that is continued into the next block, or an empty
# buffer is no string is continued.
while ( length $self->{_buffer} >= 4 ) {
my ( $str_info, $length, $str_position, $str_length ) =
_convBIFF8String( $self, $self->{_buffer}, 1 );
if ( defined $str_info->[0] ) {
push @{ $self->{PkgStr} },
{
Text => $str_info->[0],
Unicode => $str_info->[1],
Rich => $str_info->[2],
Ext => $str_info->[3],
};
$self->{_buffer} = substr( $self->{_buffer}, $length );
}
else {
$self->{_string_continued} = $str_info->[1];
$self->{_previous_info} = [ $str_position, $str_length ];
last;
}
}
}
#------------------------------------------------------------------------------
# _SwapForUnicode (for Spreadsheet::ParseExcel)
#------------------------------------------------------------------------------
sub _SwapForUnicode {
my ( $sObj ) = @_;
# for(my $i = 0; $i{_CurSheet} );
my $FmtClass = $oBook->{FmtClass};
$rhKey{Type} =
$FmtClass->ChkType( $rhKey{Numeric}, $rhKey{Format}{FmtIdx} );
my $FmtStr = $oBook->{FormatStr}{ $rhKey{Format}{FmtIdx} };
# Set "Date" type if required for numbers in a MulRK BIFF block.
if ( defined $FmtStr && $rhKey{Type} eq "Numeric" ) {
# Match a range of possible date formats. Note: this isn't important
# except for reporting. The number will still be converted to a date
# by ExcelFmt() even if 'Type' isn't set to 'Date'.
if ( $FmtStr =~ m{^[dmy][-\\/dmy]*$}i ) {
$rhKey{Type} = "Date";
}
}
my $oCell = Spreadsheet::ParseExcel::Cell->new(
Val => $rhKey{Val},
FormatNo => $rhKey{FormatNo},
Format => $rhKey{Format},
Code => $rhKey{Code},
Type => $rhKey{Type},
);
$oCell->{_Kind} = $rhKey{Kind};
$oCell->{_Value} = $FmtClass->ValFmt( $oCell, $oBook );
if ( $rhKey{Rich} ) {
my @aRich = ();
my $sRich = $rhKey{Rich};
for ( my $iWk = 0 ; $iWk < length( $sRich ) ; $iWk += 4 ) {
my ( $iPos, $iFnt ) = unpack( 'v2', substr( $sRich, $iWk ) );
push @aRich, [ $iPos, $oBook->{Font}[$iFnt] ];
}
$oCell->{Rich} = \@aRich;
}
if ( defined $oBook->{CellHandler} ) {
if ( defined $oBook->{Object} ) {
no strict;
ref( $oBook->{CellHandler} ) eq "CODE"
? $oBook->{CellHandler}->(
$_Object, $oBook, $oBook->{_CurSheet}, $iR, $iC, $oCell
)
: $oBook->{CellHandler}->callback( $_Object, $oBook, $oBook->{_CurSheet},
$iR, $iC, $oCell );
}
else {
$oBook->{CellHandler}->( $oBook, $oBook->{_CurSheet}, $iR, $iC, $oCell );
}
}
unless ( $oBook->{NotSetCell} ) {
$oBook->{Worksheet}[ $oBook->{_CurSheet} ]->{Cells}[$iR][$iC] = $oCell;
}
return $oCell;
}
#------------------------------------------------------------------------------
# ColorIdxToRGB (for Spreadsheet::ParseExcel)
#
# Returns for most recently opened book for compatibility, use
# Workbook::color_idx_to_rgb instead
#
#------------------------------------------------------------------------------
sub ColorIdxToRGB {
my ( $sPkg, $iIdx ) = @_;
unless( defined $currentbook ) {
return ( ( defined $aColor[$iIdx] ) ? $aColor[$iIdx] : $aColor[0] );
}
return $currentbook->color_idx_to_rgb( $iIdx );
}
###############################################################################
#
# error().
#
# Return an error string for a failed parse().
#
sub error {
my $self = shift;
my $parse_error = $self->{_error_status};
if ( exists $error_strings{$parse_error} ) {
return $error_strings{$parse_error};
}
else {
return 'Unknown parse error';
}
}
###############################################################################
#
# error_code().
#
# Return an error code for a failed parse().
#
sub error_code {
my $self = shift;
return $self->{_error_status};
}
###############################################################################
#
# Mapping between legacy method names and new names.
#
{
no warnings; # Ignore warnings about variables used only once.
*Parse = *parse;
}
1;
__END__
=head1 NAME
Spreadsheet::ParseExcel - Read information from an Excel file.
=head1 SYNOPSIS
#!/usr/bin/perl -w
use strict;
use Spreadsheet::ParseExcel;
my $parser = Spreadsheet::ParseExcel->new();
my $workbook = $parser->parse('Book1.xls');
if ( !defined $workbook ) {
die $parser->error(), ".\n";
}
for my $worksheet ( $workbook->worksheets() ) {
my ( $row_min, $row_max ) = $worksheet->row_range();
my ( $col_min, $col_max ) = $worksheet->col_range();
for my $row ( $row_min .. $row_max ) {
for my $col ( $col_min .. $col_max ) {
my $cell = $worksheet->get_cell( $row, $col );
next unless $cell;
print "Row, Col = ($row, $col)\n";
print "Value = ", $cell->value(), "\n";
print "Unformatted = ", $cell->unformatted(), "\n";
print "\n";
}
}
}
=head1 DESCRIPTION
The Spreadsheet::ParseExcel module can be used to read information from Excel 95-2003 binary files.
The module cannot read files in the Excel 2007 Open XML XLSX format. See the L module instead.
=head1 Parser
=head2 new()
The C method is used to create a new C parser object.
my $parser = Spreadsheet::ParseExcel->new();
It is possible to pass a password to decrypt an encrypted file:
$parser = Spreadsheet::ParseExcel->new( Password => 'secret' );
Only the default Excel encryption scheme is currently supported. See L.
As an advanced feature it is also possible to pass a call-back handler to the parser to control the parsing of the spreadsheet.
$parser = Spreadsheet::ParseExcel->new(
CellHandler => \&cell_handler,
NotSetCell => 1,
);
The call-back can be used to ignore certain cells or to reduce memory usage. See the section L for more information.
=head2 parse($filename, $formatter)
The Parser C method returns a L object.
my $parser = Spreadsheet::ParseExcel->new();
my $workbook = $parser->parse('Book1.xls');
If an error occurs C returns C. In general, programs should contain a test for failed parsing as follows:
my $parser = Spreadsheet::ParseExcel->new();
my $workbook = $parser->parse('Book1.xls');
if ( !defined $workbook ) {
die $parser->error(), ".\n";
}
The C<$filename> parameter is generally the file to be parsed. However, it can also be a filehandle or a scalar reference.
The optional C<$formatter> parameter can be an reference to a L to format the value of cells. This is useful for parsing workbooks with Unicode or Asian characters:
my $parser = Spreadsheet::ParseExcel->new();
my $formatter = Spreadsheet::ParseExcel::FmtJapan->new();
my $workbook = $parser->parse( 'Book1.xls', $formatter );
The L formatter also supports Unicode. If you encounter any encoding problems with the default formatter try that instead.
=head2 error()
The Parser C method returns an error string if a C fails:
my $parser = Spreadsheet::ParseExcel->new();
my $workbook = $parser->parse('Book1.xls');
if ( !defined $workbook ) {
die $parser->error(), ".\n";
}
If you wish to generate you own error string you can use the C method instead (see below). The C and C values are as follows:
error() error_code()
======= ============
'' 0
'File not found' 1
'No Excel data found in file' 2
'File is encrypted' 3
The C method is explained below.
Spreadsheet::ParseExcel will try to decrypt an encrypted Excel file using the default password or a user supplied password passed to C, see above. If these fail the module will return the C<'File is encrypted'> error. Only the default Excel encryption scheme is currently supported, see L.
=head2 error_code()
The Parser C method returns an error code if a C fails:
my $parser = Spreadsheet::ParseExcel->new();
my $workbook = $parser->parse('Book1.xls');
if ( !defined $workbook ) {
die "Got error code ", $parser->error_code, ".\n";
}
This can be useful if you wish to employ you own error strings or error handling methods.
=head1 Workbook
A C is created via the C C method:
my $parser = Spreadsheet::ParseExcel->new();
my $workbook = $parser->parse('Book1.xls');
The main methods of the Workbook class are:
$workbook->worksheets()
$workbook->worksheet()
$workbook->worksheet_count()
$workbook->get_filename()
These more commonly used methods of the Workbook class are outlined below. The other, less commonly used, methods are documented in L.
=head2 worksheets()
Returns an array of L objects. This was most commonly used to iterate over the worksheets in a workbook:
for my $worksheet ( $workbook->worksheets() ) {
...
}
=head2 worksheet()
The C method returns a single C object using either its name or index:
$worksheet = $workbook->worksheet('Sheet1');
$worksheet = $workbook->worksheet(0);
Returns C if the sheet name or index doesn't exist.
=head2 worksheet_count()
The C method returns the number of Worksheet objects in the Workbook.
my $worksheet_count = $workbook->worksheet_count();
=head2 get_filename()
The C method returns the name of the Excel file of C if the data was read from a filehandle rather than a file.
my $filename = $workbook->get_filename();
=head2 Other Workbook Methods
For full documentation of the methods available via a Workbook object see L.
=head1 Worksheet
The C class encapsulates the properties of an Excel worksheet.
A Worksheet object is obtained via the L or L methods.
for my $worksheet ( $workbook->worksheets() ) {
...
}
# Or:
$worksheet = $workbook->worksheet('Sheet1');
$worksheet = $workbook->worksheet(0);
The most commonly used methods of the Worksheet class are:
$worksheet->get_cell()
$worksheet->row_range()
$worksheet->col_range()
$worksheet->get_name()
The Spreadsheet::ParseExcel::Worksheet class exposes a lot of methods but in general very few are required unless you are writing an advanced filter.
The most commonly used methods are detailed below. The others are documented in L.
=head2 get_cell($row, $col)
Return the L object at row C<$row> and column C<$col> if it is defined. Otherwise returns undef.
my $cell = $worksheet->get_cell($row, $col);
=head2 row_range()
Returns a two-element list C<($min, $max)> containing the minimum and maximum defined rows in the worksheet. If there is no row defined C<$max> is smaller than C<$min>.
my ( $row_min, $row_max ) = $worksheet->row_range();
=head2 col_range()
Returns a two-element list C<($min, $max)> containing the minimum and maximum of defined columns in the worksheet. If there is no column defined C<$max> is smaller than C<$min>.
my ( $col_min, $col_max ) = $worksheet->col_range();
=head2 get_name()
The C method returns the name of the worksheet, such as 'Sheet1'.
my $name = $worksheet->get_name();
=head2 Other Worksheet Methods
For other, less commonly used, Worksheet methods see L.
=head1 Cell
The C class has the following main methods.
$cell->value()
$cell->unformatted()
=head2 value()
The C method returns the formatted value of the cell.
my $value = $cell->value();
Formatted in this sense refers to the numeric format of the cell value. For example a number such as 40177 might be formatted as 40,117, 40117.000 or even as the date 2009/12/30.
If the cell doesn't contain a numeric format then the formatted and unformatted cell values are the same, see the C method below.
For a defined C<$cell> the C method will always return a value.
In the case of a cell with formatting but no numeric or string contents the method will return the empty string C<''>.
=head2 unformatted()
The C method returns the unformatted value of the cell.
my $unformatted = $cell->unformatted();
Returns the cell value without a numeric format. See the C method above.
=head2 Other Cell Methods
For other, less commonly used, Worksheet methods see L.
=head1 Format
The C class has the following properties:
=head2 Format properties
$format->{Font}
$format->{AlignH}
$format->{AlignV}
$format->{Indent}
$format->{Wrap}
$format->{Shrink}
$format->{Rotate}
$format->{JustLast}
$format->{ReadDir}
$format->{BdrStyle}
$format->{BdrColor}
$format->{BdrDiag}
$format->{Fill}
$format->{Lock}
$format->{Hidden}
$format->{Style}
These properties are generally only of interest to advanced users. Casual users can skip this section.
=head2 $format->{Font}
Returns the L object for the Format.
=head2 $format->{AlignH}
Returns the horizontal alignment of the format where the value has the following meaning:
0 => No alignment
1 => Left
2 => Center
3 => Right
4 => Fill
5 => Justify
6 => Center across
7 => Distributed/Equal spaced
=head2 $format->{AlignV}
Returns the vertical alignment of the format where the value has the following meaning:
0 => Top
1 => Center
2 => Bottom
3 => Justify
4 => Distributed/Equal spaced
=head2 $format->{Indent}
Returns the indent level of the C horizontal alignment.
=head2 $format->{Wrap}
Returns true if textwrap is on.
=head2 $format->{Shrink}
Returns true if "Shrink to fit" is set for the format.
=head2 $format->{Rotate}
Returns the text rotation. In Excel97+, it returns the angle in degrees of the text rotation.
In Excel95 or earlier it returns a value as follows:
0 => No rotation
1 => Top down
2 => 90 degrees anti-clockwise,
3 => 90 clockwise
=head2 $format->{JustLast}
Return true if the "justify last" property is set for the format.
=head2 $format->{ReadDir}
Returns the direction that the text is read from.
=head2 $format->{BdrStyle}
Returns an array ref of border styles as follows:
[ $left, $right, $top, $bottom ]
=head2 $format->{BdrColor}
Returns an array ref of border color indexes as follows:
[ $left, $right, $top, $bottom ]
=head2 $format->{BdrDiag}
Returns an array ref of diagonal border kind, style and color index as follows:
[$kind, $style, $color ]
Where kind is:
0 => None
1 => Right-Down
2 => Right-Up
3 => Both
=head2 $format->{Fill}
Returns an array ref of fill pattern and color indexes as follows:
[ $pattern, $front_color, $back_color ]
=head2 $format->{Lock}
Returns true if the cell is locked.
=head2 $format->{Hidden}
Returns true if the cell is Hidden.
=head2 $format->{Style}
Returns true if the format is a Style format.
=head1 Font
I
Format class has these properties:
=head1 Font Properties
$font->{Name}
$font->{Bold}
$font->{Italic}
$font->{Height}
$font->{Underline}
$font->{UnderlineStyle}
$font->{Color}
$font->{Strikeout}
$font->{Super}
=head2 $font->{Name}
Returns the name of the font, for example 'Arial'.
=head2 $font->{Bold}
Returns true if the font is bold.
=head2 $font->{Italic}
Returns true if the font is italic.
=head2 $font->{Height}
Returns the size (height) of the font.
=head2 $font->{Underline}
Returns true if the font in underlined.
=head2 $font->{UnderlineStyle}
Returns the style of an underlined font where the value has the following meaning:
0 => None
1 => Single
2 => Double
33 => Single accounting
34 => Double accounting
=head2 $font->{Color}
Returns the color index for the font. The mapping to an RGB color is defined by each workbook.
The index can be converted to a RGB string using the C<$workbook->ColorIdxToRGB()> Parser method.
(Older versions of C provided the C class method, which is deprecated.)
=head2 $font->{Strikeout}
Returns true if the font has the strikeout property set.
=head2 $font->{Super}
Returns one of the following values if the superscript or subscript property of the font is set:
0 => None
1 => Superscript
2 => Subscript
=head1 Formatter Class
Formatters can be passed to the C method to deal with Unicode or Asian formatting.
Spreadsheet::ParseExcel includes 2 formatter classes. C and C. It is also possible to create a user defined formatting class.
The formatter class C should provide the following functions:
=head2 ChkType($self, $is_numeric, $format_index)
Method to check the type of data in the cell. Should return C, C or C. It is passed the following parameters:
=over
=item $self
A scalar reference to the Formatter object.
=item $is_numeric
If true, the value seems to be number.
=item $format_index
The index number for the cell Format object.
=back
=head2 TextFmt($self, $string_data, $string_encoding)
Converts the string data in the cell into the correct encoding. It is passed the following parameters:
=over
=item $self
A scalar reference to the Formatter object.
=item $string_data
The original string/text data.
=item $string_encoding
The character encoding of original string/text.
=back
=head2 ValFmt($self, $cell, $workbook)
Convert the original unformatted cell value into the appropriate formatted value. For instance turn a number into a formatted date. It is passed the following parameters:
=over
=item $self
A scalar reference to the Formatter object.
=item $cell
A scalar reference to the Cell object.
=item $workbook
A scalar reference to the Workbook object.
=back
=head2 FmtString($self, $cell, $workbook)
Get the format string for the Cell. It is passed the following parameters:
=over
=item $self
A scalar reference to the Formatter object.
=item $cell
A scalar reference to the Cell object.
=item $workbook
A scalar reference to the Workbook object.
=back
=head1 Reducing the memory usage of Spreadsheet::ParseExcel
In some cases a C application may consume a lot of memory when processing a large Excel file and, as a result, may fail to complete. The following explains why this can occur and how to resolve it.
C processes an Excel file in two stages. In the first stage it extracts the Excel binary stream from the OLE container file using C. In the second stage it parses the binary stream to read workbook, worksheet and cell data which it then stores in memory. The majority of the memory usage is required for storing cell data.
The reason for this is that as the Excel file is parsed and each cell is encountered a cell handling function creates a relatively large nested cell object that contains the cell value and all of the data that relates to the cell formatting. For large files (a 10MB Excel file on a 256MB system) this overhead can cause the system to grind to a halt.
However, in a lot of cases when an Excel file is being processed the only information that is required are the cell values. In these cases it is possible to avoid most of the memory overhead by specifying your own cell handling function and by telling Spreadsheet::ParseExcel not to store the parsed cell data. This is achieved by passing a cell handler function to C when creating the parse object. Here is an example.
#!/usr/bin/perl -w
use strict;
use Spreadsheet::ParseExcel;
my $parser = Spreadsheet::ParseExcel->new(
CellHandler => \&cell_handler,
NotSetCell => 1
);
my $workbook = $parser->parse('file.xls');
sub cell_handler {
my $workbook = $_[0];
my $sheet_index = $_[1];
my $row = $_[2];
my $col = $_[3];
my $cell = $_[4];
# Do something useful with the formatted cell value
print $cell->value(), "\n";
}
The user specified cell handler is passed as a code reference to C along with the parameter C which tells Spreadsheet::ParseExcel not to store the parsed cell. Note, you don't have to iterate over the rows and columns, this happens automatically as part of the parsing.
The cell handler is passed 5 arguments. The first, C<$workbook>, is a reference to the C object that represent the parsed workbook. This can be used to access any of the C methods, see L. The second C<$sheet_index> is the zero-based index of the worksheet being parsed. The third and fourth, C<$row> and C<$col>, are the zero-based row and column number of the cell. The fifth, C<$cell>, is a reference to the C object. This is used to extract the data from the cell. See L for more information.
This technique can be useful if you are writing an Excel to database filter since you can put your DB calls in the cell handler.
If you don't want all of the data in the spreadsheet you can add some control logic to the cell handler. For example we can extend the previous example so that it only prints the first 10 rows of the first two worksheets in the parsed workbook by adding some C statements to the cell handler:
#!/usr/bin/perl -w
use strict;
use Spreadsheet::ParseExcel;
my $parser = Spreadsheet::ParseExcel->new(
CellHandler => \&cell_handler,
NotSetCell => 1
);
my $workbook = $parser->parse('file.xls');
sub cell_handler {
my $workbook = $_[0];
my $sheet_index = $_[1];
my $row = $_[2];
my $col = $_[3];
my $cell = $_[4];
# Skip some worksheets and rows (inefficiently).
return if $sheet_index >= 3;
return if $row >= 10;
# Do something with the formatted cell value
print $cell->value(), "\n";
}
However, this still processes the entire workbook. If you wish to save some additional processing time you can abort the parsing after you have read the data that you want, using the workbook C method:
#!/usr/bin/perl -w
use strict;
use Spreadsheet::ParseExcel;
my $parser = Spreadsheet::ParseExcel->new(
CellHandler => \&cell_handler,
NotSetCell => 1
);
my $workbook = $parser->parse('file.xls');
sub cell_handler {
my $workbook = $_[0];
my $sheet_index = $_[1];
my $row = $_[2];
my $col = $_[3];
my $cell = $_[4];
# Skip some worksheets and rows (more efficiently).
if ( $sheet_index >= 1 and $row >= 10 ) {
$workbook->ParseAbort(1);
return;
}
# Do something with the formatted cell value
print $cell->value(), "\n";
}
=head1 Decryption
If a workbook is "protected" then Excel will encrypt the file whether a password is supplied or not. As of version 0.59 Spreadsheet::ParseExcel supports decrypting Excel workbooks using a default or user supplied password. However, only the following encryption scheme is supported:
Office 97/2000 Compatible encryption
The following encryption methods are not supported:
Weak Encryption (XOR)
RC4, Microsoft Base Cryptographic Provider v1.0
RC4, Microsoft Base DSS and Diffie-Hellman Cryptographic Provider
RC4, Microsoft DH SChannel Cryptographic Provider
RC4, Microsoft Enhanced Cryptographic Provider v1.0
RC4, Microsoft Enhanced DSS and Diffie-Hellman Cryptographic Provider
RC4, Microsoft Enhanced RSA and AES Cryptographic Provider
RC4, Microsoft RSA SChannel Cryptographic Provider
RC4, Microsoft Strong Cryptographic Provider
See the following for more information on Excel encryption: L.
=head1 KNOWN PROBLEMS
=over
=item * This module cannot read the values of formulas from files created with Spreadsheet::WriteExcel unless the user specified the values when creating the file (which is generally not the case). The reason for this is that Spreadsheet::WriteExcel writes the formula but not the formula result since it isn't in a position to calculate arbitrary Excel formulas without access to Excel's formula engine.
=item * If Excel has date fields where the specified format is equal to the system-default for the short-date locale, Excel does not store the format, but defaults to an internal format which is system dependent. In these cases ParseExcel uses the date format 'yyyy-mm-dd'.
=back
=head1 REPORTING A BUG
Please report bugs on GitHub with a complete, working, sample application and a test xls file.
L
=head1 SEE ALSO
=over
=item * xls2csv by Ken Prows L.
=item * xls2csv and xlscat by H.Merijn Brand (these utilities are part of Spreadsheet::Read, see below).
=item * excel2txt by Ken Youens-Clark, L. This is an excellent example of an Excel filter using Spreadsheet::ParseExcel. It can produce CSV, Tab delimited, Html, XML and Yaml.
=item * XLSperl by Jon Allen L. This application allows you to use Perl "one-liners" with Microsoft Excel files.
=item * Spreadsheet::XLSX L by Dmitry Ovsyanko. A module with a similar interface to Spreadsheet::ParseExcel for parsing Excel 2007 XLSX OpenXML files.
=item * Spreadsheet::Read L by H.Merijn Brand. A single interface for reading several different spreadsheet formats.
=item * Spreadsheet::WriteExcel L. A perl module for creating new Excel files.
=item * Spreadsheet::ParseExcel::SaveParser L. This is a combination of Spreadsheet::ParseExcel and Spreadsheet::WriteExcel and it allows you to "rewrite" an Excel file. See the following example L. It is part of the Spreadsheet::ParseExcel distro.
=item * Text::CSV_XS L by H.Merijn Brand. A fast and rigorous module for reading and writing CSV data. Don't consider rolling your own CSV handling, use this module instead.
=back
=head1 DONATIONS
If you'd care to donate to the Spreadsheet::ParseExcel project, you can do so via PayPal: L
=head1 TODO
=over
=item * The current maintenance work is directed towards making the documentation more useful, improving and simplifying the API, and improving the maintainability of the code base. After that new features will be added.
=item * Fix open bugs and documentation for SaveParser.
=item * Add Formula support, Hyperlink support, Named Range support.
=item * Improve Spreadsheet::ParseExcel::SaveParser compatibility with Spreadsheet::WriteExcel.
=item * Improve Unicode and other encoding support. This will probably require dropping support for perls prior to 5.8+.
=back
=head1 ACKNOWLEDGEMENTS
From Kawai Takanori:
First of all, I would like to acknowledge the following valuable programs and modules:
XHTML, OLE::Storage and Spreadsheet::WriteExcel.
In no particular order: Yamaji Haruna, Simamoto Takesi, Noguchi Harumi, Ikezawa Kazuhiro, Suwazono Shugo, Hirofumi Morisada, Michael Edwards, Kim Namusk, Slaven Rezic, Grant Stevens, H.Merijn Brand and many many people + Kawai Mikako.
Alexey Mazurin added the decryption facility.
=head1 DISCLAIMER OF WARRANTY
Because this software is licensed free of charge, there is no warranty for the software, to the extent permitted by applicable law. Except when otherwise stated in writing the copyright holders and/or other parties provide the software "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 software is with you. Should the software prove defective, you assume the cost of all necessary servicing, repair, or correction.
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 software as permitted by the above licence, be liable to you for damages, including any general, special, incidental, or consequential damages arising out of the use or inability to use the software (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 software to operate with any other software), even if such holder or other party has been advised of the possibility of such damages.
=head1 LICENSE
Either the Perl Artistic Licence L or the GPL L
=head1 AUTHOR
Current maintainer 0.60+: Douglas Wilson dougw@cpan.org
Maintainer 0.40-0.59: John McNamara jmcnamara@cpan.org
Maintainer 0.27-0.33: Gabor Szabo szabgab@cpan.org
Original author: Kawai Takanori (Hippo2000) kwitknr@cpan.org
=head1 COPYRIGHT
Copyright (c) 2014 Douglas Wilson
Copyright (c) 2009-2013 John McNamara
Copyright (c) 2006-2008 Gabor Szabo
Copyright (c) 2000-2006 Kawai Takanori
All rights reserved. This is free software. You may distribute under the terms of either the GNU General Public License or the Artistic License.
=cut
Spreadsheet-ParseExcel-0.66/lib/Spreadsheet/ParseExcel/SaveParser.pm 000644 000765 000024 00000017275 14543413026 025505 0 ustar 00John staff 000000 000000 package Spreadsheet::ParseExcel::SaveParser;
###############################################################################
#
# Spreadsheet::ParseExcel::SaveParser - Rewrite an existing Excel file.
#
# Used in conjunction with Spreadsheet::ParseExcel.
#
# Copyright (c) 2014 Douglas Wilson
# Copyright (c) 2009-2013 John McNamara
# Copyright (c) 2006-2008 Gabor Szabo
# Copyright (c) 2000-2006 Kawai Takanori
#
# perltidy with standard settings.
#
# Documentation after __END__
#
use strict;
use warnings;
use Spreadsheet::ParseExcel;
use Spreadsheet::ParseExcel::SaveParser::Workbook;
use Spreadsheet::ParseExcel::SaveParser::Worksheet;
use Spreadsheet::WriteExcel;
use base 'Spreadsheet::ParseExcel';
our $VERSION = '0.66';
###############################################################################
#
# new()
#
sub new {
my ( $package, %params ) = @_;
$package->SUPER::new(%params);
}
###############################################################################
#
# Create()
#
sub Create {
my ( $self, $formatter ) = @_;
#0. New $workbook
my $workbook = Spreadsheet::ParseExcel::Workbook->new();
$workbook->{SheetCount} = 0;
# User specified formatter class.
if ($formatter) {
$workbook->{FmtClass} = $formatter;
}
else {
$workbook->{FmtClass} = Spreadsheet::ParseExcel::FmtDefault->new();
}
return Spreadsheet::ParseExcel::SaveParser::Workbook->new($workbook);
}
###############################################################################
#
# Parse()
#
sub Parse {
my ( $self, $sFile, $formatter ) = @_;
my $workbook = $self->SUPER::Parse( $sFile, $formatter );
return undef unless defined $workbook;
return Spreadsheet::ParseExcel::SaveParser::Workbook->new($workbook);
}
###############################################################################
#
# SaveAs()
#
sub SaveAs {
my ( $self, $workbook, $filename ) = @_;
$workbook->SaveAs($filename);
}
1;
__END__
=head1 NAME
Spreadsheet::ParseExcel::SaveParser - Rewrite an existing Excel file.
=head1 SYNOPSIS
Say we start with an Excel file that looks like this:
-----------------------------------------------------
| | A | B | C |
-----------------------------------------------------
| 1 | Hello | ... | ... | ...
| 2 | World | ... | ... | ...
| 3 | *Bold text* | ... | ... | ...
| 4 | ... | ... | ... | ...
| 5 | ... | ... | ... | ...
Then we process it with the following program:
#!/usr/bin/perl
use strict;
use warnings;
use Spreadsheet::ParseExcel;
use Spreadsheet::ParseExcel::SaveParser;
# Open an existing file with SaveParser
my $parser = Spreadsheet::ParseExcel::SaveParser->new();
my $template = $parser->Parse('template.xls');
# Get the first worksheet.
my $worksheet = $template->worksheet(0);
my $row = 0;
my $col = 0;
# Overwrite the string in cell A1
$worksheet->AddCell( $row, $col, 'New string' );
# Add a new string in cell B1
$worksheet->AddCell( $row, $col + 1, 'Newer' );
# Add a new string in cell C1 with the format from cell A3.
my $cell = $worksheet->get_cell( $row + 2, $col );
my $format_number = $cell->{FormatNo};
$worksheet->AddCell( $row, $col + 2, 'Newest', $format_number );
# Write over the existing file or write a new file.
$template->SaveAs('newfile.xls');
We should now have an Excel file that looks like this:
-----------------------------------------------------
| | A | B | C |
-----------------------------------------------------
| 1 | New string | Newer | *Newest* | ...
| 2 | World | ... | ... | ...
| 3 | *Bold text* | ... | ... | ...
| 4 | ... | ... | ... | ...
| 5 | ... | ... | ... | ...
=head1 DESCRIPTION
The C module rewrite an existing Excel file by reading it with C and rewriting it with C.
=head1 METHODS
=head1 Parser
=head2 new()
$parse = new Spreadsheet::ParseExcel::SaveParser();
Constructor.
=head2 Parse()
$workbook = $parse->Parse($sFileName);
$workbook = $parse->Parse($sFileName , $formatter);
Returns a L object. If an error occurs, returns undef.
The optional C<$formatter> is a Formatter Class to format the value of cells.
=head1 Workbook
The C method returns a C object.
This is a subclass of the L and has the following methods:
=head2 worksheets()
Returns an array of L objects. This was most commonly used to iterate over the worksheets in a workbook:
for my $worksheet ( $workbook->worksheets() ) {
...
}
=head2 worksheet()
The C method returns a single C object using either its name or index:
$worksheet = $workbook->worksheet('Sheet1');
$worksheet = $workbook->worksheet(0);
Returns C if the sheet name or index doesn't exist.
=head2 AddWorksheet()
$workbook = $workbook->AddWorksheet($name, %properties);
Create a new Worksheet object of type C.
The C<%properties> hash contains the properties of new Worksheet.
=head2 AddFont
$workbook = $workbook->AddFont(%properties);
Create new Font object of type C.
The C<%properties> hash contains the properties of new Font.
=head2 AddFormat
$workbook = $workbook->AddFormat(%properties);
The C<%properties> hash contains the properties of new Font.
=head1 Worksheet
Spreadsheet::ParseExcel::SaveParser::Worksheet
Worksheet is a subclass of Spreadsheet::ParseExcel::Worksheet.
And has these methods :
The C method returns a C object.
This is a subclass of the L and has the following methods:
=head1 AddCell
$workbook = $worksheet->AddCell($row, $col, $value, $format [$encoding]);
Create new Cell object of type C.
The C<$format> parameter is the format number rather than a full format object.
To specify just same as another cell,
you can set it like below:
$row = 0;
$col = 0;
$worksheet = $template->worksheet(0);
$cell = $worksheet->get_cell( $row, $col );
$format_number = $cell->{FormatNo};
$worksheet->AddCell($row +1, $coll, 'New data', $format_number);
=head1 TODO
Please note that this module is currently (versions 0.50-0.60) undergoing a major
restructuring and rewriting.
=head1 Known Problems
You can only rewrite the features that Spreadsheet::WriteExcel supports so
macros, graphs and some other features in the original Excel file will be lost.
Also, formulas aren't rewritten, only the result of a formula is written.
Only last print area will remain. (Others will be removed)
=head1 AUTHOR
Current maintainer 0.60+: Douglas Wilson dougw@cpan.org
Maintainer 0.40-0.59: John McNamara jmcnamara@cpan.org
Maintainer 0.27-0.33: Gabor Szabo szabgab@cpan.org
Original author: Kawai Takanori kwitknr@cpan.org
=head1 COPYRIGHT
Copyright (c) 2014 Douglas Wilson
Copyright (c) 2009-2013 John McNamara
Copyright (c) 2006-2008 Gabor Szabo
Copyright (c) 2000-2002 Kawai Takanori and Nippon-RAD Co. OP Division
All rights reserved.
You may distribute under the terms of either the GNU General Public License or the Artistic License, as specified in the Perl README file.
=cut
Spreadsheet-ParseExcel-0.66/lib/Spreadsheet/ParseExcel/FmtDefault.pm 000644 000765 000024 00000014315 14543413026 025455 0 ustar 00John staff 000000 000000 package Spreadsheet::ParseExcel::FmtDefault;
###############################################################################
#
# Spreadsheet::ParseExcel::FmtDefault - A class for Cell formats.
#
# Used in conjunction with Spreadsheet::ParseExcel.
#
# Copyright (c) 2014 Douglas Wilson
# Copyright (c) 2009-2013 John McNamara
# Copyright (c) 2006-2008 Gabor Szabo
# Copyright (c) 2000-2006 Kawai Takanori
#
# perltidy with standard settings.
#
# Documentation after __END__
#
use strict;
use warnings;
use Spreadsheet::ParseExcel::Utility qw(ExcelFmt);
our $VERSION = '0.66';
my %hFmtDefault = (
0x00 => 'General',
0x01 => '0',
0x02 => '0.00',
0x03 => '#,##0',
0x04 => '#,##0.00',
0x05 => '($#,##0_);($#,##0)',
0x06 => '($#,##0_);[Red]($#,##0)',
0x07 => '($#,##0.00_);($#,##0.00_)',
0x08 => '($#,##0.00_);[Red]($#,##0.00_)',
0x09 => '0%',
0x0A => '0.00%',
0x0B => '0.00E+00',
0x0C => '# ?/?',
0x0D => '# ??/??',
0x0E => 'yyyy-mm-dd', # Was 'm-d-yy', which is bad as system default
0x0F => 'd-mmm-yy',
0x10 => 'd-mmm',
0x11 => 'mmm-yy',
0x12 => 'h:mm AM/PM',
0x13 => 'h:mm:ss AM/PM',
0x14 => 'h:mm',
0x15 => 'h:mm:ss',
0x16 => 'm-d-yy h:mm',
#0x17-0x24 -- Differs in Natinal
0x25 => '(#,##0_);(#,##0)',
0x26 => '(#,##0_);[Red](#,##0)',
0x27 => '(#,##0.00);(#,##0.00)',
0x28 => '(#,##0.00);[Red](#,##0.00)',
0x29 => '_(*#,##0_);_(*(#,##0);_(*"-"_);_(@_)',
0x2A => '_($*#,##0_);_($*(#,##0);_(*"-"_);_(@_)',
0x2B => '_(*#,##0.00_);_(*(#,##0.00);_(*"-"??_);_(@_)',
0x2C => '_($*#,##0.00_);_($*(#,##0.00);_(*"-"??_);_(@_)',
0x2D => 'mm:ss',
0x2E => '[h]:mm:ss',
0x2F => 'mm:ss.0',
0x30 => '##0.0E+0',
0x31 => '@',
);
#------------------------------------------------------------------------------
# new (for Spreadsheet::ParseExcel::FmtDefault)
#------------------------------------------------------------------------------
sub new {
my ( $sPkg, %hKey ) = @_;
my $oThis = {};
bless $oThis;
return $oThis;
}
#------------------------------------------------------------------------------
# TextFmt (for Spreadsheet::ParseExcel::FmtDefault)
#------------------------------------------------------------------------------
sub TextFmt {
my ( $oThis, $sTxt, $sCode ) = @_;
return $sTxt if ( ( !defined($sCode) ) || ( $sCode eq '_native_' ) );
return pack( 'U*', unpack( 'n*', $sTxt ) );
}
#------------------------------------------------------------------------------
# FmtStringDef (for Spreadsheet::ParseExcel::FmtDefault)
#------------------------------------------------------------------------------
sub FmtStringDef {
my ( $oThis, $iFmtIdx, $oBook, $rhFmt ) = @_;
my $sFmtStr = $oBook->{FormatStr}->{$iFmtIdx};
if ( !( defined($sFmtStr) ) && defined($rhFmt) ) {
$sFmtStr = $rhFmt->{$iFmtIdx};
}
$sFmtStr = $hFmtDefault{$iFmtIdx} unless ($sFmtStr);
return $sFmtStr;
}
#------------------------------------------------------------------------------
# FmtString (for Spreadsheet::ParseExcel::FmtDefault)
#------------------------------------------------------------------------------
sub FmtString {
my ( $oThis, $oCell, $oBook ) = @_;
my $sFmtStr =
$oThis->FmtStringDef( $oBook->{Format}[ $oCell->{FormatNo} ]->{FmtIdx},
$oBook );
# Special case for cells that use Lotus123 style leading
# apostrophe to designate text formatting.
if ( $oBook->{Format}[ $oCell->{FormatNo} ]->{Key123} ) {
$sFmtStr = '@';
}
unless ( defined($sFmtStr) ) {
if ( $oCell->{Type} eq 'Numeric' ) {
if ( int( $oCell->{Val} ) != $oCell->{Val} ) {
$sFmtStr = '0.00';
}
else {
$sFmtStr = '0';
}
}
elsif ( $oCell->{Type} eq 'Date' ) {
if ( int( $oCell->{Val} ) <= 0 ) {
$sFmtStr = 'h:mm:ss';
}
else {
$sFmtStr = 'yyyy-mm-dd';
}
}
else {
$sFmtStr = '@';
}
}
return $sFmtStr;
}
#------------------------------------------------------------------------------
# ValFmt (for Spreadsheet::ParseExcel::FmtDefault)
#------------------------------------------------------------------------------
sub ValFmt {
my ( $oThis, $oCell, $oBook ) = @_;
my ( $Dt, $iFmtIdx, $iNumeric, $Flg1904 );
if ( $oCell->{Type} eq 'Text' ) {
$Dt =
( ( defined $oCell->{Val} ) && ( $oCell->{Val} ne '' ) )
? $oThis->TextFmt( $oCell->{Val}, $oCell->{Code} )
: '';
return $Dt;
}
else {
$Dt = $oCell->{Val};
$Flg1904 = $oBook->{Flg1904};
my $sFmtStr = $oThis->FmtString( $oCell, $oBook );
return ExcelFmt( $sFmtStr, $Dt, $Flg1904, $oCell->{Type} );
}
}
#------------------------------------------------------------------------------
# ChkType (for Spreadsheet::ParseExcel::FmtDefault)
#------------------------------------------------------------------------------
sub ChkType {
my ( $oPkg, $iNumeric, $iFmtIdx ) = @_;
if ($iNumeric) {
if ( ( ( $iFmtIdx >= 0x0E ) && ( $iFmtIdx <= 0x16 ) )
|| ( ( $iFmtIdx >= 0x2D ) && ( $iFmtIdx <= 0x2F ) ) )
{
return "Date";
}
else {
return "Numeric";
}
}
else {
return "Text";
}
}
1;
__END__
=pod
=head1 NAME
Spreadsheet::ParseExcel::FmtDefault - A class for Cell formats.
=head1 SYNOPSIS
See the documentation for Spreadsheet::ParseExcel.
=head1 DESCRIPTION
This module is used in conjunction with Spreadsheet::ParseExcel. See the documentation for Spreadsheet::ParseExcel.
=head1 AUTHOR
Current maintainer 0.60+: Douglas Wilson dougw@cpan.org
Maintainer 0.40-0.59: John McNamara jmcnamara@cpan.org
Maintainer 0.27-0.33: Gabor Szabo szabgab@cpan.org
Original author: Kawai Takanori kwitknr@cpan.org
=head1 COPYRIGHT
Copyright (c) 2014 Douglas Wilson
Copyright (c) 2009-2013 John McNamara
Copyright (c) 2006-2008 Gabor Szabo
Copyright (c) 2000-2006 Kawai Takanori
All rights reserved.
You may distribute under the terms of either the GNU General Public License or the Artistic License, as specified in the Perl README file.
=cut
Spreadsheet-ParseExcel-0.66/lib/Spreadsheet/ParseExcel/Workbook.pm 000644 000765 000024 00000016026 14543413026 025220 0 ustar 00John staff 000000 000000 package Spreadsheet::ParseExcel::Workbook;
###############################################################################
#
# Spreadsheet::ParseExcel::Workbook - A class for Workbooks.
#
# Used in conjunction with Spreadsheet::ParseExcel.
#
# Copyright (c) 2014 Douglas Wilson
# Copyright (c) 2009-2013 John McNamara
# Copyright (c) 2006-2008 Gabor Szabo
# Copyright (c) 2000-2006 Kawai Takanori
#
# perltidy with standard settings.
#
# Documentation after __END__
#
use strict;
use warnings;
our $VERSION = '0.66';
###############################################################################
#
# new()
#
# Constructor.
#
sub new {
my ($class) = @_;
my $self = {};
bless $self, $class;
}
###############################################################################
sub color_idx_to_rgb {
my( $workbook, $iidx ) = @_;
my $palette = $workbook->{aColor};
return ( ( defined $palette->[$iidx] ) ? $palette->[$iidx] : $palette->[0] );
}
###############################################################################
#
# worksheet()
#
# This method returns a single Worksheet object using either its name or index.
#
sub worksheet {
my ( $oBook, $sName ) = @_;
my $oWkS;
foreach $oWkS ( @{ $oBook->{Worksheet} } ) {
return $oWkS if ( $oWkS->{Name} eq $sName );
}
if ( $sName =~ /^\d+$/ ) {
return $oBook->{Worksheet}->[$sName];
}
return undef;
}
###############################################################################
#
# worksheets()
#
# Returns an array of Worksheet objects.
#
sub worksheets {
my $self = shift;
return @{ $self->{Worksheet} };
}
###############################################################################
#
# worksheet_count()
#
# Returns the number Woksheet objects in the Workbook.
#
sub worksheet_count {
my $self = shift;
return $self->{SheetCount};
}
###############################################################################
#
# get_filename()
#
# Returns the name of the Excel file of C if the data was read from a filehandle rather than a file.
#
sub get_filename {
my $self = shift;
return $self->{File};
}
###############################################################################
#
# get_print_areas()
#
# Returns an array ref of print areas.
#
# TODO. This should really be a Worksheet method.
#
sub get_print_areas {
my $self = shift;
return $self->{PrintArea};
}
###############################################################################
#
# get_print_titles()
#
# Returns an array ref of print title hash refs.
#
# TODO. This should really be a Worksheet method.
#
sub get_print_titles {
my $self = shift;
return $self->{PrintTitle};
}
###############################################################################
#
# using_1904_date()
#
# Returns true if the Excel file is using the 1904 date epoch.
#
sub using_1904_date {
my $self = shift;
return $self->{Flg1904};
}
###############################################################################
#
# ParseAbort()
#
# Todo
#
sub ParseAbort {
my ( $self, $val ) = @_;
$self->{_ParseAbort} = $val;
}
=head2 get_active_sheet()
Return the number of the active (open) worksheet (at the time the workbook
was saved. May return undef.
=cut
sub get_active_sheet {
my $workbook = shift;
return $workbook->{ActiveSheet};
}
###############################################################################
#
# Parse(). Deprecated.
#
# Syntactic wrapper around Spreadsheet::ParseExcel::Parse().
# This method is *deprecated* since it doesn't conform to the current
# error handling in the S::PE Parse() method.
#
sub Parse {
my ( $class, $source, $formatter ) = @_;
my $excel = Spreadsheet::ParseExcel->new();
my $workbook = $excel->Parse( $source, $formatter );
$workbook->{_Excel} = $excel;
return $workbook;
}
###############################################################################
#
# Mapping between legacy method names and new names.
#
{
no warnings; # Ignore warnings about variables used only once.
*Worksheet = *worksheet;
}
1;
__END__
=pod
=head1 NAME
Spreadsheet::ParseExcel::Workbook - A class for Workbooks.
=head1 SYNOPSIS
See the documentation for Spreadsheet::ParseExcel.
=head1 DESCRIPTION
This module is used in conjunction with Spreadsheet::ParseExcel. See the documentation for L.
=head1 Methods
The following Workbook methods are available:
$workbook->worksheets()
$workbook->worksheet()
$workbook->worksheet_count()
$workbook->get_filename()
$workbook->get_print_areas()
$workbook->get_print_titles()
$workbook->using_1904_date()
=head2 worksheets()
The C method returns an array of Worksheet objects. This was most commonly used to iterate over the worksheets in a workbook:
for my $worksheet ( $workbook->worksheets() ) {
...
}
=head2 worksheet()
The C method returns a single C object using either its name or index:
$worksheet = $workbook->worksheet('Sheet1');
$worksheet = $workbook->worksheet(0);
Returns C if the sheet name or index doesn't exist.
=head2 worksheet_count()
The C method returns the number of Woksheet objects in the Workbook.
my $worksheet_count = $workbook->worksheet_count();
=head2 get_filename()
The C method returns the name of the Excel file of C if the data was read from a filehandle rather than a file.
my $filename = $workbook->get_filename();
=head2 get_print_areas()
The C method returns an array ref of print areas.
my $print_areas = $workbook->get_print_areas();
Each print area is as follows:
[ $start_row, $start_col, $end_row, $end_col ]
Returns undef if there are no print areas.
=head2 get_print_titles()
The C method returns an array ref of print title hash refs.
my $print_titles = $workbook->get_print_titles();
Each print title array ref is as follows:
{
Row => [ $start_row, $end_row ],
Column => [ $start_col, $end_col ],
}
Returns undef if there are no print titles.
=head2 using_1904_date()
The C method returns true if the Excel file is using the 1904 date epoch instead of the 1900 epoch.
my $using_1904_date = $workbook->using_1904_date();
The Windows version of Excel generally uses the 1900 epoch while the Mac version of Excel generally uses the 1904 epoch.
Returns 0 if the 1900 epoch is in use.
=head1 AUTHOR
Current maintainer 0.60+: Douglas Wilson dougw@cpan.org
Maintainer 0.40-0.59: John McNamara jmcnamara@cpan.org
Maintainer 0.27-0.33: Gabor Szabo szabgab@cpan.org
Original author: Kawai Takanori kwitknr@cpan.org
=head1 COPYRIGHT
Copyright (c) 2014 Douglas Wilson
Copyright (c) 2009-2013 John McNamara
Copyright (c) 2006-2008 Gabor Szabo
Copyright (c) 2000-2006 Kawai Takanori
All rights reserved.
You may distribute under the terms of either the GNU General Public License or the Artistic License, as specified in the Perl README file.
=cut
Spreadsheet-ParseExcel-0.66/lib/Spreadsheet/ParseExcel/Utility.pm 000644 000765 000024 00000156055 14543413026 025075 0 ustar 00John staff 000000 000000 package Spreadsheet::ParseExcel::Utility;
###############################################################################
#
# Spreadsheet::ParseExcel::Utility - Utility functions for ParseExcel.
#
# Used in conjunction with Spreadsheet::ParseExcel.
#
# Copyright (c) 2014 Douglas Wilson
# Copyright (c) 2009-2013 John McNamara
# Copyright (c) 2006-2008 Gabor Szabo
# Copyright (c) 2000-2006 Kawai Takanori
#
# perltidy with standard settings.
#
# Documentation after __END__
#
use strict;
use warnings;
require Exporter;
use vars qw(@ISA @EXPORT_OK);
@ISA = qw(Exporter);
@EXPORT_OK = qw(ExcelFmt LocaltimeExcel ExcelLocaltime
col2int int2col sheetRef xls2csv);
our $VERSION = '0.66';
my $qrNUMBER = qr/(^[+-]?\d+(\.\d+)?$)|(^[+-]?\d+\.?(\d*)[eE][+-](\d+))$/;
###############################################################################
#
# ExcelFmt()
#
# This function takes an Excel style number format and converts a number into
# that format. for example: 'hh:mm:ss AM/PM' + 0.01023148 = '12:14:44 AM'.
#
# It does this with a type of templating mechanism. The format string is parsed
# to identify tokens that need to be replaced and their position within the
# string is recorded. These can be thought of as placeholders. The number is
# then converted to the required formats and substituted into the placeholders.
#
# Interested parties should refer to the Excel documentation on cell formats for
# more information: http://office.microsoft.com/en-us/excel/HP051995001033.aspx
# The Microsoft documentation for the Excel Binary File Format, [MS-XLS].pdf,
# also contains a ABNF grammar for number format strings.
#
# Maintainers notes:
# ==================
#
# Note on format subsections:
# A format string can contain 4 possible sub-sections separated by semi-colons:
# Positive numbers, negative numbers, zero values, and text.
# For example: _(* #,##0_);_(* (#,##0);_(* "-"_);_(@_)
#
# Note on conditional formats.
# A number format in Excel can have a conditional expression such as:
# [>9999999](000)000-0000;000-0000
# This is equivalent to the following in Perl:
# $format = $number > 9999999 ? '(000)000-0000' : '000-0000';
# Nested conditionals are also possible but we don't support them.
#
# Efficiency: The excessive use of substr() isn't very efficient. However,
# it probably doesn't merit rewriting this function with a parser or regular
# expressions and \G.
#
# TODO: I think the single quote handling may not be required. Check.
#
sub ExcelFmt {
my ( $format_str, $number, $is_1904, $number_type, $want_subformats ) = @_;
# Return text strings without further formatting.
return $number unless $number =~ $qrNUMBER;
# Handle OpenOffice.org GENERAL format.
$format_str = '@' if uc($format_str) eq "GENERAL";
# Check for a conditional at the start of the format. See notes above.
my $conditional_op;
my $conditional_value;
if ( $format_str =~ /^\[([<>=]+)([^\]]+)\](.*)$/ ) {
$conditional_op = $1;
$conditional_value = $2;
$format_str = $3;
}
# Ignore the underscore token which is used to indicate a padding space.
$format_str =~ s/_/ /g;
# Split the format string into 4 possible sub-sections: positive numbers,
# negative numbers, zero values, and text. See notes above.
my @formats;
my $section = 0;
my $double_quote = 0;
my $single_quote = 0;
# Initial parsing of the format string to remove escape characters. This
# also handles quoted strings. See note about single quotes above.
CHARACTER:
for my $char ( split //, $format_str ) {
if ( $double_quote or $single_quote ) {
$formats[$section] .= $char;
$double_quote = 0 if $char eq '"';
$single_quote = 0;
next CHARACTER;
}
if ( $char eq ';' ) {
$section++;
next CHARACTER;
}
elsif ( $char eq '"' ) {
$double_quote = 1;
}
elsif ( $char eq '!' ) {
$single_quote = 1;
}
elsif ( $char eq '\\' ) {
$single_quote = 1;
}
elsif ( $char eq '(' ) {
next CHARACTER; # Ignore.
}
elsif ( $char eq ')' ) {
next CHARACTER; # Ignore.
}
# Convert upper case OpenOffice.org date/time formats to lowercase..
$char = lc($char) if $char =~ /[DMYHS]/;
$formats[$section] .= $char;
}
# Select the appropriate format from the 4 possible sub-sections:
# positive numbers, negative numbers, zero values, and text.
# We ignore the Text section since non-numeric values are returned
# unformatted at the start of the function.
my $format;
$section = 0;
if ( @formats == 1 ) {
$section = 0;
}
elsif ( @formats == 2 ) {
if ( $number < 0 ) {
$section = 1;
}
else {
$section = 0;
}
}
elsif ( @formats == 3 ) {
if ( $number == 0 ) {
$section = 2;
}
elsif ( $number < 0 ) {
$section = 1;
}
else {
$section = 0;
}
}
else {
$section = 0;
}
# Override the previous choice if the format is conditional.
if ($conditional_op) {
if ($conditional_op eq '>') {
$section = $number > $conditional_value ? 0 : 1;
} elsif ($conditional_op eq '>=') {
$section = $number >= $conditional_value ? 0 : 1;
} elsif ($conditional_op eq '<') {
$section = $number < $conditional_value ? 0 : 1;
} elsif ($conditional_op eq '<=') {
$section = $number <= $conditional_value ? 0 : 1;
} elsif ($conditional_op eq '=') {
$section = $number == $conditional_value ? 0 : 1;
} elsif ($conditional_op eq '==') {
$section = $number == $conditional_value ? 0 : 1;
} elsif ($conditional_op eq '<>') {
$section = $number != $conditional_value ? 0 : 1;
}
}
# We now have the required format.
$format = $formats[$section];
# The format string can contain one of the following colours:
# [Black] [Blue] [Cyan] [Green] [Magenta] [Red] [White] [Yellow]
# or the string [ColorX] where x is a colour index from 1 to 56.
# We don't use the colour but we return it to the caller.
#
my $color = '';
if ( $format =~ s/^(\[[A-Za-z]{3,}(\d{1,2})?\])// ) {
$color = $1;
}
# Remove the locale, such as [$-409], from the format string.
my $locale = '';
if ( $format =~ s/^(\[\$?-F?\d+\])// ) {
$locale = $1;
}
# Replace currency locale, such as [$$-409], with $ in the format string.
# See the RT#60547 test cases in 21_number_format_user.t.
if ( $format =~ s/(\[\$([^-]+)(-\d+)?\])/$2/s ) {
$locale = $1;
}
# Remove leading # from '# ?/?', '# ??/??' fraction formats.
$format =~ s{# \?}{?}g;
# Parse the format string and create an AoA of placeholders that contain
# the parts of the string to be replaced. The format of the information
# stored is: [ $token, $start_pos, $end_pos, $option_info ].
#
my $format_mode = ''; # Either: '', 'number', 'date'
my $pos = 0; # Character position within format string.
my @placeholders = (); # Arefs with parts of the format to be replaced.
my $token = ''; # The actual format extracted from the total str.
my $start_pos; # A position variable. Initial parser position.
my $token_start = -1; # A position variable.
my $decimal_pos = -1; # Position of the punctuation char "." or ",".
my $comma_count = 0; # Count of the commas in the format.
my $is_fraction = 0; # Number format is a fraction.
my $is_currency = 0; # Number format is a currency.
my $is_percent = 0; # Number format is a percentage.
my $is_12_hour = 0; # Time format is using 12 hour clock.
my $seen_dot = 0; # Treat only the first "." as the decimal point.
# Parse the format.
PARSER:
while ( $pos < length $format ) {
$start_pos = $pos;
my $char = substr( $format, $pos, 1 );
# Ignore control format characters such as '#0+-.?eE,%'. However,
# only ignore '.' if it is the first one encountered. RT 45502.
if ( ( !$seen_dot && $char !~ /[#0\+\-\.\?eE\,\%]/ )
|| $char !~ /[#0\+\-\?eE\,\%]/ )
{
if ( $token_start != -1 ) {
push @placeholders,
[
substr( $format, $token_start, $pos - $token_start ),
$decimal_pos, $pos - $token_start
];
$token_start = -1;
}
}
# Processing for quoted strings within the format. See notes above.
if ( $char eq '"' ) {
$double_quote = $double_quote ? 0 : 1;
$pos++;
next PARSER;
}
elsif ( $char eq '!' ) {
$single_quote = 1;
$pos++;
next PARSER;
}
elsif ( $char eq '\\' ) {
if ( $single_quote != 1 ) {
$single_quote = 1;
$pos++;
next PARSER;
}
}
if ( ( defined($double_quote) and ($double_quote) )
or ( defined($single_quote) and ($single_quote) )
or ( $seen_dot && $char eq '.' ) )
{
$single_quote = 0;
if (
( $format_mode ne 'date' )
and ( ( substr( $format, $pos, 2 ) eq "\x81\xA2" )
|| ( substr( $format, $pos, 2 ) eq "\x81\xA3" )
|| ( substr( $format, $pos, 2 ) eq "\xA2\xA4" )
|| ( substr( $format, $pos, 2 ) eq "\xA2\xA5" ) )
)
{
# The above matches are currency symbols.
push @placeholders,
[ substr( $format, $pos, 2 ), length($token), 2 ];
$is_currency = 1;
$pos += 2;
}
else {
$pos++;
}
}
elsif (
( $char =~ /[#0\+\.\?eE\,\%]/ )
|| ( ( $format_mode ne 'date' )
and ( ( $char eq '-' ) || ( $char eq '(' ) || ( $char eq ')' ) )
)
)
{
$format_mode = 'number' unless $format_mode;
if ( substr( $format, $pos, 1 ) =~ /[#0]/ ) {
if (
substr( $format, $pos ) =~
/^([#0]+[\.]?[0#]*[eE][\+\-][0#]+)/ )
{
push @placeholders, [ $1, $pos, length($1) ];
$pos += length($1);
}
else {
if ( $token_start == -1 ) {
$token_start = $pos;
$decimal_pos = length($token);
}
}
}
elsif ( substr( $format, $pos, 1 ) eq '?' ) {
# Look for a fraction format like ?/? or ??/??
if ( $token_start != -1 ) {
push @placeholders,
[
substr(
$format, $token_start, $pos - $token_start + 1
),
$decimal_pos,
$pos - $token_start + 1
];
}
$token_start = $pos;
# Find the end of the fraction format.
FRACTION:
while ( $pos < length($format) ) {
if ( substr( $format, $pos, 1 ) eq '/' ) {
$is_fraction = 1;
}
elsif ( substr( $format, $pos, 1 ) eq '?' ) {
$pos++;
next FRACTION;
}
else {
if ( $is_fraction
&& ( substr( $format, $pos, 1 ) =~ /[0-9]/ ) )
{
# TODO: Could invert if() logic and remove this.
$pos++;
next FRACTION;
}
else {
last FRACTION;
}
}
$pos++;
}
$pos--;
push @placeholders,
[
substr( $format, $token_start, $pos - $token_start + 1 ),
length($token), $pos - $token_start + 1
];
$token_start = -1;
}
elsif ( substr( $format, $pos, 3 ) =~ /^[eE][\+\-][0#]$/ ) {
if ( substr( $format, $pos ) =~ /([eE][\+\-][0#]+)/ ) {
push @placeholders, [ $1, $pos, length($1) ];
$pos += length($1);
}
$token_start = -1;
}
else {
if ( $token_start != -1 ) {
push @placeholders,
[
substr( $format, $token_start, $pos - $token_start ),
$decimal_pos, $pos - $token_start
];
$token_start = -1;
}
if ( substr( $format, $pos, 1 ) =~ /[\+\-]/ ) {
push @placeholders,
[ substr( $format, $pos, 1 ), length($token), 1 ];
$is_currency = 1;
}
elsif ( substr( $format, $pos, 1 ) eq '.' ) {
push @placeholders,
[ substr( $format, $pos, 1 ), length($token), 1 ];
$seen_dot = 1;
}
elsif ( substr( $format, $pos, 1 ) eq ',' ) {
$comma_count++;
push @placeholders,
[ substr( $format, $pos, 1 ), length($token), 1 ];
}
elsif ( substr( $format, $pos, 1 ) eq '%' ) {
$is_percent = 1;
}
elsif (( substr( $format, $pos, 1 ) eq '(' )
|| ( substr( $format, $pos, 1 ) eq ')' ) )
{
push @placeholders,
[ substr( $format, $pos, 1 ), length($token), 1 ];
$is_currency = 1;
}
}
$pos++;
}
elsif ( $char =~ /[ymdhsapg]/i ) {
$format_mode = 'date' unless $format_mode;
if ( substr( $format, $pos, 5 ) =~ /am\/pm/i ) {
push @placeholders, [ 'am/pm', length($token), 5 ];
$is_12_hour = 1;
$pos += 5;
}
elsif ( substr( $format, $pos, 3 ) =~ /a\/p/i ) {
push @placeholders, [ 'a/p', length($token), 3 ];
$is_12_hour = 1;
$pos += 3;
}
elsif ( substr( $format, $pos, 5 ) eq 'mmmmm' ) {
push @placeholders, [ 'mmmmm', length($token), 5 ];
$pos += 5;
}
elsif (( substr( $format, $pos, 4 ) eq 'mmmm' )
|| ( substr( $format, $pos, 4 ) eq 'dddd' )
|| ( substr( $format, $pos, 4 ) eq 'yyyy' )
|| ( substr( $format, $pos, 4 ) eq 'ggge' ) )
{
push @placeholders,
[ substr( $format, $pos, 4 ), length($token), 4 ];
$pos += 4;
}
elsif (( substr( $format, $pos, 3 ) eq 'ddd' )
|| ( substr( $format, $pos, 3 ) eq 'mmm' )
|| ( substr( $format, $pos, 3 ) eq 'yyy' ) )
{
push @placeholders,
[ substr( $format, $pos, 3 ), length($token), 3 ];
$pos += 3;
}
elsif (( substr( $format, $pos, 2 ) eq 'yy' )
|| ( substr( $format, $pos, 2 ) eq 'mm' )
|| ( substr( $format, $pos, 2 ) eq 'dd' )
|| ( substr( $format, $pos, 2 ) eq 'hh' )
|| ( substr( $format, $pos, 2 ) eq 'ss' )
|| ( substr( $format, $pos, 2 ) eq 'ge' ) )
{
if (
( substr( $format, $pos, 2 ) eq 'mm' )
&& (@placeholders)
&& ( ( $placeholders[-1]->[0] eq 'h' )
or ( $placeholders[-1]->[0] eq 'hh' ) )
)
{
# For this case 'm' is minutes not months.
push @placeholders, [ 'mm', length($token), 2, 'minutes' ];
}
else {
push @placeholders,
[ substr( $format, $pos, 2 ), length($token), 2 ];
}
if ( ( substr( $format, $pos, 2 ) eq 'ss' )
&& ( @placeholders > 1 ) )
{
if ( ( $placeholders[-2]->[0] eq 'm' )
|| ( $placeholders[-2]->[0] eq 'mm' ) )
{
# For this case 'm' is minutes not months.
push( @{ $placeholders[-2] }, 'minutes' );
}
}
$pos += 2;
}
elsif (( substr( $format, $pos, 1 ) eq 'm' )
|| ( substr( $format, $pos, 1 ) eq 'd' )
|| ( substr( $format, $pos, 1 ) eq 'h' )
|| ( substr( $format, $pos, 1 ) eq 's' ) )
{
if (
( substr( $format, $pos, 1 ) eq 'm' )
&& (@placeholders)
&& ( ( $placeholders[-1]->[0] eq 'h' )
or ( $placeholders[-1]->[0] eq 'hh' ) )
)
{
# For this case 'm' is minutes not months.
push @placeholders, [ 'm', length($token), 1, 'minutes' ];
}
else {
push @placeholders,
[ substr( $format, $pos, 1 ), length($token), 1 ];
}
if ( ( substr( $format, $pos, 1 ) eq 's' )
&& ( @placeholders > 1 ) )
{
if ( ( $placeholders[-2]->[0] eq 'm' )
|| ( $placeholders[-2]->[0] eq 'mm' ) )
{
# For this case 'm' is minutes not months.
push( @{ $placeholders[-2] }, 'minutes' );
}
}
$pos += 1;
}
}
elsif ( ( substr( $format, $pos, 3 ) eq '[h]' ) ) {
$format_mode = 'date' unless $format_mode;
push @placeholders, [ '[h]', length($token), 3 ];
$pos += 3;
}
elsif ( ( substr( $format, $pos, 4 ) eq '[mm]' ) ) {
$format_mode = 'date' unless $format_mode;
push @placeholders, [ '[mm]', length($token), 4 ];
$pos += 4;
}
elsif ( $char eq '@' ) {
push @placeholders, [ '@', length($token), 1 ];
$pos++;
}
elsif ( $char eq '*' ) {
push @placeholders,
[ substr( $format, $pos, 1 ), length($token), 1 ];
}
else {
$pos++;
}
$pos++ if ( $pos == $start_pos ); #No Format match
$token .= substr( $format, $start_pos, $pos - $start_pos );
} # End of parsing.
# Copy the located format string to a result string that we will perform
# the substitutions on and return to the user.
my $result = $token;
# Add a placeholder between the decimal/comma and end of the token, if any.
if ( $token_start != -1 ) {
push @placeholders,
[
substr( $format, $token_start, $pos - $token_start + 1 ),
$decimal_pos, $pos - $token_start + 1
];
}
#
# In the next sections we process date, number and text formats. We take a
# format such as yyyy/mm/dd and replace it with something like 2008/12/25.
#
if ( ( $format_mode eq 'date' ) && ( $number =~ $qrNUMBER ) ) {
# The maximum allowable date in Excel is 9999-12-31T23:59:59.000 which
# equates to 2958465.999+ in the 1900 epoch and 2957003.999+ in the
# 1904 epoch. We use 0 as the minimum in both epochs. The 1904 system
# actually supports negative numbers but that isn't worth the effort.
my $min_date = 0;
my $max_date = 2958466;
$max_date = 2957004 if $is_1904;
if ( $number < $min_date || $number >= $max_date ) {
return $number; # Return unformatted number.
}
# Process date formats.
my @time = ExcelLocaltime( $number, $is_1904 );
# 0 1 2 3 4 5 6 7
my ( $sec, $min, $hour, $day, $month, $year, $wday, $msec ) = @time;
$month++; # localtime() zero indexed month.
$year += 1900; # localtime() year.
my @full_month_name = qw(
None January February March April May June July
August September October November December
);
my @short_month_name = qw(
None Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec
);
my @full_day_name = qw(
Sunday Monday Tuesday Wednesday Thursday Friday Saturday
);
my @short_day_name = qw(
Sun Mon Tue Wed Thu Fri Sat
);
# Replace the placeholders in the template such as yyyy mm dd with
# actual numbers or strings.
my $replacement;
for my $placeholder ( reverse @placeholders ) {
if ( $placeholder->[-1] eq 'minutes' ) {
# For this case 'm/mm' is minutes not months.
if ( $placeholder->[0] eq 'mm' ) {
$replacement = sprintf( "%02d", $min );
}
else {
$replacement = sprintf( "%d", $min );
}
}
elsif ( $placeholder->[0] eq 'yyyy' ) {
# 4 digit Year. 2000 -> 2000.
$replacement = sprintf( '%04d', $year );
}
elsif ( $placeholder->[0] eq 'yy' ) {
# 2 digit Year. 2000 -> 00.
$replacement = sprintf( '%02d', $year % 100 );
}
elsif ( $placeholder->[0] eq 'mmmmm' ) {
# First character of the month name. 1 -> J.
$replacement = substr( $short_month_name[$month], 0, 1 );
}
elsif ( $placeholder->[0] eq 'mmmm' ) {
# Full month name. 1 -> January.
$replacement = $full_month_name[$month];
}
elsif ( $placeholder->[0] eq 'mmm' ) {
# Short month name. 1 -> Jan.
$replacement = $short_month_name[$month];
}
elsif ( $placeholder->[0] eq 'mm' ) {
# 2 digit month. 1 -> 01.
$replacement = sprintf( '%02d', $month );
}
elsif ( $placeholder->[0] eq 'm' ) {
# 1 digit month. 1 -> 1.
$replacement = sprintf( '%d', $month );
}
elsif ( $placeholder->[0] eq 'dddd' ) {
# Full day name. Wednesday (for example.)
$replacement = $full_day_name[$wday];
}
elsif ( $placeholder->[0] eq 'ddd' ) {
# Short day name. Wed (for example.)
$replacement = $short_day_name[$wday];
}
elsif ( $placeholder->[0] eq 'dd' ) {
# 2 digit day. 1 -> 01.
$replacement = sprintf( '%02d', $day );
}
elsif ( $placeholder->[0] eq 'd' ) {
# 1 digit day. 1 -> 1.
$replacement = sprintf( '%d', $day );
}
elsif ( $placeholder->[0] eq 'hh' ) {
# 2 digit hour.
if ($is_12_hour) {
my $hour_tmp = $hour % 12;
$hour_tmp = 12 if $hour % 12 == 0;
$replacement = sprintf( '%d', $hour_tmp );
}
else {
$replacement = sprintf( '%02d', $hour );
}
}
elsif ( $placeholder->[0] eq 'h' ) {
# 1 digit hour.
if ($is_12_hour) {
my $hour_tmp = $hour % 12;
$hour_tmp = 12 if $hour % 12 == 0;
$replacement = sprintf( '%2d', $hour_tmp );
}
else {
$replacement = sprintf( '%d', $hour );
}
}
elsif ( $placeholder->[0] eq 'ss' ) {
# 2 digit seconds.
$replacement = sprintf( '%02d', $sec );
}
elsif ( $placeholder->[0] eq 's' ) {
# 1 digit seconds.
$replacement = sprintf( '%d', $sec );
}
elsif ( $placeholder->[0] eq 'am/pm' ) {
# AM/PM.
$replacement = ( $hour >= 12 ) ? 'PM' : 'AM';
}
elsif ( $placeholder->[0] eq 'a/p' ) {
# AM/PM.
$replacement = ( $hour >= 12 ) ? 'P' : 'A';
}
elsif ( $placeholder->[0] eq '.' ) {
# Decimal point for seconds.
$replacement = '.';
}
elsif ( $placeholder->[0] =~ /(^0+$)/ ) {
# Milliseconds. For example h:ss.000.
my $length = length($1);
$replacement =
substr( sprintf( "%.${length}f", $msec / 1000 ), 2, $length );
}
elsif ( $placeholder->[0] eq '[h]' ) {
# Hours modulus 24. 25 displays as 25 not as 1.
$replacement = sprintf( '%d', int($number) * 24 + $hour );
}
elsif ( $placeholder->[0] eq '[mm]' ) {
# Mins modulus 60. 72 displays as 72 not as 12.
$replacement =
sprintf( '%d', ( int($number) * 24 + $hour ) * 60 + $min );
}
elsif ( $placeholder->[0] eq 'ge' ) {
require Spreadsheet::ParseExcel::FmtJapan;
# Japanese Nengo (aka Gengo) in initialism (abbr. name)
$replacement =
Spreadsheet::ParseExcel::FmtJapan::CnvNengo( abbr_name => @time );
}
elsif ( $placeholder->[0] eq 'ggge' ) {
require Spreadsheet::ParseExcel::FmtJapan;
# Japanese Nengo (aka Gengo) in Kanji (full name)
$replacement =
Spreadsheet::ParseExcel::FmtJapan::CnvNengo( name => @time );
}
elsif ( $placeholder->[0] eq '@' ) {
# Text format.
$replacement = $number;
}
elsif ( $placeholder->[0] eq ',' ) {
next;
}
# Substitute the replacement string back into the template.
substr( $result, $placeholder->[1], $placeholder->[2],
$replacement );
}
}
elsif ( ( $format_mode eq 'number' ) && ( $number =~ $qrNUMBER ) ) {
# Process non date formats.
if (@placeholders) {
while ( $placeholders[-1]->[0] eq ',' ) {
$comma_count--;
substr(
$result,
$placeholders[-1]->[1],
$placeholders[-1]->[2], ''
);
$number /= 1000;
pop @placeholders;
}
my $number_format = join( '', map { $_->[0] } @placeholders );
my $number_result;
my $str_length = 0;
my $engineering = 0;
my $is_decimal = 0;
my $is_integer = 0;
my $after_decimal = undef;
for my $token ( split //, $number_format ) {
if ( $token eq '.' ) {
$str_length++;
$is_decimal = 1;
}
elsif ( ( $token eq 'E' ) || ( $token eq 'e' ) ) {
$engineering = 1;
}
elsif ( $token eq '0' ) {
$str_length++;
$after_decimal++ if $is_decimal;
$is_integer = 1;
}
elsif ( $token eq '#' ) {
$after_decimal++ if $is_decimal;
$is_integer = 1;
}
elsif ( $token eq '?' ) {
$after_decimal++ if $is_decimal;
}
}
$number *= 100.0 if $is_percent;
my $data = ($is_currency) ? abs($number) : $number + 0;
if ($is_fraction) {
$number_result = sprintf( "%0${str_length}d", int($data) );
}
else {
if ($is_decimal) {
if ( defined $after_decimal ) {
$number_result =
sprintf "%0${str_length}.${after_decimal}f", $data;
}
else {
$number_result = sprintf "%0${str_length}f", $data;
}
# Fix for Perl and sprintf not rounding up like Excel.
# http://rt.cpan.org/Public/Bug/Display.html?id=45626
if ( $data =~ /^${number_result}5/ ) {
$number_result =
sprintf "%0${str_length}.${after_decimal}f",
$data . '1';
}
}
else {
$number_result = sprintf( "%0${str_length}.0f", $data );
}
}
$number_result = AddComma($number_result) if $comma_count > 0;
my $number_length = length($number_result);
my $decimal_pos = -1;
my $replacement;
for ( my $i = @placeholders - 1 ; $i >= 0 ; $i-- ) {
my $placeholder = $placeholders[$i];
if ( $placeholder->[0] =~
/([#0]*)([\.]?)([0#]*)([eE])([\+\-])([0#]+)/ )
{
substr( $result, $placeholder->[1], $placeholder->[2],
MakeE( $placeholder->[0], $number ) );
}
elsif ( $placeholder->[0] =~ /\// ) {
substr( $result, $placeholder->[1], $placeholder->[2],
MakeFraction( $placeholder->[0], $number, $is_integer )
);
}
elsif ( $placeholder->[0] eq '.' ) {
$number_length--;
$decimal_pos = $number_length;
}
elsif ( $placeholder->[0] eq '+' ) {
substr( $result, $placeholder->[1], $placeholder->[2],
( $number > 0 )
? '+'
: ( ( $number == 0 ) ? '+' : '-' ) );
}
elsif ( $placeholder->[0] eq '-' ) {
substr( $result, $placeholder->[1], $placeholder->[2],
( $number > 0 )
? ''
: ( ( $number == 0 ) ? '' : '-' ) );
}
elsif ( $placeholder->[0] eq '@' ) {
substr( $result, $placeholder->[1], $placeholder->[2],
$number );
}
elsif ( $placeholder->[0] eq '*' ) {
substr( $result, $placeholder->[1], $placeholder->[2], '' );
}
elsif (( $placeholder->[0] eq "\xA2\xA4" )
or ( $placeholder->[0] eq "\xA2\xA5" )
or ( $placeholder->[0] eq "\x81\xA2" )
or ( $placeholder->[0] eq "\x81\xA3" ) )
{
substr(
$result, $placeholder->[1],
$placeholder->[2], $placeholder->[0]
);
}
elsif (( $placeholder->[0] eq '(' )
or ( $placeholder->[0] eq ')' ) )
{
substr(
$result, $placeholder->[1],
$placeholder->[2], $placeholder->[0]
);
}
else {
if ( $number_length > 0 ) {
if ( $i <= 0 ) {
$replacement =
substr( $number_result, 0, $number_length );
$number_length = 0;
}
else {
my $real_part_length = length( $placeholder->[0] );
if ( $decimal_pos >= 0 ) {
my $format = $placeholder->[0];
$format =~ s/^#+//;
$real_part_length = length $format;
$real_part_length =
( $number_length <= $real_part_length )
? $number_length
: $real_part_length;
}
else {
$real_part_length =
( $number_length <= $real_part_length )
? $number_length
: $real_part_length;
}
$replacement =
substr( $number_result,
$number_length - $real_part_length,
$real_part_length );
$number_length -= $real_part_length;
}
}
else {
$replacement = '';
}
substr( $result, $placeholder->[1], $placeholder->[2],
"\x00" . $replacement );
}
}
$replacement =
( $number_length > 0 )
? substr( $number_result, 0, $number_length )
: '';
$result =~ s/\x00/$replacement/;
$result =~ s/\x00//g;
}
}
else {
# Process text formats
my $is_text = 0;
for ( my $i = @placeholders - 1 ; $i >= 0 ; $i-- ) {
my $placeholder = $placeholders[$i];
if ( $placeholder->[0] eq '@' ) {
substr( $result, $placeholder->[1], $placeholder->[2],
$number );
$is_text++;
}
else {
substr( $result, $placeholder->[1], $placeholder->[2], '' );
}
}
$result = $number unless $is_text;
} # End of placeholder substitutions.
# Trim the leading and trailing whitespace from the results.
$result =~ s/^\s+//;
$result =~ s/\s+$//;
# Fix for negative currency.
$result =~ s/^\$\-/\-\$/;
$result =~ s/^\$ \-/\-\$ /;
# Return color and locale strings if required.
if ($want_subformats) {
return ( $result, $color, $locale );
}
else {
return $result;
}
}
#------------------------------------------------------------------------------
# AddComma (for Spreadsheet::ParseExcel::Utility)
#------------------------------------------------------------------------------
sub AddComma {
my ($sNum) = @_;
if ( $sNum =~ /^([^\d]*)(\d\d\d\d+)(\.*.*)$/ ) {
my ( $sPre, $sObj, $sAft ) = ( $1, $2, $3 );
for ( my $i = length($sObj) - 3 ; $i > 0 ; $i -= 3 ) {
substr( $sObj, $i, 0, ',' );
}
return $sPre . $sObj . $sAft;
}
else {
return $sNum;
}
}
#------------------------------------------------------------------------------
# MakeFraction (for Spreadsheet::ParseExcel::Utility)
#------------------------------------------------------------------------------
sub MakeFraction {
my ( $sFmt, $iData, $iFlg ) = @_;
my $iBunbo;
my $iShou;
#1. Init
# print "FLG: $iFlg\n";
if ($iFlg) {
$iShou = $iData - int($iData);
return '' if ( $iShou == 0 );
}
else {
$iShou = $iData;
}
$iShou = abs($iShou);
my $sSWk;
#2.Calc BUNBO
#2.1 BUNBO defined
if ( $sFmt =~ /\/(\d+)$/ ) {
$iBunbo = $1;
return sprintf( "%d/%d", $iShou * $iBunbo, $iBunbo );
}
else {
#2.2 Calc BUNBO
$sFmt =~ /\/(\?+)$/;
my $iKeta = length($1);
my $iSWk = 1;
my $sSWk = '';
my $iBunsi;
for ( my $iBunbo = 2 ; $iBunbo < 10**$iKeta ; $iBunbo++ ) {
$iBunsi = int( $iShou * $iBunbo + 0.5 );
my $iCmp = abs( $iShou - ( $iBunsi / $iBunbo ) );
if ( $iCmp < $iSWk ) {
$iSWk = $iCmp;
$sSWk = sprintf( "%d/%d", $iBunsi, $iBunbo );
last if ( $iSWk == 0 );
}
}
return $sSWk;
}
}
#------------------------------------------------------------------------------
# MakeE (for Spreadsheet::ParseExcel::Utility)
#------------------------------------------------------------------------------
sub MakeE {
my ( $sFmt, $iData ) = @_;
$sFmt =~ /(([#0]*)[\.]?[#0]*)([eE])([\+\-][0#]+)/;
my ( $sKari, $iKeta, $sE, $sSisu ) = ( $1, length($2), $3, $4 );
$iKeta = 1 if ( $iKeta <= 0 );
my $iLog10 = 0;
$iLog10 = ( $iData == 0 ) ? 0 : ( log( abs($iData) ) / log(10) );
$iLog10 = (
int( $iLog10 / $iKeta ) +
( ( ( $iLog10 - int( $iLog10 / $iKeta ) ) < 0 ) ? -1 : 0 ) ) * $iKeta;
my $sUe = ExcelFmt( $sKari, $iData * ( 10**( $iLog10 * -1 ) ), 0 );
my $sShita = ExcelFmt( $sSisu, $iLog10, 0 );
return $sUe . $sE . $sShita;
}
#------------------------------------------------------------------------------
# LeapYear (for Spreadsheet::ParseExcel::Utility)
#------------------------------------------------------------------------------
sub LeapYear {
my ($iYear) = @_;
return 1 if ( $iYear == 1900 ); #Special for Excel
return ( ( ( $iYear % 4 ) == 0 )
&& ( ( $iYear % 100 ) || ( $iYear % 400 ) == 0 ) )
? 1
: 0;
}
#------------------------------------------------------------------------------
# LocaltimeExcel (for Spreadsheet::ParseExcel::Utility)
#------------------------------------------------------------------------------
sub LocaltimeExcel {
my ( $iSec, $iMin, $iHour, $iDay, $iMon, $iYear, $iwDay, $iMSec, $flg1904 )
= @_;
#0. Init
$iMon++;
$iYear += 1900;
#1. Calc Time
my $iTime;
$iTime = $iHour;
$iTime *= 60;
$iTime += $iMin;
$iTime *= 60;
$iTime += $iSec;
$iTime += $iMSec / 1000.0 if ( defined($iMSec) );
$iTime /= 86400.0; #3600*24(1day in seconds)
my $iY;
my $iYDays;
#2. Calc Days
if ($flg1904) {
$iY = 1904;
$iTime--; #Start from Jan 1st
$iYDays = 366;
}
else {
$iY = 1900;
$iYDays = 366; #In Excel 1900 is leap year (That's not TRUE!)
}
while ( $iY < $iYear ) {
$iTime += $iYDays;
$iY++;
$iYDays = ( LeapYear($iY) ) ? 366 : 365;
}
for ( my $iM = 1 ; $iM < $iMon ; $iM++ ) {
if ( $iM == 1
|| $iM == 3
|| $iM == 5
|| $iM == 7
|| $iM == 8
|| $iM == 10
|| $iM == 12 )
{
$iTime += 31;
}
elsif ( $iM == 4 || $iM == 6 || $iM == 9 || $iM == 11 ) {
$iTime += 30;
}
elsif ( $iM == 2 ) {
$iTime += ( LeapYear($iYear) ) ? 29 : 28;
}
}
$iTime += $iDay;
return $iTime;
}
my @month_days = qw(
0 31 28 31 30 31 30 31 31 30 31 30 31
);
#------------------------------------------------------------------------------
# ExcelLocaltime (for Spreadsheet::ParseExcel::Utility)
#------------------------------------------------------------------------------
sub ExcelLocaltime {
my ( $dObj, $flg1904 ) = @_;
my ( $iSec, $iMin, $iHour, $iDay, $iMon, $iYear, $iwDay, $iMSec );
my ( $iDt, $iTime, $iYDays, $iMD );
$iDt = int($dObj);
$iTime = $dObj - $iDt;
#1. Calc Days
if ($flg1904) {
$iYear = 1904;
$iDt++; #Start from Jan 1st
$iYDays = 366;
$iwDay = ( ( $iDt + 4 ) % 7 );
}
else {
$iYear = 1900;
$iYDays = 366; #In Excel 1900 is leap year (That's not TRUE!)
$iwDay = ( ( $iDt + 6 ) % 7 );
}
while ( $iDt > $iYDays ) {
$iDt -= $iYDays;
$iYear++;
$iYDays =
( ( ( $iYear % 4 ) == 0 )
&& ( ( $iYear % 100 ) || ( $iYear % 400 ) == 0 ) ) ? 366 : 365;
}
$iYear -= 1900; # Localtime year is relative to 1900.
for ( $iMon = 1 ; $iMon <= 12 ; $iMon++ ) {
$iMD = $month_days[$iMon];
$iMD++ if $iMon == 2 and $iYear % 4 == 0;
last if ( $iDt <= $iMD );
$iDt -= $iMD;
}
#2. Calc Time
$iDay = $iDt;
$iTime += ( 0.0005 / 86400.0 );
if ($iTime >= 1.0)
{
$iTime -= int($iTime);
$iwDay = ($iwDay == 6) ? 0 : $iwDay + 1;
if ($iDay == $iMD)
{
if ($iMon == 12)
{
$iMon = 1;
$iYear++;
}
else
{
$iMon++;
}
$iDay = 1;
}
else
{
$iDay++;
}
}
# Localtime month is 0 based.
$iMon -= 1;
$iTime *= 24.0;
$iHour = int($iTime);
$iTime -= $iHour;
$iTime *= 60.0;
$iMin = int($iTime);
$iTime -= $iMin;
$iTime *= 60.0;
$iSec = int($iTime);
$iTime -= $iSec;
$iTime *= 1000.0;
$iMSec = int($iTime);
return ( $iSec, $iMin, $iHour, $iDay, $iMon, $iYear, $iwDay, $iMSec );
}
# -----------------------------------------------------------------------------
# col2int (for Spreadsheet::ParseExcel::Utility)
#------------------------------------------------------------------------------
# converts a excel row letter into an int for use in an array
sub col2int {
my $result = 0;
my $str = shift;
my $incr = 0;
for ( my $i = length($str) ; $i > 0 ; $i-- ) {
my $char = substr( $str, $i - 1 );
my $curr += ord( lc($char) ) - ord('a') + 1;
$curr *= $incr if ($incr);
$result += $curr;
$incr += 26;
}
# this is one out as we range 0..x-1 not 1..x
$result--;
return $result;
}
# -----------------------------------------------------------------------------
# int2col (for Spreadsheet::ParseExcel::Utility)
#------------------------------------------------------------------------------
### int2col
# convert a column number into column letters
# @note this is quite a brute force coarse method
# does not manage values over 701 (ZZ)
# @arg number, to convert
# @returns string, column name
#
sub int2col {
my $out = "";
my $val = shift;
do {
$out .= chr( ( $val % 26 ) + ord('A') );
$val = int( $val / 26 ) - 1;
} while ( $val >= 0 );
return scalar reverse $out;
}
# -----------------------------------------------------------------------------
# sheetRef (for Spreadsheet::ParseExcel::Utility)
#------------------------------------------------------------------------------
# -----------------------------------------------------------------------------
### sheetRef
# convert an excel letter-number address into a useful array address
# @note that also Excel uses X-Y notation, we normally use Y-X in arrays
# @args $str, excel coord eg. A2
# @returns an array - 2 elements - column, row, or undefined
#
sub sheetRef {
my $str = shift;
my @ret;
$str =~ m/^(\D+)(\d+)$/;
if ( $1 && $2 ) {
push( @ret, $2 - 1, col2int($1) );
}
if ( $ret[0] < 0 ) {
undef @ret;
}
return @ret;
}
# -----------------------------------------------------------------------------
# xls2csv (for Spreadsheet::ParseExcel::Utility)
#------------------------------------------------------------------------------
### xls2csv
# convert a chunk of an excel file into csv text chunk
# @args $param, sheet-colrow:colrow (1-A1:B2 or A1:B2 for sheet 1
# @args $rotate, 0 or 1 decides if output should be rotated or not
# @returns string containing a chunk of csv
#
sub xls2csv {
my ( $filename, $regions, $rotate ) = @_;
my $sheet = 0;
# We need Text::CSV_XS for proper CSV handling.
require Text::CSV_XS;
# extract any sheet number from the region string
$regions =~ m/^(\d+)-(.*)/;
if ($2) {
$sheet = $1 - 1;
$regions = $2;
}
# now extract the start and end regions
$regions =~ m/(.*):(.*)/;
if ( !$1 || !$2 ) {
print STDERR "Bad Params";
return "";
}
my @start = sheetRef($1);
my @end = sheetRef($2);
if ( !@start ) {
print STDERR "Bad coorinates - $1";
return "";
}
if ( !@end ) {
print STDERR "Bad coorinates - $2";
return "";
}
if ( $start[1] > $end[1] ) {
print STDERR "Bad COLUMN ordering\n";
print STDERR "Start column " . int2col( $start[1] );
print STDERR " after end column " . int2col( $end[1] ) . "\n";
return "";
}
if ( $start[0] > $end[0] ) {
print STDERR "Bad ROW ordering\n";
print STDERR "Start row " . ( $start[0] + 1 );
print STDERR " after end row " . ( $end[0] + 1 ) . "\n";
exit;
}
# start the excel object now
my $oExcel = new Spreadsheet::ParseExcel;
my $oBook = $oExcel->Parse($filename);
# open the sheet
my $oWkS = $oBook->{Worksheet}[$sheet];
# now check that the region exists in the file
# if not truncate to the possible region
# output a warning msg
if ( $start[1] < $oWkS->{MinCol} ) {
print STDERR int2col( $start[1] )
. " < min col "
. int2col( $oWkS->{MinCol} )
. " Resetting\n";
$start[1] = $oWkS->{MinCol};
}
if ( $end[1] > $oWkS->{MaxCol} ) {
print STDERR int2col( $end[1] )
. " > max col "
. int2col( $oWkS->{MaxCol} )
. " Resetting\n";
$end[1] = $oWkS->{MaxCol};
}
if ( $start[0] < $oWkS->{MinRow} ) {
print STDERR ""
. ( $start[0] + 1 )
. " < min row "
. ( $oWkS->{MinRow} + 1 )
. " Resetting\n";
$start[0] = $oWkS->{MinCol};
}
if ( $end[0] > $oWkS->{MaxRow} ) {
print STDERR ""
. ( $end[0] + 1 )
. " > max row "
. ( $oWkS->{MaxRow} + 1 )
. " Resetting\n";
$end[0] = $oWkS->{MaxRow};
}
my $x1 = $start[1];
my $y1 = $start[0];
my $x2 = $end[1];
my $y2 = $end[0];
my @cell_data;
my $row = 0;
if ( !$rotate ) {
for ( my $y = $y1 ; $y <= $y2 ; $y++ ) {
for ( my $x = $x1 ; $x <= $x2 ; $x++ ) {
my $cell = $oWkS->{Cells}[$y][$x];
my $value;
if ( defined $cell ) {
$value .= $cell->value();
}
else {
$value = '';
}
push @{ $cell_data[$row] }, $value;
}
$row++;
}
}
else {
for ( my $x = $x1 ; $x <= $x2 ; $x++ ) {
for ( my $y = $y1 ; $y <= $y2 ; $y++ ) {
my $cell = $oWkS->{Cells}[$y][$x];
my $value;
if ( defined $cell ) {
$value .= $cell->value();
}
else {
$value = '';
}
push @{ $cell_data[$row] }, $value;
}
$row++;
}
}
# Create the CSV output string.
my $csv = Text::CSV_XS->new( { binary => 1, eol => $/ } );
my $output = "";
for my $row (@cell_data) {
$csv->combine(@$row);
$output .= $csv->string();
}
return $output;
}
1;
__END__
=pod
=head1 NAME
Spreadsheet::ParseExcel::Utility - Utility functions for Spreadsheet::ParseExcel.
=head1 SYNOPSIS
use Spreadsheet::ParseExcel::Utility qw(ExcelFmt ExcelLocaltime LocaltimeExcel);
# Convert localtime to Excel time
my $datetime = LocaltimeExcel(11, 10, 12, 23, 2, 64); # 1964-3-23 12:10:11
print $datetime, "\n"; # 23459.5070717593 (Excel date/time format)
# Convert Excel Time to localtime
my @time = ExcelLocaltime($datetime);
print join(":", @time), "\n"; # 11:10:12:23:2:64:1:0
# Formatting
print ExcelFmt('yyyy-mm-dd', $datetime), "\n"; # 1964-3-23
print ExcelFmt('m-d-yy', $datetime), "\n"; # 3-23-64
print ExcelFmt('#,##0', $datetime), "\n"; # 23,460
print ExcelFmt('#,##0.00', $datetime), "\n"; # 23,459.51
=head1 DESCRIPTION
The C module provides utility functions for working with ParseExcel and Excel data.
=head1 Functions
C can export the following functions:
ExcelFmt
ExcelLocaltime
LocaltimeExcel
col2int
int2col
sheetRef
xls2csv
These functions must be imported implicitly:
# Just one function.
use Spreadsheet::ParseExcel::Utility 'col2int';
# More than one.
use Spreadsheet::ParseExcel::Utility qw(ExcelFmt ExcelLocaltime LocaltimeExcel);
=head2 ExcelFmt($format_string, $number, $is_1904)
Excel stores data such as dates and currency values as numbers. The way these numbers are displayed is controlled by the number format string for the cell. For example a cell with a number format of C<'$#,##0.00'> for currency and a value of 1234.567 would be displayed as follows:
'$#,##0.00' + 1234.567 = '$1,234.57'.
The C function tries to emulate this formatting so that the user can convert raw numbers returned by C to a desired format. For example:
print ExcelFmt('$#,##0.00', 1234.567); # $1,234.57.
The syntax of the function is:
my $text = ExcelFmt($format_string, $number, $is_1904);
Where C<$format_string> is an Excel number format string, C<$number> is a real or integer number and C is an optional flag to indicate that dates should use Excel's 1904 epoch instead of the default 1900 epoch.
C is also used internally to convert numbers returned by the C method to the formatted value returned by the C method:
my $cell = $worksheet->get_cell( 0, 0 );
print $cell->unformatted(), "\n"; # 1234.567
print $cell->value(), "\n"; # $1,234.57
The most common usage for C is to convert numbers to dates. Dates and times in Excel are represented by real numbers, for example "1 Jan 2001 12:30 PM" is represented by the number 36892.521. The integer part of the number stores the number of days since the epoch and the fractional part stores the percentage of the day. By applying an Excel number format the number is converted to the desired string representation:
print ExcelFmt('d mmm yyyy h:mm AM/PM', 36892.521); # 1 Jan 2001 12:30 PM
C<$is_1904> is an optional flag to indicate that dates should use Excel's 1904 epoch instead of the default 1900 epoch. Excel for Windows generally uses 1900 and Excel for Mac OS uses 1904. The C<$is1904> flag isn't required very often by a casual user and can usually be ignored.
=head2 ExcelLocaltime($excel_datetime, $is_1904)
The C function converts from an Excel date/time number to a C-like array of values:
my @time = ExcelLocaltime($excel_datetime);
# 0 1 2 3 4 5 6 7
my ( $sec, $min, $hour, $day, $month, $year, $wday, $msec ) = @time;
The array elements from C<(0 .. 6)> are the same as Perl's C. The last element C<$msec> is milliseconds. In particular it should be noted that, in common with C, the month is zero indexed and the year is the number of years since 1900. This means that you will usually need to do the following:
$month++;
$year += 1900;
See also Perl's documentation for L:
The C<$is_1904> flag is an optional. It is used to indicate that dates should use Excel's 1904 epoch instead of the default 1900 epoch.
=head2 LocaltimeExcel($sec, $min, $hour, $day, $month, $year, $wday, $msec, $is_1904)
The C function converts from a C-like array of values to an Excel date/time number:
$excel_datetime = LocaltimeExcel($sec, $min, $hour, $day, $month, $year, $wday, $msec);
The array elements from C<(0 .. 6)> are the same as Perl's C. The last element C<$msec> is milliseconds. In particular it should be noted that, in common with C, the month is zero indexed and the year is the number of years since 1900. See also Perl's documentation for L:
The C<$wday> and C<$msec> elements are usually optional. This time elements can also be zeroed if they aren't of interest:
# sec, min, hour, day, month, year
$excel_datetime = LocaltimeExcel( 0, 0, 0, 1, 0, 101 );
print ExcelFmt('d mmm yyyy', $excel_datetime); # 1 Jan 2001
The C<$is_1904> flag is also optional. It is used to indicate that dates should use Excel's 1904 epoch instead of the default 1900 epoch.
=head2 col2int($column)
The C function converts an Excel column letter to an zero-indexed column number:
print col2int('A'); # 0
print col2int('AA'); # 26
This function was contributed by Kevin Mulholland.
=head2 int2col($column_number)
The C function converts an zero-indexed Excel column number to a column letter:
print int2col(0); # 'A'
print int2col(26); # 'AA'
This function was contributed by Kevin Mulholland.
=head2 sheetRef($cell_string)
The C function converts an Excel cell reference in 'A1' notation to a zero-indexed C<(row, col)> pair.
my ($row, $col) = sheetRef('A1'); # ( 0, 0 )
my ($row, $col) = sheetRef('C2'); # ( 1, 2 )
This function was contributed by Kevin Mulholland.
=head2 xls2csv($filename, $region, $rotate)
The C function converts a section of an Excel file into a CSV text string.
$csv_text = xls2csv($filename, $region, $rotate);
Where:
$region = "sheet-colrow:colrow"
For example '1-A1:B2' means 'A1:B2' for sheet 1.
and
$rotate = 0 or 1 (output is rotated/transposed or not)
This function requires C to be installed. It was contributed by Kevin Mulholland along with the C script in the C directory of the distro.
See also the following xls2csv utilities: Ken Prows' C: http://search.cpan.org/~ken/xls2csv/script/xls2csv and H.Merijn Brand's C (which is part of Spreadsheet::Read): http://search.cpan.org/~hmbrand/Spreadsheet-Read/
=head1 AUTHOR
Current maintainer 0.60+: Douglas Wilson dougw@cpan.org
Maintainer 0.40-0.59: John McNamara jmcnamara@cpan.org
Maintainer 0.27-0.33: Gabor Szabo szabgab@cpan.org
Original author: Kawai Takanori kwitknr@cpan.org
=head1 COPYRIGHT
Copyright (c) 2014 Douglas Wilson
Copyright (c) 2009-2013 John McNamara
Copyright (c) 2006-2008 Gabor Szabo
Copyright (c) 2000-2006 Kawai Takanori
All rights reserved.
You may distribute under the terms of either the GNU General Public License or the Artistic License, as specified in the Perl README file.
=cut
Spreadsheet-ParseExcel-0.66/lib/Spreadsheet/ParseExcel/Cell.pm 000644 000765 000024 00000022400 14543413026 024273 0 ustar 00John staff 000000 000000 package Spreadsheet::ParseExcel::Cell;
###############################################################################
#
# Spreadsheet::ParseExcel::Cell - A class for Cell data and formatting.
#
# Used in conjunction with Spreadsheet::ParseExcel.
#
# Copyright (c) 2014 Douglas Wilson
# Copyright (c) 2009-2013 John McNamara
# Copyright (c) 2006-2008 Gabor Szabo
# Copyright (c) 2000-2006 Kawai Takanori
#
# perltidy with standard settings.
#
# Documentation after __END__
#
use strict;
use warnings;
our $VERSION = '0.66';
###############################################################################
#
# new()
#
# Constructor.
#
sub new {
my ( $package, %properties ) = @_;
my $self = \%properties;
bless $self, $package;
}
###############################################################################
#
# value()
#
# Returns the formatted value of the cell.
#
sub value {
my $self = shift;
return $self->{_Value};
}
###############################################################################
#
# unformatted()
#
# Returns the unformatted value of the cell.
#
sub unformatted {
my $self = shift;
return $self->{Val};
}
###############################################################################
#
# get_format()
#
# Returns the Format object for the cell.
#
sub get_format {
my $self = shift;
return $self->{Format};
}
###############################################################################
#
# type()
#
# Returns the type of cell such as Text, Numeric or Date.
#
sub type {
my $self = shift;
return $self->{Type};
}
###############################################################################
#
# encoding()
#
# Returns the character encoding of the cell.
#
sub encoding {
my $self = shift;
if ( !defined $self->{Code} ) {
return 1;
}
elsif ( $self->{Code} eq 'ucs2' ) {
return 2;
}
elsif ( $self->{Code} eq '_native_' ) {
return 3;
}
else {
return 0;
}
return $self->{Code};
}
###############################################################################
#
# is_merged()
#
# Returns true if the cell is merged.
#
sub is_merged {
my $self = shift;
return $self->{Merged};
}
###############################################################################
#
# get_rich_text()
#
# Returns an array ref of font information about each string block in a "rich",
# i.e. multi-format, string.
#
sub get_rich_text {
my $self = shift;
return $self->{Rich};
}
###############################################################################
#
# get_hyperlink {
#
# Returns an array ref of hyperlink information if the cell contains a hyperlink.
# Returns undef otherwise
#
# [0] : Description of link (You may want $cell->value, as it will have rich text)
# [1] : URL - the link expressed as a URL. N.B. relative URLs will be defaulted to
# the directory of the input file, if the input file name is known. Otherwise
# %REL% will be inserted as a place-holder. Depending on your application,
# you should either remove %REL% or replace it with the appropriate path.
# [2] : Target frame (or undef if none)
sub get_hyperlink {
my $self = shift;
return $self->{Hyperlink} if exists $self->{Hyperlink};
return undef;
}
#
###############################################################################
#
# Mapping between legacy method names and new names.
#
{
no warnings; # Ignore warnings about variables used only once.
*Value = \&value;
}
1;
__END__
=pod
=head1 NAME
Spreadsheet::ParseExcel::Cell - A class for Cell data and formatting.
=head1 SYNOPSIS
See the documentation for Spreadsheet::ParseExcel.
=head1 DESCRIPTION
This module is used in conjunction with Spreadsheet::ParseExcel. See the documentation for Spreadsheet::ParseExcel.
=head1 Methods
The following Cell methods are available:
$cell->value()
$cell->unformatted()
$cell->get_format()
$cell->type()
$cell->encoding()
$cell->is_merged()
$cell->get_rich_text()
$cell->get_hyperlink()
=head2 value()
The C method returns the formatted value of the cell.
my $value = $cell->value();
Formatted in this sense refers to the numeric format of the cell value. For example a number such as 40177 might be formatted as 40,117, 40117.000 or even as the date 2009/12/30.
If the cell doesn't contain a numeric format then the formatted and unformatted cell values are the same, see the C method below.
For a defined C<$cell> the C method will always return a value.
In the case of a cell with formatting but no numeric or string contents the method will return the empty string C<''>.
=head2 unformatted()
The C method returns the unformatted value of the cell.
my $unformatted = $cell->unformatted();
Returns the cell value without a numeric format. See the C method above.
=head2 get_format()
The C method returns the L object for the cell.
my $format = $cell->get_format();
If a user defined format hasn't been applied to the cell then the default cell format is returned.
=head2 type()
The C method returns the type of cell such as Text, Numeric or Date. If the type was detected as Numeric, and the Cell Format matches C, it will be treated as a Date type.
my $type = $cell->type();
See also L.
=head2 encoding()
The C method returns the character encoding of the cell.
my $encoding = $cell->encoding();
This method is only of interest to developers. In general Spreadsheet::ParseExcel will return all character strings in UTF-8 regardless of the encoding used by Excel.
The C method returns one of the following values:
=over
=item * 0: Unknown format. This shouldn't happen. In the default case the format should be 1.
=item * 1: 8bit ASCII or single byte UTF-16. This indicates that the characters are encoded in a single byte. In Excel 95 and earlier This usually meant ASCII or an international variant. In Excel 97 it refers to a compressed UTF-16 character string where all of the high order bytes are 0 and are omitted to save space.
=item * 2: UTF-16BE.
=item * 3: Native encoding. In Excel 95 and earlier this encoding was used to represent multi-byte character encodings such as SJIS.
=back
=head2 is_merged()
The C method returns true if the cell is merged.
my $is_merged = $cell->is_merged();
Returns C if the property isn't set.
=head2 get_rich_text()
The C method returns an array ref of font information about each string block in a "rich", i.e. multi-format, string.
my $rich_text = $cell->get_rich_text();
The return value is an arrayref of arrayrefs in the form:
[
[ $start_position, $font_object ],
...,
]
Returns undef if the property isn't set.
=head2 get_hyperlink()
If a cell contains a hyperlink, the C method returns an array ref of information about it.
A cell can contain at most one hyperlink. If it does, it contains no other value.
Otherwise, it returns undef;
The array contains:
=over
=item * 0: Description (what's displayed); undef if not present
=item * 1: Link, converted to an appropriate URL - Note: Relative links are based on the input file. %REL% is used if the input file is unknown (e.g. a file handle or scalar)
=item * 2: Target - target frame (or undef if none)
=back
=head1 Dates and Time in Excel
Dates and times in Excel are represented by real numbers, for example "Jan 1 2001 12:30 PM" is represented by the number 36892.521.
The integer part of the number stores the number of days since the epoch and the fractional part stores the percentage of the day.
A date or time in Excel is just like any other number. The way in which it is displayed is controlled by the number format:
Number format $cell->value() $cell->unformatted()
============= ============== ==============
'dd/mm/yy' '28/02/08' 39506.5
'mm/dd/yy' '02/28/08' 39506.5
'd-m-yyyy' '28-2-2008' 39506.5
'dd/mm/yy hh:mm' '28/02/08 12:00' 39506.5
'd mmm yyyy' '28 Feb 2008' 39506.5
'mmm d yyyy hh:mm AM/PM' 'Feb 28 2008 12:00 PM' 39506.5
The L module contains a function called C which will convert between an unformatted Excel date/time number and a C like array.
For date conversions using the CPAN C framework see L http://search.cpan.org/search?dist=DateTime-Format-Excel
=head1 AUTHOR
Current maintainer 0.60+: Douglas Wilson dougw@cpan.org
Maintainer 0.40-0.59: John McNamara jmcnamara@cpan.org
Maintainer 0.27-0.33: Gabor Szabo szabgab@cpan.org
Original author: Kawai Takanori kwitknr@cpan.org
=head1 COPYRIGHT
Copyright (c) 2014 Douglas Wilson
Copyright (c) 2009-2013 John McNamara
Copyright (c) 2006-2008 Gabor Szabo
Copyright (c) 2000-2006 Kawai Takanori
All rights reserved.
You may distribute under the terms of either the GNU General Public License or the Artistic License, as specified in the Perl README file.
=cut
Spreadsheet-ParseExcel-0.66/lib/Spreadsheet/ParseExcel/Font.pm 000644 000765 000024 00000002704 14543413026 024327 0 ustar 00John staff 000000 000000 package Spreadsheet::ParseExcel::Font;
###############################################################################
#
# Spreadsheet::ParseExcel::Font - A class for Cell fonts.
#
# Used in conjunction with Spreadsheet::ParseExcel.
#
# Copyright (c) 2014 Douglas Wilson
# Copyright (c) 2009-2013 John McNamara
# Copyright (c) 2006-2008 Gabor Szabo
# Copyright (c) 2000-2006 Kawai Takanori
#
# perltidy with standard settings.
#
# Documentation after __END__
#
use strict;
use warnings;
our $VERSION = '0.66';
sub new {
my ( $class, %rhIni ) = @_;
my $self = \%rhIni;
bless $self, $class;
}
1;
__END__
=pod
=head1 NAME
Spreadsheet::ParseExcel::Font - A class for Cell fonts.
=head1 SYNOPSIS
See the documentation for Spreadsheet::ParseExcel.
=head1 DESCRIPTION
This module is used in conjunction with Spreadsheet::ParseExcel. See the documentation for Spreadsheet::ParseExcel.
=head1 AUTHOR
Current maintainer 0.60+: Douglas Wilson dougw@cpan.org
Maintainer 0.40-0.59: John McNamara jmcnamara@cpan.org
Maintainer 0.27-0.33: Gabor Szabo szabgab@cpan.org
Original author: Kawai Takanori kwitknr@cpan.org
=head1 COPYRIGHT
Copyright (c) 2014 Douglas Wilson
Copyright (c) 2009-2013 John McNamara
Copyright (c) 2006-2008 Gabor Szabo
Copyright (c) 2000-2006 Kawai Takanori
All rights reserved.
You may distribute under the terms of either the GNU General Public License or the Artistic License, as specified in the Perl README file.
=cut
Spreadsheet-ParseExcel-0.66/lib/Spreadsheet/ParseExcel/Format.pm 000644 000765 000024 00000002715 14543413026 024653 0 ustar 00John staff 000000 000000 package Spreadsheet::ParseExcel::Format;
###############################################################################
#
# Spreadsheet::ParseExcel::Format - A class for Cell formats.
#
# Used in conjunction with Spreadsheet::ParseExcel.
#
# Copyright (c) 2014 Douglas Wilson
# Copyright (c) 2009-2013 John McNamara
# Copyright (c) 2006-2008 Gabor Szabo
# Copyright (c) 2000-2006 Kawai Takanori
#
# perltidy with standard settings.
#
# Documentation after __END__
#
use strict;
use warnings;
our $VERSION = '0.66';
sub new {
my ( $class, %rhIni ) = @_;
my $self = \%rhIni;
bless $self, $class;
}
1;
__END__
=pod
=head1 NAME
Spreadsheet::ParseExcel::Format - A class for Cell formats.
=head1 SYNOPSIS
See the documentation for Spreadsheet::ParseExcel.
=head1 DESCRIPTION
This module is used in conjunction with Spreadsheet::ParseExcel. See the documentation for Spreadsheet::ParseExcel.
=head1 AUTHOR
Current maintainer 0.60+: Douglas Wilson dougw@cpan.org
Maintainer 0.40-0.59: John McNamara jmcnamara@cpan.org
Maintainer 0.27-0.33: Gabor Szabo szabgab@cpan.org
Original author: Kawai Takanori kwitknr@cpan.org
=head1 COPYRIGHT
Copyright (c) 2014 Douglas Wilson
Copyright (c) 2009-2013 John McNamara
Copyright (c) 2006-2008 Gabor Szabo
Copyright (c) 2000-2006 Kawai Takanori
All rights reserved.
You may distribute under the terms of either the GNU General Public License or the Artistic License, as specified in the Perl README file.
=cut
Spreadsheet-ParseExcel-0.66/lib/Spreadsheet/ParseExcel/Worksheet.pm 000644 000765 000024 00000057656 14543413026 025414 0 ustar 00John staff 000000 000000 package Spreadsheet::ParseExcel::Worksheet;
###############################################################################
#
# Spreadsheet::ParseExcel::Worksheet - A class for Worksheets.
#
# Used in conjunction with Spreadsheet::ParseExcel.
#
# Copyright (c) 2014 Douglas Wilson
# Copyright (c) 2009-2013 John McNamara
# Copyright (c) 2006-2008 Gabor Szabo
# Copyright (c) 2000-2006 Kawai Takanori
#
# perltidy with standard settings.
#
# Documentation after __END__
#
use strict;
use warnings;
use Scalar::Util qw(weaken);
our $VERSION = '0.66';
###############################################################################
#
# new()
#
sub new {
my ( $class, %properties ) = @_;
my $self = \%properties;
weaken $self->{_Book};
$self->{Cells} = undef;
$self->{DefColWidth} = 8.43;
return bless $self, $class;
}
###############################################################################
#
# get_cell( $row, $col )
#
# Returns the Cell object at row $row and column $col, if defined.
#
sub get_cell {
my ( $self, $row, $col ) = @_;
if ( !defined $row
|| !defined $col
|| !defined $self->{MaxRow}
|| !defined $self->{MaxCol} )
{
# Return undef if no arguments are given or if no cells are defined.
return undef;
}
elsif ($row < $self->{MinRow}
|| $row > $self->{MaxRow}
|| $col < $self->{MinCol}
|| $col > $self->{MaxCol} )
{
# Return undef if outside allowable row/col range.
return undef;
}
else {
# Return the Cell object.
return $self->{Cells}->[$row]->[$col];
}
}
###############################################################################
#
# row_range()
#
# Returns a two-element list ($min, $max) containing the minimum and maximum
# defined rows in the worksheet.
#
# If there is no row defined $max is smaller than $min.
#
sub row_range {
my $self = shift;
my $min = $self->{MinRow} || 0;
my $max = defined( $self->{MaxRow} ) ? $self->{MaxRow} : ( $min - 1 );
return ( $min, $max );
}
###############################################################################
#
# col_range()
#
# Returns a two-element list ($min, $max) containing the minimum and maximum
# defined cols in the worksheet.
#
# If there is no column defined $max is smaller than $min.
#
sub col_range {
my $self = shift;
my $min = $self->{MinCol} || 0;
my $max = defined( $self->{MaxCol} ) ? $self->{MaxCol} : ( $min - 1 );
return ( $min, $max );
}
###############################################################################
#
# get_name()
#
# Returns the name of the worksheet.
#
sub get_name {
my $self = shift;
return $self->{Name};
}
###############################################################################
#
# sheet_num()
#
sub sheet_num {
my $self = shift;
return $self->{_SheetNo};
}
###############################################################################
#
# get_h_pagebreaks()
#
# Returns an array ref of row numbers where a horizontal page break occurs.
#
sub get_h_pagebreaks {
my $self = shift;
return $self->{HPageBreak};
}
###############################################################################
#
# get_v_pagebreaks()
#
# Returns an array ref of column numbers where a vertical page break occurs.
#
sub get_v_pagebreaks {
my $self = shift;
return $self->{VPageBreak};
}
###############################################################################
#
# get_merged_areas()
#
# Returns an array ref of cells that are merged.
#
sub get_merged_areas {
my $self = shift;
return $self->{MergedArea};
}
###############################################################################
#
# get_row_heights()
#
# Returns an array of row heights.
#
sub get_row_heights {
my $self = shift;
if ( wantarray() ) {
return unless $self->{RowHeight};
return @{ $self->{RowHeight} };
}
return $self->{RowHeight};
}
###############################################################################
#
# get_col_widths()
#
# Returns an array of column widths.
#
sub get_col_widths {
my $self = shift;
if ( wantarray() ) {
return unless $self->{ColWidth};
return @{ $self->{ColWidth} };
}
return $self->{ColWidth};
}
###############################################################################
#
# get_default_row_height()
#
# Returns the default row height for the worksheet. Generally 12.75.
#
sub get_default_row_height {
my $self = shift;
return $self->{DefRowHeight};
}
###############################################################################
#
# get_default_col_width()
#
# Returns the default column width for the worksheet. Generally 8.43.
#
sub get_default_col_width {
my $self = shift;
return $self->{DefColWidth};
}
###############################################################################
#
# _get_row_properties()
#
# Returns an array_ref of row properties.
# TODO. This is a placeholder for a future method.
#
sub _get_row_properties {
my $self = shift;
return $self->{RowProperties};
}
###############################################################################
#
# _get_col_properties()
#
# Returns an array_ref of column properties.
# TODO. This is a placeholder for a future method.
#
sub _get_col_properties {
my $self = shift;
return $self->{ColProperties};
}
###############################################################################
#
# get_header()
#
# Returns the worksheet header string.
#
sub get_header {
my $self = shift;
return $self->{Header};
}
###############################################################################
#
# get_footer()
#
# Returns the worksheet footer string.
#
sub get_footer {
my $self = shift;
return $self->{Footer};
}
###############################################################################
#
# get_margin_left()
#
# Returns the left margin of the worksheet in inches.
#
sub get_margin_left {
my $self = shift;
return $self->{LeftMargin};
}
###############################################################################
#
# get_margin_right()
#
# Returns the right margin of the worksheet in inches.
#
sub get_margin_right {
my $self = shift;
return $self->{RightMargin};
}
###############################################################################
#
# get_margin_top()
#
# Returns the top margin of the worksheet in inches.
#
sub get_margin_top {
my $self = shift;
return $self->{TopMargin};
}
###############################################################################
#
# get_margin_bottom()
#
# Returns the bottom margin of the worksheet in inches.
#
sub get_margin_bottom {
my $self = shift;
return $self->{BottomMargin};
}
###############################################################################
#
# get_margin_header()
#
# Returns the header margin of the worksheet in inches.
#
sub get_margin_header {
my $self = shift;
return $self->{HeaderMargin};
}
###############################################################################
#
# get_margin_footer()
#
# Returns the footer margin of the worksheet in inches.
#
sub get_margin_footer {
my $self = shift;
return $self->{FooterMargin};
}
###############################################################################
#
# get_paper()
#
# Returns the printer paper size.
#
sub get_paper {
my $self = shift;
return $self->{PaperSize};
}
###############################################################################
#
# get_start_page()
#
# Returns the page number that printing will start from.
#
sub get_start_page {
my $self = shift;
# Only return the page number if the "First page number" option is set.
if ( $self->{UsePage} ) {
return $self->{PageStart};
}
else {
return 0;
}
}
###############################################################################
#
# get_print_order()
#
# Returns the Worksheet page printing order.
#
sub get_print_order {
my $self = shift;
return $self->{LeftToRight};
}
###############################################################################
#
# get_print_scale()
#
# Returns the workbook scale for printing.
#
sub get_print_scale {
my $self = shift;
return $self->{Scale};
}
###############################################################################
#
# get_fit_to_pages()
#
# Returns the number of pages wide and high that the printed worksheet page
# will fit to.
#
sub get_fit_to_pages {
my $self = shift;
if ( !$self->{PageFit} ) {
return ( 0, 0 );
}
else {
return ( $self->{FitWidth}, $self->{FitHeight} );
}
}
###############################################################################
#
# is_portrait()
#
# Returns true if the worksheet has been set for printing in portrait mode.
#
sub is_portrait {
my $self = shift;
return $self->{Landscape};
}
###############################################################################
#
# is_centered_horizontally()
#
# Returns true if the worksheet has been centered horizontally for printing.
#
sub is_centered_horizontally {
my $self = shift;
return $self->{HCenter};
}
###############################################################################
#
# is_centered_vertically()
#
# Returns true if the worksheet has been centered vertically for printing.
#
sub is_centered_vertically {
my $self = shift;
return $self->{HCenter};
}
###############################################################################
#
# is_print_gridlines()
#
# Returns true if the worksheet print "gridlines" option is turned on.
#
sub is_print_gridlines {
my $self = shift;
return $self->{PrintGrid};
}
###############################################################################
#
# is_print_row_col_headers()
#
# Returns true if the worksheet print "row and column headings" option is on.
#
sub is_print_row_col_headers {
my $self = shift;
return $self->{PrintHeaders};
}
###############################################################################
#
# is_print_black_and_white()
#
# Returns true if the worksheet print "black and white" option is turned on.
#
sub is_print_black_and_white {
my $self = shift;
return $self->{NoColor};
}
###############################################################################
#
# is_print_draft()
#
# Returns true if the worksheet print "draft" option is turned on.
#
sub is_print_draft {
my $self = shift;
return $self->{Draft};
}
###############################################################################
#
# is_print_comments()
#
# Returns true if the worksheet print "comments" option is turned on.
#
sub is_print_comments {
my $self = shift;
return $self->{Notes};
}
=head2 get_tab_color()
Return color index of tab, or undef if not set.
=cut
sub get_tab_color {
my $worksheet = shift;
return $worksheet->{TabColor};
}
=head2 is_sheet_hidden()
Return true if sheet is hidden
=cut
sub is_sheet_hidden {
my $worksheet = shift;
return $worksheet->{SheetHidden};
}
=head2 is_row_hidden($row)
In scalar context, return true if $row is hidden
In array context, return an array whose elements are true
if the corresponding row is hidden.
=cut
sub is_row_hidden {
my $worksheet = shift;
my ($row) = @_;
unless ( $worksheet->{RowHidden} ) {
return () if (wantarray);
return 0;
}
return @{ $worksheet->{RowHidden} } if (wantarray);
return $worksheet->{RowHidden}[$row];
}
=head2 is_col_hidden($col)
In scalar context, return true if $col is hidden
In array context, return an array whose elements are true
if the corresponding column is hidden.
=cut
sub is_col_hidden {
my $worksheet = shift;
my ($col) = @_;
unless ( $worksheet->{ColHidden} ) {
return () if (wantarray);
return 0;
}
return @{ $worksheet->{ColHidden} } if (wantarray);
return $worksheet->{ColHidden}[$col];
}
###############################################################################
#
# Mapping between legacy method names and new names.
#
{
no warnings; # Ignore warnings about variables used only once.
*sheetNo = *sheet_num;
*Cell = *get_cell;
*RowRange = *row_range;
*ColRange = *col_range;
}
1;
__END__
=pod
=head1 NAME
Spreadsheet::ParseExcel::Worksheet - A class for Worksheets.
=head1 SYNOPSIS
See the documentation for L.
=head1 DESCRIPTION
This module is used in conjunction with Spreadsheet::ParseExcel. See the documentation for Spreadsheet::ParseExcel.
=head1 Methods
The C class encapsulates the properties of an Excel worksheet. It has the following methods:
$worksheet->get_cell()
$worksheet->row_range()
$worksheet->col_range()
$worksheet->get_name()
$worksheet->get_h_pagebreaks()
$worksheet->get_v_pagebreaks()
$worksheet->get_merged_areas()
$worksheet->get_row_heights()
$worksheet->get_col_widths()
$worksheet->get_default_row_height()
$worksheet->get_default_col_width()
$worksheet->get_header()
$worksheet->get_footer()
$worksheet->get_margin_left()
$worksheet->get_margin_right()
$worksheet->get_margin_top()
$worksheet->get_margin_bottom()
$worksheet->get_margin_header()
$worksheet->get_margin_footer()
$worksheet->get_paper()
$worksheet->get_start_page()
$worksheet->get_print_order()
$worksheet->get_print_scale()
$worksheet->get_fit_to_pages()
$worksheet->is_portrait()
$worksheet->is_centered_horizontally()
$worksheet->is_centered_vertically()
$worksheet->is_print_gridlines()
$worksheet->is_print_row_col_headers()
$worksheet->is_print_black_and_white()
$worksheet->is_print_draft()
$worksheet->is_print_comments()
=head2 get_cell($row, $col)
Return the L object at row C<$row> and column C<$col> if it is defined. Otherwise returns undef.
my $cell = $worksheet->get_cell($row, $col);
=head2 row_range()
Returns a two-element list C<($min, $max)> containing the minimum and maximum defined rows in the worksheet. If there is no row defined C<$max> is smaller than C<$min>.
my ( $row_min, $row_max ) = $worksheet->row_range();
=head2 col_range()
Returns a two-element list C<($min, $max)> containing the minimum and maximum of defined columns in the worksheet. If there is no column defined C<$max> is smaller than C<$min>.
my ( $col_min, $col_max ) = $worksheet->col_range();
=head2 get_name()
The C method returns the name of the worksheet.
my $name = $worksheet->get_name();
=head2 get_h_pagebreaks()
The C method returns an array ref of row numbers where a horizontal page break occurs.
my $h_pagebreaks = $worksheet->get_h_pagebreaks();
Returns C if there are no pagebreaks.
=head2 get_v_pagebreaks()
The C method returns an array ref of column numbers where a vertical page break occurs.
my $v_pagebreaks = $worksheet->get_v_pagebreaks();
Returns C if there are no pagebreaks.
=head2 get_merged_areas()
The C method returns an array ref of cells that are merged.
my $merged_areas = $worksheet->get_merged_areas();
Each merged area is represented as follows:
[ $start_row, $start_col, $end_row, $end_col]
Returns C if there are no merged areas.
=head2 get_row_heights()
The C method returns an array_ref of row heights in scalar context,
and an array in list context.
my $row_heights = $worksheet->get_row_heights();
Returns C if the property isn't set.
=head2 get_col_widths()
The C method returns an array_ref of column widths in scalar context,
and an array in list context.
my $col_widths = $worksheet->get_col_widths();
Returns C if the property isn't set.
=head2 get_default_row_height()
The C method returns the default row height for the worksheet. Generally 12.75.
my $default_row_height = $worksheet->get_default_row_height();
=head2 get_default_col_width()
The C method returns the default column width for the worksheet. Generally 8.43.
my $default_col_width = $worksheet->get_default_col_width();
=head2 get_header()
The C method returns the worksheet header string. This string can contain control codes for alignment and font properties. Refer to the Excel on-line help on headers and footers or to the Spreadsheet::WriteExcel documentation for set_header().
my $header = $worksheet->get_header();
Returns C if the property isn't set.
=head2 get_footer()
The C method returns the worksheet footer string. This string can contain control codes for alignment and font properties. Refer to the Excel on-line help on headers and footers or to the Spreadsheet::WriteExcel documentation for set_header().
my $footer = $worksheet->get_footer();
Returns C if the property isn't set.
=head2 get_margin_left()
The C method returns the left margin of the worksheet in inches.
my $margin_left = $worksheet->get_margin_left();
Returns C if the property isn't set.
=head2 get_margin_right()
The C method returns the right margin of the worksheet in inches.
my $margin_right = $worksheet->get_margin_right();
Returns C if the property isn't set.
=head2 get_margin_top()
The C method returns the top margin of the worksheet in inches.
my $margin_top = $worksheet->get_margin_top();
Returns C if the property isn't set.
=head2 get_margin_bottom()
The C method returns the bottom margin of the worksheet in inches.
my $margin_bottom = $worksheet->get_margin_bottom();
Returns C if the property isn't set.
=head2 get_margin_header()
The C method returns the header margin of the worksheet in inches.
my $margin_header = $worksheet->get_margin_header();
Returns a default value of 0.5 if not set.
=head2 get_margin_footer()
The C method returns the footer margin of the worksheet in inches.
my $margin_footer = $worksheet->get_margin_footer();
Returns a default value of 0.5 if not set.
=head2 get_paper()
The C method returns the printer paper size.
my $paper = $worksheet->get_paper();
The value corresponds to the formats shown below:
Index Paper format Paper size
===== ============ ==========
0 Printer default -
1 Letter 8 1/2 x 11 in
2 Letter Small 8 1/2 x 11 in
3 Tabloid 11 x 17 in
4 Ledger 17 x 11 in
5 Legal 8 1/2 x 14 in
6 Statement 5 1/2 x 8 1/2 in
7 Executive 7 1/4 x 10 1/2 in
8 A3 297 x 420 mm
9 A4 210 x 297 mm
10 A4 Small 210 x 297 mm
11 A5 148 x 210 mm
12 B4 250 x 354 mm
13 B5 182 x 257 mm
14 Folio 8 1/2 x 13 in
15 Quarto 215 x 275 mm
16 - 10x14 in
17 - 11x17 in
18 Note 8 1/2 x 11 in
19 Envelope 9 3 7/8 x 8 7/8
20 Envelope 10 4 1/8 x 9 1/2
21 Envelope 11 4 1/2 x 10 3/8
22 Envelope 12 4 3/4 x 11
23 Envelope 14 5 x 11 1/2
24 C size sheet -
25 D size sheet -
26 E size sheet -
27 Envelope DL 110 x 220 mm
28 Envelope C3 324 x 458 mm
29 Envelope C4 229 x 324 mm
30 Envelope C5 162 x 229 mm
31 Envelope C6 114 x 162 mm
32 Envelope C65 114 x 229 mm
33 Envelope B4 250 x 353 mm
34 Envelope B5 176 x 250 mm
35 Envelope B6 176 x 125 mm
36 Envelope 110 x 230 mm
37 Monarch 3.875 x 7.5 in
38 Envelope 3 5/8 x 6 1/2 in
39 Fanfold 14 7/8 x 11 in
40 German Std Fanfold 8 1/2 x 12 in
41 German Legal Fanfold 8 1/2 x 13 in
256 User defined
The two most common paper sizes are C<1 = "US Letter"> and C<9 = A4>. Returns 9 by default.
=head2 get_start_page()
The C method returns the page number that printing will start from.
my $start_page = $worksheet->get_start_page();
Returns 0 if the property isn't set.
=head2 get_print_order()
The C method returns 0 if the worksheet print "page order" is "Down then over" (the default) or 1 if it is "Over then down".
my $print_order = $worksheet->get_print_order();
=head2 get_print_scale()
The C method returns the workbook scale for printing. The print scale factor can be in the range 10 .. 400.
my $print_scale = $worksheet->get_print_scale();
Returns 100 by default.
=head2 get_fit_to_pages()
The C method returns the number of pages wide and high that the printed worksheet page will fit to.
my ($pages_wide, $pages_high) = $worksheet->get_fit_to_pages();
Returns (0, 0) if the property isn't set.
=head2 is_portrait()
The C method returns true if the worksheet has been set for printing in portrait mode.
my $is_portrait = $worksheet->is_portrait();
Returns 0 if the worksheet has been set for printing in horizontal mode.
=head2 is_centered_horizontally()
The C method returns true if the worksheet has been centered horizontally for printing.
my $is_centered_horizontally = $worksheet->is_centered_horizontally();
Returns 0 if the property isn't set.
=head2 is_centered_vertically()
The C method returns true if the worksheet has been centered vertically for printing.
my $is_centered_vertically = $worksheet->is_centered_vertically();
Returns 0 if the property isn't set.
=head2 is_print_gridlines()
The C method returns true if the worksheet print "gridlines" option is turned on.
my $is_print_gridlines = $worksheet->is_print_gridlines();
Returns 0 if the property isn't set.
=head2 is_print_row_col_headers()
The C method returns true if the worksheet print "row and column headings" option is turned on.
my $is_print_row_col_headers = $worksheet->is_print_row_col_headers();
Returns 0 if the property isn't set.
=head2 is_print_black_and_white()
The C method returns true if the worksheet print "black and white" option is turned on.
my $is_print_black_and_white = $worksheet->is_print_black_and_white();
Returns 0 if the property isn't set.
=head2 is_print_draft()
The C method returns true if the worksheet print "draft" option is turned on.
my $is_print_draft = $worksheet->is_print_draft();
Returns 0 if the property isn't set.
=head2 is_print_comments()
The C method returns true if the worksheet print "comments" option is turned on.
my $is_print_comments = $worksheet->is_print_comments();
Returns 0 if the property isn't set.
=head1 AUTHOR
Current maintainer 0.60+: Douglas Wilson dougw@cpan.org
Maintainer 0.40-0.59: John McNamara jmcnamara@cpan.org
Maintainer 0.27-0.33: Gabor Szabo szabgab@cpan.org
Original author: Kawai Takanori kwitknr@cpan.org
=head1 COPYRIGHT
Copyright (c) 2014 Douglas Wilson
Copyright (c) 2009-2013 John McNamara
Copyright (c) 2006-2008 Gabor Szabo
Copyright (c) 2000-2006 Kawai Takanori
All rights reserved.
You may distribute under the terms of either the GNU General Public License or the Artistic License, as specified in the Perl README file.
=cut
Spreadsheet-ParseExcel-0.66/lib/Spreadsheet/ParseExcel/Dump.pm 000644 000765 000024 00000017567 14543413026 024343 0 ustar 00John staff 000000 000000 package Spreadsheet::ParseExcel::Dump;
###############################################################################
#
# Spreadsheet::ParseExcel::Dump - A class for dumping Excel records.
#
# Used in conjunction with Spreadsheet::ParseExcel.
#
# Copyright (c) 2014 Douglas Wilson
# Copyright (c) 2009-2013 John McNamara
# Copyright (c) 2006-2008 Gabor Szabo
# Copyright (c) 2000-2006 Kawai Takanori
#
# perltidy with standard settings.
#
# Documentation after __END__
#
use strict;
use warnings;
our $VERSION = '0.66';
my %NameTbl = (
#P291
0x0A => 'EOF',
0x0C => 'CALCCOUNT',
0x0D => 'CALCMODE',
0x0E => 'PRECISION',
0x0F => 'REFMODE',
0x10 => 'DELTA',
0x11 => 'ITERATION',
0x12 => 'PROTECT',
0x13 => 'PASSWORD',
0x14 => 'HEADER',
0x15 => 'FOOTER',
0x16 => 'EXTERNCOUNT',
0x17 => 'EXTERNSHEET',
0x19 => 'WINDOWPROTECT',
0x1A => 'VERTICALPAGEBREAKS',
0x1B => 'HORIZONTALPAGEBREAKS',
0x1C => 'NOTE',
0x1D => 'SELECTION',
0x22 => '1904',
0x26 => 'LEFTMARGIN',
0x27 => 'RIGHTMARGIN',
0x28 => 'TOPMARGIN',
0x29 => 'BOTTOMMARGIN',
0x2A => 'PRINTHEADERS',
0x2B => 'PRINTGRIDLINES',
0x2F => 'FILEPASS',
0x3C => 'COUNTINUE',
0x3D => 'WINDOW1',
0x40 => 'BACKUP',
0x41 => 'PANE',
0x42 => 'CODEPAGE',
0x4D => 'PLS',
0x50 => 'DCON',
0x51 => 'DCONREF',
#P292
0x52 => 'DCONNAME',
0x55 => 'DEFCOLWIDTH',
0x59 => 'XCT',
0x5A => 'CRN',
0x5B => 'FILESHARING',
0x5C => 'WRITEACCES',
0x5D => 'OBJ',
0x5E => 'UNCALCED',
0x5F => 'SAVERECALC',
0x60 => 'TEMPLATE',
0x63 => 'OBJPROTECT',
0x7D => 'COLINFO',
0x7E => 'RK',
0x7F => 'IMDATA',
0x80 => 'GUTS',
0x81 => 'WSBOOL',
0x82 => 'GRIDSET',
0x83 => 'HCENTER',
0x84 => 'VCENTER',
0x85 => 'BOUNDSHEET',
0x86 => 'WRITEPROT',
0x87 => 'ADDIN',
0x88 => 'EDG',
0x89 => 'PUB',
0x8C => 'COUNTRY',
0x8D => 'HIDEOBJ',
0x90 => 'SORT',
0x91 => 'SUB',
0x92 => 'PALETTE',
0x94 => 'LHRECORD',
0x95 => 'LHNGRAPH',
0x96 => 'SOUND',
0x98 => 'LPR',
0x99 => 'STANDARDWIDTH',
0x9A => 'FNGROUPNAME',
0x9B => 'FILTERMODE',
0x9C => 'FNGROUPCOUNT',
#P293
0x9D => 'AUTOFILTERINFO',
0x9E => 'AUTOFILTER',
0xA0 => 'SCL',
0xA1 => 'SETUP',
0xA9 => 'COORDLIST',
0xAB => 'GCW',
0xAE => 'SCENMAN',
0xAF => 'SCENARIO',
0xB0 => 'SXVIEW',
0xB1 => 'SXVD',
0xB2 => 'SXV',
0xB4 => 'SXIVD',
0xB5 => 'SXLI',
0xB6 => 'SXPI',
0xB8 => 'DOCROUTE',
0xB9 => 'RECIPNAME',
0xBC => 'SHRFMLA',
0xBD => 'MULRK',
0xBE => 'MULBLANK',
0xBF => 'TOOLBARHDR',
0xC0 => 'TOOLBAREND',
0xC1 => 'MMS',
0xC2 => 'ADDMENU',
0xC3 => 'DELMENU',
0xC5 => 'SXDI',
0xC6 => 'SXDB',
0xCD => 'SXSTRING',
0xD0 => 'SXTBL',
0xD1 => 'SXTBRGIITM',
0xD2 => 'SXTBPG',
0xD3 => 'OBPROJ',
0xD5 => 'SXISDTM',
0xD6 => 'RSTRING',
0xD7 => 'DBCELL',
0xDA => 'BOOKBOOL',
0xDC => 'PARAMQRY',
0xDC => 'SXEXT',
0xDD => 'SCENPROTECT',
0xDE => 'OLESIZE',
#P294
0xDF => 'UDDESC',
0xE0 => 'XF',
0xE1 => 'INTERFACEHDR',
0xE2 => 'INTERFACEEND',
0xE3 => 'SXVS',
0xEA => 'TABIDCONF',
0xEB => 'MSODRAWINGGROUP',
0xEC => 'MSODRAWING',
0xED => 'MSODRAWINGSELECTION',
0xEF => 'PHONETICINFO',
0xF0 => 'SXRULE',
0xF1 => 'SXEXT',
0xF2 => 'SXFILT',
0xF6 => 'SXNAME',
0xF7 => 'SXSELECT',
0xF8 => 'SXPAIR',
0xF9 => 'SXFMLA',
0xFB => 'SXFORMAT',
0xFC => 'SST',
0xFD => 'LABELSST',
0xFF => 'EXTSST',
0x100 => 'SXVDEX',
0x103 => 'SXFORMULA',
0x122 => 'SXDBEX',
0x13D => 'TABID',
0x160 => 'USESELFS',
0x161 => 'DSF',
0x162 => 'XL5MODIFY',
0x1A5 => 'FILESHARING2',
0x1A9 => 'USERBVIEW',
0x1AA => 'USERVIEWBEGIN',
0x1AB => 'USERSVIEWEND',
0x1AD => 'QSI',
0x1AE => 'SUPBOOK',
0x1AF => 'PROT4REV',
0x1B0 => 'CONDFMT',
0x1B1 => 'CF',
0x1B2 => 'DVAL',
#P295
0x1B5 => 'DCONBIN',
0x1B6 => 'TXO',
0x1B7 => 'REFRESHALL',
0x1B8 => 'HLINK',
0x1BA => 'CODENAME',
0x1BB => 'SXFDBTYPE',
0x1BC => 'PROT4REVPASS',
0x1BE => 'DV',
0x200 => 'DIMENSIONS',
0x201 => 'BLANK',
0x202 => 'Integer', #Not Documented
0x203 => 'NUMBER',
0x204 => 'LABEL',
0x205 => 'BOOLERR',
0x207 => 'STRING',
0x208 => 'ROW',
0x20B => 'INDEX',
0x218 => 'NAME',
0x221 => 'ARRAY',
0x223 => 'EXTERNNAME',
0x225 => 'DEFAULTROWHEIGHT',
0x231 => 'FONT',
0x236 => 'TABLE',
0x23E => 'WINDOW2',
0x293 => 'STYLE',
0x406 => 'FORMULA',
0x41E => 'FORMAT',
0x18 => 'NAME',
0x06 => 'FORMULA',
0x09 => 'BOF(BIFF2)',
0x209 => 'BOF(BIFF3)',
0x409 => 'BOF(BIFF4)',
0x809 => 'BOF(BIFF5-7)',
0x31 => 'FONT', 0x27E => 'RK',
#Chart/Graph
0x1001 => 'UNITS',
0x1002 => 'CHART',
0x1003 => 'SERISES',
0x1006 => 'DATAFORMAT',
0x1007 => 'LINEFORMAT',
0x1009 => 'MAKERFORMAT',
0x100A => 'AREAFORMAT',
0x100B => 'PIEFORMAT',
0x100C => 'ATTACHEDLABEL',
0x100D => 'SERIESTEXT',
0x1014 => 'CHARTFORMAT',
0x1015 => 'LEGEND',
0x1016 => 'SERIESLIST',
0x1017 => 'BAR',
0x1018 => 'LINE',
0x1019 => 'PIE',
0x101A => 'AREA',
0x101B => 'SCATTER',
0x101C => 'CHARTLINE',
0x101D => 'AXIS',
0x101E => 'TICK',
0x101F => 'VALUERANGE',
0x1020 => 'CATSERRANGE',
0x1021 => 'AXISLINEFORMAT',
0x1022 => 'CHARTFORMATLINK',
0x1024 => 'DEFAULTTEXT',
0x1025 => 'TEXT',
0x1026 => 'FONTX',
0x1027 => 'OBJECTLINK',
0x1032 => 'FRAME',
0x1033 => 'BEGIN',
0x1034 => 'END',
0x1035 => 'PLOTAREA',
0x103A => '3D',
0x103C => 'PICF',
0x103D => 'DROPBAR',
0x103E => 'RADAR',
0x103F => 'SURFACE',
0x1040 => 'RADARAREA',
0x1041 => 'AXISPARENT',
0x1043 => 'LEGENDXN',
0x1044 => 'SHTPROPS',
0x1045 => 'SERTOCRT',
0x1046 => 'AXESUSED',
0x1048 => 'SBASEREF',
0x104A => 'SERPARENT',
0x104B => 'SERAUXTREND',
0x104E => 'IFMT',
0x104F => 'POS',
0x1050 => 'ALRUNS',
0x1051 => 'AI',
0x105B => 'SERAUXERRBAR',
0x105D => 'SERFMT',
0x1060 => 'FBI',
0x1061 => 'BOPPOP',
0x1062 => 'AXCEXT',
0x1063 => 'DAT',
0x1064 => 'PLOTGROWTH',
0x1065 => 'SINDEX',
0x1066 => 'GELFRAME',
0x1067 => 'BPOPPOPCUSTOM',
);
#------------------------------------------------------------------------------
# subDUMP (for Spreadsheet::ParseExcel)
#------------------------------------------------------------------------------
sub subDUMP {
my ( $oBook, $bOp, $bLen, $sWk ) = @_;
printf "%04X:%-23s (Len:%3d) : %s\n",
$bOp, OpName($bOp), $bLen, unpack( "H40", $sWk );
}
#------------------------------------------------------------------------------
# Spreadsheet::ParseExcel->OpName
#------------------------------------------------------------------------------
sub OpName {
my ($bOp) = @_;
return ( defined $NameTbl{$bOp} ) ? $NameTbl{$bOp} : 'undef';
}
1;
__END__
=pod
=head1 NAME
Spreadsheet::ParseExcel::Dump - A class for dumping Excel records.
=head1 SYNOPSIS
See the documentation for Spreadsheet::ParseExcel.
=head1 DESCRIPTION
This module is used in conjunction with Spreadsheet::ParseExcel. See the documentation for Spreadsheet::ParseExcel.
=head1 AUTHOR
Current maintainer 0.60+: Douglas Wilson dougw@cpan.org
Maintainer 0.40-0.59: John McNamara jmcnamara@cpan.org
Maintainer 0.27-0.33: Gabor Szabo szabgab@cpan.org
Original author: Kawai Takanori kwitknr@cpan.org
=head1 COPYRIGHT
Copyright (c) 2014 Douglas Wilson
Copyright (c) 2009-2013 John McNamara
Copyright (c) 2006-2008 Gabor Szabo
Copyright (c) 2000-2006 Kawai Takanori
All rights reserved.
You may distribute under the terms of either the GNU General Public License or the Artistic License, as specified in the Perl README file.
=cut
Spreadsheet-ParseExcel-0.66/lib/Spreadsheet/ParseExcel/SaveParser/ 000755 000765 000024 00000000000 14543415025 025134 5 ustar 00John staff 000000 000000 Spreadsheet-ParseExcel-0.66/lib/Spreadsheet/ParseExcel/FmtUnicode.pm 000644 000765 000024 00000005306 14543413026 025457 0 ustar 00John staff 000000 000000 package Spreadsheet::ParseExcel::FmtUnicode;
###############################################################################
#
# Spreadsheet::ParseExcel::FmtUnicode - A class for Cell formats.
#
# Used in conjunction with Spreadsheet::ParseExcel.
#
# Copyright (c) 2014 Douglas Wilson
# Copyright (c) 2009-2013 John McNamara
# Copyright (c) 2006-2008 Gabor Szabo
# Copyright (c) 2000-2006 Kawai Takanori
#
# perltidy with standard settings.
#
# Documentation after __END__
#
use strict;
use warnings;
use Unicode::Map;
use base 'Spreadsheet::ParseExcel::FmtDefault';
our $VERSION = '0.66';
#------------------------------------------------------------------------------
# new (for Spreadsheet::ParseExcel::FmtUnicode)
#------------------------------------------------------------------------------
sub new {
my ( $sPkg, %hKey ) = @_;
my $sMap = $hKey{Unicode_Map};
my $oMap;
$oMap = Unicode::Map->new($sMap) if $sMap;
my $oThis = {
Unicode_Map => $sMap,
_UniMap => $oMap,
};
bless $oThis;
return $oThis;
}
#------------------------------------------------------------------------------
# TextFmt (for Spreadsheet::ParseExcel::FmtUnicode)
#------------------------------------------------------------------------------
sub TextFmt {
my ( $oThis, $sTxt, $sCode ) = @_;
if ( $oThis->{_UniMap} ) {
if ( !defined($sCode) ) {
my $sSv = $sTxt;
$sTxt =~ s/(.)/\x00$1/sg;
$sTxt = $oThis->{_UniMap}->from_unicode($sTxt);
$sTxt = $sSv unless ($sTxt);
}
elsif ( $sCode eq 'ucs2' ) {
$sTxt = $oThis->{_UniMap}->from_unicode($sTxt);
}
# $sTxt = $oThis->{_UniMap}->from_unicode($sTxt)
# if(defined($sCode) && $sCode eq 'ucs2');
return $sTxt;
}
else {
return $sTxt;
}
}
1;
__END__
=pod
=head1 NAME
Spreadsheet::ParseExcel::FmtUnicode - A class for Cell formats.
=head1 SYNOPSIS
See the documentation for Spreadsheet::ParseExcel.
=head1 DESCRIPTION
This module is used in conjunction with Spreadsheet::ParseExcel. See the documentation for Spreadsheet::ParseExcel.
=head1 AUTHOR
Current maintainer 0.60+: Douglas Wilson dougw@cpan.org
Maintainer 0.40-0.59: John McNamara jmcnamara@cpan.org
Maintainer 0.27-0.33: Gabor Szabo szabgab@cpan.org
Original author: Kawai Takanori kwitknr@cpan.org
=head1 COPYRIGHT
Copyright (c) 2014 Douglas Wilson
Copyright (c) 2009-2013 John McNamara
Copyright (c) 2006-2008 Gabor Szabo
Copyright (c) 2000-2006 Kawai Takanori
All rights reserved.
You may distribute under the terms of either the GNU General Public License or the Artistic License, as specified in the Perl README file.
=cut
Spreadsheet-ParseExcel-0.66/lib/Spreadsheet/ParseExcel/FmtJapan.pm 000644 000765 000024 00000013040 14543413026 025114 0 ustar 00John staff 000000 000000 package Spreadsheet::ParseExcel::FmtJapan;
use utf8;
###############################################################################
#
# Spreadsheet::ParseExcel::FmtJapan - A class for Cell formats.
#
# Used in conjunction with Spreadsheet::ParseExcel.
#
# Copyright (c) 2014 Douglas Wilson
# Copyright (c) 2009-2013 John McNamara
# Copyright (c) 2006-2008 Gabor Szabo
# Copyright (c) 2000-2006 Kawai Takanori
#
# perltidy with standard settings.
#
# Documentation after __END__
#
use strict;
use warnings;
use Encode qw(find_encoding decode);
use base 'Spreadsheet::ParseExcel::FmtDefault';
our $VERSION = '0.66';
my %FormatTable = (
0x00 => 'General',
0x01 => '0',
0x02 => '0.00',
0x03 => '#,##0',
0x04 => '#,##0.00',
0x05 => '(\\#,##0_);(\\#,##0)',
0x06 => '(\\#,##0_);[Red](\\#,##0)',
0x07 => '(\\#,##0.00_);(\\#,##0.00_)',
0x08 => '(\\#,##0.00_);[Red](\\#,##0.00_)',
0x09 => '0%',
0x0A => '0.00%',
0x0B => '0.00E+00',
0x0C => '# ?/?',
0x0D => '# ??/??',
# 0x0E => 'm/d/yy',
0x0E => 'yyyy/m/d',
0x0F => 'd-mmm-yy',
0x10 => 'd-mmm',
0x11 => 'mmm-yy',
0x12 => 'h:mm AM/PM',
0x13 => 'h:mm:ss AM/PM',
0x14 => 'h:mm',
0x15 => 'h:mm:ss',
# 0x16 => 'm/d/yy h:mm',
0x16 => 'yyyy/m/d h:mm',
#0x17-0x24 -- Differs in Natinal
0x1E => 'm/d/yy',
0x1F => 'yyyy"年"m"月"d"日"',
0x20 => 'h"時"mm"分"',
0x21 => 'h"時"mm"分"ss"秒"',
#0x17-0x24 -- Differs in Natinal
0x25 => '(#,##0_);(#,##0)',
0x26 => '(#,##0_);[Red](#,##0)',
0x27 => '(#,##0.00);(#,##0.00)',
0x28 => '(#,##0.00);[Red](#,##0.00)',
0x29 => '_(*#,##0_);_(*(#,##0);_(*"-"_);_(@_)',
0x2A => '_(\\*#,##0_);_(\\*(#,##0);_(*"-"_);_(@_)',
0x2B => '_(*#,##0.00_);_(*(#,##0.00);_(*"-"??_);_(@_)',
0x2C => '_(\\*#,##0.00_);_(\\*(#,##0.00);_(*"-"??_);_(@_)',
0x2D => 'mm:ss',
0x2E => '[h]:mm:ss',
0x2F => 'mm:ss.0',
0x30 => '##0.0E+0',
0x31 => '@',
0x37 => 'yyyy"年"m"月"',
0x38 => 'm"月"d"日"',
0x39 => 'ge.m.d',
0x3A => 'ggge"年"m"月"d"日"',
);
#------------------------------------------------------------------------------
# new (for Spreadsheet::ParseExcel::FmtJapan)
#------------------------------------------------------------------------------
sub new {
my ( $class, %args ) = @_;
my $encoding = $args{Code} || $args{encoding};
my $self = { Code => $encoding };
if($encoding){
$self->{encoding} = find_encoding($encoding eq 'sjis' ? 'cp932' : $encoding)
or do{
require Carp;
Carp::croak(qq{Unknown encoding '$encoding'});
};
}
return bless $self, $class;
}
#------------------------------------------------------------------------------
# TextFmt (for Spreadsheet::ParseExcel::FmtJapan)
#------------------------------------------------------------------------------
sub TextFmt {
my ( $self, $text, $input_encoding ) = @_;
if(!defined $input_encoding){
$input_encoding = 'utf8';
}
elsif($input_encoding eq '_native_'){
$input_encoding = 'cp932'; # Shift_JIS in Microsoft products
}
$text = decode($input_encoding, $text);
return $self->{Code} ? $self->{encoding}->encode($text) : $text;
}
#------------------------------------------------------------------------------
# FmtStringDef (for Spreadsheet::ParseExcel::FmtJapan)
#------------------------------------------------------------------------------
sub FmtStringDef {
my ( $self, $format_index, $book ) = @_;
return $self->SUPER::FmtStringDef( $format_index, $book, \%FormatTable );
}
#------------------------------------------------------------------------------
# CnvNengo (for Spreadsheet::ParseExcel::FmtJapan)
#------------------------------------------------------------------------------
# Convert A.D. into Japanese Nengo (aka Gengo)
my @Nengo = (
{
name => '平成', # Heisei
abbr_name => 'H',
base => 1988,
start => 19890108,
},
{
name => '昭和', # Showa
abbr_name => 'S',
base => 1925,
start => 19261225,
},
{
name => '大正', # Taisho
abbr_name => 'T',
base => 1911,
start => 19120730,
},
{
name => '明治', # Meiji
abbr_name => 'M',
base => 1867,
start => 18680908,
},
);
# Usage: CnvNengo(name => @tm) or CnvNeng(abbr_name => @tm)
sub CnvNengo {
my ( $kind, @tm ) = @_;
my $year = $tm[5] + 1900;
my $wk = ($year * 10000) + ($tm[4] * 100) + ($tm[3] * 1);
#my $wk = sprintf( '%04d%02d%02d', $year, $tm[4], $tm[3] );
foreach my $nengo(@Nengo){
if( $wk >= $nengo->{start} ){
return $nengo->{$kind} . ($year - $nengo->{base});
}
}
return $year;
}
1;
__END__
=pod
=head1 NAME
Spreadsheet::ParseExcel::FmtJapan - A class for Cell formats.
=head1 SYNOPSIS
See the documentation for Spreadsheet::ParseExcel.
=head1 DESCRIPTION
This module is used in conjunction with Spreadsheet::ParseExcel. See the documentation for Spreadsheet::ParseExcel.
=head1 AUTHOR
Current maintainer 0.60+: Douglas Wilson dougw@cpan.org
Maintainer 0.40-0.59: John McNamara jmcnamara@cpan.org
Maintainer 0.27-0.33: Gabor Szabo szabgab@cpan.org
Original author: Kawai Takanori kwitknr@cpan.org
=head1 COPYRIGHT
Copyright (c) 2014 Douglas Wilson
Copyright (c) 2009-2013 John McNamara
Copyright (c) 2006-2008 Gabor Szabo
Copyright (c) 2000-2006 Kawai Takanori
All rights reserved.
You may distribute under the terms of either the GNU General Public License or the Artistic License, as specified in the Perl README file.
=cut
Spreadsheet-ParseExcel-0.66/lib/Spreadsheet/ParseExcel/FmtJapan2.pm 000644 000765 000024 00000005271 14543413026 025205 0 ustar 00John staff 000000 000000 package Spreadsheet::ParseExcel::FmtJapan2;
###############################################################################
#
# Spreadsheet::ParseExcel::FmtJapan2 - A class for Cell formats.
#
# Used in conjunction with Spreadsheet::ParseExcel.
#
# Copyright (c) 2014 Douglas Wilson
# Copyright (c) 2009-2013 John McNamara
# Copyright (c) 2006-2008 Gabor Szabo
# Copyright (c) 2000-2006 Kawai Takanori
#
# perltidy with standard settings.
#
# Documentation after __END__
#
use strict;
use warnings;
use Jcode;
use Unicode::Map;
use base 'Spreadsheet::ParseExcel::FmtJapan';
our $VERSION = '0.66';
#------------------------------------------------------------------------------
# new (for Spreadsheet::ParseExcel::FmtJapan2)
#------------------------------------------------------------------------------
sub new {
my ( $sPkg, %hKey ) = @_;
my $oMap = Unicode::Map->new('CP932Excel');
die "NO MAP FILE CP932Excel!!"
unless ( -r Unicode::Map->mapping("CP932Excel") );
my $oThis = {
Code => $hKey{Code},
_UniMap => $oMap,
};
bless $oThis;
$oThis->SUPER::new(%hKey);
return $oThis;
}
#------------------------------------------------------------------------------
# TextFmt (for Spreadsheet::ParseExcel::FmtJapan2)
#------------------------------------------------------------------------------
sub TextFmt {
my ( $oThis, $sTxt, $sCode ) = @_;
# $sCode = 'sjis' if((! defined($sCode)) || ($sCode eq '_native_'));
if ( $oThis->{Code} ) {
if ( !defined($sCode) ) {
$sTxt =~ s/(.)/\x00$1/sg;
$sTxt = $oThis->{_UniMap}->from_unicode($sTxt);
}
elsif ( $sCode eq 'ucs2' ) {
$sTxt = $oThis->{_UniMap}->from_unicode($sTxt);
}
return Jcode::convert( $sTxt, $oThis->{Code}, 'sjis' );
}
else {
return $sTxt;
}
}
1;
__END__
=pod
=head1 NAME
Spreadsheet::ParseExcel::FmtJapan2 - A class for Cell formats.
=head1 SYNOPSIS
See the documentation for Spreadsheet::ParseExcel.
=head1 DESCRIPTION
This module is used in conjunction with Spreadsheet::ParseExcel. See the documentation for Spreadsheet::ParseExcel.
=head1 AUTHOR
Current maintainer 0.60+: Douglas Wilson dougw@cpan.org
Maintainer 0.40-0.59: John McNamara jmcnamara@cpan.org
Maintainer 0.27-0.33: Gabor Szabo szabgab@cpan.org
Original author: Kawai Takanori kwitknr@cpan.org
=head1 COPYRIGHT
Copyright (c) 2014 Douglas Wilson
Copyright (c) 2009-2013 John McNamara
Copyright (c) 2006-2008 Gabor Szabo
Copyright (c) 2000-2006 Kawai Takanori
All rights reserved.
You may distribute under the terms of either the GNU General Public License or the Artistic License, as specified in the Perl README file.
=cut
Spreadsheet-ParseExcel-0.66/lib/Spreadsheet/ParseExcel/SaveParser/Workbook.pm 000644 000765 000024 00000035777 14543413026 027311 0 ustar 00John staff 000000 000000 package Spreadsheet::ParseExcel::SaveParser::Workbook;
###############################################################################
#
# Spreadsheet::ParseExcel::SaveParser::Workbook - A class for SaveParser Workbooks.
#
# Used in conjunction with Spreadsheet::ParseExcel.
#
# Copyright (c) 2014 Douglas Wilson
# Copyright (c) 2009-2013 John McNamara
# Copyright (c) 2006-2008 Gabor Szabo
# Copyright (c) 2000-2006 Kawai Takanori
#
# perltidy with standard settings.
#
# Documentation after __END__
#
use strict;
use warnings;
use base 'Spreadsheet::ParseExcel::Workbook';
our $VERSION = '0.66';
#==============================================================================
# Spreadsheet::ParseExcel::SaveParser::Workbook
#==============================================================================
sub new {
my ( $sPkg, $oBook ) = @_;
return undef unless ( defined $oBook );
my %oThis = %$oBook;
bless \%oThis, $sPkg;
# re-bless worksheets (and set their _Book properties !!!)
my $sWkP = ref($sPkg) || "$sPkg";
$sWkP =~ s/Workbook$/Worksheet/;
map { bless( $_, $sWkP ); } @{ $oThis{Worksheet} };
map { $_->{_Book} = \%oThis; } @{ $oThis{Worksheet} };
return \%oThis;
}
#------------------------------------------------------------------------------
# Parse (for Spreadsheet::ParseExcel::SaveParser::Workbook)
#------------------------------------------------------------------------------
sub Parse {
my ( $sClass, $sFile, $oWkFmt ) = @_;
my $oBook = Spreadsheet::ParseExcel::Workbook->Parse( $sFile, $oWkFmt );
bless $oBook, $sClass;
# re-bless worksheets (and set their _Book properties !!!)
my $sWkP = ref($sClass) || "$sClass";
$sWkP =~ s/Workbook$/Worksheet/;
map { bless( $_, $sWkP ); } @{ $oBook->{Worksheet} };
map { $_->{_Book} = $oBook; } @{ $oBook->{Worksheet} };
return $oBook;
}
#------------------------------------------------------------------------------
# SaveAs (for Spreadsheet::ParseExcel::SaveParser::Workbook)
#------------------------------------------------------------------------------
sub SaveAs {
my ( $oBook, $sName ) = @_;
# Create a new Excel workbook
my $oWrEx = Spreadsheet::WriteExcel->new($sName);
$oWrEx->compatibility_mode();
my %hFmt;
my $iNo = 0;
my @aAlH = (
'left', 'left', 'center', 'right',
'fill', 'justify', 'merge', 'equal_space'
);
my @aAlV = ( 'top', 'vcenter', 'bottom', 'vjustify', 'vequal_space' );
foreach my $pFmt ( @{ $oBook->{Format} } ) {
my $oFmt = $oWrEx->addformat(); # Add Formats
unless ( $pFmt->{Style} ) {
$hFmt{$iNo} = $oFmt;
my $rFont = $pFmt->{Font};
$oFmt->set_font( $rFont->{Name} );
$oFmt->set_size( $rFont->{Height} );
$oFmt->set_color( $rFont->{Color} );
$oFmt->set_bold( $rFont->{Bold} );
$oFmt->set_italic( $rFont->{Italic} );
$oFmt->set_underline( $rFont->{Underline} );
$oFmt->set_font_strikeout( $rFont->{Strikeout} );
$oFmt->set_font_script( $rFont->{Super} );
$oFmt->set_hidden( $rFont->{Hidden} ); #Add
$oFmt->set_locked( $pFmt->{Lock} );
$oFmt->set_align( $aAlH[ $pFmt->{AlignH} ] );
$oFmt->set_align( $aAlV[ $pFmt->{AlignV} ] );
$oFmt->set_rotation( $pFmt->{Rotate} );
$oFmt->set_num_format(
$oBook->{FmtClass}->FmtStringDef( $pFmt->{FmtIdx}, $oBook ) );
$oFmt->set_text_wrap( $pFmt->{Wrap} );
$oFmt->set_pattern( $pFmt->{Fill}->[0] );
$oFmt->set_fg_color( $pFmt->{Fill}->[1] )
if ( ( $pFmt->{Fill}->[1] >= 8 )
&& ( $pFmt->{Fill}->[1] <= 63 ) );
$oFmt->set_bg_color( $pFmt->{Fill}->[2] )
if ( ( $pFmt->{Fill}->[2] >= 8 )
&& ( $pFmt->{Fill}->[2] <= 63 ) );
$oFmt->set_left(
( $pFmt->{BdrStyle}->[0] > 7 ) ? 3 : $pFmt->{BdrStyle}->[0] );
$oFmt->set_right(
( $pFmt->{BdrStyle}->[1] > 7 ) ? 3 : $pFmt->{BdrStyle}->[1] );
$oFmt->set_top(
( $pFmt->{BdrStyle}->[2] > 7 ) ? 3 : $pFmt->{BdrStyle}->[2] );
$oFmt->set_bottom(
( $pFmt->{BdrStyle}->[3] > 7 ) ? 3 : $pFmt->{BdrStyle}->[3] );
$oFmt->set_left_color( $pFmt->{BdrColor}->[0] )
if ( ( $pFmt->{BdrColor}->[0] >= 8 )
&& ( $pFmt->{BdrColor}->[0] <= 63 ) );
$oFmt->set_right_color( $pFmt->{BdrColor}->[1] )
if ( ( $pFmt->{BdrColor}->[1] >= 8 )
&& ( $pFmt->{BdrColor}->[1] <= 63 ) );
$oFmt->set_top_color( $pFmt->{BdrColor}->[2] )
if ( ( $pFmt->{BdrColor}->[2] >= 8 )
&& ( $pFmt->{BdrColor}->[2] <= 63 ) );
$oFmt->set_bottom_color( $pFmt->{BdrColor}->[3] )
if ( ( $pFmt->{BdrColor}->[3] >= 8 )
&& ( $pFmt->{BdrColor}->[3] <= 63 ) );
}
$iNo++;
}
for ( my $iSheet = 0 ; $iSheet < $oBook->{SheetCount} ; $iSheet++ ) {
my $oWkS = $oBook->{Worksheet}[$iSheet];
my $oWrS = $oWrEx->addworksheet( $oWkS->{Name} );
#Landscape
if ( !$oWkS->{Landscape} ) { # Landscape (0:Horizontal, 1:Vertical)
$oWrS->set_landscape();
}
else {
$oWrS->set_portrait();
}
#Protect
if ( defined $oWkS->{Protect} )
{ # Protect ('':NoPassword, Password:Password)
if ( $oWkS->{Protect} ne '' ) {
$oWrS->protect( $oWkS->{Protect} );
}
else {
$oWrS->protect();
}
}
if ( $oWkS->{Scale} != 100 ) {
# Pages on fit with width and Heigt
$oWrS->fit_to_pages( $oWkS->{FitWidth}, $oWkS->{FitHeight} );
#Print Scale and reset FitWidth/FitHeight
$oWrS->set_print_scale( $oWkS->{Scale} );
}
else {
#Print Scale
$oWrS->set_print_scale( $oWkS->{Scale} );
# Pages on fit with width and Heigt
$oWrS->fit_to_pages( $oWkS->{FitWidth}, $oWkS->{FitHeight} );
}
# Paper Size
$oWrS->set_paper( $oWkS->{PaperSize} );
# Margin
$oWrS->set_margin_left( $oWkS->{LeftMargin} );
$oWrS->set_margin_right( $oWkS->{RightMargin} );
$oWrS->set_margin_top( $oWkS->{TopMargin} );
$oWrS->set_margin_bottom( $oWkS->{BottomMargin} );
# HCenter
$oWrS->center_horizontally() if ( $oWkS->{HCenter} );
# VCenter
$oWrS->center_vertically() if ( $oWkS->{VCenter} );
# Header, Footer
$oWrS->set_header( $oWkS->{Header}, $oWkS->{HeaderMargin} );
$oWrS->set_footer( $oWkS->{Footer}, $oWkS->{FooterMargin} );
# Print Area
if ( ref( $oBook->{PrintArea}[$iSheet] ) eq 'ARRAY' ) {
my $raP;
for $raP ( @{ $oBook->{PrintArea}[$iSheet] } ) {
$oWrS->print_area(@$raP);
}
}
# Print Title
my $raW;
foreach $raW ( @{ $oBook->{PrintTitle}[$iSheet]->{Row} } ) {
$oWrS->repeat_rows(@$raW);
}
foreach $raW ( @{ $oBook->{PrintTitle}[$iSheet]->{Column} } ) {
$oWrS->repeat_columns(@$raW);
}
# Print Gridlines
if ( $oWkS->{PrintGrid} == 1 ) {
$oWrS->hide_gridlines(0);
}
else {
$oWrS->hide_gridlines(1);
}
# Print Headings
if ( $oWkS->{PrintHeaders} ) {
$oWrS->print_row_col_headers();
}
# Horizontal Page Breaks
$oWrS->set_h_pagebreaks( @{ $oWkS->{HPageBreak} } );
# Veritical Page Breaks
$oWrS->set_v_pagebreaks( @{ $oWkS->{VPageBreak} } );
# PageStart => $oWkS->{PageStart}, # Page number for start
# UsePage => $oWkS->{UsePage}, # Use own start page number
# NoColor => $oWkS->{NoColor}, # Print in black-white
# Draft => $oWkS->{Draft}, # Print in draft mode
# Notes => $oWkS->{Notes}, # Print notes
# LeftToRight => $oWkS->{LeftToRight}, # Left to Right
for (
my $iC = $oWkS->{MinCol} ;
defined $oWkS->{MaxCol} && $iC <= $oWkS->{MaxCol} ;
$iC++
)
{
if ( defined $oWkS->{ColWidth}[$iC] ) {
if ( $oWkS->{ColWidth}[$iC] > 0 ) {
$oWrS->set_column( $iC, $iC, $oWkS->{ColWidth}[$iC] )
; #, undef, 1) ;
}
else {
$oWrS->set_column( $iC, $iC, 0, undef, 1 );
}
}
}
my $merged_areas = $oWkS->get_merged_areas();
my $merged_areas_h = {};
if ($merged_areas) {
foreach my $range (@$merged_areas) {
$merged_areas_h->{$range->[0]}{$range->[1]} = $range;
}
}
for (
my $iR = $oWkS->{MinRow} ;
defined $oWkS->{MaxRow} && $iR <= $oWkS->{MaxRow} ;
$iR++
)
{
$oWrS->set_row( $iR, $oWkS->{RowHeight}[$iR] );
for (
my $iC = $oWkS->{MinCol} ;
defined $oWkS->{MaxCol} && $iC <= $oWkS->{MaxCol} ;
$iC++
)
{
my $oWkC = $oWkS->{Cells}[$iR][$iC];
if ($oWkC) {
if ( $oWkC->{Merged} and exists $merged_areas_h->{$iR}{$iC} ) {
my $oFmtN = $oWrEx->addformat();
$oFmtN->copy( $hFmt{ $oWkC->{FormatNo} } );
$oWrS->merge_range (
@{$merged_areas_h->{$iR}{$iC}},
$oBook->{FmtClass}
->TextFmt( $oWkC->{Val}, $oWkC->{Code} ),
$oFmtN
);
}
else {
$oWrS->write(
$iR,
$iC,
$oBook->{FmtClass}
->TextFmt( $oWkC->{Val}, $oWkC->{Code} ),
$hFmt{ $oWkC->{FormatNo} }
);
}
}
}
}
}
return $oWrEx;
}
#------------------------------------------------------------------------------
# AddWorksheet (for Spreadsheet::ParseExcel::SaveParser::Workbook)
#------------------------------------------------------------------------------
sub AddWorksheet {
my ( $oBook, $sName, %hAttr ) = @_;
$oBook->AddFormat if ( $#{ $oBook->{Format} } < 0 );
$hAttr{Name} ||= $sName;
$hAttr{LeftMargin} ||= 0;
$hAttr{RightMargin} ||= 0;
$hAttr{TopMargin} ||= 0;
$hAttr{BottomMargin} ||= 0;
$hAttr{HeaderMargin} ||= 0;
$hAttr{FooterMargin} ||= 0;
$hAttr{FitWidth} ||= 0;
$hAttr{FitHeight} ||= 0;
$hAttr{PrintGrid} ||= 0;
my $oWkS = Spreadsheet::ParseExcel::SaveParser::Worksheet->new(%hAttr);
$oWkS->{_Book} = $oBook;
$oWkS->{_SheetNo} = $oBook->{SheetCount};
$oBook->{Worksheet}[ $oBook->{SheetCount} ] = $oWkS;
$oBook->{SheetCount}++;
return $oWkS; #$oBook->{SheetCount} - 1;
}
#------------------------------------------------------------------------------
# AddFont (for Spreadsheet::ParseExcel::SaveParser::Workbook)
#------------------------------------------------------------------------------
sub AddFont {
my ( $oBook, %hAttr ) = @_;
$hAttr{Name} ||= 'Arial';
$hAttr{Height} ||= 10;
$hAttr{Bold} ||= 0;
$hAttr{Italic} ||= 0;
$hAttr{Underline} ||= 0;
$hAttr{Strikeout} ||= 0;
$hAttr{Super} ||= 0;
push @{ $oBook->{Font} }, Spreadsheet::ParseExcel::Font->new(%hAttr);
return $#{ $oBook->{Font} };
}
#------------------------------------------------------------------------------
# AddFormat (for Spreadsheet::ParseExcel::SaveParser::Workbook)
#------------------------------------------------------------------------------
sub AddFormat {
my ( $oBook, %hAttr ) = @_;
$hAttr{Fill} ||= [ 0, 0, 0 ];
$hAttr{BdrStyle} ||= [ 0, 0, 0, 0 ];
$hAttr{BdrColor} ||= [ 0, 0, 0, 0 ];
$hAttr{AlignH} ||= 0;
$hAttr{AlignV} ||= 0;
$hAttr{Rotate} ||= 0;
$hAttr{Landscape} ||= 0;
$hAttr{FmtIdx} ||= 0;
if ( !defined( $hAttr{Font} ) ) {
my $oFont;
if ( defined $hAttr{FontNo} ) {
$oFont = $oBook->{Font}[ $hAttr{FontNo} ];
}
elsif ( !defined $oFont ) {
if ( $#{ $oBook->{Font} } >= 0 ) {
$oFont = $oBook->{Font}[0];
}
else {
my $iNo = $oBook->AddFont;
$oFont = $oBook->{Font}[$iNo];
}
}
$hAttr{Font} = $oFont;
}
push @{ $oBook->{Format} }, Spreadsheet::ParseExcel::Format->new(%hAttr);
return $#{ $oBook->{Format} };
}
#------------------------------------------------------------------------------
# AddCell (for Spreadsheet::ParseExcel::SaveParser::Workbook)
#------------------------------------------------------------------------------
sub AddCell {
my ( $oBook, $iSheet, $iR, $iC, $sVal, $oCell, $sCode ) = @_;
my %rhKey;
$oCell ||= $oBook->{Worksheet}[$iSheet]
->{Cells}[$iR][$iC]->{FormatNo} || 0;
my $iFmt =
( UNIVERSAL::isa( $oCell, 'Spreadsheet::ParseExcel::Cell' ) )
? $oCell->{FormatNo}
: ( ref($oCell) ) ? 0
: $oCell + 0;
$rhKey{FormatNo} = $iFmt;
$rhKey{Format} = $oBook->{Format}[$iFmt];
$rhKey{Val} = $sVal;
$rhKey{Code} = $sCode || '_native_';
$oBook->{_CurSheet} = $iSheet;
my $merged_areas = $oBook->{Worksheet}[$iSheet]->get_merged_areas();
my $merged_areas_h = {};
if ($merged_areas) {
foreach my $range (@$merged_areas) {
$merged_areas_h->{$range->[0]}{$range->[1]} = $range;
}
}
my $oNewCell =
Spreadsheet::ParseExcel::_NewCell( $oBook, $iR, $iC, %rhKey );
Spreadsheet::ParseExcel::_SetDimension( $oBook, $iR, $iC, $iC );
$oNewCell->{Merged} = 1
if exists $merged_areas_h->{$iR}{$iC};
return $oNewCell;
}
1;
__END__
=pod
=head1 NAME
Spreadsheet::ParseExcel::SaveParser::Workbook - A class for SaveParser Workbooks.
=head1 SYNOPSIS
See the documentation for Spreadsheet::ParseExcel.
=head1 DESCRIPTION
This module is used in conjunction with Spreadsheet::ParseExcel. See the documentation for Spreadsheet::ParseExcel.
=head1 AUTHOR
Current maintainer 0.60+: Douglas Wilson dougw@cpan.org
Maintainer 0.40-0.59: John McNamara jmcnamara@cpan.org
Maintainer 0.27-0.33: Gabor Szabo szabgab@cpan.org
Original author: Kawai Takanori kwitknr@cpan.org
=head1 COPYRIGHT
Copyright (c) 2014 Douglas Wilson
Copyright (c) 2009-2013 John McNamara
Copyright (c) 2006-2008 Gabor Szabo
Copyright (c) 2000-2006 Kawai Takanori
All rights reserved.
You may distribute under the terms of either the GNU General Public License or the Artistic License, as specified in the Perl README file.
=cut
Spreadsheet-ParseExcel-0.66/lib/Spreadsheet/ParseExcel/SaveParser/Worksheet.pm 000644 000765 000024 00000005135 14543413026 027450 0 ustar 00John staff 000000 000000 package Spreadsheet::ParseExcel::SaveParser::Worksheet;
###############################################################################
#
# Spreadsheet::ParseExcel::SaveParser::Worksheet - A class for SaveParser Worksheets.
#
# Used in conjunction with Spreadsheet::ParseExcel.
#
# Copyright (c) 2014 Douglas Wilson
# Copyright (c) 2009-2013 John McNamara
# Copyright (c) 2006-2008 Gabor Szabo
# Copyright (c) 2000-2006 Kawai Takanori
#
# perltidy with standard settings.
#
# Documentation after __END__
#
use strict;
use warnings;
#==============================================================================
# Spreadsheet::ParseExcel::SaveParser::Worksheet
#==============================================================================
use base 'Spreadsheet::ParseExcel::Worksheet';
our $VERSION = '0.66';
sub new {
my ( $sClass, %rhIni ) = @_;
$sClass->SUPER::new(%rhIni); # returns object
}
#------------------------------------------------------------------------------
# AddCell (for Spreadsheet::ParseExcel::SaveParser::Worksheet)
#------------------------------------------------------------------------------
sub AddCell {
my ( $oSelf, $iR, $iC, $sVal, $oCell, $sCode ) = @_;
$oSelf->{_Book}
->AddCell( $oSelf->{_SheetNo}, $iR, $iC, $sVal, $oCell, $sCode );
}
#------------------------------------------------------------------------------
# Protect (for Spreadsheet::ParseExcel::SaveParser::Worksheet)
# - Password = undef -> No protect
# - Password = '' -> Protected. No password
# - Password = $pwd -> Protected. Password = $pwd
#------------------------------------------------------------------------------
sub Protect {
my ( $oSelf, $sPassword ) = @_;
$oSelf->{Protect} = $sPassword;
}
1;
__END__
=pod
=head1 NAME
Spreadsheet::ParseExcel::SaveParser::Worksheet - A class for SaveParser Worksheets.
=head1 SYNOPSIS
See the documentation for Spreadsheet::ParseExcel.
=head1 DESCRIPTION
This module is used in conjunction with Spreadsheet::ParseExcel. See the documentation for Spreadsheet::ParseExcel.
=head1 AUTHOR
Current maintainer 0.60+: Douglas Wilson dougw@cpan.org
Maintainer 0.40-0.59: John McNamara jmcnamara@cpan.org
Maintainer 0.27-0.33: Gabor Szabo szabgab@cpan.org
Original author: Kawai Takanori kwitknr@cpan.org
=head1 COPYRIGHT
Copyright (c) 2014 Douglas Wilson
Copyright (c) 2009-2013 John McNamara
Copyright (c) 2006-2008 Gabor Szabo
Copyright (c) 2000-2006 Kawai Takanori
All rights reserved.
You may distribute under the terms of either the GNU General Public License or the Artistic License, as specified in the Perl README file.
=cut
Spreadsheet-ParseExcel-0.66/sample/dmpExH.pl 000644 000765 000024 00000001711 11247565351 021022 0 ustar 00John staff 000000 000000 use strict;
use Spreadsheet::ParseExcel;
if(!(defined $ARGV[0])) {
print<{File} , "\n";
print "COUNT :", $oBook->{SheetCount} , "\n";
print "AUTHOR:", $oBook->{Author} , "\n";
}
if($iPreSheet != $iSheet) {
print "--------- SHEET:",
$oBook->{Worksheet}[$iSheet]->{Name}, "\n" ;
$iPreSheet = $iSheet;
}
print "( $iRow , $iCol ) =>", $oCell->Value, "\n";
# $oBook->ParseAbort('Exceed Data') if($iRow >= 1);
}
my $oExcel = new Spreadsheet::ParseExcel
( CellHandler => \&subCellHandler, NotSetCell => 1);
my $oBook = $oExcel->Parse($ARGV[0]);
print "ABORTED:", $oBook->{_ParseAbort} if($oBook->{_ParseAbort});
Spreadsheet-ParseExcel-0.66/sample/Excel/ 000755 000765 000024 00000000000 14543415025 020332 5 ustar 00John staff 000000 000000 Spreadsheet-ParseExcel-0.66/sample/smpFile.pl 000644 000765 000024 00000002204 11247565351 021232 0 ustar 00John staff 000000 000000 use lib qw(../);
use strict;
use Spreadsheet::ParseExcel;
my $oExcel = new Spreadsheet::ParseExcel;
sub PrnBook($);
#1.2 Normal Excel97
open(IN, 'Excel/Test97.xls');
binmode IN;
my $sWk;
read(IN, $sWk, 2000000);
close IN;
my $oBook1 = $oExcel->Parse([$sWk]);
PrnBook($oBook1);
sub PrnBook($)
{
my($oBook) = @_;
my($iR, $iC, $oWkS, $oWkC);
print "=========================================\n";
print "FILE :", $oBook->{File} , "\n";
print "COUNT :", $oBook->{SheetCount} , "\n";
print "AUTHOR:", $oBook->{Author} , "\n";
for(my $iSheet=0; $iSheet < $oBook->{SheetCount} ; $iSheet++) {
$oWkS = $oBook->{Worksheet}[$iSheet];
print "--------- SHEET:", $oWkS->{Name}, "\n";
for(my $iR = $oWkS->{MinRow} ;
defined $oWkS->{MaxRow} && $iR <= $oWkS->{MaxRow} ; $iR++) {
for(my $iC = $oWkS->{MinCol} ;
defined $oWkS->{MaxCol} && $iC <= $oWkS->{MaxCol} ; $iC++) {
$oWkC = $oWkS->{Cells}[$iR][$iC];
print "( $iR , $iC ) =>", $oWkC->Value, "\n" if($oWkC);
}
}
}
}
Spreadsheet-ParseExcel-0.66/sample/dmpEx_2xml.pl 000644 000765 000024 00000002646 11247565351 021664 0 ustar 00John staff 000000 000000 #Khalid EZZARAOUI khalid@yromem.com
use strict;
if(!(defined $ARGV[0])) {
print<Parse($ARGV[0]);
my($iR, $iC, $oWkS, $oWkC);
print '', "\n";
print "", "\n";
print "\t", "", "\n";
print "\t\t", "", $oBook->{File} , "", "\n";
print "\t\t", "", $oBook->{SheetCount} , "", "\n";
print "\t\t", "", $oBook->{Author} , "", "\n";
print "\t", "", "\n";
print "\t", "", "\n";
#for(my $iSheet=0; $iSheet < $oBook->{SheetCount} ; $iSheet++) {
# $oWkS = $oBook->{Worksheet}[$iSheet];
foreach my $oWkS (@{$oBook->{Worksheet}}) {
print "\t\t", "{Name}, "\" >", "\n";
for(my $iR = $oWkS->{MinRow} ; defined $oWkS->{MaxRow} && $iR <= $oWkS->{MaxRow} ; $iR++) {
print "\t\t\t", "", "\n" ;
for(my $iC = $oWkS->{MinCol} ; defined $oWkS->{MaxCol} && $iC <= $oWkS->{MaxCol} ; $iC++) {
$oWkC = $oWkS->{Cells}[$iR][$iC];
print "\t\t\t\t", "", $oWkC->Value, "", "\n" if($oWkC);
# print $oWkC->{_Kind}, "\n";
}
print "\t\t\t", "
", "\n" ;
}
print "\t\t", "\n" ;
}
print "\t", "", "\n";
print "", "\n";
Spreadsheet-ParseExcel-0.66/sample/dmpExU.pl 000644 000765 000024 00000002353 11247565351 021042 0 ustar 00John staff 000000 000000 # This script requieres Unicode::Map
use strict;
if($#ARGV < 1) {
print<new(Unicode_Map => $ARGV[1]);
my $oBook = $oExcel->Parse($ARGV[0], $oFmtJ);
my($iR, $iC, $oWkS, $oWkC);
print "=========================================\n";
print "FILE :", $oBook->{File} , "\n";
print "COUNT :", $oBook->{SheetCount} , "\n";
print "AUTHOR:", $oBook->{Author} , "\n";
my $table = [];
for(my $iSheet=0; $iSheet < $oBook->{SheetCount} ; $iSheet++) {
$oWkS = $oBook->{Worksheet}[$iSheet];
print "--------- SHEET:", $oWkS->{Name}, "\n";
for(my $iR = $oWkS->{MinRow} ;
defined $oWkS->{MaxRow} && $iR <= $oWkS->{MaxRow} ; $iR++) {
# print "ROW HEIGHT:", $oWkS->{RowHeight}[$iR], "\n";
for(my $iC = $oWkS->{MinCol} ;
defined $oWkS->{MaxCol} && $iC <= $oWkS->{MaxCol} ; $iC++) {
$oWkC = $oWkS->{Cells}[$iR][$iC];
print "( $iR , $iC ) =>", $oWkC->Value, "\n" if($oWkC);
}
}
}
Spreadsheet-ParseExcel-0.66/sample/sampleOEM.pl 000644 000765 000024 00000002544 11247565351 021464 0 ustar 00John staff 000000 000000 use strict;
use warnings;
use Spreadsheet::ParseExcel;
use Spreadsheet::ParseExcel::FmtJapan;
use Spreadsheet::ParseExcel::FmtJapan2;
my $oExcel = Spreadsheet::ParseExcel->new;
my $oFmtJ = Spreadsheet::ParseExcel::FmtJapan->new(Code => 'euc');
my $oFmtJ2 = Spreadsheet::ParseExcel::FmtJapan2->new(Code => 'euc');
my $oBook = $oExcel->Parse('Excel/oem.xls', $oFmtJ);
PrnAll($oBook);
$oBook = $oExcel->Parse('Excel/oem.xls', $oFmtJ2);
PrnAll($oBook);
sub PrnAll {
my ($oBook) = @_;
my($iR, $iC, $oWkS, $oWkC);
print "=========================================\n";
print "FILE :", $oBook->{File} , "\n";
print "COUNT :", $oBook->{SheetCount} , "\n";
print "AUTHOR:", $oBook->{Author} , "\n";
for(my $iSheet=0; $iSheet < $oBook->{SheetCount} ; $iSheet++) {
$oWkS = $oBook->{Worksheet}[$iSheet];
print "--------- SHEET:", $oWkS->{Name}, "\n";
for(my $iR = $oWkS->{MinRow} ;
defined $oWkS->{MaxRow} && $iR <= $oWkS->{MaxRow} ; $iR++) {
print "ROW HEIGHT:", $oWkS->{RowHeight}[$iR], "\n";
for(my $iC = $oWkS->{MinCol} ;
defined $oWkS->{MaxCol} && $iC <= $oWkS->{MaxCol} ; $iC++) {
$oWkC = $oWkS->{Cells}[$iR][$iC];
print "( $iR , $iC ) =>", $oWkC->Value, "\n" if($oWkC);
}
}
}
}
Spreadsheet-ParseExcel-0.66/sample/README 000644 000765 000024 00000002546 11247565351 020167 0 ustar 00John staff 000000 000000 chkFmt.pl : Sample Script for formatting
res_fmt : result of chkFmt.pl
chkInfo.pl : Sample Script for get information about format
res_info : result of chkInfo.pl with Excel/FmtTest.xls
sample.pl :Simple Script (using SpreadSheet::ParseExcel::FmtDefault)
sample_j.pl :Simple Script using Japanese character
(using SpreadSheet::ParseExcel::FmtJapan)
res_sample :result of sample.pl
res_samplej :result of sample_j.pl (in euc)
dmpEx.pl : print out content of Excel file
(using SpreadSheet::ParseExcel::FmtDefault)
dmpExJ.pl : print out content of Excel file
(using SpreadSheet::ParseExcel::FmtJapan)
dmpExU.pl : print out content of Excel file
(using SpreadSheet::ParseExcel::FmtUnicode)
dmpExH.pl : print out content of Excel file
(using SpreadSheet::ParseExcel::FmtDefault + event handler)
sampleOEM.pl: Displys difference between FmtJapan and FmtJapan2
res_oem : result of samplOEM.pl
dmpExR.pl : Sample Script for get information about each characters.
res_rich : result of dmpExR.pl with Excel/Rich.xls
Ilya.pl : Sample script for Object Oriented callback
smpFile.pl : Sample scripr for parsing perl variable
xls2csv.pl : Sample script for xls2csv
iftest.pl : Sample script for new interface
iftestj.pl : Sample script for new interface with FmtJapan
Spreadsheet-ParseExcel-0.66/sample/dmpExHJ.pl 000644 000765 000024 00000002404 11247565351 021134 0 ustar 00John staff 000000 000000 use strict;
use Spreadsheet::ParseExcel;
use Spreadsheet::ParseExcel::FmtJapan2;
if(!(defined $ARGV[0])) {
print<{File} , "\n";
print "COUNT :", $oBook->{SheetCount} , "\n";
print "AUTHOR:", $oBook->{Author} , "\n";
}
if($iPreSheet != $iSheet) {
print "--------- SHEET:",
$oBook->{Worksheet}[$iSheet]->{Name}, "\n" ;
$iPreSheet = $iSheet;
}
print "( $iRow , $iCol ) =>", $oCell->Value, "\n";
# $oBook->ParseAbort('Exceed Data') if($iRow >= 1);
}
my $oExcel = new Spreadsheet::ParseExcel
( CellHandler => \&subCellHandler, NotSetCell => 1);
my $oFmtJ = Spreadsheet::ParseExcel::FmtJapan2->new(Code => $ARGV[1]);
my $oBook = $oExcel->Parse($ARGV[0], $oFmtJ);
for(my $i=0;$i<$oBook->{SheetCount};$i++) {
print "LAST:\n";
print "Row:", $oBook->{Worksheet}[$i]->{MaxRow}, "\n";
print "Col:", $oBook->{Worksheet}[$i]->{MaxCol}, "\n";
}
print "ABORTED:", $oBook->{_ParseAbort} if($oBook->{_ParseAbort});
Spreadsheet-ParseExcel-0.66/sample/sample_j.pl 000644 000765 000024 00000003513 11247565351 021431 0 ustar 00John staff 000000 000000 use strict;
use warnings;
use Spreadsheet::ParseExcel;
use Spreadsheet::ParseExcel::FmtJapan;
if(($#ARGV< 0) or
(grep($ARGV[0] eq $_, ('euc', 'sjis', 'jis')) <= 0)) {
print "USAGE: \n > perl ", $0, " euc|sjis|jis\n";
exit;
}
my $oExcel = Spreadsheet::ParseExcel->new;
#1. Make Formatter
my $oFmtJ = Spreadsheet::ParseExcel::FmtJapan->new(Code => $ARGV[0]);
#2.1 Test97
my $oBook = $oExcel->Parse('sample/Excel/Test97J.xls', $oFmtJ);
PrnBook($oBook);
#2.2 Test95
$oBook = $oExcel->Parse('sample/Excel/Test95J.xls', $oFmtJ);
PrnBook($oBook);
#2.3 1904 (1904 - 97)
$oBook = $oExcel->Parse('sample/Excel/Test1904.xls', $oFmtJ);
PrnBook($oBook);
#2.4 1904 (1904 - 95)
$oBook = $oExcel->Parse('sample/Excel/Test1904_95.xls', $oFmtJ);
PrnBook($oBook);
#2.5 1904 (1904 - 95)
$oBook = $oExcel->Parse('sample/Excel/AuthorK.xls', $oFmtJ);
PrnBook($oBook);
#2.6 1904 (1904 - 95)
$oBook = $oExcel->Parse('sample/Excel/AuthorK95.xls', $oFmtJ);
PrnBook($oBook);
sub PrnBook {
my($oBook) = @_;
my($iR, $iC, $oWkS, $oWkC);
print "=========================================\n";
print "FILE :", $oBook->{File} , "\n";
print "COUNT :", $oBook->{SheetCount} , "\n";
print "AUTHOR:", $oBook->{Author} , "\n";
for(my $iSheet=0; $iSheet < $oBook->{SheetCount} ; $iSheet++) {
$oWkS = $oBook->{Worksheet}[$iSheet];
print "--------- SHEET:", $oWkS->{Name}, "\n";
for(my $iR = $oWkS->{MinRow} ;
defined $oWkS->{MaxRow} && $iR <= $oWkS->{MaxRow} ; $iR++) {
for(my $iC = $oWkS->{MinCol} ;
defined $oWkS->{MaxCol} && $iC <= $oWkS->{MaxCol} ; $iC++) {
$oWkC = $oWkS->{Cells}[$iR][$iC];
print "( $iR , $iC ) =>", $oWkC->Value, "\n" if($oWkC);
}
}
}
}
Spreadsheet-ParseExcel-0.66/sample/dmpExJ.pl 000644 000765 000024 00000002326 11247565351 021027 0 ustar 00John staff 000000 000000 use strict;
if(!(defined $ARGV[0])) {
print<new(Code => $ARGV[1]);
my $oBook = $oExcel->Parse($ARGV[0], $oFmtJ);
my($iR, $iC, $oWkS, $oWkC);
print "=========================================\n";
print "FILE :", $oBook->{File} , "\n";
print "COUNT :", $oBook->{SheetCount} , "\n";
print "AUTHOR:", $oBook->{Author} , "\n";
#for(my $iSheet=0; $iSheet < $oBook->{SheetCount} ; $iSheet++) {
# $oWkS = $oBook->{Worksheet}[$iSheet];
for my $oWkS (@{$oBook->{Worksheet}}) {
print "--------- SHEET:", $oWkS->{Name}, "\n";
for(my $iR = $oWkS->{MinRow} ;
defined $oWkS->{MaxRow} && $iR <= $oWkS->{MaxRow} ; $iR++) {
print "ROW HEIGHT:", $oWkS->{RowHeight}[$iR], "\n";
for(my $iC = $oWkS->{MinCol} ;
defined $oWkS->{MaxCol} && $iC <= $oWkS->{MaxCol} ; $iC++) {
$oWkC = $oWkS->{Cells}[$iR][$iC];
print "( $iR , $iC ) =>", $oWkC->Value, "\n" if($oWkC);
}
}
}
Spreadsheet-ParseExcel-0.66/sample/Ilya.pl 000644 000765 000024 00000001112 11247565351 020526 0 ustar 00John staff 000000 000000 use strict;
use Spreadsheet::ParseExcel;
package IlyaPackage; #:-)
sub new($){
my $self = shift;
my $obj = {};
bless $obj, $self;
}
sub cb_routine($@) {
my($self, $oBook, $iSheet, $iRow, $iCol, $oCell) = @_;
print "( $iRow , $iCol ) =>", $oCell->Value, "\n";
}
sub parse($$){
my($self, $sFile) = @_;
my $oEx =
Spreadsheet::ParseExcel->new(
CellHandler => \&cb_routine,
Object => $self,
NotSetCell => 1);
$oEx->Parse($sFile);
}
1;
my $oIlya =IlyaPackage->new;
$oIlya->parse($ARGV[0]);
Spreadsheet-ParseExcel-0.66/sample/chkInfo.pl 000644 000765 000024 00000014364 11247565351 021226 0 ustar 00John staff 000000 000000 use strict;
use warnings;
use Spreadsheet::ParseExcel;
my $oExcel = Spreadsheet::ParseExcel->new;
die "Usage: $0 file.xls\n" if not @ARGV;
#=Default
use Spreadsheet::ParseExcel::FmtDefault;
my $oFmt = Spreadsheet::ParseExcel::FmtDefault->new;
my $oBook = $oExcel->Parse($ARGV[0]);
#=cut
#Japan
#use Spreadsheet::ParseExcel::FmtJapan2;
#my $oFmt = Spreadsheet::ParseExcel::FmtJapan2->new(Code=>'sjis');
#my $oBook = $oExcel->Parse('Excel/FmtTest.xls', $oFmt);
#=cut
#Other Countries (ex. Russia (CP1251))
#use Spreadsheet::ParseExcel::FmtUnicode;
#my $oFmt = Spreadsheet::ParseExcel::FmtUnicode->new(Unicode_Map => 'CP1251');
#my $oBook = $oExcel->Parse('Excel/FmtTest.xls', $oFmt);
#=cut
my($iR, $iC, $oWkS, $oWkC);
print "=========================================\n";
print 'FILE :', $oBook->{File} , "\n",
'COUNT :', $oBook->{SheetCount} , "\n",
'AUTHOR :', $oBook->{Author} , "\n";
for(my $iSheet=0; $iSheet < $oBook->{SheetCount} ; $iSheet++) {
$oWkS = $oBook->{Worksheet}[$iSheet];
print "--------- SHEET:", $oWkS->{Name}, "\n";
print ">> Print Setting\n",
'Landscape :', $oWkS->{Landscape} , "\n",
'Scale :', $oWkS->{Scale} , "\n",
'FitWidth :', $oWkS->{FitWidth} , "\n",
'FitHeight :', $oWkS->{FitHeight} , "\n",
'PageFit :', $oWkS->{PageFit} , "\n",
'PaperSize :', $oWkS->{PaperSize} , "\n",
'PageStart :', $oWkS->{PageStart} , "\n",
'UsePage :', $oWkS->{UsePage} , "\n";
print ">> Format\n",
'Mergin Left :', $oWkS->{LeftMergin} , "\n",
' Right :', $oWkS->{RightMergin} , "\n",
' Top :', $oWkS->{TopMergin} , "\n",
' Bottom :', $oWkS->{BottomMergin} , "\n",
' Header :', $oWkS->{HeaderMergin} , "\n",
' Footer :', $oWkS->{FooterMergin} , "\n",
'Horizontal Center:', $oWkS->{HCenter} , "\n",
'Vertical Center :', $oWkS->{VCenter} , "\n",
'Header :', $oWkS->{Header} , "\n",
'Footer :', $oWkS->{Footer} , "\n";
print "Print Area :\n";
foreach my $raA (@{$oBook->{PrintArea}[$iSheet]}) {
print ' Area :', join(",", @$raA), "\n";
}
my $rhA = $oBook->{PrintTitle}[$iSheet];
print "Print Title :\n";
print " Row :\n";
foreach my $raTr (@{$rhA->{Row}}) {
print '>> :', join(",", @$raTr) , "\n";
}
print " Column :\n";
foreach my $raTr (@{$rhA->{Column}}) {
print '>> :', join(",", @$raTr) , "\n";
}
print 'Print Gridlines :', $oWkS->{PrintGrid} , "\n",
'Print Headings :', $oWkS->{PrintHeaders} , "\n",
'NoColor :', $oWkS->{NoColor} , "\n",
'Draft :', $oWkS->{Draft} , "\n",
'Notes :', $oWkS->{Notes} , "\n",
'LeftToRight :', $oWkS->{LeftToRight} , "\n";
foreach my $raA (@{$oWkS->{MergedArea}}) {
print "Merged Area:", join(",", @$raA), "\n";
}
print 'Horizontal PageBreak :', join(',', @{$oWkS->{HPageBreak}}), "\n"
if($oWkS->{HPageBreak});
print 'Vertical PageBreak :', join(',', @{$oWkS->{VPageBreak}}), "\n"
if($oWkS->{VPageBreak});
for(my $iR = $oWkS->{MinRow} ;
defined $oWkS->{MaxRow} && $iR <= $oWkS->{MaxRow} ; $iR++) {
for(my $iC = $oWkS->{MinCol} ;
defined $oWkS->{MaxCol} && $iC <= $oWkS->{MaxCol} ; $iC++) {
$oWkC = $oWkS->{Cells}[$iR][$iC];
if($oWkC) {
print "------------------------------------------------------\n",
"( $iR , $iC ) =>", $oWkC->Value, "\n";
print 'Format :', $oFmt->FmtString($oWkC, $oBook), "\n",
'AlignH :', $oWkC->{Format}->{AlignH}, "\n",
'AlignV :', $oWkC->{Format}->{AlignV}, "\n",
'Indent :', $oWkC->{Format}->{Indent}, "\n",
'Wrap :', $oWkC->{Format}->{Wrap}, "\n",
'Shrink :', $oWkC->{Format}->{Shrink}, "\n",
'Merged :', (defined($oWkC->{Merged})?
$oWkC->{Merged}: 'No'), "\n",
'Rotate :', $oWkC->{Format}->{Rotate}, "\n";
# 'JustLast :', $oWkC->{Format}->{JustLast}, "\n",
# 'ReadDir :', $oWkC->{Format}->{ReadDir}, "\n",
my $oFont = $oWkC->{Format}->{Font};
print 'Name :', $oFont->{Name}, "\n",
'Bold :', $oFont->{Bold}, "\n",
'Italic :', $oFont->{Italic}, "\n",
'Height :', $oFont->{Height}, "\n",
'Underline :', $oFont->{Underline}, "\n",
'UnderlineStyle :', sprintf("%02x", $oFont->{UnderlineStyle}), "\n",
'Color :', $oFont->{Color}, "\n",
'Color RGB :', Spreadsheet::ParseExcel->ColorIdxToRGB($oFont->{Color}), "\n",
'Strikeout :', $oFont->{Strikeout}, "\n",
'Super :', $oFont->{Super}, "\n",
'BdrStyle :', join(',', @{$oWkC->{Format}->{BdrStyle}}), "\n",
'BdrColor :', join(',', @{$oWkC->{Format}->{BdrColor}}), "\n",
'BdrDiag :', join(',', @{$oWkC->{Format}->{BdrDiag}}), "\n",
'Pattern :', join(',', @{$oWkC->{Format}->{Fill}}), "\n",
'Lock :', $oWkC->{Format}->{Lock}, "\n",
'Hidden :', $oWkC->{Format}->{Hidden}, "\n";
}
}
}
}
Spreadsheet-ParseExcel-0.66/sample/dmpExR.pl 000644 000765 000024 00000004255 11247565351 021042 0 ustar 00John staff 000000 000000 use strict;
use warnings;
if(!(defined $ARGV[0])) {
print<new;
my $oBook = $oExcel->Parse($ARGV[0]);
my($iR, $iC, $oWkS, $oWkC);
print "=========================================\n";
print "FILE :", $oBook->{File} , "\n";
print "COUNT :", $oBook->{SheetCount} , "\n";
print "AUTHOR:", $oBook->{Author} , "\n";
for(my $iSheet=0; $iSheet < $oBook->{SheetCount} ; $iSheet++) {
$oWkS = $oBook->{Worksheet}[$iSheet];
print "--------- SHEET:", $oWkS->{Name}, "\n";
for(my $iR = $oWkS->{MinRow} ;
defined $oWkS->{MaxRow} && $iR <= $oWkS->{MaxRow} ; $iR++) {
for(my $iC = $oWkS->{MinCol} ;
defined $oWkS->{MaxCol} && $iC <= $oWkS->{MaxCol} ; $iC++) {
$oWkC = $oWkS->{Cells}[$iR][$iC];
print "( $iR , $iC ) =>", $oWkC->Value, "\n" if($oWkC);
if($oWkC) {
if($oWkC->{Rich}) {
foreach my $raR (@{$oWkC->{Rich}}) {
my $oFont = $raR->[1];
print
"--------------------------------------------\n",
'POS :', $raR->[0], "\n",
'Name :', $oFont->{Name}, "\n",
'Bold :', $oFont->{Bold}, "\n",
'Italic :', $oFont->{Italic}, "\n",
'Height :', $oFont->{Height}, "\n",
'Underline :', $oFont->{Underline}, "\n",
'UnderlineStyle :', sprintf("%02x", $oFont->{UnderlineStyle}), "\n",
'Color :', $oFont->{Color}, "\n",
'Color RGB :', Spreadsheet::ParseExcel->ColorIdxToRGB($oFont->{Color}), "\n",
'Strikeout :', $oFont->{Strikeout}, "\n",
'Super :', $oFont->{Super}, "\n",
}
}
}
}
}
}
}
Spreadsheet-ParseExcel-0.66/sample/xls2csv.pl 000644 000765 000024 00000003024 11247565351 021240 0 ustar 00John staff 000000 000000 #!/usr/bin/perl -w
# Script to extract a range of columns/rows from an Excel spreadsheet
# and present it as a csv, there is also the option to rotate the
# output,
#
# (c) kevin Mulholland 2002, kevin@moodfarm.demon.co.uk
# This code is released under the Perl Artistic License
#
# See also the following utilities:.
# Ken Prows' xls2csv:
# http://search.cpan.org/~ken/xls2csv/script/xls2csv
# H.Merijn Brand's xls2csv (which is part of Spreadsheet::Read):
# http://search.cpan.org/~hmbrand/Spreadsheet-Read/
#
use strict ;
use Spreadsheet::ParseExcel;
use Spreadsheet::ParseExcel::Utility qw(xls2csv);
use Text::CSV_XS;
if(!(defined $ARGV[0])) {
usage( "Bad Args") ;
exit;
}
my $rotate = 0 ;
my $filename = $ARGV[0] ;
my $coords = $ARGV[1] ;
$rotate = 1 if( defined $ARGV[2] && $ARGV[2] eq "-rotate") ;
if( !$coords) {
usage( "No co-ordinates defined") ;
exit ;
}
if( ! -f $filename) {
usage( "File $filename does not exist") ;
exit ;
}
printf xls2csv( $filename, $coords, $rotate) ;
# -----------------------------------------------------------------------------
### error
# writes a message to STDERR
#
sub error {
printf STDERR shift ;
}
# -----------------------------------------------------------------------------
### usage
# this decribes how the program as a whole is to be used
#
sub usage {
my $errmsg = shift ;
error( "\n" . $errmsg . "\n") if( $errmsg) ;
error( "
Usage: $0 filename sheet-colrow:colrow [-rotate]
eg: $0 filename.xls 1-A1:B12
$0 filename.xls A1:M1 -rotate\n\n") ;
}
Spreadsheet-ParseExcel-0.66/sample/iftest.pl 000644 000765 000024 00000002310 11247565351 021127 0 ustar 00John staff 000000 000000 use strict;
use warnings;
use Spreadsheet::ParseExcel;
die "Usage: $0 Excel/Test97.xls\n" if not @ARGV;
my $filename = $ARGV[0];
my $oBook =
Spreadsheet::ParseExcel::Workbook->Parse($filename);
my($iR, $iC, $oWkS, $oWkC);
foreach my $oWkS (@{$oBook->{Worksheet}}) {
print "--------- SHEET:", $oWkS->{Name}, "\n";
for(my $iR = $oWkS->{MinRow} ;
defined $oWkS->{MaxRow} && $iR <= $oWkS->{MaxRow} ; $iR++) {
for(my $iC = $oWkS->{MinCol} ;
defined $oWkS->{MaxCol} && $iC <= $oWkS->{MaxCol} ; $iC++) {
$oWkC = $oWkS->{Cells}[$iR][$iC];
print "( $iR , $iC ) =>", $oWkC->Value, "\n" if($oWkC);
}
}
}
#Sheet Name
print $oBook->Worksheet('Sheet1-ASC')->{Cells}[0][1]->Value, "\n";
#Sheet No
print $oBook->Worksheet(0)->{Cells}[0][1]->Value, "\n";
#Sheet Not found
print (($oBook->Worksheet('SHEET1') ? 'Exists' : 'Not Exists'), "\n");
__END__
# removed so we can run test (by Gabor)
use Spreadsheet::ParseExcel::SaveParser;
$oBook =
Spreadsheet::ParseExcel::SaveParser::Workbook->Parse($filename);
my $oWs = $oBook->AddWorksheet('TEST1');
$oWs->AddCell(10, 1, 'New Cell');
$oBook->SaveAs('iftest.xls');
Spreadsheet-ParseExcel-0.66/sample/iftestj.pl 000644 000765 000024 00000002034 11247565351 021304 0 ustar 00John staff 000000 000000 use strict;
use Spreadsheet::ParseExcel;
use Spreadsheet::ParseExcel::FmtJapan;
my $oBook =
Spreadsheet::ParseExcel::Workbook->Parse(
'Excel/Test97J.xls',
Spreadsheet::ParseExcel::FmtJapan->new (Code => 'sjis'));
my($iR, $iC, $oWkS, $oWkC);
print "=========================================\n";
print "FILE :", $oBook->{File} , "\n";
print "COUNT :", $oBook->{SheetCount} , "\n";
print "AUTHOR:", $oBook->{Author} , "\n";
#for(my $iSheet=0; $iSheet < $oBook->{SheetCount} ; $iSheet++) {
# $oWkS = $oBook->{Worksheet}[$iSheet];
foreach my $oWkS (@{$oBook->{Worksheet}}) {
print "--------- SHEET:", $oWkS->{Name}, "\n";
for(my $iR = $oWkS->{MinRow} ;
defined $oWkS->{MaxRow} && $iR <= $oWkS->{MaxRow} ; $iR++) {
for(my $iC = $oWkS->{MinCol} ;
defined $oWkS->{MaxCol} && $iC <= $oWkS->{MaxCol} ; $iC++) {
$oWkC = $oWkS->{Cells}[$iR][$iC];
print "( $iR , $iC ) =>", $oWkC->Value, "\n" if($oWkC);
print $oWkC->{_Kind}, "\n";
}
}
}
Spreadsheet-ParseExcel-0.66/sample/sample.pl 000644 000765 000024 00000002557 11247565351 021127 0 ustar 00John staff 000000 000000 use strict;
use warnings;
use Spreadsheet::ParseExcel;
my $oExcel = Spreadsheet::ParseExcel->new;
sub PrnBook($);
#1.1 Normal Excel97
my $oBook = $oExcel->Parse('sample/Excel/Test97.xls');
PrnBook($oBook);
#1.2 Normal Excel95
$oBook = $oExcel->Parse('sample/Excel/Test95.xls');
PrnBook($oBook);
#1.3 Year 1904 Base (Excel97)
$oBook = $oExcel->Parse('sample/Excel/Test1904.xls');
PrnBook($oBook);
#1.4 Year 1904 Base (Excel95)
$oBook = $oExcel->Parse('sample/Excel/Test1904_95.xls');
PrnBook($oBook);
sub PrnBook($)
{
my($oBook) = @_;
my($iR, $iC, $oWkS, $oWkC);
print "=========================================\n";
print "FILE :", $oBook->{File} , "\n";
print "COUNT :", $oBook->{SheetCount} , "\n";
print "AUTHOR:", $oBook->{Author} , "\n";
for(my $iSheet=0; $iSheet < $oBook->{SheetCount} ; $iSheet++) {
$oWkS = $oBook->{Worksheet}[$iSheet];
print "--------- SHEET:", $oWkS->{Name}, "\n";
for(my $iR = $oWkS->{MinRow} ;
defined $oWkS->{MaxRow} && $iR <= $oWkS->{MaxRow} ; $iR++) {
for(my $iC = $oWkS->{MinCol} ;
defined $oWkS->{MaxCol} && $iC <= $oWkS->{MaxCol} ; $iC++) {
$oWkC = $oWkS->{Cells}[$iR][$iC];
print "( $iR , $iC ) =>", $oWkC->Value, "\n" if($oWkC);
}
}
}
}
Spreadsheet-ParseExcel-0.66/sample/parse.pl 000644 000765 000024 00000002745 11247565351 020757 0 ustar 00John staff 000000 000000 #!/usr/bin/perl
use strict;
use warnings;
use Spreadsheet::ParseExcel;
use Getopt::Long qw(GetOptions);
my $file;
my $help;
my $dump;
my ($row, $col);
GetOptions(
"file=s" => \$file,
"help" => \$help,
"dump" => \$dump,
"row=i" => \$row,
"col=i" => \$col,
) or usage();
usage() if $help;
usage() if not $file;
my $excel = Spreadsheet::ParseExcel::Workbook->Parse($file);
if ($dump) {
foreach my $sheet (@{$excel->{Worksheet}}) {
printf("Sheet: %s\n", $sheet->{Name});
$sheet->{MaxRow} ||= $sheet->{MinRow};
foreach my $row ($sheet->{MinRow} .. $sheet->{MaxRow}) {
$sheet->{MaxCol} ||= $sheet->{MinCol};
foreach my $col ($sheet->{MinCol} .. $sheet->{MaxCol}) {
my $cell = $sheet->{Cells}[$row][$col];
if ($cell) {
printf("( %s , %s ) => %s\n", $row, $col, $cell->{Val});
}
}
}
}
}
if (defined $row and defined $col) {
foreach my $sheet (@{$excel->{Worksheet}}) {
printf("Sheet: %s\n", $sheet->{Name});
my $cell = $sheet->{Cells}[$row][$col];
printf("( %s , %s ) => '%s'\n", $row, $col, $cell->{Val});
printf("( %s , %s ) => '%s'\n", $row, $col, $cell->Value);
}
}
sub usage {
print <<"END_USAGE";
Usage: $0
--file FILENAME
--dump
--row ROW
--col COL
--help
END_USAGE
exit;
}
Spreadsheet-ParseExcel-0.66/sample/chkFmt.pl 000644 000765 000024 00000003322 11247565351 021051 0 ustar 00John staff 000000 000000 use strict;
use warnings;
use Spreadsheet::ParseExcel::Utility;
my $sWk;
my @aData = (-2, 0, 1234, -1234, 34323.23232, -233232.3233,
Spreadsheet::ParseExcel::Utility::LocaltimeExcel(13, 11, 12, 23, 2, 64, undef, 238));
my %hFmtTest = (
0x00 => '@',
0x01 => '0',
0x02 => '0.00',
0x03 => '#,##0',
0x04 => '#,##0.00',
0x05 => '(\\\\#,##0_);(\\\\#,##0)',
0x06 => '(\\\\#,##0_);[RED](\\\\#,##0)',
0x07 => '(\\\\#,##0.00_);(\\\\#,##0.00_)',
0x08 => '(\\\\#,##0.00_);[RED](\\\\#,##0.00_)',
0x09 => '0%',
0x0A => '0.00%',
0x0B => '0.00E+00',
0x0C => '# ?/?',
0x0D => '# ??/??',
0x0E => 'm/d/yy',
0x0F => 'd-mmm-yy',
0x10 => 'd-mmm',
0x11 => 'mmm-yy',
0x12 => 'h:mm AM/PM',
0x13 => 'h:mm:ss AM/PM',
0x14 => 'h:mm',
0x15 => 'h:mm:ss',
0x16 => 'm/d/yy h:mm',
#0x17-0x24 -- Differs in Natinal
0x25 => '(#,##0_);(#,##0)',
0x26 => '(#,##0_);[RED](#,##0)',
0x27 => '(#,##0.00);(#,##0.00)',
0x28 => '(#,##0.00);[RED](#,##0.00)',
0x29 => '_(*#,##0_);_(*(#,##0);_(*"-"_);_(@_)',
0x2A => '_(\\\\*#,##0_);_(\\\\*(#,##0);_(*"-"_);_(@_)',
0x2B => '_(*#,##0.00_);_(*(#,##0.00);_(*"-"??_);_(@_)',
0x2C => '_(\\\\*#,##0.00_);_(\\\\*(#,##0.00);_(*"-"??_);_(@_)',
0x2D => 'mm:ss',
0x2E => '[h]:mm:ss',
0x2F => 'mm:ss.0',
0x30 => '##0.0E+0',
0x31 => '@',
);
foreach my $sKey (sort {$a <=> $b} keys(%hFmtTest)) {
my $sVal = $hFmtTest{$sKey};
printf "============ %02x \n", $sKey;
foreach my $sDt (@aData) {
$sWk = Spreadsheet::ParseExcel::Utility::ExcelFmt($sVal, $sDt);
printf "Fmt: %-20s : %-10s: Data: %s\n", $sVal, "$sDt", $sWk;
}
}
Spreadsheet-ParseExcel-0.66/sample/dmpEx.pl 000644 000765 000024 00000002014 11247565351 020707 0 ustar 00John staff 000000 000000 use strict;
if(!(defined $ARGV[0])) {
print<Parse($ARGV[0]);
my($iR, $iC, $oWkS, $oWkC);
print "=========================================\n";
print "FILE :", $oBook->{File} , "\n";
print "COUNT :", $oBook->{SheetCount} , "\n";
print "AUTHOR:", $oBook->{Author} , "\n";
#for(my $iSheet=0; $iSheet < $oBook->{SheetCount} ; $iSheet++) {
# $oWkS = $oBook->{Worksheet}[$iSheet];
foreach my $oWkS (@{$oBook->{Worksheet}}) {
print "--------- SHEET:", $oWkS->{Name}, "\n";
for(my $iR = $oWkS->{MinRow} ;
defined $oWkS->{MaxRow} && $iR <= $oWkS->{MaxRow} ; $iR++) {
for(my $iC = $oWkS->{MinCol} ;
defined $oWkS->{MaxCol} && $iC <= $oWkS->{MaxCol} ; $iC++) {
$oWkC = $oWkS->{Cells}[$iR][$iC];
print "( $iR , $iC ) =>", $oWkC->Value, "\n" if($oWkC);
print $oWkC->{_Kind}, "\n";
}
}
}
Spreadsheet-ParseExcel-0.66/sample/Excel/AuthorK.xls 000644 000765 000024 00000034000 11247565351 022442 0 ustar 00John staff 000000 000000 ࡱ > \ p kawait B a = = <