1
////////////////////////////////////////////////////////////////////////////
2
// NoteCase notes manager project <http://notecase.sf.net>
4
// This code is licensed under BSD license.See "license.txt" for more details.
6
// File: Implements MM/LX Mindmap/Outline document format I/O (reading only)
7
////////////////////////////////////////////////////////////////////////////
10
#pragma warning(disable: 4996) //ignore deprecated functions warning
13
#include "FormatIOMMLX.h"
14
#include "DocumentIterator.h"
16
#include "../config.h"
17
#include "../support.h"
18
#include <stdio.h> //fopen
26
#define strcasecmp stricmp
30
void replaceall(std::string &strData, const char *szFind, const char *szReplace);
31
int gtkMessageBox(const char *szText, int nButtons = GTK_BUTTONS_OK, int nIcon = GTK_MESSAGE_INFO);
33
FormatIO_MMLX::FormatIO_MMLX()
35
m_nCurParentID = -1; //TOFIX use Idx for faster operation
37
m_nLastNodeLevel = -1;
39
m_nCoversionFailuresCnt = 0;
42
FormatIO_MMLX::~FormatIO_MMLX()
46
int FormatIO_MMLX::Load(const char *szFile, NoteDocument &doc)
48
m_pDoc = &doc; //store pointer
50
//clear old document contents
53
FILE *pInFile = fopen(szFile, "r");
55
return DOC_LOAD_NOT_FOUND;
61
//TOFIX error handling
62
while(NULL != fgets(szBuffer, sizeof(szBuffer), pInFile))
64
RunLoop(); //enable progress painting events
66
//kill new line char(s)
67
if('\n'== szBuffer[strlen(szBuffer)-1])
68
szBuffer[strlen(szBuffer)-1] = '\0';
69
if('\r'== szBuffer[strlen(szBuffer)-1])
70
szBuffer[strlen(szBuffer)-1] = '\0';
78
if(m_nCoversionFailuresCnt > 0)
79
gtkMessageBox(_("There were problems converting text from ibm850 to utf-8.\nConsider installing \"glibc-gconv-ibm850\" package"));
85
int FormatIO_MMLX::Save(const char *szFile, NoteDocument &doc)
87
return DOC_SAVE_NOT_SUPPORTED; //export not implemented
90
void FormatIO_MMLX::ParseLine(char *szBuffer)
92
int nLen = (szBuffer) ? strlen(szBuffer) : 0;
95
if(0 == nLen || (nLen > 0 && szBuffer[0] != ' ')){
98
//calculate depth of the new node (number of spaces before title)
99
//NOTE: it might turn out that the text is not really a text ;)
102
char *szPos = szBuffer;
105
nSpaces ++; szPos ++;
109
bIsText = true; // it is probably a text then
114
//append the text line to the current node
115
int nIdx = m_pDoc->GetIdxFromID(m_nCurNodeID);
118
//parse out <NF1> tag (equals to empty line)
119
if(0 == strcmp("<NF1>", szBuffer)){
120
m_pDoc->GetNodeByIdx(nIdx).GetText() += "\n";
123
//parse out <NF0> tag
124
if(0 == strcmp("<NF0>", szBuffer))
127
//handle MM/LX subformat with text line indented and prefixed with '|'
128
const char *szPos = szBuffer;
129
if(szBuffer[0] == '|'){
131
int nMax = (m_nLastNodeLevel + 2) * 3 - 1;
132
for(int i=0; i<nMax; i++)
139
//append text line to the current node
140
gchar *strUtf8 = g_convert(szPos, strlen (szPos), "UTF-8", "ibm850", NULL, NULL, NULL);
141
ASSERT(NULL != strUtf8);
143
m_pDoc->GetNodeByIdx(nIdx).GetText() += strUtf8;
144
m_pDoc->GetNodeByIdx(nIdx).GetText() += "\n";
147
else //on error, fall back to unconverted text
149
m_nCoversionFailuresCnt ++;
150
m_pDoc->GetNodeByIdx(nIdx).GetText() += szPos;
151
m_pDoc->GetNodeByIdx(nIdx).GetText() += "\n";
156
char *szPos = szBuffer + nSpaces;
158
//calculate depth of the new node
159
int nLevel = nSpaces/3 - 1; //starts from 0
161
std::string strLinkUrl;
162
bool bFinished = false;
164
//check for link type 1 (link to another map file)
165
char *szPosLink1 = strchr(szPos, 0x18);
166
if(NULL != szPosLink1){
170
//check if link points to some subnode within the map
171
char *szHash = strchr(szPosLink1, '#');
173
*szHash = '\0'; //cut the hash part (currently not supported by notecase)
176
gchar *strLinkUtf8 = g_convert(szPosLink1, strlen (szPosLink1), "UTF-8", "ibm850", NULL, NULL, NULL);
177
ASSERT(NULL != strLinkUtf8);
178
if(NULL != strLinkUtf8){
179
strLinkUrl = strLinkUtf8;
182
else{ //on error, fall back to unconverted text
183
m_nCoversionFailuresCnt ++;
184
strLinkUrl = szPosLink1;
188
// check for link type 2 (link to ordinary file)
189
szPosLink1 = strchr(szPos, 0x19);
190
if(NULL != szPosLink1){
195
gchar *strLinkUtf8 = g_convert(szPosLink1, strlen (szPosLink1), "UTF-8", "ibm850", NULL, NULL, NULL);
196
ASSERT(NULL != strLinkUtf8);
197
if(NULL != strLinkUtf8){
198
strLinkUrl = strLinkUtf8;
201
else{ //on error, fall back to unconverted text
202
m_nCoversionFailuresCnt ++;
203
strLinkUrl = szPosLink1;
208
//check for finished char
209
char *szPosFinished = strchr(szPos, 0xFB);
210
if(NULL != szPosFinished){
211
*szPosFinished = '\0';
216
if(strlen (szPos) == 0)
217
TRACE("ERROR: Invalid MM/LX file. Empty title detected!\n");
220
//convert text before using it
221
gchar *strUtf8 = g_convert(szPos, strlen (szPos), "UTF-8", "ibm850", NULL, NULL, NULL);
222
ASSERT(NULL != strUtf8);
226
TRACE("ERROR: Failed to convert from ibm850\n");
229
if(nLevel > m_nLastNodeLevel)
231
//insert node as child of current node
232
m_pDoc->NodeInsert(m_nCurNodeID, -1);
233
m_nCurParentID = m_nCurNodeID; //current node will become a new parent
234
m_nCurNodeID = m_pDoc->GetNodeByIdx(m_pDoc->GetNodeCount()-1).m_nID;
236
else if(nLevel == m_nLastNodeLevel)
238
//insert node as sibling of current node
239
m_pDoc->NodeInsert(m_nCurParentID, -1);
240
m_nCurNodeID = m_pDoc->GetNodeByIdx(m_pDoc->GetNodeCount()-1).m_nID;
243
DocumentIterator it(*m_pDoc);
245
//step back X levels and create child there
246
int nDiff = m_nLastNodeLevel - nLevel;
247
while(nDiff > 0 && m_nCurParentID >= 0){
248
m_nCurParentID = it.GetNodeByID(m_nCurParentID).m_nParentID;
252
m_pDoc->NodeInsert(m_nCurParentID, -1);
253
m_nCurNodeID = m_pDoc->GetNodeByIdx(m_pDoc->GetNodeCount()-1).m_nID;
257
if(strLinkUrl.size() > 0){
258
m_pDoc->GetNodeByIdx(m_pDoc->GetNodeCount()-1).m_objLink.m_strTargetURL = strLinkUrl;
263
m_pDoc->GetNodeByIdx(m_pDoc->GetNodeCount()-1).m_bFinished = true;
267
if(NULL == strUtf8){ //on error, fall back to unconverted text
268
m_nCoversionFailuresCnt ++;
273
std::string strTitle(strUtf8);
275
//remove hotkey (&) cahracter if found
276
replaceall(strTitle, "&", "");
278
//recognize if the title is an icon
279
if(strTitle.size() > 4){
280
if(0 == strcasecmp(strTitle.substr(strTitle.size()-4).c_str(), ".icn")){
281
strTitle.insert(0, "[ICON: ");
286
m_pDoc->GetNodeByIdx(m_pDoc->GetNodeCount()-1).SetTitle(strTitle.c_str());
291
m_nLastNodeLevel = nLevel;
1
////////////////////////////////////////////////////////////////////////////
2
// NoteCase notes manager project <http://notecase.sf.net>
4
// This code is licensed under BSD license.See "license.txt" for more details.
6
// File: Implements MM/LX Mindmap/Outline document format I/O (reading only)
7
////////////////////////////////////////////////////////////////////////////
10
#pragma warning(disable: 4996) //ignore deprecated functions warning
13
#include "FormatIOMMLX.h"
14
#include "DocumentIterator.h"
16
#include "../config.h"
17
#include "../support.h"
18
#include <stdio.h> //fopen
26
#define strcasecmp stricmp
30
void replaceall(std::string &strData, const char *szFind, const char *szReplace);
31
int gtkMessageBox(const char *szText, int nButtons = GTK_BUTTONS_OK, int nIcon = GTK_MESSAGE_INFO);
33
FormatIO_MMLX::FormatIO_MMLX()
35
m_nCurParentID = -1; //TOFIX use Idx for faster operation
37
m_nLastNodeLevel = -1;
39
m_nCoversionFailuresCnt = 0;
42
FormatIO_MMLX::~FormatIO_MMLX()
46
int FormatIO_MMLX::Load(const char *szFile, NoteDocument &doc)
48
m_pDoc = &doc; //store pointer
50
//clear old document contents
53
FILE *pInFile = fopen(szFile, "r");
55
return DOC_LOAD_NOT_FOUND;
61
//TOFIX error handling
62
while(NULL != fgets(szBuffer, sizeof(szBuffer), pInFile))
64
RunLoop(); //enable progress painting events
66
//kill new line char(s)
67
if('\n'== szBuffer[strlen(szBuffer)-1])
68
szBuffer[strlen(szBuffer)-1] = '\0';
69
if('\r'== szBuffer[strlen(szBuffer)-1])
70
szBuffer[strlen(szBuffer)-1] = '\0';
78
if(m_nCoversionFailuresCnt > 0)
79
gtkMessageBox(_("There were problems converting text from ibm850 to utf-8.\nConsider installing \"glibc-gconv-ibm850\" package"));
85
int FormatIO_MMLX::Save(const char *szFile, NoteDocument &doc)
87
return DOC_SAVE_NOT_SUPPORTED; //export not implemented
90
void FormatIO_MMLX::ParseLine(char *szBuffer)
92
int nLen = (szBuffer) ? strlen(szBuffer) : 0;
95
if(0 == nLen || (nLen > 0 && szBuffer[0] != ' ')){
98
//calculate depth of the new node (number of spaces before title)
99
//NOTE: it might turn out that the text is not really a text ;)
102
char *szPos = szBuffer;
105
nSpaces ++; szPos ++;
109
bIsText = true; // it is probably a text then
114
//append the text line to the current node
115
int nIdx = m_pDoc->GetIdxFromID(m_nCurNodeID);
118
//parse out <NF1> tag (equals to empty line)
119
if(0 == strcmp("<NF1>", szBuffer)){
120
m_pDoc->GetNodeByIdx(nIdx).GetText() += "\n";
123
//parse out <NF0> tag
124
if(0 == strcmp("<NF0>", szBuffer))
127
//handle MM/LX subformat with text line indented and prefixed with '|'
128
const char *szPos = szBuffer;
129
if(szBuffer[0] == '|'){
131
int nMax = (m_nLastNodeLevel + 2) * 3 - 1;
132
for(int i=0; i<nMax; i++)
139
//append text line to the current node
140
gchar *strUtf8 = g_convert(szPos, strlen (szPos), "UTF-8", "ibm850", NULL, NULL, NULL);
141
ASSERT(NULL != strUtf8);
143
m_pDoc->GetNodeByIdx(nIdx).GetText() += strUtf8;
144
m_pDoc->GetNodeByIdx(nIdx).GetText() += "\n";
147
else //on error, fall back to unconverted text
149
m_nCoversionFailuresCnt ++;
150
m_pDoc->GetNodeByIdx(nIdx).GetText() += szPos;
151
m_pDoc->GetNodeByIdx(nIdx).GetText() += "\n";
156
char *szPos = szBuffer + nSpaces;
158
//calculate depth of the new node
159
int nLevel = nSpaces/3 - 1; //starts from 0
161
std::string strLinkUrl;
162
bool bFinished = false;
164
//check for link type 1 (link to another map file)
165
char *szPosLink1 = strchr(szPos, 0x18);
166
if(NULL != szPosLink1){
170
//check if link points to some subnode within the map
171
char *szHash = strchr(szPosLink1, '#');
173
*szHash = '\0'; //cut the hash part (currently not supported by notecase)
176
gchar *strLinkUtf8 = g_convert(szPosLink1, strlen (szPosLink1), "UTF-8", "ibm850", NULL, NULL, NULL);
177
ASSERT(NULL != strLinkUtf8);
178
if(NULL != strLinkUtf8){
179
strLinkUrl = strLinkUtf8;
182
else{ //on error, fall back to unconverted text
183
m_nCoversionFailuresCnt ++;
184
strLinkUrl = szPosLink1;
188
// check for link type 2 (link to ordinary file)
189
szPosLink1 = strchr(szPos, 0x19);
190
if(NULL != szPosLink1){
195
gchar *strLinkUtf8 = g_convert(szPosLink1, strlen (szPosLink1), "UTF-8", "ibm850", NULL, NULL, NULL);
196
ASSERT(NULL != strLinkUtf8);
197
if(NULL != strLinkUtf8){
198
strLinkUrl = strLinkUtf8;
201
else{ //on error, fall back to unconverted text
202
m_nCoversionFailuresCnt ++;
203
strLinkUrl = szPosLink1;
208
//check for finished char
209
char *szPosFinished = strchr(szPos, 0xFB);
210
if(NULL != szPosFinished){
211
*szPosFinished = '\0';
216
if(strlen (szPos) == 0)
217
TRACE("ERROR: Invalid MM/LX file. Empty title detected!\n");
220
//convert text before using it
221
gchar *strUtf8 = g_convert(szPos, strlen (szPos), "UTF-8", "ibm850", NULL, NULL, NULL);
222
ASSERT(NULL != strUtf8);
226
TRACE("ERROR: Failed to convert from ibm850\n");
229
if(nLevel > m_nLastNodeLevel)
231
//insert node as child of current node
232
m_pDoc->NodeInsert(m_nCurNodeID, -1);
233
m_nCurParentID = m_nCurNodeID; //current node will become a new parent
234
m_nCurNodeID = m_pDoc->GetNodeByIdx(m_pDoc->GetNodeCount()-1).m_nID;
236
else if(nLevel == m_nLastNodeLevel)
238
//insert node as sibling of current node
239
m_pDoc->NodeInsert(m_nCurParentID, -1);
240
m_nCurNodeID = m_pDoc->GetNodeByIdx(m_pDoc->GetNodeCount()-1).m_nID;
243
DocumentIterator it(*m_pDoc);
245
//step back X levels and create child there
246
int nDiff = m_nLastNodeLevel - nLevel;
247
while(nDiff > 0 && m_nCurParentID >= 0){
248
m_nCurParentID = it.GetNodeByID(m_nCurParentID).m_nParentID;
252
m_pDoc->NodeInsert(m_nCurParentID, -1);
253
m_nCurNodeID = m_pDoc->GetNodeByIdx(m_pDoc->GetNodeCount()-1).m_nID;
257
if(strLinkUrl.size() > 0){
258
m_pDoc->GetNodeByIdx(m_pDoc->GetNodeCount()-1).m_objLink.m_strTargetURL = strLinkUrl;
263
m_pDoc->GetNodeByIdx(m_pDoc->GetNodeCount()-1).m_bFinished = true;
267
if(NULL == strUtf8){ //on error, fall back to unconverted text
268
m_nCoversionFailuresCnt ++;
273
std::string strTitle(strUtf8);
275
//remove hotkey (&) cahracter if found
276
replaceall(strTitle, "&", "");
278
//recognize if the title is an icon
279
if(strTitle.size() > 4){
280
if(0 == strcasecmp(strTitle.substr(strTitle.size()-4).c_str(), ".icn")){
281
strTitle.insert(0, "[ICON: ");
286
m_pDoc->GetNodeByIdx(m_pDoc->GetNodeCount()-1).SetTitle(strTitle.c_str());
291
m_nLastNodeLevel = nLevel;