⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 feed.cpp.svn-base

📁 wince c++ 下 开发的 rss 阅读器源代码
💻 SVN-BASE
📖 第 1 页 / 共 2 页
字号:
/**
 *  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 + -