## Copyright (C) 2013-2018 Philip Nienhuis
## Copyright (C) 2013 Markus Bergholz (.xlsx & archive unzip stuff)
##
## This program is free software; you can redistribute it and/or modify
## it under the terms of the GNU General Public License as published by
## the Free Software Foundation; either version 3 of the License, or
## (at your option) any later version.
##
## This program is distributed in the hope that it will be useful,
## but WITHOUT ANY WARRANTY; without even the implied warranty of
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
## GNU General Public License for more details.
##
## You should have received a copy of the GNU General Public License
## along with Octave; see the file COPYING. If not, see
## .
## -*- texinfo -*-
## @deftypefn {Function File} {@var{retval} =} __OCT_spsh_open__ (@var{x} @var{y})
##
## @seealso{}
## @end deftypefn
## Author: Philip Nienhuis
## File open stuff by Markus Bergholz
## Created: 2013-09-08
function [ xls, xlssupport, lastintf] = __OCT_spsh_open__ (xls, xwrite, filename, xlssupport, ftype)
## default output (on error)
lastintf = "";
## Open and unzip file to temp location (code by Markus Bergholz)
## create current work folder
tmpdir = tempname;
## Get template if a new file is created
if (xwrite == 3)
if (ftype == 2)
ext = ".xlsx";
elseif (ftype == 3)
ext = ".ods";
elseif (ftype == 5)
ext = ".gnumeric";
endif
## New file, get it from template. Use odsopen.m to find it
templ = strrep (which ("xlsopen"), "xlsopen.m", ["templates" filesep "template" ext]);
else
templ = filename;
endif
## zip operations sometimes transfer to temp dir; make sure we get back
opwd = pwd;
if (ftype == 5)
## Gnumeric xml files are gzipped
system (sprintf ('gzip -d -c -S=gnumeric "%s" > %s', templ, tmpdir));
fid = fopen (tmpdir, 'r');
xml = fread (fid, "char=>char").';
## Close file handle, don't delete file
fclose (fid);
else
## xlsx and ods are zipped
try
## FIXME: Use "unpack" instead of system ("unzip...") when it is fixed
[stts, op] = system (sprintf ('unzip -o "%s" -d %s', templ, tmpdir));
if (stts != 0)
error ("UnZip failed with error %d\nOutput:\n%s\n", stts, op);
endif
catch err
printf ("file %s couldn't be unpacked. Is it the proper file format?\n", filename);
warning (err.message)
warning (err.stack)
xls = [];
cd (opwd);
return
end_try_catch
endif
## Make sure we get back to original work dir
cd (opwd);
## Set up file pointer struct
if (ftype == 2)
## ======================= XLSX ===========================================
## From xlsxread by Markus Bergholz
## https://github.com/markuman/xlsxread
## Get sheet names. Speeds up other functions a lot if we can do it here
fid = fopen (sprintf ('%s/xl/workbook.xml', tmpdir));
if (fid < 0)
## File open error
warning ("xls2open: file %s couldn't be unzipped\n", filename);
xls = [];
return
endif
## Fill xlsx pointer
xls.workbook = tmpdir; # subdir containing content.xml
xls.xtype = "OCT"; # OCT is fall-back interface
xls.app = 'xlsx'; # must NOT be an empty string!
xls.filename = filename; # spreadsheet filename
xls.changed = 0; # Dummy
## Get content.xml
xml = fread (fid, "char=>char").';
## Close file
fclose (fid);
## Get sheet names and indices. rId# is the position in the worksheet stack.
sheets = getxmlnode (xml, "sheets", [], 1);
xls.sheets.sh_names = cell2mat (regexp (sheets, ' 0)
str = fread (fid, "char=>char").';
fclose (fid);
ee = 1;
numrels = numel (strfind (str, 'Relationship '));
relids = cell (numrels, 3);
for ii=1:numrels
[node, ~, ee] = getxmlnode (str, "Relationship", ee);
relids{ii, 1} = getxmlattv (node, "Id");
relids{ii, 2} = getxmlattv (node, "Target");
relids(ii, 3) = "0";
endfor
id = strmatch ("worksheets", relids(:, 2));
relids(id, 3) = "1";
rels = str2double (cell2mat (cell2mat ( ...
regexp (relids(id, :), '(\d+)', "tokens"))));
id = strmatch ("chartsheets", relids(:, 2));
if (! isempty (id))
relids(id, 3) = "2";
rels = [rels; (str2double (cell2mat (cell2mat ( ...
regexp (relids(id, :), '(\d+)', "tokens")))))];
endif
rels = sortrows (rels, 1);
xls.sheets.shId = rels(:, 2)';
xls.sheets.type = rels(:, 3)';
else
xls.sheets.rels = reshape ([xls.sheets.rid xls.sheets.rid], [], ...
columns (xls.sheets.rid));
endif
elseif (ftype == 3)
## ============== ODS. Read the actual data part in content.xml ============
fid = fopen (sprintf ("%s/content.xml", tmpdir), "r");
if (fid < 0)
## File open error
error ("file %s couldn't be opened for reading", filename);
else
## Read file contents
xml = fread (fid, "char=>char").';
## Close file but keep it around, store file name in struct pointer
fclose (fid);
## To speed things up later on, get sheet names and starting indices
shtidx = strfind (xml, "");
endif
shtidx = [ shtidx sht_end ];
## Get sheet names
sh_names = cell (1, nsheets);
for ii=1:nsheets
sh_names(ii) = xml(shtidx(ii)+25 : shtidx(ii)+23+index (xml(shtidx(ii)+25:end), '"'));
endfor
## Fill ods pointer.
xls.workbook = tmpdir; # subdir containing content.xml
xls.sheets.sh_names = sh_names; # sheet names
xls.sheets.shtidx = shtidx; # start & end indices of sheets
xls.xtype = "OCT"; # OCT is fall-back interface
xls.app = 'ods'; # must NOT be an empty string!
xls.filename = filename; # spreadsheet filename
xls.changed = 0; # Dummy
endif
elseif (ftype == 5)
## ====================== Gnumeric =========================================
xls.workbook = tmpdir; # location of unzipped files
xls.xtype = "OCT"; # interface
xls.app = 'gnumeric'; #
xls.filename = filename; # file name
xls.changed = 0; # Dummy
## Get nr of sheets & pointers to start of Sheet nodes & end of Sheets node
shtidx = strfind (xml, "") ];
xls.sheets.sh_names = cell (1, numel (shtidx));
sh_names = getxmlnode (xml, "gnm:SheetNameIndex");
jdx = 1;
for ii=1:numel (shtidx)
[xls.sheets.sh_names(ii), ~, jdx] = getxmlnode (sh_names, "gnm:SheetName", jdx, 1);
endfor
endif
xlssupport += 1;
lastintf = "OCT";
endfunction