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 NoteCase HTML format (and NoteCenter format) I/O
7
////////////////////////////////////////////////////////////////////////////
9
#include "FormatHtml.h"
11
#include "DocumentIterator.h"
12
#include <stdio.h> //sprintf
14
#include <strings.h> //strcasecmp
16
#define strcasecmp stricmp
20
int InternalIcon_Name2Index(const char *szName);
21
const char *InternalIcon_Index2Name(int nIndex);
23
#define DOC_PARSE_BLANK 0
24
#define DOC_PARSE_EXPECT_TITLE 1
25
#define DOC_PARSE_EXPECT_TEXT 2
27
void replaceall(std::string &strData, const char *szFind, const char *szReplace);
28
void WriteLevel(DocumentIterator &it, File64 &file, int nParentID);
30
FormatHTML::FormatHTML()
34
m_nDocParseState = DOC_PARSE_BLANK;
35
m_bNoteCenterMode = false;
36
m_bHtmlExport = false;
37
m_nTagsParsedCount = 0;
40
FormatHTML::~FormatHTML()
44
int FormatHTML::Load(const char *szFile, NoteDocument &doc)
46
m_objDoc = &doc; //store pointer
48
//clear old document contents
52
if(!objFile.Open(szFile, F64_READ|F64_SHARE_READ|F64_OPEN_EXISTING))
53
return DOC_LOAD_NOT_FOUND;
58
//TOFIX better error handling
59
while((nRead = objFile.Read(szBuffer, sizeof(szBuffer))) > 0)
60
Parse(szBuffer, nRead);
62
//detect errors in file format (should have at least some HTML tags inside)
63
if(0 == m_nTagsParsedCount)
64
return DOC_LOAD_FORMAT_ERROR;
69
bool FormatHTML::Save(const char *szFile, NoteDocument &doc)
72
if(!objFile.Open(szFile, F64_WRITE|F64_SHARE_READ|F64_OPEN_NEW))
79
objFile.WriteString("<!DOCTYPE NoteCenter-File>\r\n");
81
objFile.WriteString("<!DOCTYPE NoteCase-File>\r\n");
83
//calc and write selected node "index"
85
sprintf(szLastNote, "<!--LastNote:%d-->\r\n", doc.m_nCurrentNode);
86
objFile.WriteString(szLastNote);
89
//write inital HTML tags including HEAD section
90
objFile.WriteString("<HTML>\r\n<HEAD>\r\n");
92
objFile.WriteString("<meta content=\"text/html;charset=UTF-8\" http-equiv=\"Content-Type\">");
93
objFile.WriteString("<TITLE>");
94
//TOFIX write file title as document title???
95
objFile.WriteString("</TITLE>\r\n</HEAD>\r\n<BODY BGCOLOR=\"#FFFFFF\">\r\n");
97
//recursively iterate through document node tree
98
DocumentIterator it(doc);
99
WriteLevel(it, objFile, -1);
102
objFile.WriteString("</BODY>\r\n</HTML>\r\n");
107
// HTMLParser event handlers
108
void FormatHTML::OnTagBegin(const char *szTag, const char *szParams)
110
//TRACE("FormatHTML:[%s] tag start\n", szTag);
112
m_nTagsParsedCount ++;
114
//if proper tag, create new node
115
if(0 == strcasecmp(szTag, "DL")) //DL indicates sublevel branching
117
m_nCurParentID = m_nCurNodeID;
120
else if(0 == strcasecmp(szTag, "DT")) //DT indicates new node title coming
122
m_objDoc->NodeInsert(m_nCurParentID, -1); //TOFIX error report
123
m_nCurNodeID = m_objDoc->GetNodeByIdx(m_objDoc->GetNodeCount()-1).m_nID;
124
m_nDocParseState = DOC_PARSE_EXPECT_TITLE;
126
else if(0 == strcasecmp(szTag, "DD")) //DD indicates new node text coming
128
m_nDocParseState = DOC_PARSE_EXPECT_TEXT;
132
void FormatHTML::OnTagEnd(const char *szTag)
134
//TRACE("FormatHTML:[%s] tag end\n", szTag);
136
//if proper tag, position on the parent node ?
137
if(0 == strcasecmp(szTag, "DL")) // </DL> indicates end of sublevel branching
139
int nIdx = m_objDoc->GetIdxFromID(m_nCurParentID);
141
m_nCurParentID = m_objDoc->GetNodeByIdx(nIdx).m_nParentID;
144
else if(0 == strcasecmp(szTag, "DT")) //DT indicates new node title coming
149
void FormatHTML::OnComment(const char *szText)
151
//TRACE("FormatHTML:[%s] HTML comment\n", szText);
153
//extract info from comments <!--LastNote:4-->
154
if(0 == strncmp(szText, "LastNote:", strlen("LastNote:")))
156
m_objDoc->m_nCurrentNode = atoi(szText+strlen("LastNote:"));
158
else if (0 == strncmp(szText, "property:icon_file=", strlen("property:icon_file=")))
160
//example tag: "<!--property:icon_file=/root/aaa.xpm-->"
161
//printf("icon_file->%s\n",szText);
162
DocumentIterator it(*m_objDoc);
163
it.GetNodeByID(m_nCurNodeID).m_nIconType = ICON_CUSTOM;
164
it.GetNodeByID(m_nCurNodeID).m_strIconFile = szText + strlen("property:icon_file=");
166
else if (0 == strncmp(szText, "property:icon_internal=", strlen("property:icon_internal=")))
168
//printf("icon_internal->%s\n",szText);
169
//example tag: "<!--property:icon_internal=blank-->"
170
DocumentIterator it(*m_objDoc);
171
int nIdx = InternalIcon_Name2Index(szText + strlen("property:icon_internal="));
173
it.GetNodeByID(m_nCurNodeID).m_nIconType = nIdx;
177
void FormatHTML::OnText(const char *szText)
179
std::string data(szText);
181
//TRACE("FormatHTML:[%s] HTML text\n", szText);
183
//set text or title for current node
184
if(DOC_PARSE_EXPECT_TITLE == m_nDocParseState)
186
//TRACE("FormatHTML:[%s] is node title \n", szText);
188
if(!m_bNoteCenterMode)
189
HTMLParser::UnescapeChars(data);
192
int nIdx = m_objDoc->GetIdxFromID(m_nCurNodeID);
194
m_objDoc->GetNodeByIdx(nIdx).SetTitle(data.c_str());
196
m_nDocParseState = DOC_PARSE_BLANK;
198
else if(DOC_PARSE_EXPECT_TEXT == m_nDocParseState)
200
//TRACE("FormatHTML:[%s] is node text\n", szText);
202
HTMLParser::UnescapeChars(data); //only for node text (NC format)
205
int nIdx = m_objDoc->GetIdxFromID(m_nCurNodeID);
207
//NoteCenter Text format: remove \r\n from text start and text end
208
if(0 == strncmp(data.c_str(), "\r\n", 2))
209
data = data.substr(2, data.size()-2);
210
if(0 == strncmp(data.c_str()+data.size()-2, "\r\n", 2))
211
data = data.substr(0, data.size()-2);
213
m_objDoc->GetNodeByIdx(nIdx).SetText(data.c_str());
216
m_nDocParseState = DOC_PARSE_BLANK;
220
void WriteLevel(DocumentIterator &it, File64 &file, int nParentID)
225
int nIdx = it.GetChildIdx(nParentID, 0); //first child
229
file.WriteString("\r\n<DL>\r\n");
234
strData = it.GetNodeByIdx(nIdx).GetTitle();
235
//TOFIX if(!m_bNoteCenterMode)
236
HTMLParser::EscapeChars(strData);
238
file.WriteString("<DT><H3>");
239
file.WriteString(strData.c_str());
240
file.WriteString("</H3></DT>\r\n");
242
//write node parameters (icon settings)
243
if(ICON_NONE != it.GetNodeByIdx(nIdx).m_nIconType)
245
if(ICON_CUSTOM == it.GetNodeByIdx(nIdx).m_nIconType)
247
file.WriteString("<!--property:icon_file=");
248
file.WriteString(it.GetNodeByIdx(nIdx).m_strIconFile.c_str());
249
file.WriteString("-->\r\n");
253
file.WriteString("<!--property:icon_internal=");
254
file.WriteString(InternalIcon_Index2Name(it.GetNodeByIdx(nIdx).m_nIconType));
255
file.WriteString("-->\r\n");
260
strData = it.GetNodeByIdx(nIdx).GetText();
261
//TOFIX if(!m_bNoteCenterMode)
262
HTMLParser::EscapeChars(strData);
264
//change all occurences "\r" to "\r\n"
265
replaceall(strData, "\r\n", "\r");
266
replaceall(strData, "\r", "\r\n");
268
file.WriteString("<DD><PRE>\r\n");
269
file.WriteString(strData.c_str());
270
file.WriteString("\r\n</PRE></DD>\r\n");
272
//recursively write children of this node
273
WriteLevel(it, file, it.GetNodeByIdx(nIdx).m_nID);
275
//go to the next sibling node
277
nIdx = it.GetChildIdx(nParentID, nSiblingIdx);
281
file.WriteString("</DL>\r\n");
284
void replaceall(std::string &strData, const char *szFind, const char *szReplace)
286
// std::replace(strData.begin(), strData.end(), szFind, szReplace);
288
int nSrcSize = strlen(szFind);
291
int nDstSize = strlen(szReplace);
293
size_t nPos = strData.find(szFind);
294
while(nPos != std::string::npos)
296
//strData.replace(nPos, nSrcSize, szReplace);
297
strData.erase(nPos, nSrcSize);
298
strData.insert(nPos, szReplace);
300
nPos = strData.find(szFind, nPos+nDstSize); //keep looking forward
305
int InternalIcon_Name2Index(const char *szName)
307
if(0 == strcmp("blank", szName))
309
else if(0 == strcmp("folder", szName))
311
else if(0 == strcmp("help", szName))
313
else if(0 == strcmp("lock", szName))
315
else if(0 == strcmp("new_dir", szName))
317
else if(0 == strcmp("recycle", szName))
323
const char *InternalIcon_Index2Name(int nIndex)
327
case 0: return "blank";
328
case 1: return "folder";
329
case 2: return "help";
330
case 3: return "lock";
331
case 4: return "new_dir";
332
case 5: return "recycle";
333
default: return NULL;