diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-10 18:07:22 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-10 18:07:22 +0000 |
commit | c04dcc2e7d834218ef2d4194331e383402495ae1 (patch) | |
tree | 7333e38d10d75386e60f336b80c2443c1166031d /tools | |
parent | Initial commit. (diff) | |
download | kodi-c04dcc2e7d834218ef2d4194331e383402495ae1.tar.xz kodi-c04dcc2e7d834218ef2d4194331e383402495ae1.zip |
Adding upstream version 2:20.4+dfsg.upstream/2%20.4+dfsg
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'tools')
450 files changed, 36012 insertions, 0 deletions
diff --git a/tools/EventClients/Clients/KodiSend/kodi-send.py b/tools/EventClients/Clients/KodiSend/kodi-send.py new file mode 100755 index 0000000..2760b11 --- /dev/null +++ b/tools/EventClients/Clients/KodiSend/kodi-send.py @@ -0,0 +1,135 @@ +#!/usr/bin/env python3 +# +# XBMC Media Center +# XBMC Send +# Copyright (c) 2009 team-xbmc +# +# 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., 675 Mass Ave, Cambridge, MA 02139, USA. +# + +import sys, os +import getopt +from socket import * +from time import sleep +try: + from kodi.xbmcclient import * +except: + sys.path.append(os.path.join(os.path.realpath(os.path.dirname(__file__)), '../../lib/python')) + from xbmcclient import * + +TYPE_MOUSE = 'mouse' +TYPE_NOTIFICATION = 'notification' +TYPE_LOG = 'log' +TYPE_ACTION = 'action' +TYPE_BUTTON = 'button' +TYPE_DELAY = 'delay' + +log_map = { + "LOGDEBUG": LOGDEBUG, + "LOGINFO": LOGINFO, + "LOGWARNING": LOGWARNING, + "LOGERROR": LOGERROR, + "LOGFATAL": LOGFATAL, +} + +def usage(): + print("Usage") + print("\tkodi-send [OPTION] --action=ACTION") + print("\tkodi-send [OPTION] --button=BUTTON") + print('Example') + print('\tkodi-send --host=192.168.0.1 --port=9777 --action="Quit"') + print("Options") + print("\t-?, --help\t\t\tWill bring up this message") + print("\t--host=HOST\t\t\tChoose what HOST to connect to (default=localhost)") + print("\t--port=PORT\t\t\tChoose what PORT to connect to (default=9777)") + print("\t--keymap=KEYMAP\t\t\tChoose which KEYMAP to use for key presses (default=KB)") + print('\t--button=BUTTON\t\t\tSends a key press event to Kodi, this option can be added multiple times to create a macro') + print('\t--mouse=X,Y\t\t\tSends the mouse position to Kodi') + print("\t--log=MESSAGE\t\t\tSends a log message to Kodi") + print("\t--loglevel=LEVEL\t\tSets the log level when using --log= (default=LOGDEBUG)") + print("\t--notification=MESSAGE\t\tSends a notification to Kodi") + print('\t-a ACTION, --action=ACTION\tSends an action to Kodi, this option can be added multiple times to create a macro') + print('\t-d T, --delay=T\t\t\tWaits for T ms, this option can be added multiple times to create a macro') + pass + +def main(): + try: + opts, args = getopt.getopt(sys.argv[1:], "?pa:d:v", ["help", "host=", "port=", "keymap=", "button=", "mouse=", "log=", "loglevel=", "notification=", "action=", "delay="]) + except getopt.GetoptError as err: + # print help information and exit: + print(str(err)) # will print something like "option -a not recognized" + usage() + sys.exit(2) + ip = "localhost" + port = 9777 + keymap = "KB" + loglevel = LOGDEBUG + actions = [] + verbose = False + for o, a in opts: + if o in ("-?", "--help"): + usage() + sys.exit() + elif o == "--host": + ip = a + elif o == "--port": + port = int(a) + elif o == "--keymap": + keymap = a + elif o == "--button": + actions.append({'type': TYPE_BUTTON, 'content': a}) + elif o == "--mouse": + actions.append({'type': TYPE_MOUSE, 'content': a}) + elif o == "--log": + actions.append({'type': TYPE_LOG, 'content': a}) + elif o == "--loglevel": + loglevel = log_map.get(a) + elif o == "--notification": + actions.append({'type': TYPE_NOTIFICATION, 'content': a}) + elif o in ("-a", "--action"): + actions.append({'type': TYPE_ACTION, 'content': a}) + elif o in ("-d", "--delay"): + actions.append({'type': TYPE_DELAY, 'content': int(a)}) + else: + assert False, "unhandled option" + + addr = (ip, port) + sock = socket(AF_INET,SOCK_DGRAM) + + if len(actions) == 0: + usage() + sys.exit(0) + + for action in actions: + print('Sending: %s' % action) + if action['type'] == TYPE_ACTION: + packet = PacketACTION(actionmessage=action['content'], actiontype=ACTION_BUTTON) + elif action['type'] == TYPE_BUTTON: + packet = PacketBUTTON(code=0, repeat=0, down=1, queue=1, map_name=keymap, button_name=action['content'], amount=0) + elif action['type'] == TYPE_MOUSE: + x = int(action['content'].split(',')[0]) + y = int(action['content'].split(',')[1]) + packet = PacketMOUSE(x=x, y=y) + elif action['type'] == TYPE_DELAY: + time.sleep(action['content'] / 1000.0) + continue + elif action['type'] == TYPE_LOG: + packet = PacketLOG(loglevel=loglevel, logmessage=action['content'], autoprint=False) + elif action['type'] == TYPE_NOTIFICATION: + packet = PacketNOTIFICATION(title='kodi-send', message=action['content']) + packet.send(sock, addr, uid=0) + +if __name__=="__main__": + main() diff --git a/tools/EventClients/Clients/PS3BDRemote/ps3_remote.py b/tools/EventClients/Clients/PS3BDRemote/ps3_remote.py new file mode 100755 index 0000000..72ae71a --- /dev/null +++ b/tools/EventClients/Clients/PS3BDRemote/ps3_remote.py @@ -0,0 +1,219 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +# Copyright (C) 2008-2013 Team XBMC +# +# 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 Street, Fifth Floor, Boston, MA 02110-1301 USA. + +# This is a quick port of brandonj's PS3 remote script to use the event server +# for sending input events. +# +# The original script and documentation regarding the remote can be found at: +# http://forum.kodi.tv/showthread.php?tid=28765 +# +# +# TODO: +# 1. Send keepalive ping at least once every 60 seconds to prevent timeouts +# 2. Permanent pairing +# 3. Detect if Kodi has been restarted (non trivial until broadcasting is +# implemented, until then maybe the HELO packet could be used instead of +# PING as keepalive +# + +import sys + +try: + # try loading modules from source directory + sys.path.append("../../lib/python") + from xbmcclient import * + from ps3.keymaps import keymap_remote as g_keymap # look here to change the keymapping + from bt.bt import * + ICON_PATH = "../../icons/" +except: + # fallback to system wide modules + from kodi.xbmcclient import * + from kodi.ps3.keymaps import keymap_remote as g_keymap # look here to change the keymapping + from kodi.bt.bt import * + from kodi.defs import * + +import os +import time + +xbmc = None +bticon = ICON_PATH + "/bluetooth.png" + +def get_remote_address(remote, target_name = "BD Remote Control"): + global xbmc + target_connected = False + target_address = None + while target_connected is False: + xbmc.send_notification("Action Required!", + "Hold Start+Enter on your remote.", + bticon) + print("Searching for %s" % target_name) + print("(Hold Start + Enter on remote to make it discoverable)") + time.sleep(2) + + if not target_address: + try: + nearby_devices = bt_discover_devices() + except Exception as e: + print("Error performing bluetooth discovery") + print(str(e)) + xbmc.send_notification("Error", "Unable to find devices.", bticon) + time.sleep(5) + continue + + for bdaddr in nearby_devices: + bname = bt_lookup_name( bdaddr ) + addr = bt_lookup_addr ( bdaddr ) + print("%s (%s) in range" % (bname,addr)) + if target_name == bname: + target_address = addr + break + + if target_address is not None: + print("Found %s with address %s" % (target_name, target_address)) + xbmc.send_notification("Found Device", + "Pairing %s, please wait." % target_name, + bticon) + print("Attempting to pair with remote") + + try: + remote.connect((target_address,19)) + target_connected = True + print("Remote Paired.\a") + xbmc.send_notification("Pairing Successful", + "Your remote was successfully "\ + "paired and is ready to be used.", + bticon) + except: + del remote + remote = bt_create_socket() + target_address = None + xbmc.send_notification("Pairing Failed", + "An error occurred while attempting to "\ + "pair.", bticon) + print("ERROR - Could Not Connect. Trying again...") + time.sleep(2) + else: + xbmc.send_notification("Error", "No remotes were found.", bticon) + print("Could not find BD Remote Control. Trying again...") + time.sleep(2) + return (remote,target_address) + + +def usage(): + print(""" +PS3 Blu-Ray Remote Control Client for XBMC v0.1 + +Usage: ps3_remote.py <address> [port] + + address => address of system that XBMC is running on + ("localhost" if it is this machine) + + port => port to send packets to + (default 9777) +""") + +def process_keys(remote, xbmc): + """ + Return codes: + 0 - key was processed normally + 2 - socket read timeout + 3 - PS and then Skip Plus was pressed (sequentially) + 4 - PS and then Skip Minus was pressed (sequentially) + + FIXME: move to enums + """ + done = 0 + + try: + xbmc.previous_key + except: + xbmc.previous_key = "" + + xbmc.connect() + datalen = 0 + try: + data = remote.recv(1024) + datalen = len(data) + except Exception as e: + if str(e)=="timed out": + return 2 + time.sleep(2) + + # some other read exception occurred, so raise it + raise e + + if datalen == 13: + keycode = data.hex()[10:12] + if keycode == "ff": + xbmc.release_button() + return done + try: + # if the user presses the PS button followed by skip + or skip - + # return different codes. + if xbmc.previous_key == "43": + xbmc.previous_key = keycode + if keycode == "31": # skip + + return 3 + elif keycode == "30": # skip - + return 4 + + # save previous key press + xbmc.previous_key = keycode + + if g_keymap[keycode]: + xbmc.send_remote_button(g_keymap[keycode]) + except Exception as e: + print("Unknown data: %s" % str(e)) + return done + +def main(): + global xbmc, bticon + + host = "127.0.0.1" + port = 9777 + + if len(sys.argv)>1: + try: + host = sys.argv[1] + port = sys.argv[2] + except: + pass + else: + return usage() + + loop_forever = True + xbmc = XBMCClient("PS3 Bluetooth Remote", + icon_file=bticon) + + while loop_forever is True: + target_connected = False + remote = bt_create_socket() + xbmc.connect(host, port) + (remote,target_address) = get_remote_address(remote) + while True: + if process_keys(remote, xbmc): + break + print("Disconnected.") + try: + remote.close() + except: + print("Cannot close.") + +if __name__=="__main__": + main() diff --git a/tools/EventClients/Clients/PS3SixaxisController/README.ubuntu b/tools/EventClients/Clients/PS3SixaxisController/README.ubuntu new file mode 100644 index 0000000..bf4a5a4 --- /dev/null +++ b/tools/EventClients/Clients/PS3SixaxisController/README.ubuntu @@ -0,0 +1 @@ +sudo apt-get install python-usb python-pyudev python-bluez diff --git a/tools/EventClients/Clients/PS3SixaxisController/ps3d.py b/tools/EventClients/Clients/PS3SixaxisController/ps3d.py new file mode 100755 index 0000000..32ed361 --- /dev/null +++ b/tools/EventClients/Clients/PS3SixaxisController/ps3d.py @@ -0,0 +1,406 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +# Copyright (C) 2008-2013 Team XBMC +# +# 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 Street, Fifth Floor, Boston, MA 02110-1301 USA. + +import sys +import traceback +import time +import struct +import threading +import os + +if os.path.exists("../../lib/python"): + sys.path.append("../PS3BDRemote") + sys.path.append("../../lib/python") + from bt.hid import HID + from bt.bt import bt_lookup_name + from xbmcclient import XBMCClient + from ps3 import sixaxis + from ps3_remote import process_keys as process_remote + try: + from ps3 import sixwatch + except Exception as e: + print("Failed to import sixwatch now disabled: " + str(e)) + sixwatch = None + + try: + import zeroconf + except: + zeroconf = None + ICON_PATH = "../../icons/" +else: + # fallback to system wide modules + from kodi.bt.hid import HID + from kodi.bt.bt import bt_lookup_name + from kodi.xbmcclient import XBMCClient + from kodi.ps3 import sixaxis + from kodi.ps3_remote import process_keys as process_remote + from kodi.defs import * + try: + from kodi.ps3 import sixwatch + except Exception as e: + print("Failed to import sixwatch now disabled: " + str(e)) + sixwatch = None + try: + import kodi.zeroconf as zeroconf + except: + zeroconf = None + + +event_threads = [] + +def printerr(): + trace = "" + exception = "" + exc_list = traceback.format_exception_only (sys.exc_type, sys.exc_value) + for entry in exc_list: + exception += entry + tb_list = traceback.format_tb(sys.exc_info()[2]) + for entry in tb_list: + trace += entry + print("%s\n%s" % (exception, trace), "Script Error") + + +class StoppableThread ( threading.Thread ): + def __init__(self): + threading.Thread.__init__(self) + self._stop = False + self.set_timeout(0) + + def stop_thread(self): + self._stop = True + + def stop(self): + return self._stop + + def close_sockets(self): + if self.isock: + try: + self.isock.close() + except: + pass + self.isock = None + if self.csock: + try: + self.csock.close() + except: + pass + self.csock = None + self.last_action = 0 + + def set_timeout(self, seconds): + self.timeout = seconds + + def reset_timeout(self): + self.last_action = time.time() + + def idle_time(self): + return time.time() - self.last_action + + def timed_out(self): + if (time.time() - self.last_action) > self.timeout: + return True + else: + return False + + +class PS3SixaxisThread ( StoppableThread ): + def __init__(self, csock, isock, ipaddr="127.0.0.1"): + StoppableThread.__init__(self) + self.csock = csock + self.isock = isock + self.xbmc = XBMCClient(name="PS3 Sixaxis", icon_file=ICON_PATH + "/bluetooth.png", ip=ipaddr) + self.set_timeout(600) + + def run(self): + six = sixaxis.sixaxis(self.xbmc, self.csock, self.isock) + self.xbmc.connect() + self.reset_timeout() + try: + while not self.stop(): + + if self.timed_out(): + raise Exception("PS3 Sixaxis powering off, timed out") + if self.idle_time() > 50: + self.xbmc.connect() + try: + if six.process_socket(self.isock): + self.reset_timeout() + except Exception as e: + print(e) + break + + except Exception as e: + printerr() + six.close() + self.close_sockets() + + +class PS3RemoteThread ( StoppableThread ): + def __init__(self, csock, isock, ipaddr="127.0.0.1"): + StoppableThread.__init__(self) + self.csock = csock + self.isock = isock + self.xbmc = XBMCClient(name="PS3 Blu-Ray Remote", icon_file=ICON_PATH + "/bluetooth.png", ip=ipaddr) + self.set_timeout(600) + self.services = [] + self.current_xbmc = 0 + + def run(self): + self.xbmc.connect() + try: + # start the zeroconf thread if possible + try: + self.zeroconf_thread = ZeroconfThread() + self.zeroconf_thread.add_service('_xbmc-events._udp', + self.zeroconf_service_handler) + self.zeroconf_thread.start() + except Exception as e: + print(str(e)) + + # main thread loop + while not self.stop(): + status = process_remote(self.isock, self.xbmc) + + if status == 2: # 2 = socket read timeout + if self.timed_out(): + raise Exception("PS3 Blu-Ray Remote powering off, "\ + "timed out") + elif status == 3: # 3 = ps and skip + + self.next_xbmc() + + elif status == 4: # 4 = ps and skip - + self.previous_xbmc() + + elif not status: # 0 = keys are normally processed + self.reset_timeout() + + # process_remote() will raise an exception on read errors + except Exception as e: + print(str(e)) + + self.zeroconf_thread.stop() + self.close_sockets() + + def next_xbmc(self): + """ + Connect to the next XBMC instance + """ + self.current_xbmc = (self.current_xbmc + 1) % len( self.services ) + self.reconnect() + return + + def previous_xbmc(self): + """ + Connect to the previous XBMC instance + """ + self.current_xbmc -= 1 + if self.current_xbmc < 0 : + self.current_xbmc = len( self.services ) - 1 + self.reconnect() + return + + def reconnect(self): + """ + Reconnect to an XBMC instance based on self.current_xbmc + """ + try: + service = self.services[ self.current_xbmc ] + print("Connecting to %s" % service['name']) + self.xbmc.connect( service['address'], service['port'] ) + self.xbmc.send_notification("PS3 Blu-Ray Remote", "New Connection", None) + except Exception as e: + print(str(e)) + + def zeroconf_service_handler(self, event, service): + """ + Zeroconf event handler + """ + if event == zeroconf.SERVICE_FOUND: # new xbmc service detected + self.services.append( service ) + + elif event == zeroconf.SERVICE_LOST: # xbmc service lost + try: + # search for the service by name, since IP+port isn't available + for s in self.services: + # nuke it, if found + if service['name'] == s['name']: + self.services.remove(s) + break + except: + pass + return + +class SixWatch(threading.Thread): + def __init__(self, mac): + threading.Thread.__init__(self) + self.mac = mac + self.daemon = True + self.start() + def run(self): + while True: + try: + sixwatch.main(self.mac) + except Exception as e: + print("Exception caught in sixwatch, restarting: " + str(e)) + +class ZeroconfThread ( threading.Thread ): + """ + + """ + def __init__(self): + threading.Thread.__init__(self) + self._zbrowser = None + self._services = [] + + def run(self): + if zeroconf: + # create zeroconf service browser + self._zbrowser = zeroconf.Browser() + + # add the requested services + for service in self._services: + self._zbrowser.add_service( service[0], service[1] ) + + # run the event loop + self._zbrowser.run() + + return + + + def stop(self): + """ + Stop the zeroconf browser + """ + try: + self._zbrowser.stop() + except: + pass + return + + def add_service(self, type, handler): + """ + Add a new service to search for. + NOTE: Services must be added before thread starts. + """ + self._services.append( [ type, handler ] ) + + +def usage(): + print(""" +PS3 Sixaxis / Blu-Ray Remote HID Server v0.1 + +Usage: ps3.py [bdaddress] [XBMC host] + + bdaddress => address of local bluetooth device to use (default: auto) + (e.g. aa:bb:cc:dd:ee:ff) + ip address => IP address or hostname of the XBMC instance (default: localhost) + (e.g. 192.168.1.110) +""") + +def start_hidd(bdaddr=None, ipaddr="127.0.0.1"): + devices = [ 'PLAYSTATION(R)3 Controller', + 'BD Remote Control' ] + hid = HID(bdaddr) + watch = None + if sixwatch: + try: + print("Starting USB sixwatch") + watch = SixWatch(hid.get_local_address()) + except Exception as e: + print("Failed to initialize sixwatch" + str(e)) + pass + + while True: + if hid.listen(): + (csock, addr) = hid.get_control_socket() + device_name = bt_lookup_name(addr[0]) + if device_name == devices[0]: + # handle PS3 controller + handle_ps3_controller(hid, ipaddr) + elif device_name == devices[1]: + # handle the PS3 remote + handle_ps3_remote(hid, ipaddr) + else: + print("Unknown Device: %s" % (device_name)) + +def handle_ps3_controller(hid, ipaddr): + print("Received connection from a Sixaxis PS3 Controller") + csock = hid.get_control_socket()[0] + isock = hid.get_interrupt_socket()[0] + sixaxis = PS3SixaxisThread(csock, isock, ipaddr) + add_thread(sixaxis) + sixaxis.start() + return + +def handle_ps3_remote(hid, ipaddr): + print("Received connection from a PS3 Blu-Ray Remote") + csock = hid.get_control_socket()[0] + isock = hid.get_interrupt_socket()[0] + isock.settimeout(1) + remote = PS3RemoteThread(csock, isock, ipaddr) + add_thread(remote) + remote.start() + return + +def add_thread(thread): + global event_threads + event_threads.append(thread) + +def main(): + if len(sys.argv)>3: + return usage() + bdaddr = "" + ipaddr = "127.0.0.1" + try: + for addr in sys.argv[1:]: + try: + # ensure that the addr is of the format 'aa:bb:cc:dd:ee:ff' + if "".join([ str(len(a)) for a in addr.split(":") ]) != "222222": + raise Exception("Invalid format") + bdaddr = addr + print("Connecting to Bluetooth device: %s" % bdaddr) + except Exception as e: + try: + ipaddr = addr + print("Connecting to : %s" % ipaddr) + except: + print(str(e)) + return usage() + except Exception as e: + pass + + print("Starting HID daemon") + start_hidd(bdaddr, ipaddr) + +if __name__=="__main__": + try: + main() + finally: + for t in event_threads: + try: + print("Waiting for thread "+str(t)+" to terminate") + t.stop_thread() + if t.isAlive(): + t.join() + print("Thread "+str(t)+" terminated") + + except Exception as e: + print(str(e)) + pass + diff --git a/tools/EventClients/Clients/WiiRemote/CMakeLists.txt b/tools/EventClients/Clients/WiiRemote/CMakeLists.txt new file mode 100644 index 0000000..8c797b2 --- /dev/null +++ b/tools/EventClients/Clients/WiiRemote/CMakeLists.txt @@ -0,0 +1,23 @@ +list(APPEND CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake/modules) + +find_package(Bluetooth REQUIRED) +find_package(CWiid REQUIRED) +find_package(GLU REQUIRED) + +set(SOURCES CWIID_WiiRemote.cpp) + +set(HEADERS CWIID_WiiRemote.h) + +add_executable(${APP_NAME_LC}-wiiremote ${SOURCES} ${HEADERS}) + +target_include_directories(${APP_NAME_LC}-wiiremote + PRIVATE ${BLUETOOTH_INCLUDE_DIRS} + ${CWIID_INCLUDE_DIRS}) + +target_link_libraries(${APP_NAME_LC}-wiiremote + PRIVATE ${SYSTEM_LDFLAGS} + ${BLUETOOTH_LIBRARIES} + ${CWIID_LIBRARIES}) + +target_compile_options(${APP_NAME_LC}-wiiremote PRIVATE ${ARCH_DEFINES}) + diff --git a/tools/EventClients/Clients/WiiRemote/CWIID_WiiRemote.cpp b/tools/EventClients/Clients/WiiRemote/CWIID_WiiRemote.cpp new file mode 100644 index 0000000..19ff811 --- /dev/null +++ b/tools/EventClients/Clients/WiiRemote/CWIID_WiiRemote.cpp @@ -0,0 +1,778 @@ +/* + * Copyright (C) 2007 by Tobias Arrskog + * topfs@tobias + * + * Copyright (C) 2007-2013 Team XBMC + * http://kodi.tv + * + * 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, 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 XBMC; see the file COPYING. If not, see + * <http://www.gnu.org/licenses/>. + * + */ + +// Compiles with g++ WiiRemote.cpp -lcwiid -o WiiRemote +// Preferably with libcwiid >= 6.0 + +#include "CWIID_WiiRemote.h" + +#include <unistd.h> + +bool g_AllowReconnect = true; +bool g_AllowMouse = true; +bool g_AllowNunchuck = true; + +CPacketHELO *g_Ping = NULL; + +#ifndef ICON_PATH +#define ICON_PATH "../../" +#endif +std::string g_BluetoothIconPath = std::string(ICON_PATH) + std::string("/bluetooth.png"); + +int32_t getTicks() +{ + int32_t ticks; + struct timeval now; + gettimeofday(&now, NULL); + ticks = now.tv_sec * 1000l; + ticks += now.tv_usec / 1000l; + return ticks; +} + +CWiiRemote g_WiiRemote; + +#ifdef CWIID_OLD +void CWiiRemote::MessageCallback(cwiid_wiimote_t *wiiremote, int mesg_count, union cwiid_mesg mesg[]) +{ + MessageCallback(wiiremote, mesg_count, mesg, NULL); +} +#endif + +/* The MessageCallback for the Wiiremote. + This callback is used for error reports, mainly to see if the connection has been broken + This callback is also used for getting the IR sources, if this is done in update as with + buttons we usually only get 1 IR source at a time which is much harder to calculate */ +void CWiiRemote::MessageCallback(cwiid_wiimote_t *wiiremote, int mesg_count, union cwiid_mesg mesg[], struct timespec *timestamp) +{ + for (int i=0; i < mesg_count; i++) + { + int valid_source; + switch (mesg[i].type) + { + case CWIID_MESG_IR: + valid_source = 0; + for (int j = 0; j < CWIID_IR_SRC_COUNT; j++) + { + if (mesg[i].ir_mesg.src[j].valid) + valid_source++; + } + if (valid_source == 2) + { + g_WiiRemote.CalculateMousePointer(mesg[i].ir_mesg.src[0].pos[CWIID_X], + mesg[i].ir_mesg.src[0].pos[CWIID_Y], + mesg[i].ir_mesg.src[1].pos[CWIID_X], + mesg[i].ir_mesg.src[1].pos[CWIID_Y]); + } + else if (valid_source > 2) + { //TODO Make this care with the strength of the sources + g_WiiRemote.CalculateMousePointer(mesg[i].ir_mesg.src[0].pos[CWIID_X], + mesg[i].ir_mesg.src[0].pos[CWIID_Y], + mesg[i].ir_mesg.src[1].pos[CWIID_X], + mesg[i].ir_mesg.src[1].pos[CWIID_Y]); + } + break; + case CWIID_MESG_ERROR: + g_WiiRemote.DisconnectNow(true); + break; + case CWIID_MESG_BTN: + g_WiiRemote.ProcessKey(mesg[i].btn_mesg.buttons); + break; + case CWIID_MESG_STATUS: + //Here we can figure out Extension types and such + break; + case CWIID_MESG_NUNCHUK: + g_WiiRemote.ProcessNunchuck(mesg[i].nunchuk_mesg); + break; + case CWIID_MESG_ACC: + case CWIID_MESG_BALANCE: + case CWIID_MESG_CLASSIC: + case CWIID_MESG_MOTIONPLUS: + //Not implemented + break; + case CWIID_MESG_UNKNOWN: + //... + break; + } + } +#ifdef CWIID_OLD + g_WiiRemote.CheckIn(); +#endif +} + +#ifndef _DEBUG +/* This takes the errors generated at pre-connect and silence them as they are mostly not needed */ +void CWiiRemote::ErrorCallback(struct wiimote *wiiremote, const char *str, va_list ap) +{ + //Error checking +} +#endif + +//Constructor +/*This constructor is never used but it shows how one would connect to just a specific Wiiremote by Mac-Address*/ +CWiiRemote::CWiiRemote(char *wii_btaddr) +{ + SetBluetoothAddress(wii_btaddr); + m_SamplesX = NULL; + m_SamplesY = NULL; + + m_JoyMap = NULL; +} + +//Destructor +CWiiRemote::~CWiiRemote() +{ + if (m_connected == true) + this->DisconnectNow(false); + + if (m_SamplesY != NULL) + free(m_SamplesY); + if (m_SamplesX != NULL) + free(m_SamplesX); + + if (m_JoyMap) + free(m_JoyMap); +} + +//---------------------Public------------------------------------------------------------------- +/* Basically this just sets up standard control bits */ +void CWiiRemote::SetBluetoothAddress(const char *btaddr) +{ + static const bdaddr_t b = {{0, 0, 0, 0, 0, 0}}; /* BDADDR_ANY */ + if (btaddr != NULL) + str2ba(btaddr, &m_btaddr); + else + bacpy(&m_btaddr, &b); +} + +void CWiiRemote::SetSensitivity(float DeadX, float DeadY, int NumSamples) +{ + m_NumSamples = NumSamples; + + m_MinX = MOUSE_MAX * DeadX; + m_MinY = MOUSE_MAX * DeadY; + + m_MaxX = MOUSE_MAX * (1.0f + DeadX + DeadX); + m_MaxY = MOUSE_MAX * (1.0f + DeadY + DeadY); + + if (m_SamplesY != NULL) + delete [] m_SamplesY; + if (m_SamplesX != NULL) + delete [] m_SamplesX; + + m_SamplesY = new int[m_NumSamples]; + m_SamplesX = new int[m_NumSamples]; +} + +void CWiiRemote::SetJoystickMap(const char *JoyMap) +{ + if (m_JoyMap) + free(m_JoyMap); + if (JoyMap != NULL) + { + m_JoyMap = (char*)malloc(strlen(JoyMap) + 5); + sprintf(m_JoyMap, "JS0:%s", JoyMap); + } + else + m_JoyMap = strdup("JS0:WiiRemote"); +} + +void CWiiRemote::Initialize(CAddress Addr, int Socket) +{ + m_connected = false; + m_lastKeyPressed = 0; + m_LastKey = 0; + m_buttonRepeat = false; + m_lastKeyPressedNunchuck = 0; + m_LastKeyNunchuck = 0; + m_buttonRepeatNunchuck = false; + m_useIRMouse = true; + m_rptMode = 0; + + m_Socket = Socket; + m_MyAddr = Addr; + + m_NumSamples = WIIREMOTE_SAMPLES; + + m_MaxX = WIIREMOTE_X_MAX; + m_MaxY = WIIREMOTE_Y_MAX; + m_MinX = WIIREMOTE_X_MIN; + m_MinY = WIIREMOTE_Y_MIN; +#ifdef CWIID_OLD + m_LastMsgTime = getTicks(); +#endif + + //All control bits are set to false when cwiid is started + //Report Button presses + ToggleBit(m_rptMode, CWIID_RPT_BTN); + if (g_AllowNunchuck) + ToggleBit(m_rptMode, CWIID_RPT_NUNCHUK); + + //If wiiremote is used as a mouse, then report the IR sources +#ifndef CWIID_OLD + if (m_useIRMouse) +#endif + ToggleBit(m_rptMode, CWIID_RPT_IR); + + //Have the first and fourth LED on the Wiiremote shine when connected + ToggleBit(m_ledState, CWIID_LED1_ON); + ToggleBit(m_ledState, CWIID_LED4_ON); +} + +/* Update is run regularly and we gather the state of the Wiiremote and see if the user have pressed on a button or moved the wiiremote + This could have been done with callbacks instead but it doesn't look nice in C++*/ +void CWiiRemote::Update() +{ + if (m_DisconnectWhenPossible) + {//If the user has chosen to disconnect or lost communication + DisconnectNow(true); + m_DisconnectWhenPossible = false; + } +#ifdef CWIID_OLD + if(m_connected) + {//Here we check if the connection is suddenly broken + if (!CheckConnection()) + { + DisconnectNow(true); + return; + } + } +#endif +} + +/* Enable mouse emulation */ +void CWiiRemote::EnableMouseEmulation() +{ + if (m_useIRMouse) + return; + + m_useIRMouse = true; + +#ifndef CWIID_OLD + //We toggle IR Reporting (Save resources?) + if (!(m_rptMode & CWIID_RPT_IR)) + ToggleBit(m_rptMode, CWIID_RPT_IR); + if (m_connected) + SetRptMode(); +#endif + + CPacketLOG log(LOGDEBUG, "Enabled WiiRemote mouse emulation"); + log.Send(m_Socket, m_MyAddr); +} +/* Disable mouse emulation */ +void CWiiRemote::DisableMouseEmulation() +{ + if (!m_useIRMouse) + return; + + m_useIRMouse = false; +#ifndef CWIID_OLD + //We toggle IR Reporting (Save resources?) + if (m_rptMode & CWIID_RPT_IR) + ToggleBit(m_rptMode, CWIID_RPT_IR); + if (m_connected) + SetRptMode(); +#endif + + CPacketLOG log(LOGDEBUG, "Disabled WiiRemote mouse emulation"); + log.Send(m_Socket, m_MyAddr); +} + +/* Is a wiiremote connected*/ +bool CWiiRemote::GetConnected() +{ + return m_connected; +} + +/* Disconnect ASAP*/ +void CWiiRemote::Disconnect() +{ //This is always called from a criticalsection + if (m_connected) + m_DisconnectWhenPossible = true; +} + +#ifdef CWIID_OLD +/* This function is mostly a hack as CWIID < 6.0 doesn't report on disconnects, this function is called everytime + a message is sent to the callback (Will be once every 10 ms or so) this is to see if the connection is interrupted. */ +void CWiiRemote::CheckIn() +{ //This is always called from a criticalsection + m_LastMsgTime = getTicks(); +} +#endif + +//---------------------Private------------------------------------------------------------------- +/* Connect is designed to be run in a different thread as it only + exits if wiiremote is either disabled or a connection is made*/ +bool CWiiRemote::Connect() +{ +#ifndef _DEBUG + cwiid_set_err(ErrorCallback); +#endif + while (!m_connected) + { + g_Ping->Send(m_Socket, m_MyAddr); + int flags = 0; + ToggleBit(flags, CWIID_FLAG_MESG_IFC); + ToggleBit(flags, CWIID_FLAG_REPEAT_BTN); + + m_wiiremoteHandle = cwiid_connect(&m_btaddr, flags); + if (m_wiiremoteHandle != NULL) + { + SetupWiiRemote(); + // get battery state etc. + cwiid_state wiiremote_state; + int err = cwiid_get_state(m_wiiremoteHandle, &wiiremote_state); + if (!err) + { + char Mesg[1024]; + sprintf(Mesg, "%i%% battery remaining", static_cast<int>(((float)(wiiremote_state.battery)/CWIID_BATTERY_MAX)*100.0)); + CPacketNOTIFICATION notification("Wii Remote connected", Mesg, ICON_PNG, g_BluetoothIconPath.c_str()); + notification.Send(m_Socket, m_MyAddr); + } + else + { + printf("Problem probing for status of WiiRemote; cwiid_get_state returned non-zero\n"); + CPacketLOG log( + LOGINFO, "Problem probing for status of WiiRemote; cwiid_get_state returned non-zero"); + log.Send(m_Socket, m_MyAddr); + CPacketNOTIFICATION notification("Wii Remote connected", "", ICON_PNG, g_BluetoothIconPath.c_str()); + notification.Send(m_Socket, m_MyAddr); + } +#ifdef CWIID_OLD + /* CheckIn to say that this is the last msg, If this isn't called it could give issues if we Connects -> Disconnect and then try to connect again + the CWIID_OLD hack would automatically disconnect the wiiremote as the lastmsg is too old. */ + CheckIn(); +#endif + m_connected = true; + + CPacketLOG log(LOGINFO, "Successfully connected a WiiRemote"); + log.Send(m_Socket, m_MyAddr); + return true; + } + //Here's a good place to have a quit flag check... + + } + return false; +} + +/* Disconnect */ +void CWiiRemote::DisconnectNow(bool startConnectThread) +{ + if (m_connected) //It shouldn't be enabled at the same time as it is connected + { + cwiid_disconnect(m_wiiremoteHandle); + + if (g_AllowReconnect) + { + CPacketNOTIFICATION notification("Wii Remote disconnected", "Press 1 and 2 to reconnect", ICON_PNG, g_BluetoothIconPath.c_str()); + notification.Send(m_Socket, m_MyAddr); + } + else + { + CPacketNOTIFICATION notification("Wii Remote disconnected", "", ICON_PNG, g_BluetoothIconPath.c_str()); + notification.Send(m_Socket, m_MyAddr); + } + + CPacketLOG log(LOGINFO, "Successfully disconnected a WiiRemote"); + log.Send(m_Socket, m_MyAddr); + } + m_connected = false; +} + +#ifdef CWIID_OLD +/* This is a harsh check if there really is a connection, It will mainly be used in CWIID < 6.0 + as it doesn't report connect error, which is needed to see if the Wiiremote suddenly disconnected. + This could possible be done with bluetooth specific queries but I cannot find how to do it. */ +bool CWiiRemote::CheckConnection() +{ + if ((getTicks() - m_LastMsgTime) > 1000) + { + CPacketLOG log(LOGINFO, "Lost connection to the WiiRemote"); + log.Send(m_Socket, m_MyAddr); + return false; + } + else + return true; +} +#endif + +/* Sets rpt mode when a new wiiremote is connected */ +void CWiiRemote::SetupWiiRemote() +{ //Lights up the appropriate led and setups the rapport mode, so buttons and IR work + SetRptMode(); + SetLedState(); + + for (int i = 0; i < WIIREMOTE_SAMPLES; i++) + { + m_SamplesX[i] = 0; + m_SamplesY[i] = 0; + } + + if (cwiid_set_mesg_callback(m_wiiremoteHandle, MessageCallback)) + { + CPacketLOG log(LOGERROR, "Unable to set message callback to the WiiRemote"); + log.Send(m_Socket, m_MyAddr); + } +} + +void CWiiRemote::ProcessKey(int Key) +{ + if (Key != m_LastKey) + { + m_LastKey = Key; + m_lastKeyPressed = getTicks(); + m_buttonRepeat = false; + } + else + { + if (m_buttonRepeat) + { + if (getTicks() - m_lastKeyPressed > WIIREMOTE_BUTTON_REPEAT_TIME) + m_lastKeyPressed = getTicks(); + else + return; + } + else + { + if (getTicks() - m_lastKeyPressed > WIIREMOTE_BUTTON_DELAY_TIME) + { + m_buttonRepeat = true; + m_lastKeyPressed = getTicks(); + } + else + return; + } + } + + int RtnKey = -1; + + if (Key == CWIID_BTN_UP) + RtnKey = 1; + else if (Key == CWIID_BTN_RIGHT) + RtnKey = 4; + else if (Key == CWIID_BTN_LEFT) + RtnKey = 3; + else if (Key == CWIID_BTN_DOWN) + RtnKey = 2; + + else if (Key == CWIID_BTN_A) + RtnKey = 5; + else if (Key == CWIID_BTN_B) + RtnKey = 6; + + else if (Key == CWIID_BTN_MINUS) + RtnKey = 7; + else if (Key == CWIID_BTN_PLUS) + RtnKey = 9; + + else if (Key == CWIID_BTN_HOME) + RtnKey = 8; + + else if (Key == CWIID_BTN_1) + RtnKey = 10; + else if (Key == CWIID_BTN_2) + RtnKey = 11; + + if (RtnKey != -1) + { + CPacketBUTTON btn(RtnKey, m_JoyMap, BTN_QUEUE | BTN_NO_REPEAT); + btn.Send(m_Socket, m_MyAddr); + } +} + +void CWiiRemote::ProcessNunchuck(struct cwiid_nunchuk_mesg &Nunchuck) +{ + if (Nunchuck.stick[0] > 135) + { //R + int x = (int)((((float)Nunchuck.stick[0] - 135.0f) / 95.0f) * 65535.0f); + printf("Right: %i\n", x); + CPacketBUTTON btn(24, m_JoyMap, (BTN_QUEUE | BTN_DOWN), x); + btn.Send(m_Socket, m_MyAddr); + } + else if (Nunchuck.stick[0] < 125) + { //L + int x = (int)((((float)Nunchuck.stick[0] - 125.0f) / 90.0f) * -65535.0f); + printf("Left: %i\n", x); + CPacketBUTTON btn(23, m_JoyMap, (BTN_QUEUE | BTN_DOWN), x); + btn.Send(m_Socket, m_MyAddr); + } + + if (Nunchuck.stick[1] > 130) + { //U + int x = (int)((((float)Nunchuck.stick[1] - 130.0f) / 92.0f) * 65535.0f); + printf("Up: %i\n", x); + CPacketBUTTON btn(21, m_JoyMap, (BTN_QUEUE | BTN_DOWN), x); + btn.Send(m_Socket, m_MyAddr); + } + else if (Nunchuck.stick[1] < 120) + { //D + int x = (int)((((float)Nunchuck.stick[1] - 120.0f) / 90.0f) * -65535.0f); + printf("Down: %i\n", x); + CPacketBUTTON btn(22, m_JoyMap, (BTN_QUEUE | BTN_DOWN), x); + btn.Send(m_Socket, m_MyAddr); + } + + if (Nunchuck.buttons != m_LastKeyNunchuck) + { + m_LastKeyNunchuck = Nunchuck.buttons; + m_lastKeyPressedNunchuck = getTicks(); + m_buttonRepeatNunchuck = false; + } + else + { + if (m_buttonRepeatNunchuck) + { + if (getTicks() - m_lastKeyPressedNunchuck > WIIREMOTE_BUTTON_REPEAT_TIME) + m_lastKeyPressedNunchuck = getTicks(); + else + return; + } + else + { + if (getTicks() - m_lastKeyPressedNunchuck > WIIREMOTE_BUTTON_DELAY_TIME) + { + m_buttonRepeatNunchuck = true; + m_lastKeyPressedNunchuck = getTicks(); + } + else + return; + } + } + + int RtnKey = -1; + + if (Nunchuck.buttons == CWIID_NUNCHUK_BTN_C) + RtnKey = 25; + else if (Nunchuck.buttons == CWIID_NUNCHUK_BTN_Z) + RtnKey = 26; + + if (RtnKey != -1) + { + CPacketBUTTON btn(RtnKey, m_JoyMap, BTN_QUEUE | BTN_NO_REPEAT); + btn.Send(m_Socket, m_MyAddr); + } +} + +/* Tell cwiid which data will be reported */ +void CWiiRemote::SetRptMode() +{ //Sets our wiiremote to report something, for example IR, Buttons +#ifdef CWIID_OLD + if (cwiid_command(m_wiiremoteHandle, CWIID_CMD_RPT_MODE, m_rptMode)) +#else + if (cwiid_set_rpt_mode(m_wiiremoteHandle, m_rptMode)) +#endif + { + CPacketLOG log(LOGERROR, "Error setting WiiRemote report mode"); + log.Send(m_Socket, m_MyAddr); + } +} +/* Tell cwiid the LED states */ +void CWiiRemote::SetLedState() +{ //Sets our leds on the wiiremote +#ifdef CWIID_OLD + if (cwiid_command(m_wiiremoteHandle, CWIID_CMD_LED, m_ledState)) +#else + if (cwiid_set_led(m_wiiremoteHandle, m_ledState)) +#endif + { + CPacketLOG log(LOGERROR, "Error setting WiiRemote LED state"); + log.Send(m_Socket, m_MyAddr); + } +} + +/* Calculate the mousepointer from 2 IR sources (Default) */ +void CWiiRemote::CalculateMousePointer(int x1, int y1, int x2, int y2) +{ + int x3, y3; + + x3 = ( (x1 + x2) / 2 ); + y3 = ( (y1 + y2) / 2 ); + + x3 = (int)( ((float)x3 / (float)CWIID_IR_X_MAX) * m_MaxX); + y3 = (int)( ((float)y3 / (float)CWIID_IR_Y_MAX) * m_MaxY); + + x3 = (int)(x3 - m_MinX); + y3 = (int)(y3 - m_MinY); + + if (x3 < MOUSE_MIN) x3 = MOUSE_MIN; + else if (x3 > MOUSE_MAX) x3 = MOUSE_MAX; + + if (y3 < MOUSE_MIN) y3 = MOUSE_MIN; + else if (y3 > MOUSE_MAX) y3 = MOUSE_MAX; + + x3 = MOUSE_MAX - x3; + + if (m_NumSamples == 1) + { + CPacketMOUSE mouse(x3, y3); + mouse.Send(m_Socket, m_MyAddr); + return; + } + else + { + for (int i = m_NumSamples; i > 0; i--) + { + m_SamplesX[i] = m_SamplesX[i-1]; + m_SamplesY[i] = m_SamplesY[i-1]; + } + + m_SamplesX[0] = x3; + m_SamplesY[0] = y3; + + long x4 = 0, y4 = 0; + + for (int i = 0; i < m_NumSamples; i++) + { + x4 += m_SamplesX[i]; + y4 += m_SamplesY[i]; + } + CPacketMOUSE mouse((x4 / m_NumSamples), (y4 / m_NumSamples)); + mouse.Send(m_Socket, m_MyAddr); + } +} + + + + + + + + + + + + + + + + +void PrintHelp(const char *Prog) +{ + printf("Commands:\n"); + printf("\t--disable-mouseemulation\n\t--disable-reconnect\n\t--disable-nunchuck\n"); + printf("\t--address ADDRESS\n\t--port PORT\n"); + printf("\t--btaddr MACADDRESS\n"); + printf("\t--deadzone-x DEADX | Number between 0 - 100 (Default: %i)\n", (int)(DEADZONE_X * 100)); + printf("\t--deadzone-y DEADY | Number between 0 - 100 (Default: %i)\n", (int)(DEADZONE_Y * 100)); + printf("\t--deadzone DEAD | Sets both X and Y too the number\n"); + printf("\t--smoothing-samples SAMPLE | Number 1 counts as Off (Default: %i)\n", WIIREMOTE_SAMPLES); + printf("\t--joystick-map JOYMAP | The string ID for the joymap (Default: WiiRemote)\n"); +} + +int main(int argc, char **argv) +{ + char *Address = NULL; + char *btaddr = NULL; + int Port = 9777; + + int NumSamples = WIIREMOTE_SAMPLES; + float DeadX = DEADZONE_X; + float DeadY = DEADZONE_Y; + + char *JoyMap = NULL; + + for (int i = 0; i < argc; i++) + { + if (strcmp(argv[i], "--help") == 0) + { + PrintHelp(argv[0]); + return 0; + } + else if (strcmp(argv[i], "--disable-mouseemulation") == 0) + g_AllowMouse = false; + else if (strcmp(argv[i], "--disable-reconnect") == 0) + g_AllowReconnect = false; + else if (strcmp(argv[i], "--disable-nunchuck") == 0) + g_AllowNunchuck = false; + else if (strcmp(argv[i], "--address") == 0 && ((i + 1) <= argc)) + Address = argv[i + 1]; + else if (strcmp(argv[i], "--port") == 0 && ((i + 1) <= argc)) + Port = atoi(argv[i + 1]); + else if (strcmp(argv[i], "--btaddr") == 0 && ((i + 1) <= argc)) + btaddr = argv[i + 1]; + else if (strcmp(argv[i], "--deadzone-x") == 0 && ((i + 1) <= argc)) + DeadX = ((float)atoi(argv[i + 1]) / 100.0f); + else if (strcmp(argv[i], "--deadzone-y") == 0 && ((i + 1) <= argc)) + DeadY = ((float)atoi(argv[i + 1]) / 100.0f); + else if (strcmp(argv[i], "--deadzone") == 0 && ((i + 1) <= argc)) + DeadX = DeadY = ((float)atoi(argv[i + 1]) / 100.0f); + else if (strcmp(argv[i], "--smoothing-samples") == 0 && ((i + 1) <= argc)) + NumSamples = atoi(argv[i + 1]); + else if (strcmp(argv[i], "--joystick-map") == 0 && ((i + 1) <= argc)) + JoyMap = argv[i + 1]; + } + + if (NumSamples < 1 || DeadX < 0 || DeadY < 0 || DeadX > 1 || DeadY > 1) + { + PrintHelp(argv[0]); + return -1; + } + + CAddress my_addr(Address, Port); // Address => localhost on 9777 + int sockfd = socket(AF_INET, SOCK_DGRAM, 0); + if (sockfd < 0) + { + printf("Error creating socket\n"); + return -1; + } + + if (hci_get_route(NULL) < 0) + { + CPacketLOG log(LOGERROR, "Error No bluetooth device"); + log.Send(sockfd, my_addr); + return -1; + } + g_Ping = new CPacketHELO("WiiRemote", ICON_PNG, g_BluetoothIconPath.c_str()); + g_WiiRemote.Initialize(my_addr, sockfd); + g_WiiRemote.SetBluetoothAddress(btaddr); + g_WiiRemote.SetSensitivity(DeadX, DeadY, NumSamples); + g_WiiRemote.SetSensitivity(DeadX, DeadY, NumSamples); + g_WiiRemote.SetJoystickMap(JoyMap); + if (g_AllowMouse) + g_WiiRemote.EnableMouseEmulation(); + else + g_WiiRemote.DisableMouseEmulation(); + + g_Ping->Send(sockfd, my_addr); + bool HaveConnected = false; + while (true) + { + bool Connected = g_WiiRemote.GetConnected(); + + while (!Connected) + { + if (HaveConnected && !g_AllowReconnect) + exit(0); + + Connected = g_WiiRemote.Connect(); + HaveConnected = true; + } +#ifdef CWIID_OLD +// Update the state of the WiiRemote more often when we have the old lib due too it not telling when disconnected.. + sleep (5); +#else + sleep (15); +#endif + g_Ping->Send(sockfd, my_addr); + g_WiiRemote.Update(); + } +} diff --git a/tools/EventClients/Clients/WiiRemote/CWIID_WiiRemote.h b/tools/EventClients/Clients/WiiRemote/CWIID_WiiRemote.h new file mode 100644 index 0000000..58d051e --- /dev/null +++ b/tools/EventClients/Clients/WiiRemote/CWIID_WiiRemote.h @@ -0,0 +1,171 @@ +/* + * Copyright (C) 2007 by Tobias Arrskog + * topfs@tobias + * + * Copyright (C) 2007-2013 Team XBMC + * http://kodi.tv + * + * 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, 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 XBMC; see the file COPYING. If not, see + * <http://www.gnu.org/licenses/>. + * + */ + +#pragma once + +/* Toggle one bit */ +#define ToggleBit(bf,b) (bf) = ((bf) & b) ? ((bf) & ~(b)) : ((bf) | (b)) + +//Settings +#define WIIREMOTE_SAMPLES 16 + +#define DEADZONE_Y 0.3f +#define DEADZONE_X 0.5f + +#define MOUSE_MAX 65535 +#define MOUSE_MIN 0 + +//The work area is from 0 - MAX but the one sent to XBMC is MIN - (MIN + MOUSE_MAX) +#define WIIREMOTE_X_MIN MOUSE_MAX * DEADZONE_X +#define WIIREMOTE_Y_MIN MOUSE_MAX * DEADZONE_Y + +#define WIIREMOTE_X_MAX MOUSE_MAX * (1.0f + DEADZONE_X + DEADZONE_X) +#define WIIREMOTE_Y_MAX MOUSE_MAX * (1.0f + DEADZONE_Y + DEADZONE_Y) + +#define WIIREMOTE_BUTTON_REPEAT_TIME 30 // How long between buttonpresses in repeat mode +#define WIIREMOTE_BUTTON_DELAY_TIME 500 +//#define CWIID_OLD // Uncomment if the system is running cwiid that is older than 6.0 (The one from ubuntu gutsy repository is < 6.0) + +//CWIID +#include <cwiid.h> +//Bluetooth specific +#include <sys/socket.h> +#include <bluetooth/bluetooth.h> +#include <bluetooth/hci.h> +#include <bluetooth/hci_lib.h> +// UDP Client +#ifdef DEB_PACK +#include <xbmc/xbmcclient.h> +#else +#include "../../lib/c++/xbmcclient.h" +#endif +/*#include <stdio.h>*/ +#include <stdlib.h> +#include <time.h> +#include <sys/time.h> +#include <string> + +class CWiiRemote +{ +public: + CWiiRemote(char *btaddr = NULL); + ~CWiiRemote(); + + void Initialize(CAddress Addr, int Socket); + void Disconnect(); + bool GetConnected(); + + bool EnableWiiRemote(); + bool DisableWiiRemote(); + + void Update(); + + // Mouse functions + bool HaveIRSources(); + bool isActive(); + void EnableMouseEmulation(); + void DisableMouseEmulation(); + + bool Connect(); + + void SetBluetoothAddress(const char * btaddr); + void SetSensitivity(float DeadX, float DeadY, int Samples); + void SetJoystickMap(const char *JoyMap); +private: + int m_NumSamples; + int *m_SamplesX; + int *m_SamplesY; + + float m_MaxX; + float m_MaxY; + float m_MinX; + float m_MinY; +#ifdef CWIID_OLD + bool CheckConnection(); + int m_LastMsgTime; +#endif + char *m_JoyMap; + int m_lastKeyPressed; + int m_LastKey; + bool m_buttonRepeat; + + int m_lastKeyPressedNunchuck; + int m_LastKeyNunchuck; + bool m_buttonRepeatNunchuck; + + void SetRptMode(); + void SetLedState(); + + void SetupWiiRemote(); + + bool m_connected; + + bool m_DisconnectWhenPossible; + bool m_connectThreadRunning; + + //CWIID Specific + cwiid_wiimote_t *m_wiiremoteHandle; + unsigned char m_ledState; + unsigned char m_rptMode; + bdaddr_t m_btaddr; + + static void MessageCallback(cwiid_wiimote_t *wiiremote, int mesgCount, union cwiid_mesg mesg[], struct timespec *timestamp); +#ifdef CWIID_OLD + static void MessageCallback(cwiid_wiimote_t *wiiremote, int mesgCount, union cwiid_mesg mesg[]); +#endif + +#ifndef _DEBUG +/* This takes the errors generated at pre-connect and silence them as they are mostly not needed */ + static void ErrorCallback(struct wiimote *wiiremote, const char *str, va_list ap); +#endif + + int m_Socket; + CAddress m_MyAddr; + + // Mouse + bool m_haveIRSources; + bool m_isActive; + bool m_useIRMouse; + int m_lastActiveTime; + +/* The protected functions is for the static callbacks */ + protected: + //Connection + void DisconnectNow(bool startConnectThread); + + //Mouse + void CalculateMousePointer(int x1, int y1, int x2, int y2); +// void SetIR(bool set); + + //Button + void ProcessKey(int Key); + + //Nunchuck + void ProcessNunchuck(struct cwiid_nunchuk_mesg &Nunchuck); +#ifdef CWIID_OLD + //Disconnect check + void CheckIn(); +#endif +}; + +extern CWiiRemote g_WiiRemote; diff --git a/tools/EventClients/Clients/WiiRemote/Makefile b/tools/EventClients/Clients/WiiRemote/Makefile new file mode 100644 index 0000000..eba0f1e --- /dev/null +++ b/tools/EventClients/Clients/WiiRemote/Makefile @@ -0,0 +1,14 @@ +CXX ?= g++ +CFLAGS = -Wall -pipe -fPIC -funroll-loops +OBJ_DIR = release-$(shell $(CC) -v 2>&1|grep ^Target:|cut -d' ' -f2) +OBJS = wiiuse_v0.12/src/$(OBJ_DIR)/libwiiuse.so +BIN = WiiUse_WiiRemote +VERSION = v0.12 + +all: + @$(MAKE) -C wiiuse_$(VERSION)/src $@ + $(CXX) $(CFLAGS) -I./wiiuse_$(VERSION)/src WiiUse_WiiRemote.cpp $(OBJS) -o $(BIN) +wiiuse: + @$(MAKE) -C wiiuse_$(VERSION)/src +clean: + rm $(OBJS) $(BIN) diff --git a/tools/EventClients/Clients/WiiRemote/WiiUse_README b/tools/EventClients/Clients/WiiRemote/WiiUse_README new file mode 100644 index 0000000..5749697 --- /dev/null +++ b/tools/EventClients/Clients/WiiRemote/WiiUse_README @@ -0,0 +1,18 @@ +To compile the WiiRemote event client: + +$ sudo apt-get install libbluetooth-dev +$ make + +NOTE: if you get a permission denied error when make'ing the event client, you may need to use root, +e.g. $ sudo make + +make will create an executable called WiiUse_WiiRemote that contains the event client. + +WiiUse_WiiRemote must be run from this directory as it uses relative linking to the built wiiuse_v0.12 library. + +WiiUse_WiiRemote.h contains the button number mappings for the WiiRemote (prefixed with KEYCODE). + +TODO: +Add IR pointer support + +TheUni + dteirney
\ No newline at end of file diff --git a/tools/EventClients/Clients/WiiRemote/WiiUse_WiiRemote.cpp b/tools/EventClients/Clients/WiiRemote/WiiUse_WiiRemote.cpp new file mode 100644 index 0000000..48f5a1a --- /dev/null +++ b/tools/EventClients/Clients/WiiRemote/WiiUse_WiiRemote.cpp @@ -0,0 +1,265 @@ + /* Copyright (C) 2009 by Cory Fields + * 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 3 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, see <http://www.gnu.org/licenses/>. + * + * + */ + +#include "WiiUse_WiiRemote.h" + +void CWiiController::get_keys(wiimote* wm) +{ + m_buttonHeld = 0; + m_buttonPressed = 0; + m_buttonReleased = 0; + + m_repeatableHeld = (wm->btns & (m_repeatFlags)); + m_holdableHeld = (wm->btns & (m_holdFlags)); + m_repeatableReleased = (wm->btns_released & (m_repeatFlags)); + m_holdableReleased = (wm->btns_released & (m_holdFlags)); + + for (int i = 1;i <= WIIMOTE_NUM_BUTTONS; i++) + { + if (IS_PRESSED(wm,convert_code(i))) + m_buttonPressed = i; + if (IS_RELEASED(wm,convert_code(i))) + m_buttonReleased = i; + if (IS_HELD(wm,convert_code(i))) + m_buttonHeld = i; + } +} + +void CWiiController::handleKeyPress() +{ + if ((m_holdableReleased && m_buttonDownTime < g_hold_button_timeout)) + EventClient.SendButton(m_buttonReleased, m_joyString, BTN_QUEUE | BTN_NO_REPEAT); + if (m_buttonPressed && !m_holdableHeld && !m_buttonHeld) + EventClient.SendButton(m_buttonPressed, m_joyString, BTN_QUEUE | BTN_NO_REPEAT); +} + +void CWiiController::handleRepeat() +{ + if (m_repeatableHeld) + EventClient.SendButton(m_buttonPressed, m_joyString, BTN_QUEUE | BTN_NO_REPEAT, 5); +} + +void CWiiController::handleACC(float currentRoll, float currentPitch) +{ + int rollWeight = 0; + int tiltWeight = 0; + + if (m_start_roll == 0) + m_start_roll = currentRoll; + m_abs_roll = smoothDeg(m_abs_roll, currentRoll); + m_rel_roll = m_abs_roll - m_start_roll; + rollWeight = int((m_rel_roll*m_rel_roll)); + if (rollWeight > 65000) + rollWeight = 65000; + + if (m_start_pitch == 0) + m_start_pitch = currentPitch; + m_abs_pitch = smoothDeg(m_abs_pitch, currentPitch); + m_rel_pitch = m_start_pitch - m_abs_pitch; + tiltWeight = int((m_rel_pitch*m_rel_pitch*16)); + if (tiltWeight > 65000) + tiltWeight = 65000; + + if (m_currentAction == ACTION_NONE) + { + if ((g_deadzone - (abs((int)m_rel_roll)) < 5) && (abs((int)m_abs_pitch) < (g_deadzone / 1.5))) + // crossed the roll deadzone threshold while inside the pitch deadzone + { + m_currentAction = ACTION_ROLL; + } + else if ((g_deadzone - (abs((int)m_rel_pitch)) < 5) && (abs((int)m_abs_roll) < (g_deadzone / 1.5))) + // crossed the pitch deadzone threshold while inside the roll deadzone + { + m_currentAction = ACTION_PITCH; + } + } + + if (m_currentAction == ACTION_ROLL) + { + if (m_rel_roll < -g_deadzone) + EventClient.SendButton(KEYCODE_ROLL_NEG, m_joyString, BTN_QUEUE | BTN_NO_REPEAT, rollWeight); + if (m_rel_roll > g_deadzone) + EventClient.SendButton(KEYCODE_ROLL_POS, m_joyString, BTN_QUEUE | BTN_NO_REPEAT, rollWeight); +// printf("Roll: %f\n",m_rel_roll); + } + + if (m_currentAction == ACTION_PITCH) + { + if (m_rel_pitch > g_deadzone) + EventClient.SendButton(KEYCODE_PITCH_POS, m_joyString, BTN_QUEUE | BTN_NO_REPEAT,tiltWeight); + if (m_rel_pitch < -g_deadzone) + EventClient.SendButton(KEYCODE_PITCH_NEG, m_joyString, BTN_QUEUE | BTN_NO_REPEAT,tiltWeight); +// printf("Pitch: %f\n",m_rel_pitch); + } +} + +void CWiiController::handleIR() +{ +//TODO +} + +int connectWiimote(wiimote** wiimotes) +{ + int found = 0; + int connected = 0; + wiimote* wm; + while(!found) + { + //Look for Wiimotes. Keep searching until one is found. Wiiuse provides no way to search forever, so search for 5 secs and repeat. + found = wiiuse_find(wiimotes, MAX_WIIMOTES, 5); + } + connected = wiiuse_connect(wiimotes, MAX_WIIMOTES); + wm = wiimotes[0]; + if (connected) + { + EventClient.SendHELO("Wii Remote", ICON_PNG, NULL); + wiiuse_set_leds(wm, WIIMOTE_LED_1); + wiiuse_rumble(wm, 1); + wiiuse_set_orient_threshold(wm,1); + DisableMotionSensing(wm); + #ifndef WIN32 + usleep(200000); + #else + Sleep(200); + #endif + wiiuse_rumble(wm, 0); + + return 1; + } + return 0; +} + +int handle_disconnect(wiimote* wm) +{ + EventClient.SendNOTIFICATION("Wii Remote disconnected", "", ICON_PNG, NULL); + return 0; +} + +unsigned short convert_code(unsigned short client_code) +{ +//WIIMOTE variables are from wiiuse. We need them to be 1-11 for the eventclient. +//For that we use this ugly conversion. + + switch (client_code) + { + case KEYCODE_BUTTON_UP: return WIIMOTE_BUTTON_UP; + case KEYCODE_BUTTON_DOWN: return WIIMOTE_BUTTON_DOWN; + case KEYCODE_BUTTON_LEFT: return WIIMOTE_BUTTON_LEFT; + case KEYCODE_BUTTON_RIGHT: return WIIMOTE_BUTTON_RIGHT; + case KEYCODE_BUTTON_A: return WIIMOTE_BUTTON_A; + case KEYCODE_BUTTON_B: return WIIMOTE_BUTTON_B; + case KEYCODE_BUTTON_MINUS: return WIIMOTE_BUTTON_MINUS; + case KEYCODE_BUTTON_HOME: return WIIMOTE_BUTTON_HOME; + case KEYCODE_BUTTON_PLUS: return WIIMOTE_BUTTON_PLUS; + case KEYCODE_BUTTON_ONE: return WIIMOTE_BUTTON_ONE; + case KEYCODE_BUTTON_TWO: return WIIMOTE_BUTTON_TWO; + default : break; + } +return 0; +} + +float smoothDeg(float oldVal, float newVal) +{ +//If values go over 180 or under -180, weird things happen. This transforms the values to -360 to 360 instead. + + if (newVal - oldVal > 300) + return (newVal - 360); + if (oldVal - newVal > 300) + return(newVal + 360); + return(newVal); +} + +int32_t getTicks(void) +{ + int32_t ticks; + struct timeval now; + gettimeofday(&now, NULL); + ticks = now.tv_sec * 1000l; + ticks += now.tv_usec / 1000l; + return ticks; +} + +int main(int argc, char** argv) +{ + int32_t timeout = 0; + bool connected = 0; + wiimote** wiimotes; + wiimotes = wiiuse_init(MAX_WIIMOTES); + CWiiController controller; + wiimote* wm; + { + //Main Loop + while (1) + { + if (!connected) connected = (connectWiimote(wiimotes)); + wm = wiimotes[0]; // Only worry about 1 controller. No need for more? + controller.m_buttonDownTime = getTicks() - timeout; + +//Handle ACC, Repeat, and IR outside of the Event loop so that buttons can be continuously sent + if (timeout) + { + if ((controller.m_buttonDownTime > g_hold_button_timeout) && controller.m_holdableHeld) + controller.handleACC(wm->orient.roll, wm->orient.pitch); + if ((controller.m_buttonDownTime > g_repeat_rate) && controller.m_repeatableHeld) + controller.handleRepeat(); + } + if (wiiuse_poll(wiimotes, MAX_WIIMOTES)) + { + for (int i = 0; i < MAX_WIIMOTES; ++i) + //MAX_WIIMOTES hardcoded at 1. + { + DisableMotionSensing(wm); + switch (wiimotes[i]->event) + { + case WIIUSE_EVENT: + + controller.get_keys(wm); //Load up the CWiiController + controller.handleKeyPress(); + if (!controller.m_buttonHeld && (controller.m_holdableHeld || controller.m_repeatableHeld)) + { + //Prepare to repeat or hold. Do this only once. + timeout = getTicks(); + controller.m_abs_roll = 0; + controller.m_abs_pitch = 0; + controller.m_start_roll = 0; + controller.m_start_pitch = 0; + } + if (controller.m_buttonReleased) + { + DisableMotionSensing(wm); + controller.m_currentAction = ACTION_NONE; + } + break; + case WIIUSE_STATUS: + break; + case WIIUSE_DISCONNECT: + case WIIUSE_UNEXPECTED_DISCONNECT: + handle_disconnect(wm); + connected = 0; + break; + case WIIUSE_READ_DATA: + break; + default: + break; + } + } + } + } + } + wiiuse_cleanup(wiimotes, MAX_WIIMOTES); + return 0; +} diff --git a/tools/EventClients/Clients/WiiRemote/WiiUse_WiiRemote.h b/tools/EventClients/Clients/WiiRemote/WiiUse_WiiRemote.h new file mode 100644 index 0000000..7226137 --- /dev/null +++ b/tools/EventClients/Clients/WiiRemote/WiiUse_WiiRemote.h @@ -0,0 +1,127 @@ + /* Copyright (C) 2009 by Cory Fields + * 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 3 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, see <http://www.gnu.org/licenses/>. + * + * + */ + +#pragma once + +#include <stdio.h> +#include <stdlib.h> +#include <sys/socket.h> +#include <sys/time.h> +//#include <math.h> +#include <unistd.h> +#ifdef DEB_PACK +#include <xbmc/xbmcclient.h> +#else +#include "../../lib/c++/xbmcclient.h" +#endif +//#ifndef WIN32 +// #include <unistd.h> +//#endif +#include "wiiuse.h" +//#define ICON_PATH "../../" +#define PORT 9777 +#define MAX_WIIMOTES 1 +#define OVER_180_DEG 1 +#define UNDER_NEG_180_DEG 2 +#define WIIMOTE_BUTTON_TWO 0x0001 +#define WIIMOTE_BUTTON_ONE 0x0002 +#define WIIMOTE_BUTTON_B 0x0004 +#define WIIMOTE_BUTTON_A 0x0008 +#define WIIMOTE_BUTTON_MINUS 0x0010 +#define WIIMOTE_BUTTON_HOME 0x0080 +#define WIIMOTE_BUTTON_LEFT 0x0100 +#define WIIMOTE_BUTTON_RIGHT 0x0200 +#define WIIMOTE_BUTTON_DOWN 0x0400 +#define WIIMOTE_BUTTON_UP 0x0800 +#define WIIMOTE_BUTTON_PLUS 0x1000 + +#define WIIMOTE_NUM_BUTTONS 11 +#define KEYCODE_BUTTON_UP 1 +#define KEYCODE_BUTTON_DOWN 2 +#define KEYCODE_BUTTON_LEFT 3 +#define KEYCODE_BUTTON_RIGHT 4 +#define KEYCODE_BUTTON_A 5 +#define KEYCODE_BUTTON_B 6 +#define KEYCODE_BUTTON_MINUS 7 +#define KEYCODE_BUTTON_HOME 8 +#define KEYCODE_BUTTON_PLUS 9 +#define KEYCODE_BUTTON_ONE 10 +#define KEYCODE_BUTTON_TWO 11 +#define KEYCODE_ROLL_NEG 33 +#define KEYCODE_ROLL_POS 34 +#define KEYCODE_PITCH_NEG 35 +#define KEYCODE_PITCH_POS 36 + + +#define ACTION_NONE 0 +#define ACTION_ROLL 1 +#define ACTION_PITCH 2 + +class CWiiController{ + public: + + bool m_holdableHeld; + bool m_holdableReleased; + bool m_repeatableHeld; + bool m_repeatableReleased; + + unsigned short m_buttonPressed; + unsigned short m_buttonReleased; + unsigned short m_buttonHeld; + unsigned short m_repeatFlags; + unsigned short m_holdFlags; + unsigned short m_currentAction; + + int32_t m_buttonDownTime; + + float m_abs_roll; + float m_abs_pitch; + float m_rel_roll; + float m_rel_pitch; + float m_start_roll; + float m_start_pitch; + char* m_joyString; + + + void get_keys(wiimote* wm); + void handleKeyPress(); + void handleRepeat(); + void handleACC(float, float); + void handleIR(); + + CWiiController() + { + m_joyString = "JS0:WiiRemote"; + m_repeatFlags = WIIMOTE_BUTTON_UP | WIIMOTE_BUTTON_DOWN | WIIMOTE_BUTTON_LEFT | WIIMOTE_BUTTON_RIGHT; + m_holdFlags = WIIMOTE_BUTTON_B; + } +}; + +unsigned short g_deadzone = 30; +unsigned short g_hold_button_timeout = 200; +unsigned short g_repeat_rate = 400; + +int handle_disconnect(wiimote* ); +int connectWiimote(wiimote** ); +int32_t getTicks(void); +void EnableMotionSensing(wiimote* wm) {if (!WIIUSE_USING_ACC(wm)) wiiuse_motion_sensing(wm, 1);} +void DisableMotionSensing(wiimote* wm) {if (WIIUSE_USING_ACC(wm)) wiiuse_motion_sensing(wm, 0);} +unsigned short convert_code(unsigned short); +float smoothDeg(float, float); + +CXBMCClient EventClient; + diff --git a/tools/EventClients/Clients/WiiRemote/wiiuse_v0.12/CHANGELOG b/tools/EventClients/Clients/WiiRemote/wiiuse_v0.12/CHANGELOG new file mode 100644 index 0000000..8ca3439 --- /dev/null +++ b/tools/EventClients/Clients/WiiRemote/wiiuse_v0.12/CHANGELOG @@ -0,0 +1,208 @@ +--------------------------- +- +- CHANGE LOG - Wiiuse +- +--------------------------- + +http://wiiuse.net/ +http://wiiuse.sourceforge.net/ +http://sourceforge.net/projects/wiiuse/ + +--------------------------- +v0.12 -- 2 Apr 2008 +--------------------------- + + Added: + - API function wiiuse_set_ir_sensitivity() + - Macro WIIUSE_GET_IR_SENSITIVITY() + - Event type WIIUSE_READ_DATA + - Event type WIIUSE_UNEXPECTED_DISCONNECT + + Fixed: + - [Linux] Ability to try to select() nothing + - [Linux] Changed Makefile to include debug output when compiling in debug mode + + Changed: + - wiiuse_set_nunchuk_orient_threshold() now takes a wiimote_t pointer + - wiiuse_set_nunchuk_accel_threshold() now takes a wiimote_t pointer + - wiiuse_read_data() generates an event WIIUSE_READ_DATA rather than executing a callback + +--------------------------- +v0.11 -- 25 Feb 2008 +--------------------------- + + Added: + - API function wiiuse_set_nunchuk_orient_threshold() + - API function wiiuse_set_nunchuk_accel_threshold() + - Event type WIIUSE_NUNCHUK_INSERTED + - Event type WIIUSE_NUNCHUK_REMOVED + - Event type WIIUSE_CLASSIC_CTRL_INSERTED + - Event type WIIUSE_CLASSIC_CTRL_REMOVED + - Event type WIIUSE_GUITAR_HERO_3_CTRL_INSERTED + - Event type WIIUSE_GUITAR_HERO_3_CTRL_REMOVED + + Fixed: + - Added some missing function prototypes to wiiuse.h + - [Linux] Fixed Makefile to link libmath and libbluetooth + - Status event is set when a status report comes in + - Orientation threshold not being saved in lstate + +--------------------------- +v0.10 -- 11 Feb 2008 +--------------------------- + + Added: + - Real dynamic linking (by noisehole) + - Changed from callback to SDL style + - Guitar Hero 3 controller support + - API function wiiuse_set_accel_threshold() + - API function wiiuse_version() + - Macro WIIUSE_USING_SPEAKER() + - Macro WIIUSE_IS_LED_SET(wm, num) + - wiiuse_init() now autogenerates unids + - orient_t::a_roll/a_pitch + - wiiuse_resync() + - wiiuse_cleanup() + - wiiuse_set_timeout() + + Fixed: + - [Windows] Fixed bug where it did not detect expansions on startup + - Renamed INFO/WARNING/DEBUG macros to WIIUSE_* (by noisehole) + - Updated Makefiles (by noisehole) + - Fixed incorrect roll/pitch when smoothing was enabled + - Fixed nunchuk and classic controller flooding events when significant changes occurred + - Fixed bug where IR was not correct on roll if IR was enabled before handshake + + Removed: + - wiiuse_startup(), no longer needed + +--------------------------- +v0.9 -- 3 Nov 2007 +--------------------------- + + Fixed: + - Can now use include/wiiuse.h in C++ projects. + - HOME button works again. + - IR now functions after expansion is connected or removed. + +--------------------------- +v0.8 -- 27 Oct 2007 +--------------------------- + + - Bumped API version to 8 + - Exported all API functions for usage with non-C/C++ languages. + - Changed event callback to only trigger if a significant state change occurs. + + Added: + - wiimote_t::lstate structure + + Fixed: + - Bug 1820140 - Buffer overflow in io_nix.c. Thanks proppy. + +--------------------------- +v0.7 -- 19 Oct 2007 +--------------------------- + + - Bumped API version to 7 + - Renamed Linux build from wii.so to wiiuse.so + - Changed version representation from float to const char*. + + Added: + - [Windows] BlueSoleil support. + - [Windows] Bluetooth stack auto-detection (WinXP SP2, Bluesoleil, Widdcomm tested). + - [Windows] API function wiiuse_set_bluetooth_stack(). + - Calculates yaw if IR tracking is enabled. + + Fixed: + - [Windows] Problem where a connection is made to a wiimote that does not exist. + - [Windows] Issue that occurred while using multiple wiimotes. + +--------------------------- +v0.6 -- 16 Oct 2007 +--------------------------- + + - Bumped API version to 0.6. + - Ported to Microsoft Windows. + - Improved IR tracking. + - Default IR virtual screen resolutions changed depending on 16:9 or 4:3. + + Added: + - src/msvc/ and api/msvc/ - Microsoft Visual C++ 6.0 project files. + +--------------------------- +v0.5 -- 13 Oct 2007 +--------------------------- + + - Bumped API version to 0.5. + - Greatly improved IR tracking. + - Renamed function wiiuse_set_ir_correction() to wiiuse_set_ir_position(). + + Added: + - API function wiiuse_set_aspect_ratio() + + Fixed: + - When rolling around 180 degree rotation smoothing would not be seemless. + +--------------------------- +v0.4 -- 08 Oct 2007 +--------------------------- + + - Bumped API version to 0.4. + - Greatly improved classic controller joystick functionality. + - Changed all functions named wiimote_*() to wiiuse_*() + - Renamed many macros from WIIMOTE_* to WIIUSE_* + + Added: + - IR support + - New WIIMOTE_CONTINUOUS flag to set continuous reporting + - Macro IS_JUST_PRESSED() + - Macro WIIUSE_USING_ACC() + - Macro WIIUSE_USING_EXP() + - Macro WIIUSE_USING_IR() + - API function wiiuse_set_ir() + - API function wiiuse_set_ir_vres() + - API function wiiuse_set_ir_correction() + + - gfx/ - A small OpenGL example that renders IR data + + Fixed: + - Sometimes classic controller would only report infinite angle and magnitude for joysticks. + +--------------------------- +v0.3 -- 10 Sept 2007 +--------------------------- + + - Moved license to GPLv3. + - Bumped API version to 0.3. + + Added: + - Support for Classic Controller + - Smoothing for roll and pitch values of the wiimote and nunchuk. + + - API: wiimote_set_flags() to set or disable wiimote options. + - API: wiimote_set_smooth_alpha() to set smoothing alpha value. + + Fixed: + - When the wiimote accelerates the roll or pitch is unreliable and was set to 0. + It now remains at previous tilt value. + - If no event callback was specified then no events would be processed internally. + +--------------------------- +v0.2 -- 25 Aug 2007 +--------------------------- + + - Bumped API version to 0.2. + + Added: + - Nunchuk support. + - Ability to write to flash memory. + + Fixed: + - Roll and pitch rotation now ranges from -180 to 180 degrees (previously -90 to 90). + - Bug when reading data from flash memory would read wrong address. + +--------------------------- +v0.1 -- 23 Feb 2007 +--------------------------- + + - Initial release diff --git a/tools/EventClients/Clients/WiiRemote/wiiuse_v0.12/LICENSE b/tools/EventClients/Clients/WiiRemote/wiiuse_v0.12/LICENSE new file mode 100644 index 0000000..85b8e59 --- /dev/null +++ b/tools/EventClients/Clients/WiiRemote/wiiuse_v0.12/LICENSE @@ -0,0 +1,620 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/> + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. 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 +them 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 prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. 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. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey 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; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If 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 convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU 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 that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + 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. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +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. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + diff --git a/tools/EventClients/Clients/WiiRemote/wiiuse_v0.12/LICENSE_noncommercial b/tools/EventClients/Clients/WiiRemote/wiiuse_v0.12/LICENSE_noncommercial new file mode 100644 index 0000000..ea8fae6 --- /dev/null +++ b/tools/EventClients/Clients/WiiRemote/wiiuse_v0.12/LICENSE_noncommercial @@ -0,0 +1,170 @@ +This license can be used for any works that this license defines +as "derived" or "combined" works that are strictly NON-COMMERCIAL. +This license prohibits the use of any source or object code +in works that are PROPRIETARY. + + GNU LESSER GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/> + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + + This version of the GNU Lesser General Public License incorporates +the terms and conditions of version 3 of the GNU General Public +License, supplemented by the additional permissions listed below. + + 0. Additional Definitions. + + As used herein, "this License" refers to version 3 of the GNU Lesser +General Public License, and the "GNU GPL" refers to version 3 of the GNU +General Public License. + + "The Library" refers to a covered work governed by this License, +other than an Application or a Combined Work as defined below. + + An "Application" is any work that makes use of an interface provided +by the Library, but which is not otherwise based on the Library. +Defining a subclass of a class defined by the Library is deemed a mode +of using an interface provided by the Library. + + A "Combined Work" is a work produced by combining or linking an +Application with the Library. The particular version of the Library +with which the Combined Work was made is also called the "Linked +Version". + + The "Minimal Corresponding Source" for a Combined Work means the +Corresponding Source for the Combined Work, excluding any source code +for portions of the Combined Work that, considered in isolation, are +based on the Application, and not on the Linked Version. + + The "Corresponding Application Code" for a Combined Work means the +object code and/or source code for the Application, including any data +and utility programs needed for reproducing the Combined Work from the +Application, but excluding the System Libraries of the Combined Work. + + 1. Exception to Section 3 of the GNU GPL. + + You may convey a covered work under sections 3 and 4 of this License +without being bound by section 3 of the GNU GPL. + + 2. Conveying Modified Versions. + + If you modify a copy of the Library, and, in your modifications, a +facility refers to a function or data to be supplied by an Application +that uses the facility (other than as an argument passed when the +facility is invoked), then you may convey a copy of the modified +version: + + a) under this License, provided that you make a good faith effort to + ensure that, in the event an Application does not supply the + function or data, the facility still operates, and performs + whatever part of its purpose remains meaningful, or + + b) under the GNU GPL, with none of the additional permissions of + this License applicable to that copy. + + 3. Object Code Incorporating Material from Library Header Files. + + The object code form of an Application may incorporate material from +a header file that is part of the Library. You may convey such object +code under terms of your choice, provided that, if the incorporated +material is not limited to numerical parameters, data structure +layouts and accessors, or small macros, inline functions and templates +(ten or fewer lines in length), you do both of the following: + + a) Give prominent notice with each copy of the object code that the + Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the object code with a copy of the GNU GPL and this license + document. + + 4. Combined Works. + + You may convey a Combined Work under terms of your choice that, +taken together, effectively do not restrict modification of the +portions of the Library contained in the Combined Work and reverse +engineering for debugging such modifications, if you also do each of +the following: + + a) Give prominent notice with each copy of the Combined Work that + the Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the Combined Work with a copy of the GNU GPL and this license + document. + + c) For a Combined Work that displays copyright notices during + execution, include the copyright notice for the Library among + these notices, as well as a reference directing the user to the + copies of the GNU GPL and this license document. + + d) Do one of the following: + + 0) Convey the Minimal Corresponding Source under the terms of this + License, and the Corresponding Application Code in a form + suitable for, and under terms that permit, the user to + recombine or relink the Application with a modified version of + the Linked Version to produce a modified Combined Work, in the + manner specified by section 6 of the GNU GPL for conveying + Corresponding Source. + + 1) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (a) uses at run time + a copy of the Library already present on the user's computer + system, and (b) will operate properly with a modified version + of the Library that is interface-compatible with the Linked + Version. + + e) Provide Installation Information, but only if you would otherwise + be required to provide such information under section 6 of the + GNU GPL, and only to the extent that such information is + necessary to install and execute a modified version of the + Combined Work produced by recombining or relinking the + Application with a modified version of the Linked Version. (If + you use option 4d0, the Installation Information must accompany + the Minimal Corresponding Source and Corresponding Application + Code. If you use option 4d1, you must provide the Installation + Information in the manner specified by section 6 of the GNU GPL + for conveying Corresponding Source.) + + 5. Combined Libraries. + + You may place library facilities that are a work based on the +Library side by side in a single library together with other library +facilities that are not Applications and are not covered by this +License, and convey such a combined library under terms of your +choice, if you do both of the following: + + a) Accompany the combined library with a copy of the same work based + on the Library, uncombined with any other library facilities, + conveyed under the terms of this License. + + b) Give prominent notice with the combined library that part of it + is a work based on the Library, and explaining where to find the + accompanying uncombined form of the same work. + + 6. Revised Versions of the GNU Lesser General Public License. + + The Free Software Foundation may publish revised and/or new versions +of the GNU Lesser 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 +Library as you received it specifies that a certain numbered version +of the GNU Lesser General Public License "or any later version" +applies to it, you have the option of following the terms and +conditions either of that published version or of any later version +published by the Free Software Foundation. If the Library as you +received it does not specify a version number of the GNU Lesser +General Public License, you may choose any version of the GNU Lesser +General Public License ever published by the Free Software Foundation. + + If the Library as you received it specifies that a proxy can decide +whether future versions of the GNU Lesser General Public License shall +apply, that proxy's public statement of acceptance of any version is +permanent authorization for you to choose that version for the +Library. diff --git a/tools/EventClients/Clients/WiiRemote/wiiuse_v0.12/Makefile b/tools/EventClients/Clients/WiiRemote/wiiuse_v0.12/Makefile new file mode 100644 index 0000000..f63da69 --- /dev/null +++ b/tools/EventClients/Clients/WiiRemote/wiiuse_v0.12/Makefile @@ -0,0 +1,23 @@ +# +# wiiuse Makefile +# + +all clean install: + @$(MAKE) -C src $@ + @$(MAKE) -C example $@ + @$(MAKE) -C example-sdl $@ + +wiiuse: + @$(MAKE) -C src + +ex: + @$(MAKE) -C example + +sdl-ex: + @$(MAKE) -C example-sdl + +distclean: + @$(MAKE) -C src $@ + @$(MAKE) -C example $@ + @$(MAKE) -C example-sdl $@ + @find . -type f \( -name "*.save" -or -name "*~" -or -name gmon.out \) -delete &> /dev/null diff --git a/tools/EventClients/Clients/WiiRemote/wiiuse_v0.12/README b/tools/EventClients/Clients/WiiRemote/wiiuse_v0.12/README new file mode 100644 index 0000000..b06bb96 --- /dev/null +++ b/tools/EventClients/Clients/WiiRemote/wiiuse_v0.12/README @@ -0,0 +1,155 @@ +--------------------------- +- +- README - Wiiuse +- +--------------------------- + +http://wiiuse.net/ +http://wiiuse.sourceforge.net/ +http://sourceforge.net/projects/wiiuse/ + +--------------------------- + +ABOUT + + Wiiuse is a library written in C that connects with several Nintendo Wii remotes. + Supports motion sensing, IR tracking, nunchuk, classic controller, and the Guitar Hero 3 controller. + Single threaded and nonblocking makes a light weight and clean API. + + Distributed under the GPL and LGPL. + + +AUTHORS + + Michael Laforest < para > + Email: < thepara (--AT--) g m a i l [--DOT--] com > + + The following people have contributed patches to wiiuse: + - dhewg + + +LICENSE + + There are two licenses for wiiuse. Please read them carefully before choosing which one + you use. You may of course at any time switch the license you are currently using to + the other. + + Briefly, the license options are: + + a) GNU LGPL (modified for non-commercial usage only) + b) GNU GPL + + PLEASE READ THE LICENSES! + + +ACKNOWLEDGEMENTS + + http://wiibrew.org/ + This site and their users have contributed an immense amount of information + about the wiimote and its technical details. I could not have written this program + without the vast amounts of reverse engineered information that was researched by them. + + Nintendo + Of course Nintendo for designing and manufacturing the Wii and Wii remote. + + BlueZ + Easy and intuitive bluetooth stack for Linux. + + Thanks to Brent for letting me borrow his Guitar Hero 3 controller. + + +DISCLAIMER AND WARNINGS + + I am in no way responsible for any damages or effects, intended or not, caused by this program. + + *** WARNING *** WARNING *** WARNING *** + + Be aware that writing to memory may damage or destroy your wiimote or expansions. + + *** WARNING *** WARNING *** WARNING *** + + This program was written using reverse engineered specifications available from wiibrew.org. + Therefore the operation of this program may not be entirely correct. + Results obtained by using this program may vary. + + +AUDIENCE + + This project is intended for developers who wish to include support for the Nintendo Wii remote + with their third party application. Please be aware that by using this software you are bound + to the terms of the GNU GPL. + + +PLATFORMS AND DEPENDENCIES + + Wiiuse currently operates on both Linux and Windows. + You will need: + + For Linux: + - The kernel must support bluetooth + - The BlueZ bluetooth drivers must be installed + + For Windows: + - Bluetooth driver (tested with Microsoft's stack with Windows XP SP2) + - If compiling, Microsoft Windows Driver Development Kit (DDK) + + +COMPILING + + Linux: + You need SDL and OpenGL installed to compile the SDL example. + + # make [target] + + If 'target' is omitted then everything is compiled. + + Where 'target' can be any of the following: + + - wiiuse + Compiles libwiiuse.so + + - ex + Compiles wiiuse-example + + - sdl-ex + Compiles wiiuse-sdl + + Become root. + + # make install + + The above command will only install the binaries that you + selected to compile. + + wiiuse.so is installed to /usr/lib + wiiuse-example and wiiuse-sdl are installed to /usr/bin + + Windows: + A Microsoft Visual C++ 6.0 project file has been included. + + You need the install the Windows DDK (driver development kit) + to compile wiiuse. Make sure you include the inc/ and lib/ + directories from the DDK in your IDE include and library paths. + You can download this from here: + http://www.microsoft.com/whdc/devtools/ddk/default.mspx + + You need to link the following libraries (already set in the + included project file): + - Ws2_32.lib + - hid.lib + - setupapi.lib + + +USING THE LIBRARY IN A THIRD PARTY APPLICATION + + To use the library in your own program you must first compile wiiuse as a module. + Include include/wiiuse.h in any file that uses wiiuse. + + For Linux you must link wiiuse.so ( -lwiiuse ). + For Windows you must link wiiuse.lib. When your program runs it will need wiiuse.dll. + + +BUGS + + On Windows using more than one wiimote (usually more than two wiimotes) may cause + significant latency. diff --git a/tools/EventClients/Clients/WiiRemote/wiiuse_v0.12/example-sdl/Makefile b/tools/EventClients/Clients/WiiRemote/wiiuse_v0.12/example-sdl/Makefile new file mode 100644 index 0000000..3420d7b --- /dev/null +++ b/tools/EventClients/Clients/WiiRemote/wiiuse_v0.12/example-sdl/Makefile @@ -0,0 +1,83 @@ +# +# wiiuse Makefile +# + +# +# Change this to your GCC version. +# +CC ?= gcc + +#################################################### +# +# You should not need to edit below this line. +# +#################################################### + +# +# Universal cflags +# +CFLAGS = -Wall -pipe -fPIC -funroll-loops + +ifeq ($(debug),1) + OBJ_PREFIX = debug + CFLAGS += -g -pg -DWITH_WIIUSE_DEBUG +else + OBJ_PREFIX = release + CFLAGS += -O2 +endif + +OBJ_DIR = $(OBJ_PREFIX)-$(shell $(CC) -v 2>&1|grep ^Target:|cut -d' ' -f2) + +# +# Linking flags +# +LDFLAGS = -L../src/$(OBJ_DIR) -lm -lGL -lGLU -lglut -lSDL -lbluetooth -lwiiuse + +# +# Target binaries (always created as BIN) +# +BIN = ./$(OBJ_DIR)/wiiuse-sdl + +# +# Inclusion paths. +# +INCLUDES = -I../src/ -I/usr/include/SDL + +# +# Generate a list of object files +# +OBJS = $(OBJ_DIR)/sdl.o + +############################### +# +# Build targets. +# +############################### + +all: $(BIN) + +clean: + @-rm $(OBJS) 2> /dev/null + +distclean: clean + @-rm -r debug-* release-* 2> /dev/null + +install: + @if [ -e $(BIN) ]; then \ + cp -v $(BIN) /usr/bin ;\ + fi + +$(BIN): mkdir $(OBJS) + $(CC) $(CFLAGS) $(LDFLAGS) $(OBJS) -o $(BIN) + +$(OBJ_DIR)/%.o: %.c + $(CC) $(CFLAGS) $(INCLUDES) -c $< -o $@ + +mkdir: + @if [ ! -d $(OBJ_DIR) ]; then \ + mkdir $(OBJ_DIR); \ + fi + +run: all + LD_LIBRARY_PATH=`pwd`/../src/$(OBJ_DIR):$(LD_LIBRARY_PATH) $(BIN) + diff --git a/tools/EventClients/Clients/WiiRemote/wiiuse_v0.12/example-sdl/msvc/wiiusesdl.dsp b/tools/EventClients/Clients/WiiRemote/wiiuse_v0.12/example-sdl/msvc/wiiusesdl.dsp new file mode 100644 index 0000000..007d676 --- /dev/null +++ b/tools/EventClients/Clients/WiiRemote/wiiuse_v0.12/example-sdl/msvc/wiiusesdl.dsp @@ -0,0 +1,111 @@ +# Microsoft Developer Studio Project File - Name="wiiusesdl" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Application" 0x0101 + +CFG=wiiusesdl - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "wiiusesdl.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "wiiusesdl.mak" CFG="wiiusesdl - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "wiiusesdl - Win32 Release" (based on "Win32 (x86) Application") +!MESSAGE "wiiusesdl - Win32 Debug" (based on "Win32 (x86) Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +MTL=midl.exe +RSC=rc.exe + +!IF "$(CFG)" == "wiiusesdl - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /W3 /GX /O2 /I "..\..\src" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /c +# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /machine:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib sdl.lib opengl32.lib glu32.lib wiiuse.lib /nologo /subsystem:windows /machine:I386 + +!ELSEIF "$(CFG)" == "wiiusesdl - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /GZ /c +# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /I "..\..\src" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /GZ /c +# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /debug /machine:I386 /pdbtype:sept +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib sdl.lib opengl32.lib glu32.lib wiiuse.lib /nologo /subsystem:windows /debug /machine:I386 /pdbtype:sept + +!ENDIF + +# Begin Target + +# Name "wiiusesdl - Win32 Release" +# Name "wiiusesdl - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=..\sdl.c +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=..\..\src\wiiuse.h +# End Source File +# End Group +# Begin Group "Resource Files" + +# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" +# End Group +# End Target +# End Project diff --git a/tools/EventClients/Clients/WiiRemote/wiiuse_v0.12/example-sdl/msvc/wiiusesdl.dsw b/tools/EventClients/Clients/WiiRemote/wiiuse_v0.12/example-sdl/msvc/wiiusesdl.dsw new file mode 100644 index 0000000..ee501ff --- /dev/null +++ b/tools/EventClients/Clients/WiiRemote/wiiuse_v0.12/example-sdl/msvc/wiiusesdl.dsw @@ -0,0 +1,29 @@ +Microsoft Developer Studio Workspace File, Format Version 6.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "wiiusesdl"=".\wiiusesdl.dsp" - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + diff --git a/tools/EventClients/Clients/WiiRemote/wiiuse_v0.12/example-sdl/msvc/wiiusesdl.opt b/tools/EventClients/Clients/WiiRemote/wiiuse_v0.12/example-sdl/msvc/wiiusesdl.opt Binary files differnew file mode 100644 index 0000000..fa46687 --- /dev/null +++ b/tools/EventClients/Clients/WiiRemote/wiiuse_v0.12/example-sdl/msvc/wiiusesdl.opt diff --git a/tools/EventClients/Clients/WiiRemote/wiiuse_v0.12/example-sdl/sdl.c b/tools/EventClients/Clients/WiiRemote/wiiuse_v0.12/example-sdl/sdl.c new file mode 100644 index 0000000..c469968 --- /dev/null +++ b/tools/EventClients/Clients/WiiRemote/wiiuse_v0.12/example-sdl/sdl.c @@ -0,0 +1,439 @@ +/* + * Written By: + * Michael Laforest < para > + * Email: < thepara (--AT--) g m a i l [--DOT--] com > + * + * Copyright 2006-2007 + * + * 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 3 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, see <http://www.gnu.org/licenses/>. + * + * $Header$ + */ + +#include <stdlib.h> +#include <math.h> + +#ifndef WIN32 + #include <unistd.h> + #include <sys/time.h> + #include <time.h> +#else + #include <windows.h> +#endif + +#include <GL/gl.h> +#include <GL/glu.h> +#include <GL/glut.h> +#include <SDL.h> + +#include <wiiuse.h> + +#define PI 3.14159265358979323846 +#define PI_DIV_180 0.017453292519943296 +#define deg PI_DIV_180 + +#define MAX_WIIMOTES 2 + +GLint width = 1024, height = 768; +GLfloat backColor[4] = {1.0,1.0,1.0,1.0}; + +wiimote** wiimotes = NULL; + +int last_dots[4][2] = {{0}}; +int xcoord = 0; +int ycoord = 0; + +#ifdef WIN32 + DWORD last_render; +#else + struct timeval last_render; + int last_sec = 0; + int fps = 0; +#endif + +enum render_mode_t { + IR = 1, + TEAPOT +}; +enum render_mode_t render_mode = IR; + +/* light information */ +struct light_t { + GLfloat position[4]; + GLfloat spotDirection[3]; + GLfloat ambient[4]; + GLfloat diffuse[4]; + GLfloat specular[4]; + GLfloat spotCutoff; + GLfloat spotExponent; + GLfloat spotAttenuation[3]; /* [0] = constant, [1] = linear, [2] = quadratic */ +}; +struct light_t light = { + { 1.0, 1.0, -2.0, 1.0 }, + { -1.0, -1.0, 2.0 }, + { 0.0, 0.0, 0.0, 1.0 }, + { 1.0, 1.0, 1.0, 1.0 }, + { 1.0, 1.0, 1.0, 1.0 }, + 180.0, 0.0, + { 1.0, 0.0, 0.0 } +}; + +/* material information */ +struct material_t { + GLfloat ambient[4]; + GLfloat diffuse[4]; + GLfloat specular[4]; + GLfloat emission[4]; + GLfloat shininess; +}; +struct material_t red_plastic = { + { 0.3, 0.0, 0.0, 1.0 }, + { 0.3, 0.0, 0.0, 1.0 }, + { 0.8, 0.6, 0.6, 1.0 }, + { 0.0, 0.0, 0.0, 1.0 }, + 32.0 +}; + + +void handle_event(struct wiimote_t* wm); +void display(); +void update_light(GLenum l, struct light_t* lptr); +void set_material(struct material_t* mptr); +void resize_window(GLint new_width, GLint new_height); + +void handle_event(struct wiimote_t* wm) { + if (IS_JUST_PRESSED(wm, WIIMOTE_BUTTON_PLUS)) + wiiuse_motion_sensing(wm, 1); + if (IS_JUST_PRESSED(wm, WIIMOTE_BUTTON_MINUS)) + wiiuse_motion_sensing(wm, 0); + + if (IS_JUST_PRESSED(wm, WIIMOTE_BUTTON_UP)) + wiiuse_set_ir(wm, 1); + if (IS_JUST_PRESSED(wm, WIIMOTE_BUTTON_DOWN)) + wiiuse_set_ir(wm, 0); + + if (IS_JUST_PRESSED(wm, WIIMOTE_BUTTON_B)) + wiiuse_toggle_rumble(wm); + + if (IS_JUST_PRESSED(wm, WIIMOTE_BUTTON_ONE)) { + int level; + WIIUSE_GET_IR_SENSITIVITY(wm, &level); + wiiuse_set_ir_sensitivity(wm, level+1); + } + if (IS_JUST_PRESSED(wm, WIIMOTE_BUTTON_TWO)) { + int level; + WIIUSE_GET_IR_SENSITIVITY(wm, &level); + wiiuse_set_ir_sensitivity(wm, level-1); + } + + #if 0 + if (IS_JUST_PRESSED(wm, WIIMOTE_BUTTON_A)) { + if (render_mode == IR) + render_mode = TEAPOT; + else + render_mode = IR; + resize_window(width, height); + } + #endif +} + +#define DRAW_TRIANGLE(x, y, z, s) do { \ + glVertex3f(x, y-s, z); \ + glVertex3f(x+s, y+s, z); \ + glVertex3f(x-s, y+s, z); \ + } while (0) + +int can_render() { + /* quick fps limit to ~60fps -- not too fancy, could be better */ + #ifdef WIN32 + if (GetTickCount() < (last_render + 16)) + return 0; + last_render = GetTickCount(); + return 1; + #else + struct timeval now; + long elapsed_usec = 0; + + gettimeofday(&now, NULL); + + if (now.tv_usec > 1000000) { + now.tv_usec -= 1000000; + ++now.tv_sec; + } + + if (now.tv_sec > last_render.tv_sec) + elapsed_usec = ((now.tv_sec - last_render.tv_sec) * 1000000); + + if (now.tv_usec > last_render.tv_usec) + elapsed_usec += now.tv_usec - last_render.tv_usec; + else + elapsed_usec += last_render.tv_usec - now.tv_usec; + + if (time(NULL) > last_sec) { + printf("fps: %i\n", fps); + fps = 0; + last_sec = time(NULL); + } + + if (elapsed_usec < 16000) + return 0; + + last_render = now; + ++fps; + + return 1; + #endif +} + +void display() { + int i, wm; + float size = 5; + + if (!can_render()) + return; + + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + + if (render_mode == IR) { + /* draw the IR stuff */ + + glDisable(GL_LIGHTING); + + glBegin(GL_TRIANGLES); + /* green center */ + glColor3f(0.0, 1.0, 0.0); + DRAW_TRIANGLE(width/2, height/2, 0, size); + glEnd(); + + for (wm = 0; wm < MAX_WIIMOTES; ++wm) { + glBegin(GL_TRIANGLES); + /* red ir */ + glColor3f(1.0, 0.0, 0.0); + for (i = 0; i < 4; ++i) { + if (wiimotes[wm]->ir.dot[i].visible) + DRAW_TRIANGLE(wiimotes[wm]->ir.dot[i].rx, wiimotes[wm]->ir.dot[i].ry, 0, size); + } + + /* yellow corrected ir */ + glColor3f(1.0, 1.0, 0.0); + for (i = 0; i < 4; ++i) { + if (wiimotes[wm]->ir.dot[i].visible) + DRAW_TRIANGLE(wiimotes[wm]->ir.dot[i].x, wiimotes[wm]->ir.dot[i].y, 0, size); + } + + /* blue cursor */ + glColor3f(0.0, 0.0, 1.0); + DRAW_TRIANGLE(wiimotes[wm]->ir.x, wiimotes[wm]->ir.y-size, 0, size); + glEnd(); + } + } else { + /* draw the teapot */ + gluLookAt(0.0, 0.0, -5.0, + 0.0, 0.0, 0.0, + 0.0, 1.0, 0.0); + + glEnable(GL_LIGHTING); + glEnable(GL_LIGHT0); + update_light(GL_LIGHT0, &light); + set_material(&red_plastic); + + glRotatef(wiimotes[0]->orient.roll, 0.0f, 0.0f, 1.0f); + glRotatef(wiimotes[0]->orient.pitch, 1.0f, 0.0f, 0.0f); + + + glutSolidTeapot(1); + } + + SDL_GL_SwapBuffers(); +} + + +void update_light(GLenum l, struct light_t* lptr) { + glLightfv(l, GL_POSITION, lptr->position); + glLightfv(l, GL_DIFFUSE, lptr->diffuse); + glLightfv(l, GL_SPECULAR, lptr->specular); + glLightfv(l, GL_AMBIENT, lptr->ambient); + glLightfv(l, GL_SPOT_DIRECTION, lptr->spotDirection); + glLightf(l, GL_SPOT_CUTOFF, lptr->spotCutoff); + glLightf(l, GL_SPOT_EXPONENT, lptr->spotExponent); + glLightf(l, GL_CONSTANT_ATTENUATION, lptr->spotAttenuation[0]); + glLightf(l, GL_LINEAR_ATTENUATION, lptr->spotAttenuation[1]); + glLightf(l, GL_QUADRATIC_ATTENUATION, lptr->spotAttenuation[2]); +} + + +void set_material(struct material_t* mptr) { + glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, mptr->ambient); + glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, mptr->diffuse); + glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, mptr->specular); + glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, mptr->shininess); + glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, mptr->emission); +} + + +void resize_window(GLint new_width, GLint new_height) { + int wm; + + width = new_width; + height = new_height; + + if (new_height == 0) + new_height = 1; + + SDL_SetVideoMode(width, height, 16, SDL_RESIZABLE | SDL_OPENGL); + + glViewport(0, 0, new_width, new_height); + + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + + if (render_mode == IR) + gluOrtho2D(0, width, height, 0); + else + gluPerspective(60.0f, (float)new_width/(float)new_height, 0.1f, 100.0f); + + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + + width = new_width; + height = new_height; + + for (wm = 0; wm < MAX_WIIMOTES; ++wm) + wiiuse_set_ir_vres(wiimotes[wm], width, height); +} + +#ifndef WIN32 +int main(int argc, char** argv) { +#else +int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { +#endif + int found, connected; + int wm; + + //printf("wiiuse version = %s\n", wiiuse_version()); + + wiimotes = wiiuse_init(MAX_WIIMOTES); + found = wiiuse_find(wiimotes, MAX_WIIMOTES, 5); + if (!found) + return 0; + connected = wiiuse_connect(wiimotes, MAX_WIIMOTES); + if (connected) + printf("Connected to %i wiimotes (of %i found).\n", connected, found); + else { + printf("Failed to connect to any wiimote.\n"); + return 0; + } + wiiuse_set_leds(wiimotes[0], WIIMOTE_LED_1 | WIIMOTE_LED_4); + wiiuse_set_leds(wiimotes[1], WIIMOTE_LED_2 | WIIMOTE_LED_4); + wiiuse_rumble(wiimotes[0], 1); + + #ifndef WIN32 + usleep(200000); + #else + Sleep(200); + #endif + + wiiuse_rumble(wiimotes[0], 0); + + /* enable IR and motion sensing for all wiimotes */ + for (wm = 0; wm < MAX_WIIMOTES; ++wm) { + wiiuse_motion_sensing(wiimotes[wm], 1); + wiiuse_set_ir(wiimotes[wm], 1); + } + + if (SDL_Init(SDL_INIT_VIDEO) < 0) { + printf("Failed to initialize SDL: %s\n", SDL_GetError()); + return 0; + } + + SDL_WM_SetCaption("wiiuse SDL IR Example", "wiiuse SDL IR Example"); + + SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); + SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 16); + + /* set window size */ + width = wiimotes[0]->ir.vres[0]; + height = wiimotes[0]->ir.vres[1]; + SDL_SetVideoMode(width, height, 16, SDL_RESIZABLE | SDL_OPENGL); + + for (wm = 0; wm < MAX_WIIMOTES; ++wm) + wiiuse_set_ir_vres(wiimotes[wm], width, height); + + /* set OpenGL stuff */ + glEnable(GL_DEPTH_TEST); + glEnable(GL_LIGHTING); + glEnable(GL_NORMALIZE); + glEnable(GL_BLEND); + + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glDepthFunc(GL_LEQUAL); + glClearColor(0, 0, 0, 0); + + /* set the size of the window */ + resize_window(width, height); + + display(); + + #ifdef WIN32 + last_render = GetTickCount(); + #endif + + while (1) { + SDL_Event event; + + if (SDL_PollEvent(&event)) { + switch (event.type) { + case SDL_VIDEORESIZE: + { + /* resize the window */ + resize_window(event.resize.w, event.resize.h); + break; + } + case SDL_QUIT: + { + /* shutdown */ + SDL_Quit(); + wiiuse_cleanup(wiimotes, MAX_WIIMOTES); + return 0; + } + default: + { + } + } + } + + if (wiiuse_poll(wiimotes, MAX_WIIMOTES)) { + /* + * This happens if something happened on any wiimote. + * So go through each one and check if anything happened. + */ + int i = 0; + for (; i < MAX_WIIMOTES; ++i) { + switch (wiimotes[i]->event) { + case WIIUSE_EVENT: + /* a generic event occurred */ + handle_event(wiimotes[i]); + break; + + default: + break; + } + } + } + + display(); + } +} diff --git a/tools/EventClients/Clients/WiiRemote/wiiuse_v0.12/example/Makefile b/tools/EventClients/Clients/WiiRemote/wiiuse_v0.12/example/Makefile new file mode 100644 index 0000000..e3e907c --- /dev/null +++ b/tools/EventClients/Clients/WiiRemote/wiiuse_v0.12/example/Makefile @@ -0,0 +1,84 @@ +# +# wiiuse Makefile +# + +# +# Change this to your GCC version. +# +CC ?= gcc + +#################################################### +# +# You should not need to edit below this line. +# +#################################################### + +# +# Universal cflags +# +CFLAGS = -Wall -pipe -fPIC -funroll-loops + +ifeq ($(debug),1) + OBJ_PREFIX = debug + CFLAGS += -g -pg -DWITH_WIIUSE_DEBUG +else + OBJ_PREFIX = release + CFLAGS += -O2 +endif + +OBJ_DIR = $(OBJ_PREFIX)-$(shell $(CC) -v 2>&1|grep ^Target:|cut -d' ' -f2) + +# +# Linking flags +# +LDFLAGS = -L../src/$(OBJ_DIR) -lm -lwiiuse + +# +# Target binaries (always created as BIN) +# +BIN = ./$(OBJ_DIR)/wiiuse-example + +# +# Inclusion paths. +# +INCLUDES = -I../src/ + +# +# Generate a list of object files +# +OBJS = $(OBJ_DIR)/example.o + +############################### +# +# Build targets. +# +############################### + +all: $(BIN) + +clean: + @-rm $(OBJS) 2> /dev/null + +distclean: + @-rm -r debug-* release-* 2> /dev/null + +install: + @if [ -e $(BIN) ]; then \ + cp -v $(BIN) /usr/bin ; \ + fi + + +$(BIN): mkdir $(OBJS) + $(CC) $(CFLAGS) $(LDFLAGS) $(OBJS) -o $(BIN) + +$(OBJ_DIR)/%.o: %.c + $(CC) $(CFLAGS) $(INCLUDES) -c $< -o $@ + +mkdir: + @if [ ! -d $(OBJ_DIR) ]; then \ + mkdir $(OBJ_DIR); \ + fi + +run: all + LD_LIBRARY_PATH=`pwd`/../src/$(OBJ_DIR):$(LD_LIBRARY_PATH) $(BIN) + diff --git a/tools/EventClients/Clients/WiiRemote/wiiuse_v0.12/example/example.c b/tools/EventClients/Clients/WiiRemote/wiiuse_v0.12/example/example.c new file mode 100644 index 0000000..d401d80 --- /dev/null +++ b/tools/EventClients/Clients/WiiRemote/wiiuse_v0.12/example/example.c @@ -0,0 +1,437 @@ +/* + * wiiuse + * + * Written By: + * Michael Laforest < para > + * Email: < thepara (--AT--) g m a i l [--DOT--] com > + * + * Copyright 2006-2007 + * + * This file is part of wiiuse. + * + * 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 3 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, see <http://www.gnu.org/licenses/>. + * + * $Header$ + * + */ + +/** + * @file + * + * @brief Example using the wiiuse API. + * + * This file is an example of how to use the wiiuse library. + */ + +#include <stdio.h> +#include <stdlib.h> + +#ifndef WIN32 + #include <unistd.h> +#endif + +#include "wiiuse.h" + + +#define MAX_WIIMOTES 4 + + +/** + * @brief Callback that handles an event. + * + * @param wm Pointer to a wiimote_t structure. + * + * This function is called automatically by the wiiuse library when an + * event occurs on the specified wiimote. + */ +void handle_event(struct wiimote_t* wm) { + printf("\n\n--- EVENT [id %i] ---\n", wm->unid); + + /* if a button is pressed, report it */ + if (IS_PRESSED(wm, WIIMOTE_BUTTON_A)) printf("A pressed\n"); + if (IS_PRESSED(wm, WIIMOTE_BUTTON_B)) printf("B pressed\n"); + if (IS_PRESSED(wm, WIIMOTE_BUTTON_UP)) printf("UP pressed\n"); + if (IS_PRESSED(wm, WIIMOTE_BUTTON_DOWN)) printf("DOWN pressed\n"); + if (IS_PRESSED(wm, WIIMOTE_BUTTON_LEFT)) printf("LEFT pressed\n"); + if (IS_PRESSED(wm, WIIMOTE_BUTTON_RIGHT)) printf("RIGHT pressed\n"); + if (IS_PRESSED(wm, WIIMOTE_BUTTON_MINUS)) printf("MINUS pressed\n"); + if (IS_PRESSED(wm, WIIMOTE_BUTTON_PLUS)) printf("PLUS pressed\n"); + if (IS_PRESSED(wm, WIIMOTE_BUTTON_ONE)) printf("ONE pressed\n"); + if (IS_PRESSED(wm, WIIMOTE_BUTTON_TWO)) printf("TWO pressed\n"); + if (IS_PRESSED(wm, WIIMOTE_BUTTON_HOME)) printf("HOME pressed\n"); + + /* + * Pressing minus will tell the wiimote we are no longer interested in movement. + * This is useful because it saves battery power. + */ + if (IS_JUST_PRESSED(wm, WIIMOTE_BUTTON_MINUS)) + wiiuse_motion_sensing(wm, 0); + + /* + * Pressing plus will tell the wiimote we are interested in movement. + */ + if (IS_JUST_PRESSED(wm, WIIMOTE_BUTTON_PLUS)) + wiiuse_motion_sensing(wm, 1); + + /* + * Pressing B will toggle the rumble + * + * if B is pressed but is not held, toggle the rumble + */ + if (IS_JUST_PRESSED(wm, WIIMOTE_BUTTON_B)) + wiiuse_toggle_rumble(wm); + + if (IS_JUST_PRESSED(wm, WIIMOTE_BUTTON_UP)) + wiiuse_set_ir(wm, 1); + if (IS_JUST_PRESSED(wm, WIIMOTE_BUTTON_DOWN)) + wiiuse_set_ir(wm, 0); + + /* if the accelerometer is turned on then print angles */ + if (WIIUSE_USING_ACC(wm)) { + printf("wiimote roll = %f [%f]\n", wm->orient.roll, wm->orient.a_roll); + printf("wiimote pitch = %f [%f]\n", wm->orient.pitch, wm->orient.a_pitch); + printf("wiimote yaw = %f\n", wm->orient.yaw); + } + + /* + * If IR tracking is enabled then print the coordinates + * on the virtual screen that the wiimote is pointing to. + * + * Also make sure that we see at least 1 dot. + */ + if (WIIUSE_USING_IR(wm)) { + int i = 0; + + /* go through each of the 4 possible IR sources */ + for (; i < 4; ++i) { + /* check if the source is visible */ + if (wm->ir.dot[i].visible) + printf("IR source %i: (%u, %u)\n", i, wm->ir.dot[i].x, wm->ir.dot[i].y); + } + + printf("IR cursor: (%u, %u)\n", wm->ir.x, wm->ir.y); + printf("IR z distance: %f\n", wm->ir.z); + } + + /* show events specific to supported expansions */ + if (wm->exp.type == EXP_NUNCHUK) { + /* nunchuk */ + struct nunchuk_t* nc = (nunchuk_t*)&wm->exp.nunchuk; + + if (IS_PRESSED(nc, NUNCHUK_BUTTON_C)) printf("Nunchuk: C pressed\n"); + if (IS_PRESSED(nc, NUNCHUK_BUTTON_Z)) printf("Nunchuk: Z pressed\n"); + + printf("nunchuk roll = %f\n", nc->orient.roll); + printf("nunchuk pitch = %f\n", nc->orient.pitch); + printf("nunchuk yaw = %f\n", nc->orient.yaw); + + printf("nunchuk joystick angle: %f\n", nc->js.ang); + printf("nunchuk joystick magnitude: %f\n", nc->js.mag); + } else if (wm->exp.type == EXP_CLASSIC) { + /* classic controller */ + struct classic_ctrl_t* cc = (classic_ctrl_t*)&wm->exp.classic; + + if (IS_PRESSED(cc, CLASSIC_CTRL_BUTTON_ZL)) printf("Classic: ZL pressed\n"); + if (IS_PRESSED(cc, CLASSIC_CTRL_BUTTON_B)) printf("Classic: B pressed\n"); + if (IS_PRESSED(cc, CLASSIC_CTRL_BUTTON_Y)) printf("Classic: Y pressed\n"); + if (IS_PRESSED(cc, CLASSIC_CTRL_BUTTON_A)) printf("Classic: A pressed\n"); + if (IS_PRESSED(cc, CLASSIC_CTRL_BUTTON_X)) printf("Classic: X pressed\n"); + if (IS_PRESSED(cc, CLASSIC_CTRL_BUTTON_ZR)) printf("Classic: ZR pressed\n"); + if (IS_PRESSED(cc, CLASSIC_CTRL_BUTTON_LEFT)) printf("Classic: LEFT pressed\n"); + if (IS_PRESSED(cc, CLASSIC_CTRL_BUTTON_UP)) printf("Classic: UP pressed\n"); + if (IS_PRESSED(cc, CLASSIC_CTRL_BUTTON_RIGHT)) printf("Classic: RIGHT pressed\n"); + if (IS_PRESSED(cc, CLASSIC_CTRL_BUTTON_DOWN)) printf("Classic: DOWN pressed\n"); + if (IS_PRESSED(cc, CLASSIC_CTRL_BUTTON_FULL_L)) printf("Classic: FULL L pressed\n"); + if (IS_PRESSED(cc, CLASSIC_CTRL_BUTTON_MINUS)) printf("Classic: MINUS pressed\n"); + if (IS_PRESSED(cc, CLASSIC_CTRL_BUTTON_HOME)) printf("Classic: HOME pressed\n"); + if (IS_PRESSED(cc, CLASSIC_CTRL_BUTTON_PLUS)) printf("Classic: PLUS pressed\n"); + if (IS_PRESSED(cc, CLASSIC_CTRL_BUTTON_FULL_R)) printf("Classic: FULL R pressed\n"); + + printf("classic L button pressed: %f\n", cc->l_shoulder); + printf("classic R button pressed: %f\n", cc->r_shoulder); + printf("classic left joystick angle: %f\n", cc->ljs.ang); + printf("classic left joystick magnitude: %f\n", cc->ljs.mag); + printf("classic right joystick angle: %f\n", cc->rjs.ang); + printf("classic right joystick magnitude: %f\n", cc->rjs.mag); + } else if (wm->exp.type == EXP_GUITAR_HERO_3) { + /* guitar hero 3 guitar */ + struct guitar_hero_3_t* gh3 = (guitar_hero_3_t*)&wm->exp.gh3; + + if (IS_PRESSED(gh3, GUITAR_HERO_3_BUTTON_STRUM_UP)) printf("Guitar: Strum Up pressed\n"); + if (IS_PRESSED(gh3, GUITAR_HERO_3_BUTTON_STRUM_DOWN)) printf("Guitar: Strum Down pressed\n"); + if (IS_PRESSED(gh3, GUITAR_HERO_3_BUTTON_YELLOW)) printf("Guitar: Yellow pressed\n"); + if (IS_PRESSED(gh3, GUITAR_HERO_3_BUTTON_GREEN)) printf("Guitar: Green pressed\n"); + if (IS_PRESSED(gh3, GUITAR_HERO_3_BUTTON_BLUE)) printf("Guitar: Blue pressed\n"); + if (IS_PRESSED(gh3, GUITAR_HERO_3_BUTTON_RED)) printf("Guitar: Red pressed\n"); + if (IS_PRESSED(gh3, GUITAR_HERO_3_BUTTON_ORANGE)) printf("Guitar: Orange pressed\n"); + if (IS_PRESSED(gh3, GUITAR_HERO_3_BUTTON_PLUS)) printf("Guitar: Plus pressed\n"); + if (IS_PRESSED(gh3, GUITAR_HERO_3_BUTTON_MINUS)) printf("Guitar: Minus pressed\n"); + + printf("Guitar whammy bar: %f\n", gh3->whammy_bar); + printf("Guitar joystick angle: %f\n", gh3->js.ang); + printf("Guitar joystick magnitude: %f\n", gh3->js.mag); + } +} + + +/** + * @brief Callback that handles a read event. + * + * @param wm Pointer to a wiimote_t structure. + * @param data Pointer to the filled data block. + * @param len Length in bytes of the data block. + * + * This function is called automatically by the wiiuse library when + * the wiimote has returned the full data requested by a previous + * call to wiiuse_read_data(). + * + * You can read data on the wiimote, such as Mii data, if + * you know the offset address and the length. + * + * The \a data pointer was specified on the call to wiiuse_read_data(). + * At the time of this function being called, it is not safe to deallocate + * this buffer. + */ +void handle_read(struct wiimote_t* wm, byte* data, unsigned short len) { + int i = 0; + + printf("\n\n--- DATA READ [wiimote id %i] ---\n", wm->unid); + printf("finished read of size %i\n", len); + for (; i < len; ++i) { + if (!(i%16)) + printf("\n"); + printf("%x ", data[i]); + } + printf("\n\n"); +} + + +/** + * @brief Callback that handles a controller status event. + * + * @param wm Pointer to a wiimote_t structure. + * @param attachment Is there an attachment? (1 for yes, 0 for no) + * @param speaker Is the speaker enabled? (1 for yes, 0 for no) + * @param ir Is the IR support enabled? (1 for yes, 0 for no) + * @param led What LEDs are lit. + * @param battery_level Battery level, between 0.0 (0%) and 1.0 (100%). + * + * This occurs when either the controller status changed + * or the controller status was requested explicitly by + * wiiuse_status(). + * + * One reason the status can change is if the nunchuk was + * inserted or removed from the expansion port. + */ +void handle_ctrl_status(struct wiimote_t* wm) { + printf("\n\n--- CONTROLLER STATUS [wiimote id %i] ---\n", wm->unid); + + printf("attachment: %i\n", wm->exp.type); + printf("speaker: %i\n", WIIUSE_USING_SPEAKER(wm)); + printf("ir: %i\n", WIIUSE_USING_IR(wm)); + printf("leds: %i %i %i %i\n", WIIUSE_IS_LED_SET(wm, 1), WIIUSE_IS_LED_SET(wm, 2), WIIUSE_IS_LED_SET(wm, 3), WIIUSE_IS_LED_SET(wm, 4)); + printf("battery: %f %%\n", wm->battery_level); +} + + +/** + * @brief Callback that handles a disconnection event. + * + * @param wm Pointer to a wiimote_t structure. + * + * This can happen if the POWER button is pressed, or + * if the connection is interrupted. + */ +void handle_disconnect(wiimote* wm) { + printf("\n\n--- DISCONNECTED [wiimote id %i] ---\n", wm->unid); +} + + +void test(struct wiimote_t* wm, byte* data, unsigned short len) { + printf("test: %i [%x %x %x %x]\n", len, data[0], data[1], data[2], data[3]); +} + + + +/** + * @brief main() + * + * Connect to up to two wiimotes and print any events + * that occur on either device. + */ +int main(int argc, char** argv) { + wiimote** wiimotes; + int found, connected; + + /* + * Initialize an array of wiimote objects. + * + * The parameter is the number of wiimotes I want to create. + */ + wiimotes = wiiuse_init(MAX_WIIMOTES); + + /* + * Find wiimote devices + * + * Now we need to find some wiimotes. + * Give the function the wiimote array we created, and tell it there + * are MAX_WIIMOTES wiimotes we are interested in. + * + * Set the timeout to be 5 seconds. + * + * This will return the number of actual wiimotes that are in discovery mode. + */ + found = wiiuse_find(wiimotes, MAX_WIIMOTES, 5); + if (!found) { + printf ("No wiimotes found."); + return 0; + } + + /* + * Connect to the wiimotes + * + * Now that we found some wiimotes, connect to them. + * Give the function the wiimote array and the number + * of wiimote devices we found. + * + * This will return the number of established connections to the found wiimotes. + */ + connected = wiiuse_connect(wiimotes, MAX_WIIMOTES); + if (connected) + printf("Connected to %i wiimotes (of %i found).\n", connected, found); + else { + printf("Failed to connect to any wiimote.\n"); + return 0; + } + + /* + * Now set the LEDs and rumble for a second so it's easy + * to tell which wiimotes are connected (just like the wii does). + */ + wiiuse_set_leds(wiimotes[0], WIIMOTE_LED_1); + wiiuse_set_leds(wiimotes[1], WIIMOTE_LED_2); + wiiuse_set_leds(wiimotes[2], WIIMOTE_LED_3); + wiiuse_set_leds(wiimotes[3], WIIMOTE_LED_4); + wiiuse_rumble(wiimotes[0], 1); + wiiuse_rumble(wiimotes[1], 1); + + #ifndef WIN32 + usleep(200000); + #else + Sleep(200); + #endif + + wiiuse_rumble(wiimotes[0], 0); + wiiuse_rumble(wiimotes[1], 0); + + /* + * Maybe I'm interested in the battery power of the 0th + * wiimote. This should be WIIMOTE_ID_1 but to be sure + * you can get the wiimote assoicated with WIIMOTE_ID_1 + * using the wiiuse_get_by_id() function. + * + * A status request will return other things too, like + * if any expansions are plugged into the wiimote or + * what LEDs are lit. + */ + //wiiuse_status(wiimotes[0]); + + /* + * This is the main loop + * + * wiiuse_poll() needs to be called with the wiimote array + * and the number of wiimote structures in that array + * (it doesn't matter if some of those wiimotes are not used + * or are not connected). + * + * This function will set the event flag for each wiimote + * when the wiimote has things to report. + */ + while (1) { + if (wiiuse_poll(wiimotes, MAX_WIIMOTES)) { + /* + * This happens if something happened on any wiimote. + * So go through each one and check if anything happened. + */ + int i = 0; + for (; i < MAX_WIIMOTES; ++i) { + switch (wiimotes[i]->event) { + case WIIUSE_EVENT: + /* a generic event occurred */ + handle_event(wiimotes[i]); + break; + + case WIIUSE_STATUS: + /* a status event occurred */ + handle_ctrl_status(wiimotes[i]); + break; + + case WIIUSE_DISCONNECT: + case WIIUSE_UNEXPECTED_DISCONNECT: + /* the wiimote disconnected */ + handle_disconnect(wiimotes[i]); + break; + + case WIIUSE_READ_DATA: + /* + * Data we requested to read was returned. + * Take a look at wiimotes[i]->read_req + * for the data. + */ + break; + + case WIIUSE_NUNCHUK_INSERTED: + /* + * a nunchuk was inserted + * This is a good place to set any nunchuk specific + * threshold values. By default they are the same + * as the wiimote. + */ + //wiiuse_set_nunchuk_orient_threshold((struct nunchuk_t*)&wiimotes[i]->exp.nunchuk, 90.0f); + //wiiuse_set_nunchuk_accel_threshold((struct nunchuk_t*)&wiimotes[i]->exp.nunchuk, 100); + printf("Nunchuk inserted.\n"); + break; + + case WIIUSE_CLASSIC_CTRL_INSERTED: + printf("Classic controller inserted.\n"); + break; + + case WIIUSE_GUITAR_HERO_3_CTRL_INSERTED: + /* some expansion was inserted */ + handle_ctrl_status(wiimotes[i]); + printf("Guitar Hero 3 controller inserted.\n"); + break; + + case WIIUSE_NUNCHUK_REMOVED: + case WIIUSE_CLASSIC_CTRL_REMOVED: + case WIIUSE_GUITAR_HERO_3_CTRL_REMOVED: + /* some expansion was removed */ + handle_ctrl_status(wiimotes[i]); + printf("An expansion was removed.\n"); + break; + + default: + break; + } + } + } + } + + /* + * Disconnect the wiimotes + */ + wiiuse_cleanup(wiimotes, MAX_WIIMOTES); + + return 0; +} diff --git a/tools/EventClients/Clients/WiiRemote/wiiuse_v0.12/example/msvc/wiiuseexample.dsp b/tools/EventClients/Clients/WiiRemote/wiiuse_v0.12/example/msvc/wiiuseexample.dsp new file mode 100644 index 0000000..2329dbc --- /dev/null +++ b/tools/EventClients/Clients/WiiRemote/wiiuse_v0.12/example/msvc/wiiuseexample.dsp @@ -0,0 +1,106 @@ +# Microsoft Developer Studio Project File - Name="wiiuseexample" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +CFG=wiiuseexample - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "wiiuseexample.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "wiiuseexample.mak" CFG="wiiuseexample - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "wiiuseexample - Win32 Release" (based on "Win32 (x86) Console Application") +!MESSAGE "wiiuseexample - Win32 Debug" (based on "Win32 (x86) Console Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "wiiuseexample - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /W3 /GX /O2 /I "..\..\src" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib wsock32.lib wiiuse.lib /nologo /subsystem:console /machine:I386 + +!ELSEIF "$(CFG)" == "wiiuseexample - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c +# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /I "..\..\src" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept + +!ENDIF + +# Begin Target + +# Name "wiiuseexample - Win32 Release" +# Name "wiiuseexample - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=..\example.c +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=..\..\src\wiiuse.h +# End Source File +# End Group +# Begin Group "Resource Files" + +# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" +# End Group +# End Target +# End Project diff --git a/tools/EventClients/Clients/WiiRemote/wiiuse_v0.12/example/msvc/wiiuseexample.dsw b/tools/EventClients/Clients/WiiRemote/wiiuse_v0.12/example/msvc/wiiuseexample.dsw new file mode 100644 index 0000000..88298b6 --- /dev/null +++ b/tools/EventClients/Clients/WiiRemote/wiiuse_v0.12/example/msvc/wiiuseexample.dsw @@ -0,0 +1,29 @@ +Microsoft Developer Studio Workspace File, Format Version 6.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "wiiuseexample"=".\wiiuseexample.dsp" - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + diff --git a/tools/EventClients/Clients/WiiRemote/wiiuse_v0.12/example/msvc/wiiuseexample.opt b/tools/EventClients/Clients/WiiRemote/wiiuse_v0.12/example/msvc/wiiuseexample.opt Binary files differnew file mode 100644 index 0000000..fe837f8 --- /dev/null +++ b/tools/EventClients/Clients/WiiRemote/wiiuse_v0.12/example/msvc/wiiuseexample.opt diff --git a/tools/EventClients/Clients/WiiRemote/wiiuse_v0.12/src/Makefile b/tools/EventClients/Clients/WiiRemote/wiiuse_v0.12/src/Makefile new file mode 100644 index 0000000..53cc612 --- /dev/null +++ b/tools/EventClients/Clients/WiiRemote/wiiuse_v0.12/src/Makefile @@ -0,0 +1,91 @@ +# +# wiiuse Makefile +# + +# +# Change this to your GCC version. +# +CC ?= gcc + +#################################################### +# +# You should not need to edit below this line. +# +#################################################### + +# +# Universal cflags +# +CFLAGS = -Wall -pipe -fPIC -funroll-loops + +ifeq ($(debug),1) + OBJ_PREFIX = debug + CFLAGS += -g -pg -DWITH_WIIUSE_DEBUG + +else + OBJ_PREFIX = release + CFLAGS += -O2 +endif + +OBJ_DIR = $(OBJ_PREFIX)-$(shell $(CC) -v 2>&1|grep ^Target:|cut -d' ' -f2) + +# +# Linking flags +# +LDFLAGS = -shared -lm -lbluetooth + +# +# Target binaries (always created as BIN) +# +BIN = ./$(OBJ_DIR)/libwiiuse.so + +# +# Inclusion paths. +# +INCLUDES = -I. + +# +# Generate a list of object files +# +OBJS = \ + $(OBJ_DIR)/classic.o \ + $(OBJ_DIR)/dynamics.o \ + $(OBJ_DIR)/events.o \ + $(OBJ_DIR)/io.o \ + $(OBJ_DIR)/io_nix.o \ + $(OBJ_DIR)/ir.o \ + $(OBJ_DIR)/nunchuk.o \ + $(OBJ_DIR)/guitar_hero_3.o \ + $(OBJ_DIR)/wiiuse.o + +############################### +# +# Build targets. +# +############################### + +all: $(BIN) + +clean: + @-rm $(OBJS) 2> /dev/null + +distclean: + @-rm -r debug-* release-* 2> /dev/null + +install: + @if [ -e $(BIN) ]; then \ + cp -v $(BIN) /usr/lib ; \ + fi + @cp -v wiiuse.h /usr/include + +$(BIN): mkdir $(OBJS) + $(CC) $(CFLAGS) $(LDFLAGS) $(OBJS) -o $(BIN) + +$(OBJ_DIR)/%.o: %.c + $(CC) $(CFLAGS) $(INCLUDES) -c $< -o $@ + +mkdir: + @if [ ! -d $(OBJ_DIR) ]; then \ + mkdir $(OBJ_DIR); \ + fi + diff --git a/tools/EventClients/Clients/WiiRemote/wiiuse_v0.12/src/classic.c b/tools/EventClients/Clients/WiiRemote/wiiuse_v0.12/src/classic.c new file mode 100644 index 0000000..1d3abaa --- /dev/null +++ b/tools/EventClients/Clients/WiiRemote/wiiuse_v0.12/src/classic.c @@ -0,0 +1,190 @@ +/* + * wiiuse + * + * Written By: + * Michael Laforest < para > + * Email: < thepara (--AT--) g m a i l [--DOT--] com > + * + * Copyright 2006-2007 + * + * This file is part of wiiuse. + * + * 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 3 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, see <http://www.gnu.org/licenses/>. + * + * $Header$ + * + */ + +/** + * @file + * @brief Classic controller expansion device. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <math.h> + +#ifdef WIN32 + #include <Winsock2.h> +#endif + +#include "definitions.h" +#include "wiiuse_internal.h" +#include "dynamics.h" +#include "events.h" +#include "classic.h" + +static void classic_ctrl_pressed_buttons(struct classic_ctrl_t* cc, short now); + +/** + * @brief Handle the handshake data from the classic controller. + * + * @param cc A pointer to a classic_ctrl_t structure. + * @param data The data read in from the device. + * @param len The length of the data block, in bytes. + * + * @return Returns 1 if handshake was successful, 0 if not. + */ +int classic_ctrl_handshake(struct wiimote_t* wm, struct classic_ctrl_t* cc, byte* data, unsigned short len) { + int i; + int offset = 0; + + cc->btns = 0; + cc->btns_held = 0; + cc->btns_released = 0; + cc->r_shoulder = 0; + cc->l_shoulder = 0; + + /* decrypt data */ + for (i = 0; i < len; ++i) + data[i] = (data[i] ^ 0x17) + 0x17; + + if (data[offset] == 0xFF) { + /* + * Sometimes the data returned here is not correct. + * This might happen because the wiimote is lagging + * behind our initialization sequence. + * To fix this just request the handshake again. + * + * Other times it's just the first 16 bytes are 0xFF, + * but since the next 16 bytes are the same, just use + * those. + */ + if (data[offset + 16] == 0xFF) { + /* get the calibration data */ + byte* handshake_buf = malloc(EXP_HANDSHAKE_LEN * sizeof(byte)); + + WIIUSE_DEBUG("Classic controller handshake appears invalid, trying again."); + wiiuse_read_data_cb(wm, handshake_expansion, handshake_buf, WM_EXP_MEM_CALIBR, EXP_HANDSHAKE_LEN); + + return 0; + } else + offset += 16; + } + + + /* joystick stuff */ + cc->ljs.max.x = data[0 + offset] / 4; + cc->ljs.min.x = data[1 + offset] / 4; + cc->ljs.center.x = data[2 + offset] / 4; + cc->ljs.max.y = data[3 + offset] / 4; + cc->ljs.min.y = data[4 + offset] / 4; + cc->ljs.center.y = data[5 + offset] / 4; + + cc->rjs.max.x = data[6 + offset] / 8; + cc->rjs.min.x = data[7 + offset] / 8; + cc->rjs.center.x = data[8 + offset] / 8; + cc->rjs.max.y = data[9 + offset] / 8; + cc->rjs.min.y = data[10 + offset] / 8; + cc->rjs.center.y = data[11 + offset] / 8; + + /* handshake done */ + wm->exp.type = EXP_CLASSIC; + + #ifdef WIN32 + wm->timeout = WIIMOTE_DEFAULT_TIMEOUT; + #endif + + return 1; +} + + +/** + * @brief The classic controller disconnected. + * + * @param cc A pointer to a classic_ctrl_t structure. + */ +void classic_ctrl_disconnected(struct classic_ctrl_t* cc) { + memset(cc, 0, sizeof(struct classic_ctrl_t)); +} + + + +/** + * @brief Handle classic controller event. + * + * @param cc A pointer to a classic_ctrl_t structure. + * @param msg The message specified in the event packet. + */ +void classic_ctrl_event(struct classic_ctrl_t* cc, byte* msg) { + int i, lx, ly, rx, ry; + byte l, r; + + /* decrypt data */ + for (i = 0; i < 6; ++i) + msg[i] = (msg[i] ^ 0x17) + 0x17; + + classic_ctrl_pressed_buttons(cc, BIG_ENDIAN_SHORT(*(short*)(msg + 4))); + + /* left/right buttons */ + l = (((msg[2] & 0x60) >> 2) | ((msg[3] & 0xE0) >> 5)); + r = (msg[3] & 0x1F); + + /* + * TODO - LR range hardcoded from 0x00 to 0x1F. + * This is probably in the calibration somewhere. + */ + cc->r_shoulder = ((float)r / 0x1F); + cc->l_shoulder = ((float)l / 0x1F); + + /* calculate joystick orientation */ + lx = (msg[0] & 0x3F); + ly = (msg[1] & 0x3F); + rx = ((msg[0] & 0xC0) >> 3) | ((msg[1] & 0xC0) >> 5) | ((msg[2] & 0x80) >> 7); + ry = (msg[2] & 0x1F); + + calc_joystick_state(&cc->ljs, lx, ly); + calc_joystick_state(&cc->rjs, rx, ry); +} + + +/** + * @brief Find what buttons are pressed. + * + * @param cc A pointer to a classic_ctrl_t structure. + * @param msg The message byte specified in the event packet. + */ +static void classic_ctrl_pressed_buttons(struct classic_ctrl_t* cc, short now) { + /* message is inverted (0 is active, 1 is inactive) */ + now = ~now & CLASSIC_CTRL_BUTTON_ALL; + + /* pressed now & were pressed, then held */ + cc->btns_held = (now & cc->btns); + + /* were pressed or were held & not pressed now, then released */ + cc->btns_released = ((cc->btns | cc->btns_held) & ~now); + + /* buttons pressed now */ + cc->btns = now; +} diff --git a/tools/EventClients/Clients/WiiRemote/wiiuse_v0.12/src/classic.h b/tools/EventClients/Clients/WiiRemote/wiiuse_v0.12/src/classic.h new file mode 100644 index 0000000..308e1b5 --- /dev/null +++ b/tools/EventClients/Clients/WiiRemote/wiiuse_v0.12/src/classic.h @@ -0,0 +1,51 @@ +/* + * wiiuse + * + * Written By: + * Michael Laforest < para > + * Email: < thepara (--AT--) g m a i l [--DOT--] com > + * + * Copyright 2006-2007 + * + * This file is part of wiiuse. + * + * 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 3 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, see <http://www.gnu.org/licenses/>. + * + * $Header$ + * + */ + +/** + * @file + * @brief Classic controller expansion device. + */ + +#pragma once + +#include "wiiuse_internal.h" + +#ifdef __cplusplus +extern "C" { +#endif + +int classic_ctrl_handshake(struct wiimote_t* wm, struct classic_ctrl_t* cc, byte* data, unsigned short len); + +void classic_ctrl_disconnected(struct classic_ctrl_t* cc); + +void classic_ctrl_event(struct classic_ctrl_t* cc, byte* msg); + +#ifdef __cplusplus +} +#endif + diff --git a/tools/EventClients/Clients/WiiRemote/wiiuse_v0.12/src/definitions.h b/tools/EventClients/Clients/WiiRemote/wiiuse_v0.12/src/definitions.h new file mode 100644 index 0000000..c5d1270 --- /dev/null +++ b/tools/EventClients/Clients/WiiRemote/wiiuse_v0.12/src/definitions.h @@ -0,0 +1,77 @@ +/* + * wiiuse + * + * Written By: + * Michael Laforest < para > + * Email: < thepara (--AT--) g m a i l [--DOT--] com > + * + * Copyright 2006-2007 + * + * This file is part of wiiuse. + * + * 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 3 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, see <http://www.gnu.org/licenses/>. + * + * $Header$ + * + */ + +/** + * @file + * @brief General definitions. + */ + +#pragma once + +/* this is wiiuse - used to distinguish from third party programs using wiiuse.h */ +#include "os.h" + +#define WIIMOTE_PI 3.14159265f + +//#define WITH_WIIUSE_DEBUG + +/* Error output macros */ +#define WIIUSE_ERROR(fmt, ...) fprintf(stderr, "[ERROR] " fmt "\n", ##__VA_ARGS__) + +/* Warning output macros */ +#define WIIUSE_WARNING(fmt, ...) fprintf(stderr, "[WARNING] " fmt "\n", ##__VA_ARGS__) + +/* Information output macros */ +#define WIIUSE_INFO(fmt, ...) fprintf(stderr, "[INFO] " fmt "\n", ##__VA_ARGS__) + +#ifdef WITH_WIIUSE_DEBUG + #ifdef WIN32 + #define WIIUSE_DEBUG(fmt, ...) do { \ + char* file = __FILE__; \ + int i = strlen(file) - 1; \ + for (; i && (file[i] != '\\'); --i); \ + fprintf(stderr, "[DEBUG] %s:%i: " fmt "\n", file+i+1, __LINE__, ##__VA_ARGS__); \ + } while (0) + #else + #define WIIUSE_DEBUG(fmt, ...) fprintf(stderr, "[DEBUG] " __FILE__ ":%i: " fmt "\n", __LINE__, ##__VA_ARGS__) + #endif +#else + #define WIIUSE_DEBUG(fmt, ...) +#endif + +/* Convert between radians and degrees */ +#define RAD_TO_DEGREE(r) ((r * 180.0f) / WIIMOTE_PI) +#define DEGREE_TO_RAD(d) (d * (WIIMOTE_PI / 180.0f)) + +/* Convert to big endian */ +#define BIG_ENDIAN_LONG(i) (htonl(i)) +#define BIG_ENDIAN_SHORT(i) (htons(i)) + +#define absf(x) ((x >= 0) ? (x) : (x * -1.0f)) +#define diff_f(x, y) ((x >= y) ? (absf(x - y)) : (absf(y - x))) + diff --git a/tools/EventClients/Clients/WiiRemote/wiiuse_v0.12/src/dynamics.c b/tools/EventClients/Clients/WiiRemote/wiiuse_v0.12/src/dynamics.c new file mode 100644 index 0000000..b6baa72 --- /dev/null +++ b/tools/EventClients/Clients/WiiRemote/wiiuse_v0.12/src/dynamics.c @@ -0,0 +1,228 @@ +/* + * wiiuse + * + * Written By: + * Michael Laforest < para > + * Email: < thepara (--AT--) g m a i l [--DOT--] com > + * + * Copyright 2006-2007 + * + * This file is part of wiiuse. + * + * 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 3 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, see <http://www.gnu.org/licenses/>. + * + * $Header$ + * + */ + +/** + * @file + * @brief Handles the dynamics of the wiimote. + * + * The file includes functions that handle the dynamics + * of the wiimote. Such dynamics include orientation and + * motion sensing. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <math.h> + +#ifdef WIN32 + #include <float.h> +#endif + +#include "definitions.h" +#include "wiiuse_internal.h" +#include "ir.h" +#include "dynamics.h" + +/** + * @brief Calculate the roll, pitch, yaw. + * + * @param ac An accelerometer (accel_t) structure. + * @param accel [in] Pointer to a vec3b_t structure that holds the raw acceleration data. + * @param orient [out] Pointer to a orient_t structure that will hold the orientation data. + * @param rorient [out] Pointer to a orient_t structure that will hold the non-smoothed orientation data. + * @param smooth If smoothing should be performed on the angles calculated. 1 to enable, 0 to disable. + * + * Given the raw acceleration data from the accelerometer struct, calculate + * the orientation of the device and set it in the \a orient parameter. + */ +void calculate_orientation(struct accel_t* ac, struct vec3b_t* accel, struct orient_t* orient, int smooth) { + float xg, yg, zg; + float x, y, z; + + /* + * roll - use atan(z / x) [ ranges from -180 to 180 ] + * pitch - use atan(z / y) [ ranges from -180 to 180 ] + * yaw - impossible to tell without IR + */ + + /* yaw - set to 0, IR will take care of it if it's enabled */ + orient->yaw = 0.0f; + + /* find out how much it has to move to be 1g */ + xg = (float)ac->cal_g.x; + yg = (float)ac->cal_g.y; + zg = (float)ac->cal_g.z; + + /* find out how much it actually moved and normalize to +/- 1g */ + x = ((float)accel->x - (float)ac->cal_zero.x) / xg; + y = ((float)accel->y - (float)ac->cal_zero.y) / yg; + z = ((float)accel->z - (float)ac->cal_zero.z) / zg; + + /* make sure x,y,z are between -1 and 1 for the tan functions */ + if (x < -1.0f) x = -1.0f; + else if (x > 1.0f) x = 1.0f; + if (y < -1.0f) y = -1.0f; + else if (y > 1.0f) y = 1.0f; + if (z < -1.0f) z = -1.0f; + else if (z > 1.0f) z = 1.0f; + + /* if it is over 1g then it is probably accelerating and not reliable */ + if (abs(accel->x - ac->cal_zero.x) <= ac->cal_g.x) { + /* roll */ + x = RAD_TO_DEGREE(atan2f(x, z)); + + orient->roll = x; + orient->a_roll = x; + } + + if (abs(accel->y - ac->cal_zero.y) <= ac->cal_g.y) { + /* pitch */ + y = RAD_TO_DEGREE(atan2f(y, z)); + + orient->pitch = y; + orient->a_pitch = y; + } + + /* smooth the angles if enabled */ + if (smooth) { + apply_smoothing(ac, orient, SMOOTH_ROLL); + apply_smoothing(ac, orient, SMOOTH_PITCH); + } +} + + +/** + * @brief Calculate the gravity forces on each axis. + * + * @param ac An accelerometer (accel_t) structure. + * @param accel [in] Pointer to a vec3b_t structure that holds the raw acceleration data. + * @param gforce [out] Pointer to a gforce_t structure that will hold the gravity force data. + */ +void calculate_gforce(struct accel_t* ac, struct vec3b_t* accel, struct gforce_t* gforce) { + float xg, yg, zg; + + /* find out how much it has to move to be 1g */ + xg = (float)ac->cal_g.x; + yg = (float)ac->cal_g.y; + zg = (float)ac->cal_g.z; + + /* find out how much it actually moved and normalize to +/- 1g */ + gforce->x = ((float)accel->x - (float)ac->cal_zero.x) / xg; + gforce->y = ((float)accel->y - (float)ac->cal_zero.y) / yg; + gforce->z = ((float)accel->z - (float)ac->cal_zero.z) / zg; +} + + +/** + * @brief Calculate the angle and magnitude of a joystick. + * + * @param js [out] Pointer to a joystick_t structure. + * @param x The raw x-axis value. + * @param y The raw y-axis value. + */ +void calc_joystick_state(struct joystick_t* js, float x, float y) { + float rx, ry, ang; + + /* + * Since the joystick center may not be exactly: + * (min + max) / 2 + * Then the range from the min to the center and the center to the max + * may be different. + * Because of this, depending on if the current x or y value is greater + * or less than the assoicated axis center value, it needs to be interpolated + * between the center and the minimum or maxmimum rather than between + * the minimum and maximum. + * + * So we have something like this: + * (x min) [-1] ---------*------ [0] (x center) [0] -------- [1] (x max) + * Where the * is the current x value. + * The range is therefore -1 to 1, 0 being the exact center rather than + * the middle of min and max. + */ + if (x == js->center.x) + rx = 0; + else if (x >= js->center.x) + rx = ((float)(x - js->center.x) / (float)(js->max.x - js->center.x)); + else + rx = ((float)(x - js->min.x) / (float)(js->center.x - js->min.x)) - 1.0f; + + if (y == js->center.y) + ry = 0; + else if (y >= js->center.y) + ry = ((float)(y - js->center.y) / (float)(js->max.y - js->center.y)); + else + ry = ((float)(y - js->min.y) / (float)(js->center.y - js->min.y)) - 1.0f; + + /* calculate the joystick angle and magnitude */ + ang = RAD_TO_DEGREE(atanf(ry / rx)); + ang -= 90.0f; + if (rx < 0.0f) + ang -= 180.0f; + js->ang = absf(ang); + js->mag = (float) sqrt((rx * rx) + (ry * ry)); +} + + +void apply_smoothing(struct accel_t* ac, struct orient_t* orient, int type) { + switch (type) { + case SMOOTH_ROLL: + { + /* it's possible last iteration was nan or inf, so set it to 0 if that happened */ + if (isnan(ac->st_roll) || isinf(ac->st_roll)) + ac->st_roll = 0.0f; + + /* + * If the sign changes (which will happen if going from -180 to 180) + * or from (-1 to 1) then don't smooth, just use the new angle. + */ + if (((ac->st_roll < 0) && (orient->roll > 0)) || ((ac->st_roll > 0) && (orient->roll < 0))) { + ac->st_roll = orient->roll; + } else { + orient->roll = ac->st_roll + (ac->st_alpha * (orient->a_roll - ac->st_roll)); + ac->st_roll = orient->roll; + } + + return; + } + + case SMOOTH_PITCH: + { + if (isnan(ac->st_pitch) || isinf(ac->st_pitch)) + ac->st_pitch = 0.0f; + + if (((ac->st_pitch < 0) && (orient->pitch > 0)) || ((ac->st_pitch > 0) && (orient->pitch < 0))) { + ac->st_pitch = orient->pitch; + } else { + orient->pitch = ac->st_pitch + (ac->st_alpha * (orient->a_pitch - ac->st_pitch)); + ac->st_pitch = orient->pitch; + } + + return; + } + } +} diff --git a/tools/EventClients/Clients/WiiRemote/wiiuse_v0.12/src/dynamics.h b/tools/EventClients/Clients/WiiRemote/wiiuse_v0.12/src/dynamics.h new file mode 100644 index 0000000..2f41d04 --- /dev/null +++ b/tools/EventClients/Clients/WiiRemote/wiiuse_v0.12/src/dynamics.h @@ -0,0 +1,54 @@ +/* + * wiiuse + * + * Written By: + * Michael Laforest < para > + * Email: < thepara (--AT--) g m a i l [--DOT--] com > + * + * Copyright 2006-2007 + * + * This file is part of wiiuse. + * + * 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 3 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, see <http://www.gnu.org/licenses/>. + * + * $Header$ + * + */ + +/** + * @file + * @brief Handles the dynamics of the wiimote. + * + * The file includes functions that handle the dynamics + * of the wiimote. Such dynamics include orientation and + * motion sensing. + */ + +#pragma once + +#include "wiiuse_internal.h" + +#ifdef __cplusplus +extern "C" { +#endif + +void calculate_orientation(struct accel_t* ac, struct vec3b_t* accel, struct orient_t* orient, int smooth); +void calculate_gforce(struct accel_t* ac, struct vec3b_t* accel, struct gforce_t* gforce); +void calc_joystick_state(struct joystick_t* js, float x, float y); +void apply_smoothing(struct accel_t* ac, struct orient_t* orient, int type); + +#ifdef __cplusplus +} +#endif + diff --git a/tools/EventClients/Clients/WiiRemote/wiiuse_v0.12/src/events.c b/tools/EventClients/Clients/WiiRemote/wiiuse_v0.12/src/events.c new file mode 100644 index 0000000..04c2ea5 --- /dev/null +++ b/tools/EventClients/Clients/WiiRemote/wiiuse_v0.12/src/events.c @@ -0,0 +1,878 @@ +/* + * wiiuse + * + * Written By: + * Michael Laforest < para > + * Email: < thepara (--AT--) g m a i l [--DOT--] com > + * + * Copyright 2006-2007 + * + * This file is part of wiiuse. + * + * 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 3 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, see <http://www.gnu.org/licenses/>. + * + * $Header$ + * + */ + +/** + * @file + * @brief Handles wiimote events. + * + * The file includes functions that handle the events + * that are sent from the wiimote to us. + */ + +#include <stdio.h> + +#ifndef WIN32 + #include <sys/time.h> + #include <unistd.h> + #include <errno.h> +#else + #include <winsock2.h> +#endif + +#include <sys/types.h> +#include <stdlib.h> +#include <math.h> + +#include "definitions.h" +#include "io.h" +#include "wiiuse_internal.h" +#include "dynamics.h" +#include "ir.h" +#include "nunchuk.h" +#include "classic.h" +#include "guitar_hero_3.h" +#include "events.h" + +static void idle_cycle(struct wiimote_t* wm); +static void clear_dirty_reads(struct wiimote_t* wm); +static void propagate_event(struct wiimote_t* wm, byte event, byte* msg); +static void event_data_read(struct wiimote_t* wm, byte* msg); +static void event_status(struct wiimote_t* wm, byte* msg); +static void handle_expansion(struct wiimote_t* wm, byte* msg); + +static void save_state(struct wiimote_t* wm); +static int state_changed(struct wiimote_t* wm); + +/** + * @brief Poll the wiimotes for any events. + * + * @param wm An array of pointers to wiimote_t structures. + * @param wiimotes The number of wiimote_t structures in the \a wm array. + * + * @return Returns number of wiimotes that an event has occurred on. + * + * It is necessary to poll the wiimote devices for events + * that occur. If an event occurs on a particular wiimote, + * the event variable will be set. + */ +int wiiuse_poll(struct wiimote_t** wm, int wiimotes) { + int evnt = 0; + + #ifndef WIN32 + /* + * *nix + */ + struct timeval tv; + fd_set fds; + int r; + int i; + int highest_fd = -1; + + if (!wm) return 0; + + /* block select() for 1/2000th of a second */ + tv.tv_sec = 0; + tv.tv_usec = 500; + + FD_ZERO(&fds); + + for (i = 0; i < wiimotes; ++i) { + /* only poll it if it is connected */ + if (WIIMOTE_IS_SET(wm[i], WIIMOTE_STATE_CONNECTED)) { + FD_SET(wm[i]->in_sock, &fds); + + /* find the highest fd of the connected wiimotes */ + if (wm[i]->in_sock > highest_fd) + highest_fd = wm[i]->in_sock; + } + + wm[i]->event = WIIUSE_NONE; + } + + if (highest_fd == -1) + /* nothing to poll */ + return 0; + + if (select(highest_fd + 1, &fds, NULL, NULL, &tv) == -1) { + WIIUSE_ERROR("Unable to select() the wiimote interrupt socket(s)."); + perror("Error Details"); + return 0; + } + + /* check each socket for an event */ + for (i = 0; i < wiimotes; ++i) { + /* if this wiimote is not connected, skip it */ + if (!WIIMOTE_IS_CONNECTED(wm[i])) + continue; + + if (FD_ISSET(wm[i]->in_sock, &fds)) { + /* clear out the event buffer */ + memset(wm[i]->event_buf, 0, sizeof(wm[i]->event_buf)); + + /* clear out any old read requests */ + clear_dirty_reads(wm[i]); + + /* read the pending message into the buffer */ + r = read(wm[i]->in_sock, wm[i]->event_buf, sizeof(wm[i]->event_buf)); + if (r == -1) { + /* error reading data */ + WIIUSE_ERROR("Receiving wiimote data (id %i).", wm[i]->unid); + perror("Error Details"); + + if (errno == ENOTCONN) { + /* this can happen if the bluetooth dongle is disconnected */ + WIIUSE_ERROR("Bluetooth appears to be disconnected. Wiimote unid %i will be disconnected.", wm[i]->unid); + wiiuse_disconnect(wm[i]); + wm[i]->event = WIIUSE_UNEXPECTED_DISCONNECT; + } + + continue; + } + if (!r) { + /* remote disconnect */ + wiiuse_disconnected(wm[i]); + evnt = 1; + continue; + } + + /* propagate the event */ + propagate_event(wm[i], wm[i]->event_buf[1], wm[i]->event_buf+2); + evnt += (wm[i]->event != WIIUSE_NONE); + } else { + idle_cycle(wm[i]); + } + } + #else + /* + * Windows + */ + int i; + + if (!wm) return 0; + + for (i = 0; i < wiimotes; ++i) { + wm[i]->event = WIIUSE_NONE; + + if (wiiuse_io_read(wm[i])) { + /* propagate the event */ + propagate_event(wm[i], wm[i]->event_buf[0], wm[i]->event_buf+1); + evnt += (wm[i]->event != WIIUSE_NONE); + + /* clear out the event buffer */ + memset(wm[i]->event_buf, 0, sizeof(wm[i]->event_buf)); + } else { + idle_cycle(wm[i]); + } + } + #endif + + return evnt; +} + + +/** + * @brief Called on a cycle where no significant change occurs. + * + * @param wm Pointer to a wiimote_t structure. + */ +static void idle_cycle(struct wiimote_t* wm) { + /* + * Smooth the angles. + * + * This is done to make sure that on every cycle the orientation + * angles are smoothed. Normally when an event occurs the angles + * are updated and smoothed, but if no packet comes in then the + * angles remain the same. This means the angle wiiuse reports + * is still an old value. Smoothing needs to be applied in this + * case in order for the angle it reports to converge to the true + * angle of the device. + */ + if (WIIUSE_USING_ACC(wm) && WIIMOTE_IS_FLAG_SET(wm, WIIUSE_SMOOTHING)) { + apply_smoothing(&wm->accel_calib, &wm->orient, SMOOTH_ROLL); + apply_smoothing(&wm->accel_calib, &wm->orient, SMOOTH_PITCH); + } + + /* clear out any old read requests */ + clear_dirty_reads(wm); +} + + +/** + * @brief Clear out all old 'dirty' read requests. + * + * @param wm Pointer to a wiimote_t structure. + */ +static void clear_dirty_reads(struct wiimote_t* wm) { + struct read_req_t* req = wm->read_req; + + while (req && req->dirty) { + WIIUSE_DEBUG("Cleared old read request for address: %x", req->addr); + + wm->read_req = req->next; + free(req); + req = wm->read_req; + } +} + + +/** + * @brief Analyze the event that occurred on a wiimote. + * + * @param wm An array of pointers to wiimote_t structures. + * @param event The event that occurred. + * @param msg The message specified in the event packet. + * + * Pass the event to the registered event callback. + */ +static void propagate_event(struct wiimote_t* wm, byte event, byte* msg) { + save_state(wm); + + switch (event) { + case WM_RPT_BTN: + { + /* button */ + wiiuse_pressed_buttons(wm, msg); + break; + } + case WM_RPT_BTN_ACC: + { + /* button - motion */ + wiiuse_pressed_buttons(wm, msg); + + wm->accel.x = msg[2]; + wm->accel.y = msg[3]; + wm->accel.z = msg[4]; + + /* calculate the remote orientation */ + calculate_orientation(&wm->accel_calib, &wm->accel, &wm->orient, WIIMOTE_IS_FLAG_SET(wm, WIIUSE_SMOOTHING)); + + /* calculate the gforces on each axis */ + calculate_gforce(&wm->accel_calib, &wm->accel, &wm->gforce); + + break; + } + case WM_RPT_READ: + { + /* data read */ + event_data_read(wm, msg); + + /* yeah buttons may be pressed, but this wasn't an "event" */ + return; + } + case WM_RPT_CTRL_STATUS: + { + /* controller status */ + event_status(wm, msg); + + /* don't execute the event callback */ + return; + } + case WM_RPT_BTN_EXP: + { + /* button - expansion */ + wiiuse_pressed_buttons(wm, msg); + handle_expansion(wm, msg+2); + + break; + } + case WM_RPT_BTN_ACC_EXP: + { + /* button - motion - expansion */ + wiiuse_pressed_buttons(wm, msg); + + wm->accel.x = msg[2]; + wm->accel.y = msg[3]; + wm->accel.z = msg[4]; + + calculate_orientation(&wm->accel_calib, &wm->accel, &wm->orient, WIIMOTE_IS_FLAG_SET(wm, WIIUSE_SMOOTHING)); + calculate_gforce(&wm->accel_calib, &wm->accel, &wm->gforce); + + handle_expansion(wm, msg+5); + + break; + } + case WM_RPT_BTN_ACC_IR: + { + /* button - motion - ir */ + wiiuse_pressed_buttons(wm, msg); + + wm->accel.x = msg[2]; + wm->accel.y = msg[3]; + wm->accel.z = msg[4]; + + calculate_orientation(&wm->accel_calib, &wm->accel, &wm->orient, WIIMOTE_IS_FLAG_SET(wm, WIIUSE_SMOOTHING)); + calculate_gforce(&wm->accel_calib, &wm->accel, &wm->gforce); + + /* ir */ + calculate_extended_ir(wm, msg+5); + + break; + } + case WM_RPT_BTN_IR_EXP: + { + /* button - ir - expansion */ + wiiuse_pressed_buttons(wm, msg); + handle_expansion(wm, msg+12); + + /* ir */ + calculate_basic_ir(wm, msg+2); + + break; + } + case WM_RPT_BTN_ACC_IR_EXP: + { + /* button - motion - ir - expansion */ + wiiuse_pressed_buttons(wm, msg); + + wm->accel.x = msg[2]; + wm->accel.y = msg[3]; + wm->accel.z = msg[4]; + + calculate_orientation(&wm->accel_calib, &wm->accel, &wm->orient, WIIMOTE_IS_FLAG_SET(wm, WIIUSE_SMOOTHING)); + calculate_gforce(&wm->accel_calib, &wm->accel, &wm->gforce); + + handle_expansion(wm, msg+15); + + /* ir */ + calculate_basic_ir(wm, msg+5); + + break; + } + case WM_RPT_WRITE: + { + /* write feedback - safe to skip */ + break; + } + default: + { + WIIUSE_WARNING("Unknown event, can not handle it [Code 0x%x].", event); + return; + } + } + + /* was there an event? */ + if (state_changed(wm)) + wm->event = WIIUSE_EVENT; +} + + +/** + * @brief Find what buttons are pressed. + * + * @param wm Pointer to a wiimote_t structure. + * @param msg The message specified in the event packet. + */ +void wiiuse_pressed_buttons(struct wiimote_t* wm, byte* msg) { + short now; + + /* convert to big endian */ + now = BIG_ENDIAN_SHORT(*(short*)msg) & WIIMOTE_BUTTON_ALL; + + /* pressed now & were pressed, then held */ + wm->btns_held = (now & wm->btns); + + /* were pressed or were held & not pressed now, then released */ + wm->btns_released = ((wm->btns | wm->btns_held) & ~now); + + /* buttons pressed now */ + wm->btns = now; +} + + +/** + * @brief Received a data packet from a read request. + * + * @param wm Pointer to a wiimote_t structure. + * @param msg The message specified in the event packet. + * + * Data from the wiimote comes in packets. If the requested + * data segment size is bigger than one packet can hold then + * several packets will be received. These packets are first + * reassembled into one, then the registered callback function + * that handles data reads is invoked. + */ +static void event_data_read(struct wiimote_t* wm, byte* msg) { + /* we must always assume the packet received is from the most recent request */ + byte err; + byte len; + unsigned short offset; + struct read_req_t* req = wm->read_req; + + wiiuse_pressed_buttons(wm, msg); + + /* find the next non-dirty request */ + while (req && req->dirty) + req = req->next; + + /* if we don't have a request out then we didn't ask for this packet */ + if (!req) { + WIIUSE_WARNING("Received data packet when no request was made."); + return; + } + + err = msg[2] & 0x0F; + + if (err == 0x08) + WIIUSE_WARNING("Unable to read data - address does not exist."); + else if (err == 0x07) + WIIUSE_WARNING("Unable to read data - address is for write-only registers."); + else if (err) + WIIUSE_WARNING("Unable to read data - unknown error code %x.", err); + + if (err) { + /* this request errored out, so skip it and go to the next one */ + + /* delete this request */ + wm->read_req = req->next; + free(req); + + /* if another request exists send it to the wiimote */ + if (wm->read_req) + wiiuse_send_next_pending_read_request(wm); + + return; + } + + len = ((msg[2] & 0xF0) >> 4) + 1; + offset = BIG_ENDIAN_SHORT(*(unsigned short*)(msg + 3)); + req->addr = (req->addr & 0xFFFF); + + req->wait -= len; + if (req->wait >= req->size) + /* this should never happen */ + req->wait = 0; + + WIIUSE_DEBUG("Received read packet:"); + WIIUSE_DEBUG(" Packet read offset: %i bytes", offset); + WIIUSE_DEBUG(" Request read offset: %i bytes", req->addr); + WIIUSE_DEBUG(" Read offset into buf: %i bytes", offset - req->addr); + WIIUSE_DEBUG(" Read data size: %i bytes", len); + WIIUSE_DEBUG(" Still need: %i bytes", req->wait); + + /* reconstruct this part of the data */ + memcpy((req->buf + offset - req->addr), (msg + 5), len); + + #ifdef WITH_WIIUSE_DEBUG + { + int i = 0; + printf("Read: "); + for (; i < req->size - req->wait; ++i) + printf("%x ", req->buf[i]); + printf("\n"); + } + #endif + + /* if all data has been received, execute the read event callback or generate event */ + if (!req->wait) { + if (req->cb) { + /* this was a callback, so invoke it now */ + req->cb(wm, req->buf, req->size); + + /* delete this request */ + wm->read_req = req->next; + free(req); + } else { + /* + * This should generate an event. + * We need to leave the event in the array so the client + * can access it still. We'll flag is as being 'dirty' + * and give the client one cycle to use it. Next event + * we will remove it from the list. + */ + wm->event = WIIUSE_READ_DATA; + req->dirty = 1; + } + + /* if another request exists send it to the wiimote */ + if (wm->read_req) + wiiuse_send_next_pending_read_request(wm); + } +} + + +/** + * @brief Read the controller status. + * + * @param wm Pointer to a wiimote_t structure. + * @param msg The message specified in the event packet. + * + * Read the controller status and execute the registered status callback. + */ +static void event_status(struct wiimote_t* wm, byte* msg) { + int led[4] = {0}; + int attachment = 0; + int ir = 0; + int exp_changed = 0; + + /* + * An event occurred. + * This event can be overwritten by a more specific + * event type during a handshake or expansion removal. + */ + wm->event = WIIUSE_STATUS; + + wiiuse_pressed_buttons(wm, msg); + + /* find what LEDs are lit */ + if (msg[2] & WM_CTRL_STATUS_BYTE1_LED_1) led[0] = 1; + if (msg[2] & WM_CTRL_STATUS_BYTE1_LED_2) led[1] = 1; + if (msg[2] & WM_CTRL_STATUS_BYTE1_LED_3) led[2] = 1; + if (msg[2] & WM_CTRL_STATUS_BYTE1_LED_4) led[3] = 1; + + /* is an attachment connected to the expansion port? */ + if ((msg[2] & WM_CTRL_STATUS_BYTE1_ATTACHMENT) == WM_CTRL_STATUS_BYTE1_ATTACHMENT) + attachment = 1; + + /* is the speaker enabled? */ + if ((msg[2] & WM_CTRL_STATUS_BYTE1_SPEAKER_ENABLED) == WM_CTRL_STATUS_BYTE1_SPEAKER_ENABLED) + WIIMOTE_ENABLE_STATE(wm, WIIMOTE_STATE_SPEAKER); + + /* is IR sensing enabled? */ + if ((msg[2] & WM_CTRL_STATUS_BYTE1_IR_ENABLED) == WM_CTRL_STATUS_BYTE1_IR_ENABLED) + ir = 1; + + /* find the battery level and normalize between 0 and 1 */ + wm->battery_level = (msg[5] / (float)WM_MAX_BATTERY_CODE); + + /* expansion port */ + if (attachment && !WIIMOTE_IS_SET(wm, WIIMOTE_STATE_EXP)) { + /* send the initialization code for the attachment */ + handshake_expansion(wm, NULL, 0); + exp_changed = 1; + } else if (!attachment && WIIMOTE_IS_SET(wm, WIIMOTE_STATE_EXP)) { + /* attachment removed */ + disable_expansion(wm); + exp_changed = 1; + } + + #ifdef WIN32 + if (!attachment) { + WIIUSE_DEBUG("Setting timeout to normal %i ms.", wm->normal_timeout); + wm->timeout = wm->normal_timeout; + } + #endif + + /* + * From now on the remote will only send status packets. + * We need to send a WIIMOTE_CMD_REPORT_TYPE packet to + * reenable other incoming reports. + */ + if (exp_changed && WIIMOTE_IS_SET(wm, WIIMOTE_STATE_IR)) { + /* + * Since the expansion status changed IR needs to + * be reset for the new IR report mode. + */ + WIIMOTE_DISABLE_STATE(wm, WIIMOTE_STATE_IR); + wiiuse_set_ir(wm, 1); + } else + wiiuse_set_report_type(wm); +} + + +/** + * @brief Handle data from the expansion. + * + * @param wm A pointer to a wiimote_t structure. + * @param msg The message specified in the event packet for the expansion. + */ +static void handle_expansion(struct wiimote_t* wm, byte* msg) { + switch (wm->exp.type) { + case EXP_NUNCHUK: + nunchuk_event(&wm->exp.nunchuk, msg); + break; + case EXP_CLASSIC: + classic_ctrl_event(&wm->exp.classic, msg); + break; + case EXP_GUITAR_HERO_3: + guitar_hero_3_event(&wm->exp.gh3, msg); + break; + default: + break; + } +} + + +/** + * @brief Handle the handshake data from the expansion device. + * + * @param wm A pointer to a wiimote_t structure. + * @param data The data read in from the device. + * @param len The length of the data block, in bytes. + * + * Tries to determine what kind of expansion was attached + * and invoke the correct handshake function. + * + * If the data is NULL then this function will try to start + * a handshake with the expansion. + */ +void handshake_expansion(struct wiimote_t* wm, byte* data, unsigned short len) { + int id; + + if (!data) { + byte* handshake_buf; + byte buf = 0x00; + + if (WIIMOTE_IS_SET(wm, WIIMOTE_STATE_EXP)) + disable_expansion(wm); + + /* increase the timeout until the handshake completes */ + #ifdef WIN32 + WIIUSE_DEBUG("Setting timeout to expansion %i ms.", wm->exp_timeout); + wm->timeout = wm->exp_timeout; + #endif + + wiiuse_write_data(wm, WM_EXP_MEM_ENABLE, &buf, 1); + + /* get the calibration data */ + handshake_buf = malloc(EXP_HANDSHAKE_LEN * sizeof(byte)); + wiiuse_read_data_cb(wm, handshake_expansion, handshake_buf, WM_EXP_MEM_CALIBR, EXP_HANDSHAKE_LEN); + + /* tell the wiimote to send expansion data */ + WIIMOTE_ENABLE_STATE(wm, WIIMOTE_STATE_EXP); + + return; + } + + id = BIG_ENDIAN_LONG(*(int*)(data + 220)); + + /* call the corresponding handshake function for this expansion */ + switch (id) { + case EXP_ID_CODE_NUNCHUK: + { + if (nunchuk_handshake(wm, &wm->exp.nunchuk, data, len)) + wm->event = WIIUSE_NUNCHUK_INSERTED; + break; + } + case EXP_ID_CODE_CLASSIC_CONTROLLER: + { + if (classic_ctrl_handshake(wm, &wm->exp.classic, data, len)) + wm->event = WIIUSE_CLASSIC_CTRL_INSERTED; + break; + } + case EXP_ID_CODE_GUITAR: + { + if (guitar_hero_3_handshake(wm, &wm->exp.gh3, data, len)) + wm->event = WIIUSE_GUITAR_HERO_3_CTRL_INSERTED; + break; + } + default: + { + WIIUSE_WARNING("Unknown expansion type. Code: 0x%x", id); + break; + } + } + + free(data); +} + + + +/** + * @brief Disable the expansion device if it was enabled. + * + * @param wm A pointer to a wiimote_t structure. + * @param data The data read in from the device. + * @param len The length of the data block, in bytes. + * + * If the data is NULL then this function will try to start + * a handshake with the expansion. + */ +void disable_expansion(struct wiimote_t* wm) { + if (!WIIMOTE_IS_SET(wm, WIIMOTE_STATE_EXP)) + return; + + /* tell the assoicated module the expansion was removed */ + switch (wm->exp.type) { + case EXP_NUNCHUK: + nunchuk_disconnected(&wm->exp.nunchuk); + wm->event = WIIUSE_NUNCHUK_REMOVED; + break; + case EXP_CLASSIC: + classic_ctrl_disconnected(&wm->exp.classic); + wm->event = WIIUSE_CLASSIC_CTRL_REMOVED; + break; + case EXP_GUITAR_HERO_3: + guitar_hero_3_disconnected(&wm->exp.gh3); + wm->event = WIIUSE_GUITAR_HERO_3_CTRL_REMOVED; + break; + default: + break; + } + + WIIMOTE_DISABLE_STATE(wm, WIIMOTE_STATE_EXP); + wm->exp.type = EXP_NONE; +} + + +/** + * @brief Save important state data. + * @param wm A pointer to a wiimote_t structure. + */ +static void save_state(struct wiimote_t* wm) { + /* wiimote */ + wm->lstate.btns = wm->btns; + wm->lstate.accel = wm->accel; + + /* ir */ + if (WIIUSE_USING_IR(wm)) { + wm->lstate.ir_ax = wm->ir.ax; + wm->lstate.ir_ay = wm->ir.ay; + wm->lstate.ir_distance = wm->ir.distance; + } + + /* expansion */ + switch (wm->exp.type) { + case EXP_NUNCHUK: + wm->lstate.exp_ljs_ang = wm->exp.nunchuk.js.ang; + wm->lstate.exp_ljs_mag = wm->exp.nunchuk.js.mag; + wm->lstate.exp_btns = wm->exp.nunchuk.btns; + wm->lstate.exp_accel = wm->exp.nunchuk.accel; + break; + + case EXP_CLASSIC: + wm->lstate.exp_ljs_ang = wm->exp.classic.ljs.ang; + wm->lstate.exp_ljs_mag = wm->exp.classic.ljs.mag; + wm->lstate.exp_rjs_ang = wm->exp.classic.rjs.ang; + wm->lstate.exp_rjs_mag = wm->exp.classic.rjs.mag; + wm->lstate.exp_r_shoulder = wm->exp.classic.r_shoulder; + wm->lstate.exp_l_shoulder = wm->exp.classic.l_shoulder; + wm->lstate.exp_btns = wm->exp.classic.btns; + break; + + case EXP_GUITAR_HERO_3: + wm->lstate.exp_ljs_ang = wm->exp.gh3.js.ang; + wm->lstate.exp_ljs_mag = wm->exp.gh3.js.mag; + wm->lstate.exp_r_shoulder = wm->exp.gh3.whammy_bar; + wm->lstate.exp_btns = wm->exp.gh3.btns; + break; + + case EXP_NONE: + break; + } +} + + +/** + * @brief Determine if the current state differs significantly from the previous. + * @param wm A pointer to a wiimote_t structure. + * @return 1 if a significant change occurred, 0 if not. + */ +static int state_changed(struct wiimote_t* wm) { + #define STATE_CHANGED(a, b) if (a != b) return 1 + + #define CROSS_THRESH(last, now, thresh) \ + do { \ + if (WIIMOTE_IS_FLAG_SET(wm, WIIUSE_ORIENT_THRESH)) { \ + if ((diff_f(last.roll, now.roll) >= thresh) || \ + (diff_f(last.pitch, now.pitch) >= thresh) || \ + (diff_f(last.yaw, now.yaw) >= thresh)) \ + { \ + last = now; \ + return 1; \ + } \ + } else { \ + if (last.roll != now.roll) return 1; \ + if (last.pitch != now.pitch) return 1; \ + if (last.yaw != now.yaw) return 1; \ + } \ + } while (0) + + #define CROSS_THRESH_XYZ(last, now, thresh) \ + do { \ + if (WIIMOTE_IS_FLAG_SET(wm, WIIUSE_ORIENT_THRESH)) { \ + if ((diff_f(last.x, now.x) >= thresh) || \ + (diff_f(last.y, now.y) >= thresh) || \ + (diff_f(last.z, now.z) >= thresh)) \ + { \ + last = now; \ + return 1; \ + } \ + } else { \ + if (last.x != now.x) return 1; \ + if (last.y != now.y) return 1; \ + if (last.z != now.z) return 1; \ + } \ + } while (0) + + /* ir */ + if (WIIUSE_USING_IR(wm)) { + STATE_CHANGED(wm->lstate.ir_ax, wm->ir.ax); + STATE_CHANGED(wm->lstate.ir_ay, wm->ir.ay); + STATE_CHANGED(wm->lstate.ir_distance, wm->ir.distance); + } + + /* accelerometer */ + if (WIIUSE_USING_ACC(wm)) { + /* raw accelerometer */ + CROSS_THRESH_XYZ(wm->lstate.accel, wm->accel, wm->accel_threshold); + + /* orientation */ + CROSS_THRESH(wm->lstate.orient, wm->orient, wm->orient_threshold); + } + + /* expansion */ + switch (wm->exp.type) { + case EXP_NUNCHUK: + { + STATE_CHANGED(wm->lstate.exp_ljs_ang, wm->exp.nunchuk.js.ang); + STATE_CHANGED(wm->lstate.exp_ljs_mag, wm->exp.nunchuk.js.mag); + STATE_CHANGED(wm->lstate.exp_btns, wm->exp.nunchuk.btns); + + CROSS_THRESH(wm->lstate.exp_orient, wm->exp.nunchuk.orient, wm->exp.nunchuk.orient_threshold); + CROSS_THRESH_XYZ(wm->lstate.exp_accel, wm->exp.nunchuk.accel, wm->exp.nunchuk.accel_threshold); + break; + } + case EXP_CLASSIC: + { + STATE_CHANGED(wm->lstate.exp_ljs_ang, wm->exp.classic.ljs.ang); + STATE_CHANGED(wm->lstate.exp_ljs_mag, wm->exp.classic.ljs.mag); + STATE_CHANGED(wm->lstate.exp_rjs_ang, wm->exp.classic.rjs.ang); + STATE_CHANGED(wm->lstate.exp_rjs_mag, wm->exp.classic.rjs.mag); + STATE_CHANGED(wm->lstate.exp_r_shoulder, wm->exp.classic.r_shoulder); + STATE_CHANGED(wm->lstate.exp_l_shoulder, wm->exp.classic.l_shoulder); + STATE_CHANGED(wm->lstate.exp_btns, wm->exp.classic.btns); + break; + } + case EXP_GUITAR_HERO_3: + { + STATE_CHANGED(wm->lstate.exp_ljs_ang, wm->exp.gh3.js.ang); + STATE_CHANGED(wm->lstate.exp_ljs_mag, wm->exp.gh3.js.mag); + STATE_CHANGED(wm->lstate.exp_r_shoulder, wm->exp.gh3.whammy_bar); + STATE_CHANGED(wm->lstate.exp_btns, wm->exp.gh3.btns); + break; + } + case EXP_NONE: + { + break; + } + } + + STATE_CHANGED(wm->lstate.btns, wm->btns); + + return 0; +} diff --git a/tools/EventClients/Clients/WiiRemote/wiiuse_v0.12/src/events.h b/tools/EventClients/Clients/WiiRemote/wiiuse_v0.12/src/events.h new file mode 100644 index 0000000..9b9121c --- /dev/null +++ b/tools/EventClients/Clients/WiiRemote/wiiuse_v0.12/src/events.h @@ -0,0 +1,51 @@ +/* + * wiiuse + * + * Written By: + * Michael Laforest < para > + * Email: < thepara (--AT--) g m a i l [--DOT--] com > + * + * Copyright 2006-2007 + * + * This file is part of wiiuse. + * + * 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 3 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, see <http://www.gnu.org/licenses/>. + * + * $Header$ + * + */ + +/** + * @file + * @brief Handles wiimote events. + * + * The file includes functions that handle the events + * that are sent from the wiimote to us. + */ + +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +void wiiuse_pressed_buttons(struct wiimote_t* wm, byte* msg); + +void handshake_expansion(struct wiimote_t* wm, byte* data, unsigned short len); +void disable_expansion(struct wiimote_t* wm); + +#ifdef __cplusplus +} +#endif + diff --git a/tools/EventClients/Clients/WiiRemote/wiiuse_v0.12/src/guitar_hero_3.c b/tools/EventClients/Clients/WiiRemote/wiiuse_v0.12/src/guitar_hero_3.c new file mode 100644 index 0000000..29c58af --- /dev/null +++ b/tools/EventClients/Clients/WiiRemote/wiiuse_v0.12/src/guitar_hero_3.c @@ -0,0 +1,172 @@ +/* + * wiiuse + * + * Written By: + * Michael Laforest < para > + * Email: < thepara (--AT--) g m a i l [--DOT--] com > + * + * Copyright 2006-2007 + * + * This file is part of wiiuse. + * + * 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 3 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, see <http://www.gnu.org/licenses/>. + * + * $Header$ + * + */ + +/** + * @file + * @brief Guitar Hero 3 expansion device. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <math.h> + +#ifdef WIN32 + #include <Winsock2.h> +#endif + +#include "definitions.h" +#include "wiiuse_internal.h" +#include "dynamics.h" +#include "events.h" +#include "guitar_hero_3.h" + +static void guitar_hero_3_pressed_buttons(struct guitar_hero_3_t* gh3, short now); + +/** + * @brief Handle the handshake data from the guitar. + * + * @param cc A pointer to a classic_ctrl_t structure. + * @param data The data read in from the device. + * @param len The length of the data block, in bytes. + * + * @return Returns 1 if handshake was successful, 0 if not. + */ +int guitar_hero_3_handshake(struct wiimote_t* wm, struct guitar_hero_3_t* gh3, byte* data, unsigned short len) { + int i; + int offset = 0; + + /* + * The good fellows that made the Guitar Hero 3 controller + * failed to factory calibrate the devices. There is no + * calibration data on the device. + */ + + gh3->btns = 0; + gh3->btns_held = 0; + gh3->btns_released = 0; + gh3->whammy_bar = 0.0f; + + /* decrypt data */ + for (i = 0; i < len; ++i) + data[i] = (data[i] ^ 0x17) + 0x17; + + if (data[offset] == 0xFF) { + /* + * Sometimes the data returned here is not correct. + * This might happen because the wiimote is lagging + * behind our initialization sequence. + * To fix this just request the handshake again. + * + * Other times it's just the first 16 bytes are 0xFF, + * but since the next 16 bytes are the same, just use + * those. + */ + if (data[offset + 16] == 0xFF) { + /* get the calibration data */ + byte* handshake_buf = malloc(EXP_HANDSHAKE_LEN * sizeof(byte)); + + WIIUSE_DEBUG("Guitar Hero 3 handshake appears invalid, trying again."); + wiiuse_read_data_cb(wm, handshake_expansion, handshake_buf, WM_EXP_MEM_CALIBR, EXP_HANDSHAKE_LEN); + + return 0; + } else + offset += 16; + } + + /* joystick stuff */ + gh3->js.max.x = GUITAR_HERO_3_JS_MAX_X; + gh3->js.min.x = GUITAR_HERO_3_JS_MIN_X; + gh3->js.center.x = GUITAR_HERO_3_JS_CENTER_X; + gh3->js.max.y = GUITAR_HERO_3_JS_MAX_Y; + gh3->js.min.y = GUITAR_HERO_3_JS_MIN_Y; + gh3->js.center.y = GUITAR_HERO_3_JS_CENTER_Y; + + /* handshake done */ + wm->exp.type = EXP_GUITAR_HERO_3; + + #ifdef WIN32 + wm->timeout = WIIMOTE_DEFAULT_TIMEOUT; + #endif + + return 1; +} + + +/** + * @brief The guitar disconnected. + * + * @param cc A pointer to a classic_ctrl_t structure. + */ +void guitar_hero_3_disconnected(struct guitar_hero_3_t* gh3) { + memset(gh3, 0, sizeof(struct guitar_hero_3_t)); +} + + + +/** + * @brief Handle guitar event. + * + * @param cc A pointer to a classic_ctrl_t structure. + * @param msg The message specified in the event packet. + */ +void guitar_hero_3_event(struct guitar_hero_3_t* gh3, byte* msg) { + int i; + + /* decrypt data */ + for (i = 0; i < 6; ++i) + msg[i] = (msg[i] ^ 0x17) + 0x17; + + guitar_hero_3_pressed_buttons(gh3, BIG_ENDIAN_SHORT(*(short*)(msg + 4))); + + /* whammy bar */ + gh3->whammy_bar = (msg[3] - GUITAR_HERO_3_WHAMMY_BAR_MIN) / (float)(GUITAR_HERO_3_WHAMMY_BAR_MAX - GUITAR_HERO_3_WHAMMY_BAR_MIN); + + /* joy stick */ + calc_joystick_state(&gh3->js, msg[0], msg[1]); +} + + +/** + * @brief Find what buttons are pressed. + * + * @param cc A pointer to a classic_ctrl_t structure. + * @param msg The message byte specified in the event packet. + */ +static void guitar_hero_3_pressed_buttons(struct guitar_hero_3_t* gh3, short now) { + /* message is inverted (0 is active, 1 is inactive) */ + now = ~now & GUITAR_HERO_3_BUTTON_ALL; + + /* pressed now & were pressed, then held */ + gh3->btns_held = (now & gh3->btns); + + /* were pressed or were held & not pressed now, then released */ + gh3->btns_released = ((gh3->btns | gh3->btns_held) & ~now); + + /* buttons pressed now */ + gh3->btns = now; +} diff --git a/tools/EventClients/Clients/WiiRemote/wiiuse_v0.12/src/guitar_hero_3.h b/tools/EventClients/Clients/WiiRemote/wiiuse_v0.12/src/guitar_hero_3.h new file mode 100644 index 0000000..a8c8ffa --- /dev/null +++ b/tools/EventClients/Clients/WiiRemote/wiiuse_v0.12/src/guitar_hero_3.h @@ -0,0 +1,60 @@ +/* + * wiiuse + * + * Written By: + * Michael Laforest < para > + * Email: < thepara (--AT--) g m a i l [--DOT--] com > + * + * Copyright 2006-2007 + * + * This file is part of wiiuse. + * + * 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 3 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, see <http://www.gnu.org/licenses/>. + * + * $Header$ + * + */ + +/** + * @file + * @brief Guitar Hero 3 expansion device. + */ + +#pragma once + +#include "wiiuse_internal.h" + +#define GUITAR_HERO_3_JS_MIN_X 0xC5 +#define GUITAR_HERO_3_JS_MAX_X 0xFC +#define GUITAR_HERO_3_JS_CENTER_X 0xE0 +#define GUITAR_HERO_3_JS_MIN_Y 0xC5 +#define GUITAR_HERO_3_JS_MAX_Y 0xFA +#define GUITAR_HERO_3_JS_CENTER_Y 0xE0 +#define GUITAR_HERO_3_WHAMMY_BAR_MIN 0xEF +#define GUITAR_HERO_3_WHAMMY_BAR_MAX 0xFA + +#ifdef __cplusplus +extern "C" { +#endif + +int guitar_hero_3_handshake(struct wiimote_t* wm, struct guitar_hero_3_t* gh3, byte* data, unsigned short len); + +void guitar_hero_3_disconnected(struct guitar_hero_3_t* gh3); + +void guitar_hero_3_event(struct guitar_hero_3_t* gh3, byte* msg); + +#ifdef __cplusplus +} +#endif + diff --git a/tools/EventClients/Clients/WiiRemote/wiiuse_v0.12/src/io.c b/tools/EventClients/Clients/WiiRemote/wiiuse_v0.12/src/io.c new file mode 100644 index 0000000..65b3627 --- /dev/null +++ b/tools/EventClients/Clients/WiiRemote/wiiuse_v0.12/src/io.c @@ -0,0 +1,119 @@ +/* + * wiiuse + * + * Written By: + * Michael Laforest < para > + * Email: < thepara (--AT--) g m a i l [--DOT--] com > + * + * Copyright 2006-2007 + * + * This file is part of wiiuse. + * + * 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 3 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, see <http://www.gnu.org/licenses/>. + * + * $Header$ + * + */ + +/** + * @file + * @brief Handles device I/O (non-OS specific). + */ + +#include <stdio.h> +#include <stdlib.h> + +#include "definitions.h" +#include "wiiuse_internal.h" +#include "io.h" + + + /** + * @brief Get initialization data from the wiimote. + * + * @param wm Pointer to a wiimote_t structure. + * @param data unused + * @param len unused + * + * When first called for a wiimote_t structure, a request + * is sent to the wiimote for initialization information. + * This includes factory set accelerometer data. + * The handshake will be concluded when the wiimote responds + * with this data. + */ +void wiiuse_handshake(struct wiimote_t* wm, byte* data, unsigned short len) { + if (!wm) return; + + switch (wm->handshake_state) { + case 0: + { + /* send request to wiimote for accelerometer calibration */ + byte* buf; + + WIIMOTE_ENABLE_STATE(wm, WIIMOTE_STATE_HANDSHAKE); + wiiuse_set_leds(wm, WIIMOTE_LED_NONE); + + buf = (byte*)malloc(sizeof(byte) * 8); + wiiuse_read_data_cb(wm, wiiuse_handshake, buf, WM_MEM_OFFSET_CALIBRATION, 7); + wm->handshake_state++; + + wiiuse_set_leds(wm, WIIMOTE_LED_NONE); + + break; + } + case 1: + { + struct read_req_t* req = wm->read_req; + struct accel_t* accel = &wm->accel_calib; + + /* received read data */ + accel->cal_zero.x = req->buf[0]; + accel->cal_zero.y = req->buf[1]; + accel->cal_zero.z = req->buf[2]; + + accel->cal_g.x = req->buf[4] - accel->cal_zero.x; + accel->cal_g.y = req->buf[5] - accel->cal_zero.y; + accel->cal_g.z = req->buf[6] - accel->cal_zero.z; + + /* done with the buffer */ + free(req->buf); + + /* handshake is done */ + WIIUSE_DEBUG("Handshake finished. Calibration: Idle: X=%x Y=%x Z=%x\t+1g: X=%x Y=%x Z=%x", + accel->cal_zero.x, accel->cal_zero.y, accel->cal_zero.z, + accel->cal_g.x, accel->cal_g.y, accel->cal_g.z); + + + /* request the status of the wiimote to see if there is an expansion */ + wiiuse_status(wm); + + WIIMOTE_DISABLE_STATE(wm, WIIMOTE_STATE_HANDSHAKE); + WIIMOTE_ENABLE_STATE(wm, WIIMOTE_STATE_HANDSHAKE_COMPLETE); + wm->handshake_state++; + + /* now enable IR if it was set before the handshake completed */ + if (WIIMOTE_IS_SET(wm, WIIMOTE_STATE_IR)) { + WIIUSE_DEBUG("Handshake finished, enabling IR."); + WIIMOTE_DISABLE_STATE(wm, WIIMOTE_STATE_IR); + wiiuse_set_ir(wm, 1); + } + + break; + } + default: + { + break; + } + } +} diff --git a/tools/EventClients/Clients/WiiRemote/wiiuse_v0.12/src/io.h b/tools/EventClients/Clients/WiiRemote/wiiuse_v0.12/src/io.h new file mode 100644 index 0000000..19e7031 --- /dev/null +++ b/tools/EventClients/Clients/WiiRemote/wiiuse_v0.12/src/io.h @@ -0,0 +1,54 @@ +/* + * wiiuse + * + * Written By: + * Michael Laforest < para > + * Email: < thepara (--AT--) g m a i l [--DOT--] com > + * + * Copyright 2006-2007 + * + * This file is part of wiiuse. + * + * 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 3 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, see <http://www.gnu.org/licenses/>. + * + * $Header$ + * + */ + +/** + * @file + * @brief Handles device I/O. + */ + +#pragma once + +#ifndef WIN32 + #include <bluetooth/bluetooth.h> +#endif + +#include "wiiuse_internal.h" + +#ifdef __cplusplus +extern "C" { +#endif + +void wiiuse_handshake(struct wiimote_t* wm, byte* data, unsigned short len); + +int wiiuse_io_read(struct wiimote_t* wm); +int wiiuse_io_write(struct wiimote_t* wm, byte* buf, int len); + +#ifdef __cplusplus +} +#endif + diff --git a/tools/EventClients/Clients/WiiRemote/wiiuse_v0.12/src/io_nix.c b/tools/EventClients/Clients/WiiRemote/wiiuse_v0.12/src/io_nix.c new file mode 100644 index 0000000..0f2c5b8 --- /dev/null +++ b/tools/EventClients/Clients/WiiRemote/wiiuse_v0.12/src/io_nix.c @@ -0,0 +1,271 @@ +/* + * wiiuse + * + * Written By: + * Michael Laforest < para > + * Email: < thepara (--AT--) g m a i l [--DOT--] com > + * + * Copyright 2006-2007 + * + * This file is part of wiiuse. + * + * 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 3 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, see <http://www.gnu.org/licenses/>. + * + * $Header$ + * + */ + +/** + * @file + * @brief Handles device I/O for *nix. + */ + +#ifndef WIN32 + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> + +#include <bluetooth/bluetooth.h> +#include <bluetooth/hci.h> +#include <bluetooth/hci_lib.h> +#include <bluetooth/l2cap.h> + +#include "definitions.h" +#include "wiiuse_internal.h" +#include "io.h" + +static int wiiuse_connect_single(struct wiimote_t* wm, char* address); + +/** + * @brief Find a wiimote or wiimotes. + * + * @param wm An array of wiimote_t structures. + * @param max_wiimotes The number of wiimote structures in \a wm. + * @param timeout The number of seconds before the search times out. + * + * @return The number of wiimotes found. + * + * @see wiimote_connect() + * + * This function will only look for wiimote devices. \n + * When a device is found the address in the structures will be set. \n + * You can then call wiimote_connect() to connect to the found \n + * devices. + */ +int wiiuse_find(struct wiimote_t** wm, int max_wiimotes, int timeout) { + int device_id; + int device_sock; + int found_devices; + int found_wiimotes; + + /* reset all wiimote bluetooth device addresses */ + for (found_wiimotes = 0; found_wiimotes < max_wiimotes; ++found_wiimotes) + wm[found_wiimotes]->bdaddr = *BDADDR_ANY; + found_wiimotes = 0; + + /* get the id of the first bluetooth device. */ + device_id = hci_get_route(NULL); + if (device_id < 0) { + perror("hci_get_route"); + return 0; + } + + /* create a socket to the device */ + device_sock = hci_open_dev(device_id); + if (device_sock < 0) { + perror("hci_open_dev"); + return 0; + } + + inquiry_info scan_info_arr[128]; + inquiry_info* scan_info = scan_info_arr; + memset(&scan_info_arr, 0, sizeof(scan_info_arr)); + + /* scan for bluetooth devices for 'timeout' seconds */ + found_devices = hci_inquiry(device_id, timeout, 128, NULL, &scan_info, IREQ_CACHE_FLUSH); + if (found_devices < 0) { + perror("hci_inquiry"); + return 0; + } + + WIIUSE_INFO("Found %i bluetooth device(s).", found_devices); + + int i = 0; + + /* display discovered devices */ + for (; (i < found_devices) && (found_wiimotes < max_wiimotes); ++i) { + if ((scan_info[i].dev_class[0] == WM_DEV_CLASS_0) && + (scan_info[i].dev_class[1] == WM_DEV_CLASS_1) && + (scan_info[i].dev_class[2] == WM_DEV_CLASS_2)) + { + /* found a device */ + ba2str(&scan_info[i].bdaddr, wm[found_wiimotes]->bdaddr_str); + + WIIUSE_INFO("Found wiimote (%s) [id %i].", wm[found_wiimotes]->bdaddr_str, wm[found_wiimotes]->unid); + + wm[found_wiimotes]->bdaddr = scan_info[i].bdaddr; + WIIMOTE_ENABLE_STATE(wm[found_wiimotes], WIIMOTE_STATE_DEV_FOUND); + ++found_wiimotes; + } + } + + close(device_sock); + return found_wiimotes; +} + + +/** + * @brief Connect to a wiimote or wiimotes once an address is known. + * + * @param wm An array of wiimote_t structures. + * @param wiimotes The number of wiimote structures in \a wm. + * + * @return The number of wiimotes that successfully connected. + * + * @see wiiuse_find() + * @see wiiuse_connect_single() + * @see wiiuse_disconnect() + * + * Connect to a number of wiimotes when the address is already set + * in the wiimote_t structures. These addresses are normally set + * by the wiiuse_find() function, but can also be set manually. + */ +int wiiuse_connect(struct wiimote_t** wm, int wiimotes) { + int connected = 0; + int i = 0; + + for (; i < wiimotes; ++i) { + if (!WIIMOTE_IS_SET(wm[i], WIIMOTE_STATE_DEV_FOUND)) + /* if the device address is not set, skip it */ + continue; + + if (wiiuse_connect_single(wm[i], NULL)) + ++connected; + } + + return connected; +} + + +/** + * @brief Connect to a wiimote with a known address. + * + * @param wm Pointer to a wiimote_t structure. + * @param address The address of the device to connect to. + * If NULL, use the address in the struct set by wiiuse_find(). + * + * @return 1 on success, 0 on failure + */ +static int wiiuse_connect_single(struct wiimote_t* wm, char* address) { + struct sockaddr_l2 addr; + + memset(&addr, 0, sizeof (addr)); + if (!wm || WIIMOTE_IS_CONNECTED(wm)) + return 0; + + addr.l2_family = AF_BLUETOOTH; + + if (address) + /* use provided address */ + str2ba(address, &addr.l2_bdaddr); + else + /* use address of device discovered */ + addr.l2_bdaddr = wm->bdaddr; + + /* + * OUTPUT CHANNEL + */ + wm->out_sock = socket(AF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP); + if (wm->out_sock == -1) + return 0; + + addr.l2_psm = htobs(WM_OUTPUT_CHANNEL); + + /* connect to wiimote */ + if (connect(wm->out_sock, (struct sockaddr*)&addr, sizeof(addr)) < 0) { + perror("connect() output sock"); + return 0; + } + + /* + * INPUT CHANNEL + */ + wm->in_sock = socket(AF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP); + if (wm->in_sock == -1) { + close(wm->out_sock); + wm->out_sock = -1; + return 0; + } + + addr.l2_psm = htobs(WM_INPUT_CHANNEL); + + /* connect to wiimote */ + if (connect(wm->in_sock, (struct sockaddr*)&addr, sizeof(addr)) < 0) { + perror("connect() interrupt sock"); + close(wm->out_sock); + wm->out_sock = -1; + return 0; + } + + WIIUSE_INFO("Connected to wiimote [id %i].", wm->unid); + + /* do the handshake */ + WIIMOTE_ENABLE_STATE(wm, WIIMOTE_STATE_CONNECTED); + wiiuse_handshake(wm, NULL, 0); + + wiiuse_set_report_type(wm); + + return 1; +} + + +/** + * @brief Disconnect a wiimote. + * + * @param wm Pointer to a wiimote_t structure. + * + * @see wiiuse_connect() + * + * Note that this will not free the wiimote structure. + */ +void wiiuse_disconnect(struct wiimote_t* wm) { + if (!wm || WIIMOTE_IS_CONNECTED(wm)) + return; + + close(wm->out_sock); + close(wm->in_sock); + + wm->out_sock = -1; + wm->in_sock = -1; + wm->event = WIIUSE_NONE; + + WIIMOTE_DISABLE_STATE(wm, WIIMOTE_STATE_CONNECTED); + WIIMOTE_DISABLE_STATE(wm, WIIMOTE_STATE_HANDSHAKE); +} + + +int wiiuse_io_read(struct wiimote_t* wm) { + /* not used */ + return 0; +} + + +int wiiuse_io_write(struct wiimote_t* wm, byte* buf, int len) { + return write(wm->out_sock, buf, len); +} + + + +#endif /* ifndef WIN32 */ diff --git a/tools/EventClients/Clients/WiiRemote/wiiuse_v0.12/src/io_win.c b/tools/EventClients/Clients/WiiRemote/wiiuse_v0.12/src/io_win.c new file mode 100644 index 0000000..6aeeb81 --- /dev/null +++ b/tools/EventClients/Clients/WiiRemote/wiiuse_v0.12/src/io_win.c @@ -0,0 +1,247 @@ +/* + * wiiuse + * + * Written By: + * Michael Laforest < para > + * Email: < thepara (--AT--) g m a i l [--DOT--] com > + * + * Copyright 2006-2007 + * + * This file is part of wiiuse. + * + * 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 3 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, see <http://www.gnu.org/licenses/>. + * + * $Header$ + * + */ + +/** + * @file + * @brief Handles device I/O for Windows. + */ + +#ifdef WIN32 + +#include <stdio.h> +#include <stdlib.h> + +#include <windows.h> +#include <hidsdi.h> +#include <setupapi.h> + +#include "definitions.h" +#include "wiiuse_internal.h" +#include "io.h" + + +int wiiuse_find(struct wiimote_t** wm, int max_wiimotes, int timeout) { + GUID device_id; + HANDLE dev; + HDEVINFO device_info; + int i, index; + DWORD len; + SP_DEVICE_INTERFACE_DATA device_data; + PSP_DEVICE_INTERFACE_DETAIL_DATA detail_data = NULL; + HIDD_ATTRIBUTES attr; + int found = 0; + + (void) timeout; // unused + + device_data.cbSize = sizeof(device_data); + index = 0; + + /* get the device id */ + HidD_GetHidGuid(&device_id); + + /* get all hid devices connected */ + device_info = SetupDiGetClassDevs(&device_id, NULL, NULL, (DIGCF_DEVICEINTERFACE | DIGCF_PRESENT)); + + for (;; ++index) { + + if (detail_data) { + free(detail_data); + detail_data = NULL; + } + + /* query the next hid device info */ + if (!SetupDiEnumDeviceInterfaces(device_info, NULL, &device_id, index, &device_data)) + break; + + /* get the size of the data block required */ + i = SetupDiGetDeviceInterfaceDetail(device_info, &device_data, NULL, 0, &len, NULL); + detail_data = malloc(len); + detail_data->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA); + + /* query the data for this device */ + if (!SetupDiGetDeviceInterfaceDetail(device_info, &device_data, detail_data, len, NULL, NULL)) + continue; + + /* open the device */ + dev = CreateFile(detail_data->DevicePath, + (GENERIC_READ | GENERIC_WRITE), + (FILE_SHARE_READ | FILE_SHARE_WRITE), + NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL); + if (dev == INVALID_HANDLE_VALUE) + continue; + + /* get device attributes */ + attr.Size = sizeof(attr); + i = HidD_GetAttributes(dev, &attr); + + if ((attr.VendorID == WM_VENDOR_ID) && (attr.ProductID == WM_PRODUCT_ID)) { + /* this is a wiimote */ + wm[found]->dev_handle = dev; + + wm[found]->hid_overlap.hEvent = CreateEvent(NULL, 1, 1, ""); + wm[found]->hid_overlap.Offset = 0; + wm[found]->hid_overlap.OffsetHigh = 0; + + WIIMOTE_ENABLE_STATE(wm[found], WIIMOTE_STATE_DEV_FOUND); + WIIMOTE_ENABLE_STATE(wm[found], WIIMOTE_STATE_CONNECTED); + + /* try to set the output report to see if the device is actually connected */ + if (!wiiuse_set_report_type(wm[found])) { + WIIMOTE_DISABLE_STATE(wm[found], WIIMOTE_STATE_CONNECTED); + continue; + } + + /* do the handshake */ + wiiuse_handshake(wm[found], NULL, 0); + + WIIUSE_INFO("Connected to wiimote [id %i].", wm[found]->unid); + + ++found; + if (found >= max_wiimotes) + break; + } else { + /* not a wiimote */ + CloseHandle(dev); + } + } + + if (detail_data) + free(detail_data); + + SetupDiDestroyDeviceInfoList(device_info); + + return found; +} + + +int wiiuse_connect(struct wiimote_t** wm, int wiimotes) { + int connected = 0; + int i = 0; + + for (; i < wiimotes; ++i) { + if (WIIMOTE_IS_SET(wm[i], WIIMOTE_STATE_CONNECTED)) + ++connected; + } + + return connected; +} + + +void wiiuse_disconnect(struct wiimote_t* wm) { + if (!wm || WIIMOTE_IS_CONNECTED(wm)) + return; + + CloseHandle(wm->dev_handle); + wm->dev_handle = 0; + + ResetEvent(&wm->hid_overlap); + + wm->event = WIIUSE_NONE; + + WIIMOTE_DISABLE_STATE(wm, WIIMOTE_STATE_CONNECTED); + WIIMOTE_DISABLE_STATE(wm, WIIMOTE_STATE_HANDSHAKE); +} + + +int wiiuse_io_read(struct wiimote_t* wm) { + DWORD b, r; + + if (!wm || !WIIMOTE_IS_CONNECTED(wm)) + return 0; + + if (!ReadFile(wm->dev_handle, wm->event_buf, sizeof(wm->event_buf), &b, &wm->hid_overlap)) { + /* partial read */ + b = GetLastError(); + + if ((b == ERROR_HANDLE_EOF) || (b == ERROR_DEVICE_NOT_CONNECTED)) { + /* remote disconnect */ + wiiuse_disconnected(wm); + return 0; + } + + r = WaitForSingleObject(wm->hid_overlap.hEvent, wm->timeout); + if (r == WAIT_TIMEOUT) { + /* timeout - cancel and continue */ + + if (*wm->event_buf) + WIIUSE_WARNING("Packet ignored. This may indicate a problem (timeout is %i ms).", wm->timeout); + + CancelIo(wm->dev_handle); + ResetEvent(wm->hid_overlap.hEvent); + return 0; + } else if (r == WAIT_FAILED) { + WIIUSE_WARNING("A wait error occurred on reading from wiimote %i.", wm->unid); + return 0; + } + + if (!GetOverlappedResult(wm->dev_handle, &wm->hid_overlap, &b, 0)) + return 0; + } + + ResetEvent(wm->hid_overlap.hEvent); + return 1; +} + + +int wiiuse_io_write(struct wiimote_t* wm, byte* buf, int len) { + DWORD bytes; + int i; + + if (!wm || !WIIMOTE_IS_CONNECTED(wm)) + return 0; + + switch (wm->stack) { + case WIIUSE_STACK_UNKNOWN: + { + /* try to auto-detect the stack type */ + if (i = WriteFile(wm->dev_handle, buf, 22, &bytes, &wm->hid_overlap)) { + /* bluesoleil will always return 1 here, even if it's not connected */ + wm->stack = WIIUSE_STACK_BLUESOLEIL; + return i; + } + + if (i = HidD_SetOutputReport(wm->dev_handle, buf, len)) { + wm->stack = WIIUSE_STACK_MS; + return i; + } + + WIIUSE_ERROR("Unable to determine bluetooth stack type."); + return 0; + } + + case WIIUSE_STACK_MS: + return HidD_SetOutputReport(wm->dev_handle, buf, len); + + case WIIUSE_STACK_BLUESOLEIL: + return WriteFile(wm->dev_handle, buf, 22, &bytes, &wm->hid_overlap); + } + + return 0; +} + +#endif /* ifdef WIN32 */ diff --git a/tools/EventClients/Clients/WiiRemote/wiiuse_v0.12/src/ir.c b/tools/EventClients/Clients/WiiRemote/wiiuse_v0.12/src/ir.c new file mode 100644 index 0000000..7a9bb68 --- /dev/null +++ b/tools/EventClients/Clients/WiiRemote/wiiuse_v0.12/src/ir.c @@ -0,0 +1,748 @@ +/* + * wiiuse + * + * Written By: + * Michael Laforest < para > + * Email: < thepara (--AT--) g m a i l [--DOT--] com > + * + * Copyright 2006-2007 + * + * This file is part of wiiuse. + * + * 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 3 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, see <http://www.gnu.org/licenses/>. + * + * $Header$ + * + */ + +/** + * @file + * @brief Handles IR data. + */ + +#include <stdio.h> +#include <math.h> + +#ifndef WIN32 + #include <unistd.h> +#endif + +#include "definitions.h" +#include "wiiuse_internal.h" +#include "ir.h" + +static int get_ir_sens(struct wiimote_t* wm, char** block1, char** block2); +static void interpret_ir_data(struct wiimote_t* wm); +static void fix_rotated_ir_dots(struct ir_dot_t* dot, float ang); +static void get_ir_dot_avg(struct ir_dot_t* dot, int* x, int* y); +static void reorder_ir_dots(struct ir_dot_t* dot); +static float ir_distance(struct ir_dot_t* dot); +static int ir_correct_for_bounds(int* x, int* y, enum aspect_t aspect, int offset_x, int offset_y); +static void ir_convert_to_vres(int* x, int* y, enum aspect_t aspect, int vx, int vy); + + +/** + * @brief Set if the wiimote should track IR targets. + * + * @param wm Pointer to a wiimote_t structure. + * @param status 1 to enable, 0 to disable. + */ +void wiiuse_set_ir(struct wiimote_t* wm, int status) { + byte buf; + char* block1 = NULL; + char* block2 = NULL; + int ir_level; + + if (!wm) + return; + + /* + * Wait for the handshake to finish first. + * When it handshake finishes and sees that + * IR is enabled, it will call this function + * again to actually enable IR. + */ + if (!WIIMOTE_IS_SET(wm, WIIMOTE_STATE_HANDSHAKE_COMPLETE)) { + WIIUSE_DEBUG("Tried to enable IR, will wait until handshake finishes."); + WIIMOTE_ENABLE_STATE(wm, WIIMOTE_STATE_IR); + return; + } + + /* + * Check to make sure a sensitivity setting is selected. + */ + ir_level = get_ir_sens(wm, &block1, &block2); + if (!ir_level) { + WIIUSE_ERROR("No IR sensitivity setting selected."); + return; + } + + if (status) { + /* if already enabled then stop */ + if (WIIMOTE_IS_SET(wm, WIIMOTE_STATE_IR)) + return; + WIIMOTE_ENABLE_STATE(wm, WIIMOTE_STATE_IR); + } else { + /* if already disabled then stop */ + if (!WIIMOTE_IS_SET(wm, WIIMOTE_STATE_IR)) + return; + WIIMOTE_DISABLE_STATE(wm, WIIMOTE_STATE_IR); + } + + /* set camera 1 and 2 */ + buf = (status ? 0x04 : 0x00); + wiiuse_send(wm, WM_CMD_IR, &buf, 1); + wiiuse_send(wm, WM_CMD_IR_2, &buf, 1); + + if (!status) { + WIIUSE_DEBUG("Disabled IR cameras for wiimote id %i.", wm->unid); + wiiuse_set_report_type(wm); + return; + } + + /* enable IR, set sensitivity */ + buf = 0x08; + wiiuse_write_data(wm, WM_REG_IR, &buf, 1); + + /* wait for the wiimote to catch up */ + #ifndef WIN32 + usleep(50000); + #else + Sleep(50); + #endif + + /* write sensitivity blocks */ + wiiuse_write_data(wm, WM_REG_IR_BLOCK1, (byte*)block1, 9); + wiiuse_write_data(wm, WM_REG_IR_BLOCK2, (byte*)block2, 2); + + /* set the IR mode */ + if (WIIMOTE_IS_SET(wm, WIIMOTE_STATE_EXP)) + buf = WM_IR_TYPE_BASIC; + else + buf = WM_IR_TYPE_EXTENDED; + wiiuse_write_data(wm, WM_REG_IR_MODENUM, &buf, 1); + + #ifndef WIN32 + usleep(50000); + #else + Sleep(50); + #endif + + /* set the wiimote report type */ + wiiuse_set_report_type(wm); + + WIIUSE_DEBUG("Enabled IR camera for wiimote id %i (sensitivity level %i).", wm->unid, ir_level); +} + + +/** + * @brief Get the IR sensitivity settings. + * + * @param wm Pointer to a wiimote_t structure. + * @param block1 [out] Pointer to where block1 will be set. + * @param block2 [out] Pointer to where block2 will be set. + * + * @return Returns the sensitivity level. + */ +static int get_ir_sens(struct wiimote_t* wm, char** block1, char** block2) { + if (WIIMOTE_IS_SET(wm, WIIMOTE_STATE_IR_SENS_LVL1)) { + *block1 = WM_IR_BLOCK1_LEVEL1; + *block2 = WM_IR_BLOCK2_LEVEL1; + return 1; + } else if (WIIMOTE_IS_SET(wm, WIIMOTE_STATE_IR_SENS_LVL2)) { + *block1 = WM_IR_BLOCK1_LEVEL2; + *block2 = WM_IR_BLOCK2_LEVEL2; + return 2; + } else if (WIIMOTE_IS_SET(wm, WIIMOTE_STATE_IR_SENS_LVL3)) { + *block1 = WM_IR_BLOCK1_LEVEL3; + *block2 = WM_IR_BLOCK2_LEVEL3; + return 3; + } else if (WIIMOTE_IS_SET(wm, WIIMOTE_STATE_IR_SENS_LVL4)) { + *block1 = WM_IR_BLOCK1_LEVEL4; + *block2 = WM_IR_BLOCK2_LEVEL4; + return 4; + } else if (WIIMOTE_IS_SET(wm, WIIMOTE_STATE_IR_SENS_LVL5)) { + *block1 = WM_IR_BLOCK1_LEVEL5; + *block2 = WM_IR_BLOCK2_LEVEL5; + return 5; + } + + *block1 = NULL; + *block2 = NULL; + return 0; +} + + +/** + * @brief Set the virtual screen resolution for IR tracking. + * + * @param wm Pointer to a wiimote_t structure. + * @param status 1 to enable, 0 to disable. + */ +void wiiuse_set_ir_vres(struct wiimote_t* wm, unsigned int x, unsigned int y) { + if (!wm) return; + + wm->ir.vres[0] = (x-1); + wm->ir.vres[1] = (y-1); +} + + +/** + * @brief Set the XY position for the IR cursor. + * + * @param wm Pointer to a wiimote_t structure. + */ +void wiiuse_set_ir_position(struct wiimote_t* wm, enum ir_position_t pos) { + if (!wm) return; + + wm->ir.pos = pos; + + switch (pos) { + + case WIIUSE_IR_ABOVE: + wm->ir.offset[0] = 0; + + if (wm->ir.aspect == WIIUSE_ASPECT_16_9) + wm->ir.offset[1] = WM_ASPECT_16_9_Y/2 - 70; + else if (wm->ir.aspect == WIIUSE_ASPECT_4_3) + wm->ir.offset[1] = WM_ASPECT_4_3_Y/2 - 100; + + return; + + case WIIUSE_IR_BELOW: + wm->ir.offset[0] = 0; + + if (wm->ir.aspect == WIIUSE_ASPECT_16_9) + wm->ir.offset[1] = -WM_ASPECT_16_9_Y/2 + 100; + else if (wm->ir.aspect == WIIUSE_ASPECT_4_3) + wm->ir.offset[1] = -WM_ASPECT_4_3_Y/2 + 70; + + return; + + default: + return; + }; +} + + +/** + * @brief Set the aspect ratio of the TV/monitor. + * + * @param wm Pointer to a wiimote_t structure. + * @param aspect Either WIIUSE_ASPECT_16_9 or WIIUSE_ASPECT_4_3 + */ +void wiiuse_set_aspect_ratio(struct wiimote_t* wm, enum aspect_t aspect) { + if (!wm) return; + + wm->ir.aspect = aspect; + + if (aspect == WIIUSE_ASPECT_4_3) { + wm->ir.vres[0] = WM_ASPECT_4_3_X; + wm->ir.vres[1] = WM_ASPECT_4_3_Y; + } else { + wm->ir.vres[0] = WM_ASPECT_16_9_X; + wm->ir.vres[1] = WM_ASPECT_16_9_Y; + } + + /* reset the position offsets */ + wiiuse_set_ir_position(wm, wm->ir.pos); +} + + +/** + * @brief Set the IR sensitivity. + * + * @param wm Pointer to a wiimote_t structure. + * @param level 1-5, same as Wii system sensitivity setting. + * + * If the level is < 1, then level will be set to 1. + * If the level is > 5, then level will be set to 5. + */ +void wiiuse_set_ir_sensitivity(struct wiimote_t* wm, int level) { + char* block1 = NULL; + char* block2 = NULL; + + if (!wm) return; + + if (level > 5) level = 5; + if (level < 1) level = 1; + + WIIMOTE_DISABLE_STATE(wm, (WIIMOTE_STATE_IR_SENS_LVL1 | + WIIMOTE_STATE_IR_SENS_LVL2 | + WIIMOTE_STATE_IR_SENS_LVL3 | + WIIMOTE_STATE_IR_SENS_LVL4 | + WIIMOTE_STATE_IR_SENS_LVL5)); + + switch (level) { + case 1: + WIIMOTE_ENABLE_STATE(wm, WIIMOTE_STATE_IR_SENS_LVL1); + break; + case 2: + WIIMOTE_ENABLE_STATE(wm, WIIMOTE_STATE_IR_SENS_LVL2); + break; + case 3: + WIIMOTE_ENABLE_STATE(wm, WIIMOTE_STATE_IR_SENS_LVL3); + break; + case 4: + WIIMOTE_ENABLE_STATE(wm, WIIMOTE_STATE_IR_SENS_LVL4); + break; + case 5: + WIIMOTE_ENABLE_STATE(wm, WIIMOTE_STATE_IR_SENS_LVL5); + break; + default: + return; + } + + /* set the new sensitivity */ + get_ir_sens(wm, &block1, &block2); + + wiiuse_write_data(wm, WM_REG_IR_BLOCK1, (byte*)block1, 9); + wiiuse_write_data(wm, WM_REG_IR_BLOCK2, (byte*)block2, 2); + + WIIUSE_DEBUG("Set IR sensitivity to level %i (unid %i)", level, wm->unid); +} + + +/** + * @brief Calculate the data from the IR spots. Basic IR mode. + * + * @param wm Pointer to a wiimote_t structure. + * @param data Data returned by the wiimote for the IR spots. + */ +void calculate_basic_ir(struct wiimote_t* wm, byte* data) { + struct ir_dot_t* dot = wm->ir.dot; + int i; + + dot[0].rx = 1023 - (data[0] | ((data[2] & 0x30) << 4)); + dot[0].ry = data[1] | ((data[2] & 0xC0) << 2); + + dot[1].rx = 1023 - (data[3] | ((data[2] & 0x03) << 8)); + dot[1].ry = data[4] | ((data[2] & 0x0C) << 6); + + dot[2].rx = 1023 - (data[5] | ((data[7] & 0x30) << 4)); + dot[2].ry = data[6] | ((data[7] & 0xC0) << 2); + + dot[3].rx = 1023 - (data[8] | ((data[7] & 0x03) << 8)); + dot[3].ry = data[9] | ((data[7] & 0x0C) << 6); + + /* set each IR spot to visible if spot is in range */ + for (i = 0; i < 4; ++i) { + if (dot[i].ry == 1023) + dot[i].visible = 0; + else { + dot[i].visible = 1; + dot[i].size = 0; /* since we don't know the size, set it as 0 */ + } + } + + interpret_ir_data(wm); +} + + +/** + * @brief Calculate the data from the IR spots. Extended IR mode. + * + * @param wm Pointer to a wiimote_t structure. + * @param data Data returned by the wiimote for the IR spots. + */ +void calculate_extended_ir(struct wiimote_t* wm, byte* data) { + struct ir_dot_t* dot = wm->ir.dot; + int i; + + for (i = 0; i < 4; ++i) { + dot[i].rx = 1023 - (data[3*i] | ((data[(3*i)+2] & 0x30) << 4)); + dot[i].ry = data[(3*i)+1] | ((data[(3*i)+2] & 0xC0) << 2); + + dot[i].size = data[(3*i)+2] & 0x0F; + + /* if in range set to visible */ + if (dot[i].ry == 1023) + dot[i].visible = 0; + else + dot[i].visible = 1; + } + + interpret_ir_data(wm); +} + + +/** + * @brief Interpret IR data into more user friendly variables. + * + * @param wm Pointer to a wiimote_t structure. + */ +static void interpret_ir_data(struct wiimote_t* wm) { + struct ir_dot_t* dot = wm->ir.dot; + int i; + float roll = 0.0f; + int last_num_dots = wm->ir.num_dots; + + if (WIIMOTE_IS_SET(wm, WIIMOTE_STATE_ACC)) + roll = wm->orient.roll; + + /* count visible dots */ + wm->ir.num_dots = 0; + for (i = 0; i < 4; ++i) { + if (dot[i].visible) + wm->ir.num_dots++; + } + + switch (wm->ir.num_dots) { + case 0: + { + wm->ir.state = 0; + + /* reset the dot ordering */ + for (i = 0; i < 4; ++i) + dot[i].order = 0; + + wm->ir.x = 0; + wm->ir.y = 0; + wm->ir.z = 0.0f; + + return; + } + case 1: + { + fix_rotated_ir_dots(wm->ir.dot, roll); + + if (wm->ir.state < 2) { + /* + * Only 1 known dot, so use just that. + */ + for (i = 0; i < 4; ++i) { + if (dot[i].visible) { + wm->ir.x = dot[i].x; + wm->ir.y = dot[i].y; + + wm->ir.ax = wm->ir.x; + wm->ir.ay = wm->ir.y; + + /* can't calculate yaw because we don't have the distance */ + //wm->orient.yaw = calc_yaw(&wm->ir); + + ir_convert_to_vres(&wm->ir.x, &wm->ir.y, wm->ir.aspect, wm->ir.vres[0], wm->ir.vres[1]); + break; + } + } + } else { + /* + * Only see 1 dot but know theres 2. + * Try to estimate where the other one + * should be and use that. + */ + for (i = 0; i < 4; ++i) { + if (dot[i].visible) { + int ox = 0; + int x, y; + + if (dot[i].order == 1) + /* visible is the left dot - estimate where the right is */ + ox = dot[i].x + wm->ir.distance; + else if (dot[i].order == 2) + /* visible is the right dot - estimate where the left is */ + ox = dot[i].x - wm->ir.distance; + + x = ((signed int)dot[i].x + ox) / 2; + y = dot[i].y; + + wm->ir.ax = x; + wm->ir.ay = y; + wm->orient.yaw = calc_yaw(&wm->ir); + + if (ir_correct_for_bounds(&x, &y, wm->ir.aspect, wm->ir.offset[0], wm->ir.offset[1])) { + ir_convert_to_vres(&x, &y, wm->ir.aspect, wm->ir.vres[0], wm->ir.vres[1]); + wm->ir.x = x; + wm->ir.y = y; + } + + break; + } + } + } + + break; + } + case 2: + case 3: + case 4: + { + /* + * Two (or more) dots known and seen. + * Average them together to estimate the true location. + */ + int x, y; + wm->ir.state = 2; + + fix_rotated_ir_dots(wm->ir.dot, roll); + + /* if there is at least 1 new dot, reorder them all */ + if (wm->ir.num_dots > last_num_dots) { + reorder_ir_dots(dot); + wm->ir.x = 0; + wm->ir.y = 0; + } + + wm->ir.distance = ir_distance(dot); + wm->ir.z = 1023 - wm->ir.distance; + + get_ir_dot_avg(wm->ir.dot, &x, &y); + + wm->ir.ax = x; + wm->ir.ay = y; + wm->orient.yaw = calc_yaw(&wm->ir); + + if (ir_correct_for_bounds(&x, &y, wm->ir.aspect, wm->ir.offset[0], wm->ir.offset[1])) { + ir_convert_to_vres(&x, &y, wm->ir.aspect, wm->ir.vres[0], wm->ir.vres[1]); + wm->ir.x = x; + wm->ir.y = y; + } + + break; + } + default: + { + break; + } + } + + #ifdef WITH_WIIUSE_DEBUG + { + int ir_level; + WIIUSE_GET_IR_SENSITIVITY(wm, &ir_level); + WIIUSE_DEBUG("IR sensitivity: %i", ir_level); + WIIUSE_DEBUG("IR visible dots: %i", wm->ir.num_dots); + for (i = 0; i < 4; ++i) + if (dot[i].visible) + WIIUSE_DEBUG("IR[%i][order %i] (%.3i, %.3i) -> (%.3i, %.3i)", i, dot[i].order, dot[i].rx, dot[i].ry, dot[i].x, dot[i].y); + WIIUSE_DEBUG("IR[absolute]: (%i, %i)", wm->ir.x, wm->ir.y); + } + #endif +} + + + +/** + * @brief Fix the rotation of the IR dots. + * + * @param dot An array of 4 ir_dot_t objects. + * @param ang The roll angle to correct by (-180, 180) + * + * If there is roll then the dots are rotated + * around the origin and give a false cursor + * position. Correct for the roll. + * + * If the accelerometer is off then obviously + * this will not do anything and the cursor + * position may be inaccurate. + */ +static void fix_rotated_ir_dots(struct ir_dot_t* dot, float ang) { + float s, c; + int x, y; + int i; + + if (!ang) { + for (i = 0; i < 4; ++i) { + dot[i].x = dot[i].rx; + dot[i].y = dot[i].ry; + } + return; + } + + s = sin(DEGREE_TO_RAD(ang)); + c = cos(DEGREE_TO_RAD(ang)); + + /* + * [ cos(theta) -sin(theta) ][ ir->rx ] + * [ sin(theta) cos(theta) ][ ir->ry ] + */ + + for (i = 0; i < 4; ++i) { + if (!dot[i].visible) + continue; + + x = dot[i].rx - (1024/2); + y = dot[i].ry - (768/2); + + dot[i].x = (c * x) + (-s * y); + dot[i].y = (s * x) + (c * y); + + dot[i].x += (1024/2); + dot[i].y += (768/2); + } +} + + +/** + * @brief Average IR dots. + * + * @param dot An array of 4 ir_dot_t objects. + * @param x [out] Average X + * @param y [out] Average Y + */ +static void get_ir_dot_avg(struct ir_dot_t* dot, int* x, int* y) { + int vis = 0, i = 0; + + *x = 0; + *y = 0; + + for (; i < 4; ++i) { + if (dot[i].visible) { + *x += dot[i].x; + *y += dot[i].y; + ++vis; + } + } + + *x /= vis; + *y /= vis; +} + + +/** + * @brief Reorder the IR dots. + * + * @param dot An array of 4 ir_dot_t objects. + */ +static void reorder_ir_dots(struct ir_dot_t* dot) { + int i, j, order; + + /* reset the dot ordering */ + for (i = 0; i < 4; ++i) + dot[i].order = 0; + + for (order = 1; order < 5; ++order) { + i = 0; + + for (; !dot[i].visible || dot[i].order; ++i) + if (i > 4) + return; + + for (j = 0; j < 4; ++j) { + if (dot[j].visible && !dot[j].order && (dot[j].x < dot[i].x)) + i = j; + } + + dot[i].order = order; + } +} + + +/** + * @brief Calculate the distance between the first 2 visible IR dots. + * + * @param dot An array of 4 ir_dot_t objects. + */ +static float ir_distance(struct ir_dot_t* dot) { + int i1, i2; + int xd, yd; + + for (i1 = 0; i1 < 4; ++i1) + if (dot[i1].visible) + break; + if (i1 == 4) + return 0.0f; + + for (i2 = i1+1; i2 < 4; ++i2) + if (dot[i2].visible) + break; + if (i2 == 4) + return 0.0f; + + xd = dot[i2].x - dot[i1].x; + yd = dot[i2].y - dot[i1].y; + + return sqrt(xd*xd + yd*yd); +} + + +/** + * @brief Correct for the IR bounding box. + * + * @param x [out] The current X, it will be updated if valid. + * @param y [out] The current Y, it will be updated if valid. + * @param aspect Aspect ratio of the screen. + * @param offset_x The X offset of the bounding box. + * @param offset_y The Y offset of the bounding box. + * + * @return Returns 1 if the point is valid and was updated. + * + * Nintendo was smart with this bit. They sacrifice a little + * precision for a big increase in usability. + */ +static int ir_correct_for_bounds(int* x, int* y, enum aspect_t aspect, int offset_x, int offset_y) { + int x0, y0; + int xs, ys; + + if (aspect == WIIUSE_ASPECT_16_9) { + xs = WM_ASPECT_16_9_X; + ys = WM_ASPECT_16_9_Y; + } else { + xs = WM_ASPECT_4_3_X; + ys = WM_ASPECT_4_3_Y; + } + + x0 = ((1024 - xs) / 2) + offset_x; + y0 = ((768 - ys) / 2) + offset_y; + + if ((*x >= x0) + && (*x <= (x0 + xs)) + && (*y >= y0) + && (*y <= (y0 + ys))) + { + *x -= offset_x; + *y -= offset_y; + + return 1; + } + + return 0; +} + + +/** + * @brief Interpolate the point to the user defined virtual screen resolution. + */ +static void ir_convert_to_vres(int* x, int* y, enum aspect_t aspect, int vx, int vy) { + int xs, ys; + + if (aspect == WIIUSE_ASPECT_16_9) { + xs = WM_ASPECT_16_9_X; + ys = WM_ASPECT_16_9_Y; + } else { + xs = WM_ASPECT_4_3_X; + ys = WM_ASPECT_4_3_Y; + } + + *x -= ((1024-xs)/2); + *y -= ((768-ys)/2); + + *x = (*x / (float)xs) * vx; + *y = (*y / (float)ys) * vy; +} + + +/** + * @brief Calculate yaw given the IR data. + * + * @param ir IR data structure. + */ +float calc_yaw(struct ir_t* ir) { + float x; + + x = ir->ax - 512; + x = x * (ir->z / 1024.0f); + + return RAD_TO_DEGREE( atanf(x / ir->z) ); +} diff --git a/tools/EventClients/Clients/WiiRemote/wiiuse_v0.12/src/ir.h b/tools/EventClients/Clients/WiiRemote/wiiuse_v0.12/src/ir.h new file mode 100644 index 0000000..1b9c5c0 --- /dev/null +++ b/tools/EventClients/Clients/WiiRemote/wiiuse_v0.12/src/ir.h @@ -0,0 +1,52 @@ +/* + * wiiuse + * + * Written By: + * Michael Laforest < para > + * Email: < thepara (--AT--) g m a i l [--DOT--] com > + * + * Copyright 2006-2007 + * + * This file is part of wiiuse. + * + * 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 3 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, see <http://www.gnu.org/licenses/>. + * + * $Header$ + * + */ + +/** + * @file + * @brief Handles IR data. + */ + +#pragma once + +#include "wiiuse_internal.h" + +#define WII_VRES_X 560 +#define WII_VRES_Y 340 + +#ifdef __cplusplus +extern "C" { +#endif + +void calculate_basic_ir(struct wiimote_t* wm, byte* data); +void calculate_extended_ir(struct wiimote_t* wm, byte* data); +float calc_yaw(struct ir_t* ir); + +#ifdef __cplusplus +} +#endif + diff --git a/tools/EventClients/Clients/WiiRemote/wiiuse_v0.12/src/msvc/wiiuse.dsp b/tools/EventClients/Clients/WiiRemote/wiiuse_v0.12/src/msvc/wiiuse.dsp new file mode 100644 index 0000000..d51562a --- /dev/null +++ b/tools/EventClients/Clients/WiiRemote/wiiuse_v0.12/src/msvc/wiiuse.dsp @@ -0,0 +1,191 @@ +# Microsoft Developer Studio Project File - Name="wiiuse" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102 + +CFG=wiiuse - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "wiiuse.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "wiiuse.mak" CFG="wiiuse - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "wiiuse - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "wiiuse - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +MTL=midl.exe +RSC=rc.exe + +!IF "$(CFG)" == "wiiuse - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "WIIUSE_EXPORTS" /YX /FD /c +# ADD CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "WIIUSE_EXPORTS" /YX /FD /c +# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib Ws2_32.lib hid.lib setupapi.lib /nologo /dll /machine:I386 + +!ELSEIF "$(CFG)" == "wiiuse - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "WIIUSE_EXPORTS" /YX /FD /GZ /c +# ADD CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "WIIUSE_EXPORTS" /D "WITH_WIIUSE_DEBUG" /YX /FD /GZ /c +# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib Ws2_32.lib hid.lib setupapi.lib /nologo /dll /debug /machine:I386 /pdbtype:sept + +!ENDIF + +# Begin Target + +# Name "wiiuse - Win32 Release" +# Name "wiiuse - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=..\classic.c +# End Source File +# Begin Source File + +SOURCE=..\dynamics.c +# End Source File +# Begin Source File + +SOURCE=..\events.c +# End Source File +# Begin Source File + +SOURCE=..\guitar_hero_3.c +# End Source File +# Begin Source File + +SOURCE=..\io.c +# End Source File +# Begin Source File + +SOURCE=..\io_nix.c +# End Source File +# Begin Source File + +SOURCE=..\io_win.c +# End Source File +# Begin Source File + +SOURCE=..\ir.c +# End Source File +# Begin Source File + +SOURCE=..\nunchuk.c +# End Source File +# Begin Source File + +SOURCE=..\wiiuse.c +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=..\classic.h +# End Source File +# Begin Source File + +SOURCE=..\definitions.h +# End Source File +# Begin Source File + +SOURCE=..\dynamics.h +# End Source File +# Begin Source File + +SOURCE=..\events.h +# End Source File +# Begin Source File + +SOURCE=..\guitar_hero_3.h +# End Source File +# Begin Source File + +SOURCE=..\io.h +# End Source File +# Begin Source File + +SOURCE=..\ir.h +# End Source File +# Begin Source File + +SOURCE=..\nunchuk.h +# End Source File +# Begin Source File + +SOURCE=..\os.h +# End Source File +# Begin Source File + +SOURCE=..\wiiuse.h +# End Source File +# Begin Source File + +SOURCE=..\wiiuse_internal.h +# End Source File +# End Group +# Begin Group "Resource Files" + +# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" +# Begin Source File + +SOURCE=..\..\CHANGELOG +# End Source File +# End Group +# End Target +# End Project diff --git a/tools/EventClients/Clients/WiiRemote/wiiuse_v0.12/src/msvc/wiiuse.dsw b/tools/EventClients/Clients/WiiRemote/wiiuse_v0.12/src/msvc/wiiuse.dsw new file mode 100644 index 0000000..1983225 --- /dev/null +++ b/tools/EventClients/Clients/WiiRemote/wiiuse_v0.12/src/msvc/wiiuse.dsw @@ -0,0 +1,29 @@ +Microsoft Developer Studio Workspace File, Format Version 6.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "wiiuse"=".\wiiuse.dsp" - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + diff --git a/tools/EventClients/Clients/WiiRemote/wiiuse_v0.12/src/msvc/wiiuse.opt b/tools/EventClients/Clients/WiiRemote/wiiuse_v0.12/src/msvc/wiiuse.opt Binary files differnew file mode 100644 index 0000000..b6ebe4c --- /dev/null +++ b/tools/EventClients/Clients/WiiRemote/wiiuse_v0.12/src/msvc/wiiuse.opt diff --git a/tools/EventClients/Clients/WiiRemote/wiiuse_v0.12/src/nunchuk.c b/tools/EventClients/Clients/WiiRemote/wiiuse_v0.12/src/nunchuk.c new file mode 100644 index 0000000..fd763bc --- /dev/null +++ b/tools/EventClients/Clients/WiiRemote/wiiuse_v0.12/src/nunchuk.c @@ -0,0 +1,210 @@ +/* + * wiiuse + * + * Written By: + * Michael Laforest < para > + * Email: < thepara (--AT--) g m a i l [--DOT--] com > + * + * Copyright 2006-2007 + * + * This file is part of wiiuse. + * + * 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 3 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, see <http://www.gnu.org/licenses/>. + * + * $Header$ + * + */ + +/** + * @file + * @brief Nunchuk expansion device. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <math.h> + +#include "definitions.h" +#include "wiiuse_internal.h" +#include "dynamics.h" +#include "events.h" +#include "nunchuk.h" + +static void nunchuk_pressed_buttons(struct nunchuk_t* nc, byte now); + +/** + * @brief Handle the handshake data from the nunchuk. + * + * @param nc A pointer to a nunchuk_t structure. + * @param data The data read in from the device. + * @param len The length of the data block, in bytes. + * + * @return Returns 1 if handshake was successful, 0 if not. + */ +int nunchuk_handshake(struct wiimote_t* wm, struct nunchuk_t* nc, byte* data, unsigned short len) { + int i; + int offset = 0; + + nc->btns = 0; + nc->btns_held = 0; + nc->btns_released = 0; + + /* set the smoothing to the same as the wiimote */ + nc->flags = &wm->flags; + nc->accel_calib.st_alpha = wm->accel_calib.st_alpha; + + /* decrypt data */ + for (i = 0; i < len; ++i) + data[i] = (data[i] ^ 0x17) + 0x17; + + if (data[offset] == 0xFF) { + /* + * Sometimes the data returned here is not correct. + * This might happen because the wiimote is lagging + * behind our initialization sequence. + * To fix this just request the handshake again. + * + * Other times it's just the first 16 bytes are 0xFF, + * but since the next 16 bytes are the same, just use + * those. + */ + if (data[offset + 16] == 0xFF) { + /* get the calibration data */ + byte* handshake_buf = malloc(EXP_HANDSHAKE_LEN * sizeof(byte)); + + WIIUSE_DEBUG("Nunchuk handshake appears invalid, trying again."); + wiiuse_read_data_cb(wm, handshake_expansion, handshake_buf, WM_EXP_MEM_CALIBR, EXP_HANDSHAKE_LEN); + + return 0; + } else + offset += 16; + } + + nc->accel_calib.cal_zero.x = data[offset + 0]; + nc->accel_calib.cal_zero.y = data[offset + 1]; + nc->accel_calib.cal_zero.z = data[offset + 2]; + nc->accel_calib.cal_g.x = data[offset + 4]; + nc->accel_calib.cal_g.y = data[offset + 5]; + nc->accel_calib.cal_g.z = data[offset + 6]; + nc->js.max.x = data[offset + 8]; + nc->js.min.x = data[offset + 9]; + nc->js.center.x = data[offset + 10]; + nc->js.max.y = data[offset + 11]; + nc->js.min.y = data[offset + 12]; + nc->js.center.y = data[offset + 13]; + + /* default the thresholds to the same as the wiimote */ + nc->orient_threshold = wm->orient_threshold; + nc->accel_threshold = wm->accel_threshold; + + /* handshake done */ + wm->exp.type = EXP_NUNCHUK; + + #ifdef WIN32 + wm->timeout = WIIMOTE_DEFAULT_TIMEOUT; + #endif + + return 1; +} + + +/** + * @brief The nunchuk disconnected. + * + * @param nc A pointer to a nunchuk_t structure. + */ +void nunchuk_disconnected(struct nunchuk_t* nc) { + memset(nc, 0, sizeof(struct nunchuk_t)); +} + + + +/** + * @brief Handle nunchuk event. + * + * @param nc A pointer to a nunchuk_t structure. + * @param msg The message specified in the event packet. + */ +void nunchuk_event(struct nunchuk_t* nc, byte* msg) { + int i; + + /* decrypt data */ + for (i = 0; i < 6; ++i) + msg[i] = (msg[i] ^ 0x17) + 0x17; + + /* get button states */ + nunchuk_pressed_buttons(nc, msg[5]); + + /* calculate joystick state */ + calc_joystick_state(&nc->js, msg[0], msg[1]); + + /* calculate orientation */ + nc->accel.x = msg[2]; + nc->accel.y = msg[3]; + nc->accel.z = msg[4]; + + calculate_orientation(&nc->accel_calib, &nc->accel, &nc->orient, NUNCHUK_IS_FLAG_SET(nc, WIIUSE_SMOOTHING)); + calculate_gforce(&nc->accel_calib, &nc->accel, &nc->gforce); +} + + +/** + * @brief Find what buttons are pressed. + * + * @param nc Pointer to a nunchuk_t structure. + * @param msg The message byte specified in the event packet. + */ +static void nunchuk_pressed_buttons(struct nunchuk_t* nc, byte now) { + /* message is inverted (0 is active, 1 is inactive) */ + now = ~now & NUNCHUK_BUTTON_ALL; + + /* pressed now & were pressed, then held */ + nc->btns_held = (now & nc->btns); + + /* were pressed or were held & not pressed now, then released */ + nc->btns_released = ((nc->btns | nc->btns_held) & ~now); + + /* buttons pressed now */ + nc->btns = now; +} + + +/** + * @brief Set the orientation event threshold for the nunchuk. + * + * @param wm Pointer to a wiimote_t structure with a nunchuk attached. + * @param threshold The decimal place that should be considered a significant change. + * + * See wiiuse_set_orient_threshold() for details. + */ +void wiiuse_set_nunchuk_orient_threshold(struct wiimote_t* wm, float threshold) { + if (!wm) return; + + wm->exp.nunchuk.orient_threshold = threshold; +} + + +/** + * @brief Set the accelerometer event threshold for the nunchuk. + * + * @param wm Pointer to a wiimote_t structure with a nunchuk attached. + * @param threshold The decimal place that should be considered a significant change. + * + * See wiiuse_set_orient_threshold() for details. + */ +void wiiuse_set_nunchuk_accel_threshold(struct wiimote_t* wm, int threshold) { + if (!wm) return; + + wm->exp.nunchuk.accel_threshold = threshold; +} diff --git a/tools/EventClients/Clients/WiiRemote/wiiuse_v0.12/src/nunchuk.h b/tools/EventClients/Clients/WiiRemote/wiiuse_v0.12/src/nunchuk.h new file mode 100644 index 0000000..a3a2c63 --- /dev/null +++ b/tools/EventClients/Clients/WiiRemote/wiiuse_v0.12/src/nunchuk.h @@ -0,0 +1,51 @@ +/* + * wiiuse + * + * Written By: + * Michael Laforest < para > + * Email: < thepara (--AT--) g m a i l [--DOT--] com > + * + * Copyright 2006-2007 + * + * This file is part of wiiuse. + * + * 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 3 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, see <http://www.gnu.org/licenses/>. + * + * $Header$ + * + */ + +/** + * @file + * @brief Nunchuk expansion device. + */ + +#pragma once + +#include "wiiuse_internal.h" + +#ifdef __cplusplus +extern "C" { +#endif + +int nunchuk_handshake(struct wiimote_t* wm, struct nunchuk_t* nc, byte* data, unsigned short len); + +void nunchuk_disconnected(struct nunchuk_t* nc); + +void nunchuk_event(struct nunchuk_t* nc, byte* msg); + +#ifdef __cplusplus +} +#endif + diff --git a/tools/EventClients/Clients/WiiRemote/wiiuse_v0.12/src/os.h b/tools/EventClients/Clients/WiiRemote/wiiuse_v0.12/src/os.h new file mode 100644 index 0000000..3e99670 --- /dev/null +++ b/tools/EventClients/Clients/WiiRemote/wiiuse_v0.12/src/os.h @@ -0,0 +1,53 @@ +/* + * wiiuse + * + * Written By: + * Michael Laforest < para > + * Email: < thepara (--AT--) g m a i l [--DOT--] com > + * + * Copyright 2006-2007 + * + * This file is part of wiiuse. + * + * 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 3 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, see <http://www.gnu.org/licenses/>. + * + * $Header$ + * + */ + + +/** + * @file + * @brief Operating system related definitions. + * + * This file is an attempt to separate operating system + * dependent functions and choose what should be used + * at compile time. + */ + +#pragma once + +#ifdef WIN32 + /* windows */ + #define isnan(x) _isnan(x) + #define isinf(x) !_finite(x) + + /* disable warnings I don't care about */ + #pragma warning(disable:4244) /* possible loss of data conversion */ + #pragma warning(disable:4273) /* inconsistent dll linkage */ + #pragma warning(disable:4217) +#else + /* nix */ +#endif + diff --git a/tools/EventClients/Clients/WiiRemote/wiiuse_v0.12/src/wiiuse.c b/tools/EventClients/Clients/WiiRemote/wiiuse_v0.12/src/wiiuse.c new file mode 100644 index 0000000..1bb617d --- /dev/null +++ b/tools/EventClients/Clients/WiiRemote/wiiuse_v0.12/src/wiiuse.c @@ -0,0 +1,764 @@ +/* + * wiiuse + * + * Written By: + * Michael Laforest < para > + * Email: < thepara (--AT--) g m a i l [--DOT--] com > + * + * Copyright 2006-2007 + * + * This file is part of wiiuse. + * + * 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 3 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, see <http://www.gnu.org/licenses/>. + * + * $Header$ + * + */ + +/** + * @file + * @brief General wiimote operations. + * + * The file includes functions that handle general + * tasks. Most of these are functions that are part + * of the API. + */ + +#include <stdio.h> +#include <stdlib.h> + +#ifndef WIN32 + #include <unistd.h> +#else + #include <Winsock2.h> +#endif + +#include "definitions.h" +#include "wiiuse_internal.h" +#include "events.h" +#include "io.h" + +static int g_banner = 0; + +/** + * @breif Returns the version of the library. + */ +const char* wiiuse_version() { + return WIIUSE_VERSION; +} + + +/** + * @brief Clean up wiimote_t array created by wiiuse_init() + */ +void wiiuse_cleanup(struct wiimote_t** wm, int wiimotes) { + int i = 0; + + if (!wm) + return; + + WIIUSE_INFO("wiiuse clean up..."); + + for (; i < wiimotes; ++i) { + wiiuse_disconnect(wm[i]); + free(wm[i]); + } + + free(wm); + + return; +} + + +/** + * @brief Initialize an array of wiimote structures. + * + * @param wiimotes Number of wiimote_t structures to create. + * + * @return An array of initialized wiimote_t structures. + * + * @see wiiuse_connect() + * + * The array returned by this function can be passed to various + * functions, including wiiuse_connect(). + */ +struct wiimote_t** wiiuse_init(int wiimotes) { + int i = 0; + struct wiimote_t** wm = NULL; + + /* + * Please do not remove this banner. + * GPL asks that you please leave output credits intact. + * Thank you. + * + * This banner is only displayed once so that if you need + * to call this function again it won't be intrusive. + */ + if (!g_banner) { + printf( "wiiuse v" WIIUSE_VERSION " loaded.\n" + " By: Michael Laforest <thepara[at]gmail{dot}com>\n" + " http://wiiuse.net http://wiiuse.sf.net\n"); + g_banner = 1; + } + + if (!wiimotes) + return NULL; + + wm = malloc(sizeof(struct wiimote_t*) * wiimotes); + + for (i = 0; i < wiimotes; ++i) { + wm[i] = malloc(sizeof(struct wiimote_t)); + memset(wm[i], 0, sizeof(struct wiimote_t)); + + wm[i]->unid = i+1; + + #ifndef WIN32 + wm[i]->bdaddr = *BDADDR_ANY; + wm[i]->out_sock = -1; + wm[i]->in_sock = -1; + #else + wm[i]->dev_handle = 0; + wm[i]->stack = WIIUSE_STACK_UNKNOWN; + wm[i]->normal_timeout = WIIMOTE_DEFAULT_TIMEOUT; + wm[i]->exp_timeout = WIIMOTE_EXP_TIMEOUT; + wm[i]->timeout = wm[i]->normal_timeout; + #endif + + wm[i]->state = WIIMOTE_INIT_STATES; + wm[i]->flags = WIIUSE_INIT_FLAGS; + + wm[i]->event = WIIUSE_NONE; + + wm[i]->exp.type = EXP_NONE; + + wiiuse_set_aspect_ratio(wm[i], WIIUSE_ASPECT_4_3); + wiiuse_set_ir_position(wm[i], WIIUSE_IR_ABOVE); + + wm[i]->orient_threshold = 0.5f; + wm[i]->accel_threshold = 5; + + wm[i]->accel_calib.st_alpha = WIIUSE_DEFAULT_SMOOTH_ALPHA; + } + + return wm; +} + + +/** + * @brief The wiimote disconnected. + * + * @param wm Pointer to a wiimote_t structure. + */ +void wiiuse_disconnected(struct wiimote_t* wm) { + if (!wm) return; + + WIIUSE_INFO("Wiimote disconnected [id %i].", wm->unid); + + /* disable the connected flag */ + WIIMOTE_DISABLE_STATE(wm, WIIMOTE_STATE_CONNECTED); + + /* reset a bunch of stuff */ + #ifndef WIN32 + wm->out_sock = -1; + wm->in_sock = -1; + #else + wm->dev_handle = 0; + #endif + + wm->leds = 0; + wm->state = WIIMOTE_INIT_STATES; + wm->read_req = NULL; + wm->handshake_state = 0; + wm->btns = 0; + wm->btns_held = 0; + wm->btns_released = 0; + memset(wm->event_buf, 0, sizeof(wm->event_buf)); + + wm->event = WIIUSE_DISCONNECT; +} + + +/** + * @brief Enable or disable the rumble. + * + * @param wm Pointer to a wiimote_t structure. + * @param status 1 to enable, 0 to disable. + */ +void wiiuse_rumble(struct wiimote_t* wm, int status) { + byte buf; + + if (!wm || !WIIMOTE_IS_CONNECTED(wm)) + return; + + /* make sure to keep the current lit leds */ + buf = wm->leds; + + if (status) { + WIIUSE_DEBUG("Starting rumble..."); + WIIMOTE_ENABLE_STATE(wm, WIIMOTE_STATE_RUMBLE); + buf |= 0x01; + } else { + WIIUSE_DEBUG("Stopping rumble..."); + WIIMOTE_DISABLE_STATE(wm, WIIMOTE_STATE_RUMBLE); + } + + /* preserve IR state */ + if (WIIMOTE_IS_SET(wm, WIIMOTE_STATE_IR)) + buf |= 0x04; + + wiiuse_send(wm, WM_CMD_RUMBLE, &buf, 1); +} + + +/** + * @brief Toggle the state of the rumble. + * + * @param wm Pointer to a wiimote_t structure. + */ +void wiiuse_toggle_rumble(struct wiimote_t* wm) { + if (!wm) return; + + wiiuse_rumble(wm, !WIIMOTE_IS_SET(wm, WIIMOTE_STATE_RUMBLE)); +} + + +/** + * @brief Set the enabled LEDs. + * + * @param wm Pointer to a wiimote_t structure. + * @param leds What LEDs to enable. + * + * \a leds is a bitwise or of WIIMOTE_LED_1, WIIMOTE_LED_2, WIIMOTE_LED_3, or WIIMOTE_LED_4. + */ +void wiiuse_set_leds(struct wiimote_t* wm, int leds) { + byte buf; + + if (!wm || !WIIMOTE_IS_CONNECTED(wm)) + return; + + /* remove the lower 4 bits because they control rumble */ + wm->leds = (leds & 0xF0); + + /* make sure if the rumble is on that we keep it on */ + if (WIIMOTE_IS_SET(wm, WIIMOTE_STATE_RUMBLE)) + wm->leds |= 0x01; + + buf = wm->leds; + + wiiuse_send(wm, WM_CMD_LED, &buf, 1); +} + + +/** + * @brief Set if the wiimote should report motion sensing. + * + * @param wm Pointer to a wiimote_t structure. + * @param status 1 to enable, 0 to disable. + * + * Since reporting motion sensing sends a lot of data, + * the wiimote saves power by not transmitting it + * by default. + */ +void wiiuse_motion_sensing(struct wiimote_t* wm, int status) { + if (status) + WIIMOTE_ENABLE_STATE(wm, WIIMOTE_STATE_ACC); + else + WIIMOTE_DISABLE_STATE(wm, WIIMOTE_STATE_ACC); + + wiiuse_set_report_type(wm); +} + + +/** + * @brief Set the report type based on the current wiimote state. + * + * @param wm Pointer to a wiimote_t structure. + * + * @return The report type sent. + * + * The wiimote reports formatted packets depending on the + * report type that was last requested. This function will + * update the type of report that should be sent based on + * the current state of the device. + */ +int wiiuse_set_report_type(struct wiimote_t* wm) { + byte buf[2]; + int motion, exp, ir; + + if (!wm || !WIIMOTE_IS_CONNECTED(wm)) + return 0; + + buf[0] = (WIIMOTE_IS_FLAG_SET(wm, WIIUSE_CONTINUOUS) ? 0x04 : 0x00); /* set to 0x04 for continuous reporting */ + buf[1] = 0x00; + + /* if rumble is enabled, make sure we keep it */ + if (WIIMOTE_IS_SET(wm, WIIMOTE_STATE_RUMBLE)) + buf[0] |= 0x01; + + motion = WIIMOTE_IS_SET(wm, WIIMOTE_STATE_ACC); + exp = WIIMOTE_IS_SET(wm, WIIMOTE_STATE_EXP); + ir = WIIMOTE_IS_SET(wm, WIIMOTE_STATE_IR); + + if (motion && ir && exp) buf[1] = WM_RPT_BTN_ACC_IR_EXP; + else if (motion && exp) buf[1] = WM_RPT_BTN_ACC_EXP; + else if (motion && ir) buf[1] = WM_RPT_BTN_ACC_IR; + else if (ir && exp) buf[1] = WM_RPT_BTN_IR_EXP; + else if (ir) buf[1] = WM_RPT_BTN_ACC_IR; + else if (exp) buf[1] = WM_RPT_BTN_EXP; + else if (motion) buf[1] = WM_RPT_BTN_ACC; + else buf[1] = WM_RPT_BTN; + + WIIUSE_DEBUG("Setting report type: 0x%x", buf[1]); + + exp = wiiuse_send(wm, WM_CMD_REPORT_TYPE, buf, 2); + if (exp <= 0) + return exp; + + return buf[1]; +} + + +/** + * @brief Read data from the wiimote (callback version). + * + * @param wm Pointer to a wiimote_t structure. + * @param read_cb Function pointer to call when the data arrives from the wiimote. + * @param buffer An allocated buffer to store the data as it arrives from the wiimote. + * Must be persistent in memory and large enough to hold the data. + * @param addr The address of wiimote memory to read from. + * @param len The length of the block to be read. + * + * The library can only handle one data read request at a time + * because it must keep track of the buffer and other + * events that are specific to that request. So if a request + * has already been made, subsequent requests will be added + * to a pending list and be sent out when the previous + * finishes. + */ +int wiiuse_read_data_cb(struct wiimote_t* wm, wiiuse_read_cb read_cb, byte* buffer, unsigned int addr, unsigned short len) { + struct read_req_t* req; + + if (!wm || !WIIMOTE_IS_CONNECTED(wm)) + return 0; + if (!buffer || !len || !read_cb) + return 0; + + /* make this request structure */ + req = (struct read_req_t*)malloc(sizeof(struct read_req_t)); + req->cb = read_cb; + req->buf = buffer; + req->addr = addr; + req->size = len; + req->wait = len; + req->dirty = 0; + req->next = NULL; + + /* add this to the request list */ + if (!wm->read_req) { + /* root node */ + wm->read_req = req; + + WIIUSE_DEBUG("Data read request can be sent out immediately."); + + /* send the request out immediately */ + wiiuse_send_next_pending_read_request(wm); + } else { + struct read_req_t* nptr = wm->read_req; + for (; nptr->next; nptr = nptr->next); + nptr->next = req; + + WIIUSE_DEBUG("Added pending data read request."); + } + + return 1; +} + + +/** + * @brief Read data from the wiimote (event version). + * + * @param wm Pointer to a wiimote_t structure. + * @param buffer An allocated buffer to store the data as it arrives from the wiimote. + * Must be persistent in memory and large enough to hold the data. + * @param addr The address of wiimote memory to read from. + * @param len The length of the block to be read. + * + * The library can only handle one data read request at a time + * because it must keep track of the buffer and other + * events that are specific to that request. So if a request + * has already been made, subsequent requests will be added + * to a pending list and be sent out when the previous + * finishes. + */ +int wiiuse_read_data(struct wiimote_t* wm, byte* buffer, unsigned int addr, unsigned short len) { + struct read_req_t* req; + + if (!wm || !WIIMOTE_IS_CONNECTED(wm)) + return 0; + if (!buffer || !len) + return 0; + + /* make this request structure */ + req = (struct read_req_t*)malloc(sizeof(struct read_req_t)); + req->cb = NULL; + req->buf = buffer; + req->addr = addr; + req->size = len; + req->wait = len; + req->dirty = 0; + req->next = NULL; + + /* add this to the request list */ + if (!wm->read_req) { + /* root node */ + wm->read_req = req; + + WIIUSE_DEBUG("Data read request can be sent out immediately."); + + /* send the request out immediately */ + wiiuse_send_next_pending_read_request(wm); + } else { + struct read_req_t* nptr = wm->read_req; + for (; nptr->next; nptr = nptr->next); + nptr->next = req; + + WIIUSE_DEBUG("Added pending data read request."); + } + + return 1; +} + + +/** + * @brief Send the next pending data read request to the wiimote. + * + * @param wm Pointer to a wiimote_t structure. + * + * @see wiiuse_read_data() + * + * This function is not part of the wiiuse API. + */ +void wiiuse_send_next_pending_read_request(struct wiimote_t* wm) { + byte buf[6]; + struct read_req_t* req; + + if (!wm || !WIIMOTE_IS_CONNECTED(wm)) + return; + if (!wm->read_req) return; + + /* skip over dirty ones since they have already been read */ + req = wm->read_req; + while (req && req->dirty) + req = req->next; + if (!req) + return; + + /* the offset is in big endian */ + *(int*)(buf) = BIG_ENDIAN_LONG(req->addr); + + /* the length is in big endian */ + *(short*)(buf + 4) = BIG_ENDIAN_SHORT(req->size); + + WIIUSE_DEBUG("Request read at address: 0x%x length: %i", req->addr, req->size); + wiiuse_send(wm, WM_CMD_READ_DATA, buf, 6); +} + + +/** + * @brief Request the wiimote controller status. + * + * @param wm Pointer to a wiimote_t structure. + * + * Controller status includes: battery level, LED status, expansions + */ +void wiiuse_status(struct wiimote_t* wm) { + byte buf = 0; + + if (!wm || !WIIMOTE_IS_CONNECTED(wm)) + return; + + WIIUSE_DEBUG("Requested wiimote status."); + + wiiuse_send(wm, WM_CMD_CTRL_STATUS, &buf, 1); +} + + +/** + * @brief Find a wiimote_t structure by its unique identifier. + * + * @param wm Pointer to a wiimote_t structure. + * @param wiimotes The number of wiimote_t structures in \a wm. + * @param unid The unique identifier to search for. + * + * @return Pointer to a wiimote_t structure, or NULL if not found. + */ +struct wiimote_t* wiiuse_get_by_id(struct wiimote_t** wm, int wiimotes, int unid) { + int i = 0; + + for (; i < wiimotes; ++i) { + if (wm[i]->unid == unid) + return wm[i]; + } + + return NULL; +} + + +/** + * @brief Write data to the wiimote. + * + * @param wm Pointer to a wiimote_t structure. + * @param addr The address to write to. + * @param data The data to be written to the memory location. + * @param len The length of the block to be written. + */ +int wiiuse_write_data(struct wiimote_t* wm, unsigned int addr, byte* data, byte len) { + byte buf[21] = {0}; /* the payload is always 23 */ + + if (!wm || !WIIMOTE_IS_CONNECTED(wm)) + return 0; + if (!data || !len) + return 0; + + WIIUSE_DEBUG("Writing %i bytes to memory location 0x%x...", len, addr); + + #ifdef WITH_WIIUSE_DEBUG + { + int i = 0; + printf("Write data is: "); + for (; i < len; ++i) + printf("%x ", data[i]); + printf("\n"); + } + #endif + + /* the offset is in big endian */ + *(int*)(buf) = BIG_ENDIAN_LONG(addr); + + /* length */ + *(byte*)(buf + 4) = len; + + /* data */ + memcpy(buf + 5, data, len); + + wiiuse_send(wm, WM_CMD_WRITE_DATA, buf, 21); + return 1; +} + + +/** + * @brief Send a packet to the wiimote. + * + * @param wm Pointer to a wiimote_t structure. + * @param report_type The report type to send (WIIMOTE_CMD_LED, WIIMOTE_CMD_RUMBLE, etc). Found in wiiuse.h + * @param msg The payload. + * @param len Length of the payload in bytes. + * + * This function should replace any write()s directly to the wiimote device. + */ +int wiiuse_send(struct wiimote_t* wm, byte report_type, byte* msg, int len) { + byte buf[32]; /* no payload is better than this */ + int rumble = 0; + + #ifndef WIN32 + buf[0] = WM_SET_REPORT | WM_BT_OUTPUT; + buf[1] = report_type; + #else + buf[0] = report_type; + #endif + + switch (report_type) { + case WM_CMD_LED: + case WM_CMD_RUMBLE: + case WM_CMD_CTRL_STATUS: + { + /* Rumble flag for: 0x11, 0x13, 0x14, 0x15, 0x19 or 0x1a */ + if (WIIMOTE_IS_SET(wm, WIIMOTE_STATE_RUMBLE)) + rumble = 1; + break; + } + default: + break; + } + + #ifndef WIN32 + memcpy(buf+2, msg, len); + if (rumble) + buf[2] |= 0x01; + #else + memcpy(buf+1, msg, len); + if (rumble) + buf[1] |= 0x01; + #endif + + #ifdef WITH_WIIUSE_DEBUG + { + int x = 2; + printf("[DEBUG] (id %i) SEND: (%x) %.2x ", wm->unid, buf[0], buf[1]); + #ifndef WIN32 + for (; x < len+2; ++x) + #else + for (; x < len+1; ++x) + #endif + printf("%.2x ", buf[x]); + printf("\n"); + } + #endif + + #ifndef WIN32 + return wiiuse_io_write(wm, buf, len+2); + #else + return wiiuse_io_write(wm, buf, len+1); + #endif +} + + +/** + * @brief Set flags for the specified wiimote. + * + * @param wm Pointer to a wiimote_t structure. + * @param enable Flags to enable. + * @param disable Flags to disable. + * + * @return The flags set after 'enable' and 'disable' have been applied. + * + * The values 'enable' and 'disable' may be any flags OR'ed together. + * Flags are defined in wiiuse.h. + */ +int wiiuse_set_flags(struct wiimote_t* wm, int enable, int disable) { + if (!wm) return 0; + + /* remove mutually exclusive flags */ + enable &= ~disable; + disable &= ~enable; + + wm->flags |= enable; + wm->flags &= ~disable; + + return wm->flags; +} + + +/** + * @brief Set the wiimote smoothing alpha value. + * + * @param wm Pointer to a wiimote_t structure. + * @param alpha The alpha value to set. Between 0 and 1. + * + * @return Returns the old alpha value. + * + * The alpha value is between 0 and 1 and is used in an exponential + * smoothing algorithm. + * + * Smoothing is only performed if the WIIMOTE_USE_SMOOTHING is set. + */ +float wiiuse_set_smooth_alpha(struct wiimote_t* wm, float alpha) { + float old; + + if (!wm) return 0.0f; + + old = wm->accel_calib.st_alpha; + + wm->accel_calib.st_alpha = alpha; + + /* if there is a nunchuk set that too */ + if (wm->exp.type == EXP_NUNCHUK) + wm->exp.nunchuk.accel_calib.st_alpha = alpha; + + return old; +} + + +/** + * @brief Set the bluetooth stack type to use. + * + * @param wm Array of wiimote_t structures. + * @param wiimotes Number of objects in the wm array. + * @param type The type of bluetooth stack to use. + */ +void wiiuse_set_bluetooth_stack(struct wiimote_t** wm, int wiimotes, enum win_bt_stack_t type) { + #ifdef WIN32 + int i; + + if (!wm) return; + + for (i = 0; i < wiimotes; ++i) + wm[i]->stack = type; + #endif +} + + +/** + * @brief Set the orientation event threshold. + * + * @param wm Pointer to a wiimote_t structure. + * @param threshold The decimal place that should be considered a significant change. + * + * If threshold is 0.01, and any angle changes by 0.01 then a significant change + * has occurred and the event callback will be invoked. If threshold is 1 then + * the angle has to change by a full degree to generate an event. + */ +void wiiuse_set_orient_threshold(struct wiimote_t* wm, float threshold) { + if (!wm) return; + + wm->orient_threshold = threshold; +} + + +/** + * @brief Set the accelerometer event threshold. + * + * @param wm Pointer to a wiimote_t structure. + * @param threshold The decimal place that should be considered a significant change. + */ +void wiiuse_set_accel_threshold(struct wiimote_t* wm, int threshold) { + if (!wm) return; + + wm->accel_threshold = threshold; +} + + +/** + * @brief Try to resync with the wiimote by starting a new handshake. + * + * @param wm Pointer to a wiimote_t structure. + */ +void wiiuse_resync(struct wiimote_t* wm) { + if (!wm) return; + + wm->handshake_state = 0; + wiiuse_handshake(wm, NULL, 0); +} + + +/** + * @brief Set the normal and expansion handshake timeouts. + * + * @param wm Array of wiimote_t structures. + * @param wiimotes Number of objects in the wm array. + * @param normal_timeout The timeout in milliseconds for a normal read. + * @param exp_timeout The timeout in millisecondsd to wait for an expansion handshake. + */ +void wiiuse_set_timeout(struct wiimote_t** wm, int wiimotes, byte normal_timeout, byte exp_timeout) { + #ifdef WIN32 + int i; + + if (!wm) return; + + for (i = 0; i < wiimotes; ++i) { + wm[i]->normal_timeout = normal_timeout; + wm[i]->exp_timeout = exp_timeout; + } + #endif +} diff --git a/tools/EventClients/Clients/WiiRemote/wiiuse_v0.12/src/wiiuse.h b/tools/EventClients/Clients/WiiRemote/wiiuse_v0.12/src/wiiuse.h new file mode 100644 index 0000000..fce263c --- /dev/null +++ b/tools/EventClients/Clients/WiiRemote/wiiuse_v0.12/src/wiiuse.h @@ -0,0 +1,649 @@ +/* + * wiiuse + * + * Written By: + * Michael Laforest < para > + * Email: < thepara (--AT--) g m a i l [--DOT--] com > + * + * Copyright 2006-2007 + * + * This file is part of wiiuse. + * + * 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 3 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, see <http://www.gnu.org/licenses/>. + * + * $Header$ + * + */ + +/** + * @file + * + * @brief API header file. + * + * If this file is included from inside the wiiuse source + * and not from a third party program, then wiimote_internal.h + * is also included which extends this file. + */ + +#pragma once + +#ifdef _WIN32 + /* windows */ + #include <windows.h> +#else + /* nix */ + #include <bluetooth/bluetooth.h> +#endif + +#ifdef WIIUSE_INTERNAL_H_INCLUDED + #define WCONST +#else + #define WCONST const +#endif + +/* led bit masks */ +#define WIIMOTE_LED_NONE 0x00 +#define WIIMOTE_LED_1 0x10 +#define WIIMOTE_LED_2 0x20 +#define WIIMOTE_LED_3 0x40 +#define WIIMOTE_LED_4 0x80 + +/* button codes */ +#define WIIMOTE_BUTTON_TWO 0x0001 +#define WIIMOTE_BUTTON_ONE 0x0002 +#define WIIMOTE_BUTTON_B 0x0004 +#define WIIMOTE_BUTTON_A 0x0008 +#define WIIMOTE_BUTTON_MINUS 0x0010 +#define WIIMOTE_BUTTON_ZACCEL_BIT6 0x0020 +#define WIIMOTE_BUTTON_ZACCEL_BIT7 0x0040 +#define WIIMOTE_BUTTON_HOME 0x0080 +#define WIIMOTE_BUTTON_LEFT 0x0100 +#define WIIMOTE_BUTTON_RIGHT 0x0200 +#define WIIMOTE_BUTTON_DOWN 0x0400 +#define WIIMOTE_BUTTON_UP 0x0800 +#define WIIMOTE_BUTTON_PLUS 0x1000 +#define WIIMOTE_BUTTON_ZACCEL_BIT4 0x2000 +#define WIIMOTE_BUTTON_ZACCEL_BIT5 0x4000 +#define WIIMOTE_BUTTON_UNKNOWN 0x8000 +#define WIIMOTE_BUTTON_ALL 0x1F9F + +/* nunchul button codes */ +#define NUNCHUK_BUTTON_Z 0x01 +#define NUNCHUK_BUTTON_C 0x02 +#define NUNCHUK_BUTTON_ALL 0x03 + +/* classic controller button codes */ +#define CLASSIC_CTRL_BUTTON_UP 0x0001 +#define CLASSIC_CTRL_BUTTON_LEFT 0x0002 +#define CLASSIC_CTRL_BUTTON_ZR 0x0004 +#define CLASSIC_CTRL_BUTTON_X 0x0008 +#define CLASSIC_CTRL_BUTTON_A 0x0010 +#define CLASSIC_CTRL_BUTTON_Y 0x0020 +#define CLASSIC_CTRL_BUTTON_B 0x0040 +#define CLASSIC_CTRL_BUTTON_ZL 0x0080 +#define CLASSIC_CTRL_BUTTON_FULL_R 0x0200 +#define CLASSIC_CTRL_BUTTON_PLUS 0x0400 +#define CLASSIC_CTRL_BUTTON_HOME 0x0800 +#define CLASSIC_CTRL_BUTTON_MINUS 0x1000 +#define CLASSIC_CTRL_BUTTON_FULL_L 0x2000 +#define CLASSIC_CTRL_BUTTON_DOWN 0x4000 +#define CLASSIC_CTRL_BUTTON_RIGHT 0x8000 +#define CLASSIC_CTRL_BUTTON_ALL 0xFEFF + +/* guitar hero 3 button codes */ +#define GUITAR_HERO_3_BUTTON_STRUM_UP 0x0001 +#define GUITAR_HERO_3_BUTTON_YELLOW 0x0008 +#define GUITAR_HERO_3_BUTTON_GREEN 0x0010 +#define GUITAR_HERO_3_BUTTON_BLUE 0x0020 +#define GUITAR_HERO_3_BUTTON_RED 0x0040 +#define GUITAR_HERO_3_BUTTON_ORANGE 0x0080 +#define GUITAR_HERO_3_BUTTON_PLUS 0x0400 +#define GUITAR_HERO_3_BUTTON_MINUS 0x1000 +#define GUITAR_HERO_3_BUTTON_STRUM_DOWN 0x4000 +#define GUITAR_HERO_3_BUTTON_ALL 0xFEFF + + +/* wiimote option flags */ +#define WIIUSE_SMOOTHING 0x01 +#define WIIUSE_CONTINUOUS 0x02 +#define WIIUSE_ORIENT_THRESH 0x04 +#define WIIUSE_INIT_FLAGS (WIIUSE_SMOOTHING | WIIUSE_ORIENT_THRESH) + +#define WIIUSE_ORIENT_PRECISION 100.0f + +/* expansion codes */ +#define EXP_NONE 0 +#define EXP_NUNCHUK 1 +#define EXP_CLASSIC 2 +#define EXP_GUITAR_HERO_3 3 + +/* IR correction types */ +typedef enum ir_position_t { + WIIUSE_IR_ABOVE, + WIIUSE_IR_BELOW +} ir_position_t; + +/** + * @brief Check if a button is pressed. + * @param dev Pointer to a wiimote_t or expansion structure. + * @param button The button you are interested in. + * @return 1 if the button is pressed, 0 if not. + */ +#define IS_PRESSED(dev, button) ((dev->btns & button) == button) + +/** + * @brief Check if a button is being held. + * @param dev Pointer to a wiimote_t or expansion structure. + * @param button The button you are interested in. + * @return 1 if the button is held, 0 if not. + */ +#define IS_HELD(dev, button) ((dev->btns_held & button) == button) + +/** + * @brief Check if a button is released on this event. \n\n + * This does not mean the button is not pressed, it means \n + * this button was just now released. + * @param dev Pointer to a wiimote_t or expansion structure. + * @param button The button you are interested in. + * @return 1 if the button is released, 0 if not. + * + */ +#define IS_RELEASED(dev, button) ((dev->btns_released & button) == button) + +/** + * @brief Check if a button has just been pressed this event. + * @param dev Pointer to a wiimote_t or expansion structure. + * @param button The button you are interested in. + * @return 1 if the button is pressed, 0 if not. + */ +#define IS_JUST_PRESSED(dev, button) (IS_PRESSED(dev, button) && !IS_HELD(dev, button)) + +/** + * @brief Return the IR sensitivity level. + * @param wm Pointer to a wiimote_t structure. + * @param lvl [out] Pointer to an int that will hold the level setting. + * If no level is set 'lvl' will be set to 0. + */ +#define WIIUSE_GET_IR_SENSITIVITY(dev, lvl) \ + do { \ + if ((wm->state & 0x0200) == 0x0200) *lvl = 1; \ + else if ((wm->state & 0x0400) == 0x0400) *lvl = 2; \ + else if ((wm->state & 0x0800) == 0x0800) *lvl = 3; \ + else if ((wm->state & 0x1000) == 0x1000) *lvl = 4; \ + else if ((wm->state & 0x2000) == 0x2000) *lvl = 5; \ + else *lvl = 0; \ + } while (0) + +#define WIIUSE_USING_ACC(wm) ((wm->state & 0x020) == 0x020) +#define WIIUSE_USING_EXP(wm) ((wm->state & 0x040) == 0x040) +#define WIIUSE_USING_IR(wm) ((wm->state & 0x080) == 0x080) +#define WIIUSE_USING_SPEAKER(wm) ((wm->state & 0x100) == 0x100) + +#define WIIUSE_IS_LED_SET(wm, num) ((wm->leds & WIIMOTE_LED_##num) == WIIMOTE_LED_##num) + +/* + * Largest known payload is 21 bytes. + * Add 2 for the prefix and round up to a power of 2. + */ +#define MAX_PAYLOAD 32 + +/* + * This is left over from an old hack, but it may actually + * be a useful feature to keep so it wasn't removed. + */ +#ifdef WIN32 + #define WIIMOTE_DEFAULT_TIMEOUT 10 + #define WIIMOTE_EXP_TIMEOUT 10 +#endif + +typedef unsigned char byte; +typedef char sbyte; + +struct wiimote_t; +struct vec3b_t; +struct orient_t; +struct gforce_t; + + +/** + * @brief Callback that handles a read event. + * + * @param wm Pointer to a wiimote_t structure. + * @param data Pointer to the filled data block. + * @param len Length in bytes of the data block. + * + * @see wiiuse_init() + * + * A registered function of this type is called automatically by the wiiuse + * library when the wiimote has returned the full data requested by a previous + * call to wiiuse_read_data(). + */ +typedef void (*wiiuse_read_cb)(struct wiimote_t* wm, byte* data, unsigned short len); + + +/** + * @struct read_req_t + * @brief Data read request structure. + */ +struct read_req_t { + wiiuse_read_cb cb; /**< read data callback */ + byte* buf; /**< buffer where read data is written */ + unsigned int addr; /**< the offset that the read started at */ + unsigned short size; /**< the length of the data read */ + unsigned short wait; /**< num bytes still needed to finish read */ + byte dirty; /**< set to 1 if not using callback and needs to be cleaned up */ + + struct read_req_t* next; /**< next read request in the queue */ +}; + + +/** + * @struct vec2b_t + * @brief Unsigned x,y byte vector. + */ +typedef struct vec2b_t { + byte x, y; +} vec2b_t; + + +/** + * @struct vec3b_t + * @brief Unsigned x,y,z byte vector. + */ +typedef struct vec3b_t { + byte x, y, z; +} vec3b_t; + + +/** + * @struct vec3f_t + * @brief Signed x,y,z float struct. + */ +typedef struct vec3f_t { + float x, y, z; +} vec3f_t; + + +/** + * @struct orient_t + * @brief Orientation struct. + * + * Yaw, pitch, and roll range from -180 to 180 degrees. + */ +typedef struct orient_t { + float roll; /**< roll, this may be smoothed if enabled */ + float pitch; /**< pitch, this may be smoothed if enabled */ + float yaw; + + float a_roll; /**< absolute roll, unsmoothed */ + float a_pitch; /**< absolute pitch, unsmoothed */ +} orient_t; + + +/** + * @struct gforce_t + * @brief Gravity force struct. + */ +typedef struct gforce_t { + float x, y, z; +} gforce_t; + + +/** + * @struct accel_t + * @brief Accelerometer struct. For any device with an accelerometer. + */ +typedef struct accel_t { + struct vec3b_t cal_zero; /**< zero calibration */ + struct vec3b_t cal_g; /**< 1g difference around 0cal */ + + float st_roll; /**< last smoothed roll value */ + float st_pitch; /**< last smoothed roll pitch */ + float st_alpha; /**< alpha value for smoothing [0-1] */ +} accel_t; + + +/** + * @struct ir_dot_t + * @brief A single IR source. + */ +typedef struct ir_dot_t { + byte visible; /**< if the IR source is visible */ + + unsigned int x; /**< interpolated X coordinate */ + unsigned int y; /**< interpolated Y coordinate */ + + short rx; /**< raw X coordinate (0-1023) */ + short ry; /**< raw Y coordinate (0-767) */ + + byte order; /**< increasing order by x-axis value */ + + byte size; /**< size of the IR dot (0-15) */ +} ir_dot_t; + + +/** + * @enum aspect_t + * @brief Screen aspect ratio. + */ +typedef enum aspect_t { + WIIUSE_ASPECT_4_3, + WIIUSE_ASPECT_16_9 +} aspect_t; + + +/** + * @struct ir_t + * @brief IR struct. Hold all data related to the IR tracking. + */ +typedef struct ir_t { + struct ir_dot_t dot[4]; /**< IR dots */ + byte num_dots; /**< number of dots at this time */ + + enum aspect_t aspect; /**< aspect ratio of the screen */ + + enum ir_position_t pos; /**< IR sensor bar position */ + + unsigned int vres[2]; /**< IR virtual screen resolution */ + int offset[2]; /**< IR XY correction offset */ + int state; /**< keeps track of the IR state */ + + int ax; /**< absolute X coordinate */ + int ay; /**< absolute Y coordinate */ + + int x; /**< calculated X coordinate */ + int y; /**< calculated Y coordinate */ + + float distance; /**< pixel distance between first 2 dots*/ + float z; /**< calculated distance */ +} ir_t; + + +/** + * @struct joystick_t + * @brief Joystick calibration structure. + * + * The angle \a ang is relative to the positive y-axis into quadrant I + * and ranges from 0 to 360 degrees. So if the joystick is held straight + * upwards then angle is 0 degrees. If it is held to the right it is 90, + * down is 180, and left is 270. + * + * The magnitude \a mag is the distance from the center to where the + * joystick is being held. The magnitude ranges from 0 to 1. + * If the joystick is only slightly tilted from the center the magnitude + * will be low, but if it is closer to the outter edge the value will + * be higher. + */ +typedef struct joystick_t { + struct vec2b_t max; /**< maximum joystick values */ + struct vec2b_t min; /**< minimum joystick values */ + struct vec2b_t center; /**< center joystick values */ + + float ang; /**< angle the joystick is being held */ + float mag; /**< magnitude of the joystick (range 0-1) */ +} joystick_t; + + +/** + * @struct nunchuk_t + * @brief Nunchuk expansion device. + */ +typedef struct nunchuk_t { + struct accel_t accel_calib; /**< nunchuk accelerometer calibration */ + struct joystick_t js; /**< joystick calibration */ + + int* flags; /**< options flag (points to wiimote_t.flags) */ + + byte btns; /**< what buttons have just been pressed */ + byte btns_held; /**< what buttons are being held down */ + byte btns_released; /**< what buttons were just released this */ + + float orient_threshold; /**< threshold for orient to generate an event */ + int accel_threshold; /**< threshold for accel to generate an event */ + + struct vec3b_t accel; /**< current raw acceleration data */ + struct orient_t orient; /**< current orientation on each axis */ + struct gforce_t gforce; /**< current gravity forces on each axis */ +} nunchuk_t; + + +/** + * @struct classic_ctrl_t + * @brief Classic controller expansion device. + */ +typedef struct classic_ctrl_t { + short btns; /**< what buttons have just been pressed */ + short btns_held; /**< what buttons are being held down */ + short btns_released; /**< what buttons were just released this */ + + float r_shoulder; /**< right shoulder button (range 0-1) */ + float l_shoulder; /**< left shoulder button (range 0-1) */ + + struct joystick_t ljs; /**< left joystick calibration */ + struct joystick_t rjs; /**< right joystick calibration */ +} classic_ctrl_t; + + +/** + * @struct guitar_hero_3_t + * @brief Guitar Hero 3 expansion device. + */ +typedef struct guitar_hero_3_t { + short btns; /**< what buttons have just been pressed */ + short btns_held; /**< what buttons are being held down */ + short btns_released; /**< what buttons were just released this */ + + float whammy_bar; /**< whammy bar (range 0-1) */ + + struct joystick_t js; /**< joystick calibration */ +} guitar_hero_3_t; + + +/** + * @struct expansion_t + * @brief Generic expansion device plugged into wiimote. + */ +typedef struct expansion_t { + int type; /**< type of expansion attached */ + + union { + struct nunchuk_t nunchuk; + struct classic_ctrl_t classic; + struct guitar_hero_3_t gh3; + }; +} expansion_t; + + +/** + * @enum win32_bt_stack_t + * @brief Available bluetooth stacks for Windows. + */ +typedef enum win_bt_stack_t { + WIIUSE_STACK_UNKNOWN, + WIIUSE_STACK_MS, + WIIUSE_STACK_BLUESOLEIL +} win_bt_stack_t; + + +/** + * @struct wiimote_state_t + * @brief Significant data from the previous event. + */ +typedef struct wiimote_state_t { + /* expansion_t */ + float exp_ljs_ang; + float exp_rjs_ang; + float exp_ljs_mag; + float exp_rjs_mag; + unsigned short exp_btns; + struct orient_t exp_orient; + struct vec3b_t exp_accel; + float exp_r_shoulder; + float exp_l_shoulder; + + /* ir_t */ + int ir_ax; + int ir_ay; + float ir_distance; + + struct orient_t orient; + unsigned short btns; + + struct vec3b_t accel; +} wiimote_state_t; + + +/** + * @enum WIIUSE_EVENT_TYPE + * @brief Events that wiiuse can generate from a poll. + */ +typedef enum WIIUSE_EVENT_TYPE { + WIIUSE_NONE = 0, + WIIUSE_EVENT, + WIIUSE_STATUS, + WIIUSE_CONNECT, + WIIUSE_DISCONNECT, + WIIUSE_UNEXPECTED_DISCONNECT, + WIIUSE_READ_DATA, + WIIUSE_NUNCHUK_INSERTED, + WIIUSE_NUNCHUK_REMOVED, + WIIUSE_CLASSIC_CTRL_INSERTED, + WIIUSE_CLASSIC_CTRL_REMOVED, + WIIUSE_GUITAR_HERO_3_CTRL_INSERTED, + WIIUSE_GUITAR_HERO_3_CTRL_REMOVED +} WIIUSE_EVENT_TYPE; + +/** + * @struct wiimote_t + * @brief Wiimote structure. + */ +typedef struct wiimote_t { + WCONST int unid; /**< user specified id */ + + #ifndef WIN32 + WCONST bdaddr_t bdaddr; /**< bt address */ + WCONST char bdaddr_str[18]; /**< readable bt address */ + WCONST int out_sock; /**< output socket */ + WCONST int in_sock; /**< input socket */ + #else + WCONST HANDLE dev_handle; /**< HID handle */ + WCONST OVERLAPPED hid_overlap; /**< overlap handle */ + WCONST enum win_bt_stack_t stack; /**< type of bluetooth stack to use */ + WCONST int timeout; /**< read timeout */ + WCONST byte normal_timeout; /**< normal timeout */ + WCONST byte exp_timeout; /**< timeout for expansion handshake */ + #endif + + WCONST int state; /**< various state flags */ + WCONST byte leds; /**< currently lit leds */ + WCONST float battery_level; /**< battery level */ + + WCONST int flags; /**< options flag */ + + WCONST byte handshake_state; /**< the state of the connection handshake */ + + WCONST struct read_req_t* read_req; /**< list of data read requests */ + WCONST struct accel_t accel_calib; /**< wiimote accelerometer calibration */ + WCONST struct expansion_t exp; /**< wiimote expansion device */ + + WCONST struct vec3b_t accel; /**< current raw acceleration data */ + WCONST struct orient_t orient; /**< current orientation on each axis */ + WCONST struct gforce_t gforce; /**< current gravity forces on each axis */ + + WCONST struct ir_t ir; /**< IR data */ + + WCONST unsigned short btns; /**< what buttons have just been pressed */ + WCONST unsigned short btns_held; /**< what buttons are being held down */ + WCONST unsigned short btns_released; /**< what buttons were just released this */ + + WCONST float orient_threshold; /**< threshold for orient to generate an event */ + WCONST int accel_threshold; /**< threshold for accel to generate an event */ + + WCONST struct wiimote_state_t lstate; /**< last saved state */ + + WCONST WIIUSE_EVENT_TYPE event; /**< type of event that occurred */ + WCONST byte event_buf[MAX_PAYLOAD]; /**< event buffer */ +} wiimote; + + +/***************************************** + * + * Include API specific stuff + * + *****************************************/ + +#ifdef _WIN32 + #define WIIUSE_EXPORT_DECL __declspec(dllexport) + #define WIIUSE_IMPORT_DECL __declspec(dllimport) +#else + #define WIIUSE_EXPORT_DECL + #define WIIUSE_IMPORT_DECL +#endif + +#ifdef WIIUSE_COMPILE_LIB + #define WIIUSE_EXPORT WIIUSE_EXPORT_DECL +#else + #define WIIUSE_EXPORT WIIUSE_IMPORT_DECL +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/* wiiuse.c */ +WIIUSE_EXPORT extern const char* wiiuse_version(); + +WIIUSE_EXPORT extern struct wiimote_t** wiiuse_init(int wiimotes); +WIIUSE_EXPORT extern void wiiuse_disconnected(struct wiimote_t* wm); +WIIUSE_EXPORT extern void wiiuse_cleanup(struct wiimote_t** wm, int wiimotes); +WIIUSE_EXPORT extern void wiiuse_rumble(struct wiimote_t* wm, int status); +WIIUSE_EXPORT extern void wiiuse_toggle_rumble(struct wiimote_t* wm); +WIIUSE_EXPORT extern void wiiuse_set_leds(struct wiimote_t* wm, int leds); +WIIUSE_EXPORT extern void wiiuse_motion_sensing(struct wiimote_t* wm, int status); +WIIUSE_EXPORT extern int wiiuse_read_data(struct wiimote_t* wm, byte* buffer, unsigned int offset, unsigned short len); +WIIUSE_EXPORT extern int wiiuse_write_data(struct wiimote_t* wm, unsigned int addr, byte* data, byte len); +WIIUSE_EXPORT extern void wiiuse_status(struct wiimote_t* wm); +WIIUSE_EXPORT extern struct wiimote_t* wiiuse_get_by_id(struct wiimote_t** wm, int wiimotes, int unid); +WIIUSE_EXPORT extern int wiiuse_set_flags(struct wiimote_t* wm, int enable, int disable); +WIIUSE_EXPORT extern float wiiuse_set_smooth_alpha(struct wiimote_t* wm, float alpha); +WIIUSE_EXPORT extern void wiiuse_set_bluetooth_stack(struct wiimote_t** wm, int wiimotes, enum win_bt_stack_t type); +WIIUSE_EXPORT extern void wiiuse_set_orient_threshold(struct wiimote_t* wm, float threshold); +WIIUSE_EXPORT extern void wiiuse_resync(struct wiimote_t* wm); +WIIUSE_EXPORT extern void wiiuse_set_timeout(struct wiimote_t** wm, int wiimotes, byte normal_timeout, byte exp_timeout); +WIIUSE_EXPORT extern void wiiuse_set_accel_threshold(struct wiimote_t* wm, int threshold); + +/* connect.c */ +WIIUSE_EXPORT extern int wiiuse_find(struct wiimote_t** wm, int max_wiimotes, int timeout); +WIIUSE_EXPORT extern int wiiuse_connect(struct wiimote_t** wm, int wiimotes); +WIIUSE_EXPORT extern void wiiuse_disconnect(struct wiimote_t* wm); + +/* events.c */ +WIIUSE_EXPORT extern int wiiuse_poll(struct wiimote_t** wm, int wiimotes); + +/* ir.c */ +WIIUSE_EXPORT extern void wiiuse_set_ir(struct wiimote_t* wm, int status); +WIIUSE_EXPORT extern void wiiuse_set_ir_vres(struct wiimote_t* wm, unsigned int x, unsigned int y); +WIIUSE_EXPORT extern void wiiuse_set_ir_position(struct wiimote_t* wm, enum ir_position_t pos); +WIIUSE_EXPORT extern void wiiuse_set_aspect_ratio(struct wiimote_t* wm, enum aspect_t aspect); +WIIUSE_EXPORT extern void wiiuse_set_ir_sensitivity(struct wiimote_t* wm, int level); + +/* nunchuk.c */ +WIIUSE_EXPORT extern void wiiuse_set_nunchuk_orient_threshold(struct wiimote_t* wm, float threshold); +WIIUSE_EXPORT extern void wiiuse_set_nunchuk_accel_threshold(struct wiimote_t* wm, int threshold); + + +#ifdef __cplusplus +} +#endif + diff --git a/tools/EventClients/Clients/WiiRemote/wiiuse_v0.12/src/wiiuse_internal.h b/tools/EventClients/Clients/WiiRemote/wiiuse_v0.12/src/wiiuse_internal.h new file mode 100644 index 0000000..de5c011 --- /dev/null +++ b/tools/EventClients/Clients/WiiRemote/wiiuse_v0.12/src/wiiuse_internal.h @@ -0,0 +1,224 @@ +/* + * wiiuse + * + * Written By: + * Michael Laforest < para > + * Email: < thepara (--AT--) g m a i l [--DOT--] com > + * + * Copyright 2006-2007 + * + * This file is part of wiiuse. + * + * 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 3 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, see <http://www.gnu.org/licenses/>. + * + * $Header$ + * + */ + +/** + * @file + * @brief General internal wiiuse stuff. + * + * Since Wiiuse is a library, wiiuse.h is a duplicate + * of the API header. + * + * The code that would normally go in that file, but + * which is not needed by third party developers, + * is put here. + * + * So wiiuse_internal.h is included by other files + * internally, wiiuse.h is included only here. + */ + +#pragma once + +#ifndef WIN32 + #include <arpa/inet.h> /* htons() */ + #include <bluetooth/bluetooth.h> +#endif + +#include "definitions.h" + +/* wiiuse version */ +#define WIIUSE_VERSION "0.12" + +/******************** + * + * Wiimote internal codes + * + ********************/ + +/* Communication channels */ +#define WM_OUTPUT_CHANNEL 0x11 +#define WM_INPUT_CHANNEL 0x13 + +#define WM_SET_REPORT 0x50 + +/* commands */ +#define WM_CMD_LED 0x11 +#define WM_CMD_REPORT_TYPE 0x12 +#define WM_CMD_RUMBLE 0x13 +#define WM_CMD_IR 0x13 +#define WM_CMD_CTRL_STATUS 0x15 +#define WM_CMD_WRITE_DATA 0x16 +#define WM_CMD_READ_DATA 0x17 +#define WM_CMD_IR_2 0x1A + +/* input report ids */ +#define WM_RPT_CTRL_STATUS 0x20 +#define WM_RPT_READ 0x21 +#define WM_RPT_WRITE 0x22 +#define WM_RPT_BTN 0x30 +#define WM_RPT_BTN_ACC 0x31 +#define WM_RPT_BTN_ACC_IR 0x33 +#define WM_RPT_BTN_EXP 0x34 +#define WM_RPT_BTN_ACC_EXP 0x35 +#define WM_RPT_BTN_IR_EXP 0x36 +#define WM_RPT_BTN_ACC_IR_EXP 0x37 + +#define WM_BT_INPUT 0x01 +#define WM_BT_OUTPUT 0x02 + +/* Identify the wiimote device by its class */ +#define WM_DEV_CLASS_0 0x04 +#define WM_DEV_CLASS_1 0x25 +#define WM_DEV_CLASS_2 0x00 +#define WM_VENDOR_ID 0x057E +#define WM_PRODUCT_ID 0x0306 + +/* controller status stuff */ +#define WM_MAX_BATTERY_CODE 0xC8 + +/* offsets in wiimote memory */ +#define WM_MEM_OFFSET_CALIBRATION 0x16 +#define WM_EXP_MEM_BASE 0x04A40000 +#define WM_EXP_MEM_ENABLE 0x04A40040 +#define WM_EXP_MEM_CALIBR 0x04A40020 + +#define WM_REG_IR 0x04B00030 +#define WM_REG_IR_BLOCK1 0x04B00000 +#define WM_REG_IR_BLOCK2 0x04B0001A +#define WM_REG_IR_MODENUM 0x04B00033 + +/* ir block data */ +#define WM_IR_BLOCK1_LEVEL1 "\x02\x00\x00\x71\x01\x00\x64\x00\xfe" +#define WM_IR_BLOCK2_LEVEL1 "\xfd\x05" +#define WM_IR_BLOCK1_LEVEL2 "\x02\x00\x00\x71\x01\x00\x96\x00\xb4" +#define WM_IR_BLOCK2_LEVEL2 "\xb3\x04" +#define WM_IR_BLOCK1_LEVEL3 "\x02\x00\x00\x71\x01\x00\xaa\x00\x64" +#define WM_IR_BLOCK2_LEVEL3 "\x63\x03" +#define WM_IR_BLOCK1_LEVEL4 "\x02\x00\x00\x71\x01\x00\xc8\x00\x36" +#define WM_IR_BLOCK2_LEVEL4 "\x35\x03" +#define WM_IR_BLOCK1_LEVEL5 "\x07\x00\x00\x71\x01\x00\x72\x00\x20" +#define WM_IR_BLOCK2_LEVEL5 "\x1f\x03" + +#define WM_IR_TYPE_BASIC 0x01 +#define WM_IR_TYPE_EXTENDED 0x03 + +/* controller status flags for the first message byte */ +/* bit 1 is unknown */ +#define WM_CTRL_STATUS_BYTE1_ATTACHMENT 0x02 +#define WM_CTRL_STATUS_BYTE1_SPEAKER_ENABLED 0x04 +#define WM_CTRL_STATUS_BYTE1_IR_ENABLED 0x08 +#define WM_CTRL_STATUS_BYTE1_LED_1 0x10 +#define WM_CTRL_STATUS_BYTE1_LED_2 0x20 +#define WM_CTRL_STATUS_BYTE1_LED_3 0x40 +#define WM_CTRL_STATUS_BYTE1_LED_4 0x80 + +/* aspect ratio */ +#define WM_ASPECT_16_9_X 660 +#define WM_ASPECT_16_9_Y 370 +#define WM_ASPECT_4_3_X 560 +#define WM_ASPECT_4_3_Y 420 + + +/** + * Expansion stuff + */ + +/* encrypted expansion id codes (located at 0x04A400FC) */ +#define EXP_ID_CODE_NUNCHUK 0x9A1EFEFE +#define EXP_ID_CODE_CLASSIC_CONTROLLER 0x9A1EFDFD +#define EXP_ID_CODE_GUITAR 0x9A1EFDFB + +#define EXP_HANDSHAKE_LEN 224 + +/******************** + * + * End Wiimote internal codes + * + ********************/ + +/* wiimote state flags - (some duplicated in wiiuse.h)*/ +#define WIIMOTE_STATE_DEV_FOUND 0x0001 +#define WIIMOTE_STATE_HANDSHAKE 0x0002 /* actual connection exists but no handshake yet */ +#define WIIMOTE_STATE_HANDSHAKE_COMPLETE 0x0004 /* actual connection exists but no handshake yet */ +#define WIIMOTE_STATE_CONNECTED 0x0008 +#define WIIMOTE_STATE_RUMBLE 0x0010 +#define WIIMOTE_STATE_ACC 0x0020 +#define WIIMOTE_STATE_EXP 0x0040 +#define WIIMOTE_STATE_IR 0x0080 +#define WIIMOTE_STATE_SPEAKER 0x0100 +#define WIIMOTE_STATE_IR_SENS_LVL1 0x0200 +#define WIIMOTE_STATE_IR_SENS_LVL2 0x0400 +#define WIIMOTE_STATE_IR_SENS_LVL3 0x0800 +#define WIIMOTE_STATE_IR_SENS_LVL4 0x1000 +#define WIIMOTE_STATE_IR_SENS_LVL5 0x2000 + +#define WIIMOTE_INIT_STATES (WIIMOTE_STATE_IR_SENS_LVL3) + +/* macro to manage states */ +#define WIIMOTE_IS_SET(wm, s) ((wm->state & (s)) == (s)) +#define WIIMOTE_ENABLE_STATE(wm, s) (wm->state |= (s)) +#define WIIMOTE_DISABLE_STATE(wm, s) (wm->state &= ~(s)) +#define WIIMOTE_TOGGLE_STATE(wm, s) ((wm->state & (s)) ? WIIMOTE_DISABLE_STATE(wm, s) : WIIMOTE_ENABLE_STATE(wm, s)) + +#define WIIMOTE_IS_FLAG_SET(wm, s) ((wm->flags & (s)) == (s)) +#define WIIMOTE_ENABLE_FLAG(wm, s) (wm->flags |= (s)) +#define WIIMOTE_DISABLE_FLAG(wm, s) (wm->flags &= ~(s)) +#define WIIMOTE_TOGGLE_FLAG(wm, s) ((wm->flags & (s)) ? WIIMOTE_DISABLE_FLAG(wm, s) : WIIMOTE_ENABLE_FLAG(wm, s)) + +#define NUNCHUK_IS_FLAG_SET(wm, s) ((*(wm->flags) & (s)) == (s)) + +/* misc macros */ +#define WIIMOTE_ID(wm) (wm->unid) +#define WIIMOTE_IS_CONNECTED(wm) (WIIMOTE_IS_SET(wm, WIIMOTE_STATE_CONNECTED)) + +/* + * Smooth tilt calculations are computed with the + * exponential moving average formula: + * St = St_last + (alpha * (tilt - St_last)) + * alpha is between 0 and 1 + */ +#define WIIUSE_DEFAULT_SMOOTH_ALPHA 0.07f + +#define SMOOTH_ROLL 0x01 +#define SMOOTH_PITCH 0x02 + +#include "wiiuse.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* not part of the api */ +int wiiuse_set_report_type(struct wiimote_t* wm); +void wiiuse_send_next_pending_read_request(struct wiimote_t* wm); +int wiiuse_send(struct wiimote_t* wm, byte report_type, byte* msg, int len); +int wiiuse_read_data_cb(struct wiimote_t* wm, wiiuse_read_cb read_cb, byte* buffer, unsigned int offset, unsigned short len); + +#ifdef __cplusplus +} +#endif + diff --git a/tools/EventClients/Clients/WiiRemote/wiiuse_v0.12/wiiuse.cbp b/tools/EventClients/Clients/WiiRemote/wiiuse_v0.12/wiiuse.cbp new file mode 100644 index 0000000..a71d3a0 --- /dev/null +++ b/tools/EventClients/Clients/WiiRemote/wiiuse_v0.12/wiiuse.cbp @@ -0,0 +1,86 @@ +<?xml version="1.0" encoding="UTF-8" standalone="yes" ?> +<CodeBlocks_project_file> + <FileVersion major="1" minor="6" /> + <Project> + <Option title="wiiuse" /> + <Option makefile_is_custom="1" /> + <Option pch_mode="2" /> + <Option compiler="gcc" /> + <MakeCommands> + <Build command="$make $target" /> + <CompileFile command="$make $file" /> + <Clean command="$make clean" /> + <DistClean command="$make distclean" /> + </MakeCommands> + <Build> + <Target title="Release"> + <Option output="bin/Release/wiiuse" prefix_auto="1" extension_auto="1" /> + <Option object_output="obj/Release/" /> + <Option type="1" /> + <Option compiler="gcc" /> + <Compiler> + <Add option="-O2" /> + </Compiler> + <Linker> + <Add option="-s" /> + </Linker> + </Target> + </Build> + <Compiler> + <Add option="-Wall" /> + </Compiler> + <Unit filename="CHANGELOG" /> + <Unit filename="README" /> + <Unit filename="example-sdl/sdl.c"> + <Option compilerVar="CC" /> + </Unit> + <Unit filename="example/example.c"> + <Option compilerVar="CC" /> + </Unit> + <Unit filename="src/classic.c"> + <Option compilerVar="CC" /> + </Unit> + <Unit filename="src/classic.h" /> + <Unit filename="src/definitions.h" /> + <Unit filename="src/dynamics.c"> + <Option compilerVar="CC" /> + </Unit> + <Unit filename="src/dynamics.h" /> + <Unit filename="src/events.c"> + <Option compilerVar="CC" /> + </Unit> + <Unit filename="src/events.h" /> + <Unit filename="src/guitar_hero_3.c"> + <Option compilerVar="CC" /> + </Unit> + <Unit filename="src/guitar_hero_3.h" /> + <Unit filename="src/io.c"> + <Option compilerVar="CC" /> + </Unit> + <Unit filename="src/io.h" /> + <Unit filename="src/io_nix.c"> + <Option compilerVar="CC" /> + </Unit> + <Unit filename="src/io_win.c"> + <Option compilerVar="CC" /> + </Unit> + <Unit filename="src/ir.c"> + <Option compilerVar="CC" /> + </Unit> + <Unit filename="src/ir.h" /> + <Unit filename="src/nunchuk.c"> + <Option compilerVar="CC" /> + </Unit> + <Unit filename="src/nunchuk.h" /> + <Unit filename="src/os.h" /> + <Unit filename="src/wiiuse.c"> + <Option compilerVar="CC" /> + </Unit> + <Unit filename="src/wiiuse.h" /> + <Unit filename="src/wiiuse_internal.h" /> + <Extensions> + <code_completion /> + <debugger /> + </Extensions> + </Project> +</CodeBlocks_project_file> diff --git a/tools/EventClients/Clients/WiiRemote/wiiuse_v0.12/wiiuse.layout b/tools/EventClients/Clients/WiiRemote/wiiuse_v0.12/wiiuse.layout new file mode 100644 index 0000000..5b74afe --- /dev/null +++ b/tools/EventClients/Clients/WiiRemote/wiiuse_v0.12/wiiuse.layout @@ -0,0 +1,61 @@ +<?xml version="1.0" encoding="UTF-8" standalone="yes" ?> +<CodeBlocks_layout_file> + <ActiveTarget name="Release" /> + <File name="CHANGELOG" open="1" top="0" tabpos="7"> + <Cursor position="0" topLine="0" /> + </File> + <File name="README" open="0" top="0" tabpos="8"> + <Cursor position="3582" topLine="0" /> + </File> + <File name="example-sdl/sdl.c" open="1" top="0" tabpos="6"> + <Cursor position="3235" topLine="105" /> + </File> + <File name="example/example.c" open="1" top="0" tabpos="5"> + <Cursor position="0" topLine="0" /> + </File> + <File name="src/classic.c" open="0" top="0" tabpos="4"> + <Cursor position="2464" topLine="53" /> + </File> + <File name="src/definitions.h" open="1" top="0" tabpos="9"> + <Cursor position="1099" topLine="12" /> + </File> + <File name="src/dynamics.c" open="0" top="0" tabpos="10"> + <Cursor position="3216" topLine="59" /> + </File> + <File name="src/events.c" open="1" top="0" tabpos="4"> + <Cursor position="2983" topLine="117" /> + </File> + <File name="src/guitar_hero_3.c" open="0" top="0" tabpos="0"> + <Cursor position="2604" topLine="45" /> + </File> + <File name="src/io.c" open="0" top="0" tabpos="6"> + <Cursor position="1817" topLine="60" /> + </File> + <File name="src/io_nix.c" open="0" top="0" tabpos="8"> + <Cursor position="6286" topLine="211" /> + </File> + <File name="src/io_win.c" open="0" top="0" tabpos="9"> + <Cursor position="4021" topLine="123" /> + </File> + <File name="src/ir.c" open="1" top="0" tabpos="8"> + <Cursor position="0" topLine="0" /> + </File> + <File name="src/ir.h" open="0" top="0" tabpos="0"> + <Cursor position="1059" topLine="0" /> + </File> + <File name="src/nunchuk.c" open="0" top="0" tabpos="10"> + <Cursor position="2454" topLine="43" /> + </File> + <File name="src/nunchuk.h" open="0" top="0" tabpos="0"> + <Cursor position="1171" topLine="0" /> + </File> + <File name="src/wiiuse.c" open="1" top="0" tabpos="1"> + <Cursor position="0" topLine="0" /> + </File> + <File name="src/wiiuse.h" open="1" top="1" tabpos="2"> + <Cursor position="0" topLine="0" /> + </File> + <File name="src/wiiuse_internal.h" open="1" top="0" tabpos="3"> + <Cursor position="3424" topLine="81" /> + </File> +</CodeBlocks_layout_file> diff --git a/tools/EventClients/Clients/Xbox360Controller/Xbox360Controller.cpp b/tools/EventClients/Clients/Xbox360Controller/Xbox360Controller.cpp new file mode 100644 index 0000000..caf2870 --- /dev/null +++ b/tools/EventClients/Clients/Xbox360Controller/Xbox360Controller.cpp @@ -0,0 +1,172 @@ +/* + * Copyright (C) 2009-2013 Team XBMC + * + * 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 Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include "StdAfx.h" +#include "Xbox360Controller.h" + + +Xbox360Controller::Xbox360Controller(int num) +{ + this->num = num; + for (int i = 0; i < 14; i++) + { + button_down[i] = false; + button_released[i] = false; + button_pressed[i] = false; + } +} + +XINPUT_STATE Xbox360Controller::getState() +{ + // Zeroise the state + ZeroMemory(&state, sizeof(XINPUT_STATE)); + + // Get the state + XInputGetState(num, &state); + + return state; +} + +void Xbox360Controller::updateButton(int num, int button) +{ + if (state.Gamepad.wButtons & button) + { + if (!button_down[num]) + { + button_pressed[num] = true; + } + button_down[num] = true; + } else + { + if (button_down[num]) + { + button_released[num] = true; + } + button_down[num] = false; + } +} + +bool Xbox360Controller::buttonPressed(int num) +{ + return button_pressed[num]; +} + +bool Xbox360Controller::buttonReleased(int num) +{ + return button_released[num]; +} + +void Xbox360Controller::updateState() +{ + for (int i = 0; i < 14; i++) + { + button_released[i] = false; + button_pressed[i] = false; + } + if (isConnected()) + { + XINPUT_STATE s = getState(); + updateButton(0, XINPUT_GAMEPAD_A); + updateButton(1, XINPUT_GAMEPAD_B); + updateButton(2, XINPUT_GAMEPAD_X); + updateButton(3, XINPUT_GAMEPAD_Y); + updateButton(4, XINPUT_GAMEPAD_DPAD_UP); + updateButton(5, XINPUT_GAMEPAD_DPAD_DOWN); + updateButton(6, XINPUT_GAMEPAD_DPAD_LEFT); + updateButton(7, XINPUT_GAMEPAD_DPAD_RIGHT); + updateButton(8, XINPUT_GAMEPAD_START); + updateButton(9, XINPUT_GAMEPAD_BACK); + updateButton(10, XINPUT_GAMEPAD_LEFT_THUMB); + updateButton(11, XINPUT_GAMEPAD_RIGHT_THUMB); + updateButton(12, XINPUT_GAMEPAD_LEFT_SHOULDER); + updateButton(13, XINPUT_GAMEPAD_RIGHT_SHOULDER); + } +} + +bool Xbox360Controller::isConnected() +{ + // Zeroise the state + ZeroMemory(&state, sizeof(XINPUT_STATE)); + + // Get the state + DWORD Result = XInputGetState(num, &state); + + if(Result == ERROR_SUCCESS) + { + return true; + } + else + { + return false; + } +} + + +bool Xbox360Controller::triggerMoved(int num) +{ + if (num == 0) + return (state.Gamepad.bRightTrigger && + state.Gamepad.bRightTrigger > XINPUT_GAMEPAD_TRIGGER_THRESHOLD); + return (state.Gamepad.bLeftTrigger && + state.Gamepad.bLeftTrigger > XINPUT_GAMEPAD_TRIGGER_THRESHOLD); +} + +BYTE Xbox360Controller::getTrigger(int num) +{ + if (num == 0) + return state.Gamepad.bRightTrigger; + return state.Gamepad.bLeftTrigger; +} + +bool Xbox360Controller::thumbMoved(int num) +{ + switch(num) + { + case 0: + return !(state.Gamepad.sThumbLX < XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE && + state.Gamepad.sThumbLX > -XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE); + case 1: + return !(state.Gamepad.sThumbLY < XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE && + state.Gamepad.sThumbLY > -XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE); + case 2: + return !(state.Gamepad.sThumbRX < XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE && + state.Gamepad.sThumbRX > -XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE); + case 3: + return !(state.Gamepad.sThumbRY < XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE && + state.Gamepad.sThumbRY > -XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE); + } + + return false; +} +SHORT Xbox360Controller::getThumb(int num) +{ + switch (num) + { + case 0: + return state.Gamepad.sThumbLX; + case 1: + return state.Gamepad.sThumbLY; + case 2: + return state.Gamepad.sThumbRX; + case 3: + return state.Gamepad.sThumbRY; + } + + return 0; +} + diff --git a/tools/EventClients/Clients/Xbox360Controller/Xbox360Controller.h b/tools/EventClients/Clients/Xbox360Controller/Xbox360Controller.h new file mode 100644 index 0000000..d7a9e2a --- /dev/null +++ b/tools/EventClients/Clients/Xbox360Controller/Xbox360Controller.h @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2009-2013 Team XBMC + * + * 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 Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#pragma once + +#include <windows.h> +#include <XInput.h> // Defines XBOX controller API +#pragma comment(lib, "XInput.lib") // Library containing necessary 360 + // functions + +class Xbox360Controller +{ +private: + XINPUT_STATE state; + int num; + bool button_down[14]; + bool button_pressed[14]; + bool button_released[14]; + + XINPUT_STATE getState(); + void updateButton(int num, int button); +public: + Xbox360Controller(int num); + void updateState(); + bool isConnected(); + bool buttonPressed(int num); + bool buttonReleased(int num); + bool thumbMoved(int num); + SHORT getThumb(int num); + bool triggerMoved(int num); + BYTE getTrigger(int num); +}; diff --git a/tools/EventClients/Clients/Xbox360Controller/Xbox360EventClient.cpp b/tools/EventClients/Clients/Xbox360Controller/Xbox360EventClient.cpp new file mode 100644 index 0000000..106befb --- /dev/null +++ b/tools/EventClients/Clients/Xbox360Controller/Xbox360EventClient.cpp @@ -0,0 +1,159 @@ +/* + * Copyright (C) 2009-2013 Team XBMC + * + * 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 Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +// Xbox360EventClient.cpp : Defines the entry point for the console application. +// + +#include "stdafx.h" +#include "Xbox360Controller.h" +#include "../../lib/c++/xbmcclient.h" +#pragma comment(lib, "wsock32.lib") // needed for xbmclient.h? + +// You can have up to 4 xbox360 controllers on a system +#define MAX_NUM_CONTROLLERS 4 + +// global variable :( +// needed for exit event handler +CXBMCClient *client; + +BOOL exitHandler( DWORD ctrlType ) +{ + // TODO: Send BYE Packet + delete client; + + WSACleanup(); + + return FALSE; +} + +void checkTrigger(Xbox360Controller &cont, CXBMCClient *client, int num, const char* name) +{ + if (cont.triggerMoved(num)) + { + client->SendButton(name, "XG", 0x20, cont.getTrigger(num) * 128); + } +} + +void checkThumb(Xbox360Controller &cont, CXBMCClient *client, int num, + const char* leftname, const char* rightname) +{ + if (cont.thumbMoved(num)) + { + if (cont.getThumb(num) < 0) + { + client->SendButton(leftname, "XG", 0x20, -cont.getThumb(num)); + } + else + { + client->SendButton(rightname, "XG", 0x20, cont.getThumb(num)); + } + } +} + +void checkButton(Xbox360Controller &cont, CXBMCClient *client, int num, const char* name) +{ + if (cont.buttonPressed(num)) + { + client->SendButton(name, "XG", 0x02); + } + else if (cont.buttonReleased(num)) + { + client->SendButton(name, "XG", 0x04); + } +} + +void checkAll(Xbox360Controller &cont) +{ + if (cont.isConnected()) + { + cont.updateState(); + checkButton(cont, client, 0, "a"); + checkButton(cont, client, 1, "b"); + checkButton(cont, client, 2, "x"); + checkButton(cont, client, 3, "y"); + checkButton(cont, client, 4, "dpadup"); + checkButton(cont, client, 5, "dpaddown"); + checkButton(cont, client, 6, "dpadleft"); + checkButton(cont, client, 7, "dpadright"); + checkButton(cont, client, 8, "start"); + checkButton(cont, client, 9, "back"); + checkButton(cont, client, 10, "leftthumbbutton"); + checkButton(cont, client, 11, "rightthumbbutton"); + checkButton(cont, client, 12, "white"); + checkButton(cont, client, 13, "black"); + checkTrigger(cont, client, 0, "rightanalogtrigger"); + checkTrigger(cont, client, 1, "leftanalogtrigger"); + checkThumb(cont, client, 0, "leftthumbstickleft", "leftthumbstickright"); + checkThumb(cont, client, 1, "leftthumbstickdown", "leftthumbstickup"); + checkThumb(cont, client, 2, "rightthumbstickleft", "rightthumbstickright"); + checkThumb(cont, client, 3, "rightthumbstickdown", "rightthumbstickup"); + } +} + +int main(int argc, char* argv[]) +{ + char *host = "localhost"; + char *port = "9777"; + Xbox360Controller *controllers[MAX_NUM_CONTROLLERS]; + int i; + + // Get access to all potential controllers + for ( i = 0; i < MAX_NUM_CONTROLLERS; i++) + { + controllers[i] = new Xbox360Controller(i); + } + + // Start Winsock stuff + WSADATA wsaData; + WSAStartup(MAKEWORD(2, 2), &wsaData); + + if ( argc > 3 ) + { + printf("USAGE: %s [HOST [PORT]]\n\nThe event client connects to the XBMC EventServer at HOST:PORT.\ + Default value for HOST is localhost, default value for port is 9777.\n", argv[0]); + return -1; + } + + if ( argc > 1 ) + { + host = argv[1]; + } + + if ( argc > 2 ) + { + port = argv[2]; + } + + client = new CXBMCClient(host, atoi(port)); + + SetConsoleCtrlHandler( (PHANDLER_ROUTINE) exitHandler, TRUE); + + client->SendHELO("Xbox 360 Controller", 0); + + while(true) + { + // Check each controller for activity + for ( i = 0; i < MAX_NUM_CONTROLLERS; i++ ) + { + checkAll(*controllers[i]); + } + Sleep(10); + } + + return 0; +} diff --git a/tools/EventClients/Clients/Xbox360Controller/Xbox360EventClient.vcproj b/tools/EventClients/Clients/Xbox360Controller/Xbox360EventClient.vcproj new file mode 100644 index 0000000..3a5a8b6 --- /dev/null +++ b/tools/EventClients/Clients/Xbox360Controller/Xbox360EventClient.vcproj @@ -0,0 +1,208 @@ +<?xml version="1.0" encoding="UTF-8"?> +<VisualStudioProject + ProjectType="Visual C++" + Version="9,00" + Name="Xbox360EventClient" + ProjectGUID="{19E7A234-4F29-4828-BBC7-E3564AB57EF0}" + Keyword="Win32Proj" + TargetFrameworkVersion="0" + > + <Platforms> + <Platform + Name="Win32" + /> + </Platforms> + <ToolFiles> + </ToolFiles> + <Configurations> + <Configuration + Name="Debug|Win32" + OutputDirectory="Debug" + IntermediateDirectory="Debug" + ConfigurationType="1" + > + <Tool + Name="VCPreBuildEventTool" + /> + <Tool + Name="VCCustomBuildTool" + /> + <Tool + Name="VCXMLDataGeneratorTool" + /> + <Tool + Name="VCWebServiceProxyGeneratorTool" + /> + <Tool + Name="VCMIDLTool" + /> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;" + MinimalRebuild="true" + BasicRuntimeChecks="3" + RuntimeLibrary="3" + UsePrecompiledHeader="0" + WarningLevel="3" + Detect64BitPortabilityProblems="true" + DebugInformationFormat="4" + /> + <Tool + Name="VCManagedResourceCompilerTool" + /> + <Tool + Name="VCResourceCompilerTool" + /> + <Tool + Name="VCPreLinkEventTool" + /> + <Tool + Name="VCLinkerTool" + LinkIncremental="2" + GenerateDebugInformation="true" + SubSystem="1" + TargetMachine="1" + /> + <Tool + Name="VCALinkTool" + /> + <Tool + Name="VCManifestTool" + /> + <Tool + Name="VCXDCMakeTool" + /> + <Tool + Name="VCBscMakeTool" + /> + <Tool + Name="VCFxCopTool" + /> + <Tool + Name="VCAppVerifierTool" + /> + <Tool + Name="VCPostBuildEventTool" + /> + </Configuration> + <Configuration + Name="Release|Win32" + OutputDirectory="Release" + IntermediateDirectory="Release" + ConfigurationType="1" + > + <Tool + Name="VCPreBuildEventTool" + /> + <Tool + Name="VCCustomBuildTool" + /> + <Tool + Name="VCXMLDataGeneratorTool" + /> + <Tool + Name="VCWebServiceProxyGeneratorTool" + /> + <Tool + Name="VCMIDLTool" + /> + <Tool + Name="VCCLCompilerTool" + PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE;" + RuntimeLibrary="2" + UsePrecompiledHeader="0" + WarningLevel="3" + Detect64BitPortabilityProblems="true" + DebugInformationFormat="3" + /> + <Tool + Name="VCManagedResourceCompilerTool" + /> + <Tool + Name="VCResourceCompilerTool" + /> + <Tool + Name="VCPreLinkEventTool" + /> + <Tool + Name="VCLinkerTool" + LinkIncremental="2" + GenerateDebugInformation="true" + SubSystem="1" + OptimizeReferences="2" + EnableCOMDATFolding="2" + TargetMachine="1" + /> + <Tool + Name="VCALinkTool" + /> + <Tool + Name="VCManifestTool" + /> + <Tool + Name="VCXDCMakeTool" + /> + <Tool + Name="VCBscMakeTool" + /> + <Tool + Name="VCFxCopTool" + /> + <Tool + Name="VCAppVerifierTool" + /> + <Tool + Name="VCPostBuildEventTool" + /> + </Configuration> + </Configurations> + <References> + </References> + <Files> + <Filter + Name="Header Files" + Filter="h;hpp;hxx;hm;inl;inc;xsd" + UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}" + > + <File + RelativePath=".\stdafx.h" + > + </File> + <File + RelativePath=".\targetver.h" + > + </File> + <File + RelativePath=".\Xbox360Controller.h" + > + </File> + </Filter> + <Filter + Name="Resource Files" + Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx" + UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}" + > + </Filter> + <Filter + Name="Source Files" + Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx" + UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}" + > + <File + RelativePath=".\stdafx.cpp" + > + </File> + <File + RelativePath=".\Xbox360Controller.cpp" + > + </File> + <File + RelativePath=".\Xbox360EventClient.cpp" + > + </File> + </Filter> + </Files> + <Globals> + </Globals> +</VisualStudioProject> diff --git a/tools/EventClients/Clients/Xbox360Controller/stdafx.cpp b/tools/EventClients/Clients/Xbox360Controller/stdafx.cpp new file mode 100644 index 0000000..648e7e6 --- /dev/null +++ b/tools/EventClients/Clients/Xbox360Controller/stdafx.cpp @@ -0,0 +1,8 @@ +// stdafx.cpp : source file that includes just the standard includes +// Xbox360EventClient.pch will be the pre-compiled header +// stdafx.obj will contain the pre-compiled type information + +#include "stdafx.h" + +// TODO: reference any additional headers you need in STDAFX.H +// and not in this file diff --git a/tools/EventClients/Clients/Xbox360Controller/stdafx.h b/tools/EventClients/Clients/Xbox360Controller/stdafx.h new file mode 100644 index 0000000..b005a83 --- /dev/null +++ b/tools/EventClients/Clients/Xbox360Controller/stdafx.h @@ -0,0 +1,15 @@ +// stdafx.h : include file for standard system include files, +// or project specific include files that are used frequently, but +// are changed infrequently +// + +#pragma once + +#include "targetver.h" + +#include <stdio.h> +#include <tchar.h> + + + +// TODO: reference additional headers your program requires here diff --git a/tools/EventClients/Clients/Xbox360Controller/targetver.h b/tools/EventClients/Clients/Xbox360Controller/targetver.h new file mode 100644 index 0000000..5697f1a --- /dev/null +++ b/tools/EventClients/Clients/Xbox360Controller/targetver.h @@ -0,0 +1,13 @@ +#pragma once + +// The following macros define the minimum required platform. The minimum required platform +// is the earliest version of Windows, Internet Explorer etc. that has the necessary features to run +// your application. The macros work by enabling all features available on platform versions up to and +// including the version specified. + +// Modify the following defines if you have to target a platform prior to the ones specified below. +// Refer to MSDN for the latest info on corresponding values for different platforms. +#ifndef _WIN32_WINNT // Specifies that the minimum required platform is Windows Vista. +#define _WIN32_WINNT 0x0600 // Change this to the appropriate value to target other versions of Windows. +#endif + diff --git a/tools/EventClients/README.txt b/tools/EventClients/README.txt new file mode 100644 index 0000000..51dcab1 --- /dev/null +++ b/tools/EventClients/README.txt @@ -0,0 +1,90 @@ +Event Client Examples and PS3 Sixaxis and Blu-Ray Remote Support +---------------------------------------------------------------- + +This directory contains 6 sample programs that demonstrate XBMC's +event server (which is still in development). The programs are in +Python and C++. XBMC also needs to be running (obviously) so that it +can receive the events. + +- example_button1.py | example_button1.cpp +- example_button2.py | example_button2.cpp +- example_notification.py | example_notification.cpp + +The first 2 show how button / key presses can be sent to XBMC. +The third one shows how to display notifications in XBMC. + +- xbmcclient.py +- xbmcclient.h + +These are the Python module and C++ header that you can use when +writing your own programs. It is not yet complete and likely to change +but is still usable. + +Implementation details can be found in the comments in the sample +programs. + + +PS3 Controller and PS3 Blu-Ray Remote Support +--------------------------------------------- + +There is also initial support for the PS3 controller (sixaxis) and the +PS3 Blu-Ray remote. + +Pairing of the PS3 Blu-Ray Remote +--------------------------------- + +The remote needs to be paired initially with the 'ps3_remote.py' +program in this directory which you can continue using if you do not +want to run 'ps3d.py' as root. The disadvantage of using +'ps3_remote.py' is that pairing is required on every run. Once initial +pairing is done, 'ps3d.py', when run as root, will automatically +detect incoming connections from both the PS3 remote and the Sixaxis +controller. + +Pairing of the PS3 Sixaxis Controller (TODO) +-------------------------------------------- + +The pairing of the PS3 controller is not yet handled automatically. It +can however be done using the program "sixaxis.c" available from: + +http://www.pabr.org/sixlinux/sixlinux.en.html + +Once pairing for either or both has been done, run the ps3d.py program +as root after disabling any existing HID servers that might currently +be running. The program requires root privileges since it listens on +Bluetooth L2CAP PSMs 17 and 19. + +Using the PS3 Sixaxis Controller +-------------------------------- + +Currently, all that is supported with the Sixaxis controller is to be able +emulate the mouse behavior. Hold down the PS button and wave the controller +around and watch the mouse in XBMC mouse. Tilt it from left to right (along +your Z axis) to control horizontal motion. Tilt it towards and away from you +along (along your X axis) to control vertical mouse movement. + +That's all for now. + +WiiRemote Support +----------------- + +The executable depends on libcwiid and libbluetooth and is compiled using +# g++ WiiRemote.cpp -lcwiid -o WiiRemote +The WiiRemote will emulate mouse by default but can be disabled by running with --disable-mouseemulation +The sensitivity of the mouseemulation can be set using the --deadzone_x or --deadzone_y where the number is +the percentage of the space is considered "dead", higher means more sensitive. +Other commands can be listed with --help + +The WiiRemote is mappable with keymap.xml where button id's are the following: +1 = Up +2 = Down +3 = Left +4 = Right +5 = A +6 = B +7 = Minus +8 = Home +9 = Plus +10 = 1 +11 = 2 +The name is by standard WiiRemote but this can be changed with the --joystick-name diff --git a/tools/EventClients/examples/c#/XBMCDemoClient1.cs b/tools/EventClients/examples/c#/XBMCDemoClient1.cs new file mode 100644 index 0000000..df74dea --- /dev/null +++ b/tools/EventClients/examples/c#/XBMCDemoClient1.cs @@ -0,0 +1,47 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Windows.Forms; +using XBMC; + +namespace XBMCEventClientDemo +{ + static class Program + { + /// <summary> + /// The main entry point for the application. + /// </summary> + [STAThread] + static void Main() + { + EventClient eventClient = new EventClient(); + eventClient.Connect("127.0.0.1", 9777); + + string iconFile = @"../../icons/icon.png"; + IconType iconType = IconType.ICON_PNG; + + if !File.Exists(iconFile) { + iconFile = @"/usr/share/xbmc/media/icon.png"; + if !File.Exists(iconFile) { + iconType = IconType.ICON_NONE; + } + } + + eventClient.SendHelo("XBMC Client Demo", iconType, iconFile); + System.Threading.Thread.Sleep(1000); + eventClient.SendNotification("XBMC Client Demo", "Notification Message", iconType, iconFile); + System.Threading.Thread.Sleep(1000); + eventClient.SendButton("dpadup", "XG", ButtonFlagsType.BTN_DOWN | ButtonFlagsType.BTN_NO_REPEAT, 0); + System.Threading.Thread.Sleep(1000); + eventClient.SendPing(); + System.Threading.Thread.Sleep(1000); + eventClient.SendMouse(32768, 32768); + System.Threading.Thread.Sleep(1000); + eventClient.SendLog(LogTypeEnum.LOGERROR, "Example error log message from XBMC Client Demo"); + System.Threading.Thread.Sleep(1000); + eventClient.SendAction("Mute"); + System.Threading.Thread.Sleep(1000); + eventClient.SendBye(); + } + } +} diff --git a/tools/EventClients/examples/c++/example_button1.cpp b/tools/EventClients/examples/c++/example_button1.cpp new file mode 100644 index 0000000..d96f268 --- /dev/null +++ b/tools/EventClients/examples/c++/example_button1.cpp @@ -0,0 +1,65 @@ +#include "../../lib/c++/xbmcclient.h" +#include <stdio.h> +#include <string.h> +#include <sys/socket.h> +#ifdef _WIN32 +#include <Windows.h> // for sleep +#else +#include <unistd.h> +#endif + +int main(int argc, char **argv) +{ + /* connect to localhost, port 9777 using a UDP socket + this only needs to be done once. + by default this is where XBMC will be listening for incoming + connections. */ + CAddress my_addr; // Address => localhost on 9777 + int sockfd = socket(AF_INET, SOCK_DGRAM, 0); + if (sockfd < 0) + { + printf("Error creating socket\n"); + return -1; + } + + my_addr.Bind(sockfd); + + std::string sIconFile = "../../icons/bluetooth.png"; + unsigned short usIconType = ICON_PNG; + + std::ifstream file (sIconFile, std::ios::in|std::ios::binary|std::ios::ate); + if (!file.is_open()) + { + sIconFile = "/usr/share/pixmaps/kodi/bluetooth.png"; + file.open(sIconFile, std::ios::in|std::ios::binary|std::ios::ate); + + if (!file.is_open()) { + usIconType = ICON_NONE; + } + else + { + file.close(); + } + } + else + { + file.close(); + } + + CPacketHELO HeloPackage("Example Remote", usIconType, sIconFile.c_str()); + HeloPackage.Send(sockfd, my_addr); + + sleep(5); + // press 'S' + CPacketBUTTON btn1('S', true); + btn1.Send(sockfd, my_addr); + + sleep(2); + // press the enter key (13 = enter) + CPacketBUTTON btn2(13, true); + btn2.Send(sockfd, my_addr); + + // BYE is not required since XBMC would have shut down + CPacketBYE bye; // CPacketPing if you want to ping + bye.Send(sockfd, my_addr); +} diff --git a/tools/EventClients/examples/c++/example_button2.cpp b/tools/EventClients/examples/c++/example_button2.cpp new file mode 100644 index 0000000..ddb55be --- /dev/null +++ b/tools/EventClients/examples/c++/example_button2.cpp @@ -0,0 +1,75 @@ +#include "../../lib/c++/xbmcclient.h" +#include <stdio.h> +#include <string.h> +#include <sys/socket.h> +#ifdef _WIN32 +#include <Windows.h> // for sleep +#else +#include <unistd.h> +#endif + +int main(int argc, char **argv) +{ + /* connect to localhost, port 9777 using a UDP socket + this only needs to be done once. + by default this is where XBMC will be listening for incoming + connections. */ + CAddress my_addr; // Address => localhost on 9777 + int sockfd = socket(AF_INET, SOCK_DGRAM, 0); + if (sockfd < 0) + { + printf("Error creating socket\n"); + return -1; + } + + my_addr.Bind(sockfd); + + std::string sIconFile = "../../icons/bluetooth.png"; + unsigned short usIconType = ICON_PNG; + + std::ifstream file (sIconFile, std::ios::in|std::ios::binary|std::ios::ate); + if (!file.is_open()) + { + sIconFile = "/usr/share/pixmaps/kodi/bluetooth.png"; + file.open(sIconFile, std::ios::in|std::ios::binary|std::ios::ate); + + if (!file.is_open()) { + usIconType = ICON_NONE; + } + else + { + file.close(); + } + } + else + { + file.close(); + } + + CPacketHELO HeloPackage("Example Remote", usIconType, sIconFile.c_str()); + HeloPackage.Send(sockfd, my_addr); + + sleep(5); + // Note that we have foo(BUTTON, DEVICEMAP); + CPacketBUTTON btn1("dpadup", "XG", 0); + btn1.Send(sockfd, my_addr); + + sleep(5); + + CPacketBUTTON btn2(0x28, 0); + btn2.Send(sockfd, my_addr); + + sleep(5); + + CPacketBUTTON btn3("right", "KB", 0); + btn3.Send(sockfd, my_addr); + + sleep(5); + // Release button + CPacketBUTTON btn4; + btn4.Send(sockfd, my_addr); + + // BYE is not required since XBMC would have shut down + CPacketBYE bye; // CPacketPing if you want to ping + bye.Send(sockfd, my_addr); +} diff --git a/tools/EventClients/examples/c++/example_log.cpp b/tools/EventClients/examples/c++/example_log.cpp new file mode 100644 index 0000000..ca61cb0 --- /dev/null +++ b/tools/EventClients/examples/c++/example_log.cpp @@ -0,0 +1,39 @@ +#include "../../lib/c++/xbmcclient.h" +#include <stdio.h> +#include <string.h> +#include <sys/socket.h> +#ifdef _WIN32 +#include <Windows.h> // for sleep +#else +#include <unistd.h> +#endif + +int main(int argc, char **argv) +{ + /* connect to localhost, port 9777 using a UDP socket + this only needs to be done once. + by default this is where XBMC will be listening for incoming + connections. */ + + CAddress my_addr; // Address => localhost on 9777 + int sockfd = socket(AF_INET, SOCK_DGRAM, 0); + if (sockfd < 0) + { + printf("Error creating socket\n"); + return -1; + } + + my_addr.Bind(sockfd); + //Normally this is already done by the client + CPacketHELO HeloPackage("LOG Test", ICON_NONE); + HeloPackage.Send(sockfd, my_addr); + + sleep(5); + //This works as XBMC internal CLog::LOG(LOGTYPE, STRING); + CPacketLOG packet(LOGERROR, "The Log Message"); + packet.Send(sockfd, my_addr); + + // BYE is not required since XBMC would have shut down + CPacketBYE bye; // CPacketPing if you want to ping + bye.Send(sockfd, my_addr); +} diff --git a/tools/EventClients/examples/c++/example_mouse.cpp b/tools/EventClients/examples/c++/example_mouse.cpp new file mode 100644 index 0000000..a0c5832 --- /dev/null +++ b/tools/EventClients/examples/c++/example_mouse.cpp @@ -0,0 +1,63 @@ +#include "../../lib/c++/xbmcclient.h" +#include <stdio.h> +#include <string.h> +#include <sys/socket.h> +#ifdef _WIN32 +#include <Windows.h> // for sleep +#else +#include <unistd.h> +#endif + +int main(int argc, char **argv) +{ + /* connect to localhost, port 9777 using a UDP socket + this only needs to be done once. + by default this is where XBMC will be listening for incoming + connections. */ + CAddress my_addr; // Address => localhost on 9777 + int sockfd = socket(AF_INET, SOCK_DGRAM, 0); + if (sockfd < 0) + { + printf("Error creating socket\n"); + return -1; + } + + my_addr.Bind(sockfd); + + std::string sIconFile = "../../icons/mouse.png"; + unsigned short usIconType = ICON_PNG; + + std::ifstream file (sIconFile, std::ios::in|std::ios::binary|std::ios::ate); + if (!file.is_open()) + { + sIconFile = "/usr/share/pixmaps/kodi/mouse.png"; + file.open(sIconFile, std::ios::in|std::ios::binary|std::ios::ate); + + if (!file.is_open()) { + usIconType = ICON_NONE; + } + else + { + file.close(); + } + } + else + { + file.close(); + } + + CPacketHELO HeloPackage("Example Mouse", usIconType, sIconFile.c_str()); + HeloPackage.Send(sockfd, my_addr); + + sleep(5); + + for(int i = 0; i < 65536; i++) + { + CPacketMOUSE mouse(i,i); + mouse.Send(sockfd, my_addr); + } + + // BYE is not required since XBMC would have shut down + CPacketBYE bye; // CPacketPing if you want to ping + bye.Send(sockfd, my_addr); +} diff --git a/tools/EventClients/examples/c++/example_notification.cpp b/tools/EventClients/examples/c++/example_notification.cpp new file mode 100644 index 0000000..5cd0657 --- /dev/null +++ b/tools/EventClients/examples/c++/example_notification.cpp @@ -0,0 +1,64 @@ +#include "../../lib/c++/xbmcclient.h" +#include <stdio.h> +#include <string.h> +#include <sys/socket.h> +#ifdef _WIN32 +#include <Windows.h> // for sleep +#else +#include <unistd.h> +#endif + +int main(int argc, char **argv) +{ + /* connect to localhost, port 9777 using a UDP socket + this only needs to be done once. + by default this is where XBMC will be listening for incoming + connections. */ + + CAddress my_addr; // Address => localhost on 9777 + int sockfd = socket(AF_INET, SOCK_DGRAM, 0); + if (sockfd < 0) + { + printf("Error creating socket\n"); + return -1; + } + + my_addr.Bind(sockfd); + + std::string sIconFile = "../../icons/mail.png"; + unsigned short usIconType = ICON_PNG; + + std::ifstream file (sIconFile, std::ios::in|std::ios::binary|std::ios::ate); + if (!file.is_open()) + { + sIconFile = "/usr/share/pixmaps/kodi/mail.png"; + file.open(sIconFile, std::ios::in|std::ios::binary|std::ios::ate); + + if (!file.is_open()) { + usIconType = ICON_NONE; + } + else + { + file.close(); + } + } + else + { + file.close(); + } + + CPacketHELO HeloPackage("Email Notifier", ICON_NONE); + HeloPackage.Send(sockfd, my_addr); + + sleep(5); + + CPacketNOTIFICATION packet("New Mail!", // caption + "RE: Check this out", // message + usIconType, // optional icon type + sIconFile.c_str()); // icon file (local) + packet.Send(sockfd, my_addr); + + // BYE is not required since XBMC would have shut down + CPacketBYE bye; // CPacketPing if you want to ping + bye.Send(sockfd, my_addr); +} diff --git a/tools/EventClients/examples/java/XBMCDemoClient1.java b/tools/EventClients/examples/java/XBMCDemoClient1.java new file mode 100644 index 0000000..5bb2821 --- /dev/null +++ b/tools/EventClients/examples/java/XBMCDemoClient1.java @@ -0,0 +1,70 @@ +package org.xbmc.eventclient.demo; + +import java.io.File; +import java.io.IOException; +import java.net.Inet4Address; +import java.net.InetAddress; + +import org.xbmc.eventclient.XBMCClient; + +/** + * Simple Demo EventClient + * @author Stefan Agner + * + */ +public class XBMCDemoClient1 { + + /** + * Simple Demo EventClient + * @param args + */ + public static void main(String[] args) throws IOException, InterruptedException { + InetAddress host = Inet4Address.getByAddress(new byte[] { (byte)127, 0, 0, 1 } ); + + Thread.sleep(20000); + + String iconFile = "/usr/share/xbmc/media/icon.png"; + + if (! new File(iconFile).exists()) { + iconFile = "../../icons/icon.png"; + + if (! new File(iconFile).exists()) { + iconFile = ""; + } + } + + XBMCClient oXBMCClient = null; + + if (iconFile != "") { + oXBMCClient = new XBMCClient(host, 9777, "My Client", iconFile); + } else { + oXBMCClient = new XBMCClient(host, 9777, "My Client"); + } + + Thread.sleep(7000); + + oXBMCClient.sendNotification("My Title", "My Message"); + + + Thread.sleep(7000); + + oXBMCClient.sendButton("KB", "escape", false, true, false, (short)0 , (byte)0); + + + Thread.sleep(7000); + oXBMCClient.sendButton("KB", "escape", true, true, false, (short)0 , (byte)0); + oXBMCClient.sendNotification("My Title", "Escape sent"); + + Thread.sleep(1000); + + oXBMCClient.sendButton("KB", "escape", true, false, false, (short)0 , (byte)0); + oXBMCClient.sendNotification("My Title", "Escape released"); + + Thread.sleep(7000); + oXBMCClient.sendLog((byte)0, "My Client disconnects...."); + oXBMCClient.sendNotification("My Title", "Client will disconnect"); + oXBMCClient.stopClient(); + + } + +} diff --git a/tools/EventClients/examples/python/example_action.py b/tools/EventClients/examples/python/example_action.py new file mode 100755 index 0000000..b87fc29 --- /dev/null +++ b/tools/EventClients/examples/python/example_action.py @@ -0,0 +1,51 @@ +#!/usr/bin/env python3 + +# This is a simple example showing how you can send a key press event +# to XBMC using the XBMCClient class + +import os +from socket import * +import sys + +if os.path.exists("../../lib/python"): + # try loading modules from source directory + sys.path.append("../../lib/python") + + from xbmcclient import * + + ICON_PATH = "../../icons/" +else: + # fallback to system wide modules + + from kodi.xbmcclient import * + from kodi.defs import * + +def main(): + + host = "localhost" + port = 9777 + + # Create an XBMCClient object and connect + xbmc = XBMCClient("Example Remote", ICON_PATH + "/bluetooth.png") + xbmc.connect() + + # send a up key press using the xbox gamepad map "XG" and button + # name "dpadup" ( see PacketBUTTON doc for more details) + try: + xbmc.send_action(sys.argv[2], ACTION_BUTTON) + except: + try: + xbmc.send_action(sys.argv[1], ACTION_EXECBUILTIN) + except Exception as e: + print(str(e)) + xbmc.send_action("ActivateWindow(ShutdownMenu)") + + + # ok we're done, close the connection + # Note that closing the connection clears any repeat key that is + # active. So in this example, the actual release button event above + # need not have been sent. + xbmc.close() + +if __name__=="__main__": + main() diff --git a/tools/EventClients/examples/python/example_button1.py b/tools/EventClients/examples/python/example_button1.py new file mode 100755 index 0000000..abdfe49 --- /dev/null +++ b/tools/EventClients/examples/python/example_button1.py @@ -0,0 +1,90 @@ +#!/usr/bin/env python3 + +# This is a simple example showing how you can send 2 button events +# to XBMC in a queued fashion to shut it down. + +# Queued button events are not repeatable. + +# The basic idea is to create single packets and shoot them to XBMC +# The provided library implements some of the support commands and +# takes care of creating the actual packet. Using it is as simple +# as creating an object with the required constructor arguments and +# sending it through a socket. + +# Currently, only keyboard keys are supported so the key codes used +# below are the same key codes used in guilib/common/SDLKeyboard.cpp + +# In effect, anything that can be done with the keyboard can be done +# using the event client. + +# import the XBMC client library +# NOTE: The library is not complete yet but is usable at this stage. + +import os +from socket import * +import sys + +if os.path.exists("../../lib/python"): + # try loading modules from source directory + sys.path.append("../../lib/python") + + from xbmcclient import * + + ICON_PATH = "../../icons/" +else: + # fallback to system wide modules + + from kodi.xbmcclient import * + from kodi.defs import * + +def main(): + import time + import sys + + # connect to localhost, port 9777 using a UDP socket + # this only needs to be done once. + # by default this is where XBMC will be listening for incoming + # connections. + host = "localhost" + port = 9777 + addr = (host, port) + sock = socket(AF_INET,SOCK_DGRAM) + + # First packet must be HELO (no it's not a typo) and can contain an icon + # 'icon_type' can be one of ICON_NONE, ICON_PNG, ICON_JPG or ICON_GIF + packet = PacketHELO(devicename="Example Remote", + icon_type=ICON_PNG, + icon_file=ICON_PATH + "/bluetooth.png") + packet.send(sock, addr) + + # IMPORTANT: After a HELO packet is sent, the client needs to "ping" XBMC + # at least once every 60 seconds or else the client will time out. + # Every valid packet sent to XBMC acts as a ping, however if no valid + # packets NEED to be sent (eg. the user hasn't pressed a key in 50 seconds) + # then you can use the PacketPING class to send a ping packet (which is + # basically just an empty packet). See below. + + # Once a client times out, it will need to reissue the HELO packet. + # Currently, since this is a unidirectional protocol, there is no way + # for the client to know if it has timed out. + + # wait for notification window to close (in XBMC) + time.sleep(5) + + # press 'S' + packet = PacketBUTTON(code='S', queue=1) + packet.send(sock, addr) + + # wait for a few seconds + time.sleep(2) + + # press the enter key (13 = enter) + packet = PacketBUTTON(code=13, queue=1) + packet.send(sock, addr) + + # BYE is not required since XBMC would have shut down + packet = PacketBYE() # PacketPING if you want to ping + packet.send(sock, addr) + +if __name__=="__main__": + main() diff --git a/tools/EventClients/examples/python/example_button2.py b/tools/EventClients/examples/python/example_button2.py new file mode 100755 index 0000000..bb91704 --- /dev/null +++ b/tools/EventClients/examples/python/example_button2.py @@ -0,0 +1,84 @@ +#!/usr/bin/env python3 + +# This is a simple example showing how you can send a key press event +# to XBMC in a non-queued fashion to achieve a button pressed down +# event i.e. a key press that repeats. + +# The repeat interval is currently hard coded in XBMC but that might +# change in the future. + +# NOTE: Read the comments in 'example_button1.py' for a more detailed +# explanation. + +import os +from socket import * +import sys + +if os.path.exists("../../lib/python"): + # try loading modules from source directory + sys.path.append("../../lib/python") + + from xbmcclient import * + + ICON_PATH = "../../icons/" +else: + # fallback to system wide modules + + from kodi.xbmcclient import * + from kodi.defs import * + +def main(): + import time + import sys + + host = "localhost" + port = 9777 + addr = (host, port) + + sock = socket(AF_INET,SOCK_DGRAM) + + # First packet must be HELO and can contain an icon + packet = PacketHELO("Example Remote", ICON_PNG, + ICON_PATH + "/bluetooth.png") + packet.send(sock, addr) + + # wait for notification window to close (in XBMC) + time.sleep(5) + + # send a up key press using the xbox gamepad map "XG" and button + # name "dpadup" ( see PacketBUTTON doc for more details) + packet = PacketBUTTON(map_name="XG", button_name="dpadup") + packet.send(sock, addr) + + # wait for a few seconds to see its effect + time.sleep(5) + + # send a down key press using the raw keyboard code + packet = PacketBUTTON(code=0x28) + packet.send(sock, addr) + + # wait for a few seconds to see its effect + time.sleep(5) + + # send a right key press using the keyboard map "KB" and button + # name "right" + packet = PacketBUTTON(map_name="KB", button_name="right") + packet.send(sock, addr) + + # wait for a few seconds to see its effect + time.sleep(5) + + # that's enough, release the button. During release, button code + # doesn't matter. + packet = PacketBUTTON(code=0x28, down=0) + packet.send(sock, addr) + + # ok we're done, close the connection + # Note that closing the connection clears any repeat key that is + # active. So in this example, the actual release button event above + # need not have been sent. + packet = PacketBYE() + packet.send(sock, addr) + +if __name__=="__main__": + main() diff --git a/tools/EventClients/examples/python/example_mouse.py b/tools/EventClients/examples/python/example_mouse.py new file mode 100755 index 0000000..7c43782 --- /dev/null +++ b/tools/EventClients/examples/python/example_mouse.py @@ -0,0 +1,56 @@ +#!/usr/bin/env python3 + +# This is a simple example showing how you can send mouse movement +# events to XBMC. + +# NOTE: Read the comments in 'example_button1.py' for a more detailed +# explanation. + +import os +from socket import * +import sys + +if os.path.exists("../../lib/python"): + # try loading modules from source directory + sys.path.append("../../lib/python") + + from xbmcclient import * + + ICON_PATH = "../../icons/" +else: + # fallback to system wide modules + + from kodi.xbmcclient import * + from kodi.defs import * + +def main(): + import time + import sys + + host = "localhost" + port = 9777 + addr = (host, port) + + sock = socket(AF_INET,SOCK_DGRAM) + + # First packet must be HELO and can contain an icon + packet = PacketHELO("Example Mouse", ICON_PNG, + ICON_PATH + "/mouse.png") + packet.send(sock, addr) + + # wait for notification window to close (in XBMC) + time.sleep(2) + + # send mouse events to take cursor from top left to bottom right of the screen + # here 0 to 65535 will map to XBMC's screen width and height. + # Specifying absolute mouse coordinates is unsupported currently. + for i in range(0, 65535, 2): + packet = PacketMOUSE(i,i) + packet.send(sock, addr) + + # ok we're done, close the connection + packet = PacketBYE() + packet.send(sock, addr) + +if __name__=="__main__": + main() diff --git a/tools/EventClients/examples/python/example_notification.py b/tools/EventClients/examples/python/example_notification.py new file mode 100755 index 0000000..fd1a82e --- /dev/null +++ b/tools/EventClients/examples/python/example_notification.py @@ -0,0 +1,49 @@ +#!/usr/bin/env python3 + +# This is a simple example showing how you can show a notification +# window with a custom icon inside XBMC. It could be used by mail +# monitoring apps, calendar apps, etc. + +import os +from socket import * +import sys + +if os.path.exists("../../lib/python"): + # try loading modules from source directory + sys.path.append("../../lib/python") + + from xbmcclient import * + + ICON_PATH = "../../icons/" +else: + # fallback to system wide modules + + from kodi.xbmcclient import * + from kodi.defs import * + +def main(): + import time + import sys + + host = "localhost" + port = 9777 + addr = (host, port) + sock = socket(AF_INET,SOCK_DGRAM) + + packet = PacketHELO("Email Notifier", ICON_NONE) + packet.send(sock, addr) + + # wait for 5 seconds + time.sleep (5) + + packet = PacketNOTIFICATION("New Mail!", # caption + "RE: Check this out", # message + ICON_PNG, # optional icon type + ICON_PATH + "/mail.png") # icon file (local) + packet.send(sock, addr) + + packet = PacketBYE() + packet.send(sock, addr) + +if __name__=="__main__": + main() diff --git a/tools/EventClients/examples/python/example_simple.py b/tools/EventClients/examples/python/example_simple.py new file mode 100755 index 0000000..2d807e8 --- /dev/null +++ b/tools/EventClients/examples/python/example_simple.py @@ -0,0 +1,60 @@ +#!/usr/bin/env python3 + +# This is a simple example showing how you can send a key press event +# to XBMC using the XBMCClient class + +import os +from socket import * +import sys +import time + +if os.path.exists("../../lib/python"): + # try loading modules from source directory + sys.path.append("../../lib/python") + + from xbmcclient import * + + ICON_PATH = "../../icons/" +else: + # fallback to system wide modules + + from kodi.xbmcclient import * + from kodi.defs import * + +def main(): + + host = "localhost" + port = 9777 + + # Create an XBMCClient object and connect + xbmc = XBMCClient("Example Remote", ICON_PATH + "/bluetooth.png") + xbmc.connect() + + # wait for notification window to close (in XBMC) (optional) + time.sleep(5) + + # send a up key press using the xbox gamepad map "XG" and button + # name "dpadup" ( see PacketBUTTON doc for more details) + xbmc.send_button(map="XG", button="dpadup") + + # wait for a few seconds to see its effect + time.sleep(5) + + # send a right key press using the keyboard map "KB" and button + # name "right" + xbmc.send_keyboard_button("right") + + # wait for a few seconds to see its effect + time.sleep(5) + + # that's enough, release the button. + xbmc.release_button() + + # ok we're done, close the connection + # Note that closing the connection clears any repeat key that is + # active. So in this example, the actual release button event above + # need not have been sent. + xbmc.close() + +if __name__=="__main__": + main() diff --git a/tools/EventClients/icons/bluetooth.png b/tools/EventClients/icons/bluetooth.png Binary files differnew file mode 100644 index 0000000..6b5837e --- /dev/null +++ b/tools/EventClients/icons/bluetooth.png diff --git a/tools/EventClients/icons/mail.png b/tools/EventClients/icons/mail.png Binary files differnew file mode 100644 index 0000000..8f4ea85 --- /dev/null +++ b/tools/EventClients/icons/mail.png diff --git a/tools/EventClients/icons/mouse.png b/tools/EventClients/icons/mouse.png Binary files differnew file mode 100644 index 0000000..0d0e588 --- /dev/null +++ b/tools/EventClients/icons/mouse.png diff --git a/tools/EventClients/icons/phone.png b/tools/EventClients/icons/phone.png Binary files differnew file mode 100644 index 0000000..43fb7fe --- /dev/null +++ b/tools/EventClients/icons/phone.png diff --git a/tools/EventClients/lib/c#/EventClient.cs b/tools/EventClients/lib/c#/EventClient.cs new file mode 100644 index 0000000..fe2615b --- /dev/null +++ b/tools/EventClients/lib/c#/EventClient.cs @@ -0,0 +1,555 @@ +/* + * Copyright (C) 2008-2013 Team XBMC + * + * 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 Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +using System; +using System.IO; +using System.Net; +using System.Net.Sockets; + +namespace XBMC +{ + + public enum IconType + { + ICON_NONE = 0x00, + ICON_JPEG = 0x01, + ICON_PNG = 0x02, + ICON_GIF = 0x03 + } + + public enum ButtonFlagsType + { + BTN_USE_NAME = 0x01, + BTN_DOWN = 0x02, + BTN_UP = 0x04, + BTN_USE_AMOUNT = 0x08, + BTN_QUEUE = 0x10, + BTN_NO_REPEAT = 0x20, + BTN_VKEY = 0x40, + BTN_AXIS = 0x80 + } + + public enum MouseFlagsType + { + MS_ABSOLUTE = 0x01 + } + + public enum LogTypeEnum + { + LOGDEBUG = 0, + LOGINFO = 1, + LOGNOTICE = 2, + LOGWARNING = 3, + LOGERROR = 4, + LOGSEVERE = 5, + LOGFATAL = 6, + LOGNONE = 7 + } + + public enum ActionType + { + ACTION_EXECBUILTIN = 0x01, + ACTION_BUTTON = 0x02 + } + + public class EventClient + { + + /************************************************************************/ + /* Written by Peter Tribe aka EqUiNox (TeamBlackbolt) */ + /* Based upon XBMC's xbmcclient.cpp class */ + /************************************************************************/ + + private enum PacketType + { + PT_HELO = 0x01, + PT_BYE = 0x02, + PT_BUTTON = 0x03, + PT_MOUSE = 0x04, + PT_PING = 0x05, + PT_BROADCAST = 0x06, //Currently not implemented + PT_NOTIFICATION = 0x07, + PT_BLOB = 0x08, + PT_LOG = 0x09, + PT_ACTION = 0x0A, + PT_DEBUG = 0xFF //Currently not implemented + } + + private const int STD_PORT = 9777; + private const int MAX_PACKET_SIZE = 1024; + private const int HEADER_SIZE = 32; + private const int MAX_PAYLOAD_SIZE = MAX_PACKET_SIZE - HEADER_SIZE; + private const byte MAJOR_VERSION = 2; + private const byte MINOR_VERSION = 0; + + private uint uniqueToken; + private Socket socket; + + public bool Connect(string Address) + { + return Connect(Address, STD_PORT, (uint)System.DateTime.Now.TimeOfDay.Milliseconds); + } + + public bool Connect(string Address, int Port) + { + return Connect(Address, Port, (uint)System.DateTime.Now.TimeOfDay.Milliseconds); + } + + + public bool Connect(string Address, int Port, uint UID) + { + try + { + if (socket != null) Disconnect(); + uniqueToken = UID; + socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp); + +// For compilation with .net framework 1.0 or 1.1 +// define the FRAMEWORK_1_x conditional compilation constant in the project +// or add /define:FRAMEWORK_1_x to the csc.exe command line +#if FRAMEWORK_1_x + socket.Connect(Dns.GetHostByName(Address).AddressList[0].ToString(), Port); +#else + socket.Connect(Address, Port); +#endif + return true; + } + catch + { + return false; + } + } + + public bool Connected + { + get + { + if (socket == null) return false; + return socket.Connected; + } + } + + public void Disconnect() + { + try + { + if (socket != null) + { + socket.Shutdown(SocketShutdown.Both); + socket.Close(); + socket = null; + } + } + catch + { + } + } + + private byte[] Header(PacketType PacketType, int NumberOfPackets, int CurrentPacket, int PayloadSize) + { + + byte[] header = new byte[HEADER_SIZE]; + + header[0] = (byte)'X'; + header[1] = (byte)'B'; + header[2] = (byte)'M'; + header[3] = (byte)'C'; + + header[4] = MAJOR_VERSION; + header[5] = MINOR_VERSION; + + if (CurrentPacket == 1) + { + header[6] = (byte)(((ushort)PacketType & 0xff00) >> 8); + header[7] = (byte)((ushort)PacketType & 0x00ff); + } + else + { + header[6] = (byte)(((ushort)PacketType.PT_BLOB & 0xff00) >> 8); + header[7] = (byte)((ushort)PacketType.PT_BLOB & 0x00ff); + } + + header[8] = (byte)((CurrentPacket & 0xff000000) >> 24); + header[9] = (byte)((CurrentPacket & 0x00ff0000) >> 16); + header[10] = (byte)((CurrentPacket & 0x0000ff00) >> 8); + header[11] = (byte)(CurrentPacket & 0x000000ff); + + header[12] = (byte)((NumberOfPackets & 0xff000000) >> 24); + header[13] = (byte)((NumberOfPackets & 0x00ff0000) >> 16); + header[14] = (byte)((NumberOfPackets & 0x0000ff00) >> 8); + header[15] = (byte)(NumberOfPackets & 0x000000ff); + + header[16] = (byte)((PayloadSize & 0xff00) >> 8); + header[17] = (byte)(PayloadSize & 0x00ff); + + header[18] = (byte)((uniqueToken & 0xff000000) >> 24); + header[19] = (byte)((uniqueToken & 0x00ff0000) >> 16); + header[20] = (byte)((uniqueToken & 0x0000ff00) >> 8); + header[21] = (byte)(uniqueToken & 0x000000ff); + + return header; + + } + + private bool Send(PacketType PacketType, byte[] Payload) + { + try + { + + bool successful = true; + int packetCount = (Payload.Length / MAX_PAYLOAD_SIZE) + 1; + int bytesToSend = 0; + int bytesSent = 0; + int bytesLeft = Payload.Length; + + for (int Package = 1; Package <= packetCount; Package++) + { + + if (bytesLeft > MAX_PAYLOAD_SIZE) + { + bytesToSend = MAX_PAYLOAD_SIZE; + bytesLeft -= bytesToSend; + } + else + { + bytesToSend = bytesLeft; + bytesLeft = 0; + } + + byte[] header = Header(PacketType, packetCount, Package, bytesToSend); + byte[] packet = new byte[MAX_PACKET_SIZE]; + + Array.Copy(header, 0, packet, 0, header.Length); + Array.Copy(Payload, bytesSent, packet, header.Length, bytesToSend); + + int sendSize = socket.Send(packet, header.Length + bytesToSend, SocketFlags.None); + + if (sendSize != (header.Length + bytesToSend)) + { + successful = false; + break; + } + + bytesSent += bytesToSend; + + } + + return successful; + + } + catch + { + + return false; + + } + + } + + /************************************************************************/ + /* SendHelo - Payload format */ + /* %s - device name (max 128 chars) */ + /* %c - icontype ( 0=>NOICON, 1=>JPEG , 2=>PNG , 3=>GIF ) */ + /* %s - my port ( 0=>not listening ) */ + /* %d - reserved1 ( 0 ) */ + /* %d - reserved2 ( 0 ) */ + /* XX - imagedata ( can span multiple packets ) */ + /************************************************************************/ + public bool SendHelo(string DevName, IconType IconType, string IconFile) + { + + byte[] icon = new byte[0]; + if (IconType != IconType.ICON_NONE) + icon = File.ReadAllBytes(IconFile); + + byte[] payload = new byte[DevName.Length + 12 + icon.Length]; + + int offset = 0; + + for (int i = 0; i < DevName.Length; i++) + payload[offset++] = (byte)DevName[i]; + payload[offset++] = (byte)'\0'; + + payload[offset++] = (byte)IconType; + + payload[offset++] = (byte)0; + payload[offset++] = (byte)'\0'; + + for (int i = 0; i < 8; i++) + payload[offset++] = (byte)0; + + Array.Copy(icon, 0, payload, DevName.Length + 12, icon.Length); + + return Send(PacketType.PT_HELO, payload); + + } + + public bool SendHelo(string DevName) + { + return SendHelo(DevName, IconType.ICON_NONE, ""); + } + + /************************************************************************/ + /* SendNotification - Payload format */ + /* %s - caption */ + /* %s - message */ + /* %c - icontype ( 0=>NOICON, 1=>JPEG , 2=>PNG , 3=>GIF ) */ + /* %d - reserved ( 0 ) */ + /* XX - imagedata ( can span multiple packets ) */ + /************************************************************************/ + public bool SendNotification(string Caption, string Message, IconType IconType, string IconFile) + { + + byte[] icon = new byte[0]; + if (IconType != IconType.ICON_NONE) + icon = File.ReadAllBytes(IconFile); + + byte[] payload = new byte[Caption.Length + Message.Length + 7 + icon.Length]; + + int offset = 0; + + for (int i = 0; i < Caption.Length; i++) + payload[offset++] = (byte)Caption[i]; + payload[offset++] = (byte)'\0'; + + for (int i = 0; i < Message.Length; i++) + payload[offset++] = (byte)Message[i]; + payload[offset++] = (byte)'\0'; + + payload[offset++] = (byte)IconType; + + for (int i = 0; i < 4; i++) + payload[offset++] = (byte)0; + + Array.Copy(icon, 0, payload, Caption.Length + Message.Length + 7, icon.Length); + + return Send(PacketType.PT_NOTIFICATION, payload); + + } + + public bool SendNotification(string Caption, string Message) + { + return SendNotification(Caption, Message, IconType.ICON_NONE, ""); + } + + /************************************************************************/ + /* SendButton - Payload format */ + /* %i - button code */ + /* %i - flags 0x01 => use button map/name instead of code */ + /* 0x02 => btn down */ + /* 0x04 => btn up */ + /* 0x08 => use amount */ + /* 0x10 => queue event */ + /* 0x20 => do not repeat */ + /* 0x40 => virtual key */ + /* 0x80 => axis key */ + /* %i - amount ( 0 => 65k maps to -1 => 1 ) */ + /* %s - device map (case sensitive and required if flags & 0x01) */ + /* "KB" - Standard keyboard map */ + /* "XG" - Xbox Gamepad */ + /* "R1" - Xbox Remote */ + /* "R2" - Xbox Universal Remote */ + /* "LI:devicename" - valid LIRC device map where 'devicename' */ + /* is the actual name of the LIRC device */ + /* "JS<num>:joyname" - valid Joystick device map where */ + /* 'joyname' is the name specified in */ + /* the keymap. JS only supports button code */ + /* and not button name currently (!0x01). */ + /* %s - button name (required if flags & 0x01) */ + /************************************************************************/ + private bool SendButton(string Button, ushort ButtonCode, string DeviceMap, ButtonFlagsType Flags, short Amount) + { + + if (Button.Length != 0) + { + if ((Flags & ButtonFlagsType.BTN_USE_NAME) == 0) + Flags |= ButtonFlagsType.BTN_USE_NAME; + ButtonCode = 0; + } + else + Button = ""; + + if (Amount > 0) + { + if ((Flags & ButtonFlagsType.BTN_USE_AMOUNT) == 0) + Flags |= ButtonFlagsType.BTN_USE_AMOUNT; + } + + if ((Flags & ButtonFlagsType.BTN_DOWN) == 0 && (Flags & ButtonFlagsType.BTN_UP) == 0) + Flags |= ButtonFlagsType.BTN_DOWN; + + byte[] payload = new byte[Button.Length + DeviceMap.Length + 8]; + + int offset = 0; + + payload[offset++] = (byte)((ButtonCode & 0xff00) >> 8); + payload[offset++] = (byte)(ButtonCode & 0x00ff); + + payload[offset++] = (byte)(((ushort)Flags & 0xff00) >> 8); + payload[offset++] = (byte)((ushort)Flags & 0x00ff); + + payload[offset++] = (byte)((Amount & 0xff00) >> 8); + payload[offset++] = (byte)(Amount & 0x00ff); + + for (int i = 0; i < DeviceMap.Length; i++) + payload[offset++] = (byte)DeviceMap[i]; + payload[offset++] = (byte)'\0'; + + for (int i = 0; i < Button.Length; i++) + payload[offset++] = (byte)Button[i]; + payload[offset++] = (byte)'\0'; + + return Send(PacketType.PT_BUTTON, payload); + + } + + public bool SendButton(string Button, string DeviceMap, ButtonFlagsType Flags, short Amount) + { + return SendButton(Button, 0, DeviceMap, Flags, Amount); + } + + public bool SendButton(string Button, string DeviceMap, ButtonFlagsType Flags) + { + return SendButton(Button, 0, DeviceMap, Flags, 0); + } + + public bool SendButton(ushort ButtonCode, string DeviceMap, ButtonFlagsType Flags, short Amount) + { + return SendButton("", ButtonCode, DeviceMap, Flags, Amount); + } + + public bool SendButton(ushort ButtonCode, string DeviceMap, ButtonFlagsType Flags) + { + return SendButton("", ButtonCode, DeviceMap, Flags, 0); + } + + public bool SendButton(ushort ButtonCode, ButtonFlagsType Flags, short Amount) + { + return SendButton("", ButtonCode, "", Flags, Amount); + } + + public bool SendButton(ushort ButtonCode, ButtonFlagsType Flags) + { + return SendButton("", ButtonCode, "", Flags, 0); + } + + public bool SendButton() + { + return SendButton("", 0, "", ButtonFlagsType.BTN_UP, 0); + } + + /************************************************************************/ + /* SendPing - No payload */ + /************************************************************************/ + public bool SendPing() + { + byte[] payload = new byte[0]; + return Send(PacketType.PT_PING, payload); + } + + /************************************************************************/ + /* SendBye - No payload */ + /************************************************************************/ + public bool SendBye() + { + byte[] payload = new byte[0]; + return Send(PacketType.PT_BYE, payload); + } + + /************************************************************************/ + /* SendMouse - Payload format */ + /* %c - flags */ + /* - 0x01 absolute position */ + /* %i - mousex (0-65535 => maps to screen width) */ + /* %i - mousey (0-65535 => maps to screen height) */ + /************************************************************************/ + public bool SendMouse(ushort X, ushort Y, MouseFlagsType Flags) + { + + byte[] payload = new byte[9]; + + int offset = 0; + + payload[offset++] = (byte)Flags; + + payload[offset++] = (byte)((X & 0xff00) >> 8); + payload[offset++] = (byte)(X & 0x00ff); + + payload[offset++] = (byte)((Y & 0xff00) >> 8); + payload[offset++] = (byte)(Y & 0x00ff); + + return Send(PacketType.PT_MOUSE, payload); + + } + + public bool SendMouse(ushort X, ushort Y) + { + return SendMouse(X, Y, MouseFlagsType.MS_ABSOLUTE); + } + + /************************************************************************/ + /* SendLog - Payload format */ + /* %c - log type */ + /* %s - message */ + /************************************************************************/ + public bool SendLog(LogTypeEnum LogLevel, string Message) + { + + byte[] payload = new byte[Message.Length + 2]; + + int offset = 0; + + payload[offset++] = (byte)LogLevel; + + for (int i = 0; i < Message.Length; i++) + payload[offset++] = (byte)Message[i]; + payload[offset++] = (byte)'\0'; + + return Send(PacketType.PT_LOG, payload); + + } + + /************************************************************************/ + /* SendAction - Payload format */ + /* %c - action type */ + /* %s - action message */ + /************************************************************************/ + public bool SendAction(ActionType Action, string Message) + { + + byte[] payload = new byte[Message.Length + 2]; + + int offset = 0; + + payload[offset++] = (byte)Action; + + for (int i = 0; i < Message.Length; i++) + payload[offset++] = (byte)Message[i]; + payload[offset++] = (byte)'\0'; + + return Send(PacketType.PT_ACTION, payload); + + } + + public bool SendAction(string Message) + { + return SendAction(ActionType.ACTION_EXECBUILTIN, Message); + } + + } +} diff --git a/tools/EventClients/lib/c++/xbmcclient.h b/tools/EventClients/lib/c++/xbmcclient.h new file mode 100644 index 0000000..ef9afc5 --- /dev/null +++ b/tools/EventClients/lib/c++/xbmcclient.h @@ -0,0 +1,823 @@ +/* + * Copyright (C) 2008-2015 Team Kodi + * http://kodi.tv + * + * 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, 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 Kodi; see the file COPYING. If not, see + * <http://www.gnu.org/licenses/>. + * + */ + +#pragma once + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/types.h> +#ifdef _WIN32 +#include <winsock.h> +#else +#include <sys/socket.h> +#include <netinet/in.h> +#include <netdb.h> +#include <arpa/inet.h> +#endif +#include <vector> +#include <iostream> +#include <fstream> +#include <time.h> + +#define STD_PORT 9777 + +#define MS_ABSOLUTE 0x01 +//#define MS_RELATIVE 0x02 + +#define BTN_USE_NAME 0x01 +#define BTN_DOWN 0x02 +#define BTN_UP 0x04 +#define BTN_USE_AMOUNT 0x08 +#define BTN_QUEUE 0x10 +#define BTN_NO_REPEAT 0x20 +#define BTN_VKEY 0x40 +#define BTN_AXIS 0x80 + +#define PT_HELO 0x01 +#define PT_BYE 0x02 +#define PT_BUTTON 0x03 +#define PT_MOUSE 0x04 +#define PT_PING 0x05 +#define PT_BROADCAST 0x06 +#define PT_NOTIFICATION 0x07 +#define PT_BLOB 0x08 +#define PT_LOG 0x09 +#define PT_ACTION 0x0A +#define PT_DEBUG 0xFF + +#define ICON_NONE 0x00 +#define ICON_JPEG 0x01 +#define ICON_PNG 0x02 +#define ICON_GIF 0x03 + +#define MAX_PACKET_SIZE 1024 +#define HEADER_SIZE 32 +#define MAX_PAYLOAD_SIZE (MAX_PACKET_SIZE - HEADER_SIZE) + +#define MAJOR_VERSION 2 +#define MINOR_VERSION 0 + +#define LOGDEBUG 0 +#define LOGINFO 1 +#define LOGNOTICE 2 +#define LOGWARNING 3 +#define LOGERROR 4 +#define LOGSEVERE 5 +#define LOGFATAL 6 +#define LOGNONE 7 + +#define ACTION_EXECBUILTIN 0x01 +#define ACTION_BUTTON 0x02 + +class CAddress +{ +private: + struct sockaddr_in m_Addr; +public: + CAddress(int Port = STD_PORT) + { + m_Addr.sin_family = AF_INET; + m_Addr.sin_port = htons(Port); + m_Addr.sin_addr.s_addr = INADDR_ANY; + memset(m_Addr.sin_zero, '\0', sizeof m_Addr.sin_zero); + } + + CAddress(const char *Address, int Port = STD_PORT) + { + m_Addr.sin_port = htons(Port); + + struct hostent *h; + if (Address == NULL || (h=gethostbyname(Address)) == NULL) + { + if (Address != NULL) + printf("Error: Get host by name\n"); + + m_Addr.sin_addr.s_addr = INADDR_ANY; + m_Addr.sin_family = AF_INET; + } + else + { + m_Addr.sin_family = h->h_addrtype; + m_Addr.sin_addr = *((struct in_addr *)h->h_addr); + } + memset(m_Addr.sin_zero, '\0', sizeof m_Addr.sin_zero); + } + + void SetPort(int port) + { + m_Addr.sin_port = htons(port); + } + + const sockaddr *GetAddress() + { + return ((struct sockaddr *)&m_Addr); + } + + bool Bind(int Sockfd) + { + return (bind(Sockfd, (struct sockaddr *)&m_Addr, sizeof m_Addr) == 0); + } +}; + +class XBMCClientUtils +{ +public: + XBMCClientUtils() = default; + ~XBMCClientUtils() = default; + static unsigned int GetUniqueIdentifier() + { + static time_t id = time(NULL); + return id; + } + + static void Clean() + { + #ifdef _WIN32 + WSACleanup(); + #endif + } + + static bool Initialize() + { + #ifdef _WIN32 + WSADATA wsaData; + if (WSAStartup(MAKEWORD(1, 1), &wsaData)) + return false; + #endif + return true; + } +}; + +class CPacket +{ +/* Base class that implements a single event packet. + + - Generic packet structure (maximum 1024 bytes per packet) + - Header is 32 bytes long, so 992 bytes available for payload + - large payloads can be split into multiple packets using H4 and H5 + H5 should contain total no. of packets in such a case + - H6 contains length of P1, which is limited to 992 bytes + - if H5 is 0 or 1, then H4 will be ignored (single packet msg) + - H7 must be set to zeros for now + + ----------------------------- + | -H1 Signature ("XBMC") | - 4 x CHAR 4B + | -H2 Version (eg. 2.0) | - 2 x UNSIGNED CHAR 2B + | -H3 PacketType | - 1 x UNSIGNED SHORT 2B + | -H4 Sequence number | - 1 x UNSIGNED LONG 4B + | -H5 No. of packets in msg | - 1 x UNSIGNED LONG 4B + | -H6 Payload size | - 1 x UNSIGNED SHORT 2B + | -H7 Client's unique token | - 1 x UNSIGNED LONG 4B + | -H8 Reserved | - 10 x UNSIGNED CHAR 10B + |---------------------------| + | -P1 payload | - + ----------------------------- +*/ +public: + CPacket() + { + m_PacketType = 0; + } + virtual ~CPacket() = default; + + bool Send(int Socket, CAddress &Addr, unsigned int UID = XBMCClientUtils::GetUniqueIdentifier()) + { + if (m_Payload.empty()) + ConstructPayload(); + bool SendSuccessful = true; + int NbrOfPackages = (m_Payload.size() / MAX_PAYLOAD_SIZE) + 1; + int Send = 0; + int Sent = 0; + int Left = m_Payload.size(); + for (int Package = 1; Package <= NbrOfPackages; Package++) + { + if (Left > MAX_PAYLOAD_SIZE) + { + Send = MAX_PAYLOAD_SIZE; + Left -= Send; + } + else + { + Send = Left; + Left = 0; + } + + ConstructHeader(m_PacketType, NbrOfPackages, Package, Send, UID, m_Header); + char t[MAX_PACKET_SIZE]; + int i, j; + for (i = 0; i < 32; i++) + t[i] = m_Header[i]; + + for (j = 0; j < Send; j++) + t[(32 + j)] = m_Payload[j + Sent]; + + int rtn = sendto(Socket, t, (32 + Send), 0, Addr.GetAddress(), sizeof(struct sockaddr)); + + if (rtn != (32 + Send)) + SendSuccessful = false; + + Sent += Send; + } + return SendSuccessful; + } +protected: + char m_Header[HEADER_SIZE]; + unsigned short m_PacketType; + + std::vector<char> m_Payload; + + static void ConstructHeader(int PacketType, int NumberOfPackets, int CurrentPacket, unsigned short PayloadSize, unsigned int UniqueToken, char *Header) + { + sprintf(Header, "XBMC"); + for (int i = 4; i < HEADER_SIZE; i++) + Header[i] = 0; + Header[4] = MAJOR_VERSION; + Header[5] = MINOR_VERSION; + if (CurrentPacket == 1) + { + Header[6] = ((PacketType & 0xff00) >> 8); + Header[7] = (PacketType & 0x00ff); + } + else + { + Header[6] = ((PT_BLOB & 0xff00) >> 8); + Header[7] = (PT_BLOB & 0x00ff); + } + Header[8] = ((CurrentPacket & 0xff000000) >> 24); + Header[9] = ((CurrentPacket & 0x00ff0000) >> 16); + Header[10] = ((CurrentPacket & 0x0000ff00) >> 8); + Header[11] = (CurrentPacket & 0x000000ff); + + Header[12] = ((NumberOfPackets & 0xff000000) >> 24); + Header[13] = ((NumberOfPackets & 0x00ff0000) >> 16); + Header[14] = ((NumberOfPackets & 0x0000ff00) >> 8); + Header[15] = (NumberOfPackets & 0x000000ff); + + Header[16] = ((PayloadSize & 0xff00) >> 8); + Header[17] = (PayloadSize & 0x00ff); + + Header[18] = ((UniqueToken & 0xff000000) >> 24); + Header[19] = ((UniqueToken & 0x00ff0000) >> 16); + Header[20] = ((UniqueToken & 0x0000ff00) >> 8); + Header[21] = (UniqueToken & 0x000000ff); + } + + virtual void ConstructPayload() + { } +}; + +class CPacketHELO : public CPacket +{ + /************************************************************************/ + /* Payload format */ + /* %s - device name (max 128 chars) */ + /* %c - icontype ( 0=>NOICON, 1=>JPEG , 2=>PNG , 3=>GIF ) */ + /* %s - my port ( 0=>not listening ) */ + /* %d - reserved1 ( 0 ) */ + /* %d - reserved2 ( 0 ) */ + /* XX - imagedata ( can span multiple packets ) */ + /************************************************************************/ +private: + std::vector<char> m_DeviceName; + unsigned short m_IconType; + char *m_IconData; + unsigned short m_IconSize; +public: + void ConstructPayload() override + { + m_Payload.clear(); + + for (unsigned int i = 0; i < m_DeviceName.size(); i++) + m_Payload.push_back(m_DeviceName[i]); + + m_Payload.push_back('\0'); + + m_Payload.push_back(m_IconType); + + m_Payload.push_back(0); + m_Payload.push_back('\0'); + + for (int j = 0; j < 8; j++) + m_Payload.push_back(0); + + for (int ico = 0; ico < m_IconSize; ico++) + m_Payload.push_back(m_IconData[ico]); + } + + CPacketHELO(const char *DevName, unsigned short IconType, const char *IconFile = NULL) : CPacket() + { + m_PacketType = PT_HELO; + + unsigned int len = strlen(DevName); + for (unsigned int i = 0; i < len; i++) + m_DeviceName.push_back(DevName[i]); + + m_IconType = IconType; + + if (IconType == ICON_NONE || IconFile == NULL) + { + m_IconData = NULL; + m_IconSize = 0; + return; + } + + std::ifstream::pos_type size; + + std::ifstream file (IconFile, std::ios::in|std::ios::binary|std::ios::ate); + if (file.is_open()) + { + size = file.tellg(); + m_IconData = new char [size]; + file.seekg (0, std::ios::beg); + file.read (m_IconData, size); + file.close(); + m_IconSize = size; + } + else + { + m_IconType = ICON_NONE; + m_IconSize = 0; + } + } + + ~CPacketHELO() override + { + m_DeviceName.clear(); + delete[] m_IconData; + } +}; + +class CPacketNOTIFICATION : public CPacket +{ + /************************************************************************/ + /* Payload format: */ + /* %s - caption */ + /* %s - message */ + /* %c - icontype ( 0=>NOICON, 1=>JPEG , 2=>PNG , 3=>GIF ) */ + /* %d - reserved ( 0 ) */ + /* XX - imagedata ( can span multiple packets ) */ + /************************************************************************/ +private: + std::vector<char> m_Title; + std::vector<char> m_Message; + unsigned short m_IconType; + char *m_IconData; + unsigned short m_IconSize; +public: + void ConstructPayload() override + { + m_Payload.clear(); + + for (unsigned int i = 0; i < m_Title.size(); i++) + m_Payload.push_back(m_Title[i]); + + m_Payload.push_back('\0'); + + for (unsigned int i = 0; i < m_Message.size(); i++) + m_Payload.push_back(m_Message[i]); + + m_Payload.push_back('\0'); + + m_Payload.push_back(m_IconType); + + for (int i = 0; i < 4; i++) + m_Payload.push_back(0); + + for (int ico = 0; ico < m_IconSize; ico++) + m_Payload.push_back(m_IconData[ico]); + } + + CPacketNOTIFICATION(const char *Title, const char *Message, unsigned short IconType, const char *IconFile = NULL) : CPacket() + { + m_PacketType = PT_NOTIFICATION; + m_IconData = NULL; + m_IconSize = 0; + unsigned int len = 0; + if (Title != NULL) + { + len = strlen(Title); + for (unsigned int i = 0; i < len; i++) + m_Title.push_back(Title[i]); + } + + if (Message != NULL) + { + len = strlen(Message); + for (unsigned int i = 0; i < len; i++) + m_Message.push_back(Message[i]); + } + m_IconType = IconType; + + if (IconType == ICON_NONE || IconFile == NULL) + return; + + std::ifstream::pos_type size; + + std::ifstream file (IconFile, std::ios::in|std::ios::binary|std::ios::ate); + if (file.is_open()) + { + size = file.tellg(); + m_IconData = new char [size]; + file.seekg (0, std::ios::beg); + file.read (m_IconData, size); + file.close(); + m_IconSize = size; + } + else + m_IconType = ICON_NONE; + } + + ~CPacketNOTIFICATION() override + { + m_Title.clear(); + m_Message.clear(); + delete[] m_IconData; + } +}; + +class CPacketBUTTON : public CPacket +{ + /************************************************************************/ + /* Payload format */ + /* %i - button code */ + /* %i - flags 0x01 => use button map/name instead of code */ + /* 0x02 => btn down */ + /* 0x04 => btn up */ + /* 0x08 => use amount */ + /* 0x10 => queue event */ + /* 0x20 => do not repeat */ + /* 0x40 => virtual key */ + /* 0x40 => axis key */ + /* %i - amount ( 0 => 65k maps to -1 => 1 ) */ + /* %s - device map (case sensitive and required if flags & 0x01) */ + /* "KB" - Standard keyboard map */ + /* "XG" - Xbox Gamepad */ + /* "R1" - Xbox Remote */ + /* "R2" - Xbox Universal Remote */ + /* "LI:devicename" - valid LIRC device map where 'devicename' */ + /* is the actual name of the LIRC device */ + /* "JS<num>:joyname" - valid Joystick device map where */ + /* 'joyname' is the name specified in */ + /* the keymap. JS only supports button code */ + /* and not button name currently (!0x01). */ + /* %s - button name (required if flags & 0x01) */ + /************************************************************************/ +private: + std::vector<char> m_DeviceMap; + std::vector<char> m_Button; + unsigned short m_ButtonCode; + unsigned short m_Amount; + unsigned short m_Flags; +public: + void ConstructPayload() override + { + m_Payload.clear(); + + if (m_Button.size() != 0) + { + if (!(m_Flags & BTN_USE_NAME)) // If the BTN_USE_NAME isn't flagged for some reason + m_Flags |= BTN_USE_NAME; + m_ButtonCode = 0; + } + else + m_Button.clear(); + + if (m_Amount > 0) + { + if (!(m_Flags & BTN_USE_AMOUNT)) + m_Flags |= BTN_USE_AMOUNT; + } + if (!((m_Flags & BTN_DOWN) || (m_Flags & BTN_UP))) //If none of them are tagged. + m_Flags |= BTN_DOWN; + + m_Payload.push_back(((m_ButtonCode & 0xff00) >> 8)); + m_Payload.push_back( (m_ButtonCode & 0x00ff)); + + m_Payload.push_back(((m_Flags & 0xff00) >> 8) ); + m_Payload.push_back( (m_Flags & 0x00ff)); + + m_Payload.push_back(((m_Amount & 0xff00) >> 8) ); + m_Payload.push_back( (m_Amount & 0x00ff)); + + + for (unsigned int i = 0; i < m_DeviceMap.size(); i++) + m_Payload.push_back(m_DeviceMap[i]); + + m_Payload.push_back('\0'); + + for (unsigned int i = 0; i < m_Button.size(); i++) + m_Payload.push_back(m_Button[i]); + + m_Payload.push_back('\0'); + } + + CPacketBUTTON(const char *Button, const char *DeviceMap, unsigned short Flags, unsigned short Amount = 0) : CPacket() + { + m_PacketType = PT_BUTTON; + m_Flags = Flags; + m_ButtonCode = 0; + m_Amount = Amount; + + unsigned int len = strlen(DeviceMap); + for (unsigned int i = 0; i < len; i++) + m_DeviceMap.push_back(DeviceMap[i]); + + len = strlen(Button); + for (unsigned int i = 0; i < len; i++) + m_Button.push_back(Button[i]); + } + + CPacketBUTTON(unsigned short ButtonCode, const char *DeviceMap, unsigned short Flags, unsigned short Amount = 0) : CPacket() + { + m_PacketType = PT_BUTTON; + m_Flags = Flags; + m_ButtonCode = ButtonCode; + m_Amount = Amount; + + unsigned int len = strlen(DeviceMap); + for (unsigned int i = 0; i < len; i++) + m_DeviceMap.push_back(DeviceMap[i]); + } + + CPacketBUTTON(unsigned short ButtonCode, unsigned short Flags, unsigned short Amount = 0) : CPacket() + { + m_PacketType = PT_BUTTON; + m_Flags = Flags; + m_ButtonCode = ButtonCode; + m_Amount = Amount; + } + + // Used to send a release event + CPacketBUTTON() : CPacket() + { + m_PacketType = PT_BUTTON; + m_Flags = BTN_UP; + m_Amount = 0; + m_ButtonCode = 0; + } + + ~CPacketBUTTON() override + { + m_DeviceMap.clear(); + m_Button.clear(); + } + + inline unsigned short GetFlags() { return m_Flags; } + inline unsigned short GetButtonCode() { return m_ButtonCode; } +}; + +class CPacketPING : public CPacket +{ + /************************************************************************/ + /* no payload */ + /************************************************************************/ +public: + CPacketPING() : CPacket() + { + m_PacketType = PT_PING; + } + ~CPacketPING() override = default; +}; + +class CPacketBYE : public CPacket +{ + /************************************************************************/ + /* no payload */ + /************************************************************************/ +public: + CPacketBYE() : CPacket() + { + m_PacketType = PT_BYE; + } + ~CPacketBYE() override = default; +}; + +class CPacketMOUSE : public CPacket +{ + /************************************************************************/ + /* Payload format */ + /* %c - flags */ + /* - 0x01 absolute position */ + /* %i - mousex (0-65535 => maps to screen width) */ + /* %i - mousey (0-65535 => maps to screen height) */ + /************************************************************************/ +private: + unsigned short m_X; + unsigned short m_Y; + unsigned char m_Flag; +public: + CPacketMOUSE(int X, int Y, unsigned char Flag = MS_ABSOLUTE) + { + m_PacketType = PT_MOUSE; + m_Flag = Flag; + m_X = X; + m_Y = Y; + } + + void ConstructPayload() override + { + m_Payload.clear(); + + m_Payload.push_back(m_Flag); + + m_Payload.push_back(((m_X & 0xff00) >> 8)); + m_Payload.push_back( (m_X & 0x00ff)); + + m_Payload.push_back(((m_Y & 0xff00) >> 8)); + m_Payload.push_back( (m_Y & 0x00ff)); + } + + ~CPacketMOUSE() override = default; +}; + +class CPacketLOG : public CPacket +{ + /************************************************************************/ + /* Payload format */ + /* %c - log type */ + /* %s - message */ + /************************************************************************/ +private: + std::vector<char> m_Message; + unsigned char m_LogLevel; + bool m_AutoPrintf; +public: + CPacketLOG(int LogLevel, const char *Message, bool AutoPrintf = true) + { + m_PacketType = PT_LOG; + + unsigned int len = strlen(Message); + for (unsigned int i = 0; i < len; i++) + m_Message.push_back(Message[i]); + + m_LogLevel = LogLevel; + m_AutoPrintf = AutoPrintf; + } + + void ConstructPayload() override + { + m_Payload.clear(); + + m_Payload.push_back( (m_LogLevel & 0x00ff) ); + + if (m_AutoPrintf) + { + char* str=&m_Message[0]; + printf("%s\n", str); + } + for (unsigned int i = 0; i < m_Message.size(); i++) + m_Payload.push_back(m_Message[i]); + + m_Payload.push_back('\0'); + } + + ~CPacketLOG() override = default; +}; + +class CPacketACTION : public CPacket +{ + /************************************************************************/ + /* Payload format */ + /* %c - action type */ + /* %s - action message */ + /************************************************************************/ +private: + unsigned char m_ActionType; + std::vector<char> m_Action; +public: + CPacketACTION(const char *Action, unsigned char ActionType = ACTION_EXECBUILTIN) + { + m_PacketType = PT_ACTION; + + m_ActionType = ActionType; + unsigned int len = strlen(Action); + for (unsigned int i = 0; i < len; i++) + m_Action.push_back(Action[i]); + } + + void ConstructPayload() override + { + m_Payload.clear(); + + m_Payload.push_back(m_ActionType); + for (unsigned int i = 0; i < m_Action.size(); i++) + m_Payload.push_back(m_Action[i]); + + m_Payload.push_back('\0'); + } + + ~CPacketACTION() override = default; +}; + +class CXBMCClient +{ +private: + CAddress m_Addr; + int m_Socket; + unsigned int m_UID; +public: + CXBMCClient(const char *IP = "127.0.0.1", int Port = 9777, int Socket = -1, unsigned int UID = 0) + { + m_Addr = CAddress(IP, Port); + if (Socket == -1) + m_Socket = socket(AF_INET, SOCK_DGRAM, 0); + else + m_Socket = Socket; + + if (UID) + m_UID = UID; + else + m_UID = XBMCClientUtils::GetUniqueIdentifier(); + } + + void SendNOTIFICATION(const char *Title, const char *Message, unsigned short IconType, const char *IconFile = NULL) + { + if (m_Socket < 0) + return; + + CPacketNOTIFICATION notification(Title, Message, IconType, IconFile); + notification.Send(m_Socket, m_Addr, m_UID); + } + + void SendHELO(const char *DevName, unsigned short IconType, const char *IconFile = NULL) + { + if (m_Socket < 0) + return; + + CPacketHELO helo(DevName, IconType, IconFile); + helo.Send(m_Socket, m_Addr, m_UID); + } + + void SendButton(const char *Button, const char *DeviceMap, unsigned short Flags, unsigned short Amount = 0) + { + if (m_Socket < 0) + return; + + CPacketBUTTON button(Button, DeviceMap, Flags, Amount); + button.Send(m_Socket, m_Addr, m_UID); + } + + void SendButton(unsigned short ButtonCode, const char *DeviceMap, unsigned short Flags, unsigned short Amount = 0) + { + if (m_Socket < 0) + return; + + CPacketBUTTON button(ButtonCode, DeviceMap, Flags, Amount); + button.Send(m_Socket, m_Addr, m_UID); + } + + void SendButton(unsigned short ButtonCode, unsigned Flags, unsigned short Amount = 0) + { + if (m_Socket < 0) + return; + + CPacketBUTTON button(ButtonCode, Flags, Amount); + button.Send(m_Socket, m_Addr, m_UID); + } + + void SendMOUSE(int X, int Y, unsigned char Flag = MS_ABSOLUTE) + { + if (m_Socket < 0) + return; + + CPacketMOUSE mouse(X, Y, Flag); + mouse.Send(m_Socket, m_Addr, m_UID); + } + + void SendLOG(int LogLevel, const char *Message, bool AutoPrintf = true) + { + if (m_Socket < 0) + return; + + CPacketLOG log(LogLevel, Message, AutoPrintf); + log.Send(m_Socket, m_Addr, m_UID); + } + + void SendACTION(const char *ActionMessage, int ActionType = ACTION_EXECBUILTIN) + { + if (m_Socket < 0) + return; + + CPacketACTION action(ActionMessage, ActionType); + action.Send(m_Socket, m_Addr, m_UID); + } +}; + diff --git a/tools/EventClients/lib/java/build.xml b/tools/EventClients/lib/java/build.xml new file mode 100644 index 0000000..fe25bde --- /dev/null +++ b/tools/EventClients/lib/java/build.xml @@ -0,0 +1,72 @@ +<project default="jar" name="JXBMCEventClient"> + <description description="JXBMCEventClient"/> + <target name="init"> + <tstamp/> + <property name="srcdir" value="${basedir}/src"/> + <property name="classdir" value="${basedir}/classes"/> + <property name="apidir" value="${basedir}/doc/api"/> + <property name="libdir" value="/usr/local/share/java/classes"/> + <property name="projectname" value="JXBMCEventClient"/> + <property name="jarfile" value="${projectname}.jar"/> + <property name="distdir" value="${basedir}/../dist"/> + <fileset id="eventclient.files" dir="${classdir}" includes="**/*"/> + <path id="classpath"> + <pathelement location="${libdir}/junit.jar" /> + </path> + </target> + + + <target name="jar" depends="compile"> + <jar jarfile="${jarfile}" index="true"> + <fileset refid="eventclient.files"/> + </jar> + </target> + + <target name="dist" depends="jar, javadoc"> + <fail unless="version">use: ant dist -Dversion=x.x</fail> + <mkdir dir="${distdir}"/> + <copy todir="${distdir}/doc"> + <fileset dir="${apidir}"/> + </copy> + <property name="filename" value="${projectname}-${version}"/> + <copy file="${jarfile}" tofile="${distdir}/${projectname}-${version}.jar" /> + <tar destfile="${distdir}/${filename}.tar.gz" compression="gzip"> + <tarfileset dir="${basedir}" prefix="${filename}"> + <exclude name="classes/**"/> + <exclude name="**/CVS"/> + <exclude name="**/.*"/> + <exclude name="${jarfile}"/> + <exclude name="doc/**"/> + </tarfileset> + </tar> + </target> + + <target name="compile" depends="init" description="Compiles all classes"> + <mkdir dir="${classdir}"/> + <javac debug="yes" deprecation="true" destdir="${classdir}" srcdir="${srcdir}" classpathref="classpath"/> + </target> + + <target name="javadoc" depends="init"> + <mkdir dir="${apidir}"/> + <javadoc + packagenames="org.xbmc.eventclient.*" + sourcepath="${srcdir}" + defaultexcludes="yes" + destdir="${apidir}" + author="true" + version="true" + use="true" + private="false" + windowtitle="${projectname} API" + classpathref="classpath"> + <link href="http://java.sun.com/j2se/1.4.2/docs/api/"/> + </javadoc> + </target> + + <target name="clean" depends="init" description="cleans all classes and jars"> + <delete dir="${classdir}"/> + <delete dir="${apidir}"/> + <delete file="${jarfile}"/> + </target> + +</project> diff --git a/tools/EventClients/lib/java/src/org/xbmc/eventclient/Packet.java b/tools/EventClients/lib/java/src/org/xbmc/eventclient/Packet.java new file mode 100644 index 0000000..09507cb --- /dev/null +++ b/tools/EventClients/lib/java/src/org/xbmc/eventclient/Packet.java @@ -0,0 +1,289 @@ +/* + * Copyright (C) 2008-2013 Team XBMC + * + * 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 Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +package org.xbmc.eventclient; +import java.io.IOException; +import java.net.DatagramPacket; +import java.net.DatagramSocket; +import java.net.InetAddress; + +/** + * XBMC Event Client Class + * <p> + * Implementation of XBMC's UDP based input system. + * A set of classes that abstract the various packets that the event server + * currently supports. In addition, there's also a class, XBMCClient, that + * provides functions that sends the various packets. Use XBMCClient if you + * don't need complete control over packet structure. + * </p> + * <p> + * The basic workflow involves: + * <ol> + * <li>Send a HELO packet</li> + * <li>Send x number of valid packets</li> + * <li>Send a BYE packet</li> + * </ol> + * </p> + * <p> + * IMPORTANT NOTE ABOUT TIMEOUTS: + * A client is considered to be timed out if XBMC doesn't received a packet + * at least once every 60 seconds. To "ping" XBMC with an empty packet use + * PacketPING or XBMCClient.ping(). See the documentation for details. + * </p> + * <p> + * Base class that implements a single event packet. + * - Generic packet structure (maximum 1024 bytes per packet) + * - Header is 32 bytes long, so 992 bytes available for payload + * - large payloads can be split into multiple packets using H4 and H5 + * H5 should contain total no. of packets in such a case + * - H6 contains length of P1, which is limited to 992 bytes + * - if H5 is 0 or 1, then H4 will be ignored (single packet msg) + * - H7 must be set to zeros for now + * </p> + * <pre> + * ----------------------------- + * | -H1 Signature ("XBMC") | - 4 x CHAR 4B + * | -H2 Version (eg. 2.0) | - 2 x UNSIGNED CHAR 2B + * | -H3 PacketType | - 1 x UNSIGNED SHORT 2B + * | -H4 Sequence number | - 1 x UNSIGNED LONG 4B + * | -H5 No. of packets in msg | - 1 x UNSIGNED LONG 4B + * | -H6 Payloadsize of packet | - 1 x UNSIGNED SHORT 2B + * | -H7 Client's unique token | - 1 x UNSIGNED LONG 4B + * | -H8 Reserved | - 10 x UNSIGNED CHAR 10B + * |---------------------------| + * | -P1 payload | - + * ----------------------------- + * </pre> + * @author Stefan Agner + * + */ +public abstract class Packet { + + private byte[] sig; + private byte[] payload = new byte[0]; + private byte minver; + private byte majver; + + private short packettype; + + + private final static short MAX_PACKET_SIZE = 1024; + private final static short HEADER_SIZE = 32; + private final static short MAX_PAYLOAD_SIZE = MAX_PACKET_SIZE - HEADER_SIZE; + + protected final static byte PT_HELO = 0x01; + protected final static byte PT_BYE = 0x02; + protected final static byte PT_BUTTON = 0x03; + protected final static byte PT_MOUSE = 0x04; + protected final static byte PT_PING = 0x05; + protected final static byte PT_BROADCAST = 0x06; + protected final static byte PT_NOTIFICATION = 0x07; + protected final static byte PT_BLOB = 0x08; + protected final static byte PT_LOG = 0x09; + protected final static byte PT_ACTION = 0x0A; + protected final static byte PT_DEBUG = (byte)0xFF; + + public final static byte ICON_NONE = 0x00; + public final static byte ICON_JPEG = 0x01; + public final static byte ICON_PNG = 0x02; + public final static byte ICON_GIF = 0x03; + + private static int uid = (int)(Math.random()*Integer.MAX_VALUE); + + /** + * This is an Abstract class and cannot be instanced. Please use one of the Packet implementation Classes + * (PacketXXX). + * + * Implements an XBMC Event Client Packet. Type is to be specified at creation time, Payload can be added + * with the various appendPayload methods. Packet can be sent through UDP-Socket with method "send". + * @param packettype Type of Packet (PT_XXX) + */ + protected Packet(short packettype) + { + sig = new byte[] {'X', 'B', 'M', 'C' }; + minver = 0; + majver = 2; + this.packettype = packettype; + } + + /** + * Appends a String to the payload (terminated with 0x00) + * @param payload Payload as String + */ + protected void appendPayload(String payload) + { + byte[] payloadarr = payload.getBytes(); + int oldpayloadsize = this.payload.length; + byte[] oldpayload = this.payload; + this.payload = new byte[oldpayloadsize+payloadarr.length+1]; // Create new Array with more place (+1 for string terminator) + System.arraycopy(oldpayload, 0, this.payload, 0, oldpayloadsize); + System.arraycopy(payloadarr, 0, this.payload, oldpayloadsize, payloadarr.length); + } + + /** + * Appends a single Byte to the payload + * @param payload Payload + */ + protected void appendPayload(byte payload) + { + appendPayload(new byte[] { payload }); + } + + /** + * Appends a Byte-Array to the payload + * @param payloadarr Payload + */ + protected void appendPayload(byte[] payloadarr) + { + int oldpayloadsize = this.payload.length; + byte[] oldpayload = this.payload; + this.payload = new byte[oldpayloadsize+payloadarr.length]; + System.arraycopy(oldpayload, 0, this.payload, 0, oldpayloadsize); + System.arraycopy(payloadarr, 0, this.payload, oldpayloadsize, payloadarr.length); + } + + /** + * Appends an integer to the payload + * @param i Payload + */ + protected void appendPayload(int i) { + appendPayload(intToByteArray(i)); + } + + /** + * Appends a short to the payload + * @param s Payload + */ + protected void appendPayload(short s) { + appendPayload(shortToByteArray(s)); + } + + /** + * Get Number of Packets which will be sent with current Payload... + * @return Number of Packets + */ + public int getNumPackets() + { + return (int)((payload.length + (MAX_PAYLOAD_SIZE - 1)) / MAX_PAYLOAD_SIZE); + } + + /** + * Get Header for a specific Packet in this sequence... + * @param seq Current sequence number + * @param maxseq Maximal sequence number + * @param actpayloadsize Payloadsize of this packet + * @return Byte-Array with Header information (currently 32-Byte long, see HEADER_SIZE) + */ + private byte[] getHeader(int seq, int maxseq, short actpayloadsize) + { + byte[] header = new byte[HEADER_SIZE]; + System.arraycopy(sig, 0, header, 0, 4); + header[4] = majver; + header[5] = minver; + byte[] packettypearr = shortToByteArray(this.packettype); + System.arraycopy(packettypearr, 0, header, 6, 2); + byte[] seqarr = intToByteArray(seq); + System.arraycopy(seqarr, 0, header, 8, 4); + byte[] maxseqarr = intToByteArray(maxseq); + System.arraycopy(maxseqarr, 0, header, 12, 4); + byte[] payloadsize = shortToByteArray(actpayloadsize); + System.arraycopy(payloadsize, 0, header, 16, 2); + byte[] uid = intToByteArray(Packet.uid); + System.arraycopy(uid, 0, header, 18, 4); + byte[] reserved = new byte[10]; + System.arraycopy(reserved, 0, header, 22, 10); + + return header; + } + + /** + * Generates the whole UDP-Message with Header and Payload of a specific Packet in sequence + * @param seq Current sequence number + * @return Byte-Array with UDP-Message + */ + private byte[] getUDPMessage(int seq) + { + int maxseq = (int)((payload.length + (MAX_PAYLOAD_SIZE - 1)) / MAX_PAYLOAD_SIZE); + if(seq > maxseq) + return null; + + short actpayloadsize; + + if(seq == maxseq) + actpayloadsize = (short)(payload.length%MAX_PAYLOAD_SIZE); + + else + actpayloadsize = (short)MAX_PAYLOAD_SIZE; + + byte[] pack = new byte[HEADER_SIZE+actpayloadsize]; + + System.arraycopy(getHeader(seq, maxseq, actpayloadsize), 0, pack, 0, HEADER_SIZE); + System.arraycopy(payload, (seq-1)*MAX_PAYLOAD_SIZE, pack, HEADER_SIZE, actpayloadsize); + + return pack; + } + + /** + * Sends this packet to the EventServer + * @param adr Address of the EventServer + * @param port Port of the EventServer + * @throws IOException + */ + public void send(InetAddress adr, int port) throws IOException + { + int maxseq = getNumPackets(); + DatagramSocket s = new DatagramSocket(); + + // For each Packet in Sequence... + for(int seq=1;seq<=maxseq;seq++) + { + // Get Message and send them... + byte[] pack = getUDPMessage(seq); + DatagramPacket p = new DatagramPacket(pack, pack.length); + p.setAddress(adr); + p.setPort(port); + s.send(p); + } + } + + /** + * Helper Method to convert an integer to a Byte array + * @param value + * @return Byte-Array + */ + private static final byte[] intToByteArray(int value) { + return new byte[] { + (byte)(value >>> 24), + (byte)(value >>> 16), + (byte)(value >>> 8), + (byte)value}; + } + + /** + * Helper Method to convert an short to a Byte array + * @param value + * @return Byte-Array + */ + private static final byte[] shortToByteArray(short value) { + return new byte[] { + (byte)(value >>> 8), + (byte)value}; + } + + +} diff --git a/tools/EventClients/lib/java/src/org/xbmc/eventclient/PacketACTION.java b/tools/EventClients/lib/java/src/org/xbmc/eventclient/PacketACTION.java new file mode 100644 index 0000000..eb597a2 --- /dev/null +++ b/tools/EventClients/lib/java/src/org/xbmc/eventclient/PacketACTION.java @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2008-2013 Team XBMC + * + * 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 Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +package org.xbmc.eventclient; +/** + * XBMC Event Client Class + * + * An ACTION packet tells XBMC to do the action specified, based on the type it knows were it needs to be sent. + * The idea is that this will be as in scripting/skining and keymapping, just triggered from afar. + * @author Stefan Agner + * + */ +public class PacketACTION extends Packet { + + public final static byte ACTION_EXECBUILTIN = 0x01; + public final static byte ACTION_BUTTON = 0x02; + + + /** + * An ACTION packet tells XBMC to do the action specified, based on the type it knows were it needs to be sent. + * @param actionmessage Actionmessage (as in scripting/skinning) + */ + public PacketACTION(String actionmessage) + { + super(PT_ACTION); + byte actiontype = ACTION_EXECBUILTIN; + appendPayload(actionmessage, actiontype); + } + + /** + * An ACTION packet tells XBMC to do the action specified, based on the type it knows were it needs to be sent. + * @param actionmessage Actionmessage (as in scripting/skinning) + * @param actiontype Actiontype (ACTION_EXECBUILTIN or ACTION_BUTTON) + */ + public PacketACTION(String actionmessage, byte actiontype) + { + super(PT_ACTION); + appendPayload(actionmessage, actiontype); + } + + private void appendPayload(String actionmessage, byte actiontype) + { + appendPayload(actiontype); + appendPayload(actionmessage); + } +} diff --git a/tools/EventClients/lib/java/src/org/xbmc/eventclient/PacketBUTTON.java b/tools/EventClients/lib/java/src/org/xbmc/eventclient/PacketBUTTON.java new file mode 100644 index 0000000..de25a2c --- /dev/null +++ b/tools/EventClients/lib/java/src/org/xbmc/eventclient/PacketBUTTON.java @@ -0,0 +1,157 @@ +/* + * Copyright (C) 2008-2013 Team XBMC + * + * 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 Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +package org.xbmc.eventclient; +/** + * XBMC Event Client Class + * + * A button packet send a key press or release event to XBMC + * @author Stefan Agner + * + */ +public class PacketBUTTON extends Packet { + + protected final static byte BT_USE_NAME = 0x01; + protected final static byte BT_DOWN = 0x02; + protected final static byte BT_UP = 0x04; + protected final static byte BT_USE_AMOUNT = 0x08; + protected final static byte BT_QUEUE = 0x10; + protected final static byte BT_NO_REPEAT = 0x20; + protected final static byte BT_VKEY = 0x40; + protected final static byte BT_AXIS = (byte)0x80; + protected final static byte BT_AXISSINGLE = (byte)0x100; + + /** + * A button packet send a key press or release event to XBMC + * @param code raw button code (default: 0) + * @param repeat this key press should repeat until released (default: 1) + * Note that queued pressed cannot repeat. + * @param down if this is 1, it implies a press event, 0 implies a release + * event. (default: 1) + * @param queue a queued key press means that the button event is + * executed just once after which the next key press is processed. + * It can be used for macros. Currently there is no support for + * time delays between queued presses. (default: 0) + * @param amount unimplemented for now; in the future it will be used for + * specifying magnitude of analog key press events + * @param axis + */ + public PacketBUTTON(short code, boolean repeat, boolean down, boolean queue, short amount, byte axis) + { + super(PT_BUTTON); + String map_name = ""; + String button_name = ""; + short flags = 0; + appendPayload(code, map_name, button_name, repeat, down, queue, amount, axis, flags); + } + + /** + * A button packet send a key press or release event to XBMC + * @param map_name a combination of map_name and button_name refers to a + * mapping in the user's Keymap.xml or Lircmap.xml. + * map_name can be one of the following: + * <ul> + * <li>"KB" => standard keyboard map ( <keyboard> section )</li> + * <li>"XG" => xbox gamepad map ( <gamepad> section )</li> + * <li>"R1" => xbox remote map ( <remote> section )</li> + * <li>"R2" => xbox universal remote map ( <universalremote> section )</li> + * <li>"LI:devicename" => LIRC remote map where 'devicename' is the + * actual device's name</li></ul> + * @param button_name a button name defined in the map specified in map_name. + * For example, if map_name is "KB" referring to the <keyboard> section in Keymap.xml + * then, valid button_names include "printscreen", "minus", "x", etc. + * @param repeat this key press should repeat until released (default: 1) + * Note that queued pressed cannot repeat. + * @param down if this is 1, it implies a press event, 0 implies a release + * event. (default: 1) + * @param queue a queued key press means that the button event is + * executed just once after which the next key press is processed. + * It can be used for macros. Currently there is no support for + * time delays between queued presses. (default: 0) + * @param amount unimplemented for now; in the future it will be used for + * specifying magnitude of analog key press events + * @param axis + */ + public PacketBUTTON(String map_name, String button_name, boolean repeat, boolean down, boolean queue, short amount, byte axis) + { + super(PT_BUTTON); + short code = 0; + short flags = BT_USE_NAME; + appendPayload(code, map_name, button_name, repeat, down, queue, amount, axis, flags); + } + + /** + * Appends Payload for a Button Packet (this method is used by the different Constructors of this Packet) + * @param code raw button code (default: 0) + * @param map_name a combination of map_name and button_name refers to a + * mapping in the user's Keymap.xml or Lircmap.xml. + * map_name can be one of the following: + * <ul> + * <li>"KB" => standard keyboard map ( <keyboard> section )</li> + * <li>"XG" => xbox gamepad map ( <gamepad> section )</li> + * <li>"R1" => xbox remote map ( <remote> section )</li> + * <li>"R2" => xbox universal remote map ( <universalremote> section )</li> + * <li>"LI:devicename" => LIRC remote map where 'devicename' is the + * actual device's name</li></ul> + * @param button_name a button name defined in the map specified in map_name. + * For example, if map_name is "KB" referring to the <keyboard> section in Keymap.xml + * then, valid button_names include "printscreen", "minus", "x", etc. + * @param repeat this key press should repeat until released (default: 1) + * Note that queued pressed cannot repeat. + * @param down if this is 1, it implies a press event, 0 implies a release + * event. (default: 1) + * @param queue a queued key press means that the button event is + * executed just once after which the next key press is processed. + * It can be used for macros. Currently there is no support for + * time delays between queued presses. (default: 0) + * @param amount unimplemented for now; in the future it will be used for + * specifying magnitude of analog key press events + * @param axis + * @param flags Packet specific flags + */ + private void appendPayload(short code, String map_name, String button_name, boolean repeat, boolean down, boolean queue, short amount, byte axis, short flags) + { + if(amount>0) + flags |= BT_USE_AMOUNT; + else + amount = 0; + + if(down) + flags |= BT_DOWN; + else + flags |= BT_UP; + + if(!repeat) + flags |= BT_NO_REPEAT; + + if(queue) + flags |= BT_QUEUE; + + if(axis == 1) + flags |= BT_AXISSINGLE; + else if (axis == 2) + flags |= BT_AXIS; + + + appendPayload(code); + appendPayload(flags); + appendPayload(amount); + appendPayload(map_name); + appendPayload(button_name); + } +} diff --git a/tools/EventClients/lib/java/src/org/xbmc/eventclient/PacketBYE.java b/tools/EventClients/lib/java/src/org/xbmc/eventclient/PacketBYE.java new file mode 100644 index 0000000..e63a2c6 --- /dev/null +++ b/tools/EventClients/lib/java/src/org/xbmc/eventclient/PacketBYE.java @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2008-2013 Team XBMC + * + * 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 Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +package org.xbmc.eventclient; +/** + * XBMC Event Client Class + * + * A BYE packet terminates the connection to XBMC. + * @author Stefan Agner + * + */ +public class PacketBYE extends Packet +{ + + /** + * A BYE packet terminates the connection to XBMC. + */ + public PacketBYE() + { + super(PT_BYE); + } +} diff --git a/tools/EventClients/lib/java/src/org/xbmc/eventclient/PacketHELO.java b/tools/EventClients/lib/java/src/org/xbmc/eventclient/PacketHELO.java new file mode 100644 index 0000000..95e8fa9 --- /dev/null +++ b/tools/EventClients/lib/java/src/org/xbmc/eventclient/PacketHELO.java @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2008-2013 Team XBMC + * + * 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 Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +package org.xbmc.eventclient; +import java.nio.charset.Charset; + +/** + * XBMC Event Client Class + * + * A HELO packet establishes a valid connection to XBMC. It is the + * first packet that should be sent. + * @author Stefan Agner + * + */ +public class PacketHELO extends Packet { + + + /** + * A HELO packet establishes a valid connection to XBMC. + * @param devicename Name of the device which connects to XBMC + */ + public PacketHELO(String devicename) + { + super(PT_HELO); + this.appendPayload(devicename); + this.appendPayload(ICON_NONE); + this.appendPayload((short)0); // port no + this.appendPayload(0); // reserved1 + this.appendPayload(0); // reserved2 + } + + /** + * A HELO packet establishes a valid connection to XBMC. + * @param devicename Name of the device which connects to XBMC + * @param iconType Type of the icon (Packet.ICON_PNG, Packet.ICON_JPEG or Packet.ICON_GIF) + * @param iconData The icon as a Byte-Array + */ + public PacketHELO(String devicename, byte iconType, byte[] iconData) + { + super(PT_HELO); + this.appendPayload(devicename); + this.appendPayload(iconType); + this.appendPayload((short)0); // port no + this.appendPayload(0); // reserved1 + this.appendPayload(0); // reserved2 + this.appendPayload(iconData); // reserved2 + } + +} diff --git a/tools/EventClients/lib/java/src/org/xbmc/eventclient/PacketLOG.java b/tools/EventClients/lib/java/src/org/xbmc/eventclient/PacketLOG.java new file mode 100644 index 0000000..b0d59bb --- /dev/null +++ b/tools/EventClients/lib/java/src/org/xbmc/eventclient/PacketLOG.java @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2008-2013 Team XBMC + * + * 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 Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +package org.xbmc.eventclient; +/** + * XBMC Event Client Class + * + * A LOG packet tells XBMC to log the message to xbmc.log with the loglevel as specified. + * @author Stefan Agner + * + */ +public class PacketLOG extends Packet { + + /** + * A LOG packet tells XBMC to log the message to xbmc.log with the loglevel as specified. + * @param loglevel the loglevel, follows XBMC standard. + * <ul> + * <li>0 = DEBUG</li> + * <li>1 = INFO</li> + * <li>2 = NOTICE</li> + * <li>3 = WARNING</li> + * <li>4 = ERROR</li> + * <li>5 = SEVERE</li> + * </ul> + * @param logmessage the message to log + */ + public PacketLOG(byte loglevel, String logmessage) + { + super(PT_LOG); + appendPayload(loglevel); + appendPayload(logmessage); + } +} diff --git a/tools/EventClients/lib/java/src/org/xbmc/eventclient/PacketMOUSE.java b/tools/EventClients/lib/java/src/org/xbmc/eventclient/PacketMOUSE.java new file mode 100644 index 0000000..816e1a7 --- /dev/null +++ b/tools/EventClients/lib/java/src/org/xbmc/eventclient/PacketMOUSE.java @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2008-2013 Team XBMC + * + * 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 Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +package org.xbmc.eventclient; +/** + * XBMC Event Client Class + * + * A MOUSE packets sets the mouse position in XBMC + * @author Stefan Agner + * + */ +public class PacketMOUSE extends Packet { + + protected final static byte MS_ABSOLUTE = 0x01; + + /** + * A MOUSE packets sets the mouse position in XBMC + * @param x horizontal position ranging from 0 to 65535 + * @param y vertical position ranging from 0 to 65535 + */ + public PacketMOUSE(int x, int y) + { + super(PT_MOUSE); + byte flags = 0; + flags |= MS_ABSOLUTE; + appendPayload(flags); + appendPayload((short)x); + appendPayload((short)y); + } +} diff --git a/tools/EventClients/lib/java/src/org/xbmc/eventclient/PacketNOTIFICATION.java b/tools/EventClients/lib/java/src/org/xbmc/eventclient/PacketNOTIFICATION.java new file mode 100644 index 0000000..7089ad6 --- /dev/null +++ b/tools/EventClients/lib/java/src/org/xbmc/eventclient/PacketNOTIFICATION.java @@ -0,0 +1,71 @@ +/* + * Copyright (C) 2008-2013 Team XBMC + * + * 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 Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +package org.xbmc.eventclient; +/** + * XBMC Event Client Class + * + * This packet displays a notification window in XBMC. It can contain + * a caption, a message and an icon. + * @author Stefan Agner + * + */ +public class PacketNOTIFICATION extends Packet { + + /** + * This packet displays a notification window in XBMC. + * @param title Message title + * @param message The actual message + * @param iconType Type of the icon (Packet.ICON_PNG, Packet.ICON_JPEG or Packet.ICON_GIF) + * @param iconData The icon as a Byte-Array + */ + public PacketNOTIFICATION(String title, String message, byte iconType, byte[] iconData) + { + super(PT_NOTIFICATION); + appendPayload(title, message, iconType, iconData); + } + + /** + * This packet displays a notification window in XBMC. + * @param title Message title + * @param message The actual message + */ + public PacketNOTIFICATION(String title, String message) + { + super(PT_NOTIFICATION); + appendPayload(title, message, Packet.ICON_NONE, null); + } + + /** + * Appends the payload to the packet... + * @param title Message title + * @param message The actual message + * @param iconType Type of the icon (Packet.ICON_PNG, Packet.ICON_JPEG or Packet.ICON_GIF) + * @param iconData The icon as a Byte-Array + */ + private void appendPayload(String title, String message, byte iconType, byte[] iconData) + { + appendPayload(title); + appendPayload(message); + appendPayload(iconType); + appendPayload(0); // reserved + if(iconData!=null) + appendPayload(iconData); + + } +} diff --git a/tools/EventClients/lib/java/src/org/xbmc/eventclient/PacketPING.java b/tools/EventClients/lib/java/src/org/xbmc/eventclient/PacketPING.java new file mode 100644 index 0000000..2afbd8d --- /dev/null +++ b/tools/EventClients/lib/java/src/org/xbmc/eventclient/PacketPING.java @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2008-2013 Team XBMC + * + * 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 Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +package org.xbmc.eventclient; +/** + * XBMC Event Client Class + * + * A PING packet tells XBMC that the client is still alive. All valid + * packets act as ping (not just this one). A client needs to ping + * XBMC at least once in 60 seconds or it will time + * @author Stefan Agner + * + */ +public class PacketPING extends Packet { + /** + * A PING packet tells XBMC that the client is still alive. + */ + public PacketPING() + { + super(PT_PING); + } +} diff --git a/tools/EventClients/lib/java/src/org/xbmc/eventclient/XBMCClient.java b/tools/EventClients/lib/java/src/org/xbmc/eventclient/XBMCClient.java new file mode 100644 index 0000000..322ebf1 --- /dev/null +++ b/tools/EventClients/lib/java/src/org/xbmc/eventclient/XBMCClient.java @@ -0,0 +1,318 @@ +/* + * Copyright (C) 2008-2013 Team XBMC + * + * 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 Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +package org.xbmc.eventclient; + +import java.io.FileInputStream; +import java.io.IOException; +import java.net.InetAddress; + +/** + * XBMC Event Client Class + * + * Implements an XBMC-Client. This class can be used to implement your own application which + * should act as a Input device for XBMC. Also starts a Ping-Thread, which tells the XBMC EventServer + * that the client is alive. Therefore if you close your application you SHOULD call stopClient()! + * @author Stefan Agner + * + */ +public class XBMCClient +{ + private boolean hasIcon = false; + private String deviceName; + private PingThread oPingThread; + private byte iconType = Packet.ICON_PNG; + private byte[] iconData; + private InetAddress hostAddress; + private int hostPort; + + /** + * Starts a XBMC EventClient. + * @param hostAddress Address of the Host running XBMC + * @param hostPort Port of the Host running XBMC (default 9777) + * @param deviceName Name of the Device + * @param iconFile Path to the Iconfile (PNG, JPEG or GIF) + * @throws IOException + */ + public XBMCClient(InetAddress hostAddress, int hostPort, String deviceName, String iconFile) throws IOException + { + byte iconType = Packet.ICON_PNG; + // Assume png as icon type + if(iconFile.toLowerCase().endsWith(".jpeg")) + iconType = Packet.ICON_JPEG; + if(iconFile.toLowerCase().endsWith(".jpg")) + iconType = Packet.ICON_JPEG; + if(iconFile.toLowerCase().endsWith(".gif")) + iconType = Packet.ICON_GIF; + + // Read the icon file to the byte array... + FileInputStream iconFileStream = new FileInputStream(iconFile); + byte[] iconData = new byte[iconFileStream.available()]; + iconFileStream.read(iconData); + + hasIcon = true; + + // Call start-Method... + startClient(hostAddress, hostPort, deviceName, iconType, iconData); + } + + + /** + * Starts a XBMC EventClient. + * @param hostAddress Address of the Host running XBMC + * @param hostPort Port of the Host running XBMC (default 9777) + * @param deviceName Name of the Device + * @param iconType Type of the icon file (see Packet.ICON_PNG, Packet.ICON_JPEG or Packet.ICON_GIF) + * @param iconData The icon itself as a Byte-Array + * @throws IOException + */ + public XBMCClient(InetAddress hostAddress, int hostPort, String deviceName, byte iconType, byte[] iconData) throws IOException + { + hasIcon = true; + startClient(hostAddress, hostPort, deviceName, iconType, iconData); + } + + /** + * Starts a XBMC EventClient without an icon. + * @param hostAddress Address of the Host running XBMC + * @param hostPort Port of the Host running XBMC (default 9777) + * @param deviceName Name of the Device + * @throws IOException + */ + public XBMCClient(InetAddress hostAddress, int hostPort, String deviceName) throws IOException + { + hasIcon = false; + byte iconType = Packet.ICON_NONE; + byte[] iconData = null; + startClient(hostAddress, hostPort, deviceName, iconType, iconData); + } + + + /** + * Starts a XBMC EventClient. + * @param hostAddress Address of the Host running XBMC + * @param hostPort Port of the Host running XBMC (default 9777) + * @param deviceName Name of the Device + * @param iconType Type of the icon file (see Packet.ICON_PNG, Packet.ICON_JPEG or Packet.ICON_GIF) + * @param iconData The icon itself as a Byte-Array + * @throws IOException + */ + private void startClient(InetAddress hostAddress, int hostPort, String deviceName, byte iconType, byte[] iconData) throws IOException + { + // Save host address and port + this.hostAddress = hostAddress; + this.hostPort = hostPort; + this.deviceName = deviceName; + + this.iconType = iconType; + this.iconData = iconData; + + // Send Hello Packet... + PacketHELO p; + if(hasIcon) + p = new PacketHELO(deviceName, iconType, iconData); + else + p = new PacketHELO(deviceName); + + p.send(hostAddress, hostPort); + + // Start Thread (for Ping packets...) + oPingThread = new PingThread(hostAddress, hostPort, 20000); + oPingThread.start(); + } + + /** + * Stops the XBMC EventClient (especially the Ping-Thread) + * @throws IOException + */ + public void stopClient() throws IOException + { + // Stop Ping-Thread... + oPingThread.giveup(); + oPingThread.interrupt(); + + PacketBYE p = new PacketBYE(); + p.send(hostAddress, hostPort); + } + + + /** + * Displays a notification window in XBMC. + * @param title Message title + * @param message The actual message + */ + public void sendNotification(String title, String message) throws IOException + { + PacketNOTIFICATION p; + if(hasIcon) + p = new PacketNOTIFICATION(title, message, iconType, iconData); + else + p = new PacketNOTIFICATION(title, message); + p.send(hostAddress, hostPort); + } + + /** + * Sends a Button event + * @param code raw button code (default: 0) + * @param repeat this key press should repeat until released (default: 1) + * Note that queued pressed cannot repeat. + * @param down if this is 1, it implies a press event, 0 implies a release + * event. (default: 1) + * @param queue a queued key press means that the button event is + * executed just once after which the next key press is processed. + * It can be used for macros. Currently there is no support for + * time delays between queued presses. (default: 0) + * @param amount unimplemented for now; in the future it will be used for + * specifying magnitude of analog key press events + * @param axis + */ + public void sendButton(short code, boolean repeat, boolean down, boolean queue, short amount, byte axis) throws IOException + { + PacketBUTTON p = new PacketBUTTON(code, repeat, down, queue, amount, axis); + p.send(hostAddress, hostPort); + } + + /** + * Sends a Button event + * @param map_name a combination of map_name and button_name refers to a + * mapping in the user's Keymap.xml or Lircmap.xml. + * map_name can be one of the following: + * <ul> + * <li>"KB" => standard keyboard map ( <keyboard> section )</li> + * <li>"XG" => xbox gamepad map ( <gamepad> section )</li> + * <li>"R1" => xbox remote map ( <remote> section )</li> + * <li>"R2" => xbox universal remote map ( <universalremote> section )</li> + * <li>"LI:devicename" => LIRC remote map where 'devicename' is the + * actual device's name</li></ul> + * @param button_name a button name defined in the map specified in map_name. + * For example, if map_name is "KB" referring to the <keyboard> section in Keymap.xml + * then, valid button_names include "printscreen", "minus", "x", etc. + * @param repeat this key press should repeat until released (default: 1) + * Note that queued pressed cannot repeat. + * @param down if this is 1, it implies a press event, 0 implies a release + * event. (default: 1) + * @param queue a queued key press means that the button event is + * executed just once after which the next key press is processed. + * It can be used for macros. Currently there is no support for + * time delays between queued presses. (default: 0) + * @param amount unimplemented for now; in the future it will be used for + * specifying magnitude of analog key press events + * @param axis + */ + public void sendButton(String map_name, String button_name, boolean repeat, boolean down, boolean queue, short amount, byte axis) throws IOException + { + PacketBUTTON p = new PacketBUTTON(map_name, button_name, repeat, down, queue, amount, axis); + p.send(hostAddress, hostPort); + } + + /** + * Sets the mouse position in XBMC + * @param x horizontal position ranging from 0 to 65535 + * @param y vertical position ranging from 0 to 65535 + */ + public void sendMouse(int x, int y) throws IOException + { + PacketMOUSE p = new PacketMOUSE(x, y); + p.send(hostAddress, hostPort); + } + + /** + * Sends a ping to the XBMC EventServer + * @throws IOException + */ + public void ping() throws IOException + { + PacketPING p = new PacketPING(); + p.send(hostAddress, hostPort); + } + + /** + * Tells XBMC to log the message to xbmc.log with the loglevel as specified. + * @param loglevel the loglevel, follows XBMC standard. + * <ul> + * <li>0 = DEBUG</li> + * <li>1 = INFO</li> + * <li>2 = NOTICE</li> + * <li>3 = WARNING</li> + * <li>4 = ERROR</li> + * <li>5 = SEVERE</li> + * </ul> + * @param logmessage the message to log + */ + public void sendLog(byte loglevel, String logmessage) throws IOException + { + PacketLOG p = new PacketLOG(loglevel, logmessage); + p.send(hostAddress, hostPort); + } + + /** + * Tells XBMC to do the action specified, based on the type it knows were it needs to be sent. + * @param actionmessage Actionmessage (as in scripting/skinning) + */ + public void sendAction(String actionmessage) throws IOException + { + PacketACTION p = new PacketACTION(actionmessage); + p.send(hostAddress, hostPort); + } + + /** + * Implements a PingThread which tells XBMC EventServer that the Client is alive (this should + * be done at least every 60 seconds! + * @author Stefan Agner + * + */ + class PingThread extends Thread + { + private InetAddress hostAddress; + private int hostPort; + private int sleepTime; + private boolean giveup = false; + + public PingThread(InetAddress hostAddress, int hostPort, int sleepTime) + { + super("XBMC EventClient Ping-Thread"); + this.hostAddress = hostAddress; + this.hostPort = hostPort; + this.sleepTime = sleepTime; + } + + public void giveup() + { + giveup = true; + } + + public void run() + { + while(!giveup) + { + try { + PacketPING p = new PacketPING(); + p.send(hostAddress, hostPort); + } catch (IOException e) { + + e.printStackTrace(); + } + + try { + Thread.sleep(sleepTime); + } catch (InterruptedException e) { + } + } + } + } +} diff --git a/tools/EventClients/lib/python/__init__.py b/tools/EventClients/lib/python/__init__.py new file mode 100644 index 0000000..7deecc4 --- /dev/null +++ b/tools/EventClients/lib/python/__init__.py @@ -0,0 +1,2 @@ +# -*- coding: utf-8 -*- +# File intentionally left blank diff --git a/tools/EventClients/lib/python/bt/__init__.py b/tools/EventClients/lib/python/bt/__init__.py new file mode 100644 index 0000000..7deecc4 --- /dev/null +++ b/tools/EventClients/lib/python/bt/__init__.py @@ -0,0 +1,2 @@ +# -*- coding: utf-8 -*- +# File intentionally left blank diff --git a/tools/EventClients/lib/python/bt/bt.py b/tools/EventClients/lib/python/bt/bt.py new file mode 100644 index 0000000..979ebf2 --- /dev/null +++ b/tools/EventClients/lib/python/bt/bt.py @@ -0,0 +1,82 @@ +# -*- coding: utf-8 -*- +# Copyright (C) 2008-2013 Team XBMC +# +# 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 Street, Fifth Floor, Boston, MA 02110-1301 USA. + +BLUEZ=0 + +try: + import bluetooth + BLUEZ=1 +except: + try: + import lightblue + except: + print("ERROR: You need to have either LightBlue or PyBluez installed\n"\ + " in order to use this program.") + print("- PyBluez (Linux / Windows XP) http://org.csail.mit.edu/pybluez/") + print("- LightBlue (Mac OS X / Linux) http://lightblue.sourceforge.net/") + exit() + +def bt_create_socket(): + if BLUEZ: + sock = bluetooth.BluetoothSocket(bluetooth.L2CAP) + else: + sock = lightblue.socket(lightblue.L2CAP) + return sock + +def bt_create_rfcomm_socket(): + if BLUEZ: + sock = bluetooth.BluetoothSocket( bluetooth.RFCOMM ) + sock.bind(("",bluetooth.PORT_ANY)) + else: + sock = lightblue.socket(lightblue.RFCOMM) + sock.bind(("",0)) + return sock + +def bt_discover_devices(): + if BLUEZ: + nearby = bluetooth.discover_devices() + else: + nearby = lightblue.finddevices() + return nearby + +def bt_lookup_name(bdaddr): + if BLUEZ: + bname = bluetooth.lookup_name( bdaddr ) + else: + bname = bdaddr[1] + return bname + +def bt_lookup_addr(bdaddr): + if BLUEZ: + return bdaddr + else: + return bdaddr[0] + +def bt_advertise(name, uuid, socket): + if BLUEZ: + bluetooth.advertise_service( socket, name, + service_id = uuid, + service_classes = [ uuid, bluetooth.SERIAL_PORT_CLASS ], + profiles = [ bluetooth.SERIAL_PORT_PROFILE ] ) + else: + lightblue.advertise(name, socket, lightblue.RFCOMM) + +def bt_stop_advertising(socket): + if BLUEZ: + stop_advertising(socket) + else: + lightblue.stopadvertise(socket) diff --git a/tools/EventClients/lib/python/bt/hid.py b/tools/EventClients/lib/python/bt/hid.py new file mode 100644 index 0000000..c065054 --- /dev/null +++ b/tools/EventClients/lib/python/bt/hid.py @@ -0,0 +1,81 @@ +# -*- coding: utf-8 -*- +# Copyright (C) 2008-2013 Team XBMC +# +# 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 Street, Fifth Floor, Boston, MA 02110-1301 USA. + +from bluetooth import * +import fcntl +import bluetooth._bluetooth as _bt +import array + +class HID: + def __init__(self, bdaddress=None): + self.cport = 0x11 # HID's control PSM + self.iport = 0x13 # HID' interrupt PSM + self.backlog = 1 + + self.address = "" + if bdaddress: + self.address = bdaddress + + # create the HID control socket + self.csock = BluetoothSocket( L2CAP ) + self.csock.bind((self.address, self.cport)) + set_l2cap_mtu(self.csock, 64) + self.csock.settimeout(2) + self.csock.listen(self.backlog) + + # create the HID interrupt socket + self.isock = BluetoothSocket( L2CAP ) + self.isock.bind((self.address, self.iport)) + set_l2cap_mtu(self.isock, 64) + self.isock.settimeout(2) + self.isock.listen(self.backlog) + + self.connected = False + + + def listen(self): + try: + (self.client_csock, self.caddress) = self.csock.accept() + print("Accepted Control connection from %s" % self.caddress[0]) + (self.client_isock, self.iaddress) = self.isock.accept() + print("Accepted Interrupt connection from %s" % self.iaddress[0]) + self.connected = True + return True + except Exception as e: + self.connected = False + return False + + def get_local_address(self): + hci = BluetoothSocket( HCI ) + fd = hci.fileno() + buf = array.array('B', [0] * 96) + fcntl.ioctl(fd, _bt.HCIGETDEVINFO, buf, 1) + data = struct.unpack_from("H8s6B", buf.tostring()) + return data[2:8][::-1] + + def get_control_socket(self): + if self.connected: + return (self.client_csock, self.caddress) + else: + return None + + + def get_interrupt_socket(self): + if self.connected: + return (self.client_isock, self.iaddress) + else: + return None diff --git a/tools/EventClients/lib/python/ps3/__init__.py b/tools/EventClients/lib/python/ps3/__init__.py new file mode 100644 index 0000000..7deecc4 --- /dev/null +++ b/tools/EventClients/lib/python/ps3/__init__.py @@ -0,0 +1,2 @@ +# -*- coding: utf-8 -*- +# File intentionally left blank diff --git a/tools/EventClients/lib/python/ps3/keymaps.py b/tools/EventClients/lib/python/ps3/keymaps.py new file mode 100644 index 0000000..99c6e04 --- /dev/null +++ b/tools/EventClients/lib/python/ps3/keymaps.py @@ -0,0 +1,81 @@ +# -*- coding: utf-8 -*- +# Copyright (C) 2008-2013 Team XBMC +# +# 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 Street, Fifth Floor, Boston, MA 02110-1301 USA. + +# PS3 Remote and Controller Keymaps + +keymap_remote = { + "16": 'power' ,#EJECT + "64": None ,#AUDIO + "65": None ,#ANGLE + "63": 'subtitle' ,#SUBTITLE + "0f": None ,#CLEAR + "28": None ,#TIME + + "00": 'one' ,#1 + "01": 'two' ,#2 + "02": 'three' ,#3 + "03": 'four' ,#4 + "04": 'five' ,#5 + "05": 'six' ,#6 + "06": 'seven' ,#7 + "07": 'eight' ,#8 + "08": 'nine' ,#9 + "09": 'zero' ,#0 + + "81": 'mytv' ,#RED + "82": 'mymusic' ,#GREEN + "80": 'mypictures' ,#BLUE + "83": 'myvideo' ,#YELLOW + + "70": 'display' ,#DISPLAY + "1a": None ,#TOP MENU + "40": 'menu' ,#POP UP/MENU + "0e": None ,#RETURN + + "5c": 'menu' ,#OPTIONS/TRIANGLE + "5d": 'back' ,#BACK/CIRCLE + "5e": 'info' ,#X + "5f": 'title' ,#VIEW/SQUARE + + "54": 'up' ,#UP + "55": 'right' ,#RIGHT + "56": 'down' ,#DOWN + "57": 'left' ,#LEFT + "0b": 'select' ,#ENTER + + "5a": 'volumeplus' ,#L1 + "58": 'volumeminus' ,#L2 + "51": 'Mute' ,#L3 + "5b": 'pageplus' ,#R1 + "59": 'pageminus' ,#R2 + "52": None ,#R3 + + "43": None ,#PLAYSTATION + "50": None ,#SELECT + "53": None ,#START + + "33": 'reverse' ,#<-SCAN + "34": 'forward' ,# SCAN-> + "30": 'skipminus' ,#PREV + "31": 'skipplus' ,#NEXT + "60": None ,#<-SLOW/STEP + "61": None ,# SLOW/STEP-> + "32": 'play' ,#PLAY + "38": 'stop' ,#STOP + "39": 'pause' ,#PAUSE + } + diff --git a/tools/EventClients/lib/python/ps3/sixaxis.py b/tools/EventClients/lib/python/ps3/sixaxis.py new file mode 100644 index 0000000..b4899f6 --- /dev/null +++ b/tools/EventClients/lib/python/ps3/sixaxis.py @@ -0,0 +1,372 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +# Copyright (C) 2008-2013 Team XBMC +# +# 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 Street, Fifth Floor, Boston, MA 02110-1301 USA. + +import time +import sys +import struct +import math +import binascii +from bluetooth import set_l2cap_mtu + +SX_SELECT = 1 << 0 +SX_L3 = 1 << 1 +SX_R3 = 1 << 2 +SX_START = 1 << 3 +SX_DUP = 1 << 4 +SX_DRIGHT = 1 << 5 +SX_DDOWN = 1 << 6 +SX_DLEFT = 1 << 7 +SX_L2 = 1 << 8 +SX_R2 = 1 << 9 +SX_L1 = 1 << 10 +SX_R1 = 1 << 11 +SX_TRIANGLE = 1 << 12 +SX_CIRCLE = 1 << 13 +SX_X = 1 << 14 +SX_SQUARE = 1 << 15 +SX_POWER = 1 << 16 + +SX_LSTICK_X = 0 +SX_LSTICK_Y = 1 +SX_RSTICK_X = 2 +SX_RSTICK_Y = 3 + +# (map, key, amount index, axis) +keymap_sixaxis = { + SX_X : ('XG', 'A', 0, 0), + SX_CIRCLE : ('XG', 'B', 0, 0), + SX_SQUARE : ('XG', 'X', 0, 0), + SX_TRIANGLE : ('XG', 'Y', 0, 0), + + SX_DUP : ('XG', 'dpadup', 0, 0), + SX_DDOWN : ('XG', 'dpaddown', 0, 0), + SX_DLEFT : ('XG', 'dpadleft', 0, 0), + SX_DRIGHT : ('XG', 'dpadright', 0, 0), + + SX_START : ('XG', 'start', 0, 0), + SX_SELECT : ('XG', 'back', 0, 0), + + SX_R1 : ('XG', 'white', 0, 0), + SX_R2 : ('XG', 'rightanalogtrigger', 6, 1), + SX_L2 : ('XG', 'leftanalogtrigger', 5, 1), + SX_L1 : ('XG', 'black', 0, 0), + + SX_L3 : ('XG', 'leftthumbbutton', 0, 0), + SX_R3 : ('XG', 'rightthumbbutton', 0, 0), +} + +# (data index, left map, left action, right map, right action) +axismap_sixaxis = { + SX_LSTICK_X : ('XG', 'leftthumbstickleft' , 'leftthumbstickright'), + SX_LSTICK_Y : ('XG', 'leftthumbstickup' , 'leftthumbstickdown'), + SX_RSTICK_X : ('XG', 'rightthumbstickleft', 'rightthumbstickright'), + SX_RSTICK_Y : ('XG', 'rightthumbstickup' , 'rightthumbstickdown'), +} + +# to make sure all combination keys are checked first +# we sort the keymap's button codes in reverse order +# this guarantees that any bit combined button code +# will be processed first +keymap_sixaxis_keys = keymap_sixaxis.keys() +keymap_sixaxis_keys.sort() +keymap_sixaxis_keys.reverse() + +def getkeys(bflags): + keys = []; + for k in keymap_sixaxis_keys: + if (k & bflags) == k: + keys.append(k) + bflags = bflags & ~k + return keys; + + +def normalize(val): + upperlimit = 65281 + lowerlimit = 2 + val_range = upperlimit - lowerlimit + offset = 10000 + + val = (val + val_range / 2) % val_range + upperlimit -= offset + lowerlimit += offset + + if val < lowerlimit: + val = lowerlimit + if val > upperlimit: + val = upperlimit + + val = ((float(val) - offset) / (float(upperlimit) - + lowerlimit)) * 65535.0 + if val <= 0: + val = 1 + return val + +def normalize_axis(val, deadzone): + + val = float(val) - 127.5 + val = val / 127.5 + + if abs(val) < deadzone: + return 0.0 + + if val > 0.0: + val = (val - deadzone) / (1.0 - deadzone) + else: + val = (val + deadzone) / (1.0 - deadzone) + + return 65536.0 * val + +def normalize_angle(val, valrange): + valrange *= 2 + + val = val / valrange + if val > 1.0: + val = 1.0 + if val < -1.0: + val = -1.0 + return (val + 0.5) * 65535.0 + +def average(array): + val = 0 + for i in array: + val += i + return val / len(array) + +def smooth(arr, val): + cnt = len(arr) + arr.insert(0, val) + arr.pop(cnt) + return average(arr) + +def set_l2cap_mtu2(sock, mtu): + SOL_L2CAP = 6 + L2CAP_OPTIONS = 1 + + s = sock.getsockopt (SOL_L2CAP, L2CAP_OPTIONS, 12) + o = list( struct.unpack ("HHHBBBH", s) ) + o[0] = o[1] = mtu + s = struct.pack ("HHHBBBH", *o) + try: + sock.setsockopt (SOL_L2CAP, L2CAP_OPTIONS, s) + except: + print("Warning: Unable to set mtu") + +class sixaxis(): + + def __init__(self, xbmc, control_sock, interrupt_sock): + + self.xbmc = xbmc + self.num_samples = 16 + self.sumx = [0] * self.num_samples + self.sumy = [0] * self.num_samples + self.sumr = [0] * self.num_samples + self.axis_amount = [0, 0, 0, 0] + + self.released = set() + self.pressed = set() + self.pending = set() + self.held = set() + self.psflags = 0 + self.psdown = 0 + self.mouse_enabled = 0 + + set_l2cap_mtu2(control_sock, 64) + set_l2cap_mtu2(interrupt_sock, 64) + time.sleep(0.25) # If we ask to quickly here, it sometimes doesn't start + + # sixaxis needs this to enable it + # 0x53 => HIDP_TRANS_SET_REPORT | HIDP_DATA_RTYPE_FEATURE + control_sock.send("\x53\xf4\x42\x03\x00\x00") + data = control_sock.recv(1) + # This command will turn on the gyro and set the leds + # I wonder if turning on the gyro makes it draw more current?? + # it's probably a flag somewhere in the following command + + # HID Command: HIDP_TRANS_SET_REPORT | HIDP_DATA_RTYPE_OUTPUT + # HID Report:1 + bytes = [0x52, 0x1] + bytes.extend([0x00, 0x00, 0x00]) + bytes.extend([0xFF, 0x72]) + bytes.extend([0x00, 0x00, 0x00, 0x00]) + bytes.extend([0x02]) # 0x02 LED1, 0x04 LED2 ... 0x10 LED4 + # The following sections should set the blink frequency of + # the leds on the controller, but i've not figured out how. + # These values where suggested in a mailing list, but no explanation + # for how they should be combined to the 5 bytes per led + #0xFF = 0.5Hz + #0x80 = 1Hz + #0x40 = 2Hz + bytes.extend([0xFF, 0x00, 0x01, 0x00, 0x01]) #LED4 [0xff, 0xff, 0x10, 0x10, 0x10] + bytes.extend([0xFF, 0x00, 0x01, 0x00, 0x01]) #LED3 [0xff, 0x40, 0x08, 0x10, 0x10] + bytes.extend([0xFF, 0x00, 0x01, 0x00, 0x01]) #LED2 [0xff, 0x00, 0x10, 0x30, 0x30] + bytes.extend([0xFF, 0x00, 0x01, 0x00, 0x01]) #LED1 [0xff, 0x00, 0x10, 0x40, 0x10] + bytes.extend([0x00, 0x00, 0x00, 0x00, 0x00]) + bytes.extend([0x00, 0x00, 0x00, 0x00, 0x00]) + + control_sock.send(struct.pack("42B", *bytes)) + data = control_sock.recv(1) + + def __del__(self): + self.close() + + def close(self): + + for key in (self.held | self.pressed): + (mapname, action, amount, axis) = keymap_sixaxis[key] + self.xbmc.send_button_state(map=mapname, button=action, amount=0, down=0, axis=axis) + self.held = set() + self.pressed = set() + + + def process_socket(self, isock): + data = isock.recv(50) + if data == None: + return False + return self.process_data(data) + + + def process_data(self, data): + if len(data) < 3: + return False + + # make sure this is the correct report + if struct.unpack("BBB", data[0:3]) != (0xa1, 0x01, 0x00): + return False + + if len(data) >= 48: + v1 = struct.unpack("h", data[42:44]) + v2 = struct.unpack("h", data[44:46]) + v3 = struct.unpack("h", data[46:48]) + else: + v1 = [0,0] + v2 = [0,0] + v3 = [0,0] + + if len(data) >= 50: + v4 = struct.unpack("h", data[48:50]) + else: + v4 = [0,0] + + ax = float(v1[0]) + ay = float(v2[0]) + az = float(v3[0]) + rz = float(v4[0]) + at = math.sqrt(ax*ax + ay*ay + az*az) + + bflags = struct.unpack("<I", data[3:7])[0] + if len(data) > 27: + pressure = struct.unpack("BBBBBBBBBBBB", data[15:27]) + else: + pressure = [0,0,0,0,0,0,0,0,0,0,0,0,0] + + roll = -math.atan2(ax, math.sqrt(ay*ay + az*az)) + pitch = math.atan2(ay, math.sqrt(ax*ax + az*az)) + + pitch -= math.radians(20); + + xpos = normalize_angle(roll, math.radians(30)) + ypos = normalize_angle(pitch, math.radians(30)) + + + axis = struct.unpack("BBBB", data[7:11]) + return self.process_input(bflags, pressure, axis, xpos, ypos) + + def process_input(self, bflags, pressure, axis, xpos, ypos): + + xval = smooth(self.sumx, xpos) + yval = smooth(self.sumy, ypos) + + analog = False + for i in range(4): + config = axismap_sixaxis[i] + self.axis_amount[i] = self.send_singleaxis(axis[i], self.axis_amount[i], config[0], config[1], config[2]) + if self.axis_amount[i] != 0: + analog = True + + # send the mouse position to xbmc + if self.mouse_enabled == 1: + self.xbmc.send_mouse_position(xval, yval) + + if (bflags & SX_POWER) == SX_POWER: + if self.psdown: + if (time.time() - self.psdown) > 5: + + for key in (self.held | self.pressed): + (mapname, action, amount, axis) = keymap_sixaxis[key] + self.xbmc.send_button_state(map=mapname, button=action, amount=0, down=0, axis=axis) + + raise Exception("PS3 Sixaxis powering off, user request") + else: + self.psdown = time.time() + else: + if self.psdown: + self.mouse_enabled = 1 - self.mouse_enabled + self.psdown = 0 + + keys = set(getkeys(bflags)) + self.released = (self.pressed | self.held) - keys + self.held = (self.pressed | self.held) - self.released + self.pressed = (keys - self.held) & self.pending + self.pending = (keys - self.held) + + for key in self.released: + (mapname, action, amount, axis) = keymap_sixaxis[key] + self.xbmc.send_button_state(map=mapname, button=action, amount=0, down=0, axis=axis) + + for key in self.held: + (mapname, action, amount, axis) = keymap_sixaxis[key] + if amount > 0: + amount = pressure[amount-1] * 256 + self.xbmc.send_button_state(map=mapname, button=action, amount=amount, down=1, axis=axis) + + for key in self.pressed: + (mapname, action, amount, axis) = keymap_sixaxis[key] + if amount > 0: + amount = pressure[amount-1] * 256 + self.xbmc.send_button_state(map=mapname, button=action, amount=amount, down=1, axis=axis) + + if analog or keys or self.mouse_enabled: + return True + else: + return False + + + def send_singleaxis(self, axis, last_amount, mapname, action_min, action_pos): + amount = normalize_axis(axis, 0.30) + if last_amount < 0: + last_action = action_min + elif last_amount > 0: + last_action = action_pos + else: + last_action = None + + if amount < 0: + new_action = action_min + elif amount > 0: + new_action = action_pos + else: + new_action = None + + if last_action and new_action != last_action: + self.xbmc.send_button_state(map=mapname, button=last_action, amount=0, axis=1) + + if new_action and amount != last_amount: + self.xbmc.send_button_state(map=mapname, button=new_action, amount=abs(amount), axis=1) + + return amount diff --git a/tools/EventClients/lib/python/ps3/sixpair.py b/tools/EventClients/lib/python/ps3/sixpair.py new file mode 100755 index 0000000..01f11c8 --- /dev/null +++ b/tools/EventClients/lib/python/ps3/sixpair.py @@ -0,0 +1,114 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +import sys +import usb + +vendor = 0x054c +product = 0x0268 +timeout = 5000 +passed_value = 0x03f5 + +def find_sixaxes(): + res = [] + for bus in usb.busses(): + for dev in bus.devices: + if dev.idVendor == vendor and dev.idProduct == product: + res.append(dev) + return res + +def find_interface(dev): + for cfg in dev.configurations: + for itf in cfg.interfaces: + for alt in itf: + if alt.interfaceClass == 3: + return alt + raise Exception("Unable to find interface") + +def mac_to_string(mac): + return "%02x:%02x:%02x:%02x:%02x:%02x" % (mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]) + +def set_pair_filename(dirname, filename, mac): + for bus in usb.busses(): + if int(bus.dirname) == int(dirname): + for dev in bus.devices: + if int(dev.filename) == int(filename): + if dev.idVendor == vendor and dev.idProduct == product: + update_pair(dev, mac) + return + else: + raise Exception("Device is not a sixaxis") + raise Exception("Device not found") + + +def set_pair(dev, mac): + itf = find_interface(dev) + handle = dev.open() + + msg = (0x01, 0x00) + mac; + + try: + handle.detachKernelDriver(itf.interfaceNumber) + except usb.USBError: + pass + + handle.claimInterface(itf.interfaceNumber) + try: + handle.controlMsg(usb.ENDPOINT_OUT | usb.TYPE_CLASS | usb.RECIP_INTERFACE + , usb.REQ_SET_CONFIGURATION, msg, passed_value, itf.interfaceNumber, timeout) + finally: + handle.releaseInterface() + + +def get_pair(dev): + itf = find_interface(dev) + handle = dev.open() + + try: + handle.detachKernelDriver(itf.interfaceNumber) + except usb.USBError: + pass + + handle.claimInterface(itf.interfaceNumber) + try: + msg = handle.controlMsg(usb.ENDPOINT_IN | usb.TYPE_CLASS | usb.RECIP_INTERFACE + , usb.REQ_CLEAR_FEATURE, 8, passed_value, itf.interfaceNumber, timeout) + finally: + handle.releaseInterface() + return msg[2:8] + +def set_pair_all(mac): + devs = find_sixaxes() + for dev in devs: + update_pair(dev, mac) + +def update_pair(dev, mac): + old = get_pair(dev) + if old != mac: + print("Re-pairing sixaxis from:" + mac_to_string(old) + " to:" + mac_to_string(mac)) + set_pair(dev, mac) + +if __name__=="__main__": + devs = find_sixaxes() + + mac = None + if len(sys.argv) > 1: + try: + mac = sys.argv[1].split(':') + mac = tuple([int(x, 16) for x in mac]) + if len(mac) != 6: + print("Invalid length of HCI address, should be 6 parts") + mac = None + except: + print("Failed to parse HCI address") + mac = None + + for dev in devs: + if mac: + update_pair(dev, mac) + else: + print("Found sixaxis paired to: " + mac_to_string(get_pair(dev))) + + + + diff --git a/tools/EventClients/lib/python/ps3/sixwatch.py b/tools/EventClients/lib/python/ps3/sixwatch.py new file mode 100755 index 0000000..553829b --- /dev/null +++ b/tools/EventClients/lib/python/ps3/sixwatch.py @@ -0,0 +1,31 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +import pyudev +import sixpair +import threading + +vendor = 0x054c +product = 0x0268 + + +def main(mac): + context = pyudev.Context() + monitor = pyudev.Monitor.from_netlink(context) + monitor.filter_by(subsystem="usb") + for action, device in monitor: + if 'ID_VENDOR_ID' in device and 'ID_MODEL_ID' in device: + if device['ID_VENDOR_ID'] == '054c' and device['ID_MODEL_ID'] == '0268': + if action == 'add': + print("Detected sixaxis connected by usb") + try: + sixpair.set_pair_filename(device.attributes['busnum'], device.attributes['devnum'], mac) + except Exception as e: + print("Failed to check pairing of sixaxis: " + str(e)) + pass + + + +if __name__=="__main__": + main((0,0,0,0,0,0)) + diff --git a/tools/EventClients/lib/python/xbmcclient.py b/tools/EventClients/lib/python/xbmcclient.py new file mode 100644 index 0000000..548c443 --- /dev/null +++ b/tools/EventClients/lib/python/xbmcclient.py @@ -0,0 +1,639 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +# Copyright (C) 2008-2013 Team XBMC +# +# 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 Street, Fifth Floor, Boston, MA 02110-1301 USA. + +""" +Implementation of XBMC's UDP based input system. + +A set of classes that abstract the various packets that the event server +currently supports. In addition, there's also a class, XBMCClient, that +provides functions that sends the various packets. Use XBMCClient if you +don't need complete control over packet structure. + +The basic workflow involves: + +1. Send a HELO packet +2. Send x number of valid packets +3. Send a BYE packet + +IMPORTANT NOTE ABOUT TIMEOUTS: +A client is considered to be timed out if XBMC doesn't received a packet +at least once every 60 seconds. To "ping" XBMC with an empty packet use +PacketPING or XBMCClient.ping(). See the documentation for details. +""" + +from __future__ import unicode_literals, print_function, absolute_import, division + +__author__ = "d4rk@xbmc.org" +__version__ = "0.1.0" + +import sys +if sys.version_info.major == 2: + str = unicode +from struct import pack +from socket import socket, AF_INET, SOCK_DGRAM, SOL_SOCKET, SO_BROADCAST +import time + +MAX_PACKET_SIZE = 1024 +HEADER_SIZE = 32 +MAX_PAYLOAD_SIZE = MAX_PACKET_SIZE - HEADER_SIZE +UNIQUE_IDENTIFICATION = (int)(time.time()) + +PT_HELO = 0x01 +PT_BYE = 0x02 +PT_BUTTON = 0x03 +PT_MOUSE = 0x04 +PT_PING = 0x05 +PT_BROADCAST = 0x06 +PT_NOTIFICATION = 0x07 +PT_BLOB = 0x08 +PT_LOG = 0x09 +PT_ACTION = 0x0A +PT_DEBUG = 0xFF + +ICON_NONE = 0x00 +ICON_JPEG = 0x01 +ICON_PNG = 0x02 +ICON_GIF = 0x03 + +BT_USE_NAME = 0x01 +BT_DOWN = 0x02 +BT_UP = 0x04 +BT_USE_AMOUNT = 0x08 +BT_QUEUE = 0x10 +BT_NO_REPEAT = 0x20 +BT_VKEY = 0x40 +BT_AXIS = 0x80 +BT_AXISSINGLE = 0x100 + +MS_ABSOLUTE = 0x01 + +LOGDEBUG = 0x00 +LOGINFO = 0x01 +LOGWARNING = 0x02 +LOGERROR = 0x03 +LOGFATAL = 0x04 +LOGNONE = 0x05 + +ACTION_EXECBUILTIN = 0x01 +ACTION_BUTTON = 0x02 + +###################################################################### +# Helper Functions +###################################################################### + +def format_string(msg): + """ """ + return msg.encode('utf-8') + b"\0" + +def format_uint32(num): + """ """ + return pack ("!I", num) + +def format_uint16(num): + """ """ + if num<0: + num = 0 + elif num>65535: + num = 65535 + return pack ("!H", num) + + +###################################################################### +# Packet Classes +###################################################################### + +class Packet: + """Base class that implements a single event packet. + + - Generic packet structure (maximum 1024 bytes per packet) + - Header is 32 bytes long, so 992 bytes available for payload + - large payloads can be split into multiple packets using H4 and H5 + H5 should contain total no. of packets in such a case + - H6 contains length of P1, which is limited to 992 bytes + - if H5 is 0 or 1, then H4 will be ignored (single packet msg) + - H7 must be set to zeros for now + + ----------------------------- + | -H1 Signature ("XBMC") | - 4 x CHAR 4B + | -H2 Version (eg. 2.0) | - 2 x UNSIGNED CHAR 2B + | -H3 PacketType | - 1 x UNSIGNED SHORT 2B + | -H4 Sequence number | - 1 x UNSIGNED LONG 4B + | -H5 No. of packets in msg | - 1 x UNSIGNED LONG 4B + | -H7 Client's unique token | - 1 x UNSIGNED LONG 4B + | -H8 Reserved | - 10 x UNSIGNED CHAR 10B + |---------------------------| + | -P1 payload | - + ----------------------------- + """ + def __init__(self): + self.sig = b"XBMC" + self.minver = 0 + self.majver = 2 + self.seq = 1 + self.maxseq = 1 + self.payloadsize = 0 + self.uid = UNIQUE_IDENTIFICATION + self.reserved = b"\0" * 10 + self.payload = b"" + + def append_payload(self, blob): + """Append to existing payload + + Arguments: + blob -- binary data to append to the current payload + """ + if isinstance(blob, str): + blob = blob.encode() + self.set_payload(self.payload + blob) + + + def set_payload(self, payload): + """Set the payload for this packet + + Arguments: + payload -- binary data that contains the payload + """ + if isinstance(payload, str): + payload = payload.encode() + self.payload = payload + self.payloadsize = len(self.payload) + self.maxseq = int((self.payloadsize + (MAX_PAYLOAD_SIZE - 1)) / MAX_PAYLOAD_SIZE) + + + def num_packets(self): + """ Return the number of packets required for payload """ + return self.maxseq + + def get_header(self, packettype=-1, seq=1, maxseq=1, payload_size=0): + """Construct a header and return as string + + Keyword arguments: + packettype -- valid packet types are PT_HELO, PT_BYE, PT_BUTTON, + PT_MOUSE, PT_PING, PT_BORADCAST, PT_NOTIFICATION, + PT_BLOB, PT_DEBUG + seq -- the sequence of this packet for a multi packet message + (default 1) + maxseq -- the total number of packets for a multi packet message + (default 1) + payload_size -- the size of the payload of this packet (default 0) + """ + if packettype < 0: + packettype = self.packettype + header = self.sig + header += chr(self.majver).encode() + header += chr(self.minver).encode() + header += format_uint16(packettype) + header += format_uint32(seq) + header += format_uint32(maxseq) + header += format_uint16(payload_size) + header += format_uint32(self.uid) + header += self.reserved + return header + + def get_payload_size(self, seq): + """Returns the calculated payload size for the particular packet + + Arguments: + seq -- the sequence number + """ + if self.maxseq == 1: + return self.payloadsize + + if seq < self.maxseq: + return MAX_PAYLOAD_SIZE + + return self.payloadsize % MAX_PAYLOAD_SIZE + + + def get_udp_message(self, packetnum=1): + """Construct the UDP message for the specified packetnum and return + as string + + Keyword arguments: + packetnum -- the packet no. for which to construct the message + (default 1) + """ + if packetnum > self.num_packets() or packetnum < 1: + return b"" + header = b"" + if packetnum==1: + header = self.get_header(self.packettype, packetnum, self.maxseq, + self.get_payload_size(packetnum)) + else: + header = self.get_header(PT_BLOB, packetnum, self.maxseq, + self.get_payload_size(packetnum)) + + payload = self.payload[ (packetnum-1) * MAX_PAYLOAD_SIZE : + (packetnum-1) * MAX_PAYLOAD_SIZE+ + self.get_payload_size(packetnum) ] + return header + payload + + def send(self, sock, addr, uid=UNIQUE_IDENTIFICATION): + """Send the entire message to the specified socket and address. + + Arguments: + sock -- datagram socket object (socket.socket) + addr -- address, port pair (eg: ("127.0.0.1", 9777) ) + uid -- unique identification + """ + self.uid = uid + for a in range ( 0, self.num_packets() ): + sock.sendto(self.get_udp_message(a+1), addr) + + +class PacketHELO (Packet): + """A HELO packet + + A HELO packet establishes a valid connection to XBMC. It is the + first packet that should be sent. + """ + def __init__(self, devicename=None, icon_type=ICON_NONE, icon_file=None): + """ + Keyword arguments: + devicename -- the string that identifies the client + icon_type -- one of ICON_NONE, ICON_JPEG, ICON_PNG, ICON_GIF + icon_file -- location of icon file with respect to current working + directory if icon_type is not ICON_NONE + """ + Packet.__init__(self) + self.packettype = PT_HELO + self.icontype = icon_type + self.set_payload ( format_string(devicename)[0:128] ) + self.append_payload( chr (icon_type) ) + self.append_payload( format_uint16 (0) ) # port no + self.append_payload( format_uint32 (0) ) # reserved1 + self.append_payload( format_uint32 (0) ) # reserved2 + if icon_type != ICON_NONE and icon_file: + with open(icon_file, 'rb') as f: + self.append_payload(f.read()) + + +class PacketNOTIFICATION (Packet): + """A NOTIFICATION packet + + This packet displays a notification window in XBMC. It can contain + a caption, a message and an icon. + """ + def __init__(self, title, message, icon_type=ICON_NONE, icon_file=None): + """ + Keyword arguments: + title -- the notification caption / title + message -- the main text of the notification + icon_type -- one of ICON_NONE, ICON_JPEG, ICON_PNG, ICON_GIF + icon_file -- location of icon file with respect to current working + directory if icon_type is not ICON_NONE + """ + Packet.__init__(self) + self.packettype = PT_NOTIFICATION + self.title = title + self.message = message + self.set_payload ( format_string(title) ) + self.append_payload( format_string(message) ) + self.append_payload( chr (icon_type) ) + self.append_payload( format_uint32 (0) ) # reserved + if icon_type != ICON_NONE and icon_file: + with open(icon_file, 'rb') as f: + self.append_payload(f.read()) + +class PacketBUTTON (Packet): + """A BUTTON packet + + A button packet send a key press or release event to XBMC + """ + def __init__(self, code=0, repeat=1, down=1, queue=0, + map_name="", button_name="", amount=0, axis=0): + """ + Keyword arguments: + code -- raw button code (default: 0) + repeat -- this key press should repeat until released (default: 1) + Note that queued pressed cannot repeat. + down -- if this is 1, it implies a press event, 0 implies a release + event. (default: 1) + queue -- a queued key press means that the button event is + executed just once after which the next key press is + processed. It can be used for macros. Currently there + is no support for time delays between queued presses. + (default: 0) + map_name -- a combination of map_name and button_name refers to a + mapping in the user's Keymap.xml or Lircmap.xml. + map_name can be one of the following: + "KB" => standard keyboard map ( <keyboard> section ) + "XG" => xbox gamepad map ( <gamepad> section ) + "R1" => xbox remote map ( <remote> section ) + "R2" => xbox universal remote map ( <universalremote> + section ) + "LI:devicename" => LIRC remote map where 'devicename' is the + actual device's name + button_name -- a button name defined in the map specified in map_name. + For example, if map_name is "KB" referring to the + <keyboard> section in Keymap.xml then, valid + button_names include "printscreen", "minus", "x", etc. + amount -- unimplemented for now; in the future it will be used for + specifying magnitude of analog key press events + """ + Packet.__init__(self) + self.flags = 0 + self.packettype = PT_BUTTON + if type (code ) == str: + code = ord(code) + + # assign code only if we don't have a map and button name + if not (map_name and button_name): + self.code = code + else: + self.flags |= BT_USE_NAME + self.code = 0 + if (amount != None): + self.flags |= BT_USE_AMOUNT + self.amount = int(amount) + else: + self.amount = 0 + + if down: + self.flags |= BT_DOWN + else: + self.flags |= BT_UP + if not repeat: + self.flags |= BT_NO_REPEAT + if queue: + self.flags |= BT_QUEUE + if axis == 1: + self.flags |= BT_AXISSINGLE + elif axis == 2: + self.flags |= BT_AXIS + + self.set_payload ( format_uint16(self.code) ) + self.append_payload( format_uint16(self.flags) ) + self.append_payload( format_uint16(self.amount) ) + self.append_payload( format_string (map_name) ) + self.append_payload( format_string (button_name) ) + +class PacketMOUSE (Packet): + """A MOUSE packet + + A MOUSE packets sets the mouse position in XBMC + """ + def __init__(self, x, y): + """ + Arguments: + x -- horizontal position ranging from 0 to 65535 + y -- vertical position ranging from 0 to 65535 + + The range will be mapped to the screen width and height in XBMC + """ + Packet.__init__(self) + self.packettype = PT_MOUSE + self.flags = MS_ABSOLUTE + self.append_payload( chr (self.flags) ) + self.append_payload( format_uint16(x) ) + self.append_payload( format_uint16(y) ) + +class PacketBYE (Packet): + """A BYE packet + + A BYE packet terminates the connection to XBMC. + """ + def __init__(self): + Packet.__init__(self) + self.packettype = PT_BYE + + +class PacketPING (Packet): + """A PING packet + + A PING packet tells XBMC that the client is still alive. All valid + packets act as ping (not just this one). A client needs to ping + XBMC at least once in 60 seconds or it will time out. + """ + def __init__(self): + Packet.__init__(self) + self.packettype = PT_PING + +class PacketLOG (Packet): + """A LOG packet + + A LOG packet tells XBMC to log the message to xbmc.log with the loglevel as specified. + """ + def __init__(self, loglevel=0, logmessage="", autoprint=True): + """ + Keyword arguments: + loglevel -- the loglevel, follows XBMC standard. + logmessage -- the message to log + autoprint -- if the logmessage should automatically be printed to stdout + """ + Packet.__init__(self) + self.packettype = PT_LOG + self.append_payload( chr (loglevel) ) + self.append_payload( format_string(logmessage) ) + if (autoprint): + print(logmessage) + +class PacketACTION (Packet): + """An ACTION packet + + An ACTION packet tells XBMC to do the action specified, based on the type it knows were it needs to be sent. + The idea is that this will be as in scripting/skining and keymapping, just triggered from afar. + """ + def __init__(self, actionmessage="", actiontype=ACTION_EXECBUILTIN): + """ + Keyword arguments: + loglevel -- the loglevel, follows XBMC standard. + logmessage -- the message to log + autoprint -- if the logmessage should automatically be printed to stdout + """ + Packet.__init__(self) + self.packettype = PT_ACTION + self.append_payload( chr (actiontype) ) + self.append_payload( format_string(actionmessage) ) + +###################################################################### +# XBMC Client Class +###################################################################### + +class XBMCClient: + """An XBMC event client""" + + def __init__(self, name ="", icon_file=None, broadcast=False, uid=UNIQUE_IDENTIFICATION, + ip="127.0.0.1"): + """ + Keyword arguments: + name -- Name of the client + icon_file -- location of an icon file, if any (png, jpg or gif) + uid -- unique identification + """ + self.name = str(name) + self.icon_file = icon_file + self.icon_type = self._get_icon_type(icon_file) + self.ip = ip + self.port = 9777 + self.sock = socket(AF_INET,SOCK_DGRAM) + if broadcast: + self.sock.setsockopt(SOL_SOCKET, SO_BROADCAST, 1) + self.uid = uid + + + def connect(self, ip=None, port=None): + """Initialize connection to XBMC + ip -- IP Address of XBMC + port -- port that the event server on XBMC is listening on + """ + if ip: + self.ip = ip + if port: + self.port = int(port) + self.addr = (self.ip, self.port) + packet = PacketHELO(self.name, self.icon_type, self.icon_file) + packet.send(self.sock, self.addr, self.uid) + + + def close(self): + """Close the current connection""" + packet = PacketBYE() + packet.send(self.sock, self.addr, self.uid) + + + def ping(self): + """Send a PING packet""" + packet = PacketPING() + packet.send(self.sock, self.addr, self.uid) + + + def send_notification(self, title="", message="", icon_file=None): + """Send a notification to the connected XBMC + Keyword Arguments: + title -- The title/heading for the notification + message -- The message to be displayed + icon_file -- location of an icon file, if any (png, jpg, gif) + """ + self.connect() + packet = PacketNOTIFICATION(title, message, + self._get_icon_type(icon_file), + icon_file) + packet.send(self.sock, self.addr, self.uid) + + + def send_keyboard_button(self, button=None): + """Send a keyboard event to XBMC + Keyword Arguments: + button -- name of the keyboard button to send (same as in Keymap.xml) + """ + if not button: + return + self.send_button(map="KB", button=button) + + + def send_remote_button(self, button=None): + """Send a remote control event to XBMC + Keyword Arguments: + button -- name of the remote control button to send (same as in Keymap.xml) + """ + if not button: + return + self.send_button(map="R1", button=button) + + + def release_button(self): + """Release all buttons""" + packet = PacketBUTTON(code=0x01, down=0) + packet.send(self.sock, self.addr, self.uid) + + + def send_button(self, map="", button="", amount=0): + """Send a button event to XBMC + Keyword arguments: + map -- a combination of map_name and button_name refers to a + mapping in the user's Keymap.xml or Lircmap.xml. + map_name can be one of the following: + "KB" => standard keyboard map ( <keyboard> section ) + "XG" => xbox gamepad map ( <gamepad> section ) + "R1" => xbox remote map ( <remote> section ) + "R2" => xbox universal remote map ( <universalremote> + section ) + "LI:devicename" => LIRC remote map where 'devicename' is the + actual device's name + button -- a button name defined in the map specified in map, above. + For example, if map is "KB" referring to the <keyboard> + section in Keymap.xml then, valid buttons include + "printscreen", "minus", "x", etc. + """ + packet = PacketBUTTON(map_name=str(map), button_name=str(button), amount=amount) + packet.send(self.sock, self.addr, self.uid) + + def send_button_state(self, map="", button="", amount=0, down=0, axis=0): + """Send a button event to XBMC + Keyword arguments: + map -- a combination of map_name and button_name refers to a + mapping in the user's Keymap.xml or Lircmap.xml. + map_name can be one of the following: + "KB" => standard keyboard map ( <keyboard> section ) + "XG" => xbox gamepad map ( <gamepad> section ) + "R1" => xbox remote map ( <remote> section ) + "R2" => xbox universal remote map ( <universalremote> + section ) + "LI:devicename" => LIRC remote map where 'devicename' is the + actual device's name + button -- a button name defined in the map specified in map, above. + For example, if map is "KB" referring to the <keyboard> + section in Keymap.xml then, valid buttons include + "printscreen", "minus", "x", etc. + """ + if axis: + down = int(amount != 0) + + packet = PacketBUTTON(map_name=str(map), button_name=str(button), amount=amount, down=down, queue=1, axis=axis) + packet.send(self.sock, self.addr, self.uid) + + def send_mouse_position(self, x=0, y=0): + """Send a mouse event to XBMC + Keywords Arguments: + x -- absolute x position of mouse ranging from 0 to 65535 + which maps to the entire screen width + y -- same a 'x' but relates to the screen height + """ + packet = PacketMOUSE(int(x), int(y)) + packet.send(self.sock, self.addr, self.uid) + + def send_log(self, loglevel=0, logmessage="", autoprint=True): + """ + Keyword arguments: + loglevel -- the loglevel, follows XBMC standard. + logmessage -- the message to log + autoprint -- if the logmessage should automatically be printed to stdout + """ + packet = PacketLOG(loglevel, logmessage) + packet.send(self.sock, self.addr, self.uid) + + def send_action(self, actionmessage="", actiontype=ACTION_EXECBUILTIN): + """ + Keyword arguments: + actionmessage -- the ActionString + actiontype -- The ActionType the ActionString should be sent to. + """ + packet = PacketACTION(actionmessage, actiontype) + packet.send(self.sock, self.addr, self.uid) + + def _get_icon_type(self, icon_file): + if icon_file: + if icon_file.lower()[-3:] == "png": + return ICON_PNG + elif icon_file.lower()[-3:] == "gif": + return ICON_GIF + elif icon_file.lower()[-3:] == "jpg": + return ICON_JPEG + return ICON_NONE diff --git a/tools/EventClients/lib/python/zeroconf.py b/tools/EventClients/lib/python/zeroconf.py new file mode 100644 index 0000000..ee2af14 --- /dev/null +++ b/tools/EventClients/lib/python/zeroconf.py @@ -0,0 +1,160 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +# Copyright (C) 2008-2013 Team XBMC +# +# 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 Street, Fifth Floor, Boston, MA 02110-1301 USA. + +""" +Simple wrapper around Avahi +""" + +__author__ = "d4rk@xbmc.org" +__version__ = "0.1" + +try: + import time + import dbus, avahi + from dbus import DBusException + from dbus.mainloop.glib import DBusGMainLoop + from gi.repository import GLib +except Exception as e: + print("Zeroconf support disabled. To enable, install the following Python modules:") + print(" dbus, gi, avahi") + pass + +SERVICE_FOUND = 1 +SERVICE_LOST = 2 + +class Browser: + """ Simple Zeroconf Browser """ + + def __init__( self, service_types = {} ): + """ + service_types - dictionary of services => handlers + """ + self._stop = False + self.loop = DBusGMainLoop() + self.bus = dbus.SystemBus( mainloop=self.loop ) + self.server = dbus.Interface( self.bus.get_object( avahi.DBUS_NAME, '/' ), + 'org.freedesktop.Avahi.Server') + self.handlers = {} + + for type in service_types.keys(): + self.add_service( type, service_types[ type ] ) + + + def add_service( self, type, handler = None ): + """ + Add a service that the browser should watch for + """ + self.sbrowser = dbus.Interface( + self.bus.get_object( + avahi.DBUS_NAME, + self.server.ServiceBrowserNew( + avahi.IF_UNSPEC, + avahi.PROTO_UNSPEC, + type, + 'local', + dbus.UInt32(0) + ) + ), + avahi.DBUS_INTERFACE_SERVICE_BROWSER) + self.handlers[ type ] = handler + self.sbrowser.connect_to_signal("ItemNew", self._new_item_handler) + self.sbrowser.connect_to_signal("ItemRemove", self._remove_item_handler) + + + def run(self): + """ + Run the GLib event loop + """ + # Don't use loop.run() because Python's GIL will block all threads + loop = GLib.MainLoop() + context = loop.get_context() + while not self._stop: + if context.pending(): + context.iteration( True ) + else: + time.sleep(1) + + def stop(self): + """ + Stop the GLib event loop + """ + self._stop = True + + + def _new_item_handler(self, interface, protocol, name, stype, domain, flags): + if flags & avahi.LOOKUP_RESULT_LOCAL: + # local service, skip + pass + + self.server.ResolveService( + interface, + protocol, + name, + stype, + domain, + avahi.PROTO_UNSPEC, + dbus.UInt32(0), + reply_handler = self._service_resolved_handler, + error_handler = self._error_handler + ) + return + + + def _remove_item_handler(self, interface, protocol, name, stype, domain, flags): + if self.handlers[ stype ]: + # FIXME: more details needed here + try: + self.handlers[ stype ]( SERVICE_LOST, { 'type' : stype, 'name' : name } ) + except: + pass + + + def _service_resolved_handler( self, *args ): + service = {} + service['type'] = str( args[3] ) + service['name'] = str( args[2] ) + service['address'] = str( args[7] ) + service['hostname'] = str( args[5] ) + service['port'] = int( args[8] ) + + # if the service type has a handler call it + try: + if self.handlers[ args[3] ]: + self.handlers[ args[3] ]( SERVICE_FOUND, service ) + except: + pass + + + def _error_handler( self, *args ): + print('ERROR: %s ' % str( args[0] )) + + +if __name__ == "__main__": + def service_handler( found, service ): + print("---------------------") + print(['Found Service', 'Lost Service'][found-1]) + for key in service.keys(): + print(key+" : "+str( service[key] )) + + browser = Browser( { + '_xbmc-events._udp' : service_handler, + '_xbmc-web._tcp' : service_handler + } ) + browser.run() + diff --git a/tools/Linux/firewalld-services/kodi-eventserver.xml b/tools/Linux/firewalld-services/kodi-eventserver.xml new file mode 100644 index 0000000..68cdb3c --- /dev/null +++ b/tools/Linux/firewalld-services/kodi-eventserver.xml @@ -0,0 +1,6 @@ +<?xml version="1.0" encoding="utf-8"?> +<service> + <short>Kodi EventServer</short> + <description>Kodi is a free cross-platform media-player jukebox and entertainment hub. Enable this option to remotely control Kodi via its EventServer API.</description> + <port protocol="udp" port="9777"/> +</service> diff --git a/tools/Linux/firewalld-services/kodi-http.xml b/tools/Linux/firewalld-services/kodi-http.xml new file mode 100644 index 0000000..863c251 --- /dev/null +++ b/tools/Linux/firewalld-services/kodi-http.xml @@ -0,0 +1,6 @@ +<?xml version="1.0" encoding="utf-8"?> +<service> + <short>Kodi web interface</short> + <description>Kodi is a free cross-platform media-player jukebox and entertainment hub. Enable this option to remotely control Kodi via its web interface.</description> + <port protocol="tcp" port="8080"/> +</service> diff --git a/tools/Linux/firewalld-services/kodi-jsonrpc.xml b/tools/Linux/firewalld-services/kodi-jsonrpc.xml new file mode 100644 index 0000000..08ed2af --- /dev/null +++ b/tools/Linux/firewalld-services/kodi-jsonrpc.xml @@ -0,0 +1,6 @@ +<?xml version="1.0" encoding="utf-8"?> +<service> + <short>Kodi JSON-RPC</short> + <description>Kodi is a free cross-platform media-player jukebox and entertainment hub. Enable this option to remotely control Kodi via its JSON-RPC API.</description> + <port protocol="tcp" port="9090"/> +</service> diff --git a/tools/Linux/kodi-standalone.sh.in b/tools/Linux/kodi-standalone.sh.in new file mode 100644 index 0000000..956e193 --- /dev/null +++ b/tools/Linux/kodi-standalone.sh.in @@ -0,0 +1,54 @@ +#!/bin/sh + +# Copyright (C) 2009-2015 Team XBMC +# http://kodi.tv +# +# 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, 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 XBMC; see the file COPYING. If not, write to +# the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. +# http://www.gnu.org/copyleft/gpl.html + +prefix="@prefix@" +exec_prefix="@exec_prefix@" +bindir="@bindir@" +bin_name=@APP_NAME_LC@ +APP="${bindir}/${bin_name} --standalone $@" + +@XBMC_STANDALONE_SH_PULSE@ + +LOOP=1 +CRASHCOUNT=0 +LASTSUCCESSFULSTART=$(date +%s) + +while [ $LOOP -eq 1 ] +do + $APP + RET=$? + NOW=$(date +%s) + if [ $RET -ge 64 ] && [ $RET -le 66 ] || [ $RET -eq 0 ]; then # clean exit + LOOP=0 + else # crash + DIFF=$((NOW-LASTSUCCESSFULSTART)) + if [ $DIFF -gt 60 ]; then # Not on startup, ignore + LASTSUCESSFULSTART=$NOW + CRASHCOUNT=0 + else # at startup, look sharp + CRASHCOUNT=$((CRASHCOUNT+1)) + if [ $CRASHCOUNT -ge 3 ]; then # Too many, bail out + LOOP=0 + echo "${APP} has exited in an unclean state 3 times in the last ${DIFF} seconds." + echo "Something is probably wrong" + fi + fi + fi +done diff --git a/tools/Linux/kodi-standalone.sh.pulse b/tools/Linux/kodi-standalone.sh.pulse new file mode 100644 index 0000000..e77efe8 --- /dev/null +++ b/tools/Linux/kodi-standalone.sh.pulse @@ -0,0 +1,4 @@ +PULSE_START="$(command -v start-pulseaudio-x11)" +if [ -n "$PULSE_START" ]; then + $PULSE_START +fi diff --git a/tools/Linux/kodi-xsession.desktop.in b/tools/Linux/kodi-xsession.desktop.in new file mode 100644 index 0000000..c9f8c43 --- /dev/null +++ b/tools/Linux/kodi-xsession.desktop.in @@ -0,0 +1,8 @@ +[Desktop Entry] +Name=@APP_NAME@ +Comment=This session will start @APP_NAME@ media center +Exec=@APP_NAME_LC@-standalone +TryExec=@APP_NAME_LC@-standalone +Type=Application +Keywords=audio;video;media;center;tv;movies;series;songs;remote; +Icon=@APP_NAME_LC@ diff --git a/tools/Linux/kodi.desktop.in b/tools/Linux/kodi.desktop.in new file mode 100644 index 0000000..71d3f7d --- /dev/null +++ b/tools/Linux/kodi.desktop.in @@ -0,0 +1,25 @@ +[Desktop Entry] +Version=1.0 +Name=@APP_NAME@ +GenericName=Media Center +GenericName[zh_CN]=媒体中心 +Comment=Manage and view your media +Comment[ru]=Просмотр и управление мультимедиа +Comment[zh_CN]=管理和查看您的媒体 +Exec=@APP_NAME_LC@ +Icon=@APP_NAME_LC@ +Terminal=false +Type=Application +Categories=AudioVideo;Video;Player;TV; + +Actions=Fullscreen;Standalone; + +[Desktop Action Fullscreen] +Name=Open in fullscreen +Name[zh_CN]=全屏打开 +Exec=@APP_NAME_LC@ -fs + +[Desktop Action Standalone] +Name=Open in standalone mode +Name[zh_CN]=在独立模式下打开 +Exec=@APP_NAME_LC@ --standalone diff --git a/tools/Linux/kodi.metainfo.xml.in b/tools/Linux/kodi.metainfo.xml.in new file mode 100644 index 0000000..998c631 --- /dev/null +++ b/tools/Linux/kodi.metainfo.xml.in @@ -0,0 +1,137 @@ +<?xml version="1.0" encoding="UTF-8"?> +<component type="desktop-application"> + <id>@APP_PACKAGE@</id> + <name>@APP_NAME@</name> + <project_license>GPL-2.0-only GPL-2.0-or-later LGPL-2.1-or-later MIT BSD-3-Clause BSD-4-Clause</project_license> + <metadata_license>CC0-1.0</metadata_license> + <developer_name>Team Kodi</developer_name> + <summary>Ultimate entertainment center</summary> + <url type="homepage">https://kodi.tv/</url> + <url type="donation">https://kodi.tv/contribute/donate</url> + <url type="bugtracker">https://github.com/xbmc/xbmc/issues</url> + <url type="faq">https://kodi.wiki/view/FAQs</url> + <url type="help">https://forum.kodi.tv/</url> + <url type="translate">https://kodi.weblate.cloud/</url> + <url type="contribute">https://github.com/xbmc/xbmc/blob/master/docs/CONTRIBUTING.md</url> + <url type="vcs-browser">https://github.com/xbmc/xbmc/</url> + <description> + <p>Kodi allows users to play and view videos, music, podcasts, + and other digital media files from local storage, network storage + and the internet. It's optimized for a 10-foot user interface to be + used with televisions and remote controls.</p> + + <p>Kodi spawned from the love of media. It is an entertainment hub + that brings all your digital media together into a beautiful + and user friendly package. It is 100% free and open source, + very customisable and runs on a wide variety of devices. It is + supported by a dedicated team of volunteers and a huge community.</p> + </description> + <keywords> + <keyword>Kodi</keyword> + <keyword>xbmc</keyword> + <keyword>audio</keyword> + <keyword>video</keyword> + <keyword>media</keyword> + <keyword>media center</keyword> + <keyword>music</keyword> + <keyword>tv</keyword> + <keyword>television</keyword> + <keyword>remote control</keyword> + </keywords> + <launchable type="desktop-id">@APP_NAME_LC@.desktop</launchable> + <screenshots> + <screenshot type="default"> + <image>https://mirrors.kodi.tv/screenshots/kodi-recently-added.jpg</image> + <caption>The homescreen keeps your media organized</caption> + </screenshot> + <screenshot> + <image>https://mirrors.kodi.tv/screenshots/kodi-videolibrary.jpg</image> + <caption>Easily browse your movies and series</caption> + </screenshot> + <screenshot> + <image>https://mirrors.kodi.tv/screenshots/kodi-video-info.jpg</image> + <caption>Get additional infos about your movies or series</caption> + </screenshot> + <screenshot> + <image>https://mirrors.kodi.tv/screenshots/kodi-tvshow.jpg</image> + <caption>Browse TV shows by seasons</caption> + </screenshot> + <screenshot> + <image>https://mirrors.kodi.tv/screenshots/kodi-music-info.jpg</image> + <caption>Use the music library to organize and read about your artists</caption> + </screenshot> + <screenshot> + <image>https://mirrors.kodi.tv/screenshots/kodi-epg.jpg</image> + <caption>Use the EPG to manage your TV stations</caption> + </screenshot> + <screenshot> + <image>https://mirrors.kodi.tv/screenshots/kodi-addons.jpg</image> + <caption>Extend what Kodi can do, just use addons</caption> + </screenshot> + <screenshot> + <image>https://mirrors.kodi.tv/screenshots/kodi-weather.jpg</image> + <caption>Keep the weather in check</caption> + </screenshot> + <screenshot> + <image>https://mirrors.kodi.tv/screenshots/kodi-webinterface.jpg</image> + <caption>The webinterface enables you to manage your Kodi from other devices</caption> + </screenshot> + </screenshots> + <releases> + <release date="2024-02-10" version="20.4-Nexus" type="stable"><url>https://kodi.tv/article/kodi-20-4-nexus-release/</url></release> + <release date="2024-01-09" version="20.3-Nexus" type="stable"><url>https://kodi.tv/article/kodi-20-3-nexus-release/</url></release> + <release date="2023-06-29" version="20.2-Nexus" type="stable"><url>https://kodi.tv/article/kodi-20-2-nexus-release/</url></release> + <release date="2023-03-11" version="20.1-Nexus" type="stable"><url>https://kodi.tv/article/kodi-20-1-nexus-release/</url></release> + <release date="2023-01-15" version="20.0-Nexus" type="stable"><url>https://kodi.tv/article/kodi-20-0-nexus-release/</url></release> + <release date="2022-12-21" version="20.0~rc2-Nexus" type="development"><url>https://kodi.tv/article/kodi-nexus-rc-2/</url></release> + <release date="2022-12-10" version="20.0~rc1-Nexus" type="development"><url>https://kodi.tv/article/kodi-nexus-rc-1/</url></release> + <release date="2022-11-08" version="20.0~b1-Nexus" type="development"><url>https://kodi.tv/article/kodi-nexus-beta-1/</url></release> + <release date="2022-09-08" version="20.0~a3-Nexus" type="development"><url>https://kodi.tv/article/kodi-nexus-alpha-3/</url></release> + <release date="2022-07-09" version="20.0~a2-Nexus" type="development"><url>https://kodi.tv/article/kodi-nexus-alpha-2/</url></release> + <release date="2022-05-16" version="20.0~a1-Nexus" type="development"><url>https://kodi.tv/article/kodi-nexus-alpha-1/</url></release> + <release date="2022-03-03" version="19.4-Matrix"/> + <release date="2021-10-24" version="19.3-Matrix"/> + <release date="2021-10-08" version="19.2-Matrix"/> + <release date="2021-05-09" version="19.1-Matrix"/> + <release date="2021-02-19" version="19.0-Matrix"/> + <release date="2020-10-24" version="18.9-Leia"/> + <release date="2020-07-28" version="18.8-Leia"/> + <release date="2020-05-21" version="18.7-Leia"/> + <release date="2020-02-29" version="18.6-Leia"/> + <release date="2019-11-18" version="18.5-Leia"/> + <release date="2019-08-31" version="18.4-Leia"/> + <release date="2019-06-27" version="18.3-Leia"/> + <release date="2019-04-22" version="18.2-Leia"/> + <release date="2019-02-17" version="18.1-Leia"/> + </releases> + <content_rating type="oars-1.0"> + <content_attribute id="violence-cartoon">none</content_attribute> + <content_attribute id="violence-fantasy">none</content_attribute> + <content_attribute id="violence-realistic">none</content_attribute> + <content_attribute id="violence-bloodshed">none</content_attribute> + <content_attribute id="violence-sexual">none</content_attribute> + <content_attribute id="drugs-alcohol">none</content_attribute> + <content_attribute id="drugs-narcotics">none</content_attribute> + <content_attribute id="drugs-tobacco">none</content_attribute> + <content_attribute id="sex-nudity">none</content_attribute> + <content_attribute id="sex-themes">none</content_attribute> + <content_attribute id="language-profanity">none</content_attribute> + <content_attribute id="language-humor">none</content_attribute> + <content_attribute id="language-discrimination">none</content_attribute> + <content_attribute id="social-chat">none</content_attribute> + <content_attribute id="social-info">none</content_attribute> + <content_attribute id="social-audio">none</content_attribute> + <content_attribute id="social-location">none</content_attribute> + <content_attribute id="social-contacts">none</content_attribute> + <content_attribute id="money-purchasing">none</content_attribute> + <content_attribute id="money-gambling">none</content_attribute> + </content_rating> + <recommends> + <control>keyboard</control> + <control>pointing</control> + <control>touch</control> + <control>tv-remote</control> + <control>gamepad</control> + <control>tablet</control> + </recommends> +</component> diff --git a/tools/Linux/kodi.sh.in b/tools/Linux/kodi.sh.in new file mode 100644 index 0000000..11cace2 --- /dev/null +++ b/tools/Linux/kodi.sh.in @@ -0,0 +1,192 @@ +#!/bin/sh + +# Copyright (C) 2008-2017 Team XBMC +# http://kodi.tv +# +# 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, 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 XBMC; see the file COPYING. If not, write to +# the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. +# http://www.gnu.org/copyleft/gpl.html + +APP=@APP_NAME@ +bin_name=@APP_NAME_LC@ +SAVED_ARGS="$@" +prefix="@prefix@" +exec_prefix="@exec_prefix@" +datarootdir="@datarootdir@" +LIBDIR="@libdir@" +APP_BINARY=$LIBDIR/${bin_name}/@APP_BINARY@ +CRASHLOG_DIR=${CRASHLOG_DIR:-$HOME} +KODI_DATA=${KODI_DATA:-"${HOME}/.${bin_name}"} # mapped to special://home/ + +# Workaround for high CPU load with nvidia GFX +export __GL_YIELD=USLEEP + +# Fix wasting RAM due to fragmentation +export MALLOC_MMAP_THRESHOLD_=131072 + +# Check for some options used by this script +while [ "$#" -gt "0" ] +do + case "$1" in + --setlibdir) + LIBDIR="$2" + shift; shift + ;; + *) + shift + ;; + esac +done + +KODI_BINARY=${APP_BINARY} + +if [ ! -x ${KODI_BINARY} ]; then + echo "Error: ${KODI_BINARY} not found" + exit 2 +fi + +APPORT_CORE="/var/crash/$(echo -n ${KODI_BINARY}|tr / _).$(id -u).crash" + +command_exists() +{ + command -pv $1 >/dev/null 2>&1 +} + +single_stacktrace() +{ + # core filename is either "core.$PID" or "core" + find "$1" -maxdepth $2 -name 'core*' | while read core; do + LC_ALL=C gdb --core="$core" --batch 2> /dev/null | grep -q "^Core was generated by \`${KODI_BINARY}" || continue + echo "=====> Core file: "$core" ($(stat -c%y "$core"))" >> $FILE + echo " =========================================" >> $FILE + gdb "${KODI_BINARY}" --core="$core" --batch -ex "thread apply all bt" 2> /dev/null >> $FILE + rm -f "$core" + done +} + +print_crash_report() +{ + FILE="$CRASHLOG_DIR/${bin_name}_crashlog-`date +%Y%m%d_%H%M%S`.log" + echo "############## $APP CRASH LOG ###############" >> $FILE + echo >> $FILE + echo "################ SYSTEM INFO ################" >> $FILE + printf " Date: " >> $FILE + date >> $FILE + echo " $APP Options: $*" >> $FILE + printf " Arch: " >> $FILE + uname -m >> $FILE + printf " Kernel: " >> $FILE + uname -rvs >> $FILE + printf " Release: " >> $FILE + if [ -f /etc/os-release ]; then + . /etc/os-release + echo $NAME $VERSION >> $FILE + elif command_exists lsb_release; then + echo >> $FILE + lsb_release -a 2> /dev/null | sed -e 's/^/ /' >> $FILE + else + echo "lsb_release not available" >> $FILE + fi + echo "############## END SYSTEM INFO ##############" >> $FILE + echo >> $FILE + echo "############### STACK TRACE #################" >> $FILE + if command_exists gdb; then + if command_exists systemd-coredumpctl; then + systemd-coredumpctl dump -o core $(basename ${KODI_BINARY}) > /dev/null 2>&1 + elif command_exists coredumpctl; then + coredumpctl dump -o core $(basename ${KODI_BINARY}) > /dev/null 2>&1 + elif command_exists apport-unpack && test -f "${APPORT_CORE}"; then + TMP_DIR="$(mktemp -d -p ${HOME})" + if [ -d "${TMP_DIR}" ]; then + rm -f "${HOME}/core" + apport-unpack "${APPORT_CORE}" "${TMP_DIR}" + mv "${TMP_DIR}/CoreDump" "${HOME}/core" + rm -rf "${TMP_DIR}" + fi + fi + single_stacktrace "$PWD" 1 + # Find in plugins directories + if [ $KODI_HOME ]; then + BASEDIR=$KODI_HOME + else + BASEDIR="$LIBDIR/${bin_name}/" + fi + single_stacktrace "$BASEDIR" 5 + # find in userdata dir + single_stacktrace "$HOME" 5 + # try /proc/sys/kernel/core_pattern + # Check if it does not contain a pipe to a program (see man 5 core) + if [ "$(cat /proc/sys/kernel/core_pattern | cut -c 1)" != "|" ]; then + [ -d "$(dirname $(cat /proc/sys/kernel/core_pattern))" ] && single_stacktrace "$(dirname $(cat /proc/sys/kernel/core_pattern))" 1 + fi + else + echo "gdb not installed, can't get stack trace." >> $FILE + fi + echo "############# END STACK TRACE ###############" >> $FILE + echo >> $FILE + echo "################# LOG FILE ##################" >> $FILE + echo >> $FILE + if [ -f $KODI_TEMP/@APP_NAME_LC@.log ] + then + cat $KODI_TEMP/@APP_NAME_LC@.log >> $FILE + echo >> $FILE + elif [ -f $KODI_DATA/temp/@APP_NAME_LC@.log ] + then + cat $KODI_DATA/temp/@APP_NAME_LC@.log >> $FILE + echo >> $FILE + else + echo "Logfile not found in the usual place." >> $FILE + echo "Please attach it separately." >> $FILE + echo "Use pastebin.com or similar for forums or IRC." >> $FILE + fi + echo >> $FILE + echo "############### END LOG FILE ################" >> $FILE + echo >> $FILE + echo "############ END $APP CRASH LOG #############" >> $FILE + echo "Crash report available at $FILE" +} + +propagate_sigterm() { + kill -TERM "$CHILD" 2>/dev/null +} + +trap propagate_sigterm TERM + +if command_exists gdb; then + # Output warning in case ulimit is unsupported by shell + eval ulimit -c unlimited + if [ ! $? = "0" ]; then + echo "${bin_name}: ulimit is unsupported by this shell" 1>&2 + fi +fi + +LOOP=1 +while [ $(( $LOOP )) = "1" ] +do + [ -f "${APPORT_CORE}" ] && rm -f "${APPORT_CORE}" + LOOP=0 + ${KODI_BINARY} $SAVED_ARGS & + CHILD=$! + wait "${CHILD}" + RET=$? + if [ $RET -eq 65 ] + then # User requested to restart app + LOOP=1 + elif [ $RET -ge 131 ] && [ $RET -le 136 ] || [ $RET -eq 139 ] + then # Crashed with core dump + print_crash_report + fi +done + +exit $RET diff --git a/tools/Linux/packaging/README.debian b/tools/Linux/packaging/README.debian new file mode 100644 index 0000000..5e217d3 --- /dev/null +++ b/tools/Linux/packaging/README.debian @@ -0,0 +1,31 @@ +--- How to build a Kodi Debian package --- + +There are two available build methods: +1.) debuild / debhelper + Requirements: debhelper, devscripts, all Kodi build deps + sudo apt-get install debhelper devscripts + sudo apt-get build-dep kodi (if you have one of our repos/ppas added, else read docs/README.Linux.md or docs/README.Ubuntu.md) + + Result: Debian package for your host distribution and architecture only + Recommended for local installs + + Example Usage: ./mk-debian-package.sh + +2.) pdebuild / pbuilder + Requirements: pbuilder, devscripts, proper pbuilder environment + For a comprehensive example how to setup pbuilder read: + https://wiki.ubuntu.com/PbuilderHowto + + Result: Debian package for arbitrary Debian based distributions and architectures. + Recommended for hosting your own apt repository or (clean room) compile testing for various distributions + + Example Usage: + RELEASEV=16 \ + DISTS=-"unstable" \ + ARCHS="i386 amd64" \ + BUILDER="pdebuild" \ + PDEBUILD_OPTS="--debbuildopts \"-j4\"" \ + PBUILDER_BASE="/home/$USER/xbmc-packaging/pbuilder" \ + DPUT_TARGET="local" \ + ./mk-debian-package.sh + diff --git a/tools/Linux/packaging/media/icon128x128.png b/tools/Linux/packaging/media/icon128x128.png Binary files differnew file mode 100644 index 0000000..8a25c4a --- /dev/null +++ b/tools/Linux/packaging/media/icon128x128.png diff --git a/tools/Linux/packaging/media/icon16x16.png b/tools/Linux/packaging/media/icon16x16.png Binary files differnew file mode 100644 index 0000000..9b27352 --- /dev/null +++ b/tools/Linux/packaging/media/icon16x16.png diff --git a/tools/Linux/packaging/media/icon22x22.png b/tools/Linux/packaging/media/icon22x22.png Binary files differnew file mode 100644 index 0000000..21f76e5 --- /dev/null +++ b/tools/Linux/packaging/media/icon22x22.png diff --git a/tools/Linux/packaging/media/icon24x24.png b/tools/Linux/packaging/media/icon24x24.png Binary files differnew file mode 100644 index 0000000..dad983b --- /dev/null +++ b/tools/Linux/packaging/media/icon24x24.png diff --git a/tools/Linux/packaging/media/icon256x256.png b/tools/Linux/packaging/media/icon256x256.png Binary files differnew file mode 100644 index 0000000..cc2ee49 --- /dev/null +++ b/tools/Linux/packaging/media/icon256x256.png diff --git a/tools/Linux/packaging/media/icon32x32.png b/tools/Linux/packaging/media/icon32x32.png Binary files differnew file mode 100644 index 0000000..c0a0534 --- /dev/null +++ b/tools/Linux/packaging/media/icon32x32.png diff --git a/tools/Linux/packaging/media/icon48x48.png b/tools/Linux/packaging/media/icon48x48.png Binary files differnew file mode 100644 index 0000000..898c023 --- /dev/null +++ b/tools/Linux/packaging/media/icon48x48.png diff --git a/tools/Linux/packaging/media/icon64x64.png b/tools/Linux/packaging/media/icon64x64.png Binary files differnew file mode 100644 index 0000000..700144b --- /dev/null +++ b/tools/Linux/packaging/media/icon64x64.png diff --git a/tools/Linux/packaging/mk-debian-package.sh b/tools/Linux/packaging/mk-debian-package.sh new file mode 100755 index 0000000..ad81be0 --- /dev/null +++ b/tools/Linux/packaging/mk-debian-package.sh @@ -0,0 +1,187 @@ +#!/bin/bash +# +# Copyright (C) 2013 Team XBMC +# http://kodi.tv +# +# 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, 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 XBMC; see the file COPYING. If not, see +# <http://www.gnu.org/licenses/>. +# + + +RELEASEV=${RELEASEV:-"auto"} +VERSION_PREFIX=${VERSION_PREFIX:-""} +TAG=${TAG} +TAGREV=${TAGREV:-""} +REPO_DIR=${WORKSPACE:-$(cd "$(dirname $0)/../../../" ; pwd)} +[[ $(which lsb_release) ]] && DISTS=${DISTS:-$(lsb_release -cs)} || DISTS=${DISTS:-"stable"} +ARCHS=${ARCHS:-$(dpkg --print-architecture)} +BUILDER=${BUILDER:-"debuild"} +DEBUILD_OPTS=${DEBUILD_OPTS:-""} +PDEBUILD_OPTS=${PDEBUILD_OPTS:-""} +PBUILDER_BASE=${PBUILDER_BASE:-"/var/cache/pbuilder"} +DPUT_TARGET=${DPUT_TARGET:-"local"} +DEBIAN=${DEBIAN:-"https://github.com/xbmc/xbmc-packaging/archive/master.tar.gz"} +BUILD_DATE=$(date '+%Y%m%d.%H%M') + +function usage { + echo "$0: This script builds a Kodi debian package from a git repository." + echo "The build is controlled by ENV variables, which can be overridden as appropriate:" + echo "BUILDER is either debuild(default) or pdebuild(needs a proper pbuilder setup)" + checkEnv +} + +function checkEnv { + echo "#------ build environment ------#" + echo "REPO_DIR: $REPO_DIR" + getVersion + echo "RELEASEV: $RELEASEV" + echo "REVISION: $TAGREV" + [[ -n $TAG ]] && echo "TAG: $TAG" + echo "DISTS: $DISTS" + echo "ARCHS: $ARCHS" + echo "DEBIAN: $DEBIAN" + echo "BUILDER: $BUILDER" + echo "CONFIGURATION: $Configuration" + + if ! [[ $(which $BUILDER) ]] + then + echo "Error: can't find ${BUILDER}, consider using full path to [debuild|pdebuild]" + exit 1 + fi + + if [[ "$BUILDER" =~ "pdebuild" ]] + then + if ! [[ -d $PBUILDER_BASE ]] ; then echo "Error: $PBUILDER_BASE does not exist"; exit 1; fi + echo "PBUILDER_BASE: $PBUILDER_BASE" + echo "PDEBUILD_OPTS: $PDEBUILD_OPTS" + else + echo "DEBUILD_OPTS: $DEBUILD_OPTS" + fi + + echo "#-------------------------------#" +} + +function getVersion { + getGitRev + if [[ $RELEASEV == "auto" ]] + then + local MAJORVER=$(grep VERSION_MAJOR $REPO_DIR/version.txt | awk '{ print $2 }') + local MINORVER=$(grep VERSION_MINOR $REPO_DIR/version.txt | awk '{ print $2 }') + RELEASEV=${MAJORVER}.${MINORVER} + else + PACKAGEVERSION="${RELEASEV}~git${BUILD_DATE}-${TAG}" + fi + + if [[ -n ${VERSION_PREFIX} ]] + then + PACKAGEVERSION="${VERSION_PREFIX}:${RELEASEV}~git${BUILD_DATE}-${TAG}" + else + PACKAGEVERSION="${RELEASEV}~git${BUILD_DATE}-${TAG}" + fi +} + +function getGitRev { + cd $REPO_DIR || exit 1 + REV=$(git log -1 --pretty=format:"%h") + [[ -z $TAG ]] && TAG=$REV + [[ -z $TAGREV ]] && TAGREV=0 +} + +function archiveRepo { + cd $REPO_DIR || exit 1 + git clean -xfd + echo $REV > VERSION + tools/depends/target/ffmpeg/autobuild.sh -d + DEST="kodi-${RELEASEV}~git${BUILD_DATE}-${TAG}" + [[ -d debian ]] && rm -rf debian + cd .. + tar -czf ${DEST}.tar.gz --exclude .git $(basename $REPO_DIR) + ln -s ${DEST}.tar.gz ${DEST/-/_}.orig.tar.gz + echo "Output Archive: ${DEST}.tar.gz" + + cd $REPO_DIR || exit 1 + getDebian +} + +function getDebian { + if [[ -d $DEBIAN ]] + then + cp -r $DEBIAN . + else + mkdir tmp && cd tmp + curl -L -s $DEBIAN -o debian.tar.gz + tar xzf debian.tar.gz + cd xbmc-packaging-* + for FILE in *.unified; do mv $FILE debian/${FILE%.unified}; done + mv debian $REPO_DIR + cd $REPO_DIR ; rm -rf tmp + fi +} + +function buildDebianPackages { + archiveRepo + cd $REPO_DIR || exit 1 + sed -e "s/#PACKAGEVERSION#/${PACKAGEVERSION}/g" -e "s/#TAGREV#/${TAGREV}/g" debian/changelog.in > debian/changelog.tmp + [ "$Configuration" == "Debug" ] && sed -i "s/XBMC_RELEASE = yes/XBMC_RELEASE = no/" debian/rules + + for dist in $DISTS + do + sed "s/#DIST#/${dist}/g" debian/changelog.tmp > debian/changelog + for arch in $ARCHS + do + cd $REPO_DIR + echo "building: DIST=$dist ARCH=$arch" + if [[ "$BUILDER" =~ "pdebuild" ]] + then + DIST=$dist ARCH=$arch $BUILDER $PDEBUILD_OPTS + [ $? -eq 0 ] && uploadPkg || exit 1 + else + $BUILDER $DEBUILD_OPTS + echo "output directory: $REPO_DIR/.." + fi + done + done +} + +function uploadPkg { + PKG="${PBUILDER_BASE}/${dist}-${arch}/result/${DEST/-/_}-${TAGREV}_${arch}.changes" + echo "signing package" + debsign $PKG + echo "uploading $PKG to $DPUT_TARGET" + dput $DPUT_TARGET $PKG + UPLOAD_DONE=$? +} + +function cleanup { + if [[ $UPLOAD_DONE -eq 0 ]] && [[ "$BUILDER" =~ "pdebuild" ]] + then + cd $REPO_DIR/.. || exit 1 + rm ${DEST}* + rm ${DEST/-/_}* + fi +} + +### +# main +### +if [[ $1 = "-h" ]] || [[ $1 = "--help" ]] +then + usage + exit +fi + +checkEnv +buildDebianPackages +cleanup + diff --git a/tools/Linux/packaging/package-kodi-launchpad.sh b/tools/Linux/packaging/package-kodi-launchpad.sh new file mode 100755 index 0000000..d6e7c51 --- /dev/null +++ b/tools/Linux/packaging/package-kodi-launchpad.sh @@ -0,0 +1,81 @@ +#!/bin/bash + +releaseversion=${VERSION:-"AUTO"} +epoch=${EPOCH:-"2"} +gitrev=${GITREV:-"$(git log -1 --pretty=format:"%h")"} +tag=${TAG:-${gitrev}} +tagrev=${tagrev:-"0"} +dists=${DISTS:-"hirsute groovy focal bionic"} +gpgkey=${GPG_KEY:-"jenkins (jenkins build bot) <jenkins@kodi.tv>"} +ppa=${PPA:-"nightly"} +debianrepo="${DEBIAN:-"https://github.com/xbmc/xbmc-packaging"}" + +if [ "$releaseversion" = "AUTO" ]; then + majorversion="$(awk '/VERSION_MAJOR/ {print $2}' version.txt)" + minorversion="$(awk '/VERSION_MINOR/ {print $2}' version.txt)" + releaseversion="${majorversion}.${minorversion}" +fi + +version="${releaseversion}+git$(date '+%Y%m%d.%H%M')-${tag}" +debversion="${epoch}:${version}" +origtarball="kodi_${version}.orig.tar.gz" + +declare -A PPAS=( + ["nightly"]='ppa:team-xbmc/xbmc-nightly' + ["unstable"]='ppa:team-xbmc/unstable' + ["stable"]='ppa:team-xbmc/ppa' + ["wsnipex-nightly"]='ppa:wsnipex/kodi-git' + ["wsnipex-stable"]='ppa:wsnipex/kodi-stable' +) + +# clean up before creating the source tarball +git clean -xfd + +# set build info +date '+%Y%m%d' > BUILDDATE +echo $gitrev > VERSION + +# download packaging files +wget -O - ${debianrepo}/archive/master.tar.gz | tar xzv --strip-components=1 --exclude=".git*" -f - +[ -d debian ] || { echo "ERROR: directory debian does not exist"; exit 3; } + +# add tarballs for internal ffmpeg, libdvd +tools/depends/target/ffmpeg/autobuild.sh -d || { echo "Error downloading ffmpeg"; exit 2; } +make -C tools/depends/target/libdvdnav download || { echo "Error downloading libdvdnav"; exit 2; } +make -C tools/depends/target/libdvdread download || { echo "Error downloading libdvdread"; exit 2; } +make -C tools/depends/target/libdvdcss download || { echo "Error downloading libdvdcss"; exit 2; } +make -C tools/depends/target/dav1d download || { echo "Error downloading dav1d"; exit 2; } + +# create orig tarball if needed +if grep -q quilt debian/source/format; then + echo "origtarball: ${origtarball}" + git archive -o ../${origtarball} ${gitrev} +fi + + +# build source packages +for dist in ${dists//,/ }; do + echo "### Building for ${dist} ###" + sed \ + -e "s/#PACKAGEVERSION#/${debversion}/" \ + -e "s/#TAGREV#/${tagrev}/" \ + -e "s/#DIST#/${dist}/g" \ + debian/changelog.in > debian/changelog + + echo "Changelog:" + cat debian/changelog + echo + + debuild -d -S -k"${gpgkey}" + echo "### DONE ###" +done + +# upload to PPA +echo "### Uploading to PPA ${PPAS[${ppa}]} ###" +dput ${PPAS[${ppa}]} ../kodi_${version}*.changes +if [ $? -eq 0 ]; then + echo "### Successfully pushed ${version} to launchpad ###" +else + echo "### ERROR could not upload package ###" +fi + diff --git a/tools/buildsteps/README b/tools/buildsteps/README new file mode 100644 index 0000000..048ff84 --- /dev/null +++ b/tools/buildsteps/README @@ -0,0 +1,15 @@ +This folder holds all the platform dependent build scripts which are called from the jenkins buildserver. + +The following ENV variables are available on all scripts: + +$WORKSPACE - the folder where jenkins checked out the source - XBMC_HOME so to say +$Configuration - its either Debug, Release or Default and should be taken into account if possible (Defaults select platform default from <platformdir>/startbuild) +$SDK_VERSION - the requested SDK_VERSION to be used for building. If "Default" is passed it uses the platform default from <platformdir>/startbuild +$BUILDTHREADS - number of threads which can be used when building (e.x. use it for make -j$BUILDTHREADS) +$XBMC_DEPENDS_ROOT - root for installing the xbmc build depends and toolchain helpers. If "Default" is passed it uses the platform default from <platformdir>/startbuild + +Additional ENV variables might be specified by the buildnodes. For android buildslaves these are: + +TOOLCHAIN - the used toolchain dir +NDK_PATH - the path to the android native ndk +SDK_PATH - the path to the android sdk diff --git a/tools/buildsteps/android-arm64-v8a/configure-depends b/tools/buildsteps/android-arm64-v8a/configure-depends new file mode 100644 index 0000000..cec12b7 --- /dev/null +++ b/tools/buildsteps/android-arm64-v8a/configure-depends @@ -0,0 +1,18 @@ +WORKSPACE=${WORKSPACE:-$( cd $(dirname $0)/../../.. ; pwd -P )} +XBMC_PLATFORM_DIR=android +. $WORKSPACE/tools/buildsteps/defaultenv + +#the following path must exist on the slave and use the defined scheme here! +NDK_PATH=$ANDROID_DEV_ROOT/android-ndk-r$NDK_VERSION + +if [ "$(pathChanged $WORKSPACE/tools/depends)" == "1" ] +then + cd $WORKSPACE/tools/depends;./configure \ + --with-tarballs=$TARBALLS \ + --host=aarch64-linux-android \ + --with-sdk-path=$SDK_PATH \ + --with-ndk-path=$NDK_PATH \ + $(if [ "$NDK_API" != "Default" ]; then echo --with-ndk-api=$NDK_API;fi) \ + --prefix=$XBMC_DEPENDS_ROOT \ + $DEBUG_SWITCH +fi diff --git a/tools/buildsteps/android-arm64-v8a/configure-xbmc b/tools/buildsteps/android-arm64-v8a/configure-xbmc new file mode 100644 index 0000000..81c0d3c --- /dev/null +++ b/tools/buildsteps/android-arm64-v8a/configure-xbmc @@ -0,0 +1,5 @@ +WORKSPACE=${WORKSPACE:-$( cd $(dirname $0)/../../.. ; pwd -P )} +XBMC_PLATFORM_DIR=android +. $WORKSPACE/tools/buildsteps/defaultenv + +make -C $WORKSPACE/tools/depends/target/cmakebuildsys diff --git a/tools/buildsteps/android-arm64-v8a/make-binary-addons b/tools/buildsteps/android-arm64-v8a/make-binary-addons new file mode 100644 index 0000000..3bb9e74 --- /dev/null +++ b/tools/buildsteps/android-arm64-v8a/make-binary-addons @@ -0,0 +1,29 @@ +WORKSPACE=${WORKSPACE:-$( cd $(dirname $0)/../../.. ; pwd -P )} +XBMC_PLATFORM_DIR=android +. $WORKSPACE/tools/buildsteps/defaultenv + +. $WORKSPACE/tools/buildsteps/$XBMC_PLATFORM_DIR/make-native-depends + +#clear the build failed file +rm -f $WORKSPACE/cmake/$FAILED_BUILD_FILENAME + +ALL_BINARY_ADDONS_BUILT="1" +#only build binary addons when requested by env/jenkins +if [ "$BUILD_BINARY_ADDONS" == "true" ] +then + for addon in $BINARY_ADDONS + do + echo "building $addon" + git clean -xffd $WORKSPACE/$BINARY_ADDONS_ROOT/$addon + + cd $WORKSPACE/$BINARY_ADDONS_ROOT/$addon;make -j $BUILDTHREADS V=99 VERBOSE=1 || ALL_BINARY_ADDONS_BUILT="0" + done +fi + +if [ "$ALL_BINARY_ADDONS_BUILT" == "1" ] +then + tagSuccessFulBuild $WORKSPACE/cmake +else + #mark the build failure in the filesystem but leave jenkins running + tagFailedBuild $WORKSPACE/cmake +fi diff --git a/tools/buildsteps/android-arm64-v8a/make-depends b/tools/buildsteps/android-arm64-v8a/make-depends new file mode 100644 index 0000000..c5869b2 --- /dev/null +++ b/tools/buildsteps/android-arm64-v8a/make-depends @@ -0,0 +1,9 @@ +WORKSPACE=${WORKSPACE:-$( cd $(dirname $0)/../../.. ; pwd -P )} +XBMC_PLATFORM_DIR=android +. $WORKSPACE/tools/buildsteps/defaultenv + +if [ "$(pathChanged $WORKSPACE/tools/depends)" == "1" ] +then + cd $WORKSPACE/tools/depends;make -j $BUILDTHREADS && tagSuccessFulBuild $WORKSPACE/tools/depends +fi + diff --git a/tools/buildsteps/android-arm64-v8a/make-native-depends b/tools/buildsteps/android-arm64-v8a/make-native-depends new file mode 100644 index 0000000..c327180 --- /dev/null +++ b/tools/buildsteps/android-arm64-v8a/make-native-depends @@ -0,0 +1,9 @@ +WORKSPACE=${WORKSPACE:-$( cd $(dirname $0)/../../.. ; pwd -P )} +XBMC_PLATFORM_DIR=android +. $WORKSPACE/tools/buildsteps/defaultenv + +if [ "$(pathChanged $WORKSPACE/tools/depends)" == "1" ] && [ "$BINARY_ADDONS_CLEAN_NATIVETOOLS" != "0" ] +then + git clean -xffd $WORKSPACE/tools/depends/native + cd $WORKSPACE/tools/depends/native;make -j $BUILDTHREADS && tagSuccessFulBuild $WORKSPACE/tools/depends +fi diff --git a/tools/buildsteps/android-arm64-v8a/make-xbmc b/tools/buildsteps/android-arm64-v8a/make-xbmc new file mode 100644 index 0000000..11d8d70 --- /dev/null +++ b/tools/buildsteps/android-arm64-v8a/make-xbmc @@ -0,0 +1,5 @@ +WORKSPACE=${WORKSPACE:-$( cd $(dirname $0)/../../.. ; pwd -P )} +XBMC_PLATFORM_DIR=android +. $WORKSPACE/tools/buildsteps/defaultenv + +cd $WORKSPACE/build;make -j$BUILDTHREADS || make diff --git a/tools/buildsteps/android-arm64-v8a/package b/tools/buildsteps/android-arm64-v8a/package new file mode 100644 index 0000000..d1ddf48 --- /dev/null +++ b/tools/buildsteps/android-arm64-v8a/package @@ -0,0 +1,14 @@ +WORKSPACE=${WORKSPACE:-$( cd $(dirname $0)/../../.. ; pwd -P )} +XBMC_PLATFORM_DIR=android +. $WORKSPACE/tools/buildsteps/defaultenv + +TARGET=apk + +cd $WORKSPACE/build;make -j$BUILDTHREADS $TARGET + +cd $WORKSPACE + +#rename for upload +#e.x. xbmc-20130314-8c2fb31-Frodo-arm64-v8a.apk +UPLOAD_FILENAME="kodi-$(getBuildRevDateStr)-arm64-v8a" +mv kodiapp-arm64-v8a-*.apk $UPLOAD_FILENAME.apk diff --git a/tools/buildsteps/android-arm64-v8a/prepare-depends b/tools/buildsteps/android-arm64-v8a/prepare-depends new file mode 100644 index 0000000..b4d02b7 --- /dev/null +++ b/tools/buildsteps/android-arm64-v8a/prepare-depends @@ -0,0 +1,15 @@ +WORKSPACE=${WORKSPACE:-$( cd $(dirname $0)/../../.. ; pwd -P )} +XBMC_PLATFORM_DIR=android +. $WORKSPACE/tools/buildsteps/defaultenv + +#clean without depends for skipping depends build if possible +#also skip binary addons (pvr, audioencoder) as long as they are deployed in tree +cd $WORKSPACE;git clean -xfd -e "cmake/.last_success_revision" -e "tools/depends" ${DEPLOYED_BINARY_ADDONS} + +# if depends path has changed - cleanout everything and do a full rebuild +if [ "$(pathChanged $WORKSPACE/tools/depends)" == "1" ] +then + #clean up the rest too + cd $WORKSPACE;git clean -xffd + cd $WORKSPACE/tools/depends/;./bootstrap +fi diff --git a/tools/buildsteps/android-arm64-v8a/prepare-xbmc b/tools/buildsteps/android-arm64-v8a/prepare-xbmc new file mode 100644 index 0000000..29e374b --- /dev/null +++ b/tools/buildsteps/android-arm64-v8a/prepare-xbmc @@ -0,0 +1,9 @@ +WORKSPACE=${WORKSPACE:-$( cd $(dirname $0)/../../.. ; pwd -P )} +XBMC_PLATFORM_DIR=android +. $WORKSPACE/tools/buildsteps/defaultenv + +#build binary addons before building xbmc... +#make sure that binary_addons don't clean the native tools +#here +BINARY_ADDONS_CLEAN_NATIVETOOLS="0" +. $WORKSPACE/tools/buildsteps/$XBMC_PLATFORM_DIR/make-binary-addons diff --git a/tools/buildsteps/android-x86_64/configure-depends b/tools/buildsteps/android-x86_64/configure-depends new file mode 100644 index 0000000..c27d6d8 --- /dev/null +++ b/tools/buildsteps/android-x86_64/configure-depends @@ -0,0 +1,17 @@ +WORKSPACE=${WORKSPACE:-$( cd $(dirname $0)/../../.. ; pwd -P )} +XBMC_PLATFORM_DIR=android +. $WORKSPACE/tools/buildsteps/defaultenv + +#the following path must exist on the slave and use the defined scheme here! +NDK_PATH=$ANDROID_DEV_ROOT/android-ndk-r$NDK_VERSION + +if [ "$(pathChanged $WORKSPACE/tools/depends)" == "1" ] +then + cd $WORKSPACE/tools/depends;./configure \ + --with-tarballs=$TARBALLS \ + --host=x86_64-linux-android \ + --with-sdk-path=$SDK_PATH \ + --with-ndk-path=$NDK_PATH \ + $(if [ "$NDK_API" != "Default" ]; then echo --with-ndk-api=$NDK_API;fi) \ + --prefix=$XBMC_DEPENDS_ROOT $DEBUG_SWITCH +fi diff --git a/tools/buildsteps/android-x86_64/configure-xbmc b/tools/buildsteps/android-x86_64/configure-xbmc new file mode 100644 index 0000000..81c0d3c --- /dev/null +++ b/tools/buildsteps/android-x86_64/configure-xbmc @@ -0,0 +1,5 @@ +WORKSPACE=${WORKSPACE:-$( cd $(dirname $0)/../../.. ; pwd -P )} +XBMC_PLATFORM_DIR=android +. $WORKSPACE/tools/buildsteps/defaultenv + +make -C $WORKSPACE/tools/depends/target/cmakebuildsys diff --git a/tools/buildsteps/android-x86_64/make-binary-addons b/tools/buildsteps/android-x86_64/make-binary-addons new file mode 100644 index 0000000..3bb9e74 --- /dev/null +++ b/tools/buildsteps/android-x86_64/make-binary-addons @@ -0,0 +1,29 @@ +WORKSPACE=${WORKSPACE:-$( cd $(dirname $0)/../../.. ; pwd -P )} +XBMC_PLATFORM_DIR=android +. $WORKSPACE/tools/buildsteps/defaultenv + +. $WORKSPACE/tools/buildsteps/$XBMC_PLATFORM_DIR/make-native-depends + +#clear the build failed file +rm -f $WORKSPACE/cmake/$FAILED_BUILD_FILENAME + +ALL_BINARY_ADDONS_BUILT="1" +#only build binary addons when requested by env/jenkins +if [ "$BUILD_BINARY_ADDONS" == "true" ] +then + for addon in $BINARY_ADDONS + do + echo "building $addon" + git clean -xffd $WORKSPACE/$BINARY_ADDONS_ROOT/$addon + + cd $WORKSPACE/$BINARY_ADDONS_ROOT/$addon;make -j $BUILDTHREADS V=99 VERBOSE=1 || ALL_BINARY_ADDONS_BUILT="0" + done +fi + +if [ "$ALL_BINARY_ADDONS_BUILT" == "1" ] +then + tagSuccessFulBuild $WORKSPACE/cmake +else + #mark the build failure in the filesystem but leave jenkins running + tagFailedBuild $WORKSPACE/cmake +fi diff --git a/tools/buildsteps/android-x86_64/make-depends b/tools/buildsteps/android-x86_64/make-depends new file mode 100644 index 0000000..c5869b2 --- /dev/null +++ b/tools/buildsteps/android-x86_64/make-depends @@ -0,0 +1,9 @@ +WORKSPACE=${WORKSPACE:-$( cd $(dirname $0)/../../.. ; pwd -P )} +XBMC_PLATFORM_DIR=android +. $WORKSPACE/tools/buildsteps/defaultenv + +if [ "$(pathChanged $WORKSPACE/tools/depends)" == "1" ] +then + cd $WORKSPACE/tools/depends;make -j $BUILDTHREADS && tagSuccessFulBuild $WORKSPACE/tools/depends +fi + diff --git a/tools/buildsteps/android-x86_64/make-native-depends b/tools/buildsteps/android-x86_64/make-native-depends new file mode 100644 index 0000000..c327180 --- /dev/null +++ b/tools/buildsteps/android-x86_64/make-native-depends @@ -0,0 +1,9 @@ +WORKSPACE=${WORKSPACE:-$( cd $(dirname $0)/../../.. ; pwd -P )} +XBMC_PLATFORM_DIR=android +. $WORKSPACE/tools/buildsteps/defaultenv + +if [ "$(pathChanged $WORKSPACE/tools/depends)" == "1" ] && [ "$BINARY_ADDONS_CLEAN_NATIVETOOLS" != "0" ] +then + git clean -xffd $WORKSPACE/tools/depends/native + cd $WORKSPACE/tools/depends/native;make -j $BUILDTHREADS && tagSuccessFulBuild $WORKSPACE/tools/depends +fi diff --git a/tools/buildsteps/android-x86_64/make-xbmc b/tools/buildsteps/android-x86_64/make-xbmc new file mode 100644 index 0000000..11d8d70 --- /dev/null +++ b/tools/buildsteps/android-x86_64/make-xbmc @@ -0,0 +1,5 @@ +WORKSPACE=${WORKSPACE:-$( cd $(dirname $0)/../../.. ; pwd -P )} +XBMC_PLATFORM_DIR=android +. $WORKSPACE/tools/buildsteps/defaultenv + +cd $WORKSPACE/build;make -j$BUILDTHREADS || make diff --git a/tools/buildsteps/android-x86_64/package b/tools/buildsteps/android-x86_64/package new file mode 100644 index 0000000..b477126 --- /dev/null +++ b/tools/buildsteps/android-x86_64/package @@ -0,0 +1,14 @@ +WORKSPACE=${WORKSPACE:-$( cd $(dirname $0)/../../.. ; pwd -P )} +XBMC_PLATFORM_DIR=android +. $WORKSPACE/tools/buildsteps/defaultenv + +TARGET=apk + +cd $WORKSPACE/build;make -j$BUILDTHREADS $TARGET + +cd $WORKSPACE + +#rename for upload +#e.x. xbmc-20130314-8c2fb31-Frodo-x86_64.apk +UPLOAD_FILENAME="kodi-$(getBuildRevDateStr)-x86_64" +mv kodiapp-x86_64-*.apk $UPLOAD_FILENAME.apk diff --git a/tools/buildsteps/android-x86_64/prepare-depends b/tools/buildsteps/android-x86_64/prepare-depends new file mode 100644 index 0000000..b4d02b7 --- /dev/null +++ b/tools/buildsteps/android-x86_64/prepare-depends @@ -0,0 +1,15 @@ +WORKSPACE=${WORKSPACE:-$( cd $(dirname $0)/../../.. ; pwd -P )} +XBMC_PLATFORM_DIR=android +. $WORKSPACE/tools/buildsteps/defaultenv + +#clean without depends for skipping depends build if possible +#also skip binary addons (pvr, audioencoder) as long as they are deployed in tree +cd $WORKSPACE;git clean -xfd -e "cmake/.last_success_revision" -e "tools/depends" ${DEPLOYED_BINARY_ADDONS} + +# if depends path has changed - cleanout everything and do a full rebuild +if [ "$(pathChanged $WORKSPACE/tools/depends)" == "1" ] +then + #clean up the rest too + cd $WORKSPACE;git clean -xffd + cd $WORKSPACE/tools/depends/;./bootstrap +fi diff --git a/tools/buildsteps/android-x86_64/prepare-xbmc b/tools/buildsteps/android-x86_64/prepare-xbmc new file mode 100644 index 0000000..29e374b --- /dev/null +++ b/tools/buildsteps/android-x86_64/prepare-xbmc @@ -0,0 +1,9 @@ +WORKSPACE=${WORKSPACE:-$( cd $(dirname $0)/../../.. ; pwd -P )} +XBMC_PLATFORM_DIR=android +. $WORKSPACE/tools/buildsteps/defaultenv + +#build binary addons before building xbmc... +#make sure that binary_addons don't clean the native tools +#here +BINARY_ADDONS_CLEAN_NATIVETOOLS="0" +. $WORKSPACE/tools/buildsteps/$XBMC_PLATFORM_DIR/make-binary-addons diff --git a/tools/buildsteps/android/configure-depends b/tools/buildsteps/android/configure-depends new file mode 100644 index 0000000..649ff6d --- /dev/null +++ b/tools/buildsteps/android/configure-depends @@ -0,0 +1,18 @@ +WORKSPACE=${WORKSPACE:-$( cd $(dirname $0)/../../.. ; pwd -P )} +XBMC_PLATFORM_DIR=android +. $WORKSPACE/tools/buildsteps/defaultenv + +#the following path must exist on the slave and use the defined scheme here! +NDK_PATH=$ANDROID_DEV_ROOT/android-ndk-r$NDK_VERSION + +if [ "$(pathChanged $WORKSPACE/tools/depends)" == "1" ] +then + cd $WORKSPACE/tools/depends;./configure \ + --with-tarballs=$TARBALLS \ + --host=arm-linux-androideabi \ + --with-sdk-path=$SDK_PATH \ + --with-ndk-path=$NDK_PATH \ + $(if [ "$NDK_API" != "Default" ]; then echo --with-ndk-api=$NDK_API;fi) \ + --prefix=$XBMC_DEPENDS_ROOT \ + $DEBUG_SWITCH +fi diff --git a/tools/buildsteps/android/configure-xbmc b/tools/buildsteps/android/configure-xbmc new file mode 100644 index 0000000..81c0d3c --- /dev/null +++ b/tools/buildsteps/android/configure-xbmc @@ -0,0 +1,5 @@ +WORKSPACE=${WORKSPACE:-$( cd $(dirname $0)/../../.. ; pwd -P )} +XBMC_PLATFORM_DIR=android +. $WORKSPACE/tools/buildsteps/defaultenv + +make -C $WORKSPACE/tools/depends/target/cmakebuildsys diff --git a/tools/buildsteps/android/make-binary-addons b/tools/buildsteps/android/make-binary-addons new file mode 100644 index 0000000..3bb9e74 --- /dev/null +++ b/tools/buildsteps/android/make-binary-addons @@ -0,0 +1,29 @@ +WORKSPACE=${WORKSPACE:-$( cd $(dirname $0)/../../.. ; pwd -P )} +XBMC_PLATFORM_DIR=android +. $WORKSPACE/tools/buildsteps/defaultenv + +. $WORKSPACE/tools/buildsteps/$XBMC_PLATFORM_DIR/make-native-depends + +#clear the build failed file +rm -f $WORKSPACE/cmake/$FAILED_BUILD_FILENAME + +ALL_BINARY_ADDONS_BUILT="1" +#only build binary addons when requested by env/jenkins +if [ "$BUILD_BINARY_ADDONS" == "true" ] +then + for addon in $BINARY_ADDONS + do + echo "building $addon" + git clean -xffd $WORKSPACE/$BINARY_ADDONS_ROOT/$addon + + cd $WORKSPACE/$BINARY_ADDONS_ROOT/$addon;make -j $BUILDTHREADS V=99 VERBOSE=1 || ALL_BINARY_ADDONS_BUILT="0" + done +fi + +if [ "$ALL_BINARY_ADDONS_BUILT" == "1" ] +then + tagSuccessFulBuild $WORKSPACE/cmake +else + #mark the build failure in the filesystem but leave jenkins running + tagFailedBuild $WORKSPACE/cmake +fi diff --git a/tools/buildsteps/android/make-depends b/tools/buildsteps/android/make-depends new file mode 100644 index 0000000..c5869b2 --- /dev/null +++ b/tools/buildsteps/android/make-depends @@ -0,0 +1,9 @@ +WORKSPACE=${WORKSPACE:-$( cd $(dirname $0)/../../.. ; pwd -P )} +XBMC_PLATFORM_DIR=android +. $WORKSPACE/tools/buildsteps/defaultenv + +if [ "$(pathChanged $WORKSPACE/tools/depends)" == "1" ] +then + cd $WORKSPACE/tools/depends;make -j $BUILDTHREADS && tagSuccessFulBuild $WORKSPACE/tools/depends +fi + diff --git a/tools/buildsteps/android/make-native-depends b/tools/buildsteps/android/make-native-depends new file mode 100644 index 0000000..c327180 --- /dev/null +++ b/tools/buildsteps/android/make-native-depends @@ -0,0 +1,9 @@ +WORKSPACE=${WORKSPACE:-$( cd $(dirname $0)/../../.. ; pwd -P )} +XBMC_PLATFORM_DIR=android +. $WORKSPACE/tools/buildsteps/defaultenv + +if [ "$(pathChanged $WORKSPACE/tools/depends)" == "1" ] && [ "$BINARY_ADDONS_CLEAN_NATIVETOOLS" != "0" ] +then + git clean -xffd $WORKSPACE/tools/depends/native + cd $WORKSPACE/tools/depends/native;make -j $BUILDTHREADS && tagSuccessFulBuild $WORKSPACE/tools/depends +fi diff --git a/tools/buildsteps/android/make-xbmc b/tools/buildsteps/android/make-xbmc new file mode 100644 index 0000000..11d8d70 --- /dev/null +++ b/tools/buildsteps/android/make-xbmc @@ -0,0 +1,5 @@ +WORKSPACE=${WORKSPACE:-$( cd $(dirname $0)/../../.. ; pwd -P )} +XBMC_PLATFORM_DIR=android +. $WORKSPACE/tools/buildsteps/defaultenv + +cd $WORKSPACE/build;make -j$BUILDTHREADS || make diff --git a/tools/buildsteps/android/package b/tools/buildsteps/android/package new file mode 100644 index 0000000..cbe3607 --- /dev/null +++ b/tools/buildsteps/android/package @@ -0,0 +1,14 @@ +WORKSPACE=${WORKSPACE:-$( cd $(dirname $0)/../../.. ; pwd -P )} +XBMC_PLATFORM_DIR=android +. $WORKSPACE/tools/buildsteps/defaultenv + +TARGET=apk + +cd $WORKSPACE/build;make -j$BUILDTHREADS $TARGET + +cd $WORKSPACE + +#rename for upload +#e.x. xbmc-20130314-8c2fb31-Frodo-armeabi-v7a.apk +UPLOAD_FILENAME="kodi-$(getBuildRevDateStr)-armeabi-v7a" +mv kodiapp-armeabi-*.apk $UPLOAD_FILENAME.apk diff --git a/tools/buildsteps/android/prepare-depends b/tools/buildsteps/android/prepare-depends new file mode 100644 index 0000000..b4d02b7 --- /dev/null +++ b/tools/buildsteps/android/prepare-depends @@ -0,0 +1,15 @@ +WORKSPACE=${WORKSPACE:-$( cd $(dirname $0)/../../.. ; pwd -P )} +XBMC_PLATFORM_DIR=android +. $WORKSPACE/tools/buildsteps/defaultenv + +#clean without depends for skipping depends build if possible +#also skip binary addons (pvr, audioencoder) as long as they are deployed in tree +cd $WORKSPACE;git clean -xfd -e "cmake/.last_success_revision" -e "tools/depends" ${DEPLOYED_BINARY_ADDONS} + +# if depends path has changed - cleanout everything and do a full rebuild +if [ "$(pathChanged $WORKSPACE/tools/depends)" == "1" ] +then + #clean up the rest too + cd $WORKSPACE;git clean -xffd + cd $WORKSPACE/tools/depends/;./bootstrap +fi diff --git a/tools/buildsteps/android/prepare-xbmc b/tools/buildsteps/android/prepare-xbmc new file mode 100644 index 0000000..29e374b --- /dev/null +++ b/tools/buildsteps/android/prepare-xbmc @@ -0,0 +1,9 @@ +WORKSPACE=${WORKSPACE:-$( cd $(dirname $0)/../../.. ; pwd -P )} +XBMC_PLATFORM_DIR=android +. $WORKSPACE/tools/buildsteps/defaultenv + +#build binary addons before building xbmc... +#make sure that binary_addons don't clean the native tools +#here +BINARY_ADDONS_CLEAN_NATIVETOOLS="0" +. $WORKSPACE/tools/buildsteps/$XBMC_PLATFORM_DIR/make-binary-addons diff --git a/tools/buildsteps/androidx86/configure-depends b/tools/buildsteps/androidx86/configure-depends new file mode 100644 index 0000000..9fb0e20 --- /dev/null +++ b/tools/buildsteps/androidx86/configure-depends @@ -0,0 +1,17 @@ +WORKSPACE=${WORKSPACE:-$( cd $(dirname $0)/../../.. ; pwd -P )} +XBMC_PLATFORM_DIR=android +. $WORKSPACE/tools/buildsteps/defaultenv + +#the following path must exist on the slave and use the defined scheme here! +NDK_PATH=$ANDROID_DEV_ROOT/android-ndk-r$NDK_VERSION + +if [ "$(pathChanged $WORKSPACE/tools/depends)" == "1" ] +then + cd $WORKSPACE/tools/depends;./configure \ + --with-tarballs=$TARBALLS \ + --host=i686-linux-android \ + --with-sdk-path=$SDK_PATH \ + --with-ndk-path=$NDK_PATH \ + $(if [ "$NDK_API" != "Default" ]; then echo --with-ndk-api=$NDK_API;fi) \ + --prefix=$XBMC_DEPENDS_ROOT $DEBUG_SWITCH +fi diff --git a/tools/buildsteps/androidx86/configure-xbmc b/tools/buildsteps/androidx86/configure-xbmc new file mode 100644 index 0000000..81c0d3c --- /dev/null +++ b/tools/buildsteps/androidx86/configure-xbmc @@ -0,0 +1,5 @@ +WORKSPACE=${WORKSPACE:-$( cd $(dirname $0)/../../.. ; pwd -P )} +XBMC_PLATFORM_DIR=android +. $WORKSPACE/tools/buildsteps/defaultenv + +make -C $WORKSPACE/tools/depends/target/cmakebuildsys diff --git a/tools/buildsteps/androidx86/make-binary-addons b/tools/buildsteps/androidx86/make-binary-addons new file mode 100644 index 0000000..3bb9e74 --- /dev/null +++ b/tools/buildsteps/androidx86/make-binary-addons @@ -0,0 +1,29 @@ +WORKSPACE=${WORKSPACE:-$( cd $(dirname $0)/../../.. ; pwd -P )} +XBMC_PLATFORM_DIR=android +. $WORKSPACE/tools/buildsteps/defaultenv + +. $WORKSPACE/tools/buildsteps/$XBMC_PLATFORM_DIR/make-native-depends + +#clear the build failed file +rm -f $WORKSPACE/cmake/$FAILED_BUILD_FILENAME + +ALL_BINARY_ADDONS_BUILT="1" +#only build binary addons when requested by env/jenkins +if [ "$BUILD_BINARY_ADDONS" == "true" ] +then + for addon in $BINARY_ADDONS + do + echo "building $addon" + git clean -xffd $WORKSPACE/$BINARY_ADDONS_ROOT/$addon + + cd $WORKSPACE/$BINARY_ADDONS_ROOT/$addon;make -j $BUILDTHREADS V=99 VERBOSE=1 || ALL_BINARY_ADDONS_BUILT="0" + done +fi + +if [ "$ALL_BINARY_ADDONS_BUILT" == "1" ] +then + tagSuccessFulBuild $WORKSPACE/cmake +else + #mark the build failure in the filesystem but leave jenkins running + tagFailedBuild $WORKSPACE/cmake +fi diff --git a/tools/buildsteps/androidx86/make-depends b/tools/buildsteps/androidx86/make-depends new file mode 100644 index 0000000..c5869b2 --- /dev/null +++ b/tools/buildsteps/androidx86/make-depends @@ -0,0 +1,9 @@ +WORKSPACE=${WORKSPACE:-$( cd $(dirname $0)/../../.. ; pwd -P )} +XBMC_PLATFORM_DIR=android +. $WORKSPACE/tools/buildsteps/defaultenv + +if [ "$(pathChanged $WORKSPACE/tools/depends)" == "1" ] +then + cd $WORKSPACE/tools/depends;make -j $BUILDTHREADS && tagSuccessFulBuild $WORKSPACE/tools/depends +fi + diff --git a/tools/buildsteps/androidx86/make-native-depends b/tools/buildsteps/androidx86/make-native-depends new file mode 100644 index 0000000..33cc579 --- /dev/null +++ b/tools/buildsteps/androidx86/make-native-depends @@ -0,0 +1,9 @@ +WORKSPACE=${WORKSPACE:-$( cd $(dirname $0)/../../.. ; pwd -P )} +XBMC_PLATFORM_DIR=android +. $WORKSPACE/tools/buildsteps/defaultenv + +if [ "$(pathChanged $WORKSPACE/tools/depends)" == "1" ] && [ "$BINARY_ADDONS_CLEAN_NATIVETOOLS" != "0" ] +then + git clean -xffd $WORKSPACE/tools/depends/native + cd $WORKSPACE/tools/depends/native;make -j $BUILDTHREADS && tagSuccessFulBuild $WORKSPACE/tools/depends +fi
\ No newline at end of file diff --git a/tools/buildsteps/androidx86/make-xbmc b/tools/buildsteps/androidx86/make-xbmc new file mode 100644 index 0000000..11d8d70 --- /dev/null +++ b/tools/buildsteps/androidx86/make-xbmc @@ -0,0 +1,5 @@ +WORKSPACE=${WORKSPACE:-$( cd $(dirname $0)/../../.. ; pwd -P )} +XBMC_PLATFORM_DIR=android +. $WORKSPACE/tools/buildsteps/defaultenv + +cd $WORKSPACE/build;make -j$BUILDTHREADS || make diff --git a/tools/buildsteps/androidx86/package b/tools/buildsteps/androidx86/package new file mode 100644 index 0000000..4e8ca13 --- /dev/null +++ b/tools/buildsteps/androidx86/package @@ -0,0 +1,14 @@ +WORKSPACE=${WORKSPACE:-$( cd $(dirname $0)/../../.. ; pwd -P )} +XBMC_PLATFORM_DIR=android +. $WORKSPACE/tools/buildsteps/defaultenv + +TARGET=apk + +cd $WORKSPACE/build;make -j$BUILDTHREADS $TARGET + +cd $WORKSPACE + +#rename for upload +#e.x. xbmc-20130314-8c2fb31-Frodo-x86.apk +UPLOAD_FILENAME="kodi-$(getBuildRevDateStr)-x86" +mv kodiapp-x86-*.apk $UPLOAD_FILENAME.apk diff --git a/tools/buildsteps/androidx86/prepare-depends b/tools/buildsteps/androidx86/prepare-depends new file mode 100644 index 0000000..b4d02b7 --- /dev/null +++ b/tools/buildsteps/androidx86/prepare-depends @@ -0,0 +1,15 @@ +WORKSPACE=${WORKSPACE:-$( cd $(dirname $0)/../../.. ; pwd -P )} +XBMC_PLATFORM_DIR=android +. $WORKSPACE/tools/buildsteps/defaultenv + +#clean without depends for skipping depends build if possible +#also skip binary addons (pvr, audioencoder) as long as they are deployed in tree +cd $WORKSPACE;git clean -xfd -e "cmake/.last_success_revision" -e "tools/depends" ${DEPLOYED_BINARY_ADDONS} + +# if depends path has changed - cleanout everything and do a full rebuild +if [ "$(pathChanged $WORKSPACE/tools/depends)" == "1" ] +then + #clean up the rest too + cd $WORKSPACE;git clean -xffd + cd $WORKSPACE/tools/depends/;./bootstrap +fi diff --git a/tools/buildsteps/androidx86/prepare-xbmc b/tools/buildsteps/androidx86/prepare-xbmc new file mode 100644 index 0000000..29e374b --- /dev/null +++ b/tools/buildsteps/androidx86/prepare-xbmc @@ -0,0 +1,9 @@ +WORKSPACE=${WORKSPACE:-$( cd $(dirname $0)/../../.. ; pwd -P )} +XBMC_PLATFORM_DIR=android +. $WORKSPACE/tools/buildsteps/defaultenv + +#build binary addons before building xbmc... +#make sure that binary_addons don't clean the native tools +#here +BINARY_ADDONS_CLEAN_NATIVETOOLS="0" +. $WORKSPACE/tools/buildsteps/$XBMC_PLATFORM_DIR/make-binary-addons diff --git a/tools/buildsteps/defaultenv b/tools/buildsteps/defaultenv new file mode 100644 index 0000000..e571e83 --- /dev/null +++ b/tools/buildsteps/defaultenv @@ -0,0 +1,183 @@ +BUILDTHREADS=${BUILDTHREADS:-1} +SDK_VERSION=${SDK_VERSION:-"Default"} +NDK_VERSION=${NDK_VERSION:-"Default"} +NDK_API=${NDK_API:-"Default"} +Configuration=${Configuration:-"Default"} +XBMC_DEPENDS_ROOT=${XBMC_DEPENDS_ROOT:-"Default"} +XCODE_APP=${XCODE_APP:-"Default"} +PATH_CHANGE_REV_FILENAME=".last_success_revision" +FAILED_BUILD_FILENAME=".last_failed_revision" +#TARBALLS ENV-VAR is only used by android scripts atm +TARBALLS=${TARBALLS:-"/opt/xbmc-tarballs"} +RENDER_SYSTEM=${RENDER_SYSTEM:-"Default"} +BUILD_HOST=${BUILD_HOST:-"Default"} + +BINARY_ADDONS_ROOT=tools/depends/target +BINARY_ADDONS="binary-addons" +DEPLOYED_BINARY_ADDONS="-e /addons" + +# Jenkins env variables +JENKINS_BUILD_TIMESTAMP=${BUILD_TIMESTAMP:-"unknown"} +JENKINS_BUILD_COMMIT=$(echo ${GIT_COMMIT:-"unknown"} | cut -c1-8) +JENKINS_BUILD_REVISION=${Revision:-"unknown"} +JENKINS_BUILD_ID=${BUILD_ID:-"unknown"} + +JENKINS_BUILD_STRING="${JENKINS_BUILD_TIMESTAMP}-${JENKINS_BUILD_COMMIT}-${JENKINS_BUILD_REVISION}-${JENKINS_BUILD_ID}" + +#set platform defaults +#$XBMC_PLATFORM_DIR matches the platform subdirs! +case $XBMC_PLATFORM_DIR in + ios) + DEFAULT_SDK_VERSION=14.4 + DEFAULT_XBMC_DEPENDS_ROOT=$WORKSPACE/tools/depends/xbmc-depends + DEFAULT_CONFIGURATION="Debug" + DEFAULT_XCODE_APP="Xcode12.4.app" + ;; + + tvos) + DEFAULT_SDK_VERSION=14.3 + DEFAULT_XBMC_DEPENDS_ROOT=$WORKSPACE/tools/depends/xbmc-depends + DEFAULT_CONFIGURATION="Debug" + DEFAULT_XCODE_APP="Xcode12.4.app" + ;; + + osx64) + DEFAULT_SDK_VERSION=11.1 + DEFAULT_XBMC_DEPENDS_ROOT=$WORKSPACE/tools/depends/xbmc-depends + DEFAULT_CONFIGURATION="Debug" + DEFAULT_XCODE_APP="Xcode12.4.app" + ;; + + osx-arm64) + DEFAULT_SDK_VERSION=11.1 + DEFAULT_XBMC_DEPENDS_ROOT=$WORKSPACE/tools/depends/xbmc-depends + DEFAULT_CONFIGURATION="Debug" + DEFAULT_XCODE_APP="Xcode12.4.app" + ;; + + android) + DEFAULT_NDK_VERSION="21e" # NDK package version (newer API can be inside) + DEFAULT_NDK_API="21" # Lollipop API level (21) defined in package ./sysroot/usr/include/android/api-level.h + DEFAULT_XBMC_DEPENDS_ROOT=$WORKSPACE/tools/depends/xbmc-depends + DEFAULT_CONFIGURATION="RelWithDebInfo" + ;; + + linux) + DEFAULT_XBMC_DEPENDS_ROOT=$WORKSPACE/tools/depends/xbmc-depends + DEFAULT_CONFIGURATION="Debug" + DEFAULT_RENDER_SYSTEM="gl" + DEFAULT_BUILD_HOST="x86_64-linux-gnu" + ;; + + freebsd) + DEFAULT_CONFIGURATION="Debug" + ;; +esac + +if [ "$SDK_VERSION" == "Default" ] +then + SDK_VERSION=$DEFAULT_SDK_VERSION +fi + +if [ "$NDK_VERSION" == "Default" ] +then + NDK_VERSION=$DEFAULT_NDK_VERSION +fi + +if [ "$NDK_API" == "Default" ] +then + NDK_API=$DEFAULT_NDK_API +fi + +if [ "$XBMC_DEPENDS_ROOT" == "Default" ] +then + XBMC_DEPENDS_ROOT=$DEFAULT_XBMC_DEPENDS_ROOT +fi + +if [ "$XCODE_APP" == "Default" ] +then + XCODE_APP=$DEFAULT_XCODE_APP +fi + +# make osx environment aware of the selected xcode app +export DEVELOPER_DIR=/Applications/$XCODE_APP/Contents/Developer + +if [ "$Configuration" == "Default" ] +then + Configuration=$DEFAULT_CONFIGURATION +fi + +if [ "$Configuration" == "Release" ] +then + DEBUG_SWITCH='--disable-debug' +fi + +if [ "$RENDER_SYSTEM" == "Default" ] +then + RENDER_SYSTEM=$DEFAULT_RENDER_SYSTEM +fi + +if [ "$BUILD_HOST" == "Default" ] +then + BUILD_HOST=$DEFAULT_BUILD_HOST +fi + +#helper functions + +#hash a dir based on the git revision, Configuration, SDK_PATH, NDK_PATH, NDK_VERSION, SDK_VERSION, TOOLCHAIN and XBMC_DEPENDS_ROOT +#param1 path to be hashed +function getBuildHash () +{ + local checkPath + checkPath="$1" + local hashStr + hashStr="$(git rev-list HEAD --max-count=1 -- $checkPath)" + hashStr="$hashStr $Configuration $SDK_PATH $NDK_PATH $NDK_VERSION $SDK_VERSION $TOOLCHAIN $XBMC_DEPENDS_ROOT $XCODE_APP" + echo $hashStr +} + +#param1 path to be checked for changes +function pathChanged () +{ + local ret + local checkPath + ret="0" + + checkPath="$1" + if [ -e $checkPath/$PATH_CHANGE_REV_FILENAME ] + then + if [ "$(cat $checkPath/$PATH_CHANGE_REV_FILENAME)" != "$(getBuildHash $checkPath)" ] + then + ret="1" + fi + else + ret="1" + fi + + echo $ret +} + +#param1 path to be tagged with hash +function tagSuccessFulBuild () +{ + local pathToTag + pathToTag="$1" + # tag last successful build with revisions of the given dir + # needs to match the checks in function getBuildHash + echo "$(getBuildHash $pathToTag)" > $pathToTag/$PATH_CHANGE_REV_FILENAME +} + +#param1 path to be tagged with hash +function tagFailedBuild () +{ + local pathToTag + pathToTag="$1" + # tag last failed build with revisions of the given dir + # needs to match the checks in function getBuildHash + echo "$(getBuildHash $pathToTag)" > $pathToTag/$FAILED_BUILD_FILENAME +} + +function getBuildRevDateStr () +{ + echo "${JENKINS_BUILD_STRING}" +} diff --git a/tools/buildsteps/freebsd/configure-depends b/tools/buildsteps/freebsd/configure-depends new file mode 100644 index 0000000..d152e7c --- /dev/null +++ b/tools/buildsteps/freebsd/configure-depends @@ -0,0 +1,5 @@ +WORKSPACE=${WORKSPACE:-$( cd $(dirname $0)/../../.. ; pwd -P )} +XBMC_PLATFORM_DIR=freebsd +. $WORKSPACE/tools/buildsteps/defaultenv + +#nothing for freebsd atm diff --git a/tools/buildsteps/freebsd/configure-xbmc b/tools/buildsteps/freebsd/configure-xbmc new file mode 100644 index 0000000..b6c2260 --- /dev/null +++ b/tools/buildsteps/freebsd/configure-xbmc @@ -0,0 +1,7 @@ +WORKSPACE=${WORKSPACE:-$( cd $(dirname $0)/../../.. ; pwd -P )} +XBMC_PLATFORM_DIR=freebsd +. $WORKSPACE/tools/buildsteps/defaultenv + +mkdir -p $WORKSPACE/build +cd $WORKSPACE/build +cmake -DCMAKE_BUILD_TYPE=$Configuration -DAPP_RENDER_SYSTEM=gl .. diff --git a/tools/buildsteps/freebsd/make-binary-addons b/tools/buildsteps/freebsd/make-binary-addons new file mode 100644 index 0000000..0647693 --- /dev/null +++ b/tools/buildsteps/freebsd/make-binary-addons @@ -0,0 +1,28 @@ +WORKSPACE=${WORKSPACE:-$( cd $(dirname $0)/../../.. ; pwd -P )} +XBMC_PLATFORM_DIR=freebsd +. $WORKSPACE/tools/buildsteps/defaultenv + +. $WORKSPACE/tools/buildsteps/$XBMC_PLATFORM_DIR/make-native-depends + +#clear the build failed file +rm -f $WORKSPACE/cmake/$FAILED_BUILD_FILENAME + +ALL_BINARY_ADDONS_BUILT="1" +#only build binary addons when requested by env/jenkins +if [ "$BUILD_BINARY_ADDONS" == "true" ] +then + for addon in $BINARY_ADDONS + do + echo "building $addon" + git clean -xffd $WORKSPACE/$BINARY_ADDONS_ROOT/$addon + cd $WORKSPACE/$BINARY_ADDONS_ROOT/$addon;gmake -j $BUILDTHREADS V=99 VERBOSE=1 || ALL_BINARY_ADDONS_BUILT="0" + done +fi + +if [ "$ALL_BINARY_ADDONS_BUILT" == "1" ] +then + tagSuccessFulBuild $WORKSPACE/cmake +else + #mark the build failure in the filesystem but leave jenkins running + tagFailedBuild $WORKSPACE/cmake +fi diff --git a/tools/buildsteps/freebsd/make-depends b/tools/buildsteps/freebsd/make-depends new file mode 100644 index 0000000..d152e7c --- /dev/null +++ b/tools/buildsteps/freebsd/make-depends @@ -0,0 +1,5 @@ +WORKSPACE=${WORKSPACE:-$( cd $(dirname $0)/../../.. ; pwd -P )} +XBMC_PLATFORM_DIR=freebsd +. $WORKSPACE/tools/buildsteps/defaultenv + +#nothing for freebsd atm diff --git a/tools/buildsteps/freebsd/make-native-depends b/tools/buildsteps/freebsd/make-native-depends new file mode 100644 index 0000000..d152e7c --- /dev/null +++ b/tools/buildsteps/freebsd/make-native-depends @@ -0,0 +1,5 @@ +WORKSPACE=${WORKSPACE:-$( cd $(dirname $0)/../../.. ; pwd -P )} +XBMC_PLATFORM_DIR=freebsd +. $WORKSPACE/tools/buildsteps/defaultenv + +#nothing for freebsd atm diff --git a/tools/buildsteps/freebsd/make-xbmc b/tools/buildsteps/freebsd/make-xbmc new file mode 100644 index 0000000..70faded --- /dev/null +++ b/tools/buildsteps/freebsd/make-xbmc @@ -0,0 +1,5 @@ +WORKSPACE=${WORKSPACE:-$( cd $(dirname $0)/../../.. ; pwd -P )} +XBMC_PLATFORM_DIR=freebsd +. $WORKSPACE/tools/buildsteps/defaultenv + +cd $WORKSPACE/build;gmake -j$BUILDTHREADS || gmake diff --git a/tools/buildsteps/freebsd/package b/tools/buildsteps/freebsd/package new file mode 100644 index 0000000..d152e7c --- /dev/null +++ b/tools/buildsteps/freebsd/package @@ -0,0 +1,5 @@ +WORKSPACE=${WORKSPACE:-$( cd $(dirname $0)/../../.. ; pwd -P )} +XBMC_PLATFORM_DIR=freebsd +. $WORKSPACE/tools/buildsteps/defaultenv + +#nothing for freebsd atm diff --git a/tools/buildsteps/freebsd/prepare-depends b/tools/buildsteps/freebsd/prepare-depends new file mode 100644 index 0000000..7aae09b --- /dev/null +++ b/tools/buildsteps/freebsd/prepare-depends @@ -0,0 +1,8 @@ +WORKSPACE=${WORKSPACE:-$( cd $(dirname $0)/../../.. ; pwd -P )} +XBMC_PLATFORM_DIR=freebsd +. $WORKSPACE/tools/buildsteps/defaultenv + +#clean without depends for skipping depends build if possible +#also skip binary addons (pvr, audioencoder) as long as they are deployed in tree +#freebsd doesn't use depends atm +cd $WORKSPACE;git clean -xfd -e "cmake/.last_success_revision" -e "tools/depends" ${DEPLOYED_BINARY_ADDONS} diff --git a/tools/buildsteps/freebsd/prepare-xbmc b/tools/buildsteps/freebsd/prepare-xbmc new file mode 100644 index 0000000..18f2cf8 --- /dev/null +++ b/tools/buildsteps/freebsd/prepare-xbmc @@ -0,0 +1,9 @@ +WORKSPACE=${WORKSPACE:-$( cd $(dirname $0)/../../.. ; pwd -P )} +XBMC_PLATFORM_DIR=freebsd +. $WORKSPACE/tools/buildsteps/defaultenv + +#build binary addons before building xbmc... +#make sure that binary_addons don't clean the native tools +#here +BINARY_ADDONS_CLEAN_NATIVETOOLS="0" +. $WORKSPACE/tools/buildsteps/$XBMC_PLATFORM_DIR/make-binary-addons diff --git a/tools/buildsteps/freebsd/run-tests b/tools/buildsteps/freebsd/run-tests new file mode 100644 index 0000000..9ee91ce --- /dev/null +++ b/tools/buildsteps/freebsd/run-tests @@ -0,0 +1,14 @@ +WORKSPACE=${WORKSPACE:-$( cd $(dirname $0)/../../.. ; pwd -P )} +XBMC_PLATFORM_DIR=freebsd +. $WORKSPACE/tools/buildsteps/defaultenv + +cd $WORKSPACE/build;gmake -j$BUILDTHREADS kodi-test +if [ "$Configuration" != "Coverage" ]; then + cd $WORKSPACE;build/kodi-test --gtest_output=xml:gtestresults.xml +else + cd $WORKSPACE/build;GTEST_OUTPUT="xml:$WORKSPACE/gtestresults.xml" gmake coverage +fi + +awk '{ if ($1 == "<testcase" && match($0, "notrun")) print substr($0,0,length($0)-2) "><skipped/></testcase>"; else print $0;}' gtestresults.xml > gtestresults-skipped.xml +rm gtestresults.xml +mv gtestresults-skipped.xml gtestresults.xml diff --git a/tools/buildsteps/ios/configure-depends b/tools/buildsteps/ios/configure-depends new file mode 100755 index 0000000..37e1f77 --- /dev/null +++ b/tools/buildsteps/ios/configure-depends @@ -0,0 +1,13 @@ +WORKSPACE=${WORKSPACE:-$( cd $(dirname $0)/../../.. ; pwd -P )} +XBMC_PLATFORM_DIR=ios +. $WORKSPACE/tools/buildsteps/defaultenv + +if [ "$(pathChanged $WORKSPACE/tools/depends)" == "1" ] +then + cd $WORKSPACE/tools/depends;./configure \ + --with-tarballs=/Users/Shared/xbmc-depends/tarballs \ + --host=aarch64-apple-darwin \ + --with-platform=ios \ + --with-sdk=$SDK_VERSION \ + --prefix=$XBMC_DEPENDS_ROOT $DEBUG_SWITCH +fi diff --git a/tools/buildsteps/ios/configure-xbmc b/tools/buildsteps/ios/configure-xbmc new file mode 100755 index 0000000..dbe8a74 --- /dev/null +++ b/tools/buildsteps/ios/configure-xbmc @@ -0,0 +1,5 @@ +WORKSPACE=${WORKSPACE:-$( cd $(dirname $0)/../../.. ; pwd -P )} +XBMC_PLATFORM_DIR=ios +. $WORKSPACE/tools/buildsteps/defaultenv + +make -C $WORKSPACE/tools/depends/target/cmakebuildsys diff --git a/tools/buildsteps/ios/make-binary-addons b/tools/buildsteps/ios/make-binary-addons new file mode 100755 index 0000000..3f5bd02 --- /dev/null +++ b/tools/buildsteps/ios/make-binary-addons @@ -0,0 +1,30 @@ +WORKSPACE=${WORKSPACE:-$( cd $(dirname $0)/../../.. ; pwd -P )} +XBMC_PLATFORM_DIR=ios +. $WORKSPACE/tools/buildsteps/defaultenv + +. $WORKSPACE/tools/buildsteps/$XBMC_PLATFORM_DIR/make-native-depends + +#clear the build failed file +rm -f $WORKSPACE/cmake/$FAILED_BUILD_FILENAME + +ALL_BINARY_ADDONS_BUILT="1" +#only build binary addons when requested by env/jenkins +if [ "$BUILD_BINARY_ADDONS" == "true" ] +then + for addon in $BINARY_ADDONS + do + echo "building $addon" + git clean -xffd $WORKSPACE/$BINARY_ADDONS_ROOT/$addon + + INSTALL_PREFIX="../../../../../build/addons/" + cd $WORKSPACE/$BINARY_ADDONS_ROOT/$addon;make -j $BUILDTHREADS V=99 VERBOSE=1 INSTALL_PREFIX="$INSTALL_PREFIX" || ALL_BINARY_ADDONS_BUILT="0" + done +fi + +if [ "$ALL_BINARY_ADDONS_BUILT" == "1" ] +then + tagSuccessFulBuild $WORKSPACE/cmake +else + #mark the build failure in the filesystem but leave jenkins running + tagFailedBuild $WORKSPACE/cmake +fi diff --git a/tools/buildsteps/ios/make-depends b/tools/buildsteps/ios/make-depends new file mode 100755 index 0000000..eb36ee2 --- /dev/null +++ b/tools/buildsteps/ios/make-depends @@ -0,0 +1,9 @@ +WORKSPACE=${WORKSPACE:-$( cd $(dirname $0)/../../.. ; pwd -P )} +XBMC_PLATFORM_DIR=ios +. $WORKSPACE/tools/buildsteps/defaultenv + +if [ "$(pathChanged $WORKSPACE/tools/depends)" == "1" ] +then + cd $WORKSPACE/tools/depends;make -j $BUILDTHREADS && tagSuccessFulBuild $WORKSPACE/tools/depends +fi + diff --git a/tools/buildsteps/ios/make-native-depends b/tools/buildsteps/ios/make-native-depends new file mode 100755 index 0000000..3211bf7 --- /dev/null +++ b/tools/buildsteps/ios/make-native-depends @@ -0,0 +1,9 @@ +WORKSPACE=${WORKSPACE:-$( cd $(dirname $0)/../../.. ; pwd -P )} +XBMC_PLATFORM_DIR=ios +. $WORKSPACE/tools/buildsteps/defaultenv + +if [ "$(pathChanged $WORKSPACE/tools/depends)" == "1" ] && [ "$BINARY_ADDONS_CLEAN_NATIVETOOLS" != "0" ] +then + git clean -xffd $WORKSPACE/tools/depends/native + cd $WORKSPACE/tools/depends/native;make -j $BUILDTHREADS && tagSuccessFulBuild $WORKSPACE/tools/depends +fi
\ No newline at end of file diff --git a/tools/buildsteps/ios/make-xbmc b/tools/buildsteps/ios/make-xbmc new file mode 100755 index 0000000..5d7c604 --- /dev/null +++ b/tools/buildsteps/ios/make-xbmc @@ -0,0 +1,9 @@ +WORKSPACE=${WORKSPACE:-$( cd $(dirname $0)/../../.. ; pwd -P )} +XBMC_PLATFORM_DIR=ios +. $WORKSPACE/tools/buildsteps/defaultenv + +cd $WORKSPACE/build;xcodebuild -configuration $Configuration -jobs $BUILDTHREADS \ + -parallelizeTargets \ + -target deb \ + SDKROOT=iphoneos$SDK_VERSION XBMC_DEPENDS_ROOT=$XBMC_DEPENDS_ROOT \ + CODE_SIGNING_ALLOWED="NO" diff --git a/tools/buildsteps/ios/package b/tools/buildsteps/ios/package new file mode 100755 index 0000000..b264094 --- /dev/null +++ b/tools/buildsteps/ios/package @@ -0,0 +1,11 @@ +WORKSPACE=${WORKSPACE:-$( cd $(dirname $0)/../../.. ; pwd -P )} +XBMC_PLATFORM_DIR=ios +. $WORKSPACE/tools/buildsteps/defaultenv + +cd $WORKSPACE/build/tools/darwin/packaging/darwin_embedded/ + +#rename for upload +#e.x. kodi-20130314-8c2fb31-Frodo-ios64.deb +UPLOAD_FILENAME="kodi-$(getBuildRevDateStr)-ios64.deb" +mkdir $WORKSPACE/tools/darwin/packaging/ios +mv *.deb $WORKSPACE/tools/darwin/packaging/ios/$UPLOAD_FILENAME diff --git a/tools/buildsteps/ios/prepare-depends b/tools/buildsteps/ios/prepare-depends new file mode 100755 index 0000000..3b6a893 --- /dev/null +++ b/tools/buildsteps/ios/prepare-depends @@ -0,0 +1,15 @@ +WORKSPACE=${WORKSPACE:-$( cd $(dirname $0)/../../.. ; pwd -P )} +XBMC_PLATFORM_DIR=ios +. $WORKSPACE/tools/buildsteps/defaultenv + +#clean without depends for skipping depends build if possible +#also skip binary addons (pvr, audioencoder) as long as they are deployed in tree +cd $WORKSPACE;git clean -xfd -e "cmake/.last_success_revision" -e "tools/depends" ${DEPLOYED_BINARY_ADDONS} + +# if depends path has changed - cleanout everything and do a full rebuild +if [ "$(pathChanged $WORKSPACE/tools/depends)" == "1" ] +then + #clean up the rest too + cd $WORKSPACE;git clean -xffd + cd $WORKSPACE/tools/depends/;./bootstrap +fi diff --git a/tools/buildsteps/ios/prepare-xbmc b/tools/buildsteps/ios/prepare-xbmc new file mode 100755 index 0000000..d1dc25c --- /dev/null +++ b/tools/buildsteps/ios/prepare-xbmc @@ -0,0 +1,9 @@ +WORKSPACE=${WORKSPACE:-$( cd $(dirname $0)/../../.. ; pwd -P )} +XBMC_PLATFORM_DIR=ios +. $WORKSPACE/tools/buildsteps/defaultenv + +#build binary addons before building xbmc... +#make sure that binary_addons don't clean the native tools +#here +BINARY_ADDONS_CLEAN_NATIVETOOLS="0" +. $WORKSPACE/tools/buildsteps/$XBMC_PLATFORM_DIR/make-binary-addons diff --git a/tools/buildsteps/jenkins_docs/README.mac b/tools/buildsteps/jenkins_docs/README.mac new file mode 100644 index 0000000..edbf52c --- /dev/null +++ b/tools/buildsteps/jenkins_docs/README.mac @@ -0,0 +1,100 @@ +This are the steps to be done for configuring a mac for being a build slave to the Kodi jenkins CI system +-------------------------------------------------------------------------------------------------------- + +1. setup user jenkins as follows: + +# create jenkins group +NEXT_GID=$((`dscl /Local/Default list /Groups gid | awk '{ print $2 }' | sort -n | grep -v '^[5-9]' | tail -n1` + 1)) +sudo dscl /Local/Default create /Groups/jenkins +sudo dscl /Local/Default create /Groups/jenkins PrimaryGroupID $NEXT_GID +sudo dscl /Local/Default create /Groups/jenkins Password \* +sudo dscl /Local/Default create /Groups/jenkins RealName 'Jenkins Node Service' +# create jenkins user +NEXT_UID=$((`dscl /Local/Default list /Users uid | awk '{ print $2 }' | sort -n | grep -v '^[5-9]' | tail -n1` + 1)) +sudo dscl /Local/Default create /Users/jenkins +sudo dscl /Local/Default create /Users/jenkins UniqueID $NEXT_UID +sudo dscl /Local/Default create /Users/jenkins PrimaryGroupID $NEXT_GID +sudo dscl /Local/Default create /Users/jenkins UserShell /usr/bin/false +sudo dscl /Local/Default create /Users/jenkins NFSHomeDirectory /var/lib/jenkins +sudo dscl /Local/Default create /Users/jenkins Password \* +sudo dseditgroup -o edit -a jenkins -t user jenkins +# create the jenkins home dir +sudo mkdir /var/lib/jenkins +sudo chown -R jenkins:wheel /var/lib/jenkins +# create a logging space +sudo mkdir /var/log/jenkins +sudo chown jenkins:wheel /var/log/jenkins + +3. mkdir /Users/Shared/jenkins + +4. sudo chown jenkins:wheel /Users/Shared/jenkins + +5. mkdir -p /Users/Shared/xbmc-depends/dSyms + +6. sudo chown -R jenkins:wheel /Users/Shared/xbmc-depends/ + +7. Change to user jenknis via sudo -u jenkins bash + +8. mkdir /Users/Shared/jenkins/slave + +9. nano /Users/Shared/jenkins/slave/startslave.sh and add the following + +#!/bin/sh + +rm error.log +rm stdout.log +java -Djava.awt.headless=true -jar slave.jar -jar-cache /Users/Shared/jenkins/cache -jnlpUrl http://jenkins.kodi.tv/computer/<node name from jenkins node page>/slave-agent.jnlp -secret <secret from jenkins node page> + +10. chmod +x /Users/Shared/jenkins/slave/startslave.sh + +11. edit startslave.sh and add nodename and the secret at the end of the command line from the node page + +12. nano /Users/Shared/jenkins/slave/org.jenkins-ci.slave.jnlp.plist and add the following + +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> +<plist version="1.0"> +<dict> + <key>Label</key> + <string>com.example.ci</string> + <key>ProgramArguments</key> + <array> + <string>/Users/Shared/jenkins/slave/startslave.sh</string> + </array> + <key>KeepAlive</key> + <true/> + <key>RunAtLoad</key> + <true/> + <key>SessionCreate</key> + <true/> + <key>UserName</key> + <string>jenkins</string> + <key>WorkingDirectory</key> + <string>/Users/Shared/jenkins</string> + <key>StandardOutPath</key> + <string>/Users/Shared/jenkins/slave/stdout.log</string> + <key>StandardErrorPath</key> + <string>/Users/Shared/jenkins/slave/error.log</string> +</dict> +</plist> + +13. sudo mv /Users/Shared/jenkins/slave/org.jenkins-ci.slave.jnlp.plist /Library/LaunchDaemons/org.jenkins-ci.slave.jnlp.plist + +14. sudo nano /etc/profile and add PATH=$PATH:/usr/local/bin + +15. curl http://jenkins.kodi.tv/jnlpJars/slave.jar -Lo /Users/Shared/jenkins/slave.jar + +16. install java JDK 8 + +17. Install Xcode (get it from developer.apple.com -> Downloads) and start it once (accept license): +- 10.2 to /Applications/Xcode10.2.app - for macOS and iOS builds +- 11.3.1 to /Applications/Xcode11.3.1.app - for tvOS builds + +18. install brew + +19. install ccache via brew (brew install ccache) + +20. edit /var/lib/jenkins/.ccache/ccache.conf and set max_size to 20.0G (this file might just appear after the first build done on the node) + +21. load service: +sudo launchctl load /Library/LaunchDaemons/org.jenkins-ci.slave.jnlp.plist diff --git a/tools/buildsteps/linux-debian/configure-depends b/tools/buildsteps/linux-debian/configure-depends new file mode 100755 index 0000000..96e6aaa --- /dev/null +++ b/tools/buildsteps/linux-debian/configure-depends @@ -0,0 +1,2 @@ +# We do not use unified dependencies here, but system libs +exit 0 diff --git a/tools/buildsteps/linux-debian/configure-xbmc b/tools/buildsteps/linux-debian/configure-xbmc new file mode 100755 index 0000000..44380b3 --- /dev/null +++ b/tools/buildsteps/linux-debian/configure-xbmc @@ -0,0 +1,2 @@ +# Nothing to be done, this is all handled by the package script +exit 0 diff --git a/tools/buildsteps/linux-debian/make-depends b/tools/buildsteps/linux-debian/make-depends new file mode 100755 index 0000000..d1de8c7 --- /dev/null +++ b/tools/buildsteps/linux-debian/make-depends @@ -0,0 +1,2 @@ +# noop +exit 0 diff --git a/tools/buildsteps/linux-debian/make-xbmc b/tools/buildsteps/linux-debian/make-xbmc new file mode 100755 index 0000000..d1de8c7 --- /dev/null +++ b/tools/buildsteps/linux-debian/make-xbmc @@ -0,0 +1,2 @@ +# noop +exit 0 diff --git a/tools/buildsteps/linux-debian/package b/tools/buildsteps/linux-debian/package new file mode 100755 index 0000000..accffd1 --- /dev/null +++ b/tools/buildsteps/linux-debian/package @@ -0,0 +1,16 @@ +WORKSPACE=${WORKSPACE:-$( cd $(dirname $0)/../../.. ; pwd -P )} +XBMC_PLATFORM_DIR=linux-debian +. $WORKSPACE/tools/buildsteps/defaultenv + +cd $WORKSPACE + +RELEASEV=$VERSION \ +TAG=$TAG \ +DISTS=${DISTS:-"stable"} \ +ARCHS=${ARCHS:-"i386 amd64"} \ +BUILDER=${BUILDER:-"pdebuild"} \ +PDEBUILD_OPTS=${PDEBUILD_OPTS:-"--debbuildopts \"-j$BUILDTHREADS\""} \ +PBUILDER_BASE=${PBUILDER_BASE:-"/home/$USER/xbmc-packaging/pbuilder"} \ +DPUT_TARGET=${DPUT_TARGET:-"local"} \ +Configuration="$Configuration" \ +tools/Linux/packaging/mk-debian-package.sh diff --git a/tools/buildsteps/linux-debian/prepare-depends b/tools/buildsteps/linux-debian/prepare-depends new file mode 100755 index 0000000..ca916d0 --- /dev/null +++ b/tools/buildsteps/linux-debian/prepare-depends @@ -0,0 +1 @@ +exit 0 diff --git a/tools/buildsteps/linux-debian/prepare-xbmc b/tools/buildsteps/linux-debian/prepare-xbmc new file mode 100755 index 0000000..d54f426 --- /dev/null +++ b/tools/buildsteps/linux-debian/prepare-xbmc @@ -0,0 +1,2 @@ +#nothing on linux +exit 0 diff --git a/tools/buildsteps/linux/configure-depends b/tools/buildsteps/linux/configure-depends new file mode 100755 index 0000000..7046717 --- /dev/null +++ b/tools/buildsteps/linux/configure-depends @@ -0,0 +1,9 @@ +WORKSPACE=${WORKSPACE:-$( cd $(dirname $0)/../../.. ; pwd -P )} +XBMC_PLATFORM_DIR=linux +. $WORKSPACE/tools/buildsteps/defaultenv + +if [ "$(pathChanged $WORKSPACE/tools/depends)" == "1" ] +then + cd $WORKSPACE/tools/depends;./configure \ + --with-toolchain=/usr --prefix=$XBMC_DEPENDS_ROOT --host=$BUILD_HOST --with-rendersystem=$RENDER_SYSTEM --with-tarballs=$TARBALLS $DEBUG_SWITCH +fi diff --git a/tools/buildsteps/linux/configure-xbmc b/tools/buildsteps/linux/configure-xbmc new file mode 100755 index 0000000..92557bf --- /dev/null +++ b/tools/buildsteps/linux/configure-xbmc @@ -0,0 +1,5 @@ +WORKSPACE=${WORKSPACE:-$( cd $(dirname $0)/../../.. ; pwd -P )} +XBMC_PLATFORM_DIR=linux +. $WORKSPACE/tools/buildsteps/defaultenv + +make -C $WORKSPACE/tools/depends/target/cmakebuildsys diff --git a/tools/buildsteps/linux/make-binary-addons b/tools/buildsteps/linux/make-binary-addons new file mode 100755 index 0000000..1f93c3e --- /dev/null +++ b/tools/buildsteps/linux/make-binary-addons @@ -0,0 +1,28 @@ +WORKSPACE=${WORKSPACE:-$( cd $(dirname $0)/../../.. ; pwd -P )} +XBMC_PLATFORM_DIR=linux +. $WORKSPACE/tools/buildsteps/defaultenv + +. $WORKSPACE/tools/buildsteps/$XBMC_PLATFORM_DIR/make-native-depends + +#clear the build failed file +rm -f $WORKSPACE/cmake/$FAILED_BUILD_FILENAME + +ALL_BINARY_ADDONS_BUILT="1" +#only build binary addons when requested by env/jenkins +if [ "$BUILD_BINARY_ADDONS" == "true" ] +then + for addon in $BINARY_ADDONS + do + echo "building $addon" + git clean -xffd $WORKSPACE/$BINARY_ADDONS_ROOT/$addon + cd $WORKSPACE/$BINARY_ADDONS_ROOT/$addon;make -j $BUILDTHREADS V=99 VERBOSE=1 || ALL_BINARY_ADDONS_BUILT="0" + done +fi + +if [ "$ALL_BINARY_ADDONS_BUILT" == "1" ] +then + tagSuccessFulBuild $WORKSPACE/cmake +else + #mark the build failure in the filesystem but leave jenkins running + tagFailedBuild $WORKSPACE/cmake +fi diff --git a/tools/buildsteps/linux/make-depends b/tools/buildsteps/linux/make-depends new file mode 100755 index 0000000..224d4e5 --- /dev/null +++ b/tools/buildsteps/linux/make-depends @@ -0,0 +1,9 @@ +WORKSPACE=${WORKSPACE:-$( cd $(dirname $0)/../../.. ; pwd -P )} +XBMC_PLATFORM_DIR=linux +. $WORKSPACE/tools/buildsteps/defaultenv + +if [ "$(pathChanged $WORKSPACE/tools/depends)" == "1" ] +then + cd $WORKSPACE/tools/depends;make -j $BUILDTHREADS || make && tagSuccessFulBuild $WORKSPACE/tools/depends +fi + diff --git a/tools/buildsteps/linux/make-native-depends b/tools/buildsteps/linux/make-native-depends new file mode 100755 index 0000000..5ac21af --- /dev/null +++ b/tools/buildsteps/linux/make-native-depends @@ -0,0 +1,9 @@ +WORKSPACE=${WORKSPACE:-$( cd $(dirname $0)/../../.. ; pwd -P )} +XBMC_PLATFORM_DIR=linux +. $WORKSPACE/tools/buildsteps/defaultenv + +if [ "$(pathChanged $WORKSPACE/tools/depends)" == "1" ] && [ "$BINARY_ADDONS_CLEAN_NATIVETOOLS" != "0" ] +then + git clean -xffd $WORKSPACE/tools/depends/native + cd $WORKSPACE/tools/depends/native;make -j $BUILDTHREADS && tagSuccessFulBuild $WORKSPACE/tools/depends +fi diff --git a/tools/buildsteps/linux/make-xbmc b/tools/buildsteps/linux/make-xbmc new file mode 100755 index 0000000..534b578 --- /dev/null +++ b/tools/buildsteps/linux/make-xbmc @@ -0,0 +1,5 @@ +WORKSPACE=${WORKSPACE:-$( cd $(dirname $0)/../../.. ; pwd -P )} +XBMC_PLATFORM_DIR=linux +. $WORKSPACE/tools/buildsteps/defaultenv + +cd $WORKSPACE/build;make -j$BUILDTHREADS || make diff --git a/tools/buildsteps/linux/package b/tools/buildsteps/linux/package new file mode 100755 index 0000000..09da07b --- /dev/null +++ b/tools/buildsteps/linux/package @@ -0,0 +1,5 @@ +WORKSPACE=${WORKSPACE:-$( cd $(dirname $0)/../../.. ; pwd -P )} +XBMC_PLATFORM_DIR=linux +. $WORKSPACE/tools/buildsteps/defaultenv + +#nothing for linux atm diff --git a/tools/buildsteps/linux/prepare-depends b/tools/buildsteps/linux/prepare-depends new file mode 100755 index 0000000..ec5219a --- /dev/null +++ b/tools/buildsteps/linux/prepare-depends @@ -0,0 +1,15 @@ +WORKSPACE=${WORKSPACE:-$( cd $(dirname $0)/../../.. ; pwd -P )} +XBMC_PLATFORM_DIR=linux +. $WORKSPACE/tools/buildsteps/defaultenv + +#clean without depends for skipping depends build if possible +#also skip binary addons (pvr, audioencoder) as long as they are deployed in tree +cd $WORKSPACE;git clean -xfd -e "cmake/.last_success_revision" -e "tools/depends" ${DEPLOYED_BINARY_ADDONS} + +# if depends path has changed - cleanout everything and do a full rebuild +if [ "$(pathChanged $WORKSPACE/tools/depends)" == "1" ] +then + #clean up the rest too + cd $WORKSPACE;git clean -xffd + cd $WORKSPACE/tools/depends/;./bootstrap +fi diff --git a/tools/buildsteps/linux/prepare-xbmc b/tools/buildsteps/linux/prepare-xbmc new file mode 100755 index 0000000..84a96e5 --- /dev/null +++ b/tools/buildsteps/linux/prepare-xbmc @@ -0,0 +1,9 @@ +WORKSPACE=${WORKSPACE:-$( cd $(dirname $0)/../../.. ; pwd -P )} +XBMC_PLATFORM_DIR=linux +. $WORKSPACE/tools/buildsteps/defaultenv + +#build binary addons before building xbmc... +#make sure that binary_addons don't clean the native tools +#here +BINARY_ADDONS_CLEAN_NATIVETOOLS="0" +. $WORKSPACE/tools/buildsteps/$XBMC_PLATFORM_DIR/make-binary-addons diff --git a/tools/buildsteps/linux/run-tests b/tools/buildsteps/linux/run-tests new file mode 100755 index 0000000..f11d5f1 --- /dev/null +++ b/tools/buildsteps/linux/run-tests @@ -0,0 +1,14 @@ +WORKSPACE=${WORKSPACE:-$( cd $(dirname $0)/../../.. ; pwd -P )} +XBMC_PLATFORM_DIR=linux +. $WORKSPACE/tools/buildsteps/defaultenv + +cd $WORKSPACE/build;make -j$BUILDTHREADS kodi-test +if [ "$Configuration" != "Coverage" ]; then + cd $WORKSPACE;build/kodi-test --gtest_output=xml:gtestresults.xml +else + cd $WORKSPACE/build;GTEST_OUTPUT="xml:$WORKSPACE/gtestresults.xml" make coverage +fi + +awk '{ if ($1 == "<testcase" && match($0, "notrun")) print substr($0,0,length($0)-2) "><skipped/></testcase>"; else print $0;}' gtestresults.xml > gtestresults-skipped.xml +rm gtestresults.xml +mv gtestresults-skipped.xml gtestresults.xml diff --git a/tools/buildsteps/osx-arm64/configure-depends b/tools/buildsteps/osx-arm64/configure-depends new file mode 100755 index 0000000..c950eb9 --- /dev/null +++ b/tools/buildsteps/osx-arm64/configure-depends @@ -0,0 +1,13 @@ +WORKSPACE=${WORKSPACE:-$( cd $(dirname $0)/../../.. ; pwd -P )} +XBMC_PLATFORM_DIR=osx-arm64 +. $WORKSPACE/tools/buildsteps/defaultenv + +if [ "$(pathChanged $WORKSPACE/tools/depends)" == "1" ] +then + cd $WORKSPACE/tools/depends;./configure \ + --with-tarballs=/Users/Shared/xbmc-depends/tarballs \ + --host=aarch64-apple-darwin \ + --with-sdk=$SDK_VERSION \ + --with-platform=macos \ + --prefix=$XBMC_DEPENDS_ROOT $DEBUG_SWITCH +fi diff --git a/tools/buildsteps/osx-arm64/configure-xbmc b/tools/buildsteps/osx-arm64/configure-xbmc new file mode 100755 index 0000000..c8adee0 --- /dev/null +++ b/tools/buildsteps/osx-arm64/configure-xbmc @@ -0,0 +1,5 @@ +WORKSPACE=${WORKSPACE:-$( cd $(dirname $0)/../../.. ; pwd -P )} +XBMC_PLATFORM_DIR=osx-arm64 +. $WORKSPACE/tools/buildsteps/defaultenv + +make -C $WORKSPACE/tools/depends/target/cmakebuildsys APP_WINDOW_SYSTEM=native CMAKE_EXTRA_ARGUMENTS="-D CODE_SIGN_IDENTITY='$CODE_SIGN_IDENTITY' -D NOTARYTOOL_KEYCHAIN_PROFILE='$NOTARYTOOL_KEYCHAIN_PROFILE' -D NOTARYTOOL_KEYCHAIN_PATH='$NOTARYTOOL_KEYCHAIN_PATH'" diff --git a/tools/buildsteps/osx-arm64/load-env b/tools/buildsteps/osx-arm64/load-env new file mode 100755 index 0000000..4990f4b --- /dev/null +++ b/tools/buildsteps/osx-arm64/load-env @@ -0,0 +1,3 @@ +WORKSPACE=${WORKSPACE:-$( cd $(dirname $0)/../../.. ; pwd -P )} +XBMC_PLATFORM_DIR=osx-arm64 +. $WORKSPACE/tools/buildsteps/defaultenv diff --git a/tools/buildsteps/osx-arm64/make-binary-addons b/tools/buildsteps/osx-arm64/make-binary-addons new file mode 100755 index 0000000..458f9f1 --- /dev/null +++ b/tools/buildsteps/osx-arm64/make-binary-addons @@ -0,0 +1,30 @@ +WORKSPACE=${WORKSPACE:-$( cd $(dirname $0)/../../.. ; pwd -P )} +XBMC_PLATFORM_DIR=osx-arm64 +. $WORKSPACE/tools/buildsteps/defaultenv + +. $WORKSPACE/tools/buildsteps/$XBMC_PLATFORM_DIR/make-native-depends + +#clear the build failed file +rm -f $WORKSPACE/cmake/$FAILED_BUILD_FILENAME + +ALL_BINARY_ADDONS_BUILT="1" +#only build binary addons when requested by env/jenkins +if [ "$BUILD_BINARY_ADDONS" == "true" ] +then + for addon in $BINARY_ADDONS + do + echo "building $addon" + git clean -xffd $WORKSPACE/$BINARY_ADDONS_ROOT/$addon + + INSTALL_PREFIX="../../../../../build/addons/" + cd $WORKSPACE/$BINARY_ADDONS_ROOT/$addon;make -j $BUILDTHREADS V=99 VERBOSE=1 INSTALL_PREFIX="$INSTALL_PREFIX" || ALL_BINARY_ADDONS_BUILT="0" + done +fi + +if [ "$ALL_BINARY_ADDONS_BUILT" == "1" ] +then + tagSuccessFulBuild $WORKSPACE/cmake +else + #mark the build failure in the filesystem but leave jenkins running + tagFailedBuild $WORKSPACE/cmake +fi diff --git a/tools/buildsteps/osx-arm64/make-depends b/tools/buildsteps/osx-arm64/make-depends new file mode 100755 index 0000000..74e4213 --- /dev/null +++ b/tools/buildsteps/osx-arm64/make-depends @@ -0,0 +1,9 @@ +WORKSPACE=${WORKSPACE:-$( cd $(dirname $0)/../../.. ; pwd -P )} +XBMC_PLATFORM_DIR=osx-arm64 +. $WORKSPACE/tools/buildsteps/defaultenv + +if [ "$(pathChanged $WORKSPACE/tools/depends)" == "1" ] +then + cd $WORKSPACE/tools/depends;make -j $BUILDTHREADS && tagSuccessFulBuild $WORKSPACE/tools/depends +fi + diff --git a/tools/buildsteps/osx-arm64/make-native-depends b/tools/buildsteps/osx-arm64/make-native-depends new file mode 100755 index 0000000..d0e6d76 --- /dev/null +++ b/tools/buildsteps/osx-arm64/make-native-depends @@ -0,0 +1,9 @@ +WORKSPACE=${WORKSPACE:-$( cd $(dirname $0)/../../.. ; pwd -P )} +XBMC_PLATFORM_DIR=osx-arm64 +. $WORKSPACE/tools/buildsteps/defaultenv + +if [ "$(pathChanged $WORKSPACE/tools/depends)" == "1" ] && [ "$BINARY_ADDONS_CLEAN_NATIVETOOLS" != "0" ] +then + git clean -xffd $WORKSPACE/tools/depends/native + cd $WORKSPACE/tools/depends/native;make -j $BUILDTHREADS && tagSuccessFulBuild $WORKSPACE/tools/depends +fi
\ No newline at end of file diff --git a/tools/buildsteps/osx-arm64/make-xbmc b/tools/buildsteps/osx-arm64/make-xbmc new file mode 100755 index 0000000..b43dec9 --- /dev/null +++ b/tools/buildsteps/osx-arm64/make-xbmc @@ -0,0 +1,5 @@ +WORKSPACE=${WORKSPACE:-$( cd $(dirname $0)/../../.. ; pwd -P )} +XBMC_PLATFORM_DIR=osx-arm64 +. $WORKSPACE/tools/buildsteps/defaultenv + +cd $WORKSPACE/build;make -j$BUILDTHREADS || make diff --git a/tools/buildsteps/osx-arm64/package b/tools/buildsteps/osx-arm64/package new file mode 100755 index 0000000..b14c2e0 --- /dev/null +++ b/tools/buildsteps/osx-arm64/package @@ -0,0 +1,11 @@ +WORKSPACE=${WORKSPACE:-$( cd $(dirname $0)/../../.. ; pwd -P )} +XBMC_PLATFORM_DIR=osx-arm64 +. $WORKSPACE/tools/buildsteps/defaultenv + +cd $WORKSPACE/build;make -j$BUILDTHREADS dmg +cd $WORKSPACE/build/tools/darwin/packaging/osx/ + +#rename for upload +#e.x. kodi-20130314-8c2fb31-Frodo-x86_64.dmg +UPLOAD_FILENAME="kodi-$(getBuildRevDateStr)-arm64.dmg" +mv *.dmg $WORKSPACE/tools/darwin/packaging/osx/$UPLOAD_FILENAME diff --git a/tools/buildsteps/osx-arm64/prepare-depends b/tools/buildsteps/osx-arm64/prepare-depends new file mode 100755 index 0000000..13faf12 --- /dev/null +++ b/tools/buildsteps/osx-arm64/prepare-depends @@ -0,0 +1,15 @@ +WORKSPACE=${WORKSPACE:-$( cd $(dirname $0)/../../.. ; pwd -P )} +XBMC_PLATFORM_DIR=osx-arm64 +. $WORKSPACE/tools/buildsteps/defaultenv + +#clean without depends for skipping depends build if possible +#also skip binary addons (pvr, audioencoder) as long as they are deployed in tree +cd $WORKSPACE;git clean -xfd -e "cmake/.last_success_revision" -e "tools/depends" ${DEPLOYED_BINARY_ADDONS} + +# if depends path has changed - cleanout everything and do a full rebuild +if [ "$(pathChanged $WORKSPACE/tools/depends)" == "1" ] +then + #clean up the rest too + cd $WORKSPACE;git clean -xffd + cd $WORKSPACE/tools/depends/;./bootstrap +fi diff --git a/tools/buildsteps/osx-arm64/prepare-xbmc b/tools/buildsteps/osx-arm64/prepare-xbmc new file mode 100755 index 0000000..9402652 --- /dev/null +++ b/tools/buildsteps/osx-arm64/prepare-xbmc @@ -0,0 +1,9 @@ +WORKSPACE=${WORKSPACE:-$( cd $(dirname $0)/../../.. ; pwd -P )} +XBMC_PLATFORM_DIR=osx-arm64 +. $WORKSPACE/tools/buildsteps/defaultenv + +#build binary addons before building xbmc... +#make sure that binary_addons don't clean the native tools +#here +BINARY_ADDONS_CLEAN_NATIVETOOLS="0" +. $WORKSPACE/tools/buildsteps/$XBMC_PLATFORM_DIR/make-binary-addons diff --git a/tools/buildsteps/osx64/configure-depends b/tools/buildsteps/osx64/configure-depends new file mode 100755 index 0000000..c44250e --- /dev/null +++ b/tools/buildsteps/osx64/configure-depends @@ -0,0 +1,13 @@ +WORKSPACE=${WORKSPACE:-$( cd $(dirname $0)/../../.. ; pwd -P )} +XBMC_PLATFORM_DIR=osx64 +. $WORKSPACE/tools/buildsteps/defaultenv + +if [ "$(pathChanged $WORKSPACE/tools/depends)" == "1" ] +then + cd $WORKSPACE/tools/depends;./configure \ + --with-tarballs=/Users/Shared/xbmc-depends/tarballs \ + --host=x86_64-apple-darwin \ + --with-sdk=$SDK_VERSION \ + --with-platform=macos \ + --prefix=$XBMC_DEPENDS_ROOT $DEBUG_SWITCH +fi diff --git a/tools/buildsteps/osx64/configure-xbmc b/tools/buildsteps/osx64/configure-xbmc new file mode 100755 index 0000000..2643cc9 --- /dev/null +++ b/tools/buildsteps/osx64/configure-xbmc @@ -0,0 +1,5 @@ +WORKSPACE=${WORKSPACE:-$( cd $(dirname $0)/../../.. ; pwd -P )} +XBMC_PLATFORM_DIR=osx64 +. $WORKSPACE/tools/buildsteps/defaultenv + +make -C $WORKSPACE/tools/depends/target/cmakebuildsys CMAKE_EXTRA_ARGUMENTS="-D CODE_SIGN_IDENTITY='$CODE_SIGN_IDENTITY' -D NOTARYTOOL_KEYCHAIN_PROFILE='$NOTARYTOOL_KEYCHAIN_PROFILE' -D NOTARYTOOL_KEYCHAIN_PATH='$NOTARYTOOL_KEYCHAIN_PATH'" diff --git a/tools/buildsteps/osx64/load-env b/tools/buildsteps/osx64/load-env new file mode 100755 index 0000000..59635b7 --- /dev/null +++ b/tools/buildsteps/osx64/load-env @@ -0,0 +1,3 @@ +WORKSPACE=${WORKSPACE:-$( cd $(dirname $0)/../../.. ; pwd -P )} +XBMC_PLATFORM_DIR=osx64 +. $WORKSPACE/tools/buildsteps/defaultenv diff --git a/tools/buildsteps/osx64/make-binary-addons b/tools/buildsteps/osx64/make-binary-addons new file mode 100755 index 0000000..fd0bd7a --- /dev/null +++ b/tools/buildsteps/osx64/make-binary-addons @@ -0,0 +1,30 @@ +WORKSPACE=${WORKSPACE:-$( cd $(dirname $0)/../../.. ; pwd -P )} +XBMC_PLATFORM_DIR=osx64 +. $WORKSPACE/tools/buildsteps/defaultenv + +. $WORKSPACE/tools/buildsteps/$XBMC_PLATFORM_DIR/make-native-depends + +#clear the build failed file +rm -f $WORKSPACE/cmake/$FAILED_BUILD_FILENAME + +ALL_BINARY_ADDONS_BUILT="1" +#only build binary addons when requested by env/jenkins +if [ "$BUILD_BINARY_ADDONS" == "true" ] +then + for addon in $BINARY_ADDONS + do + echo "building $addon" + git clean -xffd $WORKSPACE/$BINARY_ADDONS_ROOT/$addon + + INSTALL_PREFIX="../../../../../build/addons/" + cd $WORKSPACE/$BINARY_ADDONS_ROOT/$addon;make -j $BUILDTHREADS V=99 VERBOSE=1 INSTALL_PREFIX="$INSTALL_PREFIX" || ALL_BINARY_ADDONS_BUILT="0" + done +fi + +if [ "$ALL_BINARY_ADDONS_BUILT" == "1" ] +then + tagSuccessFulBuild $WORKSPACE/cmake +else + #mark the build failure in the filesystem but leave jenkins running + tagFailedBuild $WORKSPACE/cmake +fi diff --git a/tools/buildsteps/osx64/make-depends b/tools/buildsteps/osx64/make-depends new file mode 100755 index 0000000..5a325e1 --- /dev/null +++ b/tools/buildsteps/osx64/make-depends @@ -0,0 +1,9 @@ +WORKSPACE=${WORKSPACE:-$( cd $(dirname $0)/../../.. ; pwd -P )} +XBMC_PLATFORM_DIR=osx64 +. $WORKSPACE/tools/buildsteps/defaultenv + +if [ "$(pathChanged $WORKSPACE/tools/depends)" == "1" ] +then + cd $WORKSPACE/tools/depends;make -j $BUILDTHREADS && tagSuccessFulBuild $WORKSPACE/tools/depends +fi + diff --git a/tools/buildsteps/osx64/make-native-depends b/tools/buildsteps/osx64/make-native-depends new file mode 100755 index 0000000..b5ef526 --- /dev/null +++ b/tools/buildsteps/osx64/make-native-depends @@ -0,0 +1,9 @@ +WORKSPACE=${WORKSPACE:-$( cd $(dirname $0)/../../.. ; pwd -P )} +XBMC_PLATFORM_DIR=osx64 +. $WORKSPACE/tools/buildsteps/defaultenv + +if [ "$(pathChanged $WORKSPACE/tools/depends)" == "1" ] && [ "$BINARY_ADDONS_CLEAN_NATIVETOOLS" != "0" ] +then + git clean -xffd $WORKSPACE/tools/depends/native + cd $WORKSPACE/tools/depends/native;make -j $BUILDTHREADS && tagSuccessFulBuild $WORKSPACE/tools/depends +fi
\ No newline at end of file diff --git a/tools/buildsteps/osx64/make-xbmc b/tools/buildsteps/osx64/make-xbmc new file mode 100755 index 0000000..cc1184b --- /dev/null +++ b/tools/buildsteps/osx64/make-xbmc @@ -0,0 +1,5 @@ +WORKSPACE=${WORKSPACE:-$( cd $(dirname $0)/../../.. ; pwd -P )} +XBMC_PLATFORM_DIR=osx64 +. $WORKSPACE/tools/buildsteps/defaultenv + +cd $WORKSPACE/build;make -j$BUILDTHREADS || make diff --git a/tools/buildsteps/osx64/package b/tools/buildsteps/osx64/package new file mode 100755 index 0000000..66db6d3 --- /dev/null +++ b/tools/buildsteps/osx64/package @@ -0,0 +1,11 @@ +WORKSPACE=${WORKSPACE:-$( cd $(dirname $0)/../../.. ; pwd -P )} +XBMC_PLATFORM_DIR=osx64 +. $WORKSPACE/tools/buildsteps/defaultenv + +cd $WORKSPACE/build;make -j$BUILDTHREADS dmg +cd $WORKSPACE/build/tools/darwin/packaging/osx/ + +#rename for upload +#e.x. kodi-20130314-8c2fb31-Frodo-x86_64.dmg +UPLOAD_FILENAME="kodi-$(getBuildRevDateStr)-x86_64.dmg" +mv *.dmg $WORKSPACE/tools/darwin/packaging/osx/$UPLOAD_FILENAME diff --git a/tools/buildsteps/osx64/prepare-depends b/tools/buildsteps/osx64/prepare-depends new file mode 100755 index 0000000..8aba95e --- /dev/null +++ b/tools/buildsteps/osx64/prepare-depends @@ -0,0 +1,15 @@ +WORKSPACE=${WORKSPACE:-$( cd $(dirname $0)/../../.. ; pwd -P )} +XBMC_PLATFORM_DIR=osx64 +. $WORKSPACE/tools/buildsteps/defaultenv + +#clean without depends for skipping depends build if possible +#also skip binary addons (pvr, audioencoder) as long as they are deployed in tree +cd $WORKSPACE;git clean -xfd -e "cmake/.last_success_revision" -e "tools/depends" ${DEPLOYED_BINARY_ADDONS} + +# if depends path has changed - cleanout everything and do a full rebuild +if [ "$(pathChanged $WORKSPACE/tools/depends)" == "1" ] +then + #clean up the rest too + cd $WORKSPACE;git clean -xffd + cd $WORKSPACE/tools/depends/;./bootstrap +fi diff --git a/tools/buildsteps/osx64/prepare-xbmc b/tools/buildsteps/osx64/prepare-xbmc new file mode 100755 index 0000000..05b5ed3 --- /dev/null +++ b/tools/buildsteps/osx64/prepare-xbmc @@ -0,0 +1,9 @@ +WORKSPACE=${WORKSPACE:-$( cd $(dirname $0)/../../.. ; pwd -P )} +XBMC_PLATFORM_DIR=osx64 +. $WORKSPACE/tools/buildsteps/defaultenv + +#build binary addons before building xbmc... +#make sure that binary_addons don't clean the native tools +#here +BINARY_ADDONS_CLEAN_NATIVETOOLS="0" +. $WORKSPACE/tools/buildsteps/$XBMC_PLATFORM_DIR/make-binary-addons diff --git a/tools/buildsteps/osx64/run-tests b/tools/buildsteps/osx64/run-tests new file mode 100755 index 0000000..38ae333 --- /dev/null +++ b/tools/buildsteps/osx64/run-tests @@ -0,0 +1,10 @@ +WORKSPACE=${WORKSPACE:-$( cd $(dirname $0)/../../.. ; pwd -P )} +XBMC_PLATFORM_DIR=osx64 +. $WORKSPACE/tools/buildsteps/defaultenv + +cd $WORKSPACE/build;make -j$BUILDTHREADS kodi-test +cd $WORKSPACE;build/kodi-test --gtest_output=xml:gtestresults.xml + +awk '{ if ($1 == "<testcase" && match($0, "notrun")) print substr($0,0,length($0)-2) "><skipped/></testcase>"; else print $0;}' gtestresults.xml > gtestresults-skipped.xml +rm gtestresults.xml +mv gtestresults-skipped.xml gtestresults.xml diff --git a/tools/buildsteps/tvos/configure-depends b/tools/buildsteps/tvos/configure-depends new file mode 100755 index 0000000..98d78e3 --- /dev/null +++ b/tools/buildsteps/tvos/configure-depends @@ -0,0 +1,13 @@ +WORKSPACE=${WORKSPACE:-$( cd $(dirname $0)/../../.. ; pwd -P )} +XBMC_PLATFORM_DIR=tvos +. $WORKSPACE/tools/buildsteps/defaultenv + +if [ "$(pathChanged $WORKSPACE/tools/depends)" == "1" ] +then + cd $WORKSPACE/tools/depends;./configure \ + --with-tarballs=/Users/Shared/xbmc-depends/tarballs \ + --host=aarch64-apple-darwin \ + --with-sdk=$SDK_VERSION \ + --with-platform=tvos \ + --prefix=$XBMC_DEPENDS_ROOT $DEBUG_SWITCH +fi diff --git a/tools/buildsteps/tvos/configure-xbmc b/tools/buildsteps/tvos/configure-xbmc new file mode 100755 index 0000000..e3c3767 --- /dev/null +++ b/tools/buildsteps/tvos/configure-xbmc @@ -0,0 +1,5 @@ +WORKSPACE=${WORKSPACE:-$( cd $(dirname $0)/../../.. ; pwd -P )} +XBMC_PLATFORM_DIR=tvos +. $WORKSPACE/tools/buildsteps/defaultenv + +make -C $WORKSPACE/tools/depends/target/cmakebuildsys diff --git a/tools/buildsteps/tvos/make-binary-addons b/tools/buildsteps/tvos/make-binary-addons new file mode 100755 index 0000000..ae64154 --- /dev/null +++ b/tools/buildsteps/tvos/make-binary-addons @@ -0,0 +1,30 @@ +WORKSPACE=${WORKSPACE:-$( cd $(dirname $0)/../../.. ; pwd -P )} +XBMC_PLATFORM_DIR=tvos +. $WORKSPACE/tools/buildsteps/defaultenv + +. $WORKSPACE/tools/buildsteps/$XBMC_PLATFORM_DIR/make-native-depends + +#clear the build failed file +rm -f $WORKSPACE/cmake/$FAILED_BUILD_FILENAME + +ALL_BINARY_ADDONS_BUILT="1" +#only build binary addons when requested by env/jenkins +if [ "$BUILD_BINARY_ADDONS" == "true" ] +then + for addon in $BINARY_ADDONS + do + echo "building $addon" + git clean -xffd $WORKSPACE/$BINARY_ADDONS_ROOT/$addon + + INSTALL_PREFIX="../../../../../build/addons/" + cd $WORKSPACE/$BINARY_ADDONS_ROOT/$addon;make -j $BUILDTHREADS V=99 VERBOSE=1 INSTALL_PREFIX="$INSTALL_PREFIX" || ALL_BINARY_ADDONS_BUILT="0" + done +fi + +if [ "$ALL_BINARY_ADDONS_BUILT" == "1" ] +then + tagSuccessFulBuild $WORKSPACE/cmake +else + #mark the build failure in the filesystem but leave jenkins running + tagFailedBuild $WORKSPACE/cmake +fi diff --git a/tools/buildsteps/tvos/make-depends b/tools/buildsteps/tvos/make-depends new file mode 100755 index 0000000..e887290 --- /dev/null +++ b/tools/buildsteps/tvos/make-depends @@ -0,0 +1,8 @@ +WORKSPACE=${WORKSPACE:-$( cd $(dirname $0)/../../.. ; pwd -P )} +XBMC_PLATFORM_DIR=tvos +. $WORKSPACE/tools/buildsteps/defaultenv + +if [ "$(pathChanged $WORKSPACE/tools/depends)" == "1" ] +then + cd $WORKSPACE/tools/depends;make -j $BUILDTHREADS && tagSuccessFulBuild $WORKSPACE/tools/depends +fi diff --git a/tools/buildsteps/tvos/make-native-depends b/tools/buildsteps/tvos/make-native-depends new file mode 100755 index 0000000..3e44687 --- /dev/null +++ b/tools/buildsteps/tvos/make-native-depends @@ -0,0 +1,9 @@ +WORKSPACE=${WORKSPACE:-$( cd $(dirname $0)/../../.. ; pwd -P )} +XBMC_PLATFORM_DIR=tvos +. $WORKSPACE/tools/buildsteps/defaultenv + +if [ "$(pathChanged $WORKSPACE/tools/depends)" == "1" ] && [ "$BINARY_ADDONS_CLEAN_NATIVETOOLS" != "0" ] +then + git clean -xffd $WORKSPACE/tools/depends/native + cd $WORKSPACE/tools/depends/native;make -j $BUILDTHREADS && tagSuccessFulBuild $WORKSPACE/tools/depends +fi diff --git a/tools/buildsteps/tvos/make-xbmc b/tools/buildsteps/tvos/make-xbmc new file mode 100755 index 0000000..439711c --- /dev/null +++ b/tools/buildsteps/tvos/make-xbmc @@ -0,0 +1,9 @@ +WORKSPACE=${WORKSPACE:-$( cd $(dirname $0)/../../.. ; pwd -P )} +XBMC_PLATFORM_DIR=tvos +. $WORKSPACE/tools/buildsteps/defaultenv + +cd $WORKSPACE/build;xcodebuild -configuration $Configuration -jobs $BUILDTHREADS \ + -parallelizeTargets \ + -target deb \ + SDKROOT=appletvos$SDK_VERSION XBMC_DEPENDS_ROOT=$XBMC_DEPENDS_ROOT \ + CODE_SIGNING_ALLOWED="NO" diff --git a/tools/buildsteps/tvos/package b/tools/buildsteps/tvos/package new file mode 100755 index 0000000..2318af2 --- /dev/null +++ b/tools/buildsteps/tvos/package @@ -0,0 +1,11 @@ +WORKSPACE=${WORKSPACE:-$( cd $(dirname $0)/../../.. ; pwd -P )} +XBMC_PLATFORM_DIR=tvos +. $WORKSPACE/tools/buildsteps/defaultenv + +cd $WORKSPACE/build/tools/darwin/packaging/darwin_embedded/ + +#rename for upload +#e.x. kodi-20130314-8c2fb31-Frodo-tvos.deb +UPLOAD_FILENAME="kodi-$(getBuildRevDateStr)-tvos.deb" +mkdir $WORKSPACE/tools/darwin/packaging/tvos +mv *.deb $WORKSPACE/tools/darwin/packaging/tvos/$UPLOAD_FILENAME diff --git a/tools/buildsteps/tvos/prepare-depends b/tools/buildsteps/tvos/prepare-depends new file mode 100755 index 0000000..96cdae4 --- /dev/null +++ b/tools/buildsteps/tvos/prepare-depends @@ -0,0 +1,15 @@ +WORKSPACE=${WORKSPACE:-$( cd $(dirname $0)/../../.. ; pwd -P )} +XBMC_PLATFORM_DIR=tvos +. $WORKSPACE/tools/buildsteps/defaultenv + +#clean without depends for skipping depends build if possible +#also skip binary addons (pvr, audioencoder) as long as they are deployed in tree +cd $WORKSPACE;git clean -xfd -e "cmake/.last_success_revision" -e "tools/depends" ${DEPLOYED_BINARY_ADDONS} + +# if depends path has changed - cleanout everything and do a full rebuild +if [ "$(pathChanged $WORKSPACE/tools/depends)" == "1" ] +then + #clean up the rest too + cd $WORKSPACE;git clean -xffd + cd $WORKSPACE/tools/depends/;./bootstrap +fi diff --git a/tools/buildsteps/tvos/prepare-xbmc b/tools/buildsteps/tvos/prepare-xbmc new file mode 100755 index 0000000..af48229 --- /dev/null +++ b/tools/buildsteps/tvos/prepare-xbmc @@ -0,0 +1,9 @@ +WORKSPACE=${WORKSPACE:-$( cd $(dirname $0)/../../.. ; pwd -P )} +XBMC_PLATFORM_DIR=tvos +. $WORKSPACE/tools/buildsteps/defaultenv + +#build binary addons before building xbmc... +#make sure that binary_addons don't clean the native tools +#here +BINARY_ADDONS_CLEAN_NATIVETOOLS="0" +. $WORKSPACE/tools/buildsteps/$XBMC_PLATFORM_DIR/make-binary-addons diff --git a/tools/buildsteps/windows/BuildSetup.bat b/tools/buildsteps/windows/BuildSetup.bat new file mode 100644 index 0000000..6d2180a --- /dev/null +++ b/tools/buildsteps/windows/BuildSetup.bat @@ -0,0 +1,300 @@ +@ECHO OFF +REM setup all paths +PUSHD %~dp0\..\..\.. +SET base_dir=%CD% +POPD + +REM read the version values from version.txt +FOR /f "tokens=1,*" %%i IN (%base_dir%\version.txt) DO SET %%i=%%j + +SET APP_VERSION=%VERSION_MAJOR%.%VERSION_MINOR% +IF NOT [%VERSION_TAG%] == [] ( + SET APP_VERSION=%APP_VERSION%-%VERSION_TAG% +) + +rem ----Usage---- +rem BuildSetup [clean|noclean] [noprompt] [nobinaryaddons] [sh] +rem clean to force a full rebuild +rem noclean to force a build without clean +rem noprompt to avoid all prompts +rem nobinaryaddons to skip building binary addons +rem sh to use sh shell instead rxvt +CLS +TITLE %APP_NAME% for Windows Build Script +rem ----PURPOSE---- +rem - Create a working application build with a single click +rem ------------------------------------------------------------- +rem Config +rem If you get an error that Visual studio was not found, SET your path for VSNET main executable. +rem ------------------------------------------------------------- +rem CONFIG START +SET buildmode=ask +SET promptlevel=prompt +SET buildbinaryaddons=true +SET exitcode=0 +SET useshell=rxvt +FOR %%b in (%*) DO ( + IF %%b==clean SET buildmode=clean + IF %%b==noclean SET buildmode=noclean + IF %%b==noprompt SET promptlevel=noprompt + IF %%b==nobinaryaddons SET buildbinaryaddons=false + IF %%b==sh SET useshell=sh +) + +SET PreferredToolArchitecture=x64 +SET buildconfig=Release +set WORKSPACE=%base_dir%\kodi-build.%TARGET_PLATFORM% + + + :: sets the BRANCH env var + FOR /f %%a IN ('getbranch.bat') DO SET BRANCH=%%a + + rem CONFIG END + rem ------------------------------------------------------------- + goto COMPILE_CMAKE_EXE + +:COMPILE_CMAKE_EXE + ECHO Wait while preparing the build. + ECHO ------------------------------------------------------------ + ECHO Compiling %APP_NAME% branch %BRANCH%... + + IF %buildmode%==clean ( + RMDIR /S /Q %WORKSPACE% + ) + MKDIR %WORKSPACE% + PUSHD %WORKSPACE% + + cmake.exe -G "%cmakeGenerator%" -A %cmakeArch% -T host=x64 %cmakeProps% %base_dir% + IF %errorlevel%==1 ( + set DIETEXT="%APP_NAME%.EXE failed to build!" + goto DIE + ) + + cmake.exe --build . --config "%buildconfig%" + IF %errorlevel%==1 ( + set DIETEXT="%APP_NAME%.EXE failed to build!" + goto DIE + ) + + set EXE="%WORKSPACE%\%buildconfig%\%APP_NAME%.exe" + set PDB="%WORKSPACE%\%buildconfig%\%APP_NAME%.pdb" + set D3D="%WORKSPACE%\D3DCompile*.DLL" + + POPD + ECHO Done! + ECHO ------------------------------------------------------------ + IF "%cmakeProps%" NEQ "" GOTO MAKE_APPX + GOTO MAKE_BUILD_EXE + + +:MAKE_BUILD_EXE + ECHO Copying files... + PUSHD %base_dir%\project\Win32BuildSetup + IF EXIST BUILD_WIN32\application rmdir BUILD_WIN32\application /S /Q + rem Add files to exclude.txt that should not be included in the installer + + Echo Thumbs.db>>exclude.txt + Echo Desktop.ini>>exclude.txt + Echo dsstdfx.bin>>exclude.txt + Echo exclude.txt>>exclude.txt + Echo xbmc.log>>exclude.txt + Echo xbmc.old.log>>exclude.txt + Echo kodi.log>>exclude.txt + Echo kodi.old.log>>exclude.txt + Echo .so\>>exclude.txt + Echo .h\>>exclude.txt + Echo .cpp\>>exclude.txt + Echo .exp\>>exclude.txt + Echo .lib\>>exclude.txt + rem Exclude userdata files + Echo userdata\advancedsettings.xml>>exclude.txt + Echo userdata\guisettings.xml>>exclude.txt + Echo userdata\mediasources.xml>>exclude.txt + Echo userdata\ModeLines_template.xml>>exclude.txt + Echo userdata\passwords.xml>>exclude.txt + Echo userdata\profiles.xml>>exclude.txt + Echo userdata\sources.xml>>exclude.txt + Echo userdata\upnpserver.xml>>exclude.txt + rem Exclude userdata folders + Echo userdata\addon_data\>>exclude.txt + Echo userdata\cache\>>exclude.txt + Echo userdata\database\>>exclude.txt + Echo userdata\playlists\>>exclude.txt + Echo userdata\thumbnails\>>exclude.txt + + rem Exclude dlls from system to avoid duplicates + Echo .dll>>exclude_dll.txt + + md BUILD_WIN32\application + + xcopy %EXE% BUILD_WIN32\application > NUL + xcopy %D3D% BUILD_WIN32\application > NUL + xcopy %base_dir%\userdata BUILD_WIN32\application\userdata /E /Q /I /Y /EXCLUDE:exclude.txt > NUL + copy %base_dir%\LICENSE.md BUILD_WIN32\application > NUL + copy %base_dir%\privacy-policy.txt BUILD_WIN32\application > NUL + copy %base_dir%\known_issues.txt BUILD_WIN32\application > NUL + + xcopy %WORKSPACE%\addons BUILD_WIN32\application\addons /E /Q /I /Y /EXCLUDE:exclude.txt > NUL + xcopy %WORKSPACE%\*.dll BUILD_WIN32\application /Q /I /Y > NUL + xcopy %WORKSPACE%\libbluray-*.jar BUILD_WIN32\application /Q /I /Y > NUL + xcopy %WORKSPACE%\system BUILD_WIN32\application\system /E /Q /I /Y /EXCLUDE:exclude.txt+exclude_dll.txt > NUL + xcopy %WORKSPACE%\media BUILD_WIN32\application\media /E /Q /I /Y /EXCLUDE:exclude.txt > NUL + + REM create AppxManifest.xml + @PowerShell "(GC .\AppxManifest.xml.in)|%%{$_" ^ + " -Replace '@APP_NAME@', '%APP_NAME%'" ^ + " -Replace '@COMPANY_NAME@', '%COMPANY_NAME%'" ^ + " -Replace '@TARGET_ARCHITECTURE@', '%TARGET_ARCHITECTURE%'" ^ + " -Replace '@VERSION_CODE@', '%VERSION_CODE%'" ^ + " -Replace '@PACKAGE_IDENTITY@', '%PACKAGE_IDENTITY%'" ^ + " -Replace '@PACKAGE_PUBLISHER@', '%PACKAGE_PUBLISHER%'" ^ + " -Replace '@PACKAGE_DESCRIPTION@', '%PACKAGE_DESCRIPTION%'" ^ + "}|SC .\BUILD_WIN32\application\AppxManifest.xml" + + SET build_path=%CD% + IF %buildbinaryaddons%==true ( + ECHO ------------------------------------------------------------ + ECHO Building addons... + cd %base_dir%\tools\buildsteps\windows + IF %buildmode%==clean ( + call make-addons.bat clean + ) + call make-addons.bat + IF %errorlevel%==1 ( + set DIETEXT="failed to build addons" + cd %build_path% + goto DIE + ) + + cd %build_path% + IF EXIST error.log del error.log > NUL + ) + + rem restore title, some scripts mess these up + TITLE %APP_NAME% for Windows Build Script + + IF EXIST exclude.txt del exclude.txt > NUL + IF EXIST exclude_dll.txt del exclude_dll.txt > NUL + POPD + + ECHO ------------------------------------------------------------ + ECHO Build Succeeded! + GOTO NSIS_EXE + +:NSIS_EXE + ECHO ------------------------------------------------------------ + ECHO Generating installer includes... + PUSHD %base_dir%\project\Win32BuildSetup + call genNsisIncludes.bat + ECHO ------------------------------------------------------------ + call getdeploydependencies.bat + CALL extract_git_rev.bat > NUL + SET APP_SETUPFILE=%APP_NAME%Setup-%GIT_REV%-%BRANCH%-%TARGET_ARCHITECTURE%.exe + SET APP_PDBFILE=%APP_NAME%Setup-%GIT_REV%-%BRANCH%-%TARGET_ARCHITECTURE%.pdb + ECHO Creating installer %APP_SETUPFILE%... + IF EXIST %APP_SETUPFILE% del %APP_SETUPFILE% > NUL + + rem determine if current system is 32 or 64 bits + SET HOST_BITS=32 + IF %PROCESSOR_ARCHITECTURE% == AMD64 SET HOST_BITS=64 + IF %PROCESSOR_ARCHITECTURE% == ARM64 SET HOST_BITS=64 + + IF %HOST_BITS% == 64 ( + SET NSIS_REG_KEY=HKLM\Software\Wow6432Node\NSIS + ) ELSE ( + SET NSIS_REG_KEY=HKLM\Software\NSIS + ) + + rem get path to makensis.exe from registry, first try tab delim + FOR /F "tokens=2* delims= " %%A IN ('REG QUERY "%NSIS_REG_KEY%" /ve') DO SET NSISExePath=%%B + + IF NOT EXIST "%NSISExePath%" ( + rem try with space delim instead of tab + FOR /F "tokens=2* delims= " %%A IN ('REG QUERY "%NSIS_REG_KEY%" /ve') DO SET NSISExePath=%%B + ) + + IF NOT EXIST "%NSISExePath%" ( + rem fails on localized windows (Default) becomes (Par D�faut) + FOR /F "tokens=3* delims= " %%A IN ('REG QUERY "%NSIS_REG_KEY%" /ve') DO SET NSISExePath=%%B + ) + + IF NOT EXIST "%NSISExePath%" ( + FOR /F "tokens=3* delims= " %%A IN ('REG QUERY "%NSIS_REG_KEY%" /ve') DO SET NSISExePath=%%B + ) + + SET NSISExe=%NSISExePath%\makensis.exe + "%NSISExe%" /V1 /X"SetCompressor /FINAL lzma" /Dapp_root="%CD%\BUILD_WIN32" /DAPP_NAME="%APP_NAME%" /DTARGET_ARCHITECTURE="%TARGET_ARCHITECTURE%" /DVERSION_NUMBER="%VERSION_CODE%.0" /DCOMPANY_NAME="%COMPANY_NAME%" /DWEBSITE="%WEBSITE%" /Dapp_revision="%GIT_REV%" /Dapp_branch="%BRANCH%" /D%TARGET_ARCHITECTURE% "genNsisInstaller.nsi" + IF NOT EXIST "%APP_SETUPFILE%" ( + POPD + set DIETEXT=Failed to create %APP_SETUPFILE%. NSIS installed? + goto DIE + ) + copy %PDB% %APP_PDBFILE% > nul + ECHO ------------------------------------------------------------ + ECHO Done! + ECHO Setup is located at %CD%\%APP_SETUPFILE% + ECHO ------------------------------------------------------------ + POPD + GOTO END + +:MAKE_APPX + set app_ext=msix + set app_path=%base_dir%\project\UWPBuildSetup + if not exist "%app_path%" mkdir %app_path% + call %base_dir%\project\Win32BuildSetup\extract_git_rev.bat > NUL + for /F %%a IN ('dir /B /S %WORKSPACE%\AppPackages ^| findstr /I /R "%APP_NAME%_.*_%TARGET_ARCHITECTURE%_%buildconfig%\.%app_ext%$"') DO ( + copy /Y %%a %app_path%\%APP_NAME%-%GIT_REV%-%BRANCH%-%TARGET_ARCHITECTURE%.%app_ext% + copy /Y %%~dpna.cer %app_path%\%APP_NAME%-%GIT_REV%-%BRANCH%-%TARGET_ARCHITECTURE%.cer + copy /Y %%~dpna.appxsym %app_path%\%APP_NAME%-%GIT_REV%-%BRANCH%-%TARGET_ARCHITECTURE%.appxsym + goto END_APPX + ) + rem Release builds don't have Release in it's name + for /F %%a IN ('dir /B /S %WORKSPACE%\AppPackages ^| findstr /I /R "%APP_NAME%_.*_%TARGET_ARCHITECTURE%\.%app_ext%$"') DO ( + copy /Y %%a %app_path%\%APP_NAME%-%GIT_REV%-%BRANCH%-%TARGET_ARCHITECTURE%.%app_ext% + copy /Y %%~dpna.cer %app_path%\%APP_NAME%-%GIT_REV%-%BRANCH%-%TARGET_ARCHITECTURE%.cer + copy /Y %%~dpna.appxsym %app_path%\%APP_NAME%-%GIT_REV%-%BRANCH%-%TARGET_ARCHITECTURE%.appxsym + goto END_APPX + ) + + rem apxx file has win32 instead of x86 in it's name + if %TARGET_ARCHITECTURE%==x86 ( + for /F %%a IN ('dir /B /S %WORKSPACE%\AppPackages ^| findstr /I /R "%APP_NAME%_.*_win32_%buildconfig%\.%app_ext%$"') DO ( + copy /Y %%a %app_path%\%APP_NAME%-%GIT_REV%-%BRANCH%-%TARGET_ARCHITECTURE%.%app_ext% + copy /Y %%~dpna.cer %app_path%\%APP_NAME%-%GIT_REV%-%BRANCH%-%TARGET_ARCHITECTURE%.cer + copy /Y %%~dpna.appxsym %app_path%\%APP_NAME%-%GIT_REV%-%BRANCH%-%TARGET_ARCHITECTURE%.appxsym + goto END_APPX + ) + + rem Release builds don't have Release in it's name + for /F %%a IN ('dir /B /S %WORKSPACE%\AppPackages ^| findstr /I /R "%APP_NAME%_.*_win32\.%app_ext%$"') DO ( + copy /Y %%a %app_path%\%APP_NAME%-%GIT_REV%-%BRANCH%-%TARGET_ARCHITECTURE%.%app_ext% + copy /Y %%~dpna.cer %app_path%\%APP_NAME%-%GIT_REV%-%BRANCH%-%TARGET_ARCHITECTURE%.cer + copy /Y %%~dpna.appxsym %app_path%\%APP_NAME%-%GIT_REV%-%BRANCH%-%TARGET_ARCHITECTURE%.appxsym + goto END_APPX + ) + ) + +:END_APPX + ECHO ------------------------------------------------------------ + ECHO Done! + ECHO Setup is located at %app_path% + ECHO ------------------------------------------------------------ + GOTO END + +:DIE + ECHO ------------------------------------------------------------ + ECHO !-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!- + ECHO ERROR ERROR ERROR ERROR ERROR ERROR ERROR ERROR ERROR + ECHO !-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!- + set DIETEXT=ERROR: %DIETEXT% + echo %DIETEXT% + SET exitcode=1 + ECHO ------------------------------------------------------------ + GOTO END + +:END + IF %promptlevel% NEQ noprompt ( + ECHO Press any key to exit... + pause > NUL + ) + EXIT /B %exitcode% diff --git a/tools/buildsteps/windows/arm-uwp/BuildSetup.bat b/tools/buildsteps/windows/arm-uwp/BuildSetup.bat new file mode 100644 index 0000000..8fd6e03 --- /dev/null +++ b/tools/buildsteps/windows/arm-uwp/BuildSetup.bat @@ -0,0 +1,19 @@ +@ECHO OFF + +PUSHD %~dp0\.. + +CALL vswhere.bat arm store +IF ERRORLEVEL 1 ( + ECHO ERROR! BuildSetup.bat: Something went wrong when calling vswhere.bat + POPD + EXIT /B 1 +) + +SET cmakeGenerator=Visual Studio %vsver% +SET cmakeArch=ARM +SET TARGET_ARCHITECTURE=arm +SET TARGET_PLATFORM=%TARGET_ARCHITECTURE%-uwp +SET cmakeProps=-DCMAKE_SYSTEM_NAME=WindowsStore -DCMAKE_SYSTEM_VERSION=%UCRTVersion% + +CALL BuildSetup.bat %* +POPD diff --git a/tools/buildsteps/windows/arm-uwp/bootstrap-addons.bat b/tools/buildsteps/windows/arm-uwp/bootstrap-addons.bat new file mode 100644 index 0000000..0e672f0 --- /dev/null +++ b/tools/buildsteps/windows/arm-uwp/bootstrap-addons.bat @@ -0,0 +1,11 @@ +@ECHO OFF + +PUSHD %~dp0\.. +CALL vswhere.bat arm store +IF ERRORLEVEL 1 ( + ECHO ERROR! bootstrap-addons.bat: Something went wrong when calling vswhere.bat + POPD + EXIT /B 1 +) +CALL bootstrap-addons %* +POPD diff --git a/tools/buildsteps/windows/arm-uwp/download-dependencies.bat b/tools/buildsteps/windows/arm-uwp/download-dependencies.bat new file mode 100644 index 0000000..36b23ff --- /dev/null +++ b/tools/buildsteps/windows/arm-uwp/download-dependencies.bat @@ -0,0 +1,5 @@ +@ECHO OFF + +PUSHD %~dp0\.. +CALL download-dependencies.bat win10-arm +POPD diff --git a/tools/buildsteps/windows/arm-uwp/download-msys2.bat b/tools/buildsteps/windows/arm-uwp/download-msys2.bat new file mode 100644 index 0000000..8c041ba --- /dev/null +++ b/tools/buildsteps/windows/arm-uwp/download-msys2.bat @@ -0,0 +1,5 @@ +@ECHO OFF + +PUSHD %~dp0\.. +CALL download-msys2.bat %* +POPD diff --git a/tools/buildsteps/windows/arm-uwp/make-addons.bat b/tools/buildsteps/windows/arm-uwp/make-addons.bat new file mode 100644 index 0000000..6c23384 --- /dev/null +++ b/tools/buildsteps/windows/arm-uwp/make-addons.bat @@ -0,0 +1,11 @@ +@ECHO OFF + +PUSHD %~dp0\.. +CALL vswhere.bat arm store +IF ERRORLEVEL 1 ( + ECHO ERROR! make-addons.bat: Something went wrong when calling vswhere.bat + POPD + EXIT /B 1 +) +CALL make-addons.bat win10 %* +POPD diff --git a/tools/buildsteps/windows/arm-uwp/make-mingwlibs.bat b/tools/buildsteps/windows/arm-uwp/make-mingwlibs.bat new file mode 100644 index 0000000..6a59615 --- /dev/null +++ b/tools/buildsteps/windows/arm-uwp/make-mingwlibs.bat @@ -0,0 +1,11 @@ +@ECHO OFF + +PUSHD %~dp0\.. +CALL vswhere.bat arm store +IF ERRORLEVEL 1 ( + ECHO ERROR! make-mingwlibs.bat: Something went wrong when calling vswhere.bat + POPD + EXIT /B 1 +) +CALL make-mingwlibs.bat buildArm win10 %* +POPD diff --git a/tools/buildsteps/windows/arm-uwp/prepare-env.bat b/tools/buildsteps/windows/arm-uwp/prepare-env.bat new file mode 100644 index 0000000..354a5cf --- /dev/null +++ b/tools/buildsteps/windows/arm-uwp/prepare-env.bat @@ -0,0 +1,5 @@ +@ECHO OFF + +PUSHD %~dp0\.. +CALL prepare-env.bat +POPD diff --git a/tools/buildsteps/windows/bootstrap-addons.bat b/tools/buildsteps/windows/bootstrap-addons.bat new file mode 100644 index 0000000..cbd2b44 --- /dev/null +++ b/tools/buildsteps/windows/bootstrap-addons.bat @@ -0,0 +1,91 @@ +@ECHO OFF + +SETLOCAL + +SET EXITCODE=0 + +SET clean=false +if "%1" == "clean" ( + SET clean=true +) ELSE ( + IF "%1" NEQ "" ( + SET REPOSITORY=%1 + + IF "%2" NEQ "" ( + SET REPOSITORY_REVISION=%2 + ) + ) +) + +PUSHD %~dp0\..\..\.. +SET WORKDIR=%CD% +POPD + +rem setup some paths that we need later +SET CUR_PATH=%CD% +SET BASE_PATH=%WORKDIR%\cmake +SET ADDONS_PATH=%BASE_PATH%\addons +SET ADDONS_BOOTSTRAP_PATH=%ADDONS_PATH%\bootstrap +SET BOOTSTRAP_BUILD_PATH=%ADDONS_PATH%\build\bootstrap +SET ADDONS_DEFINITION_PATH=%ADDONS_PATH%\addons + +IF %clean% == true ( + rem remove the build directory if it exists + IF EXIST "%BOOTSTRAP_BUILD_PATH%" ( + ECHO Cleaning build directory... + RMDIR "%BOOTSTRAP_BUILD_PATH%" /S /Q > NUL + ) + + rem clean the addons definition path if it exists + IF EXIST "%ADDONS_DEFINITION_PATH%" ( + ECHO Cleaning bootstrapped addons... + RMDIR "%ADDONS_DEFINITION_PATH%" /S /Q > NUL + ) + + GOTO END +) + +rem create the build directory +IF NOT EXIST "%BOOTSTRAP_BUILD_PATH%" MKDIR "%BOOTSTRAP_BUILD_PATH%" + +rem create the addons definition directory +IF NOT EXIST "%ADDONS_DEFINITION_PATH%" MKDIR "%ADDONS_DEFINITION_PATH%" + +rem go into the build directory +CD "%BOOTSTRAP_BUILD_PATH%" + +ECHO -------------------------------------------------- +ECHO Bootstrapping addons +ECHO -------------------------------------------------- + +rem execute cmake to generate makefiles processable by nmake +cmake "%ADDONS_BOOTSTRAP_PATH%" -G "NMake Makefiles" ^ + -DCMAKE_BUILD_TYPE=Release ^ + -DCMAKE_INSTALL_PREFIX=%ADDONS_DEFINITION_PATH% ^ + -DBUILD_DIR=%BOOTSTRAP_BUILD_PATH% ^ + -DREPOSITORY_TO_BUILD="%REPOSITORY%" ^ + -DREPOSITORY_REVISION="%REPOSITORY_REVISION%" +IF ERRORLEVEL 1 ( + ECHO cmake error level: %ERRORLEVEL% + GOTO ERROR +) + +rem execute nmake to prepare the buildsystem +nmake +IF ERRORLEVEL 1 ( + ECHO nmake failed with error level: %ERRORLEVEL% +) +rem everything was fine +GOTO END + +:ERROR +rem something went wrong +ECHO Failed to bootstrap addons +SET EXITCODE=1 + +:END +rem go back to the original directory +cd %CUR_PATH% + +rem exit the script with the defined exitcode +EXIT /B %EXITCODE% diff --git a/tools/buildsteps/windows/buildffmpeg.sh b/tools/buildsteps/windows/buildffmpeg.sh new file mode 100644 index 0000000..f2e72cb --- /dev/null +++ b/tools/buildsteps/windows/buildffmpeg.sh @@ -0,0 +1,129 @@ +#!/bin/bash + +[[ -f buildhelpers.sh ]] && + source buildhelpers.sh + +FFMPEG_CONFIG_FILE=/xbmc/tools/buildsteps/windows/ffmpeg_options.txt +FFMPEG_VERSION_FILE=/xbmc/tools/depends/target/ffmpeg/FFMPEG-VERSION +FFMPEG_BASE_OPTS="--disable-debug --disable-doc --enable-gpl --enable-w32threads" +FFMPEG_DEFAULT_OPTS="" +FFMPEG_TARGET_OS=mingw32 + +do_loaddeps $FFMPEG_VERSION_FILE +FFMPEGDESTDIR=$PREFIX + +do_getFFmpegConfig() { + if [[ -f "$FFMPEG_CONFIG_FILE" ]]; then + FFMPEG_OPTS_SHARED="$FFMPEG_BASE_OPTS $(cat "$FFMPEG_CONFIG_FILE" | sed -e 's:\\::g' -e 's/#.*//')" + else + FFMPEG_OPTS_SHARED="$FFMPEG_BASE_OPTS $FFMPEG_DEFAULT_OPTS" + fi + + if [ "$ARCH" == "x86_64" ]; then + FFMPEG_TARGET_OS=mingw64 + elif [ "$ARCH" == "x86" ]; then + FFMPEG_TARGET_OS=mingw32 + do_addOption "--cpu=i686" + elif [ "$ARCH" == "arm" ]; then + FFMPEG_TARGET_OS=mingw32 + do_addOption "--cpu=armv7" + fi + + # add options for static modplug + if do_checkForOptions "--enable-libmodplug"; then + do_addOption "--extra-cflags=-DMODPLUG_STATIC" + fi + + # handle gplv3 libs + if do_checkForOptions "--enable-libopencore-amrwb --enable-libopencore-amrnb \ + --enable-libvo-aacenc --enable-libvo-amrwbenc"; then + do_addOption "--enable-version3" + fi + + do_removeOption "--enable-nonfree" + do_removeOption "--enable-libfdk-aac" + do_removeOption "--enable-nvenc" + do_removeOption "--enable-libfaac" + + # remove libs that don't work with shared + do_removeOption "--enable-decklink" + do_removeOption "--enable-libutvideo" + do_removeOption "--enable-libgme" +} + +do_checkForOptions() { + local isPresent=1 + for option in "$@"; do + for option2 in $option; do + if echo "$FFMPEG_OPTS_SHARED" | grep -q -E -e "$option2"; then + isPresent=0 + fi + done + done + return $isPresent +} + +do_addOption() { + local option=${1%% *} + local shared=$2 + if ! do_checkForOptions "$option"; then + FFMPEG_OPTS_SHARED="$FFMPEG_OPTS_SHARED $option" + fi +} + +do_removeOption() { + local option=${1%% *} + FFMPEG_OPTS_SHARED=$(echo "$FFMPEG_OPTS_SHARED" | sed "s/ *$option//g") +} + +do_getFFmpegConfig + +# enable OpenSSL, because schannel has issues +do_removeOption "--enable-gnutls" +do_addOption "--disable-gnutls" +do_addOption "--enable-openssl" +do_addOption "--enable-nonfree" +do_addOption "--toolchain=msvc" +do_addOption "--disable-mediafoundation" + +if [ "$ARCH" == "x86_64" ]; then + FFMPEG_TARGET_OS=win64 +elif [ "$ARCH" = "x86" ]; then + FFMPEG_TARGET_OS=win32 +elif [ "$ARCH" = "arm" ]; then + FFMPEG_TARGET_OS=win32 +fi + +export CFLAGS="" +export CXXFLAGS="" +export LDFLAGS="" + +extra_cflags="-I$LOCALDESTDIR/include -I/depends/$TRIPLET/include -DWIN32_LEAN_AND_MEAN" +extra_ldflags="-LIBPATH:\"$LOCALDESTDIR/lib\" -LIBPATH:\"$MINGW_PREFIX/lib\" -LIBPATH:\"/depends/$TRIPLET/lib\"" +if [ $win10 == "yes" ]; then + do_addOption "--enable-cross-compile" + extra_cflags=$extra_cflags" -MD -DWINAPI_FAMILY=WINAPI_FAMILY_APP -D_WIN32_WINNT=0x0A00" + extra_ldflags=$extra_ldflags" -APPCONTAINER WindowsApp.lib" +fi + +# compile ffmpeg with debug symbols +if do_checkForOptions "--enable-debug"; then + extra_cflags=$extra_cflags" -MDd" + extra_ldflags=$extra_ldflags" -NODEFAULTLIB:libcmt" +fi + +cd $LOCALBUILDDIR + +do_clean_get $1 +[ -f config.mak ] && make distclean +do_print_status "$LIBNAME-$VERSION (${TRIPLET})" "$blue_color" "Configuring" + +[[ -z "$extra_cflags" ]] && extra_cflags=-DPTW32_STATIC_LIB +[[ -z "$extra_ldflags" ]] && extra_ldflags=-static-libgcc + +$LOCALSRCDIR/configure --target-os=$FFMPEG_TARGET_OS --prefix=$FFMPEGDESTDIR --arch=$ARCH \ + $FFMPEG_OPTS_SHARED \ + --extra-cflags="$extra_cflags" --extra-ldflags="$extra_ldflags" + +do_makelib +exit $? diff --git a/tools/buildsteps/windows/buildhelpers.sh b/tools/buildsteps/windows/buildhelpers.sh new file mode 100644 index 0000000..2a059de --- /dev/null +++ b/tools/buildsteps/windows/buildhelpers.sh @@ -0,0 +1,216 @@ +#!/bin/bash + +MAKEFLAGS="$1" +BGPROCESSFILE="$2" + +cpuCount=1 +if [[ $NUMBER_OF_PROCESSORS > 1 ]]; then + if [[ $NUMBER_OF_PROCESSORS > 4 ]]; then + cpuCount=$NUMBER_OF_PROCESSORS + else + cpuCount=`expr $NUMBER_OF_PROCESSORS + $NUMBER_OF_PROCESSORS / 2` + fi +fi +if [[ ! $cpuCount =~ ^[0-9]+$ ]]; then + cpuCount="$(($(nproc)/2))" +fi + +if which tput >/dev/null 2>&1; then + ncolors=$(tput colors) + if test -n "$ncolors" && test "$ncolors" -ge 8; then + bold_color=$(tput bold) + blue_color=$(tput setaf 4) + orange_color=$(tput setaf 3) + green_color=$(tput setaf 2) + red_color=$(tput setaf 1) + reset_color=$(tput sgr0) + fi + ncols=72 +fi + +if [[ ! -d /build/src ]]; then + mkdir /build/src +fi + +do_wget() { + local URL="$1" + local archive="$2" + + if [[ -z $archive ]]; then + wget --tries=5 --retry-connrefused --waitretry=2 --no-check-certificate -c -P /downloads/ $URL + else + wget --tries=5 --retry-connrefused --waitretry=2 --no-check-certificate -c $URL -O /downloads/$archive + fi +} + +do_makeinstall() { + make -j"$cpuCount" "$@" + make install +} + +do_makelib() { + do_print_status "$LIBNAME-$VERSION (${TRIPLET})" "$blue_color" "Compiling" + do_makeinstall $1 + if [ $? == 0 ]; then + do_print_status "$LIBNAME-$VERSION (${TRIPLET})" "$green_color" "Done" + else + do_print_status "$LIBNAME-$VERSION (${TRIPLET})" "$red_color" "Error" + fi +} + +do_print_status() { + local pad=$(printf '%0.1s' "."{1..72}) + local padlen=$((${#pad}-${#1}-${#3})) + printf '%s %*.*s%s%s%s\n' "${bold_color}$1${reset_color}" 0 "$padlen" "$pad" " [$2" "$3" "$reset_color]" +} + +do_print_progress() { + echo -e "\e]0;$* in $(get_first_subdir)\007" + echo -e "${bold_color}$* in $(get_first_subdir)${reset_color}" +} + +get_first_subdir() { + local subdir="${PWD#*build/}" + if [[ "$subdir" != "$PWD" ]]; then + subdir="${subdir%%/*}" + echo "$subdir" + else + echo "." + fi +} + +do_pkgConfig() { + local pkg=${1%% *} + local version=$2 + [[ -z "$version" ]] && version="${1##*= }" + [[ "$version" = "$1" ]] && version="" || version=" $version" + local prefix=$(pkg-config --variable=prefix --silence-errors "$1") + [[ ! -z "$prefix" ]] && prefix="$(cygpath -u "$prefix")" + if [[ "$prefix" = "$LOCALDESTDIR" || "$prefix" = "/trunk${LOCALDESTDIR}" ]]; then + do_print_status "${pkg} ${version}" "$green_color" "Up-to-date" + return 1 + else + do_print_status "${pkg} ${version}" "$red_color" "Not installed" + fi +} + +do_autoreconf() { + if [[ ! -f $LOCALSRCDIR/configure ]]; then + local CURDIR=$(pwd) + cd $LOCALSRCDIR + autoreconf -fiv + cd $CURDIR + fi +} + +do_clean() { + if [[ "$1" == "clean" ]]; then + if [ -d "$LIBBUILDDIR" ]; then + do_print_status "$LIBNAME ($TRIPLET)" "$red_color" "Removing" + rm -rf "$LIBBUILDDIR" + fi + fi +} + +do_download() { + if [ ! -d "$LOCALSRCDIR" ]; then + if [ ! -f /downloads/$ARCHIVE ]; then + do_print_status "$LIBNAME-$VERSION" "$orange_color" "Downloading" + do_wget $BASE_URL/$VERSION.tar.gz $ARCHIVE + fi + + do_print_status "$LIBNAME-$VERSION" "$blue_color" "Extracting" + mkdir $LOCALSRCDIR && cd $LOCALSRCDIR + tar -xaf /downloads/$ARCHIVE --strip 1 + fi + # applying patches + local patches=(/xbmc/tools/buildsteps/windows/patches/*-$LIBNAME-*.patch) + for patch in ${patches[@]}; do + echo "Applying patch ${patch}" + if [[ -f $patch ]]; then + patch -p1 -d $LOCALSRCDIR -i $patch -N -r - + fi + done +} + +do_loaddeps() { + local file="$1" + LIBNAME=$(grep "LIBNAME=" $file | sed 's/LIBNAME=//g;s/#.*$//g;/^$/d') + BASE_URL=$(grep "BASE_URL=" $file | sed 's/BASE_URL=//g;s/#.*$//g;/^$/d') + VERSION=$(grep "VERSION=" $file | sed 's/VERSION=//g;s/#.*$//g;/^$/d') + GITREV=$(git ls-remote $BASE_URL $VERSION | awk '{print substr($1, 1, 10)}') + if [[ -z "$GITREV" ]]; then + ARCHIVE=$LIBNAME-$(echo "${VERSION}" | sed 's/\//-/g').tar.gz + else + ARCHIVE=$LIBNAME-$GITREV.tar.gz + fi + BASE_URL=$BASE_URL/archive + local libsrcdir=$LIBNAME-$VERSION + if [[ ! -z "$GITREV" ]]; then + libsrcdir=$LIBNAME-$GITREV + fi + LOCALSRCDIR=$LOCALBUILDDIR/src/$libsrcdir + LIBBUILDDIR=$LOCALBUILDDIR/$LIBNAME-$TRIPLET +} + +do_clean_get() { + do_clean $1 + do_download + + if [[ ! -d "$LIBBUILDDIR" ]]; then + mkdir "$LIBBUILDDIR" + fi + cd "$LIBBUILDDIR" +} + + +PATH_CHANGE_REV_FILENAME=".last_success_revision" + +#hash a dir based on the git revision and $TRIPLET +#params paths to be hashed +function getBuildHash () +{ + local hashStr + hashStr="$(git rev-list HEAD --max-count=1 -- $@)" + hashStr="$hashStr $@ $TRIPLET" + echo $hashStr +} + +#param1 path to be checked for changes +function pathChanged () +{ + local ret + local checkPath + ret="0" + #no optims in release builds! + if [ "$Configuration" == "Release" ] + then + echo "1" + return + fi + + checkPath="$1" + shift 1 + if [ -e $checkPath/$PATH_CHANGE_REV_FILENAME ] + then + if [ "$(cat $checkPath/$PATH_CHANGE_REV_FILENAME)" != "$(getBuildHash $checkPath $@)" ] + then + ret="1" + fi + else + ret="1" + fi + + echo $ret +} + +#param1 path to be tagged with hash +function tagSuccessFulBuild () +{ + local pathToTag + pathToTag="$1" + shift 1 + # tag last successful build with revisions of the given dir + # needs to match the checks in function getBuildHash + echo "$(getBuildHash $pathToTag $@)" > $pathToTag/$PATH_CHANGE_REV_FILENAME +} diff --git a/tools/buildsteps/windows/download-dependencies.bat b/tools/buildsteps/windows/download-dependencies.bat new file mode 100644 index 0000000..0a129fd --- /dev/null +++ b/tools/buildsteps/windows/download-dependencies.bat @@ -0,0 +1,72 @@ +@ECHO OFF + +SETLOCAL + +PUSHD %~dp0\..\..\.. +SET WORKSPACE=%CD% +POPD + +SET TARGETPLATFORM=%1 +SET NATIVEPLATFORM=%2 + +IF "%TARGETPLATFORM%" == "" SET TARGETPLATFORM=win32 +IF "%NATIVEPLATFORM%" == "" SET NATIVEPLATFORM=win32 + +ECHO TARGETPLATFORM: %TARGETPLATFORM% +ECHO NATIVEPLATFORM: %NATIVEPLATFORM% + +REM If KODI_MIRROR is not set externally to this script, set it to the default mirror URL +IF "%KODI_MIRROR%" == "" SET KODI_MIRROR=http://mirrors.kodi.tv +echo Downloading from mirror %KODI_MIRROR% + +REM Locate the BuildDependencies directory, based on the path of this script +SET BUILD_DEPS_PATH=%WORKSPACE%\project\BuildDependencies +SET APP_PATH=%WORKSPACE%\project\BuildDependencies\%TARGETPLATFORM% +SET TMP_PATH=%BUILD_DEPS_PATH%\scripts\tmp + +REM Change to the BuildDependencies directory, if we're not there already +PUSHD %BUILD_DEPS_PATH% + +REM Can't run rmdir and md back to back. access denied error otherwise. +IF EXIST %TMP_PATH% rmdir %TMP_PATH% /S /Q + +SET DL_PATH="%BUILD_DEPS_PATH%\downloads" +SET WGET=%BUILD_DEPS_PATH%\bin\wget +SET ZIP=%BUILD_DEPS_PATH%\..\Win32BuildSetup\tools\7z\7za + +IF NOT EXIST %DL_PATH% md %DL_PATH% + +md %TMP_PATH% + +cd scripts + +SET FORMED_OK_FLAG=%TMP_PATH%\got-all-formed-packages +REM Trick to preserve console title +start /b /wait cmd.exe /c get_formed.cmd +IF NOT EXIST %FORMED_OK_FLAG% ( + ECHO ERROR: Not all formed packages are ready! + ECHO. + ECHO I tried to get the packages from %KODI_MIRROR%; + ECHO if this download mirror seems to be having problems, try choosing another from + ECHO the list on http://mirrors.kodi.tv/timestamp.txt?mirrorlist, and setting %%KODI_MIRROR%% to + ECHO point to it, like so: + ECHO C:\^> SET KODI_MIRROR=http://example.com/pub/xbmc/ + ECHO. + ECHO Then, rerun this script. + + REM Restore the previous current directory + POPD + + ENDLOCAL + + EXIT /B 101 +) + +rmdir %TMP_PATH% /S /Q + +REM Restore the previous current directory +POPD + +ENDLOCAL + +EXIT /B 0 diff --git a/tools/buildsteps/windows/download-msys2.bat b/tools/buildsteps/windows/download-msys2.bat new file mode 100644 index 0000000..34c3472 --- /dev/null +++ b/tools/buildsteps/windows/download-msys2.bat @@ -0,0 +1,406 @@ +::------------------------------------------------------------------------------------- +:: LICENSE ------------------------------------------------------------------------- +::------------------------------------------------------------------------------------- +:: This Windows Batchscript is for setup a compiler environment for building ffmpeg and other media tools under Windows. +:: +:: Copyright (C) 2013 jb_alvarado +:: +:: 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 3 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, see <http://www.gnu.org/licenses/>. +::------------------------------------------------------------------------------------- + +@echo off +title msys2 + +PUSHD %~dp0\..\..\.. +SET WORKSPACE=%CD% +POPD + +set msysver=20210725 +set msys2=msys64 +set instdir=%WORKSPACE%\project\BuildDependencies +set msyspackages=diffutils gcc make patch perl tar yasm +set gaspreprocurl=https://github.com/FFmpeg/gas-preprocessor/archive/master.tar.gz +set usemirror=yes +set opt=mintty + +:: if KODI_MIRROR is not set externally to this script, set it to the default mirror URL +if "%KODI_MIRROR%"=="" set KODI_MIRROR=http://mirrors.kodi.tv +if "%usemirror%"=="yes" ( + echo ------------------------------------------------------------------------------- + echo. Downloading will be performed from mirror %KODI_MIRROR% + echo ------------------------------------------------------------------------------- + set MSYS_MIRROR=%KODI_MIRROR%/build-deps/win32/msys2 +) + +set downloaddir=%instdir%\downloads2 +set unpack_exe=%instdir%\..\Win32BuildSetup\tools\7z\7za.exe + +for %%b in (%*) do ( + if %%b==sh (set opt=sh) +) + +:: use 32bit msys2 on x86 machine +if %PROCESSOR_ARCHITECTURE%=="x86" set msys2=msys32 +if %msys2%==msys32 (set arch=i686) else (set arch=x86_64) +set msysfile=msys2-base-%arch%-%msysver%.tar.xz +if %opt%==mintty ( + set sh=%instdir%\%msys2%\usr\bin\mintty.exe -d -i /msys2.ico /usr/bin/bash +) else ( + set sh=%instdir%\%msys2%\usr\bin\sh.exe +) + +::------------------------------------------------------------------ +::download and install basic msys2 system: +::------------------------------------------------------------------ +if exist "%instdir%\%msys2%\msys2_shell.cmd" GOTO minttySettings + if not exist %downloaddir% mkdir %downloaddir% + +:download +if exist "%downloaddir%\%msysfile%" ( + setlocal EnableDelayedExpansion + for /F "tokens=*" %%A in ("%downloaddir%\%msysfile%") do set fileSize=%%~zA + if !fileSize!==0 del %downloaddir%\%msysfile% + endlocal + ) + +if exist "%downloaddir%\%msysfile%" GOTO unpack + echo ------------------------------------------------------------------------------- + echo.- Download msys2 basic system (Kodi mirrors: %usemirror%) + echo ------------------------------------------------------------------------------- + + set msysurl=http://sourceforge.net/projects/msys2/files/Base/%arch%/%msysfile%/download + if %usemirror%==yes ( + ::download msys2 from our mirror + set msysurl=%MSYS_MIRROR%/%msysfile% + ) + %instdir%\bin\wget --tries=20 --retry-connrefused --waitretry=2 --no-check-certificate -c -O %downloaddir%\%msysfile% %msysurl% + if errorlevel == 1 ( + if exist "%downloaddir%\%msysfile%" del %downloaddir%\%msysfile% + if %usemirror%==yes ( + set usemirror=no + goto download + ) + echo ERROR: Unable to download msys2! + exit /B 1 + ) + +:unpack +if exist "%downloaddir%\%msysfile%" ( + echo ------------------------------------------------------------------------------- + echo.- Installing msys2 basic system + echo ------------------------------------------------------------------------------- + %unpack_exe% x %downloaddir%\%msysfile% -so 2>NUL | %unpack_exe% x -aoa -si -ttar -o%instdir% >NUL 2>NUL + ) + +if not exist %instdir%\%msys2%\usr\bin\msys-2.0.dll ( + echo ------------------------------------------------------------------------------- + echo.- Installing msys2 basic system failed, + echo ------------------------------------------------------------------------------- + exit /B 1 + ) + +:minttySettings +if exist "%instdir%\%msys2%\home\%USERNAME%\.minttyrc" GOTO updatemirrors +if not exist "%instdir%\%msys2%\home\%USERNAME%" mkdir "%instdir%\%msys2%\home\%USERNAME%" + ( + echo.BoldAsFont=no + echo.BackgroundColour=57,57,57 + echo.ForegroundColour=221,221,221 + echo.Transparency=medium + echo.FontHeight=^9 + echo.FontSmoothing=full + echo.AllowBlinking=yes + echo.Columns=120 + echo.Rows=30 + echo.Term=xterm-256color + echo.CursorType=block + echo.ClicksPlaceCursor=yes + echo.Black=38,39,41 + echo.Red=249,38,113 + echo.Green=166,226,46 + echo.Yellow=253,151,31 + echo.Blue=102,217,239 + echo.Magenta=158,111,254 + echo.Cyan=94,113,117 + echo.White=248,248,242 + echo.BoldBlack=85,68,68 + echo.BoldRed=249,38,113 + echo.BoldGreen=166,226,46 + echo.BoldYellow=253,151,31 + echo.BoldBlue=102,217,239 + echo.BoldMagenta=158,111,254 + echo.BoldCyan=163,186,191 + echo.BoldWhite=248,248,242 + )>>"%instdir%\%msys2%\home\%USERNAME%\.minttyrc" + +:updatemirrors +if not "%usemirror%"=="yes" GOTO rebase + echo.------------------------------------------------------------------------------- + echo.update pacman mirrors + echo.------------------------------------------------------------------------------- + setlocal EnableDelayedExpansion + + for %%f in (msys,mingw32,mingw64) do ( + set filename=%instdir%\%msys2%\etc\pacman.d\mirrorlist.%%f + set oldfile=!filename!.old + if not exist !oldfile! if exist !filename! ( + set mirror=%MSYS_MIRROR%/repos/%%f + if %%f==msys set mirror=!mirror!2/$arch + move !filename! !oldfile!>nul + for /F "usebackq delims=" %%a in (!oldfile!) do ( + echo %%a | find /i "server = http://repo.msys2.org/">nul && ( + echo.Server = !mirror! + )>>!filename! + echo %%a>>!filename! + ) + ) + ) + endlocal + +:rebase +if %msys2%==msys32 ( + echo.------------------------------------------------------------------------------- + echo.rebase msys32 system + echo.------------------------------------------------------------------------------- + call %instdir%\msys32\autorebase.bat + ) + +:preparedirs +if not exist %instdir%\build mkdir %instdir%\build +if not exist %instdir%\downloads2 mkdir %instdir%\downloads2 +if not exist %instdir%\locals mkdir %instdir%\locals +if not exist %instdir%\locals\win32 mkdir %instdir%\locals\win32 +if not exist %instdir%\locals\x64 mkdir %instdir%\locals\x64 + +if not exist %instdir%\locals\win32\share ( + echo.------------------------------------------------------------------------------- + echo.create local win32 folders + echo.------------------------------------------------------------------------------- + mkdir %instdir%\locals\win32\bin + mkdir %instdir%\locals\win32\etc + mkdir %instdir%\locals\win32\include + mkdir %instdir%\locals\win32\lib + mkdir %instdir%\locals\win32\lib\pkgconfig + mkdir %instdir%\locals\win32\share + ) + +if not exist %instdir%\locals\x64\share ( + echo.------------------------------------------------------------------------------- + echo.create local x64 folders + echo.------------------------------------------------------------------------------- + mkdir %instdir%\locals\x64\bin + mkdir %instdir%\locals\x64\etc + mkdir %instdir%\locals\x64\include + mkdir %instdir%\locals\x64\lib + mkdir %instdir%\locals\x64\lib\pkgconfig + mkdir %instdir%\locals\x64\share + ) + +if not exist %instdir%\%msys2%\etc\fstab. GOTO writeFstab +for /f "tokens=2 delims=/" %%a in ('findstr /i xbmc %instdir%\%msys2%\etc\fstab.') do set searchRes=%%a +if "%searchRes%"=="xbmc" GOTO installbase + +:writeFstab +echo ------------------------------------------------------------------------------- +echo.- write fstab mount file +echo ------------------------------------------------------------------------------- +set cygdrive=no +if exist %instdir%\%msys2%\etc\fstab. ( + for /f %%b in ('findstr /i binary %instdir%\%msys2%\etc\fstab.') do set cygdrive=yes + ) +if "%cygdrive%"=="no" echo.none / cygdrive binary,posix=0,noacl,user 0 ^0>>%instdir%\%msys2%\etc\fstab. +( + echo. + echo.%instdir%\build\ /build + echo.%instdir%\downloads\ /downloads + echo.%instdir%\locals\win32\ /local32 + echo.%instdir%\locals\x64\ /local64 + echo.%instdir%\%msys2%\mingw32\ /mingw32 + echo.%instdir%\%msys2%\mingw64\ /mingw64 + echo.%instdir%\downloads2\ /var/cache/pacman/pkg + echo.%instdir%\win32\ /depends/win32 + echo.%instdir%\x64\ /depends/x64 + echo.%instdir%\win10-arm\ /depends/win10-arm + echo.%instdir%\win10-win32\ /depends/win10-win32 + echo.%instdir%\win10-x64\ /depends/win10-x64 + echo.%instdir%\..\..\ /xbmc +)>>%instdir%\%msys2%\etc\fstab. + +:installbase +if exist "%instdir%\%msys2%\etc\pac-base-old.pk" del "%instdir%\%msys2%\etc\pac-base-old.pk" +if exist "%instdir%\%msys2%\etc\pac-base-new.pk" ren "%instdir%\%msys2%\etc\pac-base-new.pk" pac-base-old.pk + +for %%i in (%msyspackages%) do echo.%%i>>%instdir%\%msys2%\etc\pac-base-new.pk + +if exist %instdir%\%msys2%\usr\bin\make.exe GOTO rebase2 + echo.------------------------------------------------------------------------------- + echo.install msys2 base system + echo.------------------------------------------------------------------------------- + if exist %instdir%\pacman.sh del %instdir%\pacman.sh + ( + echo.echo -ne "\033]0;install base system\007" + echo.pacman --noconfirm -S $(cat /etc/pac-base-new.pk ^| sed -e 's#\\##'^) + echo.sleep ^3 + echo.exit + )>>%instdir%\pacman.sh + %sh% --login %instdir%\pacman.sh & + del %instdir%\pacman.sh + + for %%i in (%instdir%\%msys2%\usr\ssl\cert.pem) do ( + if %%~zi==0 ( + echo.update-ca-trust>>cert.sh + echo.sleep ^3>>cert.sh + echo.exit>>cert.sh + %sh% --login %instdir%\cert.sh + del cert.sh + ) + ) + +:rebase2 +if %msys2%==msys32 ( + echo.------------------------------------------------------------------------------- + echo.second rebase msys32 system + echo.------------------------------------------------------------------------------- + call %instdir%\msys32\autorebase.bat + ) + +::------------------------------------------------------------------ +:: write config profiles: +::------------------------------------------------------------------ + +:writeProfile32 +if exist %instdir%\locals\win32\etc\profile.local GOTO writeProfile64 + echo ------------------------------------------------------------------------------- + echo.- write profile for 32 bit compiling + echo ------------------------------------------------------------------------------- + ( + echo.# + echo.# /local32/etc/profile.local + echo.# + echo. + echo.MSYSTEM=MINGW32 + echo. + echo.alias dir='ls -la --color=auto' + echo.alias ls='ls --color=auto' + echo.export CC=gcc + echo.export python=/usr/bin/python + echo. + echo.MSYS2_PATH="/usr/local/bin:/usr/bin" + echo.MANPATH="/usr/share/man:/mingw32/share/man:/local32/man:/local32/share/man" + echo.INFOPATH="/usr/local/info:/usr/share/info:/usr/info:/mingw32/share/info" + echo.MINGW_PREFIX="/mingw32" + echo.MINGW_CHOST="i686-w64-mingw32" + echo.export MSYSTEM MINGW_PREFIX MINGW_CHOST + echo. + echo.DXSDK_DIR="/mingw32/i686-w64-mingw32" + echo.ACLOCAL_PATH="/mingw32/share/aclocal:/usr/share/aclocal" + echo.PKG_CONFIG_LOCAL_PATH="/local32/lib/pkgconfig" + echo.PKG_CONFIG_PATH="/local32/lib/pkgconfig:/mingw32/lib/pkgconfig" + echo.CPPFLAGS="-I/local32/include -D_FORTIFY_SOURCE=2" + echo.CFLAGS="-I/local32/include -mms-bitfields -mthreads -mtune=generic -pipe" + echo.CXXFLAGS="-I/local32/include -mms-bitfields -mthreads -mtune=generic -pipe" + echo.LDFLAGS="-L/local32/lib -mthreads -pipe" + echo.export DXSDK_DIR ACLOCAL_PATH PKG_CONFIG_PATH PKG_CONFIG_LOCAL_PATH CPPFLAGS CFLAGS CXXFLAGS LDFLAGS MSYSTEM + echo. + echo.PYTHONHOME=/usr + echo.PYTHONPATH="/usr/lib/python2.7:/usr/lib/python2.7/Tools/Scripts" + echo. + echo.PATH=".:/local32/bin:/mingw32/bin:${MSYS2_PATH}:${INFOPATH}:${PYTHONHOME}:${PYTHONPATH}:${PATH}" + echo.PS1='\[\033[32m\]\u@\h \[\e[33m\]\w\[\e[0m\]\n\$ ' + echo.export PATH PS1 + echo. + echo.# package build directory + echo.LOCALBUILDDIR=/build + echo.# package installation prefix + echo.LOCALDESTDIR=/local32 + echo.export LOCALBUILDDIR LOCALDESTDIR + )>>%instdir%\locals\win32\etc\profile.local + ) + +:writeProfile64 +if exist %instdir%\locals\x64\etc\profile.local GOTO loadGasPreproc + echo ------------------------------------------------------------------------------- + echo.- write profile for 64 bit compiling + echo ------------------------------------------------------------------------------- + ( + echo.# + echo.# /local64/etc/profile.local + echo.# + echo. + echo.MSYSTEM=MINGW64 + echo. + echo.alias dir='ls -la --color=auto' + echo.alias ls='ls --color=auto' + echo.export CC=gcc + echo.export python=/usr/bin/python + echo. + echo.MSYS2_PATH="/usr/local/bin:/usr/bin" + echo.MANPATH="/usr/share/man:/mingw64/share/man:/local64/man:/local64/share/man" + echo.INFOPATH="/usr/local/info:/usr/share/info:/usr/info:/mingw64/share/info" + echo.MINGW_PREFIX="/mingw64" + echo.MINGW_CHOST="x86_64-w64-mingw32" + echo.export MSYSTEM MINGW_PREFIX MINGW_CHOST + echo. + echo.DXSDK_DIR="/mingw64/x86_64-w64-mingw32" + echo.ACLOCAL_PATH="/mingw64/share/aclocal:/usr/share/aclocal" + echo.PKG_CONFIG_LOCAL_PATH="/local64/lib/pkgconfig" + echo.PKG_CONFIG_PATH="/local64/lib/pkgconfig:/mingw64/lib/pkgconfig" + echo.CPPFLAGS="-I/local64/include -D_FORTIFY_SOURCE=2" + echo.CFLAGS="-I/local64/include -mms-bitfields -mthreads -mtune=generic -pipe" + echo.CXXFLAGS="-I/local64/include -mms-bitfields -mthreads -mtune=generic -pipe" + echo.LDFLAGS="-L/local64/lib -pipe" + echo.export DXSDK_DIR ACLOCAL_PATH PKG_CONFIG_PATH PKG_CONFIG_LOCAL_PATH CPPFLAGS CFLAGS CXXFLAGS LDFLAGS MSYSTEM + echo. + echo.PYTHONHOME=/usr + echo.PYTHONPATH="/usr/lib/python2.7:/usr/lib/python2.7/Tools/Scripts" + echo. + echo.PATH=".:/local64/bin:/mingw64/bin:${MSYS2_PATH}:${INFOPATH}:${PYTHONHOME}:${PYTHONPATH}:${PATH}" + echo.PS1='\[\033[32m\]\u@\h \[\e[33m\]\w\[\e[0m\]\n\$ ' + echo.export PATH PS1 + echo. + echo.# package build directory + echo.LOCALBUILDDIR=/build + echo.# package installation prefix + echo.LOCALDESTDIR=/local64 + echo.export LOCALBUILDDIR LOCALDESTDIR + )>>%instdir%\locals\x64\etc\profile.local + ) + +:loadGasPreproc +set gaspreprocfile=gas-preprocessor.tar.gz +if exist %downloaddir%\%gaspreprocfile% goto extractGasPreproc + echo ------------------------------------------------------------------------------- + echo.- Downloading gas-preprocessor.pl + echo ------------------------------------------------------------------------------- + %instdir%\bin\wget --tries=20 --retry-connrefused --waitretry=2 --no-check-certificate -c -O %downloaddir%\%gaspreprocfile% %gaspreprocurl% + +:extractGasPreproc +if exist %instdir%\%msys2%\usr\bin\gas-preprocessor.pl goto end + echo ------------------------------------------------------------------------------- + echo.- Installing gas-preprocessor.pl + echo ------------------------------------------------------------------------------- + %unpack_exe% x %downloaddir%\%gaspreprocfile% -so 2>NUL | %unpack_exe% e -si -ttar -o%instdir%\%msys2%\usr\bin *.pl -r >NUL 2>NUL + +:end +cd %instdir% +IF ERRORLEVEL == 1 ( + ECHO Something goes wrong... + exit /B 1 + ) + +echo.------------------------------------------------------------------------------- +echo.install msys2 system done +echo.------------------------------------------------------------------------------- + +@echo on diff --git a/tools/buildsteps/windows/ffmpeg_options.txt b/tools/buildsteps/windows/ffmpeg_options.txt new file mode 100644 index 0000000..fbaf417 --- /dev/null +++ b/tools/buildsteps/windows/ffmpeg_options.txt @@ -0,0 +1,19 @@ +--disable-avdevice +--disable-crystalhd +--disable-cuda +--disable-cuvid +--disable-devices +--disable-dxva2 +--disable-gnutls +--disable-nvenc +--disable-openssl +--disable-programs +--disable-shared +--enable-encoder=ac3,aac,wmav2,png,mjpeg +--enable-muxer=spdif,adts,asf,ipod +--enable-postproc +--enable-protocol=http +--enable-runtime-cpudetect +--enable-static +--enable-zlib +--enable-libdav1d diff --git a/tools/buildsteps/windows/getbranch.bat b/tools/buildsteps/windows/getbranch.bat new file mode 100644 index 0000000..a078c05 --- /dev/null +++ b/tools/buildsteps/windows/getbranch.bat @@ -0,0 +1,56 @@ +@echo off +rem this gets the current branch from either the branchname (if we attached) or +rem by using scientific branch fetching algorithms [tm] git is in detached HEAD state +rem result will be in env var %BRANCH% +SET BRANCH= +SET DETACHED=1 +:: detect detached head +git symbolic-ref HEAD >nul 2>&1 +IF %ERRORLEVEL%==0 ( + SET DETACHED=0 +) +rem find the branchname - if current branch is a pr we have to take this into account aswell +rem (would be refs/heads/pr/number/head then) +rem normal branch would be refs/heads/branchname +IF %DETACHED%==0 ( + FOR /f %%a IN ('git symbolic-ref HEAD') DO SET BRANCH=%%a + SETLOCAL EnableDelayedExpansion + SET BRANCH=!BRANCH:*/=! + SETLOCAL DisableDelayedExpansion + GOTO branchfound +) + +:: when building with jenkins there's no branch. First git command gets the branches +:: and then prefers a non pr branch if one exists +:: (this mimics what the linux side does via sed and head -n1 +:: but is empty in a normal build environment. Second git command gets the branch there. +SET command=git branch -r --points-at HEAD +%command% >nul 2>&1 +IF NOT %ERRORLEVEL%==0 ( + SET command=git branch -r --contains HEAD +) + +%command% | findstr "%GITHUB_REPO%\/" | findstr /V "%GITHUB_REPO%\/pr\/" >nul +IF %ERRORLEVEL%==0 ( + FOR /f %%a IN ('%%command%% ^| findstr "%GITHUB_REPO%\/" ^| findstr /V "%GITHUB_REPO%\/pr\/"') DO ( + SET BRANCH=%%a + GOTO branchfound + ) +) ELSE ( + FOR /f %%a IN ('%%command%% ^| findstr "%GITHUB_REPO%\/"') DO ( + SET BRANCH=%%a + GOTO branchfound + ) +) + +:branchfound +SETLOCAL EnableDelayedExpansion +IF NOT "!BRANCH!"=="" ( + :: BRANCH is now (head|GITHUB_REPO)/(branchname|pr/number/(head|merge)) + SET BRANCH=!BRANCH:/pr/=/PR! + SET BRANCH=!BRANCH:*/=! + SET BRANCH=!BRANCH:/=-! +) +SETLOCAL DisableDelayedExpansion + +ECHO.%BRANCH% diff --git a/tools/buildsteps/windows/make-addons.bat b/tools/buildsteps/windows/make-addons.bat new file mode 100644 index 0000000..b8e0ac5 --- /dev/null +++ b/tools/buildsteps/windows/make-addons.bat @@ -0,0 +1,169 @@ +@ECHO OFF + +SET EXITCODE=0 + +SET install=false +SET clean=false +SET package=false +SET addon= +SET store= + +SETLOCAL EnableDelayedExpansion +FOR %%b IN (%*) DO ( + IF %%~b == install ( + SET install=true + ) ELSE ( IF %%~b == clean ( + SET clean=true + ) ELSE ( IF %%~b == package ( + SET package=true + ) ELSE ( IF %%~b == win10 ( + SET store=store + ) ELSE ( + SET addon=!addon! %%~b + )))) +) +SETLOCAL DisableDelayedExpansion + +PUSHD %~dp0\..\..\.. +SET WORKDIR=%CD% +POPD + +rem setup some paths that we need later +SET CUR_PATH=%CD% +SET BASE_PATH=%WORKDIR%\cmake +SET SCRIPTS_PATH=%BASE_PATH%\scripts\windows%store% +SET ADDONS_PATH=%BASE_PATH%\addons +SET ADDON_DEPENDS_PATH=%ADDONS_PATH%\output +SET ADDONS_BUILD_PATH=%ADDONS_PATH%\build + +SET ADDONS_SUCCESS_FILE=%ADDONS_PATH%\.success +SET ADDONS_FAILURE_FILE=%ADDONS_PATH%\.failure + +SET ERRORFILE=%ADDONS_PATH%\make-addons.error + +rem remove the success and failure files from a previous build +DEL /F %ADDONS_SUCCESS_FILE% > NUL 2>&1 +DEL /F %ADDONS_FAILURE_FILE% > NUL 2>&1 + +IF %clean% == true ( + rem remove the build directory if it exists + IF EXIST "%ADDONS_BUILD_PATH%" ( + ECHO Cleaning build directory... + RMDIR "%ADDONS_BUILD_PATH%" /S /Q > NUL + ) + + rem remove the build directory if it exists + IF EXIST "%ADDON_DEPENDS_PATH%" ( + ECHO Cleaning dependencies... + RMDIR "%ADDON_DEPENDS_PATH%" /S /Q > NUL + ) + + GOTO END +) + +rem create the depends directory +IF NOT EXIST "%ADDON_DEPENDS_PATH%" MKDIR "%ADDON_DEPENDS_PATH%" + +rem create the build directory +IF NOT EXIST "%ADDONS_BUILD_PATH%" MKDIR "%ADDONS_BUILD_PATH%" + +rem go into the build directory +CD "%ADDONS_BUILD_PATH%" + +rem determine the proper install path for the built addons +IF %install% == true ( + SET ADDONS_INSTALL_PATH=%WORKSPACE%\addons +) ELSE ( + SET ADDONS_INSTALL_PATH=%WORKDIR%\project\Win32BuildSetup\BUILD_WIN32\addons +) + +ECHO -------------------------------------------------- +ECHO Building addons +ECHO -------------------------------------------------- + +IF "%addon%" NEQ "" ( + SET CMAKE_EXTRA=%CMAKE_EXTRA% -DADDONS_TO_BUILD="%addon%" +) + +IF "%ADDON_SRC_PREFIX%" NEQ "" ( + SET CMAKE_EXTRA=%CMAKE_EXTRA% -DADDON_SRC_PREFIX=%ADDON_SRC_PREFIX% +) + +IF "%ADDONS_DEFINITION_DIR" NEQ "" ( + SET CMAKE_EXTRA=%CMAKE_EXTRA% -DADDONS_DEFINITION_DIR=%ADDONS_DEFINITION_DIR% +) + +IF "%store%" NEQ "" ( + SET CMAKE_EXTRA=%CMAKE_EXTRA% -DCMAKE_SYSTEM_NAME=WindowsStore -DCMAKE_SYSTEM_VERSION=%UCRTVersion% +) + +rem execute cmake to generate makefiles processable by nmake +cmake "%ADDONS_PATH%" -G "NMake Makefiles" ^ + -DCMAKE_BUILD_TYPE=Release ^ + -DCMAKE_USER_MAKE_RULES_OVERRIDE="%SCRIPTS_PATH%/CFlagOverrides.cmake" ^ + -DCMAKE_USER_MAKE_RULES_OVERRIDE_CXX="%SCRIPTS_PATH%/CXXFlagOverrides.cmake" ^ + -DCMAKE_INSTALL_PREFIX=%ADDONS_INSTALL_PATH% ^ + -DCMAKE_SOURCE_DIR=%WORKDIR% ^ + -DBUILD_DIR=%ADDONS_BUILD_PATH% ^ + -DADDON_DEPENDS_PATH=%ADDON_DEPENDS_PATH% ^ + -DPACKAGE_ZIP=ON ^ + %CMAKE_EXTRA% + +IF ERRORLEVEL 1 ( + ECHO cmake error level: %ERRORLEVEL% > %ERRORFILE% + GOTO ERROR +) + +rem get the list of addons that can actually be built +SET ADDONS_TO_MAKE= +SETLOCAL EnableDelayedExpansion +FOR /f "delims=" %%i IN ('cmake --build . --target supported_addons') DO ( + SET line="%%i" + SET addons=!line:ALL_ADDONS_BUILDING=! + IF NOT "!addons!" == "!line!" ( + SET ADDONS_TO_MAKE=!addons:~3,-1! + ) +) +SETLOCAL DisableDelayedExpansion + +rem loop over all addons to build +FOR %%a IN (%ADDONS_TO_MAKE%) DO ( + ECHO Building %%a... + rem execute cmake to build the addons + cmake --build . --target %%a + IF ERRORLEVEL 1 ( + ECHO nmake %%a error level: %ERRORLEVEL% > %ERRORFILE% + ECHO %%a >> %ADDONS_FAILURE_FILE% + ) ELSE ( + if %package% == true ( + nmake package-%%a + IF ERRORLEVEL 1 ( + ECHO nmake package-%%a error level: %ERRORLEVEL% > %ERRORFILE% + ECHO %%a >> %ADDONS_FAILURE_FILE% + ) ELSE ( + ECHO %%a >> %ADDONS_SUCCESS_FILE% + ) + ) ELSE ( + ECHO %%a >> %ADDONS_SUCCESS_FILE% + ) + ) +) + +rem everything was fine +GOTO END + +:ERROR +rem something went wrong +FOR %%a IN (%ADDONS_TO_BUILD%) DO ( + ECHO %%a >> %ADDONS_FAILURE_FILE% +) +ECHO Failed to build addons +ECHO See %ERRORFILE% for more details +SET EXITCODE=1 + +:END +rem go back to the original directory +cd %CUR_PATH% + +rem exit the script with the defined exitcode +EXIT /B %EXITCODE% diff --git a/tools/buildsteps/windows/make-mingwlibs.bat b/tools/buildsteps/windows/make-mingwlibs.bat new file mode 100644 index 0000000..62c41f0 --- /dev/null +++ b/tools/buildsteps/windows/make-mingwlibs.bat @@ -0,0 +1,88 @@ +@ECHO OFF + +rem batch file to compile mingw libs via BuildSetup +PUSHD %~dp0\..\..\.. +SET WORKDIR=%CD% +POPD + +REM recreates clean ffmpeg build dir +SET BUILD_DIR=%WORKDIR%\project\BuildDependencies\build +IF EXIST %BUILD_DIR% rmdir %BUILD_DIR% /S /Q +IF NOT EXIST %BUILD_DIR% mkdir %BUILD_DIR% + +SET PROMPTLEVEL=prompt +SET BUILDMODE=clean +SET opt=mintty +SET build32=yes +SET build64=no +SET buildArm=no +SET vcarch=x86 +SET msys2=msys64 +SET win10=no +SET TARGETPLATFORM=win32 + +FOR %%b in (%*) DO ( + IF %%b==noprompt SET PROMPTLEVEL=noprompt + IF %%b==clean SET BUILDMODE=clean + IF %%b==noclean SET BUILDMODE=noclean + IF %%b==sh SET opt=sh + IF %%b==build64 ( + SET build64=yes + SET build32=no + SET buildArm=no + SET vcarch=amd64 + SET TARGETPLATFORM=x64 + ) + IF %%b==buildArm ( + SET build64=no + SET build32=no + SET buildArm=yes + SET vcarch=arm + SET TARGETPLATFORM=arm + ) + IF %%b==win10 ( + SET win10=yes + ) +) +:: Export full current PATH from environment into MSYS2 +set MSYS2_PATH_TYPE=inherit + +REM Prepend the msys and mingw paths onto %PATH% +SET MSYS_INSTALL_PATH=%WORKDIR%\project\BuildDependencies\msys +SET PATH=%MSYS_INSTALL_PATH%\mingw\bin;%MSYS_INSTALL_PATH%\bin;%PATH% +SET ERRORFILE=%WORKDIR%\project\Win32BuildSetup\errormingw +SET BS_DIR=%WORKDIR%\project\Win32BuildSetup + +IF EXIST %ERRORFILE% del %ERRORFILE% > NUL + +rem compiles a bunch of mingw libs and not more +IF %opt%==sh ( + IF EXIST %WORKDIR%\project\BuildDependencies\%msys2%\usr\bin\sh.exe ( + ECHO starting sh shell + %WORKDIR%\project\BuildDependencies\%msys2%\usr\bin\sh.exe --login -i /xbmc/tools/buildsteps/windows/make-mingwlibs.sh --prompt=%PROMPTLEVEL% --mode=%BUILDMODE% --build32=%build32% --build64=%build64% --buildArm=%buildArm% --win10=%win10% + GOTO END + ) ELSE ( + GOTO ENDWITHERROR + ) +) +IF EXIST %WORKDIR%\project\BuildDependencies\%msys2%\usr\bin\mintty.exe ( + ECHO starting mintty shell + %WORKDIR%\project\BuildDependencies\%msys2%\usr\bin\mintty.exe -d -i /msys2.ico /usr/bin/bash --login /xbmc/tools/buildsteps/windows/make-mingwlibs.sh --prompt=%PROMPTLEVEL% --mode=%BUILDMODE% --build32=%build32% --build64=%build64% --buildArm=%buildArm% --win10=%win10% + GOTO END +) +GOTO ENDWITHERROR + +:ENDWITHERROR + ECHO msys environment not found + ECHO bla>%ERRORFILE% + EXIT /B 1 + +:END + ECHO exiting msys environment + IF EXIST %ERRORFILE% ( + ECHO failed to build mingw libs + EXIT /B 1 + ) + EXIT /B 0 + +ENDLOCAL diff --git a/tools/buildsteps/windows/make-mingwlibs.sh b/tools/buildsteps/windows/make-mingwlibs.sh new file mode 100644 index 0000000..e5a3594 --- /dev/null +++ b/tools/buildsteps/windows/make-mingwlibs.sh @@ -0,0 +1,162 @@ +[[ -f $(dirname $0)/buildhelpers.sh ]] && + source $(dirname $0)/buildhelpers.sh + +Win32BuildSetup=/xbmc/project/Win32BuildSetup +ERRORFILE=$Win32BuildSetup/errormingw +TOUCH=/bin/touch +RM=/bin/rm +NOPROMPT=0 +MAKECLEAN="" +MAKEFLAGS="" +TRIPLET="" + +while true; do + case $1 in + --build32=* ) build32="${1#*=}"; shift ;; + --build64=* ) build64="${1#*=}"; shift ;; + --buildArm=* ) buildArm="${1#*=}"; shift ;; + --prompt=* ) PROMPTLEVEL="${1#*=}"; shift ;; + --mode=* ) BUILDMODE="${1#*=}"; shift ;; + --win10=* ) win10="${1#*=}"; shift ;; + -- ) shift; break ;; + -* ) shift ;; + * ) break ;; + esac +done + +if [[ $build32 = "yes" ]]; then + TRIPLET=win32 + ARCH=x86 +elif [[ $build64 = "yes" ]]; then + TRIPLET=x64 + ARCH=x86_64 +elif [[ $buildArm = "yes" ]]; then + TRIPLET=arm + ARCH=arm +else + echo "-------------------------------------------------------------------------------" + echo " none of build types (build32, build64 or buildArm) was specified " + echo "-------------------------------------------------------------------------------" + # wait for key press + if [ "$PROMPTLEVEL" != "noprompt" ]; then + echo press a key to close the window + read + fi + exit +fi + +if [[ $win10 = "no" ]]; then + export _WIN32_WINNT=0x0600 + export NTDDI_VERSION=0x06000000 +elif [[ $win10 = "yes" ]]; then + TRIPLET=win10-$TRIPLET +fi + +export TRIPLET ARCH + +throwerror() { + $TOUCH $ERRORFILE + echo failed to compile $1 + if [ $NOPROMPT == 0 ]; then + read + fi +} + +checkfiles() { + for i in $@; do + if [ ! -f "$PREFIX/$i" ]; then + throwerror "$PREFIX/$i" + exit 1 + fi + done +} + +buildProcess() { +export PREFIX=/xbmc/project/BuildDependencies/mingwlibs/$TRIPLET +if [ "$(pathChanged $PREFIX /xbmc/tools/buildsteps/windows /xbmc/tools/depends/target/ffmpeg/FFMPEG-VERSION)" == "0" ]; then + return +fi + +if [ -d "$PREFIX" ]; then + rm -rdf $PREFIX/* +fi + +cd /xbmc/tools/buildsteps/windows + +# compile our mingw dlls +echo "-------------------------------------------------------------------------------" +echo " compiling mingw libs $TRIPLET" +echo +echo " NOPROMPT = $NOPROMPT" +echo " MAKECLEAN = $MAKECLEAN" +echo " WORKSPACE = $WORKSPACE" +echo +echo "-------------------------------------------------------------------------------" + +echo -ne "\033]0;building FFmpeg $TRIPLET\007" +echo "-------------------------------------------------" +echo " building FFmpeg $TRIPLET" +echo "-------------------------------------------------" +./buildffmpeg.sh $MAKECLEAN +checkfiles lib/avcodec.lib lib/avformat.lib lib/avutil.lib lib/postproc.lib lib/swscale.lib lib/avfilter.lib lib/swresample.lib +echo "-------------------------------------------------" +echo " building of FFmpeg $TRIPLET done..." +echo "-------------------------------------------------" +echo "-------------------------------------------------------------------------------" +echo " compile mingw libs $TRIPLET done..." +echo "-------------------------------------------------------------------------------" + +tagSuccessFulBuild $PREFIX /xbmc/tools/buildsteps/windows /xbmc/tools/depends/target/ffmpeg/FFMPEG-VERSION +} + +run_builds() { + local profile_path="" + if [[ $build32 = "yes" ]]; then + profile_path=/local32/etc/profile.local + elif [[ $build64 = "yes" ]]; then + profile_path=/local64/etc/profile.local + elif [[ $buildArm = "yes" ]]; then + profile_path=/local32/etc/profile.local + fi + + if [ ! -z $profile_path ]; then + if [[ ! -f "$profile_path" ]]; then + echo "-------------------------------------------------------------------------------" + echo " $TRIPLET build environment not configured, please run download-msys2.bat" + echo "-------------------------------------------------------------------------------" + else + source $profile_path + buildProcess + echo "-------------------------------------------------------------------------------" + echo " compile all libs $TRIPLET done..." + echo "-------------------------------------------------------------------------------" + fi + fi +} + +# cleanup +if [ -f $ERRORFILE ]; then + $RM $ERRORFILE +fi + +# check for noprompt +if [ "$PROMPTLEVEL" == "noprompt" ]; then + NOPROMPT=1 +fi + +if [ "$BUILDMODE" == "clean" ]; then + MAKECLEAN="clean" +else + MAKECLEAN="noclean" +fi + +run_builds + +echo -e "\033]0;compiling done...\007" +echo + +# wait for key press +if [ $NOPROMPT == 0 ]; then + echo press a key to close the window + read +fi diff --git a/tools/buildsteps/windows/patches/0001-ffmpeg-windows-configure-detect-openssl.patch b/tools/buildsteps/windows/patches/0001-ffmpeg-windows-configure-detect-openssl.patch new file mode 100644 index 0000000..b8e5b2f --- /dev/null +++ b/tools/buildsteps/windows/patches/0001-ffmpeg-windows-configure-detect-openssl.patch @@ -0,0 +1,25 @@ +From 08ae41e824e04ab48eafde763c72d1ff3e878a41 Mon Sep 17 00:00:00 2001 +From: Lukas Rusak <lorusak@gmail.com> +Date: Sat, 10 Apr 2021 08:16:11 -0700 +Subject: [PATCH 1/4] ffmpeg: windows: configure: detect openssl + +--- + configure | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/configure b/configure +index d7a3f507e8..4b85e881b1 100755 +--- a/configure ++++ b/configure +@@ -6530,6 +6530,8 @@ enabled openssl && { check_pkg_config openssl openssl openssl/ssl.h OP + check_lib openssl openssl/ssl.h SSL_library_init -lssl -lcrypto || + check_lib openssl openssl/ssl.h SSL_library_init -lssl32 -leay32 || + check_lib openssl openssl/ssl.h SSL_library_init -lssl -lcrypto -lws2_32 -lgdi32 || ++ check_lib openssl openssl/ssl.h OPENSSL_init_ssl -llibssl -llibcrypto -lws2_32 -lgdi32 -ladvapi32 -luser32 || ++ check_lib openssl openssl/ssl.h SSL_library_init -llibeay32 -lssleay32 || + die "ERROR: openssl not found"; } + enabled pocketsphinx && require_pkg_config pocketsphinx pocketsphinx pocketsphinx/pocketsphinx.h ps_init + enabled rkmpp && { require_pkg_config rkmpp rockchip_mpp rockchip/rk_mpi.h mpp_create && +-- +2.29.2 + diff --git a/tools/buildsteps/windows/patches/0002-ffmpeg-windows-configure-fix-zlib-conflict.patch b/tools/buildsteps/windows/patches/0002-ffmpeg-windows-configure-fix-zlib-conflict.patch new file mode 100644 index 0000000..064be1d --- /dev/null +++ b/tools/buildsteps/windows/patches/0002-ffmpeg-windows-configure-fix-zlib-conflict.patch @@ -0,0 +1,26 @@ +From 1e57e7f49f1a74ee11d3c8dd5d407f35eecd5167 Mon Sep 17 00:00:00 2001 +From: Lukas Rusak <lorusak@gmail.com> +Date: Sat, 10 Apr 2021 08:16:48 -0700 +Subject: [PATCH 2/4] ffmpeg: windows: configure: fix zlib conflict + +--- + configure | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/configure b/configure +index 4b85e881b1..da457705d1 100755 +--- a/configure ++++ b/configure +@@ -7627,6 +7627,9 @@ print_config CONFIG_ "$config_files" $CONFIG_LIST \ + $CONFIG_EXTRA \ + $ALL_COMPONENTS \ + ++echo "#if defined(HAVE_UNISTD_H) && HAVE_UNISTD_H == 0" >> $TMPH ++echo "#undef HAVE_UNISTD_H" >> $TMPH ++echo "#endif" >> $TMPH + echo "#endif /* FFMPEG_CONFIG_H */" >> $TMPH + echo "endif # FFMPEG_CONFIG_MAK" >> ffbuild/config.mak + +-- +2.29.2 + diff --git a/tools/buildsteps/windows/patches/0003-ffmpeg-windows-configure-allow-building-static.patch b/tools/buildsteps/windows/patches/0003-ffmpeg-windows-configure-allow-building-static.patch new file mode 100644 index 0000000..bbb3e0a --- /dev/null +++ b/tools/buildsteps/windows/patches/0003-ffmpeg-windows-configure-allow-building-static.patch @@ -0,0 +1,34 @@ +From efb771d944e96bcbb24635bcae99a43dffab262e Mon Sep 17 00:00:00 2001 +From: Lukas Rusak <lorusak@gmail.com> +Date: Sat, 10 Apr 2021 08:17:11 -0700 +Subject: [PATCH 3/4] ffmpeg: windows: configure: allow building static + +--- + configure | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/configure b/configure +index da457705d1..e3a8f45ff4 100755 +--- a/configure ++++ b/configure +@@ -5440,6 +5440,8 @@ case $target_os in + enabled shared && ! enabled small && test_cmd $windres --version && enable gnu_windres + enabled x86_32 && check_ldflags -Wl,--large-address-aware + shlibdir_default="$bindir_default" ++ LIBPREF="" ++ LIBSUF=".lib" + SLIBPREF="" + SLIBSUF=".dll" + SLIBNAME_WITH_VERSION='$(SLIBPREF)$(FULLNAME)-$(LIBVERSION)$(SLIBSUF)' +@@ -5489,6 +5491,8 @@ case $target_os in + fi + enabled x86_32 && check_ldflags -LARGEADDRESSAWARE + shlibdir_default="$bindir_default" ++ LIBPREF="" ++ LIBSUF=".lib" + SLIBPREF="" + SLIBSUF=".dll" + SLIBNAME_WITH_VERSION='$(SLIBPREF)$(FULLNAME)-$(LIBVERSION)$(SLIBSUF)' +-- +2.29.2 + diff --git a/tools/buildsteps/windows/patches/0004-ffmpeg-windows-configure-detect-libdav1d.patch b/tools/buildsteps/windows/patches/0004-ffmpeg-windows-configure-detect-libdav1d.patch new file mode 100644 index 0000000..617c87a --- /dev/null +++ b/tools/buildsteps/windows/patches/0004-ffmpeg-windows-configure-detect-libdav1d.patch @@ -0,0 +1,25 @@ +From d475edac8c6890fbaea5ca20d552c60aead0f04a Mon Sep 17 00:00:00 2001 +From: Lukas Rusak <lorusak@gmail.com> +Date: Sat, 10 Apr 2021 08:19:27 -0700 +Subject: [PATCH 4/4] ffmpeg: windows: configure: detect libdav1d + +--- + configure | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/configure b/configure +index e3a8f45ff4..983d7e1078 100755 +--- a/configure ++++ b/configure +@@ -6358,7 +6358,7 @@ enabled libcelt && require libcelt celt/celt.h celt_decode -lcelt0 && + die "ERROR: libcelt must be installed and version must be >= 0.11.0."; } + enabled libcaca && require_pkg_config libcaca caca caca.h caca_create_canvas + enabled libcodec2 && require libcodec2 codec2/codec2.h codec2_create -lcodec2 +-enabled libdav1d && require_pkg_config libdav1d "dav1d >= 0.5.0" "dav1d/dav1d.h" dav1d_version ++enabled libdav1d && require libdav1d dav1d/dav1d.h dav1d_version -llibdav1d + enabled libdavs2 && require_pkg_config libdavs2 "davs2 >= 1.6.0" davs2.h davs2_decoder_open + enabled libdc1394 && require_pkg_config libdc1394 libdc1394-2 dc1394/dc1394.h dc1394_new + enabled libdrm && require_pkg_config libdrm libdrm xf86drm.h drmGetVersion +-- +2.29.2 + diff --git a/tools/buildsteps/windows/patches/readme.txt b/tools/buildsteps/windows/patches/readme.txt new file mode 100644 index 0000000..80632dc --- /dev/null +++ b/tools/buildsteps/windows/patches/readme.txt @@ -0,0 +1,6 @@ +The folder contains patches for libs which will be built by mingw +in the following format: + + dddd-libname-*.patch + +The build system will apply these patches automatically
\ No newline at end of file diff --git a/tools/buildsteps/windows/prepare-env.bat b/tools/buildsteps/windows/prepare-env.bat new file mode 100644 index 0000000..bcbaded --- /dev/null +++ b/tools/buildsteps/windows/prepare-env.bat @@ -0,0 +1,27 @@ +@ECHO OFF + +PUSHD %~dp0\..\..\.. +SET WORKSPACE=%CD% +POPD + +ECHO Workspace is %WORKSPACE% + +cd %WORKSPACE% +rem clean the BUILD_WIN32 at first to avoid problems with possible git files in there +IF EXIST %WORKSPACE%\project\Win32BuildSetup\BUILD_WIN32 rmdir %WORKSPACE%\project\Win32BuildSetup\BUILD_WIN32 /S /Q + +rem also clean 'build' dir used to build ffmpeg as git clean has trouble to remove some times +IF EXIST %WORKSPACE%\project\BuildDependencies\build rmdir %WORKSPACE%\project\BuildDependencies\build /S /Q + +rem daemonized executables block mingw from being cleaned with git +TASKKILL /IM "dirmngr.exe" /F >nul 2>&1 +TASKKILL /IM "gpg-agent.exe" /F >nul 2>&1 + +rem we assume git in path as this is a requirement +rem git clean the untracked files and directories +rem but keep the downloaded dependencies +rem also keeps MSYS2 installation +SET GIT_CLEAN_CMD=git clean -xffd -e "project/BuildDependencies/downloads" -e "project/BuildDependencies/downloads2" -e "project/BuildDependencies/mingwlibs" -e "project/BuildDependencies/msys64" -e "project/BuildDependencies/tools" -e "cmake/addons/build/download/msys2-base-*.tar.xz" + +ECHO running %GIT_CLEAN_CMD% +%GIT_CLEAN_CMD% diff --git a/tools/buildsteps/windows/run-tests.bat b/tools/buildsteps/windows/run-tests.bat new file mode 100644 index 0000000..2bde835 --- /dev/null +++ b/tools/buildsteps/windows/run-tests.bat @@ -0,0 +1,70 @@ +@ECHO OFF +SETLOCAL ENABLEDELAYEDEXPANSION + +REM setup all paths +PUSHD %~dp0\..\..\.. +SET WORKSPACE=%CD% +POPD +cd %WORKSPACE%\kodi-build.%TARGET_PLATFORM% + +REM read the version values from version.txt +FOR /f "tokens=1,2" %%i IN (%WORKSPACE%\version.txt) DO IF "%%i" == "APP_NAME" SET APP_NAME=%%j + +CLS +COLOR 1B +TITLE %APP_NAME% testsuite Build-/Runscript + +rem ------------------------------------------------------------- +rem CONFIG START +SET exitcode=0 +SET useshell=sh +SET buildconfig=Release +SET PreferredToolArchitecture=x64 + + + rem CONFIG END + rem ------------------------------------------------------------- + +echo Building %buildconfig% +IF EXIST buildlog.html del buildlog.html /q + +ECHO Compiling testsuite... +cmake.exe --build . --config "%buildconfig%" --target %APP_NAME%-test + +IF %errorlevel%==1 ( + set DIETEXT="%APP_NAME%-test.exe failed to build! See %CD%\..\vs2010express\XBMC\%buildconfig%\objs\XBMC.log" + type "%CD%\..\vs2010express\XBMC\%buildconfig%\objs\XBMC.log" + goto DIE +) +ECHO Done building! +ECHO ------------------------------------------------------------ + +:RUNTESTSUITE +ECHO Running testsuite... + "%buildconfig%\%APP_NAME%-test.exe" --gtest_output=xml:%WORKSPACE%\gtestresults.xml + + rem Adapt gtest xml output to be conform with junit xml + rem this basically looks for lines which have "notrun" in the <testcase /> tag + rem and adds a <skipped/> subtag into it. For example: + rem <testcase name="IsStarted" status="notrun" time="0" classname="TestWebServer"/> + rem becomes + rem <testcase name="IsStarted" status="notrun" time="0" classname="TestWebServer"><skipped/></testcase> + @PowerShell "(GC %WORKSPACE%\gtestresults.xml)|%%{$_ -Replace '(<testcase.+)("notrun")(.+)(/>)','$1$2$3><skipped/></testcase>'}|SC %WORKSPACE%\gtestresults-skipped.xml" + del %WORKSPACE%\gtestresults.xml + move %WORKSPACE%\gtestresults-skipped.xml %WORKSPACE%\gtestresults.xml +ECHO Done running testsuite! +ECHO ------------------------------------------------------------ +GOTO END + +:DIE + ECHO ------------------------------------------------------------ + ECHO !-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!- + ECHO ERROR ERROR ERROR ERROR ERROR ERROR ERROR ERROR ERROR + ECHO !-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!- + set DIETEXT=ERROR: %DIETEXT% + echo %DIETEXT% + SET exitcode=1 + ECHO ------------------------------------------------------------ + +:END + EXIT /B %exitcode% diff --git a/tools/buildsteps/windows/vswhere.bat b/tools/buildsteps/windows/vswhere.bat new file mode 100644 index 0000000..b8c60b9 --- /dev/null +++ b/tools/buildsteps/windows/vswhere.bat @@ -0,0 +1,86 @@ +@ECHO OFF + +IF "%1"=="" ( + ECHO ERROR! vswhere.bat: architecture not specified + EXIT /B 1 +) + +REM running vcvars more than once can cause problems; exit early if using the same configuration, error if different +IF "%VSWHERE_SET%"=="%*" ( + ECHO vswhere.bat: VC vars already configured for %VSWHERE_SET% + GOTO :EOF +) +IF "%VSWHERE_SET%" NEQ "" ( + ECHO ERROR! vswhere.bat: VC vars are configured for %VSWHERE_SET% + EXIT /B 1 +) + +REM Trick to make the path absolute +PUSHD %~dp0\..\..\..\project\BuildDependencies +SET builddeps=%CD% +POPD + +SET arch=%1 +SET vcarch=amd64 +SET vcstore=%2 +SET vcvars=no +SET sdkver= + +SET vsver= +SET toolsdir=%arch% + +IF "%arch%" NEQ "x64" ( + SET vcarch=%vcarch%_%arch% +) + +IF "%arch%"=="x86" ( + SET toolsdir=win32 +) + +IF "%vcstore%"=="store" ( + SET sdkver=10.0.18362.0 + SET toolsdir="win10-%toolsdir%" +) + +SET vswhere="%builddeps%\%toolsdir%\tools\vswhere\vswhere.exe" + +FOR /f "usebackq tokens=1* delims=" %%i in (`%vswhere% -latest -property installationPath`) do ( + IF EXIST "%%i\VC\Auxiliary\Build\vcvarsall.bat" ( + SET vcvars="%%i\VC\Auxiliary\Build\vcvarsall.bat" + SET vsver=15 2017 + ECHO %%i | findstr "2019" >NUL 2>NUL + IF NOT ERRORLEVEL 1 SET vsver=16 2019 + ECHO %%i | findstr "2022" >NUL 2>NUL + IF NOT ERRORLEVEL 1 SET vsver=17 2022 + ) +) + +IF %vcvars%==no ( + FOR /f "usebackq tokens=1* delims=" %%i in (`%vswhere% -legacy -property installationPath`) do ( + ECHO %%i | findstr "14" >NUL 2>NUL + IF NOT ERRORLEVEL 1 ( + IF EXIST "%%i\VC\vcvarsall.bat" ( + SET vcvars="%%i\VC\vcvarsall.bat" + SET vsver=14 2015 + ) + ) + ) +) + +IF %vcvars%==no ( + ECHO "ERROR! Could not find vcvarsall.bat" + EXIT /B 1 +) + +REM vcvars changes the cwd so we need to store it and restore it +PUSHD %~dp0 +CALL %vcvars% %vcarch% %vcstore% %sdkver% +POPD + +IF ERRORLEVEL 1 ( + ECHO "ERROR! something went wrong when calling" + ECHO %vcvars% %vcarch% %vcstore% %sdkver% + EXIT /B 1 +) + +SET VSWHERE_SET=%* diff --git a/tools/buildsteps/windows/win32-uwp/BuildSetup.bat b/tools/buildsteps/windows/win32-uwp/BuildSetup.bat new file mode 100644 index 0000000..5ddf234 --- /dev/null +++ b/tools/buildsteps/windows/win32-uwp/BuildSetup.bat @@ -0,0 +1,18 @@ +@ECHO OFF + +PUSHD %~dp0\.. +CALL vswhere.bat x86 store +IF ERRORLEVEL 1 ( + ECHO ERROR! BuildSetup.bat: Something went wrong when calling vswhere.bat + POPD + EXIT /B 1 +) + +SET cmakeGenerator=Visual Studio %vsver% +SET cmakeArch=Win32 +SET TARGET_ARCHITECTURE=x86 +SET TARGET_PLATFORM=win32-uwp +SET cmakeProps=-DCMAKE_SYSTEM_NAME=WindowsStore -DCMAKE_SYSTEM_VERSION=%UCRTVersion% + +CALL BuildSetup.bat %* +POPD diff --git a/tools/buildsteps/windows/win32-uwp/bootstrap-addons.bat b/tools/buildsteps/windows/win32-uwp/bootstrap-addons.bat new file mode 100644 index 0000000..0f67ddb --- /dev/null +++ b/tools/buildsteps/windows/win32-uwp/bootstrap-addons.bat @@ -0,0 +1,11 @@ +@ECHO OFF + +PUSHD %~dp0\.. +CALL vswhere.bat x86 store +IF ERRORLEVEL 1 ( + ECHO ERROR! bootstrap-addons.bat: Something went wrong when calling vswhere.bat + POPD + EXIT /B 1 +) +CALL bootstrap-addons %* +POPD diff --git a/tools/buildsteps/windows/win32-uwp/download-dependencies.bat b/tools/buildsteps/windows/win32-uwp/download-dependencies.bat new file mode 100644 index 0000000..24ed2f1 --- /dev/null +++ b/tools/buildsteps/windows/win32-uwp/download-dependencies.bat @@ -0,0 +1,5 @@ +@ECHO OFF + +PUSHD %~dp0\.. +CALL download-dependencies.bat win10-win32 +POPD diff --git a/tools/buildsteps/windows/win32-uwp/download-msys2.bat b/tools/buildsteps/windows/win32-uwp/download-msys2.bat new file mode 100644 index 0000000..8c041ba --- /dev/null +++ b/tools/buildsteps/windows/win32-uwp/download-msys2.bat @@ -0,0 +1,5 @@ +@ECHO OFF + +PUSHD %~dp0\.. +CALL download-msys2.bat %* +POPD diff --git a/tools/buildsteps/windows/win32-uwp/make-addons.bat b/tools/buildsteps/windows/win32-uwp/make-addons.bat new file mode 100644 index 0000000..0893cee --- /dev/null +++ b/tools/buildsteps/windows/win32-uwp/make-addons.bat @@ -0,0 +1,11 @@ +@ECHO OFF + +PUSHD %~dp0\.. +CALL vswhere.bat x86 store +IF ERRORLEVEL 1 ( + ECHO ERROR! make-addons.bat: Something went wrong when calling vswhere.bat + POPD + EXIT /B 1 +) +CALL make-addons.bat win10 %* +POPD diff --git a/tools/buildsteps/windows/win32-uwp/make-mingwlibs.bat b/tools/buildsteps/windows/win32-uwp/make-mingwlibs.bat new file mode 100644 index 0000000..f47434e --- /dev/null +++ b/tools/buildsteps/windows/win32-uwp/make-mingwlibs.bat @@ -0,0 +1,11 @@ +@ECHO OFF + +PUSHD %~dp0\.. +CALL vswhere.bat x86 store +IF ERRORLEVEL 1 ( + ECHO ERROR! make-mingwlibs.bat: Something went wrong when calling vswhere.bat + POPD + EXIT /B 1 +) +CALL make-mingwlibs.bat win10 %* +POPD diff --git a/tools/buildsteps/windows/win32-uwp/prepare-env.bat b/tools/buildsteps/windows/win32-uwp/prepare-env.bat new file mode 100644 index 0000000..354a5cf --- /dev/null +++ b/tools/buildsteps/windows/win32-uwp/prepare-env.bat @@ -0,0 +1,5 @@ +@ECHO OFF + +PUSHD %~dp0\.. +CALL prepare-env.bat +POPD diff --git a/tools/buildsteps/windows/win32/BuildSetup.bat b/tools/buildsteps/windows/win32/BuildSetup.bat new file mode 100644 index 0000000..0c10f43 --- /dev/null +++ b/tools/buildsteps/windows/win32/BuildSetup.bat @@ -0,0 +1,18 @@ +@ECHO OFF + +PUSHD %~dp0\.. + +CALL vswhere.bat x86 +IF ERRORLEVEL 1 ( + ECHO ERROR! BuildSetup.bat: Something went wrong when calling vswhere.bat + POPD + EXIT /B 1 +) + +SET cmakeGenerator=Visual Studio %vsver% +SET cmakeArch=Win32 +SET TARGET_ARCHITECTURE=x86 +SET TARGET_PLATFORM=%TARGET_ARCHITECTURE% + +CALL BuildSetup.bat %* +POPD diff --git a/tools/buildsteps/windows/win32/bootstrap-addons.bat b/tools/buildsteps/windows/win32/bootstrap-addons.bat new file mode 100644 index 0000000..5918ad9 --- /dev/null +++ b/tools/buildsteps/windows/win32/bootstrap-addons.bat @@ -0,0 +1,11 @@ +@ECHO OFF + +PUSHD %~dp0\.. +CALL vswhere.bat x86 +IF ERRORLEVEL 1 ( + ECHO ERROR! bootstrap-addons.bat: Something went wrong when calling vswhere.bat + POPD + EXIT /B 1 +) +CALL bootstrap-addons %* +POPD diff --git a/tools/buildsteps/windows/win32/download-dependencies.bat b/tools/buildsteps/windows/win32/download-dependencies.bat new file mode 100644 index 0000000..ecb5897 --- /dev/null +++ b/tools/buildsteps/windows/win32/download-dependencies.bat @@ -0,0 +1,5 @@ +@ECHO OFF + +PUSHD %~dp0\.. +CALL download-dependencies.bat win32 +POPD diff --git a/tools/buildsteps/windows/win32/download-msys2.bat b/tools/buildsteps/windows/win32/download-msys2.bat new file mode 100644 index 0000000..8c041ba --- /dev/null +++ b/tools/buildsteps/windows/win32/download-msys2.bat @@ -0,0 +1,5 @@ +@ECHO OFF + +PUSHD %~dp0\.. +CALL download-msys2.bat %* +POPD diff --git a/tools/buildsteps/windows/win32/make-addons.bat b/tools/buildsteps/windows/win32/make-addons.bat new file mode 100644 index 0000000..7efc4ca --- /dev/null +++ b/tools/buildsteps/windows/win32/make-addons.bat @@ -0,0 +1,11 @@ +@ECHO OFF + +PUSHD %~dp0\.. +CALL vswhere.bat x86 +IF ERRORLEVEL 1 ( + ECHO ERROR! make-addons.bat: Something went wrong when calling vswhere.bat + POPD + EXIT /B 1 +) +CALL make-addons.bat %* +POPD diff --git a/tools/buildsteps/windows/win32/make-mingwlibs.bat b/tools/buildsteps/windows/win32/make-mingwlibs.bat new file mode 100644 index 0000000..889b27e --- /dev/null +++ b/tools/buildsteps/windows/win32/make-mingwlibs.bat @@ -0,0 +1,11 @@ +@ECHO OFF + +PUSHD %~dp0\.. +CALL vswhere.bat x86 +IF ERRORLEVEL 1 ( + ECHO ERROR! make-mingwlibs.bat: Something went wrong when calling vswhere.bat + POPD + EXIT /B 1 +) +CALL make-mingwlibs.bat %* +POPD diff --git a/tools/buildsteps/windows/win32/prepare-env.bat b/tools/buildsteps/windows/win32/prepare-env.bat new file mode 100644 index 0000000..354a5cf --- /dev/null +++ b/tools/buildsteps/windows/win32/prepare-env.bat @@ -0,0 +1,5 @@ +@ECHO OFF + +PUSHD %~dp0\.. +CALL prepare-env.bat +POPD diff --git a/tools/buildsteps/windows/win32/run-tests.bat b/tools/buildsteps/windows/win32/run-tests.bat new file mode 100644 index 0000000..1c07563 --- /dev/null +++ b/tools/buildsteps/windows/win32/run-tests.bat @@ -0,0 +1,13 @@ +@ECHO OFF + +PUSHD %~dp0\.. +CALL vswhere.bat x86 +IF ERRORLEVEL 1 ( + ECHO ERROR! run-tests.bat: Something went wrong when calling vswhere.bat + POPD + EXIT /B 1 +) +SET TARGET_PLATFORM=x86 + +CALL run-tests.bat +POPD diff --git a/tools/buildsteps/windows/x64-uwp/BuildSetup.bat b/tools/buildsteps/windows/x64-uwp/BuildSetup.bat new file mode 100644 index 0000000..8144248 --- /dev/null +++ b/tools/buildsteps/windows/x64-uwp/BuildSetup.bat @@ -0,0 +1,18 @@ +@ECHO OFF + +PUSHD %~dp0\.. +CALL vswhere.bat x64 store +IF ERRORLEVEL 1 ( + ECHO ERROR! BuildSetup.bat: Something went wrong when calling vswhere.bat + POPD + EXIT /B 1 +) + +SET cmakeGenerator=Visual Studio %vsver% +SET cmakeArch=x64 +SET TARGET_ARCHITECTURE=x64 +SET TARGET_PLATFORM=%TARGET_ARCHITECTURE%-uwp +SET cmakeProps=-DCMAKE_SYSTEM_NAME=WindowsStore -DCMAKE_SYSTEM_VERSION=%UCRTVersion% + +CALL BuildSetup.bat %* +POPD diff --git a/tools/buildsteps/windows/x64-uwp/bootstrap-addons.bat b/tools/buildsteps/windows/x64-uwp/bootstrap-addons.bat new file mode 100644 index 0000000..83eed23 --- /dev/null +++ b/tools/buildsteps/windows/x64-uwp/bootstrap-addons.bat @@ -0,0 +1,11 @@ +@ECHO OFF + +PUSHD %~dp0\.. +CALL vswhere.bat x64 store +IF ERRORLEVEL 1 ( + ECHO ERROR! bootstrap-addons.bat: Something went wrong when calling vswhere.bat + POPD + EXIT /B 1 +) +CALL bootstrap-addons %* +POPD diff --git a/tools/buildsteps/windows/x64-uwp/download-dependencies.bat b/tools/buildsteps/windows/x64-uwp/download-dependencies.bat new file mode 100644 index 0000000..4af0164 --- /dev/null +++ b/tools/buildsteps/windows/x64-uwp/download-dependencies.bat @@ -0,0 +1,5 @@ +@ECHO OFF + +PUSHD %~dp0\.. +CALL download-dependencies.bat win10-x64 +POPD diff --git a/tools/buildsteps/windows/x64-uwp/download-msys2.bat b/tools/buildsteps/windows/x64-uwp/download-msys2.bat new file mode 100644 index 0000000..8c041ba --- /dev/null +++ b/tools/buildsteps/windows/x64-uwp/download-msys2.bat @@ -0,0 +1,5 @@ +@ECHO OFF + +PUSHD %~dp0\.. +CALL download-msys2.bat %* +POPD diff --git a/tools/buildsteps/windows/x64-uwp/make-addons.bat b/tools/buildsteps/windows/x64-uwp/make-addons.bat new file mode 100644 index 0000000..82bd1af --- /dev/null +++ b/tools/buildsteps/windows/x64-uwp/make-addons.bat @@ -0,0 +1,11 @@ +@ECHO OFF + +PUSHD %~dp0\.. +CALL vswhere.bat x64 store +IF ERRORLEVEL 1 ( + ECHO ERROR! make-addons.bat: Something went wrong when calling vswhere.bat + POPD + EXIT /B 1 +) +CALL make-addons.bat win10 %* +POPD diff --git a/tools/buildsteps/windows/x64-uwp/make-mingwlibs.bat b/tools/buildsteps/windows/x64-uwp/make-mingwlibs.bat new file mode 100644 index 0000000..9e1ef90 --- /dev/null +++ b/tools/buildsteps/windows/x64-uwp/make-mingwlibs.bat @@ -0,0 +1,11 @@ +@ECHO OFF + +PUSHD %~dp0\.. +CALL vswhere.bat x64 store +IF ERRORLEVEL 1 ( + ECHO ERROR! make-mingwlibs.bat: Something went wrong when calling vswhere.bat + POPD + EXIT /B 1 +) +CALL make-mingwlibs.bat build64 win10 %* +POPD diff --git a/tools/buildsteps/windows/x64-uwp/prepare-env.bat b/tools/buildsteps/windows/x64-uwp/prepare-env.bat new file mode 100644 index 0000000..354a5cf --- /dev/null +++ b/tools/buildsteps/windows/x64-uwp/prepare-env.bat @@ -0,0 +1,5 @@ +@ECHO OFF + +PUSHD %~dp0\.. +CALL prepare-env.bat +POPD diff --git a/tools/buildsteps/windows/x64/BuildSetup.bat b/tools/buildsteps/windows/x64/BuildSetup.bat new file mode 100644 index 0000000..09acf3f --- /dev/null +++ b/tools/buildsteps/windows/x64/BuildSetup.bat @@ -0,0 +1,17 @@ +@ECHO OFF + +PUSHD %~dp0\.. +CALL vswhere.bat x64 +IF ERRORLEVEL 1 ( + ECHO ERROR! BuildSetup.bat: Something went wrong when calling vswhere.bat + POPD + EXIT /B 1 +) + +SET cmakeGenerator=Visual Studio %vsver% +SET cmakeArch=x64 +SET TARGET_ARCHITECTURE=x64 +SET TARGET_PLATFORM=%TARGET_ARCHITECTURE% + +CALL BuildSetup.bat %* +POPD diff --git a/tools/buildsteps/windows/x64/bootstrap-addons.bat b/tools/buildsteps/windows/x64/bootstrap-addons.bat new file mode 100644 index 0000000..45c5de6 --- /dev/null +++ b/tools/buildsteps/windows/x64/bootstrap-addons.bat @@ -0,0 +1,11 @@ +@ECHO OFF + +PUSHD %~dp0\.. +CALL vswhere.bat x64 +IF ERRORLEVEL 1 ( + ECHO ERROR! bootstrap-addons.bat: Something went wrong when calling vswhere.bat + POPD + EXIT /B 1 +) +CALL bootstrap-addons %* +POPD diff --git a/tools/buildsteps/windows/x64/download-dependencies.bat b/tools/buildsteps/windows/x64/download-dependencies.bat new file mode 100644 index 0000000..a51c3d4 --- /dev/null +++ b/tools/buildsteps/windows/x64/download-dependencies.bat @@ -0,0 +1,5 @@ +@ECHO OFF + +PUSHD %~dp0\.. +CALL download-dependencies.bat x64 +POPD diff --git a/tools/buildsteps/windows/x64/download-msys2.bat b/tools/buildsteps/windows/x64/download-msys2.bat new file mode 100644 index 0000000..8c041ba --- /dev/null +++ b/tools/buildsteps/windows/x64/download-msys2.bat @@ -0,0 +1,5 @@ +@ECHO OFF + +PUSHD %~dp0\.. +CALL download-msys2.bat %* +POPD diff --git a/tools/buildsteps/windows/x64/make-addons.bat b/tools/buildsteps/windows/x64/make-addons.bat new file mode 100644 index 0000000..ec9803f --- /dev/null +++ b/tools/buildsteps/windows/x64/make-addons.bat @@ -0,0 +1,11 @@ +@ECHO OFF + +PUSHD %~dp0\.. +CALL vswhere.bat x64 +IF ERRORLEVEL 1 ( + ECHO ERROR! make-addons.bat: Something went wrong when calling vswhere.bat + POPD + EXIT /B 1 +) +CALL make-addons.bat %* +POPD diff --git a/tools/buildsteps/windows/x64/make-mingwlibs.bat b/tools/buildsteps/windows/x64/make-mingwlibs.bat new file mode 100644 index 0000000..41471e5 --- /dev/null +++ b/tools/buildsteps/windows/x64/make-mingwlibs.bat @@ -0,0 +1,11 @@ +@ECHO OFF + +PUSHD %~dp0\.. +CALL vswhere.bat x64 +IF ERRORLEVEL 1 ( + ECHO ERROR! make-mingwlibs.bat: Something went wrong when calling vswhere.bat + POPD + EXIT /B 1 +) +CALL make-mingwlibs.bat build64 %* +POPD diff --git a/tools/buildsteps/windows/x64/prepare-env.bat b/tools/buildsteps/windows/x64/prepare-env.bat new file mode 100644 index 0000000..354a5cf --- /dev/null +++ b/tools/buildsteps/windows/x64/prepare-env.bat @@ -0,0 +1,5 @@ +@ECHO OFF + +PUSHD %~dp0\.. +CALL prepare-env.bat +POPD diff --git a/tools/buildsteps/windows/x64/run-tests.bat b/tools/buildsteps/windows/x64/run-tests.bat new file mode 100644 index 0000000..a21ea89 --- /dev/null +++ b/tools/buildsteps/windows/x64/run-tests.bat @@ -0,0 +1,13 @@ +@ECHO OFF + +PUSHD %~dp0\.. +CALL vswhere.bat x64 +IF ERRORLEVEL 1 ( + ECHO ERROR! run-tests.bat: Something went wrong when calling vswhere.bat + POPD + EXIT /B 1 +) +SET TARGET_PLATFORM=x64 + +CALL run-tests.bat +POPD diff --git a/tools/codegenerator/Generator.groovy b/tools/codegenerator/Generator.groovy new file mode 100644 index 0000000..79cfe4f --- /dev/null +++ b/tools/codegenerator/Generator.groovy @@ -0,0 +1,74 @@ +/* + * Copyright (C) 2005-2013 Team XBMC + * http://xbmc.org + * + * 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, 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 XBMC; see the file COPYING. If not, see + * <http://www.gnu.org/licenses/>. + * + */ + +import groovy.text.SimpleTemplateEngine +import groovy.xml.XmlParser +import groovy.xml.XmlUtil + +import Helper + +def usage() +{ + println "java/groovy -cp [...] " + getClass().getName() + " [-verbose] moduleSpecFile templateFile outputFile [doxygenoutputdir]"; + System.exit 1 +} + +def verbose = false; + +newargs = [] + +println args + +args.each { + if (it == '-verbose' || it == '--verbose' || it == '-v') + verbose = true + else + newargs.add(it) +} + +if (newargs.size() != 3 && newargs.size() != 4) + usage() + +// set the doxygen xml directory on the Helper assuming the output file will be placed +// in the same place the doxygen subdirectory is placed +if (newargs.size() > 3) + Helper.setDoxygenXmlDir(new File(newargs[3])) + +File moduleSpec = new File(newargs[0]) +assert moduleSpec.exists() && moduleSpec.isFile(), 'Cannot locate the spec file "' + moduleSpec.getCanonicalPath() + '."' + +File templateFile = new File(newargs[1]) +assert templateFile.exists() && templateFile.isFile(), 'Cannot locate the template file "' + templateFile.getCanonicalPath() + '."' + +spec = [ 'module' : Helper.transformSwigXml(new XmlParser().parse(moduleSpec)), 'templateFile' : templateFile ] + +if (verbose) + println XmlUtil.serialize(spec['module']) + +te = new SimpleTemplateEngine() +println 'Processing "' + templateFile + '" using the module specification for module "' + moduleSpec + '"' +if (verbose) te.setVerbose(true) +template = te.createTemplate(templateFile).make(spec) +String output = template.toString() +if (verbose) println output + +println 'writing' +new File(newargs[2]).write output + diff --git a/tools/codegenerator/Helper.groovy b/tools/codegenerator/Helper.groovy new file mode 100644 index 0000000..4308ffd --- /dev/null +++ b/tools/codegenerator/Helper.groovy @@ -0,0 +1,882 @@ +/* + * Copyright (C) 2005-2013 Team XBMC + * http://xbmc.org + * + * 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, 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 XBMC; see the file COPYING. If not, see + * <http://www.gnu.org/licenses/>. + * + */ + +import groovy.xml.XmlParser +import groovy.xml.XmlUtil +import org.apache.commons.lang.StringEscapeUtils + +import groovy.text.SimpleTemplateEngine +import java.util.regex.Pattern + +/** + * This class contains a series of helper methods for parsing a xbmc addon spec xml file. It is intended to be + * used from a bindings template. + * + * @author jim + * + */ +public class Helper +{ + private static List classes + private static Map outTypemap = [:] + private static def defaultOutTypeConversion = null + private static Map inTypemap = [:] + private static def defaultInTypeConversion = null + private static def doxygenXmlDir = null + public static String newline = System.getProperty("line.separator"); + public static File curTemplateFile = null; + + public static void setTemplateFile(File templateFile) { curTemplateFile = templateFile } + + /** + * In order to use any of the typemap helper features, the Helper class needs to be initialized with + * this information. + * @param pclasses is the list of all class nodes from the module + * @param poutTypemap is the typemap table for output return values to the scripting language + * @param defaultOutTypemap is the default typemap to use when the type conversion is unknown + * @param pinTypemap is the typemap table for input parameters from the scripting language + * @param defaultInTypemap is the default typemap for the input parameters from the scripting language + */ + public static void setup(def template,List pclasses, Map poutTypemap, def defaultOutTypemap, + Map pinTypemap, def defaultInTypemap) + { + setTemplateFile(template.binding.templateFile) + classes = pclasses ? pclasses : [] + if (poutTypemap) outTypemap.putAll(poutTypemap) + if (defaultOutTypemap) defaultOutTypeConversion = defaultOutTypemap + if (pinTypemap) inTypemap.putAll(pinTypemap) + if (defaultInTypemap) defaultInTypeConversion = defaultInTypemap + } + + public static class Sequence + { + private long cur = 0; + + public long increment() { return ++cur } + } + + private static ThreadLocal<Sequence> curSequence = new ThreadLocal<Sequence>(); + + public static void setDoxygenXmlDir(File dir) { doxygenXmlDir = dir } + + private static String retrieveDocStringFromDoxygen(Node methodOrClass) + { + if (doxygenXmlDir == null) + return null + + Node doc = null + def ret = '' + + // make the class name or namespace + String doxygenId = findFullClassName(methodOrClass,'_1_1',true) + boolean isInClass = doxygenId != null + if (!doxygenId) + doxygenId = findNamespace(methodOrClass,'_1_1',false,true) + doxygenId = (isInClass ? 'class' : 'namespace') + doxygenId + + String doxygenFilename = doxygenId + '.xml' + File doxygenXmlFile = new File(doxygenXmlDir,doxygenFilename) + if (! doxygenXmlFile.exists()) + { + System.out.println("WARNING: Cannot find doxygen file for ${methodOrClass.toString()} which should be \"${doxygenXmlFile}\"") + return null + } + + Node docspec = (new XmlParser().parse(doxygenXmlFile)) + if (methodOrClass.name() == 'class') + doc = docspec.compounddef[0].detaileddescription[0] + else // it's a method of some sort ... or it better be + { + Node memberdef = docspec.depthFirst().find { + return (it instanceof String) ? false : + ((it.name() == 'memberdef' && (it.@kind == 'function' || it.@kind == 'variable') && it.@id.startsWith(doxygenId)) && + (it.name != null && it.name.text().trim() == methodOrClass.@sym_name)) + } + + doc = memberdef != null ? memberdef.detaileddescription[0] : null + } + + if (doc != null) + { + def indent = ' ' + def curIndent = '' + def prevIndent = '' + + def handleDoc + handleDoc = { + if (it instanceof String) + ret += it + else // it's a Node + { + if (it.name() == 'detaileddescription') + it.children().each handleDoc + else if (it.name() == 'para') + { + it.children().each handleDoc + ret += (it.parent()?.name() == 'listitem') ? newline : (newline + newline) + } + else if (it.name() == 'ref' || it.name() == "ulink") + ret += (it.text() + ' ') + else if (it.name() == 'verbatim') + ret += it.text().denormalize() + else if (it.name() == 'itemizedlist') + { + ret += newline + prevIndent = curIndent + curIndent += indent + it.children().each handleDoc + curIndent = prevIndent + } + else if (it.name() == 'listitem') + { + ret += (curIndent + '- ') + it.children().each handleDoc + } + else if (it.name() == 'linebreak') + ret += newline + else if (it.name() == 'ndash') + ret += "--" + else if (it.name() == 'emphasis') + { + ret += '*' + it.children().each handleDoc + } + else + System.out.println("WARNING: Cannot parse the following as part of the doxygen processing:" + XmlUtil.serialize(it)) + } + } + + doc.children().each handleDoc + } + + return ret.denormalize() + } + + /** + * <p>This method uses the previously set outTypemap and defaultOutTypemap to produce the chunk of code + * that will be used to return the method invocation result to the scripting language. For example, in + * python, if the return type from the method is a long, then the OutConversion could look something like:</p> + * <code> + * result = PyInt_FromLong(thingReturnedFromMethod); + * </code> + * <p>This could have resulted from a mini-template stored as the way to handle 'long's in the outTypemap:</p> + * <code> + * ${result} = PyInt_FromLong(${api}); + * </code> + * @param apiType - is the Swig typecode that describes the return type from the native method + * @param method - is the node from the module xml that contains the method description + * @return the code chunk as a string ready to be placed into the generated code. + */ + public static String getOutConversion(String apiType, String apiName, Node method, Map overrideBindings = null, boolean recurse = true) + { + def convertTemplate = outTypemap[apiType] + + // String apiLType = SwigTypeParser.convertTypeToLType(apiType) + // if (convertTemplate == null) convertTemplate = outTypemap[apiLType] + + // is the returns a pointer to a known class + String className = null + if (convertTemplate == null && apiType.startsWith('p.')) + { + Node classNode = findClassNodeByName(parents(method)[0], SwigTypeParser.getRootType(apiType),method) + if (classNode) + { + className = findFullClassName(classNode) + convertTemplate = defaultOutTypeConversion + } + } + + if (convertTemplate == null) + { + // Look for Pattern for keys that might fit + convertTemplate = outTypemap.find({ key, value -> (key instanceof Pattern && key.matcher(apiType).matches()) })?.value + } + + if (!convertTemplate) + { + String knownApiType = isKnownApiType(apiType,method) + if (knownApiType) + { + convertTemplate = defaultOutTypeConversion + className = knownApiType + } + } + + if (!convertTemplate) + { + // check the typedef resolution + String apiTypeResolved = SwigTypeParser.SwigType_resolve_all_typedefs(apiType) + if (!apiTypeResolved.equals(apiType)) + return getOutConversion(apiTypeResolved, apiName, method, overrideBindings, recurse) + + if (recurse) + return getOutConversion(SwigTypeParser.SwigType_ltype(apiType),apiName,method,overrideBindings,false) + else if (!isKnownApiType(apiType,method)) + throw new RuntimeException("WARNING: Cannot convert the return value of swig type ${apiType} for the call ${Helper.findFullClassName(method) + '::' + Helper.callingName(method)}") + } + + boolean seqSetHere = false + Sequence seq = curSequence.get() + if (seq == null) + { + seqSetHere = true + seq = new Sequence() + curSequence.set(seq) + } + + Map bindings = ['result' : apiName, 'api' : 'apiResult', 'type' : "${apiType}", + 'method' : method, 'helper' : Helper.class, + 'swigTypeParser' : SwigTypeParser.class, + 'sequence' : seq ] + if (className) bindings['classname'] = className + + if (overrideBindings) bindings.putAll(overrideBindings) + + if (convertTemplate instanceof List) /// then we expect the template string/file to be the first entry + { + Map additionalBindings = convertTemplate.size() > 1 ? convertTemplate[1] : [:] + bindings.putAll(additionalBindings) + convertTemplate = convertTemplate[0] + } + + if (File.class.isAssignableFrom(convertTemplate.getClass())) + { + File cur = (File)convertTemplate + if (!cur.exists()) // see if the file is relative to the template file + { + File parent = curTemplateFile.getParentFile() + // find the relative path to the convertTemplate + File cwd = new File('.').getCanonicalFile() + String relative = cwd.getAbsoluteFile().toURI().relativize(convertTemplate.getAbsoluteFile().toURI()).getPath() + convertTemplate = new File(parent,relative) + + // This is a fallback case which is hit occasionally on OSX as a result + // of case mismatches between the two paths in the relativize call above. + if (!convertTemplate.exists()) + convertTemplate = new File(parent,cur.toString()) + } + } + + if (seqSetHere) curSequence.set(null) + return new SimpleTemplateEngine().createTemplate(convertTemplate).make(bindings).toString() + } + + /** + * <p>This method uses the previously set inTypemap and defaultInTypemap to produce the chunk of code + * that will be used to convert input parameters from the scripting language to the native method invocation + * parameters. For example, if the native call takes a 'String' then the InConversion could look something like:</p> + * <code> + * if (pythonStringArgument) PyXBMCGetUnicodeString(cArgument,pythonStringArgument,"cArgumentName"); + * </code> + * <p>This could have resulted from a mini-template stored as the way to handle 'long's in the outTypemap:</p> + * <code> + * if (${slarg}) PyXBMCGetUnicodeString(${api},${slarg},"${api}"); + * </code> + * @param apiType - is the Swig typecode that describes the parameter type from the native method + * @param apiName - is the name of the parameter from the method parameter list in the api + * @param slName - is the name of the variable that holds the parameter from the scripting language + * @param method - is the node from the module xml that contains the method description + * @return the code chunk as a string ready to be placed into the generated code. + */ + public static String getInConversion(String apiType, String apiName, String slName, Node method, Map overrideBindings = null) + { + return getInConversion(apiType, apiName, apiName, slName, method, overrideBindings); + } + + /** + * <p>This method uses the previously set inTypemap and defaultInTypemap to produce the chunk of code + * that will be used to convert input parameters from the scripting language to the native method invocation + * parameters. For example, if the native call takes a 'String' then the InConversion could look something like:</p> + * <code> + * if (pythonStringArgument) PyXBMCGetUnicodeString(cArgument,pythonStringArgument,"cArgumentName"); + * </code> + * <p>This could have resulted from a mini-template stored as the way to handle 'long's in the outTypemap:</p> + * <code> + * if (${slarg}) PyXBMCGetUnicodeString(${api},${slarg},"${api}"); + * </code> + * @param apiType - is the Swig typecode that describes the parameter type from the native method + * @param apiName - is the name of the variable that holds the api parameter + * @param paramName - is the name of the parameter from the method parameter list in the api + * @param slName - is the name of the variable that holds the parameter from the scripting language + * @param method - is the node from the module xml that contains the method description + * @return the code chunk as a string ready to be placed into the generated code. + */ + public static String getInConversion(String apiType, String apiName, String paramName, String slName, Node method, Map overrideBindings = null) + { + def convertTemplate = inTypemap[apiType] + + String apiLType = SwigTypeParser.convertTypeToLTypeForParam(apiType) + + if (convertTemplate == null) convertTemplate = inTypemap[apiLType] + + // is the returns a pointer to a known class + if (convertTemplate == null && apiType.startsWith('p.')) + { + // strip off rval qualifiers + String thisNamespace = Helper.findNamespace(method) + Node clazz = classes.find { Helper.findFullClassName(it) == apiLType.substring(2) || + (it.@sym_name == apiLType.substring(2) && thisNamespace == Helper.findNamespace(it)) } + if (clazz != null) convertTemplate = defaultInTypeConversion + } + + // Look for Pattern for keys that might fit + if (convertTemplate == null) + convertTemplate = inTypemap.find({ key, value -> (key instanceof Pattern && key.matcher(apiType).matches()) })?.value + + // Try the LType + if (convertTemplate == null) + convertTemplate = inTypemap.find({ key, value -> (key instanceof Pattern && key.matcher(apiLType).matches()) })?.value + + if (!convertTemplate) + { + // check the typedef resolution + String apiTypeResolved = SwigTypeParser.SwigType_resolve_all_typedefs(apiType) + if (!apiTypeResolved.equals(apiType)) + return getInConversion(apiTypeResolved, apiName, paramName, slName, method, overrideBindings) + + // it's ok if this is a known type + if (!isKnownApiType(apiType,method) && !isKnownApiType(apiLType,method)) + System.out.println("WARNING: Unknown parameter type: ${apiType} (or ${apiLType}) for the call ${Helper.findFullClassName(method) + '::' + Helper.callingName(method)}") + convertTemplate = defaultInTypeConversion + } + + if (convertTemplate) + { + boolean seqSetHere = false + Sequence seq = curSequence.get() + if (seq == null) + { + seqSetHere = true + seq = new Sequence() + curSequence.set(seq) + } + + Map bindings = [ + 'type': "${apiType}", 'ltype': "${apiLType}", + 'slarg' : "${slName}", 'api' : "${apiName}", + 'param' : "${paramName}", + 'method' : method, 'helper' : Helper.class, + 'swigTypeParser' : SwigTypeParser.class, + 'sequence' : seq + ] + + if (overrideBindings) bindings.putAll(overrideBindings) + + if (convertTemplate instanceof List) /// then we expect the template string/file to be the first entry + { + Map additionalBindings = convertTemplate.size() > 1 ? convertTemplate[1] : [:] + bindings.putAll(additionalBindings) + convertTemplate = convertTemplate[0] + } + + if (File.class.isAssignableFrom(convertTemplate.getClass())) + { + File cur = (File)convertTemplate + if (!cur.exists()) // see if the file is relative to the template file + { + File parent = curTemplateFile.getParentFile() + // find the relative path to the convertTemplate + File cwd = new File('.').getCanonicalFile() + String relative = cwd.getAbsoluteFile().toURI().relativize(convertTemplate.getAbsoluteFile().toURI()).getPath() + convertTemplate = new File(parent,relative) + + // This is a fallback case which is hit occasionally on OSX as a result + // of case mismatches between the two paths in the relativize call above. + if (!convertTemplate.exists()) + convertTemplate = new File(parent,cur.toString()) + } + } + + if (seqSetHere) curSequence.set(null); + return new SimpleTemplateEngine().createTemplate(convertTemplate).make(bindings).toString() + } + + return '' + } + + static def ignoreAttributes = ['classes', 'symtab', 'sym_symtab', + 'sym_overname', 'options', 'sym_nextSibling', 'csym_nextSibling', + 'sym_previousSibling' ] + + /** + * <p>Transform a Swig generated xml file into something more manageable. For the most part this method will:</p> + * + * <li>1) Make all pertinent 'attributelist' elements actually be attributes of the parent element while + * an attribute with the name 'name' will become that parent element name.</li> + * <li>2) Filter out unused attributes</li> + * <li>3) Filter out the automatically included 'swig'swg'</li> + * <li>4) Flatten out the remaining 'include' elements</li> + * <li>5) Removes extraneous default argument function/method Node</li> + * <li>6) Converts all type tables to a single entry under the main module node removing all 1-1 mappings.</li> + * <li>7) Removes all non-public non-constructor methods.</li> + * @param swigxml is the raw swig output xml document + * @return the transformed document + */ + public static Node transformSwigXml(Node swigxml) + { + Node node = transform(swigxml, + { + // do not include the 'include' entry that references the default swig.swg file. + !(it.name() == 'include' && + // needs to also contain an attribute list with an attribute 'name' that matches the swig.swg file + it.find { + it.name() == 'attributelist' && it.find { + it.name() == 'attribute' && it.@name == 'name' && it.@value =~ /swig\.swg$/ + } + } || + // also don't include any typescope entries + it.name() == 'typescopesitem' || it.name() == 'typetabsitem' + ) + },{ key, value -> !ignoreAttributes.contains(key) }) + + // now make sure the outer most node is an include and there's only one + assert node.include?.size() == 1 && node.include[0].module?.size() == 1 && node.include[0].module[0]?.@name != null, + "Invalid xml doc result. Expected a single child node of the root node call 'include' with a single 'module' child node but got " + XmlUtil.serialize(node) + + // create an outermost 'module' node with the correct name + Node ret = new Node(null, 'module', [ 'name':node.include[0].module[0].@name] ) + node.include[0].children().each { if (it.name() != 'module') ret.append(it) } + + // flatten out all other 'include' elements, parmlists, and typescopes + flatten(ret,['include', 'parmlist', 'typescope' ]) + + // remove any function nodes with default arguments + List tmpl = [] + tmpl.addAll(ret.depthFirst()) + for (Node cur : tmpl) + { + if ((cur.name() == 'function' || cur.name() == 'constructor') && cur.@defaultargs != null) + cur.parent().remove(cur) + } + + // now validate that no other methods are overloaded since we can't handle those right now. + functionNodesByOverloads(ret).each { key, value -> assert value.size() == 1, "Cannot handle overloaded methods unless simply using defaulting: " + value } + + // now gather up all of the typetabs and add a nice single + // typetab entry with a better format in the main module + List allTypetabs = ret.depthFirst().findAll { it.name() == 'typetab' } + Node typenode = new Node(ret,'typetab') + allTypetabs.each { + it.attributes().each { key, value -> + if (key != 'id' && key != value) + { + Node typeentry = new Node(null,'entry') + String namespace = findNamespace(it) + typeentry.@namespace = namespace != null ? namespace.trim() : '' + typeentry.@type = key + typeentry.@basetype = value + + if (typenode.find({ it.@basetype == typeentry.@basetype && it.@namespace == typeentry.@namespace }) == null) + typenode.append(typeentry) + } + } + it.parent().remove(it) + } + + // now remove all non-public methods, but leave constructors + List allMethods = ret.depthFirst().findAll({ it.name() == 'function' || it.name() == 'destructor' || it.name() == 'constructor'}) + allMethods.each { + if (it.@access != null && it.@access != 'public' && it.name() != 'constructor') + it.parent().remove(it) + else + { + def doc = retrieveDocStringFromDoxygen(it) + if (doc != null && doc != '' && doc.trim() != ' ') + new Node(it,'doc',['value' : doc]) + } + } + + // now remove all non-public variables + List allVariables = ret.depthFirst().findAll({ it.name() == 'variable' }) + allVariables.each { + if (it.@access != null && it.@access != 'public') + it.parent().remove(it) + else + { + def doc = retrieveDocStringFromDoxygen(it) + if (doc != null && doc != '' && doc.trim() != ' ') + new Node(it,'doc',['value' : doc]) + } + } + + // add the doc string to the classes + List allClasses = ret.depthFirst().findAll({ it.name() == 'class'}) + allClasses.each { + def doc = retrieveDocStringFromDoxygen(it) + if (doc != null && doc != '' && doc.trim() != ' ') + new Node(it,'doc',['value' : doc]) + } + + return ret + } + + /** + * @return true if the class node has a defined constructor. false otherwise. + */ + public static boolean hasDefinedConstructor(Node clazz) + { + return (clazz.constructor != null && clazz.constructor.size() > 0) + } + + /** + * @return true id this Node has a docstring associated with it. + */ + public static boolean hasDoc(Node methodOrClass) + { + return methodOrClass.doc != null && methodOrClass.doc[0] != null && methodOrClass.doc[0].@value != null + } + + /** + * @return true of the class node has a constructor but it's hidden (not 'public'). false otherwise. + */ + public static boolean hasHiddenConstructor(Node clazz) + { + return (hasDefinedConstructor(clazz) && clazz.constructor[0].@access != null && clazz.constructor[0].@access != 'public') + } + + /** + * <p>This will look through the entire module and look up a class node by name. It will return null if + * that class node isn't found. It's meant to be used to look up base classes from a base class list + * so it's fairly robust. It goes through the following rules:</p> + * + * <li>Does the FULL classname (considering the namespace) match the name provided.</li> + * <li>Does the FULL classname match the reference nodes namespace + '::' + the provided classname.</li> + * <li>Does the class node's name (which may contain the full classname) match the classname provided.</li> + * + * <p>Note, this method is not likely to find the classnode if you just pass a simple name and + * no referenceNode in the case where namespaces are used extensively.</p> + */ + public static Node findClassNodeByName(Node module, String classname, Node referenceNode = null) + { + return module.depthFirst().findAll({ it.name() == 'class' }).find { + // first check to see if this FULL class name matches + if (findFullClassName(it).trim() == classname.trim()) return true + + // now check to see if it matches the straight name considering the reference node + if (referenceNode != null && (findNamespace(referenceNode) + classname) == findFullClassName(it)) return true + + // now just see if it matches the straight name + if (it.@name == classname) return true + + return false + } + } + + /** + * Find me the class node that this node either is, or is within. + * If this node is not within a class node then it will return null. + */ + public static Node findClassNode(Node node) + { + if (node.name() == 'class') return node + return node.parent() == null ? null : findClassNode(node.parent()) + } + + /** + * If this node is a class node, or a child of a class name (for example, a method) then + * the full classname, with the namespace will be returned. Otherwise, null. + */ + public static String findFullClassName(Node node, String separator = '::', boolean filename = false) + { + String ret = null + List rents = parents(node, { it.name() == 'class' }) + if (node.name() == 'class') rents.add(node) + rents.each { + if (ret == null) + ret = it.@sym_name + else + ret += separator + it.@sym_name + } + + return ret ? findNamespace(node,separator,true,filename) + ret : null + } + + /** + * Given the Node this method looks to see if it occurs within namespace and returns + * the namespace as a String. It includes the trailing '::' + */ + public static String findNamespace(Node node, String separator = '::', boolean endingSeparator = true, boolean filename = false) + { + String ret = null + parents(node, { it.name() == 'namespace' }).each { + String data = it.@name + if (filename) + data = data.replaceAll("_", "__") + if (ret == null) + ret = data + else + ret += separator + data + } + + return ret == null ? '' : (ret + (endingSeparator ? separator : '')) + } + + /** + * Gather up all of the parent nodes in a list ordered from the top node, down to the + * node that's passed as a parameter. + */ + public static List parents(Node node, Closure filter = null, List ret = null) + { + Node parent = node.parent() + if (parent != null) + { + ret = parents(parent,filter,ret) + if (filter == null || filter.call(parent)) + ret += parent + } + else if (ret == null) + ret = [] + + return ret + } + + /** + * Group together overloaded methods into a map keyed by the first method's id. Each + * entry in this map contains a list of nodes that represent overloaded versions of + * the same method. + */ + public static Map functionNodesByOverloads(Node module) + { + // find function nodes + Map ret = [:] + module.depthFirst().each { + if (it.name() == 'function' || it.name() == 'constructor' || it.name() == 'destructor') + { + String id = it.@sym_overloaded != null ? it.@sym_overloaded : it.@id + if (ret[id] == null) ret[id] = [it] + else ret[id] += it + } + } + return ret + } + + /** + * Because the return type of a property is a combination of the function + * 'decl' and the function 'type,' this method will construct a valid Swig + * typestring from the two. + */ + public static String getPropertyReturnSwigType(Node method) + { + // we're going to take a shortcut here because it appears only the pointer indicator + // ends up attached to the decl. + String prefix = (method.@decl != null && method.@decl == 'p.') ? 'p.' : '' + return method.@type != null ? prefix + method.@type : 'void' + } + + /** + * Because the return type is a combination of the function 'decl' and the + * function 'type,' this method will construct a valid Swig typestring from + * the two. + */ + public static String getReturnSwigType(Node method) + { + // we're going to take a shortcut here because it appears only the pointer indicator + // ends up attached to the decl. + String prefix = (method.@decl != null && method.@decl.endsWith('.p.')) ? 'p.' : '' + return method.@type != null ? prefix + method.@type : 'void' + } + + /** + * Given the method node this will produce the actual name of the method as if + * it's being called. In the case of a constructor it will do a 'new.' In the + * case of a destructor it will produce a 'delete.' + */ + public static String callingName(Node method) + { + // if we're not in a class we need the fully qualified name + String clazz = findFullClassName(method) + // if we're in a class then we are going to assume we have a 'self' pointer + // that we are going to invoke this on. + if (clazz == null) + return method.@name + + if (method.name() == 'constructor') + return "new ${findNamespace(method)}${method.@sym_name}" + + if (method.name() == 'destructor') + return 'delete' + + // otherwise it's just a call on a class being invoked on an instance + return method.@name + } + + /** + * Swig has 'insert' nodes in it's parse tree that contain code chunks that are + * meant to be inserted into various positions in the generated code. This method + * will extract the nodes that refer to the specific section asked for. See the + * Swig documentation for more information. + */ + public static List getInsertNodes(Node module, String section) + { + return module.insert.findAll { section == it.@section || (section == 'header' && it.@section == null) } + } + + public static String unescape(Node insertSection) { return unescape(insertSection.@code) } + + public static String unescape(String insertSection) { return StringEscapeUtils.unescapeHtml(insertSection) } + + public static boolean isDirector(Node method) + { + Node clazz = findClassNode(method) + if (!clazz || !clazz.@feature_director) + return false + if (method.name() == 'destructor') + return false + if (method.name() == 'constructor') + return false + return method.@storage && method.@storage == 'virtual' + } + + /** + * This method will search from the 'searchFrom' Node up to the root + * looking for a %feature("knownbasetypes") declaration that the given 'type' is + * known for 'searchFrom' Node. + */ + public static boolean isKnownBaseType(String type, Node searchFrom) + { + return hasFeatureSetting(type,searchFrom,'feature_knownbasetypes',{ it.split(',').find({ it.trim() == type }) != null }) + } + + /** + * This method will search from the 'searchFrom' Node up to the root + * looking for a %feature("knownapitypes") declaration that the given 'type' is + * known for 'searchFrom' Node. + */ + public static String isKnownApiType(String type, Node searchFrom) + { + String rootType = SwigTypeParser.getRootType(type) + String namespace = findNamespace(searchFrom,'::',false) + String lastMatch = null + hasFeatureSetting(type,searchFrom,'feature_knownapitypes',{ it.split(',').find( + { + if (it.trim() == rootType) + { + lastMatch = rootType + return true + } + // we assume the 'type' is defined within namespace and + // so we can walk up the namespace appending the type until + // we find a match. + while (namespace != '') + { +// System.out.println('checking ' + (namespace + '::' + rootType)) + if ((namespace + '::' + rootType) == it.trim()) + { + lastMatch = it.trim() + return true + } + // truncate the last namespace + int chop = namespace.lastIndexOf('::') + namespace = (chop > 0) ? namespace.substring(0,chop) : '' + } + return false + }) != null }) + return lastMatch + } + + private static String hasFeatureSetting(String type, Node searchFrom, String feature, Closure test) + { + if (!searchFrom) + return null + + Object attr = searchFrom.attribute(feature) + if (attr && test.call(attr)) + return attr.toString() + + return hasFeatureSetting(type,searchFrom.parent(),feature,test) + } + + private static void flatten(Node node, List elementsToRemove) + { + for (boolean done = false; !done;) + { + done = true + for (Node child : node.breadthFirst()) + { + if (elementsToRemove.contains(child.name())) + { + Node parent = child.parent() + parent.remove(child) + child.each { parent.append(it) } + done = false + break + } + } + } + } + + private static Node transform(Node node, Closure nodeFilter, Closure attributeFilter) + { + // need to create a map and a list of nodes (which will be children) from the + // attribute list. + Map attributes = [:] + List nodes = [] + node.each { + if (nodeFilter == null || nodeFilter.call(it) == true) + { + if (it.name() == 'attributelist') + { + Tuple results = transformSwigAttributeList(it) + attributes.putAll(results[0].findAll(attributeFilter)) + List childNodes = results[1] + childNodes.each { + if (nodeFilter != null && nodeFilter.call(it) == true) + nodes.add(transform(it,nodeFilter,attributeFilter)) + } + } + else + nodes.add(transform(it,nodeFilter,attributeFilter)) + } + } + + // transfer the addr attribute from the original node over to the 'id' attribute of the + // new node by adding it to the attributes map + if (node.@addr) + { + // copy over the other attributes + node.attributes().findAll { key,value -> if (key != 'addr' && key != 'id') attributes[key] = value } + attributes['id'] = node.@addr + } + + // In the case when the Node is a cdecl, we really want to replace the node name + // with the 'kind' attribute value. + Node ret + if (node.name() == 'cdecl' && attributes.containsKey('kind')) + ret = new Node(null, attributes['kind'], attributes.findAll({key, value -> key != 'kind' } )) + else + ret = new Node(null, node.name(), attributes) + nodes.each { ret.append(it) } + return ret + } + + private static Tuple transformSwigAttributeList(Node attributeList) + { + Map attributes = [:] + List nodes = [] + attributeList.each { + if (it.name() == 'attribute') + attributes[it.@name] = it.@value + else + nodes.add(it) + } + return [attributes, nodes] + } +} + diff --git a/tools/codegenerator/SwigTypeParser.groovy b/tools/codegenerator/SwigTypeParser.groovy new file mode 100644 index 0000000..24dfa8f --- /dev/null +++ b/tools/codegenerator/SwigTypeParser.groovy @@ -0,0 +1,617 @@ +/* + * Copyright (C) 2005-2013 Team XBMC + * http://xbmc.org + * + * 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, 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 XBMC; see the file COPYING. If not, see + * <http://www.gnu.org/licenses/>. + * + */ + +import groovy.xml.XmlParser + +/** + * These methods are somewhat ugly because they have been copied out of + * the Swig source code and simply made compilable with groovy. They could + * all be much cleaner and smaller if they were completely groovyfied but + * I have no intention of doing that since they are complicated and they work + * and I don't want to try to trace down problems that would be inevitable + * with such a refactor. + */ +public class SwigTypeParser +{ + /** + * This holds a mapping for typedefs from a type to it's base type. + */ + private static Map typeTable = [:] + + /** + * Add a typedef node to the global list of typedefs to be used later in + * parsing types. + */ + public static void appendTypeTable(Node typetab) { typetab.each { typeTable[it.@namespace + it.@type] = it.@basetype } } + + /** + * Convert the type to an ltype considering the overloaded conversions. + */ + public static String convertTypeToLTypeForParam(String ty) + { + // in the case where we're converting from a type to an ltype for a parameter, + // and the type is a r.*, we are going to assume the ltype is + // a "pass-by-value" on the stack. + return (ty.trim().startsWith('r.') ? SwigTypeParser.SwigType_ltype(ty.trim().substring(2)) : SwigTypeParser.SwigType_ltype(ty.trim())) + } + + /** + * This method will return the base type for the provided type string. For example, + * if the type string is p.MyType you will get MyType. If the string is + * p.q(const).int you will get 'int' + */ + public static String getRootType(String ty) + { + int li = ty.lastIndexOf('.') + return li >= 0 ? ty.substring(li + 1) : ty + } + + /** + * SwigType_str() + * + * Create a C string representation of a datatype. + */ + public static String SwigType_str(String ty, String id = null) + { + String result = id ? id : '' + String nextelement + String forwardelement + List elements = SwigType_split(ty) + if (elements == null) elements = [] + int nelements = elements.size() + String element = nelements > 0 ? elements[0] : null + + /* Now, walk the type list and start emitting */ + for (int i = 0; i < nelements; i++) { + if (i < (nelements - 1)) { + nextelement = elements[i + 1] + forwardelement = nextelement + if (nextelement.startsWith('q(')) { + if (i < (nelements - 2)) forwardelement = elements[i + 2] + } + } else { + nextelement = null + forwardelement = null + } + if (element.startsWith('q(')) { + String q = SwigType_parm(element) + result = q + ' ' + result + } else if (SwigType_ispointer(element)) { + result = "*" + result + if ((forwardelement) && ((SwigType_isfunction(forwardelement) || (SwigType_isarray(forwardelement))))) { + result = "(" + result + ")" + } + } else if (SwigType_ismemberpointer(element)) { + String q = SwigType_parm(element); + result = q + "::*" + result + if ((forwardelement) && ((SwigType_isfunction(forwardelement) || (SwigType_isarray(forwardelement))))) { + result = '(' + result + ')' + } + } else if (SwigType_isreference(element)) { + result = '&' + result + if ((forwardelement) && ((SwigType_isfunction(forwardelement) || (SwigType_isarray(forwardelement))))) { + result = '(' + result + ')' + } + } else if (SwigType_isarray(element)) { + result += '[' + SwigType_parm(element) + ']' + } else if (SwigType_isfunction(element)) { + result += '(' + List parms = SwigType_parmlist(element) + boolean didOne = false + for (String cur : parms) { + String p = SwigType_str(cur) + result += (didOne ? ',' : '') + p + didOne = true + } + result += ')' + } else { + if (element.startsWith("v(...)")) result = result + "..." + else { + String bs = SwigType_namestr(element); + result = bs + ' ' + result + } + } + element = nextelement; + } + // convert template parameters + return result.replaceAll('<\\(', '<').replaceAll('\\)>', '>') + } + + /** + * This will resolve the typedefs given the parameter passed is a simple type. + * see SwigType_resolve_all_typedefs which will handle qualifiers, pointers, + * references, and typedef of typedefs to resolve all the way down to the + * most basic types. + */ + public static String SwigType_typedef_resolve(String t) + { + String td = typeTable[t] + String ret = td == null ? t : td + return ret + } + + /** + * This will resolve typedefs and handle qualifiers, pointers, + * references, and typedef of typedefs to resolve all the way down to the + * most basic types. + */ + public static String SwigType_resolve_all_typedefs(String s) + { + String result = '' + String tc = s + + /* Nuke all leading qualifiers, appending them to the result*/ + while (SwigType_isqualifier(tc)) { + List tmpl = SwigType_pop(tc) + tc = tmpl[1] + result += tmpl[0] + } + + if (SwigType_issimple(tc)) { + /* Resolve any typedef definitions */ + String tt = tc + String td + while ((td = SwigType_typedef_resolve(tt)) != tt) { + if (td != tt) { + tt = td + break + } + else if (td != tt) tt = td + } + tc = td + + return tc + } + + List tmpl = SwigType_pop(tc) + result += tmpl[0] + result += SwigType_resolve_all_typedefs(tmpl[1]) + return result + } + + /** + * SwigType_ltype(const SwigType *ty) + * + * Create a locally assignable type + */ + public static String SwigType_ltype(String s) { + String result = '' + String tc = s + + /* Nuke all leading qualifiers */ + while (SwigType_isqualifier(tc)) { + tc = SwigType_pop(tc)[1] + } + + if (SwigType_issimple(tc)) { + /* Resolve any typedef definitions */ + String tt = tc + String td + while ((td = SwigType_typedef_resolve(tt)) != tt) { + if ((td != tt) && (SwigType_isconst(td) || SwigType_isarray(td) || SwigType_isreference(td))) { + /* We need to use the typedef type */ + tt = td + break + } + else if (td != tt) tt = td + } + tc = td + } + List elements = SwigType_split(tc) + int nelements = elements.size() + + /* Now, walk the type list and start emitting */ + boolean notypeconv = false + boolean firstarray = true + for (int i = 0; i < nelements; i++) { + String element = elements[i] + /* when we see a function, we need to preserve the following types */ + if (SwigType_isfunction(element)) { + notypeconv = true + } + if (SwigType_isqualifier(element)) { + /* Do nothing. Ignore */ + } else if (SwigType_ispointer(element)) { + result += element + // this is a bit of a short circuit to avoid having to import the entire SwigType_typedef_resolve method which + // handles pointers to typedefed types, etc. + // collapse the rest of the list + String tmps = '' + for (int j = i + 1; j < nelements; j++) tmps += elements[j] + return result + SwigType_ltype(tmps) + //firstarray = false + } else if (SwigType_ismemberpointer(element)) { + result += element + firstarray = false + } else if (SwigType_isreference(element)) { + if (notypeconv) { + result += element + } else { + result += "p." + } + firstarray = false + } else if (SwigType_isarray(element) && firstarray) { + if (notypeconv) { + result += element + } else { + result += "p." + } + firstarray = false; + } else if (SwigType_isenum(element)) { + boolean anonymous_enum = (element == "enum ") + if (notypeconv || !anonymous_enum) { + result += element + } else { + result += "int" + } + } else { + result += element + } + } + + return result + // convert template parameters + //return result.replaceAll('<\\(', '<').replaceAll('\\)>', '>') + } + + /** + * SwigType_lrtype(const SwigType *ty) + * + * Create a locally assignable reference type + */ + public static String SwigType_lrtype(String s) { + String ltype = SwigType_ltype(s); + if (SwigType_ispointer(s)) { + return ltype; + } else { + return "r." + ltype; + } + } + + /** + * This creates the C++ declaration for a valid ltype for the type string + * given. For example, if the type is a "const char*" which is equivalent + * to the type string 'p.q(const).char', the return value from this method + * will be "char *". + */ + public static String SwigType_lstr(String type) + { + return SwigType_str(convertTypeToLTypeForParam(type)) + } + + public static boolean SwigType_ispointer(String t) + { + if (t.startsWith('q(')) t = t.substring(t.indexOf('.') + 1) + return t.startsWith('p.') + } + + public static String SwigType_makepointer(String t) + { + String prefix = (t.startsWith('q(')) ? t.substring(0,t.indexOf('.') + 1) : "" + String remainder = (t.startsWith('q(')) ? t.substring(t.indexOf('.') + 1) : t + + return prefix + "p." + remainder + } + + public static boolean SwigType_isarray(String t) { return t.startsWith('a(') } + + public static boolean SwigType_ismemberpointer(String t) { return t?.startsWith('m(') } + + public static boolean SwigType_isqualifier(String t) { return t?.startsWith('q(') } + + public static boolean SwigType_isreference(String t) { return t.startsWith('r.') } + + public static boolean SwigType_isenum(String t) { return t.startsWith('enum') } + + public static String SwigType_istemplate(String t) { + int c = t.indexOf("<(") + return (c >= 0 && t.indexOf(')>',c+2) >= 0) + } + + public static boolean SwigType_isfunction(String t) + { + if (t.startsWith('q(')) t = t.substring(t.indexOf('.') + 1,) + return t.startsWith('f(') + } + + public static boolean SwigType_isconst(String t) { + int c = 0 + if (t == null) return false + if (t.substring(c).startsWith("q(")) { + String q = SwigType_parm(t) + if (q.indexOf("const") >= 0) return true + } + /* Hmmm. Might be const through a typedef */ + if (SwigType_issimple(t)) { + String td = SwigType_typedef_resolve(t) + if (td != t) return SwigType_isconst(td) + } + return false + } + + + private static String SwigType_parm(String t) { + int start = t.indexOf("(") + if (start < 0) return null + start++ + int nparens = 0 + int c = start + while (c < t.length()) { + if (t.charAt(c) == ')') { + if (nparens == 0) break; + nparens--; + } + else if (t.charAt(c) == '(') nparens++ + c++; + } + return t.substring(start,c) + } + + public static List SwigType_templateparmlist(String t) + { + int i = t.indexOf('<'); + return SwigType_parmlist(t.substring(i)) + } + + /* ----------------------------------------------------------------------------- + * SwigType_parmlist() + * + * Splits a comma separated list of parameters into its component parts + * The input is expected to contain the parameter list within () brackets + * Returns 0 if no argument list in the input, ie there are no round brackets () + * Returns an empty List if there are no parameters in the () brackets + * For example: + * + * Foo(std::string,p.f().Bar<(int,double)>) + * + * returns 2 elements in the list: + * std::string + * p.f().Bar<(int,double)> + * ----------------------------------------------------------------------------- */ + + private static List SwigType_parmlist(String p) { + List list = [] + int itemstart + + assert p, "Cannot pass null to SwigType_parmlist" + itemstart = p.indexOf('(') + assert p.indexOf('.') == -1 || p.indexOf('.') > itemstart, p + " is expected to contain sub elements of a type" + itemstart++ + int c = itemstart + while (c < p.length()) { + if (p.charAt(c) == ',') { + list.add(p.substring(itemstart,c)) + itemstart = c + 1 + } else if (p.charAt(c) == '(') { + int nparens = 1 + c++ + while (c < p.length()) { + if (p.charAt(c) == '(') nparens++ + if (p.charAt(c) == ')') { + nparens-- + if (nparens == 0) break + } + c++ + } + } else if (p.charAt(c) == ')') { + break; + } + if (c < p.length()) c++ + } + + if (c != itemstart) { + list.add(p.substring(itemstart,c)) + } + return list; + } + + /* ----------------------------------------------------------------------------- + * SwigType_namestr() + * + * Returns a string of the base type. Takes care of template expansions + * ----------------------------------------------------------------------------- */ + + private static String SwigType_namestr(String t) { + int d = 0 + int c = t.indexOf("<(") + + if (c < 0 || t.indexOf(')>',c+2) < 0) return t + + String r = t.substring(0,c) + if (t.charAt(c - 1) == '<') r += ' ' + r += '<' + + List p = SwigType_parmlist(t.substring(c + 1)) + for (int i = 0; i < p.size(); i++) { + String str = SwigType_str(p[i], null); + /* Avoid creating a <: token, which is the same as [ in C++ - put a space after '<'. */ + if (i == 0 && str.length() > 0) r += ' ' + r += str + if ((i + 1) < p.size()) r += ',' + } + r += ' >' + String suffix = SwigType_templatesuffix(t); + if (suffix.length() > 0) { + String suffix_namestr = SwigType_namestr(suffix); + r += suffix_namestr + } else { + r += suffix + } + return r; + } + + /* ----------------------------------------------------------------------------- + * SwigType_templatesuffix() + * + * Returns text after a template substitution. Used to handle scope names + * for example: + * + * Foo<(p.int)>::bar + * + * returns "::bar" + * ----------------------------------------------------------------------------- */ + + private static String SwigType_templatesuffix(String t) { + int c = 0 + while (c < t.length()) { + if ((t.charAt(c) == '<') && (t.charAt(c + 1) == '(')) { + int nest = 1 + c++ + while (c < t.length() && nest != 0) { + if (t.charAt(c) == '<') nest++ + if (t.charAt(c) == '>') nest-- + c++ + } + return t.substring(c) + } + c++ + } + return '' + } + + /* ----------------------------------------------------------------------------- + * SwigType_split() + * + * Splits a type into it's component parts and returns a list of string. + * ----------------------------------------------------------------------------- */ + + private static List SwigType_split(String t) { + List list = [] + int c = 0 + int len + + while (c < t.length()) { + len = element_size(t.substring(c)) + String item = t.substring(c,c + len) + list += item + c = c + len + if (c < t.length() && t.charAt(c) == '.') c++ + } + return list; + } + + /* ----------------------------------------------------------------------------- + * static element_size() + * + * This utility function finds the size of a single type element in a type string. + * Type elements are always delimited by periods, but may be nested with + * parentheses. A nested element is always handled as a single item. + * + * Returns the integer size of the element (which can be used to extract a + * substring, to chop the element off, or for other purposes). + * ----------------------------------------------------------------------------- */ + + private static int element_size(String s) { + int nparen + int c = 0 + while (c < s.length()) { + if (s.charAt(c) == '.') { + c++ + return c + } else if (s.charAt(c) == '(') { + nparen = 1 + c++ + while (c < s.length()) { + if (s.charAt(c) == '(') nparen++ + if (s.charAt(c) == ')') { + nparen-- + if (nparen == 0) break + } + c++ + } + } + if (c < s.length()) c++ + } + return c; + } + + /* ----------------------------------------------------------------------------- + * SwigType_pop() + * + * Pop one type element off the type. + * Example: t in: q(const).p.Integer + * t out: p.Integer + * result: q(const). + * ----------------------------------------------------------------------------- */ + + private static Tuple SwigType_pop(String t) { + String result + int c = 0 + + if (t == null) + return null + + int sz = element_size(t.substring(c)) + return [ t.substring(c,c + sz), t.substring(c+sz) ] + } + + private static boolean SwigType_issimple(String t) { + int c = 0 + if (!t) return false + while (c < t.length()) { + if (t.charAt(c) == '<') { + int nest = 1 + c++ + while (c < t.length() && nest != 0) { + if (t.charAt(c) == '<') nest++ + if (t.charAt(c) == '>') nest-- + c++ + } + c-- + } + if (t.charAt(c) == '.') + return false + c++ + } + return true + } + + + public static void main(String[] args) + { + String xmlText = ''' + <typetab> + <entry basetype="std::vector<(p.XBMCAddon::xbmcgui::ListItem)>" type="ListItemList" namespace="XBMCAddon::xbmcgui::"/> + </typetab> + ''' + Node xml = new XmlParser().parseText(xmlText) + + SwigTypeParser.appendTypeTable(xml) + + // testPrint('f(int,int,int)','foo') + // testPrint('p.a(10).p.f(int,p.f(int).int)','foo') + // testPrint('p.q(const).char','foo') + // testPrint('f(r.q(const).String,p.q(const).XBMCAddon::xbmcgui::ListItem,bool)','foo') + // testPrint('r.q(const).String','foo') + // testPrint('q(const).p.q(const).char','foo') + //testPrint('std::vector<(p.String)>','foo') + // testPrint('r.q(const).String') + //System.out.println "${convertTypeToLType('bool')}" + //testPrint('p.q(const).XBMCAddon::xbmcgui::ListItemList') + //testPrint('p.q(const).XBMCAddon::xbmcgui::ListItemList') + //testPrint(SwigTypeParser.SwigType_makepointer('r.q(const).std::map<(String,String)>'), 'foo') + testPrint(SwigTypeParser.SwigType_makepointer('q(const).p.q(const).char'),'bfoo') + } + + private static void testPrint(String ty, String id = 'foo') + { + println SwigTypeParser.SwigType_ltype(ty) + "|" + SwigTypeParser.SwigType_str(SwigTypeParser.SwigType_ltype(ty),id) + ' ' + " = " + ty + '|' + SwigTypeParser.SwigType_str(ty,id) + } +} diff --git a/tools/codegenerator/example/AddonModuleXbmc.i b/tools/codegenerator/example/AddonModuleXbmc.i new file mode 100644 index 0000000..3837828 --- /dev/null +++ b/tools/codegenerator/example/AddonModuleXbmc.i @@ -0,0 +1,11 @@ +/* + * Copyright (C) 2005-2013 Team XBMC + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +%module xbmc + +%include "native/ModuleXbmc.h" diff --git a/tools/codegenerator/example/Example-lval-rval.template b/tools/codegenerator/example/Example-lval-rval.template new file mode 100644 index 0000000..77d506e --- /dev/null +++ b/tools/codegenerator/example/Example-lval-rval.template @@ -0,0 +1,18 @@ +<% +import SwigTypeParser +%> +Module Name: ${module.@name} +<% +module.function.each { functionNode -> +%> + function: ${functionNode.@name} +<% + functionNode.parm.eachWithIndex { param, index -> +%> + parameter ${index}= name:${param.@name}, type:${param.@type}<% if (param.@value) { %>, default value: ${param.@value} <% } %> + type:${SwigTypeParser.SwigType_str(param.@type)} + lvalue-type:${SwigTypeParser.SwigType_lstr(param.@type)} +<% + } +} +%> diff --git a/tools/codegenerator/example/Example.call.template b/tools/codegenerator/example/Example.call.template new file mode 100644 index 0000000..bc17282 --- /dev/null +++ b/tools/codegenerator/example/Example.call.template @@ -0,0 +1,48 @@ +<% +import SwigTypeParser +import Helper + +Helper.setup(null, + [ 'void': 'Py_INCREF(Py_None); ${result} = Py_None;' ], + null, + [ 'p.q(const).char':'${api} = convertSlString(${slarg});', + 'int':'${api} = convertSlInt(${slarg});'], + null) +%> +Module Name: ${module.@name} +<% +module.function.each { functionNode -> +%> + function: ${functionNode.@name} + +<% + functionNode.parm.eachWithIndex { param, index -> +%> + parameter ${index}= name:${param.@name}, type:${param.@type}<% if (param.@value) { %>, default value: ${param.@value} <% } %> + lvalue:${SwigTypeParser.SwigType_lstr(param.@type)} + rvalue:${SwigTypeParser.SwigType_str(param.@type)} + code to handle parameter ${index} { + // declare and set the value that came in from the scripting language + ScriptingLanguageType sl_${param.@name} = /* set the value from the scripting language */; + // declare and set the variable that will contain the api parameter + ${SwigTypeParser.SwigType_lstr(param.@type)} p_${param.@name}; + ${Helper.getInConversion(param.@type,'p_' + param.@name,'sl_' + param.@name, functionNode)} + } +<% + } +%> + code to invoke the api method { + ${Helper.callingName(functionNode)}( <% + functionNode.parm.eachWithIndex { param, i -> + %> p_${param.@name}${i < functionNode.parm.size() - 1 ? "," : ""} <% } %> ); + } + + code to handle return value { + // This is an example of how Python handles return values + Py_Object* result; + ${Helper.getOutConversion(Helper.getReturnSwigType(functionNode),'result',functionNode)} + return result; + } +<% +} +%> diff --git a/tools/codegenerator/example/Example.intypemap.template b/tools/codegenerator/example/Example.intypemap.template new file mode 100644 index 0000000..b64a49c --- /dev/null +++ b/tools/codegenerator/example/Example.intypemap.template @@ -0,0 +1,31 @@ +<% +import SwigTypeParser +import Helper + +Helper.setup(null,null,null, + [ 'p.q(const).char':'${api} = convertSlString(${slarg});', + 'int':'${api} = convertSlInt(${slarg});'], + null) +%> +Module Name: ${module.@name} +<% +module.function.each { functionNode -> +%> + function: ${functionNode.@name} +<% + functionNode.parm.eachWithIndex { param, index -> +%> + parameter ${index}= name:${param.@name}, type:${param.@type}<% if (param.@value) { %>, default value: ${param.@value} <% } %> + type:${SwigTypeParser.SwigType_str(param.@type)} + lvalue-type:${SwigTypeParser.SwigType_lstr(param.@type)} + code to handle parameter ${index} { + // declare and set the value that came in from the scripting language + ScriptingLanguageType sl_${param.@name} = /* set the value from the scripting language */; + // declare and set the variable that will contain the api parameter + ${SwigTypeParser.SwigType_lstr(param.@type)} p_${param.@name}; + ${Helper.getInConversion(param.@type,'p_' + param.@name,'sl_' + param.@name, functionNode)} + } +<% + } +} +%> diff --git a/tools/codegenerator/example/Example.returns.template b/tools/codegenerator/example/Example.returns.template new file mode 100644 index 0000000..9f6f75d --- /dev/null +++ b/tools/codegenerator/example/Example.returns.template @@ -0,0 +1,42 @@ +<% +import SwigTypeParser +import Helper + +Helper.setup(null, + [ 'void': 'Py_INCREF(Py_None); ${result} = Py_None;' ], + null, + [ 'p.q(const).char':'${api} = convertSlString(${slarg});', + 'int':'${api} = convertSlInt(${slarg});'], + null) +%> +Module Name: ${module.@name} +<% +module.function.each { functionNode -> +%> + function: ${functionNode.@name} + +<% + functionNode.parm.eachWithIndex { param, index -> +%> + parameter ${index}= name:${param.@name}, type:${param.@type}<% if (param.@value) { %>, default value: ${param.@value} <% } %> + type:${SwigTypeParser.SwigType_str(param.@type)} + lvalue-type:${SwigTypeParser.SwigType_lstr(param.@type)} + code to handle parameter ${index} { + // declare and set the value that came in from the scripting language + ScriptingLanguageType sl_${param.@name} = /* set the value from the scripting language */; + // declare and set the variable that will contain the api parameter + ${SwigTypeParser.SwigType_lstr(param.@type)} p_${param.@name}; + ${Helper.getInConversion(param.@type,'p_' + param.@name,'sl_' + param.@name, functionNode)} + } +<% + } +%> + code to handle return value { + // This is an example of how Python handles return values + Py_Object* result; + ${Helper.getOutConversion(Helper.getReturnSwigType(functionNode),'result',functionNode)} + return result; + } +<% +} +%> diff --git a/tools/codegenerator/example/native/ModuleXbmc.h b/tools/codegenerator/example/native/ModuleXbmc.h new file mode 100644 index 0000000..14dd80d --- /dev/null +++ b/tools/codegenerator/example/native/ModuleXbmc.h @@ -0,0 +1 @@ +void log(const char* msg, int level = LOGNOTICE); diff --git a/tools/depends/.gitignore b/tools/depends/.gitignore new file mode 100644 index 0000000..4f750fb --- /dev/null +++ b/tools/depends/.gitignore @@ -0,0 +1,51 @@ +/configure +/Makefile.include +/autom4te.cache/ +/**/.gitignore +/**/.installed-* + +/native/*/.installed-* +/native/*/x86-native/* +/native/*/x86_64-linux-gnu-native/* +/native/*/x86_64-darwin*.*.*-native/ +/native/*/*-darwin*.*.*-native/ +/native/*/armeabi-v7a-native/* + +/target/*/.installed-* +/target/*/native/* +/target/*/x86/* +/target/*/x86_64-linux-android-** +/target/*/x86_64-linux-gnu-** +/target/*/armeabi-v7a-** +/target/*/arm*-linux-gnueabihf-** +/target/*/arm*-linux-androideabi-** +/target/*/arm*-linux-gnueabi-** +/target/*/aarch64-linux-** +/target/*/macosx*-target-** +/target/*/i686-linux-android-** +/target/*/iphoneos*.*_arm*-target-** +/target/*/iphonesimulator*.*_x86_64*-target-** +/target/*/appletvos*.*_arm64*-target-** +/target/*/appletvsimulator*.*_x86_64*-target-** + +/pre-depends/ +/pre-build-deps/ +Toolchain.cmake +Toolchain-Native.cmake +config.site +config.site.native +/native/*/*native/ +/JsonSchemaBuilder/bin/ +/TexturePacker/bin/ +/target/ffmpeg/.build-* +/target/ffmpeg/.ffmpeg-installed +/target/ffmpeg/ffmpeg-*-*.tar.gz +/target/ffmpeg/ffmpeg-*-*/ +/tools/depends/target/ffmpeg/ffmpeg-install/ +/tools/depends/target/Toolchain_binaddons.cmake +/tools/depends/target/config-binaddons.site +/target/cross-file.meson +/target/libfmt/fmt-*.tar.gz +/target/rapidjson/rapidjson-*.tar.gz +/target/flatbuffers/*.tar.gz +/target/libspdlog/spdlog-*.tar.gz diff --git a/tools/depends/Makefile b/tools/depends/Makefile new file mode 100644 index 0000000..8f53370 --- /dev/null +++ b/tools/depends/Makefile @@ -0,0 +1,25 @@ +include Makefile.include + +NATIVE=native/.installed-$(NATIVEPLATFORM) +target=target/.installed-$(PLATFORM) +all: $(target) + +$(NATIVE): + $(MAKE) -C native + +$(target): $(NATIVE) + $(MAKE) -C target + +clean: + $(MAKE) -C native clean + $(MAKE) -C target clean + +test-dependencies: + $(MAKE) -C native test-dependencies + $(MAKE) -C native + $(MAKE) -C target test-dependencies + +distclean:: + $(MAKE) -C native distclean + $(MAKE) -C target distclean + diff --git a/tools/depends/Makefile.include.in b/tools/depends/Makefile.include.in new file mode 100644 index 0000000..3a36d20 --- /dev/null +++ b/tools/depends/Makefile.include.in @@ -0,0 +1,127 @@ +abs_top_srcdir=@abs_top_srcdir@ + +DEBUG_BUILD=@use_debug@ +TOOLCHAIN=@use_toolchain@ +NDKROOT=@use_ndk_path@ +SDKROOT=@use_sdk_path@ +CMAKE_SOURCE_DIR=$(abspath $(abs_top_srcdir)/../../) +TARBALLS_LOCATION=@use_tarballs@ +PLATFORM=@deps_dir@ +HOST=@use_host@ +BUILD=@use_build@ +BUILD_CPU=@use_buildcpu@ +CPU=@use_cpu@ +MESON_CPU=@meson_cpu@ +MESON_SYSTEM=@meson_system@ +NATIVEPLATFORM=@build_cpu@-@build_os@-native +NDK_LEVEL=@use_ndk_api@ +RETRIEVE_TOOL=@CURL@ +ARCHIVE_TOOL=@TAR@ +PREFIX=@prefix@/@deps_dir@ +NATIVEPREFIX=@prefix@/@tool_dir@ +OS=@platform_os@ +NATIVE_OS=@build_os@ +CROSS_COMPILING=@cross_compiling@ +ARCH_DEFINES=@ARCH_DEFINES@ +NATIVE_ARCH_DEFINES=@NATIVE_ARCH_DEFINES@ +TARGET_PLATFORM=@target_platform@ +RENDER_SYSTEM=@app_rendersystem@ +WINDOW_SYSTEM=@app_winsystem@ +SHA512SUM=@SHA512SUM@ +SHA256SUM=@SHA256SUM@ +SHASUM=@SHASUM@ +HASH_TOOL_FLAGS=-c --status + +HAS_ZLIB=@has_zlib@ +NEED_LIBICONV=@need_libiconv@ +LINK_ICONV=@link_iconv@ +ENABLE_GPLV3=@use_gplv3@ + +BASE_URL=http://mirrors.kodi.tv/build-deps/sources +ifneq ($(KODI_MIRROR),) +BASE_URL=$(KODI_MIRROR)/build-deps/sources +endif +RETRIEVE_TOOL_FLAGS=-LsS --create-dirs --retry 10 --retry-connrefused -O +ARCHIVE_TOOL_FLAGS=--strip-components=1 -xf +CONFIG_SUB=@prefix@/@tool_dir@/share/automake-1.16/config.sub +CONFIG_GUESS=@prefix@/@tool_dir@/share/automake-1.16/config.guess + +USE_CCACHE=@use_ccache@ + +LD=@LD@ +ifneq (@use_ccache@,yes) + CC=@CC@ + CXX=@CXX@ + CPP=@CPP@ +else + CC=@CCACHE@ @CC@ + CXX=@CCACHE@ @CXX@ + CPP=@CCACHE@ @CPP@ +endif +AR=@AR@ +RANLIB=@RANLIB@ +AS=@AS@ +NM=@NM@ +STRIP=@STRIP@ +READELF=@READELF@ +OBJDUMP=@OBJDUMP@ + +CMAKE=@prefix@/@tool_dir@/bin/cmake -DCMAKE_TOOLCHAIN_FILE=$(PREFIX)/share/Toolchain.cmake -DCMAKE_INSTALL_PREFIX=$(PREFIX) +CFLAGS=@platform_cflags@ @platform_includes@ -isystem @prefix@/@deps_dir@/include +LDFLAGS=-L@prefix@/@deps_dir@/lib @platform_ldflags@ +CXXFLAGS=@platform_cxxflags@ @platform_includes@ -isystem @prefix@/@deps_dir@/include +CPPFLAGS=@platform_cflags@ @platform_includes@ -isystem @prefix@/@deps_dir@/include +# set configured FFmpeg configure options +FFMPEG_CONFIGURE_OPTIONS=@ffmpeg_options@ + + +ifneq (@use_build_toolchain@,) + PATH:=@use_build_toolchain@/bin:@use_build_toolchain@/usr/bin:$(PATH) +endif +PATH:=@prefix@/@tool_dir@/bin:$(PATH) +LD_FOR_BUILD=@LD_FOR_BUILD@ +CC_BINARY_FOR_BUILD=@CC_FOR_BUILD@ +CXX_BINARY_FOR_BUILD=@CXX_FOR_BUILD@ +ifneq (@use_ccache@,yes) + CC_FOR_BUILD=@CC_FOR_BUILD@ + CXX_FOR_BUILD=@CXX_FOR_BUILD@ +else + CC_FOR_BUILD=@CCACHE@ @CC_FOR_BUILD@ + CXX_FOR_BUILD=@CCACHE@ @CXX_FOR_BUILD@ + CCACHE=@CCACHE@ +endif +AR_FOR_BUILD=@AR_FOR_BUILD@ +RANLIB_FOR_BUILD=@RANLIB_FOR_BUILD@ +AS_FOR_BUILD=@AS_FOR_BUILD@ +NM_FOR_BUILD=@NM_FOR_BUILD@ +STRIP_FOR_BUILD=@STRIP_FOR_BUILD@ +READELF_FOR_BUILD=@READELF_FOR_BUILD@ +OBJDUMP_FOR_BUILD=@OBJDUMP_FOR_BUILD@ + +NATIVE_CFLAGS=@host_includes@ -I@prefix@/@tool_dir@/include +NATIVE_LDFLAGS=@host_includes@ -L@prefix@/@tool_dir@/lib +NATIVE_CPPFLAGS=@host_includes@ -I@prefix@/@tool_dir@/include +NATIVE_CXXFLAGS=@host_includes@ -I@prefix@/@tool_dir@/include + +VERSION.TXT := $(CMAKE_SOURCE_DIR)/version.txt +APP_NAME=$(shell awk '/APP_NAME/ {print tolower($$2)}' $(VERSION.TXT)) + +# Python related vars +PYTHON_VERSION=3.11 +PYTHON_SITE_PKG=@prefix@/@deps_dir@/lib/python${PYTHON_VERSION}/site-packages + +ifeq ($(CPU), arm64) + export GASPP_FIX_XCODE5=1 +endif +export AUTOM4TE=@prefix@/@tool_dir@/bin/autom4te +export AUTOMAKE=@prefix@/@tool_dir@/bin/automake +export AUTOCONF=@prefix@/@tool_dir@/bin/autoconf +export ACLOCAL=@prefix@/@tool_dir@/bin/aclocal +export ACLOCAL_PATH=@prefix@/@deps_dir@/share/aclocal:@prefix@/@tool_dir@/share/aclocal +export AUTOPOINT=@prefix@/@tool_dir@/bin/autopoint +export AUTOHEADER=@prefix@/@tool_dir@/bin/autoheader +export LIBTOOL=@prefix@/@tool_dir@/bin/libtool +export LIBTOOLIZE=@prefix@/@tool_dir@/bin/libtoolize + +export AUTORECONF=@prefix@/@tool_dir@/bin/autoreconf +export JSON_BUILDER=$(NATIVEPREFIX)/bin/JsonSchemaBuilder diff --git a/tools/depends/README.md b/tools/depends/README.md new file mode 100644 index 0000000..64fb3f0 --- /dev/null +++ b/tools/depends/README.md @@ -0,0 +1,56 @@ +![Kodi Logo](../../docs/resources/banner_slim.png) + +# Kodi's Unified Depends Build System +This builds native tools and library dependencies for platforms that do not provide them. It is used on our continuous integration system, **[jenkins](http://jenkins.kodi.tv/)**. A nice side effect is that it allows us to use the same tools and library versions across all platforms. + +In terms of build system usage, largest percentage is Autotools, followed by CMake and, in rare cases, hand crafted Makefiles. Tools and libraries versions are picked for a reason. If you feel the urge to start bumping them, be prepared for robust testing. Some tools and libraries need patching, most do not. + +That said, we try to stay fairly current with used versions and send patches upstream whenever possible. + + +* **Autotools driven tools and libraries** tend to just work **provided** the author(s) followed proper Autotools format. Execute `./bootstrap`, followed by `./configure --[...]` and you're all set. If `./configure --[...]` gives you problems, try `./autoreconf -vif` before `./configure --[...]`. +Some authors do silly things and only a `config.site` can correct the errors. Watch for this in the config.site(.in) file(s). It is the only way to handle bad Autotools behaviour. + +* **CMake driven tools and libraries** also tend to just work. Setup CMake flags correctly and go. On rare cases, you might need to diddle the native CMake setup. + +* **Hand crafted Makefiles driven tools and libraries** typically require manual sed tweaks or patching. May give you nightmares. + +## Usage Examples +Paths below are examples. If you want to build Kodi, follow our **[build guides](../../docs/README.md)**. +### All platforms +`./bootstrap` +### Darwin +**macOS (x86_64)** +`./configure --host=x86_64-apple-darwin` + +**iOS (arm64)** +`./configure --host=aarch64-apple-darwin` + +**tvOS** +`./configure --host=aarch64-apple-darwin --with-platform=tvos` + +**NOTE:** You can target the same `--prefix=` path. Each setup will be done in an isolated directory. The last configure/make you do is the one used for Kodi/Xcode. + +### Android +**arm** +`./configure --with-tarballs=$HOME/android-tools/xbmc-tarballs --host=arm-linux-androideabi --with-sdk-path=$HOME/android-tools/android-sdk-linux --with-ndk-path=$HOME/android-tools/android-ndk-r20 --prefix=$HOME/android-tools/xbmc-depends` + +**aarch64** +`./configure --with-tarballs=$HOME/android-tools/xbmc-tarballs --host=aarch64-linux-android --with-sdk-path=$HOME/android-tools/android-sdk-linux --with-ndk-path=$HOME/android-tools/android-ndk-r20 --prefix=$HOME/android-tools/xbmc-depends` + +**x86** +`./configure --with-tarballs=$HOME/android-tools/xbmc-tarballs --host=i686-linux-android --with-sdk-path=$HOME/android-tools/android-sdk-linux --with-ndk-path=$HOME/android-tools/android-ndk-r20 --prefix=$HOME/android-tools/xbmc-depends` + +**x86_64** +`./configure --with-tarballs=$HOME/android-tools/xbmc-tarballs --host=x86_64-linux-android --with-sdk-path=$HOME/android-tools/android-sdk-linux --with-ndk-path=$HOME/android-tools/android-ndk-r20 --prefix=$HOME/android-tools/xbmc-depends` + +> **Note:** Android x86 and x86_64 are not maintained and are not 100% sure that everything works correctly! + +### Linux +**ARM (codesourcery/lenaro/etc)** +`./configure --with-toolchain=/opt/toolchains/my-example-toolchain/ --prefix=/opt/xbmc-deps --host=arm-linux-gnueabi --with-rendersystem=gles` + +**Native** +`./configure --with-toolchain=/usr --prefix=/opt/xbmc-deps --host=x86_64-linux-gnu --with-rendersystem=gl` + +Cross compiling is a PITA. diff --git a/tools/depends/bootstrap b/tools/depends/bootstrap new file mode 100755 index 0000000..9f03bce --- /dev/null +++ b/tools/depends/bootstrap @@ -0,0 +1,12 @@ +#!/bin/sh + +# Some platforms may not have m4/autoconf. If not, build temporary copies in +# order to bootstrap. +DEPENDS=`dirname $0` +export PATH="$DEPENDS/pre-build-deps/bin:$PATH" +which m4 >/dev/null 2>/dev/null || make -C $DEPENDS/pre-depends/m4-pre-depends +which autoconf >/dev/null 2>/dev/null || make -C $DEPENDS/pre-depends/autoconf-pre-depends +which autoconf >/dev/null 2>/dev/null || \ + (echo "autoconf was not found and could not be built. Aborting." && exit 1) + +autoconf -f diff --git a/tools/depends/build-aux/config.guess b/tools/depends/build-aux/config.guess new file mode 100644 index 0000000..c4bd827 --- /dev/null +++ b/tools/depends/build-aux/config.guess @@ -0,0 +1,1456 @@ +#! /bin/sh +# Attempt to guess a canonical system name. +# Copyright 1992-2016 Free Software Foundation, Inc. + +timestamp='2016-05-15' + +# 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 3 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, see <http://www.gnu.org/licenses/>. +# +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that +# program. This Exception is an additional permission under section 7 +# of the GNU General Public License, version 3 ("GPLv3"). +# +# Originally written by Per Bothner; maintained since 2000 by Ben Elliston. +# +# You can get the latest version of this script from: +# http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess +# +# Please send patches to <config-patches@gnu.org>. + + +me=`echo "$0" | sed -e 's,.*/,,'` + +usage="\ +Usage: $0 [OPTION] + +Output the configuration name of the system \`$me' is run on. + +Operation modes: + -h, --help print this help, then exit + -t, --time-stamp print date of last modification, then exit + -v, --version print version number, then exit + +Report bugs and patches to <config-patches@gnu.org>." + +version="\ +GNU config.guess ($timestamp) + +Originally written by Per Bothner. +Copyright 1992-2016 Free Software Foundation, Inc. + +This is free software; see the source for copying conditions. There is NO +warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." + +help=" +Try \`$me --help' for more information." + +# Parse command line +while test $# -gt 0 ; do + case $1 in + --time-stamp | --time* | -t ) + echo "$timestamp" ; exit ;; + --version | -v ) + echo "$version" ; exit ;; + --help | --h* | -h ) + echo "$usage"; exit ;; + -- ) # Stop option processing + shift; break ;; + - ) # Use stdin as input. + break ;; + -* ) + echo "$me: invalid option $1$help" >&2 + exit 1 ;; + * ) + break ;; + esac +done + +if test $# != 0; then + echo "$me: too many arguments$help" >&2 + exit 1 +fi + +trap 'exit 1' 1 2 15 + +# CC_FOR_BUILD -- compiler used by this script. Note that the use of a +# compiler to aid in system detection is discouraged as it requires +# temporary files to be created and, as you can see below, it is a +# headache to deal with in a portable fashion. + +# Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still +# use `HOST_CC' if defined, but it is deprecated. + +# Portable tmp directory creation inspired by the Autoconf team. + +set_cc_for_build=' +trap "exitcode=\$?; (rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null) && exit \$exitcode" 0 ; +trap "rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null; exit 1" 1 2 13 15 ; +: ${TMPDIR=/tmp} ; + { tmp=`(umask 077 && mktemp -d "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } || + { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir $tmp) ; } || + { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir $tmp) && echo "Warning: creating insecure temp directory" >&2 ; } || + { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } ; +dummy=$tmp/dummy ; +tmpfiles="$dummy.c $dummy.o $dummy.rel $dummy" ; +case $CC_FOR_BUILD,$HOST_CC,$CC in + ,,) echo "int x;" > $dummy.c ; + for c in cc gcc c89 c99 ; do + if ($c -c -o $dummy.o $dummy.c) >/dev/null 2>&1 ; then + CC_FOR_BUILD="$c"; break ; + fi ; + done ; + if test x"$CC_FOR_BUILD" = x ; then + CC_FOR_BUILD=no_compiler_found ; + fi + ;; + ,,*) CC_FOR_BUILD=$CC ;; + ,*,*) CC_FOR_BUILD=$HOST_CC ;; +esac ; set_cc_for_build= ;' + +# This is needed to find uname on a Pyramid OSx when run in the BSD universe. +# (ghazi@noc.rutgers.edu 1994-08-24) +if (test -f /.attbin/uname) >/dev/null 2>&1 ; then + PATH=$PATH:/.attbin ; export PATH +fi + +UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown +UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown +UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown +UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown + +case "${UNAME_SYSTEM}" in +Linux|GNU|GNU/*) + # If the system lacks a compiler, then just pick glibc. + # We could probably try harder. + LIBC=gnu + + eval $set_cc_for_build + cat <<-EOF > $dummy.c + #include <features.h> + #if defined(__UCLIBC__) + LIBC=uclibc + #elif defined(__dietlibc__) + LIBC=dietlibc + #else + LIBC=gnu + #endif + EOF + eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^LIBC' | sed 's, ,,g'` + ;; +esac + +# Note: order is significant - the case branches are not exclusive. + +case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in + *:NetBSD:*:*) + # NetBSD (nbsd) targets should (where applicable) match one or + # more of the tuples: *-*-netbsdelf*, *-*-netbsdaout*, + # *-*-netbsdecoff* and *-*-netbsd*. For targets that recently + # switched to ELF, *-*-netbsd* would select the old + # object file format. This provides both forward + # compatibility and a consistent mechanism for selecting the + # object file format. + # + # Note: NetBSD doesn't particularly care about the vendor + # portion of the name. We always set it to "unknown". + sysctl="sysctl -n hw.machine_arch" + UNAME_MACHINE_ARCH=`(uname -p 2>/dev/null || \ + /sbin/$sysctl 2>/dev/null || \ + /usr/sbin/$sysctl 2>/dev/null || \ + echo unknown)` + case "${UNAME_MACHINE_ARCH}" in + armeb) machine=armeb-unknown ;; + arm*) machine=arm-unknown ;; + sh3el) machine=shl-unknown ;; + sh3eb) machine=sh-unknown ;; + sh5el) machine=sh5le-unknown ;; + earmv*) + arch=`echo ${UNAME_MACHINE_ARCH} | sed -e 's,^e\(armv[0-9]\).*$,\1,'` + endian=`echo ${UNAME_MACHINE_ARCH} | sed -ne 's,^.*\(eb\)$,\1,p'` + machine=${arch}${endian}-unknown + ;; + *) machine=${UNAME_MACHINE_ARCH}-unknown ;; + esac + # The Operating System including object format, if it has switched + # to ELF recently (or will in the future) and ABI. + case "${UNAME_MACHINE_ARCH}" in + earm*) + os=netbsdelf + ;; + arm*|i386|m68k|ns32k|sh3*|sparc|vax) + eval $set_cc_for_build + if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \ + | grep -q __ELF__ + then + # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout). + # Return netbsd for either. FIX? + os=netbsd + else + os=netbsdelf + fi + ;; + *) + os=netbsd + ;; + esac + # Determine ABI tags. + case "${UNAME_MACHINE_ARCH}" in + earm*) + expr='s/^earmv[0-9]/-eabi/;s/eb$//' + abi=`echo ${UNAME_MACHINE_ARCH} | sed -e "$expr"` + ;; + esac + # The OS release + # Debian GNU/NetBSD machines have a different userland, and + # thus, need a distinct triplet. However, they do not need + # kernel version information, so it can be replaced with a + # suitable tag, in the style of linux-gnu. + case "${UNAME_VERSION}" in + Debian*) + release='-gnu' + ;; + *) + release=`echo ${UNAME_RELEASE} | sed -e 's/[-_].*//' | cut -d. -f1,2` + ;; + esac + # Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM: + # contains redundant information, the shorter form: + # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used. + echo "${machine}-${os}${release}${abi}" + exit ;; + *:Bitrig:*:*) + UNAME_MACHINE_ARCH=`arch | sed 's/Bitrig.//'` + echo ${UNAME_MACHINE_ARCH}-unknown-bitrig${UNAME_RELEASE} + exit ;; + *:OpenBSD:*:*) + UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'` + echo ${UNAME_MACHINE_ARCH}-unknown-openbsd${UNAME_RELEASE} + exit ;; + *:LibertyBSD:*:*) + UNAME_MACHINE_ARCH=`arch | sed 's/^.*BSD\.//'` + echo ${UNAME_MACHINE_ARCH}-unknown-libertybsd${UNAME_RELEASE} + exit ;; + *:ekkoBSD:*:*) + echo ${UNAME_MACHINE}-unknown-ekkobsd${UNAME_RELEASE} + exit ;; + *:SolidBSD:*:*) + echo ${UNAME_MACHINE}-unknown-solidbsd${UNAME_RELEASE} + exit ;; + macppc:MirBSD:*:*) + echo powerpc-unknown-mirbsd${UNAME_RELEASE} + exit ;; + *:MirBSD:*:*) + echo ${UNAME_MACHINE}-unknown-mirbsd${UNAME_RELEASE} + exit ;; + *:Sortix:*:*) + echo ${UNAME_MACHINE}-unknown-sortix + exit ;; + alpha:OSF1:*:*) + case $UNAME_RELEASE in + *4.0) + UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'` + ;; + *5.*) + UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $4}'` + ;; + esac + # According to Compaq, /usr/sbin/psrinfo has been available on + # OSF/1 and Tru64 systems produced since 1995. I hope that + # covers most systems running today. This code pipes the CPU + # types through head -n 1, so we only detect the type of CPU 0. + ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^ The alpha \(.*\) processor.*$/\1/p' | head -n 1` + case "$ALPHA_CPU_TYPE" in + "EV4 (21064)") + UNAME_MACHINE=alpha ;; + "EV4.5 (21064)") + UNAME_MACHINE=alpha ;; + "LCA4 (21066/21068)") + UNAME_MACHINE=alpha ;; + "EV5 (21164)") + UNAME_MACHINE=alphaev5 ;; + "EV5.6 (21164A)") + UNAME_MACHINE=alphaev56 ;; + "EV5.6 (21164PC)") + UNAME_MACHINE=alphapca56 ;; + "EV5.7 (21164PC)") + UNAME_MACHINE=alphapca57 ;; + "EV6 (21264)") + UNAME_MACHINE=alphaev6 ;; + "EV6.7 (21264A)") + UNAME_MACHINE=alphaev67 ;; + "EV6.8CB (21264C)") + UNAME_MACHINE=alphaev68 ;; + "EV6.8AL (21264B)") + UNAME_MACHINE=alphaev68 ;; + "EV6.8CX (21264D)") + UNAME_MACHINE=alphaev68 ;; + "EV6.9A (21264/EV69A)") + UNAME_MACHINE=alphaev69 ;; + "EV7 (21364)") + UNAME_MACHINE=alphaev7 ;; + "EV7.9 (21364A)") + UNAME_MACHINE=alphaev79 ;; + esac + # A Pn.n version is a patched version. + # A Vn.n version is a released version. + # A Tn.n version is a released field test version. + # A Xn.n version is an unreleased experimental baselevel. + # 1.2 uses "1.2" for uname -r. + echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[PVTX]//' | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz` + # Reset EXIT trap before exiting to avoid spurious non-zero exit code. + exitcode=$? + trap '' 0 + exit $exitcode ;; + Alpha\ *:Windows_NT*:*) + # How do we know it's Interix rather than the generic POSIX subsystem? + # Should we change UNAME_MACHINE based on the output of uname instead + # of the specific Alpha model? + echo alpha-pc-interix + exit ;; + 21064:Windows_NT:50:3) + echo alpha-dec-winnt3.5 + exit ;; + Amiga*:UNIX_System_V:4.0:*) + echo m68k-unknown-sysv4 + exit ;; + *:[Aa]miga[Oo][Ss]:*:*) + echo ${UNAME_MACHINE}-unknown-amigaos + exit ;; + *:[Mm]orph[Oo][Ss]:*:*) + echo ${UNAME_MACHINE}-unknown-morphos + exit ;; + *:OS/390:*:*) + echo i370-ibm-openedition + exit ;; + *:z/VM:*:*) + echo s390-ibm-zvmoe + exit ;; + *:OS400:*:*) + echo powerpc-ibm-os400 + exit ;; + arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*) + echo arm-acorn-riscix${UNAME_RELEASE} + exit ;; + arm*:riscos:*:*|arm*:RISCOS:*:*) + echo arm-unknown-riscos + exit ;; + SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*) + echo hppa1.1-hitachi-hiuxmpp + exit ;; + Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*) + # akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE. + if test "`(/bin/universe) 2>/dev/null`" = att ; then + echo pyramid-pyramid-sysv3 + else + echo pyramid-pyramid-bsd + fi + exit ;; + NILE*:*:*:dcosx) + echo pyramid-pyramid-svr4 + exit ;; + DRS?6000:unix:4.0:6*) + echo sparc-icl-nx6 + exit ;; + DRS?6000:UNIX_SV:4.2*:7* | DRS?6000:isis:4.2*:7*) + case `/usr/bin/uname -p` in + sparc) echo sparc-icl-nx7; exit ;; + esac ;; + s390x:SunOS:*:*) + echo ${UNAME_MACHINE}-ibm-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + sun4H:SunOS:5.*:*) + echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*) + echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + i86pc:AuroraUX:5.*:* | i86xen:AuroraUX:5.*:*) + echo i386-pc-auroraux${UNAME_RELEASE} + exit ;; + i86pc:SunOS:5.*:* | i86xen:SunOS:5.*:*) + eval $set_cc_for_build + SUN_ARCH=i386 + # If there is a compiler, see if it is configured for 64-bit objects. + # Note that the Sun cc does not turn __LP64__ into 1 like gcc does. + # This test works for both compilers. + if [ "$CC_FOR_BUILD" != no_compiler_found ]; then + if (echo '#ifdef __amd64'; echo IS_64BIT_ARCH; echo '#endif') | \ + (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \ + grep IS_64BIT_ARCH >/dev/null + then + SUN_ARCH=x86_64 + fi + fi + echo ${SUN_ARCH}-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + sun4*:SunOS:6*:*) + # According to config.sub, this is the proper way to canonicalize + # SunOS6. Hard to guess exactly what SunOS6 will be like, but + # it's likely to be more like Solaris than SunOS4. + echo sparc-sun-solaris3`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + sun4*:SunOS:*:*) + case "`/usr/bin/arch -k`" in + Series*|S4*) + UNAME_RELEASE=`uname -v` + ;; + esac + # Japanese Language versions have a version number like `4.1.3-JL'. + echo sparc-sun-sunos`echo ${UNAME_RELEASE}|sed -e 's/-/_/'` + exit ;; + sun3*:SunOS:*:*) + echo m68k-sun-sunos${UNAME_RELEASE} + exit ;; + sun*:*:4.2BSD:*) + UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null` + test "x${UNAME_RELEASE}" = x && UNAME_RELEASE=3 + case "`/bin/arch`" in + sun3) + echo m68k-sun-sunos${UNAME_RELEASE} + ;; + sun4) + echo sparc-sun-sunos${UNAME_RELEASE} + ;; + esac + exit ;; + aushp:SunOS:*:*) + echo sparc-auspex-sunos${UNAME_RELEASE} + exit ;; + # The situation for MiNT is a little confusing. The machine name + # can be virtually everything (everything which is not + # "atarist" or "atariste" at least should have a processor + # > m68000). The system name ranges from "MiNT" over "FreeMiNT" + # to the lowercase version "mint" (or "freemint"). Finally + # the system name "TOS" denotes a system which is actually not + # MiNT. But MiNT is downward compatible to TOS, so this should + # be no problem. + atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*) + echo m68k-atari-mint${UNAME_RELEASE} + exit ;; + atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*) + echo m68k-atari-mint${UNAME_RELEASE} + exit ;; + *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*) + echo m68k-atari-mint${UNAME_RELEASE} + exit ;; + milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*) + echo m68k-milan-mint${UNAME_RELEASE} + exit ;; + hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*) + echo m68k-hades-mint${UNAME_RELEASE} + exit ;; + *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*) + echo m68k-unknown-mint${UNAME_RELEASE} + exit ;; + m68k:machten:*:*) + echo m68k-apple-machten${UNAME_RELEASE} + exit ;; + powerpc:machten:*:*) + echo powerpc-apple-machten${UNAME_RELEASE} + exit ;; + RISC*:Mach:*:*) + echo mips-dec-mach_bsd4.3 + exit ;; + RISC*:ULTRIX:*:*) + echo mips-dec-ultrix${UNAME_RELEASE} + exit ;; + VAX*:ULTRIX*:*:*) + echo vax-dec-ultrix${UNAME_RELEASE} + exit ;; + 2020:CLIX:*:* | 2430:CLIX:*:*) + echo clipper-intergraph-clix${UNAME_RELEASE} + exit ;; + mips:*:*:UMIPS | mips:*:*:RISCos) + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c +#ifdef __cplusplus +#include <stdio.h> /* for printf() prototype */ + int main (int argc, char *argv[]) { +#else + int main (argc, argv) int argc; char *argv[]; { +#endif + #if defined (host_mips) && defined (MIPSEB) + #if defined (SYSTYPE_SYSV) + printf ("mips-mips-riscos%ssysv\n", argv[1]); exit (0); + #endif + #if defined (SYSTYPE_SVR4) + printf ("mips-mips-riscos%ssvr4\n", argv[1]); exit (0); + #endif + #if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD) + printf ("mips-mips-riscos%sbsd\n", argv[1]); exit (0); + #endif + #endif + exit (-1); + } +EOF + $CC_FOR_BUILD -o $dummy $dummy.c && + dummyarg=`echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` && + SYSTEM_NAME=`$dummy $dummyarg` && + { echo "$SYSTEM_NAME"; exit; } + echo mips-mips-riscos${UNAME_RELEASE} + exit ;; + Motorola:PowerMAX_OS:*:*) + echo powerpc-motorola-powermax + exit ;; + Motorola:*:4.3:PL8-*) + echo powerpc-harris-powermax + exit ;; + Night_Hawk:*:*:PowerMAX_OS | Synergy:PowerMAX_OS:*:*) + echo powerpc-harris-powermax + exit ;; + Night_Hawk:Power_UNIX:*:*) + echo powerpc-harris-powerunix + exit ;; + m88k:CX/UX:7*:*) + echo m88k-harris-cxux7 + exit ;; + m88k:*:4*:R4*) + echo m88k-motorola-sysv4 + exit ;; + m88k:*:3*:R3*) + echo m88k-motorola-sysv3 + exit ;; + AViiON:dgux:*:*) + # DG/UX returns AViiON for all architectures + UNAME_PROCESSOR=`/usr/bin/uname -p` + if [ $UNAME_PROCESSOR = mc88100 ] || [ $UNAME_PROCESSOR = mc88110 ] + then + if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx ] || \ + [ ${TARGET_BINARY_INTERFACE}x = x ] + then + echo m88k-dg-dgux${UNAME_RELEASE} + else + echo m88k-dg-dguxbcs${UNAME_RELEASE} + fi + else + echo i586-dg-dgux${UNAME_RELEASE} + fi + exit ;; + M88*:DolphinOS:*:*) # DolphinOS (SVR3) + echo m88k-dolphin-sysv3 + exit ;; + M88*:*:R3*:*) + # Delta 88k system running SVR3 + echo m88k-motorola-sysv3 + exit ;; + XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3) + echo m88k-tektronix-sysv3 + exit ;; + Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD) + echo m68k-tektronix-bsd + exit ;; + *:IRIX*:*:*) + echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'` + exit ;; + ????????:AIX?:[12].1:2) # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX. + echo romp-ibm-aix # uname -m gives an 8 hex-code CPU id + exit ;; # Note that: echo "'`uname -s`'" gives 'AIX ' + i*86:AIX:*:*) + echo i386-ibm-aix + exit ;; + ia64:AIX:*:*) + if [ -x /usr/bin/oslevel ] ; then + IBM_REV=`/usr/bin/oslevel` + else + IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} + fi + echo ${UNAME_MACHINE}-ibm-aix${IBM_REV} + exit ;; + *:AIX:2:3) + if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #include <sys/systemcfg.h> + + main() + { + if (!__power_pc()) + exit(1); + puts("powerpc-ibm-aix3.2.5"); + exit(0); + } +EOF + if $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` + then + echo "$SYSTEM_NAME" + else + echo rs6000-ibm-aix3.2.5 + fi + elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then + echo rs6000-ibm-aix3.2.4 + else + echo rs6000-ibm-aix3.2 + fi + exit ;; + *:AIX:*:[4567]) + IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'` + if /usr/sbin/lsattr -El ${IBM_CPU_ID} | grep ' POWER' >/dev/null 2>&1; then + IBM_ARCH=rs6000 + else + IBM_ARCH=powerpc + fi + if [ -x /usr/bin/lslpp ] ; then + IBM_REV=`/usr/bin/lslpp -Lqc bos.rte.libc | + awk -F: '{ print $3 }' | sed s/[0-9]*$/0/` + else + IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} + fi + echo ${IBM_ARCH}-ibm-aix${IBM_REV} + exit ;; + *:AIX:*:*) + echo rs6000-ibm-aix + exit ;; + ibmrt:4.4BSD:*|romp-ibm:BSD:*) + echo romp-ibm-bsd4.4 + exit ;; + ibmrt:*BSD:*|romp-ibm:BSD:*) # covers RT/PC BSD and + echo romp-ibm-bsd${UNAME_RELEASE} # 4.3 with uname added to + exit ;; # report: romp-ibm BSD 4.3 + *:BOSX:*:*) + echo rs6000-bull-bosx + exit ;; + DPX/2?00:B.O.S.:*:*) + echo m68k-bull-sysv3 + exit ;; + 9000/[34]??:4.3bsd:1.*:*) + echo m68k-hp-bsd + exit ;; + hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*) + echo m68k-hp-bsd4.4 + exit ;; + 9000/[34678]??:HP-UX:*:*) + HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` + case "${UNAME_MACHINE}" in + 9000/31? ) HP_ARCH=m68000 ;; + 9000/[34]?? ) HP_ARCH=m68k ;; + 9000/[678][0-9][0-9]) + if [ -x /usr/bin/getconf ]; then + sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null` + sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null` + case "${sc_cpu_version}" in + 523) HP_ARCH=hppa1.0 ;; # CPU_PA_RISC1_0 + 528) HP_ARCH=hppa1.1 ;; # CPU_PA_RISC1_1 + 532) # CPU_PA_RISC2_0 + case "${sc_kernel_bits}" in + 32) HP_ARCH=hppa2.0n ;; + 64) HP_ARCH=hppa2.0w ;; + '') HP_ARCH=hppa2.0 ;; # HP-UX 10.20 + esac ;; + esac + fi + if [ "${HP_ARCH}" = "" ]; then + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + + #define _HPUX_SOURCE + #include <stdlib.h> + #include <unistd.h> + + int main () + { + #if defined(_SC_KERNEL_BITS) + long bits = sysconf(_SC_KERNEL_BITS); + #endif + long cpu = sysconf (_SC_CPU_VERSION); + + switch (cpu) + { + case CPU_PA_RISC1_0: puts ("hppa1.0"); break; + case CPU_PA_RISC1_1: puts ("hppa1.1"); break; + case CPU_PA_RISC2_0: + #if defined(_SC_KERNEL_BITS) + switch (bits) + { + case 64: puts ("hppa2.0w"); break; + case 32: puts ("hppa2.0n"); break; + default: puts ("hppa2.0"); break; + } break; + #else /* !defined(_SC_KERNEL_BITS) */ + puts ("hppa2.0"); break; + #endif + default: puts ("hppa1.0"); break; + } + exit (0); + } +EOF + (CCOPTS="" $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null) && HP_ARCH=`$dummy` + test -z "$HP_ARCH" && HP_ARCH=hppa + fi ;; + esac + if [ ${HP_ARCH} = hppa2.0w ] + then + eval $set_cc_for_build + + # hppa2.0w-hp-hpux* has a 64-bit kernel and a compiler generating + # 32-bit code. hppa64-hp-hpux* has the same kernel and a compiler + # generating 64-bit code. GNU and HP use different nomenclature: + # + # $ CC_FOR_BUILD=cc ./config.guess + # => hppa2.0w-hp-hpux11.23 + # $ CC_FOR_BUILD="cc +DA2.0w" ./config.guess + # => hppa64-hp-hpux11.23 + + if echo __LP64__ | (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | + grep -q __LP64__ + then + HP_ARCH=hppa2.0w + else + HP_ARCH=hppa64 + fi + fi + echo ${HP_ARCH}-hp-hpux${HPUX_REV} + exit ;; + ia64:HP-UX:*:*) + HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` + echo ia64-hp-hpux${HPUX_REV} + exit ;; + 3050*:HI-UX:*:*) + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #include <unistd.h> + int + main () + { + long cpu = sysconf (_SC_CPU_VERSION); + /* The order matters, because CPU_IS_HP_MC68K erroneously returns + true for CPU_PA_RISC1_0. CPU_IS_PA_RISC returns correct + results, however. */ + if (CPU_IS_PA_RISC (cpu)) + { + switch (cpu) + { + case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break; + case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break; + case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break; + default: puts ("hppa-hitachi-hiuxwe2"); break; + } + } + else if (CPU_IS_HP_MC68K (cpu)) + puts ("m68k-hitachi-hiuxwe2"); + else puts ("unknown-hitachi-hiuxwe2"); + exit (0); + } +EOF + $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` && + { echo "$SYSTEM_NAME"; exit; } + echo unknown-hitachi-hiuxwe2 + exit ;; + 9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* ) + echo hppa1.1-hp-bsd + exit ;; + 9000/8??:4.3bsd:*:*) + echo hppa1.0-hp-bsd + exit ;; + *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*) + echo hppa1.0-hp-mpeix + exit ;; + hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* ) + echo hppa1.1-hp-osf + exit ;; + hp8??:OSF1:*:*) + echo hppa1.0-hp-osf + exit ;; + i*86:OSF1:*:*) + if [ -x /usr/sbin/sysversion ] ; then + echo ${UNAME_MACHINE}-unknown-osf1mk + else + echo ${UNAME_MACHINE}-unknown-osf1 + fi + exit ;; + parisc*:Lites*:*:*) + echo hppa1.1-hp-lites + exit ;; + C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*) + echo c1-convex-bsd + exit ;; + C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*) + if getsysinfo -f scalar_acc + then echo c32-convex-bsd + else echo c2-convex-bsd + fi + exit ;; + C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*) + echo c34-convex-bsd + exit ;; + C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*) + echo c38-convex-bsd + exit ;; + C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*) + echo c4-convex-bsd + exit ;; + CRAY*Y-MP:*:*:*) + echo ymp-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; + CRAY*[A-Z]90:*:*:*) + echo ${UNAME_MACHINE}-cray-unicos${UNAME_RELEASE} \ + | sed -e 's/CRAY.*\([A-Z]90\)/\1/' \ + -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ \ + -e 's/\.[^.]*$/.X/' + exit ;; + CRAY*TS:*:*:*) + echo t90-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; + CRAY*T3E:*:*:*) + echo alphaev5-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; + CRAY*SV1:*:*:*) + echo sv1-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; + *:UNICOS/mp:*:*) + echo craynv-cray-unicosmp${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; + F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*) + FUJITSU_PROC=`uname -m | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz` + FUJITSU_SYS=`uname -p | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/\///'` + FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'` + echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" + exit ;; + 5000:UNIX_System_V:4.*:*) + FUJITSU_SYS=`uname -p | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/\///'` + FUJITSU_REL=`echo ${UNAME_RELEASE} | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/ /_/'` + echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" + exit ;; + i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*) + echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE} + exit ;; + sparc*:BSD/OS:*:*) + echo sparc-unknown-bsdi${UNAME_RELEASE} + exit ;; + *:BSD/OS:*:*) + echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE} + exit ;; + *:FreeBSD:*:*) + UNAME_PROCESSOR=`/usr/bin/uname -p` + case ${UNAME_PROCESSOR} in + amd64) + echo x86_64-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; + *) + echo ${UNAME_PROCESSOR}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; + esac + exit ;; + i*:CYGWIN*:*) + echo ${UNAME_MACHINE}-pc-cygwin + exit ;; + *:MINGW64*:*) + echo ${UNAME_MACHINE}-pc-mingw64 + exit ;; + *:MINGW*:*) + echo ${UNAME_MACHINE}-pc-mingw32 + exit ;; + *:MSYS*:*) + echo ${UNAME_MACHINE}-pc-msys + exit ;; + i*:windows32*:*) + # uname -m includes "-pc" on this system. + echo ${UNAME_MACHINE}-mingw32 + exit ;; + i*:PW*:*) + echo ${UNAME_MACHINE}-pc-pw32 + exit ;; + *:Interix*:*) + case ${UNAME_MACHINE} in + x86) + echo i586-pc-interix${UNAME_RELEASE} + exit ;; + authenticamd | genuineintel | EM64T) + echo x86_64-unknown-interix${UNAME_RELEASE} + exit ;; + IA64) + echo ia64-unknown-interix${UNAME_RELEASE} + exit ;; + esac ;; + [345]86:Windows_95:* | [345]86:Windows_98:* | [345]86:Windows_NT:*) + echo i${UNAME_MACHINE}-pc-mks + exit ;; + 8664:Windows_NT:*) + echo x86_64-pc-mks + exit ;; + i*:Windows_NT*:* | Pentium*:Windows_NT*:*) + # How do we know it's Interix rather than the generic POSIX subsystem? + # It also conflicts with pre-2.0 versions of AT&T UWIN. Should we + # UNAME_MACHINE based on the output of uname instead of i386? + echo i586-pc-interix + exit ;; + i*:UWIN*:*) + echo ${UNAME_MACHINE}-pc-uwin + exit ;; + amd64:CYGWIN*:*:* | x86_64:CYGWIN*:*:*) + echo x86_64-unknown-cygwin + exit ;; + p*:CYGWIN*:*) + echo powerpcle-unknown-cygwin + exit ;; + prep*:SunOS:5.*:*) + echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + *:GNU:*:*) + # the GNU system + echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-${LIBC}`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'` + exit ;; + *:GNU/*:*:*) + # other systems with GNU libc and userland + echo ${UNAME_MACHINE}-unknown-`echo ${UNAME_SYSTEM} | sed 's,^[^/]*/,,' | tr "[:upper:]" "[:lower:]"``echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`-${LIBC} + exit ;; + i*86:Minix:*:*) + echo ${UNAME_MACHINE}-pc-minix + exit ;; + aarch64:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + aarch64_be:Linux:*:*) + UNAME_MACHINE=aarch64_be + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + alpha:Linux:*:*) + case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in + EV5) UNAME_MACHINE=alphaev5 ;; + EV56) UNAME_MACHINE=alphaev56 ;; + PCA56) UNAME_MACHINE=alphapca56 ;; + PCA57) UNAME_MACHINE=alphapca56 ;; + EV6) UNAME_MACHINE=alphaev6 ;; + EV67) UNAME_MACHINE=alphaev67 ;; + EV68*) UNAME_MACHINE=alphaev68 ;; + esac + objdump --private-headers /bin/sh | grep -q ld.so.1 + if test "$?" = 0 ; then LIBC=gnulibc1 ; fi + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + arc:Linux:*:* | arceb:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + arm*:Linux:*:*) + eval $set_cc_for_build + if echo __ARM_EABI__ | $CC_FOR_BUILD -E - 2>/dev/null \ + | grep -q __ARM_EABI__ + then + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + else + if echo __ARM_PCS_VFP | $CC_FOR_BUILD -E - 2>/dev/null \ + | grep -q __ARM_PCS_VFP + then + echo ${UNAME_MACHINE}-unknown-linux-${LIBC}eabi + else + echo ${UNAME_MACHINE}-unknown-linux-${LIBC}eabihf + fi + fi + exit ;; + avr32*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + cris:Linux:*:*) + echo ${UNAME_MACHINE}-axis-linux-${LIBC} + exit ;; + crisv32:Linux:*:*) + echo ${UNAME_MACHINE}-axis-linux-${LIBC} + exit ;; + e2k:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + frv:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + hexagon:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + i*86:Linux:*:*) + echo ${UNAME_MACHINE}-pc-linux-${LIBC} + exit ;; + ia64:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + k1om:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + m32r*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + m68*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + mips:Linux:*:* | mips64:Linux:*:*) + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #undef CPU + #undef ${UNAME_MACHINE} + #undef ${UNAME_MACHINE}el + #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL) + CPU=${UNAME_MACHINE}el + #else + #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB) + CPU=${UNAME_MACHINE} + #else + CPU= + #endif + #endif +EOF + eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^CPU'` + test x"${CPU}" != x && { echo "${CPU}-unknown-linux-${LIBC}"; exit; } + ;; + openrisc*:Linux:*:*) + echo or1k-unknown-linux-${LIBC} + exit ;; + or32:Linux:*:* | or1k*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + padre:Linux:*:*) + echo sparc-unknown-linux-${LIBC} + exit ;; + parisc64:Linux:*:* | hppa64:Linux:*:*) + echo hppa64-unknown-linux-${LIBC} + exit ;; + parisc:Linux:*:* | hppa:Linux:*:*) + # Look for CPU level + case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in + PA7*) echo hppa1.1-unknown-linux-${LIBC} ;; + PA8*) echo hppa2.0-unknown-linux-${LIBC} ;; + *) echo hppa-unknown-linux-${LIBC} ;; + esac + exit ;; + ppc64:Linux:*:*) + echo powerpc64-unknown-linux-${LIBC} + exit ;; + ppc:Linux:*:*) + echo powerpc-unknown-linux-${LIBC} + exit ;; + ppc64le:Linux:*:*) + echo powerpc64le-unknown-linux-${LIBC} + exit ;; + ppcle:Linux:*:*) + echo powerpcle-unknown-linux-${LIBC} + exit ;; + s390:Linux:*:* | s390x:Linux:*:*) + echo ${UNAME_MACHINE}-ibm-linux-${LIBC} + exit ;; + sh64*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + sh*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + sparc:Linux:*:* | sparc64:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + tile*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + vax:Linux:*:*) + echo ${UNAME_MACHINE}-dec-linux-${LIBC} + exit ;; + x86_64:Linux:*:*) + echo ${UNAME_MACHINE}-pc-linux-${LIBC} + exit ;; + xtensa*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + i*86:DYNIX/ptx:4*:*) + # ptx 4.0 does uname -s correctly, with DYNIX/ptx in there. + # earlier versions are messed up and put the nodename in both + # sysname and nodename. + echo i386-sequent-sysv4 + exit ;; + i*86:UNIX_SV:4.2MP:2.*) + # Unixware is an offshoot of SVR4, but it has its own version + # number series starting with 2... + # I am not positive that other SVR4 systems won't match this, + # I just have to hope. -- rms. + # Use sysv4.2uw... so that sysv4* matches it. + echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION} + exit ;; + i*86:OS/2:*:*) + # If we were able to find `uname', then EMX Unix compatibility + # is probably installed. + echo ${UNAME_MACHINE}-pc-os2-emx + exit ;; + i*86:XTS-300:*:STOP) + echo ${UNAME_MACHINE}-unknown-stop + exit ;; + i*86:atheos:*:*) + echo ${UNAME_MACHINE}-unknown-atheos + exit ;; + i*86:syllable:*:*) + echo ${UNAME_MACHINE}-pc-syllable + exit ;; + i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.[02]*:*) + echo i386-unknown-lynxos${UNAME_RELEASE} + exit ;; + i*86:*DOS:*:*) + echo ${UNAME_MACHINE}-pc-msdosdjgpp + exit ;; + i*86:*:4.*:* | i*86:SYSTEM_V:4.*:*) + UNAME_REL=`echo ${UNAME_RELEASE} | sed 's/\/MP$//'` + if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then + echo ${UNAME_MACHINE}-univel-sysv${UNAME_REL} + else + echo ${UNAME_MACHINE}-pc-sysv${UNAME_REL} + fi + exit ;; + i*86:*:5:[678]*) + # UnixWare 7.x, OpenUNIX and OpenServer 6. + case `/bin/uname -X | grep "^Machine"` in + *486*) UNAME_MACHINE=i486 ;; + *Pentium) UNAME_MACHINE=i586 ;; + *Pent*|*Celeron) UNAME_MACHINE=i686 ;; + esac + echo ${UNAME_MACHINE}-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION} + exit ;; + i*86:*:3.2:*) + if test -f /usr/options/cb.name; then + UNAME_REL=`sed -n 's/.*Version //p' </usr/options/cb.name` + echo ${UNAME_MACHINE}-pc-isc$UNAME_REL + elif /bin/uname -X 2>/dev/null >/dev/null ; then + UNAME_REL=`(/bin/uname -X|grep Release|sed -e 's/.*= //')` + (/bin/uname -X|grep i80486 >/dev/null) && UNAME_MACHINE=i486 + (/bin/uname -X|grep '^Machine.*Pentium' >/dev/null) \ + && UNAME_MACHINE=i586 + (/bin/uname -X|grep '^Machine.*Pent *II' >/dev/null) \ + && UNAME_MACHINE=i686 + (/bin/uname -X|grep '^Machine.*Pentium Pro' >/dev/null) \ + && UNAME_MACHINE=i686 + echo ${UNAME_MACHINE}-pc-sco$UNAME_REL + else + echo ${UNAME_MACHINE}-pc-sysv32 + fi + exit ;; + pc:*:*:*) + # Left here for compatibility: + # uname -m prints for DJGPP always 'pc', but it prints nothing about + # the processor, so we play safe by assuming i586. + # Note: whatever this is, it MUST be the same as what config.sub + # prints for the "djgpp" host, or else GDB configure will decide that + # this is a cross-build. + echo i586-pc-msdosdjgpp + exit ;; + Intel:Mach:3*:*) + echo i386-pc-mach3 + exit ;; + paragon:*:*:*) + echo i860-intel-osf1 + exit ;; + i860:*:4.*:*) # i860-SVR4 + if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then + echo i860-stardent-sysv${UNAME_RELEASE} # Stardent Vistra i860-SVR4 + else # Add other i860-SVR4 vendors below as they are discovered. + echo i860-unknown-sysv${UNAME_RELEASE} # Unknown i860-SVR4 + fi + exit ;; + mini*:CTIX:SYS*5:*) + # "miniframe" + echo m68010-convergent-sysv + exit ;; + mc68k:UNIX:SYSTEM5:3.51m) + echo m68k-convergent-sysv + exit ;; + M680?0:D-NIX:5.3:*) + echo m68k-diab-dnix + exit ;; + M68*:*:R3V[5678]*:*) + test -r /sysV68 && { echo 'm68k-motorola-sysv'; exit; } ;; + 3[345]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0 | SHG2:*:4.0:3.0 | S7501*:*:4.0:3.0) + OS_REL='' + test -r /etc/.relid \ + && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` + /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ + && { echo i486-ncr-sysv4.3${OS_REL}; exit; } + /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ + && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;; + 3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*) + /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ + && { echo i486-ncr-sysv4; exit; } ;; + NCR*:*:4.2:* | MPRAS*:*:4.2:*) + OS_REL='.3' + test -r /etc/.relid \ + && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` + /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ + && { echo i486-ncr-sysv4.3${OS_REL}; exit; } + /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ + && { echo i586-ncr-sysv4.3${OS_REL}; exit; } + /bin/uname -p 2>/dev/null | /bin/grep pteron >/dev/null \ + && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;; + m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*) + echo m68k-unknown-lynxos${UNAME_RELEASE} + exit ;; + mc68030:UNIX_System_V:4.*:*) + echo m68k-atari-sysv4 + exit ;; + TSUNAMI:LynxOS:2.*:*) + echo sparc-unknown-lynxos${UNAME_RELEASE} + exit ;; + rs6000:LynxOS:2.*:*) + echo rs6000-unknown-lynxos${UNAME_RELEASE} + exit ;; + PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.[02]*:*) + echo powerpc-unknown-lynxos${UNAME_RELEASE} + exit ;; + SM[BE]S:UNIX_SV:*:*) + echo mips-dde-sysv${UNAME_RELEASE} + exit ;; + RM*:ReliantUNIX-*:*:*) + echo mips-sni-sysv4 + exit ;; + RM*:SINIX-*:*:*) + echo mips-sni-sysv4 + exit ;; + *:SINIX-*:*:*) + if uname -p 2>/dev/null >/dev/null ; then + UNAME_MACHINE=`(uname -p) 2>/dev/null` + echo ${UNAME_MACHINE}-sni-sysv4 + else + echo ns32k-sni-sysv + fi + exit ;; + PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort + # says <Richard.M.Bartel@ccMail.Census.GOV> + echo i586-unisys-sysv4 + exit ;; + *:UNIX_System_V:4*:FTX*) + # From Gerald Hewes <hewes@openmarket.com>. + # How about differentiating between stratus architectures? -djm + echo hppa1.1-stratus-sysv4 + exit ;; + *:*:*:FTX*) + # From seanf@swdc.stratus.com. + echo i860-stratus-sysv4 + exit ;; + i*86:VOS:*:*) + # From Paul.Green@stratus.com. + echo ${UNAME_MACHINE}-stratus-vos + exit ;; + *:VOS:*:*) + # From Paul.Green@stratus.com. + echo hppa1.1-stratus-vos + exit ;; + mc68*:A/UX:*:*) + echo m68k-apple-aux${UNAME_RELEASE} + exit ;; + news*:NEWS-OS:6*:*) + echo mips-sony-newsos6 + exit ;; + R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*) + if [ -d /usr/nec ]; then + echo mips-nec-sysv${UNAME_RELEASE} + else + echo mips-unknown-sysv${UNAME_RELEASE} + fi + exit ;; + BeBox:BeOS:*:*) # BeOS running on hardware made by Be, PPC only. + echo powerpc-be-beos + exit ;; + BeMac:BeOS:*:*) # BeOS running on Mac or Mac clone, PPC only. + echo powerpc-apple-beos + exit ;; + BePC:BeOS:*:*) # BeOS running on Intel PC compatible. + echo i586-pc-beos + exit ;; + BePC:Haiku:*:*) # Haiku running on Intel PC compatible. + echo i586-pc-haiku + exit ;; + x86_64:Haiku:*:*) + echo x86_64-unknown-haiku + exit ;; + SX-4:SUPER-UX:*:*) + echo sx4-nec-superux${UNAME_RELEASE} + exit ;; + SX-5:SUPER-UX:*:*) + echo sx5-nec-superux${UNAME_RELEASE} + exit ;; + SX-6:SUPER-UX:*:*) + echo sx6-nec-superux${UNAME_RELEASE} + exit ;; + SX-7:SUPER-UX:*:*) + echo sx7-nec-superux${UNAME_RELEASE} + exit ;; + SX-8:SUPER-UX:*:*) + echo sx8-nec-superux${UNAME_RELEASE} + exit ;; + SX-8R:SUPER-UX:*:*) + echo sx8r-nec-superux${UNAME_RELEASE} + exit ;; + SX-ACE:SUPER-UX:*:*) + echo sxace-nec-superux${UNAME_RELEASE} + exit ;; + Power*:Rhapsody:*:*) + echo powerpc-apple-rhapsody${UNAME_RELEASE} + exit ;; + *:Rhapsody:*:*) + echo ${UNAME_MACHINE}-apple-rhapsody${UNAME_RELEASE} + exit ;; + *:Darwin:*:*) + UNAME_PROCESSOR=`uname -p` || UNAME_PROCESSOR=unknown + eval $set_cc_for_build + if test "$UNAME_PROCESSOR" = unknown ; then + UNAME_PROCESSOR=powerpc + fi + if test `echo "$UNAME_RELEASE" | sed -e 's/\..*//'` -le 10 ; then + if [ "$CC_FOR_BUILD" != no_compiler_found ]; then + if (echo '#ifdef __LP64__'; echo IS_64BIT_ARCH; echo '#endif') | \ + (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \ + grep IS_64BIT_ARCH >/dev/null + then + case $UNAME_PROCESSOR in + i386) UNAME_PROCESSOR=x86_64 ;; + powerpc) UNAME_PROCESSOR=powerpc64 ;; + esac + fi + fi + elif test "$UNAME_PROCESSOR" = i386 ; then + # Avoid executing cc on OS X 10.9, as it ships with a stub + # that puts up a graphical alert prompting to install + # developer tools. Any system running Mac OS X 10.7 or + # later (Darwin 11 and later) is required to have a 64-bit + # processor. This is not true of the ARM version of Darwin + # that Apple uses in portable devices. + UNAME_PROCESSOR=x86_64 + fi + echo ${UNAME_PROCESSOR}-apple-darwin${UNAME_RELEASE} + exit ;; + *:procnto*:*:* | *:QNX:[0123456789]*:*) + UNAME_PROCESSOR=`uname -p` + if test "$UNAME_PROCESSOR" = x86; then + UNAME_PROCESSOR=i386 + UNAME_MACHINE=pc + fi + echo ${UNAME_PROCESSOR}-${UNAME_MACHINE}-nto-qnx${UNAME_RELEASE} + exit ;; + *:QNX:*:4*) + echo i386-pc-qnx + exit ;; + NEO-?:NONSTOP_KERNEL:*:*) + echo neo-tandem-nsk${UNAME_RELEASE} + exit ;; + NSE-*:NONSTOP_KERNEL:*:*) + echo nse-tandem-nsk${UNAME_RELEASE} + exit ;; + NSR-?:NONSTOP_KERNEL:*:*) + echo nsr-tandem-nsk${UNAME_RELEASE} + exit ;; + *:NonStop-UX:*:*) + echo mips-compaq-nonstopux + exit ;; + BS2000:POSIX*:*:*) + echo bs2000-siemens-sysv + exit ;; + DS/*:UNIX_System_V:*:*) + echo ${UNAME_MACHINE}-${UNAME_SYSTEM}-${UNAME_RELEASE} + exit ;; + *:Plan9:*:*) + # "uname -m" is not consistent, so use $cputype instead. 386 + # is converted to i386 for consistency with other x86 + # operating systems. + if test "$cputype" = 386; then + UNAME_MACHINE=i386 + else + UNAME_MACHINE="$cputype" + fi + echo ${UNAME_MACHINE}-unknown-plan9 + exit ;; + *:TOPS-10:*:*) + echo pdp10-unknown-tops10 + exit ;; + *:TENEX:*:*) + echo pdp10-unknown-tenex + exit ;; + KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*) + echo pdp10-dec-tops20 + exit ;; + XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*) + echo pdp10-xkl-tops20 + exit ;; + *:TOPS-20:*:*) + echo pdp10-unknown-tops20 + exit ;; + *:ITS:*:*) + echo pdp10-unknown-its + exit ;; + SEI:*:*:SEIUX) + echo mips-sei-seiux${UNAME_RELEASE} + exit ;; + *:DragonFly:*:*) + echo ${UNAME_MACHINE}-unknown-dragonfly`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` + exit ;; + *:*VMS:*:*) + UNAME_MACHINE=`(uname -p) 2>/dev/null` + case "${UNAME_MACHINE}" in + A*) echo alpha-dec-vms ; exit ;; + I*) echo ia64-dec-vms ; exit ;; + V*) echo vax-dec-vms ; exit ;; + esac ;; + *:XENIX:*:SysV) + echo i386-pc-xenix + exit ;; + i*86:skyos:*:*) + echo ${UNAME_MACHINE}-pc-skyos`echo ${UNAME_RELEASE} | sed -e 's/ .*$//'` + exit ;; + i*86:rdos:*:*) + echo ${UNAME_MACHINE}-pc-rdos + exit ;; + i*86:AROS:*:*) + echo ${UNAME_MACHINE}-pc-aros + exit ;; + x86_64:VMkernel:*:*) + echo ${UNAME_MACHINE}-unknown-esx + exit ;; + amd64:Isilon\ OneFS:*:*) + echo x86_64-unknown-onefs + exit ;; +esac + +cat >&2 <<EOF +$0: unable to guess system type + +This script (version $timestamp), has failed to recognize the +operating system you are using. If your script is old, overwrite +config.guess and config.sub with the latest versions from: + + http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess +and + http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub + +If $0 has already been updated, send the following data and any +information you think might be pertinent to config-patches@gnu.org to +provide the necessary information to handle your system. + +config.guess timestamp = $timestamp + +uname -m = `(uname -m) 2>/dev/null || echo unknown` +uname -r = `(uname -r) 2>/dev/null || echo unknown` +uname -s = `(uname -s) 2>/dev/null || echo unknown` +uname -v = `(uname -v) 2>/dev/null || echo unknown` + +/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null` +/bin/uname -X = `(/bin/uname -X) 2>/dev/null` + +hostinfo = `(hostinfo) 2>/dev/null` +/bin/universe = `(/bin/universe) 2>/dev/null` +/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null` +/bin/arch = `(/bin/arch) 2>/dev/null` +/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null` +/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null` + +UNAME_MACHINE = ${UNAME_MACHINE} +UNAME_RELEASE = ${UNAME_RELEASE} +UNAME_SYSTEM = ${UNAME_SYSTEM} +UNAME_VERSION = ${UNAME_VERSION} +EOF + +exit 1 + +# Local variables: +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "timestamp='" +# time-stamp-format: "%:y-%02m-%02d" +# time-stamp-end: "'" +# End: diff --git a/tools/depends/build-aux/config.sub b/tools/depends/build-aux/config.sub new file mode 100644 index 0000000..a1f8229 --- /dev/null +++ b/tools/depends/build-aux/config.sub @@ -0,0 +1,1823 @@ +#! /bin/sh +# Configuration validation subroutine script. +# Copyright 1992-2016 Free Software Foundation, Inc. + +timestamp='2016-08-25' + +# 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 3 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, see <http://www.gnu.org/licenses/>. +# +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that +# program. This Exception is an additional permission under section 7 +# of the GNU General Public License, version 3 ("GPLv3"). + + +# Please send patches to <config-patches@gnu.org>. +# +# Configuration subroutine to validate and canonicalize a configuration type. +# Supply the specified configuration type as an argument. +# If it is invalid, we print an error message on stderr and exit with code 1. +# Otherwise, we print the canonical config type on stdout and succeed. + +# You can get the latest version of this script from: +# http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub + +# This file is supposed to be the same for all GNU packages +# and recognize all the CPU types, system types and aliases +# that are meaningful with *any* GNU software. +# Each package is responsible for reporting which valid configurations +# it does not support. The user should be able to distinguish +# a failure to support a valid configuration from a meaningless +# configuration. + +# The goal of this file is to map all the various variations of a given +# machine specification into a single specification in the form: +# CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM +# or in some cases, the newer four-part form: +# CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM +# It is wrong to echo any other type of specification. + +me=`echo "$0" | sed -e 's,.*/,,'` + +usage="\ +Usage: $0 [OPTION] CPU-MFR-OPSYS or ALIAS + +Canonicalize a configuration name. + +Operation modes: + -h, --help print this help, then exit + -t, --time-stamp print date of last modification, then exit + -v, --version print version number, then exit + +Report bugs and patches to <config-patches@gnu.org>." + +version="\ +GNU config.sub ($timestamp) + +Copyright 1992-2016 Free Software Foundation, Inc. + +This is free software; see the source for copying conditions. There is NO +warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." + +help=" +Try \`$me --help' for more information." + +# Parse command line +while test $# -gt 0 ; do + case $1 in + --time-stamp | --time* | -t ) + echo "$timestamp" ; exit ;; + --version | -v ) + echo "$version" ; exit ;; + --help | --h* | -h ) + echo "$usage"; exit ;; + -- ) # Stop option processing + shift; break ;; + - ) # Use stdin as input. + break ;; + -* ) + echo "$me: invalid option $1$help" + exit 1 ;; + + *local*) + # First pass through any local machine types. + echo $1 + exit ;; + + * ) + break ;; + esac +done + +case $# in + 0) echo "$me: missing argument$help" >&2 + exit 1;; + 1) ;; + *) echo "$me: too many arguments$help" >&2 + exit 1;; +esac + +# Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any). +# Here we must recognize all the valid KERNEL-OS combinations. +maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'` +case $maybe_os in + nto-qnx* | linux-gnu* | linux-android* | linux-dietlibc | linux-newlib* | \ + linux-musl* | linux-uclibc* | uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | \ + knetbsd*-gnu* | netbsd*-gnu* | netbsd*-eabi* | \ + kopensolaris*-gnu* | \ + storm-chaos* | os2-emx* | rtmk-nova*) + os=-$maybe_os + basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'` + ;; + android-linux) + os=-linux-android + basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`-unknown + ;; + *) + basic_machine=`echo $1 | sed 's/-[^-]*$//'` + if [ $basic_machine != $1 ] + then os=`echo $1 | sed 's/.*-/-/'` + else os=; fi + ;; +esac + +### Let's recognize common machines as not being operating systems so +### that things like config.sub decstation-3100 work. We also +### recognize some manufacturers as not being operating systems, so we +### can provide default operating systems below. +case $os in + -sun*os*) + # Prevent following clause from handling this invalid input. + ;; + -dec* | -mips* | -sequent* | -encore* | -pc532* | -sgi* | -sony* | \ + -att* | -7300* | -3300* | -delta* | -motorola* | -sun[234]* | \ + -unicom* | -ibm* | -next | -hp | -isi* | -apollo | -altos* | \ + -convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\ + -c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \ + -harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \ + -apple | -axis | -knuth | -cray | -microblaze*) + os= + basic_machine=$1 + ;; + -bluegene*) + os=-cnk + ;; + -sim | -cisco | -oki | -wec | -winbond) + os= + basic_machine=$1 + ;; + -scout) + ;; + -wrs) + os=-vxworks + basic_machine=$1 + ;; + -chorusos*) + os=-chorusos + basic_machine=$1 + ;; + -chorusrdb) + os=-chorusrdb + basic_machine=$1 + ;; + -hiux*) + os=-hiuxwe2 + ;; + -sco6) + os=-sco5v6 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco5) + os=-sco3.2v5 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco4) + os=-sco3.2v4 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco3.2.[4-9]*) + os=`echo $os | sed -e 's/sco3.2./sco3.2v/'` + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco3.2v[4-9]*) + # Don't forget version if it is 3.2v4 or newer. + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco5v6*) + # Don't forget version if it is 3.2v4 or newer. + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco*) + os=-sco3.2v2 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -udk*) + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -isc) + os=-isc2.2 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -clix*) + basic_machine=clipper-intergraph + ;; + -isc*) + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -lynx*178) + os=-lynxos178 + ;; + -lynx*5) + os=-lynxos5 + ;; + -lynx*) + os=-lynxos + ;; + -ptx*) + basic_machine=`echo $1 | sed -e 's/86-.*/86-sequent/'` + ;; + -windowsnt*) + os=`echo $os | sed -e 's/windowsnt/winnt/'` + ;; + -psos*) + os=-psos + ;; + -mint | -mint[0-9]*) + basic_machine=m68k-atari + os=-mint + ;; +esac + +# Decode aliases for certain CPU-COMPANY combinations. +case $basic_machine in + # Recognize the basic CPU types without company name. + # Some are omitted here because they have special meanings below. + 1750a | 580 \ + | a29k \ + | aarch64 | aarch64_be \ + | alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \ + | alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \ + | am33_2.0 \ + | arc | arceb \ + | arm | arm[bl]e | arme[lb] | armv[2-8] | armv[3-8][lb] | armv7[arm] \ + | avr | avr32 \ + | ba \ + | be32 | be64 \ + | bfin \ + | c4x | c8051 | clipper \ + | d10v | d30v | dlx | dsp16xx \ + | e2k | epiphany \ + | fido | fr30 | frv | ft32 \ + | h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \ + | hexagon \ + | i370 | i860 | i960 | ia64 \ + | ip2k | iq2000 \ + | k1om \ + | le32 | le64 \ + | lm32 \ + | m32c | m32r | m32rle | m68000 | m68k | m88k \ + | maxq | mb | microblaze | microblazeel | mcore | mep | metag \ + | mips | mipsbe | mipseb | mipsel | mipsle \ + | mips16 \ + | mips64 | mips64el \ + | mips64octeon | mips64octeonel \ + | mips64orion | mips64orionel \ + | mips64r5900 | mips64r5900el \ + | mips64vr | mips64vrel \ + | mips64vr4100 | mips64vr4100el \ + | mips64vr4300 | mips64vr4300el \ + | mips64vr5000 | mips64vr5000el \ + | mips64vr5900 | mips64vr5900el \ + | mipsisa32 | mipsisa32el \ + | mipsisa32r2 | mipsisa32r2el \ + | mipsisa32r6 | mipsisa32r6el \ + | mipsisa64 | mipsisa64el \ + | mipsisa64r2 | mipsisa64r2el \ + | mipsisa64r6 | mipsisa64r6el \ + | mipsisa64sb1 | mipsisa64sb1el \ + | mipsisa64sr71k | mipsisa64sr71kel \ + | mipsr5900 | mipsr5900el \ + | mipstx39 | mipstx39el \ + | mn10200 | mn10300 \ + | moxie \ + | mt \ + | msp430 \ + | nds32 | nds32le | nds32be \ + | nios | nios2 | nios2eb | nios2el \ + | ns16k | ns32k \ + | open8 | or1k | or1knd | or32 \ + | pdp10 | pdp11 | pj | pjl \ + | powerpc | powerpc64 | powerpc64le | powerpcle \ + | pyramid \ + | riscv32 | riscv64 \ + | rl78 | rx \ + | score \ + | sh | sh[1234] | sh[24]a | sh[24]aeb | sh[23]e | sh[234]eb | sheb | shbe | shle | sh[1234]le | sh3ele \ + | sh64 | sh64le \ + | sparc | sparc64 | sparc64b | sparc64v | sparc86x | sparclet | sparclite \ + | sparcv8 | sparcv9 | sparcv9b | sparcv9v \ + | spu \ + | tahoe | tic4x | tic54x | tic55x | tic6x | tic80 | tron \ + | ubicom32 \ + | v850 | v850e | v850e1 | v850e2 | v850es | v850e2v3 \ + | visium \ + | we32k \ + | x86 | xc16x | xstormy16 | xtensa \ + | z8k | z80) + basic_machine=$basic_machine-unknown + ;; + c54x) + basic_machine=tic54x-unknown + ;; + c55x) + basic_machine=tic55x-unknown + ;; + c6x) + basic_machine=tic6x-unknown + ;; + leon|leon[3-9]) + basic_machine=sparc-$basic_machine + ;; + m6811 | m68hc11 | m6812 | m68hc12 | m68hcs12x | nvptx | picochip) + basic_machine=$basic_machine-unknown + os=-none + ;; + m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | v70 | w65 | z8k) + ;; + ms1) + basic_machine=mt-unknown + ;; + + strongarm | thumb | xscale) + basic_machine=arm-unknown + ;; + xgate) + basic_machine=$basic_machine-unknown + os=-none + ;; + xscaleeb) + basic_machine=armeb-unknown + ;; + + xscaleel) + basic_machine=armel-unknown + ;; + + # We use `pc' rather than `unknown' + # because (1) that's what they normally are, and + # (2) the word "unknown" tends to confuse beginning users. + i*86 | x86_64) + basic_machine=$basic_machine-pc + ;; + # Object if more than one company name word. + *-*-*) + echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 + exit 1 + ;; + # Recognize the basic CPU types with company name. + 580-* \ + | a29k-* \ + | aarch64-* | aarch64_be-* \ + | alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \ + | alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \ + | alphapca5[67]-* | alpha64pca5[67]-* | arc-* | arceb-* \ + | arm-* | armbe-* | armle-* | armeb-* | armv*-* \ + | avr-* | avr32-* \ + | ba-* \ + | be32-* | be64-* \ + | bfin-* | bs2000-* \ + | c[123]* | c30-* | [cjt]90-* | c4x-* \ + | c8051-* | clipper-* | craynv-* | cydra-* \ + | d10v-* | d30v-* | dlx-* \ + | e2k-* | elxsi-* \ + | f30[01]-* | f700-* | fido-* | fr30-* | frv-* | fx80-* \ + | h8300-* | h8500-* \ + | hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \ + | hexagon-* \ + | i*86-* | i860-* | i960-* | ia64-* \ + | ip2k-* | iq2000-* \ + | k1om-* \ + | le32-* | le64-* \ + | lm32-* \ + | m32c-* | m32r-* | m32rle-* \ + | m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \ + | m88110-* | m88k-* | maxq-* | mcore-* | metag-* \ + | microblaze-* | microblazeel-* \ + | mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \ + | mips16-* \ + | mips64-* | mips64el-* \ + | mips64octeon-* | mips64octeonel-* \ + | mips64orion-* | mips64orionel-* \ + | mips64r5900-* | mips64r5900el-* \ + | mips64vr-* | mips64vrel-* \ + | mips64vr4100-* | mips64vr4100el-* \ + | mips64vr4300-* | mips64vr4300el-* \ + | mips64vr5000-* | mips64vr5000el-* \ + | mips64vr5900-* | mips64vr5900el-* \ + | mipsisa32-* | mipsisa32el-* \ + | mipsisa32r2-* | mipsisa32r2el-* \ + | mipsisa32r6-* | mipsisa32r6el-* \ + | mipsisa64-* | mipsisa64el-* \ + | mipsisa64r2-* | mipsisa64r2el-* \ + | mipsisa64r6-* | mipsisa64r6el-* \ + | mipsisa64sb1-* | mipsisa64sb1el-* \ + | mipsisa64sr71k-* | mipsisa64sr71kel-* \ + | mipsr5900-* | mipsr5900el-* \ + | mipstx39-* | mipstx39el-* \ + | mmix-* \ + | mt-* \ + | msp430-* \ + | nds32-* | nds32le-* | nds32be-* \ + | nios-* | nios2-* | nios2eb-* | nios2el-* \ + | none-* | np1-* | ns16k-* | ns32k-* \ + | open8-* \ + | or1k*-* \ + | orion-* \ + | pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \ + | powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* \ + | pyramid-* \ + | riscv32-* | riscv64-* \ + | rl78-* | romp-* | rs6000-* | rx-* \ + | sh-* | sh[1234]-* | sh[24]a-* | sh[24]aeb-* | sh[23]e-* | sh[34]eb-* | sheb-* | shbe-* \ + | shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \ + | sparc-* | sparc64-* | sparc64b-* | sparc64v-* | sparc86x-* | sparclet-* \ + | sparclite-* \ + | sparcv8-* | sparcv9-* | sparcv9b-* | sparcv9v-* | sv1-* | sx*-* \ + | tahoe-* \ + | tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* \ + | tile*-* \ + | tron-* \ + | ubicom32-* \ + | v850-* | v850e-* | v850e1-* | v850es-* | v850e2-* | v850e2v3-* \ + | vax-* \ + | visium-* \ + | we32k-* \ + | x86-* | x86_64-* | xc16x-* | xps100-* \ + | xstormy16-* | xtensa*-* \ + | ymp-* \ + | z8k-* | z80-*) + ;; + # Recognize the basic CPU types without company name, with glob match. + xtensa*) + basic_machine=$basic_machine-unknown + ;; + # Recognize the various machine names and aliases which stand + # for a CPU type and a company and sometimes even an OS. + 386bsd) + basic_machine=i386-unknown + os=-bsd + ;; + 3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc) + basic_machine=m68000-att + ;; + 3b*) + basic_machine=we32k-att + ;; + a29khif) + basic_machine=a29k-amd + os=-udi + ;; + abacus) + basic_machine=abacus-unknown + ;; + adobe68k) + basic_machine=m68010-adobe + os=-scout + ;; + alliant | fx80) + basic_machine=fx80-alliant + ;; + altos | altos3068) + basic_machine=m68k-altos + ;; + am29k) + basic_machine=a29k-none + os=-bsd + ;; + amd64) + basic_machine=x86_64-pc + ;; + amd64-*) + basic_machine=x86_64-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + amdahl) + basic_machine=580-amdahl + os=-sysv + ;; + amiga | amiga-*) + basic_machine=m68k-unknown + ;; + amigaos | amigados) + basic_machine=m68k-unknown + os=-amigaos + ;; + amigaunix | amix) + basic_machine=m68k-unknown + os=-sysv4 + ;; + apollo68) + basic_machine=m68k-apollo + os=-sysv + ;; + apollo68bsd) + basic_machine=m68k-apollo + os=-bsd + ;; + aros) + basic_machine=i386-pc + os=-aros + ;; + asmjs) + basic_machine=asmjs-unknown + ;; + aux) + basic_machine=m68k-apple + os=-aux + ;; + balance) + basic_machine=ns32k-sequent + os=-dynix + ;; + blackfin) + basic_machine=bfin-unknown + os=-linux + ;; + blackfin-*) + basic_machine=bfin-`echo $basic_machine | sed 's/^[^-]*-//'` + os=-linux + ;; + bluegene*) + basic_machine=powerpc-ibm + os=-cnk + ;; + c54x-*) + basic_machine=tic54x-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + c55x-*) + basic_machine=tic55x-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + c6x-*) + basic_machine=tic6x-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + c90) + basic_machine=c90-cray + os=-unicos + ;; + cegcc) + basic_machine=arm-unknown + os=-cegcc + ;; + convex-c1) + basic_machine=c1-convex + os=-bsd + ;; + convex-c2) + basic_machine=c2-convex + os=-bsd + ;; + convex-c32) + basic_machine=c32-convex + os=-bsd + ;; + convex-c34) + basic_machine=c34-convex + os=-bsd + ;; + convex-c38) + basic_machine=c38-convex + os=-bsd + ;; + cray | j90) + basic_machine=j90-cray + os=-unicos + ;; + craynv) + basic_machine=craynv-cray + os=-unicosmp + ;; + cr16 | cr16-*) + basic_machine=cr16-unknown + os=-elf + ;; + crds | unos) + basic_machine=m68k-crds + ;; + crisv32 | crisv32-* | etraxfs*) + basic_machine=crisv32-axis + ;; + cris | cris-* | etrax*) + basic_machine=cris-axis + ;; + crx) + basic_machine=crx-unknown + os=-elf + ;; + da30 | da30-*) + basic_machine=m68k-da30 + ;; + decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn) + basic_machine=mips-dec + ;; + decsystem10* | dec10*) + basic_machine=pdp10-dec + os=-tops10 + ;; + decsystem20* | dec20*) + basic_machine=pdp10-dec + os=-tops20 + ;; + delta | 3300 | motorola-3300 | motorola-delta \ + | 3300-motorola | delta-motorola) + basic_machine=m68k-motorola + ;; + delta88) + basic_machine=m88k-motorola + os=-sysv3 + ;; + dicos) + basic_machine=i686-pc + os=-dicos + ;; + djgpp) + basic_machine=i586-pc + os=-msdosdjgpp + ;; + dpx20 | dpx20-*) + basic_machine=rs6000-bull + os=-bosx + ;; + dpx2* | dpx2*-bull) + basic_machine=m68k-bull + os=-sysv3 + ;; + e500v[12]) + basic_machine=powerpc-unknown + os=$os"spe" + ;; + e500v[12]-*) + basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'` + os=$os"spe" + ;; + ebmon29k) + basic_machine=a29k-amd + os=-ebmon + ;; + elxsi) + basic_machine=elxsi-elxsi + os=-bsd + ;; + encore | umax | mmax) + basic_machine=ns32k-encore + ;; + es1800 | OSE68k | ose68k | ose | OSE) + basic_machine=m68k-ericsson + os=-ose + ;; + fx2800) + basic_machine=i860-alliant + ;; + genix) + basic_machine=ns32k-ns + ;; + gmicro) + basic_machine=tron-gmicro + os=-sysv + ;; + go32) + basic_machine=i386-pc + os=-go32 + ;; + h3050r* | hiux*) + basic_machine=hppa1.1-hitachi + os=-hiuxwe2 + ;; + h8300hms) + basic_machine=h8300-hitachi + os=-hms + ;; + h8300xray) + basic_machine=h8300-hitachi + os=-xray + ;; + h8500hms) + basic_machine=h8500-hitachi + os=-hms + ;; + harris) + basic_machine=m88k-harris + os=-sysv3 + ;; + hp300-*) + basic_machine=m68k-hp + ;; + hp300bsd) + basic_machine=m68k-hp + os=-bsd + ;; + hp300hpux) + basic_machine=m68k-hp + os=-hpux + ;; + hp3k9[0-9][0-9] | hp9[0-9][0-9]) + basic_machine=hppa1.0-hp + ;; + hp9k2[0-9][0-9] | hp9k31[0-9]) + basic_machine=m68000-hp + ;; + hp9k3[2-9][0-9]) + basic_machine=m68k-hp + ;; + hp9k6[0-9][0-9] | hp6[0-9][0-9]) + basic_machine=hppa1.0-hp + ;; + hp9k7[0-79][0-9] | hp7[0-79][0-9]) + basic_machine=hppa1.1-hp + ;; + hp9k78[0-9] | hp78[0-9]) + # FIXME: really hppa2.0-hp + basic_machine=hppa1.1-hp + ;; + hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893) + # FIXME: really hppa2.0-hp + basic_machine=hppa1.1-hp + ;; + hp9k8[0-9][13679] | hp8[0-9][13679]) + basic_machine=hppa1.1-hp + ;; + hp9k8[0-9][0-9] | hp8[0-9][0-9]) + basic_machine=hppa1.0-hp + ;; + hppa-next) + os=-nextstep3 + ;; + hppaosf) + basic_machine=hppa1.1-hp + os=-osf + ;; + hppro) + basic_machine=hppa1.1-hp + os=-proelf + ;; + i370-ibm* | ibm*) + basic_machine=i370-ibm + ;; + i*86v32) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-sysv32 + ;; + i*86v4*) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-sysv4 + ;; + i*86v) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-sysv + ;; + i*86sol2) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-solaris2 + ;; + i386mach) + basic_machine=i386-mach + os=-mach + ;; + i386-vsta | vsta) + basic_machine=i386-unknown + os=-vsta + ;; + iris | iris4d) + basic_machine=mips-sgi + case $os in + -irix*) + ;; + *) + os=-irix4 + ;; + esac + ;; + isi68 | isi) + basic_machine=m68k-isi + os=-sysv + ;; + leon-*|leon[3-9]-*) + basic_machine=sparc-`echo $basic_machine | sed 's/-.*//'` + ;; + m68knommu) + basic_machine=m68k-unknown + os=-linux + ;; + m68knommu-*) + basic_machine=m68k-`echo $basic_machine | sed 's/^[^-]*-//'` + os=-linux + ;; + m88k-omron*) + basic_machine=m88k-omron + ;; + magnum | m3230) + basic_machine=mips-mips + os=-sysv + ;; + merlin) + basic_machine=ns32k-utek + os=-sysv + ;; + microblaze*) + basic_machine=microblaze-xilinx + ;; + mingw64) + basic_machine=x86_64-pc + os=-mingw64 + ;; + mingw32) + basic_machine=i686-pc + os=-mingw32 + ;; + mingw32ce) + basic_machine=arm-unknown + os=-mingw32ce + ;; + miniframe) + basic_machine=m68000-convergent + ;; + *mint | -mint[0-9]* | *MiNT | *MiNT[0-9]*) + basic_machine=m68k-atari + os=-mint + ;; + mips3*-*) + basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'` + ;; + mips3*) + basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown + ;; + monitor) + basic_machine=m68k-rom68k + os=-coff + ;; + morphos) + basic_machine=powerpc-unknown + os=-morphos + ;; + moxiebox) + basic_machine=moxie-unknown + os=-moxiebox + ;; + msdos) + basic_machine=i386-pc + os=-msdos + ;; + ms1-*) + basic_machine=`echo $basic_machine | sed -e 's/ms1-/mt-/'` + ;; + msys) + basic_machine=i686-pc + os=-msys + ;; + mvs) + basic_machine=i370-ibm + os=-mvs + ;; + nacl) + basic_machine=le32-unknown + os=-nacl + ;; + ncr3000) + basic_machine=i486-ncr + os=-sysv4 + ;; + netbsd386) + basic_machine=i386-unknown + os=-netbsd + ;; + netwinder) + basic_machine=armv4l-rebel + os=-linux + ;; + news | news700 | news800 | news900) + basic_machine=m68k-sony + os=-newsos + ;; + news1000) + basic_machine=m68030-sony + os=-newsos + ;; + news-3600 | risc-news) + basic_machine=mips-sony + os=-newsos + ;; + necv70) + basic_machine=v70-nec + os=-sysv + ;; + next | m*-next ) + basic_machine=m68k-next + case $os in + -nextstep* ) + ;; + -ns2*) + os=-nextstep2 + ;; + *) + os=-nextstep3 + ;; + esac + ;; + nh3000) + basic_machine=m68k-harris + os=-cxux + ;; + nh[45]000) + basic_machine=m88k-harris + os=-cxux + ;; + nindy960) + basic_machine=i960-intel + os=-nindy + ;; + mon960) + basic_machine=i960-intel + os=-mon960 + ;; + nonstopux) + basic_machine=mips-compaq + os=-nonstopux + ;; + np1) + basic_machine=np1-gould + ;; + neo-tandem) + basic_machine=neo-tandem + ;; + nse-tandem) + basic_machine=nse-tandem + ;; + nsr-tandem) + basic_machine=nsr-tandem + ;; + op50n-* | op60c-*) + basic_machine=hppa1.1-oki + os=-proelf + ;; + openrisc | openrisc-*) + basic_machine=or32-unknown + ;; + os400) + basic_machine=powerpc-ibm + os=-os400 + ;; + OSE68000 | ose68000) + basic_machine=m68000-ericsson + os=-ose + ;; + os68k) + basic_machine=m68k-none + os=-os68k + ;; + pa-hitachi) + basic_machine=hppa1.1-hitachi + os=-hiuxwe2 + ;; + paragon) + basic_machine=i860-intel + os=-osf + ;; + parisc) + basic_machine=hppa-unknown + os=-linux + ;; + parisc-*) + basic_machine=hppa-`echo $basic_machine | sed 's/^[^-]*-//'` + os=-linux + ;; + pbd) + basic_machine=sparc-tti + ;; + pbb) + basic_machine=m68k-tti + ;; + pc532 | pc532-*) + basic_machine=ns32k-pc532 + ;; + pc98) + basic_machine=i386-pc + ;; + pc98-*) + basic_machine=i386-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pentium | p5 | k5 | k6 | nexgen | viac3) + basic_machine=i586-pc + ;; + pentiumpro | p6 | 6x86 | athlon | athlon_*) + basic_machine=i686-pc + ;; + pentiumii | pentium2 | pentiumiii | pentium3) + basic_machine=i686-pc + ;; + pentium4) + basic_machine=i786-pc + ;; + pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*) + basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pentiumpro-* | p6-* | 6x86-* | athlon-*) + basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pentiumii-* | pentium2-* | pentiumiii-* | pentium3-*) + basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pentium4-*) + basic_machine=i786-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pn) + basic_machine=pn-gould + ;; + power) basic_machine=power-ibm + ;; + ppc | ppcbe) basic_machine=powerpc-unknown + ;; + ppc-* | ppcbe-*) + basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ppcle | powerpclittle) + basic_machine=powerpcle-unknown + ;; + ppcle-* | powerpclittle-*) + basic_machine=powerpcle-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ppc64) basic_machine=powerpc64-unknown + ;; + ppc64-*) basic_machine=powerpc64-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ppc64le | powerpc64little) + basic_machine=powerpc64le-unknown + ;; + ppc64le-* | powerpc64little-*) + basic_machine=powerpc64le-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ps2) + basic_machine=i386-ibm + ;; + pw32) + basic_machine=i586-unknown + os=-pw32 + ;; + rdos | rdos64) + basic_machine=x86_64-pc + os=-rdos + ;; + rdos32) + basic_machine=i386-pc + os=-rdos + ;; + rom68k) + basic_machine=m68k-rom68k + os=-coff + ;; + rm[46]00) + basic_machine=mips-siemens + ;; + rtpc | rtpc-*) + basic_machine=romp-ibm + ;; + s390 | s390-*) + basic_machine=s390-ibm + ;; + s390x | s390x-*) + basic_machine=s390x-ibm + ;; + sa29200) + basic_machine=a29k-amd + os=-udi + ;; + sb1) + basic_machine=mipsisa64sb1-unknown + ;; + sb1el) + basic_machine=mipsisa64sb1el-unknown + ;; + sde) + basic_machine=mipsisa32-sde + os=-elf + ;; + sei) + basic_machine=mips-sei + os=-seiux + ;; + sequent) + basic_machine=i386-sequent + ;; + sh) + basic_machine=sh-hitachi + os=-hms + ;; + sh5el) + basic_machine=sh5le-unknown + ;; + sh64) + basic_machine=sh64-unknown + ;; + sparclite-wrs | simso-wrs) + basic_machine=sparclite-wrs + os=-vxworks + ;; + sps7) + basic_machine=m68k-bull + os=-sysv2 + ;; + spur) + basic_machine=spur-unknown + ;; + st2000) + basic_machine=m68k-tandem + ;; + stratus) + basic_machine=i860-stratus + os=-sysv4 + ;; + strongarm-* | thumb-*) + basic_machine=arm-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + sun2) + basic_machine=m68000-sun + ;; + sun2os3) + basic_machine=m68000-sun + os=-sunos3 + ;; + sun2os4) + basic_machine=m68000-sun + os=-sunos4 + ;; + sun3os3) + basic_machine=m68k-sun + os=-sunos3 + ;; + sun3os4) + basic_machine=m68k-sun + os=-sunos4 + ;; + sun4os3) + basic_machine=sparc-sun + os=-sunos3 + ;; + sun4os4) + basic_machine=sparc-sun + os=-sunos4 + ;; + sun4sol2) + basic_machine=sparc-sun + os=-solaris2 + ;; + sun3 | sun3-*) + basic_machine=m68k-sun + ;; + sun4) + basic_machine=sparc-sun + ;; + sun386 | sun386i | roadrunner) + basic_machine=i386-sun + ;; + sv1) + basic_machine=sv1-cray + os=-unicos + ;; + symmetry) + basic_machine=i386-sequent + os=-dynix + ;; + t3e) + basic_machine=alphaev5-cray + os=-unicos + ;; + t90) + basic_machine=t90-cray + os=-unicos + ;; + tile*) + basic_machine=$basic_machine-unknown + os=-linux-gnu + ;; + tx39) + basic_machine=mipstx39-unknown + ;; + tx39el) + basic_machine=mipstx39el-unknown + ;; + toad1) + basic_machine=pdp10-xkl + os=-tops20 + ;; + tower | tower-32) + basic_machine=m68k-ncr + ;; + tpf) + basic_machine=s390x-ibm + os=-tpf + ;; + udi29k) + basic_machine=a29k-amd + os=-udi + ;; + ultra3) + basic_machine=a29k-nyu + os=-sym1 + ;; + v810 | necv810) + basic_machine=v810-nec + os=-none + ;; + vaxv) + basic_machine=vax-dec + os=-sysv + ;; + vms) + basic_machine=vax-dec + os=-vms + ;; + vpp*|vx|vx-*) + basic_machine=f301-fujitsu + ;; + vxworks960) + basic_machine=i960-wrs + os=-vxworks + ;; + vxworks68) + basic_machine=m68k-wrs + os=-vxworks + ;; + vxworks29k) + basic_machine=a29k-wrs + os=-vxworks + ;; + w65*) + basic_machine=w65-wdc + os=-none + ;; + w89k-*) + basic_machine=hppa1.1-winbond + os=-proelf + ;; + xbox) + basic_machine=i686-pc + os=-mingw32 + ;; + xps | xps100) + basic_machine=xps100-honeywell + ;; + xscale-* | xscalee[bl]-*) + basic_machine=`echo $basic_machine | sed 's/^xscale/arm/'` + ;; + ymp) + basic_machine=ymp-cray + os=-unicos + ;; + z8k-*-coff) + basic_machine=z8k-unknown + os=-sim + ;; + z80-*-coff) + basic_machine=z80-unknown + os=-sim + ;; + none) + basic_machine=none-none + os=-none + ;; + +# Here we handle the default manufacturer of certain CPU types. It is in +# some cases the only manufacturer, in others, it is the most popular. + w89k) + basic_machine=hppa1.1-winbond + ;; + op50n) + basic_machine=hppa1.1-oki + ;; + op60c) + basic_machine=hppa1.1-oki + ;; + romp) + basic_machine=romp-ibm + ;; + mmix) + basic_machine=mmix-knuth + ;; + rs6000) + basic_machine=rs6000-ibm + ;; + vax) + basic_machine=vax-dec + ;; + pdp10) + # there are many clones, so DEC is not a safe bet + basic_machine=pdp10-unknown + ;; + pdp11) + basic_machine=pdp11-dec + ;; + we32k) + basic_machine=we32k-att + ;; + sh[1234] | sh[24]a | sh[24]aeb | sh[34]eb | sh[1234]le | sh[23]ele) + basic_machine=sh-unknown + ;; + sparc | sparcv8 | sparcv9 | sparcv9b | sparcv9v) + basic_machine=sparc-sun + ;; + cydra) + basic_machine=cydra-cydrome + ;; + orion) + basic_machine=orion-highlevel + ;; + orion105) + basic_machine=clipper-highlevel + ;; + mac | mpw | mac-mpw) + basic_machine=m68k-apple + ;; + pmac | pmac-mpw) + basic_machine=powerpc-apple + ;; + *-unknown) + # Make sure to match an already-canonicalized machine name. + ;; + *) + echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 + exit 1 + ;; +esac + +# Here we canonicalize certain aliases for manufacturers. +case $basic_machine in + *-digital*) + basic_machine=`echo $basic_machine | sed 's/digital.*/dec/'` + ;; + *-commodore*) + basic_machine=`echo $basic_machine | sed 's/commodore.*/cbm/'` + ;; + *) + ;; +esac + +# Decode manufacturer-specific aliases for certain operating systems. + +if [ x"$os" != x"" ] +then +case $os in + # First match some system type aliases + # that might get confused with valid system types. + # -solaris* is a basic system type, with this one exception. + -auroraux) + os=-auroraux + ;; + -solaris1 | -solaris1.*) + os=`echo $os | sed -e 's|solaris1|sunos4|'` + ;; + -solaris) + os=-solaris2 + ;; + -svr4*) + os=-sysv4 + ;; + -unixware*) + os=-sysv4.2uw + ;; + -gnu/linux*) + os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'` + ;; + # First accept the basic system types. + # The portable systems comes first. + # Each alternative MUST END IN A *, to match a version number. + # -sysv* is not here because it comes later, after sysvr4. + -gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \ + | -*vms* | -sco* | -esix* | -isc* | -aix* | -cnk* | -sunos | -sunos[34]*\ + | -hpux* | -unos* | -osf* | -luna* | -dgux* | -auroraux* | -solaris* \ + | -sym* | -kopensolaris* | -plan9* \ + | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \ + | -aos* | -aros* | -cloudabi* | -sortix* \ + | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \ + | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \ + | -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* \ + | -bitrig* | -openbsd* | -solidbsd* | -libertybsd* \ + | -ekkobsd* | -kfreebsd* | -freebsd* | -riscix* | -lynxos* \ + | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \ + | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \ + | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \ + | -chorusos* | -chorusrdb* | -cegcc* \ + | -cygwin* | -msys* | -pe* | -psos* | -moss* | -proelf* | -rtems* \ + | -midipix* | -mingw32* | -mingw64* | -linux-gnu* | -linux-android* \ + | -linux-newlib* | -linux-musl* | -linux-uclibc* \ + | -uxpv* | -beos* | -mpeix* | -udk* | -moxiebox* \ + | -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \ + | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \ + | -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \ + | -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \ + | -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \ + | -powermax* | -dnix* | -nx6 | -nx7 | -sei* | -dragonfly* \ + | -skyos* | -haiku* | -rdos* | -toppers* | -drops* | -es* \ + | -onefs* | -tirtos* | -phoenix*) + # Remember, each alternative MUST END IN *, to match a version number. + ;; + -qnx*) + case $basic_machine in + x86-* | i*86-*) + ;; + *) + os=-nto$os + ;; + esac + ;; + -nto-qnx*) + ;; + -nto*) + os=`echo $os | sed -e 's|nto|nto-qnx|'` + ;; + -sim | -es1800* | -hms* | -xray | -os68k* | -none* | -v88r* \ + | -windows* | -osx | -abug | -netware* | -os9* | -beos* | -haiku* \ + | -macos* | -mpw* | -magic* | -mmixware* | -mon960* | -lnews*) + ;; + -mac*) + os=`echo $os | sed -e 's|mac|macos|'` + ;; + -linux-dietlibc) + os=-linux-dietlibc + ;; + -linux*) + os=`echo $os | sed -e 's|linux|linux-gnu|'` + ;; + -sunos5*) + os=`echo $os | sed -e 's|sunos5|solaris2|'` + ;; + -sunos6*) + os=`echo $os | sed -e 's|sunos6|solaris3|'` + ;; + -opened*) + os=-openedition + ;; + -os400*) + os=-os400 + ;; + -wince*) + os=-wince + ;; + -osfrose*) + os=-osfrose + ;; + -osf*) + os=-osf + ;; + -utek*) + os=-bsd + ;; + -dynix*) + os=-bsd + ;; + -acis*) + os=-aos + ;; + -atheos*) + os=-atheos + ;; + -syllable*) + os=-syllable + ;; + -386bsd) + os=-bsd + ;; + -ctix* | -uts*) + os=-sysv + ;; + -nova*) + os=-rtmk-nova + ;; + -ns2 ) + os=-nextstep2 + ;; + -nsk*) + os=-nsk + ;; + # Preserve the version number of sinix5. + -sinix5.*) + os=`echo $os | sed -e 's|sinix|sysv|'` + ;; + -sinix*) + os=-sysv4 + ;; + -tpf*) + os=-tpf + ;; + -triton*) + os=-sysv3 + ;; + -oss*) + os=-sysv3 + ;; + -svr4) + os=-sysv4 + ;; + -svr3) + os=-sysv3 + ;; + -sysvr4) + os=-sysv4 + ;; + # This must come after -sysvr4. + -sysv*) + ;; + -ose*) + os=-ose + ;; + -es1800*) + os=-ose + ;; + -xenix) + os=-xenix + ;; + -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) + os=-mint + ;; + -aros*) + os=-aros + ;; + -zvmoe) + os=-zvmoe + ;; + -dicos*) + os=-dicos + ;; + -nacl*) + ;; + -ios) + ;; + -none) + ;; + *) + # Get rid of the `-' at the beginning of $os. + os=`echo $os | sed 's/[^-]*-//'` + echo Invalid configuration \`$1\': system \`$os\' not recognized 1>&2 + exit 1 + ;; +esac +else + +# Here we handle the default operating systems that come with various machines. +# The value should be what the vendor currently ships out the door with their +# machine or put another way, the most popular os provided with the machine. + +# Note that if you're going to try to match "-MANUFACTURER" here (say, +# "-sun"), then you have to tell the case statement up towards the top +# that MANUFACTURER isn't an operating system. Otherwise, code above +# will signal an error saying that MANUFACTURER isn't an operating +# system, and we'll never get to this point. + +case $basic_machine in + score-*) + os=-elf + ;; + spu-*) + os=-elf + ;; + *-acorn) + os=-riscix1.2 + ;; + arm*-rebel) + os=-linux + ;; + arm*-semi) + os=-aout + ;; + c4x-* | tic4x-*) + os=-coff + ;; + c8051-*) + os=-elf + ;; + hexagon-*) + os=-elf + ;; + tic54x-*) + os=-coff + ;; + tic55x-*) + os=-coff + ;; + tic6x-*) + os=-coff + ;; + # This must come before the *-dec entry. + pdp10-*) + os=-tops20 + ;; + pdp11-*) + os=-none + ;; + *-dec | vax-*) + os=-ultrix4.2 + ;; + m68*-apollo) + os=-domain + ;; + i386-sun) + os=-sunos4.0.2 + ;; + m68000-sun) + os=-sunos3 + ;; + m68*-cisco) + os=-aout + ;; + mep-*) + os=-elf + ;; + mips*-cisco) + os=-elf + ;; + mips*-*) + os=-elf + ;; + or32-*) + os=-coff + ;; + *-tti) # must be before sparc entry or we get the wrong os. + os=-sysv3 + ;; + sparc-* | *-sun) + os=-sunos4.1.1 + ;; + *-be) + os=-beos + ;; + *-haiku) + os=-haiku + ;; + *-ibm) + os=-aix + ;; + *-knuth) + os=-mmixware + ;; + *-wec) + os=-proelf + ;; + *-winbond) + os=-proelf + ;; + *-oki) + os=-proelf + ;; + *-hp) + os=-hpux + ;; + *-hitachi) + os=-hiux + ;; + i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent) + os=-sysv + ;; + *-cbm) + os=-amigaos + ;; + *-dg) + os=-dgux + ;; + *-dolphin) + os=-sysv3 + ;; + m68k-ccur) + os=-rtu + ;; + m88k-omron*) + os=-luna + ;; + *-next ) + os=-nextstep + ;; + *-sequent) + os=-ptx + ;; + *-crds) + os=-unos + ;; + *-ns) + os=-genix + ;; + i370-*) + os=-mvs + ;; + *-next) + os=-nextstep3 + ;; + *-gould) + os=-sysv + ;; + *-highlevel) + os=-bsd + ;; + *-encore) + os=-bsd + ;; + *-sgi) + os=-irix + ;; + *-siemens) + os=-sysv4 + ;; + *-masscomp) + os=-rtu + ;; + f30[01]-fujitsu | f700-fujitsu) + os=-uxpv + ;; + *-rom68k) + os=-coff + ;; + *-*bug) + os=-coff + ;; + *-apple) + os=-macos + ;; + *-atari*) + os=-mint + ;; + *) + os=-none + ;; +esac +fi + +# Here we handle the case where we know the os, and the CPU type, but not the +# manufacturer. We pick the logical manufacturer. +vendor=unknown +case $basic_machine in + *-unknown) + case $os in + -riscix*) + vendor=acorn + ;; + -sunos*) + vendor=sun + ;; + -cnk*|-aix*) + vendor=ibm + ;; + -beos*) + vendor=be + ;; + -hpux*) + vendor=hp + ;; + -mpeix*) + vendor=hp + ;; + -hiux*) + vendor=hitachi + ;; + -unos*) + vendor=crds + ;; + -dgux*) + vendor=dg + ;; + -luna*) + vendor=omron + ;; + -genix*) + vendor=ns + ;; + -mvs* | -opened*) + vendor=ibm + ;; + -os400*) + vendor=ibm + ;; + -ptx*) + vendor=sequent + ;; + -tpf*) + vendor=ibm + ;; + -vxsim* | -vxworks* | -windiss*) + vendor=wrs + ;; + -aux*) + vendor=apple + ;; + -hms*) + vendor=hitachi + ;; + -mpw* | -macos*) + vendor=apple + ;; + -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) + vendor=atari + ;; + -vos*) + vendor=stratus + ;; + esac + basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"` + ;; +esac + +echo $basic_machine$os +exit + +# Local variables: +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "timestamp='" +# time-stamp-format: "%:y-%02m-%02d" +# time-stamp-end: "'" +# End: diff --git a/tools/depends/build-aux/install-sh b/tools/depends/build-aux/install-sh new file mode 100644 index 0000000..a9244eb --- /dev/null +++ b/tools/depends/build-aux/install-sh @@ -0,0 +1,527 @@ +#!/bin/sh +# install - install a program, script, or datafile + +scriptversion=2011-01-19.21; # UTC + +# This originates from X11R5 (mit/util/scripts/install.sh), which was +# later released in X11R6 (xc/config/util/install.sh) with the +# following copyright and license. +# +# Copyright (C) 1994 X Consortium +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to +# deal in the Software without restriction, including without limitation the +# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +# sell copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +# AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC- +# TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# +# Except as contained in this notice, the name of the X Consortium shall not +# be used in advertising or otherwise to promote the sale, use or other deal- +# ings in this Software without prior written authorization from the X Consor- +# tium. +# +# +# FSF changes to this file are in the public domain. +# +# Calling this script install-sh is preferred over install.sh, to prevent +# `make' implicit rules from creating a file called install from it +# when there is no Makefile. +# +# This script is compatible with the BSD install script, but was written +# from scratch. + +nl=' +' +IFS=" "" $nl" + +# set DOITPROG to echo to test this script + +# Don't use :- since 4.3BSD and earlier shells don't like it. +doit=${DOITPROG-} +if test -z "$doit"; then + doit_exec=exec +else + doit_exec=$doit +fi + +# Put in absolute file names if you don't have them in your path; +# or use environment vars. + +chgrpprog=${CHGRPPROG-chgrp} +chmodprog=${CHMODPROG-chmod} +chownprog=${CHOWNPROG-chown} +cmpprog=${CMPPROG-cmp} +cpprog=${CPPROG-cp} +mkdirprog=${MKDIRPROG-mkdir} +mvprog=${MVPROG-mv} +rmprog=${RMPROG-rm} +stripprog=${STRIPPROG-strip} + +posix_glob='?' +initialize_posix_glob=' + test "$posix_glob" != "?" || { + if (set -f) 2>/dev/null; then + posix_glob= + else + posix_glob=: + fi + } +' + +posix_mkdir= + +# Desired mode of installed file. +mode=0755 + +chgrpcmd= +chmodcmd=$chmodprog +chowncmd= +mvcmd=$mvprog +rmcmd="$rmprog -f" +stripcmd= + +src= +dst= +dir_arg= +dst_arg= + +copy_on_change=false +no_target_directory= + +usage="\ +Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE + or: $0 [OPTION]... SRCFILES... DIRECTORY + or: $0 [OPTION]... -t DIRECTORY SRCFILES... + or: $0 [OPTION]... -d DIRECTORIES... + +In the 1st form, copy SRCFILE to DSTFILE. +In the 2nd and 3rd, copy all SRCFILES to DIRECTORY. +In the 4th, create DIRECTORIES. + +Options: + --help display this help and exit. + --version display version info and exit. + + -c (ignored) + -C install only if different (preserve the last data modification time) + -d create directories instead of installing files. + -g GROUP $chgrpprog installed files to GROUP. + -m MODE $chmodprog installed files to MODE. + -o USER $chownprog installed files to USER. + -s $stripprog installed files. + -t DIRECTORY install into DIRECTORY. + -T report an error if DSTFILE is a directory. + +Environment variables override the default commands: + CHGRPPROG CHMODPROG CHOWNPROG CMPPROG CPPROG MKDIRPROG MVPROG + RMPROG STRIPPROG +" + +while test $# -ne 0; do + case $1 in + -c) ;; + + -C) copy_on_change=true;; + + -d) dir_arg=true;; + + -g) chgrpcmd="$chgrpprog $2" + shift;; + + --help) echo "$usage"; exit $?;; + + -m) mode=$2 + case $mode in + *' '* | *' '* | *' +'* | *'*'* | *'?'* | *'['*) + echo "$0: invalid mode: $mode" >&2 + exit 1;; + esac + shift;; + + -o) chowncmd="$chownprog $2" + shift;; + + -s) stripcmd=$stripprog;; + + -t) dst_arg=$2 + # Protect names problematic for `test' and other utilities. + case $dst_arg in + -* | [=\(\)!]) dst_arg=./$dst_arg;; + esac + shift;; + + -T) no_target_directory=true;; + + --version) echo "$0 $scriptversion"; exit $?;; + + --) shift + break;; + + -*) echo "$0: invalid option: $1" >&2 + exit 1;; + + *) break;; + esac + shift +done + +if test $# -ne 0 && test -z "$dir_arg$dst_arg"; then + # When -d is used, all remaining arguments are directories to create. + # When -t is used, the destination is already specified. + # Otherwise, the last argument is the destination. Remove it from $@. + for arg + do + if test -n "$dst_arg"; then + # $@ is not empty: it contains at least $arg. + set fnord "$@" "$dst_arg" + shift # fnord + fi + shift # arg + dst_arg=$arg + # Protect names problematic for `test' and other utilities. + case $dst_arg in + -* | [=\(\)!]) dst_arg=./$dst_arg;; + esac + done +fi + +if test $# -eq 0; then + if test -z "$dir_arg"; then + echo "$0: no input file specified." >&2 + exit 1 + fi + # It's OK to call `install-sh -d' without argument. + # This can happen when creating conditional directories. + exit 0 +fi + +if test -z "$dir_arg"; then + do_exit='(exit $ret); exit $ret' + trap "ret=129; $do_exit" 1 + trap "ret=130; $do_exit" 2 + trap "ret=141; $do_exit" 13 + trap "ret=143; $do_exit" 15 + + # Set umask so as not to create temps with too-generous modes. + # However, 'strip' requires both read and write access to temps. + case $mode in + # Optimize common cases. + *644) cp_umask=133;; + *755) cp_umask=22;; + + *[0-7]) + if test -z "$stripcmd"; then + u_plus_rw= + else + u_plus_rw='% 200' + fi + cp_umask=`expr '(' 777 - $mode % 1000 ')' $u_plus_rw`;; + *) + if test -z "$stripcmd"; then + u_plus_rw= + else + u_plus_rw=,u+rw + fi + cp_umask=$mode$u_plus_rw;; + esac +fi + +for src +do + # Protect names problematic for `test' and other utilities. + case $src in + -* | [=\(\)!]) src=./$src;; + esac + + if test -n "$dir_arg"; then + dst=$src + dstdir=$dst + test -d "$dstdir" + dstdir_status=$? + else + + # Waiting for this to be detected by the "$cpprog $src $dsttmp" command + # might cause directories to be created, which would be especially bad + # if $src (and thus $dsttmp) contains '*'. + if test ! -f "$src" && test ! -d "$src"; then + echo "$0: $src does not exist." >&2 + exit 1 + fi + + if test -z "$dst_arg"; then + echo "$0: no destination specified." >&2 + exit 1 + fi + dst=$dst_arg + + # If destination is a directory, append the input filename; won't work + # if double slashes aren't ignored. + if test -d "$dst"; then + if test -n "$no_target_directory"; then + echo "$0: $dst_arg: Is a directory" >&2 + exit 1 + fi + dstdir=$dst + dst=$dstdir/`basename "$src"` + dstdir_status=0 + else + # Prefer dirname, but fall back on a substitute if dirname fails. + dstdir=` + (dirname "$dst") 2>/dev/null || + expr X"$dst" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$dst" : 'X\(//\)[^/]' \| \ + X"$dst" : 'X\(//\)$' \| \ + X"$dst" : 'X\(/\)' \| . 2>/dev/null || + echo X"$dst" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q' + ` + + test -d "$dstdir" + dstdir_status=$? + fi + fi + + obsolete_mkdir_used=false + + if test $dstdir_status != 0; then + case $posix_mkdir in + '') + # Create intermediate dirs using mode 755 as modified by the umask. + # This is like FreeBSD 'install' as of 1997-10-28. + umask=`umask` + case $stripcmd.$umask in + # Optimize common cases. + *[2367][2367]) mkdir_umask=$umask;; + .*0[02][02] | .[02][02] | .[02]) mkdir_umask=22;; + + *[0-7]) + mkdir_umask=`expr $umask + 22 \ + - $umask % 100 % 40 + $umask % 20 \ + - $umask % 10 % 4 + $umask % 2 + `;; + *) mkdir_umask=$umask,go-w;; + esac + + # With -d, create the new directory with the user-specified mode. + # Otherwise, rely on $mkdir_umask. + if test -n "$dir_arg"; then + mkdir_mode=-m$mode + else + mkdir_mode= + fi + + posix_mkdir=false + case $umask in + *[123567][0-7][0-7]) + # POSIX mkdir -p sets u+wx bits regardless of umask, which + # is incompatible with FreeBSD 'install' when (umask & 300) != 0. + ;; + *) + tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$ + trap 'ret=$?; rmdir "$tmpdir/d" "$tmpdir" 2>/dev/null; exit $ret' 0 + + if (umask $mkdir_umask && + exec $mkdirprog $mkdir_mode -p -- "$tmpdir/d") >/dev/null 2>&1 + then + if test -z "$dir_arg" || { + # Check for POSIX incompatibilities with -m. + # HP-UX 11.23 and IRIX 6.5 mkdir -m -p sets group- or + # other-writeable bit of parent directory when it shouldn't. + # FreeBSD 6.1 mkdir -m -p sets mode of existing directory. + ls_ld_tmpdir=`ls -ld "$tmpdir"` + case $ls_ld_tmpdir in + d????-?r-*) different_mode=700;; + d????-?--*) different_mode=755;; + *) false;; + esac && + $mkdirprog -m$different_mode -p -- "$tmpdir" && { + ls_ld_tmpdir_1=`ls -ld "$tmpdir"` + test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1" + } + } + then posix_mkdir=: + fi + rmdir "$tmpdir/d" "$tmpdir" + else + # Remove any dirs left behind by ancient mkdir implementations. + rmdir ./$mkdir_mode ./-p ./-- 2>/dev/null + fi + trap '' 0;; + esac;; + esac + + if + $posix_mkdir && ( + umask $mkdir_umask && + $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir" + ) + then : + else + + # The umask is ridiculous, or mkdir does not conform to POSIX, + # or it failed possibly due to a race condition. Create the + # directory the slow way, step by step, checking for races as we go. + + case $dstdir in + /*) prefix='/';; + [-=\(\)!]*) prefix='./';; + *) prefix='';; + esac + + eval "$initialize_posix_glob" + + oIFS=$IFS + IFS=/ + $posix_glob set -f + set fnord $dstdir + shift + $posix_glob set +f + IFS=$oIFS + + prefixes= + + for d + do + test X"$d" = X && continue + + prefix=$prefix$d + if test -d "$prefix"; then + prefixes= + else + if $posix_mkdir; then + (umask=$mkdir_umask && + $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir") && break + # Don't fail if two instances are running concurrently. + test -d "$prefix" || exit 1 + else + case $prefix in + *\'*) qprefix=`echo "$prefix" | sed "s/'/'\\\\\\\\''/g"`;; + *) qprefix=$prefix;; + esac + prefixes="$prefixes '$qprefix'" + fi + fi + prefix=$prefix/ + done + + if test -n "$prefixes"; then + # Don't fail if two instances are running concurrently. + (umask $mkdir_umask && + eval "\$doit_exec \$mkdirprog $prefixes") || + test -d "$dstdir" || exit 1 + obsolete_mkdir_used=true + fi + fi + fi + + if test -n "$dir_arg"; then + { test -z "$chowncmd" || $doit $chowncmd "$dst"; } && + { test -z "$chgrpcmd" || $doit $chgrpcmd "$dst"; } && + { test "$obsolete_mkdir_used$chowncmd$chgrpcmd" = false || + test -z "$chmodcmd" || $doit $chmodcmd $mode "$dst"; } || exit 1 + else + + # Make a couple of temp file names in the proper directory. + dsttmp=$dstdir/_inst.$$_ + rmtmp=$dstdir/_rm.$$_ + + # Trap to clean up those temp files at exit. + trap 'ret=$?; rm -f "$dsttmp" "$rmtmp" && exit $ret' 0 + + # Copy the file name to the temp name. + (umask $cp_umask && $doit_exec $cpprog "$src" "$dsttmp") && + + # and set any options; do chmod last to preserve setuid bits. + # + # If any of these fail, we abort the whole thing. If we want to + # ignore errors from any of these, just make sure not to ignore + # errors from the above "$doit $cpprog $src $dsttmp" command. + # + { test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } && + { test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } && + { test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } && + { test -z "$chmodcmd" || $doit $chmodcmd $mode "$dsttmp"; } && + + # If -C, don't bother to copy if it wouldn't change the file. + if $copy_on_change && + old=`LC_ALL=C ls -dlL "$dst" 2>/dev/null` && + new=`LC_ALL=C ls -dlL "$dsttmp" 2>/dev/null` && + + eval "$initialize_posix_glob" && + $posix_glob set -f && + set X $old && old=:$2:$4:$5:$6 && + set X $new && new=:$2:$4:$5:$6 && + $posix_glob set +f && + + test "$old" = "$new" && + $cmpprog "$dst" "$dsttmp" >/dev/null 2>&1 + then + rm -f "$dsttmp" + else + # Rename the file to the real destination. + $doit $mvcmd -f "$dsttmp" "$dst" 2>/dev/null || + + # The rename failed, perhaps because mv can't rename something else + # to itself, or perhaps because mv is so ancient that it does not + # support -f. + { + # Now remove or move aside any old file at destination location. + # We try this two ways since rm can't unlink itself on some + # systems and the destination file might be busy for other + # reasons. In this case, the final cleanup might fail but the new + # file should still install successfully. + { + test ! -f "$dst" || + $doit $rmcmd -f "$dst" 2>/dev/null || + { $doit $mvcmd -f "$dst" "$rmtmp" 2>/dev/null && + { $doit $rmcmd -f "$rmtmp" 2>/dev/null; :; } + } || + { echo "$0: cannot unlink or rename $dst" >&2 + (exit 1); exit 1 + } + } && + + # Now rename the file to the real destination. + $doit $mvcmd "$dsttmp" "$dst" + } + fi || exit 1 + + trap '' 0 + fi +done + +# Local variables: +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "scriptversion=" +# time-stamp-format: "%:y-%02m-%02d.%02H" +# time-stamp-time-zone: "UTC" +# time-stamp-end: "; # UTC" +# End: diff --git a/tools/depends/configure.ac b/tools/depends/configure.ac new file mode 100644 index 0000000..30adee3 --- /dev/null +++ b/tools/depends/configure.ac @@ -0,0 +1,856 @@ +AC_PREREQ(2.59) +AC_INIT([xbmc-depends], [2.00], [https://github.com/xbmc/xbmc]) +:${CFLAGS=""} +AC_CONFIG_AUX_DIR([build-aux]) +AC_CONFIG_FILES([native/config.site.native Makefile.include + target/config.site target/config-binaddons.site + target/Toolchain.cmake target/Toolchain_binaddons.cmake + native/Toolchain-Native.cmake]) +AC_CANONICAL_HOST +AC_CANONICAL_BUILD + +m4_include([m4/xbmc_arch.m4]) +m4_include([m4/ax_cxx_compile_stdcxx.m4]) +m4_include([m4/ax_compare_version.m4]) + +# check for not same cpu value +AC_DEFUN([MC_CHECK_NOT_CPU], +[ + AC_MSG_CHECKING([for $2]) + case $1 in + $2*) + AC_MSG_ERROR(error in configure of --with-cpu=$1) + ;; + *) + AC_MSG_RESULT([$1 is not $2]) + esac +]) + +AC_ARG_ENABLE([debug], + [AS_HELP_STRING([--enable-debug], + [enable debugging information (default is yes)])], + [use_debug=$enableval], + [use_debug=yes]) + +AC_ARG_ENABLE([ccache], + [AS_HELP_STRING([--disable-ccache], + [disable ccache])], + [use_ccache=no], + [use_ccache=yes]) + +AC_ARG_WITH([linker], + [AS_HELP_STRING([--with-linker], + [specify linker to use.])], + [use_linker=$withval]) + +AC_ARG_WITH([toolchain], + [AS_HELP_STRING([--with-toolchain], + [specify path to toolchain. Auto set for android. Defaults to xcode root for darwin, /usr for linux])], + [use_toolchain=$withval]) + +AC_ARG_WITH([platform], + [AS_HELP_STRING([--with-platform], + [target platform [auto]])], + [use_platform=$withval], + [use_platform=auto]) + +AC_ARG_WITH([firmware], + [AS_HELP_STRING([--with-firmware], + [platform specific firmware []])], + [use_firmware=$withval]) + +AC_ARG_WITH([tarballs], + [AS_HELP_STRING([--with-tarballs], + [path where tarballs will be saved [prefix/xbmc-tarballs]])], + [use_tarballs=$withval]) + +AC_ARG_WITH([cpu], + [AS_HELP_STRING([--with-cpu], + [optional. specify target cpu. guessed if not specified])], + [use_cpu=$withval], + [use_cpu=auto]) + +AC_ARG_WITH([ndk-path], + [AS_HELP_STRING([--with-ndk-path], + [specify path to ndk (required for android only)])], + [use_ndk_path=$withval]) + +AC_ARG_WITH([sdk-path], + [AS_HELP_STRING([--with-sdk-path], + [specify path to sdk (required for android only)])], + [use_sdk_path=$withval]) + +AC_ARG_WITH([sdk], + [AS_HELP_STRING([--with-sdk], + [specify sdk platform version.])], + [use_sdk=$withval]) + +AC_ARG_WITH([ndk-api], + [AS_HELP_STRING([--with-ndk-api], + [specify ndk level (optional for android), default is 21.])], + [use_ndk_api=$withval], + [use_ndk_api=21]) + +AC_ARG_ENABLE([gplv3], + [AS_HELP_STRING([--enable-gplv3], + [enable gplv3 components. default is yes])], + [use_gplv3=$enableval], + [use_gplv3=yes]) + +AC_ARG_WITH([rendersystem], + [AS_HELP_STRING([--with-rendersystem], + [render system to use])], + [app_rendersystem=$withval]) + +AC_ARG_WITH([windowsystem], + [AS_HELP_STRING([--with-windowsystem], + [Windowing system to use])], + [app_winsystem=$withval]) + +AC_ARG_WITH([target-cflags], + [AS_HELP_STRING([--with-target-cflags], + [C compiler flags (target)])], + [target_cflags=$withval]) + +AC_ARG_WITH([target-cxxflags], + [AS_HELP_STRING([--with-target-cxxflags], + [C++ compiler flags (target)])], + [target_cxxflags=$withval], + [target_cxxflags=$target_cflags]) + +AC_ARG_WITH([target-ldflags], + [AS_HELP_STRING([--with-target-ldflags], + [linker flags. Use e.g. for -l<lib> (target)])], + [target_ldflags=$withval]) + +AC_ARG_WITH([ffmpeg-options], + [AS_HELP_STRING([--with-ffmpeg-options], + [FFmpeg configure options, e.g. --enable-vaapi (target)])], + [ffmpeg_options=$withval], + [ffmpeg_options=default]) + + +if test "$use_ccache" = "yes"; then + AC_CHECK_PROG(HAVE_CCACHE,ccache,"yes","no",) + if test "x$HAVE_CCACHE" = "xno" ; then + use_ccache=no + fi +fi + +AC_PATH_PROG(CURL,curl,"no") +if test "x$CURL" = "xno" ; then + AC_MSG_ERROR("Missing program: curl") +fi + +AC_PATH_PROG(TAR,tar,"no") +if test "x$TAR" = "xno" ; then + AC_MSG_ERROR("Missing program: tar") +fi + +if test "x$use_linker" = "x" ; then + use_linker=ld +fi + +if test "$use_debug" = "yes"; then + build_type="debug" +else + build_type="release" +fi + +use_host=$host_alias +use_build=$build_cpu-$build_vendor-$build_os +use_buildcpu=$build_cpu + +cross_compiling="yes" +if test "x$host" = "x$build"; then + use_host=$build_cpu-$build_os + cross_compiling="no" +fi + +deps_dir=$use_host-$build_type +tool_dir=$build_cpu-$build_os-native +cross_compiling="yes" + +case $build in + aarch64*-*-linux-gnu*|aarch64*-*-linux-uclibc*) + build_os="linux" + ;; + arm*-*-linux-gnu*|arm*-*-linux-uclibc*) + build_os="linux" + ;; + *i686*-linux-gnu*|i*86*-*-linux-uclibc*) + build_os="linux" + ;; + x86_64*-linux-gnu*|x86_64-*-linux-uclibc*) + build_os="linux" + android_toolchain_name="linux-x86_64" + ;; + *darwin*) + build_os="osx" + if test "x$build_cpu" = "xx86_64"; then + host_includes="-arch x86_64 -mmacosx-version-min=10.13" + else + host_includes="-arch arm64 -mmacosx-version-min=11.0" + fi + use_xcrun=xcrun + + # acquire build platform (native) sdk sysroot. + build_platform=macosx + native_sdk_path=[`$use_xcrun --show-sdk-path`] + host_sysroot="$native_sdk_path" + host_includes="${host_includes} -isysroot $native_sdk_path" + + CC_FOR_BUILD=[`$use_xcrun --find clang`] + use_build_toolchain=[`$CC_FOR_BUILD --version | grep InstalledDir | awk '{ print $2}'`] + + # Android NDK currently only x86_64 prebuilts - Arctic Fox 2020.3.1 + android_toolchain_name="darwin-x86_64" + + host_cxxflags="-std=c++17 -stdlib=libc++" + + if test "x$prefix" = "xNONE"; then + prefix=/Users/Shared/xbmc-depends + fi + ;; + *) + AC_MSG_ERROR(unsupported native build platform: $build) +esac + + +if test "x$build_os" = "xosx"; then + AC_PATH_PROG(SHASUM,shasum,"no") + if test "x$SHASUM" = "xno" ; then + AC_MSG_ERROR("Missing program: shasum") + fi +else + AC_PATH_PROG(SHA512SUM,sha512sum,"no") + if test "x$SHA512SUM" = "xno" ; then + AC_MSG_ERROR("Missing program: sha512sum") + fi + + AC_PATH_PROG(SHA256SUM,sha256sum,"no") + if test "x$SHA256SUM" = "xno" ; then + AC_MSG_ERROR("Missing program: sha256sum") + fi +fi + +if test -n $use_build_toolchain; then + PATH_FOR_BUILD=$use_build_toolchain:$use_build_toolchain/usr/bin:$use_toolchain/bin:$PATH +else + PATH_FOR_BUILD=$PATH +fi + +AC_PATH_PROG([RANLIB_FOR_BUILD], [ranlib], ranlib, $PATH_FOR_BUILD) +AC_PATH_PROG([LD_FOR_BUILD], [ld], ld, $PATH_FOR_BUILD) +AC_PATH_PROG([AR_FOR_BUILD], [ar], ar, $PATH_FOR_BUILD) +AC_PATH_PROG([READELF_FOR_BUILD], [readelf],, $PATH_FOR_BUILD) +AC_PATH_PROG([STRIP_FOR_BUILD], [strip], strip, $PATH_FOR_BUILD) +AC_PATH_PROG([AS_FOR_BUILD], [as], as, $PATH_FOR_BUILD) +AC_PATH_PROG([NM_FOR_BUILD], [nm], nm, $PATH_FOR_BUILD) +AC_PATH_PROG([OBJDUMP_FOR_BUILD], [objdump], objdump, $PATH_FOR_BUILD) +AC_PATH_PROG([CC_FOR_BUILD],[clang gcc llvm-gcc], gcc, $PATH_FOR_BUILD) +AC_PATH_PROG([CXX_FOR_BUILD],[clang++ g++ llvm-g++], g++, $PATH_FOR_BUILD) + +platform_cc=gcc +platform_cxx=g++ + +case $host in + *-*linux-android*) + use_toolchain="${use_toolchain:-$use_ndk_path/toolchains/llvm/prebuilt/$android_toolchain_name}" + platform_cc=$use_host$use_ndk_api-clang + platform_cxx=$use_host$use_ndk_api-clang++ + + platform_tool_prefix=llvm- + + case $host in + arm*-*linux-android*) + platform_cc=armv7a-linux-androideabi$use_ndk_api-clang + platform_cxx=armv7a-linux-androideabi$use_ndk_api-clang++ + esac + ;; + *darwin*) + CC=[`$use_xcrun --find clang`] + platform_cxx=clang++ + use_toolchain=[`$CC --version | grep InstalledDir | awk '{ print $2}'`] +esac + +if test -n $use_toolchain; then + PATH_FOR_HOST=$use_toolchain:$use_toolchain/usr/bin:$use_toolchain/bin:$PATH +else + PATH_FOR_HOST=$PATH +fi + +AC_PATH_TOOL([RANLIB], [${platform_tool_prefix}ranlib],, $PATH_FOR_HOST) +AC_PATH_TOOL([LD], [${use_linker}],, $PATH_FOR_HOST) +AC_PATH_TOOL([AR], [${platform_tool_prefix}ar],, $PATH_FOR_HOST) +AC_PATH_TOOL([READELF], [${platform_tool_prefix}readelf],, $PATH_FOR_HOST) +AC_PATH_TOOL([STRIP], [${platform_tool_prefix}strip],, $PATH_FOR_HOST) +AC_PATH_TOOL([AS], [${platform_tool_prefix}as],, $PATH_FOR_HOST) +AC_PATH_TOOL([NM], [${platform_tool_prefix}nm],, $PATH_FOR_HOST) +AC_PATH_TOOL([OBJDUMP], [${platform_tool_prefix}objdump],, $PATH_FOR_HOST) +AC_PATH_TOOL([CC],[$platform_cc],,$PATH_FOR_HOST) +AC_PATH_TOOL([CXX],[$platform_cxx],,$PATH_FOR_HOST) + +if test "x$LD" = "x"; then + AC_MSG_ERROR(No linker found with name ${use_linker}. You may want to provide using --with-linker=<linker>) +fi + +case $build in + *darwin*) + # MacOS 11 requires explicit isysroot for autoconf compiler tests + # However we do not want to pollute CFLAGS/CXXFLAGS once compiler tests are complete + CFLAGS="${CFLAGS} $host_includes" + CXXFLAGS="${CXXFLAGS} $host_includes" +esac + +AC_PROG_CPP + +case $build in + *darwin*) + CFLAGS=$(echo "$CFLAGS" | sed "s|$host_includes||") + CXXFLAGS=$(echo "$CXXFLAGS" | sed "s|$host_includes||") +esac + +case $host in + *-*linux-android*) + deps_dir="$use_host-$use_ndk_api-$build_type" + platform_cflags="-DANDROID -D__ANDROID_API__=$use_ndk_api -fexceptions -funwind-tables -fstack-protector-strong -no-canonical-prefixes -fPIC -DPIC" + optimize_flags="-Os" + platform_ldflags="-Wl,--exclude-libs,libgcc.a -Wl,--exclude-libs,libatomic.a -L$prefix/$deps_dir/lib/android-$use_ndk_api" + + case $host in + arm*-*linux-android*) + if test "x$use_cpu" = "xauto"; then + use_cpu="armeabi-v7a" + fi + if test "x$use_cpu" = "xarmeabi-v7a"; then + platform_cflags="${platform_cflags} -march=armv7-a -mtune=cortex-a9 -mfloat-abi=softfp -mfpu=neon" + fi + platform_ldflags="${platform_ldflags} -Wl,--exclude-libs,libunwind.a" + meson_cpu="arm" + ;; + aarch64*-*linux-android*) + if test "x$use_cpu" = "xauto"; then + use_cpu="arm64-v8a" + fi + if test "x$use_cpu" = "xarm64-v8a"; then + platform_cflags="${platform_cflags} -march=armv8-a -mtune=cortex-a53" + fi + meson_cpu="aarch64" + ;; + i*86*-linux-android*) + if test "x$use_cpu" = "xauto"; then + use_cpu=$host_cpu + fi + meson_cpu="x86" + ;; + x86_64*-linux-android*) + if test "x$use_cpu" = "xauto"; then + use_cpu=$host_cpu + fi + meson_cpu="x86_64" + ;; + *) + AC_MSG_ERROR(unsupported host ($use_host)) + esac + + platform_cxxflags="$platform_cflags -frtti" + platform_includes="-isystem $prefix/$deps_dir/include/android-$use_ndk_api" + platform_os="android" + meson_system="android" + #android builds are always cross + cross_compiling="yes" + ;; + arm*-*-linux-gnu*|arm*-*-linux-uclibc*|aarch64*-*-linux-gnu*|aarch*-*-linux-be*) + case $host in + arm*-*-linux-gnu*|arm*-*-linux-uclibc*) + meson_cpu="arm" + ;; + aarch64*-*-linux-gnu*|aarch*-*-linux-be*) + meson_cpu="aarch64" + ;; + esac + if test "x$use_cpu" = "xauto"; then + use_cpu=$host_cpu + fi + use_toolchain="${use_toolchain:-/usr}" + platform_cflags="-fPIC -DPIC" + optimize_flags="-Os" + platform_ldflags="-Wl,-rpath-link=$prefix/$deps_dir/lib" + platform_cxxflags="$platform_cflags" + platform_os="linux" + meson_system="linux" + target_platform="wayland gbm" + ;; + *i686*-linux-gnu*|i*86*-*-linux-uclibc*|x86_64*-linux-gnu*|x86_64-*-linux-uclibc*) + case $host in + *i686*-linux-gnu*|i*86*-*-linux-uclibc*) + meson_cpu="x86" + ;; + x86_64*-linux-gnu*|x86_64-*-linux-uclibc*) + meson_cpu="x86_64" + ;; + esac + use_cpu=$host_cpu + use_toolchain="${use_toolchain:-/usr}" + platform_cflags="-fPIC -DPIC" + optimize_flags="-O2" + platform_cxxflags="$platform_cflags" + platform_os="linux" + meson_system="linux" + ffmpeg_options_default="--enable-vaapi --enable-vdpau --cpu=$use_cpu" + target_platform="x11 wayland gbm" + ;; + *darwin*) + # darwin builds are always cross + cross_compiling="yes" + + meson_system="darwin" + + platform_cflags="-fheinous-gnu-extensions" + platform_ldflags="-Wl,-search_paths_first" + + case $use_platform in + tvos) + target_platform=appletvos + platform_os="darwin_embedded" + ;; + ios) + target_platform=iphoneos + platform_os="darwin_embedded" + ;; + macos) + target_platform=macosx + platform_os="osx" + ;; + *) + AC_MSG_ERROR(error in configure no platform provided --with-platform) + ;; + esac + + found_sdk_version=[`$use_xcrun --sdk $target_platform --show-sdk-version`] + use_sdk="${use_sdk:-$found_sdk_version}" + use_sdk_path=$($use_xcrun --sdk $target_platform --show-sdk-path) + sdk_name=$target_platform$use_sdk + + case $host in + x86_64-apple-darwin) + MC_CHECK_NOT_CPU([$use_cpu], "arm*") + + # setup which cpu to use + if test "x$use_cpu" = "xauto"; then + use_cpu=x86_64 + meson_cpu=$use_cpu + else + AC_MSG_ERROR(invalid architecture (--with-cpu=$use_cpu)) + fi + + target_minver="10.13" + + # check provided window system is valid_sdk + # if no window system supplied, default to SDL for now. + if test -n "$app_winsystem"; then + if test "$app_winsystem" != "native" && test "$app_winsystem" != "sdl"; then + AC_MSG_ERROR(Window system must be native or sdl) + fi + else + app_winsystem=sdl + fi + ;; + aarch64-apple-darwin*) + MC_CHECK_NOT_CPU([$use_cpu], "*86") + + case $platform_os in + darwin_embedded) + target_minver="11.0" + ;; + osx) + target_minver="11.0" + app_winsystem=native + ;; + *) + AC_MSG_ERROR(invalid platform for architecture ($host)) + ;; + esac + + # setup which cpu to use + if test "x$use_cpu" = "xauto"; then + use_cpu=arm64 + meson_cpu="aarch64" + else + AC_MSG_ERROR(invalid architecture (--with-cpu=$use_cpu)) + fi + + platform_cflags="${platform_cflags} -ftree-vectorize -pipe -Wno-trigraphs -fpascal-strings" + platform_cflags="${platform_cflags} -Wreturn-type -Wunused-variable -fmessage-length=0 -gdwarf-2" + optimize_flags="-O3" + platform_ldflags="${platform_ldflags} -L$use_sdk_path/usr/lib" + ;; + esac + + AX_COMPARE_VERSION([$use_sdk], [ge], [$target_minver], , AC_MSG_ERROR("invalid SDK version provided (--with-sdk=$use_sdk) less than minimum supported ($target_minver)")) + + platform_min_version="$target_platform-version-min=$target_minver" + + platform_includes="-arch $use_cpu -m$platform_min_version -isysroot $use_sdk_path" + platform_ldflags="${platform_ldflags} $platform_includes -stdlib=libc++" + platform_cxxflags="${platform_cxxflags} -stdlib=libc++" + deps_dir="${sdk_name}_${use_cpu}-target-${build_type}" + ;; + *) + AC_MSG_ERROR(unsupported host ($use_host)) +esac + +case $use_platform in + ios|tvos|macos) + ;; + auto) + ;; + *) + AC_MSG_ERROR(unsupported platform ($use_platform)) +esac + +XBMC_SETUP_ARCH_DEFINES() + +case $build in + *darwin*) + if test "$platform_os" != "android"; then + # MacOS 11 requires explicit isysroot for autoconf link tests + # However we do not want to pollute LDFLAGS once lib link tests are complete + LDFLAGS="$platform_includes" + AC_CHECK_LIB([z], [main], has_zlib=1, AC_MSG_WARN("No zlib support in toolchain. Will build libz."); has_zlib=0) + fi +esac + +if test "$platform_os" = "android"; then + need_libiconv=1 +else + AC_SEARCH_LIBS([iconv_open],iconv, link_iconv=$ac_cv_search_iconv_open, link_iconv=-liconv; AC_MSG_WARN("No iconv support in toolchain. Will build libiconv."); need_libiconv=1) +fi + +case $build in + *darwin*) + LDFLAGS=$(echo "$LDFLAGS" | sed "s|$platform_includes||") +esac + +if test "$link_iconv" = "none required"; then + link_iconv= +fi + +if test "x$prefix" = "xNONE"; then + AC_MSG_ERROR([No prefix path defined. Use for ex: --prefix=/opt/xbmc-depends]); +fi + +if test "$use_ccache" = "yes"; then + AC_PATH_TOOL([CCACHE], [ccache],, $PATH_FOR_HOST) +fi + +if test -z $use_tarballs; then + use_tarballs=$prefix/xbmc-tarballs +fi + +if test "$platform_os" = "linux"; then + if test "$app_rendersystem" != "gl" && test "$app_rendersystem" != "gles"; then + AC_MSG_ERROR(Rendersystem is required for linux - must be gl or gles) + fi +fi + +if test "$platform_os" = "android"; then + if test -z $use_ndk_path; then + AC_MSG_ERROR("NDK path is required for android") + fi + + if ([! test -f "$use_ndk_path/source.properties"] && [! test -f "$use_ndk_path/RELEASE.TXT"]) ; then + AC_MSG_ERROR("$use_ndk_path is not an NDK directory") + fi + + if test -z $use_sdk_path; then + AC_MSG_ERROR("SDK path is required for android") + fi + + if [ ! test -f $use_sdk_path/tools/bin/sdkmanager ]; then + AC_MSG_ERROR(verify sdk path) + fi + + if [ ! test -f $use_ndk_path/sources/android/native_app_glue/android_native_app_glue.h ]; then + AC_MSG_ERROR(verify ndk path) + fi + + #not all sort versions support -V - probe it... + SORT_PARAMS="" + sort -V /dev/null > /dev/null 2>&1 && SORT_PARAMS="-V" + build_tools_path=$use_sdk_path/tools:$use_sdk_path/platform-tools:$use_sdk_path/build-tools/`ls $use_sdk_path/build-tools | sort $SORT_PARAMS | tail -n 1` +fi + +# darwin needs unzip in Codesign.command +if test "$platform_os" = "android" || test "$platform_os" = "osx" || test "$platform_os" = "darwin_embedded"; then + AC_CHECK_PROG(HAVE_UNZIP,unzip,"yes","no",) + if test "x$HAVE_UNZIP" = "xno"; then + AC_MSG_ERROR("Missing program: unzip") + fi +fi +# darwin needs zip in Codesign.command +# android needs zip in tools/android/packaging/Makefile sharedobb target +if test "$platform_os" = "android" || test "$platform_os" = "osx" || test "$platform_os" = "darwin_embedded"; then + AC_CHECK_PROG(HAVE_ZIP,zip,"yes","no",) + if test "x$HAVE_ZIP" = "xno"; then + AC_MSG_ERROR("Missing program: zip") + fi +fi + +# Some dumb checks to see if paths might be correct. +if [ ! `mkdir -p $prefix/$deps_dir/include` ]; then + AC_MSG_ERROR(unable to create $prefix/$deps_dir/include. verify that the path and permissions are correct.) +fi + +if [ ! `mkdir -p $prefix/$deps_dir/lib` ]; then + AC_MSG_ERROR(unable to create $prefix/$deps_dir/lib. verify that the path and permissions are correct.) +fi + +if [ ! `mkdir -p $prefix/$deps_dir/share` ]; then + AC_MSG_ERROR(unable to create $prefix/$deps_dir/share. verify that the path and permissions are correct.) +fi + +if [ ! `mkdir -p $prefix/$tool_dir/include` ]; then + AC_MSG_ERROR(unable to create $prefix/$tool_dir/include. verify that the path and permissions are correct.) +fi + +if [ ! `mkdir -p $prefix/$tool_dir/lib` ]; then + AC_MSG_ERROR(unable to create $prefix/$tool_dir/lib. verify that the path and permissions are correct.) +fi + +if [ ! `mkdir -p $prefix/$tool_dir/share` ]; then + AC_MSG_ERROR(unable to create $prefix/$tool_dir/share. verify that the path and permissions are correct.) +fi + +if [ ! `mkdir -p $prefix/$tool_dir/bin` ]; then + AC_MSG_ERROR(unable to create $prefix/$tool_dir/share. verify that the path and permissions are correct.) +fi + +if [ ! `mkdir -p $use_tarballs` ]; then + AC_MSG_ERROR(unable to create tarballs dir. verify that the path and permissions are correct.) +fi + +# remove unwanted optimization flags +tmp_cflags=$(echo $CFLAGS $platform_cflags | sed 's/-O@<:@123@:>@//g;s/-g //g;s/ \{2,\}//g') +tmp_cxxflags=$(echo $CXXFLAGS $platform_cxxflags | sed 's/-O@<:@123@:>@//g;s/-g //g;s/ \{2,\}//g') + +release_cflags="-DNDEBUG=1" + +# newer xcode version accept -Og flag, but debugging doesn't work with it +if test "$platform_os" = "osx" || test "$platform_os" = "darwin_embedded"; then + debug_cflags="-g -D_DEBUG" +else + CFLAGS="$tmp_cflags -Og -g -D_DEBUG" + AC_COMPILE_IFELSE( + [AC_LANG_SOURCE([int foo;])], + [debug_cflags="-Og -g -D_DEBUG"], + [debug_cflags="-g -D_DEBUG"]) +fi + +# add user supplied flags to the end, so they override our defaults +platform_cflags_release="$tmp_cflags $release_cflags $optimize_flags $target_cflags" +platform_cxxflags_release="$tmp_cxxflags $release_cflags $optimize_flags $target_cxxflags" +platform_cflags_debug="$tmp_cflags $debug_cflags $target_cflags" +platform_cxxflags_debug="$tmp_cxxflags $debug_cflags $target_cxxflags" +platform_ldflags="${platform_ldflags} $target_ldflags $LIBS" + +if test "$use_debug" = "yes"; then + platform_cflags="$platform_cflags_debug" + platform_cxxflags="$platform_cxxflags_debug" +else + platform_cflags="$platform_cflags_release" + platform_cxxflags="$platform_cxxflags_release" +fi + +CXXFLAGS="$platform_cxxflags $platform_includes" +CXX_CACHED="$CXX" +AX_CXX_COMPILE_STDCXX([17], [noext], [mandatory]) +CXX="$CXX_CACHED" +platform_cxxflags="${platform_cxxflags} -std=c++17" + +if test "$ffmpeg_options" = "default"; then + ffmpeg_options="$ffmpeg_options_default" +fi + +if test "$platform_os" = "android"; then +echo -e + AC_SUBST(use_sdk_path) + AC_SUBST(use_ndk_path) + AC_SUBST(use_ndk_api) + AC_SUBST(build_tools_path) +fi + +AC_SUBST(meson_system) +AC_SUBST(meson_cpu) +AC_SUBST(use_debug) +AC_SUBST(use_host) +AC_SUBST(use_build) +AC_SUBST(deps_dir) +AC_SUBST(tool_dir) +AC_SUBST(use_buildcpu) +AC_SUBST(use_cpu) +AC_SUBST(use_toolchain) +AC_SUBST(use_build_toolchain) +AC_SUBST(use_tarballs) +AC_SUBST(target_platform) +AC_SUBST(use_firmware) +AC_SUBST(cross_compiling) +AC_SUBST(platform_cflags) +AC_SUBST(platform_cxxflags) +AC_SUBST(platform_cflags_release) +AC_SUBST(platform_cxxflags_release) +AC_SUBST(platform_cflags_debug) +AC_SUBST(platform_cxxflags_debug) +AC_SUBST(platform_ldflags) +AC_SUBST(platform_includes) +AC_SUBST(platform_os) +AC_SUBST(build_os) +AC_SUBST(has_zlib) +AC_SUBST(link_iconv) +AC_SUBST(need_libiconv) +AC_SUBST(use_gplv3) +AC_SUBST(use_ccache) +AC_SUBST(host_includes) +AC_SUBST(host_sysroot) +AC_SUBST(host_cxxflags) +AC_SUBST(app_rendersystem) +AC_SUBST(app_winsystem) +AC_SUBST(ffmpeg_options) + +[ +if test "x$CCACHE" = "x" +then + MESON_CC="'$CC'" + MESON_CXX="'$CXX'" +else + MESON_CC="['$CCACHE', '$CC']" + MESON_CXX="['$CCACHE', '$CXX']" +fi + +# Parse and handle CFLAGS +read -r CFLAGS_ARRAY << EOF +$platform_cflags $platform_includes -isystem $prefix/$deps_dir/include +EOF + +count=1 +for flag in $CFLAGS_ARRAY; do + if test "$flag" != "-g" + then + if test "$flag" != "-gdwarf-2" + then + MESON_CFLAGS="${MESON_CFLAGS:+${MESON_CFLAGS}, }'$flag'" + count=$((count + 1)) + fi + fi +done +if test "$count" -gt "2" +then + MESON_CFLAGS="[$MESON_CFLAGS]" +fi + +# Parse and handle CXXFLAGS +read -r CXXFLAGS_ARRAY << EOF +$platform_cxxflags $platform_includes -isystem $prefix/$deps_dir/include +EOF + +count=1 +for flag in $CXXFLAGS_ARRAY; do + if test "$flag" != "-g" + then + if test "$flag" != "-gdwarf-2" + then + MESON_CXXFLAGS="${MESON_CXXFLAGS:+${MESON_CXXFLAGS}, }'$flag'" + count=$((count + 1)) + fi + fi +done +if test "$count" -gt "2" +then + MESON_CXXFLAGS="[$MESON_CXXFLAGS]" +fi + +# Parse and handle LDFLAGS +read -r LDFLAGS_ARRAY << EOF +-L$prefix/$deps_dir/lib $platform_ldflags +EOF + +count=1 +for flag in $LDFLAGS_ARRAY; do + MESON_LDFLAGS="${MESON_LDFLAGS:+${MESON_LDFLAGS}, }'$flag'" + count=$((count + 1)) +done +if test "$count" -gt "2" +then + MESON_LDFLAGS="[$MESON_LDFLAGS]" +fi + +cat > $prefix/$deps_dir/share/cross-file.meson << EOF +[binaries] +c = $MESON_CC +cpp = $MESON_CXX +ar = '$AR' +strip = '$STRIP' +pkgconfig = '$prefix/$tool_dir/bin/pkg-config' + +[host_machine] +system = '$meson_system' +cpu_family = '$meson_cpu' +cpu = '$use_cpu' +endian = 'little' + +[properties] +pkg_config_libdir = '$prefix/$deps_dir/lib/pkgconfig' + +[built-in options] +c_args = $MESON_CFLAGS +c_link_args = $MESON_LDFLAGS +cpp_args = $MESON_CXXFLAGS +cpp_link_args = $MESON_LDFLAGS +default_library = 'static' +prefix = '$prefix/$deps_dir' +libdir = 'lib' +bindir = 'bin' +includedir = 'include' +EOF +] + +AC_OUTPUT + +if test "$platform_os" = "darwin_embedded"; then + if test "$use_platform" = "ios"; then + simulator_sdk_path=[`$use_xcrun --sdk iphonesimulator --show-sdk-path`] + echo -e "use simulator:\t $simulator_sdk_path" + fi +fi + +cp -vf target/config.site $prefix/$deps_dir/share +cp -vf target/config-binaddons.site $prefix/$tool_dir/share +cp -vf target/Toolchain.cmake $prefix/$deps_dir/share +cp -vf target/Toolchain_binaddons.cmake $prefix/$deps_dir/share +cp -vf native/config.site.native $prefix/$tool_dir/share/config.site +cp -vf native/Toolchain-Native.cmake $prefix/$tool_dir/share + + +echo -e "\n\n#------- configuration -------#" +echo -e "ccache:\t\t $use_ccache" +echo -e "build type:\t\t $build_type" +echo -e "build system:\t $use_build" +echo -e "build cpu:\t\t $use_buildcpu" +echo -e "build includes:\t $host_includes" +echo -e "toolchain:\t\t $use_toolchain" +echo -e "cpu:\t\t\t $use_cpu" +echo -e "host:\t\t $use_host" +echo -e "CC:\t\t $CC" +echo -e "CXX:\t\t $CXX" +echo -e "cflags:\t\t $platform_cflags" +echo -e "cxxflags:\t\t $platform_cxxflags" +echo -e "ldflags:\t\t $platform_ldflags" +echo -e "platform_includes:\t $platform_includes" +echo -e "ffmpeg options:\t $ffmpeg_options" +echo -e "prefix:\t\t $prefix" +echo -e "depends:\t\t $prefix/$deps_dir" +if test "$platform_os" = "android"; then + echo -e "ndk-api-level:\t $use_ndk_api" + echo -e "build-tools:\t $build_tools_path" +fi diff --git a/tools/depends/download-files.include b/tools/depends/download-files.include new file mode 100644 index 0000000..3f41dfa --- /dev/null +++ b/tools/depends/download-files.include @@ -0,0 +1,59 @@ +# +HASH_FOUND = yes +ifneq ($(SHA512),) + HASH_TYPE = sha512 + HASH_TOOL ?= $(SHA512SUM) +else ifneq ($(SHA256),) + HASH_TYPE = sha256 + HASH_TOOL ?= $(SHA256SUM) +else + HASH_FOUND = no + HASH_TYPE = sha512 + HASH_TOOL = sha512sum +endif + +SED_FLAG = -i +ifeq ($(NATIVE_OS), osx) + HASH_TOOL = $(SHASUM) -a $(shell echo $(HASH_TYPE) | sed 's/^sha//') + SED_FLAG = -i '' +endif + +# non-depends builds might not set this, use defaults +ifeq ($(HASH_TOOL),) + HASH_TOOL = sha512sum + HASH_TOOL_FLAGS = -c --status +endif + +HASH_SUM = $($(shell echo $(HASH_TYPE) | tr '[:lower:]' '[:upper:]')) + +.PHONY: $(TARBALLS_LOCATION)/$(ARCHIVE).$(HASH_TYPE) +all: $(TARBALLS_LOCATION)/$(ARCHIVE).$(HASH_TYPE) + +$(TARBALLS_LOCATION)/$(ARCHIVE): + cd $(TARBALLS_LOCATION); $(RETRIEVE_TOOL) $(RETRIEVE_TOOL_FLAGS) $(BASE_URL)/$(ARCHIVE) + +$(TARBALLS_LOCATION)/$(ARCHIVE).$(HASH_TYPE): $(TARBALLS_LOCATION)/$(ARCHIVE) +ifeq ($(HASH_FOUND),no) + cd $(TARBALLS_LOCATION); $(HASH_TOOL) $(ARCHIVE) > $(ARCHIVE).$(HASH_TYPE) + $(HASH_TYPE)=$$(cat $(TARBALLS_LOCATION)/$(ARCHIVE).$(HASH_TYPE) | cut -d ' ' -f 1) && \ + sed $(SED_FLAG) -e "s/#SHA512#/SHA512=$${sha512}/" -e "s/#SHA256#/SHA256=$${sha256}/" Makefile +endif +ifeq ($(HASH_FOUND),yes) +# we really need 2 spaces between sha hash and file name! +# if the hash sum doesn't match we retry up to 3 times, add verbose curl output for diagnostics on retries +# if we fail 3 times, cleanup anything downloaded (eg bad tar) + @cd $(TARBALLS_LOCATION); echo "$(HASH_SUM) $(ARCHIVE)" > $(ARCHIVE).$(HASH_TYPE) && $(HASH_TOOL) $(HASH_TOOL_FLAGS) $(ARCHIVE).$(HASH_TYPE) \ + || {\ + echo "Error: failed to verify hash sum of $(ARCHIVE), expected type: $(HASH_TYPE) value $(HASH_SUM), retrying.." ;\ + tries=1 ;\ + while [ $$tries -le 3 ]; do \ + echo "download $(ARCHIVE) retry $$tries" ;\ + rm $(TARBALLS_LOCATION)/$(ARCHIVE) ;\ + sleep 3 ;\ + $(RETRIEVE_TOOL) $(RETRIEVE_TOOL_FLAGS) -v $(BASE_URL)/$(ARCHIVE) ;\ + $(HASH_TOOL) $(HASH_TOOL_FLAGS) $(ARCHIVE).$(HASH_TYPE) && exit 0 || tries=$$((tries + 1)) ;\ + done ;\ + rm $(TARBALLS_LOCATION)/$(ARCHIVE) ;\ + exit 1 ;\ + } +endif diff --git a/tools/depends/m4/ax_compare_version.m4 b/tools/depends/m4/ax_compare_version.m4 new file mode 100644 index 0000000..ffb4997 --- /dev/null +++ b/tools/depends/m4/ax_compare_version.m4 @@ -0,0 +1,177 @@ +# =========================================================================== +# https://www.gnu.org/software/autoconf-archive/ax_compare_version.html +# =========================================================================== +# +# SYNOPSIS +# +# AX_COMPARE_VERSION(VERSION_A, OP, VERSION_B, [ACTION-IF-TRUE], [ACTION-IF-FALSE]) +# +# DESCRIPTION +# +# This macro compares two version strings. Due to the various number of +# minor-version numbers that can exist, and the fact that string +# comparisons are not compatible with numeric comparisons, this is not +# necessarily trivial to do in a autoconf script. This macro makes doing +# these comparisons easy. +# +# The six basic comparisons are available, as well as checking equality +# limited to a certain number of minor-version levels. +# +# The operator OP determines what type of comparison to do, and can be one +# of: +# +# eq - equal (test A == B) +# ne - not equal (test A != B) +# le - less than or equal (test A <= B) +# ge - greater than or equal (test A >= B) +# lt - less than (test A < B) +# gt - greater than (test A > B) +# +# Additionally, the eq and ne operator can have a number after it to limit +# the test to that number of minor versions. +# +# eq0 - equal up to the length of the shorter version +# ne0 - not equal up to the length of the shorter version +# eqN - equal up to N sub-version levels +# neN - not equal up to N sub-version levels +# +# When the condition is true, shell commands ACTION-IF-TRUE are run, +# otherwise shell commands ACTION-IF-FALSE are run. The environment +# variable 'ax_compare_version' is always set to either 'true' or 'false' +# as well. +# +# Examples: +# +# AX_COMPARE_VERSION([3.15.7],[lt],[3.15.8]) +# AX_COMPARE_VERSION([3.15],[lt],[3.15.8]) +# +# would both be true. +# +# AX_COMPARE_VERSION([3.15.7],[eq],[3.15.8]) +# AX_COMPARE_VERSION([3.15],[gt],[3.15.8]) +# +# would both be false. +# +# AX_COMPARE_VERSION([3.15.7],[eq2],[3.15.8]) +# +# would be true because it is only comparing two minor versions. +# +# AX_COMPARE_VERSION([3.15.7],[eq0],[3.15]) +# +# would be true because it is only comparing the lesser number of minor +# versions of the two values. +# +# Note: The characters that separate the version numbers do not matter. An +# empty string is the same as version 0. OP is evaluated by autoconf, not +# configure, so must be a string, not a variable. +# +# The author would like to acknowledge Guido Draheim whose advice about +# the m4_case and m4_ifvaln functions make this macro only include the +# portions necessary to perform the specific comparison specified by the +# OP argument in the final configure script. +# +# LICENSE +# +# Copyright (c) 2008 Tim Toolan <toolan@ele.uri.edu> +# +# Copying and distribution of this file, with or without modification, are +# permitted in any medium without royalty provided the copyright notice +# and this notice are preserved. This file is offered as-is, without any +# warranty. + +#serial 13 + +dnl ######################################################################### +AC_DEFUN([AX_COMPARE_VERSION], [ + AC_REQUIRE([AC_PROG_AWK]) + + # Used to indicate true or false condition + ax_compare_version=false + + # Convert the two version strings to be compared into a format that + # allows a simple string comparison. The end result is that a version + # string of the form 1.12.5-r617 will be converted to the form + # 0001001200050617. In other words, each number is zero padded to four + # digits, and non digits are removed. + AS_VAR_PUSHDEF([A],[ax_compare_version_A]) + A=`echo "$1" | sed -e 's/\([[0-9]]*\)/Z\1Z/g' \ + -e 's/Z\([[0-9]]\)Z/Z0\1Z/g' \ + -e 's/Z\([[0-9]][[0-9]]\)Z/Z0\1Z/g' \ + -e 's/Z\([[0-9]][[0-9]][[0-9]]\)Z/Z0\1Z/g' \ + -e 's/[[^0-9]]//g'` + + AS_VAR_PUSHDEF([B],[ax_compare_version_B]) + B=`echo "$3" | sed -e 's/\([[0-9]]*\)/Z\1Z/g' \ + -e 's/Z\([[0-9]]\)Z/Z0\1Z/g' \ + -e 's/Z\([[0-9]][[0-9]]\)Z/Z0\1Z/g' \ + -e 's/Z\([[0-9]][[0-9]][[0-9]]\)Z/Z0\1Z/g' \ + -e 's/[[^0-9]]//g'` + + dnl # In the case of le, ge, lt, and gt, the strings are sorted as necessary + dnl # then the first line is used to determine if the condition is true. + dnl # The sed right after the echo is to remove any indented white space. + m4_case(m4_tolower($2), + [lt],[ + ax_compare_version=`echo "x$A +x$B" | sed 's/^ *//' | sort -r | sed "s/x${A}/false/;s/x${B}/true/;1q"` + ], + [gt],[ + ax_compare_version=`echo "x$A +x$B" | sed 's/^ *//' | sort | sed "s/x${A}/false/;s/x${B}/true/;1q"` + ], + [le],[ + ax_compare_version=`echo "x$A +x$B" | sed 's/^ *//' | sort | sed "s/x${A}/true/;s/x${B}/false/;1q"` + ], + [ge],[ + ax_compare_version=`echo "x$A +x$B" | sed 's/^ *//' | sort -r | sed "s/x${A}/true/;s/x${B}/false/;1q"` + ],[ + dnl Split the operator from the subversion count if present. + m4_bmatch(m4_substr($2,2), + [0],[ + # A count of zero means use the length of the shorter version. + # Determine the number of characters in A and B. + ax_compare_version_len_A=`echo "$A" | $AWK '{print(length)}'` + ax_compare_version_len_B=`echo "$B" | $AWK '{print(length)}'` + + # Set A to no more than B's length and B to no more than A's length. + A=`echo "$A" | sed "s/\(.\{$ax_compare_version_len_B\}\).*/\1/"` + B=`echo "$B" | sed "s/\(.\{$ax_compare_version_len_A\}\).*/\1/"` + ], + [[0-9]+],[ + # A count greater than zero means use only that many subversions + A=`echo "$A" | sed "s/\(\([[0-9]]\{4\}\)\{m4_substr($2,2)\}\).*/\1/"` + B=`echo "$B" | sed "s/\(\([[0-9]]\{4\}\)\{m4_substr($2,2)\}\).*/\1/"` + ], + [.+],[ + AC_WARNING( + [invalid OP numeric parameter: $2]) + ],[]) + + # Pad zeros at end of numbers to make same length. + ax_compare_version_tmp_A="$A`echo $B | sed 's/./0/g'`" + B="$B`echo $A | sed 's/./0/g'`" + A="$ax_compare_version_tmp_A" + + # Check for equality or inequality as necessary. + m4_case(m4_tolower(m4_substr($2,0,2)), + [eq],[ + test "x$A" = "x$B" && ax_compare_version=true + ], + [ne],[ + test "x$A" != "x$B" && ax_compare_version=true + ],[ + AC_WARNING([invalid OP parameter: $2]) + ]) + ]) + + AS_VAR_POPDEF([A])dnl + AS_VAR_POPDEF([B])dnl + + dnl # Execute ACTION-IF-TRUE / ACTION-IF-FALSE. + if test "$ax_compare_version" = "true" ; then + m4_ifvaln([$4],[$4],[:])dnl + m4_ifvaln([$5],[else $5])dnl + fi +]) dnl AX_COMPARE_VERSION diff --git a/tools/depends/m4/ax_cxx_compile_stdcxx.m4 b/tools/depends/m4/ax_cxx_compile_stdcxx.m4 new file mode 100644 index 0000000..43087b2 --- /dev/null +++ b/tools/depends/m4/ax_cxx_compile_stdcxx.m4 @@ -0,0 +1,951 @@ +# =========================================================================== +# https://www.gnu.org/software/autoconf-archive/ax_cxx_compile_stdcxx.html +# =========================================================================== +# +# SYNOPSIS +# +# AX_CXX_COMPILE_STDCXX(VERSION, [ext|noext], [mandatory|optional]) +# +# DESCRIPTION +# +# Check for baseline language coverage in the compiler for the specified +# version of the C++ standard. If necessary, add switches to CXX and +# CXXCPP to enable support. VERSION may be '11' (for the C++11 standard) +# or '14' (for the C++14 standard). +# +# The second argument, if specified, indicates whether you insist on an +# extended mode (e.g. -std=gnu++11) or a strict conformance mode (e.g. +# -std=c++11). If neither is specified, you get whatever works, with +# preference for an extended mode. +# +# The third argument, if specified 'mandatory' or if left unspecified, +# indicates that baseline support for the specified C++ standard is +# required and that the macro should error out if no mode with that +# support is found. If specified 'optional', then configuration proceeds +# regardless, after defining HAVE_CXX${VERSION} if and only if a +# supporting mode is found. +# +# LICENSE +# +# Copyright (c) 2008 Benjamin Kosnik <bkoz@redhat.com> +# Copyright (c) 2012 Zack Weinberg <zackw@panix.com> +# Copyright (c) 2013 Roy Stogner <roystgnr@ices.utexas.edu> +# Copyright (c) 2014, 2015 Google Inc.; contributed by Alexey Sokolov <sokolov@google.com> +# Copyright (c) 2015 Paul Norman <penorman@mac.com> +# Copyright (c) 2015 Moritz Klammler <moritz@klammler.eu> +# Copyright (c) 2016, 2018 Krzesimir Nowak <qdlacz@gmail.com> +# Copyright (c) 2019 Enji Cooper <yaneurabeya@gmail.com> +# +# Copying and distribution of this file, with or without modification, are +# permitted in any medium without royalty provided the copyright notice +# and this notice are preserved. This file is offered as-is, without any +# warranty. + +#serial 11 + +dnl This macro is based on the code from the AX_CXX_COMPILE_STDCXX_11 macro +dnl (serial version number 13). + +AC_DEFUN([AX_CXX_COMPILE_STDCXX], [dnl + m4_if([$1], [11], [ax_cxx_compile_alternatives="11 0x"], + [$1], [14], [ax_cxx_compile_alternatives="14 1y"], + [$1], [17], [ax_cxx_compile_alternatives="17 1z"], + [m4_fatal([invalid first argument `$1' to AX_CXX_COMPILE_STDCXX])])dnl + m4_if([$2], [], [], + [$2], [ext], [], + [$2], [noext], [], + [m4_fatal([invalid second argument `$2' to AX_CXX_COMPILE_STDCXX])])dnl + m4_if([$3], [], [ax_cxx_compile_cxx$1_required=true], + [$3], [mandatory], [ax_cxx_compile_cxx$1_required=true], + [$3], [optional], [ax_cxx_compile_cxx$1_required=false], + [m4_fatal([invalid third argument `$3' to AX_CXX_COMPILE_STDCXX])]) + AC_LANG_PUSH([C++])dnl + ac_success=no + + m4_if([$2], [noext], [], [dnl + if test x$ac_success = xno; then + for alternative in ${ax_cxx_compile_alternatives}; do + switch="-std=gnu++${alternative}" + cachevar=AS_TR_SH([ax_cv_cxx_compile_cxx$1_$switch]) + AC_CACHE_CHECK(whether $CXX supports C++$1 features with $switch, + $cachevar, + [ac_save_CXX="$CXX" + CXX="$CXX $switch" + AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_testbody_$1])], + [eval $cachevar=yes], + [eval $cachevar=no]) + CXX="$ac_save_CXX"]) + if eval test x\$$cachevar = xyes; then + CXX="$CXX $switch" + if test -n "$CXXCPP" ; then + CXXCPP="$CXXCPP $switch" + fi + ac_success=yes + break + fi + done + fi]) + + m4_if([$2], [ext], [], [dnl + if test x$ac_success = xno; then + dnl HP's aCC needs +std=c++11 according to: + dnl http://h21007.www2.hp.com/portal/download/files/unprot/aCxx/PDF_Release_Notes/769149-001.pdf + dnl Cray's crayCC needs "-h std=c++11" + for alternative in ${ax_cxx_compile_alternatives}; do + for switch in -std=c++${alternative} +std=c++${alternative} "-h std=c++${alternative}"; do + cachevar=AS_TR_SH([ax_cv_cxx_compile_cxx$1_$switch]) + AC_CACHE_CHECK(whether $CXX supports C++$1 features with $switch, + $cachevar, + [ac_save_CXX="$CXX" + CXX="$CXX $switch" + AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_testbody_$1])], + [eval $cachevar=yes], + [eval $cachevar=no]) + CXX="$ac_save_CXX"]) + if eval test x\$$cachevar = xyes; then + CXX="$CXX $switch" + if test -n "$CXXCPP" ; then + CXXCPP="$CXXCPP $switch" + fi + ac_success=yes + break + fi + done + if test x$ac_success = xyes; then + break + fi + done + fi]) + AC_LANG_POP([C++]) + if test x$ax_cxx_compile_cxx$1_required = xtrue; then + if test x$ac_success = xno; then + AC_MSG_ERROR([*** A compiler with support for C++$1 language features is required.]) + fi + fi + if test x$ac_success = xno; then + HAVE_CXX$1=0 + AC_MSG_NOTICE([No compiler with C++$1 support was found]) + else + HAVE_CXX$1=1 + AC_DEFINE(HAVE_CXX$1,1, + [define if the compiler supports basic C++$1 syntax]) + fi + AC_SUBST(HAVE_CXX$1) +]) + + +dnl Test body for checking C++11 support + +m4_define([_AX_CXX_COMPILE_STDCXX_testbody_11], + _AX_CXX_COMPILE_STDCXX_testbody_new_in_11 +) + + +dnl Test body for checking C++14 support + +m4_define([_AX_CXX_COMPILE_STDCXX_testbody_14], + _AX_CXX_COMPILE_STDCXX_testbody_new_in_11 + _AX_CXX_COMPILE_STDCXX_testbody_new_in_14 +) + +m4_define([_AX_CXX_COMPILE_STDCXX_testbody_17], + _AX_CXX_COMPILE_STDCXX_testbody_new_in_11 + _AX_CXX_COMPILE_STDCXX_testbody_new_in_14 + _AX_CXX_COMPILE_STDCXX_testbody_new_in_17 +) + +dnl Tests for new features in C++11 + +m4_define([_AX_CXX_COMPILE_STDCXX_testbody_new_in_11], [[ + +// If the compiler admits that it is not ready for C++11, why torture it? +// Hopefully, this will speed up the test. + +#ifndef __cplusplus + +#error "This is not a C++ compiler" + +#elif __cplusplus < 201103L + +#error "This is not a C++11 compiler" + +#else + +namespace cxx11 +{ + + namespace test_static_assert + { + + template <typename T> + struct check + { + static_assert(sizeof(int) <= sizeof(T), "not big enough"); + }; + + } + + namespace test_final_override + { + + struct Base + { + virtual ~Base() {} + virtual void f() {} + }; + + struct Derived : public Base + { + virtual ~Derived() override {} + virtual void f() override {} + }; + + } + + namespace test_double_right_angle_brackets + { + + template < typename T > + struct check {}; + + typedef check<void> single_type; + typedef check<check<void>> double_type; + typedef check<check<check<void>>> triple_type; + typedef check<check<check<check<void>>>> quadruple_type; + + } + + namespace test_decltype + { + + int + f() + { + int a = 1; + decltype(a) b = 2; + return a + b; + } + + } + + namespace test_type_deduction + { + + template < typename T1, typename T2 > + struct is_same + { + static const bool value = false; + }; + + template < typename T > + struct is_same<T, T> + { + static const bool value = true; + }; + + template < typename T1, typename T2 > + auto + add(T1 a1, T2 a2) -> decltype(a1 + a2) + { + return a1 + a2; + } + + int + test(const int c, volatile int v) + { + static_assert(is_same<int, decltype(0)>::value == true, ""); + static_assert(is_same<int, decltype(c)>::value == false, ""); + static_assert(is_same<int, decltype(v)>::value == false, ""); + auto ac = c; + auto av = v; + auto sumi = ac + av + 'x'; + auto sumf = ac + av + 1.0; + static_assert(is_same<int, decltype(ac)>::value == true, ""); + static_assert(is_same<int, decltype(av)>::value == true, ""); + static_assert(is_same<int, decltype(sumi)>::value == true, ""); + static_assert(is_same<int, decltype(sumf)>::value == false, ""); + static_assert(is_same<int, decltype(add(c, v))>::value == true, ""); + return (sumf > 0.0) ? sumi : add(c, v); + } + + } + + namespace test_noexcept + { + + int f() { return 0; } + int g() noexcept { return 0; } + + static_assert(noexcept(f()) == false, ""); + static_assert(noexcept(g()) == true, ""); + + } + + namespace test_constexpr + { + + template < typename CharT > + unsigned long constexpr + strlen_c_r(const CharT *const s, const unsigned long acc) noexcept + { + return *s ? strlen_c_r(s + 1, acc + 1) : acc; + } + + template < typename CharT > + unsigned long constexpr + strlen_c(const CharT *const s) noexcept + { + return strlen_c_r(s, 0UL); + } + + static_assert(strlen_c("") == 0UL, ""); + static_assert(strlen_c("1") == 1UL, ""); + static_assert(strlen_c("example") == 7UL, ""); + static_assert(strlen_c("another\0example") == 7UL, ""); + + } + + namespace test_rvalue_references + { + + template < int N > + struct answer + { + static constexpr int value = N; + }; + + answer<1> f(int&) { return answer<1>(); } + answer<2> f(const int&) { return answer<2>(); } + answer<3> f(int&&) { return answer<3>(); } + + void + test() + { + int i = 0; + const int c = 0; + static_assert(decltype(f(i))::value == 1, ""); + static_assert(decltype(f(c))::value == 2, ""); + static_assert(decltype(f(0))::value == 3, ""); + } + + } + + namespace test_uniform_initialization + { + + struct test + { + static const int zero {}; + static const int one {1}; + }; + + static_assert(test::zero == 0, ""); + static_assert(test::one == 1, ""); + + } + + namespace test_lambdas + { + + void + test1() + { + auto lambda1 = [](){}; + auto lambda2 = lambda1; + lambda1(); + lambda2(); + } + + int + test2() + { + auto a = [](int i, int j){ return i + j; }(1, 2); + auto b = []() -> int { return '0'; }(); + auto c = [=](){ return a + b; }(); + auto d = [&](){ return c; }(); + auto e = [a, &b](int x) mutable { + const auto identity = [](int y){ return y; }; + for (auto i = 0; i < a; ++i) + a += b--; + return x + identity(a + b); + }(0); + return a + b + c + d + e; + } + + int + test3() + { + const auto nullary = [](){ return 0; }; + const auto unary = [](int x){ return x; }; + using nullary_t = decltype(nullary); + using unary_t = decltype(unary); + const auto higher1st = [](nullary_t f){ return f(); }; + const auto higher2nd = [unary](nullary_t f1){ + return [unary, f1](unary_t f2){ return f2(unary(f1())); }; + }; + return higher1st(nullary) + higher2nd(nullary)(unary); + } + + } + + namespace test_variadic_templates + { + + template <int...> + struct sum; + + template <int N0, int... N1toN> + struct sum<N0, N1toN...> + { + static constexpr auto value = N0 + sum<N1toN...>::value; + }; + + template <> + struct sum<> + { + static constexpr auto value = 0; + }; + + static_assert(sum<>::value == 0, ""); + static_assert(sum<1>::value == 1, ""); + static_assert(sum<23>::value == 23, ""); + static_assert(sum<1, 2>::value == 3, ""); + static_assert(sum<5, 5, 11>::value == 21, ""); + static_assert(sum<2, 3, 5, 7, 11, 13>::value == 41, ""); + + } + + // http://stackoverflow.com/questions/13728184/template-aliases-and-sfinae + // Clang 3.1 fails with headers of libstd++ 4.8.3 when using std::function + // because of this. + namespace test_template_alias_sfinae + { + + struct foo {}; + + template<typename T> + using member = typename T::member_type; + + template<typename T> + void func(...) {} + + template<typename T> + void func(member<T>*) {} + + void test(); + + void test() { func<foo>(0); } + + } + +} // namespace cxx11 + +#endif // __cplusplus >= 201103L + +]]) + + +dnl Tests for new features in C++14 + +m4_define([_AX_CXX_COMPILE_STDCXX_testbody_new_in_14], [[ + +// If the compiler admits that it is not ready for C++14, why torture it? +// Hopefully, this will speed up the test. + +#ifndef __cplusplus + +#error "This is not a C++ compiler" + +#elif __cplusplus < 201402L + +#error "This is not a C++14 compiler" + +#else + +namespace cxx14 +{ + + namespace test_polymorphic_lambdas + { + + int + test() + { + const auto lambda = [](auto&&... args){ + const auto istiny = [](auto x){ + return (sizeof(x) == 1UL) ? 1 : 0; + }; + const int aretiny[] = { istiny(args)... }; + return aretiny[0]; + }; + return lambda(1, 1L, 1.0f, '1'); + } + + } + + namespace test_binary_literals + { + + constexpr auto ivii = 0b0000000000101010; + static_assert(ivii == 42, "wrong value"); + + } + + namespace test_generalized_constexpr + { + + template < typename CharT > + constexpr unsigned long + strlen_c(const CharT *const s) noexcept + { + auto length = 0UL; + for (auto p = s; *p; ++p) + ++length; + return length; + } + + static_assert(strlen_c("") == 0UL, ""); + static_assert(strlen_c("x") == 1UL, ""); + static_assert(strlen_c("test") == 4UL, ""); + static_assert(strlen_c("another\0test") == 7UL, ""); + + } + + namespace test_lambda_init_capture + { + + int + test() + { + auto x = 0; + const auto lambda1 = [a = x](int b){ return a + b; }; + const auto lambda2 = [a = lambda1(x)](){ return a; }; + return lambda2(); + } + + } + + namespace test_digit_separators + { + + constexpr auto ten_million = 100'000'000; + static_assert(ten_million == 100000000, ""); + + } + + namespace test_return_type_deduction + { + + auto f(int& x) { return x; } + decltype(auto) g(int& x) { return x; } + + template < typename T1, typename T2 > + struct is_same + { + static constexpr auto value = false; + }; + + template < typename T > + struct is_same<T, T> + { + static constexpr auto value = true; + }; + + int + test() + { + auto x = 0; + static_assert(is_same<int, decltype(f(x))>::value, ""); + static_assert(is_same<int&, decltype(g(x))>::value, ""); + return x; + } + + } + +} // namespace cxx14 + +#endif // __cplusplus >= 201402L + +]]) + + +dnl Tests for new features in C++17 + +m4_define([_AX_CXX_COMPILE_STDCXX_testbody_new_in_17], [[ + +// If the compiler admits that it is not ready for C++17, why torture it? +// Hopefully, this will speed up the test. + +#ifndef __cplusplus + +#error "This is not a C++ compiler" + +#elif __cplusplus < 201703L + +#error "This is not a C++17 compiler" + +#else + +#include <initializer_list> +#include <utility> +#include <type_traits> + +namespace cxx17 +{ + + namespace test_constexpr_lambdas + { + + constexpr int foo = [](){return 42;}(); + + } + + namespace test::nested_namespace::definitions + { + + } + + namespace test_fold_expression + { + + template<typename... Args> + int multiply(Args... args) + { + return (args * ... * 1); + } + + template<typename... Args> + bool all(Args... args) + { + return (args && ...); + } + + } + + namespace test_extended_static_assert + { + + static_assert (true); + + } + + namespace test_auto_brace_init_list + { + + auto foo = {5}; + auto bar {5}; + + static_assert(std::is_same<std::initializer_list<int>, decltype(foo)>::value); + static_assert(std::is_same<int, decltype(bar)>::value); + } + + namespace test_typename_in_template_template_parameter + { + + template<template<typename> typename X> struct D; + + } + + namespace test_fallthrough_nodiscard_maybe_unused_attributes + { + + int f1() + { + return 42; + } + + [[nodiscard]] int f2() + { + [[maybe_unused]] auto unused = f1(); + + switch (f1()) + { + case 17: + f1(); + [[fallthrough]]; + case 42: + f1(); + } + return f1(); + } + + } + + namespace test_extended_aggregate_initialization + { + + struct base1 + { + int b1, b2 = 42; + }; + + struct base2 + { + base2() { + b3 = 42; + } + int b3; + }; + + struct derived : base1, base2 + { + int d; + }; + + derived d1 {{1, 2}, {}, 4}; // full initialization + derived d2 {{}, {}, 4}; // value-initialized bases + + } + + namespace test_general_range_based_for_loop + { + + struct iter + { + int i; + + int& operator* () + { + return i; + } + + const int& operator* () const + { + return i; + } + + iter& operator++() + { + ++i; + return *this; + } + }; + + struct sentinel + { + int i; + }; + + bool operator== (const iter& i, const sentinel& s) + { + return i.i == s.i; + } + + bool operator!= (const iter& i, const sentinel& s) + { + return !(i == s); + } + + struct range + { + iter begin() const + { + return {0}; + } + + sentinel end() const + { + return {5}; + } + }; + + void f() + { + range r {}; + + for (auto i : r) + { + [[maybe_unused]] auto v = i; + } + } + + } + + namespace test_lambda_capture_asterisk_this_by_value + { + + struct t + { + int i; + int foo() + { + return [*this]() + { + return i; + }(); + } + }; + + } + + namespace test_enum_class_construction + { + + enum class byte : unsigned char + {}; + + byte foo {42}; + + } + + namespace test_constexpr_if + { + + template <bool cond> + int f () + { + if constexpr(cond) + { + return 13; + } + else + { + return 42; + } + } + + } + + namespace test_selection_statement_with_initializer + { + + int f() + { + return 13; + } + + int f2() + { + if (auto i = f(); i > 0) + { + return 3; + } + + switch (auto i = f(); i + 4) + { + case 17: + return 2; + + default: + return 1; + } + } + + } + + namespace test_template_argument_deduction_for_class_templates + { + + template <typename T1, typename T2> + struct pair + { + pair (T1 p1, T2 p2) + : m1 {p1}, + m2 {p2} + {} + + T1 m1; + T2 m2; + }; + + void f() + { + [[maybe_unused]] auto p = pair{13, 42u}; + } + + } + + namespace test_non_type_auto_template_parameters + { + + template <auto n> + struct B + {}; + + B<5> b1; + B<'a'> b2; + + } + + namespace test_structured_bindings + { + + int arr[2] = { 1, 2 }; + std::pair<int, int> pr = { 1, 2 }; + + auto f1() -> int(&)[2] + { + return arr; + } + + auto f2() -> std::pair<int, int>& + { + return pr; + } + + struct S + { + int x1 : 2; + volatile double y1; + }; + + S f3() + { + return {}; + } + + auto [ x1, y1 ] = f1(); + auto& [ xr1, yr1 ] = f1(); + auto [ x2, y2 ] = f2(); + auto& [ xr2, yr2 ] = f2(); + const auto [ x3, y3 ] = f3(); + + } + + namespace test_exception_spec_type_system + { + + struct Good {}; + struct Bad {}; + + void g1() noexcept; + void g2(); + + template<typename T> + Bad + f(T*, T*); + + template<typename T1, typename T2> + Good + f(T1*, T2*); + + static_assert (std::is_same_v<Good, decltype(f(g1, g2))>); + + } + + namespace test_inline_variables + { + + template<class T> void f(T) + {} + + template<class T> inline T g(T) + { + return T{}; + } + + template<> inline void f<>(int) + {} + + template<> int g<>(int) + { + return 5; + } + + } + +} // namespace cxx17 + +#endif // __cplusplus < 201703L + +]]) diff --git a/tools/depends/m4/xbmc_arch.m4 b/tools/depends/m4/xbmc_arch.m4 new file mode 100644 index 0000000..05b254d --- /dev/null +++ b/tools/depends/m4/xbmc_arch.m4 @@ -0,0 +1,84 @@ +AC_DEFUN([XBMC_SETUP_ARCH_DEFINES],[ + +# build detection and setup - this is the native arch +case $build in + i*86*-linux-gnu*|i*86*-*-linux-uclibc*) + AC_SUBST(NATIVE_ARCH_DEFINES, "-DTARGET_POSIX -DTARGET_LINUX") + ;; + x86_64-*-linux-gnu*|x86_64-*-linux-uclibc*) + AC_SUBST(NATIVE_ARCH_DEFINES, "-DTARGET_POSIX -DTARGET_LINUX") + ;; + i386-*-freebsd*) + AC_SUBST(NATIVE_ARCH_DEFINES, "-DTARGET_POSIX -DTARGET_FREEBSD") + ;; + amd64-*-freebsd*) + AC_SUBST(NATIVE_ARCH_DEFINES, "-DTARGET_POSIX -DTARGET_FREEBSD") + ;; + arm-apple-darwin*) + AC_SUBST(NATIVE_ARCH_DEFINES, "-DTARGET_POSIX -DTARGET_DARWIN -DTARGET_DARWIN_OSX") + ;; + x86_64-apple-darwin*) + AC_SUBST(NATIVE_ARCH_DEFINES, "-DTARGET_POSIX -DTARGET_DARWIN -DTARGET_DARWIN_OSX") + ;; + powerpc-*-linux-gnu*|powerpc-*-linux-uclibc*) + AC_SUBST(NATIVE_ARCH_DEFINES, "-DTARGET_POSIX -DTARGET_LINUX -D_POWERPC") + ;; + powerpc64-*-linux-gnu*|powerpc64-*-linux-uclibc*) + AC_SUBST(NATIVE_ARCH_DEFINES, "-DTARGET_POSIX -DTARGET_LINUX -D_POWERPC64") + ;; + arm*-*-linux-gnu*|arm*-*-linux-uclibc*|aarch64*-*-linux-gnu*|aarch64*-*-linux-uclibc*) + AC_SUBST(NATIVE_ARCH_DEFINES, "-DTARGET_POSIX -DTARGET_LINUX") + ;; + *) + AC_MSG_ERROR(unsupported native build platform: $build) +esac + + +# host detection and setup - this is the target arch +case $host in + i*86*-linux-gnu*|i*86*-*-linux-uclibc*) + AC_SUBST(ARCH_DEFINES, "-DTARGET_POSIX -DTARGET_LINUX") + ;; + x86_64-*-linux-gnu*|x86_64-*-linux-uclibc*) + AC_SUBST(ARCH_DEFINES, "-DTARGET_POSIX -DTARGET_LINUX") + ;; + i386-*-freebsd*) + AC_SUBST(ARCH_DEFINES, "-DTARGET_POSIX -DTARGET_FREEBSD") + ;; + amd64-*-freebsd*) + AC_SUBST(ARCH_DEFINES, "-DTARGET_POSIX -DTARGET_FREEBSD") + ;; + aarch64-apple-darwin*) + if test "$target_platform" = "macosx" ; then + AC_SUBST(ARCH_DEFINES, "-DTARGET_POSIX -DTARGET_DARWIN -DTARGET_DARWIN_OSX") + else + AC_SUBST(ARCH_DEFINES, "-DTARGET_POSIX -DTARGET_DARWIN -DTARGET_DARWIN_EMBEDDED") + fi + ;; + x86_64-apple-darwin*) + AC_SUBST(ARCH_DEFINES, "-DTARGET_POSIX -DTARGET_DARWIN -DTARGET_DARWIN_OSX") + ;; + powerpc-*-linux-gnu*|powerpc-*-linux-uclibc*) + AC_SUBST(ARCH_DEFINES, "-DTARGET_POSIX -DTARGET_LINUX -D_POWERPC") + ;; + powerpc64*-*-linux-gnu*|powerpc64*-*-linux-uclibc*) + AC_SUBST(ARCH_DEFINES, "-DTARGET_POSIX -DTARGET_LINUX -D_POWERPC64") + ;; + arm*-*-linux-gnu*|arm*-*-linux-uclibc*|aarch64*-*-linux-gnu*|aarch64*-*-linux-uclibc*) + AC_SUBST(ARCH_DEFINES, "-DTARGET_POSIX -DTARGET_LINUX") + ;; + mips*-*-linux-gnu*|mips*-*-linux-uclibc*) + AC_SUBST(ARCH_DEFINES, "-DTARGET_POSIX -DTARGET_LINUX") + ;; + *-*linux-android*) + AC_SUBST(ARCH_DEFINES, "-DTARGET_POSIX -DTARGET_LINUX -DTARGET_ANDROID") + ;; + *) + AC_MSG_ERROR(unsupported build target: $host) +esac + +if test "$target_platform" = "target_android" ; then + AC_SUBST(ARCH_DEFINES, "-DTARGET_POSIX -DTARGET_LINUX -DTARGET_ANDROID") +fi + +]) diff --git a/tools/depends/native/JsonSchemaBuilder/CMakeLists.txt b/tools/depends/native/JsonSchemaBuilder/CMakeLists.txt new file mode 100644 index 0000000..e1c6c21 --- /dev/null +++ b/tools/depends/native/JsonSchemaBuilder/CMakeLists.txt @@ -0,0 +1,10 @@ +project(JsonSchemaBuilder) + +set(SOURCES src/JsonSchemaBuilder.cpp) + +set(CMAKE_CXX_STANDARD 11) +set(CMAKE_CXX_STANDARD_REQUIRED ON) +add_executable(JsonSchemaBuilder ${SOURCES}) + +install(TARGETS JsonSchemaBuilder DESTINATION ${CMAKE_INSTALL_PREFIX}/bin + RENAME "${APP_NAME_LC}-JsonSchemaBuilder") diff --git a/tools/depends/native/JsonSchemaBuilder/LICENSE.GPL b/tools/depends/native/JsonSchemaBuilder/LICENSE.GPL new file mode 100644 index 0000000..c7e8863 --- /dev/null +++ b/tools/depends/native/JsonSchemaBuilder/LICENSE.GPL @@ -0,0 +1,287 @@ + + You may use, distribute and copy JsonSchemaBuilder under the terms of GNU General + Public License version 2, which is displayed below. + +------------------------------------------------------------------------- + + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS +------------------------------------------------------------------------- diff --git a/tools/depends/native/JsonSchemaBuilder/Makefile b/tools/depends/native/JsonSchemaBuilder/Makefile new file mode 100644 index 0000000..78c4433 --- /dev/null +++ b/tools/depends/native/JsonSchemaBuilder/Makefile @@ -0,0 +1,46 @@ +ROOT_DIR := $(shell dirname $(realpath $(lastword $(MAKEFILE_LIST)))) +-include ../../Makefile.include +DEPS=Makefile + +ifeq ($(NATIVEPREFIX),) + PREFIX = $(ROOT_DIR) +else + PREFIX = $(NATIVEPREFIX) +endif + +ifeq ($(NATIVEPLATFORM),) + PLATFORM = native +else + PLATFORM = $(NATIVEPLATFORM) + DEPS += ../../Makefile.include +endif + +SOURCE=$(ROOT_DIR)/src + +CONFIGURE=./configure --prefix=$(PREFIX) +APP=$(PLATFORM)/JsonSchemaBuilder +APPBIN=$(PREFIX)/bin/JsonSchemaBuilder + +all: .installed-$(PLATFORM) + +$(PLATFORM): $(DEPS) + -rm -rf $(PLATFORM)/*; mkdir -p $(PLATFORM) + cd $(PLATFORM); cp -a $(SOURCE)/* . + cd $(PLATFORM); ./autogen.sh + cd $(PLATFORM); $(CONFIGURE) + + +$(APP): $(PLATFORM) + $(MAKE) -C $(PLATFORM) + + +.installed-$(PLATFORM): $(APP) + $(MAKE) -C $(PLATFORM) install + touch $@ + +clean: + $(MAKE) -C $(PLATFORM) clean + +distclean:: + rm -rf $(PLATFORM) .installed-$(PLATFORM) + -rm -rf bin diff --git a/tools/depends/native/JsonSchemaBuilder/README b/tools/depends/native/JsonSchemaBuilder/README new file mode 100644 index 0000000..f6fcb8e --- /dev/null +++ b/tools/depends/native/JsonSchemaBuilder/README @@ -0,0 +1,5 @@ +JSON Schema Builder +=================== +JSON Schema Builder is a tool used by XBMC to transform files containing JSON +schema definitions of XBMC's JSON-RPC API into a C++ header file which can be +parsed by XBMC's JSON-RPC implementation at runtime.
\ No newline at end of file diff --git a/tools/depends/native/JsonSchemaBuilder/src/JsonSchemaBuilder.cpp b/tools/depends/native/JsonSchemaBuilder/src/JsonSchemaBuilder.cpp new file mode 100644 index 0000000..7f219bb --- /dev/null +++ b/tools/depends/native/JsonSchemaBuilder/src/JsonSchemaBuilder.cpp @@ -0,0 +1,176 @@ +/* + * Copyright (C) 2011 Tobias Arrskog + * https://github.com/topfs2/jsd_builder + * + * 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, 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 XBMC; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +#include <fstream> +#include <iostream> +#include <regex> +#include <string> + +void print_version(std::ifstream &in, std::ofstream &out) +{ + std::string line; + if (getline(in, line)) + out << std::regex_replace(line, std::regex("(\\s+)?JSONRPC_VERSION\\s+|(\\s+)?#.*"), ""); +} + +void print_license(std::ifstream &in, std::ofstream &out) +{ + std::string line; + + while (getline(in, line, '\n')) + out << line << std::endl; +} + +void print_json(std::ifstream &in, std::ofstream &out) +{ + std::string line; + unsigned int count = 0; + bool closing = false; + + while (getline(in, line, '\n')) + { + // No need to handle the last line + if (line == "}") + { + out << std::endl; + continue; + } + + // If we just closed a whole object we need to print the separator + if (closing) + out << "," << std::endl; + + out << " "; + bool started = false; + closing = false; + for (std::string::iterator itr = line.begin(); itr != line.end(); ++itr) + { + // Skip \r characters + if (*itr == '\r') { + break; + } + + // Count opening { but ignore the first one + if (*itr == '{') + { + count++; + if (count == 1) + break; + } + // Replace tabs with 2 spaces + if (*itr == '\t') + { + out << " "; + continue; + } + // Count closing } but ignore the last one + if (*itr == '}') + { + count--; + if (count == 0) + break; + + if (count == 1) + { + out << "\"}\""; + closing = true; + break; + } + } + // Only print a " before the first real sign + if (!started && *itr != ' ') + { + started = true; + out << '"'; + } + // Add a backslash before a double-quote and backslashes + if (*itr == '"' || *itr == '\\') + out << '\\'; + out << (*itr); + } + // Only print a closing " if there was real content on the line + if (started) + out << '"'; + + // Only print a newline if we haven't just closed a whole object + if (!closing) + out << std::endl; + } +} + +void print_usage(const char *application) +{ + std::cout << application << " version.txt license.txt methods.json types.json notifications.json" << std::endl; +} + +int main(int argc, char* argv[]) +{ + if (argc < 6) + { + print_usage(argv[0]); + return -1; + } + + std::ofstream out ("ServiceDescription.h", std::ofstream::binary); + + std::ifstream version(argv[1], std::ios_base::in); + std::ifstream license(argv[2], std::ios_base::in); + std::ifstream methods(argv[3], std::ios_base::in); + std::ifstream types(argv[4], std::ios_base::in); + std::ifstream notifications(argv[5], std::ios_base::in); + + if (!(version && license && methods && types && notifications)) + { + std::cout << "Failed to find one or more of version.txt, license.txt, methods.json, types.json or notifications.json" << std::endl; + return -1; + } + + out << "#pragma once" << std::endl; + + print_license(license, out); + + out << std::endl; + + out << "namespace JSONRPC" << std::endl; + out << "{" << std::endl; + out << " const char* const JSONRPC_SERVICE_ID = \"http://xbmc.org/jsonrpc/ServiceDescription.json\";" << std::endl; + out << " const char* const JSONRPC_SERVICE_VERSION = \""; print_version(version, out); out << "\";" << std::endl; + out << " const char* const JSONRPC_SERVICE_DESCRIPTION = \"JSON-RPC API of XBMC\";" << std::endl; + out << std::endl; + + out << " const char* const JSONRPC_SERVICE_TYPES[] = {"; + print_json(types, out); + out << " };" << std::endl; + out << std::endl; + + out << " const char* const JSONRPC_SERVICE_METHODS[] = {"; + print_json(methods, out); + out << " };" << std::endl; + out << std::endl; + + out << " const char* const JSONRPC_SERVICE_NOTIFICATIONS[] = {"; + print_json(notifications, out); + out << " };" << std::endl; + + out << "}" << std::endl; + + return 0; +} diff --git a/tools/depends/native/JsonSchemaBuilder/src/Makefile.am b/tools/depends/native/JsonSchemaBuilder/src/Makefile.am new file mode 100644 index 0000000..99454a1 --- /dev/null +++ b/tools/depends/native/JsonSchemaBuilder/src/Makefile.am @@ -0,0 +1,4 @@ +bin_PROGRAMS = JsonSchemaBuilder +JsonSchemaBuilder_SOURCES = JsonSchemaBuilder.cpp +AM_CXXFLAGS = -O2 -std=c++11 + diff --git a/tools/depends/native/JsonSchemaBuilder/src/autogen.sh b/tools/depends/native/JsonSchemaBuilder/src/autogen.sh new file mode 100755 index 0000000..872167c --- /dev/null +++ b/tools/depends/native/JsonSchemaBuilder/src/autogen.sh @@ -0,0 +1,3 @@ +#!/bin/sh + +autoreconf -vif diff --git a/tools/depends/native/JsonSchemaBuilder/src/configure.ac b/tools/depends/native/JsonSchemaBuilder/src/configure.ac new file mode 100644 index 0000000..54ebee2 --- /dev/null +++ b/tools/depends/native/JsonSchemaBuilder/src/configure.ac @@ -0,0 +1,10 @@ +dnl Process this file with autoconf to produce a configure script. +AC_INIT(JsonSchemaBuilder, 1.0, me@mail.com) +AC_CONFIG_AUX_DIR(config) +AC_CONFIG_SRCDIR(JsonSchemaBuilder.cpp) + +AM_INIT_AUTOMAKE([foreign]) + +AC_PROG_CXX + +AC_OUTPUT(Makefile) diff --git a/tools/depends/native/JsonSchemaBuilder/win32/JsonSchemaBuilder.sln b/tools/depends/native/JsonSchemaBuilder/win32/JsonSchemaBuilder.sln new file mode 100644 index 0000000..33a7195 --- /dev/null +++ b/tools/depends/native/JsonSchemaBuilder/win32/JsonSchemaBuilder.sln @@ -0,0 +1,20 @@ + +Microsoft Visual Studio Solution File, Format Version 11.00 +# Visual Studio 2010 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "JsonSchemaBuilder", "JsonSchemaBuilder.vcxproj", "{6D4C9949-FF2B-4B14-83BB-D86AB27B855A}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Release|Win32 = Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {6D4C9949-FF2B-4B14-83BB-D86AB27B855A}.Debug|Win32.ActiveCfg = Debug|Win32 + {6D4C9949-FF2B-4B14-83BB-D86AB27B855A}.Debug|Win32.Build.0 = Debug|Win32 + {6D4C9949-FF2B-4B14-83BB-D86AB27B855A}.Release|Win32.ActiveCfg = Release|Win32 + {6D4C9949-FF2B-4B14-83BB-D86AB27B855A}.Release|Win32.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/tools/depends/native/JsonSchemaBuilder/win32/JsonSchemaBuilder.vcxproj b/tools/depends/native/JsonSchemaBuilder/win32/JsonSchemaBuilder.vcxproj new file mode 100644 index 0000000..ab84c5c --- /dev/null +++ b/tools/depends/native/JsonSchemaBuilder/win32/JsonSchemaBuilder.vcxproj @@ -0,0 +1,85 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <ItemGroup Label="ProjectConfigurations"> + <ProjectConfiguration Include="Debug|Win32"> + <Configuration>Debug</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|Win32"> + <Configuration>Release</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + </ItemGroup> + <PropertyGroup Label="Globals"> + <ProjectGuid>{6D4C9949-FF2B-4B14-83BB-D86AB27B855A}</ProjectGuid> + <Keyword>Win32Proj</Keyword> + <RootNamespace>JsonSchemaBuilder</RootNamespace> + <WindowsTargetPlatformVersion>10.0.17763.0</WindowsTargetPlatformVersion> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration"> + <ConfigurationType>Application</ConfigurationType> + <UseDebugLibraries>true</UseDebugLibraries> + <CharacterSet>Unicode</CharacterSet> + <PlatformToolset>v141</PlatformToolset> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration"> + <ConfigurationType>Application</ConfigurationType> + <UseDebugLibraries>false</UseDebugLibraries> + <WholeProgramOptimization>true</WholeProgramOptimization> + <CharacterSet>Unicode</CharacterSet> + <PlatformToolset>v141</PlatformToolset> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> + <ImportGroup Label="ExtensionSettings"> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + </ImportGroup> + <PropertyGroup Label="UserMacros" /> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <LinkIncremental>true</LinkIncremental> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <LinkIncremental>false</LinkIncremental> + </PropertyGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <ClCompile> + <PrecompiledHeader> + </PrecompiledHeader> + <WarningLevel>Level3</WarningLevel> + <Optimization>Disabled</Optimization> + <PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> + </ClCompile> + <Link> + <SubSystem>Console</SubSystem> + <GenerateDebugInformation>true</GenerateDebugInformation> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <ClCompile> + <WarningLevel>Level3</WarningLevel> + <PrecompiledHeader> + </PrecompiledHeader> + <Optimization>MaxSpeed</Optimization> + <FunctionLevelLinking>true</FunctionLevelLinking> + <IntrinsicFunctions>true</IntrinsicFunctions> + <PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> + </ClCompile> + <Link> + <SubSystem>Console</SubSystem> + <GenerateDebugInformation>true</GenerateDebugInformation> + <EnableCOMDATFolding>true</EnableCOMDATFolding> + <OptimizeReferences>true</OptimizeReferences> + </Link> + </ItemDefinitionGroup> + <ItemGroup> + <ClCompile Include="..\src\JsonSchemaBuilder.cpp" /> + </ItemGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> + <ImportGroup Label="ExtensionTargets"> + </ImportGroup> +</Project>
\ No newline at end of file diff --git a/tools/depends/native/JsonSchemaBuilder/win32/JsonSchemaBuilder.vcxproj.filters b/tools/depends/native/JsonSchemaBuilder/win32/JsonSchemaBuilder.vcxproj.filters new file mode 100644 index 0000000..3c090a8 --- /dev/null +++ b/tools/depends/native/JsonSchemaBuilder/win32/JsonSchemaBuilder.vcxproj.filters @@ -0,0 +1,13 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <ItemGroup> + <Filter Include="src"> + <UniqueIdentifier>{7ce1989c-783c-4e53-bb32-8511e3adab08}</UniqueIdentifier> + </Filter> + </ItemGroup> + <ItemGroup> + <ClCompile Include="..\src\JsonSchemaBuilder.cpp"> + <Filter>src</Filter> + </ClCompile> + </ItemGroup> +</Project>
\ No newline at end of file diff --git a/tools/depends/native/Makefile b/tools/depends/native/Makefile new file mode 100644 index 0000000..800270f --- /dev/null +++ b/tools/depends/native/Makefile @@ -0,0 +1,105 @@ +include ../Makefile.include + +ifneq ($(shell test -f $(NATIVEPREFIX)/share/config.site && echo 1),1) + $(error Error: $(NATIVEPREFIX)/share/config.site is missing. Please reconfigure depends to generate it) +endif + +# Keep in alphabetical order +NATIVE= \ + autoconf \ + autoconf-archive \ + automake \ + cmake \ + gas-preprocessor \ + gettext \ + giflib \ + heimdal \ + JsonSchemaBuilder \ + libjpeg-turbo \ + liblzo2 \ + libpng \ + libtool \ + m4 \ + meson \ + nasm \ + ninja \ + openssl \ + pcre \ + perlmodule-parseyapp \ + pkg-config \ + python3 \ + swig \ + TexturePacker \ + zlib + +ifneq ($(NATIVE_OS),osx) + NATIVE += libffi + LIBFFI = libffi +endif + +ifeq ($(OS),darwin_embedded) + NATIVE += dpkg xz tar ldid +endif + +ifeq ($(OS),linux) + NATIVE += expat wayland-scanner pugixml waylandpp-scanner + EXPAT = expat + + ifeq ($(RENDER_SYSTEM),gles) + NATIVE += MarkupSafe Mako + endif +endif + +.PHONY: $(NATIVE) native + +all: native + @echo "Dependencies built successfully." + +# Dependency layout for parallel builds +autoconf-archive: autoconf +autoconf: m4 +automake: autoconf +dpkg: automake gettext libtool pkg-config tar +heimdal: libtool +JsonSchemaBuilder: automake +libjpeg-turbo: cmake nasm +libpng: zlib automake +libtool: automake +Mako: MarkupSafe +meson: python3 +ninja: meson +openssl: zlib +pugixml: cmake +python3: $(EXPAT) $(LIBFFI) pkg-config zlib openssl autoconf-archive +swig: pcre +tar: xz automake +TexturePacker: automake pkg-config libpng liblzo2 giflib libjpeg-turbo +wayland-scanner: expat pkg-config +waylandpp-scanner: cmake pugixml + +# python installs are not thread safe when using easy_install method. +# MarkupSafe doesn't really depend on ninja but we need to make the +# build sequential +MarkupSafe: ninja + +#liblzo2 has stale packaged automake files that cause borked host/build detection +liblzo2: automake + +native: $(NATIVE) +$(NATIVE): + $(MAKE) -C $@ +clean: + for d in $(NATIVE); do $(MAKE) -C $$d clean; done + +# Debug target, this will DELETE all data in staging! +test-dependencies: + ( for d in $(NATIVE); do \ + rm -rf $(NATIVEPREFIX); \ + mkdir -p $(NATIVEPREFIX)/include $(NATIVEPREFIX)/share $(NATIVEPREFIX)/bin; \ + cp -f config.site $(NATIVEPREFIX)/share/; \ + $(MAKE) distclean; \ + $(MAKE) $$d; done ) && echo "$@ built successfully" + +distclean:: + for d in $(NATIVE); do $(MAKE) -C $$d distclean; done + diff --git a/tools/depends/native/Mako/Makefile b/tools/depends/native/Mako/Makefile new file mode 100644 index 0000000..c31e462 --- /dev/null +++ b/tools/depends/native/Mako/Makefile @@ -0,0 +1,27 @@ +include ../../Makefile.include +PREFIX=$(NATIVEPREFIX) +PLATFORM=$(NATIVEPLATFORM) +DEPS = ../../Makefile.include Makefile ../../download-files.include + +# lib name, version +LIBNAME=Mako +VERSION=1.1.3 +ARCHIVE=$(LIBNAME)-$(VERSION).tar.gz +SHA512=a9b94fa34a61e7794b6e4549fa0bada6ff84dfb0d9edb8d5c7f9b95d12184fa4499f42303cfee720b576a9f7e986a57d91ad3aeb26c9f93154dbc08fb2975952 +include ../../download-files.include + +all: .installed-$(PLATFORM) + +$(PLATFORM): $(DEPS) | $(TARBALLS_LOCATION)/$(ARCHIVE).$(HASH_TYPE) + -rm -rf $(PLATFORM)/*; mkdir -p $(PLATFORM) + cd $(PLATFORM); $(ARCHIVE_TOOL) $(ARCHIVE_TOOL_FLAGS) $(TARBALLS_LOCATION)/$(ARCHIVE) + +.installed-$(PLATFORM): $(PLATFORM) + cd $(PLATFORM); $(PREFIX)/bin/python3 setup.py install --prefix=$(PREFIX) + touch $@ + +clean: + rm -f .installed-$(PLATFORM) + +distclean:: + rm -rf $(PLATFORM) .installed-$(PLATFORM) diff --git a/tools/depends/native/MarkupSafe/Makefile b/tools/depends/native/MarkupSafe/Makefile new file mode 100644 index 0000000..fa43727 --- /dev/null +++ b/tools/depends/native/MarkupSafe/Makefile @@ -0,0 +1,27 @@ +include ../../Makefile.include +PREFIX=$(NATIVEPREFIX) +PLATFORM=$(NATIVEPLATFORM) +DEPS = ../../Makefile.include Makefile ../../download-files.include + +# lib name, version +LIBNAME=MarkupSafe +VERSION=1.1.1 +ARCHIVE=$(LIBNAME)-$(VERSION).tar.gz +SHA512=f3014e6131a3ab866914c5635b5397ef71906bffb1b6f8c5f2ed2acf167429ff7914236d38943e872683a57a9be9669f4c5aace6274f3307ab21ef25373db0b6 +include ../../download-files.include + +all: .installed-$(PLATFORM) + +$(PLATFORM): $(DEPS) | $(TARBALLS_LOCATION)/$(ARCHIVE).$(HASH_TYPE) + -rm -rf $(PLATFORM)/*; mkdir -p $(PLATFORM) + cd $(PLATFORM); $(ARCHIVE_TOOL) $(ARCHIVE_TOOL_FLAGS) $(TARBALLS_LOCATION)/$(ARCHIVE) + +.installed-$(PLATFORM): $(PLATFORM) + cd $(PLATFORM); $(PREFIX)/bin/python3 setup.py install --prefix=$(PREFIX) + touch $@ + +clean: + rm -f .installed-$(PLATFORM) + +distclean:: + rm -rf $(PLATFORM) .installed-$(PLATFORM) diff --git a/tools/depends/native/TexturePacker/CMakeLists.txt b/tools/depends/native/TexturePacker/CMakeLists.txt new file mode 100644 index 0000000..97dc1d3 --- /dev/null +++ b/tools/depends/native/TexturePacker/CMakeLists.txt @@ -0,0 +1,54 @@ +list(APPEND CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake/modules) + +if(APPLE) + set(CMAKE_FIND_ROOT_PATH ${NATIVEPREFIX}) +endif() + +find_package(Lzo2 REQUIRED) +find_package(PNG REQUIRED) +find_package(GIF REQUIRED) +find_package(JPEG REQUIRED) + +if(GIF_VERSION LESS 4) + message(FATAL_ERROR "giflib < 4 not supported") +else() + file(STRINGS ${GIF_INCLUDE_DIR}/gif_lib.h GIFSTRINGS) + string(REGEX MATCH "GIFLIB_MAJOR ([0-9])" GIFLIB_MAJOR ${GIFSTRINGS}) + if(GIFLIB_MAJOR) + string(REPLACE " " ";" GIFLIB_MAJOR ${GIFLIB_MAJOR}) + list(GET GIFLIB_MAJOR 1 GIFLIB_MAJOR) + else() + set(GIFLIB_MAJOR ${GIF_VERSION}) + endif() + if(NOT GIFLIB_MAJOR OR GIFLIB_MAJOR LESS 5) + message(WARNING "giflib${GIFLIB_MAJOR} support is experimental. Consider updating to giflib5") + endif() +endif() + +set(SOURCES src/md5.cpp + src/DecoderManager.cpp + src/TexturePacker.cpp + src/XBTFWriter.cpp + src/decoder/GIFDecoder.cpp + src/decoder/GifHelper.cpp + src/decoder/JPGDecoder.cpp + src/decoder/PNGDecoder.cpp + ${CMAKE_SOURCE_DIR}/xbmc/guilib/XBTF.cpp) + +set(CMAKE_POSITITION_INDEPENDENT_CODE 1) + +add_executable(TexturePacker ${SOURCES}) +target_include_directories(TexturePacker + PRIVATE ${PNG_INCLUDE_DIRS} + ${JPEG_INCLUDE_DIR} + ${GIF_INCLUDE_DIR} + ${CMAKE_SOURCE_DIR}/xbmc + ${CMAKE_CURRENT_SOURCE_DIR}/src + ${CMAKE_CURRENT_SOURCE_DIR}/src/decoder) +target_link_libraries(TexturePacker + PRIVATE ${SYSTEM_LDFLAGS} + ${GIF_LIBRARIES} + ${PNG_LIBRARIES} + ${JPEG_LIBRARIES} + ${LZO2_LIBRARIES}) +target_compile_options(TexturePacker PRIVATE ${ARCH_DEFINES} ${SYSTEM_DEFINES}) diff --git a/tools/depends/native/TexturePacker/Makefile b/tools/depends/native/TexturePacker/Makefile new file mode 100644 index 0000000..f50dc87 --- /dev/null +++ b/tools/depends/native/TexturePacker/Makefile @@ -0,0 +1,62 @@ +ROOT_DIR := $(shell dirname $(realpath $(lastword $(MAKEFILE_LIST)))) +-include ../../Makefile.include +DEPS=Makefile + +ifeq ($(NATIVEPREFIX),) + PREFIX = $(ROOT_DIR) +else + PREFIX = $(NATIVEPREFIX) +endif + +ifeq ($(NATIVEPLATFORM),) + PLATFORM = native + EXTRA_CONFIGURE = --enable-static +else + PLATFORM = $(NATIVEPLATFORM) + DEPS += ../../Makefile.include +endif + +ifeq ($(NATIVE_OS), linux) + EXTRA_CONFIGURE = --enable-static +endif +ifeq ($(NATIVE_OS), android) + EXTRA_CONFIGURE = --enable-static +endif + +ifeq ($(CMAKE_SOURCE_DIR),) + CMAKE_SOURCE_DIR = $(ROOT_DIR)/../../../.. +endif + +SOURCE=$(ROOT_DIR)/src + +APP=$(PLATFORM)/TexturePacker +APPBIN=$(PREFIX)/bin/TexturePacker + +all: .installed-$(PLATFORM) + +$(PLATFORM): $(DEPS) + -rm -rf $(PLATFORM)/*; mkdir -p $(PLATFORM) + cd $(PLATFORM); cp -a $(SOURCE)/* . + cd $(PLATFORM); ./autogen.sh + cd $(PLATFORM); ./configure --prefix=$(PREFIX) $(EXTRA_CONFIGURE) EXTRA_DEFINES="$(NATIVE_ARCH_DEFINES)" + + +$(APP): $(PLATFORM) + $(MAKE) -C $(PLATFORM) + +.installed-$(PLATFORM): $(APP) + $(MAKE) -C $(PLATFORM) install + touch $@ + #TEMP workaround for skins: create legacy link. Remove me when skins are fixed + @mkdir -p $(CMAKE_SOURCE_DIR)/tools/TexturePacker + @[ -f $(CMAKE_SOURCE_DIR)/tools/TexturePacker/TexturePacker ] && rm $(CMAKE_SOURCE_DIR)/tools/TexturePacker/TexturePacker || : + @ln -sf $(APPBIN) $(CMAKE_SOURCE_DIR)/tools/TexturePacker/TexturePacker + @echo "all:" > $(CMAKE_SOURCE_DIR)/tools/TexturePacker/Makefile + @echo "\t@echo "WARNING: use of tools/TexturePacker/TexturePacker is deprecated, please update your skins Makefile"" >> $(CMAKE_SOURCE_DIR)/tools/TexturePacker/Makefile + +clean: + $(MAKE) -C $(PLATFORM) clean + +distclean:: + rm -rf $(PLATFORM) .installed-$(PLATFORM) + -rm -rf bin diff --git a/tools/depends/native/TexturePacker/src/DecoderManager.cpp b/tools/depends/native/TexturePacker/src/DecoderManager.cpp new file mode 100644 index 0000000..8f6a904 --- /dev/null +++ b/tools/depends/native/TexturePacker/src/DecoderManager.cpp @@ -0,0 +1,88 @@ +/* + * Copyright (C) 2014 Team Kodi + * http://kodi.tv + * + * 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, 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 XBMC; see the file COPYING. If not, see + * <http://www.gnu.org/licenses/>. + * + */ +#include <cstdio> +#include "DecoderManager.h" + +bool DecoderManager::verbose; +std::vector<IDecoder *> DecoderManager::m_decoders; + +// ADD new decoders here +// include decoders +#include "PNGDecoder.h" +#include "JPGDecoder.h" +#include "GIFDecoder.h" + +void DecoderManager::InstantiateDecoders() +{ + m_decoders.push_back(new PNGDecoder()); + m_decoders.push_back(new JPGDecoder()); + m_decoders.push_back(new GIFDecoder()); +} + +void DecoderManager::FreeDecoders() +{ + for (unsigned int i = 0; i < m_decoders.size(); i++) + { + delete m_decoders[i]; + } + m_decoders.clear(); +} + +// returns true for png, bmp, tga, jpg and dds files, otherwise returns false +bool DecoderManager::IsSupportedGraphicsFile(char *strFileName) +{ + std::string filename = strFileName; + if (filename.length() < 4) + return false; + + for (unsigned int i = 0; i < m_decoders.size(); i++) + { + const std::vector<std::string> extensions = m_decoders[i]->GetSupportedExtensions(); + for (unsigned int n = 0; n < extensions.size(); n++) + { + int extLen = extensions[n].length(); + if (std::string::npos != filename.rfind(extensions[n].c_str(), filename.length() - extLen, extLen)) + { + return true; + } + } + } + return false; +} + +bool DecoderManager::LoadFile(const std::string &filename, DecodedFrames &frames) +{ + for (unsigned int i = 0; i < m_decoders.size(); i++) + { + if (m_decoders[i]->CanDecode(filename)) + { + if (verbose) + fprintf(stdout, "This is a %s - lets load it via %s...\n", + m_decoders[i]->GetImageFormatName(), m_decoders[i]->GetDecoderName()); + return m_decoders[i]->LoadFile(filename, frames); + } + } + return false; +} + +void DecoderManager::FreeDecodedFrames(DecodedFrames &frames) +{ + frames.clear(); +} diff --git a/tools/depends/native/TexturePacker/src/DecoderManager.h b/tools/depends/native/TexturePacker/src/DecoderManager.h new file mode 100644 index 0000000..2c59aa2 --- /dev/null +++ b/tools/depends/native/TexturePacker/src/DecoderManager.h @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2014 Team Kodi + * http://kodi.tv + * + * 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, 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 XBMC; see the file COPYING. If not, see + * <http://www.gnu.org/licenses/>. + * + */ + +#pragma once + +#include "IDecoder.h" + +class DecoderManager +{ + public: + static void InstantiateDecoders(); + static void FreeDecoders(); + static bool IsSupportedGraphicsFile(char *strFileName); + static bool LoadFile(const std::string &filename, DecodedFrames &frames); + static void FreeDecodedFrames(DecodedFrames &frames); + static bool verbose; + + private: + static std::vector<IDecoder *> m_decoders; +}; diff --git a/tools/depends/native/TexturePacker/src/Makefile.am b/tools/depends/native/TexturePacker/src/Makefile.am new file mode 100644 index 0000000..d6b676f --- /dev/null +++ b/tools/depends/native/TexturePacker/src/Makefile.am @@ -0,0 +1,29 @@ +AUTOMAKE_OPTIONS = subdir-objects + +AM_CFLAGS = -DTARGET_POSIX +AM_CFLAGS += @EXTRA_DEFINES@ +AM_CXXFLAGS = $(AM_CFLAGS) -std=c++0x + +AM_CPPFLAGS = \ + -I. \ + -I./decoder \ + -I@KODI_SRC_DIR@/xbmc \ + -I@KODI_SRC_DIR@/xbmc/guilib \ + @CPPFLAGS@ + +AM_LDFLAGS = @LIBS@ @STATIC_FLAG@ + + +bin_PROGRAMS = TexturePacker +TexturePacker_SOURCES = md5.cpp \ + XBTFWriter.cpp \ + TexturePacker.cpp \ + DecoderManager.cpp \ + decoder/PNGDecoder.cpp \ + decoder/JPGDecoder.cpp \ + decoder/GifHelper.cpp \ + decoder/GIFDecoder.cpp \ + XBTF.cpp + +XBTF.cpp: + @cp @KODI_SRC_DIR@/xbmc/guilib/XBTF.cpp . diff --git a/tools/depends/native/TexturePacker/src/SimpleFS.h b/tools/depends/native/TexturePacker/src/SimpleFS.h new file mode 100644 index 0000000..69d3342 --- /dev/null +++ b/tools/depends/native/TexturePacker/src/SimpleFS.h @@ -0,0 +1,107 @@ +/* + * Copyright (C) 2005-2013 Team XBMC + * http://kodi.tv + * + * 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, 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 XBMC; see the file COPYING. If not, see + * <http://www.gnu.org/licenses/>. + * + */ + +#pragma once + +#include <cstdint> +#include <cstdio> +#include <string> + +class CFile +{ +public: + CFile() + { + m_file = NULL; + } + + ~CFile() + { + Close(); + } + + bool Open(const std::string &file) + { + Close(); + m_file = fopen(file.c_str(), "rb"); + return NULL != m_file; + } + + bool OpenForWrite(const std::string &file, bool overwrite) + { + Close(); + m_file = fopen(file.c_str(), "wb"); + return NULL != m_file; + } + void Close() + { + if (m_file) + fclose(m_file); + m_file = NULL; + } + + uint64_t Read(void *data, uint64_t size) + { + if (fread(data, (size_t)size, 1, m_file) == 1) + return size; + return 0; + } + + uint64_t Write(const void *data, uint64_t size) + { + if (fwrite(data, (size_t)size, 1, m_file) == 1) + return size; + return 0; + } + + FILE *getFP() + { + return m_file; + } + + uint64_t GetFileSize() + { + long curPos = ftell(m_file); + uint64_t fileSize = 0; + if (fseek(m_file, 0, SEEK_END) == 0) + { + long size = ftell(m_file); + if (size >= 0) + fileSize = (uint64_t)size; + } + + // restore fileptr + Seek(curPos); + + return fileSize; + } + + uint64_t Seek(uint64_t offset) + { + uint64_t seekedBytes = 0; + int seekRet = fseek(m_file, offset, SEEK_SET); + if (seekRet == 0) + seekedBytes = offset; + return seekedBytes; + } + +private: + FILE* m_file; +}; diff --git a/tools/depends/native/TexturePacker/src/TexturePacker.cpp b/tools/depends/native/TexturePacker/src/TexturePacker.cpp new file mode 100644 index 0000000..a6fd428 --- /dev/null +++ b/tools/depends/native/TexturePacker/src/TexturePacker.cpp @@ -0,0 +1,420 @@ +/* + * Copyright (C) 2005-2014 Team XBMC + * http://kodi.tv + * + * 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, 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 XBMC; see the file COPYING. If not, see + * <http://www.gnu.org/licenses/>. + * + */ + +#ifdef TARGET_WINDOWS +#include <sys/types.h> +#define __STDC_FORMAT_MACROS +#include <cinttypes> +#define platform_stricmp _stricmp +#else +#include <inttypes.h> +#define platform_stricmp strcasecmp +#endif +#include <cerrno> +#include <dirent.h> +#include <map> + +#include "guilib/XBTF.h" +#include "guilib/XBTFReader.h" + +#include "DecoderManager.h" + +#include "XBTFWriter.h" +#include "md5.h" +#include "cmdlineargs.h" + +#ifdef TARGET_WINDOWS +#define strncasecmp _strnicmp +#endif + +#include <lzo/lzo1x.h> +#include <sys/stat.h> + +#define FLAGS_USE_LZO 1 + +#define DIR_SEPARATOR '/' + +const char *GetFormatString(unsigned int format) +{ + switch (format) + { + case XB_FMT_DXT1: + return "DXT1 "; + case XB_FMT_DXT3: + return "DXT3 "; + case XB_FMT_DXT5: + return "DXT5 "; + case XB_FMT_DXT5_YCoCg: + return "YCoCg"; + case XB_FMT_A8R8G8B8: + return "ARGB "; + case XB_FMT_A8: + return "A8 "; + default: + return "?????"; + } +} + +void CreateSkeletonHeaderImpl(CXBTFWriter& xbtfWriter, + const std::string& fullPath, + const std::string& relativePath) +{ + struct dirent* dp; + struct stat stat_p; + DIR *dirp = opendir(fullPath.c_str()); + + if (dirp) + { + for (errno = 0; (dp = readdir(dirp)); errno = 0) + { + if (strcmp(dp->d_name, ".") == 0 || strcmp(dp->d_name, "..") == 0) + { + continue; + } + + //stat to check for dir type (reiserfs fix) + std::string fileN = fullPath + "/" + dp->d_name; + if (stat(fileN.c_str(), &stat_p) == 0) + { + if (dp->d_type == DT_DIR || stat_p.st_mode & S_IFDIR) + { + std::string tmpPath = relativePath; + if (tmpPath.size() > 0) + { + tmpPath += "/"; + } + + CreateSkeletonHeaderImpl(xbtfWriter, fullPath + DIR_SEPARATOR + dp->d_name, tmpPath + dp->d_name); + } + else if (DecoderManager::IsSupportedGraphicsFile(dp->d_name)) + { + std::string fileName = ""; + if (relativePath.size() > 0) + { + fileName += relativePath; + fileName += "/"; + } + + fileName += dp->d_name; + + CXBTFFile file; + file.SetPath(fileName); + xbtfWriter.AddFile(file); + } + } + } + if (errno) + fprintf(stderr, "Error reading directory %s (%s)\n", fullPath.c_str(), strerror(errno)); + + closedir(dirp); + } + else + { + fprintf(stderr, "Error opening %s (%s)\n", fullPath.c_str(), strerror(errno)); + } +} + +void CreateSkeletonHeader(CXBTFWriter& xbtfWriter, const std::string& fullPath) +{ + std::string temp; + CreateSkeletonHeaderImpl(xbtfWriter, fullPath, temp); +} + +CXBTFFrame appendContent(CXBTFWriter &writer, int width, int height, unsigned char *data, unsigned int size, unsigned int format, bool hasAlpha, unsigned int flags) +{ + CXBTFFrame frame; + lzo_uint packedSize = size; + + if ((flags & FLAGS_USE_LZO) == FLAGS_USE_LZO) + { + // grab a temporary buffer for unpacking into + packedSize = size + size / 16 + 64 + 3; // see simple.c in lzo + unsigned char *packed = new unsigned char[packedSize]; + unsigned char *working = new unsigned char[LZO1X_999_MEM_COMPRESS]; + if (packed && working) + { + if (lzo1x_999_compress(data, size, packed, &packedSize, working) != LZO_E_OK || packedSize > size) + { + // compression failed, or compressed size is bigger than uncompressed, so store as uncompressed + packedSize = size; + writer.AppendContent(data, size); + } + else + { // success + lzo_uint optimSize = size; + if (lzo1x_optimize(packed, packedSize, data, &optimSize, NULL) != LZO_E_OK || optimSize != size) + { //optimisation failed + packedSize = size; + writer.AppendContent(data, size); + } + else + { // success + writer.AppendContent(packed, packedSize); + } + } + delete[] working; + delete[] packed; + } + } + else + { + writer.AppendContent(data, size); + } + frame.SetPackedSize(packedSize); + frame.SetUnpackedSize(size); + frame.SetWidth(width); + frame.SetHeight(height); + frame.SetFormat(hasAlpha ? format : format | XB_FMT_OPAQUE); + frame.SetDuration(0); + return frame; +} + +bool HasAlpha(unsigned char *argb, unsigned int width, unsigned int height) +{ + unsigned char *p = argb + 3; // offset of alpha + for (unsigned int i = 0; i < 4*width*height; i += 4) + { + if (p[i] != 0xff) + return true; + } + return false; +} + +CXBTFFrame createXBTFFrame(RGBAImage &image, CXBTFWriter& writer, double maxMSE, unsigned int flags) +{ + + int width, height; + unsigned int format = 0; + unsigned char* argb = (unsigned char*)image.pixels; + + width = image.width; + height = image.height; + bool hasAlpha = HasAlpha(argb, width, height); + + CXBTFFrame frame; + format = XB_FMT_A8R8G8B8; + frame = appendContent(writer, width, height, argb, (width * height * 4), format, hasAlpha, flags); + + return frame; +} + +void Usage() +{ + puts("Usage:"); + puts(" -help Show this screen."); + puts(" -input <dir> Input directory. Default: current dir"); + puts(" -output <dir> Output directory/filename. Default: Textures.xbt"); + puts(" -dupecheck Enable duplicate file detection. Reduces output file size. Default: off"); +} + +static bool checkDupe(struct MD5Context* ctx, + std::map<std::string, unsigned int>& hashes, + std::vector<unsigned int>& dupes, unsigned int pos) +{ + unsigned char digest[17]; + MD5Final(digest,ctx); + digest[16] = 0; + char hex[33]; + sprintf(hex, "%02X%02X%02X%02X%02X%02X%02X%02X"\ + "%02X%02X%02X%02X%02X%02X%02X%02X", digest[0], digest[1], digest[2], + digest[3], digest[4], digest[5], digest[6], digest[7], digest[8], + digest[9], digest[10], digest[11], digest[12], digest[13], digest[14], + digest[15]); + hex[32] = 0; + std::map<std::string, unsigned int>::iterator it = hashes.find(hex); + if (it != hashes.end()) + { + dupes[pos] = it->second; + return true; + } + + hashes.insert(std::make_pair(hex,pos)); + dupes[pos] = pos; + + return false; +} + +int createBundle(const std::string& InputDir, const std::string& OutputFile, double maxMSE, unsigned int flags, bool dupecheck) +{ + CXBTFWriter writer(OutputFile); + if (!writer.Create()) + { + fprintf(stderr, "Error creating file\n"); + return 1; + } + + std::map<std::string, unsigned int> hashes; + std::vector<unsigned int> dupes; + CreateSkeletonHeader(writer, InputDir); + + std::vector<CXBTFFile> files = writer.GetFiles(); + dupes.resize(files.size()); + if (!dupecheck) + { + for (unsigned int i=0;i<dupes.size();++i) + dupes[i] = i; + } + + for (size_t i = 0; i < files.size(); i++) + { + struct MD5Context ctx; + MD5Init(&ctx); + CXBTFFile& file = files[i]; + + std::string fullPath = InputDir; + fullPath += file.GetPath(); + + std::string output = file.GetPath(); + output = output.substr(0, 40); + while (output.size() < 46) + output += ' '; + + DecodedFrames frames; + bool loaded = DecoderManager::LoadFile(fullPath, frames); + + if (!loaded) + { + fprintf(stderr, "...unable to load image %s\n", file.GetPath().c_str()); + continue; + } + + printf("%s\n", output.c_str()); + bool skip=false; + if (dupecheck) + { + for (unsigned int j = 0; j < frames.frameList.size(); j++) + MD5Update(&ctx, + (const uint8_t*)frames.frameList[j].rgbaImage.pixels, + frames.frameList[j].rgbaImage.height * frames.frameList[j].rgbaImage.pitch); + + if (checkDupe(&ctx,hashes,dupes,i)) + { + printf("**** duplicate of %s\n", files[dupes[i]].GetPath().c_str()); + file.GetFrames().insert(file.GetFrames().end(), + files[dupes[i]].GetFrames().begin(), + files[dupes[i]].GetFrames().end()); + skip = true; + } + } + + if (!skip) + { + for (unsigned int j = 0; j < frames.frameList.size(); j++) + { + printf(" frame %4i (delay:%4i) ", j, frames.frameList[j].delay); + CXBTFFrame frame = createXBTFFrame(frames.frameList[j].rgbaImage, writer, maxMSE, flags); + frame.SetDuration(frames.frameList[j].delay); + file.GetFrames().push_back(frame); + printf("%s%c (%d,%d @ %" PRIu64 " bytes)\n", GetFormatString(frame.GetFormat()), frame.HasAlpha() ? ' ' : '*', + frame.GetWidth(), frame.GetHeight(), frame.GetUnpackedSize()); + } + } + DecoderManager::FreeDecodedFrames(frames); + file.SetLoop(0); + + writer.UpdateFile(file); + } + + if (!writer.UpdateHeader(dupes)) + { + fprintf(stderr, "Error writing header to file\n"); + return 1; + } + + if (!writer.Close()) + { + fprintf(stderr, "Error closing file\n"); + return 1; + } + + return 0; +} + +int main(int argc, char* argv[]) +{ + if (lzo_init() != LZO_E_OK) + return 1; + bool valid = false; + unsigned int flags = 0; + bool dupecheck = false; + CmdLineArgs args(argc, (const char**)argv); + + // setup some defaults, lzo packing, + flags = FLAGS_USE_LZO; + + if (args.size() == 1) + { + Usage(); + return 1; + } + + std::string InputDir; + std::string OutputFilename = "Textures.xbt"; + + for (unsigned int i = 1; i < args.size(); ++i) + { + if (!platform_stricmp(args[i], "-help") || !platform_stricmp(args[i], "-h") || !platform_stricmp(args[i], "-?")) + { + Usage(); + return 1; + } + else if (!platform_stricmp(args[i], "-input") || !platform_stricmp(args[i], "-i")) + { + InputDir = args[++i]; + valid = true; + } + else if (!strcmp(args[i], "-dupecheck")) + { + dupecheck = true; + } + else if (!strcmp(args[i], "-verbose")) + { + DecoderManager::verbose = true; + } + else if (!platform_stricmp(args[i], "-output") || !platform_stricmp(args[i], "-o")) + { + OutputFilename = args[++i]; + valid = true; +#ifdef TARGET_POSIX + char *c = NULL; + while ((c = (char *)strchr(OutputFilename.c_str(), '\\')) != NULL) *c = '/'; +#endif + } + else + { + fprintf(stderr, "Unrecognized command line flag: %s\n", args[i]); + } + } + + if (!valid) + { + Usage(); + return 1; + } + + size_t pos = InputDir.find_last_of(DIR_SEPARATOR); + if (pos != InputDir.length() - 1) + InputDir += DIR_SEPARATOR; + + double maxMSE = 1.5; // HQ only please + DecoderManager::InstantiateDecoders(); + createBundle(InputDir, OutputFilename, maxMSE, flags, dupecheck); + DecoderManager::FreeDecoders(); +} diff --git a/tools/depends/native/TexturePacker/src/Win32/TexturePacker.sln b/tools/depends/native/TexturePacker/src/Win32/TexturePacker.sln new file mode 100644 index 0000000..07cd920 --- /dev/null +++ b/tools/depends/native/TexturePacker/src/Win32/TexturePacker.sln @@ -0,0 +1,22 @@ +
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio 2013
+VisualStudioVersion = 12.0.30723.0
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "TexturePacker", "TexturePacker.vcxproj", "{57EC0A84-7E0C-4EEA-9E63-BB4EBF2310D7}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Win32 = Debug|Win32
+ Release|Win32 = Release|Win32
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {57EC0A84-7E0C-4EEA-9E63-BB4EBF2310D7}.Debug|Win32.ActiveCfg = Debug|Win32
+ {57EC0A84-7E0C-4EEA-9E63-BB4EBF2310D7}.Debug|Win32.Build.0 = Debug|Win32
+ {57EC0A84-7E0C-4EEA-9E63-BB4EBF2310D7}.Release|Win32.ActiveCfg = Release|Win32
+ {57EC0A84-7E0C-4EEA-9E63-BB4EBF2310D7}.Release|Win32.Build.0 = Release|Win32
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+EndGlobal
diff --git a/tools/depends/native/TexturePacker/src/Win32/TexturePacker.vcxproj b/tools/depends/native/TexturePacker/src/Win32/TexturePacker.vcxproj new file mode 100644 index 0000000..8f540ed --- /dev/null +++ b/tools/depends/native/TexturePacker/src/Win32/TexturePacker.vcxproj @@ -0,0 +1,144 @@ +<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup Label="ProjectConfigurations">
+ <ProjectConfiguration Include="Debug|Win32">
+ <Configuration>Debug</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|Win32">
+ <Configuration>Release</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ </ItemGroup>
+ <PropertyGroup Label="Globals">
+ <ProjectGuid>{57EC0A84-7E0C-4EEA-9E63-BB4EBF2310D7}</ProjectGuid>
+ <RootNamespace>TexturePacker</RootNamespace>
+ <Keyword>Win32Proj</Keyword>
+ <WindowsTargetPlatformVersion>10.0.17763.0</WindowsTargetPlatformVersion>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
+ <ConfigurationType>Application</ConfigurationType>
+ <CharacterSet>NotSet</CharacterSet>
+ <WholeProgramOptimization>true</WholeProgramOptimization>
+ <PlatformToolset>v141</PlatformToolset>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
+ <ConfigurationType>Application</ConfigurationType>
+ <CharacterSet>NotSet</CharacterSet>
+ <PlatformToolset>v141</PlatformToolset>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+ <ImportGroup Label="ExtensionSettings">
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <PropertyGroup Label="UserMacros" />
+ <PropertyGroup>
+ <_ProjectFileVersion>10.0.30319.1</_ProjectFileVersion>
+ <OutDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(SolutionDir)$(Configuration)\</OutDir>
+ <IntDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(Configuration)\</IntDir>
+ <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</LinkIncremental>
+ <OutDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(SolutionDir)$(Configuration)\</OutDir>
+ <IntDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(Configuration)\</IntDir>
+ <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">false</LinkIncremental>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <IncludePath>$(VC_IncludePath);$(WindowsSDK_IncludePath);..\..\..\..\..\..\project\BuildDependencies\include</IncludePath>
+ <LibraryPath>$(VC_LibraryPath_x86);$(WindowsSDK_LibraryPath_x86);$(NETFXKitsDir)Lib\um\x86;..\..\..\..\..\..\project\BuildDependencies\lib</LibraryPath>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <IncludePath>$(VC_IncludePath);$(WindowsSDK_IncludePath);..\..\..\..\..\..\project\BuildDependencies\include</IncludePath>
+ <LibraryPath>$(VC_LibraryPath_x86);$(WindowsSDK_LibraryPath_x86);$(NETFXKitsDir)Lib\um\x86;..\..\..\..\..\..\project\BuildDependencies\lib</LibraryPath>
+ </PropertyGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <ClCompile>
+ <Optimization>Disabled</Optimization>
+ <AdditionalIncludeDirectories>.;..;..\decoder;..\..\..\..\..\..\xbmc;..\..\..\..\..\..\project\BuildDependencies\win32\include</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;TARGET_WINDOWS;_ITERATOR_DEBUG_LEVEL=0;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <MinimalRebuild>true</MinimalRebuild>
+ <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
+ <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
+ <PrecompiledHeader>
+ </PrecompiledHeader>
+ <WarningLevel>Level3</WarningLevel>
+ <DebugInformationFormat>EditAndContinue</DebugInformationFormat>
+ <ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName>
+ </ClCompile>
+ <Link>
+ <AdditionalDependencies>jpeg-staticd.lib;libpng16_staticd.lib;gifd.lib;zlibstaticd.lib;lzo2d.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ <IgnoreSpecificDefaultLibraries>libcmtd.lib;%(IgnoreSpecificDefaultLibraries)</IgnoreSpecificDefaultLibraries>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <SubSystem>Console</SubSystem>
+ <TargetMachine>MachineX86</TargetMachine>
+ <AdditionalLibraryDirectories>..\..\..\..\..\..\project\BuildDependencies\win32\lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
+ <ImageHasSafeExceptionHandlers>false</ImageHasSafeExceptionHandlers>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <ClCompile>
+ <Optimization>MaxSpeed</Optimization>
+ <IntrinsicFunctions>true</IntrinsicFunctions>
+ <AdditionalIncludeDirectories>.;..;..\decoder;..\..\..\..\..\..\xbmc;..\..\..\..\..\..\project\BuildDependencies\win32\include</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;TARGET_WINDOWS;_ITERATOR_DEBUG_LEVEL=0;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
+ <FunctionLevelLinking>true</FunctionLevelLinking>
+ <PrecompiledHeader>
+ </PrecompiledHeader>
+ <WarningLevel>Level3</WarningLevel>
+ <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
+ <ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName>
+ </ClCompile>
+ <Link>
+ <AdditionalDependencies>jpeg-static.lib;libpng16_static.lib;gif.lib;zlibstatic.lib;lzo2.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ <IgnoreSpecificDefaultLibraries>libc.lib;%(IgnoreSpecificDefaultLibraries)</IgnoreSpecificDefaultLibraries>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <SubSystem>Console</SubSystem>
+ <OptimizeReferences>true</OptimizeReferences>
+ <EnableCOMDATFolding>true</EnableCOMDATFolding>
+ <TargetMachine>MachineX86</TargetMachine>
+ <AdditionalLibraryDirectories>..\..\..\..\..\..\project\BuildDependencies\win32\lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
+ <ImageHasSafeExceptionHandlers>false</ImageHasSafeExceptionHandlers>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemGroup>
+ <ClCompile Include="..\DecoderManager.cpp" />
+ <ClCompile Include="..\decoder\GIFDecoder.cpp" />
+ <ClCompile Include="..\decoder\GifHelper.cpp" />
+ <ClCompile Include="..\decoder\JPGDecoder.cpp" />
+ <ClCompile Include="..\decoder\PNGDecoder.cpp" />
+ <ClCompile Include="..\md5.cpp" />
+ <ClCompile Include="..\TexturePacker.cpp" />
+ <ClCompile Include="dirent.c" />
+ <ClCompile Include="..\..\..\..\..\..\xbmc\guilib\XBTF.cpp" />
+ <ClCompile Include="..\XBTFWriter.cpp" />
+ </ItemGroup>
+ <ItemGroup>
+ <ClInclude Include="..\cmdlineargs.h" />
+ <ClInclude Include="..\DecoderManager.h" />
+ <ClInclude Include="..\decoder\GIFDecoder.h" />
+ <ClInclude Include="..\decoder\GifHelper.h" />
+ <ClInclude Include="..\decoder\IDecoder.h" />
+ <ClInclude Include="..\decoder\JPGDecoder.h" />
+ <ClInclude Include="..\decoder\PNGDecoder.h" />
+ <ClInclude Include="..\rgbaimage.h" />
+ <ClInclude Include="dirent.h" />
+ <ClInclude Include="..\md5.h" />
+ <ClInclude Include="..\..\..\..\..\..\xbmc\guilib\XBTF.h" />
+ <ClInclude Include="..\XBTFWriter.h" />
+ <ClInclude Include="resource.h" />
+ </ItemGroup>
+ <ItemGroup>
+ <None Include="ReadMe.txt" />
+ </ItemGroup>
+ <ItemGroup>
+ <ResourceCompile Include="version.rc" />
+ </ItemGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+ <ImportGroup Label="ExtensionTargets">
+ </ImportGroup>
+</Project>
\ No newline at end of file diff --git a/tools/depends/native/TexturePacker/src/Win32/TexturePacker.vcxproj.filters b/tools/depends/native/TexturePacker/src/Win32/TexturePacker.vcxproj.filters new file mode 100644 index 0000000..f045d9c --- /dev/null +++ b/tools/depends/native/TexturePacker/src/Win32/TexturePacker.vcxproj.filters @@ -0,0 +1,101 @@ +<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup>
+ <Filter Include="Source Files">
+ <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
+ <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
+ </Filter>
+ <Filter Include="Header Files">
+ <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
+ <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>
+ </Filter>
+ <Filter Include="Resource Files">
+ <UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
+ <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav</Extensions>
+ </Filter>
+ <Filter Include="decoder">
+ <UniqueIdentifier>{c79bff3f-9118-4c2d-bc31-68b25f7dfbba}</UniqueIdentifier>
+ </Filter>
+ </ItemGroup>
+ <ItemGroup>
+ <ClCompile Include="dirent.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\..\..\..\..\xbmc\guilib\XBTF.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\XBTFWriter.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\md5.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\decoder\GIFDecoder.cpp">
+ <Filter>decoder</Filter>
+ </ClCompile>
+ <ClCompile Include="..\decoder\GifHelper.cpp">
+ <Filter>decoder</Filter>
+ </ClCompile>
+ <ClCompile Include="..\decoder\JPGDecoder.cpp">
+ <Filter>decoder</Filter>
+ </ClCompile>
+ <ClCompile Include="..\decoder\PNGDecoder.cpp">
+ <Filter>decoder</Filter>
+ </ClCompile>
+ <ClCompile Include="..\TexturePacker.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\DecoderManager.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ </ItemGroup>
+ <ItemGroup>
+ <ClInclude Include="..\cmdlineargs.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="dirent.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\md5.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\..\..\..\..\xbmc\guilib\XBTF.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\XBTFWriter.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\rgbaimage.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\decoder\GIFDecoder.h">
+ <Filter>decoder</Filter>
+ </ClInclude>
+ <ClInclude Include="..\decoder\GifHelper.h">
+ <Filter>decoder</Filter>
+ </ClInclude>
+ <ClInclude Include="..\decoder\IDecoder.h">
+ <Filter>decoder</Filter>
+ </ClInclude>
+ <ClInclude Include="..\decoder\JPGDecoder.h">
+ <Filter>decoder</Filter>
+ </ClInclude>
+ <ClInclude Include="..\decoder\PNGDecoder.h">
+ <Filter>decoder</Filter>
+ </ClInclude>
+ <ClInclude Include="..\DecoderManager.h">
+ <Filter>Source Files</Filter>
+ </ClInclude>
+ <ClInclude Include="resource.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ </ItemGroup>
+ <ItemGroup>
+ <None Include="ReadMe.txt" />
+ </ItemGroup>
+ <ItemGroup>
+ <ResourceCompile Include="version.rc">
+ <Filter>Resource Files</Filter>
+ </ResourceCompile>
+ </ItemGroup>
+</Project>
\ No newline at end of file diff --git a/tools/depends/native/TexturePacker/src/Win32/dirent.c b/tools/depends/native/TexturePacker/src/Win32/dirent.c new file mode 100644 index 0000000..7598516 --- /dev/null +++ b/tools/depends/native/TexturePacker/src/Win32/dirent.c @@ -0,0 +1,145 @@ +/* + + Implementation of POSIX directory browsing functions and types for Win32. + + Author: Kevlin Henney (kevlin@acm.org, kevlin@curbralan.com) + History: Created March 1997. Updated June 2003 and July 2012. + + Copyright Kevlin Henney, 1997, 2003. All rights reserved. + + Permission to use, copy, modify, and distribute this software and its + documentation for any purpose is hereby granted without fee, provided + that this copyright and permissions notice appear in all copies and + derivatives. + + This software is supplied "as is" without express or implied warranty. + + But that said, if there are any problems please get in touch. +*/ + +#include <errno.h> +#include <stdlib.h> +#include <string.h> + +#include <dirent.h> +#include <io.h> /* _findfirst and _findnext set errno iff they return -1 */ + +#ifdef __cplusplus +extern "C" +{ +#endif + +typedef ptrdiff_t handle_type; /* C99's intptr_t not sufficiently portable */ + +struct DIR +{ + handle_type handle; /* -1 for failed rewind */ + struct _finddata_t info; + struct dirent result; /* d_name null iff first time */ + char *name; /* null-terminated char string */ +}; + +DIR *opendir(const char *name) +{ + DIR *dir = 0; + + if(name && name[0]) + { + size_t base_length = strlen(name); + const char *all = /* search pattern must end with suitable wildcard */ + strchr("/\\", name[base_length - 1]) ? "*" : "/*"; + + if((dir = (DIR *) malloc(sizeof *dir)) != 0 && + (dir->name = (char *) malloc(base_length + strlen(all) + 1)) != 0) + { + strcat(strcpy(dir->name, name), all); + + if ((dir->handle = (handle_type)_findfirst(dir->name, &dir->info)) != -1) + { + dir->result.d_name = 0; + dir->result.d_type = 0; + } + else /* rollback */ + { + free(dir->name); + free(dir); + dir = 0; + } + } + else /* rollback */ + { + free(dir); + dir = 0; + errno = ENOMEM; + } + } + else + { + errno = EINVAL; + } + + return dir; +} + +int closedir(DIR *dir) +{ + int result = -1; + + if(dir) + { + if(dir->handle != -1) + { + result = _findclose(dir->handle); + } + + free(dir->name); + free(dir); + } + + if(result == -1) /* map all errors to EBADF */ + { + errno = EBADF; + } + + return result; +} + +struct dirent *readdir(DIR *dir) +{ + struct dirent *result = 0; + + if(dir && dir->handle != -1) + { + if(!dir->result.d_name || _findnext(dir->handle, &dir->info) != -1) + { + result = &dir->result; + result->d_name = dir->info.name; + result->d_type = (dir->info.attrib == _A_SUBDIR) ? DT_DIR : DT_UNKNOWN; + } + } + else + { + errno = EBADF; + } + + return result; +} + +void rewinddir(DIR *dir) +{ + if(dir && dir->handle != -1) + { + _findclose(dir->handle); + dir->handle = (handle_type)_findfirst(dir->name, &dir->info); + dir->result.d_name = 0; + dir->result.d_type = 0; + } + else + { + errno = EBADF; + } +} + +#ifdef __cplusplus +} +#endif diff --git a/tools/depends/native/TexturePacker/src/Win32/dirent.h b/tools/depends/native/TexturePacker/src/Win32/dirent.h new file mode 100644 index 0000000..e57b250 --- /dev/null +++ b/tools/depends/native/TexturePacker/src/Win32/dirent.h @@ -0,0 +1,53 @@ +/* + + Declaration of POSIX directory browsing functions and types for Win32. + + Author: Kevlin Henney (kevlin@acm.org, kevlin@curbralan.com) + History: Created March 1997. Updated June 2003. + + Copyright Kevlin Henney, 1997, 2003. All rights reserved. + + Permission to use, copy, modify, and distribute this software and its + documentation for any purpose is hereby granted without fee, provided + that this copyright and permissions notice appear in all copies and + derivatives. + + This software is supplied "as is" without express or implied warranty. + + But that said, if there are any problems please get in touch. +*/ + +#pragma once + +#ifdef __cplusplus +extern "C" +{ +#endif + +typedef struct DIR DIR; + +#define DT_UNKNOWN 0 +#define DT_FIFO 1 +#define DT_CHR 2 +#define DT_DIR 4 +#define DT_BLK 6 +#define DT_REG 8 +#define DT_LNK 10 +#define DT_SOCK 12 +#define DT_WHT 14 + +struct dirent +{ + char *d_name; + unsigned char d_type; +}; + +DIR *opendir(const char *); +int closedir(DIR *); +struct dirent *readdir(DIR *); +void rewinddir(DIR *); + +#ifdef __cplusplus +} +#endif + diff --git a/tools/depends/native/TexturePacker/src/Win32/version.rc b/tools/depends/native/TexturePacker/src/Win32/version.rc Binary files differnew file mode 100644 index 0000000..7ccb57f --- /dev/null +++ b/tools/depends/native/TexturePacker/src/Win32/version.rc diff --git a/tools/depends/native/TexturePacker/src/XBTFWriter.cpp b/tools/depends/native/TexturePacker/src/XBTFWriter.cpp new file mode 100644 index 0000000..1607db1 --- /dev/null +++ b/tools/depends/native/TexturePacker/src/XBTFWriter.cpp @@ -0,0 +1,164 @@ +/* + * Copyright (C) 2005-2013 Team XBMC + * http://kodi.tv + * + * 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, 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 XBMC; see the file COPYING. If not, see + * <http://www.gnu.org/licenses/>. + * + */ + +#define __STDC_FORMAT_MACROS +#include <cinttypes> +#if defined(TARGET_FREEBSD) || defined(TARGET_DARWIN) +#include <cstdlib> +#elif !defined(TARGET_DARWIN) +#include <malloc.h> +#endif +#include <memory.h> +#include <cstring> + +#include "XBTFWriter.h" +#include "guilib/XBTFReader.h" +#include "utils/EndianSwap.h" + + +#define WRITE_STR(str, size, file) fwrite(str, size, 1, file) +#define WRITE_U32(i, file) { uint32_t _n = Endian_SwapLE32(i); fwrite(&_n, 4, 1, file); } +#define WRITE_U64(i, file) { uint64_t _n = i; _n = Endian_SwapLE64(i); fwrite(&_n, 8, 1, file); } + +CXBTFWriter::CXBTFWriter(const std::string& outputFile) + : m_outputFile(outputFile), + m_file(nullptr), + m_data(nullptr), + m_size(0) +{ } + +CXBTFWriter::~CXBTFWriter() +{ + Close(); +} + +bool CXBTFWriter::Create() +{ + m_file = fopen(m_outputFile.c_str(), "wb"); + if (m_file == nullptr) + return false; + + return true; +} + +bool CXBTFWriter::Close() +{ + if (m_file == nullptr || m_data == nullptr) + return false; + + fwrite(m_data, 1, m_size, m_file); + + Cleanup(); + + return true; +} + +void CXBTFWriter::Cleanup() +{ + free(m_data); + m_data = nullptr; + m_size = 0; + if (m_file) + { + fclose(m_file); + m_file = nullptr; + } +} + +bool CXBTFWriter::AppendContent(unsigned char const* data, size_t length) +{ + unsigned char *new_data = (unsigned char *)realloc(m_data, m_size + length); + + if (new_data == nullptr) + { // OOM - cleanup and fail + Cleanup(); + return false; + } + + m_data = new_data; + + memcpy(m_data + m_size, data, length); + m_size += length; + + return true; +} + +bool CXBTFWriter::UpdateHeader(const std::vector<unsigned int>& dupes) +{ + if (m_file == nullptr) + return false; + + uint64_t headerSize = GetHeaderSize(); + uint64_t offset = headerSize; + + WRITE_STR(XBTF_MAGIC.c_str(), 4, m_file); + WRITE_STR(XBTF_VERSION.c_str(), 1, m_file); + + auto files = GetFiles(); + WRITE_U32(files.size(), m_file); + for (size_t i = 0; i < files.size(); i++) + { + CXBTFFile& file = files[i]; + + // Convert path to lower case and store it into a fixed size array because + // we need to store the path as a fixed length 256 byte character array. + std::string path = file.GetPath(); + char pathMem[CXBTFFile::MaximumPathLength]; + memset(pathMem, 0, sizeof(pathMem)); + + for (std::string::iterator ch = path.begin(); ch != path.end(); ++ch) + pathMem[std::distance(path.begin(), ch)] = tolower(*ch); + + WRITE_STR(pathMem, CXBTFFile::MaximumPathLength, m_file); + WRITE_U32(file.GetLoop(), m_file); + + std::vector<CXBTFFrame>& frames = file.GetFrames(); + WRITE_U32(frames.size(), m_file); + for (size_t j = 0; j < frames.size(); j++) + { + CXBTFFrame& frame = frames[j]; + if (dupes[i] != i) + frame.SetOffset(files[dupes[i]].GetFrames()[j].GetOffset()); + else + { + frame.SetOffset(offset); + offset += frame.GetPackedSize(); + } + + WRITE_U32(frame.GetWidth(), m_file); + WRITE_U32(frame.GetHeight(), m_file); + WRITE_U32(frame.GetFormat(true), m_file); + WRITE_U64(frame.GetPackedSize(), m_file); + WRITE_U64(frame.GetUnpackedSize(), m_file); + WRITE_U32(frame.GetDuration(), m_file); + WRITE_U64(frame.GetOffset(), m_file); + } + } + + // Sanity check + int64_t pos = ftell(m_file); + if (pos != static_cast<int64_t>(headerSize)) + { + printf("Expected header size (%" PRIu64 ") != actual size (%" PRId64 ")\n", headerSize, pos); + return false; + } + + return true; +} diff --git a/tools/depends/native/TexturePacker/src/XBTFWriter.h b/tools/depends/native/TexturePacker/src/XBTFWriter.h new file mode 100644 index 0000000..1e6496d --- /dev/null +++ b/tools/depends/native/TexturePacker/src/XBTFWriter.h @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2005-2013 Team XBMC + * http://kodi.tv + * + * 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, 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 XBMC; see the file COPYING. If not, see + * <http://www.gnu.org/licenses/>. + * + */ + +#pragma once + +#include "guilib/XBTF.h" + +#include <cstdio> +#include <string> +#include <vector> + +class CXBTFWriter : public CXBTFBase +{ +public: + CXBTFWriter(const std::string& outputFile); + ~CXBTFWriter() override; + + bool Create(); + bool Close(); + bool AppendContent(unsigned char const* data, size_t length); + bool UpdateHeader(const std::vector<unsigned int>& dupes); + +private: + void Cleanup(); + + std::string m_outputFile; + FILE* m_file; + unsigned char *m_data; + size_t m_size; +}; + diff --git a/tools/depends/native/TexturePacker/src/autogen.sh b/tools/depends/native/TexturePacker/src/autogen.sh new file mode 100755 index 0000000..bbec436 --- /dev/null +++ b/tools/depends/native/TexturePacker/src/autogen.sh @@ -0,0 +1,3 @@ +#/bin/sh + +autoreconf -vif diff --git a/tools/depends/native/TexturePacker/src/cmdlineargs.h b/tools/depends/native/TexturePacker/src/cmdlineargs.h new file mode 100644 index 0000000..d0b9d03 --- /dev/null +++ b/tools/depends/native/TexturePacker/src/cmdlineargs.h @@ -0,0 +1,148 @@ +/* + * Copyright (C) 2005-2013 Team XBMC + * http://kodi.tv + * + * 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, 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 XBMC; see the file COPYING. If not, see + * <http://www.gnu.org/licenses/>. + * + */ + +#pragma once + +#ifdef TARGET_POSIX +char* GetCommandLine(); +#define _snprintf snprintf +#else +#include <windows.h> +#endif +#include <vector> +#include <string> + +class CmdLineArgs : public std::vector<char*> +{ +public: + CmdLineArgs () + { + // Save local copy of the command line string, because + // ParseCmdLine() modifies this string while parsing it. + char* cmdline = GetCommandLine(); + m_cmdline = new char [strlen (cmdline) + 1]; + if (m_cmdline) + { + strcpy (m_cmdline, cmdline); + ParseCmdLine(); + } else { +#ifdef TARGET_POSIX + delete[] cmdline; +#endif + } + } + + CmdLineArgs (const int argc, const char **argv) + { + std::string cmdline; +#ifdef TARGET_POSIX + cmdline = "\""; +#endif + for (int i = 0 ; i<argc ; i++) + { + cmdline += std::string(argv[i]); + if ( i != (argc-1) ) + { +#ifdef TARGET_POSIX + cmdline += "\" \""; +#else + cmdline += " "; +#endif + } + } +#ifdef TARGET_POSIX + cmdline += "\""; +#endif + m_cmdline = new char [cmdline.length() + 1]; + if (m_cmdline) + { + strcpy(m_cmdline, cmdline.c_str()); + ParseCmdLine(); + } + } + + ~CmdLineArgs() + { + delete[] m_cmdline; + } + +private: + char* m_cmdline; // the command line string + + //////////////////////////////////////////////////////////////////////////////// + // Parse m_cmdline into individual tokens, which are delimited by spaces. If a + // token begins with a quote, then that token is terminated by the next quote + // followed immediately by a space or terminator. This allows tokens to contain + // spaces. + // This input string: This "is" a ""test"" "of the parsing" alg"o"rithm. + // Produces these tokens: This, is, a, "test", of the parsing, alg"o"rithm + //////////////////////////////////////////////////////////////////////////////// + void ParseCmdLine () + { + enum { TERM = '\0', + QUOTE = '\"' }; + + bool bInQuotes = false; + char* pargs = m_cmdline; + + while (*pargs) + { + while (isspace (*pargs)) // skip leading whitespace + pargs++; + + bInQuotes = (*pargs == QUOTE); // see if this token is quoted + + if (bInQuotes) // skip leading quote + pargs++; + + push_back (pargs); // store position of current token + + // Find next token. + // NOTE: Args are normally terminated by whitespace, unless the + // arg is quoted. That's why we handle the two cases separately, + // even though they are very similar. + if (bInQuotes) + { + // find next quote followed by a space or terminator + while (*pargs && + !(*pargs == QUOTE && (isspace (pargs[1]) || pargs[1] == TERM))) + pargs++; + if (*pargs) + { + *pargs = TERM; // terminate token + if (pargs[1]) // if quoted token not followed by a terminator + pargs += 2; // advance to next token + } + } + else + { + // skip to next non-whitespace character + while (*pargs && !isspace (*pargs)) + pargs++; + if (*pargs && isspace (*pargs)) // end of token + { + *pargs = TERM; // terminate token + pargs++; // advance to next token or terminator + } + } + } // while (*pargs) + } // ParseCmdLine() +}; // class CmdLineArgs + diff --git a/tools/depends/native/TexturePacker/src/configure.ac b/tools/depends/native/TexturePacker/src/configure.ac new file mode 100644 index 0000000..4b83b5e --- /dev/null +++ b/tools/depends/native/TexturePacker/src/configure.ac @@ -0,0 +1,41 @@ +dnl Process this file with autoconf to produce a configure script. +AC_INIT(TexturePacker, 1.0) +AC_CONFIG_AUX_DIR(config) +AC_CONFIG_HEADERS([config.h]) +AC_CONFIG_SRCDIR(TexturePacker.cpp) +AM_INIT_AUTOMAKE([foreign]) +AC_PROG_CXX +AC_LANG([C++]) +AC_C_BIGENDIAN + +abs_top_srcdir=${abs_top_srcdir=$(cd $srcdir; pwd)} +KODI_SRC_DIR=${KODI_SRC_DIR:-"${abs_top_srcdir}/../../../../.."} + +AC_ARG_ENABLE([static], + [AS_HELP_STRING([--enable-static], + [build static TexturePacker (default is no)])], + [STATIC_FLAG="-static"], + [STATIC_FLAG=""]) + + +PKG_CHECK_MODULES([PNG], [libpng], + [INCLUDES="$PNG_CFLAGS"; LIBS="$LIBS $(${PKG_CONFIG} --silence-errors --static --libs libpng)"], + AC_MSG_ERROR("libpng not found")) + +AC_CHECK_HEADER([gif_lib.h],, AC_MSG_ERROR("gif_lib.h not found")) +AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include <gif_lib.h>]], [[ +#if !defined GIFLIB_MAJOR || GIFLIB_MAJOR < 5 +#error libgif version < 5; +#endif ]])], [], [AC_MSG_NOTICE([[WARNING: libgif version is unsupported, please consider upgrading to 5.0.5 or higher.]])]) + +AC_CHECK_LIB([gif],[main],, AC_MSG_ERROR("libgif not found")) +AC_CHECK_HEADER([jpeglib.h],, AC_MSG_ERROR("jpeglib.h not found")) +AC_CHECK_LIB([jpeg],[main],, AC_MSG_ERROR("libjpeg not found")) +AC_CHECK_HEADER([lzo/lzo1x.h],, AC_MSG_ERROR("lzo/lzo1x.h not found")) +AC_CHECK_LIB([lzo2],[main],, AC_MSG_ERROR("liblzo2 not found")) + +AC_SUBST(KODI_SRC_DIR) +AC_SUBST(STATIC_FLAG) +AC_SUBST(EXTRA_DEFINES) + +AC_OUTPUT(Makefile) diff --git a/tools/depends/native/TexturePacker/src/decoder/GIFDecoder.cpp b/tools/depends/native/TexturePacker/src/decoder/GIFDecoder.cpp new file mode 100644 index 0000000..5bdfacd --- /dev/null +++ b/tools/depends/native/TexturePacker/src/decoder/GIFDecoder.cpp @@ -0,0 +1,79 @@ +/* + * Copyright (C) 2014 Team Kodi + * http://kodi.tv + * + * 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, 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 XBMC; see the file COPYING. If not, see + * <http://www.gnu.org/licenses/>. + * + */ + +#include "GIFDecoder.h" + +#include "GifHelper.h" + +#include <cstring> + +// returns true for gif files, otherwise returns false +bool GIFDecoder::CanDecode(const std::string &filename) +{ + return std::string::npos != filename.rfind(".gif",filename.length() - 4, 4); +} + +bool GIFDecoder::LoadFile(const std::string &filename, DecodedFrames &frames) +{ + int n = 0; + bool result = false; + + GifHelper *gifImage = new GifHelper(); + if (gifImage->LoadGif(filename.c_str())) + { + auto extractedFrames = gifImage->GetFrames(); + n = extractedFrames.size(); + if (n > 0) + { + unsigned int height = gifImage->GetHeight(); + unsigned int width = gifImage->GetWidth(); + unsigned int pitch = gifImage->GetPitch(); + unsigned int frameSize = pitch * height; + for (unsigned int i = 0; i < extractedFrames.size(); i++) + { + DecodedFrame frame; + + frame.rgbaImage.pixels = (char *)new char[frameSize]; + memcpy(frame.rgbaImage.pixels, extractedFrames[i]->m_pImage, frameSize); + frame.rgbaImage.height = height; + frame.rgbaImage.width = width; + frame.rgbaImage.bbp = 32; + frame.rgbaImage.pitch = pitch; + frame.delay = extractedFrames[i]->m_delay; + frame.decoder = this; + + frames.frameList.push_back(frame); + } + } + result = true; + } + delete gifImage; + return result; +} + +void GIFDecoder::FreeDecodedFrame(DecodedFrame &frame) +{ + delete [] frame.rgbaImage.pixels; +} + +void GIFDecoder::FillSupportedExtensions() +{ + m_supportedExtensions.emplace_back(".gif"); +} diff --git a/tools/depends/native/TexturePacker/src/decoder/GIFDecoder.h b/tools/depends/native/TexturePacker/src/decoder/GIFDecoder.h new file mode 100644 index 0000000..8f0b42d --- /dev/null +++ b/tools/depends/native/TexturePacker/src/decoder/GIFDecoder.h @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2014 Team Kodi + * http://kodi.tv + * + * 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, 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 XBMC; see the file COPYING. If not, see + * <http://www.gnu.org/licenses/>. + * + */ + +#pragma once + +#include "IDecoder.h" + +class GIFDecoder : public IDecoder +{ + public: + ~GIFDecoder() override = default; + bool CanDecode(const std::string &filename) override; + bool LoadFile(const std::string &filename, DecodedFrames &frames) override; + void FreeDecodedFrame(DecodedFrame &frame) override; + const char* GetImageFormatName() override { return "GIF"; } + const char* GetDecoderName() override { return "libgif"; } + protected: + void FillSupportedExtensions() override; +}; diff --git a/tools/depends/native/TexturePacker/src/decoder/GifHelper.cpp b/tools/depends/native/TexturePacker/src/decoder/GifHelper.cpp new file mode 100644 index 0000000..41ca270 --- /dev/null +++ b/tools/depends/native/TexturePacker/src/decoder/GifHelper.cpp @@ -0,0 +1,493 @@ +/* + * Copyright (C) 2014 Team Kodi + * http://kodi.tv + * + * 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, 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 XBMC; see the file COPYING. If not, see + * <http://www.gnu.org/licenses/>. + * + */ + +#include "GifHelper.h" + +#include <algorithm> +#include <cstdlib> +#include <cstring> + +#define UNSIGNED_LITTLE_ENDIAN(lo, hi) ((lo) | ((hi) << 8)) +#define GIF_MAX_MEMORY 82944000U // about 79 MB, which is equivalent to 10 full hd frames. + +class Gifreader +{ +public: + unsigned char* buffer = nullptr; + unsigned int buffSize = 0; + unsigned int readPosition = 0; + + Gifreader() = default; +}; + +int ReadFromVfs(GifFileType* gif, GifByteType* gifbyte, int len) +{ + CFile *gifFile = static_cast<CFile*>(gif->UserData); + return gifFile->Read(gifbyte, len); +} + +GifHelper::GifHelper() +{ + m_gifFile = new CFile(); +} + +GifHelper::~GifHelper() +{ + Close(m_gif); + Release(); + delete m_gifFile; +} + +bool GifHelper::Open(GifFileType*& gif, void *dataPtr, InputFunc readFunc) +{ + int err = 0; +#if GIFLIB_MAJOR == 5 + gif = DGifOpen(dataPtr, readFunc, &err); +#else + gif = DGifOpen(dataPtr, readFunc); + if (!gif) + err = GifLastError(); +#endif + + if (!gif) + { + fprintf(stderr, "Gif::Open(): Could not open file %s. Reason: %s\n", m_filename.c_str(), GifErrorString(err)); + return false; + } + + return true; +} + +void GifHelper::Close(GifFileType* gif) +{ + int err = 0; + int reason = 0; +#if GIFLIB_MAJOR == 5 && GIFLIB_MINOR >= 1 + err = DGifCloseFile(gif, &reason); +#else + err = DGifCloseFile(gif); +#if GIFLIB_MAJOR < 5 + reason = GifLastError(); +#endif + if (err == GIF_ERROR) + free(gif); +#endif + if (err == GIF_ERROR) + { + fprintf(stderr, "GifHelper::Close(): closing file %s failed. Reason: %s\n", m_filename.c_str(), Reason(reason)); + } +} + +const char* GifHelper::Reason(int reason) +{ + const char* err = GifErrorString(reason); + if (err) + return err; + + return "unknown"; + +} + +void GifHelper::Release() +{ + delete[] m_pTemplate; + m_pTemplate = nullptr; + m_globalPalette.clear(); + m_frames.clear(); +} + +void GifHelper::ConvertColorTable(std::vector<GifColor> &dest, ColorMapObject* src, unsigned int size) +{ + for (unsigned int i = 0; i < size; ++i) + { + GifColor c; + + c.r = src->Colors[i].Red; + c.g = src->Colors[i].Green; + c.b = src->Colors[i].Blue; + c.a = 0xff; + dest.push_back(c); + } +} + +bool GifHelper::LoadGifMetaData(GifFileType* gif) +{ + if (!Slurp(gif)) + return false; + + m_height = gif->SHeight; + m_width = gif->SWidth; + if (!m_height || !m_width) + { + fprintf(stderr, "Gif::LoadGif(): Zero sized image. File %s\n", m_filename.c_str()); + return false; + } + + m_numFrames = gif->ImageCount; + if (m_numFrames > 0) + { + ExtensionBlock* extb = gif->SavedImages[0].ExtensionBlocks; + if (extb && extb->Function == APPLICATION_EXT_FUNC_CODE) + { + // Read number of loops + if (++extb && extb->Function == CONTINUE_EXT_FUNC_CODE) + { + uint8_t low = static_cast<uint8_t>(extb->Bytes[1]); + uint8_t high = static_cast<uint8_t>(extb->Bytes[2]); + m_loops = UNSIGNED_LITTLE_ENDIAN(low, high); + } + } + } + else + { + fprintf(stderr, "Gif::LoadGif(): No images found in file %s\n", m_filename.c_str()); + return false; + } + + m_pitch = m_width * sizeof(GifColor); + m_imageSize = m_pitch * m_height; + unsigned long memoryUsage = m_numFrames * m_imageSize; + if (memoryUsage > GIF_MAX_MEMORY) + { + // at least 1 image + m_numFrames = std::max(1U, GIF_MAX_MEMORY / m_imageSize); + fprintf(stderr, "Gif::LoadGif(): Memory consumption too high: %lu bytes. Restricting animation to %u. File %s\n", memoryUsage, m_numFrames, m_filename.c_str()); + } + + return true; +} + +bool GifHelper::LoadGifMetaData(const char* file) +{ + m_gifFile->Close(); + if (!m_gifFile->Open(file) || !Open(m_gif, m_gifFile, ReadFromVfs)) + return false; + + return LoadGifMetaData(m_gif); +} + +bool GifHelper::Slurp(GifFileType* gif) +{ + if (DGifSlurp(gif) == GIF_ERROR) + { + int reason = 0; +#if GIFLIB_MAJOR == 5 + reason = gif->Error; +#else + reason = GifLastError(); +#endif + fprintf(stderr, "Gif::LoadGif(): Could not read file %s. Reason: %s\n", m_filename.c_str(), GifErrorString(reason)); + return false; + } + + return true; +} + +bool GifHelper::LoadGif(const char* file) +{ + m_filename = file; + if (!LoadGifMetaData(m_filename.c_str())) + return false; + + try + { + InitTemplateAndColormap(); + + int extractedFrames = ExtractFrames(m_numFrames); + if (extractedFrames < 0) + { + fprintf(stderr, "Gif::LoadGif(): Could not extract any frame. File %s\n", m_filename.c_str()); + return false; + } + else if (extractedFrames < (int)m_numFrames) + { + fprintf(stderr, "Gif::LoadGif(): Could only extract %d/%d frames. File %s\n", extractedFrames, m_numFrames, m_filename.c_str()); + m_numFrames = extractedFrames; + } + + return true; + } + catch (std::bad_alloc& ba) + { + fprintf(stderr, "Gif::Load(): Out of memory while reading file %s - %s\n", m_filename.c_str(), ba.what()); + Release(); + return false; + } +} + +void GifHelper::InitTemplateAndColormap() +{ + m_pTemplate = new unsigned char[m_imageSize]; + memset(m_pTemplate, 0, m_imageSize); + + if (m_gif->SColorMap) + { + m_globalPalette.clear(); + ConvertColorTable(m_globalPalette, m_gif->SColorMap, m_gif->SColorMap->ColorCount); + } + else + m_globalPalette.clear(); +} + +bool GifHelper::GcbToFrame(GifFrame &frame, unsigned int imgIdx) +{ + int transparent = -1; + frame.m_delay = 0; + frame.m_disposal = 0; + + if (m_gif->ImageCount > 0) + { +#if GIFLIB_MAJOR == 5 + GraphicsControlBlock gcb; + if (DGifSavedExtensionToGCB(m_gif, imgIdx, &gcb)) + { + // delay in ms + frame.m_delay = gcb.DelayTime * 10; + frame.m_disposal = gcb.DisposalMode; + transparent = gcb.TransparentColor; + } +#else + ExtensionBlock* extb = m_gif->SavedImages[imgIdx].ExtensionBlocks; + while (extb && extb->Function != GRAPHICS_EXT_FUNC_CODE) + extb++; + + if (extb && extb->ByteCount == 4) + { + uint8_t low = static_cast<uint8_t>(extb->Bytes[1]); + uint8_t high = static_cast<uint8_t>(extb->Bytes[2]); + frame.m_delay = UNSIGNED_LITTLE_ENDIAN(low, high) * 10; + frame.m_disposal = (extb->Bytes[0] >> 2) & 0x07; + if (extb->Bytes[0] & 0x01) + { + transparent = static_cast<uint8_t>(extb->Bytes[3]); + } + else + transparent = -1; + } +#endif + } + + if (transparent >= 0 && (unsigned)transparent < frame.m_palette.size()) + frame.m_palette[transparent].a = 0; + return true; +} + +int GifHelper::ExtractFrames(unsigned int count) +{ + if (!m_gif) + return -1; + + if (!m_pTemplate) + { + fprintf(stderr, "Gif::ExtractFrames(): No frame template available\n"); + return -1; + } + + int extracted = 0; + for (unsigned int i = 0; i < count; i++) + { + FramePtr frame(new GifFrame); + SavedImage savedImage = m_gif->SavedImages[i]; + GifImageDesc imageDesc = m_gif->SavedImages[i].ImageDesc; + frame->m_height = imageDesc.Height; + frame->m_width = imageDesc.Width; + frame->m_top = imageDesc.Top; + frame->m_left = imageDesc.Left; + + if (frame->m_top + frame->m_height > m_height || frame->m_left + frame->m_width > m_width + || !frame->m_width || !frame->m_height + || frame->m_width > m_width || frame->m_height > m_height) + { + fprintf(stderr, "Gif::ExtractFrames(): Illegal frame dimensions: width: %d, height: %d, left: %d, top: %d instead of (%d,%d), skip it\n", + frame->m_width, frame->m_height, frame->m_left, frame->m_top, m_width, m_height); + continue; + } + + if (imageDesc.ColorMap) + { + frame->m_palette.clear(); + ConvertColorTable(frame->m_palette, imageDesc.ColorMap, imageDesc.ColorMap->ColorCount); + // TODO save a backup of the palette for frames without a table in case there's no global table. + } + else if (m_gif->SColorMap) + { + frame->m_palette = m_globalPalette; + } + else + { + fprintf(stderr, "Gif::ExtractFrames(): No color map found for frame %d, skip it\n", i); + continue; + } + + // fill delay, disposal and transparent color into frame + if (!GcbToFrame(*frame, i)) + { + fprintf(stderr, "Gif::ExtractFrames(): Corrupted Graphics Control Block for frame %d, skip it\n", i); + continue; + } + + frame->m_pImage = new unsigned char[m_imageSize]; + frame->m_imageSize = m_imageSize; + memcpy(frame->m_pImage, m_pTemplate, m_imageSize); + + ConstructFrame(*frame, savedImage.RasterBits); + + if (!PrepareTemplate(*frame)) + { + fprintf(stderr, "Gif::ExtractFrames(): Could not prepare template after frame %d, skip it\n", i); + continue; + } + + extracted++; + m_frames.push_back(frame); + } + return extracted; +} + +void GifHelper::ConstructFrame(GifFrame &frame, const unsigned char* src) const +{ + size_t paletteSize = frame.m_palette.size(); + + for (unsigned int dest_y = frame.m_top, src_y = 0; src_y < frame.m_height; ++dest_y, ++src_y) + { + unsigned char *to = frame.m_pImage + (dest_y * m_pitch) + (frame.m_left * sizeof(GifColor)); + + const unsigned char *from = src + (src_y * frame.m_width); + for (unsigned int src_x = 0; src_x < frame.m_width; ++src_x) + { + unsigned char index = *from++; + + if (index >= paletteSize) + { + fprintf(stderr, "Gif::ConstructFrame(): Pixel (%d,%d) has no valid palette entry, skip it\n", src_x, src_y); + continue; + } + + GifColor col = frame.m_palette[index]; + if (col.a != 0) + memcpy(to, &col, sizeof(GifColor)); + + to += 4; + } + } +} + +bool GifHelper::PrepareTemplate(GifFrame &frame) +{ + switch (frame.m_disposal) + { + /* No disposal specified. */ + case DISPOSAL_UNSPECIFIED: + /* Leave image in place */ + case DISPOSE_DO_NOT: + memcpy(m_pTemplate, frame.m_pImage, m_imageSize); + break; + + /* + Clear the frame's area to transparency. + The disposal names is misleading. Do not restore to the background color because + this part of the specification is ignored by all browsers/image viewers. + */ + case DISPOSE_BACKGROUND: + { + ClearFrameAreaToTransparency(m_pTemplate, frame); + break; + } + /* Restore to previous content */ + case DISPOSE_PREVIOUS: + { + + /* + * This disposal method makes no sense for the first frame + * Since browsers etc. handle that too, we'll fall back to DISPOSE_DO_NOT + */ + if (m_frames.empty()) + { + frame.m_disposal = DISPOSE_DO_NOT; + return PrepareTemplate(frame); + } + + bool valid = false; + + for (int i = m_frames.size() - 1; i >= 0; --i) + { + if (m_frames[i]->m_disposal != DISPOSE_PREVIOUS) + { + memcpy(m_pTemplate, m_frames[i]->m_pImage, m_imageSize); + valid = true; + break; + } + } + if (!valid) + { + fprintf(stderr, "Gif::PrepareTemplate(): Disposal method DISPOSE_PREVIOUS encountered, but could not find a suitable frame.\n"); + return false; + } + break; + } + default: + { + fprintf(stderr, "Gif::PrepareTemplate(): Unknown disposal method: %d. Using DISPOSAL_UNSPECIFIED, the animation might be wrong now.\n", frame.m_disposal); + frame.m_disposal = DISPOSAL_UNSPECIFIED; + return PrepareTemplate(frame); + } + } + return true; +} + +void GifHelper::ClearFrameAreaToTransparency(unsigned char* dest, const GifFrame &frame) +{ + for (unsigned int dest_y = frame.m_top, src_y = 0; src_y < frame.m_height; ++dest_y, ++src_y) + { + unsigned char *to = dest + (dest_y * m_pitch) + (frame.m_left * sizeof(GifColor)); + for (unsigned int src_x = 0; src_x < frame.m_width; ++src_x) + { + to += 3; + *to++ = 0; + } + } +} + +GifFrame::GifFrame(const GifFrame& src) + : m_delay(src.m_delay), + m_top(src.m_top), + m_left(src.m_left), + m_disposal(src.m_disposal), + m_height(src.m_height), + m_width(src.m_width), + m_imageSize(src.m_imageSize) +{ + if (src.m_pImage) + { + m_pImage = new unsigned char[m_imageSize]; + memcpy(m_pImage, src.m_pImage, m_imageSize); + } + + if (src.m_palette.size()) + { + m_palette = src.m_palette; + } +} + +GifFrame::~GifFrame() +{ + delete[] m_pImage; + m_pImage = nullptr; +} diff --git a/tools/depends/native/TexturePacker/src/decoder/GifHelper.h b/tools/depends/native/TexturePacker/src/decoder/GifHelper.h new file mode 100644 index 0000000..1e897a7 --- /dev/null +++ b/tools/depends/native/TexturePacker/src/decoder/GifHelper.h @@ -0,0 +1,220 @@ +/* + * Copyright (C) 2014 Team Kodi + * http://kodi.tv + * + * 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, 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 XBMC; see the file COPYING. If not, see + * <http://www.gnu.org/licenses/>. + * + */ + +#pragma once + +#include <gif_lib.h> +#ifndef CONTINUE_EXT_FUNC_CODE +#define CONTINUE_EXT_FUNC_CODE 0 +#endif + +#ifndef DISPOSAL_UNSPECIFIED +#define DISPOSAL_UNSPECIFIED 0 +#endif + +#ifndef DISPOSE_DO_NOT +#define DISPOSE_DO_NOT 1 +#endif + +#ifndef DISPOSE_BACKGROUND +#define DISPOSE_BACKGROUND 2 +#endif + +#ifndef DISPOSE_PREVIOUS +#define DISPOSE_PREVIOUS 3 +#endif + +#include <vector> +#include <string> +#include <memory> +#include "SimpleFS.h" + +#pragma pack(1) +struct GifColor +{ + uint8_t b, g, r, a; +}; +#pragma pack() + +class CFile; + +class GifFrame +{ + friend class GifHelper; +public: + + GifFrame() = default; + virtual ~GifFrame(); + + unsigned char* m_pImage = nullptr; + unsigned int m_delay = 0; + +private: + GifFrame(const GifFrame& src); + + unsigned int m_top = 0; + unsigned int m_left = 0; + unsigned int m_disposal = 0; + unsigned int m_height = 0; + unsigned int m_width = 0; + unsigned int m_imageSize = 0; + std::vector<GifColor> m_palette; +}; + + + +class GifHelper +{ + friend class GifFrame; + + typedef std::shared_ptr<GifFrame> FramePtr; + +public: + GifHelper(); + virtual ~GifHelper(); + + + bool LoadGif(const char* file); + + std::vector<FramePtr>& GetFrames() { return m_frames; } + unsigned int GetPitch() const { return m_pitch; } + unsigned int GetNumLoops() const { return m_loops; } + unsigned int GetWidth() const { return m_width; } + unsigned int GetHeight() const { return m_height; } + +private: + std::vector<FramePtr> m_frames; + unsigned int m_imageSize = 0; + unsigned int m_pitch = 0; + unsigned int m_loops = 0; + unsigned int m_numFrames = 0; + + std::string m_filename; + GifFileType* m_gif = nullptr; + std::vector<GifColor> m_globalPalette; + unsigned char* m_pTemplate = nullptr; + CFile* m_gifFile; + + unsigned int m_width; + unsigned int m_height; + + bool Open(GifFileType *& gif, void * dataPtr, InputFunc readFunc); + void Close(GifFileType * gif); + + const char* Reason(int reason); + + bool LoadGifMetaData(const char* file); + bool Slurp(GifFileType* gif); + void InitTemplateAndColormap(); + bool LoadGifMetaData(GifFileType* gif); + static void ConvertColorTable(std::vector<GifColor> &dest, ColorMapObject* src, unsigned int size); + bool GcbToFrame(GifFrame &frame, unsigned int imgIdx); + int ExtractFrames(unsigned int count); + void ClearFrameAreaToTransparency(unsigned char* dest, const GifFrame &frame); + void ConstructFrame(GifFrame &frame, const unsigned char* src) const; + bool PrepareTemplate(GifFrame &frame); + void Release(); + +#if GIFLIB_MAJOR != 5 + /* + taken from giflib 5.1.0 + */ + const char* GifErrorString(int ErrorCode) + { + const char *Err; + + switch (ErrorCode) { + case E_GIF_ERR_OPEN_FAILED: + Err = "Failed to open given file"; + break; + case E_GIF_ERR_WRITE_FAILED: + Err = "Failed to write to given file"; + break; + case E_GIF_ERR_HAS_SCRN_DSCR: + Err = "Screen descriptor has already been set"; + break; + case E_GIF_ERR_HAS_IMAG_DSCR: + Err = "Image descriptor is still active"; + break; + case E_GIF_ERR_NO_COLOR_MAP: + Err = "Neither global nor local color map"; + break; + case E_GIF_ERR_DATA_TOO_BIG: + Err = "Number of pixels bigger than width * height"; + break; + case E_GIF_ERR_NOT_ENOUGH_MEM: + Err = "Failed to allocate required memory"; + break; + case E_GIF_ERR_DISK_IS_FULL: + Err = "Write failed (disk full?)"; + break; + case E_GIF_ERR_CLOSE_FAILED: + Err = "Failed to close given file"; + break; + case E_GIF_ERR_NOT_WRITEABLE: + Err = "Given file was not opened for write"; + break; + case D_GIF_ERR_OPEN_FAILED: + Err = "Failed to open given file"; + break; + case D_GIF_ERR_READ_FAILED: + Err = "Failed to read from given file"; + break; + case D_GIF_ERR_NOT_GIF_FILE: + Err = "Data is not in GIF format"; + break; + case D_GIF_ERR_NO_SCRN_DSCR: + Err = "No screen descriptor detected"; + break; + case D_GIF_ERR_NO_IMAG_DSCR: + Err = "No Image Descriptor detected"; + break; + case D_GIF_ERR_NO_COLOR_MAP: + Err = "Neither global nor local color map"; + break; + case D_GIF_ERR_WRONG_RECORD: + Err = "Wrong record type detected"; + break; + case D_GIF_ERR_DATA_TOO_BIG: + Err = "Number of pixels bigger than width * height"; + break; + case D_GIF_ERR_NOT_ENOUGH_MEM: + Err = "Failed to allocate required memory"; + break; + case D_GIF_ERR_CLOSE_FAILED: + Err = "Failed to close given file"; + break; + case D_GIF_ERR_NOT_READABLE: + Err = "Given file was not opened for read"; + break; + case D_GIF_ERR_IMAGE_DEFECT: + Err = "Image is defective, decoding aborted"; + break; + case D_GIF_ERR_EOF_TOO_SOON: + Err = "Image EOF detected before image complete"; + break; + default: + Err = NULL; + break; + } + return Err; + } +#endif +}; diff --git a/tools/depends/native/TexturePacker/src/decoder/IDecoder.h b/tools/depends/native/TexturePacker/src/decoder/IDecoder.h new file mode 100644 index 0000000..673ff1a --- /dev/null +++ b/tools/depends/native/TexturePacker/src/decoder/IDecoder.h @@ -0,0 +1,99 @@ +/* + * Copyright (C) 2014 Team Kodi + * http://kodi.tv + * + * 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, 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 XBMC; see the file COPYING. If not, see + * <http://www.gnu.org/licenses/>. + * + */ + +#pragma once + +#include <cstdint> +#include <string> +#include <vector> + +/* forward declarations */ + +class DecodedFrame; +class DecodedFrames; + +class IDecoder +{ + public: + virtual ~IDecoder() = default; + virtual bool CanDecode(const std::string &filename) = 0; + virtual bool LoadFile(const std::string &filename, DecodedFrames &frames) = 0; + virtual void FreeDecodedFrame(DecodedFrame &frame) = 0; + virtual const char* GetImageFormatName() = 0; + virtual const char* GetDecoderName() = 0; + + const std::vector<std::string>& GetSupportedExtensions() + { + m_supportedExtensions.clear(); + FillSupportedExtensions(); + return m_supportedExtensions; + } + + protected: + virtual void FillSupportedExtensions() = 0; + //fill this with extensions in FillSupportedExtensions like ".png" + std::vector<std::string> m_supportedExtensions; +}; + +class RGBAImage +{ +public: + RGBAImage() = default; + + char* pixels = nullptr; // image data + int width = 0; // width + int height = 0; // height + int bbp = 0; // bits per pixel + int pitch = 0; // rowsize in bytes +}; + +class DecodedFrame +{ +public: + DecodedFrame() = default; + RGBAImage rgbaImage; /* rgbaimage for this frame */ + int delay = 0; /* Frame delay in ms */ + IDecoder* decoder = nullptr; /* Pointer to decoder */ +}; + +class DecodedFrames +{ + public: + DecodedFrames() = default; + std::vector<DecodedFrame> frameList; + + void clear() + { + for (auto f : frameList) + { + if (f.decoder != NULL) + { + f.decoder->FreeDecodedFrame(f); + } + else + { + fprintf(stderr, + "ERROR: %s - can not determine decoder type for frame!\n", + __FUNCTION__); + } + } + frameList.clear(); + } +}; diff --git a/tools/depends/native/TexturePacker/src/decoder/JPGDecoder.cpp b/tools/depends/native/TexturePacker/src/decoder/JPGDecoder.cpp new file mode 100644 index 0000000..ce06d28 --- /dev/null +++ b/tools/depends/native/TexturePacker/src/decoder/JPGDecoder.cpp @@ -0,0 +1,137 @@ +/* + * Copyright (C) 2014 Team Kodi + * http://kodi.tv + * + * 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, 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 XBMC; see the file COPYING. If not, see + * <http://www.gnu.org/licenses/>. + * + */ + +#include "JPGDecoder.h" + +#include "SimpleFS.h" + +#include <jpeglib.h> + +bool JPGDecoder::CanDecode(const std::string &filename) +{ + CFile *fp = new CFile(); + bool ret = false; + unsigned char magic[2]; + if (fp->Open(filename)) + { + + //JPEG image files begin with FF D8 and end with FF D9. + // check for FF D8 big + little endian on start + uint64_t readbytes = fp->Read(magic, 2); + if (readbytes == 2) + { + if ((magic[0] == 0xd8 && magic[1] == 0xff) || + (magic[1] == 0xd8 && magic[0] == 0xff)) + ret = true; + } + + if (ret) + { + ret = false; + //check on FF D9 big + little endian on end + uint64_t fileSize = fp->GetFileSize(); + fp->Seek(fileSize - 2); + readbytes = fp->Read(magic, 2); + if (readbytes == 2) + { + if ((magic[0] == 0xd9 && magic[1] == 0xff) || + (magic[1] == 0xd9 && magic[0] == 0xff)) + ret = true; + } + } + } + delete fp; + return ret; +} + +bool JPGDecoder::LoadFile(const std::string &filename, DecodedFrames &frames) +{ + #define WIDTHBYTES(bits) ((((bits) + 31) / 32) * 4) + CFile *arq = new CFile(); + if (!arq->Open(filename)) + { + delete arq; + return false; + } + + struct jpeg_decompress_struct cinfo; + struct jpeg_error_mgr jerr; + + int ImageSize; + + cinfo.err = jpeg_std_error(&jerr); + jpeg_create_decompress(&cinfo); + + jpeg_stdio_src(&cinfo, arq->getFP()); + jpeg_read_header(&cinfo, TRUE); + jpeg_start_decompress(&cinfo); + + // Image Size is calculated as (width * height * bytes per pixel = 4 + ImageSize = cinfo.image_width * cinfo.image_height * 4; + + DecodedFrame frame; + + frame.rgbaImage.pixels = (char *)new char[ImageSize]; + + unsigned char *scanlinebuff = new unsigned char[3 * cinfo.image_width]; + unsigned char *dst = (unsigned char *)frame.rgbaImage.pixels; + while (cinfo.output_scanline < cinfo.output_height) + { + jpeg_read_scanlines(&cinfo,&scanlinebuff,1); + + unsigned char *src2 = scanlinebuff; + unsigned char *dst2 = dst; + for (unsigned int x = 0; x < cinfo.image_width; x++, src2 += 3) + { + *dst2++ = src2[2]; + *dst2++ = src2[1]; + *dst2++ = src2[0]; + *dst2++ = 0xff; + } + dst += cinfo.image_width * 4; + } + delete [] scanlinebuff; + + jpeg_finish_decompress(&cinfo); + jpeg_destroy_decompress(&cinfo); + + frame.rgbaImage.height = cinfo.image_height; + frame.rgbaImage.width = cinfo.image_width; + frame.rgbaImage.bbp = 32; + frame.rgbaImage.pitch = 4 * cinfo.image_width; + + frame.decoder = this; + + frames.frameList.push_back(frame); + + delete arq; + return true; +} + +void JPGDecoder::FreeDecodedFrame(DecodedFrame &frame) +{ + delete [] frame.rgbaImage.pixels; +} + +void JPGDecoder::FillSupportedExtensions() +{ + m_supportedExtensions.emplace_back(".jpg"); + m_supportedExtensions.emplace_back(".jpeg"); +} diff --git a/tools/depends/native/TexturePacker/src/decoder/JPGDecoder.h b/tools/depends/native/TexturePacker/src/decoder/JPGDecoder.h new file mode 100644 index 0000000..bbf23ba --- /dev/null +++ b/tools/depends/native/TexturePacker/src/decoder/JPGDecoder.h @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2014 Team Kodi + * http://kodi.tv + * + * 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, 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 XBMC; see the file COPYING. If not, see + * <http://www.gnu.org/licenses/>. + * + */ + +#pragma once + +#include "IDecoder.h" + +class JPGDecoder : public IDecoder +{ + public: + ~JPGDecoder() override = default; + bool CanDecode(const std::string &filename) override; + bool LoadFile(const std::string &filename, DecodedFrames &frames) override; + void FreeDecodedFrame(DecodedFrame &frame) override; + const char* GetImageFormatName() override { return "JPG"; } + const char* GetDecoderName() override { return "libjpeg"; } + protected: + void FillSupportedExtensions() override; +}; diff --git a/tools/depends/native/TexturePacker/src/decoder/PNGDecoder.cpp b/tools/depends/native/TexturePacker/src/decoder/PNGDecoder.cpp new file mode 100644 index 0000000..f327400 --- /dev/null +++ b/tools/depends/native/TexturePacker/src/decoder/PNGDecoder.cpp @@ -0,0 +1,244 @@ +/* + * Copyright (C) 2014 Team Kodi + * http://kodi.tv + * + * 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, 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 XBMC; see the file COPYING. If not, see + * <http://www.gnu.org/licenses/>. + * + */ + +#include "PNGDecoder.h" + +#include "SimpleFS.h" + +#include <png.h> + +#ifndef png_jmpbuf +# define png_jmpbuf(png_ptr) ((png_ptr)->jmpbuf) +#endif + +/* Check to see if a file is a PNG file using png_sig_cmp(). png_sig_cmp() + * returns zero if the image is a PNG and nonzero if it isn't a PNG. + * + * The function check_if_png() shown here, but not used, returns nonzero (true) + * if the file can be opened and is a PNG, 0 (false) otherwise. + * + * If this call is successful, and you are going to keep the file open, + * you should call png_set_sig_bytes(png_ptr, PNG_BYTES_TO_CHECK); once + * you have created the png_ptr, so that libpng knows your application + * has read that many bytes from the start of the file. Make sure you + * don't call png_set_sig_bytes() with more than 8 bytes read or give it + * an incorrect number of bytes read, or you will either have read too + * many bytes (your fault), or you are telling libpng to read the wrong + * number of magic bytes (also your fault). + * + * Many applications already read the first 2 or 4 bytes from the start + * of the image to determine the file type, so it would be easiest just + * to pass the bytes to png_sig_cmp() or even skip that if you know + * you have a PNG file, and call png_set_sig_bytes(). + */ +bool PNGDecoder::CanDecode(const std::string &filename) +{ + #define PNG_BYTES_TO_CHECK 4 + CFile fp; + char buf[PNG_BYTES_TO_CHECK]; + + /* Open the prospective PNG file. */ + if (!fp.Open(filename)) + return false; + + /* Read in some of the signature bytes */ + if (fp.Read(buf, PNG_BYTES_TO_CHECK) != PNG_BYTES_TO_CHECK) + { + fprintf(stderr, "error reading header ...\n"); + return false; + } + fp.Close(); + + /* Compare the first PNG_BYTES_TO_CHECK bytes of the signature. + Return nonzero (true) if they match */ + return(!png_sig_cmp((png_bytep)buf, (png_size_t)0, PNG_BYTES_TO_CHECK)); +} + +bool PNGDecoder::LoadFile(const std::string &filename, DecodedFrames &frames) +{ + png_byte header[8]; + + CFile fp; + if (!fp.Open(filename)) + { + perror(filename.c_str()); + return false; + } + + // read the header + fp.Read(header, 8); + + if (png_sig_cmp(header, 0, 8)) + { + fprintf(stderr, "error: %s is not a PNG.\n", filename.c_str()); + return false; + } + + png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); + if (!png_ptr) + { + fprintf(stderr, "error: png_create_read_struct returned 0.\n"); + return false; + } + + // create png info struct + png_infop info_ptr = png_create_info_struct(png_ptr); + if (!info_ptr) + { + fprintf(stderr, "error: png_create_info_struct returned 0.\n"); + png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL); + return false; + } + + // create png info struct + png_infop end_info = png_create_info_struct(png_ptr); + if (!end_info) + { + fprintf(stderr, "error: png_create_info_struct returned 0.\n"); + png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp) NULL); + return false; + } + + // the code in this if statement gets called if libpng encounters an error + if (setjmp(png_jmpbuf(png_ptr))) { + fprintf(stderr, "error from libpng\n"); + png_destroy_read_struct(&png_ptr, &info_ptr, &end_info); + return false; + } + + // init png reading + png_init_io(png_ptr, fp.getFP()); + + // let libpng know you already read the first 8 bytes + png_set_sig_bytes(png_ptr, 8); + + // read all the info up to the image data + png_read_info(png_ptr, info_ptr); + + // variables to pass to get info + int bit_depth, color_type; + png_uint_32 temp_width, temp_height; + + // get info about png + png_get_IHDR(png_ptr, info_ptr, &temp_width, &temp_height, &bit_depth, &color_type, + NULL, NULL, NULL); + + if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) + { + png_set_tRNS_to_alpha(png_ptr); + } + + //set it to 32bit pixeldepth + png_color_8 sig_bit; + sig_bit.red = 32; + sig_bit.green = 32; + sig_bit.blue = 32; + // if the image has an alpha channel then + sig_bit.alpha = 32; + png_set_sBIT(png_ptr, info_ptr, &sig_bit); + + + /* Add filler (or alpha) byte (before/after each RGB triplet) */ + png_set_filler(png_ptr, 0xff, PNG_FILLER_AFTER); + + + if (color_type == PNG_COLOR_TYPE_RGB || + color_type == PNG_COLOR_TYPE_RGB_ALPHA) + png_set_bgr(png_ptr); + + // convert indexed color to rgb + if (color_type == PNG_COLOR_TYPE_PALETTE) + png_set_palette_to_rgb(png_ptr); + + /* swap the RGBA or GA data to ARGB or AG (or BGRA to ABGR) */ + //png_set_swap_alpha(png_ptr); + + //libsquish only eats 32bit RGBA, must convert grayscale into this format + if (color_type == PNG_COLOR_TYPE_GRAY || + color_type == PNG_COLOR_TYPE_GRAY_ALPHA) + { + png_set_expand_gray_1_2_4_to_8(png_ptr); + png_set_gray_to_rgb(png_ptr); + } + + // Update the png info struct. + png_read_update_info(png_ptr, info_ptr); + + // Row size in bytes. + int rowbytes = png_get_rowbytes(png_ptr, info_ptr); + + // glTexImage2d requires rows to be 4-byte aligned + // rowbytes += 3 - ((rowbytes-1) % 4); + + // Allocate the image_data as a big block, to be given to opengl + png_byte * image_data; + image_data = (png_byte*)new png_byte[rowbytes * temp_height * sizeof(png_byte)+15]; + if (image_data == NULL) + { + fprintf(stderr, "error: could not allocate memory for PNG image data\n"); + png_destroy_read_struct(&png_ptr, &info_ptr, &end_info); + return false; + } + + // row_pointers is for pointing to image_data for reading the png with libpng + png_bytep * row_pointers = (png_bytep*) new png_bytep[temp_height * sizeof(png_bytep)]; + if (row_pointers == NULL) + { + fprintf(stderr, "error: could not allocate memory for PNG row pointers\n"); + png_destroy_read_struct(&png_ptr, &info_ptr, &end_info); + delete [] image_data; + return false; + } + + // set the individual row_pointers to point at the correct offsets of image_data + for (unsigned int i = 0; i < temp_height; i++) + { + row_pointers[i] = image_data + i * rowbytes; + } + + // read the png into image_data through row_pointers + png_read_image(png_ptr, row_pointers); + + DecodedFrame frame; + + frame.rgbaImage.pixels = (char *)image_data; + frame.rgbaImage.height = temp_height; + frame.rgbaImage.width = temp_width; + frame.rgbaImage.bbp = 32; + frame.rgbaImage.pitch = 4 * temp_width; + + frame.decoder = this; + + frames.frameList.push_back(frame); + // clean up + png_destroy_read_struct(&png_ptr, &info_ptr, &end_info); + delete [] row_pointers; + return true; +} + +void PNGDecoder::FreeDecodedFrame(DecodedFrame &frame) +{ + delete [] frame.rgbaImage.pixels; +} + +void PNGDecoder::FillSupportedExtensions() +{ + m_supportedExtensions.emplace_back(".png"); +} diff --git a/tools/depends/native/TexturePacker/src/decoder/PNGDecoder.h b/tools/depends/native/TexturePacker/src/decoder/PNGDecoder.h new file mode 100644 index 0000000..c7dba76 --- /dev/null +++ b/tools/depends/native/TexturePacker/src/decoder/PNGDecoder.h @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2014 Team Kodi + * http://kodi.tv + * + * 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, 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 XBMC; see the file COPYING. If not, see + * <http://www.gnu.org/licenses/>. + * + */ + +#pragma once + +#include "IDecoder.h" + +class PNGDecoder : public IDecoder +{ + public: + ~PNGDecoder() override = default; + bool CanDecode(const std::string &filename) override; + bool LoadFile(const std::string &filename, DecodedFrames &frames) override; + void FreeDecodedFrame(DecodedFrame &frame) override; + const char* GetImageFormatName() override { return "PNG"; } + const char* GetDecoderName() override { return "libpng"; } + protected: + void FillSupportedExtensions() override; +}; diff --git a/tools/depends/native/TexturePacker/src/md5.cpp b/tools/depends/native/TexturePacker/src/md5.cpp new file mode 100644 index 0000000..b9788dd --- /dev/null +++ b/tools/depends/native/TexturePacker/src/md5.cpp @@ -0,0 +1,231 @@ +/* + * This code implements the MD5 message-digest algorithm. + * The algorithm is due to Ron Rivest. This code was + * written by Colin Plumb in 1993, no copyright is claimed. + * This code is in the public domain; do with it what you wish. + * + * Equivalent code is available from RSA Data Security, Inc. + * This code has been tested against that, and is equivalent, + * except that you don't need to include two pages of legalese + * with every copy. + * + * To compute the message digest of a chunk of bytes, declare an + * MD5Context structure, pass it to MD5Init, call MD5Update as + * needed on buffers full of bytes, and then call MD5Final, which + * will fill a supplied 16-byte array with the digest. + * + * Changed so as no longer to depend on Colin Plumb's `usual.h' header + * definitions; now uses stuff from dpkg's config.h. + * - Ian Jackson <ian@chiark.greenend.org.uk>. + * Still in the public domain. + */ + +#include "md5.h" + + +#ifdef WORDS_BIGENDIAN +void +byteSwap(uint32_t *buf, unsigned words) +{ + uint8_t *p = (uint8_t*)buf; + + do { + *buf++ = (uint32_t)((unsigned)p[3] << 8 | p[2]) << 16 | + ((unsigned)p[1] << 8 | p[0]); + p += 4; + } while (--words); +} +#else +#define byteSwap(buf,words) +#endif + +/* The four core functions - F1 is optimized somewhat */ + +/* #define F1(x, y, z) (x & y | ~x & z) */ +#define F1(x, y, z) (z ^ (x & (y ^ z))) +#define F2(x, y, z) F1(z, x, y) +#define F3(x, y, z) (x ^ y ^ z) +#define F4(x, y, z) (y ^ (x | ~z)) + +/* This is the central step in the MD5 algorithm. */ +#define MD5STEP(f,w,x,y,z,in,s) \ + (w += f(x,y,z) + in, w = (w<<s | w>>(32-s)) + x) + +/* + * The core of the MD5 algorithm, this alters an existing MD5 hash to + * reflect the addition of 16 longwords of new data. MD5Update blocks + * the data and converts bytes into longwords for this routine. + */ +static void +MD5Transform(uint32_t buf[4], uint32_t const in[16]) +{ + uint32_t a, b, c, d; + + a = buf[0]; + b = buf[1]; + c = buf[2]; + d = buf[3]; + + MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7); + MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12); + MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17); + MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22); + MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7); + MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12); + MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17); + MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22); + MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7); + MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12); + MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17); + MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22); + MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7); + MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12); + MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17); + MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22); + + MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5); + MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9); + MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14); + MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20); + MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5); + MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9); + MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14); + MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20); + MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5); + MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9); + MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14); + MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20); + MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5); + MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9); + MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14); + MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20); + + MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4); + MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11); + MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16); + MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23); + MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4); + MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11); + MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16); + MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23); + MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4); + MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11); + MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16); + MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23); + MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4); + MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11); + MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16); + MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23); + + MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6); + MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10); + MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15); + MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21); + MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6); + MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10); + MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15); + MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21); + MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6); + MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10); + MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15); + MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21); + MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6); + MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10); + MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15); + MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21); + + buf[0] += a; + buf[1] += b; + buf[2] += c; + buf[3] += d; +} + +/* + * Start MD5 accumulation. Set bit count to 0 and buffer to mysterious + * initialization constants. + */ +void MD5Init(struct MD5Context *ctx) +{ + ctx->buf[0] = 0x67452301; + ctx->buf[1] = 0xefcdab89; + ctx->buf[2] = 0x98badcfe; + ctx->buf[3] = 0x10325476; + + ctx->bytes[0] = 0; + ctx->bytes[1] = 0; +} + +/* + * Update context to reflect the concatenation of another buffer full + * of bytes. + */ +void MD5Update(struct MD5Context *ctx, const uint8_t *buf, unsigned len) +{ + uint32_t t; + + /* Update byte count */ + + t = ctx->bytes[0]; + if ((ctx->bytes[0] = t + len) < t) + ctx->bytes[1]++; /* Carry from low to high */ + + t = 64 - (t & 0x3f); /* Space available in ctx->in (at least 1) */ + if (t > len) { + memcpy((uint8_t*)ctx->in + 64 - t, buf, len); + return; + } + /* First chunk is an odd size */ + memcpy((uint8_t*)ctx->in + 64 - t, buf, t); + byteSwap(ctx->in, 16); + MD5Transform(ctx->buf, ctx->in); + buf += t; + len -= t; + + /* Process data in 64-byte chunks */ + while (len >= 64) { + memcpy(ctx->in, buf, 64); + byteSwap(ctx->in, 16); + MD5Transform(ctx->buf, ctx->in); + buf += 64; + len -= 64; + } + + /* Handle any remaining bytes of data. */ + memcpy(ctx->in, buf, len); +} + +/* + * Final wrapup - pad to 64-byte boundary with the bit pattern + * 1 0* (64-bit count of bits processed, MSB-first) + */ +void MD5Final(uint8_t digest[16], struct MD5Context *ctx) +{ + int count = ctx->bytes[0] & 0x3f; /* Number of bytes in ctx->in */ + uint8_t *p = (uint8_t*)ctx->in + count; + + /* Set the first char of padding to 0x80. There is always room. */ + *p++ = 0x80; + + /* Bytes of padding needed to make 56 bytes (-8..55) */ + count = 56 - 1 - count; + + if (count < 0) { /* Padding forces an extra block */ + memset(p, 0, count + 8); + byteSwap(ctx->in, 16); + MD5Transform(ctx->buf, ctx->in); + p = (uint8_t*)ctx->in; + count = 56; + } + memset(p, 0, count); + byteSwap(ctx->in, 14); + + /* Append length in bits and transform */ + ctx->in[14] = ctx->bytes[0] << 3; + ctx->in[15] = ctx->bytes[1] << 3 | ctx->bytes[0] >> 29; + MD5Transform(ctx->buf, ctx->in); + + byteSwap(ctx->buf, 4); + memcpy(digest, ctx->buf, 16); + memset(ctx, 0, sizeof(*ctx)); /* In case it's sensitive */ +} + diff --git a/tools/depends/native/TexturePacker/src/md5.h b/tools/depends/native/TexturePacker/src/md5.h new file mode 100644 index 0000000..76475bc --- /dev/null +++ b/tools/depends/native/TexturePacker/src/md5.h @@ -0,0 +1,38 @@ +/* + * This code implements the MD5 message-digest algorithm. + * The algorithm is due to Ron Rivest. This code was + * written by Colin Plumb in 1993, no copyright is claimed. + * This code is in the public domain; do with it what you wish. + * + * Equivalent code is available from RSA Data Security, Inc. + * This code has been tested against that, and is equivalent, + * except that you don't need to include two pages of legalese + * with every copy. + * + * To compute the message digest of a chunk of bytes, declare an + * MD5Context structure, pass it to MD5Init, call MD5Update as + * needed on buffers full of bytes, and then call MD5Final, which + * will fill a supplied 16-byte array with the digest. + * + * Changed so as no longer to depend on Colin Plumb's `usual.h' header + * definitions; now uses stuff from dpkg's config.h. + * - Ian Jackson <ian@chiark.greenend.org.uk>. + * Still in the public domain. + */ + +#pragma once + +#include <cstdint> +#include <cstring> /* for memcpy() */ + +struct MD5Context +{ + uint32_t buf[4]; + uint32_t bytes[2]; + uint32_t in[16]; +}; + +void MD5Init(struct MD5Context *ctx); +void MD5Update(struct MD5Context *ctx, const uint8_t *buf, unsigned len); +void MD5Final(unsigned char digest[16], struct MD5Context *ctx); + diff --git a/tools/depends/native/Toolchain-Native.cmake.in b/tools/depends/native/Toolchain-Native.cmake.in new file mode 100644 index 0000000..c5f5643 --- /dev/null +++ b/tools/depends/native/Toolchain-Native.cmake.in @@ -0,0 +1,79 @@ +set(NATIVEPREFIX "@prefix@/@tool_dir@") + +set(TARBALL_DIR "@use_tarballs@") + +set(OS "@build_os@") +set(CMAKE_SYSTEM_PROCESSOR @host_cpu@) +set(CPU "@use_buildcpu@") + +if(OS STREQUAL linux) + set(CMAKE_SYSTEM_NAME Linux) +elseif(OS STREQUAL osx) + set(CMAKE_SYSTEM_NAME Darwin) +endif() + +if(CMAKE_SYSTEM_NAME STREQUAL Darwin) + if(CPU STREQUAL "arm") + set(CPU arm64) + endif() + if(CPU STREQUAL arm64) + set(CMAKE_OSX_DEPLOYMENT_TARGET 11.0) + else() + set(CMAKE_OSX_DEPLOYMENT_TARGET 10.13) + endif() + + set(CMAKE_OSX_SYSROOT "@host_sysroot@") +endif() +set(CMAKE_SYSTEM_VERSION 1) + +# specify the cross compiler +set(CMAKE_C_COMPILER @CC_FOR_BUILD@) +set(CMAKE_CXX_COMPILER @CXX_FOR_BUILD@) +set(CMAKE_AR @AR_FOR_BUILD@ CACHE FILEPATH "Archiver") +SET(CMAKE_AS @AS_FOR_BUILD@ CACHE FILEPATH "Assembler") +set(CMAKE_LINKER @LD_FOR_BUILD@ CACHE FILEPATH "Linker") +set(CMAKE_NM @NM_FOR_BUILD@ CACHE FILEPATH "Nm") +set(CMAKE_STRIP @STRIP_FOR_BUILD@ CACHE PATH "strip binary" FORCE) +set(CMAKE_OBJDUMP @OBJDUMP_FOR_BUILD@ CACHE FILEPATH "Objdump") +set(CMAKE_RANLIB @RANLIB_FOR_BUILD@ CACHE FILEPATH "Ranlib") + +if(NOT "@use_ccache@" STREQUAL "") + set(CMAKE_CXX_COMPILER_LAUNCHER @CCACHE@) + set(CMAKE_C_COMPILER_LAUNCHER @CCACHE@) +endif() + +set(CMAKE_C_FLAGS "@host_includes@ -I@prefix@/@tool_dir@/include") +set(CMAKE_CXX_FLAGS "@host_cxxflags@ @host_includes@ -I@prefix@/@tool_dir@/include") +set(CMAKE_EXE_LINKER_FLAGS "@host_includes@ -L@prefix@/@tool_dir@/lib") + +# where is the target environment +set(CMAKE_FIND_ROOT_PATH @prefix@/@tool_dir@) +set(CMAKE_LIBRARY_PATH @prefix@/@tool_dir@/lib) +if(NOT "@use_toolchain@" STREQUAL "") + list(APPEND CMAKE_FIND_ROOT_PATH @use_toolchain@ @use_toolchain@/@use_host@ @use_toolchain@/@use_host@/sysroot @use_toolchain@/@use_host@/sysroot/usr @use_toolchain@/@use_host@/libc @use_toolchain@/lib/@use_host@/sysroot @use_toolchain@/usr @use_toolchain@/sysroot/usr) + set(CMAKE_LIBRARY_PATH "${CMAKE_LIBRARY_PATH}:@use_toolchain@/usr/lib/@use_host@:@use_toolchain@/lib/@use_host@") +endif() +if(NOT "@host_sysroot@" STREQUAL "") + list(APPEND CMAKE_FIND_ROOT_PATH @host_sysroot@ @host_sysroot@/usr) +endif() + +# search for programs in the build host directories +set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) +# for libraries and headers in the target directories +set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) +set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) +set(CMAKE_FIND_FRAMEWORK LAST) + +# common autoconf build tools +find_program(AUTOCONF autoconf HINTS "${NATIVEPREFIX}/bin" REQUIRED) +find_program(ACLOCAL aclocal HINTS "${NATIVEPREFIX}/bin" REQUIRED) +find_program(AUTOHEADER autoheader HINTS "${NATIVEPREFIX}/bin" REQUIRED) +find_program(AUTOMAKE automake HINTS "${NATIVEPREFIX}/bin" REQUIRED) +find_program(AUTOM4TE autom4te HINTS "${NATIVEPREFIX}/bin" REQUIRED) +find_program(AUTOPOINT autopoint HINTS "${NATIVEPREFIX}/bin" REQUIRED) +find_program(AUTORECONF autoreconf HINTS "${NATIVEPREFIX}/bin" REQUIRED) +find_program(LIBTOOL libtool HINTS "${NATIVEPREFIX}/bin" REQUIRED) +find_program(LIBTOOLIZE libtoolize HINTS "${NATIVEPREFIX}/bin" REQUIRED) + +set(ENV{ACLOCAL_PATH} "${NATIVEPREFIX}/share/aclocal") +set(ENV{PATH} "${NATIVEPREFIX}/bin:$ENV{PATH}") diff --git a/tools/depends/native/autoconf-archive/Makefile b/tools/depends/native/autoconf-archive/Makefile new file mode 100644 index 0000000..c1e599d --- /dev/null +++ b/tools/depends/native/autoconf-archive/Makefile @@ -0,0 +1,39 @@ +include ../../Makefile.include +PREFIX=$(NATIVEPREFIX) +PLATFORM=$(NATIVEPLATFORM) +DEPS = ../../Makefile.include Makefile ../../download-files.include + +# lib name, version +LIBNAME=autoconf-archive +VERSION=2021.02.19 +SOURCE=$(LIBNAME)-$(VERSION) +ARCHIVE=$(SOURCE).tar.xz +SHA512=a968c355c3cf66d74dc5b452141afbdf763e84a6c43b12c25da9a08482910d6d57ba3952aaf270d8cd5fd8b9d2dadf2d7d943ae2e1b067d68b71d2738d881aa0 +include ../../download-files.include + +# configuration settings +CONFIGURE=./configure --prefix=$(PREFIX) + +LIBDYLIB=$(PLATFORM)/bin/autoconf + +all: .installed-$(PLATFORM) + + +$(PLATFORM): $(DEPS) | $(TARBALLS_LOCATION)/$(ARCHIVE).$(HASH_TYPE) + -rm -rf $(PLATFORM)/*; mkdir -p $(PLATFORM) + cd $(PLATFORM); $(ARCHIVE_TOOL) $(ARCHIVE_TOOL_FLAGS) $(TARBALLS_LOCATION)/$(ARCHIVE) + +$(LIBDYLIB): $(PLATFORM) + cd $(PLATFORM); $(CONFIGURE) + $(MAKE) -C $(PLATFORM) + +.installed-$(PLATFORM): $(LIBDYLIB) + $(MAKE) -C $(PLATFORM) install + touch $@ + +clean: + $(MAKE) -C $(PLATFORM) clean + rm -f .installed-$(PLATFORM) + +distclean:: + rm -rf $(PLATFORM) .installed-$(PLATFORM) diff --git a/tools/depends/native/autoconf/Makefile b/tools/depends/native/autoconf/Makefile new file mode 100644 index 0000000..d0f08d8 --- /dev/null +++ b/tools/depends/native/autoconf/Makefile @@ -0,0 +1,40 @@ +include ../../Makefile.include +PREFIX=$(NATIVEPREFIX) +PLATFORM=$(NATIVEPLATFORM) +DEPS = ../../Makefile.include Makefile ../../download-files.include + +# lib name, version +LIBNAME=autoconf +VERSION=2.71 +SOURCE=$(LIBNAME)-$(VERSION) +ARCHIVE=$(SOURCE).tar.xz +SHA512=73d32b4adcbe24e3bafa9f43f59ed3b6efbd3de0f194e5ec90375f35da1199c583f5d3e89139b7edbad35171403709270e339ffa56a2ecb9b3123e9285021ff0 +include ../../download-files.include + +# configuration settings +CONFIGURE=./configure --prefix=$(PREFIX) + +LIBDYLIB=$(PLATFORM)/bin/autoconf + +all: .installed-$(PLATFORM) + + +$(PLATFORM): $(DEPS) | $(TARBALLS_LOCATION)/$(ARCHIVE).$(HASH_TYPE) + -rm -rf $(PLATFORM)/*; mkdir -p $(PLATFORM) + cd $(PLATFORM); $(ARCHIVE_TOOL) $(ARCHIVE_TOOL_FLAGS) $(TARBALLS_LOCATION)/$(ARCHIVE) + +$(LIBDYLIB): $(PLATFORM) + cd $(PLATFORM); $(CONFIGURE) + $(MAKE) -C $(PLATFORM) install +# patch autoreconf to not use gtkdocize. Details: https://savannah.gnu.org/support/?110503 + cd $(NATIVEPREFIX); sed -ie 's|$uses_gtkdoc = 1 if \$$macro eq "GTK_DOC_CHECK";|$uses_gtkdoc = 0; # if \$$macro eq "GTK_DOC_CHECK";|' bin/autoreconf + +.installed-$(PLATFORM): $(LIBDYLIB) + touch $@ + +clean: + $(MAKE) -C $(PLATFORM) clean + rm -f .installed-$(PLATFORM) + +distclean:: + rm -rf $(PLATFORM) .installed-$(PLATFORM) diff --git a/tools/depends/native/automake/01-fix-help2man-error.patch b/tools/depends/native/automake/01-fix-help2man-error.patch new file mode 100644 index 0000000..e05e429 --- /dev/null +++ b/tools/depends/native/automake/01-fix-help2man-error.patch @@ -0,0 +1,11 @@ +--- a/Makefile.in ++++ b/Makefile.in +@@ -703,7 +703,7 @@ + update_mans = \ + $(AM_V_GEN): \ + && $(MKDIR_P) doc \ +- && ./pre-inst-env $(PERL) $(srcdir)/doc/help2man --output=$@ ++ && ./pre-inst-env $(PERL) $(srcdir)/doc/help2man --output=$@ --no-discard-stderr + + checklinkx = $(top_srcdir)/contrib/checklinkx + # that 4-second sleep seems to be what gnu.org likes. diff --git a/tools/depends/native/automake/Makefile b/tools/depends/native/automake/Makefile new file mode 100644 index 0000000..5e33556 --- /dev/null +++ b/tools/depends/native/automake/Makefile @@ -0,0 +1,39 @@ +include ../../Makefile.include +PLATFORM=$(NATIVEPLATFORM) +DEPS = ../../Makefile.include Makefile 01-fix-help2man-error.patch ../../download-files.include + +# lib name, version +LIBNAME=automake +VERSION=1.16.5 +SOURCE=$(LIBNAME)-$(VERSION) +ARCHIVE=$(SOURCE).tar.xz +SHA512=3084ae543aa3fb5a05104ffb2e66cfa9a53080f2343c44809707fd648516869511500dba50dae67ff10f92a1bf3b5a92b2a0fa01cda30adb69b9da03994d9d88 +include ../../download-files.include + +# configuration settings +CONFIGURE=./configure --prefix=$(NATIVEPREFIX) + +LIBDYLIB=$(PLATFORM)/bin/automake + +all: .installed-$(PLATFORM) + + +$(PLATFORM): $(DEPS) | $(TARBALLS_LOCATION)/$(ARCHIVE).$(HASH_TYPE) + -rm -rf $(PLATFORM)/*; mkdir -p $(PLATFORM) + cd $(PLATFORM); $(ARCHIVE_TOOL) $(ARCHIVE_TOOL_FLAGS) $(TARBALLS_LOCATION)/$(ARCHIVE) + cd $(PLATFORM); patch -p1 -i ../01-fix-help2man-error.patch + cd $(PLATFORM); $(CONFIGURE) + +$(LIBDYLIB): $(PLATFORM) + $(MAKE) -C $(PLATFORM) + +.installed-$(PLATFORM): $(LIBDYLIB) + $(MAKE) -C $(PLATFORM) install + touch $@ + +clean: + $(MAKE) -C $(PLATFORM) clean + rm -f .installed-$(PLATFORM) + +distclean:: + rm -rf $(PLATFORM) .installed-$(PLATFORM) diff --git a/tools/depends/native/cmake/Makefile b/tools/depends/native/cmake/Makefile new file mode 100644 index 0000000..1a4dc3e --- /dev/null +++ b/tools/depends/native/cmake/Makefile @@ -0,0 +1,50 @@ +include ../../Makefile.include +PLATFORM=$(NATIVEPLATFORM) +DEPS = ../../Makefile.include Makefile ../../download-files.include + +APPNAME=cmake +VERSION=3.21.3 +SOURCE=$(APPNAME)-$(VERSION) +ARCHIVE=$(SOURCE).tar.gz +SHA512=0571b78443906c5ad51fb0fafbd32d565caf628cc150b1190802cb819e8497c108ea6b7ecaa03133df2dbbceb730696d24b4df38468c92088c769ce4076d9e9f +include ../../download-files.include + +# configuration settings + +SETENV=CC="$(CC_FOR_BUILD)" CXX="$(CXX_FOR_BUILD)" LD=$(LD_FOR_BUILD) CFLAGS="$(NATIVE_CFLAGS)" \ + CXXFLAGS="$(NATIVE_CXXFLAGS)" LDFLAGS="$(NATIVE_LDFLAGS)" + +ifeq ($(NATIVE_OS), osx) + SETENV+=SDKROOT=$(shell xcrun --show-sdk-path) +endif + +CONFIGURE=./bootstrap --prefix=$(NATIVEPREFIX) --system-curl +ifeq ($(USE_CCACHE), yes) + CONFIGURE+=--enable-ccache +endif + +APP=$(PLATFORM)/bin/$(APPNAME) + +all: .installed-$(PLATFORM) + + +$(PLATFORM): $(DEPS) | $(TARBALLS_LOCATION)/$(ARCHIVE).$(HASH_TYPE) + -rm -rf $(PLATFORM)/*; mkdir -p $(PLATFORM) + cd $(PLATFORM); $(ARCHIVE_TOOL) $(ARCHIVE_TOOL_FLAGS) $(TARBALLS_LOCATION)/$(ARCHIVE) + cd $(PLATFORM); $(SETENV) $(CONFIGURE) + +$(APP): $(PLATFORM) + $(MAKE) -C $(PLATFORM) + touch $@ + +.installed-$(PLATFORM): $(APP) + $(MAKE) -C $(PLATFORM) install + touch $@ + +clean: + $(MAKE) -C $(PLATFORM) clean + rm -f .installed-$(PLATFORM) + +distclean:: + rm -rf $(PLATFORM) .installed-$(PLATFORM) + diff --git a/tools/depends/native/config.site.native.in b/tools/depends/native/config.site.native.in new file mode 100644 index 0000000..35171a7 --- /dev/null +++ b/tools/depends/native/config.site.native.in @@ -0,0 +1,26 @@ +LD="${LD:-@LD_FOR_BUILD@}" +CC="${CC:-@CCACHE@ @CC_FOR_BUILD@}" +CXX="${CXX:-@CCACHE@ @CXX_FOR_BUILD@}" +AR="${AR:-@AR_FOR_BUILD@}" +RANLIB="${RANLIB:-@RANLIB_FOR_BUILD@}" +AS="${AS:-@AS_FOR_BUILD@}" +NM="${NM:-@NM_FOR_BUILD@}" +STRIP="${STRIP:-@STRIP_FOR_BUILD@}" +READELF="${READELF:-@READELF_FOR_BUILD@}" +OBJDUMP="${OBJDUMP:-@OBJDUMP_FOR_BUILD@}" + +CFLAGS="@host_includes@ -I@prefix@/@tool_dir@/include $CFLAGS" +LDFLAGS="@host_includes@ -L@prefix@/@tool_dir@/lib $LDFLAGS" +CPPFLAGS="@host_includes@ -I@prefix@/@tool_dir@/include $CPPFLAGS" +CXXFLAGS="@host_includes@ -I@prefix@/@tool_dir@/include $CXXFLAGS" + +PKG_CONFIG=@prefix@/@tool_dir@/bin/pkg-config +export PKG_CONFIG_LIBDIR=@prefix@/@tool_dir@/lib/pkgconfig + +PATH=@prefix@/@tool_dir@/bin:$PATH +if test -n "@use_build_toolchain@"; then + PATH=@use_build_toolchain@/usr/bin:@use_build_toolchain@/bin:$PATH +fi + +LD_LIBRARY_PATH=@prefix@/@tool_dir@/lib:$LD_LIBRARY_PATH +NASM=@prefix@/@tool_dir@/bin/nasm diff --git a/tools/depends/native/dpkg/01-no-gnu-patch.patch b/tools/depends/native/dpkg/01-no-gnu-patch.patch new file mode 100644 index 0000000..7536983 --- /dev/null +++ b/tools/depends/native/dpkg/01-no-gnu-patch.patch @@ -0,0 +1,10 @@ +--- a/configure.ac ++++ b/configure.ac +@@ -74,7 +74,6 @@ + DPKG_C_C99 + AC_PROG_CXX + DPKG_CXX_CXX11 +-DPKG_PROG_PATCH + AC_CHECK_PROGS([DOXYGEN], [doxygen]) + AC_CHECK_PROG([HAVE_DOT], [dot], [YES], [NO]) + DPKG_PROG_PO4A diff --git a/tools/depends/native/dpkg/02-perl-min-version.patch b/tools/depends/native/dpkg/02-perl-min-version.patch new file mode 100644 index 0000000..4fb60ef --- /dev/null +++ b/tools/depends/native/dpkg/02-perl-min-version.patch @@ -0,0 +1,11 @@ +--- a/m4/dpkg-progs.m4 ++++ b/m4/dpkg-progs.m4 +@@ -7,7 +7,7 @@ + # Locate perl interpreter in the path + AC_DEFUN([DPKG_PROG_PERL], [ + AC_ARG_VAR([PERL], [Perl interpreter])dnl +- m4_define([_PERL_MIN_VERSION], [5.20.2]) ++ m4_define([_PERL_MIN_VERSION], [5.18.2]) + AC_SUBST([PERL_MIN_VERSION], [_PERL_MIN_VERSION]) + AC_CACHE_CHECK([for perl >= _PERL_MIN_VERSION], [ac_cv_path_PERL], [ + AC_PATH_PROGS_FEATURE_CHECK([PERL], [perl], [ diff --git a/tools/depends/native/dpkg/03-lzma-compression.patch b/tools/depends/native/dpkg/03-lzma-compression.patch new file mode 100644 index 0000000..c9bf535 --- /dev/null +++ b/tools/depends/native/dpkg/03-lzma-compression.patch @@ -0,0 +1,11 @@ +--- a/dpkg-deb/main.c ++++ b/dpkg-deb/main.c +@@ -195,7 +195,7 @@ + if (compress_params.type == COMPRESSOR_TYPE_UNKNOWN) + badusage(_("unknown compression type '%s'!"), value); + if (compress_params.type == COMPRESSOR_TYPE_LZMA) +- badusage(_("obsolete compression type '%s'; use xz instead"), value); ++ warning(_("obsolete compression type '%s'; use xz instead"), value); + if (compress_params.type == COMPRESSOR_TYPE_BZIP2) + badusage(_("obsolete compression type '%s'; use xz or gzip instead"), value); + } diff --git a/tools/depends/native/dpkg/Makefile b/tools/depends/native/dpkg/Makefile new file mode 100644 index 0000000..08b94ca --- /dev/null +++ b/tools/depends/native/dpkg/Makefile @@ -0,0 +1,45 @@ +include ../../Makefile.include +PREFIX=$(NATIVEPREFIX) +PLATFORM=$(NATIVEPLATFORM) +DEPS = ../../Makefile.include Makefile 01-no-gnu-patch.patch 02-perl-min-version.patch 03-lzma-compression.patch ../../download-files.include + +# lib name, version +LIBNAME=dpkg +VERSION=1.19.7 +SOURCE=$(LIBNAME)_$(VERSION) +ARCHIVE=$(SOURCE).tar.xz +SHA512=9ca441dc265baf5359c71617aef1c57504a7097c26ea57108b88dadc511bfa9918fcc765d8c67cec9def9916c5df92d6cabe508446dbc7223a29b45260445e81 +include ../../download-files.include + +# configuration settings +CONFIGURE=./configure --prefix=$(PREFIX) --enable-static --disable-shared --disable-devel-docs \ + --disable-linker-optimizations --disable-nls --disable-dselect --disable-start-stop-daemon \ + ac_cv_header_libintl_h=no + +LIBDYLIB=$(PLATFORM)/dpkg-deb/dpkg-deb + +all: .installed-$(PLATFORM) + + +$(PLATFORM): $(DEPS) | $(TARBALLS_LOCATION)/$(ARCHIVE).$(HASH_TYPE) + rm -rf $(PLATFORM)/*; mkdir -p $(PLATFORM) + cd $(PLATFORM); $(ARCHIVE_TOOL) $(ARCHIVE_TOOL_FLAGS) $(TARBALLS_LOCATION)/$(ARCHIVE) + cd $(PLATFORM); patch -p1 -i ../01-no-gnu-patch.patch + cd $(PLATFORM); patch -p1 -i ../02-perl-min-version.patch + cd $(PLATFORM); patch -p1 -i ../03-lzma-compression.patch + cd $(PLATFORM); $(AUTORECONF) -vif + cd $(PLATFORM); $(CONFIGURE) + +$(LIBDYLIB): $(PLATFORM) + $(MAKE) -C $(PLATFORM) + +.installed-$(PLATFORM): $(LIBDYLIB) + $(MAKE) -C $(PLATFORM)/dpkg-deb install + touch $@ + +clean: + $(MAKE) -C $(PLATFORM) clean + rm -f .installed-$(PLATFORM) + +distclean:: + rm -rf $(PLATFORM) .installed-$(PLATFORM) diff --git a/tools/depends/native/expat/EXPAT-VERSION b/tools/depends/native/expat/EXPAT-VERSION new file mode 100644 index 0000000..ea1b164 --- /dev/null +++ b/tools/depends/native/expat/EXPAT-VERSION @@ -0,0 +1,5 @@ +LIBNAME=expat +VERSION=2.4.9 +SOURCE=$(LIBNAME)-$(VERSION) +ARCHIVE=$(SOURCE).tar.xz +SHA512=8508379b4915d84d50f3638678a90792179c98247d1cb5e6e6387d117af4dc148ac7031c1debea8b96e7b710ef436cf0dd5da91f3d22b8186a00cfafe1201169 diff --git a/tools/depends/native/expat/Makefile b/tools/depends/native/expat/Makefile new file mode 100644 index 0000000..0a0b484 --- /dev/null +++ b/tools/depends/native/expat/Makefile @@ -0,0 +1,31 @@ +include ../../Makefile.include EXPAT-VERSION ../../download-files.include +PREFIX=$(NATIVEPREFIX) +PLATFORM=$(NATIVEPLATFORM) +DEPS=../../Makefile.include Makefile EXPAT-VERSION ../../download-files.include + +# configuration settings +CONFIGURE=cp -f $(CONFIG_SUB) $(CONFIG_GUESS) ./conftools; CFLAGS="-fPIC" ./configure --prefix=$(PREFIX) --disable-shared + +LIBDYLIB=$(PLATFORM)/lib/.libs/lib$(LIBNAME).a + +all: .installed-$(PLATFORM) + + +$(PLATFORM): $(DEPS) | $(TARBALLS_LOCATION)/$(ARCHIVE).$(HASH_TYPE) + rm -rf $(PLATFORM)/*; mkdir -p $(PLATFORM) + cd $(PLATFORM); $(ARCHIVE_TOOL) $(ARCHIVE_TOOL_FLAGS) $(TARBALLS_LOCATION)/$(ARCHIVE) + cd $(PLATFORM); $(CONFIGURE) + +$(LIBDYLIB): $(PLATFORM) + $(MAKE) -C $(PLATFORM) + +.installed-$(PLATFORM): $(LIBDYLIB) + $(MAKE) -C $(PLATFORM) install + touch $@ + +clean: + $(MAKE) -C $(PLATFORM) clean + rm -f .installed-$(PLATFORM) + +distclean:: + rm -rf $(PLATFORM) .installed-$(PLATFORM) diff --git a/tools/depends/native/flatbuffers/Makefile b/tools/depends/native/flatbuffers/Makefile new file mode 100644 index 0000000..6911d4c --- /dev/null +++ b/tools/depends/native/flatbuffers/Makefile @@ -0,0 +1,68 @@ +include ../../Makefile.include +PREFIX=$(NATIVEPREFIX) +PLATFORM=$(NATIVEPLATFORM) +DEPS =../../Makefile.include Makefile ../../download-files.include + +# lib name, version +LIBNAME=flatbuffers +VERSION=2.0.0 +SOURCE=$(LIBNAME)-$(VERSION) +ARCHIVE=$(SOURCE).tar.gz +SHA512=26a06b572c0e4c9685743bd2d2162ac7dcd74b9324624cc3f3ef5b154c0cee7c52a04b77cdc184245d2d6ae38dfdcc4fd66001c318aa8ca001d2bf1d85d66a89 +include ../../download-files.include + +APP=$(PLATFORM)/build-cmake/flatc + +# BUILD Notes +# When we go c++17, flatbuffers has FLATBUFFERS_BUILD_CPP17 to enable +# If we bump cmake min req to 3.16, enable FLATBUFFERS_ENABLE_PCH + +ifeq ($(USE_CCACHE), yes) + LAUNCHER=-DCMAKE_CXX_COMPILER_LAUNCHER=$(CCACHE) +endif + +# Only this package uses CMake for build on native at the moment, +# so there is no separate toolchain file. Still we have to unset +# the CMAKE_TOOLCHAIN_FILE, which is part of $(CMAKE) and set to +# the target toolchain file. +CMAKE_OPTIONS := -DCMAKE_TOOLCHAIN_FILE= \ + -DCMAKE_BUILD_TYPE=Release \ + -DFLATBUFFERS_CODE_COVERAGE=OFF \ + -DFLATBUFFERS_BUILD_TESTS=OFF \ + -DFLATBUFFERS_INSTALL=ON \ + -DFLATBUFFERS_BUILD_FLATLIB=OFF \ + -DFLATBUFFERS_BUILD_FLATC=ON \ + -DFLATBUFFERS_BUILD_FLATHASH=OFF \ + -DFLATBUFFERS_BUILD_GRPCTEST=OFF \ + -DFLATBUFFERS_BUILD_SHAREDLIB=OFF \ + -DCMAKE_C_COMPILER="$(CC_BINARY_FOR_BUILD)" \ + -DCMAKE_CXX_COMPILER="$(CXX_BINARY_FOR_BUILD)" \ + $(LAUNCHER) \ + -DCMAKE_C_FLAGS="$(NATIVE_CFLAGS)" \ + -DCMAKE_CXX_FLAGS="$(NATIVE_CXXFLAGS)" \ + -DCMAKE_EXE_LINKER_FLAGS="$(NATIVE_LDFLAGS)" \ + $(CMAKE_OPTIONS) +BUILDDIR = $(PLATFORM)/build-cmake # 'build' conflicts with file BUILD on case-insensitive FS + +all: .installed-$(PLATFORM) + + +$(PLATFORM): $(DEPS) | $(TARBALLS_LOCATION)/$(ARCHIVE).$(HASH_TYPE) + rm -rf $(PLATFORM)/*; mkdir -p $(PLATFORM) + cd $(PLATFORM); $(ARCHIVE_TOOL) $(ARCHIVE_TOOL_FLAGS) $(TARBALLS_LOCATION)/$(ARCHIVE) + mkdir -p $(BUILDDIR) + cd $(BUILDDIR); $(CMAKE) $(CMAKE_OPTIONS) .. + +$(APP): $(PLATFORM) + $(MAKE) -C $(BUILDDIR) + +.installed-$(PLATFORM): $(APP) + $(MAKE) -C $(BUILDDIR) install + touch $@ + +clean: + $(MAKE) -C $(BUILDDIR) clean + rm -f .installed-$(PLATFORM) + +distclean: + rm -rf $(PLATFORM) .installed-$(PLATFORM) diff --git a/tools/depends/native/gas-preprocessor/Makefile b/tools/depends/native/gas-preprocessor/Makefile new file mode 100644 index 0000000..d257890 --- /dev/null +++ b/tools/depends/native/gas-preprocessor/Makefile @@ -0,0 +1,13 @@ +include ../../Makefile.include + +GASBIN=$(NATIVEPREFIX)/bin/gas-preprocessor.pl + +all: $(GASBIN) + +$(GASBIN): + mkdir -p $(NATIVEPREFIX)/bin + cp gas-preprocessor.pl $(GASBIN) + +clean: +distclean:: + rm -f $(GASBIN) diff --git a/tools/depends/native/gas-preprocessor/README b/tools/depends/native/gas-preprocessor/README new file mode 100644 index 0000000..2c8ab2b --- /dev/null +++ b/tools/depends/native/gas-preprocessor/README @@ -0,0 +1,13 @@ +To configure Libav for iOS: + +./configure --enable-cross-compile --arch=arm --target-os=darwin --cc='clang -arch armv7' --sysroot=$(xcrun --sdk iphoneos --show-sdk-path) --cpu=cortex-a8 --enable-pic + +If deploying to all generations, it's recommended to do separate out-of-tree +builds for each architecture, then lipo together the resulting libs. For +instance, assuming separate builds in armv6 and armv7: + +lipo -create -arch armv6 armv6/libavcodec/libavcodec.a -arch armv7 armv7/libavcodec/libavcodec.a -output universal/libavcodec.a + +and similar for each library. Then in XCode, make sure to build for both armv6 +and armv7. If you only care about one generation (since the armv6 devices are +too slow for instance), then lipo is unnecessary of course. diff --git a/tools/depends/native/gas-preprocessor/VERSION b/tools/depends/native/gas-preprocessor/VERSION new file mode 100644 index 0000000..90992e4 --- /dev/null +++ b/tools/depends/native/gas-preprocessor/VERSION @@ -0,0 +1,4 @@ +LIBNAME=gas-preprocessor +BASE_URL=https://github.com/libav/gas-preprocessor +COMMIT=d09971fad329d32df19f5bbafe88cf2f0ed04ed7 +COMMIT_DATE=2019/10/04 diff --git a/tools/depends/native/gas-preprocessor/gas-preprocessor.pl b/tools/depends/native/gas-preprocessor/gas-preprocessor.pl new file mode 100755 index 0000000..9cc8b2c --- /dev/null +++ b/tools/depends/native/gas-preprocessor/gas-preprocessor.pl @@ -0,0 +1,1213 @@ +#!/usr/bin/env perl +# by David Conrad +# This code is licensed under GPLv2 or later; go to gnu.org to read it +# (not that it much matters for an asm preprocessor) +# usage: set your assembler to be something like "perl gas-preprocessor.pl gcc" +use strict; + +# Apple's gas is ancient and doesn't support modern preprocessing features like +# .rept and has ugly macro syntax, among other things. Thus, this script +# implements the subset of the gas preprocessor used by x264 and ffmpeg +# that isn't supported by Apple's gas. + +my %canonical_arch = ("aarch64" => "aarch64", "arm64" => "aarch64", + "arm" => "arm", + "powerpc" => "powerpc", "ppc" => "powerpc"); + +my %comments = ("aarch64" => '//', + "arm" => '@', + "powerpc" => '#'); + +my @gcc_cmd; +my @preprocess_c_cmd; + +my $comm; +my $arch; +my $as_type = "apple-gas"; + +my $fix_unreq = $^O eq "darwin"; +my $force_thumb = 0; +my $verbose = 0; + +my $arm_cond_codes = "eq|ne|cs|cc|mi|pl|vs|vc|hi|ls|ge|lt|gt|le|al|hs|lo"; + +my $usage_str = " +$0\n +Gas-preprocessor.pl converts assembler files using modern GNU as syntax for +Apple's ancient gas version or clang's incompatible integrated assembler. The +conversion is regularly tested for Libav, x264 and vlc. Other projects might +use different features which are not correctly handled. +Options for this program needs to be separated with ' -- ' from the assembler +command. Following options are currently supported: + -help - this usage text + -arch - target architecture + -as-type - one value out of {{,apple-}{gas,clang},armasm} + -fix-unreq + -no-fix-unreq + -force-thumb - assemble as thumb regardless of the input source + (note, this is incomplete and only works for sources + it explicitly was tested with) + -verbose - print executed commands +"; + +sub usage() { + print $usage_str; +} + +while (@ARGV) { + my $opt = shift; + + if ($opt =~ /^-(no-)?fix-unreq$/) { + $fix_unreq = $1 ne "no-"; + } elsif ($opt eq "-force-thumb") { + $force_thumb = 1; + } elsif ($opt eq "-verbose") { + $verbose = 1; + } elsif ($opt eq "-arch") { + $arch = shift; + die "unknown arch: '$arch'\n" if not exists $canonical_arch{$arch}; + } elsif ($opt eq "-as-type") { + $as_type = shift; + die "unknown as type: '$as_type'\n" if $as_type !~ /^((apple-)?(gas|clang)|armasm)$/; + } elsif ($opt eq "-help") { + usage(); + exit 0; + } elsif ($opt eq "--" ) { + @gcc_cmd = @ARGV; + } elsif ($opt =~ /^-/) { + die "option '$opt' is not known. See '$0 -help' for usage information\n"; + } else { + push @gcc_cmd, $opt, @ARGV; + } + last if (@gcc_cmd); +} + +if (grep /\.c$/, @gcc_cmd) { + # C file (inline asm?) - compile + @preprocess_c_cmd = (@gcc_cmd, "-S"); +} elsif (grep /\.[sS]$/, @gcc_cmd) { + # asm file, just do C preprocessor + @preprocess_c_cmd = (@gcc_cmd, "-E"); +} elsif (grep /-(v|h|-version|dumpversion)/, @gcc_cmd) { + # pass -v/--version along, used during probing. Matching '-v' might have + # uninteded results but it doesn't matter much if gas-preprocessor or + # the compiler fails. + print STDERR join(" ", @gcc_cmd)."\n" if $verbose; + exec(@gcc_cmd); +} else { + die "Unrecognized input filetype"; +} +if ($as_type eq "armasm") { + + $preprocess_c_cmd[0] = "cpp"; + push(@preprocess_c_cmd, "-undef"); + # Normally a preprocessor for windows would predefine _WIN32, + # but we're using any generic system-agnostic preprocessor "cpp" + # with -undef (to avoid getting predefined variables from the host + # system in cross compilation cases), so manually define it here. + push(@preprocess_c_cmd, "-D_WIN32"); + + @preprocess_c_cmd = grep ! /^-nologo$/, @preprocess_c_cmd; + # Remove -ignore XX parameter pairs from preprocess_c_cmd + my $index = 1; + while ($index < $#preprocess_c_cmd) { + if ($preprocess_c_cmd[$index] eq "-ignore" and $index + 1 < $#preprocess_c_cmd) { + splice(@preprocess_c_cmd, $index, 2); + next; + } + $index++; + } + if (grep /^-MM$/, @preprocess_c_cmd) { + print STDERR join(" ", @preprocess_c_cmd)."\n" if $verbose; + system(@preprocess_c_cmd) == 0 or die "Error running preprocessor"; + exit 0; + } +} + +# if compiling, avoid creating an output file named '-.o' +if ((grep /^-c$/, @gcc_cmd) && !(grep /^-o/, @gcc_cmd)) { + foreach my $i (@gcc_cmd) { + if ($i =~ /\.[csS]$/) { + my $outputfile = $i; + $outputfile =~ s/\.[csS]$/.o/; + push(@gcc_cmd, "-o"); + push(@gcc_cmd, $outputfile); + last; + } + } +} +# replace only the '-o' argument with '-', avoids rewriting the make dependency +# target specified with -MT to '-' +my $index = 1; +while ($index < $#preprocess_c_cmd) { + if ($preprocess_c_cmd[$index] eq "-o") { + $index++; + $preprocess_c_cmd[$index] = "-"; + } + $index++; +} + +my $tempfile; +if ($as_type ne "armasm") { + @gcc_cmd = map { /\.[csS]$/ ? qw(-x assembler -) : $_ } @gcc_cmd; +} else { + @preprocess_c_cmd = grep ! /^-c$/, @preprocess_c_cmd; + @preprocess_c_cmd = grep ! /^-m/, @preprocess_c_cmd; + + @preprocess_c_cmd = grep ! /^-G/, @preprocess_c_cmd; + @preprocess_c_cmd = grep ! /^-W/, @preprocess_c_cmd; + @preprocess_c_cmd = grep ! /^-Z/, @preprocess_c_cmd; + @preprocess_c_cmd = grep ! /^-fp/, @preprocess_c_cmd; + @preprocess_c_cmd = grep ! /^-EHsc$/, @preprocess_c_cmd; + @preprocess_c_cmd = grep ! /^-O/, @preprocess_c_cmd; + @preprocess_c_cmd = grep ! /^-oldit/, @preprocess_c_cmd; + + @gcc_cmd = grep ! /^-G/, @gcc_cmd; + @gcc_cmd = grep ! /^-W/, @gcc_cmd; + @gcc_cmd = grep ! /^-Z/, @gcc_cmd; + @gcc_cmd = grep ! /^-fp/, @gcc_cmd; + @gcc_cmd = grep ! /^-EHsc$/, @gcc_cmd; + @gcc_cmd = grep ! /^-O/, @gcc_cmd; + + my @outfiles = grep /\.(o|obj)$/, @gcc_cmd; + $tempfile = $outfiles[0].".asm"; + + # Remove most parameters from gcc_cmd, which actually is the armasm command, + # which doesn't support any of the common compiler/preprocessor options. + @gcc_cmd = grep ! /^-D/, @gcc_cmd; + @gcc_cmd = grep ! /^-U/, @gcc_cmd; + @gcc_cmd = grep ! /^-m/, @gcc_cmd; + @gcc_cmd = grep ! /^-M/, @gcc_cmd; + @gcc_cmd = grep ! /^-c$/, @gcc_cmd; + @gcc_cmd = grep ! /^-I/, @gcc_cmd; + @gcc_cmd = map { /\.S$/ ? $tempfile : $_ } @gcc_cmd; +} + +# detect architecture from gcc binary name +if (!$arch) { + if ($gcc_cmd[0] =~ /(arm64|aarch64|arm|powerpc|ppc)/) { + $arch = $1; + } else { + # look for -arch flag + foreach my $i (1 .. $#gcc_cmd-1) { + if ($gcc_cmd[$i] eq "-arch" and + $gcc_cmd[$i+1] =~ /(arm64|aarch64|arm|powerpc|ppc)/) { + $arch = $1; + } + } + } +} + +# assume we're not cross-compiling if no -arch or the binary doesn't have the arch name +$arch = qx/arch/ if (!$arch); + +die "Unknown target architecture '$arch'" if not exists $canonical_arch{$arch}; + +$arch = $canonical_arch{$arch}; +$comm = $comments{$arch}; +my $inputcomm = $comm; +$comm = ";" if $as_type =~ /armasm/; + +my %ppc_spr = (ctr => 9, + vrsave => 256); + +print STDERR join(" ", @preprocess_c_cmd)."\n" if $verbose; +open(INPUT, "-|", @preprocess_c_cmd) || die "Error running preprocessor"; + +if ($ENV{GASPP_DEBUG}) { + open(ASMFILE, ">&STDOUT"); +} else { + if ($as_type ne "armasm") { + print STDERR join(" ", @gcc_cmd)."\n" if $verbose; + open(ASMFILE, "|-", @gcc_cmd) or die "Error running assembler"; + } else { + open(ASMFILE, ">", $tempfile); + } +} + +my $current_macro = ''; +my $macro_level = 0; +my $rept_level = 0; +my %macro_lines; +my %macro_args; +my %macro_args_default; +my $macro_count = 0; +my $altmacro = 0; +my $in_irp = 0; + +my $num_repts; +my @rept_lines; + +my @irp_args; +my $irp_param; + +my @ifstack; + +my %symbols; + +my @sections; + +my %literal_labels; # for ldr <reg>, =<expr> +my $literal_num = 0; +my $literal_expr = ".word"; +$literal_expr = ".quad" if $arch eq "aarch64"; + +my $thumb = 0; + +my %thumb_labels; +my %call_targets; +my %import_symbols; + +my %neon_alias_reg; +my %neon_alias_type; + +my $temp_label_next = 0; +my %last_temp_labels; +my %next_temp_labels; + +my %labels_seen; + +my %aarch64_req_alias; + +if ($force_thumb) { + parse_line(".thumb\n"); +} + +# pass 1: parse .macro +# note that the handling of arguments is probably overly permissive vs. gas +# but it should be the same for valid cases +while (<INPUT>) { + # remove lines starting with '#', preprocessing is done, '#' at start of + # the line indicates a comment for all supported archs (aarch64, arm, ppc + # and x86). Also strips line number comments but since they are off anyway + # it is no loss. + s/^\s*#.*$//; + # remove all comments (to avoid interfering with evaluating directives) + s/(?<!\\)$inputcomm.*//x; + # Strip out windows linefeeds + s/\r$//; + + foreach my $subline (split(";", $_)) { + # Add newlines at the end of lines that don't already have one + chomp $subline; + $subline .= "\n"; + parse_line($subline); + } +} + +sub eval_expr { + my $expr = $_[0]; + while ($expr =~ /([A-Za-z._][A-Za-z0-9._]*)/g) { + my $sym = $1; + $expr =~ s/$sym/($symbols{$sym})/ if defined $symbols{$sym}; + } + eval $expr; +} + +sub handle_if { + my $line = $_[0]; + # handle .if directives; apple's assembler doesn't support important non-basic ones + # evaluating them is also needed to handle recursive macros + if ($line =~ /\.if(n?)([a-z]*)\s+(.*)/) { + my $result = $1 eq "n"; + my $type = $2; + my $expr = $3; + + if ($type eq "b") { + $expr =~ s/\s//g; + $result ^= $expr eq ""; + } elsif ($type eq "c") { + if ($expr =~ /(.*)\s*,\s*(.*)/) { + $result ^= $1 eq $2; + } else { + die "argument to .ifc not recognized"; + } + } elsif ($type eq "") { + $result ^= eval_expr($expr) != 0; + } elsif ($type eq "eq") { + $result = eval_expr($expr) == 0; + } elsif ($type eq "lt") { + $result = eval_expr($expr) < 0; + } else { + chomp($line); + die "unhandled .if varient. \"$line\""; + } + push (@ifstack, $result); + return 1; + } else { + return 0; + } +} + +sub parse_if_line { + my $line = $_[0]; + + # evaluate .if blocks + if (scalar(@ifstack)) { + # Don't evaluate any new if statements if we're within + # a repetition or macro - they will be evaluated once + # the repetition is unrolled or the macro is expanded. + if (scalar(@rept_lines) == 0 and $macro_level == 0) { + if ($line =~ /\.endif/) { + pop(@ifstack); + return 1; + } elsif ($line =~ /\.elseif\s+(.*)/) { + if ($ifstack[-1] == 0) { + $ifstack[-1] = !!eval_expr($1); + } elsif ($ifstack[-1] > 0) { + $ifstack[-1] = -$ifstack[-1]; + } + return 1; + } elsif ($line =~ /\.else/) { + $ifstack[-1] = !$ifstack[-1]; + return 1; + } elsif (handle_if($line)) { + return 1; + } + } + + # discard lines in false .if blocks + foreach my $i (0 .. $#ifstack) { + if ($ifstack[$i] <= 0) { + return 1; + } + } + } + return 0; +} + +sub parse_line { + my $line = $_[0]; + + return if (parse_if_line($line)); + + if (scalar(@rept_lines) == 0) { + if ($line =~ /\.macro/) { + $macro_level++; + if ($macro_level > 1 && !$current_macro) { + die "nested macros but we don't have master macro"; + } + } elsif ($line =~ /\.endm/) { + $macro_level--; + if ($macro_level < 0) { + die "unmatched .endm"; + } elsif ($macro_level == 0) { + $current_macro = ''; + return; + } + } + } + + if ($macro_level == 0) { + if ($line =~ /\.(rept|irp)/) { + $rept_level++; + } elsif ($line =~ /.endr/) { + $rept_level--; + } + } + + if ($macro_level > 1) { + push(@{$macro_lines{$current_macro}}, $line); + } elsif (scalar(@rept_lines) and $rept_level >= 1) { + push(@rept_lines, $line); + } elsif ($macro_level == 0) { + expand_macros($line); + } else { + if ($line =~ /\.macro\s+([\d\w\.]+)\s*,?\s*(.*)/) { + $current_macro = $1; + + # commas in the argument list are optional, so only use whitespace as the separator + my $arglist = $2; + $arglist =~ s/,/ /g; + + my @args = split(/\s+/, $arglist); + foreach my $i (0 .. $#args) { + my @argpair = split(/=/, $args[$i]); + $macro_args{$current_macro}[$i] = $argpair[0]; + $argpair[0] =~ s/:vararg$//; + $macro_args_default{$current_macro}{$argpair[0]} = $argpair[1]; + } + # ensure %macro_lines has the macro name added as a key + $macro_lines{$current_macro} = []; + + } elsif ($current_macro) { + push(@{$macro_lines{$current_macro}}, $line); + } else { + die "macro level without a macro name"; + } + } +} + +sub handle_set { + my $line = $_[0]; + if ($line =~ /\.(?:set|equ)\s+(\S*)\s*,\s*(.*)/) { + $symbols{$1} = eval_expr($2); + return 1; + } + return 0; +} + +sub expand_macros { + my $line = $_[0]; + + # handle .if directives; apple's assembler doesn't support important non-basic ones + # evaluating them is also needed to handle recursive macros + if (handle_if($line)) { + return; + } + + if (/\.purgem\s+([\d\w\.]+)/) { + delete $macro_lines{$1}; + delete $macro_args{$1}; + delete $macro_args_default{$1}; + return; + } + + if ($line =~ /\.altmacro/) { + $altmacro = 1; + return; + } + + if ($line =~ /\.noaltmacro/) { + $altmacro = 0; + return; + } + + $line =~ s/\%([^,]*)/eval_expr($1)/eg if $altmacro; + + # Strip out the .set lines from the armasm output + return if (handle_set($line) and $as_type eq "armasm"); + + if ($line =~ /\.rept\s+(.*)/) { + $num_repts = $1; + @rept_lines = ("\n"); + + # handle the possibility of repeating another directive on the same line + # .endr on the same line is not valid, I don't know if a non-directive is + if ($num_repts =~ s/(\.\w+.*)//) { + push(@rept_lines, "$1\n"); + } + $num_repts = eval_expr($num_repts); + } elsif ($line =~ /\.irp\s+([\d\w\.]+)\s*(.*)/) { + $in_irp = 1; + $num_repts = 1; + @rept_lines = ("\n"); + $irp_param = $1; + + # only use whitespace as the separator + my $irp_arglist = $2; + $irp_arglist =~ s/,/ /g; + $irp_arglist =~ s/^\s+//; + @irp_args = split(/\s+/, $irp_arglist); + } elsif ($line =~ /\.irpc\s+([\d\w\.]+)\s*(.*)/) { + $in_irp = 1; + $num_repts = 1; + @rept_lines = ("\n"); + $irp_param = $1; + + my $irp_arglist = $2; + $irp_arglist =~ s/,/ /g; + $irp_arglist =~ s/^\s+//; + @irp_args = split(//, $irp_arglist); + } elsif ($line =~ /\.endr/) { + my @prev_rept_lines = @rept_lines; + my $prev_in_irp = $in_irp; + my @prev_irp_args = @irp_args; + my $prev_irp_param = $irp_param; + my $prev_num_repts = $num_repts; + @rept_lines = (); + $in_irp = 0; + @irp_args = ''; + + if ($prev_in_irp != 0) { + foreach my $i (@prev_irp_args) { + foreach my $origline (@prev_rept_lines) { + my $line = $origline; + $line =~ s/\\$prev_irp_param/$i/g; + $line =~ s/\\\(\)//g; # remove \() + parse_line($line); + } + } + } else { + for (1 .. $prev_num_repts) { + foreach my $origline (@prev_rept_lines) { + my $line = $origline; + parse_line($line); + } + } + } + } elsif ($line =~ /(\S+:|)\s*([\w\d\.]+)\s*(.*)/ && exists $macro_lines{$2}) { + handle_serialized_line($1); + my $macro = $2; + + # commas are optional here too, but are syntactically important because + # parameters can be blank + my @arglist = split(/,/, $3); + my @args; + my @args_seperator; + + my $comma_sep_required = 0; + foreach (@arglist) { + # allow arithmetic/shift operators in macro arguments + $_ =~ s/\s*(\+|-|\*|\/|<<|>>|<|>)\s*/$1/g; + + my @whitespace_split = split(/\s+/, $_); + if (!@whitespace_split) { + push(@args, ''); + push(@args_seperator, ''); + } else { + foreach (@whitespace_split) { + #print ("arglist = \"$_\"\n"); + if (length($_)) { + push(@args, $_); + my $sep = $comma_sep_required ? "," : " "; + push(@args_seperator, $sep); + #print ("sep = \"$sep\", arg = \"$_\"\n"); + $comma_sep_required = 0; + } + } + } + + $comma_sep_required = 1; + } + + my %replacements; + if ($macro_args_default{$macro}){ + %replacements = %{$macro_args_default{$macro}}; + } + + # construct hashtable of text to replace + foreach my $i (0 .. $#args) { + my $argname = $macro_args{$macro}[$i]; + my @macro_args = @{ $macro_args{$macro} }; + if ($args[$i] =~ m/=/) { + # arg=val references the argument name + # XXX: I'm not sure what the expected behaviour if a lot of + # these are mixed with unnamed args + my @named_arg = split(/=/, $args[$i]); + $replacements{$named_arg[0]} = $named_arg[1]; + } elsif ($i > $#{$macro_args{$macro}}) { + # more args given than the macro has named args + # XXX: is vararg allowed on arguments before the last? + $argname = $macro_args{$macro}[-1]; + if ($argname =~ s/:vararg$//) { + #print "macro = $macro, args[$i] = $args[$i], args_seperator=@args_seperator, argname = $argname, arglist[$i] = $arglist[$i], arglist = @arglist, args=@args, macro_args=@macro_args\n"; + #$replacements{$argname} .= ", $args[$i]"; + $replacements{$argname} .= "$args_seperator[$i] $args[$i]"; + } else { + die "Too many arguments to macro $macro"; + } + } else { + $argname =~ s/:vararg$//; + $replacements{$argname} = $args[$i]; + } + } + + my $count = $macro_count++; + + # apply replacements as regex + foreach (@{$macro_lines{$macro}}) { + my $macro_line = $_; + # do replacements by longest first, this avoids wrong replacement + # when argument names are subsets of each other + foreach (reverse sort {length $a <=> length $b} keys %replacements) { + $macro_line =~ s/\\$_/$replacements{$_}/g; + } + if ($altmacro) { + foreach (reverse sort {length $a <=> length $b} keys %replacements) { + $macro_line =~ s/\b$_\b/$replacements{$_}/g; + } + } + $macro_line =~ s/\\\@/$count/g; + $macro_line =~ s/\\\(\)//g; # remove \() + parse_line($macro_line); + } + } else { + handle_serialized_line($line); + } +} + +sub is_arm_register { + my $name = $_[0]; + if ($name eq "lr" or + $name eq "ip" or + $name =~ /^[rav]\d+$/) { + return 1; + } + return 0; +} + +sub is_aarch64_register { + my $name = $_[0]; + if ($name =~ /^[xw]\d+$/) { + return 1; + } + return 0; +} + +sub handle_local_label { + my $line = $_[0]; + my $num = $_[1]; + my $dir = $_[2]; + my $target = "$num$dir"; + if ($dir eq "b") { + $line =~ s/\b$target\b/$last_temp_labels{$num}/g; + } else { + my $name = "temp_label_$temp_label_next"; + $temp_label_next++; + push(@{$next_temp_labels{$num}}, $name); + $line =~ s/\b$target\b/$name/g; + } + return $line; +} + +sub handle_serialized_line { + my $line = $_[0]; + + # handle .previous (only with regard to .section not .subsection) + if ($line =~ /\.(section|text|const_data)/) { + push(@sections, $line); + } elsif ($line =~ /\.previous/) { + if (!$sections[-2]) { + die ".previous without a previous section"; + } + $line = $sections[-2]; + push(@sections, $line); + } + + $thumb = 1 if $line =~ /\.code\s+16|\.thumb/; + $thumb = 0 if $line =~ /\.code\s+32|\.arm/; + + # handle ldr <reg>, =<expr> + if ($line =~ /(.*)\s*ldr([\w\s\d]+)\s*,\s*=(.*)/ and $as_type ne "armasm") { + my $label = $literal_labels{$3}; + if (!$label) { + $label = "Literal_$literal_num"; + $literal_num++; + $literal_labels{$3} = $label; + } + $line = "$1 ldr$2, $label\n"; + } elsif ($line =~ /\.ltorg/ and $as_type ne "armasm") { + $line .= ".align 2\n"; + foreach my $literal (keys %literal_labels) { + $line .= "$literal_labels{$literal}:\n $literal_expr $literal\n"; + } + %literal_labels = (); + } + + # handle GNU as pc-relative relocations for adrp/add + if ($line =~ /(.*)\s*adrp([\w\s\d]+)\s*,\s*#?:pg_hi21:([^\s]+)/ and $as_type =~ /^apple-/) { + $line = "$1 adrp$2, ${3}\@PAGE\n"; + } elsif ($line =~ /(.*)\s*add([\w\s\d]+)\s*,([\w\s\d]+)\s*,\s*#?:lo12:([^\s]+)/ and $as_type =~ /^apple-/) { + $line = "$1 add$2, $3, ${4}\@PAGEOFF\n"; + } + + # thumb add with large immediate needs explicit add.w + if ($thumb and $line =~ /add\s+.*#([^@]+)/) { + $line =~ s/add/add.w/ if eval_expr($1) > 255; + } + + # mach-o local symbol names start with L (no dot) + $line =~ s/(?<!\w)\.(L\w+)/$1/g; + + # recycle the '.func' directive for '.thumb_func' + if ($thumb and $as_type =~ /^apple-/) { + $line =~ s/\.func/.thumb_func/x; + } + + if ($thumb and $line =~ /^\s*(\w+)\s*:/) { + $thumb_labels{$1}++; + } + + if ($as_type =~ /^apple-/ and + $line =~ /^\s*((\w+\s*:\s*)?bl?x?(..)?(?:\.w)?|\.global)\s+(\w+)/) { + my $cond = $3; + my $label = $4; + # Don't interpret e.g. bic as b<cc> with ic as conditional code + if ($cond =~ /^(|$arm_cond_codes)$/) { + if (exists $thumb_labels{$label}) { + print ASMFILE ".thumb_func $label\n"; + } else { + $call_targets{$label}++; + } + } + } + + # @l -> lo16() @ha -> ha16() + $line =~ s/,\s+([^,]+)\@l\b/, lo16($1)/g; + $line =~ s/,\s+([^,]+)\@ha\b/, ha16($1)/g; + + # move to/from SPR + if ($line =~ /(\s+)(m[ft])([a-z]+)\s+(\w+)/ and exists $ppc_spr{$3}) { + if ($2 eq 'mt') { + $line = "$1${2}spr $ppc_spr{$3}, $4\n"; + } else { + $line = "$1${2}spr $4, $ppc_spr{$3}\n"; + } + } + + if ($line =~ /\.unreq\s+(.*)/) { + if (defined $neon_alias_reg{$1}) { + delete $neon_alias_reg{$1}; + delete $neon_alias_type{$1}; + return; + } elsif (defined $aarch64_req_alias{$1}) { + delete $aarch64_req_alias{$1}; + return; + } + } + # old gas versions store upper and lower case names on .req, + # but they remove only one on .unreq + if ($fix_unreq) { + if ($line =~ /\.unreq\s+(.*)/) { + $line = ".unreq " . lc($1) . "\n"; + $line .= ".unreq " . uc($1) . "\n"; + } + } + + if ($line =~ /(\w+)\s+\.(dn|qn)\s+(\w+)(?:\.(\w+))?(\[\d+\])?/) { + $neon_alias_reg{$1} = "$3$5"; + $neon_alias_type{$1} = $4; + return; + } + if (scalar keys %neon_alias_reg > 0 && $line =~ /^\s+v\w+/) { + # This line seems to possibly have a neon instruction + foreach (keys %neon_alias_reg) { + my $alias = $_; + # Require the register alias to match as an invididual word, not as a substring + # of a larger word-token. + if ($line =~ /\b$alias\b/) { + $line =~ s/\b$alias\b/$neon_alias_reg{$alias}/g; + # Add the type suffix. If multiple aliases match on the same line, + # only do this replacement the first time (a vfoo.bar string won't match v\w+). + $line =~ s/^(\s+)(v\w+)(\s+)/$1$2.$neon_alias_type{$alias}$3/; + } + } + } + + if ($arch eq "aarch64" or $as_type eq "armasm") { + # clang's integrated aarch64 assembler in Xcode 5 does not support .req/.unreq + if ($line =~ /\b(\w+)\s+\.req\s+(\w+)\b/) { + $aarch64_req_alias{$1} = $2; + return; + } + foreach (keys %aarch64_req_alias) { + my $alias = $_; + # recursively resolve aliases + my $resolved = $aarch64_req_alias{$alias}; + while (defined $aarch64_req_alias{$resolved}) { + $resolved = $aarch64_req_alias{$resolved}; + } + $line =~ s/\b$alias\b/$resolved/g; + } + } + if ($arch eq "aarch64") { + # fix missing aarch64 instructions in Xcode 5.1 (beta3) + # mov with vector arguments is not supported, use alias orr instead + if ($line =~ /^(\d+:)?\s*mov\s+(v\d[\.{}\[\]\w]+),\s*(v\d[\.{}\[\]\w]+)\b\s*$/) { + $line = "$1 orr $2, $3, $3\n"; + } + # movi 16, 32 bit shifted variant, shift is optional + if ($line =~ /^(\d+:)?\s*movi\s+(v[0-3]?\d\.(?:2|4|8)[hsHS])\s*,\s*(#\w+)\b\s*$/) { + $line = "$1 movi $2, $3, lsl #0\n"; + } + # Xcode 5 misses the alias uxtl. Replace it with the more general ushll. + # Clang 3.4 misses the alias sxtl too. Replace it with the more general sshll. + # armasm64 also misses these instructions. + if ($line =~ /^(\d+:)?\s*(s|u)xtl(2)?\s+(v[0-3]?\d\.[248][hsdHSD])\s*,\s*(v[0-3]?\d\.(?:2|4|8|16)[bhsBHS])\b\s*$/) { + $line = "$1 $2shll$3 $4, $5, #0\n"; + } + # clang 3.4 and armasm64 do not automatically use shifted immediates in add/sub + if (($as_type eq "clang" or $as_type eq "armasm") and + $line =~ /^(\d+:)?(\s*(?:add|sub)s?) ([^#l]+)#([\d\+\-\*\/ <>]+)\s*$/) { + my $imm = eval $4; + if ($imm > 4095 and not ($imm & 4095)) { + $line = "$1 $2 $3#" . ($imm >> 12) . ", lsl #12\n"; + } + } + if ($ENV{GASPP_FIX_XCODE5}) { + if ($line =~ /^\s*bsl\b/) { + $line =~ s/\b(bsl)(\s+v[0-3]?\d\.(\w+))\b/$1.$3$2/; + $line =~ s/\b(v[0-3]?\d)\.$3\b/$1/g; + } + if ($line =~ /^\s*saddl2?\b/) { + $line =~ s/\b(saddl2?)(\s+v[0-3]?\d\.(\w+))\b/$1.$3$2/; + $line =~ s/\b(v[0-3]?\d)\.\w+\b/$1/g; + } + if ($line =~ /^\s*dup\b.*\]$/) { + $line =~ s/\bdup(\s+v[0-3]?\d)\.(\w+)\b/dup.$2$1/g; + $line =~ s/\b(v[0-3]?\d)\.[bhsdBHSD](\[\d\])$/$1$2/g; + } + } + } + + if ($as_type eq "armasm") { + # Also replace variables set by .set + foreach (keys %symbols) { + my $sym = $_; + $line =~ s/\b$sym\b/$symbols{$sym}/g; + } + + # Handle function declarations and keep track of the declared labels + if ($line =~ s/^\s*\.func\s+(\w+)/$1 PROC/) { + $labels_seen{$1} = 1; + } + + if ($line =~ s/^\s*(\d+)://) { + # Convert local labels into unique labels. armasm (at least in + # RVCT) has something similar, but still different enough. + # By converting to unique labels we avoid any possible + # incompatibilities. + + my $num = $1; + foreach (@{$next_temp_labels{$num}}) { + $line = "$_\n" . $line; + } + @next_temp_labels{$num} = (); + my $name = "temp_label_$temp_label_next"; + $temp_label_next++; + # The matching regexp above removes the label from the start of + # the line (which might contain an instruction as well), readd + # it on a separate line above it. + $line = "$name:\n" . $line; + $last_temp_labels{$num} = $name; + } + + if ($line =~ s/^\s*(\w+):/$1/) { + # Skip labels that have already been declared with a PROC, + # labels must not be declared multiple times. + return if (defined $labels_seen{$1}); + $labels_seen{$1} = 1; + } elsif ($line !~ /(\w+) PROC/) { + # If not a label, make sure the line starts with whitespace, + # otherwise ms armasm interprets it incorrectly. + $line =~ s/^[\.\w]/\t$&/; + } + + + # Check branch instructions + if ($line =~ /(?:^|\n)\s*(\w+\s*:\s*)?(bl?x?\.?([^\s]{2})?(\.w)?)\s+(\w+)/) { + my $instr = $2; + my $cond = $3; + my $width = $4; + my $target = $5; + # Don't interpret e.g. bic as b<cc> with ic as conditional code + if ($cond !~ /^(|$arm_cond_codes)$/) { + # Not actually a branch + } elsif ($target =~ /^(\d+)([bf])$/) { + # The target is a local label + $line = handle_local_label($line, $1, $2); + $line =~ s/\b$instr\b/$&.w/ if $width eq "" and $arch eq "arm"; + } elsif (($arch eq "arm" and !is_arm_register($target)) or + ($arch eq "aarch64" and !is_aarch64_register($target))) { + $call_targets{$target}++; + } + } elsif ($line =~ /(?:^|\n)\s*(\w+\s*:\s*)?(cbn?z|adr|tbz)\s+(\w+)\s*,(\s*#\d+\s*,)?\s*(\w+)/) { + my $instr = $2; + my $reg = $3; + my $bit = $4; + my $target = $5; + if ($target =~ /^(\d+)([bf])$/) { + # The target is a local label + $line = handle_local_label($line, $1, $2); + } else { + $call_targets{$target}++; + } + # Convert tbz with a wX register into an xX register, + # due to armasm64 bugs/limitations. + if ($instr eq "tbz" and $reg =~ /w\d+/) { + my $xreg = $reg; + $xreg =~ s/w/x/; + $line =~ s/\b$reg\b/$xreg/; + } + } elsif ($line =~ /^\s*.h?word.*\b\d+[bf]\b/) { + while ($line =~ /\b(\d+)([bf])\b/g) { + $line = handle_local_label($line, $1, $2); + } + } + + # ALIGN in armasm syntax is the actual number of bytes + if ($line =~ /\.(?:p2)?align\s+(\d+)/) { + my $align = 1 << $1; + $line =~ s/\.(?:p2)?align\s+(\d+)/ALIGN $align/; + } + # Convert gas style [r0, :128] into armasm [r0@128] alignment specification + $line =~ s/\[([^\[,]+),?\s*:(\d+)\]/[$1\@$2]/g; + + # armasm treats logical values {TRUE} and {FALSE} separately from + # numeric values - logical operators and values can't be intermixed + # with numerical values. Evaluate !<number> and (a <> b) into numbers, + # let the assembler evaluate the rest of the expressions. This current + # only works for cases when ! and <> are used with actual constant numbers, + # we don't evaluate subexpressions here. + + # Evaluate !<number> + while ($line =~ /!\s*(\d+)/g) { + my $val = ($1 != 0) ? 0 : 1; + $line =~ s/!(\d+)/$val/; + } + # Evaluate (a > b) + while ($line =~ /\(\s*(\d+)\s*([<>])\s*(\d+)\s*\)/) { + my $val; + if ($2 eq "<") { + $val = ($1 < $3) ? 1 : 0; + } else { + $val = ($1 > $3) ? 1 : 0; + } + $line =~ s/\(\s*(\d+)\s*([<>])\s*(\d+)\s*\)/$val/; + } + + if ($arch eq "arm") { + # Change a movw... #:lower16: into a mov32 pseudoinstruction + $line =~ s/^(\s*)movw(\s+\w+\s*,\s*)\#:lower16:(.*)$/$1mov32$2$3/; + # and remove the following, matching movt completely + $line =~ s/^\s*movt\s+\w+\s*,\s*\#:upper16:.*$//; + + if ($line =~ /^\s*mov32\s+\w+,\s*([a-zA-Z]\w*)/) { + $import_symbols{$1}++; + } + + # Misc bugs/deficiencies: + # armasm seems unable to parse e.g. "vmov s0, s1" without a type + # qualifier, thus add .f32. + $line =~ s/^(\s+(?:vmov|vadd))(\s+s\d+\s*,\s*s\d+)/$1.f32$2/; + } elsif ($arch eq "aarch64") { + # Convert ext into ext8; armasm64 seems to require it named as ext8. + $line =~ s/^(\s+)ext(\s+)/$1ext8$2/; + + # Pick up targets from ldr x0, =sym+offset + if ($line =~ /^\s*ldr\s+(\w+)\s*,\s*=([a-zA-Z]\w*)(.*)$/) { + my $reg = $1; + my $sym = $2; + my $offset = eval_expr($3); + if ($offset < 0 and $ENV{GASPP_ARMASM64_SKIP_NEG_OFFSET}) { + # armasm64 in VS < 15.6 is buggy with ldr x0, =sym+offset where the + # offset is a negative value; it does write a negative + # offset into the literal pool as it should, but the + # negative offset only covers the lower 32 bit of the 64 + # bit literal/relocation. + # Thus remove the offset and apply it manually with a sub + # afterwards. + $offset = -$offset; + $line = "\tldr $reg, =$sym\n\tsub $reg, $reg, #$offset\n"; + } + $import_symbols{$sym}++; + } + + # armasm64 (currently) doesn't support offsets on adrp targets, + # even though the COFF format relocations (and the linker) + # supports it. Therefore strip out the offsets from adrp and + # add :lo12: (in case future armasm64 would start handling it) + # and add an extra explicit add instruction for the offset. + if ($line =~ s/(adrp\s+\w+\s*,\s*(\w+))([\d\+\-\*\/\(\) <>]+)?/\1/) { + $import_symbols{$2}++; + } + if ($line =~ s/(add\s+(\w+)\s*,\s*\w+\s*,\s*):lo12:(\w+)([\d\+\-\*\/\(\) <>]+)?/\1\3/) { + my $reg = $2; + my $sym = $3; + my $offset = eval_expr($4); + $line .= "\tadd $reg, $reg, #$offset\n" if $offset > 0; + $import_symbols{$sym}++; + } + + # Convert e.g. "add x0, x0, w0, uxtw" into "add x0, x0, w0, uxtw #0", + # or "ldr x0, [x0, w0, uxtw]" into "ldr x0, [x0, w0, uxtw #0]". + $line =~ s/(uxt[whb]|sxt[whb])(\s*\]?\s*)$/\1 #0\2/i; + + # Convert "mov x0, v0.d[0]" into "umov x0, v0.d[0]" + $line =~ s/\bmov\s+[xw]\d+\s*,\s*v\d+\.[ds]/u$&/i; + + # Convert "ccmp w0, #0, #0, ne" into "ccmpne w0, #0, #0", + # and "csel w0, w0, w0, ne" into "cselne w0, w0, w0". + $line =~ s/(ccmp|csel)\s+([xw]\w+)\s*,\s*([xw#]\w+)\s*,\s*([xw#]\w+)\s*,\s*($arm_cond_codes)/\1\5 \2, \3, \4/; + + # Convert "cinc w0, w0, ne" into "cincne w0, w0". + $line =~ s/(cinc)\s+([xw]\w+)\s*,\s*([xw]\w+)\s*,\s*($arm_cond_codes)/\1\4 \2, \3/; + + # Convert "cset w0, lo" into "csetlo w0" + $line =~ s/(cset)\s+([xw]\w+)\s*,\s*($arm_cond_codes)/\1\3 \2/; + + if ($ENV{GASPP_ARMASM64_SKIP_PRFUM}) { + # Strip out prfum; armasm64 (VS < 15.5) fails to assemble any + # variant/combination of prfum tested so far, but since it is + # a prefetch instruction it can be skipped without changing + # results. + $line =~ s/prfum.*\]//; + } + + # Convert "ldrb w0, [x0, #-1]" into "ldurb w0, [x0, #-1]". + # Don't do this for forms with writeback though. + if ($line =~ /(ld|st)(r[bh]?)\s+(\w+)\s*,\s*\[\s*(\w+)\s*,\s*#([^\]]+)\s*\][^!]/) { + my $instr = $1; + my $suffix = $2; + my $target = $3; + my $base = $4; + my $offset = eval_expr($5); + if ($offset < 0) { + $line =~ s/$instr$suffix/${instr}u$suffix/; + } + } + + if ($ENV{GASPP_ARMASM64_INVERT_SCALE}) { + # Instructions like fcvtzs and scvtf store the scale value + # inverted in the opcode (stored as 64 - scale), but armasm64 + # in VS < 15.5 stores it as-is. Thus convert from + # "fcvtzs w0, s0, #8" into "fcvtzs w0, s0, #56". + if ($line =~ /(?:fcvtzs|scvtf)\s+(\w+)\s*,\s*(\w+)\s*,\s*#(\d+)/) { + my $scale = $3; + my $inverted_scale = 64 - $3; + $line =~ s/#$scale/#$inverted_scale/; + } + } + + # Convert "ld1 {v0.4h-v3.4h}" into "ld1 {v0.4h,v1.4h,v2.4h,v3.4h}" + if ($line =~ /(?:ld|st)\d\s+({\s*v(\d+)\.(\d[bhsdBHSD])\s*-\s*v(\d+)\.(\d[bhsdBHSD])\s*})/) { + my $regspec = $1; + my $reg1 = $2; + my $layout1 = $3; + my $reg2 = $4; + my $layout2 = $5; + if ($layout1 eq $layout2) { + my $new_regspec = "{"; + foreach my $i ($reg1 .. $reg2) { + $new_regspec .= "," if ($i > $reg1); + $new_regspec .= "v$i.$layout1"; + } + $new_regspec .= "}"; + $line =~ s/$regspec/$new_regspec/; + } + } + } + # armasm is unable to parse &0x - add spacing + $line =~ s/&0x/& 0x/g; + } + + if ($force_thumb) { + # Convert register post indexing to a separate add instruction. + # This converts e.g. "ldr r0, [r1], r2" into "ldr r0, [r1]", + # "add r1, r1, r2". + $line =~ s/((?:ldr|str)[bh]?)\s+(\w+),\s*\[(\w+)\],\s*(\w+)/$1 $2, [$3]\n\tadd $3, $3, $4/g; + + # Convert "mov pc, lr" into "bx lr", since the former only works + # for switching from arm to thumb (and only in armv7), but not + # from thumb to arm. + $line =~ s/mov\s*pc\s*,\s*lr/bx lr/g; + + # Convert stmdb/ldmia/stmfd/ldmfd/ldm with only one register into a plain str/ldr with post-increment/decrement. + # Wide thumb2 encoding requires at least two registers in register list while all other encodings support one register too. + $line =~ s/stm(?:db|fd)\s+sp!\s*,\s*\{([^,-]+)\}/str $1, [sp, #-4]!/g; + $line =~ s/ldm(?:ia|fd)?\s+sp!\s*,\s*\{([^,-]+)\}/ldr $1, [sp], #4/g; + + # Convert muls into mul+cmp + $line =~ s/muls\s+(\w+),\s*(\w+)\,\s*(\w+)/mul $1, $2, $3\n\tcmp $1, #0/g; + + # Convert "and r0, sp, #xx" into "mov r0, sp", "and r0, r0, #xx" + $line =~ s/and\s+(\w+),\s*(sp|r13)\,\s*#(\w+)/mov $1, $2\n\tand $1, $1, #$3/g; + + # Convert "ldr r0, [r0, r1, lsl #6]" where the shift is >3 (which + # can't be handled in thumb) into "add r0, r0, r1, lsl #6", + # "ldr r0, [r0]", for the special case where the same address is + # used as base and target for the ldr. + if ($line =~ /(ldr[bh]?)\s+(\w+),\s*\[\2,\s*(\w+),\s*lsl\s*#(\w+)\]/ and $4 > 3) { + $line =~ s/(ldr[bh]?)\s+(\w+),\s*\[\2,\s*(\w+),\s*lsl\s*#(\w+)\]/add $2, $2, $3, lsl #$4\n\t$1 $2, [$2]/; + } + + $line =~ s/\.arm/.thumb/x; + } + + # comment out unsupported directives + $line =~ s/\.type/$comm$&/x if $as_type =~ /^(apple-|armasm)/; + $line =~ s/\.func/$comm$&/x if $as_type =~ /^(apple-|clang)/; + $line =~ s/\.endfunc/$comm$&/x if $as_type =~ /^(apple-|clang)/; + $line =~ s/\.endfunc/ENDP/x if $as_type =~ /armasm/; + $line =~ s/\.ltorg/$comm$&/x if $as_type =~ /^(apple-|clang)/; + $line =~ s/\.ltorg/LTORG/x if $as_type eq "armasm"; + $line =~ s/\.size/$comm$&/x if $as_type =~ /^(apple-|armasm)/; + $line =~ s/\.fpu/$comm$&/x if $as_type =~ /^(apple-|armasm)/; + $line =~ s/\.arch/$comm$&/x if $as_type =~ /^(apple-|clang|armasm)/; + $line =~ s/\.object_arch/$comm$&/x if $as_type =~ /^(apple-|armasm)/; + $line =~ s/.section\s+.note.GNU-stack.*/$comm$&/x if $as_type =~ /^(apple-|armasm)/; + + $line =~ s/\.syntax/$comm$&/x if $as_type =~ /armasm/; + + $line =~ s/\.hword/.short/x; + + if ($as_type =~ /^apple-/) { + # the syntax for these is a little different + $line =~ s/\.global/.globl/x; + # also catch .section .rodata since the equivalent to .const_data is .section __DATA,__const + $line =~ s/(.*)\.rodata/.const_data/x; + $line =~ s/\.int/.long/x; + $line =~ s/\.float/.single/x; + } + if ($as_type eq "apple-gas") { + $line =~ s/vmrs\s+APSR_nzcv/fmrx r15/x; + } + if ($as_type eq "armasm") { + $line =~ s/\.global/EXPORT/x; + $line =~ s/\.extern/IMPORT/x; + $line =~ s/\.int/dcd/x; + $line =~ s/\.long/dcd/x; + $line =~ s/\.float/dcfs/x; + $line =~ s/\.word/dcd/x; + $line =~ s/\.short/dcw/x; + $line =~ s/\.byte/dcb/x; + $line =~ s/\.quad/dcq/x; + $line =~ s/\.ascii/dcb/x; + $line =~ s/\.asciz(.*)$/dcb\1,0/x; + $line =~ s/\.thumb/THUMB/x; + $line =~ s/\.arm/ARM/x; + # The alignment in AREA is the power of two, just as .align in gas + $line =~ s/\.text/AREA |.text|, CODE, READONLY, ALIGN=4, CODEALIGN/; + $line =~ s/(\s*)(.*)\.ro?data/$1AREA |.rdata|, DATA, READONLY, ALIGN=5/; + $line =~ s/\.data/AREA |.data|, DATA, ALIGN=5/; + } + if ($as_type eq "armasm" and $arch eq "arm") { + $line =~ s/fmxr/vmsr/; + $line =~ s/fmrx/vmrs/; + $line =~ s/fadds/vadd.f32/; + # Armasm in VS 2019 16.3 errors out on "it" instructions. But + # armasm implicitly adds the necessary it instructions anyway, so we + # can just filter them out. + $line =~ s/^\s*it[te]*\s+/$comm$&/; + } + if ($as_type eq "armasm" and $arch eq "aarch64") { + # Convert "b.eq" into "beq" + $line =~ s/\bb\.($arm_cond_codes)\b/b\1/; + } + + # catch unknown section names that aren't mach-o style (with a comma) + if ($as_type =~ /apple-/ and $line =~ /.section ([^,]*)$/) { + die ".section $1 unsupported; figure out the mach-o section name and add it"; + } + + print ASMFILE $line; +} + +if ($as_type ne "armasm") { + print ASMFILE ".text\n"; + print ASMFILE ".align 2\n"; + foreach my $literal (keys %literal_labels) { + print ASMFILE "$literal_labels{$literal}:\n $literal_expr $literal\n"; + } + + map print(ASMFILE ".thumb_func $_\n"), + grep exists $thumb_labels{$_}, keys %call_targets; +} else { + map print(ASMFILE "\tIMPORT $_\n"), + grep ! exists $labels_seen{$_}, (keys %call_targets, keys %import_symbols); + + print ASMFILE "\tEND\n"; +} + +close(INPUT) or exit 1; +close(ASMFILE) or exit 1; +if ($as_type eq "armasm" and ! defined $ENV{GASPP_DEBUG}) { + print STDERR join(" ", @gcc_cmd)."\n" if $verbose; + system(@gcc_cmd) == 0 or die "Error running assembler"; +} + +END { + unlink($tempfile) if defined $tempfile; +} +#exit 1 diff --git a/tools/depends/native/gettext/01-gettext-tools-stpncpy.patch b/tools/depends/native/gettext/01-gettext-tools-stpncpy.patch new file mode 100644 index 0000000..a7541bf --- /dev/null +++ b/tools/depends/native/gettext/01-gettext-tools-stpncpy.patch @@ -0,0 +1,11 @@ +--- a/gettext-tools/gnulib-lib/stpncpy.c ++++ b/gettext-tools/gnulib-lib/stpncpy.c +@@ -24,7 +24,7 @@ + /* Specification. */ + #include <string.h> + +-#ifndef weak_alias ++#ifndef HAVE_STPNCPY + # define __stpncpy stpncpy + #endif + diff --git a/tools/depends/native/gettext/02-disable-test-doc.patch b/tools/depends/native/gettext/02-disable-test-doc.patch new file mode 100644 index 0000000..1e539d1 --- /dev/null +++ b/tools/depends/native/gettext/02-disable-test-doc.patch @@ -0,0 +1,11 @@ +--- a/gettext-tools/Makefile.in ++++ b/gettext-tools/Makefile.in +@@ -2198,7 +2198,7 @@ + top_srcdir = @top_srcdir@ + AUTOMAKE_OPTIONS = 1.5 gnu no-dependencies + ACLOCAL_AMFLAGS = -I m4 -I ../gettext-runtime/m4 -I ../m4 -I gnulib-m4 -I libgrep/gnulib-m4 -I libgettextpo/gnulib-m4 +-SUBDIRS = intl gnulib-lib libgrep src libgettextpo po its projects styles emacs misc man m4 tests system-tests gnulib-tests examples doc ++SUBDIRS = intl gnulib-lib libgrep src libgettextpo po its projects styles emacs misc man m4 + + # Allow users to use "gnulib-tool --update". + diff --git a/tools/depends/native/gettext/Makefile b/tools/depends/native/gettext/Makefile new file mode 100644 index 0000000..f78acea --- /dev/null +++ b/tools/depends/native/gettext/Makefile @@ -0,0 +1,62 @@ +include ../../Makefile.include +PREFIX=$(NATIVEPREFIX) +PLATFORM=$(NATIVEPLATFORM) +DEPS = ../../Makefile.include Makefile 01-gettext-tools-stpncpy.patch 02-disable-test-doc.patch ../../download-files.include + +# lib name, version +LIBNAME=gettext +VERSION=0.21 +SOURCE=$(LIBNAME)-$(VERSION) +ARCHIVE=$(SOURCE).tar.xz +SHA512=f7e2968651879f8444d43a176a149db9f9411f4a03132a7f3b37c2ed97e3978ae6888169c995c1953cb78943b6e3573811abcbb8661b6631edbbe067b2699ddf +include ../../download-files.include + +# configuration settings +CONFIGURE=./configure --prefix=$(PREFIX) \ + --disable-csharp --disable-native-java --disable-java --without-emacs \ + --disable-libasprintf --disable-openmp \ + --with-included-gettext \ + --with-included-glib \ + --with-included-libcroco \ + --with-included-libxml \ + --without-git --without-cvs \ + --disable-shared --disable-curses --disable-acl --disable-c++ --disable-nls + +ifeq ($(NATIVE_OS), osx) + # As per homebrew - https://github.com/Homebrew/homebrew-core/blob/f6df737d9479dd215185000a3dbd641185eafec2/Formula/g/gettext.rb#L52C1-L55 + # Sonoma iconv() has a regression w.r.t. transliteration, which happens to + # break gettext's configure check. Force it. + # Reported to Apple as FB13163914 + CONFIGURE+= am_cv_func_iconv_works=y +endif + +LIBDYLIB=$(PLATFORM)/gettext-tools/src/.libs/libgettextsrc.a + +all: .installed-$(PLATFORM) + + +$(PLATFORM): $(DEPS) | $(TARBALLS_LOCATION)/$(ARCHIVE).$(HASH_TYPE) + rm -rf $(PLATFORM)/*; mkdir -p $(PLATFORM) + cd $(PLATFORM); $(ARCHIVE_TOOL) $(ARCHIVE_TOOL_FLAGS) $(TARBALLS_LOCATION)/$(ARCHIVE) + cd $(PLATFORM); sed -ie '/gets is a security hole/d' gettext-tools/gnulib-lib/stdio.in.h + cd $(PLATFORM); sed -ie '/gets is a security hole/d' gettext-tools/libgettextpo/stdio.in.h + cd $(PLATFORM); sed -ie '/gets is a security hole/d' gettext-runtime/gnulib-lib/stdio.in.h + cd $(PLATFORM); patch -p1 -i ../01-gettext-tools-stpncpy.patch + cd $(PLATFORM); patch -p1 -i ../02-disable-test-doc.patch + cd $(PLATFORM); $(CONFIGURE) + +$(LIBDYLIB): $(PLATFORM) + $(MAKE) -C $(PLATFORM)/libtextstyle + $(MAKE) -C $(PLATFORM)/gettext-tools + +.installed-$(PLATFORM): $(LIBDYLIB) + $(MAKE) -j1 -C $(PLATFORM)/gettext-tools install + touch $@ + +clean: + $(MAKE) -C $(PLATFORM) clean + rm -f .installed-$(PLATFORM) + +distclean:: + rm -rf $(PLATFORM) .installed-$(PLATFORM) + diff --git a/tools/depends/native/giflib/01-static-lib.patch b/tools/depends/native/giflib/01-static-lib.patch new file mode 100644 index 0000000..a5b0ebc --- /dev/null +++ b/tools/depends/native/giflib/01-static-lib.patch @@ -0,0 +1,12 @@ +--- a/Makefile ++++ b/Makefile +@@ -99,9 +99,6 @@ + install-lib: + $(INSTALL) -d "$(DESTDIR)$(LIBDIR)" + $(INSTALL) -m 644 libgif.a "$(DESTDIR)$(LIBDIR)/libgif.a" +- $(INSTALL) -m 755 libgif.so "$(DESTDIR)$(LIBDIR)/libgif.so.$(LIBVER)" +- ln -sf libgif.so.$(LIBVER) "$(DESTDIR)$(LIBDIR)/libgif.so.$(LIBMAJOR)" +- ln -sf libgif.so.$(LIBMAJOR) "$(DESTDIR)$(LIBDIR)/libgif.so" + install-man: + $(INSTALL) -d "$(DESTDIR)$(MANDIR)/man1" + $(INSTALL) -m 644 doc/*.1 "$(DESTDIR)$(MANDIR)/man1" diff --git a/tools/depends/native/giflib/Makefile b/tools/depends/native/giflib/Makefile new file mode 100644 index 0000000..a5df837 --- /dev/null +++ b/tools/depends/native/giflib/Makefile @@ -0,0 +1,40 @@ +include ../../Makefile.include +DEPS = ../../Makefile.include Makefile 01-static-lib.patch ../../download-files.include +PREFIX=$(NATIVEPREFIX) +PLATFORM=$(NATIVEPLATFORM) + +# lib name, version +LIBNAME=giflib +VERSION=5.2.1 +SOURCE=$(LIBNAME)-$(VERSION) +ARCHIVE=$(SOURCE).tar.gz +SHA512=4550e53c21cb1191a4581e363fc9d0610da53f7898ca8320f0d3ef6711e76bdda2609c2df15dc94c45e28bff8de441f1227ec2da7ea827cb3c0405af4faa4736 +include ../../download-files.include + +# configuration settings +CONFIGURE=./configure --prefix=$(PREFIX) + +LIBDYLIB=$(PLATFORM)/libgif.a + +all: .installed-$(PLATFORM) + + +$(PLATFORM): $(DEPS) | $(TARBALLS_LOCATION)/$(ARCHIVE).$(HASH_TYPE) + -rm -rf $(PLATFORM); mkdir -p $(PLATFORM) + cd $(PLATFORM); $(ARCHIVE_TOOL) $(ARCHIVE_TOOL_FLAGS) $(TARBALLS_LOCATION)/$(ARCHIVE) + cd $(PLATFORM); patch -p1 -i ../01-static-lib.patch + +$(LIBDYLIB): $(PLATFORM) + $(MAKE) -C $(PLATFORM) libgif.a CFLAGS="$(NATIVE_CFLAGS)" LDFLAGS="$(NATIVE_LDFLAGS)" + +.installed-$(PLATFORM): $(LIBDYLIB) + $(MAKE) -C $(PLATFORM) install-include PREFIX="$(PREFIX)" + $(MAKE) -C $(PLATFORM) install-lib PREFIX="$(PREFIX)" + touch $@ +clean: + $(MAKE) -C $(PLATFORM) clean + rm -r .installed-$(PLATFORM) + rm -rf $(PLATFORM) + +distclean:: + rm -rf $(PLATFORM) .installed-$(PLATFORM) diff --git a/tools/depends/native/heimdal/01-disable-libedit.patch b/tools/depends/native/heimdal/01-disable-libedit.patch new file mode 100644 index 0000000..0e17025 --- /dev/null +++ b/tools/depends/native/heimdal/01-disable-libedit.patch @@ -0,0 +1,11 @@ +--- a/configure.ac ++++ b/configure.ac +@@ -309,8 +309,6 @@ + #endif + ],-ledit,,, READLINE,, [readline.h readline/readline.h editline/readline.h]) + +-AC_CONFIG_SUBDIRS([lib/libedit]) +- + KRB_C_BIGENDIAN + AC_C_INLINE + diff --git a/tools/depends/native/heimdal/02-autoconf-2.70-configure.patch b/tools/depends/native/heimdal/02-autoconf-2.70-configure.patch new file mode 100644 index 0000000..7275504 --- /dev/null +++ b/tools/depends/native/heimdal/02-autoconf-2.70-configure.patch @@ -0,0 +1,11 @@ +--- a/cf/check-var.m4 ++++ b/cf/check-var.m4 +@@ -20,7 +20,7 @@ + if test "$ac_foo" = yes; then + AC_DEFINE_UNQUOTED(AS_TR_CPP(HAVE_[]$1), 1, + [Define if you have the `]$1[' variable.]) +- m4_ifval([$2], AC_CHECK_DECLS([$1],[],[],[$2])) ++ m4_ifval([$2], [AC_CHECK_DECLS([$1],[],[],[$2])]) + fi + ]) + diff --git a/tools/depends/native/heimdal/Makefile b/tools/depends/native/heimdal/Makefile new file mode 100644 index 0000000..29d2a79 --- /dev/null +++ b/tools/depends/native/heimdal/Makefile @@ -0,0 +1,43 @@ +include ../../Makefile.include +PREFIX=$(NATIVEPREFIX) +PLATFORM=$(NATIVEPLATFORM) +DEPS = ../../Makefile.include Makefile 01-disable-libedit.patch 02-autoconf-2.70-configure.patch ../../download-files.include + +# lib name, version +LIBNAME=heimdal +VERSION=7.7.0 +SOURCE=$(LIBNAME)-$(VERSION) +ARCHIVE=$(SOURCE).tar.gz +SHA512=6660939b5a36ce36310721a08a089fb671d1e3d2e8ac74ea4775bfa5f8f772d32de805551456200fe96cc486c092c44beb84f5dd877008bc305490ee971bbf99 +include ../../download-files.include + +APP=$(PLATFORM)/lib/asn1/asn1_compile + +all: .installed-$(PLATFORM) + + +$(PLATFORM): $(DEPS) | $(TARBALLS_LOCATION)/$(ARCHIVE).$(HASH_TYPE) + rm -rf $(PLATFORM); mkdir -p $(PLATFORM) + cd $(PLATFORM); $(ARCHIVE_TOOL) $(ARCHIVE_TOOL_FLAGS) $(TARBALLS_LOCATION)/$(ARCHIVE) + cd $(PLATFORM); patch -p1 -i ../01-disable-libedit.patch + cd $(PLATFORM); patch -p1 -i ../02-autoconf-2.70-configure.patch + cd $(PLATFORM); $(AUTORECONF) -vif + cd $(PLATFORM); ./configure --prefix=$(PREFIX) --disable-shared + +$(APP): $(PLATFORM) + make -C $(PLATFORM)/include + make -C $(PLATFORM)/lib/roken + make -C $(PLATFORM)/lib/vers + make -C $(PLATFORM)/lib/com_err + make -C $(PLATFORM)/lib/asn1 + +.installed-$(PLATFORM): $(APP) + install $(PLATFORM)/lib/asn1/asn1_compile $(PLATFORM)/lib/com_err/compile_et $(PREFIX)/bin + touch $@ + +clean: + $(MAKE) -C $(PLATFORM) clean + rm -f .installed-$(PLATFORM) + +distclean:: + rm -rf $(PLATFORM) .installed-$(PLATFORM) diff --git a/tools/depends/native/ldid/01-disable-openssl-plist.patch b/tools/depends/native/ldid/01-disable-openssl-plist.patch new file mode 100644 index 0000000..d25b2a0 --- /dev/null +++ b/tools/depends/native/ldid/01-disable-openssl-plist.patch @@ -0,0 +1,21 @@ +--- a/Makefile ++++ b/Makefile +@@ -1,13 +1,14 @@ + DESTDIR ?= / + PREFIX ?= /usr/local +-OPENSSL_LDFLAGS := $(shell pkg-config --libs-only-L openssl) +-OPENSSL_CFLAGS := $(shell pkg-config --cflags openssl) +-CFLAGS += $(OPENSSL_CFLAGS) -O2 +-LDFLAGS ?= $(LDID_LIBS) $(OPENSSL_LDFLAGS) ++#OPENSSL_LDFLAGS := $(shell pkg-config --libs-only-L openssl) ++#OPENSSL_CFLAGS := $(shell pkg-config --cflags openssl) ++#CFLAGS += $(OPENSSL_CFLAGS) -O2 -DLDID_NOSMIME=1 -DLDID_NOPLIST=1 ++CFLAGS += -O2 -DLDID_NOSMIME=1 -DLDID_NOPLIST=1 ++#LDFLAGS ?= $(LDID_LIBS) $(OPENSSL_LDFLAGS) + + .PHONY: all clean + LDID_OBJS = ldid.cpp.o lookup2.c.o +-LDID_LIBS = -lplist -lcrypto ++#LDID_LIBS = -lplist -lcrypto + + all: ldid diff --git a/tools/depends/native/ldid/Makefile b/tools/depends/native/ldid/Makefile new file mode 100644 index 0000000..04a209d --- /dev/null +++ b/tools/depends/native/ldid/Makefile @@ -0,0 +1,37 @@ +include ../../Makefile.include +PREFIX=$(NATIVEPREFIX) +PLATFORM=$(NATIVEPLATFORM) +DEPS = ../../Makefile.include Makefile 01-disable-openssl-plist.patch ../../download-files.include + +# lib name, version +LIBNAME=ldid +VERSION=2.1.2-b462a92 +# tarball source: https://github.com/sbingner/ldid/commit/b462a92349c57f38f2a6844adabee940afe01ca6 +SOURCE=$(LIBNAME)-$(VERSION) +ARCHIVE=$(SOURCE).tar.gz +SHA512=9582d747f55e8fd1d54c20b6a3f0825d2ab0cfaffeb6992e53b39343b3aa3936f31e6353d59518f294ecc154adf687fd2dee0405d9b2e594cc16b19409f3c0f4 +include ../../download-files.include + +LIBDYLIB=$(PLATFORM)/ldid + +all: .installed-$(PLATFORM) + + +$(PLATFORM): $(DEPS) | $(TARBALLS_LOCATION)/$(ARCHIVE).$(HASH_TYPE) + rm -rf $(PLATFORM)/*; mkdir -p $(PLATFORM) + cd $(PLATFORM); $(ARCHIVE_TOOL) $(ARCHIVE_TOOL_FLAGS) $(TARBALLS_LOCATION)/$(ARCHIVE) + cd $(PLATFORM); patch -p1 -i ../01-disable-openssl-plist.patch + +$(LIBDYLIB): $(PLATFORM) + $(MAKE) -C $(PLATFORM) + +.installed-$(PLATFORM): $(LIBDYLIB) + cp $(PLATFORM)/ldid $(NATIVEPREFIX)/bin + touch $@ + +clean: + rm -r $(PLATFORM) + rm -f .installed-$(PLATFORM) + +distclean:: + rm -rf $(PLATFORM) .installed-$(PLATFORM) diff --git a/tools/depends/native/libffi/Makefile b/tools/depends/native/libffi/Makefile new file mode 100644 index 0000000..499dfda --- /dev/null +++ b/tools/depends/native/libffi/Makefile @@ -0,0 +1,43 @@ +include ../../Makefile.include +PREFIX=$(NATIVEPREFIX) +PLATFORM=$(NATIVEPLATFORM) +DEPS = ../../Makefile.include Makefile ../../download-files.include + +# lib name, version +LIBNAME=libffi +VERSION=3.2.1 +SOURCE=$(LIBNAME)-$(VERSION) +ARCHIVE=$(SOURCE).tar.gz +SHA512=980ca30a8d76f963fca722432b1fe5af77d7a4e4d2eac5144fbc5374d4c596609a293440573f4294207e1bdd9fda80ad1e1cafb2ffb543df5a275bc3bd546483 +include ../../download-files.include + +# configuration settings +CONFIGURE= CFLAGS="-fPIC" ./configure --prefix=$(NATIVEPREFIX) --disable-shared --disable-builddir + + +LIBDYLIB=$(PLATFORM)/.libs/$(LIBNAME).a + +all: .installed-$(PLATFORM) + + +$(PLATFORM): $(DEPS) | $(TARBALLS_LOCATION)/$(ARCHIVE).$(HASH_TYPE) + rm -rf $(PLATFORM); mkdir -p $(PLATFORM) + cd $(PLATFORM); $(ARCHIVE_TOOL) $(ARCHIVE_TOOL_FLAGS) $(TARBALLS_LOCATION)/$(ARCHIVE) + cd $(PLATFORM); $(CONFIGURE) + +$(LIBDYLIB): $(PLATFORM) + $(MAKE) -j 1 -C $(PLATFORM) + touch $@ + +.installed-$(PLATFORM): $(LIBDYLIB) + $(MAKE) -C $(PLATFORM) install + mkdir -p $(NATIVEPREFIX)/include/ffi + cp $(NATIVEPREFIX)/lib/$(SOURCE)/include/* $(NATIVEPREFIX)/include/ffi/ + touch $@ + +clean: + $(MAKE) -C $(PLATFORM) clean + rm -f .installed-$(PLATFORM) + +distclean:: + rm -rf $(PLATFORM) .installed-$(PLATFORM) diff --git a/tools/depends/native/libjpeg-turbo/01-disable-executables.patch b/tools/depends/native/libjpeg-turbo/01-disable-executables.patch new file mode 100644 index 0000000..8a672b2 --- /dev/null +++ b/tools/depends/native/libjpeg-turbo/01-disable-executables.patch @@ -0,0 +1,118 @@ +--- a/CMakeLists.txt ++++ b/CMakeLists.txt +@@ -211,6 +211,9 @@ + boolean_number(WITH_TURBOJPEG) + option(WITH_FUZZ "Build fuzz targets" FALSE) + ++option(ENABLE_TESTS "Enable testing targets" FALSE) ++boolean_number(ENABLE_TESTS) ++ + macro(report_option var desc) + if(${var}) + message(STATUS "${desc} enabled (${var} = ${${var}})") +@@ -634,6 +637,7 @@ + LINK_FLAGS "${TJMAPFLAG}${TJMAPFILE}") + endif() + ++if(ENABLE_TESTS) + add_executable(tjunittest tjunittest.c tjutil.c md5/md5.c md5/md5hl.c) + target_link_libraries(tjunittest turbojpeg) + +@@ -645,6 +649,7 @@ + + add_executable(tjexample tjexample.c) + target_link_libraries(tjexample turbojpeg) ++endif() + endif() + + if(ENABLE_STATIC) +@@ -656,7 +661,7 @@ + if(NOT MSVC) + set_target_properties(turbojpeg-static PROPERTIES OUTPUT_NAME turbojpeg) + endif() +- ++if(ENABLE_TESTS) + add_executable(tjunittest-static tjunittest.c tjutil.c md5/md5.c + md5/md5hl.c) + target_link_libraries(tjunittest-static turbojpeg-static) +@@ -666,6 +671,7 @@ + if(UNIX) + target_link_libraries(tjbench-static m) + endif() ++endif() + endif() + endif() + +@@ -680,6 +686,7 @@ + set(DJPEG_BMP_SOURCES wrbmp.c wrtarga.c) + endif() + ++if(ENABLE_TESTS) + if(ENABLE_STATIC) + add_executable(cjpeg-static cjpeg.c cdjpeg.c rdgif.c rdppm.c rdswitch.c + ${CJPEG_BMP_SOURCES}) +@@ -699,11 +706,12 @@ + add_executable(rdjpgcom rdjpgcom.c) + + add_executable(wrjpgcom wrjpgcom.c) +- ++endif() + + ############################################################################### + # TESTS + ############################################################################### ++if(ENABLE_TESTS) + + if(WITH_FUZZ) + add_subdirectory(fuzz) +@@ -1419,7 +1427,7 @@ + DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/tjbenchtest) + endif() + endif() +- ++endif() + + ############################################################################### + # INSTALLATION +@@ -1434,8 +1442,10 @@ + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}) ++if(ENABLE_TESTS) + install(TARGETS tjbench + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}) ++endif() + if(NOT CMAKE_VERSION VERSION_LESS "3.1" AND MSVC AND + CMAKE_C_LINKER_SUPPORTS_PDB) + install(FILES "$<TARGET_PDB_FILE:turbojpeg>" +@@ -1452,8 +1462,10 @@ + else() + set(DIR ${CMAKE_CURRENT_BINARY_DIR}) + endif() ++ if(ENABLE_TESTS) + install(PROGRAMS ${DIR}/tjbench-static${EXE} + DESTINATION ${CMAKE_INSTALL_BINDIR} RENAME tjbench${EXE}) ++ endif() + endif() + endif() + install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/turbojpeg.h +@@ -1464,6 +1476,7 @@ + install(TARGETS jpeg-static EXPORT ${CMAKE_PROJECT_NAME}Targets + INCLUDES DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}) ++if(ENABLE_TESTS) + if(NOT ENABLE_SHARED) + if(MSVC_IDE OR XCODE) + set(DIR "${CMAKE_CURRENT_BINARY_DIR}/\${CMAKE_INSTALL_CONFIG_NAME}") +@@ -1478,8 +1491,11 @@ + DESTINATION ${CMAKE_INSTALL_BINDIR} RENAME jpegtran${EXE}) + endif() + endif() ++endif() + ++if(ENABLE_TESTS) + install(TARGETS rdjpgcom wrjpgcom RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}) ++endif() + + install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/README.ijg + ${CMAKE_CURRENT_SOURCE_DIR}/README.md ${CMAKE_CURRENT_SOURCE_DIR}/example.txt diff --git a/tools/depends/native/libjpeg-turbo/LIBJPEG-TURBO-VERSION b/tools/depends/native/libjpeg-turbo/LIBJPEG-TURBO-VERSION new file mode 100644 index 0000000..61eb008 --- /dev/null +++ b/tools/depends/native/libjpeg-turbo/LIBJPEG-TURBO-VERSION @@ -0,0 +1,4 @@ +LIBNAME=libjpeg-turbo +VERSION=2.1.4 +ARCHIVE=$(LIBNAME)-$(VERSION).tar.gz +SHA512=d3e92d614168355827e0ed884ff847cc7df8f6f1fb7b673c6c99afdf61fdfc0372afe5d30fdbf5e743335e2a7a27ca9f510c67d213e5cb2315a8d946e9414575 diff --git a/tools/depends/native/libjpeg-turbo/Makefile b/tools/depends/native/libjpeg-turbo/Makefile new file mode 100644 index 0000000..990c2ba --- /dev/null +++ b/tools/depends/native/libjpeg-turbo/Makefile @@ -0,0 +1,38 @@ +include ../../Makefile.include LIBJPEG-TURBO-VERSION ../../download-files.include +PREFIX=$(NATIVEPREFIX) +PLATFORM=$(NATIVEPLATFORM) +DEPS = ../../Makefile.include LIBJPEG-TURBO-VERSION Makefile ../../download-files.include \ + 01-disable-executables.patch + +CMAKE_OPTIONS := -DCMAKE_TOOLCHAIN_FILE= \ + -DCMAKE_ASM_NASM_COMPILER:FILEPATH=$(NATIVEPREFIX)/bin/nasm \ + -DENABLE_SHARED:BOOL=OFF \ + -DWITH_JPEG8:BOOL=ON \ + -DCMAKE_C_COMPILER="$(CC_BINARY_FOR_BUILD)" \ + -DCMAKE_C_FLAGS="$(NATIVE_CFLAGS)" \ + -DCMAKE_EXE_LINKER_FLAGS="$(NATIVE_LDFLAGS)" \ + -DCMAKE_INSTALL_LIBDIR:STRING=lib + +LIBDYLIB=$(PLATFORM)/build/libjpeg.a + +all: .installed-$(PLATFORM) + +$(PLATFORM): $(DEPS) | $(TARBALLS_LOCATION)/$(ARCHIVE).$(HASH_TYPE) + rm -rf $(PLATFORM)/*; mkdir -p $(PLATFORM) + cd $(PLATFORM); $(ARCHIVE_TOOL) $(ARCHIVE_TOOL_FLAGS) $(TARBALLS_LOCATION)/$(ARCHIVE) + cd $(PLATFORM); patch -p1 -i ../01-disable-executables.patch + cd $(PLATFORM); $(CMAKE) -B build $(CMAKE_OPTIONS) + +$(LIBDYLIB): $(PLATFORM) + $(MAKE) -C $(PLATFORM)/build + +.installed-$(PLATFORM): $(LIBDYLIB) + $(MAKE) -C $(PLATFORM)/build install + touch $@ + +clean: + $(MAKE) -C $(PLATFORM) clean + rm -f .installed-$(PLATFORM) + +distclean:: + rm -rf $(PLATFORM) .installed-$(PLATFORM) diff --git a/tools/depends/native/liblzo2/Makefile b/tools/depends/native/liblzo2/Makefile new file mode 100644 index 0000000..e6ca6e4 --- /dev/null +++ b/tools/depends/native/liblzo2/Makefile @@ -0,0 +1,41 @@ +include ../../Makefile.include +PREFIX=$(NATIVEPREFIX) +PLATFORM=$(NATIVEPLATFORM) +DEPS = ../../Makefile.include Makefile ../../download-files.include + +# lib name, version +LIBNAME=lzo +VERSION=2.10 +SOURCE=$(LIBNAME)-$(VERSION) +ARCHIVE=$(SOURCE).tar.gz +SHA512=a3dae5e4a6b93b1f5bf7435e8ab114a9be57252e9efc5dd444947d7a2d031b0819f34bcaeb35f60b5629a01b1238d738735a64db8f672be9690d3c80094511a4 +include ../../download-files.include + +# configuration settings +CONFIGURE=cp -f $(CONFIG_SUB) $(CONFIG_GUESS) autoconf/; \ + ./configure --prefix=$(PREFIX) --enable-shared + +LIBDYLIB=$(PLATFORM)/src/.libs/lib$(LIBNAME)2.a + +all: .installed-$(PLATFORM) + + +$(PLATFORM): $(DEPS) | $(TARBALLS_LOCATION)/$(ARCHIVE).$(HASH_TYPE) + rm -rf $(PLATFORM)/*; mkdir -p $(PLATFORM) + cd $(PLATFORM); $(ARCHIVE_TOOL) $(ARCHIVE_TOOL_FLAGS) $(TARBALLS_LOCATION)/$(ARCHIVE) + cd $(PLATFORM); $(CONFIGURE) + +$(LIBDYLIB): $(PLATFORM) + $(MAKE) -C $(PLATFORM) + +.installed-$(PLATFORM): $(LIBDYLIB) + $(MAKE) -C $(PLATFORM) install + touch $@ + +clean: + $(MAKE) -C $(PLATFORM) clean + rm -f .installed-$(PLATFORM) + +distclean:: + rm -rf $(PLATFORM) .installed-$(PLATFORM) + diff --git a/tools/depends/native/libpng/Makefile b/tools/depends/native/libpng/Makefile new file mode 100644 index 0000000..6059b69 --- /dev/null +++ b/tools/depends/native/libpng/Makefile @@ -0,0 +1,41 @@ +include ../../Makefile.include +PREFIX=$(NATIVEPREFIX) +PLATFORM=$(NATIVEPLATFORM) +DEPS = ../../Makefile.include Makefile ../../download-files.include + +# lib name, version +LIBNAME=libpng +VERSION=1.6.37 +SOURCE=$(LIBNAME)-$(VERSION) +ARCHIVE=$(SOURCE).tar.gz +SHA512=2ce2b855af307ca92a6e053f521f5d262c36eb836b4810cb53c809aa3ea2dcc08f834aee0ffd66137768a54397e28e92804534a74abb6fc9f6f3127f14c9c338 +include ../../download-files.include + +# configuration settings +CONFIGURE=cp -f $(CONFIG_SUB) $(CONFIG_GUESS) .; \ + ./configure --prefix=$(PREFIX) + +LIBDYLIB=$(PLATFORM)/.libs/$(LIBNAME)16.a + +all: .installed-$(PLATFORM) + + +$(PLATFORM): $(DEPS) | $(TARBALLS_LOCATION)/$(ARCHIVE).$(HASH_TYPE) + rm -rf $(PLATFORM)/*; mkdir -p $(PLATFORM) + cd $(PLATFORM); $(ARCHIVE_TOOL) $(ARCHIVE_TOOL_FLAGS) $(TARBALLS_LOCATION)/$(ARCHIVE) + cd $(PLATFORM); $(CONFIGURE) + +$(LIBDYLIB): $(PLATFORM) + $(MAKE) -C $(PLATFORM) + touch $@ + +.installed-$(PLATFORM): $(LIBDYLIB) + $(MAKE) -C $(PLATFORM) install + touch $@ + +clean: + $(MAKE) -C $(PLATFORM) clean + rm -f .installed-$(PLATFORM) + +distclean:: + rm -rf $(PLATFORM) .installed-$(PLATFORM) diff --git a/tools/depends/native/libtool/Makefile b/tools/depends/native/libtool/Makefile new file mode 100644 index 0000000..ebbfdaf --- /dev/null +++ b/tools/depends/native/libtool/Makefile @@ -0,0 +1,41 @@ +include ../../Makefile.include +PREFIX=$(NATIVEPREFIX) +PLATFORM=$(NATIVEPLATFORM) +DEPS = ../../Makefile.include Makefile ../../download-files.include + +# lib name, version +LIBNAME=libtool +VERSION=2.4.6 +SOURCE=$(LIBNAME)-$(VERSION) +ARCHIVE=$(SOURCE).tar.gz +SHA512=3233d81cb2739a54b840a0a82064eebbfaa4fb442fb993a35d6bd41d8395c51f038c90ae048b9252f172d0a5bbfb4b36e2b13d4477001f9ff7d4124237819a18 +include ../../download-files.include + +# configuration settings +CONFIGURE=./configure --prefix=$(PREFIX) \ + --disable-shared --disable-ltdl-install + +LIBDYLIB=$(PLATFORM)/libtool + +all: .installed-$(PLATFORM) + + +$(PLATFORM): $(DEPS) | $(TARBALLS_LOCATION)/$(ARCHIVE).$(HASH_TYPE) + -rm -rf $(PLATFORM)/*; mkdir -p $(PLATFORM) + cd $(PLATFORM); $(ARCHIVE_TOOL) $(ARCHIVE_TOOL_FLAGS) $(TARBALLS_LOCATION)/$(ARCHIVE) + cd $(PLATFORM); $(CONFIGURE) + +$(LIBDYLIB): $(PLATFORM) + $(MAKE) -C $(PLATFORM) + touch $@ + +.installed-$(PLATFORM): $(LIBDYLIB) + $(MAKE) -C $(PLATFORM) install + touch $@ + +clean: + $(MAKE) -C $(PLATFORM) clean + rm -f .installed-$(PLATFORM) + +distclean:: + rm -rf $(PLATFORM) .installed-$(PLATFORM) diff --git a/tools/depends/native/m4/Makefile b/tools/depends/native/m4/Makefile new file mode 100644 index 0000000..016f098 --- /dev/null +++ b/tools/depends/native/m4/Makefile @@ -0,0 +1,38 @@ +include ../../Makefile.include +PREFIX=$(NATIVEPREFIX) +PLATFORM=$(NATIVEPLATFORM) +DEPS = ../../Makefile.include Makefile ../../download-files.include + +# lib name, version +LIBNAME=m4 +VERSION=1.4.19 +SOURCE=$(LIBNAME)-$(VERSION) +ARCHIVE=$(SOURCE).tar.xz +SHA512=47f595845c89709727bda0b3fc78e3188ef78ec818965b395532e7041cabe9e49677ee4aca3d042930095a7f8df81de3da1026b23b6897be471f6cf13ddd512b +include ../../download-files.include + +# configuration settings +CONFIGURE=./configure --prefix=$(PREFIX) + +LIBDYLIB=$(PLATFORM)/src/$(LIBNAME) + +all: .installed-$(PLATFORM) + +$(PLATFORM): $(DEPS) | $(TARBALLS_LOCATION)/$(ARCHIVE).$(HASH_TYPE) + -rm -rf $(PLATFORM)/*; mkdir -p $(PLATFORM) + cd $(PLATFORM); $(ARCHIVE_TOOL) $(ARCHIVE_TOOL_FLAGS) $(TARBALLS_LOCATION)/$(ARCHIVE) + cd $(PLATFORM); $(CONFIGURE) + +$(LIBDYLIB): $(PLATFORM) + $(MAKE) -C $(PLATFORM) + +.installed-$(PLATFORM): $(LIBDYLIB) + $(MAKE) -C $(PLATFORM) install + touch $@ + +clean: + $(MAKE) -C $(PLATFORM) clean + rm -f .installed-$(PLATFORM) + +distclean:: + rm -rf $(PLATFORM) .installed-$(PLATFORM) diff --git a/tools/depends/native/meson/Makefile b/tools/depends/native/meson/Makefile new file mode 100644 index 0000000..553d4a3 --- /dev/null +++ b/tools/depends/native/meson/Makefile @@ -0,0 +1,35 @@ +include ../../Makefile.include +PLATFORM=$(NATIVEPLATFORM) +DEPS =../../Makefile.include Makefile ../../download-files.include + +# lib name, version +LIBNAME=meson +VERSION=0.59.2 +SOURCE=$(LIBNAME)-$(VERSION) +ARCHIVE=$(SOURCE).tar.gz +SHA512=126ac3a6c6b9e1fba1b3ac163f02d1eb0b61fedb312bcfe4996f6150522688d424f47283070c95101cc456afe9ea5cb462fb38f368d0c732952ffb8c600fda00 +include ../../download-files.include + +LIBDYLIB=$(PLATFORM)/build + +all: .installed-$(PLATFORM) + + +$(PLATFORM): $(DEPS) | $(TARBALLS_LOCATION)/$(ARCHIVE).$(HASH_TYPE) + rm -rf $(PLATFORM)/*; mkdir -p $(PLATFORM) + cd $(PLATFORM); $(ARCHIVE_TOOL) $(ARCHIVE_TOOL_FLAGS) $(TARBALLS_LOCATION)/$(ARCHIVE) + cd $(PLATFORM); $(NATIVEPREFIX)/bin/python3 setup.py config + +$(LIBDYLIB): $(PLATFORM) + cd $(PLATFORM); $(NATIVEPREFIX)/bin/python3 setup.py build + +.installed-$(PLATFORM): $(LIBDYLIB) + cd $(PLATFORM); $(NATIVEPREFIX)/bin/python3 setup.py install --prefix="$(NATIVEPREFIX)" + touch $@ + +clean: + $(MAKE) -C $(PLATFORM) clean + rm -f .installed-$(PLATFORM) + +distclean:: + rm -rf $(PLATFORM) .installed-$(PLATFORM) diff --git a/tools/depends/native/nasm/Makefile b/tools/depends/native/nasm/Makefile new file mode 100644 index 0000000..c3b77e3 --- /dev/null +++ b/tools/depends/native/nasm/Makefile @@ -0,0 +1,39 @@ +include ../../Makefile.include +PREFIX=$(NATIVEPREFIX) +PLATFORM=$(NATIVEPLATFORM) +DEPS = ../../Makefile.include Makefile ../../download-files.include + +APPNAME=nasm +VERSION=2.15.05 +SOURCE=$(APPNAME)-$(VERSION) +ARCHIVE=$(SOURCE).tar.xz +SHA512=512f90a2584f1c5811429274b97c64a2cedf37b9fdeffb1bcd0ea64afd9ecc19a2d7877ca8f1e05393aa324153fc9f39ea51dacbf8d25a7d5a2d7728c925dba7 +include ../../download-files.include + +# configuration settings +CONFIGURE=./configure --prefix=$(PREFIX) + +APP=$(PLATFORM)/$(APPNAME) + +all: .installed-$(PLATFORM) + + +$(PLATFORM): $(DEPS) | $(TARBALLS_LOCATION)/$(ARCHIVE).$(HASH_TYPE) + rm -rf $(PLATFORM)/*; mkdir -p $(PLATFORM) + cd $(PLATFORM); $(ARCHIVE_TOOL) $(ARCHIVE_TOOL_FLAGS) $(TARBALLS_LOCATION)/$(ARCHIVE) + cd $(PLATFORM); $(CONFIGURE) + +$(APP): $(PLATFORM) + $(MAKE) -C $(PLATFORM) + +.installed-$(PLATFORM): $(APP) + $(MAKE) -C $(PLATFORM) install + touch $@ + +clean: + $(MAKE) -C $(PLATFORM) clean + rm .installed-$(PLATFORM) + +distclean:: + rm -rf $(PLATFORM) .installed-$(PLATFORM) + diff --git a/tools/depends/native/ninja/Makefile b/tools/depends/native/ninja/Makefile new file mode 100644 index 0000000..f54cf8d --- /dev/null +++ b/tools/depends/native/ninja/Makefile @@ -0,0 +1,33 @@ +include ../../Makefile.include +PLATFORM=$(NATIVEPLATFORM) +DEPS = ../../Makefile.include Makefile ../../download-files.include + +# lib name, version +LIBNAME=ninja +VERSION=1.10.2 +SOURCE=$(LIBNAME)-$(VERSION) +ARCHIVE=$(SOURCE).tar.gz +SHA512=895412ae1cbc83c656e92f282602a29300e08274e9dea0da4464202ae556e7a1ab03bec057f23da4756bbd91bd2d744cd7a64b336740fd2782bb4db5c3b7b496 +include ../../download-files.include + +LIBDYLIB=$(PLATFORM)/ninja + +all: .installed-$(PLATFORM) + + +$(PLATFORM): $(DEPS) | $(TARBALLS_LOCATION)/$(ARCHIVE).$(HASH_TYPE) + rm -rf $(PLATFORM)/*; mkdir -p $(PLATFORM) + cd $(PLATFORM); $(ARCHIVE_TOOL) $(ARCHIVE_TOOL_FLAGS) $(TARBALLS_LOCATION)/$(ARCHIVE) + +$(LIBDYLIB): $(PLATFORM) + cd $(PLATFORM); CXX="$(CXX_FOR_BUILD)" AR="$(AR_FOR_BUILD)" CFLAGS="$(NATIVE_CFLAGS)" LDFLAGS="$(NATIVE_LDFLAGS)" $(NATIVEPREFIX)/bin/python3 configure.py --bootstrap + +.installed-$(PLATFORM): $(LIBDYLIB) + install $(PLATFORM)/ninja $(NATIVEPREFIX)/bin + touch $@ + +clean: + rm -rf $(PLATFORM) .installed-$(PLATFORM) + +distclean:: + rm -rf $(PLATFORM) .installed-$(PLATFORM) diff --git a/tools/depends/native/openssl/Makefile b/tools/depends/native/openssl/Makefile new file mode 100644 index 0000000..189acf0 --- /dev/null +++ b/tools/depends/native/openssl/Makefile @@ -0,0 +1,54 @@ +include ../../Makefile.include +PLATFORM=$(NATIVEPLATFORM) +DEPS = ../../Makefile.include Makefile ../../download-files.include + +# lib name, version +LIBNAME=openssl +VERSION=1.1.1k +SOURCE=$(LIBNAME)-$(VERSION) +ARCHIVE=$(SOURCE).tar.gz +SHA512=73cd042d4056585e5a9dd7ab68e7c7310a3a4c783eafa07ab0b560e7462b924e4376436a6d38a155c687f6942a881cfc0c1b9394afcde1d8c46bf396e7d51121 +include ../../download-files.include + +# configuration settings +CONFIGURE=MACHINE=$(PLATFORM) ./config no-shared zlib no-asm --prefix=$(NATIVEPREFIX) --with-zlib-include=$(NATIVEPREFIX)/include --with-zlib-lib=$(NATIVEPREFIX)/lib + +ifeq ($(NATIVE_OS), osx) + ifeq ($(BUILD_CPU), x86_64) + CONFIGURE=./Configure darwin64-$(BUILD_CPU)-cc zlib no-asm no-shared --prefix=$(NATIVEPREFIX) + else + CONFIGURE=./Configure darwin64-arm64-cc zlib no-asm no-shared --prefix=$(NATIVEPREFIX) + endif +endif + +CFLAGS=$(NATIVE_CFLAGS) +LDFLAGS=$(NATIVE_LDFLAGS) +CXXFLAGS=$(NATIVE_CXXFLAGS) +CPPFLAGS=$(NATIVE_CPPFLAGS) + +export CFLAGS CPPFLAGS CXXFLAGS LDFLAGS + +LIBDYLIB=$(PLATFORM)/libssl.a + +all: .installed-$(PLATFORM) + + +$(PLATFORM): $(DEPS) | $(TARBALLS_LOCATION)/$(ARCHIVE).$(HASH_TYPE) + rm -rf $(PLATFORM); mkdir -p $(PLATFORM) + cd $(PLATFORM); $(ARCHIVE_TOOL) $(ARCHIVE_TOOL_FLAGS) $(TARBALLS_LOCATION)/$(ARCHIVE) + cd $(PLATFORM); $(CONFIGURE) + +$(LIBDYLIB): $(PLATFORM) + $(MAKE) -C $(PLATFORM) + touch $@ + +.installed-$(PLATFORM): $(LIBDYLIB) + $(MAKE) -C $(PLATFORM) install_sw + touch $@ + +clean: + $(MAKE) -C $(PLATFORM) clean + rm -f .installed-$(PLATFORM) + +distclean:: + rm -rf $(PLATFORM) .installed-$(PLATFORM) diff --git a/tools/depends/native/pcre/Makefile b/tools/depends/native/pcre/Makefile new file mode 100644 index 0000000..d50252f --- /dev/null +++ b/tools/depends/native/pcre/Makefile @@ -0,0 +1,44 @@ +include ../../Makefile.include +PREFIX=$(NATIVEPREFIX) +PLATFORM=$(NATIVEPLATFORM) +DEPS = ../../Makefile.include Makefile ../../download-files.include + +# lib name, version +LIBNAME=pcre +VERSION=8.45 +SOURCE=$(LIBNAME)-$(VERSION) +ARCHIVE=$(SOURCE).tar.bz2 +SHA512=91bff52eed4a2dfc3f3bfdc9c672b88e7e2ffcf3c4b121540af8a4ae8c1ce05178430aa6b8000658b9bb7b4252239357250890e20ceb84b79cdfcde05154061a +include ../../download-files.include + +# configuration settings +CONFIGURE=./configure --prefix=$(PREFIX) --disable-cpp \ + --disable-shared --disable-stack-for-recursion \ + --enable-pcre8 --disable-pcre16 --disable-pcre32 \ + --enable-jit --enable-utf --enable-unicode-properties + + +LIBDYLIB=$(PLATFORM)/.libs/lib$(LIBNAME).so + +all: .installed-$(PLATFORM) + + +$(PLATFORM): $(DEPS) | $(TARBALLS_LOCATION)/$(ARCHIVE).$(HASH_TYPE) + rm -rf $(PLATFORM)/*; mkdir -p $(PLATFORM) + cd $(PLATFORM); $(ARCHIVE_TOOL) $(ARCHIVE_TOOL_FLAGS) $(TARBALLS_LOCATION)/$(ARCHIVE) + cd $(PLATFORM); $(CONFIGURE) + +$(LIBDYLIB): $(PLATFORM) + $(MAKE) -C $(PLATFORM) + +.installed-$(PLATFORM): $(LIBDYLIB) + $(MAKE) -C $(PLATFORM) install + touch $(LIBDYLIB) + touch $@ + +clean: + $(MAKE) -C $(PLATFORM) clean + rm -f .installed-$(PLATFORM) + +distclean:: + rm -rf $(PLATFORM) .installed-$(PLATFORM) diff --git a/tools/depends/native/perlmodule-parseyapp/Makefile b/tools/depends/native/perlmodule-parseyapp/Makefile new file mode 100644 index 0000000..85dec65 --- /dev/null +++ b/tools/depends/native/perlmodule-parseyapp/Makefile @@ -0,0 +1,43 @@ +include ../../Makefile.include +PREFIX=$(NATIVEPREFIX) +PLATFORM=$(NATIVEPLATFORM) +DEPS = ../../Makefile.include Makefile ../../download-files.include + +# lib name, version +LIBNAME=Parse-Yapp +VERSION=1.21 +SOURCE=$(LIBNAME)-$(VERSION) +ARCHIVE=$(SOURCE).tar.gz +SHA512=dbf6182d4813ff7e355ea1713c748bfdf8290040a93f123acec645c7a1733fe457ab6e0ab51c4ec83cf82bc43d7fb35cbf89875df7b5c2ffc9635e85458cfeee +include ../../download-files.include + +# configuration settings +CONFIGURE=./configure --prefix=$(PREFIX) + +# clear env vars in case already active on system +export PERL_MB_OPT= +export PERL_MM_OPT= + +LIBDYLIB=$(PLATFORM)/bin/autoconf + +all: .installed-$(PLATFORM) + + +$(PLATFORM): $(DEPS) | $(TARBALLS_LOCATION)/$(ARCHIVE).$(HASH_TYPE) + -rm -rf $(PLATFORM)/*; mkdir -p $(PLATFORM) + cd $(PLATFORM); $(ARCHIVE_TOOL) $(ARCHIVE_TOOL_FLAGS) $(TARBALLS_LOCATION)/$(ARCHIVE) + +$(LIBDYLIB): $(PLATFORM) + cd $(PLATFORM); perl Makefile.PL PREFIX=$(NATIVEPREFIX) + cd $(PLATFORM); $(MAKE) + +.installed-$(PLATFORM): $(LIBDYLIB) + cd $(PLATFORM); $(MAKE) install + touch $@ + +clean: + $(MAKE) -C $(PLATFORM) clean + rm -f .installed-$(PLATFORM) + +distclean:: + rm -rf $(PLATFORM) .installed-$(PLATFORM) diff --git a/tools/depends/native/pkg-config/Makefile b/tools/depends/native/pkg-config/Makefile new file mode 100644 index 0000000..1ba81b7 --- /dev/null +++ b/tools/depends/native/pkg-config/Makefile @@ -0,0 +1,45 @@ +include ../../Makefile.include +PREFIX=$(NATIVEPREFIX) +PLATFORM=$(NATIVEPLATFORM) +DEPS = ../../Makefile.include Makefile ../../download-files.include + +# lib name, version +# lib name, version +LIBNAME=pkg-config +VERSION=0.29.2 +SOURCE=$(LIBNAME)-$(VERSION) +ARCHIVE=$(SOURCE).tar.gz +SHA512=4861ec6428fead416f5cbbbb0bbad10b9152967e481d4b0ff2eb396a9f297f552984c9bb72f6864a37dcd8fca1d9ccceda3ef18d8f121938dbe4fdf2b870fe75 +include ../../download-files.include + +PC_PATH=$(PREFIX)/lib/pkgconfig:$(PREFIX)/share/pkgconfig +ifeq ($(CROSS_COMPILING),no) +PC_PATH:=$(PC_PATH):/usr/lib/pkgconfig:/usr/lib/$(HOST)/pkgconfig:/usr/share/pkgconfig +endif + +# configuration settings +CONFIGURE=./configure --prefix=$(PREFIX) --enable-indirect-deps --with-pc-path=$(PC_PATH) --with-internal-glib +LIBDYLIB=$(PLATFORM)/pkg-config + +all: .installed-$(PLATFORM) + + +$(PLATFORM): $(DEPS) | $(TARBALLS_LOCATION)/$(ARCHIVE).$(HASH_TYPE) + -rm -rf $(PLATFORM)/*; mkdir -p $(PLATFORM) + cd $(PLATFORM); $(ARCHIVE_TOOL) $(ARCHIVE_TOOL_FLAGS) $(TARBALLS_LOCATION)/$(ARCHIVE) + cd $(PLATFORM); $(CONFIGURE) + cd $(PLATFORM); sed -ie "s|LN = ln|LN = ln -f|" Makefile + +$(LIBDYLIB): $(PLATFORM) + $(MAKE) -C $(PLATFORM) + +.installed-$(PLATFORM): $(LIBDYLIB) + $(MAKE) -C $(PLATFORM) install + touch $@ + +clean: + $(MAKE) -C $(PLATFORM) clean + rm -f .installed-$(PLATFORM) + +distclean:: + rm -rf $(PLATFORM) .installed-$(PLATFORM) diff --git a/tools/depends/native/pugixml/Makefile b/tools/depends/native/pugixml/Makefile new file mode 100644 index 0000000..03ef707 --- /dev/null +++ b/tools/depends/native/pugixml/Makefile @@ -0,0 +1,43 @@ +include ../../Makefile.include +PREFIX=$(NATIVEPREFIX) +PLATFORM=$(NATIVEPLATFORM) +DEPS =../../Makefile.include Makefile ../../download-files.include + +# lib name, version +LIBNAME=pugixml +VERSION=1.10 +SOURCE=$(LIBNAME)-$(VERSION) +ARCHIVE=$(SOURCE).tar.gz +SHA512=bfc80661005d0a0fb82ca6d5299e5efdd1bb468e11ee52d7ee9367e15776d28efb60266ce03842715cd43aae023afc2b369797bb3cbecd6d6a65c3ae3903e469 +include ../../download-files.include + +LIBDYLIB=$(PLATFORM)/build/libpugixml.a + +CMAKE_OPTIONS := -DCMAKE_INSTALL_LIBDIR=lib \ + -DCMAKE_INSTALL_PREFIX=$(NATIVEPREFIX) \ + $(CMAKE_OPTIONS) + +BUILDDIR = $(PLATFORM)/build + +all: .installed-$(PLATFORM) + + +$(PLATFORM): $(DEPS) | $(TARBALLS_LOCATION)/$(ARCHIVE).$(HASH_TYPE) + rm -rf $(PLATFORM)/*; mkdir -p $(PLATFORM) + cd $(PLATFORM); $(ARCHIVE_TOOL) $(ARCHIVE_TOOL_FLAGS) $(TARBALLS_LOCATION)/$(ARCHIVE) + mkdir -p $(BUILDDIR) + cd $(BUILDDIR); $(NATIVEPREFIX)/bin/cmake $(CMAKE_OPTIONS) .. + +$(LIBDYLIB): $(PLATFORM) + $(MAKE) -C $(BUILDDIR) + +.installed-$(PLATFORM): $(LIBDYLIB) + $(MAKE) -C $(BUILDDIR) install + touch $@ + +clean: + $(MAKE) -C $(BUILDDIR) clean + rm -f .installed-$(PLATFORM) + +distclean: + rm -rf $(PLATFORM) .installed-$(PLATFORM) diff --git a/tools/depends/native/python3/01-distutil-flags.patch b/tools/depends/native/python3/01-distutil-flags.patch new file mode 100644 index 0000000..28cd2f9 --- /dev/null +++ b/tools/depends/native/python3/01-distutil-flags.patch @@ -0,0 +1,12 @@ +--- a/Lib/distutils/sysconfig.py ++++ b/Lib/distutils/sysconfig.py +@@ -214,6 +214,9 @@ + (cc, cxx, cflags, ccshared, ldshared, shlib_suffix, ar, ar_flags) = \ + get_config_vars('CC', 'CXX', 'CFLAGS', + 'CCSHARED', 'LDSHARED', 'SHLIB_SUFFIX', 'AR', 'ARFLAGS') ++ # get_config_vars returns host vars. clear cflags, ldshared for crosscompile use ++ cflags = "" ++ ldshared = cc + " -shared" + + if 'CC' in os.environ: + newcc = os.environ['CC'] diff --git a/tools/depends/native/python3/Makefile b/tools/depends/native/python3/Makefile new file mode 100644 index 0000000..74ebe06 --- /dev/null +++ b/tools/depends/native/python3/Makefile @@ -0,0 +1,46 @@ +include ../../Makefile.include PYTHON3-VERSION ../../download-files.include +PLATFORM=$(NATIVEPLATFORM) +DEPS = ../../Makefile.include Makefile PYTHON3-VERSION ../../download-files.include \ + 01-distutil-flags.patch + +CONFIGURE=./configure --prefix=$(NATIVEPREFIX) \ + --disable-shared \ + --disable-framework \ + --without-pymalloc \ + --with-system-ffi + +NATIVE_SITEPACKAGES=$(NATIVEPREFIX)/lib/python$(PYTHON_VERSION)/site-packages + +ifeq ($(OS),linux) + CONFIGURE += --with-system-expat +endif + +LIBDYLIB=$(PLATFORM)/python +ifeq ($(NATIVE_OS), osx) + # Case insensitive FS will add .exe to buildexe regardless of --with-suffix=no + LIBDYLIB=$(PLATFORM)/python.exe +endif + +all: .installed-$(PLATFORM) + +$(PLATFORM): $(DEPS) | $(TARBALLS_LOCATION)/$(ARCHIVE).$(HASH_TYPE) + rm -rf $(PLATFORM)/*; mkdir -p $(PLATFORM) + cd $(PLATFORM); $(ARCHIVE_TOOL) $(ARCHIVE_TOOL_FLAGS) $(TARBALLS_LOCATION)/$(ARCHIVE) + cd $(PLATFORM); $(CONFIGURE) + +$(LIBDYLIB): $(PLATFORM) + cd $(PLATFORM); $(MAKE) + +.installed-$(PLATFORM): $(LIBDYLIB) + cd $(PLATFORM); patch -p1 -i ../01-distutil-flags.patch + cd $(PLATFORM); $(MAKE) install +# Sed patch setuptools that is installed via ensurepip as we cant patch the source + cd $(NATIVE_SITEPACKAGES); sed -ie "s|cflags = cflags + ' ' + os.environ\['CFLAGS'\]|cflags = os.environ\['CFLAGS'\]|" setuptools/_distutils/sysconfig.py + touch $(LIBDYLIB) + touch $@ + +clean: + rm -rf $(PLATFORM) .installed-$(PLATFORM) + +distclean:: + rm -rf $(PLATFORM) .installed-$(PLATFORM) diff --git a/tools/depends/native/python3/PYTHON3-VERSION b/tools/depends/native/python3/PYTHON3-VERSION new file mode 100644 index 0000000..290e333 --- /dev/null +++ b/tools/depends/native/python3/PYTHON3-VERSION @@ -0,0 +1,4 @@ +LIBNAME=Python +VERSION=3.11.2 +ARCHIVE=$(LIBNAME)-$(VERSION).tar.xz +SHA512=5684ec7eae2dce26facc54d448ccdb6901bbfa1cab03abbe8fd34e4268a2b701daa13df15903349492447035be78380d473389e8703b4e910a65b088d2462e8b diff --git a/tools/depends/native/swig/Makefile b/tools/depends/native/swig/Makefile new file mode 100644 index 0000000..045cbcc --- /dev/null +++ b/tools/depends/native/swig/Makefile @@ -0,0 +1,41 @@ +include ../../Makefile.include +PREFIX=$(NATIVEPREFIX) +PLATFORM=$(NATIVEPLATFORM) + +DEPS = ../../Makefile.include Makefile ../../download-files.include + +# lib name, version +LIBNAME=swig +VERSION=4.0.2 +SOURCE=$(LIBNAME)-$(VERSION) +ARCHIVE=$(SOURCE).tar.gz +SHA512=05e7da70ce6d9a733b96c0bcfa3c1b82765bd859f48c74759bbf4bb1467acb1809caa310cba5e2b3280cd704fca249eaa0624821dffae1d2a75097c7f55d14ed +include ../../download-files.include + +# configuration settings +CONFIGURE=./configure --prefix=$(PREFIX) --without-alllang --without-x --disable-ccache + +LIBDYLIB=$(PLATFORM)/swig + +all: .installed-$(PLATFORM) + + +$(PLATFORM): $(DEPS) | $(TARBALLS_LOCATION)/$(ARCHIVE).$(HASH_TYPE) + rm -rf $(PLATFORM)/*; mkdir -p $(PLATFORM) + cd $(PLATFORM); $(ARCHIVE_TOOL) $(ARCHIVE_TOOL_FLAGS) $(TARBALLS_LOCATION)/$(ARCHIVE) + cd $(PLATFORM); $(CONFIGURE) + +$(LIBDYLIB): $(PLATFORM) + $(MAKE) -C $(PLATFORM) + +.installed-$(PLATFORM): $(LIBDYLIB) + $(MAKE) -C $(PLATFORM) install + touch $@ + +clean: + $(MAKE) -C $(PLATFORM) clean + rm -f .installed-$(PLATFORM) + +distclean:: + rm -rf $(PLATFORM) .installed-$(PLATFORM) + diff --git a/tools/depends/native/tar/Makefile b/tools/depends/native/tar/Makefile new file mode 100644 index 0000000..a3624ff --- /dev/null +++ b/tools/depends/native/tar/Makefile @@ -0,0 +1,45 @@ +include ../../Makefile.include +PREFIX=$(NATIVEPREFIX) +PLATFORM=$(NATIVEPLATFORM) +DEPS = ../../Makefile.include Makefile ../../download-files.include + +# app name, version +APPNAME=tar +VERSION=1.34 +SOURCE=$(APPNAME)-$(VERSION) +ARCHIVE=$(SOURCE).tar.xz +SHA512=5e77c4a7b49983ad7d15238c2bce28be7a8aa437b4b1815fc00abd13096da308b6bba196cc6e3ed79d85e62823d520ae0d8fcda2d93873842cf84dc3369fc902 +include ../../download-files.include + +export PATH:=$(PREFIX)/bin:$(PATH) +CONFIGURE=./configure --prefix=$(PREFIX) \ + --program-transform-name=s/tar/gtar/ \ + --disable-dependency-tracking \ + $(PLATFORM_CONFIGURE) + +APP=$(PLATFORM)/src/tar +APPBIN=$(PREFIX)/bin/tar + +all: .installed-$(PLATFORM) + + +$(PLATFORM): $(DEPS) | $(TARBALLS_LOCATION)/$(ARCHIVE).$(HASH_TYPE) + -rm -rf $(PLATFORM)/*; mkdir -p $(PLATFORM) + cd $(PLATFORM); $(ARCHIVE_TOOL) $(ARCHIVE_TOOL_FLAGS) $(TARBALLS_LOCATION)/$(ARCHIVE) + cd $(PLATFORM); $(AUTORECONF) + cd $(PLATFORM); $(CONFIGURE) + +$(APP): $(PLATFORM) + $(MAKE) -C $(PLATFORM) + +.installed-$(PLATFORM): $(APP) + $(MAKE) -C $(PLATFORM) install + rm -f $(PREFIX)/bin/tar $(PREFIX)/bin/gnutar + cd $(PREFIX)/bin; ln -s gtar tar; ln -s gtar gnutar + touch $@ + +clean: + $(MAKE) -C $(PLATFORM) clean + +distclean:: + rm -rf $(PLATFORM) .installed-$(PLATFORM) diff --git a/tools/depends/native/wayland-scanner/Makefile b/tools/depends/native/wayland-scanner/Makefile new file mode 100644 index 0000000..ea46e21 --- /dev/null +++ b/tools/depends/native/wayland-scanner/Makefile @@ -0,0 +1,39 @@ +include ../../Makefile.include +PREFIX=$(NATIVEPREFIX) +PLATFORM=$(NATIVEPLATFORM) +DEPS =../../Makefile.include Makefile ../../download-files.include + +APPNAME=wayland-scanner +PROJECTNAME=wayland +VERSION=1.17.0 +SOURCE=$(PROJECTNAME)-$(VERSION) +ARCHIVE=$(SOURCE).tar.xz +SHA512=c5051aab5ff078b368c196ecfedb33ccd961265bb914845d7ed81de361bb86ae18299575baa6c4eceb0d82cf8b495e8293f31b51d1cbc05d84af0a199ab3f946 +include ../../download-files.include + +# configuration settings +CONFIGURE=./configure --prefix=$(PREFIX) --disable-libraries --disable-documentation --disable-dtd-validation + +APP=$(PLATFORM)/wayland-scanner + +all: .installed-$(PLATFORM) + + +$(PLATFORM): $(DEPS) | $(TARBALLS_LOCATION)/$(ARCHIVE).$(HASH_TYPE) + rm -rf $(PLATFORM)/*; mkdir -p $(PLATFORM) + cd $(PLATFORM); $(ARCHIVE_TOOL) $(ARCHIVE_TOOL_FLAGS) $(TARBALLS_LOCATION)/$(ARCHIVE) + cd $(PLATFORM); $(CONFIGURE) + +$(APP): $(PLATFORM) + $(MAKE) -C $(PLATFORM) + +.installed-$(PLATFORM): $(APP) + $(MAKE) -C $(PLATFORM) install + touch $@ + +clean: + $(MAKE) -C $(PLATFORM) clean + rm -f .installed-$(PLATFORM) + +distclean:: + rm -rf $(PLATFORM) .installed-$(PLATFORM) diff --git a/tools/depends/native/waylandpp-scanner/Makefile b/tools/depends/native/waylandpp-scanner/Makefile new file mode 100644 index 0000000..571412e --- /dev/null +++ b/tools/depends/native/waylandpp-scanner/Makefile @@ -0,0 +1,47 @@ +include ../../Makefile.include +PREFIX=$(NATIVEPREFIX) +PLATFORM=$(NATIVEPLATFORM) +DEPS =../../Makefile.include Makefile ../../download-files.include + +# lib name, version +LIBNAME=waylandpp +VERSION=0.2.8 +SOURCE=$(LIBNAME)-$(VERSION) +ARCHIVE=$(SOURCE).tar.gz +SHA512=bf1b8a9e69b87547fc65989b9eaff88a442d8b2f01f5446cef960000b093390b1e557536837fbf38bb6d9a4f93e3985ea34c3253f94925b0f571b4606c980832 +include ../../download-files.include + +APP=$(PLATFORM)/wayland-scanner++ + +CMAKE_OPTIONS := -DBUILD_DOCUMENTATION=OFF \ + -DBUILD_LIBRARIES=OFF \ + -DBUILD_EXAMPLES=OFF \ + -DBUILD_SCANNER=ON \ + -DCMAKE_INSTALL_LIBDIR=lib \ + -DCMAKE_INSTALL_PREFIX=$(NATIVEPREFIX) \ + $(CMAKE_OPTIONS) + +BUILDDIR = $(PLATFORM)/build + +all: .installed-$(PLATFORM) + + +$(PLATFORM): $(DEPS) | $(TARBALLS_LOCATION)/$(ARCHIVE).$(HASH_TYPE) + rm -rf $(PLATFORM)/*; mkdir -p $(PLATFORM) + cd $(PLATFORM); $(ARCHIVE_TOOL) $(ARCHIVE_TOOL_FLAGS) $(TARBALLS_LOCATION)/$(ARCHIVE) + mkdir -p $(BUILDDIR) + cd $(BUILDDIR); $(NATIVEPREFIX)/bin/cmake $(CMAKE_OPTIONS) .. + +$(APP): $(PLATFORM) + $(MAKE) -C $(BUILDDIR) + +.installed-$(PLATFORM): $(APP) + $(MAKE) -C $(BUILDDIR) install + touch $@ + +clean: + $(MAKE) -C $(BUILDDIR) clean + rm -f .installed-$(PLATFORM) + +distclean: + rm -rf $(PLATFORM) .installed-$(PLATFORM) diff --git a/tools/depends/native/xz/Makefile b/tools/depends/native/xz/Makefile new file mode 100644 index 0000000..8986c49 --- /dev/null +++ b/tools/depends/native/xz/Makefile @@ -0,0 +1,30 @@ +include ../../Makefile.include XZ-VERSION ../../download-files.include +PREFIX=$(NATIVEPREFIX) +PLATFORM=$(NATIVEPLATFORM) +DEPS = ../../Makefile.include Makefile XZ-VERSION ../../download-files.include + +export LIBTOOL=builds/unix/libtool +export PATH:=$(PREFIX)/bin:$(PATH) +CONFIGURE=./configure --prefix=$(PREFIX) + +APP=$(PLATFORM)/src/xz/xz + +all: .installed-$(PLATFORM) + +$(PLATFORM): $(DEPS) | $(TARBALLS_LOCATION)/$(ARCHIVE).$(HASH_TYPE) + -rm -rf $(PLATFORM)/*; mkdir -p $(PLATFORM) + cd $(PLATFORM); $(ARCHIVE_TOOL) $(ARCHIVE_TOOL_FLAGS) $(TARBALLS_LOCATION)/$(ARCHIVE) + cd $(PLATFORM); $(CONFIGURE) + +$(APP): $(PLATFORM) + $(MAKE) -C $(PLATFORM) + +.installed-$(PLATFORM): $(APP) + $(MAKE) -C $(PLATFORM) install + touch $@ + +clean: + $(MAKE) -C $(PLATFORM) clean + +distclean:: + rm -rf $(PLATFORM) .installed-$(PLATFORM) diff --git a/tools/depends/native/xz/XZ-VERSION b/tools/depends/native/xz/XZ-VERSION new file mode 100644 index 0000000..288df10 --- /dev/null +++ b/tools/depends/native/xz/XZ-VERSION @@ -0,0 +1,4 @@ +LIBNAME=xz +VERSION=5.2.6 +ARCHIVE=$(LIBNAME)-$(VERSION).tar.xz +SHA512=5c69a492227c0ff72836d7a87e6372dc2e62bedfffb33f057263e28a6341825cef67834a863ed6ac02c5368c86da89f8affbe767f8bb914064cfa478f653e935 diff --git a/tools/depends/native/zlib/Makefile b/tools/depends/native/zlib/Makefile new file mode 100644 index 0000000..863ac4b --- /dev/null +++ b/tools/depends/native/zlib/Makefile @@ -0,0 +1,40 @@ +include ../../Makefile.include +PREFIX=$(NATIVEPREFIX) +PLATFORM=$(NATIVEPLATFORM) +DEPS = ../../Makefile.include Makefile visibility.patch ../../download-files.include + +# lib name, version +LIBNAME=zlib +VERSION=1.2.11 +SOURCE=$(LIBNAME)-$(VERSION) +ARCHIVE=$(SOURCE).tar.gz +SHA512=73fd3fff4adeccd4894084c15ddac89890cd10ef105dd5e1835e1e9bbb6a49ff229713bd197d203edfa17c2727700fce65a2a235f07568212d820dca88b528ae +include ../../download-files.include +# configuration settings +CONFIGURE= CC="$(CC_FOR_BUILD)" CFLAGS="$(NATIVE_CFLAGS)" ./configure --prefix=$(PREFIX) + +LIBDYLIB=$(PLATFORM)/$(LIBNAME).a + +all: .installed-$(PLATFORM) + + +$(PLATFORM): $(DEPS) | $(TARBALLS_LOCATION)/$(ARCHIVE).$(HASH_TYPE) + rm -rf $(PLATFORM); mkdir -p $(PLATFORM) + cd $(PLATFORM); $(ARCHIVE_TOOL) $(ARCHIVE_TOOL_FLAGS) $(TARBALLS_LOCATION)/$(ARCHIVE) + cd $(PLATFORM); patch -p1 -i ../visibility.patch + cd $(PLATFORM); $(CONFIGURE) + +$(LIBDYLIB): $(PLATFORM) + $(MAKE) -C $(PLATFORM) + touch $@ + +.installed-$(PLATFORM): $(LIBDYLIB) + $(MAKE) -C $(PLATFORM) install + touch $@ + +clean: + $(MAKE) -C $(PLATFORM) clean + rm -f .installed-$(PLATFORM) + +distclean:: + rm -rf $(PLATFORM) .installed-$(PLATFORM) diff --git a/tools/depends/native/zlib/visibility.patch b/tools/depends/native/zlib/visibility.patch new file mode 100644 index 0000000..3257f7f --- /dev/null +++ b/tools/depends/native/zlib/visibility.patch @@ -0,0 +1,15 @@ +--- a/zconf.h.in ++++ b/zconf.h.in +@@ -374,7 +374,11 @@ + #endif + + #ifndef ZEXTERN +-# define ZEXTERN extern ++# ifdef HAVE_HIDDEN ++# define ZEXTERN extern __attribute__((visibility ("default"))) ++# else ++# define ZEXTERN extern ++# endif + #endif + #ifndef ZEXPORT + # define ZEXPORT diff --git a/tools/depends/pre-depends/autoconf-pre-depends/Makefile b/tools/depends/pre-depends/autoconf-pre-depends/Makefile new file mode 100644 index 0000000..23feab1 --- /dev/null +++ b/tools/depends/pre-depends/autoconf-pre-depends/Makefile @@ -0,0 +1,43 @@ +include ../../Makefile.include.in +PREFIX=$(CURDIR)/../../pre-build-deps +PLATFORM=native +TARBALLS_LOCATION=$(PREFIX) +RETRIEVE_TOOL=curl +ARCHIVE_TOOL=tar +# lib name, version +LIBNAME=autoconf +VERSION=2.71 +SOURCE=$(LIBNAME)-$(VERSION) +ARCHIVE=$(SOURCE).tar.xz + +export PATH:=$(CURDIR)/../../pre-build-deps/bin:$(PATH) + +# configuration settings +CONFIGURE=./configure --prefix=$(PREFIX) + +LIBDYLIB=$(PLATFORM)/bin/autoconf + +all: $(PREFIX)/bin/$(LIBNAME) + +$(TARBALLS_LOCATION)/$(ARCHIVE): + mkdir -p $(TARBALLS_LOCATION) + cd $(TARBALLS_LOCATION); $(RETRIEVE_TOOL) $(RETRIEVE_TOOL_FLAGS) $(BASE_URL)/$(ARCHIVE) + +$(PLATFORM): $(TARBALLS_LOCATION)/$(ARCHIVE) $(DEPS) + -rm -rf $(PLATFORM)/*; mkdir -p $(PLATFORM) + cd $(PLATFORM); $(ARCHIVE_TOOL) $(ARCHIVE_TOOL_FLAGS) $(TARBALLS_LOCATION)/$(ARCHIVE) + +$(LIBDYLIB): $(PLATFORM) + cd $(PLATFORM); $(CONFIGURE) + $(MAKE) -C $(PLATFORM) + +$(PREFIX)/bin/$(LIBNAME): $(LIBDYLIB) + $(MAKE) -C $(PLATFORM) install + touch $@ + +clean: + $(MAKE) -C $(PLATFORM) clean + rm -f .installed-$(PLATFORM) + +distclean:: + rm -rf $(PLATFORM) .installed-$(PLATFORM) diff --git a/tools/depends/pre-depends/m4-pre-depends/Makefile b/tools/depends/pre-depends/m4-pre-depends/Makefile new file mode 100644 index 0000000..fa60e37 --- /dev/null +++ b/tools/depends/pre-depends/m4-pre-depends/Makefile @@ -0,0 +1,41 @@ +include ../../Makefile.include.in +DEPS=Makefile +PREFIX=$(CURDIR)/../../pre-build-deps +PLATFORM=native +TARBALLS_LOCATION=$(PREFIX) +RETRIEVE_TOOL=curl +ARCHIVE_TOOL=tar +# lib name, version +LIBNAME=m4 +VERSION=1.4.19 +SOURCE=$(LIBNAME)-$(VERSION) +ARCHIVE=$(SOURCE).tar.xz + +# configuration settings +CONFIGURE=./configure --prefix=$(PREFIX) + +LIBDYLIB=$(PLATFORM)/src/$(LIBNAME) + +all: $(PREFIX)/bin/$(LIBNAME) + +$(TARBALLS_LOCATION)/$(ARCHIVE): + mkdir -p $(TARBALLS_LOCATION) + cd $(TARBALLS_LOCATION); $(RETRIEVE_TOOL) $(RETRIEVE_TOOL_FLAGS) $(BASE_URL)/$(ARCHIVE) + +$(PLATFORM): $(TARBALLS_LOCATION)/$(ARCHIVE) $(DEPS) + -rm -rf $(PLATFORM)/*; mkdir -p $(PLATFORM) + cd $(PLATFORM); $(ARCHIVE_TOOL) $(ARCHIVE_TOOL_FLAGS) $(TARBALLS_LOCATION)/$(ARCHIVE) + cd $(PLATFORM); $(CONFIGURE) + +$(LIBDYLIB): $(PLATFORM) + $(MAKE) -C $(PLATFORM) + +$(PREFIX)/bin/$(LIBNAME): $(LIBDYLIB) + $(MAKE) -C $(PLATFORM) install + touch $@ + +clean: + $(MAKE) -C $(PLATFORM) clean + +distclean:: + rm -rf $(PLATFORM) diff --git a/tools/depends/target/crossguid/CROSSGUID-VERSION b/tools/depends/target/crossguid/CROSSGUID-VERSION new file mode 100644 index 0000000..b5e40b8 --- /dev/null +++ b/tools/depends/target/crossguid/CROSSGUID-VERSION @@ -0,0 +1,6 @@ +LIBNAME=crossguid +VERSION=ca1bf4b810e2d188d04cb6286f957008ee1b7681 +ARCHIVE=$(LIBNAME)-$(VERSION).tar.gz +SHA512=f0a80d8e99b10473bcfdfde3d1c5fd7b766959819f0d1c0595ac84ce46db9007a5fbfde9a55aca60530c46cb7f8ef4c7e472c6191559ded92f868589c141ccaf +BYPRODUCT=libcrossguid.a +BYPRODUCT_WIN=crossguid.lib diff --git a/tools/depends/target/dav1d/DAV1D-VERSION b/tools/depends/target/dav1d/DAV1D-VERSION new file mode 100644 index 0000000..bb6d404 --- /dev/null +++ b/tools/depends/target/dav1d/DAV1D-VERSION @@ -0,0 +1,5 @@ +LIBNAME=dav1d +VERSION=1.0.0 +ARCHIVE=$(LIBNAME)-$(VERSION).tar.bz2 +SHA512=86c6481e787fb6b8c28521e1efb1876d1be99f5fa5332cddab1111059b44775e05203cfc5c80a1b404ee00f35a1f5e1099e21b1f0851d77fb0101567e8b1a892 +BYPRODUCT=libdav1d.a diff --git a/tools/depends/target/expat/EXPAT-VERSION b/tools/depends/target/expat/EXPAT-VERSION new file mode 100644 index 0000000..fac7be7 --- /dev/null +++ b/tools/depends/target/expat/EXPAT-VERSION @@ -0,0 +1,6 @@ +LIBNAME=expat +VERSION=2.4.9 +SOURCE=$(LIBNAME)-$(VERSION) +ARCHIVE=$(SOURCE).tar.xz +SHA512=8508379b4915d84d50f3638678a90792179c98247d1cb5e6e6387d117af4dc148ac7031c1debea8b96e7b710ef436cf0dd5da91f3d22b8186a00cfafe1201169 +BYPRODUCT=libexpat.a diff --git a/tools/depends/target/ffmpeg/FFMPEG-VERSION b/tools/depends/target/ffmpeg/FFMPEG-VERSION new file mode 100644 index 0000000..2c9eda8 --- /dev/null +++ b/tools/depends/target/ffmpeg/FFMPEG-VERSION @@ -0,0 +1,5 @@ +LIBNAME=ffmpeg +BASE_URL=https://github.com/xbmc/FFmpeg +VERSION=4.4.1-Nexus-Alpha1 +ARCHIVE=$(LIBNAME)-$(VERSION).tar.gz +SHA512=8beb04d577b5251e74b0d52f4d130997a8ba94bbd488c7c8309e6b45095c27807e150212888ce3a384b23dff52f8df1a7bde5407bae924ddc363f8125c0616c5 diff --git a/tools/depends/target/flatbuffers/FLATBUFFERS-VERSION b/tools/depends/target/flatbuffers/FLATBUFFERS-VERSION new file mode 100644 index 0000000..4d05761 --- /dev/null +++ b/tools/depends/target/flatbuffers/FLATBUFFERS-VERSION @@ -0,0 +1,4 @@ +LIBNAME=flatbuffers +VERSION=2.0.0 +ARCHIVE=$(LIBNAME)-$(VERSION).tar.gz +SHA512=26a06b572c0e4c9685743bd2d2162ac7dcd74b9324624cc3f3ef5b154c0cee7c52a04b77cdc184245d2d6ae38dfdcc4fd66001c318aa8ca001d2bf1d85d66a89 diff --git a/tools/depends/target/fmt/FMT-VERSION b/tools/depends/target/fmt/FMT-VERSION new file mode 100644 index 0000000..f887185 --- /dev/null +++ b/tools/depends/target/fmt/FMT-VERSION @@ -0,0 +1,6 @@ +LIBNAME=fmt +VERSION=9.1.0 +ARCHIVE=$(LIBNAME)-$(VERSION).tar.gz +SHA512=a18442042722dd48e20714ec034a12fcc0576c9af7be5188586970e2edf47529825bdc99af366b1d5891630c8dbf6f63bfa9f012e77ab3d3ed80d1a118e3b2be +BYPRODUCT=libfmt.a +BYPRODUCT_WIN=fmt.lib diff --git a/tools/depends/target/fontconfig/FONTCONFIG-VERSION b/tools/depends/target/fontconfig/FONTCONFIG-VERSION new file mode 100644 index 0000000..60e2d31 --- /dev/null +++ b/tools/depends/target/fontconfig/FONTCONFIG-VERSION @@ -0,0 +1,7 @@ +LIBNAME=fontconfig +VERSION=2.14.0 +ARCHIVE=$(LIBNAME)-$(VERSION).tar.xz +SHA512=a5257249d031b3cd1a7b1521cd58f48d235a970020da4136a727db5407ec98e74a3776bc467d7e39f30ec664f56ff9fe39068317744a5e737a65109f7a005bfc +BYPRODUCT=libfontconfig.a + +BASE_URL=https://www.freedesktop.org/software/fontconfig/release diff --git a/tools/depends/target/freetype2-noharfbuzz/FREETYPE2-NOHARFBUZZ-VERSION b/tools/depends/target/freetype2-noharfbuzz/FREETYPE2-NOHARFBUZZ-VERSION new file mode 100644 index 0000000..eba6f0e --- /dev/null +++ b/tools/depends/target/freetype2-noharfbuzz/FREETYPE2-NOHARFBUZZ-VERSION @@ -0,0 +1,5 @@ +LIBNAME=freetype +VERSION=2.11.1 +ARCHIVE=$(LIBNAME)-$(VERSION).tar.xz +SHA512=0848678482fbe20603a866f02da82c91122014d6f815ba4f1d9c03601c32e3ceb781f721c2b4427b6117d7c9742018af8dbb26566faf018595c70b50f8db3f08 +BYPRODUCT=libfreetype.a diff --git a/tools/depends/target/freetype2/FREETYPE2-VERSION b/tools/depends/target/freetype2/FREETYPE2-VERSION new file mode 100644 index 0000000..eba6f0e --- /dev/null +++ b/tools/depends/target/freetype2/FREETYPE2-VERSION @@ -0,0 +1,5 @@ +LIBNAME=freetype +VERSION=2.11.1 +ARCHIVE=$(LIBNAME)-$(VERSION).tar.xz +SHA512=0848678482fbe20603a866f02da82c91122014d6f815ba4f1d9c03601c32e3ceb781f721c2b4427b6117d7c9742018af8dbb26566faf018595c70b50f8db3f08 +BYPRODUCT=libfreetype.a diff --git a/tools/depends/target/fribidi/FRIBIDI-VERSION b/tools/depends/target/fribidi/FRIBIDI-VERSION new file mode 100644 index 0000000..2f1bcbd --- /dev/null +++ b/tools/depends/target/fribidi/FRIBIDI-VERSION @@ -0,0 +1,5 @@ +LIBNAME=fribidi +VERSION=1.0.11 +SOURCE=$(LIBNAME)-$(VERSION) +ARCHIVE=$(SOURCE).tar.xz +SHA512=6afde86784de06759f18235ccb44f23261a975f7cce0021b16755065a6a8ed84d7d5fb7fdcaadd691b48011efb4bfc2ee67555e5133a294a418cca1a0c85476c diff --git a/tools/depends/target/fstrcmp/FSTRCMP-VERSION b/tools/depends/target/fstrcmp/FSTRCMP-VERSION new file mode 100644 index 0000000..4712cad --- /dev/null +++ b/tools/depends/target/fstrcmp/FSTRCMP-VERSION @@ -0,0 +1,5 @@ +LIBNAME=fstrcmp +VERSION=0.7.D001 +ARCHIVE=$(LIBNAME)-$(VERSION).tar.gz +SHA512=aaeb0227afd5ada5955cbe6a565254ff88d2028d677d199c00e03b7cb5de1f2c69b18e6e8b032e452350a8eda7081807b01765adbeb8476eaf803d9de6e5509c +BYPRODUCT=libfstrcmp.a diff --git a/tools/depends/target/gtest/GTEST-VERSION b/tools/depends/target/gtest/GTEST-VERSION new file mode 100644 index 0000000..3e6dd42 --- /dev/null +++ b/tools/depends/target/gtest/GTEST-VERSION @@ -0,0 +1,5 @@ +LIBNAME=gtest +VERSION=1.11.0 +ARCHIVE=googletest-$(VERSION).tar.gz +SHA512=6fcc7827e4c4d95e3ae643dd65e6c4fc0e3d04e1778b84f6e06e390410fe3d18026c131d828d949d2f20dde6327d30ecee24dcd3ef919e21c91e010d149f3a28 +BYPRODUCT=libgtest.a diff --git a/tools/depends/target/libandroidjni/LIBANDROIDJNI-VERSION b/tools/depends/target/libandroidjni/LIBANDROIDJNI-VERSION new file mode 100644 index 0000000..cf6697c --- /dev/null +++ b/tools/depends/target/libandroidjni/LIBANDROIDJNI-VERSION @@ -0,0 +1,6 @@ +LIBNAME=libandroidjni +VERSION=3a2401853946f5ed9ae91e2163ab213edb8f4b62 +BASE_URL=https://github.com/xbmc/libandroidjni/archive +ARCHIVE=$(VERSION).tar.gz +SHA512=074e9d37b8f1574b6b30489cfb5127d11b3ed558d5edb15a8cc40fc0d57d88373a621eeb16fcd6eaa5fc97eb1c7598feeb60f95778989354a35e4efa02014b78 +BYPRODUCT=libandroidjni.a diff --git a/tools/depends/target/libbluray/LIBBLURAY-VERSION b/tools/depends/target/libbluray/LIBBLURAY-VERSION new file mode 100644 index 0000000..c34fdc1 --- /dev/null +++ b/tools/depends/target/libbluray/LIBBLURAY-VERSION @@ -0,0 +1,5 @@ +LIBNAME=libbluray +VERSION=1.3.2 +ARCHIVE=$(LIBNAME)-$(VERSION).tar.bz2 +SHA512=6f2d3a984809db33a99d2fe3618370a3fda3ef1c417b725d3c2e1f24ff21495f95a6a5f78b30b2b26bab47865f68dd08c08e8a554809d3a5225956da712dc064 +BYPRODUCT=libbluray.a diff --git a/tools/depends/target/libdvdcss/LIBDVDCSS-VERSION b/tools/depends/target/libdvdcss/LIBDVDCSS-VERSION new file mode 100644 index 0000000..4fb78d9 --- /dev/null +++ b/tools/depends/target/libdvdcss/LIBDVDCSS-VERSION @@ -0,0 +1,7 @@ +LIBNAME=libdvdcss +BASE_URL=https://github.com/xbmc/libdvdcss +VERSION=1.4.3-Next-Nexus-Alpha2-2 +ARCHIVE=$(LIBNAME)-$(VERSION).tar.gz +SHA512=d3be3bfc13c5ea56d8db745c2aab090c99760684fe4c8f62a13d266feb319e9180ceeecf8116bfd2ed90d9accba2c11dbbf93b61ad00f69a40812ebf4eabcdda +BYPRODUCT=libdvdcss.a +BYPRODUCT_WIN=dvdcss.lib diff --git a/tools/depends/target/libdvdnav/LIBDVDNAV-VERSION b/tools/depends/target/libdvdnav/LIBDVDNAV-VERSION new file mode 100644 index 0000000..3d6d1ec --- /dev/null +++ b/tools/depends/target/libdvdnav/LIBDVDNAV-VERSION @@ -0,0 +1,7 @@ +LIBNAME=libdvdnav +BASE_URL=https://github.com/xbmc/libdvdnav +VERSION=6.1.1-Next-Nexus-Alpha2-2 +ARCHIVE=$(LIBNAME)-$(VERSION).tar.gz +SHA512=51e6fc033121241354a5f0b3fc9a430577ae3ff6bb7f31445aa548ef4893037fb80eea3b2c6774c81e9ebaf9c45e9b490c98c2c65eb38f9f7daba84b236f7e1d +BYPRODUCT=libdvdnav.a +BYPRODUCT_WIN=libdvdnav.lib diff --git a/tools/depends/target/libdvdread/LIBDVDREAD-VERSION b/tools/depends/target/libdvdread/LIBDVDREAD-VERSION new file mode 100644 index 0000000..d51b629 --- /dev/null +++ b/tools/depends/target/libdvdread/LIBDVDREAD-VERSION @@ -0,0 +1,7 @@ +LIBNAME=libdvdread +BASE_URL=https://github.com/xbmc/libdvdread +VERSION=6.1.3-Next-Nexus-Alpha2-2 +ARCHIVE=$(LIBNAME)-$(VERSION).tar.gz +SHA512=629a41157d07b8ec0ea1fe89ae5ec48f63047472a862782b805c531ae31a0376fc4dc15175f8280c3ef91d7fa977bacebb1b51232640034a34bab2293210fc5e +BYPRODUCT=libdvdread.a +BYPRODUCT_WIN=dvdread.lib diff --git a/tools/depends/target/libffi/LIBFFI-VERSION b/tools/depends/target/libffi/LIBFFI-VERSION new file mode 100644 index 0000000..9d1e722 --- /dev/null +++ b/tools/depends/target/libffi/LIBFFI-VERSION @@ -0,0 +1,4 @@ +LIBNAME=libffi +VERSION=3.4.2 +ARCHIVE=$(LIBNAME)-$(VERSION).tar.gz +SHA512=31bad35251bf5c0adb998c88ff065085ca6105cf22071b9bd4b5d5d69db4fadf16cadeec9baca944c4bb97b619b035bb8279de8794b922531fddeb0779eb7fb1 diff --git a/tools/depends/target/libgcrypt/LIBGCRYPT-VERSION b/tools/depends/target/libgcrypt/LIBGCRYPT-VERSION new file mode 100644 index 0000000..1010baf --- /dev/null +++ b/tools/depends/target/libgcrypt/LIBGCRYPT-VERSION @@ -0,0 +1,5 @@ +LIBNAME=libgcrypt +VERSION=1.10.1 +ARCHIVE=$(LIBNAME)-$(VERSION).tar.bz2 +SHA512=e5ca7966624fff16c3013795836a2c4377f0193dbb4ac5ad2b79654b1fa8992e17d83816569a402212dc8367a7980d4141f5d6ac282bae6b9f02186365b61f13 +BYPRODUCT=libgcrypt.a diff --git a/tools/depends/target/libgpg-error/LIBGPG-ERROR-VERSION b/tools/depends/target/libgpg-error/LIBGPG-ERROR-VERSION new file mode 100644 index 0000000..3456a91 --- /dev/null +++ b/tools/depends/target/libgpg-error/LIBGPG-ERROR-VERSION @@ -0,0 +1,5 @@ +LIBNAME=libgpg-error +VERSION=1.45 +SOURCE=$(LIBNAME)-$(VERSION) +ARCHIVE=$(SOURCE).tar.bz2 +SHA512=882f2dd617e89137d7a9d61b60488dac32321dd4fdb699e9687b6bd9380c056c027da502837f4482289c0fe00e7de01210e804428f05a0843ae2ca23fdcc6457 diff --git a/tools/depends/target/libjpeg-turbo/LIBJPEG-TURBO-VERSION b/tools/depends/target/libjpeg-turbo/LIBJPEG-TURBO-VERSION new file mode 100644 index 0000000..61eb008 --- /dev/null +++ b/tools/depends/target/libjpeg-turbo/LIBJPEG-TURBO-VERSION @@ -0,0 +1,4 @@ +LIBNAME=libjpeg-turbo +VERSION=2.1.4 +ARCHIVE=$(LIBNAME)-$(VERSION).tar.gz +SHA512=d3e92d614168355827e0ed884ff847cc7df8f6f1fb7b673c6c99afdf61fdfc0372afe5d30fdbf5e743335e2a7a27ca9f510c67d213e5cb2315a8d946e9414575 diff --git a/tools/depends/target/liblzo2/LIBLZO2-VERSION b/tools/depends/target/liblzo2/LIBLZO2-VERSION new file mode 100644 index 0000000..05008a9 --- /dev/null +++ b/tools/depends/target/liblzo2/LIBLZO2-VERSION @@ -0,0 +1,6 @@ +LIBNAME=lzo +VERSION=2.10 +SOURCE=$(LIBNAME)-$(VERSION) +ARCHIVE=$(SOURCE).tar.gz +SHA512=a3dae5e4a6b93b1f5bf7435e8ab114a9be57252e9efc5dd444947d7a2d031b0819f34bcaeb35f60b5629a01b1238d738735a64db8f672be9690d3c80094511a4 +BYPRODUCT=liblzo2.a diff --git a/tools/depends/target/libmicrohttpd/LIBMICROHTTPD-VERSION b/tools/depends/target/libmicrohttpd/LIBMICROHTTPD-VERSION new file mode 100644 index 0000000..b6c751d --- /dev/null +++ b/tools/depends/target/libmicrohttpd/LIBMICROHTTPD-VERSION @@ -0,0 +1,4 @@ +LIBNAME=libmicrohttpd +VERSION=0.9.75 +ARCHIVE=$(LIBNAME)-$(VERSION).tar.gz +SHA512=4dc62ed191342a61cc2767171bb1ff4050f390db14ef7100299888237b52ea0b04b939c843878fe7f5daec2b35a47b3c1b7e7c11fb32d458184fe6b19986a37c diff --git a/tools/depends/target/libnfs/LIBNFS-VERSION b/tools/depends/target/libnfs/LIBNFS-VERSION new file mode 100644 index 0000000..892aa7a --- /dev/null +++ b/tools/depends/target/libnfs/LIBNFS-VERSION @@ -0,0 +1,6 @@ +LIBNAME=libnfs +VERSION=5.0.2 +ARCHIVE=$(LIBNAME)-$(VERSION).tar.gz +SHA512=6dcf4ea8a01b35beb53694625d20fbebd858a88725c2742671878ad6fe7877999f93d262fb58a435b00c283c3e6fb6fa7222d04bb4540bf674b7ce196e9424f5 +BYPRODUCT=libnfs.a +BYPRODUCT_WIN=nfs.lib diff --git a/tools/depends/target/libpng/LIBPNG-VERSION b/tools/depends/target/libpng/LIBPNG-VERSION new file mode 100644 index 0000000..c67b9d4 --- /dev/null +++ b/tools/depends/target/libpng/LIBPNG-VERSION @@ -0,0 +1,5 @@ +LIBNAME=libpng +VERSION=1.6.37 +ARCHIVE=$(LIBNAME)-$(VERSION).tar.gz +SHA512=2ce2b855af307ca92a6e053f521f5d262c36eb836b4810cb53c809aa3ea2dcc08f834aee0ffd66137768a54397e28e92804534a74abb6fc9f6f3127f14c9c338 +BYPRODUCT=libpng.a diff --git a/tools/depends/target/libxml2/LIBXML2-VERSION b/tools/depends/target/libxml2/LIBXML2-VERSION new file mode 100644 index 0000000..9a8fbb1 --- /dev/null +++ b/tools/depends/target/libxml2/LIBXML2-VERSION @@ -0,0 +1,5 @@ +LIBNAME=libxml2 +VERSION=2.10.1 +ARCHIVE=$(LIBNAME)-$(VERSION).tar.xz +SHA512=7ae653eef725706c825a8755da14a92124c3f85b38f81fd1148c6e373b149d095eae935a47d874d210dafc7e76f09c019866657b8f9d6a44c666ce741e12f3ce +BYPRODUCT=libxml2.a diff --git a/tools/depends/target/libzip/LIBZIP-VERSION b/tools/depends/target/libzip/LIBZIP-VERSION new file mode 100644 index 0000000..af0835b --- /dev/null +++ b/tools/depends/target/libzip/LIBZIP-VERSION @@ -0,0 +1,5 @@ +LIBNAME=libzip +VERSION=1.8.0 +ARCHIVE=$(LIBNAME)-$(VERSION).tar.xz +SHA512=fe94a26a2797dff7c9b27334f29982f8e523dd5095bf32ebcadc6443726864f0ff7b2e8bf243e52cad8f79297bc7a87d73fdbc35edae4ffc8ab6aa0bcc93b03e +BYPRODUCT=libzip.a diff --git a/tools/depends/target/mariadb/MARIADB-VERSION b/tools/depends/target/mariadb/MARIADB-VERSION new file mode 100644 index 0000000..e05f933 --- /dev/null +++ b/tools/depends/target/mariadb/MARIADB-VERSION @@ -0,0 +1,4 @@ +LIBNAME=mariadb +VERSION=3.3.2 +ARCHIVE=$(LIBNAME)-connector-c-$(VERSION)-src.tar.gz +SHA512=1f9754112ba02b863435840dab8e0954b98c646e6e6d73bbc2f338cd6493824b0f8973bbf80b129631ccafd684e0579743fe81a0e8f1120ed9f18154d9d446b3 diff --git a/tools/depends/target/nghttp2/NGHTTP2-VERSION b/tools/depends/target/nghttp2/NGHTTP2-VERSION new file mode 100644 index 0000000..998667c --- /dev/null +++ b/tools/depends/target/nghttp2/NGHTTP2-VERSION @@ -0,0 +1,5 @@ +LIBNAME=nghttp2 +VERSION=1.46.0 +ARCHIVE=$(LIBNAME)-$(VERSION).tar.xz +SHA512=fcf3573bcc421705190c7cf0e3230f6f3028b669cb2976d29cfeb73e706deaae91ce60d0a615472e3f296454049ea5798f1e8defdd260a98895e94fea6a7a16b +BYPRODUCT=libnghttp2.a diff --git a/tools/depends/target/pcre/PCRE-VERSION b/tools/depends/target/pcre/PCRE-VERSION new file mode 100644 index 0000000..af533d2 --- /dev/null +++ b/tools/depends/target/pcre/PCRE-VERSION @@ -0,0 +1,6 @@ +LIBNAME=pcre +VERSION=8.45 +ARCHIVE=$(LIBNAME)-$(VERSION).tar.bz2 +SHA512=91bff52eed4a2dfc3f3bfdc9c672b88e7e2ffcf3c4b121540af8a4ae8c1ce05178430aa6b8000658b9bb7b4252239357250890e20ceb84b79cdfcde05154061a +BYPRODUCT=libpcre.a +BYPRODUCT_WIN=pcre.lib diff --git a/tools/depends/target/python3/PYTHON3-VERSION b/tools/depends/target/python3/PYTHON3-VERSION new file mode 100644 index 0000000..290e333 --- /dev/null +++ b/tools/depends/target/python3/PYTHON3-VERSION @@ -0,0 +1,4 @@ +LIBNAME=Python +VERSION=3.11.2 +ARCHIVE=$(LIBNAME)-$(VERSION).tar.xz +SHA512=5684ec7eae2dce26facc54d448ccdb6901bbfa1cab03abbe8fd34e4268a2b701daa13df15903349492447035be78380d473389e8703b4e910a65b088d2462e8b diff --git a/tools/depends/target/pythonmodule-pil/PYTHONMODULE-PIL-VERSION b/tools/depends/target/pythonmodule-pil/PYTHONMODULE-PIL-VERSION new file mode 100644 index 0000000..9940c86 --- /dev/null +++ b/tools/depends/target/pythonmodule-pil/PYTHONMODULE-PIL-VERSION @@ -0,0 +1,4 @@ +LIBNAME=Pillow +VERSION=8.4.0 +ARCHIVE=$(LIBNAME)-$(VERSION).tar.gz +SHA512=d395f69ccb37c52a3b6f45836700ffbc3173afae31848cc61d7b47db88ca1594541023beb9a14fd9067aca664e182c7d6e3300ab3e3095c31afe8dcbc6e08233 diff --git a/tools/depends/target/pythonmodule-pycryptodome/PYTHONMODULE-PYCRYPTODOME-VERSION b/tools/depends/target/pythonmodule-pycryptodome/PYTHONMODULE-PYCRYPTODOME-VERSION new file mode 100644 index 0000000..236dc94 --- /dev/null +++ b/tools/depends/target/pythonmodule-pycryptodome/PYTHONMODULE-PYCRYPTODOME-VERSION @@ -0,0 +1,4 @@ +LIBNAME=pycryptodome +VERSION=3.12.0 +ARCHIVE=$(LIBNAME)-$(VERSION).tar.gz +SHA512=67f2a814d74305614fdf9dfb633c4fd9d80d2064119d0ecab24ae52fd8ce4b6de1a1e82c6ba7bcf22fb7db1a5a850adf078e22317b4c07229cd7cb8cb7f1ffd4 diff --git a/tools/depends/target/pythonmodule-setuptools/PYTHONMODULE-SETUPTOOLS-VERSION b/tools/depends/target/pythonmodule-setuptools/PYTHONMODULE-SETUPTOOLS-VERSION new file mode 100644 index 0000000..1eca9e1 --- /dev/null +++ b/tools/depends/target/pythonmodule-setuptools/PYTHONMODULE-SETUPTOOLS-VERSION @@ -0,0 +1,4 @@ +LIBNAME=setuptools +VERSION=65.5.0 +ARCHIVE=$(LIBNAME)-$(VERSION).tar.gz +SHA512=b3ed6546bfa45c96f9b69fd7f014a87b52e6d8a6591340bf980bd4de98e33dbe0990b089940c348f2ad20a27590b82de84aec44c8ba1dce0510a3835653930d3 diff --git a/tools/depends/target/rapidjson/RAPIDJSON-VERSION b/tools/depends/target/rapidjson/RAPIDJSON-VERSION new file mode 100644 index 0000000..120e868 --- /dev/null +++ b/tools/depends/target/rapidjson/RAPIDJSON-VERSION @@ -0,0 +1,4 @@ +LIBNAME=rapidjson +VERSION=1.1.0 +ARCHIVE=$(LIBNAME)-$(VERSION).tar.gz +SHA512=2e82a4bddcd6c4669541f5945c2d240fb1b4fdd6e239200246d3dd50ce98733f0a4f6d3daa56f865d8c88779c036099c52a9ae85d47ad263686b68a88d832dff diff --git a/tools/depends/target/samba-gplv3/SAMBA-GPLV3-VERSION b/tools/depends/target/samba-gplv3/SAMBA-GPLV3-VERSION new file mode 100644 index 0000000..57d2c98 --- /dev/null +++ b/tools/depends/target/samba-gplv3/SAMBA-GPLV3-VERSION @@ -0,0 +1,4 @@ +LIBNAME=samba +VERSION=4.13.17 +ARCHIVE=$(LIBNAME)-$(VERSION).tar.gz +SHA512=3f47cc588c370510a11a1d5dc1a9f64872d765a2940a0dd39f02718f9a81b134dda9c9cb593f291f2aa1657de65b26458adcda33369c0858e16edf7f088edaf4 diff --git a/tools/depends/target/spdlog/SPDLOG-VERSION b/tools/depends/target/spdlog/SPDLOG-VERSION new file mode 100644 index 0000000..297caea --- /dev/null +++ b/tools/depends/target/spdlog/SPDLOG-VERSION @@ -0,0 +1,6 @@ +LIBNAME=spdlog +VERSION=1.10.0 +ARCHIVE=$(LIBNAME)-$(VERSION).tar.gz +SHA512=e82ec0a0c813ed2f1c8a31a0f21dbb733d0a7bd8d05284feae3bd66040bc53ad47a93b26c3e389c7e5623cfdeba1854d690992c842748e072aab3e6e6ecc5666 +BYPRODUCT=libspdlog.a +BYPRODUCT_WIN=spdlog.lib diff --git a/tools/depends/target/sqlite3/SQLITE3-VERSION b/tools/depends/target/sqlite3/SQLITE3-VERSION new file mode 100644 index 0000000..1bfb2cc --- /dev/null +++ b/tools/depends/target/sqlite3/SQLITE3-VERSION @@ -0,0 +1,4 @@ +LIBNAME=sqlite +VERSION=3390400 +ARCHIVE=$(LIBNAME)-autoconf-$(VERSION).tar.gz +SHA512=cc1de214e69ef677cac3f6dd2000ccfcf4b672ab464a115d96f24707009a408630e762c3cda89741b728ab34c4d9f5b8f8b12e9b11448e8364642b4421c3393d diff --git a/tools/depends/target/taglib/TAGLIB-VERSION b/tools/depends/target/taglib/TAGLIB-VERSION new file mode 100644 index 0000000..8f980b0 --- /dev/null +++ b/tools/depends/target/taglib/TAGLIB-VERSION @@ -0,0 +1,6 @@ +LIBNAME=taglib +VERSION=1.12 +ARCHIVE=$(LIBNAME)-$(VERSION).tar.gz +SHA512=7e369faa5e3c6c6401052b7a19e35b0cf8c1e5ed9597053ac731a7718791d5d4803d1b18a93e903ec8c3fc6cb92e34d9616daa2ae4d326965d4c4d5624dcdaba +BYPRODUCT=libtag.a +BYPRODUCT_WIN=tag.lib diff --git a/tools/depends/target/udfread/UDFREAD-VERSION b/tools/depends/target/udfread/UDFREAD-VERSION new file mode 100644 index 0000000..64c5a41 --- /dev/null +++ b/tools/depends/target/udfread/UDFREAD-VERSION @@ -0,0 +1,5 @@ +LIBNAME=udfread +VERSION=1.1.2 +ARCHIVE=lib$(LIBNAME)-$(VERSION).tar.gz +SHA512=3069feb5db40288beb5b112b285186162a704f0fdd3cf67a17fd4eeea015f2cfcfbb455b7aa7c3d79d00fd095a3fd11cffc7b121dce94d99c3b06a509a8977d2 +BYPRODUCT=libudfread.a diff --git a/tools/depends/target/xz/XZ-VERSION b/tools/depends/target/xz/XZ-VERSION new file mode 100644 index 0000000..288df10 --- /dev/null +++ b/tools/depends/target/xz/XZ-VERSION @@ -0,0 +1,4 @@ +LIBNAME=xz +VERSION=5.2.6 +ARCHIVE=$(LIBNAME)-$(VERSION).tar.xz +SHA512=5c69a492227c0ff72836d7a87e6372dc2e62bedfffb33f057263e28a6341825cef67834a863ed6ac02c5368c86da89f8affbe767f8bb914064cfa478f653e935 diff --git a/tools/depends/target/zlib/ZLIB-VERSION b/tools/depends/target/zlib/ZLIB-VERSION new file mode 100644 index 0000000..c609cbe --- /dev/null +++ b/tools/depends/target/zlib/ZLIB-VERSION @@ -0,0 +1,5 @@ +LIBNAME=zlib +VERSION=1.2.12 +ARCHIVE=$(LIBNAME)-$(VERSION).tar.xz +SHA512=12940e81e988f7661da52fa20bdc333314ae86a621fdb748804a20840b065a1d6d984430f2d41f3a057de0effc6ff9bcf42f9ee9510b88219085f59cbbd082bd +BYPRODUCT=libz.a diff --git a/tools/depends/xbmc-addons.include b/tools/depends/xbmc-addons.include new file mode 100644 index 0000000..928845b --- /dev/null +++ b/tools/depends/xbmc-addons.include @@ -0,0 +1,133 @@ +ADDON_DEPS_DIR := $(BUILDDIR)/$(PLATFORM)/build/depends +TOOLCHAIN_FILE = $(ADDON_DEPS_DIR)/share/Toolchain_binaddons.cmake +ADDON_PROJECT_DIR = $(BUILDDIR)/../../../../cmake/addons +export PKG_CONFIG_LIBDIR = $(ADDON_DEPS_DIR)/lib/pkgconfig + +ifeq ($(CROSS_COMPILING),yes) + DEPS = $(TOOLCHAIN_FILE) $(abs_top_srcdir)/target/config-binaddons.site $(abs_top_srcdir)/target/Toolchain_binaddons.cmake $(CONFIG_SUB) $(CONFIG_GUESS) + TOOLCHAIN = -DCMAKE_TOOLCHAIN_FILE=$(TOOLCHAIN_FILE) + ifeq ($(OS),linux) + DEPS += linux-system-libs linux-system-x11-libs + + ifeq ($(RENDER_SYSTEM),gl) + DEPS += linux-system-gl-libs + else + DEPS += linux-system-gles-libs + endif + endif +endif + +ifeq ($(PLATFORM),) + PLATFORM = native +endif +ifeq ($(CMAKE),) + CMAKE = cmake +endif + +CMAKE_EXTRA = +ifeq (darwin, $(findstring darwin, $(HOST))) + INSTALL_PREFIX = ../../../../../addons/ + CMAKE_EXTRA = -DPACKAGE_ZIP=ON +endif + +ifneq ($(PREFIX),) + ifneq (darwin, $(findstring darwin, $(HOST))) + INSTALL_PREFIX = $(PREFIX) -DOVERRIDE_PATHS=ON + endif + + CMAKE_EXTRA += -DAUTOCONF_FILES="$(CONFIG_SUB) $(CONFIG_GUESS)" +endif + +ifneq ($(TARBALLS_LOCATION),) + CMAKE_EXTRA += -DTARBALL_DIR=$(TARBALLS_LOCATION) +endif + +ifneq ($(ADDON_SRC_PREFIX),) + CMAKE_EXTRA += -DADDON_SRC_PREFIX=$(ADDON_SRC_PREFIX) +endif + +ifneq ($(ADDONS_DEFINITION_DIR),) + CMAKE_EXTRA += -DADDONS_DEFINITION_DIR=$(ADDONS_DEFINITION_DIR) +endif + +ifneq ($(EXTRA_CMAKE_ARGS),) + CMAKE_EXTRA += $(EXTRA_CMAKE_ARGS) +endif + +ifeq ($(PACKAGE),1) + MAKE_PACKAGE = package- +endif + +all: .installed-$(PLATFORM) + + +clean: + rm -f .installed-$(PLATFORM) + +distclean: + rm -rf $(PLATFORM) .installed-$(PLATFORM) native + +.installed-$(PLATFORM): $(DEPS) + cd $(ADDON_PROJECT_DIR) && (git clean -xfd || rm -rf CMakeCache.txt CMakeFiles cmake_install.cmake build/*) + mkdir -p $(PLATFORM) +ifeq ($(PREFIX),) + @echo + @echo "ERROR: please set PREFIX to the xbmc install path e.g. $(MAKE) PREFIX=/usr/local" + @exit 1 +endif +ifeq ($(CROSS_COMPILING),yes) + mkdir -p $(PLATFORM)/build/depends/share; \ + cp -f $(abs_top_srcdir)/target/config-binaddons.site $(PLATFORM)/build/depends/share/config.site +endif + cd $(PLATFORM); \ + $(CMAKE) -DCMAKE_INSTALL_PREFIX=$(INSTALL_PREFIX) $(CMAKE_EXTRA) \ + $(TOOLCHAIN) \ + -DADDONS_TO_BUILD="$(ADDONS)" $(ADDON_PROJECT_DIR) -DBUILD_DIR=$(BUILDDIR)/$(PLATFORM)/build ;\ + for addon in $$($(MAKE) supported_addons | awk '/^ALL_ADDONS_BUILDING: .*$$/ { first = $$1; $$1 = ""; print $$0 }'); do \ + $(MAKE) $(MAKE_PACKAGE)$$addon && echo $$addon >> $(ADDON_PROJECT_DIR)/.success || echo $$addon >> $(ADDON_PROJECT_DIR)/.failure ;\ + done +ifneq ($(CROSS_COMPILING),yes) + @[ -f $(ADDON_PROJECT_DIR)/.failure ] && echo "Following Addons failed to build:" $(shell cat $(ADDON_PROJECT_DIR)/.failure) || : + @cd $(PLATFORM); $(MAKE) need-sudo | grep -q TRUE && $(MAKE) sudo-install || : +endif + touch $@ + +$(TOOLCHAIN_FILE): $(abs_top_srcdir)/target/Toolchain_binaddons.cmake + mkdir -p $(ADDON_DEPS_DIR)/share + sed "s|@CMAKE_FIND_ROOT_PATH@|$(ADDON_DEPS_DIR)|g" $(abs_top_srcdir)/target/Toolchain_binaddons.cmake > $@ + +HOST_LIBDIR := $(firstword $(wildcard /usr/lib64 /usr/lib/$(HOST))) + +linux-system-libs: + mkdir -p $(ADDON_DEPS_DIR)/lib + [ -f $(ADDON_DEPS_DIR)/lib/libm.so ] || ln -sf $(HOST_LIBDIR)/libm.so $(ADDON_DEPS_DIR)/lib/ + +linux-system-x11-libs: + mkdir -p $(ADDON_DEPS_DIR)/lib/pkgconfig $(ADDON_DEPS_DIR)/include + [ -f $(ADDON_DEPS_DIR)/lib/pkgconfig/x11.pc ] || ln -sf $(HOST_LIBDIR)/pkgconfig/x*.pc $(ADDON_DEPS_DIR)/lib/pkgconfig/ + [ -f $(ADDON_DEPS_DIR)/lib/libX11.so ] || ln -sf $(HOST_LIBDIR)/libX11.so* $(ADDON_DEPS_DIR)/lib/ + [ -L $(ADDON_DEPS_DIR)/include/X11 ] || ln -sf /usr/include/X11 $(ADDON_DEPS_DIR)/include/X11 + [ -f $(ADDON_DEPS_DIR)/lib/pkgconfig/xproto.pc ] || ln -sf /usr/share/pkgconfig/x*.pc $(ADDON_DEPS_DIR)/lib/pkgconfig/ + [ -f $(ADDON_DEPS_DIR)/lib/pkgconfig/kbproto.pc ] || ln -sf /usr/share/pkgconfig/kbproto.pc $(ADDON_DEPS_DIR)/lib/pkgconfig/kbproto.pc + [ -f $(ADDON_DEPS_DIR)/lib/pkgconfig/damageproto.pc ] || ln -sf /usr/share/pkgconfig/damageproto.pc $(ADDON_DEPS_DIR)/lib/pkgconfig/damageproto.pc + [ -f $(ADDON_DEPS_DIR)/lib/pkgconfig/fixesproto.pc ] || ln -sf /usr/share/pkgconfig/fixesproto.pc $(ADDON_DEPS_DIR)/lib/pkgconfig/fixesproto.pc + [ -f $(ADDON_DEPS_DIR)/lib/pkgconfig/pthread-stubs.pc ] || ln -sf $(HOST_LIBDIR)/pkgconfig/pthread-stubs.pc $(ADDON_DEPS_DIR)/lib/pkgconfig/pthread-stubs.pc + [ -f $(ADDON_DEPS_DIR)/lib/pkgconfig/ice.pc ] || ln -sf $(HOST_LIBDIR)/pkgconfig/ice.pc $(ADDON_DEPS_DIR)/lib/pkgconfig/ice.pc + [ -f $(ADDON_DEPS_DIR)/lib/pkgconfig/sm.pc ] || ln -sf $(HOST_LIBDIR)/pkgconfig/sm.pc $(ADDON_DEPS_DIR)/lib/pkgconfig/sm.pc + [ -f $(ADDON_DEPS_DIR)/lib/pkgconfig/libdrm.pc ] || ln -sf $(HOST_LIBDIR)/pkgconfig/libdrm.pc $(ADDON_DEPS_DIR)/lib/pkgconfig/libdrm.pc + +linux-system-gl-libs: + mkdir -p $(ADDON_DEPS_DIR)/lib/pkgconfig $(ADDON_DEPS_DIR)/include + [ -f $(ADDON_DEPS_DIR)/lib/pkgconfig/gl.pc ] || ln -sf $(HOST_LIBDIR)/pkgconfig/gl.pc $(ADDON_DEPS_DIR)/lib/pkgconfig/gl.pc + [ -f $(ADDON_DEPS_DIR)/lib/pkgconfig/glu.pc ] || ln -sf $(HOST_LIBDIR)/pkgconfig/glu.pc $(ADDON_DEPS_DIR)/lib/pkgconfig/glu.pc + [ -f $(ADDON_DEPS_DIR)/lib/libGL.so ] || ln -sf $(HOST_LIBDIR)/libGL.so $(ADDON_DEPS_DIR)/lib/libGL.so + [ -L $(ADDON_DEPS_DIR)/include/GL ] || ln -sf /usr/include/GL $(ADDON_DEPS_DIR)/include/GL + +linux-system-gles-libs: + mkdir -p $(ADDON_DEPS_DIR)/lib/pkgconfig $(ADDON_DEPS_DIR)/include + [ -f $(ADDON_DEPS_DIR)/lib/pkgconfig/glesv2.pc ] || ln -sf $(PREFIX)/lib/pkgconfig/glesv2.pc $(ADDON_DEPS_DIR)/lib/pkgconfig/glesv2.pc + [ -f $(ADDON_DEPS_DIR)/lib/libGLESv2.so ] || ln -sf $(PREFIX)/lib/libGLESv2.so $(ADDON_DEPS_DIR)/lib/libGLESv2.so + [ -L $(ADDON_DEPS_DIR)/include/GLES2 ] || ln -sf $(PREFIX)/include/GLES2 $(ADDON_DEPS_DIR)/include/GLES2 + [ -L $(ADDON_DEPS_DIR)/include/KHR ] || ln -sf $(PREFIX)/include/KHR $(ADDON_DEPS_DIR)/include/KHR + [ -L $(ADDON_DEPS_DIR)/include/EGL ] || ln -sf $(PREFIX)/include/EGL $(ADDON_DEPS_DIR)/include/EGL + [ -f $(ADDON_DEPS_DIR)/lib/libEGL.so ] || ln -sf $(PREFIX)/lib/libEGL.so $(ADDON_DEPS_DIR)/lib/libEGL.so diff --git a/tools/static-analysis/cppcheck/cppcheck-rules.xml b/tools/static-analysis/cppcheck/cppcheck-rules.xml new file mode 100644 index 0000000..35f1fd1 --- /dev/null +++ b/tools/static-analysis/cppcheck/cppcheck-rules.xml @@ -0,0 +1,10 @@ +<?xml version="1.0"?> +<def> + <type-checks> + <unusedvar> + <suppress>CSingleLock</suppress> + <suppress>CSharedLock</suppress> + <suppress>CExclusiveLock</suppress> + </unusedvar> + </type-checks> +</def> diff --git a/tools/static-analysis/cppcheck/cppcheck-suppressions.xml b/tools/static-analysis/cppcheck/cppcheck-suppressions.xml new file mode 100644 index 0000000..251fd80 --- /dev/null +++ b/tools/static-analysis/cppcheck/cppcheck-suppressions.xml @@ -0,0 +1,19 @@ +<?xml version="1.0"?> +<suppressions> + <suppress> + <id>*</id> + <fileName>lib/*</fileName> + </suppress> + <suppress> + <id>*</id> + <fileName>build/*</fileName> + </suppress> + <suppress> + <id>*</id> + <fileName>tools/*</fileName> + </suppress> + <suppress> + <id>*</id> + <fileName>*.c</fileName> + </suppress> +</suppressions> |