diff -Nru vdr-1.5.13/channels.c vdr-1.5.13-Speed-up-starting-and-stopping/channels.c --- vdr-1.5.13/channels.c 2008-01-20 12:24:53.000000000 +0100 +++ vdr-1.5.13-Speed-up-starting-and-stopping/channels.c 2008-01-20 13:00:18.000000000 +0100 @@ -179,7 +179,7 @@ modification = CHANNELMOD_NONE; schedule = NULL; linkChannels = NULL; - refChannel = NULL; + refChannels = NULL; } cChannel::cChannel(const cChannel &Channel) @@ -191,28 +191,26 @@ pluginParam = NULL; schedule = NULL; linkChannels = NULL; - refChannel = NULL; + refChannels = NULL; *this = Channel; } cChannel::~cChannel() { - delete linkChannels; - linkChannels = NULL; // more than one channel can link to this one, so we need the following loop - for (cChannel *Channel = Channels.First(); Channel; Channel = Channels.Next(Channel)) { - if (Channel->linkChannels) { - for (cLinkChannel *lc = Channel->linkChannels->First(); lc; lc = Channel->linkChannels->Next(lc)) { - if (lc->Channel() == this) { - Channel->linkChannels->Del(lc); - break; - } - } - if (Channel->linkChannels->Count() == 0) { - delete Channel->linkChannels; - Channel->linkChannels = NULL; - } - } - } + if (linkChannels) { + // in all channels which we link to remove the reference to us + for (cLinkChannel *lc = linkChannels->First(); lc; lc = linkChannels->Next(lc)) + lc->Channel()->DelRefChannel(this); + delete linkChannels; + linkChannels = NULL; + } + if (refChannels) { + // in all channels which reference us remove their link to us + for (cLinkChannel *lc = refChannels->First(); lc; lc = refChannels->Next(lc)) + lc->Channel()->DelLinkChannel(this); + delete refChannels; + refChannels = NULL; + } free(name); free(shortName); free(provider); @@ -589,7 +587,7 @@ q += sprintf(q, "linking channel %d from", Number()); if (linkChannels) { for (cLinkChannel *lc = linkChannels->First(); lc; lc = linkChannels->Next(lc)) { - lc->Channel()->SetRefChannel(NULL); + lc->Channel()->DelRefChannel(this); q += sprintf(q, " %d", lc->Channel()->Number()); } delete linkChannels; @@ -600,7 +598,7 @@ linkChannels = LinkChannels; if (linkChannels) { for (cLinkChannel *lc = linkChannels->First(); lc; lc = linkChannels->Next(lc)) { - lc->Channel()->SetRefChannel(this); + lc->Channel()->AddRefChannel(this); q += sprintf(q, " %d", lc->Channel()->Number()); //dsyslog("link %4d -> %4d: %s", Number(), lc->Channel()->Number(), lc->Channel()->Name()); } @@ -610,9 +608,39 @@ dsyslog(buffer); } -void cChannel::SetRefChannel(cChannel *RefChannel) +void cChannel::AddRefChannel(cChannel *RefChannel) { - refChannel = RefChannel; + if (!refChannels) + refChannels = new cLinkChannels; + refChannels->Add(new cLinkChannel(RefChannel)); +} + +void cChannel::DelRefChannel(cChannel *RefChannel) +{ + for (cLinkChannel *lc = refChannels->First(); lc; lc = refChannels->Next(lc)) { + if (lc->Channel() == RefChannel) { + refChannels->Del(lc); + if (refChannels->Count() <= 0) { + delete refChannels; + refChannels = NULL; + } + return; + } + } +} + +void cChannel::DelLinkChannel(cChannel *LinkChannel) +{ + for (cLinkChannel *lc = linkChannels->First(); lc; lc = linkChannels->Next(lc)) { + if (lc->Channel() == LinkChannel) { + linkChannels->Del(lc); + if (linkChannels->Count() <= 0) { + delete linkChannels; + linkChannels = NULL; + } + return; + } + } } static int PrintParameter(char *p, char Name, int Value) @@ -940,14 +968,72 @@ return false; } +void cChannels::ClearChannelHashes(void) +{ + channelsHashSid.Clear(); + channelsHashNidTid.Clear(); +} + void cChannels::HashChannel(cChannel *Channel) { channelsHashSid.Add(Channel, Channel->Sid()); + channelsHashNidTid.Add(Channel, HashKeyNidTid(Channel->Nid(), Channel->Tid())); } void cChannels::UnhashChannel(cChannel *Channel) { channelsHashSid.Del(Channel, Channel->Sid()); + channelsHashNidTid.Del(Channel, HashKeyNidTid(Channel->Nid(), Channel->Tid())); +} + +unsigned int cChannels::HashKeyNidTid(unsigned short Nid, unsigned short Tid) +{ + return Nid << 16 | Tid; +} + +cIterator cChannels::GetChannelsBySourceNidTid(int Source, unsigned short Nid, unsigned short Tid) +{ + class cIteratorImplSourceNidTid : public cIteratorImpl { + private: + cList *hashList; + cHashObject *current; + int source; + unsigned short nid; + unsigned short tid; + cChannel *FindMatchingChannel(bool reverse, bool reset = false) { + if (!hashList || (!current && !reset)) + return NULL; + while (true) { + if (reset) { + reset = false; + current = reverse ? hashList->Last() : hashList->First(); + } + else + current = reverse ? hashList->Prev(current) : hashList->Next(current); + if (!current) + break; + cChannel *Channel = (cChannel *)current->Object(); + if (Channel->Source() == source && Channel->Nid() == nid && Channel->Tid() == tid) + return Channel; + } + return NULL; + } + public: + cIteratorImplSourceNidTid(cList *HashList, int Source, unsigned short Nid, unsigned short Tid) { + hashList = HashList; + source = Source; + nid = Nid; + tid = Tid; + current = NULL; + } + virtual void *First(void) { return FindMatchingChannel(false, true); } + virtual void *Last(void) { return FindMatchingChannel(true, true); } + virtual void *Prev(void) { return FindMatchingChannel(false); } + virtual void *Next(void) { return FindMatchingChannel(true); } + virtual void *Current(void) const { return current ? (cChannel *)current->Object() : NULL; } + }; + + return cIterator(new cIteratorImplSourceNidTid(channelsHashNidTid.GetList(HashKeyNidTid(Nid, Tid)), Source, Nid, Tid)); } int cChannels::GetNextGroup(int Idx) @@ -984,7 +1070,7 @@ void cChannels::ReNumber( void ) { - channelsHashSid.Clear(); + ClearChannelHashes(); int Number = 1; for (cChannel *channel = First(); channel; channel = Next(channel)) { if (channel->GroupSep()) { diff -Nru vdr-1.5.13/channels.h vdr-1.5.13-Speed-up-starting-and-stopping/channels.h --- vdr-1.5.13/channels.h 2008-01-20 12:24:53.000000000 +0100 +++ vdr-1.5.13-Speed-up-starting-and-stopping/channels.h 2008-01-20 12:55:34.000000000 +0100 @@ -148,9 +148,12 @@ int modification; mutable const cSchedule *schedule; cLinkChannels *linkChannels; - cChannel *refChannel; + cLinkChannels *refChannels; cString ParametersToString(void) const; bool StringToParameters(const char *s); + void AddRefChannel(cChannel *RefChannel); + void DelRefChannel(cChannel *RefChannel); + void DelLinkChannel(cChannel *RefChannel); public: cChannel(void); cChannel(const cChannel &Channel); @@ -200,7 +203,8 @@ int Guard(void) const { return guard; } int Hierarchy(void) const { return hierarchy; } const cLinkChannels* LinkChannels(void) const { return linkChannels; } - const cChannel *RefChannel(void) const { return refChannel; } + const cChannel *RefChannel(void) const { return refChannels ? refChannels->Last()->Channel() : 0; } + const cLinkChannels* RefChannels(void) const { return refChannels; } bool IsPlug(void) const { return cSource::IsPlug(source); } bool IsCable(void) const { return cSource::IsCable(source); } bool IsSat(void) const { return cSource::IsSat(source); } @@ -221,7 +225,39 @@ void SetCaIds(const int *CaIds); // list must be zero-terminated void SetCaDescriptors(int Level); void SetLinkChannels(cLinkChannels *LinkChannels); - void SetRefChannel(cChannel *RefChannel); + }; + +class cIteratorImpl { +private: + int refCount; + cIteratorImpl(const cIteratorImpl &); + const cIteratorImpl &operator =(const cIteratorImpl &); +public: + cIteratorImpl(void) { refCount = 0; } + virtual ~cIteratorImpl() {} + virtual int AddRef(void) { return ++refCount; } + virtual int DelRef(void) { int RefCount = --refCount; if (RefCount <= 0) delete this; return RefCount; } + virtual void *First(void) = 0; + virtual void *Last(void) = 0; + virtual void *Prev(void) = 0; + virtual void *Next(void) = 0; + virtual void *Current(void) const = 0; + }; + +template class cIterator +{ +private: + cIteratorImpl *impl; +public: + cIterator(cIteratorImpl *Impl) { impl = Impl; impl->AddRef(); } + cIterator(const cIterator &rhs) { impl = rhs.impl; impl->AddRef(); } + ~cIterator() { impl->DelRef(); } + const cIterator &operator =(const cIterator &rhs) { rhs.impl->AddRef(); impl->DelRef(); impl = rhs.impl; return *this; } + T *First(void) const { return (T *)impl->First(); } + T *Last(void) const { return (T *)impl->Last(); } + T *Prev(void) const { return (T *)impl->Prev(); } + T *Next(void) const { return (T *)impl->Next(); } + T *Current(void) const { return (T *)impl->Current(); } }; class cChannels : public cRwLock, public cConfig { @@ -230,7 +266,10 @@ int modified; int beingEdited; cHash channelsHashSid; + cHash channelsHashNidTid; void DeleteDuplicateChannels(void); + void ClearChannelHashes(void); + static unsigned int HashKeyNidTid(unsigned short Nid, unsigned short Tid); public: cChannels(void); bool Load(const char *FileName, bool AllowComments = false, bool MustExist = false); @@ -245,6 +284,7 @@ cChannel *GetByServiceID(int Source, int Transponder, unsigned short ServiceID); cChannel *GetByChannelID(tChannelID ChannelID, bool TryWithoutRid = false, bool TryWithoutPolarization = false); cChannel *GetByTransponderID(tChannelID ChannelID); + cIterator GetChannelsBySourceNidTid(int Source, unsigned short Nid, unsigned short Tid); int BeingEdited(void) { return beingEdited; } void IncBeingEdited(void) { beingEdited++; } void DecBeingEdited(void) { beingEdited--; } diff -Nru vdr-1.5.13/epg.c vdr-1.5.13-Speed-up-starting-and-stopping/epg.c --- vdr-1.5.13/epg.c 2008-01-20 12:24:13.000000000 +0100 +++ vdr-1.5.13-Speed-up-starting-and-stopping/epg.c 2008-01-20 12:48:09.000000000 +0100 @@ -1068,6 +1068,7 @@ if (!p) { p = new cSchedule(ChannelID); Add(p); + HashSchedule(p); cChannel *channel = Channels.GetByChannelID(ChannelID); if (channel) channel->schedule = p; @@ -1078,10 +1079,14 @@ const cSchedule *cSchedules::GetSchedule(tChannelID ChannelID) const { ChannelID.ClrRid(); - for (cSchedule *p = First(); p; p = Next(p)) { - if (p->ChannelID() == ChannelID) - return p; - } + cList *list = schedulesHash.GetList(HashKey(ChannelID)); + if (list) { + for (cHashObject *hobj = list->First(); hobj; hobj = list->Next(hobj)) { + cSchedule *p = (cSchedule *)hobj->Object(); + if (p->ChannelID() == ChannelID) + return p; + } + } return NULL; } @@ -1097,7 +1102,23 @@ if (Channel->schedule == &DummySchedule && AddIfMissing) { cSchedule *Schedule = new cSchedule(Channel->GetChannelID()); ((cSchedules *)this)->Add(Schedule); + ((cSchedules *)this)->HashSchedule(Schedule); Channel->schedule = Schedule; } return Channel->schedule != &DummySchedule? Channel->schedule : NULL; } + +void cSchedules::HashSchedule(cSchedule *Schedule) +{ + schedulesHash.Add(Schedule, HashKey(Schedule->ChannelID().ClrRid())); +} + +void cSchedules::UnhashSchedule(cSchedule *Schedule) +{ + schedulesHash.Del(Schedule, HashKey(Schedule->ChannelID().ClrRid())); +} + +unsigned int cSchedules::HashKey(tChannelID ChannelID) +{ + return (unsigned int)((ChannelID.Nid() << 16 | ChannelID.Source()) ^ (ChannelID.Tid() << 16 | ChannelID.Sid()) ^ ChannelID.Rid()); +} diff -Nru vdr-1.5.13/epg.h vdr-1.5.13-Speed-up-starting-and-stopping/epg.h --- vdr-1.5.13/epg.h 2008-01-20 12:24:13.000000000 +0100 +++ vdr-1.5.13-Speed-up-starting-and-stopping/epg.h 2008-01-20 12:46:10.000000000 +0100 @@ -165,11 +165,15 @@ friend class cSchedulesLock; private: cRwLock rwlock; + cHash schedulesHash; static cSchedules schedules; static const char *epgDataFileName; static time_t lastCleanup; static time_t lastDump; static time_t modified; + void HashSchedule(cSchedule *Schedule); + void UnhashSchedule(cSchedule *Schedule); + static unsigned int HashKey(tChannelID ChannelID); public: static void SetEpgDataFileName(const char *FileName); static const cSchedules *Schedules(cSchedulesLock &SchedulesLock); diff -Nru vdr-1.5.13/libsi/util.c vdr-1.5.13-Speed-up-starting-and-stopping/libsi/util.c --- vdr-1.5.13/libsi/util.c 2006-02-18 12:17:50.000000000 +0100 +++ vdr-1.5.13-Speed-up-starting-and-stopping/libsi/util.c 2008-01-20 12:45:17.000000000 +0100 @@ -219,58 +219,73 @@ //taken and adapted from libdtv, (c) Rolf Hakenes // CRC32 lookup table for polynomial 0x04c11db7 +// swapped bytes to avoid one shift operation in CRC loop (c) Reinhard Nissl u_int32_t CRC32::crc_table[256] = { - 0x00000000, 0x04c11db7, 0x09823b6e, 0x0d4326d9, 0x130476dc, 0x17c56b6b, - 0x1a864db2, 0x1e475005, 0x2608edb8, 0x22c9f00f, 0x2f8ad6d6, 0x2b4bcb61, - 0x350c9b64, 0x31cd86d3, 0x3c8ea00a, 0x384fbdbd, 0x4c11db70, 0x48d0c6c7, - 0x4593e01e, 0x4152fda9, 0x5f15adac, 0x5bd4b01b, 0x569796c2, 0x52568b75, - 0x6a1936c8, 0x6ed82b7f, 0x639b0da6, 0x675a1011, 0x791d4014, 0x7ddc5da3, - 0x709f7b7a, 0x745e66cd, 0x9823b6e0, 0x9ce2ab57, 0x91a18d8e, 0x95609039, - 0x8b27c03c, 0x8fe6dd8b, 0x82a5fb52, 0x8664e6e5, 0xbe2b5b58, 0xbaea46ef, - 0xb7a96036, 0xb3687d81, 0xad2f2d84, 0xa9ee3033, 0xa4ad16ea, 0xa06c0b5d, - 0xd4326d90, 0xd0f37027, 0xddb056fe, 0xd9714b49, 0xc7361b4c, 0xc3f706fb, - 0xceb42022, 0xca753d95, 0xf23a8028, 0xf6fb9d9f, 0xfbb8bb46, 0xff79a6f1, - 0xe13ef6f4, 0xe5ffeb43, 0xe8bccd9a, 0xec7dd02d, 0x34867077, 0x30476dc0, - 0x3d044b19, 0x39c556ae, 0x278206ab, 0x23431b1c, 0x2e003dc5, 0x2ac12072, - 0x128e9dcf, 0x164f8078, 0x1b0ca6a1, 0x1fcdbb16, 0x018aeb13, 0x054bf6a4, - 0x0808d07d, 0x0cc9cdca, 0x7897ab07, 0x7c56b6b0, 0x71159069, 0x75d48dde, - 0x6b93dddb, 0x6f52c06c, 0x6211e6b5, 0x66d0fb02, 0x5e9f46bf, 0x5a5e5b08, - 0x571d7dd1, 0x53dc6066, 0x4d9b3063, 0x495a2dd4, 0x44190b0d, 0x40d816ba, - 0xaca5c697, 0xa864db20, 0xa527fdf9, 0xa1e6e04e, 0xbfa1b04b, 0xbb60adfc, - 0xb6238b25, 0xb2e29692, 0x8aad2b2f, 0x8e6c3698, 0x832f1041, 0x87ee0df6, - 0x99a95df3, 0x9d684044, 0x902b669d, 0x94ea7b2a, 0xe0b41de7, 0xe4750050, - 0xe9362689, 0xedf73b3e, 0xf3b06b3b, 0xf771768c, 0xfa325055, 0xfef34de2, - 0xc6bcf05f, 0xc27dede8, 0xcf3ecb31, 0xcbffd686, 0xd5b88683, 0xd1799b34, - 0xdc3abded, 0xd8fba05a, 0x690ce0ee, 0x6dcdfd59, 0x608edb80, 0x644fc637, - 0x7a089632, 0x7ec98b85, 0x738aad5c, 0x774bb0eb, 0x4f040d56, 0x4bc510e1, - 0x46863638, 0x42472b8f, 0x5c007b8a, 0x58c1663d, 0x558240e4, 0x51435d53, - 0x251d3b9e, 0x21dc2629, 0x2c9f00f0, 0x285e1d47, 0x36194d42, 0x32d850f5, - 0x3f9b762c, 0x3b5a6b9b, 0x0315d626, 0x07d4cb91, 0x0a97ed48, 0x0e56f0ff, - 0x1011a0fa, 0x14d0bd4d, 0x19939b94, 0x1d528623, 0xf12f560e, 0xf5ee4bb9, - 0xf8ad6d60, 0xfc6c70d7, 0xe22b20d2, 0xe6ea3d65, 0xeba91bbc, 0xef68060b, - 0xd727bbb6, 0xd3e6a601, 0xdea580d8, 0xda649d6f, 0xc423cd6a, 0xc0e2d0dd, - 0xcda1f604, 0xc960ebb3, 0xbd3e8d7e, 0xb9ff90c9, 0xb4bcb610, 0xb07daba7, - 0xae3afba2, 0xaafbe615, 0xa7b8c0cc, 0xa379dd7b, 0x9b3660c6, 0x9ff77d71, - 0x92b45ba8, 0x9675461f, 0x8832161a, 0x8cf30bad, 0x81b02d74, 0x857130c3, - 0x5d8a9099, 0x594b8d2e, 0x5408abf7, 0x50c9b640, 0x4e8ee645, 0x4a4ffbf2, - 0x470cdd2b, 0x43cdc09c, 0x7b827d21, 0x7f436096, 0x7200464f, 0x76c15bf8, - 0x68860bfd, 0x6c47164a, 0x61043093, 0x65c52d24, 0x119b4be9, 0x155a565e, - 0x18197087, 0x1cd86d30, 0x029f3d35, 0x065e2082, 0x0b1d065b, 0x0fdc1bec, - 0x3793a651, 0x3352bbe6, 0x3e119d3f, 0x3ad08088, 0x2497d08d, 0x2056cd3a, - 0x2d15ebe3, 0x29d4f654, 0xc5a92679, 0xc1683bce, 0xcc2b1d17, 0xc8ea00a0, - 0xd6ad50a5, 0xd26c4d12, 0xdf2f6bcb, 0xdbee767c, 0xe3a1cbc1, 0xe760d676, - 0xea23f0af, 0xeee2ed18, 0xf0a5bd1d, 0xf464a0aa, 0xf9278673, 0xfde69bc4, - 0x89b8fd09, 0x8d79e0be, 0x803ac667, 0x84fbdbd0, 0x9abc8bd5, 0x9e7d9662, - 0x933eb0bb, 0x97ffad0c, 0xafb010b1, 0xab710d06, 0xa6322bdf, 0xa2f33668, - 0xbcb4666d, 0xb8757bda, 0xb5365d03, 0xb1f740b4}; + 0x00000000, 0xb71dc104, 0x6e3b8209, 0xd926430d, 0xdc760413, 0x6b6bc517, + 0xb24d861a, 0x0550471e, 0xb8ed0826, 0x0ff0c922, 0xd6d68a2f, 0x61cb4b2b, + 0x649b0c35, 0xd386cd31, 0x0aa08e3c, 0xbdbd4f38, 0x70db114c, 0xc7c6d048, + 0x1ee09345, 0xa9fd5241, 0xacad155f, 0x1bb0d45b, 0xc2969756, 0x758b5652, + 0xc836196a, 0x7f2bd86e, 0xa60d9b63, 0x11105a67, 0x14401d79, 0xa35ddc7d, + 0x7a7b9f70, 0xcd665e74, 0xe0b62398, 0x57abe29c, 0x8e8da191, 0x39906095, + 0x3cc0278b, 0x8bdde68f, 0x52fba582, 0xe5e66486, 0x585b2bbe, 0xef46eaba, + 0x3660a9b7, 0x817d68b3, 0x842d2fad, 0x3330eea9, 0xea16ada4, 0x5d0b6ca0, + 0x906d32d4, 0x2770f3d0, 0xfe56b0dd, 0x494b71d9, 0x4c1b36c7, 0xfb06f7c3, + 0x2220b4ce, 0x953d75ca, 0x28803af2, 0x9f9dfbf6, 0x46bbb8fb, 0xf1a679ff, + 0xf4f63ee1, 0x43ebffe5, 0x9acdbce8, 0x2dd07dec, 0x77708634, 0xc06d4730, + 0x194b043d, 0xae56c539, 0xab068227, 0x1c1b4323, 0xc53d002e, 0x7220c12a, + 0xcf9d8e12, 0x78804f16, 0xa1a60c1b, 0x16bbcd1f, 0x13eb8a01, 0xa4f64b05, + 0x7dd00808, 0xcacdc90c, 0x07ab9778, 0xb0b6567c, 0x69901571, 0xde8dd475, + 0xdbdd936b, 0x6cc0526f, 0xb5e61162, 0x02fbd066, 0xbf469f5e, 0x085b5e5a, + 0xd17d1d57, 0x6660dc53, 0x63309b4d, 0xd42d5a49, 0x0d0b1944, 0xba16d840, + 0x97c6a5ac, 0x20db64a8, 0xf9fd27a5, 0x4ee0e6a1, 0x4bb0a1bf, 0xfcad60bb, + 0x258b23b6, 0x9296e2b2, 0x2f2bad8a, 0x98366c8e, 0x41102f83, 0xf60dee87, + 0xf35da999, 0x4440689d, 0x9d662b90, 0x2a7bea94, 0xe71db4e0, 0x500075e4, + 0x892636e9, 0x3e3bf7ed, 0x3b6bb0f3, 0x8c7671f7, 0x555032fa, 0xe24df3fe, + 0x5ff0bcc6, 0xe8ed7dc2, 0x31cb3ecf, 0x86d6ffcb, 0x8386b8d5, 0x349b79d1, + 0xedbd3adc, 0x5aa0fbd8, 0xeee00c69, 0x59fdcd6d, 0x80db8e60, 0x37c64f64, + 0x3296087a, 0x858bc97e, 0x5cad8a73, 0xebb04b77, 0x560d044f, 0xe110c54b, + 0x38368646, 0x8f2b4742, 0x8a7b005c, 0x3d66c158, 0xe4408255, 0x535d4351, + 0x9e3b1d25, 0x2926dc21, 0xf0009f2c, 0x471d5e28, 0x424d1936, 0xf550d832, + 0x2c769b3f, 0x9b6b5a3b, 0x26d61503, 0x91cbd407, 0x48ed970a, 0xfff0560e, + 0xfaa01110, 0x4dbdd014, 0x949b9319, 0x2386521d, 0x0e562ff1, 0xb94beef5, + 0x606dadf8, 0xd7706cfc, 0xd2202be2, 0x653deae6, 0xbc1ba9eb, 0x0b0668ef, + 0xb6bb27d7, 0x01a6e6d3, 0xd880a5de, 0x6f9d64da, 0x6acd23c4, 0xddd0e2c0, + 0x04f6a1cd, 0xb3eb60c9, 0x7e8d3ebd, 0xc990ffb9, 0x10b6bcb4, 0xa7ab7db0, + 0xa2fb3aae, 0x15e6fbaa, 0xccc0b8a7, 0x7bdd79a3, 0xc660369b, 0x717df79f, + 0xa85bb492, 0x1f467596, 0x1a163288, 0xad0bf38c, 0x742db081, 0xc3307185, + 0x99908a5d, 0x2e8d4b59, 0xf7ab0854, 0x40b6c950, 0x45e68e4e, 0xf2fb4f4a, + 0x2bdd0c47, 0x9cc0cd43, 0x217d827b, 0x9660437f, 0x4f460072, 0xf85bc176, + 0xfd0b8668, 0x4a16476c, 0x93300461, 0x242dc565, 0xe94b9b11, 0x5e565a15, + 0x87701918, 0x306dd81c, 0x353d9f02, 0x82205e06, 0x5b061d0b, 0xec1bdc0f, + 0x51a69337, 0xe6bb5233, 0x3f9d113e, 0x8880d03a, 0x8dd09724, 0x3acd5620, + 0xe3eb152d, 0x54f6d429, 0x7926a9c5, 0xce3b68c1, 0x171d2bcc, 0xa000eac8, + 0xa550add6, 0x124d6cd2, 0xcb6b2fdf, 0x7c76eedb, 0xc1cba1e3, 0x76d660e7, + 0xaff023ea, 0x18ede2ee, 0x1dbda5f0, 0xaaa064f4, 0x738627f9, 0xc49be6fd, + 0x09fdb889, 0xbee0798d, 0x67c63a80, 0xd0dbfb84, 0xd58bbc9a, 0x62967d9e, + 0xbbb03e93, 0x0cadff97, 0xb110b0af, 0x060d71ab, 0xdf2b32a6, 0x6836f3a2, + 0x6d66b4bc, 0xda7b75b8, 0x035d36b5, 0xb440f7b1}; + +inline void swap_bytes(u_int32_t &crc) +{ + unsigned char a = crc >> 24; + unsigned char b = crc >> 16; + unsigned char c = crc >> 8; + unsigned char d = crc; + + crc = ((d << 8 | c) << 8 | b) << 8 | a; +} u_int32_t CRC32::crc32 (const char *d, int len, u_int32_t crc) { register int i; const unsigned char *u=(unsigned char*)d; // Saves '& 0xff' + swap_bytes(crc); + for (i=0; i> 24) ^ *u++)]; + crc = (crc >> 8) ^ crc_table[(unsigned char)crc ^ *u++]; + + swap_bytes(crc); return crc; } diff -Nru vdr-1.5.13/nit.c vdr-1.5.13-Speed-up-starting-and-stopping/nit.c --- vdr-1.5.13/nit.c 2008-01-20 12:24:30.000000000 +0100 +++ vdr-1.5.13-Speed-up-starting-and-stopping/nit.c 2008-01-20 12:40:49.000000000 +0100 @@ -142,21 +142,20 @@ } if (Setup.UpdateChannels >= 5) { bool found = false; - for (cChannel *Channel = Channels.First(); Channel; Channel = Channels.Next(Channel)) { - if (!Channel->GroupSep() && Channel->Source() == Source && Channel->Nid() == ts.getOriginalNetworkId() && Channel->Tid() == ts.getTransportStreamId()) { - int transponder = Channel->Transponder(); - found = true; - if (!ISTRANSPONDER(cChannel::Transponder(Frequency, Polarization), transponder)) { - for (int n = 0; n < NumFrequencies; n++) { - if (ISTRANSPONDER(cChannel::Transponder(Frequencies[n], Polarization), transponder)) { - Frequency = Frequencies[n]; - break; - } + cIterator ChannelIterator = Channels.GetChannelsBySourceNidTid(Source, ts.getOriginalNetworkId(), ts.getTransportStreamId()); + for (cChannel *Channel = ChannelIterator.First(); Channel; Channel = ChannelIterator.Next()) { + int transponder = Channel->Transponder(); + found = true; + if (!ISTRANSPONDER(cChannel::Transponder(Frequency, Polarization), transponder)) { + for (int n = 0; n < NumFrequencies; n++) { + if (ISTRANSPONDER(cChannel::Transponder(Frequencies[n], Polarization), transponder)) { + Frequency = Frequencies[n]; + break; } - } - if (ISTRANSPONDER(cChannel::Transponder(Frequency, Polarization), Transponder())) // only modify channels if we're actually receiving this transponder - Channel->SetSatTransponderData(Source, Frequency, Polarization, SymbolRate, CodeRate); + } } + if (ISTRANSPONDER(cChannel::Transponder(Frequency, Polarization), Transponder())) // only modify channels if we're actually receiving this transponder + Channel->SetSatTransponderData(Source, Frequency, Polarization, SymbolRate, CodeRate); } if (!found) { for (int n = 0; n < NumFrequencies; n++) { @@ -193,21 +192,20 @@ } if (Setup.UpdateChannels >= 5) { bool found = false; - for (cChannel *Channel = Channels.First(); Channel; Channel = Channels.Next(Channel)) { - if (!Channel->GroupSep() && Channel->Source() == Source && Channel->Nid() == ts.getOriginalNetworkId() && Channel->Tid() == ts.getTransportStreamId()) { - int transponder = Channel->Transponder(); - found = true; - if (!ISTRANSPONDER(Frequency / 1000, transponder)) { - for (int n = 0; n < NumFrequencies; n++) { - if (ISTRANSPONDER(Frequencies[n] / 1000, transponder)) { - Frequency = Frequencies[n]; - break; - } + cIterator ChannelIterator = Channels.GetChannelsBySourceNidTid(Source, ts.getOriginalNetworkId(), ts.getTransportStreamId()); + for (cChannel *Channel = ChannelIterator.First(); Channel; Channel = ChannelIterator.Next()) { + int transponder = Channel->Transponder(); + found = true; + if (!ISTRANSPONDER(Frequency / 1000, transponder)) { + for (int n = 0; n < NumFrequencies; n++) { + if (ISTRANSPONDER(Frequencies[n] / 1000, transponder)) { + Frequency = Frequencies[n]; + break; } - } - if (ISTRANSPONDER(Frequency / 1000, Transponder())) // only modify channels if we're actually receiving this transponder - Channel->SetCableTransponderData(Source, Frequency, Modulation, SymbolRate, CodeRate); + } } + if (ISTRANSPONDER(Frequency / 1000, Transponder())) // only modify channels if we're actually receiving this transponder + Channel->SetCableTransponderData(Source, Frequency, Modulation, SymbolRate, CodeRate); } if (!found) { for (int n = 0; n < NumFrequencies; n++) { @@ -251,21 +249,20 @@ } if (Setup.UpdateChannels >= 5) { bool found = false; - for (cChannel *Channel = Channels.First(); Channel; Channel = Channels.Next(Channel)) { - if (!Channel->GroupSep() && Channel->Source() == Source && Channel->Nid() == ts.getOriginalNetworkId() && Channel->Tid() == ts.getTransportStreamId()) { - int transponder = Channel->Transponder(); - found = true; - if (!ISTRANSPONDER(Frequency / 1000000, transponder)) { - for (int n = 0; n < NumFrequencies; n++) { - if (ISTRANSPONDER(Frequencies[n] / 1000000, transponder)) { - Frequency = Frequencies[n]; - break; - } + cIterator ChannelIterator = Channels.GetChannelsBySourceNidTid(Source, ts.getOriginalNetworkId(), ts.getTransportStreamId()); + for (cChannel *Channel = ChannelIterator.First(); Channel; Channel = ChannelIterator.Next()) { + int transponder = Channel->Transponder(); + found = true; + if (!ISTRANSPONDER(Frequency / 1000000, transponder)) { + for (int n = 0; n < NumFrequencies; n++) { + if (ISTRANSPONDER(Frequencies[n] / 1000000, transponder)) { + Frequency = Frequencies[n]; + break; } - } - if (ISTRANSPONDER(Frequency / 1000000, Transponder())) // only modify channels if we're actually receiving this transponder - Channel->SetTerrTransponderData(Source, Frequency, Bandwidth, Constellation, Hierarchy, CodeRateHP, CodeRateLP, GuardInterval, TransmissionMode); + } } + if (ISTRANSPONDER(Frequency / 1000000, Transponder())) // only modify channels if we're actually receiving this transponder + Channel->SetTerrTransponderData(Source, Frequency, Bandwidth, Constellation, Hierarchy, CodeRateHP, CodeRateLP, GuardInterval, TransmissionMode); } if (!found) { for (int n = 0; n < NumFrequencies; n++) { diff -Nru vdr-1.5.13/osd.c vdr-1.5.13-Speed-up-starting-and-stopping/osd.c --- vdr-1.5.13/osd.c 2008-01-20 12:24:50.000000000 +0100 +++ vdr-1.5.13-Speed-up-starting-and-stopping/osd.c 2008-01-20 13:10:20.000000000 +0100 @@ -395,15 +395,20 @@ void cBitmap::SetIndex(int x, int y, tIndex Index) { if (bitmap) { - if (0 <= x && x < width && 0 <= y && y < height) { - if (bitmap[width * y + x] != Index) { - bitmap[width * y + x] = Index; - if (dirtyX1 > x) dirtyX1 = x; - if (dirtyY1 > y) dirtyY1 = y; - if (dirtyX2 < x) dirtyX2 = x; - if (dirtyY2 < y) dirtyY2 = y; - } - } + if (0 <= x && x < width && 0 <= y && y < height) + SetIndexInternal(x, y, Index); + } +} + +void cBitmap::SetIndexInternal(int x, int y, tIndex Index) +{ + // this function relies on existing bitmap and valid coordinates + if (bitmap[width * y + x] != Index) { + bitmap[width * y + x] = Index; + if (dirtyX1 > x) dirtyX1 = x; + if (dirtyY1 > y) dirtyY1 = y; + if (dirtyX2 < x) dirtyX2 = x; + if (dirtyY2 < y) dirtyY2 = y; } } @@ -411,37 +416,147 @@ { x -= x0; y -= y0; - if (0 <= x && x < width && 0 <= y && y < height) - SetIndex(x, y, Index(Color)); + if (bitmap && 0 <= x && x < width && 0 <= y && y < height) + SetIndexInternal(x, y, Index(Color)); } void cBitmap::DrawBitmap(int x, int y, const cBitmap &Bitmap, tColor ColorFg, tColor ColorBg, bool ReplacePalette, bool Overlay) { if (bitmap && Bitmap.bitmap && Intersects(x, y, x + Bitmap.Width() - 1, y + Bitmap.Height() - 1)) { - if (Covers(x, y, x + Bitmap.Width() - 1, y + Bitmap.Height() - 1)) + bool Covered = Covers(x, y, x + Bitmap.Width() - 1, y + Bitmap.Height() - 1); + if (Covered) Reset(); x -= x0; y -= y0; - if (ReplacePalette && Covers(x + x0, y + y0, x + x0 + Bitmap.Width() - 1, y + y0 + Bitmap.Height() - 1)) { + // determine valid destination area [x1,x2]x[y1,y2] to avoid range checks inside the loops + int x1 = max(0, x), x2 = min(0 + width , x + Bitmap.width) - 1; + int y1 = max(0, y), y2 = min(0 + height, y + Bitmap.height) - 1; + +#define FOR_Y_LOOP0 \ + tIndex *pRowSrc = &Bitmap.bitmap[Bitmap.width * (y1 - y) + (x1 - x)]; \ + tIndex *pRowDst = &bitmap[width * y1 + x1]; \ + for (int &yy = y1, ye = min(y2, dirtyY1 - 1); yy <= ye; yy++, pRowDst += width, pRowSrc += Bitmap.width) + +#define FOR_Y_LOOP1 \ + tIndex *pRowSrc = &Bitmap.bitmap[Bitmap.width * (y2 - y) + (x1 - x)]; \ + tIndex *pRowDst = &bitmap[width * y2 + x1]; \ + for (int &yy = y2, ye = max(y1, dirtyY2 + 1); yy >= ye; yy--, pRowDst -= width, pRowSrc -= Bitmap.width) + +#define DETECT_DIRTY_AREA_Y(Reverse, TransferCondition, TransferOperation) \ + do { \ + FOR_Y_LOOP##Reverse { \ + tIndex *pSrc = pRowSrc; \ + tIndex *pDst = pRowDst; \ + bool GotDirty = false; \ + for (int xx = x1; xx <= x2; xx++) { \ + if (TransferCondition) { \ + if (*pDst != TransferOperation) { \ + GotDirty = true; \ + if (dirtyX1 > xx) dirtyX1 = xx; \ + if (dirtyX2 < xx) dirtyX2 = xx; \ + } \ + } \ + pSrc++; \ + pDst++; \ + } \ + if (GotDirty) { \ + if (dirtyY1 > yy) dirtyY1 = yy; \ + if (dirtyY2 < yy) dirtyY2 = yy; \ + break; \ + } \ + } \ + } \ + while (false) + +#define FOR_X_LOOP0 \ + tIndex *pColSrc = &Bitmap.bitmap[Bitmap.width * (y1 - y) + (x1 - x)]; \ + tIndex *pColDst = &bitmap[width * y1 + x1]; \ + for (int &xx = x1, xe = min(x2, dirtyX1 - 1); xx <= xe; xx++, pColDst++, pColSrc++) + +#define FOR_X_LOOP1 \ + tIndex *pColSrc = &Bitmap.bitmap[Bitmap.width * (y1 - y) + (x2 - x)]; \ + tIndex *pColDst = &bitmap[width * y1 + x2]; \ + for (int &xx = x2, xe = max(x1, dirtyX2 + 1); xx >= xe; xx--, pColDst--, pColSrc--) + +#define DETECT_DIRTY_AREA_X(Reverse, TransferCondition, TransferOperation) \ + do { \ + FOR_X_LOOP##Reverse { \ + tIndex *pSrc = pColSrc; \ + tIndex *pDst = pColDst; \ + bool GotDirty = false; \ + for (int yy = y1; yy <= y2; yy++) { \ + if (TransferCondition) { \ + if (*pDst != TransferOperation) { \ + GotDirty = true; \ + if (dirtyX1 > xx) dirtyX1 = xx; \ + if (dirtyX2 < xx) dirtyX2 = xx; \ + break; \ + } \ + } \ + pSrc += Bitmap.width; \ + pDst += width; \ + } \ + if (GotDirty) \ + break; \ + } \ + } \ + while (false) + +#define DRAW_BITMAP(TransferCondition, TransferOperation, CanUseMemCpy) \ + do { \ + DETECT_DIRTY_AREA_Y(0, TransferCondition, TransferOperation); /* above */ \ + DETECT_DIRTY_AREA_Y(1, TransferCondition, TransferOperation); /* below */ \ + if (y2 < y1) /* nothing dirty */ \ + return; \ + DETECT_DIRTY_AREA_X(0, TransferCondition, TransferOperation); /* left */ \ + DETECT_DIRTY_AREA_X(1, TransferCondition, TransferOperation); /* right */ \ + /* process dirty area now */ \ + tIndex *pRowSrc = &Bitmap.bitmap[Bitmap.width * (y1 - y) + (x1 - x)]; \ + tIndex *pRowDst = &bitmap[width * y1 + x1]; \ + int n = sizeof(tIndex) * (x2 - x1 + 1); \ + for (int yy = y1; yy <= y2; yy++) { \ + tIndex *pSrc = pRowSrc; \ + tIndex *pDst = pRowDst; \ + if (CanUseMemCpy) \ + memcpy(pDst, pSrc, n); \ + else { \ + for (int xx = x1; xx <= x2; xx++) { \ + if (TransferCondition) \ + *pDst = TransferOperation; \ + pSrc++; \ + pDst++; \ + } \ + } \ + pRowSrc += Bitmap.width; \ + pRowDst += width; \ + } \ + } \ + while (false) + + if (ReplacePalette && Covered) { Replace(Bitmap); - for (int ix = 0; ix < Bitmap.width; ix++) { - for (int iy = 0; iy < Bitmap.height; iy++) { - if (!Overlay || Bitmap.bitmap[Bitmap.width * iy + ix] != 0) - SetIndex(x + ix, y + iy, Bitmap.bitmap[Bitmap.width * iy + ix]); - } - } + if (Overlay) + DRAW_BITMAP(*pSrc != 0, *pSrc, false); + else + DRAW_BITMAP(true, *pSrc, true); } else { tIndexes Indexes; Take(Bitmap, &Indexes, ColorFg, ColorBg); - for (int ix = 0; ix < Bitmap.width; ix++) { - for (int iy = 0; iy < Bitmap.height; iy++) { - if (!Overlay || Bitmap.bitmap[Bitmap.width * iy + ix] != 0) - SetIndex(x + ix, y + iy, Indexes[int(Bitmap.bitmap[Bitmap.width * iy + ix])]); - } - } + if (Overlay) + DRAW_BITMAP(*pSrc != 0, Indexes[(int)*pSrc], false); + else + DRAW_BITMAP(true, Indexes[(int)*pSrc], false); } } + +#undef DRAW_BITMAP +#undef DETECT_DIRTY_AREA_Y +#undef FOR_Y_LOOP0 +#undef FOR_Y_LOOP1 +#undef DETECT_DIRTY_AREA_X +#undef FOR_X_LOOP0 +#undef FOR_X_LOOP1 } void cBitmap::DrawText(int x, int y, const char *s, tColor ColorFg, tColor ColorBg, const cFont *Font, int Width, int Height, int Alignment) @@ -503,10 +618,91 @@ x2 = min(x2, width - 1); y2 = min(y2, height - 1); tIndex c = Index(Color); - for (int y = y1; y <= y2; y++) - for (int x = x1; x <= x2; x++) - SetIndex(x, y, c); + +#define FOR_Y_LOOP0 \ + tIndex *pRowDst = &bitmap[width * y1 + x1]; \ + for (int &yy = y1, ye = min(y2, dirtyY1 - 1); yy <= ye; yy++, pRowDst += width) + +#define FOR_Y_LOOP1 \ + tIndex *pRowDst = &bitmap[width * y2 + x1]; \ + for (int &yy = y2, ye = max(y1, dirtyY2 + 1); yy >= ye; yy--, pRowDst -= width) + +#define DETECT_DIRTY_AREA_Y(Reverse) \ + do { \ + FOR_Y_LOOP##Reverse { \ + tIndex *pDst = pRowDst; \ + bool GotDirty = false; \ + for (int xx = x1; xx <= x2; xx++) { \ + if (*pDst != c) { \ + GotDirty = true; \ + if (dirtyX1 > xx) dirtyX1 = xx; \ + if (dirtyX2 < xx) dirtyX2 = xx; \ + } \ + pDst++; \ + } \ + if (GotDirty) { \ + if (dirtyY1 > yy) dirtyY1 = yy; \ + if (dirtyY2 < yy) dirtyY2 = yy; \ + break; \ + } \ + } \ + } \ + while (false) + +#define FOR_X_LOOP0 \ + tIndex *pColDst = &bitmap[width * y1 + x1]; \ + for (int &xx = x1, xe = min(x2, dirtyX1 - 1); xx <= xe; xx++, pColDst++) + +#define FOR_X_LOOP1 \ + tIndex *pColDst = &bitmap[width * y1 + x2]; \ + for (int &xx = x2, xe = max(x1, dirtyX2 + 1); xx >= xe; xx--, pColDst--) + +#define DETECT_DIRTY_AREA_X(Reverse) \ + do { \ + FOR_X_LOOP##Reverse { \ + tIndex *pDst = pColDst; \ + bool GotDirty = false; \ + for (int yy = y1; yy <= y2; yy++) { \ + if (*pDst != c) { \ + GotDirty = true; \ + if (dirtyX1 > xx) dirtyX1 = xx; \ + if (dirtyX2 < xx) dirtyX2 = xx; \ + break; \ + } \ + pDst += width; \ + } \ + if (GotDirty) \ + break; \ + } \ + } \ + while (false) + + DETECT_DIRTY_AREA_Y(0); /* above */ + DETECT_DIRTY_AREA_Y(1); /* below */ + if (y2 < y1) /* nothing dirty */ + return; + DETECT_DIRTY_AREA_X(0); /* left */ + DETECT_DIRTY_AREA_X(1); /* right */ + // now fill only dirty area of rectangle + tIndex *pRowDst = &bitmap[width * y1 + x1]; + tIndex *pDst = pRowDst; + for (int x = x1; x <= x2; x++) + *pDst++ = c; + // copy the single line above to all other lines + tIndex *pRowSrc = pRowDst; + int n = sizeof(tIndex) * (x2 - x1 + 1); + for (int y = y1 + 1; y <= y2; y++) { + pRowDst += width; + memcpy(pRowDst, pRowSrc, n); + } } + +#undef DETECT_DIRTY_AREA_Y +#undef FOR_Y_LOOP0 +#undef FOR_Y_LOOP1 +#undef DETECT_DIRTY_AREA_X +#undef FOR_X_LOOP0 +#undef FOR_X_LOOP1 } void cBitmap::DrawEllipse(int x1, int y1, int x2, int y2, tColor Color, int Quadrants) diff -Nru vdr-1.5.13/osd.h vdr-1.5.13-Speed-up-starting-and-stopping/osd.h --- vdr-1.5.13/osd.h 2008-01-20 12:24:50.000000000 +0100 +++ vdr-1.5.13-Speed-up-starting-and-stopping/osd.h 2008-01-20 13:02:34.000000000 +0100 @@ -135,6 +135,7 @@ int x0, y0; int width, height; int dirtyX1, dirtyY1, dirtyX2, dirtyY2; + void SetIndexInternal(int x, int y, tIndex Index); public: cBitmap(int Width, int Height, int Bpp, int X0 = 0, int Y0 = 0); ///< Creates a bitmap with the given Width, Height and color depth (Bpp). diff -Nru vdr-1.5.13/skinclassic.c vdr-1.5.13-Speed-up-starting-and-stopping/skinclassic.c --- vdr-1.5.13/skinclassic.c 2008-01-13 13:38:00.000000000 +0100 +++ vdr-1.5.13-Speed-up-starting-and-stopping/skinclassic.c 2008-01-20 12:27:58.000000000 +0100 @@ -77,6 +77,7 @@ int lineHeight; int timeWidth; bool message; + cString lastDate; public: cSkinClassicDisplayChannel(bool WithInfo); virtual ~cSkinClassicDisplayChannel(); @@ -149,7 +150,10 @@ cString date = DayDateTime(); const cFont *font = cFont::GetFont(fontSml); int w = font->Width(date); - osd->DrawText(osd->Width() - w - 2, 0, date, Theme.Color(clrChannelDate), Theme.Color(clrBackground), cFont::GetFont(fontSml), w); + if (!lastDate || strcmp(lastDate, date)) { + osd->DrawText(osd->Width() - w - 2, 0, date, Theme.Color(clrChannelDate), Theme.Color(clrBackground), cFont::GetFont(fontSml), w); + lastDate = date; + } } osd->Flush(); } diff -Nru vdr-1.5.13/skinsttng.c vdr-1.5.13-Speed-up-starting-and-stopping/skinsttng.c --- vdr-1.5.13/skinsttng.c 2007-06-17 15:51:56.000000000 +0200 +++ vdr-1.5.13-Speed-up-starting-and-stopping/skinsttng.c 2008-01-20 12:28:46.000000000 +0100 @@ -131,6 +131,7 @@ const cEvent *present; int lastSeen; tTrackId lastTrackId; + cString lastDate; static cBitmap bmTeletext, bmRadio, bmAudio, bmDolbyDigital, bmEncrypted, bmRecording; public: cSkinSTTNGDisplayChannel(bool WithInfo); @@ -307,7 +308,10 @@ const cFont *font = cFont::GetFont(fontSml); cString date = DayDateTime(); int w = font->Width(date); - osd->DrawText(x4 - w - 2, y7 - font->Height(), date, Theme.Color(clrChannelDate), frameColor, font, w); + if (!lastDate || strcmp(lastDate, date)) { + osd->DrawText(x4 - w - 2, y7 - font->Height(), date, Theme.Color(clrChannelDate), frameColor, font, w); + lastDate = date; + } cDevice *Device = cDevice::PrimaryDevice(); const tTrackId *Track = Device->GetTrack(Device->GetCurrentAudioTrack()); if (!Track && *lastTrackId.description || Track && strcmp(lastTrackId.description, Track->description)) { diff -Nru vdr-1.5.13/tools.c vdr-1.5.13-Speed-up-starting-and-stopping/tools.c --- vdr-1.5.13/tools.c 2008-01-13 12:26:30.000000000 +0100 +++ vdr-1.5.13-Speed-up-starting-and-stopping/tools.c 2008-01-20 13:02:03.000000000 +0100 @@ -140,11 +140,8 @@ { if (s) { char *p = s; - while (*p) { - if (*p == c1) - *p = c2; - p++; - } + while ((p = strchr(p, c1))) + *p++ = c2; } return s; } diff -Nru vdr-1.5.13/tools.h vdr-1.5.13-Speed-up-starting-and-stopping/tools.h --- vdr-1.5.13/tools.h 2008-01-13 12:22:26.000000000 +0100 +++ vdr-1.5.13-Speed-up-starting-and-stopping/tools.h 2008-01-20 12:53:56.000000000 +0100 @@ -527,7 +527,7 @@ cList *GetList(unsigned int Id) const; }; -#define HASHSIZE 512 +#define HASHSIZE 521 template class cHash : public cHashBase { public: