Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
/*
* HomeFileRecorder.java 30 aout 2006
*
* Sweet Home 3D, Copyright (c) 2006 Emmanuel PUYBARET / eTeks
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package com.eteks.sweethome3d.io;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InterruptedIOException;
import java.io.OutputStream;
import com.eteks.sweethome3d.model.DamagedHomeRecorderException;
import com.eteks.sweethome3d.model.Home;
import com.eteks.sweethome3d.model.HomeRecorder;
import com.eteks.sweethome3d.model.InterruptedRecorderException;
import com.eteks.sweethome3d.model.NotEnoughSpaceRecorderException;
import com.eteks.sweethome3d.model.RecorderException;
import com.eteks.sweethome3d.model.UserPreferences;
import com.eteks.sweethome3d.tools.OperatingSystem;
/**
* Recorder that stores homes in files with {@link DefaultHomeOutputStream} and
* {@link DefaultHomeInputStream}.
* @author Emmanuel Puybaret
*/
public class HomeFileRecorder implements HomeRecorder {
private final int compressionLevel;
private final boolean includeOnlyTemporaryContent;
private final UserPreferences preferences;
private final boolean preferPreferencesContent;
private final boolean preferXmlEntry;
/**
* Creates a home recorder able to write and read homes in uncompressed files.
*/
public HomeFileRecorder() {
this(0);
}
/**
* Creates a home recorder able to write and read homes in files compressed
* at a level from 0 to 9.
* @param compressionLevel 0 (uncompressed) to 9 (compressed).
*/
public HomeFileRecorder(int compressionLevel) {
this(compressionLevel, false);
}
/**
* Creates a home recorder able to write and read homes in files compressed
* at a level from 0 to 9.
* @param compressionLevel 0-9
* @param includeOnlyTemporaryContent if true, content instances of
* TemporaryURLContent class referenced by the saved home
* as well as the content previously saved with it will be written.
* If false, all the content instances
* referenced by the saved home will be written in the zip stream.
*/
public HomeFileRecorder(int compressionLevel,
boolean includeOnlyTemporaryContent) {
this(compressionLevel, includeOnlyTemporaryContent, null, false);
}
/**
* Creates a home recorder able to write and read homes in files compressed
* at a level from 0 to 9.
* @param compressionLevel 0-9
* @param includeOnlyTemporaryContent if true, content instances of
* TemporaryURLContent class referenced by the saved home
* as well as the content previously saved with it will be written.
* If false, all the content instances
* referenced by the saved home will be written in the zip stream.
* @param preferences If not null, the furniture and textures contents
* it references might be used to replace the one of read homes
* when they are equal.
* @param preferPreferencesContent If true, the furniture and textures contents
* referenced by preferences will replace the one of read homes
* as often as possible when they are equal. Otherwise, these contents will be
* used only to replace damaged content that might be found in read home files.
*/
public HomeFileRecorder(int compressionLevel,
boolean includeOnlyTemporaryContent,
UserPreferences preferences,
boolean preferPreferencesContent) {
this(compressionLevel, includeOnlyTemporaryContent, preferences, preferPreferencesContent, false);
}
/**
* Creates a home recorder able to write and read homes in files compressed
* at a level from 0 to 9.
* @param compressionLevel 0-9
* @param includeOnlyTemporaryContent if true, content instances of
* TemporaryURLContent class referenced by the saved home
* as well as the content previously saved with it will be written.
* If false, all the content instances
* referenced by the saved home will be written in the zip stream.
* @param preferences If not null, the furniture and textures contents
* it references might be used to replace the one of read homes
* when they are equal.
* @param preferPreferencesContent If true, the furniture and textures contents
* referenced by preferences will replace the one of read homes
* as often as possible when they are equal. Otherwise, these contents will be
* used only to replace damaged content that might be found in read home files.
* @param preferXmlEntry If true, an additional Home.xml entry
* will be saved in files and read in priority from saved files.
*/
public HomeFileRecorder(int compressionLevel,
boolean includeOnlyTemporaryContent,
UserPreferences preferences,
boolean preferPreferencesContent,
boolean preferXmlEntry) {
this.compressionLevel = compressionLevel;
this.includeOnlyTemporaryContent = includeOnlyTemporaryContent;
this.preferences = preferences;
this.preferPreferencesContent = preferPreferencesContent;
this.preferXmlEntry = preferXmlEntry;
}
/**
* Writes home data.
* @throws RecorderException if a problem occurred while writing home.
*/
public void writeHome(Home home, String name) throws RecorderException {
File homeFile = new File(name);
if (homeFile.exists()
&& !homeFile.canWrite()) {
throw new RecorderException("Can't write over file " + name);
}
DefaultHomeOutputStream homeOut = null;
File tempFile = null;
try {
// Open a stream on a temporary file
tempFile = OperatingSystem.createTemporaryFile("save", ".sweethome3d");
homeOut = new DefaultHomeOutputStream(new FileOutputStream(tempFile),
this.compressionLevel,
this.includeOnlyTemporaryContent
? ContentRecording.INCLUDE_TEMPORARY_CONTENT
: ContentRecording.INCLUDE_ALL_CONTENT,
true,
this.preferXmlEntry
? getHomeXMLExporter()
: null);
// Write home with HomeOuputStream
homeOut.writeHome(home);
} catch (InterruptedIOException ex) {
throw new InterruptedRecorderException("Save " + name + " interrupted");
} catch (IOException ex) {
throw new RecorderException("Can't save home " + name, ex);
} finally {
try {
if (homeOut != null) {
homeOut.close();
}
} catch (IOException ex) {
throw new RecorderException("Can't close temporary file " + name, ex);
}
}
try {
// Check disk space under Java 1.6
long usableSpace = (Long)File.class.getMethod("getUsableSpace").invoke(homeFile);
long requiredSpace = tempFile.length();
if (homeFile.exists()) {
requiredSpace -= homeFile.length();
}
if (usableSpace != 0
&& usableSpace < requiredSpace) {
throw new NotEnoughSpaceRecorderException("Not enough disk space to save file " + name, requiredSpace - usableSpace);
}
} catch (NoSuchMethodException ex) {
// The method File#getUsableSpace doesn't exist under Java 5
} catch (NotEnoughSpaceRecorderException ex) {
if (tempFile != null) {
tempFile.delete();
}
throw ex;
} catch (Exception ex) {
// Too bad let's not check and take the risk
ex.printStackTrace();
}
// Open destination file
OutputStream out;
try {
out = new FileOutputStream(homeFile);
} catch (FileNotFoundException ex) {
if (tempFile != null) {
tempFile.delete();
}
throw new RecorderException("Can't save file " + name, ex);
}
// Copy temporary file to home file
// Overwriting home file will ensure that its rights are kept
byte [] buffer = new byte [8192];
InputStream in = null;
try {
in = new FileInputStream(tempFile);
int size;
while ((size = in.read(buffer)) != -1) {
out.write(buffer, 0, size);
}
} catch (IOException ex) {
throw new RecorderException("Can't copy file " + tempFile + " to " + name);
} finally {
try {
if (out != null) {
out.close();
}
} catch (IOException ex) {
throw new RecorderException("Can't close file " + name, ex);
}
try {
if (in != null) {
in.close();
tempFile.delete();
}
} catch (IOException ex) {
// Forget exception
}
}
}
/**
* Returns an exporter able to generate the content of a Home.xml entry.
*/
protected HomeXMLExporter getHomeXMLExporter() {
return new HomeXMLExporter();
}
/**
* Returns a home instance read from its file name.
* @throws RecorderException if a problem occurred while reading home,
* or if file name doesn't exist.
*/
public Home readHome(String name) throws RecorderException {
DefaultHomeInputStream in = null;
try {
// Open a stream on file
in = new DefaultHomeInputStream(new FileInputStream(name), ContentRecording.INCLUDE_ALL_CONTENT,
this.preferXmlEntry ? getHomeXMLHandler() : null,
this.preferences, this.preferPreferencesContent);
// Read home with HomeInputStream
Home home = in.readHome();
return home;
} catch (InterruptedIOException ex) {
throw new InterruptedRecorderException("Read " + name + " interrupted");
} catch (DamagedHomeIOException ex) {
throw new DamagedHomeRecorderException(ex.getDamagedHome(), ex.getInvalidContent());
} catch (IOException ex) {
throw new RecorderException("Can't read home from " + name, ex);
} catch (ClassNotFoundException ex) {
throw new RecorderException("Missing classes to read home from " + name, ex);
} finally {
try {
if (in != null) {
in.close();
}
} catch (IOException ex) {
throw new RecorderException("Can't close file " + name, ex);
}
}
}
/**
* Returns a SAX XML handler able to interpret the information contained in the
* Home.xml entry.
*/
protected HomeXMLHandler getHomeXMLHandler() {
return new HomeXMLHandler(this.preferences);
}
/**
* Returns true if the file name exists.
*/
public boolean exists(String name) throws RecorderException {
return new File(name).exists();
}
}