/*
* This file is part of NixNote
* Copyright 2009 Randy Baumgarte
*
* This file may be licensed under the terms of of the
* GNU General Public License Version 2 (the ``GPL'').
*
* Software distributed under the License is distributed
* on an ``AS IS'' basis, WITHOUT WARRANTY OF ANY KIND, either
* express or implied. See the GPL for the specific language
* governing rights and limitations.
*
* You should have received a copy of the GPL along with this
* program. If not, go to http://www.gnu.org/licenses/gpl.html
* or write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
package cx.fbn.nevernote.xml;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Random;
import com.evernote.edam.type.Data;
import com.evernote.edam.type.LinkedNotebook;
import com.evernote.edam.type.Note;
import com.evernote.edam.type.NoteAttributes;
import com.evernote.edam.type.NoteSortOrder;
import com.evernote.edam.type.Notebook;
import com.evernote.edam.type.Publishing;
import com.evernote.edam.type.Resource;
import com.evernote.edam.type.ResourceAttributes;
import com.evernote.edam.type.SavedSearch;
import com.evernote.edam.type.SharedNotebook;
import com.evernote.edam.type.Tag;
import com.trolltech.qt.core.QByteArray;
import com.trolltech.qt.core.QFile;
import com.trolltech.qt.core.QIODevice;
import com.trolltech.qt.gui.QIcon;
import com.trolltech.qt.gui.QImage;
import com.trolltech.qt.gui.QPixmap;
import com.trolltech.qt.xml.QXmlStreamAttributes;
import com.trolltech.qt.xml.QXmlStreamReader;
import cx.fbn.nevernote.evernote.NoteMetadata;
import cx.fbn.nevernote.sql.DatabaseConnection;
import cx.fbn.nevernote.utilities.ApplicationLogger;
public class ImportData {
public int lastError;
private String errorMessage;
private String fileName;
DatabaseConnection conn;
QXmlStreamReader reader;
private Note note;
private boolean noteIsDirty;
private Notebook notebook;
private boolean notebookIsDirty;
private boolean notebookIsLocal;
private boolean notebookIsReadOnly;
private QIcon notebookIcon;
private Tag tag;
private boolean tagIsDirty;
// private final HashMap<String,Integer> titleColors;
private SavedSearch search;
private boolean searchIsDirty;
public int highUpdateSequenceNumber;
public long lastSequenceDate;
private final ApplicationLogger logger;
private final boolean backup;
private String notebookGuid;
private boolean linkedNotebookIsDirty;
private boolean sharedNotebookIsDirty;
private LinkedNotebook linkedNotebook;
private SharedNotebook sharedNotebook;
public final boolean importTags = false;
public final boolean importNotebooks = false;
private final HashMap<String,String> noteMap;
private final HashMap<String, NoteMetadata> metaData;
public ImportData(DatabaseConnection c, boolean full) {
logger = new ApplicationLogger("import.log");
backup = full;
conn = c;
metaData = new HashMap<String,NoteMetadata>();
noteMap = new HashMap<String,String>();
}
public void importData(String f) {
fileName = f;
errorMessage = "";
lastError = 0;
errorMessage = "";
QFile xmlFile = new QFile(fileName);
if (!xmlFile.open(QIODevice.OpenModeFlag.ReadOnly)) {
lastError = 16;
errorMessage = "Cannot open file.";
}
reader = new QXmlStreamReader(xmlFile);
while (!reader.atEnd()) {
reader.readNext();
if (reader.hasError()) {
errorMessage = reader.errorString();
logger.log(logger.LOW, "************************* ERROR READING BACKUP " +reader.errorString());
lastError = 16;
return;
}
if (reader.name().equalsIgnoreCase("nevernote-export") && reader.isStartElement()) {
QXmlStreamAttributes attributes = reader.attributes();
String version = attributes.value("version");
String type = attributes.value("exportType");
String application = attributes.value("application");
if (!version.equalsIgnoreCase("0.85") && !version.equalsIgnoreCase("0.86")
&& !version.equalsIgnoreCase("0.95")) {
lastError = 1;
errorMessage = "Unknown backup version = " +version;
return;
}
if (!application.equalsIgnoreCase("NeverNote")) {
lastError = 2;
errorMessage = "This backup is from an unknown application = " +application;
return;
}
if (!type.equalsIgnoreCase("backup") && backup) {
lastError = 4;
errorMessage = "This is an export file, not a backup file";
return;
}
if (type.equalsIgnoreCase("export") && backup) {
lastError = 5;
errorMessage = "This is a backup file, not an export file";
return;
}
}
if (reader.name().equalsIgnoreCase("Synchronization") && reader.isStartElement() && backup) {
processSynchronizationNode();
conn.getSyncTable().setLastSequenceDate(lastSequenceDate);
conn.getSyncTable().setUpdateSequenceNumber(highUpdateSequenceNumber);
}
if (reader.name().equalsIgnoreCase("note") && reader.isStartElement()) {
processNoteNode();
if (backup)
conn.getNoteTable().addNote(note, noteIsDirty);
else {
note.setUpdateSequenceNum(0);
if (notebookGuid != null)
note.setNotebookGuid(notebookGuid);
for (int i=0; i<note.getResourcesSize(); i++) {
note.getResources().get(i).setUpdateSequenceNum(0);
}
conn.getNoteTable().addNote(note, true);
}
if (metaData.containsKey(note.getGuid()))
conn.getNoteTable().updateNoteMetadata(metaData.get(note.getGuid()));
}
if (reader.name().equalsIgnoreCase("notebook") && reader.isStartElement() && (backup || importNotebooks)) {
processNotebookNode();
String existingGuid = conn.getNotebookTable().findNotebookByName(notebook.getName());
if (existingGuid == null) {
conn.getNotebookTable().addNotebook(notebook, notebookIsDirty, notebookIsLocal);
} else {
conn.getNotebookTable().updateNotebookGuid(existingGuid, notebook.getGuid());
conn.getNotebookTable().updateNotebook(notebook, notebookIsDirty);
}
conn.getNotebookTable().setIcon(notebook.getGuid(), notebookIcon, "PNG");
conn.getNotebookTable().setReadOnly(notebook.getGuid(), notebookIsReadOnly);
}
if (reader.name().equalsIgnoreCase("tag") && reader.isStartElement() && (backup || importTags)) {
processTagNode();
String testGuid = conn.getTagTable().findTagByName(tag.getName());
if (testGuid == null)
conn.getTagTable().addTag(tag, tagIsDirty);
else {
conn.getTagTable().updateTagGuid(testGuid, tag.getGuid());
conn.getTagTable().updateTag(tag,tagIsDirty);
}
}
if (reader.name().equalsIgnoreCase("savedsearch") && reader.isStartElement() && backup) {
processSavedSearchNode();
conn.getSavedSearchTable().addSavedSearch(search, searchIsDirty);
}
if (reader.name().equalsIgnoreCase("LinkedNotebook") && reader.isStartElement() && backup) {
processLinkedNotebookNode();
conn.getLinkedNotebookTable().addNotebook(linkedNotebook, linkedNotebookIsDirty);
}
if (reader.name().equalsIgnoreCase("SharedNotebook") && reader.isStartElement() && backup) {
processSharedNotebookNode();
conn.getSharedNotebookTable().addNotebook(sharedNotebook, sharedNotebookIsDirty);
}
}
xmlFile.close();
}
private void processNoteNode() {
note = new Note();
note.setResources(new ArrayList<Resource>());
boolean atEnd = false;
while(!atEnd) {
if (reader.isStartElement()) {
if (reader.name().equalsIgnoreCase("Guid")) {
note.setGuid(textValue());
if (!backup) {
Random random1 = new Random();
String newGuid = "IMP" +new Integer(random1.nextInt(1000)).toString();
newGuid = newGuid+"-"+new Integer(random1.nextInt(1000)).toString();
newGuid = newGuid+"-"+new Integer(random1.nextInt(1000)).toString();
newGuid = newGuid+"-"+new Integer(random1.nextInt(1000)).toString();
noteMap.put(note.getGuid(), newGuid);
note.setGuid(newGuid);
} else
noteMap.put(note.getGuid(), note.getGuid());
}
if (reader.name().equalsIgnoreCase("UpdateSequenceNumber"))
note.setUpdateSequenceNum(intValue());
if (reader.name().equalsIgnoreCase("Title"))
note.setTitle(textValue());
if (reader.name().equalsIgnoreCase("Created"))
note.setCreated(longValue());
if (reader.name().equalsIgnoreCase("Updated"))
note.setUpdated(longValue());
if (reader.name().equalsIgnoreCase("Deleted"))
note.setDeleted(longValue());
if (reader.name().equalsIgnoreCase("Active"))
note.setActive(booleanValue());
if (reader.name().equalsIgnoreCase("NotebookGuid"))
note.setNotebookGuid(textValue());
if (reader.name().equalsIgnoreCase("Content"))
note.setContent(textValue());
if (reader.name().equalsIgnoreCase("NoteTags"))
note.setTagGuids(processNoteTagList());
if (reader.name().equalsIgnoreCase("NoteAttributes"))
note.setAttributes(processNoteAttributes());
if (reader.name().equalsIgnoreCase("NoteResource"))
note.getResources().add(processResource());
if (reader.name().equalsIgnoreCase("Dirty")) {
if (booleanValue())
noteIsDirty=true;
}
if (reader.name().equalsIgnoreCase("TitleColor")) {
if (metaData.get(note.getGuid()) == null) {
NoteMetadata m = new NoteMetadata();
m.setColor(intValue());
metaData.put(note.getGuid(), m);
} else
metaData.get(note.getGuid()).setColor(intValue());
}
}
reader.readNext();
if (reader.name().equalsIgnoreCase("note") && reader.isEndElement())
atEnd = true;
}
return;
}
private Resource processResource() {
Resource resource = new Resource();
boolean atEnd = false;
boolean isDirty = false;
while(!atEnd) {
if (reader.isStartElement()) {
if (reader.name().equalsIgnoreCase("Guid"))
resource.setGuid(textValue());
if (!backup) {
Random random1 = new Random();
String newGuid = "IMP" +new Integer(random1.nextInt(1000)).toString();
newGuid = newGuid+"-"+new Integer(random1.nextInt(1000)).toString();
newGuid = newGuid+"-"+new Integer(random1.nextInt(1000)).toString();
newGuid = newGuid+"-"+new Integer(random1.nextInt(1000)).toString();
resource.setGuid(newGuid);
}
if (reader.name().equalsIgnoreCase("NoteGuid")) {
String tx = textValue();
resource.setNoteGuid(noteMap.get(textValue()));
resource.setNoteGuid(noteMap.get(tx));
}
if (reader.name().equalsIgnoreCase("UpdateSequenceNumber"))
resource.setUpdateSequenceNum(intValue());
if (reader.name().equalsIgnoreCase("Active"))
resource.setActive(booleanValue());
if (reader.name().equalsIgnoreCase("Mime"))
resource.setMime(textValue());
if (reader.name().equalsIgnoreCase("Duration"))
resource.setDuration(shortValue());
if (reader.name().equalsIgnoreCase("Height"))
resource.setHeight(shortValue());
if (reader.name().equalsIgnoreCase("Width"))
resource.setWidth(shortValue());
if (reader.name().equalsIgnoreCase("dirty"))
isDirty = booleanValue();
if (reader.name().equalsIgnoreCase("Data"))
resource.setData(processData("Data"));
if (reader.name().equalsIgnoreCase("AlternateData"))
resource.setAlternateData(processData("AlternateData"));
if (reader.name().equalsIgnoreCase("RecognitionData"))
resource.setRecognition(processData("RecognitionData"));
if (reader.name().equalsIgnoreCase("NoteResourceAttribute"))
resource.setAttributes(processResourceAttributes());
}
reader.readNext();
if (reader.name().equalsIgnoreCase("noteresource") && reader.isEndElement())
atEnd = true;
}
conn.getNoteTable().noteResourceTable.saveNoteResource(resource, isDirty);
return resource;
}
private Data processData(String nodeName) {
Data data = new Data();
boolean atEnd = false;
while(!atEnd) {
if (reader.isStartElement()) {
if (reader.name().equalsIgnoreCase("Size"))
data.setSize(intValue());
if (reader.name().equalsIgnoreCase("Body")) {
byte[] b = textValue().getBytes(); // data binary
QByteArray hexData = new QByteArray(b);
QByteArray binData = new QByteArray(QByteArray.fromHex(hexData));
data.setBody(binData.toByteArray());
}
if (reader.name().equalsIgnoreCase("BodyHash")) {
byte[] b = textValue().getBytes(); // data binary
QByteArray hexData = new QByteArray(b);
QByteArray binData = new QByteArray(QByteArray.fromHex(hexData));
data.setBodyHash(binData.toByteArray());
}
reader.readNext();
if (reader.name().equalsIgnoreCase("data") && reader.isEndElement())
atEnd = true;
}
reader.readNext();
if (reader.name().equalsIgnoreCase(nodeName) && reader.isEndElement())
atEnd = true;
}
return data;
}
private ResourceAttributes processResourceAttributes() {
ResourceAttributes attributes = new ResourceAttributes();
boolean atEnd = false;
while(!atEnd) {
if (reader.isStartElement()) {
if (reader.name().equalsIgnoreCase("CameraMake"))
attributes.setCameraMake(textValue());
if (reader.name().equalsIgnoreCase("CameraModel"))
attributes.setCameraModel(textValue());
if (reader.name().equalsIgnoreCase("FileName"))
attributes.setFileName(textValue());
if (reader.name().equalsIgnoreCase("RecoType"))
attributes.setRecoType(textValue());
if (reader.name().equalsIgnoreCase("CameraModel"))
attributes.setCameraMake(textValue());
if (reader.name().equalsIgnoreCase("SourceURL"))
attributes.setSourceURL(textValue());
if (reader.name().equalsIgnoreCase("Altitude"))
attributes.setAltitude(doubleValue());
if (reader.name().equalsIgnoreCase("Longitude"))
attributes.setLongitude(doubleValue());
if (reader.name().equalsIgnoreCase("Latitude"))
attributes.setLatitude(doubleValue());
if (reader.name().equalsIgnoreCase("Timestamp"))
attributes.setTimestamp(longValue());
if (reader.name().equalsIgnoreCase("Attachment"))
attributes.setAttachment(booleanValue());
if (reader.name().equalsIgnoreCase("ClientWillIndex"))
attributes.setClientWillIndex(booleanValue());
}
reader.readNext();
if (reader.name().equalsIgnoreCase("noteresourceattribute") && reader.isEndElement())
atEnd = true;
}
return attributes;
}
private List<String> processNoteTagList() {
List<String> guidList = new ArrayList<String>();
boolean atEnd = false;
while(!atEnd) {
if (reader.isStartElement()) {
if (reader.name().equalsIgnoreCase("guid"))
guidList.add(textValue());
}
reader.readNext();
if (reader.name().equalsIgnoreCase("notetags") && reader.isEndElement())
atEnd = true;
}
return guidList;
}
private NoteAttributes processNoteAttributes() {
NoteAttributes attributes = new NoteAttributes();
boolean atEnd = false;
while(!atEnd) {
if (reader.isStartElement()) {
if (reader.name().equalsIgnoreCase("Author"))
attributes.setAuthor(textValue());
if (reader.name().equalsIgnoreCase("SourceURL"))
attributes.setSourceURL(textValue());
if (reader.name().equalsIgnoreCase("Source"))
attributes.setSource(textValue());
if (reader.name().equalsIgnoreCase("SourceApplication"))
attributes.setSourceApplication(textValue());
if (reader.name().equalsIgnoreCase("Altitude"))
attributes.setAltitude(doubleValue());
if (reader.name().equalsIgnoreCase("Longitude"))
attributes.setLongitude(doubleValue());
if (reader.name().equalsIgnoreCase("Latitude"))
attributes.setLatitude(doubleValue());
if (reader.name().equalsIgnoreCase("SubjectDate"))
attributes.setSubjectDate(longValue());
}
reader.readNext();
if (reader.name().equalsIgnoreCase("noteattributes") && reader.isEndElement())
atEnd = true;
}
return attributes;
}
private void processSynchronizationNode() {
boolean atEnd = false;
while(!atEnd) {
if (reader.isStartElement()) {
if (reader.name().equalsIgnoreCase("UpdateSequenceNumber"))
highUpdateSequenceNumber = intValue();
if (reader.name().equalsIgnoreCase("LastSequenceDate"))
lastSequenceDate = longValue();
}
reader.readNext();
if (reader.name().equalsIgnoreCase("synchronization") && reader.isEndElement())
atEnd = true;
}
}
private void processSavedSearchNode() {
search = new SavedSearch();
searchIsDirty = false;
boolean atEnd = false;
while(!atEnd) {
if (reader.isStartElement()) {
if (reader.name().equalsIgnoreCase("Guid"))
search.setGuid(textValue());
if (reader.name().equalsIgnoreCase("Name"))
search.setName(textValue());
if (reader.name().equalsIgnoreCase("UpdateSequenceNumber"))
search.setUpdateSequenceNum(intValue());
if (reader.name().equalsIgnoreCase("Query"))
search.setQuery(textValue());
if (reader.name().equalsIgnoreCase("Dirty")) {
if (booleanValue())
searchIsDirty = true;
}
}
reader.readNext();
if (reader.name().equalsIgnoreCase("savedsearch") && reader.isEndElement())
atEnd = true; }
return;
}
private void processLinkedNotebookNode() {
linkedNotebook = new LinkedNotebook();
linkedNotebookIsDirty = false;
boolean atEnd = false;
while(!atEnd) {
if (reader.isStartElement()) {
if (reader.name().equalsIgnoreCase("Guid"))
linkedNotebook.setGuid(textValue());
if (reader.name().equalsIgnoreCase("ShardID"))
linkedNotebook.setShardId(textValue());
if (reader.name().equalsIgnoreCase("UpdateSequenceNumber"))
linkedNotebook.setUpdateSequenceNum(intValue());
if (reader.name().equalsIgnoreCase("ShareKey"))
linkedNotebook.setShareKey(textValue());
if (reader.name().equalsIgnoreCase("ShareName"))
linkedNotebook.setShareName(textValue());
if (reader.name().equalsIgnoreCase("Uri"))
linkedNotebook.setUri(textValue());
if (reader.name().equalsIgnoreCase("Username"))
linkedNotebook.setUsername(textValue());
if (reader.name().equalsIgnoreCase("Dirty")) {
if (booleanValue())
linkedNotebookIsDirty = true;
}
}
reader.readNext();
if (reader.name().equalsIgnoreCase("LinkedNotebook") && reader.isEndElement())
atEnd = true; }
return;
}
private void processSharedNotebookNode() {
sharedNotebook = new SharedNotebook();
sharedNotebookIsDirty = false;
boolean atEnd = false;
while(!atEnd) {
if (reader.isStartElement()) {
if (reader.name().equalsIgnoreCase("Id"))
sharedNotebook.setId(intValue());
if (reader.name().equalsIgnoreCase("Userid"))
sharedNotebook.setUserId(intValue());
if (reader.name().equalsIgnoreCase("Email"))
sharedNotebook.setEmail(textValue());
if (reader.name().equalsIgnoreCase("NotebookGuid"))
sharedNotebook.setNotebookGuid(textValue());
if (reader.name().equalsIgnoreCase("ShareKey"))
sharedNotebook.setShareKey(textValue());
if (reader.name().equalsIgnoreCase("Username"))
sharedNotebook.setUsername(textValue());
if (reader.name().equalsIgnoreCase("ServiceCreated"))
sharedNotebook.setServiceCreated(longValue());
if (reader.name().equalsIgnoreCase("Dirty")) {
if (booleanValue())
sharedNotebookIsDirty = true;
}
}
reader.readNext();
if (reader.name().equalsIgnoreCase("LinkedNotebook") && reader.isEndElement())
atEnd = true; }
return;
}
private void processNotebookNode() {
notebook = new Notebook();
Publishing p = new Publishing();
notebook.setPublishing(p);
notebookIsDirty = false;
notebookIsLocal = false;
notebookIsReadOnly = false;
notebookIcon = null;
boolean atEnd = false;
while(!atEnd) {
if (backup || importNotebooks) {
if (reader.isStartElement()) {
if (reader.name().equalsIgnoreCase("Guid"))
notebook.setGuid(textValue());
if (reader.name().equalsIgnoreCase("Name"))
notebook.setName(textValue());
if (reader.name().equalsIgnoreCase("UpdateSequenceNumber"))
notebook.setUpdateSequenceNum(intValue());
if (reader.name().equalsIgnoreCase("ServiceCreated"))
notebook.setServiceCreated(longValue());
if (reader.name().equalsIgnoreCase("ServiceUpdated"))
notebook.setServiceUpdated(longValue());
if (reader.name().equalsIgnoreCase("DefaultNotebook")) {
notebook.setDefaultNotebook(booleanValue());
}
if (reader.name().equalsIgnoreCase("Dirty")) {
if (booleanValue())
notebookIsDirty = true;
}
if (reader.name().equalsIgnoreCase("LocalNotebook")) {
if (booleanValue())
notebookIsLocal = true;
}
if (reader.name().equalsIgnoreCase("ReadOnly")) {
if (booleanValue())
notebookIsReadOnly = true;
}
if (reader.name().equalsIgnoreCase("PublishingPublicDescription")) {
notebook.getPublishing().setPublicDescription(textValue());
}
if (reader.name().equalsIgnoreCase("PublishingUri")) {
notebook.getPublishing().setUri(textValue());
}
if (reader.name().equalsIgnoreCase("PublishingOrder")) {
notebook.getPublishing().setOrder(NoteSortOrder.findByValue(intValue()));
}
if (reader.name().equalsIgnoreCase("ReadOnly")) {
if (booleanValue())
notebookIsReadOnly = true;
}
if (reader.name().equalsIgnoreCase("PublishingAscending")) {
if (booleanValue())
notebook.getPublishing().setAscending(true);
else
notebook.getPublishing().setAscending(false);
}
if (reader.name().equalsIgnoreCase("Icon")) {
byte[] b = textValue().getBytes(); // data binary
QByteArray hexData = new QByteArray(b);
QByteArray binData = new QByteArray(QByteArray.fromHex(hexData));
notebookIcon = new QIcon(QPixmap.fromImage(QImage.fromData(binData)));
}
if (reader.name().equalsIgnoreCase("Stack"))
notebook.setStack(textValue());
}
}
reader.readNext();
if (reader.name().equalsIgnoreCase("notebook") && reader.isEndElement())
atEnd = true;
}
return;
}
private void processTagNode() {
tag = new Tag();
tagIsDirty = false;
boolean atEnd = false;
while(!atEnd) {
if (backup || importTags) {
if (reader.isStartElement()) {
if (reader.name().equalsIgnoreCase("Guid"))
tag.setGuid(textValue());
if (reader.name().equalsIgnoreCase("Name"))
tag.setName(textValue());
if (reader.name().equalsIgnoreCase("UpdateSequenceNumber"))
tag.setUpdateSequenceNum(intValue());
if (reader.name().equalsIgnoreCase("ParentGuid"))
tag.setParentGuid(textValue());
if (reader.name().equalsIgnoreCase("Dirty")) {
if (booleanValue())
tagIsDirty = true;
}
}
}
reader.readNext();
if (reader.name().equalsIgnoreCase("tag") && reader.isEndElement())
atEnd = true;
}
return;
}
private String textValue() {
return reader.readElementText();
}
private int intValue() {
return new Integer(textValue());
}
private long longValue() {
return new Long(textValue());
}
private double doubleValue() {
return new Double(textValue());
}
private boolean booleanValue() {
String value = textValue();
if (value.equalsIgnoreCase("true"))
return true;
else
return false;
}
private short shortValue() {
return new Short(textValue());
}
public void setNotebookGuid(String g) {
notebookGuid = g;
}
public String getErrorMessage() {
return errorMessage;
}
}