[vdr-plugin-eepg] 01/05: Imported Upstream version 0.0.5.git20121123
Tobias Grimm
tiber-guest at moszumanska.debian.org
Sun Feb 15 19:14:06 UTC 2015
This is an automated email from the git hooks/post-receive script.
tiber-guest pushed a commit to branch master
in repository vdr-plugin-eepg.
commit 403dc09b2ea2911423f16c3a559d3ce8306bafaa
Author: etobi <git at e-tobi.net>
Date: Sun Feb 15 19:39:51 2015 +0100
Imported Upstream version 0.0.5.git20121123
---
.pc/.dpkg-source-unapply | 0
.pc/.quilt_patches | 1 +
.pc/.quilt_series | 1 +
.pc/.version | 1 +
COPYING | 340 ++
HISTORY | 64 +
Makefile | 136 +
README | 135 +
TODO | 14 +
dish.c | 619 ++++
dish.h | 300 ++
eepg.c | 3628 ++++++++++++++++++++
eepg.equiv.IT | 17 +
eepg.h | 7182 +++++++++++++++++++++++++++++++++++++++
eit2.c | 587 ++++
eit2.h | 50 +
epghandler.c | 198 ++
epghandler.h | 48 +
equivhandler.c | 233 ++
equivhandler.h | 40 +
log.h | 78 +
scripts/README | 28 +
scripts/extract_vdr_chan_ids.pl | 38 +
scripts/makeequiv.sh | 56 +
setupeepg.c | 37 +
setupeepg.h | 52 +
util.c | 392 +++
util.h | 93 +
28 files changed, 14368 insertions(+)
diff --git a/.pc/.dpkg-source-unapply b/.pc/.dpkg-source-unapply
new file mode 100644
index 0000000..e69de29
diff --git a/.pc/.quilt_patches b/.pc/.quilt_patches
new file mode 100644
index 0000000..6857a8d
--- /dev/null
+++ b/.pc/.quilt_patches
@@ -0,0 +1 @@
+debian/patches
diff --git a/.pc/.quilt_series b/.pc/.quilt_series
new file mode 100644
index 0000000..c206706
--- /dev/null
+++ b/.pc/.quilt_series
@@ -0,0 +1 @@
+series
diff --git a/.pc/.version b/.pc/.version
new file mode 100644
index 0000000..0cfbf08
--- /dev/null
+++ b/.pc/.version
@@ -0,0 +1 @@
+2
diff --git a/COPYING b/COPYING
new file mode 100644
index 0000000..5b6e7c6
--- /dev/null
+++ b/COPYING
@@ -0,0 +1,340 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ 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, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) year name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/HISTORY b/HISTORY
new file mode 100644
index 0000000..f3ccd4d
--- /dev/null
+++ b/HISTORY
@@ -0,0 +1,64 @@
+Release 0.0.6pre:
+- Fix for vdr-1.7.x
+- Fix for OTV formats
+- Fix MHW2 format
+- Fix crash when Themes are less than the size needed for the MHW2. This has also to be completely modified since the current implementation is not best.
+- Added parental rating for SKY since it is provided and handled by vdr-1.7.15
+- Fixed charset
+- Added viasat support
+- Removed include si.c
+- Changed docodeText2 to use code from vdr which also handles charset override
+- Removed some gotos
+- Removed some code duplication
+- Removed some todos
+- moved Premiere code in separate method
+- Added setup option to display message after finish of writing epg
+- Added Dish Network and Bell ExpressVU support, thanks to the VDR patch, Mrgandalf and VDR User
+- Applied patch to Load Huffman dictionaries only on first use, thanks to Torsten Lang
+- Fixed update of equivalents for Freesat
+- Add category and genere to the description usable with epgsearch
+- Added EpgHandler for manipulation of the EPG for VDR > 1.7.26
+- Try to discard very long events that override more than one existing event
+- Equivalents stored in map for all equivalents for better handling
+- Move equivalence to separate file/class
+- Move utilities to separate files
+- Added cAddEventThread from VDR EPGFixer Plug-in to update equivalent channels in separate thread
+- Try to discard very long events that override more than one existing event
+- Use map instead of list in cAddEventThread to reduce sorting
+- Move cEIT2 in a separate file and try to use it in epghandler also
+- Drop unmanaged NOEPG support, there is a separate plugin for that
+- Drop unmanaged Disable Double EPG entry. EEPG tries to handle this anyway
+- Aditional fixes logged at http://projects.vdr-developer.org/git/vdr-plugin-eepg.git/
+
+Release 0.0.5:
+-changed TableId's so that Now/Next overwrites Nagra which overwrites MHW
+
+
+Release 0.0.4:
+-fixed changed format MHW1 that CDNL temporarily broadcasted, but has reversed after a lot of complaints
+-now first loading NagraGuide, not loading MHW if present on same stream (CDNL)
+
+Release 0.0.3:
+-fixed undefined symbol error when not using NO_EPG patch
+-declare Nagra-events that have day-of-the month in the period between today-7days and yesterday as "old events"; some providers keep sending old eepg data that otherways are presented as next months'
+-stopped processing the second title-field that is sent with Nagra, since it is not clear when it is valid
+-make eepg-plugin actually obey the rules defined by the NO_EPG patch, if used
+-fixed all compiler warnings
+
+Release 0.0.2a:
+-fixed problem in NagraGuide, where month of title could get random value
+
+Release 0.0.2:
+-decoded and added NagraGuide
+-tested daylight savings functionality for SKY_UK
+-added daylight savings fucntionality for MHW1 and NAGRA
+-added possiblity to scan more eepg-streams on same transponder (like CanaalDigitaalNL, both MHW1 and Nagra)
+-disabled scan after 1 hour idle time; this was unused functionality, since a) most updates are once/24 hour, and b) most of the time zapping is done within 1 hour
+-added lookup for eventid, so existing events will be updated instead of added. This means less use for the DD_EPG patch, because double EPG entries will be minimized.
+-fixed compile problem when using NO_EPG patch
+-added hexdump routine for debugging
+-improved use of TableId's, so now the plugin can decide whether to overwrite or to preserve the existing EPG data
+-improved several routines, less memory use, less cpu use.
+
+Release 0.0.1:
+First release.
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..49e8770
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,136 @@
+#
+# EEPG plugin to VDR
+#
+# (C) 2008-2009 Dingo35
+#
+# This code 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 code 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, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+# Or, point your browser to http://www.gnu.org/copyleft/gpl.html
+
+# The official name of this plugin.
+# This name will be used in the '-P...' option of VDR to load the plugin.
+# By default the main source file also carries this name.
+#
+PLUGIN = eepg
+
+### The version number of this plugin (taken from the main source file):
+
+VERSION = $(shell grep 'static const char \*VERSION *=' $(PLUGIN).c | awk '{ print $$6 }' | sed -e 's/[";]//g')
+
+### The C++ compiler and options:
+
+CXX ?= g++
+CXXFLAGS ?= -O2 -fPIC -Wall -Woverloaded-virtual
+
+### The directory environment:
+
+VDRDIR = ../../..
+LIBDIR = ../../lib
+TMPDIR = /tmp
+
+### Allow user defined options to overwrite defaults:
+
+-include $(VDRDIR)/Make.config
+-include Make.config
+
+### The version number of VDR (taken from VDR's "config.h"):
+
+VDRVERSION = $(shell sed -ne '/define VDRVERSION/ s/^.*"\(.*\)".*$$/\1/p' $(VDRDIR)/config.h)
+APIVERSION = $(shell sed -ne '/define APIVERSION/ s/^.*"\(.*\)".*$$/\1/p' $(VDRDIR)/config.h)
+ifeq ($(strip $(APIVERSION)),)
+ APIVERSION = $(VDRVERSION)
+endif
+
+### The name of the distribution archive:
+
+ARCHIVE = $(PLUGIN)-$(VERSION)
+PACKAGE = vdr-$(ARCHIVE)
+
+### Includes and Defines (add further entries here):
+
+INCLUDES += -I$(VDRDIR)/include
+
+DEFINES += -D_GNU_SOURCE -DPLUGIN_NAME_I18N='"$(PLUGIN)"'
+
+### The object files (add further files here):
+
+OBJS = $(PLUGIN).o dish.o epghandler.o setupeepg.o equivhandler.o util.o eit2.o
+
+ifdef DBG
+CXXFLAGS += -g
+endif
+
+### Internationalization (I18N):
+
+PODIR = po
+I18Npot = $(PODIR)/$(PLUGIN).pot
+I18Nmsgs = $(addprefix $(LOCALEDIR)/,$(addsuffix /LC_MESSAGES/vdr-$(PLUGIN).mo,$(notdir $(foreach file, $(wildcard $(PODIR)/*.po), $(basename $(file))))))
+LOCALEDIR = $(VDRDIR)/locale
+
+### Default Target
+default: $(OBJS)
+
+### Dependencies:
+
+MAKEDEP = $(CXX) -MM -MG
+DEPFILE = .dependencies
+$(DEPFILE): Makefile
+ @$(MAKEDEP) $(DEFINES) $(INCLUDES) $(OBJS:%.o=%.c) > $@
+
+-include $(DEPFILE)
+
+### Targets:
+
+TARGETS = libvdr-$(PLUGIN).so
+ifneq ($(shell grep -l 'Phrases' $(VDRDIR)/i18n.c),$(VDRDIR)/i18n.c)
+TARGETS += i18n
+endif
+
+all: $(TARGETS)
+.PHONY: i18n
+
+%.o: %.c
+ $(CXX) $(CXXFLAGS) -c $(DEFINES) $(INCLUDES) $<
+
+libvdr-$(PLUGIN).so: $(OBJS)
+ $(CXX) $(CXXFLAGS) -shared $(OBJS) -o $@
+ @cp $@ $(LIBDIR)/$@.$(APIVERSION)
+
+$(I18Npot): $(shell grep -rl '\(tr\|trNOOP\)(\".*\")' *.c $(SYSDIR))
+ xgettext -C -cTRANSLATORS --no-wrap -F -k -ktr -ktrNOOP -o $@ $^
+
+%.po: $(I18Npot)
+ msgmerge -U --no-wrap -F --backup=none -q $@ $<
+ @touch $@
+
+%.mo: %.po
+ msgfmt -c -o $@ $<
+
+$(I18Nmsgs): $(LOCALEDIR)/%/LC_MESSAGES/vdr-$(PLUGIN).mo: $(PODIR)/%.mo
+ @mkdir -p $(dir $@)
+ cp $< $@
+
+i18n: $(I18Nmsgs)
+
+dist: clean
+ @-rm -rf $(TMPDIR)/$(ARCHIVE)
+ @mkdir $(TMPDIR)/$(ARCHIVE)
+ @cp -a * $(TMPDIR)/$(ARCHIVE)
+ @tar czf $(PACKAGE).tar.gz -C $(TMPDIR) $(ARCHIVE)
+ @-rm -rf $(TMPDIR)/$(ARCHIVE)
+ @echo Distribution package created as $(PACKAGE).tar.gz
+
+clean:
+ @-rm -f $(OBJS) $(DEPFILE) *.so *.tar.gz core* *~
+# @-rm -f $(PODIR)/*.mo $(PODIR)/*.pot
diff --git a/README b/README
new file mode 100644
index 0000000..edde5b7
--- /dev/null
+++ b/README
@@ -0,0 +1,135 @@
+
+This is the Extended EPG (EEPG) "plugin" for the Video Disk Recorder (VDR).
+
+Written by: Dingo35
+
+Mainnained by: Dimitar Petrovski <dimeptr at gmail.com>
+
+Project's homepage: http://projects.vdr-developer.org/projects/plg-eepg
+
+Latest stable version available at:
+ http://projects.vdr-developer.org/git/vdr-plugin-eepg.git/snapshot/vdr-plugin-eepg-master.tar.bz2
+Latest experimental version available at:
+ http://projects.vdr-developer.org/git/vdr-plugin-eepg.git/snapshot/vdr-plugin-eepg-experimental.tar.bz2
+
+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.
+See the file COPYING for more information.
+
+----------------------------------------------------------------------
+
+Description:
+
+This plugin parses the extended (2 to 10 day) EPG data which is send by
+providers on their portal channels. This EEPG data is transmitted in a
+non-standard format on a non-standard PID.
+
+Currently the following EEPG formats are supported:
+* Mediahighway 1 (CanaalDigitaalNL, CSat, Cyfra+)
+* Mediahighway 2 (Digital+)
+* Sky Italy
+* Sky UK
+* Freesat
+* Premiere
+* NagraGuide (CanaalDigitaalNL, only in test)
+* NA Dish and BEV
+
+INSTALL
+Unpack, make and make plugins like any other plugin. Call like any other
+On the first run, in the vdr-plugins directory a subdirectory eepg is created
+where all necessary files are created.
+One can define equivalent channels in the eepg.equiv file to "copy"
+EEPG data to other channels.
+E.g., CanaalDigitaalNL still sends Dorcel EEPG data on S19.2E, which can be used
+for Dorcel on S13.0E.
+Some sample eepg.equiv files are included.
+
+Scripts
+The provided scripts in the package can also help generate the eepg.equiv file.
+For more information see README in scripts/
+
+USE
+The plugin has no mainmenu entry, and only a few settings for Premiere.
+When one of VDR's devices is tuned to a transponder (by tuning, a recording or
+an EPG scan triggered by VDR), the plugin scans all channels on the transponder
+for the supported EEPG formats. When all of the supported formats are detected,
+all available EEPG data is loaded into the schedule of VDR.
+Additionally, the EEPG data is loaded into additional channels if they are specified
+in the eepg.equiv file (not for Premiere).
+Everything is done automatically and transparently, all is done concurrently
+with recordings and live viewings.
+Freesat and Premiere are loading their EEPG info continuously.
+
+The plugin is designed to use as less recources as possible: it only uses 1 Pid
+(especially important to users of FF cards, which have a max. of 32 Pids),
+and allocates and frees memory according to its needs.
+
+If one needs to reload EEPG data periodically, it is sufficient to create
+a cron job which tunes to the proper channel through the SVDRP interface.
+In practice, viewing and tuning to your favourite channels reloads the EEPG data daily,
+which is often enough since EEPG data is valid for 2 - 10 days.
+
+New, unknown EEPG transponders will be detected automatically (MHW1, MHW2, Freesat) or
+have to be added (Sky uses different huffman decoding tables for every country).
+
+Currently known transponders that send EEPG data:
+* Sky Italia S13.0E:11881V (OpenTV)
+* Sky UK S28.2E:11778V (OpenTV)
+* Cyfra+ S13.0E:10719V (Mediahighway 1)
+* CSat S19.2E:12363V (Mediahighway 1)
+* Canal DigitaalNL S19.2E:12515H (Mediahighway 1, NagraGuide)
+* Digital+ S19.2E:10847V (Mediahighway 2)
+* Premiere Sport Portal, Premiere Direkt Portal
+* Freesat all freesat channels
+* Dish and BEV S119.0W:12472H S91.0W12224R
+
+Please note that the NagraGuide broadcasts of Canal DigitaalNL are stil in betatest;
+therefore its information is not always reliable. It seems that sometimes, when no summaries
+are available for certain titles, random summaries are chosen by the broadcaster.
+This could, of course, also be a bug, since the protocol of NagraGuide is not published.
+It can be further investigated only when NagraGuide is taken into production, and
+certified receivers will be able to decode Nagra... in the mean time YOU can already
+enjoy the 7-day EEPG schedule!
+The unreliability of Nagra is compensated by having Mediahighway 1 overwrite Nagra-events it
+detects.
+
+For Premiere, the plugin can tag option events i.e. the same event with the same time on
+different channels e.g. F1 sub channels. The tagging format (e.g. before or
+after event name) can be selected in the plugin setup menu.
+In addition there are two switches in the plugin setup menu to control inclusion
+of order and parental rating information into the event description.
+The plugin setup menu is only for Premiere protocol!
+
+
+THANKS
+This code is based on:
+* Premiere plugin (C) 2005-2007 Stefan Huelswitt <s.huelswitt at gmx.de>
+* mhwepg program (C) 2002, 2003 Jean-Claude Repetto <mhwepg at repetto.org>
+* LoadEpg plugin written by Luca De Pieri <dpluca at libero.it>
+* Freesat patch written by dom /at/ suborbital.org.uk
+* Dish/BEV patch written by
+* cAddEventThread from EPGFixer plugin by Matti Lehtimaki matti.lehtimaki /at/ gmail.com
+Thanks to mrgandalf, and the others who helped map NA eit.
+Thanks to VDR User for testing and providing makequiv.sh script for S72.7W channels.
+
+We wish to thank all authors for the great work they have been doing, decoding
+this EEPG data; this plugin tries to combine the best of all worlds.
+Specific improvement has been done on Mediahigway 1 protocol: all software known
+tries to combine titles and summaries on the basis of the event-id, but several
+channels can use the same event-id at the same time. This leads in practice to
+20-25% erroneous summaries. The plugin uses the same technique as more simple
+satellite receivers, which take into account the order in which titles
+and summaries are sent. This leads to 99-100% accuracy.
+Also, the "number of replays" technique for CSAT is implemented correctly; not all
+software supported this information, which leads to loss of 80-90% of the EEPG
+information.
+
+
+KNOWN BUGS
+-Equivalents file is not used for Premiere.
+-On Sky Italy and Sky UK, a lot of "summaries not found" are reported. This is
+ because it is not (yet) known where the "summary available" flag is coded in the
+ OpenTV protocol used, so all titles are assumed to have a summary available.
+
diff --git a/TODO b/TODO
new file mode 100644
index 0000000..50c9f51
--- /dev/null
+++ b/TODO
@@ -0,0 +1,14 @@
+TODO/WISH:
+-Missing support for Freesat DVB-T
+-extend equivalents file with transponder SKIP (do not retrieve EEPG info) or
+ transponder ONCE (retrieve once a day, first possiblity after midnight).
+ TUNE (retrieve every time transponder gets tuned to) transponder CONT (retrieve continuously)
+-look at collisions and language problems (eg Cyfra at MTV)
+-check broadcasting frequencys + windows of all providers; report first event seen and last event seen
+-use event-> as database instead of title[] and summary[] , except for MHW1
+-try to minimize resync problems by using sliding window after "lock" on 50 succesfull sequential syncs or so
+-stop premiere after having read all titles (from CONT to ONCE)
+-check version info for all providers
+-decode summary-available bit for OpenTV
+-parallellize when not on FF card
+-NAGRA 2nd textstring is not used right now, find out when it is relevant...
diff --git a/dish.c b/dish.c
new file mode 100644
index 0000000..d257d91
--- /dev/null
+++ b/dish.c
@@ -0,0 +1,619 @@
+/***************************************************************************
+ * *
+ * These routines decompress Huffman coded Dish Network EIT data. *
+ * The implementation is based on the algorithm presentend in *
+ * *
+ * "A memory-efficient Huffman decoding algorithm" *
+ * Pi-Chung Wang, Yuan-Rung Yang, Chun-Liang Lee, Hung-Yi Chang *
+ * Proceedings of the 19th International Conference on Advanced *
+ * Information Networking and Applications (AINA'05) *
+ * *
+ ***************************************************************************/
+
+#include "dish.h"
+#include <libsi/si.h>
+//#include <libsi/descriptor.h>
+#include <string.h>
+#include <string>
+#include <stdlib.h>
+#include <vdr/tools.h>
+
+namespace SI
+{
+
+ // returns the value of a sequence of bits in the byte array
+ static unsigned int getBits(int bitIndex, int bitCount, const unsigned char *byteptr,
+ int length) {
+ union
+ {
+ unsigned char b[4];
+ unsigned long val;
+ } chunk;
+
+ int offset = bitIndex >> 3;
+ int bitnum = bitIndex - (offset << 3);
+ int rightend = 32 - bitnum - bitCount;
+
+ chunk.b[3] = byteptr[offset];
+ chunk.b[2] = (offset + 1 < length) ? byteptr[offset + 1] : 0;
+ chunk.b[1] = (offset + 2 < length) ? byteptr[offset + 2] : 0;
+ chunk.b[0] = 0; // Never need to look this far ahead.
+
+ return (unsigned int) ((((((chunk.val & (0xFFFFFFFF >> bitnum)) >> rightend)))));
+ }
+
+ DishDescriptor::DishDescriptor()
+ {
+ name = NULL;
+ shortText = NULL;
+ description = NULL;
+ decompressedShort = NULL;
+ decompressedExtended = NULL;
+ DishTheme = 0;
+ DishCategory = 0;
+ mpaaRating = 0;
+ starRating = 0;
+ originalAirDate = 0;
+ programId = NULL;
+ seriesId = NULL;
+ ratingStr = NULL;
+ }
+
+ DishDescriptor::~DishDescriptor()
+ {
+ delete [] decompressedShort;
+ decompressedShort = NULL;
+ delete [] decompressedExtended;
+ decompressedExtended = NULL;
+ delete [] programId;
+ programId = NULL;
+ delete [] seriesId;
+ seriesId = NULL;
+ }
+
+ const char *DishDescriptor::getTheme()
+ {
+ const char* theme;
+ using namespace DISH_THEMES;
+
+ switch (DishTheme){
+ case Movie:
+ theme = "Movie";
+ break;
+ case Sports:
+ theme = "Sports";
+ break;
+ case News_Business:
+ theme = "News/Business";
+ break;
+ case Family_Children:
+ theme = "Family/Children";
+ break;
+ case Education:
+ theme = "Education";
+ break;
+ case Series_Special:
+ theme = "Series/Special";
+ break;
+ case Music_Art:
+ theme = "Music/Art";
+ break;
+ case Religious:
+ theme = "Religious";
+ break;
+ default:
+ theme = "";
+ break;
+ }
+ return theme;
+ }
+
+ const char *DishDescriptor::getCategory()
+ {
+ using namespace DISH_CATEGORIES;
+
+ switch (DishCategory) {
+ case Action: return "Action";
+ case ActionSports: return "Action Sports";
+ case Adults_only: return "Adults only";
+ case Adventure: return "Adventure";
+ case Agriculture: return "Agriculture";
+ case AirRacing: return "Air racing";
+ case Animals: return "Animals";
+ case Animated: return "Animated";
+ case Anime: return "Anime";
+ case Anthology: return "Anthology";
+ case ArmWrestling: return "Arm wrestling";
+ case Art: return "Art";
+ case Arts_crafts: return "Arts/crafts";
+ case Auction: return "Auction";
+ case Auto: return "Auto";
+ case AutoRacing: return "Auto racing";
+ case Awards: return "Awards";
+ case Badminton: return "Badminton";
+ case Ballet: return "Ballet";
+ case Baseball: return "Baseball";
+ case Basketball: return "Basketball";
+ case BicycleRacing: return "Bicycle racing";
+ case Biography: return "Biography";
+ case Boat: return "Boat";
+ case BoatRacing: return "Boat racing";
+ case Bowling: return "Bowling";
+ case Boxing: return "Boxing";
+ case Bus_financial: return "Bus./financial";
+ case CardGames: return "Card games";
+ case Children: return "Children";
+ case ChildrenMusic: return "Children music";
+ case ChildrenNews: return "Children news";
+ case ChildrenSpecial: return "Children special";
+ case Collectibles: return "Collectibles";
+ case Comedy: return "Comedy";
+ case ComedyDrama: return "Comedy-drama";
+ case Community: return "Community";
+ case Computers: return "Computers";
+ case Consumer: return "Consumer";
+ case Cooking: return "Cooking";
+ case Crime: return "Crime";
+ case CrimeDrama: return "Crime drama";
+ case Dance: return "Dance";
+ case Debate: return "Debate";
+ case DishNetwork: return "Dish Network";
+ case Docudrama: return "Docudrama";
+ case Documentary: return "Documentary";
+ case DogShow: return "DogShow";
+ case DragRacing: return "DragRacing";
+ case Drama: return "Drama";
+ case Educational: return "Educational";
+ case Entertainment: return "Entertainment";
+ case Environment: return "Environment";
+ case Equestrian: return "Equestrian";
+ case Excercise: return "Excercise";
+ case Fantasy: return "Fantasy";
+ case Fashion: return "Fashion";
+ case FieldHockey: return "Field hockey";
+ case Fishing: return "Fishing";
+ case Football:
+ case Football2: return "Football";
+ case French: return "French";
+ case Fundraiser: return "Fundraiser";
+ case GameShow: return "GameShow";
+ case Gay_lesbian: return "Gay/lesbian";
+ case Golf: return "Golf";
+ case Gymnastics: return "Gymnastics";
+ case Handball: return "Handball";
+ case Health: return "Health";
+ case HistoricalDrama: return "Historical drama";
+ case History: return "History";
+ case Hockey: return "Hockey";
+ case Holiday: return "Holiday";
+ case HolidayChildren: return "Holiday children";
+ case HolidayChildrenSpecial: return "Holiday children special";
+ case HolidaySpecial: return "Holiday special";
+ case HomeImprovement: return "Home improvement";
+ case Horror: return "Horror";
+ case HorseRacing: return "Horse racing";
+ case House_garden: return "House/garden";
+ case HowTo: return "HowTo";
+ case Hunting: return "Hunting";
+ case HydroplaneRacing: return "Hydroplane racing";
+ case Interview: return "Interview";
+ case Lacrosse: return "Lacrosse";
+ case Law: return "Law";
+ case MartialArts: return "Martial arts";
+ case Medical: return "Medical";
+ case Military: return "Military";
+ case Miniseries: return "Miniseries";
+ case MixedMartialArts: return "Mixed martial arts";
+ case Motorcycle: return "Motorcycle";
+ case MotorcycleRacing: return "Motorcycle racing";
+ case Motorsports: return "Motorsports";
+ case Music: return "Music";
+ case MusicSpecial: return "Music special";
+ case MusicTalk: return "Music talk";
+ case Musical: return "Musical";
+ case MusicalComedy: return "Musical comedy";
+ case Mystery: return "Mystery";
+ case Nature: return "Nature";
+ case News: return "News";
+ case Newsmagazine: return "Newsmagazine";
+ case Opera: return "Opera";
+ case Outdoors: return "Outdoors";
+ case Paranormal: return "Paranormal";
+ case Parenting: return "Parenting";
+ case PerformingArts: return "Performing arts";
+ case Poker: return "Poker";
+ case Politics: return "Politics";
+ case ProWrestling: return "Pro wrestling";
+ case PublicAffairs: return "Public affairs";
+ case Reality: return "Reality";
+ case Religious: return "Religious";
+ case Rodeo: return "Rodeo";
+ case Romance: return "Romance";
+ case RomanceComedy: return "Romance comedy";
+ case Rugby: return "Rugby";
+ case Running: return "Running";
+ case Sailing: return "Sailing";
+ case Science: return "Science";
+ case ScienceFiction: return "Science fiction";
+ case SelfImprovement: return "Self improvement";
+ case Shooting: return "Shooting";
+ case Shopping: return "Shopping";
+ case Sitcom: return "Sitcom";
+ case Skateboarding: return "Skateboarding";
+ case Skiing: return "Skiing";
+ case Snowboarding: return "Snowboarding";
+ case Soap: return "Soap";
+ case Soccor: return "Soccor";
+ case Softball: return "Softball";
+ case Spanish: return "Spanish";
+ case Special: return "Special";
+ case SportsNonEvent: return "SportsNonEvent";
+ case SportsTalk: return "SportsTalk";
+ case Standup: return "Standup";
+ case Surfing: return "Surfing";
+ case Suspense: return "Suspense";
+ case Swimming: return "Swimming";
+ case Talk: return "Talk";
+ case Technology: return "Technology";
+ case Tennis:
+ case Tennis2: return "Tennis";
+ case Track_field: return "Track/field";
+ case Travel: return "Travel";
+ case Triathlon: return "Triathlon";
+ case Variety: return "Variety";
+ case Volleyball: return "Volleyball";
+ case War: return "War";
+ case Watersports: return "Watersports";
+ case Weather: return "Weather";
+ case Western: return "Western";
+ case Wrestling: return "Wrestling";
+ case Yoga: return "Yoga";
+ default: return "";
+ }
+ }
+
+ void DishDescriptor::setShortData(unsigned char Tid, CharArray data)
+ {
+ decompressedShort = Decompress(Tid, data);
+ if (decompressedShort) {
+ name = (char*)decompressedShort;
+ }
+ }
+
+ void DishDescriptor::setExtendedtData(unsigned char Tid, CharArray data)
+ {
+ decompressedExtended = Decompress(Tid, data);
+ if (decompressedExtended) {
+ char *split = strchr((char*)((decompressedExtended)), 0x0D); // Look for carriage return
+ //LogD(2, prep("dLength:%d, length:%d, count:%d, decompressed: %s"), dLength, length, count, decompressed);
+ if(split){
+ *split = 0;
+ shortText = (char*)decompressedExtended;
+ description = (split[1] == 0x20) ? split + 2 : split + 1;
+ }else{
+ description = (char*)decompressedExtended;
+ }
+ }
+ }
+
+ const char *DishDescriptor::getShortText(void)
+ {
+// string tmp = "";
+//// if (shortText != NULL) tmp += *shortText;
+// tmp += shortText;
+// if(DishTheme > 0){
+// if(tmp != "") tmp += " - ";
+//
+// tmp += getTheme();
+// }
+// if(DishCategory > 0){
+// if(tmp != "") tmp += " - ";
+//
+// tmp += getCategory();
+// }
+// return tmp.c_str();
+ return shortText?shortText:"";
+ }
+
+ const char *DishDescriptor::getDescription(void) {
+// string tmp = "";
+//// if (description != NULL) tmp += *description;
+// tmp += description;
+// const char* rating = getRating();
+// if (rating && strcmp(rating,"") != 0) {
+// if(tmp != "") tmp += " ~ ";
+// tmp += rating;
+// }
+// if (starRating > 0) {
+// if(tmp != "") tmp += " ~ ";
+// tmp += getStarRating();
+// }
+// return tmp.c_str();
+ return description?description:"";
+ }
+
+ const char *DishDescriptor::getProgramId(void) {
+ return programId?programId:"";
+ }
+
+ const char *DishDescriptor::getSeriesId(void) {
+ return seriesId?seriesId:"";
+ }
+
+ void DishDescriptor::setEpisodeInfo(CharArray data)
+ {
+ data.addOffset(2);
+ int series = (data[1] << 0x12) | (data[2] << 0x0a) | (data[3] << 0x02) | ((data[4] & 0xc0) >> 0x06);
+ int episode = ((data[4] & 0x3f) << 0x08) | data[5];
+ const char* prefix;
+
+ if (data[0] == 0x7c)
+ prefix = "MV";
+ else if (data[0] == 0x7d)
+ prefix = "SP";
+ else if (data[0] == 0x7e)
+ prefix = "EP";
+ else
+ prefix ="";
+
+ programId = new char[17];
+
+ sprintf(programId, "%s%08d%04d", (data[0] == 0x7e && episode == 0 ? "SH" : prefix), series, episode);
+
+ if (data[0] == 0x7e) {
+ seriesId = new char[11];
+ sprintf(seriesId, "%s%08d", prefix, series);
+ }
+
+ if (data.TwoBytes(6) != 0 && data.TwoBytes(6) != 0x9e8b ) {
+ originalAirDate = ((data[6] << 0x08 | data[7]) - 40587) * 86400;
+ }
+ }
+
+ void DishDescriptor::setContent(ContentDescriptor::Nibble Nibble)
+ {
+ DishTheme = Nibble.getContentNibbleLevel2() & 0xF;
+ DishCategory = ((Nibble.getUserNibble1() & 0xF) << 4) | (Nibble.getUserNibble2() & 0xF);
+ }
+
+ void DishDescriptor::setRating(uint16_t rating)
+ {
+ uint16_t newRating = (rating >> 10) & 0x07;
+ if (newRating == 0) newRating = 5;
+ if (newRating == 6) newRating = 0;
+ mpaaRating = (newRating << 10) | (rating & 0x3FF);
+ starRating = (rating >> 13) & 0x07;
+ }
+
+ const char* DishDescriptor::getRating(){
+ static const char *const ratings[8] = { "", "G", "PG", "PG-13", "R", "NR/AO", "", "NC-17" };
+
+ if (mpaaRating == 0) {
+ return ratings[mpaaRating];
+ }
+
+ std::string str = ratings[(mpaaRating >> 10) & 0x07];
+// char buffer[19];
+// buffer[0] = 0;
+// strcpy(buffer, ratings[(mpaaRating >> 10) & 0x07]);
+ if (mpaaRating & 0x3A7F) {
+ str += " [";
+// strcat(buffer, " [");
+ if (mpaaRating & 0x0230)
+ str += "V,";
+// strcat(buffer, "V,");
+ if (mpaaRating & 0x000A)
+ str += "L,";
+// strcat(buffer, "L,");
+ if (mpaaRating & 0x0044)
+ str += "N,";
+// strcat(buffer, "N,");
+ if (mpaaRating & 0x0101)
+ str += "SC,";
+// strcat(buffer, "SC,");
+// if (char *s = strrchr(buffer, ','))
+// s[0] = ']';
+ if (str.find(',') != std::string::npos) {
+ str.erase(str.find_last_of(','));
+ }
+ str += "]";
+ }
+
+ if (!ratingStr) ratingStr = new char[19];
+ if (ratingStr) strcpy(ratingStr,str.c_str());
+ return ratingStr;
+
+// return isempty(buffer) ? "" : buffer;
+ }
+
+ const char* DishDescriptor::getStarRating(){
+ static const char *const critiques[8] = { "", "*", "*+", "**", "**+", "***", "***+", "****" };
+ return critiques[starRating & 0x07];
+ }
+
+ unsigned char* DishDescriptor::Decompress(unsigned char Tid, CharArray data)
+ {
+ const unsigned char *str = data.getData();
+ const unsigned char *cmp = NULL;
+ int length = 0; // Length of compressed data
+ unsigned int dLength = 0; // Length of decompressed data
+ if((str[3] & 0xFC) == 0x80){
+ length = str[1] - 2;
+ dLength = (str[2] & 0x40) ? ((str[3] << 6) & 0xFF) | (str[2] & 0x3F) : str[2] & 0x3F;
+ cmp = str + 4;
+ }else{
+ length = str[1] - 1;
+ dLength = str[2] & 0x7F;
+ cmp = str + 3;
+ }
+ if(length <= 0 || !dLength)
+ return NULL;
+
+ unsigned char* decompressed = new unsigned char[dLength + 1];
+ HuffmanTable *table;
+ unsigned int tableSize, numBits;
+ if (Tid > 0x80) {
+ table = Table255;
+ tableSize = SIZE_TABLE_255;
+ numBits = 13;
+ } else {
+ table = Table128;
+ tableSize = SIZE_TABLE_128;
+ numBits = 11;
+ }
+ unsigned int bLength = length << 3; // number of bits
+ unsigned int currentBit = 0, count = 0;
+ while(currentBit < bLength - 1 && count < dLength){
+ // Find the interval containing the sequence of length numBits starting
+ // at currentBit. The corresponding character will be the one encoded
+ // at the begin of the sequence.
+ unsigned int code = getBits(currentBit, numBits, cmp, length);
+ // We could use a binary search, but in practice this linear search is faster.
+ unsigned int index = 0;
+ while(table[index].startingAddress <= code && index < tableSize){
+ index++;
+ }
+ index--;
+ decompressed[count++] = table[index].character;
+ currentBit += table[index].numberOfBits;
+ }
+
+ decompressed[count] = 0;
+ return decompressed;
+ }
+
+struct DishDescriptor::HuffmanTable DishDescriptor::Table128[SIZE_TABLE_128] = {
+ { 0x0000, 0x20, 0x03 }, { 0x0100, 0x65, 0x04 }, { 0x0180, 0x74, 0x04 },
+ { 0x0200, 0x61, 0x04 }, { 0x0280, 0x6F, 0x04 }, { 0x0300, 0x73, 0x04 },
+ { 0x0380, 0x6E, 0x04 }, { 0x0400, 0x72, 0x06 }, { 0x0420, 0x69, 0x06 },
+ { 0x0440, 0x6C, 0x06 }, { 0x0460, 0x63, 0x06 }, { 0x0480, 0x68, 0x06 },
+ { 0x04A0, 0x75, 0x06 }, { 0x04C0, 0x64, 0x06 }, { 0x04E0, 0x70, 0x06 },
+ { 0x0500, 0x6D, 0x06 }, { 0x0520, 0x67, 0x06 }, { 0x0540, 0x79, 0x06 },
+ { 0x0560, 0x76, 0x06 }, { 0x0580, 0x0A, 0x06 }, { 0x05A0, 0x2E, 0x06 },
+ { 0x05C0, 0x77, 0x06 }, { 0x05E0, 0x66, 0x06 }, { 0x0600, 0x53, 0x07 },
+ { 0x0610, 0x62, 0x07 }, { 0x0620, 0x54, 0x07 }, { 0x0630, 0x22, 0x07 },
+ { 0x0640, 0x6B, 0x07 }, { 0x0650, 0x50, 0x07 }, { 0x0660, 0x41, 0x07 },
+ { 0x0670, 0x43, 0x07 }, { 0x0680, 0x44, 0x07 }, { 0x0690, 0x4C, 0x07 },
+ { 0x06A0, 0x4D, 0x07 }, { 0x06B0, 0x49, 0x07 }, { 0x06C0, 0x4E, 0x07 },
+ { 0x06D0, 0x3A, 0x07 }, { 0x06E0, 0x52, 0x07 }, { 0x06F0, 0x2C, 0x07 },
+ { 0x0700, 0x45, 0x08 }, { 0x0708, 0x55, 0x08 }, { 0x0710, 0x46, 0x08 },
+ { 0x0718, 0x48, 0x08 }, { 0x0720, 0x59, 0x08 }, { 0x0728, 0x56, 0x08 },
+ { 0x0730, 0x2D, 0x08 }, { 0x0738, 0x7A, 0x08 }, { 0x0740, 0x78, 0x08 },
+ { 0x0748, 0x2F, 0x08 }, { 0x0750, 0x4F, 0x08 }, { 0x0758, 0x3F, 0x08 },
+ { 0x0760, 0x57, 0x08 }, { 0x0768, 0x47, 0x08 }, { 0x0770, 0x42, 0x08 },
+ { 0x0778, 0x33, 0x08 }, { 0x0780, 0x31, 0x09 }, { 0x0784, 0x71, 0x09 },
+ { 0x0788, 0x30, 0x09 }, { 0x078C, 0x21, 0x09 }, { 0x0790, 0x6A, 0x09 },
+ { 0x0794, 0x5A, 0x09 }, { 0x0798, 0x39, 0x09 }, { 0x079C, 0x34, 0x09 },
+ { 0x07A0, 0x4B, 0x09 }, { 0x07A4, 0x2A, 0x09 }, { 0x07A8, 0x37, 0x09 },
+ { 0x07AC, 0x36, 0x09 }, { 0x07B0, 0x35, 0x09 }, { 0x07B4, 0x4A, 0x09 },
+ { 0x07B8, 0x38, 0x09 }, { 0x07BC, 0x29, 0x09 }, { 0x07C0, 0x28, 0x0A },
+ { 0x07C2, 0x58, 0x0A }, { 0x07C4, 0x51, 0x0A }, { 0x07C6, 0x3C, 0x0A },
+ { 0x07C8, 0x32, 0x0A }, { 0x07CA, 0x27, 0x0A }, { 0x07CC, 0x26, 0x0A },
+ { 0x07CE, 0x7F, 0x0B }, { 0x07CF, 0x7E, 0x0B }, { 0x07D0, 0x7D, 0x0B },
+ { 0x07D1, 0x7C, 0x0B }, { 0x07D2, 0x7B, 0x0B }, { 0x07D3, 0x60, 0x0B },
+ { 0x07D4, 0x5F, 0x0B }, { 0x07D5, 0x5E, 0x0B }, { 0x07D6, 0x5D, 0x0B },
+ { 0x07D7, 0x5C, 0x0B }, { 0x07D8, 0x5B, 0x0B }, { 0x07D9, 0x40, 0x0B },
+ { 0x07DA, 0x3E, 0x0B }, { 0x07DB, 0x3D, 0x0B }, { 0x07DC, 0x3B, 0x0B },
+ { 0x07DD, 0x2B, 0x0B }, { 0x07DE, 0x25, 0x0B }, { 0x07DF, 0x24, 0x0B },
+ { 0x07E0, 0x23, 0x0B }, { 0x07E1, 0x1F, 0x0B }, { 0x07E2, 0x1E, 0x0B },
+ { 0x07E3, 0x1D, 0x0B }, { 0x07E4, 0x1C, 0x0B }, { 0x07E5, 0x1B, 0x0B },
+ { 0x07E6, 0x1A, 0x0B }, { 0x07E7, 0x19, 0x0B }, { 0x07E8, 0x18, 0x0B },
+ { 0x07E9, 0x17, 0x0B }, { 0x07EA, 0x16, 0x0B }, { 0x07EB, 0x15, 0x0B },
+ { 0x07EC, 0x14, 0x0B }, { 0x07ED, 0x13, 0x0B }, { 0x07EE, 0x12, 0x0B },
+ { 0x07EF, 0x11, 0x0B }, { 0x07F0, 0x10, 0x0B }, { 0x07F1, 0x0F, 0x0B },
+ { 0x07F2, 0x0E, 0x0B }, { 0x07F3, 0x0D, 0x0B }, { 0x07F4, 0x0C, 0x0B },
+ { 0x07F5, 0x0B, 0x0B }, { 0x07F6, 0x09, 0x0B }, { 0x07F7, 0x08, 0x0B },
+ { 0x07F8, 0x07, 0x0B }, { 0x07F9, 0x06, 0x0B }, { 0x07FA, 0x05, 0x0B },
+ { 0x07FB, 0x04, 0x0B }, { 0x07FC, 0x03, 0x0B }, { 0x07FD, 0x02, 0x0B },
+ { 0x07FE, 0x01, 0x0B }, { 0x07FF, 0x00, 0x0B }
+};
+
+struct DishDescriptor::HuffmanTable DishDescriptor::Table255[SIZE_TABLE_255] = {
+ { 0x0000, 0x20, 0x02 }, { 0x0800, 0x65, 0x04 }, { 0x0A00, 0x72, 0x04 },
+ { 0x0C00, 0x6E, 0x04 }, { 0x0E00, 0x61, 0x04 }, { 0x1000, 0x74, 0x05 },
+ { 0x1100, 0x6F, 0x05 }, { 0x1200, 0x73, 0x05 }, { 0x1300, 0x69, 0x05 },
+ { 0x1400, 0x6C, 0x05 }, { 0x1500, 0x75, 0x05 }, { 0x1600, 0x63, 0x05 },
+ { 0x1700, 0x64, 0x05 }, { 0x1800, 0x70, 0x07 }, { 0x1840, 0x6D, 0x07 },
+ { 0x1880, 0x76, 0x07 }, { 0x18C0, 0x67, 0x07 }, { 0x1900, 0x68, 0x07 },
+ { 0x1940, 0x2E, 0x07 }, { 0x1980, 0x66, 0x07 }, { 0x19C0, 0x0A, 0x07 },
+ { 0x1A00, 0x53, 0x07 }, { 0x1A40, 0x41, 0x07 }, { 0x1A80, 0x45, 0x07 },
+ { 0x1AC0, 0x43, 0x07 }, { 0x1B00, 0x27, 0x07 }, { 0x1B40, 0x7A, 0x07 },
+ { 0x1B80, 0x52, 0x07 }, { 0x1BC0, 0x22, 0x07 }, { 0x1C00, 0x4C, 0x08 },
+ { 0x1C20, 0x49, 0x08 }, { 0x1C40, 0x4F, 0x08 }, { 0x1C60, 0x62, 0x08 },
+ { 0x1C80, 0x54, 0x08 }, { 0x1CA0, 0x4E, 0x08 }, { 0x1CC0, 0x55, 0x08 },
+ { 0x1CE0, 0x79, 0x08 }, { 0x1D00, 0x44, 0x08 }, { 0x1D20, 0x50, 0x08 },
+ { 0x1D40, 0x71, 0x08 }, { 0x1D60, 0x56, 0x08 }, { 0x1D80, 0x2D, 0x08 },
+ { 0x1DA0, 0x3A, 0x08 }, { 0x1DC0, 0x2C, 0x08 }, { 0x1DE0, 0x48, 0x08 },
+ { 0x1E00, 0x4D, 0x09 }, { 0x1E10, 0x78, 0x09 }, { 0x1E20, 0x77, 0x09 },
+ { 0x1E30, 0x42, 0x09 }, { 0x1E40, 0x47, 0x09 }, { 0x1E50, 0x46, 0x09 },
+ { 0x1E60, 0x30, 0x09 }, { 0x1E70, 0x3F, 0x09 }, { 0x1E80, 0x33, 0x09 },
+ { 0x1E90, 0x2F, 0x09 }, { 0x1EA0, 0x39, 0x09 }, { 0x1EB0, 0x31, 0x09 },
+ { 0x1EC0, 0x38, 0x09 }, { 0x1ED0, 0x6B, 0x09 }, { 0x1EE0, 0x6A, 0x09 },
+ { 0x1EF0, 0x21, 0x09 }, { 0x1F00, 0x36, 0x0A }, { 0x1F08, 0x35, 0x0A },
+ { 0x1F10, 0x59, 0x0A }, { 0x1F18, 0x51, 0x0A }, { 0x1F20, 0x34, 0x0B },
+ { 0x1F24, 0x58, 0x0B }, { 0x1F28, 0x32, 0x0B }, { 0x1F2C, 0x2B, 0x0B },
+ { 0x1F30, 0x2A, 0x0B }, { 0x1F34, 0x5A, 0x0B }, { 0x1F38, 0x4A, 0x0B },
+ { 0x1F3C, 0x29, 0x0B }, { 0x1F40, 0x28, 0x0C }, { 0x1F42, 0x23, 0x0C },
+ { 0x1F44, 0x57, 0x0C }, { 0x1F46, 0x4B, 0x0C }, { 0x1F48, 0x3C, 0x0C },
+ { 0x1F4A, 0x37, 0x0C }, { 0x1F4C, 0x7D, 0x0C }, { 0x1F4E, 0x7B, 0x0C },
+ { 0x1F50, 0x60, 0x0C }, { 0x1F52, 0x26, 0x0C }, { 0x1F54, 0xFE, 0x0D },
+ { 0x1F55, 0xFD, 0x0D }, { 0x1F56, 0xFC, 0x0D }, { 0x1F57, 0xFB, 0x0D },
+ { 0x1F58, 0xFA, 0x0D }, { 0x1F59, 0xF9, 0x0D }, { 0x1F5A, 0xF8, 0x0D },
+ { 0x1F5B, 0xF7, 0x0D }, { 0x1F5C, 0xF6, 0x0D }, { 0x1F5D, 0xF5, 0x0D },
+ { 0x1F5E, 0xF4, 0x0D }, { 0x1F5F, 0xF3, 0x0D }, { 0x1F60, 0xF2, 0x0D },
+ { 0x1F61, 0xF1, 0x0D }, { 0x1F62, 0xF0, 0x0D }, { 0x1F63, 0xEF, 0x0D },
+ { 0x1F64, 0xEE, 0x0D }, { 0x1F65, 0xED, 0x0D }, { 0x1F66, 0xEC, 0x0D },
+ { 0x1F67, 0xEB, 0x0D }, { 0x1F68, 0xEA, 0x0D }, { 0x1F69, 0xE9, 0x0D },
+ { 0x1F6A, 0xE8, 0x0D }, { 0x1F6B, 0xE7, 0x0D }, { 0x1F6C, 0xE6, 0x0D },
+ { 0x1F6D, 0xE5, 0x0D }, { 0x1F6E, 0xE4, 0x0D }, { 0x1F6F, 0xE3, 0x0D },
+ { 0x1F70, 0xE2, 0x0D }, { 0x1F71, 0xE1, 0x0D }, { 0x1F72, 0xE0, 0x0D },
+ { 0x1F73, 0xDF, 0x0D }, { 0x1F74, 0xDE, 0x0D }, { 0x1F75, 0xDD, 0x0D },
+ { 0x1F76, 0xDC, 0x0D }, { 0x1F77, 0xDB, 0x0D }, { 0x1F78, 0xDA, 0x0D },
+ { 0x1F79, 0xD9, 0x0D }, { 0x1F7A, 0xD8, 0x0D }, { 0x1F7B, 0xD7, 0x0D },
+ { 0x1F7C, 0xD6, 0x0D }, { 0x1F7D, 0xD5, 0x0D }, { 0x1F7E, 0xD4, 0x0D },
+ { 0x1F7F, 0xD3, 0x0D }, { 0x1F80, 0xD2, 0x0D }, { 0x1F81, 0xD1, 0x0D },
+ { 0x1F82, 0xD0, 0x0D }, { 0x1F83, 0xCF, 0x0D }, { 0x1F84, 0xCE, 0x0D },
+ { 0x1F85, 0xCD, 0x0D }, { 0x1F86, 0xCC, 0x0D }, { 0x1F87, 0xCB, 0x0D },
+ { 0x1F88, 0xCA, 0x0D }, { 0x1F89, 0xC9, 0x0D }, { 0x1F8A, 0xC8, 0x0D },
+ { 0x1F8B, 0xC7, 0x0D }, { 0x1F8C, 0xC6, 0x0D }, { 0x1F8D, 0xC5, 0x0D },
+ { 0x1F8E, 0xC4, 0x0D }, { 0x1F8F, 0xC3, 0x0D }, { 0x1F90, 0xC2, 0x0D },
+ { 0x1F91, 0xC1, 0x0D }, { 0x1F92, 0xC0, 0x0D }, { 0x1F93, 0xBF, 0x0D },
+ { 0x1F94, 0xBE, 0x0D }, { 0x1F95, 0xBD, 0x0D }, { 0x1F96, 0xBC, 0x0D },
+ { 0x1F97, 0xBB, 0x0D }, { 0x1F98, 0xBA, 0x0D }, { 0x1F99, 0xB9, 0x0D },
+ { 0x1F9A, 0xB8, 0x0D }, { 0x1F9B, 0xB7, 0x0D }, { 0x1F9C, 0xB6, 0x0D },
+ { 0x1F9D, 0xB5, 0x0D }, { 0x1F9E, 0xB4, 0x0D }, { 0x1F9F, 0xB3, 0x0D },
+ { 0x1FA0, 0xB2, 0x0D }, { 0x1FA1, 0xB1, 0x0D }, { 0x1FA2, 0xB0, 0x0D },
+ { 0x1FA3, 0xAF, 0x0D }, { 0x1FA4, 0xAE, 0x0D }, { 0x1FA5, 0xAD, 0x0D },
+ { 0x1FA6, 0xAC, 0x0D }, { 0x1FA7, 0xAB, 0x0D }, { 0x1FA8, 0xAA, 0x0D },
+ { 0x1FA9, 0xA9, 0x0D }, { 0x1FAA, 0xA8, 0x0D }, { 0x1FAB, 0xA7, 0x0D },
+ { 0x1FAC, 0xA6, 0x0D }, { 0x1FAD, 0xA5, 0x0D }, { 0x1FAE, 0xA4, 0x0D },
+ { 0x1FAF, 0xA3, 0x0D }, { 0x1FB0, 0xA2, 0x0D }, { 0x1FB1, 0xA1, 0x0D },
+ { 0x1FB2, 0xA0, 0x0D }, { 0x1FB3, 0x9F, 0x0D }, { 0x1FB4, 0x9E, 0x0D },
+ { 0x1FB5, 0x9D, 0x0D }, { 0x1FB6, 0x9C, 0x0D }, { 0x1FB7, 0x9B, 0x0D },
+ { 0x1FB8, 0x9A, 0x0D }, { 0x1FB9, 0x99, 0x0D }, { 0x1FBA, 0x98, 0x0D },
+ { 0x1FBB, 0x97, 0x0D }, { 0x1FBC, 0x96, 0x0D }, { 0x1FBD, 0x95, 0x0D },
+ { 0x1FBE, 0x94, 0x0D }, { 0x1FBF, 0x93, 0x0D }, { 0x1FC0, 0x92, 0x0D },
+ { 0x1FC1, 0x91, 0x0D }, { 0x1FC2, 0x90, 0x0D }, { 0x1FC3, 0x8F, 0x0D },
+ { 0x1FC4, 0x8E, 0x0D }, { 0x1FC5, 0x8D, 0x0D }, { 0x1FC6, 0x8C, 0x0D },
+ { 0x1FC7, 0x8B, 0x0D }, { 0x1FC8, 0x8A, 0x0D }, { 0x1FC9, 0x89, 0x0D },
+ { 0x1FCA, 0x88, 0x0D }, { 0x1FCB, 0x87, 0x0D }, { 0x1FCC, 0x86, 0x0D },
+ { 0x1FCD, 0x85, 0x0D }, { 0x1FCE, 0x84, 0x0D }, { 0x1FCF, 0x83, 0x0D },
+ { 0x1FD0, 0x82, 0x0D }, { 0x1FD1, 0x81, 0x0D }, { 0x1FD2, 0x80, 0x0D },
+ { 0x1FD3, 0x7F, 0x0D }, { 0x1FD4, 0x7E, 0x0D }, { 0x1FD5, 0x7C, 0x0D },
+ { 0x1FD6, 0x5F, 0x0D }, { 0x1FD7, 0x5E, 0x0D }, { 0x1FD8, 0x5D, 0x0D },
+ { 0x1FD9, 0x5C, 0x0D }, { 0x1FDA, 0x5B, 0x0D }, { 0x1FDB, 0x40, 0x0D },
+ { 0x1FDC, 0x3E, 0x0D }, { 0x1FDD, 0x3D, 0x0D }, { 0x1FDE, 0x3B, 0x0D },
+ { 0x1FDF, 0x25, 0x0D }, { 0x1FE0, 0x24, 0x0D }, { 0x1FE1, 0x1F, 0x0D },
+ { 0x1FE2, 0x1E, 0x0D }, { 0x1FE3, 0x1D, 0x0D }, { 0x1FE4, 0x1C, 0x0D },
+ { 0x1FE5, 0x1B, 0x0D }, { 0x1FE6, 0x1A, 0x0D }, { 0x1FE7, 0x19, 0x0D },
+ { 0x1FE8, 0x18, 0x0D }, { 0x1FE9, 0x17, 0x0D }, { 0x1FEA, 0x16, 0x0D },
+ { 0x1FEB, 0x15, 0x0D }, { 0x1FEC, 0x14, 0x0D }, { 0x1FED, 0x13, 0x0D },
+ { 0x1FEE, 0x12, 0x0D }, { 0x1FEF, 0x11, 0x0D }, { 0x1FF0, 0x10, 0x0D },
+ { 0x1FF1, 0x0F, 0x0D }, { 0x1FF2, 0x0E, 0x0D }, { 0x1FF3, 0x0D, 0x0D },
+ { 0x1FF4, 0x0C, 0x0D }, { 0x1FF5, 0x0B, 0x0D }, { 0x1FF6, 0x09, 0x0D },
+ { 0x1FF7, 0x08, 0x0D }, { 0x1FF8, 0x07, 0x0D }, { 0x1FF9, 0x06, 0x0D },
+ { 0x1FFA, 0x05, 0x0D }, { 0x1FFB, 0x04, 0x0D }, { 0x1FFC, 0x03, 0x0D },
+ { 0x1FFD, 0x02, 0x0D }, { 0x1FFE, 0x01, 0x0D }, { 0x1FFF, 0x00, 0x0D }
+};
+
+} //end of namespace
diff --git a/dish.h b/dish.h
new file mode 100644
index 0000000..f891d7b
--- /dev/null
+++ b/dish.h
@@ -0,0 +1,300 @@
+/***************************************************************************
+ * *
+ * 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. *
+ * *
+ ***************************************************************************/
+
+#ifndef LIBSI_DISH_H
+#define LIBSI_DISH_H
+
+#include <libsi/util.h>
+#include <libsi/descriptor.h>
+#include <time.h>
+
+namespace SI
+{
+
+ namespace DISH_THEMES {
+ enum eDishThemes {
+ Movie = 0x01,
+ Sports = 0x02,
+ News_Business = 0x03,
+ Family_Children = 0x04,
+ Education = 0x05,
+ Series_Special = 0x06,
+ Music_Art = 0x07,
+ Religious = 0x08
+ };
+ };
+
+ namespace DISH_CATEGORIES {
+ enum eDishCategories {
+ Action = 0x01,
+ Adults_only = 0x02,
+ Adventure = 0x03,
+ Animals = 0x04,
+ Animated = 0x05,
+ // Anime
+ Anthology = 0x07,
+ Art = 0x08,
+ Auto = 0x09,
+ Awards = 0x0a,
+ Ballet = 0x0b,
+ Baseball = 0x0c,
+ Basketball = 0x0d,
+ // Beach soccer
+ // Beach volleyball
+ // Biathlon
+ Biography = 0x11,
+ Boat = 0x12,
+ // Boat racing
+ Bowling = 0x14,
+ Boxing = 0x15,
+ Bus_financial = 0x16,
+ Children = 0x1a,
+ ChildrenSpecial = 0x1b,
+ ChildrenNews = 0x1c,
+ ChildrenMusic = 0x1d,
+ Collectibles = 0x1f,
+ Comedy = 0x20,
+ ComedyDrama = 0x21,
+ Computers = 0x22,
+ Cooking = 0x23,
+ Crime = 0x24,
+ CrimeDrama = 0x25,
+ // Curling
+ Dance = 0x27,
+ // Dark comedy
+ Docudrama = 0x29,
+ Documentary = 0x2a,
+ Drama = 0x2b,
+ Educational = 0x2c,
+ // Erotic
+ Excercise = 0x2f,
+ Fantasy = 0x31,
+ Fashion = 0x32,
+ // Fencing
+ Fishing = 0x34,
+ Football = 0x35,
+ French = 0x36,
+ Fundraiser = 0x37,
+ GameShow = 0x38,
+ Golf = 0x39,
+ Gymnastics = 0x3a,
+ Health = 0x3b,
+ History = 0x3c,
+ HistoricalDrama = 0x3d,
+ Hockey = 0x3e,
+ Holiday = 0x3f,
+ HolidayChildren = 0x40,
+ HolidayChildrenSpecial = 0x41,
+ // Holiday music
+ // Holiday music special
+ HolidaySpecial = 0x44,
+ Horror = 0x45,
+ HorseRacing = 0x46,
+ House_garden = 0x47,
+ HowTo = 0x49,
+ Interview = 0x4b,
+ Lacrosse = 0x4d,
+ MartialArts = 0x4f,
+ Medical = 0x50,
+ Miniseries = 0x51,
+ Motorsports = 0x52,
+ Motorcycle = 0x53,
+ Music = 0x54,
+ MusicSpecial = 0x55,
+ MusicTalk = 0x56,
+ Musical = 0x57,
+ MusicalComedy = 0x58,
+ Mystery = 0x5a,
+ Nature = 0x5b,
+ News = 0x5c,
+ // Olympics
+ Opera = 0x5f,
+ Outdoors = 0x60,
+ // Parade
+ // Politics = 0x62,
+ PublicAffairs = 0x63,
+ Reality = 0x66,
+ Religious = 0x67,
+ Rodeo = 0x68,
+ Romance = 0x69,
+ RomanceComedy = 0x6a,
+ Rugby = 0x6b,
+ Running = 0x6c,
+ Science = 0x6e,
+ ScienceFiction = 0x6f,
+ SelfImprovement = 0x70,
+ Shopping = 0x71,
+ Skiing = 0x74,
+ Soap = 0x77,
+ // Soap special
+ // Soap talk
+ Soccor = 0x7b,
+ Softball = 0x7c,
+ Spanish = 0x7d,
+ Special = 0x7e,
+ // Speedskating
+ // Sports event
+ SportsNonEvent = 0x81,
+ SportsTalk = 0x82,
+ Suspense = 0x83,
+ Swimming = 0x85,
+ Talk = 0x86,
+ Tennis = 0x87,
+ // Theater
+ // Thriller
+ Track_field = 0x89,
+ Travel = 0x8a,
+ Variety = 0x8b,
+ Volleyball = 0x8c,
+ War = 0x8d,
+ Watersports = 0x8e,
+ Weather = 0x8f,
+ Western = 0x90,
+ Wrestling = 0x92,
+ Yoga = 0x93,
+ Agriculture = 0x94,
+ Anime = 0x95,
+ ArmWrestling = 0x97,
+ Arts_crafts = 0x98,
+ Auction = 0x99,
+ AutoRacing = 0x9a,
+ AirRacing = 0x9b,
+ Badminton = 0x9c,
+ // Bicycle
+ BicycleRacing = 0xa0,
+ BoatRacing = 0xa1,
+ // Bobsled
+ // Bodybilding
+ // Canoe
+ // Cheerleading
+ Community = 0xa6,
+ Consumer = 0xa7,
+ // Darts
+ Debate = 0xaa,
+ // Diving
+ DogShow = 0xac,
+ DragRacing = 0xad,
+ Entertainment = 0xae,
+ Environment = 0xaf,
+ Equestrian = 0xb0,
+ // Event
+ FieldHockey = 0xb3,
+ // Figure skating
+ Football2 = 0xb5,
+ Gay_lesbian = 0xb6,
+ Handball = 0xb7,
+ HomeImprovement = 0xb8,
+ Hunting = 0xb9,
+ // Hurling
+ HydroplaneRacing = 0xbb,
+ // Indoor soccer
+ // Intl hockey
+ // Intl soccer
+ // Kayaking
+ Law = 0xc1,
+ // Luge
+ // Mountain biking
+ MotorcycleRacing = 0xc3,
+ Newsmagazine = 0xc5,
+ Paranormal = 0xc7,
+ Parenting = 0xc8,
+ PerformingArts = 0xca,
+ // Playoff sports
+ Politics = 0xcc,
+ // Polo
+ // Pool
+ ProWrestling = 0xcf,
+ // Ringuette
+ // Roller derby
+ // Rowing
+ Sailing = 0xd3,
+ Shooting = 0xd4,
+ Sitcom = 0xd5,
+ Skateboarding = 0xd6,
+ // Skating
+ // Skeleton
+ Snowboarding = 0xd9,
+ // Snowmobile = 0xda,
+ Standup = 0xdd,
+ // Sumo wrestling
+ Surfing = 0xdf,
+ Tennis2 = 0xe0,
+ Triathlon = 0xe1,
+ // Water polo
+ // Water skiing
+ // Weightlifting
+ // Yacht racing
+ CardGames = 0xe6 ,
+ Poker = 0xe7 ,
+ // Musical = 0xe9,
+ Military = 0xea,
+ Technology = 0xeb,
+ MixedMartialArts = 0xec,
+ ActionSports = 0xed,
+ DishNetwork = 0xff
+ };
+ };
+#define SIZE_TABLE_128 128
+#define SIZE_TABLE_255 255
+
+using namespace std;
+
+class DishDescriptor {
+public:
+ DishDescriptor();
+ virtual ~DishDescriptor();
+ const char* getName(void) const { return name; }
+ const char* getShortText(void);
+ const char *getDescription(void);
+ // const char* getShortText(void) const { return shortText?shortText->c_str():""; }
+ // const char* getDescription(void) const { return description?description->c_str():""; }
+ const char *getTheme();
+ const char *getCategory();
+ const char *getRating();
+ const char *getStarRating();
+ const char *getSeriesId();
+ const char *getProgramId();
+ time_t getOriginalAirDate() { return originalAirDate; }
+ bool hasTheme() {return DishTheme > 0;}
+ bool hasCategory() {return DishCategory > 0;}
+ void setShortData(unsigned char Tid, CharArray data);
+ void setExtendedtData(unsigned char Tid, CharArray data);
+ void setRating(uint16_t value);
+ void setContent(ContentDescriptor::Nibble Nibble);
+ void setEpisodeInfo(CharArray data);
+
+protected:
+ // Decompress the byte array and stores the result to a text string
+ unsigned char* Decompress(unsigned char Tid, CharArray data);
+ const char* name; // name of the event
+ const char* shortText; // usually the episode name
+ const char* description; // description of the event
+ unsigned char* decompressedShort;
+ unsigned char* decompressedExtended;
+ unsigned char DishTheme;
+ unsigned char DishCategory;
+ uint16_t mpaaRating;
+ uint8_t starRating;
+ time_t originalAirDate;
+ char* seriesId;
+ char* programId;
+ char* ratingStr;
+
+ struct HuffmanTable
+ {
+ unsigned int startingAddress;
+ unsigned char character;
+ unsigned char numberOfBits;
+ };
+ static HuffmanTable Table128[SIZE_TABLE_128];
+ static HuffmanTable Table255[SIZE_TABLE_255];
+};
+
+} /* namespace SI */
+#endif /* LIBSI_DISH_H */
diff --git a/eepg.c b/eepg.c
new file mode 100644
index 0000000..fc7a5b0
--- /dev/null
+++ b/eepg.c
@@ -0,0 +1,3628 @@
+/*
+ * Extended Epg plugin to VDR (C++)
+ *
+ * (C) 2008-2009 Dingo35
+ *
+ * This code is based on:
+ * -Premiere plugin (C) 2005-2007 Stefan Huelswitt <s.huelswitt at gmx.de>
+ * -mhwepg program (C) 2002, 2003 Jean-Claude Repetto <mhwepg at repetto.org>
+ * -LoadEpg plugin written by Luca De Pieri <dpluca at libero.it>
+ * -Freesat patch written by dom /at/ suborbital.org.uk
+ *
+ *
+ * This code 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 code 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
+ */
+
+#include <vdr/plugin.h>
+#include <vdr/filter.h>
+#include <vdr/epg.h>
+#include <vdr/channels.h>
+#include <vdr/dvbdevice.h>
+#include <vdr/i18n.h>
+#include <vdr/config.h>
+#include <libsi/section.h>
+#include <libsi/descriptor.h>
+#include <libsi/si.h>
+#include "eepg.h"
+#include "dish.h"
+#if APIVERSNUM > 10725
+#include "epghandler.h"
+#endif
+#include "log.h"
+#include "setupeepg.h"
+#include "equivhandler.h"
+#include "util.h"
+#include "eit2.h"
+
+#include <map>
+#include <string>
+#include <stdarg.h>
+
+
+#if APIVERSNUM < 10401
+#error You need at least VDR API version 1.4.1 for this plugin
+#endif
+#if APIVERSNUM < 10507
+#define trNOOP(s) (s)
+#endif
+
+#define PMT_SCAN_TIMEOUT 10 // seconds
+#define PMT_SCAN_IDLE 3600 // seconds
+
+static const char *VERSION = "0.0.6pre";
+static const char *DESCRIPTION = trNOOP ("Parses Extended EPG data");
+
+using namespace std;
+using namespace util;
+
+const char *optPats[] = {
+ "%s",
+ "%s (Option %d)",
+ "%s (O%d)",
+ "#%2$d %1$s",
+ "[%2$d] %1$s"
+};
+
+#define NUM_PATS (sizeof(optPats)/sizeof(char *))
+
+char *cs_hexdump (int m, const uchar * buf, int n)
+{
+ int i;
+ static char dump[1024];
+
+ dump[i = 0] = '\0';
+ m = (m) ? 3 : 2;
+ if (m * n >= (int) sizeof (dump))
+ n = (sizeof (dump) / m) - 1;
+ while (i < n)
+ sprintf (dump + (m * i++), "%02X%s", *buf++, (m > 2) ? " " : "");
+ return (dump);
+}
+
+cSetupEEPG* SetupPE = cSetupEEPG::getInstance();
+
+// --- cMenuSetupPremiereEpg ------------------------------------------------------------
+
+class cMenuSetupPremiereEpg:public cMenuSetupPage
+{
+private:
+ cSetupEEPG* data;
+ const char *optDisp[NUM_PATS];
+ char buff[NUM_PATS][32];
+protected:
+ virtual void Store (void);
+public:
+ cMenuSetupPremiereEpg (void);
+};
+
+cMenuSetupPremiereEpg::cMenuSetupPremiereEpg (void)
+{
+ data = cSetupEEPG::getInstance();
+ SetSection (tr ("PremiereEPG"));
+ optDisp[0] = tr ("off");
+ for (unsigned int i = 1; i < NUM_PATS; i++) {
+ snprintf (buff[i], sizeof (buff[i]), optPats[i], "Event", 1);
+ optDisp[i] = buff[i];
+ }
+ Add (new cMenuEditStraItem (tr ("Tag option events"), &data->OptPat, NUM_PATS, optDisp));
+ Add (new cMenuEditBoolItem (tr ("Show order information"), &data->OrderInfo));
+ Add (new cMenuEditBoolItem (tr ("Show rating information"), &data->RatingInfo));
+ Add (new cMenuEditBoolItem (tr ("Fix EPG data"), &data->FixEpg));
+ Add (new cMenuEditBoolItem (tr ("Display summary message"), &data->DisplayMessage));
+#ifdef DEBUG
+ Add (new cMenuEditIntItem (tr ("Level of logging verbosity"), &data->LogLevel, 0, 5));
+ Add (new cMenuEditBoolItem (tr ("Process EIT info with EEPG"), &data->ProcessEIT));
+#endif
+}
+
+void cMenuSetupPremiereEpg::Store (void)
+{
+ //SetupPE = data;
+ SetupStore ("OptionPattern", SetupPE->OptPat);
+ SetupStore ("OrderInfo", SetupPE->OrderInfo);
+ SetupStore ("RatingInfo", SetupPE->RatingInfo);
+ SetupStore ("FixEpg", SetupPE->FixEpg);
+ SetupStore ("DisplayMessage", SetupPE->DisplayMessage);
+#ifdef DEBUG
+ SetupStore ("LogLevel", SetupPE->LogLevel);
+ SetupStore ("ProcessEIT", SetupPE->ProcessEIT);
+#endif
+}
+
+//#define Asprintf(a, b, c...) void( asprintf(a, b, c) < 0 ? esyslog("memory allocation error - %s", b) : void() )
+
+// --- CRC16 -------------------------------------------------------------------
+
+#define POLY 0xA001 // CRC16
+
+unsigned int crc16 (unsigned int crc, unsigned char const *p, int len)
+{
+ while (len--) {
+ crc ^= *p++;
+ for (int i = 0; i < 8; i++)
+ crc = (crc & 1) ? (crc >> 1) ^ POLY : (crc >> 1);
+ }
+ return crc & 0xFFFF;
+}
+
+// --- cFilterEEPG ------------------------------------------------------
+
+#define STARTTIME_BIAS (20*60)
+
+static int LastVersionNagra = -1; //currently only used for Nagra, should be stored per transponder, per system
+
+
+class cFilterEEPG:public cFilter
+{
+private:
+ int pmtpid, pmtsid, pmtidx, pmtnext;
+ int UnprocessedFormat[HIGHEST_FORMAT + 1]; //stores the pid when a format is detected on this transponder, and that are not processed yet
+ int nChannels, nThemes, nTitles, nSummaries, NumberOfTables, Version;
+ int TitleCounter, SummaryCounter, NoSummaryCounter, RejectTableId;
+ bool EndChannels, EndThemes; //only used for ??
+ int MHWStartTime; //only used for MHW1
+ bool ChannelsOk;
+ //int Format; //the format that this filter currently is processing
+ std::map < int, int >ChannelSeq; // ChannelSeq[ChannelId] returns the recordnumber of the channel
+
+ Summary_t *Summaries[MAX_TITLES];
+ Title_t *Titles[MAX_TITLES];
+ sChannel sChannels[MAX_CHANNELS];
+ unsigned char Themes[MAX_THEMES][64];
+
+ std::map < unsigned short int, unsigned char *>buffer; //buffer[Table_Extension_Id] returns the pointer to the buffer for this TEI
+ std::map < unsigned short int, int >bufsize; //bufsize[Table_Extension_Id] returns the buffersize of the buffer for this TEI
+ unsigned short int NagraTIE[64]; //at this moment a max of 31 table_ids could be used, so 64 should be enough ....stores the Table_Extension_Id's of summaries received, so they can be processed. Processing while receiving somehow drops sections, the 0x0000 marker will be missed ...
+ unsigned short int NagraCounter;
+
+ unsigned char InitialChannel[8];
+ unsigned char InitialTitle[64];
+ unsigned char InitialSummary[64];
+
+ void NextPmt (void);
+ void ProccessContinuous(u_short Pid, u_char Tid, int Length, const u_char *Data);
+protected:
+ virtual void Process (u_short Pid, u_char Tid, const u_char * Data, int Length);
+ virtual void AddFilter (u_short Pid, u_char Tid);
+ virtual void AddFilter (u_short Pid, u_char Tid, unsigned char Mask);
+ virtual void ProcessNextFormat (bool FirstTime);
+ virtual int GetChannelsSKYBOX (const u_char * Data, int Length);
+ virtual bool GetThemesSKYBOX (void);
+ virtual int GetTitlesSKYBOX (const u_char * Data, int Length);
+ virtual int GetSummariesSKYBOX (const u_char * Data, int Length);
+ virtual int GetChannelsMHW (const u_char * Data, int Length, int MHW); //TODO replace MHW by Format?
+ virtual int GetThemesMHW1 (const u_char * Data, int Length);
+ virtual int GetNagra (const u_char * Data, int Length);
+ virtual void ProcessNagra (void);
+ virtual void GetTitlesNagra (const u_char * Data, int Length, unsigned short TableIdExtension);
+ virtual char *GetSummaryTextNagra (const u_char * DataStart, long int Offset, unsigned int EventId);
+ virtual int GetChannelsNagra (const u_char * Data, int Length);
+ virtual int GetThemesNagra (const u_char * Data, int Length, unsigned short TableIdExtension);
+ virtual int GetTitlesMHW1 (const u_char * Data, int Length);
+ virtual int GetSummariesMHW1 (const u_char * Data, int Length);
+ virtual int GetThemesMHW2 (const u_char * Data, int Length);
+ virtual int GetTitlesMHW2 (const u_char * Data, int Length);
+ virtual int GetSummariesMHW2 (const u_char * Data, int Length);
+ virtual void FreeSummaries (void);
+ virtual void FreeTitles (void);
+ //virtual void PrepareToWriteToSchedule (sChannel * C, cSchedules * s, cSchedule * ps/*[MAX_EQUIVALENCES]*/); //gets a channel and returns an array of schedules that WriteToSchedule can write to. Call this routine before a batch of titles with the same ChannelId will be WriteToScheduled; batchsize can be 1
+ //virtual void FinishWriteToSchedule (sChannel * C, cSchedules * s, cSchedule * ps[MAX_EQUIVALENCES]);
+ virtual void WriteToSchedule (tChannelID channelID, cSchedules* s, unsigned int EventId, unsigned int StartTime,
+ unsigned int Duration, char *Text, char *SummText, unsigned short int ThemeId,
+ unsigned short int TableId, unsigned short int Version, char Rating = 0x00);
+ virtual void LoadIntoSchedule (void);
+ //virtual void LoadEquivalentChannels (void);
+
+ void ProcessPremiere(const u_char *& Data);
+public:
+ cFilterEEPG (void);
+ virtual void SetStatus (bool On);
+ void Trigger (void);
+ bool InitDictionary (void); //Initialize the Huffman tables for SKY and Freesat
+
+ static const int EIT_PID = 0x12;
+};
+
+cFilterEEPG::cFilterEEPG (void)
+{
+ nSummaries = 0;
+ nTitles = 0;
+ Trigger ();
+ //Set (0x00, 0x00);
+}
+
+void cFilterEEPG::Trigger (void)
+{
+ LogI(3, prep("trigger\n"));
+ pmtpid = 0;
+ pmtidx = 0;
+ pmtnext = 0;
+}
+
+void cFilterEEPG::SetStatus (bool On)
+{
+ LogI(0, prep("setstatus %d\n"), On);
+ if (!On) {
+ FreeSummaries ();
+ FreeTitles ();
+ //Format = 0;
+ ChannelsOk = false;
+ NumberOfTables = 0;
+ } else {
+ //Set(0x00,0x00);
+ for (int i = 0; i <= HIGHEST_FORMAT; i++)
+ UnprocessedFormat[i] = 0; //pid 0 is assumed to be nonvalid for EEPG transfers
+ AddFilter (0, 0);
+ }
+ cFilter::SetStatus (On);
+ Trigger ();
+}
+
+void cFilterEEPG::NextPmt (void)
+{
+ Del (pmtpid, 0x02);
+ pmtpid = 0;
+ pmtidx++;
+ LogE(3, prep("PMT next\n"));
+}
+
+
+
+// ------------------- Freesat -------------------
+
+/* FreeSat Huffman decoder for VDR
+ *
+ * Insert GPL licence
+ */
+
+/* The following features can be controlled:
+ *
+ * FREEVIEW_NO_SYSLOG - Disable use of isyslog
+ */
+
+#ifndef FREEVIEW_NO_SYSLOG
+#include <vdr/tools.h>
+/* Logging via vdr */
+#ifndef isyslog
+#define isyslog(a...) void( (SysLogLevel > 1) ? syslog_with_tid(LOG_INFO, a) : void() )
+#endif
+void syslog_with_tid (int priority, const char *format, ...) __attribute__ ((format (printf, 2, 3)));
+#else
+#define isyslog(a...) fprintf(stderr,a)
+#endif
+
+
+
+//struct hufftab {
+// unsigned int value;
+// short bits;
+// char next;
+//};
+//
+//#define START '\0'
+//#define STOP '\0'
+//#define ESCAPE '\1'
+
+
+//int freesat_decode_error = 0; /* If set an error has occurred during decoding */
+
+//static struct hufftab *tables[2][128];
+//static int table_size[2][128];
+static sNodeH* sky_tables[2];
+
+/** \brief Convert a textual character description into a value
+ *
+ * \param str - Encoded (in someway) string
+ *
+ * \return Raw character
+ */
+static unsigned char resolve_char (char *str)
+{
+ int val;
+ if (strcmp (str, "ESCAPE") == 0) {
+ return ESCAPE;
+ } else if (strcmp (str, "STOP") == 0) {
+ return STOP;
+ } else if (strcmp (str, "START") == 0) {
+ return START;
+ } else if (sscanf (str, "0x%02x", &val) == 1) {
+ return val;
+ }
+ return str[0];
+
+
+}
+
+
+/** \brief Decode a binary string into a value
+ *
+ * \param binary - Binary string to decode
+ *
+ * \return Decoded value
+ */
+static unsigned long decode_binary (char *binary)
+{
+ unsigned long mask = 0x80000000;
+ unsigned long maskval = 0;
+ unsigned long val = 0;
+ size_t i;
+
+ for (i = 0; i < strlen (binary); i++) {
+ if (binary[i] == '1') {
+ val |= mask;
+ }
+ maskval |= mask;
+ mask >>= 1;
+ }
+ return val;
+}
+
+/** \brief Load an individual freesat data file
+ *
+ * \param tableid - Table id that should be loaded
+ * \param filename - Filename to load
+ * \return Success of operation
+ */
+static bool load_freesat_file (int tableid, const char *filename)
+{
+ char buf[1024];
+ char *from, *to, *binary;
+ FILE *fp;
+
+ tableid--;
+ if ((fp = fopen (filename, "r")) != NULL) {
+ LogI(2, prep("Loading table %d Filename <%s>"), tableid + 1, filename);
+
+ while (fgets (buf, sizeof (buf), fp) != NULL) {
+ from = binary = to = NULL;
+ int elems = sscanf (buf, "%a[^:]:%a[^:]:%a[^:]:", &from, &binary, &to);
+ if (elems == 3) {
+ int bin_len = strlen (binary);
+ int from_char = resolve_char (from);
+ char to_char = resolve_char (to);
+ unsigned long bin = decode_binary (binary);
+ int i = table_size[tableid][from_char]++;
+
+ tables[tableid][from_char] =
+ (struct hufftab *) REALLOC (tables[tableid][from_char], (i + 1) * sizeof (tables[tableid][from_char][0]));
+ tables[tableid][from_char][i].value = bin;
+ tables[tableid][from_char][i].next = to_char;
+ tables[tableid][from_char][i].bits = bin_len;
+ /* char from; unsigned int value; short bits; char next; */
+ LogI(2, prep("%02x;%08x;%04x;%02x"), from_char, bin, bin_len, to_char);
+
+ free (from);
+ free (to);
+ free (binary);
+ }
+ }
+ fclose (fp);
+ } else {
+ LogE(0, prep("Cannot load <%s> for table %d"), filename, tableid + 1);
+ return false;
+ }
+ return true;
+}
+
+/** \brief Load an individual freesat data file
+ *
+ * \param filename - Filename to load
+ * \return Success of operation
+ */
+static bool load_sky_file (const char *filename)
+{
+ FILE *FileDict;
+ char *Line;
+ char Buffer[256];
+ sNodeH *nH;
+ int tableId;
+
+ FileDict = fopen (filename, "r");
+ if (FileDict == NULL) {
+ LogE (0, prep("Error opening file '%s'. %s"), filename, strerror (errno));
+ return false;
+ } else {
+ int i;
+ int LenPrefix;
+ char string1[256];
+ char string2[256];
+
+ tableId = Format == SKY_IT ? 0 : 1;
+ if (!sky_tables[tableId]) {
+ sky_tables[tableId] = (sNodeH*) calloc(1,sizeof(sNodeH));
+ if (!sky_tables[tableId]) {
+ LogE (0, prep("Not enough memory to load file '%s'."), filename);
+ return false;
+ }
+ }
+
+ while ((Line = fgets (Buffer, sizeof (Buffer), FileDict)) != NULL) {
+ if (!isempty (Line)) {
+ memset (string1, 0, sizeof (string1));
+ memset (string2, 0, sizeof (string2));
+ if (sscanf (Line, "%c=%[^\n]\n", string1, string2) == 2
+ || (sscanf (Line, "%[^=]=%[^\n]\n", string1, string2) == 2)) {
+ nH = sky_tables[tableId];
+ LenPrefix = strlen (string2);
+ for (i = 0; i < LenPrefix; i++) {
+ switch (string2[i]) {
+ case '0':
+ if (nH->P0 == NULL) {
+ nH->P0 = new sNodeH ();
+ nH = nH->P0;
+ nH->Value = NULL;
+ nH->P0 = NULL;
+ nH->P1 = NULL;
+ if ((LenPrefix - 1) == i) {
+ Asprintf (&nH->Value, "%s", string1);
+ }
+ } else {
+ nH = nH->P0;
+ if (nH->Value != NULL || (LenPrefix - 1) == i) {
+ LogE (0 ,prep("Error, huffman prefix code already exists for \"%s\"=%s with '%s'"), string1,
+ string2, nH->Value);
+ }
+ }
+ break;
+ case '1':
+ if (nH->P1 == NULL) {
+ nH->P1 = new sNodeH ();
+ nH = nH->P1;
+ nH->Value = NULL;
+ nH->P0 = NULL;
+ nH->P1 = NULL;
+ if ((LenPrefix - 1) == i) {
+ Asprintf (&nH->Value, "%s", string1);
+ }
+ } else {
+ nH = nH->P1;
+ if (nH->Value != NULL || (LenPrefix - 1) == i) {
+ LogE (0, prep("Error, huffman prefix code already exists for \"%s\"=%s with '%s'"), string1,
+ string2, nH->Value);
+ }
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ }
+ }
+ }
+ fclose (FileDict);
+ }
+
+ // check tree huffman nodes
+ FileDict = fopen (filename, "r");
+ if (FileDict) {
+ int i;
+ int LenPrefix;
+ char string1[256];
+ char string2[256];
+ while ((Line = fgets (Buffer, sizeof (Buffer), FileDict)) != NULL) {
+ if (!isempty (Line)) {
+ memset (string1, 0, sizeof (string1));
+ memset (string2, 0, sizeof (string2));
+ if (sscanf (Line, "%c=%[^\n]\n", string1, string2) == 2
+ || (sscanf (Line, "%[^=]=%[^\n]\n", string1, string2) == 2)) {
+ nH = sky_tables[tableId];
+ LenPrefix = strlen (string2);
+ for (i = 0; i < LenPrefix; i++) {
+ switch (string2[i]) {
+ case '0':
+ if (nH->P0 != NULL) {
+ nH = nH->P0;
+ }
+ break;
+ case '1':
+ if (nH->P1 != NULL) {
+ nH = nH->P1;
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ if (nH->Value != NULL) {
+ if (memcmp (nH->Value, string1, strlen (nH->Value)) != 0) {
+ LogE (0, prep("Error, huffman prefix value '%s' not equal to '%s'"), nH->Value, string1);
+ }
+ } else {
+ LogE (0, prep("Error, huffman prefix value is not exists for \"%s\"=%s"), string1, string2);
+ }
+ }
+ }
+ }
+ fclose (FileDict);
+ }
+ return true;
+}
+
+/** \brief Decode an EPG string as necessary
+ *
+ * \param src - Possibly encoded string
+ * \param size - Size of the buffer
+ *
+ * \retval NULL - Can't decode
+ * \return A decoded string
+ */
+char *freesat_huffman_decode (const unsigned char *src, size_t size)
+{
+ int tableid;
+// freesat_decode_error = 0;
+
+ if (src[0] == 0x1f && (src[1] == 1 || src[1] == 2)) {
+ int uncompressed_len = 30;
+ char *uncompressed = (char *) calloc (1, uncompressed_len + 1);
+ unsigned value = 0, byte = 2, bit = 0;
+ int p = 0;
+ unsigned char lastch = START;
+
+ tableid = src[1] - 1;
+ while (byte < 6 && byte < size) {
+ value |= src[byte] << ((5 - byte) * 8);
+ byte++;
+ }
+ //freesat_table_load (); /**< Load the tables as necessary */
+
+ do {
+ bool found = false;
+ unsigned bitShift = 0;
+ if (lastch == ESCAPE) {
+ char nextCh = (value >> 24) & 0xff;
+ found = true;
+ // Encoded in the next 8 bits.
+ // Terminated by the first ASCII character.
+ bitShift = 8;
+ if ((nextCh & 0x80) == 0)
+ lastch = nextCh;
+ if (p >= uncompressed_len) {
+ uncompressed_len += 10;
+ uncompressed = (char *) REALLOC (uncompressed, uncompressed_len + 1);
+ }
+ uncompressed[p++] = nextCh;
+ uncompressed[p] = 0;
+ } else {
+ int j;
+ for (j = 0; j < table_size[tableid][lastch]; j++) {
+ unsigned mask = 0, maskbit = 0x80000000;
+ short kk;
+ for (kk = 0; kk < tables[tableid][lastch][j].bits; kk++) {
+ mask |= maskbit;
+ maskbit >>= 1;
+ }
+ if ((value & mask) == tables[tableid][lastch][j].value) {
+ char nextCh = tables[tableid][lastch][j].next;
+ bitShift = tables[tableid][lastch][j].bits;
+ if (nextCh != STOP && nextCh != ESCAPE) {
+ if (p >= uncompressed_len) {
+ uncompressed_len += 10;
+ uncompressed = (char *) REALLOC (uncompressed, uncompressed_len + 1);
+ }
+ uncompressed[p++] = nextCh;
+ uncompressed[p] = 0;
+ }
+ found = true;
+ lastch = nextCh;
+ break;
+ }
+ }
+ }
+ if (found) {
+ // Shift up by the number of bits.
+ unsigned b;
+ for (b = 0; b < bitShift; b++) {
+ value = (value << 1) & 0xfffffffe;
+ if (byte < size)
+ value |= (src[byte] >> (7 - bit)) & 1;
+ if (bit == 7) {
+ bit = 0;
+ byte++;
+ } else
+ bit++;
+ }
+ } else {
+ LogE (0, prep("Missing table %d entry: <%s>"), tableid + 1, uncompressed);
+ // Entry missing in table.
+ return uncompressed;
+ }
+ } while (lastch != STOP && value != 0);
+
+ return uncompressed;
+ }
+ return NULL;
+}
+
+int sky_huffman_decode (const u_char * Data, int Length, unsigned char *DecodeText)
+{
+ sNodeH *nH, H=(Format==SKY_IT)?*sky_tables[0]:*sky_tables[1];
+ int i;
+ int p;
+ int q;
+ bool CodeError;
+ bool IsFound;
+ unsigned char Byte;
+ unsigned char lastByte;
+ unsigned char Mask;
+ unsigned char lastMask;
+ nH = &H;
+ p = 0;
+ q = 0;
+ DecodeText[0] = '\0';
+ //DecodeErrorText[0] = '\0';
+ CodeError = false;
+ IsFound = false;
+ lastByte = 0;
+ lastMask = 0;
+ for (i = 0; i < Length; i++) {
+ Byte = Data[i];
+ Mask = 0x80;
+ if (i == 0) {
+ Mask = 0x20;
+ lastByte = i;
+ lastMask = Mask;
+ }
+loop1:
+ if (IsFound) {
+ lastByte = i;
+ lastMask = Mask;
+ IsFound = false;
+ }
+ if ((Byte & Mask) == 0) {
+ if (CodeError) {
+ //DecodeErrorText[q] = 0x30;
+ q++;
+ goto nextloop1;
+ }
+ if (nH->P0 != NULL) {
+ nH = nH->P0;
+ if (nH->Value != NULL) {
+ memcpy (&DecodeText[p], nH->Value, strlen (nH->Value));
+ p += strlen (nH->Value);
+ nH = &H;
+ IsFound = true;
+ }
+ } else {
+ memcpy (&DecodeText[p], "<...?...>", 9);
+ p += 9;
+ i = lastByte;
+ Byte = Data[lastByte];
+ Mask = lastMask;
+ CodeError = true;
+ goto loop1;
+ }
+ } else {
+ if (CodeError) {
+ //DecodeErrorText[q] = 0x31;
+ q++;
+ goto nextloop1;
+ }
+ if (nH->P1 != NULL) {
+ nH = nH->P1;
+ if (nH->Value != NULL) {
+ memcpy (&DecodeText[p], nH->Value, strlen (nH->Value));
+ p += strlen (nH->Value);
+ nH = &H;
+ IsFound = true;
+ }
+ } else {
+ memcpy (&DecodeText[p], "<...?...>", 9);
+ p += 9;
+ i = lastByte;
+ Byte = Data[lastByte];
+ Mask = lastMask;
+ CodeError = true;
+ goto loop1;
+ }
+ }
+nextloop1:
+ Mask = Mask >> 1;
+ if (Mask > 0) {
+ goto loop1;
+ }
+ }
+ DecodeText[p] = '\0';
+ //DecodeErrorText[q] = '\0';
+ return p;
+}
+
+//here all declarations for global variables over all devices
+
+//char *ConfDir;
+
+//unsigned char DecodeErrorText[4096]; //TODO only used for debugging?
+
+bool cFilterEEPG::GetThemesSKYBOX (void) //TODO can't we read this from the DVB stream?
+{
+ string FileName = cSetupEEPG::getInstance()->getConfDir();
+ FILE *FileThemes;
+ char *Line;
+ char Buffer[256];
+ if (Format == SKY_IT)
+ FileName += "/sky_it.themes";
+ else if (Format == SKY_UK)
+ FileName += "/sky_uk.themes";
+ else {
+ LogE (0, prep("Error, wrong format detected in GetThemesSKYBOX. Format = %i."), Format);
+ return false;
+ }
+ //asprintf( &FileName, "%s/%s", ConfDir, ( lProviders + CurrentProvider )->Parm3 );
+ FileThemes = fopen (FileName.c_str(), "r");
+ if (FileThemes == NULL) {
+ LogE (0, prep("Error opening file '%s'. %s"), FileName.c_str(), strerror (errno));
+ return false;
+ } else {
+ //int id = 0;
+ nThemes = 0;
+ char string1[256];
+ char string2[256];
+ //sTheme *T;
+ while ((Line = fgets (Buffer, sizeof (Buffer), FileThemes)) != NULL) {
+ memset (string1, 0, sizeof (string1));
+ memset (string2, 0, sizeof (string2));
+ if (!isempty (Line)) {
+ //T = &Themes[nThemes];
+ if (sscanf (Line, "%[^=] =%[^\n] ", string1, string2) == 2) {
+ snprintf ((char *) Themes[nThemes], 255, "%s", string2);
+ } else {
+ Themes[nThemes][0] = '\0';
+ }
+ //id ++;
+ nThemes++;
+ }
+ }
+ fclose (FileThemes);
+ }
+ return true;
+}
+
+/**
+ * \brief Initialize the Huffman dictionaries if they are not already initialized.
+ *
+ */
+bool cFilterEEPG::InitDictionary (void)
+{
+ string FileName = cSetupEEPG::getInstance()->getConfDir();
+ switch (Format) {
+ case SKY_IT:
+ if (sky_tables[0] == NULL) {
+ FileName += "/sky_it.dict";
+ LogD (4, prep("EEPGDebug: loading sky_it.dict"));
+ return load_sky_file(FileName.c_str());
+ } else
+ LogD (4, prep("EEPGDebug: sky_it.dict already loaded"));
+ break;
+ case SKY_UK:
+ if (sky_tables[1] == NULL) {
+ FileName += "/sky_uk.dict";
+ LogD (4, prep("EEPGDebug: loading sky_uk.dict"));
+ return load_sky_file(FileName.c_str());
+ } else
+ LogD (4, prep("EEPGDebug: sky_uk.dict already loaded"));
+ break;
+ case FREEVIEW:
+ if (tables[0][0] == NULL) {
+ LogD (4, prep("EEPGDebug: loading freesat.dict"));
+ FileName += "/freesat.t1";
+ if (!load_freesat_file (1, FileName.c_str()))
+ return false;
+ FileName = cSetupEEPG::getInstance()->getConfDir();
+ FileName += "/freesat.t2";
+ return load_freesat_file (2, FileName.c_str());
+ } else
+ LogD (4, prep("EEPGDebug: freesat.dict already loaded"));
+ break;
+ default:
+ LogE (0 ,prep("Error, wrong format detected in ReadFileDictionary. Format = %i."), Format);
+ return false;
+ }
+ return true;
+}
+
+//void decodeText2 (const unsigned char *from, int len, char *buffer, int buffsize)
+//{
+// if (from[0] == 0x1f) {
+// char *temp = freesat_huffman_decode (from, len);
+// if (temp) {
+// len = strlen (temp);
+// len = len < buffsize - 1 ? len : buffsize - 1;
+// strncpy (buffer, temp, len);
+// buffer[len] = 0;
+// free (temp);
+// return;
+// }
+// }
+//
+// SI::String convStr;
+// SI::CharArray charArray;
+// charArray.assign(from, len);
+// convStr.setData(charArray, len);
+// //LogE(5, prep("decodeText2 from %s - length %d"), from, len);
+// convStr.getText(buffer, buffsize);
+// //LogE(5, prep("decodeText2 buffer %s - buffsize %d"), buffer, buffsize);
+//}
+
+/**
+ * \brief Get MHW channels
+ *
+ * \return 0 = fatal error, code 1 = success, code 2 = last item processed
+ */
+int cFilterEEPG::GetChannelsMHW (const u_char * Data, int Length, int MHW)
+{
+ if ((MHW == 1) || (nChannels == 0)) { //prevents MHW2 from reading channels twice while waiting for themes on same filter
+ sChannelMHW1 *Channel;
+ int Size, Off;
+ Size = sizeof (sChannelMHW1);
+ Off = 4;
+ if (MHW == 1) {
+ //Channel = (sChannelMHW1 *) (Data + 4);
+ nChannels = (Length - Off) / sizeof (sChannelMHW1);
+ }
+ if (MHW == 2) {
+ if (Length > 120)
+ nChannels = Data[120];
+ else {
+ LogE(0, prep("Error, channels packet too short for MHW2."));
+ return 0;
+ }
+ int pName = ((nChannels * 8) + 121);
+ if (Length > pName) {
+ //Channel = (sChannelMHW1 *) (Data + 120);
+ Size -= 14; //MHW2 is 14 bytes shorter
+ Off = 121; //and offset differs
+ } else {
+ LogE(0, prep("Error, channels length does not match pname."));
+ return 0;
+ }
+ }
+
+ if (nChannels > MAX_CHANNELS) {
+ LogE(0, prep("EEPG: Error, %i channels found more than %i"), nChannels, MAX_CHANNELS);
+ return 0;
+ } else {
+ LogI(1, "| ID | %-26.26s | %-22.22s | FND | %-8.8s |\n", "Channel ID", "Channel Name", "Sky Num.");
+ LogI(1, "|------|-%-26.26s-|-%-22.22s-|-----|-%-8.8s-|\n", "------------------------------",
+ "-----------------------------", "--------------------");
+ int pName = ((nChannels * 8) + 121); //TODO double ...
+ for (int i = 0; i < nChannels; i++) {
+ Channel = (sChannelMHW1 *) (Data + Off);
+ sChannel *C = &sChannels[i];
+ C->ChannelId = i;
+ ChannelSeq[C->ChannelId] = i; //fill lookup table to go from channel-id to sequence nr in table
+ C->SkyNumber = 0;
+ if (MHW == 1)
+ memcpy (C->Name, &Channel->Name, 16); //MHW1
+ else { //MHW2
+ int lenName = Data[pName] & 0x0f;
+ //LogD (1, prep("EEPGDebug: MHW2 lenName:%d"), lenName);
+ decodeText2(&Data[pName+1],lenName,(char*)C->Name,256);
+ //memcpy (C->Name, &Data[pName + 1], lenName);
+ //else
+ //memcpy (C->Name, &Data[pName + 1], 256);
+ pName += (lenName + 1);
+ }
+ //C->NumberOfEquivalences = 1; //there is always an original channel. every equivalence adds 1
+ C->Src = Source (); //assume all EPG channels are on same satellite, if not, manage this via equivalents!!!
+ C->Nid = HILO16 (Channel->NetworkId);
+ C->Tid = HILO16 (Channel->TransportId);
+ C->Sid = HILO16 (Channel->ServiceId);
+ tChannelID channelID = tChannelID (C->Src, C->Nid, C->Tid, C->Sid);
+ cChannel *VC = GetChannelByID(channelID, true);
+ bool IsFound = (VC);
+ if(IsFound) {
+ C->Src = VC->Source();
+ }
+ CleanString (C->Name);
+
+ LogI(1, "|% 5d | %-26.26s | %-22.22s | %-3.3s | % 6d |\n", C->ChannelId
+ , *tChannelID (C->Src, C->Nid, C->Tid, C->Sid).ToString()
+ , C->Name, IsFound ? "YES" : "NO", C->SkyNumber);
+
+ Off += Size;
+ } //for loop
+ } //else nChannels > MAX_CHANNELS
+ //LoadEquivalentChannels ();
+ EquivHandler->loadEquivalentChannelMap();
+ GetLocalTimeOffset (); //reread timing variables, only used for MHW
+ return 2; //obviously, when you get here, channels are read successfully, but since all channels are sent at once, you can stop now
+ } //if nChannels == 0
+ LogE (0, prep("Warning: Trying to read Channels more than once!"));
+ //you will only get here when GetChannelsMHW is called, and nChannels !=0, e.g. when multiple citpids cause channels to be read multiple times. Second time, do nothing, give error so that the rest of the chain is not restarted also.
+ return 0;
+}
+
+/**
+ * \brief Get MHW1 Themes
+ *
+ * \return 0 = fatal error, code 1 = success, code 2 = last item processed
+ */
+int cFilterEEPG::GetThemesMHW1 (const u_char * Data, int Length)
+{ //MHW1 Themes
+ if (Length > 19) {
+ sThemeMHW1 *Theme = (sThemeMHW1 *) (Data + 19);
+ nThemes = (Length - 19) / 15;
+ if (nThemes > MAX_THEMES) {
+ LogE(1, prep("Error, %i themes found more than %i"), nThemes, MAX_THEMES);
+ return 0;
+ } else {
+ LogI(1, "-------------THEMES FOUND--------------");
+ int ThemeId = 0;
+ int Offset = 0;
+ const u_char *ThemesIndex = (Data + 3);
+ for (int i = 0; i < nThemes; i++) {
+ if (ThemesIndex[ThemeId] == i) {
+ Offset = (Offset + 15) & 0xf0; //TODO do not understand this
+ ThemeId++;
+ }
+ memcpy (&Themes[Offset][0], &Theme->Name, 15);
+ Themes[Offset][15] = '\0'; //trailing null
+ CleanString (Themes[Offset]);
+ LogI(1, prep("%.15s"), Themes[Offset]);
+ Offset++;
+ Theme++;
+ }
+ if ((nThemes * 15) + 19 != Length) {
+ LogE(0, "Themes error: buffer is smaller or bigger than sum of entries.");
+ return 0;
+ } else
+ return 2;
+ }
+ }
+ return 1;
+}
+
+/**
+ * \brief Get MHW2 Themes
+ *
+ * \return 0 = fatal error, code 1 = success, code 2 = last item processed
+ */
+int cFilterEEPG::GetThemesMHW2 (const u_char * Data, int Length)
+{
+ if (!EndThemes) { //only process if not processed
+ int p1;
+ int p2;
+ int pThemeName = 0;
+ int pSubThemeName = 0;
+ int lenThemeName = 0;
+ int lenSubThemeName = 0;
+ int pThemeId = 0;
+ if (Length > 4) {
+ LogI(1, "-------------THEMES FOUND--------------");
+ for (int i = 0; i < Data[4]; i++) {
+ p1 = ((Data[5 + i * 2] << 8) | Data[6 + i * 2]) + 3;
+ if (Length > p1) {
+ for (int ii = 0; ii <= (Data[p1] & 0x3f); ii++) {
+ p2 = ((Data[p1 + 1 + ii * 2] << 8) | Data[p1 + 2 + ii * 2]) + 3;
+ if (Length > p2) {
+ if (ii == 0) {
+ pThemeName = p2 + 1;
+ lenThemeName = Data[p2] & 0x1f;
+ lenSubThemeName = 0;
+ } else {
+ pSubThemeName = p2 + 1;
+ lenSubThemeName = Data[p2] & 0x1f;
+ }
+ if (Length >= (pThemeName + lenThemeName)) {
+ pThemeId = ((i & 0x3f) << 6) | (ii & 0x3f);
+ if (pThemeId > MAX_THEMES) {
+ LogE(1, prep("Error, something wrong with themes id calculation MaxThemes: %i pThemeID:%d"), MAX_THEMES, pThemeId);
+ return 0; //fatal error
+ }
+ if ((lenThemeName + 2) < 256) {
+ decodeText2(&Data[pThemeName],lenThemeName,(char*)Themes[pThemeId],256);
+ //memcpy (Themes[pThemeId], &Data[pThemeName], lenThemeName);
+ if (Length >= (pSubThemeName + lenSubThemeName))
+ if (lenSubThemeName > 0)
+ if ((lenThemeName + lenSubThemeName + 2) < 256) {
+ Themes[pThemeId][lenThemeName] = '-';
+ decodeText2(&Data[pSubThemeName],lenSubThemeName,(char*)&Themes[pThemeId][lenThemeName + 1],256);
+ //memcpy (&Themes[pThemeId][lenThemeName + 1], &Data[pSubThemeName], lenSubThemeName);
+ }
+ CleanString (Themes[pThemeId]);
+ LogI(1, prep("%.*s"), lenThemeName + 1 + lenSubThemeName, Themes[pThemeId]);
+ //isyslog ("%.15s", (lThemes + pThemeId)->Name);
+ nThemes++;
+ if (nThemes > MAX_THEMES) {
+ LogE(1, prep("Error, %i themes found more than %i"), nThemes, MAX_THEMES);
+ return 0; //fatal error
+ }
+ }
+ } else
+ return 1; //I assume non fatal error or success
+ } else
+ return 1; //I assume non fatal error or success
+ }
+ } else
+ return 1; //I assume non fatal error or success
+ } //for loop
+ //Del (Pid, Tid);
+ EndThemes = true;
+ return 2; //all themes read
+ } //if length
+ } //if !EndThemes
+ return 1; //non fatal or success
+}
+
+/**
+ * \brief Get Nagra Summary text
+ *
+ * \param TitleEventId EventId passed from title, to check it against the eventId of the summary
+ * \return pointer to reserved part of memory with summary text in it, terminated by NULL
+ */
+char *cFilterEEPG::GetSummaryTextNagra (const u_char * DataStart, long int Offset, unsigned int TitleEventId)
+//EventId is passed from title, to check it against the eventid of the summary
+{
+ u_char *p = (u_char *) DataStart + Offset;
+ sSummaryDataNagraGuide *SD = (sSummaryDataNagraGuide *) p;
+
+ if (TitleEventId != HILO32 (SD->EventId)) {
+ LogI(0, prep("ERROR, Title has EventId %08x and points to Summary with EventId %08x."), TitleEventId,
+ HILO32 (SD->EventId));
+ return 0; //return empty string
+ }
+
+ if (CheckLevel(3)) {
+ if (SD->AlwaysZero1 != 0)
+ isyslog ("EEPGDEBUG: SummAlwaysZero1 is NOT ZERO:%x.", SD->AlwaysZero1);
+ if (SD->AlwaysZero2 != 0)
+ isyslog ("EEPGDEBUG: SummAlwaysZero2 is NOT ZERO:%x.", SD->AlwaysZero2);
+ if (SD->AlwaysZero3 != 0)
+ isyslog ("EEPGDEBUG: SummAlwaysZero3 is NOT ZERO:%x.", SD->AlwaysZero3);
+ if (SD->AlwaysZero4 != 0)
+ isyslog ("EEPGDEBUG: SummAlwaysZero4 is NOT ZERO:%x.", SD->AlwaysZero4);
+ if (SD->AlwaysZero5 != 0)
+ isyslog ("EEPGDEBUG: SummAlwaysZero5 is NOT ZERO:%x.", SD->AlwaysZero5);
+ if (SD->AlwaysZero6 != 0)
+ isyslog ("EEPGDEBUG: SummAlwaysZero6 is NOT ZERO:%x.", SD->AlwaysZero6);
+ if (SD->AlwaysZero7 != 0)
+ isyslog ("EEPGDEBUG: SummAlwaysZero7 is NOT ZERO:%x.", SD->AlwaysZero7);
+ if (SD->AlwaysZero8 != 0)
+ isyslog ("EEPGDEBUG: SummAlwaysZero8 is NOT ZERO:%x.", SD->AlwaysZero8);
+ if (SD->AlwaysZero9 != 0)
+ isyslog ("EEPGDEBUG: SummAlwaysZero9 is NOT ZERO:%x.", SD->AlwaysZero9);
+
+ if (SD->Always1 != 0x31) //1970
+ isyslog ("EEPGDEBUG: SummAlways1:%02x.", SD->Always1);
+ if (SD->Always9 != 0x39)
+ isyslog ("EEPGDEBUG: SummAlways9:%02x.", SD->Always9);
+ if (SD->Always7 != 0x37)
+ isyslog ("EEPGDEBUG: SummAlways7:%02x.", SD->Always7);
+ if (SD->Always0 != 0x30)
+ isyslog ("EEPGDEBUG: SummAlways0:%02x.", SD->Always0);
+
+ if (SD->Always0x01 != 0x01) // 0x01 byte
+ isyslog ("EEPGDEBUG: Summ0x01 byte:%02x.", SD->Always0x01);
+ }
+ u_char *p2 = (u_char *) DataStart + HILO32 (SD->SummTxtOffset);
+ /* esyslog
+ ("EEPGDEBUG: EventId %08x NumberOfBlocks %02x BlockId %08x SummTxtOffset %08x *p2: %02x Unkn1:%02x, Unkn2:%02x.",
+ HILO32 (SD->EventId), SD->NumberOfBlocks, HILO32 (SD->BlockId), HILO32 (SD->SummTxtOffset), *p2, SD->Unknown1,
+ SD->Unknown2);
+ */
+ unsigned char *Text = NULL; //makes first realloc work like malloc
+ int TotLength = 0; //and also makes empty summaries if *p2 != 0x4e
+ if (SD->NumberOfBlocks > 1) {
+ switch (*p2) {
+ case 0x4e: //valid summary text follows
+ {
+ bool LastTextBlock = false;
+
+ do { //for all text parts
+ sSummaryTextNagraGuide *ST = (sSummaryTextNagraGuide *) p2;
+ p2 += 8; //skip fixed block
+ if (ST->AlwaysZero1 != 0)
+ LogD(3, prep("DEBUG: ST AlwaysZero1 is NOT ZERO:%x."), ST->AlwaysZero1);
+ if (ST->Always0x4e != 0x4e) {
+ LogI(0, prep("DEBUG: ST Always0x4e is NOT 0x4e:%x."), ST->AlwaysZero1);
+ return 0; //fatal error, empty text
+ }
+ LogI(5, prep("DEBUG: Textnr %i, Lasttxt %i."), ST->TextNr, ST->LastTextNr);
+ int SummaryLength = ST->Textlength;
+
+ Text = (unsigned char *) REALLOC (Text, SummaryLength + TotLength);
+ if (Text == NULL) {
+ LogI(0, prep("Summaries memory allocation error."));
+ return 0; //empty text
+ }
+ memcpy (Text + TotLength, p2, SummaryLength); //append new textpart
+ TotLength += SummaryLength;
+ p2 += ST->Textlength; //skip text
+
+ LastTextBlock = ((ST->LastTextNr == 0) || (ST->TextNr >= ST->LastTextNr));
+ } while (!LastTextBlock);
+ Text = (unsigned char *) REALLOC (Text, 1 + TotLength); //allocate 1 extra byte
+ Text[TotLength] = '\0'; //terminate string by NULL char
+ LogD(5, prep("DEBUG: Full Text:%s."), Text);
+
+ break;
+ }
+ case 0x8c: //"Geen uitzending" "Geen informatie beschikbaar" e.d.
+ {
+ sSummaryGBRNagraGuide *GBR = (sSummaryGBRNagraGuide *) p2;
+
+ p2 += 16; //skip fixed part, point to byte after Nextlength
+ if (CheckLevel(3)) {
+ if (GBR->AlwaysZero1 != 0)
+ isyslog ("EEPGDEBUG: GBR AlwaysZero1 is NOT ZERO:%x.", GBR->AlwaysZero1);
+ if (GBR->AlwaysZero2 != 0)
+ isyslog ("EEPGDEBUG: GBR AlwaysZero2 is NOT ZERO:%x.", GBR->AlwaysZero2);
+ if (GBR->AlwaysZero3 != 0)
+ isyslog ("EEPGDEBUG: GBR AlwaysZero3 is NOT ZERO:%x.", GBR->AlwaysZero3);
+ if (GBR->AlwaysZero4 != 0)
+ isyslog ("EEPGDEBUG: GBR AlwaysZero4 is NOT ZERO:%x.", GBR->AlwaysZero4);
+
+ isyslog ("EEPGDEBUG: Blocklength: %02x Data %02x %02x %02x %02x %02x %02x %02x %02x %02x", GBR->Blocklength,
+ GBR->Un1, GBR->Un2, GBR->Un3, GBR->Un4, GBR->Un5, GBR->Un6, GBR->Un7, GBR->Un8, GBR->Un9);
+ for (int i = 0; i < GBR->Nextlength; i += 2)
+ isyslog ("GBR Extradata %02x %02x.", *(p2 + i), *(p2 + i + 1));
+ }
+ }
+ break;
+ default:
+ LogE(0, prep("ERROR *p2 has strange value: EventId %08x NumberOfBlocks %02x BlockId %08x SummTxtOffset %08x *p2: %02x Unkn1:%02x, Unkn2:%02x."),
+ HILO32 (SD->EventId), SD->NumberOfBlocks, HILO32 (SD->BlockId), HILO32 (SD->SummTxtOffset), *p2,
+ SD->Unknown1, SD->Unknown2);
+ break;
+ } //end of switch
+ } //NrOfBlocks > 1
+
+ if (TotLength == 0)
+ Text = NULL;
+
+ p += 29; //skip fixed part of block
+ if (SD->NumberOfBlocks == 1)
+ p -= 4; //in this case there is NO summary text AND no GBR??!!
+ for (int i = 1; i < (SD->NumberOfBlocks - 1); i++) {
+ LogD(3, prep("DEBUG: Extra Block info: %02x %02x %02x %02x."), *p, *(p + 1), *(p + 2), *(p + 3));
+ p += 4; //skip this extra block info
+ }
+ return (char *) Text;
+}
+
+/**
+ * \brief Prepare to Write to Schedule
+ *
+ * gets a channel and returns an array of schedules that WriteToSchedule can write to.
+ * Call this routine before a batch of titles with the same ChannelId will be WriteToScheduled; batchsize can be 1
+ *
+ * \param C channel to prepare
+ * \param s VDR epg schedules
+ * \param ps pointer to the schedules that WriteToSchedule can write to
+ */
+//void cFilterEEPG::PrepareToWriteToSchedule (sChannel * C, cSchedules * s, cSchedule * ps/*[MAX_EQUIVALENCES]*/)
+//{
+// //for (int eq = 0; eq < C->NumberOfEquivalences; eq++) {
+// tChannelID channelID = tChannelID (C->Src/*[eq]*/, C->Nid/*[eq]*/, C->Tid/*[eq]*/, C->Sid/*[eq]*/);
+//#ifdef USE_NOEPG
+// if (allowedEPG (channelID) && (channelID.Valid ()))
+//#else
+// if (channelID.Valid ()) //only add channels that are known to vdr
+//#endif /* NOEPG */
+// ps/*[eq]*/ = s->AddSchedule (channelID); //open a a schedule for each equivalent channel
+// else {
+// ps/*[eq]*/ = NULL;
+//// LogE(5, prep("ERROR: Title block has invalid (equivalent) channel ID: Equivalence: %i, Source:%x, C->Nid:%x,C->Tid:%x,C->Sid:%x."),
+//// eq, C->Src[eq], C->Nid[eq], C->Tid[eq], C->Sid[eq]);
+// }
+// //}
+//}
+
+//void cFilterEEPG::FinishWriteToSchedule (sChannel * C, cSchedules * s, cSchedule * ps[MAX_EQUIVALENCES])
+//{
+// for (int eq = 0; eq < C->NumberOfEquivalences; eq++)
+// if (ps[eq]) {
+// ps[eq]->Sort ();
+// s->SetModified (ps[eq]);
+// }
+//}
+
+/**
+ * \brief write event to schedule
+ *
+ * \param Duration the Duration of the event in minutes
+ * \param ps points to array of schedules ps[eq], where eq is equivalence number of the channel. If channelId is invalid then ps[eq]=NULL
+ */
+void cFilterEEPG::WriteToSchedule (tChannelID channelID, cSchedules* pSchedules, unsigned int EventId, unsigned int StartTime, unsigned int Duration, char *Text, char *SummText, unsigned short int ThemeId, unsigned short int TableId, unsigned short int Version, char Rating)
+{
+ bool WrittenTitle = false;
+ bool WrittenSummary = false;
+// for (int eq = 0; eq < NumberOfEquivalences; eq++) {
+ cSchedule* ps;
+ if (channelID.Valid ()) //only add channels that are known to VDR
+ ps = pSchedules->AddSchedule (channelID); //open or create new schedule
+ else {
+ ps = NULL;
+ }
+
+ cEvent *Event = NULL;
+ if (ps/*[eq]*/) {
+
+ Event = (cEvent *) ps->GetEvent (EventId); //since Nagra uses consistent EventIds, try this first
+ bool TableIdMatches = false;
+ if (Event)
+ TableIdMatches = (Event->TableID() == TableId);
+ if (!Event || !TableIdMatches || abs(Event->StartTime() - (time_t) StartTime) > Duration * 60) //if EventId does not match, or it matched with wrong TableId, then try with StartTime
+ Event = (cEvent *) ps->GetEvent (EventId, StartTime);
+ }
+ cEvent *newEvent = NULL;
+ if (!Event) { //event is new
+ Event = newEvent = new cEvent (EventId);
+ Event->SetSeen ();
+ } else if (Event->TableID() < TableId) { //existing table may not be overwritten
+ RejectTableId++;
+ //esyslog ("EEPGDEBUG: Rejecting Event, existing TableID:%x, new TableID:%x.", Event->TableID (),
+ // TableId);
+ Event = NULL;
+ }
+
+ if (Event) {
+ Event->SetEventID (EventId); //otherwise the summary cannot be added later
+ Event->SetTableID (TableId); //TableID 0 is reserved for external epg, will not be overwritten; the lower the TableID, the more actual it is
+ Event->SetVersion (Version); //TODO use version and tableID to decide whether to update; TODO add language code
+ Event->SetStartTime (StartTime);
+ Event->SetDuration (Duration * 60);
+ if (Rating) {
+ Event->SetParentalRating(Rating);
+ }
+ char *tmp;
+ if (Text != 0x00) {
+ WrittenTitle = true;
+ CleanString ((uchar *) Text);
+ Event->SetTitle (Text);
+ }
+ Asprintf (&tmp, "%s - %d\'", Themes[ThemeId], Duration);
+ Event->SetShortText (tmp);
+ free(tmp);
+ //strreplace(t, '|', '\n');
+ if (SummText != 0x00) {
+ WrittenSummary = true;
+ CleanString ((uchar *) SummText);
+
+ //Add themes and categories epgsearch style
+ char *theme;
+ Asprintf (&theme, "%s", Themes[ThemeId]);
+ if (theme && 0 != strcmp(theme,"")) {
+ char *category, *genre;
+ category = NULL;
+ genre = NULL;
+ char *split = strchr(theme, '-'); // Look for '-' delim to separate category from genre
+ if (split){
+ *split = 0;
+ category = theme;
+ genre = (split[1] == 0x20) ? split + 2 : split + 1;
+ }else{
+ category = theme;
+ }
+ string fmt;
+ fmt = "%s";
+ if (stripspace(category)) {
+ fmt += "\nCategory: %s";
+ }
+ if (genre) {
+ fmt += "\nGenre: %s";
+ }
+ Asprintf (&tmp, fmt.c_str(), SummText, category, stripspace (genre));
+
+ Event->SetDescription (tmp);
+ free(tmp);
+ free(theme);
+ }
+ else
+ Event->SetDescription (SummText);
+ }
+ if (ps && newEvent)
+ ps->AddEvent (newEvent);
+
+ EquivHandler->updateEquivalent(pSchedules, channelID, Event);
+
+ if (!ps) {
+ //the event is not send to VDR so it has to be deleted.
+ delete Event;
+ Event = NULL;
+ }
+
+ //newEvent->FixEpgBugs (); causes segfault
+ }
+ /* else
+ esyslog ("EEPG: ERROR, somehow not able to add/update event.");*///at this moment only reports RejectTableId events
+ if (CheckLevel(4)) {
+ isyslog ("EEPG: Title:%i, Summary:%i I would put into schedule:", TitleCounter, SummaryCounter);
+ //isyslog ("C %s-%i-%i-%i\n", *cSource::ToString (C->Src[eq]), C->Nid[eq], C->Tid[eq], C->Sid[eq]);
+ isyslog ("E %u %u %u 01 FF\n", EventId, StartTime, Duration * 60);
+ isyslog ("T %s\n", Text);
+ isyslog ("S %s - %d\'\n", Themes[ThemeId], Duration);
+ isyslog ("D %s\n", SummText);
+ isyslog ("e\nc\n.\n");
+ }
+// } //if ps[eq]
+// } //for eq
+ if (WrittenTitle)
+ TitleCounter++;
+ if (WrittenSummary)
+ SummaryCounter++;
+}
+
+/**
+ * \brief Get Nagra titles
+ *
+ * \param TableIdExtension the TIE from the relevant summary sections!
+ */
+void cFilterEEPG::GetTitlesNagra (const u_char * Data, int Length, unsigned short TableIdExtension)
+{
+ u_char *p = (u_char *) Data;
+ u_char *DataEnd = (u_char *) Data + Length;
+ u_char *next_p;
+ unsigned short int MonthdayTitles = ((TableIdExtension & 0x1ff) >> 4); //Day is coded in day of the month
+ time_t timeLocal;
+ struct tm *tmCurrent;
+
+ timeLocal = time (NULL);
+ tmCurrent = gmtime (&timeLocal); //gmtime gives UTC; only used for getting current year and current day of the month...
+ unsigned short int CurrentMonthday = tmCurrent->tm_mday;
+ unsigned short int CurrentYear = tmCurrent->tm_year;
+ unsigned short int CurrentMonth = tmCurrent->tm_mon;
+ //esyslog("EEPGDEBUG: CurrentMonthday=%i, TableIdExtension:%04x, MonthdayTitles=%i.",CurrentMonthday,TableIdExtension, MonthdayTitles);
+ cSchedulesLock SchedulesLock (true);
+ cSchedules *s = (cSchedules *) cSchedules::Schedules (SchedulesLock);
+ do { //process each block of titles
+ sTitleBlockNagraGuide *TB = (sTitleBlockNagraGuide *) p;
+ int ChannelId = HILO16 (TB->ChannelId);
+ int Blocklength = HILO16 (TB->Blocklength);
+ long int NumberOfTitles = HILO32 (TB->NumberOfTitles);
+
+ LogD(3, prep("DEBUG: ChannelId %04x, Blocklength %04x, NumberOfTitles %lu."), ChannelId, Blocklength,
+ NumberOfTitles);
+ p += 4; //skip ChannelId and Block length
+ next_p = p + Blocklength;
+ if (next_p > DataEnd) { //only process if block is complete
+ LogE(0, prep("ERROR, Block exceeds end of Data. p:%p, Blocklength:%x,DataEnd:%p."), p, Blocklength, DataEnd);
+ return; //fatal error, this should never happen
+ }
+ p += 4; //skip Title number
+
+ sChannel *C = &sChannels[ChannelSeq[ChannelId]]; //find channel
+ //cSchedule *ps = NULL;//[MAX_EQUIVALENCES];
+ //PrepareToWriteToSchedule (C, s, ps);
+
+ for (int i = 0; i < NumberOfTitles; i++) { //process each title within block
+ sTitleNagraGuide *Title = (sTitleNagraGuide *) p;
+ unsigned int EventId = HILO32 (Title->EventId);
+
+ unsigned int StartTime = Title->StartTimeHigh << 5 | Title->StartTimeLow;
+ int Hours = (StartTime / 60);
+ int Minutes = StartTime % 60;
+
+ /*StartTime */
+ tmCurrent->tm_year = CurrentYear;
+ tmCurrent->tm_mon = CurrentMonth;
+ tmCurrent->tm_mday = MonthdayTitles;
+ tmCurrent->tm_hour = 0;
+ tmCurrent->tm_min = StartTime; //if start time is bigger than 1 hour, mktime will correct this!
+ tmCurrent->tm_sec = 0;
+ tmCurrent->tm_isdst = -1; //now correct with daylight savings
+ if (MonthdayTitles < CurrentMonthday - 7) //the titles that are older than one week are not from the past, but from next month!
+ //at first this was set at -1 day (= yesterday), but sometimes providers send old data which then
+ //end up in next months schedule ...
+ tmCurrent->tm_mon++; //if a year border is passed, mktime will take care of this!
+ StartTime = UTC2LocalTime (mktime (tmCurrent)); //VDR stores its times in UTC, but wants its input in local time...
+
+ char *Text = NULL;
+ u_char *t = (u_char *) Data + HILO32 (Title->OffsetToText);
+ //u_char *t2 = (u_char *) Data + HILO32 (Title->OffsetToText2);
+ if (t >= DataEnd)
+ LogE(0, prep("ERROR, Title Text out of range: t:%p, DataEnd:%p, Data:%p, Length:%i."), t, DataEnd, Data,
+ Length);
+ else {
+ Asprintf (&Text, "%.*s", *t, t + 1);
+ //asprintf (&Text, "%.*s %.*s", *t, t + 1, *t2, t2 + 1); //FIXME second text string is not processed right now
+
+ //now get summary texts
+ u_char *DataStartSummaries = buffer[TableIdExtension] + 4;
+ unsigned int DataLengthSummaries = bufsize[TableIdExtension] - 4;
+ char *SummText = NULL;
+ if (HILO32 (Title->SumDataOffset) >= DataLengthSummaries)
+ LogE(0, prep("ERROR, SumDataOffset out of range: Title->SumDataOffset:%i, DataLengthSummaries:%i."), HILO32 (Title->SumDataOffset),DataLengthSummaries);
+ else
+ SummText = GetSummaryTextNagra (DataStartSummaries, HILO32 (Title->SumDataOffset), EventId);
+
+ LogD(3, prep("DEBUG: Eventid: %08x ChannelId:%x, Start time %02i:%02i, Duration %i, OffsetToText:%08x, OffsetToText2:%08x, SumDataOffset:%08x ThemeId:%x Title:%s \n SummaryText:%s"),
+ EventId, ChannelId, Hours, Minutes, Title->Duration,
+ HILO32 (Title->OffsetToText), HILO32 (Title->OffsetToText2),
+ HILO32 (Title->SumDataOffset), Title->ThemeId, Text, SummText);
+
+ if (Themes[Title->ThemeId][0] == 0x00) //if detailed themeid is not known, get global themeid
+ Title->ThemeId &= 0xf0;
+
+ WriteToSchedule (tChannelID (C->Src, C->Nid, C->Tid, C->Sid), s, EventId, StartTime, Title->Duration, Text, SummText,
+ Title->ThemeId, NAGRA_TABLE_ID, Version);
+
+ if (Text != NULL)
+ free (Text);
+ Text = NULL;
+ if (SummText != NULL)
+ free (SummText);
+ SummText = NULL;
+ }
+
+ if (CheckLevel(3)) {
+ if (Title->AlwaysZero16 != 0)
+ isyslog ("EEPGDEBUG: TitleAlwaysZero16 (3bits) is NOT ZERO:%x.", Title->AlwaysZero16);
+ if (Title->AlwaysZero17 != 0)
+ isyslog ("EEPGDEBUG: TitleAlwaysZero17 is NOT ZERO:%x.", Title->AlwaysZero17);
+ if (Title->AlwaysZero1 != 0)
+ isyslog ("EEPGDEBUG: TitleAlwaysZero1 is NOT ZERO:%x.", Title->AlwaysZero1);
+ if (Title->AlwaysZero2 != 0)
+ isyslog ("EEPGDEBUG: TitleAlwaysZero2 is NOT ZERO:%x.", Title->AlwaysZero2);
+ if (Title->AlwaysZero3 != 0)
+ isyslog ("EEPGDEBUG: TitleAlwaysZero3 is NOT ZERO:%x.", Title->AlwaysZero3);
+ if (Title->AlwaysZero4 != 0)
+ isyslog ("EEPGDEBUG: TitleAlwaysZero4 is NOT ZERO:%x.", Title->AlwaysZero4);
+ if (Title->AlwaysZero5 != 0)
+ isyslog ("EEPGDEBUG: TitleAlwaysZero5 is NOT ZERO:%x.", Title->AlwaysZero5);
+ if (Title->AlwaysZero8 != 0)
+ isyslog ("EEPGDEBUG: TitleAlwaysZero8 is NOT ZERO:%x.", Title->AlwaysZero8);
+ if (Title->AlwaysZero9 != 0)
+ isyslog ("EEPGDEBUG: TitleAlwaysZero9 is NOT ZERO:%x.", Title->AlwaysZero9);
+ if (Title->AlwaysZero10 != 0)
+ isyslog ("EEPGDEBUG: TitleAlwaysZero10 is NOT ZERO:%x.", Title->AlwaysZero10);
+ if (Title->AlwaysZero11 != 0)
+ isyslog ("EEPGDEBUG: TitleAlwaysZero11 is NOT ZERO:%x.", Title->AlwaysZero11);
+ }
+ p += 30; //next title
+ } //end for titles
+
+ //FinishWriteToSchedule (C, s, ps);
+ sortSchedules(s, tChannelID (C->Src, C->Nid, C->Tid, C->Sid));
+ p = next_p;
+ } while (p < DataEnd); //end of TitleBlock
+}
+
+int cFilterEEPG::GetThemesNagra (const u_char * Data, int Length, unsigned short TableIdExtension) //return code 0 = fatal error, code 1 = success, code 2 = last item processed
+{
+ u_char *DataStart = (u_char *) Data;
+ u_char *p = DataStart; //TODO Language code terminated by 0 is ignored
+ u_char *DataEnd = DataStart + Length;
+ u_char *DataStartTitles = buffer[TableIdExtension] + 4;
+ u_char *DataEndTitles = DataStartTitles + bufsize[TableIdExtension] - 4;
+ if (Length == 0) {
+ LogI(1, prep("NO THEMES FOUND"));
+ return 2;
+ }
+
+ int NumberOfThemes = (*p << 24) | *(p + 1) << 16 | *(p + 2) << 8 | *(p + 3);
+ p += 4; //skip number of themes block
+ //isyslog ("EEPG: found %i themes.", NumberOfThemes);
+
+ if ((nThemes == 0))
+ LogI(1, "-------------THEMES FOUND--------------");
+
+ for (int i = 0; i < NumberOfThemes; i++) {
+ int Textlength = *p;
+ p++; //skip textlength byte
+ u_char *Text = p;
+ u_char ThemeId = 0;
+ p += Textlength; //skip text
+ int NrOfBlocks = (*p << 8) | *(p + 1);
+ p += 2; //skip nrofblocks
+ bool AnyDoubt = false;
+ u_char *p2 = p;
+ p += NrOfBlocks * 8;
+ for (int j = 0; j < NrOfBlocks; j++) {
+ sThemesTitlesNagraGuide *TT = (sThemesTitlesNagraGuide *) p2;
+ p2 += 8; //skip block
+ u_char *NewThemeId = DataStartTitles + HILO32 (TT->TitleOffset) + 28;
+ if (NewThemeId >= DataEndTitles)
+ LogE(0, prep("ERROR, ThemeId out of range: NewThemeId:%p, DataEndTitles:%p, DataStartTitles:%p."), NewThemeId,
+ DataEndTitles, DataStartTitles);
+ else {
+ //esyslog("EEPGDEBUG: NewThemeId:%02x, Text:%s.",*NewThemeId, Text);
+ if (Themes[*NewThemeId][0] != 0x00) { //theme is already filled, break off
+ AnyDoubt = true;
+ break;
+ }
+ if (j == 0) //first block
+ ThemeId = *NewThemeId;
+ else if (ThemeId != *NewThemeId) { //different theme ids in block
+ if ((ThemeId & 0xf0) != (*NewThemeId & 0xf0)) { //major nible of themeid does not correspond
+ LogE(3, prep("ERROR, Theme has multiple indices which differ in major nibble, old index = %x, new index = %x. Ignoring both indices."),
+ ThemeId, *NewThemeId);
+ AnyDoubt = true;
+ break;
+ } else if ((ThemeId & 0x0f) != 0) //ThemeId is like 1a, 2a, not like 10,20. So it is minor in tree-structure, and it should be labeled in major part of tree
+ ThemeId = *NewThemeId; //lets hope new themeid is major, if not, it has not worsened....
+ }
+ } //else NewThemeId >= DataEndTitles
+ if (CheckLevel(3)) {
+ if (TT->Always1 != 1)
+ isyslog ("EEPGDEBUG: TT Always1 is NOT 1:%x.", TT->Always1);
+ if (TT->AlwaysZero1 != 0)
+ isyslog ("EEPGDEBUG: TT AlwaysZero1 is NOT ZERO:%x.", TT->AlwaysZero1);
+ if (TT->AlwaysZero2 != 0)
+ isyslog ("EEPGDEBUG: TT AlwaysZero2 is NOT ZERO:%x.", TT->AlwaysZero2);
+ }
+ } //for nrofblocks
+ // esyslog("EEPGDEBUG: AnyDoubt:%x.",AnyDoubt);
+ if (!AnyDoubt) {
+ if (Textlength > 63)
+ Textlength = 63; //leave room for trailing NULL
+ if (Themes[ThemeId][0] != 0) {
+ LogE(0, prep("Trying to add new theme, but Id already exists. ThemeId = %x, Old theme with this Id:%s, new theme: %s."),
+ ThemeId, Themes[ThemeId], Text);
+ continue;
+ }
+ memcpy (&Themes[ThemeId], Text, Textlength);
+ Themes[ThemeId][Textlength] = '\0'; //trailing NULL
+ CleanString (Themes[ThemeId]);
+ nThemes++;
+ LogI(1, prep("%02x %s"), ThemeId, Themes[ThemeId]);
+ }
+ } //for NumberOfThemes
+ if (p != DataEnd) {
+ LogE(0, prep("Themes error: buffer is smaller or bigger than sum of entries. p:%p,DataEnd:%p"), p, DataEnd);
+ return 0;
+ } else
+ return 2;
+}
+
+/**
+ * \brief Get Nagra channels
+ *
+ * \return 0 = fatal error, code 1 = success, code 2 = last item processed
+ */
+int cFilterEEPG::GetChannelsNagra (const u_char * Data, int Length)
+{
+ u_char *DataStart = (u_char *) Data;
+ u_char *p = DataStart;
+ u_char *DataEnd = DataStart + Length;
+
+ nChannels = (*p << 24) | *(p + 1) << 16 | *(p + 2) << 8 | *(p + 3);
+ p += 4; //skip numberofchannels
+ if (CheckLevel(1)) {
+ isyslog ("| ID | %-26.26s | %-22.22s | FND | %-8.8s |\n", "Channel ID", "Channel Name", "Sky Num.");
+ isyslog ("|------|-%-26.26s-|-%-22.22s-|-----|-%-8.8s-|\n", "------------------------------",
+ "-----------------------------", "--------------------");
+ }
+
+ for (int j = 0; j < nChannels; j++) {
+ sChannelsNagraGuide *Channel = (sChannelsNagraGuide *) p;
+ sChannel *C = &sChannels[j];
+ C->ChannelId = j + 1; //Nagra starts numbering at 1
+ ChannelSeq[C->ChannelId] = j; //fill lookup table to go from channel-id to sequence nr in table; lookup table starts with 0
+ C->SkyNumber = 0;
+ //C->NumberOfEquivalences = 1; //there is always an original channel. every equivalence adds 1
+ C->Src = Source(); //assume all EPG channels are on same satellite, if not, manage this via equivalents!!!
+ C->Nid = HILO16 (Channel->NetworkId);
+ C->Tid = HILO16 (Channel->TransportId);
+ C->Sid = HILO16 (Channel->ServiceId);
+ tChannelID channelID = tChannelID(C->Src, C->Nid, C->Tid, C->Sid);
+ cChannel *VC = GetChannelByID(channelID, true);
+ bool IsFound = (VC);
+ if(IsFound) {
+ strncpy((char*)(C->Name), VC->Name (), 64);
+ C->Src = VC->Source();
+ CleanString (C->Name);
+ }
+ else
+ C->Name[0] = '\0'; //empty string
+
+ LogI(1, "|% 5d | %-26.26s | %-22.22s | %-3.3s | % 6d |\n", C->ChannelId
+ , *channelID.ToString(), C->Name, IsFound ? "YES" : "NO", C->SkyNumber);
+
+ LogD(4, prep("DEBUG: start : %s"), cs_hexdump (0, p, 9));
+
+ p += 8; //skip to first 0x8c if non-FTA, or 0x00 if FTA
+ for (int i = 0; i < Channel->Nr8cBlocks; i++) {
+ if (*p != 0x8c) {
+ LogD(0, prep("DEBUG: ERROR in Channel Table, expected value of 0x8c is %02x"), *p);
+ return 0; //fatal error
+ }
+ p++; //skip 8c byte
+ LogD(4, prep("DEBUG: 8c string: %s"), cs_hexdump (0, p + 1, *p));
+ p += *p; //skip 8c block
+ p++; //forgot to skip length byte
+ }
+ //start last non 8c block here
+ if (*p != 0x00) {
+ LogE(0, prep("ERROR in Channel Table, expected value of 0x00 is %02x"), *p);
+ return 0; //fatal error
+ }
+ p++; //skip 0x00 byte
+ LogD(4, prep("DEBUG: endstring: %s"), cs_hexdump (0, p + 1, *p * 4));
+ p += (*p * 4); //p points to nrofblocks, each block is 4 bytes
+ p++; //forgot to skip nrofblocks byte
+
+ /*
+ if (Channel->AlwaysZero1 != 0)
+ isyslog ("EEPGDEBUG: AlwaysZero1 is NOT ZERO:%x.", Channel->AlwaysZero1);
+ if (Channel->AlwaysZero2 != 0)
+ isyslog ("EEPGDEBUG: AlwaysZero2 is NOT ZERO:%x.", Channel->AlwaysZero2);
+ if (Channel->Always0x8c != 0x8c)
+ isyslog ("EEPGDEBUG: Always0x8c is NOT 0x8c:%x.", Channel->Always0x8c);
+ if (Channel->Always0x08 != 0x08)
+ isyslog ("EEPGDEBUG: Always0x08 is NOT 0x08:%x.", Channel->Always0x08);
+ if (Channel->Always0x02 != 0x02)
+ isyslog ("EEPGDEBUG: Always0x02 is NOT 0x02:%x.", Channel->Always0x02);
+ if (Channel->Always0x01 != 0x01)
+ isyslog ("EEPGDEBUG: Always0x01 is NOT 0x01:%x.", Channel->Always0x01);
+ if (Channel->Always0x20 != 0x20)
+ isyslog ("EEPGDEBUG: Always0x20 is NOT 0x20:%x.", Channel->Always0x20);
+ if (Channel->Always0x0a != 0x0a)
+ isyslog ("EEPGDEBUG: Always0x0a is NOT 0x0a:%x.", Channel->Always0x0a);
+ if (Channel->Always0x81 != 0x81)
+ isyslog ("EEPGDEBUG: Always0x81 is NOT 0x81:%x.", Channel->Always0x81);
+ if (Channel->Always0x44 != 0x44)
+ isyslog ("EEPGDEBUG: Always0x44 is NOT 0x44:%x.", Channel->Always0x44);
+ */
+
+ }
+ if (p != DataEnd)
+ LogE(0, prep("Warning, possible problem at end of channel table; p = %p, DataEnd = %p"), p, DataEnd);
+ //LoadEquivalentChannels ();
+ EquivHandler->loadEquivalentChannelMap();
+ return 2; //obviously, when you get here, channels are read succesfully, but since all channels are sent at once, you can stop now
+}
+
+/**
+ * \brief Get Nagra extended EPG
+ *
+ * \return 0 = fatal error, code 1 = success, code 2 = last item processed
+ */
+int cFilterEEPG::GetNagra (const u_char * Data, int Length)
+{
+ sTitleBlockHeaderNagraGuide *TBH = (sTitleBlockHeaderNagraGuide *) Data;
+ if (InitialTitle[0] == 0x00) { //InitialTitle is empty, so we are waiting for the start marker
+ if (TBH->TableIdExtensionHigh == 0x00 && TBH->TableIdExtensionLow == 0x00) { //this is the start of the data
+ if (TBH->VersionNumber == LastVersionNagra) {
+ LogI(0, prep("Nagra EEPG already up-to-date with version %i"), LastVersionNagra);
+ return 2;
+ }
+ Version = TBH->VersionNumber;
+ LogI(0, prep("initialized Nagraguide, version %i"), Version);
+ //u_char *p = (u_char *) Data + 11;
+ u_char *p = (u_char *) Data + 8;
+ if (*p != 0x01) {
+ LogE(0, prep("Error, Nagra first byte in table_id_extension 0x00 is not 0x01 but %02x. Format unknown, exiting."),
+ *p);
+ return 0; //fatal error
+ }
+ p++; //skip 0x01 byte
+ unsigned short int l = ((*p << 8) | *(p + 1));
+ u_char *p_end = p + l - 3; //this ensures a full block of 4 bytes is there to process
+ p += 2; //skip length bytes
+ while (p < p_end) {
+ sSection0000BlockNagraGuide *S = (sSection0000BlockNagraGuide *) p;
+ int TTT = ((S->TableIdExtensionHigh << 10) | (S->TableIdExtensionLow << 3) | (S->TIE200 << 9));
+ LogD(4, prep("DEBUG: TableIdExtension %04x, Unknown1 %02x Version %02x Always 0xd6 %02x DayCounter %02x"),
+ TTT, S->Unknown1, S->VersionNumber, S->Always0xd6, S->DayCounter);
+ if ((TTT > 0x0400) && (TTT < 0x0600)) //take high byte and compare with summarie tables in 0x0400 and 0x0500 range;
+ NagraTIE[NagraCounter++] = TTT; //only store TIEs of titlessummaries, all others can be derived; they are stored in the order of the 0x0000 index table,
+ //lets hope first entry corresponds with today, next with tomorrow etc.
+ p += 4;
+ }
+ buffer.clear (); //clear buffer maps
+ bufsize.clear (); //clear buffer maps
+ InitialTitle[0] = 0xff; //copy data into initial title
+ }
+ return (1);
+ }
+ unsigned short SectionLength = ((TBH->SectionLengthHigh & 0x0f) << 8) | TBH->SectionLengthLow;
+ unsigned short TableIdExtension = HILO16 (TBH->TableIdExtension);
+ if (TableIdExtension == 0x0000) {
+ LastVersionNagra = Version;
+ return (2); //done
+ }
+ /*
+ Table_id_extensions:
+ (0x0000)
+ (0x0010) per channel, nr_of_channels entries, every entry is 8 bytes, first 4 bytes gives nr. of titles in corresponding title table
+ (0x0020) per channel info day 2 of the month
+ (0x01F0) per channel info day 31 of the month
+ (0x0200) leeg; letop op je leest gemakkelijk door naar 0x0210!
+ (0x0210) titles day 1 of the month
+ (0x0220) titles day 2 of the month
+ (0x03F0) titles day 31 of the month
+ (0x0400) channel info
+ (0x0410) summaries day 1 of the month
+ (0x0420) summaries day 2 of the month
+ (0x05F0) summaries day 31 of the month
+ (0x0610) themes/title reference sunday, correspond to titles 0x0400 lower...
+ (0x0620) themes/title reference monday
+ ... this goes on until 0x07f0
+ (0x0810) bouquet info; references to channels within a package, day 1 of the month
+ (0x0820) same day 2 of the month
+ (0x09f0) same day 31 of the month
+ */
+
+ if (!(TBH->TableIdExtensionHigh >= 0x02 && TBH->TableIdExtensionHigh <= 0x07)) //here we regulate which tables we are testing
+ return (1);
+ if (TableIdExtension == 0x0200) //table 0x0200 only contains language code, because it is for day 0 of the month, and 0x0400 is used for channels
+ return 1;
+ if (TBH->SectionNumber == 0) { //first section, create a table
+ buffer[TableIdExtension] = NULL;
+ bufsize[TableIdExtension] = 0;
+ NumberOfTables++;
+ }
+ //store all sections in core until last section is found; processing incomplete sections is very complex and doesnt save much memory,
+ //since the data has to be stored anyway; summaries do not seem to have channelid included, so storing titles and separately storing summaries will not work...
+ //GetEventId only works for a specific Schedule for a specific ChannelId....
+ buffer[TableIdExtension] =
+ (unsigned char *) REALLOC (buffer[TableIdExtension], SectionLength - 9 + bufsize[TableIdExtension]);
+ memcpy (buffer[TableIdExtension] + bufsize[TableIdExtension], Data + 8, SectionLength - 9); //append new section
+ bufsize[TableIdExtension] += SectionLength - 9;
+ if (TBH->SectionNumber >= TBH->LastSectionNumber) {
+ LogI(1, prep("found %04x lastsection nr:%i."), TableIdExtension, TBH->SectionNumber);
+ // if (TBH->TableIdExtensionHigh == 0x04 || TBH->TableIdExtensionHigh == 0x05) {
+ if (TableIdExtension == 0x0400) {
+ int Result = GetChannelsNagra (buffer[TableIdExtension] + 4, bufsize[TableIdExtension] - 4); //TODO language code terminated by 0 is ignored
+ free (buffer[TableIdExtension]);
+ buffer[TableIdExtension] = NULL;
+ NumberOfTables--;
+ if (Result == 0)
+ return 0; //fatal error; TODO this exit should also free all other, non-Channel sections that are stored!
+ }
+ } //if lastsection read
+ return (1); //return and continue, nonfatal
+}
+
+void cFilterEEPG::ProcessNagra ()
+{
+ for (int i = 0; i < MAX_THEMES; i++) //clear all themes
+ Themes[i][0] = '\0';
+
+ for (int i = 0; i < NagraCounter; i++) { //first prcoess all themes, since they all use the same codes
+ unsigned short int TableIdExtension = NagraTIE[i];
+ int TIE = TableIdExtension + 0x0200; //from 0x0400 to 0x0600 -> themes
+ LogI(3, prep("Processing Theme with TableIdExtension:%04x"), TIE);
+ GetThemesNagra (buffer[TIE] + 4, bufsize[TIE] - 4, TableIdExtension - 0x0200); //assume theme is completed //TODO Language code terminatd by 0 is ignored
+ free (buffer[TIE]);
+ buffer[TIE] = NULL;
+ NumberOfTables--;
+ }
+
+ for (int i = 0; i < NagraCounter; i++) { //first process all themes, since they all use the same codes
+ unsigned short int TableIdExtension = NagraTIE[i];
+ int TIE = TableIdExtension - 0x0200; //from 0x0400 to 0x0200 -> titles
+ LogI(0, prep("Processing TableIdExtension:%04x"), TableIdExtension);
+ GetTitlesNagra (buffer[TIE] + 4, bufsize[TIE] - 4, TableIdExtension); //assume title-reading is completed //TODO Language code terminated by 0 is ignored
+ free (buffer[TIE]);
+ buffer[TIE] = NULL;
+ NumberOfTables--;
+
+ free (buffer[TableIdExtension]); //summaries
+ buffer[TableIdExtension] = NULL;
+ NumberOfTables--;
+ }
+ if (NumberOfTables != 0)
+ LogE(0, prep("ERROR, Not all tables processed and stream is already repeating. NumberOfTables = %i."),
+ NumberOfTables);
+}
+
+/**
+ * \brief Get MHW1 Titles
+ *
+ * \return 0 = fatal error, code 1 = success, code 2 = last item processed
+ */
+int cFilterEEPG::GetTitlesMHW1 (const u_char * Data, int Length)
+{
+ if (Length >= 42) {
+ sTitleMHW1 *Title = (sTitleMHW1 *) Data;
+ if (Title->ChannelId == 0xff) { //FF is separator packet
+ if (memcmp (InitialTitle, Data, 46) == 0) { //data is the same as initial title //TODO use easier notation
+ LogD(2, prep("End processing titles"));
+ return 2;
+ }
+ if (nTitles == 0)
+ memcpy (InitialTitle, Data, 46); //copy data into initial title
+ int Day = Title->Day;
+ int Hours = Title->Hours;
+ if (Hours > 15)
+ Hours -= 4;
+ else if (Hours > 7)
+ Hours -= 2;
+ else
+ Day++;
+ if (Day > 6)
+ Day = Day - 7;
+ Day -= Yesterday;
+ if (Day < 1)
+ Day = 7 + Day;
+ //if (Day == 1 && Hours < 6)
+ if (Day == 0 && Hours < 6)
+ Day = 7;
+ //Day = 8;
+ MHWStartTime = (Day * 86400) + (Hours * 3600) + YesterdayEpochUTC;
+ LogI(3, prep("Titles: FF PACKET, seqnr:%02x."), Data[5]);
+ } else if (InitialTitle[0] != 0x00) { //if initialized this should always be 0x90 = tableid!
+ if (nTitles < MAX_TITLES) {
+ Title_t *T;
+ T = (Title_t *) malloc (sizeof (Title_t));
+ Titles[nTitles] = T;
+ int Minutes = Title->Minutes;
+ int StartTime = MHWStartTime + (Minutes * 60);
+ T->ChannelId = Title->ChannelId - 1;
+ T->ThemeId = Title->ThemeId;
+ T->TableId = Title->TableId;
+ T->MjdTime = 0; //only used at MHW2 and SKY
+ T->EventId = HILO32 (Title->ProgramId);
+ T->StartTime = LocalTime2UTC (StartTime); //here also Daylight Savings correction is done
+ T->Duration = HILO16 (Title->Duration) * 60;
+ T->SummaryAvailable = Title->SummaryAvailable;
+ T->Text = (unsigned char *) malloc (47);
+ if (T->Text == NULL) {
+ LogE(0, prep("Titles memory allocation error."));
+ return 0;
+ }
+ //T->Text[46] = '\0'; //end string with NULL character
+ //memcpy (T->Text, &Title->Title, 23);
+ decodeText2((unsigned char *)&Title->Title, 23, (char*)T->Text, 47);
+ CleanString (T->Text);
+ LogI(3, prep("EvId:%08x,ChanId:%x, Titlenr:%d:, StartTime(epoch):%i, SummAv:%x,Name:%s."), T->EventId,
+ T->ChannelId, nTitles, T->StartTime, T->SummaryAvailable, T->Text);
+ nTitles++;
+ } //nTitles < MaxTitles
+ else {
+ LogE(0, prep("Error, %i titles found more than %i"), nTitles, MAX_TITLES);
+ return 0;
+ }
+ } //else if InitialTitle
+ } //Length==46
+ else {
+ LogE(0, prep("Error, length of title package < 42."));
+ return 1; //non fatal
+ }
+
+ return 1;
+}
+
+/**
+ * \brief Get MHW2 Titles
+ *
+ * \return 0 = fatal error, code 1 = success, code 2 = last item processed
+ */
+int cFilterEEPG::GetTitlesMHW2 (const u_char * Data, int Length)
+{
+ if (Length > 18) {
+ int Pos = 18;
+ int Len = 0;
+ /*bool Check = false;
+ while (Pos < Length) {
+ Check = false;
+ Pos += 7;
+ if (Pos < Length) {
+ Pos += 3;
+ if (Pos < Length)
+ if (Data[Pos] > 0xc0) {
+ Pos += (Data[Pos] - 0xc0);
+ Pos += 4;
+ if (Pos < Length) {
+ if (Data[Pos] == 0xff) {
+ Pos += 1;
+ Check = true;
+ }
+ }
+ }
+ }
+ if (Check == false){
+ isyslog ("EEPGDebug: Check==false");
+ return 1; // I assume nonfatal error or success
+ }
+ }*/
+ if (memcmp (InitialTitle, Data, 16) == 0) { //data is the same as initial title
+ return 2; //last item processed
+ } else {
+ if (nTitles == 0)
+ memcpy (InitialTitle, Data, 16); //copy data into initial title
+ //Pos = 18;
+ while (Pos < Length) {
+ Title_t *T;
+ T = (Title_t *) malloc (sizeof (Title_t));
+ Titles[nTitles] = T;
+ T->ChannelId = Data[Pos];
+ Pos+=11;//The date time starts here
+ //isyslog ("EEPGDebug: ChannelID:%d", T->ChannelId);
+ unsigned int MjdTime = (Data[Pos] << 8) | Data[Pos + 1];
+ T->MjdTime = 0; //not used for matching MHW2
+ T->StartTime = ((MjdTime - 40587) * 86400)
+ + (((((Data[Pos + 2] & 0xf0) >> 4) * 10) + (Data[Pos + 2] & 0x0f)) * 3600)
+ + (((((Data[Pos + 3] & 0xf0) >> 4) * 10) + (Data[Pos + 3] & 0x0f)) * 60);
+ T->Duration = (((Data[Pos + 5] << 8) | Data[Pos + 6]) >> 4) * 60;
+ Len = Data[Pos + 7] & 0x3f;
+ //isyslog ("EEPGDebug: Len:%d", Len);
+ T->Text = (unsigned char *) malloc (2 * Len + 1);
+ if (T->Text == NULL) {
+ LogE(0, prep("Titles memory allocation error."));
+ return 0; //fatal error
+ }
+ decodeText2(&Data[Pos + 8],Len,(char*)T->Text,2 * Len + 1);
+ //T->Text[Len] = '\0'; //end string with NULL character
+ //memcpy (T->Text, &Data[Pos + 8], Len);
+ CleanString (T->Text);
+ Pos += Len + 8; // Sub Theme starts here
+ T->ThemeId = ((Data[7] & 0x3f) << 6) | (Data[Pos] & 0x3f);
+ T->TableId = DEFAULT_TABLE_ID; //TODO locate the actual table id
+ T->EventId = (Data[Pos + 1] << 8) | Data[Pos + 2];
+ T->SummaryAvailable = (T->EventId != 0xFFFF);
+ LogI(3, prep("EventId %04x Titlenr %d:SummAv:%x,Name:%s."), T->EventId,
+ nTitles, T->SummaryAvailable, T->Text);
+ Pos += 3;
+ nTitles++;
+ if (nTitles > MAX_TITLES) {
+ LogE(0, prep("Error, %i titles found more than %i"), nTitles, MAX_TITLES);
+ return 0; //fatal error
+ }
+ }
+ return 1; //success
+ } //else memcmp
+ } //if length
+ return 1; //non fatal error
+}
+
+/**
+ * \brief Get MHW1 Summaries
+ *
+ * \return 0 = fatal error, code 1 = success, code 2 = last item processed
+ */
+int cFilterEEPG::GetSummariesMHW1 (const u_char * Data, int Length)
+{
+ sSummaryMHW1 *Summary = (sSummaryMHW1 *) Data;
+ if (Length >= 11) {
+ if (Summary->NumReplays < 10) { //Why limit this at 10?
+ if (Length >= (11 + (Summary->NumReplays * 7))) {
+ if (Summary->Byte7 == 0xff && Summary->Byte8 == 0xff && Summary->Byte9 == 0xff) {
+ if (memcmp (InitialSummary, Data, 20) == 0) { //data is equal to initial buffer
+ return 2;
+ } else if (nSummaries < MAX_TITLES) {
+ if (nSummaries == 0)
+ memcpy (InitialSummary, Data, 20); //copy this data in initial buffer
+ int SummaryOffset = 11 + (Summary->NumReplays * 7);
+ int SummaryLength = Length - SummaryOffset;
+ unsigned char *Text = (unsigned char *) malloc (2*SummaryLength + 1);
+ if (Text == NULL) {
+ LogE(0, prep("Summaries memory allocation error."));
+ return 0;
+ }
+ Text[SummaryLength+1] = '\0'; //end string with NULL character
+ //memcpy (Text, &Data[SummaryOffset], SummaryLength);
+ decodeText2(&Data[SummaryOffset], SummaryLength, (char*)Text, 2*SummaryLength + 1);
+// CleanString (Text);
+// if (Summary->NumReplays != 0)
+// esyslog ("EEPG: Number of replays:%i.", Summary->NumReplays);
+ //int Replays = Summary->NumReplays;
+ int ReplayOffset = 11;
+ Summary_t *S;
+ S = (Summary_t *) malloc (sizeof (Summary_t));
+ Summaries[nSummaries] = S;
+ S->NumReplays = Summary->NumReplays;
+ S->EventId = HILO32 (Summary->ProgramId);
+ S->Text = Text;
+ int i = 0;
+ do {
+ S->Replays[i].MjdTime = 0; //only used for SKY
+ //if (Summary->NumReplays == 0) {
+ //S->ChannelId = 0xFFFF; //signal that ChannelId is not known; 0 is bad signal value because it is a valid ChannelId...
+ //S->StartTime = 0;
+ //}
+ //else {
+ S->Replays[i].ChannelId = Data[ReplayOffset++] - 1;
+ unsigned int Date_hi = Data[ReplayOffset++];
+ unsigned int Date_lo = Data[ReplayOffset++];
+ unsigned short int Hour = Data[ReplayOffset++];
+ unsigned short int Minute = Data[ReplayOffset++];
+ unsigned short int Sec = Data[ReplayOffset++];
+ ReplayOffset++; //makes total of 7 bytes
+
+ LogI(4, prep("EvId:%08x ChanId:%x, ChanName %s, Time: %02d:%02d:%02d."),
+ S->EventId, S->Replays[i].ChannelId,
+ sChannels[ChannelSeq[S->Replays[i].ChannelId]].Name, Hour, Minute, Sec);
+
+ S->Replays[i].StartTime = MjdToEpochTime (Date) + (((((Hour & 0xf0) >> 4) * 10) + (Hour & 0x0f)) * 3600)
+ + (((((Minute & 0xf0) >> 4) * 10) + (Minute & 0x0f)) * 60)
+ + ((((Sec & 0xf0) >> 4) * 10) + (Sec & 0x0f));
+// summary -> time[i] = ProviderLocalTime2UTC (summary -> time[i]);
+ S->Replays[i].StartTime = LocalTime2UTC (S->Replays[i].StartTime);
+ //}
+ i++;
+ } while (i < Summary->NumReplays);
+ //} while (Replays-- >= 0);
+ LogI(3, prep("EvId:%08x ChanId:%x, Replays:%d, Summnr %d:%.35s."), S->EventId,
+ S->Replays[0].ChannelId, S->NumReplays, nSummaries, S->Text);
+ nSummaries++;
+ } else {
+ LogE(0, prep("Error, %i summaries found more than %i"), nSummaries, MAX_TITLES);
+ return 0;
+ }
+ } //0xff
+ else {
+ LogE(0, prep("Warning, Summary bytes not as expected."));
+ return 1; //it is not a success, but error is not fatal
+ }
+ } //numreplays length
+ else {
+ LogE(0, prep("Warning, number of replays is not conforming to length."));
+ return 1; //nonfatal error
+ }
+ } //numreplays <10
+ else {
+ LogE(0, prep("Warning, number of replays %d > 10, cannot process."),
+ Summary->NumReplays);
+ return 1; //nonfatal error
+ }
+ } //length >11
+ else {
+ LogE(0, prep("Summary length too small:%s"), cs_hexdump (0, Data, Length));
+ return 1; //nonfatal error
+ }
+ return 1; //success
+}
+
+/**
+ * \brief Get MHW2 Summaries
+ *
+ * \return 0 = fatal error, code 1 = success, code 2 = last item processed
+ */
+int cFilterEEPG::GetSummariesMHW2 (const u_char * Data, int Length)
+{
+ if (Length > (Data[14] + 17)) {
+ if (memcmp (InitialSummary, Data, 16) == 0) //data is equal to initial buffer
+ return 2;
+ else {
+ if (nSummaries == 0)
+ memcpy (InitialSummary, Data, 16); //copy this data in initial buffer
+ if (nSummaries < MAX_TITLES) {
+ int lenText = Data[14];
+ int SummaryLength = lenText;
+ int Pos = 15;
+ int Loop = Data[Pos + SummaryLength] & 0x0f;
+ Summary_t *S;
+ S = (Summary_t *) malloc (sizeof (Summary_t));
+ Summaries[nSummaries] = S;
+
+ S->Replays[0].ChannelId = 0xFFFF; //signal that ChannelId is not known; 0 is bad signal value because it is a valid ChannelId...
+ S->Replays[0].StartTime = 0; //not used
+ S->Replays[0].MjdTime = 0; //not used
+ S->NumReplays = 0; //not used
+ S->EventId = (Data[3] << 8) | Data[4];
+ unsigned char tmp[4096]; //TODO do this smarter
+ memcpy (tmp, &Data[Pos], lenText);
+ tmp[SummaryLength] = '\n';
+ SummaryLength += 1;
+ Pos += (lenText + 1);
+ if (Loop > 0) {
+ while (Loop > 0) {
+ lenText = Data[Pos];
+ Pos += 1;
+ if ((Pos + lenText) < Length) {
+ memcpy (&tmp[SummaryLength], &Data[Pos], lenText);
+ SummaryLength += lenText;
+ if (Loop > 1) {
+ tmp[SummaryLength] = ' ';// This is considered as an EPG bug in VDR '\n';
+ SummaryLength += 1;
+ }
+ } else
+ break;
+ Pos += lenText;
+ Loop--;
+ }
+ }
+ S->Text = (unsigned char *) malloc (2 * SummaryLength + 1);
+ if (S->Text == NULL) {
+ LogE(0, prep("Summaries memory allocation error."));
+ return 0; //fatal error
+ }
+ //memcpy (S->Text, tmp, SummaryLength);
+ //S->Text[SummaryLength] = '\0'; //end string with NULL character
+ decodeText2(tmp,SummaryLength,(char*)S->Text,2 * SummaryLength + 1);
+ CleanString (S->Text);
+ LogI(3, prep("EventId %08x Summnr %d:%.30s."), S->EventId, nSummaries, S->Text);
+ nSummaries++;
+ } else {
+ LogE(0, prep("Error, %i summaries found more than %i"), nSummaries, MAX_TITLES);
+ return 0; //fatal error
+ }
+ } //else
+ } //if length
+ return 1; //succes or nonfatal error
+}
+
+/**
+ * \brief Get SKYBOX Channels
+ *
+ * \return 0 = fatal error, code 1 = success, code 2 = last item processed
+ */
+int cFilterEEPG::GetChannelsSKYBOX (const u_char * Data, int Length)
+{
+
+ if (memcmp (InitialChannel, Data, 8) == 0) { //data is the same as initial title
+ //LoadEquivalentChannels ();
+ EquivHandler->loadEquivalentChannelMap();
+ return 2;
+ } else {
+ if (nChannels == 0)
+ memcpy (InitialChannel, Data, 8); //copy data into initial title
+ if (nChannels == 0) {
+ LogI(1, "| ID | %-26.26s | %-22.22s | FND | %-8.8s |\n", "Channel ID", "Channel Name", "Sky Num.");
+ LogI(1, "|------|-%-26.26s-|-%-22.22s-|-----|-%-8.8s-|\n", "------------------------------",
+ "-----------------------------", "--------------------");
+ }
+// unsigned short int BouquetId = (Data[3] << 8) | Data[4];
+ int BouquetDescriptorsLength = ((Data[8] & 0x0f) << 8) | Data[9];
+ int TransportStreamLoopLength =
+ ((Data[BouquetDescriptorsLength + 10] & 0x0f) << 8) | Data[BouquetDescriptorsLength + 11];
+ int p1 = (BouquetDescriptorsLength + 12);
+ while (TransportStreamLoopLength > 0) {
+ unsigned short int Tid = (Data[p1] << 8) | Data[p1 + 1];
+ unsigned short int Nid = (Data[p1 + 2] << 8) | Data[p1 + 3];
+ int TransportDescriptorsLength = ((Data[p1 + 4] & 0x0f) << 8) | Data[p1 + 5];
+ int p2 = (p1 + 6);
+ p1 += (TransportDescriptorsLength + 6);
+ TransportStreamLoopLength -= (TransportDescriptorsLength + 6);
+ while (TransportDescriptorsLength > 0) {
+ unsigned char DescriptorTag = Data[p2];
+ int DescriptorLength = Data[p2 + 1];
+ int p3 = (p2 + 2);
+ p2 += (DescriptorLength + 2);
+ TransportDescriptorsLength -= (DescriptorLength + 2);
+ switch (DescriptorTag) { //TODO switch with only 1 case??? replace this by template
+ case 0xb1:
+ p3 += 2;
+ DescriptorLength -= 2;
+ while (DescriptorLength > 0) {
+ // 0x01 = Video Channel
+ // 0x02 = Audio Channel
+ // 0x05 = Other Channel
+ //if( Data[p3+2] == 0x01 || Data[p3+2] == 0x02 || Data[p3+2] == 0x05 )
+ //{
+ unsigned short int Sid = (Data[p3] << 8) | Data[p3 + 1];
+ unsigned short int ChannelId = (Data[p3 + 3] << 8) | Data[p3 + 4];
+ unsigned short int SkyNumber = (Data[p3 + 5] << 8) | Data[p3 + 6];
+ if (SkyNumber > 100 && SkyNumber < 1000) {
+ if (ChannelId > 0) {
+ sChannel *C;
+ if (ChannelSeq.count (ChannelId) == 0) { //not found
+ C = &sChannels[nChannels];
+ C->ChannelId = ChannelId;
+ //C->NumberOfEquivalences = 1; //there is always an original channel. every equivalence adds 1
+ C->Src = Source (); //assume all EPG channels are on same satellite, if not, manage this via equivalents!!!
+ C->Nid = Nid;
+ C->Tid = Tid;
+ C->Sid = Sid;
+ C->SkyNumber = SkyNumber;
+ tChannelID channelID = tChannelID (C->Src, C->Nid, C->Tid, C->Sid);
+ cChannel *VC = Channels.GetByChannelID (channelID, true);
+ bool IsFound = (VC);
+ if (IsFound)
+ strncpy ((char *) C->Name, VC->Name (), 64);
+ else
+ C->Name[0] = '\0'; //empty string
+
+ LogI(1, "|% 5d | %-26.26s | %-22.22s | %-3.3s | % 6d |\n", C->ChannelId
+ , *channelID.ToString(), C->Name, IsFound ? "YES" : "NO", C->SkyNumber);
+
+ ChannelSeq[C->ChannelId] = nChannels; //fill lookup table to go from channel-id to sequence nr in table
+ nChannels++;
+ if (nChannels >= MAX_CHANNELS) {
+ LogE(0, prep("Error, %i channels found more than %i"), nChannels, MAX_CHANNELS);
+ return 0;
+ }
+ }
+ }
+ }
+ p3 += 9;
+ DescriptorLength -= 9;
+ }
+ break;
+ default:
+ break;
+ } //switch descriptortag
+ }
+ } //while
+ return 1;
+ } //else part of memcmp
+}
+
+/**
+ * \brief Get SKYBOX Titles
+ *
+ * \return 0 = fatal error, code 1 = success, code 2 = last item processed
+ */
+int cFilterEEPG::GetTitlesSKYBOX (const u_char * Data, int Length)
+{
+ int p;
+ unsigned short int ChannelId;
+ unsigned short int MjdTime;
+ int Len1;
+ int Len2;
+
+ if (Length < 20)
+ return 1; //nonfatal error
+ if (memcmp (InitialTitle, Data, 20) == 0) //data is the same as initial title
+ return 2;
+ else {
+ if (nTitles == 0)
+ memcpy (InitialTitle, Data, 20); //copy data into initial title
+ ChannelId = (Data[3] << 8) | Data[4];
+ MjdTime = ((Data[8] << 8) | Data[9]);
+ if (ChannelId > 0) {
+ if (MjdTime > 0) {
+ p = 10;
+ do {
+ Title_t *T;
+ T = (Title_t *) malloc (sizeof (Title_t));
+ Titles[nTitles] = T;
+ T->ChannelId = ChannelId;
+ T->MjdTime = MjdTime; //only date, no time. Is used to match titles and summaries, SKYBOX only
+ T->EventId = (Data[p] << 8) | Data[p + 1];
+ Len1 = ((Data[p + 2] & 0x0f) << 8) | Data[p + 3];
+ if (Data[p + 4] != 0xb5) {
+ LogD(5, prep("Data error signature for title - Data[p + 4] != 0xb5"));
+ break;
+ }
+ if (Len1 > Length) {
+ LogD(5, prep("Data error signature for title - Len1 > Length"));
+ break;
+ }
+ p += 4;
+ Len2 = Data[p + 1] - 7;
+ T->StartTime = ((MjdTime - 40587) * 86400) + ((Data[p + 2] << 9) | (Data[p + 3] << 1));
+ T->Duration = ((Data[p + 4] << 9) | (Data[p + 5] << 1));
+ T->ThemeId = Data[p + 6];
+ T->TableId = DEFAULT_TABLE_ID; //TODO locate the actual table id
+ //TODO Data[p + 7] is Quality value add it to description
+ //int quality = Data[p + 7];
+ switch (Data[p + 8] & 0x0F) {
+ case 0x01:
+ T->Rating = 0x00; //"U"
+ break;
+ case 0x02:
+ T->Rating = 0x08; //"PG"
+ break;
+ case 0x03:
+ T->Rating = 0x0C; //"12"
+ break;
+ case 0x04:
+ T->Rating = 0x0F; //"15"
+ break;
+ case 0x05:
+ T->Rating = 0x12; //"18"
+ break;
+ default:
+ T->Rating = 0x00; //"-"
+ break;
+ }
+ T->Unknown1 = Data[p + 4 - 13]; //FIXME
+ T->Unknown2 = Data[p + 4 - 12]; //FIXME
+ T->Unknown3 = Data[p + 4 - 11]; //FIXME
+ unsigned char tmp[4096]; //TODO smarter
+ Len2 = sky_huffman_decode (&Data[p + 9], Len2, tmp);
+ if (Len2 == 0) {
+ LogE(0, prep("Warning, could not huffman-decode title-text, skipping title."));
+ return 1; //non-fatal error
+ }
+ T->Text = (unsigned char *) malloc (Len2 + 1);
+ if (T->Text == NULL) {
+ LogE(0, prep("Titles memory allocation error."));
+ return 0;
+ }
+ T->Text[Len2] = '\0'; //end string with NULL character
+ memcpy (T->Text, tmp, Len2);
+ CleanString (T->Text);
+ T->SummaryAvailable = 1; //TODO I assume this is true?
+
+ LogI(3, prep("EventId %08x Titlenr %d,Unknown1:%x,Unknown2:%x,Un3:%x,Name:%s."),
+ T->EventId, nTitles, T->Unknown1, T->Unknown2, T->Unknown3, T->Text);
+
+ p += Len1;
+ nTitles++;
+ if (nTitles >= MAX_TITLES) {
+ LogE(0, prep("Error, %i titles found more than %i"), nTitles, MAX_TITLES);
+ return 0; //fatal error
+ }
+ } while (p < Length);
+ }
+ }
+ }
+ return 1; //success
+}
+
+/**
+ * \brief Get SKYBOX Summaries
+ *
+ * \return 0 = fatal error, code 1 = success, code 2 = last item processed
+ */
+int cFilterEEPG::GetSummariesSKYBOX (const u_char * Data, int Length)
+{
+ int p;
+ unsigned short int ChannelId;
+ unsigned short int MjdTime;
+ int Len1;
+ int Len2;
+
+ if (Length < 20) {
+ return 1; //non fatal error I assume
+ }
+ if (memcmp (InitialSummary, Data, 20) == 0) //data is equal to initial buffer
+ return 2;
+// else if (nSummaries < MAX_SUMMARIES) {
+ else {
+ if (nSummaries == 0)
+ memcpy (InitialSummary, Data, 20); //copy this data in initial buffer
+ ChannelId = (Data[3] << 8) | Data[4];
+ MjdTime = ((Data[8] << 8) | Data[9]);
+ if (ChannelId > 0) {
+ if (MjdTime > 0) {
+ p = 10;
+ do {
+ Summary_t *S;
+ S = (Summary_t *) malloc (sizeof (Summary_t));
+ Summaries[nSummaries] = S;
+ S->Replays[0].ChannelId = ChannelId;
+ S->Replays[0].MjdTime = MjdTime;
+ S->NumReplays = 0; //not used
+ S->EventId = (Data[p] << 8) | Data[p + 1];
+ Len1 = ((Data[p + 2] & 0x0f) << 8) | Data[p + 3];
+ if (Data[p + 4] != 0xb9) {
+ LogD(5, prep("Data error signature for title - Data[p + 4] != 0xb5"));
+ break;
+ }
+ if (Len1 > Length) {
+ LogD(5, prep("Data error signature for title - Len1 > Length"));
+ break;
+ }
+ p += 4;
+ Len2 = Data[p + 1];
+ unsigned char tmp[4096]; //TODO can this be done better?
+ Len2 = sky_huffman_decode (&Data[p + 2], Len2, tmp);
+ if (Len2 == 0) {
+ LogE(0, prep("Warning, could not huffman-decode text, skipping summary."));
+ return 1; //non-fatal error
+ }
+ S->Text = (unsigned char *) malloc (Len2 + 1);
+ if (S->Text == NULL) {
+ LogE(0, prep("Summaries memory allocation error."));
+ return 0;
+ }
+ memcpy (S->Text, tmp, Len2);
+ S->Text[Len2] = '\0'; //end string with NULL character
+ CleanString (S->Text);
+ LogI(3, prep("EventId %08x Summnr %d:%.30s."), S->EventId, nSummaries, S->Text);
+ p += Len1;
+ nSummaries++;
+ if (nSummaries >= MAX_TITLES) {
+ LogI(0, prep("Error, %i summaries found more than %i"), nSummaries, MAX_TITLES);
+ return 0;
+ }
+ } while (p < Length);
+ }
+ }
+ }
+ return 1;
+}
+
+void cFilterEEPG::FreeSummaries (void)
+{
+ if (Format == MHW1 || Format == MHW2 || Format == SKY_IT || Format == SKY_UK) {
+ Summary_t *S; //TODO do I need this?
+ Summary_t *S2; //TODO do I need this?
+ for (int i = 0; i < nSummaries; i++) {
+ S = Summaries[i];
+ if (i < nSummaries - 1) {
+ S2 = Summaries[i + 1]; //look at next summary
+ if (S->Text != S2->Text && S->Text != 0x00) //this is the last summary that points to this text block; needed in case NumReplays > 1, multiple pointers to same textblock
+ free (S->Text);
+ } else if (S->Text != 0x00)
+ free (S->Text);
+ free (S);
+ }
+ }
+ nSummaries = 0;
+}
+
+void cFilterEEPG::FreeTitles (void)
+{
+ if (Format == MHW1 || Format == MHW2 || Format == SKY_IT || Format == SKY_UK) {
+ Title_t *T;
+ for (int i = 0; i < nTitles; i++) {
+ T = Titles[i];
+ free (T->Text);
+ free (T);
+ }
+ }
+ nTitles = 0;
+}
+
+void cFilterEEPG::LoadIntoSchedule (void)
+{
+ int i, j;
+ i = 0;
+ j = 0;
+ bool foundtitle;
+ foundtitle = false;
+ Title_t *T;
+ Summary_t *S;
+ int remembersummary;
+ //keep statistics
+ int SummariesNotFound = 0;
+ int NoSummary = 0;
+ int NotMatching = 0;
+ int LostSync = 0;
+ remembersummary = -1;
+
+ {
+ cSchedulesLock SchedulesLock (true);
+ cSchedules *s = (cSchedules *) cSchedules::Schedules (SchedulesLock);
+ if (s) {
+
+ while (i < nTitles) {
+ T = Titles[i];
+ S = Summaries[j];
+ foundtitle = false;
+
+ while ((i < nTitles) && (!foundtitle)) { //find next title that has summary
+ T = Titles[i];
+ if (T->SummaryAvailable)
+ foundtitle = true;
+ else {
+ NoSummary++;
+ i++;
+ }
+ }
+//esyslog("foundtitle %x for next title that has a summary:%d",foundtitle,i);
+
+ if (!foundtitle) //no more titles with summaries
+ break;
+ if ((T->EventId == S->EventId) && (T->MjdTime == S->Replays[0].MjdTime)
+ && ((T->ChannelId == S->Replays[0].ChannelId) || ((Format != SKY_IT) && (Format != SKY_UK)))) { //should always be true, titles and summaries are broadcasted in order...
+ LogD(3, prep("T->EventId == S->EventId"));
+ //MjdTime = 0 for all but SKY
+ //S->ChannelId must be equal to T->ChannelId only for SKY; in MHW1 S->ChannelId overrides T->ChannelId when NumReplays > 1
+ remembersummary = -1; //reset summary searcher
+ //int Replays = S->NumReplays;
+
+ int index = 0;
+ do {
+ unsigned short int ChannelId;
+ time_t StartTime;
+ if (S->NumReplays == 0) {
+ ChannelId = T->ChannelId;
+ StartTime = T->StartTime;
+ } else {
+ ChannelId = S->Replays[index].ChannelId;
+ StartTime = S->Replays[index].StartTime;
+ }
+
+ //channelids are sequentially numbered and sent in MHW1 and MHW2, but not in SKY, so we need to lookup the table index
+ sChannel *C = &sChannels[ChannelSeq[ChannelId]]; //find channel
+ //cSchedule *p;//[MAX_EQUIVALENCES];
+ //PrepareToWriteToSchedule (C, s, p);
+ tChannelID chanID = tChannelID (C->Src, C->Nid, C->Tid, C->Sid);
+
+ char rating = 0x00;
+ if ((Format == SKY_IT || Format == SKY_UK) && T->Rating) { //TODO only works on OTV for now
+ rating = T->Rating;
+ }
+ unsigned short int TableId = DEFAULT_TABLE_ID;
+ if (T->TableId) {
+ TableId = T->TableId;
+ }
+
+ WriteToSchedule (chanID, s, T->EventId, StartTime, T->Duration / 60, (char *) T->Text,
+ (char *) S->Text, T->ThemeId, TableId, 0, rating);
+ sortSchedules(s, chanID);
+
+ //FinishWriteToSchedule (C, s, p);
+ //Replays--;
+ //if ((S->NumReplays != 0) && (Replays > 0)) { //when replays are used, all summaries of the replays are stored consecutively; currently only CSAT
+ //j++; //move to next summary
+ //if (j >= nSummaries) //do not forget to look in beginning of (ring)buffer
+ //j = 0;
+ //S = Summaries[j]; //next summary within replay range
+ //}
+ index++;
+ } //while
+ while (index < S->NumReplays);
+
+ //TODO: why load events that have already past, and then run Cleanup
+ //end of putting title and summary in schedule
+ i++; //move to next title
+ } //if T->EventId == S->EventId
+ else {
+// esyslog("EEPG ERROR: ProgramIds not matching, title:%d,summary%d, T->EventId:%u, S->Eventid:%u.",i,j,T->EventId,S->EventId);
+ NotMatching++;
+ if (remembersummary == -1) { //I am not in search loop yet
+ remembersummary = j;
+ if (remembersummary == 0)
+ remembersummary = nSummaries; //or next test will never be succesfull for remembersummary = 0
+ LostSync++;
+// esyslog("EEPG Error: lost sync at title %d, summary %d.",i,j);
+ } else if (j == (remembersummary - 1)) { //the last summary to be checked has failed also
+ //esyslog ("EEPG Error: could not find summary for summary-available Title %d.", i);
+ esyslog
+ ("EEPG: Error, summary not found for EventId %08x Titlenr %d:SummAv:%x,Unknown1:%x,Unknown2:%x,Un3:%x,Name:%s.",
+ T->EventId, i, T->SummaryAvailable, T->Unknown1, T->Unknown2, T->Unknown3, T->Text);
+
+ /* write Title info to schedule */
+ sChannel *C = &sChannels[ChannelSeq[T->ChannelId]]; //find channel
+ //cSchedule *p;//[MAX_EQUIVALENCES];
+ tChannelID chanID = tChannelID (C->Src, C->Nid, C->Tid, C->Sid);
+ //PrepareToWriteToSchedule (C, s, p);
+ char rating = 0x00;
+ if ((Format == SKY_IT || Format == SKY_UK) && T->Rating) { //TODO only works on OTV for now
+ rating = T->Rating;
+ }
+ WriteToSchedule (chanID, s, T->EventId, T->StartTime, T->Duration / 60, (char *) T->Text,
+ NULL, T->ThemeId, DEFAULT_TABLE_ID, 0, rating);
+ //FinishWriteToSchedule (C, s, p);
+ sortSchedules(s, chanID);
+
+ SummariesNotFound++;
+ i++; //move to next title, for this one no summary can be found
+ }
+
+// esyslog("Trying again for this title %d, remember summary %d, but advancing one Summary to %d.",i,remembersummary,j);
+ }
+ j++; //move to next summary
+ if (j >= nSummaries) //do not forget to look in beginning of (ring)buffer
+ j = 0;
+ } //while title
+ } // if s
+ else
+ LogE (0, prep("Error: could not lock schedules."));
+
+ }//release ScheduleLock
+ cSchedules::Cleanup (true); //deletes all past events
+
+ //isyslog ("EEPG: found %i equivalents channels", nEquivChannels);
+ isyslog ("EEPG: found %i themes", nThemes);
+ isyslog ("EEPG: found %i channels", nChannels);
+ isyslog ("EEPG: found %i titles", nTitles);
+ if (NoSummary != 0)
+ isyslog ("EEPG: of which %i reported to have no summary available; skipping these BIENTOT titles", NoSummary);
+ isyslog ("EEPG: found %i summaries", nSummaries);
+ if (SummariesNotFound != 0)
+ esyslog ("EEPG: %i summaries not found", SummariesNotFound);
+ if (NotMatching > nSummaries)
+ LogI (0, prep("Warning: lost sync %i times, summary did not match %i times."),
+ LostSync, NotMatching);
+
+ FreeSummaries (); //do NOT free channels, themes and bouquets here because they will be reused in SKY!
+ FreeTitles ();
+ if (!((Format == SKY_IT) || (Format == SKY_UK))) { //everything but SKY; SKY is the only protocol where LoadIntoSchedule is called repeatedly
+ ChannelSeq.clear ();
+ }
+}
+
+void cFilterEEPG::AddFilter (u_short Pid, u_char Tid)
+{
+ if (!Matches (Pid, Tid)) {
+ Add (Pid, Tid);
+ esyslog (prep("Filter Pid:%x,Tid:%x added."), Pid, Tid);
+ }
+}
+
+void cFilterEEPG::AddFilter (u_short Pid, u_char Tid, unsigned char Mask)
+{
+ if (!Matches (Pid, Tid)) {
+ Add (Pid, Tid, Mask);
+ esyslog (prep("Filter Pid:%x,Tid:%x,Mask:%x added."), Pid, Tid, Mask);
+ }
+}
+
+void cFilterEEPG::ProcessNextFormat (bool FirstTime = false)
+{
+ /* for (int i = 0; i <= HIGHEST_FORMAT; i++)
+ esyslog ("EEPGDEBUG: Format %i on pid %x", i, UnprocessedFormat[i]); */
+
+ if (!FirstTime) {
+ //isyslog ("EEPG: found %i equivalents channels", equiChanMap.size());
+ isyslog ("EEPG: found %i themes", nThemes);
+ isyslog ("EEPG: found %i channels", nChannels);
+ isyslog ("EEPG: found %i titles", nTitles);
+ isyslog ("EEPG: found %i summaries", nSummaries);
+ isyslog ("EEPG: written %i titles", TitleCounter);
+ isyslog ("EEPG: written %i summaries", SummaryCounter);
+ isyslog ("EEPG: rejected %i titles/summaries because of higher TableId", RejectTableId);
+ //Send message when finished
+ if (SetupPE->DisplayMessage) {
+ char *mesg;
+ Asprintf(&mesg, "EEPG: written %i summaries", SummaryCounter);
+ Skins.QueueMessage(mtInfo, mesg, 2);
+ free(mesg);
+ }
+
+ TitleCounter = 0;
+ SummaryCounter = 0;
+ /*if (SummariesNotFound != 0)
+ esyslog ("EEPG: %i summaries not found", SummariesNotFound);
+ else if (VERBOSE >= 1)
+ isyslog ("EEPG: %i summaries not found", SummariesNotFound); */
+ UnprocessedFormat[Format] = 0; //clear previously processed format
+
+ //Next few lines prevent eepg from reading multiple eepg-systems on one transponder e.g. CDNL
+ //isyslog ("EEPG: Ended all processing");
+ //return;
+ //If you remove these lines, multiple systems WILL be read
+
+ }
+ TitleCounter = 0;
+ SummaryCounter = 0;
+ RejectTableId = 0;
+ //cleanup mess of last processing
+ ChannelSeq.clear ();
+ FreeTitles ();
+ FreeSummaries ();
+
+ // Enable EIT scan for all except DISH_BEV since it is already enabled
+ if (SetupPE->ProcessEIT && !UnprocessedFormat[EIT]
+ && !UnprocessedFormat[FREEVIEW] && !UnprocessedFormat[DISH_BEV]) {
+ UnprocessedFormat[EIT] = EIT_PID;
+ EquivHandler->loadEquivalentChannelMap();
+ }
+
+ //now start looking for next format to process
+ int pid;
+ for (int i = 0; i <= HIGHEST_FORMAT; i++){ //find first format that is detected
+ if (UnprocessedFormat[i]) {
+ isyslog ("EEPG: %s Extended EPG detected on pid %x.", FormatName[i], UnprocessedFormat[i]);
+ Format = (EFormat)i;
+ // highest format is processed first this way
+ // make sure that CONT protocols like Premiere, Freesat are processed
+ // AFTER ONCE protocols like MHW, SKY and NAGRA
+ break;
+ }
+ if (i == HIGHEST_FORMAT) { //there are no formats left to process
+ isyslog ("EEPG: Ended all processing");
+ return;
+ }
+ }
+
+ pid = UnprocessedFormat[Format]; //and reinstall its pid
+
+ memset (&InitialChannel, 0, 8);
+ memset (&InitialTitle, 0, 64);
+ memset (&InitialSummary, 0, 64);
+ NagraCounter = 0;
+ Version = -1; //because 0 can be a valid version number...
+ nChannels = 0;
+ nThemes = 0;
+ EndChannels = false;
+ EndThemes = false;
+ switch (Format) {
+ case PREMIERE:
+ AddFilter (pid, 0xA0);
+ break;
+ case MHW1:
+ AddFilter (0xd3, 0x92); //ThemesMHW1//TODO: all filters are serialized, strictly speaking Themes is non-fatal...
+ break;
+ case MHW2:
+ AddFilter (0x231, 0xc8); //MHW2 Channels & Themes
+ break;
+ case SKY_IT:
+ case SKY_UK:
+ AddFilter (0x11, 0x4a); //Sky Channels
+ break;
+ case FREEVIEW: //Freeview, CONT mode //TODO streamline this for other modes
+ InitDictionary ();
+ AddFilter (pid, 0x4e, 0xfe); //event info, actual(0x4e)/other(0x4f) TS, present/following
+ AddFilter (pid, 0x50, 0xf0); //event info, actual TS, schedule(0x50)/schedule for future days(0x5X)
+ AddFilter (pid, 0x60, 0xf0); //event info, other TS, schedule(0x60)/schedule for future days(0x6X)
+ AddFilter (0x39, 0x50, 0xf0); //event info, actual TS, Viasat
+ AddFilter (0x39, 0x60, 0xf0); //event info, other TS, Viasat
+ break;
+ case NAGRA:
+ AddFilter (pid, 0xb0); //perhaps TID is equal to first data byte?
+ break;
+ case DISH_BEV:
+#if APIVERSNUM < 10726
+ AddFilter (EIT_PID, 0, 0); // event info, actual(0x4e)/other(0x4f) TS, present/following
+#endif
+ AddFilter (0x0300, 0, 0); // Dish Network EEPG event info, actual(0x4e)/other(0x4f) TS, present/following
+ AddFilter (0x0441, 0, 0); // Dish Network EEPG event info, actual(0x4e)/other(0x4f) TS, present/following
+// AddFilter (0x0441, 0x50, 0xf0); // Bell ExpressVU EEPG
+// AddFilter (0x0441, 0x60, 0xf0); // Bell ExpressVU EEPG
+ break;
+ case EIT:
+ AddFilter (pid, 0x4e, 0xfe); //event info, actual(0x4e)/other(0x4f) TS, present/following
+ AddFilter (pid, 0x50, 0xf0); //event info, actual TS, schedule(0x50)/schedule for future days(0x5X)
+ AddFilter (pid, 0x60, 0xf0); //event info, other TS, schedule(0x60)/schedule for future days(0x6X)
+ break;
+ default:
+ break;
+ }
+}
+
+void cFilterEEPG::ProccessContinuous(u_short Pid, u_char Tid, int Length, const u_char *Data)
+{
+ //0x39 Viasat, 0x0300 Dish Network EEPG, 0x0441 Bell ExpressVU EEPG
+ LogD(4, prep("Pid: 0x%02x Tid: %d Length: %d"), Pid, Tid, Length);
+ cSchedulesLock SchedulesLock(true, 10);
+ cSchedules *Schedules = (cSchedules*)(cSchedules::Schedules(SchedulesLock));
+ //Look for other satelite positions only if Dish/Bell ExpressVU for the moment hardcoded pid check
+ if(Schedules)
+ SI::cEIT2 EIT(Schedules, Source(), Tid, Data, Pid == EIT_PID);
+
+ else//cEIT EIT (Schedules, Source (), Tid, Data);
+ {
+ // If we don't get a write lock, let's at least get a read lock, so
+ // that we can set the running status and 'seen' timestamp (well, actually
+ // with a read lock we shouldn't be doing that, but it's only integers that
+ // get changed, so it should be ok)
+ cSchedulesLock SchedulesLock;
+ cSchedules *Schedules = (cSchedules*)(cSchedules::Schedules(SchedulesLock));
+ if(Schedules)
+ SI::cEIT2 EIT(Schedules, Source(), Tid, Data, Pid == EIT_PID, true);
+
+ //cEIT EIT (Schedules, Source (), Tid, Data, true);
+ }
+}
+
+void cFilterEEPG::Process (u_short Pid, u_char Tid, const u_char * Data, int Length)
+{
+ int now = time (0);
+// LogD(2, prep("Pid: 0x%02x Tid: %d Length: %d PMT pid: 0x%04x"), Pid, Tid, Length, pmtpid);
+// LogD(2, prep("Source: %d Transponder: %d"), Source () , Transponder ());
+
+ if (Pid == 0 && Tid == SI::TableIdPAT) {
+ if (!pmtnext || now > pmtnext) {
+ if (pmtpid)
+ NextPmt ();
+ if (!pmtpid) {
+ SI::PAT pat (Data, false);
+ if (pat.CheckCRCAndParse ()) {
+ SI::PAT::Association assoc;
+ int idx = 0;
+ for (SI::Loop::Iterator it; pat.associationLoop.getNext (assoc, it);) {
+ if (!assoc.isNITPid ()) {
+ //if (!assoc.isNITPid () && Scanning) {
+ if (idx++ == pmtidx) {
+ pmtpid = assoc.getPid ();
+ pmtsid = assoc.getServiceId ();
+ Add (pmtpid, 0x02);
+ pmtnext = now + PMT_SCAN_TIMEOUT;
+ LogI(3, prep("PMT pid now 0x%04x (idx=%d)\n"), pmtpid, pmtidx);
+ break;
+ }
+ }
+ }
+ if (!pmtpid) {
+ pmtidx = 0;
+ pmtnext = now + PMT_SCAN_IDLE;
+ LogI(1, prep("PMT scan idle\n"));
+
+ Del (0, 0); //this effectively kills the PMT_SCAN_IDLE functionality
+
+ //now after the scan is completed, start processing
+ ProcessNextFormat (true); //FirstTime flag is set
+ }
+ }
+ }
+ }
+ } else if (pmtpid > 0 && Pid == pmtpid && Tid == SI::TableIdPMT && Source () && Transponder ()) {
+ SI::PMT pmt (Data, false);
+ if (pmt.CheckCRCAndParse () && pmt.getServiceId () == pmtsid) {
+ SI::PMT::Stream stream;
+ for (SI::Loop::Iterator it; pmt.streamLoop.getNext (stream, it);) {
+ LogD(4, prep("StreamType: 0x%02x"), stream.getStreamType ());
+ if (stream.getStreamType () == 0x05 || stream.getStreamType () == 0xc1) { //0x05 = Premiere, SKY, Freeview, Nagra 0xc1 = MHW1,MHW2;
+ SI::CharArray data = stream.getData ();
+ if ((data[1] & 0xE0) == 0xE0 && (data[3] & 0xF0) == 0xF0) {
+ bool prvData = false, usrData = false;
+ bool prvOTV = false, prvFRV = false;
+ int usrOTV = 0, usrFRV = 0;
+ if (data[2]==0x39) {//TODO Test This
+ prvFRV = true;
+ usrFRV = 1;
+ LogD(4, prep("if (data[2]==0x39) {//TODO Test This"));
+ }
+ //Format = 0; // 0 = premiere, 1 = MHW1, 2 = MHW2, 3 = Sky Italy (OpenTV), 4 = Sky UK (OpenTV), 5 = Freesat (Freeview), 6 = Nagraguide
+ SI::Descriptor * d;
+ unsigned char nDescriptorTag;
+ for (SI::Loop::Iterator it; (d = stream.streamDescriptors.getNext (it));) {
+ LogD(4, prep("EEPGDEBUG:d->getDescriptorTAG():%x,SI::PrivateTag:%x\n"), d->getDescriptorTag (), SI::PrivateDataSpecifierDescriptorTag);
+ nDescriptorTag = d->getDescriptorTag ();
+ switch (nDescriptorTag) {
+ case SI::PrivateDataSpecifierDescriptorTag:
+ //esyslog ("prv: %d %08x\n", d->getLength (), d->getData ().FourBytes (2));
+ if (d->getLength () == 6 && d->getData ().FourBytes (2) == 0x000000be)
+ prvData = true;
+ if (d->getLength () == 6 && d->getData ().FourBytes (2) == 0x4f545600) //OpenTV
+ prvOTV = true;
+ if (d->getLength () == 6 && d->getData ().FourBytes (2) == 0x46534154) //Freeview
+ prvFRV = true;
+ break;
+ case 0x52:
+ //if (d->getLength () == 3 && d->getData ().FourBytes (2) == 0xb07ea882) {
+ if (d->getLength () == 3 && ((d->getData ().TwoBytes (2) & 0xff00) == 0xb000))
+ UnprocessedFormat[NAGRA] = stream.getPid ();
+ break;
+ case 0x90:
+ //esyslog ("usr: %d %08x\n", d->getLength (), d->getData ().FourBytes (2));
+ if (d->getLength () == 6 && d->getData ().FourBytes (2) == 0x0000ffff)
+ usrData = true;
+ if (d->getLength () == 3 && ((d->getData ().TwoBytes (2) & 0xff00) == 0xb600)) //SKY IT //TODO ugly!
+ //if (d->getLength () == 3 && (d->getData ().TwoBytes (2) == 0xb6a5)) //SKY IT //TODO ugly!
+ usrOTV = SKY_IT;
+ //Format = SKY_IT;
+ if (d->getLength () == 3 && d->getData ().FourBytes (2) == 0xc004e288) //SKY UK
+ usrOTV = SKY_UK;
+ //Format = SKY_UK;
+ break;
+ case 0xc1: //MHW1, MHW2
+// esyslog("EEPGDEBUG:d->getDescriptorTAG:%d %08x\n",d->getLength(),d->getData().FourBytes(2));
+ if (d->getLength () == 10 && d->getData ().FourBytes (2) == 0x50555348) //MHw1 Cyfra
+ UnprocessedFormat[MHW1] = stream.getPid ();
+ break;
+ case 0xc2: //MHW1, MHW2
+ if (d->getLength () == 10 && d->getData ().FourBytes (2) == 0x45504700) //MHw1 CanDigNL and CSat
+ UnprocessedFormat[MHW1] = stream.getPid ();
+ else if (d->getLength () == 10 && d->getData ().FourBytes (2) == 0x46494348) { //MHW2
+ UnprocessedFormat[MHW2] = stream.getPid ();
+ }
+ break;
+ case 0xd1: //Freeview
+ LogD(4, prep("case 0xd1: //Freeview"));
+ if (d->getLength () == 3 && ((d->getData ().TwoBytes (2) & 0xff00) == 0x0100))
+ usrFRV = 0x01;
+ //01 = EIT pid 3842
+ //03 04 = SDT Service Description Table pid 3841
+ //07 = still undocumented, definition of buch of transport streams pid 3840
+ //02 = ATSC reserved, find out what huffman encoded text is sent here! pid 3843
+ //05 06 = TOT Time Offset Table pid 3844
+ break;
+
+ /* case 0xfe: //SKY_IT
+ if (d->getLength () == 6 && d->getData ().FourBytes (2) == 0x534b5900) { //SKY_IT
+ Format = SKY_IT;
+ }
+ break;*/
+ default:
+ break;
+ }
+ delete d;
+ }
+ if ((prvOTV) && ((usrOTV == SKY_IT) || (usrOTV == SKY_UK)))
+ UnprocessedFormat[usrOTV] = stream.getPid ();
+ else if (prvFRV)
+ if (usrFRV == 0x01)
+ UnprocessedFormat[FREEVIEW] = stream.getPid ();
+ if (prvData && usrData)
+ UnprocessedFormat[PREMIERE] = stream.getPid ();
+ //TODO DPE DISH/BEV filters are always ON on provided transponders,
+ // but there is no knowledge for the loop of the data at the moment.
+ //EEPG:12472:H:S119.0W:20000:0:0:0:0:36862:4100:18:36862
+ if (((Source() == cSource::FromString("S119.0W")
+ && Transponder() == cChannel::Transponder(12472,'H'))
+ || (Source() == cSource::FromString("S91.0W")
+ && Transponder() == cChannel::Transponder(12224,'V')))
+ && !UnprocessedFormat[DISH_BEV]) {
+ UnprocessedFormat[DISH_BEV] = stream.getPid ();
+ }
+
+ } //if data[1] && data [3]
+ } //if streamtype
+ } //for loop that walks through streams
+ NextPmt ();
+ pmtnext = 0;
+ /* }
+ else {
+ Del (pmtpid, 0x02);
+ Del (0, 0);
+ pmtidx = 0;
+ pmtnext = now + PMT_SCAN_IDLE;
+ isyslog ("PMT scan forced idle\n");
+ }*/
+ } //checkCRC
+ } //if pmtpid
+ else if (Source ()) {
+
+ if ( Pid == EIT_PID || Pid == 0x0300 || Pid == 0x0441 ) {
+ if (Tid >= 0x4E)
+ ProccessContinuous(Pid, Tid, Length, Data);
+ return;
+ }
+ int Result;
+ switch (Tid) {
+ case 0xA0:
+ if ((Pid < 0x30) || (Pid > 0x37)) {
+
+ ProcessPremiere(Data);
+ break;
+ } //if citpid == 0xb11 Premiere
+ /* no break - used for sky also*/
+ case 0xa1:
+ case 0xa2:
+ case 0xa3:
+ Result = GetTitlesSKYBOX (Data, Length - 4);
+ if (Result != 1) //when fatal error or finished
+ Del (Pid, 0xa0, 0xfc); //kill filter
+ if (Result == 0) { //fatal error
+ esyslog ("EEPG: Fatal error reading titles.");
+ ProcessNextFormat (); //and go process other formats
+ }
+ if (Result == 2)
+ AddFilter (Pid + 0x10, 0xa8, 0xfc); //Set filter that processes summaries of this batch
+ break;
+ case 0xa8:
+ case 0xa9:
+ case 0xaa:
+ case 0xab:
+ Result = GetSummariesSKYBOX (Data, Length - 4);
+ if (Result != 1) //when fatal error or finished
+ Del (Pid, 0xa8, 0xfc); //kill filter
+ if (Result == 0) {
+ esyslog ("EEPG: Fatal error reading summaries.");
+ ProcessNextFormat ();
+ }
+ if (Result == 2) {
+ LoadIntoSchedule ();
+ if (Pid < 0x47) //this is not the last batch//FIXME chaining is easy on the PIDs and the CPU, but error when Pid,Tid is not used at the moment...
+ AddFilter (Pid - 0x0F, 0xa0, 0xfc); //next pid, first tid
+ else //last pid was processed
+ ProcessNextFormat ();
+ }
+ break;
+ case 0x90:
+ if (Pid == 0xd2) {
+ Result = GetTitlesMHW1 (Data, Length);
+ if (Result != 1) //fatal error or last processed
+ Del (Pid, Tid);
+ if (Result == 0) {
+ esyslog ("EEPG: Fatal error reading titles.");
+ ProcessNextFormat ();
+ }
+ if (Result == 2)
+ AddFilter (0xd3, 0x90); //SummariesMHW1
+ } else if (Pid == 0xd3) {
+ Result = GetSummariesMHW1 (Data, Length);
+ if (Result != 1) //fatal error or last processed
+ Del (Pid, Tid);
+ if (Result == 0) {
+ esyslog ("EEPG: Fatal error reading summaries.");
+ }
+ if (Result == 2) {
+ LoadIntoSchedule ();
+ }
+ if (Result != 1) {
+ ProcessNextFormat ();
+ }
+ }
+ break;
+ case 0xc8: //GetChannelsMHW2 or GetThemesMHW2
+ if (Pid == 0x231) {
+ if (Data[3] == 0x01) { //Themes it will be
+ Result = GetThemesMHW2 (Data, Length); //return code 0 = fatal error, code 1 = sucess, code 2 = last item processed
+ //break;
+ if (Result != 1)
+ EndThemes = true; //also set Endthemes on true on fatal error
+ } //if Data
+ else if (Data[3] == 0x00) { //Channels it will be
+ Result = GetChannelsMHW (Data, Length, 2); //return code 0 = fatal error, code 1 = sucess, code 2 = last item processed
+ if (Result != 1)
+ EndChannels = true; //always remove filter, code 1 should never be returned since MHW2 always reads all channels..
+ ChannelsOk = (Result == 2);
+ }
+ if (EndChannels && EndThemes) { //those are only set withing MHW2
+ Del (0x231, 0xc8); //stop reading MHW2 themes and channels
+ if (ChannelsOk) //No channels = fatal, no themes = nonfatal
+ AddFilter (0x234, 0xe6); //start reading MHW2 titles
+ else {
+ esyslog ("EEPG: Fatal error reading channels.");
+ ProcessNextFormat ();
+ }
+ }
+ } //if Pid == 0x231
+ break;
+ case 0x91:
+ Result = GetChannelsMHW (Data, Length, 1); //return code 0 = fatal error, code 1 = sucess, code 2 = last item processed
+ Del (Pid, Tid); //always remove filter, code 1 should never be returned since MHW1 always reads all channels...
+ if (Result == 2)
+ AddFilter (0xd2, 0x90); //TitlesMHW1
+ else {
+ esyslog ("EEPG: Fatal error reading channels.");
+ ProcessNextFormat ();
+ }
+ break;
+ case 0x92:
+ Result = GetThemesMHW1 (Data, Length); //return code 0 = fatal error, code 1 = sucess, code 2 = last item processed
+ if (Result != 1)
+ Del (Pid, Tid);
+ if (Result == 2)
+ AddFilter (0xd3, 0x91); //ChannelsMHW1
+ else {
+ esyslog ("EEPG: Fatal error reading themes."); //doesnt have to be fatal...
+ ProcessNextFormat ();
+ }
+ break;
+ case 0xe6: //TitlesMHW2
+ if (Pid == 0x234) {
+ Result = GetTitlesMHW2 (Data, Length); //return code 0 = fatal error, code 1 = sucess, code 2 = last item processed
+ if (Result != 1)
+ Del (Pid, Tid);
+ if (Result == 0) {
+ esyslog ("EEPG: Fatal error reading titles.");
+ ProcessNextFormat ();
+ }
+ if (Result == 2)
+ AddFilter (0x236, 0x96); //start reading MHW2 summaries....
+ }
+ break;
+ case 0x96: //Summaries MHW2
+ if (Pid == 0x236) {
+ Result = GetSummariesMHW2 (Data, Length); //return code 0 = fatal error, code 1 = sucess, code 2 = last item processed
+ if (Result != 1)
+ Del (Pid, Tid);
+ if (Result == 0) {
+ esyslog ("EEPG: Fatal error reading summaries.");
+ }
+ if (Result == 2)
+ LoadIntoSchedule ();
+ if (Result != 1) {
+ ProcessNextFormat ();
+ }
+ } //if pid
+ break;
+ case 0x4a: //Sky channels
+ if (Pid == 0x11) {
+ Result = GetChannelsSKYBOX (Data, Length - 4);
+ if (Result != 1) //only breakoff on completion or error; do NOT clean up after success, because then not all bouquets will be read
+ Del (Pid, Tid); //Read all channels, clean up filter
+ if (Result == 2) {
+ GetThemesSKYBOX (); //Sky Themes from file; must be called AFTER first channels to have lThemes initialized FIXME
+ if (InitDictionary ())
+ AddFilter (0x30, 0xa0, 0xfc); //SKY Titles batch 0 of 7
+ else {
+ esyslog ("EEPG: Fatal error reading huffman table.");
+ ProcessNextFormat ();
+ }
+ }
+
+ } //if Pid == 0x11
+ break;
+ case 0xb0: //NagraGuide
+ if (Pid == 0xc8) {
+ Result = GetNagra (Data, Length);
+ if (Result != 1)
+ Del (Pid, Tid);
+ if (Result == 0) {
+ esyslog ("EEPG: Fatal error processing NagraGuide. End of processing.");
+ }
+ if (Result == 2) {
+ ProcessNagra ();
+ cSchedules::Cleanup (true); //deletes all past events
+ isyslog ("EEPG: Ended processing Nagra");
+ }
+ if (Result != 1) {
+ ProcessNextFormat ();
+ }
+ }
+ break;
+
+ case 0x4E:
+ case 0x4F:
+ case 0x50:
+ case 0x51:
+ case 0x52:
+ case 0x53:
+ case 0x54:
+ case 0x55:
+ case 0x56:
+ case 0x57:
+ case 0x58:
+ case 0x59:
+ case 0x5A:
+ case 0x5B:
+ case 0x5C:
+ case 0x5D:
+ case 0x5E:
+ case 0x5F:
+ case 0x60:
+ case 0x61:
+ case 0x62:
+ case 0x63:
+ case 0x64:
+ case 0x65:
+ case 0x66:
+ case 0x67:
+ case 0x68:
+ case 0x69:
+ case 0x6A:
+ case 0x6B:
+ case 0x6C:
+ case 0x6D:
+ case 0x6E:
+ case 0x6F:
+ // Freesat:
+ // Set(3842, 0x4E, 0xFE); // event info, actual(0x4E)/other(0x4F) TS, present/following
+ // Set(3842, 0x50, 0xF0); // event info, actual TS, schedule(0x50)/schedule for future days(0x5X)
+ // Set(3842, 0x60, 0xF0); // event info, other TS, schedule(0x60)/schedule for future days(0x6X)
+ //
+ // PID found: 3841 (0x0f01) [SECTION: Service Description Table (SDT) - other transport stream]
+ // PID found: 3842 (0x0f02) [SECTION: Event Information Table (EIT) - other transport stream, schedule]
+ // PID found: 3843 (0x0f03) [SECTION: ATSC reserved] TODO find out what compressed text info is here!
+ // PID found: 3844 (0x0f04) [SECTION: Time Offset Table (TOT)]
+
+ if (Pid == 3842 || Pid == 0x39) {//0x39 Viasat, 0x0300 Dish Network EEPG, 0x0441 Bell ExpressVU EEPG
+ ProccessContinuous(Pid, Tid, Length, Data);
+ }
+ break;
+
+ default:
+ break;
+ } //end switch
+ } //closes SOURCE()
+} //end of closing
+
+void cFilterEEPG::ProcessPremiere(const u_char *& Data)
+
+{
+
+ SI::PremiereCIT cit(Data, false);
+
+ if (cit.CheckCRCAndParse ()) {
+ cSchedulesLock SchedulesLock (true, 10);
+ cSchedules *Schedules = (cSchedules *) cSchedules::Schedules (SchedulesLock);
+ if (Schedules) {
+ int now = time (0);
+ int nCount = 0;
+ int nRating = 0;
+ unsigned char Tid = 0xa0; // TODO maybe default TableID
+ SI::ExtendedEventDescriptors * ExtendedEventDescriptors = 0;
+ SI::ShortEventDescriptor * ShortEventDescriptor = 0;
+ char *order = 0, *rating = 0;
+ {
+ time_t firstTime = 0;
+ SI::Descriptor * d;
+ unsigned char nDescriptorTag;
+ bool UseExtendedEventDescriptor = false;
+ int LanguagePreferenceShort = -1;
+ int LanguagePreferenceExt = -1;
+ for (SI::Loop::Iterator it; (d = cit.eventDescriptors.getNext (it));) {
+ nDescriptorTag = d->getDescriptorTag ();
+ switch (nDescriptorTag) {
+ case 0xF0: // order information
+ if (SetupPE->OrderInfo) {
+ static const char *text[] = {
+ trNOOP ("Ordernumber"),
+ trNOOP ("Price"),
+ trNOOP ("Ordering"),
+ trNOOP ("SMS"),
+ trNOOP ("WWW")
+ };
+ char buff[512];
+ int p = 0;
+ const unsigned char *data = d->getData ().getData () + 2;
+ for (int i = 0; i < 5; i++) {
+ int l = data[0];
+ if (l > 0)
+ p += snprintf (&buff[p], sizeof (buff) - p, "\n%s: %.*s", tr (text[i]), l, &data[1]);
+ data += l + 1;
+ }
+ if (p > 0)
+ order = strdup (buff);
+ }
+ break;
+ case 0xF1: // parental rating
+ if (SetupPE->RatingInfo) {
+ char buff[512];
+ int p = 0;
+ const unsigned char *data = d->getData ().getData () + 2;
+ nRating = data[0] + 3;
+ p += snprintf (&buff[p], sizeof (buff) - p, "\n%s: %d %s", tr ("Rating"), nRating, tr ("years"));
+ data += 7;
+ int l = data[0];
+ if (l > 0)
+ p += snprintf (&buff[p], sizeof (buff) - p, " (%.*s)", l, &data[1]);
+ if (p > 0)
+ rating = strdup (buff);
+ }
+ break;
+ case SI::PremiereContentTransmissionDescriptorTag:
+ if (nCount >= 0) {
+ SI::PremiereContentTransmissionDescriptor * pct = (SI::PremiereContentTransmissionDescriptor *) d;
+ nCount++;
+ SI::PremiereContentTransmissionDescriptor::StartDayEntry sd;
+ SI::Loop::Iterator it;
+ if (pct->startDayLoop.getNext (sd, it)) {
+ SI::PremiereContentTransmissionDescriptor::StartDayEntry::StartTimeEntry st;
+ SI::Loop::Iterator it2;
+ if (sd.startTimeLoop.getNext (st, it2)) {
+ time_t StartTime = st.getStartTime (sd.getMJD ());
+ if (nCount == 1)
+ firstTime = StartTime;
+ else if (firstTime < StartTime - 5 * 50 || firstTime > StartTime + 5 * 60)
+ nCount = -1;
+ }
+ }
+ }
+ break;
+ case SI::ExtendedEventDescriptorTag: {
+ SI::ExtendedEventDescriptor * eed = (SI::ExtendedEventDescriptor *) d;
+ if (I18nIsPreferredLanguage (Setup.EPGLanguages, eed->languageCode, LanguagePreferenceExt)
+ || !ExtendedEventDescriptors) {
+ delete ExtendedEventDescriptors;
+ ExtendedEventDescriptors = new SI::ExtendedEventDescriptors;
+ UseExtendedEventDescriptor = true;
+ }
+ if (UseExtendedEventDescriptor) {
+ ExtendedEventDescriptors->Add (eed);
+ d = NULL; // so that it is not deleted
+ }
+ if (eed->getDescriptorNumber () == eed->getLastDescriptorNumber ())
+ UseExtendedEventDescriptor = false;
+ }
+ break;
+ case SI::ShortEventDescriptorTag: {
+ SI::ShortEventDescriptor * sed = (SI::ShortEventDescriptor *) d;
+ if (I18nIsPreferredLanguage (Setup.EPGLanguages, sed->languageCode, LanguagePreferenceShort)
+ || !ShortEventDescriptor) {
+ delete ShortEventDescriptor;
+ ShortEventDescriptor = sed;
+ d = NULL; // so that it is not deleted
+ }
+ }
+ break;
+ default:
+ break;
+ }
+ delete d;
+ }
+ }
+
+ {
+ bool Modified = false;
+ int optCount = 0;
+ unsigned int crc[3];
+ crc[0] = cit.getContentId ();
+ SI::PremiereContentTransmissionDescriptor * pct;
+ for (SI::Loop::Iterator it;
+ (pct =
+ (SI::PremiereContentTransmissionDescriptor *) cit.eventDescriptors.getNext (it,
+ SI::
+ PremiereContentTransmissionDescriptorTag));) {
+ int nid = pct->getOriginalNetworkId ();
+ int tid = pct->getTransportStreamId ();
+ int sid = pct->getServiceId ();
+ if (SetupPE->FixEpg) {
+ if (nid == 133) {
+ if (tid == 0x03 && sid == 0xf0) {
+ tid = 0x02;
+ sid = 0xe0;
+ } else if (tid == 0x03 && sid == 0xf1) {
+ tid = 0x02;
+ sid = 0xe1;
+ } else if (tid == 0x03 && sid == 0xf5) {
+ tid = 0x03;
+ sid = 0xdc;
+ } else if (tid == 0x04 && sid == 0xd2) {
+ tid = 0x11;
+ sid = 0xe2;
+ } else if (tid == 0x11 && sid == 0xd3) {
+ tid = 0x11;
+ sid = 0xe3;
+ }
+ }
+ }
+ tChannelID channelID (Source (), nid, tid, sid);
+ cChannel *channel = Channels.GetByChannelID (channelID, true);
+
+ if (!channel)
+ continue;
+
+ cSchedule *pSchedule = (cSchedule *) Schedules->GetSchedule (channelID);
+ if (!pSchedule) {
+ pSchedule = new cSchedule (channelID);
+ Schedules->Add (pSchedule);
+ }
+
+ optCount++;
+ SI::PremiereContentTransmissionDescriptor::StartDayEntry sd;
+ int index = 0;
+ for (SI::Loop::Iterator it; pct->startDayLoop.getNext (sd, it);) {
+ int mjd = sd.getMJD ();
+ SI::PremiereContentTransmissionDescriptor::StartDayEntry::StartTimeEntry st;
+ for (SI::Loop::Iterator it2; sd.startTimeLoop.getNext (st, it2);) {
+ time_t StartTime = st.getStartTime (mjd);
+ time_t EndTime = StartTime + cit.getDuration ();
+ int runningStatus =
+ (StartTime < now && now < EndTime) ? SI::RunningStatusRunning :
+ ((StartTime - 30 < now && now < StartTime) ?
+ SI::RunningStatusStartsInAFewSeconds : SI::RunningStatusNotRunning);
+ bool isOpt = false;
+ if (index++ == 0 && nCount > 1)
+ isOpt = true;
+ crc[1] = isOpt ? optCount : 0;
+ crc[2] = StartTime / STARTTIME_BIAS;
+ tEventID EventId = ((('P' << 8) | 'W') << 16) | crc16 (0, (unsigned char *) crc, sizeof (crc));
+ LogI(2, "%s R%d %04x/%.4x %d %d/%d %s +%d ", *channelID.ToString (), runningStatus,
+ EventId & 0xFFFF, cit.getContentId (), index, isOpt, optCount,
+ stripspace (ctime (&StartTime)), (int) cit.getDuration () / 60);
+ if (EndTime + Setup.EPGLinger * 60 < now) {
+ LogI(2, "(old)\n");
+ continue;
+ }
+
+ bool newEvent = false;
+ cEvent *pEvent = (cEvent *) pSchedule->GetEvent (EventId, -1);
+ if (!pEvent) {
+ LogI(2, "(new)\n");
+ pEvent = new cEvent (EventId);
+ if (!pEvent)
+ continue;
+ newEvent = true;
+ } else {
+ LogI(2, "(upd)\n");
+ pEvent->SetSeen ();
+ if (pEvent->TableID () == 0x00 || pEvent->Version () == cit.getVersionNumber ()) {
+ if (pEvent->RunningStatus () != runningStatus)
+ pSchedule->SetRunningStatus (pEvent, runningStatus, channel);
+ continue;
+ }
+ }
+ pEvent->SetEventID (EventId);
+ pEvent->SetTableID (Tid);
+ pEvent->SetVersion (cit.getVersionNumber ());
+ pEvent->SetStartTime (StartTime);
+ pEvent->SetDuration (cit.getDuration ());
+
+ if (ShortEventDescriptor) {
+ char buffer[256];
+ ShortEventDescriptor->name.getText (buffer, sizeof (buffer));
+ if (isOpt) {
+ char buffer2[sizeof (buffer) + 32];
+ snprintf (buffer2, sizeof (buffer2), optPats[SetupPE->OptPat], buffer, optCount);
+ pEvent->SetTitle (buffer2);
+ } else
+ pEvent->SetTitle (buffer);
+ LogI(2, "title: %s\n", pEvent->Title ());
+ pEvent->SetShortText (ShortEventDescriptor->text.getText (buffer, sizeof (buffer)));
+ }
+ if (ExtendedEventDescriptors) {
+ char buffer[ExtendedEventDescriptors->getMaximumTextLength (": ") + 1];
+ pEvent->SetDescription (ExtendedEventDescriptors->getText (buffer, sizeof (buffer), ": "));
+ }
+ if (order || rating) {
+ int len = (pEvent->Description ()? strlen (pEvent->Description ()) : 0) +
+ (order ? strlen (order) : 0) + (rating ? strlen (rating) : 0);
+ char buffer[len + 32];
+ buffer[0] = 0;
+ if (pEvent->Description ())
+ strcat (buffer, pEvent->Description ());
+ if (rating) {
+ strcat (buffer, rating);
+ pEvent->SetParentalRating(nRating);
+ }
+ if (order)
+ strcat (buffer, order);
+ pEvent->SetDescription (buffer);
+ }
+
+ if (newEvent)
+ pSchedule->AddEvent (pEvent);
+
+ pEvent->FixEpgBugs ();
+ if (pEvent->RunningStatus () != runningStatus)
+ pSchedule->SetRunningStatus (pEvent, runningStatus, channel);
+ pSchedule->DropOutdated (StartTime, EndTime, Tid, cit.getVersionNumber ());
+ Modified = true;
+ }
+ }
+ if (Modified) {
+ pSchedule->Sort ();
+ Schedules->SetModified (pSchedule);
+ }
+ delete pct;
+ }
+ }
+ delete ExtendedEventDescriptors;
+ delete ShortEventDescriptor;
+ free (order);
+ free (rating);
+ }
+ }
+
+}
+
+// --- cPluginEEPG ------------------------------------------------------
+
+class cPluginEEPG:public cPlugin
+{
+private:
+ struct {
+ cFilterEEPG *filter;
+ cDevice *device;
+ } epg[MAXDVBDEVICES];
+
+ void CheckCreateFile(const char* Name, const char *fileContent[]);
+
+public:
+ cPluginEEPG (void);
+ virtual const char *Version (void) {
+ return VERSION;
+ }
+ virtual const char *Description (void) {
+ return tr (DESCRIPTION);
+ }
+ virtual bool Start (void);
+ virtual void Stop (void);
+ virtual cMenuSetupPage *SetupMenu (void);
+ virtual bool SetupParse (const char *Name, const char *Value);
+};
+
+cPluginEEPG::cPluginEEPG (void)
+{
+ memset (epg, 0, sizeof (epg));
+}
+
+void cPluginEEPG::CheckCreateFile(const char* Name, const char *fileContent[])
+{
+ FILE *File;
+ string FileName = string(cSetupEEPG::getInstance()->getConfDir()) + "/" + Name;
+ File = fopen(FileName.c_str(), "r");
+ if (File == NULL) {
+ LogE (0, prep("Error opening file '%s', %s"), FileName.c_str(), strerror (errno));
+ File = fopen (FileName.c_str(), "w");
+ if (File == NULL) {
+ LogE (0, prep("Error creating file '%s', %s"), FileName.c_str(), strerror (errno));
+ } else {
+ int i = 0;
+ while (fileContent[i] != NULL) {
+ fprintf (File, "%s\n", fileContent[i]);
+ i++;
+ }
+ LogI (0, prep("Success creating file '%s'"), FileName.c_str());
+ fclose (File);
+ }
+ } else {
+ fclose (File);
+ }
+}
+
+bool cPluginEEPG::Start (void)
+{
+#if APIVERSNUM < 10507
+ RegisterI18n (Phrases);
+#endif
+ for (int i = 0; i < MAXDVBDEVICES; i++) {
+ cDevice *dev = cDevice::GetDevice (i);
+ if (dev) {
+ epg[i].device = dev;
+ dev->AttachFilter (epg[i].filter = new cFilterEEPG);
+ isyslog ("Attached EEPG filter to device %d", i);
+ }
+ }
+ char *ConfDir = NULL;
+ // Initialize any background activities the plugin shall perform.
+ DIR *ConfigDir;
+ //if (ConfDir == NULL) {
+ Asprintf (&ConfDir, "%s/eepg", cPlugin::ConfigDirectory ());
+ //}
+ ConfigDir = opendir (ConfDir);
+ if (ConfigDir == NULL) {
+ esyslog ("EEPG: Error opening directory '%s', %s", ConfDir, strerror (errno));
+ if (mkdir (ConfDir, 0777) < 0) {
+ esyslog ("EEPG: Error creating directory '%s', %s", ConfDir, strerror (errno));
+ } else {
+ isyslog ("EEPG: Success creating directory '%s'", ConfDir);
+ }
+ }
+ cSetupEEPG::getInstance()->setConfDir(ConfDir);
+
+ CheckCreateFile(EEPG_FILE_EQUIV, FileEquivalences);
+ CheckCreateFile("sky_it.dict", SkyItDictionary);
+ CheckCreateFile("sky_uk.dict", SkyUkDictionary);
+ CheckCreateFile("sky_it.themes", SkyItThemes);
+ CheckCreateFile("sky_uk.themes", SkyUkThemes);
+ CheckCreateFile("freesat.t1", FreesatT1);
+ CheckCreateFile("freesat.t2", FreesatT2);
+ CheckCreateFile("sky_uk.themes", SkyUkThemes);
+
+ sky_tables[0] = NULL;
+ sky_tables[1] = NULL;
+ tables[0][0] = NULL;
+ //store all available sources, so when a channel is not found on current satellite, we can look for alternate sat positions.
+ //perhaps this can be done smarter through existing VDR function???
+ for (cChannel * Channel = Channels.First (); Channel; Channel = Channels.Next (Channel)) {
+ if (!Channel->GroupSep ()) {
+ bool found = false;
+ for (int i = 0; (i < NumberOfAvailableSources) && (!found); i++)
+ found = (Channel->Source () == AvailableSources[i]);
+ if (!found)
+ AvailableSources[NumberOfAvailableSources++] = Channel->Source ();
+ }
+ }
+ if (CheckLevel(3))
+ for (int i = 0; i < NumberOfAvailableSources; i++)
+ isyslog ("EEPG: Available sources:%s.", *cSource::ToString (AvailableSources[i]));
+
+#if APIVERSNUM > 10725
+ new cEEpgHandler();
+#endif
+ EquivHandler = new cEquivHandler();
+
+ if (ConfDir) {
+ free (ConfDir);
+ }
+ closedir(ConfigDir);
+ return true;
+}
+
+void cPluginEEPG::Stop (void)
+{
+ for (int i = 0; i < MAXDVBDEVICES; i++) {
+ cDevice *dev = epg[i].device;
+ if (dev)
+ dev->Detach (epg[i].filter);
+ delete epg[i].filter;
+ epg[i].device = 0;
+ epg[i].filter = 0;
+ }
+
+ // Clean up after yourself!
+// if (ConfDir) {
+// free (ConfDir);
+// }
+ if (sky_tables[0]) {
+ free(sky_tables[0]);
+ }
+ if (sky_tables[1]) {
+ free(sky_tables[1]);
+ }
+ if (EquivHandler) {
+ delete EquivHandler;
+ }
+
+}
+
+cMenuSetupPage *cPluginEEPG::SetupMenu (void)
+{
+ return new cMenuSetupPremiereEpg;
+}
+
+bool cPluginEEPG::SetupParse (const char *Name, const char *Value)
+{
+// LogF(0, "!!!! Dime test LogF");
+// LogF(0, "!!!! Dime test LogF %d", 2);
+// LogI(0, "!!!! Dime test LogI");
+// LogI(0, "!!!! Dime test LogI %d", 2);
+// LogI(0, prep2("!!!! Dime test prep"));
+// LogI(0, prep2("!!!! Dime test prep %d"), 2);
+// LogD(0, "!!!! Dime test LogD");
+// LogD(0, "!!!! Dime test LogD %d", 2);
+// LogE(0, "!!!! Dime test LogE");
+// LogE(0, "!!!! Dime test LogE %d", 2);
+
+
+ if (!strcasecmp (Name, "OptionPattern"))
+ SetupPE->OptPat = atoi (Value);
+ else if (!strcasecmp (Name, "OrderInfo"))
+ SetupPE->OrderInfo = atoi (Value);
+ else if (!strcasecmp (Name, "RatingInfo"))
+ SetupPE->RatingInfo = atoi (Value);
+ else if (!strcasecmp (Name, "FixEpg"))
+ SetupPE->FixEpg = atoi (Value);
+ else if (!strcasecmp (Name, "DisplayMessage"))
+ SetupPE->DisplayMessage = atoi (Value);
+#ifdef DEBUG
+ else if (!strcasecmp (Name, "LogLevel"))
+ SetupPE->LogLevel = atoi (Value);
+ else if (!strcasecmp (Name, "ProcessEIT"))
+ SetupPE->ProcessEIT = atoi (Value);
+#endif
+ else
+ return false;
+ return true;
+}
+
+VDRPLUGINCREATOR (cPluginEEPG); // Don't touch this!
diff --git a/eepg.equiv.IT b/eepg.equiv.IT
new file mode 100644
index 0000000..6c21282
--- /dev/null
+++ b/eepg.equiv.IT
@@ -0,0 +1,17 @@
+#
+# Simply add a list of the channels in this file with the following format:
+#
+# <OriginalChannelId> <OtherChannelId> <ChannelName>
+#
+
+S13.0E-64511-6700-11517 S13.0E-318-13000-14601 BBC Prime
+S13.0E-318-5200-3401 S19.2E-1-1024-9015 Rai Uno
+S13.0E-318-5200-3401 S13.0E-318-12400-8511 Rai Uno
+S13.0E-318-5200-3402 S13.0E-318-12400-8512 Rai Due
+S13.0E-318-5200-3403 S13.0E-318-12400-8513 Rai Tre
+S13.0E-272-6000-3 T-272-905-143 Rete 4
+S13.0E-272-6000-2 T-272-905-141 Canale 5
+S13.0E-272-6000-1 T-272-905-142 Italia 1
+S13.0E-64511-8600-11733 T-29-514-1 La 7
+S13.0E-64511-6700-11504 S13.0E-318-200-13831 Eurosport
+
diff --git a/eepg.h b/eepg.h
new file mode 100644
index 0000000..7e1cc74
--- /dev/null
+++ b/eepg.h
@@ -0,0 +1,7182 @@
+//#define DEBUG false
+//#define DEBUG_STARTTIME false
+
+#define MAX_THEMES 2046 //this should always be >=256, or Nagra will go wrong!!
+#define MAX_CHANNELS 2048
+#define MAX_TITLES 262144
+
+//#define MAX_EQUIVALENCES 8 //the number of equivalences one channel can have
+
+//Formats (need to be consecutively numbered):
+//#define PREMIERE 0
+//#define FREEVIEW 1
+//#define MHW1 2
+//#define MHW2 3
+//#define SKY_IT 4
+//#define SKY_UK 5
+//#define NAGRA 6
+//#define HIGHEST_FORMAT 6
+
+
+#define NAGRA_TABLE_ID 0x55 //the lower the table Id, the more "current" it is; table_id 0x00 never gets overwritten, now/next are at 0x4e or 0x4f!
+#define DEFAULT_TABLE_ID 0x30
+
+const char *FormatName[]= {"MediaHighWay 1","MediaHighWay 2","Sky Italy","Sky UK","NagraGuide","Premiere","FreeView","Dish/Bev","EIT"};
+
+struct sNode
+{
+ char *Value;
+ struct sNode *P0;
+ struct sNode *P1;
+};
+
+typedef struct sNode sNodeH;
+
+typedef struct
+{
+ unsigned short int ChannelId;
+ unsigned short int SkyNumber;
+ //unsigned short int NumberOfEquivalences;//original channel sets this value to 1, every equivalent channel adds 1
+ unsigned int Src;//[MAX_EQUIVALENCES];
+ unsigned short int Nid;//[MAX_EQUIVALENCES];
+ unsigned short int Tid;//[MAX_EQUIVALENCES];
+ unsigned short int Sid;//[MAX_EQUIVALENCES];
+ unsigned char Name[64];
+} sChannel;
+
+typedef struct {
+ unsigned short int ChannelId;
+ unsigned short int ThemeId;
+ unsigned short int MjdTime;
+ unsigned int EventId;//short is not sufficient for Nagra
+ unsigned int StartTime;
+ unsigned int Duration;
+ unsigned char SummaryAvailable;
+ unsigned char * Text;
+ unsigned char Unknown1;//FIXME
+ unsigned char Unknown2;//FIXME
+ unsigned char Unknown3;//FIXME
+ unsigned char Rating;
+ unsigned short int TableId;
+} Title_t;
+
+typedef struct {
+ unsigned short int ChannelId;
+ unsigned int StartTime;
+ unsigned short int MjdTime;
+} Replays_t;
+typedef struct {
+ Replays_t Replays[11]; //at the moment 10 is allowed, check why
+ unsigned int EventId;//short is not sufficient for Nagra
+ unsigned short int NumReplays;
+ unsigned char * Text;
+} Summary_t;
+
+
+// -- InheritEnum.h
+template <typename EnumT, typename BaseEnumT>
+class InheritEnum
+{
+public:
+ InheritEnum() {}
+ InheritEnum(EnumT e)
+ : enum_(e)
+ {}
+
+ InheritEnum(BaseEnumT e)
+ : baseEnum_(e)
+ {}
+
+ explicit InheritEnum( int val )
+ : enum_(static_cast<EnumT>(val))
+ {}
+
+ operator EnumT() const { return enum_; }
+private:
+ // Note - the value is declared as a union mainly for as a debugging aid. If
+ // the union is undesired and you have other methods of debugging, change it
+ // to either of EnumT and do a cast for the constructor that accepts BaseEnumT.
+ union
+ {
+ EnumT enum_;
+ BaseEnumT baseEnum_;
+ };
+};
+
+static const char *FileEquivalences[] = {
+ "#",
+ "# Simply add a list of the channels in this file with the following format:",
+ "#",
+ "# <OriginalChannelId> <OtherChannelId> <ChannelName>",
+ "#",
+ "",
+ "S13.0E-64511-6700-11517 S13.0E-318-13000-14601 BBC Prime",
+ "S13.0E-318-5200-3401 S19.2E-1-1024-9015 Rai Uno",
+ "S13.0E-318-5200-3401 S13.0E-318-12400-8511 Rai Uno",
+ "S13.0E-318-5200-3402 S13.0E-318-12400-8512 Rai Due",
+ "S13.0E-318-5200-3403 S13.0E-318-12400-8513 Rai Tre",
+ "S13.0E-272-6000-3 T-272-905-143 Rete 4",
+ "S13.0E-272-6000-2 T-272-905-141 Canale 5",
+ "S13.0E-272-6000-1 T-272-905-142 Italia 1",
+ "S13.0E-64511-8600-11733 T-29-514-1 La 7",
+ "S13.0E-64511-6700-11504 S13.0E-318-200-13831 Eurosport",
+ "",
+ NULL
+};
+
+static const char *SkyItDictionary[] = {
+ " =00001011010110001111010101010",
+ " =00001011010110001111010101011",
+ " =00001011010110001111010101100",
+ " =00001011010110001111010101101",
+ " =00001011010110001111010101110",
+ " =00001011010110001111010101111",
+ " =00001011010110001111010110000",
+ " =00001011010110001111010110001",
+ " =00001011010110001111010110010",
+ " =00001011010110001111010110011",
+ " =00001011010110001111010110100",
+ " =00001011010110001111010110101",
+ " =00001011010110001111010110110",
+ " =1001110",
+ " =00001011010110001111010110111",
+ " =00001011010110001111010111000",
+ " =00001011010110001111010111001",
+ " =00001011010110001111010111010",
+ " =00001011010110001111010111011",
+ " =00001011010110001111010111100",
+ " =00001011010110001111010111101",
+ " =00001011010110001111010111110",
+ " =00001011010110001111010111111",
+ " =00001011010110001111011000000",
+ " =00001011010110001111011000001",
+ " =00001011010110001111011000010",
+ " =00001011010110001111011000011",
+ " =00001011010110001111011000100",
+ " =00001011010110001111011000101",
+ " =00001011010110001111011000110",
+ " =00001011010110001111011000111",
+ " =00001011010110001111011001000",
+ " =01",
+ "!=1110000011101",
+ "\"=11100010000100011",
+ "#=00001011010110001111011001001",
+ "$=00001011010110001111011001010",
+ "%=00001011010110001111011001011",
+ "&=11100010000101",
+ "'=0000100",
+ "(=0000101101010",
+ ")=110100111111",
+ "*=00001011010110001111011001100",
+ "+=000010110101100011111",
+ ",=110000",
+ "-=10110011",
+ ".=100110",
+ "/=111000100001001",
+ "0=10010011",
+ "1=100100000",
+ "2=1111011001",
+ "3=1110001110",
+ "4=11000100101",
+ "5=111101110100",
+ "6=101100101111",
+ "7=110100011110",
+ "8=11010001110",
+ "9=1111010111",
+ ":=100100011",
+ ";=10000111101",
+ "<=00001011010110001111011001101",
+ "==00001011010110001111011001110",
+ ">=00001011010110001111011001111",
+ "?=1100110110110",
+ "@=1110001000010000",
+ "A=00001010",
+ "B=111101001",
+ "C=10010100",
+ "D=100001010",
+ "E=111000000",
+ "F=1110001100",
+ "G=100101100",
+ "H=1000011111",
+ "I=1111011111",
+ "J=1100010110",
+ "K=11110100011",
+ "L=001111101",
+ "M=100001101",
+ "N=100001011",
+ "O=1100101011",
+ "P=110100000",
+ "Q=00001011000",
+ "R=110010100",
+ "S=10110100",
+ "T=110101100",
+ "U=110100010011",
+ "V=1001000011",
+ "W=1101000110",
+ "X=1110001011001",
+ "Y=1100011110011",
+ "Z=1100010100110",
+ "[=00001011010110001111011010000",
+ "\\=00001011010110001111011010001",
+ "]=00001011010110001111011010010",
+ "^=0000101101011000100",
+ "_=00001011010110001111011010011",
+ "`=00001011010111",
+ "a=11111",
+ "b=11100001",
+ "c=111001",
+ "d=1011000",
+ "e=1010",
+ "f=0011011",
+ "g=000011",
+ "h=10110110",
+ "i=0001",
+ "j=110100010000",
+ "k=110001100",
+ "l=1111001",
+ "m=100010",
+ "n=10111",
+ "o=0010",
+ "p=100011",
+ "q=1110001001",
+ "r=11011",
+ "s=00000",
+ "t=11101",
+ "u=001110",
+ "v=1100111",
+ "w=001100110",
+ "x=11100011110",
+ "y=111101101",
+ "z=0011010",
+ "{=00001011010110001111011010100",
+ "|=00001011010110001111011010101",
+ "}=00001011010110001111011010110",
+ "~=00001011010110001111011010111",
+ " =00001011010110001111011011000",
+ " =000010110101100000",
+ " =00001011010110001111011011001",
+ " =00001011010110001111011011010",
+ " =00001011010110001111011011011",
+ " =00001011010110001111011011100",
+ " =00001011010110001111011011101",
+ " =00001011010110001111011011110",
+ " =00001011010110001111011011111",
+ " =11100010000100010",
+ " =000010110101100001",
+ " =00001011010110001111011100000",
+ " =00001011010110001111011100001",
+ " =00001011010110001111011100010",
+ " =00001011010110001111011100011",
+ " =00001011010110001111011100100",
+ " =00001011010110001111011100101",
+ " =00001011010110001111011100110",
+ " =00001011010110001111011100111",
+ " =00001011010110001110",
+ " =00001011010110001111011101000",
+ " =00001011010110001111011101001",
+ " =00001011010110001111011101010",
+ " =00001011010110001111011101011",
+ " =0000101101011000101",
+ " =00001011010110001111011101100",
+ " =00001011010110001111011101101",
+ " =00001011010110001111011101110",
+ " =00001011010110001111011101111",
+ " =00001011010110001111011110000",
+ " =00001011010110001111011110001",
+ " =00001011010110001111011110010",
+ " =00001011010110001111011110011",
+ " =00001011010110001111011110100",
+ "¡=00001011010110001111011110101",
+ "¢=00001011010110001111011110110",
+ "£=00001011010110001111011110111",
+ "¤=00001011010110001111011111000",
+ "¥=00001011010110001111011111001",
+ "¦=00001011010110001111011111010",
+ "§=00001011010110001111011111011",
+ "¨=00001011010110001111011111100",
+ "©=00001011010110001111011111101",
+ "ª=00001011010110001111011111110",
+ "«=00001011010110001111011111111",
+ "¬=0000101101011000111100000000",
+ "=0000101101011000111100000001",
+ "®=0000101101011000111100000010",
+ "¯=0000101101011000111100000011",
+ "°=0000101101011000111100000100",
+ "±=0000101101011000111100000101",
+ "²=0000101101011000111100000110",
+ "³=0000101101011000111100000111",
+ "´=0000101101011000111100001000",
+ "µ=0000101101011000111100001001",
+ "¶=0000101101011000111100001010",
+ "·=0000101101011001",
+ "¸=0000101101011000111100001011",
+ "¹=0000101101011000111100001100",
+ "º=0000101101011000111100001101",
+ "»=0000101101011000111100001110",
+ "¼=0000101101011000111100001111",
+ "½=0000101101011000111100010000",
+ "¾=0000101101011000111100010001",
+ "¿=0000101101011000111100010010",
+ "À=0000101101011000111100010011",
+ "Á=0000101101011000111100010100",
+ "Â=0000101101011000111100010101",
+ "Ã=0000101101011000111100010110",
+ "Ä=0000101101011000111100010111",
+ "Å=0000101101011000111100011000",
+ "Æ=000010110101101",
+ "Ç=0000101101011000111100011001",
+ "È=0000101101011000111100011010",
+ "É=0000101101011000111100011011",
+ "Ê=0000101101011000111100011100",
+ "Ë=0000101101011000111100011101",
+ "Ì=0000101101011000111100011110",
+ "Í=0000101101011000111100011111",
+ "Î=0000101101011000111100100000",
+ "Ï=0000101101011000111100100001",
+ "Ð=0000101101011000111100100010",
+ "Ñ=0000101101011000111100100011",
+ "Ò=0000101101011000111100100100",
+ "Ó=0000101101011000111100100101",
+ "Ô=0000101101011000111100100110",
+ "Õ=0000101101011000111100100111",
+ "Ö=0000101101011000111100101000",
+ "×=0000101101011000111100101001",
+ "Ø=0000101101011000111100101010",
+ "Ù=0000101101011000111100101011",
+ "Ú=0000101101011000111100101100",
+ "Û=0000101101011000111100101101",
+ "Ü=0000101101011000111100101110",
+ "Ý=0000101101011000111100101111",
+ "Þ=0000101101011000111100110000",
+ "ß=0000101101011000111100110001",
+ "à=0000101101011000110",
+ "á=0000101101011000111100110010",
+ "â=0000101101011000111100110011",
+ "ã=0000101101011000111100110100",
+ "ä=0000101101011000111100110101",
+ "å=0000101101011000111100110110",
+ "æ=0000101101011000111100110111",
+ "ç=0000101101011000111100111000",
+ "è=0000101101011000111100111001",
+ "é=0000101101011000111100111010",
+ "ê=0000101101011000111100111011",
+ "ë=0000101101011000111100111100",
+ "ì=0000101101011000111100111101",
+ "í=0000101101011000111100111110",
+ "î=0000101101011000111100111111",
+ "ï=0000101101011000111101000000",
+ "ð=0000101101011000111101000001",
+ "ñ=0000101101011000111101000010",
+ "ò=0000101101011000111101000011",
+ "ó=0000101101011000111101000100",
+ "ô=0000101101011000111101000101",
+ "õ=0000101101011000111101000110",
+ "ö=0000101101011000111101000111",
+ "÷=0000101101011000111101001000",
+ "ø=0000101101011000111101001001",
+ "ù=0000101101011000111101001010",
+ "ú=0000101101011000111101001011",
+ "û=0000101101011000111101001100",
+ "ü=0000101101011000111101001101",
+ "ý=0000101101011000111101001110",
+ "þ=0000101101011000111101001111",
+ "ÿ=0000101101011000111101010000",
+ "(dur=100001111000",
+ "2001=001111100",
+ "2002=111000110101",
+ "Adulti=100001111001",
+ "Alle=1100110111",
+ "American=10110101100",
+ "Argentina=110010101011",
+ "Attualita'=110001000001",
+ "Bateman=10010111111",
+ "Bechis=1100010111011",
+ "Campionato=1101001111000",
+ "Carlos=1101000011101",
+ "Cartoon=11110111011",
+ "Club=10000110010",
+ "Commedia=100001100001",
+ "Con=10110101101",
+ "D'Alo'=1100100011111",
+ "Da=1001010111",
+ "Dal=1111010100011",
+ "Dalle=10010111110",
+ "Drammatico=111101111001",
+ "Durante=1101000111110",
+ "Echeverria=1100011100110",
+ "Emmanuelle=1100011100111",
+ "Enzo=1101000100010",
+ "Fares=00001011011",
+ "Figli=1100100011000",
+ "Film=1101011010",
+ "Fine=100001001100",
+ "Fiumi=00001011100",
+ "Francia=10000110001",
+ "Giallo=110001001000",
+ "Giovanni=1100011101000",
+ "Harron=10011110000",
+ "ITV=1101000100100",
+ "Il=0011001110",
+ "In=1001011011",
+ "Informazione=11110100001",
+ "Intrattenimento=1000010000",
+ "Italia=11100010001",
+ "Javier=1100011101001",
+ "Jean=10010101011",
+ "John=1111011100101",
+ "Kassovitz=00110000101",
+ "L'appassionante=00001011101",
+ "La=1001010110",
+ "Le=11000100111",
+ "Ma=1101001110",
+ "Magazine=100001110010",
+ "Mammuccari=1100011101010",
+ "Manhattan=10110010010",
+ "Marco=1110001011110",
+ "Mary=10011110110",
+ "Mathieu=00110000110",
+ "Michael=1101001111011",
+ "Momo=110010001011",
+ "Nadia=00001011110",
+ "News=110100111110",
+ "Notiziario=101100101110",
+ "Orario=1001000100",
+ "Patrick=10110010110",
+ "Paul=000010110011",
+ "Per=11000100110",
+ "Peter=1100101010101",
+ "Programmazione=1110001101001",
+ "Psycho=10011110111",
+ "Regia=110010000",
+ "Reno=00110000111",
+ "Rosa=1100011110101",
+ "Rubrica=1111011100100",
+ "Sandrelli=1100100010001",
+ "Seigner=1100011101011",
+ "Servizi=001100000110",
+ "Snow=100100001000",
+ "Sorvino=1100011110110",
+ "Stefania=1101011011010",
+ "Stream=111101000100",
+ "Street=10110101111",
+ "Streghe=1100011101100",
+ "TRAMA:=1100010111010",
+ "Teo=110001110010",
+ "USA=1101000101",
+ "Un=11110111101",
+ "Una=101100100010",
+ "Veronesi=1100011101101",
+ "Vincent=00110001001",
+ "Wall=11000100001",
+ "World=001100010110",
+ "XXX=10000110011",
+ "ad=1111010110",
+ "affidare=00110000100",
+ "ai=1001011110",
+ "al=0011110",
+ "alla=11010110111",
+ "alle=111101110101",
+ "amici=111000101110",
+ "ammazzare=10011110001",
+ "and=1111010101",
+ "anfiteatro=1100100011001",
+ "anni=10010101010",
+ "as=110011010",
+ "attraverso=1101011011001",
+ "aver=000010110100",
+ "bambina=1101000100011",
+ "banda=1110001011000",
+ "bello=10110101000",
+ "brani=1100100010010",
+ "broker=10011110010",
+ "business=000010110010",
+ "casa=101100100011",
+ "casi=10000111010",
+ "cassel=00001011111",
+ "cerca=11100010100",
+ "che=10010010",
+ "chilometri=00110001111",
+ "citta'=110001000101",
+ "come=110001011100",
+ "compagnia=1100110110001",
+ "con=11010010",
+ "conquista=1101000111111",
+ "contro=110001000100",
+ "crede=1110001111110",
+ "cui=001100111110",
+ "cultura=100001110001",
+ "curiosita'=001100010111",
+ "da=00110010",
+ "dai=1101000100101",
+ "dal=11110110000",
+ "dalla=100101101001",
+ "decidG266 : dedicato=0000101101011000111101010001",
+ "degli=110001000000",
+ "dei=0011000110",
+ "del=111100010",
+ "della=1011001010",
+ "delle=11000111000",
+ "destra=1100101010001",
+ "deve=1111010001011",
+ "di=100000",
+ "diabolici=1100100011010",
+ "dice=1100110110000",
+ "diretta=100100001011",
+ "distanza=00110000000",
+ "divide=10110010011",
+ "divisi=1100011101110",
+ "dolce=1101001111001",
+ "domani=1111010100010",
+ "due=1100011111",
+ "e'=110001101",
+ "ed=101101111",
+ "essere=1110001000000",
+ "esseri=1110001111101",
+ "eventiG=0000101101011000111101010010",
+ "fatti=001100111111",
+ "feste=10110101001",
+ "film=10000100011",
+ "gemelli=1110001000011",
+ "giorno=11110100000",
+ "giovane=11100000110",
+ "giovani=1111011110001",
+ "gli=100101110",
+ "grande=1110001011111",
+ "grandi=1111010001010",
+ "grigi'=1100100011011",
+ "ha=1100010101",
+ "il=11001011",
+ "imbattere=1100100011100",
+ "in=1101010",
+ "incinta=1100101010000",
+ "informazione=110001001001",
+ "inizio=1001010100",
+ "internazionale=100001110111",
+ "interviste=100100001001",
+ "la=11001100",
+ "lavoro=11010000110",
+ "le=11010111",
+ "levatrice=1100011101111",
+ "libro=1100011110100",
+ "lo=111100011",
+ "loro=11000101000",
+ "ma=10011111",
+ "maggiori=100001110110",
+ "malcapitati=10110010000",
+ "maschietto=1100011110000",
+ "mondo=11100010101",
+ "musica=111000001111",
+ "nato=111101110011",
+ "nel=11110111000",
+ "nella=1111010100000",
+ "nello=10000100100",
+ "news=10010110101",
+ "non=00110011110",
+ "nord=1100100011101",
+ "nuovi=001100000111",
+ "of=1011010101",
+ "ogni=100001110011",
+ "ore=1101000010",
+ "parte=1101011011011",
+ "per=00111111",
+ "piccola=1101001111010",
+ "piu'=1001111010",
+ "poliziotti=00110001110",
+ "porpora=00110000001",
+ "prima=1110001111100",
+ "produttore=1100011110111",
+ "programmazione=1110001101000",
+ "proprio=1101011011000",
+ "prossimo=1001000101",
+ "quattro=1111011000110",
+ "regime=1100011110001",
+ "ricco=10110101110",
+ "ricordi=1100101010100",
+ "rovine=1110001000001",
+ "salvare=1110000011100",
+ "scrittore=1100110110111",
+ "scrive=1101000011110",
+ "serie=1111011000111",
+ "servizi=100001110000",
+ "settimanale=1100010100111",
+ "si=11110000",
+ "singolari=00110001000",
+ "solo=110010001010",
+ "sono=11000100011",
+ "stesso=10000100010",
+ "storia=11100011011",
+ "streghe=1100100010000",
+ "su=1110000010",
+ "sua=10000100101",
+ "successo=100101101000",
+ "sui=110011011001",
+ "sulle=100100001010",
+ "suo=10000100111",
+ "suoi=1101000011100",
+ "tale=110010101001",
+ "tempo=111101100010",
+ "the=11110101001",
+ "timida=1100100011110",
+ "torturare=10011110011",
+ "tra=110100110",
+ "trasformarlo=1100011110010",
+ "trecento=00110000010",
+ "trovato=1101000011111",
+ "tutto=110011011010",
+ "ultimi=1100100010011",
+ "un=11001001",
+ "una=101101110",
+ "uno=111000101101",
+ "uomini=1111011110000",
+ "vedono=00110001010",
+ "vengono=100001001101",
+ "verso=100001100000",
+ "viaggio=110001010010",
+ "viene=1111010100001",
+ "vita=11000101111",
+ "vuole=1110001111111",
+ NULL
+};
+
+static const char *SkyUkDictionary[] = {
+ " =101010111000110000101001100",
+ " =101010111000110000101001101",
+ " =101010111000110000101001110",
+ " =101010111000110000101001111",
+ " =101010111000110000101010000",
+ " =101010111000110000101010001",
+ " =101010111000110000101010010",
+ " =101010111000110000101010011",
+ " =101010111000110000101010100",
+ " =0001000",
+ " =1110111",
+ " =101010111000110000101010101",
+ " =101010111000110000101010110",
+ " =101010111000110000101010111",
+ " =101010111000110000101011000",
+ " =101010111000110000101011001",
+ " =101010111000110000101011010",
+ " =101010111000110000101011011",
+ " =101010111000110000101011100",
+ " =101010111000110000101011101",
+ " =101010111000110000101011110",
+ " =101010111000110000101011111",
+ " =101010111000110000101100000",
+ " =101010111000110000101100001",
+ " =101010111000110000101100010",
+ " =101010111000110000101100011",
+ " =101010111000110000101100100",
+ " =101010111000110000101100101",
+ " =101010111000110000101100110",
+ " =101010111000110000101100111",
+ " =101010111000110000101101000",
+ " =101010111000110000101101001",
+ " =110",
+ "!=01000011000",
+ "\"=101010111000110000101101010",
+ "#=101010111000110000101101011",
+ "$=1010101110001101",
+ "%=101010111000110000101101100",
+ "&=10000011101",
+ "'=10000010",
+ "(=11101000101",
+ ")=1010101100",
+ "*=100010101110",
+ "+=101010111000110000101101101",
+ ",=1011000",
+ "-=10001011",
+ ".=1110110",
+ "/=00010100011110",
+ "0=111010010",
+ "1=101100111",
+ "2=1000101000",
+ "3=1000001111",
+ "4=0001010000",
+ "5=1110101000",
+ "6=1000101001",
+ "7=1000100010",
+ "8=10001010110",
+ "9=0100001101",
+ ":=11101000110",
+ ";=00010100010",
+ "<=1110100011111",
+ "==101010111000110000101101110",
+ ">=1110101001100",
+ "?=111010100111",
+ "@=101010111000110001",
+ "A=11100010",
+ "B=01000000",
+ "C=01000010",
+ "D=111000111",
+ "E=1110100000",
+ "F=101010100",
+ "G=100010000",
+ "H=101010101",
+ "I=1110100001",
+ "J=000101001",
+ "K=1110100111",
+ "L=100000110",
+ "M=10001001",
+ "N=111010111",
+ "O=010000010",
+ "P=00010101",
+ "Q=1000101010111",
+ "R=111010110",
+ "S=0001001",
+ "T=0001011",
+ "U=10101011101",
+ "V=11101010101",
+ "W=10110010",
+ "X=1110001101101111",
+ "Y=10101011110",
+ "Z=1110101010000",
+ "[=10101011100011001",
+ "\\=101010111000110000101101111",
+ "]=11100011011011100",
+ "^=101010111000110000101110000",
+ "_=101010111000110000101110001",
+ "`=11101010010",
+ "a=1001",
+ "b=1110000",
+ "c=111001",
+ "d=01001",
+ "e=1111",
+ "f=100001",
+ "g=100011",
+ "h=10111",
+ "i=0101",
+ "j=11100011010",
+ "k=1000000",
+ "l=10100",
+ "m=101011",
+ "n=0111",
+ "o=0011",
+ "p=000111",
+ "q=10101011011",
+ "r=0010",
+ "s=0000",
+ "t=0110",
+ "u=101101",
+ "v=1010100",
+ "w=000110",
+ "x=1110101011",
+ "y=010001",
+ "z=1011001100",
+ "{=101010111000110000101110010",
+ "|=101010111000110000101110011",
+ "}=101010111000110000101110100",
+ "~=101010111000110000101110101",
+ " =101010111000110000101110110",
+ " =101010111000110000101110111",
+ " =101010111000110000101111000",
+ " =101010111000110000101111001",
+ " =101010111000110000101111010",
+ " =101010111000110000101111011",
+ " =101010111000110000101111100",
+ " =101010111000110000101111101",
+ " =101010111000110000101111110",
+ " =101010111000110000101111111",
+ " =101010111000110000110000000",
+ " =101010111000110000110000001",
+ " =101010111000110000110000010",
+ " =101010111000110000110000011",
+ " =101010111000110000110000100",
+ " =101010111000110000110000101",
+ " =101010111000110000110000110",
+ " =101010111000110000110000111",
+ " =101010111000110000110001000",
+ " =101010111000110000110001001",
+ " =101010111000110000110001010",
+ " =101010111000110000110001011",
+ " =101010111000110000110001100",
+ " =101010111000110000110001101",
+ " =101010111000110000110001110",
+ " =101010111000110000110001111",
+ " =101010111000110000110010000",
+ " =101010111000110000110010001",
+ " =101010111000110000110010010",
+ " =11100011011011101",
+ " =101010111000110000110010011",
+ " =101010111000110000110010100",
+ " =101010111000110000110010101",
+ " =101010111000110000110010110",
+ "¡=101010111000110000110010111",
+ "¢=101010111000110000110011000",
+ "£=101010111000110000110011001",
+ "¤=101010111000110000110011010",
+ "¥=101010111000110000110011011",
+ "¦=101010111000110000110011100",
+ "§=101010111000110000110011101",
+ "¨=101010111000110000110011110",
+ "©=101010111000110000110011111",
+ "ª=101010111000110000110100000",
+ "«=101010111000110000110100001",
+ "¬=101010111000110000110100010",
+ "=101010111000110000110100011",
+ "®=101010111000110000110100100",
+ "¯=101010111000110000110100101",
+ "°=101010111000110000110100110",
+ "±=101010111000110000110100111",
+ "²=101010111000110000110101000",
+ "³=101010111000110000110101001",
+ "´=101010111000110000110101010",
+ "µ=101010111000110000110101011",
+ "¶=101010111000110000110101100",
+ "·=101010111000110000110101101",
+ "¸=101010111000110000110101110",
+ "¹=101010111000110000110101111",
+ "º=101010111000110000110110000",
+ "»=101010111000110000110110001",
+ "¼=101010111000110000110110010",
+ "½=101010111000110000110110011",
+ "¾=101010111000110000110110100",
+ "¿=101010111000110000110110101",
+ "À=101010111000110000110110110",
+ "Á=101010111000110000110110111",
+ "Â=101010111000110000110111000",
+ "Ã=101010111000110000110111001",
+ "Ä=101010111000110000110111010",
+ "Å=101010111000110000110111011",
+ "Æ=101010111000110000110111100",
+ "Ç=101010111000110000110111101",
+ "È=101010111000110000110111110",
+ "É=101010111000110000110111111",
+ "Ê=101010111000110000111000000",
+ "Ë=101010111000110000111000001",
+ "Ì=101010111000110000111000010",
+ "Í=101010111000110000111000011",
+ "Î=101010111000110000111000100",
+ "Ï=101010111000110000111000101",
+ "Ð=101010111000110000111000110",
+ "Ñ=101010111000110000111000111",
+ "Ò=101010111000110000111001000",
+ "Ó=101010111000110000111001001",
+ "Ô=101010111000110000111001010",
+ "Õ=101010111000110000111001011",
+ "Ö=101010111000110000111001100",
+ "×=101010111000110000111001101",
+ "Ø=101010111000110000111001110",
+ "Ù=101010111000110000111001111",
+ "Ú=101010111000110000111010000",
+ "Û=101010111000110000111010001",
+ "Ü=101010111000110000111010010",
+ "Ý=101010111000110000111010011",
+ "Þ=101010111000110000111010100",
+ "ß=101010111000110000111010101",
+ "à=101010111000110000111010110",
+ "á=101010111000110000111010111",
+ "â=101010111000110000111011000",
+ "ã=101010111000110000111011001",
+ "ä=101010111000110000111011010",
+ "å=101010111000110000111011011",
+ "æ=101010111000110000111011100",
+ "ç=101010111000110000111011101",
+ "è=101010111000110000111011110",
+ "é=101010111000110000111011111",
+ "ê=101010111000110000111100000",
+ "ë=101010111000110000111100001",
+ "ì=101010111000110000111100010",
+ "í=101010111000110000111100011",
+ "î=101010111000110000111100100",
+ "ï=101010111000110000111100101",
+ "ð=101010111000110000111100110",
+ "ñ=101010111000110000111100111",
+ "ò=101010111000110000111101000",
+ "ó=101010111000110000111101001",
+ "ô=101010111000110000111101010",
+ "õ=101010111000110000111101011",
+ "ö=101010111000110000111101100",
+ "÷=101010111000110000111101101",
+ "ø=101010111000110000111101110",
+ "ù=101010111000110000111101111",
+ "ú=101010111000110000111110000",
+ "û=101010111000110000111110001",
+ "ü=101010111000110000111110010",
+ "ý=101010111000110000111110011",
+ "þ=101010111000110000111110100",
+ "ÿ=101010111000110000111110101",
+ "(Including =10101011111110",
+ "(New Series)=11101000100010",
+ "(Part =1110100011101",
+ "(Repeat)=1110100110",
+ "(Stereo)=010000111",
+ "(Stereo) (Teletext)=010000011",
+ "(Teletext)=1110001100",
+ "(Widescreen)=100000111001110",
+ "Action=101010111000111",
+ "Adventures=10110011011111",
+ "America=0100001100100",
+ "Animated=111010100110111",
+ "Australia=0100001100101",
+ "Away=11101010100010",
+ "BBC=10101011111111",
+ "Baby=11100011011000",
+ "Best=11101010100011",
+ "Big=10110011011000",
+ "Bill=1000101011111",
+ "Black=1000101010000",
+ "Blue=1011001101110",
+ "Breakfast=000101000110",
+ "Britain=1010101111100",
+ "British=1110100011100",
+ "Business=0100001100110",
+ "Call=1010101111101",
+ "Cartoon=10101011100000",
+ "Channel=10101011100001",
+ "Children=11101010100111",
+ "Clock=11100011011001",
+ "Comedy=11101000100011",
+ "Cook=111010101001010",
+ "Country=111010100110110",
+ "Directed by =101010110100",
+ "Drama=0100001100111",
+ "East=1000101010001",
+ "Education=100000111001111",
+ "English=00010100011111",
+ "Europe=0001010001110",
+ "Extra=10110011011001",
+ "Final=10101011100010",
+ "Financial=111000110110100",
+ "For=111000110111",
+ "French=11101000111101",
+ "From=1000101010010",
+ "George=1010101111110",
+ "Get=1000100011010",
+ "Girls=10001000110110",
+ "Golden=10001000110111",
+ "Golf=111010101001011",
+ "Good=1010101101010",
+ "Great=11101000100100",
+ "Hampshire=111010101001100",
+ "Headlines=1000101010011",
+ "Hear=11101010011010",
+ "Hill=1000001110000",
+ "Hollywood=111000110110101",
+ "Home=1000101010100",
+ "Hour=11101000100101",
+ "House=1000001110010",
+ "How=1010101101011",
+ "ITN=11101010100100",
+ "Important=111010101001101",
+ "Including=1000101011110",
+ "International=11101000100110",
+ "John=10001000111",
+ "Last=11101000100111",
+ "Late=10000011100110",
+ "Learn=10001010101100",
+ "Little=10001010101101",
+ "Live=1110100010000",
+ "London=11101000111100",
+ "Look=10110011011110",
+ "Lunch=111000110110110",
+ "Man=1000101010101",
+ "Mark=1000001110001",
+ "Meridian=101010111001",
+ "Michael=1011001101101",
+ "Minutes=101010111000110000111110110",
+ "More=101010111000110000111110111",
+ "Morning=101010111000110000111111000",
+ "Murder=101010111000110000111111001",
+ "Nation=101010111000110000111111010",
+ "Neighbours=101010111000110000111111011",
+ "New=101010111000110000111111100",
+ "News & Weather=101010111000110000111111101",
+ "News And Weather=101010111000110000111111110",
+ "Paul=101010111000110000111111111",
+ "Plus=10101011100011000000000000",
+ "Prayer=10101011100011000000000001",
+ "Present=10101011100011000000000010",
+ "Presented by=10101011100011000000000011",
+ "Quiz=10101011100011000000000100",
+ "Regional=10101011100011000000000101",
+ "Represent=10101011100011000000000110",
+ "Resource=10101011100011000000000111",
+ "Review=10101011100011000000001000",
+ "Richard=10101011100011000000001001",
+ "School=10101011100011000000001010",
+ "Series=10101011100011000000001011",
+ "Service=10101011100011000000001100",
+ "Show=10101011100011000000001101",
+ "Smith=10101011100011000000001110",
+ "South=10101011100011000000001111",
+ "Sport=10101011100011000000010000",
+ "Star=10101011100011000000010001",
+ "Street=10101011100011000000010010",
+ "TV=10101011100011000000010011",
+ "Teaching=10101011100011000000010100",
+ "The=10101011100011000000010101",
+ "Today=10101011100011000000010110",
+ "Tonight=10101011100011000000010111",
+ "Weather=10101011100011000000011000",
+ "Western=10101011100011000000011001",
+ "Westminster=10101011100011000000011010",
+ "William=10101011100011000000011011",
+ "With=10101011100011000000011100",
+ "World=10101011100011000000011101",
+ "about=10101011100011000000011110",
+ "action-packed=10101011100011000000011111",
+ "adventure=10101011100011000000100000",
+ "afternoon=10101011100011000000100001",
+ "alert=10101011100011000000100010",
+ "all-star cast=10101011100011000000100011",
+ "and=10101011100011000000100100",
+ "anywhere=10101011100011000000100101",
+ "audience=10101011100011000000100110",
+ "based=10101011100011000000100111",
+ "book=10101011100011000000101000",
+ "business=10101011100011000000101001",
+ "but=10101011100011000000101010",
+ "celebrity=10101011100011000000101011",
+ "chance=10101011100011000000101100",
+ "chat=10101011100011000000101101",
+ "child=10101011100011000000101110",
+ "classic=10101011100011000000101111",
+ "consumer=10101011100011000000110000",
+ "contestants=10101011100011000000110001",
+ "continues=10101011100011000000110010",
+ "controversial=10101011100011000000110011",
+ "dealer=10101011100011000000110100",
+ "deliver=10101011100011000000110101",
+ "discuss=10101011100011000000110110",
+ "document=10101011100011000000110111",
+ "drama=10101011100011000000111000",
+ "edition=10101011100011000000111001",
+ "education=10101011100011000000111010",
+ "events=10101011100011000000111011",
+ "every=10101011100011000000111100",
+ "excellent=10101011100011000000111101",
+ "eyed=10101011100011000000111110",
+ "family=10101011100011000000111111",
+ "famous=10101011100011000001000000",
+ "featur=10101011100011000001000001",
+ "film=10101011100011000001000010",
+ "football=10101011100011000001000011",
+ "for=10101011100011000001000100",
+ "from=10101011100011000001000101",
+ "general knowledge=10101011100011000001000110",
+ "get=10101011100011000001000111",
+ "guest=10101011100011000001001000",
+ "guests=10101011100011000001001001",
+ "has=10101011100011000001001010",
+ "have=10101011100011000001001011",
+ "headline=10101011100011000001001100",
+ "her=10101011100011000001001101",
+ "his=10101011100011000001001110",
+ "home and abroad=10101011100011000001001111",
+ "host=10101011100011000001010000",
+ "how=10101011100011000001010001",
+ "in=10101011100011000001010010",
+ "including=10101011100011000001010011",
+ "international=10101011100011000001010100",
+ "interview=10101011100011000001010101",
+ "introduce=10101011100011000001010110",
+ "investigat=10101011100011000001010111",
+ "invites=10101011100011000001011000",
+ "issue=10101011100011000001011001",
+ "knowledge=10101011100011000001011010",
+ "life=10101011100011000001011011",
+ "live=10101011100011000001011100",
+ "look=10101011100011000001011101",
+ "magazine=10101011100011000001011110",
+ "meets =10101011100011000001011111",
+ "morning=10101011100011000001100000",
+ "morning magazine=10101011100011000001100001",
+ "music=10101011100011000001100010",
+ "near=10101011100011000001100011",
+ "network=10101011100011000001100100",
+ "new=10101011100011000001100101",
+ "new series=10101011100011000001100110",
+ "night=10101011100011000001100111",
+ "of=10101011100011000001101000",
+ "on=10101011100011000001101001",
+ "onight=10101011100011000001101010",
+ "out=10101011100011000001101011",
+ "over=10101011100011000001101100",
+ "part=10101011100011000001101101",
+ "people=10101011100011000001101110",
+ "phone=10101011100011000001101111",
+ "poli=10101011100011000001110000",
+ "police=10101011100011000001110001",
+ "political chat show=10101011100011000001110010",
+ "popular=10101011100011000001110011",
+ "presented by =10101011100011000001110100",
+ "programm=10101011100011000001110101",
+ "quiz=10101011100011000001110110",
+ "reconstruction=10101011100011000001110111",
+ "report=10101011100011000001111000",
+ "review=10101011100011000001111001",
+ "school=10101011100011000001111010",
+ "series=10101011100011000001111011",
+ "short =10101011100011000001111100",
+ "show=10101011100011000001111101",
+ "some=10101011100011000001111110",
+ "starring=10101011100011000001111111",
+ "stars=10101011100011000010000000",
+ "stories=10101011100011000010000001",
+ "story=10101011100011000010000010",
+ "studio=10101011100011000010000011",
+ "surprise=10101011100011000010000100",
+ "teller=10101011100011000010000101",
+ "that=10101011100011000010000110",
+ "the=10101011100011000010000111",
+ "their=10101011100011000010001000",
+ "them=10101011100011000010001001",
+ "they=10101011100011000010001010",
+ "this=10101011100011000010001011",
+ "through=10101011100011000010001100",
+ "to=10101011100011000010001101",
+ "top=10101011100011000010001110",
+ "trans=10101011100011000010001111",
+ "under=10101011100011000010010000",
+ "up=10101011100011000010010001",
+ "very=10101011100011000010010010",
+ "video=10101011100011000010010011",
+ "view=10101011100011000010010100",
+ "vintage=10101011100011000010010101",
+ "visit=10101011100011000010010110",
+ "was=10101011100011000010010111",
+ "way=10101011100011000010011000",
+ "week=10101011100011000010011001",
+ "well=10101011100011000010011010",
+ "what=10101011100011000010011011",
+ "when=10101011100011000010011100",
+ "which=10101011100011000010011101",
+ "while=10101011100011000010011110",
+ "who=10101011100011000010011111",
+ "will=10101011100011000010100000",
+ "win=10101011100011000010100001",
+ "with=10101011100011000010100010",
+ "words=10101011100011000010100011",
+ "world=10101011100011000010100100",
+ "written=10101011100011000010100101",
+ "year=100010001100",
+ "you=10110011010",
+ NULL
+};
+
+static const char *SkyItThemes[] = {
+ "Non Definito", // 000 00000
+ NULL, // 000 00001
+ NULL, // 000 00010
+ NULL, // 000 00011
+ NULL, // 000 00100
+ NULL, // 000 00101
+ NULL, // 000 00110
+ NULL, // 000 00111
+ NULL, // 000 01000
+ NULL, // 000 01001
+ NULL, // 000 01010
+ NULL, // 000 01011
+ NULL, // 000 01100
+ NULL, // 000 01101
+ NULL, // 000 01110
+ NULL, // 000 01111
+ NULL, // 000 10000
+ NULL, // 000 10001
+ NULL, // 000 10010
+ NULL, // 000 10011
+ NULL, // 000 10100
+ NULL, // 000 10101
+ NULL, // 000 10110
+ NULL, // 000 10111
+ NULL, // 000 11000
+ NULL, // 000 11001
+ NULL, // 000 11010
+ NULL, // 000 11011
+ NULL, // 000 11100
+ NULL, // 000 11101
+ NULL, // 000 11110
+ NULL, // 000 11111
+ "Intrattenimento", // 001 00000
+ "Intrattenimento - Fiction", // 001 00001
+ "Intrattenimento - Sit Com", // 001 00010
+ "Intrattenimento - Show", // 001 00011
+ "Intrattenimento - Telefilm", // 001 00100
+ "Intrattenimento - Soap Opera", // 001 00101
+ "Intrattenimento - Telenovela", // 001 00110
+ "Intrattenimento - Fantascienza", // 001 00111
+ "Intrattenimento - Animazione", // 001 01000
+ "Intrattenimento - Giallo", // 001 01001
+ "Intrattenimento - Drammatico", // 001 01010
+ "Intrattenimento - Romantico", // 001 01011
+ "Intrattenimento - Miniserie", // 001 01100
+ "Intrattenimento - Spettacolo", // 001 01101
+ "Intrattenimento - Quiz", // 001 01110
+ "Intrattenimento - Talk Show", // 001 01111
+ "Intrattenimento - Varietà", // 001 10000
+ "Intrattenimento - Festival", // 001 10001
+ "Intrattenimento - Teatro", // 001 10010
+ "Intrattenimento - Gioco", // 001 10011
+ NULL, // 001 10100
+ NULL, // 001 10101
+ NULL, // 001 10110
+ NULL, // 001 10111
+ NULL, // 001 11000
+ NULL, // 001 11001
+ NULL, // 001 11010
+ NULL, // 001 11011
+ NULL, // 001 11100
+ NULL, // 001 11101
+ NULL, // 001 11110
+ NULL, // 001 11111
+ "Sport", // 010 00000
+ "Sport - Calcio", // 010 00001
+ "Sport - Tennis", // 010 00010
+ "Sport - Motori", // 010 00011
+ "Sport - Altri", // 010 00100
+ "Sport - Baseball", // 010 00101
+ "Sport - Ciclismo", // 010 00110
+ "Sport - Rugby", // 010 00111
+ "Sport - Basket", // 010 01000
+ "Sport - Boxe", // 010 01001
+ "Sport - Atletica", // 010 01010
+ "Sport - Football USA", // 010 01011
+ "Sport - Hockey", // 010 01100
+ "Sport - Sci", // 010 01101
+ "Sport - Equestri", // 010 01110
+ "Sport - Golf", // 010 01111
+ "Sport - Nuoto", // 010 10000
+ "Sport - Wrestling", // 010 10001
+ NULL, // 010 10010
+ NULL, // 010 10011
+ NULL, // 010 10100
+ NULL, // 010 10101
+ NULL, // 010 10110
+ NULL, // 010 10111
+ NULL, // 010 11000
+ NULL, // 010 11001
+ NULL, // 010 11010
+ NULL, // 010 11011
+ NULL, // 010 11100
+ NULL, // 010 11101
+ NULL, // 010 11110
+ NULL, // 010 11111
+ "Film", // 011 00000
+ "Film - Drammatico", // 011 00001
+ "Film - Commedia", // 011 00010
+ "Film - Romantico", // 011 00011
+ "Film - Azione", // 011 00100
+ "Film - Fantascienza", // 011 00101
+ "Film - Western", // 011 00110
+ "Film - Comico", // 011 00111
+ "Film - Fantastico", // 011 01000
+ "Film - Avventura", // 011 01001
+ "Film - Poliziesco", // 011 01010
+ "Film - Guerra", // 011 01011
+ "Film - Horror", // 011 01100
+ "Film - Animazione", // 011 01101
+ "Film - Thriller", // 011 01110
+ "Film - Musicale", // 011 01111
+ "Film - Corto", // 011 10000
+ "Film - Cortometraggio", // 011 10001
+ NULL, // 011 10010
+ NULL, // 011 10011
+ NULL, // 011 10100
+ NULL, // 011 10101
+ NULL, // 011 10110
+ NULL, // 011 10111
+ NULL, // 011 11000
+ NULL, // 011 11001
+ NULL, // 011 11010
+ NULL, // 011 11011
+ NULL, // 011 11100
+ NULL, // 011 11101
+ NULL, // 011 11110
+ NULL, // 011 11111
+ "Mondo e Tendenze", // 100 00000
+ "Mondo e Tendenze - Natura", // 100 00001
+ "Mondo e Tendenze - Arte e Cultura", // 100 00010
+ "Mondo e Tendenze - Lifestyle", // 100 00011
+ "Mondo e Tendenze - Viaggi", // 100 00100
+ "Mondo e Tendenze - Documentario", // 100 00101
+ "Mondo e Tendenze - Società", // 100 00110
+ "Mondo e Tendenze - Scienza", // 100 00111
+ "Mondo e Tendenze - Storia", // 100 01000
+ "Mondo e Tendenze - Sport", // 100 01001
+ "Mondo e Tendenze - Pesca", // 100 01010
+ "Mondo e Tendenze - Popoli", // 100 01011
+ "Mondo e Tendenze - Cinema", // 100 01100
+ "Mondo e Tendenze - Musica", // 100 01101
+ "Mondo e Tendenze - Hobby", // 100 01110
+ "Mondo e Tendenze - Caccia", // 100 01111
+ "Mondo e Tendenze - Reportage", // 100 10000
+ "Mondo e Tendenze - Magazine", // 100 10001
+ "Mondo e Tendenze - Magazine Cultura", // 100 10010
+ "Mondo e Tendenze - Magazine Scienza", // 100 10011
+ "Mondo e Tendenze - Politica", // 100 10100
+ "Mondo e Tendenze - Magazine Cinema", // 100 10101
+ "Mondo e Tendenze - Magazine Sport", // 100 10110
+ "Mondo e Tendenze - Attualità", // 100 10111
+ "Mondo e Tendenze - Moda", // 100 11000
+ "Mondo e Tendenze - Economia", // 100 11001
+ "Mondo e Tendenze - Magazine Caccia e Pesca", // 100 11010
+ "Mondo e Tendenze - Magazine Viaggi", // 100 11011
+ "Mondo e Tendenze - Magazine Natura", // 100 11100
+ "Mondo e Tendenze - Magazine Musica", // 100 11101
+ "Mondo e Tendenze - Religione", // 100 11110
+ "Mondo e Tendenze - Televendita", // 100 11111
+ "Informazione", // 101 00000
+ "Informazione - Notiziario", // 101 00001
+ "Informazione - Sport", // 101 00010
+ "Informazione - Economia", // 101 00011
+ NULL, // 101 00100
+ NULL, // 101 00101
+ NULL, // 101 00110
+ NULL, // 101 00111
+ NULL, // 101 01000
+ NULL, // 101 01001
+ NULL, // 101 01010
+ NULL, // 101 01011
+ NULL, // 101 01100
+ NULL, // 101 01101
+ NULL, // 101 01110
+ NULL, // 101 01111
+ NULL, // 101 10000
+ NULL, // 101 10001
+ NULL, // 101 10010
+ NULL, // 101 10011
+ NULL, // 101 10100
+ NULL, // 101 10101
+ NULL, // 101 10110
+ NULL, // 101 10111
+ NULL, // 101 11000
+ NULL, // 101 11001
+ NULL, // 101 11010
+ NULL, // 101 11011
+ NULL, // 101 11100
+ NULL, // 101 11101
+ NULL, // 101 11110
+ NULL, // 101 11111
+ "Ragazzi e Musica", // 110 00000
+ "Ragazzi e Musica - Bambini", // 110 00001
+ "Ragazzi e Musica - Ragazzi", // 110 00010
+ "Ragazzi e Musica - Cartoni Animati", // 110 00011
+ "Ragazzi e Musica - Musica", // 110 00100
+ "Ragazzi e Musica - Film Animazione", // 110 00101
+ "Ragazzi e Musica - Film", // 110 00110
+ "Ragazzi e Musica - Telefilm", // 110 00111
+ "Ragazzi e Musica - Magazine", // 110 01000
+ NULL, // 110 01001
+ NULL, // 110 01010
+ NULL, // 110 01011
+ NULL, // 110 01100
+ NULL, // 110 01101
+ NULL, // 110 01110
+ NULL, // 110 01111
+ NULL, // 110 10000
+ NULL, // 110 10001
+ NULL, // 110 10010
+ NULL, // 110 10011
+ "Ragazzi e Musica - Danza", // 110 10100
+ NULL, // 110 10101
+ NULL, // 110 10110
+ NULL, // 110 10111
+ NULL, // 110 11000
+ NULL, // 110 11001
+ NULL, // 110 11010
+ NULL, // 110 11011
+ NULL, // 110 11100
+ NULL, // 110 11101
+ NULL, // 110 11110
+ NULL, // 110 11111
+ "Altri Programmi", // 111 00000
+ "Altri Programmi - Educational", // 111 00001
+ "Altri Programmi - Regionale", // 111 00010
+ "Altri Programmi - Shopping", // 111 00011
+ NULL, // 111 00100
+ "Altri Programmi - Inizio e Fine Trasmissioni", // 111 00101
+ "Altri Programmi - Eventi Speciali", // 111 00110
+ "Altri Programmi - Film per Adulti", // 111 00111
+ NULL, // 111 01000
+ NULL, // 111 01001
+ NULL, // 111 01010
+ NULL, // 111 01011
+ NULL, // 111 01100
+ NULL, // 111 01101
+ NULL, // 111 01110
+ NULL, // 111 01111
+ NULL, // 111 10000
+ NULL, // 111 10001
+ NULL, // 111 10010
+ NULL, // 111 10011
+ NULL, // 111 10100
+ NULL, // 111 10101
+ NULL, // 111 10110
+ NULL, // 111 10111
+ NULL, // 111 11000
+ NULL, // 111 11001
+ NULL, // 111 11010
+ NULL, // 111 11011
+ NULL, // 111 11100
+ NULL, // 111 11101
+ NULL, // 111 11110
+ NULL, // 111 11111
+};
+
+static const char *SkyUkThemes[] = {
+ "No Category", // 000 00000
+ NULL, // 000 00001
+ NULL, // 000 00010
+ NULL, // 000 00011
+ NULL, // 000 00100
+ NULL, // 000 00101
+ NULL, // 000 00110
+ NULL, // 000 00111
+ NULL, // 000 01000
+ NULL, // 000 01001
+ NULL, // 000 01010
+ NULL, // 000 01011
+ NULL, // 000 01100
+ NULL, // 000 01101
+ NULL, // 000 01110
+ NULL, // 000 01111
+ NULL, // 000 10000
+ NULL, // 000 10001
+ NULL, // 000 10010
+ NULL, // 000 10011
+ NULL, // 000 10100
+ NULL, // 000 10101
+ NULL, // 000 10110
+ NULL, // 000 10111
+ NULL, // 000 11000
+ NULL, // 000 11001
+ NULL, // 000 11010
+ NULL, // 000 11011
+ NULL, // 000 11100
+ NULL, // 000 11101
+ NULL, // 000 11110
+ NULL, // 000 11111
+ NULL, // 001 00000
+ NULL, // 001 00001
+ NULL, // 001 00010
+ "Shopping", // 001 00011
+ NULL, // 001 00100
+ NULL, // 001 00101
+ NULL, // 001 00110
+ NULL, // 001 00111
+ NULL, // 001 01000
+ NULL, // 001 01001
+ NULL, // 001 01010
+ NULL, // 001 01011
+ NULL, // 001 01100
+ NULL, // 001 01101
+ NULL, // 001 01110
+ NULL, // 001 01111
+ NULL, // 001 10000
+ NULL, // 001 10001
+ NULL, // 001 10010
+ NULL, // 001 10011
+ NULL, // 001 10100
+ NULL, // 001 10101
+ NULL, // 001 10110
+ NULL, // 001 10111
+ NULL, // 001 11000
+ NULL, // 001 11001
+ NULL, // 001 11010
+ NULL, // 001 11011
+ NULL, // 001 11100
+ NULL, // 001 11101
+ NULL, // 001 11110
+ NULL, // 001 11111
+ "Children", // 010 00000
+ "Children - Cartoons", // 010 00001
+ "Children - Comedy", // 010 00010
+ "Children - Drama", // 010 00011
+ "Children - Educational", // 010 00100
+ "Children - Under 5", // 010 00101
+ "Children - Factual", // 010 00110
+ "Children - Magazine", // 010 00111
+ NULL, // 010 01000
+ NULL, // 010 01001
+ NULL, // 010 01010
+ NULL, // 010 01011
+ NULL, // 010 01100
+ NULL, // 010 01101
+ NULL, // 010 01110
+ NULL, // 010 01111
+ NULL, // 010 10000
+ NULL, // 010 10001
+ NULL, // 010 10010
+ NULL, // 010 10011
+ NULL, // 010 10100
+ NULL, // 010 10101
+ NULL, // 010 10110
+ NULL, // 010 10111
+ NULL, // 010 11000
+ NULL, // 010 11001
+ NULL, // 010 11010
+ NULL, // 010 11011
+ NULL, // 010 11100
+ NULL, // 010 11101
+ NULL, // 010 11110
+ NULL, // 010 11111
+ "Entertainment", // 011 00000
+ "Entertainment - Action", // 011 00001
+ "Entertainment - Comedy", // 011 00010
+ "Entertainment - Detective", // 011 00011
+ "Entertainment - Drama", // 011 00100
+ "Entertainment - Game Show", // 011 00101
+ "Entertainment - Sci-FI", // 011 00110
+ "Entertainment - Soap", // 011 00111
+ "Entertainment - Animation", // 011 01000
+ "Entertainment - Chat Show", // 011 01001
+ "Entertainment - Cooking", // 011 01010
+ "Entertainment - Factual", // 011 01011
+ "Entertainment - Fashion", // 011 01100
+ "Entertainment - Gardening", // 011 01101
+ "Entertainment - Travel", // 011 01110
+ "Entertainment - Technology", // 011 01111
+ "Entertainment - Arts", // 011 10000
+ "Entertainment - Lifestyle", // 011 10001
+ "Entertainment - Home", // 011 10010
+ "Entertainment - Magazine", // 011 10011
+ "Entertainment - Medical", // 011 10100
+ "Entertainment - Review", // 011 10101
+ "Entertainment - Antiques", // 011 10110
+ "Entertainment - Motors", // 011 10111
+ "Entertainment - Art&Lit", // 011 11000
+ "Entertainment - Ballet", // 011 11001
+ "Entertainment - Opera", // 011 11010
+ NULL, // 011 11011
+ NULL, // 011 11100
+ NULL, // 011 11101
+ NULL, // 011 11110
+ NULL, // 011 11111
+ "Music", // 100 00000
+ "Music - Classical ", // 100 00001
+ "Music - Folk and Country", // 100 00010
+ "Music - National Music", // 100 00011
+ "Music - Jazz", // 100 00100
+ "Music - Opera", // 100 00101
+ "Music - Rock&Pop", // 100 00110
+ "Music - Alternative Music", // 100 00111
+ "Music - Events", // 100 01000
+ "Music - Club and Dance", // 100 01001
+ "Music - Hip Hop", // 100 01010
+ "Music - Soul/R&B", // 100 01011
+ "Music - Dance", // 100 01100
+ NULL, // 100 01101
+ NULL, // 100 01110
+ NULL, // 100 01111
+ "Music - Features", // 100 10000
+ NULL, // 100 10001
+ NULL, // 100 10010
+ NULL, // 100 10011
+ NULL, // 100 10100
+ "Music - Lifestyle", // 100 10101
+ "Music - News and Weather", // 100 10110
+ "Music - Easy Listening", // 100 10111
+ "Music - Discussion", // 100 11000
+ "Music - Entertainment", // 100 11001
+ "Music - Religious", // 100 11010
+ NULL, // 100 11011
+ NULL, // 100 11100
+ NULL, // 100 11101
+ NULL, // 100 11110
+ NULL, // 100 11111
+ "News & Documentaries", // 101 00000
+ "News & Documentaries - Business", // 101 00001
+ "News & Documentaries - World Cultures", // 101 00010
+ "News & Documentaries - Adventure", // 101 00011
+ "News & Documentaries - Biography", // 101 00100
+ "News & Documentaries - Educational", // 101 00101
+ "News & Documentaries - Feature", // 101 00110
+ "News & Documentaries - Politics", // 101 00111
+ "News & Documentaries - News", // 101 01000
+ "News & Documentaries - Nature", // 101 01001
+ "News & Documentaries - Religious", // 101 01010
+ "News & Documentaries - Science", // 101 01011
+ "News & Documentaries - Showbiz", // 101 01100
+ "News & Documentaries - War Documentary", // 101 01101
+ "News & Documentaries - Historical", // 101 01110
+ "News & Documentaries - Ancient", // 101 01111
+ "News & Documentaries - Transport", // 101 10000
+ "News & Documentaries - Docudrama", // 101 10001
+ "News & Documentaries - World Affairs", // 101 10010
+ NULL, // 101 10011
+ NULL, // 101 10100
+ NULL, // 101 10101
+ NULL, // 101 10110
+ NULL, // 101 10111
+ NULL, // 101 11000
+ NULL, // 101 11001
+ NULL, // 101 11010
+ NULL, // 101 11011
+ NULL, // 101 11100
+ NULL, // 101 11101
+ NULL, // 101 11110
+ NULL, // 101 11111
+ "Movie", // 110 00000
+ "Movie - Action", // 110 00001
+ "Movie - Animation", // 110 00010
+ NULL, // 110 00011
+ "Movie - Comedy", // 110 00100
+ "Movie - Family", // 110 00101
+ "Movie - Drama", // 110 00110
+ NULL, // 110 00111
+ "Movie - Sci-Fi", // 110 01000
+ "Movie - Thriller", // 110 01001
+ "Movie - Horror", // 110 01010
+ "Movie - Romance", // 110 01011
+ "Movie - Musical", // 110 01100
+ "Movie - Mystery", // 110 01101
+ "Movie - Western", // 110 01110
+ "Movie - Factual", // 110 01111
+ "Movie - Fantasy", // 110 10000
+ "Movie - Erotic", // 110 10001
+ "Movie - Adventure", // 110 10010
+ NULL, // 110 10011
+ NULL, // 110 10100
+ NULL, // 110 10101
+ NULL, // 110 10110
+ NULL, // 110 10111
+ NULL, // 110 11000
+ NULL, // 110 11001
+ NULL, // 110 11010
+ NULL, // 110 11011
+ NULL, // 110 11100
+ NULL, // 110 11101
+ NULL, // 110 11110
+ NULL, // 110 11111
+ "Sports - Other", // 111 00000
+ "Sports - American Football", // 111 00001
+ "Sports - Athletics", // 111 00010
+ "Sports - Baseball", // 111 00011
+ "Sports - Basketball", // 111 00100
+ "Sports - Boxing", // 111 00101
+ "Sports - Cricket", // 111 00110
+ "Sports - Fishing", // 111 00111
+ "Sports - Football", // 111 01000
+ "Sports - Golf", // 111 01001
+ "Sports - Ice Hockey", // 111 01010
+ "Sports - Motor Sport", // 111 01011
+ "Sports - Racing", // 111 01100
+ "Sports - Rugby", // 111 01101
+ "Sports - Equestrian", // 111 01110
+ "Sports - Winter Sports", // 111 01111
+ "Sports - Snooker / Pool", // 111 10000
+ "Sports - Tennis", // 111 10001
+ "Sports - Wrestling", // 111 10010
+ "Sports - Darts", // 111 10011
+ "Sports - Watersports", // 111 10100
+ "Sports - Extreme", // 111 10101
+ NULL, // 111 10110
+ NULL, // 111 10111
+ NULL, // 111 11000
+ NULL, // 111 11001
+ NULL, // 111 11010
+ NULL, // 111 11011
+ NULL, // 111 11100
+ NULL, // 111 11101
+ NULL, // 111 11110
+ NULL, // 111 11111
+};
+
+static const char *FreesatT1[] = {
+ "START:00:T:",
+ "START:010:B:",
+ "START:1000:C:",
+ "START:1001:I:",
+ "START:1101:S:",
+ "START:01100:L:",
+ "START:01110:D:",
+ "START:01111:H:",
+ "START:10100:R:",
+ "START:10101:N:",
+ "START:10110:E:",
+ "START:11000:F:",
+ "START:11001:A:",
+ "START:11100:M:",
+ "START:11101:P:",
+ "START:11110:W:",
+ "START:011011:Q:",
+ "START:101111:G:",
+ "START:111110:J:",
+ "START:0110100:K:",
+ "START:1011101:U:",
+ "START:1111110:O:",
+ "START:01101010:6:",
+ "START:01101011:.:",
+ "START:10111000:V:",
+ "START:11111110:Y:",
+ "START:101110011:2:",
+ "START:111111111:X:",
+ "START:1011100100:Z:",
+ "START:1111111100:8:",
+ "START:10111001010:1:",
+ "START:10111001011:3:",
+ "START:111111110100:4:",
+ "START:111111110101:':",
+ "START:111111110111: :",
+ "START:11111111011000:5:",
+ "START:11111111011011:0:",
+ "START:111111110110011:m:",
+ "START:1111111101100100:c:",
+ "START:1111111101101000:9:",
+ "START:1111111101101010:a:",
+ "START:1111111101101011:d:",
+ "START:11111111011001010:s:",
+ "START:11111111011001011:p:",
+ "START:11111111011010010:(:",
+ "START:111111110110100110:t:",
+ "START:1111111101101001110:7:",
+ "START:11111111011010011110:ESCAPE:",
+ "START:11111111011010011111:l:",
+ "ESCAPE:0:ESCAPE:",
+ "ESCAPE:1:ESCAPE:",
+ "STOP:0:ESCAPE:",
+ "STOP:1:ESCAPE:",
+ "0x03:0:ESCAPE:",
+ "0x03:1:ESCAPE:",
+ "0x04:0:ESCAPE:",
+ "0x04:1:ESCAPE:",
+ "0x05:0:ESCAPE:",
+ "0x05:1:ESCAPE:",
+ "0x06:0:ESCAPE:",
+ "0x06:1:ESCAPE:",
+ "0x07:0:ESCAPE:",
+ "0x07:1:ESCAPE:",
+ "0x08:0:ESCAPE:",
+ "0x08:1:ESCAPE:",
+ "0x09:0:ESCAPE:",
+ "0x09:1:ESCAPE:",
+ "0x0a:0:ESCAPE:",
+ "0x0a:1:ESCAPE:",
+ "0x0b:0:ESCAPE:",
+ "0x0b:1:ESCAPE:",
+ "0x0c:0:ESCAPE:",
+ "0x0c:1:ESCAPE:",
+ "0x0d:0:ESCAPE:",
+ "0x0d:1:ESCAPE:",
+ "0x0e:0:ESCAPE:",
+ "0x0e:1:ESCAPE:",
+ "0x0f:0:ESCAPE:",
+ "0x0f:1:ESCAPE:",
+ "0x10:0:ESCAPE:",
+ "0x10:1:ESCAPE:",
+ "0x11:0:ESCAPE:",
+ "0x11:1:ESCAPE:",
+ "0x12:0:ESCAPE:",
+ "0x12:1:ESCAPE:",
+ "0x13:0:ESCAPE:",
+ "0x13:1:ESCAPE:",
+ "0x14:0:ESCAPE:",
+ "0x14:1:ESCAPE:",
+ "0x15:0:ESCAPE:",
+ "0x15:1:ESCAPE:",
+ "0x16:0:ESCAPE:",
+ "0x16:1:ESCAPE:",
+ "0x17:0:ESCAPE:",
+ "0x17:1:ESCAPE:",
+ "0x18:0:ESCAPE:",
+ "0x18:1:ESCAPE:",
+ "0x19:0:ESCAPE:",
+ "0x19:1:ESCAPE:",
+ "0x1a:0:ESCAPE:",
+ "0x1a:1:ESCAPE:",
+ "0x1b:0:ESCAPE:",
+ "0x1b:1:ESCAPE:",
+ "0x1c:0:ESCAPE:",
+ "0x1c:1:ESCAPE:",
+ "0x1d:0:ESCAPE:",
+ "0x1d:1:ESCAPE:",
+ "0x1e:0:ESCAPE:",
+ "0x1e:1:ESCAPE:",
+ "0x1f:0:ESCAPE:",
+ "0x1f:1:ESCAPE:",
+ " :0000:W:",
+ " :0011:M:",
+ " :0100:C:",
+ " :0101:B:",
+ " :0111:P:",
+ " :1001:T:",
+ " :1100:N:",
+ " :1111:S:",
+ " :00011:I:",
+ " :00100:G:",
+ " :01100:H:",
+ " :01101:D:",
+ " :10000:o:",
+ " :10001:A:",
+ " :10100:t:",
+ " :10110:a:",
+ " :10111:F:",
+ " :11010:L:",
+ " :11011:R:",
+ " :001011:U:",
+ " :101011:O:",
+ " :111001:J:",
+ " :111010:E:",
+ " :0001000:f:",
+ " :0001001:Q:",
+ " :0001011:V:",
+ " :0010100:STOP:",
+ " :0010101:w:",
+ " :1110000:2:",
+ " :1110001:K:",
+ " :1110110:Y:",
+ " :1110111:i:",
+ " :00010100:-:",
+ " :10101001:1:",
+ " :101010000:&:",
+ " :101010101:X:",
+ " :0001010101:r:",
+ " :1010100010:5:",
+ " :1010100011:Z:",
+ " :1010101001:9:",
+ " :1010101101:s:",
+ " :1010101110:4:",
+ " :1010101111:3:",
+ " :00010101000:7:",
+ " :00010101100:b:",
+ " :00010101110:y:",
+ " :10101010000:':",
+ " :10101011000:6:",
+ " :000101011010:v:",
+ " :000101011011:d:",
+ " :000101011110:(:",
+ " :101010100010: :",
+ " :101010100011:0:",
+ " :101010110010:n:",
+ " :101010110011:8:",
+ " :0001010100110:g:",
+ " :0001010111110:u:",
+ " :00010101001000:+:",
+ " :00010101001001:.:",
+ " :00010101001010:ESCAPE:",
+ " :00010101001011:l:",
+ " :00010101001111:m:",
+ " :00010101111110:p:",
+ " :000101010011100:\\:",
+ " :000101010011101:/:",
+ " :000101011111111:e:",
+ " :0001010111111101:\":",
+ " :00010101111111001:c:",
+ " :000101011111110000:k:",
+ " :000101011111110001:h:",
+ "!:1:STOP:",
+ "!:01: :",
+ "!:001:.:",
+ "!:0001:!:",
+ "!:00001:\":",
+ "!:000000:ESCAPE:",
+ "!:000001:0x3a:",
+ "\":0: :",
+ "\":10:ESCAPE:",
+ "\":11:I:",
+ "#:0:ESCAPE:",
+ "#:1:ESCAPE:",
+ "$:0:ESCAPE:",
+ "$:1:ESCAPE:",
+ "%:1: :",
+ "%:00:ESCAPE:",
+ "%:01:STOP:",
+ "&:1: :",
+ "&:01:B:",
+ "&:000:ESCAPE:",
+ "&:001:.:",
+ "':1:s:",
+ "':000:m:",
+ "':010:C:",
+ "':0010:t:",
+ "':0011: :",
+ "':01100:d:",
+ "':01110:v:",
+ "':011011:r:",
+ "':011111:A:",
+ "':0110101:n:",
+ "':01101000:G:",
+ "':01111001:l:",
+ "':011010011:D:",
+ "':011110000:B:",
+ "':011110001:e:",
+ "':011110101:i:",
+ "':011110110:6:",
+ "':0110100100:L:",
+ "':0111101001:STOP:",
+ "':0111101111:w:",
+ "':01101001010:O:",
+ "':01111010000:S:",
+ "':01111010001:E:",
+ "':01111011101:N:",
+ "':011110111001:R:",
+ "':0110100101100:a:",
+ "':0110100101101:M:",
+ "':0110100101110:K:",
+ "':0110100101111:F:",
+ "':0111101110000:0:",
+ "':01111011100010:ESCAPE:",
+ "':01111011100011:c:",
+ "(:1:c:",
+ "(:000:1:",
+ "(:0010:M:",
+ "(:0011:U:",
+ "(:0100:R:",
+ "(:0101:D:",
+ "(:0110:H:",
+ "(:01110:S:",
+ "(:011110:F:",
+ "(:0111110:G:",
+ "(:01111110:ESCAPE:",
+ "(:01111111:Y:",
+ "):1:STOP:",
+ "):00:ESCAPE:",
+ "):01: :",
+ "*:0:*:",
+ "*:101: :",
+ "*:1000:d:",
+ "*:1100:m:",
+ "*:1101:t:",
+ "*:1111:s:",
+ "*:10010:e:",
+ "*:11100:g:",
+ "*:11101:k:",
+ "*:100110:ESCAPE:",
+ "*:100111:y:",
+ "+:0:ESCAPE:",
+ "+:1: :",
+ ",:1: :",
+ ",:01:0:",
+ ",:000:ESCAPE:",
+ ",:001:.:",
+ "-:11: :",
+ "-:011:S:",
+ "-:100:G:",
+ "-:101:O:",
+ "-:0011:T:",
+ "-:0100:U:",
+ "-:00000:E:",
+ "-:00010:D:",
+ "-:000010:m:",
+ "-:000110:0:",
+ "-:000111:I:",
+ "-:001010:6:",
+ "-:010100:F:",
+ "-:010101:o:",
+ "-:0000110:L:",
+ "-:0000111:C:",
+ "-:0010001:A:",
+ "-:0010010:t:",
+ "-:0010011:Y:",
+ "-:0010111:2:",
+ "-:0101100:B:",
+ "-:0101101:.:",
+ "-:00100000:P:",
+ "-:00100001:Z:",
+ "-:01011100:8:",
+ "-:01011101:i:",
+ "-:01011110:d:",
+ "-:01011111:H:",
+ "-:001011001:N:",
+ "-:001011011:R:",
+ "-:0010110000:1:",
+ "-:0010110001:W:",
+ "-:00101101001:c:",
+ "-:00101101010:a:",
+ "-:00101101011:M:",
+ "-:001011010000:ESCAPE:",
+ "-:001011010001:Q:",
+ ".:1:.:",
+ ".:01:STOP:",
+ ".:0010: :",
+ ".:00000:I:",
+ ".:00001:T:",
+ ".:00010:C:",
+ ".:00110:p:",
+ ".:00111:0:",
+ ".:000111:H:",
+ ".:00011010:W:",
+ ".:000110001:S:",
+ ".:000110110:3:",
+ ".:000110111:B:",
+ ".:0001100000:1:",
+ ".:0001100001:M:",
+ ".:0001100110:c:",
+ ".:00011001000:t:",
+ ".:00011001001:R:",
+ ".:00011001010:F:",
+ ".:00011001110:E:",
+ ".:00011001111:A:",
+ ".:0001100101100:ESCAPE:",
+ ".:0001100101101:l:",
+ ".:0001100101110:d:",
+ ".:0001100101111:U:",
+ "/:00:1:",
+ "/:10:7:",
+ "/:010:4:",
+ "/:011:2:",
+ "/:110:3:",
+ "/:1110:5:",
+ "/:111100:6:",
+ "/:111110:C:",
+ "/:1111010:9:",
+ "/:1111011: :",
+ "/:1111110:8:",
+ "/:11111111:U:",
+ "/:1111111000:G:",
+ "/:1111111010:0:",
+ "/:11111110010:ESCAPE:",
+ "/:11111110011:W:",
+ "/:11111110110:V:",
+ "/:11111110111:S:",
+ "0:00:6:",
+ "0:01: :",
+ "0:11:0:",
+ "0:1001:p:",
+ "0:1010:STOP:",
+ "0:10000:1:",
+ "0:10001:a:",
+ "0:10111:7:",
+ "0:1011000:-:",
+ "0:1011010:s:",
+ "0:10110011:4:",
+ "0:10110110:t:",
+ "0:101101111:%:",
+ "0:1011001000:8:",
+ "0:1011001001:0x3a:",
+ "0:1011001010:5:",
+ "0:1011001011:2:",
+ "0:1011011100:/:",
+ "0:10110111011:U:",
+ "0:101101110101:,:",
+ "0:1011011101000:.:",
+ "0:10110111010010:ESCAPE:",
+ "0:10110111010011:l:",
+ "1:01:STOP:",
+ "1:000:.:",
+ "1:101:0:",
+ "1:111:1:",
+ "1:0010:2:",
+ "1:0011: :",
+ "1:1101:/:",
+ "1:10010:8:",
+ "1:11000:3:",
+ "1:100000:5:",
+ "1:100001:s:",
+ "1:100010:6:",
+ "1:100011:0x3a:",
+ "1:100110:':",
+ "1:110010:X:",
+ "1:110011:9:",
+ "1:1001111:4:",
+ "1:10011101:-:",
+ "1:100111001:7:",
+ "1:1001110000:):",
+ "1:10011100010:ESCAPE:",
+ "1:10011100011:,:",
+ "2:0:0:",
+ "2:11:4:",
+ "2:101:STOP:",
+ "2:1001: :",
+ "2:10000:0x3a:",
+ "2:1000101:5:",
+ "2:1000111:/:",
+ "2:10001000:.:",
+ "2:10001001:1:",
+ "2:10001100:W:",
+ "2:100011011:7:",
+ "2:10001101001:3:",
+ "2:10001101011:Z:",
+ "2:100011010000:n:",
+ "2:100011010001:6:",
+ "2:100011010101:':",
+ "2:1000110101000:ESCAPE:",
+ "2:1000110101001:s:",
+ "3:0: :",
+ "3:10:STOP:",
+ "3:1100:r:",
+ "3:1101:/:",
+ "3:1111:B:",
+ "3:11100:0:",
+ "3:1110100:0x3a:",
+ "3:1110110:-:",
+ "3:11101010:1:",
+ "3:11101011:8:",
+ "3:11101111:4:",
+ "3:1110111000:6:",
+ "3:1110111011:9:",
+ "3:11101110011:t:",
+ "3:11101110100:3:",
+ "3:111011100100:ESCAPE:",
+ "3:111011100101:e:",
+ "3:111011101010:7:",
+ "3:111011101011:5:",
+ "4:0:STOP:",
+ "4:11: :",
+ "4:1001:0x3a:",
+ "4:1011:/:",
+ "4:10001:8:",
+ "4:10101:.:",
+ "4:100000:9:",
+ "4:101000:0:",
+ "4:1010010:M:",
+ "4:10000101:I:",
+ "4:10000110:):",
+ "4:10100110:R:",
+ "4:10100111:-:",
+ "4:100001000:W:",
+ "4:100001110:P:",
+ "4:100001111:5:",
+ "4:1000010011:2:",
+ "4:10000100100:ESCAPE:",
+ "4:10000100101:':",
+ "5:0:STOP:",
+ "5:11: :",
+ "5:101:0:",
+ "5:1001:/:",
+ "5:100001:-:",
+ "5:100011:0x3a:",
+ "5:1000001:t:",
+ "5:1000100:3:",
+ "5:1000101:1:",
+ "5:10000000:ESCAPE:",
+ "5:10000001:a:",
+ "6:00:STOP:",
+ "6:01: :",
+ "6:10:0:",
+ "6:111:0x3a:",
+ "6:11001:.:",
+ "6:11011:i:",
+ "6:110000:-:",
+ "6:110101:a:",
+ "6:1100011:4:",
+ "6:1101000:8:",
+ "6:1101001:/:",
+ "6:11000100:6:",
+ "6:110001011:9:",
+ "6:1100010100:3:",
+ "6:11000101010:ESCAPE:",
+ "6:11000101011:t:",
+ "7:1:STOP:",
+ "7:01: :",
+ "7:000:0:",
+ "7:0011:.:",
+ "7:00101:/:",
+ "7:0010000:1:",
+ "7:0010010:5:",
+ "7:00100010:ESCAPE:",
+ "7:00100011:4:",
+ "7:00100110:3:",
+ "7:00100111:2:",
+ "8:1: :",
+ "8:00:0:",
+ "8:010:0x3a:",
+ "8:01101:STOP:",
+ "8:011000:t:",
+ "8:011001:p:",
+ "8:011101:8:",
+ "8:011110:.:",
+ "8:011111:6:",
+ "8:0111000:5:",
+ "8:01110010:9:",
+ "8:011100110:M:",
+ "8:0111001110:F:",
+ "8:01110011110:ESCAPE:",
+ "8:01110011111:c:",
+ "9:0:1:",
+ "9:11:STOP:",
+ "9:1000:9:",
+ "9:1010:.:",
+ "9:10011:0:",
+ "9:100100: :",
+ "9:100101:8:",
+ "9:101100:7:",
+ "9:101101:/:",
+ "9:101110:6:",
+ "9:1011111:0x3a:",
+ "9:10111101:4:",
+ "9:101111000:ESCAPE:",
+ "9:101111001:3:",
+ "0x3a:1: :",
+ "0x3a:00:0:",
+ "0x3a:011:.:",
+ "0x3a:0100:2:",
+ "0x3a:01010:1:",
+ "0x3a:010111:3:",
+ "0x3a:0101101:C:",
+ "0x3a:01011000:ESCAPE:",
+ "0x3a:01011001:T:",
+ ";:1: :",
+ ";:00:ESCAPE:",
+ ";:01:.:",
+ "<:0:ESCAPE:",
+ "<:1:ESCAPE:",
+ "=:0:ESCAPE:",
+ "=:1:ESCAPE:",
+ ">:0:ESCAPE:",
+ ">:1:ESCAPE:",
+ "?:1:STOP:",
+ "?:01: :",
+ "?:001:0x3a:",
+ "?:0000:ESCAPE:",
+ "?:0001:.:",
+ "@:0:ESCAPE:",
+ "@:1:H:",
+ "A:001:r:",
+ "A:010: :",
+ "A:100:l:",
+ "A:110:n:",
+ "A:0000:m:",
+ "A:0111:g:",
+ "A:1111:d:",
+ "A:00010:w:",
+ "A:01100:T:",
+ "A:01101:c:",
+ "A:10101:t:",
+ "A:10110:f:",
+ "A:10111:i:",
+ "A:11100:s:",
+ "A:000110:u:",
+ "A:000111:STOP:",
+ "A:101001:R:",
+ "A:111010:b:",
+ "A:1010001:v:",
+ "A:1110110:p:",
+ "A:10100000:S:",
+ "A:11101110:M:",
+ "A:101000011:P:",
+ "A:111011111:.:",
+ "A:10100001000:e:",
+ "A:10100001001:B:",
+ "A:10100001010:1:",
+ "A:11101111011:-:",
+ "A:101000010110:k:",
+ "A:101000010111:h:",
+ "A:111011110000:a:",
+ "A:111011110100:y:",
+ "A:111011110101:*:",
+ "A:1110111100010:x:",
+ "A:1110111100011:':",
+ "A:1110111100100:N:",
+ "A:1110111100110:2:",
+ "A:11101111001010:0x3a:",
+ "A:11101111001111:z:",
+ "A:111011110010110:L:",
+ "A:111011110010111:F:",
+ "A:111011110011100:D:",
+ "A:1110111100111010:ESCAPE:",
+ "A:1110111100111011:q:",
+ "B:00:C:",
+ "B:01:B:",
+ "B:101:r:",
+ "B:1001:i:",
+ "B:1100:o:",
+ "B:1101:u:",
+ "B:1110:a:",
+ "B:1111:e:",
+ "B:10001:l:",
+ "B:1000000:STOP:",
+ "B:1000010:y:",
+ "B:10000010:O:",
+ "B:10000110:3:",
+ "B:100000111:A:",
+ "B:100001110:S:",
+ "B:1000001101:0x3a:",
+ "B:10000011000:.:",
+ "B:10000011001:w:",
+ "B:10000111101:h:",
+ "B:10000111110:*:",
+ "B:10000111111: :",
+ "B:100001111001:R:",
+ "B:1000011110000:':",
+ "B:10000111100011:T:",
+ "B:100001111000100:ESCAPE:",
+ "B:100001111000101:4:",
+ "C:00:o:",
+ "C:01: :",
+ "C:100:l:",
+ "C:110:h:",
+ "C:1010:r:",
+ "C:1110:a:",
+ "C:10110:i:",
+ "C:10111:e:",
+ "C:111100:u:",
+ "C:111101:B:",
+ "C:1111100:y:",
+ "C:1111110:!:",
+ "C:11111011:.:",
+ "C:111110100:w:",
+ "C:111111100:STOP:",
+ "C:111111110:S:",
+ "C:111111111:T:",
+ "C:1111101011:2:",
+ "C:1111111011:I:",
+ "C:11111010100:4:",
+ "C:11111010101:*:",
+ "C:11111110101:D:",
+ "C:111111101000:U:",
+ "C:1111111010010:':",
+ "C:11111110100110:n:",
+ "C:111111101001110:z:",
+ "C:11111110100111100:O:",
+ "C:11111110100111101:E:",
+ "C:11111110100111110:A:",
+ "C:111111101001111110:ESCAPE:",
+ "C:111111101001111111:s:",
+ "D:01:o:",
+ "D:10:a:",
+ "D:000:r:",
+ "D:110:e:",
+ "D:111:i:",
+ "D:00100:t:",
+ "D:00111:u:",
+ "D:001011: :",
+ "D:0010101:J:",
+ "D:0011000:y:",
+ "D:0011010:STOP:",
+ "D:0011011:I:",
+ "D:00110011:0x3a:",
+ "D:001010001:*:",
+ "D:001010010:-:",
+ "D:001010011:&:",
+ "D:001100100:':",
+ "D:0010100000:A:",
+ "D:0010100001:h:",
+ "D:00110010101:N:",
+ "D:00110010110:V:",
+ "D:001100101110:D:",
+ "D:001100101111:w:",
+ "D:0011001010000:O:",
+ "D:0011001010001:E:",
+ "D:0011001010011:d:",
+ "D:00110010100100:ESCAPE:",
+ "D:00110010100101:T:",
+ "E:00:m:",
+ "E:011:v:",
+ "E:101:n:",
+ "E:111:a:",
+ "E:0100:E:",
+ "E:1000:STOP:",
+ "E:1101:x:",
+ "E:10011:d:",
+ "E:11001:l:",
+ "E:010100:4:",
+ "E:010101:y:",
+ "E:010110:u:",
+ "E:100100:r:",
+ "E:110000:i:",
+ "E:0101111:s:",
+ "E:1001010:F:",
+ "E:1100010:X:",
+ "E:10010110:R:",
+ "E:11000111: :",
+ "E:010111010:g:",
+ "E:100101111:0x3a:",
+ "E:110001100:T:",
+ "E:110001101:':",
+ "E:0101110001:c:",
+ "E:0101110011:q:",
+ "E:0101110110:e:",
+ "E:0101110111:C:",
+ "E:1001011100:p:",
+ "E:01011100000:-:",
+ "E:01011100101:Z:",
+ "E:10010111011:t:",
+ "E:010111000010:S:",
+ "E:010111000011:.:",
+ "E:100101110101:W:",
+ "E:0101110010000:!:",
+ "E:1001011101000:o:",
+ "E:01011100100010:f:",
+ "E:01011100100011:U:",
+ "E:01011100100100:N:",
+ "E:01011100100101:M:",
+ "E:01011100100110:L:",
+ "E:01011100100111:A:",
+ "E:10010111010011:D:",
+ "E:100101110100100:ESCAPE:",
+ "E:100101110100101:w:",
+ "F:00:i:",
+ "F:10:a:",
+ "F:011:r:",
+ "F:110:u:",
+ "F:111:o:",
+ "F:0100:e:",
+ "F:01011:l:",
+ "F:0101000:A:",
+ "F:0101010:O:",
+ "F:01010010: :",
+ "F:010100110:h:",
+ "F:010100111:t:",
+ "F:010101101:f:",
+ "F:010101111:L:",
+ "F:0101011001:STOP:",
+ "F:01010111000:j:",
+ "F:01010111001:I:",
+ "F:01010111010:.:",
+ "F:01010111011:1:",
+ "F:010101100000:M:",
+ "F:010101100010:*:",
+ "F:010101100011:K:",
+ "F:0101011000010:y:",
+ "F:01010110000111:H:",
+ "F:010101100001100:ESCAPE:",
+ "F:010101100001101:!:",
+ "G:10:r:",
+ "G:001:M:",
+ "G:010:a:",
+ "G:011:o:",
+ "G:110:i:",
+ "G:111:e:",
+ "G:00001:u:",
+ "G:00010:X:",
+ "G:000001:h:",
+ "G:000111:l:",
+ "G:0000001:y:",
+ "G:0001100:w:",
+ "G:00000000:0x3a:",
+ "G:00011011:C:",
+ "G:000000011:STOP:",
+ "G:000110100:-:",
+ "G:0001101010:P:",
+ "G:0001101011: :",
+ "G:00000001000:':",
+ "G:00000001010:A:",
+ "G:000000010010:U:",
+ "G:000000010110:T:",
+ "G:000000010111:4:",
+ "G:0000000100110:ESCAPE:",
+ "G:0000000100111:Y:",
+ "H:0:o:",
+ "H:100:a:",
+ "H:101:i:",
+ "H:110:e:",
+ "H:1110:u:",
+ "H:11110:R:",
+ "H:111110:A:",
+ "H:1111110:.:",
+ "H:111111101:y:",
+ "H:111111110:S:",
+ "H:1111111110:E:",
+ "H:1111111111:r:",
+ "H:11111110000:STOP:",
+ "H:11111110010:L:",
+ "H:11111110011:M:",
+ "H:111111100011:w:",
+ "H:1111111000101:D:",
+ "H:11111110001000:ESCAPE:",
+ "H:11111110001001:I:",
+ "I:0:T:",
+ "I:100:s:",
+ "I:101:n:",
+ "I:1101:t:",
+ "I:11001: :",
+ "I:11101:':",
+ "I:11111:r:",
+ "I:110000:I:",
+ "I:110001:STOP:",
+ "I:111001:m:",
+ "I:1110000:d:",
+ "I:1110001:N:",
+ "I:1111001:z:",
+ "I:1111010:.:",
+ "I:11110000:a:",
+ "I:11110001:Y:",
+ "I:111101100:S:",
+ "I:111101110:c:",
+ "I:11110110101:D:",
+ "I:11110110110:f:",
+ "I:11110111100:l:",
+ "I:11110111111:y:",
+ "I:111101101000:V:",
+ "I:111101101110:o:",
+ "I:111101111011:F:",
+ "I:1111011010010:,:",
+ "I:1111011010011:A:",
+ "I:1111011011110:O:",
+ "I:1111011110101:g:",
+ "I:1111011111000:C:",
+ "I:1111011111001:0x3a:",
+ "I:1111011111011:v:",
+ "I:11110110111110:p:",
+ "I:11110110111111:E:",
+ "I:11110111101000:B:",
+ "I:11110111110100:k:",
+ "I:11110111110101:b:",
+ "I:1111011110100100:ESCAPE:",
+ "I:1111011110100101:R:",
+ "I:1111011110100110:L:",
+ "I:1111011110100111:G:",
+ "J:00:a:",
+ "J:01:u:",
+ "J:11:e:",
+ "J:101:o:",
+ "J:1001:i:",
+ "J:10000: :",
+ "J:100010:K:",
+ "J:1000111:STOP:",
+ "J:100011001:s:",
+ "J:100011010:F:",
+ "J:1000110000:V:",
+ "J:1000110001:':",
+ "J:1000110111:f:",
+ "J:10001101101:G:",
+ "J:100011011000:ESCAPE:",
+ "J:100011011001:D:",
+ "K:01:i:",
+ "K:11:y:",
+ "K:001:e:",
+ "K:101: :",
+ "K:0000:a:",
+ "K:1000:o:",
+ "K:00010:STOP:",
+ "K:00011:r:",
+ "K:100101:t:",
+ "K:100110:n:",
+ "K:100111:S:",
+ "K:10010011:G:",
+ "K:100100000:-:",
+ "K:100100011:O:",
+ "K:100100100:h:",
+ "K:100100101:w:",
+ "K:1001000010:1:",
+ "K:1001000011:':",
+ "K:10010001011:u:",
+ "K:100100010000:T:",
+ "K:100100010001:N:",
+ "K:100100010010:0x3a:",
+ "K:100100010011:.:",
+ "K:100100010100:,:",
+ "K:1001000101010:ESCAPE:",
+ "K:1001000101011:l:",
+ "L:00:a:",
+ "L:10:o:",
+ "L:11:i:",
+ "L:010:e:",
+ "L:0111:u:",
+ "L:01101:K:",
+ "L:0110000:l:",
+ "L:0110010:A:",
+ "L:0110011: :",
+ "L:01100011:y:",
+ "L:0110001000:L:",
+ "L:0110001001:I:",
+ "L:01100010100:C:",
+ "L:01100010101:.:",
+ "L:01100010111:STOP:",
+ "L:011000101101:':",
+ "L:0110001011000:E:",
+ "L:01100010110010:ESCAPE:",
+ "L:01100010110011:Y:",
+ "M:01:a:",
+ "M:10:o:",
+ "M:000:e:",
+ "M:111:i:",
+ "M:0010:T:",
+ "M:1100:y:",
+ "M:1101:u:",
+ "M:00110:STOP:",
+ "M:001111:c:",
+ "M:00111001:r:",
+ "M:00111010:E:",
+ "M:001110111:F:",
+ "M:0011100001:Z:",
+ "M:0011100011: :",
+ "M:0011101100:1:",
+ "M:0011101101:I:",
+ "M:00111000001:h:",
+ "M:00111000100:C:",
+ "M:001110000001:Q:",
+ "M:001110001010:K:",
+ "M:0011100010110:P:",
+ "M:00111000000000:0x3a:",
+ "M:00111000000001:.:",
+ "M:00111000000010:':",
+ "M:00111000101110:M:",
+ "M:001110000000110:ESCAPE:",
+ "M:001110000000111:w:",
+ "M:001110001011110:S:",
+ "M:001110001011111:R:",
+ "N:1:e:",
+ "N:00:o:",
+ "N:011:i:",
+ "N:0101:a:",
+ "N:01001:u:",
+ "N:010000:C:",
+ "N:01000100:E:",
+ "N:01000110:F:",
+ "N:010001110:B:",
+ "N:010001111:H:",
+ "N:0100010110:Y:",
+ "N:01000101000:G:",
+ "N:01000101001:':",
+ "N:01000101011:I:",
+ "N:01000101110:A:",
+ "N:010001010100:M:",
+ "N:010001011110: :",
+ "N:010001011111:STOP:",
+ "N:0100010101010:T:",
+ "N:01000101010110:.:",
+ "N:010001010101110:ESCAPE:",
+ "N:010001010101111:Z:",
+ "O:000:':",
+ "O:010:f:",
+ "O:110:u:",
+ "O:111:n:",
+ "O:0010:M:",
+ "O:0011:l:",
+ "O:1001:m:",
+ "O:01101:r:",
+ "O:01110:d:",
+ "O:10000:p:",
+ "O:10100:h:",
+ "O:10110:STOP:",
+ "O:011001:S:",
+ "O:011110:z:",
+ "O:011111:b:",
+ "O:100011:v:",
+ "O:101010:w:",
+ "O:101011:U:",
+ "O:1011100:T:",
+ "O:1011101:O:",
+ "O:1011110:K:",
+ "O:01100001:C:",
+ "O:01100010:x:",
+ "O:01100011:.:",
+ "O:10001001:t:",
+ "O:10001011: :",
+ "O:10111110:s:",
+ "O:10111111:N:",
+ "O:011000001:g:",
+ "O:100010000:-:",
+ "O:100010101:a:",
+ "O:1000100010:i:",
+ "O:1000100011:e:",
+ "O:1000101001:o:",
+ "O:01100000000:A:",
+ "O:01100000001:j:",
+ "O:01100000010:c:",
+ "O:10001010000:2:",
+ "O:011000000111:R:",
+ "O:100010100010:P:",
+ "O:100010100011:0x3a:",
+ "O:0110000001100:E:",
+ "O:01100000011010:ESCAPE:",
+ "O:01100000011011:L:",
+ "P:01:r:",
+ "P:10:l:",
+ "P:000:e:",
+ "P:001:a:",
+ "P:111:o:",
+ "P:1101:i:",
+ "P:110000:D:",
+ "P:110001:u:",
+ "P:110011:h:",
+ "P:11001000: :",
+ "P:11001010:2:",
+ "P:110010010:H:",
+ "P:110010011:M:",
+ "P:110010110:S:",
+ "P:11001011100:0x3a:",
+ "P:11001011101:*:",
+ "P:110010111101:s:",
+ "P:1100101111001:I:",
+ "P:1100101111100:STOP:",
+ "P:1100101111101:G:",
+ "P:1100101111110:':",
+ "P:11001011111110:y:",
+ "P:110010111100000:Y:",
+ "P:110010111100001:L:",
+ "P:110010111100010:C:",
+ "P:110010111100011:ESCAPE:",
+ "P:110010111111110:O:",
+ "P:110010111111111:.:",
+ "Q:1:u:",
+ "Q:000:I:",
+ "Q:001:STOP:",
+ "Q:010:V:",
+ "Q:0111: :",
+ "Q:01101:C:",
+ "Q:011000:ESCAPE:",
+ "Q:011001:':",
+ "R:00:a:",
+ "R:01:o:",
+ "R:11:e:",
+ "R:100:i:",
+ "R:1011:u:",
+ "R:10101:E:",
+ "R:101000:D:",
+ "R:1010011:STOP:",
+ "R:10100101:h:",
+ "R:1010010000:I:",
+ "R:1010010010:y:",
+ "R:1010010011:n:",
+ "R:101001000110: :",
+ "R:1010010001000:':",
+ "R:1010010001011:S:",
+ "R:1010010001110:N:",
+ "R:10100100010010:B:",
+ "R:10100100010011:.:",
+ "R:10100100010100:&:",
+ "R:10100100011110:T:",
+ "R:10100100011111:1:",
+ "R:101001000101010:ESCAPE:",
+ "R:101001000101011:C:",
+ "S:001:o:",
+ "S:010:p:",
+ "S:011:u:",
+ "S:110:h:",
+ "S:111:t:",
+ "S:0001:a:",
+ "S:1001:e:",
+ "S:1011:c:",
+ "S:00000:n:",
+ "S:10001:i:",
+ "S:10101:k:",
+ "S:000011:w:",
+ "S:101000:m:",
+ "S:0000101:A:",
+ "S:1000010:l:",
+ "S:1010010:q:",
+ "S:1010011:M:",
+ "S:00001000:2:",
+ "S:00001001:P:",
+ "S:10000000:O:",
+ "S:10000010:I:",
+ "S:10000011: :",
+ "S:10000111:STOP:",
+ "S:100000010:y:",
+ "S:100001100:E:",
+ "S:1000000111:?:",
+ "S:1000011011:H:",
+ "S:10000001100:B:",
+ "S:10000110100:g:",
+ "S:100000011011:r:",
+ "S:100001101010:*:",
+ "S:1000011010110:3:",
+ "S:1000011010111:.:",
+ "S:10000001101000:5:",
+ "S:10000001101010:0x3a:",
+ "S:10000001101011:1:",
+ "S:100000011010010:C:",
+ "S:1000000110100110:ESCAPE:",
+ "S:1000000110100111:Y:",
+ "T:0:h:",
+ "T:101:o:",
+ "T:111:V:",
+ "T:1000:e:",
+ "T:1001:r:",
+ "T:11000:a:",
+ "T:11010:w:",
+ "T:110011:i:",
+ "T:1101101:O:",
+ "T:1101111:H:",
+ "T:11001001:y:",
+ "T:11001010:M:",
+ "T:11011000:.:",
+ "T:11011100:u:",
+ "T:11011101:W:",
+ "T:110010001:P:",
+ "T:110010110:0x3a:",
+ "T:110010111:4:",
+ "T:110110011:I:",
+ "T:1101100100: :",
+ "T:1101100101:STOP:",
+ "T:11001000010:X:",
+ "T:11001000011:s:",
+ "T:110010000000:T:",
+ "T:110010000001:S:",
+ "T:110010000010:B:",
+ "T:1100100000110:U:",
+ "T:11001000001110:A:",
+ "T:1100100000111100:C:",
+ "T:1100100000111101:*:",
+ "T:1100100000111111:N:",
+ "T:11001000001111100:ESCAPE:",
+ "T:11001000001111101:Y:",
+ "U:0:n:",
+ "U:10:p:",
+ "U:1101:K:",
+ "U:1111:l:",
+ "U:11000:R:",
+ "U:11100:S:",
+ "U:110011:E:",
+ "U:111011:s:",
+ "U:1100101:g:",
+ "U:1110101:T:",
+ "U:11001001: :",
+ "U:110010000:-:",
+ "U:110010001:r:",
+ "U:111010000:2:",
+ "U:111010001:m:",
+ "U:111010011:STOP:",
+ "U:1110100100:.:",
+ "U:11101001010:c:",
+ "U:111010010110:k:",
+ "U:11101001011100:ESCAPE:",
+ "U:11101001011101:z:",
+ "U:11101001011110:t:",
+ "U:11101001011111:B:",
+ "V:1: :",
+ "V:000:0x3a:",
+ "V:011:i:",
+ "V:0010:e:",
+ "V:0011:a:",
+ "V:0100:3:",
+ "V:010101:C:",
+ "V:010111:STOP:",
+ "V:0101000:':",
+ "V:0101001:4:",
+ "V:0101101:o:",
+ "V:01011001:I:",
+ "V:0101100000:s:",
+ "V:0101100001:D:",
+ "V:0101100010:.:",
+ "V:01011000110:8:",
+ "V:0101100011101:u:",
+ "V:0101100011110:r:",
+ "V:0101100011111:B:",
+ "V:01011000111000:ESCAPE:",
+ "V:01011000111001:E:",
+ "W:01:o:",
+ "W:11:e:",
+ "W:001:h:",
+ "W:100:a:",
+ "W:101:i:",
+ "W:00000:.:",
+ "W:00010:O:",
+ "W:00011:r:",
+ "W:000011:y:",
+ "W:0000100:u:",
+ "W:00001010:STOP:",
+ "W:000010111:A:",
+ "W:00001011001:Y:",
+ "W:00001011010:T:",
+ "W:00001011011: :",
+ "W:000010110000:I:",
+ "W:0000101100010:ESCAPE:",
+ "W:0000101100011:l:",
+ "X:00:STOP:",
+ "X:10: :",
+ "X:11:t:",
+ "X:010:T:",
+ "X:0111:c:",
+ "X:01101:m:",
+ "X:011001:U:",
+ "X:01100000:a:",
+ "X:01100001:X:",
+ "X:01100010:-:",
+ "X:011000110:x:",
+ "X:0110001111:9:",
+ "X:01100011100:ESCAPE:",
+ "X:01100011101:i:",
+ "Y:1:o:",
+ "Y:01:e:",
+ "Y:000:u:",
+ "Y:0011: :",
+ "Y:00100:v:",
+ "Y:001010:a:",
+ "Y:00101110:P:",
+ "Y:00101111:':",
+ "Y:001011000:n:",
+ "Y:001011011:r:",
+ "Y:0010110010:D:",
+ "Y:00101100110:w:",
+ "Y:00101100111:s:",
+ "Y:00101101000:R:",
+ "Y:00101101001:L:",
+ "Y:00101101010:STOP:",
+ "Y:001011010110:C:",
+ "Y:0010110101110:ESCAPE:",
+ "Y:0010110101111:N:",
+ "Z:1:o:",
+ "Z:00:a:",
+ "Z:010:i:",
+ "Z:01100:O:",
+ "Z:01101:u:",
+ "Z:01110:e:",
+ "Z:011110: :",
+ "Z:0111111:STOP:",
+ "Z:01111101:0x3a:",
+ "Z:011111000:ESCAPE:",
+ "Z:011111001:-:",
+ "[:0:ESCAPE:",
+ "[:1:ESCAPE:",
+ "\\:0:ESCAPE:",
+ "\\:1:x:",
+ "]:0:ESCAPE:",
+ "]:1:ESCAPE:",
+ "^:0:ESCAPE:",
+ "^:1:ESCAPE:",
+ "_:0:ESCAPE:",
+ "_:1:ESCAPE:",
+ "`:0:ESCAPE:",
+ "`:1:ESCAPE:",
+ "a:001:r:",
+ "a:011:t:",
+ "a:100:l:",
+ "a:110:n:",
+ "a:0001:m:",
+ "a:0100:c:",
+ "a:1010:s:",
+ "a:1110:y:",
+ "a:10110: :",
+ "a:10111:d:",
+ "a:11110:i:",
+ "a:11111:k:",
+ "a:000010:b:",
+ "a:000011:STOP:",
+ "a:010110:p:",
+ "a:010111:g:",
+ "a:0000000:e:",
+ "a:0000001:':",
+ "a:0000011:w:",
+ "a:0101001:u:",
+ "a:0101010:z:",
+ "a:0101011:v:",
+ "a:00000101:f:",
+ "a:01010001:h:",
+ "a:000001001:0x3a:",
+ "a:0000010000:!:",
+ "a:0101000000:o:",
+ "a:0101000001:x:",
+ "a:00000100010:-:",
+ "a:00000100011:a:",
+ "a:01010000101:.:",
+ "a:01010000110:N:",
+ "a:01010000111:,:",
+ "a:010100001000:q:",
+ "a:0101000010010:j:",
+ "a:01010000100111:?:",
+ "a:010100001001101:J:",
+ "a:0101000010011000:ESCAPE:",
+ "a:0101000010011001:U:",
+ "b:000:r:",
+ "b:001:o:",
+ "b:010:e:",
+ "b:011:a:",
+ "b:100:i:",
+ "b:1011:u:",
+ "b:1100:y:",
+ "b:1101:l:",
+ "b:1111: :",
+ "b:10101:s:",
+ "b:11100:b:",
+ "b:11101:STOP:",
+ "b:101000:h:",
+ "b:1010010:3:",
+ "b:10100111:':",
+ "b:1010011001:t:",
+ "b:1010011010:j:",
+ "b:10100110000:n:",
+ "b:10100110001:d:",
+ "b:10100110111:w:",
+ "b:101001101101:m:",
+ "b:1010011011001:.:",
+ "b:10100110110000:ESCAPE:",
+ "b:10100110110001:0x3a:",
+ "c:00:k:",
+ "c:010:o:",
+ "c:100:h:",
+ "c:110:t:",
+ "c:111:e:",
+ "c:0111:r:",
+ "c:10100: :",
+ "c:10110:i:",
+ "c:10111:a:",
+ "c:011000:l:",
+ "c:011001:y:",
+ "c:011010:s:",
+ "c:011011:STOP:",
+ "c:1010100:c:",
+ "c:1010111:u:",
+ "c:10101010:0x3a:",
+ "c:10101011:P:",
+ "c:101011001:D:",
+ "c:1010110100:G:",
+ "c:1010110110:b:",
+ "c:10101100000:L:",
+ "c:10101100001:K:",
+ "c:10101100011:A:",
+ "c:10101101010:q:",
+ "c:10101101110:.:",
+ "c:10101101111:C:",
+ "c:101011000100:n:",
+ "c:101011000101:':",
+ "c:1010110101100:B:",
+ "c:1010110101101:I:",
+ "c:10101101011101:f:",
+ "c:10101101011110:8:",
+ "c:101011010111000:M:",
+ "c:101011010111001:ESCAPE:",
+ "c:101011010111111:F:",
+ "c:1010110101111100:w:",
+ "c:1010110101111101:Q:",
+ "d:11: :",
+ "d:001:e:",
+ "d:100:STOP:",
+ "d:101:a:",
+ "d:0001:y:",
+ "d:0100:i:",
+ "d:0110:s:",
+ "d:00000:o:",
+ "d:01010:d:",
+ "d:000011:u:",
+ "d:010110:r:",
+ "d:010111:l:",
+ "d:011101:v:",
+ "d:011110:g:",
+ "d:0000100:':",
+ "d:0111111:.:",
+ "d:00001010:0x3a:",
+ "d:00001011:h:",
+ "d:01110000:c:",
+ "d:01110010:n:",
+ "d:01110011:w:",
+ "d:011100010:?:",
+ "d:011111000:!:",
+ "d:011111001:-:",
+ "d:011111010:f:",
+ "d:0111000111:m:",
+ "d:0111110110:,:",
+ "d:01111101110:t:",
+ "d:01111101111:b:",
+ "d:011100011001:):",
+ "d:011100011010:/:",
+ "d:011100011011:k:",
+ "d:0111000110001:p:",
+ "d:01110001100001:z:",
+ "d:011100011000000:ESCAPE:",
+ "d:011100011000001:4:",
+ "e:01: :",
+ "e:000:s:",
+ "e:101:r:",
+ "e:0010:t:",
+ "e:1001:n:",
+ "e:1100:STOP:",
+ "e:1110:a:",
+ "e:1111:w:",
+ "e:10000:l:",
+ "e:11011:e:",
+ "e:001110:m:",
+ "e:100010:c:",
+ "e:100011:d:",
+ "e:0011010:i:",
+ "e:0011011:p:",
+ "e:0011110:b:",
+ "e:1101000:v:",
+ "e:1101011:y:",
+ "e:00110000:g:",
+ "e:00110001:f:",
+ "e:00110010:x:",
+ "e:00111110:k:",
+ "e:00111111:0x3a:",
+ "e:11010011:o:",
+ "e:11010100:':",
+ "e:001100111:h:",
+ "e:110100101:.:",
+ "e:0011001100:P:",
+ "e:0011001101:B:",
+ "e:1101001000:,:",
+ "e:1101010100:V:",
+ "e:1101010101:z:",
+ "e:1101010111:j:",
+ "e:11010010010:4:",
+ "e:11010010011:?:",
+ "e:11010101101:u:",
+ "e:110101011001:-:",
+ "e:1101010110001:!:",
+ "e:11010101100001:q:",
+ "e:110101011000001:G:",
+ "e:1101010110000000:ESCAPE:",
+ "e:1101010110000001:S:",
+ "f:0: :",
+ "f:101:o:",
+ "f:1001:t:",
+ "f:1100:a:",
+ "f:1101:i:",
+ "f:1111:e:",
+ "f:10000:.:",
+ "f:11100:r:",
+ "f:11101:f:",
+ "f:100010:STOP:",
+ "f:10001101:y:",
+ "f:10001111:u:",
+ "f:100011000:':",
+ "f:100011101:l:",
+ "f:1000110011:n:",
+ "f:1000111000:g:",
+ "f:10001100100:c:",
+ "f:10001110010:-:",
+ "f:100011001010:,:",
+ "f:100011001011:s:",
+ "f:100011100111:0x3a:",
+ "f:1000111001101:k:",
+ "f:10001110011000:ESCAPE:",
+ "f:10001110011001:b:",
+ "g:00:h:",
+ "g:10: :",
+ "g:010:STOP:",
+ "g:011:e:",
+ "g:1100:i:",
+ "g:11100:0x3a:",
+ "g:11101:r:",
+ "g:11111:a:",
+ "g:110100:s:",
+ "g:110111:l:",
+ "g:111101:u:",
+ "g:1101011:b:",
+ "g:1101100:g:",
+ "g:1101101:o:",
+ "g:1111001:n:",
+ "g:11010100:2:",
+ "g:11110000:!:",
+ "g:111100011:d:",
+ "g:1101010100:.:",
+ "g:1101010101:,:",
+ "g:1101010110:':",
+ "g:1101010111:t:",
+ "g:1111000101:y:",
+ "g:11110001000:w:",
+ "g:111100010011:m:",
+ "g:11110001001011:?:",
+ "g:111100010010000:p:",
+ "g:111100010010001:f:",
+ "g:111100010010010:@:",
+ "g:111100010010011:-:",
+ "g:111100010010101:;:",
+ "g:1111000100101000:ESCAPE:",
+ "g:1111000100101001:z:",
+ "h:0:e:",
+ "h:101:o:",
+ "h:1001:i:",
+ "h:1100:a:",
+ "h:1110: :",
+ "h:1111:t:",
+ "h:11010:r:",
+ "h:11011:STOP:",
+ "h:100000:b:",
+ "h:100001:u:",
+ "h:10001000:w:",
+ "h:10001001:d:",
+ "h:10001010:n:",
+ "h:10001011:y:",
+ "h:10001100:!:",
+ "h:10001101:l:",
+ "h:10001111:.:",
+ "h:100011100:':",
+ "h:1000111010:s:",
+ "h:10001110110:m:",
+ "h:100011101111:0x3a:",
+ "h:10001110111000:f:",
+ "h:10001110111001:?:",
+ "h:10001110111010:c:",
+ "h:1000111011101100:v:",
+ "h:1000111011101101:q:",
+ "h:1000111011101110:g:",
+ "h:100011101110111100:h:",
+ "h:100011101110111101:ESCAPE:",
+ "h:100011101110111110:,:",
+ "h:100011101110111111:*:",
+ "i:01:n:",
+ "i:000:c:",
+ "i:1001:o:",
+ "i:1010:l:",
+ "i:1100:g:",
+ "i:1101:s:",
+ "i:1110:t:",
+ "i:1111:e:",
+ "i:00101:a:",
+ "i:00110:v:",
+ "i:10000:r:",
+ "i:10001:d:",
+ "i:10110:m:",
+ "i:001000:p:",
+ "i:001110: :",
+ "i:101111:f:",
+ "i:0011110:z:",
+ "i:0011111:STOP:",
+ "i:1011100:b:",
+ "i:1011101:k:",
+ "i:00100101:-:",
+ "i:00100110:x:",
+ "i:001001001:':",
+ "i:001001111:q:",
+ "i:0010011100:u:",
+ "i:0010011101:i:",
+ "i:00100100001:h:",
+ "i:00100100010:0x3a:",
+ "i:00100100011:w:",
+ "i:0010010000001:,:",
+ "i:0010010000010:y:",
+ "i:0010010000011:/:",
+ "i:00100100000000:.:",
+ "i:001001000000010:ESCAPE:",
+ "i:001001000000011:j:",
+ "j:0:y:",
+ "j:11:o:",
+ "j:101:e:",
+ "j:1001:a:",
+ "j:10001:u:",
+ "j:100001:i:",
+ "j:1000000:STOP:",
+ "j:10000010:ESCAPE:",
+ "j:10000011: :",
+ "k:00: :",
+ "k:10:e:",
+ "k:010:i:",
+ "k:110:STOP:",
+ "k:0110:y:",
+ "k:0111:s:",
+ "k:1111:f:",
+ "k:111001:a:",
+ "k:111010:l:",
+ "k:1110001:0x3a:",
+ "k:1110110:k:",
+ "k:11100000:':",
+ "k:11101111:.:",
+ "k:111000011:w:",
+ "k:111011100:o:",
+ "k:1110000101:h:",
+ "k:11100001000:b:",
+ "k:11100001001:,:",
+ "k:11101110111:n:",
+ "k:111011101010:?:",
+ "k:111011101100:m:",
+ "k:111011101101:!:",
+ "k:1110111010010:u:",
+ "k:1110111010011:c:",
+ "k:1110111010110:d:",
+ "k:1110111010111:t:",
+ "k:11101110100001:j:",
+ "k:11101110100010:-:",
+ "k:111011101000000:p:",
+ "k:111011101000001:/:",
+ "k:111011101000111:S:",
+ "k:1110111010001100:ESCAPE:",
+ "k:1110111010001101:r:",
+ "l:01:e:",
+ "l:000:l:",
+ "l:101:a:",
+ "l:0011:y:",
+ "l:1000:STOP:",
+ "l:1001:d:",
+ "l:1100:o:",
+ "l:1110:i:",
+ "l:1111: :",
+ "l:00100:u:",
+ "l:11010:s:",
+ "l:001010:t:",
+ "l:001011:m:",
+ "l:1101101:k:",
+ "l:11011000:f:",
+ "l:11011100:b:",
+ "l:11011110:':",
+ "l:11011111:c:",
+ "l:110110011:v:",
+ "l:110111010:0x3a:",
+ "l:1101100101:.:",
+ "l:1101110110:w:",
+ "l:11011001000:z:",
+ "l:11011101111:p:",
+ "l:110110010010:h:",
+ "l:110110010011:*:",
+ "l:1101110111000:g:",
+ "l:1101110111001:,:",
+ "l:11011101110100:r:",
+ "l:11011101110101:n:",
+ "l:11011101110111:-:",
+ "l:110111011101100:!:",
+ "l:1101110111011011:?:",
+ "l:11011101110110101:C:",
+ "l:110111011101101000:ESCAPE:",
+ "l:110111011101101001:j:",
+ "m:10:e:",
+ "m:001:m:",
+ "m:011: :",
+ "m:111:a:",
+ "m:0000:i:",
+ "m:0001:STOP:",
+ "m:0100:y:",
+ "m:1101:p:",
+ "m:01010:b:",
+ "m:11000:o:",
+ "m:110010:n:",
+ "m:110011:s:",
+ "m:0101100:l:",
+ "m:0101110:f:",
+ "m:01011010:0x3a:",
+ "m:01011110:4:",
+ "m:010110110:h:",
+ "m:010111110:w:",
+ "m:0101101111:':",
+ "m:0101111110:r:",
+ "m:0101111111:u:",
+ "m:01011011101:.:",
+ "m:010110111001:k:",
+ "m:0101101110000:ESCAPE:",
+ "m:0101101110001:d:",
+ "n:000:i:",
+ "n:100:g:",
+ "n:101: :",
+ "n:110:d:",
+ "n:0011:a:",
+ "n:0100:s:",
+ "n:0110:e:",
+ "n:1110:STOP:",
+ "n:1111:t:",
+ "n:01110:c:",
+ "n:01111:n:",
+ "n:001010:y:",
+ "n:010100:':",
+ "n:010101:k:",
+ "n:010111:o:",
+ "n:0010000:r:",
+ "n:0010011:f:",
+ "n:0010110:u:",
+ "n:0010111:j:",
+ "n:00100010:v:",
+ "n:00100100:-:",
+ "n:00100101:.:",
+ "n:01011000:l:",
+ "n:01011010:x:",
+ "n:01011011:0x3a:",
+ "n:001000111:,:",
+ "n:010110011:m:",
+ "n:0010001100:!:",
+ "n:00100011010:z:",
+ "n:01011001001:?:",
+ "n:01011001010:h:",
+ "n:01011001011:b:",
+ "n:001000110110:B:",
+ "n:001000110111:*:",
+ "n:010110010000:w:",
+ "n:0101100100011:q:",
+ "n:01011001000101:p:",
+ "n:010110010001000:;:",
+ "n:0101100100010010:/:",
+ "n:0101100100010011:ESCAPE:",
+ "o:00:r:",
+ "o:110:n:",
+ "o:0100:f:",
+ "o:0101: :",
+ "o:0110:w:",
+ "o:1000:o:",
+ "o:1011:u:",
+ "o:01111:t:",
+ "o:10010:c:",
+ "o:10100:p:",
+ "o:10101:d:",
+ "o:11100:m:",
+ "o:11110:l:",
+ "o:011100:a:",
+ "o:011101:b:",
+ "o:100110:y:",
+ "o:100111:STOP:",
+ "o:111010:s:",
+ "o:111011:k:",
+ "o:1111101:v:",
+ "o:1111110:g:",
+ "o:11111111:i:",
+ "o:111110001:h:",
+ "o:111110010:!:",
+ "o:111111100:e:",
+ "o:111111101:j:",
+ "o:1111100110:':",
+ "o:11111000001:?:",
+ "o:11111000010:0x3a:",
+ "o:11111001110:z:",
+ "o:11111001111:x:",
+ "o:111110000000:J:",
+ "o:111110000110:.:",
+ "o:111110000111:-:",
+ "o:11111000000100:4:",
+ "o:11111000000110:,:",
+ "o:11111000000111:G:",
+ "o:111110000001011:):",
+ "o:1111100000010100:S:",
+ "o:11111000000101010:D:",
+ "o:111110000001010110:ESCAPE:",
+ "o:111110000001010111:q:",
+ "p:00:e:",
+ "p:010:STOP:",
+ "p:100:i:",
+ "p:110:o:",
+ "p:0110:s:",
+ "p:1010: :",
+ "p:1110:p:",
+ "p:01110:l:",
+ "p:01111:r:",
+ "p:10110:h:",
+ "p:11110:a:",
+ "p:101110:t:",
+ "p:101111:':",
+ "p:1111100:d:",
+ "p:1111101:m:",
+ "p:1111110:y:",
+ "p:111111101:0x3a:",
+ "p:111111111:!:",
+ "p:1111111100:w:",
+ "p:1111111101:u:",
+ "p:11111110000:b:",
+ "p:11111110010:-:",
+ "p:11111110011:.:",
+ "p:111111100011:n:",
+ "p:1111111000101:k:",
+ "p:11111110001001:,:",
+ "p:111111100010000:ESCAPE:",
+ "p:111111100010001:c:",
+ "q:1:u:",
+ "q:01:STOP:",
+ "q:001:0x3a:",
+ "q:0000:ESCAPE:",
+ "q:0001:':",
+ "r:000: :",
+ "r:011:i:",
+ "r:101:e:",
+ "r:0011:y:",
+ "r:0100:d:",
+ "r:1000:s:",
+ "r:1001:t:",
+ "r:1100:a:",
+ "r:1101:STOP:",
+ "r:1111:o:",
+ "r:01011:n:",
+ "r:11101:l:",
+ "r:001001:k:",
+ "r:001010:r:",
+ "r:001011:m:",
+ "r:010101:u:",
+ "r:111001:g:",
+ "r:0010000:':",
+ "r:0101001:c:",
+ "r:1110001:0x3a:",
+ "r:00100010:f:",
+ "r:00100011:.:",
+ "r:01010001:b:",
+ "r:11100000:v:",
+ "r:010100000:,:",
+ "r:010100001:p:",
+ "r:111000010:w:",
+ "r:1110000111:j:",
+ "r:11100001100:-:",
+ "r:111000011010:h:",
+ "r:1110000110110:G:",
+ "r:11100001101110:q:",
+ "r:111000011011111:S:",
+ "r:1110000110111100:!:",
+ "r:111000011011110100:*:",
+ "r:111000011011110110:T:",
+ "r:1110000110111101010:ESCAPE:",
+ "r:1110000110111101011:E:",
+ "r:1110000110111101110:1:",
+ "r:1110000110111101111:/:",
+ "s:10: :",
+ "s:11:STOP:",
+ "s:011:t:",
+ "s:0000:s:",
+ "s:0010:i:",
+ "s:0011:h:",
+ "s:00011:;:",
+ "s:01010:e:",
+ "s:010001:o:",
+ "s:010011:c:",
+ "s:010110:0x3a:",
+ "s:0001000:.:",
+ "s:0001001:!:",
+ "s:0001011:y:",
+ "s:0100000:p:",
+ "s:0100100:a:",
+ "s:0101111:u:",
+ "s:00010100:,:",
+ "s:00010101:f:",
+ "s:01000011:':",
+ "s:01001011:n:",
+ "s:01011100:l:",
+ "s:01011101:r:",
+ "s:010000101:k:",
+ "s:010010100:d:",
+ "s:0100001001:m:",
+ "s:0100101011:b:",
+ "s:01000010000:?:",
+ "s:01000010001:w:",
+ "s:01001010100:g:",
+ "s:010010101010:q:",
+ "s:01001010101101:E:",
+ "s:01001010101110:-:",
+ "s:010010101011000:ESCAPE:",
+ "s:010010101011001:):",
+ "s:010010101011110:W:",
+ "s:010010101011111:1:",
+ "t:000:i:",
+ "t:011:STOP:",
+ "t:100: :",
+ "t:111:h:",
+ "t:0010:a:",
+ "t:0100:r:",
+ "t:1010:s:",
+ "t:1011:o:",
+ "t:1101:e:",
+ "t:00111:t:",
+ "t:01010:y:",
+ "t:11000:u:",
+ "t:010110:m:",
+ "t:110010:c:",
+ "t:110011:l:",
+ "t:0011000:':",
+ "t:0011010:0x3a:",
+ "t:00110010:w:",
+ "t:00110110:!:",
+ "t:01011100:.:",
+ "t:01011101:b:",
+ "t:01011110:E:",
+ "t:01011111:f:",
+ "t:001100110:?:",
+ "t:001101110:n:",
+ "t:0011001110:z:",
+ "t:0011011110:d:",
+ "t:00110011111:,:",
+ "t:00110111110:P:",
+ "t:001100111100:v:",
+ "t:001100111101:-:",
+ "t:001101111110:):",
+ "t:0011011111110:g:",
+ "t:00110111111110:ESCAPE:",
+ "t:001101111111110:S:",
+ "t:0011011111111111:4:",
+ "t:00110111111111100:k:",
+ "t:001101111111111010:j:",
+ "t:001101111111111011:p:",
+ "u:00:r:",
+ "u:100:s:",
+ "u:111:n:",
+ "u:0100:e:",
+ "u:0101:m:",
+ "u:1100:t:",
+ "u:01100:c:",
+ "u:01101:g:",
+ "u:01110:b:",
+ "u:10100:p:",
+ "u:10101:i:",
+ "u:10110:l:",
+ "u:11010:d:",
+ "u:11011:a:",
+ "u:011110:STOP:",
+ "u:101110:y:",
+ "u:0111110:z:",
+ "u:1011110: :",
+ "u:01111111:':",
+ "u:10111110:-:",
+ "u:011111100:k:",
+ "u:101111111:0x3a:",
+ "u:0111111010:f:",
+ "u:0111111011:,:",
+ "u:1011111100:w:",
+ "u:101111110100:v:",
+ "u:101111110101:x:",
+ "u:101111110111:o:",
+ "u:1011111101100:j:",
+ "u:10111111011010:u:",
+ "u:101111110110110:.:",
+ "u:1011111101101111:h:",
+ "u:10111111011011100:?:",
+ "u:10111111011011101:ESCAPE:",
+ "v:1:e:",
+ "v:01:i:",
+ "v:001:a:",
+ "v:0001:o:",
+ "v:00000: :",
+ "v:000011:STOP:",
+ "v:0000100:y:",
+ "v:00001011:s:",
+ "v:000010101:r:",
+ "v:0000101000:ESCAPE:",
+ "v:0000101001:.:",
+ "w:0:s:",
+ "w:100: :",
+ "w:110:STOP:",
+ "w:1011:i:",
+ "w:1110:o:",
+ "w:10100:a:",
+ "w:11110:n:",
+ "w:11111:e:",
+ "w:1010111:y:",
+ "w:10101000:m:",
+ "w:10101011:d:",
+ "w:10101101:l:",
+ "w:101010011:b:",
+ "w:101010100:k:",
+ "w:101010101:r:",
+ "w:1010100100:j:",
+ "w:1010110001:,:",
+ "w:1010110011:h:",
+ "w:10101001011:-:",
+ "w:10101100000:c:",
+ "w:10101100001:f:",
+ "w:10101100101:p:",
+ "w:101010010100:g:",
+ "w:101011001000:t:",
+ "w:1010100101010:.:",
+ "w:1010100101011:0x3a:",
+ "w:1010110010011:q:",
+ "w:10101100100101:':",
+ "w:101011001001001:?:",
+ "w:1010110010010000:ESCAPE:",
+ "w:1010110010010001:B:",
+ "x:00:p:",
+ "x:10: :",
+ "x:11:t:",
+ "x:0110:STOP:",
+ "x:01000:o:",
+ "x:01010:c:",
+ "x:01110:i:",
+ "x:01111:m:",
+ "x:010010:e:",
+ "x:010110:y:",
+ "x:0100110:u:",
+ "x:0100111:f:",
+ "x:0101111:,:",
+ "x:010111000:g:",
+ "x:010111001:a:",
+ "x:010111011:9:",
+ "x:0101110101:':",
+ "x:01011101001:x:",
+ "x:010111010000:ESCAPE:",
+ "x:010111010001:s:",
+ "y:0: :",
+ "y:11:STOP:",
+ "y:10001:o:",
+ "y:10010:s:",
+ "y:10100:a:",
+ "y:10110:l:",
+ "y:10111:0x3a:",
+ "y:100110:d:",
+ "y:1000001:n:",
+ "y:1000010:t:",
+ "y:1010100:':",
+ "y:1010101:b:",
+ "y:1010111:.:",
+ "y:10000000:i:",
+ "y:10000110:,:",
+ "y:10000111:p:",
+ "y:10011100:m:",
+ "y:10011110:c:",
+ "y:10101100:w:",
+ "y:10101101:e:",
+ "y:100000010:?:",
+ "y:100000011:f:",
+ "y:100111010:r:",
+ "y:100111011:g:",
+ "y:1001111100:z:",
+ "y:1001111110:-:",
+ "y:1001111111:T:",
+ "y:100111110100:2:",
+ "y:100111110110:!:",
+ "y:100111110111:k:",
+ "y:1001111101010:v:",
+ "y:10011111010110:y:",
+ "y:100111110101110:h:",
+ "y:1001111101011111:j:",
+ "y:10011111010111100:ESCAPE:",
+ "y:10011111010111101:):",
+ "z:00:z:",
+ "z:01:STOP:",
+ "z:101:i:",
+ "z:1000:y:",
+ "z:1001:e:",
+ "z:1100:w:",
+ "z:1101: :",
+ "z:1110:l:",
+ "z:11110:a:",
+ "z:111110:o:",
+ "z:11111100:m:",
+ "z:11111101:0x3a:",
+ "z:11111111:c:",
+ "z:111111100:,:",
+ "z:1111111011:b:",
+ "z:11111110100:u:",
+ "z:111111101011:!:",
+ "z:11111110101000:ESCAPE:",
+ "z:11111110101001:t:",
+ "z:11111110101010:h:",
+ "z:11111110101011:?:",
+ "{:0:ESCAPE:",
+ "{:1:ESCAPE:",
+ "|:0:ESCAPE:",
+ "|:1:ESCAPE:",
+ "}:0:ESCAPE:",
+ "}:1:ESCAPE:",
+ "~:0:ESCAPE:",
+ "~:1:ESCAPE:",
+ "0x7f:0:ESCAPE:",
+ "0x7f:1:ESCAPE:",
+ NULL
+};
+
+static const char *FreesatT2[] = {
+ "START:010:A:",
+ "START:100:C:",
+ "START:111:T:",
+ "START:0001:J:",
+ "START:0011:D:",
+ "START:1010:S:",
+ "START:00000:H:",
+ "START:00100:I:",
+ "START:00101:R:",
+ "START:01101:F:",
+ "START:01110:.:",
+ "START:01111:W:",
+ "START:10111:M:",
+ "START:11000:B:",
+ "START:11001:P:",
+ "START:11011:N:",
+ "START:000010:O:",
+ "START:011001:[:",
+ "START:101101:L:",
+ "START:110101:E:",
+ "START:0000110:K:",
+ "START:1101000:Y:",
+ "START:1101001:G:",
+ "START:00001110:2:",
+ "START:01100000:p:",
+ "START:01100001:b:",
+ "START:01100010:U:",
+ "START:01100011:(:",
+ "START:10110000:1:",
+ "START:10110011:V:",
+ "START:000011110:Q:",
+ "START:101100010:3:",
+ "START:0000111110:9:",
+ "START:0000111111:8:",
+ "START:1011000110:6:",
+ "START:1011000111:5:",
+ "START:1011001000:Z:",
+ "START:1011001001:7:",
+ "START:1011001010:4:",
+ "START:101100101110:X:",
+ "START:101100101111: :",
+ "START:1011001011001:w:",
+ "START:1011001011010:':",
+ "START:1011001011011:\":",
+ "START:10110010110000:t:",
+ "START:101100101100010:a:",
+ "START:1011001011000110:`:",
+ "START:10110010110001110:ESCAPE:",
+ "START:10110010110001111:m:",
+ "ESCAPE:0:ESCAPE:",
+ "ESCAPE:1:ESCAPE:",
+ "STOP:0:ESCAPE:",
+ "STOP:1:ESCAPE:",
+ "0x03:0:ESCAPE:",
+ "0x03:1:ESCAPE:",
+ "0x04:0:ESCAPE:",
+ "0x04:1:ESCAPE:",
+ "0x05:0:ESCAPE:",
+ "0x05:1:ESCAPE:",
+ "0x06:0:ESCAPE:",
+ "0x06:1:ESCAPE:",
+ "0x07:0:ESCAPE:",
+ "0x07:1:ESCAPE:",
+ "0x08:0:ESCAPE:",
+ "0x08:1:ESCAPE:",
+ "0x09:0:ESCAPE:",
+ "0x09:1:ESCAPE:",
+ "0x0a:0:ESCAPE:",
+ "0x0a:1:ESCAPE:",
+ "0x0b:0:ESCAPE:",
+ "0x0b:1:ESCAPE:",
+ "0x0c:0:ESCAPE:",
+ "0x0c:1:ESCAPE:",
+ "0x0d:0:ESCAPE:",
+ "0x0d:1:ESCAPE:",
+ "0x0e:0:ESCAPE:",
+ "0x0e:1:ESCAPE:",
+ "0x0f:0:ESCAPE:",
+ "0x0f:1:ESCAPE:",
+ "0x10:0:ESCAPE:",
+ "0x10:1:ESCAPE:",
+ "0x11:0:ESCAPE:",
+ "0x11:1:ESCAPE:",
+ "0x12:0:ESCAPE:",
+ "0x12:1:ESCAPE:",
+ "0x13:0:ESCAPE:",
+ "0x13:1:ESCAPE:",
+ "0x14:0:ESCAPE:",
+ "0x14:1:ESCAPE:",
+ "0x15:0:ESCAPE:",
+ "0x15:1:ESCAPE:",
+ "0x16:0:ESCAPE:",
+ "0x16:1:ESCAPE:",
+ "0x17:0:ESCAPE:",
+ "0x17:1:ESCAPE:",
+ "0x18:0:ESCAPE:",
+ "0x18:1:ESCAPE:",
+ "0x19:0:ESCAPE:",
+ "0x19:1:ESCAPE:",
+ "0x1a:0:ESCAPE:",
+ "0x1a:1:ESCAPE:",
+ "0x1b:0:ESCAPE:",
+ "0x1b:1:ESCAPE:",
+ "0x1c:0:ESCAPE:",
+ "0x1c:1:ESCAPE:",
+ "0x1d:0:ESCAPE:",
+ "0x1d:1:ESCAPE:",
+ "0x1e:0:ESCAPE:",
+ "0x1e:1:ESCAPE:",
+ "0x1f:0:ESCAPE:",
+ "0x1f:1:ESCAPE:",
+ " :010:a:",
+ " :100:t:",
+ " :0001:o:",
+ " :0010:s:",
+ " :00110:d:",
+ " :01100:[:",
+ " :01111:p:",
+ " :10101:b:",
+ " :11001:c:",
+ " :11010:h:",
+ " :11100:w:",
+ " :11101:i:",
+ " :11111:f:",
+ " :000000:A:",
+ " :000011:M:",
+ " :001111:e:",
+ " :011100:B:",
+ " :011101:C:",
+ " :101000:T:",
+ " :101101:S:",
+ " :101110:g:",
+ " :110000:r:",
+ " :110110:n:",
+ " :110111:l:",
+ " :111101:m:",
+ " :0000011:v:",
+ " :0000100:G:",
+ " :0000101:N:",
+ " :0011101:y:",
+ " :0110101:H:",
+ " :0110111:L:",
+ " :1010010:J:",
+ " :1010011:F:",
+ " :1011001:R:",
+ " :1011110:u:",
+ " :1100010:D:",
+ " :1100011:W:",
+ " :1111001:P:",
+ " :00000100:k:",
+ " :00000101:O:",
+ " :01101000:-:",
+ " :01101101:1:",
+ " :10110001:K:",
+ " :10111110:j:",
+ " :11110000:I:",
+ " :11110001:E:",
+ " :001110010:q:",
+ " :001110011:U:",
+ " :011010010:V:",
+ " :011011000:Y:",
+ " :011011001: :",
+ " :101100001:2:",
+ " :101111110:STOP:",
+ " :0011100000:3:",
+ " :0011100001:8:",
+ " :0011100010:6:",
+ " :0110100111:5:",
+ " :1011000000:(:",
+ " :1011111110:7:",
+ " :00111000110:0:",
+ " :01101001100:':",
+ " :01101001101:9:",
+ " :10110000010:Z:",
+ " :10111111110:4:",
+ " :10111111111:Q:",
+ " :001110001111:X:",
+ " :1011000001100:ESCAPE:",
+ " :1011000001101:.:",
+ " :1011000001110:&:",
+ " :00111000111000:\\:",
+ " :00111000111010:@:",
+ " :00111000111011:`:",
+ " :10110000011110:\":",
+ " :10110000011111:z:",
+ " :001110001110011:$:",
+ " :0011100011100100:+:",
+ " :00111000111001011:x:",
+ " :001110001110010101:]:",
+ " :0011100011100101000:/:",
+ " :0011100011100101001:?:",
+ "!:1: :",
+ "!:01:STOP:",
+ "!:001:.:",
+ "!:0000:0x3a:",
+ "!:00011:[:",
+ "!:0001001:\":",
+ "!:0001010:/:",
+ "!:0001011:!:",
+ "!:00010000:):",
+ "!:000100010:':",
+ "!:0001000111:?:",
+ "!:00010001100:ESCAPE:",
+ "!:00010001101:]:",
+ "\":11: :",
+ "\":001:.:",
+ "\":0000:p:",
+ "\":0101:B:",
+ "\":0111:T:",
+ "\":1000:i:",
+ "\":00010:f:",
+ "\":00011:W:",
+ "\":01000:S:",
+ "\":01100:t:",
+ "\":01101:C:",
+ "\":10100:STOP:",
+ "\":10111:,:",
+ "\":010010:J:",
+ "\":100100:m:",
+ "\":101010:n:",
+ "\":101011:I:",
+ "\":0100110:E:",
+ "\":0100111:D:",
+ "\":1001010:w:",
+ "\":1001011:g:",
+ "\":1001100:b:",
+ "\":1001101:L:",
+ "\":1001110:-:",
+ "\":1011000:c:",
+ "\":1011001:H:",
+ "\":10011110:P:",
+ "\":10110100:r:",
+ "\":10110111:K:",
+ "\":100111111:l:",
+ "\":101101010:Y:",
+ "\":101101011:Q:",
+ "\":101101100:G:",
+ "\":101101101:A:",
+ "\":1001111100:ESCAPE:",
+ "\":1001111101:a:",
+ "#:0:ESCAPE:",
+ "#:1:ESCAPE:",
+ "$:0:1:",
+ "$:11:3:",
+ "$:100:4:",
+ "$:1011:2:",
+ "$:10101:7:",
+ "$:101001:5:",
+ "$:1010000:ESCAPE:",
+ "$:1010001:9:",
+ "%:1: :",
+ "%:00:ESCAPE:",
+ "%:01:,:",
+ "&:1: :",
+ "&:01:w:",
+ "&:001:B:",
+ "&:0000:E:",
+ "&:000100:2:",
+ "&:000110:A:",
+ "&:000111:R:",
+ "&:00010100:O:",
+ "&:00010101:4:",
+ "&:00010111:J:",
+ "&:000101100:ESCAPE:",
+ "&:000101101:P:",
+ "':1:s:",
+ "':001:t:",
+ "':010: :",
+ "':0000:l:",
+ "':01101:r:",
+ "':000100:n:",
+ "':000101:.:",
+ "':000110:C:",
+ "':011000:B:",
+ "':011101:A:",
+ "':0111000:d:",
+ "':0111100:v:",
+ "':00011100:S:",
+ "':00011111:p:",
+ "':01100101:D:",
+ "':01111011:i:",
+ "':01111100:c:",
+ "':01111101:m:",
+ "':01111111:,:",
+ "':000111010:f:",
+ "':000111011:g:",
+ "':011001000:F:",
+ "':011001001:h:",
+ "':011001101:H:",
+ "':011001110:N:",
+ "':011100101:R:",
+ "':011100110:STOP:",
+ "':011100111:T:",
+ "':011110101:G:",
+ "':011111101:L:",
+ "':0001111000:o:",
+ "':0001111001:K:",
+ "':0001111011:a:",
+ "':0110011001:u:",
+ "':0110011111:O:",
+ "':0111001001:I:",
+ "':0111101000:w:",
+ "':0111101001:b:",
+ "':0111111001:e:",
+ "':00011110101:?:",
+ "':01100110000:E:",
+ "':01100110001:7:",
+ "':01110010000:P:",
+ "':000111101001:W:",
+ "':011001111001:0x3a:",
+ "':011001111010:!:",
+ "':011100100011:J:",
+ "':011111100001:q:",
+ "':011111100011:M:",
+ "':0001111010001:V:",
+ "':0110011110001:9:",
+ "':0110011110111:y:",
+ "':0111001000100:8:",
+ "':0111001000101:5:",
+ "':0111111000000:6:",
+ "':0111111000101:k:",
+ "':00011110100000:2:",
+ "':00011110100001:0:",
+ "':01100111100001:Y:",
+ "':01100111101100:):",
+ "':01111110000010:j:",
+ "':01111110000011:Q:",
+ "':011001111000000:-:",
+ "':011001111000001:':",
+ "':011001111011011:z:",
+ "':011111100010000:X:",
+ "':011111100010001:U:",
+ "':011111100010010:4:",
+ "':011111100010011:3:",
+ "':0110011110110100:ESCAPE:",
+ "':0110011110110101:1:",
+ "(:01:1:",
+ "(:000:P:",
+ "(:101:t:",
+ "(:1000:2:",
+ "(:1101:5:",
+ "(:1110:N:",
+ "(:00111:T:",
+ "(:10010:p:",
+ "(:11111:c:",
+ "(:001001:a:",
+ "(:001010:S:",
+ "(:001100:R:",
+ "(:100111:e:",
+ "(:111100:J:",
+ "(:111101:A:",
+ "(:0010110:D:",
+ "(:0011011:K:",
+ "(:1001100:v:",
+ "(:1001101:s:",
+ "(:1100000:b:",
+ "(:1100010:G:",
+ "(:1100011:8:",
+ "(:1100100:M:",
+ "(:1100101:H:",
+ "(:1100110:C:",
+ "(:00100000:m:",
+ "(:00100010:o:",
+ "(:00100011:E:",
+ "(:00101110:W:",
+ "(:11000011:g:",
+ "(:11001110:L:",
+ "(:001000010:d:",
+ "(:001011111:U:",
+ "(:001101000:F:",
+ "(:001101010:f:",
+ "(:110000100:w:",
+ "(:110000101:B:",
+ "(:110011111:n:",
+ "(:0010000110:l:",
+ "(:0010000111:9:",
+ "(:0010111100:4:",
+ "(:0010111101:I:",
+ "(:0011010010:3:",
+ "(:0011010111:h:",
+ "(:1100111101:i:",
+ "(:00110100110:Z:",
+ "(:00110100111:V:",
+ "(:00110101100: :",
+ "(:11001111000:k:",
+ "(:001101011011:O:",
+ "(:110011110010:':",
+ "(:0011010110100:ESCAPE:",
+ "(:0011010110101:u:",
+ "(:1100111100110:X:",
+ "(:1100111100111:7:",
+ "):0: :",
+ "):11:.:",
+ "):101:STOP:",
+ "):1001:,:",
+ "):10000:0x3a:",
+ "):100011:;:",
+ "):1000101:!:",
+ "):10001001:(:",
+ "):1000100000:ESCAPE:",
+ "):1000100001:o:",
+ "):1000100010:?:",
+ "):1000100011:):",
+ "*:0:*:",
+ "*:100:s:",
+ "*:101: :",
+ "*:1100:m:",
+ "*:1110:t:",
+ "*:11010:g:",
+ "*:11011:k:",
+ "*:11111:d:",
+ "*:111101:y:",
+ "*:1111001:e:",
+ "*:11110000:i:",
+ "*:111100010:ESCAPE:",
+ "*:111100011:n:",
+ "+:1:n:",
+ "+:00:ESCAPE:",
+ "+:01: :",
+ ",:1: :",
+ ",:01:S:",
+ ",:001:0:",
+ ",:0001:A:",
+ ",:00000:5:",
+ ",:0000110:b:",
+ ",:0000111:3:",
+ ",:00001000:2:",
+ ",:00001001:\":",
+ ",:00001011:1:",
+ ",:0000101000:Q:",
+ ",:0000101010:':",
+ ",:00001010111:4:",
+ ",:000010100100:T:",
+ ",:000010100101:B:",
+ ",:000010100110:7:",
+ ",:000010100111:6:",
+ ",:000010101100:STOP:",
+ ",:0000101011010:ESCAPE:",
+ ",:0000101011011:i:",
+ "-:00: :",
+ "-:0100:t:",
+ "-:0101:b:",
+ "-:0110:w:",
+ "-:0111:u:",
+ "-:1001:o:",
+ "-:1010:s:",
+ "-:1011:f:",
+ "-:10000:c:",
+ "-:11011:l:",
+ "-:11101:d:",
+ "-:100010:9:",
+ "-:110000:h:",
+ "-:110010:1:",
+ "-:110011:y:",
+ "-:110101:r:",
+ "-:111000:a:",
+ "-:111100:m:",
+ "-:111110:p:",
+ "-:1000110:S:",
+ "-:1101000:e:",
+ "-:1101001:i:",
+ "-:1111011:n:",
+ "-:10001110:C:",
+ "-:11000101:W:",
+ "-:11000111:g:",
+ "-:11100101:J:",
+ "-:11100110:D:",
+ "-:11110101:2:",
+ "-:11111100:7:",
+ "-:11111110:G:",
+ "-:11111111:O:",
+ "-:100011111:H:",
+ "-:110001000:A:",
+ "-:110001100:6:",
+ "-:110001101:B:",
+ "-:111001111:M:",
+ "-:111101000:E:",
+ "-:111101001:L:",
+ "-:111111010:U:",
+ "-:111111011:k:",
+ "-:1000111100:F:",
+ "-:1100010010:j:",
+ "-:1100010011:P:",
+ "-:1110010001:q:",
+ "-:1110010010:5:",
+ "-:1110010011:T:",
+ "-:1110011101:I:",
+ "-:10001111011:K:",
+ "-:11100100000:v:",
+ "-:11100100001:Z:",
+ "-:11100111001:N:",
+ "-:100011110101:R:",
+ "-:111001110001:Y:",
+ "-:1000111101001:0:",
+ "-:10001111010000:4:",
+ "-:10001111010001:z:",
+ "-:11100111000001:V:",
+ "-:11100111000010:3:",
+ "-:11100111000011:8:",
+ "-:111001110000001:Q:",
+ "-:1110011100000000:':",
+ "-:11100111000000010:ESCAPE:",
+ "-:11100111000000011:x:",
+ ".:1: :",
+ ".:01:STOP:",
+ ".:0011:.:",
+ ".:00010:i:",
+ ".:00100:0:",
+ ".:00101:c:",
+ ".:000001:u:",
+ ".:0000000:a:",
+ ".:0000001:[:",
+ ".:0001101:3:",
+ ".:00001000:4:",
+ ".:00001110:H:",
+ ".:00011000:S:",
+ ".:00011001:W:",
+ ".:00011100:o:",
+ ".:00011110:1:",
+ ".:000010100:5:",
+ ".:000010101:L:",
+ ".:000010111:p:",
+ ".:000011000:T:",
+ ".:000011001:A:",
+ ".:000011010:M:",
+ ".:000011110:C:",
+ ".:000011111:2:",
+ ".:000111011:D:",
+ ".:000111110:B:",
+ ".:0000100100:N:",
+ ".:0000100110:t:",
+ ".:0000100111:J:",
+ ".:0000101101:R:",
+ ".:0000110111:P:",
+ ".:0001110101:s:",
+ ".:0001111111:I:",
+ ".:00001011000:r:",
+ ".:00001101100:V:",
+ ".:00011101000:w:",
+ ".:00011101001:F:",
+ ".:00011111101:G:",
+ ".:000010010100:E:",
+ ".:000010010101:0x3a:",
+ ".:000010110010:h:",
+ ".:000011011010:,:",
+ ".:000111111000:':",
+ ".:0000100101101:b:",
+ ".:0000100101110:K:",
+ ".:0000100101111:Y:",
+ ".:0000101100111:O:",
+ ".:0000110110110:-:",
+ ".:0001111110010:f:",
+ ".:0001111110011:(:",
+ ".:00001011001100:\":",
+ ".:00001101101110:y:",
+ ".:000010010110000:?:",
+ ".:000010010110001:m:",
+ ".:000010010110010:Q:",
+ ".:000011011011110:*:",
+ ".:000011011011111:&:",
+ ".:0000100101100110:U:",
+ ".:0000100101100111:;:",
+ ".:0000101100110100:8:",
+ ".:0000101100110101:6:",
+ ".:0000101100110111:k:",
+ ".:00001011001101100:d:",
+ ".:000010110011011010:ESCAPE:",
+ ".:000010110011011011:n:",
+ "/:01:c:",
+ "/:110:1:",
+ "/:111:e:",
+ "/:0000:5:",
+ "/:0010:8:",
+ "/:00010:T:",
+ "/:00011:f:",
+ "/:00110:B:",
+ "/:00111:2:",
+ "/:10001:3:",
+ "/:10010:7:",
+ "/:10100:6:",
+ "/:10110:a:",
+ "/:101111:4:",
+ "/:1000000:F:",
+ "/:1000010:s:",
+ "/:1000011:M:",
+ "/:1001100:H:",
+ "/:1001110:D:",
+ "/:1001111:A:",
+ "/:1010101:S:",
+ "/:10000011:m:",
+ "/:10011010:W:",
+ "/:10101000:G:",
+ "/:10101001:U:",
+ "/:10101100:d:",
+ "/:10101101:O:",
+ "/:10101110:N:",
+ "/:10111001:C:",
+ "/:10111011:P:",
+ "/:100110110:L:",
+ "/:101011110: :",
+ "/:101011111:I:",
+ "/:101110000:E:",
+ "/:101110001:R:",
+ "/:101110100:K:",
+ "/:101110101:t:",
+ "/:1000001001:J:",
+ "/:1000001011:9:",
+ "/:10000010000:v:",
+ "/:10000010001:p:",
+ "/:10000010100:h:",
+ "/:10011011101:o:",
+ "/:10011011110:Q:",
+ "/:10011011111:0:",
+ "/:100000101010:l:",
+ "/:100000101011:i:",
+ "/:100110111000:V:",
+ "/:1001101110011:y:",
+ "/:10011011100100:ESCAPE:",
+ "/:10011011100101:g:",
+ "0:0:0:",
+ "0:111: :",
+ "0:1001:a:",
+ "0:1011:p:",
+ "0:10001:s:",
+ "0:11000:.:",
+ "0:11001:8:",
+ "0:11011:,:",
+ "0:100000:4:",
+ "0:100001:t:",
+ "0:101001:5:",
+ "0:110100:6:",
+ "0:1010000:3:",
+ "0:1010001:7:",
+ "0:1010101:]:",
+ "0:1010110:-:",
+ "0:1010111:1:",
+ "0:10101000:):",
+ "0:10101001:/:",
+ "0:11010100:STOP:",
+ "0:11010101:9:",
+ "0:11010111:2:",
+ "0:110101100:%:",
+ "0:1101011010:0x3a:",
+ "0:110101101101:f:",
+ "0:110101101111:m:",
+ "0:1101011011100:y:",
+ "0:11010110110001:l:",
+ "0:11010110110010:;:",
+ "0:11010110110011:':",
+ "0:11010110111010:k:",
+ "0:11010110111011:!:",
+ "0:110101101100000:C:",
+ "0:1101011011000010:ESCAPE:",
+ "0:1101011011000011:J:",
+ "1:00:9:",
+ "1:100:1:",
+ "1:111:0:",
+ "1:0101: :",
+ "1:0111:2:",
+ "1:1011:.:",
+ "1:1100:5:",
+ "1:01000:6:",
+ "1:01001:8:",
+ "1:01101:/:",
+ "1:10100:]:",
+ "1:11010:3:",
+ "1:011001:7:",
+ "1:110110:4:",
+ "1:0110000:STOP:",
+ "1:0110001:-:",
+ "1:1010100:):",
+ "1:1010110:0x3a:",
+ "1:1010111:s:",
+ "1:1101110:,:",
+ "1:1101111:x:",
+ "1:10101010:':",
+ "1:101010110:X:",
+ "1:10101011110:t:",
+ "1:10101011111:R:",
+ "1:101010111011:;:",
+ "1:1010101110000:p:",
+ "1:1010101110001:m:",
+ "1:1010101110010:!:",
+ "1:1010101110101:&:",
+ "1:10101011100110:e:",
+ "1:101010111001110:b:",
+ "1:101010111001111:a:",
+ "1:101010111010000:D:",
+ "1:101010111010001:C:",
+ "1:101010111010010:%:",
+ "1:1010101110100110:ESCAPE:",
+ "1:1010101110100111:o:",
+ "2:11:0:",
+ "2:000: :",
+ "2:010:.:",
+ "2:100:5:",
+ "2:0011:/:",
+ "2:1011:,:",
+ "2:00100:]:",
+ "2:00101:p:",
+ "2:01101:1:",
+ "2:10101:4:",
+ "2:011000:6:",
+ "2:011001:2:",
+ "2:011100:0x3a:",
+ "2:011101:-:",
+ "2:011111:):",
+ "2:1010000:STOP:",
+ "2:1010010:8:",
+ "2:1010011:9:",
+ "2:01111000:D:",
+ "2:01111001:3:",
+ "2:01111010:t:",
+ "2:01111011:7:",
+ "2:10100010:n:",
+ "2:101000110:a:",
+ "2:1010001110:':",
+ "2:10100011111:;:",
+ "2:101000111100:s:",
+ "2:1010001111010:\":",
+ "2:101000111101100:ESCAPE:",
+ "2:101000111101101:i:",
+ "2:101000111101110:W:",
+ "2:101000111101111:L:",
+ "3:00: :",
+ "3:10:0:",
+ "3:110:.:",
+ "3:1110:/:",
+ "3:01000:2:",
+ "3:01001:1:",
+ "3:01010:):",
+ "3:01100:0x3a:",
+ "3:01110:-:",
+ "3:11111:]:",
+ "3:010110:D:",
+ "3:011010:4:",
+ "3:011011:STOP:",
+ "3:011111:5:",
+ "3:111100:,:",
+ "3:0101110:7:",
+ "3:0101111:3:",
+ "3:0111101:6:",
+ "3:1111011:t:",
+ "3:01111001:B:",
+ "3:11110100:8:",
+ "3:111101010:9:",
+ "3:0111100001:;:",
+ "3:1111010110:r:",
+ "3:1111010111:s:",
+ "3:01111000000:n:",
+ "3:01111000101:b:",
+ "3:01111000110:':",
+ "3:01111000111:A:",
+ "3:011110000010:p:",
+ "3:011110000011:e:",
+ "3:0111100010000:a:",
+ "3:0111100010001:&:",
+ "3:0111100010010:%:",
+ "3:01111000100110:ESCAPE:",
+ "3:01111000100111:k:",
+ "4:01: :",
+ "4:000:4:",
+ "4:100:.:",
+ "4:110:0:",
+ "4:0010:/:",
+ "4:1010:5:",
+ "4:1011:-:",
+ "4:00110:1:",
+ "4:11101:]:",
+ "4:11110:,:",
+ "4:001110:2:",
+ "4:111001:8:",
+ "4:111110:):",
+ "4:0011110:0x3a:",
+ "4:0011111:':",
+ "4:1110000:t:",
+ "4:1110001:3:",
+ "4:1111111:STOP:",
+ "4:11111101:6:",
+ "4:1111110000:9:",
+ "4:1111110010:7:",
+ "4:11111100011:C:",
+ "4:11111100110:;:",
+ "4:111111000101:x:",
+ "4:1111110011101:m:",
+ "4:1111110011110:I:",
+ "4:11111100010000:f:",
+ "4:11111100010001:e:",
+ "4:11111100010010:b:",
+ "4:11111100010011:L:",
+ "4:11111100111000:%:",
+ "4:11111100111110:p:",
+ "4:11111100111111:c:",
+ "4:111111001110010:ESCAPE:",
+ "4:111111001110011:i:",
+ "5:00:0:",
+ "5:10: :",
+ "5:010:.:",
+ "5:0111:p:",
+ "5:1100:5:",
+ "5:01100:/:",
+ "5:11010:a:",
+ "5:11011:-:",
+ "5:11101:6:",
+ "5:011010:3:",
+ "5:111100:2:",
+ "5:111110:8:",
+ "5:111111:]:",
+ "5:0110110:0x3a:",
+ "5:1110000:):",
+ "5:1110001:s:",
+ "5:1110011:,:",
+ "5:1111010:7:",
+ "5:1111011:9:",
+ "5:01101110:4:",
+ "5:11100100:STOP:",
+ "5:11100101:t:",
+ "5:0110111110:c:",
+ "5:0110111111:1:",
+ "5:01101111001:;:",
+ "5:01101111011:m:",
+ "5:011011110000:e:",
+ "5:011011110001:':",
+ "5:011011110101:k:",
+ "5:0110111101001:l:",
+ "5:01101111010000:ESCAPE:",
+ "5:01101111010001:f:",
+ "6:00: :",
+ "6:10:.:",
+ "6:111:0:",
+ "6:0101:]:",
+ "6:01001:1:",
+ "6:01100:7:",
+ "6:01110:):",
+ "6:11000:,:",
+ "6:11001:0x3a:",
+ "6:11010:/:",
+ "6:010001:-:",
+ "6:011010:5:",
+ "6:011011:4:",
+ "6:011111:8:",
+ "6:110111:t:",
+ "6:0100000:6:",
+ "6:0111100:3:",
+ "6:0111101:2:",
+ "6:1101101:9:",
+ "6:01000010:STOP:",
+ "6:01000011:+:",
+ "6:11011000:':",
+ "6:1101100101:a:",
+ "6:1101100110:?:",
+ "6:11011001000:m:",
+ "6:11011001001:e:",
+ "6:11011001110:;:",
+ "6:1101100111100:f:",
+ "6:1101100111101:b:",
+ "6:1101100111110:M:",
+ "6:11011001111110:\":",
+ "6:110110011111110:ESCAPE:",
+ "6:110110011111111:i:",
+ "7:11:.:",
+ "7:001: :",
+ "7:011:0:",
+ "7:101:-:",
+ "7:0000:8:",
+ "7:0100:7:",
+ "7:1001:]:",
+ "7:01010:/:",
+ "7:000101:6:",
+ "7:000110:2:",
+ "7:000111:1:",
+ "7:010111:t:",
+ "7:100000:9:",
+ "7:100010:):",
+ "7:100011:5:",
+ "7:0001001:3:",
+ "7:0101101:,:",
+ "7:1000010:a:",
+ "7:1000011:4:",
+ "7:00010000:STOP:",
+ "7:01011000:0x3a:",
+ "7:01011001:p:",
+ "7:0001000101:R:",
+ "7:0001000110:;:",
+ "7:00010001000:':",
+ "7:00010001111:m:",
+ "7:000100010011:f:",
+ "7:000100011100:A:",
+ "7:000100011101:?:",
+ "7:0001000100100:ESCAPE:",
+ "7:0001000100101:s:",
+ "8:01: :",
+ "8:000:4:",
+ "8:110:.:",
+ "8:0011:0:",
+ "8:1000:9:",
+ "8:1001:7:",
+ "8:1011:8:",
+ "8:1110:1:",
+ "8:00100:/:",
+ "8:10100:3:",
+ "8:11110:5:",
+ "8:101010:):",
+ "8:111110:6:",
+ "8:111111:]:",
+ "8:0010100:0x3a:",
+ "8:0010101:,:",
+ "8:1010111:t:",
+ "8:00101100:p:",
+ "8:00101101:-:",
+ "8:00101111:a:",
+ "8:10101100:c:",
+ "8:10101101:2:",
+ "8:001011101:STOP:",
+ "8:0010111001:;:",
+ "8:001011100000:l:",
+ "8:001011100001:':",
+ "8:0010111000100:f:",
+ "8:0010111000101:D:",
+ "8:0010111000110:A:",
+ "8:00101110001110:ESCAPE:",
+ "8:00101110001111:i:",
+ "9:000:5:",
+ "9:001:]:",
+ "9:111:9:",
+ "9:0101:0:",
+ "9:0110:.:",
+ "9:0111:-:",
+ "9:1000:4:",
+ "9:1001:8:",
+ "9:1011:6:",
+ "9:1100: :",
+ "9:1101:7:",
+ "9:01000:2:",
+ "9:10100:3:",
+ "9:010010:1:",
+ "9:010011:/:",
+ "9:101010:t:",
+ "9:1010111:):",
+ "9:10101100:0x3a:",
+ "9:101011010:,:",
+ "9:10101101100:p:",
+ "9:10101101101:;:",
+ "9:10101101111:STOP:",
+ "9:1010110111000:n:",
+ "9:1010110111001:m:",
+ "9:1010110111010:a:",
+ "9:10101101110111:e:",
+ "9:101011011101100:ESCAPE:",
+ "9:101011011101101:k:",
+ "0x3a:1: :",
+ "0x3a:01:0:",
+ "0x3a:001:3:",
+ "0x3a:00001:1:",
+ "0x3a:00010:T:",
+ "0x3a:00011:C:",
+ "0x3a:000001:4:",
+ "0x3a:0000000:ESCAPE:",
+ "0x3a:0000001:5:",
+ ";:0:ESCAPE:",
+ ";:1: :",
+ "<:0:ESCAPE:",
+ "<:1:ESCAPE:",
+ "=:0:ESCAPE:",
+ "=:1:ESCAPE:",
+ ">:0:ESCAPE:",
+ ">:1:ESCAPE:",
+ "?:1: :",
+ "?:01:STOP:",
+ "?:000:0x3a:",
+ "?:00100:!:",
+ "?:00110:[:",
+ "?:00111:.:",
+ "?:001010:;:",
+ "?:0010110:':",
+ "?:00101111:,:",
+ "?:001011101:/:",
+ "?:0010111000:ESCAPE:",
+ "?:0010111001:Q:",
+ "@:0:k:",
+ "@:10: :",
+ "@:111:T:",
+ "@:1101:b:",
+ "@:11000:ESCAPE:",
+ "@:11001:H:",
+ "A:01: :",
+ "A:110:D:",
+ "A:111:n:",
+ "A:0000:s:",
+ "A:0001:m:",
+ "A:0010:d:",
+ "A:1000:r:",
+ "A:1011:l:",
+ "A:00110:c:",
+ "A:10010:u:",
+ "A:10100:g:",
+ "A:001111:b:",
+ "A:100111:t:",
+ "A:101011:f:",
+ "A:1010100:w:",
+ "A:1010101:i:",
+ "A:10011001:v:",
+ "A:10011011:p:",
+ "A:001110010:h:",
+ "A:001110100:.:",
+ "A:001110111:B:",
+ "A:100110100:q:",
+ "A:0011100000:C:",
+ "A:0011100010:,:",
+ "A:0011100110:y:",
+ "A:0011101010:S:",
+ "A:0011101100:k:",
+ "A:0011101101:T:",
+ "A:1001100001:R:",
+ "A:1001100010:F:",
+ "A:1001100011:z:",
+ "A:1001101011:a:",
+ "A:00111000010:P:",
+ "A:00111000110:-:",
+ "A:00111010110:A:",
+ "A:00111010111:I:",
+ "A:10011000001:e:",
+ "A:10011010100:N:",
+ "A:10011010101:x:",
+ "A:001110000110:X:",
+ "A:001110000111:K:",
+ "A:001110001110:3:",
+ "A:001110001111:&:",
+ "A:001110011101:M:",
+ "A:001110011111:Y:",
+ "A:0011100111000:L:",
+ "A:0011100111001:W:",
+ "A:0011100111100:*:",
+ "A:1001100000000:o:",
+ "A:1001100000001:1:",
+ "A:1001100000010:':",
+ "A:1001100000011:0x3a:",
+ "A:00111001111010:j:",
+ "A:001110011110110:G:",
+ "A:0011100111101110:O:",
+ "A:00111001111011110:4:",
+ "A:001110011110111110:ESCAPE:",
+ "A:001110011110111111:E:",
+ "B:00:C:",
+ "B:010:a:",
+ "B:101:r:",
+ "B:110:e:",
+ "B:111:B:",
+ "B:0111:i:",
+ "B:1000:u:",
+ "B:1001:o:",
+ "B:01101:l:",
+ "B:01100000:T:",
+ "B:01100001:.:",
+ "B:01100011:y:",
+ "B:01100100:I:",
+ "B:01100110:h:",
+ "B:01100111: :",
+ "B:011000100:A:",
+ "B:0110001010:O:",
+ "B:01100010110:0x3a:",
+ "B:01100101000:&:",
+ "B:01100101001:3:",
+ "B:01100101010:j:",
+ "B:01100101011:M:",
+ "B:01100101110:D:",
+ "B:011000101111:W:",
+ "B:011001011000:*:",
+ "B:011001011010:,:",
+ "B:011001011011:1:",
+ "B:011001011110:ESCAPE:",
+ "B:011001011111:P:",
+ "B:0110001011100:E:",
+ "B:0110010110011:R:",
+ "B:01100010111011:w:",
+ "B:011000101110100:-:",
+ "B:011001011001001:U:",
+ "B:011001011001010:S:",
+ "B:011001011001011:F:",
+ "B:0110001011101010:X:",
+ "B:0110001011101011:V:",
+ "B:0110010110010000:Q:",
+ "B:0110010110010001:4:",
+ "C:00:h:",
+ "C:011:B:",
+ "C:100:a:",
+ "C:110:o:",
+ "C:0101:r:",
+ "C:1010:.:",
+ "C:1110: :",
+ "C:1111:l:",
+ "C:01000:':",
+ "C:10111:i:",
+ "C:010011:e:",
+ "C:101101:u:",
+ "C:0100101:y:",
+ "C:1011001:,:",
+ "C:01001001:I:",
+ "C:010010000:A:",
+ "C:1011000000:C:",
+ "C:1011000001:D:",
+ "C:1011000011:STOP:",
+ "C:1011000100:S:",
+ "C:1011000101:T:",
+ "C:1011000111:G:",
+ "C:01001000100:*:",
+ "C:01001000111:w:",
+ "C:10110001101:J:",
+ "C:010010001010:R:",
+ "C:010010001100:2:",
+ "C:010010001101:U:",
+ "C:101100001000:?:",
+ "C:101100001010:O:",
+ "C:101100001011:H:",
+ "C:101100011000:E:",
+ "C:0100100010110:z:",
+ "C:1011000010011:-:",
+ "C:1011000110011:s:",
+ "C:01001000101111:1:",
+ "C:10110000100101:!:",
+ "C:10110001100100:P:",
+ "C:010010001011101:n:",
+ "C:101100001001000:K:",
+ "C:101100001001001:7:",
+ "C:101100011001011:4:",
+ "C:0100100010111000:0x3a:",
+ "C:1011000110010100:F:",
+ "C:1011000110010101:):",
+ "C:01001000101110010:ESCAPE:",
+ "C:01001000101110011:b:",
+ "D:00:a:",
+ "D:01:,:",
+ "D:100:r:",
+ "D:101:o:",
+ "D:110:e:",
+ "D:1110:i:",
+ "D:111111:u:",
+ "D:1111001: :",
+ "D:1111011:':",
+ "D:11110000:.:",
+ "D:11110001:]:",
+ "D:11111010:y:",
+ "D:111101010:w:",
+ "D:111101011:W:",
+ "D:111110001:N:",
+ "D:111110010:C:",
+ "D:111110111:J:",
+ "D:1111010010:h:",
+ "D:1111100000:t:",
+ "D:1111100111:I:",
+ "D:1111101101:0x3a:",
+ "D:11110100001:M:",
+ "D:11110100010:&:",
+ "D:11110100011:V:",
+ "D:11111000010:-:",
+ "D:11111000011:G:",
+ "D:11111001100:O:",
+ "D:11111001101:A:",
+ "D:11111011001:S:",
+ "D:111101000000:F:",
+ "D:111101001100:*:",
+ "D:111101001101:s:",
+ "D:111101001111:d:",
+ "D:111110110000:v:",
+ "D:1111010011100:m:",
+ "D:1111010011101:j:",
+ "D:1111101100010:ESCAPE:",
+ "D:1111101100011:T:",
+ "D:11110100000110:9:",
+ "D:111101000001000:):",
+ "D:111101000001011:E:",
+ "D:111101000001110:8:",
+ "D:111101000001111:7:",
+ "D:1111010000010010:U:",
+ "D:1111010000010011:R:",
+ "D:1111010000010100:B:",
+ "D:1111010000010101:4:",
+ "E:000:p:",
+ "E:010:a:",
+ "E:011:n:",
+ "E:110:l:",
+ "E:1001:m:",
+ "E:1010:x:",
+ "E:1110:v:",
+ "E:1111:d:",
+ "E:00100:s:",
+ "E:00110:r:",
+ "E:00111:u:",
+ "E:10000:E:",
+ "E:10001: :",
+ "E:001010:.:",
+ "E:001011:i:",
+ "E:101101:0x3a:",
+ "E:1011000:y:",
+ "E:1011001:t:",
+ "E:1011100:g:",
+ "E:1011110:4:",
+ "E:101110110:w:",
+ "E:101111100:c:",
+ "E:101111110:b:",
+ "E:1011101010:R:",
+ "E:1011101011:F:",
+ "E:1011101111:C:",
+ "E:10111010001:k:",
+ "E:10111010010:f:",
+ "E:10111010011:o:",
+ "E:10111011100:U:",
+ "E:10111011101:L:",
+ "E:10111110101:e:",
+ "E:10111110110:N:",
+ "E:10111111100:h:",
+ "E:10111111101:I:",
+ "E:10111111111:D:",
+ "E:101111101000:M:",
+ "E:101111101111:':",
+ "E:101111111100:2:",
+ "E:101111111101:-:",
+ "E:1011101000011:q:",
+ "E:1011111010010:O:",
+ "E:1011111010011:A:",
+ "E:1011111011101:Z:",
+ "E:10111010000000:W:",
+ "E:10111010000001:S:",
+ "E:10111010000010:H:",
+ "E:10111010000011:9:",
+ "E:10111010000100:):",
+ "E:10111110111000:T:",
+ "E:10111110111001:,:",
+ "E:101110100001010:P:",
+ "E:1011101000010110:ESCAPE:",
+ "E:1011101000010111:z:",
+ "F:00:o:",
+ "F:10:r:",
+ "F:010:e:",
+ "F:110:i:",
+ "F:111:a:",
+ "F:0110:l:",
+ "F:01110:u:",
+ "F:0111100: :",
+ "F:0111101:O:",
+ "F:01111101:A:",
+ "F:01111111:B:",
+ "F:011111100:f:",
+ "F:0111110000:.:",
+ "F:0111110011:L:",
+ "F:01111100010:M:",
+ "F:01111100011:E:",
+ "F:01111100101:T:",
+ "F:01111110101:C:",
+ "F:01111110110:W:",
+ "F:011111001000:0x3a:",
+ "F:011111101000:U:",
+ "F:011111101001:':",
+ "F:011111101111:1:",
+ "F:0111110010010:y:",
+ "F:0111110010011:,:",
+ "F:01111110111000:-:",
+ "F:01111110111010:I:",
+ "F:011111101110011:h:",
+ "F:0111111011100100:*:",
+ "F:0111111011100101:K:",
+ "F:0111111011101100:F:",
+ "F:0111111011101101:ESCAPE:",
+ "F:01111110111011100:X:",
+ "F:01111110111011101:R:",
+ "F:01111110111011110:;:",
+ "F:01111110111011111:4:",
+ "G:00:r:",
+ "G:01:a:",
+ "G:101:o:",
+ "G:110:e:",
+ "G:1001:u:",
+ "G:1111:i:",
+ "G:10001:n:",
+ "G:11101:l:",
+ "G:100000:X:",
+ "G:1110000:y:",
+ "G:1110001: :",
+ "G:1110011:w:",
+ "G:10000101:4:",
+ "G:10000111:P:",
+ "G:11100101:h:",
+ "G:100001000:-:",
+ "G:100001100:C:",
+ "G:111001001:M:",
+ "G:1000011010:B:",
+ "G:1110010000:.:",
+ "G:1110010001:I:",
+ "G:10000100100:;:",
+ "G:10000100101:,:",
+ "G:10000100110:A:",
+ "G:10000100111:N:",
+ "G:10000110111:0x3a:",
+ "G:1000011011000:O:",
+ "G:1000011011001:L:",
+ "G:10000110110110:b:",
+ "G:100001101101000:K:",
+ "G:100001101101001:2:",
+ "G:100001101101010:1:",
+ "G:100001101101011:':",
+ "G:1000011011011100:ESCAPE:",
+ "G:1000011011011101:m:",
+ "G:1000011011011110:T:",
+ "G:1000011011011111:S:",
+ "H:00:e:",
+ "H:01:a:",
+ "H:10:o:",
+ "H:110:i:",
+ "H:1111:u:",
+ "H:11100:R:",
+ "H:1110100:P:",
+ "H:1110110:y:",
+ "H:11101011:I:",
+ "H:111011100:Q:",
+ "H:111011101:M:",
+ "H:111011110:A:",
+ "H:111011111: :",
+ "H:1110101000:S:",
+ "H:1110101001:.:",
+ "H:11101010101:G:",
+ "H:11101010110:):",
+ "H:111010101001:E:",
+ "H:1110101011100:O:",
+ "H:1110101011101:L:",
+ "H:11101010100000:1:",
+ "H:11101010100001:&:",
+ "H:11101010111100:H:",
+ "H:11101010111101:w:",
+ "H:11101010111110:v:",
+ "H:111010101000100:X:",
+ "H:111010101000101:W:",
+ "H:111010101000110:D:",
+ "H:111010101111110:s:",
+ "H:111010101111111:F:",
+ "H:1110101010001110:ESCAPE:",
+ "H:1110101010001111:r:",
+ "I:0:n:",
+ "I:110:t:",
+ "I:1001:s:",
+ "I:1111:r:",
+ "I:10000:T:",
+ "I:10101:a:",
+ "I:11100: :",
+ "I:100010:c:",
+ "I:101001:m:",
+ "I:101100:z:",
+ "I:101101:.:",
+ "I:101111:d:",
+ "I:111011:I:",
+ "I:1000111:':",
+ "I:1011101:l:",
+ "I:10100000:A:",
+ "I:10100001:v:",
+ "I:10111001:V:",
+ "I:11101001:f:",
+ "I:11101011:o:",
+ "I:100011001:C:",
+ "I:100011010:P:",
+ "I:101000100:w:",
+ "I:101000110:0x3a:",
+ "I:101110000:p:",
+ "I:111010000:R:",
+ "I:111010001:,:",
+ "I:111010101:Y:",
+ "I:1000110000:E:",
+ "I:1000110001:6:",
+ "I:1000110111:q:",
+ "I:1010001011:y:",
+ "I:1010001110:M:",
+ "I:1110101000:g:",
+ "I:1110101001:D:",
+ "I:10001101100:e:",
+ "I:10001101101:5:",
+ "I:10100010100:S:",
+ "I:10100010101:9:",
+ "I:10100011111:F:",
+ "I:10111000100:b:",
+ "I:10111000110:-:",
+ "I:10111000111:L:",
+ "I:101000111100:B:",
+ "I:101000111101:):",
+ "I:1011100010100:N:",
+ "I:1011100010101:Q:",
+ "I:1011100010110:k:",
+ "I:10111000101111:O:",
+ "I:101110001011101:?:",
+ "I:1011100010111000:ESCAPE:",
+ "I:1011100010111001:h:",
+ "J:00:e:",
+ "J:10:a:",
+ "J:11:o:",
+ "J:011:u:",
+ "J:0101:i:",
+ "J:01000: :",
+ "J:0100110:D:",
+ "J:0100111:.:",
+ "J:01001001:r:",
+ "J:010010110:s:",
+ "J:0100100000:M:",
+ "J:0100100010:J:",
+ "J:0100100011:,:",
+ "J:0100101000:B:",
+ "J:0100101001:-:",
+ "J:0100101010:V:",
+ "J:0100101110:K:",
+ "J:0100101111:T:",
+ "J:01001000010:C:",
+ "J:01001010110:n:",
+ "J:010010000110:!:",
+ "J:0100100001110:w:",
+ "J:0100100001111:R:",
+ "J:0100101011100:F:",
+ "J:0100101011110:7:",
+ "J:0100101011111:':",
+ "J:01001010111010:G:",
+ "J:010010101110110:ESCAPE:",
+ "J:010010101110111:L:",
+ "K:00:i:",
+ "K:01:a:",
+ "K:10:e:",
+ "K:1111:y:",
+ "K:11000:n:",
+ "K:11001:o:",
+ "K:11011:r:",
+ "K:11101: :",
+ "K:110100:':",
+ "K:111000:u:",
+ "K:1101011:.:",
+ "K:1110011:l:",
+ "K:11100101:h:",
+ "K:110101000:T:",
+ "K:110101011:G:",
+ "K:111001001:,:",
+ "K:1101010100:w:",
+ "K:11010100100:5:",
+ "K:11010100101:4:",
+ "K:11010100110:A:",
+ "K:11010101010:3:",
+ "K:11100100000:2:",
+ "K:11100100011:M:",
+ "K:110101001110:-:",
+ "K:110101010110:0x3a:",
+ "K:110101010111:!:",
+ "K:111001000010:):",
+ "K:111001000101:S:",
+ "K:1101010011110:V:",
+ "K:1110010000110:6:",
+ "K:1110010000111:1:",
+ "K:11010100111111:L:",
+ "K:11100100010000:I:",
+ "K:11100100010001:?:",
+ "K:110101001111100:ESCAPE:",
+ "K:110101001111101:v:",
+ "K:111001000100100:k:",
+ "K:111001000100101:Y:",
+ "K:111001000100110:N:",
+ "K:111001000100111:E:",
+ "L:00:i:",
+ "L:10:o:",
+ "L:011:]:",
+ "L:110:e:",
+ "L:111:a:",
+ "L:0100:u:",
+ "L:010100:l:",
+ "L:010101:A:",
+ "L:010111:y:",
+ "L:01011011: :",
+ "L:010110000:I:",
+ "L:010110001:R:",
+ "L:010110101:,:",
+ "L:0101100100:O:",
+ "L:0101100101:':",
+ "L:01011001101:.:",
+ "L:01011001110:C:",
+ "L:01011001111:Y:",
+ "L:01011010001:F:",
+ "L:01011010010:L:",
+ "L:010110011001:t:",
+ "L:010110100001:G:",
+ "L:010110100111:S:",
+ "L:0101100110001:h:",
+ "L:0101101000001:W:",
+ "L:0101101001100:J:",
+ "L:01011001100000:E:",
+ "L:01011010000001:\":",
+ "L:01011010011011:STOP:",
+ "L:010110011000010:T:",
+ "L:010110011000011:P:",
+ "L:010110100000000:D:",
+ "L:010110100000001:7:",
+ "L:010110100110101:j:",
+ "L:0101101001101000:ESCAPE:",
+ "L:0101101001101001:U:",
+ "M:00:o:",
+ "M:11:a:",
+ "M:011:e:",
+ "M:101:i:",
+ "M:0101:c:",
+ "M:1001:u:",
+ "M:01001:y:",
+ "M:10001:r:",
+ "M:100000:S:",
+ "M:100001:P:",
+ "M:0100001: :",
+ "M:01000001:C:",
+ "M:01000110:F:",
+ "M:010000000:1:",
+ "M:010001000:h:",
+ "M:010001010:I:",
+ "M:010001110:T:",
+ "M:010001111:X:",
+ "M:0100000010:A:",
+ "M:0100010010:z:",
+ "M:01000100110:f:",
+ "M:01000101110:.:",
+ "M:010000001100:Z:",
+ "M:010000001101:K:",
+ "M:010000001110:B:",
+ "M:010001001111:s:",
+ "M:010001011000:R:",
+ "M:010001011001:W:",
+ "M:010001011010:O:",
+ "M:0100000011110:,:",
+ "M:0100000011111:':",
+ "M:0100010110111:D:",
+ "M:0100010111100:4:",
+ "M:0100010111110:E:",
+ "M:01000100111000:m:",
+ "M:01000100111001:J:",
+ "M:01000100111010:ESCAPE:",
+ "M:01000101111010:l:",
+ "M:01000101111011:-:",
+ "M:01000101111110:):",
+ "M:01000101111111:w:",
+ "M:010001001110110:t:",
+ "M:010001001110111:V:",
+ "M:010001011011000:Q:",
+ "M:010001011011001:N:",
+ "M:010001011011010:6:",
+ "M:010001011011011:2:",
+ "N:00:a:",
+ "N:10:o:",
+ "N:11:e:",
+ "N:011:i:",
+ "N:01010:u:",
+ "N:01011:E:",
+ "N:010010:A:",
+ "N:0100010:y:",
+ "N:0100110:g:",
+ "N:01000001:B:",
+ "N:01000010:I:",
+ "N:01000110:F:",
+ "N:01000111: :",
+ "N:010000000:):",
+ "N:010000001:':",
+ "N:010000111:Y:",
+ "N:010011100:L:",
+ "N:010011101:H:",
+ "N:0100001100:C:",
+ "N:0100111100:W:",
+ "N:0100111110:N:",
+ "N:0100111111:T:",
+ "N:010000110101:M:",
+ "N:010000110111:O:",
+ "N:010011110100:,:",
+ "N:010011110101:J:",
+ "N:010011110111:h:",
+ "N:0100001101000:D:",
+ "N:0100001101001:.:",
+ "N:0100111101100:X:",
+ "N:0100111101101:ESCAPE:",
+ "N:01000011011000:k:",
+ "N:01000011011001:Z:",
+ "N:01000011011010:Q:",
+ "N:01000011011011:G:",
+ "O:111:n:",
+ "O:0000:s:",
+ "O:0001:N:",
+ "O:0011:z:",
+ "O:0100:r:",
+ "O:1000:u:",
+ "O:1010:p:",
+ "O:1011:l:",
+ "O:1101:':",
+ "O:00101:U:",
+ "O:01011:h:",
+ "O:01110:f:",
+ "O:01111:w:",
+ "O:10010:.:",
+ "O:11000: :",
+ "O:001000:o:",
+ "O:001001:J:",
+ "O:010100:b:",
+ "O:010101:m:",
+ "O:011001:H:",
+ "O:011010:O:",
+ "O:011011:v:",
+ "O:100111:c:",
+ "O:110011:x:",
+ "O:1001101:d:",
+ "O:1100100:a:",
+ "O:01100001:t:",
+ "O:01100010:k:",
+ "O:10011000:g:",
+ "O:11001010:R:",
+ "O:011000000:K:",
+ "O:100110010:i:",
+ "O:110010111:V:",
+ "O:0110000011:2:",
+ "O:0110001101:S:",
+ "O:0110001110:B:",
+ "O:1001100110:W:",
+ "O:1001100111:-:",
+ "O:01100000100:,:",
+ "O:01100011000:j:",
+ "O:01100011001:L:",
+ "O:01100011111:I:",
+ "O:11001011001:A:",
+ "O:11001011011:C:",
+ "O:011000001010:0x3a:",
+ "O:011000111100:e:",
+ "O:110010110000:y:",
+ "O:110010110001:/:",
+ "O:110010110100:M:",
+ "O:0110000010110:!:",
+ "O:0110001111011:P:",
+ "O:1100101101011:F:",
+ "O:01100000101110:E:",
+ "O:01100000101111:D:",
+ "O:01100011110100:8:",
+ "O:01100011110101:4:",
+ "O:11001011010101:T:",
+ "O:110010110101000:ESCAPE:",
+ "O:110010110101001:q:",
+ "P:11:a:",
+ "P:000:i:",
+ "P:010:e:",
+ "P:011:l:",
+ "P:100:o:",
+ "P:101:r:",
+ "P:0010:h:",
+ "P:001111:u:",
+ "P:0011010:C:",
+ "P:0011100:.:",
+ "P:0011101: :",
+ "P:00110000:B:",
+ "P:00110010:D:",
+ "P:00110111:s:",
+ "P:001100011:O:",
+ "P:001100111:,:",
+ "P:0011000101:y:",
+ "P:0011001100:M:",
+ "P:0011011000:E:",
+ "P:0011011001:':",
+ "P:0011011011:3:",
+ "P:00110001001:T:",
+ "P:001100010000:L:",
+ "P:001100010001:G:",
+ "P:001100110100:*:",
+ "P:001100110110:A:",
+ "P:001100110111:S:",
+ "P:001101101000:w:",
+ "P:001101101001:F:",
+ "P:0011001101011:J:",
+ "P:0011011010100:f:",
+ "P:0011011010101:R:",
+ "P:0011011010111:t:",
+ "P:00110011010100:V:",
+ "P:00110110101100:Y:",
+ "P:00110110101101:I:",
+ "P:001100110101011:&:",
+ "P:0011001101010100:ESCAPE:",
+ "P:0011001101010101:):",
+ "Q:1:u:",
+ "Q:00:V:",
+ "Q:011: :",
+ "Q:0101:.:",
+ "Q:01000:a:",
+ "Q:0100100:w:",
+ "Q:0100110:E:",
+ "Q:0100111:C:",
+ "Q:01001011:&:",
+ "Q:010010101:':",
+ "Q:0100101000:T:",
+ "Q:01001010010:ESCAPE:",
+ "Q:01001010011:s:",
+ "R:01:a:",
+ "R:11:o:",
+ "R:100:i:",
+ "R:101:e:",
+ "R:0000:p:",
+ "R:0011:u:",
+ "R:00011:E:",
+ "R:00100:h:",
+ "R:000100: :",
+ "R:001010:y:",
+ "R:00010100:D:",
+ "R:00010110:.:",
+ "R:00101100:T:",
+ "R:00101110:S:",
+ "R:000101010:F:",
+ "R:001011010:B:",
+ "R:001011011:n:",
+ "R:001011111:A:",
+ "R:0001010110:w:",
+ "R:0001011100:N:",
+ "R:0001011101:&:",
+ "R:0001011110:V:",
+ "R:0001011111:H:",
+ "R:0010111101:':",
+ "R:00010101110:t:",
+ "R:00010101111:I:",
+ "R:001011110000:C:",
+ "R:001011110010:O:",
+ "R:00101111000100:,:",
+ "R:00101111000101:s:",
+ "R:00101111000110:U:",
+ "R:00101111000111:M:",
+ "R:00101111001100:-:",
+ "R:00101111001101:ESCAPE:",
+ "R:00101111001111:0x3a:",
+ "R:001011110011100:2:",
+ "R:001011110011101:R:",
+ "S:1:]:",
+ "S:0000:a:",
+ "S:0010:h:",
+ "S:0111:t:",
+ "S:00010:p:",
+ "S:00011:,:",
+ "S:00110:L:",
+ "S:01000:i:",
+ "S:01001:u:",
+ "S:01010:o:",
+ "S:01011:c:",
+ "S:01100:e:",
+ "S:001111:k:",
+ "S:0011100:w:",
+ "S:0110101: :",
+ "S:0110111:m:",
+ "S:00111010:q:",
+ "S:01101000:M:",
+ "S:01101001:n:",
+ "S:01101100:l:",
+ "S:001110110:P:",
+ "S:011011011:y:",
+ "S:0011101110:A:",
+ "S:01101101001:.:",
+ "S:001110111101:r:",
+ "S:001110111110:S:",
+ "S:001110111111:W:",
+ "S:011011010000:C:",
+ "S:011011010101:E:",
+ "S:011011010110:v:",
+ "S:0110110100011:ESCAPE:",
+ "S:0110110101000:I:",
+ "S:0110110101111:g:",
+ "S:00111011110000:*:",
+ "S:00111011110010:4:",
+ "S:00111011110011:1:",
+ "S:01101101000100:O:",
+ "S:01101101010010:STOP:",
+ "S:01101101011100:z:",
+ "S:011011010001011:B:",
+ "S:011011010111010:H:",
+ "S:011011010111011:T:",
+ "S:0011101111000100:G:",
+ "S:0011101111000110:}:",
+ "S:0011101111000111:D:",
+ "S:0110110100010100:-:",
+ "S:0110110101001100:3:",
+ "S:0110110101001101:2:",
+ "S:00111011110001010:':",
+ "S:00111011110001011:?:",
+ "S:01101101010011101:s:",
+ "S:01101101010011110:j:",
+ "S:01101101010011111:b:",
+ "S:011011010001010100:R:",
+ "S:011011010001010101:K:",
+ "S:011011010001010110:J:",
+ "S:011011010001010111:F:",
+ "S:011011010100111000:0x3a:",
+ "S:011011010100111001:):",
+ "T:0:h:",
+ "T:100:o:",
+ "T:1010:V:",
+ "T:1011:w:",
+ "T:1100:r:",
+ "T:1111:e:",
+ "T:11010:a:",
+ "T:11011:i:",
+ "T:11100:u:",
+ "T:1110100:H:",
+ "T:1110110:W:",
+ "T:11101010: :",
+ "T:11101011:y:",
+ "T:111011101:M:",
+ "T:111011111:x:",
+ "T:1110111000:S:",
+ "T:11101110010:A:",
+ "T:11101111001:s:",
+ "T:11101111011:J:",
+ "T:111011100111:X:",
+ "T:111011110000:.:",
+ "T:1110111001101:-:",
+ "T:1110111100011:L:",
+ "T:1110111101000:C:",
+ "T:1110111101011:c:",
+ "T:11101110011000:T:",
+ "T:11101110011001:U:",
+ "T:11101111000101:4:",
+ "T:11101111010010:O:",
+ "T:111011110001001:G:",
+ "T:111011110100110:E:",
+ "T:111011110100111:,:",
+ "T:111011110101010:':",
+ "T:1110111100010001:;:",
+ "T:1110111101010000:P:",
+ "T:1110111101010001:1:",
+ "T:1110111101010010:ESCAPE:",
+ "T:1110111101010111:D:",
+ "T:11101111000100000:0x3a:",
+ "T:11101111000100001:*:",
+ "T:11101111010100110:R:",
+ "T:11101111010100111:N:",
+ "T:11101111010101100:I:",
+ "T:11101111010101101:B:",
+ "U:00:K:",
+ "U:10:n:",
+ "U:011:S:",
+ "U:110:p:",
+ "U:1111:l:",
+ "U:01010:s:",
+ "U:01011:r:",
+ "U:11101:R:",
+ "U:010000:g:",
+ "U:111000: :",
+ "U:0100111:.:",
+ "U:1110010:m:",
+ "U:01000100:k:",
+ "U:01000101:t:",
+ "U:01000110:E:",
+ "U:01000111:-:",
+ "U:01001000:F:",
+ "U:01001100:2:",
+ "U:11100110:c:",
+ "U:11100111:N:",
+ "U:010010010:f:",
+ "U:010010011:8:",
+ "U:010010100:,:",
+ "U:010010111:Z:",
+ "U:0100101010:h:",
+ "U:0100110100:i:",
+ "U:0100110101:w:",
+ "U:0100110110:a:",
+ "U:01001010110:b:",
+ "U:01001010111:D:",
+ "U:01001101110:!:",
+ "U:010010110000:e:",
+ "U:010010110001:V:",
+ "U:010010110010:P:",
+ "U:010010110011:I:",
+ "U:010010110100:B:",
+ "U:010010110101:A:",
+ "U:010011011111:d:",
+ "U:0100101101100:H:",
+ "U:0100101101101:C:",
+ "U:0100101101110:0x3a:",
+ "U:0100101101111:):",
+ "U:0100110111101:z:",
+ "U:01001101111000:ESCAPE:",
+ "U:01001101111001:T:",
+ "V:01: :",
+ "V:11:i:",
+ "V:000:.:",
+ "V:001:a:",
+ "V:101:e:",
+ "V:10001:C:",
+ "V:10011:o:",
+ "V:1000001:F:",
+ "V:1000011:I:",
+ "V:10000001:1:",
+ "V:10000101:4:",
+ "V:10010000:r:",
+ "V:10010010:E:",
+ "V:10010011:s:",
+ "V:10010101:':",
+ "V:10010110:0x3a:",
+ "V:10010111:l:",
+ "V:100000001:/:",
+ "V:100001001:-:",
+ "V:100100010:D:",
+ "V:100100011:u:",
+ "V:100101001:,:",
+ "V:1000000000:6:",
+ "V:1000000001:2:",
+ "V:1000010000:5:",
+ "V:1001010000:;:",
+ "V:10010100010:ESCAPE:",
+ "V:100001000100:7:",
+ "V:100101000110:3:",
+ "V:1000010001010:9:",
+ "V:1000010001011:y:",
+ "V:1000010001100:P:",
+ "V:1000010001101:H:",
+ "V:1000010001110:A:",
+ "V:1000010001111:8:",
+ "V:1001010001111:W:",
+ "V:10010100011100:f:",
+ "V:10010100011101:B:",
+ "W:00:h:",
+ "W:10:i:",
+ "W:011:a:",
+ "W:110:o:",
+ "W:111:e:",
+ "W:0100:r:",
+ "W:01011:O:",
+ "W:0101001: :",
+ "W:0101010:y:",
+ "W:010100000:B:",
+ "W:010100001:.:",
+ "W:010101100:I:",
+ "W:010101110:W:",
+ "W:010101111:A:",
+ "W:0101000100:':",
+ "W:0101000101:M:",
+ "W:0101000111:T:",
+ "W:01010001100:2:",
+ "W:01010001101:0x3a:",
+ "W:01010110100:H:",
+ "W:01010110110:V:",
+ "W:010101101010:l:",
+ "W:010101101110:s:",
+ "W:010101101111:,:",
+ "W:0101011010111:u:",
+ "W:010101101011000:5:",
+ "W:010101101011001:):",
+ "W:010101101011011:E:",
+ "W:0101011010110100:ESCAPE:",
+ "W:0101011010110101:m:",
+ "X:1: :",
+ "X:000:a:",
+ "X:0010:z:",
+ "X:0011:m:",
+ "X:0111:t:",
+ "X:01001:U:",
+ "X:01010:-:",
+ "X:01011:e:",
+ "X:011000:u:",
+ "X:011001:I:",
+ "X:011011:,:",
+ "X:0100010:V:",
+ "X:0110100:5:",
+ "X:0110101:.:",
+ "X:01000000:S:",
+ "X:01000010:0x3a:",
+ "X:01000110:c:",
+ "X:01000111:i:",
+ "X:010000010:9:",
+ "X:010000011:':",
+ "X:010000111:X:",
+ "X:0100001100:):",
+ "X:01000011010:ESCAPE:",
+ "X:01000011011:y:",
+ "Y:1:o:",
+ "Y:00:e:",
+ "Y:010:u:",
+ "Y:01100:a:",
+ "Y:01110:v:",
+ "Y:01111: :",
+ "Y:0110100:n:",
+ "Y:01101010:r:",
+ "Y:01101101:O:",
+ "Y:01101111:i:",
+ "Y:011010111:N:",
+ "Y:011011000:L:",
+ "Y:011011001:s:",
+ "Y:011011101:m:",
+ "Y:0110101100:.:",
+ "Y:0110101101:M:",
+ "Y:0110111001:P:",
+ "Y:011011100001:R:",
+ "Y:011011100010:2:",
+ "Y:0110111000000:-:",
+ "Y:0110111000110:C:",
+ "Y:0110111000111:,:",
+ "Y:01101110000010:ESCAPE:",
+ "Y:01101110000011:d:",
+ "Z:01:a:",
+ "Z:10:e:",
+ "Z:11:o:",
+ "Z:0010:z:",
+ "Z:0011:i:",
+ "Z:00001:Z:",
+ "Z:00010: :",
+ "Z:00011:u:",
+ "Z:0000010:O:",
+ "Z:0000011:.:",
+ "Z:00000000:y:",
+ "Z:00000001:4:",
+ "Z:00000010:,:",
+ "Z:0000001100:f:",
+ "Z:0000001101:-:",
+ "Z:0000001110:STOP:",
+ "Z:00000011110:ESCAPE:",
+ "Z:00000011111:l:",
+ "[:1:S:",
+ "[:01:A:",
+ "[:0000:2:",
+ "[:0010:R:",
+ "[:0011:1:",
+ "[:000101:n:",
+ "[:000110:m:",
+ "[:0001111:l:",
+ "[:00010011:r:",
+ "[:00011101:b:",
+ "[:000100001:C:",
+ "[:000100010:f:",
+ "[:000100101:M:",
+ "[:000111001:c:",
+ "[:0001000001:STOP:",
+ "[:0001000111:K:",
+ "[:0001001000:H:",
+ "[:0001110001:T:",
+ "[:00010000000:J:",
+ "[:00010000001:B:",
+ "[:00010001101:Z:",
+ "[:00010010011:P:",
+ "[:00011100000:L:",
+ "[:000100011000:F:",
+ "[:000100100101:I:",
+ "[:000111000011:N:",
+ "[:0001000110010:s:",
+ "[:0001000110011:V:",
+ "[:0001001001000:U:",
+ "[:0001001001001:G:",
+ "[:0001110000101:D:",
+ "[:00011100001000:O:",
+ "[:000111000010010:ESCAPE:",
+ "[:000111000010011:W:",
+ "\\:0:ESCAPE:",
+ "\\:1:x:",
+ "]:1:STOP:",
+ "]:01: :",
+ "]:001:.:",
+ "]:0001:[:",
+ "]:00001:0x3a:",
+ "]:000001:,:",
+ "]:0000001:;:",
+ "]:00000000:ESCAPE:",
+ "]:00000001:]:",
+ "^:0:ESCAPE:",
+ "^:1:ESCAPE:",
+ "_:0:ESCAPE:",
+ "_:1:ESCAPE:",
+ "`:001:w:",
+ "`:011:H:",
+ "`:110:P:",
+ "`:111:F:",
+ "`:0101:n:",
+ "`:1011:D:",
+ "`:00001:s:",
+ "`:00010:A:",
+ "`:01001:t:",
+ "`:10000:g:",
+ "`:10011:c:",
+ "`:000000:W:",
+ "`:000001:r:",
+ "`:000110:e:",
+ "`:000111:C:",
+ "`:100011:l:",
+ "`:100100:h:",
+ "`:100101:G:",
+ "`:101001:B:",
+ "`:101010:T:",
+ "`:101011:S:",
+ "`:0100000:o:",
+ "`:0100001:d:",
+ "`:0100010:b:",
+ "`:0100011:R:",
+ "`:1000100:O:",
+ "`:1000101:L:",
+ "`:1010001:f:",
+ "`:10100000:J:",
+ "`:101000010:ESCAPE:",
+ "`:101000011:M:",
+ "a:01:n:",
+ "a:001:r:",
+ "a:101:t:",
+ "a:0000:m:",
+ "a:1001:s:",
+ "a:1110: :",
+ "a:1111:l:",
+ "a:00011:d:",
+ "a:10000:i:",
+ "a:11000:y:",
+ "a:11010:c:",
+ "a:000100:p:",
+ "a:100010:u:",
+ "a:100011:v:",
+ "a:110011:g:",
+ "a:110110:b:",
+ "a:110111:k:",
+ "a:0001010:w:",
+ "a:00010111:z:",
+ "a:11001000:.:",
+ "a:11001011:f:",
+ "a:000101100:,:",
+ "a:000101101:':",
+ "a:110010011:e:",
+ "a:110010101:h:",
+ "a:1100101001:x:",
+ "a:11001001000:a:",
+ "a:11001001001:-:",
+ "a:11001001011:j:",
+ "a:11001010000:0x3a:",
+ "a:11001010001:o:",
+ "a:110010010100:q:",
+ "a:11001001010100:!:",
+ "a:11001001010111:?:",
+ "a:1100100101010100:ESCAPE:",
+ "a:1100100101010110:;:",
+ "a:1100100101010111:):",
+ "a:1100100101011001:/:",
+ "a:1100100101011011:@:",
+ "a:11001001010101010:J:",
+ "a:11001001010101011:]:",
+ "a:11001001010110100:N:",
+ "a:11001001010110101:L:",
+ "a:110010010101100000:R:",
+ "a:110010010101100001:S:",
+ "a:110010010101100010:V:",
+ "a:11001001010110001100:[:",
+ "a:11001001010110001110:P:",
+ "a:11001001010110001111:STOP:",
+ "a:110010010101100011010:W:",
+ "a:110010010101100011011:1:",
+ "b:00:e:",
+ "b:010:u:",
+ "b:011:a:",
+ "b:100:y:",
+ "b:101:o:",
+ "b:1100:l:",
+ "b:1110:r:",
+ "b:1111:i:",
+ "b:110100:s:",
+ "b:110110: :",
+ "b:110111:b:",
+ "b:11010101:c:",
+ "b:110101000:j:",
+ "b:110101100:,:",
+ "b:110101101:.:",
+ "b:1101010011:':",
+ "b:1101011111:t:",
+ "b:11010100101:0x3a:",
+ "b:11010111000:w:",
+ "b:11010111001:d:",
+ "b:11010111010:h:",
+ "b:11010111011:&:",
+ "b:11010111101:-:",
+ "b:110101111000:m:",
+ "b:110101111001:n:",
+ "b:1101010010000:?:",
+ "b:1101010010010:v:",
+ "b:11010100100010:f:",
+ "b:11010100100111:p:",
+ "b:110101001000111:;:",
+ "b:110101001001101:D:",
+ "b:1101010010001100:/:",
+ "b:1101010010011001:@:",
+ "b:11010100100011010:X:",
+ "b:11010100100011011:\":",
+ "b:11010100100110001:k:",
+ "b:110101001001100000:STOP:",
+ "b:1101010010011000010:ESCAPE:",
+ "b:1101010010011000011:!:",
+ "c:00:o:",
+ "c:011:a:",
+ "c:100:e:",
+ "c:110:h:",
+ "c:0100:i:",
+ "c:0101:l:",
+ "c:1011:k:",
+ "c:1111:t:",
+ "c:10100:u:",
+ "c:10101:r:",
+ "c:11100: :",
+ "c:1110100:y:",
+ "c:1110101:c:",
+ "c:11101101:s:",
+ "c:11101110:.:",
+ "c:111011111:,:",
+ "c:1110110001:G:",
+ "c:11101100001:n:",
+ "c:11101100110:D:",
+ "c:11101111000:K:",
+ "c:11101111011:C:",
+ "c:111011000000:0x3a:",
+ "c:111011001001:-:",
+ "c:111011001010:A:",
+ "c:111011001110:L:",
+ "c:111011001111:':",
+ "c:111011110010:d:",
+ "c:111011110100:q:",
+ "c:111011110101:I:",
+ "c:1110110010000:N:",
+ "c:1110110010001:z:",
+ "c:1110111100111:F:",
+ "c:11101100000101:w:",
+ "c:11101100000111:E:",
+ "c:11101100101100:?:",
+ "c:11101111001100:M:",
+ "c:11101111001101:S:",
+ "c:111011000001000:b:",
+ "c:111011000001001:ESCAPE:",
+ "c:111011000001100:!:",
+ "c:111011001011010:Q:",
+ "c:111011001011011:P:",
+ "c:111011001011100:;:",
+ "c:111011001011110:B:",
+ "c:1110110000011011:V:",
+ "c:1110110010111011:m:",
+ "c:1110110010111110:/:",
+ "c:11101100000110101:):",
+ "c:11101100101110100:U:",
+ "c:11101100101111110:W:",
+ "c:111011000001101000:p:",
+ "c:111011000001101001:H:",
+ "c:111011001011101010:STOP:",
+ "c:111011001011111110:R:",
+ "c:111011001011111111:T:",
+ "c:1110110010111010110:]:",
+ "c:1110110010111010111:[:",
+ "d:0: :",
+ "d:101:e:",
+ "d:1100:a:",
+ "d:1110:i:",
+ "d:10001:.:",
+ "d:10011:o:",
+ "d:11011:r:",
+ "d:11111:s:",
+ "d:100001:d:",
+ "d:100101:l:",
+ "d:110100:u:",
+ "d:111101:y:",
+ "d:1001001:-:",
+ "d:1101011:v:",
+ "d:1111000:g:",
+ "d:1111001:,:",
+ "d:10000000:h:",
+ "d:10000001:0x3a:",
+ "d:10000010:m:",
+ "d:10010000:w:",
+ "d:10010001:n:",
+ "d:11010101:':",
+ "d:100000111:f:",
+ "d:1101010001:?:",
+ "d:1101010010:b:",
+ "d:1101010011:c:",
+ "d:10000011000:!:",
+ "d:11010100000:p:",
+ "d:11010100001:t:",
+ "d:100000110010:STOP:",
+ "d:100000110011:):",
+ "d:100000110100:k:",
+ "d:100000110101:;:",
+ "d:100000110111:/:",
+ "d:10000011011010:\":",
+ "d:10000011011011:j:",
+ "d:100000110110000:z:",
+ "d:100000110110011:q:",
+ "d:1000001101100011:@:",
+ "d:1000001101100100:ESCAPE:",
+ "d:10000011011000101:C:",
+ "d:10000011011001010:]:",
+ "d:100000110110001000:Z:",
+ "d:100000110110001001:[:",
+ "d:100000110110010110:T:",
+ "d:100000110110010111:`:",
+ "e:10: :",
+ "e:010:s:",
+ "e:110:r:",
+ "e:0000:d:",
+ "e:0011:a:",
+ "e:1111:n:",
+ "e:00010:c:",
+ "e:01100:e:",
+ "e:01101:w:",
+ "e:01111:t:",
+ "e:11100:l:",
+ "e:000110:x:",
+ "e:001000:v:",
+ "e:001001:i:",
+ "e:001010:y:",
+ "e:011100:m:",
+ "e:111010:.:",
+ "e:0001110:f:",
+ "e:0010111:b:",
+ "e:0111010:,:",
+ "e:1110110:p:",
+ "e:00011110:-:",
+ "e:00011111:h:",
+ "e:00101100:k:",
+ "e:01110110:':",
+ "e:11101110:g:",
+ "e:11101111:o:",
+ "e:001011011:0x3a:",
+ "e:0010110100:):",
+ "e:0010110101:q:",
+ "e:0111011101:?:",
+ "e:0111011110:u:",
+ "e:01110111000:z:",
+ "e:01110111110:!:",
+ "e:011101111110:STOP:",
+ "e:011101111111:j:",
+ "e:0111011100110:/:",
+ "e:01110111001001:4:",
+ "e:01110111001010:B:",
+ "e:01110111001110:]:",
+ "e:01110111001111:;:",
+ "e:011101110010000:\":",
+ "e:0111011100100011:D:",
+ "e:0111011100101100:ESCAPE:",
+ "e:0111011100101110:@:",
+ "e:01110111001000100:T:",
+ "e:01110111001000101:C:",
+ "e:01110111001011011:[:",
+ "e:01110111001011111:L:",
+ "e:011101110010110100:V:",
+ "e:011101110010110101:G:",
+ "e:011101110010111100:1:",
+ "e:01110111001011110101:E:",
+ "e:011101110010111101000:2:",
+ "e:011101110010111101001:N:",
+ "e:011101110010111101100:F:",
+ "e:011101110010111101101:A:",
+ "e:0111011100101111011100:\\:",
+ "e:0111011100101111011101:P:",
+ "e:0111011100101111011110:M:",
+ "e:0111011100101111011111:H:",
+ "f:00:o:",
+ "f:10: :",
+ "f:010:i:",
+ "f:110:r:",
+ "f:0111:a:",
+ "f:1110:e:",
+ "f:01100:t:",
+ "f:11110:u:",
+ "f:11111:f:",
+ "f:011011:l:",
+ "f:01101000:s:",
+ "f:01101001:y:",
+ "f:011010110:.:",
+ "f:0110101000:?:",
+ "f:0110101011:,:",
+ "f:0110101111:-:",
+ "f:01101010011:0x3a:",
+ "f:01101010100:':",
+ "f:01101010101:g:",
+ "f:011010100100:m:",
+ "f:011010111000:ESCAPE:",
+ "f:011010111010:b:",
+ "f:011010111011:n:",
+ "f:0110101001011:c:",
+ "f:0110101110010:!:",
+ "f:01101011100110:):",
+ "f:01101011100111:w:",
+ "f:011010100101001:p:",
+ "f:011010100101010:/:",
+ "f:0110101001010000:h:",
+ "f:0110101001010110:;:",
+ "f:01101010010100010:STOP:",
+ "f:01101010010100011:d:",
+ "f:01101010010101110:k:",
+ "f:01101010010101111:v:",
+ "g:11: :",
+ "g:000:a:",
+ "g:010:h:",
+ "g:101:e:",
+ "g:0011:u:",
+ "g:0110:r:",
+ "g:1000:i:",
+ "g:01110:l:",
+ "g:10010:s:",
+ "g:10011:o:",
+ "g:001001:,:",
+ "g:001010:n:",
+ "g:011110:g:",
+ "g:011111:.:",
+ "g:0010110:y:",
+ "g:00100001:':",
+ "g:00100010:-:",
+ "g:00100011:0x3a:",
+ "g:001000000:d:",
+ "g:001011101:b:",
+ "g:001011110:t:",
+ "g:001011111:w:",
+ "g:0010000010:?:",
+ "g:0010000011:m:",
+ "g:00101110001:!:",
+ "g:00101110011:f:",
+ "g:001011100001:;:",
+ "g:001011100101:STOP:",
+ "g:0010111000000:k:",
+ "g:0010111001000:p:",
+ "g:00101110000010:):",
+ "g:00101110000011:\":",
+ "g:001011100100101:c:",
+ "g:001011100100111:/:",
+ "g:0010111001001000:ESCAPE:",
+ "g:0010111001001100:]:",
+ "g:0010111001001101:z:",
+ "g:00101110010010010:`:",
+ "g:001011100100100110:v:",
+ "g:001011100100100111:@:",
+ "h:0:e:",
+ "h:100:o:",
+ "h:101:i:",
+ "h:110: :",
+ "h:1111:a:",
+ "h:111001:r:",
+ "h:111011:t:",
+ "h:11100001:y:",
+ "h:11100011:l:",
+ "h:11101000:.:",
+ "h:11101001:n:",
+ "h:11101011:u:",
+ "h:111000000:d:",
+ "h:111000100:s:",
+ "h:111010100:,:",
+ "h:1110000011:w:",
+ "h:1110001010:':",
+ "h:1110001011:-:",
+ "h:11101010101:m:",
+ "h:11101010110:0x3a:",
+ "h:11101010111:b:",
+ "h:111000001001:c:",
+ "h:111000001011:?:",
+ "h:111010101000:!:",
+ "h:1110000010000:):",
+ "h:1110000010100:h:",
+ "h:1110000010101:k:",
+ "h:1110101010011:f:",
+ "h:11101010100101:g:",
+ "h:111000001000100:p:",
+ "h:111000001000101:;:",
+ "h:111000001000110:/:",
+ "h:111000001000111:STOP:",
+ "h:111010101001001:v:",
+ "h:1110101010010000:q:",
+ "h:11101010100100010:ESCAPE:",
+ "h:111010101001000110:\":",
+ "h:11101010100100011100:z:",
+ "h:11101010100100011101:j:",
+ "h:11101010100100011110:]:",
+ "h:11101010100100011111:*:",
+ "i:10:n:",
+ "i:000:t:",
+ "i:010:s:",
+ "i:0011:l:",
+ "i:1100:o:",
+ "i:1101:c:",
+ "i:1111:e:",
+ "i:00100:a:",
+ "i:01100:m:",
+ "i:01101:d:",
+ "i:01110:v:",
+ "i:11100:g:",
+ "i:11101:r:",
+ "i:001010:p:",
+ "i:011110:f:",
+ "i:0010110:z:",
+ "i:0111110: :",
+ "i:00101111:b:",
+ "i:01111110:k:",
+ "i:001011100:-:",
+ "i:001011101:x:",
+ "i:0111111100:u:",
+ "i:0111111110:q:",
+ "i:01111111010:.:",
+ "i:01111111110:,:",
+ "i:011111110111:w:",
+ "i:011111111111:':",
+ "i:0111111101101:i:",
+ "i:0111111111101:j:",
+ "i:01111111011001:0x3a:",
+ "i:01111111111000:h:",
+ "i:011111110110000:/:",
+ "i:011111111110011:y:",
+ "i:0111111101100011:?:",
+ "i:0111111111100100:P:",
+ "i:01111111011000101:R:",
+ "i:01111111111001011:!:",
+ "i:011111111110010100:):",
+ "i:011111111110010101:S:",
+ "i:0111111101100010000:STOP:",
+ "i:0111111101100010001:C:",
+ "i:0111111101100010010:ESCAPE:",
+ "i:01111111011000100110:D:",
+ "i:01111111011000100111:;:",
+ "j:0:o:",
+ "j:11:u:",
+ "j:101:a:",
+ "j:1001:e:",
+ "j:10000:i:",
+ "j:100011:y:",
+ "j:1000101: :",
+ "j:10001001:.:",
+ "j:100010000:':",
+ "j:1000100011:t:",
+ "j:10001000100:n:",
+ "j:100010001011:s:",
+ "j:1000100010100:ESCAPE:",
+ "j:1000100010101:h:",
+ "k:10: :",
+ "k:11:e:",
+ "k:000:s:",
+ "k:011:i:",
+ "k:0010:.:",
+ "k:01001:y:",
+ "k:001100:':",
+ "k:001101:a:",
+ "k:001110:p:",
+ "k:001111:,:",
+ "k:010100:l:",
+ "k:010101:f:",
+ "k:010110:n:",
+ "k:0100000:/:",
+ "k:0100010:-:",
+ "k:0100011:o:",
+ "k:01011101:0x3a:",
+ "k:010000111:b:",
+ "k:010111000:w:",
+ "k:010111001:m:",
+ "k:010111100:h:",
+ "k:010111110:u:",
+ "k:010111111:k:",
+ "k:0100001000:r:",
+ "k:0100001001:ESCAPE:",
+ "k:0100001010:?:",
+ "k:0100001100:t:",
+ "k:0100001101:g:",
+ "k:0101111011:d:",
+ "k:01000010110:j:",
+ "k:010000101110:):",
+ "k:010111101000:;:",
+ "k:010111101001:c:",
+ "k:010111101010:S:",
+ "k:0100001011110:v:",
+ "k:0100001011111:R:",
+ "k:0101111010110:!:",
+ "k:01011110101110:@:",
+ "k:010111101011110:\":",
+ "k:010111101011111:STOP:",
+ "l:010:a:",
+ "l:011:i:",
+ "l:100:l:",
+ "l:110:e:",
+ "l:111: :",
+ "l:0000:u:",
+ "l:0001:d:",
+ "l:0010:y:",
+ "l:1011:o:",
+ "l:10100:s:",
+ "l:001100:.:",
+ "l:001110:t:",
+ "l:0011010:v:",
+ "l:0011110:f:",
+ "l:1010100:m:",
+ "l:1010101:k:",
+ "l:1010110:p:",
+ "l:00110111:c:",
+ "l:00111110:-:",
+ "l:10101111:,:",
+ "l:001101101:0x3a:",
+ "l:001111111:b:",
+ "l:101011100:':",
+ "l:0011011000:r:",
+ "l:0011011001:h:",
+ "l:0011111100:n:",
+ "l:0011111101:g:",
+ "l:1010111011:w:",
+ "l:10101110100:?:",
+ "l:1010111010100:!:",
+ "l:1010111010110:z:",
+ "l:10101110101011:/:",
+ "l:101011101010100:;:",
+ "l:101011101011100:E:",
+ "l:101011101011101:*:",
+ "l:101011101011111:STOP:",
+ "l:1010111010101011:ESCAPE:",
+ "l:1010111010111100:):",
+ "l:10101110101010100:@:",
+ "l:10101110101010101:j:",
+ "l:10101110101111010:\":",
+ "l:101011101011110110:[:",
+ "l:101011101011110111:]:",
+ "m:00:a:",
+ "m:01:e:",
+ "m:111: :",
+ "m:1001:p:",
+ "m:1011:o:",
+ "m:1100:i:",
+ "m:10000:.:",
+ "m:10001:s:",
+ "m:11010:u:",
+ "m:11011:m:",
+ "m:101001:y:",
+ "m:101011:b:",
+ "m:1010000:,:",
+ "m:1010100:/:",
+ "m:10100010:]:",
+ "m:101000110:0x3a:",
+ "m:101010100:':",
+ "m:1010001111:r:",
+ "m:1010101011:f:",
+ "m:1010101100:l:",
+ "m:1010101110:n:",
+ "m:10100011100:?:",
+ "m:10100011101:!:",
+ "m:10101010100:STOP:",
+ "m:10101010101:w:",
+ "m:10101011011:h:",
+ "m:10101011110:-:",
+ "m:101010111110:4:",
+ "m:1010101101010:t:",
+ "m:1010101101011:@:",
+ "m:1010101111110:;:",
+ "m:1010101111111:c:",
+ "m:10101011010000:):",
+ "m:10101011010001:ESCAPE:",
+ "m:10101011010011:d:",
+ "m:101010110100101:g:",
+ "m:10101011010010000:[:",
+ "m:10101011010010001:v:",
+ "m:10101011010010010:k:",
+ "m:10101011010010011:z:",
+ "n:01: :",
+ "n:001:t:",
+ "n:100:g:",
+ "n:111:d:",
+ "n:0000:s:",
+ "n:1010:a:",
+ "n:1101:e:",
+ "n:10110:c:",
+ "n:11000:i:",
+ "n:000111:.:",
+ "n:101111:n:",
+ "n:110011:o:",
+ "n:0001001:u:",
+ "n:0001011:v:",
+ "n:0001100:f:",
+ "n:1011100:k:",
+ "n:1011101:':",
+ "n:1100100:y:",
+ "n:1100101:,:",
+ "n:00010000:m:",
+ "n:00010100:l:",
+ "n:00010101:-:",
+ "n:000100011:w:",
+ "n:000110101:0x3a:",
+ "n:0001000101:z:",
+ "n:0001101000:h:",
+ "n:0001101100:b:",
+ "n:0001101101:j:",
+ "n:0001101110:r:",
+ "n:00010001000:p:",
+ "n:00011010011:x:",
+ "n:00011011111:?:",
+ "n:000100010011:;:",
+ "n:000110100101:):",
+ "n:000110111100:!:",
+ "n:000110111101:q:",
+ "n:0001000100100:/:",
+ "n:0001000100101:STOP:",
+ "n:0001101001000:ESCAPE:",
+ "n:00011010010010:B:",
+ "n:0001101001001100:]:",
+ "n:0001101001001101:\":",
+ "n:0001101001001110:@:",
+ "n:0001101001001111:*:",
+ "o:001:u:",
+ "o:011: :",
+ "o:100:r:",
+ "o:111:n:",
+ "o:0000:l:",
+ "o:1100:m:",
+ "o:1101:f:",
+ "o:00010:v:",
+ "o:01000:s:",
+ "o:01001:p:",
+ "o:10100:t:",
+ "o:10101:o:",
+ "o:10111:w:",
+ "o:000110:k:",
+ "o:000111:i:",
+ "o:010100:g:",
+ "o:010111:c:",
+ "o:101101:d:",
+ "o:0101011:e:",
+ "o:0101100:y:",
+ "o:0101101:a:",
+ "o:1011001:b:",
+ "o:01010101:h:",
+ "o:10110000:.:",
+ "o:010101000:-:",
+ "o:010101001:,:",
+ "o:1011000101:':",
+ "o:1011000111:x:",
+ "o:10110001001:0x3a:",
+ "o:10110001101:z:",
+ "o:101100010001:?:",
+ "o:101100011001:j:",
+ "o:1011000100000:!:",
+ "o:1011000110001:q:",
+ "o:10110001000010:J:",
+ "o:10110001100000:/:",
+ "o:10110001100001:):",
+ "o:1011000100001101:;:",
+ "o:1011000100001110:G:",
+ "o:10110001000011000:\":",
+ "o:10110001000011110:ESCAPE:",
+ "o:101100010000110010:]:",
+ "o:101100010000110011:@:",
+ "o:1011000100001111100:4:",
+ "o:1011000100001111101:STOP:",
+ "o:1011000100001111110:B:",
+ "o:10110001000011111110:O:",
+ "o:10110001000011111111:C:",
+ "p:001:l:",
+ "p:010: :",
+ "p:011:o:",
+ "p:101:r:",
+ "p:111:e:",
+ "p:0000:p:",
+ "p:1100:a:",
+ "p:1101:i:",
+ "p:00011:t:",
+ "p:10000:u:",
+ "p:10001:h:",
+ "p:10010:s:",
+ "p:000101:m:",
+ "p:0001001:d:",
+ "p:1001101:y:",
+ "p:1001110:.:",
+ "p:1001111:,:",
+ "p:00010000:-:",
+ "p:000100011:?:",
+ "p:100110001:0x3a:",
+ "p:1001100100:':",
+ "p:1001100101:]:",
+ "p:1001100110:+:",
+ "p:1001100111:b:",
+ "p:00010001001:f:",
+ "p:00010001010:k:",
+ "p:00010001011:!:",
+ "p:10011000001:c:",
+ "p:10011000010:n:",
+ "p:10011000011:w:",
+ "p:000100010000:STOP:",
+ "p:000100010001:;:",
+ "p:100110000001:/:",
+ "p:1001100000001:g:",
+ "p:10011000000001:):",
+ "p:100110000000001:\":",
+ "p:1001100000000001:S:",
+ "p:10011000000000000:ESCAPE:",
+ "p:10011000000000001:B:",
+ "q:1:u:",
+ "q:000:,:",
+ "q:001:.:",
+ "q:011: :",
+ "q:01001:b:",
+ "q:01010:':",
+ "q:01011:i:",
+ "q:010001:a:",
+ "q:01000000:?:",
+ "q:01000001:0x3a:",
+ "q:01000011:):",
+ "q:010000100:ESCAPE:",
+ "q:010000101:w:",
+ "r:000:a:",
+ "r:001:o:",
+ "r:100:i:",
+ "r:110: :",
+ "r:111:e:",
+ "r:0100:s:",
+ "r:0101:t:",
+ "r:01110:d:",
+ "r:10100:n:",
+ "r:10101:y:",
+ "r:011010:u:",
+ "r:011011:m:",
+ "r:011111:k:",
+ "r:101101:l:",
+ "r:101110:.:",
+ "r:101111:r:",
+ "r:0110000:f:",
+ "r:0110010:,:",
+ "r:0110011:v:",
+ "r:1011000:c:",
+ "r:1011001:g:",
+ "r:01100011:':",
+ "r:01111000:-:",
+ "r:01111001:b:",
+ "r:01111011:p:",
+ "r:011000101:0x3a:",
+ "r:011110100:w:",
+ "r:0111101010:?:",
+ "r:0111101011:h:",
+ "r:01100010010:!:",
+ "r:011000100001:q:",
+ "r:011000100010:j:",
+ "r:011000100011:STOP:",
+ "r:011000100110:/:",
+ "r:0110001000001:;:",
+ "r:0110001001111:):",
+ "r:01100010011100:8:",
+ "r:01100010011101:z:",
+ "r:011000100000001:\":",
+ "r:011000100000011:]:",
+ "r:0110001000000000:T:",
+ "r:0110001000000100:x:",
+ "r:0110001000000101:ESCAPE:",
+ "r:01100010000000011:Z:",
+ "r:011000100000000100:*:",
+ "r:0110001000000001010:D:",
+ "r:0110001000000001011:B:",
+ "s:0: :",
+ "s:101:t:",
+ "s:1000:.:",
+ "s:1110:e:",
+ "s:10011:,:",
+ "s:11000:o:",
+ "s:11001:s:",
+ "s:11110:h:",
+ "s:11111:i:",
+ "s:100101:c:",
+ "s:110100:u:",
+ "s:110110:p:",
+ "s:1101111:a:",
+ "s:10010001:n:",
+ "s:10010011:m:",
+ "s:11010100:y:",
+ "s:11010110:0x3a:",
+ "s:11011100:l:",
+ "s:11011101:k:",
+ "s:100100001:b:",
+ "s:100100100:f:",
+ "s:110101010:w:",
+ "s:110101111:':",
+ "s:1001000000:!:",
+ "s:1001000001:g:",
+ "s:1001001010:r:",
+ "s:1101010110:?:",
+ "s:1101010111:-:",
+ "s:1101011101:q:",
+ "s:11010111001:d:",
+ "s:100100101100:/:",
+ "s:100100101101:):",
+ "s:100100101111:STOP:",
+ "s:110101110000:]:",
+ "s:110101110001:;:",
+ "s:1001001011101:v:",
+ "s:100100101110001:\":",
+ "s:100100101110011:z:",
+ "s:1001001011100000:j:",
+ "s:1001001011100001:ESCAPE:",
+ "s:1001001011100100:[:",
+ "s:10010010111001011:@:",
+ "s:100100101110010101:T:",
+ "s:1001001011100101000:x:",
+ "s:1001001011100101001:`:",
+ "t:10:h:",
+ "t:000:i:",
+ "t:010:o:",
+ "t:011:e:",
+ "t:111: :",
+ "t:0010:a:",
+ "t:00110:u:",
+ "t:11001:r:",
+ "t:11011:s:",
+ "t:001111:.:",
+ "t:110001:t:",
+ "t:110100:y:",
+ "t:0011101:c:",
+ "t:1100001:l:",
+ "t:00111001:-:",
+ "t:11000000:v:",
+ "t:11000001:m:",
+ "t:11010101:w:",
+ "t:11010110:,:",
+ "t:11010111:':",
+ "t:001110000:n:",
+ "t:0011100011:?:",
+ "t:1101010001:b:",
+ "t:1101010010:0x3a:",
+ "t:00111000100:!:",
+ "t:11010100000:z:",
+ "t:11010100110:d:",
+ "t:11010100111:f:",
+ "t:110101000010:x:",
+ "t:0011100010100:g:",
+ "t:0011100010101:;:",
+ "t:1101010000110:p:",
+ "t:00111000101100:P:",
+ "t:00111000101101:STOP:",
+ "t:00111000101111:):",
+ "t:11010100001110:/:",
+ "t:11010100001111:k:",
+ "t:0011100010111000:@:",
+ "t:0011100010111010:E:",
+ "t:00111000101110011:]:",
+ "t:00111000101110111:\":",
+ "t:001110001011100100:F:",
+ "t:001110001011101100:ESCAPE:",
+ "t:0011100010111001010:j:",
+ "t:0011100010111011010:1:",
+ "t:0011100010111011011:[:",
+ "t:00111000101110010110:\\:",
+ "t:001110001011100101110:K:",
+ "t:001110001011100101111:C:",
+ "u:011:t:",
+ "u:101:n:",
+ "u:110:s:",
+ "u:111:r:",
+ "u:0001:d:",
+ "u:0010:e:",
+ "u:0101:l:",
+ "u:1000:p:",
+ "u:00000:b:",
+ "u:00001: :",
+ "u:00110:i:",
+ "u:01000:a:",
+ "u:01001:g:",
+ "u:10010:c:",
+ "u:10011:m:",
+ "u:0011100:y:",
+ "u:00111010:z:",
+ "u:00111100:':",
+ "u:00111110:f:",
+ "u:00111111:k:",
+ "u:001111010:,:",
+ "u:0011101101:-:",
+ "u:0011101110:o:",
+ "u:0011110110:.:",
+ "u:0011110111:x:",
+ "u:00111011000:w:",
+ "u:00111011110:0x3a:",
+ "u:001110110010:q:",
+ "u:001110111110:h:",
+ "u:001110111111:v:",
+ "u:0011101100110:j:",
+ "u:001110110011100:u:",
+ "u:001110110011101:?:",
+ "u:0011101100111110:/:",
+ "u:0011101100111111:!:",
+ "u:00111011001111001:ESCAPE:",
+ "u:001110110011110000:\\:",
+ "u:001110110011110001:STOP:",
+ "u:001110110011110100:;:",
+ "u:001110110011110110:J:",
+ "u:001110110011110111:):",
+ "u:0011101100111101010:T:",
+ "u:0011101100111101011:]:",
+ "v:1:e:",
+ "v:01:i:",
+ "v:000:a:",
+ "v:0011:o:",
+ "v:00101:.:",
+ "v:001001: :",
+ "v:00100001:':",
+ "v:00100011:y:",
+ "v:001000000:u:",
+ "v:001000100:s:",
+ "v:0010001010:r:",
+ "v:00100000100:-:",
+ "v:00100000110:,:",
+ "v:00100010110:n:",
+ "v:001000001010:g:",
+ "v:001000001011:v:",
+ "v:001000001111:l:",
+ "v:001000101110:@:",
+ "v:001000101111:0x3a:",
+ "v:0010000011101:k:",
+ "v:00100000111000:b:",
+ "v:001000001110010:t:",
+ "v:0010000011100110:d:",
+ "v:00100000111001110:/:",
+ "v:001000001110011110:ESCAPE:",
+ "v:001000001110011111:1:",
+ "w:00:i:",
+ "w:011:e:",
+ "w:100: :",
+ "w:101:s:",
+ "w:110:h:",
+ "w:0101:a:",
+ "w:1111:o:",
+ "w:01000:.:",
+ "w:01001:w:",
+ "w:11100:n:",
+ "w:1110110:r:",
+ "w:11101010:,:",
+ "w:11101011:l:",
+ "w:11101111:y:",
+ "w:111010010:c:",
+ "w:111011101:b:",
+ "w:1110100010:0x3a:",
+ "w:1110100110:m:",
+ "w:1110100111:':",
+ "w:1110111000:d:",
+ "w:11101000000:f:",
+ "w:11101000001:]:",
+ "w:11101000010:!:",
+ "w:11101000111:k:",
+ "w:11101110010:-:",
+ "w:111010000111:g:",
+ "w:111010001100:?:",
+ "w:111010001101:t:",
+ "w:111011100111:p:",
+ "w:1110100001100:STOP:",
+ "w:1110100001101:u:",
+ "w:1110111001101:):",
+ "w:11101110011001:j:",
+ "w:111011100110001:q:",
+ "w:1110111001100000:/:",
+ "w:11101110011000010:;:",
+ "w:111011100110000111:[:",
+ "w:1110111001100001100:ESCAPE:",
+ "w:1110111001100001101:B:",
+ "x:01:p:",
+ "x:11:t:",
+ "x:101: :",
+ "x:0000:i:",
+ "x:0010:a:",
+ "x:1000:c:",
+ "x:00010:u:",
+ "x:00111:e:",
+ "x:10011:-:",
+ "x:000110:f:",
+ "x:001101:o:",
+ "x:100100:.:",
+ "x:0001110:,:",
+ "x:0001111:m:",
+ "x:0011001:y:",
+ "x:00110001:9:",
+ "x:10010101:':",
+ "x:10010110:q:",
+ "x:001100000:s:",
+ "x:100101000:0x3a:",
+ "x:100101110:h:",
+ "x:0011000011:?:",
+ "x:1001010010:l:",
+ "x:1001011110:w:",
+ "x:00110000100:A:",
+ "x:10010100110:x:",
+ "x:10010100111:b:",
+ "x:10010111111:):",
+ "x:001100001011:/:",
+ "x:0011000010100:4:",
+ "x:0011000010101:!:",
+ "x:1001011111000:g:",
+ "x:1001011111001:STOP:",
+ "x:1001011111011:;:",
+ "x:100101111101001:v:",
+ "x:100101111101010:F:",
+ "x:100101111101011:E:",
+ "x:1001011111010000:ESCAPE:",
+ "x:1001011111010001:C:",
+ "y:1: :",
+ "y:000:o:",
+ "y:0011:s:",
+ "y:0101:.:",
+ "y:01001:,:",
+ "y:01100:e:",
+ "y:01110:':",
+ "y:001001:a:",
+ "y:001010:i:",
+ "y:001011:d:",
+ "y:010001:n:",
+ "y:011011:0x3a:",
+ "y:011111:l:",
+ "y:0010000:w:",
+ "y:0110100:t:",
+ "y:0110101:m:",
+ "y:0111101:-:",
+ "y:00100011:b:",
+ "y:01000000:?:",
+ "y:01000001:r:",
+ "y:01000010:p:",
+ "y:01000011:f:",
+ "y:01111001:c:",
+ "y:0010001001:;:",
+ "y:0010001010:J:",
+ "y:0111100000:h:",
+ "y:0111100001:!:",
+ "y:0111100011:g:",
+ "y:00100010000:):",
+ "y:00100010111:/:",
+ "y:01111000101:]:",
+ "y:001000100011:k:",
+ "y:001000101100:ESCAPE:",
+ "y:001000101101:u:",
+ "y:011110001001:STOP:",
+ "y:0010001000100:z:",
+ "y:0111100010001:\":",
+ "y:00100010001011:j:",
+ "y:01111000100001:2:",
+ "y:001000100010100:y:",
+ "y:001000100010101:x:",
+ "y:0111100010000000:v:",
+ "y:0111100010000001:T:",
+ "y:0111100010000010:E:",
+ "y:0111100010000011:P:",
+ "z:10:e:",
+ "z:001:a:",
+ "z:011:z:",
+ "z:110: :",
+ "z:111:i:",
+ "z:0001:l:",
+ "z:0100:y:",
+ "z:01010:o:",
+ "z:000000:c:",
+ "z:000010:,:",
+ "z:000011:.:",
+ "z:010110:w:",
+ "z:0000010:':",
+ "z:00000110:0x3a:",
+ "z:00000111:t:",
+ "z:01011101:m:",
+ "z:010111000:k:",
+ "z:010111100:-:",
+ "z:010111101:u:",
+ "z:010111111:b:",
+ "z:01011100100:s:",
+ "z:01011100101:/:",
+ "z:01011100111:d:",
+ "z:01011111001:p:",
+ "z:01011111011:?:",
+ "z:010111001100:h:",
+ "z:010111110000:@:",
+ "z:010111110100:):",
+ "z:0101110011010:!:",
+ "z:0101111100011:v:",
+ "z:0101111101010:g:",
+ "z:01011100110110:f:",
+ "z:01011100110111:r:",
+ "z:01011111000100:q:",
+ "z:01011111000101:n:",
+ "z:01011111010110:ESCAPE:",
+ "z:01011111010111:]:",
+ "{:0:ESCAPE:",
+ "{:1:ESCAPE:",
+ "|:0:ESCAPE:",
+ "|:1:ESCAPE:",
+ "}:0:ESCAPE:",
+ "}:1:STOP:",
+ "~:0:ESCAPE:",
+ "~:1:ESCAPE:",
+ "0x7f:0:ESCAPE:",
+ "0x7f:1:ESCAPE:",
+ NULL,
+};
+
+// MediaHighWay Ver. 1
+
+typedef struct
+{
+ u_char Name [15];
+} sThemeMHW1;
+
+typedef struct
+{
+ u_char NetworkIdHigh :8;
+ u_char NetworkIdLow :8;
+ u_char TransportIdHigh :8;
+ u_char TransportIdLow :8;
+ u_char ServiceIdHigh :8;
+ u_char ServiceIdLow :8;
+ u_char Name [16];
+} sChannelMHW1;
+
+typedef struct
+{
+ u_char TableId :8;
+#if BYTE_ORDER == BIG_ENDIAN
+ u_char SectionSyntaxIndicator :1;
+ u_char :1;
+ u_char :2;
+ u_char SectionLengthHigh :4;
+#else
+ u_char SectionLengthHigh :4;
+ u_char :2;
+ u_char :1;
+ u_char SectionSyntaxIndicator :1;
+#endif
+ u_char SectionLengthLow :8;
+ u_char ChannelId :8;
+ u_char ThemeId :8;
+#if BYTE_ORDER == BIG_ENDIAN
+ u_char Day :3;
+ u_char Hours :5;
+#else
+ u_char Hours :5;
+ u_char Day :3;
+#endif
+#if BYTE_ORDER == BIG_ENDIAN
+ u_char Minutes :6;
+ u_char :1;
+ u_char SummaryAvailable :1;
+#else
+ u_char SummaryAvailable :1;
+ u_char :1;
+ u_char Minutes :6;
+#endif
+ u_char :8;
+ u_char :8;
+ u_char DurationHigh :8;
+ u_char DurationLow :8;
+ u_char Title [23];
+ u_char PpvIdHigh :8;
+ u_char PpvIdMediumHigh :8;
+ u_char PpvIdMediumLow :8;
+ u_char PpvIdLow :8;
+ u_char ProgramIdHigh :8;
+ u_char ProgramIdMediumHigh :8;
+ u_char ProgramIdMediumLow :8;
+ u_char ProgramIdLow :8;
+ u_char :8;
+ u_char :8;
+ u_char :8;
+ u_char :8;
+} sTitleMHW1;
+
+typedef struct {
+ u_char TableId :8;
+#if BYTE_ORDER == BIG_ENDIAN
+ u_char SectionSyntaxIndicator :1;
+ u_char :1;
+ u_char :2;
+ u_char SectionLengthHigh :4;
+#else
+ u_char SectionLengthHigh :4;
+ u_char :2;
+ u_char :1;
+ u_char SectionSyntaxIndicator :1;
+#endif
+ u_char SectionLengthLow :8;
+ u_char ProgramIdHigh :8;
+ u_char ProgramIdMediumHigh :8;
+ u_char ProgramIdMediumLow :8;
+ u_char ProgramIdLow :8;
+ u_char Byte7 :8;
+ u_char Byte8 :8;
+ u_char Byte9 :8;
+ u_char NumReplays :8;
+} sSummaryMHW1;
+
+typedef struct {
+ u_char TableId :8;
+#if BYTE_ORDER == BIG_ENDIAN
+ u_char SectionSyntaxIndicator :1;
+ u_char :1;
+ u_char :2;
+ u_char SectionLengthHigh :4;
+#else
+ u_char SectionLengthHigh :4;
+ u_char :2;
+ u_char :1;
+ u_char SectionSyntaxIndicator :1;
+#endif
+ u_char SectionLengthLow :8;
+ u_char TableIdExtensionHigh :8;
+ u_char TableIdExtensionLow :8;
+#if BYTE_ORDER == BIG_ENDIAN
+ u_char Reserved :2;
+ u_char VersionNumber :5;
+ u_char CurrentNextIndicator :1;
+#else
+ u_char CurrentNextIndicator :1;
+ u_char VersionNumber :5;
+ u_char Reserved :2;
+#endif
+ u_char SectionNumber :8;
+ u_char LastSectionNumber :8;
+ u_char LanguageCodeHigh :8;
+ u_char LanguageCodeMedium :8;
+ u_char LanguageCodeLow :8;
+ u_char AlwaysZero0 :8;
+} sTitleBlockHeaderNagraGuide;
+
+typedef struct {
+ u_char ChannelIdHigh :8;
+ u_char ChannelIdLow :8;
+ u_char BlocklengthHigh :8;
+ u_char BlocklengthLow :8;
+ u_char NumberOfTitlesHigh :8;
+ u_char NumberOfTitlesMediumHigh :8;
+ u_char NumberOfTitlesMediumLow :8;
+ u_char NumberOfTitlesLow :8;
+} sTitleBlockNagraGuide; //all titles in one block are on the same channel
+
+typedef struct {
+ u_char EventIdHigh :8;
+ u_char EventIdMediumHigh :8;
+ u_char EventIdMediumLow :8;
+ u_char EventIdLow :8;
+ u_char StartTimeHigh :8;
+#if BYTE_ORDER == BIG_ENDIAN
+ u_char StartTimeLow :5;
+ u_char AlwaysZero16 :3;
+#else
+ u_char AlwaysZero16 :3;//can be 1,2,3 or 4 with night-programs etc.???
+ u_char StartTimeLow :5;
+#endif
+ u_char Duration :8;
+ u_char AlwaysZero1 :8;
+ u_char AlwaysZero2 :8;
+ u_char AlwaysZero3 :8;
+ u_char AlwaysZero4 :8;
+ u_char AlwaysZero5 :8;
+ u_char SumDataOffsetHigh :8;//address of relevant Summary Data Record
+ u_char SumDataOffsetMediumHigh :8;
+ u_char SumDataOffsetMediumLow :8;
+ u_char SumDataOffsetLow :8;
+ u_char AlwaysZero8 :8;
+ u_char AlwaysZero9 :8;
+ u_char AlwaysZero10 :8;
+ u_char AlwaysZero11 :8;
+ u_char OffsetToTextHigh :8;//offset from 2nd byte after languagecode gives length byte of title-text
+ u_char OffsetToTextMediumHigh :8;
+ u_char OffsetToTextMediumLow :8;
+ u_char OffsetToTextLow :8;
+ u_char OffsetToText2High :8;//offset from 2nd byte after languagecode gives length byte of title-text2
+ u_char OffsetToText2MediumHigh :8;
+ u_char OffsetToText2MediumLow :8;
+ u_char OffsetToText2Low :8;
+ u_char ThemeId :8;
+ u_char AlwaysZero17 :8;
+} sTitleNagraGuide;
+
+//first 4 bytes with zeroterminated language code
+typedef struct {
+ u_char AlwaysZero1 :8;
+ u_char AlwaysZero2 :8;
+ u_char AlwaysZero3 :8;
+ u_char AlwaysZero4 :8;
+ u_char Always1 :8;
+ u_char Always9 :8;
+ u_char Always7 :8;
+ u_char Always0 :8;
+ u_char AlwaysZero5 :8;
+ u_char AlwaysZero6 :8;
+ u_char AlwaysZero7 :8;
+ u_char AlwaysZero8 :8;
+ u_char AlwaysZero9 :8;
+ u_char Always0x01 :8;
+ u_char EventIdHigh :8;
+ u_char EventIdMediumHigh :8;
+ u_char EventIdMediumLow :8;
+ u_char EventIdLow :8;
+ u_char NumberOfBlocks :8;//every block > 2 adds 4 bytes, if block = 1 then no summtxtoffset so subtract 4 bytes!
+ u_char BlockIdHigh :8;
+ u_char BlockIdMediumHigh :8;
+ u_char BlockIdMediumLow :8;
+ u_char BlockIdLow :8;
+ u_char SummTxtOffsetHigh :8;//address from start of section + 4 points to relevant Always0x4e
+ u_char SummTxtOffsetMediumHigh :8;
+ u_char SummTxtOffsetMediumLow :8;
+ u_char SummTxtOffsetLow :8;
+ u_char Unknown1 :8;
+ u_char Unknown2 :8;
+} sSummaryDataNagraGuide;
+
+typedef struct {
+ u_char Always0x4e :8;//if 0x4e summarytext follows if 0x8c no summarytext GBR record follows
+ u_char Blocklength :8;
+#if BYTE_ORDER == BIG_ENDIAN
+ u_char TextNr :4;
+ u_char LastTextNr :4;
+#else
+ u_char LastTextNr :4;//last nr of block of text
+ u_char TextNr :4;//nr of a block of text, starts with 0!!!
+#endif
+ u_char LanguageCodeHigh :8;
+ u_char LanguageCodeMedium :8;
+ u_char LanguageCodeLow :8;
+ u_char AlwaysZero1 :8;
+ u_char Textlength :8;
+ u_char Text :8;
+} sSummaryTextNagraGuide;
+
+typedef struct {
+ u_char Always0x8c :8;
+ u_char Blocklength :8;
+ u_char AlwaysZero1 :8;
+ u_char AlwaysZero2 :8;
+ u_char Un1 :8;
+ u_char Un2 :8;
+ u_char Un3 :8;
+ u_char Un4 :8;
+ u_char AlwaysZero3 :8;
+ u_char Un5 :8;
+ u_char Un6 :8;
+ u_char Un7 :8;
+ u_char AlwaysZero4 :8;
+ u_char Un8 :8;
+ u_char Un9 :8;
+ u_char Nextlength :8;
+ u_char Always0x81 :8;
+ u_char EventIdHigh :8;
+ u_char EventIdMedium :8;
+ u_char EventIdLow :8;
+} sSummaryGBRNagraGuide;
+
+typedef struct {
+ u_char SatId :8;//is always 0x01
+ u_char NetworkIdHigh :8;
+ u_char NetworkIdLow :8;
+ u_char TransportIdHigh :8;
+ u_char TransportIdLow :8;
+ u_char ServiceIdHigh :8;
+ u_char ServiceIdLow :8;
+ u_char Nr8cBlocks :8;
+ u_char Always0x8c :8;//next three fields are 0x00 for FTA channels....
+ u_char Nr8cBytes :8;
+ u_char AlwaysZero1 :8;//from here on optional fields, not used for FTA channels like BVN, regional S23.5 broadcasts
+ u_char ProviderIdHigh :8;
+ u_char ProviderIdLow :8;
+ u_char Always0x08 :8;
+ u_char Always0x02 :8;
+ u_char Always0x01 :8;
+ u_char AlwaysZero2 :8;
+ u_char Always0x20 :8;
+ u_char Always0x0a :8;
+ u_char Un4 :8;
+ u_char Always0x81 :8;
+ u_char Un5 :8;
+ u_char Always0x44 :8;
+ u_char Un6 :8;
+ u_char Un7 :8;
+ u_char Un8 :8;
+ u_char Un9 :8;
+} sChannelsNagraGuide;
+
+typedef struct {
+ u_char TitleOffsetHigh :8;//address from start of section (in 0x02x0) + 4 points to eventid of title that has this theme
+ u_char TitleOffsetMediumHigh :8;
+ u_char TitleOffsetMediumLow :8;
+ u_char TitleOffsetLow :8;
+ u_char AlwaysZero1 :8;
+ u_char Un1 :8;
+ u_char AlwaysZero2 :8;
+ u_char Always1 :8;
+} sThemesTitlesNagraGuide;
+
+typedef struct { //first three bytes form unknown header, then X blocks, where X = number of distinct table_id_extensio
+#if BYTE_ORDER == BIG_ENDIAN
+ u_char TableIdExtensionLow :6;//BIG_ENDIAN not tested!!
+ u_char TableIdExtensionHigh :2;
+ u_char TIE200 :1;
+ u_char Unknown1 :2;
+ u_char VersionNumber :5;//contains current version of table_id_extension
+#else
+ u_char TableIdExtensionHigh :2;
+ u_char TableIdExtensionLow :6;
+ u_char VersionNumber :5;//contains current version of table_id_extension
+ u_char Unknown1 :2;
+ u_char TIE200 :1;
+#endif
+ u_char Always0xd6 :8;
+ u_char DayCounter :8;//for most sections this increments each day
+} sSection0000BlockNagraGuide;
+
+#define HILO16( x ) ( ( ( x##High << 8 ) | x##Low ) & 0xffff )
+#define HILO32( x ) ( ( ( ( ( x##High << 24 ) | ( x##MediumHigh << 16 ) ) | ( x##MediumLow << 8 ) ) | x##Low ) & 0xffffffff )
+#define MjdToEpochTime(x) (((x##_hi << 8 | x##_lo)-40587)*86400)
diff --git a/eit2.c b/eit2.c
new file mode 100644
index 0000000..3980dba
--- /dev/null
+++ b/eit2.c
@@ -0,0 +1,587 @@
+/*
+ * eit2.c
+ *
+ * Created on: Oct 16, 2012
+ * Author: d.petrovski
+ */
+#include "eit2.h"
+
+#include <string>
+#include <vdr/config.h>
+#include "log.h"
+#include "util.h"
+#include "dish.h"
+#include "equivhandler.h"
+
+using namespace std;
+using namespace util;
+
+namespace SI
+{
+
+cEvent* cEIT2::ProcessEitEvent(cSchedule* pSchedule,const SI::EIT::Event* EitEvent,
+ uchar Tid, uchar versionNumber)
+{
+ bool ExternalData = false;
+ // Drop bogus events - but keep NVOD reference events, where all bits of the start time field are set to 1, resulting in a negative number.
+ if (EitEvent->getStartTime () == 0 || (EitEvent->getStartTime () > 0 && EitEvent->getDuration () == 0))
+ return NULL;
+ Empty = false;
+ if (!SegmentStart)
+ SegmentStart = EitEvent->getStartTime ();
+ SegmentEnd = EitEvent->getStartTime () + EitEvent->getDuration ();
+ // int versionNumber = getVersionNumber();
+
+ cEvent *newEvent = NULL;
+ cEvent *pEvent = (cEvent *) pSchedule->GetEvent (EitEvent->getEventId (), EitEvent->getStartTime ());
+ if (!pEvent) {
+ if (OnlyRunningStatus)
+ return NULL;
+ // If we don't have that event yet, we create a new one.
+ // Otherwise we copy the information into the existing event anyway, because the data might have changed.
+ pEvent = newEvent = new cEvent (EitEvent->getEventId ());
+ if (!pEvent)
+ return NULL;
+ } else {
+ //LogD(3, prep("existing event channelID: %s Title: %s TableID 0x%02X new TID 0x%02X Version %i, new version %i"), *channel->GetChannelID().ToString(), pEvent->Title(), pEvent->TableID(), Tid, pEvent->Version(), versionNumber);
+ // We have found an existing event, either through its event ID or its start time.
+ pEvent->SetSeen ();
+
+ // If the existing event has a zero table ID it was defined externally and shall
+ // not be overwritten.
+ if (pEvent->TableID () == 0x00) {
+ if (pEvent->Version () == versionNumber)
+ return NULL;
+ /*HasExternalData = */ExternalData = true;
+ }
+ // If the new event has a higher table ID, let's skip it.
+ // The lower the table ID, the more "current" the information.
+ else if (Tid > pEvent->TableID())
+ return NULL;
+ // If the new event comes from the same table and has the same version number
+ // as the existing one, let's skip it to avoid unnecessary work.
+ // Unfortunately some stations (like, e.g. "Premiere") broadcast their EPG data on several transponders (like
+ // the actual Premiere transponder and the Sat.1/Pro7 transponder), but use different version numbers on
+ // each of them :-( So if one DVB card is tuned to the Premiere transponder, while an other one is tuned
+ // to the Sat.1/Pro7 transponder, events will keep toggling because of the bogus version numbers.
+ else if (Tid == pEvent->TableID() && pEvent->Version() == versionNumber)
+ return NULL;
+ }
+ if (!ExternalData) {
+ pEvent->SetEventID (EitEvent->getEventId ()); // unfortunately some stations use different event ids for the same event in different tables :-(
+ pEvent->SetTableID (Tid);
+ pEvent->SetStartTime (EitEvent->getStartTime ());
+ pEvent->SetDuration (EitEvent->getDuration ());
+ }
+ if (newEvent)
+ pSchedule->AddEvent (newEvent);
+ if (Tid == 0x4E) { // we trust only the present/following info on the actual TS
+ if (EitEvent->getRunningStatus () >= SI::RunningStatusNotRunning)
+ pSchedule->SetRunningStatus (pEvent, EitEvent->getRunningStatus (), channel);
+ }
+ if (OnlyRunningStatus)
+ return NULL; // do this before setting the version, so that the full update can be done later
+ pEvent->SetVersion (versionNumber);
+
+ ProcessEventDescriptors(ExternalData, channel->Source(), Tid, EitEvent,
+ pEvent, Schedules, channel);
+
+ Modified = true;
+ return pEvent;
+}
+
+void cEIT2::ProcessEventDescriptors(bool ExternalData, int Source,
+ u_char Tid, const SI::EIT::Event* SiEitEvent, cEvent* pEvent,
+ cSchedules* Schedules, cChannel* channel)
+{
+
+ cEvent *rEvent = NULL;
+ int LanguagePreferenceShort = -1;
+ int LanguagePreferenceExt = -1;
+ unsigned char nDescriptorTag;
+ bool UseExtendedEventDescriptor = false;
+ SI::Descriptor * d;
+ SI::ExtendedEventDescriptors * ExtendedEventDescriptors = NULL;
+ SI::ShortEventDescriptor * ShortEventDescriptor = NULL;
+ //SI::DishDescriptor *DishExtendedEventDescriptor = NULL;
+ SI::DishDescriptor *DishEventDescriptor = NULL;
+ //uchar DishTheme = 0, DishCategory = 0;
+
+
+ cLinkChannels *LinkChannels = NULL;
+ cComponents *Components = NULL;
+
+
+ DescriptorLoop dl = SiEitEvent->eventDescriptors;
+ for (SI::Loop::Iterator it2; (d = dl.getNext(it2)); )
+ {
+ if (ExternalData && d->getDescriptorTag() != SI::ComponentDescriptorTag)
+ {
+ delete d;
+ LogD(2, prep("continue:d->getDescriptorTAG():%x)"), d->getDescriptorTag ());
+ continue;
+ }
+
+ //LogD(2, prep("EEPGDEBUG:d->getDescriptorTAG():%x)"), d->getDescriptorTag ());
+ nDescriptorTag = d->getDescriptorTag();
+ switch (nDescriptorTag) {
+ case SI::ExtendedEventDescriptorTag: {
+ SI::ExtendedEventDescriptor * eed = (SI::ExtendedEventDescriptor *) d;
+ if (I18nIsPreferredLanguage(Setup.EPGLanguages, eed->languageCode, LanguagePreferenceExt)
+ || !ExtendedEventDescriptors) {
+ delete ExtendedEventDescriptors;
+ ExtendedEventDescriptors = new SI::ExtendedEventDescriptors;
+ UseExtendedEventDescriptor = true;
+ }
+ if (UseExtendedEventDescriptor) {
+ ExtendedEventDescriptors->Add(eed);
+ d = NULL; // so that it is not deleted
+ }
+ if (eed->getDescriptorNumber() == eed->getLastDescriptorNumber())
+ UseExtendedEventDescriptor = false;
+ }
+ break;
+ case SI::ShortEventDescriptorTag: {
+ SI::ShortEventDescriptor * sed = (SI::ShortEventDescriptor *) d;
+ if (I18nIsPreferredLanguage(Setup.EPGLanguages, sed->languageCode, LanguagePreferenceShort)
+ || !ShortEventDescriptor) {
+ delete ShortEventDescriptor;
+ ShortEventDescriptor = sed;
+ d = NULL; // so that it is not deleted
+ }
+ }
+ break;
+#if APIVERSNUM > 10711
+ case SI::ContentDescriptorTag: {
+ SI::ContentDescriptor *cd = (SI::ContentDescriptor *) d;
+ SI::ContentDescriptor::Nibble Nibble;
+ int NumContents = 0;
+ uchar Contents[MaxEventContents] = { 0 };
+ for (SI::Loop::Iterator it3; cd->nibbleLoop.getNext(Nibble, it3);) {
+ if (NumContents < MaxEventContents) {
+ Contents[NumContents] = ((Nibble.getContentNibbleLevel1() & 0xF) << 4)
+ | (Nibble.getContentNibbleLevel2() & 0xF);
+ NumContents++;
+ }
+ if (DishEventDescriptor && NumContents == 1) {
+ DishEventDescriptor->setContent(Nibble);
+ }
+ // LogD(2, prep("EEPGDEBUG:Nibble:%x-%x-%x-%x)"), Nibble.getContentNibbleLevel1(),Nibble.getContentNibbleLevel2()
+ // , Nibble.getUserNibble1(), Nibble.getUserNibble2());
+
+ }
+ pEvent->SetContents(Contents);
+ }
+ break;
+#endif
+ case SI::ParentalRatingDescriptorTag: {
+ int LanguagePreferenceRating = -1;
+ SI::ParentalRatingDescriptor *prd = (SI::ParentalRatingDescriptor *) d;
+ SI::ParentalRatingDescriptor::Rating Rating;
+ for (SI::Loop::Iterator it3; prd->ratingLoop.getNext(Rating, it3);) {
+ if (I18nIsPreferredLanguage(Setup.EPGLanguages, Rating.languageCode,
+ LanguagePreferenceRating)) {
+ int ParentalRating = (Rating.getRating() & 0xFF);
+ switch (ParentalRating) {
+ // values defined by the DVB standard (minimum age = rating + 3 years):
+ case 0x01 ... 0x0F: ParentalRating += 3; break;
+ // values defined by broadcaster CSAT (now why didn't they just use 0x07, 0x09 and 0x0D?):
+ case 0x11: ParentalRating = 10; break;
+ case 0x12: ParentalRating = 12; break;
+ case 0x13: ParentalRating = 16; break;
+ default: ParentalRating = 0;
+ }
+ pEvent->SetParentalRating(ParentalRating);
+ }
+ }
+ }
+ break;
+ case SI::PDCDescriptorTag: {
+ SI::PDCDescriptor * pd = (SI::PDCDescriptor *) d;
+ time_t now = time(NULL);
+ struct tm tm_r;
+ struct tm t = *localtime_r(&now, &tm_r); // this initializes the time zone in 't'
+ t.tm_isdst = -1; // makes sure mktime() will determine the correct DST setting
+ int month = t.tm_mon;
+ t.tm_mon = pd->getMonth() - 1;
+ t.tm_mday = pd->getDay();
+ t.tm_hour = pd->getHour();
+ t.tm_min = pd->getMinute();
+ t.tm_sec = 0;
+ if (month == 11 && t.tm_mon == 0) // current month is dec, but event is in jan
+ t.tm_year++;
+ else if (month == 0 && t.tm_mon == 11) // current month is jan, but event is in dec
+ t.tm_year--;
+ time_t vps = mktime(&t);
+ pEvent->SetVps(vps);
+ }
+ break;
+ case SI::TimeShiftedEventDescriptorTag: {
+ if (Schedules) {
+ SI::TimeShiftedEventDescriptor * tsed = (SI::TimeShiftedEventDescriptor *) d;
+ cSchedule *rSchedule = (cSchedule *) Schedules->GetSchedule(
+ tChannelID(Source, channel->Nid(), channel->Tid(), tsed->getReferenceServiceId()));
+ if (!rSchedule)
+ break;
+ rEvent = (cEvent *) rSchedule->GetEvent(tsed->getReferenceEventId());
+ if (!rEvent)
+ break;
+ pEvent->SetTitle(rEvent->Title());
+ pEvent->SetShortText(rEvent->ShortText());
+ pEvent->SetDescription(rEvent->Description());
+ }
+ }
+ break;
+ case SI::LinkageDescriptorTag: {
+ SI::LinkageDescriptor * ld = (SI::LinkageDescriptor *) d;
+ tChannelID linkID(Source, ld->getOriginalNetworkId(), ld->getTransportStreamId(),
+ ld->getServiceId());
+ if (ld->getLinkageType() == 0xB0) { // Premiere World
+ time_t now = time(NULL);
+ bool hit = SiEitEvent->getStartTime() <= now
+ && now < SiEitEvent->getStartTime() + SiEitEvent->getDuration();
+ if (hit) {
+ char linkName[ld->privateData.getLength() + 1];
+ strn0cpy(linkName, (const char *) ld->privateData.getData(), sizeof(linkName));
+ // TODO is there a standard way to determine the character set of this string?
+ cChannel *link = Channels.GetByChannelID(linkID);
+ if (link != channel) { // only link to other channels, not the same one
+ //fprintf(stderr, "Linkage %s %4d %4d %5d %5d %5d %5d %02X '%s'\n", hit ? "*" : "", channel->Number(), link ? link->Number() : -1, SiEitEvent.getEventId(), ld->getOriginalNetworkId(), ld->getTransportStreamId(), ld->getServiceId(), ld->getLinkageType(), linkName);//XXX
+ if (link) {
+ if (Setup.UpdateChannels == 1 || Setup.UpdateChannels >= 3)
+ link->SetName(linkName, "", "");
+ }
+ else if (Setup.UpdateChannels >= 4) {
+ cChannel *transponder = channel;
+ if (channel->Tid() != ld->getTransportStreamId())
+ transponder = Channels.GetByTransponderID(linkID);
+ link = Channels.NewChannel(transponder, linkName, "", "", ld->getOriginalNetworkId(),
+ ld->getTransportStreamId(), ld->getServiceId());
+ }
+ if (link) {
+ if (!LinkChannels) LinkChannels = new cLinkChannels;
+ LinkChannels->Add(new cLinkChannel(link));
+ }
+ }
+ else
+ channel->SetPortalName(linkName);
+ }
+ }
+ }
+ break;
+ case SI::ComponentDescriptorTag: {
+ SI::ComponentDescriptor * cd = (SI::ComponentDescriptor *) d;
+ uchar Stream = cd->getStreamContent();
+ uchar Type = cd->getComponentType();
+ //if (1 <= Stream && Stream <= 3 && Type != 0) { // 1=video, 2=audio, 3=subtitles
+ if (1 <= Stream && Stream <= 6 && Type != 0) { // 1=MPEG2-video, 2=MPEG1-audio, 3=subtitles, 4=AC3-audio, 5=H.264-video, 6=HEAAC-audio
+ if (!Components)
+ Components = new cComponents;
+ char buffer[Utf8BufSize (256)];
+ Components->SetComponent(Components->NumComponents(), Stream,
+ Type, I18nNormalizeLanguageCode(cd->languageCode),
+ cd->description.getText(buffer, sizeof(buffer)));
+ }
+ }
+ break;
+ case SI::DishExtendedEventDescriptorTag: {
+ SI::UnimplementedDescriptor *deed = (SI::UnimplementedDescriptor *) d;
+ if (!DishEventDescriptor) {
+ DishEventDescriptor = new SI::DishDescriptor();
+ }
+ DishEventDescriptor->setExtendedtData(Tid + 1, deed->getData());
+ // HasExternalData = true;
+ }
+ break;
+ case SI::DishShortEventDescriptorTag: {
+ SI::UnimplementedDescriptor *dsed = (SI::UnimplementedDescriptor *) d;
+ if (!DishEventDescriptor) {
+ DishEventDescriptor = new SI::DishDescriptor();
+ }
+ DishEventDescriptor->setShortData(Tid + 1, dsed->getData());
+ // HasExternalData = true;
+ }
+ break;
+ case SI::DishRatingDescriptorTag: {
+ if (d->getLength() == 4) {
+ if (!DishEventDescriptor) {
+ DishEventDescriptor = new SI::DishDescriptor();
+ }
+ uint16_t rating = d->getData().TwoBytes(2);
+ DishEventDescriptor->setRating(rating);
+ }
+ }
+ break;
+ case SI::DishSeriesDescriptorTag: {
+ if (d->getLength() == 10) {
+ //LogD(2, prep("DishSeriesDescriptorTag: %s)"), (const char*) d->getData().getData());
+ if (!DishEventDescriptor) {
+ DishEventDescriptor = new SI::DishDescriptor();
+ }
+ DishEventDescriptor->setEpisodeInfo(d->getData());
+ }
+ // else {
+ // LogD(2, prep("DishSeriesDescriptorTag length: %d)"), d->getLength());
+ // }
+ }
+ break;
+ default:
+ break;
+ }
+ delete d;
+ }
+ if (!rEvent) {
+ if (ShortEventDescriptor) {
+ char buffer[Utf8BufSize (256)];
+ unsigned char *f;
+ int l = ShortEventDescriptor->name.getLength();
+ f = (unsigned char *) ShortEventDescriptor->name.getData().getData();
+ decodeText2 (f, l, buffer, sizeof (buffer));
+ //ShortEventDescriptor->name.getText(buffer, sizeof(buffer));
+ LogD(2, prep("Title: %s Decoded: %s"), f, buffer);
+ pEvent->SetTitle (buffer);
+ LogD(3, prep("channelID: %s Title: %s"), *channel->GetChannelID().ToString(), pEvent->Title());
+ l = ShortEventDescriptor->text.getLength();
+ if (l > 0) { //Set the Short Text only if there is data so that we do not overwrite valid data
+ f = (unsigned char *) ShortEventDescriptor->text.getData().getData();
+ decodeText2 (f, l, buffer, sizeof (buffer));
+ //ShortEventDescriptor->text.getText(buffer, sizeof(buffer));
+ pEvent->SetShortText (buffer);
+ }
+ LogD(3, prep("ShortText: %s"), pEvent->ShortText());
+ LogD(2, prep("ShortText: %s Decoded: %s"), f, buffer);
+ } else if (/*!HasExternalData*/!DishEventDescriptor) {
+ pEvent->SetTitle (NULL);
+ pEvent->SetShortText (NULL);
+ LogD(3, prep("SetTitle (NULL)"));
+ }
+ if (ExtendedEventDescriptors) {
+ char buffer[Utf8BufSize (ExtendedEventDescriptors->getMaximumTextLength (": ")) + 1];
+ pEvent->SetDescription (ExtendedEventDescriptors->getText (buffer, sizeof (buffer), ": "));
+ LogD(3, prep("Description: %s"), pEvent->Description());
+ } else if (!/*HasExternalData*/DishEventDescriptor)
+ pEvent->SetDescription (NULL);
+
+ if (DishEventDescriptor) {
+ if (DishEventDescriptor->getName())
+ pEvent->SetTitle(DishEventDescriptor->getName());
+ //LogD(2, prep("channelID: %s DishTitle: %s"), *channel->GetChannelID().ToString(), DishEventDescriptor->getName());
+ pEvent->SetShortText(DishEventDescriptor->getShortText());
+ char *tmp;
+ string fmt;
+
+ const char * description = DishEventDescriptor->getDescription();
+ //BEV sets the description previously with ExtendedEventDescriptor
+ if (0 == strcmp(DishEventDescriptor->getDescription(),"") && pEvent->Description())
+ description = pEvent->Description();
+
+
+ fmt = "%s";
+ if (DishEventDescriptor->hasTheme()) {
+ fmt += "\nTheme: ";
+ }
+ fmt += "%s";
+ if (DishEventDescriptor->hasCategory()) {
+ fmt += "\nCategory: ";
+ }
+ fmt += "%s";
+
+ if ((0 != strcmp(DishEventDescriptor->getRating(),"")
+ || 0 != strcmp(DishEventDescriptor->getStarRating(),""))) {
+ fmt += "\n\nRating: ";
+ }
+ fmt += "%s %s";
+ if (0 != strcmp(DishEventDescriptor->getProgramId(),"")) {
+ fmt += "\n\nProgram ID: ";
+ }
+ fmt += "%s %s%s";
+ time_t orgAirDate = DishEventDescriptor->getOriginalAirDate();
+ char datestr [80];
+ bool dateok = false;
+ if (orgAirDate != 0) {
+ dateok = strftime (datestr,80," \nOriginal Air Date: %a %b %d %Y",gmtime(&orgAirDate)) > 0;
+ }
+
+ Asprintf (&tmp, fmt.c_str(), description
+ , DishEventDescriptor->getTheme(), DishEventDescriptor->getCategory()
+ , DishEventDescriptor->getRating(), DishEventDescriptor->getStarRating()
+ , DishEventDescriptor->getProgramId(), DishEventDescriptor->getSeriesId()
+ , orgAirDate == 0 || !dateok ? "" : datestr);
+ pEvent->SetDescription(tmp);
+ free(tmp);
+
+ //LogD(2, prep("DishDescription: %s"), DishEventDescriptor->getDescription());
+ //LogD(2, prep("DishShortText: %s"), DishEventDescriptor->getShortText());
+ }
+
+ }
+ delete ExtendedEventDescriptors;
+ delete ShortEventDescriptor;
+ delete DishEventDescriptor;
+
+ pEvent->SetComponents (Components);
+
+ // LogD(2, prep("channelID: %s Title: %s"), *channel->GetChannelID().ToString(), pEvent->Title());
+
+ // if (pEvent->ChannelID() == tChannelID::FromString("S119.0W-4100-6-110-110")) {
+ // LogD(2, prep("ID: %d Title: %s Time: %d Tid: 0x%x"), pEvent->EventID(), pEvent->Title(), pEvent->StartTime(), pEvent->TableID());
+ // }
+
+ //FixEpgBugs removes newlines from description which is not wanted especially for DISH/BEV
+ if (Format != DISH_BEV)
+ pEvent->FixEpgBugs();
+
+ if (LinkChannels)
+ channel->SetLinkChannels (LinkChannels);
+}
+
+cEIT2::cEIT2 (cSchedules * Schedules, int Source, u_char Tid, const u_char * Data, bool isEITPid, bool OnlyRunningStatus)
+: SI::EIT (Data, false)
+, OnlyRunningStatus(OnlyRunningStatus)
+, Schedules(Schedules)
+{
+
+ //LogD(2, prep("cEIT2::cEIT2"));
+ if (Tid > 0 && (Format == DISH_BEV || (cSetupEEPG::getInstance()->ProcessEIT && isEITPid))) Tid--;
+
+ if (!CheckCRCAndParse ()) {
+ LogD(2, prep("!CheckCRCAndParse ()"));
+ return;
+ }
+
+ bool searchOtherSatPositions = Format == DISH_BEV;
+
+ tChannelID channelID (Source, getOriginalNetworkId (), getTransportStreamId (), getServiceId ());
+ channel = GetChannelByID (channelID, searchOtherSatPositions);
+ if (!channel) {
+ LogD(3, prep("!channel channelID: %s"), *channelID.ToString());
+ return; // only collect data for known channels
+ }
+
+ //LogD(5, prep("channelID: %s format:%d"), *channel->GetChannelID().ToString(), Format);
+
+ cSchedule *pSchedule = (cSchedule *) Schedules->GetSchedule (channel, true);
+
+ Empty = true;
+ Modified = false;
+ // bool HasExternalData = false;
+ SegmentStart = 0;
+ SegmentEnd = 0;
+
+ SI::EIT::Event SiEitEvent;
+ for (SI::Loop::Iterator it; eventLoop.getNext (SiEitEvent, it);) {
+ int versionNumber = getVersionNumber();
+ // bool ExternalData = false;
+ // // Drop bogus events - but keep NVOD reference events, where all bits of the start time field are set to 1, resulting in a negative number.
+ // if (SiEitEvent.getStartTime () == 0 || (SiEitEvent.getStartTime () > 0 && SiEitEvent.getDuration () == 0))
+ // continue;
+ // Empty = false;
+ // if (!SegmentStart)
+ // SegmentStart = SiEitEvent.getStartTime ();
+ // SegmentEnd = SiEitEvent.getStartTime () + SiEitEvent.getDuration ();
+ // int versionNumber = getVersionNumber();
+ //
+ // cEvent *newEvent = NULL;
+ // cEvent *pEvent = (cEvent *) pSchedule->GetEvent (SiEitEvent.getEventId (), SiEitEvent.getStartTime ());
+ // if (!pEvent) {
+ // if (OnlyRunningStatus)
+ // continue;
+ // // If we don't have that event yet, we create a new one.
+ // // Otherwise we copy the information into the existing event anyway, because the data might have changed.
+ // pEvent = newEvent = new cEvent (SiEitEvent.getEventId ());
+ // if (!pEvent)
+ // continue;
+ // } else {
+ // //LogD(3, prep("existing event channelID: %s Title: %s TableID 0x%02X new TID 0x%02X Version %i, new version %i"), *channel->GetChannelID().ToString(), pEvent->Title(), pEvent->TableID(), Tid, pEvent->Version(), versionNumber);
+ // // We have found an existing event, either through its event ID or its start time.
+ // pEvent->SetSeen ();
+ //
+ // // If the existing event has a zero table ID it was defined externally and shall
+ // // not be overwritten.
+ // if (pEvent->TableID () == 0x00) {
+ // if (pEvent->Version () == versionNumber)
+ // continue;
+ // /*HasExternalData = */ExternalData = true;
+ // }
+ // // If the new event has a higher table ID, let's skip it.
+ // // The lower the table ID, the more "current" the information.
+ // else if (Tid > pEvent->TableID())
+ // continue;
+ // // If the new event comes from the same table and has the same version number
+ // // as the existing one, let's skip it to avoid unnecessary work.
+ // // Unfortunately some stations (like, e.g. "Premiere") broadcast their EPG data on several transponders (like
+ // // the actual Premiere transponder and the Sat.1/Pro7 transponder), but use different version numbers on
+ // // each of them :-( So if one DVB card is tuned to the Premiere transponder, while an other one is tuned
+ // // to the Sat.1/Pro7 transponder, events will keep toggling because of the bogus version numbers.
+ // else if (Tid == pEvent->TableID() && pEvent->Version() == versionNumber)
+ // continue;
+ // }
+ // if (!ExternalData) {
+ // pEvent->SetEventID (SiEitEvent.getEventId ()); // unfortunately some stations use different event ids for the same event in different tables :-(
+ // pEvent->SetTableID (Tid);
+ // pEvent->SetStartTime (SiEitEvent.getStartTime ());
+ // pEvent->SetDuration (SiEitEvent.getDuration ());
+ // }
+ // if (newEvent)
+ // pSchedule->AddEvent (newEvent);
+ // if (Tid == 0x4E) { // we trust only the present/following info on the actual TS
+ // if (SiEitEvent.getRunningStatus () >= SI::RunningStatusNotRunning)
+ // pSchedule->SetRunningStatus (pEvent, SiEitEvent.getRunningStatus (), channel);
+ // }
+ // if (OnlyRunningStatus)
+ // continue; // do this before setting the version, so that the full update can be done later
+ // pEvent->SetVersion (versionNumber);
+ //
+ // ProcessEventDescriptors(ExternalData, Source, Tid, SiEitEvent,
+ // pEvent, Schedules, channel);
+ //
+ // Modified = true;
+ cEvent *pEvent = ProcessEitEvent(pSchedule, &SiEitEvent,
+ Tid, versionNumber);
+ if (pEvent)
+ EquivHandler->updateEquivalent(Schedules, channel->GetChannelID(), pEvent);
+ }
+
+ ////
+
+ if (Empty && Tid == 0x4E && getSectionNumber () == 0)
+ // ETR 211: an empty entry in section 0 of table 0x4E means there is currently no event running
+ pSchedule->ClrRunningStatus (channel);
+ if (Tid == 0x4E)
+ pSchedule->SetPresentSeen ();
+ if (OnlyRunningStatus) {
+ LogD(4, prep("OnlyRunningStatus"));
+ return;
+ }
+ if (Modified) {
+ // if (!HasExternalData)
+ pSchedule->DropOutdated (SegmentStart, SegmentEnd, Tid, getVersionNumber ());
+ sortSchedules(Schedules, channel->GetChannelID());
+ }
+ LogD(4, prep("end of cEIT2"));
+
+}
+//end of cEIT2
+
+cEIT2::cEIT2 (cSchedule * Schedule)
+: Empty(true)
+, Modified(false)
+, OnlyRunningStatus(false)
+, SegmentStart(0)
+, SegmentEnd(0)
+, Schedules(NULL)
+{
+ //LogD(2, prep("cEIT2::cEIT2"));
+ // if (Tid > 0 && (Format == DISH_BEV || (SetupPE->ProcessEIT && isEITPid))) Tid--;
+
+ bool searchOtherSatPositions = Format == DISH_BEV;
+
+ tChannelID channelID = Schedule->ChannelID();
+ channel = GetChannelByID (channelID, searchOtherSatPositions);
+ if (!channel) {
+ LogD(3, prep("!channel channelID: %s"), *channelID.ToString());
+ return; // only collect data for known channels
+ }
+}
+} //end namespace SI
+
diff --git a/eit2.h b/eit2.h
new file mode 100644
index 0000000..7686672
--- /dev/null
+++ b/eit2.h
@@ -0,0 +1,50 @@
+#ifndef CEIT2_H_
+#define CEIT2_H_
+#include <libsi/section.h>
+#include <libsi/descriptor.h>
+#include <libsi/si.h>
+#include <vdr/epg.h>
+
+namespace SI
+{
+enum DescriptorTagExt {
+ DishRatingDescriptorTag = 0x89,
+ DishShortEventDescriptorTag = 0x91,
+ DishExtendedEventDescriptorTag = 0x92,
+ DishSeriesDescriptorTag = 0x96,
+};
+
+// typedef InheritEnum< DescriptorTagExt, SI::DescriptorTag > ExtendedDescriptorTag;
+
+/*extern const char *getCharacterTable(const unsigned char *&buffer, int &length, bool *isSingleByte = NULL);
+extern bool convertCharacterTable(const char *from, size_t fromLength, char *to, size_t toLength, const char *fromCode);
+extern bool SystemCharacterTableIsSingleByte;*/
+class cEIT2:public SI::EIT
+{
+public:
+ cEIT2(cSchedules * Schedules, int Source, u_char Tid, const u_char * Data, bool isEITPid = false,
+ bool OnlyRunningStatus = false);
+ cEIT2 (cSchedule * Schedule);
+ //protected:
+ // void updateEquivalent(cSchedules * Schedules, tChannelID channelID, cEvent *pEvent);
+ cEvent* ProcessEitEvent(cSchedule *Schedule, const SI::EIT::Event *EitEvent, uchar TableID, uchar Version);
+
+private:
+ void ProcessEventDescriptors(bool ExternalData, int Source, u_char Tid,
+ const SI::EIT::Event* SiEitEvent, cEvent* pEvent,
+ cSchedules* Schedules, cChannel* channel);
+
+private:
+ bool Empty;
+ bool Modified;
+ // bool HasExternalData = false;
+ bool OnlyRunningStatus;
+ time_t SegmentStart;
+ time_t SegmentEnd;
+ cSchedules* Schedules;
+ cChannel* channel;
+
+};
+} //end namespace SI
+
+#endif /* CEIT2_H_ */
diff --git a/epghandler.c b/epghandler.c
new file mode 100644
index 0000000..49c89e4
--- /dev/null
+++ b/epghandler.c
@@ -0,0 +1,198 @@
+/*
+ * cEEpgHandler.c
+ *
+ * Created on: 11.3.2012
+ * Author: d.petrovski
+ */
+
+#include "epghandler.h"
+#if APIVERSNUM > 10725
+#include "log.h"
+#include "equivhandler.h"
+#include "eit2.h"
+#include "util.h"
+#include <vdr/sources.h>
+#include <libsi/si.h>
+
+using namespace util;
+
+cEEpgHandler::cEEpgHandler() {
+ LogD(4, prep("cEEpgHandler()"));
+ equivHandler = new cEquivHandler();
+ modified = false;
+}
+
+cEEpgHandler::~cEEpgHandler() {
+ delete equivHandler;
+ equivHandler = NULL;
+}
+
+bool cEEpgHandler::HandleEitEvent(cSchedule* Schedule,
+ const SI::EIT::Event* EitEvent, uchar TableID, uchar Version) {
+ //LogD(1, prep("HandleEitEvent"));
+ //DISH NID 0x1001 to 0x100B BEV 0x100 and 0x101
+ int nid = Schedule->ChannelID().Nid();
+ if ((nid >= 0x1001 && nid <= 0x100B) || nid == 0x101 || nid == 0x100) {
+ //Set the Format for Eit events so that the new lines are not erased with FixEpgBugs
+ if (Format != DISH_BEV) Format = DISH_BEV;
+
+ SI::cEIT2 eit2(Schedule);
+ eit2.ProcessEitEvent(Schedule, EitEvent, TableID, Version);
+ return true;
+ }
+
+ //TODO Should it be added in setup?
+ if (EitEvent->getDurationHour() > _LONG_EVENT_HOURS) {
+ LogD(4, prep("Event longer than 10h Duration:%d DurationHour:%d StartTimeHour:%d"), EitEvent->getDuration(), EitEvent->getDurationHour(), EitEvent->getStartTimeHour());
+ const cEvent* exEvent = Schedule->GetEventAround(EitEvent->getStartTime()+EitEvent->getDuration()/3);
+ if (exEvent) {
+ const cEvent* exEvent2 = Schedule->GetEventAround(EitEvent->getStartTime()+EitEvent->getDuration()/3*2);
+ if (exEvent2 && exEvent != exEvent2) {
+ LogD(2, prep("EitEvent overrides existing events '%s', '%s' ... Skipping"), *exEvent->Title(), *exEvent2->Title());
+ return true;
+ }
+ }
+ }
+
+ modified = false;
+ //VDR creates new event if the EitEvent StartTime is different than EEPG time so
+ //the EEPG event has to be deleted but the data should be kept
+ const cEvent* ev = Schedule->GetEvent(EitEvent->getEventId(),EitEvent->getStartTime());
+ if (!ev){
+ ev = Schedule->GetEvent(EitEvent->getEventId());
+ if (ev && ((ev->StartTime()>EitEvent->getStartTime() && ev->StartTime()<=EitEvent->getStartTime()+EitEvent->getDuration())
+ || (EitEvent->getStartTime() > ev->StartTime() && EitEvent->getStartTime() <= ev->EndTime()))) {
+ LogD(0, prep("!!!Deleting Event id:%d title:%s start_time:%d new_start_time:%d duration:%d new_duration:%d"), ev->EventID(), ev->Title(), ev->StartTime(), EitEvent->getStartTime(), ev->Duration(), EitEvent->getDuration());
+
+ if (ev->Description() && strcmp(ev->Description(),"") != 0)
+ origDescription = ev->Description();
+ if (ev->ShortText() && strcmp(ev->ShortText(),"") != 0)
+ origShortText = ev->ShortText();
+ Schedule->DelEvent((cEvent *) ev);
+// Schedule->DropOutdated(ev->StartTime()-1,ev->EndTime()+1,ev->TableID()-1,ev->Version());
+ LogD(0, prep("!!!End Deleting Event"));
+ //TODO equivalent channels !!!
+ }
+ }
+
+
+
+ return false;
+ // return true;
+}
+
+bool cEEpgHandler::SetEventID(cEvent* Event, tEventID EventID) {
+ Event->SetEventID(EventID);
+ return true;
+}
+
+bool cEEpgHandler::SetTitle(cEvent* Event, const char* Title) {
+ LogD(3, prep("Event id:%d title:%s new title:%s"), Event->EventID(), Event->Title(), Title);
+
+ if (!Event->Title() || (Title && (!strcmp(Event->Title(),"") || (strcmp(Title,"") && strcmp(Event->Title(),Title))))) {
+ //LogD(0, prep("Event id:%d title:%s new title:%s"), Event->EventID(), Event->Title(), Title);
+ modified = true;
+ Event->SetTitle(Title);
+ }
+ return true;
+}
+
+bool cEEpgHandler::SetShortText(cEvent* Event, const char* ShortText) {
+ LogD(3, prep("Event id:%d ShortText:%s new ShortText:%s"), Event->EventID(), Event->ShortText(), ShortText);
+
+ if (Event->ShortText() && strcmp(Event->ShortText(),"") != 0) {
+ origShortText = std::string(Event->ShortText());
+ }
+ else {
+ origShortText.clear();
+ }
+
+ //if (!Event->ShortText() || ShortText && (!strcmp(Event->ShortText(),"") || (strcmp(ShortText,"") && strcmp(Event->ShortText(),ShortText))))
+ Event->SetShortText(ShortText);
+ return true;
+}
+
+bool cEEpgHandler::SetDescription(cEvent* Event, const char* Description) {
+ LogD(3, prep("Event id:%d Description:%s new Description:%s"), Event->EventID(), Event->Description(), Description);
+
+ if (Event->Description() && strcmp(Event->Description(),"") != 0)
+ origDescription = Event->Description();
+ else
+ origDescription.clear();
+
+ //Based on asumption that SetDescription is always called after SetTitle
+ if (!modified && Description && (!Event->Description() || strcmp(Event->Description(),Description) ))
+ modified = true;
+
+ //if (!Event->Description() || Description && (!strcmp(Event->Description(),"") || (strcmp(Description,"") && strcmp(Event->Description(),Description))))
+ Event->SetDescription(Description);
+ return true;
+}
+
+bool cEEpgHandler::SetContents(cEvent* Event, uchar* Contents) {
+ Event->SetContents(Contents);
+ return true;
+}
+
+bool cEEpgHandler::SetParentalRating(cEvent* Event, int ParentalRating) {
+ Event->SetParentalRating(ParentalRating);
+ return true;
+}
+
+bool cEEpgHandler::SetStartTime(cEvent* Event, time_t StartTime) {
+ Event->SetStartTime(StartTime);
+ return true;
+}
+
+bool cEEpgHandler::SetDuration(cEvent* Event, int Duration) {
+ Event->SetDuration(Duration);
+ return true;
+}
+
+bool cEEpgHandler::SetVps(cEvent* Event, time_t Vps) {
+ Event->SetVps(Vps);
+ return true;
+}
+
+bool cEEpgHandler::HandleEvent(cEvent* Event) {
+
+ LogD(3, prep("HandleEvent st:%s ost:%s desc:%s odesc:%s"),Event->ShortText(),origShortText.c_str(),Event->Description(),origDescription.c_str());
+
+ //After FixEpgBugs of cEvent set the original Short Text if empty
+ if (!Event->ShortText() || !strcmp(Event->ShortText(),""))
+ Event->SetShortText(origShortText.c_str());
+
+ if ((!Event->Description() && !origDescription.empty()) || (Event->Description() && !origDescription.empty() && origDescription.find(Event->Description()) != string::npos) ) {
+ Event->SetDescription(origDescription.c_str());
+ }
+
+ if (equivHandler->getEquiChanMap().count(*Event->ChannelID().ToString()) <= 0)
+ return true;
+
+ //if (modified)
+ equivHandler->updateEquivalent(Event->ChannelID(), Event);
+
+ //TODO just to see the difference
+ //else if (!origDescription.empty() && !origDescription.compare(Event->Description())) {
+ // origDescription.append(" | EIT: ");
+ // origDescription.append(Event->Description());
+ // Event->SetDescription(origDescription.c_str());
+ // }
+
+ return true;
+}
+
+
+bool cEEpgHandler::SortSchedule(cSchedule* Schedule) {
+
+ Schedule->Sort();
+
+ return true;
+}
+
+bool cEEpgHandler::DropOutdated(cSchedule* Schedule, time_t SegmentStart,
+ time_t SegmentEnd, uchar TableID, uchar Version) {
+ return false;
+}
+
+#endif
diff --git a/epghandler.h b/epghandler.h
new file mode 100644
index 0000000..003fd32
--- /dev/null
+++ b/epghandler.h
@@ -0,0 +1,48 @@
+/*
+ * cEEpgHandler.h
+ *
+ * Created on: 11.3.2012
+ * Author: d.petrovski
+ */
+
+#ifndef CEEPGHANDLER_H_
+#define CEEPGHANDLER_H_
+#include <vdr/config.h>
+#if APIVERSNUM > 10725
+#include <vdr/epg.h>
+#include <string>
+
+class cEquivHandler;
+
+class cEEpgHandler : public cEpgHandler {
+public:
+ cEEpgHandler();
+ virtual ~cEEpgHandler();
+ virtual bool IgnoreChannel(const cChannel *Channel) { return false; }
+ virtual bool HandleEitEvent(cSchedule *Schedule, const SI::EIT::Event *EitEvent, uchar TableID, uchar Version);
+ virtual bool SetEventID(cEvent *Event, tEventID EventID);
+ virtual bool SetTitle(cEvent *Event, const char *Title);
+ virtual bool SetShortText(cEvent *Event, const char *ShortText);
+ virtual bool SetDescription(cEvent *Event, const char *Description);
+ virtual bool SetContents(cEvent *Event, uchar *Contents);
+ virtual bool SetParentalRating(cEvent *Event, int ParentalRating);
+ virtual bool SetStartTime(cEvent *Event, time_t StartTime);
+ virtual bool SetDuration(cEvent *Event, int Duration);
+ virtual bool SetVps(cEvent *Event, time_t Vps);
+ virtual bool FixEpgBugs(cEvent *Event) { return false; }
+ virtual bool HandleEvent(cEvent *Event);
+ virtual bool SortSchedule(cSchedule *Schedule);
+ virtual bool DropOutdated(cSchedule *Schedule, time_t SegmentStart, time_t SegmentEnd, uchar TableID, uchar Version);
+
+// bool ParseEitEvent(cSchedule *Schedule, const SI::EIT::Event *EitEvent, uchar TableID, uchar Version);
+
+private:
+ std::string origShortText;
+ std::string origDescription;
+ cEquivHandler* equivHandler;
+ static const int _LONG_EVENT_HOURS = 10;
+ bool modified;
+};
+
+#endif /*APIVERSNUM > 10725*/
+#endif /* CEEPGHANDLER_H_ */
diff --git a/equivhandler.c b/equivhandler.c
new file mode 100644
index 0000000..281d2f3
--- /dev/null
+++ b/equivhandler.c
@@ -0,0 +1,233 @@
+/*
+ * equivhandler.cpp
+ *
+ * Created on: 19.5.2012
+ * Author: d.petrovski
+ */
+
+#include "equivhandler.h"
+#include "setupeepg.h"
+#include "log.h"
+#include "util.h"
+
+#include <string>
+
+using namespace util;
+
+multimap<string, string> cEquivHandler::equiChanMap;
+long cEquivHandler::equiChanFileTime = 0;
+
+cEquivHandler::cEquivHandler()
+{
+ loadEquivalentChannelMap();
+}
+
+cEquivHandler::~cEquivHandler()
+{
+ // TODO Auto-generated destructor stub
+}
+
+void cEquivHandler::loadEquivalentChannelMap (void)
+{
+ char Buffer[1024];
+ char *Line;
+ FILE *File;
+ string FileName = string(cSetupEEPG::getInstance()->getConfDir()) + "/" + EEPG_FILE_EQUIV;
+ multimap<string,string>::iterator it,it2;
+ pair<multimap<string,string>::iterator,multimap<string,string>::iterator> ret;
+
+ //Test if file is changed and reload
+ struct stat st;
+ if (stat(FileName.c_str(), &st)) {
+ LogE(0, prep("Error obtaining stats for '%s' "), FileName.c_str());
+ return;
+ }
+
+ if (equiChanMap.size() > 0 && equiChanFileTime == st.st_mtim.tv_nsec)
+ return;
+ else
+ equiChanMap.clear();
+
+
+ File = fopen (FileName.c_str(), "r");
+ if (File) {
+ memset (Buffer, 0, sizeof (Buffer));
+ char origChanID[256];
+ char equiChanID[256];
+ char source[256];
+ int nid = 0;
+ int tid = 0;
+ int sid = 0;
+ int rid = 0;
+ while ((Line = fgets (Buffer, sizeof (Buffer), File)) != NULL) {
+ Line = compactspace (skipspace (stripspace (Line)));
+ if (!isempty (Line)) {
+ if (sscanf (Line, "%[^ ] %[^ ] %[^\n]\n", origChanID, equiChanID, source) == 3) {
+ if (origChanID[0] != '#' && origChanID[0] != ';') {
+ nid = 0;
+ tid = 0;
+ sid = 0;
+ rid = 0;
+ if (sscanf (origChanID, "%[^-]-%i -%i -%i ", source, &nid, &tid, &sid) == 4)
+ if (sscanf (equiChanID, "%[^-]-%i -%i -%i ", source, &nid, &tid, &sid) == 4) {
+ if (sscanf (origChanID, "%[^-]-%i -%i -%i -%i ", source, &nid, &tid, &sid, &rid) != 5) {
+ rid = 0;
+ }
+ tChannelID OriginalChID = tChannelID (cSource::FromString (source), nid, tid, sid, rid);
+ bool found = false;
+ //int i = 0;
+ cChannel *OriginalChannel = Channels.GetByChannelID (OriginalChID, false);
+ if (!OriginalChannel) {
+ LogI(2, prep("Warning, not found epg channel \'%s\' in channels.conf. Equivalency is assumed to be valid, but perhaps you should check the entry in the equivalents file"), origChanID); //TODO: skip this ing?
+ continue;
+ }
+ if (sscanf (equiChanID, "%[^-]-%i -%i -%i ", source, &nid, &tid, &sid) == 4) {
+ if (sscanf (equiChanID, "%[^-]-%i -%i -%i -%i ", source, &nid, &tid, &sid, &rid)
+ != 5) {
+ rid = 0;
+ }
+ tChannelID EquivChID = tChannelID (cSource::FromString (source), nid, tid, sid, rid);
+ cChannel *EquivChannel = Channels.GetByChannelID (EquivChID, false); //TODO use valid function?
+ if (EquivChannel) {
+ ret = equiChanMap.equal_range(*OriginalChID.ToString());
+ for (it=ret.first; it!=ret.second; ++it)
+ if ((*it).second == *OriginalChID.ToString()) {
+ found = true;
+ break;
+ }
+
+ if (!found) {
+ string origCh(*OriginalChID.ToString());
+ string equiCh(*EquivChID.ToString());
+ equiChanMap.insert(pair<string,string>(origCh.c_str(),equiCh.c_str()));
+ LogD(4, prep("Found %s equivalent to %s. origCh %s"), *EquivChID.ToString(), *OriginalChID.ToString(), origCh.c_str());
+ for ( it2=equiChanMap.begin() ; it2 != equiChanMap.end(); it2++ )
+ LogD(3, prep("Original ID %s <-> Equivalent ID %s"), (*it2).first.c_str(), it2->second.c_str());
+ }
+ } else
+ LogI(0, prep("Warning, not found equivalent channel \'%s\' in channels.conf"), equiChanID);
+ }
+ } //if scanf string1
+ } //if string1
+ } //if scanf
+ } //if isempty
+ } //while
+ fclose (File);
+ equiChanFileTime = st.st_mtim.tv_nsec;
+ LogD(2, prep("Loaded %i equivalents."), equiChanMap.size());
+ for ( it2=equiChanMap.begin() ; it2 != equiChanMap.end(); it2++ )
+ LogD(2, prep("Original ID %s <-> Equivalent ID %s"), (*it2).first.c_str(), it2->second.c_str());
+ } //if file
+}
+
+void cEquivHandler::updateEquivalent(cSchedules * Schedules, tChannelID channelID, cEvent *pEvent){
+ multimap<string,string>::iterator it;
+ pair<multimap<string,string>::iterator,multimap<string,string>::iterator> ret;
+
+ LogD(2, prep("Start updateEquivalent %s"), *channelID.ToString());
+
+ ret = equiChanMap.equal_range(*channelID.ToString());
+ for (it=ret.first; it!=ret.second; ++it) {
+ LogD(2, prep("equivalent channel exists"));
+ tChannelID equChannelID (tChannelID::FromString((*it).second.c_str()));
+ cChannel *equChannel = GetChannelByID (equChannelID, false);
+ if (equChannel) {
+ LogD(2, prep("found Equivalent channel %s"), *equChannelID.ToString());
+ cSchedule *pSchedule = (cSchedule *) Schedules->GetSchedule (equChannel, true);
+ cEvent *pEqvEvent = (cEvent *) pSchedule->GetEvent (pEvent->EventID(), pEvent->StartTime());
+ if (pEqvEvent) {
+ LogD(3, prep("equivalent event exists"));
+ if (pEqvEvent == pEvent) {
+ LogD(3, prep("equal event exists"));
+
+ } else {
+ LogD(2, prep("remove equivalent"));
+ pSchedule->DelEvent(pEqvEvent);
+ cEvent* newEvent = new cEvent (pEvent->EventID());
+ cloneEvent(pEvent, newEvent);
+
+ pSchedule->AddEvent(newEvent);
+
+ }
+
+ } else {
+ LogD(3, prep("equivalent event does not exist"));
+ cEvent* newEvent = new cEvent (pEvent->EventID());
+ cloneEvent(pEvent, newEvent);
+
+ pSchedule->AddEvent(newEvent);
+
+ }
+ }
+ }
+}
+
+void cEquivHandler::updateEquivalent(tChannelID channelID, cEvent *pEvent){
+ multimap<string,string>::iterator it;
+ pair<multimap<string,string>::iterator,multimap<string,string>::iterator> ret;
+
+ LogD(3, prep("Start updateEquivalent %s"), *channelID.ToString());
+
+ ret = equiChanMap.equal_range(*channelID.ToString());
+ for (it=ret.first; it!=ret.second; ++it) {
+ tChannelID equChannelID (tChannelID::FromString((*it).second.c_str()));
+ LogD(3, prep("equivalent channel '%s' exists"), *equChannelID.ToString());
+ cEvent* newEvent = new cEvent (pEvent->EventID());
+ cloneEvent(pEvent, newEvent);
+
+ AddEvent(newEvent, equChannelID);
+ }
+}
+
+
+void cEquivHandler::sortEquivalents(tChannelID channelID, cSchedules* Schedules)
+{
+ multimap<string, string>::iterator it;
+ pair < multimap < string, string > ::iterator, multimap < string, string
+ > ::iterator > ret;
+ LogD(2, prep("sortEquivalents for channel %s count: %d"), *channelID.ToString(), cEquivHandler::getEquiChanMap().count(*channelID.ToString()));
+
+ ret = equiChanMap.equal_range(*channelID.ToString());
+ for (it = ret.first; it != ret.second; ++it)
+ {
+ LogD(3, prep("equivalent channel exists"));
+ tChannelID equChannelID(tChannelID::FromString((*it).second.c_str()));
+ cChannel* pChannel = GetChannelByID(equChannelID, false);
+ if (pChannel)
+ {
+ LogD(2, prep("found Equivalent channel %s"), *equChannelID.ToString());
+ cSchedule* pSchedule = (cSchedule *) Schedules->GetSchedule(pChannel, true);
+
+ pSchedule->Sort();
+ Schedules->SetModified(pSchedule);
+ }
+ }
+}
+
+void cEquivHandler::cloneEvent(cEvent *Source, cEvent *Dest) {
+
+ Dest->SetEventID(Source->EventID());
+ Dest->SetTableID(Source->TableID());
+ Dest->SetVersion(Source->Version());
+ Dest->SetRunningStatus(Source->RunningStatus());
+ Dest->SetTitle(Source->Title());
+ Dest->SetShortText(Source->ShortText());
+ Dest->SetDescription(Source->Description());
+ cComponents *components = new cComponents();
+ if (Source->Components()) {
+ for (int i = 0; i < Source->Components()->NumComponents(); ++i)
+ components->SetComponent(i, Source->Components()->Component(i)->ToString());
+ }
+ Dest->SetComponents(components);
+ uchar contents[MaxEventContents];
+ for (int i = 0; i < MaxEventContents; ++i)
+ contents[i] = Source->Contents(i);
+ Dest->SetContents(contents);
+ Dest->SetParentalRating(Source->ParentalRating());
+ Dest->SetStartTime(Source->StartTime());
+ Dest->SetDuration(Source->Duration());
+ Dest->SetVps(Source->Vps());
+ if (Source->Seen())
+ Dest->SetSeen();
+}
+
diff --git a/equivhandler.h b/equivhandler.h
new file mode 100644
index 0000000..f60dbfc
--- /dev/null
+++ b/equivhandler.h
@@ -0,0 +1,40 @@
+/*
+ * equivhandler.h
+ *
+ * Created on: 19.5.2012
+ * Author: d.petrovski
+ */
+
+#ifndef EQUIVHANDLER_H_
+#define EQUIVHANDLER_H_
+
+#include <vdr/epg.h>
+#include <vdr/channels.h>
+#include <map>
+#include <string>
+
+#define EEPG_FILE_EQUIV "eepg.equiv"
+
+using namespace std;
+
+class cEquivHandler
+{
+public:
+ cEquivHandler();
+ virtual ~cEquivHandler();
+
+ void loadEquivalentChannelMap (void);
+ void updateEquivalent(cSchedules * Schedules, tChannelID channelID, cEvent *pEvent);
+ void updateEquivalent(tChannelID channelID, cEvent *pEvent);
+ void sortEquivalents(tChannelID channelID, cSchedules* Schedules);
+ void cloneEvent(cEvent *Source, cEvent *Dest);
+
+ static multimap<string, string> getEquiChanMap() { return cEquivHandler::equiChanMap; };
+
+private:
+ static multimap<string, string> equiChanMap;
+ static long equiChanFileTime;
+
+};
+
+#endif /* EQUIVHANDLER_H_ */
diff --git a/log.h b/log.h
new file mode 100644
index 0000000..b743763
--- /dev/null
+++ b/log.h
@@ -0,0 +1,78 @@
+/*
+ * log.h
+ *
+ * Created on: 08.5.2012
+ * Author: d.petrovski
+ */
+
+#ifndef LOG_H_
+#define LOG_H_
+
+#include <string>
+#include <vdr/tools.h>
+#include <vdr/thread.h>
+#include "setupeepg.h"
+
+#define VERBOSE 1
+/* 0 = only print errors, 1 = print channels and themes, 2 = print channels, themes, titles, summaries 3 = debug mode */
+/* all is logged into /var/log/syslog */
+
+
+inline bool CheckLevel(int level)
+{
+#ifdef DEBUG
+ if (cSetupEEPG::getInstance()->LogLevel >= level)
+#else
+ if (VERBOSE >= level)
+#endif
+ {
+ return true;
+ }
+ return false;
+}
+
+inline const char* PrepareLog(std::string message)
+{
+ message = "EEPG: " + message;
+ return message.c_str();
+}
+
+#define MAXSYSLOGBUF 256
+
+//void LogVsyslog(int errLevel, const char * message, ...)
+inline void LogVsyslog(int errLevel, int const& lineNum, const char * function, const char * message, ...)
+{
+ va_list ap;
+ char fmt[MAXSYSLOGBUF];
+ if (errLevel == LOG_DEBUG) {
+ snprintf(fmt, sizeof(fmt), "[%d] %s:%d %s", cThread::ThreadId(), function, lineNum, message);
+ } else {
+ snprintf(fmt, sizeof(fmt), "[%d] %s", cThread::ThreadId(), message);
+ }
+ va_start(ap,message);
+ vsyslog ( errLevel, fmt, ap );
+ va_end(ap);
+}
+
+#define LogI(a, b...) void( CheckLevel(a) ? LogVsyslog ( LOG_INFO, __LINE__, __FUNCTION__, b ) : void() )
+#define LogE(a, b...) void( CheckLevel(a) ? LogVsyslog ( LOG_ERR, __LINE__, __FUNCTION__, b ) : void() )
+#define LogD(a, b...) void( CheckLevel(a) ? LogVsyslog ( LOG_DEBUG, __LINE__, __FUNCTION__, b ) : void() )
+//#define LogE(a, b...) void( CheckLevel(a) ? esyslog ( b ) : void() )
+//#define LogD(a, b...) void( CheckLevel(a) ? dsyslog ( b ) : void() )
+#define prep(s) PrepareLog(s)
+#define prep2(s) s
+
+
+//void LogF(int level, const char * message, ...) __attribute__ ((format (printf,2,3)));
+
+//void LogF(int level, const char * message, ...)
+//{
+// if (CheckLevel(level)) {
+// va_list ap;
+// va_start(ap,message);
+// vsyslog (LOG_ERR, PrepareLog(message), ap );
+// va_end(ap);
+// }
+//}
+
+#endif /* LOG_H_ */
diff --git a/scripts/README b/scripts/README
new file mode 100644
index 0000000..22e2835
--- /dev/null
+++ b/scripts/README
@@ -0,0 +1,28 @@
+extract_vdr_chan_ids.pl
+The script extract_vdr_chan_ids.pl can be used along with grep to extract the IDs
+of required channel i.e.:
+
+USAGE:
+ extract_vdr_chan_ids.pl [/path/to/channels.conf]
+
+EXAMPES:
+ extract_vdr_chan_ids.pl /path/to/channels.conf | grep -i Chanel Name
+
+makeequiv.sh thanks to VDR User
+The makeequiv.sh bash script can be used to generate an eepg.equiv
+file based on SID matching. You may optionally require channel name
+matching as well.
+
+USAGE:
+ makeequiv.sh [channels.conf] [listsources|source to map epg from] <matchname>
+
+EXAMPES:
+ makequiv.sh /video/channels.conf listsources
+ * shows a list of all available sources in channels.conf
+
+ makeequiv.sh /video/channels.conf S72.7W
+ * map epg from S72.7W channels based on SID match
+
+ makeequiv.sh /video/channels.conf S72.7W matchname
+ * map epg from S72.7W channels based on SID and channel name match
+
diff --git a/scripts/extract_vdr_chan_ids.pl b/scripts/extract_vdr_chan_ids.pl
new file mode 100755
index 0000000..e40bbb9
--- /dev/null
+++ b/scripts/extract_vdr_chan_ids.pl
@@ -0,0 +1,38 @@
+#!/usr/bin/perl -w
+#
+# extract VDR channel ID's from channels conf
+#
+
+use strict;
+use File::Path;
+
+my $channelsConf = "../channels.conf";
+my $Usage = qq{
+Usage: $0 (default: ../channels.conf)
+ $0 /path/to/channels.conf
+};
+
+$channelsConf = "@ARGV" if @ARGV;
+
+#my $file;
+open(MYINPUTFILE, "<$channelsConf") or die("Could not open $channelsConf" . $Usage);
+
+foreach (<MYINPUTFILE>)
+{
+ chomp;
+ if ( /^:.*/ )
+ {
+ print $_ . "\n";
+ next;
+ }
+
+ my($line) = $_;
+
+ my(@tokens) = split(":");
+
+ my($chanID) = "$tokens[3]-$tokens[10]-$tokens[11]-$tokens[9] $tokens[0]";
+
+ print $chanID . "\n"
+
+}
+
diff --git a/scripts/makeequiv.sh b/scripts/makeequiv.sh
new file mode 100755
index 0000000..1be3e80
--- /dev/null
+++ b/scripts/makeequiv.sh
@@ -0,0 +1,56 @@
+#!/bin/bash
+
+equiv_file="eepg.equiv"
+
+usage() {
+ echo
+ [[ "$@" ]] && echo -e "ABORTED! $@\n"
+ echo -e "usage: ${0##*/} [channels.conf] [listsources|source to map epg from] <matchname>"
+ echo -e " * the 3rd argument is optional. if its \"matchname\", channel name matching is required for a positive match.\n"
+ exit
+}
+
+getsources() { awk -F: '{print $4}' "$1" |sort -V |uniq; }
+listsources() { getsources "$1"; exit; }
+
+(($# < 2)) && usage
+[[ -e "$1" ]] || usage "$1 not found"
+[[ "$2" == "listsources" ]] && listsources "$1"
+[[ $(getsources "$1" |grep "$2$") ]] || usage "$2 is not a source in $1"
+[[ "$3" == "matchname" ]] && match_name=1 || match_name=0
+[[ -e "$equiv_file" ]] && rm "$equiv_file"
+echo
+tput sc
+OLDIFS=$IFS; IFS=$'\n'
+for i in $(awk -F: -v var="$2" '$4==var' "$1"); do
+ matched=0
+ mapto_name=" ${i%%:*}"
+ mapto_sid=$(awk -F: '{print $10}' <<<"$i")
+ mapto_line=$(awk -F: '{print $4"-"$11"-"$12"-"$10"-"$13}' <<<"$i")
+ mapto_source=$(awk -F: '{print $4}' <<<"$i")
+ for j in $(awk -F: -v var1="$2" -v var2="$mapto_sid" '$4!=var1 && $10==var2' "$1"); do
+ mapfrom_source=$(awk -F: '{print $4}' <<<"$j")
+ mapfrom_line=$(awk -F: '{print $4"-"$11"-"$12"-"$10"-"$13}' <<<"$j")
+ matched=1
+ (($match_name)) && {
+ [[ " ${j%%:*}" == "$mapto_name" ]] || matched=0
+ } || unset mapto_name
+ done
+ (($matched)) && {
+ ((matchcount++))
+ outline="$mapfrom_line $mapto_line$mapto_name"
+ echo "$outline" >>"$equiv_file"
+ } || {
+ ((unmatchcount++))
+ array+=( "$i" )
+ unset outline
+ }
+ tput rc
+ tput el
+ echo "$outline"
+ echo -n "matched: $matchcount - unmatched: $unmatchcount"
+done
+IFS=$OLDIFS
+echo -e "\n"
+((${#array[@]} > 0)) && for i in "${array[@]}"; do echo "NO MATCH: $i"; done
+echo "wrote $equiv_file ($matchcount entries)."
diff --git a/setupeepg.c b/setupeepg.c
new file mode 100644
index 0000000..c0dff6a
--- /dev/null
+++ b/setupeepg.c
@@ -0,0 +1,37 @@
+/*
+ * setupeepg.c
+ *
+ * Created on: 08.5.2012
+ * Author: d.petrovski
+ */
+
+#include <stddef.h>
+#include "setupeepg.h"
+
+// --- cSetupEEPG -------------------------------------------------------
+
+cSetupEEPG* cSetupEEPG::_setupEEPG = NULL;
+
+cSetupEEPG::cSetupEEPG (void)
+:ConfDir(NULL)
+{
+ ConfDir = NULL;
+ OptPat = 1;
+ OrderInfo = 1;
+ RatingInfo = 1;
+ FixEpg = 0;
+ DisplayMessage = 1;
+ ProcessEIT = 0;
+#ifdef DEBUG
+ LogLevel = 0;
+#endif
+}
+
+cSetupEEPG* cSetupEEPG::getInstance()
+{
+ if (!_setupEEPG)
+ _setupEEPG = new cSetupEEPG();
+
+ return _setupEEPG;
+}
+
diff --git a/setupeepg.h b/setupeepg.h
new file mode 100644
index 0000000..0db20d1
--- /dev/null
+++ b/setupeepg.h
@@ -0,0 +1,52 @@
+/*
+ * setupeepg.h
+ *
+ * Created on: 08.5.2012
+ * Author: d.petrovski
+ */
+
+#ifndef SETUPEEPG_H_
+#define SETUPEEPG_H_
+#include <string.h>
+
+class cSetupEEPG
+{
+public:
+ int OptPat;
+ int OrderInfo;
+ int RatingInfo;
+ int FixEpg;
+ int DisplayMessage;
+ int ProcessEIT;
+#ifdef DEBUG
+ int LogLevel;
+#endif
+
+public:
+ static cSetupEEPG* getInstance();
+
+ char* getConfDir() const
+ {
+ return ConfDir;
+ }
+
+ void setConfDir(char* confDir)
+ {
+ if (ConfDir)
+ delete [] ConfDir;
+ ConfDir = new char[strlen(confDir)+1];
+ strcpy(ConfDir, confDir);
+ }
+
+private:
+ cSetupEEPG (void);
+ cSetupEEPG(cSetupEEPG const&); // copy constructor is private
+ cSetupEEPG& operator=(cSetupEEPG const&); // assignment operator is private
+ static cSetupEEPG* _setupEEPG;
+
+private:
+ char *ConfDir;
+
+};
+
+#endif /* SETUPEEPG_H_ */
diff --git a/util.c b/util.c
new file mode 100644
index 0000000..415f213
--- /dev/null
+++ b/util.c
@@ -0,0 +1,392 @@
+/*
+ * util.c
+ *
+ * Created on: 23.5.2012
+ * Author: d.petrovski
+ */
+#include "util.h"
+#include "log.h"
+#include "equivhandler.h"
+#include <vdr/channels.h>
+#include <vdr/thread.h>
+#include <vdr/epg.h>
+
+#include <map>
+
+namespace util
+{
+
+int AvailableSources[32];
+int NumberOfAvailableSources = 0;
+
+int Yesterday;
+int YesterdayEpoch;
+int YesterdayEpochUTC;
+
+struct hufftab *tables[2][128];
+int table_size[2][128];
+
+EFormat Format;
+cEquivHandler* EquivHandler;
+
+cChannel *GetChannelByID(tChannelID & channelID, bool searchOtherPos)
+{
+ cChannel *VC = Channels.GetByChannelID(channelID, true);
+ if(!VC && searchOtherPos){
+ //look on other satpositions
+ for(int i = 0;i < NumberOfAvailableSources;i++){
+ channelID = tChannelID(AvailableSources[i], channelID.Nid(), channelID.Tid(), channelID.Sid());
+ VC = Channels.GetByChannelID(channelID, true);
+ if(VC){
+ //found this actually on satellite nextdoor...
+ break;
+ }
+ }
+ }
+
+ return VC;
+}
+
+/*
+ * Convert local time to UTC
+ */
+time_t LocalTime2UTC (time_t t)
+{
+ struct tm *temp;
+
+ temp = gmtime (&t);
+ temp->tm_isdst = -1;
+ return mktime (temp);
+}
+
+/*
+ * Convert UTC to local time
+ */
+time_t UTC2LocalTime (time_t t)
+{
+ return 2 * t - LocalTime2UTC (t);
+}
+
+void GetLocalTimeOffset (void)
+{
+ time_t timeLocal;
+ struct tm *tmCurrent;
+
+ timeLocal = time (NULL);
+ timeLocal -= 86400;
+ tmCurrent = gmtime (&timeLocal);
+ Yesterday = tmCurrent->tm_wday;
+ tmCurrent->tm_hour = 0;
+ tmCurrent->tm_min = 0;
+ tmCurrent->tm_sec = 0;
+ tmCurrent->tm_isdst = -1;
+ YesterdayEpoch = mktime (tmCurrent);
+ YesterdayEpochUTC = UTC2LocalTime (mktime (tmCurrent));
+}
+
+void CleanString (unsigned char *String)
+{
+
+// LogD (1, prep("Unclean: %s"), String);
+ unsigned char *Src;
+ unsigned char *Dst;
+ int Spaces;
+ int pC;
+ Src = String;
+ Dst = String;
+ Spaces = 0;
+ pC = 0;
+ while (*Src) {
+ // corrections
+ if (*Src == 0x8c) { // iso-8859-2 LATIN CAPITAL LETTER S WITH ACUTE
+ *Src = 0xa6;
+ }
+ if (*Src == 0x8f) { // iso-8859-2 LATIN CAPITAL LETTER Z WITH ACUTE
+ *Src = 0xac;
+ }
+
+ if (*Src!=0x0A && *Src < 0x20) { //don't remove newline
+ *Src = 0x20;
+ }
+ if (*Src == 0x20) {
+ Spaces++;
+ if (pC == 0) {
+ Spaces++;
+ }
+ } else {
+ Spaces = 0;
+ }
+ if (Spaces < 2) {
+ *Dst = *Src;
+ Dst++;
+ pC++;
+ }
+ Src++;
+ }
+ if (Spaces > 0 && String && String < Dst) {
+ Dst--;
+ *Dst = 0;
+ } else {
+ *Dst = 0;
+ }
+// LogD (1, prep("Clean: %s"), String);
+}
+
+struct tChannelIDCompare
+{
+ bool operator() (const tChannelID& lhs, const tChannelID& rhs) const
+ {
+ if (lhs.Source() < rhs.Source()) return true;
+ bool eq = lhs.Source() == rhs.Source();
+ if (eq && lhs.Nid() < rhs.Nid()) return true;
+ eq &= lhs.Nid() == rhs.Nid();
+ if (eq && lhs.Tid() < rhs.Tid()) return true;
+ eq &= lhs.Tid() == rhs.Tid();
+ if (eq && lhs.Sid() < rhs.Sid()) return true;
+ eq &= lhs.Sid() == rhs.Sid();
+ if (eq && lhs.Rid() < rhs.Rid()) return true;
+ return false;
+ }
+};
+
+cTimeMs LastAddEventThread;
+enum { INSERT_TIMEOUT_IN_MS = 10000 };
+
+class cAddEventThread : public cThread
+{
+private:
+ cTimeMs LastHandleEvent;
+ std::map<tChannelID,cList<cEvent>*,tChannelIDCompare> *map_list;
+// enum { INSERT_TIMEOUT_IN_MS = 10000 };
+protected:
+ virtual void Action(void);
+public:
+ cAddEventThread(void);
+ ~cAddEventThread(void);
+ void AddEvent(cEvent *Event, tChannelID ChannelID);
+};
+
+cAddEventThread::cAddEventThread(void)
+:cThread("cAddEEPGEventThread"), LastHandleEvent()
+{
+ map_list = new std::map<tChannelID,cList<cEvent>*,tChannelIDCompare>;
+}
+
+cAddEventThread::~cAddEventThread(void)
+{
+// LOCK_THREAD;
+ Cancel(3);
+ std::map<tChannelID,cList<cEvent>*,tChannelIDCompare>::iterator it;
+ for ( it=map_list->begin() ; it != map_list->end(); it++ )
+ (*it).second->Clear();
+}
+
+void cAddEventThread::Action(void)
+{
+ //LogD (0, prep("Action"));
+ SetPriority(19);
+ while (Running() && !LastHandleEvent.TimedOut()) {
+ std::map<tChannelID, cList<cEvent>*, tChannelIDCompare>::iterator it;
+
+ cSchedulesLock SchedulesLock(true, 10);
+ cSchedules *schedules = (cSchedules *) cSchedules::Schedules(SchedulesLock);
+ Lock();
+
+ it = map_list->begin();
+ while (schedules && it != map_list->end()) {
+ cSchedule *schedule = (cSchedule *) schedules->GetSchedule(
+ Channels.GetByChannelID((*it).first), true);
+ while (((*it).second->First()) != NULL) {
+ cEvent* event = (*it).second->First();
+
+ cEvent *pEqvEvent = (cEvent *) schedule->GetEvent (event->EventID(), event->StartTime());
+ if (pEqvEvent){
+// LogD (0, prep("schedule->DelEvent(event) size:%d"), (*it).second->Count());
+ (*it).second->Del(event);
+// schedule->DelEvent(pEqvEvent);
+ } else {
+
+ (*it).second->Del(event, false);
+ EpgHandlers.DropOutdated(schedule, event->StartTime(), event->EndTime(), event->TableID(),
+ event->Version());
+ schedule->AddEvent(event);
+ }
+ }
+ EpgHandlers.SortSchedule(schedule);
+ //sortSchedules(schedules, (*it).first);
+ //schedule->Sort();
+ delete (*it).second;
+ map_list->erase(it);
+ it = map_list->begin();
+
+ }
+ Unlock();
+ cCondWait::SleepMs(10);
+ }
+}
+
+void cAddEventThread::AddEvent(cEvent *Event, tChannelID ChannelID)
+{
+ LOCK_THREAD;
+ if (map_list->count(ChannelID) == 0) {
+ cList<cEvent>* list = new cList<cEvent>;
+ list->Add(Event);
+ map_list->insert(std::make_pair(ChannelID, list));
+ } else {
+ map_list->find(ChannelID)->second->Add(Event);
+ }
+// LogD (0, prep("AddEventT %s channel: <%s> map size:%d"), Event->Title(), *ChannelID.ToString(), map_list->size());
+ LastHandleEvent.Set(INSERT_TIMEOUT_IN_MS);
+}
+
+static cAddEventThread AddEventThread;
+
+// ---
+
+void AddEvent(cEvent *Event, tChannelID ChannelID)
+{
+// LogD (0, prep("AddEvent %s channel: <%s>"), Event->Title(), *ChannelID.ToString());
+ AddEventThread.AddEvent(Event, ChannelID);
+// if (!AddEventThread.Active())
+// AddEventThread.Start();
+ if (!AddEventThread.Active() && LastAddEventThread.TimedOut()){
+ LastAddEventThread.Set(INSERT_TIMEOUT_IN_MS * 2);
+ AddEventThread.Start();
+ }
+
+}
+
+/** \brief Decode an EPG string as necessary
+ *
+ * \param src - Possibly encoded string
+ * \param size - Size of the buffer
+ *
+ * \retval NULL - Can't decode
+ * \return A decoded string
+ */
+char *freesat_huffman_decode (const unsigned char *src, size_t size)
+{
+ int tableid;
+
+ if (src[0] == 0x1f && (src[1] == 1 || src[1] == 2)) {
+ int uncompressed_len = 30;
+ char *uncompressed = (char *) calloc (1, uncompressed_len + 1);
+ unsigned value = 0, byte = 2, bit = 0;
+ int p = 0;
+ unsigned char lastch = START;
+
+ tableid = src[1] - 1;
+ while (byte < 6 && byte < size) {
+ value |= src[byte] << ((5 - byte) * 8);
+ byte++;
+ }
+ //freesat_table_load (); /**< Load the tables as necessary */
+
+ do {
+ bool found = false;
+ unsigned bitShift = 0;
+ if (lastch == ESCAPE) {
+ char nextCh = (value >> 24) & 0xff;
+ found = true;
+ // Encoded in the next 8 bits.
+ // Terminated by the first ASCII character.
+ bitShift = 8;
+ if ((nextCh & 0x80) == 0)
+ lastch = nextCh;
+ if (p >= uncompressed_len) {
+ uncompressed_len += 10;
+ uncompressed = (char *) REALLOC (uncompressed, uncompressed_len + 1);
+ }
+ uncompressed[p++] = nextCh;
+ uncompressed[p] = 0;
+ } else {
+ int j;
+ for (j = 0; j < table_size[tableid][lastch]; j++) {
+ unsigned mask = 0, maskbit = 0x80000000;
+ short kk;
+ for (kk = 0; kk < tables[tableid][lastch][j].bits; kk++) {
+ mask |= maskbit;
+ maskbit >>= 1;
+ }
+ if ((value & mask) == tables[tableid][lastch][j].value) {
+ char nextCh = tables[tableid][lastch][j].next;
+ bitShift = tables[tableid][lastch][j].bits;
+ if (nextCh != STOP && nextCh != ESCAPE) {
+ if (p >= uncompressed_len) {
+ uncompressed_len += 10;
+ uncompressed = (char *) REALLOC (uncompressed, uncompressed_len + 1);
+ }
+ uncompressed[p++] = nextCh;
+ uncompressed[p] = 0;
+ }
+ found = true;
+ lastch = nextCh;
+ break;
+ }
+ }
+ }
+ if (found) {
+ // Shift up by the number of bits.
+ unsigned b;
+ for (b = 0; b < bitShift; b++) {
+ value = (value << 1) & 0xfffffffe;
+ if (byte < size)
+ value |= (src[byte] >> (7 - bit)) & 1;
+ if (bit == 7) {
+ bit = 0;
+ byte++;
+ } else
+ bit++;
+ }
+ } else {
+ LogE (0, prep("Missing table %d entry: <%s>"), tableid + 1, uncompressed);
+ // Entry missing in table.
+ return uncompressed;
+ }
+ } while (lastch != STOP && value != 0);
+
+ return uncompressed;
+ }
+ return NULL;
+}
+
+void decodeText2 (const unsigned char *from, int len, char *buffer, int buffsize)
+{
+ if (from[0] == 0x1f) {
+ char *temp = freesat_huffman_decode (from, len);
+ if (temp) {
+ len = strlen (temp);
+ len = len < buffsize - 1 ? len : buffsize - 1;
+ strncpy (buffer, temp, len);
+ buffer[len] = 0;
+ free (temp);
+ return;
+ }
+ }
+
+ SI::String convStr;
+ SI::CharArray charArray;
+ charArray.assign(from, len);
+ convStr.setData(charArray, len);
+ //LogE(5, prep("decodeText2 from %s - length %d"), from, len);
+ convStr.getText(buffer, buffsize);
+ //LogE(5, prep("decodeText2 buffer %s - buffsize %d"), buffer, buffsize);
+}
+
+void sortSchedules(cSchedules * Schedules, tChannelID channelID){
+
+ LogD(3, prep("Start sortEquivalent %s"), *channelID.ToString());
+
+ cChannel *pChannel = GetChannelByID (channelID, false);
+ cSchedule *pSchedule;
+ if (pChannel) {
+ pSchedule = (cSchedule *) (Schedules->GetSchedule(pChannel, true));
+ pSchedule->Sort();
+ Schedules->SetModified(pSchedule);
+ }
+ if (EquivHandler->getEquiChanMap().count(*channelID.ToString()) > 0)
+ EquivHandler->sortEquivalents(channelID, Schedules);
+}
+
+}
+
diff --git a/util.h b/util.h
new file mode 100644
index 0000000..dec5b70
--- /dev/null
+++ b/util.h
@@ -0,0 +1,93 @@
+/*
+ * util.h
+ *
+ * Created on: 23.5.2012
+ * Author: d.petrovski
+ */
+
+#ifndef UTIL_H_
+#define UTIL_H_
+#include <time.h>
+#include <stdlib.h>
+
+class cChannel;
+struct tChannelID;
+class cEvent;
+class cEquivHandler;
+class cSchedules;
+
+#define START '\0'
+#define STOP '\0'
+#define ESCAPE '\1'
+
+#define Asprintf(a, b, c...) void( asprintf(a, b, c) < 0 ? esyslog("memory allocation error - %s", b) : void() )
+
+namespace util
+{
+
+extern int AvailableSources[32];
+extern int NumberOfAvailableSources;
+
+extern int Yesterday;
+extern int YesterdayEpoch;
+extern int YesterdayEpochUTC;
+
+extern enum EFormat
+{
+//First all batchmode, load ONCE protocols:
+ MHW1 = 0,
+ MHW2,
+ SKY_IT,
+ SKY_UK,
+ NAGRA,
+//Than all CONTinuous protocols, so they will be processed LAST:
+ PREMIERE,
+ FREEVIEW,
+ DISH_BEV,
+ EIT,
+//the highest number of EPG-formats that is supported by this plugin
+ HIGHEST_FORMAT = EIT
+} Format;
+
+extern cEquivHandler* EquivHandler;
+
+void AddEvent(cEvent *event, tChannelID ChannelID);
+
+cChannel *GetChannelByID(tChannelID & channelID, bool searchOtherPos);
+time_t LocalTime2UTC(time_t t);
+time_t UTC2LocalTime(time_t t);
+void GetLocalTimeOffset(void);
+void CleanString(unsigned char *String);
+void decodeText2(const unsigned char *from, int len, char *buffer, int buffsize);
+char *freesat_huffman_decode(const unsigned char *src, size_t size);
+void sortSchedules(cSchedules * Schedules, tChannelID channelID);
+
+//struct sNode
+//{
+// char *Value;
+// struct sNode *P0;
+// struct sNode *P1;
+//};
+//
+//typedef struct sNode sNodeH;
+
+template<class T> T REALLOC(T Var, size_t Size)
+{
+ T p = (T) realloc(Var, Size);
+ if (!p) free(Var);
+ return p;
+}
+
+struct hufftab
+{
+ unsigned int value;
+ short bits;
+ char next;
+};
+
+extern struct hufftab *tables[2][128];
+extern int table_size[2][128];
+//static sNodeH* sky_tables[2];
+
+}
+#endif /* UTIL_H_ */
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-vdr-dvb/vdr-plugin-eepg.git
More information about the pkg-vdr-dvb-changes
mailing list