net.sf.mpxj.primavera.p3.P3PRXFileReader 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: P3PRXFileReader.java
* author: Jon Iles
* copyright: (c) Packwood Software 2018
* date: 11/03/2018
*/
/*
* 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.primavera.p3;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.file.Files;
import net.sf.mpxj.MPXJException;
import net.sf.mpxj.ProjectFile;
import net.sf.mpxj.common.FileHelper;
import net.sf.mpxj.common.FixedLengthInputStream;
import net.sf.mpxj.common.InputStreamHelper;
import net.sf.mpxj.primavera.common.Blast;
import net.sf.mpxj.primavera.suretrak.SureTrakDatabaseReader;
import net.sf.mpxj.reader.AbstractProjectStreamReader;
/**
* Reads a schedule data from a P3 PRX file.
*/
public final class P3PRXFileReader extends AbstractProjectStreamReader
{
@Override public ProjectFile read(InputStream stream) throws MPXJException
{
File tempDir = null;
try
{
InputStreamHelper.skip(stream, 27000);
tempDir = FileHelper.createTempDir();
while (stream.available() > 0)
{
extractFile(stream, tempDir);
}
// Normally we'd expect a PRX file to contains a P3 database...
if (!P3DatabaseReader.listProjectNames(tempDir).isEmpty())
{
return P3DatabaseReader.setProjectNameAndRead(tempDir);
}
// But I have found PRX files which contain a SureTrak database
if (!SureTrakDatabaseReader.listProjectNames(tempDir).isEmpty())
{
return SureTrakDatabaseReader.setProjectNameAndRead(tempDir);
}
return null;
}
catch (IOException ex)
{
throw new MPXJException("Failed to parse file", ex);
}
finally
{
FileHelper.deleteQuietly(tempDir);
}
}
/**
* Extracts the data for a single file from the input stream and writes
* it to a target directory.
*
* @param stream input stream
* @param dir target directory
*/
private void extractFile(InputStream stream, File dir) throws IOException
{
InputStreamHelper.skip(stream, 8); // header
byte[] fileName = InputStreamHelper.read(stream, 13);
byte[] dataSize = InputStreamHelper.read(stream, 4);
int dataSizeValue = getInt(dataSize, 0);
String fileNameValue = getString(fileName, 0);
File file = new File(dir, fileNameValue);
if (dataSizeValue == 0)
{
FileHelper.createNewFile(file);
}
else
{
OutputStream os = Files.newOutputStream(file.toPath());
FixedLengthInputStream inputStream = new FixedLengthInputStream(stream, dataSizeValue);
Blast blast = new Blast();
blast.blast(inputStream, os);
os.close();
}
}
/**
* Retrieve a four byte integer.
*
* @param data byte array
* @param offset offset into array
* @return int value
*/
private int getInt(byte[] data, int offset)
{
int result = 0;
int i = offset;
for (int shiftBy = 0; shiftBy < 32; shiftBy += 8)
{
result |= ((data[i] & 0xff)) << shiftBy;
++i;
}
return result;
}
/**
* Retrieve a string from the byte array.
*
* @param data byte array
* @param offset offset into byte array
* @return String instance
*/
private String getString(byte[] data, int offset)
{
StringBuilder buffer = new StringBuilder();
char c;
for (int loop = 0; offset + loop < data.length; loop++)
{
c = (char) data[offset + loop];
if (c == 0)
{
break;
}
buffer.append(c);
}
return buffer.toString();
}
}