From c59a610f66bb7cfd3cf00df3551a3578d4368d35 Mon Sep 17 00:00:00 2001 From: root Date: Sun, 24 Apr 2011 17:54:07 +0200 Subject: Initial eepg git repository with version eepg-0.0.3 --- COPYING | 340 +++ HISTORY | 24 + Makefile | 132 ++ README | 109 + TODO | 14 + eepg.c | 4222 ++++++++++++++++++++++++++++++++++ eepg.equiv.IT | 17 + eepg.h | 7149 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 8 files changed, 12007 insertions(+) create mode 100644 COPYING create mode 100644 HISTORY create mode 100644 Makefile create mode 100644 README create mode 100644 TODO create mode 100644 eepg.c create mode 100644 eepg.equiv.IT create mode 100644 eepg.h 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. + + + Copyright (C) + + 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. + + , 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..b425237 --- /dev/null +++ b/HISTORY @@ -0,0 +1,24 @@ +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..3319320 --- /dev/null +++ b/Makefile @@ -0,0 +1,132 @@ +# +# 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 + +### 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 + +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 + +# 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..a11b771 --- /dev/null +++ b/README @@ -0,0 +1,109 @@ + +This is the Extended EPG (EEPG) plugin for VDR. + + +See the file COPYING for license information. + +---------------------------------------------------------------------- + +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) + +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. + +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 or Freesat). +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 + +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 + -mhwepg program (C) 2002, 2003 Jean-Claude Repetto + -LoadEpg plugin written by Luca De Pieri + -Freesat patch written by dom /at/ suborbital.org.uk + +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 Freesat, 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..888e3f2 --- /dev/null +++ b/TODO @@ -0,0 +1,14 @@ +TODO/WISH: +-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 +-include DDEPG functionality +-parallellize when not on FF card +-NAGRA 2nd textstring is not used right now, find out when it is relevant... diff --git a/eepg.c b/eepg.c new file mode 100644 index 0000000..ce42f6c --- /dev/null +++ b/eepg.c @@ -0,0 +1,4222 @@ +/* + * Extended Epg plugin to VDR (C++) + * + * (C) 2008-2009 Dingo35 + * + * This code is based on: + * -Premiere plugin (C) 2005-2007 Stefan Huelswitt + * -mhwepg program (C) 2002, 2003 Jean-Claude Repetto + * -LoadEpg plugin written by Luca De Pieri + * -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 +#include +#include +#include +#include +#include +#include +#include +#include +#include "eepg.h" + +#include +#include "../../../libsi/si.c" + +#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 */ + +#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 DEBUG +//#define DEBUG2 + +/*#ifdef DEBUG +#define d(x) { (x); } +#else +#define d(x) ; +#endif +#ifdef DEBUG2 +#define d2(x) { (x); } +#else +#define d2(x) ; +#endif*/ + +#define PMT_SCAN_TIMEOUT 10 // seconds +#define PMT_SCAN_IDLE 3600 // seconds + +static const char *VERSION = "0.0.3"; +static const char *DESCRIPTION = trNOOP ("Parses Extended EPG data"); + +// --- cSetupEEPG ------------------------------------------------------- + +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); +} + +class cSetupEEPG +{ +public: + int OptPat; + int OrderInfo; + int RatingInfo; + int FixEpg; +public: + cSetupEEPG (void); +}; + +cSetupEEPG SetupPE; + +cSetupEEPG::cSetupEEPG (void) +{ + OptPat = 1; + OrderInfo = 1; + RatingInfo = 1; + FixEpg = 0; +} + +// --- 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 = SetupPE; + 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)); +} + +void cMenuSetupPremiereEpg::Store (void) +{ + SetupPE = data; + SetupStore ("OptionPattern", SetupPE.OptPat); + SetupStore ("OrderInfo", SetupPE.OrderInfo); + SetupStore ("RatingInfo", SetupPE.RatingInfo); + SetupStore ("FixEpg", SetupPE.FixEpg); +} + +// --- 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 AvailableSources[32]; +static int NumberOfAvailableSources = 0; +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 nEquivChannels, 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); +protected: +#ifdef USE_NOEPG + virtual bool allowedEPG(tChannelID kanalID); +#endif + 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 bool ReadFileDictionary (void); //Reads Huffman tables for SKY + 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 (cSchedule * ps[MAX_EQUIVALENCES], unsigned short int NumberOfEquivalences, + 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); + virtual void LoadIntoSchedule (void); + virtual void LoadEquivalentChannels (void); +public: + cFilterEEPG (void); + virtual void SetStatus (bool On); + void Trigger (void); +}; + +cFilterEEPG::cFilterEEPG (void) +{ + Trigger (); + //Set (0x00, 0x00); +} + +void cFilterEEPG::Trigger (void) +{ + if (VERBOSE >= 3) + isyslog ("trigger\n"); + pmtpid = 0; + pmtidx = 0; + pmtnext = 0; +} + +void cFilterEEPG::SetStatus (bool On) +{ + isyslog ("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++; + if (VERBOSE >= 3) + esyslog ("PMT next\n"); +} +//TODO next routine is also in cEIT2, make this simpler +#ifdef USE_NOEPG + bool cFilterEEPG::allowedEPG (tChannelID kanalID) + { + bool rc; + + if (Setup.noEPGMode == 1) { + rc = false; + if (strstr (::Setup.noEPGList, kanalID.ToString ()) != NULL) + rc = true; + } + else { + rc = true; + if (strstr (::Setup.noEPGList, kanalID.ToString ()) != NULL) + rc = false; + } + + return rc; + } +#endif /* NOEPG */ + + +// ------------------- 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 "../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][256]; +static int table_size[2][256]; + +/** \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 + */ +static void load_file (int tableid, char *filename) +{ + char buf[1024]; + char *from, *to, *binary; + FILE *fp; + + tableid--; + if ((fp = fopen (filename, "r")) != NULL) { + isyslog ("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; + free (from); + free (to); + free (binary); + } + } + fclose (fp); + } + else { + isyslog ("EEPG: Cannot load <%s> for table %d", filename, tableid + 1); + } +} + + +/** \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; + int 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 { + int found = 0; + unsigned bitShift = 0; + if (lastch == ESCAPE) { + char nextCh = (value >> 24) & 0xff; + found = 1; + // 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 = 1; + 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 { + isyslog ("Missing table %d entry: <%s>", tableid + 1, uncompressed); + // Entry missing in table. + return uncompressed; + } + } while (lastch != STOP && value != 0); + + return uncompressed; + } + return NULL; +} + +//here all declarations for global variables over all devices + +char *ConfDir; + +sNodeH *nH, H; + +//unsigned char DecodeErrorText[4096]; //TODO only used for debugging? + +int Yesterday; +int YesterdayEpoch; +int YesterdayEpochUTC; + +/* + * 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) +{ + 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 < 0x20) { + *Src = 0x20; + } + if (*Src == 0x20) { + Spaces++; + if (pC == 0) { + Spaces++; + } + } + else { + Spaces = 0; + } + if (Spaces < 2) { + *Dst = *Src; + *Dst++; + pC++; + } + *Src++; + } + if (Spaces > 0) { + Dst--; + *Dst = 0; + } + else { + *Dst = 0; + } +} + +bool cFilterEEPG::GetThemesSKYBOX (void) //TODO can't we read this from the DVB stream? +{ + char *FileName; + FILE *FileThemes; + char *Line; + char Buffer[256]; + if (Format == SKY_IT) + asprintf (&FileName, "%s/%s", ConfDir, "sky_it.themes"); + else if (Format == SKY_UK) + asprintf (&FileName, "%s/%s", ConfDir, "sky_uk.themes"); + else { + esyslog ("EEPG: Error, wrong format detected in GetThemesSKYBOX. Format = %i.", Format); + return false; + } + //asprintf( &FileName, "%s/%s", ConfDir, ( lProviders + CurrentProvider )->Parm3 ); + FileThemes = fopen (FileName, "r"); + if (FileThemes == NULL) { + esyslog ("EEPG: Error opening file '%s'. %s", FileName, strerror (errno)); + free (FileName); + 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); + } + free (FileName); + return true; +} + +bool cFilterEEPG::ReadFileDictionary (void) +{ + char *FileName; + FILE *FileDict; + char *Line; + char Buffer[256]; + switch (Format) { + case SKY_IT: + asprintf (&FileName, "%s/%s", ConfDir, "sky_it.dict"); + break; + case SKY_UK: + asprintf (&FileName, "%s/%s", ConfDir, "sky_uk.dict"); + break; + case FREEVIEW: + asprintf (&FileName, "%s/%s", ConfDir, "freesat.t1"); + load_file (1, FileName); + asprintf (&FileName, "%s/%s", ConfDir, "freesat.t2"); + load_file (2, FileName); + break; + default: + esyslog ("EEPG: Error, wrong format detected in ReadFileDictionary. Format = %i.", Format); + return false; + } + if ((Format == SKY_IT) || (Format == SKY_UK)) { //SKY + FileDict = fopen (FileName, "r"); + if (FileDict == NULL) { + esyslog ("EEPG: Error opening file '%s'. %s", FileName, strerror (errno)); + free (FileName); + return false; + } + else { + int i; + int LenPrefix; + char string1[256]; + char string2[256]; + H.Value = NULL; + H.P0 = NULL; + H.P1 = NULL; + 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) { + goto codingstart; + } + else if (sscanf (Line, "%[^=]=%[^\n]\n", string1, string2) == 2) { + codingstart:; + nH = &H; + 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) { + esyslog ("EEPG: 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) { + esyslog ("EEPG: 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) { + goto verifystart; + } + else if (sscanf (Line, "%[^=]=%[^\n]\n", string1, string2) == 2) { + verifystart:; + nH = &H; + 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) { + esyslog ("EEPG: Error, huffman prefix value '%s' not equal to '%s'", nH->Value, string1); + } + } + else { + esyslog ("EEPG: Error, huffman prefix value is not exists for \"%s\"=%s", string1, string2); + } + } + } + } + fclose (FileDict); + } + } //if Format == 3 || Format == 4 + free (FileName); + return true; +} + + +int DecodeHuffmanCode (const u_char * Data, int Length, unsigned char *DecodeText) +{ + 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; +} + + +void cFilterEEPG::LoadEquivalentChannels (void) +{ + char Buffer[1024]; + char *Line; + FILE *File; + char *FileName; + + asprintf (&FileName, "%s/%s", ConfDir, EEPG_FILE_EQUIV); + File = fopen (FileName, "r"); + if (File) { + memset (Buffer, 0, sizeof (Buffer)); + char string1[256]; + char string2[256]; + char string3[256]; + int int1; + int int2; + int int3; + int int4; + while ((Line = fgets (Buffer, sizeof (Buffer), File)) != NULL) { + Line = compactspace (skipspace (stripspace (Line))); + if (!isempty (Line)) { + if (sscanf (Line, "%[^ ] %[^ ] %[^\n]\n", string1, string2, string3) == 3) { + if (string1[0] != '#' && string1[0] != ';') { + int1 = 0; //TODO: this could be made more readable + int2 = 0; + int3 = 0; + int4 = 0; + if (sscanf (string1, "%[^-]-%i -%i -%i ", string3, &int1, &int2, &int3) == 4) + if (sscanf (string2, "%[^-]-%i -%i -%i ", string3, &int1, &int2, &int3) == 4) { + if (sscanf (string1, "%[^-]-%i -%i -%i -%i ", string3, &int1, &int2, &int3, &int4) != 5) { + int4 = 0; + } + tChannelID OriginalChID = tChannelID (cSource::FromString (string3), int1, int2, int3, int4); + bool found = false; + int i = 0; + sChannel *C; + while (i < nChannels && (!found)) { + C = &sChannels[i]; + if (C->Src[0] == cSource::FromString (string3) && C->Nid[0] == int1 + && C->Tid[0] == int2 && C->Sid[0] == int3) + found = true; + else + i++; + } + if (!found) { + if (VERBOSE >= 2) + isyslog + ("EEPG Warning: in equivalence file, cannot find original channel %s. Perhaps you are tuned to another transponder right now.", + string1); + } + else { + cChannel *OriginalChannel = Channels.GetByChannelID (OriginalChID, false); + if (!OriginalChannel && (VERBOSE >= 2)) + isyslog ("EEPG: 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", string1); //TODO: skip this warning? + if (sscanf (string2, "%[^-]-%i -%i -%i ", string3, &int1, &int2, &int3) == 4) { + if (sscanf (string2, "%[^-]-%i -%i -%i -%i ", string3, &int1, &int2, &int3, &int4) + != 5) { + int4 = 0; + } + tChannelID EquivChID = tChannelID (cSource::FromString (string3), int1, int2, int3, int4); + cChannel *EquivChannel = Channels.GetByChannelID (EquivChID, false); //TODO use valid function? + if (EquivChannel) { + if (C->NumberOfEquivalences < MAX_EQUIVALENCES) { + C->Src[C->NumberOfEquivalences] = EquivChannel->Source (); + C->Nid[C->NumberOfEquivalences] = EquivChannel->Nid (); + C->Tid[C->NumberOfEquivalences] = EquivChannel->Tid (); + C->Sid[C->NumberOfEquivalences] = EquivChannel->Sid (); + C->NumberOfEquivalences++; + nEquivChannels++; + if (VERBOSE >= 3) + isyslog + ("EEPG: Added equivalent nr %i with Channel Id %s-%i-%i-%i to channel with id %i.", + C->NumberOfEquivalences, *cSource::ToString (C->Src[C->NumberOfEquivalences-1]), + C->Nid[C->NumberOfEquivalences-1], C->Tid[C->NumberOfEquivalences-1], + C->Sid[C->NumberOfEquivalences-1], i); + } + else + esyslog + ("EEPG: Error, channel with id %i has more than %i equivalences. Increase MAX_EQUIVALENCES.", + i, MAX_EQUIVALENCES); + } + else + isyslog ("EEPG: warning, not found equivalent channel \'%s\' in channels.conf", string2); + } + } //else !found + } //if scanf string1 + } //if string1 + } //if scanf + } //if isempty + } //while + fclose (File); + } //if file + free (FileName); +} //end of loadequiv + +int cFilterEEPG::GetChannelsMHW (const u_char * Data, int Length, int MHW) //return code 0 = fatal error, code 1 = sucess, code 2 = last item processed +{ + 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 - 4) / sizeof (sChannelMHW1); + } + if (MHW == 2) { + if (Length > 119) + nChannels = Data[119]; + else { + esyslog ("EEPG: Error, channels packet too short for MHW2."); + return 0; + } + int pName = ((nChannels * 8) + 120); + if (Length > pName) { + //Channel = (sChannelMHW1 *) (Data + 120); + Size -= 14; //MHW2 is 14 bytes shorter + Off = 120; //and offset differs + } + else { + esyslog ("EEPG: Error, channels length does not match pname."); + return 0; + } + } + + if (nChannels > MAX_CHANNELS) { + esyslog ("EEPG: Error, channels found more than %i", MAX_CHANNELS); + return 0; + } + else { + if (VERBOSE >= 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", "------------------------------", + "-----------------------------", "--------------------"); + } + int pName = ((nChannels * 8) + 120); //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; + if (lenName < 256) //TODO impossible, after & 0x0f lenName is always < 0x0f !! + 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[0] = Source (); //assume all EPG channels are on same satellite, if not, manage this via equivalents!!! + C->Nid[0] = HILO16 (Channel->NetworkId); + C->Tid[0] = HILO16 (Channel->TransportId); + C->Sid[0] = HILO16 (Channel->ServiceId); + tChannelID channelID = tChannelID (C->Src[0], C->Nid[0], C->Tid[0], C->Sid[0]); + cChannel *VC = Channels.GetByChannelID (channelID, true); + bool IsFound = (VC); + if (!IsFound) { //look on other satpositions + for (int i = 0; i < NumberOfAvailableSources; i++) { + channelID = tChannelID (AvailableSources[i], C->Nid[0], C->Tid[0], C->Sid[0]); + VC = Channels.GetByChannelID (channelID, true); + IsFound = (VC); + if (IsFound) { //found this actually on satellite nextdoor... + C->Src[0] = AvailableSources[i]; + break; + } + } + } + CleanString (C->Name); + + if (VERBOSE >= 1) { + char *ChID; + asprintf (&ChID, "%s-%i-%i-%i-0", *cSource::ToString (C->Src[0]), C->Nid[0], C->Tid[0], C->Sid[0]); + char *IsF; + if (IsFound) + asprintf (&IsF, " %-3.3s |", "YES"); + else + asprintf (&IsF, " %-3.3s |", "NO"); + isyslog ("|% 5d | %-26.26s | %-22.22s |%s % 6d |\n", C->ChannelId, ChID, C->Name, IsF, C->SkyNumber); + free (ChID); + free (IsF); + } + Off += Size; + } //for loop + } //else nChannels > MAX_CHANNELS + LoadEquivalentChannels (); + GetLocalTimeOffset (); //reread timing variables, only used for MHW + return 2; //obviously, when you get here, channels are read succesfully, but since all channels are sent at once, you can stop now + } //if nChannels == 0 + esyslog ("EEPG 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; +} + +int cFilterEEPG::GetThemesMHW1 (const u_char * Data, int Length) //return code 0 = fatal error, code 1 = sucess, code 2 = last item processed +{ //MHW1 Themes + if (Length > 19) { + sThemeMHW1 *Theme = (sThemeMHW1 *) (Data + 19); + nThemes = (Length - 19) / 15; + if (nThemes > MAX_THEMES) { + esyslog ("EEPG: Error, themes found more than %i", MAX_THEMES); + return 0; + } + else { + if (VERBOSE >= 1) + isyslog ("-------------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] = NULL; //trailing null + CleanString (Themes[Offset]); + if (VERBOSE >= 1) + isyslog ("%.15s", Themes[Offset]); + Offset++; + Theme++; + } + if ((nThemes * 15) + 19 != Length) { + esyslog ("EEPG: Themes error: buffer is smaller or bigger than sum of entries."); + return 0; + } + else + return 2; + } + } + return 1; +} + +int cFilterEEPG::GetThemesMHW2 (const u_char * Data, int Length) //return code 0 = fatal error, code 1 = sucess, code 2 = last item processed +{ + if (!EndThemes) { //only proces 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) { + if (VERBOSE >= 1) + isyslog ("-------------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 ((lenThemeName + 2) < 256) { + memcpy (Themes[pThemeId], &Data[pThemeName], lenThemeName); + if (Length >= (pSubThemeName + lenSubThemeName)) + if (lenSubThemeName > 0) + if ((lenThemeName + lenSubThemeName + 2) < 256) { + Themes[pThemeId][lenThemeName] = ' '; + memcpy (&Themes[pThemeId][lenThemeName + 1], &Data[pSubThemeName], lenSubThemeName); + } + CleanString (Themes[pThemeId]); + if (VERBOSE >= 1) + isyslog ("%.*s", lenThemeName + 1 + lenSubThemeName, Themes[pThemeId]); + //isyslog ("%.15s", (lThemes + pThemeId)->Name); + nThemes++; + if (nThemes > MAX_THEMES) { + esyslog ("EEPG: Error, themes found more than %i", 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 +} + +char *cFilterEEPG::GetSummaryTextNagra (const u_char * DataStart, long int Offset, unsigned int TitleEventId) //this function returns pointer to reserved part of memory with summary text in it, terminated by NULL + //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)) { + esyslog ("EEPG: ERROR, Title has EventId %08x and points to Summary with EventId %08x.", TitleEventId, + HILO32 (SD->EventId)); + return 0; //return empty string + } + + if (VERBOSE >= 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 + { //prevents compiler from complaining + bool LastTextBlock = false; + + do { //for all text parts + sSummaryTextNagraGuide *ST = (sSummaryTextNagraGuide *) p2; + p2 += 8; //skip fixed block + if (VERBOSE >= 3) + if (ST->AlwaysZero1 != 0) + isyslog ("EEPGDEBUG: ST AlwaysZero1 is NOT ZERO:%x.", ST->AlwaysZero1); + if (ST->Always0x4e != 0x4e) { + isyslog ("EEPGDEBUG: ST Always0x4e is NOT 0x4e:%x.", ST->AlwaysZero1); + return 0; //fatal error, empty text + } + //esyslog ("EEPGDEBUG: Textnr %i, Lasttxt %i.", ST->TextNr, ST->LastTextNr); + int SummaryLength = ST->Textlength; + + Text = (unsigned char *) realloc (Text, SummaryLength + TotLength); + if (Text == NULL) { + esyslog ("EEPG: 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] = NULL; //terminate string by NULL char +// isyslog ("EEPGDEBUG: Full Text:%s.", Text); + + break; + } //prevents compiler from complaining + case 0x8c: //"Geen uitzending" "Geen informatie beschikbaar" e.d. + { //prevents compiler from complaining + sSummaryGBRNagraGuide *GBR = (sSummaryGBRNagraGuide *) p2; + + p2 += 16; //skip fixed part, point to byte after Nextlength + if (VERBOSE >= 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)); + } + } //prevents compiler from complaining + break; + default: + esyslog + ("EEPG: 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 summarytext AND no GBR??!! + for (int i = 1; i < (SD->NumberOfBlocks - 1); i++) { + if (VERBOSE >= 3) + isyslog ("EEPGDEBUG: Extra Blockinfo: %02x %02x %02x %02x.", *p, *(p + 1), *(p + 2), *(p + 3)); + p += 4; //skip this extra blockinfo + } + return (char *) Text; +} + +void cFilterEEPG::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 +{ + 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; + if (VERBOSE >= 5) + esyslog + ("EEPG ERROR: Titleblock 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]); + } +} + +void cFilterEEPG::WriteToSchedule (cSchedule * ps[MAX_EQUIVALENCES], unsigned short int NumberOfEquivalences, 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) //ps points to array of schedules ps[eq], where eq is equivalence number of the channel. If channelId is invalid then ps[eq]=NULL + //Duration in minutes +{ + bool WrittenTitle = false; + bool WrittenSummary = false; + for (int eq = 0; eq < NumberOfEquivalences; eq++) { + if (ps[eq]) { + cEvent *Event = NULL; + + Event = (cEvent *) ps[eq]->GetEvent (EventId); //since Nagra uses consistent EventIds, try this first + if (!Event) //if EventId does not match, then try with StartTime + Event = (cEvent *) ps[eq]->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); + char *tmp; + if (Text != 0x00) { + WrittenTitle = true; + CleanString ((uchar *) Text); + Event->SetTitle (Text); + } + asprintf (&tmp, "%s - %d\'", Themes[ThemeId], Duration); + Event->SetShortText (tmp); + //strreplace(t, '|', '\n'); + if (SummText != 0x00) { + WrittenSummary = true; + CleanString ((uchar *) SummText); + Event->SetDescription (SummText); + } + free (tmp); + if (newEvent) + ps[eq]->AddEvent (newEvent); + //newEvent->FixEpgBugs (); causes segfault + } +/* else + esyslog ("EEPG: ERROR, somehow not able to add/update event.");*///at this moment only reports RejectTableId events + if (VERBOSE >= 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++; +} + +void cFilterEEPG::GetTitlesNagra (const u_char * Data, int Length, unsigned short TableIdExtension) //return code 0 = fatal error, code 1 = sucess, code 2 = last item processed +{ //TableIdExtension is the TIE from the relevant summary sections! + 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); + + if (VERBOSE >= 3) + isyslog ("EEPGDEBUG: ChannelId %04x, Blocklength %04x, NumberOfTitles %lu.", ChannelId, Blocklength, + NumberOfTitles); + p += 4; //skip ChannelId and Blocklength + next_p = p + Blocklength; + if (next_p > DataEnd) { //only process if block is complete + esyslog ("EEPG: 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 Titlenumber + + sChannel *C = &sChannels[ChannelSeq[ChannelId]]; //find channel + cSchedule *ps[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 starttime 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); + asprintf (&Text, "%.*s", *t, t + 1); //FIXME second text string is not processed right now + //asprintf (&Text, "%.*s %.*s", *t, t + 1, *t2, t2 + 1); + + //now get summary texts + u_char *DataStartSummaries = buffer[TableIdExtension] + 4; + char *SummText = GetSummaryTextNagra (DataStartSummaries, HILO32 (Title->SumDataOffset), EventId); + + if (VERBOSE >= 3) + isyslog + ("EEPGDEBUG: Eventid: %08x ChannelId:%x, Starttime %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 (ps, C->NumberOfEquivalences, 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 (VERBOSE >= 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); + 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 = sucess, 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; + if (Length == 0) { + if (VERBOSE >= 1) + isyslog ("EEPG: 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 ((VERBOSE >= 1) && (nThemes == 0)) + isyslog ("-------------THEMES FOUND--------------"); + + for (int i = 0; i < NumberOfThemes; i++) { + int Textlength = *p; + p++; //skip textlength byte + u_char *Text = p; + u_char ThemeId; + 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; + //esyslog("EEPGDEBUG: NewThemeId:%02x, Text:%s.",*NewThemeId, Text); + if (Themes[*NewThemeId][0] != 0x00) { //theme is already filled, break off + AnyDoubt = true; + break; //FIXME enabling this break will cause segfault + } + 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 + if (VERBOSE >= 3) + esyslog + ("EEPG: 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.... + } + if (VERBOSE >= 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) { + esyslog + ("EEPG: 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] = NULL; //trailing NULL + CleanString (Themes[ThemeId]); + nThemes++; + if (VERBOSE >= 1) + isyslog ("%02x %s", ThemeId, Themes[ThemeId]); + } + } //for NumberOfThemes + if (p != DataEnd) { + esyslog ("EEPG: Themes error: buffer is smaller or bigger than sum of entries. p:%p,DataEnd:%p", p, DataEnd); + return 0; + } + else + return 2; +} + +int cFilterEEPG::GetChannelsNagra (const u_char * Data, int Length) //return code 0 = fatal error, code 1 = sucess, code 2 = last item processed +{ + 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 (VERBOSE >= 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; lookuptable starts with 0 + C->SkyNumber = 0; + C->NumberOfEquivalences = 1; //there is always an original channel. every equivalence adds 1 + C->Src[0] = Source (); //assume all EPG channels are on same satellite, if not, manage this via equivalents!!! + C->Nid[0] = HILO16 (Channel->NetworkId); + C->Tid[0] = HILO16 (Channel->TransportId); + C->Sid[0] = HILO16 (Channel->ServiceId); + tChannelID channelID = tChannelID (C->Src[0], C->Nid[0], C->Tid[0], C->Sid[0]); + cChannel *VC = Channels.GetByChannelID (channelID, true); + bool IsFound = (VC); + + if (!IsFound) { //look on other satpositions + for (int i = 0; i < NumberOfAvailableSources; i++) { + channelID = tChannelID (AvailableSources[i], C->Nid[0], C->Tid[0], C->Sid[0]); + VC = Channels.GetByChannelID (channelID, true); + IsFound = (VC); + if (IsFound) { //found this actually on satellite nextdoor... + C->Src[0] = AvailableSources[i]; + break; + } + } + } + if (IsFound) + strncpy ((char *) C->Name, VC->Name (), 64); + else + C->Name[0] = NULL; //empty string + CleanString (C->Name); + + if (VERBOSE >= 1) { + char *ChID; + asprintf (&ChID, "%s-%i-%i-%i-0", *cSource::ToString (C->Src[0]), C->Nid[0], C->Tid[0], C->Sid[0]); + char *IsF; + if (IsFound) + asprintf (&IsF, " %-3.3s |", "YES"); + else + asprintf (&IsF, " %-3.3s |", "NO"); + isyslog ("|% 5d | %-26.26s | %-22.22s |%s % 6d |\n", C->ChannelId, ChID, C->Name, IsF, C->SkyNumber); + free (ChID); + free (IsF); + } + if (VERBOSE >= 4) + isyslog ("EEPGDEBUG: 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) { + esyslog ("EEPGDEBUG: ERROR in Channel Table, expected value of 0x8c is %02x", *p); + return 0; //fatal error + } + p++; //skip 8c byte + if (VERBOSE >= 4) + isyslog ("EEPGDEBUG: 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) { + esyslog ("EEPGDEBUG: ERROR in Channel Table, expected value of 0x00 is %02x", *p); + return 0; //fatal error + } + p++; //skip 0x00 byte + if (VERBOSE >= 4) + isyslog ("EEPGDEBUG: 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) + esyslog ("EEPG: Warning, possible problem at end of channel table; p = %p, DataEnd = %p", p, DataEnd); + LoadEquivalentChannels (); + return 2; //obviously, when you get here, channels are read succesfully, but since all channels are sent at once, you can stop now +} + +int cFilterEEPG::GetNagra (const u_char * Data, int Length) //return code 0 = fatal error, code 1 = sucess, code 2 = last item processed +{ + 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) { + isyslog ("EEPG: Nagra EEPG already up-to-date with version %i", LastVersionNagra); + return 2; + } + Version = TBH->VersionNumber; + isyslog ("EEPG: initialized Nagraguide, version %i", Version); + //u_char *p = (u_char *) Data + 11; + u_char *p = (u_char *) Data + 8; + if (*p != 0x01) { + esyslog + ("EEPG: Error, Nagra first byte in table_id_extension 0x0000 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)); + if (VERBOSE >= 4) + isyslog ("EEPGDEBUG: 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) { + if (VERBOSE >= 1) + isyslog ("EEPG: 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] = NULL; + + 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 + if (VERBOSE >= 3) + isyslog ("EEPG: 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 prcoess all themes, since they all use the same codes + unsigned short int TableIdExtension = NagraTIE[i]; + int TIE = TableIdExtension - 0x0200; //from 0x0400 to 0x0200 -> titles + isyslog ("EEPG: Processing TableIdExtension:%04x", TableIdExtension); + GetTitlesNagra (buffer[TIE] + 4, bufsize[TIE] - 4, TableIdExtension); //assume title-reading is completed //TODO Language code terminatd by 0 is ignored + free (buffer[TIE]); + buffer[TIE] = NULL; + NumberOfTables--; + + free (buffer[TableIdExtension]); //summaries + buffer[TableIdExtension] = NULL; + NumberOfTables--; + } + if (NumberOfTables != 0) + esyslog ("EEPG: ERROR, Not all tables processed and stream is already repeating. NumberOfTables = %i.", + NumberOfTables); +} + +int cFilterEEPG::GetTitlesMHW1 (const u_char * Data, int Length) //return code 0 = fatal error, code 1 = sucess, code 2 = last item processed +{ + sTitleMHW1 *Title = (sTitleMHW1 *) Data; + if (Length == 46) { + 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 + 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; + if (VERBOSE >= 3) + isyslog ("EEPG 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->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 (23 + 1); + if (T->Text == NULL) { + esyslog ("EEPG: Titles memory allocation error."); + return 0; + } + T->Text[23] = NULL; //end string with NULL character + memcpy (T->Text, &Title->Title, 23); + CleanString (T->Text); + if (VERBOSE >= 3) + isyslog ("EEPG: EventId:%04x,ChannelId:%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 { + esyslog ("EEPG: Error, titles found more than %i", MAX_TITLES); + return 0; + } + } //else if InitialTitle + } //Length==46 + else { + esyslog ("EEPG: Error, length of title package is not 46."); + return 1; //non fatal + } + + return 1; +} + +int cFilterEEPG::GetTitlesMHW2 (const u_char * Data, int Length) //return code 0 = fatal error, code 1 = sucess, code 2 = last item processed +{ + 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) + 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]; + unsigned int MjdTime = (Data[Pos + 3] << 8) | Data[Pos + 4]; + T->MjdTime = 0; //not used for matching MHW2 + T->StartTime = ((MjdTime - 40587) * 86400) + + (((((Data[Pos + 5] & 0xf0) >> 4) * 10) + (Data[Pos + 5] & 0x0f)) * 3600) + + (((((Data[Pos + 6] & 0xf0) >> 4) * 10) + (Data[Pos + 6] & 0x0f)) * 60); + T->Duration = (((Data[Pos + 8] << 8) | Data[Pos + 9]) >> 4) * 60; + Len = Data[Pos + 10] & 0x3f; + T->Text = (unsigned char *) malloc (Len + 1); + if (T->Text == NULL) { + esyslog ("EEPG: Titles memory allocation error."); + return 0; //fatal error + } + T->Text[Len] = NULL; //end string with NULL character + memcpy (T->Text, &Data[Pos + 11], Len); + CleanString (T->Text); + Pos += Len + 11; + T->ThemeId = ((Data[7] & 0x3f) << 6) | (Data[Pos] & 0x3f); + T->EventId = (Data[Pos + 1] << 8) | Data[Pos + 2]; + T->SummaryAvailable = (T->EventId != 0xFFFF); + if (VERBOSE >= 3) + isyslog ("EEPG: EventId %04x Titlenr %d:SummAv:%x,Name:%s.", T->EventId, nTitles, + T->SummaryAvailable, T->Text); + Pos += 4; + nTitles++; + if (nTitles > MAX_TITLES) { + esyslog ("EEPG: Error, titles found more than %i", MAX_TITLES); + return 0; //fatal error + } + } + return 1; //success + } //else memcmp + } //if length + return 1; //non fatal error +} + +int cFilterEEPG::GetSummariesMHW1 (const u_char * Data, int Length) //return code 0 = fatal error, code 1 = sucess, code 2 = last item processed +{ + 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 (Summary->Byte7 == 0xff && Summary->Byte8 && 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 (SummaryLength + 1); + if (Text == NULL) { + esyslog ("EEPG: Summaries memory allocation error."); + return 0; + } + Text[SummaryLength] = NULL; //end string with NULL character + memcpy (Text, &Data[SummaryOffset], SummaryLength); + CleanString (Text); +// if (Summary->NumReplays != 0) +// esyslog ("EEPG: Number of replays:%i.", Summary->NumReplays); + int Replays = Summary->NumReplays; + int ReplayOffset = 11; + do { + Summary_t *S; + S = (Summary_t *) malloc (sizeof (Summary_t)); + Summaries[nSummaries] = S; + S->NumReplays = Summary->NumReplays; + S->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->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 + + + S->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->StartTime = LocalTime2UTC (S->StartTime); + } + S->EventId = HILO32 (Summary->ProgramId); + S->Text = Text; + if (VERBOSE >= 3) + isyslog ("EEPG: Eventid:%04x Channelid:%x, Summnr %d:%.30s.", S->EventId, S->ChannelId, + nSummaries, S->Text); + nSummaries++; + Replays = Replays - 1; + } while (Replays > 0); + //} while (Replays-- >= 0); + } + else { + esyslog ("EEPG: Error, summaries found more than %i", MAX_TITLES); + return 0; + } + } //0xff + else { + esyslog ("EEPG: Warning, Summary bytes not as expected."); + return 1; //it is not a success, but error is not fatal + } + } //numreplays length + else { + esyslog ("EEPG: Warning, number of replays is not conforming to length."); + return 1; //nonfatal error + } + } //numreplays <10 + else { + esyslog ("EEPG: Warning, number of replays 10 or more, cannot process."); + return 1; //nonfatal error + } + } //length >11 + else { + esyslog ("EEPG: Summary length too small."); + return 1; //nonfatal error + } + return 1; //success +} + +int cFilterEEPG::GetSummariesMHW2 (const u_char * Data, int Length) //return code 0 = fatal error, code 1 = sucess, code 2 = last item processed +{ + 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->ChannelId = 0xFFFF; //signal that ChannelId is not known; 0 is bad signal value because it is a valid ChannelId... + S->StartTime = 0; //not used + S->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] = '|'; + 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] = '|'; + SummaryLength += 1; + } + } + else + break; + Pos += lenText; + Loop--; + } + } + S->Text = (unsigned char *) malloc (SummaryLength + 1); + S->Text[SummaryLength] = NULL; //end string with NULL character + if (S->Text == NULL) { + esyslog ("EEPG: Summaries memory allocation error."); + return 0; //fatal error + } + memcpy (S->Text, tmp, SummaryLength); + CleanString (S->Text); + if (VERBOSE >= 3) + isyslog ("EEPG: EventId %04x Summnr %d:%.30s.", S->EventId, nSummaries, S->Text); + nSummaries++; + } + else { + esyslog ("EEPG: Error, summaries found more than %i", MAX_TITLES); + return 0; //fatal error + } + } //else + } //if length + return 1; //succes or nonfatal error +} + +int cFilterEEPG::GetChannelsSKYBOX (const u_char * Data, int Length) //return code 0 = fatal error, code 1 = sucess, code 2 = last item processed +{ + + if (memcmp (InitialChannel, Data, 8) == 0) { //data is the same as initial title + LoadEquivalentChannels (); + return 2; + } + else { + if (nChannels == 0) + memcpy (InitialChannel, Data, 8); //copy data into initial title + if (VERBOSE >= 1 && nChannels == 0) { + isyslog ("| ID | %-26.26s | %-22.22s | FND | %-8.8s |\n", "Channel ID", "Channel Name", "Sky Num."); + isyslog ("|------|-%-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[0] = Source (); //assume all EPG channels are on same satellite, if not, manage this via equivalents!!! + C->Nid[0] = Nid; + C->Tid[0] = Tid; + C->Sid[0] = Sid; + C->SkyNumber = SkyNumber; + tChannelID channelID = tChannelID (C->Src[0], C->Nid[0], C->Tid[0], C->Sid[0]); + cChannel *VC = Channels.GetByChannelID (channelID, true); + bool IsFound = (VC); + if (IsFound) + strncpy ((char *) C->Name, VC->Name (), 64); + else + C->Name[0] = NULL; //empty string + + if (VERBOSE >= 1) { + char *ChID; + asprintf (&ChID, "%s-%i-%i-%i-0", *cSource::ToString (C->Src[0]), C->Nid[0], C->Tid[0], C->Sid[0]); + char *IsF; + if (IsFound) + asprintf (&IsF, " %-3.3s |", "YES"); + else + asprintf (&IsF, " %-3.3s |", "NO"); + isyslog ("|% 5d | %-26.26s | %-22.22s |%s % 6d |\n", C->ChannelId, ChID, C->Name, IsF, + C->SkyNumber); + free (ChID); + free (IsF); + } + ChannelSeq[C->ChannelId] = nChannels; //fill lookup table to go from channel-id to sequence nr in table + nChannels++; + if (nChannels >= MAX_CHANNELS) { + esyslog ("EEPG: Error, channels found more than %i", MAX_CHANNELS); + return 0; + } + } + } + } + p3 += 9; + DescriptorLength -= 9; + } + break; + default: + break; + } //switch descriptortag + } + } //while + return 1; + } //else part of memcmp +} + +int cFilterEEPG::GetTitlesSKYBOX (const u_char * Data, int Length) //return code 0 = fatal error, code 1 = sucess, code 2 = last item processed +{ + 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) { + if (DEBUG) { + esyslog ("EEPG: Data error signature for title"); + } + break; + } + if (Len1 > Length) { + if (DEBUG) { + esyslog ("EEPG: Data error length for title"); + } + 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->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 = DecodeHuffmanCode (&Data[p + 9], Len2, tmp); + if (Len2 == 0) { + esyslog ("EEPG: 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) { + esyslog ("EEPG: Titles memory allocation error."); + return 0; + } + T->Text[Len2] = NULL; //end string with NULL character + memcpy (T->Text, tmp, Len2); + CleanString (T->Text); + T->SummaryAvailable = 1; //TODO I assume this is true? + + if (VERBOSE >= 3) + isyslog ("EEPG: EventId %04x 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) { + esyslog ("EEPG: Error, titles found more than %i", MAX_TITLES); + return 0; //fatal error + } + } while (p < Length); + } + } + } + return 1; //success +} + +int cFilterEEPG::GetSummariesSKYBOX (const u_char * Data, int Length) //return code 0 = fatal error, code 1 = sucess, code 2 = last item processed +{ + 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->ChannelId = ChannelId; + S->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) { + if (DEBUG) { + esyslog ("EEPG: Data error signature for summary"); + } + break; + } + if (Len1 > Length) { + if (DEBUG) { + esyslog ("EEPG: Data error length for summary"); + } + break; + } + p += 4; + Len2 = Data[p + 1]; + unsigned char tmp[4096]; //TODO can this be done better? + Len2 = DecodeHuffmanCode (&Data[p + 2], Len2, tmp); + if (Len2 == 0) { + esyslog ("EEPG: Warning, could not huffman-decode text, skipping summary."); + return 1; //non-fatal error + } + S->Text = (unsigned char *) malloc (Len2 + 1); + if (S->Text == NULL) { + esyslog ("EEPG: Summaries memory allocation error."); + return 0; + } + memcpy (S->Text, tmp, Len2); + S->Text[Len2] = NULL; //end string with NULL character + CleanString (S->Text); + if (VERBOSE >= 3) + isyslog ("EEPG: EventId %04x Summnr %d:%.30s.", S->EventId, nSummaries, S->Text); + p += Len1; + nSummaries++; + if (nSummaries >= MAX_TITLES) { + esyslog ("EEPG: Error, summaries found more than %i", 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 textblock; 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, k; + i = 0; + j = 0; + k = 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; //TODO: does this work??? + else if ((T->EventId == S->EventId) && (T->MjdTime == S->MjdTime) && ((T->ChannelId == S->ChannelId) || ((Format != SKY_IT) && (Format != SKY_UK)))) { //should always be true, titles and summaries are broadcasted in order... + //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; + + do { + unsigned short int ChannelId; + time_t StartTime; + if (S->NumReplays == 0) { + ChannelId = T->ChannelId; + StartTime = T->StartTime; + } + else { + ChannelId = S->ChannelId; + StartTime = S->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); + + WriteToSchedule (p, C->NumberOfEquivalences, T->EventId, StartTime, T->Duration / 60, (char *) T->Text, + (char *) S->Text, T->ThemeId, DEFAULT_TABLE_ID, 0); + + 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 + } + } //while + while (Replays > 0); + +//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 %04x 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]; + PrepareToWriteToSchedule (C, s, p); + WriteToSchedule (p, C->NumberOfEquivalences, T->EventId, T->StartTime, T->Duration / 60, (char *) T->Text, + NULL, T->ThemeId, DEFAULT_TABLE_ID, 0); + FinishWriteToSchedule (C, s, p); + + 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 + esyslog ("EEPG Error: could not lock schedules."); + + 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); + 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); + else if (VERBOSE >= 1) + isyslog ("EEPG: %i summaries not found", SummariesNotFound); + if (NotMatching > nSummaries) + isyslog ("EEPG 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 ("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 ("Filter Pid:%x,Tid:%x,Mask:%x added.", Pid, Tid, Mask); + } +} + +namespace SI +{ +/*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::cSchedules * Schedules, int Source, u_char Tid, const u_char * Data, + bool OnlyRunningStatus = false); + +// originally from libdtv, Copyright Rolf Hakenes +//void decodeText2(char *from, char *buffer, int size) { + void decodeText2 (const unsigned char *from, int len, char *buffer, int size) + { +// const unsigned char *from=data.getData(0); + char *to = buffer; +// int len=getLength(); + if (len < 0 || len >= size) + { + strncpy (buffer, "text error", size); + buffer[size - 1] = 0; + return; + } + if (len <= 0) + { + *to = '\0'; + return; + } + bool singleByte; + + + if (from[0] == 0x1f) { + char *temp = freesat_huffman_decode (from, len); + if (temp) { + len = strlen (temp); + len = len < size - 1 ? len : size - 1; + strncpy (buffer, temp, len); + buffer[len] = 0; + free (temp); + return; + } + } + + + const char *cs = getCharacterTable (from, len, &singleByte); + // FIXME Need to make this UTF-8 aware (different control codes). + // However, there's yet to be found a broadcaster that actually + // uses UTF-8 for the SI data... (kls 2007-06-10) + for (int i = 0; i < len; i++) { + if (*from == 0) + break; + if (((' ' <= *from) && (*from <= '~')) + || (*from == '\n') + || (0xA0 <= *from) + ) + *to++ = *from; + else if (*from == 0x8A) + *to++ = '\n'; + from++; + if (to - buffer >= size - 1) + break; + } + *to = '\0'; + if (!singleByte || !SystemCharacterTableIsSingleByte) { + char convBuffer[size]; + if (convertCharacterTable (buffer, strlen (buffer), convBuffer, sizeof (convBuffer), cs)) + strncpy (buffer, convBuffer, strlen (convBuffer) + 1); + } + } + +#ifdef USE_NOEPG + private: + bool allowedEPG (tChannelID kanalID); +#endif /* NOEPG */ + }; + +#ifdef USE_NOEPG + bool cEIT2::allowedEPG (tChannelID kanalID) + { + bool rc; + + if (Setup.noEPGMode == 1) { + rc = false; + if (strstr (::Setup.noEPGList, kanalID.ToString ()) != NULL) + rc = true; + } + else { + rc = true; + if (strstr (::Setup.noEPGList, kanalID.ToString ()) != NULL) + rc = false; + } + + return rc; + } +#endif /* NOEPG */ + + cEIT2::cEIT2 (cSchedules::cSchedules * Schedules, int Source, u_char Tid, const u_char * Data, bool OnlyRunningStatus) +: SI::EIT (Data, false) { + if (!CheckCRCAndParse ()) + return; + + tChannelID channelID (Source, getOriginalNetworkId (), getTransportStreamId (), getServiceId ()); + cChannel *channel = Channels.GetByChannelID (channelID, true); + if (!channel) + return; // only collect data for known channels + +#ifdef USE_NOEPG + // only use epg from channels not blocked by noEPG-patch + tChannelID kanalID; + kanalID = channel->GetChannelID (); + if (!allowedEPG (kanalID)) + return; +#endif /* NOEPG */ + + cSchedule *pSchedule = (cSchedule *) Schedules->GetSchedule (channel, true); + + bool Empty = true; + bool Modified = false; + bool HasExternalData = false; + time_t SegmentStart = 0; + time_t SegmentEnd = 0; + + SI::EIT::Event SiEitEvent; + for (SI::Loop::Iterator it; eventLoop.getNext (SiEitEvent, it);) { + 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 (); + cEvent *newEvent = NULL; + cEvent *rEvent = 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 { + // 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) { +#ifdef USE_DDEPGENTRY + if (pEvent->Version () == getVersionNumber ()) { + if (Setup.MixEpgAction == 0) + continue; + //printf("in"); + //printf("%s", pEvent->GetTimeString()); + // to use the info of the original epg, update the extern one, + // if it has less info + SI::Descriptor * d; + SI::ExtendedEventDescriptors * ExtendedEventDescriptors = NULL; + //SI::ExtendedEventDescriptor *eed = NULL; + SI::ShortEventDescriptor * ShortEventDescriptor = NULL; + //SI::ShortEventDescriptor *sed = NULL; + //SI::TimeShiftedEventDescriptor *tsed = NULL; + //cLinkChannels *LinkChannels = NULL; + for (SI::Loop::Iterator it2; (d = SiEitEvent.eventDescriptors.getNext (it2));) { + if (d->getDescriptorTag () == SI::ShortEventDescriptorTag) { + int LanguagePreferenceShort = -1; + 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 + } + } + else if (d->getDescriptorTag () == SI::ExtendedEventDescriptorTag) { + int LanguagePreferenceExt = -1; + bool UseExtendedEventDescriptor = false; + 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; + } + delete d; + } + if (pEvent) { + if (ShortEventDescriptor) { + char buffer[256]; + if (ShortEventDescriptor->text.getText (buffer, sizeof (buffer)) && pEvent->ShortText () + && (strlen (ShortEventDescriptor->text.getText (buffer, sizeof (buffer))) > + strlen (pEvent->ShortText ()))) { + pEvent->SetShortText (ShortEventDescriptor->text.getText (buffer, sizeof (buffer))); + pEvent->FixEpgBugs (); + } + } + if (ExtendedEventDescriptors) { + char buffer[ExtendedEventDescriptors->getMaximumTextLength (": ") + 1]; + //pEvent->SetDescription(ExtendedEventDescriptors->getText(buffer, sizeof(buffer), ": ")); + if (ExtendedEventDescriptors->getText (buffer, sizeof (buffer), ": ") + && pEvent->Description () + && (strlen (ExtendedEventDescriptors->getText (buffer, sizeof (buffer), ": ")) > + strlen (pEvent->Description ()))) { + pEvent->SetDescription (ExtendedEventDescriptors->getText (buffer, sizeof (buffer), ": ")); + pEvent->FixEpgBugs (); + } + } + } + delete ExtendedEventDescriptors; + delete ShortEventDescriptor; + continue; + } +#else + if (pEvent->Version () == getVersionNumber ()) + continue; +#endif /* DDEPGENTRY */ + 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 () == getVersionNumber ()) + 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 +#ifdef USE_DDEPGENTRY + if (Setup.DisableVPS == 0 && SiEitEvent.getRunningStatus () >= SI::RunningStatusNotRunning) +#else + if (SiEitEvent.getRunningStatus () >= SI::RunningStatusNotRunning) +#endif /* DDEPGENTRY */ + 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 (getVersionNumber ()); + + int LanguagePreferenceShort = -1; + int LanguagePreferenceExt = -1; + bool UseExtendedEventDescriptor = false; + SI::Descriptor * d; + SI::ExtendedEventDescriptors * ExtendedEventDescriptors = NULL; + SI::ShortEventDescriptor * ShortEventDescriptor = NULL; + cLinkChannels *LinkChannels = NULL; + cComponents *Components = NULL; + for (SI::Loop::Iterator it2; (d = SiEitEvent.eventDescriptors.getNext (it2));) { + if (ExternalData && d->getDescriptorTag () != SI::ComponentDescriptorTag) { + delete d; + continue; + } + switch (d->getDescriptorTag ()) { + 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; + case SI::ContentDescriptorTag: + break; + case SI::ParentalRatingDescriptorTag: + 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:{ + 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 ()); + //XXX patFilter->Trigger(); + } + 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 (!Components) + Components = new cComponents; + char buffer[Utf8BufSize (256)]; + Components->SetComponent (Components->NumComponents (), Stream, Type, + I18nNormalizeLanguageCode (cd->languageCode), + cd->description.getText (buffer, sizeof (buffer))); + } + } + break; + default:; + } + 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)); + pEvent->SetTitle (buffer); + l = ShortEventDescriptor->text.getLength (); + f = (unsigned char *) ShortEventDescriptor->text.getData ().getData (); + decodeText2 (f, l, buffer, sizeof (buffer)); + pEvent->SetShortText (buffer); + } + else if (!HasExternalData) { + pEvent->SetTitle (NULL); + pEvent->SetShortText (NULL); + } + if (ExtendedEventDescriptors) { + char buffer[Utf8BufSize (ExtendedEventDescriptors->getMaximumTextLength (": ")) + 1]; + pEvent->SetDescription (ExtendedEventDescriptors->getText (buffer, sizeof (buffer), ": ")); + } + else if (!HasExternalData) + pEvent->SetDescription (NULL); + } + delete ExtendedEventDescriptors; + delete ShortEventDescriptor; + + pEvent->SetComponents (Components); + + if (!HasExternalData) + pEvent->FixEpgBugs (); + if (LinkChannels) + channel->SetLinkChannels (LinkChannels); + Modified = true; +#ifdef USE_DDEPGENTRY + //to avoid double epg-entrys from ext and int epg sources :EW + if (pEvent && pEvent->TableID () != 0x00) { + cEvent *pPreviousEvent = (cEvent *) pSchedule->GetPreviousEvent (pEvent); + if (pPreviousEvent) { + if (Setup.DoubleEpgAction == 0) { + pPreviousEvent->SetStartTime (pEvent->StartTime ()); + pPreviousEvent->SetDuration (pEvent->Duration ()); + if (Setup.DisableVPS == 0) { + if (channel) + pPreviousEvent->SetRunningStatus (pEvent->RunningStatus (), channel); + else + pPreviousEvent->SetRunningStatus (pEvent->RunningStatus ()); + } + // to use the info of the original epg, update the extern one, + // if it has less info + char buffer_short_intern[256]; + char buffer_short_extern[256]; + int len_short_intern = 0; + int len_short_extern = 0; + if (pEvent->ShortText ()) + len_short_intern = + snprintf (buffer_short_intern, sizeof (buffer_short_intern) - 1, "%s", pEvent->ShortText ()); + if (pPreviousEvent->ShortText ()) + len_short_extern = + snprintf (buffer_short_extern, sizeof (buffer_short_extern) - 1, "%s", pPreviousEvent->ShortText ()); + if (len_short_intern > 0) { + if (len_short_extern < 1) + pPreviousEvent->SetShortText (buffer_short_intern); + else if (len_short_intern > len_short_extern) + pPreviousEvent->SetShortText (buffer_short_intern); + } + if (pEvent->Description ()) { + char buffer_title_intern[4096]; + char buffer_title_extern[4096]; + int len_title_intern = 0; + int len_title_extern = 0; + if (pEvent->Description ()) + len_title_intern = + snprintf (buffer_title_intern, sizeof (buffer_title_intern) - 1, "%s", pEvent->Description ()); + if (pPreviousEvent->Description ()) + len_title_extern = + snprintf (buffer_title_extern, sizeof (buffer_title_extern) - 1, "%s", + pPreviousEvent->Description ()); + if (len_title_intern > 0) { + if (len_title_extern < 1) + pPreviousEvent->SetDescription (buffer_title_intern); + else if (len_title_intern > len_title_extern) + pPreviousEvent->SetDescription (buffer_title_intern); + } + } + if (pPreviousEvent->Vps () == 0 && pEvent->Vps () != 0) + pPreviousEvent->SetVps (pEvent->Vps ()); + pSchedule->DelEvent (pEvent); + pPreviousEvent->FixEpgBugs (); + } + else + pSchedule->DelEvent (pPreviousEvent); + } + } +#endif /* DDEPGENTRY */ + } + 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) + return; + if (Modified) { + pSchedule->Sort (); + if (!HasExternalData) + pSchedule->DropOutdated (SegmentStart, SegmentEnd, Tid, getVersionNumber ()); + Schedules->SetModified (pSchedule); + } + } +//end of cEIT2 +} //end namespace SI + +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", nEquivChannels); + 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); + 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 + } + TitleCounter = 0; + SummaryCounter = 0; + RejectTableId = 0; + //cleanup mess of last processing + ChannelSeq.clear (); + FreeTitles (); + FreeSummaries (); + + //now start looking for next format to process + int pid; + Format = -1; //unused value + 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 = i; + } //highest format is processed first this way;; TODO make sure that CONT protocols like Premiere, Freesat are processed AFTER ONCE protocols like MHW, SKY and NAGRA + + if (Format == -1) { //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... + nEquivChannels = 0; + nChannels = 0; + nThemes = 0; + EndChannels = false; + EndThemes = false; + switch (Format) { + case PREMIERE: + if (!Matches (pid, 0xA0)) + Add (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 + ReadFileDictionary (); + 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) + case NAGRA: + // isyslog ("EEPG: NagraGuide Extended EPG detected."); + AddFilter (pid, 0xb0); //perhaps TID is equal to first data byte? + default: + break; + } +} + +void cFilterEEPG::Process (u_short Pid, u_char Tid, const u_char * Data, int Length) +{ + int now = time (0); + 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; + if (VERBOSE >= 3) + esyslog ("PMT pid now 0x%04x (idx=%d)\n", pmtpid, pmtidx); + break; + } + } + } + if (!pmtpid) { + pmtidx = 0; + pmtnext = now + PMT_SCAN_IDLE; + if (VERBOSE >= 1) + esyslog ("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);) { +// if(stream.getStreamType()==0x05) { + 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; + //Format = 0; // 0 = premiere, 1 = MHW1, 2 = MHW2, 3 = Sky Italy (OpenTV), 4 = Sky UK (OpenTV), 5 = Freesat (Freeview), 6 = Nagraguide + SI::Descriptor * d; + for (SI::Loop::Iterator it; (d = stream.streamDescriptors.getNext (it));) { + //esyslog ("EEPGDEBUG:d->getDescriptorTAG():%x,SI::PrivateTag:%x\n", d->getDescriptorTag (), SI::PrivateDataSpecifierDescriptorTag); + switch (d->getDescriptorTag ()) { + 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 (); + //int nop; //FIXME + 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) & 0xff000000) == 0xc0000000)) //SKY UK + if (d->getLength () == 3 && ((d->getData ().TwoBytes (2) & 0xff00) == 0x9d00)) //SKY UK //TODO ugly! + 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 (); + //int nop;//FIXME + else if (d->getLength () == 10 && d->getData ().FourBytes (2) == 0x46494348) { //MHW2 + UnprocessedFormat[MHW2] = stream.getPid (); + } + break; + 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 (); + } //if data[1] && data [3] + } //if streamtype + /*if (Format != PREMIERE) //any format found + break; //break out for loop */ + } //for loop that walks through streams +// if (Format == PREMIERE) { //FIXME for Premiere you should also stop scanning when found... + 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 ()) { + int Result; + switch (Tid) { + case 0xA0: + if ((Pid < 0x30) || (Pid > 0x37)) { + SI::PremiereCIT cit (Data, false); + if (cit.CheckCRCAndParse ()) { + cSchedulesLock SchedulesLock (true, 10); + cSchedules *Schedules = (cSchedules *) cSchedules::Schedules (SchedulesLock); + if (Schedules) { + int nCount = 0; + SI::ExtendedEventDescriptors * ExtendedEventDescriptors = 0; + SI::ShortEventDescriptor * ShortEventDescriptor = 0; + char *order = 0, *rating = 0; + { + time_t firstTime = 0; + SI::Descriptor * d; + bool UseExtendedEventDescriptor = false; + int LanguagePreferenceShort = -1; + int LanguagePreferenceExt = -1; + for (SI::Loop::Iterator it; (d = cit.eventDescriptors.getNext (it));) { + switch (d->getDescriptorTag ()) { + 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; + p += + snprintf (&buff[p], sizeof (buff) - p, "\n%s: %d %s", tr ("Rating"), data[0] + 3, 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); +#ifdef USE_NOEPG + // only use epg from channels not blocked by noEPG-patch + if (!allowedEPG (channelID)) + continue; +#endif /* NOEPG */ + + 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)); + if (VERBOSE >= 2) + isyslog ("%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) { + if (VERBOSE >= 2) + isyslog ("(old)\n"); + continue; + } + + bool newEvent = false; + cEvent *pEvent = (cEvent *) pSchedule->GetEvent (EventId, -1); + if (!pEvent) { + if (VERBOSE >= 2) + isyslog ("(new)\n"); + pEvent = new cEvent (EventId); + if (!pEvent) + continue; + newEvent = true; + } + else { + if (VERBOSE >= 2) + isyslog ("(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); + if (VERBOSE >= 2) + isyslog ("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); + 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); + } + } //if checkcrcandpars + break; + } //if citpid == 0xb11 Premiere + else //SKY also uses 0xA0 Tid, do NOT break then!! + { + } //TODO do I need this dummy? + 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 (ReadFileDictionary ()) + 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) { + cSchedulesLock SchedulesLock (true, 10); + cSchedules *Schedules = (cSchedules *) cSchedules::Schedules (SchedulesLock); + if (Schedules) + SI::cEIT2 EIT (Schedules, Source (), Tid, Data); + //cEIT EIT (Schedules, Source (), Tid, Data); + else { + // 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, true); + //cEIT EIT (Schedules, Source (), Tid, Data, true); + } + } + break; + + default: + break; + } //end switch + } //closes SOURCE() +} //end of closing + +// --- cPluginEEPG ------------------------------------------------------ + +class cPluginEEPG:public cPlugin +{ +private: + struct + { + cFilterEEPG *filter; + cDevice *device; + } epg[MAXDVBDEVICES]; +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)); +} + +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); + } + } + ConfDir = NULL; + // Initialize any background activities the plugin shall perform. + char *FileName; + DIR *ConfigDir; + FILE *File; + 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); + } + } + asprintf (&FileName, "%s/%s", ConfDir, EEPG_FILE_EQUIV); + File = fopen (FileName, "r"); + if (File == NULL) { + esyslog ("EEPG: Error opening file '%s', %s", FileName, strerror (errno)); + File = fopen (FileName, "w"); + if (File == NULL) { + esyslog ("EEPG: Error creating file '%s', %s", FileName, strerror (errno)); + } + else { + int i = 0; + while (FileEquivalences[i] != NULL) { + fprintf (File, "%s\n", FileEquivalences[i]); + i++; + } + isyslog ("EEPG: Success creating file '%s'", FileName); + fclose (File); + } + } + else { + fclose (File); + } + free (FileName); + asprintf (&FileName, "%s/%s", ConfDir, "sky_it.dict"); + File = fopen (FileName, "r"); + if (File == NULL) { + esyslog ("EEPG: Error opening file '%s', %s", FileName, strerror (errno)); + File = fopen (FileName, "w"); + if (File == NULL) { + esyslog ("EEPG: Error creating file '%s', %s", FileName, strerror (errno)); + } + else { + int i = 0; + while (SkyItDictionary[i] != NULL) { + fprintf (File, "%s\n", SkyItDictionary[i]); + i++; + } + isyslog ("EEPG: Success creating file '%s'", FileName); + fclose (File); + } + } + else { + fclose (File); + } + free (FileName); + asprintf (&FileName, "%s/%s", ConfDir, "sky_uk.dict"); + File = fopen (FileName, "r"); + if (File == NULL) { + esyslog ("EEPG: Error opening file '%s', %s", FileName, strerror (errno)); + File = fopen (FileName, "w"); + if (File == NULL) { + esyslog ("EEPG: Error creating file '%s', %s", FileName, strerror (errno)); + } + else { + int i = 0; + while (SkyUkDictionary[i] != NULL) { + fprintf (File, "%s\n", SkyUkDictionary[i]); + i++; + } + isyslog ("EEPG: Success creating file '%s'", FileName); + fclose (File); + } + } + else { + fclose (File); + } + free (FileName); + asprintf (&FileName, "%s/%s", ConfDir, "sky_it.themes"); + File = fopen (FileName, "r"); + if (File == NULL) { + esyslog ("EEPG: Error opening file '%s', %s", FileName, strerror (errno)); + File = fopen (FileName, "w"); + if (File == NULL) { + esyslog ("EEPG: Error creating file '%s', %s", FileName, strerror (errno)); + } + else { + for (int i = 0; i < 256; i++) { + if (SkyItThemes[i]) { + fprintf (File, "0x%02x=%s\n", i, SkyItThemes[i]); + } + else { + fprintf (File, "0x%02x=\n", i); + } + } + isyslog ("EEPG: Success creating file '%s'", FileName); + fclose (File); + } + } + else { + fclose (File); + } + free (FileName); + asprintf (&FileName, "%s/%s", ConfDir, "sky_uk.themes"); + File = fopen (FileName, "r"); + if (File == NULL) { + esyslog ("EEPG: Error opening file '%s', %s", FileName, strerror (errno)); + File = fopen (FileName, "w"); + if (File == NULL) { + esyslog ("EEPG: Error creating file '%s', %s", FileName, strerror (errno)); + } + else { + for (int i = 0; i < 256; i++) { + if (SkyUkThemes[i]) { + fprintf (File, "0x%02x=%s\n", i, SkyUkThemes[i]); + } + else { + fprintf (File, "0x%02x=\n", i); + } + } + isyslog ("EEPG: Success creating file '%s'", FileName); + fclose (File); + } + } + else { + fclose (File); + } + free (FileName); + asprintf (&FileName, "%s/%s", ConfDir, "freesat.t1"); + File = fopen (FileName, "r"); + if (File == NULL) { + esyslog ("EEPG: Error opening file '%s', %s", FileName, strerror (errno)); + File = fopen (FileName, "w"); + if (File == NULL) { + esyslog ("EEPG: Error creating file '%s', %s", FileName, strerror (errno)); + } + else { + int i = 0; + while (FreesatT1[i] != NULL) { + fprintf (File, "%s\n", FreesatT1[i]); + i++; + } + isyslog ("EEPG: Success creating file '%s'", FileName); + fclose (File); + } + } + else { + fclose (File); + } + free (FileName); + asprintf (&FileName, "%s/%s", ConfDir, "freesat.t2"); + File = fopen (FileName, "r"); + if (File == NULL) { + esyslog ("EEPG: Error opening file '%s', %s", FileName, strerror (errno)); + File = fopen (FileName, "w"); + if (File == NULL) { + esyslog ("EEPG: Error creating file '%s', %s", FileName, strerror (errno)); + } + else { + int i = 0; + while (FreesatT2[i] != NULL) { + fprintf (File, "%s\n", FreesatT2[i]); + i++; + } + isyslog ("EEPG: Success creating file '%s'", FileName); + fclose (File); + } + } + else { + fclose (File); + } + free (FileName); + + //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 (VERBOSE >= 3) + for (int i = 0; i < NumberOfAvailableSources; i++) + isyslog ("EEPG: Available sources:%s.", *cSource::ToString (AvailableSources[i])); + + + 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); + } +} + +cMenuSetupPage *cPluginEEPG::SetupMenu (void) +{ + return new cMenuSetupPremiereEpg; +} + +bool cPluginEEPG::SetupParse (const char *Name, const char *Value) +{ + 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 + 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: +# +# +# + +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..5372714 --- /dev/null +++ b/eepg.h @@ -0,0 +1,7149 @@ +#define DEBUG false +//#define DEBUG_STARTTIME false + +#define EEPG_FILE_EQUIV "eepg.equiv" + +#define MAX_THEMES 256 //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): +//First all CONTinuous protocols, so they will be processed LAST: +#define PREMIERE 0 +#define FREEVIEW 1 +//Then all batchmode, load ONCE protocols: +#define MHW1 2 +#define MHW2 3 +#define SKY_IT 4 +#define SKY_UK 5 +#define NAGRA 6 +#define HIGHEST_FORMAT 6 //the highest number of EPG-formats that is supported by this plugin + +#define NAGRA_TABLE_ID 0x60 //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[]= {"Premiere","FreeView","MediaHighWay 1","MediaHighWay 2","Sky Italy","Sky UK","NagraGuide"}; + +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 short 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 +} Title_t; + +typedef struct { + unsigned short int ChannelId; + unsigned int StartTime; + unsigned short int MjdTime; + unsigned int EventId;//short is not sufficient for Nagra + unsigned short int NumReplays; + unsigned char * Text; +} Summary_t; + +static const char *FileEquivalences[] = { + "#", + "# Simply add a list of the channels in this file with the following format:", + "#", + "# ", + "#", + "", + "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) -- cgit v1.2.3