/* * file: MPP9Reader.java * author: Jon Iles * copyright: (c) Packwood Software 2002-2006 * date: 22/05/2003 */ /* * 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.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.CustomFieldContainer; import net.sf.mpxj.DateRange; import net.sf.mpxj.Day; import net.sf.mpxj.DayType; import net.sf.mpxj.Duration; import net.sf.mpxj.EventManager; import net.sf.mpxj.FieldType; 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.TimeUnit; import net.sf.mpxj.View; import net.sf.mpxj.common.DateHelper; import net.sf.mpxj.common.MPPResourceField; import net.sf.mpxj.common.MPPTaskField; import net.sf.mpxj.common.NumberHelper; import net.sf.mpxj.common.Pair; 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 MPP9 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 MPP9Reader implements MPPVariantReader { /** * This method is used to process an MPP9 file. This is the file format * used by Project 2000, 2002, and 2003. * * @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 (never encoded) // Props9 props9 = new Props9(new DocumentInputStream(((DocumentEntry) root.getEntry("Props9")))); //System.out.println(props9); file.getProjectProperties().setProjectFilePath(props9.getUnicodeString(Props.PROJECT_FILE_PATH)); m_inputStreamFactory = new DocumentInputStreamFactory(props9); // // 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 ((props9.getByte(Props.PASSWORD_FLAG) & 0x01) != 0) { // File is password protected for reading, let's read the password // and see if the correct read password was given to us. String readPassword = MPPUtility.decodePassword(props9.getByteArray(Props.PROTECTION_PASSWORD_HASH), m_inputStreamFactory.getEncryptionCode()); // It looks like it is possible for a project file to have the password protection flag on without a password. In // this case MS Project treats the file as NOT protected. We need to do the same. It is worth noting that MS Project does // correct the problem if the file is re-saved (at least it did for me). if (readPassword != null && readPassword.length() > 0) { // See if the correct read password was given if (reader.getReadPassword() == null || reader.getReadPassword().matches(readPassword) == false) { // Passwords don't match throw new MPXJException(MPXJException.PASSWORD_PROTECTED_ENTER_PASSWORD); } } // Passwords matched so let's allow the reading to continue. } m_resourceMap = new HashMap<Integer, ProjectCalendar>(); m_projectDir = (DirectoryEntry) root.getEntry(" 19"); m_viewDir = (DirectoryEntry) root.getEntry(" 29"); DirectoryEntry outlineCodeDir = (DirectoryEntry) m_projectDir.getEntry("TBkndOutlCode"); VarMeta outlineCodeVarMeta = new VarMeta9(new DocumentInputStream(((DocumentEntry) outlineCodeDir.getEntry("VarMeta")))); m_outlineCodeVarData = new Var2Data(outlineCodeVarMeta, new DocumentInputStream(((DocumentEntry) outlineCodeDir.getEntry("Var2Data")))); m_projectProps = new Props9(m_inputStreamFactory.getInstance(m_projectDir, "Props")); //MPPUtility.fileDump("c:\\temp\\props.txt", m_projectProps.toString().getBytes()); m_fontBases = new HashMap<Integer, FontBase>(); m_taskSubProjects = new HashMap<Integer, SubProject>(); m_file.getProjectProperties().setMppFileType(Integer.valueOf(9)); m_file.getProjectProperties().setAutoFilter(props9.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_fontBases = null; m_taskSubProjects = null; } /** * 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; SubProject sp; 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.getShort(subProjData, offset); offset += 4; MPPUtility.getByteArray(subProjData, itemHeaderOffset, itemHeader.length, itemHeader, 0); // System.out.println (); // System.out.println (); // System.out.println ("offset=" + offset); // System.out.println ("ItemHeaderOffset=" + itemHeaderOffset); // System.out.println ("type=" + MPPUtility.hexdump(itemHeader, 16, 1, false)); // System.out.println (MPPUtility.hexdump(itemHeader, false, 16, "")); byte subProjectType = itemHeader[16]; 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: { offset += 8; break; } // // task unique ID, 8 bytes, path, file name // case (byte) 0x99: case 0x09: case 0x0D: { uniqueIDOffset = MPPUtility.getShort(subProjData, offset); offset += 4; // sometimes offset of a task ID? offset += 4; filePathOffset = MPPUtility.getShort(subProjData, offset); offset += 4; fileNameOffset = MPPUtility.getShort(subProjData, offset); offset += 4; sp = readSubProject(subProjData, uniqueIDOffset, filePathOffset, fileNameOffset, index); break; } // // task unique ID, 8 bytes, path, file name // case (byte) 0x91: { uniqueIDOffset = MPPUtility.getShort(subProjData, offset); offset += 4; filePathOffset = MPPUtility.getShort(subProjData, offset); offset += 4; fileNameOffset = MPPUtility.getShort(subProjData, offset); offset += 4; // Unknown offset offset += 4; sp = readSubProject(subProjData, uniqueIDOffset, filePathOffset, fileNameOffset, index); break; } // // task unique ID, path, file name // case 0x01: case 0x03: case 0x08: case 0x0A: case 0x11: { uniqueIDOffset = MPPUtility.getShort(subProjData, offset); offset += 4; filePathOffset = MPPUtility.getShort(subProjData, offset); offset += 4; fileNameOffset = MPPUtility.getShort(subProjData, offset); offset += 4; sp = readSubProject(subProjData, uniqueIDOffset, filePathOffset, fileNameOffset, index); break; } // // task unique ID, path, unknown, file name // case (byte) 0x81: case 0x41: { uniqueIDOffset = MPPUtility.getShort(subProjData, offset); offset += 4; filePathOffset = MPPUtility.getShort(subProjData, offset); offset += 4; // unknown offset to 2 bytes of data? offset += 4; fileNameOffset = MPPUtility.getShort(subProjData, offset); offset += 4; sp = readSubProject(subProjData, uniqueIDOffset, filePathOffset, fileNameOffset, index); break; } // // task unique ID, path, file name // case (byte) 0xC0: { uniqueIDOffset = itemHeaderOffset; filePathOffset = MPPUtility.getShort(subProjData, offset); offset += 4; fileNameOffset = MPPUtility.getShort(subProjData, offset); offset += 4; // unknown offset offset += 4; sp = readSubProject(subProjData, uniqueIDOffset, filePathOffset, fileNameOffset, index); break; } // // resource, task unique ID, path, file name // case 0x05: { uniqueIDOffset = MPPUtility.getShort(subProjData, offset); offset += 4; filePathOffset = MPPUtility.getShort(subProjData, offset); offset += 4; fileNameOffset = MPPUtility.getShort(subProjData, offset); offset += 4; sp = readSubProject(subProjData, uniqueIDOffset, filePathOffset, fileNameOffset, index); m_file.getSubProjects().setResourceSubProject(sp); 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; sp = readSubProject(subProjData, uniqueIDOffset, filePathOffset, fileNameOffset, index); m_file.getSubProjects().setResourceSubProject(sp); break; } // // path, file name // case 0x02: case 0x04: { filePathOffset = MPPUtility.getShort(subProjData, offset); offset += 4; fileNameOffset = MPPUtility.getShort(subProjData, offset); offset += 4; sp = readSubProject(subProjData, -1, filePathOffset, fileNameOffset, index); // 0x02 looks to be the link FROM the resource pool to a project that uses it if (subProjectType == 0x04) { m_file.getSubProjects().setResourceSubProject(sp); } 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; sp = readSubProject(subProjData, uniqueIDOffset, filePathOffset, fileNameOffset, index); break; } // // Appears when a subproject is collapsed // case (byte) 0x80: { offset += 12; break; } // deleted entry? case 0x10: { offset += 8; break; } // new resource pool entry case (byte) 0x44: { filePathOffset = MPPUtility.getShort(subProjData, offset); offset += 4; offset += 4; fileNameOffset = MPPUtility.getShort(subProjData, offset); offset += 4; sp = readSubProject(subProjData, -1, filePathOffset, fileNameOffset, index); m_file.getSubProjects().setResourceSubProject(sp); break; } // // Any other value, assume 12 bytes to handle old/deleted data? // default: { offset += 12; break; } } } } } /** * 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(); if (uniqueIDOffset != -1) { int prev = 0; int value = MPPUtility.getInt(data, uniqueIDOffset); while (value != SUBPROJECT_LISTEND) { switch (value) { case SUBPROJECT_TASKUNIQUEID0: case SUBPROJECT_TASKUNIQUEID1: case SUBPROJECT_TASKUNIQUEID2: case SUBPROJECT_TASKUNIQUEID3: case SUBPROJECT_TASKUNIQUEID4: case SUBPROJECT_TASKUNIQUEID5: // The previous value was for the subproject unique task id sp.setTaskUniqueID(Integer.valueOf(prev)); m_taskSubProjects.put(sp.getTaskUniqueID(), sp); prev = 0; break; default: if (prev != 0) { // The previous value was for an external task unique task id sp.addExternalTaskUniqueID(Integer.valueOf(prev)); m_taskSubProjects.put(Integer.valueOf(prev), sp); } prev = value; break; } // Read the next value uniqueIDOffset += 4; value = MPPUtility.getInt(data, uniqueIDOffset); } if (prev != 0) { // The previous value was for an external task unique task id sp.addExternalTaskUniqueID(Integer.valueOf(prev)); m_taskSubProjects.put(Integer.valueOf(prev), sp); } // Now get the unique id offset for this subproject value = 0x00800000 + ((subprojectIndex - 1) * 0x00400000); sp.setUniqueIDOffset(Integer.valueOf(value)); } // // 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 { Props9 props = new Props9(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); } } } /** * Retrieve any task field value lists defined in the MPP file. */ private void processCustomValueLists() { CustomFieldValueReader9 reader = new CustomFieldValueReader9(m_file.getProjectProperties(), m_projectProps, m_file.getCustomFields()); reader.process(); } /** * Retrieves the description value list associated with a custom task field. * This method will return null if no descriptions for the value list has * been defined for this field. * * @param data data block * @return list of descriptions */ public List<String> getTaskFieldDescriptions(byte[] data) { if (data == null || data.length == 0) { return null; } List<String> descriptions = new LinkedList<String>(); int offset = 0; while (offset < data.length) { String description = MPPUtility.getUnicodeString(data, offset); descriptions.add(description); offset += description.length() * 2 + 2; } return descriptions; } /** * Retrieves the description value list associated with a custom task field. * This method will return null if no descriptions for the value list has * been defined for this field. * * @param properties project properties * @param field task field * @param data data block * @return list of task field values */ public List<Object> getTaskFieldValues(ProjectProperties properties, FieldType field, byte[] data) { if (field == null || data == null || data.length == 0) { return null; } List<Object> list = new LinkedList<Object>(); int offset = 0; switch (field.getDataType()) { case DATE: while (offset + 4 <= data.length) { Date date = MPPUtility.getTimestamp(data, offset); list.add(date); offset += 4; } break; case CURRENCY: while (offset + 8 <= data.length) { Double number = NumberHelper.getDouble(MPPUtility.getDouble(data, offset) / 100.0); list.add(number); offset += 8; } break; case NUMERIC: while (offset + 8 <= data.length) { Double number = NumberHelper.getDouble(MPPUtility.getDouble(data, offset)); list.add(number); offset += 8; } break; case DURATION: while (offset + 6 <= data.length) { Duration duration = MPPUtility.getAdjustedDuration(properties, MPPUtility.getInt(data, offset), MPPUtility.getDurationTimeUnits(MPPUtility.getShort(data, offset + 4))); list.add(duration); offset += 6; } break; case STRING: while (offset < data.length) { String s = MPPUtility.getUnicodeString(data, offset); list.add(s); offset += s.length() * 2 + 2; } break; case BOOLEAN: while (offset + 2 <= data.length) { boolean b = (MPPUtility.getShort(data, offset) == 0x01); list.add(Boolean.valueOf(b)); offset += 2; } break; default: return null; } return list; } /** * Retrieve any resource field aliases defined in the MPP file. * * @param map index to field map * @param data resource field name alias data */ private void processFieldNameAliases(Map<Integer, FieldType> map, byte[] data) { if (data != null) { int offset = 0; int index = 0; CustomFieldContainer fields = m_file.getCustomFields(); while (offset < data.length) { String alias = MPPUtility.getUnicodeString(data, offset); if (!alias.isEmpty()) { FieldType field = map.get(Integer.valueOf(index)); if (field != null) { fields.getCustomField(field).setAlias(alias); } } offset += (alias.length() + 1) * 2; index++; } } } /** * 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<Integer, Integer> createTaskMap(FieldMap fieldMap, FixedMeta taskFixedMeta, FixedData taskFixedData) { TreeMap<Integer, Integer> taskMap = new TreeMap<Integer, Integer>(); 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<Integer, Integer> createResourceMap(FieldMap fieldMap, FixedMeta rscFixedMeta, FixedData rscFixedData) { TreeMap<Integer, Integer> resourceMap = new TreeMap<Integer, Integer>(); 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)); 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"); VarMeta calVarMeta = new VarMeta9(new DocumentInputStream(((DocumentEntry) calDir.getEntry("VarMeta")))); Var2Data calVarData = new Var2Data(calVarMeta, new DocumentInputStream(((DocumentEntry) calDir.getEntry("Var2Data")))); FixedMeta calFixedMeta = new FixedMeta(new DocumentInputStream(((DocumentEntry) calDir.getEntry("FixedMeta"))), 10); FixedData calFixedData = new FixedData(calFixedMeta, m_inputStreamFactory.getInstance(calDir, "FixedData"), 12); HashMap<Integer, ProjectCalendar> calendarMap = new HashMap<Integer, ProjectCalendar>(); int items = calFixedData.getItemCount(); List<Pair<ProjectCalendar, Integer>> baseCalendars = new LinkedList<Pair<ProjectCalendar, Integer>>(); 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<ProjectCalendar, Integer>(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. * * @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 periodCount; int periodIndex; int index; int defaultFlag; Date start; long duration; Day day; for (index = 0; index < 7; index++) { offset = 4 + (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 { periodCount = MPPUtility.getShort(data, offset + 2); if (periodCount == 0) { cal.setWorkingDay(day, false); } else { cal.setWorkingDay(day, true); hours = cal.addCalendarHours(Day.getInstance(index + 1)); for (periodIndex = 0; periodIndex < periodCount; periodIndex++) { start = MPPUtility.getTime(data, offset + 8 + (periodIndex * 2)); duration = MPPUtility.getDuration(data, offset + 20 + (periodIndex * 4)); hours.addRange(new DateRange(start, new Date(start.getTime() + duration))); } } } } } /** * 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 // int exceptionCount = MPPUtility.getShort(data, 0); if (exceptionCount != 0) { int index; int offset; ProjectCalendarException exception; long duration; int periodCount; Date start; for (index = 0; index < exceptionCount; index++) { offset = 4 + (60 * 7) + (index * 64); Date fromDate = MPPUtility.getDate(data, offset); Date toDate = MPPUtility.getDate(data, offset + 2); exception = cal.addCalendarException(fromDate, toDate); periodCount = MPPUtility.getShort(data, offset + 6); if (periodCount != 0) { for (int exceptionPeriodIndex = 0; exceptionPeriodIndex < periodCount; exceptionPeriodIndex++) { start = MPPUtility.getTime(data, offset + 12 + (exceptionPeriodIndex * 2)); duration = MPPUtility.getDuration(data, offset + 24 + (exceptionPeriodIndex * 4)); exception.addRange(new DateRange(start, new Date(start.getTime() + duration))); } } } } } /** * The way calendars are stored in an MPP9 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<Pair<ProjectCalendar, Integer>> baseCalendars, HashMap<Integer, ProjectCalendar> map) { for (Pair<ProjectCalendar, Integer> 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 IOException */ private void processTaskData() throws IOException { FieldMap fieldMap = new FieldMap9(m_file.getProjectProperties(), m_file.getCustomFields()); fieldMap.createTaskFieldMap(m_projectProps); DirectoryEntry taskDir = (DirectoryEntry) m_projectDir.getEntry("TBkndTask"); VarMeta taskVarMeta = new VarMeta9(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, m_inputStreamFactory.getInstance(taskDir, "FixedData"), 768, fieldMap.getMaxFixedDataSize(0)); //System.out.println(taskFixedData); //System.out.println(taskFixedMeta); //System.out.println(taskVarMeta); //System.out.println(taskVarData); processFieldNameAliases(TASK_FIELD_ALIASES, m_projectProps.getByteArray(Props.TASK_FIELD_NAME_ALIASES)); TreeMap<Integer, Integer> 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; Task task; boolean autoWBS = true; LinkedList<Task> externalTasks = new LinkedList<Task>(); 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))); continue; } if (data.length < fieldMap.getMaxFixedDataSize(0)) { continue; } if (uniqueID.intValue() != 0 && !taskVarMeta.containsKey(uniqueID)) { continue; } metaData = taskFixedMeta.getByteArrayValue(offset.intValue()); //System.out.println (MPPUtility.hexdump(data, false, 16, "")); //System.out.println (MPPUtility.hexdump(metaData, 8, 4, false)); //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); 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 }, 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.setSubprojectTaskID(externalTaskID); 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, m_outlineCodeVarData.getUnicodeString((Integer) task.getCachedValue(TaskField.OUTLINE_CODE1_INDEX), OUTLINECODE_DATA)); task.setOutlineCode(2, m_outlineCodeVarData.getUnicodeString((Integer) task.getCachedValue(TaskField.OUTLINE_CODE2_INDEX), OUTLINECODE_DATA)); task.setOutlineCode(3, m_outlineCodeVarData.getUnicodeString((Integer) task.getCachedValue(TaskField.OUTLINE_CODE3_INDEX), OUTLINECODE_DATA)); task.setOutlineCode(4, m_outlineCodeVarData.getUnicodeString((Integer) task.getCachedValue(TaskField.OUTLINE_CODE4_INDEX), OUTLINECODE_DATA)); task.setOutlineCode(5, m_outlineCodeVarData.getUnicodeString((Integer) task.getCachedValue(TaskField.OUTLINE_CODE5_INDEX), OUTLINECODE_DATA)); task.setOutlineCode(6, m_outlineCodeVarData.getUnicodeString((Integer) task.getCachedValue(TaskField.OUTLINE_CODE6_INDEX), OUTLINECODE_DATA)); task.setOutlineCode(7, m_outlineCodeVarData.getUnicodeString((Integer) task.getCachedValue(TaskField.OUTLINE_CODE7_INDEX), OUTLINECODE_DATA)); task.setOutlineCode(8, m_outlineCodeVarData.getUnicodeString((Integer) task.getCachedValue(TaskField.OUTLINE_CODE8_INDEX), OUTLINECODE_DATA)); task.setOutlineCode(9, m_outlineCodeVarData.getUnicodeString((Integer) task.getCachedValue(TaskField.OUTLINE_CODE9_INDEX), OUTLINECODE_DATA)); task.setOutlineCode(10, m_outlineCodeVarData.getUnicodeString((Integer) task.getCachedValue(TaskField.OUTLINE_CODE10_INDEX), OUTLINECODE_DATA)); 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 = taskVarData.getString(id, TASK_NOTES); notes = task.getNotes(); if (notes != null) { //claur // 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<DateRange>()); } // // 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()))) { m_file.removeTask(task); task = m_file.addTask(); task.setNull(true); task.setUniqueID(uniqueID); task.setID(id); continue; } // // Process any enterprise columns // processTaskEnterpriseColumns(fieldMap, task, taskVarData); // // Fire the task read event // m_eventManager.fireTaskReadEvent(task); //System.out.println(task); //dumpUnknownData (task.getName(), UNKNOWN_TASK_DATA, data); } // // Enable auto WBS if necessary // m_file.getProjectConfig().setAutoWBS(autoWBS); // // We have now read all of the tasks, 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); } } /** * Extracts task enterprise column values. * * @param fieldMap fieldMap * @param task task instance * @param taskVarData task var data */ private void processTaskEnterpriseColumns(FieldMap fieldMap, Task task, Var2Data taskVarData) { byte[] data = null; Integer varDataKey = fieldMap.getVarDataKey(TaskField.ENTERPRISE_DATA); if (varDataKey != null) { data = taskVarData.getByteArray(task.getUniqueID(), varDataKey); } if (data != null) { PropsBlock props = new PropsBlock(data); //System.out.println(props); for (Integer key : props.keySet()) { int keyValue = key.intValue() - MPPTaskField.TASK_FIELD_BASE; TaskField field = MPPTaskField.getInstance(keyValue); if (field != null) { Object value = null; switch (field.getDataType()) { case CURRENCY: { value = Double.valueOf(props.getDouble(key) / 100); break; } case DATE: { value = props.getTimestamp(key); break; } case WORK: { double durationValueInHours = MPPUtility.getDouble(props.getByteArray(key), 0) / 60000; value = Duration.getInstance(durationValueInHours, TimeUnit.HOURS); break; } case DURATION: { byte[] durationData = props.getByteArray(key); double durationValueInHours = ((double) MPPUtility.getInt(durationData, 0)) / 600; TimeUnit durationUnits; if (durationData.length < 6) { durationUnits = TimeUnit.DAYS; } else { durationUnits = MPPUtility.getDurationTimeUnits(MPPUtility.getShort(durationData, 4)); } Duration duration = Duration.getInstance(durationValueInHours, TimeUnit.HOURS); value = duration.convertUnits(durationUnits, m_file.getProjectProperties()); break; } case BOOLEAN: { field = null; int bits = props.getInt(key); task.set(TaskField.ENTERPRISE_FLAG1, Boolean.valueOf((bits & 0x00002) != 0)); task.set(TaskField.ENTERPRISE_FLAG2, Boolean.valueOf((bits & 0x00004) != 0)); task.set(TaskField.ENTERPRISE_FLAG3, Boolean.valueOf((bits & 0x00008) != 0)); task.set(TaskField.ENTERPRISE_FLAG4, Boolean.valueOf((bits & 0x00010) != 0)); task.set(TaskField.ENTERPRISE_FLAG5, Boolean.valueOf((bits & 0x00020) != 0)); task.set(TaskField.ENTERPRISE_FLAG6, Boolean.valueOf((bits & 0x00040) != 0)); task.set(TaskField.ENTERPRISE_FLAG7, Boolean.valueOf((bits & 0x00080) != 0)); task.set(TaskField.ENTERPRISE_FLAG8, Boolean.valueOf((bits & 0x00100) != 0)); task.set(TaskField.ENTERPRISE_FLAG9, Boolean.valueOf((bits & 0x00200) != 0)); task.set(TaskField.ENTERPRISE_FLAG10, Boolean.valueOf((bits & 0x00400) != 0)); task.set(TaskField.ENTERPRISE_FLAG11, Boolean.valueOf((bits & 0x00800) != 0)); task.set(TaskField.ENTERPRISE_FLAG12, Boolean.valueOf((bits & 0x01000) != 0)); task.set(TaskField.ENTERPRISE_FLAG13, Boolean.valueOf((bits & 0x02000) != 0)); task.set(TaskField.ENTERPRISE_FLAG14, Boolean.valueOf((bits & 0x04000) != 0)); task.set(TaskField.ENTERPRISE_FLAG15, Boolean.valueOf((bits & 0x08000) != 0)); task.set(TaskField.ENTERPRISE_FLAG16, Boolean.valueOf((bits & 0x10000) != 0)); task.set(TaskField.ENTERPRISE_FLAG17, Boolean.valueOf((bits & 0x20000) != 0)); task.set(TaskField.ENTERPRISE_FLAG18, Boolean.valueOf((bits & 0x40000) != 0)); task.set(TaskField.ENTERPRISE_FLAG19, Boolean.valueOf((bits & 0x80000) != 0)); task.set(TaskField.ENTERPRISE_FLAG20, Boolean.valueOf((bits & 0x100000) != 0)); break; } case NUMERIC: { value = Double.valueOf(props.getDouble(key)); break; } case STRING: { value = props.getUnicodeString(key); break; } case PERCENTAGE: { value = Integer.valueOf(props.getShort(key)); break; } default: { break; } } task.set(field, value); } } } } /** * Extracts resource enterprise column data. * * @param fieldMap field map * @param resource resource instance * @param resourceVarData resource var data */ private void processResourceEnterpriseColumns(FieldMap fieldMap, Resource resource, Var2Data resourceVarData) { byte[] data = null; Integer varDataKey = fieldMap.getVarDataKey(ResourceField.ENTERPRISE_DATA); if (varDataKey != null) { data = resourceVarData.getByteArray(resource.getUniqueID(), varDataKey); } if (data != null) { PropsBlock props = new PropsBlock(data); //System.out.println(props); resource.setCreationDate(props.getTimestamp(Props.RESOURCE_CREATION_DATE)); for (Integer key : props.keySet()) { int keyValue = key.intValue() - MPPResourceField.RESOURCE_FIELD_BASE; //System.out.println("Key=" + keyValue); ResourceField field = MPPResourceField.getInstance(keyValue); if (field != null) { Object value = null; switch (field.getDataType()) { case CURRENCY: { value = Double.valueOf(props.getDouble(key) / 100); break; } case DATE: { value = props.getTimestamp(key); break; } case DURATION: { byte[] durationData = props.getByteArray(key); double durationValueInHours = ((double) MPPUtility.getInt(durationData, 0)) / 600; TimeUnit durationUnits; if (durationData.length < 6) { durationUnits = TimeUnit.DAYS; } else { durationUnits = MPPUtility.getDurationTimeUnits(MPPUtility.getShort(durationData, 4)); } Duration duration = Duration.getInstance(durationValueInHours, TimeUnit.HOURS); value = duration.convertUnits(durationUnits, m_file.getProjectProperties()); break; } case BOOLEAN: { if (field == ResourceField.FLAG1) { field = null; int bits = props.getInt(key); resource.set(ResourceField.ENTERPRISE_FLAG1, Boolean.valueOf((bits & 0x00002) != 0)); resource.set(ResourceField.ENTERPRISE_FLAG2, Boolean.valueOf((bits & 0x00004) != 0)); resource.set(ResourceField.ENTERPRISE_FLAG3, Boolean.valueOf((bits & 0x00008) != 0)); resource.set(ResourceField.ENTERPRISE_FLAG4, Boolean.valueOf((bits & 0x00010) != 0)); resource.set(ResourceField.ENTERPRISE_FLAG5, Boolean.valueOf((bits & 0x00020) != 0)); resource.set(ResourceField.ENTERPRISE_FLAG6, Boolean.valueOf((bits & 0x00040) != 0)); resource.set(ResourceField.ENTERPRISE_FLAG7, Boolean.valueOf((bits & 0x00080) != 0)); resource.set(ResourceField.ENTERPRISE_FLAG8, Boolean.valueOf((bits & 0x00100) != 0)); resource.set(ResourceField.ENTERPRISE_FLAG9, Boolean.valueOf((bits & 0x00200) != 0)); resource.set(ResourceField.ENTERPRISE_FLAG10, Boolean.valueOf((bits & 0x00400) != 0)); resource.set(ResourceField.ENTERPRISE_FLAG11, Boolean.valueOf((bits & 0x00800) != 0)); resource.set(ResourceField.ENTERPRISE_FLAG12, Boolean.valueOf((bits & 0x01000) != 0)); resource.set(ResourceField.ENTERPRISE_FLAG13, Boolean.valueOf((bits & 0x02000) != 0)); resource.set(ResourceField.ENTERPRISE_FLAG14, Boolean.valueOf((bits & 0x04000) != 0)); resource.set(ResourceField.ENTERPRISE_FLAG15, Boolean.valueOf((bits & 0x08000) != 0)); resource.set(ResourceField.ENTERPRISE_FLAG16, Boolean.valueOf((bits & 0x10000) != 0)); resource.set(ResourceField.ENTERPRISE_FLAG17, Boolean.valueOf((bits & 0x20000) != 0)); resource.set(ResourceField.ENTERPRISE_FLAG18, Boolean.valueOf((bits & 0x40000) != 0)); resource.set(ResourceField.ENTERPRISE_FLAG19, Boolean.valueOf((bits & 0x80000) != 0)); resource.set(ResourceField.ENTERPRISE_FLAG20, Boolean.valueOf((bits & 0x100000) != 0)); } break; } case NUMERIC: { value = Double.valueOf(props.getDouble(key)); break; } case STRING: { value = props.getUnicodeString(key); break; } default: { break; } } resource.set(field, value); } } } } /** * 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<Task> 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 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 IOException */ private void processResourceData() throws IOException { FieldMap fieldMap = new FieldMap9(m_file.getProjectProperties(), m_file.getCustomFields()); fieldMap.createResourceFieldMap(m_projectProps); DirectoryEntry rscDir = (DirectoryEntry) m_projectDir.getEntry("TBkndRsc"); VarMeta rscVarMeta = new VarMeta9(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")); //System.out.println(rscVarMeta); //System.out.println(rscVarData); //System.out.println(rscFixedMeta); //System.out.println(rscFixedData); processFieldNameAliases(RESOURCE_FIELD_ALIASES, m_projectProps.getByteArray(Props.RESOURCE_FIELD_NAME_ALIASES)); TreeMap<Integer, Integer> 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()); //MPPUtility.dataDump(data, 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 }, rscVarData); resource.enableEvents(); processHyperlinkData(resource, rscVarData.getByteArray(id, fieldMap.getVarDataKey(ResourceField.HYPERLINK_DATA))); resource.setID(Integer.valueOf(MPPUtility.getInt(data, 4))); resource.setOutlineCode1(m_outlineCodeVarData.getUnicodeString((Integer) resource.getCachedValue(ResourceField.OUTLINE_CODE1_INDEX), OUTLINECODE_DATA)); resource.setOutlineCode2(m_outlineCodeVarData.getUnicodeString((Integer) resource.getCachedValue(ResourceField.OUTLINE_CODE2_INDEX), OUTLINECODE_DATA)); resource.setOutlineCode3(m_outlineCodeVarData.getUnicodeString((Integer) resource.getCachedValue(ResourceField.OUTLINE_CODE3_INDEX), OUTLINECODE_DATA)); resource.setOutlineCode4(m_outlineCodeVarData.getUnicodeString((Integer) resource.getCachedValue(ResourceField.OUTLINE_CODE4_INDEX), OUTLINECODE_DATA)); resource.setOutlineCode5(m_outlineCodeVarData.getUnicodeString((Integer) resource.getCachedValue(ResourceField.OUTLINE_CODE5_INDEX), OUTLINECODE_DATA)); resource.setOutlineCode6(m_outlineCodeVarData.getUnicodeString((Integer) resource.getCachedValue(ResourceField.OUTLINE_CODE6_INDEX), OUTLINECODE_DATA)); resource.setOutlineCode7(m_outlineCodeVarData.getUnicodeString((Integer) resource.getCachedValue(ResourceField.OUTLINE_CODE7_INDEX), OUTLINECODE_DATA)); resource.setOutlineCode8(m_outlineCodeVarData.getUnicodeString((Integer) resource.getCachedValue(ResourceField.OUTLINE_CODE8_INDEX), OUTLINECODE_DATA)); resource.setOutlineCode9(m_outlineCodeVarData.getUnicodeString((Integer) resource.getCachedValue(ResourceField.OUTLINE_CODE9_INDEX), OUTLINECODE_DATA)); resource.setOutlineCode10(m_outlineCodeVarData.getUnicodeString((Integer) resource.getCachedValue(ResourceField.OUTLINE_CODE10_INDEX), OUTLINECODE_DATA)); resource.setType((MPPUtility.getShort(data, fieldMap.getFixedDataOffset(ResourceField.WORKGROUP)) == 0 ? ResourceType.WORK : ResourceType.MATERIAL)); 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(); //claur // 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(fieldMap, resource, rscVarData); // // 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 FieldMap9(m_file.getProjectProperties(), m_file.getCustomFields()); fieldMap.createAssignmentFieldMap(m_projectProps); DirectoryEntry assnDir = (DirectoryEntry) m_projectDir.getEntry("TBkndAssn"); VarMeta assnVarMeta = new VarMeta9(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); FixedData assnFixedData = new FixedData(142, m_inputStreamFactory.getInstance(assnDir, "FixedData")); if (assnFixedData.getItemCount() != assnFixedMeta.getAdjustedItemCount()) { assnFixedData = new FixedData(assnFixedMeta, m_inputStreamFactory.getInstance(assnDir, "FixedData")); } ResourceAssignmentFactory factory = new ResourceAssignmentFactory(); factory.process(m_file, fieldMap, null, m_reader.getUseRawTimephasedData(), m_reader.getPreserveNoteFormatting(), assnVarMeta, assnVarData, assnFixedMeta, assnFixedData, null, 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 IOException */ private void processViewData() throws IOException { DirectoryEntry dir = (DirectoryEntry) m_viewDir.getEntry("CV_iew"); VarMeta viewVarMeta = new VarMeta9(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(122, m_inputStreamFactory.getInstance(dir, "FixedData")); int items = fixedMeta.getAdjustedItemCount(); View view; ViewFactory factory = new ViewFactory9(); 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); //System.out.print(view); } lastOffset = offset; } } } /** * This method extracts table data from the MPP file. * * @todo This implementation does not deal with MPP9 files saved by later * versions of MS Project * * @throws IOException */ private void processTableData() throws IOException { DirectoryEntry dir = (DirectoryEntry) m_viewDir.getEntry("CTable"); //FixedMeta fixedMeta = new FixedMeta(getEncryptableInputStream(dir, "FixedMeta"), 9); FixedData fixedData = new FixedData(110, m_inputStreamFactory.getInstance(dir, "FixedData")); VarMeta varMeta = new VarMeta9(new DocumentInputStream(((DocumentEntry) dir.getEntry("VarMeta")))); Var2Data varData = new Var2Data(varMeta, new DocumentInputStream(((DocumentEntry) dir.getEntry("Var2Data")))); 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. * * @todo Doesn't work correctly with MPP9 files saved by Propject 2007 and 2010 * @throws IOException */ private void processFilterData() throws IOException { DirectoryEntry dir = (DirectoryEntry) m_viewDir.getEntry("CFilter"); //FixedMeta fixedMeta = new FixedMeta(new DocumentInputStream(((DocumentEntry) dir.getEntry("FixedMeta"))), 9); //FixedData fixedData = new FixedData(fixedMeta, getEncryptableInputStream(dir, "FixedData")); FixedData fixedData = new FixedData(110, m_inputStreamFactory.getInstance(dir, "FixedData"), true); VarMeta varMeta = new VarMeta9(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 FilterReader9(); reader.process(m_file.getProjectProperties(), m_file.getFilters(), fixedData, varData); } /** * Read group definitions. * * @todo Doesn't work correctly with MPP9 files saved by Propject 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"))), 9); FixedData fixedData = new FixedData(110, m_inputStreamFactory.getInstance(dir, "FixedData")); VarMeta varMeta = new VarMeta9(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 GroupReader9(); reader.process(m_file, fixedData, varData, m_fontBases); } /** * 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 VarMeta9(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 = m_inputStreamFactory.getInstance(dir, "FixedData"); byte[] fixedData = new byte[is.available()]; is.read(fixedData); //System.out.println(MPPUtility.hexdump(fixedData, false, 16, "")); ViewStateReader reader = new ViewStateReader9(); reader.process(m_file, varData, fixedData); } /** * This method is called to try to catch any invalid tasks that may have sneaked past all our other checks. * This is done by validating the tasks by task ID. */ private void postProcessTasks() { List<Task> allTasks = m_file.getAllTasks(); if (allTasks.size() > 1) { Collections.sort(allTasks); int taskID = -1; int lastTaskID = -1; for (int i = 0; i < allTasks.size(); i++) { Task task = allTasks.get(i); taskID = NumberHelper.getInt(task.getID()); // In Project the tasks IDs are always contiguous so we can spot invalid tasks by making sure all // IDs are represented. if (!task.getNull() && lastTaskID != -1 && taskID > lastTaskID + 1) { // This task looks to be invalid. task.setNull(true); } else { lastTaskID = taskID; } } } } // private static void dumpUnknownData (String name, int[][] spec, byte[] data) // { // System.out.println (name); // for (int loop=0; loop < spec.length; loop++) // { // System.out.println (spec[loop][0] + ": "+ MPPUtility.hexdump(data, spec[loop][0], spec[loop][1], false)); // } // System.out.println (); // } // private static final int[][] UNKNOWN_TASK_DATA = new int[][] // { // {36, 4}, // {42, 18}, // {116, 4}, // {134, 14}, // {144, 4}, // {148, 4}, // {152, 4}, // {156, 4}, // {248, 8}, // }; // private static final int[][] UNKNOWN_RESOURCE_DATA = new int[][] // { // {14, 6}, // {108, 16}, // }; private MPPReader m_reader; private ProjectFile m_file; private EventManager m_eventManager; private DirectoryEntry m_root; private HashMap<Integer, ProjectCalendar> m_resourceMap; private Var2Data m_outlineCodeVarData; private Props9 m_projectProps; private Map<Integer, FontBase> m_fontBases; private Map<Integer, SubProject> m_taskSubProjects; private DirectoryEntry m_projectDir; private DirectoryEntry m_viewDir; 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 = 0x02F70000; private static final int SUBPROJECT_TASKUNIQUEID5 = 0x07010000; /** * Calendar data types. */ private static final Integer CALENDAR_NAME = Integer.valueOf(1); private static final Integer CALENDAR_DATA = Integer.valueOf(3); private static final Integer TABLE_COLUMN_DATA_STANDARD = Integer.valueOf(1); private static final Integer TABLE_COLUMN_DATA_ENTERPRISE = Integer.valueOf(2); private static final Integer TABLE_COLUMN_DATA_BASELINE = null; private static final Integer OUTLINECODE_DATA = Integer.valueOf(1); /** * 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 = 8; /** * Default working week. */ private static final boolean[] DEFAULT_WORKING_WEEK = { false, true, true, true, true, true, false }; private static final Map<Integer, FieldType> RESOURCE_FIELD_ALIASES = new HashMap<Integer, FieldType>(); static { RESOURCE_FIELD_ALIASES.put(Integer.valueOf(52), ResourceField.TEXT1); RESOURCE_FIELD_ALIASES.put(Integer.valueOf(53), ResourceField.TEXT2); RESOURCE_FIELD_ALIASES.put(Integer.valueOf(54), ResourceField.TEXT3); RESOURCE_FIELD_ALIASES.put(Integer.valueOf(55), ResourceField.TEXT4); RESOURCE_FIELD_ALIASES.put(Integer.valueOf(56), ResourceField.TEXT5); RESOURCE_FIELD_ALIASES.put(Integer.valueOf(57), ResourceField.TEXT6); RESOURCE_FIELD_ALIASES.put(Integer.valueOf(58), ResourceField.TEXT7); RESOURCE_FIELD_ALIASES.put(Integer.valueOf(59), ResourceField.TEXT8); RESOURCE_FIELD_ALIASES.put(Integer.valueOf(60), ResourceField.TEXT9); RESOURCE_FIELD_ALIASES.put(Integer.valueOf(61), ResourceField.TEXT10); RESOURCE_FIELD_ALIASES.put(Integer.valueOf(62), ResourceField.TEXT11); RESOURCE_FIELD_ALIASES.put(Integer.valueOf(63), ResourceField.TEXT12); RESOURCE_FIELD_ALIASES.put(Integer.valueOf(64), ResourceField.TEXT13); RESOURCE_FIELD_ALIASES.put(Integer.valueOf(65), ResourceField.TEXT14); RESOURCE_FIELD_ALIASES.put(Integer.valueOf(66), ResourceField.TEXT15); RESOURCE_FIELD_ALIASES.put(Integer.valueOf(67), ResourceField.TEXT16); RESOURCE_FIELD_ALIASES.put(Integer.valueOf(68), ResourceField.TEXT17); RESOURCE_FIELD_ALIASES.put(Integer.valueOf(69), ResourceField.TEXT18); RESOURCE_FIELD_ALIASES.put(Integer.valueOf(70), ResourceField.TEXT19); RESOURCE_FIELD_ALIASES.put(Integer.valueOf(71), ResourceField.TEXT20); RESOURCE_FIELD_ALIASES.put(Integer.valueOf(72), ResourceField.TEXT21); RESOURCE_FIELD_ALIASES.put(Integer.valueOf(73), ResourceField.TEXT22); RESOURCE_FIELD_ALIASES.put(Integer.valueOf(74), ResourceField.TEXT23); RESOURCE_FIELD_ALIASES.put(Integer.valueOf(75), ResourceField.TEXT24); RESOURCE_FIELD_ALIASES.put(Integer.valueOf(76), ResourceField.TEXT25); RESOURCE_FIELD_ALIASES.put(Integer.valueOf(77), ResourceField.TEXT26); RESOURCE_FIELD_ALIASES.put(Integer.valueOf(78), ResourceField.TEXT27); RESOURCE_FIELD_ALIASES.put(Integer.valueOf(79), ResourceField.TEXT28); RESOURCE_FIELD_ALIASES.put(Integer.valueOf(80), ResourceField.TEXT29); RESOURCE_FIELD_ALIASES.put(Integer.valueOf(81), ResourceField.TEXT30); RESOURCE_FIELD_ALIASES.put(Integer.valueOf(82), ResourceField.START1); RESOURCE_FIELD_ALIASES.put(Integer.valueOf(83), ResourceField.START2); RESOURCE_FIELD_ALIASES.put(Integer.valueOf(84), ResourceField.START3); RESOURCE_FIELD_ALIASES.put(Integer.valueOf(85), ResourceField.START4); RESOURCE_FIELD_ALIASES.put(Integer.valueOf(86), ResourceField.START5); RESOURCE_FIELD_ALIASES.put(Integer.valueOf(87), ResourceField.START6); RESOURCE_FIELD_ALIASES.put(Integer.valueOf(88), ResourceField.START7); RESOURCE_FIELD_ALIASES.put(Integer.valueOf(89), ResourceField.START8); RESOURCE_FIELD_ALIASES.put(Integer.valueOf(90), ResourceField.START9); RESOURCE_FIELD_ALIASES.put(Integer.valueOf(91), ResourceField.START10); RESOURCE_FIELD_ALIASES.put(Integer.valueOf(92), ResourceField.FINISH1); RESOURCE_FIELD_ALIASES.put(Integer.valueOf(93), ResourceField.FINISH2); RESOURCE_FIELD_ALIASES.put(Integer.valueOf(94), ResourceField.FINISH3); RESOURCE_FIELD_ALIASES.put(Integer.valueOf(95), ResourceField.FINISH4); RESOURCE_FIELD_ALIASES.put(Integer.valueOf(96), ResourceField.FINISH5); RESOURCE_FIELD_ALIASES.put(Integer.valueOf(97), ResourceField.FINISH6); RESOURCE_FIELD_ALIASES.put(Integer.valueOf(98), ResourceField.FINISH7); RESOURCE_FIELD_ALIASES.put(Integer.valueOf(99), ResourceField.FINISH8); RESOURCE_FIELD_ALIASES.put(Integer.valueOf(100), ResourceField.FINISH9); RESOURCE_FIELD_ALIASES.put(Integer.valueOf(101), ResourceField.FINISH10); RESOURCE_FIELD_ALIASES.put(Integer.valueOf(102), ResourceField.NUMBER1); RESOURCE_FIELD_ALIASES.put(Integer.valueOf(103), ResourceField.NUMBER2); RESOURCE_FIELD_ALIASES.put(Integer.valueOf(104), ResourceField.NUMBER3); RESOURCE_FIELD_ALIASES.put(Integer.valueOf(105), ResourceField.NUMBER4); RESOURCE_FIELD_ALIASES.put(Integer.valueOf(106), ResourceField.NUMBER5); RESOURCE_FIELD_ALIASES.put(Integer.valueOf(107), ResourceField.NUMBER6); RESOURCE_FIELD_ALIASES.put(Integer.valueOf(108), ResourceField.NUMBER7); RESOURCE_FIELD_ALIASES.put(Integer.valueOf(109), ResourceField.NUMBER8); RESOURCE_FIELD_ALIASES.put(Integer.valueOf(110), ResourceField.NUMBER9); RESOURCE_FIELD_ALIASES.put(Integer.valueOf(111), ResourceField.NUMBER10); RESOURCE_FIELD_ALIASES.put(Integer.valueOf(112), ResourceField.NUMBER11); RESOURCE_FIELD_ALIASES.put(Integer.valueOf(113), ResourceField.NUMBER12); RESOURCE_FIELD_ALIASES.put(Integer.valueOf(114), ResourceField.NUMBER13); RESOURCE_FIELD_ALIASES.put(Integer.valueOf(115), ResourceField.NUMBER14); RESOURCE_FIELD_ALIASES.put(Integer.valueOf(116), ResourceField.NUMBER15); RESOURCE_FIELD_ALIASES.put(Integer.valueOf(117), ResourceField.NUMBER16); RESOURCE_FIELD_ALIASES.put(Integer.valueOf(118), ResourceField.NUMBER17); RESOURCE_FIELD_ALIASES.put(Integer.valueOf(119), ResourceField.NUMBER18); RESOURCE_FIELD_ALIASES.put(Integer.valueOf(120), ResourceField.NUMBER19); RESOURCE_FIELD_ALIASES.put(Integer.valueOf(121), ResourceField.NUMBER20); RESOURCE_FIELD_ALIASES.put(Integer.valueOf(122), ResourceField.DURATION1); RESOURCE_FIELD_ALIASES.put(Integer.valueOf(123), ResourceField.DURATION2); RESOURCE_FIELD_ALIASES.put(Integer.valueOf(124), ResourceField.DURATION3); RESOURCE_FIELD_ALIASES.put(Integer.valueOf(125), ResourceField.DURATION4); RESOURCE_FIELD_ALIASES.put(Integer.valueOf(126), ResourceField.DURATION5); RESOURCE_FIELD_ALIASES.put(Integer.valueOf(127), ResourceField.DURATION6); RESOURCE_FIELD_ALIASES.put(Integer.valueOf(128), ResourceField.DURATION7); RESOURCE_FIELD_ALIASES.put(Integer.valueOf(129), ResourceField.DURATION8); RESOURCE_FIELD_ALIASES.put(Integer.valueOf(130), ResourceField.DURATION9); RESOURCE_FIELD_ALIASES.put(Integer.valueOf(131), ResourceField.DURATION10); RESOURCE_FIELD_ALIASES.put(Integer.valueOf(145), ResourceField.DATE1); RESOURCE_FIELD_ALIASES.put(Integer.valueOf(146), ResourceField.DATE2); RESOURCE_FIELD_ALIASES.put(Integer.valueOf(147), ResourceField.DATE3); RESOURCE_FIELD_ALIASES.put(Integer.valueOf(148), ResourceField.DATE4); RESOURCE_FIELD_ALIASES.put(Integer.valueOf(149), ResourceField.DATE5); RESOURCE_FIELD_ALIASES.put(Integer.valueOf(150), ResourceField.DATE6); RESOURCE_FIELD_ALIASES.put(Integer.valueOf(151), ResourceField.DATE7); RESOURCE_FIELD_ALIASES.put(Integer.valueOf(152), ResourceField.DATE8); RESOURCE_FIELD_ALIASES.put(Integer.valueOf(153), ResourceField.DATE9); RESOURCE_FIELD_ALIASES.put(Integer.valueOf(154), ResourceField.DATE10); RESOURCE_FIELD_ALIASES.put(Integer.valueOf(155), ResourceField.OUTLINE_CODE1); RESOURCE_FIELD_ALIASES.put(Integer.valueOf(156), ResourceField.OUTLINE_CODE2); RESOURCE_FIELD_ALIASES.put(Integer.valueOf(157), ResourceField.OUTLINE_CODE3); RESOURCE_FIELD_ALIASES.put(Integer.valueOf(158), ResourceField.OUTLINE_CODE4); RESOURCE_FIELD_ALIASES.put(Integer.valueOf(159), ResourceField.OUTLINE_CODE5); RESOURCE_FIELD_ALIASES.put(Integer.valueOf(160), ResourceField.OUTLINE_CODE6); RESOURCE_FIELD_ALIASES.put(Integer.valueOf(161), ResourceField.OUTLINE_CODE7); RESOURCE_FIELD_ALIASES.put(Integer.valueOf(162), ResourceField.OUTLINE_CODE8); RESOURCE_FIELD_ALIASES.put(Integer.valueOf(163), ResourceField.OUTLINE_CODE9); RESOURCE_FIELD_ALIASES.put(Integer.valueOf(164), ResourceField.OUTLINE_CODE10); RESOURCE_FIELD_ALIASES.put(Integer.valueOf(165), ResourceField.FLAG10); RESOURCE_FIELD_ALIASES.put(Integer.valueOf(166), ResourceField.FLAG1); RESOURCE_FIELD_ALIASES.put(Integer.valueOf(167), ResourceField.FLAG2); RESOURCE_FIELD_ALIASES.put(Integer.valueOf(168), ResourceField.FLAG3); RESOURCE_FIELD_ALIASES.put(Integer.valueOf(169), ResourceField.FLAG4); RESOURCE_FIELD_ALIASES.put(Integer.valueOf(170), ResourceField.FLAG5); RESOURCE_FIELD_ALIASES.put(Integer.valueOf(171), ResourceField.FLAG6); RESOURCE_FIELD_ALIASES.put(Integer.valueOf(172), ResourceField.FLAG7); RESOURCE_FIELD_ALIASES.put(Integer.valueOf(173), ResourceField.FLAG8); RESOURCE_FIELD_ALIASES.put(Integer.valueOf(174), ResourceField.FLAG9); RESOURCE_FIELD_ALIASES.put(Integer.valueOf(175), ResourceField.FLAG11); RESOURCE_FIELD_ALIASES.put(Integer.valueOf(176), ResourceField.FLAG12); RESOURCE_FIELD_ALIASES.put(Integer.valueOf(177), ResourceField.FLAG13); RESOURCE_FIELD_ALIASES.put(Integer.valueOf(178), ResourceField.FLAG14); RESOURCE_FIELD_ALIASES.put(Integer.valueOf(179), ResourceField.FLAG15); RESOURCE_FIELD_ALIASES.put(Integer.valueOf(180), ResourceField.FLAG16); RESOURCE_FIELD_ALIASES.put(Integer.valueOf(181), ResourceField.FLAG17); RESOURCE_FIELD_ALIASES.put(Integer.valueOf(182), ResourceField.FLAG18); RESOURCE_FIELD_ALIASES.put(Integer.valueOf(183), ResourceField.FLAG19); RESOURCE_FIELD_ALIASES.put(Integer.valueOf(184), ResourceField.FLAG20); RESOURCE_FIELD_ALIASES.put(Integer.valueOf(207), ResourceField.COST1); RESOURCE_FIELD_ALIASES.put(Integer.valueOf(208), ResourceField.COST2); RESOURCE_FIELD_ALIASES.put(Integer.valueOf(209), ResourceField.COST3); RESOURCE_FIELD_ALIASES.put(Integer.valueOf(210), ResourceField.COST4); RESOURCE_FIELD_ALIASES.put(Integer.valueOf(211), ResourceField.COST5); RESOURCE_FIELD_ALIASES.put(Integer.valueOf(212), ResourceField.COST6); RESOURCE_FIELD_ALIASES.put(Integer.valueOf(213), ResourceField.COST7); RESOURCE_FIELD_ALIASES.put(Integer.valueOf(214), ResourceField.COST8); RESOURCE_FIELD_ALIASES.put(Integer.valueOf(215), ResourceField.COST9); RESOURCE_FIELD_ALIASES.put(Integer.valueOf(216), ResourceField.COST10); } private static final Map<Integer, FieldType> TASK_FIELD_ALIASES = new HashMap<Integer, FieldType>(); static { TASK_FIELD_ALIASES.put(Integer.valueOf(118), TaskField.TEXT1); TASK_FIELD_ALIASES.put(Integer.valueOf(119), TaskField.TEXT2); TASK_FIELD_ALIASES.put(Integer.valueOf(120), TaskField.TEXT3); TASK_FIELD_ALIASES.put(Integer.valueOf(121), TaskField.TEXT4); TASK_FIELD_ALIASES.put(Integer.valueOf(122), TaskField.TEXT5); TASK_FIELD_ALIASES.put(Integer.valueOf(123), TaskField.TEXT6); TASK_FIELD_ALIASES.put(Integer.valueOf(124), TaskField.TEXT7); TASK_FIELD_ALIASES.put(Integer.valueOf(125), TaskField.TEXT8); TASK_FIELD_ALIASES.put(Integer.valueOf(126), TaskField.TEXT9); TASK_FIELD_ALIASES.put(Integer.valueOf(127), TaskField.TEXT10); TASK_FIELD_ALIASES.put(Integer.valueOf(128), TaskField.START1); TASK_FIELD_ALIASES.put(Integer.valueOf(129), TaskField.FINISH1); TASK_FIELD_ALIASES.put(Integer.valueOf(130), TaskField.START2); TASK_FIELD_ALIASES.put(Integer.valueOf(131), TaskField.FINISH2); TASK_FIELD_ALIASES.put(Integer.valueOf(132), TaskField.START3); TASK_FIELD_ALIASES.put(Integer.valueOf(133), TaskField.FINISH3); TASK_FIELD_ALIASES.put(Integer.valueOf(134), TaskField.START4); TASK_FIELD_ALIASES.put(Integer.valueOf(135), TaskField.FINISH4); TASK_FIELD_ALIASES.put(Integer.valueOf(136), TaskField.START5); TASK_FIELD_ALIASES.put(Integer.valueOf(137), TaskField.FINISH5); TASK_FIELD_ALIASES.put(Integer.valueOf(138), TaskField.START6); TASK_FIELD_ALIASES.put(Integer.valueOf(139), TaskField.FINISH6); TASK_FIELD_ALIASES.put(Integer.valueOf(140), TaskField.START7); TASK_FIELD_ALIASES.put(Integer.valueOf(141), TaskField.FINISH7); TASK_FIELD_ALIASES.put(Integer.valueOf(142), TaskField.START8); TASK_FIELD_ALIASES.put(Integer.valueOf(143), TaskField.FINISH8); TASK_FIELD_ALIASES.put(Integer.valueOf(144), TaskField.START9); TASK_FIELD_ALIASES.put(Integer.valueOf(145), TaskField.FINISH9); TASK_FIELD_ALIASES.put(Integer.valueOf(146), TaskField.START10); TASK_FIELD_ALIASES.put(Integer.valueOf(147), TaskField.FINISH10); TASK_FIELD_ALIASES.put(Integer.valueOf(149), TaskField.NUMBER1); TASK_FIELD_ALIASES.put(Integer.valueOf(150), TaskField.NUMBER2); TASK_FIELD_ALIASES.put(Integer.valueOf(151), TaskField.NUMBER3); TASK_FIELD_ALIASES.put(Integer.valueOf(152), TaskField.NUMBER4); TASK_FIELD_ALIASES.put(Integer.valueOf(153), TaskField.NUMBER5); TASK_FIELD_ALIASES.put(Integer.valueOf(154), TaskField.NUMBER6); TASK_FIELD_ALIASES.put(Integer.valueOf(155), TaskField.NUMBER7); TASK_FIELD_ALIASES.put(Integer.valueOf(156), TaskField.NUMBER8); TASK_FIELD_ALIASES.put(Integer.valueOf(157), TaskField.NUMBER9); TASK_FIELD_ALIASES.put(Integer.valueOf(158), TaskField.NUMBER10); TASK_FIELD_ALIASES.put(Integer.valueOf(159), TaskField.DURATION1); TASK_FIELD_ALIASES.put(Integer.valueOf(161), TaskField.DURATION2); TASK_FIELD_ALIASES.put(Integer.valueOf(163), TaskField.DURATION3); TASK_FIELD_ALIASES.put(Integer.valueOf(165), TaskField.DURATION4); TASK_FIELD_ALIASES.put(Integer.valueOf(167), TaskField.DURATION5); TASK_FIELD_ALIASES.put(Integer.valueOf(169), TaskField.DURATION6); TASK_FIELD_ALIASES.put(Integer.valueOf(171), TaskField.DURATION7); TASK_FIELD_ALIASES.put(Integer.valueOf(173), TaskField.DURATION8); TASK_FIELD_ALIASES.put(Integer.valueOf(175), TaskField.DURATION9); TASK_FIELD_ALIASES.put(Integer.valueOf(177), TaskField.DURATION10); TASK_FIELD_ALIASES.put(Integer.valueOf(184), TaskField.DATE1); TASK_FIELD_ALIASES.put(Integer.valueOf(185), TaskField.DATE2); TASK_FIELD_ALIASES.put(Integer.valueOf(186), TaskField.DATE3); TASK_FIELD_ALIASES.put(Integer.valueOf(187), TaskField.DATE4); TASK_FIELD_ALIASES.put(Integer.valueOf(188), TaskField.DATE5); TASK_FIELD_ALIASES.put(Integer.valueOf(189), TaskField.DATE6); TASK_FIELD_ALIASES.put(Integer.valueOf(190), TaskField.DATE7); TASK_FIELD_ALIASES.put(Integer.valueOf(191), TaskField.DATE8); TASK_FIELD_ALIASES.put(Integer.valueOf(192), TaskField.DATE9); TASK_FIELD_ALIASES.put(Integer.valueOf(193), TaskField.DATE10); TASK_FIELD_ALIASES.put(Integer.valueOf(194), TaskField.TEXT11); TASK_FIELD_ALIASES.put(Integer.valueOf(195), TaskField.TEXT12); TASK_FIELD_ALIASES.put(Integer.valueOf(196), TaskField.TEXT13); TASK_FIELD_ALIASES.put(Integer.valueOf(197), TaskField.TEXT14); TASK_FIELD_ALIASES.put(Integer.valueOf(198), TaskField.TEXT15); TASK_FIELD_ALIASES.put(Integer.valueOf(199), TaskField.TEXT16); TASK_FIELD_ALIASES.put(Integer.valueOf(200), TaskField.TEXT17); TASK_FIELD_ALIASES.put(Integer.valueOf(201), TaskField.TEXT18); TASK_FIELD_ALIASES.put(Integer.valueOf(202), TaskField.TEXT19); TASK_FIELD_ALIASES.put(Integer.valueOf(203), TaskField.TEXT20); TASK_FIELD_ALIASES.put(Integer.valueOf(204), TaskField.TEXT21); TASK_FIELD_ALIASES.put(Integer.valueOf(205), TaskField.TEXT22); TASK_FIELD_ALIASES.put(Integer.valueOf(206), TaskField.TEXT23); TASK_FIELD_ALIASES.put(Integer.valueOf(207), TaskField.TEXT24); TASK_FIELD_ALIASES.put(Integer.valueOf(208), TaskField.TEXT25); TASK_FIELD_ALIASES.put(Integer.valueOf(209), TaskField.TEXT26); TASK_FIELD_ALIASES.put(Integer.valueOf(210), TaskField.TEXT27); TASK_FIELD_ALIASES.put(Integer.valueOf(211), TaskField.TEXT28); TASK_FIELD_ALIASES.put(Integer.valueOf(212), TaskField.TEXT29); TASK_FIELD_ALIASES.put(Integer.valueOf(213), TaskField.TEXT30); TASK_FIELD_ALIASES.put(Integer.valueOf(214), TaskField.NUMBER11); TASK_FIELD_ALIASES.put(Integer.valueOf(215), TaskField.NUMBER12); TASK_FIELD_ALIASES.put(Integer.valueOf(216), TaskField.NUMBER13); TASK_FIELD_ALIASES.put(Integer.valueOf(217), TaskField.NUMBER14); TASK_FIELD_ALIASES.put(Integer.valueOf(218), TaskField.NUMBER15); TASK_FIELD_ALIASES.put(Integer.valueOf(219), TaskField.NUMBER16); TASK_FIELD_ALIASES.put(Integer.valueOf(220), TaskField.NUMBER17); TASK_FIELD_ALIASES.put(Integer.valueOf(221), TaskField.NUMBER18); TASK_FIELD_ALIASES.put(Integer.valueOf(222), TaskField.NUMBER19); TASK_FIELD_ALIASES.put(Integer.valueOf(223), TaskField.NUMBER20); TASK_FIELD_ALIASES.put(Integer.valueOf(227), TaskField.OUTLINE_CODE1); TASK_FIELD_ALIASES.put(Integer.valueOf(228), TaskField.OUTLINE_CODE2); TASK_FIELD_ALIASES.put(Integer.valueOf(229), TaskField.OUTLINE_CODE3); TASK_FIELD_ALIASES.put(Integer.valueOf(230), TaskField.OUTLINE_CODE4); TASK_FIELD_ALIASES.put(Integer.valueOf(231), TaskField.OUTLINE_CODE5); TASK_FIELD_ALIASES.put(Integer.valueOf(232), TaskField.OUTLINE_CODE6); TASK_FIELD_ALIASES.put(Integer.valueOf(233), TaskField.OUTLINE_CODE7); TASK_FIELD_ALIASES.put(Integer.valueOf(234), TaskField.OUTLINE_CODE8); TASK_FIELD_ALIASES.put(Integer.valueOf(235), TaskField.OUTLINE_CODE9); TASK_FIELD_ALIASES.put(Integer.valueOf(236), TaskField.OUTLINE_CODE10); TASK_FIELD_ALIASES.put(Integer.valueOf(237), TaskField.FLAG1); TASK_FIELD_ALIASES.put(Integer.valueOf(238), TaskField.FLAG2); TASK_FIELD_ALIASES.put(Integer.valueOf(239), TaskField.FLAG3); TASK_FIELD_ALIASES.put(Integer.valueOf(240), TaskField.FLAG4); TASK_FIELD_ALIASES.put(Integer.valueOf(241), TaskField.FLAG5); TASK_FIELD_ALIASES.put(Integer.valueOf(242), TaskField.FLAG6); TASK_FIELD_ALIASES.put(Integer.valueOf(243), TaskField.FLAG7); TASK_FIELD_ALIASES.put(Integer.valueOf(244), TaskField.FLAG8); TASK_FIELD_ALIASES.put(Integer.valueOf(245), TaskField.FLAG9); TASK_FIELD_ALIASES.put(Integer.valueOf(246), TaskField.FLAG10); TASK_FIELD_ALIASES.put(Integer.valueOf(247), TaskField.FLAG11); TASK_FIELD_ALIASES.put(Integer.valueOf(248), TaskField.FLAG12); TASK_FIELD_ALIASES.put(Integer.valueOf(249), TaskField.FLAG13); TASK_FIELD_ALIASES.put(Integer.valueOf(250), TaskField.FLAG14); TASK_FIELD_ALIASES.put(Integer.valueOf(251), TaskField.FLAG15); TASK_FIELD_ALIASES.put(Integer.valueOf(252), TaskField.FLAG16); TASK_FIELD_ALIASES.put(Integer.valueOf(253), TaskField.FLAG17); TASK_FIELD_ALIASES.put(Integer.valueOf(254), TaskField.FLAG18); TASK_FIELD_ALIASES.put(Integer.valueOf(255), TaskField.FLAG19); TASK_FIELD_ALIASES.put(Integer.valueOf(256), TaskField.FLAG20); TASK_FIELD_ALIASES.put(Integer.valueOf(278), TaskField.COST1); TASK_FIELD_ALIASES.put(Integer.valueOf(279), TaskField.COST2); TASK_FIELD_ALIASES.put(Integer.valueOf(280), TaskField.COST3); TASK_FIELD_ALIASES.put(Integer.valueOf(281), TaskField.COST4); TASK_FIELD_ALIASES.put(Integer.valueOf(282), TaskField.COST5); TASK_FIELD_ALIASES.put(Integer.valueOf(283), TaskField.COST6); TASK_FIELD_ALIASES.put(Integer.valueOf(284), TaskField.COST7); TASK_FIELD_ALIASES.put(Integer.valueOf(285), TaskField.COST8); TASK_FIELD_ALIASES.put(Integer.valueOf(286), TaskField.COST9); TASK_FIELD_ALIASES.put(Integer.valueOf(287), TaskField.COST10); } }