From 725da5ed0bc6a2703ff4aacda8115cffd6879d62 Mon Sep 17 00:00:00 2001 From: Chris Tallon Date: Tue, 28 Jun 2005 22:16:29 +0000 Subject: [PATCH 1/1] Initial import --- COPYING | 340 +++ Makefile | 47 + afeed.cc | 92 + afeed.h | 54 + afeedr.cc | 73 + afeedr.h | 52 + audio.cc | 281 ++ audio.h | 89 + bogl.h | 17 + box.cc | 192 ++ box.h | 75 + callback.h | 30 + channel.cc | 36 + channel.h | 41 + command.cc | 393 +++ command.h | 88 + defines.h | 36 + demuxer.cc | 480 ++++ demuxer.h | 147 ++ directory.cc | 86 + directory.h | 55 + dsock.cc | 190 ++ dsock.h | 67 + fonts/helvB18-ISO8859-1.pcf | Bin 0 -> 16200 bytes fonts/helvB18.bdf | 4034 +++++++++++++++++++++++++++++ fonts/helvB18.cc | Bin 0 -> 240846 bytes fonts/helvB24-ISO8859-1.pcf | Bin 0 -> 19620 bytes fonts/helvB24.bdf | 4889 +++++++++++++++++++++++++++++++++++ fonts/helvB24.cc | Bin 0 -> 298697 bytes fonts/licence.txt | 876 +++++++ led.cc | 75 + led.h | 48 + list.cc | 170 ++ list.h | 66 + log.cc | 149 ++ log.h | 89 + main.cc | 399 +++ message.cc | 30 + message.h | 52 + messagequeue.cc | 38 + messagequeue.h | 46 + mtd.cc | 127 + mtd.h | 59 + node.cc | 46 + node.h | 37 + osd.cc | 111 + osd.h | 61 + other/licence.txt | 45 + other/vdr.jpg | Bin 0 -> 14359 bytes other/wallpaper.jpg | Bin 0 -> 14125 bytes player.cc | 497 ++++ player.h | 85 + playerradio.cc | 372 +++ playerradio.h | 76 + queue.cc | 79 + queue.h | 45 + recording.cc | 89 + recording.h | 49 + remote.cc | 124 + remote.h | 88 + stb.h | 220 ++ stream.cc | 128 + stream.h | 50 + surface.cc | 526 ++++ surface.h | 249 ++ tcp.cc | 403 +++ tcp.h | 69 + thread.cc | 92 + thread.h | 57 + vchannellist.cc | 210 ++ vchannellist.h | 58 + vchannelselect.cc | 129 + vchannelselect.h | 52 + vdr.cc | 608 +++++ vdr.h | 107 + vfeed.cc | 72 + vfeed.h | 51 + video.cc | 304 +++ video.h | 111 + view.cc | 123 + view.h | 74 + viewman.cc | 540 ++++ viewman.h | 82 + vinfo.cc | 69 + vinfo.h | 48 + vlivebanner.cc | 89 + vlivebanner.h | 46 + vmute.cc | 62 + vmute.h | 43 + vquestion.cc | 118 + vquestion.h | 59 + vradiolive.cc | 115 + vradiolive.h | 54 + vrecordinglist.cc | 350 +++ vrecordinglist.h | 63 + vrecordingmenu.cc | 171 ++ vrecordingmenu.h | 58 + vserverselect.cc | 81 + vserverselect.h | 47 + vvideolive.cc | 165 ++ vvideolive.h | 57 + vvideorec.cc | 122 + vvideorec.h | 47 + vvolume.cc | 85 + vvolume.h | 45 + vwallpaper.cc | 54 + vwallpaper.h | 48 + vwelcome.cc | 212 ++ vwelcome.h | 58 + wbutton.cc | 76 + wbutton.h | 45 + wjpeg.cc | 112 + wjpeg.h | 48 + wselectlist.cc | 171 ++ wselectlist.h | 60 + wsymbol.cc | 563 ++++ wsymbol.h | 55 + 117 files changed, 23723 insertions(+) create mode 100644 COPYING create mode 100644 Makefile create mode 100644 afeed.cc create mode 100644 afeed.h create mode 100644 afeedr.cc create mode 100644 afeedr.h create mode 100644 audio.cc create mode 100644 audio.h create mode 100644 bogl.h create mode 100644 box.cc create mode 100644 box.h create mode 100644 callback.h create mode 100644 channel.cc create mode 100644 channel.h create mode 100644 command.cc create mode 100644 command.h create mode 100644 defines.h create mode 100644 demuxer.cc create mode 100644 demuxer.h create mode 100644 directory.cc create mode 100644 directory.h create mode 100644 dsock.cc create mode 100644 dsock.h create mode 100644 fonts/helvB18-ISO8859-1.pcf create mode 100644 fonts/helvB18.bdf create mode 100644 fonts/helvB18.cc create mode 100644 fonts/helvB24-ISO8859-1.pcf create mode 100644 fonts/helvB24.bdf create mode 100644 fonts/helvB24.cc create mode 100644 fonts/licence.txt create mode 100644 led.cc create mode 100644 led.h create mode 100644 list.cc create mode 100644 list.h create mode 100644 log.cc create mode 100644 log.h create mode 100644 main.cc create mode 100644 message.cc create mode 100644 message.h create mode 100644 messagequeue.cc create mode 100644 messagequeue.h create mode 100644 mtd.cc create mode 100644 mtd.h create mode 100644 node.cc create mode 100644 node.h create mode 100644 osd.cc create mode 100644 osd.h create mode 100644 other/licence.txt create mode 100644 other/vdr.jpg create mode 100644 other/wallpaper.jpg create mode 100644 player.cc create mode 100644 player.h create mode 100644 playerradio.cc create mode 100644 playerradio.h create mode 100644 queue.cc create mode 100644 queue.h create mode 100644 recording.cc create mode 100644 recording.h create mode 100644 remote.cc create mode 100644 remote.h create mode 100644 stb.h create mode 100644 stream.cc create mode 100644 stream.h create mode 100644 surface.cc create mode 100644 surface.h create mode 100644 tcp.cc create mode 100644 tcp.h create mode 100644 thread.cc create mode 100644 thread.h create mode 100644 vchannellist.cc create mode 100644 vchannellist.h create mode 100644 vchannelselect.cc create mode 100644 vchannelselect.h create mode 100644 vdr.cc create mode 100644 vdr.h create mode 100644 vfeed.cc create mode 100644 vfeed.h create mode 100644 video.cc create mode 100644 video.h create mode 100644 view.cc create mode 100644 view.h create mode 100644 viewman.cc create mode 100644 viewman.h create mode 100644 vinfo.cc create mode 100644 vinfo.h create mode 100644 vlivebanner.cc create mode 100644 vlivebanner.h create mode 100644 vmute.cc create mode 100644 vmute.h create mode 100644 vquestion.cc create mode 100644 vquestion.h create mode 100644 vradiolive.cc create mode 100644 vradiolive.h create mode 100644 vrecordinglist.cc create mode 100644 vrecordinglist.h create mode 100644 vrecordingmenu.cc create mode 100644 vrecordingmenu.h create mode 100644 vserverselect.cc create mode 100644 vserverselect.h create mode 100644 vvideolive.cc create mode 100644 vvideolive.h create mode 100644 vvideorec.cc create mode 100644 vvideorec.h create mode 100644 vvolume.cc create mode 100644 vvolume.h create mode 100644 vwallpaper.cc create mode 100644 vwallpaper.h create mode 100644 vwelcome.cc create mode 100644 vwelcome.h create mode 100644 wbutton.cc create mode 100644 wbutton.h create mode 100644 wjpeg.cc create mode 100644 wjpeg.h create mode 100644 wselectlist.cc create mode 100644 wselectlist.h create mode 100644 wsymbol.cc create mode 100644 wsymbol.h diff --git a/COPYING b/COPYING new file mode 100644 index 0000000..3912109 --- /dev/null +++ b/COPYING @@ -0,0 +1,340 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..aae4319 --- /dev/null +++ b/Makefile @@ -0,0 +1,47 @@ +CC = /opt/crosstool/powerpc-405-linux-gnu/gcc-2.95.3-glibc-2.2.5/bin/powerpc-405-linux-gnu-g++ +STRIP = /opt/crosstool/powerpc-405-linux-gnu/gcc-2.95.3-glibc-2.2.5/bin/powerpc-405-linux-gnu-strip +CXX = $(CC) +INCLUDES = -I../jpeg-6b +CXXFLAGS = -Wall -Woverloaded-virtual -Werror $(INCLUDES) +LDFLAGS = -Wall -static + +LIBPATHS = +LIBS = -lpthread -lrt +CROSSLIBS = ../jpeg-6b/libjpeg.a + +OBJECTS = main.o command.o log.o remote.o led.o mtd.o video.o audio.o tcp.o directory.o thread.o \ + player.o demuxer.o stream.o vfeed.o afeed.o afeedr.o osd.o surface.o viewman.o vdr.o dsock.o box.o \ + list.o queue.o node.o recording.o channel.o message.o playerradio.o messagequeue.o \ + view.o vinfo.o vwallpaper.o vvolume.o vrecordinglist.o vlivebanner.o vmute.o \ + vrecordingmenu.o vquestion.o vchannellist.o vwelcome.o vvideolive.o vvideorec.o vradiolive.o \ + vchannelselect.o vserverselect.o \ + wselectlist.o wjpeg.o wsymbol.o wbutton.o \ + fonts/helvB24.o fonts/helvB18.o + +.PHONY: clean fresh all install strip + +default: vompclient +fresh: clean all +all: vompclient + +clean: + rm -f *.o deps vompclient test *~ fonts/*.o fonts/*~ + +vompclient: $(OBJECTS) + $(CC) $(LDFLAGS) $(LIBPATHS) -o vompclient $(OBJECTS) $(CROSSLIBS) $(LIBS) + +strip: + $(STRIP) vompclient + +install: + rm /diskless/nfs/mvp/vompclient + cp vompclient /diskless/nfs/mvp + +dongle: strip + cp vompclient ../dongle + cd ../dongle ; ./go + +deps: Makefile + $(CC) -MM $(INCLUDES) $(OBJECTS:%.o=%.cc) > deps + +-include deps diff --git a/afeed.cc b/afeed.cc new file mode 100644 index 0000000..bfdfe1c --- /dev/null +++ b/afeed.cc @@ -0,0 +1,92 @@ +/* + Copyright 2004-2005 Chris Tallon + + This file is part of VOMP. + + VOMP 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. + + VOMP 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 VOMP; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include "afeed.h" + +AFeed::AFeed(Callback* tcb) +: cb(*tcb) +{ + delayTime.tv_sec = 0; + delayTime.tv_nsec = 100000000; + audioEnabled = 1; +} + +int AFeed::init(int tfd) +{ + fd = tfd; + return 1; +} + +int AFeed::shutdown() +{ + // FIXME + return 1; +} + +void AFeed::disable() +{ + audioEnabled = 0; +} + +void AFeed::enable() +{ + audioEnabled = 1; +} + +int AFeed::start() +{ + return threadStart(); +} + +void AFeed::stop() +{ + threadCancel(); +} + +void AFeed::threadMethod() +{ + Log::getInstance()->log("AFeed", Log::DEBUG, "Started"); + + int alen; + + while(1) + { + if (audioEnabled) + { + alen = Demuxer::getInstance()->writeAudio(fd); // FIXME ? + + if (alen) + { + Log::getInstance()->log("AFeed", Log::DEBUG, "Written %i", alen); + cb.call(); + } + else + { + nanosleep(&delayTime, NULL); + } + } + else + { + Demuxer::getInstance()->flushAudio(); // FIXME, no delay here now +// if (demux_get_audio(demuxHandle, buffer, 1000) != 1000) nanosleep(&delayTime, NULL); + } + } +} + diff --git a/afeed.h b/afeed.h new file mode 100644 index 0000000..b858e96 --- /dev/null +++ b/afeed.h @@ -0,0 +1,54 @@ +/* + Copyright 2004-2005 Chris Tallon + + This file is part of VOMP. + + VOMP 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. + + VOMP 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 VOMP; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#ifndef AFEED_H +#define AFEED_H + +#include +#include + +#include "log.h" +#include "thread.h" +#include "demuxer.h" +#include "callback.h" + +class AFeed : public Thread +{ + public: + AFeed(Callback* tcb); + + int init(int fd); + int shutdown(); + + int start(); + void stop(); + void enable(); + void disable(); + + private: + void threadMethod(); + int audioEnabled; + int fd; + Callback& cb; + struct timespec delayTime; + +}; + +#endif diff --git a/afeedr.cc b/afeedr.cc new file mode 100644 index 0000000..1dd8a01 --- /dev/null +++ b/afeedr.cc @@ -0,0 +1,73 @@ +/* + Copyright 2004-2005 Chris Tallon + + This file is part of VOMP. + + VOMP 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. + + VOMP 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 VOMP; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include "afeedr.h" + +AFeedR::AFeedR(Callback* tcb, Stream* tstream) +: cb(*tcb), stream(*tstream) +{ + delayTime.tv_sec = 0; + delayTime.tv_nsec = 100000000; +} + +int AFeedR::init(int tfd) +{ + fd = tfd; + return 1; +} + +int AFeedR::shutdown() +{ + // FIXME + return 1; +} + +int AFeedR::start() +{ + return threadStart(); +} + +void AFeedR::stop() +{ + threadCancel(); +} + +void AFeedR::threadMethod() +{ + Log::getInstance()->log("AFeedR", Log::DEBUG, "Started"); + + int alen; + + while(1) + { + alen = stream.drain(fd); + + if (alen) + { + Log::getInstance()->log("AFeedR", Log::DEBUG, "Written %i", alen); + cb.call(); + } + else + { + nanosleep(&delayTime, NULL); + } + } +} + diff --git a/afeedr.h b/afeedr.h new file mode 100644 index 0000000..eb94db2 --- /dev/null +++ b/afeedr.h @@ -0,0 +1,52 @@ +/* + Copyright 2004-2005 Chris Tallon + + This file is part of VOMP. + + VOMP 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. + + VOMP 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 VOMP; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#ifndef AFEEDR_H +#define AFEEDR_H + +#include +#include + +#include "log.h" +#include "thread.h" +#include "callback.h" +#include "stream.h" + +class AFeedR : public Thread +{ + public: + AFeedR(Callback* tcb, Stream* tstream); + + int init(int fd); + int shutdown(); + + int start(); + void stop(); + + private: + void threadMethod(); + int fd; + Callback& cb; + Stream& stream; + struct timespec delayTime; + +}; + +#endif diff --git a/audio.cc b/audio.cc new file mode 100644 index 0000000..bacdc8f --- /dev/null +++ b/audio.cc @@ -0,0 +1,281 @@ +/* + Copyright 2004-2005 Chris Tallon + + This file is part of VOMP. + + VOMP 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. + + VOMP 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 VOMP; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include "audio.h" + +Audio* Audio::instance = NULL; + +Audio::Audio() +{ + if (instance) return; + instance = this; + initted = 0; + fdAudio = 0; + streamType = 0; + volume = 20; + muted = 0; + userMute = 0; + systemMute = 0; +} + +Audio::~Audio() +{ + instance = NULL; +} + +Audio* Audio::getInstance() +{ + return instance; +} + +int Audio::init(UCHAR streamType) +{ + if (initted) return 0; + initted = 1; + +// if ((fdAudio = open("/dev/adec_mpg", O_RDWR | O_NONBLOCK)) < 0) return 0; + if ((fdAudio = open("/dev/adec_mpg", O_WRONLY)) < 0) return 0; + + this->streamType = streamType; + + if (!initAllParams()) + { + shutdown(); + return 0; + } + + unMute(); + + return 1; +} + +int Audio::initAllParams() +{ + return (setStreamType(streamType) && setChannel() && setSource()); +} + +int Audio::shutdown() +{ + if (!initted) return 0; + initted = 0; + close(fdAudio); + return 1; +} + +int Audio::getFD() +{ + if (!initted) return 0; + + return fdAudio; +} + +int Audio::write(char *buf, int len) +{ + return 0; //write(fdAudio, buf, len); +} + +int Audio::setStreamType(UCHAR type) +{ + if (!initted) return 0; + + if (ioctl(fdAudio, AV_SET_AUD_STREAMTYPE, type) != 0) return 0; + return 1; +} + +int Audio::setChannel() +{ + if (!initted) return 0; + + if (ioctl(fdAudio, AV_SET_AUD_CHANNEL, 0) != 0) return 0; + return 1; +} + +int Audio::setSource() +{ + if (!initted) return 0; + + if (ioctl(fdAudio, AV_SET_AUD_SRC, 1) != 0) return 0; + return 1; +} + +int Audio::sync() +{ + if (!initted) return 0; + + if (ioctl(fdAudio, AV_SET_AUD_SYNC, 2) != 0) return 0; + return 1; +} + +int Audio::play() +{ + if (!initted) return 0; + + if (ioctl(fdAudio, AV_SET_AUD_PLAY, 0) != 0) return 0; + return 1; +} + +int Audio::stop() +{ + if (!initted) return 0; + + if (ioctl(fdAudio, AV_SET_AUD_RESET, 0x11) != 0) return 0; + return 1; +} + +int Audio::mute() +{ + if (!initted) return 0; + + if (ioctl(fdAudio, AV_SET_AUD_MUTE, 1) != 0) return 0; + Log::getInstance()->log("Audio", Log::DEBUG, "MUTE MUTE MUTE"); + + muted = 1; + return 1; +} + +int Audio::unMute() +{ + if (!initted) return 0; + + if (ioctl(fdAudio, AV_SET_AUD_MUTE, 0) != 0) return 0; + Log::getInstance()->log("Audio", Log::DEBUG, "MUTE OFF OFF OFF"); + + muted = 0; + return 1; +} + +int Audio::pause() +{ + if (!initted) return 0; + + if (ioctl(fdAudio, AV_SET_AUD_PAUSE, 1) != 0) return 0; + return 1; +} + +int Audio::unPause() +{ + if (!initted) return 0; + + if (ioctl(fdAudio, AV_SET_AUD_UNPAUSE, 1) != 0) return 0; + return 1; +} + +int Audio::reset() +{ + if (!initted) return 0; +//test(); + if (ioctl(fdAudio, AV_SET_AUD_RESET, 0x11) != 0) return 0; + if (ioctl(fdAudio, AV_SET_AUD_PLAY, 0) != 0) return 0; + + doMuting(); + return 1; +} + +int Audio::setVolume(int volume) +{ + // parameter: 0 for silence, 20 for full + + if ((volume < 0) || (volume > 20)) return 0; + + volume = 2 * (20 - volume); + + unsigned long vol = (volume << 24) | (volume << 16); + + Log::getInstance()->log("Audio", Log::DEBUG, "%lx", vol); + Log::getInstance()->log("Audio", Log::DEBUG, "%i", volume); + + if (ioctl(fdAudio, AV_SET_AUD_VOLUME, &vol) != 0) return 0; + return 1; +} + +int Audio::test() +{ + ULLONG stc = 0; + return ioctl(fdAudio, AV_SET_AUD_STC, &stc); +} + +int Audio::volumeUp() +{ + if (!initted) return 0; + if (volume == 20) return volume; + volume++; + setVolume(volume); + return volume; +} + +int Audio::volumeDown() +{ + if (!initted) return 0; + if (volume == 0) return 0; + volume--; + setVolume(volume); + return volume; +} + +int Audio::getVolume() +{ + if (!initted) return 0; + return volume; +} + +int Audio::toggleUserMute() +{ + if (!initted) return 0; + + if (userMute) + { + userMute = 0; + } + else + { + userMute = 1; + } + + doMuting(); + + return userMute; +} + +int Audio::systemMuteOn() +{ + systemMute = 1; + return doMuting(); +} + +int Audio::systemMuteOff() +{ + systemMute = 0; + return doMuting(); +} + +int Audio::doMuting() +{ + Log::getInstance()->log("Audio", Log::DEBUG, "doMuting: user=%i sys=%i", userMute, systemMute); + + + if (userMute || systemMute) + { + return mute(); + } + else + { + return unMute(); + } +} diff --git a/audio.h b/audio.h new file mode 100644 index 0000000..190513e --- /dev/null +++ b/audio.h @@ -0,0 +1,89 @@ +/* + Copyright 2004-2005 Chris Tallon + + This file is part of VOMP. + + VOMP 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. + + VOMP 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 VOMP; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +// Thanks to Jon Gettler and BtB for all the ioctl information + +#ifndef AUDIO_H +#define AUDIO_H + +#include +#include +#include +#include + +#include "defines.h" +#include "log.h" +#include "stb.h" + +class Audio +{ + public: + Audio(); + ~Audio(); + static Audio* getInstance(); + + int init(UCHAR streamType); + int shutdown(); + + // Audio stream type + const static UCHAR MPEG2_PES = 2; + const static UCHAR MPEG1_PES = 3; // unused + + int setStreamType(UCHAR streamType); + int setChannel(); + int setSource(); + int sync(); + int play(); + int stop(); + int pause(); + int unPause(); + int reset(); + int setVolume(int volume); + int volumeUp(); + int volumeDown(); + int getVolume(); + int toggleUserMute(); + int systemMuteOn(); + int systemMuteOff(); + int test(); + + int write(char *buf, int len); + + int getFD(); + + int doMuting(); + private: + static Audio* instance; + int initted; + int volume; + UCHAR muted; + UCHAR userMute; + UCHAR systemMute; + + int mute(); + int unMute(); + int initAllParams(); + + UCHAR streamType; + + int fdAudio; +}; + +#endif diff --git a/bogl.h b/bogl.h new file mode 100644 index 0000000..be7a623 --- /dev/null +++ b/bogl.h @@ -0,0 +1,17 @@ +#ifndef BOGL_H +#define BOGL_H + +/* + * This header file is here for font .c files that are created with the + * bdftobogl utility that comes with bogl. + */ + +typedef struct bogl_font { + char *name; /* Font name. */ + int height; /* Height in pixels. */ + unsigned long *content; /* 32-bit right-padded bitmap array. */ + short *offset; /* 256 offsets into content. */ + unsigned char *width; /* 256 character widths. */ +} osd_font_t; + +#endif /* BOGL_H */ diff --git a/box.cc b/box.cc new file mode 100644 index 0000000..b15980b --- /dev/null +++ b/box.cc @@ -0,0 +1,192 @@ +/* + Copyright 2004-2005 Chris Tallon + + This file is part of VOMP. + + VOMP 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. + + VOMP 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 VOMP; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include "box.h" + +char Box::numBoxes = 0; + +Box::Box() +{ + height = 0; + width = 0; + screenX = 0; + screenY = 0; + + numBoxes++; + Log::getInstance()->log("Box", Log::DEBUG, "Construct, now %u", numBoxes); + + surface = Surface::getObject(Surface::BUFFER); +} + +Box::~Box() +{ + numBoxes--; + Log::getInstance()->log("Box", Log::DEBUG, "Destruct, now %u", numBoxes); +} + +void Box::draw() +{ +} + +void Box::setDimensions(int h, int w) +{ + height = h; + width = w; +} + +void Box::setScreenPos(int x, int y) +{ + screenX = x; + screenY = y; +} + +void Box::show() +{ + Log::getInstance()->log("Box", Log::DEBUG, "Show data %u %u %u %u", screenX, screenY, width, height); + surface->updateToScreen(screenX, screenY, width, height); +} + +void Box::showAll() +{ + Surface::bufferToScreen(); +} + +int Box::getScreenX() +{ + return screenX; +} + +int Box::getScreenY() +{ + return screenY; +} + +int Box::getWidth() +{ + return width; +} + +int Box::getHeight() +{ + return height; +} + +// Level 1 drawing functions + +void Box::fillColour(int r, int g, int b, int a) +{ + rectangle(0, 0, width, height, r, g, b, a); +} + +void Box::drawPara(char* text, int x, int y, int r, int g, int b) +{ + char line[256]; + int lineHeight = surface->getFontHeight() + 6; + + int lineWidth; + int thisCharWidth; + int textPos; + int linePos; + int ypos; + int printLine; + + textPos = 0; + ypos = y; + + while(1) + { + linePos = 0; + lineWidth = 0; + while(1) + { + printLine = 0; + + if (text[textPos] == '\0') break; + + if (text[textPos] == '\n') + { + textPos++; // ignore the \n + printLine = 1; + break; + } + + thisCharWidth = surface->getCharWidth(text[textPos]); + if ((lineWidth + thisCharWidth) > (width - (2 * paraMargin))) + { + // this character would break the right margin + if (text[textPos] == ' ') + { + // this char is a space, ignore and break + textPos++; + break; + } + else + { + // Need to go back to the last space in the line + while ((text[textPos] != ' ') && (linePos >= 0)) + { + textPos--; + linePos--; + } + // Now take the space we just found + textPos++; + break; + } + } + line[linePos++] = text[textPos]; + lineWidth += thisCharWidth; + textPos++; + } + + line[linePos++] = '\0'; + if (printLine || (linePos > 1)) // if some text was put in line + { + drawText(line, x, ypos, r, g, b); + ypos += lineHeight; + if (ypos > (height - lineHeight)) break; + } + else + { + break; + } + } +} + +// Level 0 drawing functions + +void Box::rectangle(int x1, int y1, int width, int height, int r, int g, int b, int a) +{ + surface->fillblt(screenX + x1, screenY + y1, width, height, surface->rgba(r, g, b, a)); +} + +void Box::drawText(char* text, int x, int y, int r, int g, int b) +{ + surface->drawText(text, screenX + x, screenY + y, r, g, b); +} + +void Box::drawTextRJ(char* text, int x, int y, int r, int g, int b) +{ + surface->drawTextRJ(text, screenX + x, screenY + y, r, g, b); +} + +void Box::drawPixel(int x, int y, int c) +{ + surface->drawPixel(screenX + x, screenY + y, c); +} diff --git a/box.h b/box.h new file mode 100644 index 0000000..ee80e49 --- /dev/null +++ b/box.h @@ -0,0 +1,75 @@ +/* + Copyright 2004-2005 Chris Tallon + + This file is part of VOMP. + + VOMP 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. + + VOMP 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 VOMP; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#ifndef BOX_H +#define BOX_H + +#include + +#include "log.h" +#include "surface.h" + +// Abstract ??????? +class Box +{ + public: + Box(); + virtual ~Box(); + + void setScreenPos(int x, int y); + void setDimensions(int h, int w); + void show(); + + virtual void draw(); + + // Drawing functions level 1 + void fillColour(int r, int g, int b, int a); + void drawPara(char* text, int x, int y, int r, int g, int b); + + // Drawing functions level 0 + void rectangle(int x1, int y1, int x2, int y2, int r, int g, int b, int a); + void drawText(char* text, int x, int y, int r, int g, int b); + void drawTextRJ(char* text, int x, int y, int r, int g, int b); + void drawPixel(int x, int y, int c); + + int getScreenX(); + int getScreenY(); + int getWidth(); + int getHeight(); + + static void showAll(); + + private: + + protected: + Surface* surface; + int width; + int height; + + int screenX; + int screenY; + + static char numBoxes; + + static const int paraMargin = 10; + +}; + +#endif diff --git a/callback.h b/callback.h new file mode 100644 index 0000000..3fbc2e0 --- /dev/null +++ b/callback.h @@ -0,0 +1,30 @@ +/* + Copyright 2004-2005 Chris Tallon + + This file is part of VOMP. + + VOMP 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. + + VOMP 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 VOMP; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#ifndef CALLBACK_H +#define CALLBACK_H + +class Callback +{ + public: + virtual void call()=0; +}; + +#endif diff --git a/channel.cc b/channel.cc new file mode 100644 index 0000000..cc01b23 --- /dev/null +++ b/channel.cc @@ -0,0 +1,36 @@ +/* + Copyright 2004-2005 Chris Tallon + + This file is part of VOMP. + + VOMP 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. + + VOMP 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 VOMP; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include "channel.h" + +Channel::Channel() +{ + number = 0; + type = 0; + name = NULL; + + index = -1; +} + +Channel::~Channel() +{ + if (name) delete[] name; + index = -1; // just in case +} diff --git a/channel.h b/channel.h new file mode 100644 index 0000000..e17bdd3 --- /dev/null +++ b/channel.h @@ -0,0 +1,41 @@ +/* + Copyright 2004-2005 Chris Tallon + + This file is part of VOMP. + + VOMP 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. + + VOMP 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 VOMP; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#ifndef CHANNEL_H +#define CHANNEL_H + +#include + +#include "defines.h" + +class Channel +{ + public: + Channel(); + ~Channel(); + + ULONG number; + ULONG type; + char* name; + + int index; +}; + +#endif diff --git a/command.cc b/command.cc new file mode 100644 index 0000000..f438d88 --- /dev/null +++ b/command.cc @@ -0,0 +1,393 @@ +/* + Copyright 2004-2005 Chris Tallon + + This file is part of VOMP. + + VOMP 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. + + VOMP 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 VOMP; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include "command.h" + +Command* Command::instance = NULL; + +Command::Command() +{ + if (instance) return; + instance = this; + initted = 0; + state = 0; +} + +Command::~Command() +{ + instance = NULL; +} + +Command* Command::getInstance() +{ + return instance; +} + +int Command::init() +{ + if (initted) return 0; + initted = 1; + + logger = Log::getInstance(); + viewman = ViewMan::getInstance(); + remote = Remote::getInstance(); + + if (!logger || !viewman || !remote) + { + initted = 0; + return 0; + } + + return 1; +} + +int Command::shutdown() +{ + if (!initted) return 0; + initted = 0; + return 1; +} + +void Command::stop() +{ + VDR::getInstance()->cancelFindingServer(); + irun = 0; +} + +void Command::run() +{ + if (!initted) return; + irun = 1; + + mainPid = getpid(); + + // moved from startup because surface delete doesn't work + + // just in case + Video::getInstance()->signalOn(); + Led::getInstance()->on(); + + // Blue background + View* v = new View(); + v->setDimensions(SCREENHEIGHT, SCREENWIDTH); + v->setBackgroundColour(0, 0, 150, 255); + v->draw(); + v->show(); + viewman->add(v); + viewman->removeView(v); + + // Wallpaper + VWallpaper* w = new VWallpaper(); + w->init("/wallpaper.jpg"); + w->draw(); + w->show(); + viewman->add(w); + + +// handleCommand(Remote::TWO); +// handleCommand(Remote::UP); +// handleCommand(Remote::PLAY); + +// handleCommand(Remote::DOWN); +// handleCommand(Remote::OK); + +// handleCommand(Remote::DOWN); +// handleCommand(Remote::DOWN); +// handleCommand(Remote::DOWN); +// handleCommand(Remote::OK); + + // state values: + // 0 = not connected + // 1 = got servers + // 2 = multiple servers, showing select box + // 3 = a server has been selected + // 4 = connected + // 5 = standby + + int selectServer; + UCHAR button = 0; + while(irun) + { + if (state != 4) // not really necessary, but chops out all the connecting rubbish if already connected + { + if (state == 0) + { + clearServerIPs(); + broadcastForServers(); + if (!irun) break; + state = 1; + } + + if (state == 1) + { + if (serverIPs.size() == 1) + { + selectServer = 0; + state = 3; + } + else + { + selectServer = -1; + state = 2; + VServerSelect* vs = new VServerSelect(&serverIPs, &selectServer); + vs->draw(); + vs->show(); + viewman->add(vs); + } + } + + if (state == 2) + { + // entering loop for 2nd time.. has a server been selected? + if (selectServer != -1) state = 3; + } + + if (state == 3) + { + Log::getInstance()->log("Command", Log::DEBUG, "Server selected: %i", selectServer); + + int success = connectToServer(selectServer); + clearServerIPs(); + + if (success) + { + VWelcome* vw = new VWelcome(); + vw->draw(); + vw->show(); + viewman->add(vw); + state = 4; + } + else + { + state = 0; + } + } + + if (state == 0) continue; + // state can't be 1 + // if state == 2 then drop to remote handling below + // state can't be 3 + // if state == 4 then drop through to main system, job done + } + + + button = remote->getButtonPress(2); // FIXME why is this set to 2 and not 0? so it can quit + if ((button == Remote::NONE) || (button == Remote::UNKNOWN)) continue; + + if (button != Remote::SIGNAL) handleCommand(button); + processMessageQueue(); + } +} + +void Command::postMessage(Message* m) +{ + MessageQueue::postMessage(m); + kill(mainPid, SIGURG); +} + +void Command::processMessage(Message* m) +{ + Log::getInstance()->log("Command", Log::DEBUG, "processing message %i", m->message); + + switch(m->message) + { + case Message::STANDBY: + { + doStandby(); + break; + } + case Message::STOP_PLAYBACK: + { + handleCommand(Remote::STOP); // an odd way of doing it, but so simple + break; + } + } +} + +void Command::clearServerIPs() +{ + // Clear the serverIPs vector + for(UINT k = 0; k < serverIPs.size(); k++) + { + delete[] serverIPs[k]; + } + serverIPs.clear(); +} + +void Command::handleCommand(int button) +{ + if (state == 5 && (button != Remote::POWER)) return; + + if (viewman->handleCommand(button)) return; + + // command was not handled + + switch(button) + { + case Remote::LEFT: + case Remote::RIGHT: + { + VVolume* v = new VVolume(); + v->handleCommand(button); // this will draw+show + viewman->add(v); + viewman->timedDelete(v, 2, 1); + return; + } + case Remote::MUTE: + { + VMute* v = new VMute(); + v->draw(); + v->show(); + viewman->add(v); + viewman->timedDelete(v, 2, 1); + return; + } + case Remote::POWER: + { + doStandby(); + return; + } + case Remote::RECORD: + { + Osd::getInstance()->screenShot("/out.jpg"); + return; + } + } +} + +void Command::broadcastForServers() +{ + VInfo* viewWait = new VInfo(); + viewWait->setDimensions(200, 400); + viewWait->setScreenPos(170, 200); + viewWait->setMainText("\n Locating server"); + viewWait->draw(); + viewWait->show(); + viewman->add(viewWait); + + + VDR* vdr = VDR::getInstance(); + vdr->findServers(serverIPs); + if (!irun) return; + viewman->removeView(viewWait); +} + +int Command::connectToServer(int vectorIndex) +{ + char a[60]; + struct timespec ts; + + VDR* vdr = VDR::getInstance(); + vdr->setServerIP(serverIPs[vectorIndex]); + + logger->log("Command", Log::NOTICE, "Connecting to server at %s", serverIPs[vectorIndex]); + + VInfo* viewWait = new VInfo(); + viewWait->setDimensions(200, 400); + viewWait->setScreenPos(170, 200); + viewWait->setMainText("\n Connecting to VDR"); + viewWait->draw(); + viewWait->show(); + viewman->add(viewWait); + + int success = vdr->connect(); + + if (success) + { + Log::getInstance()->log("Command", Log::DEBUG, "Connected ok, doing login"); + success = vdr->doLogin(); + + if (success) + { + strcpy(a, "\n Connected"); + ts.tv_sec = 0; + ts.tv_nsec = 500000000; + } + else + { + strcpy(a, "\n Login failed"); + ts.tv_sec = 3; + ts.tv_nsec = 0; + } + } + else + { + strcpy(a, "\n Connection failed"); + ts.tv_sec = 3; + ts.tv_nsec = 0; + } + + viewWait->setMainText(a); + viewWait->draw(); + viewWait->show(); + + if (irun) nanosleep(&ts, NULL); // only do the wait if we aren't shutting down + +/* + vdr->configSave("Section Name This Is blah blah blah 495834509725049375032end", "thekey with this space ", "1234value"); + sleep(10); + + char* conf = vdr->configLoad("fred", "bill"); + if (conf) + { + //printf("And the config value returned is %s\n", conf); + delete[] conf; + } + else + { + //printf("Conf value return is NULL :(\n"); + } +*/ + + viewman->removeView(viewWait); + + return success; +} + +void Command::doStandby() +{ + if (state == 5) + { + Video::getInstance()->signalOn(); + Led::getInstance()->on(); + state = 0; + } + else + { + ViewMan* viewman = ViewMan::getInstance(); + + viewman->removeAll(); + viewman->redrawAll(); + + + VDR::getInstance()->disconnect(); + Video::getInstance()->signalOff(); + Led::getInstance()->off(); + state = 5; + } +} + +void Command::doReboot() +{ + VDR::getInstance()->disconnect(); + // just kill it... + logger->log("Command", Log::NOTICE, "Reboot"); + reboot(LINUX_REBOOT_CMD_RESTART); +} diff --git a/command.h b/command.h new file mode 100644 index 0000000..6cef15a --- /dev/null +++ b/command.h @@ -0,0 +1,88 @@ +/* + Copyright 2004-2005 Chris Tallon + + This file is part of VOMP. + + VOMP 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. + + VOMP 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 VOMP; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#ifndef COMMAND_H +#define COMMAND_H + +#include // for reboot +#include +#include + +#include +#include + +#include + +#include "defines.h" +#include "log.h" +#include "viewman.h" +#include "led.h" +#include "video.h" +#include "remote.h" +#include "vdr.h" +#include "list.h" +#include "message.h" +#include "messagequeue.h" +#include "box.h" +#include "view.h" +#include "vinfo.h" +#include "vwallpaper.h" +#include "vvolume.h" +#include "vserverselect.h" +#include "vwelcome.h" +#include "vmute.h" + +class Command : public MessageQueue +{ + public: + Command(); + ~Command(); + static Command* getInstance(); + + int init(); + int shutdown(); + void run(); + void stop(); + void doReboot(); + void postMessage(Message* m); // override of MessageQueue::postMessage + + private: + void handleCommand(int); + void broadcastForServers(); + int connectToServer(int vectorIndex); + void doStandby(); + void clearServerIPs(); + + static Command* instance; + pid_t mainPid; + UCHAR initted; + UCHAR irun; + UCHAR state; + + std::vector serverIPs; + + Log* logger; + ViewMan* viewman; + Remote* remote; + + void processMessage(Message* m); +}; + +#endif diff --git a/defines.h b/defines.h new file mode 100644 index 0000000..8b3a337 --- /dev/null +++ b/defines.h @@ -0,0 +1,36 @@ +/* + Copyright 2004-2005 Chris Tallon + + This file is part of VOMP. + + VOMP 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. + + VOMP 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 VOMP; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#ifndef DEFINES_H +#define DEFINES_H + +typedef unsigned char UCHAR; +typedef unsigned short USHORT; +typedef unsigned int UINT; +typedef unsigned long ULONG; +typedef unsigned long long ULLONG; + +#define SCREENWIDTH 720 +#define SCREENHEIGHT 576 + +ULLONG htonll(ULLONG a); +ULLONG ntohll(ULLONG a); + +#endif diff --git a/demuxer.cc b/demuxer.cc new file mode 100644 index 0000000..b166173 --- /dev/null +++ b/demuxer.cc @@ -0,0 +1,480 @@ +/* + Copyright 2005 Mark Calderbank + + This file is part of VOMP. + + VOMP 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. + + VOMP 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 VOMP; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include "demuxer.h" + +const int Demuxer::FrameRates[9] = { 0, 23, 24, 25, 29, 30, 50, 59, 60 }; + +Demuxer* Demuxer::instance = NULL; + +Demuxer::Demuxer() +{ + if (instance) return; + instance = this; + initted = 0; +} + +Demuxer::~Demuxer() +{ + shutdown(); + instance = NULL; +} + +Demuxer* Demuxer::getInstance() +{ + return instance; +} + +int Demuxer::init() +{ + if (!initted) + { + if ( videostream.init(demuxMemory) || + audiostream.init(demuxMemory) || + !(local_frame = (UCHAR *) malloc(0x10000))) + { + printf("failed to initialize demuxer\n"); + shutdown(); + return 1; + } + } + + reset(); + initted = 1; + return 0; +} + +void Demuxer::reset() +{ + flush(); + video_current = audio_current = -1; + horizontal_size = vertical_size = 0; + aspect_ratio = (enum AspectRatio) 0; + frame_rate = bit_rate = 0; +} + +int Demuxer::shutdown() +{ + videostream.shutdown(); + audiostream.shutdown(); + free(local_frame); + initted = 0; + return 1; +} + +void Demuxer::flush() +{ + videostream.flush(); + audiostream.flush(); + state_frametype = state_framepos = 0; + seek(); +} + +void Demuxer::flushAudio() +{ + audiostream.flush(); +} + +void Demuxer::seek() +{ + seeking = 1; +} + +void Demuxer::setAudioStream(int id) +{ + audio_current = id; +} + +void Demuxer::setVideoStream(int id) +{ + video_current = id; +} + +int Demuxer::scan(UCHAR *buf, int len) +{ + // Temporarily, just look for the lowest audio stream and return it + int ret = 0; + UCHAR byte; + int zeros = 0; + while (len > 1) + { + // We are searching for a string of bytes (0,0,1). + byte = *(buf++); --len; + + if (byte == 0) + { + ++zeros; continue; + } + if (zeros < 2 || byte != 1) + { + zeros = 0; continue; + } + zeros = 0; + // We have found the pattern (0,0,1). + // Check the next byte for the sub-frame type. + byte = *(buf++); --len; + if (byte >= 0xc0 && byte <= 0xdf) // Audio + if (ret == 0 || ret > byte) ret = byte; + } + return ret; +} + +int Demuxer::put(UCHAR* buf, int len) +{ + int ret = 0; // return number of bytes consumed + int parsed = 0; // number of bytes parsed by sub-function + int full; // sub-function sets this to tell us to exit early + inbuf = buf; // Initialize buffer pointer + + while (len) + { + full = 0; + switch (state_frametype) + { + case 0: // Search for frame + parsed = parse_find_frame(len); + break; + case FRAMETYPE_VID0 ... FRAMETYPE_VIDMAX: + parsed = parse_video_frame(len, &full); + break; + case FRAMETYPE_AUD0 ... FRAMETYPE_AUDMAX: + parsed = parse_audio_frame(len, &full); + break; + } + ret += parsed; len -= parsed; + if (full) // We have to exit early. + break; // out of while loop + } + Log::getInstance()->log( + "Demuxer", Log::DEBUG, "Put %d; took %d", ret + len, ret); + return ret; +} + +int Demuxer::parse_find_frame(int len) +{ + int ret = 0; // return number of bytes parsed + UCHAR byte; + + // In this function, state_framepos represents + // the number of fixed header bytes found so far. + if (state_framepos > 3 || state_framepos < 0) + { + // ERROR! + state_framepos = 0; + } + + while (len) + { + byte = *inbuf++; + ++ret; --len; + switch (state_framepos) + { + case 0: + case 1: + if (byte == 0) + ++state_framepos; + else + state_framepos = 0; + break; + case 2: + if (byte == 1) + ++state_framepos; + else if (byte != 0) + state_framepos = 0; + break; + default: + state_framepos = 0; // Set initial state for the new frame + switch (byte) + { + case 0: + state_framepos = 1; // Count this as a first header byte! + break; + case FRAMETYPE_VID0 ... FRAMETYPE_VIDMAX: + case FRAMETYPE_AUD0 ... FRAMETYPE_AUDMAX: + state_frametype = byte; + return ret; + } + // Not a recognised frame type. Go back to Old Kent Road. + break; + } + } + return ret; +} + +int Demuxer::parse_video_frame(int len, int* full) +{ + int ret = 0; // return number of bytes consumed + int stream_sent, bytes_remaining; + + switch(state_framepos) + { + case 0: // Brand new video frame. Set initial states. + state_stream_fill = 0; state_vid_parsed = 0; + // Create a local copy of the frame header + local_frame[0] = local_frame[1] = 0; local_frame[2] = 1; + local_frame[3] = state_frametype; + // If no video stream has been set, use this one. + if (video_current == -1) video_current = state_frametype; + // Get MSB of frame length and copy to local frame. + frame_length = *inbuf << 8; + local_frame[4] = *inbuf; + ++inbuf; ++state_framepos; ++ret; --len; + if (len == 0) return ret; + // FALL THROUGH TO NEXT BYTE IN STREAM + case 1: // Get LSB of frame length and copy to local frame. + frame_length += *inbuf; + local_frame[5] = *inbuf; + ++inbuf; ++state_framepos; ++ret; --len; + if (len == 0) return ret; + // FALL THROUGH TO NEXT BYTE IN STREAM + case 2: // First data byte + if (len >= frame_length // If we have the entire frame + && !state_vid_parsed) // and haven't parsed it yet + { + if (video_current == state_frametype) // and we're interested + parse_video_details(inbuf, frame_length); // then parse it + state_vid_parsed = 1; + } + } + // We are in the frame data + bytes_remaining = 2 + frame_length - state_framepos; + if (video_current != state_frametype) + { + // We don't want this frame. Throw it away. + if (len >= bytes_remaining) + { + inbuf += bytes_remaining; + ret += bytes_remaining; + state_frametype = state_framepos = 0; + return ret; + } + else + { + inbuf += len; ret += len; + state_framepos += len; + return ret; + } + } // No fall through here + + if (state_vid_parsed) + { + // We have already parsed the whole frame + if (seeking) // Still not found a sync point. Throw this frame away. + { + if (len >= bytes_remaining) + { + inbuf += bytes_remaining; + ret += bytes_remaining; + state_frametype = state_framepos = 0; + return ret; + } + else + { + inbuf += len; ret += len; return ret; + } + } // No fall through is allowed here + // Send frame header to stream + if (state_stream_fill < 6) + { + state_stream_fill += videostream.put(local_frame, + 6 - state_stream_fill); + if (state_stream_fill < 6) // stream is full! + { + *full = 1; return ret; + } + } + // Send all frame data we have to stream + if (len >= bytes_remaining) len = bytes_remaining; + stream_sent = videostream.put(inbuf, len); + inbuf += stream_sent; ret += stream_sent; + state_framepos += stream_sent; + state_stream_fill += stream_sent; + if (stream_sent != len) // stream is full! + { + *full = 1; return ret; + } + if (state_framepos == frame_length + 2) // frame done + { + state_frametype = state_framepos = 0; + } + return ret; + } // No fall through is allowed here + + // We haven't parsed the frame yet. It's arriving in pieces. + if (bytes_remaining) // There is data yet to copy to local_frame + { + if (len >= bytes_remaining) len = bytes_remaining; + memcpy(local_frame + state_framepos + 4, inbuf, len); + inbuf += len; ret += len; state_framepos += len; + if (len < bytes_remaining) // Not all arrived yet + return ret; + parse_video_details(local_frame+6, frame_length); + if (seeking) // Still not found a sync point. Ignore this frame. + return ret; + } + // We have the whole frame in local_frame. Send it to the stream. + state_stream_fill += videostream.put(local_frame, + 6 + frame_length - state_stream_fill); + if (state_stream_fill < frame_length + 6) // stream is full! + { + *full = 1; return ret; + } + state_frametype = state_framepos = 0; + return ret; +} + +int Demuxer::parse_audio_frame(int len, int* full) +{ + int ret = 0; // return number of bytes consumed + int stream_sent, bytes_remaining; + + switch(state_framepos) + { + case 0: // Brand new audio frame. Set initial states. + state_stream_fill = 0; + // Create a local copy of the frame header + local_frame[0] = local_frame[1] = 0; local_frame[2] = 1; + local_frame[3] = state_frametype; + // If no audio stream has been set, use this one. + if (audio_current == -1) audio_current = state_frametype; + // Get MSB of frame length and copy to local frame. + frame_length = *inbuf << 8; + local_frame[4] = *inbuf; + ++inbuf; ++state_framepos; ++ret; --len; + if (len == 0) return ret; + // FALL THROUGH TO NEXT BYTE IN STREAM + case 1: // Get LSB of frame length and copy to local frame. + frame_length += *inbuf; + local_frame[5] = *inbuf; + ++inbuf; ++state_framepos; ++ret; --len; + if (len == 0) return ret; + } + // We are in the frame data + bytes_remaining = 2 + frame_length - state_framepos; + if (audio_current != state_frametype) + { + // We don't want this frame. Throw it away. + if (len >= bytes_remaining) + { + inbuf += bytes_remaining; + ret += bytes_remaining; + state_frametype = state_framepos = 0; + return ret; + } + else + { + inbuf += len; ret += len; + state_framepos += len; + return ret; + } + } // No fall through is allowed here + + // Send frame header to stream + if (state_stream_fill < 6) + { + state_stream_fill += audiostream.put(local_frame, + 6 - state_stream_fill); + if (state_stream_fill < 6) // stream is full! + { + *full = 1; return ret; + } + } + // Send all frame data we have to stream + if (len >= bytes_remaining) len = bytes_remaining; + stream_sent = audiostream.put(inbuf, len); + inbuf += stream_sent; ret += stream_sent; + state_framepos += stream_sent; + state_stream_fill += stream_sent; + if (stream_sent != len) // stream is full! + { + *full = 1; return ret; + } + if (state_framepos == frame_length + 2) // frame done + { + state_frametype = state_framepos = 0; + } + return ret; +} + +void Demuxer::parse_video_details(UCHAR* buf, int len) +{ + UCHAR byte; + int zeros = 0; + while (len >= 8) // 8 is length of a GOP header + { + // We are searching for a string of bytes (0,0,1). + byte = *(buf++); --len; + + if (byte == 0) + { + ++zeros; continue; + } + if (zeros < 2 || byte != 1) + { + zeros = 0; continue; + } + zeros = 0; + // We have found the pattern (0,0,1). + // Check the next byte for the sub-frame type. + byte = *(buf++); --len; + switch (byte) + { + case 0x00: // Picture header + // 10 bits: temporal reference + // 3 bits: coding type (I/P/B) + // ... + if (len < 2) return; + if ( (buf[1] & 0x38) == 0x08 ) // I-frame + seeking = 0; + buf += 4; // Minimum length of picture header + len -= 4; + break; + case 0xb3: // Sequence header + // 12 bits: Horizontal size + // 12 bits: Vertical size + // 4 bits: Aspect ratio + // 4 bits: Frame rate code + // 18 bits: Bit rate value + // ... + if (len < 7) return; + horizontal_size = ((int)buf[0] << 4) | ((int)buf[1] >> 4); + vertical_size = (((int)buf[1] & 0xf) << 8) | (int)buf[2]; + aspect_ratio = (enum AspectRatio)(buf[3] >> 4); + frame_rate = buf[3] & 0x0f; + if (frame_rate >= 1 && frame_rate <= 8) + frame_rate = FrameRates[frame_rate]; + else + frame_rate = 0; + bit_rate = ((int)buf[4] << 10) | + ((int)buf[5] << 2) | + ((int)buf[6] >> 6); + seeking = 0; + buf += 8; // Minimum length of sequence header + len -= 8; + break; + case 0xb8: // Group header + // We're not going to bother parsing anything. + seeking = 0; + buf += 4; // Minimum length of group header + len -= 4; + break; + } + } +} diff --git a/demuxer.h b/demuxer.h new file mode 100644 index 0000000..2193c8e --- /dev/null +++ b/demuxer.h @@ -0,0 +1,147 @@ +/* + Copyright 2005 Mark Calderbank + + This file is part of VOMP. + + VOMP 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. + + VOMP 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 VOMP; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +/* + +Thanks goes to Jon Gettler of the MVPMC project and Stephen Rice for +the demuxer in mvpmc. It was used in the creation of this Demuxer, +however, no code was copied verbatim. + +*/ + + +#ifndef DEMUXER_H +#define DEMUXER_H + +#include +#include +#include "stream.h" +#include "log.h" +#include "defines.h" + +class Demuxer +{ + public: + Demuxer(); + ~Demuxer(); + static Demuxer* getInstance(); + int init(); + void reset(); + void flush(); + void flushAudio(); + void seek(); + void setVideoStream(int id); + void setAudioStream(int id); + int writeAudio(int fd) { return audiostream.drain(fd); } + int writeVideo(int fd) { return videostream.drain(fd); } + int scan(UCHAR* buf, int len); + int put(UCHAR* buf, int len); + + private: + static Demuxer* instance; + Stream videostream; + Stream audiostream; + int shutdown(); + int initted; + int seeking; + UCHAR* inbuf; + + int video_current, audio_current; + int state_frametype, state_framepos; + int state_stream_fill, state_vid_parsed; + int frame_length; + int parse_find_frame(int len); + int parse_video_frame(int len, int* full); + int parse_audio_frame(int len, int* full); + void parse_video_details(UCHAR* buf, int len); + + UCHAR* local_frame; + static const int demuxMemory = 2097152; + static const int Demuxer::FrameRates[9]; + + enum FRAMETYPE + { + FRAMETYPE_AUD0 = 0xc0, + FRAMETYPE_AUD1, + FRAMETYPE_AUD2, + FRAMETYPE_AUD3, + FRAMETYPE_AUD4, + FRAMETYPE_AUD5, + FRAMETYPE_AUD6, + FRAMETYPE_AUD7, + FRAMETYPE_AUD8, + FRAMETYPE_AUD9, + FRAMETYPE_AUD10, + FRAMETYPE_AUD11, + FRAMETYPE_AUD12, + FRAMETYPE_AUD13, + FRAMETYPE_AUD14, + FRAMETYPE_AUD15, + FRAMETYPE_AUD16, + FRAMETYPE_AUD17, + FRAMETYPE_AUD18, + FRAMETYPE_AUD19, + FRAMETYPE_AUD20, + FRAMETYPE_AUD21, + FRAMETYPE_AUD22, + FRAMETYPE_AUD23, + FRAMETYPE_AUD24, + FRAMETYPE_AUD25, + FRAMETYPE_AUD26, + FRAMETYPE_AUD27, + FRAMETYPE_AUD28, + FRAMETYPE_AUD29, + FRAMETYPE_AUD30, + FRAMETYPE_AUD31, + FRAMETYPE_AUDMAX = FRAMETYPE_AUD31, + + FRAMETYPE_VID0 = 0xe0, + FRAMETYPE_VID1, + FRAMETYPE_VID2, + FRAMETYPE_VID3, + FRAMETYPE_VID4, + FRAMETYPE_VID5, + FRAMETYPE_VID6, + FRAMETYPE_VID7, + FRAMETYPE_VID8, + FRAMETYPE_VID9, + FRAMETYPE_VID10, + FRAMETYPE_VID11, + FRAMETYPE_VID12, + FRAMETYPE_VID13, + FRAMETYPE_VID14, + FRAMETYPE_VID15, + FRAMETYPE_VIDMAX = FRAMETYPE_VID15 + }; + + enum AspectRatio + { + ASPECT_4_3 = 2, + ASPECT_16_9 = 3 + }; + + int horizontal_size; + int vertical_size; + enum AspectRatio aspect_ratio; + int frame_rate; + int bit_rate; +}; + +#endif diff --git a/directory.cc b/directory.cc new file mode 100644 index 0000000..b73b982 --- /dev/null +++ b/directory.cc @@ -0,0 +1,86 @@ +/* + Copyright 2004-2005 Chris Tallon + + This file is part of VOMP. + + VOMP 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. + + VOMP 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 VOMP; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include "directory.h" + +ULONG Directory::totalSpace = 0; +ULONG Directory::freeSpace = 0; +ULONG Directory::usedPercent = 0; + +Directory::Directory() +{ + name = NULL; + dirList = new List(); + recList = new List(); + + isRoot = 0; + index = -1; +} + +Directory::~Directory() +{ + if (name) delete[] name; + index = -1; // just in case + + if (dirList) + { + while (!dirList->isEmpty()) + { + dirList->reset(); + delete (Directory*)dirList->remove(); + } + + delete dirList; + } + + if (recList) + { + while (!recList->isEmpty()) + { + recList->reset(); + delete (Recording*)recList->remove(); + } + + delete recList; + } +} + +void Directory::setName(char* newName) +{ + name = new char[strlen(newName) + 1]; + strcpy(name, newName); +} + +Directory* Directory::getDirByName(char* dirName) +{ + Directory* currentDir; + for(dirList->reset(); (currentDir = (Directory*)dirList->getCurrent()); dirList->next()) + { + if (!strcmp(dirName, currentDir->name)) return currentDir; + } + return NULL; +} + +ULONG Directory::getNumRecordings() +{ + return recList->getNumElements(); +} + +// FIXME make an add function in here that adds recs to the end of the list diff --git a/directory.h b/directory.h new file mode 100644 index 0000000..f9d0d3c --- /dev/null +++ b/directory.h @@ -0,0 +1,55 @@ +/* + Copyright 2004-2005 Chris Tallon + + This file is part of VOMP. + + VOMP 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. + + VOMP 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 VOMP; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#ifndef DIRECTORY_H +#define DIRECTORY_H + +#include + +#include "defines.h" +#include "list.h" +#include "recording.h" + +class Directory +{ + public: + Directory(); + ~Directory(); + + void setName(char* newName); + Directory* getDirByName(char* dirName); + void setFreeSpace(ULLONG); + ULONG getNumRecordings(); + + UCHAR isRoot; + char* name; + + int index; + + List* dirList; + List* recList; + + static ULONG totalSpace; + static ULONG freeSpace; + static ULONG usedPercent; + +}; + +#endif diff --git a/dsock.cc b/dsock.cc new file mode 100644 index 0000000..4acc89f --- /dev/null +++ b/dsock.cc @@ -0,0 +1,190 @@ +/* + Copyright 2004-2005 Chris Tallon + + This file is part of VOMP. + + VOMP 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. + + VOMP 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 VOMP; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include "dsock.h" + +DatagramSocket::DatagramSocket(short port) +{ + theInstance = this; + myPort = port; + addrlen = sizeof(struct sockaddr); + + if ((socketnum = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1) + { perror("socket"); exit(1); } + + myAddr.sin_family = AF_INET; // host byte order + myAddr.sin_port = htons(myPort); // short, network byte order + myAddr.sin_addr.s_addr = INADDR_ANY; // auto-fill with my IP + memset(&(myAddr.sin_zero), 0, 8); // zero the rest of the struct + + if (bind(socketnum, (struct sockaddr *)&myAddr, addrlen) == -1) + { perror("bind"); exit(1); } + + FD_ZERO(&readfds); + FD_SET(socketnum, &readfds); + tv.tv_sec = 0; + tv.tv_usec = 0; + + int allowed = 1; + setsockopt(socketnum, SOL_SOCKET, SO_BROADCAST, &allowed, sizeof(allowed)); +} + +DatagramSocket::~DatagramSocket() +{ + close(socketnum); +} + +DatagramSocket* DatagramSocket::theInstance = 0; +DatagramSocket* DatagramSocket::getInstance(void) +{ + return theInstance; +} + +unsigned char DatagramSocket::waitforMessage(unsigned char how) +{ + /* how = 0 - block + how = 1 - start new wait + how = 2 - continue wait + */ + + struct timeval* passToSelect = NULL; + + + if (how == 0) + { + passToSelect = NULL; + } + else if (how == 1) + { + tv.tv_sec = 1; + tv.tv_usec = 500000; + passToSelect = &tv; + } + else if (how == 2) + { + if ((tv.tv_sec == 0) && (tv.tv_usec == 0)) // protection in case timer = 0 + { + tv.tv_sec = 1; + tv.tv_usec = 500000; + } + passToSelect = &tv; + } + FD_ZERO(&readfds); + FD_SET(socketnum, &readfds); + + if (select(socketnum + 1, &readfds, NULL, NULL, passToSelect) <= 0) + { return 1; } + + if ((mlength = recvfrom(socketnum, buf, MAXBUFLEN, 0, + (struct sockaddr *)&theirAddr, &addrlen)) == -1) + { perror("recvfrom"); return 0; } + else + { + memset(&buf[mlength], 0, MAXBUFLEN - mlength); + strcpy(fromIPA, inet_ntoa(theirAddr.sin_addr)); + fromPort = ntohs(theirAddr.sin_port); + + if (DSOCKDEBUG) + { + //printf("%s:%i\tIN %i\t", fromIPA, fromPort, mlength); + int k; + for(k = 0; k < mlength; k++) + printf("%u ", (unsigned char)buf[k]); + printf("\n"); + } + return 2; + } + + /* Return 0, failure + Return 1, nothing happened, timer expired + Return 2, packet arrived (timer not expired) + */ +} + +int DatagramSocket::getDataLength(void) const +{ + return mlength; +} + +char *DatagramSocket::getData(void) { return buf; } +char *DatagramSocket::getFromIPA(void) { return fromIPA; } +short DatagramSocket::getFromPort(void) const { return fromPort; } + +void DatagramSocket::send(char *ipa, short port, char *message, int length) +{ + if (DSOCKDEBUG) + { + printf("%s:%i\tOUT %i\t", ipa, port, length); + int k; + uchar l; + for (k = 0; k < length; k++) + { l = (uchar)message[k]; printf("%u ", l); } + } + + int sentLength = 0; + + theirAddr.sin_family = AF_INET; // host byte order + theirAddr.sin_port = htons(port); // short, network byte order + struct in_addr tad; // temp struct tad needed to pass to theirAddr.sin_addr + tad.s_addr = inet_addr(ipa); + theirAddr.sin_addr = tad; // address + memset(&(theirAddr.sin_zero), 0, 8); // zero the rest of the struct + + errno = 0; + + sentLength = sendto(socketnum, message, length, 0, (struct sockaddr *)&theirAddr, addrlen); + if (sentLength == length) + { + if (DSOCKDEBUG) printf(" GOOD\n"); + } + else + { + if (DSOCKDEBUG) + { + printf(" --BAD--"); fflush(stdout); + } + sentLength = sendto(socketnum, message, length, 0, (struct sockaddr *)&theirAddr, addrlen); + if (sentLength == length) + { + if (DSOCKDEBUG) printf(" GOOD\n"); + } + else + { + if (DSOCKDEBUG && (sentLength != length)) + { + + printf(" -#-FAILED-#-\n"); + printf("--------------\n"); + printf("Sendto failure\n"); + printf("--------------\n"); + printf("%s:%i\tOUT %i %i ...\n", ipa, port, length, sentLength); + perror("Perror reports"); + printf("errno value: %d\n", errno); + printf("errno translated: %s\n", strerror(errno)); + // printf("h_errno value: %d\n", h_errno); + // printf("\nActual address: %s\n", inet_ntoa(tad)); + // printf("Actual port: %i\n", ntohs(theirAddr.sin_port)); + printf("continuing...\n\n"); + + } + } + } +} + diff --git a/dsock.h b/dsock.h new file mode 100644 index 0000000..110c31a --- /dev/null +++ b/dsock.h @@ -0,0 +1,67 @@ +/* + Copyright 2004-2005 Chris Tallon + + This file is part of VOMP. + + VOMP 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. + + VOMP 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 VOMP; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#ifndef DSOCK_H +#define DSOCK_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define MAXBUFLEN 2000 +typedef unsigned char uchar; + +class DatagramSocket +{ + public: + DatagramSocket(short); // port + ~DatagramSocket(); + static DatagramSocket* getInstance(void); + unsigned char waitforMessage(unsigned char); // int =0-block =1-new wait =2-continue wait + int getDataLength(void) const; + char *getData(void); // returns a pointer to the data + char *getFromIPA(void); // returns a pointer to from IP address + short getFromPort(void) const; + void send(char *, short, char *, int); // send wants: IP Address ddn style, port, + // data, length of data + private: + const static char DSOCKDEBUG = 0; + static DatagramSocket* theInstance; + int socketnum; // Socket descriptor + short myPort; // My port number + struct sockaddr_in myAddr; // My address + struct sockaddr_in theirAddr; // User address + socklen_t addrlen; // length of sockaddr struct + char buf[MAXBUFLEN]; // main data buffer + char fromIPA[20]; // from string (ip address) + short fromPort; // which port user sent on + int mlength; // length of message + struct timeval tv; + fd_set readfds; +}; + +#endif diff --git a/fonts/helvB18-ISO8859-1.pcf b/fonts/helvB18-ISO8859-1.pcf new file mode 100644 index 0000000000000000000000000000000000000000..ad032c3ef3b6c53511d3ead795abcf68323aacba GIT binary patch literal 16200 zcmb`Oe|S~(eaAn^jRqA2EohWqx25 zIYE9#2XY-H4lWuXHLt1=Vo|Tfl-sha} z%}EFlW6$I3e1CmDpYP}U`Fzh0t~q6!o7$(CSs7dn#}a1yDa)gFGv&P%X8dPYBlHsE z&(M&L>Yy!I$T2=Wbbg3elJ+AVEg#QShQqLB6PCb7I-&5sP_%Q^Y zolxaU_^F28!mR|AvT5*)Dqn@uRLZY_!0(SxSs< z=Tx~0%D;7A!@5<=)~vVM=G>;V-B){m{mS(lR@L5LXDia#ZRw6oQ_3E!t6#pNG3@<# zF57HtSJtj-v^BQ2uJOV8WsNJsp;ftjYbtBC%a(0e+qiyZUD#`@>mRCHxnXVnr|N8V zL;b48u)3yhZNtiSjr9$yHaujp#(G=3x^`*(s^zxYY9FXuQ@gxwLokOeT~WJ+2{){% zTVB7m5tr-NHdI&NaaU=eZq?F;Wzt+^OKVqeSP^(_54p;HwM!$HN-IkSt6AExdi@%$ z(3a-fyYrbXEgi|5n?9IabXWE5x9EIlGKfxcZFiv~-C9W2w>9PR?YVraBi(#!vNoGd zu8~q9xh7pm=eMczJWJKGbl0NfvdorDM=G1F+uE6FZ%wy#AR5}rzBq7 zlFSs6sboh!)tqikj&FtF19o5 zlj~}iMO%TLt7|xR%%FZ5lnoDa8CMLS8|K2{W^xUe=C#2{On9PI-FK|mcks|5&+FUM z=k@L0GvMvow|`)}_t<0f9q1p})i-eDkk>ab!0FN54D8)Eu)A-cPWulGboKQ=cAyuv zM|bt@-M6ntHP73F6?D;!coa{m1*by; z)PmDv2dM?8pc#y69r9j|bLxML)8QkW0+FB=Xi)15?WxJ45gD1|$m8@Kl=+}97~Q*f zV0XB{J*xHhAL{0`GwAEY=l;l-{*l^a{hmj_G|<00^hN&la-u0G)$AKMjBY=|l8b}` zjeYxQ%Cfh2FEN#fci;f0Lx)_A=I(Iv{rfTcD3(3asM+@Q1gTYEC30|=*H3C?WoMWp zgdb%9;l29~b>fEdwtrv;a-lD~yS-Xku6AJN|)8p#nMB;o7?$W)Y7+v?bQ&vMeFlxu(47ZM3U?X(E z3*0;^U=A#S)$lO1z|-)mS%O!E1Y-&8B%Xoeysb=ydjT62&%!I=ZRxU`D3QGk`9m}3g|rYwUV_$Itzb_KSsco?vA1@^DRk1Lt;$}V^w zUgz1Kgooe=95tkQ z0=`Vgm+5bq%|LF(62R_^qfi9qzlQm)SpoE4b1Zy6x|a5}=wFK;*B*hF;H=rZ=D=!r z5?%v*npp+do%t|eV`dLL57?Ud3cO`Di@9gr4y=7v7cloMY|g^Qtg~j<5rgX(yRHMC z1^TZ?=lX|%bzYDERp?itTlE6GWp)GdH|z)IxDg+2MD|8xZ$x%Bva^w$jUThmn9V_U z4zhEQor~;TWasw4H{q<=yk&3@7@yDh{MCT`{34*ATnH`j6ub)Pyt^9O;aTv_-ZK+c z!ftp0PMN*;X4nWv;T2v|r@+0?0Z#&QH@#){zFVLfkb57t-jCi4UQ6HgQR-Q zN%+3cdwkLCpJ0%BZ#&~SLvs`!?Kw~l3js0P2>vCIjAW%FUD@y<-d7d%YwSWuCO)@M zdj{yA9zCEjHiofrN7)$m$N|Ld`p7soQZK@p7(R7}=5=U3t;3O|zA@rn%3=)7r`&Ca zLGQw7TyoC8CDhMGxW0>(F1K!ugvZ?%{rRA=E@%fITr8Z<5PgFn`FS9nN{^=j48jn| zH_1yzds8wsa3{$3EieSmw&Wbc>IXmKT-27`M8qJa+LGG|nyVMIPyL9Klo~(njl@xP z$w}VLEt{3J^?of}+^VSy#lhj`(fkf)PwR4hDqX+R8H&cg$CwD>M0qzP)V9#y9!ft3 z)lr8}Ydl5?jgh&Rwg;MLI>;yG*pEuJ)vs~IOt{0feLBuSAWIq8irVV;VJAp_C_?d^ z2a2g;>7ZJwtFQ7Dd*rOy5`^0?H*5MfHcp$p*u?!xd=Fj>c@w#zV_{B~pgSL3>AU>R zS0BuV#UA&wh^<9(65;#!8*$F?*&}yFvl9`6w1fSjwm%}Py6(+dqvBOVy9?UcAg6%p zDAcDh$w*c@(v^*pUFnSn^6~kCdC{YL6mB1%*N?2zQF-3D$2g4bckQw33w*Rte()6W z0`&#!qh15^pQjH4<1tLX7;h}-i)O zJQy8BESHWS#cw2^1(9O~5(xM)5&dE5@3 zDe9XHPQQr0<6i0;V@L6~pOQ(>EEM{#5kmK@AkVaL*NsBkT0(*V;8l59m4? z0_8(G+oQJnhNHGm8Atb{VK022IZ+(h*Q%eUUt^MyAHCG&hfh6@`ZOk)vf^m&rriq# zkj*&i)0kue`xdR!3+ElC^rJp!Uvl?=i|aY+!nH3{PSg+iA777;?Ktsx4SHNh7r^OQ zbh!4VO6R}RbM1+iXHYx^W9J#7?sp&h@bGL$8R;D{iggjMX0VmjSa?ddqI9_T=rb)?5iwZ z1cpjSk=lh=!kE_f{Rp433(mrepnk9FNd@U$svT7VesmBB;RFb2cZXEj^M||;E*3;ZZUjUQ*2H~sJ_?>#}pq?7UPVK+{5F3 z<&H4V@sPv#C7(q0)M&q)eiwG+gY!*w_05TJbGtU(fiLQh>uOwWA7n$s$E#^C0nOva z)YlF^40;!4h%wFgEAVYJHT3PE?^olX{>3nR0u+%E8$mu*!5JWI!8@KxS6>+Qxw4D4 zi=Qjir^CfUd5!0EZgF(Z7jDG9pnoCg{e96Fqihrua6POYTmKC(4&1h^GvM@nPcI8pa>4vR*6cG zXQl}5F+-HYple5ClF@agL#3D>p}c612WzF=TI4WQ^#cO z%=Nfmz@0L}Fq*ZL!CRW3qN`Ls#gStPLMsLKwt|A}AHF$sjvE=+0MQ4H@vHQ3O-La46$lEx}e zlFPF^%gA|k5BD0{TmOae0iL;6^DKfMl&X0c^(^6?^-TEx84(}#eDZzv!31&7s`=PR zc%$z*6SX0^xEbmc`-&9W&!@Bx3 z=EopS!8^ndWt@|=MZ8aS{rg`1T)w4e3DpVzCMMt69;JJ14|Vw@+tZ;2wnuIC4M%P1 z+!NI)COqF_WP71aN*oiN@1w{H9TU}&k4{hZiR$&7Vx3$oLnuv$nzJJ@c=IX7Xm=ws z51YED7Qm+-M|~QTOch|pE(gVI35>l416%Yn!8+V^fKyNNGHE^ee z$3*=+Z+~IqQn6G#gbu|}=y3hh7vhW09w>6ZrrZuYp$irj$pie*!koMK(!6LM+`q+l zcq7j|=flPF7uS>gJ+K{gOjOU^!`_b0*!;)m()Y=PZs zALhrCMfMT?33R*N!9(ayZb*08$M{)hiQUaYYxv=@);?}a`9rBXzPVU#E3Dprn@>Jg z+Wof58u)bKllnTs8f~3DU=P|uw%$HvpSFkXckDB^;TU`d4449uuj{?hUv0y`<(6I*7v)-qV)3TFMYPl9_8;}_t;+B z$EP<3tlu8vXTL)>V2AC9J#J6f@7a^~`}TSJ13PMe$OkN6-~*OFwm-2i+SB%@_9go> zd&d6UzHDEyXYDWSIs2-8&HmE9ZhvLZ+c)g5?Qi%V=3Dl+_HF*g_B-}nK6rV-{@(t< z{;_mVEb@!*kN8)_b#OoYJMCLS65ZjL9u2{m#`n;-g3`&W1gCSU(%F%X5>31fb4!sQ zqxb@Cja?b`m*$b2`fJ1fU>sQ|S03pFw$%STa_Wov10N#)10Ptg`U2mv8!v-?^+B-a zXsxOT@rlMX9>^#@&Yt?H2Yy8{E#vP(6~i)a6Jui;%p1uCHjpXVI)QvXYzOg|zv@#? zj!;)lRF4S!ksr}IgZ|b~Kk;#ViU{P!#yx5$UPoSa7rUr*ad4%}nbtWL`BlnGd>&^r ziqY7$s~yBQ77r)m=5?iu{kWy}*_a#!ZP^Xxj_!+G2f;Cw^R;jTyayJ*?XU#ygEjCl zYysWkJ7EXxf&*|Eo`j?D6nqK30$&66A=jdD4f4M@;QR2e@MCxleggjsr{L$nUa?=m z8Tdaq3+KowMOisi0IyMHQ-Ii);d>d&DVqVTp=>57|JrLe!W@_fNnmYdH^D;q7%Ydi z@EK@^&Cmj$g)Fo|JLI7Qwm}zs4tiiGct9M=cEeuS5B+cu2H*%h0mP^5^FWNsh)>y< z;T!M*{4@LjegyvkKY`cb=Rgd~6EF?PPx%MnBXAcigHOO3co^`#93RW^t-Ke=O*!+G zKMmxf{5$Xx{2MS&`G3PN;MeTC3Lu7w>*3wNJc$nhuUiRXrTb3ees~awS0W8tfqjr* zt^{jO90JyvV7|mxfb}K53*~dm^bmC@CLBH1ans~cg0n}+!f@i;%2xN76Eft zFn7fYXawf2VD1X?Q$a2&hdbaDwWN4-wWpfWmhNiGrdn-lXO2(pHf61?vvpHCU&w4}v*uhji(Gp;-^5pR zmTIL|;H$S#xR7bvl1*ECDxYr4rZ;zlwcy)6OYs$7K2vza+OwSnYs$5@rmUsAy(Qfy zYnfcL6|$*9i+wJg&snZ5Z5`Wl*3ptr^Qg^r=52FkTiOblE-R$Bp_A6Pf7X^kuql_# zwb9+032WJOpUHaD z%4C`{`KHcR>uhT#EPSq*#)A}oPv*5j*3;39c?(*xnL0ArX5tacS95NAn*~`>q_d>L znmY4jqN&@uiP)xm?vZrcCS^I@6a=F=lg_6L8D%5-0@HH&=FJ2$i0hWlOg5Wt&4tU( z=C)*-QdvHDbZN_{w`4R`y4hM&O?jf*oF?GppA2JzG?T+ZXOP}}n9EWt)zsOMw$@H< zkrY8{Z;7^nRuI^1N;flqN_(NCg?p{3LQ^NJBec%HFf7QC^SshcwI!9^98MW^7D}5S z2vlvDnA*^f+AwjOv*|9Y4MSU7icW1_v8=7LrOu_gP`NHtu8S$xm9*+Znfg$sJ|F|tdUIhQ+fq)4%ITOgsf)H&CX~s9GSLMR z#F>v{BbhW|XbY#yh2ptTJQp*Wiv&tq&6#Z(E`eMagw9a0GgR!1DR!1Ly2HVaAPC*1 WZY#YPQwt8B1N<9@htGw+YyE#^n^95# literal 0 HcmV?d00001 diff --git a/fonts/helvB18.bdf b/fonts/helvB18.bdf new file mode 100644 index 0000000..9df3e60 --- /dev/null +++ b/fonts/helvB18.bdf @@ -0,0 +1,4034 @@ +STARTFONT 2.1 +FONT -Adobe-Helvetica-Bold-R-Normal--18-180-75-75-P-103-ISO8859-1 +SIZE 18 75 75 +FONTBOUNDINGBOX 18 23 -1 -5 + +STARTPROPERTIES 28 +FOUNDRY "Adobe" +FAMILY_NAME "Helvetica" +WEIGHT_NAME "Bold" +SLANT "R" +SETWIDTH_NAME "Normal" +ADD_STYLE_NAME "" +PIXEL_SIZE 18 +POINT_SIZE 180 +RESOLUTION_X 75 +RESOLUTION_Y 75 +SPACING "P" +AVERAGE_WIDTH 103 +CHARSET_REGISTRY "ISO8859" +CHARSET_ENCODING "1" +CAP_HEIGHT 14 +X_HEIGHT 10 +FACE_NAME "Helvetica Bold" +COPYRIGHT "Copyright (c) 1984, 1987 Adobe Systems Incorporated. All Rights Reserved. Copyright (c) 1988, 1991 Digital Equipment Corporation. All Rights Reserved." +NOTICE "Helvetica is a trademark of Linotype-Hell AG and/or its subsidiaries. " +_DEC_DEVICE_FONTNAMES "PS=Helvetica-Bold" +RELATIVE_SETWIDTH 50 +RELATIVE_WEIGHT 70 +FULL_NAME "Helvetica Bold" +WEIGHT 10 +QUAD_WIDTH 11 +DEFAULT_CHAR 0 +FONT_DESCENT 5 +FONT_ASCENT 16 +ENDPROPERTIES + +CHARS 192 + +STARTCHAR defaultchar +ENCODING 0 +SWIDTH 722 0 +DWIDTH 13 0 +BBX 11 13 1 0 +BITMAP +AAA0 +0000 +8020 +0000 +8020 +0000 +8020 +0000 +8020 +0000 +8020 +0000 +AAA0 +ENDCHAR + +STARTCHAR space +ENCODING 32 +SWIDTH 278 0 +DWIDTH 5 0 +BBX 1 1 0 0 +BITMAP +00 +ENDCHAR + +STARTCHAR exclam +ENCODING 33 +SWIDTH 333 0 +DWIDTH 5 0 +BBX 3 14 1 0 +BITMAP +E0 +E0 +E0 +E0 +E0 +E0 +E0 +E0 +C0 +C0 +00 +E0 +E0 +E0 +ENDCHAR + +STARTCHAR quotedbl +ENCODING 34 +SWIDTH 474 0 +DWIDTH 8 0 +BBX 5 5 2 9 +BITMAP +D8 +D8 +D8 +D8 +90 +ENDCHAR + +STARTCHAR numbersign +ENCODING 35 +SWIDTH 556 0 +DWIDTH 11 0 +BBX 11 13 0 0 +BITMAP +0D80 +0D80 +0D80 +7FE0 +7FE0 +1B00 +1B00 +1B00 +FFC0 +FFC0 +3600 +3600 +3600 +ENDCHAR + +STARTCHAR dollar +ENCODING 36 +SWIDTH 556 0 +DWIDTH 10 0 +BBX 9 16 0 -2 +BITMAP +0800 +3E00 +7F00 +EB80 +EB80 +E800 +7800 +3E00 +0F00 +0B80 +EB80 +EB80 +7F00 +3E00 +0800 +0800 +ENDCHAR + +STARTCHAR percent +ENCODING 37 +SWIDTH 889 0 +DWIDTH 16 0 +BBX 13 13 1 0 +BITMAP +7860 +FC60 +CCC0 +CC80 +FD80 +7B00 +0200 +06F0 +0DF8 +0998 +1998 +31F8 +30F0 +ENDCHAR + +STARTCHAR ampersand +ENCODING 38 +SWIDTH 722 0 +DWIDTH 14 0 +BBX 13 13 1 0 +BITMAP +3E00 +7F00 +6300 +7300 +3E00 +7C60 +EE60 +C7E0 +C3C0 +C1C0 +E3E0 +7F70 +3E78 +ENDCHAR + +STARTCHAR quotesingle +ENCODING 39 +SWIDTH 238 0 +DWIDTH 4 0 +BBX 2 5 1 9 +BITMAP +C0 +C0 +C0 +C0 +80 +ENDCHAR + +STARTCHAR parenleft +ENCODING 40 +SWIDTH 333 0 +DWIDTH 7 0 +BBX 6 18 0 -4 +BITMAP +1C +38 +30 +70 +60 +E0 +E0 +E0 +E0 +E0 +E0 +E0 +E0 +60 +70 +30 +38 +1C +ENDCHAR + +STARTCHAR parenright +ENCODING 41 +SWIDTH 333 0 +DWIDTH 7 0 +BBX 6 18 1 -4 +BITMAP +E0 +70 +30 +38 +18 +1C +1C +1C +1C +1C +1C +1C +1C +18 +38 +30 +70 +E0 +ENDCHAR + +STARTCHAR asterisk +ENCODING 42 +SWIDTH 389 0 +DWIDTH 9 0 +BBX 7 6 1 8 +BITMAP +10 +D6 +7C +38 +6C +44 +ENDCHAR + +STARTCHAR plus +ENCODING 43 +SWIDTH 584 0 +DWIDTH 11 0 +BBX 9 8 1 1 +BITMAP +1C00 +1C00 +1C00 +FF80 +FF80 +1C00 +1C00 +1C00 +ENDCHAR + +STARTCHAR comma +ENCODING 44 +SWIDTH 278 0 +DWIDTH 5 0 +BBX 3 5 1 -2 +BITMAP +E0 +E0 +E0 +60 +C0 +ENDCHAR + +STARTCHAR hyphen +ENCODING 45 +SWIDTH 333 0 +DWIDTH 7 0 +BBX 5 3 1 4 +BITMAP +F8 +F8 +F8 +ENDCHAR + +STARTCHAR period +ENCODING 46 +SWIDTH 278 0 +DWIDTH 5 0 +BBX 3 3 1 0 +BITMAP +E0 +E0 +E0 +ENDCHAR + +STARTCHAR slash +ENCODING 47 +SWIDTH 278 0 +DWIDTH 5 0 +BBX 5 14 0 0 +BITMAP +18 +18 +18 +10 +30 +30 +30 +20 +60 +60 +40 +C0 +C0 +C0 +ENDCHAR + +STARTCHAR zero +ENCODING 48 +SWIDTH 556 0 +DWIDTH 10 0 +BBX 9 13 0 0 +BITMAP +1C00 +7F00 +7700 +E380 +E380 +E380 +E380 +E380 +E380 +E380 +7700 +7F00 +1C00 +ENDCHAR + +STARTCHAR one +ENCODING 49 +SWIDTH 556 0 +DWIDTH 10 0 +BBX 6 13 1 0 +BITMAP +1C +3C +FC +FC +1C +1C +1C +1C +1C +1C +1C +1C +1C +ENDCHAR + +STARTCHAR two +ENCODING 50 +SWIDTH 556 0 +DWIDTH 10 0 +BBX 9 13 0 0 +BITMAP +3E00 +7F00 +E380 +E380 +0380 +0700 +1F00 +3E00 +7800 +7000 +E000 +FF80 +FF80 +ENDCHAR + +STARTCHAR three +ENCODING 51 +SWIDTH 556 0 +DWIDTH 10 0 +BBX 9 13 0 0 +BITMAP +3E00 +7F00 +E700 +E300 +0700 +1E00 +1F00 +0780 +0380 +E380 +E780 +7F00 +3E00 +ENDCHAR + +STARTCHAR four +ENCODING 52 +SWIDTH 556 0 +DWIDTH 10 0 +BBX 9 13 0 0 +BITMAP +0700 +0F00 +1F00 +3F00 +3700 +7700 +6700 +E700 +FF80 +FF80 +0700 +0700 +0700 +ENDCHAR + +STARTCHAR five +ENCODING 53 +SWIDTH 556 0 +DWIDTH 10 0 +BBX 9 13 0 0 +BITMAP +FF00 +FF00 +E000 +E000 +FE00 +FF00 +E780 +0380 +0380 +E380 +E780 +FF00 +7E00 +ENDCHAR + +STARTCHAR six +ENCODING 54 +SWIDTH 556 0 +DWIDTH 10 0 +BBX 9 13 0 0 +BITMAP +3E00 +7F00 +7300 +E000 +E000 +EE00 +FF00 +F380 +E380 +E380 +F380 +7F00 +3E00 +ENDCHAR + +STARTCHAR seven +ENCODING 55 +SWIDTH 556 0 +DWIDTH 10 0 +BBX 9 13 0 0 +BITMAP +FF80 +FF80 +0380 +0700 +0E00 +0E00 +1C00 +1C00 +3800 +3800 +7000 +7000 +7000 +ENDCHAR + +STARTCHAR eight +ENCODING 56 +SWIDTH 556 0 +DWIDTH 10 0 +BBX 9 13 0 0 +BITMAP +3E00 +7F00 +E380 +E380 +E380 +7F00 +3E00 +7700 +E380 +E380 +E380 +7F00 +3E00 +ENDCHAR + +STARTCHAR nine +ENCODING 57 +SWIDTH 556 0 +DWIDTH 10 0 +BBX 9 13 0 0 +BITMAP +3E00 +7F00 +E700 +E380 +C380 +C380 +E780 +7F80 +3D80 +0380 +E700 +FF00 +7C00 +ENDCHAR + +STARTCHAR colon +ENCODING 58 +SWIDTH 333 0 +DWIDTH 6 0 +BBX 3 10 2 0 +BITMAP +E0 +E0 +E0 +00 +00 +00 +00 +E0 +E0 +E0 +ENDCHAR + +STARTCHAR semicolon +ENCODING 59 +SWIDTH 333 0 +DWIDTH 6 0 +BBX 3 12 2 -2 +BITMAP +E0 +E0 +E0 +00 +00 +00 +00 +E0 +E0 +E0 +40 +80 +ENDCHAR + +STARTCHAR less +ENCODING 60 +SWIDTH 584 0 +DWIDTH 11 0 +BBX 9 9 1 0 +BITMAP +0380 +0F80 +3E00 +7800 +E000 +7800 +3E00 +0F80 +0380 +ENDCHAR + +STARTCHAR equal +ENCODING 61 +SWIDTH 584 0 +DWIDTH 10 0 +BBX 8 6 1 2 +BITMAP +FF +FF +00 +00 +FF +FF +ENDCHAR + +STARTCHAR greater +ENCODING 62 +SWIDTH 584 0 +DWIDTH 11 0 +BBX 9 9 1 0 +BITMAP +E000 +F800 +3E00 +0F00 +0380 +0F00 +3E00 +F800 +E000 +ENDCHAR + +STARTCHAR question +ENCODING 63 +SWIDTH 611 0 +DWIDTH 10 0 +BBX 8 14 1 0 +BITMAP +7E +FF +E7 +E7 +0E +1E +1C +38 +38 +38 +00 +38 +38 +38 +ENDCHAR + +STARTCHAR at +ENCODING 64 +SWIDTH 975 0 +DWIDTH 18 0 +BBX 16 17 1 -3 +BITMAP +07F0 +1FFC +3C1E +7006 +63B7 +E7F3 +C663 +CC63 +CCC3 +CCC6 +CCC6 +EFFC +E7B8 +7000 +3C00 +1FF0 +07F0 +ENDCHAR + +STARTCHAR A +ENCODING 65 +SWIDTH 722 0 +DWIDTH 13 0 +BBX 11 14 1 0 +BITMAP +0E00 +0E00 +1F00 +1F00 +1B00 +3B80 +3180 +3180 +71C0 +7FC0 +7FC0 +E0E0 +E0E0 +E0E0 +ENDCHAR + +STARTCHAR B +ENCODING 66 +SWIDTH 722 0 +DWIDTH 13 0 +BBX 11 14 1 0 +BITMAP +FE00 +FF80 +E3C0 +E1C0 +E1C0 +E380 +FF80 +FFC0 +E1E0 +E0E0 +E0E0 +E1E0 +FFC0 +FF00 +ENDCHAR + +STARTCHAR C +ENCODING 67 +SWIDTH 722 0 +DWIDTH 14 0 +BBX 12 14 1 0 +BITMAP +0F80 +3FE0 +78E0 +7070 +F070 +E000 +E000 +E000 +E000 +F070 +7070 +78E0 +3FE0 +0F80 +ENDCHAR + +STARTCHAR D +ENCODING 68 +SWIDTH 722 0 +DWIDTH 14 0 +BBX 12 14 1 0 +BITMAP +FF00 +FFC0 +E1E0 +E0E0 +E070 +E070 +E070 +E070 +E070 +E070 +E0E0 +E1E0 +FFC0 +FF00 +ENDCHAR + +STARTCHAR E +ENCODING 69 +SWIDTH 667 0 +DWIDTH 12 0 +BBX 10 14 1 0 +BITMAP +FFC0 +FFC0 +E000 +E000 +E000 +E000 +FF80 +FF80 +E000 +E000 +E000 +E000 +FFC0 +FFC0 +ENDCHAR + +STARTCHAR F +ENCODING 70 +SWIDTH 611 0 +DWIDTH 12 0 +BBX 10 14 1 0 +BITMAP +FFC0 +FFC0 +E000 +E000 +E000 +E000 +FF80 +FF80 +E000 +E000 +E000 +E000 +E000 +E000 +ENDCHAR + +STARTCHAR G +ENCODING 71 +SWIDTH 778 0 +DWIDTH 14 0 +BBX 12 14 1 0 +BITMAP +0F80 +3FE0 +78E0 +7070 +E070 +E000 +E000 +E3F0 +E3F0 +E070 +7070 +78F0 +3FF0 +1FB0 +ENDCHAR + +STARTCHAR H +ENCODING 72 +SWIDTH 722 0 +DWIDTH 13 0 +BBX 11 14 1 0 +BITMAP +E0E0 +E0E0 +E0E0 +E0E0 +E0E0 +E0E0 +FFE0 +FFE0 +E0E0 +E0E0 +E0E0 +E0E0 +E0E0 +E0E0 +ENDCHAR + +STARTCHAR I +ENCODING 73 +SWIDTH 278 0 +DWIDTH 5 0 +BBX 3 14 1 0 +BITMAP +E0 +E0 +E0 +E0 +E0 +E0 +E0 +E0 +E0 +E0 +E0 +E0 +E0 +E0 +ENDCHAR + +STARTCHAR J +ENCODING 74 +SWIDTH 556 0 +DWIDTH 10 0 +BBX 9 14 0 0 +BITMAP +0380 +0380 +0380 +0380 +0380 +0380 +0380 +0380 +0380 +E380 +E380 +F780 +7F00 +3E00 +ENDCHAR + +STARTCHAR K +ENCODING 75 +SWIDTH 722 0 +DWIDTH 14 0 +BBX 13 14 1 0 +BITMAP +E0F0 +E1E0 +E3C0 +E780 +EF00 +FE00 +FC00 +FE00 +EF00 +E780 +E3C0 +E1E0 +E0F0 +E078 +ENDCHAR + +STARTCHAR L +ENCODING 76 +SWIDTH 611 0 +DWIDTH 11 0 +BBX 9 14 1 0 +BITMAP +E000 +E000 +E000 +E000 +E000 +E000 +E000 +E000 +E000 +E000 +E000 +E000 +FF80 +FF80 +ENDCHAR + +STARTCHAR M +ENCODING 77 +SWIDTH 833 0 +DWIDTH 16 0 +BBX 14 14 1 0 +BITMAP +E01C +E01C +F03C +F03C +F87C +F87C +F87C +ECDC +ECDC +ECDC +E79C +E79C +E31C +E31C +ENDCHAR + +STARTCHAR N +ENCODING 78 +SWIDTH 722 0 +DWIDTH 14 0 +BBX 12 14 1 0 +BITMAP +E070 +F070 +F070 +F870 +FC70 +EC70 +EE70 +E670 +E770 +E370 +E1F0 +E1F0 +E0F0 +E070 +ENDCHAR + +STARTCHAR O +ENCODING 79 +SWIDTH 778 0 +DWIDTH 16 0 +BBX 14 14 1 0 +BITMAP +0FC0 +3FF0 +7878 +7038 +F03C +E01C +E01C +E01C +E01C +F03C +7038 +7878 +3FF0 +0FC0 +ENDCHAR + +STARTCHAR P +ENCODING 80 +SWIDTH 667 0 +DWIDTH 12 0 +BBX 10 14 1 0 +BITMAP +FE00 +FF80 +E3C0 +E1C0 +E1C0 +E3C0 +FF80 +FE00 +E000 +E000 +E000 +E000 +E000 +E000 +ENDCHAR + +STARTCHAR Q +ENCODING 81 +SWIDTH 778 0 +DWIDTH 16 0 +BBX 14 15 1 -1 +BITMAP +0FC0 +3FF0 +7878 +7038 +F03C +E01C +E01C +E01C +E01C +F19C +71D8 +78F8 +3FF0 +0FF8 +0018 +ENDCHAR + +STARTCHAR R +ENCODING 82 +SWIDTH 722 0 +DWIDTH 13 0 +BBX 11 14 1 0 +BITMAP +FF00 +FFC0 +E1E0 +E0E0 +E0E0 +E1E0 +FFC0 +FF80 +E1C0 +E0E0 +E0E0 +E0E0 +E0E0 +E0E0 +ENDCHAR + +STARTCHAR S +ENCODING 83 +SWIDTH 667 0 +DWIDTH 12 0 +BBX 10 14 1 0 +BITMAP +3F00 +7F80 +E3C0 +E1C0 +F000 +7C00 +3F00 +0F80 +03C0 +E1C0 +E1C0 +F3C0 +7F80 +3F00 +ENDCHAR + +STARTCHAR T +ENCODING 84 +SWIDTH 611 0 +DWIDTH 11 0 +BBX 11 14 0 0 +BITMAP +FFE0 +FFE0 +0E00 +0E00 +0E00 +0E00 +0E00 +0E00 +0E00 +0E00 +0E00 +0E00 +0E00 +0E00 +ENDCHAR + +STARTCHAR U +ENCODING 85 +SWIDTH 722 0 +DWIDTH 13 0 +BBX 11 14 1 0 +BITMAP +E0E0 +E0E0 +E0E0 +E0E0 +E0E0 +E0E0 +E0E0 +E0E0 +E0E0 +E0E0 +E0E0 +71C0 +7FC0 +1F00 +ENDCHAR + +STARTCHAR V +ENCODING 86 +SWIDTH 667 0 +DWIDTH 13 0 +BBX 11 14 1 0 +BITMAP +E0E0 +E0E0 +E0E0 +71C0 +71C0 +71C0 +3180 +3B80 +3B80 +1B00 +1F00 +1F00 +0E00 +0E00 +ENDCHAR + +STARTCHAR W +ENCODING 87 +SWIDTH 944 0 +DWIDTH 17 0 +BBX 15 14 1 0 +BITMAP +E38E +E38E +E38E +E38E +739C +739C +739C +76DC +36D8 +36D8 +3EF8 +1C70 +1C70 +1C70 +ENDCHAR + +STARTCHAR X +ENCODING 88 +SWIDTH 667 0 +DWIDTH 12 0 +BBX 12 14 0 0 +BITMAP +E070 +E070 +70E0 +79E0 +1980 +1F80 +0F00 +1F80 +1980 +39C0 +70E0 +70E0 +E070 +E070 +ENDCHAR + +STARTCHAR Y +ENCODING 89 +SWIDTH 667 0 +DWIDTH 13 0 +BBX 11 14 1 0 +BITMAP +E0E0 +E0E0 +E0E0 +71C0 +71C0 +3B80 +3B80 +1F00 +0E00 +0E00 +0E00 +0E00 +0E00 +0E00 +ENDCHAR + +STARTCHAR Z +ENCODING 90 +SWIDTH 611 0 +DWIDTH 11 0 +BBX 10 14 1 0 +BITMAP +FFC0 +FFC0 +01C0 +0380 +0700 +0700 +0E00 +1C00 +3800 +3800 +7000 +E000 +FFC0 +FFC0 +ENDCHAR + +STARTCHAR bracketleft +ENCODING 91 +SWIDTH 333 0 +DWIDTH 6 0 +BBX 5 18 1 -4 +BITMAP +F8 +F8 +E0 +E0 +E0 +E0 +E0 +E0 +E0 +E0 +E0 +E0 +E0 +E0 +E0 +E0 +F8 +F8 +ENDCHAR + +STARTCHAR backslash +ENCODING 92 +SWIDTH 278 0 +DWIDTH 5 0 +BBX 5 14 0 0 +BITMAP +C0 +C0 +C0 +40 +60 +60 +60 +20 +30 +30 +10 +18 +18 +18 +ENDCHAR + +STARTCHAR bracketright +ENCODING 93 +SWIDTH 333 0 +DWIDTH 6 0 +BBX 5 18 0 -4 +BITMAP +F8 +F8 +38 +38 +38 +38 +38 +38 +38 +38 +38 +38 +38 +38 +38 +38 +F8 +F8 +ENDCHAR + +STARTCHAR asciicircum +ENCODING 94 +SWIDTH 584 0 +DWIDTH 10 0 +BBX 10 6 0 7 +BITMAP +0C00 +1E00 +3F00 +7380 +E1C0 +C0C0 +ENDCHAR + +STARTCHAR underscore +ENCODING 95 +SWIDTH 556 0 +DWIDTH 10 0 +BBX 10 2 0 -4 +BITMAP +FFC0 +FFC0 +ENDCHAR + +STARTCHAR grave +ENCODING 96 +SWIDTH 333 0 +DWIDTH 5 0 +BBX 5 3 0 11 +BITMAP +E0 +70 +38 +ENDCHAR + +STARTCHAR a +ENCODING 97 +SWIDTH 556 0 +DWIDTH 10 0 +BBX 8 10 1 0 +BITMAP +7C +FE +E7 +0F +3F +77 +E7 +E7 +FF +77 +ENDCHAR + +STARTCHAR b +ENCODING 98 +SWIDTH 611 0 +DWIDTH 12 0 +BBX 10 14 1 0 +BITMAP +E000 +E000 +E000 +E000 +EF00 +FF80 +F380 +E1C0 +E1C0 +E1C0 +E1C0 +F380 +FF80 +EF00 +ENDCHAR + +STARTCHAR c +ENCODING 99 +SWIDTH 556 0 +DWIDTH 10 0 +BBX 9 10 1 0 +BITMAP +1E00 +7F80 +7380 +E000 +E000 +E000 +E000 +7380 +7F80 +1E00 +ENDCHAR + +STARTCHAR d +ENCODING 100 +SWIDTH 611 0 +DWIDTH 12 0 +BBX 10 14 1 0 +BITMAP +01C0 +01C0 +01C0 +01C0 +3DC0 +7FC0 +73C0 +E1C0 +E1C0 +E1C0 +E1C0 +73C0 +7FC0 +3DC0 +ENDCHAR + +STARTCHAR e +ENCODING 101 +SWIDTH 556 0 +DWIDTH 11 0 +BBX 9 10 1 0 +BITMAP +1E00 +7F00 +7380 +E180 +FF80 +FF80 +E000 +7380 +7F80 +1E00 +ENDCHAR + +STARTCHAR f +ENCODING 102 +SWIDTH 333 0 +DWIDTH 7 0 +BBX 7 14 0 0 +BITMAP +1E +3E +38 +38 +FE +FE +38 +38 +38 +38 +38 +38 +38 +38 +ENDCHAR + +STARTCHAR g +ENCODING 103 +SWIDTH 611 0 +DWIDTH 12 0 +BBX 10 14 1 -4 +BITMAP +3DC0 +7FC0 +73C0 +E1C0 +E1C0 +E1C0 +E1C0 +73C0 +7FC0 +3DC0 +01C0 +7380 +7F80 +1E00 +ENDCHAR + +STARTCHAR h +ENCODING 104 +SWIDTH 611 0 +DWIDTH 11 0 +BBX 9 14 1 0 +BITMAP +E000 +E000 +E000 +E000 +EF00 +FF80 +F380 +E380 +E380 +E380 +E380 +E380 +E380 +E380 +ENDCHAR + +STARTCHAR i +ENCODING 105 +SWIDTH 278 0 +DWIDTH 5 0 +BBX 3 14 1 0 +BITMAP +E0 +E0 +00 +00 +E0 +E0 +E0 +E0 +E0 +E0 +E0 +E0 +E0 +E0 +ENDCHAR + +STARTCHAR j +ENCODING 106 +SWIDTH 278 0 +DWIDTH 5 0 +BBX 5 18 -1 -4 +BITMAP +38 +38 +00 +00 +38 +38 +38 +38 +38 +38 +38 +38 +38 +38 +38 +38 +F8 +F0 +ENDCHAR + +STARTCHAR k +ENCODING 107 +SWIDTH 556 0 +DWIDTH 10 0 +BBX 9 14 1 0 +BITMAP +E000 +E000 +E000 +E000 +E700 +EE00 +FC00 +F800 +F800 +FC00 +EE00 +E700 +E780 +E380 +ENDCHAR + +STARTCHAR l +ENCODING 108 +SWIDTH 278 0 +DWIDTH 5 0 +BBX 3 14 1 0 +BITMAP +E0 +E0 +E0 +E0 +E0 +E0 +E0 +E0 +E0 +E0 +E0 +E0 +E0 +E0 +ENDCHAR + +STARTCHAR m +ENCODING 109 +SWIDTH 889 0 +DWIDTH 15 0 +BBX 13 10 1 0 +BITMAP +EE70 +FFF8 +F7B8 +E738 +E738 +E738 +E738 +E738 +E738 +E738 +ENDCHAR + +STARTCHAR n +ENCODING 110 +SWIDTH 611 0 +DWIDTH 11 0 +BBX 9 10 1 0 +BITMAP +EF00 +FF80 +F380 +E380 +E380 +E380 +E380 +E380 +E380 +E380 +ENDCHAR + +STARTCHAR o +ENCODING 111 +SWIDTH 611 0 +DWIDTH 12 0 +BBX 10 10 1 0 +BITMAP +1E00 +7F80 +7380 +E1C0 +E1C0 +E1C0 +E1C0 +7380 +7F80 +1E00 +ENDCHAR + +STARTCHAR p +ENCODING 112 +SWIDTH 611 0 +DWIDTH 12 0 +BBX 10 14 1 -4 +BITMAP +EF00 +FF80 +F380 +E1C0 +E1C0 +E1C0 +E1C0 +F380 +FF80 +EF00 +E000 +E000 +E000 +E000 +ENDCHAR + +STARTCHAR q +ENCODING 113 +SWIDTH 611 0 +DWIDTH 12 0 +BBX 10 14 1 -4 +BITMAP +3DC0 +7FC0 +73C0 +E1C0 +E1C0 +E1C0 +E1C0 +73C0 +7FC0 +3DC0 +01C0 +01C0 +01C0 +01C0 +ENDCHAR + +STARTCHAR r +ENCODING 114 +SWIDTH 389 0 +DWIDTH 7 0 +BBX 6 10 1 0 +BITMAP +EC +FC +FC +E0 +E0 +E0 +E0 +E0 +E0 +E0 +ENDCHAR + +STARTCHAR s +ENCODING 115 +SWIDTH 556 0 +DWIDTH 10 0 +BBX 8 10 1 0 +BITMAP +1E +7F +E7 +E0 +FE +3F +07 +E7 +FE +78 +ENDCHAR + +STARTCHAR t +ENCODING 116 +SWIDTH 333 0 +DWIDTH 6 0 +BBX 6 13 0 0 +BITMAP +70 +70 +70 +FC +FC +70 +70 +70 +70 +70 +70 +7C +3C +ENDCHAR + +STARTCHAR u +ENCODING 117 +SWIDTH 611 0 +DWIDTH 11 0 +BBX 9 10 1 0 +BITMAP +E380 +E380 +E380 +E380 +E380 +E380 +E380 +E780 +FF80 +7B80 +ENDCHAR + +STARTCHAR v +ENCODING 118 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 9 10 0 0 +BITMAP +E380 +E380 +E380 +7700 +7700 +7700 +3E00 +3E00 +1C00 +1C00 +ENDCHAR + +STARTCHAR w +ENCODING 119 +SWIDTH 778 0 +DWIDTH 13 0 +BBX 13 10 0 0 +BITMAP +E738 +E738 +E738 +6730 +7770 +7570 +3DE0 +3DE0 +18C0 +18C0 +ENDCHAR + +STARTCHAR x +ENCODING 120 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 9 10 0 0 +BITMAP +E380 +E380 +7700 +3E00 +1C00 +3E00 +7700 +7700 +E380 +E380 +ENDCHAR + +STARTCHAR y +ENCODING 121 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 9 14 0 -4 +BITMAP +E380 +E380 +E380 +7700 +7700 +7700 +3E00 +3E00 +1C00 +1C00 +1C00 +1800 +7800 +7000 +ENDCHAR + +STARTCHAR z +ENCODING 122 +SWIDTH 500 0 +DWIDTH 10 0 +BBX 8 10 1 0 +BITMAP +FF +FF +07 +0E +1C +38 +70 +E0 +FF +FF +ENDCHAR + +STARTCHAR braceleft +ENCODING 123 +SWIDTH 389 0 +DWIDTH 8 0 +BBX 7 18 1 -4 +BITMAP +0E +1C +38 +38 +38 +38 +38 +70 +E0 +70 +38 +38 +38 +38 +38 +38 +1C +0E +ENDCHAR + +STARTCHAR bar +ENCODING 124 +SWIDTH 280 0 +DWIDTH 5 0 +BBX 2 18 1 -4 +BITMAP +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +ENDCHAR + +STARTCHAR braceright +ENCODING 125 +SWIDTH 389 0 +DWIDTH 8 0 +BBX 7 18 0 -4 +BITMAP +E0 +70 +38 +38 +38 +38 +38 +1C +0E +1C +38 +38 +38 +38 +38 +38 +70 +E0 +ENDCHAR + +STARTCHAR asciitilde +ENCODING 126 +SWIDTH 584 0 +DWIDTH 11 0 +BBX 9 3 1 4 +BITMAP +7980 +FF80 +CF00 +ENDCHAR + +STARTCHAR space +ENCODING 160 +SWIDTH 278 0 +DWIDTH 5 0 +BBX 1 1 0 0 +BITMAP +00 +ENDCHAR + +STARTCHAR exclamdown +ENCODING 161 +SWIDTH 333 0 +DWIDTH 6 0 +BBX 3 14 2 -4 +BITMAP +E0 +E0 +00 +00 +60 +60 +E0 +E0 +E0 +E0 +E0 +E0 +E0 +E0 +ENDCHAR + +STARTCHAR cent +ENCODING 162 +SWIDTH 556 0 +DWIDTH 10 0 +BBX 8 14 1 -2 +BITMAP +02 +02 +3E +7F +E7 +C8 +C8 +D0 +D0 +E3 +7F +7E +40 +40 +ENDCHAR + +STARTCHAR sterling +ENCODING 163 +SWIDTH 556 0 +DWIDTH 11 0 +BBX 10 13 0 0 +BITMAP +1F00 +3FC0 +71C0 +7000 +7000 +3800 +7F00 +1C00 +1C00 +3800 +70C0 +FFC0 +EF80 +ENDCHAR + +STARTCHAR currency +ENCODING 164 +SWIDTH 556 0 +DWIDTH 11 0 +BBX 9 8 1 2 +BITMAP +C180 +FF80 +7700 +6300 +6300 +7700 +FF80 +C180 +ENDCHAR + +STARTCHAR yen +ENCODING 165 +SWIDTH 556 0 +DWIDTH 10 0 +BBX 9 13 0 0 +BITMAP +E380 +E380 +E380 +7700 +7700 +3E00 +FF80 +1C00 +FF80 +1C00 +1C00 +1C00 +1C00 +ENDCHAR + +STARTCHAR brokenbar +ENCODING 166 +SWIDTH 280 0 +DWIDTH 5 0 +BBX 2 17 1 -3 +BITMAP +C0 +C0 +C0 +C0 +C0 +C0 +C0 +00 +00 +00 +C0 +C0 +C0 +C0 +C0 +C0 +C0 +ENDCHAR + +STARTCHAR section +ENCODING 167 +SWIDTH 556 0 +DWIDTH 10 0 +BBX 8 18 1 -4 +BITMAP +3C +7E +C7 +C7 +E0 +78 +FC +C6 +C7 +E3 +73 +3F +0E +07 +E3 +E3 +7E +3C +ENDCHAR + +STARTCHAR dieresis +ENCODING 168 +SWIDTH 333 0 +DWIDTH 7 0 +BBX 5 2 1 11 +BITMAP +D8 +D8 +ENDCHAR + +STARTCHAR copyright +ENCODING 169 +SWIDTH 737 0 +DWIDTH 15 0 +BBX 13 13 1 0 +BITMAP +0F80 +38E0 +6030 +6730 +CD98 +D818 +9808 +D818 +CD98 +6730 +6030 +38E0 +0F80 +ENDCHAR + +STARTCHAR ordfeminine +ENCODING 170 +SWIDTH 370 0 +DWIDTH 8 0 +BBX 6 9 1 5 +BITMAP +78 +8C +7C +CC +CC +74 +00 +FC +FC +ENDCHAR + +STARTCHAR guillemotleft +ENCODING 171 +SWIDTH 556 0 +DWIDTH 11 0 +BBX 10 8 0 1 +BITMAP +1DC0 +3B80 +7700 +EE00 +EE00 +7700 +3B80 +1DC0 +ENDCHAR + +STARTCHAR logicalnot +ENCODING 172 +SWIDTH 584 0 +DWIDTH 11 0 +BBX 9 5 1 2 +BITMAP +FF80 +FF80 +0180 +0180 +0180 +ENDCHAR + +STARTCHAR hyphen +ENCODING 173 +SWIDTH 333 0 +DWIDTH 7 0 +BBX 5 3 1 4 +BITMAP +F8 +F8 +F8 +ENDCHAR + +STARTCHAR registered +ENCODING 174 +SWIDTH 737 0 +DWIDTH 15 0 +BBX 13 13 1 0 +BITMAP +0F80 +38E0 +6030 +6F90 +CCD8 +CCD8 +8F08 +CD98 +CD98 +6CF0 +6030 +38E0 +0F80 +ENDCHAR + +STARTCHAR macron +ENCODING 175 +SWIDTH 333 0 +DWIDTH 7 0 +BBX 5 2 1 12 +BITMAP +F8 +F8 +ENDCHAR + +STARTCHAR degree +ENCODING 176 +SWIDTH 400 0 +DWIDTH 7 0 +BBX 6 6 0 7 +BITMAP +78 +FC +CC +CC +FC +78 +ENDCHAR + +STARTCHAR plusminus +ENCODING 177 +SWIDTH 584 0 +DWIDTH 11 0 +BBX 9 9 1 0 +BITMAP +1C00 +1C00 +FF80 +FF80 +1C00 +1C00 +0000 +FF80 +FF80 +ENDCHAR + +STARTCHAR twosuperior +ENCODING 178 +SWIDTH 333 0 +DWIDTH 6 0 +BBX 6 8 0 5 +BITMAP +78 +FC +CC +1C +78 +E0 +FC +FC +ENDCHAR + +STARTCHAR threesuperior +ENCODING 179 +SWIDTH 333 0 +DWIDTH 6 0 +BBX 6 8 0 5 +BITMAP +78 +FC +CC +38 +3C +CC +FC +78 +ENDCHAR + +STARTCHAR acute +ENCODING 180 +SWIDTH 333 0 +DWIDTH 5 0 +BBX 5 3 0 11 +BITMAP +38 +70 +E0 +ENDCHAR + +STARTCHAR mu +ENCODING 181 +SWIDTH 611 0 +DWIDTH 11 0 +BBX 9 14 1 -4 +BITMAP +E380 +E380 +E380 +E380 +E380 +E380 +E380 +E780 +FF80 +FB80 +E000 +E000 +E000 +E000 +ENDCHAR + +STARTCHAR paragraph +ENCODING 182 +SWIDTH 556 0 +DWIDTH 10 0 +BBX 9 18 0 -4 +BITMAP +3F80 +7B00 +FB00 +FB00 +FB00 +FB00 +FB00 +7B00 +3B00 +1B00 +1B00 +1B00 +1B00 +1B00 +1B00 +1B00 +1B00 +1B00 +ENDCHAR + +STARTCHAR periodcentered +ENCODING 183 +SWIDTH 278 0 +DWIDTH 4 0 +BBX 2 2 1 4 +BITMAP +C0 +C0 +ENDCHAR + +STARTCHAR cedilla +ENCODING 184 +SWIDTH 333 0 +DWIDTH 7 0 +BBX 5 5 1 -5 +BITMAP +60 +70 +18 +F8 +F0 +ENDCHAR + +STARTCHAR onesuperior +ENCODING 185 +SWIDTH 333 0 +DWIDTH 6 0 +BBX 4 8 0 5 +BITMAP +30 +F0 +F0 +30 +30 +30 +30 +30 +ENDCHAR + +STARTCHAR ordmasculine +ENCODING 186 +SWIDTH 365 0 +DWIDTH 8 0 +BBX 6 9 1 5 +BITMAP +78 +CC +CC +CC +CC +78 +00 +FC +FC +ENDCHAR + +STARTCHAR guillemotright +ENCODING 187 +SWIDTH 556 0 +DWIDTH 11 0 +BBX 10 8 0 1 +BITMAP +EE00 +7700 +3B80 +1DC0 +1DC0 +3B80 +7700 +EE00 +ENDCHAR + +STARTCHAR onequarter +ENCODING 188 +SWIDTH 834 0 +DWIDTH 15 0 +BBX 14 13 0 0 +BITMAP +3060 +F060 +F0C0 +30C0 +3180 +3198 +3338 +3638 +0678 +0CD8 +0CFC +1818 +1818 +ENDCHAR + +STARTCHAR onehalf +ENCODING 189 +SWIDTH 834 0 +DWIDTH 15 0 +BBX 15 13 0 0 +BITMAP +3060 +F060 +F0C0 +30C0 +3180 +31BC +337E +3666 +060E +0C3C +0C70 +187E +187E +ENDCHAR + +STARTCHAR threequarters +ENCODING 190 +SWIDTH 834 0 +DWIDTH 15 0 +BBX 14 13 0 0 +BITMAP +7830 +FC30 +CC60 +3860 +3CC0 +CCD8 +FDB8 +7B38 +0378 +06D8 +06FC +0C18 +0C18 +ENDCHAR + +STARTCHAR questiondown +ENCODING 191 +SWIDTH 611 0 +DWIDTH 10 0 +BBX 8 14 1 -4 +BITMAP +1C +1C +00 +00 +1C +1C +1C +38 +78 +70 +E7 +E7 +FF +7E +ENDCHAR + +STARTCHAR Agrave +ENCODING 192 +SWIDTH 722 0 +DWIDTH 13 0 +BBX 11 18 1 0 +BITMAP +3800 +1C00 +0E00 +0000 +0E00 +0E00 +1F00 +1F00 +1B00 +3B80 +3180 +3180 +71C0 +7FC0 +7FC0 +E0E0 +E0E0 +E0E0 +ENDCHAR + +STARTCHAR Aacute +ENCODING 193 +SWIDTH 722 0 +DWIDTH 13 0 +BBX 11 18 1 0 +BITMAP +0380 +0700 +0E00 +0000 +0E00 +0E00 +1F00 +1F00 +1B00 +3B80 +3180 +3180 +71C0 +7FC0 +7FC0 +E0E0 +E0E0 +E0E0 +ENDCHAR + +STARTCHAR Acircumflex +ENCODING 194 +SWIDTH 722 0 +DWIDTH 13 0 +BBX 11 18 1 0 +BITMAP +0E00 +1F00 +3B80 +0000 +0E00 +0E00 +1F00 +1F00 +1B00 +3B80 +3180 +3180 +71C0 +7FC0 +7FC0 +E0E0 +E0E0 +E0E0 +ENDCHAR + +STARTCHAR Atilde +ENCODING 195 +SWIDTH 722 0 +DWIDTH 13 0 +BBX 11 18 1 0 +BITMAP +1D80 +3F80 +3700 +0000 +0E00 +0E00 +1F00 +1F00 +1B00 +3B80 +3180 +3180 +71C0 +7FC0 +7FC0 +E0E0 +E0E0 +E0E0 +ENDCHAR + +STARTCHAR Adieresis +ENCODING 196 +SWIDTH 722 0 +DWIDTH 13 0 +BBX 11 17 1 0 +BITMAP +1980 +1980 +0000 +0E00 +0E00 +1F00 +1F00 +1B00 +3B80 +3180 +3180 +71C0 +7FC0 +7FC0 +E0E0 +E0E0 +E0E0 +ENDCHAR + +STARTCHAR Aring +ENCODING 197 +SWIDTH 722 0 +DWIDTH 13 0 +BBX 11 17 1 0 +BITMAP +0E00 +1B00 +1B00 +0E00 +0E00 +1F00 +1F00 +1B00 +3B80 +3180 +3180 +71C0 +7FC0 +7FC0 +E0E0 +E0E0 +E0E0 +ENDCHAR + +STARTCHAR AE +ENCODING 198 +SWIDTH 1000 0 +DWIDTH 18 0 +BBX 16 14 1 0 +BITMAP +0FFF +0FFF +1F80 +1B80 +3B80 +3B80 +33FE +73FE +7380 +7F80 +FF80 +E380 +E3FF +E3FF +ENDCHAR + +STARTCHAR Ccedilla +ENCODING 199 +SWIDTH 722 0 +DWIDTH 14 0 +BBX 12 19 1 -5 +BITMAP +0F80 +3FE0 +78E0 +7070 +F070 +E000 +E000 +E000 +E000 +F070 +7070 +78E0 +3FE0 +0F80 +0C00 +0E00 +0300 +1F00 +1E00 +ENDCHAR + +STARTCHAR Egrave +ENCODING 200 +SWIDTH 667 0 +DWIDTH 12 0 +BBX 10 18 1 0 +BITMAP +3800 +1C00 +0E00 +0000 +FFC0 +FFC0 +E000 +E000 +E000 +E000 +FF80 +FF80 +E000 +E000 +E000 +E000 +FFC0 +FFC0 +ENDCHAR + +STARTCHAR Eacute +ENCODING 201 +SWIDTH 667 0 +DWIDTH 12 0 +BBX 10 18 1 0 +BITMAP +0380 +0700 +0E00 +0000 +FFC0 +FFC0 +E000 +E000 +E000 +E000 +FF80 +FF80 +E000 +E000 +E000 +E000 +FFC0 +FFC0 +ENDCHAR + +STARTCHAR Ecircumflex +ENCODING 202 +SWIDTH 667 0 +DWIDTH 12 0 +BBX 10 18 1 0 +BITMAP +0E00 +1F00 +3B80 +0000 +FFC0 +FFC0 +E000 +E000 +E000 +E000 +FF80 +FF80 +E000 +E000 +E000 +E000 +FFC0 +FFC0 +ENDCHAR + +STARTCHAR Edieresis +ENCODING 203 +SWIDTH 667 0 +DWIDTH 12 0 +BBX 10 17 1 0 +BITMAP +3300 +3300 +0000 +FFC0 +FFC0 +E000 +E000 +E000 +E000 +FF80 +FF80 +E000 +E000 +E000 +E000 +FFC0 +FFC0 +ENDCHAR + +STARTCHAR Igrave +ENCODING 204 +SWIDTH 278 0 +DWIDTH 5 0 +BBX 5 18 -1 0 +BITMAP +E0 +70 +38 +00 +38 +38 +38 +38 +38 +38 +38 +38 +38 +38 +38 +38 +38 +38 +ENDCHAR + +STARTCHAR Iacute +ENCODING 205 +SWIDTH 278 0 +DWIDTH 5 0 +BBX 5 18 1 0 +BITMAP +38 +70 +E0 +00 +E0 +E0 +E0 +E0 +E0 +E0 +E0 +E0 +E0 +E0 +E0 +E0 +E0 +E0 +ENDCHAR + +STARTCHAR Icircumflex +ENCODING 206 +SWIDTH 278 0 +DWIDTH 5 0 +BBX 5 18 0 0 +BITMAP +20 +70 +D8 +00 +70 +70 +70 +70 +70 +70 +70 +70 +70 +70 +70 +70 +70 +70 +ENDCHAR + +STARTCHAR Idieresis +ENCODING 207 +SWIDTH 278 0 +DWIDTH 5 0 +BBX 5 17 0 0 +BITMAP +D8 +D8 +00 +70 +70 +70 +70 +70 +70 +70 +70 +70 +70 +70 +70 +70 +70 +ENDCHAR + +STARTCHAR Eth +ENCODING 208 +SWIDTH 722 0 +DWIDTH 14 0 +BBX 13 14 0 0 +BITMAP +7F80 +7FE0 +70F0 +7070 +7038 +7038 +FE38 +FE38 +7038 +7038 +7070 +70F0 +7FE0 +7F80 +ENDCHAR + +STARTCHAR Ntilde +ENCODING 209 +SWIDTH 722 0 +DWIDTH 14 0 +BBX 12 18 1 0 +BITMAP +0EC0 +1FC0 +1B80 +0000 +E070 +F070 +F070 +F870 +FC70 +EC70 +EE70 +E670 +E770 +E370 +E1F0 +E1F0 +E0F0 +E070 +ENDCHAR + +STARTCHAR Ograve +ENCODING 210 +SWIDTH 778 0 +DWIDTH 16 0 +BBX 14 18 1 0 +BITMAP +0E00 +0700 +0380 +0000 +0FC0 +3FF0 +7878 +7038 +F03C +E01C +E01C +E01C +E01C +F03C +7038 +7878 +3FF0 +0FC0 +ENDCHAR + +STARTCHAR Oacute +ENCODING 211 +SWIDTH 778 0 +DWIDTH 16 0 +BBX 14 18 1 0 +BITMAP +00E0 +01C0 +0380 +0000 +0FC0 +3FF0 +7878 +7038 +F03C +E01C +E01C +E01C +E01C +F03C +7038 +7878 +3FF0 +0FC0 +ENDCHAR + +STARTCHAR Ocircumflex +ENCODING 212 +SWIDTH 778 0 +DWIDTH 16 0 +BBX 14 18 1 0 +BITMAP +0380 +07C0 +0EE0 +0000 +0FC0 +3FF0 +7878 +7038 +F03C +E01C +E01C +E01C +E01C +F03C +7038 +7878 +3FF0 +0FC0 +ENDCHAR + +STARTCHAR Otilde +ENCODING 213 +SWIDTH 778 0 +DWIDTH 16 0 +BBX 14 18 1 0 +BITMAP +0760 +0FE0 +0DC0 +0000 +0FC0 +3FF0 +7878 +7038 +F03C +E01C +E01C +E01C +E01C +F03C +7038 +7878 +3FF0 +0FC0 +ENDCHAR + +STARTCHAR Odieresis +ENCODING 214 +SWIDTH 778 0 +DWIDTH 16 0 +BBX 14 17 1 0 +BITMAP +0CC0 +0CC0 +0000 +0FC0 +3FF0 +7878 +7038 +F03C +E01C +E01C +E01C +E01C +F03C +7038 +7878 +3FF0 +0FC0 +ENDCHAR + +STARTCHAR multiply +ENCODING 215 +SWIDTH 584 0 +DWIDTH 11 0 +BBX 10 8 0 1 +BITMAP +E1C0 +7380 +3F00 +1E00 +1E00 +3F00 +7380 +E1C0 +ENDCHAR + +STARTCHAR Oslash +ENCODING 216 +SWIDTH 778 0 +DWIDTH 16 0 +BBX 15 14 0 0 +BITMAP +07EE +1FFC +3C38 +387C +78EE +71CE +738E +770E +7E0E +7C1E +381C +7C3C +EFF8 +C7E0 +ENDCHAR + +STARTCHAR Ugrave +ENCODING 217 +SWIDTH 722 0 +DWIDTH 13 0 +BBX 11 18 1 0 +BITMAP +3800 +1C00 +0E00 +0000 +E0E0 +E0E0 +E0E0 +E0E0 +E0E0 +E0E0 +E0E0 +E0E0 +E0E0 +E0E0 +E0E0 +71C0 +7FC0 +1F00 +ENDCHAR + +STARTCHAR Uacute +ENCODING 218 +SWIDTH 722 0 +DWIDTH 13 0 +BBX 11 18 1 0 +BITMAP +0380 +0700 +0E00 +0000 +E0E0 +E0E0 +E0E0 +E0E0 +E0E0 +E0E0 +E0E0 +E0E0 +E0E0 +E0E0 +E0E0 +71C0 +7FC0 +1F00 +ENDCHAR + +STARTCHAR Ucircumflex +ENCODING 219 +SWIDTH 722 0 +DWIDTH 13 0 +BBX 11 18 1 0 +BITMAP +0E00 +1F00 +3B80 +0000 +E0E0 +E0E0 +E0E0 +E0E0 +E0E0 +E0E0 +E0E0 +E0E0 +E0E0 +E0E0 +E0E0 +71C0 +7FC0 +1F00 +ENDCHAR + +STARTCHAR Udieresis +ENCODING 220 +SWIDTH 722 0 +DWIDTH 13 0 +BBX 11 17 1 0 +BITMAP +1980 +1980 +0000 +E0E0 +E0E0 +E0E0 +E0E0 +E0E0 +E0E0 +E0E0 +E0E0 +E0E0 +E0E0 +E0E0 +71C0 +7FC0 +1F00 +ENDCHAR + +STARTCHAR Yacute +ENCODING 221 +SWIDTH 667 0 +DWIDTH 13 0 +BBX 11 18 1 0 +BITMAP +0380 +0700 +0E00 +0000 +E0E0 +E0E0 +E0E0 +71C0 +71C0 +3B80 +3B80 +1F00 +0E00 +0E00 +0E00 +0E00 +0E00 +0E00 +ENDCHAR + +STARTCHAR Thorn +ENCODING 222 +SWIDTH 667 0 +DWIDTH 12 0 +BBX 10 14 1 0 +BITMAP +E000 +E000 +E000 +FE00 +FF80 +E3C0 +E1C0 +E1C0 +E3C0 +FF80 +FE00 +E000 +E000 +E000 +ENDCHAR + +STARTCHAR germandbls +ENCODING 223 +SWIDTH 611 0 +DWIDTH 10 0 +BBX 8 14 1 0 +BITMAP +3C +7E +E7 +E7 +E7 +E7 +EE +EE +E7 +E7 +E7 +E7 +EF +EE +ENDCHAR + +STARTCHAR agrave +ENCODING 224 +SWIDTH 556 0 +DWIDTH 10 0 +BBX 8 14 1 0 +BITMAP +70 +38 +1C +00 +7C +FE +E7 +0F +3F +77 +E7 +E7 +FF +77 +ENDCHAR + +STARTCHAR aacute +ENCODING 225 +SWIDTH 556 0 +DWIDTH 10 0 +BBX 8 14 1 0 +BITMAP +0E +1C +38 +00 +7C +FE +E7 +0F +3F +77 +E7 +E7 +FF +77 +ENDCHAR + +STARTCHAR acircumflex +ENCODING 226 +SWIDTH 556 0 +DWIDTH 10 0 +BBX 8 14 1 0 +BITMAP +1C +3E +77 +00 +7C +FE +E7 +0F +3F +77 +E7 +E7 +FF +77 +ENDCHAR + +STARTCHAR atilde +ENCODING 227 +SWIDTH 556 0 +DWIDTH 10 0 +BBX 8 14 1 0 +BITMAP +3B +7F +6E +00 +7C +FE +E7 +0F +3F +77 +E7 +E7 +FF +77 +ENDCHAR + +STARTCHAR adieresis +ENCODING 228 +SWIDTH 556 0 +DWIDTH 10 0 +BBX 8 13 1 0 +BITMAP +36 +36 +00 +7C +FE +E7 +0F +3F +77 +E7 +E7 +FF +77 +ENDCHAR + +STARTCHAR aring +ENCODING 229 +SWIDTH 556 0 +DWIDTH 10 0 +BBX 8 14 1 0 +BITMAP +1C +36 +36 +1C +7C +FE +E7 +0F +3F +77 +E7 +E7 +FF +77 +ENDCHAR + +STARTCHAR ae +ENCODING 230 +SWIDTH 889 0 +DWIDTH 16 0 +BBX 14 10 1 0 +BITMAP +7CF0 +FFF8 +E71C +0F1C +3FFC +7700 +E700 +EF9C +FFFC +79F0 +ENDCHAR + +STARTCHAR ccedilla +ENCODING 231 +SWIDTH 556 0 +DWIDTH 10 0 +BBX 9 15 1 -5 +BITMAP +1E00 +7F80 +7380 +E000 +E000 +E000 +E000 +7380 +7F80 +1E00 +1800 +1C00 +0600 +3E00 +3C00 +ENDCHAR + +STARTCHAR egrave +ENCODING 232 +SWIDTH 556 0 +DWIDTH 11 0 +BBX 9 14 1 0 +BITMAP +3800 +1C00 +0E00 +0000 +1E00 +7F00 +7380 +E180 +FF80 +FF80 +E000 +7380 +7F80 +1E00 +ENDCHAR + +STARTCHAR eacute +ENCODING 233 +SWIDTH 556 0 +DWIDTH 11 0 +BBX 9 14 1 0 +BITMAP +0700 +0E00 +1C00 +0000 +1E00 +7F00 +7380 +E180 +FF80 +FF80 +E000 +7380 +7F80 +1E00 +ENDCHAR + +STARTCHAR ecircumflex +ENCODING 234 +SWIDTH 556 0 +DWIDTH 11 0 +BBX 9 14 1 0 +BITMAP +0E00 +1F00 +3B80 +0000 +1E00 +7F00 +7380 +E180 +FF80 +FF80 +E000 +7380 +7F80 +1E00 +ENDCHAR + +STARTCHAR edieresis +ENCODING 235 +SWIDTH 556 0 +DWIDTH 11 0 +BBX 9 13 1 0 +BITMAP +3300 +3300 +0000 +1E00 +7F00 +7380 +E180 +FF80 +FF80 +E000 +7380 +7F80 +1E00 +ENDCHAR + +STARTCHAR igrave +ENCODING 236 +SWIDTH 278 0 +DWIDTH 5 0 +BBX 5 14 0 0 +BITMAP +E0 +70 +38 +00 +70 +70 +70 +70 +70 +70 +70 +70 +70 +70 +ENDCHAR + +STARTCHAR iacute +ENCODING 237 +SWIDTH 278 0 +DWIDTH 5 0 +BBX 5 14 0 0 +BITMAP +38 +70 +E0 +00 +70 +70 +70 +70 +70 +70 +70 +70 +70 +70 +ENDCHAR + +STARTCHAR icircumflex +ENCODING 238 +SWIDTH 278 0 +DWIDTH 5 0 +BBX 7 14 -1 0 +BITMAP +38 +7C +EE +00 +38 +38 +38 +38 +38 +38 +38 +38 +38 +38 +ENDCHAR + +STARTCHAR idieresis +ENCODING 239 +SWIDTH 278 0 +DWIDTH 5 0 +BBX 5 13 0 0 +BITMAP +D8 +D8 +00 +70 +70 +70 +70 +70 +70 +70 +70 +70 +70 +ENDCHAR + +STARTCHAR eth +ENCODING 240 +SWIDTH 611 0 +DWIDTH 12 0 +BBX 10 14 1 0 +BITMAP +7000 +1F00 +7C00 +0600 +1F00 +7F80 +7380 +E1C0 +E1C0 +E1C0 +E1C0 +7380 +7F80 +1E00 +ENDCHAR + +STARTCHAR ntilde +ENCODING 241 +SWIDTH 611 0 +DWIDTH 11 0 +BBX 9 14 1 0 +BITMAP +3B00 +7F00 +6E00 +0000 +EF00 +FF80 +F380 +E380 +E380 +E380 +E380 +E380 +E380 +E380 +ENDCHAR + +STARTCHAR ograve +ENCODING 242 +SWIDTH 611 0 +DWIDTH 12 0 +BBX 10 14 1 0 +BITMAP +3800 +1C00 +0E00 +0000 +1E00 +7F80 +7380 +E1C0 +E1C0 +E1C0 +E1C0 +7380 +7F80 +1E00 +ENDCHAR + +STARTCHAR oacute +ENCODING 243 +SWIDTH 611 0 +DWIDTH 12 0 +BBX 10 14 1 0 +BITMAP +0700 +0E00 +1C00 +0000 +1E00 +7F80 +7380 +E1C0 +E1C0 +E1C0 +E1C0 +7380 +7F80 +1E00 +ENDCHAR + +STARTCHAR ocircumflex +ENCODING 244 +SWIDTH 611 0 +DWIDTH 12 0 +BBX 10 14 1 0 +BITMAP +0E00 +1F00 +3B80 +0000 +1E00 +7F80 +7380 +E1C0 +E1C0 +E1C0 +E1C0 +7380 +7F80 +1E00 +ENDCHAR + +STARTCHAR otilde +ENCODING 245 +SWIDTH 611 0 +DWIDTH 12 0 +BBX 10 14 1 0 +BITMAP +1D80 +3F80 +3700 +0000 +1E00 +7F80 +7380 +E1C0 +E1C0 +E1C0 +E1C0 +7380 +7F80 +1E00 +ENDCHAR + +STARTCHAR odieresis +ENCODING 246 +SWIDTH 611 0 +DWIDTH 12 0 +BBX 10 13 1 0 +BITMAP +3300 +3300 +0000 +1E00 +7F80 +7380 +E1C0 +E1C0 +E1C0 +E1C0 +7380 +7F80 +1E00 +ENDCHAR + +STARTCHAR divide +ENCODING 247 +SWIDTH 584 0 +DWIDTH 11 0 +BBX 9 8 1 1 +BITMAP +1C00 +1C00 +0000 +FF80 +FF80 +0000 +1C00 +1C00 +ENDCHAR + +STARTCHAR oslash +ENCODING 248 +SWIDTH 611 0 +DWIDTH 12 0 +BBX 12 10 0 0 +BITMAP +0F30 +3FE0 +38C0 +71E0 +77E0 +7EE0 +78E0 +31C0 +7FC0 +CF00 +ENDCHAR + +STARTCHAR ugrave +ENCODING 249 +SWIDTH 611 0 +DWIDTH 11 0 +BBX 9 14 1 0 +BITMAP +7000 +3800 +1C00 +0000 +E380 +E380 +E380 +E380 +E380 +E380 +E380 +E780 +FF80 +7B80 +ENDCHAR + +STARTCHAR uacute +ENCODING 250 +SWIDTH 611 0 +DWIDTH 11 0 +BBX 9 14 1 0 +BITMAP +0700 +0E00 +1C00 +0000 +E380 +E380 +E380 +E380 +E380 +E380 +E380 +E780 +FF80 +7B80 +ENDCHAR + +STARTCHAR ucircumflex +ENCODING 251 +SWIDTH 611 0 +DWIDTH 11 0 +BBX 9 14 1 0 +BITMAP +1C00 +3E00 +7700 +0000 +E380 +E380 +E380 +E380 +E380 +E380 +E380 +E780 +FF80 +7B80 +ENDCHAR + +STARTCHAR udieresis +ENCODING 252 +SWIDTH 611 0 +DWIDTH 11 0 +BBX 9 13 1 0 +BITMAP +3600 +3600 +0000 +E380 +E380 +E380 +E380 +E380 +E380 +E380 +E780 +FF80 +7B80 +ENDCHAR + +STARTCHAR yacute +ENCODING 253 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 9 18 0 -4 +BITMAP +0700 +0E00 +1C00 +0000 +E380 +E380 +E380 +7700 +7700 +7700 +3E00 +3E00 +1C00 +1C00 +1C00 +1800 +7800 +7000 +ENDCHAR + +STARTCHAR thorn +ENCODING 254 +SWIDTH 611 0 +DWIDTH 12 0 +BBX 10 18 1 -4 +BITMAP +E000 +E000 +E000 +E000 +EF00 +FF80 +F380 +E1C0 +E1C0 +E1C0 +E1C0 +F380 +FF80 +EF00 +E000 +E000 +E000 +E000 +ENDCHAR + +STARTCHAR ydieresis +ENCODING 255 +SWIDTH 556 0 +DWIDTH 9 0 +BBX 9 17 0 -4 +BITMAP +3600 +3600 +0000 +E380 +E380 +E380 +7700 +7700 +7700 +3E00 +3E00 +1C00 +1C00 +1C00 +1800 +7800 +7000 +ENDCHAR + +ENDFONT diff --git a/fonts/helvB18.cc b/fonts/helvB18.cc new file mode 100644 index 0000000000000000000000000000000000000000..5da9b7f5cb70b0de232ff7d9c9a80a712631cf79 GIT binary patch literal 240846 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 z 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 QVa_h@(s1jOH-dHlABsh~Q~&?~ literal 0 HcmV?d00001 diff --git a/fonts/helvB24-ISO8859-1.pcf b/fonts/helvB24-ISO8859-1.pcf new file mode 100644 index 0000000000000000000000000000000000000000..6309e1e8424b13d798f22437983e46e6f189e4fa GIT binary patch literal 19620 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 literal 0 HcmV?d00001 diff --git a/fonts/helvB24.bdf b/fonts/helvB24.bdf new file mode 100644 index 0000000..971b857 --- /dev/null +++ b/fonts/helvB24.bdf @@ -0,0 +1,4889 @@ +STARTFONT 2.1 +FONT -Adobe-Helvetica-Bold-R-Normal--24-240-75-75-P-138-ISO8859-1 +SIZE 24 75 75 +FONTBOUNDINGBOX 24 29 -1 -5 + +STARTPROPERTIES 28 +FOUNDRY "Adobe" +FAMILY_NAME "Helvetica" +WEIGHT_NAME "Bold" +SLANT "R" +SETWIDTH_NAME "Normal" +ADD_STYLE_NAME "" +PIXEL_SIZE 24 +POINT_SIZE 240 +RESOLUTION_X 75 +RESOLUTION_Y 75 +SPACING "P" +AVERAGE_WIDTH 138 +CHARSET_REGISTRY "ISO8859" +CHARSET_ENCODING "1" +CAP_HEIGHT 19 +X_HEIGHT 14 +FACE_NAME "Helvetica Bold" +COPYRIGHT "Copyright (c) 1984, 1987 Adobe Systems Incorporated. All Rights Reserved. Copyright (c) 1988, 1991 Digital Equipment Corporation. All Rights Reserved." +NOTICE "Helvetica is a trademark of Linotype-Hell AG and/or its subsidiaries. " +_DEC_DEVICE_FONTNAMES "PS=Helvetica-Bold" +RELATIVE_SETWIDTH 50 +RELATIVE_WEIGHT 70 +FULL_NAME "Helvetica Bold" +WEIGHT 10 +QUAD_WIDTH 15 +DEFAULT_CHAR 0 +FONT_DESCENT 5 +FONT_ASCENT 22 +ENDPROPERTIES + +CHARS 192 + +STARTCHAR defaultchar +ENCODING 0 +SWIDTH 722 0 +DWIDTH 19 0 +BBX 15 19 2 0 +BITMAP +AAAA +0000 +8002 +0000 +8002 +0000 +8002 +0000 +8002 +0000 +8002 +0000 +8002 +0000 +8002 +0000 +8002 +0000 +AAAA +ENDCHAR + +STARTCHAR space +ENCODING 32 +SWIDTH 278 0 +DWIDTH 6 0 +BBX 1 1 0 0 +BITMAP +00 +ENDCHAR + +STARTCHAR exclam +ENCODING 33 +SWIDTH 333 0 +DWIDTH 7 0 +BBX 3 19 2 0 +BITMAP +E0 +E0 +E0 +E0 +E0 +E0 +E0 +E0 +E0 +E0 +E0 +E0 +E0 +E0 +00 +00 +E0 +E0 +E0 +ENDCHAR + +STARTCHAR quotedbl +ENCODING 34 +SWIDTH 474 0 +DWIDTH 9 0 +BBX 5 6 2 13 +BITMAP +D8 +D8 +D8 +D8 +D8 +90 +ENDCHAR + +STARTCHAR numbersign +ENCODING 35 +SWIDTH 556 0 +DWIDTH 14 0 +BBX 12 18 0 0 +BITMAP +0CC0 +0CC0 +0CC0 +0CC0 +0CC0 +7FF0 +7FF0 +1980 +1980 +1980 +1980 +FFE0 +FFE0 +3300 +3300 +3300 +3300 +3300 +ENDCHAR + +STARTCHAR dollar +ENCODING 36 +SWIDTH 556 0 +DWIDTH 13 0 +BBX 12 21 0 -2 +BITMAP +0600 +3F80 +7FC0 +F6E0 +E6E0 +E6E0 +F600 +7E00 +3E00 +0F00 +07C0 +07E0 +06F0 +E670 +E670 +E670 +F6F0 +7FE0 +1FC0 +0600 +0600 +ENDCHAR + +STARTCHAR percent +ENCODING 37 +SWIDTH 889 0 +DWIDTH 22 0 +BBX 21 18 0 0 +BITMAP +000700 +3E0700 +7F0E00 +E38E00 +C19C00 +C19C00 +E3B800 +7F3800 +3E7000 +007000 +00E3E0 +00E7F0 +01CE38 +01CC18 +038C18 +038E38 +0707F0 +0703E0 +ENDCHAR + +STARTCHAR ampersand +ENCODING 38 +SWIDTH 722 0 +DWIDTH 18 0 +BBX 16 18 1 0 +BITMAP +0F80 +1FC0 +3DE0 +38E0 +38E0 +38E0 +1DC0 +0F80 +1F00 +3F9C +7BDC +71FC +E0F8 +E070 +E0F8 +F1FC +7FCE +1F87 +ENDCHAR + +STARTCHAR quotesingle +ENCODING 39 +SWIDTH 238 0 +DWIDTH 6 0 +BBX 2 6 2 13 +BITMAP +C0 +C0 +C0 +C0 +C0 +80 +ENDCHAR + +STARTCHAR parenleft +ENCODING 40 +SWIDTH 333 0 +DWIDTH 8 0 +BBX 6 24 1 -5 +BITMAP +0C +1C +38 +38 +70 +70 +60 +E0 +E0 +E0 +E0 +E0 +E0 +E0 +E0 +E0 +E0 +60 +70 +70 +38 +38 +1C +0C +ENDCHAR + +STARTCHAR parenright +ENCODING 41 +SWIDTH 333 0 +DWIDTH 8 0 +BBX 6 24 1 -5 +BITMAP +C0 +E0 +70 +70 +38 +38 +18 +1C +1C +1C +1C +1C +1C +1C +1C +1C +1C +18 +38 +38 +70 +70 +E0 +C0 +ENDCHAR + +STARTCHAR asterisk +ENCODING 42 +SWIDTH 389 0 +DWIDTH 10 0 +BBX 8 7 1 12 +BITMAP +18 +18 +DB +FF +3C +66 +66 +ENDCHAR + +STARTCHAR plus +ENCODING 43 +SWIDTH 584 0 +DWIDTH 15 0 +BBX 11 12 2 1 +BITMAP +0E00 +0E00 +0E00 +0E00 +0E00 +FFE0 +FFE0 +0E00 +0E00 +0E00 +0E00 +0E00 +ENDCHAR + +STARTCHAR comma +ENCODING 44 +SWIDTH 278 0 +DWIDTH 7 0 +BBX 3 6 2 -3 +BITMAP +E0 +E0 +E0 +60 +60 +C0 +ENDCHAR + +STARTCHAR hyphen +ENCODING 45 +SWIDTH 333 0 +DWIDTH 8 0 +BBX 7 3 0 6 +BITMAP +FE +FE +FE +ENDCHAR + +STARTCHAR period +ENCODING 46 +SWIDTH 278 0 +DWIDTH 7 0 +BBX 3 3 2 0 +BITMAP +E0 +E0 +E0 +ENDCHAR + +STARTCHAR slash +ENCODING 47 +SWIDTH 278 0 +DWIDTH 8 0 +BBX 8 19 0 0 +BITMAP +07 +07 +06 +06 +0E +0C +0C +1C +1C +18 +18 +38 +30 +30 +70 +60 +60 +E0 +E0 +ENDCHAR + +STARTCHAR zero +ENCODING 48 +SWIDTH 556 0 +DWIDTH 13 0 +BBX 12 18 0 0 +BITMAP +1F80 +3FC0 +79E0 +70E0 +70E0 +E070 +E070 +E070 +E070 +E070 +E070 +E070 +E070 +70E0 +70E0 +79E0 +3FC0 +1F80 +ENDCHAR + +STARTCHAR one +ENCODING 49 +SWIDTH 556 0 +DWIDTH 13 0 +BBX 7 18 2 0 +BITMAP +0E +0E +1E +FE +FE +0E +0E +0E +0E +0E +0E +0E +0E +0E +0E +0E +0E +0E +ENDCHAR + +STARTCHAR two +ENCODING 50 +SWIDTH 556 0 +DWIDTH 13 0 +BBX 12 18 0 0 +BITMAP +1F00 +7FC0 +71E0 +E0E0 +E070 +E070 +0070 +00E0 +01E0 +03C0 +0780 +1F00 +3C00 +7800 +F000 +E000 +FFF0 +FFF0 +ENDCHAR + +STARTCHAR three +ENCODING 51 +SWIDTH 556 0 +DWIDTH 13 0 +BBX 12 18 0 0 +BITMAP +1F00 +7FC0 +71C0 +E0E0 +E0E0 +E0E0 +00E0 +01C0 +0F80 +0FE0 +00E0 +0070 +0070 +E070 +E0F0 +71E0 +7FE0 +1F80 +ENDCHAR + +STARTCHAR four +ENCODING 52 +SWIDTH 556 0 +DWIDTH 13 0 +BBX 12 18 0 0 +BITMAP +01C0 +03C0 +03C0 +07C0 +07C0 +0DC0 +1DC0 +19C0 +31C0 +71C0 +61C0 +E1C0 +FFF0 +FFF0 +01C0 +01C0 +01C0 +01C0 +ENDCHAR + +STARTCHAR five +ENCODING 53 +SWIDTH 556 0 +DWIDTH 13 0 +BBX 12 18 0 0 +BITMAP +7FE0 +7FE0 +7000 +7000 +7000 +7000 +7F80 +7FC0 +71E0 +00E0 +0070 +0070 +0070 +E070 +E0F0 +F1E0 +7FC0 +1F80 +ENDCHAR + +STARTCHAR six +ENCODING 54 +SWIDTH 556 0 +DWIDTH 13 0 +BBX 12 18 0 0 +BITMAP +0F80 +3FE0 +78E0 +7070 +E070 +E000 +E000 +EF00 +FFC0 +F9E0 +F0E0 +E070 +E070 +E070 +70E0 +79E0 +3FC0 +1F80 +ENDCHAR + +STARTCHAR seven +ENCODING 55 +SWIDTH 556 0 +DWIDTH 13 0 +BBX 12 18 0 0 +BITMAP +FFF0 +FFF0 +00F0 +00E0 +01C0 +01C0 +0380 +0380 +0700 +0700 +0E00 +0E00 +1E00 +1C00 +1C00 +3C00 +3800 +3800 +ENDCHAR + +STARTCHAR eight +ENCODING 56 +SWIDTH 556 0 +DWIDTH 13 0 +BBX 12 18 0 0 +BITMAP +0F00 +3FC0 +39C0 +70E0 +70E0 +70E0 +70E0 +39C0 +1F80 +3FC0 +70E0 +E070 +E070 +E070 +E070 +70E0 +7FE0 +1F80 +ENDCHAR + +STARTCHAR nine +ENCODING 57 +SWIDTH 556 0 +DWIDTH 13 0 +BBX 12 18 0 0 +BITMAP +1F80 +7FC0 +79E0 +F0E0 +E070 +E070 +E070 +E070 +F0F0 +79F0 +7FF0 +1F70 +0070 +0070 +E0E0 +F3E0 +7FC0 +1F00 +ENDCHAR + +STARTCHAR colon +ENCODING 58 +SWIDTH 333 0 +DWIDTH 7 0 +BBX 3 14 2 0 +BITMAP +E0 +E0 +E0 +00 +00 +00 +00 +00 +00 +00 +00 +E0 +E0 +E0 +ENDCHAR + +STARTCHAR semicolon +ENCODING 59 +SWIDTH 333 0 +DWIDTH 7 0 +BBX 3 17 2 -3 +BITMAP +E0 +E0 +E0 +00 +00 +00 +00 +00 +00 +00 +00 +E0 +E0 +E0 +60 +60 +C0 +ENDCHAR + +STARTCHAR less +ENCODING 60 +SWIDTH 584 0 +DWIDTH 15 0 +BBX 13 12 0 1 +BITMAP +0038 +00F8 +03E0 +0F80 +3E00 +F000 +F000 +3E00 +0F80 +03E0 +00F8 +0038 +ENDCHAR + +STARTCHAR equal +ENCODING 61 +SWIDTH 584 0 +DWIDTH 14 0 +BBX 10 6 2 4 +BITMAP +FFC0 +FFC0 +0000 +0000 +FFC0 +FFC0 +ENDCHAR + +STARTCHAR greater +ENCODING 62 +SWIDTH 584 0 +DWIDTH 14 0 +BBX 13 12 0 1 +BITMAP +E000 +F800 +3E00 +0F80 +03E0 +0078 +0078 +03E0 +0F80 +3E00 +F800 +E000 +ENDCHAR + +STARTCHAR question +ENCODING 63 +SWIDTH 611 0 +DWIDTH 15 0 +BBX 11 19 2 0 +BITMAP +1F80 +7FC0 +79E0 +F0E0 +E0E0 +E1E0 +01C0 +03C0 +0780 +0700 +0E00 +0E00 +0E00 +0E00 +0000 +0000 +0E00 +0E00 +0E00 +ENDCHAR + +STARTCHAR at +ENCODING 64 +SWIDTH 975 0 +DWIDTH 24 0 +BBX 22 22 1 -4 +BITMAP +01FF00 +07FFC0 +0F81F0 +1E0078 +3C0038 +787D9C +70FF9C +F1C71C +E3871C +E30E1C +E70E38 +E70C38 +E71C70 +E71C70 +E39DE0 +F3FFC0 +71F700 +780000 +3C0000 +1F0700 +0FFF00 +03FC00 +ENDCHAR + +STARTCHAR A +ENCODING 65 +SWIDTH 722 0 +DWIDTH 18 0 +BBX 16 19 1 0 +BITMAP +03C0 +03C0 +07E0 +07E0 +0E60 +0E70 +0E70 +1C38 +1C38 +1C38 +381C +381C +3FFC +7FFE +700E +700E +E007 +E007 +E007 +ENDCHAR + +STARTCHAR B +ENCODING 66 +SWIDTH 722 0 +DWIDTH 18 0 +BBX 15 19 2 0 +BITMAP +FFE0 +FFF8 +E078 +E01C +E01C +E01C +E01C +E038 +FFF0 +FFF8 +E01C +E00E +E00E +E00E +E00E +E01E +E07C +FFF8 +FFE0 +ENDCHAR + +STARTCHAR C +ENCODING 67 +SWIDTH 722 0 +DWIDTH 18 0 +BBX 16 19 1 0 +BITMAP +07F0 +1FFC +3E3E +780F +7007 +F000 +E000 +E000 +E000 +E000 +E000 +E000 +E000 +F007 +7007 +780F +3E3E +1FFC +07F0 +ENDCHAR + +STARTCHAR D +ENCODING 68 +SWIDTH 722 0 +DWIDTH 19 0 +BBX 16 19 2 0 +BITMAP +FFE0 +FFF8 +E07C +E01E +E00E +E00F +E007 +E007 +E007 +E007 +E007 +E007 +E007 +E00F +E00E +E01E +E07C +FFF8 +FFE0 +ENDCHAR + +STARTCHAR E +ENCODING 69 +SWIDTH 667 0 +DWIDTH 16 0 +BBX 13 19 2 0 +BITMAP +FFF0 +FFF0 +E000 +E000 +E000 +E000 +E000 +E000 +FFE0 +FFE0 +E000 +E000 +E000 +E000 +E000 +E000 +E000 +FFF8 +FFF8 +ENDCHAR + +STARTCHAR F +ENCODING 70 +SWIDTH 611 0 +DWIDTH 15 0 +BBX 12 19 2 0 +BITMAP +FFF0 +FFF0 +E000 +E000 +E000 +E000 +E000 +E000 +FFE0 +FFE0 +E000 +E000 +E000 +E000 +E000 +E000 +E000 +E000 +E000 +ENDCHAR + +STARTCHAR G +ENCODING 71 +SWIDTH 778 0 +DWIDTH 19 0 +BBX 17 19 1 0 +BITMAP +07F000 +1FFC00 +3E3E00 +780F00 +700700 +F00000 +E00000 +E00000 +E00000 +E07F80 +E07F80 +E00380 +E00380 +F00380 +700780 +780F80 +3E3F80 +1FFB80 +07F180 +ENDCHAR + +STARTCHAR H +ENCODING 72 +SWIDTH 722 0 +DWIDTH 19 0 +BBX 15 19 2 0 +BITMAP +E00E +E00E +E00E +E00E +E00E +E00E +E00E +E00E +FFFE +FFFE +E00E +E00E +E00E +E00E +E00E +E00E +E00E +E00E +E00E +ENDCHAR + +STARTCHAR I +ENCODING 73 +SWIDTH 278 0 +DWIDTH 7 0 +BBX 3 19 2 0 +BITMAP +E0 +E0 +E0 +E0 +E0 +E0 +E0 +E0 +E0 +E0 +E0 +E0 +E0 +E0 +E0 +E0 +E0 +E0 +E0 +ENDCHAR + +STARTCHAR J +ENCODING 74 +SWIDTH 556 0 +DWIDTH 14 0 +BBX 11 19 1 0 +BITMAP +00E0 +00E0 +00E0 +00E0 +00E0 +00E0 +00E0 +00E0 +00E0 +00E0 +00E0 +00E0 +E0E0 +E0E0 +E0E0 +E0E0 +71E0 +7FC0 +3F80 +ENDCHAR + +STARTCHAR K +ENCODING 75 +SWIDTH 722 0 +DWIDTH 18 0 +BBX 16 19 2 0 +BITMAP +E03C +E078 +E0F0 +E1E0 +E3C0 +E780 +EF00 +FE00 +FE00 +FF00 +F780 +E3C0 +E1E0 +E0F0 +E078 +E03C +E01E +E00F +E007 +ENDCHAR + +STARTCHAR L +ENCODING 76 +SWIDTH 611 0 +DWIDTH 15 0 +BBX 12 19 2 0 +BITMAP +E000 +E000 +E000 +E000 +E000 +E000 +E000 +E000 +E000 +E000 +E000 +E000 +E000 +E000 +E000 +E000 +E000 +FFF0 +FFF0 +ENDCHAR + +STARTCHAR M +ENCODING 77 +SWIDTH 833 0 +DWIDTH 23 0 +BBX 19 19 2 0 +BITMAP +E000E0 +F001E0 +F001E0 +F803E0 +F803E0 +FC07E0 +EC06E0 +EE0EE0 +E60CE0 +E71CE0 +E71CE0 +E318E0 +E3B8E0 +E3B8E0 +E1F0E0 +E1F0E0 +E0E0E0 +E0E0E0 +E0E0E0 +ENDCHAR + +STARTCHAR N +ENCODING 78 +SWIDTH 722 0 +DWIDTH 19 0 +BBX 15 19 2 0 +BITMAP +E00E +F00E +F00E +F80E +F80E +FC0E +EE0E +EE0E +E70E +E38E +E38E +E1CE +E0CE +E0EE +E07E +E03E +E03E +E01E +E00E +ENDCHAR + +STARTCHAR O +ENCODING 79 +SWIDTH 778 0 +DWIDTH 19 0 +BBX 17 19 1 0 +BITMAP +07F000 +1FFC00 +3E3E00 +780F00 +700700 +F00780 +E00380 +E00380 +E00380 +E00380 +E00380 +E00380 +E00380 +F00780 +700700 +780F00 +3E3E00 +1FFC00 +07F000 +ENDCHAR + +STARTCHAR P +ENCODING 80 +SWIDTH 667 0 +DWIDTH 17 0 +BBX 14 19 2 0 +BITMAP +FFE0 +FFF8 +E038 +E01C +E01C +E01C +E01C +E038 +FFF8 +FFF0 +E000 +E000 +E000 +E000 +E000 +E000 +E000 +E000 +E000 +ENDCHAR + +STARTCHAR Q +ENCODING 81 +SWIDTH 778 0 +DWIDTH 19 0 +BBX 17 19 1 0 +BITMAP +07F000 +1FFC00 +3E3E00 +780F00 +700700 +F00780 +E00380 +E00380 +E00380 +E00380 +E00380 +E00380 +E00380 +F00780 +70F700 +787F00 +3E1E00 +1FFF00 +07F780 +ENDCHAR + +STARTCHAR R +ENCODING 82 +SWIDTH 722 0 +DWIDTH 17 0 +BBX 14 19 2 0 +BITMAP +FFE0 +FFF8 +E038 +E01C +E01C +E01C +E01C +E038 +FFF8 +FFF0 +E078 +E038 +E01C +E01C +E01C +E01C +E01C +E01C +E01C +ENDCHAR + +STARTCHAR S +ENCODING 83 +SWIDTH 667 0 +DWIDTH 17 0 +BBX 15 19 1 0 +BITMAP +07E0 +1FF8 +3C7C +781C +701C +7000 +7800 +3E00 +1FE0 +03F8 +007C +001E +000E +E00E +E00E +F01E +7C7C +3FF8 +0FE0 +ENDCHAR + +STARTCHAR T +ENCODING 84 +SWIDTH 611 0 +DWIDTH 15 0 +BBX 15 19 0 0 +BITMAP +FFFE +FFFE +0380 +0380 +0380 +0380 +0380 +0380 +0380 +0380 +0380 +0380 +0380 +0380 +0380 +0380 +0380 +0380 +0380 +ENDCHAR + +STARTCHAR U +ENCODING 85 +SWIDTH 722 0 +DWIDTH 19 0 +BBX 15 19 2 0 +BITMAP +E00E +E00E +E00E +E00E +E00E +E00E +E00E +E00E +E00E +E00E +E00E +E00E +E00E +E00E +F01E +701C +7C7C +3FF8 +0FE0 +ENDCHAR + +STARTCHAR V +ENCODING 86 +SWIDTH 667 0 +DWIDTH 18 0 +BBX 16 19 1 0 +BITMAP +E007 +E007 +F00F +700E +781E +381C +381C +3C3C +1C38 +1C38 +1E78 +0E70 +0E70 +0E70 +07E0 +07E0 +03C0 +03C0 +03C0 +ENDCHAR + +STARTCHAR W +ENCODING 87 +SWIDTH 944 0 +DWIDTH 23 0 +BBX 21 19 1 0 +BITMAP +E07038 +E07038 +E07038 +E07038 +70F870 +70F870 +70D870 +71DC70 +31DC60 +39DCE0 +398CE0 +3B8EE0 +1B8EC0 +1B8EC0 +1F07C0 +1F07C0 +0E0380 +0E0380 +0E0380 +ENDCHAR + +STARTCHAR X +ENCODING 88 +SWIDTH 667 0 +DWIDTH 18 0 +BBX 16 19 1 0 +BITMAP +E007 +F00F +781E +381C +1C38 +0E70 +0FF0 +07E0 +03C0 +03C0 +07E0 +0FF0 +0E70 +1C38 +3C3C +381C +700E +F00F +E007 +ENDCHAR + +STARTCHAR Y +ENCODING 89 +SWIDTH 667 0 +DWIDTH 17 0 +BBX 15 19 1 0 +BITMAP +E00E +F01E +701C +783C +3838 +3C78 +1C70 +1EF0 +0EE0 +0FE0 +07C0 +07C0 +0380 +0380 +0380 +0380 +0380 +0380 +0380 +ENDCHAR + +STARTCHAR Z +ENCODING 90 +SWIDTH 611 0 +DWIDTH 16 0 +BBX 14 19 1 0 +BITMAP +FFFC +FFFC +003C +0078 +00F0 +01E0 +01E0 +03C0 +0780 +0780 +0F00 +1E00 +1E00 +3C00 +3800 +7800 +F000 +FFFC +FFFC +ENDCHAR + +STARTCHAR bracketleft +ENCODING 91 +SWIDTH 333 0 +DWIDTH 8 0 +BBX 5 24 1 -5 +BITMAP +F8 +F8 +E0 +E0 +E0 +E0 +E0 +E0 +E0 +E0 +E0 +E0 +E0 +E0 +E0 +E0 +E0 +E0 +E0 +E0 +E0 +E0 +F8 +F8 +ENDCHAR + +STARTCHAR backslash +ENCODING 92 +SWIDTH 278 0 +DWIDTH 8 0 +BBX 8 19 0 0 +BITMAP +E0 +E0 +60 +60 +70 +30 +30 +38 +38 +18 +18 +1C +0C +0C +0E +06 +06 +07 +07 +ENDCHAR + +STARTCHAR bracketright +ENCODING 93 +SWIDTH 333 0 +DWIDTH 8 0 +BBX 5 24 2 -5 +BITMAP +F8 +F8 +38 +38 +38 +38 +38 +38 +38 +38 +38 +38 +38 +38 +38 +38 +38 +38 +38 +38 +38 +38 +F8 +F8 +ENDCHAR + +STARTCHAR asciicircum +ENCODING 94 +SWIDTH 584 0 +DWIDTH 14 0 +BBX 11 9 1 10 +BITMAP +0E00 +0E00 +1F00 +1B00 +3B80 +71C0 +71C0 +E0E0 +E0E0 +ENDCHAR + +STARTCHAR underscore +ENCODING 95 +SWIDTH 556 0 +DWIDTH 14 0 +BBX 14 2 0 -5 +BITMAP +FFFC +FFFC +ENDCHAR + +STARTCHAR grave +ENCODING 96 +SWIDTH 333 0 +DWIDTH 8 0 +BBX 6 4 1 15 +BITMAP +E0 +70 +38 +1C +ENDCHAR + +STARTCHAR a +ENCODING 97 +SWIDTH 556 0 +DWIDTH 14 0 +BBX 12 14 1 0 +BITMAP +1F80 +3FC0 +71E0 +70E0 +00E0 +07E0 +3FE0 +7CE0 +F0E0 +E0E0 +E1E0 +F3E0 +7FF0 +3E70 +ENDCHAR + +STARTCHAR b +ENCODING 98 +SWIDTH 611 0 +DWIDTH 15 0 +BBX 12 19 2 0 +BITMAP +E000 +E000 +E000 +E000 +E000 +EF80 +FFC0 +F9E0 +F0E0 +E070 +E070 +E070 +E070 +E070 +E070 +F0E0 +F9E0 +FFC0 +EF80 +ENDCHAR + +STARTCHAR c +ENCODING 99 +SWIDTH 556 0 +DWIDTH 13 0 +BBX 11 14 1 0 +BITMAP +1F80 +3FC0 +79E0 +70E0 +E000 +E000 +E000 +E000 +E000 +E000 +70E0 +79E0 +3FC0 +1F80 +ENDCHAR + +STARTCHAR d +ENCODING 100 +SWIDTH 611 0 +DWIDTH 15 0 +BBX 12 19 1 0 +BITMAP +0070 +0070 +0070 +0070 +0070 +1F70 +3FF0 +79F0 +70F0 +E070 +E070 +E070 +E070 +E070 +E070 +70F0 +79F0 +3FF0 +1F70 +ENDCHAR + +STARTCHAR e +ENCODING 101 +SWIDTH 556 0 +DWIDTH 14 0 +BBX 12 14 1 0 +BITMAP +0F00 +3FC0 +79E0 +70E0 +E070 +E070 +FFF0 +FFF0 +E000 +E000 +7070 +78F0 +3FE0 +0F80 +ENDCHAR + +STARTCHAR f +ENCODING 102 +SWIDTH 333 0 +DWIDTH 9 0 +BBX 7 19 1 0 +BITMAP +1E +3E +38 +38 +38 +FE +FE +38 +38 +38 +38 +38 +38 +38 +38 +38 +38 +38 +38 +ENDCHAR + +STARTCHAR g +ENCODING 103 +SWIDTH 611 0 +DWIDTH 15 0 +BBX 12 19 1 -5 +BITMAP +1F70 +3FF0 +79F0 +70F0 +E070 +E070 +E070 +E070 +E070 +E070 +70F0 +79F0 +3FF0 +1F70 +0070 +E070 +F0E0 +7FE0 +1F80 +ENDCHAR + +STARTCHAR h +ENCODING 104 +SWIDTH 611 0 +DWIDTH 15 0 +BBX 11 19 2 0 +BITMAP +E000 +E000 +E000 +E000 +E000 +EF00 +FFC0 +F1C0 +E0E0 +E0E0 +E0E0 +E0E0 +E0E0 +E0E0 +E0E0 +E0E0 +E0E0 +E0E0 +E0E0 +ENDCHAR + +STARTCHAR i +ENCODING 105 +SWIDTH 278 0 +DWIDTH 7 0 +BBX 3 19 2 0 +BITMAP +E0 +E0 +E0 +00 +00 +E0 +E0 +E0 +E0 +E0 +E0 +E0 +E0 +E0 +E0 +E0 +E0 +E0 +E0 +ENDCHAR + +STARTCHAR j +ENCODING 106 +SWIDTH 278 0 +DWIDTH 7 0 +BBX 5 24 0 -5 +BITMAP +38 +38 +38 +00 +00 +38 +38 +38 +38 +38 +38 +38 +38 +38 +38 +38 +38 +38 +38 +38 +38 +38 +F8 +F0 +ENDCHAR + +STARTCHAR k +ENCODING 107 +SWIDTH 556 0 +DWIDTH 14 0 +BBX 12 19 2 0 +BITMAP +E000 +E000 +E000 +E000 +E000 +E1E0 +E3C0 +E780 +EF00 +FE00 +FC00 +FE00 +EF00 +E700 +E780 +E3C0 +E1C0 +E1E0 +E0F0 +ENDCHAR + +STARTCHAR l +ENCODING 108 +SWIDTH 278 0 +DWIDTH 7 0 +BBX 3 19 2 0 +BITMAP +E0 +E0 +E0 +E0 +E0 +E0 +E0 +E0 +E0 +E0 +E0 +E0 +E0 +E0 +E0 +E0 +E0 +E0 +E0 +ENDCHAR + +STARTCHAR m +ENCODING 109 +SWIDTH 889 0 +DWIDTH 21 0 +BBX 17 14 2 0 +BITMAP +EF3E00 +FFFF00 +F3E780 +E1C380 +E1C380 +E1C380 +E1C380 +E1C380 +E1C380 +E1C380 +E1C380 +E1C380 +E1C380 +E1C380 +ENDCHAR + +STARTCHAR n +ENCODING 110 +SWIDTH 611 0 +DWIDTH 15 0 +BBX 11 14 2 0 +BITMAP +EF80 +FFC0 +F1C0 +E0E0 +E0E0 +E0E0 +E0E0 +E0E0 +E0E0 +E0E0 +E0E0 +E0E0 +E0E0 +E0E0 +ENDCHAR + +STARTCHAR o +ENCODING 111 +SWIDTH 611 0 +DWIDTH 14 0 +BBX 12 14 1 0 +BITMAP +0F00 +3FC0 +79E0 +70E0 +E070 +E070 +E070 +E070 +E070 +E070 +70E0 +79E0 +3FC0 +0F00 +ENDCHAR + +STARTCHAR p +ENCODING 112 +SWIDTH 611 0 +DWIDTH 15 0 +BBX 12 19 2 -5 +BITMAP +EF80 +FFC0 +F9E0 +F0E0 +E070 +E070 +E070 +E070 +E070 +E070 +F0E0 +F9E0 +FFC0 +EF80 +E000 +E000 +E000 +E000 +E000 +ENDCHAR + +STARTCHAR q +ENCODING 113 +SWIDTH 611 0 +DWIDTH 15 0 +BBX 12 19 1 -5 +BITMAP +1F70 +3FF0 +79F0 +70F0 +E070 +E070 +E070 +E070 +E070 +E070 +70F0 +79F0 +3FF0 +1F70 +0070 +0070 +0070 +0070 +0070 +ENDCHAR + +STARTCHAR r +ENCODING 114 +SWIDTH 389 0 +DWIDTH 10 0 +BBX 7 14 2 0 +BITMAP +E6 +EE +FE +F0 +E0 +E0 +E0 +E0 +E0 +E0 +E0 +E0 +E0 +E0 +ENDCHAR + +STARTCHAR s +ENCODING 115 +SWIDTH 556 0 +DWIDTH 13 0 +BBX 11 14 1 0 +BITMAP +3F00 +7F80 +F3C0 +E1C0 +E000 +FC00 +7F80 +0FC0 +01E0 +E0E0 +E0E0 +F1E0 +7FC0 +3F80 +ENDCHAR + +STARTCHAR t +ENCODING 116 +SWIDTH 333 0 +DWIDTH 9 0 +BBX 7 18 1 0 +BITMAP +38 +38 +38 +38 +FE +FE +38 +38 +38 +38 +38 +38 +38 +38 +38 +38 +3E +1E +ENDCHAR + +STARTCHAR u +ENCODING 117 +SWIDTH 611 0 +DWIDTH 15 0 +BBX 11 14 2 0 +BITMAP +E0E0 +E0E0 +E0E0 +E0E0 +E0E0 +E0E0 +E0E0 +E0E0 +E0E0 +E0E0 +E1E0 +73E0 +7EE0 +1CE0 +ENDCHAR + +STARTCHAR v +ENCODING 118 +SWIDTH 556 0 +DWIDTH 14 0 +BBX 12 14 1 0 +BITMAP +E070 +E070 +E070 +70E0 +70E0 +70E0 +39C0 +39C0 +39C0 +1F80 +1F80 +0F00 +0F00 +0F00 +ENDCHAR + +STARTCHAR w +ENCODING 119 +SWIDTH 778 0 +DWIDTH 19 0 +BBX 19 14 0 0 +BITMAP +E0E0E0 +E0E0E0 +60E0C0 +71F1C0 +71F1C0 +31B180 +33B980 +3BBB80 +1B1B00 +1F1F00 +1F1F00 +0E0E00 +0E0E00 +0E0E00 +ENDCHAR + +STARTCHAR x +ENCODING 120 +SWIDTH 556 0 +DWIDTH 13 0 +BBX 11 14 1 0 +BITMAP +E0E0 +F1E0 +71C0 +3B80 +3F80 +1F00 +0E00 +1F00 +1F00 +3B80 +7BC0 +71C0 +F1E0 +E0E0 +ENDCHAR + +STARTCHAR y +ENCODING 121 +SWIDTH 556 0 +DWIDTH 15 0 +BBX 13 19 1 -5 +BITMAP +E038 +E038 +7038 +7870 +3870 +3CF0 +1CE0 +1CE0 +0FC0 +0FC0 +07C0 +0780 +0380 +0380 +0700 +0700 +0E00 +3E00 +3C00 +ENDCHAR + +STARTCHAR z +ENCODING 122 +SWIDTH 500 0 +DWIDTH 13 0 +BBX 11 14 1 0 +BITMAP +FFE0 +FFE0 +01C0 +0380 +0780 +0F00 +0E00 +1E00 +3C00 +3800 +7000 +F000 +FFE0 +FFE0 +ENDCHAR + +STARTCHAR braceleft +ENCODING 123 +SWIDTH 389 0 +DWIDTH 10 0 +BBX 7 24 1 -5 +BITMAP +0E +1C +38 +38 +38 +38 +38 +38 +38 +38 +70 +E0 +E0 +70 +38 +38 +38 +38 +38 +38 +38 +38 +1C +0E +ENDCHAR + +STARTCHAR bar +ENCODING 124 +SWIDTH 280 0 +DWIDTH 7 0 +BBX 3 24 2 -5 +BITMAP +E0 +E0 +E0 +E0 +E0 +E0 +E0 +E0 +E0 +E0 +E0 +E0 +E0 +E0 +E0 +E0 +E0 +E0 +E0 +E0 +E0 +E0 +E0 +E0 +ENDCHAR + +STARTCHAR braceright +ENCODING 125 +SWIDTH 389 0 +DWIDTH 10 0 +BBX 7 24 2 -5 +BITMAP +E0 +70 +38 +38 +38 +38 +38 +38 +38 +38 +1C +0E +0E +1C +38 +38 +38 +38 +38 +38 +38 +38 +70 +E0 +ENDCHAR + +STARTCHAR asciitilde +ENCODING 126 +SWIDTH 584 0 +DWIDTH 14 0 +BBX 11 4 1 5 +BITMAP +78E0 +FEE0 +EFE0 +E3C0 +ENDCHAR + +STARTCHAR space +ENCODING 160 +SWIDTH 278 0 +DWIDTH 6 0 +BBX 1 1 0 0 +BITMAP +00 +ENDCHAR + +STARTCHAR exclamdown +ENCODING 161 +SWIDTH 333 0 +DWIDTH 7 0 +BBX 3 19 2 -5 +BITMAP +E0 +E0 +E0 +00 +00 +E0 +E0 +E0 +E0 +E0 +E0 +E0 +E0 +E0 +E0 +E0 +E0 +E0 +E0 +ENDCHAR + +STARTCHAR cent +ENCODING 162 +SWIDTH 556 0 +DWIDTH 14 0 +BBX 11 18 1 -2 +BITMAP +0180 +0180 +1F80 +3FC0 +7BE0 +7360 +E300 +E600 +E600 +E600 +E600 +EC00 +ECE0 +7DE0 +7FC0 +3F80 +1800 +1800 +ENDCHAR + +STARTCHAR sterling +ENCODING 163 +SWIDTH 556 0 +DWIDTH 14 0 +BBX 13 18 0 0 +BITMAP +1F80 +3FC0 +70E0 +70E0 +7000 +7800 +3800 +1C00 +FFC0 +FFC0 +1C00 +1C00 +1C00 +3800 +3800 +7738 +FFF8 +F9F0 +ENDCHAR + +STARTCHAR currency +ENCODING 164 +SWIDTH 556 0 +DWIDTH 14 0 +BBX 12 12 1 3 +BITMAP +C030 +EF70 +7FE0 +39C0 +70E0 +70E0 +70E0 +70E0 +39C0 +7FE0 +EF70 +C030 +ENDCHAR + +STARTCHAR yen +ENCODING 165 +SWIDTH 556 0 +DWIDTH 14 0 +BBX 13 18 0 0 +BITMAP +E038 +E038 +7070 +7070 +38E0 +38E0 +1DC0 +1DC0 +7FF0 +7FF0 +0700 +7FF0 +7FF0 +0700 +0700 +0700 +0700 +0700 +ENDCHAR + +STARTCHAR brokenbar +ENCODING 166 +SWIDTH 280 0 +DWIDTH 7 0 +BBX 3 23 2 -4 +BITMAP +E0 +E0 +E0 +E0 +E0 +E0 +E0 +E0 +E0 +00 +00 +00 +00 +00 +E0 +E0 +E0 +E0 +E0 +E0 +E0 +E0 +E0 +ENDCHAR + +STARTCHAR section +ENCODING 167 +SWIDTH 556 0 +DWIDTH 14 0 +BBX 12 24 1 -5 +BITMAP +1F80 +3FC0 +79E0 +70E0 +78E0 +3C00 +1E00 +7F00 +F780 +E3C0 +E1E0 +E0E0 +7070 +7870 +3C70 +1EE0 +0FC0 +0780 +03C0 +71E0 +70E0 +79E0 +3FC0 +1F80 +ENDCHAR + +STARTCHAR dieresis +ENCODING 168 +SWIDTH 333 0 +DWIDTH 9 0 +BBX 7 2 1 16 +BITMAP +EE +EE +ENDCHAR + +STARTCHAR copyright +ENCODING 169 +SWIDTH 737 0 +DWIDTH 19 0 +BBX 17 17 1 0 +BITMAP +07F000 +1E3C00 +380E00 +700700 +63E300 +E73380 +CE3180 +CE0180 +CE0180 +CE0180 +CE3180 +E73180 +63E300 +700700 +380E00 +1E3C00 +07F000 +ENDCHAR + +STARTCHAR ordfeminine +ENCODING 170 +SWIDTH 370 0 +DWIDTH 10 0 +BBX 8 12 1 7 +BITMAP +7C +FE +C6 +1E +7E +E6 +C6 +FF +7B +00 +FF +FF +ENDCHAR + +STARTCHAR guillemotleft +ENCODING 171 +SWIDTH 556 0 +DWIDTH 13 0 +BBX 10 8 1 3 +BITMAP +1DC0 +3B80 +7700 +EE00 +EE00 +7700 +3B80 +1DC0 +ENDCHAR + +STARTCHAR logicalnot +ENCODING 172 +SWIDTH 584 0 +DWIDTH 15 0 +BBX 12 7 1 4 +BITMAP +FFF0 +FFF0 +0030 +0030 +0030 +0030 +0030 +ENDCHAR + +STARTCHAR hyphen +ENCODING 173 +SWIDTH 333 0 +DWIDTH 8 0 +BBX 7 3 0 6 +BITMAP +FE +FE +FE +ENDCHAR + +STARTCHAR registered +ENCODING 174 +SWIDTH 737 0 +DWIDTH 19 0 +BBX 17 17 1 0 +BITMAP +07F000 +1E3C00 +380E00 +700700 +67E300 +E63380 +C63180 +C63180 +C7E180 +C6C180 +C66180 +E63180 +661B00 +700700 +380E00 +1E3C00 +07F000 +ENDCHAR + +STARTCHAR macron +ENCODING 175 +SWIDTH 333 0 +DWIDTH 9 0 +BBX 7 2 1 17 +BITMAP +FE +FE +ENDCHAR + +STARTCHAR degree +ENCODING 176 +SWIDTH 400 0 +DWIDTH 9 0 +BBX 8 7 0 11 +BITMAP +3C +66 +C3 +C3 +C3 +66 +3C +ENDCHAR + +STARTCHAR plusminus +ENCODING 177 +SWIDTH 584 0 +DWIDTH 15 0 +BBX 11 13 2 0 +BITMAP +0E00 +0E00 +0E00 +0E00 +FFE0 +FFE0 +0E00 +0E00 +0E00 +0E00 +0000 +FFE0 +FFE0 +ENDCHAR + +STARTCHAR twosuperior +ENCODING 178 +SWIDTH 333 0 +DWIDTH 7 0 +BBX 6 10 0 8 +BITMAP +78 +FC +CC +0C +1C +78 +E0 +C0 +FC +FC +ENDCHAR + +STARTCHAR threesuperior +ENCODING 179 +SWIDTH 333 0 +DWIDTH 7 0 +BBX 6 10 0 8 +BITMAP +78 +FC +CC +0C +38 +38 +0C +CC +FC +78 +ENDCHAR + +STARTCHAR acute +ENCODING 180 +SWIDTH 333 0 +DWIDTH 8 0 +BBX 6 4 1 15 +BITMAP +1C +38 +70 +E0 +ENDCHAR + +STARTCHAR mu +ENCODING 181 +SWIDTH 611 0 +DWIDTH 15 0 +BBX 11 19 2 -5 +BITMAP +E0E0 +E0E0 +E0E0 +E0E0 +E0E0 +E0E0 +E0E0 +E0E0 +E0E0 +E0E0 +E1E0 +F3E0 +FEE0 +ECE0 +E000 +E000 +E000 +E000 +E000 +ENDCHAR + +STARTCHAR paragraph +ENCODING 182 +SWIDTH 556 0 +DWIDTH 13 0 +BBX 11 24 1 -5 +BITMAP +0FE0 +3FE0 +7CC0 +7CC0 +FCC0 +FCC0 +FCC0 +FCC0 +FCC0 +7CC0 +7CC0 +3CC0 +1CC0 +0CC0 +0CC0 +0CC0 +0CC0 +0CC0 +0CC0 +0CC0 +0CC0 +0CC0 +0CC0 +0CC0 +ENDCHAR + +STARTCHAR periodcentered +ENCODING 183 +SWIDTH 278 0 +DWIDTH 7 0 +BBX 3 3 2 6 +BITMAP +E0 +E0 +E0 +ENDCHAR + +STARTCHAR cedilla +ENCODING 184 +SWIDTH 333 0 +DWIDTH 8 0 +BBX 6 6 1 -5 +BITMAP +70 +78 +1C +1C +FC +78 +ENDCHAR + +STARTCHAR onesuperior +ENCODING 185 +SWIDTH 333 0 +DWIDTH 7 0 +BBX 4 10 0 8 +BITMAP +30 +30 +F0 +F0 +30 +30 +30 +30 +30 +30 +ENDCHAR + +STARTCHAR ordmasculine +ENCODING 186 +SWIDTH 365 0 +DWIDTH 10 0 +BBX 8 12 1 7 +BITMAP +3C +7E +E7 +C3 +C3 +C3 +E7 +7E +3C +00 +FF +FF +ENDCHAR + +STARTCHAR guillemotright +ENCODING 187 +SWIDTH 556 0 +DWIDTH 13 0 +BBX 10 8 1 3 +BITMAP +EE00 +7700 +3B80 +1DC0 +1DC0 +3B80 +7700 +EE00 +ENDCHAR + +STARTCHAR onequarter +ENCODING 188 +SWIDTH 834 0 +DWIDTH 19 0 +BBX 17 18 1 0 +BITMAP +301800 +301800 +F03000 +F03000 +306000 +306000 +30C000 +30C000 +318600 +318E00 +031E00 +031E00 +063600 +066600 +0C7F80 +0C7F80 +180600 +180600 +ENDCHAR + +STARTCHAR onehalf +ENCODING 189 +SWIDTH 834 0 +DWIDTH 19 0 +BBX 16 18 1 0 +BITMAP +3018 +3018 +F030 +F030 +3060 +3060 +30C0 +30C0 +319E +31BF +0333 +0303 +0607 +061E +0C38 +0C30 +183F +183F +ENDCHAR + +STARTCHAR threequarters +ENCODING 190 +SWIDTH 834 0 +DWIDTH 19 0 +BBX 17 18 1 0 +BITMAP +781800 +FC1800 +CC3000 +0C3000 +386000 +386000 +0CC000 +CCC000 +FD8600 +798E00 +031E00 +031E00 +063600 +066600 +0C7F80 +0C7F80 +180600 +180600 +ENDCHAR + +STARTCHAR questiondown +ENCODING 191 +SWIDTH 611 0 +DWIDTH 15 0 +BBX 11 19 2 -5 +BITMAP +0E00 +0E00 +0E00 +0000 +0000 +0E00 +0E00 +0E00 +0E00 +1C00 +3C00 +7800 +7000 +F0E0 +E0E0 +E1E0 +F3C0 +7FC0 +3F00 +ENDCHAR + +STARTCHAR Agrave +ENCODING 192 +SWIDTH 722 0 +DWIDTH 18 0 +BBX 16 24 1 0 +BITMAP +0E00 +0700 +0380 +01C0 +0000 +03C0 +03C0 +07E0 +07E0 +0E60 +0E70 +0E70 +1C38 +1C38 +1C38 +381C +381C +3FFC +7FFE +700E +700E +E007 +E007 +E007 +ENDCHAR + +STARTCHAR Aacute +ENCODING 193 +SWIDTH 722 0 +DWIDTH 18 0 +BBX 16 24 1 0 +BITMAP +0038 +0070 +00E0 +01C0 +0000 +03C0 +03C0 +07E0 +07E0 +0E60 +0E70 +0E70 +1C38 +1C38 +1C38 +381C +381C +3FFC +7FFE +700E +700E +E007 +E007 +E007 +ENDCHAR + +STARTCHAR Acircumflex +ENCODING 194 +SWIDTH 722 0 +DWIDTH 18 0 +BBX 16 24 1 0 +BITMAP +01C0 +03E0 +0770 +0E38 +0000 +03C0 +03C0 +07E0 +07E0 +0E60 +0E70 +0E70 +1C38 +1C38 +1C38 +381C +381C +3FFC +7FFE +700E +700E +E007 +E007 +E007 +ENDCHAR + +STARTCHAR Atilde +ENCODING 195 +SWIDTH 722 0 +DWIDTH 18 0 +BBX 16 23 1 0 +BITMAP +0798 +0FF8 +0CF0 +0000 +03C0 +03C0 +07E0 +07E0 +0E60 +0E70 +0E70 +1C38 +1C38 +1C38 +381C +381C +3FFC +7FFE +700E +700E +E007 +E007 +E007 +ENDCHAR + +STARTCHAR Adieresis +ENCODING 196 +SWIDTH 722 0 +DWIDTH 18 0 +BBX 16 23 1 0 +BITMAP +0E70 +0E70 +0000 +0000 +03C0 +03C0 +07E0 +07E0 +0E60 +0E70 +0E70 +1C38 +1C38 +1C38 +381C +381C +3FFC +7FFE +700E +700E +E007 +E007 +E007 +ENDCHAR + +STARTCHAR Aring +ENCODING 197 +SWIDTH 722 0 +DWIDTH 18 0 +BBX 16 23 1 0 +BITMAP +03C0 +0660 +0660 +0660 +03C0 +03C0 +07E0 +07E0 +0E60 +0E70 +0E70 +1C38 +1C38 +1C38 +381C +381C +3FFC +7FFE +700E +700E +E007 +E007 +E007 +ENDCHAR + +STARTCHAR AE +ENCODING 198 +SWIDTH 1000 0 +DWIDTH 24 0 +BBX 22 19 1 0 +BITMAP +03FFF8 +03FFF8 +07F000 +067000 +0E7000 +0E7000 +0E7000 +1C7000 +1C7FF0 +1C7FF0 +387000 +387000 +3FF000 +7FF000 +707000 +707000 +E07000 +E07FFC +E07FFC +ENDCHAR + +STARTCHAR Ccedilla +ENCODING 199 +SWIDTH 722 0 +DWIDTH 18 0 +BBX 16 24 1 -5 +BITMAP +07F0 +1FFC +3E3E +780F +7007 +F000 +E000 +E000 +E000 +E000 +E000 +E000 +E000 +F007 +7007 +780F +3E3E +1FFC +07F0 +03C0 +00E0 +00E0 +07E0 +03C0 +ENDCHAR + +STARTCHAR Egrave +ENCODING 200 +SWIDTH 667 0 +DWIDTH 16 0 +BBX 13 24 2 0 +BITMAP +7000 +3800 +1C00 +0E00 +0000 +FFF0 +FFF0 +E000 +E000 +E000 +E000 +E000 +E000 +FFE0 +FFE0 +E000 +E000 +E000 +E000 +E000 +E000 +E000 +FFF8 +FFF8 +ENDCHAR + +STARTCHAR Eacute +ENCODING 201 +SWIDTH 667 0 +DWIDTH 16 0 +BBX 13 24 2 0 +BITMAP +00E0 +01C0 +0380 +0700 +0000 +FFF0 +FFF0 +E000 +E000 +E000 +E000 +E000 +E000 +FFE0 +FFE0 +E000 +E000 +E000 +E000 +E000 +E000 +E000 +FFF8 +FFF8 +ENDCHAR + +STARTCHAR Ecircumflex +ENCODING 202 +SWIDTH 667 0 +DWIDTH 16 0 +BBX 13 24 2 0 +BITMAP +0700 +0F80 +1DC0 +38E0 +0000 +FFF0 +FFF0 +E000 +E000 +E000 +E000 +E000 +E000 +FFE0 +FFE0 +E000 +E000 +E000 +E000 +E000 +E000 +E000 +FFF8 +FFF8 +ENDCHAR + +STARTCHAR Edieresis +ENCODING 203 +SWIDTH 667 0 +DWIDTH 16 0 +BBX 13 23 2 0 +BITMAP +39C0 +39C0 +0000 +0000 +FFF0 +FFF0 +E000 +E000 +E000 +E000 +E000 +E000 +FFE0 +FFE0 +E000 +E000 +E000 +E000 +E000 +E000 +E000 +FFF8 +FFF8 +ENDCHAR + +STARTCHAR Igrave +ENCODING 204 +SWIDTH 278 0 +DWIDTH 7 0 +BBX 6 24 0 0 +BITMAP +E0 +70 +38 +1C +00 +38 +38 +38 +38 +38 +38 +38 +38 +38 +38 +38 +38 +38 +38 +38 +38 +38 +38 +38 +ENDCHAR + +STARTCHAR Iacute +ENCODING 205 +SWIDTH 278 0 +DWIDTH 7 0 +BBX 6 24 2 0 +BITMAP +1C +38 +70 +E0 +00 +E0 +E0 +E0 +E0 +E0 +E0 +E0 +E0 +E0 +E0 +E0 +E0 +E0 +E0 +E0 +E0 +E0 +E0 +E0 +ENDCHAR + +STARTCHAR Icircumflex +ENCODING 206 +SWIDTH 278 0 +DWIDTH 7 0 +BBX 9 24 -1 0 +BITMAP +1C00 +3E00 +7700 +E380 +0000 +1C00 +1C00 +1C00 +1C00 +1C00 +1C00 +1C00 +1C00 +1C00 +1C00 +1C00 +1C00 +1C00 +1C00 +1C00 +1C00 +1C00 +1C00 +1C00 +ENDCHAR + +STARTCHAR Idieresis +ENCODING 207 +SWIDTH 278 0 +DWIDTH 7 0 +BBX 7 23 0 0 +BITMAP +EE +EE +00 +00 +38 +38 +38 +38 +38 +38 +38 +38 +38 +38 +38 +38 +38 +38 +38 +38 +38 +38 +38 +ENDCHAR + +STARTCHAR Eth +ENCODING 208 +SWIDTH 722 0 +DWIDTH 19 0 +BBX 19 19 -1 0 +BITMAP +1FFC00 +1FFF00 +1C0F80 +1C03C0 +1C01C0 +1C01E0 +1C00E0 +1C00E0 +FFC0E0 +FFC0E0 +1C00E0 +1C00E0 +1C00E0 +1C01E0 +1C01C0 +1C03C0 +1C0F80 +1FFF00 +1FFC00 +ENDCHAR + +STARTCHAR Ntilde +ENCODING 209 +SWIDTH 722 0 +DWIDTH 19 0 +BBX 15 23 2 0 +BITMAP +0E30 +1FF0 +19E0 +0000 +E00E +F00E +F00E +F80E +F80E +FC0E +EE0E +EE0E +E70E +E38E +E38E +E1CE +E0CE +E0EE +E07E +E03E +E03E +E01E +E00E +ENDCHAR + +STARTCHAR Ograve +ENCODING 210 +SWIDTH 778 0 +DWIDTH 19 0 +BBX 17 24 1 0 +BITMAP +070000 +038000 +01C000 +00E000 +000000 +07F000 +1FFC00 +3E3E00 +780F00 +700700 +F00780 +E00380 +E00380 +E00380 +E00380 +E00380 +E00380 +E00380 +F00780 +700700 +780F00 +3E3E00 +1FFC00 +07F000 +ENDCHAR + +STARTCHAR Oacute +ENCODING 211 +SWIDTH 778 0 +DWIDTH 19 0 +BBX 17 24 1 0 +BITMAP +003800 +007000 +00E000 +01C000 +000000 +07F000 +1FFC00 +3E3E00 +780F00 +700700 +F00780 +E00380 +E00380 +E00380 +E00380 +E00380 +E00380 +E00380 +F00780 +700700 +780F00 +3E3E00 +1FFC00 +07F000 +ENDCHAR + +STARTCHAR Ocircumflex +ENCODING 212 +SWIDTH 778 0 +DWIDTH 19 0 +BBX 17 24 1 0 +BITMAP +01C000 +03E000 +077000 +0E3800 +000000 +07F000 +1FFC00 +3E3E00 +780F00 +700700 +F00780 +E00380 +E00380 +E00380 +E00380 +E00380 +E00380 +E00380 +F00780 +700700 +780F00 +3E3E00 +1FFC00 +07F000 +ENDCHAR + +STARTCHAR Otilde +ENCODING 213 +SWIDTH 778 0 +DWIDTH 19 0 +BBX 17 24 1 0 +BITMAP +079800 +0FF800 +0CF000 +000000 +000000 +07F000 +1FFC00 +3E3E00 +780F00 +700700 +F00780 +E00380 +E00380 +E00380 +E00380 +E00380 +E00380 +E00380 +F00780 +700700 +780F00 +3E3E00 +1FFC00 +07F000 +ENDCHAR + +STARTCHAR Odieresis +ENCODING 214 +SWIDTH 778 0 +DWIDTH 19 0 +BBX 17 23 1 0 +BITMAP +0E3800 +0E3800 +000000 +000000 +07F000 +1FFC00 +3E3E00 +780F00 +700700 +F00780 +E00380 +E00380 +E00380 +E00380 +E00380 +E00380 +E00380 +F00780 +700700 +780F00 +3E3E00 +1FFC00 +07F000 +ENDCHAR + +STARTCHAR multiply +ENCODING 215 +SWIDTH 584 0 +DWIDTH 15 0 +BBX 12 12 1 1 +BITMAP +4020 +E070 +70E0 +39C0 +1F80 +0F00 +0F00 +1F80 +39C0 +70E0 +E070 +4020 +ENDCHAR + +STARTCHAR Oslash +ENCODING 216 +SWIDTH 778 0 +DWIDTH 19 0 +BBX 19 19 0 0 +BITMAP +03F860 +0FFEE0 +1F1FC0 +3C0380 +380780 +780FC0 +701DC0 +7039C0 +7071C0 +70E1C0 +71C1C0 +7381C0 +7701C0 +7E03C0 +3C0380 +3C0780 +7F1F00 +EFFE00 +C3F800 +ENDCHAR + +STARTCHAR Ugrave +ENCODING 217 +SWIDTH 722 0 +DWIDTH 19 0 +BBX 15 24 2 0 +BITMAP +0E00 +0700 +0380 +01C0 +0000 +E00E +E00E +E00E +E00E +E00E +E00E +E00E +E00E +E00E +E00E +E00E +E00E +E00E +F01E +F01E +701C +7C7C +3FF8 +0FE0 +ENDCHAR + +STARTCHAR Uacute +ENCODING 218 +SWIDTH 722 0 +DWIDTH 19 0 +BBX 15 24 2 0 +BITMAP +0070 +00E0 +01C0 +0380 +0000 +E00E +E00E +E00E +E00E +E00E +E00E +E00E +E00E +E00E +E00E +E00E +E00E +E00E +F01E +F01E +701C +7C7C +3FF8 +0FE0 +ENDCHAR + +STARTCHAR Ucircumflex +ENCODING 219 +SWIDTH 722 0 +DWIDTH 19 0 +BBX 15 24 2 0 +BITMAP +0780 +0FC0 +1CE0 +3870 +0000 +E00E +E00E +E00E +E00E +E00E +E00E +E00E +E00E +E00E +E00E +E00E +E00E +E00E +F01E +F01E +701C +7C7C +3FF8 +0FE0 +ENDCHAR + +STARTCHAR Udieresis +ENCODING 220 +SWIDTH 722 0 +DWIDTH 19 0 +BBX 15 23 2 0 +BITMAP +1C70 +1C70 +0000 +0000 +E00E +E00E +E00E +E00E +E00E +E00E +E00E +E00E +E00E +E00E +E00E +E00E +E00E +F01E +F01E +701C +7C7C +3FF8 +0FE0 +ENDCHAR + +STARTCHAR Yacute +ENCODING 221 +SWIDTH 667 0 +DWIDTH 17 0 +BBX 15 24 1 0 +BITMAP +0070 +00E0 +01C0 +0380 +0000 +F01E +701C +783C +3838 +3C78 +1C70 +1EF0 +0EE0 +0FE0 +07C0 +07C0 +0380 +0380 +0380 +0380 +0380 +0380 +0380 +0380 +ENDCHAR + +STARTCHAR Thorn +ENCODING 222 +SWIDTH 667 0 +DWIDTH 17 0 +BBX 14 19 2 0 +BITMAP +E000 +E000 +E000 +E000 +FFE0 +FFF8 +E038 +E01C +E01C +E01C +E01C +E038 +FFF8 +FFF0 +E000 +E000 +E000 +E000 +E000 +ENDCHAR + +STARTCHAR germandbls +ENCODING 223 +SWIDTH 611 0 +DWIDTH 14 0 +BBX 11 19 2 0 +BITMAP +1E00 +7F80 +F380 +E1C0 +E1C0 +E1C0 +E1C0 +E380 +EF00 +EF80 +E3C0 +E1C0 +E0E0 +E0E0 +E0E0 +E0E0 +E1C0 +EFC0 +EF80 +ENDCHAR + +STARTCHAR agrave +ENCODING 224 +SWIDTH 556 0 +DWIDTH 14 0 +BBX 12 19 1 0 +BITMAP +1C00 +0E00 +0700 +0380 +0000 +1F80 +3FC0 +71E0 +70E0 +00E0 +07E0 +3FE0 +7CE0 +F0E0 +E0E0 +E1E0 +F3E0 +7FF0 +3E70 +ENDCHAR + +STARTCHAR aacute +ENCODING 225 +SWIDTH 556 0 +DWIDTH 14 0 +BBX 12 19 1 0 +BITMAP +01C0 +0380 +0700 +0E00 +0000 +1F80 +3FC0 +71E0 +70E0 +00E0 +07E0 +3FE0 +7CE0 +F0E0 +E0E0 +E1E0 +F3E0 +7FF0 +3E70 +ENDCHAR + +STARTCHAR acircumflex +ENCODING 226 +SWIDTH 556 0 +DWIDTH 14 0 +BBX 12 19 1 0 +BITMAP +0700 +0F80 +1DC0 +38E0 +0000 +1F80 +3FC0 +71E0 +70E0 +00E0 +07E0 +3FE0 +7CE0 +F0E0 +E0E0 +E1E0 +F3E0 +7FF0 +3E70 +ENDCHAR + +STARTCHAR atilde +ENCODING 227 +SWIDTH 556 0 +DWIDTH 14 0 +BBX 12 19 1 0 +BITMAP +1E60 +3FE0 +33C0 +0000 +0000 +1F80 +3FC0 +71E0 +70E0 +00E0 +07E0 +3FE0 +7CE0 +F0E0 +E0E0 +E1E0 +F3E0 +7FF0 +3E70 +ENDCHAR + +STARTCHAR adieresis +ENCODING 228 +SWIDTH 556 0 +DWIDTH 14 0 +BBX 12 18 1 0 +BITMAP +1DC0 +1DC0 +0000 +0000 +1F80 +3FC0 +71E0 +70E0 +00E0 +07E0 +3FE0 +7CE0 +F0E0 +E0E0 +E1E0 +F3E0 +7FF0 +3E70 +ENDCHAR + +STARTCHAR aring +ENCODING 229 +SWIDTH 556 0 +DWIDTH 14 0 +BBX 12 19 1 0 +BITMAP +0F00 +1980 +1980 +1980 +0F00 +1F80 +3FC0 +71E0 +70E0 +00E0 +07E0 +3FE0 +7CE0 +F0E0 +E0E0 +E1E0 +F3E0 +7FF0 +3E70 +ENDCHAR + +STARTCHAR ae +ENCODING 230 +SWIDTH 889 0 +DWIDTH 22 0 +BBX 20 14 1 0 +BITMAP +1F8F00 +3FFFC0 +71F9E0 +70F0E0 +00E070 +07E070 +3FFFF0 +7CFFF0 +F0E000 +E0E000 +E1F070 +F3F8F0 +7F3FE0 +3E0F80 +ENDCHAR + +STARTCHAR ccedilla +ENCODING 231 +SWIDTH 556 0 +DWIDTH 13 0 +BBX 11 19 1 -5 +BITMAP +1F80 +3FC0 +79E0 +70E0 +E000 +E000 +E000 +E000 +E000 +E000 +70E0 +79E0 +3FC0 +1F80 +1E00 +0700 +0700 +3F00 +1E00 +ENDCHAR + +STARTCHAR egrave +ENCODING 232 +SWIDTH 556 0 +DWIDTH 14 0 +BBX 12 19 1 0 +BITMAP +1C00 +0E00 +0700 +0380 +0000 +0F00 +3FC0 +79E0 +70E0 +E070 +E070 +FFF0 +FFF0 +E000 +E000 +7070 +78F0 +3FE0 +0F80 +ENDCHAR + +STARTCHAR eacute +ENCODING 233 +SWIDTH 556 0 +DWIDTH 14 0 +BBX 12 19 1 0 +BITMAP +01C0 +0380 +0700 +0E00 +0000 +0F00 +3FC0 +79E0 +70E0 +E070 +E070 +FFF0 +FFF0 +E000 +E000 +7070 +78F0 +3FE0 +0F80 +ENDCHAR + +STARTCHAR ecircumflex +ENCODING 234 +SWIDTH 556 0 +DWIDTH 14 0 +BBX 12 19 1 0 +BITMAP +0700 +0F80 +1DC0 +38E0 +0000 +0F00 +3FC0 +79E0 +70E0 +E070 +E070 +FFF0 +FFF0 +E000 +E000 +7070 +78F0 +3FE0 +0F80 +ENDCHAR + +STARTCHAR edieresis +ENCODING 235 +SWIDTH 556 0 +DWIDTH 14 0 +BBX 12 18 1 0 +BITMAP +39C0 +39C0 +0000 +0000 +0F00 +3FC0 +79E0 +70E0 +E070 +E070 +FFF0 +FFF0 +E000 +E000 +7070 +78F0 +3FE0 +0F80 +ENDCHAR + +STARTCHAR igrave +ENCODING 236 +SWIDTH 278 0 +DWIDTH 7 0 +BBX 6 19 1 0 +BITMAP +E0 +70 +38 +1C +00 +70 +70 +70 +70 +70 +70 +70 +70 +70 +70 +70 +70 +70 +70 +ENDCHAR + +STARTCHAR iacute +ENCODING 237 +SWIDTH 278 0 +DWIDTH 7 0 +BBX 6 19 1 0 +BITMAP +1C +38 +70 +E0 +00 +70 +70 +70 +70 +70 +70 +70 +70 +70 +70 +70 +70 +70 +70 +ENDCHAR + +STARTCHAR icircumflex +ENCODING 238 +SWIDTH 278 0 +DWIDTH 7 0 +BBX 9 19 -1 0 +BITMAP +1C00 +3E00 +7700 +E380 +0000 +1C00 +1C00 +1C00 +1C00 +1C00 +1C00 +1C00 +1C00 +1C00 +1C00 +1C00 +1C00 +1C00 +1C00 +ENDCHAR + +STARTCHAR idieresis +ENCODING 239 +SWIDTH 278 0 +DWIDTH 7 0 +BBX 7 18 0 0 +BITMAP +EE +EE +00 +00 +38 +38 +38 +38 +38 +38 +38 +38 +38 +38 +38 +38 +38 +38 +ENDCHAR + +STARTCHAR eth +ENCODING 240 +SWIDTH 611 0 +DWIDTH 14 0 +BBX 12 19 1 0 +BITMAP +E000 +39C0 +1F00 +3E00 +C300 +0F80 +3FC0 +79E0 +70E0 +E070 +E070 +E070 +E070 +E070 +E070 +70E0 +79E0 +3FC0 +0F00 +ENDCHAR + +STARTCHAR ntilde +ENCODING 241 +SWIDTH 611 0 +DWIDTH 15 0 +BBX 11 19 2 0 +BITMAP +3CC0 +7FC0 +6780 +0000 +0000 +EF80 +FFC0 +F1C0 +E0E0 +E0E0 +E0E0 +E0E0 +E0E0 +E0E0 +E0E0 +E0E0 +E0E0 +E0E0 +E0E0 +ENDCHAR + +STARTCHAR ograve +ENCODING 242 +SWIDTH 611 0 +DWIDTH 14 0 +BBX 12 19 1 0 +BITMAP +1C00 +0E00 +0700 +0380 +0000 +0F00 +3FC0 +79E0 +70E0 +E070 +E070 +E070 +E070 +E070 +E070 +70E0 +79E0 +3FC0 +0F00 +ENDCHAR + +STARTCHAR oacute +ENCODING 243 +SWIDTH 611 0 +DWIDTH 14 0 +BBX 12 19 1 0 +BITMAP +01C0 +0380 +0700 +0E00 +0000 +0F00 +3FC0 +79E0 +70E0 +E070 +E070 +E070 +E070 +E070 +E070 +70E0 +79E0 +3FC0 +0F00 +ENDCHAR + +STARTCHAR ocircumflex +ENCODING 244 +SWIDTH 611 0 +DWIDTH 14 0 +BBX 12 19 1 0 +BITMAP +0700 +0F80 +1DC0 +38E0 +0000 +0F00 +3FC0 +79E0 +70E0 +E070 +E070 +E070 +E070 +E070 +E070 +70E0 +79E0 +3FC0 +0F00 +ENDCHAR + +STARTCHAR otilde +ENCODING 245 +SWIDTH 611 0 +DWIDTH 14 0 +BBX 12 19 1 0 +BITMAP +1E60 +3FE0 +33C0 +0000 +0000 +0F00 +3FC0 +79E0 +70E0 +E070 +E070 +E070 +E070 +E070 +E070 +70E0 +79E0 +3FC0 +0F00 +ENDCHAR + +STARTCHAR odieresis +ENCODING 246 +SWIDTH 611 0 +DWIDTH 14 0 +BBX 12 18 1 0 +BITMAP +1DC0 +1DC0 +0000 +0000 +0F00 +3FC0 +79E0 +70E0 +E070 +E070 +E070 +E070 +E070 +E070 +70E0 +79E0 +3FC0 +0F00 +ENDCHAR + +STARTCHAR divide +ENCODING 247 +SWIDTH 584 0 +DWIDTH 15 0 +BBX 11 12 2 1 +BITMAP +0E00 +0E00 +0E00 +0000 +0000 +FFE0 +FFE0 +0000 +0000 +0E00 +0E00 +0E00 +ENDCHAR + +STARTCHAR oslash +ENCODING 248 +SWIDTH 611 0 +DWIDTH 14 0 +BBX 14 14 0 0 +BITMAP +078C +1FF8 +3CF0 +3870 +70F8 +71F8 +73B8 +7738 +7E38 +7C38 +3870 +7CF0 +DFE0 +8780 +ENDCHAR + +STARTCHAR ugrave +ENCODING 249 +SWIDTH 611 0 +DWIDTH 15 0 +BBX 11 19 2 0 +BITMAP +3800 +1C00 +0E00 +0700 +0000 +E0E0 +E0E0 +E0E0 +E0E0 +E0E0 +E0E0 +E0E0 +E0E0 +E0E0 +E0E0 +E1E0 +73E0 +7EE0 +1CE0 +ENDCHAR + +STARTCHAR uacute +ENCODING 250 +SWIDTH 611 0 +DWIDTH 15 0 +BBX 11 19 2 0 +BITMAP +0380 +0700 +0E00 +1C00 +0000 +E0E0 +E0E0 +E0E0 +E0E0 +E0E0 +E0E0 +E0E0 +E0E0 +E0E0 +E0E0 +E1E0 +73E0 +7EE0 +1CE0 +ENDCHAR + +STARTCHAR ucircumflex +ENCODING 251 +SWIDTH 611 0 +DWIDTH 15 0 +BBX 11 19 2 0 +BITMAP +0E00 +1F00 +3B80 +71C0 +0000 +E0E0 +E0E0 +E0E0 +E0E0 +E0E0 +E0E0 +E0E0 +E0E0 +E0E0 +E0E0 +E1E0 +73E0 +7EE0 +1CE0 +ENDCHAR + +STARTCHAR udieresis +ENCODING 252 +SWIDTH 611 0 +DWIDTH 15 0 +BBX 11 18 2 0 +BITMAP +3B80 +3B80 +0000 +0000 +E0E0 +E0E0 +E0E0 +E0E0 +E0E0 +E0E0 +E0E0 +E0E0 +E0E0 +E0E0 +E1E0 +73E0 +7EE0 +1CE0 +ENDCHAR + +STARTCHAR yacute +ENCODING 253 +SWIDTH 556 0 +DWIDTH 15 0 +BBX 13 24 1 -5 +BITMAP +00E0 +01C0 +0380 +0700 +0000 +E038 +E038 +7038 +7870 +3870 +3CF0 +1CE0 +1CE0 +0FC0 +0FC0 +07C0 +0780 +0380 +0380 +0700 +0700 +0E00 +3E00 +3C00 +ENDCHAR + +STARTCHAR thorn +ENCODING 254 +SWIDTH 611 0 +DWIDTH 15 0 +BBX 12 24 2 -5 +BITMAP +E000 +E000 +E000 +E000 +E000 +EF80 +FFC0 +F9E0 +F0E0 +E070 +E070 +E070 +E070 +E070 +E070 +F0E0 +F9E0 +FFC0 +EF80 +E000 +E000 +E000 +E000 +E000 +ENDCHAR + +STARTCHAR ydieresis +ENCODING 255 +SWIDTH 556 0 +DWIDTH 15 0 +BBX 13 23 1 -5 +BITMAP +1CE0 +1CE0 +0000 +0000 +E038 +E038 +7038 +7870 +3870 +3CF0 +1CE0 +1CE0 +0FC0 +0FC0 +07C0 +0780 +0380 +0380 +0700 +0700 +0E00 +3E00 +3C00 +ENDCHAR + +ENDFONT diff --git a/fonts/helvB24.cc b/fonts/helvB24.cc new file mode 100644 index 0000000000000000000000000000000000000000..8ed2c3b25df3ee83c4522a16483b36bf3f5c72a3 GIT binary patch literal 298697 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 zQ<~device = device; + return 1; +} + +int Led::shutdown() +{ + if (!initted) return 0; + initted = 0; + device = 0; + return 1; +} + +int Led::on() +{ + if (!initted) return 0; + + int result = ioctl(device, IR_SET_LED, 0); + if (result >= 0) return 1; + else return 0; +} + +int Led::off() +{ + if (!initted) return 0; + + int result = ioctl(device, IR_SET_LED, 1); + if (result >= 0) return 1; + else return 0; +} diff --git a/led.h b/led.h new file mode 100644 index 0000000..4b67e0b --- /dev/null +++ b/led.h @@ -0,0 +1,48 @@ +/* + Copyright 2004-2005 Chris Tallon + + This file is part of VOMP. + + VOMP 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. + + VOMP 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 VOMP; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#ifndef LED_H +#define LED_H + +#include +#include + +#include "stb.h" + +class Led +{ + public: + Led(); + ~Led(); + static Led* getInstance(); + + int init(int device); + int shutdown(); + + int on(); + int off(); + + private: + static Led* instance; + int initted; + int device; +}; + +#endif diff --git a/list.cc b/list.cc new file mode 100644 index 0000000..39a049d --- /dev/null +++ b/list.cc @@ -0,0 +1,170 @@ +/* + Copyright 2004-2005 Chris Tallon + + This file is part of VOMP. + + VOMP 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. + + VOMP 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 VOMP; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include "list.h" + +// ------ Constructor add delete get methods ------------------------------------- + +List::List(void) +{ + start = NULL; + current = NULL; + prev = NULL; + numElements = 0; +} + +List::~List() +{ + while (!isEmpty()) + { + reset(); + remove(); + } + numElements = 0; +} + +void List::add(void *newData) +{ + Node *temp = new Node(newData, current); + current = temp; + if (prev == 0) + start = current; + else + prev->setPtr(current); + ++numElements; +} + +void *List::getCurrent(void) const +{ + if (current == 0) return 0; + else return current->getData(); +} + +void *List::remove(void) +{ + if (current == 0) return 0; + Node *dN; + + if (prev == 0) + start = current->getPtr(); + else + prev->setPtr(current->getPtr()); + dN = current; + current = current->getPtr(); + + // saved a reference to the Node in dN and current points to where it should + // that's dN out of the list but it still needs to be deleted, and what it + // points to + + void *returnObject; + returnObject = dN->getData(); + delete dN; + --numElements; + return returnObject; +} + +void List::remove(void *removeThis) +{ + reset(); + while((!eol()) && (current->getData() != removeThis)) next(); + // Now use method above to actually remove the node and get the object + remove(); +} + +unsigned long int List::getNumElements() +{ + return numElements; +} + +// ------ Pointer shift methods ----------------------------------------------- + +void List::reset(void) +{ + current = start; + prev = 0; +} + +void List::next(void) +{ + if (current == 0) return; + prev = current; + current = current->getPtr(); +} + +// ------ Boolean methods ----------------------------------------------------- + +short List::isEmpty(void) const +{ + return (start == 0); +} + +short List::eol(void) const +{ + return (current == 0); +} + +// ------ Save / load methods method -------------------------------------------- + +void List::save(char *fileName, long int objectLength) +{ + FILE *f = fopen(fileName, "w"); + fwrite(&objectLength, sizeof(long int), 1, f); + + void *v; + reset(); + while(!eol()) + { + v = getCurrent(); + fwrite(v, objectLength, 1, f); + next(); + } + fclose(f); +} + +int List::load(char *fileName) +{ +int temp1 = 0; + + int readIn = 0; + long int objectLength = 0; + FILE *f = fopen(fileName, "r"); + if (!f) return readIn; + + if (fread(&objectLength, sizeof(long int), 1, f) != 1) + { + fclose(f); + return 0; + } + + void *temp = 0; + + while(1) + { + temp = malloc(objectLength); + if ((temp1=fread(temp, objectLength, 1, f)) < 1) break; + readIn++; + add(temp); + } + + // We allocated temp but then fread failed + free(temp); + fclose(f); + return readIn; +} diff --git a/list.h b/list.h new file mode 100644 index 0000000..e1a6451 --- /dev/null +++ b/list.h @@ -0,0 +1,66 @@ +/* + Copyright 2004-2005 Chris Tallon + + This file is part of VOMP. + + VOMP 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. + + VOMP 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 VOMP; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#ifndef LIST_H +#define LIST_H + +#include +#include +#include "node.h" + +class List +{ + public: + List(); + ~List(); + void add(void *); + void *getCurrent(void) const; + void *remove(void); // Removes node from current position from list + // and passes it back to be deleted + void remove(void *); // Removes node passed in from list, does not delete it + void reset(void); + void next(void); + short isEmpty(void) const; + short eol(void) const; + void save(char *, long int); + int load(char *); + unsigned long int getNumElements(); + + private: + Node *start; + Node *current; + Node *prev; + unsigned long int numElements; +}; + +/* The list class can not delete the object stored in the node object because + it does not know the length of it. All the node has is a void *. This is why + List always passes back the actual stored object to the calling method. +*/ + +/* Fixed memory hole, when delete List, it deletes any remaining Nodes but not + stored objects. That's just tuff. +*/ + +/* The new saving code will work as long as the objects don't contain any + pointers to other areas of memory. Only for use with self-contained objects! +*/ + +#endif diff --git a/log.cc b/log.cc new file mode 100644 index 0000000..6823f75 --- /dev/null +++ b/log.cc @@ -0,0 +1,149 @@ +/* + Copyright 2004-2005 Chris Tallon + Copyright 2003-2004 University Of Bradford + + This file is part of VOMP. + + VOMP 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. + + VOMP 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 VOMP; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include "log.h" + +Log* Log::instance = NULL; + +Log::Log() +{ + if (instance) return; + instance = this; + logfile = NULL; + initted = 0; + logLevel = 0; +} + +Log::~Log() +{ + instance = NULL; +} + +Log* Log::getInstance() +{ + return instance; +} + +void Log::upLogLevel() +{ + if (logLevel == Log::DEBUG) + { + log("Log", logLevel, "Log level is at its highest already"); + return; + } + + logLevel++; + log("Log", logLevel, "Log level is now %i", logLevel); +} + +void Log::downLogLevel() +{ + if (logLevel == Log::CRAZY) + { + log("Log", logLevel, "Log level is at its lowest already"); + return; + } + + logLevel--; + log("Log", logLevel, "Log level is now %i", logLevel); +} + +int Log::init(int startLogLevel, char* fileName, int tenabled) +{ + initted = 1; + logLevel = startLogLevel; + enabled = tenabled; +// logfile = fopen(fileName, "a"); +// logfile = fopen(stdout, "a"); + logfile = stdout; + if (logfile) return 1; + else return 0; +} + +int Log::shutdown() +{ + if (!initted) return 1; + if (logfile) fclose(logfile); + return 1; +} + +int Log::log(char *fromModule, int level, char* message, ...) +{ + if (!instance || !logfile) return 0; + + if (!enabled) return 1; + if (level > logLevel) return 1; + + char buffer[151]; + int spaceLeft = 150; + + struct timeval tv; + gettimeofday(&tv, NULL); + struct tm* tm = gmtime(&tv.tv_sec); + spaceLeft -= strftime(buffer, spaceLeft, "%H:%M:%S.", tm); + spaceLeft -= snprintf(&buffer[150-spaceLeft], spaceLeft, "%06lu ", (unsigned long)tv.tv_usec); + + + char levelString[10]; + if (level == CRAZY) strcpy(levelString, "[CRAZY] "); + if (level == EMERG) strcpy(levelString, "[EMERG] "); + if (level == ALERT) strcpy(levelString, "[ALERT] "); + if (level == CRIT) strcpy(levelString, "[CRIT] "); + if (level == ERR) strcpy(levelString, "[ERR] "); + if (level == WARN) strcpy(levelString, "[WARN] "); + if (level == NOTICE) strcpy(levelString, "[notice]"); + if (level == INFO) strcpy(levelString, "[info] "); + if (level == DEBUG) strcpy(levelString, "[debug] "); + + spaceLeft -= snprintf(&buffer[150-spaceLeft], spaceLeft, "%s %s - ", levelString, fromModule); + + va_list ap; + va_start(ap, message); + spaceLeft = vsnprintf(&buffer[150-spaceLeft], spaceLeft, message, ap); + va_end(ap); + + int messageLength = strlen(buffer); + if (messageLength < 150) + { + buffer[messageLength] = '\n'; + buffer[messageLength+1] = '\0'; + } + else + { + buffer[149] = '\n'; + buffer[150] = '\0'; + } + + int success = fputs(buffer, logfile); + fflush(NULL); + + if (success != EOF) + return 1; + else + return 0; + +} + +int Log::status() +{ + if (instance && logfile) return 1; + else return 0; +} diff --git a/log.h b/log.h new file mode 100644 index 0000000..bf45f42 --- /dev/null +++ b/log.h @@ -0,0 +1,89 @@ +/* + Copyright 2004-2005 Chris Tallon + Copyright 2003-2004 University Of Bradford + + This file is part of VOMP. + + VOMP 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. + + VOMP 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 VOMP; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#ifndef LOG_H +#define LOG_H + +#include +#include +#include +#include +#include + +class Log +{ + public: + Log(); + ~Log(); + static Log* getInstance(); + + int init(int defaultLevel, char* fileName, int enabled); + int shutdown(); + int log(char *fromModule, int level, char *message, ...); + int status(); + void upLogLevel(); + void downLogLevel(); + + const static int CRAZY = 0; // mad crazy things that should never happen + const static int EMERG = 1; // human assist required NOW + const static int ALERT = 2; // system unusable, but happy to sit there + const static int CRIT = 3; // still working, but maybe about to die + const static int ERR = 4; // that response is not even listed... + const static int WARN = 5; // this could be a bad thing. still running tho + const static int NOTICE = 6; // significant good thing + const static int INFO = 7; // verbose good thing + const static int DEBUG = 8; // debug-level messages + + private: + static Log* instance; + int initted; + int logLevel; + int enabled; + + FILE *logfile; +}; + +#endif + +/* + +Documentation +------------- + +This class is intended to be instatiated once by the core. +For a one off use: + +Log::getInstance()->log("", Log::, ""); + +Or, a pointer can be stored and used: + +Log *myptr = Log::getInstance(); + +myptr->log("", Log::, ""); +myptr->log("", Log::, ""); + +Level usages are above. + +The message parameter in the log function can be used in the same way as printf, eg. + +myptr->log("", Log::, "Success: %s %i", stringpointer, integer); + +*/ diff --git a/main.cc b/main.cc new file mode 100644 index 0000000..92e53d1 --- /dev/null +++ b/main.cc @@ -0,0 +1,399 @@ +/* + Copyright 2004-2005 Chris Tallon + + This file is part of VOMP. + + VOMP 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. + + VOMP 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 VOMP; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif + +#include +#include +#include +#include +#include +#include + +#include "defines.h" +#include "log.h" +#include "remote.h" +#include "led.h" +#include "mtd.h" +#include "video.h" +#include "audio.h" +#include "vdr.h" +#include "osd.h" +#include "viewman.h" +#include "command.h" + +void sighandler(int signal); +void shutdown(int code); + +// Global variables -------------------------------------------------------------------------------------------------- +int debugEnabled = 0; +Log* logger; +Remote* remote; +Mtd* mtd; +Led* led; +Osd* osd; +ViewMan* viewman; +Command* command; +VDR* vdr; +Video* video; +Audio* audio; + +int main(int argc, char** argv) +{ + if ((argc > 1) && (!strcmp(argv[1], "-d"))) debugEnabled = 1; + + + // Init global vars ------------------------------------------------------------------------------------------------ + + logger = new Log(); + remote = new Remote(); + mtd = new Mtd(); + led = new Led(); + osd = new Osd(); + vdr = new VDR(); + video = new Video(); + audio = new Audio(); + viewman = new ViewMan(); + command = new Command(); + + if (!logger || !remote || !mtd || !led || !osd || !video || !audio || !viewman || !command) + { + printf("Could not create objects. Memory problems?\n"); + shutdown(1); + } + + // Get logging module started -------------------------------------------------------------------------------------- + + if (!logger->init(Log::DEBUG, "dummy", debugEnabled)) + { + printf("Could not initialise log object. Aborting.\n"); + shutdown(1); + } + + logger->log("Core", Log::INFO, "Starting up..."); + + // Set up signal handling ------------------------------------------------------------------------------------------ + + sighandler_t sigtest; + + sigtest = signal(SIGPIPE, SIG_IGN); + if (sigtest == SIG_ERR) + { + logger->log("Core", Log::EMERG, "Could not set up signal handler for SIGPIPE. Aborting."); + shutdown(1); + } + sigtest = signal(SIGINT, sighandler); + if (sigtest == SIG_ERR) + { + logger->log("Core", Log::EMERG, "Could not set up signal handler for SIGINT. Aborting."); + shutdown(1); + } + sigtest = signal(SIGTERM, sighandler); + if (sigtest == SIG_ERR) + { + logger->log("Core", Log::EMERG, "Could not set up signal handler for SIGTERM. Aborting."); + shutdown(1); + } + sigtest = signal(SIGUSR1, sighandler); + if (sigtest == SIG_ERR) + { + logger->log("Core", Log::EMERG, "Could not set up signal handler for SIGUSR1. Aborting."); + shutdown(1); + } + sigtest = signal(SIGUSR2, sighandler); + if (sigtest == SIG_ERR) + { + logger->log("Core", Log::EMERG, "Could not set up signal handler for SIGUSR2. Aborting."); + shutdown(1); + } + sigtest = signal(SIGURG, sighandler); + if (sigtest == SIG_ERR) + { + logger->log("Core", Log::EMERG, "Could not set up signal handler for SIGURG. Aborting."); + shutdown(1); + } + + logger->log("Core", Log::INFO, "Signal handlers set up successfully"); + + + // Init modules ---------------------------------------------------------------------------------------------------- + int success; + + success = remote->init("/dev/rawir"); + if (success) + { + logger->log("Core", Log::INFO, "Remote module initialised"); + } + else + { + logger->log("Core", Log::EMERG, "Remote module failed to initialise"); + shutdown(1); + } + + success = led->init(remote->getDevice()); + if (success) + { + logger->log("Core", Log::INFO, "LED module initialised"); + } + else + { + logger->log("Core", Log::EMERG, "LED module failed to initialise"); + shutdown(1); + } + + success = mtd->init("/dev/mtd1"); + if (success) + { + logger->log("Core", Log::INFO, "Mtd module initialised"); + } + else + { + logger->log("Core", Log::EMERG, "Mtd module failed to initialise"); + shutdown(1); + } + + success = osd->init("/dev/stbgfx", SCREENHEIGHT, SCREENWIDTH, 1); + if (success) + { + logger->log("Core", Log::INFO, "OSD module initialised"); + } + else + { + logger->log("Core", Log::EMERG, "OSD module failed to initialise"); + shutdown(1); + } + + success = vdr->init(3024); + if (success) + { + logger->log("Core", Log::INFO, "VDR module initialised"); + } + else + { + logger->log("Core", Log::EMERG, "VDR module failed to initialise"); + shutdown(1); + } + + success = video->init(Video::PAL, Video::SCART, Video::ASPECT4X3, Video::NORMAL); + if (success) + { + logger->log("Core", Log::INFO, "Video module initialised"); + } + else + { + logger->log("Core", Log::EMERG, "Video module failed to initialise"); + shutdown(1); + } + + success = audio->init(Audio::MPEG2_PES); + if (success) + { + logger->log("Core", Log::INFO, "Audio module initialised"); + } + else + { + logger->log("Core", Log::EMERG, "Audio module failed to initialise"); + shutdown(1); + } + + success = viewman->init(); + if (success) + { + logger->log("Core", Log::INFO, "ViewMan module initialised"); + } + else + { + logger->log("Core", Log::EMERG, "ViewMan module failed to initialise"); + shutdown(1); + } + + success = command->init(); + if (success) + { + logger->log("Core", Log::INFO, "Command module initialised"); + } + else + { + logger->log("Core", Log::EMERG, "Command module failed to initialise"); + shutdown(1); + } + + // Other init ------------------------------------------------------------------------------------------------------ + + logger->log("Core", Log::NOTICE, "Startup successful"); + + // Run main loop --------------------------------------------------------------------------------------------------- + + // Ok, all major device components and other bits are loaded and ready + command->run(); + + // When that returns quit ------------------------------------------------------------------------------------------ + + shutdown(0); + return 0; +} + +// ------------------------------------------------------------------------------------------------------------------- + +void shutdown(int code) +{ + if (command) + { + command->shutdown(); + delete command; + logger->log("Core", Log::NOTICE, "Command module shut down"); + } + + if (viewman) + { + viewman->shutdown(); + delete viewman; + logger->log("Core", Log::NOTICE, "ViewMan module shut down"); + } + + if (audio) + { + audio->shutdown(); + delete audio; + logger->log("Core", Log::NOTICE, "Audio module shut down"); + } + + if (video) + { + video->shutdown(); + delete video; + logger->log("Core", Log::NOTICE, "Video module shut down"); + } + + if (vdr) + { + vdr->shutdown(); + delete vdr; + logger->log("Core", Log::NOTICE, "VDR module shut down"); + } + + if (osd) + { + osd->shutdown(); + delete osd; + logger->log("Core", Log::NOTICE, "OSD module shut down"); + } + + if (mtd) + { + mtd->shutdown(); + delete mtd; + logger->log("Core", Log::NOTICE, "MTD module shut down"); + } + + if (led) + { + led->shutdown(); + delete led; + logger->log("Core", Log::NOTICE, "LED module shut down"); + } + + if (remote) + { + remote->shutdown(); + delete remote; + logger->log("Core", Log::NOTICE, "Remote module shut down"); + } + + if (logger) + { + logger->log("Core", Log::NOTICE, "Log module shutting down... bye!\n\n"); + logger->shutdown(); + delete logger; + } + + exit(code); +} + +// ------------------------------------------------------------------------------------------------------------------- + +void sighandler(int signal) +{ + Log* logger = Log::getInstance(); + + logger->log("Core", Log::NOTICE, "Signal %i received", signal); + + switch (signal) + { + case SIGINT: + { + logger->log("Core", Log::NOTICE, "Interrupt signal, shutting down..."); + command->stop(); // FIXME this is probably not safe - use the messaging system / is that even safe? + break; + } + case SIGTERM: + { + logger->log("Core", Log::NOTICE, "Term signal, shutting down..."); + command->stop(); // FIXME this is probably not safe - use the messaging system / is that even safe? + break; + } + case SIGUSR1: + { + logger->log("Core", Log::DEBUG, "SIGUSR1 caught"); + logger->upLogLevel(); + break; + } + case SIGUSR2: + { + logger->log("Core", Log::DEBUG, "SIGUSR2 caught"); + logger->downLogLevel(); + break; + } + case SIGURG: + { + logger->log("Core", Log::DEBUG, "SIGURG caught"); + break; + } + } +} + +// ------------------------------------------------------------------------------------------------------------------- + +ULLONG ntohll(ULLONG a) +{ + return htonll(a); +} + +ULLONG htonll(ULLONG a) +{ + #if BYTE_ORDER == BIG_ENDIAN + return a; + #else + ULLONG b = 0; + + b = ((a << 56) & 0xFF00000000000000ULL) + | ((a << 40) & 0x00FF000000000000ULL) + | ((a << 24) & 0x0000FF0000000000ULL) + | ((a << 8) & 0x000000FF00000000ULL) + | ((a >> 8) & 0x00000000FF000000ULL) + | ((a >> 24) & 0x0000000000FF0000ULL) + | ((a >> 40) & 0x000000000000FF00ULL) + | ((a >> 56) & 0x00000000000000FFULL) ; + + return b; + #endif +} diff --git a/message.cc b/message.cc new file mode 100644 index 0000000..21e693d --- /dev/null +++ b/message.cc @@ -0,0 +1,30 @@ +/* + Copyright 2004-2005 Chris Tallon + + This file is part of VOMP. + + VOMP 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. + + VOMP 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 VOMP; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include "message.h" + +Message::Message() +{ + from = NULL; + to = NULL; + message = 0; + parameter = 0; + tag = 0; +} diff --git a/message.h b/message.h new file mode 100644 index 0000000..523bf76 --- /dev/null +++ b/message.h @@ -0,0 +1,52 @@ +/* + Copyright 2004-2005 Chris Tallon + + This file is part of VOMP. + + VOMP 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. + + VOMP 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 VOMP; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#ifndef MESSAGE_H +#define MESSAGE_H + +#include +#include "defines.h" + +class View; + +class Message +{ + public: + Message(); + + void* from; + void* to; + ULONG message; + ULONG parameter; + ULONG tag; // use this for identifying which object / question is being replied to + + const static ULONG QUESTION_YES = 1; + const static ULONG CLOSE_ME = 2; + const static ULONG PLAY_SELECTED_RECORDING = 3; + const static ULONG DELETE_SELECTED_RECORDING = 4; + const static ULONG UPDATE_SCREEN = 5; + const static ULONG SWAP_ME_FOR = 6; + const static ULONG CHANNEL_CHANGE = 7; + const static ULONG RESUME_SELECTED_RECORDING = 8; + const static ULONG STANDBY = 9; + const static ULONG STOP_PLAYBACK = 10; +}; + +#endif diff --git a/messagequeue.cc b/messagequeue.cc new file mode 100644 index 0000000..5c4bbd9 --- /dev/null +++ b/messagequeue.cc @@ -0,0 +1,38 @@ +/* + Copyright 2004-2005 Chris Tallon + + This file is part of VOMP. + + VOMP 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. + + VOMP 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 VOMP; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include "messagequeue.h" + +void MessageQueue::postMessage(Message* m) +{ + messages.store(m); + Log::getInstance()->log("MessageQueue", Log::DEBUG, "have stored message in queue"); +} + +void MessageQueue::processMessageQueue() +{ + Message *m; + while((m = (Message*)messages.retrieve())) + { + Log::getInstance()->log("MessageQueue", Log::DEBUG, "retrieved message from queue"); + processMessage(m); + delete m; + } +} diff --git a/messagequeue.h b/messagequeue.h new file mode 100644 index 0000000..6e36a9b --- /dev/null +++ b/messagequeue.h @@ -0,0 +1,46 @@ +/* + Copyright 2004-2005 Chris Tallon + + This file is part of VOMP. + + VOMP 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. + + VOMP 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 VOMP; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#ifndef MESSAGEQUEUE_H +#define MESSAGEQUEUE_H + +#include "queue.h" +#include "message.h" +#include "log.h" + +class MessageQueue +{ + public: + MessageQueue() {}; + virtual ~MessageQueue() {}; + + virtual void postMessage(Message* m); + + protected: + virtual void processMessageQueue(); + virtual void processMessage(Message* m)=0; + + Queue messages; + + private: + +}; + +#endif diff --git a/mtd.cc b/mtd.cc new file mode 100644 index 0000000..f5d900c --- /dev/null +++ b/mtd.cc @@ -0,0 +1,127 @@ +/* + Copyright 2004-2005 Chris Tallon + + This file is part of VOMP. + + VOMP 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. + + VOMP 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 VOMP; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include "mtd.h" + +Mtd* Mtd::instance = NULL; + +Mtd::Mtd() +{ + if (instance) return; + instance = this; + initted = 0; +} + +Mtd::~Mtd() +{ + instance = NULL; +} + +Mtd* Mtd::getInstance() +{ + return instance; +} + +int Mtd::init(char* device) +{ + if (initted) return 0; + initted = 1; + + int fd; + + if ((fd = open(device, O_RDONLY)) < 0) + { + initted = 0; + return 0; + } + + if (read(fd, data, 8192) < 8192) + { + initted = 0; + return 0; + } + + close(fd); + + logit(); + + return 1; +} + +int Mtd::shutdown() +{ + if (!initted) return 0; + initted = 0; + return 1; +} + +short Mtd::getVideoMode() +{ + return data[2119]; +} + +short Mtd::getAspect() +{ + return data[2125]; +} + +short Mtd::getFlicker() +{ + return data[2124]; +} + +short Mtd::getBootLogoOutput() +{ + return data[2116]; +} + +short Mtd::getBootLogoDisplayVideoLeft() +{ + return data[2120]; +} + +short Mtd::getBootLogoDisplayVideoUpper() +{ + return data[2121]; +} + +short Mtd::getBootLogoDisplayVideoWidth() +{ + return data[2122]; +} + +short Mtd::getBootLogoDisplayVideoHeight() +{ + return data[2123]; +} + +void Mtd::logit() +{ + Log* logger = Log::getInstance(); + + logger->log("MTD", Log::DEBUG, "Mode: %i", getVideoMode()); + logger->log("MTD", Log::DEBUG, "Aspect: %i", getAspect()); + logger->log("MTD", Log::DEBUG, "Flicker: %i", getFlicker()); + logger->log("MTD", Log::DEBUG, "Bootlogo output: %i", getBootLogoOutput()); + logger->log("MTD", Log::DEBUG, "Bootlogo display video left: %i", getBootLogoDisplayVideoLeft()); + logger->log("MTD", Log::DEBUG, "Bootlogo display video upper: %i", getBootLogoDisplayVideoUpper()); + logger->log("MTD", Log::DEBUG, "Bootlogo display video width: %i", getBootLogoDisplayVideoWidth()); + logger->log("MTD", Log::DEBUG, "Bootlogo display video height: %i", getBootLogoDisplayVideoHeight()); +} diff --git a/mtd.h b/mtd.h new file mode 100644 index 0000000..c143222 --- /dev/null +++ b/mtd.h @@ -0,0 +1,59 @@ +/* + Copyright 2004-2005 Chris Tallon + + This file is part of VOMP. + + VOMP 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. + + VOMP 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 VOMP; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +// Information for this class taken from the mvpmc project - thanks + +#ifndef MTD_H +#define MTD_H + +#include +#include + +#include "log.h" + +class Mtd +{ + public: + Mtd(); + ~Mtd(); + static Mtd* getInstance(); + + int init(char* device); + int shutdown(); + + short getVideoMode(); + short getAspect(); + short getFlicker(); + short getBootLogoOutput(); + short getBootLogoDisplayVideoLeft(); + short getBootLogoDisplayVideoUpper(); + short getBootLogoDisplayVideoWidth(); + short getBootLogoDisplayVideoHeight(); + + void logit(); + + private: + static Mtd* instance; + int initted; + + short data[4096]; +}; + +#endif diff --git a/node.cc b/node.cc new file mode 100644 index 0000000..c99db45 --- /dev/null +++ b/node.cc @@ -0,0 +1,46 @@ +/* + Copyright 2004-2005 Chris Tallon + + This file is part of VOMP. + + VOMP 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. + + VOMP 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 VOMP; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include "node.h" + +Node::Node(void *newData, Node *ptr) +{ + myData = newData; + ptrNext = ptr; +} + +Node::~Node() +{ +} + +void *Node::getData(void) +{ + return myData; +} + +Node *Node::getPtr(void) +{ + return ptrNext; +} + +void Node::setPtr(Node *newPtr) +{ + ptrNext = newPtr; +} diff --git a/node.h b/node.h new file mode 100644 index 0000000..50788dc --- /dev/null +++ b/node.h @@ -0,0 +1,37 @@ +/* + Copyright 2004-2005 Chris Tallon + + This file is part of VOMP. + + VOMP 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. + + VOMP 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 VOMP; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#ifndef NODE_H +#define NODE_H + +class Node +{ + public: + Node(void *, Node *); + ~Node(); + void *getData(void); + Node *getPtr(void); + void setPtr(Node *); + private: + void *myData; + Node *ptrNext; +}; + +#endif diff --git a/osd.cc b/osd.cc new file mode 100644 index 0000000..d325301 --- /dev/null +++ b/osd.cc @@ -0,0 +1,111 @@ +/* + Copyright 2004-2005 Chris Tallon + + This file is part of VOMP. + + VOMP 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. + + VOMP 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 VOMP; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include "osd.h" + +Osd* Osd::instance = NULL; + +Osd::Osd() +{ + if (instance) return; + instance = this; + initted = 0; + + fdOsd = 0; + screen = NULL; + buffer = NULL; +} + +Osd::~Osd() +{ + if (initted) shutdown(); + instance = NULL; +} + +Osd* Osd::getInstance() +{ + return instance; +} + +int Osd::getFD() +{ + if (!initted) return 0; + return fdOsd; +} + +int Osd::getScreenHeight() +{ + return height; +} + +int Osd::getScreenWidth() +{ + return width; +} + +int Osd::init(char* device, int height, int width, int doubleBuffering) +{ + if (initted) return 0; + + fdOsd = open(device, O_RDWR); + if (!fdOsd) + { + Log::getInstance()->log("OSD", Log::DEBUG, "Could not open OSD device!"); + return 0; + } + + initted = 1; // must set this here or create surface won't work + + this->height = height; + this->width = width; + + Surface::initConversionTables(); + + screen = new Surface(fdOsd, Surface::SCREEN); + screen->create(height, width); + screen->display(); + + if (doubleBuffering) + { + buffer = new Surface(fdOsd, Surface::BUFFER); + buffer->create(height, width); + } + else + { + Surface::disableBuffer(); + } + + return 1; +} + +int Osd::shutdown() +{ + if (!initted) return 0; + initted = 0; + if (buffer) delete buffer; + delete screen; + close(fdOsd); + return 1; +} + +void Osd::screenShot(char* fileName) +{ + screen->screenShot(fileName); +} diff --git a/osd.h b/osd.h new file mode 100644 index 0000000..1c11504 --- /dev/null +++ b/osd.h @@ -0,0 +1,61 @@ +/* + Copyright 2004-2005 Chris Tallon + + This file is part of VOMP. + + VOMP 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. + + VOMP 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 VOMP; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#ifndef OSD_H +#define OSD_H + +#include +#include +#include + +#include "defines.h" +#include "log.h" +#include "surface.h" + +class Osd +{ + public: + Osd(); + ~Osd(); + static Osd* getInstance(); + + int init(char* device, int height, int width, int doubleBuffering); + int shutdown(); + + int getFD(); + int getScreenHeight(); + int getScreenWidth(); + + void screenShot(char* fileName); + + private: + static Osd* instance; + int initted; + + Surface* screen; + Surface* buffer; + + int fdOsd; + int width; + int height; + +}; + +#endif diff --git a/other/licence.txt b/other/licence.txt new file mode 100644 index 0000000..f780226 --- /dev/null +++ b/other/licence.txt @@ -0,0 +1,45 @@ +vdr.jpg is lifted from VDR's home page which states: +"Free project statement This is a FREE and completely non-commercial project. +Any information posted on these pages is freely available to anybody. All +source code published here is protected by the GNU general public licence." + +------------------------------------------------------------------ + +wallpaper.jpg is actually blue-bend.jpg from the KDE wallpapers. +It was taken from the debian package kdebase-data - the copyright +file is below. + +------------------------------------------------------------------ + +This package was debianized by Christopher L Cheney on +Tue, 16 Apr 2002 22:00:00 -0500. + +It was downloaded via CVS from cvs.kde.org + +Upstream Authors: Stephan Kulow and many others... + +License: + +All programs are either under the GPL or LGPL. On Debian systems, +the complete text of the GPL and LGPL licenses can be found in the +/usr/share/common-licenses/GPL and /usr/share/common-licenses/LGPL files. + +When in doubt, check the individual file, they should all have license +headings and other identifying marks. + +Artistic +-------- +kdcop, kdesu, klipper + +BSD +--- +drkonqi, kaddressbook, kicker, ksmserver, ksplash, kwin, legacyimport + +GPL +--- +kappfinder, kate, kcheckpass, kdeprint, kdm, kfind, khelpcenter, kmenuedit, +konqueror, konsole, kpager, kpersonalizer, kreadconfig, kstart, ksysguard, ktip + +LGPL +---- +kdebugdialog, kdesktop, khotkeys, kxkb, libkonq, nsplugins diff --git a/other/vdr.jpg b/other/vdr.jpg new file mode 100644 index 0000000000000000000000000000000000000000..37be1c9240a41d4551fd9bbbaea82b3c6110c897 GIT binary patch literal 14359 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 literal 0 HcmV?d00001 diff --git a/other/wallpaper.jpg b/other/wallpaper.jpg new file mode 100644 index 0000000000000000000000000000000000000000..ed56138ec4ebb2ec0244f1d129ea8c45314a392b GIT binary patch literal 14125 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 CsfMor literal 0 HcmV?d00001 diff --git a/player.cc b/player.cc new file mode 100644 index 0000000..d77d5aa --- /dev/null +++ b/player.cc @@ -0,0 +1,497 @@ +/* + Copyright 2004-2005 Chris Tallon + + This file is part of VOMP. + + VOMP 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. + + VOMP 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 VOMP; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include "player.h" + +Player::Player(MessageQueue* messageQueue) +: vfeed(this), afeed(this) +{ + initted = 0; + commandMessageQueue = messageQueue; + + paused = 0; + playing = 0; + ffwd = 0; + fbwd = 0; + feedPosition = 0; + feedMode = MODE_NORMAL; + + streamLength = 0; + // FIXME - this might need settings back to zero for new live play depending on what is done with it +} + +Player::~Player() +{ + if (initted) shutdown(); +} + +int Player::init() +{ + if (initted) return 0; + + video = Video::getInstance(); + audio = Audio::getInstance(); + + if (demuxer.init()) // inverted + { + Log::getInstance()->log("Player", Log::ERR, "Demuxer failed to init"); + shutdown(); + return 0; + } + + vfeed.init(video->getFD()); + afeed.init(audio->getFD()); + + video->stop(); + video->blank(); + audio->stop(); + + startup = 0; + initted = 1; + return 1; +} + +int Player::shutdown() +{ + if (!initted) return 0; + initted = 0; + + Log::getInstance()->log("Player", Log::DEBUG, "Player shutdown..."); + + // copy of stop + if (playing) + { + playing = 0; + threadStop(); + video->stop(); + video->blank(); + audio->stop(); + vfeed.stop(); + afeed.stop(); + video->reset(); + demuxer.reset(); + feedPosition = 0; + } + + return 1; +} + +int Player::play() +{ + if (!initted) return 0; + + // If we are just paused, unpause! + if (paused) + { + togglePause(); + return 1; + } + + // If we are fast forwarding, set to normal + if (ffwd) + { + toggleFastForward(); + return 1; + } + + // If we are fast backwarding, set to normal + if (fbwd) + { + toggleFastBackward(); + return 1; + } + + // If we are already playing, bail // FIXME - resync? + if (playing) + { + Log::getInstance()->log("Player", Log::DEBUG, "DOING RESYNC"); + + vfeed.stop(); + afeed.stop(); + video->reset(); + audio->reset(); + demuxer.flush(); + demuxer.seek(); + vfeed.start(); + afeed.start(); + + + video->play(); + audio->play(); + video->sync(); + audio->sync(); + call(); + + return 1; + } + + // Standard play start + + audio->reset(); + video->reset(); + demuxer.reset(); + startup = 1; + +// ------------------------ This one works, but doesn't allow any pre-buffering. + threadStart(); + vfeed.start(); + afeed.start(); + video->play(); + audio->play(); + video->sync(); + audio->sync(); +// ------------------------ This one doesn't work, but it should, and would allow for prebuffering. + +/* + + threadStart(); + sleep(2); + +// struct timespec delay; +// delay.tv_sec = 1; +// delay.tv_nsec = 500000000; +// nanosleep(&delay, NULL); + + vfeed.start(); + afeed.start(); + video->play(); + audio->play(); + video->sync(); + audio->sync(); +*/ +// ------------------------------------------------------------------------------------------------ + + playing = 1; + return 1; +} + +void Player::stop() +{ + if (!initted) return; + if (!playing) return; + + if (ffwd || fbwd) + { + ffwd = 0; + fbwd = 0; + afeed.enable(); + video->unFastForward(); + audio->systemMuteOff(); + feedMode = MODE_NORMAL; + } + + playing = 0; + + threadStop(); + video->stop(); + video->blank(); + audio->stop(); + vfeed.stop(); + afeed.stop(); + video->reset(); + demuxer.reset(); + + feedPosition = 0; +} + +void Player::togglePause() +{ + if (!initted) return; + if (!playing) return; + + if (ffwd) toggleFastForward(); + if (fbwd) toggleFastBackward(); + + if (paused) + { + video->unPause(); + audio->unPause(); + paused = 0; + } + else + { + video->pause(); + audio->pause(); + paused = 1; + } +} + +void Player::test() +{ + Log::getInstance()->log("Player", Log::DEBUG, "PLAYER TEST"); + + video->test(); + +// static int flipflop = 0; + +// if (flipflop) video->setAspectRatio(Video::ASPECT16X9); +// else video->setAspectRatio(Video::ASPECT4X3); + +// flipflop = !flipflop; + +} + +void Player::test2() +{ + Log::getInstance()->log("Player", Log::DEBUG, "PLAYER TEST"); + + video->test2(); +} + +void Player::setPosition(ULLONG position) +{ + feedPosition = position; +} + +void Player::setLength(ULLONG length) +{ + streamLength = length; + Log::getInstance()->log("Player", Log::DEBUG, "Player has received length of %llu", streamLength); +} + +void Player::skipForward(int seconds) +{ + // skip forward 1 minute + Log::getInstance()->log("Player", Log::DEBUG, "SKIP FORWARD %i SECONDS", seconds); + + if (paused) togglePause(); + + ULLONG moveBy = seconds * 500000; + + threadStop(); + vfeed.stop(); + afeed.stop(); + video->stop(); + video->reset(); + audio->reset(); + audio->doMuting(); // ??? + demuxer.flush(); + feedPosition += moveBy; + + printf("Audio test %i\n", audio->test()); + + vfeed.start(); + afeed.start(); + threadStart(); + video->sync(); + audio->sync(); + video->play(); + audio->play(); + +} + +void Player::skipBackward(int seconds) +{ + // skip forward 1 minute + Log::getInstance()->log("Player", Log::DEBUG, "SKIP BACKWARD %i SECONDS", seconds); + + if (paused) togglePause(); + + ULLONG moveBy = seconds * 500000; + + threadStop(); + vfeed.stop(); + afeed.stop(); + video->stop(); + audio->stop(); + video->reset(); + audio->reset(); + audio->doMuting(); // ??? + demuxer.flush(); + if (feedPosition > moveBy) feedPosition -= moveBy; + vfeed.start(); + afeed.start(); + threadStart(); + video->play(); + audio->play(); + video->sync(); + audio->sync(); +} + +void Player::toggleFastForward() +{ + if (!initted) return; + if (!playing) return; + + if (paused) togglePause(); + if (fbwd) toggleFastBackward(); + + if (ffwd) + { + ffwd = 0; + afeed.enable(); + video->unFastForward(); + audio->reset(); + video->sync(); + audio->sync(); + audio->systemMuteOff(); + } + else + { + ffwd = 1; + afeed.disable(); + audio->systemMuteOn(); + video->fastForward(); + } +} + +void Player::toggleFastBackward() +{ + if (!initted) return; + if (!playing) return; + + if (paused) togglePause(); + if (ffwd) toggleFastForward(); + + if (fbwd) + { + fbwd = 0; + afeed.enable(); + audio->systemMuteOff(); + +// threadStop(); + feedMode = MODE_NORMAL; +// threadStart(); + } + else + { + fbwd = 1; + afeed.disable(); + audio->systemMuteOn(); + + threadStop(); + feedMode = MODE_BACKWARDS; + video->reset(); + video->play(); + demuxer.flush(); + threadStart(); + } +} + +void Player::jumpToPercent(int percent) +{ + threadStop(); + vfeed.stop(); + afeed.stop(); + video->stop(); + audio->stop(); + video->reset(); + audio->reset(); + demuxer.flush(); + demuxer.seek(); + feedPosition = streamLength * percent / 100; + vfeed.start(); + afeed.start(); + threadStart(); + video->play(); + audio->play(); + video->sync(); + audio->sync(); +} + + +void Player::call() +{ + threadSignalNoLock(); +} + +// Feed thread + +void Player::threadMethod() +{ + UCHAR buf[blockSize]; + int thisRead; + int writeLength; + int thisWrite; + + VDR* vdr = VDR::getInstance(); + + int askFor; + while(1) + { + thisRead = 0; + writeLength = 0; + thisWrite = 0; + + threadCheckExit(); + + // a bit hackey. this needs to be split to live and rec players + if (streamLength && (feedPosition >= streamLength)) break; + askFor = blockSize; + if (streamLength && ((feedPosition + blockSize) > streamLength)) + { + askFor = streamLength - feedPosition; + } + thisRead = vdr->getBlock(buf, feedPosition, askFor); + if (startup) + { + int a_stream = demuxer.scan(buf, thisRead); + demuxer.setAudioStream(a_stream); + Log::getInstance()->log("Player", Log::DEBUG, "Startup Audio stream chosen %x", a_stream); + startup = 0; + } + + if (feedMode == MODE_NORMAL) + { + feedPosition += thisRead; + } + else if (feedMode == MODE_BACKWARDS) + { + if (feedPosition >= 100000) + { + feedPosition -= 100000; + demuxer.seek(); + } + else + { + // got to the start of the recording.. revert to play mode? how? + feedPosition += thisRead; + } + } + + threadCheckExit(); + + while(writeLength < thisRead) + { + thisWrite = demuxer.put(buf + writeLength, thisRead - writeLength); + writeLength += thisWrite; + + if (!thisWrite) + { + Log::getInstance()->log("Player", Log::DEBUG, "DEMUXER FULL!!!"); + // demuxer is full and cant take anymore + threadWaitForSignal(); + Log::getInstance()->log("Player", Log::DEBUG, "BACK FROM WAIT"); + } + + threadCheckExit(); + } + } + + // end of recording + Log::getInstance()->log("Player", Log::DEBUG, "Recording playback ends"); + Message* m = new Message(); + m->message = Message::STOP_PLAYBACK; + Log::getInstance()->log("Player", Log::DEBUG, "Posting message..."); + commandMessageQueue->postMessage(m); + Log::getInstance()->log("Player", Log::DEBUG, "Message posted..."); + + +} diff --git a/player.h b/player.h new file mode 100644 index 0000000..ca9183b --- /dev/null +++ b/player.h @@ -0,0 +1,85 @@ +/* + Copyright 2004-2005 Chris Tallon + + This file is part of VOMP. + + VOMP 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. + + VOMP 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 VOMP; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#ifndef PLAYER_H +#define PLAYER_H + +#include + +#include "audio.h" +#include "video.h" +#include "demuxer.h" +#include "vfeed.h" +#include "afeed.h" +#include "remote.h" +#include "thread.h" +#include "vdr.h" +#include "callback.h" +#include "message.h" +#include "messagequeue.h" + +class Player : public Thread, public Callback +{ + public: + Player(MessageQueue* messageQueue); + virtual ~Player(); + + int init(); + int shutdown(); + + int play(); + void stop(); + void togglePause(); + void toggleFastForward(); + void toggleFastBackward(); + void jumpToPercent(int percent); + void skipForward(int seconds); + void skipBackward(int seconds); + void test(); + void test2(); + void call(); // for callback interface + void setPosition(ULLONG position); + void setLength(ULLONG length); + + void threadMethod(); + + private: + int initted; + MessageQueue* commandMessageQueue; + Video* video; + Audio* audio; + Demuxer demuxer; + int startup; + VFeed vfeed; + AFeed afeed; + ULLONG streamLength; + ULLONG feedPosition; + UCHAR feedMode; + const static UCHAR MODE_NORMAL = 1; + const static UCHAR MODE_BACKWARDS = 2; + const static int blockSize = 100000; + + UCHAR playing; // As in not stopped, (playing && paused) can == TRUE + UCHAR paused; // Must be in playing state as well + UCHAR ffwd; // Must be in playing state as well + UCHAR fbwd; // Must be in playing state as well +}; + +#endif diff --git a/playerradio.cc b/playerradio.cc new file mode 100644 index 0000000..b8f05ce --- /dev/null +++ b/playerradio.cc @@ -0,0 +1,372 @@ +/* + Copyright 2004-2005 Chris Tallon + + This file is part of VOMP. + + VOMP 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. + + VOMP 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 VOMP; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +// this is a total copy from player but with video stuff taken out +// most of this isn't used because it's designed for recording playback + + +#include "playerradio.h" + +PlayerRadio::PlayerRadio() +: afeedr(this, &stream) +{ + initted = 0; + + paused = 0; + playing = 0; + ffwd = 0; + fbwd = 0; + feedPosition = 0; + feedMode = MODE_NORMAL; + + streamLength = 0; + // FIXME - this might need settings back to zero for new live play depending on what is done with it +} + +PlayerRadio::~PlayerRadio() +{ + if (initted) shutdown(); +} + +int PlayerRadio::init() +{ + if (initted) return 0; + + audio = Audio::getInstance(); + stream.init(120000); + afeedr.init(audio->getFD()); + + audio->stop(); + + initted = 1; + return 1; +} + +int PlayerRadio::shutdown() +{ + if (!initted) return 0; + initted = 0; + + Log::getInstance()->log("PlayerRadio", Log::DEBUG, "PlayerRadio shutdown..."); + + // copy of stop + if (playing) + { + playing = 0; + threadStop(); + audio->stop(); + afeedr.stop(); + feedPosition = 0; + } + + return 1; +} + +int PlayerRadio::play() +{ + if (!initted) return 0; + + // If we are just paused, unpause! + if (paused) + { + togglePause(); + return 1; + } + + // If we are fast forwarding, set to normal + if (ffwd) + { + toggleFastForward(); + return 1; + } + + // If we are fast backwarding, set to normal + if (fbwd) + { + toggleFastBackward(); + return 1; + } + + // If we are already playing, bail // FIXME - resync? + if (playing) + { + Log::getInstance()->log("PlayerRadio", Log::DEBUG, "DOING RESYNC"); + + afeedr.stop(); + audio->reset(); + afeedr.start(); + + audio->play(); + call(); + + return 1; + } + + // Standard play start + + audio->reset(); + +/* +// ------------------------ This one works, but doesn't allow any pre-buffering. + threadStart(); + afeedr.start(); + audio->play(); + audio->sync(); + +// ------------------------ This one doesn't work, but it should, and would allow for prebuffering. +*/ + + threadStart(); + sleep(6); + +// struct timespec delay; +// delay.tv_sec = 1; +// delay.tv_nsec = 500000000; +// nanosleep(&delay, NULL); + + afeedr.start(); + audio->play(); +// audio->sync(); +// ------------------------------------------------------------------------------------------------ + + playing = 1; + return 1; +} + +void PlayerRadio::stop() +{ + if (!initted) return; + if (!playing) return; + playing = 0; + + threadCancel(); + audio->stop(); + afeedr.stop(); + + feedPosition = 0; +} + +void PlayerRadio::togglePause() +{ + if (!initted) return; + if (!playing) return; + + if (ffwd) toggleFastForward(); + if (fbwd) toggleFastBackward(); + + if (paused) + { + audio->unPause(); + paused = 0; + } + else + { + audio->pause(); + paused = 1; + } +} + +void PlayerRadio::setPosition(ULLONG position) +{ + feedPosition = position; +} + +void PlayerRadio::setLength(ULLONG length) +{ + streamLength = length; + Log::getInstance()->log("PlayerRadio", Log::DEBUG, "PlayerRadio has received length of %llu", streamLength); +} + +void PlayerRadio::skipForward() +{ + // skip forward 1 minute + Log::getInstance()->log("PlayerRadio", Log::DEBUG, "SKIP FORWARD 1 MINUTE"); + + if (paused) togglePause(); + + threadStop(); + afeedr.stop(); + audio->stop(); + audio->reset(); + audio->doMuting(); // ??? + feedPosition += 30000000; + afeedr.start(); + threadStart(); + audio->play(); +} + +void PlayerRadio::skipBackward() +{ + // skip forward 1 minute + Log::getInstance()->log("PlayerRadio", Log::DEBUG, "SKIP BACKWARD 1 MINUTE"); + + if (paused) togglePause(); + + threadStop(); + afeedr.stop(); + audio->stop(); + audio->reset(); + audio->doMuting(); // ??? + if (feedPosition > 30000000) feedPosition -= 30000000; + afeedr.start(); + threadStart(); + audio->play(); +} + +void PlayerRadio::toggleFastForward() +{ + if (!initted) return; + if (!playing) return; + + if (paused) togglePause(); + if (fbwd) toggleFastBackward(); + + if (ffwd) + { + ffwd = 0; +// afeedr.enable(); + audio->reset(); + audio->systemMuteOff(); + } + else + { + ffwd = 1; +// afeedr.disable(); + audio->systemMuteOn(); + } +} + +void PlayerRadio::toggleFastBackward() +{ + if (!initted) return; + if (!playing) return; + + if (paused) togglePause(); + if (ffwd) toggleFastForward(); + + if (fbwd) + { + fbwd = 0; +// afeedr.enable(); + audio->systemMuteOff(); + +// threadStop(); + feedMode = MODE_NORMAL; +// threadStart(); + } + else + { + fbwd = 1; +// afeedr.disable(); + audio->systemMuteOn(); + + threadStop(); + feedMode = MODE_BACKWARDS; + threadStart(); + } +} + +void PlayerRadio::jumpToPercent(int percent) +{ + threadStop(); + afeedr.stop(); + audio->stop(); + audio->reset(); + feedPosition = streamLength * percent / 100; + afeedr.start(); + threadStart(); + audio->play(); + audio->sync(); +} + + +void PlayerRadio::call() +{ + threadSignalNoLock(); +} + +// Feed thread + +void PlayerRadio::threadMethod() +{ + UCHAR buf[blockSize]; + int thisRead; + int writeLength; + int thisWrite; + + VDR* vdr = VDR::getInstance(); + + int askFor; + while(1) + { + thisRead = 0; + writeLength = 0; + thisWrite = 0; + + threadCheckExit(); + + // a bit hackey. this needs to be split to live and rec players + if (streamLength && (feedPosition >= streamLength)) break; + askFor = blockSize; + if (streamLength && ((feedPosition + blockSize) > streamLength)) + { + askFor = streamLength - feedPosition; + } + thisRead = vdr->getBlock(buf, feedPosition, askFor); + + if (feedMode == MODE_NORMAL) + { + feedPosition += thisRead; + } + else if (feedMode == MODE_BACKWARDS) + { + if (feedPosition >= 100000) + { + feedPosition -= 100000; + } + else + { + // got to the start of the recording.. revert to play mode? how? + feedPosition += thisRead; + } + } + + threadCheckExit(); + + while(writeLength < thisRead) + { + thisWrite = stream.put(buf + writeLength, thisRead - writeLength); + writeLength += thisWrite; + + if (!thisWrite) + { + Log::getInstance()->log("Player", Log::DEBUG, "RADIO OUTPUT STREAM FULL!!!"); + // stream is full and cant take anymore + threadWaitForSignal(); + Log::getInstance()->log("Player", Log::DEBUG, "BACK FROM WAIT"); + } + + threadCheckExit(); + } + + Log::getInstance()->log("PlayerRadio", Log::DEBUG, "Written audio"); + + } +} diff --git a/playerradio.h b/playerradio.h new file mode 100644 index 0000000..ba17295 --- /dev/null +++ b/playerradio.h @@ -0,0 +1,76 @@ +/* + Copyright 2004-2005 Chris Tallon + + This file is part of VOMP. + + VOMP 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. + + VOMP 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 VOMP; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#ifndef PLAYERRADIO_H +#define PLAYERRADIO_H + +#include + +#include "audio.h" +#include "afeedr.h" +#include "remote.h" +#include "thread.h" +#include "vdr.h" +#include "callback.h" +#include "stream.h" + +class PlayerRadio : public Thread, public Callback +{ + public: + PlayerRadio(); + virtual ~PlayerRadio(); + + int init(); + int shutdown(); + + int play(); + void stop(); + void togglePause(); + void toggleFastForward(); + void toggleFastBackward(); + void jumpToPercent(int percent); + void skipForward(); + void skipBackward(); + void call(); // for callback interface + void setPosition(ULLONG position); + void setLength(ULLONG length); + + void threadMethod(); + + private: + int initted; + Audio* audio; + int startup; + Stream stream; + AFeedR afeedr; + ULLONG streamLength; + ULLONG feedPosition; + UCHAR feedMode; + const static UCHAR MODE_NORMAL = 1; + const static UCHAR MODE_BACKWARDS = 2; + const static int blockSize = 30000; + + UCHAR playing; // As in not stopped, (playing && paused) can == TRUE + UCHAR paused; // Must be in playing state as well + UCHAR ffwd; // Must be in playing state as well + UCHAR fbwd; // Must be in playing state as well +}; + +#endif diff --git a/queue.cc b/queue.cc new file mode 100644 index 0000000..d33fa03 --- /dev/null +++ b/queue.cc @@ -0,0 +1,79 @@ +/* + Copyright 2004-2005 Chris Tallon + + This file is part of VOMP. + + VOMP 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. + + VOMP 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 VOMP; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include "queue.h" + +// ------ Constructor add delete get methods ------------------------------------- + +Queue::Queue(void) +{ + start = NULL; + end = NULL; +} + +Queue::~Queue() +{ + while(!isEmpty()) retrieve(); +} + +void Queue::store(void *newData) +{ + Node *temp = new Node(newData, NULL); + if (temp == NULL) + { + // oh dear. + } + if (start == NULL) // add to empty queue + { + start = temp; + end = temp; + } + else // add to non-empty queue + { + end->setPtr(temp); + end = temp; + } +} + +void *Queue::retrieve(void) +{ + if (start == NULL) { return NULL; } // there was an exit EXIT here bug?!!?!? + if (start == end) // then we are removing the last node so set end to 0 + { + end = NULL; + } + void *toReturn = start->getData(); + Node *next = start->getPtr(); + delete start; + start = next; + return toReturn; +} + +void *Queue::peekNext(void) +{ + return start->getData(); +} + +// ------ Boolean methods ----------------------------------------------------- + +short Queue::isEmpty(void) const +{ + return (start == NULL); +} diff --git a/queue.h b/queue.h new file mode 100644 index 0000000..29cdd85 --- /dev/null +++ b/queue.h @@ -0,0 +1,45 @@ +/* + Copyright 2004-2005 Chris Tallon + + This file is part of VOMP. + + VOMP 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. + + VOMP 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 VOMP; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#ifndef QUEUE_H +#define QUEUE_H + +#include + +#include "node.h" + +class Queue +{ + public: + Queue(); + ~Queue(); + void store(void *); + void *retrieve(void); + short isEmpty(void) const; + void *peekNext(void); + + private: + Node *start; + Node *end; +}; + +/* The destructor deletes any remaining QNodes but not stored objects. */ + +#endif diff --git a/recording.cc b/recording.cc new file mode 100644 index 0000000..016ef5a --- /dev/null +++ b/recording.cc @@ -0,0 +1,89 @@ +/* + Copyright 2004-2005 Chris Tallon + + This file is part of VOMP. + + VOMP 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. + + VOMP 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 VOMP; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include "recording.h" + +Recording::Recording() +{ + start = 0; + dirName = NULL; + progName = NULL; + fileName = NULL; + + index = -1; +} + +Recording::~Recording() +{ + if (dirName) delete[] dirName; + if (progName) delete[] progName; + if (fileName) delete[] fileName; + index = -1; // just in case +} + +int Recording::isInDir() +{ +// if (strstr(name, "~")) return 1; +// else return 0; + return (dirName != NULL); +} + +char* Recording::getDirName() +{ +/* char* sub = strstr(name, "~"); + if (!sub) return NULL; + + char* dirName = new char[sub - name + 1]; + memcpy(dirName, name, sub - name); + dirName[sub - name] = '\0'; + return dirName; +*/ + return dirName; +} + +char* Recording::getProgName() +{ + return progName; +} + +void Recording::setName(char* name) +{ + char* sub = strstr(name, "~"); + + if (sub) // Its in a dir + { + dirName = new char[sub - name + 1]; + memcpy(dirName, name, sub - name); + dirName[sub - name] = '\0'; + + sub++; + int sublen = strlen(sub); + progName = new char[sublen + 1]; + memcpy(progName, sub, strlen(sub)); + progName[sublen] = '\0'; + } + else + { + int len = strlen(name); + progName = new char[len + 1]; + memcpy(progName, name, len); + progName[len] = '\0'; + } +} diff --git a/recording.h b/recording.h new file mode 100644 index 0000000..57e0701 --- /dev/null +++ b/recording.h @@ -0,0 +1,49 @@ +/* + Copyright 2004-2005 Chris Tallon + + This file is part of VOMP. + + VOMP 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. + + VOMP 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 VOMP; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#ifndef RECORDING_H +#define RECORDING_H + +#include +#include + +class Recording +{ + public: + Recording(); + ~Recording(); + + void setName(char* name); + + int isInDir(); + char* getDirName(); + char* getProgName(); + + unsigned long start; + char* fileName; + + int index; + + private: + char* dirName; + char* progName; +}; + +#endif diff --git a/remote.cc b/remote.cc new file mode 100644 index 0000000..080bab8 --- /dev/null +++ b/remote.cc @@ -0,0 +1,124 @@ +/* + Copyright 2004-2005 Chris Tallon + + This file is part of VOMP. + + VOMP 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. + + VOMP 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 VOMP; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include "remote.h" + +Remote* Remote::instance = NULL; + +Remote::Remote() +{ + if (instance) return; + instance = this; + initted = 0; + device = 0; + tv.tv_sec = 0; + tv.tv_usec = 0; +} + +Remote::~Remote() +{ + instance = NULL; +} + +Remote* Remote::getInstance() +{ + return instance; +} + +int Remote::init(char* devName) +{ + if (initted) return 0; + initted = 1; + + device = open(devName, O_RDONLY); + if (device < 0) + { + initted = 0; + return 0; + } + + return 1; +} + +int Remote::shutdown() +{ + if (!initted) return 0; + initted = 0; + close(device); + device = 0; + return 1; +} + +int Remote::getDevice() +{ + if (!initted) return 0; + return device; +} + +UCHAR Remote::getButtonPress(int waitType) +{ + /* how = 0 - block + how = 1 - start new wait + how = 2 - continue wait + */ + + unsigned long input; + struct timeval* passToSelect = NULL; + int retval; + fd_set readfds; + + if (waitType == 0) + { + passToSelect = NULL; + } + else if (waitType == 1) + { + tv.tv_sec = 1; + tv.tv_usec = 000000; + passToSelect = &tv; + } + else if (waitType == 2) + { + if ((tv.tv_sec == 0) && (tv.tv_usec == 0)) // protection in case timer = 0 + { + tv.tv_sec = 1; + tv.tv_usec = 000000; + } + passToSelect = &tv; + } + FD_ZERO(&readfds); + FD_SET(device, &readfds); + + retval = select(device + 1, &readfds, NULL, NULL, &tv); + // 0 = nothing happened + // 1 = data arrived (actually num of descriptors that changed) + // other value = signal or error + if (retval == 0) return NONE; + if (retval == -1) return SIGNAL; + + int count = read(device, &input, 4); + if (count == 4) + { + input = (0X00FF0000 & input) >> 16; + Log::getInstance()->log("Remote", Log::DEBUG, "Button %i", input); + return (UCHAR) input; + } + return UNKNOWN; +} diff --git a/remote.h b/remote.h new file mode 100644 index 0000000..440718c --- /dev/null +++ b/remote.h @@ -0,0 +1,88 @@ +/* + Copyright 2004-2005 Chris Tallon + + This file is part of VOMP. + + VOMP 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. + + VOMP 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 VOMP; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#ifndef REMOTE_H +#define REMOTE_H + +#include +#include +#include + +#include "defines.h" +#include "log.h" + +class Remote +{ + public: + Remote(); + ~Remote(); + static Remote* getInstance(); + + int init(char *devName); + int shutdown(); + int getDevice(); + UCHAR getButtonPress(int how); + + const static UCHAR ZERO = 0; + const static UCHAR ONE = 1; + const static UCHAR TWO = 2; + const static UCHAR THREE = 3; + const static UCHAR FOUR = 4; + const static UCHAR FIVE = 5; + const static UCHAR SIX = 6; + const static UCHAR SEVEN = 7; + const static UCHAR EIGHT = 8; + const static UCHAR NINE = 9; + const static UCHAR POWER = 61; + const static UCHAR GO = 59; + const static UCHAR BACK = 31; + const static UCHAR MENU = 13; + const static UCHAR RED = 11; + const static UCHAR GREEN = 46; + const static UCHAR YELLOW = 56; + const static UCHAR BLUE = 41; + const static UCHAR LEFT = 17; + const static UCHAR RIGHT = 16; + const static UCHAR UP = 32; + const static UCHAR DOWN = 33; + const static UCHAR MUTE = 15; + const static UCHAR OSD = 12; + const static UCHAR FULL = 60; + const static UCHAR REVERSE = 50; + const static UCHAR PLAY = 53; + const static UCHAR FORWARD = 52; + const static UCHAR RECORD = 55; + const static UCHAR STOP = 54; + const static UCHAR PAUSE = 48; + const static UCHAR SKIPBACK = 36; + const static UCHAR SKIPFORWARD = 30; + const static UCHAR OK = 37; + const static UCHAR NONE = 98; + const static UCHAR UNKNOWN = 99; + const static UCHAR SIGNAL = 100; + + private: + static Remote* instance; + int initted; + int device; + struct timeval tv; +}; + +#endif diff --git a/stb.h b/stb.h new file mode 100644 index 0000000..62e6873 --- /dev/null +++ b/stb.h @@ -0,0 +1,220 @@ +/* + + This file is modified by Chris Tallon from the original stb.h + in libav, from the mvpmc project. libav is licensed under the + Lesser General Public License. + + As per point 3 of the Lesser General Public License, I am + applying the General Public License to my copy of the library + and therefore to this file. The copyright notice below has been + changed accordingly. + +*/ + +/* + Copyright (C) 2004, BtB, Jon Gettler + http://mvpmc.sourceforge.net/ + + This file 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 file 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 file; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + */ + + +#ifndef STB_H +#define STB_H + +/* + * $Id$ + * + * This describes the IBM STBx25xx/STBx30xxx hardware interface. + * + * Jon Gettler + */ + +#include + +typedef struct { + int arg; + int a; + int b; + int c; + int d; + int e; + int f; +} set_display_t; + + + +typedef struct { + unsigned long handle1; + unsigned long x; + unsigned long y; + unsigned long w; + unsigned long h; + unsigned long handle2; + unsigned long x1; + unsigned long y1; + unsigned long w1; + unsigned long h1; + unsigned long colour1; +} osd_blend_t; + +typedef struct { + unsigned long handle; + unsigned long x; + unsigned long y; + unsigned long w; + unsigned long h; + unsigned long colour1; + unsigned long colour2; + unsigned long colour3; + unsigned long colour4; + unsigned long colour5; + unsigned long colour6; + unsigned long colour7; + unsigned char c[2]; +} osd_afillblt_t; + +typedef struct { + unsigned long handle; + unsigned long left; + unsigned long top; + unsigned long right; + unsigned long bottom; +} osd_clip_rec_t; + +typedef struct { + int w; + int h; + int scale; + int x1; + int y; + int x; + int y2; + int x3; + int y3; + int x4; + int y4; +} vid_pos_regs_t; + +typedef struct { + int stc_b32; + int stc_b0; + int pts_b32; + int pts_b0; +} pts_sync_data_t; + +typedef struct { + int parm1; + int parm2; +} aud_sync_parms_t; + +typedef struct { + int aud_ctl0; + int aud_ctl1; + int aud_ctl2; +} aud_ctl_regs_t; + +typedef struct { + int denc0_cr1; + int denc1_cr1; + int dencmux; + int vid_disp_mode; +} vid_ctl_regs_t; + +struct vid_regs { + unsigned char dummy[44]; +}; + +typedef struct { + int nleft; + int state; +} vid_state_regs_t; + +typedef struct { + uint64_t stc; + uint64_t pts; +} sync_data_t; + + +/* + * /dev/adec_mpeg + */ +#define AV_SET_AUD_PLAY _IOW('a',2,int) +#define AV_SET_AUD_PAUSE _IOW('a',3,int) +#define AV_SET_AUD_UNPAUSE _IOW('a',4,int) +#define AV_SET_AUD_SRC _IOW('a',5,int) +#define AV_SET_AUD_MUTE _IOW('a',6,int) +#define AV_SET_AUD_CHANNEL _IOW('a',9,int) +#define AV_GET_AUD_INFO _IOR('a',10,int) +#define AV_SET_AUD_VOLUME _IOW('a',13,int) +#define AV_GET_AUD_VOLUME _IOR('a',14,int) +#define AV_SET_AUD_STREAMTYPE _IOW('a',15,int) +#define AV_SET_AUD_FORMAT _IOW('a',16,int) +#define AV_GET_AUD_SYNC _IOR('a',21,pts_sync_data_t*) +#define AV_SET_AUD_STC _IOW('a',22,uint64_t *) +#define AV_SET_AUD_SYNC _IOW('a',23,int) +#define AV_SET_AUD_DISABLE_SYNC _IOW('a',24,aud_sync_parms_t*) +#define AV_SET_AUD_RESET _IOW('a',26,int) +#define AV_SET_AUD_DAC_CLK _IOW('a',27,int) +#define AV_GET_AUD_REGS _IOW('a',28,aud_ctl_regs_t*) + +/* + * /dev/vdec_dev + */ + +// CJT +#define AV_SET_VID_STOP _IOW('v', 21, int) + + +#define AV_SET_VID_PLAY _IOW('v',22,int) +#define AV_SET_VID_FREEZE _IOW('v',23,int) +#define AV_SET_VID_RESUME _IOW('v',24,int) +#define AV_SET_VID_SRC _IOW('v',25,int) +#define AV_SET_VID_FB _IOW('v',26,int) +#define AV_GET_VID_STATE _IOR('v',27,vid_state_regs_t*) +#define AV_SET_VID_PAUSE _IOW('v',28,int) +#define AV_SET_VID_FFWD _IOW('v',29,int) +#define AV_SET_VID_SLOMO _IOW('v',30,int) +#define AV_SET_VID_BLANK _IOW('v',32,int) +#define AV_SET_VID_POSITION _IOW('v',36,vid_pos_regs_t*) +#define AV_SET_VID_SCALE_ON _IOW('v',37,int) +#define AV_SET_VID_SCALE_OFF _IOW('v',38,int) +#define AV_GET_VID_SYNC _IOR('v',39,int) +#define AV_SET_VID_STC _IOW('v',40,uint64_t *) +#define AV_SET_VID_RATIO _IOW('v',41,int) +#define AV_SET_VID_SYNC _IOW('v',42,int) +#define AV_SET_VID_DISABLE_SYNC _IOW('v',43,int) +#define AV_SET_VID_DISP_FMT _IOW('v',45,int) +#define AV_SET_VID_RESET _IOW('v',51,int) +#define AV_SET_VID_OUTPUT _IOW('v',57,int) +#define AV_SET_VID_MODE _IOW('v',58,int) +#define AV_GET_VID_REGS _IOR('v',61,struct vid_regs*) +#define AV_SET_VID_COLORBAR _IOW('v',62,int) +#define AV_SET_VID_DENC _IOW('v',63,int) +#define AV_CHK_SCART _IOW('v',64,int) + +/* + * screen device + */ +#define AV_GET_VID_INFO _IOR('s',44,int) + +/* + * /dev/rawir + */ +#define IR_SET_LED _IOW('i',21,int) + + +#endif /* STB_H */ diff --git a/stream.cc b/stream.cc new file mode 100644 index 0000000..116d8ea --- /dev/null +++ b/stream.cc @@ -0,0 +1,128 @@ +/* + Copyright 2005 Mark Calderbank + + This file is part of VOMP. + + VOMP 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. + + VOMP 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 VOMP; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include "stream.h" + +Stream::Stream() +{ + initted = 0; +} + +Stream::~Stream() +{ + shutdown(); +} + +void Stream::shutdown() +{ + if (initted) { + free(outbuf); + } + initted = 0; +} + +int Stream::init(int bufsize) +{ + outbuf = (UCHAR*) malloc(bufsize); + if (!outbuf) return 1; + bufferSize = bufsize; + bufferHead = bufferTail = 0; + full = 0; + initted = 1; + return 0; +} + +void Stream::flush() +{ + bufferHead = bufferTail = 0; + full = 0; +} + +int Stream::put(UCHAR* inbuf, int len) +{ + int ret = 0; + int localTail = bufferTail; + if (len == 0 || (full)) return ret; + + if (bufferHead >= localTail) + { + // We have free rein to the end of the buffer + if (len < (bufferSize - bufferHead)) + { + // We won't reach the end of the buffer. + memcpy(outbuf + bufferHead, inbuf, len); + bufferHead += len; + ret += len; return ret; + } else + { + // We'll reach the end of the buffer and loop round. + memcpy(outbuf + bufferHead, inbuf, (bufferSize - bufferHead)); + inbuf += (bufferSize - bufferHead); + ret += (bufferSize - bufferHead); + len -= (bufferSize - bufferHead); + bufferHead = 0; + if (localTail == 0) full = 1; + if (len == 0 || (full)) return ret; + } + } + // We can advance the head up to the tail + // If we reach it, we are full. + if (len < (localTail - bufferHead)) + { + // We'll fall short of the tail. + memcpy(outbuf + bufferHead, inbuf, len); + bufferHead += len; + ret += len; return ret; + } else + { + // We'll hit the tail. + memcpy(outbuf + bufferHead, inbuf, (localTail - bufferHead)); + ret += (localTail - bufferHead); + bufferHead = localTail; full = 1; + return ret; + } +} + +int Stream::drain(int fd) +{ + int ret = 0; + int localHead = bufferHead; + int written; + if (localHead == bufferTail && (!full)) return ret; + + if (localHead <= bufferTail) + { + // Drain to the end of the buffer + written = write(fd, outbuf + bufferTail, (bufferSize - bufferTail)); + if (written < 0) return ret; + full = 0; + ret += written; + if (written == (bufferSize - bufferTail)) + bufferTail = 0; + else + bufferTail += written; + if (localHead == 0) return ret; + } + written = write(fd, outbuf + bufferTail, (localHead - bufferTail)); + if (written < 0) return ret; + ret += written; + bufferTail += written; + return ret; +} diff --git a/stream.h b/stream.h new file mode 100644 index 0000000..bb3b572 --- /dev/null +++ b/stream.h @@ -0,0 +1,50 @@ +/* + Copyright 2005 Mark Calderbank + + This file is part of VOMP. + + VOMP 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. + + VOMP 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 VOMP; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#ifndef STREAM_H +#define STREAM_H + +#include +#include +#include +#include "defines.h" + +class Stream +{ + public: + Stream(); + ~Stream(); + int init(int bufsize); + void shutdown(); + void flush(); + int put(UCHAR* inbuf, int len); + int drain(int fd); + + private: + + int initted; + UCHAR* outbuf; + int bufferSize; + int bufferHead; + int bufferTail; + int full; +}; + +#endif diff --git a/surface.cc b/surface.cc new file mode 100644 index 0000000..d550b30 --- /dev/null +++ b/surface.cc @@ -0,0 +1,526 @@ +/* + Copyright 2004-2005 Chris Tallon + Portions copyright 2004 Jon Gettler + + This file is part of VOMP. + + VOMP 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. + + VOMP 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 VOMP; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include "surface.h" + +Surface* Surface::screen = NULL; +Surface* Surface::buffer = NULL; +int Surface::disableDoubleBuffering = 0; + +Surface::Surface(int fd, int id) +{ + if (id == SCREEN) screen = this; + if (id == BUFFER) buffer = this; + + fdOsd = fd; + memset(&surface, 0, sizeof(osd_surface_t)); + memset(&surface.sfc, 0, sizeof(stbgfx_sfc_t)); + memset(&surface.map, 0, sizeof(stbgfx_map_t)); + + font = &font_helvB18; +} + +Surface::~Surface() +{ + for (int i = 0; i < 3; i++) + { + if (surface.base[i]) munmap(surface.base[i], surface.map.map[i].size); + } + + int a; + + a = ioctl(fdOsd, GFX_FB_SFC_UNMAP, surface.sfc.handle); + if (a) Log::getInstance()->log("Surface", Log::ERR, "Surface unmap failed"); + + a = ioctl(fdOsd, GFX_FB_SFC_FREE, surface.sfc.handle); + if (a) Log::getInstance()->log("Surface", Log::ERR, "Surface destroy failed"); + +} + +void Surface::disableBuffer() +{ + disableDoubleBuffering = 1; +} + +Surface* Surface::getObject(int id) +{ + if (id == SCREEN) return screen; + if (disableDoubleBuffering) return screen; + if (id == BUFFER) return buffer; + return NULL; +} + +int Surface::create(int height, int width) +{ + int r = 0; + int displayNumber = 0; // mvpmc iterates 0->15 till it gets one that works? + + surface.sfc.width = width; + surface.sfc.height = height; + surface.sfc.flags = 0x3f1533; + + surface.sfc.unknown = -1; + + r = ioctl(fdOsd, GFX_FB_SET_OSD, &displayNumber); + if (r) return 0; + + r = ioctl(fdOsd, GFX_FB_OSD_SURFACE, &displayNumber); + if (r) return 0; + + r = ioctl(fdOsd, GFX_FB_SFC_ALLOC, &surface.sfc); + if (r) return 0; + + surface.map.map[0].unknown = surface.sfc.handle; + r = ioctl(fdOsd, GFX_FB_MAP, &surface.map); + if (r) return 0; + + surface.base[0] = (unsigned char *)mmap(NULL, surface.map.map[0].size, PROT_READ|PROT_WRITE, MAP_SHARED, fdOsd, surface.map.map[0].addr); + if (surface.base[0] == MAP_FAILED) return 0; + + surface.base[1] = (unsigned char *)mmap(NULL, surface.map.map[1].size, PROT_READ|PROT_WRITE, MAP_SHARED, fdOsd, surface.map.map[1].addr); + if (surface.base[1] == MAP_FAILED) return 0; + + surface.base[2] = (unsigned char *)mmap(NULL, surface.map.map[2].size, PROT_READ|PROT_WRITE, MAP_SHARED, fdOsd, surface.map.map[2].addr); + if (surface.base[2] == MAP_FAILED) return 0; + + surface.display.num = displayNumber; + r = ioctl(fdOsd, GFX_FB_MOVE_DISPLAY, &surface.display); + if (r) return 0; + + r = ioctl(fdOsd, GFX_FB_SET_DISPLAY, &surface.display); + if (r) return 0; + + return 1; +} + +void Surface::display() +{ + unsigned long fb_descriptor[2]; + + fb_descriptor[0] = surface.sfc.handle; + fb_descriptor[1] = 1; + + ioctl(fdOsd, GFX_FB_ATTACH, fb_descriptor); +} + +unsigned long Surface::getSurfaceHandle() +{ + return surface.sfc.handle; +} + +// ---------------------------------------------------------------------------- + +// Now for the drawing functions + +/* + * RGB to YUV conversion tables + */ +int Surface::conv_YB[256]; +int Surface::conv_YG[256]; +int Surface::conv_YR[256]; +int Surface::conv_UB[256]; +int Surface::conv_UG[256]; +int Surface::conv_UR[256]; +int Surface::conv_VB[256]; +int Surface::conv_VG[256]; +int Surface::conv_VR[256]; + +int Surface::conv_BY[256]; +int Surface::conv_GY[256]; +int Surface::conv_RY[256]; +int Surface::conv_BU[256]; +int Surface::conv_GU[256]; +int Surface::conv_RU[256]; +int Surface::conv_BV[256]; +int Surface::conv_GV[256]; +int Surface::conv_RV[256]; + +/* + * gfx_init() - initialize the RGB to YUV conversion tables + */ +void Surface::initConversionTables(void) +{ + int i; + + for (i=0; i<256; i++) { + conv_YB[i] = (int)(0.299 * (double)i); + conv_BY[i] = i; + } + for (i=0; i<256; i++) { + conv_YG[i] = (int)(0.587 * (double)i); + conv_GY[i] = i; + } + for (i=0; i<256; i++) { + conv_YR[i] = (int)(0.114 * (double)i); + conv_RY[i] = i; + } + + for (i=0; i<256; i++) { + conv_UB[i] = (int)(0.5 * (double)i); + conv_BU[i] = (int)(1.732 * (i - 128)); + } + for (i=0; i<256; i++) { + conv_UG[i] = (int)(-0.33126 * (double)i); + conv_GU[i] = (int)(-0.338 * (i - 128)); + } + for (i=0; i<256; i++) { + conv_UR[i] = (int)(-0.16874 * (double)i); + conv_RU[i] = 0; + } + + for (i=0; i<256; i++) { + conv_VB[i] = (int)(-0.08131 * (double)i); + conv_BV[i] = 0; + } + for (i=0; i<256; i++) { + conv_VG[i] = (int)(-0.41869 * (double)i); + conv_GV[i] = (int)(-0.698 * (i - 128)); + } + for (i=0; i<256; i++) { + conv_VR[i] = (int)(0.5 * (double)i); + conv_RV[i] = (int)(1.370 * ((double)i - 128)); + } +} + +/* + * rgb2yuv() - convert an RGB pixel to YUV + */ + //inline me? +void Surface::rgb2yuv(unsigned char r, unsigned char g, unsigned char b, unsigned char *y, unsigned char *u, unsigned char *v) +{ + int Y, U, V; + + Y = conv_YB[b] + conv_YG[g] + conv_YR[r]; + U = conv_UB[b] + conv_UG[g] + conv_UR[r] + 128; + V = conv_VB[b] + conv_VG[g] + conv_VR[r] + 128; + + if (Y > 255) + Y = 255; + else if (Y < 0) + Y = 0; + if (U > 255) + U = 255; + else if (U < 0) + U = 0; + if (V > 255) + V = 255; + else if (V < 0) + V = 0; + + *y = Y; + *u = U; + *v = V; +} + +int Surface::fillblt(int x, int y, int width, int height, unsigned int c) +{ + osd_fillblt_t fblt; + + fblt.handle = surface.sfc.handle; + fblt.x = x; + fblt.y = y; + fblt.width = width; + fblt.height = height; + fblt.colour = c; + + return ioctl(fdOsd, GFX_FB_OSD_FILLBLT, &fblt); +} + +void Surface::drawPixel(int x, int y, unsigned int c) +{ + int offset; + unsigned char r, g, b, a, Y, U, V; + unsigned int line, remainder; + + if ((x >= (int)surface.sfc.width) || (y >= (int)surface.sfc.height)) + return; + + c2rgba(c, &r, &g, &b, &a); + + rgb2yuv(r, g, b, &Y, &U, &V); + + remainder = (surface.sfc.width % 4); + if (remainder == 0) + line = surface.sfc.width; + else + line = surface.sfc.width + (4 - remainder); + + offset = (y * line) + x; + + *(surface.base[0] + offset) = Y; + *(surface.base[1] + (offset & 0xfffffffe)) = U; + *(surface.base[1] + (offset & 0xfffffffe) + 1) = V; + *(surface.base[2] + offset) = a; + +} + +void Surface::drawHorzLine(int x1, int x2, int y, unsigned int c) +{ + fillblt(x1, y, x2-x1, 1, c); +} + +void Surface::drawVertLine(int x, int y1, int y2, unsigned int c) +{ + fillblt(x, y1, 1, y2-y1, c); +} + +void Surface::bufferToScreen() // static, this is for Box::showAll +{ + if (disableDoubleBuffering) return; + buffer->updateToScreen(0, 0, buffer->surface.sfc.width, buffer->surface.sfc.height); +} + +int Surface::updateToScreen(int x, int y, int width, int height) // main method for all normal windows +{ + /* + With double buffering: + A view has buffer for its surface. this is buffer, copy area specified to screen + Without double buffering: + A view has screen for its surface. this is screen, all painting work has already been done. ignore + */ + + if (this == screen) return 0; + + return blt(fdOsd, surface.sfc.handle, x, y, width, height, screen->getSurfaceHandle(), x, y); +} + +int Surface::blt(int fd, unsigned long shandle, int sx, int sy, int width, int height, unsigned long dhandle, int dx, int dy) +{ + osd_bitblt_t fblt; + memset(&fblt, 0, sizeof(fblt)); + + fblt.dst_handle = dhandle; + fblt.dst_x = dx; + fblt.dst_y = dy; + + fblt.src_handle = shandle; + fblt.src_x = sx; + fblt.src_y = sy; + + fblt.width = width; + fblt.height = height; + + fblt.u1 = 1; + fblt.u2 = 0; + fblt.u3 = 0x0f; + + return ioctl(fd, GFX_FB_OSD_BITBLT, &fblt); +} + +int Surface::drawText(char* text, int x, int y, int r, int g, int b) +{ + int h, n, i; + int Y, X, cx; + unsigned long fg; + + fg = rgba(r, g, b, 255); + + n = strlen(text); + h = font->height; + + X = 0; + cx = 0; + for (i=0; icontent[font->offset[c]]; + int w = font->width[c]; + int pixels = 0; + + for (X=0; X> (32 - X)) & 0x1) + { + drawPixel(x+X+cx, y+Y, fg); + pixels++; + } + } + } + cx += w; + } + return 1; +} + +int Surface::drawTextRJ(char* text, int x, int y, int r, int g, int b) +{ + int i, n, w; + w = 0; + + n = strlen(text); + + for (i = 0; i < n; i++) + { + w += font->width[text[i]]; + } + + x -= w; + + if (x < 0) return 0; + else return drawText(text, x, y, r, g, b); +} + +int Surface::getCharWidth(char c) +{ + return font->width[c]; +} + +int Surface::getFontHeight() +{ + return font->height; +} + +void Surface::screenShot(char* fileName) +{ + Log* logger = Log::getInstance(); + + FILE* outfile = fopen(fileName, "w"); + if (outfile == NULL) + { + logger->log("Surface", Log::ERR, "Can't open JPEG"); + return; + } + logger->log("Surface", Log::DEBUG, "File opened %u %u", surface.sfc.height, surface.sfc.width); + + struct jpeg_compress_struct cinfo; + struct jpeg_error_mgr jerr; + cinfo.err = jpeg_std_error(&jerr); + jpeg_create_compress(&cinfo); + jpeg_stdio_dest(&cinfo, outfile); + cinfo.image_width = surface.sfc.width; + cinfo.image_height = surface.sfc.height; + cinfo.input_components = 3; + cinfo.in_color_space = JCS_RGB; + jpeg_set_defaults(&cinfo); + jpeg_start_compress(&cinfo, TRUE); + + + unsigned char row[surface.sfc.width * 3]; + unsigned char* prow = (unsigned char*)&row; + unsigned char r, g, b; + + while (cinfo.next_scanline < cinfo.image_height) + { + for(unsigned int i = 0; i < surface.sfc.width; i++) + { + readPixel(i, cinfo.next_scanline, &r, &g, &b); + row[i * 3] = r; + row[(i * 3) + 1] = g; + row[(i * 3) + 2] = b; + } + jpeg_write_scanlines(&cinfo, (JSAMPLE **)&prow, 1); + } + + jpeg_finish_compress(&cinfo); + jpeg_destroy_compress(&cinfo); + fclose(outfile); + logger->log("Surface", Log::DEBUG, "Jpeg saved"); +} + +void Surface::readPixel(int x, int y, unsigned char* r, unsigned char* g, unsigned char* b) +{ + int offset; + unsigned char a, Y, U, V; + unsigned int line, remainder; + + if (((unsigned int)x >= surface.sfc.width) || ((unsigned int)y >= surface.sfc.height)) return; + + remainder = (surface.sfc.width % 4); + if (remainder == 0) + line = surface.sfc.width; + else + line = surface.sfc.width + (4 - remainder); + + offset = (y * line) + x; + + Y = *(surface.base[0] + offset); + U = *(surface.base[1] + (offset & 0xfffffffe)); + V = *(surface.base[1] + (offset & 0xfffffffe) + 1); + a = *(surface.base[2] + offset); + + yuv2rgb(Y, U, V, r, g, b); +} + +void Surface::yuv2rgb(int y, int u, int v, unsigned char* pr, unsigned char* pg, unsigned char* pb) +{ + // from http://www.fourcc.org/index.php?http%3A//www.fourcc.org/fccyvrgb.php + +// unsigned int pixel32; +// unsigned char *pixel = (unsigned char *)&pixel32; + int r, g, b; + + + /* + One formula I found: (not the right one) + + R = 1.164(Y - 16) + 1.596(Cr - 128) + G = 1.164(Y - 16) - 0.813(Cr - 128) - 0.391(Cb - 128) + B = 1.164(Y - 16) + 2.018(Cb - 128) + + + r = (1.164 * (y - 16)) + + (2.018 * (v - 128)); + g = (1.164 * (y - 16)) + - (0.813 * (u - 128)) + - (0.391 * (v - 128)); + b = (1.164 * (y - 16)) + + (1.596 * (u - 128)); + + + Another formula I found: (seems to work) + + R = Y + 1.370705 (V-128) + G = Y - 0.698001 (V-128) - 0.337633 (U-128) + B = Y + 1.732446 (U-128) + */ + + r = (int)( y + (1.370705 * (v-128)) ); + g = (int)( y - (0.698001 * (v-128)) - (0.337633 * (u-128)) ); + b = (int)( y + (1.732446 * (u-128)) ); + + // Even with proper conversion, some values still need clipping. + if (r > 255) r = 255; + if (g > 255) g = 255; + if (b > 255) b = 255; + if (r < 0) r = 0; + if (g < 0) g = 0; + if (b < 0) b = 0; + + // Values only go from 0-220.. Why? +// pixel[0] = r * 220 / 256; +// pixel[1] = g * 220 / 256; +// pixel[2] = b * 220 / 256; +// pixel[3] = 0; + + *pr = (unsigned char) (r * 220 / 256); + *pg = (unsigned char) (g * 220 / 256); + *pb = (unsigned char) (b * 220 / 256); + + /* Debug + //printf("yuv2rgb(%i, %i, %i) -> %i, %i, %i (0x%x)\n", + y, u, v, + pixel[0], pixel[1], pixel[2], + pixel32); + */ + +// return pixel32; +} diff --git a/surface.h b/surface.h new file mode 100644 index 0000000..fde124d --- /dev/null +++ b/surface.h @@ -0,0 +1,249 @@ +/* + Copyright 2004-2005 Chris Tallon + Portions copyright 2004 Jon Gettler + + This file is part of VOMP. + + VOMP 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. + + VOMP 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 VOMP; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#ifndef SURFACE_H +#define SURFACE_H + +#include +#include +#include +#include +#include + +// Structures for surface management + +typedef struct +{ + unsigned long num; + unsigned long unknown[4]; + unsigned long width; + unsigned long height; + char unknown2; +} stbgfx_display_t; + +typedef struct +{ + unsigned long unknown; + unsigned long win_unknown; + unsigned long addr; + unsigned long size; + unsigned long unknown2; + unsigned long width; + unsigned long height; + unsigned long unknown3; + unsigned long unknown4; + unsigned long width2; + unsigned long unknown5; + unsigned long unknown6; +} stbgfx_map_item_t; + +typedef struct { + stbgfx_map_item_t map[3]; + unsigned long other[2]; +} stbgfx_map_t; + +typedef struct +{ + unsigned long handle; /* surface handle */ + unsigned long width; + unsigned long height; + unsigned long flags; + long unknown; //unsigned long + unsigned long depth; /* number of subplanes */ +} stbgfx_sfc_t; + +typedef struct +{ + stbgfx_display_t display; + stbgfx_map_t map; + stbgfx_sfc_t sfc; + unsigned char *base[3]; +} osd_surface_t; + + +// Structures for surface drawing + +typedef struct +{ + unsigned long handle; + unsigned long x; + unsigned long y; + unsigned long width; + unsigned long height; + unsigned long colour; +} osd_fillblt_t; + +typedef struct { + unsigned long dst_handle; + unsigned long dst_x; + unsigned long dst_y; + unsigned long width; + unsigned long height; + unsigned long src_handle; + unsigned long src_x; + unsigned long src_y; + unsigned long u1; + unsigned long u2; + unsigned char u3; +} osd_bitblt_t; + +// Font stuff + +typedef struct bogl_font { + char *name; /* Font name. */ + int height; /* Height in pixels. */ + unsigned long *content; /* 32-bit right-padded bitmap array. */ + short *offset; /* 256 offsets into content. */ + unsigned char *width; /* 256 character widths. */ +} osd_font_t; + +extern osd_font_t font_CaslonRoman_1_25; +extern osd_font_t font_helvB24; +extern osd_font_t font_helvB18; + +// Surface ioctls + +#define GFX_FB_SFC_ALLOC _IOWR(0xfb,1,int*) +#define GFX_FB_SFC_FREE _IOWR(0xfb,2,int) +#define GFX_FB_MAP _IOWR(0xfb,3,int*) +#define GFX_FB_SFC_UNMAP _IOWR(0xfb,4,int) +#define GFX_FB_SET_PAL_1 _IOWR(0xfb,5,int*) +#define GFX_FB_SET_PAL_2 _IOW(0xfb,6,int*) +#define GFX_FB_OSD_SURFACE _IO(0xfb,7) +#define GFX_FB_SFC_SET_SHARE _IOW(0xfb,8,int) +#define GFX_FB_OSD_CUR_SETATTR _IOW(0xfb,9,int*) +#define GFX_FB_ATTACH _IOW(0xfb,11,int) +#define GFX_FB_SFC_DETACH _IOW(0xfb,12,int*) +#define GFX_FB_MOVE_DISPLAY _IOWR(0xfb,13,int) +#define GFX_FB_SET_DISPLAY _IOW(0xfb,14,int) +#define GFX_FB_OSD_CUR_MOVE_1 _IOW(0xfb,15,int*) +#define GFX_FB_OSD_CUR_MOVE_2 _IOW(0xfb,16,int) +#define GFX_FB_SET_OSD _IOW(0xfb,18,int) +#define GFX_FB_SET_DISP_CTRL _IOW(0xfb,21,int*) +#define GFX_FB_GET_DISP_CTRL _IOWR(0xfb,22,int*) +#define GFX_FB_SET_VIS_DEV_CTL _IOWR(0xfb,23,int*) +#define GFX_FB_GET_VIS_DEV_CTL _IOWR(0xfb,24,int*) +#define GFX_FB_OSD_BITBLT _IOW(0xfb,51,osd_bitblt_t*) +#define GFX_FB_OSD_FILLBLT _IOW(0xfb,53,osd_fillblt_t*) +#define GFX_FB_OSD_ADVFILLBLT _IOW(0xfb,54,osd_afillblt_t*) +#define GFX_FB_OSD_BLEND _IOW(0xfb,55,int*) +#define GFX_FB_OSD_ADVBLEND _IOW(0xfb,56,int*) +#define GFX_FB_OSD_RESIZE _IOW(0xfb,58,int*) +#define GFX_FB_ENGINE_WAIT _IOW(0xfb,60,int) +#define GFX_FB_RESET_ENGINE _IO(0xfb,61) +#define GFX_FB_SET_ENGINE_MODE _IOW(0xfb,62,int) +#define GFX_FB_GET_ENGINE_MODE _IO(0xfb,63) +#define GFX_FB_GET_SFC_INFO _IO(0xfb,64,int*) +#define GFX_FB_OSD_SFC_CLIP _IOW(0xfb,65,osd_clip_rec_t*) +#define GFX_FB_OSD_COLOURKEY _IOW(0xfb,67,int*) +#define GFX_FB_GET_SFC_PSEUDO _IOWR(0xfb,68,int*) + +extern "C" +{ + #include +} + +#include "log.h" + +class Surface +{ + public: + Surface(int fd, int id); + ~Surface(); + + static Surface* getObject(int id); + + int create(int height, int width); + void display(); + unsigned long getSurfaceHandle(); + + int fillblt(int x, int y, int width, int height, unsigned int c); + void drawPixel(int x, int y, unsigned int c); + void drawHorzLine(int x1, int x2, int y, unsigned int c); + void drawVertLine(int x, int y1, int y2, unsigned int c); + int updateToScreen(int x, int y, int width, int height); + int drawText(char* text, int x, int y, int r, int g, int b); + int drawTextRJ(char* text, int x, int y, int r, int g, int b); + int getCharWidth(char c); + int getFontHeight(); + void readPixel(int x, int y, unsigned char* r, unsigned char* g, unsigned char* b); + void yuv2rgb(int y, int u, int v, unsigned char* pr, unsigned char* pg, unsigned char* pb); + void screenShot(char* fileName); + + static void initConversionTables(); + + static void disableBuffer(); + static void bufferToScreen(); + static int blt(int fd, unsigned long shandle, int sx, int sy, int width, int height, unsigned long dhandle, int dx, int dy); + + const static int SCREEN = 1; + const static int BUFFER = 2; + + // Implicit inlines + void c2rgba(unsigned long c, unsigned char *r, unsigned char *g, unsigned char *b, unsigned char *a) + { + *a = (c & 0xff000000) >> 24; + *r = (c & 0x00ff0000) >> 16; + *g = (c & 0x0000ff00) >> 8; + *b = (c & 0x000000ff); + } + + unsigned long rgba(unsigned char r, unsigned char g, unsigned char b, unsigned char a) + { + return (a<<24) | (r<<16) | (g<<8) | b; + + } + + private: + static Surface* screen; + static Surface* buffer; + static int disableDoubleBuffering; + + int fdOsd; + + osd_surface_t surface; + osd_font_t* font; + + void rgb2yuv(unsigned char r, unsigned char g, unsigned char b, unsigned char *y, unsigned char *u, unsigned char *v); + + static int conv_YB[256]; + static int conv_YG[256]; + static int conv_YR[256]; + static int conv_UB[256]; + static int conv_UG[256]; + static int conv_UR[256]; + static int conv_VB[256]; + static int conv_VG[256]; + static int conv_VR[256]; + + static int conv_BY[256]; + static int conv_GY[256]; + static int conv_RY[256]; + static int conv_BU[256]; + static int conv_GU[256]; + static int conv_RU[256]; + static int conv_BV[256]; + static int conv_GV[256]; + static int conv_RV[256]; + +}; + +#endif diff --git a/tcp.cc b/tcp.cc new file mode 100644 index 0000000..ef78c96 --- /dev/null +++ b/tcp.cc @@ -0,0 +1,403 @@ +/* + Copyright 2004-2005 Chris Tallon + Copyright 2003-2004 University Of Bradford + + This file is part of VOMP. + + VOMP 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. + + VOMP 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 VOMP; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include "tcp.h" + +TCP::TCP() +{ + sock = 0; + connected = 0; + timeoutEnabled = 1; +} + +TCP::~TCP() +{ + if (connected) + { + close(sock); + Log::getInstance()->log("TCP", Log::DEBUG, "Have closed"); + } +} + +void TCP::disableTimeout() +{ + timeoutEnabled = 0; +} + +int TCP::connectTo(char* host, unsigned short port) +{ + sock = socket(PF_INET, SOCK_STREAM, 0); + if (sock == -1) return 0; + + struct sockaddr_in dest_addr; + dest_addr.sin_family = AF_INET; + dest_addr.sin_port = htons(port); + + if (!inet_aton(host, &dest_addr.sin_addr)) + { + close(sock); + return 0; + } + + memset(&(dest_addr.sin_zero), '\0', 8); + + // set non blocking + int oldflags = fcntl (sock, F_GETFL, 0); + oldflags |= O_NONBLOCK; + fcntl(sock, F_SETFL, oldflags); + + // ok, how to open a connection in non blocking mode (and therefore have a self set timeout!!) + + int success = connect(sock, (struct sockaddr *)&dest_addr, sizeof(struct sockaddr)); + + if (success == 0) // if by some miracle the connection succeeded in no time flat, just return! + { + connected = 1; + return 1; + } + + // first check errno for EINPROGRESS, otherwise it's a fail + // this doesn't work? + if (errno != EINPROGRESS) + { + close(sock); + return 0; + } + + // now do a timeout wait on writability on the socket + + fd_set connectSet; + struct timeval timeout; + FD_ZERO(&connectSet); + FD_SET(sock, &connectSet); + timeout.tv_sec = 10; + timeout.tv_usec = 0; + success = select(sock + 1, NULL, &connectSet, NULL, &timeout); + if (success < 1) + { + // timeout or error + close(sock); + return 0; + } + + // so the socket became available for writing. Contrary to expectation, this doesn't actually + // mean it connected... + + int soError; + socklen_t soErrorSize = sizeof(soError); + int gso = getsockopt(sock, SOL_SOCKET, SO_ERROR, &soError, &soErrorSize); + + if ((gso == 0) && (soError == 0)) + { + // success! + connected = 1; + return 1; + } + else + { + close(sock); + return 0; + } + +/* +The full documentation: + + EINPROGRESS + The socket is non-blocking and the connection can­ + not be completed immediately. It is possible to + select(2) or poll(2) for completion by selecting + the socket for writing. After select indicates + writability, use getsockopt(2) to read the SO_ERROR + option at level SOL_SOCKET to determine whether + connect completed successfully (SO_ERROR is zero) + or unsuccessfully (SO_ERROR is one of the usual + error codes listed here, explaining the reason for + the failure). +*/ +} + +void TCP::assignSocket(int tsocket) +{ + sock = tsocket; +} + +int TCP::isConnected() +{ + return connected; +} + +int TCP::sendPacket(void* buf, size_t count) +{ + size_t bytes_sent = 0; + int this_write; + int temp_write; + + while (bytes_sent < count) + { + do + { + temp_write = this_write = write(sock, buf, count - bytes_sent); +// Log::getInstance()->log("TCP", Log::DEBUG, "TCP has written %i bytes", temp_write); + } while ( (this_write < 0) && (errno == EINTR) ); + + + if (this_write <= 0) + { + return(this_write); + } + bytes_sent += this_write; + (unsigned char*)buf += this_write; + } + return(count); +} + +UCHAR* TCP::receivePacket() +{ + ULONG packetLength; + int success; + + success = readData((UCHAR*)&packetLength, sizeof(int)); + if (!success) return NULL; + + packetLength = ntohl(packetLength); + + if (packetLength > 200000) + { + Log::getInstance()->log("TCP", Log::ERR, "Received packet > 200000"); + return NULL; + } + if (packetLength == 0) + { + Log::getInstance()->log("TCP", Log::ERR, "Received packet len = 0"); + return NULL; + } + + UCHAR* buffer = (UCHAR*) malloc(packetLength); + + success = readData(buffer, packetLength); + + if (!success) + { + Log::getInstance()->log("TCP", Log::ERR, "readData failed"); + free(buffer); + close(sock); + connected = 0; + return NULL; + } + + dataLength = packetLength; + return buffer; +} + +int TCP::getDataLength() +{ + return dataLength; +} + +int TCP::readData(UCHAR* buffer, int totalBytes) +{ + + int bytesRead = 0; + int thisRead; + int readTries = 0; + int success; + fd_set readSet; + struct timeval timeout; + struct timeval* passToSelect; + + if (timeoutEnabled) passToSelect = &timeout; + else passToSelect = NULL; + + while(1) + { + FD_ZERO(&readSet); + FD_SET(sock, &readSet); + timeout.tv_sec = 10; + timeout.tv_usec = 0; + success = select(sock + 1, &readSet, NULL, NULL, passToSelect); + if (success < 1) + { + Log::getInstance()->log("TCP", Log::ERR, "Error or timeout"); + return 0; // error, or timeout + } + + thisRead = read(sock, &buffer[bytesRead], totalBytes - bytesRead); + if (!thisRead) + { + // if read returns 0 then connection is closed + // in non-blocking mode if read is called with no data available, it returns -1 + // and sets errno to EGAGAIN. but we use select so it wouldn't do that anyway. + Log::getInstance()->log("TCP", Log::ERR, "Detected connection closed"); + connected = 0; + return 0; + } + bytesRead += thisRead; + + if (bytesRead == totalBytes) + { + return 1; + } + else + { + if (++readTries == 100) + { + Log::getInstance()->log("TCP", Log::ERR, "Too many reads"); + return 0; + } + } + } +} + +void TCP::dump(unsigned char* data, ULONG size) +{ + printf("Size = %lu\n", size); + + ULONG c = 0; + while(c < size) + { + if ((size - c) > 15) + { + printf(" %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c\n", + data[c], data[c+1], data[c+2], data[c+3], data[c+4], data[c+5], data[c+6], data[c+7], + data[c+8], data[c+9], data[c+10], data[c+11], data[c+12], data[c+13], data[c+14], data[c+15], + dcc(data[c]), dcc(data[c+1]), dcc(data[c+2]), dcc(data[c+3]), dcc(data[c+4]), dcc(data[c+5]), dcc(data[c+6]), dcc(data[c+7]), + dcc(data[c+8]), dcc(data[c+9]), dcc(data[c+10]), dcc(data[c+11]), dcc(data[c+12]), dcc(data[c+13]), dcc(data[c+14]), dcc(data[c+15])); + c += 16; + } + else + { + switch (size - c) + { + case 15: + printf(" %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %c%c%c%c%c%c%c%c%c%c%c%c%c%c%c\n", + data[c], data[c+1], data[c+2], data[c+3], data[c+4], data[c+5], data[c+6], data[c+7], + data[c+8], data[c+9], data[c+10], data[c+11], data[c+12], data[c+13], data[c+14], + dcc(data[c]), dcc(data[c+1]), dcc(data[c+2]), dcc(data[c+3]), dcc(data[c+4]), dcc(data[c+5]), dcc(data[c+6]), dcc(data[c+7]), + dcc(data[c+8]), dcc(data[c+9]), dcc(data[c+10]), dcc(data[c+11]), dcc(data[c+12]), dcc(data[c+13]), dcc(data[c+14])); + c += 15; + break; + case 14: + printf(" %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %c%c%c%c%c%c%c%c%c%c%c%c%c%c\n", + data[c], data[c+1], data[c+2], data[c+3], data[c+4], data[c+5], data[c+6], data[c+7], + data[c+8], data[c+9], data[c+10], data[c+11], data[c+12], data[c+13], + dcc(data[c]), dcc(data[c+1]), dcc(data[c+2]), dcc(data[c+3]), dcc(data[c+4]), dcc(data[c+5]), dcc(data[c+6]), dcc(data[c+7]), + dcc(data[c+8]), dcc(data[c+9]), dcc(data[c+10]), dcc(data[c+11]), dcc(data[c+12]), dcc(data[c+13])); + c += 14; + break; + case 13: + printf(" %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %c%c%c%c%c%c%c%c%c%c%c%c%c\n", + data[c], data[c+1], data[c+2], data[c+3], data[c+4], data[c+5], data[c+6], data[c+7], + data[c+8], data[c+9], data[c+10], data[c+11], data[c+12], + dcc(data[c]), dcc(data[c+1]), dcc(data[c+2]), dcc(data[c+3]), dcc(data[c+4]), dcc(data[c+5]), dcc(data[c+6]), dcc(data[c+7]), + dcc(data[c+8]), dcc(data[c+9]), dcc(data[c+10]), dcc(data[c+11]), dcc(data[c+12])); + c += 13; + break; + case 12: + printf(" %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %c%c%c%c%c%c%c%c%c%c%c%c\n", + data[c], data[c+1], data[c+2], data[c+3], data[c+4], data[c+5], data[c+6], data[c+7], + data[c+8], data[c+9], data[c+10], data[c+11], + dcc(data[c]), dcc(data[c+1]), dcc(data[c+2]), dcc(data[c+3]), dcc(data[c+4]), dcc(data[c+5]), dcc(data[c+6]), dcc(data[c+7]), + dcc(data[c+8]), dcc(data[c+9]), dcc(data[c+10]), dcc(data[c+11])); + c += 12; + break; + case 11: + printf(" %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %c%c%c%c%c%c%c%c%c%c%c\n", + data[c], data[c+1], data[c+2], data[c+3], data[c+4], data[c+5], data[c+6], data[c+7], + data[c+8], data[c+9], data[c+10], + dcc(data[c]), dcc(data[c+1]), dcc(data[c+2]), dcc(data[c+3]), dcc(data[c+4]), dcc(data[c+5]), dcc(data[c+6]), dcc(data[c+7]), + dcc(data[c+8]), dcc(data[c+9]), dcc(data[c+10])); + c += 11; + break; + case 10: + printf(" %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %c%c%c%c%c%c%c%c%c%c\n", + data[c], data[c+1], data[c+2], data[c+3], data[c+4], data[c+5], data[c+6], data[c+7], + data[c+8], data[c+9], + dcc(data[c]), dcc(data[c+1]), dcc(data[c+2]), dcc(data[c+3]), dcc(data[c+4]), dcc(data[c+5]), dcc(data[c+6]), dcc(data[c+7]), + dcc(data[c+8]), dcc(data[c+9])); + c += 10; + break; + case 9: + printf(" %02X %02X %02X %02X %02X %02X %02X %02X %02X %c%c%c%c%c%c%c%c%c\n", + data[c], data[c+1], data[c+2], data[c+3], data[c+4], data[c+5], data[c+6], data[c+7], + data[c+8], + dcc(data[c]), dcc(data[c+1]), dcc(data[c+2]), dcc(data[c+3]), dcc(data[c+4]), dcc(data[c+5]), dcc(data[c+6]), dcc(data[c+7]), + dcc(data[c+8])); + c += 9; + break; + case 8: + printf(" %02X %02X %02X %02X %02X %02X %02X %02X %c%c%c%c%c%c%c%c\n", + data[c], data[c+1], data[c+2], data[c+3], data[c+4], data[c+5], data[c+6], data[c+7], + dcc(data[c]), dcc(data[c+1]), dcc(data[c+2]), dcc(data[c+3]), dcc(data[c+4]), dcc(data[c+5]), dcc(data[c+6]), dcc(data[c+7])); + c += 8; + break; + case 7: + printf(" %02X %02X %02X %02X %02X %02X %02X %c%c%c%c%c%c%c\n", + data[c], data[c+1], data[c+2], data[c+3], data[c+4], data[c+5], data[c+6], + dcc(data[c]), dcc(data[c+1]), dcc(data[c+2]), dcc(data[c+3]), dcc(data[c+4]), dcc(data[c+5]), dcc(data[c+6])); + c += 7; + break; + case 6: + printf(" %02X %02X %02X %02X %02X %02X %c%c%c%c%c%c\n", + data[c], data[c+1], data[c+2], data[c+3], data[c+4], data[c+5], + dcc(data[c]), dcc(data[c+1]), dcc(data[c+2]), dcc(data[c+3]), dcc(data[c+4]), dcc(data[c+5])); + c += 6; + break; + case 5: + printf(" %02X %02X %02X %02X %02X %c%c%c%c%c\n", + data[c], data[c+1], data[c+2], data[c+3], data[c+4], + dcc(data[c]), dcc(data[c+1]), dcc(data[c+2]), dcc(data[c+3]), dcc(data[c+4])); + c += 5; + break; + case 4: + printf(" %02X %02X %02X %02X %c%c%c%c\n", + data[c], data[c+1], data[c+2], data[c+3], + dcc(data[c]), dcc(data[c+1]), dcc(data[c+2]), dcc(data[c+3])); + c += 4; + break; + case 3: + printf(" %02X %02X %02X %c%c%c\n", + data[c], data[c+1], data[c+2], + dcc(data[c]), dcc(data[c+1]), dcc(data[c+2])); + c += 3; + break; + case 2: + printf(" %02X %02X %c%c\n", + data[c], data[c+1], + dcc(data[c]), dcc(data[c+1])); + c += 2; + break; + case 1: + printf(" %02X %c\n", + data[c], + dcc(data[c])); + c += 1; + break; + } + } + } +} + +UCHAR TCP::dcc(UCHAR c) +{ + if (isspace(c)) return ' '; + if (isprint(c)) return c; + return '.'; +} diff --git a/tcp.h b/tcp.h new file mode 100644 index 0000000..5eeed6b --- /dev/null +++ b/tcp.h @@ -0,0 +1,69 @@ +/* + Copyright 2004-2005 Chris Tallon + Copyright 2003-2004 University Of Bradford + + This file is part of VOMP. + + VOMP 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. + + VOMP 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 VOMP; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#ifndef TCP_H +#define TCP_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "defines.h" +#include "log.h" + +class TCP +{ + public: + TCP(); + ~TCP(); + + int connectTo(char *host, unsigned short port); + void assignSocket(int tsocket); + + int isConnected(); + void disableTimeout(); + + int sendPacket(void *, size_t size); + UCHAR* receivePacket(); + int getDataLength(); + + int readData(UCHAR* buffer, int totalBytes); + + static void dump(unsigned char* data, ULONG size); + + private: + int sock; + int connected; + int timeoutEnabled; + int dataLength; + + static UCHAR dcc(UCHAR c); +}; + +#endif diff --git a/thread.cc b/thread.cc new file mode 100644 index 0000000..75b4281 --- /dev/null +++ b/thread.cc @@ -0,0 +1,92 @@ +/* + Copyright 2004-2005 Chris Tallon + + This file is part of VOMP. + + VOMP 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. + + VOMP 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 VOMP; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include "thread.h" + +// Undeclared functions, only for use in this file to start the thread +void threadInternalStart(void *arg) +{ + // I don't want signals + sigset_t sigset; + sigfillset(&sigset); + pthread_sigmask(SIG_BLOCK, &sigset, NULL); + + Thread *t = (Thread *)arg; + t->threadInternalStart2(); +} + +void Thread::threadInternalStart2() +{ + threadMethod(); +} + +int Thread::threadStart() +{ + pthread_cond_init(&threadCond, NULL); + pthread_mutex_init(&threadCondMutex, NULL); + + threadActive = 1; + if (pthread_create(&pthread, NULL, (void*(*)(void*))threadInternalStart, (void *)this) == -1) return 0; + return 1; +} + +void Thread::threadStop() +{ + threadActive = 0; + // Signal thread here in case it's waiting + threadSignal(); + pthread_join(pthread, NULL); +} + +void Thread::threadCancel() +{ + threadActive = 0; + pthread_cancel(pthread); + pthread_join(pthread, NULL); +} + +void Thread::threadCheckExit() +{ + if (!threadActive) pthread_exit(NULL); +} + +char Thread::threadIsActive() +{ + return threadActive; +} + +void Thread::threadSignal() +{ + pthread_mutex_lock(&threadCondMutex); + pthread_cond_signal(&threadCond); + pthread_mutex_unlock(&threadCondMutex); +} + +void Thread::threadSignalNoLock() +{ + pthread_cond_signal(&threadCond); +} + +void Thread::threadWaitForSignal() +{ + pthread_mutex_lock(&threadCondMutex); + pthread_cond_wait(&threadCond, &threadCondMutex); + pthread_mutex_unlock(&threadCondMutex); +} diff --git a/thread.h b/thread.h new file mode 100644 index 0000000..d57375a --- /dev/null +++ b/thread.h @@ -0,0 +1,57 @@ +/* + Copyright 2004-2005 Chris Tallon + + This file is part of VOMP. + + VOMP 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. + + VOMP 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 VOMP; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#ifndef THREAD_H +#define THREAD_H + +#include +#include + +class Thread +{ + protected: + // Override this method in derived classes + virtual void threadMethod()=0; + + // Methods to use from outside the thread + int threadStart(); // start the thread. threadMethod() will be called in derived class + void threadStop(); // stop the thread nicely. thread will be stopped when it next calls threadCheckExit() + void threadCancel(); // stop thread immediately. thread will be stopped at the next cancellation point + void threadSignal(); // releases a thread that has called threadWaitForSignal + void threadSignalNoLock(); // same as above but without locking guarantees. probably not a good idea. + char threadIsActive(); // returns 1 if thread has been started but not stop() or cancel() 'd + + // Methods to use from inside the thread + void threadCheckExit(); // terminates thread if threadStop() has been called + void threadWaitForSignal(); // pauses thread until threadSignal() is called + + // Internal bits and pieces + + private: + char threadActive; + pthread_t pthread; + pthread_cond_t threadCond; + pthread_mutex_t threadCondMutex; + + public: + void threadInternalStart2(); +}; + +#endif diff --git a/vchannellist.cc b/vchannellist.cc new file mode 100644 index 0000000..f1a818f --- /dev/null +++ b/vchannellist.cc @@ -0,0 +1,210 @@ +/* + Copyright 2004-2005 Chris Tallon + + This file is part of VOMP. + + VOMP 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. + + VOMP 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 VOMP; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include "vchannellist.h" + +VChannelList::VChannelList(ULONG type) +{ + setScreenPos(80, 70); + setDimensions(420, 570); + + setBackgroundColour(0, 0, 100, 255); + setTitleBarOn(1); + + if (type == VDR::VIDEO) + { + setTitleText("Channels"); + } + else if (type == VDR::RADIO) + { + setTitleText("Radio Stations"); + } + setTitleBarColour(0, 0, 200, 255); + + sl.setScreenPos(screenX + 10, screenY + 30 + 5); + sl.setDimensions(height - 30 - 15 - 30, width - 20); +} + +VChannelList::~VChannelList() +{ + if (chanList) + { + while (!chanList->isEmpty()) + { + chanList->reset(); + delete (Channel*)chanList->remove(); + } + + delete chanList; + } +} + +void VChannelList::setList(List* tlist) +{ + char str[500]; + + chanList = tlist; + + Channel* chan; + int first = 1; + if (chanList) + { + chanList->reset(); + + while((chan = (Channel*)chanList->getCurrent())) + { + sprintf(str, "%lu. %s", chan->number, chan->name); + chan->index = sl.addOption(str, first); + first = 0; + chanList->next(); + } + } +} + +void VChannelList::draw() +{ + View::draw(); + sl.draw(); + + // Put the status stuff at the bottom + + WSymbol w; + + w.nextSymbol = WSymbol::UP; + w.setScreenPos(screenX + 20, screenY + 385); + w.draw(); + + w.nextSymbol = WSymbol::DOWN; + w.setScreenPos(screenX + 50, screenY + 385); + w.draw(); + + w.nextSymbol = WSymbol::SKIPBACK; + w.setScreenPos(screenX + 85, screenY + 385); + w.draw(); + + w.nextSymbol = WSymbol::SKIPFORWARD; + w.setScreenPos(screenX + 115, screenY + 385); + w.draw(); + + w.nextSymbol = WSymbol::PLAY; + w.setScreenPos(screenX + 150, screenY + 385); + w.draw(); + + doShowingBar(); +} + +void VChannelList::doShowingBar() +{ + int topOption = sl.getTopOption() + 1; + if (sl.getNumOptions() == 0) topOption = 0; + + char showing[200]; + sprintf(showing, "%i to %i of %i", topOption, sl.getBottomOption(), sl.getNumOptions()); + Box b; + b.setScreenPos(screenX + 220, screenY + 385); + b.setDimensions(25, 160); + b.fillColour(0, 0, 100, 255); + b.drawText(showing, 0, 0, 255, 255, 255); +} + +int VChannelList::handleCommand(int command) +{ + if (command == Remote::UP) + { + sl.up(); + sl.draw(); + + doShowingBar(); + show(); + return 2; + } + else if (command == Remote::DOWN) + { + sl.down(); + sl.draw(); + + doShowingBar(); + show(); + return 2; + } + else if (command == Remote::SKIPBACK) + { + sl.pageUp(); + sl.draw(); + + doShowingBar(); + show(); + return 2; + } + else if (command == Remote::SKIPFORWARD) + { + sl.pageDown(); + sl.draw(); + + doShowingBar(); + show(); + return 2; + } + else if (command == Remote::OK) + { + Channel* chan = NULL; + if (chanList) + { + int currentOption = sl.getCurrentOption(); + chanList->reset(); + + while((chan = (Channel*)chanList->getCurrent())) + { + if (currentOption == chan->index) break; + chanList->next(); + } + } + + if (chan == NULL) return 2; + + View* v = NULL; + +// stop radio +// if (chan->type == VDR::RADIO) return 2; + + if (chan->type == VDR::VIDEO) + { + v = new VVideoLive(chanList); + ((VVideoLive*)v)->setChannel(chan->number); + } + else if (chan->type == VDR::RADIO) + { + v = new VRadioLive(chanList); + ((VRadioLive*)v)->setChannel(chan->number); + } + + ViewMan::getInstance()->addNoLock(v); + v->draw(); + v->show(); + + return 2; + } + else if (command == Remote::BACK) + { + return 4; + } + // stop command getting to any more views + return 1; +} diff --git a/vchannellist.h b/vchannellist.h new file mode 100644 index 0000000..d45196c --- /dev/null +++ b/vchannellist.h @@ -0,0 +1,58 @@ +/* + Copyright 2004-2005 Chris Tallon + + This file is part of VOMP. + + VOMP 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. + + VOMP 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 VOMP; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#ifndef VCHANNELLIST_H +#define VCHANNELLIST_H + +#include +#include + +#include "view.h" +#include "list.h" +#include "wselectlist.h" +#include "remote.h" +#include "wsymbol.h" +#include "viewman.h" +#include "vdr.h" +#include "channel.h" +#include "vvideolive.h" +#include "vradiolive.h" + +class VChannelList : public View +{ + public: + VChannelList(ULONG type); + ~VChannelList(); + + void setList(List* chanList); + + int handleCommand(int command); + void draw(); + + private: + List* chanList; + ULONG type; + + WSelectList sl; + + void doShowingBar(); +}; + +#endif diff --git a/vchannelselect.cc b/vchannelselect.cc new file mode 100644 index 0000000..b9e3c17 --- /dev/null +++ b/vchannelselect.cc @@ -0,0 +1,129 @@ +/* + Copyright 2004-2005 Chris Tallon + + This file is part of VOMP. + + VOMP 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. + + VOMP 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 VOMP; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include "vchannelselect.h" + +// this class only works as it does because the remote command +// values for the numbers are the numbers themselves ! + +VChannelSelect::VChannelSelect(VVideoLive* v, int command) +{ + setDimensions(30, 53); + setScreenPos(80, 60); + + setBackgroundColour(0, 0, 100, 255); + + first = -1; + second = -1; + third = command; + pos = 0; + + videoLive = v; +} + +void VChannelSelect::draw() +{ + View::draw(); + + // draw numbers + + char text[2]; + + switch(first) + { + case 0 ... 9: + { + sprintf(text, "%i", first); + drawText(text, 7, 5, 255, 255, 255); + break; + } + case -1: + { + drawText("_", 7, 5, 255, 255, 255); + break; + } + } + + switch(second) + { + case 0 ... 9: + { + sprintf(text, "%i", second); + drawText(text, 20, 5, 255, 255, 255); + break; + } + case -1: + { + drawText("_", 20, 5, 255, 255, 255); + break; + } + } + + switch(third) + { + case 0 ... 9: + { + sprintf(text, "%i", third); + drawText(text, 33, 5, 255, 255, 255); + break; + } + case -1: + { + drawText("_", 33, 5, 255, 255, 255); + break; + } + } +} + +int VChannelSelect::handleCommand(int command) +{ + switch(command) + { + case Remote::ZERO ... Remote::NINE: + { + if (pos == 1) first = second; + second = third; + third = command; + draw(); + show(); + if (pos == 1) + { + Message* m = new Message(); + m->from = this; + m->to = ViewMan::getInstance(); + m->message = Message::CLOSE_ME; + ViewMan::getInstance()->postMessage(m); + + m = new Message(); + m->from = this; + m->to = videoLive; + m->message = Message::CHANNEL_CHANGE; + m->parameter = (first * 100) + (second * 10) + third; + ViewMan::getInstance()->postMessage(m); + } + pos = 1; + + return 2; + } + } + + // allow command to drop through to other views + return 0; +} diff --git a/vchannelselect.h b/vchannelselect.h new file mode 100644 index 0000000..0c0461b --- /dev/null +++ b/vchannelselect.h @@ -0,0 +1,52 @@ +/* + Copyright 2004-2005 Chris Tallon + + This file is part of VOMP. + + VOMP 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. + + VOMP 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 VOMP; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#ifndef VCHANNELSELECT_H +#define VCHANNELSELECT_H + +#include + +#include "view.h" +#include "remote.h" +#include "vvideolive.h" +#include "message.h" +#include "viewman.h" + +class VVideoLive; + +class VChannelSelect : public View +{ + public: + VChannelSelect(VVideoLive* v, int command); + void draw(); + int handleCommand(int command); + + private: + int first; + int second; + int third; + + int pos; + + VVideoLive* videoLive; +}; + +#endif + diff --git a/vdr.cc b/vdr.cc new file mode 100644 index 0000000..6600856 --- /dev/null +++ b/vdr.cc @@ -0,0 +1,608 @@ +/* + Copyright 2004-2005 Chris Tallon + + This file is part of VOMP. + + VOMP 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. + + VOMP 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 VOMP; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include "vdr.h" + +VDR* VDR::instance = NULL; + +VDR::VDR() +{ + if (instance) return; + instance = this; + initted = 0; + findingServer = 0; + tcp = NULL; + pthread_mutex_init(&mutex, NULL); +} + +VDR::~VDR() +{ + instance = NULL; + if (initted) shutdown(); +} + +VDR* VDR::getInstance() +{ + return instance; +} + +int VDR::init(int tport) +{ + if (initted) return 0; + initted = 1; + port = tport; + logger = Log::getInstance(); + return 1; +} + +int VDR::shutdown() +{ + if (!initted) return 0; + initted = 0; + disconnect(); + return 1; +} + +void VDR::findServers(std::vector& serverIPs) +{ + findingServer = 1; + char* message = "VOMP CLIENT"; + DatagramSocket ds(port); + + int haveAtLeastOne = 0; + char* newIP; + int retval; + int waitType = 1; + while(findingServer) + { + if (waitType == 1) + { + logger->log("Core", Log::NOTICE, "Broadcasting for server"); + ds.send("255.255.255.255", 3024, message, strlen(message)); + } + retval = ds.waitforMessage(waitType); + + if (retval == 2) // we got a reply + { + if (strcmp(ds.getData(), "VOMP SERVER")) // echo..... + { + waitType = 2; + } + else + { + newIP = new char[16]; + strcpy(newIP, ds.getFromIPA()); + serverIPs.push_back(newIP); + waitType = 2; + haveAtLeastOne = 1; + } + } + else + { + if (haveAtLeastOne) break; + waitType = 1; + } + } +} + +void VDR::cancelFindingServer() +{ + findingServer = 0; +} + +void VDR::setServerIP(char* newIP) +{ + strcpy(serverIP, newIP); +} + +int VDR::connect() +{ + if (tcp) delete tcp; + tcp = new TCP(); + return tcp->connectTo(serverIP, 3024); +} + +void VDR::disconnect() +{ + if (tcp) delete tcp; + tcp = NULL; +} + +long VDR::getSimpleReply() +{ + unsigned char* p = (unsigned char*)tcp->receivePacket(); + if (!p) return -1; + + Log::getInstance()->log("VDR", Log::DEBUG, "tcp data length = %i", tcp->getDataLength()); + + if (tcp->getDataLength() != 4) + { + free(p); + return -1; + } + + ULONG reply = ntohl(*(ULONG*)p); + + Log::getInstance()->log("VDR", Log::DEBUG, "VDR said %li", reply); + + free(p); + + return reply; +} + +char* VDR::getStringReply() +{ + unsigned char* p = (unsigned char*)tcp->receivePacket(); + if (!p) return NULL; + + int dataLength = tcp->getDataLength(); + + Log::getInstance()->log("VDR", Log::DEBUG, "Data length %u", dataLength); + + int count = 0; + + char* returnText; + int tLength; + + tLength = strlen((char*)&p[count]); + returnText = new char[tLength + 1]; + strcpy(returnText, (char*)&p[count]); + count += tLength + 1; + + free(p); + + return returnText; +} + +///////////////////////////////////////////////////////////////////////////// + +int VDR::doLogin() +{ + UCHAR buffer[8]; + + *(unsigned long*)&buffer[0] = htonl(4); + *(unsigned long*)&buffer[4] = htonl(VDR_LOGIN); + + pthread_mutex_lock(&mutex); + int a = tcp->sendPacket(buffer, 8); + if (a != 8) + { + pthread_mutex_unlock(&mutex); + return 0; + } + + // reply + + UCHAR* p = tcp->receivePacket(); + pthread_mutex_unlock(&mutex); + if (!p) return 0; + + unsigned long vdrTime = ntohl(*(unsigned long*)p); + Log::getInstance()->log("VDR", Log::DEBUG, "vdrtime = %lu", vdrTime); + + struct timespec currentTime; + currentTime.tv_sec = vdrTime; + currentTime.tv_nsec = 0; + int b = clock_settime(CLOCK_REALTIME, ¤tTime); + + Log::getInstance()->log("VDR", Log::DEBUG, "set clock = %u", b); + + free(p); + return 1; +} + +Directory* VDR::getRecordingsList() +{ + UCHAR buffer[8]; + + *(unsigned long*)&buffer[0] = htonl(4); + *(unsigned long*)&buffer[4] = htonl(VDR_GETRECORDINGLIST); + + pthread_mutex_lock(&mutex); + int a = tcp->sendPacket(buffer, 8); + if (a != 8) + { + pthread_mutex_unlock(&mutex); + return NULL; + } + + // reply + + unsigned char* p = (unsigned char*)tcp->receivePacket(); + pthread_mutex_unlock(&mutex); + if (!p) return 0; + + Directory* recDir = new Directory(); + recDir->setName("/"); + recDir->isRoot = 1; + + int dataLength = tcp->getDataLength(); + + Log::getInstance()->log("VDR", Log::DEBUG, "Data length %u", dataLength); + + int count = 0; + + Directory::totalSpace = (*(ULONG*)&p[count]); + count += sizeof(ULONG); + Directory::freeSpace = (*(ULONG*)&p[count]); + count += sizeof(ULONG); + Directory::usedPercent = (*(ULONG*)&p[count]); + count += sizeof(ULONG); + + int tLength; + + while (count < dataLength) + { + Recording* rec = new Recording(); + rec->start = ntohl(*(unsigned long*)&p[count]); + count += 4; + + tLength = strlen((char*)&p[count]); + rec->setName((char*)&p[count]); + +// rec->name = new char[tLength + 1]; +// strcpy(rec->name, (char*)&p[count]); + count += tLength + 1; + + tLength = strlen((char*)&p[count]); + rec->fileName = new char[tLength + 1]; + strcpy(rec->fileName, (char*)&p[count]); + count += tLength + 1; + + if(rec->isInDir()) + { + char* dirName = rec->getDirName(); + + Directory* d = recDir->getDirByName(dirName); + if (!d) + { + d = new Directory(); + d->setName(dirName); + Log::getInstance()->log("VDR", Log::DEBUG, "Added a new directory = %s", d->name); + recDir->dirList->add(d); + } + + d->recList->add(rec); + d->recList->next(); + } + else + { + recDir->recList->add(rec); + recDir->recList->next(); + } + + Log::getInstance()->log("VDR", Log::DEBUG, "Have added a recording to list. %lu %s", rec->start, rec->getProgName()); + } + + free(p); + + return recDir; +} + +int VDR::deleteRecording(char* fileName) +{ + unsigned long totalLength = 8 + strlen(fileName) + 1; + UCHAR buffer[totalLength]; + + *(unsigned long*)&buffer[0] = htonl(totalLength - 4); + *(unsigned long*)&buffer[4] = htonl(VDR_DELETERECORDING); + strcpy((char*)&buffer[8], fileName); + + pthread_mutex_lock(&mutex); + unsigned int a = tcp->sendPacket(buffer, totalLength); + if (a != totalLength) + { + pthread_mutex_unlock(&mutex); + return 0; + } + + int toReturn = getSimpleReply(); + pthread_mutex_unlock(&mutex); + return toReturn; +} + +char* VDR::getRecordingSummary(char* fileName) +{ + unsigned long totalLength = 8 + strlen(fileName) + 1; + UCHAR buffer[totalLength]; + + *(unsigned long*)&buffer[0] = htonl(totalLength - 4); + *(unsigned long*)&buffer[4] = htonl(VDR_GETSUMMARY); + strcpy((char*)&buffer[8], fileName); + + pthread_mutex_lock(&mutex); + unsigned int a = tcp->sendPacket(buffer, totalLength); + if (a != totalLength) + { + pthread_mutex_unlock(&mutex); + return NULL; + } + + char* toReturn = getStringReply(); + pthread_mutex_unlock(&mutex); + return toReturn; +} + +List* VDR::getChannelsList(ULONG type) +{ + UCHAR buffer[8]; + + *(unsigned long*)&buffer[0] = htonl(4); + *(unsigned long*)&buffer[4] = htonl(VDR_GETCHANNELLIST); + + pthread_mutex_lock(&mutex); + int a = tcp->sendPacket(buffer, 8); + if (a != 8) + { + pthread_mutex_unlock(&mutex); + return NULL; + } + + // reply + + unsigned char* p = (unsigned char*)tcp->receivePacket(); + pthread_mutex_unlock(&mutex); + if (!p) return NULL; + + List* chanList = new List(); + + int dataLength = tcp->getDataLength(); + + Log::getInstance()->log("VDR", Log::DEBUG, "Data length %u", dataLength); + + int count = 0; + + int tLength; + + while (count < dataLength) + { + Channel* chan = new Channel(); + chan->number = ntohl(*(unsigned long*)&p[count]); + count += 4; + chan->type = ntohl(*(unsigned long*)&p[count]); + count += 4; + + tLength = strlen((char*)&p[count]); + chan->name = new char[tLength + 1]; + strcpy(chan->name, (char*)&p[count]); + count += tLength + 1; + + if (chan->type == type) + { + chanList->add(chan); + chanList->next(); + Log::getInstance()->log("VDR", Log::DEBUG, "Have added a channel to list. %lu %lu %s", chan->number, chan->type, chan->name); + } + else + { + delete chan; + } + } + + free(p); + + return chanList; +} + +int VDR::streamChannel(ULONG number) +{ + UCHAR buffer[12]; + + *(unsigned long*)&buffer[0] = htonl(8); + *(unsigned long*)&buffer[4] = htonl(VDR_STREAMCHANNEL); + *(unsigned long*)&buffer[8] = htonl(number); + + pthread_mutex_lock(&mutex); + int a = tcp->sendPacket(buffer, 12); + + if (a != 12) + { + pthread_mutex_unlock(&mutex); + return 0; + } + + int toReturn = getSimpleReply(); + pthread_mutex_unlock(&mutex); + return toReturn; +} + +int VDR::stopStreaming() +{ + UCHAR buffer[8]; + + *(unsigned long*)&buffer[0] = htonl(4); + *(unsigned long*)&buffer[4] = htonl(VDR_STOPSTREAMING); + + pthread_mutex_lock(&mutex); + int a = tcp->sendPacket(buffer, 8); + + if (a != 8) + { + pthread_mutex_unlock(&mutex); + return 0; + } + + int toReturn = getSimpleReply(); + pthread_mutex_unlock(&mutex); + return toReturn; +} + +int VDR::getBlock(UCHAR* buf, ULLONG position, int amount) +{ + UCHAR buffer[20]; + + *(unsigned long*)&buffer[0] = htonl(16); + *(unsigned long*)&buffer[4] = htonl(VDR_GETBLOCK); + *(ULLONG*)&buffer[8] = htonll(position); + *(unsigned long*)&buffer[16] = htonl(amount); + + pthread_mutex_lock(&mutex); + int a = tcp->sendPacket(buffer, 20); + if (a != 20) + { + pthread_mutex_unlock(&mutex); + return 0; + } + + unsigned char* p = (unsigned char*)tcp->receivePacket(); + pthread_mutex_unlock(&mutex); + if (!p) return 0; + int dataLength = tcp->getDataLength(); + + memcpy(buf, p, dataLength); + free(p); + return dataLength; +} + +ULLONG VDR::streamRecording(Recording* rec) +{ + unsigned long totalLength = 8 + strlen(rec->fileName) + 1; + UCHAR buffer[totalLength]; + + *(unsigned long*)&buffer[0] = htonl(totalLength - 4); + *(unsigned long*)&buffer[4] = htonl(VDR_STREAMRECORDING); + strcpy((char*)&buffer[8], rec->fileName); + + pthread_mutex_lock(&mutex); + unsigned int a = tcp->sendPacket(buffer, totalLength); + if (a != totalLength) + { + pthread_mutex_unlock(&mutex); + return 0; + } + + unsigned char* p = (unsigned char*)tcp->receivePacket(); + pthread_mutex_unlock(&mutex); + if (!p) return 0; + + if (tcp->getDataLength() != 8) + { + free(p); + return 0; + } + + ULLONG recordingLength = ntohll(*(ULLONG*)p); + + Log::getInstance()->log("VDR", Log::DEBUG, "VDR said length is: %llu", recordingLength); + free(p); + + return recordingLength; +} + +int VDR::getChannelSchedule(ULONG number) +{ + UCHAR buffer[12]; + + *(unsigned long*)&buffer[0] = htonl(8); + *(unsigned long*)&buffer[4] = htonl(VDR_GETCHANNELSCHEDULE); + *(unsigned long*)&buffer[8] = htonl(number); + + pthread_mutex_lock(&mutex); + int a = tcp->sendPacket(buffer, 12); + + if (a != 12) + { + pthread_mutex_unlock(&mutex); + return -1; + } + + unsigned char* p = (unsigned char*)tcp->receivePacket(); + pthread_mutex_unlock(&mutex); + if (!p) return -1; + + int dataLength = tcp->getDataLength(); + + if (dataLength != 4) + { + free(p); + return -1; + } + + ULONG data = ntohl(*(ULONG*)p); + free(p); + + Log::getInstance()->log("VDR", Log::DEBUG, "Success got to end of getChannelSchedule %lu", data); + + return data; +} + +ULLONG VDR::getResumePoint(char* fileName) +{ + char* resumeString = configLoad("ResumeData", fileName); + if (!resumeString) return 0; + + ULLONG toReturn = strtoull(resumeString, NULL, 10); + delete[] resumeString; + return toReturn; +} + +int VDR::configSave(char* section, char* key, char* value) +{ + ULONG totalLength = 8 + strlen(section) + strlen(key) + strlen(value) + 3; // 8 for headers, 3 for nulls + UCHAR buffer[totalLength]; + + *(unsigned long*)&buffer[0] = htonl(totalLength - 4); + *(unsigned long*)&buffer[4] = htonl(VDR_CONFIGSAVE); + + int position = 8; + strcpy((char*)&buffer[position], section); + position += strlen(section) + 1; + strcpy((char*)&buffer[position], key); + position += strlen(key) + 1; + strcpy((char*)&buffer[position], value); + + pthread_mutex_lock(&mutex); + unsigned int a = tcp->sendPacket(buffer, totalLength); + if (a != totalLength) + { + pthread_mutex_unlock(&mutex); + return 0; + } + + int toReturn = getSimpleReply(); + pthread_mutex_unlock(&mutex); + return toReturn; +} + +char* VDR::configLoad(char* section, char* key) +{ + ULONG totalLength = 8 + strlen(section) + strlen(key) + 2; // 8 for headers, 2 for nulls + UCHAR buffer[totalLength]; + + *(unsigned long*)&buffer[0] = htonl(totalLength - 4); + *(unsigned long*)&buffer[4] = htonl(VDR_CONFIGLOAD); + + int position = 8; + strcpy((char*)&buffer[position], section); + position += strlen(section) + 1; + strcpy((char*)&buffer[position], key); + + pthread_mutex_lock(&mutex); + unsigned int a = tcp->sendPacket(buffer, totalLength); + if (a != totalLength) + { + pthread_mutex_unlock(&mutex); + return NULL; + } + + char* toReturn = getStringReply(); + pthread_mutex_unlock(&mutex); + return toReturn; +} diff --git a/vdr.h b/vdr.h new file mode 100644 index 0000000..9144a15 --- /dev/null +++ b/vdr.h @@ -0,0 +1,107 @@ +/* + Copyright 2004-2005 Chris Tallon + + This file is part of VOMP. + + VOMP 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. + + VOMP 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 VOMP; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#ifndef VDR_H +#define VDR_H + +#include +#include +#include +#include + +#include "defines.h" +#include "log.h" +#include "dsock.h" +#include "tcp.h" +#include "list.h" +#include "directory.h" +#include "recording.h" +#include "channel.h" + + // FIXME do some tcp connection error checking and kill it! + +class VDR +{ + public: + VDR(); + ~VDR(); + static VDR* getInstance(); + + int init(int port); + int shutdown(); + + void findServers(std::vector& serverIPs); + void cancelFindingServer(); + void setServerIP(char*); + int connect(); + void disconnect(); + ULLONG getResumePoint(char* fileName); // uses configLoad + + // protocol functions + + int doLogin(); + + Directory* getRecordingsList(); + char* getRecordingSummary(char* fileName); + int deleteRecording(char* fileName); + ULLONG streamRecording(Recording* rec); + + List* getChannelsList(ULONG type); + int streamChannel(ULONG number); + + int getBlock(UCHAR* buf, ULLONG position, int maxAmount); + int stopStreaming(); + int getChannelSchedule(ULONG number); + int configSave(char* section, char* key, char* value); + char* configLoad(char* section, char* key); + + // end + + const static ULONG VIDEO = 1; + const static ULONG RADIO = 2; + + private: + static VDR* instance; + Log* logger; + int initted; + int findingServer; + TCP* tcp; + int port; + char serverIP[16]; + pthread_mutex_t mutex; + + const static ULONG VDR_LOGIN = 1; + const static ULONG VDR_GETRECORDINGLIST = 2; + const static ULONG VDR_DELETERECORDING = 3; + const static ULONG VDR_GETSUMMARY = 4; + const static ULONG VDR_GETCHANNELLIST = 5; + const static ULONG VDR_STREAMCHANNEL = 6; + const static ULONG VDR_GETBLOCK = 7; + const static ULONG VDR_STOPSTREAMING = 8; + const static ULONG VDR_STREAMRECORDING = 9; + const static ULONG VDR_GETCHANNELSCHEDULE = 10; + const static ULONG VDR_CONFIGSAVE = 11; + const static ULONG VDR_CONFIGLOAD = 12; + + long getSimpleReply(); + char* getStringReply(); +}; + +#endif diff --git a/vfeed.cc b/vfeed.cc new file mode 100644 index 0000000..7dc9a1b --- /dev/null +++ b/vfeed.cc @@ -0,0 +1,72 @@ +/* + Copyright 2004-2005 Chris Tallon + + This file is part of VOMP. + + VOMP 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. + + VOMP 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 VOMP; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include "vfeed.h" + +VFeed::VFeed(Callback* tcb) +: cb(*tcb) +{ + delayTime.tv_sec = 0; + delayTime.tv_nsec = 100000000; +} + +int VFeed::init(int tfd) +{ + fd = tfd; + return 1; +} + +int VFeed::shutdown() +{ + // FIXME + return 1; +} + +int VFeed::start() +{ + return threadStart(); +} + +void VFeed::stop() +{ + threadCancel(); +} + +void VFeed::threadMethod() +{ + Log::getInstance()->log("VFeed", Log::DEBUG, "Started"); + + int vlen; + + while(1) + { + vlen = Demuxer::getInstance()->writeVideo(fd); // FIXME + if (vlen) + { + Log::getInstance()->log("VFeed", Log::DEBUG, "Written %i", vlen); + cb.call(); + } + else + { + nanosleep(&delayTime, NULL); + } + } +} + diff --git a/vfeed.h b/vfeed.h new file mode 100644 index 0000000..2e7019b --- /dev/null +++ b/vfeed.h @@ -0,0 +1,51 @@ +/* + Copyright 2004-2005 Chris Tallon + + This file is part of VOMP. + + VOMP 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. + + VOMP 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 VOMP; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#ifndef VFEED_H +#define VFEED_H + +#include +#include + +#include "log.h" +#include "thread.h" +#include "demuxer.h" +#include "callback.h" + +class VFeed : public Thread +{ + public: + VFeed(Callback* tcb); + + int init(int fd); + int shutdown(); + + int start(); + void stop(); + + private: + void threadMethod(); + int fd; + Callback& cb; + struct timespec delayTime; + +}; + +#endif diff --git a/video.cc b/video.cc new file mode 100644 index 0000000..608f7b3 --- /dev/null +++ b/video.cc @@ -0,0 +1,304 @@ +/* + Copyright 2004-2005 Chris Tallon + + This file is part of VOMP. + + VOMP 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. + + VOMP 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 VOMP; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include "video.h" + +Video* Video::instance = NULL; + +Video::Video() +{ + if (instance) return; + instance = this; + initted = 0; + + fdVideo = 0; + + format = 0; + connection = 0; + aspectRatio = 0; + mode = 0; +} + +Video::~Video() +{ + instance = NULL; +} + +Video* Video::getInstance() +{ + return instance; +} + +int Video::init(UCHAR format, UCHAR connection, UCHAR aspectRatio, UCHAR mode) +{ + if (initted) return 0; + initted = 1; + +// if ((fdVideo = open("/dev/vdec_dev", O_RDWR | O_NONBLOCK)) < 0) return 0; + if ((fdVideo = open("/dev/vdec_dev", O_WRONLY)) < 0) return 0; + + this->format = format; + this->connection = connection; + this->aspectRatio = aspectRatio; + this->mode = mode; + + if (!initAllParams()) + { + shutdown(); + return 0; + } + + attachFrameBuffer(); + stop(); + + return 1; +} + +int Video::initAllParams() +{ + return (setFormat(format) && setConnection(connection) && + setAspectRatio(aspectRatio) && setMode(mode) && setSource()); +} + +int Video::shutdown() +{ + if (!initted) return 0; + initted = 0; + close(fdVideo); + return 1; +} + +int Video::write(char *buf, int len) +{ + return 1;//write(fdVideo, buf, len); +} + +int Video::setFormat(UCHAR format) +{ + if (!initted) return 0; + if ((format != PAL) && (format != NTSC)) return 0; + + if (ioctl(fdVideo, AV_SET_VID_DISP_FMT, format) != 0) return 0; + this->format = format; + return 1; +} + +int Video::setConnection(UCHAR connection) +{ + if (!initted) return 0; + if ((connection != SCART) && (connection != COMPOSITE) && (connection != SVIDEO)) return 0; + + if (ioctl(fdVideo, AV_SET_VID_OUTPUT, connection) != 0) return 0; + this->connection = connection; + return 1; +} + +int Video::setAspectRatio(UCHAR aspectRatio) +{ + if (!initted) return 0; + if ((aspectRatio != ASPECT4X3) && (aspectRatio != ASPECT16X9)) return 0; + + if (ioctl(fdVideo, AV_SET_VID_RATIO, aspectRatio) != 0) return 0; + this->aspectRatio = aspectRatio; + return 1; +} + +int Video::setMode(UCHAR mode) +{ + if (!initted) return 0; + + if ((mode != NORMAL) && (mode != LETTERBOX) && (mode != UNKNOWN2) && (mode != QUARTER) && (mode != EIGHTH) + && (mode != ZOOM) && (mode != UNKNOWN6)) return 0; + +// mode = LETTERBOX; + + if (ioctl(fdVideo, AV_SET_VID_MODE, mode) != 0) return 0; + this->mode = mode; + return 1; +} + +int Video::test() +{ + return 0; + +// ULLONG stc = 0; +// return ioctl(fdVideo, AV_SET_VID_STC, &stc); +/* + // reset(); + return 1; +*/ +} + +int Video::test2() +{ + return 0; +} + + + +int Video::signalOff() +{ + if (ioctl(fdVideo, AV_SET_VID_DENC, 0) != 0) return 0; + return 1; +} + +int Video::signalOn() +{ + if (ioctl(fdVideo, AV_SET_VID_DENC, 1) != 0) return 0; + return 1; +} + +int Video::setSource() +{ + if (!initted) return 0; + + // What does this do... + if (ioctl(fdVideo, AV_SET_VID_SRC, 1) != 0) return 0; + return 1; +} + +int Video::setPosition(int x, int y) +{ + if (!initted) return 0; + + vid_pos_regs_t pos_d; + pos_d.x = x; + pos_d.y = y; + +/* +typedef struct { + int w; + int h; + int scale; + int x1; + int y; + int x; + int y2; + int x3; + int y3; + int x4; + int y4; +} vid_pos_regs_t; +*/ + +/* + pos_d.w = 100; + pos_d.h = 30; + pos_d.scale = 2; + pos_d.x1 = 0; + pos_d.y = 100; // Top left X + pos_d.x = 50; // Top left Y + pos_d.y2 = 30; + pos_d.x3 = 60; + pos_d.y3 = 90; + pos_d.x4 = 120; + pos_d.y4 = 150; +*/ + + if (ioctl(fdVideo, AV_SET_VID_POSITION, &pos_d) != 0) return 0; + return 1; +} + +int Video::sync() +{ + if (!initted) return 0; + + if (ioctl(fdVideo, AV_SET_VID_SYNC, 2) != 0) return 0; + return 1; +} + +int Video::play() +{ + if (!initted) return 0; + + if (ioctl(fdVideo, AV_SET_VID_PLAY, 0) != 0) return 0; + return 1; +} + +int Video::stop() +{ + if (!initted) return 0; + + if (ioctl(fdVideo, AV_SET_VID_STOP, 0) != 0) return 0; + return 1; +} + +int Video::reset() +{ + if (!initted) return 0; + + if (ioctl(fdVideo, AV_SET_VID_RESET, 0x11) != 0) return 0; + return 1; +} + +int Video::pause() +{ + if (!initted) return 0; + + if (ioctl(fdVideo, AV_SET_VID_PAUSE, 0) != 0) return 0; + return 1; +} + +int Video::unPause() +{ + if (!initted) return 0; + if (ioctl(fdVideo, AV_SET_VID_PLAY, 0) != 0) return 0; + return 1; +} + +int Video::fastForward() +{ + if (!initted) return 0; + + if (ioctl(fdVideo, AV_SET_VID_FFWD, 1) != 0) return 0; + return 1; +} + +int Video::unFastForward() +{ + if (!initted) return 0; + +// if (ioctl(fdVideo, AV_SET_VID_RESET, 0x11) != 0) return 0; // don't need this. + + if (ioctl(fdVideo, AV_SET_VID_PLAY, 0) != 0) return 0; + return 1; +} + +int Video::attachFrameBuffer() +{ + if (!initted) return 0; + + if (ioctl(fdVideo, AV_SET_VID_FB, 0) != 0) return 0; + return 1; +} + +int Video::blank(void) +{ + if (ioctl(fdVideo, AV_SET_VID_FB, 1) != 0) return 0; + if (ioctl(fdVideo, AV_SET_VID_FB, 0) != 0) return 0; + return 1; +} + +int Video::getFD() +{ + if (!initted) return 0; + + return fdVideo; +} diff --git a/video.h b/video.h new file mode 100644 index 0000000..ba6ff77 --- /dev/null +++ b/video.h @@ -0,0 +1,111 @@ +/* + Copyright 2004-2005 Chris Tallon + + This file is part of VOMP. + + VOMP 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. + + VOMP 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 VOMP; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +// Thanks to Jon Gettler and BtB of the MVPMC project for all the hardware information + + +#ifndef VIDEO_H +#define VIDEO_H + +// FIXME - check why so many things include unistd + +#include +#include +#include +#include + +#include "defines.h" +#include "stb.h" + +class Video +{ + public: + Video(); + ~Video(); + static Video* getInstance(); + + int init(UCHAR format, UCHAR connection, UCHAR aspectRatio, UCHAR mode); + int shutdown(); + + // Video formats - AV_SET_VID_DISP_FMT + const static UCHAR NTSC = 0; + const static UCHAR PAL = 1; + + // Video connections - AV_SET_VID_OUTPUT + const static UCHAR SCART = 0; + const static UCHAR COMPOSITE = 1; + const static UCHAR SVIDEO = 2; + + // Video aspect ratios - AV_SET_VID_RATIO + const static UCHAR ASPECT4X3 = 0; + const static UCHAR ASPECT16X9 = 1; + + // Video modes - AV_SET_VID_MODE + const static UCHAR NORMAL = 0; // If aspect==4:3, 4:3 unknown / 16:9 chop sides + // If aspect==16:9, 4:3 unknown / 16:9 stretch middle over all screen + const static UCHAR LETTERBOX = 1; // If aspect==4:3, 4:3 unknown / 16:9 letterbox at top of screen (!!) + // If aspect==16:9, 4:3 unknown / 16:9 proper 16:9 mode + const static UCHAR UNKNOWN2 = 2; + const static UCHAR QUARTER = 3; + const static UCHAR EIGHTH = 4; + const static UCHAR ZOOM = 5; + const static UCHAR UNKNOWN6 = 6; + + int setFormat(UCHAR format); + int setConnection(UCHAR connection); + int setAspectRatio(UCHAR aspectRatio); + int setMode(UCHAR mode); + int test(); + int test2(); + int setSource(); + int setPosition(int x, int y); + int sync(); + int play(); + int stop(); + int pause(); + int unPause(); + int fastForward(); + int unFastForward(); + int reset(); + int blank(); + int signalOn(); + int signalOff(); + + int attachFrameBuffer(); // What does this do? + + int write(char *buf, int len); + + int getFD(); + + private: + static Video* instance; + int initted; + + int initAllParams(); + + int fdVideo; + + UCHAR format; + UCHAR connection; + UCHAR aspectRatio; + UCHAR mode; +}; + +#endif diff --git a/view.cc b/view.cc new file mode 100644 index 0000000..e39115f --- /dev/null +++ b/view.cc @@ -0,0 +1,123 @@ +/* + Copyright 2004-2005 Chris Tallon + + This file is part of VOMP. + + VOMP 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. + + VOMP 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 VOMP; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include "view.h" + +char View::numViews = 0; + +View::View() +{ + height = 0; + width = 0; + screenX = 0; + screenY = 0; + + delSec = 0; + delNSec = 0; + seconds = 0; + + backgroundR = 0; + backgroundG = 0; + backgroundB = 0; + backgroundA = 0; + + titleBarR = 0; + titleBarG = 0; + titleBarB = 0; + titleBarA = 0; + + titleBarOn = 0; + borderOn = 0; + + titleText = NULL; + + numViews++; + Log::getInstance()->log("View", Log::DEBUG, "Construct %p, now %u", this, numViews); +} + +View::~View() +{ + if (titleText) delete[] titleText; + + numViews--; + Log::getInstance()->log("View", Log::DEBUG, "Destruct, now %u", numViews); +} + +void View::setTitleText(char* takeText) +{ + int length = strlen(takeText); + titleText = new char[length + 1]; + strcpy(titleText, takeText); +} + +void View::draw() +{ + + if (borderOn) + { + rectangle(0, 0, width, height, titleBarR, titleBarG, titleBarB, titleBarA); + rectangle(5, 5, width-10, height-10, backgroundR, backgroundG, backgroundB, backgroundA); + } + else + { + fillColour(backgroundR, backgroundG, backgroundB, backgroundA); + } + + if (titleBarOn) + { + rectangle(0, 0, width, 30, titleBarR, titleBarG, titleBarB, titleBarA); + if (titleText) drawText(titleText, 5, 5, 255, 255, 255); + } +} + +int View::handleCommand(int command) +{ + return 0; +} + +void View::processMessage(Message* m) +{ +} + +void View::setBackgroundColour(UCHAR r, UCHAR g, UCHAR b, UCHAR a) +{ + backgroundR = r; + backgroundG = g; + backgroundB = b; + backgroundA = a; +} + +void View::setTitleBarColour(UCHAR r, UCHAR g, UCHAR b, UCHAR a) +{ + titleBarR = r; + titleBarG = g; + titleBarB = b; + titleBarA = a; +} + +void View::setTitleBarOn(UCHAR on) +{ + titleBarOn = on; +} + +void View::setBorderOn(UCHAR on) +{ + borderOn = on; +} diff --git a/view.h b/view.h new file mode 100644 index 0000000..d70d566 --- /dev/null +++ b/view.h @@ -0,0 +1,74 @@ +/* + Copyright 2004-2005 Chris Tallon + + This file is part of VOMP. + + VOMP 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. + + VOMP 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 VOMP; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#ifndef VIEW_H +#define VIEW_H + +#include + +#include "log.h" +#include "box.h" +#include "defines.h" +#include "message.h" + +class View : public Box +{ + public: + View(); + virtual ~View(); + + virtual void draw(); + virtual int handleCommand(int command); + + void setBorderOn(UCHAR on); + void setTitleBarOn(UCHAR on); + void setTitleText(char* title); + void setBackgroundColour(UCHAR r, UCHAR g, UCHAR b, UCHAR a); + void setTitleBarColour(UCHAR r, UCHAR g, UCHAR b, UCHAR a); + + // For use by ViewMan + long delSec; + long delNSec; + int seconds; + // + + virtual void processMessage(Message* m); + + private: + static char numViews; + + UCHAR backgroundR; + UCHAR backgroundG; + UCHAR backgroundB; + UCHAR backgroundA; + + UCHAR titleBarOn; + UCHAR borderOn; + + char* titleText; + + protected: + UCHAR titleBarR; + UCHAR titleBarG; + UCHAR titleBarB; + UCHAR titleBarA; +}; + +#endif diff --git a/viewman.cc b/viewman.cc new file mode 100644 index 0000000..4ab9ad4 --- /dev/null +++ b/viewman.cc @@ -0,0 +1,540 @@ +/* + Copyright 2004-2005 Chris Tallon + + This file is part of VOMP. + + VOMP 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. + + VOMP 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 VOMP; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include "viewman.h" + +ViewMan* ViewMan::instance = NULL; + +ViewMan::ViewMan() +{ + if (instance) return; + instance = this; + initted = 0; + topView = 0; + resetThreadFlag = 0; + autoDeleteThreadRun = 0; + callFromThread = 0; +} + +ViewMan::~ViewMan() +{ + instance = NULL; +} + +ViewMan* ViewMan::getInstance() +{ + return instance; +} + +int ViewMan::init() +{ + if (initted) return 0; + pthread_mutex_init(&viewManLock, NULL); + pthread_cond_init(&autoDeleteThreadSignal, NULL); + if (!startAutoDeleteThread()) return 0; + initted = 1; + return 1; +} + +int ViewMan::shutdown() +{ + if (!initted) return 0; + + removeAll(); + + // get the lock here to ensure that the thread is waiting on the cond + pthread_mutex_lock(&viewManLock); + autoDeleteThreadRun = 0; + pthread_cond_signal(&autoDeleteThreadSignal); + pthread_mutex_unlock(&viewManLock); + pthread_join(autoDeleteThread, NULL); + initted = 0; + return 1; +} + +int ViewMan::add(View* v) +{ + if (!initted) return 0; + if (topView == 10) return 0; + + pthread_mutex_lock(&viewManLock); + + topView++; + views[topView] = v; + + resetThread(); + pthread_mutex_unlock(&viewManLock); + + return 1; +} + +int ViewMan::addNoLock(View* v) +{ + if (!initted) return 0; + if (topView == 10) return 0; + + topView++; + views[topView] = v; + + resetThread(); + + return 1; +} + + +// ---------------------------------------------------- REMOVE CODE + +int ViewMan::removeView(View* toDelete, int noLock, int noShow) +{ + if (!initted) return 0; + if (topView == 0) return 0; + + if (!noLock) pthread_mutex_lock(&viewManLock); + + Log::getInstance()->log("ViewMan", Log::DEBUG, "entering remove, %u topview", topView); + + int i; + int wasTopView = 0; + int slotTakenFrom = 0; + + if (toDelete == NULL) + { + toDelete = views[topView]; + i = topView; + wasTopView = 1; + } + else + { + // to be deleted view is more likely to be at the top + + + for (i = topView; i > 0; i--) + { + if (views[i] == toDelete) + { + if (i == topView) wasTopView = 1; + break; + } + } + + if (i == 0) + { + // not a View we have! + pthread_mutex_unlock(&viewManLock); + return 0; + } + } + + // Save the position we are deleting the view from + slotTakenFrom = i; + + // Shift the views on top down one + for(; i < topView; i++) + { + views[i] = views[i + 1]; + } + topView--; + + // Done. Now on to drawing. + + View* newTopBox = views[topView]; // just to make second optimisation easier + + // First optimisation. If there are no views left, don't do anything! + if (topView == 0) + { + Log::getInstance()->log("ViewMan", Log::DEBUG, "re-draw using optimisation 1"); + } + + // second optimisation. if view being deleted is entirely within the view underneath it, + // and was the top most box, + // only need to redraw the one underneath + else if ( wasTopView + && (toDelete->getScreenX() >= newTopBox->getScreenX()) + && (toDelete->getScreenY() >= newTopBox->getScreenY()) + && ((toDelete->getScreenX() + toDelete->getWidth()) <= (newTopBox->getScreenX() + newTopBox->getWidth())) + && ((toDelete->getScreenY() + toDelete->getHeight()) <= (newTopBox->getScreenY() + newTopBox->getHeight())) + ) + { + newTopBox->draw(); + newTopBox->show(); + Log::getInstance()->log("ViewMan", Log::DEBUG, "re-draw using optimisation 2"); + } + + // third optimisation. if the box being deleted is totally within one above it, don't do anything + else if ((slotTakenFrom <= topView) && isTotallyCovered(toDelete, slotTakenFrom)) + { + Log::getInstance()->log("ViewMan", Log::DEBUG, "re-draw using optimisation 3"); + } + + // no optimisations left, redo everything. + else + { + redrawAll(noShow); + Log::getInstance()->log("ViewMan", Log::DEBUG, "re-draw using no optimisation"); + } + + // Delete the view + delete toDelete; + + resetThread(); + if (!noLock) pthread_mutex_unlock(&viewManLock); + + return 1; +} + +int ViewMan::isTotallyCovered(View* toDelete, int slotTakenFrom) +{ + int todelx1 = toDelete->getScreenX(); + int todelx2 = toDelete->getScreenX() + toDelete->getWidth(); + int todely1 = toDelete->getScreenY(); + int todely2 = toDelete->getScreenY() + toDelete->getHeight(); + + int x1 = 999999; + int x2 = 0; + int y1 = 999999; + int y2 = 0; + + int currentx1; + int currentx2; + int currenty1; + int currenty2; + + for (int i = slotTakenFrom; i <= topView; i++) + { + currentx1 = views[i]->getScreenX(); + currentx2 = currentx1 + views[i]->getWidth(); + currenty1 = views[i]->getScreenY(); + currenty2 = currenty1 + views[i]->getHeight(); + +// printf("Iteration in tc before. i=%i x1=%i x2=%i y1=%i y2=%i cx1=%i cx2=%i cy1=%i cy2=%i\n", i, x1, x2, y1, y2, currentx1, currentx2, currenty1, currenty2); + + if (currentx1 < x1) x1 = currentx1; + if (currentx2 > x2) x2 = currentx2; + if (currenty1 < y1) y1 = currenty1; + if (currenty2 > y2) y2 = currenty2; + +// printf("Iteration in tc after . i=%i x1=%i x2=%i y1=%i y2=%i\n", i, x1, x2, y1, y2); + } + + // k, now x1 x2 y1 y2 contain the dimensions of the biggest box over the deleted slot + + if ( (x1 <= todelx1) + && (x2 >= todelx2) + && (y1 <= todely1) + && (y2 >= todely2) + ) + { + return 1; + } + else + { + return 0; + } +} + +void ViewMan::redrawAll(int noShow) +{ + for (int i = 1; i <= topView; i++) + { + views[i]->draw(); + } + + if (!noShow) Box::showAll(); +} + +// ---------------------------------------------------- END OF REMOVE CODE + + +void ViewMan::removeAll() +{ + pthread_mutex_lock(&viewManLock); + + // FIXME for don't delete wallpaper cos surface destroy doesn't work + + for (; topView > 1; topView--) + { + delete views[topView]; + } + + resetThread(); + pthread_mutex_unlock(&viewManLock); +} + +int ViewMan::handleCommand(UCHAR command) +{ + pthread_mutex_lock(&viewManLock); + + int retVal; + int retVal2 = 0; + int i; + + // handle command return values + // 0 - drop through to next view + // 1 - dont drop to next view, but not handled + // 2 - handled - stop command here + // 4 - handled - delete this view + + for (i=topView; i>0; i--) + { + retVal = views[i]->handleCommand(command); + if (retVal == 1) + { + // not handled but don't give to any more views + pthread_mutex_unlock(&viewManLock); + return 0; + } + + if (retVal == 2) + { + // command handled + if (views[i]->seconds) + { + struct timespec currentTime; + clock_gettime(CLOCK_REALTIME, ¤tTime); + views[i]->delSec = currentTime.tv_sec + views[i]->seconds; + views[i]->delNSec = currentTime.tv_nsec; + resetThread(); + } + pthread_mutex_unlock(&viewManLock); + retVal2 = 1; + break; + } + else if (retVal == 4) + { +// removeNoLock(views[i]); +// Box::showAll(); +// resetThread(); + removeView(views[i], 1); + pthread_mutex_unlock(&viewManLock); + retVal2 = 1; + break; + } + } + + Log::getInstance()->log("ViewMan", Log::DEBUG, "out of handlecommand code, now on to messages"); + + processMessageQueue(); + + pthread_mutex_unlock(&viewManLock); + return retVal2; +} + +void ViewMan::processMessage(Message* m) +{ + if (m->to != this) + { + for (int i = topView; i > 0; i--) + { + if (views[i] == m->to) + { + Log::getInstance()->log("ViewMan", Log::DEBUG, "sending message to view"); + Log::getInstance()->log("ViewMan", Log::DEBUG, "%p %p %lu", m->from, m->to, m->message); + views[i]->processMessage(m); + return; + } + } + } + + Log::getInstance()->log("ViewMan", Log::DEBUG, "it's for meeee!"); + + switch(m->message) + { + case Message::CLOSE_ME: + { + removeView((View*)m->from, 1, 1); + break; + } + case Message::UPDATE_SCREEN: + { + Box::showAll(); + break; + } + case Message::SWAP_ME_FOR: + { + View* toReplace = (View*) m->parameter; + + removeView((View*)m->from, 1, 1); + + topView++; + views[topView] = toReplace; + if (toReplace->seconds) + { + struct timespec currentTime; + clock_gettime(CLOCK_REALTIME, ¤tTime); + toReplace->delSec = currentTime.tv_sec + toReplace->seconds; + toReplace->delNSec = currentTime.tv_nsec; + } + toReplace->draw(); + Box::showAll(); + resetThread(); + break; + } + } +} + +int ViewMan::timedDelete(View* v, int seconds, int lock) +{ + int success; + + if (lock) pthread_mutex_lock(&viewManLock); + + struct timespec currentTime; + clock_gettime(CLOCK_REALTIME, ¤tTime); + + if (v) + { + if (seconds) + { + v->seconds = seconds; + v->delSec = currentTime.tv_sec + seconds; + v->delNSec = currentTime.tv_nsec; + } + else + { + // for cancelling the delete + v->seconds = 0; + v->delSec = 0; + v->delNSec = 0; + } + success = 1; + } + else + { + success = 0; + } + + resetThread(); + if (lock) pthread_mutex_unlock(&viewManLock); + + return success; +} + + +// THE THREAD CODE STARTS HERE ///////////////////////////////////////////////////////////// + +void ViewMan::resetThread() +{ + // must be called with mutex already locked + resetThreadFlag = 1; + pthread_cond_signal(&autoDeleteThreadSignal); +} + +// undeclared function +void startAutoDeleteThread2(void *arg) +{ + ViewMan *v = (ViewMan *)arg; + v->startAutoDeleteThread3(); +} +int ViewMan::startAutoDeleteThread() +{ + pthread_mutex_lock(&viewManLock); + resetThreadFlag = 1; + autoDeleteThreadRun = 1; + if (pthread_create(&autoDeleteThread, NULL, (void*(*)(void*))startAutoDeleteThread2, (void *)this) == -1) return 0; + return 1; +} + +void ViewMan::startAutoDeleteThread3() +{ + struct timespec nextTime; + View* nextToDelete = NULL; + + // I don't want signals + sigset_t sigset; + sigfillset(&sigset); + pthread_sigmask(SIG_BLOCK, &sigset, NULL); + + // locked here + + while(1) + { + if (resetThreadFlag) + { + resetThreadFlag = 0; + + // Work out the next View to be deleted + + nextTime.tv_sec = 0; + nextTime.tv_nsec = 0; + nextToDelete = NULL; + + for(int i = 1; i <= topView; i++) + { + if ((views[i]->delSec > 0) && (views[i]->delNSec > 0)) + { + if ((nextTime.tv_sec == 0) && (nextTime.tv_nsec == 0)) + { + nextTime.tv_sec = views[i]->delSec; + nextTime.tv_nsec = views[i]->delNSec; + nextToDelete = views[i]; + } + else + { + if (views[i]->delSec < nextTime.tv_sec) + { + nextTime.tv_sec = views[i]->delSec; + nextTime.tv_nsec = views[i]->delNSec; + nextToDelete = views[i]; + } + else if (views[i]->delSec == nextTime.tv_sec) + { + if (views[i]->delNSec < nextTime.tv_nsec) + { + nextTime.tv_sec = views[i]->delNSec; + nextTime.tv_nsec = views[i]->delNSec; + nextToDelete = views[i]; + } + } + } + } + // no case + } + // end + } + + if (nextTime.tv_sec == 0) + { + pthread_cond_wait(&autoDeleteThreadSignal, &viewManLock); + } + else + { + pthread_cond_timedwait(&autoDeleteThreadSignal, &viewManLock, &nextTime); + } + + // ok. we have been signalled or the time has run out + + // see if we have been signalled. we only get signalled if we + // are to reset the timer or if we are to die completely + if (!autoDeleteThreadRun) + { + pthread_exit(NULL); + // exiting thread with mutex locked + } + + if (resetThreadFlag) continue; + + // timer ran out + Log::getInstance()->log("ViewMan", Log::DEBUG, "About to remove %p", nextToDelete); + removeView(nextToDelete, 1); // enter this method with mutex locked + + resetThreadFlag = 1; + } +} + diff --git a/viewman.h b/viewman.h new file mode 100644 index 0000000..a742d51 --- /dev/null +++ b/viewman.h @@ -0,0 +1,82 @@ +/* + Copyright 2004-2005 Chris Tallon + + This file is part of VOMP. + + VOMP 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. + + VOMP 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 VOMP; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#ifndef VIEWMAN_H +#define VIEWMAN_H + +#include +#include +#include +#include + +#include "defines.h" +#include "view.h" +#include "message.h" +#include "messagequeue.h" + +class ViewMan : public MessageQueue +{ + public: + ViewMan(); + ~ViewMan(); + static ViewMan* getInstance(); + + int init(); + int shutdown(); + + // All these reset the thread + int add(View* v); + int addNoLock(View* v); + int removeView(View* toRemove = NULL, int noLock = 0, int noShow = 0); + void removeAll(); + void redrawAll(int noShow = 0); + + int handleCommand(UCHAR command); + int timedDelete(View* v, int seconds, int lock); + // + + // not for external use + void startAutoDeleteThread3(); + + private: + int isTotallyCovered(View* toDelete, int slotTakenFrom); + + static ViewMan* instance; + int initted; + + View* views[11]; + UCHAR topView; + + // Threading stuff + + int startAutoDeleteThread(); + pthread_mutex_t viewManLock; + pthread_t autoDeleteThread; + pthread_cond_t autoDeleteThreadSignal; + int resetThreadFlag; + int autoDeleteThreadRun; + int callFromThread; + void resetThread(); + + void processMessage(Message* m); + +}; + +#endif diff --git a/vinfo.cc b/vinfo.cc new file mode 100644 index 0000000..eb8a057 --- /dev/null +++ b/vinfo.cc @@ -0,0 +1,69 @@ +/* + Copyright 2004-2005 Chris Tallon + + This file is part of VOMP. + + VOMP 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. + + VOMP 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 VOMP; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include "vinfo.h" + +VInfo::VInfo() +{ + mainText = NULL; + exitable = 0; + + setBackgroundColour(0, 0, 100, 255); + setTitleBarOn(1); + setTitleBarColour(0, 0, 200, 255); +} + +VInfo::~VInfo() +{ + if (mainText) delete[] mainText; +} + +void VInfo::setExitable() +{ + exitable = 1; +} + +void VInfo::setMainText(char* takeText) +{ + int length = strlen(takeText); + mainText = new char[length + 1]; + strcpy(mainText, takeText); +} + +void VInfo::draw() +{ + View::draw(); + + if (mainText) drawPara(mainText, 10, 45, 255, 255, 255); +} + +int VInfo::handleCommand(int command) +{ + switch(command) + { + case Remote::OK: + case Remote::BACK: + { + if (exitable) return 4; + } + } + + return 1; +} diff --git a/vinfo.h b/vinfo.h new file mode 100644 index 0000000..4c9ae37 --- /dev/null +++ b/vinfo.h @@ -0,0 +1,48 @@ +/* + Copyright 2004-2005 Chris Tallon + + This file is part of VOMP. + + VOMP 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. + + VOMP 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 VOMP; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#ifndef VINFO_H +#define VINFO_H + +#include +#include + +#include "defines.h" +#include "view.h" +#include "remote.h" + +class VInfo : public View +{ + public: + VInfo(); + ~VInfo(); + + void setMainText(char* title); + void setExitable(); + + int handleCommand(int command); + void draw(); + + private: + char* mainText; + UCHAR exitable; +}; + +#endif diff --git a/vlivebanner.cc b/vlivebanner.cc new file mode 100644 index 0000000..155b34a --- /dev/null +++ b/vlivebanner.cc @@ -0,0 +1,89 @@ +/* + Copyright 2004-2005 Chris Tallon + + This file is part of VOMP. + + VOMP 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. + + VOMP 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 VOMP; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include "vlivebanner.h" + +VLiveBanner::VLiveBanner() +{ + setScreenPos(130, 370); + setDimensions(120, 500); + + setBackgroundColour(0, 0, 100, 255); + setTitleBarOn(1); + setTitleText("The channel name"); + setTitleBarColour(0, 0, 200, 255); + + sl.setScreenPos(screenX, screenY + 30); + sl.setDimensions(height - 60, width); +} + +VLiveBanner::~VLiveBanner() +{ +} + +void VLiveBanner::draw() +{ + int success = VDR::getInstance()->getChannelSchedule(1); + + if (!success) + { + sl.addOption("No channel data available", 1); + } + else + { + sl.addOption("This Programme", 1); + sl.addOption("The Next Programme", 0); + sl.addOption("The Programme after that", 0); + } + + View::draw(); + sl.draw(); + rectangle(0, height - 30, width, 30, titleBarR, titleBarG, titleBarB, titleBarA); +} + +int VLiveBanner::handleCommand(int command) +{ + switch (command) + { + case Remote::OK: + case Remote::BACK: + { + return 4; + } + case Remote::UP: + { + sl.up(); + sl.draw(); + + show(); + return 2; + } + case Remote::DOWN: + { + sl.down(); + sl.draw(); + + show(); + return 2; + } + } + + return 1; +} diff --git a/vlivebanner.h b/vlivebanner.h new file mode 100644 index 0000000..03267d5 --- /dev/null +++ b/vlivebanner.h @@ -0,0 +1,46 @@ +/* + Copyright 2004-2005 Chris Tallon + + This file is part of VOMP. + + VOMP 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. + + VOMP 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 VOMP; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#ifndef VLIVEBANNER_H +#define VLIVEBANNER_H + +#include +#include + +#include "view.h" +#include "remote.h" +#include "vdr.h" +#include "wselectlist.h" + +class VLiveBanner : public View +{ + public: + VLiveBanner(); + ~VLiveBanner(); + + int handleCommand(int command); + void draw(); + + private: + WSelectList sl; + +}; + +#endif diff --git a/vmute.cc b/vmute.cc new file mode 100644 index 0000000..00d6e24 --- /dev/null +++ b/vmute.cc @@ -0,0 +1,62 @@ +/* + Copyright 2004-2005 Chris Tallon + + This file is part of VOMP. + + VOMP 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. + + VOMP 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 VOMP; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include "vmute.h" + +VMute::VMute() +{ + isMuted = Audio::getInstance()->toggleUserMute(); + + setDimensions(40, 40); + setScreenPos(600, 500); + + setBackgroundColour(0, 0, 100, 255); +} + +void VMute::draw() +{ + View::draw(); + + WSymbol* w = new WSymbol; + if (isMuted) w->nextSymbol = WSymbol::MUTE; + else w->nextSymbol = WSymbol::UNMUTE; + w->setScreenPos(screenX + 5, screenY + 5); + w->draw(); + + delete w; +} + +int VMute::handleCommand(int command) +{ + switch(command) + { + case Remote::MUTE: + { + isMuted = Audio::getInstance()->toggleUserMute(); + draw(); + show(); + // handled + return 2; + } + } + + // allow command to drop through to other views + return 0; +} diff --git a/vmute.h b/vmute.h new file mode 100644 index 0000000..b3d1f0c --- /dev/null +++ b/vmute.h @@ -0,0 +1,43 @@ +/* + Copyright 2004-2005 Chris Tallon + + This file is part of VOMP. + + VOMP 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. + + VOMP 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 VOMP; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#ifndef VMUTE_H +#define VMUTE_H + +#include + +#include "view.h" +#include "remote.h" +#include "audio.h" +#include "wsymbol.h" + +class VMute : public View +{ + public: + VMute(); + void draw(); + int handleCommand(int command); + + private: + int isMuted; +}; + +#endif + diff --git a/vquestion.cc b/vquestion.cc new file mode 100644 index 0000000..075ff25 --- /dev/null +++ b/vquestion.cc @@ -0,0 +1,118 @@ +/* + Copyright 2004-2005 Chris Tallon + + This file is part of VOMP. + + VOMP 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. + + VOMP 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 VOMP; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include "vquestion.h" + +VQuestion::VQuestion() +{ + mainText = NULL; + selectedOption = NO; + + buttonYes.setText("Yes"); + buttonNo.setText("No"); + buttonNo.setActive(1); + +} + +VQuestion::~VQuestion() +{ + if (mainText) delete[] mainText; +} + +void VQuestion::setMainText(char* takeText) +{ + int length = strlen(takeText); + mainText = new char[length + 1]; + strcpy(mainText, takeText); +} + +void VQuestion::draw() +{ + View::draw(); + + buttonYes.setScreenPos(screenX + 40, screenY + 120); + buttonNo.setScreenPos(screenX + 140, screenY + 120); + + if (mainText) drawPara(mainText, 10, 45, 255, 255, 255); + buttonYes.draw(); + buttonNo.draw(); +} + +void VQuestion::swap() +{ + if (selectedOption == NO) + { + selectedOption = YES; + buttonYes.setActive(1); + buttonNo.setActive(0); + } + else if (selectedOption == YES) + { + selectedOption = NO; + buttonYes.setActive(0); + buttonNo.setActive(1); + } +} + +int VQuestion::handleCommand(int command) +{ + if (command == Remote::LEFT) + { + swap(); + draw(); + show(); + return 2; + } + else if (command == Remote::RIGHT) + { + swap(); + draw(); + show(); + return 2; + } + else if (command == Remote::BACK) + { + return 4; + } + else if (command == Remote::OK) + { + if (selectedOption != YES) return 4; + + Message* m = new Message(); + m->from = this; + m->to = questionReceiver; + m->message = Message::QUESTION_YES; + ViewMan::getInstance()->postMessage(m); + + return 4; + } + + return 1; +} + +void VQuestion::setParent(View* tquestionReceiver) +{ + questionReceiver = tquestionReceiver; +} + +void VQuestion::setDefault(UCHAR option) +{ + selectedOption = option; +} diff --git a/vquestion.h b/vquestion.h new file mode 100644 index 0000000..7a0b857 --- /dev/null +++ b/vquestion.h @@ -0,0 +1,59 @@ +/* + Copyright 2004-2005 Chris Tallon + + This file is part of VOMP. + + VOMP 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. + + VOMP 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 VOMP; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#ifndef VQUESTION_H +#define VQUESTION_H + +#include +#include + +#include "view.h" +#include "wbutton.h" +#include "remote.h" +#include "viewman.h" + +class VQuestion : public View +{ + public: + VQuestion(); + ~VQuestion(); + void setParent(View* tquestionReceiver); + void setDefault(UCHAR option); + void setMainText(char* title); + + int handleCommand(int command); + void draw(); + + const static UCHAR NO = 0; + const static UCHAR YES = 1; + + private: + char* mainText; + + void swap(); + + View* questionReceiver; + UCHAR selectedOption; + + WButton buttonYes; + WButton buttonNo; +}; + +#endif diff --git a/vradiolive.cc b/vradiolive.cc new file mode 100644 index 0000000..e941cff --- /dev/null +++ b/vradiolive.cc @@ -0,0 +1,115 @@ +/* + Copyright 2004-2005 Chris Tallon + + This file is part of VOMP. + + VOMP 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. + + VOMP 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 VOMP; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include "vradiolive.h" + +VRadioLive::VRadioLive(List* tchanList) +{ + player = new PlayerRadio(); + player->init(); + vdr = VDR::getInstance(); + chanList = tchanList; + currentChannel = 0; + + setDimensions(100, 100); + setBackgroundColour(0, 0, 0, 255); +} + +VRadioLive::~VRadioLive() +{ + delete player; +} + +void VRadioLive::draw() +{ + View::draw(); +} + +int VRadioLive::handleCommand(int command) +{ + switch(command) + { + case Remote::STOP: + case Remote::BACK: + case Remote::MENU: + { + player->stop(); + vdr->stopStreaming(); + return 4; + } + case Remote::UP: + { + player->stop(); + vdr->stopStreaming(); + upChannel(); + vdr->streamChannel(currentChannel); + player->play(); + return 2; + } + case Remote::DOWN: + { + player->stop(); + vdr->stopStreaming(); + downChannel(); + vdr->streamChannel(currentChannel); + player->play(); + return 2; + } + } + + return 1; +} + +void VRadioLive::setChannel(int number) +{ + currentChannel = number; + vdr->streamChannel(currentChannel); + player->play(); +} + +void VRadioLive::upChannel() +{ + Channel* channel; + for(chanList->reset(); (channel = (Channel*)chanList->getCurrent()); chanList->next()) + { + if (channel->number == currentChannel) + { + chanList->next(); + channel = (Channel*)chanList->getCurrent(); + if (!channel) return; + currentChannel = channel->number; + } + } +} + +void VRadioLive::downChannel() +{ + Channel* channel; + Channel* prevChannel = NULL; + for(chanList->reset(); (channel = (Channel*)chanList->getCurrent()); chanList->next()) + { + if (channel->number == currentChannel) + { + if (!prevChannel) return; + currentChannel = prevChannel->number; + } + prevChannel = channel; + } +} diff --git a/vradiolive.h b/vradiolive.h new file mode 100644 index 0000000..00dc743 --- /dev/null +++ b/vradiolive.h @@ -0,0 +1,54 @@ +/* + Copyright 2004-2005 Chris Tallon + + This file is part of VOMP. + + VOMP 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. + + VOMP 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 VOMP; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#ifndef VRADIOLIVE_H +#define VRADIOLIVE_H + +#include + +#include "view.h" +#include "playerradio.h" +#include "vdr.h" +#include "list.h" +#include "channel.h" +#include "viewman.h" +#include "remote.h" + +class VRadioLive : public View +{ + public: + VRadioLive(List* chanList); + ~VRadioLive(); + void draw(); + int handleCommand(int command); + + void setChannel(int number); + + private: + VDR* vdr; + PlayerRadio* player; + List* chanList; + ULONG currentChannel; + + void upChannel(); + void downChannel(); +}; + +#endif diff --git a/vrecordinglist.cc b/vrecordinglist.cc new file mode 100644 index 0000000..91979a2 --- /dev/null +++ b/vrecordinglist.cc @@ -0,0 +1,350 @@ +/* + Copyright 2004-2005 Chris Tallon + + This file is part of VOMP. + + VOMP 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. + + VOMP 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 VOMP; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include "vrecordinglist.h" + +VRecordingList::VRecordingList() +{ + setScreenPos(80, 70); + setDimensions(420, 570); + + setBackgroundColour(0, 0, 100, 255); + setTitleBarOn(1); + setTitleBarColour(0, 0, 200, 255); + + sl.setScreenPos(screenX + 10, screenY + 30 + 5); + sl.setDimensions(height - 30 - 15 - 30, width - 20); +} + +VRecordingList::~VRecordingList() +{ + // only delete the list if this is not a sub dir window + if (recDir->isRoot) delete recDir; +} + +void VRecordingList::setDir(Directory* tdir) +{ + recDir = tdir; + int first = 1; + + char tempA[300]; // FIXME this is guesswork! + char tempB[300]; // FIXME + struct tm* btime; + + char spaces[13]; + char theNumber[10]; + int theNumberLength; + + Directory* dir; + recDir->dirList->reset(); + while((dir = (Directory*)recDir->dirList->getCurrent())) + { + strcpy(spaces, " "); + theNumberLength = snprintf(theNumber, 9, "%lu", dir->getNumRecordings()); + + spaces[11 - theNumberLength] = '\0'; + + //snprintf(tempA, 299, " %s", dir->name); + snprintf(tempA, 299, " %s%s%s", theNumber, spaces, dir->name); + //int numSize = snprintf(tempA + + dir->index = sl.addOption(tempA, first); + first = 0; + recDir->dirList->next(); + } + + // temp FIXME + List* recList = recDir->recList; + + // FIXME convert the whole program to time_t's + + + Recording* rec; + recList->reset(); + while((rec = (Recording*)recList->getCurrent())) + { + btime = localtime((time_t*)&rec->start); + strftime(tempA, 299, "%0d/%0m %0H:%0M ", btime); + sprintf(tempB, "%s %s", tempA, rec->getProgName()); + rec->index = sl.addOption(tempB, first); + first = 0; + recList->next(); + } + + if (!recDir->isRoot) + { + snprintf(tempA, 299, "Recordings - %s", recDir->name); + setTitleText(tempA); + } + else + { + setTitleText("Recordings"); + } +} + +void VRecordingList::draw() +{ + View::draw(); + sl.draw(); + + // Put the status stuff at the bottom + + WSymbol w; + + w.nextSymbol = WSymbol::UP; + w.setScreenPos(screenX + 20, screenY + 385); + w.draw(); + + w.nextSymbol = WSymbol::DOWN; + w.setScreenPos(screenX + 50, screenY + 385); + w.draw(); + + w.nextSymbol = WSymbol::SKIPBACK; + w.setScreenPos(screenX + 85, screenY + 385); + w.draw(); + + w.nextSymbol = WSymbol::SKIPFORWARD; + w.setScreenPos(screenX + 115, screenY + 385); + w.draw(); + + w.nextSymbol = WSymbol::PLAY; + w.setScreenPos(screenX + 150, screenY + 385); + w.draw(); + + // FIXME Right justify this! + drawText("[ok] = menu", 450, 385, 255, 255, 255); + + doShowingBar(); + + char freeSpace[50]; + int gigFree = Directory::freeSpace / 1024; + snprintf(freeSpace, 49, "%lu%%, %iGB free", Directory::usedPercent, gigFree); + drawTextRJ(freeSpace, 560, 5, 255, 255, 255); +} + +void VRecordingList::doShowingBar() +{ + int topOption = sl.getTopOption() + 1; + if (sl.getNumOptions() == 0) topOption = 0; + + char showing[200]; + sprintf(showing, "%i to %i of %i", topOption, sl.getBottomOption(), sl.getNumOptions()); + Box b; + b.setScreenPos(screenX + 220, screenY + 385); + b.setDimensions(25, 160); + b.fillColour(0, 0, 100, 255); + b.drawText(showing, 0, 0, 255, 255, 255); +} + + + +void VRecordingList::processMessage(Message* m) +{ + Log::getInstance()->log("VRecordingList", Log::DEBUG, "Got message value %lu", m->message); + if (m->message == Message::DELETE_SELECTED_RECORDING) + { + Log::getInstance()->log("VRecordingList", Log::DEBUG, "Doing delete selected"); + doDeleteSelected(); + return; + } + + if (m->message == Message::PLAY_SELECTED_RECORDING) + { + doPlay(); + return; + } + + if (m->message == Message::RESUME_SELECTED_RECORDING) + { + doResume(); + return; + } +} + +void VRecordingList::doDeleteSelected() +{ + Recording* toDelete = getCurrentOptionRecording(); + + int saveIndex; + int saveTop; + + if (toDelete) + { + saveIndex = toDelete->index; + saveTop = sl.getTopOption(); + Log::getInstance()->log("VRecordingList", Log::DEBUG, "FOUND: %i %s %s\n", toDelete->index, toDelete->getProgName(), toDelete->fileName); + recDir->recList->remove(toDelete); + Log::getInstance()->log("VRecordingList", Log::DEBUG, "I have removed: %s %s\n", toDelete->getProgName(), toDelete->fileName); + + VDR* vdr = VDR::getInstance(); + vdr->deleteRecording(toDelete->fileName); + + delete toDelete; + + sl.clear(); + setDir(recDir); + sl.hintSetCurrent(saveIndex); + sl.hintSetTop(saveTop); + draw(); + } + + Message* m2 = new Message(); + m2->from = this; + m2->to = ViewMan::getInstance(); + m2->message = Message::UPDATE_SCREEN; + ViewMan::getInstance()->postMessage(m2); +} + +int VRecordingList::doPlay() +{ + Recording* toPlay = getCurrentOptionRecording(); + if (toPlay) + { + VVideoRec* vidrec = new VVideoRec(toPlay); + ViewMan::getInstance()->addNoLock(vidrec); + vidrec->draw(); + vidrec->show(); + vidrec->go(0); + return 1; + } + // should not get to here + return 0; +} + +int VRecordingList::doResume() +{ + Recording* toResume = getCurrentOptionRecording(); + if (toResume) + { + ULLONG position = VDR::getInstance()->getResumePoint(toResume->fileName); + + VVideoRec* vidrec = new VVideoRec(toResume); + ViewMan::getInstance()->addNoLock(vidrec); + vidrec->draw(); + vidrec->show(); + vidrec->go(position); + return 1; + } + // should not get to here + return 0; +} + +Recording* VRecordingList::getCurrentOptionRecording() +{ + Recording* current; + for(recDir->recList->reset(); (current = (Recording*)recDir->recList->getCurrent()); recDir->recList->next()) + { + if (current->index == sl.getCurrentOption()) return current; + } + return NULL; +} + +int VRecordingList::handleCommand(int command) +{ + if (command == Remote::UP) + { + sl.up(); + sl.draw(); + + doShowingBar(); + show(); + return 2; + } + else if (command == Remote::DOWN) + { + sl.down(); + sl.draw(); + + doShowingBar(); + show(); + return 2; + } + else if (command == Remote::SKIPBACK) + { + sl.pageUp(); + sl.draw(); + + doShowingBar(); + show(); + return 2; + } + else if (command == Remote::SKIPFORWARD) + { + sl.pageDown(); + sl.draw(); + + doShowingBar(); + show(); + return 2; + } + else if (command == Remote::OK) + { + if (sl.getNumOptions() == 0) return 2; + + // Check to see if it is a sub directory + Directory* curDir; + for(recDir->dirList->reset(); (curDir = (Directory*)recDir->dirList->getCurrent()); recDir->dirList->next()) + { + if (curDir->index == sl.getCurrentOption()) + { + VRecordingList* sub = new VRecordingList(); + sub->setDir(curDir); + ViewMan::getInstance()->addNoLock(sub); + + sub->draw(); + sub->show(); + + return 2; + } + } + + // check to see if it's a recording + Recording* current; + for(recDir->recList->reset(); (current = (Recording*)recDir->recList->getCurrent()); recDir->recList->next()) + { + if (current->index == sl.getCurrentOption()) + { + Log::getInstance()->log("VRecordingList", Log::DEBUG, "Found the option you pointed at. %s %s", current->getProgName(), current->fileName); + + VRecordingMenu* v = new VRecordingMenu(); + v->setParent(this); + v->setRecording(current); + ViewMan::getInstance()->addNoLock(v); + v->draw(); + v->show(); + return 2; + } + } + // should not get to here + return 1; + } + else if (command == Remote::BACK) + { + return 4; + } + else if (command == Remote::PLAY) + { + if (doPlay()) return 2; + return 1; + } + + // stop command getting to any more views + return 1; +} diff --git a/vrecordinglist.h b/vrecordinglist.h new file mode 100644 index 0000000..1d5425c --- /dev/null +++ b/vrecordinglist.h @@ -0,0 +1,63 @@ +/* + Copyright 2004-2005 Chris Tallon + + This file is part of VOMP. + + VOMP 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. + + VOMP 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 VOMP; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#ifndef VRECORDINGLIST_H +#define VRECORDINGLIST_H + +#include +#include + +#include "view.h" +#include "list.h" +#include "directory.h" +#include "recording.h" +#include "wselectlist.h" +#include "remote.h" +#include "wsymbol.h" +#include "viewman.h" +#include "vrecordingmenu.h" +#include "vdr.h" +#include "vvideorec.h" + +class VRecordingList : public View +{ + public: + VRecordingList(); + ~VRecordingList(); + + void setDir(Directory* dir); + + int handleCommand(int command); + void processMessage(Message* m); + void draw(); + + private: + Directory* recDir; + + WSelectList sl; + + void doShowingBar(); + void doDeleteSelected(); + int doPlay(); + int doResume(); + Recording* getCurrentOptionRecording(); +}; + +#endif diff --git a/vrecordingmenu.cc b/vrecordingmenu.cc new file mode 100644 index 0000000..fc434e3 --- /dev/null +++ b/vrecordingmenu.cc @@ -0,0 +1,171 @@ +/* + Copyright 2004-2005 Chris Tallon + + This file is part of VOMP. + + VOMP 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. + + VOMP 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 VOMP; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include "vrecordingmenu.h" + +VRecordingMenu::VRecordingMenu() +{ + rec = NULL; + + setScreenPos(260, 190); + setDimensions(140, 200); + + setBackgroundColour(0, 0, 100, 255); + setTitleBarOn(1); + setBorderOn(1); + setTitleText("Programme menu"); + setTitleBarColour(0, 0, 200, 255); + + sl.setScreenPos(screenX + 10, screenY + 30 + 5); + sl.setDimensions(height - 30 - 15, width - 20); + sl.addOption("Play", 1); + sl.addOption("Resume", 0); + sl.addOption("Summary", 0); + sl.addOption("Delete", 0); +} + +VRecordingMenu::~VRecordingMenu() +{ +} + +void VRecordingMenu::setParent(VRecordingList* tvRecList) +{ + vRecList = tvRecList; +} + +void VRecordingMenu::setRecording(Recording* trec) +{ + rec = trec; +} + +void VRecordingMenu::draw() +{ + View::draw(); + sl.draw(); +} + +int VRecordingMenu::handleCommand(int command) +{ + if (command == Remote::UP) + { + sl.up(); + sl.draw(); + show(); + return 2; + } + else if (command == Remote::DOWN) + { + sl.down(); + sl.draw(); + show(); + return 2; + } + else if (command == Remote::OK) + { + if (sl.getCurrentOption() == 0) + { + Message* m = new Message(); + m->from = this; + m->to = vRecList; + m->message = Message::PLAY_SELECTED_RECORDING; + ViewMan::getInstance()->postMessage(m); + return 4; + } + + if (sl.getCurrentOption() == 1) + { + Message* m = new Message(); + m->from = this; + m->to = vRecList; + m->message = Message::RESUME_SELECTED_RECORDING; + ViewMan::getInstance()->postMessage(m); + return 4; + } + + if (sl.getCurrentOption() == 2) + { + char* summary = VDR::getInstance()->getRecordingSummary(rec->fileName); + + VInfo* vi = new VInfo(); + vi->setTitleText("Programme summary"); + vi->setBorderOn(1); + vi->setExitable(); + if (summary) vi->setMainText(summary); + else vi->setMainText("Summary unavailable"); + vi->setScreenPos(120, 130); + vi->setDimensions(300, 490); + + ViewMan::getInstance()->addNoLock(vi); + vi->draw(); + vi->show(); + + if (summary) delete[] summary; + + return 2; + } + else if (sl.getCurrentOption() == 3) + { + VQuestion* v = new VQuestion(); + v->setParent(this); + v->setBackgroundColour(0, 0, 100, 255); + v->setTitleBarColour(200, 0, 0, 255); + v->setTitleBarOn(1); + v->setBorderOn(1); + v->setTitleText("Delete recording"); + v->setMainText("Are you sure you want to delete this recording?"); + v->setDefault(VQuestion::NO); + v->setScreenPos(230, 160); + v->setDimensions(180, 260); + + ViewMan::getInstance()->addNoLock(v); + v->draw(); + v->show(); + return 2; + } + } + else if (command == Remote::BACK) + { + return 4; + } + + // stop command getting to any more views + return 1; +} + +void VRecordingMenu::processMessage(Message* m) +{ + if (m->message == Message::QUESTION_YES) + { + if (sl.getCurrentOption() == 3) + { + Message* m = new Message(); + m->from = this; + m->to = ViewMan::getInstance(); + m->message = Message::CLOSE_ME; + ViewMan::getInstance()->postMessage(m); + + m = new Message(); + m->from = this; + m->to = vRecList; + m->message = Message::DELETE_SELECTED_RECORDING; + ViewMan::getInstance()->postMessage(m); + } + } +} diff --git a/vrecordingmenu.h b/vrecordingmenu.h new file mode 100644 index 0000000..6fe269e --- /dev/null +++ b/vrecordingmenu.h @@ -0,0 +1,58 @@ +/* + Copyright 2004-2005 Chris Tallon + + This file is part of VOMP. + + VOMP 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. + + VOMP 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 VOMP; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#ifndef VRECORDINGMENU_H +#define VRECORDINGMENU_H + +#include +#include + +#include "view.h" +#include "recording.h" +#include "wselectlist.h" +#include "remote.h" +#include "vrecordinglist.h" +#include "vquestion.h" +#include "message.h" +#include "vinfo.h" +#include "vdr.h" + +class VRecordingList; + +class VRecordingMenu : public View +{ + public: + VRecordingMenu(); + ~VRecordingMenu(); + void setParent(VRecordingList* tvRecList); + void setRecording(Recording* rec); + + int handleCommand(int command); + void processMessage(Message* m); + void draw(); + + private: + + WSelectList sl; + VRecordingList* vRecList; + Recording* rec; +}; + +#endif diff --git a/vserverselect.cc b/vserverselect.cc new file mode 100644 index 0000000..8a96bdc --- /dev/null +++ b/vserverselect.cc @@ -0,0 +1,81 @@ +/* + Copyright 2004-2005 Chris Tallon + + This file is part of VOMP. + + VOMP 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. + + VOMP 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 VOMP; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include "vserverselect.h" + +VServerSelect::VServerSelect(std::vector* serverIPs, int* tselectServer) +{ + // I tried the whole passing using a reference here, but + // the program segfaulted when settitletext tried to new + // a char array. so now we have the messy dereferencing... + // anyway, now it doesn't use a object wide reference. + selectServer = tselectServer; + + setDimensions(200, 300); + setScreenPos(220, 200); + setBackgroundColour(0, 0, 100, 255); + setTitleBarOn(1); + setTitleBarColour(0, 0, 200, 255); + setTitleText("Choose a VDR server"); + + sl.setScreenPos(screenX + 10, screenY + 30 + 5); + sl.setDimensions(height - 30 - 15, width - 20); + + sl.addOption((*serverIPs)[0], 1); + for(UINT k = 1; k < serverIPs->size(); k++) + { + sl.addOption((*serverIPs)[k], 0); + } +} + +VServerSelect::~VServerSelect() +{ +} + +void VServerSelect::draw() +{ + View::draw(); + sl.draw(); +} + +int VServerSelect::handleCommand(int command) +{ + if (command == Remote::UP) + { + sl.up(); + sl.draw(); + show(); + return 2; + } + else if (command == Remote::DOWN) + { + sl.down(); + sl.draw(); + show(); + return 2; + } + else if (command == Remote::OK) + { + *selectServer = sl.getCurrentOption(); + return 4; + } + + return 1; +} diff --git a/vserverselect.h b/vserverselect.h new file mode 100644 index 0000000..c00b9ff --- /dev/null +++ b/vserverselect.h @@ -0,0 +1,47 @@ +/* + Copyright 2004-2005 Chris Tallon + + This file is part of VOMP. + + VOMP 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. + + VOMP 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 VOMP; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#ifndef VSERVERSELECT_H +#define VSERVERSELECT_H + +#include +#include +#include + +#include "defines.h" +#include "view.h" +#include "remote.h" +#include "wselectlist.h" + +class VServerSelect : public View +{ + public: + VServerSelect(std::vector* tserverIPs, int* tselectServer); + ~VServerSelect(); + + int handleCommand(int command); + void draw(); + + private: + WSelectList sl; + int* selectServer; +}; + +#endif diff --git a/vvideolive.cc b/vvideolive.cc new file mode 100644 index 0000000..c6da0eb --- /dev/null +++ b/vvideolive.cc @@ -0,0 +1,165 @@ +/* + Copyright 2004-2005 Chris Tallon + + This file is part of VOMP. + + VOMP 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. + + VOMP 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 VOMP; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include "vvideolive.h" + +VVideoLive::VVideoLive(List* tchanList) +{ + player = new Player(NULL); + player->init(); + vdr = VDR::getInstance(); + chanList = tchanList; + currentChannel = 0; + + setDimensions(SCREENHEIGHT, SCREENWIDTH); + setBackgroundColour(0, 0, 0, 0); +} + +VVideoLive::~VVideoLive() +{ + delete player; +} + +void VVideoLive::draw() +{ + View::draw(); +} + +int VVideoLive::handleCommand(int command) +{ + switch(command) + { + case Remote::PLAY: + { + player->play(); // do resync + return 2; + } + + case Remote::STOP: + case Remote::BACK: + case Remote::MENU: + { + player->stop(); + vdr->stopStreaming(); + return 4; + } + case Remote::UP: + { + player->stop(); + vdr->stopStreaming(); + upChannel(); + doBanner(); + vdr->streamChannel(currentChannel); + player->play(); + return 2; + } + case Remote::DOWN: + { + player->stop(); + vdr->stopStreaming(); + downChannel(); + doBanner(); + vdr->streamChannel(currentChannel); + player->play(); + return 2; + } + case Remote::OK: + { + doBanner(); + return 2; + } + + case Remote::ZERO ... Remote::NINE: + { + VChannelSelect* v = new VChannelSelect(this, command); + ViewMan::getInstance()->addNoLock(v); +// ViewMan::getInstance()->timedDelete(v, 4, 0); + v->draw(); + v->show(); + } + } + + return 1; +} + +void VVideoLive::processMessage(Message* m) +{ + if (m->message == Message::CHANNEL_CHANGE) + { + // check channel number is valid + Channel* channel; + for(chanList->reset(); (channel = (Channel*)chanList->getCurrent()); chanList->next()) + { + if (channel->number == m->parameter) + { + player->stop(); + vdr->stopStreaming(); + setChannel(channel->number); + } + } + } +} + +void VVideoLive::doBanner() +{ + VLiveBanner* v = new VLiveBanner(); + ViewMan::getInstance()->addNoLock(v); + ViewMan::getInstance()->timedDelete(v, 4, 0); + v->draw(); + v->show(); +} + +void VVideoLive::setChannel(int number) +{ + currentChannel = number; +// doBanner(); + vdr->streamChannel(currentChannel); + player->play(); +} + +void VVideoLive::upChannel() +{ + Channel* channel; + for(chanList->reset(); (channel = (Channel*)chanList->getCurrent()); chanList->next()) + { + if (channel->number == currentChannel) + { + chanList->next(); + channel = (Channel*)chanList->getCurrent(); + if (!channel) return; + currentChannel = channel->number; + } + } +} + +void VVideoLive::downChannel() +{ + Channel* channel; + Channel* prevChannel = NULL; + for(chanList->reset(); (channel = (Channel*)chanList->getCurrent()); chanList->next()) + { + if (channel->number == currentChannel) + { + if (!prevChannel) return; + currentChannel = prevChannel->number; + } + prevChannel = channel; + } +} diff --git a/vvideolive.h b/vvideolive.h new file mode 100644 index 0000000..5664871 --- /dev/null +++ b/vvideolive.h @@ -0,0 +1,57 @@ +/* + Copyright 2004-2005 Chris Tallon + + This file is part of VOMP. + + VOMP 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. + + VOMP 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 VOMP; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#ifndef VVIDEOLIVE_H +#define VVIDEOLIVE_H + +#include + +#include "view.h" +#include "player.h" +#include "vdr.h" +#include "list.h" +#include "channel.h" +#include "vlivebanner.h" +#include "viewman.h" +#include "vchannelselect.h" + +class VVideoLive : public View +{ + public: + VVideoLive(List* chanList); + ~VVideoLive(); + void draw(); + int handleCommand(int command); + void processMessage(Message* m); + + void setChannel(int number); + + private: + VDR* vdr; + Player* player; + List* chanList; + ULONG currentChannel; + + void upChannel(); + void downChannel(); + void doBanner(); +}; + +#endif diff --git a/vvideorec.cc b/vvideorec.cc new file mode 100644 index 0000000..a1e8af0 --- /dev/null +++ b/vvideorec.cc @@ -0,0 +1,122 @@ +/* + Copyright 2004-2005 Chris Tallon + + This file is part of VOMP. + + VOMP 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. + + VOMP 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 VOMP; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include "vvideorec.h" + +VVideoRec::VVideoRec(Recording* rec) +{ + player = new Player(Command::getInstance()); + player->init(); + vdr = VDR::getInstance(); + + myRec = rec; + + setDimensions(SCREENHEIGHT, SCREENWIDTH); + setBackgroundColour(0, 0, 0, 0); +} + +VVideoRec::~VVideoRec() +{ + delete player; +} + +void VVideoRec::draw() +{ + View::draw(); +} + +void VVideoRec::go(ULLONG startPosition) +{ + ULLONG recLength = vdr->streamRecording(myRec); + + player->setLength(recLength); + player->setPosition(startPosition); + player->play(); +} + +int VVideoRec::handleCommand(int command) +{ + switch(command) + { + case Remote::PLAY: + { + player->play(); // do resync + return 2; + } + + case Remote::STOP: + case Remote::BACK: + case Remote::MENU: + { + player->stop(); + vdr->stopStreaming(); + return 4; + } + case Remote::PAUSE: + { + player->togglePause(); + return 2; + } + case Remote::SKIPFORWARD: + { + player->skipForward(60); + return 2; + } + case Remote::SKIPBACK: + { + player->skipBackward(60); + return 2; + } + case Remote::FORWARD: + { + player->toggleFastForward(); + return 2; + } + case Remote::YELLOW: + { + player->skipBackward(10); + return 2; + } + case Remote::BLUE: + { + player->skipForward(10); + return 2; + } +// case Remote::REVERSE: +// { +// player->toggleFastBackward(); +// return 2; +// } + + case Remote::ZERO: player->jumpToPercent(0); return 2; + case Remote::ONE: player->jumpToPercent(10); return 2; + case Remote::TWO: player->jumpToPercent(20); return 2; + case Remote::THREE: player->jumpToPercent(30); return 2; + case Remote::FOUR: player->jumpToPercent(40); return 2; + case Remote::FIVE: player->jumpToPercent(50); return 2; + case Remote::SIX: player->jumpToPercent(60); return 2; + case Remote::SEVEN: player->jumpToPercent(70); return 2; + case Remote::EIGHT: player->jumpToPercent(80); return 2; + case Remote::NINE: player->jumpToPercent(90); return 2; + + } + + return 1; +} diff --git a/vvideorec.h b/vvideorec.h new file mode 100644 index 0000000..42ac6ad --- /dev/null +++ b/vvideorec.h @@ -0,0 +1,47 @@ +/* + Copyright 2004-2005 Chris Tallon + + This file is part of VOMP. + + VOMP 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. + + VOMP 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 VOMP; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#ifndef VVIDEOREC_H +#define VVIDEOREC_H + +#include + +#include "view.h" +#include "player.h" +#include "vdr.h" +#include "recording.h" +#include "command.h" + +class VVideoRec : public View +{ + public: + VVideoRec(Recording* rec); + ~VVideoRec(); + void draw(); + int handleCommand(int command); + void go(ULLONG startPosition); + + private: + VDR* vdr; + Player* player; + Recording* myRec; +}; + +#endif diff --git a/vvolume.cc b/vvolume.cc new file mode 100644 index 0000000..d8cd838 --- /dev/null +++ b/vvolume.cc @@ -0,0 +1,85 @@ +/* + Copyright 2004-2005 Chris Tallon + + This file is part of VOMP. + + VOMP 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. + + VOMP 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 VOMP; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include "vvolume.h" + +VVolume::VVolume() +{ + displayVolume = Audio::getInstance()->getVolume(); + + setDimensions(31, 227); + setScreenPos(100, 499); + + setBackgroundColour(0, 0, 100, 255); +} + +void VVolume::draw() +{ + View::draw(); + + WSymbol* w = new WSymbol; + w->nextSymbol = WSymbol::VOLUME2; + w->setScreenPos(103, 509); + w->draw(); + + int i = 0; + + for(; i < displayVolume; i++) + { + w->nextSymbol = WSymbol::VOLBAR; + w->setScreenPos(140 + (i * 9), 502); + w->draw(); + } + + for(; i < 20; i++) + { + w->nextSymbol = WSymbol::VOLDOT; + w->setScreenPos(140 + (i * 9), 512); + w->draw(); + } + + delete w; +} + +int VVolume::handleCommand(int command) +{ + switch(command) + { + case Remote::LEFT: + { + displayVolume = Audio::getInstance()->volumeDown(); + draw(); + show(); + // handled + return 2; + } + case Remote::RIGHT: + { + displayVolume = Audio::getInstance()->volumeUp(); + draw(); + show(); + // handled + return 2; + } + } + + // allow command to drop through to other views + return 0; +} diff --git a/vvolume.h b/vvolume.h new file mode 100644 index 0000000..a5ea0b7 --- /dev/null +++ b/vvolume.h @@ -0,0 +1,45 @@ +/* + Copyright 2004-2005 Chris Tallon + + This file is part of VOMP. + + VOMP 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. + + VOMP 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 VOMP; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#ifndef VVOLUME_H +#define VVOLUME_H + +#include + +#include "view.h" +#include "remote.h" +#include "audio.h" +#include "wsymbol.h" + +class VVolume : public View +{ + public: + VVolume(); + void draw(); + int handleCommand(int command); + + private: + int displayCommand; + int displayVolume; + +}; + +#endif + diff --git a/vwallpaper.cc b/vwallpaper.cc new file mode 100644 index 0000000..6b149f3 --- /dev/null +++ b/vwallpaper.cc @@ -0,0 +1,54 @@ +/* + Copyright 2004-2005 Chris Tallon + + This file is part of VOMP. + + VOMP 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. + + VOMP 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 VOMP; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include "vwallpaper.h" + +VWallpaper::VWallpaper() +{ + +} + +VWallpaper::~VWallpaper() +{ + delete surface; +} + +void VWallpaper::init(char* name) +{ + jpeg.init(name); + + Osd* o = Osd::getInstance(); + setDimensions(o->getScreenHeight(), o->getScreenWidth()); + + // Now override the surface pointer found in Box to a seperate wallpaper surface + // but only for the wjpeg, not for this object + wallpaperSurface = new Surface(o->getFD(), 0); + wallpaperSurface->create(height, width); + + jpeg.overrideSurface(wallpaperSurface); + jpeg.draw(); +} + +void VWallpaper::draw() +{ + // we want to blit from wallpaperSurface to buffer (or screen if !doubleBuffer) + Surface::blt(Osd::getInstance()->getFD(), wallpaperSurface->getSurfaceHandle(), 0, 0, width, height, surface->getSurfaceHandle(), 0, 0); + // and the fd business here is terrible, but what can you do. +} diff --git a/vwallpaper.h b/vwallpaper.h new file mode 100644 index 0000000..0154ff3 --- /dev/null +++ b/vwallpaper.h @@ -0,0 +1,48 @@ +/* + Copyright 2004-2005 Chris Tallon + + This file is part of VOMP. + + VOMP 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. + + VOMP 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 VOMP; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#ifndef VWALLPAPER_H +#define VWALLPAPER_H + +#include +#include + +#include "view.h" +#include "wjpeg.h" + +#include "osd.h" +#include "surface.h" + +class VWallpaper : public View +{ + public: + VWallpaper(); + ~VWallpaper(); + + void init(char* file); + + void draw(); + + private: + Surface* wallpaperSurface; + WJpeg jpeg; +}; + +#endif diff --git a/vwelcome.cc b/vwelcome.cc new file mode 100644 index 0000000..1fb335e --- /dev/null +++ b/vwelcome.cc @@ -0,0 +1,212 @@ +/* + Copyright 2004-2005 Chris Tallon + + This file is part of VOMP. + + VOMP 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. + + VOMP 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 VOMP; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include "vwelcome.h" + +VWelcome::VWelcome() +{ + setDimensions(190, 460); + setScreenPos(140, 170); + + setBackgroundColour(0, 0, 100, 255); + setTitleBarOn(1); + setTitleBarColour(0, 0, 200, 255); + setTitleText("Welcome"); + + sl.setScreenPos(screenX + 20, screenY + 40); + sl.setDimensions(130, 170); + + sl.addOption("1. Live TV", 1); + sl.addOption("2. Radio", 0); + sl.addOption("3. Recordings", 0); + sl.addOption("4. Stand by", 0); + sl.addOption("5. Reboot", 0); + + jpeg.setScreenPos(screenX + 240, screenY + 50); +} + +VWelcome::~VWelcome() +{ +} + +void VWelcome::draw() +{ + + View::draw(); + sl.draw(); + + char timeString[20]; + time_t t; + time(&t); + struct tm* tm = localtime(&t); + strftime(timeString, 19, "%H:%M", tm); + + drawTextRJ(timeString, 450, 5, 255, 255, 255); + + jpeg.init("/vdr.jpg"); + jpeg.draw(); +} + +int VWelcome::handleCommand(int command) +{ + if (command == Remote::UP) + { + sl.up(); + sl.draw(); + show(); + return 2; + } + else if (command == Remote::DOWN) + { + sl.down(); + sl.draw(); + show(); + return 2; + } + else if (command == Remote::ONE) + { + doChannelsList(); + return 2; + } + else if (command == Remote::TWO) + { + doRadioList(); + return 2; + } + else if (command == Remote::THREE) + { + doRecordingsList(); + return 2; + } + else if (command == Remote::FOUR) + { + Message* m = new Message(); + m->message = Message::STANDBY; + Command::getInstance()->postMessage(m); + return 4; + } + else if (command == Remote::FIVE) + { + Command::getInstance()->doReboot(); + } + else if (command == Remote::OK) + { + int option = sl.getCurrentOption(); + if (option == 0) + { + doChannelsList(); + return 2; + } + else if (option == 1) + { + doRadioList(); + return 2; + } + else if (option == 2) + { + doRecordingsList(); + return 2; + } + else if (option == 3) + { + Message* m = new Message(); + m->message = Message::STANDBY; + Command::getInstance()->postMessage(m); + return 4; + } + else if (option == 4) + { + Command::getInstance()->doReboot(); + return 2; + } + } + + return 1; +} + + +void VWelcome::doChannelsList() +{ + List* chanList = VDR::getInstance()->getChannelsList(VDR::VIDEO); + + if (chanList) + { + VChannelList* vchan = new VChannelList(VDR::VIDEO); + vchan->setList(chanList); + + ViewMan::getInstance()->addNoLock(vchan); + vchan->draw(); + vchan->show(); + +// Message* m = new Message(); +// m->from = this; +// m->to = ViewMan::getInstance(); +// m->message = Message::SWAP_ME_FOR; +// m->parameter = (ULONG)vchan; +// ViewMan::getInstance()->postMessage(m); + } +} + +void VWelcome::doRadioList() +{ + List* chanList = VDR::getInstance()->getChannelsList(VDR::RADIO); + + if (chanList) + { + VChannelList* vchan = new VChannelList(VDR::RADIO); + vchan->setList(chanList); + + ViewMan::getInstance()->addNoLock(vchan); + vchan->draw(); + vchan->show(); + } +} + +void VWelcome::doRecordingsList() +{ + ViewMan* viewman = ViewMan::getInstance(); + + VInfo* viewWait = new VInfo(); + viewWait->setDimensions(190, 460); + viewWait->setScreenPos(140, 170); + viewWait->setMainText("\n Downloading recordings list"); + viewWait->draw(); + viewWait->show(); + viewman->addNoLock(viewWait); + + + VDR* vdr = VDR::getInstance(); + Directory* recDir = vdr->getRecordingsList(); + + if (recDir) + { + VRecordingList* vrec = new VRecordingList(); + vrec->setDir(recDir); + + ViewMan::getInstance()->addNoLock(vrec); + + vrec->draw(); + vrec->show(); + } + + Log::getInstance()->log("VWelcome", Log::DEBUG, "possible delay start"); + viewman->removeView(viewWait, 1, 1); + Log::getInstance()->log("VWelcome", Log::DEBUG, "possible delay end"); +} diff --git a/vwelcome.h b/vwelcome.h new file mode 100644 index 0000000..fe5a52b --- /dev/null +++ b/vwelcome.h @@ -0,0 +1,58 @@ +/* + Copyright 2004-2005 Chris Tallon + + This file is part of VOMP. + + VOMP 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. + + VOMP 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 VOMP; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#ifndef VWELCOME_H +#define VWELCOME_H + +#include +#include + +#include "view.h" +#include "remote.h" +#include "wselectlist.h" +#include "wjpeg.h" +#include "viewman.h" +#include "vdr.h" +#include "directory.h" +#include "vchannellist.h" +#include "vrecordinglist.h" +#include "command.h" +#include "message.h" + +class VWelcome : public View +{ + public: + VWelcome(); + ~VWelcome(); + + int handleCommand(int command); + void draw(); + + private: + + WSelectList sl; + WJpeg jpeg; + + void doChannelsList(); + void doRadioList(); + void doRecordingsList(); +}; + +#endif diff --git a/wbutton.cc b/wbutton.cc new file mode 100644 index 0000000..ccf322f --- /dev/null +++ b/wbutton.cc @@ -0,0 +1,76 @@ +/* + Copyright 2004-2005 Chris Tallon + + This file is part of VOMP. + + VOMP 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. + + VOMP 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 VOMP; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include "wbutton.h" + +WButton::WButton() +{ + int fontHeight = surface->getFontHeight(); + setDimensions(fontHeight, 70); + + mytext = NULL; + active = 0; +} + +WButton::~WButton() +{ + if (mytext) delete[] mytext; +} + +void WButton::setText(char* takeText) +{ + int length = strlen(takeText); + mytext = new char[length + 1]; + strcpy(mytext, takeText); +} + +void WButton::setActive(UCHAR tactive) +{ + active = tactive; +} + +void WButton::draw() +{ + UCHAR r1, g1, b1, r2, g2, b2; + + if (active) + { + r1 = 0; + g1 = 0; + b1 = 100; + r2 = 240; + g2 = 250; + b2 = 80; + } + else + { + r1 = 255; + g1 = 255; + b1 = 255; + r2 = 0; + g2 = 0; + b2 = 150; + } + + fillColour(r2, g2, b2, 255); + drawText(mytext, 0, 0, r1, g1, b1); + + +} diff --git a/wbutton.h b/wbutton.h new file mode 100644 index 0000000..f93c5c3 --- /dev/null +++ b/wbutton.h @@ -0,0 +1,45 @@ +/* + Copyright 2004-2005 Chris Tallon + + This file is part of VOMP. + + VOMP 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. + + VOMP 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 VOMP; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#ifndef WBUTTON_H +#define WBUTTON_H + +#include +#include + +#include "defines.h" +#include "box.h" + +class WButton : public Box +{ + public: + WButton(); + ~WButton(); + void setText(char* text); + void setActive(UCHAR tactive); + void draw(); + + private: + UCHAR active; + + char* mytext; +}; + +#endif diff --git a/wjpeg.cc b/wjpeg.cc new file mode 100644 index 0000000..6379c4e --- /dev/null +++ b/wjpeg.cc @@ -0,0 +1,112 @@ +/* + Copyright 2004-2005 Chris Tallon + + This file is part of VOMP. + + VOMP 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. + + VOMP 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 VOMP; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include "wjpeg.h" + +int WJpeg::init(char* fileName) +{ + this->fileName = fileName; + return 1; +} + +void WJpeg::overrideSurface(Surface* newSurface) +{ + surface = newSurface; +} + +void WJpeg::draw() +{ + Log* logger = Log::getInstance(); + + logger->log("BJpeg", Log::DEBUG, "Here1"); + + FILE* infile = fopen(fileName, "r"); + if (infile == NULL) + { + logger->log("BJpeg", Log::ERR, "Can't open JPEG"); + return; + } + logger->log("BJpeg", Log::DEBUG, "File opened"); + + struct jpeg_decompress_struct cinfo; + struct jpeg_error_mgr jerr; + cinfo.err = jpeg_std_error(&jerr); + jpeg_create_decompress(&cinfo); + jpeg_stdio_src(&cinfo, infile); + jpeg_read_header(&cinfo, TRUE); + jpeg_start_decompress(&cinfo); + + logger->log("BJpeg", Log::DEBUG, "JPEG startup done"); + + // Init the surface + setDimensions(cinfo.output_height, cinfo.output_width); + + + // MAKE THE 2D ARRAY + + unsigned char* buffer = (unsigned char*)malloc(height * width * 3); + logger->log("BJpeg", Log::DEBUG, "Buffer allocated at %p", buffer); + + unsigned char* bufferPointers[height]; + for(int ps = 0; ps < height; ps++) bufferPointers[ps] = buffer + (ps * width * 3); + + logger->log("BJpeg", Log::DEBUG, "done array check"); + + int rowsread = 0; + while (cinfo.output_scanline < cinfo.output_height) + { + rowsread += jpeg_read_scanlines(&cinfo, &bufferPointers[rowsread], height); + } + + logger->log("BJpeg", Log::DEBUG, "Done all jpeg_read"); + + jpeg_finish_decompress(&cinfo); + jpeg_destroy_decompress(&cinfo); + + fclose(infile); + + logger->log("BJpeg", Log::DEBUG, "jpeg shutdown done, x, y %u %u", width, height); + + unsigned int c; + int x, y, xoff; + unsigned char* p; + + for (y = 0; y < height; y++) + { + p = bufferPointers[y]; + + for (x = 0; x < width; x++) + { + xoff = x * 3; + + c = ( (0xFF000000 ) + | (p[xoff ] << 16) + | (p[xoff + 1] << 8) + | (p[xoff + 2] ) ); + + surface->drawPixel(screenX + x, screenY + y, c); + } + } + + free(buffer); + logger->log("BJpeg", Log::DEBUG, "deleted buffer"); + +} + diff --git a/wjpeg.h b/wjpeg.h new file mode 100644 index 0000000..2b43df7 --- /dev/null +++ b/wjpeg.h @@ -0,0 +1,48 @@ +/* + Copyright 2004-2005 Chris Tallon + + This file is part of VOMP. + + VOMP 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. + + VOMP 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 VOMP; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#ifndef WJPEG_H +#define WJPEG_H + +#include +#include +extern "C" +{ + #include +} + +#include "log.h" +#include "box.h" +#include "surface.h" + +class WJpeg : public Box +{ + public: + + int init(char* fileName); + void draw(); + + void overrideSurface(Surface *newSurface); + + private: + char* fileName; +}; + +#endif diff --git a/wselectlist.cc b/wselectlist.cc new file mode 100644 index 0000000..de93a2e --- /dev/null +++ b/wselectlist.cc @@ -0,0 +1,171 @@ +/* + Copyright 2004-2005 Chris Tallon + + This file is part of VOMP. + + VOMP 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. + + VOMP 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 VOMP; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include "wselectlist.h" + +WSelectList::WSelectList() +{ + numOptions = 0; + selectedOption = 0; + topOption = 0; + numOptionsDisplayable = 0; +} + +WSelectList::~WSelectList() +{ + clear(); +} + +void WSelectList::clear() +{ + for (int i = 0; i < numOptions; i++) + { + delete[] options[i]; + } + + numOptions = 0; + selectedOption = 0; + topOption = 0; + numOptionsDisplayable = 0; +} + +void WSelectList::hintSetCurrent(int index) +{ + selectedOption = index; + if (selectedOption >= numOptions) selectedOption = numOptions - 1; +} + +void WSelectList::hintSetTop(int index) +{ + topOption = index; +} + +int WSelectList::addOption(char* text, int selected) +{ + int thisNewOption = numOptions; + int length = strlen(text); + options[thisNewOption] = new char[length + 1]; + strcpy(options[thisNewOption], text); + if (selected) selectedOption = thisNewOption; + numOptions++; + return thisNewOption; +} + +void WSelectList::draw() +{ + int fontHeight = surface->getFontHeight(); + int ySeperation = fontHeight + 1; + + numOptionsDisplayable = (height - 5) / ySeperation; + + if (selectedOption == (topOption + numOptionsDisplayable)) topOption++; + if (selectedOption == (topOption - 1)) topOption--; + // if still not visible... + if ((selectedOption < topOption) || (selectedOption > (topOption + numOptionsDisplayable))) + { + topOption = selectedOption - (numOptionsDisplayable / 2); + } + + if (topOption < 0) topOption = 0; + + + + fillColour(0, 0, 100, 255); + + int ypos = 5; + for (int i = topOption; i < (topOption + numOptionsDisplayable); i++) + { + if (i == numOptions) return; + if ((ypos + ySeperation) > height) break; + + if (i == selectedOption) + { + rectangle(0, ypos, width, fontHeight, 240, 250, 80, 255); + drawText(options[i], 5, ypos, 0, 0, 0); + } + else + { + drawText(options[i], 5, ypos, 255, 255, 255); + } + ypos += ySeperation; + } +} + +void WSelectList::up() +{ + if (selectedOption > 0) + { + selectedOption--; + } + else + { + selectedOption = numOptions - 1; + } +} + +void WSelectList::down() +{ + if (selectedOption < numOptions - 1) + { + selectedOption++; + } + else + { + selectedOption = 0; + } +} + +void WSelectList::pageUp() +{ + topOption -= numOptionsDisplayable; + if (topOption < 0) topOption = 0; + + selectedOption = topOption; +} + +void WSelectList::pageDown() +{ + if ((topOption + numOptionsDisplayable) >= numOptions) return; + + topOption += numOptionsDisplayable; + selectedOption = topOption; +} + +int WSelectList::getTopOption() +{ + return topOption; +} + +int WSelectList::getNumOptions() +{ + return numOptions; +} + +int WSelectList::getBottomOption() +{ + int retval = topOption + numOptionsDisplayable; + if (retval > numOptions) return numOptions; + else return retval; +} + +int WSelectList::getCurrentOption() +{ + return selectedOption; +} diff --git a/wselectlist.h b/wselectlist.h new file mode 100644 index 0000000..3dca0b7 --- /dev/null +++ b/wselectlist.h @@ -0,0 +1,60 @@ +/* + Copyright 2004-2005 Chris Tallon + + This file is part of VOMP. + + VOMP 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. + + VOMP 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 VOMP; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#ifndef WSELECTLIST_H +#define WSELECTLIST_H + +#include +#include + +#include "box.h" + +class WSelectList : public Box +{ + public: + WSelectList(); + ~WSelectList(); + void clear(); + + int addOption(char* text, int selected); + void draw(); + + void down(); + void up(); + void pageUp(); + void pageDown(); + + int getTopOption(); + int getNumOptions(); + int getBottomOption(); + int getCurrentOption(); + + void hintSetCurrent(int index); + void hintSetTop(int index); + + private: + char* options[500]; + int numOptions; + int selectedOption; + int topOption; + int numOptionsDisplayable; +}; + +#endif diff --git a/wsymbol.cc b/wsymbol.cc new file mode 100644 index 0000000..4315f98 --- /dev/null +++ b/wsymbol.cc @@ -0,0 +1,563 @@ +/* + Copyright 2004-2005 Chris Tallon + + This file is part of VOMP. + + VOMP 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. + + VOMP 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 VOMP; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include "wsymbol.h" + +UCHAR WSymbol::widths[] = { 2, 2, 4, 4, 1, 1, 3, 3, 3, 3, 3, 4, 4 }; +UCHAR WSymbol::heights[] = { 8, 8, 12, 12, 24, 4, 18, 18, 18, 18, 18, 30, 30 }; + +UCHAR WSymbol::symbols[] = { + +/* +00000000 00000011 +00000000 00001111 +00000000 00111111 +00000000 11111111 +00000011 11111111 +00001111 11111111 +00111111 11111111 +11111111 11111111 +*/ + +0x00, 0x03, +0x00, 0x0F, +0x00, 0x3F, +0x00, 0xFF, +0x03, 0xFF, +0x0F, 0xFF, +0x3F, 0xFF, +0xFF, 0xFF, + +/* +11111111 00000011 +00000000 00001111 +00000000 00111111 +00000000 11111111 +00000011 11111111 +00001111 11111111 +00111111 11111111 +11111111 11111111 +*/ + +0xFF, 0x03, +0x00, 0x0F, +0x00, 0x3F, +0x00, 0xFF, +0x03, 0xFF, +0x0F, 0xFF, +0x3F, 0xFF, +0xFF, 0xFF, + +/* +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +*/ + +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, + +/* +00000000 00000000 00000000 00000011 +00000000 00000000 00000000 00011111 +00000000 00000000 00000000 11111111 +00000000 00000000 00000011 11111111 +00000000 00000000 00011111 11111111 +00000000 00000000 11111111 11111111 +00000000 00000011 11111111 11111111 +00000000 00011111 11111111 11111111 +00000000 11111111 11111111 11111111 +00000011 11111111 11111111 11111111 +00011111 11111111 11111111 11111111 +11111111 11111111 11111111 11111111 +*/ + +0x00, 0x00, 0x00, 0x03, +0x00, 0x00, 0x00, 0x1F, +0x00, 0x00, 0x00, 0xFF, +0x00, 0x00, 0x03, 0xFF, +0x00, 0x00, 0x1F, 0xFF, +0x00, 0x00, 0xFF, 0xFF, +0x00, 0x03, 0xFF, 0xFF, +0x00, 0x1F, 0xFF, 0xFF, +0x00, 0xFF, 0xFF, 0xFF, +0x03, 0xFF, 0xFF, 0xFF, +0x1F, 0xFF, 0xFF, 0xFF, +0xFF, 0xFF, 0xFF, 0xFF, + +/* +00001111 +00001111 +00001111 +00001111 +00001111 +00001111 +00001111 +00001111 +00001111 +00001111 +00001111 +00001111 +00001111 +00001111 +00001111 +00001111 +00001111 +00001111 +00001111 +00001111 +00001111 +00001111 +00001111 +00001111 +*/ + +0x0F, +0x0F, +0x0F, +0x0F, +0x0F, +0x0F, +0x0F, +0x0F, +0x0F, +0x0F, +0x0F, +0x0F, +0x0F, +0x0F, +0x0F, +0x0F, +0x0F, +0x0F, +0x0F, +0x0F, +0x0F, +0x0F, +0x0F, +0x0F, + +/* +00001111 +00001111 +00001111 +00001111 +*/ + +0x0F, +0x0F, +0x0F, +0x0F, + +/* +11000000 00000000 00110000 +11000000 00000000 11110000 +11000000 00000011 11110000 +11000000 00001111 11110000 +11000000 00111111 11110000 +11000000 11111111 11110000 +11000011 11111111 11110000 +11001111 11111111 11110000 +11111111 11111111 11110000 + +11111111 11111111 11110000 +11001111 11111111 11110000 +11000011 11111111 11110000 +11000000 11111111 11110000 +11000000 00111111 11110000 +11000000 00001111 11110000 +11000000 00000011 11110000 +11000000 00000000 11110000 +11000000 00000000 00110000 +*/ + +0xC0, 0x00, 0x30, +0xC0, 0x00, 0xF0, +0xC0, 0x03, 0xF0, +0xC0, 0x0F, 0xF0, +0xC0, 0x3F, 0xF0, +0xC0, 0xFF, 0xF0, +0xC3, 0xFF, 0xF0, +0xCF, 0xFF, 0xF0, +0xFF, 0xFF, 0xF0, + +0xFF, 0xFF, 0xF0, +0xCF, 0xFF, 0xF0, +0xC3, 0xFF, 0xF0, +0xC0, 0xFF, 0xF0, +0xC0, 0x3F, 0xF0, +0xC0, 0x0F, 0xF0, +0xC0, 0x03, 0xF0, +0xC0, 0x00, 0xF0, +0xC0, 0x00, 0x30, + +/* +11000000 00000000 00110000 +11110000 00000000 00110000 +11111100 00000000 00110000 +11111111 00000000 00110000 +11111111 11000000 00110000 +11111111 11110000 00110000 +11111111 11111100 00110000 +11111111 11111111 00110000 +11111111 11111111 11110000 + +11111111 11111111 11110000 +11111111 11111111 00110000 +11111111 11111100 00110000 +11111111 11110000 00110000 +11111111 11000000 00110000 +11111111 00000000 00110000 +11111100 00000000 00110000 +11110000 00000000 00110000 +11000000 00000000 00110000 +*/ + +0xC0, 0x00, 0x30, +0xF0, 0x00, 0x30, +0xFC, 0x00, 0x30, +0xFF, 0x00, 0x30, +0xFF, 0xC0, 0x30, +0xFF, 0xF0, 0x30, +0xFF, 0xFC, 0x30, +0xFF, 0xFF, 0x30, +0xFF, 0xFF, 0xF0, + +0xFF, 0xFF, 0xF0, +0xFF, 0xFF, 0x30, +0xFF, 0xFC, 0x30, +0xFF, 0xF0, 0x30, +0xFF, 0xC0, 0x30, +0xFF, 0x00, 0x30, +0xFC, 0x00, 0x30, +0xF0, 0x00, 0x30, +0xC0, 0x00, 0x30, + +/* +00000000 00000000 00000000 +00000000 00000000 00000000 +00000000 00000000 00000000 +00000000 00000000 00000000 +00000000 01100000 00000000 +00000000 11110000 00000000 +00000001 11111000 00000000 +00000001 11111000 00000000 +00000011 11111100 00000000 + +00000111 11111110 00000000 +00001111 11111111 00000000 +00011111 11111111 10000000 +00011111 11111111 10000000 +00111111 11111111 11000000 +01111111 11111111 11100000 +11111111 11111111 11110000 +00000000 00000000 00000000 +00000000 00000000 00000000 +*/ + +0x00, 0x00, 0x00, +0x00, 0x00, 0x00, +0x00, 0x00, 0x00, +0x00, 0x00, 0x00, +0x00, 0x60, 0x00, +0x00, 0xF0, 0x00, +0x01, 0xF8, 0x00, +0x01, 0xF8, 0x00, +0x03, 0xFC, 0x00, + +0x07, 0xFE, 0x00, +0x0F, 0xFF, 0x00, +0x1F, 0xFF, 0x80, +0x1F, 0xFF, 0x80, +0x3F, 0xFF, 0xC0, +0x7F, 0xFF, 0xE0, +0xFF, 0xFF, 0xF0, +0x00, 0x00, 0x00, +0x00, 0x00, 0x00, + +/* +00000000 00000000 00000000 +00000000 00000000 00000000 +00000000 00000000 00000000 +00000000 00000000 00000000 +11111111 11111111 11110000 +01111111 11111111 11100000 +00111111 11111111 11000000 +00011111 11111111 10000000 +00011111 11111111 10000000 + +00001111 11111111 00000000 +00000111 11111110 00000000 +00000011 11111100 00000000 +00000001 11111000 00000000 +00000001 11111000 00000000 +00000000 11110000 00000000 +00000000 01100000 00000000 +00000000 00000000 00000000 +00000000 00000000 00000000 +*/ + +0x00, 0x00, 0x00, +0x00, 0x00, 0x00, +0x00, 0x00, 0x00, +0x00, 0x00, 0x00, +0xFF, 0xFF, 0xF0, +0x7F, 0xFF, 0xE0, +0x3F, 0xFF, 0xC0, +0x1F, 0xFF, 0x80, +0x1F, 0xFF, 0x80, + +0x0F, 0xFF, 0x00, +0x07, 0xFE, 0x00, +0x03, 0xFC, 0x00, +0x01, 0xF8, 0x00, +0x01, 0xF8, 0x00, +0x00, 0xF0, 0x00, +0x00, 0x60, 0x00, +0x00, 0x00, 0x00, +0x00, 0x00, 0x00, + + +/* +11000000 00000000 00000000 +11110000 00000000 00000000 +11111100 00000000 00000000 +11111111 00000000 00000000 +11111111 11000000 00000000 +11111111 11110000 00000000 +11111111 11111100 00000000 +11111111 11111111 00000000 +11111111 11111111 11000000 + +11111111 11111111 11000000 +11111111 11111111 00000000 +11111111 11111100 00000000 +11111111 11110000 00000000 +11111111 11000000 00000000 +11111111 00000000 00000000 +11111100 00000000 00000000 +11110000 00000000 00000000 +11000000 00000000 00000000 +*/ + +0xC0, 0x00, 0x00, +0xF0, 0x00, 0x00, +0xFC, 0x00, 0x00, +0xFF, 0x00, 0x00, +0xFF, 0xC0, 0x00, +0xFF, 0xF0, 0x00, +0xFF, 0xFC, 0x00, +0xFF, 0xFF, 0x00, +0xFF, 0xFF, 0xC0, + +0xFF, 0xFF, 0xC0, +0xFF, 0xFF, 0x00, +0xFF, 0xFC, 0x00, +0xFF, 0xF0, 0x00, +0xFF, 0xC0, 0x00, +0xFF, 0x00, 0x00, +0xFC, 0x00, 0x00, +0xF0, 0x00, 0x00, +0xC0, 0x00, 0x00, + +/* +11000000 00000000 00000000 00001100 +01100000 00000000 11000000 00011000 +00110000 00000001 11000000 00110000 +00011000 00000011 11000000 01100000 +00001100 00000111 11000000 11000000 +00000110 00001111 11000001 10000000 +00000011 00011111 11000011 00000000 +00000001 10111111 11000110 00000000 +00000000 11111111 11001100 00000000 +00000000 11111111 11011000 00000000 +00001111 11111111 11110000 00000000 +00001111 11111111 11100000 00000000 +00001111 11111111 11000000 00000000 +00001111 11111111 11000000 00000000 +00001111 11111111 11000000 00000000 +00001111 11111111 11000000 00000000 +00001111 11111111 11000000 00000000 +00001111 11111111 11100000 00000000 +00001111 11111111 11110000 00000000 +00000000 11111111 11011000 00000000 +00000000 11111111 11001100 00000000 +00000001 10111111 11000110 00000000 +00000011 00011111 11000011 00000000 +00000110 00001111 11000001 10000000 +00001100 00000111 11000000 11000000 +00011000 00000011 11000000 01100000 +00110000 00000001 11000000 00110000 +01100000 00000000 11000000 00011000 +11000000 00000000 00000000 00001100 +00000000 00000000 00000000 00000000 +*/ + +0xC0, 0x00, 0x00, 0x0C, +0x60, 0x00, 0xC0, 0x18, +0x30, 0x01, 0xC0, 0x30, +0x18, 0x03, 0xC0, 0x60, +0x0C, 0x07, 0xC0, 0xC0, +0x06, 0x0F, 0xC1, 0x80, +0x03, 0x1F, 0xC3, 0x00, +0x01, 0xBF, 0xC6, 0x00, +0x00, 0xFF, 0xCC, 0x00, +0x00, 0xFF, 0xD8, 0x00, +0x0F, 0xFF, 0xF0, 0x00, +0x0F, 0xFF, 0xE0, 0x00, +0x0F, 0xFF, 0xC0, 0x00, +0x0F, 0xFF, 0xC0, 0x00, +0x0F, 0xFF, 0xC0, 0x00, +0x0F, 0xFF, 0xC0, 0x00, +0x0F, 0xFF, 0xC0, 0x00, +0x0F, 0xFF, 0xE0, 0x00, +0x0F, 0xFF, 0xF0, 0x00, +0x00, 0xFF, 0xD8, 0x00, +0x00, 0xFF, 0xCC, 0x00, +0x01, 0xBF, 0xC6, 0x00, +0x03, 0x1F, 0xC3, 0x00, +0x06, 0x0F, 0xC1, 0x80, +0x0C, 0x07, 0xC0, 0xC0, +0x18, 0x03, 0xC0, 0x60, +0x30, 0x01, 0xC0, 0x30, +0x60, 0x00, 0xC0, 0x18, +0xC0, 0x00, 0x00, 0x0C, +0x00, 0x00, 0x00, 0x00, + +/* +00000000 00000000 00000000 00000000 +00000000 00000000 11000000 00000000 +00000000 00000001 11000000 00000000 +00000000 00000011 11011111 10000000 +00000000 00000111 11011111 10000000 +00000000 00001111 11000000 00000000 +00000000 00011111 11000000 00000000 +00000000 00111111 11000000 00000000 +00000000 01111111 11011111 10000000 +00000000 11111111 11011111 10000000 +00001111 11111111 11000000 00000000 +00001111 11111111 11000000 00000000 +00001111 11111111 11000000 00000000 +00001111 11111111 11011111 10000000 +00001111 11111111 11011111 10000000 +00001111 11111111 11000000 00000000 +00001111 11111111 11000000 00000000 +00001111 11111111 11000000 00000000 +00001111 11111111 11011111 10000000 +00000000 11111111 11011111 10000000 +00000000 01111111 11000000 00000000 +00000000 00111111 11000000 00000000 +00000000 00011111 11000000 00000000 +00000000 00001111 11011111 10000000 +00000000 00000111 11011111 10000000 +00000000 00000011 11000000 00000000 +00000000 00000001 11000000 00000000 +00000000 00000000 11000000 00000000 +00000000 00000000 00000000 00000000 +00000000 00000000 00000000 00000000 +*/ + +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0xC0, 0x00, +0x00, 0x01, 0xC0, 0x00, +0x00, 0x03, 0xDF, 0x80, +0x00, 0x07, 0xDF, 0x80, +0x00, 0x0F, 0xC0, 0x00, +0x00, 0x1F, 0xC0, 0x00, +0x00, 0x3F, 0xC0, 0x00, +0x00, 0x7F, 0xDF, 0x80, +0x00, 0xFF, 0xDF, 0x80, +0x0F, 0xFF, 0xC0, 0x00, +0x0F, 0xFF, 0xC0, 0x00, +0x0F, 0xFF, 0xC0, 0x00, +0x0F, 0xFF, 0xDF, 0x80, +0x0F, 0xFF, 0xDF, 0x80, +0x0F, 0xFF, 0xC0, 0x00, +0x0F, 0xFF, 0xC0, 0x00, +0x0F, 0xFF, 0xC0, 0x00, +0x0F, 0xFF, 0xDF, 0x80, +0x00, 0xFF, 0xDF, 0x80, +0x00, 0x7F, 0xC0, 0x00, +0x00, 0x3F, 0xC0, 0x00, +0x00, 0x1F, 0xC0, 0x00, +0x00, 0x0F, 0xDF, 0x80, +0x00, 0x07, 0xDF, 0x80, +0x00, 0x03, 0xC0, 0x00, +0x00, 0x01, 0xC0, 0x00, +0x00, 0x00, 0xC0, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00 + + +}; + +WSymbol::WSymbol() +{ + nextSymbol = 0; +} + +void WSymbol::draw() +{ + int offset = 0; + for(int i = 0; i < nextSymbol; i++) + { + offset += (widths[i]) * heights[i]; + } + + UCHAR* base = symbols + offset; + int widthBytes = widths[nextSymbol]; + int widthBits = widthBytes * 8; + int height = heights[nextSymbol]; + + int x, y, bytesIn, bitsIn; + + for (y = 0; y < height; y++) + { + for (x = 0; x < widthBits; x++) + { + bytesIn = (y * widthBytes) + (int)(x / 8); + bitsIn = x % 8; + + if ((base[bytesIn] >> (7 - bitsIn)) & 0x01) + { + drawPixel(x, y, 0xFFFFFFFF); + } + } + } +} diff --git a/wsymbol.h b/wsymbol.h new file mode 100644 index 0000000..c7e66ea --- /dev/null +++ b/wsymbol.h @@ -0,0 +1,55 @@ +/* + Copyright 2004-2005 Chris Tallon + + This file is part of VOMP. + + VOMP 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. + + VOMP 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 VOMP; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#ifndef WSYMBOL_H +#define WSYMBOL_H + +#include "defines.h" +#include "box.h" + +class WSymbol : public Box +{ + public: + WSymbol(); + + void draw(); + UCHAR nextSymbol; + + const static UCHAR VOLUME = 0; + const static UCHAR TEST = 1; + const static UCHAR TEST2 = 2; + const static UCHAR VOLUME2 = 3; + const static UCHAR VOLBAR = 4; + const static UCHAR VOLDOT = 5; + const static UCHAR SKIPBACK = 6; + const static UCHAR SKIPFORWARD = 7; + const static UCHAR UP = 8; + const static UCHAR DOWN = 9; + const static UCHAR PLAY = 10; + const static UCHAR MUTE = 11; + const static UCHAR UNMUTE = 12; + + private: + static UCHAR symbols[]; + static UCHAR widths[]; + static UCHAR heights[]; +}; + +#endif -- 2.39.5