function outputNames = createArchive(filename, files, rootDir, ...
                       createArchiveEntryFcn, archiveOutputStream, fcnName)
%CREATEARCHIVE Create an archive of files
%
%   CREATEARCHIVE creates an archive FILENAME from the files specified by
%   FILES and ROOTDIR. OUPUTNAMES is a string cell array of relative path
%   filenames stored in the archive. For all operating systems, the
%   directory delimiter is '/'.
%
%   FILENAME is a string containing the name of the archive.
%
%   FILES is a string cell array of the filenames to add to the archive.
%
%   ROOTDIR is a string containing the name of the root directory of FILES.
%
%   CREATEARCHIVEENTRYFCN is a function handle to create an archive entry
%
%   ARCHIVEOUTPUTSTREAM is a Java stream object attached to the archive 
%   output file.
%
%   FCNNAME is the string name of the calling function and used in
%   constructing error messages.

%   Copyright 2004 The MathWorks, Inc.
%   $Revision: 1.1.6.1 $   $Date: 2004/11/23 20:39:55 $

% Create a structure of the inputs.
entries = getArchiveEntries(filename, files, rootDir, fcnName);

% Check for duplicates
checkDuplicateEntries(entries, fcnName)

% Create a stream copier to copy files
streamCopier = ...
   com.mathworks.mlwidgets.io.InterruptibleStreamCopier.getInterruptibleStreamCopier;

% Add each entry to the archive.
for i = 1:length(entries)
   % Create the entry objects.
   addArchiveEntry(filename, createArchiveEntryFcn, entries(i), ...
                   archiveOutputStream, streamCopier, fcnName);
end

% Close stream.
archiveOutputStream.close;

% Return outputNames
outputNames = {entries(:).entry};

%--------------------------------------------------------------------------
function checkDuplicateEntries(entries, fcnName)
% Check for duplicate entry names.
allNames = {entries.entry};
[uniqueNames,i] = unique(allNames);
if length(uniqueNames) < length(entries)
   firstDup = allNames{min(setdiff(1:length(entries),i))};
   eid = sprintf('MATLAB:%s:duplicateEntry',fcnName);
   error(eid, 'Function %s tried to add two files as "%s".', ...
              upper(fcnName), firstDup);
end

%--------------------------------------------------------------------------
function addArchiveEntry(archiveFilename, createArchiveEntryFcn, entry, ...
                         fileOutputStream, streamCopier, archiveFcn)

% Create the archive entry
archiveEntry = createArchiveEntryFcn(entry);

% Create a Java file input stream from the archive entry
try
   file = java.io.File(entry.file);
   fileInputStream = java.io.FileInputStream(file);
catch
   eid = sprintf('MATLAB:%s:openEntryError',archiveFcn);
   error(eid,'Could not open "%s" for reading.',entry.file);
end

% Put and copy the entry into the archive
verbose = false;
try
   if verbose
      fprintf('Adding: %s\n',entry.entry);
   end
   fileOutputStream.putNextEntry(archiveEntry);
   streamCopier.copyStream(fileInputStream,fileOutputStream);

catch
   eid=sprintf('MATLAB:%s:copyStreamError', archiveFcn);
   error(eid,'Unable to write entry %s to %s file %s', ...
             entry.entry, archiveFcn, archiveFilename);
end

% Close everything up.
fileInputStream.close;
fileOutputStream.closeEntry;
