?? feed.cpp.svn-base
字號:
/**
* Feed.cpp
*
* Copyright (C) 2008 David Andrs <pda@jasnapaka.com>
*
* 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, see <http://www.gnu.org/licenses/>.
*
*/
#ifdef PRSSR_APP
#include "StdAfx.h"
#include "prssr.h"
#endif
#ifdef PRSSR_TODAY
#include "../prssrtoday/StdAfx.h"
#endif
#include "Feed.h"
#include "xml/FeedFile.h"
#include "Site.h"
#include "sha1/sha1.h"
#include "../share/reg.h"
#include "../share/helpers.h"
#include "../share/str.h"
#include "../share/cache.h"
#include "www/LocalHtmlFile.h"
#ifdef PRSSR_APP
#include "Config.h"
// #include "WebDownloader.h"
// #include "WebHtml.h"
#include "net/Connection.h"
#elif defined PRSSR_TODAY || PRSSR_TODAYSTUB
#include "../prssrtoday/Config.h"
#endif
#ifdef MYDEBUG
#undef THIS_FILE
static TCHAR THIS_FILE[] = _T(__FILE__);
#include "debug/crtdbg.h"
#define new MYDEBUG_NEW
#endif
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
//////////////////////////////////////////////////////////////////////
void FeedDiff(CFeed *first, CFeed *second, CArray<CFeedItem *, CFeedItem *> *diff) {
LOG0(5, "FeedDiff()");
CCache cache;
int i;
if (second != NULL)
for (i = 0; i < second->GetItemCount(); i++)
cache.AddItem(second->GetItem(i)->Hash);
if (first != NULL)
for (i = 0; i < first->GetItemCount(); i++) {
CFeedItem *fi = first->GetItem(i);
if (!cache.InCache(fi->Hash))
diff->Add(fi);
}
}
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
CFeedItem::CFeedItem(CSiteItem *si) {
SiteItem = si;
Flags = MESSAGE_NEW;
#ifdef PRSSR_APP
Hidden = FALSE;
ZeroMemory(&Date, sizeof(Date));
#endif
ZeroMemory(&PubDate, sizeof(PubDate));
}
CFeedItem::CFeedItem(const CFeedItem &o) {
SiteItem = o.SiteItem;
Hash = o.Hash;
Flags = o.Flags;
PubDate = o.PubDate;
Title = o.Title;
Link = o.Link;
#ifdef PRSSR_APP
Description = o.Description;
Hidden = o.Hidden;
Author = o.Author;
Date = o.Date;
while (!Enclosures.IsEmpty())
delete Enclosures.RemoveHead();
POSITION pos = o.Enclosures.GetHeadPosition();
while (pos != NULL) {
CEnclosureItem *enclosure = o.Enclosures.GetNext(pos);
Enclosures.AddTail(new CEnclosureItem(*enclosure));
}
for (int i = 0; i < o.KeywordPos.GetSize(); i++)
KeywordPos.SetAtGrow(i, o.KeywordPos[i]);
#endif
}
CFeedItem::~CFeedItem() {
#ifdef PRSSR_APP
while (!Enclosures.IsEmpty())
delete Enclosures.RemoveHead();
#endif
}
#if defined PRSSR_APP
void CFeedItem::ComputeHash(CString prefix) {
LOG0(5, "CFeedItem::ComputeHash()");
SHA1Context sha = { 0 };
int err;
uint8_t digest[20];
CString strMessage;
strMessage.Format(_T("%s%s%s"), prefix, Title, Link);
err = SHA1Reset(&sha);
err = SHA1Input(&sha, strMessage.GetBuffer(strMessage.GetLength()), strMessage.GetLength());
strMessage.ReleaseBuffer();
err = SHA1Result(&sha, digest);
// convert to string
LPTSTR hash = Hash.GetBufferSetLength(40);
TCHAR hexTab[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
for (int i = 0; i < 20; i++) {
hash[2 * i] = hexTab[digest[i] & 0x0F];
hash[(2 * i) + 1] = hexTab[(digest[i] >> 4) & 0x0F];
}
}
void CFeedItem::GetItemImages(CStringList &list) {
LOG0(5, "CFeedItem::GetItemImages()");
CString html;
html.Format(_T("<div>%s</div>"), Description); // workaround for libsgml
CLocalHtmlFile h;
h.LoadFromMemory(html);
h.ExtractImages(list);
}
void CFeedItem::GetEnclosures(CStringList &list, DWORD limit/* = 0*/) {
LOG0(5, "CFeedItem::GetEnclosures()");
POSITION pos = Enclosures.GetHeadPosition();
while (pos != NULL) {
CEnclosureItem *enclosure = Enclosures.GetNext(pos);
if (limit == 0 || enclosure->Length <= limit)
list.AddTail(enclosure->URL);
}
}
void CFeedItem::UpdateHiddenFlag() {
Hidden = FALSE;
}
#endif
void CFeedItem::SetFlags(DWORD flags, DWORD mask) {
Flags = (Flags & ~mask) | flags;
SiteItem->SetModified();
}
#if defined PRSSR_APP
void CFeedItem::SearchKeywords(CStringArray &keywords) {
LOG0(5, "CFeedItem::SearchKeywords()");
KeywordPos.RemoveAll();
for (int k = 0; k < keywords.GetSize(); k++) {
CString kword = keywords.GetAt(k);
CString text = StripHtmlTags(Description);
if (text.Find(kword) != -1) {
KeywordPos.Add(k);
}
}
}
#endif
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
CFeed::CFeed() {
FILETIME ft = { 0 };
#ifdef PRSSR_APP
memset(&Published, 0, sizeof(Published));
UpdateInterval = 0;
#endif
InitializeCriticalSection(&CS);
}
CFeed::~CFeed() {
DeleteCriticalSection(&CS);
}
// Load/Save
struct CArchiveFileChunkHeader {
char Id[4];
DWORD Size;
BOOL Load(CBufferedFile &file) {
if (!file.Read(Id, 4))
return FALSE;
if (!file.Read(&Size, 4))
return FALSE;
return TRUE;
}
BOOL Save(CBufferedFile &file) {
if (!file.Write(Id, 4))
return FALSE;
return file.Write(&Size, sizeof(DWORD));
}
};
struct CArchiveFileChunk {
CArchiveFileChunkHeader Header;
char *Data;
CList<CArchiveFileChunk *, CArchiveFileChunk*> Childs;
CArchiveFileChunk(char id[]) {
// assert(strlen(id) == 4);
strncpy(Header.Id, id, 4);
Header.Size = 0;
Data = NULL;
}
void Add(CArchiveFileChunk *chunk) {
// LOG1(5, "CArchiveFileChunk::Add(%p) - chunk", chunk);
Childs.AddTail(chunk);
}
void Add(char id[], const CString &str) {
// LOG2(5, "CArchiveFileChunk::Add('%s', '%S')", id, str);
CArchiveFileChunk *chunk = new CArchiveFileChunk(id);
chunk->Data = WCharToChar(str, CP_UTF8);
chunk->Header.Size = strlen(chunk->Data);
Add(chunk);
}
void Add(char id[], int number) {
// LOG2(5, "CArchiveFileChunk::Add('%s', %d)", id, number);
CArchiveFileChunk *chunk = new CArchiveFileChunk(id);
chunk->Data = new char [sizeof(int)];
memcpy(chunk->Data + 0, &number, sizeof(number));
chunk->Header.Size = sizeof(int);
Add(chunk);
}
void Add(char id[], SYSTEMTIME &st) {
// LOG1(5, "CArchiveFileChunk::Add('%s', ) - systime", id);
CArchiveFileChunk *chunk = new CArchiveFileChunk(id);
FILETIME ft;
SystemTimeToFileTime(&st, &ft);
chunk->Data = new char [sizeof(DWORD) * 2];
memcpy(chunk->Data + 0, &ft.dwHighDateTime, sizeof(DWORD));
memcpy(chunk->Data + 4, &ft.dwLowDateTime, sizeof(DWORD));
chunk->Header.Size = sizeof(DWORD) * 2;
Add(chunk);
}
void Add(char id[], CArray<int, int> &arr) {
// LOG2(5, "CArchiveFileChunk::Add('%s', %d)", id, number);
CArchiveFileChunk *chunk = new CArchiveFileChunk(id);
chunk->Data = new char [sizeof(int) * arr.GetSize()];
int *dest = (int *) chunk->Data;
for (int i = 0; i < arr.GetSize(); i++)
dest[i] = arr[i];
chunk->Header.Size = sizeof(int) * arr.GetSize();
Add(chunk);
}
~CArchiveFileChunk() {
delete [] Data;
while (!Childs.IsEmpty())
delete Childs.RemoveHead();
}
void CalcSize() {
// LOG0(5, "CArchiveFileChunk::CalcSize()");
if (Childs.GetCount() > 0) {
Header.Size = 0;
POSITION pos = Childs.GetHeadPosition();
while (pos != NULL) {
CArchiveFileChunk *fc = Childs.GetNext(pos);
fc->CalcSize();
Header.Size += fc->Header.Size + 8;
}
}
}
void Save(CBufferedFile &file) {
// LOG0(5, "CArchiveFileChunk::Save()");
Header.Save(file);
if (Childs.GetCount() > 0) {
POSITION pos = Childs.GetHeadPosition();
while (pos != NULL) {
CArchiveFileChunk *fc = Childs.GetNext(pos);
fc->Save(file);
}
}
else {
if (Data != NULL)
file.Write(Data, Header.Size);
}
}
};
static BOOL ReadString(CBufferedFile &file, int len, CString &str) {
if (len > 0) {
char *buffer = new char[len + 1];
memset(buffer, 0, sizeof(char) * (len + 1));
if (!file.Read(buffer, len)) {
delete [] buffer;
return FALSE;
}
str = CharToWChar(buffer, CP_UTF8);
delete [] buffer;
}
else
str.Empty();
return TRUE;
}
static BOOL ReadNumber(CBufferedFile &file, int &number) {
int i;
if (!file.Read(&i, sizeof(i)))
return FALSE;
number = i;
return TRUE;
}
static BOOL ReadNumber(CBufferedFile &file, DWORD &number) {
DWORD i;
if (!file.Read(&i, sizeof(i)))
return FALSE;
number = i;
return TRUE;
}
static BOOL ReadSystemTime(CBufferedFile &file, SYSTEMTIME &st) {
FILETIME ft;
char buffer[8];
if (!file.Read(buffer, sizeof(buffer)))
return FALSE;
memcpy(&ft.dwHighDateTime, buffer + 0, sizeof(DWORD));
memcpy(&ft.dwLowDateTime, buffer + 4, sizeof(DWORD));
FileTimeToSystemTime(&ft, &st);
return TRUE;
}
static BOOL ReadIntArray(CBufferedFile &file, int len, CArray<int, int> &array) {
for (int i = 0; i < (int) (len / sizeof(int)); i++) {
int number;
if (!ReadNumber(file, number))
return FALSE;
array.Add(number);
}
return TRUE;
}
BOOL CFeed::Load(LPCTSTR fileName, CSiteItem *si) {
LOG1(5, "CFeed::Load('%S')", fileName);
CBufferedFile file;
if (!file.Create(fileName, GENERIC_READ, FILE_SHARE_READ, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL))
return FALSE;
DWORD remain;
CArchiveFileChunkHeader header;
if (!header.Load(file) || strncmp(header.Id, "PRSS", 4) != 0)
return FALSE;
// LOG0(1, "- loading header");
// load HEAD
if (!header.Load(file) || strncmp(header.Id, "HEAD", 4) != 0)
return FALSE;
remain = header.Size;
while (remain > 0) {
CArchiveFileChunkHeader hdr;
if (!hdr.Load(file))
return FALSE;
remain -= 8; // sizeof(hdr)
if (strncmp(hdr.Id, "TITL", 4) == 0)
ReadString(file, hdr.Size, Title);
#ifdef PRSSR_APP
else if (strncmp(hdr.Id, "LINK", 4) == 0)
ReadString(file, hdr.Size, HtmlUrl);
else if (strncmp(hdr.Id, "DESC", 4) == 0)
ReadString(file, hdr.Size, Description);
else if (strncmp(hdr.Id, "PUBL", 4) == 0)
ReadSystemTime(file, Published);
else if (strncmp(hdr.Id, "LANG", 4) == 0)
ReadString(file, hdr.Size, Language);
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -