diff options
author | root <root@ubsatserv.(none)> | 2011-04-24 17:54:07 +0200 |
---|---|---|
committer | root <root@ubsatserv.(none)> | 2011-04-24 17:56:25 +0200 |
commit | c59a610f66bb7cfd3cf00df3551a3578d4368d35 (patch) | |
tree | 04c4d4df080deacfc80c9cf75e327783d94f697f | |
download | vdr-plugin-eepg-c59a610f66bb7cfd3cf00df3551a3578d4368d35.tar.gz vdr-plugin-eepg-c59a610f66bb7cfd3cf00df3551a3578d4368d35.tar.bz2 |
Initial eepg git repository with version eepg-0.0.3eepg-0.0.3
-rw-r--r-- | COPYING | 340 | ||||
-rw-r--r-- | HISTORY | 24 | ||||
-rw-r--r-- | Makefile | 132 | ||||
-rw-r--r-- | README | 109 | ||||
-rw-r--r-- | TODO | 14 | ||||
-rw-r--r-- | eepg.c | 4222 | ||||
-rw-r--r-- | eepg.equiv.IT | 17 | ||||
-rw-r--r-- | eepg.h | 7149 |
8 files changed, 12007 insertions, 0 deletions
@@ -0,0 +1,340 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + <one line to give the program's name and a brief idea of what it does.> + Copyright (C) <year> <name of author> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + <signature of Ty Coon>, 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. @@ -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 @@ -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 <s.huelswitt@gmx.de> + -mhwepg program (C) 2002, 2003 Jean-Claude Repetto <mhwepg@repetto.org> + -LoadEpg plugin written by Luca De Pieri <dpluca@libero.it> + -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. + @@ -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... @@ -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 <s.huelswitt@gmx.de> + * -mhwepg program (C) 2002, 2003 Jean-Claude Repetto <mhwepg@repetto.org> + * -LoadEpg plugin written by Luca De Pieri <dpluca@libero.it> + * -Freesat patch written by dom /at/ suborbital.org.uk + * + * + * This code is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This code is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * Or, point your browser to http://www.gnu.org/copyleft/gpl.html + */ + +#include <vdr/plugin.h> +#include <vdr/filter.h> +#include <vdr/epg.h> +#include <vdr/channels.h> +#include <vdr/dvbdevice.h> +#include <vdr/i18n.h> +#include <vdr/config.h> +#include <libsi/section.h> +#include <libsi/descriptor.h> +#include "eepg.h" + +#include <map> +#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 <hakenes@hippomi.de> +//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: +# +# <OriginalChannelId> <OtherChannelId> <ChannelName> +# + +S13.0E-64511-6700-11517 S13.0E-318-13000-14601 BBC Prime +S13.0E-318-5200-3401 S19.2E-1-1024-9015 Rai Uno +S13.0E-318-5200-3401 S13.0E-318-12400-8511 Rai Uno +S13.0E-318-5200-3402 S13.0E-318-12400-8512 Rai Due +S13.0E-318-5200-3403 S13.0E-318-12400-8513 Rai Tre +S13.0E-272-6000-3 T-272-905-143 Rete 4 +S13.0E-272-6000-2 T-272-905-141 Canale 5 +S13.0E-272-6000-1 T-272-905-142 Italia 1 +S13.0E-64511-8600-11733 T-29-514-1 La 7 +S13.0E-64511-6700-11504 S13.0E-318-200-13831 Eurosport + @@ -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:", + "#", + "# <OriginalChannelId> <OtherChannelId> <ChannelName>", + "#", + "", + "S13.0E-64511-6700-11517 S13.0E-318-13000-14601 BBC Prime", + "S13.0E-318-5200-3401 S19.2E-1-1024-9015 Rai Uno", + "S13.0E-318-5200-3401 S13.0E-318-12400-8511 Rai Uno", + "S13.0E-318-5200-3402 S13.0E-318-12400-8512 Rai Due", + "S13.0E-318-5200-3403 S13.0E-318-12400-8513 Rai Tre", + "S13.0E-272-6000-3 T-272-905-143 Rete 4", + "S13.0E-272-6000-2 T-272-905-141 Canale 5", + "S13.0E-272-6000-1 T-272-905-142 Italia 1", + "S13.0E-64511-8600-11733 T-29-514-1 La 7", + "S13.0E-64511-6700-11504 S13.0E-318-200-13831 Eurosport", + "", + NULL +}; + +static const char *SkyItDictionary[] = { + " =00001011010110001111010101010", + " =00001011010110001111010101011", + " =00001011010110001111010101100", + " =00001011010110001111010101101", + " =00001011010110001111010101110", + " =00001011010110001111010101111", + " =00001011010110001111010110000", + " =00001011010110001111010110001", + " =00001011010110001111010110010", + " =00001011010110001111010110011", + " =00001011010110001111010110100", + " =00001011010110001111010110101", + " =00001011010110001111010110110", + " =1001110", + " =00001011010110001111010110111", + " =00001011010110001111010111000", + " =00001011010110001111010111001", + " =00001011010110001111010111010", + " =00001011010110001111010111011", + " =00001011010110001111010111100", + " =00001011010110001111010111101", + " =00001011010110001111010111110", + " =00001011010110001111010111111", + " =00001011010110001111011000000", + " =00001011010110001111011000001", + " =00001011010110001111011000010", + " =00001011010110001111011000011", + " =00001011010110001111011000100", + " =00001011010110001111011000101", + " =00001011010110001111011000110", + " =00001011010110001111011000111", + " =00001011010110001111011001000", + " =01", + "!=1110000011101", + "\"=11100010000100011", + "#=00001011010110001111011001001", + "$=00001011010110001111011001010", + "%=00001011010110001111011001011", + "&=11100010000101", + "'=0000100", + "(=0000101101010", + ")=110100111111", + "*=00001011010110001111011001100", + "+=000010110101100011111", + ",=110000", + "-=10110011", + ".=100110", + "/=111000100001001", + "0=10010011", + "1=100100000", + "2=1111011001", + "3=1110001110", + "4=11000100101", + "5=111101110100", + "6=101100101111", + "7=110100011110", + "8=11010001110", + "9=1111010111", + ":=100100011", + ";=10000111101", + "<=00001011010110001111011001101", + "==00001011010110001111011001110", + ">=00001011010110001111011001111", + "?=1100110110110", + "@=1110001000010000", + "A=00001010", + "B=111101001", + "C=10010100", + "D=100001010", + "E=111000000", + "F=1110001100", + "G=100101100", + "H=1000011111", + "I=1111011111", + "J=1100010110", + "K=11110100011", + "L=001111101", + "M=100001101", + "N=100001011", + "O=1100101011", + "P=110100000", + "Q=00001011000", + "R=110010100", + "S=10110100", + "T=110101100", + "U=110100010011", + "V=1001000011", + "W=1101000110", + "X=1110001011001", + "Y=1100011110011", + "Z=1100010100110", + "[=00001011010110001111011010000", + "\\=00001011010110001111011010001", + "]=00001011010110001111011010010", + "^=0000101101011000100", + "_=00001011010110001111011010011", + "`=00001011010111", + "a=11111", + "b=11100001", + "c=111001", + "d=1011000", + "e=1010", + "f=0011011", + "g=000011", + "h=10110110", + "i=0001", + "j=110100010000", + "k=110001100", + "l=1111001", + "m=100010", + "n=10111", + "o=0010", + "p=100011", + "q=1110001001", + "r=11011", + "s=00000", + "t=11101", + "u=001110", + "v=1100111", + "w=001100110", + "x=11100011110", + "y=111101101", + "z=0011010", + "{=00001011010110001111011010100", + "|=00001011010110001111011010101", + "}=00001011010110001111011010110", + "~=00001011010110001111011010111", + " =00001011010110001111011011000", + " =000010110101100000", + " =00001011010110001111011011001", + " =00001011010110001111011011010", + " =00001011010110001111011011011", + " =00001011010110001111011011100", + " =00001011010110001111011011101", + " =00001011010110001111011011110", + " =00001011010110001111011011111", + " =11100010000100010", + " =000010110101100001", + " =00001011010110001111011100000", + " =00001011010110001111011100001", + " =00001011010110001111011100010", + " =00001011010110001111011100011", + " =00001011010110001111011100100", + " =00001011010110001111011100101", + " =00001011010110001111011100110", + " =00001011010110001111011100111", + " =00001011010110001110", + " =00001011010110001111011101000", + " =00001011010110001111011101001", + " =00001011010110001111011101010", + " =00001011010110001111011101011", + " =0000101101011000101", + " =00001011010110001111011101100", + " =00001011010110001111011101101", + " =00001011010110001111011101110", + " =00001011010110001111011101111", + " =00001011010110001111011110000", + " =00001011010110001111011110001", + " =00001011010110001111011110010", + " =00001011010110001111011110011", + " =00001011010110001111011110100", + "¡=00001011010110001111011110101", + "¢=00001011010110001111011110110", + "£=00001011010110001111011110111", + "¤=00001011010110001111011111000", + "¥=00001011010110001111011111001", + "¦=00001011010110001111011111010", + "§=00001011010110001111011111011", + "¨=00001011010110001111011111100", + "©=00001011010110001111011111101", + "ª=00001011010110001111011111110", + "«=00001011010110001111011111111", + "¬=0000101101011000111100000000", + "=0000101101011000111100000001", + "®=0000101101011000111100000010", + "¯=0000101101011000111100000011", + "°=0000101101011000111100000100", + "±=0000101101011000111100000101", + "²=0000101101011000111100000110", + "³=0000101101011000111100000111", + "´=0000101101011000111100001000", + "µ=0000101101011000111100001001", + "¶=0000101101011000111100001010", + "·=0000101101011001", + "¸=0000101101011000111100001011", + "¹=0000101101011000111100001100", + "º=0000101101011000111100001101", + "»=0000101101011000111100001110", + "¼=0000101101011000111100001111", + "½=0000101101011000111100010000", + "¾=0000101101011000111100010001", + "¿=0000101101011000111100010010", + "À=0000101101011000111100010011", + "Á=0000101101011000111100010100", + "Â=0000101101011000111100010101", + "Ã=0000101101011000111100010110", + "Ä=0000101101011000111100010111", + "Å=0000101101011000111100011000", + "Æ=000010110101101", + "Ç=0000101101011000111100011001", + "È=0000101101011000111100011010", + "É=0000101101011000111100011011", + "Ê=0000101101011000111100011100", + "Ë=0000101101011000111100011101", + "Ì=0000101101011000111100011110", + "Í=0000101101011000111100011111", + "Î=0000101101011000111100100000", + "Ï=0000101101011000111100100001", + "Ð=0000101101011000111100100010", + "Ñ=0000101101011000111100100011", + "Ò=0000101101011000111100100100", + "Ó=0000101101011000111100100101", + "Ô=0000101101011000111100100110", + "Õ=0000101101011000111100100111", + "Ö=0000101101011000111100101000", + "×=0000101101011000111100101001", + "Ø=0000101101011000111100101010", + "Ù=0000101101011000111100101011", + "Ú=0000101101011000111100101100", + "Û=0000101101011000111100101101", + "Ü=0000101101011000111100101110", + "Ý=0000101101011000111100101111", + "Þ=0000101101011000111100110000", + "ß=0000101101011000111100110001", + "à=0000101101011000110", + "á=0000101101011000111100110010", + "â=0000101101011000111100110011", + "ã=0000101101011000111100110100", + "ä=0000101101011000111100110101", + "å=0000101101011000111100110110", + "æ=0000101101011000111100110111", + "ç=0000101101011000111100111000", + "è=0000101101011000111100111001", + "é=0000101101011000111100111010", + "ê=0000101101011000111100111011", + "ë=0000101101011000111100111100", + "ì=0000101101011000111100111101", + "í=0000101101011000111100111110", + "î=0000101101011000111100111111", + "ï=0000101101011000111101000000", + "ð=0000101101011000111101000001", + "ñ=0000101101011000111101000010", + "ò=0000101101011000111101000011", + "ó=0000101101011000111101000100", + "ô=0000101101011000111101000101", + "õ=0000101101011000111101000110", + "ö=0000101101011000111101000111", + "÷=0000101101011000111101001000", + "ø=0000101101011000111101001001", + "ù=0000101101011000111101001010", + "ú=0000101101011000111101001011", + "û=0000101101011000111101001100", + "ü=0000101101011000111101001101", + "ý=0000101101011000111101001110", + "þ=0000101101011000111101001111", + "ÿ=0000101101011000111101010000", + "(dur=100001111000", + "2001=001111100", + "2002=111000110101", + "Adulti=100001111001", + "Alle=1100110111", + "American=10110101100", + "Argentina=110010101011", + "Attualita'=110001000001", + "Bateman=10010111111", + "Bechis=1100010111011", + "Campionato=1101001111000", + "Carlos=1101000011101", + "Cartoon=11110111011", + "Club=10000110010", + "Commedia=100001100001", + "Con=10110101101", + "D'Alo'=1100100011111", + "Da=1001010111", + "Dal=1111010100011", + "Dalle=10010111110", + "Drammatico=111101111001", + "Durante=1101000111110", + "Echeverria=1100011100110", + "Emmanuelle=1100011100111", + "Enzo=1101000100010", + "Fares=00001011011", + "Figli=1100100011000", + "Film=1101011010", + "Fine=100001001100", + "Fiumi=00001011100", + "Francia=10000110001", + "Giallo=110001001000", + "Giovanni=1100011101000", + "Harron=10011110000", + "ITV=1101000100100", + "Il=0011001110", + "In=1001011011", + "Informazione=11110100001", + "Intrattenimento=1000010000", + "Italia=11100010001", + "Javier=1100011101001", + "Jean=10010101011", + "John=1111011100101", + "Kassovitz=00110000101", + "L'appassionante=00001011101", + "La=1001010110", + "Le=11000100111", + "Ma=1101001110", + "Magazine=100001110010", + "Mammuccari=1100011101010", + "Manhattan=10110010010", + "Marco=1110001011110", + "Mary=10011110110", + "Mathieu=00110000110", + "Michael=1101001111011", + "Momo=110010001011", + "Nadia=00001011110", + "News=110100111110", + "Notiziario=101100101110", + "Orario=1001000100", + "Patrick=10110010110", + "Paul=000010110011", + "Per=11000100110", + "Peter=1100101010101", + "Programmazione=1110001101001", + "Psycho=10011110111", + "Regia=110010000", + "Reno=00110000111", + "Rosa=1100011110101", + "Rubrica=1111011100100", + "Sandrelli=1100100010001", + "Seigner=1100011101011", + "Servizi=001100000110", + "Snow=100100001000", + "Sorvino=1100011110110", + "Stefania=1101011011010", + "Stream=111101000100", + "Street=10110101111", + "Streghe=1100011101100", + "TRAMA:=1100010111010", + "Teo=110001110010", + "USA=1101000101", + "Un=11110111101", + "Una=101100100010", + "Veronesi=1100011101101", + "Vincent=00110001001", + "Wall=11000100001", + "World=001100010110", + "XXX=10000110011", + "ad=1111010110", + "affidare=00110000100", + "ai=1001011110", + "al=0011110", + "alla=11010110111", + "alle=111101110101", + "amici=111000101110", + "ammazzare=10011110001", + "and=1111010101", + "anfiteatro=1100100011001", + "anni=10010101010", + "as=110011010", + "attraverso=1101011011001", + "aver=000010110100", + "bambina=1101000100011", + "banda=1110001011000", + "bello=10110101000", + "brani=1100100010010", + "broker=10011110010", + "business=000010110010", + "casa=101100100011", + "casi=10000111010", + "cassel=00001011111", + "cerca=11100010100", + "che=10010010", + "chilometri=00110001111", + "citta'=110001000101", + "come=110001011100", + "compagnia=1100110110001", + "con=11010010", + "conquista=1101000111111", + "contro=110001000100", + "crede=1110001111110", + "cui=001100111110", + "cultura=100001110001", + "curiosita'=001100010111", + "da=00110010", + "dai=1101000100101", + "dal=11110110000", + "dalla=100101101001", + "decidG266 : dedicato=0000101101011000111101010001", + "degli=110001000000", + "dei=0011000110", + "del=111100010", + "della=1011001010", + "delle=11000111000", + "destra=1100101010001", + "deve=1111010001011", + "di=100000", + "diabolici=1100100011010", + "dice=1100110110000", + "diretta=100100001011", + "distanza=00110000000", + "divide=10110010011", + "divisi=1100011101110", + "dolce=1101001111001", + "domani=1111010100010", + "due=1100011111", + "e'=110001101", + "ed=101101111", + "essere=1110001000000", + "esseri=1110001111101", + "eventiG=0000101101011000111101010010", + "fatti=001100111111", + "feste=10110101001", + "film=10000100011", + "gemelli=1110001000011", + "giorno=11110100000", + "giovane=11100000110", + "giovani=1111011110001", + "gli=100101110", + "grande=1110001011111", + "grandi=1111010001010", + "grigi'=1100100011011", + "ha=1100010101", + "il=11001011", + "imbattere=1100100011100", + "in=1101010", + "incinta=1100101010000", + "informazione=110001001001", + "inizio=1001010100", + "internazionale=100001110111", + "interviste=100100001001", + "la=11001100", + "lavoro=11010000110", + "le=11010111", + "levatrice=1100011101111", + "libro=1100011110100", + "lo=111100011", + "loro=11000101000", + "ma=10011111", + "maggiori=100001110110", + "malcapitati=10110010000", + "maschietto=1100011110000", + "mondo=11100010101", + "musica=111000001111", + "nato=111101110011", + "nel=11110111000", + "nella=1111010100000", + "nello=10000100100", + "news=10010110101", + "non=00110011110", + "nord=1100100011101", + "nuovi=001100000111", + "of=1011010101", + "ogni=100001110011", + "ore=1101000010", + "parte=1101011011011", + "per=00111111", + "piccola=1101001111010", + "piu'=1001111010", + "poliziotti=00110001110", + "porpora=00110000001", + "prima=1110001111100", + "produttore=1100011110111", + "programmazione=1110001101000", + "proprio=1101011011000", + "prossimo=1001000101", + "quattro=1111011000110", + "regime=1100011110001", + "ricco=10110101110", + "ricordi=1100101010100", + "rovine=1110001000001", + "salvare=1110000011100", + "scrittore=1100110110111", + "scrive=1101000011110", + "serie=1111011000111", + "servizi=100001110000", + "settimanale=1100010100111", + "si=11110000", + "singolari=00110001000", + "solo=110010001010", + "sono=11000100011", + "stesso=10000100010", + "storia=11100011011", + "streghe=1100100010000", + "su=1110000010", + "sua=10000100101", + "successo=100101101000", + "sui=110011011001", + "sulle=100100001010", + "suo=10000100111", + "suoi=1101000011100", + "tale=110010101001", + "tempo=111101100010", + "the=11110101001", + "timida=1100100011110", + "torturare=10011110011", + "tra=110100110", + "trasformarlo=1100011110010", + "trecento=00110000010", + "trovato=1101000011111", + "tutto=110011011010", + "ultimi=1100100010011", + "un=11001001", + "una=101101110", + "uno=111000101101", + "uomini=1111011110000", + "vedono=00110001010", + "vengono=100001001101", + "verso=100001100000", + "viaggio=110001010010", + "viene=1111010100001", + "vita=11000101111", + "vuole=1110001111111", + NULL +}; + +static const char *SkyUkDictionary[] = { + " =101010111000110000101001100", + " =101010111000110000101001101", + " =101010111000110000101001110", + " =101010111000110000101001111", + " =101010111000110000101010000", + " =101010111000110000101010001", + " =101010111000110000101010010", + " =101010111000110000101010011", + " =101010111000110000101010100", + " =0001000", + " =1110111", + " =101010111000110000101010101", + " =101010111000110000101010110", + " =101010111000110000101010111", + " =101010111000110000101011000", + " =101010111000110000101011001", + " =101010111000110000101011010", + " =101010111000110000101011011", + " =101010111000110000101011100", + " =101010111000110000101011101", + " =101010111000110000101011110", + " =101010111000110000101011111", + " =101010111000110000101100000", + " =101010111000110000101100001", + " =101010111000110000101100010", + " =101010111000110000101100011", + " =101010111000110000101100100", + " =101010111000110000101100101", + " =101010111000110000101100110", + " =101010111000110000101100111", + " =101010111000110000101101000", + " =101010111000110000101101001", + " =110", + "!=01000011000", + "\"=101010111000110000101101010", + "#=101010111000110000101101011", + "$=1010101110001101", + "%=101010111000110000101101100", + "&=10000011101", + "'=10000010", + "(=11101000101", + ")=1010101100", + "*=100010101110", + "+=101010111000110000101101101", + ",=1011000", + "-=10001011", + ".=1110110", + "/=00010100011110", + "0=111010010", + "1=101100111", + "2=1000101000", + "3=1000001111", + "4=0001010000", + "5=1110101000", + "6=1000101001", + "7=1000100010", + "8=10001010110", + "9=0100001101", + ":=11101000110", + ";=00010100010", + "<=1110100011111", + "==101010111000110000101101110", + ">=1110101001100", + "?=111010100111", + "@=101010111000110001", + "A=11100010", + "B=01000000", + "C=01000010", + "D=111000111", + "E=1110100000", + "F=101010100", + "G=100010000", + "H=101010101", + "I=1110100001", + "J=000101001", + "K=1110100111", + "L=100000110", + "M=10001001", + "N=111010111", + "O=010000010", + "P=00010101", + "Q=1000101010111", + "R=111010110", + "S=0001001", + "T=0001011", + "U=10101011101", + "V=11101010101", + "W=10110010", + "X=1110001101101111", + "Y=10101011110", + "Z=1110101010000", + "[=10101011100011001", + "\\=101010111000110000101101111", + "]=11100011011011100", + "^=101010111000110000101110000", + "_=101010111000110000101110001", + "`=11101010010", + "a=1001", + "b=1110000", + "c=111001", + "d=01001", + "e=1111", + "f=100001", + "g=100011", + "h=10111", + "i=0101", + "j=11100011010", + "k=1000000", + "l=10100", + "m=101011", + "n=0111", + "o=0011", + "p=000111", + "q=10101011011", + "r=0010", + "s=0000", + "t=0110", + "u=101101", + "v=1010100", + "w=000110", + "x=1110101011", + "y=010001", + "z=1011001100", + "{=101010111000110000101110010", + "|=101010111000110000101110011", + "}=101010111000110000101110100", + "~=101010111000110000101110101", + " =101010111000110000101110110", + " =101010111000110000101110111", + " =101010111000110000101111000", + " =101010111000110000101111001", + " =101010111000110000101111010", + " =101010111000110000101111011", + " =101010111000110000101111100", + " =101010111000110000101111101", + " =101010111000110000101111110", + " =101010111000110000101111111", + " =101010111000110000110000000", + " =101010111000110000110000001", + " =101010111000110000110000010", + " =101010111000110000110000011", + " =101010111000110000110000100", + " =101010111000110000110000101", + " =101010111000110000110000110", + " =101010111000110000110000111", + " =101010111000110000110001000", + " =101010111000110000110001001", + " =101010111000110000110001010", + " =101010111000110000110001011", + " =101010111000110000110001100", + " =101010111000110000110001101", + " =101010111000110000110001110", + " =101010111000110000110001111", + " =101010111000110000110010000", + " =101010111000110000110010001", + " =101010111000110000110010010", + " =11100011011011101", + " =101010111000110000110010011", + " =101010111000110000110010100", + " =101010111000110000110010101", + " =101010111000110000110010110", + "¡=101010111000110000110010111", + "¢=101010111000110000110011000", + "£=101010111000110000110011001", + "¤=101010111000110000110011010", + "¥=101010111000110000110011011", + "¦=101010111000110000110011100", + "§=101010111000110000110011101", + "¨=101010111000110000110011110", + "©=101010111000110000110011111", + "ª=101010111000110000110100000", + "«=101010111000110000110100001", + "¬=101010111000110000110100010", + "=101010111000110000110100011", + "®=101010111000110000110100100", + "¯=101010111000110000110100101", + "°=101010111000110000110100110", + "±=101010111000110000110100111", + "²=101010111000110000110101000", + "³=101010111000110000110101001", + "´=101010111000110000110101010", + "µ=101010111000110000110101011", + "¶=101010111000110000110101100", + "·=101010111000110000110101101", + "¸=101010111000110000110101110", + "¹=101010111000110000110101111", + "º=101010111000110000110110000", + "»=101010111000110000110110001", + "¼=101010111000110000110110010", + "½=101010111000110000110110011", + "¾=101010111000110000110110100", + "¿=101010111000110000110110101", + "À=101010111000110000110110110", + "Á=101010111000110000110110111", + "Â=101010111000110000110111000", + "Ã=101010111000110000110111001", + "Ä=101010111000110000110111010", + "Å=101010111000110000110111011", + "Æ=101010111000110000110111100", + "Ç=101010111000110000110111101", + "È=101010111000110000110111110", + "É=101010111000110000110111111", + "Ê=101010111000110000111000000", + "Ë=101010111000110000111000001", + "Ì=101010111000110000111000010", + "Í=101010111000110000111000011", + "Î=101010111000110000111000100", + "Ï=101010111000110000111000101", + "Ð=101010111000110000111000110", + "Ñ=101010111000110000111000111", + "Ò=101010111000110000111001000", + "Ó=101010111000110000111001001", + "Ô=101010111000110000111001010", + "Õ=101010111000110000111001011", + "Ö=101010111000110000111001100", + "×=101010111000110000111001101", + "Ø=101010111000110000111001110", + "Ù=101010111000110000111001111", + "Ú=101010111000110000111010000", + "Û=101010111000110000111010001", + "Ü=101010111000110000111010010", + "Ý=101010111000110000111010011", + "Þ=101010111000110000111010100", + "ß=101010111000110000111010101", + "à=101010111000110000111010110", + "á=101010111000110000111010111", + "â=101010111000110000111011000", + "ã=101010111000110000111011001", + "ä=101010111000110000111011010", + "å=101010111000110000111011011", + "æ=101010111000110000111011100", + "ç=101010111000110000111011101", + "è=101010111000110000111011110", + "é=101010111000110000111011111", + "ê=101010111000110000111100000", + "ë=101010111000110000111100001", + "ì=101010111000110000111100010", + "í=101010111000110000111100011", + "î=101010111000110000111100100", + "ï=101010111000110000111100101", + "ð=101010111000110000111100110", + "ñ=101010111000110000111100111", + "ò=101010111000110000111101000", + "ó=101010111000110000111101001", + "ô=101010111000110000111101010", + "õ=101010111000110000111101011", + "ö=101010111000110000111101100", + "÷=101010111000110000111101101", + "ø=101010111000110000111101110", + "ù=101010111000110000111101111", + "ú=101010111000110000111110000", + "û=101010111000110000111110001", + "ü=101010111000110000111110010", + "ý=101010111000110000111110011", + "þ=101010111000110000111110100", + "ÿ=101010111000110000111110101", + "(Including =10101011111110", + "(New Series)=11101000100010", + "(Part =1110100011101", + "(Repeat)=1110100110", + "(Stereo)=010000111", + "(Stereo) (Teletext)=010000011", + "(Teletext)=1110001100", + "(Widescreen)=100000111001110", + "Action=101010111000111", + "Adventures=10110011011111", + "America=0100001100100", + "Animated=111010100110111", + "Australia=0100001100101", + "Away=11101010100010", + "BBC=10101011111111", + "Baby=11100011011000", + "Best=11101010100011", + "Big=10110011011000", + "Bill=1000101011111", + "Black=1000101010000", + "Blue=1011001101110", + "Breakfast=000101000110", + "Britain=1010101111100", + "British=1110100011100", + "Business=0100001100110", + "Call=1010101111101", + "Cartoon=10101011100000", + "Channel=10101011100001", + "Children=11101010100111", + "Clock=11100011011001", + "Comedy=11101000100011", + "Cook=111010101001010", + "Country=111010100110110", + "Directed by =101010110100", + "Drama=0100001100111", + "East=1000101010001", + "Education=100000111001111", + "English=00010100011111", + "Europe=0001010001110", + "Extra=10110011011001", + "Final=10101011100010", + "Financial=111000110110100", + "For=111000110111", + "French=11101000111101", + "From=1000101010010", + "George=1010101111110", + "Get=1000100011010", + "Girls=10001000110110", + "Golden=10001000110111", + "Golf=111010101001011", + "Good=1010101101010", + "Great=11101000100100", + "Hampshire=111010101001100", + "Headlines=1000101010011", + "Hear=11101010011010", + "Hill=1000001110000", + "Hollywood=111000110110101", + "Home=1000101010100", + "Hour=11101000100101", + "House=1000001110010", + "How=1010101101011", + "ITN=11101010100100", + "Important=111010101001101", + "Including=1000101011110", + "International=11101000100110", + "John=10001000111", + "Last=11101000100111", + "Late=10000011100110", + "Learn=10001010101100", + "Little=10001010101101", + "Live=1110100010000", + "London=11101000111100", + "Look=10110011011110", + "Lunch=111000110110110", + "Man=1000101010101", + "Mark=1000001110001", + "Meridian=101010111001", + "Michael=1011001101101", + "Minutes=101010111000110000111110110", + "More=101010111000110000111110111", + "Morning=101010111000110000111111000", + "Murder=101010111000110000111111001", + "Nation=101010111000110000111111010", + "Neighbours=101010111000110000111111011", + "New=101010111000110000111111100", + "News & Weather=101010111000110000111111101", + "News And Weather=101010111000110000111111110", + "Paul=101010111000110000111111111", + "Plus=10101011100011000000000000", + "Prayer=10101011100011000000000001", + "Present=10101011100011000000000010", + "Presented by=10101011100011000000000011", + "Quiz=10101011100011000000000100", + "Regional=10101011100011000000000101", + "Represent=10101011100011000000000110", + "Resource=10101011100011000000000111", + "Review=10101011100011000000001000", + "Richard=10101011100011000000001001", + "School=10101011100011000000001010", + "Series=10101011100011000000001011", + "Service=10101011100011000000001100", + "Show=10101011100011000000001101", + "Smith=10101011100011000000001110", + "South=10101011100011000000001111", + "Sport=10101011100011000000010000", + "Star=10101011100011000000010001", + "Street=10101011100011000000010010", + "TV=10101011100011000000010011", + "Teaching=10101011100011000000010100", + "The=10101011100011000000010101", + "Today=10101011100011000000010110", + "Tonight=10101011100011000000010111", + "Weather=10101011100011000000011000", + "Western=10101011100011000000011001", + "Westminster=10101011100011000000011010", + "William=10101011100011000000011011", + "With=10101011100011000000011100", + "World=10101011100011000000011101", + "about=10101011100011000000011110", + "action-packed=10101011100011000000011111", + "adventure=10101011100011000000100000", + "afternoon=10101011100011000000100001", + "alert=10101011100011000000100010", + "all-star cast=10101011100011000000100011", + "and=10101011100011000000100100", + "anywhere=10101011100011000000100101", + "audience=10101011100011000000100110", + "based=10101011100011000000100111", + "book=10101011100011000000101000", + "business=10101011100011000000101001", + "but=10101011100011000000101010", + "celebrity=10101011100011000000101011", + "chance=10101011100011000000101100", + "chat=10101011100011000000101101", + "child=10101011100011000000101110", + "classic=10101011100011000000101111", + "consumer=10101011100011000000110000", + "contestants=10101011100011000000110001", + "continues=10101011100011000000110010", + "controversial=10101011100011000000110011", + "dealer=10101011100011000000110100", + "deliver=10101011100011000000110101", + "discuss=10101011100011000000110110", + "document=10101011100011000000110111", + "drama=10101011100011000000111000", + "edition=10101011100011000000111001", + "education=10101011100011000000111010", + "events=10101011100011000000111011", + "every=10101011100011000000111100", + "excellent=10101011100011000000111101", + "eyed=10101011100011000000111110", + "family=10101011100011000000111111", + "famous=10101011100011000001000000", + "featur=10101011100011000001000001", + "film=10101011100011000001000010", + "football=10101011100011000001000011", + "for=10101011100011000001000100", + "from=10101011100011000001000101", + "general knowledge=10101011100011000001000110", + "get=10101011100011000001000111", + "guest=10101011100011000001001000", + "guests=10101011100011000001001001", + "has=10101011100011000001001010", + "have=10101011100011000001001011", + "headline=10101011100011000001001100", + "her=10101011100011000001001101", + "his=10101011100011000001001110", + "home and abroad=10101011100011000001001111", + "host=10101011100011000001010000", + "how=10101011100011000001010001", + "in=10101011100011000001010010", + "including=10101011100011000001010011", + "international=10101011100011000001010100", + "interview=10101011100011000001010101", + "introduce=10101011100011000001010110", + "investigat=10101011100011000001010111", + "invites=10101011100011000001011000", + "issue=10101011100011000001011001", + "knowledge=10101011100011000001011010", + "life=10101011100011000001011011", + "live=10101011100011000001011100", + "look=10101011100011000001011101", + "magazine=10101011100011000001011110", + "meets =10101011100011000001011111", + "morning=10101011100011000001100000", + "morning magazine=10101011100011000001100001", + "music=10101011100011000001100010", + "near=10101011100011000001100011", + "network=10101011100011000001100100", + "new=10101011100011000001100101", + "new series=10101011100011000001100110", + "night=10101011100011000001100111", + "of=10101011100011000001101000", + "on=10101011100011000001101001", + "onight=10101011100011000001101010", + "out=10101011100011000001101011", + "over=10101011100011000001101100", + "part=10101011100011000001101101", + "people=10101011100011000001101110", + "phone=10101011100011000001101111", + "poli=10101011100011000001110000", + "police=10101011100011000001110001", + "political chat show=10101011100011000001110010", + "popular=10101011100011000001110011", + "presented by =10101011100011000001110100", + "programm=10101011100011000001110101", + "quiz=10101011100011000001110110", + "reconstruction=10101011100011000001110111", + "report=10101011100011000001111000", + "review=10101011100011000001111001", + "school=10101011100011000001111010", + "series=10101011100011000001111011", + "short =10101011100011000001111100", + "show=10101011100011000001111101", + "some=10101011100011000001111110", + "starring=10101011100011000001111111", + "stars=10101011100011000010000000", + "stories=10101011100011000010000001", + "story=10101011100011000010000010", + "studio=10101011100011000010000011", + "surprise=10101011100011000010000100", + "teller=10101011100011000010000101", + "that=10101011100011000010000110", + "the=10101011100011000010000111", + "their=10101011100011000010001000", + "them=10101011100011000010001001", + "they=10101011100011000010001010", + "this=10101011100011000010001011", + "through=10101011100011000010001100", + "to=10101011100011000010001101", + "top=10101011100011000010001110", + "trans=10101011100011000010001111", + "under=10101011100011000010010000", + "up=10101011100011000010010001", + "very=10101011100011000010010010", + "video=10101011100011000010010011", + "view=10101011100011000010010100", + "vintage=10101011100011000010010101", + "visit=10101011100011000010010110", + "was=10101011100011000010010111", + "way=10101011100011000010011000", + "week=10101011100011000010011001", + "well=10101011100011000010011010", + "what=10101011100011000010011011", + "when=10101011100011000010011100", + "which=10101011100011000010011101", + "while=10101011100011000010011110", + "who=10101011100011000010011111", + "will=10101011100011000010100000", + "win=10101011100011000010100001", + "with=10101011100011000010100010", + "words=10101011100011000010100011", + "world=10101011100011000010100100", + "written=10101011100011000010100101", + "year=100010001100", + "you=10110011010", + NULL +}; + +static const char *SkyItThemes[] = { + "Non Definito", // 000 00000 + NULL, // 000 00001 + NULL, // 000 00010 + NULL, // 000 00011 + NULL, // 000 00100 + NULL, // 000 00101 + NULL, // 000 00110 + NULL, // 000 00111 + NULL, // 000 01000 + NULL, // 000 01001 + NULL, // 000 01010 + NULL, // 000 01011 + NULL, // 000 01100 + NULL, // 000 01101 + NULL, // 000 01110 + NULL, // 000 01111 + NULL, // 000 10000 + NULL, // 000 10001 + NULL, // 000 10010 + NULL, // 000 10011 + NULL, // 000 10100 + NULL, // 000 10101 + NULL, // 000 10110 + NULL, // 000 10111 + NULL, // 000 11000 + NULL, // 000 11001 + NULL, // 000 11010 + NULL, // 000 11011 + NULL, // 000 11100 + NULL, // 000 11101 + NULL, // 000 11110 + NULL, // 000 11111 + "Intrattenimento", // 001 00000 + "Intrattenimento - Fiction", // 001 00001 + "Intrattenimento - Sit Com", // 001 00010 + "Intrattenimento - Show", // 001 00011 + "Intrattenimento - Telefilm", // 001 00100 + "Intrattenimento - Soap Opera", // 001 00101 + "Intrattenimento - Telenovela", // 001 00110 + "Intrattenimento - Fantascienza", // 001 00111 + "Intrattenimento - Animazione", // 001 01000 + "Intrattenimento - Giallo", // 001 01001 + "Intrattenimento - Drammatico", // 001 01010 + "Intrattenimento - Romantico", // 001 01011 + "Intrattenimento - Miniserie", // 001 01100 + "Intrattenimento - Spettacolo", // 001 01101 + "Intrattenimento - Quiz", // 001 01110 + "Intrattenimento - Talk Show", // 001 01111 + "Intrattenimento - Varietà", // 001 10000 + "Intrattenimento - Festival", // 001 10001 + "Intrattenimento - Teatro", // 001 10010 + "Intrattenimento - Gioco", // 001 10011 + NULL, // 001 10100 + NULL, // 001 10101 + NULL, // 001 10110 + NULL, // 001 10111 + NULL, // 001 11000 + NULL, // 001 11001 + NULL, // 001 11010 + NULL, // 001 11011 + NULL, // 001 11100 + NULL, // 001 11101 + NULL, // 001 11110 + NULL, // 001 11111 + "Sport", // 010 00000 + "Sport - Calcio", // 010 00001 + "Sport - Tennis", // 010 00010 + "Sport - Motori", // 010 00011 + "Sport - Altri", // 010 00100 + "Sport - Baseball", // 010 00101 + "Sport - Ciclismo", // 010 00110 + "Sport - Rugby", // 010 00111 + "Sport - Basket", // 010 01000 + "Sport - Boxe", // 010 01001 + "Sport - Atletica", // 010 01010 + "Sport - Football USA", // 010 01011 + "Sport - Hockey", // 010 01100 + "Sport - Sci", // 010 01101 + "Sport - Equestri", // 010 01110 + "Sport - Golf", // 010 01111 + "Sport - Nuoto", // 010 10000 + "Sport - Wrestling", // 010 10001 + NULL, // 010 10010 + NULL, // 010 10011 + NULL, // 010 10100 + NULL, // 010 10101 + NULL, // 010 10110 + NULL, // 010 10111 + NULL, // 010 11000 + NULL, // 010 11001 + NULL, // 010 11010 + NULL, // 010 11011 + NULL, // 010 11100 + NULL, // 010 11101 + NULL, // 010 11110 + NULL, // 010 11111 + "Film", // 011 00000 + "Film - Drammatico", // 011 00001 + "Film - Commedia", // 011 00010 + "Film - Romantico", // 011 00011 + "Film - Azione", // 011 00100 + "Film - Fantascienza", // 011 00101 + "Film - Western", // 011 00110 + "Film - Comico", // 011 00111 + "Film - Fantastico", // 011 01000 + "Film - Avventura", // 011 01001 + "Film - Poliziesco", // 011 01010 + "Film - Guerra", // 011 01011 + "Film - Horror", // 011 01100 + "Film - Animazione", // 011 01101 + "Film - Thriller", // 011 01110 + "Film - Musicale", // 011 01111 + "Film - Corto", // 011 10000 + "Film - Cortometraggio", // 011 10001 + NULL, // 011 10010 + NULL, // 011 10011 + NULL, // 011 10100 + NULL, // 011 10101 + NULL, // 011 10110 + NULL, // 011 10111 + NULL, // 011 11000 + NULL, // 011 11001 + NULL, // 011 11010 + NULL, // 011 11011 + NULL, // 011 11100 + NULL, // 011 11101 + NULL, // 011 11110 + NULL, // 011 11111 + "Mondo e Tendenze", // 100 00000 + "Mondo e Tendenze - Natura", // 100 00001 + "Mondo e Tendenze - Arte e Cultura", // 100 00010 + "Mondo e Tendenze - Lifestyle", // 100 00011 + "Mondo e Tendenze - Viaggi", // 100 00100 + "Mondo e Tendenze - Documentario", // 100 00101 + "Mondo e Tendenze - Società", // 100 00110 + "Mondo e Tendenze - Scienza", // 100 00111 + "Mondo e Tendenze - Storia", // 100 01000 + "Mondo e Tendenze - Sport", // 100 01001 + "Mondo e Tendenze - Pesca", // 100 01010 + "Mondo e Tendenze - Popoli", // 100 01011 + "Mondo e Tendenze - Cinema", // 100 01100 + "Mondo e Tendenze - Musica", // 100 01101 + "Mondo e Tendenze - Hobby", // 100 01110 + "Mondo e Tendenze - Caccia", // 100 01111 + "Mondo e Tendenze - Reportage", // 100 10000 + "Mondo e Tendenze - Magazine", // 100 10001 + "Mondo e Tendenze - Magazine Cultura", // 100 10010 + "Mondo e Tendenze - Magazine Scienza", // 100 10011 + "Mondo e Tendenze - Politica", // 100 10100 + "Mondo e Tendenze - Magazine Cinema", // 100 10101 + "Mondo e Tendenze - Magazine Sport", // 100 10110 + "Mondo e Tendenze - Attualità", // 100 10111 + "Mondo e Tendenze - Moda", // 100 11000 + "Mondo e Tendenze - Economia", // 100 11001 + "Mondo e Tendenze - Magazine Caccia e Pesca", // 100 11010 + "Mondo e Tendenze - Magazine Viaggi", // 100 11011 + "Mondo e Tendenze - Magazine Natura", // 100 11100 + "Mondo e Tendenze - Magazine Musica", // 100 11101 + "Mondo e Tendenze - Religione", // 100 11110 + "Mondo e Tendenze - Televendita", // 100 11111 + "Informazione", // 101 00000 + "Informazione - Notiziario", // 101 00001 + "Informazione - Sport", // 101 00010 + "Informazione - Economia", // 101 00011 + NULL, // 101 00100 + NULL, // 101 00101 + NULL, // 101 00110 + NULL, // 101 00111 + NULL, // 101 01000 + NULL, // 101 01001 + NULL, // 101 01010 + NULL, // 101 01011 + NULL, // 101 01100 + NULL, // 101 01101 + NULL, // 101 01110 + NULL, // 101 01111 + NULL, // 101 10000 + NULL, // 101 10001 + NULL, // 101 10010 + NULL, // 101 10011 + NULL, // 101 10100 + NULL, // 101 10101 + NULL, // 101 10110 + NULL, // 101 10111 + NULL, // 101 11000 + NULL, // 101 11001 + NULL, // 101 11010 + NULL, // 101 11011 + NULL, // 101 11100 + NULL, // 101 11101 + NULL, // 101 11110 + NULL, // 101 11111 + "Ragazzi e Musica", // 110 00000 + "Ragazzi e Musica - Bambini", // 110 00001 + "Ragazzi e Musica - Ragazzi", // 110 00010 + "Ragazzi e Musica - Cartoni Animati", // 110 00011 + "Ragazzi e Musica - Musica", // 110 00100 + "Ragazzi e Musica - Film Animazione", // 110 00101 + "Ragazzi e Musica - Film", // 110 00110 + "Ragazzi e Musica - Telefilm", // 110 00111 + "Ragazzi e Musica - Magazine", // 110 01000 + NULL, // 110 01001 + NULL, // 110 01010 + NULL, // 110 01011 + NULL, // 110 01100 + NULL, // 110 01101 + NULL, // 110 01110 + NULL, // 110 01111 + NULL, // 110 10000 + NULL, // 110 10001 + NULL, // 110 10010 + NULL, // 110 10011 + "Ragazzi e Musica - Danza", // 110 10100 + NULL, // 110 10101 + NULL, // 110 10110 + NULL, // 110 10111 + NULL, // 110 11000 + NULL, // 110 11001 + NULL, // 110 11010 + NULL, // 110 11011 + NULL, // 110 11100 + NULL, // 110 11101 + NULL, // 110 11110 + NULL, // 110 11111 + "Altri Programmi", // 111 00000 + "Altri Programmi - Educational", // 111 00001 + "Altri Programmi - Regionale", // 111 00010 + "Altri Programmi - Shopping", // 111 00011 + NULL, // 111 00100 + "Altri Programmi - Inizio e Fine Trasmissioni", // 111 00101 + "Altri Programmi - Eventi Speciali", // 111 00110 + "Altri Programmi - Film per Adulti", // 111 00111 + NULL, // 111 01000 + NULL, // 111 01001 + NULL, // 111 01010 + NULL, // 111 01011 + NULL, // 111 01100 + NULL, // 111 01101 + NULL, // 111 01110 + NULL, // 111 01111 + NULL, // 111 10000 + NULL, // 111 10001 + NULL, // 111 10010 + NULL, // 111 10011 + NULL, // 111 10100 + NULL, // 111 10101 + NULL, // 111 10110 + NULL, // 111 10111 + NULL, // 111 11000 + NULL, // 111 11001 + NULL, // 111 11010 + NULL, // 111 11011 + NULL, // 111 11100 + NULL, // 111 11101 + NULL, // 111 11110 + NULL, // 111 11111 +}; + +static const char *SkyUkThemes[] = { + "No Category", // 000 00000 + NULL, // 000 00001 + NULL, // 000 00010 + NULL, // 000 00011 + NULL, // 000 00100 + NULL, // 000 00101 + NULL, // 000 00110 + NULL, // 000 00111 + NULL, // 000 01000 + NULL, // 000 01001 + NULL, // 000 01010 + NULL, // 000 01011 + NULL, // 000 01100 + NULL, // 000 01101 + NULL, // 000 01110 + NULL, // 000 01111 + NULL, // 000 10000 + NULL, // 000 10001 + NULL, // 000 10010 + NULL, // 000 10011 + NULL, // 000 10100 + NULL, // 000 10101 + NULL, // 000 10110 + NULL, // 000 10111 + NULL, // 000 11000 + NULL, // 000 11001 + NULL, // 000 11010 + NULL, // 000 11011 + NULL, // 000 11100 + NULL, // 000 11101 + NULL, // 000 11110 + NULL, // 000 11111 + NULL, // 001 00000 + NULL, // 001 00001 + NULL, // 001 00010 + "Shopping", // 001 00011 + NULL, // 001 00100 + NULL, // 001 00101 + NULL, // 001 00110 + NULL, // 001 00111 + NULL, // 001 01000 + NULL, // 001 01001 + NULL, // 001 01010 + NULL, // 001 01011 + NULL, // 001 01100 + NULL, // 001 01101 + NULL, // 001 01110 + NULL, // 001 01111 + NULL, // 001 10000 + NULL, // 001 10001 + NULL, // 001 10010 + NULL, // 001 10011 + NULL, // 001 10100 + NULL, // 001 10101 + NULL, // 001 10110 + NULL, // 001 10111 + NULL, // 001 11000 + NULL, // 001 11001 + NULL, // 001 11010 + NULL, // 001 11011 + NULL, // 001 11100 + NULL, // 001 11101 + NULL, // 001 11110 + NULL, // 001 11111 + "Children", // 010 00000 + "Children - Cartoons", // 010 00001 + "Children - Comedy", // 010 00010 + "Children - Drama", // 010 00011 + "Children - Educational", // 010 00100 + "Children - Under 5", // 010 00101 + "Children - Factual", // 010 00110 + "Children - Magazine", // 010 00111 + NULL, // 010 01000 + NULL, // 010 01001 + NULL, // 010 01010 + NULL, // 010 01011 + NULL, // 010 01100 + NULL, // 010 01101 + NULL, // 010 01110 + NULL, // 010 01111 + NULL, // 010 10000 + NULL, // 010 10001 + NULL, // 010 10010 + NULL, // 010 10011 + NULL, // 010 10100 + NULL, // 010 10101 + NULL, // 010 10110 + NULL, // 010 10111 + NULL, // 010 11000 + NULL, // 010 11001 + NULL, // 010 11010 + NULL, // 010 11011 + NULL, // 010 11100 + NULL, // 010 11101 + NULL, // 010 11110 + NULL, // 010 11111 + "Entertainment", // 011 00000 + "Entertainment - Action", // 011 00001 + "Entertainment - Comedy", // 011 00010 + "Entertainment - Detective", // 011 00011 + "Entertainment - Drama", // 011 00100 + "Entertainment - Game Show", // 011 00101 + "Entertainment - Sci-FI", // 011 00110 + "Entertainment - Soap", // 011 00111 + "Entertainment - Animation", // 011 01000 + "Entertainment - Chat Show", // 011 01001 + "Entertainment - Cooking", // 011 01010 + "Entertainment - Factual", // 011 01011 + "Entertainment - Fashion", // 011 01100 + "Entertainment - Gardening", // 011 01101 + "Entertainment - Travel", // 011 01110 + "Entertainment - Technology", // 011 01111 + "Entertainment - Arts", // 011 10000 + "Entertainment - Lifestyle", // 011 10001 + "Entertainment - Home", // 011 10010 + "Entertainment - Magazine", // 011 10011 + "Entertainment - Medical", // 011 10100 + "Entertainment - Review", // 011 10101 + "Entertainment - Antiques", // 011 10110 + "Entertainment - Motors", // 011 10111 + "Entertainment - Art&Lit", // 011 11000 + "Entertainment - Ballet", // 011 11001 + "Entertainment - Opera", // 011 11010 + NULL, // 011 11011 + NULL, // 011 11100 + NULL, // 011 11101 + NULL, // 011 11110 + NULL, // 011 11111 + "Music", // 100 00000 + "Music - Classical ", // 100 00001 + "Music - Folk and Country", // 100 00010 + "Music - National Music", // 100 00011 + "Music - Jazz", // 100 00100 + "Music - Opera", // 100 00101 + "Music - Rock&Pop", // 100 00110 + "Music - Alternative Music", // 100 00111 + "Music - Events", // 100 01000 + "Music - Club and Dance", // 100 01001 + "Music - Hip Hop", // 100 01010 + "Music - Soul/R&B", // 100 01011 + "Music - Dance", // 100 01100 + NULL, // 100 01101 + NULL, // 100 01110 + NULL, // 100 01111 + "Music - Features", // 100 10000 + NULL, // 100 10001 + NULL, // 100 10010 + NULL, // 100 10011 + NULL, // 100 10100 + "Music - Lifestyle", // 100 10101 + "Music - News and Weather", // 100 10110 + "Music - Easy Listening", // 100 10111 + "Music - Discussion", // 100 11000 + "Music - Entertainment", // 100 11001 + "Music - Religious", // 100 11010 + NULL, // 100 11011 + NULL, // 100 11100 + NULL, // 100 11101 + NULL, // 100 11110 + NULL, // 100 11111 + "News & Documentaries", // 101 00000 + "News & Documentaries - Business", // 101 00001 + "News & Documentaries - World Cultures", // 101 00010 + "News & Documentaries - Adventure", // 101 00011 + "News & Documentaries - Biography", // 101 00100 + "News & Documentaries - Educational", // 101 00101 + "News & Documentaries - Feature", // 101 00110 + "News & Documentaries - Politics", // 101 00111 + "News & Documentaries - News", // 101 01000 + "News & Documentaries - Nature", // 101 01001 + "News & Documentaries - Religious", // 101 01010 + "News & Documentaries - Science", // 101 01011 + "News & Documentaries - Showbiz", // 101 01100 + "News & Documentaries - War Documentary", // 101 01101 + "News & Documentaries - Historical", // 101 01110 + "News & Documentaries - Ancient", // 101 01111 + "News & Documentaries - Transport", // 101 10000 + "News & Documentaries - Docudrama", // 101 10001 + "News & Documentaries - World Affairs", // 101 10010 + NULL, // 101 10011 + NULL, // 101 10100 + NULL, // 101 10101 + NULL, // 101 10110 + NULL, // 101 10111 + NULL, // 101 11000 + NULL, // 101 11001 + NULL, // 101 11010 + NULL, // 101 11011 + NULL, // 101 11100 + NULL, // 101 11101 + NULL, // 101 11110 + NULL, // 101 11111 + "Movie", // 110 00000 + "Movie - Action", // 110 00001 + "Movie - Animation", // 110 00010 + NULL, // 110 00011 + "Movie - Comedy", // 110 00100 + "Movie - Family", // 110 00101 + "Movie - Drama", // 110 00110 + NULL, // 110 00111 + "Movie - Sci-Fi", // 110 01000 + "Movie - Thriller", // 110 01001 + "Movie - Horror", // 110 01010 + "Movie - Romance", // 110 01011 + "Movie - Musical", // 110 01100 + "Movie - Mystery", // 110 01101 + "Movie - Western", // 110 01110 + "Movie - Factual", // 110 01111 + "Movie - Fantasy", // 110 10000 + "Movie - Erotic", // 110 10001 + "Movie - Adventure", // 110 10010 + NULL, // 110 10011 + NULL, // 110 10100 + NULL, // 110 10101 + NULL, // 110 10110 + NULL, // 110 10111 + NULL, // 110 11000 + NULL, // 110 11001 + NULL, // 110 11010 + NULL, // 110 11011 + NULL, // 110 11100 + NULL, // 110 11101 + NULL, // 110 11110 + NULL, // 110 11111 + "Sports - Other", // 111 00000 + "Sports - American Football", // 111 00001 + "Sports - Athletics", // 111 00010 + "Sports - Baseball", // 111 00011 + "Sports - Basketball", // 111 00100 + "Sports - Boxing", // 111 00101 + "Sports - Cricket", // 111 00110 + "Sports - Fishing", // 111 00111 + "Sports - Football", // 111 01000 + "Sports - Golf", // 111 01001 + "Sports - Ice Hockey", // 111 01010 + "Sports - Motor Sport", // 111 01011 + "Sports - Racing", // 111 01100 + "Sports - Rugby", // 111 01101 + "Sports - Equestrian", // 111 01110 + "Sports - Winter Sports", // 111 01111 + "Sports - Snooker / Pool", // 111 10000 + "Sports - Tennis", // 111 10001 + "Sports - Wrestling", // 111 10010 + "Sports - Darts", // 111 10011 + "Sports - Watersports", // 111 10100 + "Sports - Extreme", // 111 10101 + NULL, // 111 10110 + NULL, // 111 10111 + NULL, // 111 11000 + NULL, // 111 11001 + NULL, // 111 11010 + NULL, // 111 11011 + NULL, // 111 11100 + NULL, // 111 11101 + NULL, // 111 11110 + NULL, // 111 11111 +}; + +static const char *FreesatT1[] = { + "START:00:T:", + "START:010:B:", + "START:1000:C:", + "START:1001:I:", + "START:1101:S:", + "START:01100:L:", + "START:01110:D:", + "START:01111:H:", + "START:10100:R:", + "START:10101:N:", + "START:10110:E:", + "START:11000:F:", + "START:11001:A:", + "START:11100:M:", + "START:11101:P:", + "START:11110:W:", + "START:011011:Q:", + "START:101111:G:", + "START:111110:J:", + "START:0110100:K:", + "START:1011101:U:", + "START:1111110:O:", + "START:01101010:6:", + "START:01101011:.:", + "START:10111000:V:", + "START:11111110:Y:", + "START:101110011:2:", + "START:111111111:X:", + "START:1011100100:Z:", + "START:1111111100:8:", + "START:10111001010:1:", + "START:10111001011:3:", + "START:111111110100:4:", + "START:111111110101:':", + "START:111111110111: :", + "START:11111111011000:5:", + "START:11111111011011:0:", + "START:111111110110011:m:", + "START:1111111101100100:c:", + "START:1111111101101000:9:", + "START:1111111101101010:a:", + "START:1111111101101011:d:", + "START:11111111011001010:s:", + "START:11111111011001011:p:", + "START:11111111011010010:(:", + "START:111111110110100110:t:", + "START:1111111101101001110:7:", + "START:11111111011010011110:ESCAPE:", + "START:11111111011010011111:l:", + "ESCAPE:0:ESCAPE:", + "ESCAPE:1:ESCAPE:", + "STOP:0:ESCAPE:", + "STOP:1:ESCAPE:", + "0x03:0:ESCAPE:", + "0x03:1:ESCAPE:", + "0x04:0:ESCAPE:", + "0x04:1:ESCAPE:", + "0x05:0:ESCAPE:", + "0x05:1:ESCAPE:", + "0x06:0:ESCAPE:", + "0x06:1:ESCAPE:", + "0x07:0:ESCAPE:", + "0x07:1:ESCAPE:", + "0x08:0:ESCAPE:", + "0x08:1:ESCAPE:", + "0x09:0:ESCAPE:", + "0x09:1:ESCAPE:", + "0x0a:0:ESCAPE:", + "0x0a:1:ESCAPE:", + "0x0b:0:ESCAPE:", + "0x0b:1:ESCAPE:", + "0x0c:0:ESCAPE:", + "0x0c:1:ESCAPE:", + "0x0d:0:ESCAPE:", + "0x0d:1:ESCAPE:", + "0x0e:0:ESCAPE:", + "0x0e:1:ESCAPE:", + "0x0f:0:ESCAPE:", + "0x0f:1:ESCAPE:", + "0x10:0:ESCAPE:", + "0x10:1:ESCAPE:", + "0x11:0:ESCAPE:", + "0x11:1:ESCAPE:", + "0x12:0:ESCAPE:", + "0x12:1:ESCAPE:", + "0x13:0:ESCAPE:", + "0x13:1:ESCAPE:", + "0x14:0:ESCAPE:", + "0x14:1:ESCAPE:", + "0x15:0:ESCAPE:", + "0x15:1:ESCAPE:", + "0x16:0:ESCAPE:", + "0x16:1:ESCAPE:", + "0x17:0:ESCAPE:", + "0x17:1:ESCAPE:", + "0x18:0:ESCAPE:", + "0x18:1:ESCAPE:", + "0x19:0:ESCAPE:", + "0x19:1:ESCAPE:", + "0x1a:0:ESCAPE:", + "0x1a:1:ESCAPE:", + "0x1b:0:ESCAPE:", + "0x1b:1:ESCAPE:", + "0x1c:0:ESCAPE:", + "0x1c:1:ESCAPE:", + "0x1d:0:ESCAPE:", + "0x1d:1:ESCAPE:", + "0x1e:0:ESCAPE:", + "0x1e:1:ESCAPE:", + "0x1f:0:ESCAPE:", + "0x1f:1:ESCAPE:", + " :0000:W:", + " :0011:M:", + " :0100:C:", + " :0101:B:", + " :0111:P:", + " :1001:T:", + " :1100:N:", + " :1111:S:", + " :00011:I:", + " :00100:G:", + " :01100:H:", + " :01101:D:", + " :10000:o:", + " :10001:A:", + " :10100:t:", + " :10110:a:", + " :10111:F:", + " :11010:L:", + " :11011:R:", + " :001011:U:", + " :101011:O:", + " :111001:J:", + " :111010:E:", + " :0001000:f:", + " :0001001:Q:", + " :0001011:V:", + " :0010100:STOP:", + " :0010101:w:", + " :1110000:2:", + " :1110001:K:", + " :1110110:Y:", + " :1110111:i:", + " :00010100:-:", + " :10101001:1:", + " :101010000:&:", + " :101010101:X:", + " :0001010101:r:", + " :1010100010:5:", + " :1010100011:Z:", + " :1010101001:9:", + " :1010101101:s:", + " :1010101110:4:", + " :1010101111:3:", + " :00010101000:7:", + " :00010101100:b:", + " :00010101110:y:", + " :10101010000:':", + " :10101011000:6:", + " :000101011010:v:", + " :000101011011:d:", + " :000101011110:(:", + " :101010100010: :", + " :101010100011:0:", + " :101010110010:n:", + " :101010110011:8:", + " :0001010100110:g:", + " :0001010111110:u:", + " :00010101001000:+:", + " :00010101001001:.:", + " :00010101001010:ESCAPE:", + " :00010101001011:l:", + " :00010101001111:m:", + " :00010101111110:p:", + " :000101010011100:\\:", + " :000101010011101:/:", + " :000101011111111:e:", + " :0001010111111101:\":", + " :00010101111111001:c:", + " :000101011111110000:k:", + " :000101011111110001:h:", + "!:1:STOP:", + "!:01: :", + "!:001:.:", + "!:0001:!:", + "!:00001:\":", + "!:000000:ESCAPE:", + "!:000001:0x3a:", + "\":0: :", + "\":10:ESCAPE:", + "\":11:I:", + "#:0:ESCAPE:", + "#:1:ESCAPE:", + "$:0:ESCAPE:", + "$:1:ESCAPE:", + "%:1: :", + "%:00:ESCAPE:", + "%:01:STOP:", + "&:1: :", + "&:01:B:", + "&:000:ESCAPE:", + "&:001:.:", + "':1:s:", + "':000:m:", + "':010:C:", + "':0010:t:", + "':0011: :", + "':01100:d:", + "':01110:v:", + "':011011:r:", + "':011111:A:", + "':0110101:n:", + "':01101000:G:", + "':01111001:l:", + "':011010011:D:", + "':011110000:B:", + "':011110001:e:", + "':011110101:i:", + "':011110110:6:", + "':0110100100:L:", + "':0111101001:STOP:", + "':0111101111:w:", + "':01101001010:O:", + "':01111010000:S:", + "':01111010001:E:", + "':01111011101:N:", + "':011110111001:R:", + "':0110100101100:a:", + "':0110100101101:M:", + "':0110100101110:K:", + "':0110100101111:F:", + "':0111101110000:0:", + "':01111011100010:ESCAPE:", + "':01111011100011:c:", + "(:1:c:", + "(:000:1:", + "(:0010:M:", + "(:0011:U:", + "(:0100:R:", + "(:0101:D:", + "(:0110:H:", + "(:01110:S:", + "(:011110:F:", + "(:0111110:G:", + "(:01111110:ESCAPE:", + "(:01111111:Y:", + "):1:STOP:", + "):00:ESCAPE:", + "):01: :", + "*:0:*:", + "*:101: :", + "*:1000:d:", + "*:1100:m:", + "*:1101:t:", + "*:1111:s:", + "*:10010:e:", + "*:11100:g:", + "*:11101:k:", + "*:100110:ESCAPE:", + "*:100111:y:", + "+:0:ESCAPE:", + "+:1: :", + ",:1: :", + ",:01:0:", + ",:000:ESCAPE:", + ",:001:.:", + "-:11: :", + "-:011:S:", + "-:100:G:", + "-:101:O:", + "-:0011:T:", + "-:0100:U:", + "-:00000:E:", + "-:00010:D:", + "-:000010:m:", + "-:000110:0:", + "-:000111:I:", + "-:001010:6:", + "-:010100:F:", + "-:010101:o:", + "-:0000110:L:", + "-:0000111:C:", + "-:0010001:A:", + "-:0010010:t:", + "-:0010011:Y:", + "-:0010111:2:", + "-:0101100:B:", + "-:0101101:.:", + "-:00100000:P:", + "-:00100001:Z:", + "-:01011100:8:", + "-:01011101:i:", + "-:01011110:d:", + "-:01011111:H:", + "-:001011001:N:", + "-:001011011:R:", + "-:0010110000:1:", + "-:0010110001:W:", + "-:00101101001:c:", + "-:00101101010:a:", + "-:00101101011:M:", + "-:001011010000:ESCAPE:", + "-:001011010001:Q:", + ".:1:.:", + ".:01:STOP:", + ".:0010: :", + ".:00000:I:", + ".:00001:T:", + ".:00010:C:", + ".:00110:p:", + ".:00111:0:", + ".:000111:H:", + ".:00011010:W:", + ".:000110001:S:", + ".:000110110:3:", + ".:000110111:B:", + ".:0001100000:1:", + ".:0001100001:M:", + ".:0001100110:c:", + ".:00011001000:t:", + ".:00011001001:R:", + ".:00011001010:F:", + ".:00011001110:E:", + ".:00011001111:A:", + ".:0001100101100:ESCAPE:", + ".:0001100101101:l:", + ".:0001100101110:d:", + ".:0001100101111:U:", + "/:00:1:", + "/:10:7:", + "/:010:4:", + "/:011:2:", + "/:110:3:", + "/:1110:5:", + "/:111100:6:", + "/:111110:C:", + "/:1111010:9:", + "/:1111011: :", + "/:1111110:8:", + "/:11111111:U:", + "/:1111111000:G:", + "/:1111111010:0:", + "/:11111110010:ESCAPE:", + "/:11111110011:W:", + "/:11111110110:V:", + "/:11111110111:S:", + "0:00:6:", + "0:01: :", + "0:11:0:", + "0:1001:p:", + "0:1010:STOP:", + "0:10000:1:", + "0:10001:a:", + "0:10111:7:", + "0:1011000:-:", + "0:1011010:s:", + "0:10110011:4:", + "0:10110110:t:", + "0:101101111:%:", + "0:1011001000:8:", + "0:1011001001:0x3a:", + "0:1011001010:5:", + "0:1011001011:2:", + "0:1011011100:/:", + "0:10110111011:U:", + "0:101101110101:,:", + "0:1011011101000:.:", + "0:10110111010010:ESCAPE:", + "0:10110111010011:l:", + "1:01:STOP:", + "1:000:.:", + "1:101:0:", + "1:111:1:", + "1:0010:2:", + "1:0011: :", + "1:1101:/:", + "1:10010:8:", + "1:11000:3:", + "1:100000:5:", + "1:100001:s:", + "1:100010:6:", + "1:100011:0x3a:", + "1:100110:':", + "1:110010:X:", + "1:110011:9:", + "1:1001111:4:", + "1:10011101:-:", + "1:100111001:7:", + "1:1001110000:):", + "1:10011100010:ESCAPE:", + "1:10011100011:,:", + "2:0:0:", + "2:11:4:", + "2:101:STOP:", + "2:1001: :", + "2:10000:0x3a:", + "2:1000101:5:", + "2:1000111:/:", + "2:10001000:.:", + "2:10001001:1:", + "2:10001100:W:", + "2:100011011:7:", + "2:10001101001:3:", + "2:10001101011:Z:", + "2:100011010000:n:", + "2:100011010001:6:", + "2:100011010101:':", + "2:1000110101000:ESCAPE:", + "2:1000110101001:s:", + "3:0: :", + "3:10:STOP:", + "3:1100:r:", + "3:1101:/:", + "3:1111:B:", + "3:11100:0:", + "3:1110100:0x3a:", + "3:1110110:-:", + "3:11101010:1:", + "3:11101011:8:", + "3:11101111:4:", + "3:1110111000:6:", + "3:1110111011:9:", + "3:11101110011:t:", + "3:11101110100:3:", + "3:111011100100:ESCAPE:", + "3:111011100101:e:", + "3:111011101010:7:", + "3:111011101011:5:", + "4:0:STOP:", + "4:11: :", + "4:1001:0x3a:", + "4:1011:/:", + "4:10001:8:", + "4:10101:.:", + "4:100000:9:", + "4:101000:0:", + "4:1010010:M:", + "4:10000101:I:", + "4:10000110:):", + "4:10100110:R:", + "4:10100111:-:", + "4:100001000:W:", + "4:100001110:P:", + "4:100001111:5:", + "4:1000010011:2:", + "4:10000100100:ESCAPE:", + "4:10000100101:':", + "5:0:STOP:", + "5:11: :", + "5:101:0:", + "5:1001:/:", + "5:100001:-:", + "5:100011:0x3a:", + "5:1000001:t:", + "5:1000100:3:", + "5:1000101:1:", + "5:10000000:ESCAPE:", + "5:10000001:a:", + "6:00:STOP:", + "6:01: :", + "6:10:0:", + "6:111:0x3a:", + "6:11001:.:", + "6:11011:i:", + "6:110000:-:", + "6:110101:a:", + "6:1100011:4:", + "6:1101000:8:", + "6:1101001:/:", + "6:11000100:6:", + "6:110001011:9:", + "6:1100010100:3:", + "6:11000101010:ESCAPE:", + "6:11000101011:t:", + "7:1:STOP:", + "7:01: :", + "7:000:0:", + "7:0011:.:", + "7:00101:/:", + "7:0010000:1:", + "7:0010010:5:", + "7:00100010:ESCAPE:", + "7:00100011:4:", + "7:00100110:3:", + "7:00100111:2:", + "8:1: :", + "8:00:0:", + "8:010:0x3a:", + "8:01101:STOP:", + "8:011000:t:", + "8:011001:p:", + "8:011101:8:", + "8:011110:.:", + "8:011111:6:", + "8:0111000:5:", + "8:01110010:9:", + "8:011100110:M:", + "8:0111001110:F:", + "8:01110011110:ESCAPE:", + "8:01110011111:c:", + "9:0:1:", + "9:11:STOP:", + "9:1000:9:", + "9:1010:.:", + "9:10011:0:", + "9:100100: :", + "9:100101:8:", + "9:101100:7:", + "9:101101:/:", + "9:101110:6:", + "9:1011111:0x3a:", + "9:10111101:4:", + "9:101111000:ESCAPE:", + "9:101111001:3:", + "0x3a:1: :", + "0x3a:00:0:", + "0x3a:011:.:", + "0x3a:0100:2:", + "0x3a:01010:1:", + "0x3a:010111:3:", + "0x3a:0101101:C:", + "0x3a:01011000:ESCAPE:", + "0x3a:01011001:T:", + ";:1: :", + ";:00:ESCAPE:", + ";:01:.:", + "<:0:ESCAPE:", + "<:1:ESCAPE:", + "=:0:ESCAPE:", + "=:1:ESCAPE:", + ">:0:ESCAPE:", + ">:1:ESCAPE:", + "?:1:STOP:", + "?:01: :", + "?:001:0x3a:", + "?:0000:ESCAPE:", + "?:0001:.:", + "@:0:ESCAPE:", + "@:1:H:", + "A:001:r:", + "A:010: :", + "A:100:l:", + "A:110:n:", + "A:0000:m:", + "A:0111:g:", + "A:1111:d:", + "A:00010:w:", + "A:01100:T:", + "A:01101:c:", + "A:10101:t:", + "A:10110:f:", + "A:10111:i:", + "A:11100:s:", + "A:000110:u:", + "A:000111:STOP:", + "A:101001:R:", + "A:111010:b:", + "A:1010001:v:", + "A:1110110:p:", + "A:10100000:S:", + "A:11101110:M:", + "A:101000011:P:", + "A:111011111:.:", + "A:10100001000:e:", + "A:10100001001:B:", + "A:10100001010:1:", + "A:11101111011:-:", + "A:101000010110:k:", + "A:101000010111:h:", + "A:111011110000:a:", + "A:111011110100:y:", + "A:111011110101:*:", + "A:1110111100010:x:", + "A:1110111100011:':", + "A:1110111100100:N:", + "A:1110111100110:2:", + "A:11101111001010:0x3a:", + "A:11101111001111:z:", + "A:111011110010110:L:", + "A:111011110010111:F:", + "A:111011110011100:D:", + "A:1110111100111010:ESCAPE:", + "A:1110111100111011:q:", + "B:00:C:", + "B:01:B:", + "B:101:r:", + "B:1001:i:", + "B:1100:o:", + "B:1101:u:", + "B:1110:a:", + "B:1111:e:", + "B:10001:l:", + "B:1000000:STOP:", + "B:1000010:y:", + "B:10000010:O:", + "B:10000110:3:", + "B:100000111:A:", + "B:100001110:S:", + "B:1000001101:0x3a:", + "B:10000011000:.:", + "B:10000011001:w:", + "B:10000111101:h:", + "B:10000111110:*:", + "B:10000111111: :", + "B:100001111001:R:", + "B:1000011110000:':", + "B:10000111100011:T:", + "B:100001111000100:ESCAPE:", + "B:100001111000101:4:", + "C:00:o:", + "C:01: :", + "C:100:l:", + "C:110:h:", + "C:1010:r:", + "C:1110:a:", + "C:10110:i:", + "C:10111:e:", + "C:111100:u:", + "C:111101:B:", + "C:1111100:y:", + "C:1111110:!:", + "C:11111011:.:", + "C:111110100:w:", + "C:111111100:STOP:", + "C:111111110:S:", + "C:111111111:T:", + "C:1111101011:2:", + "C:1111111011:I:", + "C:11111010100:4:", + "C:11111010101:*:", + "C:11111110101:D:", + "C:111111101000:U:", + "C:1111111010010:':", + "C:11111110100110:n:", + "C:111111101001110:z:", + "C:11111110100111100:O:", + "C:11111110100111101:E:", + "C:11111110100111110:A:", + "C:111111101001111110:ESCAPE:", + "C:111111101001111111:s:", + "D:01:o:", + "D:10:a:", + "D:000:r:", + "D:110:e:", + "D:111:i:", + "D:00100:t:", + "D:00111:u:", + "D:001011: :", + "D:0010101:J:", + "D:0011000:y:", + "D:0011010:STOP:", + "D:0011011:I:", + "D:00110011:0x3a:", + "D:001010001:*:", + "D:001010010:-:", + "D:001010011:&:", + "D:001100100:':", + "D:0010100000:A:", + "D:0010100001:h:", + "D:00110010101:N:", + "D:00110010110:V:", + "D:001100101110:D:", + "D:001100101111:w:", + "D:0011001010000:O:", + "D:0011001010001:E:", + "D:0011001010011:d:", + "D:00110010100100:ESCAPE:", + "D:00110010100101:T:", + "E:00:m:", + "E:011:v:", + "E:101:n:", + "E:111:a:", + "E:0100:E:", + "E:1000:STOP:", + "E:1101:x:", + "E:10011:d:", + "E:11001:l:", + "E:010100:4:", + "E:010101:y:", + "E:010110:u:", + "E:100100:r:", + "E:110000:i:", + "E:0101111:s:", + "E:1001010:F:", + "E:1100010:X:", + "E:10010110:R:", + "E:11000111: :", + "E:010111010:g:", + "E:100101111:0x3a:", + "E:110001100:T:", + "E:110001101:':", + "E:0101110001:c:", + "E:0101110011:q:", + "E:0101110110:e:", + "E:0101110111:C:", + "E:1001011100:p:", + "E:01011100000:-:", + "E:01011100101:Z:", + "E:10010111011:t:", + "E:010111000010:S:", + "E:010111000011:.:", + "E:100101110101:W:", + "E:0101110010000:!:", + "E:1001011101000:o:", + "E:01011100100010:f:", + "E:01011100100011:U:", + "E:01011100100100:N:", + "E:01011100100101:M:", + "E:01011100100110:L:", + "E:01011100100111:A:", + "E:10010111010011:D:", + "E:100101110100100:ESCAPE:", + "E:100101110100101:w:", + "F:00:i:", + "F:10:a:", + "F:011:r:", + "F:110:u:", + "F:111:o:", + "F:0100:e:", + "F:01011:l:", + "F:0101000:A:", + "F:0101010:O:", + "F:01010010: :", + "F:010100110:h:", + "F:010100111:t:", + "F:010101101:f:", + "F:010101111:L:", + "F:0101011001:STOP:", + "F:01010111000:j:", + "F:01010111001:I:", + "F:01010111010:.:", + "F:01010111011:1:", + "F:010101100000:M:", + "F:010101100010:*:", + "F:010101100011:K:", + "F:0101011000010:y:", + "F:01010110000111:H:", + "F:010101100001100:ESCAPE:", + "F:010101100001101:!:", + "G:10:r:", + "G:001:M:", + "G:010:a:", + "G:011:o:", + "G:110:i:", + "G:111:e:", + "G:00001:u:", + "G:00010:X:", + "G:000001:h:", + "G:000111:l:", + "G:0000001:y:", + "G:0001100:w:", + "G:00000000:0x3a:", + "G:00011011:C:", + "G:000000011:STOP:", + "G:000110100:-:", + "G:0001101010:P:", + "G:0001101011: :", + "G:00000001000:':", + "G:00000001010:A:", + "G:000000010010:U:", + "G:000000010110:T:", + "G:000000010111:4:", + "G:0000000100110:ESCAPE:", + "G:0000000100111:Y:", + "H:0:o:", + "H:100:a:", + "H:101:i:", + "H:110:e:", + "H:1110:u:", + "H:11110:R:", + "H:111110:A:", + "H:1111110:.:", + "H:111111101:y:", + "H:111111110:S:", + "H:1111111110:E:", + "H:1111111111:r:", + "H:11111110000:STOP:", + "H:11111110010:L:", + "H:11111110011:M:", + "H:111111100011:w:", + "H:1111111000101:D:", + "H:11111110001000:ESCAPE:", + "H:11111110001001:I:", + "I:0:T:", + "I:100:s:", + "I:101:n:", + "I:1101:t:", + "I:11001: :", + "I:11101:':", + "I:11111:r:", + "I:110000:I:", + "I:110001:STOP:", + "I:111001:m:", + "I:1110000:d:", + "I:1110001:N:", + "I:1111001:z:", + "I:1111010:.:", + "I:11110000:a:", + "I:11110001:Y:", + "I:111101100:S:", + "I:111101110:c:", + "I:11110110101:D:", + "I:11110110110:f:", + "I:11110111100:l:", + "I:11110111111:y:", + "I:111101101000:V:", + "I:111101101110:o:", + "I:111101111011:F:", + "I:1111011010010:,:", + "I:1111011010011:A:", + "I:1111011011110:O:", + "I:1111011110101:g:", + "I:1111011111000:C:", + "I:1111011111001:0x3a:", + "I:1111011111011:v:", + "I:11110110111110:p:", + "I:11110110111111:E:", + "I:11110111101000:B:", + "I:11110111110100:k:", + "I:11110111110101:b:", + "I:1111011110100100:ESCAPE:", + "I:1111011110100101:R:", + "I:1111011110100110:L:", + "I:1111011110100111:G:", + "J:00:a:", + "J:01:u:", + "J:11:e:", + "J:101:o:", + "J:1001:i:", + "J:10000: :", + "J:100010:K:", + "J:1000111:STOP:", + "J:100011001:s:", + "J:100011010:F:", + "J:1000110000:V:", + "J:1000110001:':", + "J:1000110111:f:", + "J:10001101101:G:", + "J:100011011000:ESCAPE:", + "J:100011011001:D:", + "K:01:i:", + "K:11:y:", + "K:001:e:", + "K:101: :", + "K:0000:a:", + "K:1000:o:", + "K:00010:STOP:", + "K:00011:r:", + "K:100101:t:", + "K:100110:n:", + "K:100111:S:", + "K:10010011:G:", + "K:100100000:-:", + "K:100100011:O:", + "K:100100100:h:", + "K:100100101:w:", + "K:1001000010:1:", + "K:1001000011:':", + "K:10010001011:u:", + "K:100100010000:T:", + "K:100100010001:N:", + "K:100100010010:0x3a:", + "K:100100010011:.:", + "K:100100010100:,:", + "K:1001000101010:ESCAPE:", + "K:1001000101011:l:", + "L:00:a:", + "L:10:o:", + "L:11:i:", + "L:010:e:", + "L:0111:u:", + "L:01101:K:", + "L:0110000:l:", + "L:0110010:A:", + "L:0110011: :", + "L:01100011:y:", + "L:0110001000:L:", + "L:0110001001:I:", + "L:01100010100:C:", + "L:01100010101:.:", + "L:01100010111:STOP:", + "L:011000101101:':", + "L:0110001011000:E:", + "L:01100010110010:ESCAPE:", + "L:01100010110011:Y:", + "M:01:a:", + "M:10:o:", + "M:000:e:", + "M:111:i:", + "M:0010:T:", + "M:1100:y:", + "M:1101:u:", + "M:00110:STOP:", + "M:001111:c:", + "M:00111001:r:", + "M:00111010:E:", + "M:001110111:F:", + "M:0011100001:Z:", + "M:0011100011: :", + "M:0011101100:1:", + "M:0011101101:I:", + "M:00111000001:h:", + "M:00111000100:C:", + "M:001110000001:Q:", + "M:001110001010:K:", + "M:0011100010110:P:", + "M:00111000000000:0x3a:", + "M:00111000000001:.:", + "M:00111000000010:':", + "M:00111000101110:M:", + "M:001110000000110:ESCAPE:", + "M:001110000000111:w:", + "M:001110001011110:S:", + "M:001110001011111:R:", + "N:1:e:", + "N:00:o:", + "N:011:i:", + "N:0101:a:", + "N:01001:u:", + "N:010000:C:", + "N:01000100:E:", + "N:01000110:F:", + "N:010001110:B:", + "N:010001111:H:", + "N:0100010110:Y:", + "N:01000101000:G:", + "N:01000101001:':", + "N:01000101011:I:", + "N:01000101110:A:", + "N:010001010100:M:", + "N:010001011110: :", + "N:010001011111:STOP:", + "N:0100010101010:T:", + "N:01000101010110:.:", + "N:010001010101110:ESCAPE:", + "N:010001010101111:Z:", + "O:000:':", + "O:010:f:", + "O:110:u:", + "O:111:n:", + "O:0010:M:", + "O:0011:l:", + "O:1001:m:", + "O:01101:r:", + "O:01110:d:", + "O:10000:p:", + "O:10100:h:", + "O:10110:STOP:", + "O:011001:S:", + "O:011110:z:", + "O:011111:b:", + "O:100011:v:", + "O:101010:w:", + "O:101011:U:", + "O:1011100:T:", + "O:1011101:O:", + "O:1011110:K:", + "O:01100001:C:", + "O:01100010:x:", + "O:01100011:.:", + "O:10001001:t:", + "O:10001011: :", + "O:10111110:s:", + "O:10111111:N:", + "O:011000001:g:", + "O:100010000:-:", + "O:100010101:a:", + "O:1000100010:i:", + "O:1000100011:e:", + "O:1000101001:o:", + "O:01100000000:A:", + "O:01100000001:j:", + "O:01100000010:c:", + "O:10001010000:2:", + "O:011000000111:R:", + "O:100010100010:P:", + "O:100010100011:0x3a:", + "O:0110000001100:E:", + "O:01100000011010:ESCAPE:", + "O:01100000011011:L:", + "P:01:r:", + "P:10:l:", + "P:000:e:", + "P:001:a:", + "P:111:o:", + "P:1101:i:", + "P:110000:D:", + "P:110001:u:", + "P:110011:h:", + "P:11001000: :", + "P:11001010:2:", + "P:110010010:H:", + "P:110010011:M:", + "P:110010110:S:", + "P:11001011100:0x3a:", + "P:11001011101:*:", + "P:110010111101:s:", + "P:1100101111001:I:", + "P:1100101111100:STOP:", + "P:1100101111101:G:", + "P:1100101111110:':", + "P:11001011111110:y:", + "P:110010111100000:Y:", + "P:110010111100001:L:", + "P:110010111100010:C:", + "P:110010111100011:ESCAPE:", + "P:110010111111110:O:", + "P:110010111111111:.:", + "Q:1:u:", + "Q:000:I:", + "Q:001:STOP:", + "Q:010:V:", + "Q:0111: :", + "Q:01101:C:", + "Q:011000:ESCAPE:", + "Q:011001:':", + "R:00:a:", + "R:01:o:", + "R:11:e:", + "R:100:i:", + "R:1011:u:", + "R:10101:E:", + "R:101000:D:", + "R:1010011:STOP:", + "R:10100101:h:", + "R:1010010000:I:", + "R:1010010010:y:", + "R:1010010011:n:", + "R:101001000110: :", + "R:1010010001000:':", + "R:1010010001011:S:", + "R:1010010001110:N:", + "R:10100100010010:B:", + "R:10100100010011:.:", + "R:10100100010100:&:", + "R:10100100011110:T:", + "R:10100100011111:1:", + "R:101001000101010:ESCAPE:", + "R:101001000101011:C:", + "S:001:o:", + "S:010:p:", + "S:011:u:", + "S:110:h:", + "S:111:t:", + "S:0001:a:", + "S:1001:e:", + "S:1011:c:", + "S:00000:n:", + "S:10001:i:", + "S:10101:k:", + "S:000011:w:", + "S:101000:m:", + "S:0000101:A:", + "S:1000010:l:", + "S:1010010:q:", + "S:1010011:M:", + "S:00001000:2:", + "S:00001001:P:", + "S:10000000:O:", + "S:10000010:I:", + "S:10000011: :", + "S:10000111:STOP:", + "S:100000010:y:", + "S:100001100:E:", + "S:1000000111:?:", + "S:1000011011:H:", + "S:10000001100:B:", + "S:10000110100:g:", + "S:100000011011:r:", + "S:100001101010:*:", + "S:1000011010110:3:", + "S:1000011010111:.:", + "S:10000001101000:5:", + "S:10000001101010:0x3a:", + "S:10000001101011:1:", + "S:100000011010010:C:", + "S:1000000110100110:ESCAPE:", + "S:1000000110100111:Y:", + "T:0:h:", + "T:101:o:", + "T:111:V:", + "T:1000:e:", + "T:1001:r:", + "T:11000:a:", + "T:11010:w:", + "T:110011:i:", + "T:1101101:O:", + "T:1101111:H:", + "T:11001001:y:", + "T:11001010:M:", + "T:11011000:.:", + "T:11011100:u:", + "T:11011101:W:", + "T:110010001:P:", + "T:110010110:0x3a:", + "T:110010111:4:", + "T:110110011:I:", + "T:1101100100: :", + "T:1101100101:STOP:", + "T:11001000010:X:", + "T:11001000011:s:", + "T:110010000000:T:", + "T:110010000001:S:", + "T:110010000010:B:", + "T:1100100000110:U:", + "T:11001000001110:A:", + "T:1100100000111100:C:", + "T:1100100000111101:*:", + "T:1100100000111111:N:", + "T:11001000001111100:ESCAPE:", + "T:11001000001111101:Y:", + "U:0:n:", + "U:10:p:", + "U:1101:K:", + "U:1111:l:", + "U:11000:R:", + "U:11100:S:", + "U:110011:E:", + "U:111011:s:", + "U:1100101:g:", + "U:1110101:T:", + "U:11001001: :", + "U:110010000:-:", + "U:110010001:r:", + "U:111010000:2:", + "U:111010001:m:", + "U:111010011:STOP:", + "U:1110100100:.:", + "U:11101001010:c:", + "U:111010010110:k:", + "U:11101001011100:ESCAPE:", + "U:11101001011101:z:", + "U:11101001011110:t:", + "U:11101001011111:B:", + "V:1: :", + "V:000:0x3a:", + "V:011:i:", + "V:0010:e:", + "V:0011:a:", + "V:0100:3:", + "V:010101:C:", + "V:010111:STOP:", + "V:0101000:':", + "V:0101001:4:", + "V:0101101:o:", + "V:01011001:I:", + "V:0101100000:s:", + "V:0101100001:D:", + "V:0101100010:.:", + "V:01011000110:8:", + "V:0101100011101:u:", + "V:0101100011110:r:", + "V:0101100011111:B:", + "V:01011000111000:ESCAPE:", + "V:01011000111001:E:", + "W:01:o:", + "W:11:e:", + "W:001:h:", + "W:100:a:", + "W:101:i:", + "W:00000:.:", + "W:00010:O:", + "W:00011:r:", + "W:000011:y:", + "W:0000100:u:", + "W:00001010:STOP:", + "W:000010111:A:", + "W:00001011001:Y:", + "W:00001011010:T:", + "W:00001011011: :", + "W:000010110000:I:", + "W:0000101100010:ESCAPE:", + "W:0000101100011:l:", + "X:00:STOP:", + "X:10: :", + "X:11:t:", + "X:010:T:", + "X:0111:c:", + "X:01101:m:", + "X:011001:U:", + "X:01100000:a:", + "X:01100001:X:", + "X:01100010:-:", + "X:011000110:x:", + "X:0110001111:9:", + "X:01100011100:ESCAPE:", + "X:01100011101:i:", + "Y:1:o:", + "Y:01:e:", + "Y:000:u:", + "Y:0011: :", + "Y:00100:v:", + "Y:001010:a:", + "Y:00101110:P:", + "Y:00101111:':", + "Y:001011000:n:", + "Y:001011011:r:", + "Y:0010110010:D:", + "Y:00101100110:w:", + "Y:00101100111:s:", + "Y:00101101000:R:", + "Y:00101101001:L:", + "Y:00101101010:STOP:", + "Y:001011010110:C:", + "Y:0010110101110:ESCAPE:", + "Y:0010110101111:N:", + "Z:1:o:", + "Z:00:a:", + "Z:010:i:", + "Z:01100:O:", + "Z:01101:u:", + "Z:01110:e:", + "Z:011110: :", + "Z:0111111:STOP:", + "Z:01111101:0x3a:", + "Z:011111000:ESCAPE:", + "Z:011111001:-:", + "[:0:ESCAPE:", + "[:1:ESCAPE:", + "\\:0:ESCAPE:", + "\\:1:x:", + "]:0:ESCAPE:", + "]:1:ESCAPE:", + "^:0:ESCAPE:", + "^:1:ESCAPE:", + "_:0:ESCAPE:", + "_:1:ESCAPE:", + "`:0:ESCAPE:", + "`:1:ESCAPE:", + "a:001:r:", + "a:011:t:", + "a:100:l:", + "a:110:n:", + "a:0001:m:", + "a:0100:c:", + "a:1010:s:", + "a:1110:y:", + "a:10110: :", + "a:10111:d:", + "a:11110:i:", + "a:11111:k:", + "a:000010:b:", + "a:000011:STOP:", + "a:010110:p:", + "a:010111:g:", + "a:0000000:e:", + "a:0000001:':", + "a:0000011:w:", + "a:0101001:u:", + "a:0101010:z:", + "a:0101011:v:", + "a:00000101:f:", + "a:01010001:h:", + "a:000001001:0x3a:", + "a:0000010000:!:", + "a:0101000000:o:", + "a:0101000001:x:", + "a:00000100010:-:", + "a:00000100011:a:", + "a:01010000101:.:", + "a:01010000110:N:", + "a:01010000111:,:", + "a:010100001000:q:", + "a:0101000010010:j:", + "a:01010000100111:?:", + "a:010100001001101:J:", + "a:0101000010011000:ESCAPE:", + "a:0101000010011001:U:", + "b:000:r:", + "b:001:o:", + "b:010:e:", + "b:011:a:", + "b:100:i:", + "b:1011:u:", + "b:1100:y:", + "b:1101:l:", + "b:1111: :", + "b:10101:s:", + "b:11100:b:", + "b:11101:STOP:", + "b:101000:h:", + "b:1010010:3:", + "b:10100111:':", + "b:1010011001:t:", + "b:1010011010:j:", + "b:10100110000:n:", + "b:10100110001:d:", + "b:10100110111:w:", + "b:101001101101:m:", + "b:1010011011001:.:", + "b:10100110110000:ESCAPE:", + "b:10100110110001:0x3a:", + "c:00:k:", + "c:010:o:", + "c:100:h:", + "c:110:t:", + "c:111:e:", + "c:0111:r:", + "c:10100: :", + "c:10110:i:", + "c:10111:a:", + "c:011000:l:", + "c:011001:y:", + "c:011010:s:", + "c:011011:STOP:", + "c:1010100:c:", + "c:1010111:u:", + "c:10101010:0x3a:", + "c:10101011:P:", + "c:101011001:D:", + "c:1010110100:G:", + "c:1010110110:b:", + "c:10101100000:L:", + "c:10101100001:K:", + "c:10101100011:A:", + "c:10101101010:q:", + "c:10101101110:.:", + "c:10101101111:C:", + "c:101011000100:n:", + "c:101011000101:':", + "c:1010110101100:B:", + "c:1010110101101:I:", + "c:10101101011101:f:", + "c:10101101011110:8:", + "c:101011010111000:M:", + "c:101011010111001:ESCAPE:", + "c:101011010111111:F:", + "c:1010110101111100:w:", + "c:1010110101111101:Q:", + "d:11: :", + "d:001:e:", + "d:100:STOP:", + "d:101:a:", + "d:0001:y:", + "d:0100:i:", + "d:0110:s:", + "d:00000:o:", + "d:01010:d:", + "d:000011:u:", + "d:010110:r:", + "d:010111:l:", + "d:011101:v:", + "d:011110:g:", + "d:0000100:':", + "d:0111111:.:", + "d:00001010:0x3a:", + "d:00001011:h:", + "d:01110000:c:", + "d:01110010:n:", + "d:01110011:w:", + "d:011100010:?:", + "d:011111000:!:", + "d:011111001:-:", + "d:011111010:f:", + "d:0111000111:m:", + "d:0111110110:,:", + "d:01111101110:t:", + "d:01111101111:b:", + "d:011100011001:):", + "d:011100011010:/:", + "d:011100011011:k:", + "d:0111000110001:p:", + "d:01110001100001:z:", + "d:011100011000000:ESCAPE:", + "d:011100011000001:4:", + "e:01: :", + "e:000:s:", + "e:101:r:", + "e:0010:t:", + "e:1001:n:", + "e:1100:STOP:", + "e:1110:a:", + "e:1111:w:", + "e:10000:l:", + "e:11011:e:", + "e:001110:m:", + "e:100010:c:", + "e:100011:d:", + "e:0011010:i:", + "e:0011011:p:", + "e:0011110:b:", + "e:1101000:v:", + "e:1101011:y:", + "e:00110000:g:", + "e:00110001:f:", + "e:00110010:x:", + "e:00111110:k:", + "e:00111111:0x3a:", + "e:11010011:o:", + "e:11010100:':", + "e:001100111:h:", + "e:110100101:.:", + "e:0011001100:P:", + "e:0011001101:B:", + "e:1101001000:,:", + "e:1101010100:V:", + "e:1101010101:z:", + "e:1101010111:j:", + "e:11010010010:4:", + "e:11010010011:?:", + "e:11010101101:u:", + "e:110101011001:-:", + "e:1101010110001:!:", + "e:11010101100001:q:", + "e:110101011000001:G:", + "e:1101010110000000:ESCAPE:", + "e:1101010110000001:S:", + "f:0: :", + "f:101:o:", + "f:1001:t:", + "f:1100:a:", + "f:1101:i:", + "f:1111:e:", + "f:10000:.:", + "f:11100:r:", + "f:11101:f:", + "f:100010:STOP:", + "f:10001101:y:", + "f:10001111:u:", + "f:100011000:':", + "f:100011101:l:", + "f:1000110011:n:", + "f:1000111000:g:", + "f:10001100100:c:", + "f:10001110010:-:", + "f:100011001010:,:", + "f:100011001011:s:", + "f:100011100111:0x3a:", + "f:1000111001101:k:", + "f:10001110011000:ESCAPE:", + "f:10001110011001:b:", + "g:00:h:", + "g:10: :", + "g:010:STOP:", + "g:011:e:", + "g:1100:i:", + "g:11100:0x3a:", + "g:11101:r:", + "g:11111:a:", + "g:110100:s:", + "g:110111:l:", + "g:111101:u:", + "g:1101011:b:", + "g:1101100:g:", + "g:1101101:o:", + "g:1111001:n:", + "g:11010100:2:", + "g:11110000:!:", + "g:111100011:d:", + "g:1101010100:.:", + "g:1101010101:,:", + "g:1101010110:':", + "g:1101010111:t:", + "g:1111000101:y:", + "g:11110001000:w:", + "g:111100010011:m:", + "g:11110001001011:?:", + "g:111100010010000:p:", + "g:111100010010001:f:", + "g:111100010010010:@:", + "g:111100010010011:-:", + "g:111100010010101:;:", + "g:1111000100101000:ESCAPE:", + "g:1111000100101001:z:", + "h:0:e:", + "h:101:o:", + "h:1001:i:", + "h:1100:a:", + "h:1110: :", + "h:1111:t:", + "h:11010:r:", + "h:11011:STOP:", + "h:100000:b:", + "h:100001:u:", + "h:10001000:w:", + "h:10001001:d:", + "h:10001010:n:", + "h:10001011:y:", + "h:10001100:!:", + "h:10001101:l:", + "h:10001111:.:", + "h:100011100:':", + "h:1000111010:s:", + "h:10001110110:m:", + "h:100011101111:0x3a:", + "h:10001110111000:f:", + "h:10001110111001:?:", + "h:10001110111010:c:", + "h:1000111011101100:v:", + "h:1000111011101101:q:", + "h:1000111011101110:g:", + "h:100011101110111100:h:", + "h:100011101110111101:ESCAPE:", + "h:100011101110111110:,:", + "h:100011101110111111:*:", + "i:01:n:", + "i:000:c:", + "i:1001:o:", + "i:1010:l:", + "i:1100:g:", + "i:1101:s:", + "i:1110:t:", + "i:1111:e:", + "i:00101:a:", + "i:00110:v:", + "i:10000:r:", + "i:10001:d:", + "i:10110:m:", + "i:001000:p:", + "i:001110: :", + "i:101111:f:", + "i:0011110:z:", + "i:0011111:STOP:", + "i:1011100:b:", + "i:1011101:k:", + "i:00100101:-:", + "i:00100110:x:", + "i:001001001:':", + "i:001001111:q:", + "i:0010011100:u:", + "i:0010011101:i:", + "i:00100100001:h:", + "i:00100100010:0x3a:", + "i:00100100011:w:", + "i:0010010000001:,:", + "i:0010010000010:y:", + "i:0010010000011:/:", + "i:00100100000000:.:", + "i:001001000000010:ESCAPE:", + "i:001001000000011:j:", + "j:0:y:", + "j:11:o:", + "j:101:e:", + "j:1001:a:", + "j:10001:u:", + "j:100001:i:", + "j:1000000:STOP:", + "j:10000010:ESCAPE:", + "j:10000011: :", + "k:00: :", + "k:10:e:", + "k:010:i:", + "k:110:STOP:", + "k:0110:y:", + "k:0111:s:", + "k:1111:f:", + "k:111001:a:", + "k:111010:l:", + "k:1110001:0x3a:", + "k:1110110:k:", + "k:11100000:':", + "k:11101111:.:", + "k:111000011:w:", + "k:111011100:o:", + "k:1110000101:h:", + "k:11100001000:b:", + "k:11100001001:,:", + "k:11101110111:n:", + "k:111011101010:?:", + "k:111011101100:m:", + "k:111011101101:!:", + "k:1110111010010:u:", + "k:1110111010011:c:", + "k:1110111010110:d:", + "k:1110111010111:t:", + "k:11101110100001:j:", + "k:11101110100010:-:", + "k:111011101000000:p:", + "k:111011101000001:/:", + "k:111011101000111:S:", + "k:1110111010001100:ESCAPE:", + "k:1110111010001101:r:", + "l:01:e:", + "l:000:l:", + "l:101:a:", + "l:0011:y:", + "l:1000:STOP:", + "l:1001:d:", + "l:1100:o:", + "l:1110:i:", + "l:1111: :", + "l:00100:u:", + "l:11010:s:", + "l:001010:t:", + "l:001011:m:", + "l:1101101:k:", + "l:11011000:f:", + "l:11011100:b:", + "l:11011110:':", + "l:11011111:c:", + "l:110110011:v:", + "l:110111010:0x3a:", + "l:1101100101:.:", + "l:1101110110:w:", + "l:11011001000:z:", + "l:11011101111:p:", + "l:110110010010:h:", + "l:110110010011:*:", + "l:1101110111000:g:", + "l:1101110111001:,:", + "l:11011101110100:r:", + "l:11011101110101:n:", + "l:11011101110111:-:", + "l:110111011101100:!:", + "l:1101110111011011:?:", + "l:11011101110110101:C:", + "l:110111011101101000:ESCAPE:", + "l:110111011101101001:j:", + "m:10:e:", + "m:001:m:", + "m:011: :", + "m:111:a:", + "m:0000:i:", + "m:0001:STOP:", + "m:0100:y:", + "m:1101:p:", + "m:01010:b:", + "m:11000:o:", + "m:110010:n:", + "m:110011:s:", + "m:0101100:l:", + "m:0101110:f:", + "m:01011010:0x3a:", + "m:01011110:4:", + "m:010110110:h:", + "m:010111110:w:", + "m:0101101111:':", + "m:0101111110:r:", + "m:0101111111:u:", + "m:01011011101:.:", + "m:010110111001:k:", + "m:0101101110000:ESCAPE:", + "m:0101101110001:d:", + "n:000:i:", + "n:100:g:", + "n:101: :", + "n:110:d:", + "n:0011:a:", + "n:0100:s:", + "n:0110:e:", + "n:1110:STOP:", + "n:1111:t:", + "n:01110:c:", + "n:01111:n:", + "n:001010:y:", + "n:010100:':", + "n:010101:k:", + "n:010111:o:", + "n:0010000:r:", + "n:0010011:f:", + "n:0010110:u:", + "n:0010111:j:", + "n:00100010:v:", + "n:00100100:-:", + "n:00100101:.:", + "n:01011000:l:", + "n:01011010:x:", + "n:01011011:0x3a:", + "n:001000111:,:", + "n:010110011:m:", + "n:0010001100:!:", + "n:00100011010:z:", + "n:01011001001:?:", + "n:01011001010:h:", + "n:01011001011:b:", + "n:001000110110:B:", + "n:001000110111:*:", + "n:010110010000:w:", + "n:0101100100011:q:", + "n:01011001000101:p:", + "n:010110010001000:;:", + "n:0101100100010010:/:", + "n:0101100100010011:ESCAPE:", + "o:00:r:", + "o:110:n:", + "o:0100:f:", + "o:0101: :", + "o:0110:w:", + "o:1000:o:", + "o:1011:u:", + "o:01111:t:", + "o:10010:c:", + "o:10100:p:", + "o:10101:d:", + "o:11100:m:", + "o:11110:l:", + "o:011100:a:", + "o:011101:b:", + "o:100110:y:", + "o:100111:STOP:", + "o:111010:s:", + "o:111011:k:", + "o:1111101:v:", + "o:1111110:g:", + "o:11111111:i:", + "o:111110001:h:", + "o:111110010:!:", + "o:111111100:e:", + "o:111111101:j:", + "o:1111100110:':", + "o:11111000001:?:", + "o:11111000010:0x3a:", + "o:11111001110:z:", + "o:11111001111:x:", + "o:111110000000:J:", + "o:111110000110:.:", + "o:111110000111:-:", + "o:11111000000100:4:", + "o:11111000000110:,:", + "o:11111000000111:G:", + "o:111110000001011:):", + "o:1111100000010100:S:", + "o:11111000000101010:D:", + "o:111110000001010110:ESCAPE:", + "o:111110000001010111:q:", + "p:00:e:", + "p:010:STOP:", + "p:100:i:", + "p:110:o:", + "p:0110:s:", + "p:1010: :", + "p:1110:p:", + "p:01110:l:", + "p:01111:r:", + "p:10110:h:", + "p:11110:a:", + "p:101110:t:", + "p:101111:':", + "p:1111100:d:", + "p:1111101:m:", + "p:1111110:y:", + "p:111111101:0x3a:", + "p:111111111:!:", + "p:1111111100:w:", + "p:1111111101:u:", + "p:11111110000:b:", + "p:11111110010:-:", + "p:11111110011:.:", + "p:111111100011:n:", + "p:1111111000101:k:", + "p:11111110001001:,:", + "p:111111100010000:ESCAPE:", + "p:111111100010001:c:", + "q:1:u:", + "q:01:STOP:", + "q:001:0x3a:", + "q:0000:ESCAPE:", + "q:0001:':", + "r:000: :", + "r:011:i:", + "r:101:e:", + "r:0011:y:", + "r:0100:d:", + "r:1000:s:", + "r:1001:t:", + "r:1100:a:", + "r:1101:STOP:", + "r:1111:o:", + "r:01011:n:", + "r:11101:l:", + "r:001001:k:", + "r:001010:r:", + "r:001011:m:", + "r:010101:u:", + "r:111001:g:", + "r:0010000:':", + "r:0101001:c:", + "r:1110001:0x3a:", + "r:00100010:f:", + "r:00100011:.:", + "r:01010001:b:", + "r:11100000:v:", + "r:010100000:,:", + "r:010100001:p:", + "r:111000010:w:", + "r:1110000111:j:", + "r:11100001100:-:", + "r:111000011010:h:", + "r:1110000110110:G:", + "r:11100001101110:q:", + "r:111000011011111:S:", + "r:1110000110111100:!:", + "r:111000011011110100:*:", + "r:111000011011110110:T:", + "r:1110000110111101010:ESCAPE:", + "r:1110000110111101011:E:", + "r:1110000110111101110:1:", + "r:1110000110111101111:/:", + "s:10: :", + "s:11:STOP:", + "s:011:t:", + "s:0000:s:", + "s:0010:i:", + "s:0011:h:", + "s:00011:;:", + "s:01010:e:", + "s:010001:o:", + "s:010011:c:", + "s:010110:0x3a:", + "s:0001000:.:", + "s:0001001:!:", + "s:0001011:y:", + "s:0100000:p:", + "s:0100100:a:", + "s:0101111:u:", + "s:00010100:,:", + "s:00010101:f:", + "s:01000011:':", + "s:01001011:n:", + "s:01011100:l:", + "s:01011101:r:", + "s:010000101:k:", + "s:010010100:d:", + "s:0100001001:m:", + "s:0100101011:b:", + "s:01000010000:?:", + "s:01000010001:w:", + "s:01001010100:g:", + "s:010010101010:q:", + "s:01001010101101:E:", + "s:01001010101110:-:", + "s:010010101011000:ESCAPE:", + "s:010010101011001:):", + "s:010010101011110:W:", + "s:010010101011111:1:", + "t:000:i:", + "t:011:STOP:", + "t:100: :", + "t:111:h:", + "t:0010:a:", + "t:0100:r:", + "t:1010:s:", + "t:1011:o:", + "t:1101:e:", + "t:00111:t:", + "t:01010:y:", + "t:11000:u:", + "t:010110:m:", + "t:110010:c:", + "t:110011:l:", + "t:0011000:':", + "t:0011010:0x3a:", + "t:00110010:w:", + "t:00110110:!:", + "t:01011100:.:", + "t:01011101:b:", + "t:01011110:E:", + "t:01011111:f:", + "t:001100110:?:", + "t:001101110:n:", + "t:0011001110:z:", + "t:0011011110:d:", + "t:00110011111:,:", + "t:00110111110:P:", + "t:001100111100:v:", + "t:001100111101:-:", + "t:001101111110:):", + "t:0011011111110:g:", + "t:00110111111110:ESCAPE:", + "t:001101111111110:S:", + "t:0011011111111111:4:", + "t:00110111111111100:k:", + "t:001101111111111010:j:", + "t:001101111111111011:p:", + "u:00:r:", + "u:100:s:", + "u:111:n:", + "u:0100:e:", + "u:0101:m:", + "u:1100:t:", + "u:01100:c:", + "u:01101:g:", + "u:01110:b:", + "u:10100:p:", + "u:10101:i:", + "u:10110:l:", + "u:11010:d:", + "u:11011:a:", + "u:011110:STOP:", + "u:101110:y:", + "u:0111110:z:", + "u:1011110: :", + "u:01111111:':", + "u:10111110:-:", + "u:011111100:k:", + "u:101111111:0x3a:", + "u:0111111010:f:", + "u:0111111011:,:", + "u:1011111100:w:", + "u:101111110100:v:", + "u:101111110101:x:", + "u:101111110111:o:", + "u:1011111101100:j:", + "u:10111111011010:u:", + "u:101111110110110:.:", + "u:1011111101101111:h:", + "u:10111111011011100:?:", + "u:10111111011011101:ESCAPE:", + "v:1:e:", + "v:01:i:", + "v:001:a:", + "v:0001:o:", + "v:00000: :", + "v:000011:STOP:", + "v:0000100:y:", + "v:00001011:s:", + "v:000010101:r:", + "v:0000101000:ESCAPE:", + "v:0000101001:.:", + "w:0:s:", + "w:100: :", + "w:110:STOP:", + "w:1011:i:", + "w:1110:o:", + "w:10100:a:", + "w:11110:n:", + "w:11111:e:", + "w:1010111:y:", + "w:10101000:m:", + "w:10101011:d:", + "w:10101101:l:", + "w:101010011:b:", + "w:101010100:k:", + "w:101010101:r:", + "w:1010100100:j:", + "w:1010110001:,:", + "w:1010110011:h:", + "w:10101001011:-:", + "w:10101100000:c:", + "w:10101100001:f:", + "w:10101100101:p:", + "w:101010010100:g:", + "w:101011001000:t:", + "w:1010100101010:.:", + "w:1010100101011:0x3a:", + "w:1010110010011:q:", + "w:10101100100101:':", + "w:101011001001001:?:", + "w:1010110010010000:ESCAPE:", + "w:1010110010010001:B:", + "x:00:p:", + "x:10: :", + "x:11:t:", + "x:0110:STOP:", + "x:01000:o:", + "x:01010:c:", + "x:01110:i:", + "x:01111:m:", + "x:010010:e:", + "x:010110:y:", + "x:0100110:u:", + "x:0100111:f:", + "x:0101111:,:", + "x:010111000:g:", + "x:010111001:a:", + "x:010111011:9:", + "x:0101110101:':", + "x:01011101001:x:", + "x:010111010000:ESCAPE:", + "x:010111010001:s:", + "y:0: :", + "y:11:STOP:", + "y:10001:o:", + "y:10010:s:", + "y:10100:a:", + "y:10110:l:", + "y:10111:0x3a:", + "y:100110:d:", + "y:1000001:n:", + "y:1000010:t:", + "y:1010100:':", + "y:1010101:b:", + "y:1010111:.:", + "y:10000000:i:", + "y:10000110:,:", + "y:10000111:p:", + "y:10011100:m:", + "y:10011110:c:", + "y:10101100:w:", + "y:10101101:e:", + "y:100000010:?:", + "y:100000011:f:", + "y:100111010:r:", + "y:100111011:g:", + "y:1001111100:z:", + "y:1001111110:-:", + "y:1001111111:T:", + "y:100111110100:2:", + "y:100111110110:!:", + "y:100111110111:k:", + "y:1001111101010:v:", + "y:10011111010110:y:", + "y:100111110101110:h:", + "y:1001111101011111:j:", + "y:10011111010111100:ESCAPE:", + "y:10011111010111101:):", + "z:00:z:", + "z:01:STOP:", + "z:101:i:", + "z:1000:y:", + "z:1001:e:", + "z:1100:w:", + "z:1101: :", + "z:1110:l:", + "z:11110:a:", + "z:111110:o:", + "z:11111100:m:", + "z:11111101:0x3a:", + "z:11111111:c:", + "z:111111100:,:", + "z:1111111011:b:", + "z:11111110100:u:", + "z:111111101011:!:", + "z:11111110101000:ESCAPE:", + "z:11111110101001:t:", + "z:11111110101010:h:", + "z:11111110101011:?:", + "{:0:ESCAPE:", + "{:1:ESCAPE:", + "|:0:ESCAPE:", + "|:1:ESCAPE:", + "}:0:ESCAPE:", + "}:1:ESCAPE:", + "~:0:ESCAPE:", + "~:1:ESCAPE:", + "0x7f:0:ESCAPE:", + "0x7f:1:ESCAPE:", + NULL +}; + +static const char *FreesatT2[] = { + "START:010:A:", + "START:100:C:", + "START:111:T:", + "START:0001:J:", + "START:0011:D:", + "START:1010:S:", + "START:00000:H:", + "START:00100:I:", + "START:00101:R:", + "START:01101:F:", + "START:01110:.:", + "START:01111:W:", + "START:10111:M:", + "START:11000:B:", + "START:11001:P:", + "START:11011:N:", + "START:000010:O:", + "START:011001:[:", + "START:101101:L:", + "START:110101:E:", + "START:0000110:K:", + "START:1101000:Y:", + "START:1101001:G:", + "START:00001110:2:", + "START:01100000:p:", + "START:01100001:b:", + "START:01100010:U:", + "START:01100011:(:", + "START:10110000:1:", + "START:10110011:V:", + "START:000011110:Q:", + "START:101100010:3:", + "START:0000111110:9:", + "START:0000111111:8:", + "START:1011000110:6:", + "START:1011000111:5:", + "START:1011001000:Z:", + "START:1011001001:7:", + "START:1011001010:4:", + "START:101100101110:X:", + "START:101100101111: :", + "START:1011001011001:w:", + "START:1011001011010:':", + "START:1011001011011:\":", + "START:10110010110000:t:", + "START:101100101100010:a:", + "START:1011001011000110:`:", + "START:10110010110001110:ESCAPE:", + "START:10110010110001111:m:", + "ESCAPE:0:ESCAPE:", + "ESCAPE:1:ESCAPE:", + "STOP:0:ESCAPE:", + "STOP:1:ESCAPE:", + "0x03:0:ESCAPE:", + "0x03:1:ESCAPE:", + "0x04:0:ESCAPE:", + "0x04:1:ESCAPE:", + "0x05:0:ESCAPE:", + "0x05:1:ESCAPE:", + "0x06:0:ESCAPE:", + "0x06:1:ESCAPE:", + "0x07:0:ESCAPE:", + "0x07:1:ESCAPE:", + "0x08:0:ESCAPE:", + "0x08:1:ESCAPE:", + "0x09:0:ESCAPE:", + "0x09:1:ESCAPE:", + "0x0a:0:ESCAPE:", + "0x0a:1:ESCAPE:", + "0x0b:0:ESCAPE:", + "0x0b:1:ESCAPE:", + "0x0c:0:ESCAPE:", + "0x0c:1:ESCAPE:", + "0x0d:0:ESCAPE:", + "0x0d:1:ESCAPE:", + "0x0e:0:ESCAPE:", + "0x0e:1:ESCAPE:", + "0x0f:0:ESCAPE:", + "0x0f:1:ESCAPE:", + "0x10:0:ESCAPE:", + "0x10:1:ESCAPE:", + "0x11:0:ESCAPE:", + "0x11:1:ESCAPE:", + "0x12:0:ESCAPE:", + "0x12:1:ESCAPE:", + "0x13:0:ESCAPE:", + "0x13:1:ESCAPE:", + "0x14:0:ESCAPE:", + "0x14:1:ESCAPE:", + "0x15:0:ESCAPE:", + "0x15:1:ESCAPE:", + "0x16:0:ESCAPE:", + "0x16:1:ESCAPE:", + "0x17:0:ESCAPE:", + "0x17:1:ESCAPE:", + "0x18:0:ESCAPE:", + "0x18:1:ESCAPE:", + "0x19:0:ESCAPE:", + "0x19:1:ESCAPE:", + "0x1a:0:ESCAPE:", + "0x1a:1:ESCAPE:", + "0x1b:0:ESCAPE:", + "0x1b:1:ESCAPE:", + "0x1c:0:ESCAPE:", + "0x1c:1:ESCAPE:", + "0x1d:0:ESCAPE:", + "0x1d:1:ESCAPE:", + "0x1e:0:ESCAPE:", + "0x1e:1:ESCAPE:", + "0x1f:0:ESCAPE:", + "0x1f:1:ESCAPE:", + " :010:a:", + " :100:t:", + " :0001:o:", + " :0010:s:", + " :00110:d:", + " :01100:[:", + " :01111:p:", + " :10101:b:", + " :11001:c:", + " :11010:h:", + " :11100:w:", + " :11101:i:", + " :11111:f:", + " :000000:A:", + " :000011:M:", + " :001111:e:", + " :011100:B:", + " :011101:C:", + " :101000:T:", + " :101101:S:", + " :101110:g:", + " :110000:r:", + " :110110:n:", + " :110111:l:", + " :111101:m:", + " :0000011:v:", + " :0000100:G:", + " :0000101:N:", + " :0011101:y:", + " :0110101:H:", + " :0110111:L:", + " :1010010:J:", + " :1010011:F:", + " :1011001:R:", + " :1011110:u:", + " :1100010:D:", + " :1100011:W:", + " :1111001:P:", + " :00000100:k:", + " :00000101:O:", + " :01101000:-:", + " :01101101:1:", + " :10110001:K:", + " :10111110:j:", + " :11110000:I:", + " :11110001:E:", + " :001110010:q:", + " :001110011:U:", + " :011010010:V:", + " :011011000:Y:", + " :011011001: :", + " :101100001:2:", + " :101111110:STOP:", + " :0011100000:3:", + " :0011100001:8:", + " :0011100010:6:", + " :0110100111:5:", + " :1011000000:(:", + " :1011111110:7:", + " :00111000110:0:", + " :01101001100:':", + " :01101001101:9:", + " :10110000010:Z:", + " :10111111110:4:", + " :10111111111:Q:", + " :001110001111:X:", + " :1011000001100:ESCAPE:", + " :1011000001101:.:", + " :1011000001110:&:", + " :00111000111000:\\:", + " :00111000111010:@:", + " :00111000111011:`:", + " :10110000011110:\":", + " :10110000011111:z:", + " :001110001110011:$:", + " :0011100011100100:+:", + " :00111000111001011:x:", + " :001110001110010101:]:", + " :0011100011100101000:/:", + " :0011100011100101001:?:", + "!:1: :", + "!:01:STOP:", + "!:001:.:", + "!:0000:0x3a:", + "!:00011:[:", + "!:0001001:\":", + "!:0001010:/:", + "!:0001011:!:", + "!:00010000:):", + "!:000100010:':", + "!:0001000111:?:", + "!:00010001100:ESCAPE:", + "!:00010001101:]:", + "\":11: :", + "\":001:.:", + "\":0000:p:", + "\":0101:B:", + "\":0111:T:", + "\":1000:i:", + "\":00010:f:", + "\":00011:W:", + "\":01000:S:", + "\":01100:t:", + "\":01101:C:", + "\":10100:STOP:", + "\":10111:,:", + "\":010010:J:", + "\":100100:m:", + "\":101010:n:", + "\":101011:I:", + "\":0100110:E:", + "\":0100111:D:", + "\":1001010:w:", + "\":1001011:g:", + "\":1001100:b:", + "\":1001101:L:", + "\":1001110:-:", + "\":1011000:c:", + "\":1011001:H:", + "\":10011110:P:", + "\":10110100:r:", + "\":10110111:K:", + "\":100111111:l:", + "\":101101010:Y:", + "\":101101011:Q:", + "\":101101100:G:", + "\":101101101:A:", + "\":1001111100:ESCAPE:", + "\":1001111101:a:", + "#:0:ESCAPE:", + "#:1:ESCAPE:", + "$:0:1:", + "$:11:3:", + "$:100:4:", + "$:1011:2:", + "$:10101:7:", + "$:101001:5:", + "$:1010000:ESCAPE:", + "$:1010001:9:", + "%:1: :", + "%:00:ESCAPE:", + "%:01:,:", + "&:1: :", + "&:01:w:", + "&:001:B:", + "&:0000:E:", + "&:000100:2:", + "&:000110:A:", + "&:000111:R:", + "&:00010100:O:", + "&:00010101:4:", + "&:00010111:J:", + "&:000101100:ESCAPE:", + "&:000101101:P:", + "':1:s:", + "':001:t:", + "':010: :", + "':0000:l:", + "':01101:r:", + "':000100:n:", + "':000101:.:", + "':000110:C:", + "':011000:B:", + "':011101:A:", + "':0111000:d:", + "':0111100:v:", + "':00011100:S:", + "':00011111:p:", + "':01100101:D:", + "':01111011:i:", + "':01111100:c:", + "':01111101:m:", + "':01111111:,:", + "':000111010:f:", + "':000111011:g:", + "':011001000:F:", + "':011001001:h:", + "':011001101:H:", + "':011001110:N:", + "':011100101:R:", + "':011100110:STOP:", + "':011100111:T:", + "':011110101:G:", + "':011111101:L:", + "':0001111000:o:", + "':0001111001:K:", + "':0001111011:a:", + "':0110011001:u:", + "':0110011111:O:", + "':0111001001:I:", + "':0111101000:w:", + "':0111101001:b:", + "':0111111001:e:", + "':00011110101:?:", + "':01100110000:E:", + "':01100110001:7:", + "':01110010000:P:", + "':000111101001:W:", + "':011001111001:0x3a:", + "':011001111010:!:", + "':011100100011:J:", + "':011111100001:q:", + "':011111100011:M:", + "':0001111010001:V:", + "':0110011110001:9:", + "':0110011110111:y:", + "':0111001000100:8:", + "':0111001000101:5:", + "':0111111000000:6:", + "':0111111000101:k:", + "':00011110100000:2:", + "':00011110100001:0:", + "':01100111100001:Y:", + "':01100111101100:):", + "':01111110000010:j:", + "':01111110000011:Q:", + "':011001111000000:-:", + "':011001111000001:':", + "':011001111011011:z:", + "':011111100010000:X:", + "':011111100010001:U:", + "':011111100010010:4:", + "':011111100010011:3:", + "':0110011110110100:ESCAPE:", + "':0110011110110101:1:", + "(:01:1:", + "(:000:P:", + "(:101:t:", + "(:1000:2:", + "(:1101:5:", + "(:1110:N:", + "(:00111:T:", + "(:10010:p:", + "(:11111:c:", + "(:001001:a:", + "(:001010:S:", + "(:001100:R:", + "(:100111:e:", + "(:111100:J:", + "(:111101:A:", + "(:0010110:D:", + "(:0011011:K:", + "(:1001100:v:", + "(:1001101:s:", + "(:1100000:b:", + "(:1100010:G:", + "(:1100011:8:", + "(:1100100:M:", + "(:1100101:H:", + "(:1100110:C:", + "(:00100000:m:", + "(:00100010:o:", + "(:00100011:E:", + "(:00101110:W:", + "(:11000011:g:", + "(:11001110:L:", + "(:001000010:d:", + "(:001011111:U:", + "(:001101000:F:", + "(:001101010:f:", + "(:110000100:w:", + "(:110000101:B:", + "(:110011111:n:", + "(:0010000110:l:", + "(:0010000111:9:", + "(:0010111100:4:", + "(:0010111101:I:", + "(:0011010010:3:", + "(:0011010111:h:", + "(:1100111101:i:", + "(:00110100110:Z:", + "(:00110100111:V:", + "(:00110101100: :", + "(:11001111000:k:", + "(:001101011011:O:", + "(:110011110010:':", + "(:0011010110100:ESCAPE:", + "(:0011010110101:u:", + "(:1100111100110:X:", + "(:1100111100111:7:", + "):0: :", + "):11:.:", + "):101:STOP:", + "):1001:,:", + "):10000:0x3a:", + "):100011:;:", + "):1000101:!:", + "):10001001:(:", + "):1000100000:ESCAPE:", + "):1000100001:o:", + "):1000100010:?:", + "):1000100011:):", + "*:0:*:", + "*:100:s:", + "*:101: :", + "*:1100:m:", + "*:1110:t:", + "*:11010:g:", + "*:11011:k:", + "*:11111:d:", + "*:111101:y:", + "*:1111001:e:", + "*:11110000:i:", + "*:111100010:ESCAPE:", + "*:111100011:n:", + "+:1:n:", + "+:00:ESCAPE:", + "+:01: :", + ",:1: :", + ",:01:S:", + ",:001:0:", + ",:0001:A:", + ",:00000:5:", + ",:0000110:b:", + ",:0000111:3:", + ",:00001000:2:", + ",:00001001:\":", + ",:00001011:1:", + ",:0000101000:Q:", + ",:0000101010:':", + ",:00001010111:4:", + ",:000010100100:T:", + ",:000010100101:B:", + ",:000010100110:7:", + ",:000010100111:6:", + ",:000010101100:STOP:", + ",:0000101011010:ESCAPE:", + ",:0000101011011:i:", + "-:00: :", + "-:0100:t:", + "-:0101:b:", + "-:0110:w:", + "-:0111:u:", + "-:1001:o:", + "-:1010:s:", + "-:1011:f:", + "-:10000:c:", + "-:11011:l:", + "-:11101:d:", + "-:100010:9:", + "-:110000:h:", + "-:110010:1:", + "-:110011:y:", + "-:110101:r:", + "-:111000:a:", + "-:111100:m:", + "-:111110:p:", + "-:1000110:S:", + "-:1101000:e:", + "-:1101001:i:", + "-:1111011:n:", + "-:10001110:C:", + "-:11000101:W:", + "-:11000111:g:", + "-:11100101:J:", + "-:11100110:D:", + "-:11110101:2:", + "-:11111100:7:", + "-:11111110:G:", + "-:11111111:O:", + "-:100011111:H:", + "-:110001000:A:", + "-:110001100:6:", + "-:110001101:B:", + "-:111001111:M:", + "-:111101000:E:", + "-:111101001:L:", + "-:111111010:U:", + "-:111111011:k:", + "-:1000111100:F:", + "-:1100010010:j:", + "-:1100010011:P:", + "-:1110010001:q:", + "-:1110010010:5:", + "-:1110010011:T:", + "-:1110011101:I:", + "-:10001111011:K:", + "-:11100100000:v:", + "-:11100100001:Z:", + "-:11100111001:N:", + "-:100011110101:R:", + "-:111001110001:Y:", + "-:1000111101001:0:", + "-:10001111010000:4:", + "-:10001111010001:z:", + "-:11100111000001:V:", + "-:11100111000010:3:", + "-:11100111000011:8:", + "-:111001110000001:Q:", + "-:1110011100000000:':", + "-:11100111000000010:ESCAPE:", + "-:11100111000000011:x:", + ".:1: :", + ".:01:STOP:", + ".:0011:.:", + ".:00010:i:", + ".:00100:0:", + ".:00101:c:", + ".:000001:u:", + ".:0000000:a:", + ".:0000001:[:", + ".:0001101:3:", + ".:00001000:4:", + ".:00001110:H:", + ".:00011000:S:", + ".:00011001:W:", + ".:00011100:o:", + ".:00011110:1:", + ".:000010100:5:", + ".:000010101:L:", + ".:000010111:p:", + ".:000011000:T:", + ".:000011001:A:", + ".:000011010:M:", + ".:000011110:C:", + ".:000011111:2:", + ".:000111011:D:", + ".:000111110:B:", + ".:0000100100:N:", + ".:0000100110:t:", + ".:0000100111:J:", + ".:0000101101:R:", + ".:0000110111:P:", + ".:0001110101:s:", + ".:0001111111:I:", + ".:00001011000:r:", + ".:00001101100:V:", + ".:00011101000:w:", + ".:00011101001:F:", + ".:00011111101:G:", + ".:000010010100:E:", + ".:000010010101:0x3a:", + ".:000010110010:h:", + ".:000011011010:,:", + ".:000111111000:':", + ".:0000100101101:b:", + ".:0000100101110:K:", + ".:0000100101111:Y:", + ".:0000101100111:O:", + ".:0000110110110:-:", + ".:0001111110010:f:", + ".:0001111110011:(:", + ".:00001011001100:\":", + ".:00001101101110:y:", + ".:000010010110000:?:", + ".:000010010110001:m:", + ".:000010010110010:Q:", + ".:000011011011110:*:", + ".:000011011011111:&:", + ".:0000100101100110:U:", + ".:0000100101100111:;:", + ".:0000101100110100:8:", + ".:0000101100110101:6:", + ".:0000101100110111:k:", + ".:00001011001101100:d:", + ".:000010110011011010:ESCAPE:", + ".:000010110011011011:n:", + "/:01:c:", + "/:110:1:", + "/:111:e:", + "/:0000:5:", + "/:0010:8:", + "/:00010:T:", + "/:00011:f:", + "/:00110:B:", + "/:00111:2:", + "/:10001:3:", + "/:10010:7:", + "/:10100:6:", + "/:10110:a:", + "/:101111:4:", + "/:1000000:F:", + "/:1000010:s:", + "/:1000011:M:", + "/:1001100:H:", + "/:1001110:D:", + "/:1001111:A:", + "/:1010101:S:", + "/:10000011:m:", + "/:10011010:W:", + "/:10101000:G:", + "/:10101001:U:", + "/:10101100:d:", + "/:10101101:O:", + "/:10101110:N:", + "/:10111001:C:", + "/:10111011:P:", + "/:100110110:L:", + "/:101011110: :", + "/:101011111:I:", + "/:101110000:E:", + "/:101110001:R:", + "/:101110100:K:", + "/:101110101:t:", + "/:1000001001:J:", + "/:1000001011:9:", + "/:10000010000:v:", + "/:10000010001:p:", + "/:10000010100:h:", + "/:10011011101:o:", + "/:10011011110:Q:", + "/:10011011111:0:", + "/:100000101010:l:", + "/:100000101011:i:", + "/:100110111000:V:", + "/:1001101110011:y:", + "/:10011011100100:ESCAPE:", + "/:10011011100101:g:", + "0:0:0:", + "0:111: :", + "0:1001:a:", + "0:1011:p:", + "0:10001:s:", + "0:11000:.:", + "0:11001:8:", + "0:11011:,:", + "0:100000:4:", + "0:100001:t:", + "0:101001:5:", + "0:110100:6:", + "0:1010000:3:", + "0:1010001:7:", + "0:1010101:]:", + "0:1010110:-:", + "0:1010111:1:", + "0:10101000:):", + "0:10101001:/:", + "0:11010100:STOP:", + "0:11010101:9:", + "0:11010111:2:", + "0:110101100:%:", + "0:1101011010:0x3a:", + "0:110101101101:f:", + "0:110101101111:m:", + "0:1101011011100:y:", + "0:11010110110001:l:", + "0:11010110110010:;:", + "0:11010110110011:':", + "0:11010110111010:k:", + "0:11010110111011:!:", + "0:110101101100000:C:", + "0:1101011011000010:ESCAPE:", + "0:1101011011000011:J:", + "1:00:9:", + "1:100:1:", + "1:111:0:", + "1:0101: :", + "1:0111:2:", + "1:1011:.:", + "1:1100:5:", + "1:01000:6:", + "1:01001:8:", + "1:01101:/:", + "1:10100:]:", + "1:11010:3:", + "1:011001:7:", + "1:110110:4:", + "1:0110000:STOP:", + "1:0110001:-:", + "1:1010100:):", + "1:1010110:0x3a:", + "1:1010111:s:", + "1:1101110:,:", + "1:1101111:x:", + "1:10101010:':", + "1:101010110:X:", + "1:10101011110:t:", + "1:10101011111:R:", + "1:101010111011:;:", + "1:1010101110000:p:", + "1:1010101110001:m:", + "1:1010101110010:!:", + "1:1010101110101:&:", + "1:10101011100110:e:", + "1:101010111001110:b:", + "1:101010111001111:a:", + "1:101010111010000:D:", + "1:101010111010001:C:", + "1:101010111010010:%:", + "1:1010101110100110:ESCAPE:", + "1:1010101110100111:o:", + "2:11:0:", + "2:000: :", + "2:010:.:", + "2:100:5:", + "2:0011:/:", + "2:1011:,:", + "2:00100:]:", + "2:00101:p:", + "2:01101:1:", + "2:10101:4:", + "2:011000:6:", + "2:011001:2:", + "2:011100:0x3a:", + "2:011101:-:", + "2:011111:):", + "2:1010000:STOP:", + "2:1010010:8:", + "2:1010011:9:", + "2:01111000:D:", + "2:01111001:3:", + "2:01111010:t:", + "2:01111011:7:", + "2:10100010:n:", + "2:101000110:a:", + "2:1010001110:':", + "2:10100011111:;:", + "2:101000111100:s:", + "2:1010001111010:\":", + "2:101000111101100:ESCAPE:", + "2:101000111101101:i:", + "2:101000111101110:W:", + "2:101000111101111:L:", + "3:00: :", + "3:10:0:", + "3:110:.:", + "3:1110:/:", + "3:01000:2:", + "3:01001:1:", + "3:01010:):", + "3:01100:0x3a:", + "3:01110:-:", + "3:11111:]:", + "3:010110:D:", + "3:011010:4:", + "3:011011:STOP:", + "3:011111:5:", + "3:111100:,:", + "3:0101110:7:", + "3:0101111:3:", + "3:0111101:6:", + "3:1111011:t:", + "3:01111001:B:", + "3:11110100:8:", + "3:111101010:9:", + "3:0111100001:;:", + "3:1111010110:r:", + "3:1111010111:s:", + "3:01111000000:n:", + "3:01111000101:b:", + "3:01111000110:':", + "3:01111000111:A:", + "3:011110000010:p:", + "3:011110000011:e:", + "3:0111100010000:a:", + "3:0111100010001:&:", + "3:0111100010010:%:", + "3:01111000100110:ESCAPE:", + "3:01111000100111:k:", + "4:01: :", + "4:000:4:", + "4:100:.:", + "4:110:0:", + "4:0010:/:", + "4:1010:5:", + "4:1011:-:", + "4:00110:1:", + "4:11101:]:", + "4:11110:,:", + "4:001110:2:", + "4:111001:8:", + "4:111110:):", + "4:0011110:0x3a:", + "4:0011111:':", + "4:1110000:t:", + "4:1110001:3:", + "4:1111111:STOP:", + "4:11111101:6:", + "4:1111110000:9:", + "4:1111110010:7:", + "4:11111100011:C:", + "4:11111100110:;:", + "4:111111000101:x:", + "4:1111110011101:m:", + "4:1111110011110:I:", + "4:11111100010000:f:", + "4:11111100010001:e:", + "4:11111100010010:b:", + "4:11111100010011:L:", + "4:11111100111000:%:", + "4:11111100111110:p:", + "4:11111100111111:c:", + "4:111111001110010:ESCAPE:", + "4:111111001110011:i:", + "5:00:0:", + "5:10: :", + "5:010:.:", + "5:0111:p:", + "5:1100:5:", + "5:01100:/:", + "5:11010:a:", + "5:11011:-:", + "5:11101:6:", + "5:011010:3:", + "5:111100:2:", + "5:111110:8:", + "5:111111:]:", + "5:0110110:0x3a:", + "5:1110000:):", + "5:1110001:s:", + "5:1110011:,:", + "5:1111010:7:", + "5:1111011:9:", + "5:01101110:4:", + "5:11100100:STOP:", + "5:11100101:t:", + "5:0110111110:c:", + "5:0110111111:1:", + "5:01101111001:;:", + "5:01101111011:m:", + "5:011011110000:e:", + "5:011011110001:':", + "5:011011110101:k:", + "5:0110111101001:l:", + "5:01101111010000:ESCAPE:", + "5:01101111010001:f:", + "6:00: :", + "6:10:.:", + "6:111:0:", + "6:0101:]:", + "6:01001:1:", + "6:01100:7:", + "6:01110:):", + "6:11000:,:", + "6:11001:0x3a:", + "6:11010:/:", + "6:010001:-:", + "6:011010:5:", + "6:011011:4:", + "6:011111:8:", + "6:110111:t:", + "6:0100000:6:", + "6:0111100:3:", + "6:0111101:2:", + "6:1101101:9:", + "6:01000010:STOP:", + "6:01000011:+:", + "6:11011000:':", + "6:1101100101:a:", + "6:1101100110:?:", + "6:11011001000:m:", + "6:11011001001:e:", + "6:11011001110:;:", + "6:1101100111100:f:", + "6:1101100111101:b:", + "6:1101100111110:M:", + "6:11011001111110:\":", + "6:110110011111110:ESCAPE:", + "6:110110011111111:i:", + "7:11:.:", + "7:001: :", + "7:011:0:", + "7:101:-:", + "7:0000:8:", + "7:0100:7:", + "7:1001:]:", + "7:01010:/:", + "7:000101:6:", + "7:000110:2:", + "7:000111:1:", + "7:010111:t:", + "7:100000:9:", + "7:100010:):", + "7:100011:5:", + "7:0001001:3:", + "7:0101101:,:", + "7:1000010:a:", + "7:1000011:4:", + "7:00010000:STOP:", + "7:01011000:0x3a:", + "7:01011001:p:", + "7:0001000101:R:", + "7:0001000110:;:", + "7:00010001000:':", + "7:00010001111:m:", + "7:000100010011:f:", + "7:000100011100:A:", + "7:000100011101:?:", + "7:0001000100100:ESCAPE:", + "7:0001000100101:s:", + "8:01: :", + "8:000:4:", + "8:110:.:", + "8:0011:0:", + "8:1000:9:", + "8:1001:7:", + "8:1011:8:", + "8:1110:1:", + "8:00100:/:", + "8:10100:3:", + "8:11110:5:", + "8:101010:):", + "8:111110:6:", + "8:111111:]:", + "8:0010100:0x3a:", + "8:0010101:,:", + "8:1010111:t:", + "8:00101100:p:", + "8:00101101:-:", + "8:00101111:a:", + "8:10101100:c:", + "8:10101101:2:", + "8:001011101:STOP:", + "8:0010111001:;:", + "8:001011100000:l:", + "8:001011100001:':", + "8:0010111000100:f:", + "8:0010111000101:D:", + "8:0010111000110:A:", + "8:00101110001110:ESCAPE:", + "8:00101110001111:i:", + "9:000:5:", + "9:001:]:", + "9:111:9:", + "9:0101:0:", + "9:0110:.:", + "9:0111:-:", + "9:1000:4:", + "9:1001:8:", + "9:1011:6:", + "9:1100: :", + "9:1101:7:", + "9:01000:2:", + "9:10100:3:", + "9:010010:1:", + "9:010011:/:", + "9:101010:t:", + "9:1010111:):", + "9:10101100:0x3a:", + "9:101011010:,:", + "9:10101101100:p:", + "9:10101101101:;:", + "9:10101101111:STOP:", + "9:1010110111000:n:", + "9:1010110111001:m:", + "9:1010110111010:a:", + "9:10101101110111:e:", + "9:101011011101100:ESCAPE:", + "9:101011011101101:k:", + "0x3a:1: :", + "0x3a:01:0:", + "0x3a:001:3:", + "0x3a:00001:1:", + "0x3a:00010:T:", + "0x3a:00011:C:", + "0x3a:000001:4:", + "0x3a:0000000:ESCAPE:", + "0x3a:0000001:5:", + ";:0:ESCAPE:", + ";:1: :", + "<:0:ESCAPE:", + "<:1:ESCAPE:", + "=:0:ESCAPE:", + "=:1:ESCAPE:", + ">:0:ESCAPE:", + ">:1:ESCAPE:", + "?:1: :", + "?:01:STOP:", + "?:000:0x3a:", + "?:00100:!:", + "?:00110:[:", + "?:00111:.:", + "?:001010:;:", + "?:0010110:':", + "?:00101111:,:", + "?:001011101:/:", + "?:0010111000:ESCAPE:", + "?:0010111001:Q:", + "@:0:k:", + "@:10: :", + "@:111:T:", + "@:1101:b:", + "@:11000:ESCAPE:", + "@:11001:H:", + "A:01: :", + "A:110:D:", + "A:111:n:", + "A:0000:s:", + "A:0001:m:", + "A:0010:d:", + "A:1000:r:", + "A:1011:l:", + "A:00110:c:", + "A:10010:u:", + "A:10100:g:", + "A:001111:b:", + "A:100111:t:", + "A:101011:f:", + "A:1010100:w:", + "A:1010101:i:", + "A:10011001:v:", + "A:10011011:p:", + "A:001110010:h:", + "A:001110100:.:", + "A:001110111:B:", + "A:100110100:q:", + "A:0011100000:C:", + "A:0011100010:,:", + "A:0011100110:y:", + "A:0011101010:S:", + "A:0011101100:k:", + "A:0011101101:T:", + "A:1001100001:R:", + "A:1001100010:F:", + "A:1001100011:z:", + "A:1001101011:a:", + "A:00111000010:P:", + "A:00111000110:-:", + "A:00111010110:A:", + "A:00111010111:I:", + "A:10011000001:e:", + "A:10011010100:N:", + "A:10011010101:x:", + "A:001110000110:X:", + "A:001110000111:K:", + "A:001110001110:3:", + "A:001110001111:&:", + "A:001110011101:M:", + "A:001110011111:Y:", + "A:0011100111000:L:", + "A:0011100111001:W:", + "A:0011100111100:*:", + "A:1001100000000:o:", + "A:1001100000001:1:", + "A:1001100000010:':", + "A:1001100000011:0x3a:", + "A:00111001111010:j:", + "A:001110011110110:G:", + "A:0011100111101110:O:", + "A:00111001111011110:4:", + "A:001110011110111110:ESCAPE:", + "A:001110011110111111:E:", + "B:00:C:", + "B:010:a:", + "B:101:r:", + "B:110:e:", + "B:111:B:", + "B:0111:i:", + "B:1000:u:", + "B:1001:o:", + "B:01101:l:", + "B:01100000:T:", + "B:01100001:.:", + "B:01100011:y:", + "B:01100100:I:", + "B:01100110:h:", + "B:01100111: :", + "B:011000100:A:", + "B:0110001010:O:", + "B:01100010110:0x3a:", + "B:01100101000:&:", + "B:01100101001:3:", + "B:01100101010:j:", + "B:01100101011:M:", + "B:01100101110:D:", + "B:011000101111:W:", + "B:011001011000:*:", + "B:011001011010:,:", + "B:011001011011:1:", + "B:011001011110:ESCAPE:", + "B:011001011111:P:", + "B:0110001011100:E:", + "B:0110010110011:R:", + "B:01100010111011:w:", + "B:011000101110100:-:", + "B:011001011001001:U:", + "B:011001011001010:S:", + "B:011001011001011:F:", + "B:0110001011101010:X:", + "B:0110001011101011:V:", + "B:0110010110010000:Q:", + "B:0110010110010001:4:", + "C:00:h:", + "C:011:B:", + "C:100:a:", + "C:110:o:", + "C:0101:r:", + "C:1010:.:", + "C:1110: :", + "C:1111:l:", + "C:01000:':", + "C:10111:i:", + "C:010011:e:", + "C:101101:u:", + "C:0100101:y:", + "C:1011001:,:", + "C:01001001:I:", + "C:010010000:A:", + "C:1011000000:C:", + "C:1011000001:D:", + "C:1011000011:STOP:", + "C:1011000100:S:", + "C:1011000101:T:", + "C:1011000111:G:", + "C:01001000100:*:", + "C:01001000111:w:", + "C:10110001101:J:", + "C:010010001010:R:", + "C:010010001100:2:", + "C:010010001101:U:", + "C:101100001000:?:", + "C:101100001010:O:", + "C:101100001011:H:", + "C:101100011000:E:", + "C:0100100010110:z:", + "C:1011000010011:-:", + "C:1011000110011:s:", + "C:01001000101111:1:", + "C:10110000100101:!:", + "C:10110001100100:P:", + "C:010010001011101:n:", + "C:101100001001000:K:", + "C:101100001001001:7:", + "C:101100011001011:4:", + "C:0100100010111000:0x3a:", + "C:1011000110010100:F:", + "C:1011000110010101:):", + "C:01001000101110010:ESCAPE:", + "C:01001000101110011:b:", + "D:00:a:", + "D:01:,:", + "D:100:r:", + "D:101:o:", + "D:110:e:", + "D:1110:i:", + "D:111111:u:", + "D:1111001: :", + "D:1111011:':", + "D:11110000:.:", + "D:11110001:]:", + "D:11111010:y:", + "D:111101010:w:", + "D:111101011:W:", + "D:111110001:N:", + "D:111110010:C:", + "D:111110111:J:", + "D:1111010010:h:", + "D:1111100000:t:", + "D:1111100111:I:", + "D:1111101101:0x3a:", + "D:11110100001:M:", + "D:11110100010:&:", + "D:11110100011:V:", + "D:11111000010:-:", + "D:11111000011:G:", + "D:11111001100:O:", + "D:11111001101:A:", + "D:11111011001:S:", + "D:111101000000:F:", + "D:111101001100:*:", + "D:111101001101:s:", + "D:111101001111:d:", + "D:111110110000:v:", + "D:1111010011100:m:", + "D:1111010011101:j:", + "D:1111101100010:ESCAPE:", + "D:1111101100011:T:", + "D:11110100000110:9:", + "D:111101000001000:):", + "D:111101000001011:E:", + "D:111101000001110:8:", + "D:111101000001111:7:", + "D:1111010000010010:U:", + "D:1111010000010011:R:", + "D:1111010000010100:B:", + "D:1111010000010101:4:", + "E:000:p:", + "E:010:a:", + "E:011:n:", + "E:110:l:", + "E:1001:m:", + "E:1010:x:", + "E:1110:v:", + "E:1111:d:", + "E:00100:s:", + "E:00110:r:", + "E:00111:u:", + "E:10000:E:", + "E:10001: :", + "E:001010:.:", + "E:001011:i:", + "E:101101:0x3a:", + "E:1011000:y:", + "E:1011001:t:", + "E:1011100:g:", + "E:1011110:4:", + "E:101110110:w:", + "E:101111100:c:", + "E:101111110:b:", + "E:1011101010:R:", + "E:1011101011:F:", + "E:1011101111:C:", + "E:10111010001:k:", + "E:10111010010:f:", + "E:10111010011:o:", + "E:10111011100:U:", + "E:10111011101:L:", + "E:10111110101:e:", + "E:10111110110:N:", + "E:10111111100:h:", + "E:10111111101:I:", + "E:10111111111:D:", + "E:101111101000:M:", + "E:101111101111:':", + "E:101111111100:2:", + "E:101111111101:-:", + "E:1011101000011:q:", + "E:1011111010010:O:", + "E:1011111010011:A:", + "E:1011111011101:Z:", + "E:10111010000000:W:", + "E:10111010000001:S:", + "E:10111010000010:H:", + "E:10111010000011:9:", + "E:10111010000100:):", + "E:10111110111000:T:", + "E:10111110111001:,:", + "E:101110100001010:P:", + "E:1011101000010110:ESCAPE:", + "E:1011101000010111:z:", + "F:00:o:", + "F:10:r:", + "F:010:e:", + "F:110:i:", + "F:111:a:", + "F:0110:l:", + "F:01110:u:", + "F:0111100: :", + "F:0111101:O:", + "F:01111101:A:", + "F:01111111:B:", + "F:011111100:f:", + "F:0111110000:.:", + "F:0111110011:L:", + "F:01111100010:M:", + "F:01111100011:E:", + "F:01111100101:T:", + "F:01111110101:C:", + "F:01111110110:W:", + "F:011111001000:0x3a:", + "F:011111101000:U:", + "F:011111101001:':", + "F:011111101111:1:", + "F:0111110010010:y:", + "F:0111110010011:,:", + "F:01111110111000:-:", + "F:01111110111010:I:", + "F:011111101110011:h:", + "F:0111111011100100:*:", + "F:0111111011100101:K:", + "F:0111111011101100:F:", + "F:0111111011101101:ESCAPE:", + "F:01111110111011100:X:", + "F:01111110111011101:R:", + "F:01111110111011110:;:", + "F:01111110111011111:4:", + "G:00:r:", + "G:01:a:", + "G:101:o:", + "G:110:e:", + "G:1001:u:", + "G:1111:i:", + "G:10001:n:", + "G:11101:l:", + "G:100000:X:", + "G:1110000:y:", + "G:1110001: :", + "G:1110011:w:", + "G:10000101:4:", + "G:10000111:P:", + "G:11100101:h:", + "G:100001000:-:", + "G:100001100:C:", + "G:111001001:M:", + "G:1000011010:B:", + "G:1110010000:.:", + "G:1110010001:I:", + "G:10000100100:;:", + "G:10000100101:,:", + "G:10000100110:A:", + "G:10000100111:N:", + "G:10000110111:0x3a:", + "G:1000011011000:O:", + "G:1000011011001:L:", + "G:10000110110110:b:", + "G:100001101101000:K:", + "G:100001101101001:2:", + "G:100001101101010:1:", + "G:100001101101011:':", + "G:1000011011011100:ESCAPE:", + "G:1000011011011101:m:", + "G:1000011011011110:T:", + "G:1000011011011111:S:", + "H:00:e:", + "H:01:a:", + "H:10:o:", + "H:110:i:", + "H:1111:u:", + "H:11100:R:", + "H:1110100:P:", + "H:1110110:y:", + "H:11101011:I:", + "H:111011100:Q:", + "H:111011101:M:", + "H:111011110:A:", + "H:111011111: :", + "H:1110101000:S:", + "H:1110101001:.:", + "H:11101010101:G:", + "H:11101010110:):", + "H:111010101001:E:", + "H:1110101011100:O:", + "H:1110101011101:L:", + "H:11101010100000:1:", + "H:11101010100001:&:", + "H:11101010111100:H:", + "H:11101010111101:w:", + "H:11101010111110:v:", + "H:111010101000100:X:", + "H:111010101000101:W:", + "H:111010101000110:D:", + "H:111010101111110:s:", + "H:111010101111111:F:", + "H:1110101010001110:ESCAPE:", + "H:1110101010001111:r:", + "I:0:n:", + "I:110:t:", + "I:1001:s:", + "I:1111:r:", + "I:10000:T:", + "I:10101:a:", + "I:11100: :", + "I:100010:c:", + "I:101001:m:", + "I:101100:z:", + "I:101101:.:", + "I:101111:d:", + "I:111011:I:", + "I:1000111:':", + "I:1011101:l:", + "I:10100000:A:", + "I:10100001:v:", + "I:10111001:V:", + "I:11101001:f:", + "I:11101011:o:", + "I:100011001:C:", + "I:100011010:P:", + "I:101000100:w:", + "I:101000110:0x3a:", + "I:101110000:p:", + "I:111010000:R:", + "I:111010001:,:", + "I:111010101:Y:", + "I:1000110000:E:", + "I:1000110001:6:", + "I:1000110111:q:", + "I:1010001011:y:", + "I:1010001110:M:", + "I:1110101000:g:", + "I:1110101001:D:", + "I:10001101100:e:", + "I:10001101101:5:", + "I:10100010100:S:", + "I:10100010101:9:", + "I:10100011111:F:", + "I:10111000100:b:", + "I:10111000110:-:", + "I:10111000111:L:", + "I:101000111100:B:", + "I:101000111101:):", + "I:1011100010100:N:", + "I:1011100010101:Q:", + "I:1011100010110:k:", + "I:10111000101111:O:", + "I:101110001011101:?:", + "I:1011100010111000:ESCAPE:", + "I:1011100010111001:h:", + "J:00:e:", + "J:10:a:", + "J:11:o:", + "J:011:u:", + "J:0101:i:", + "J:01000: :", + "J:0100110:D:", + "J:0100111:.:", + "J:01001001:r:", + "J:010010110:s:", + "J:0100100000:M:", + "J:0100100010:J:", + "J:0100100011:,:", + "J:0100101000:B:", + "J:0100101001:-:", + "J:0100101010:V:", + "J:0100101110:K:", + "J:0100101111:T:", + "J:01001000010:C:", + "J:01001010110:n:", + "J:010010000110:!:", + "J:0100100001110:w:", + "J:0100100001111:R:", + "J:0100101011100:F:", + "J:0100101011110:7:", + "J:0100101011111:':", + "J:01001010111010:G:", + "J:010010101110110:ESCAPE:", + "J:010010101110111:L:", + "K:00:i:", + "K:01:a:", + "K:10:e:", + "K:1111:y:", + "K:11000:n:", + "K:11001:o:", + "K:11011:r:", + "K:11101: :", + "K:110100:':", + "K:111000:u:", + "K:1101011:.:", + "K:1110011:l:", + "K:11100101:h:", + "K:110101000:T:", + "K:110101011:G:", + "K:111001001:,:", + "K:1101010100:w:", + "K:11010100100:5:", + "K:11010100101:4:", + "K:11010100110:A:", + "K:11010101010:3:", + "K:11100100000:2:", + "K:11100100011:M:", + "K:110101001110:-:", + "K:110101010110:0x3a:", + "K:110101010111:!:", + "K:111001000010:):", + "K:111001000101:S:", + "K:1101010011110:V:", + "K:1110010000110:6:", + "K:1110010000111:1:", + "K:11010100111111:L:", + "K:11100100010000:I:", + "K:11100100010001:?:", + "K:110101001111100:ESCAPE:", + "K:110101001111101:v:", + "K:111001000100100:k:", + "K:111001000100101:Y:", + "K:111001000100110:N:", + "K:111001000100111:E:", + "L:00:i:", + "L:10:o:", + "L:011:]:", + "L:110:e:", + "L:111:a:", + "L:0100:u:", + "L:010100:l:", + "L:010101:A:", + "L:010111:y:", + "L:01011011: :", + "L:010110000:I:", + "L:010110001:R:", + "L:010110101:,:", + "L:0101100100:O:", + "L:0101100101:':", + "L:01011001101:.:", + "L:01011001110:C:", + "L:01011001111:Y:", + "L:01011010001:F:", + "L:01011010010:L:", + "L:010110011001:t:", + "L:010110100001:G:", + "L:010110100111:S:", + "L:0101100110001:h:", + "L:0101101000001:W:", + "L:0101101001100:J:", + "L:01011001100000:E:", + "L:01011010000001:\":", + "L:01011010011011:STOP:", + "L:010110011000010:T:", + "L:010110011000011:P:", + "L:010110100000000:D:", + "L:010110100000001:7:", + "L:010110100110101:j:", + "L:0101101001101000:ESCAPE:", + "L:0101101001101001:U:", + "M:00:o:", + "M:11:a:", + "M:011:e:", + "M:101:i:", + "M:0101:c:", + "M:1001:u:", + "M:01001:y:", + "M:10001:r:", + "M:100000:S:", + "M:100001:P:", + "M:0100001: :", + "M:01000001:C:", + "M:01000110:F:", + "M:010000000:1:", + "M:010001000:h:", + "M:010001010:I:", + "M:010001110:T:", + "M:010001111:X:", + "M:0100000010:A:", + "M:0100010010:z:", + "M:01000100110:f:", + "M:01000101110:.:", + "M:010000001100:Z:", + "M:010000001101:K:", + "M:010000001110:B:", + "M:010001001111:s:", + "M:010001011000:R:", + "M:010001011001:W:", + "M:010001011010:O:", + "M:0100000011110:,:", + "M:0100000011111:':", + "M:0100010110111:D:", + "M:0100010111100:4:", + "M:0100010111110:E:", + "M:01000100111000:m:", + "M:01000100111001:J:", + "M:01000100111010:ESCAPE:", + "M:01000101111010:l:", + "M:01000101111011:-:", + "M:01000101111110:):", + "M:01000101111111:w:", + "M:010001001110110:t:", + "M:010001001110111:V:", + "M:010001011011000:Q:", + "M:010001011011001:N:", + "M:010001011011010:6:", + "M:010001011011011:2:", + "N:00:a:", + "N:10:o:", + "N:11:e:", + "N:011:i:", + "N:01010:u:", + "N:01011:E:", + "N:010010:A:", + "N:0100010:y:", + "N:0100110:g:", + "N:01000001:B:", + "N:01000010:I:", + "N:01000110:F:", + "N:01000111: :", + "N:010000000:):", + "N:010000001:':", + "N:010000111:Y:", + "N:010011100:L:", + "N:010011101:H:", + "N:0100001100:C:", + "N:0100111100:W:", + "N:0100111110:N:", + "N:0100111111:T:", + "N:010000110101:M:", + "N:010000110111:O:", + "N:010011110100:,:", + "N:010011110101:J:", + "N:010011110111:h:", + "N:0100001101000:D:", + "N:0100001101001:.:", + "N:0100111101100:X:", + "N:0100111101101:ESCAPE:", + "N:01000011011000:k:", + "N:01000011011001:Z:", + "N:01000011011010:Q:", + "N:01000011011011:G:", + "O:111:n:", + "O:0000:s:", + "O:0001:N:", + "O:0011:z:", + "O:0100:r:", + "O:1000:u:", + "O:1010:p:", + "O:1011:l:", + "O:1101:':", + "O:00101:U:", + "O:01011:h:", + "O:01110:f:", + "O:01111:w:", + "O:10010:.:", + "O:11000: :", + "O:001000:o:", + "O:001001:J:", + "O:010100:b:", + "O:010101:m:", + "O:011001:H:", + "O:011010:O:", + "O:011011:v:", + "O:100111:c:", + "O:110011:x:", + "O:1001101:d:", + "O:1100100:a:", + "O:01100001:t:", + "O:01100010:k:", + "O:10011000:g:", + "O:11001010:R:", + "O:011000000:K:", + "O:100110010:i:", + "O:110010111:V:", + "O:0110000011:2:", + "O:0110001101:S:", + "O:0110001110:B:", + "O:1001100110:W:", + "O:1001100111:-:", + "O:01100000100:,:", + "O:01100011000:j:", + "O:01100011001:L:", + "O:01100011111:I:", + "O:11001011001:A:", + "O:11001011011:C:", + "O:011000001010:0x3a:", + "O:011000111100:e:", + "O:110010110000:y:", + "O:110010110001:/:", + "O:110010110100:M:", + "O:0110000010110:!:", + "O:0110001111011:P:", + "O:1100101101011:F:", + "O:01100000101110:E:", + "O:01100000101111:D:", + "O:01100011110100:8:", + "O:01100011110101:4:", + "O:11001011010101:T:", + "O:110010110101000:ESCAPE:", + "O:110010110101001:q:", + "P:11:a:", + "P:000:i:", + "P:010:e:", + "P:011:l:", + "P:100:o:", + "P:101:r:", + "P:0010:h:", + "P:001111:u:", + "P:0011010:C:", + "P:0011100:.:", + "P:0011101: :", + "P:00110000:B:", + "P:00110010:D:", + "P:00110111:s:", + "P:001100011:O:", + "P:001100111:,:", + "P:0011000101:y:", + "P:0011001100:M:", + "P:0011011000:E:", + "P:0011011001:':", + "P:0011011011:3:", + "P:00110001001:T:", + "P:001100010000:L:", + "P:001100010001:G:", + "P:001100110100:*:", + "P:001100110110:A:", + "P:001100110111:S:", + "P:001101101000:w:", + "P:001101101001:F:", + "P:0011001101011:J:", + "P:0011011010100:f:", + "P:0011011010101:R:", + "P:0011011010111:t:", + "P:00110011010100:V:", + "P:00110110101100:Y:", + "P:00110110101101:I:", + "P:001100110101011:&:", + "P:0011001101010100:ESCAPE:", + "P:0011001101010101:):", + "Q:1:u:", + "Q:00:V:", + "Q:011: :", + "Q:0101:.:", + "Q:01000:a:", + "Q:0100100:w:", + "Q:0100110:E:", + "Q:0100111:C:", + "Q:01001011:&:", + "Q:010010101:':", + "Q:0100101000:T:", + "Q:01001010010:ESCAPE:", + "Q:01001010011:s:", + "R:01:a:", + "R:11:o:", + "R:100:i:", + "R:101:e:", + "R:0000:p:", + "R:0011:u:", + "R:00011:E:", + "R:00100:h:", + "R:000100: :", + "R:001010:y:", + "R:00010100:D:", + "R:00010110:.:", + "R:00101100:T:", + "R:00101110:S:", + "R:000101010:F:", + "R:001011010:B:", + "R:001011011:n:", + "R:001011111:A:", + "R:0001010110:w:", + "R:0001011100:N:", + "R:0001011101:&:", + "R:0001011110:V:", + "R:0001011111:H:", + "R:0010111101:':", + "R:00010101110:t:", + "R:00010101111:I:", + "R:001011110000:C:", + "R:001011110010:O:", + "R:00101111000100:,:", + "R:00101111000101:s:", + "R:00101111000110:U:", + "R:00101111000111:M:", + "R:00101111001100:-:", + "R:00101111001101:ESCAPE:", + "R:00101111001111:0x3a:", + "R:001011110011100:2:", + "R:001011110011101:R:", + "S:1:]:", + "S:0000:a:", + "S:0010:h:", + "S:0111:t:", + "S:00010:p:", + "S:00011:,:", + "S:00110:L:", + "S:01000:i:", + "S:01001:u:", + "S:01010:o:", + "S:01011:c:", + "S:01100:e:", + "S:001111:k:", + "S:0011100:w:", + "S:0110101: :", + "S:0110111:m:", + "S:00111010:q:", + "S:01101000:M:", + "S:01101001:n:", + "S:01101100:l:", + "S:001110110:P:", + "S:011011011:y:", + "S:0011101110:A:", + "S:01101101001:.:", + "S:001110111101:r:", + "S:001110111110:S:", + "S:001110111111:W:", + "S:011011010000:C:", + "S:011011010101:E:", + "S:011011010110:v:", + "S:0110110100011:ESCAPE:", + "S:0110110101000:I:", + "S:0110110101111:g:", + "S:00111011110000:*:", + "S:00111011110010:4:", + "S:00111011110011:1:", + "S:01101101000100:O:", + "S:01101101010010:STOP:", + "S:01101101011100:z:", + "S:011011010001011:B:", + "S:011011010111010:H:", + "S:011011010111011:T:", + "S:0011101111000100:G:", + "S:0011101111000110:}:", + "S:0011101111000111:D:", + "S:0110110100010100:-:", + "S:0110110101001100:3:", + "S:0110110101001101:2:", + "S:00111011110001010:':", + "S:00111011110001011:?:", + "S:01101101010011101:s:", + "S:01101101010011110:j:", + "S:01101101010011111:b:", + "S:011011010001010100:R:", + "S:011011010001010101:K:", + "S:011011010001010110:J:", + "S:011011010001010111:F:", + "S:011011010100111000:0x3a:", + "S:011011010100111001:):", + "T:0:h:", + "T:100:o:", + "T:1010:V:", + "T:1011:w:", + "T:1100:r:", + "T:1111:e:", + "T:11010:a:", + "T:11011:i:", + "T:11100:u:", + "T:1110100:H:", + "T:1110110:W:", + "T:11101010: :", + "T:11101011:y:", + "T:111011101:M:", + "T:111011111:x:", + "T:1110111000:S:", + "T:11101110010:A:", + "T:11101111001:s:", + "T:11101111011:J:", + "T:111011100111:X:", + "T:111011110000:.:", + "T:1110111001101:-:", + "T:1110111100011:L:", + "T:1110111101000:C:", + "T:1110111101011:c:", + "T:11101110011000:T:", + "T:11101110011001:U:", + "T:11101111000101:4:", + "T:11101111010010:O:", + "T:111011110001001:G:", + "T:111011110100110:E:", + "T:111011110100111:,:", + "T:111011110101010:':", + "T:1110111100010001:;:", + "T:1110111101010000:P:", + "T:1110111101010001:1:", + "T:1110111101010010:ESCAPE:", + "T:1110111101010111:D:", + "T:11101111000100000:0x3a:", + "T:11101111000100001:*:", + "T:11101111010100110:R:", + "T:11101111010100111:N:", + "T:11101111010101100:I:", + "T:11101111010101101:B:", + "U:00:K:", + "U:10:n:", + "U:011:S:", + "U:110:p:", + "U:1111:l:", + "U:01010:s:", + "U:01011:r:", + "U:11101:R:", + "U:010000:g:", + "U:111000: :", + "U:0100111:.:", + "U:1110010:m:", + "U:01000100:k:", + "U:01000101:t:", + "U:01000110:E:", + "U:01000111:-:", + "U:01001000:F:", + "U:01001100:2:", + "U:11100110:c:", + "U:11100111:N:", + "U:010010010:f:", + "U:010010011:8:", + "U:010010100:,:", + "U:010010111:Z:", + "U:0100101010:h:", + "U:0100110100:i:", + "U:0100110101:w:", + "U:0100110110:a:", + "U:01001010110:b:", + "U:01001010111:D:", + "U:01001101110:!:", + "U:010010110000:e:", + "U:010010110001:V:", + "U:010010110010:P:", + "U:010010110011:I:", + "U:010010110100:B:", + "U:010010110101:A:", + "U:010011011111:d:", + "U:0100101101100:H:", + "U:0100101101101:C:", + "U:0100101101110:0x3a:", + "U:0100101101111:):", + "U:0100110111101:z:", + "U:01001101111000:ESCAPE:", + "U:01001101111001:T:", + "V:01: :", + "V:11:i:", + "V:000:.:", + "V:001:a:", + "V:101:e:", + "V:10001:C:", + "V:10011:o:", + "V:1000001:F:", + "V:1000011:I:", + "V:10000001:1:", + "V:10000101:4:", + "V:10010000:r:", + "V:10010010:E:", + "V:10010011:s:", + "V:10010101:':", + "V:10010110:0x3a:", + "V:10010111:l:", + "V:100000001:/:", + "V:100001001:-:", + "V:100100010:D:", + "V:100100011:u:", + "V:100101001:,:", + "V:1000000000:6:", + "V:1000000001:2:", + "V:1000010000:5:", + "V:1001010000:;:", + "V:10010100010:ESCAPE:", + "V:100001000100:7:", + "V:100101000110:3:", + "V:1000010001010:9:", + "V:1000010001011:y:", + "V:1000010001100:P:", + "V:1000010001101:H:", + "V:1000010001110:A:", + "V:1000010001111:8:", + "V:1001010001111:W:", + "V:10010100011100:f:", + "V:10010100011101:B:", + "W:00:h:", + "W:10:i:", + "W:011:a:", + "W:110:o:", + "W:111:e:", + "W:0100:r:", + "W:01011:O:", + "W:0101001: :", + "W:0101010:y:", + "W:010100000:B:", + "W:010100001:.:", + "W:010101100:I:", + "W:010101110:W:", + "W:010101111:A:", + "W:0101000100:':", + "W:0101000101:M:", + "W:0101000111:T:", + "W:01010001100:2:", + "W:01010001101:0x3a:", + "W:01010110100:H:", + "W:01010110110:V:", + "W:010101101010:l:", + "W:010101101110:s:", + "W:010101101111:,:", + "W:0101011010111:u:", + "W:010101101011000:5:", + "W:010101101011001:):", + "W:010101101011011:E:", + "W:0101011010110100:ESCAPE:", + "W:0101011010110101:m:", + "X:1: :", + "X:000:a:", + "X:0010:z:", + "X:0011:m:", + "X:0111:t:", + "X:01001:U:", + "X:01010:-:", + "X:01011:e:", + "X:011000:u:", + "X:011001:I:", + "X:011011:,:", + "X:0100010:V:", + "X:0110100:5:", + "X:0110101:.:", + "X:01000000:S:", + "X:01000010:0x3a:", + "X:01000110:c:", + "X:01000111:i:", + "X:010000010:9:", + "X:010000011:':", + "X:010000111:X:", + "X:0100001100:):", + "X:01000011010:ESCAPE:", + "X:01000011011:y:", + "Y:1:o:", + "Y:00:e:", + "Y:010:u:", + "Y:01100:a:", + "Y:01110:v:", + "Y:01111: :", + "Y:0110100:n:", + "Y:01101010:r:", + "Y:01101101:O:", + "Y:01101111:i:", + "Y:011010111:N:", + "Y:011011000:L:", + "Y:011011001:s:", + "Y:011011101:m:", + "Y:0110101100:.:", + "Y:0110101101:M:", + "Y:0110111001:P:", + "Y:011011100001:R:", + "Y:011011100010:2:", + "Y:0110111000000:-:", + "Y:0110111000110:C:", + "Y:0110111000111:,:", + "Y:01101110000010:ESCAPE:", + "Y:01101110000011:d:", + "Z:01:a:", + "Z:10:e:", + "Z:11:o:", + "Z:0010:z:", + "Z:0011:i:", + "Z:00001:Z:", + "Z:00010: :", + "Z:00011:u:", + "Z:0000010:O:", + "Z:0000011:.:", + "Z:00000000:y:", + "Z:00000001:4:", + "Z:00000010:,:", + "Z:0000001100:f:", + "Z:0000001101:-:", + "Z:0000001110:STOP:", + "Z:00000011110:ESCAPE:", + "Z:00000011111:l:", + "[:1:S:", + "[:01:A:", + "[:0000:2:", + "[:0010:R:", + "[:0011:1:", + "[:000101:n:", + "[:000110:m:", + "[:0001111:l:", + "[:00010011:r:", + "[:00011101:b:", + "[:000100001:C:", + "[:000100010:f:", + "[:000100101:M:", + "[:000111001:c:", + "[:0001000001:STOP:", + "[:0001000111:K:", + "[:0001001000:H:", + "[:0001110001:T:", + "[:00010000000:J:", + "[:00010000001:B:", + "[:00010001101:Z:", + "[:00010010011:P:", + "[:00011100000:L:", + "[:000100011000:F:", + "[:000100100101:I:", + "[:000111000011:N:", + "[:0001000110010:s:", + "[:0001000110011:V:", + "[:0001001001000:U:", + "[:0001001001001:G:", + "[:0001110000101:D:", + "[:00011100001000:O:", + "[:000111000010010:ESCAPE:", + "[:000111000010011:W:", + "\\:0:ESCAPE:", + "\\:1:x:", + "]:1:STOP:", + "]:01: :", + "]:001:.:", + "]:0001:[:", + "]:00001:0x3a:", + "]:000001:,:", + "]:0000001:;:", + "]:00000000:ESCAPE:", + "]:00000001:]:", + "^:0:ESCAPE:", + "^:1:ESCAPE:", + "_:0:ESCAPE:", + "_:1:ESCAPE:", + "`:001:w:", + "`:011:H:", + "`:110:P:", + "`:111:F:", + "`:0101:n:", + "`:1011:D:", + "`:00001:s:", + "`:00010:A:", + "`:01001:t:", + "`:10000:g:", + "`:10011:c:", + "`:000000:W:", + "`:000001:r:", + "`:000110:e:", + "`:000111:C:", + "`:100011:l:", + "`:100100:h:", + "`:100101:G:", + "`:101001:B:", + "`:101010:T:", + "`:101011:S:", + "`:0100000:o:", + "`:0100001:d:", + "`:0100010:b:", + "`:0100011:R:", + "`:1000100:O:", + "`:1000101:L:", + "`:1010001:f:", + "`:10100000:J:", + "`:101000010:ESCAPE:", + "`:101000011:M:", + "a:01:n:", + "a:001:r:", + "a:101:t:", + "a:0000:m:", + "a:1001:s:", + "a:1110: :", + "a:1111:l:", + "a:00011:d:", + "a:10000:i:", + "a:11000:y:", + "a:11010:c:", + "a:000100:p:", + "a:100010:u:", + "a:100011:v:", + "a:110011:g:", + "a:110110:b:", + "a:110111:k:", + "a:0001010:w:", + "a:00010111:z:", + "a:11001000:.:", + "a:11001011:f:", + "a:000101100:,:", + "a:000101101:':", + "a:110010011:e:", + "a:110010101:h:", + "a:1100101001:x:", + "a:11001001000:a:", + "a:11001001001:-:", + "a:11001001011:j:", + "a:11001010000:0x3a:", + "a:11001010001:o:", + "a:110010010100:q:", + "a:11001001010100:!:", + "a:11001001010111:?:", + "a:1100100101010100:ESCAPE:", + "a:1100100101010110:;:", + "a:1100100101010111:):", + "a:1100100101011001:/:", + "a:1100100101011011:@:", + "a:11001001010101010:J:", + "a:11001001010101011:]:", + "a:11001001010110100:N:", + "a:11001001010110101:L:", + "a:110010010101100000:R:", + "a:110010010101100001:S:", + "a:110010010101100010:V:", + "a:11001001010110001100:[:", + "a:11001001010110001110:P:", + "a:11001001010110001111:STOP:", + "a:110010010101100011010:W:", + "a:110010010101100011011:1:", + "b:00:e:", + "b:010:u:", + "b:011:a:", + "b:100:y:", + "b:101:o:", + "b:1100:l:", + "b:1110:r:", + "b:1111:i:", + "b:110100:s:", + "b:110110: :", + "b:110111:b:", + "b:11010101:c:", + "b:110101000:j:", + "b:110101100:,:", + "b:110101101:.:", + "b:1101010011:':", + "b:1101011111:t:", + "b:11010100101:0x3a:", + "b:11010111000:w:", + "b:11010111001:d:", + "b:11010111010:h:", + "b:11010111011:&:", + "b:11010111101:-:", + "b:110101111000:m:", + "b:110101111001:n:", + "b:1101010010000:?:", + "b:1101010010010:v:", + "b:11010100100010:f:", + "b:11010100100111:p:", + "b:110101001000111:;:", + "b:110101001001101:D:", + "b:1101010010001100:/:", + "b:1101010010011001:@:", + "b:11010100100011010:X:", + "b:11010100100011011:\":", + "b:11010100100110001:k:", + "b:110101001001100000:STOP:", + "b:1101010010011000010:ESCAPE:", + "b:1101010010011000011:!:", + "c:00:o:", + "c:011:a:", + "c:100:e:", + "c:110:h:", + "c:0100:i:", + "c:0101:l:", + "c:1011:k:", + "c:1111:t:", + "c:10100:u:", + "c:10101:r:", + "c:11100: :", + "c:1110100:y:", + "c:1110101:c:", + "c:11101101:s:", + "c:11101110:.:", + "c:111011111:,:", + "c:1110110001:G:", + "c:11101100001:n:", + "c:11101100110:D:", + "c:11101111000:K:", + "c:11101111011:C:", + "c:111011000000:0x3a:", + "c:111011001001:-:", + "c:111011001010:A:", + "c:111011001110:L:", + "c:111011001111:':", + "c:111011110010:d:", + "c:111011110100:q:", + "c:111011110101:I:", + "c:1110110010000:N:", + "c:1110110010001:z:", + "c:1110111100111:F:", + "c:11101100000101:w:", + "c:11101100000111:E:", + "c:11101100101100:?:", + "c:11101111001100:M:", + "c:11101111001101:S:", + "c:111011000001000:b:", + "c:111011000001001:ESCAPE:", + "c:111011000001100:!:", + "c:111011001011010:Q:", + "c:111011001011011:P:", + "c:111011001011100:;:", + "c:111011001011110:B:", + "c:1110110000011011:V:", + "c:1110110010111011:m:", + "c:1110110010111110:/:", + "c:11101100000110101:):", + "c:11101100101110100:U:", + "c:11101100101111110:W:", + "c:111011000001101000:p:", + "c:111011000001101001:H:", + "c:111011001011101010:STOP:", + "c:111011001011111110:R:", + "c:111011001011111111:T:", + "c:1110110010111010110:]:", + "c:1110110010111010111:[:", + "d:0: :", + "d:101:e:", + "d:1100:a:", + "d:1110:i:", + "d:10001:.:", + "d:10011:o:", + "d:11011:r:", + "d:11111:s:", + "d:100001:d:", + "d:100101:l:", + "d:110100:u:", + "d:111101:y:", + "d:1001001:-:", + "d:1101011:v:", + "d:1111000:g:", + "d:1111001:,:", + "d:10000000:h:", + "d:10000001:0x3a:", + "d:10000010:m:", + "d:10010000:w:", + "d:10010001:n:", + "d:11010101:':", + "d:100000111:f:", + "d:1101010001:?:", + "d:1101010010:b:", + "d:1101010011:c:", + "d:10000011000:!:", + "d:11010100000:p:", + "d:11010100001:t:", + "d:100000110010:STOP:", + "d:100000110011:):", + "d:100000110100:k:", + "d:100000110101:;:", + "d:100000110111:/:", + "d:10000011011010:\":", + "d:10000011011011:j:", + "d:100000110110000:z:", + "d:100000110110011:q:", + "d:1000001101100011:@:", + "d:1000001101100100:ESCAPE:", + "d:10000011011000101:C:", + "d:10000011011001010:]:", + "d:100000110110001000:Z:", + "d:100000110110001001:[:", + "d:100000110110010110:T:", + "d:100000110110010111:`:", + "e:10: :", + "e:010:s:", + "e:110:r:", + "e:0000:d:", + "e:0011:a:", + "e:1111:n:", + "e:00010:c:", + "e:01100:e:", + "e:01101:w:", + "e:01111:t:", + "e:11100:l:", + "e:000110:x:", + "e:001000:v:", + "e:001001:i:", + "e:001010:y:", + "e:011100:m:", + "e:111010:.:", + "e:0001110:f:", + "e:0010111:b:", + "e:0111010:,:", + "e:1110110:p:", + "e:00011110:-:", + "e:00011111:h:", + "e:00101100:k:", + "e:01110110:':", + "e:11101110:g:", + "e:11101111:o:", + "e:001011011:0x3a:", + "e:0010110100:):", + "e:0010110101:q:", + "e:0111011101:?:", + "e:0111011110:u:", + "e:01110111000:z:", + "e:01110111110:!:", + "e:011101111110:STOP:", + "e:011101111111:j:", + "e:0111011100110:/:", + "e:01110111001001:4:", + "e:01110111001010:B:", + "e:01110111001110:]:", + "e:01110111001111:;:", + "e:011101110010000:\":", + "e:0111011100100011:D:", + "e:0111011100101100:ESCAPE:", + "e:0111011100101110:@:", + "e:01110111001000100:T:", + "e:01110111001000101:C:", + "e:01110111001011011:[:", + "e:01110111001011111:L:", + "e:011101110010110100:V:", + "e:011101110010110101:G:", + "e:011101110010111100:1:", + "e:01110111001011110101:E:", + "e:011101110010111101000:2:", + "e:011101110010111101001:N:", + "e:011101110010111101100:F:", + "e:011101110010111101101:A:", + "e:0111011100101111011100:\\:", + "e:0111011100101111011101:P:", + "e:0111011100101111011110:M:", + "e:0111011100101111011111:H:", + "f:00:o:", + "f:10: :", + "f:010:i:", + "f:110:r:", + "f:0111:a:", + "f:1110:e:", + "f:01100:t:", + "f:11110:u:", + "f:11111:f:", + "f:011011:l:", + "f:01101000:s:", + "f:01101001:y:", + "f:011010110:.:", + "f:0110101000:?:", + "f:0110101011:,:", + "f:0110101111:-:", + "f:01101010011:0x3a:", + "f:01101010100:':", + "f:01101010101:g:", + "f:011010100100:m:", + "f:011010111000:ESCAPE:", + "f:011010111010:b:", + "f:011010111011:n:", + "f:0110101001011:c:", + "f:0110101110010:!:", + "f:01101011100110:):", + "f:01101011100111:w:", + "f:011010100101001:p:", + "f:011010100101010:/:", + "f:0110101001010000:h:", + "f:0110101001010110:;:", + "f:01101010010100010:STOP:", + "f:01101010010100011:d:", + "f:01101010010101110:k:", + "f:01101010010101111:v:", + "g:11: :", + "g:000:a:", + "g:010:h:", + "g:101:e:", + "g:0011:u:", + "g:0110:r:", + "g:1000:i:", + "g:01110:l:", + "g:10010:s:", + "g:10011:o:", + "g:001001:,:", + "g:001010:n:", + "g:011110:g:", + "g:011111:.:", + "g:0010110:y:", + "g:00100001:':", + "g:00100010:-:", + "g:00100011:0x3a:", + "g:001000000:d:", + "g:001011101:b:", + "g:001011110:t:", + "g:001011111:w:", + "g:0010000010:?:", + "g:0010000011:m:", + "g:00101110001:!:", + "g:00101110011:f:", + "g:001011100001:;:", + "g:001011100101:STOP:", + "g:0010111000000:k:", + "g:0010111001000:p:", + "g:00101110000010:):", + "g:00101110000011:\":", + "g:001011100100101:c:", + "g:001011100100111:/:", + "g:0010111001001000:ESCAPE:", + "g:0010111001001100:]:", + "g:0010111001001101:z:", + "g:00101110010010010:`:", + "g:001011100100100110:v:", + "g:001011100100100111:@:", + "h:0:e:", + "h:100:o:", + "h:101:i:", + "h:110: :", + "h:1111:a:", + "h:111001:r:", + "h:111011:t:", + "h:11100001:y:", + "h:11100011:l:", + "h:11101000:.:", + "h:11101001:n:", + "h:11101011:u:", + "h:111000000:d:", + "h:111000100:s:", + "h:111010100:,:", + "h:1110000011:w:", + "h:1110001010:':", + "h:1110001011:-:", + "h:11101010101:m:", + "h:11101010110:0x3a:", + "h:11101010111:b:", + "h:111000001001:c:", + "h:111000001011:?:", + "h:111010101000:!:", + "h:1110000010000:):", + "h:1110000010100:h:", + "h:1110000010101:k:", + "h:1110101010011:f:", + "h:11101010100101:g:", + "h:111000001000100:p:", + "h:111000001000101:;:", + "h:111000001000110:/:", + "h:111000001000111:STOP:", + "h:111010101001001:v:", + "h:1110101010010000:q:", + "h:11101010100100010:ESCAPE:", + "h:111010101001000110:\":", + "h:11101010100100011100:z:", + "h:11101010100100011101:j:", + "h:11101010100100011110:]:", + "h:11101010100100011111:*:", + "i:10:n:", + "i:000:t:", + "i:010:s:", + "i:0011:l:", + "i:1100:o:", + "i:1101:c:", + "i:1111:e:", + "i:00100:a:", + "i:01100:m:", + "i:01101:d:", + "i:01110:v:", + "i:11100:g:", + "i:11101:r:", + "i:001010:p:", + "i:011110:f:", + "i:0010110:z:", + "i:0111110: :", + "i:00101111:b:", + "i:01111110:k:", + "i:001011100:-:", + "i:001011101:x:", + "i:0111111100:u:", + "i:0111111110:q:", + "i:01111111010:.:", + "i:01111111110:,:", + "i:011111110111:w:", + "i:011111111111:':", + "i:0111111101101:i:", + "i:0111111111101:j:", + "i:01111111011001:0x3a:", + "i:01111111111000:h:", + "i:011111110110000:/:", + "i:011111111110011:y:", + "i:0111111101100011:?:", + "i:0111111111100100:P:", + "i:01111111011000101:R:", + "i:01111111111001011:!:", + "i:011111111110010100:):", + "i:011111111110010101:S:", + "i:0111111101100010000:STOP:", + "i:0111111101100010001:C:", + "i:0111111101100010010:ESCAPE:", + "i:01111111011000100110:D:", + "i:01111111011000100111:;:", + "j:0:o:", + "j:11:u:", + "j:101:a:", + "j:1001:e:", + "j:10000:i:", + "j:100011:y:", + "j:1000101: :", + "j:10001001:.:", + "j:100010000:':", + "j:1000100011:t:", + "j:10001000100:n:", + "j:100010001011:s:", + "j:1000100010100:ESCAPE:", + "j:1000100010101:h:", + "k:10: :", + "k:11:e:", + "k:000:s:", + "k:011:i:", + "k:0010:.:", + "k:01001:y:", + "k:001100:':", + "k:001101:a:", + "k:001110:p:", + "k:001111:,:", + "k:010100:l:", + "k:010101:f:", + "k:010110:n:", + "k:0100000:/:", + "k:0100010:-:", + "k:0100011:o:", + "k:01011101:0x3a:", + "k:010000111:b:", + "k:010111000:w:", + "k:010111001:m:", + "k:010111100:h:", + "k:010111110:u:", + "k:010111111:k:", + "k:0100001000:r:", + "k:0100001001:ESCAPE:", + "k:0100001010:?:", + "k:0100001100:t:", + "k:0100001101:g:", + "k:0101111011:d:", + "k:01000010110:j:", + "k:010000101110:):", + "k:010111101000:;:", + "k:010111101001:c:", + "k:010111101010:S:", + "k:0100001011110:v:", + "k:0100001011111:R:", + "k:0101111010110:!:", + "k:01011110101110:@:", + "k:010111101011110:\":", + "k:010111101011111:STOP:", + "l:010:a:", + "l:011:i:", + "l:100:l:", + "l:110:e:", + "l:111: :", + "l:0000:u:", + "l:0001:d:", + "l:0010:y:", + "l:1011:o:", + "l:10100:s:", + "l:001100:.:", + "l:001110:t:", + "l:0011010:v:", + "l:0011110:f:", + "l:1010100:m:", + "l:1010101:k:", + "l:1010110:p:", + "l:00110111:c:", + "l:00111110:-:", + "l:10101111:,:", + "l:001101101:0x3a:", + "l:001111111:b:", + "l:101011100:':", + "l:0011011000:r:", + "l:0011011001:h:", + "l:0011111100:n:", + "l:0011111101:g:", + "l:1010111011:w:", + "l:10101110100:?:", + "l:1010111010100:!:", + "l:1010111010110:z:", + "l:10101110101011:/:", + "l:101011101010100:;:", + "l:101011101011100:E:", + "l:101011101011101:*:", + "l:101011101011111:STOP:", + "l:1010111010101011:ESCAPE:", + "l:1010111010111100:):", + "l:10101110101010100:@:", + "l:10101110101010101:j:", + "l:10101110101111010:\":", + "l:101011101011110110:[:", + "l:101011101011110111:]:", + "m:00:a:", + "m:01:e:", + "m:111: :", + "m:1001:p:", + "m:1011:o:", + "m:1100:i:", + "m:10000:.:", + "m:10001:s:", + "m:11010:u:", + "m:11011:m:", + "m:101001:y:", + "m:101011:b:", + "m:1010000:,:", + "m:1010100:/:", + "m:10100010:]:", + "m:101000110:0x3a:", + "m:101010100:':", + "m:1010001111:r:", + "m:1010101011:f:", + "m:1010101100:l:", + "m:1010101110:n:", + "m:10100011100:?:", + "m:10100011101:!:", + "m:10101010100:STOP:", + "m:10101010101:w:", + "m:10101011011:h:", + "m:10101011110:-:", + "m:101010111110:4:", + "m:1010101101010:t:", + "m:1010101101011:@:", + "m:1010101111110:;:", + "m:1010101111111:c:", + "m:10101011010000:):", + "m:10101011010001:ESCAPE:", + "m:10101011010011:d:", + "m:101010110100101:g:", + "m:10101011010010000:[:", + "m:10101011010010001:v:", + "m:10101011010010010:k:", + "m:10101011010010011:z:", + "n:01: :", + "n:001:t:", + "n:100:g:", + "n:111:d:", + "n:0000:s:", + "n:1010:a:", + "n:1101:e:", + "n:10110:c:", + "n:11000:i:", + "n:000111:.:", + "n:101111:n:", + "n:110011:o:", + "n:0001001:u:", + "n:0001011:v:", + "n:0001100:f:", + "n:1011100:k:", + "n:1011101:':", + "n:1100100:y:", + "n:1100101:,:", + "n:00010000:m:", + "n:00010100:l:", + "n:00010101:-:", + "n:000100011:w:", + "n:000110101:0x3a:", + "n:0001000101:z:", + "n:0001101000:h:", + "n:0001101100:b:", + "n:0001101101:j:", + "n:0001101110:r:", + "n:00010001000:p:", + "n:00011010011:x:", + "n:00011011111:?:", + "n:000100010011:;:", + "n:000110100101:):", + "n:000110111100:!:", + "n:000110111101:q:", + "n:0001000100100:/:", + "n:0001000100101:STOP:", + "n:0001101001000:ESCAPE:", + "n:00011010010010:B:", + "n:0001101001001100:]:", + "n:0001101001001101:\":", + "n:0001101001001110:@:", + "n:0001101001001111:*:", + "o:001:u:", + "o:011: :", + "o:100:r:", + "o:111:n:", + "o:0000:l:", + "o:1100:m:", + "o:1101:f:", + "o:00010:v:", + "o:01000:s:", + "o:01001:p:", + "o:10100:t:", + "o:10101:o:", + "o:10111:w:", + "o:000110:k:", + "o:000111:i:", + "o:010100:g:", + "o:010111:c:", + "o:101101:d:", + "o:0101011:e:", + "o:0101100:y:", + "o:0101101:a:", + "o:1011001:b:", + "o:01010101:h:", + "o:10110000:.:", + "o:010101000:-:", + "o:010101001:,:", + "o:1011000101:':", + "o:1011000111:x:", + "o:10110001001:0x3a:", + "o:10110001101:z:", + "o:101100010001:?:", + "o:101100011001:j:", + "o:1011000100000:!:", + "o:1011000110001:q:", + "o:10110001000010:J:", + "o:10110001100000:/:", + "o:10110001100001:):", + "o:1011000100001101:;:", + "o:1011000100001110:G:", + "o:10110001000011000:\":", + "o:10110001000011110:ESCAPE:", + "o:101100010000110010:]:", + "o:101100010000110011:@:", + "o:1011000100001111100:4:", + "o:1011000100001111101:STOP:", + "o:1011000100001111110:B:", + "o:10110001000011111110:O:", + "o:10110001000011111111:C:", + "p:001:l:", + "p:010: :", + "p:011:o:", + "p:101:r:", + "p:111:e:", + "p:0000:p:", + "p:1100:a:", + "p:1101:i:", + "p:00011:t:", + "p:10000:u:", + "p:10001:h:", + "p:10010:s:", + "p:000101:m:", + "p:0001001:d:", + "p:1001101:y:", + "p:1001110:.:", + "p:1001111:,:", + "p:00010000:-:", + "p:000100011:?:", + "p:100110001:0x3a:", + "p:1001100100:':", + "p:1001100101:]:", + "p:1001100110:+:", + "p:1001100111:b:", + "p:00010001001:f:", + "p:00010001010:k:", + "p:00010001011:!:", + "p:10011000001:c:", + "p:10011000010:n:", + "p:10011000011:w:", + "p:000100010000:STOP:", + "p:000100010001:;:", + "p:100110000001:/:", + "p:1001100000001:g:", + "p:10011000000001:):", + "p:100110000000001:\":", + "p:1001100000000001:S:", + "p:10011000000000000:ESCAPE:", + "p:10011000000000001:B:", + "q:1:u:", + "q:000:,:", + "q:001:.:", + "q:011: :", + "q:01001:b:", + "q:01010:':", + "q:01011:i:", + "q:010001:a:", + "q:01000000:?:", + "q:01000001:0x3a:", + "q:01000011:):", + "q:010000100:ESCAPE:", + "q:010000101:w:", + "r:000:a:", + "r:001:o:", + "r:100:i:", + "r:110: :", + "r:111:e:", + "r:0100:s:", + "r:0101:t:", + "r:01110:d:", + "r:10100:n:", + "r:10101:y:", + "r:011010:u:", + "r:011011:m:", + "r:011111:k:", + "r:101101:l:", + "r:101110:.:", + "r:101111:r:", + "r:0110000:f:", + "r:0110010:,:", + "r:0110011:v:", + "r:1011000:c:", + "r:1011001:g:", + "r:01100011:':", + "r:01111000:-:", + "r:01111001:b:", + "r:01111011:p:", + "r:011000101:0x3a:", + "r:011110100:w:", + "r:0111101010:?:", + "r:0111101011:h:", + "r:01100010010:!:", + "r:011000100001:q:", + "r:011000100010:j:", + "r:011000100011:STOP:", + "r:011000100110:/:", + "r:0110001000001:;:", + "r:0110001001111:):", + "r:01100010011100:8:", + "r:01100010011101:z:", + "r:011000100000001:\":", + "r:011000100000011:]:", + "r:0110001000000000:T:", + "r:0110001000000100:x:", + "r:0110001000000101:ESCAPE:", + "r:01100010000000011:Z:", + "r:011000100000000100:*:", + "r:0110001000000001010:D:", + "r:0110001000000001011:B:", + "s:0: :", + "s:101:t:", + "s:1000:.:", + "s:1110:e:", + "s:10011:,:", + "s:11000:o:", + "s:11001:s:", + "s:11110:h:", + "s:11111:i:", + "s:100101:c:", + "s:110100:u:", + "s:110110:p:", + "s:1101111:a:", + "s:10010001:n:", + "s:10010011:m:", + "s:11010100:y:", + "s:11010110:0x3a:", + "s:11011100:l:", + "s:11011101:k:", + "s:100100001:b:", + "s:100100100:f:", + "s:110101010:w:", + "s:110101111:':", + "s:1001000000:!:", + "s:1001000001:g:", + "s:1001001010:r:", + "s:1101010110:?:", + "s:1101010111:-:", + "s:1101011101:q:", + "s:11010111001:d:", + "s:100100101100:/:", + "s:100100101101:):", + "s:100100101111:STOP:", + "s:110101110000:]:", + "s:110101110001:;:", + "s:1001001011101:v:", + "s:100100101110001:\":", + "s:100100101110011:z:", + "s:1001001011100000:j:", + "s:1001001011100001:ESCAPE:", + "s:1001001011100100:[:", + "s:10010010111001011:@:", + "s:100100101110010101:T:", + "s:1001001011100101000:x:", + "s:1001001011100101001:`:", + "t:10:h:", + "t:000:i:", + "t:010:o:", + "t:011:e:", + "t:111: :", + "t:0010:a:", + "t:00110:u:", + "t:11001:r:", + "t:11011:s:", + "t:001111:.:", + "t:110001:t:", + "t:110100:y:", + "t:0011101:c:", + "t:1100001:l:", + "t:00111001:-:", + "t:11000000:v:", + "t:11000001:m:", + "t:11010101:w:", + "t:11010110:,:", + "t:11010111:':", + "t:001110000:n:", + "t:0011100011:?:", + "t:1101010001:b:", + "t:1101010010:0x3a:", + "t:00111000100:!:", + "t:11010100000:z:", + "t:11010100110:d:", + "t:11010100111:f:", + "t:110101000010:x:", + "t:0011100010100:g:", + "t:0011100010101:;:", + "t:1101010000110:p:", + "t:00111000101100:P:", + "t:00111000101101:STOP:", + "t:00111000101111:):", + "t:11010100001110:/:", + "t:11010100001111:k:", + "t:0011100010111000:@:", + "t:0011100010111010:E:", + "t:00111000101110011:]:", + "t:00111000101110111:\":", + "t:001110001011100100:F:", + "t:001110001011101100:ESCAPE:", + "t:0011100010111001010:j:", + "t:0011100010111011010:1:", + "t:0011100010111011011:[:", + "t:00111000101110010110:\\:", + "t:001110001011100101110:K:", + "t:001110001011100101111:C:", + "u:011:t:", + "u:101:n:", + "u:110:s:", + "u:111:r:", + "u:0001:d:", + "u:0010:e:", + "u:0101:l:", + "u:1000:p:", + "u:00000:b:", + "u:00001: :", + "u:00110:i:", + "u:01000:a:", + "u:01001:g:", + "u:10010:c:", + "u:10011:m:", + "u:0011100:y:", + "u:00111010:z:", + "u:00111100:':", + "u:00111110:f:", + "u:00111111:k:", + "u:001111010:,:", + "u:0011101101:-:", + "u:0011101110:o:", + "u:0011110110:.:", + "u:0011110111:x:", + "u:00111011000:w:", + "u:00111011110:0x3a:", + "u:001110110010:q:", + "u:001110111110:h:", + "u:001110111111:v:", + "u:0011101100110:j:", + "u:001110110011100:u:", + "u:001110110011101:?:", + "u:0011101100111110:/:", + "u:0011101100111111:!:", + "u:00111011001111001:ESCAPE:", + "u:001110110011110000:\\:", + "u:001110110011110001:STOP:", + "u:001110110011110100:;:", + "u:001110110011110110:J:", + "u:001110110011110111:):", + "u:0011101100111101010:T:", + "u:0011101100111101011:]:", + "v:1:e:", + "v:01:i:", + "v:000:a:", + "v:0011:o:", + "v:00101:.:", + "v:001001: :", + "v:00100001:':", + "v:00100011:y:", + "v:001000000:u:", + "v:001000100:s:", + "v:0010001010:r:", + "v:00100000100:-:", + "v:00100000110:,:", + "v:00100010110:n:", + "v:001000001010:g:", + "v:001000001011:v:", + "v:001000001111:l:", + "v:001000101110:@:", + "v:001000101111:0x3a:", + "v:0010000011101:k:", + "v:00100000111000:b:", + "v:001000001110010:t:", + "v:0010000011100110:d:", + "v:00100000111001110:/:", + "v:001000001110011110:ESCAPE:", + "v:001000001110011111:1:", + "w:00:i:", + "w:011:e:", + "w:100: :", + "w:101:s:", + "w:110:h:", + "w:0101:a:", + "w:1111:o:", + "w:01000:.:", + "w:01001:w:", + "w:11100:n:", + "w:1110110:r:", + "w:11101010:,:", + "w:11101011:l:", + "w:11101111:y:", + "w:111010010:c:", + "w:111011101:b:", + "w:1110100010:0x3a:", + "w:1110100110:m:", + "w:1110100111:':", + "w:1110111000:d:", + "w:11101000000:f:", + "w:11101000001:]:", + "w:11101000010:!:", + "w:11101000111:k:", + "w:11101110010:-:", + "w:111010000111:g:", + "w:111010001100:?:", + "w:111010001101:t:", + "w:111011100111:p:", + "w:1110100001100:STOP:", + "w:1110100001101:u:", + "w:1110111001101:):", + "w:11101110011001:j:", + "w:111011100110001:q:", + "w:1110111001100000:/:", + "w:11101110011000010:;:", + "w:111011100110000111:[:", + "w:1110111001100001100:ESCAPE:", + "w:1110111001100001101:B:", + "x:01:p:", + "x:11:t:", + "x:101: :", + "x:0000:i:", + "x:0010:a:", + "x:1000:c:", + "x:00010:u:", + "x:00111:e:", + "x:10011:-:", + "x:000110:f:", + "x:001101:o:", + "x:100100:.:", + "x:0001110:,:", + "x:0001111:m:", + "x:0011001:y:", + "x:00110001:9:", + "x:10010101:':", + "x:10010110:q:", + "x:001100000:s:", + "x:100101000:0x3a:", + "x:100101110:h:", + "x:0011000011:?:", + "x:1001010010:l:", + "x:1001011110:w:", + "x:00110000100:A:", + "x:10010100110:x:", + "x:10010100111:b:", + "x:10010111111:):", + "x:001100001011:/:", + "x:0011000010100:4:", + "x:0011000010101:!:", + "x:1001011111000:g:", + "x:1001011111001:STOP:", + "x:1001011111011:;:", + "x:100101111101001:v:", + "x:100101111101010:F:", + "x:100101111101011:E:", + "x:1001011111010000:ESCAPE:", + "x:1001011111010001:C:", + "y:1: :", + "y:000:o:", + "y:0011:s:", + "y:0101:.:", + "y:01001:,:", + "y:01100:e:", + "y:01110:':", + "y:001001:a:", + "y:001010:i:", + "y:001011:d:", + "y:010001:n:", + "y:011011:0x3a:", + "y:011111:l:", + "y:0010000:w:", + "y:0110100:t:", + "y:0110101:m:", + "y:0111101:-:", + "y:00100011:b:", + "y:01000000:?:", + "y:01000001:r:", + "y:01000010:p:", + "y:01000011:f:", + "y:01111001:c:", + "y:0010001001:;:", + "y:0010001010:J:", + "y:0111100000:h:", + "y:0111100001:!:", + "y:0111100011:g:", + "y:00100010000:):", + "y:00100010111:/:", + "y:01111000101:]:", + "y:001000100011:k:", + "y:001000101100:ESCAPE:", + "y:001000101101:u:", + "y:011110001001:STOP:", + "y:0010001000100:z:", + "y:0111100010001:\":", + "y:00100010001011:j:", + "y:01111000100001:2:", + "y:001000100010100:y:", + "y:001000100010101:x:", + "y:0111100010000000:v:", + "y:0111100010000001:T:", + "y:0111100010000010:E:", + "y:0111100010000011:P:", + "z:10:e:", + "z:001:a:", + "z:011:z:", + "z:110: :", + "z:111:i:", + "z:0001:l:", + "z:0100:y:", + "z:01010:o:", + "z:000000:c:", + "z:000010:,:", + "z:000011:.:", + "z:010110:w:", + "z:0000010:':", + "z:00000110:0x3a:", + "z:00000111:t:", + "z:01011101:m:", + "z:010111000:k:", + "z:010111100:-:", + "z:010111101:u:", + "z:010111111:b:", + "z:01011100100:s:", + "z:01011100101:/:", + "z:01011100111:d:", + "z:01011111001:p:", + "z:01011111011:?:", + "z:010111001100:h:", + "z:010111110000:@:", + "z:010111110100:):", + "z:0101110011010:!:", + "z:0101111100011:v:", + "z:0101111101010:g:", + "z:01011100110110:f:", + "z:01011100110111:r:", + "z:01011111000100:q:", + "z:01011111000101:n:", + "z:01011111010110:ESCAPE:", + "z:01011111010111:]:", + "{:0:ESCAPE:", + "{:1:ESCAPE:", + "|:0:ESCAPE:", + "|:1:ESCAPE:", + "}:0:ESCAPE:", + "}:1:STOP:", + "~:0:ESCAPE:", + "~:1:ESCAPE:", + "0x7f:0:ESCAPE:", + "0x7f:1:ESCAPE:", + NULL, +}; + +// MediaHighWay Ver. 1 + +typedef struct +{ + u_char Name [15]; +} sThemeMHW1; + +typedef struct +{ + u_char NetworkIdHigh :8; + u_char NetworkIdLow :8; + u_char TransportIdHigh :8; + u_char TransportIdLow :8; + u_char ServiceIdHigh :8; + u_char ServiceIdLow :8; + u_char Name [16]; +} sChannelMHW1; + +typedef struct +{ + u_char TableId :8; +#if BYTE_ORDER == BIG_ENDIAN + u_char SectionSyntaxIndicator :1; + u_char :1; + u_char :2; + u_char SectionLengthHigh :4; +#else + u_char SectionLengthHigh :4; + u_char :2; + u_char :1; + u_char SectionSyntaxIndicator :1; +#endif + u_char SectionLengthLow :8; + u_char ChannelId :8; + u_char ThemeId :8; +#if BYTE_ORDER == BIG_ENDIAN + u_char Day :3; + u_char Hours :5; +#else + u_char Hours :5; + u_char Day :3; +#endif +#if BYTE_ORDER == BIG_ENDIAN + u_char Minutes :6; + u_char :1; + u_char SummaryAvailable :1; +#else + u_char SummaryAvailable :1; + u_char :1; + u_char Minutes :6; +#endif + u_char :8; + u_char :8; + u_char DurationHigh :8; + u_char DurationLow :8; + u_char Title [23]; + u_char PpvIdHigh :8; + u_char PpvIdMediumHigh :8; + u_char PpvIdMediumLow :8; + u_char PpvIdLow :8; + u_char ProgramIdHigh :8; + u_char ProgramIdMediumHigh :8; + u_char ProgramIdMediumLow :8; + u_char ProgramIdLow :8; + u_char :8; + u_char :8; + u_char :8; + u_char :8; +} sTitleMHW1; + +typedef struct { + u_char TableId :8; +#if BYTE_ORDER == BIG_ENDIAN + u_char SectionSyntaxIndicator :1; + u_char :1; + u_char :2; + u_char SectionLengthHigh :4; +#else + u_char SectionLengthHigh :4; + u_char :2; + u_char :1; + u_char SectionSyntaxIndicator :1; +#endif + u_char SectionLengthLow :8; + u_char ProgramIdHigh :8; + u_char ProgramIdMediumHigh :8; + u_char ProgramIdMediumLow :8; + u_char ProgramIdLow :8; + u_char Byte7 :8; + u_char Byte8 :8; + u_char Byte9 :8; + u_char NumReplays :8; +} sSummaryMHW1; + +typedef struct { + u_char TableId :8; +#if BYTE_ORDER == BIG_ENDIAN + u_char SectionSyntaxIndicator :1; + u_char :1; + u_char :2; + u_char SectionLengthHigh :4; +#else + u_char SectionLengthHigh :4; + u_char :2; + u_char :1; + u_char SectionSyntaxIndicator :1; +#endif + u_char SectionLengthLow :8; + u_char TableIdExtensionHigh :8; + u_char TableIdExtensionLow :8; +#if BYTE_ORDER == BIG_ENDIAN + u_char Reserved :2; + u_char VersionNumber :5; + u_char CurrentNextIndicator :1; +#else + u_char CurrentNextIndicator :1; + u_char VersionNumber :5; + u_char Reserved :2; +#endif + u_char SectionNumber :8; + u_char LastSectionNumber :8; + u_char LanguageCodeHigh :8; + u_char LanguageCodeMedium :8; + u_char LanguageCodeLow :8; + u_char AlwaysZero0 :8; +} sTitleBlockHeaderNagraGuide; + +typedef struct { + u_char ChannelIdHigh :8; + u_char ChannelIdLow :8; + u_char BlocklengthHigh :8; + u_char BlocklengthLow :8; + u_char NumberOfTitlesHigh :8; + u_char NumberOfTitlesMediumHigh :8; + u_char NumberOfTitlesMediumLow :8; + u_char NumberOfTitlesLow :8; +} sTitleBlockNagraGuide; //all titles in one block are on the same channel + +typedef struct { + u_char EventIdHigh :8; + u_char EventIdMediumHigh :8; + u_char EventIdMediumLow :8; + u_char EventIdLow :8; + u_char StartTimeHigh :8; +#if BYTE_ORDER == BIG_ENDIAN + u_char StartTimeLow :5; + u_char AlwaysZero16 :3; +#else + u_char AlwaysZero16 :3;//can be 1,2,3 or 4 with night-programs etc.??? + u_char StartTimeLow :5; +#endif + u_char Duration :8; + u_char AlwaysZero1 :8; + u_char AlwaysZero2 :8; + u_char AlwaysZero3 :8; + u_char AlwaysZero4 :8; + u_char AlwaysZero5 :8; + u_char SumDataOffsetHigh :8;//address of relevant Summary Data Record + u_char SumDataOffsetMediumHigh :8; + u_char SumDataOffsetMediumLow :8; + u_char SumDataOffsetLow :8; + u_char AlwaysZero8 :8; + u_char AlwaysZero9 :8; + u_char AlwaysZero10 :8; + u_char AlwaysZero11 :8; + u_char OffsetToTextHigh :8;//offset from 2nd byte after languagecode gives length byte of title-text + u_char OffsetToTextMediumHigh :8; + u_char OffsetToTextMediumLow :8; + u_char OffsetToTextLow :8; + u_char OffsetToText2High :8;//offset from 2nd byte after languagecode gives length byte of title-text2 + u_char OffsetToText2MediumHigh :8; + u_char OffsetToText2MediumLow :8; + u_char OffsetToText2Low :8; + u_char ThemeId :8; + u_char AlwaysZero17 :8; +} sTitleNagraGuide; + +//first 4 bytes with zeroterminated language code +typedef struct { + u_char AlwaysZero1 :8; + u_char AlwaysZero2 :8; + u_char AlwaysZero3 :8; + u_char AlwaysZero4 :8; + u_char Always1 :8; + u_char Always9 :8; + u_char Always7 :8; + u_char Always0 :8; + u_char AlwaysZero5 :8; + u_char AlwaysZero6 :8; + u_char AlwaysZero7 :8; + u_char AlwaysZero8 :8; + u_char AlwaysZero9 :8; + u_char Always0x01 :8; + u_char EventIdHigh :8; + u_char EventIdMediumHigh :8; + u_char EventIdMediumLow :8; + u_char EventIdLow :8; + u_char NumberOfBlocks :8;//every block > 2 adds 4 bytes, if block = 1 then no summtxtoffset so subtract 4 bytes! + u_char BlockIdHigh :8; + u_char BlockIdMediumHigh :8; + u_char BlockIdMediumLow :8; + u_char BlockIdLow :8; + u_char SummTxtOffsetHigh :8;//address from start of section + 4 points to relevant Always0x4e + u_char SummTxtOffsetMediumHigh :8; + u_char SummTxtOffsetMediumLow :8; + u_char SummTxtOffsetLow :8; + u_char Unknown1 :8; + u_char Unknown2 :8; +} sSummaryDataNagraGuide; + +typedef struct { + u_char Always0x4e :8;//if 0x4e summarytext follows if 0x8c no summarytext GBR record follows + u_char Blocklength :8; +#if BYTE_ORDER == BIG_ENDIAN + u_char TextNr :4; + u_char LastTextNr :4; +#else + u_char LastTextNr :4;//last nr of block of text + u_char TextNr :4;//nr of a block of text, starts with 0!!! +#endif + u_char LanguageCodeHigh :8; + u_char LanguageCodeMedium :8; + u_char LanguageCodeLow :8; + u_char AlwaysZero1 :8; + u_char Textlength :8; + u_char Text :8; +} sSummaryTextNagraGuide; + +typedef struct { + u_char Always0x8c :8; + u_char Blocklength :8; + u_char AlwaysZero1 :8; + u_char AlwaysZero2 :8; + u_char Un1 :8; + u_char Un2 :8; + u_char Un3 :8; + u_char Un4 :8; + u_char AlwaysZero3 :8; + u_char Un5 :8; + u_char Un6 :8; + u_char Un7 :8; + u_char AlwaysZero4 :8; + u_char Un8 :8; + u_char Un9 :8; + u_char Nextlength :8; + u_char Always0x81 :8; + u_char EventIdHigh :8; + u_char EventIdMedium :8; + u_char EventIdLow :8; +} sSummaryGBRNagraGuide; + +typedef struct { + u_char SatId :8;//is always 0x01 + u_char NetworkIdHigh :8; + u_char NetworkIdLow :8; + u_char TransportIdHigh :8; + u_char TransportIdLow :8; + u_char ServiceIdHigh :8; + u_char ServiceIdLow :8; + u_char Nr8cBlocks :8; + u_char Always0x8c :8;//next three fields are 0x00 for FTA channels.... + u_char Nr8cBytes :8; + u_char AlwaysZero1 :8;//from here on optional fields, not used for FTA channels like BVN, regional S23.5 broadcasts + u_char ProviderIdHigh :8; + u_char ProviderIdLow :8; + u_char Always0x08 :8; + u_char Always0x02 :8; + u_char Always0x01 :8; + u_char AlwaysZero2 :8; + u_char Always0x20 :8; + u_char Always0x0a :8; + u_char Un4 :8; + u_char Always0x81 :8; + u_char Un5 :8; + u_char Always0x44 :8; + u_char Un6 :8; + u_char Un7 :8; + u_char Un8 :8; + u_char Un9 :8; +} sChannelsNagraGuide; + +typedef struct { + u_char TitleOffsetHigh :8;//address from start of section (in 0x02x0) + 4 points to eventid of title that has this theme + u_char TitleOffsetMediumHigh :8; + u_char TitleOffsetMediumLow :8; + u_char TitleOffsetLow :8; + u_char AlwaysZero1 :8; + u_char Un1 :8; + u_char AlwaysZero2 :8; + u_char Always1 :8; +} sThemesTitlesNagraGuide; + +typedef struct { //first three bytes form unknown header, then X blocks, where X = number of distinct table_id_extensio +#if BYTE_ORDER == BIG_ENDIAN + u_char TableIdExtensionLow :6;//BIG_ENDIAN not tested!! + u_char TableIdExtensionHigh :2; + u_char TIE200 :1; + u_char Unknown1 :2; + u_char VersionNumber :5;//contains current version of table_id_extension +#else + u_char TableIdExtensionHigh :2; + u_char TableIdExtensionLow :6; + u_char VersionNumber :5;//contains current version of table_id_extension + u_char Unknown1 :2; + u_char TIE200 :1; +#endif + u_char Always0xd6 :8; + u_char DayCounter :8;//for most sections this increments each day +} sSection0000BlockNagraGuide; + +#define HILO16( x ) ( ( ( x##High << 8 ) | x##Low ) & 0xffff ) +#define HILO32( x ) ( ( ( ( ( x##High << 24 ) | ( x##MediumHigh << 16 ) ) | ( x##MediumLow << 8 ) ) | x##Low ) & 0xffffffff ) +#define MjdToEpochTime(x) (((x##_hi << 8 | x##_lo)-40587)*86400) |