net.sf.mpxj.mpp.MPP12Reader Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of mpxj Show documentation
Show all versions of mpxj Show documentation
Library that provides facilities to allow project information to be manipulated in Java and .Net. Supports a range of data formats: Microsoft Project Exchange (MPX), Microsoft Project (MPP,MPT), Microsoft Project Data Interchange (MSPDI XML), Microsoft Project Database (MPD), Planner (XML), Primavera (PM XML, XER, and database), Asta Powerproject (PP, MDB), Asta Easyplan (PP), Phoenix Project Manager (PPX), FastTrack Schedule (FTS), and the Standard Data Exchange Format (SDEF).
/*
* file: MPP12Reader.java
* author: Jon Iles
* copyright: (c) Packwood Software 2002-2005
* date: 05/12/2005
*/
/*
* This library is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by the
* Free Software Foundation; either version 2.1 of the License, or (at your
* option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
* License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library; if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
*/
package net.sf.mpxj.mpp;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import net.sf.mpxj.AssignmentField;
import net.sf.mpxj.DateRange;
import net.sf.mpxj.Day;
import net.sf.mpxj.DayType;
import net.sf.mpxj.EventManager;
import net.sf.mpxj.MPXJException;
import net.sf.mpxj.ProjectCalendar;
import net.sf.mpxj.ProjectCalendarException;
import net.sf.mpxj.ProjectCalendarHours;
import net.sf.mpxj.ProjectCalendarWeek;
import net.sf.mpxj.ProjectFile;
import net.sf.mpxj.ProjectProperties;
import net.sf.mpxj.Resource;
import net.sf.mpxj.ResourceField;
import net.sf.mpxj.ResourceType;
import net.sf.mpxj.SubProject;
import net.sf.mpxj.Table;
import net.sf.mpxj.TableContainer;
import net.sf.mpxj.Task;
import net.sf.mpxj.TaskField;
import net.sf.mpxj.View;
import net.sf.mpxj.WorkGroup;
import net.sf.mpxj.common.DateHelper;
import net.sf.mpxj.common.NumberHelper;
import net.sf.mpxj.common.Pair;
import net.sf.mpxj.common.RtfHelper;
import org.apache.poi.poifs.filesystem.DirectoryEntry;
import org.apache.poi.poifs.filesystem.DocumentEntry;
import org.apache.poi.poifs.filesystem.DocumentInputStream;
/**
* This class is used to represent a Microsoft Project MPP12 file. This
* implementation allows the file to be read, and the data it contains
* exported as a set of MPX objects. These objects can be interrogated
* to retrieve any required data, or stored as an MPX file.
*/
final class MPP12Reader implements MPPVariantReader
{
/**
* This method is used to process an MPP12 file. This is the file format
* used by Project 12.
*
* @param reader parent file reader
* @param file parent MPP file
* @param root Root of the POI file system.
*/
@Override public void process(MPPReader reader, ProjectFile file, DirectoryEntry root) throws MPXJException, IOException
{
try
{
populateMemberData(reader, file, root);
processProjectProperties();
if (!reader.getReadPropertiesOnly())
{
processSubProjectData();
processGraphicalIndicators();
processCustomValueLists();
processCalendarData();
processResourceData();
processTaskData();
processConstraintData();
processAssignmentData();
postProcessTasks();
if (reader.getReadPresentationData())
{
processViewPropertyData();
processTableData();
processViewData();
processFilterData();
processGroupData();
processSavedViewState();
}
}
}
finally
{
clearMemberData();
}
}
/**
* Populate member data used by the rest of the reader.
*
* @param reader parent file reader
* @param file parent MPP file
* @param root Root of the POI file system.
*/
private void populateMemberData(MPPReader reader, ProjectFile file, DirectoryEntry root) throws MPXJException, IOException
{
m_reader = reader;
m_file = file;
m_eventManager = file.getEventManager();
m_root = root;
//
// Retrieve the high level document properties
//
Props12 props12 = new Props12(new DocumentInputStream(((DocumentEntry) root.getEntry("Props12"))));
//System.out.println(props12);
file.getProjectProperties().setProjectFilePath(props12.getUnicodeString(Props.PROJECT_FILE_PATH));
m_inputStreamFactory = new DocumentInputStreamFactory(props12);
//
// Test for password protection. In the single byte retrieved here:
//
// 0x00 = no password
// 0x01 = protection password has been supplied
// 0x02 = write reservation password has been supplied
// 0x03 = both passwords have been supplied
//
if ((props12.getByte(Props.PASSWORD_FLAG) & 0x01) != 0)
{
// Couldn't figure out how to get the password for MPP12 files so for now we just need to block the reading
throw new MPXJException(MPXJException.PASSWORD_PROTECTED);
}
m_resourceMap = new HashMap();
m_projectDir = (DirectoryEntry) root.getEntry(" 112");
m_viewDir = (DirectoryEntry) root.getEntry(" 212");
DirectoryEntry outlineCodeDir = (DirectoryEntry) m_projectDir.getEntry("TBkndOutlCode");
m_outlineCodeVarMeta = new VarMeta12(new DocumentInputStream(((DocumentEntry) outlineCodeDir.getEntry("VarMeta"))));
m_outlineCodeVarData = new Var2Data(m_outlineCodeVarMeta, new DocumentInputStream(((DocumentEntry) outlineCodeDir.getEntry("Var2Data"))));
m_outlineCodeFixedMeta = new FixedMeta(new DocumentInputStream(((DocumentEntry) outlineCodeDir.getEntry("FixedMeta"))), 10);
m_outlineCodeFixedData = new FixedData(m_outlineCodeFixedMeta, new DocumentInputStream(((DocumentEntry) outlineCodeDir.getEntry("FixedData"))));
m_outlineCodeFixedMeta2 = new FixedMeta(new DocumentInputStream(((DocumentEntry) outlineCodeDir.getEntry("Fixed2Meta"))), 10);
m_outlineCodeFixedData2 = new FixedData(m_outlineCodeFixedMeta2, new DocumentInputStream(((DocumentEntry) outlineCodeDir.getEntry("Fixed2Data"))));
m_projectProps = new Props12(m_inputStreamFactory.getInstance(m_projectDir, "Props"));
//MPPUtility.fileDump("c:\\temp\\props.txt", m_projectProps.toString().getBytes());
m_fontBases = new HashMap();
m_taskSubProjects = new HashMap();
m_taskOrder = new TreeMap();
m_nullTaskOrder = new TreeMap();
m_file.getProjectProperties().setMppFileType(Integer.valueOf(12));
m_file.getProjectProperties().setAutoFilter(props12.getBoolean(Props.AUTO_FILTER));
}
/**
* Clear transient member data.
*/
private void clearMemberData()
{
m_reader = null;
m_file = null;
m_eventManager = null;
m_root = null;
m_resourceMap = null;
m_projectDir = null;
m_viewDir = null;
m_outlineCodeVarData = null;
m_outlineCodeVarMeta = null;
m_projectProps = null;
m_fontBases = null;
m_taskSubProjects = null;
m_taskOrder = null;
m_nullTaskOrder = null;
m_inputStreamFactory = null;
}
/**
* This method extracts and collates the value list information
* for custom column value lists.
*/
private void processCustomValueLists() throws IOException
{
DirectoryEntry taskDir = (DirectoryEntry) m_projectDir.getEntry("TBkndTask");
Props taskProps = new Props12(m_inputStreamFactory.getInstance(taskDir, "Props"));
CustomFieldValueReader12 reader = new CustomFieldValueReader12(m_file.getProjectProperties(), m_file.getCustomFields(), m_outlineCodeVarMeta, m_outlineCodeVarData, m_outlineCodeFixedData, m_outlineCodeFixedData2, taskProps);
reader.process();
}
/**
* Process the project properties data.
*/
private void processProjectProperties() throws MPXJException
{
ProjectPropertiesReader reader = new ProjectPropertiesReader();
reader.process(m_file, m_projectProps, m_root);
}
/**
* Process the graphical indicator data.
*/
private void processGraphicalIndicators()
{
GraphicalIndicatorReader graphicalIndicatorReader = new GraphicalIndicatorReader();
graphicalIndicatorReader.process(m_file.getCustomFields(), m_file.getProjectProperties(), m_projectProps);
}
/**
* Read sub project data from the file, and add it to a hash map
* indexed by task ID.
*
* Project stores all subprojects that have ever been inserted into this project
* in sequence and that is what used to count unique id offsets for each of the
* subprojects.
*/
private void processSubProjectData()
{
byte[] subProjData = m_projectProps.getByteArray(Props.SUBPROJECT_DATA);
//System.out.println (MPPUtility.hexdump(subProjData, true, 16, ""));
//MPPUtility.fileHexDump("c:\\temp\\dump.txt", subProjData);
if (subProjData != null)
{
int index = 0;
int offset = 0;
int itemHeaderOffset;
int uniqueIDOffset;
int filePathOffset;
int fileNameOffset;
byte[] itemHeader = new byte[20];
/*int blockSize = MPPUtility.getInt(subProjData, offset);*/
offset += 4;
/*int unknown = MPPUtility.getInt(subProjData, offset);*/
offset += 4;
int itemCountOffset = MPPUtility.getInt(subProjData, offset);
offset += 4;
while (offset < itemCountOffset)
{
index++;
itemHeaderOffset = MPPUtility.getInt(subProjData, offset) & 0x1FFFF;
offset += 4;
MPPUtility.getByteArray(subProjData, itemHeaderOffset, itemHeader.length, itemHeader, 0);
//System.out.println();
//System.out.println (MPPUtility.hexdump(itemHeader, false, 16, ""));
//System.out.println(MPPUtility.hexdump(subProjData, offset, 16, false));
//System.out.println("Offset1: " + (MPPUtility.getInt(subProjData, offset) & 0x1FFFF));
//System.out.println("Offset2: " + (MPPUtility.getInt(subProjData, offset+4) & 0x1FFFF));
//System.out.println("Offset3: " + (MPPUtility.getInt(subProjData, offset+8) & 0x1FFFF));
//System.out.println("Offset4: " + (MPPUtility.getInt(subProjData, offset+12) & 0x1FFFF));
//System.out.println ("Offset: " + offset);
//System.out.println ("Item Header Offset: " + itemHeaderOffset);
byte subProjectType = itemHeader[16];
//System.out.println("SubProjectType: " + Integer.toHexString(subProjectType));
switch (subProjectType)
{
//
// Subproject that is no longer inserted. This is a placeholder in order to be
// able to always guarantee unique unique ids.
//
case 0x00:
//
// deleted entry?
//
case 0x10:
{
offset += 8;
break;
}
//
// task unique ID, 8 bytes, path, file name
//
case 0x0b:
case (byte) 0x99:
case 0x09:
case 0x0D:
{
uniqueIDOffset = MPPUtility.getInt(subProjData, offset) & 0x1FFFF;
offset += 4;
// sometimes offset of a task ID?
offset += 4;
filePathOffset = MPPUtility.getInt(subProjData, offset) & 0x1FFFF;
offset += 4;
fileNameOffset = MPPUtility.getInt(subProjData, offset) & 0x1FFFF;
offset += 4;
readSubProjects(subProjData, uniqueIDOffset, filePathOffset, fileNameOffset, index);
break;
}
//
// task unique ID, 8 bytes, path, file name
//
case 0x03:
case 0x11:
case (byte) 0x91:
{
uniqueIDOffset = MPPUtility.getInt(subProjData, offset) & 0x1FFFF;
offset += 4;
filePathOffset = MPPUtility.getInt(subProjData, offset) & 0x1FFFF;
offset += 4;
fileNameOffset = MPPUtility.getInt(subProjData, offset) & 0x1FFFF;
offset += 4;
// Unknown offset
offset += 4;
readSubProjects(subProjData, uniqueIDOffset, filePathOffset, fileNameOffset, index);
break;
}
//
// task unique ID, path, unknown, file name
//
case (byte) 0x81:
case (byte) 0x83:
case 0x41:
{
uniqueIDOffset = MPPUtility.getInt(subProjData, offset) & 0x1FFFF;
offset += 4;
filePathOffset = MPPUtility.getInt(subProjData, offset) & 0x1FFFF;
offset += 4;
// unknown offset to 2 bytes of data?
offset += 4;
fileNameOffset = MPPUtility.getInt(subProjData, offset) & 0x1FFFF;
offset += 4;
readSubProjects(subProjData, uniqueIDOffset, filePathOffset, fileNameOffset, index);
break;
}
//
// task unique ID, path, file name
//
case 0x01:
case 0x08:
{
uniqueIDOffset = MPPUtility.getInt(subProjData, offset) & 0x1FFFF;
offset += 4;
filePathOffset = MPPUtility.getInt(subProjData, offset) & 0x1FFFF;
offset += 4;
fileNameOffset = MPPUtility.getInt(subProjData, offset) & 0x1FFFF;
offset += 4;
readSubProjects(subProjData, uniqueIDOffset, filePathOffset, fileNameOffset, index);
break;
}
//
// task unique ID, path, file name
//
case (byte) 0xC0:
{
uniqueIDOffset = itemHeaderOffset;
filePathOffset = MPPUtility.getInt(subProjData, offset) & 0x1FFFF;
offset += 4;
fileNameOffset = MPPUtility.getInt(subProjData, offset) & 0x1FFFF;
offset += 4;
// unknown offset
offset += 4;
readSubProjects(subProjData, uniqueIDOffset, filePathOffset, fileNameOffset, index);
break;
}
//
// resource, task unique ID, path, file name
//
case 0x05:
{
uniqueIDOffset = MPPUtility.getInt(subProjData, offset) & 0x1FFFF;
offset += 4;
filePathOffset = MPPUtility.getInt(subProjData, offset) & 0x1FFFF;
offset += 4;
fileNameOffset = MPPUtility.getInt(subProjData, offset) & 0x1FFFF;
offset += 4;
m_file.getSubProjects().setResourceSubProject(readSubProject(subProjData, uniqueIDOffset, filePathOffset, fileNameOffset, index));
break;
}
case 0x45:
{
uniqueIDOffset = MPPUtility.getInt(subProjData, offset) & 0x1FFFF;
offset += 4;
filePathOffset = MPPUtility.getInt(subProjData, offset) & 0x1FFFF;
offset += 4;
fileNameOffset = MPPUtility.getInt(subProjData, offset) & 0x1FFFF;
offset += 4;
offset += 4;
m_file.getSubProjects().setResourceSubProject(readSubProject(subProjData, uniqueIDOffset, filePathOffset, fileNameOffset, index));
break;
}
//
// path, file name
//
case 0x02:
{
//filePathOffset = MPPUtility.getInt(subProjData, offset) & 0x1FFFF;
offset += 4;
//fileNameOffset = MPPUtility.getInt(subProjData, offset) & 0x1FFFF;
offset += 4;
//sp = readSubProject(subProjData, -1, filePathOffset, fileNameOffset, index);
// 0x02 looks to be the link FROM the resource pool to a project that is using it.
break;
}
case 0x04:
{
filePathOffset = MPPUtility.getInt(subProjData, offset) & 0x1FFFF;
offset += 4;
fileNameOffset = MPPUtility.getInt(subProjData, offset) & 0x1FFFF;
offset += 4;
m_file.getSubProjects().setResourceSubProject(readSubProject(subProjData, -1, filePathOffset, fileNameOffset, index));
break;
}
//
// task unique ID, 4 bytes, path, 4 bytes, file name
//
case (byte) 0x8D:
{
uniqueIDOffset = MPPUtility.getShort(subProjData, offset);
offset += 8;
filePathOffset = MPPUtility.getShort(subProjData, offset);
offset += 8;
fileNameOffset = MPPUtility.getShort(subProjData, offset);
offset += 4;
readSubProjects(subProjData, uniqueIDOffset, filePathOffset, fileNameOffset, index);
break;
}
//
// task unique ID, path, file name
//
case 0x0A:
{
uniqueIDOffset = MPPUtility.getShort(subProjData, offset);
offset += 4;
filePathOffset = MPPUtility.getShort(subProjData, offset);
offset += 4;
fileNameOffset = MPPUtility.getShort(subProjData, offset);
offset += 4;
readSubProjects(subProjData, uniqueIDOffset, filePathOffset, fileNameOffset, index);
break;
}
// new resource pool entry
case (byte) 0x44:
{
filePathOffset = MPPUtility.getInt(subProjData, offset) & 0x1FFFF;
offset += 4;
offset += 4;
fileNameOffset = MPPUtility.getInt(subProjData, offset) & 0x1FFFF;
offset += 4;
readSubProjects(subProjData, -1, filePathOffset, fileNameOffset, index);
break;
}
//
// Appears when a subproject is collapsed
//
case (byte) 0x80:
{
offset += 12;
break;
}
//
// Any other value, assume 12 bytes to handle old/deleted data?
//
default:
{
offset += 12;
break;
}
}
}
}
}
/**
* Read a list of sub projects.
*
* @param data byte array
* @param uniqueIDOffset offset of unique ID
* @param filePathOffset offset of file path
* @param fileNameOffset offset of file name
* @param subprojectIndex index of the subproject, used to calculate unique id offset
*/
private void readSubProjects(byte[] data, int uniqueIDOffset, int filePathOffset, int fileNameOffset, int subprojectIndex)
{
while (uniqueIDOffset < filePathOffset)
{
readSubProject(data, uniqueIDOffset, filePathOffset, fileNameOffset, subprojectIndex++);
uniqueIDOffset += 4;
}
}
/**
* Method used to read the sub project details from a byte array.
*
* @param data byte array
* @param uniqueIDOffset offset of unique ID
* @param filePathOffset offset of file path
* @param fileNameOffset offset of file name
* @param subprojectIndex index of the subproject, used to calculate unique id offset
* @return new SubProject instance
*/
private SubProject readSubProject(byte[] data, int uniqueIDOffset, int filePathOffset, int fileNameOffset, int subprojectIndex)
{
try
{
SubProject sp = new SubProject();
int type = SUBPROJECT_TASKUNIQUEID0;
if (uniqueIDOffset != -1)
{
int value = MPPUtility.getInt(data, uniqueIDOffset);
type = MPPUtility.getInt(data, uniqueIDOffset + 4);
switch (type)
{
case SUBPROJECT_TASKUNIQUEID0:
case SUBPROJECT_TASKUNIQUEID1:
case SUBPROJECT_TASKUNIQUEID2:
case SUBPROJECT_TASKUNIQUEID3:
case SUBPROJECT_TASKUNIQUEID4:
case SUBPROJECT_TASKUNIQUEID5:
case SUBPROJECT_TASKUNIQUEID6:
{
sp.setTaskUniqueID(Integer.valueOf(value));
m_taskSubProjects.put(sp.getTaskUniqueID(), sp);
break;
}
default:
{
if (value != 0)
{
sp.addExternalTaskUniqueID(Integer.valueOf(value));
m_taskSubProjects.put(Integer.valueOf(value), sp);
}
break;
}
}
// Now get the unique id offset for this subproject
value = 0x00800000 + ((subprojectIndex - 1) * 0x00400000);
sp.setUniqueIDOffset(Integer.valueOf(value));
}
if (type == SUBPROJECT_TASKUNIQUEID4)
{
sp.setFullPath(MPPUtility.getUnicodeString(data, filePathOffset));
}
else
{
//
// First block header
//
filePathOffset += 18;
//
// String size as a 4 byte int
//
filePathOffset += 4;
//
// Full DOS path
//
sp.setDosFullPath(MPPUtility.getString(data, filePathOffset));
filePathOffset += (sp.getDosFullPath().length() + 1);
//
// 24 byte block
//
filePathOffset += 24;
//
// 4 byte block size
//
int size = MPPUtility.getInt(data, filePathOffset);
filePathOffset += 4;
if (size == 0)
{
sp.setFullPath(sp.getDosFullPath());
}
else
{
//
// 4 byte unicode string size in bytes
//
size = MPPUtility.getInt(data, filePathOffset);
filePathOffset += 4;
//
// 2 byte data
//
filePathOffset += 2;
//
// Unicode string
//
sp.setFullPath(MPPUtility.getUnicodeString(data, filePathOffset, size));
//filePathOffset += size;
}
//
// Second block header
//
fileNameOffset += 18;
//
// String size as a 4 byte int
//
fileNameOffset += 4;
//
// DOS file name
//
sp.setDosFileName(MPPUtility.getString(data, fileNameOffset));
fileNameOffset += (sp.getDosFileName().length() + 1);
//
// 24 byte block
//
fileNameOffset += 24;
//
// 4 byte block size
//
size = MPPUtility.getInt(data, fileNameOffset);
fileNameOffset += 4;
if (size == 0)
{
sp.setFileName(sp.getDosFileName());
}
else
{
//
// 4 byte unicode string size in bytes
//
size = MPPUtility.getInt(data, fileNameOffset);
fileNameOffset += 4;
//
// 2 byte data
//
fileNameOffset += 2;
//
// Unicode string
//
sp.setFileName(MPPUtility.getUnicodeString(data, fileNameOffset, size));
//fileNameOffset += size;
}
}
//System.out.println(sp.toString());
// Add to the list of subprojects
m_file.getSubProjects().add(sp);
return (sp);
}
//
// Admit defeat at this point - we have probably stumbled
// upon a data format we don't understand, so we'll fail
// gracefully here. This will now be reported as a missing
// sub project error by end users of the library, rather
// than as an exception being thrown.
//
catch (ArrayIndexOutOfBoundsException ex)
{
return (null);
}
}
/**
* This method process the data held in the props file specific to the
* visual appearance of the project data.
*/
private void processViewPropertyData() throws IOException
{
Props12 props = new Props12(m_inputStreamFactory.getInstance(m_viewDir, "Props"));
byte[] data = props.getByteArray(Props.FONT_BASES);
if (data != null)
{
processBaseFonts(data);
}
ProjectProperties properties = m_file.getProjectProperties();
properties.setShowProjectSummaryTask(props.getBoolean(Props.SHOW_PROJECT_SUMMARY_TASK));
}
/**
* Create an index of base font numbers and their associated base
* font instances.
* @param data property data
*/
private void processBaseFonts(byte[] data)
{
int offset = 0;
int blockCount = MPPUtility.getShort(data, 0);
offset += 2;
int size;
String name;
for (int loop = 0; loop < blockCount; loop++)
{
/*unknownAttribute = MPPUtility.getShort(data, offset);*/
offset += 2;
size = MPPUtility.getShort(data, offset);
offset += 2;
name = MPPUtility.getUnicodeString(data, offset);
offset += 64;
if (name.length() != 0)
{
FontBase fontBase = new FontBase(Integer.valueOf(loop), name, size);
m_fontBases.put(fontBase.getIndex(), fontBase);
}
}
}
/**
* This method maps the task unique identifiers to their index number
* within the FixedData block.
*
* @param fieldMap field map
* @param taskFixedMeta Fixed meta data for this task
* @param taskFixedData Fixed data for this task
* @return Mapping between task identifiers and block position
*/
private TreeMap createTaskMap(FieldMap fieldMap, FixedMeta taskFixedMeta, FixedData taskFixedData)
{
TreeMap taskMap = new TreeMap();
int uniqueIdOffset = fieldMap.getFixedDataOffset(TaskField.UNIQUE_ID);
int itemCount = taskFixedMeta.getAdjustedItemCount();
int uniqueID;
Integer key;
//
// First three items are not tasks, so let's skip them
//
for (int loop = 3; loop < itemCount; loop++)
{
byte[] data = taskFixedData.getByteArrayValue(loop);
if (data != null)
{
byte[] metaData = taskFixedMeta.getByteArrayValue(loop);
//
// Check for the deleted task flag
//
int flags = MPPUtility.getInt(metaData, 0);
if ((flags & 0x02) != 0)
{
// Project stores the deleted tasks unique id's into the fixed data as well
// and at least in one case the deleted task was listed twice in the list
// the second time with data with it causing a phantom task to be shown.
// See CalendarErrorPhantomTasks.mpp
//
// So let's add the unique id for the deleted task into the map so we don't
// accidentally include the task later.
//
uniqueID = MPPUtility.getShort(data, TASK_UNIQUE_ID_FIXED_OFFSET); // Only a short stored for deleted tasks?
key = Integer.valueOf(uniqueID);
if (taskMap.containsKey(key) == false)
{
taskMap.put(key, null); // use null so we can easily ignore this later
}
}
else
{
//
// Do we have a null task?
//
if (data.length == NULL_TASK_BLOCK_SIZE)
{
uniqueID = MPPUtility.getInt(data, TASK_UNIQUE_ID_FIXED_OFFSET);
key = Integer.valueOf(uniqueID);
if (taskMap.containsKey(key) == false)
{
taskMap.put(key, Integer.valueOf(loop));
}
}
else
{
//
// We apply a heuristic here - if we have more than 75% of the data, we assume
// the task is valid.
//
int maxSize = fieldMap.getMaxFixedDataSize(0);
if (maxSize == 0 || ((data.length * 100) / maxSize) > 75)
{
uniqueID = MPPUtility.getInt(data, uniqueIdOffset);
key = Integer.valueOf(uniqueID);
if (taskMap.containsKey(key) == false)
{
taskMap.put(key, Integer.valueOf(loop));
}
}
}
}
}
}
return (taskMap);
}
/**
* This method maps the resource unique identifiers to their index number
* within the FixedData block.
*
* @param fieldMap field map
* @param rscFixedMeta resource fixed meta data
* @param rscFixedData resource fixed data
* @return map of resource IDs to resource data
*/
private TreeMap createResourceMap(FieldMap fieldMap, FixedMeta rscFixedMeta, FixedData rscFixedData)
{
TreeMap resourceMap = new TreeMap();
int itemCount = rscFixedMeta.getAdjustedItemCount();
for (int loop = 0; loop < itemCount; loop++)
{
byte[] data = rscFixedData.getByteArrayValue(loop);
if (data == null || data.length < fieldMap.getMaxFixedDataSize(0))
{
continue;
}
Integer uniqueID = Integer.valueOf(MPPUtility.getShort(data, 0));
if (resourceMap.containsKey(uniqueID) == false)
{
resourceMap.put(uniqueID, Integer.valueOf(loop));
}
}
return (resourceMap);
}
/**
* The format of the calendar data is a 4 byte header followed
* by 7x 60 byte blocks, one for each day of the week. Optionally
* following this is a set of 64 byte blocks representing exceptions
* to the calendar.
*/
private void processCalendarData() throws IOException
{
DirectoryEntry calDir = (DirectoryEntry) m_projectDir.getEntry("TBkndCal");
//MPPUtility.fileHexDump("c:\\temp\\varmeta.txt", new DocumentInputStream (((DocumentEntry)calDir.getEntry("VarMeta"))));
VarMeta calVarMeta = new VarMeta12(new DocumentInputStream(((DocumentEntry) calDir.getEntry("VarMeta"))));
Var2Data calVarData = new Var2Data(calVarMeta, new DocumentInputStream((DocumentEntry) calDir.getEntry("Var2Data")));
//System.out.println(calVarMeta);
//System.out.println(calVarData);
FixedMeta calFixedMeta = new FixedMeta(new DocumentInputStream(((DocumentEntry) calDir.getEntry("FixedMeta"))), 10);
FixedData calFixedData = new FixedData(calFixedMeta, m_inputStreamFactory.getInstance(calDir, "FixedData"), 12);
//System.out.println (calFixedMeta);
//System.out.println (calFixedData);
HashMap calendarMap = new HashMap();
int items = calFixedData.getItemCount();
List> baseCalendars = new LinkedList>();
byte[] defaultCalendarData = m_projectProps.getByteArray(Props.DEFAULT_CALENDAR_HOURS);
ProjectCalendar defaultCalendar = new ProjectCalendar(m_file);
processCalendarHours(defaultCalendarData, null, defaultCalendar, true);
for (int loop = 0; loop < items; loop++)
{
byte[] fixedData = calFixedData.getByteArrayValue(loop);
if (fixedData != null && fixedData.length >= 8)
{
int offset = 0;
//
// Bug 890909, here we ensure that we have a complete 12 byte
// block before attempting to process the data.
//
while (offset + 12 <= fixedData.length)
{
Integer calendarID = Integer.valueOf(MPPUtility.getInt(fixedData, offset + 0));
int baseCalendarID = MPPUtility.getInt(fixedData, offset + 4);
if (calendarID.intValue() > 0 && calendarMap.containsKey(calendarID) == false)
{
byte[] varData = calVarData.getByteArray(calendarID, CALENDAR_DATA);
ProjectCalendar cal;
if (baseCalendarID == 0 || baseCalendarID == -1 || baseCalendarID == calendarID.intValue())
{
if (varData != null || defaultCalendarData != null)
{
cal = m_file.addCalendar();
if (varData == null)
{
varData = defaultCalendarData;
}
}
else
{
cal = m_file.addDefaultBaseCalendar();
}
cal.setName(calVarData.getUnicodeString(calendarID, CALENDAR_NAME));
}
else
{
if (varData != null)
{
cal = m_file.addCalendar();
}
else
{
cal = m_file.addDefaultDerivedCalendar();
}
baseCalendars.add(new Pair(cal, Integer.valueOf(baseCalendarID)));
Integer resourceID = Integer.valueOf(MPPUtility.getInt(fixedData, offset + 8));
m_resourceMap.put(resourceID, cal);
}
cal.setUniqueID(calendarID);
if (varData != null)
{
processCalendarHours(varData, defaultCalendar, cal, baseCalendarID == -1);
processCalendarExceptions(varData, cal);
}
calendarMap.put(calendarID, cal);
m_eventManager.fireCalendarReadEvent(cal);
}
offset += 12;
}
}
}
updateBaseCalendarNames(baseCalendars, calendarMap);
}
/**
* For a given set of calendar data, this method sets the working
* day status for each day, and if present, sets the hours for that
* day.
*
* NOTE: MPP12 defines the concept of working weeks. MPXJ does not
* currently support this, and thus we only read the working hours
* for the default working week.
*
* @param data calendar data block
* @param defaultCalendar calendar to use for default values
* @param cal calendar instance
* @param isBaseCalendar true if this is a base calendar
*/
private void processCalendarHours(byte[] data, ProjectCalendar defaultCalendar, ProjectCalendar cal, boolean isBaseCalendar)
{
// Dump out the calendar related data and fields.
//MPPUtility.dataDump(data, true, false, false, false, true, false, true);
int offset;
ProjectCalendarHours hours;
int periodIndex;
int index;
int defaultFlag;
int periodCount;
Date start;
long duration;
Day day;
List dateRanges = new ArrayList(5);
for (index = 0; index < 7; index++)
{
offset = (60 * index);
defaultFlag = data == null ? 1 : MPPUtility.getShort(data, offset);
day = Day.getInstance(index + 1);
if (defaultFlag == 1)
{
if (isBaseCalendar)
{
if (defaultCalendar == null)
{
cal.setWorkingDay(day, DEFAULT_WORKING_WEEK[index]);
if (cal.isWorkingDay(day))
{
hours = cal.addCalendarHours(Day.getInstance(index + 1));
hours.addRange(ProjectCalendarWeek.DEFAULT_WORKING_MORNING);
hours.addRange(ProjectCalendarWeek.DEFAULT_WORKING_AFTERNOON);
}
}
else
{
boolean workingDay = defaultCalendar.isWorkingDay(day);
cal.setWorkingDay(day, workingDay);
if (workingDay)
{
hours = cal.addCalendarHours(Day.getInstance(index + 1));
for (DateRange range : defaultCalendar.getHours(day))
{
hours.addRange(range);
}
}
}
}
else
{
cal.setWorkingDay(day, DayType.DEFAULT);
}
}
else
{
dateRanges.clear();
periodIndex = 0;
periodCount = MPPUtility.getShort(data, offset + 2);
while (periodIndex < periodCount)
{
int startOffset = offset + 8 + (periodIndex * 2);
start = MPPUtility.getTime(data, startOffset);
int durationOffset = offset + 20 + (periodIndex * 4);
duration = MPPUtility.getDuration(data, durationOffset);
Date end = new Date(start.getTime() + duration);
dateRanges.add(new DateRange(start, end));
++periodIndex;
}
if (dateRanges.isEmpty())
{
cal.setWorkingDay(day, false);
}
else
{
cal.setWorkingDay(day, true);
hours = cal.addCalendarHours(Day.getInstance(index + 1));
for (DateRange range : dateRanges)
{
hours.addRange(range);
}
}
}
}
}
/**
* This method extracts any exceptions associated with a calendar.
*
* @param data calendar data block
* @param cal calendar instance
*/
private void processCalendarExceptions(byte[] data, ProjectCalendar cal)
{
//
// Handle any exceptions
//
if (data.length > 420)
{
int offset = 420; // The first 420 is for the working hours data
int exceptionCount = MPPUtility.getShort(data, offset);
if (exceptionCount != 0)
{
int index;
ProjectCalendarException exception;
long duration;
int periodCount;
Date start;
//
// Move to the start of the first exception
//
offset += 4;
//
// Each exception is a 92 byte block, followed by a
// variable length text block
//
for (index = 0; index < exceptionCount; index++)
{
Date fromDate = MPPUtility.getDate(data, offset);
Date toDate = MPPUtility.getDate(data, offset + 2);
exception = cal.addCalendarException(fromDate, toDate);
periodCount = MPPUtility.getShort(data, offset + 14);
if (periodCount != 0)
{
for (int exceptionPeriodIndex = 0; exceptionPeriodIndex < periodCount; exceptionPeriodIndex++)
{
start = MPPUtility.getTime(data, offset + 20 + (exceptionPeriodIndex * 2));
duration = MPPUtility.getDuration(data, offset + 32 + (exceptionPeriodIndex * 4));
exception.addRange(new DateRange(start, new Date(start.getTime() + duration)));
}
}
//
// Extract the name length - ensure that it is aligned to a 4 byte boundary
//
int exceptionNameLength = MPPUtility.getInt(data, offset + 88);
if (exceptionNameLength % 4 != 0)
{
exceptionNameLength = ((exceptionNameLength / 4) + 1) * 4;
}
//String exceptionName = MPPUtility.getUnicodeString(data, offset+92);
offset += (92 + exceptionNameLength);
}
}
}
}
/**
* The way calendars are stored in an MPP12 file means that there
* can be forward references between the base calendar unique ID for a
* derived calendar, and the base calendar itself. To get around this,
* we initially populate the base calendar name attribute with the
* base calendar unique ID, and now in this method we can convert those
* ID values into the correct names.
*
* @param baseCalendars list of calendars and base calendar IDs
* @param map map of calendar ID values and calendar objects
*/
private void updateBaseCalendarNames(List> baseCalendars, HashMap map)
{
for (Pair pair : baseCalendars)
{
ProjectCalendar cal = pair.getFirst();
Integer baseCalendarID = pair.getSecond();
ProjectCalendar baseCal = map.get(baseCalendarID);
if (baseCal != null && baseCal.getName() != null)
{
cal.setParent(baseCal);
}
else
{
// Remove invalid calendar to avoid serious problems later.
m_file.removeCalendar(cal);
}
}
}
/**
* This method extracts and collates task data. The code below
* goes through the modifier methods of the Task class in alphabetical
* order extracting the data from the MPP file. Where there is no
* mapping (e.g. the field is calculated on the fly, or we can't
* find it in the data) the line is commented out.
*
* The missing boolean attributes are probably represented in the Props
* section of the task data, which we have yet to decode.
*
* @throws java.io.IOException
*/
private void processTaskData() throws IOException
{
FieldMap fieldMap = new FieldMap12(m_file.getProjectProperties(), m_file.getCustomFields());
fieldMap.createTaskFieldMap(m_projectProps);
FieldMap enterpriseCustomFieldMap = new FieldMap12(m_file.getProjectProperties(), m_file.getCustomFields());
enterpriseCustomFieldMap.createEnterpriseCustomFieldMap(m_projectProps, TaskField.class);
DirectoryEntry taskDir = (DirectoryEntry) m_projectDir.getEntry("TBkndTask");
VarMeta taskVarMeta = new VarMeta12(new DocumentInputStream(((DocumentEntry) taskDir.getEntry("VarMeta"))));
Var2Data taskVarData = new Var2Data(taskVarMeta, new DocumentInputStream(((DocumentEntry) taskDir.getEntry("Var2Data"))));
FixedMeta taskFixedMeta = new FixedMeta(new DocumentInputStream(((DocumentEntry) taskDir.getEntry("FixedMeta"))), 47);
FixedData taskFixedData = new FixedData(taskFixedMeta, new DocumentInputStream(((DocumentEntry) taskDir.getEntry("FixedData"))), 768, fieldMap.getMaxFixedDataSize(0));
FixedMeta taskFixed2Meta = new FixedMeta(new DocumentInputStream(((DocumentEntry) taskDir.getEntry("Fixed2Meta"))), 86);
FixedData taskFixed2Data = new FixedData(taskFixed2Meta, new DocumentInputStream(((DocumentEntry) taskDir.getEntry("Fixed2Data"))));
Props12 props = new Props12(m_inputStreamFactory.getInstance(taskDir, "Props"));
//System.out.println(taskFixedMeta);
//System.out.println(taskFixedData);
//System.out.println(taskVarMeta);
//System.out.println(taskVarData);
//System.out.println(taskFixed2Meta);
//System.out.println(m_outlineCodeVarData.getVarMeta());
//System.out.println(m_outlineCodeVarData);
//System.out.println(props);
// Process aliases
new CustomFieldAliasReader(m_file.getCustomFields(), props.getByteArray(TASK_FIELD_NAME_ALIASES)).process();
TreeMap taskMap = createTaskMap(fieldMap, taskFixedMeta, taskFixedData);
// The var data may not contain all the tasks as tasks with no var data assigned will
// not be saved in there. Most notably these are tasks with no name. So use the task map
// which contains all the tasks.
Object[] uniqueIdArray = taskMap.keySet().toArray(); //taskVarMeta.getUniqueIdentifierArray();
Integer offset;
byte[] data;
byte[] metaData;
byte[] metaData2;
Task task;
boolean autoWBS = true;
LinkedList externalTasks = new LinkedList();
RecurringTaskReader recurringTaskReader = null;
String notes;
for (int loop = 0; loop < uniqueIdArray.length; loop++)
{
Integer uniqueID = (Integer) uniqueIdArray[loop];
offset = taskMap.get(uniqueID);
if (taskFixedData.isValidOffset(offset) == false)
{
continue;
}
data = taskFixedData.getByteArrayValue(offset.intValue());
Integer id = Integer.valueOf(MPPUtility.getInt(data, fieldMap.getFixedDataOffset(TaskField.ID)));
if (data.length == NULL_TASK_BLOCK_SIZE)
{
task = m_file.addTask();
task.setNull(true);
task.setUniqueID(Integer.valueOf(MPPUtility.getShort(data, TASK_UNIQUE_ID_FIXED_OFFSET)));
task.setID(Integer.valueOf(MPPUtility.getShort(data, TASK_ID_FIXED_OFFSET)));
m_nullTaskOrder.put(task.getID(), task.getUniqueID());
continue;
}
if (data.length < fieldMap.getMaxFixedDataSize(0))
{
if (uniqueID.intValue() == 0)
{
byte[] newData = new byte[fieldMap.getMaxFixedDataSize(0) + 8];
System.arraycopy(data, 0, newData, 0, data.length);
data = newData;
}
else
{
continue;
}
}
//System.out.println (id+": "+MPPUtility.hexdump(data, false, 16, ""));
metaData = taskFixedMeta.getByteArrayValue(offset.intValue());
//System.out.println (MPPUtility.hexdump(data, false, 16, ""));
//System.out.println (MPPUtility.hexdump(metaData, false, 16, ""));
//MPPUtility.dataDump(data, true, true, true, true, true, true, true);
//MPPUtility.dataDump(metaData, true, true, true, true, true, true, true);
//MPPUtility.varDataDump(taskVarData, id, true, true, true, true, true, true);
metaData2 = taskFixed2Meta.getByteArrayValue(offset.intValue());
byte[] data2 = taskFixed2Data.getByteArrayValue(offset.intValue());
//System.out.println (MPPUtility.hexdump(metaData2, false, 16, ""));
//System.out.println (MPPUtility.hexdump(data2, false, 16, ""));
byte[] recurringData = taskVarData.getByteArray(uniqueID, fieldMap.getVarDataKey(TaskField.RECURRING_DATA));
Task temp = m_file.getTaskByID(id);
if (temp != null)
{
// Task with this id already exists... determine if this is the 'real' task by seeing
// if this task has some var data. This is sort of hokey, but it's the best method i have
// been able to see.
if (!taskVarMeta.getUniqueIdentifierSet().contains(uniqueID))
{
// Sometimes Project contains phantom tasks that coexist on the same id as a valid
// task. In this case don't want to include the phantom task. Seems to be a very rare case.
continue;
}
else
if (temp.getName() == null)
{
// Ok, this looks valid. Remove the previous instance since it is most likely not a valid task.
// At worst case this removes a task with an empty name.
m_file.removeTask(temp);
}
}
task = m_file.addTask();
task.disableEvents();
fieldMap.populateContainer(TaskField.class, task, uniqueID, new byte[][]
{
data,
data2
}, taskVarData);
enterpriseCustomFieldMap.populateContainer(TaskField.class, task, uniqueID, null, taskVarData);
task.enableEvents();
task.setEffortDriven((metaData[11] & 0x10) != 0);
task.setEstimated(getDurationEstimated(MPPUtility.getShort(data, fieldMap.getFixedDataOffset(TaskField.ACTUAL_DURATION_UNITS))));
task.setExpanded(((metaData[12] & 0x02) == 0));
Integer externalTaskID = task.getSubprojectTaskID();
if (externalTaskID != null && externalTaskID.intValue() != 0)
{
task.setExternalTask(true);
externalTasks.add(task);
}
task.setFlag(1, (metaData[37] & 0x20) != 0);
task.setFlag(2, (metaData[37] & 0x40) != 0);
task.setFlag(3, (metaData[37] & 0x80) != 0);
task.setFlag(4, (metaData[38] & 0x01) != 0);
task.setFlag(5, (metaData[38] & 0x02) != 0);
task.setFlag(6, (metaData[38] & 0x04) != 0);
task.setFlag(7, (metaData[38] & 0x08) != 0);
task.setFlag(8, (metaData[38] & 0x10) != 0);
task.setFlag(9, (metaData[38] & 0x20) != 0);
task.setFlag(10, (metaData[38] & 0x40) != 0);
task.setFlag(11, (metaData[38] & 0x80) != 0);
task.setFlag(12, (metaData[39] & 0x01) != 0);
task.setFlag(13, (metaData[39] & 0x02) != 0);
task.setFlag(14, (metaData[39] & 0x04) != 0);
task.setFlag(15, (metaData[39] & 0x08) != 0);
task.setFlag(16, (metaData[39] & 0x10) != 0);
task.setFlag(17, (metaData[39] & 0x20) != 0);
task.setFlag(18, (metaData[39] & 0x40) != 0);
task.setFlag(19, (metaData[39] & 0x80) != 0);
task.setFlag(20, (metaData[40] & 0x01) != 0);
task.setHideBar((metaData[10] & 0x80) != 0);
processHyperlinkData(task, taskVarData.getByteArray(uniqueID, fieldMap.getVarDataKey(TaskField.HYPERLINK_DATA)));
task.setID(id);
task.setIgnoreResourceCalendar((metaData[10] & 0x02) != 0);
task.setLevelAssignments((metaData[13] & 0x04) != 0);
task.setLevelingCanSplit((metaData[13] & 0x02) != 0);
task.setMarked((metaData[9] & 0x40) != 0);
task.setMilestone((metaData[8] & 0x20) != 0);
task.setOutlineCode(1, getCustomFieldOutlineCodeValue(taskVarData, m_outlineCodeVarData, uniqueID, fieldMap.getVarDataKey(TaskField.OUTLINE_CODE1_INDEX)));
task.setOutlineCode(2, getCustomFieldOutlineCodeValue(taskVarData, m_outlineCodeVarData, uniqueID, fieldMap.getVarDataKey(TaskField.OUTLINE_CODE2_INDEX)));
task.setOutlineCode(3, getCustomFieldOutlineCodeValue(taskVarData, m_outlineCodeVarData, uniqueID, fieldMap.getVarDataKey(TaskField.OUTLINE_CODE3_INDEX)));
task.setOutlineCode(4, getCustomFieldOutlineCodeValue(taskVarData, m_outlineCodeVarData, uniqueID, fieldMap.getVarDataKey(TaskField.OUTLINE_CODE4_INDEX)));
task.setOutlineCode(5, getCustomFieldOutlineCodeValue(taskVarData, m_outlineCodeVarData, uniqueID, fieldMap.getVarDataKey(TaskField.OUTLINE_CODE5_INDEX)));
task.setOutlineCode(6, getCustomFieldOutlineCodeValue(taskVarData, m_outlineCodeVarData, uniqueID, fieldMap.getVarDataKey(TaskField.OUTLINE_CODE6_INDEX)));
task.setOutlineCode(7, getCustomFieldOutlineCodeValue(taskVarData, m_outlineCodeVarData, uniqueID, fieldMap.getVarDataKey(TaskField.OUTLINE_CODE7_INDEX)));
task.setOutlineCode(8, getCustomFieldOutlineCodeValue(taskVarData, m_outlineCodeVarData, uniqueID, fieldMap.getVarDataKey(TaskField.OUTLINE_CODE8_INDEX)));
task.setOutlineCode(9, getCustomFieldOutlineCodeValue(taskVarData, m_outlineCodeVarData, uniqueID, fieldMap.getVarDataKey(TaskField.OUTLINE_CODE9_INDEX)));
task.setOutlineCode(10, getCustomFieldOutlineCodeValue(taskVarData, m_outlineCodeVarData, uniqueID, fieldMap.getVarDataKey(TaskField.OUTLINE_CODE10_INDEX)));
task.setRollup((metaData[10] & 0x08) != 0);
task.setUniqueID(uniqueID);
switch (task.getConstraintType())
{
//
// Adjust the start and finish dates if the task
// is constrained to start as late as possible.
//
case AS_LATE_AS_POSSIBLE:
{
if (DateHelper.compare(task.getStart(), task.getLateStart()) < 0)
{
task.setStart(task.getLateStart());
}
if (DateHelper.compare(task.getFinish(), task.getLateFinish()) < 0)
{
task.setFinish(task.getLateFinish());
}
break;
}
case START_NO_LATER_THAN:
case FINISH_NO_LATER_THAN:
{
if (DateHelper.compare(task.getFinish(), task.getStart()) < 0)
{
task.setFinish(task.getLateFinish());
}
break;
}
default:
{
break;
}
}
//
// Retrieve task recurring data
//
if (recurringData != null)
{
if (recurringTaskReader == null)
{
recurringTaskReader = new RecurringTaskReader(m_file.getProjectProperties());
}
recurringTaskReader.processRecurringTask(task, recurringData);
task.setRecurring(true);
}
//
// Retrieve the task notes.
//
notes = task.getNotes();
if (notes != null)
{
if (m_reader.getPreserveNoteFormatting() == false)
{
notes = RtfHelper.strip(notes);
}
task.setNotes(notes);
}
//
// Set the calendar name
//
Integer calendarID = (Integer) task.getCachedValue(TaskField.CALENDAR_UNIQUE_ID);
if (calendarID != null && calendarID.intValue() != -1)
{
ProjectCalendar calendar = m_file.getCalendarByUniqueID(calendarID);
if (calendar != null)
{
task.setCalendar(calendar);
}
}
//
// Set the sub project flag
//
SubProject sp = m_taskSubProjects.get(task.getUniqueID());
task.setSubProject(sp);
//
// Set the external flag
//
if (sp != null)
{
task.setExternalTask(sp.isExternalTask(task.getUniqueID()));
if (task.getExternalTask())
{
task.setExternalTaskProject(sp.getFullPath());
}
}
//
// If we have a WBS value from the MPP file, don't autogenerate
//
if (task.getWBS() != null)
{
autoWBS = false;
}
//
// If this is a split task, allocate space for the split durations
//
if ((metaData[9] & 0x80) == 0)
{
task.setSplits(new LinkedList());
}
//
// Process any enterprise columns
//
processTaskEnterpriseColumns(uniqueID, task, taskVarData, metaData2);
// Unfortunately it looks like 'null' tasks sometimes make it through. So let's check for to see if we
// need to mark this task as a null task after all.
if (task.getName() == null && ((task.getStart() == null || task.getStart().getTime() == MPPUtility.getEpochDate().getTime()) || (task.getFinish() == null || task.getFinish().getTime() == MPPUtility.getEpochDate().getTime()) /*|| (task.getCreateDate() == null || task.getCreateDate().getTime() == MPPUtility.getEpochDate().getTime())*//* Valid tasks can have a null create date */))
{
// Remove this to avoid passing bad data to the client
m_file.removeTask(task);
task = m_file.addTask();
task.setNull(true);
task.setUniqueID(uniqueID);
task.setID(id);
m_nullTaskOrder.put(task.getID(), task.getUniqueID());
//System.out.println(task);
continue;
}
if (data2 == null || data2.length < 24)
{
m_nullTaskOrder.put(task.getID(), task.getUniqueID());
}
else
{
Long key = Long.valueOf(MPPUtility.getLong(data2, 16));
m_taskOrder.put(key, task.getUniqueID());
}
m_eventManager.fireTaskReadEvent(task);
//dumpUnknownData(task.getUniqueID().toString(), UNKNOWN_TASK_DATA, data);
//System.out.println(task);
}
//
// Enable auto WBS if necessary
//
m_file.getProjectConfig().setAutoWBS(autoWBS);
//
// We have now read all of the task, so we are in a position
// to perform post-processing to set up the relevant details
// for each external task.
//
if (!externalTasks.isEmpty())
{
processExternalTasks(externalTasks);
}
}
/**
* MPP14 files seem to exhibit some occasional weirdness
* with duplicate ID values which leads to the task structure
* being reported incorrectly. The following method attempts to correct this.
* The method uses ordering data embedded in the file to reconstruct
* the correct ID order of the tasks.
*/
private void postProcessTasks() throws MPXJException
{
//
// Renumber ID values using a large increment to allow
// space for later inserts.
//
TreeMap taskMap = new TreeMap();
int nextIDIncrement = 1000;
int nextID = (m_file.getTaskByUniqueID(Integer.valueOf(0)) == null ? nextIDIncrement : 0);
for (Map.Entry entry : m_taskOrder.entrySet())
{
taskMap.put(Integer.valueOf(nextID), entry.getValue());
nextID += nextIDIncrement;
}
//
// Insert any null tasks into the correct location
//
int insertionCount = 0;
for (Map.Entry entry : m_nullTaskOrder.entrySet())
{
int idValue = entry.getKey().intValue();
int baseTargetIdValue = (idValue - insertionCount) * nextIDIncrement;
int targetIDValue = baseTargetIdValue;
int offset = 0;
++insertionCount;
while (taskMap.containsKey(Integer.valueOf(targetIDValue)))
{
++offset;
if (offset == nextIDIncrement)
{
throw new MPXJException("Unable to fix task order");
}
targetIDValue = baseTargetIdValue - (nextIDIncrement - offset);
}
taskMap.put(Integer.valueOf(targetIDValue), entry.getValue());
}
//
// Finally, we can renumber the tasks
//
nextID = (m_file.getTaskByUniqueID(Integer.valueOf(0)) == null ? 1 : 0);
for (Map.Entry entry : taskMap.entrySet())
{
Task task = m_file.getTaskByUniqueID(entry.getValue());
if (task != null)
{
task.setID(Integer.valueOf(nextID));
}
nextID++;
}
}
/**
* Extracts task enterprise column values.
*
* @param id task unique ID
* @param task task instance
* @param taskVarData task var data
* @param metaData2 task meta data
*/
private void processTaskEnterpriseColumns(Integer id, Task task, Var2Data taskVarData, byte[] metaData2)
{
// task.setEnterpriseCost(1, NumberUtility.getDouble(taskVarData.getDouble(id, TASK_ENTERPRISE_COST1) / 100));
// task.setEnterpriseCost(2, NumberUtility.getDouble(taskVarData.getDouble(id, TASK_ENTERPRISE_COST2) / 100));
// task.setEnterpriseCost(3, NumberUtility.getDouble(taskVarData.getDouble(id, TASK_ENTERPRISE_COST3) / 100));
// task.setEnterpriseCost(4, NumberUtility.getDouble(taskVarData.getDouble(id, TASK_ENTERPRISE_COST4) / 100));
// task.setEnterpriseCost(5, NumberUtility.getDouble(taskVarData.getDouble(id, TASK_ENTERPRISE_COST5) / 100));
// task.setEnterpriseCost(6, NumberUtility.getDouble(taskVarData.getDouble(id, TASK_ENTERPRISE_COST6) / 100));
// task.setEnterpriseCost(7, NumberUtility.getDouble(taskVarData.getDouble(id, TASK_ENTERPRISE_COST7) / 100));
// task.setEnterpriseCost(8, NumberUtility.getDouble(taskVarData.getDouble(id, TASK_ENTERPRISE_COST8) / 100));
// task.setEnterpriseCost(9, NumberUtility.getDouble(taskVarData.getDouble(id, TASK_ENTERPRISE_COST9) / 100));
// task.setEnterpriseCost(10, NumberUtility.getDouble(taskVarData.getDouble(id, TASK_ENTERPRISE_COST10) / 100));
// task.setEnterpriseDate(1, taskVarData.getTimestamp(id, TASK_ENTERPRISE_DATE1));
// task.setEnterpriseDate(2, taskVarData.getTimestamp(id, TASK_ENTERPRISE_DATE2));
// task.setEnterpriseDate(3, taskVarData.getTimestamp(id, TASK_ENTERPRISE_DATE3));
// task.setEnterpriseDate(4, taskVarData.getTimestamp(id, TASK_ENTERPRISE_DATE4));
// task.setEnterpriseDate(5, taskVarData.getTimestamp(id, TASK_ENTERPRISE_DATE5));
// task.setEnterpriseDate(6, taskVarData.getTimestamp(id, TASK_ENTERPRISE_DATE6));
// task.setEnterpriseDate(7, taskVarData.getTimestamp(id, TASK_ENTERPRISE_DATE7));
// task.setEnterpriseDate(8, taskVarData.getTimestamp(id, TASK_ENTERPRISE_DATE8));
// task.setEnterpriseDate(9, taskVarData.getTimestamp(id, TASK_ENTERPRISE_DATE9));
// task.setEnterpriseDate(10, taskVarData.getTimestamp(id, TASK_ENTERPRISE_DATE10));
// task.setEnterpriseDate(11, taskVarData.getTimestamp(id, TASK_ENTERPRISE_DATE11));
// task.setEnterpriseDate(12, taskVarData.getTimestamp(id, TASK_ENTERPRISE_DATE12));
// task.setEnterpriseDate(13, taskVarData.getTimestamp(id, TASK_ENTERPRISE_DATE13));
// task.setEnterpriseDate(14, taskVarData.getTimestamp(id, TASK_ENTERPRISE_DATE14));
// task.setEnterpriseDate(15, taskVarData.getTimestamp(id, TASK_ENTERPRISE_DATE15));
// task.setEnterpriseDate(16, taskVarData.getTimestamp(id, TASK_ENTERPRISE_DATE16));
// task.setEnterpriseDate(17, taskVarData.getTimestamp(id, TASK_ENTERPRISE_DATE17));
// task.setEnterpriseDate(18, taskVarData.getTimestamp(id, TASK_ENTERPRISE_DATE18));
// task.setEnterpriseDate(19, taskVarData.getTimestamp(id, TASK_ENTERPRISE_DATE19));
// task.setEnterpriseDate(20, taskVarData.getTimestamp(id, TASK_ENTERPRISE_DATE20));
// task.setEnterpriseDate(21, taskVarData.getTimestamp(id, TASK_ENTERPRISE_DATE21));
// task.setEnterpriseDate(22, taskVarData.getTimestamp(id, TASK_ENTERPRISE_DATE22));
// task.setEnterpriseDate(23, taskVarData.getTimestamp(id, TASK_ENTERPRISE_DATE23));
// task.setEnterpriseDate(24, taskVarData.getTimestamp(id, TASK_ENTERPRISE_DATE24));
// task.setEnterpriseDate(25, taskVarData.getTimestamp(id, TASK_ENTERPRISE_DATE25));
// task.setEnterpriseDate(26, taskVarData.getTimestamp(id, TASK_ENTERPRISE_DATE26));
// task.setEnterpriseDate(27, taskVarData.getTimestamp(id, TASK_ENTERPRISE_DATE27));
// task.setEnterpriseDate(28, taskVarData.getTimestamp(id, TASK_ENTERPRISE_DATE28));
// task.setEnterpriseDate(29, taskVarData.getTimestamp(id, TASK_ENTERPRISE_DATE29));
// task.setEnterpriseDate(30, taskVarData.getTimestamp(id, TASK_ENTERPRISE_DATE30));
// task.setEnterpriseDuration(1, MPPUtility.getAdjustedDuration(m_file, taskVarData.getInt(id, TASK_ENTERPRISE_DURATION1), MPPUtility.getDurationTimeUnits(taskVarData.getShort(id, TASK_ENTERPRISE_DURATION1_UNITS))));
// task.setEnterpriseDuration(2, MPPUtility.getAdjustedDuration(m_file, taskVarData.getInt(id, TASK_ENTERPRISE_DURATION2), MPPUtility.getDurationTimeUnits(taskVarData.getShort(id, TASK_ENTERPRISE_DURATION2_UNITS))));
// task.setEnterpriseDuration(3, MPPUtility.getAdjustedDuration(m_file, taskVarData.getInt(id, TASK_ENTERPRISE_DURATION3), MPPUtility.getDurationTimeUnits(taskVarData.getShort(id, TASK_ENTERPRISE_DURATION3_UNITS))));
// task.setEnterpriseDuration(4, MPPUtility.getAdjustedDuration(m_file, taskVarData.getInt(id, TASK_ENTERPRISE_DURATION4), MPPUtility.getDurationTimeUnits(taskVarData.getShort(id, TASK_ENTERPRISE_DURATION4_UNITS))));
// task.setEnterpriseDuration(5, MPPUtility.getAdjustedDuration(m_file, taskVarData.getInt(id, TASK_ENTERPRISE_DURATION5), MPPUtility.getDurationTimeUnits(taskVarData.getShort(id, TASK_ENTERPRISE_DURATION5_UNITS))));
// task.setEnterpriseDuration(6, MPPUtility.getAdjustedDuration(m_file, taskVarData.getInt(id, TASK_ENTERPRISE_DURATION6), MPPUtility.getDurationTimeUnits(taskVarData.getShort(id, TASK_ENTERPRISE_DURATION6_UNITS))));
// task.setEnterpriseDuration(7, MPPUtility.getAdjustedDuration(m_file, taskVarData.getInt(id, TASK_ENTERPRISE_DURATION7), MPPUtility.getDurationTimeUnits(taskVarData.getShort(id, TASK_ENTERPRISE_DURATION7_UNITS))));
// task.setEnterpriseDuration(8, MPPUtility.getAdjustedDuration(m_file, taskVarData.getInt(id, TASK_ENTERPRISE_DURATION8), MPPUtility.getDurationTimeUnits(taskVarData.getShort(id, TASK_ENTERPRISE_DURATION8_UNITS))));
// task.setEnterpriseDuration(9, MPPUtility.getAdjustedDuration(m_file, taskVarData.getInt(id, TASK_ENTERPRISE_DURATION9), MPPUtility.getDurationTimeUnits(taskVarData.getShort(id, TASK_ENTERPRISE_DURATION9_UNITS))));
// task.setEnterpriseDuration(10, MPPUtility.getAdjustedDuration(m_file, taskVarData.getInt(id, TASK_ENTERPRISE_DURATION10), MPPUtility.getDurationTimeUnits(taskVarData.getShort(id, TASK_ENTERPRISE_DURATION10_UNITS))));
// task.setEnterpriseNumber(1, NumberUtility.getDouble(taskVarData.getDouble(id, TASK_ENTERPRISE_NUMBER1)));
// task.setEnterpriseNumber(2, NumberUtility.getDouble(taskVarData.getDouble(id, TASK_ENTERPRISE_NUMBER2)));
// task.setEnterpriseNumber(3, NumberUtility.getDouble(taskVarData.getDouble(id, TASK_ENTERPRISE_NUMBER3)));
// task.setEnterpriseNumber(4, NumberUtility.getDouble(taskVarData.getDouble(id, TASK_ENTERPRISE_NUMBER4)));
// task.setEnterpriseNumber(5, NumberUtility.getDouble(taskVarData.getDouble(id, TASK_ENTERPRISE_NUMBER5)));
// task.setEnterpriseNumber(6, NumberUtility.getDouble(taskVarData.getDouble(id, TASK_ENTERPRISE_NUMBER6)));
// task.setEnterpriseNumber(7, NumberUtility.getDouble(taskVarData.getDouble(id, TASK_ENTERPRISE_NUMBER7)));
// task.setEnterpriseNumber(8, NumberUtility.getDouble(taskVarData.getDouble(id, TASK_ENTERPRISE_NUMBER8)));
// task.setEnterpriseNumber(9, NumberUtility.getDouble(taskVarData.getDouble(id, TASK_ENTERPRISE_NUMBER9)));
// task.setEnterpriseNumber(10, NumberUtility.getDouble(taskVarData.getDouble(id, TASK_ENTERPRISE_NUMBER10)));
// task.setEnterpriseNumber(11, NumberUtility.getDouble(taskVarData.getDouble(id, TASK_ENTERPRISE_NUMBER11)));
// task.setEnterpriseNumber(12, NumberUtility.getDouble(taskVarData.getDouble(id, TASK_ENTERPRISE_NUMBER12)));
// task.setEnterpriseNumber(13, NumberUtility.getDouble(taskVarData.getDouble(id, TASK_ENTERPRISE_NUMBER13)));
// task.setEnterpriseNumber(14, NumberUtility.getDouble(taskVarData.getDouble(id, TASK_ENTERPRISE_NUMBER14)));
// task.setEnterpriseNumber(15, NumberUtility.getDouble(taskVarData.getDouble(id, TASK_ENTERPRISE_NUMBER15)));
// task.setEnterpriseNumber(16, NumberUtility.getDouble(taskVarData.getDouble(id, TASK_ENTERPRISE_NUMBER16)));
// task.setEnterpriseNumber(17, NumberUtility.getDouble(taskVarData.getDouble(id, TASK_ENTERPRISE_NUMBER17)));
// task.setEnterpriseNumber(18, NumberUtility.getDouble(taskVarData.getDouble(id, TASK_ENTERPRISE_NUMBER18)));
// task.setEnterpriseNumber(19, NumberUtility.getDouble(taskVarData.getDouble(id, TASK_ENTERPRISE_NUMBER19)));
// task.setEnterpriseNumber(20, NumberUtility.getDouble(taskVarData.getDouble(id, TASK_ENTERPRISE_NUMBER20)));
// task.setEnterpriseNumber(21, NumberUtility.getDouble(taskVarData.getDouble(id, TASK_ENTERPRISE_NUMBER21)));
// task.setEnterpriseNumber(22, NumberUtility.getDouble(taskVarData.getDouble(id, TASK_ENTERPRISE_NUMBER22)));
// task.setEnterpriseNumber(23, NumberUtility.getDouble(taskVarData.getDouble(id, TASK_ENTERPRISE_NUMBER23)));
// task.setEnterpriseNumber(24, NumberUtility.getDouble(taskVarData.getDouble(id, TASK_ENTERPRISE_NUMBER24)));
// task.setEnterpriseNumber(25, NumberUtility.getDouble(taskVarData.getDouble(id, TASK_ENTERPRISE_NUMBER25)));
// task.setEnterpriseNumber(26, NumberUtility.getDouble(taskVarData.getDouble(id, TASK_ENTERPRISE_NUMBER26)));
// task.setEnterpriseNumber(27, NumberUtility.getDouble(taskVarData.getDouble(id, TASK_ENTERPRISE_NUMBER27)));
// task.setEnterpriseNumber(28, NumberUtility.getDouble(taskVarData.getDouble(id, TASK_ENTERPRISE_NUMBER28)));
// task.setEnterpriseNumber(29, NumberUtility.getDouble(taskVarData.getDouble(id, TASK_ENTERPRISE_NUMBER29)));
// task.setEnterpriseNumber(30, NumberUtility.getDouble(taskVarData.getDouble(id, TASK_ENTERPRISE_NUMBER30)));
// task.setEnterpriseNumber(31, NumberUtility.getDouble(taskVarData.getDouble(id, TASK_ENTERPRISE_NUMBER31)));
// task.setEnterpriseNumber(32, NumberUtility.getDouble(taskVarData.getDouble(id, TASK_ENTERPRISE_NUMBER32)));
// task.setEnterpriseNumber(33, NumberUtility.getDouble(taskVarData.getDouble(id, TASK_ENTERPRISE_NUMBER33)));
// task.setEnterpriseNumber(34, NumberUtility.getDouble(taskVarData.getDouble(id, TASK_ENTERPRISE_NUMBER34)));
// task.setEnterpriseNumber(35, NumberUtility.getDouble(taskVarData.getDouble(id, TASK_ENTERPRISE_NUMBER35)));
// task.setEnterpriseNumber(36, NumberUtility.getDouble(taskVarData.getDouble(id, TASK_ENTERPRISE_NUMBER36)));
// task.setEnterpriseNumber(37, NumberUtility.getDouble(taskVarData.getDouble(id, TASK_ENTERPRISE_NUMBER37)));
// task.setEnterpriseNumber(38, NumberUtility.getDouble(taskVarData.getDouble(id, TASK_ENTERPRISE_NUMBER38)));
// task.setEnterpriseNumber(39, NumberUtility.getDouble(taskVarData.getDouble(id, TASK_ENTERPRISE_NUMBER39)));
// task.setEnterpriseNumber(40, NumberUtility.getDouble(taskVarData.getDouble(id, TASK_ENTERPRISE_NUMBER40)));
// task.setEnterpriseText(1, taskVarData.getUnicodeString(id, TASK_ENTERPRISE_TEXT1));
// task.setEnterpriseText(2, taskVarData.getUnicodeString(id, TASK_ENTERPRISE_TEXT2));
// task.setEnterpriseText(3, taskVarData.getUnicodeString(id, TASK_ENTERPRISE_TEXT3));
// task.setEnterpriseText(4, taskVarData.getUnicodeString(id, TASK_ENTERPRISE_TEXT4));
// task.setEnterpriseText(5, taskVarData.getUnicodeString(id, TASK_ENTERPRISE_TEXT5));
// task.setEnterpriseText(6, taskVarData.getUnicodeString(id, TASK_ENTERPRISE_TEXT6));
// task.setEnterpriseText(7, taskVarData.getUnicodeString(id, TASK_ENTERPRISE_TEXT7));
// task.setEnterpriseText(8, taskVarData.getUnicodeString(id, TASK_ENTERPRISE_TEXT8));
// task.setEnterpriseText(9, taskVarData.getUnicodeString(id, TASK_ENTERPRISE_TEXT9));
// task.setEnterpriseText(10, taskVarData.getUnicodeString(id, TASK_ENTERPRISE_TEXT10));
// task.setEnterpriseText(11, taskVarData.getUnicodeString(id, TASK_ENTERPRISE_TEXT11));
// task.setEnterpriseText(12, taskVarData.getUnicodeString(id, TASK_ENTERPRISE_TEXT12));
// task.setEnterpriseText(13, taskVarData.getUnicodeString(id, TASK_ENTERPRISE_TEXT13));
// task.setEnterpriseText(14, taskVarData.getUnicodeString(id, TASK_ENTERPRISE_TEXT14));
// task.setEnterpriseText(15, taskVarData.getUnicodeString(id, TASK_ENTERPRISE_TEXT15));
// task.setEnterpriseText(16, taskVarData.getUnicodeString(id, TASK_ENTERPRISE_TEXT16));
// task.setEnterpriseText(17, taskVarData.getUnicodeString(id, TASK_ENTERPRISE_TEXT17));
// task.setEnterpriseText(18, taskVarData.getUnicodeString(id, TASK_ENTERPRISE_TEXT18));
// task.setEnterpriseText(19, taskVarData.getUnicodeString(id, TASK_ENTERPRISE_TEXT19));
// task.setEnterpriseText(20, taskVarData.getUnicodeString(id, TASK_ENTERPRISE_TEXT20));
// task.setEnterpriseText(21, taskVarData.getUnicodeString(id, TASK_ENTERPRISE_TEXT21));
// task.setEnterpriseText(22, taskVarData.getUnicodeString(id, TASK_ENTERPRISE_TEXT22));
// task.setEnterpriseText(23, taskVarData.getUnicodeString(id, TASK_ENTERPRISE_TEXT23));
// task.setEnterpriseText(24, taskVarData.getUnicodeString(id, TASK_ENTERPRISE_TEXT24));
// task.setEnterpriseText(25, taskVarData.getUnicodeString(id, TASK_ENTERPRISE_TEXT25));
// task.setEnterpriseText(26, taskVarData.getUnicodeString(id, TASK_ENTERPRISE_TEXT26));
// task.setEnterpriseText(27, taskVarData.getUnicodeString(id, TASK_ENTERPRISE_TEXT27));
// task.setEnterpriseText(28, taskVarData.getUnicodeString(id, TASK_ENTERPRISE_TEXT28));
// task.setEnterpriseText(29, taskVarData.getUnicodeString(id, TASK_ENTERPRISE_TEXT29));
// task.setEnterpriseText(30, taskVarData.getUnicodeString(id, TASK_ENTERPRISE_TEXT30));
// task.setEnterpriseText(31, taskVarData.getUnicodeString(id, TASK_ENTERPRISE_TEXT31));
// task.setEnterpriseText(32, taskVarData.getUnicodeString(id, TASK_ENTERPRISE_TEXT32));
// task.setEnterpriseText(33, taskVarData.getUnicodeString(id, TASK_ENTERPRISE_TEXT33));
// task.setEnterpriseText(34, taskVarData.getUnicodeString(id, TASK_ENTERPRISE_TEXT34));
// task.setEnterpriseText(35, taskVarData.getUnicodeString(id, TASK_ENTERPRISE_TEXT35));
// task.setEnterpriseText(36, taskVarData.getUnicodeString(id, TASK_ENTERPRISE_TEXT36));
// task.setEnterpriseText(37, taskVarData.getUnicodeString(id, TASK_ENTERPRISE_TEXT37));
// task.setEnterpriseText(38, taskVarData.getUnicodeString(id, TASK_ENTERPRISE_TEXT38));
// task.setEnterpriseText(39, taskVarData.getUnicodeString(id, TASK_ENTERPRISE_TEXT39));
// task.setEnterpriseText(40, taskVarData.getUnicodeString(id, TASK_ENTERPRISE_TEXT40));
if (metaData2 != null)
{
int bits = MPPUtility.getInt(metaData2, 59);
task.set(TaskField.ENTERPRISE_FLAG1, Boolean.valueOf((bits & 0x00001) != 0));
task.set(TaskField.ENTERPRISE_FLAG2, Boolean.valueOf((bits & 0x00002) != 0));
task.set(TaskField.ENTERPRISE_FLAG3, Boolean.valueOf((bits & 0x00004) != 0));
task.set(TaskField.ENTERPRISE_FLAG4, Boolean.valueOf((bits & 0x00008) != 0));
task.set(TaskField.ENTERPRISE_FLAG5, Boolean.valueOf((bits & 0x00010) != 0));
task.set(TaskField.ENTERPRISE_FLAG6, Boolean.valueOf((bits & 0x00020) != 0));
task.set(TaskField.ENTERPRISE_FLAG7, Boolean.valueOf((bits & 0x00040) != 0));
task.set(TaskField.ENTERPRISE_FLAG8, Boolean.valueOf((bits & 0x00080) != 0));
task.set(TaskField.ENTERPRISE_FLAG9, Boolean.valueOf((bits & 0x00100) != 0));
task.set(TaskField.ENTERPRISE_FLAG10, Boolean.valueOf((bits & 0x00200) != 0));
task.set(TaskField.ENTERPRISE_FLAG11, Boolean.valueOf((bits & 0x00400) != 0));
task.set(TaskField.ENTERPRISE_FLAG12, Boolean.valueOf((bits & 0x00800) != 0));
task.set(TaskField.ENTERPRISE_FLAG13, Boolean.valueOf((bits & 0x01000) != 0));
task.set(TaskField.ENTERPRISE_FLAG14, Boolean.valueOf((bits & 0x02000) != 0));
task.set(TaskField.ENTERPRISE_FLAG15, Boolean.valueOf((bits & 0x04000) != 0));
task.set(TaskField.ENTERPRISE_FLAG16, Boolean.valueOf((bits & 0x08000) != 0));
task.set(TaskField.ENTERPRISE_FLAG17, Boolean.valueOf((bits & 0x10000) != 0));
task.set(TaskField.ENTERPRISE_FLAG18, Boolean.valueOf((bits & 0x20000) != 0));
task.set(TaskField.ENTERPRISE_FLAG19, Boolean.valueOf((bits & 0x40000) != 0));
task.set(TaskField.ENTERPRISE_FLAG20, Boolean.valueOf((bits & 0x80000) != 0));
}
}
/**
* Extracts resource enterprise column data.
*
* @param resource resource instance
* @param metaData2 resource meta data
*/
private void processResourceEnterpriseColumns(Resource resource, byte[] metaData2)
{
if (metaData2 != null)
{
int bits = MPPUtility.getInt(metaData2, 16);
resource.set(ResourceField.ENTERPRISE_FLAG1, Boolean.valueOf((bits & 0x00010) != 0));
resource.set(ResourceField.ENTERPRISE_FLAG2, Boolean.valueOf((bits & 0x00020) != 0));
resource.set(ResourceField.ENTERPRISE_FLAG3, Boolean.valueOf((bits & 0x00040) != 0));
resource.set(ResourceField.ENTERPRISE_FLAG4, Boolean.valueOf((bits & 0x00080) != 0));
resource.set(ResourceField.ENTERPRISE_FLAG5, Boolean.valueOf((bits & 0x00100) != 0));
resource.set(ResourceField.ENTERPRISE_FLAG6, Boolean.valueOf((bits & 0x00200) != 0));
resource.set(ResourceField.ENTERPRISE_FLAG7, Boolean.valueOf((bits & 0x00400) != 0));
resource.set(ResourceField.ENTERPRISE_FLAG8, Boolean.valueOf((bits & 0x00800) != 0));
resource.set(ResourceField.ENTERPRISE_FLAG9, Boolean.valueOf((bits & 0x01000) != 0));
resource.set(ResourceField.ENTERPRISE_FLAG10, Boolean.valueOf((bits & 0x02000) != 0));
resource.set(ResourceField.ENTERPRISE_FLAG11, Boolean.valueOf((bits & 0x04000) != 0));
resource.set(ResourceField.ENTERPRISE_FLAG12, Boolean.valueOf((bits & 0x08000) != 0));
resource.set(ResourceField.ENTERPRISE_FLAG13, Boolean.valueOf((bits & 0x10000) != 0));
resource.set(ResourceField.ENTERPRISE_FLAG14, Boolean.valueOf((bits & 0x20000) != 0));
resource.set(ResourceField.ENTERPRISE_FLAG15, Boolean.valueOf((bits & 0x40000) != 0));
resource.set(ResourceField.ENTERPRISE_FLAG16, Boolean.valueOf((bits & 0x80000) != 0));
resource.set(ResourceField.ENTERPRISE_FLAG17, Boolean.valueOf((bits & 0x100000) != 0));
resource.set(ResourceField.ENTERPRISE_FLAG18, Boolean.valueOf((bits & 0x200000) != 0));
resource.set(ResourceField.ENTERPRISE_FLAG19, Boolean.valueOf((bits & 0x400000) != 0));
resource.set(ResourceField.ENTERPRISE_FLAG20, Boolean.valueOf((bits & 0x800000) != 0));
}
}
/**
* The project files to which external tasks relate appear not to be
* held against each task, instead there appears to be the concept
* of the "current" external task file, i.e. the last one used.
* This method iterates through the list of tasks marked as external
* and attempts to ensure that the correct external project data (in the
* form of a SubProject object) is linked to the task.
*
* @param externalTasks list of tasks marked as external
*/
private void processExternalTasks(List externalTasks)
{
//
// Sort the list of tasks into ID order
//
Collections.sort(externalTasks);
//
// Find any external tasks which don't have a sub project
// object, and set this attribute using the most recent
// value.
//
SubProject currentSubProject = null;
for (Task currentTask : externalTasks)
{
SubProject sp = currentTask.getSubProject();
if (sp == null)
{
currentTask.setSubProject(currentSubProject);
//we need to set the external task project path now that we have
//the subproject for this task (was skipped while processing the task earlier)
if (currentSubProject != null)
{
currentTask.setExternalTaskProject(currentSubProject.getFullPath());
}
}
else
{
currentSubProject = sp;
}
if (currentSubProject != null)
{
//System.out.println ("Task: " +currentTask.getUniqueID() + " " + currentTask.getName() + " File=" + currentSubProject.getFullPath() + " ID=" + currentTask.getExternalTaskID());
currentTask.setProject(currentSubProject.getFullPath());
}
}
}
/**
* This method is used to extract the task hyperlink attributes
* from a block of data and call the appropriate modifier methods
* to configure the specified task object.
*
* @param task task instance
* @param data hyperlink data block
*/
private void processHyperlinkData(Task task, byte[] data)
{
if (data != null)
{
int offset = 12;
String hyperlink;
String address;
String subaddress;
offset += 12;
hyperlink = MPPUtility.getUnicodeString(data, offset);
offset += ((hyperlink.length() + 1) * 2);
offset += 12;
address = MPPUtility.getUnicodeString(data, offset);
offset += ((address.length() + 1) * 2);
offset += 12;
subaddress = MPPUtility.getUnicodeString(data, offset);
task.setHyperlink(hyperlink);
task.setHyperlinkAddress(address);
task.setHyperlinkSubAddress(subaddress);
}
}
/**
* This method is used to extract the resource hyperlink attributes
* from a block of data and call the appropriate modifier methods
* to configure the specified task object.
*
* @param resource resource instance
* @param data hyperlink data block
*/
private void processHyperlinkData(Resource resource, byte[] data)
{
if (data != null)
{
int offset = 12;
String hyperlink;
String address;
String subaddress;
offset += 12;
hyperlink = MPPUtility.getUnicodeString(data, offset);
offset += ((hyperlink.length() + 1) * 2);
offset += 12;
address = MPPUtility.getUnicodeString(data, offset);
offset += ((address.length() + 1) * 2);
offset += 12;
subaddress = MPPUtility.getUnicodeString(data, offset);
resource.setHyperlink(hyperlink);
resource.setHyperlinkAddress(address);
resource.setHyperlinkSubAddress(subaddress);
}
}
/**
* This method extracts and collates constraint data.
*
* @throws java.io.IOException
*/
private void processConstraintData() throws IOException
{
ConstraintFactory factory = new ConstraintFactory();
factory.process(m_projectDir, m_file, m_inputStreamFactory);
}
/**
* This method extracts and collates resource data.
*
* @throws java.io.IOException
*/
private void processResourceData() throws IOException
{
FieldMap fieldMap = new FieldMap12(m_file.getProjectProperties(), m_file.getCustomFields());
fieldMap.createResourceFieldMap(m_projectProps);
FieldMap enterpriseCustomFieldMap = new FieldMap12(m_file.getProjectProperties(), m_file.getCustomFields());
enterpriseCustomFieldMap.createEnterpriseCustomFieldMap(m_projectProps, ResourceField.class);
DirectoryEntry rscDir = (DirectoryEntry) m_projectDir.getEntry("TBkndRsc");
VarMeta rscVarMeta = new VarMeta12(new DocumentInputStream(((DocumentEntry) rscDir.getEntry("VarMeta"))));
Var2Data rscVarData = new Var2Data(rscVarMeta, new DocumentInputStream(((DocumentEntry) rscDir.getEntry("Var2Data"))));
FixedMeta rscFixedMeta = new FixedMeta(new DocumentInputStream(((DocumentEntry) rscDir.getEntry("FixedMeta"))), 37);
FixedData rscFixedData = new FixedData(rscFixedMeta, m_inputStreamFactory.getInstance(rscDir, "FixedData"));
FixedMeta rscFixed2Meta = new FixedMeta(new DocumentInputStream(((DocumentEntry) rscDir.getEntry("Fixed2Meta"))), 49);
FixedData rscFixed2Data = new FixedData(rscFixed2Meta, m_inputStreamFactory.getInstance(rscDir, "Fixed2Data"));
Props12 props = new Props12(m_inputStreamFactory.getInstance(rscDir, "Props"));
//System.out.println(rscVarMeta);
//System.out.println(rscVarData);
//System.out.println(rscFixedMeta);
//System.out.println(rscFixedData);
//System.out.println(rscFixed2Meta);
//System.out.println(rscFixed2Data);
//System.out.println(props);
// Process aliases
new CustomFieldAliasReader(m_file.getCustomFields(), props.getByteArray(RESOURCE_FIELD_NAME_ALIASES)).process();
TreeMap resourceMap = createResourceMap(fieldMap, rscFixedMeta, rscFixedData);
Integer[] uniqueid = rscVarMeta.getUniqueIdentifierArray();
Integer id;
Integer offset;
byte[] data;
byte[] metaData;
Resource resource;
String notes;
for (int loop = 0; loop < uniqueid.length; loop++)
{
id = uniqueid[loop];
offset = resourceMap.get(id);
if (offset == null)
{
continue;
}
data = rscFixedData.getByteArrayValue(offset.intValue());
byte[] metaData2 = rscFixed2Meta.getByteArrayValue(offset.intValue());
byte[] data2 = rscFixed2Data.getByteArrayValue(offset.intValue());
//metaData = rscFixedMeta.getByteArrayValue(offset.intValue());
//MPPUtility.dataDump(data, true, true, true, true, true, true, true);
//MPPUtility.dataDump(metaData, true, true, true, true, true, true, true);
//MPPUtility.varDataDump(rscVarData, id, true, true, true, true, true, true);
resource = m_file.addResource();
resource.disableEvents();
fieldMap.populateContainer(ResourceField.class, resource, id, new byte[][]
{
data,
data2
}, rscVarData);
enterpriseCustomFieldMap.populateContainer(ResourceField.class, resource, id, null, rscVarData);
resource.enableEvents();
resource.setBudget((metaData2[8] & 0x20) != 0);
resource.setGUID(MPPUtility.getGUID(data2, 0));
processHyperlinkData(resource, rscVarData.getByteArray(id, fieldMap.getVarDataKey(ResourceField.HYPERLINK_DATA)));
resource.setID(Integer.valueOf(MPPUtility.getInt(data, 4)));
resource.setOutlineCode1(m_outlineCodeVarData.getUnicodeString(Integer.valueOf(rscVarData.getInt(id, 2, fieldMap.getVarDataKey(ResourceField.OUTLINE_CODE1_INDEX))), OUTLINECODE_DATA));
resource.setOutlineCode2(m_outlineCodeVarData.getUnicodeString(Integer.valueOf(rscVarData.getInt(id, 2, fieldMap.getVarDataKey(ResourceField.OUTLINE_CODE2_INDEX))), OUTLINECODE_DATA));
resource.setOutlineCode3(m_outlineCodeVarData.getUnicodeString(Integer.valueOf(rscVarData.getInt(id, 2, fieldMap.getVarDataKey(ResourceField.OUTLINE_CODE3_INDEX))), OUTLINECODE_DATA));
resource.setOutlineCode4(m_outlineCodeVarData.getUnicodeString(Integer.valueOf(rscVarData.getInt(id, 2, fieldMap.getVarDataKey(ResourceField.OUTLINE_CODE4_INDEX))), OUTLINECODE_DATA));
resource.setOutlineCode5(m_outlineCodeVarData.getUnicodeString(Integer.valueOf(rscVarData.getInt(id, 2, fieldMap.getVarDataKey(ResourceField.OUTLINE_CODE5_INDEX))), OUTLINECODE_DATA));
resource.setOutlineCode6(m_outlineCodeVarData.getUnicodeString(Integer.valueOf(rscVarData.getInt(id, 2, fieldMap.getVarDataKey(ResourceField.OUTLINE_CODE6_INDEX))), OUTLINECODE_DATA));
resource.setOutlineCode7(m_outlineCodeVarData.getUnicodeString(Integer.valueOf(rscVarData.getInt(id, 2, fieldMap.getVarDataKey(ResourceField.OUTLINE_CODE7_INDEX))), OUTLINECODE_DATA));
resource.setOutlineCode8(m_outlineCodeVarData.getUnicodeString(Integer.valueOf(rscVarData.getInt(id, 2, fieldMap.getVarDataKey(ResourceField.OUTLINE_CODE8_INDEX))), OUTLINECODE_DATA));
resource.setOutlineCode9(m_outlineCodeVarData.getUnicodeString(Integer.valueOf(rscVarData.getInt(id, 2, fieldMap.getVarDataKey(ResourceField.OUTLINE_CODE9_INDEX))), OUTLINECODE_DATA));
resource.setOutlineCode10(m_outlineCodeVarData.getUnicodeString(Integer.valueOf(rscVarData.getInt(id, 2, fieldMap.getVarDataKey(ResourceField.OUTLINE_CODE10_INDEX))), OUTLINECODE_DATA));
resource.setType((resource.getWorkGroup() == WorkGroup.DEFAULT ? ResourceType.WORK : ((metaData2[8] & 0x10) == 0) ? ResourceType.MATERIAL : ResourceType.COST));
resource.setUniqueID(id);
metaData = rscFixedMeta.getByteArrayValue(offset.intValue());
resource.setFlag(1, (metaData[28] & 0x40) != 0);
resource.setFlag(2, (metaData[28] & 0x80) != 0);
resource.setFlag(3, (metaData[29] & 0x01) != 0);
resource.setFlag(4, (metaData[29] & 0x02) != 0);
resource.setFlag(5, (metaData[29] & 0x04) != 0);
resource.setFlag(6, (metaData[29] & 0x08) != 0);
resource.setFlag(7, (metaData[29] & 0x10) != 0);
resource.setFlag(8, (metaData[29] & 0x20) != 0);
resource.setFlag(9, (metaData[29] & 0x40) != 0);
resource.setFlag(10, (metaData[28] & 0x20) != 0);
resource.setFlag(11, (metaData[29] & 0x20) != 0);
resource.setFlag(12, (metaData[30] & 0x01) != 0);
resource.setFlag(13, (metaData[30] & 0x02) != 0);
resource.setFlag(14, (metaData[30] & 0x04) != 0);
resource.setFlag(15, (metaData[30] & 0x08) != 0);
resource.setFlag(16, (metaData[30] & 0x10) != 0);
resource.setFlag(17, (metaData[30] & 0x20) != 0);
resource.setFlag(18, (metaData[30] & 0x40) != 0);
resource.setFlag(19, (metaData[30] & 0x80) != 0);
resource.setFlag(20, (metaData[31] & 0x01) != 0);
notes = resource.getNotes();
if (m_reader.getPreserveNoteFormatting() == false)
{
notes = RtfHelper.strip(notes);
}
resource.setNotes(notes);
//
// Configure the resource calendar
//
resource.setResourceCalendar(m_resourceMap.get(id));
//
// Process any enterprise columns
//
processResourceEnterpriseColumns(resource, metaData2);
//
// Process cost rate tables
//
CostRateTableFactory crt = new CostRateTableFactory();
crt.process(resource, 0, rscVarData.getByteArray(id, fieldMap.getVarDataKey(ResourceField.COST_RATE_A)));
crt.process(resource, 1, rscVarData.getByteArray(id, fieldMap.getVarDataKey(ResourceField.COST_RATE_B)));
crt.process(resource, 2, rscVarData.getByteArray(id, fieldMap.getVarDataKey(ResourceField.COST_RATE_C)));
crt.process(resource, 3, rscVarData.getByteArray(id, fieldMap.getVarDataKey(ResourceField.COST_RATE_D)));
crt.process(resource, 4, rscVarData.getByteArray(id, fieldMap.getVarDataKey(ResourceField.COST_RATE_E)));
//
// Process availability table
//
AvailabilityFactory af = new AvailabilityFactory();
af.process(resource.getAvailability(), rscVarData.getByteArray(id, fieldMap.getVarDataKey(ResourceField.AVAILABILITY_DATA)));
m_eventManager.fireResourceReadEvent(resource);
}
}
/**
* This method extracts and collates resource assignment data.
*
* @throws IOException
*/
private void processAssignmentData() throws IOException
{
FieldMap fieldMap = new FieldMap12(m_file.getProjectProperties(), m_file.getCustomFields());
fieldMap.createAssignmentFieldMap(m_projectProps);
FieldMap enterpriseCustomFieldMap = new FieldMap12(m_file.getProjectProperties(), m_file.getCustomFields());
enterpriseCustomFieldMap.createEnterpriseCustomFieldMap(m_projectProps, AssignmentField.class);
DirectoryEntry assnDir = (DirectoryEntry) m_projectDir.getEntry("TBkndAssn");
VarMeta assnVarMeta = new VarMeta12(new DocumentInputStream(((DocumentEntry) assnDir.getEntry("VarMeta"))));
Var2Data assnVarData = new Var2Data(assnVarMeta, new DocumentInputStream(((DocumentEntry) assnDir.getEntry("Var2Data"))));
FixedMeta assnFixedMeta = new FixedMeta(new DocumentInputStream(((DocumentEntry) assnDir.getEntry("FixedMeta"))), 34);
// MSP 20007 seems to write 142 byte blocks, MSP 2010 writes 110 byte blocks
// We need to identify any cases where the meta data count does not correctly identify the block size
FixedData assnFixedData = new FixedData(assnFixedMeta, m_inputStreamFactory.getInstance(assnDir, "FixedData"));
FixedData assnFixedData2 = new FixedData(48, m_inputStreamFactory.getInstance(assnDir, "Fixed2Data"));
ResourceAssignmentFactory factory = new ResourceAssignmentFactory();
factory.process(m_file, fieldMap, enterpriseCustomFieldMap, m_reader.getUseRawTimephasedData(), m_reader.getPreserveNoteFormatting(), assnVarMeta, assnVarData, assnFixedMeta, assnFixedData, assnFixedData2, assnFixedMeta.getAdjustedItemCount());
}
/**
* This method is used to determine if a duration is estimated.
*
* @param type Duration units value
* @return boolean Estimated flag
*/
private boolean getDurationEstimated(int type)
{
return ((type & DURATION_CONFIRMED_MASK) != 0);
}
/**
* This method extracts view data from the MPP file.
*
* @throws java.io.IOException
*/
private void processViewData() throws IOException
{
DirectoryEntry dir = (DirectoryEntry) m_viewDir.getEntry("CV_iew");
VarMeta viewVarMeta = new VarMeta12(new DocumentInputStream(((DocumentEntry) dir.getEntry("VarMeta"))));
Var2Data viewVarData = new Var2Data(viewVarMeta, new DocumentInputStream(((DocumentEntry) dir.getEntry("Var2Data"))));
FixedMeta fixedMeta = new FixedMeta(new DocumentInputStream(((DocumentEntry) dir.getEntry("FixedMeta"))), 10);
FixedData fixedData = new FixedData(138, m_inputStreamFactory.getInstance(dir, "FixedData"));
int items = fixedMeta.getAdjustedItemCount();
View view;
ViewFactory factory = new ViewFactory12();
int lastOffset = -1;
for (int loop = 0; loop < items; loop++)
{
byte[] fm = fixedMeta.getByteArrayValue(loop);
int offset = MPPUtility.getShort(fm, 4);
if (offset > lastOffset)
{
byte[] fd = fixedData.getByteArrayValue(fixedData.getIndexFromOffset(offset));
if (fd != null)
{
view = factory.createView(m_file, fm, fd, viewVarData, m_fontBases);
m_file.getViews().add(view);
}
lastOffset = offset;
}
}
}
/**
* This method extracts table data from the MPP file.
*
* @throws java.io.IOException
*/
private void processTableData() throws IOException
{
DirectoryEntry dir = (DirectoryEntry) m_viewDir.getEntry("CTable");
VarMeta varMeta = new VarMeta12(new DocumentInputStream(((DocumentEntry) dir.getEntry("VarMeta"))));
Var2Data varData = new Var2Data(varMeta, new DocumentInputStream(((DocumentEntry) dir.getEntry("Var2Data"))));
FixedData fixedData = new FixedData(230, new DocumentInputStream(((DocumentEntry) dir.getEntry("FixedData"))));
//System.out.println(varMeta);
//System.out.println(varData);
//System.out.println(fixedData);
TableContainer container = m_file.getTables();
TableFactory factory = new TableFactory(TABLE_COLUMN_DATA_STANDARD, TABLE_COLUMN_DATA_ENTERPRISE, TABLE_COLUMN_DATA_BASELINE);
int items = fixedData.getItemCount();
for (int loop = 0; loop < items; loop++)
{
byte[] data = fixedData.getByteArrayValue(loop);
Table table = factory.createTable(m_file, data, varMeta, varData);
container.add(table);
//System.out.println(table);
}
}
/**
* Read filter definitions.
*
* @throws IOException
*/
private void processFilterData() throws IOException
{
DirectoryEntry dir = (DirectoryEntry) m_viewDir.getEntry("CFilter");
FixedMeta fixedMeta = new FixedMeta(new DocumentInputStream(((DocumentEntry) dir.getEntry("FixedMeta"))), 10);
FixedData fixedData = new FixedData(fixedMeta, m_inputStreamFactory.getInstance(dir, "FixedData"));
VarMeta varMeta = new VarMeta12(new DocumentInputStream(((DocumentEntry) dir.getEntry("VarMeta"))));
Var2Data varData = new Var2Data(varMeta, new DocumentInputStream(((DocumentEntry) dir.getEntry("Var2Data"))));
//System.out.println(fixedMeta);
//System.out.println(fixedData);
//System.out.println(varMeta);
//System.out.println(varData);
FilterReader reader = new FilterReader12();
reader.process(m_file.getProjectProperties(), m_file.getFilters(), fixedData, varData);
}
/**
* Read saved view state from an MPP file.
*
* @throws IOException
*/
private void processSavedViewState() throws IOException
{
DirectoryEntry dir = (DirectoryEntry) m_viewDir.getEntry("CEdl");
VarMeta varMeta = new VarMeta12(new DocumentInputStream(((DocumentEntry) dir.getEntry("VarMeta"))));
Var2Data varData = new Var2Data(varMeta, new DocumentInputStream(((DocumentEntry) dir.getEntry("Var2Data"))));
//System.out.println(varMeta);
//System.out.println(varData);
InputStream is = new DocumentInputStream(((DocumentEntry) dir.getEntry("FixedData")));
byte[] fixedData = new byte[is.available()];
is.read(fixedData);
is.close();
//System.out.println(MPPUtility.hexdump(fixedData, false, 16, ""));
ViewStateReader reader = new ViewStateReader12();
reader.process(m_file, varData, fixedData);
}
/**
* Read group definitions.
*
* @todo Doesn't work correctly with MPP12 files saved by Project 2007 and 2010
* @throws IOException
*/
private void processGroupData() throws IOException
{
DirectoryEntry dir = (DirectoryEntry) m_viewDir.getEntry("CGrouping");
FixedMeta fixedMeta = new FixedMeta(new DocumentInputStream(((DocumentEntry) dir.getEntry("FixedMeta"))), 10);
FixedData fixedData = new FixedData(fixedMeta, m_inputStreamFactory.getInstance(dir, "FixedData"));
VarMeta varMeta = new VarMeta12(new DocumentInputStream(((DocumentEntry) dir.getEntry("VarMeta"))));
Var2Data varData = new Var2Data(varMeta, new DocumentInputStream(((DocumentEntry) dir.getEntry("Var2Data"))));
// System.out.println(fixedMeta);
// System.out.println(fixedData);
// System.out.println(varMeta);
// System.out.println(varData);
GroupReader reader = new GroupReader12();
reader.process(m_file, fixedData, varData, m_fontBases);
}
/**
* Retrieve custom field value.
*
* @param varData var data block
* @param outlineCodeVarData var data block
* @param id item ID
* @param type item type
* @return item value
*/
private String getCustomFieldOutlineCodeValue(Var2Data varData, Var2Data outlineCodeVarData, Integer id, Integer type)
{
String result = null;
int mask = varData.getShort(id, type);
if ((mask & 0xFF00) != VALUE_LIST_MASK)
{
result = outlineCodeVarData.getUnicodeString(Integer.valueOf(varData.getInt(id, 2, type)), OUTLINECODE_DATA);
}
else
{
int uniqueId = varData.getInt(id, 2, type);
CustomFieldValueItem item = m_file.getCustomFields().getCustomFieldValueItemByUniqueID(uniqueId);
if (item != null)
{
Object value = item.getValue();
if (value instanceof String)
{
result = (String) value;
}
String result2 = getCustomFieldOutlineCodeValue(varData, outlineCodeVarData, item.getParent());
if (result2 != null && !result2.isEmpty())
{
result = result2 + "." + result;
}
}
}
return result;
}
/**
* Retrieve custom field value.
*
* @param varData var data block
* @param outlineCodeVarData var data block
* @param id parent item ID
* @return item value
*/
private String getCustomFieldOutlineCodeValue(Var2Data varData, Var2Data outlineCodeVarData, Integer id)
{
String result = null;
int uniqueId = id.intValue();
if (uniqueId == 0)
{
return "";
}
CustomFieldValueItem item = m_file.getCustomFields().getCustomFieldValueItemByUniqueID(uniqueId);
if (item != null)
{
Object value = item.getValue();
if (value instanceof String)
{
result = (String) value;
}
if (result != null && !NumberHelper.equals(id, item.getParent()))
{
String result2 = getCustomFieldOutlineCodeValue(varData, outlineCodeVarData, item.getParent());
if (result2 != null && !result2.isEmpty())
{
result = result2 + "." + result;
}
}
}
return result;
}
private MPPReader m_reader;
private ProjectFile m_file;
private EventManager m_eventManager;
private DirectoryEntry m_root;
private HashMap m_resourceMap;
private Var2Data m_outlineCodeVarData;
private VarMeta m_outlineCodeVarMeta;
private FixedData m_outlineCodeFixedData;
private FixedMeta m_outlineCodeFixedMeta;
private FixedData m_outlineCodeFixedData2;
private FixedMeta m_outlineCodeFixedMeta2;
private Props12 m_projectProps;
private Map m_fontBases;
private Map m_taskSubProjects;
private DirectoryEntry m_projectDir;
private DirectoryEntry m_viewDir;
private Map m_taskOrder;
private Map m_nullTaskOrder;
private DocumentInputStreamFactory m_inputStreamFactory;
// Signals the end of the list of subproject task unique ids
//private static final int SUBPROJECT_LISTEND = 0x00000303;
// Signals that the previous value was for the subproject task unique id
private static final int SUBPROJECT_TASKUNIQUEID0 = 0x00000000;
private static final int SUBPROJECT_TASKUNIQUEID1 = 0x0B340000;
private static final int SUBPROJECT_TASKUNIQUEID2 = 0x0ABB0000;
private static final int SUBPROJECT_TASKUNIQUEID3 = 0x05A10000;
private static final int SUBPROJECT_TASKUNIQUEID4 = 0x0BD50000;
private static final int SUBPROJECT_TASKUNIQUEID5 = 0x03D60000;
private static final int SUBPROJECT_TASKUNIQUEID6 = 0x07010000;
/**
* Calendar data types.
*/
private static final Integer CALENDAR_NAME = Integer.valueOf(1);
private static final Integer CALENDAR_DATA = Integer.valueOf(8);
/**
* Resource data types.
*/
private static final Integer TABLE_COLUMN_DATA_STANDARD = Integer.valueOf(6);
private static final Integer TABLE_COLUMN_DATA_ENTERPRISE = Integer.valueOf(7);
private static final Integer TABLE_COLUMN_DATA_BASELINE = Integer.valueOf(8);
/**
* Outline code data types.
*/
private static final Integer OUTLINECODE_DATA = Integer.valueOf(22);
/**
* Custom value list data types.
*/
private static final int VALUE_LIST_MASK = 0x0700;
/**
* Mask used to isolate confirmed flag from the duration units field.
*/
private static final int DURATION_CONFIRMED_MASK = 0x20;
/**
* Deleted and null tasks have their ID and UniqueID attributes at fixed offsets.
*/
private static final int TASK_UNIQUE_ID_FIXED_OFFSET = 0;
private static final int TASK_ID_FIXED_OFFSET = 4;
private static final int NULL_TASK_BLOCK_SIZE = 16;
/**
* Alias data types.
*/
private static final Integer RESOURCE_FIELD_NAME_ALIASES = Integer.valueOf(71303169);
private static final Integer TASK_FIELD_NAME_ALIASES = Integer.valueOf(71303169);
/**
* Default working week.
*/
private static final boolean[] DEFAULT_WORKING_WEEK =
{
false,
true,
true,
true,
true,
true,
false
};
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy