Browse Source

initial commit

Kevin Bradley 4 years ago
parent
commit
05e3eb0a4c
100 changed files with 8804 additions and 0 deletions
  1. 101 0
      CycriptLoader/CycriptLoader.xm
  2. 18 0
      CycriptLoader/Makefile
  3. 18 0
      CycriptLoader/Makefile.tvos
  4. 1 0
      CycriptLoader/theos/Defines.h
  5. 609 0
      CycriptLoader/theos/LICENSE.md
  6. 55 0
      CycriptLoader/theos/Prefix.pch
  7. 6 0
      CycriptLoader/theos/README.md
  8. 31 0
      CycriptLoader/theos/bin/deb_build_num.sh
  9. 48 0
      CycriptLoader/theos/bin/denicify.pl
  10. 200 0
      CycriptLoader/theos/bin/dm.pl
  11. 1 0
      CycriptLoader/theos/bin/dm.pl.txt
  12. 46 0
      CycriptLoader/theos/bin/fakeroot.sh
  13. 6 0
      CycriptLoader/theos/bin/install.copyFile
  14. 19 0
      CycriptLoader/theos/bin/install.exec
  15. 4 0
      CycriptLoader/theos/bin/install.mergeDir
  16. 122 0
      CycriptLoader/theos/bin/lib/Logos/Class.pm
  17. 64 0
      CycriptLoader/theos/bin/lib/Logos/Function.pm
  18. 48 0
      CycriptLoader/theos/bin/lib/Logos/Generator.pm
  19. 55 0
      CycriptLoader/theos/bin/lib/Logos/Generator/Base/Class.pm
  20. 177 0
      CycriptLoader/theos/bin/lib/Logos/Generator/Base/Function.pm
  21. 49 0
      CycriptLoader/theos/bin/lib/Logos/Generator/Base/Generator.pm
  22. 28 0
      CycriptLoader/theos/bin/lib/Logos/Generator/Base/Group.pm
  23. 119 0
      CycriptLoader/theos/bin/lib/Logos/Generator/Base/Method.pm
  24. 271 0
      CycriptLoader/theos/bin/lib/Logos/Generator/Base/Property.pm
  25. 34 0
      CycriptLoader/theos/bin/lib/Logos/Generator/Base/StaticClassGroup.pm
  26. 12 0
      CycriptLoader/theos/bin/lib/Logos/Generator/Base/Subclass.pm
  27. 19 0
      CycriptLoader/theos/bin/lib/Logos/Generator/MobileSubstrate/Class.pm
  28. 18 0
      CycriptLoader/theos/bin/lib/Logos/Generator/MobileSubstrate/Function.pm
  29. 22 0
      CycriptLoader/theos/bin/lib/Logos/Generator/MobileSubstrate/Generator.pm
  30. 122 0
      CycriptLoader/theos/bin/lib/Logos/Generator/MobileSubstrate/Method.pm
  31. 32 0
      CycriptLoader/theos/bin/lib/Logos/Generator/MobileSubstrate/Subclass.pm
  32. 54 0
      CycriptLoader/theos/bin/lib/Logos/Generator/Thunk.pm
  33. 51 0
      CycriptLoader/theos/bin/lib/Logos/Generator/internal/Class.pm
  34. 14 0
      CycriptLoader/theos/bin/lib/Logos/Generator/internal/Function.pm
  35. 22 0
      CycriptLoader/theos/bin/lib/Logos/Generator/internal/Generator.pm
  36. 141 0
      CycriptLoader/theos/bin/lib/Logos/Generator/internal/Method.pm
  37. 33 0
      CycriptLoader/theos/bin/lib/Logos/Generator/internal/Subclass.pm
  38. 136 0
      CycriptLoader/theos/bin/lib/Logos/Group.pm
  39. 39 0
      CycriptLoader/theos/bin/lib/Logos/Ivar.pm
  40. 285 0
      CycriptLoader/theos/bin/lib/Logos/Method.pm
  41. 98 0
      CycriptLoader/theos/bin/lib/Logos/Patch.pm
  42. 27 0
      CycriptLoader/theos/bin/lib/Logos/Patch/Source/Generator.pm
  43. 69 0
      CycriptLoader/theos/bin/lib/Logos/Property.pm
  44. 51 0
      CycriptLoader/theos/bin/lib/Logos/StaticClassGroup.pm
  45. 67 0
      CycriptLoader/theos/bin/lib/Logos/Subclass.pm
  46. 113 0
      CycriptLoader/theos/bin/lib/Logos/Util.pm
  47. 120 0
      CycriptLoader/theos/bin/lib/NIC/Bridge/Context.pm
  48. 6 0
      CycriptLoader/theos/bin/lib/NIC/Bridge/Directory.pm
  49. 13 0
      CycriptLoader/theos/bin/lib/NIC/Bridge/File.pm
  50. 76 0
      CycriptLoader/theos/bin/lib/NIC/Bridge/NICBase.pm
  51. 29 0
      CycriptLoader/theos/bin/lib/NIC/Bridge/NICType.pm
  52. 13 0
      CycriptLoader/theos/bin/lib/NIC/Bridge/Symlink.pm
  53. 28 0
      CycriptLoader/theos/bin/lib/NIC/Bridge/Tie/WrappedMethod.pm
  54. 19 0
      CycriptLoader/theos/bin/lib/NIC/Bridge/_BridgedObject.pm
  55. 21 0
      CycriptLoader/theos/bin/lib/NIC/Bridge/_Undefined.pm
  56. 60 0
      CycriptLoader/theos/bin/lib/NIC/Formats/NIC1.pm
  57. 146 0
      CycriptLoader/theos/bin/lib/NIC/Formats/NICTar.pm
  58. 11 0
      CycriptLoader/theos/bin/lib/NIC/Formats/NICTar/Directory.pm
  59. 16 0
      CycriptLoader/theos/bin/lib/NIC/Formats/NICTar/File.pm
  60. 11 0
      CycriptLoader/theos/bin/lib/NIC/Formats/NICTar/Symlink.pm
  61. 20 0
      CycriptLoader/theos/bin/lib/NIC/Formats/NICTar/_TarMixin.pm
  62. 221 0
      CycriptLoader/theos/bin/lib/NIC/NICBase.pm
  63. 24 0
      CycriptLoader/theos/bin/lib/NIC/NICBase/Directory.pm
  64. 36 0
      CycriptLoader/theos/bin/lib/NIC/NICBase/File.pm
  65. 52 0
      CycriptLoader/theos/bin/lib/NIC/NICBase/Symlink.pm
  66. 79 0
      CycriptLoader/theos/bin/lib/NIC/NICType.pm
  67. 26 0
      CycriptLoader/theos/bin/lib/NIC/Tie/Method.pm
  68. 34 0
      CycriptLoader/theos/bin/lib/NIC/Tie/PrefixedHandleRedirect.pm
  69. 326 0
      CycriptLoader/theos/bin/lib/aliased.pm
  70. 136 0
      CycriptLoader/theos/bin/lib/parent.pm
  71. 63 0
      CycriptLoader/theos/bin/logify.pl
  72. 967 0
      CycriptLoader/theos/bin/logos.pl
  73. 324 0
      CycriptLoader/theos/bin/nic.pl
  74. 147 0
      CycriptLoader/theos/bin/nicify.pl
  75. 44 0
      CycriptLoader/theos/bin/package_version.sh
  76. 26 0
      CycriptLoader/theos/bin/target.pl
  77. 23 0
      CycriptLoader/theos/bin/vercmp.pl
  78. 7 0
      CycriptLoader/theos/documentation/Makefile
  79. 405 0
      CycriptLoader/theos/documentation/makefiles.docbook
  80. 3 0
      CycriptLoader/theos/extras/vim/README
  81. 11 0
      CycriptLoader/theos/extras/vim/ftplugin/logos.vim
  82. 6 0
      CycriptLoader/theos/extras/vim/indent/logos.vim
  83. 69 0
      CycriptLoader/theos/extras/vim/syntax/logos.vim
  84. 11 0
      CycriptLoader/theos/git-submodule-recur.sh
  85. 0 0
      CycriptLoader/theos/include/.keep
  86. 1 0
      CycriptLoader/theos/include/APDeviceController.h
  87. 32 0
      CycriptLoader/theos/include/AppSupport/CPDistributedMessagingCenter.h
  88. 65 0
      CycriptLoader/theos/include/ContextFilterLogFormatter.h
  89. 35 0
      CycriptLoader/theos/include/Cycript.h
  90. 41 0
      CycriptLoader/theos/include/DDASLLogger.h
  91. 102 0
      CycriptLoader/theos/include/DDAbstractDatabaseLogger.h
  92. 14 0
      CycriptLoader/theos/include/DDData.h
  93. 334 0
      CycriptLoader/theos/include/DDFileLogger.h
  94. 601 0
      CycriptLoader/theos/include/DDLog.h
  95. 12 0
      CycriptLoader/theos/include/DDNumber.h
  96. 56 0
      CycriptLoader/theos/include/DDRange.h
  97. 167 0
      CycriptLoader/theos/include/DDTTYLogger.h
  98. 19 0
      CycriptLoader/theos/include/DHCommon.h
  99. 141 0
      CycriptLoader/theos/include/DHHookCommon.h
  100. 0 0
      CycriptLoader/theos/include/DispatchQueueLogFormatter.h

+ 101 - 0
CycriptLoader/CycriptLoader.xm

@@ -0,0 +1,101 @@
+/**
+ * CycriptLoader
+ *
+ * Load cycript!
+ *
+ * By Sam Binger and Kevin Bradley
+ *
+ */
+
+/**
+
+This dylib injects into our target process, iterates through which port is available and then posts a distributed notification that our cycripter binary is waiting to hear back
+and starts listening with CYListenServer on the specified port. After cycripter echoes out the command the user can succesfully connect to cycript and control the injected process.
+
+
+*/
+
+
+#import <Foundation/Foundation.h>
+#import "Cycript.h"
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+
+@interface NSDistributedNotificationCenter : NSNotificationCenter
+
++ (id)defaultCenter;
+
+- (void)addObserver:(id)arg1 selector:(SEL)arg2 name:(id)arg3 object:(id)arg4;
+- (void)postNotificationName:(id)arg1 object:(id)arg2 userInfo:(id)arg3;
+
+@end
+
+
+%ctor
+{
+
+    //check to see if 1337 is available
+
+int sock = socket(AF_INET, SOCK_STREAM, 0);
+    if(sock < 0) {
+        NSLog(@"#### cycript runner: socket error\n");
+        return;
+    }
+    printf("Opened %d\n", sock);
+    in_port_t port = 1337;
+    struct sockaddr_in serv_addr;
+    bzero((char *) &serv_addr, sizeof(serv_addr));
+    serv_addr.sin_family = AF_INET;
+    serv_addr.sin_addr.s_addr = INADDR_ANY;
+    serv_addr.sin_port = port;
+    BOOL usablePort = FALSE;
+    
+    while(usablePort != TRUE){
+        if (bind(sock, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0) {
+            if(errno == EADDRINUSE) {
+                 NSLog(@"#### cycript runner: the port is not available: %hu already to other process\n", port);
+                port++;
+                serv_addr.sin_port = port;
+                continue;
+            } else {
+                NSLog(@"#### cycript runner: could not bind to process (%d) %s\n", errno, strerror(errno));
+                break;
+                //return;
+            }
+        } else {
+            
+            usablePort = TRUE;
+            NSLog(@"#### cycript runner: success with port %i\n", port);
+            
+        }
+        
+    }
+    
+   
+    
+    socklen_t len = sizeof(serv_addr);
+    if (getsockname(sock, (struct sockaddr *)&serv_addr, &len) == -1) {
+        perror("getsockname");
+        //return;
+    }
+
+    //int port = ntohs(serv_addr.sin_port);
+
+
+    NSLog(@"#### cycript runner: port number %d\n", port);
+    NSString *portNumber = [NSString stringWithFormat:@"%d", port];
+    [[NSDistributedNotificationCenter defaultCenter] postNotificationName:@"cycriptPortAvailable" object:nil userInfo:@{@"port": portNumber}];
+    
+  
+    /*
+    if (close (sock) < 0 ) {
+        NSLog(@"#### cycript runner: did not close: %s\n", strerror(errno));
+       // return;
+    }
+    */
+
+    CYListenServer(port);
+    NSLog(@"running server on port: %d", port);
+} 

+ 18 - 0
CycriptLoader/Makefile

@@ -0,0 +1,18 @@
+ARCHS = arm64
+TARGET = iphone
+export GO_EASY_ON_ME=1
+export SDKVERSION=11.0
+THEOS_DEVICE_IP=bedroom.local
+
+include theos/makefiles/common.mk
+
+LIBRARY_NAME = CycriptLoader
+CycriptLoader_FILES = CycriptLoader.xm
+CycriptLoader_FRAMEWORKS = Foundation
+CycriptLoader_LDFLAGS = -lcycript -undefined dynamic_lookup
+
+
+include $(THEOS_MAKE_PATH)/library.mk
+
+after-install::
+	install.exec "killall -9 lsd"

+ 18 - 0
CycriptLoader/Makefile.tvos

@@ -0,0 +1,18 @@
+ARCHS = arm64
+TARGET = appletv
+export GO_EASY_ON_ME=1
+export SDKVERSION=11.0
+THEOS_DEVICE_IP=bedroom.local
+
+include theos/makefiles/common.mk
+
+LIBRARY_NAME = CycriptLoader
+CycriptLoader_FILES = CycriptLoader.xm
+CycriptLoader_FRAMEWORKS = Foundation
+CycriptLoader_LDFLAGS = -lcycript -undefined dynamic_lookup
+
+
+include $(THEOS_MAKE_PATH)/library.mk
+
+after-install::
+	install.exec "killall -9 lsd"

+ 1 - 0
CycriptLoader/theos/Defines.h

@@ -0,0 +1 @@
+../Defines.h

+ 609 - 0
CycriptLoader/theos/LICENSE.md

@@ -0,0 +1,609 @@
+Theos (and by extension, Logos) is available under the provisions of the GNU
+General Public License, version 3 (or later), available here:
+http://www.gnu.org/licenses/gpl-3.0.html.
+
+Projects created using Theos and/or Logos are not considered derivative works
+(from a licensing standpoint, or, for that matter, any other standpoint) and
+are, as such, not required to be licensed under the GNU GPL.
+
+The included project templates are license-free. The use of a template does
+not confer a license to your project.
+
+----
+
+GNU GENERAL PUBLIC LICENSE
+==========================
+
+Version 3, 29 June 2007
+
+Copyright © 2007 Free Software Foundation, Inc. &lt;<http://fsf.org/>&gt;
+
+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.
+
+END OF TERMS AND CONDITIONS
+
+## How to Apply These Terms to Your New Programs
+
+If you develop a new program, and you want it to be of the greatest possible use to
+the public, the best way to achieve this is to make it free software which everyone
+can redistribute and change under these terms.
+
+To do so, attach the following notices to the program. It is safest to attach them
+to the start of each source file to most effectively state the exclusion of warranty;
+and each file should have at least the “copyright” line and a pointer to
+where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This program is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 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/>.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program does terminal interaction, make it output a short notice like this
+when it starts in an interactive mode:
+
+    <program>  Copyright (C) <year>  <name of author>
+    This program comes with ABSOLUTELY NO WARRANTY; for details type 'show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type 'show c' for details.
+
+The hypothetical commands 'show w' and 'show c' should show the appropriate parts of
+the General Public License. Of course, your program's commands might be different;
+for a GUI interface, you would use an “about box”.
+
+You should also get your employer (if you work as a programmer) or school, if any, to
+sign a “copyright disclaimer” for the program, if necessary. For more
+information on this, and how to apply and follow the GNU GPL, see
+&lt;<http://www.gnu.org/licenses/>&gt;.
+
+The GNU General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may consider it
+more useful to permit linking proprietary applications with the library. If this is
+what you want to do, use the GNU Lesser General Public License instead of this
+License. But first, please read
+&lt;<http://www.gnu.org/philosophy/why-not-lgpl.html>&gt;.

+ 55 - 0
CycriptLoader/theos/Prefix.pch

@@ -0,0 +1,55 @@
+#ifdef DEBUG
+	#define __DEBUG__
+#endif
+
+#ifdef __OBJC__
+	#import <_Prefix/NullabilityCompat.h>
+
+	#if __has_feature(modules)
+		@import Foundation;
+	#else
+		#import <Foundation/Foundation.h>
+	#endif
+
+	#ifdef TARGET_OS_SIMULATOR
+		#define _THEOS_IS_SIMULATOR TARGET_OS_SIMULATOR
+	#else
+		#define _THEOS_IS_SIMULATOR TARGET_IPHONE_SIMULATOR
+	#endif
+
+	#if TARGET_IPHONE || _THEOS_IS_SIMULATOR
+		#if __has_feature(modules)
+			@import UIKit;
+		#else
+			#import <UIKit/UIKit.h>
+			
+		#endif
+
+		#import <_Prefix/IOSWebKitCompatHacks.h>
+	#endif
+
+	#if TARGET_MACOSX
+		#if __has_feature(modules)
+			@import Cocoa;
+			@import AppKit;
+		#else
+			#import <Cocoa/Cocoa.h>
+			#import <AppKit/AppKit.h>
+		#endif
+	#endif
+
+	#import <_Prefix/HBLog.h>
+	#import <_Prefix/IOSMacros.h>
+	#define NB [NSBundle mainBundle]
+	#define UD [NSUserDefaults standardUserDefaults]
+	#define FM [NSFileManager defaultManager]
+#endif
+
+#ifndef __clang__
+#import <Availability.h>
+#undef NS_AVAILABLE
+#define NS_AVAILABLE(osx, ios)
+#undef __OSX_AVAILABLE_STARTING
+#define __OSX_AVAILABLE_STARTING(osx, ios)
+#include <stdbool.h>
+#endif

+ 6 - 0
CycriptLoader/theos/README.md

@@ -0,0 +1,6 @@
+# Theos
+**Unified cross-platform Makefile system.**
+
+See [LICENSE.md](LICENSE.md) for licensing information.
+
+To learn more, including how to install or switch to this fork of Theos, visit [**the wiki**](https://github.com/kirb/theos/wiki).

+ 31 - 0
CycriptLoader/theos/bin/deb_build_num.sh

@@ -0,0 +1,31 @@
+#!/bin/bash
+GETONLY=0
+if [[ $1 == "-g" ]]; then
+	GETONLY=1
+	shift
+fi
+
+if [[ $# -lt 2 ]]; then
+	echo "Syntax: $0 [-g] packagename versionname" >&2
+	exit 1
+fi
+
+if [[ ! -d $TOP_DIR/.debmake ]]; then
+	mkdir $TOP_DIR/.debmake
+fi
+
+PACKAGE=$1
+VERSION=$2
+INFOFILE=$TOP_DIR/.debmake/$PACKAGE-$VERSION
+if [[ ! -e $INFOFILE ]]; then
+	echo -n 1 > $INFOFILE
+	echo -n 1
+	exit 0
+else
+	CURNUM=$(cat $INFOFILE)
+	if [[ $GETONLY -eq 0 ]]; then
+		let CURNUM++
+		echo -n $CURNUM > $INFOFILE
+	fi
+	echo $CURNUM
+fi

+ 48 - 0
CycriptLoader/theos/bin/denicify.pl

@@ -0,0 +1,48 @@
+#!/usr/bin/perl
+
+use warnings;
+use FindBin;
+use lib "$FindBin::Bin/lib";
+
+use NIC::NICBase;
+
+use Module::Load::Conditional 'can_load';
+
+$nicfile = $ARGV[0] if($ARGV[0]);
+$outputdir = $ARGV[1];
+if(!$nicfile || !$outputdir) {
+	exitWithError("Syntax: $0 nicfile outputdir");
+}
+
+### LOAD THE NICFILE! ###
+open(my $nichandle, "<", $nicfile);
+my $line = <$nichandle>;
+my $nicversion = 1;
+if($line =~ /^nic (\w+)$/) {
+	$nicversion = $1;
+} elsif($nicfile =~ /\.tar$/) {
+	$nicversion = "Tar";
+}
+seek($nichandle, 0, 0);
+
+my $NICPackage = "NIC$nicversion";
+exitWithError("I don't understand NIC version $nicversion!") if(!can_load(modules => {"NIC::Formats::$NICPackage" => undef}));
+
+{
+	no warnings 'redefine';
+	sub NIC::NICBase::_meetsConstraints { return 1; }
+}
+
+my $NIC = "NIC::Formats::$NICPackage"->new($nichandle);
+$NIC->addConstraint("package");
+close($nichandle);
+### YAY! ###
+
+$NIC->build($outputdir);
+$NIC->dumpPreamble("pre.NIC");
+
+sub exitWithError {
+	my $error = shift;
+	print STDERR "[error] ", $error, $/;
+	exit 1;
+}

+ 200 - 0
CycriptLoader/theos/bin/dm.pl

@@ -0,0 +1,200 @@
+#!/usr/bin/perl
+use strict;
+use warnings;
+use File::Find;
+use File::Spec;
+use Cwd;
+use Getopt::Long;
+use Pod::Usage;
+use Archive::Tar;
+use IO::Compress::Gzip;
+use IO::Compress::Bzip2;
+
+package NIC::Archive::Tar::File;
+use parent "Archive::Tar::File";
+sub new {
+	my $class = shift;
+	my $self = Archive::Tar::File->new(@_);
+	bless($self, $class);
+	return $self;
+}
+
+sub full_path {
+	my $self = shift;
+	my $full_path = $self->SUPER::full_path(); $full_path = '' unless defined $full_path;
+	$full_path =~ s#^#./# if $full_path ne "" && $full_path ne "." && $full_path !~ m#^\./#;
+	return $full_path;
+}
+1;
+package main;
+
+our $VERSION = '2.0';
+
+our $_PROGNAME = "dm.pl";
+
+my $ADMINARCHIVENAME = "control.tar.gz";
+my $DATAARCHIVENAME = "data.tar";
+my $ARCHIVEVERSION = "2.0";
+
+$Archive::Tar::DO_NOT_USE_PREFIX = 1; # use GNU extensions (not POSIX prefix)
+
+our $compression = "gzip";
+Getopt::Long::Configure("bundling", "auto_version");
+GetOptions('compression|Z=s' => \$compression,
+	'build|b' => sub { },
+	'help|?' => sub { pod2usage(1); },
+	'man' => sub { pod2usage(-exitstatus => 0, -verbose => 2); })
+	or pod2usage(2);
+
+pod2usage(1) if(@ARGV < 2);
+
+my $pwd = Cwd::cwd();
+my $indir = File::Spec->rel2abs($ARGV[0]);
+my $outfile = $ARGV[1];
+
+die "ERROR: '$indir' is not a directory or does not exist.\n" unless -d $indir;
+
+my $controldir = File::Spec->catpath("", $indir, "DEBIAN");
+
+die "ERROR: control directory '$controldir' is not a directory or does not exist.\n" unless -d $controldir;
+my $mode = (lstat($controldir))[2];
+die sprintf("ERROR: control directory has bad permissions %03lo (must be >=0755 and <=0775)\n", $mode & 07777) if(($mode & 07757) != 0755);
+
+my $controlfile = File::Spec->catfile($controldir, "control");
+die "ERROR: control file '$controlfile' is not a plain file\n" unless -f $controlfile;
+my %control_data = read_control_file($controlfile);
+
+die "ERROR: package name has characters that aren't alphanumueric or '-+.'.\n" if($control_data{"package"} =~ m/[^a-zA-Z0-9+-.]/);
+die "ERROR: package version ".$control_data{"version"}." doesn't contain any digits.\n" if($control_data{"version"} !~ m/[0-9]/);
+
+foreach my $m ("preinst", "postinst", "prerm", "postrm", "extrainst_") {
+	$_ = File::Spec->catfile($controldir, $m);
+	next unless -e $_;
+	die "ERROR: maintainer script '$m' is not a plain file or symlink\n" unless(-f $_ || -l $_);
+	$mode = (lstat)[2];
+	die sprintf("ERROR: maintainer script '$m' has bad permissions %03lo (must be >=0555 and <=0775)\n", $mode & 07777) if(($mode & 07557) != 0555)
+}
+
+print "$_PROGNAME: building package `".$control_data{"package"}.":".$control_data{"architecture"}."' in `$outfile'\n";
+
+open(my $ar, '>', $outfile) or die $!;
+
+print $ar "!<arch>\n";
+print_ar_record($ar, "debian-binary", time, 0, 0, 0100644, 4);
+print_ar_file($ar, "$ARCHIVEVERSION\n", 4);
+
+{
+	my $tar = Archive::Tar->new();
+	$tar->add_files(tar_filelist($controldir));
+	my $comp;
+	my $zFd = IO::Compress::Gzip->new(\$comp, -Level => 9);
+	$tar->write($zFd);
+	$zFd->close();
+	print_ar_record($ar, $ADMINARCHIVENAME, time, 0, 0, 0100644, length($comp));
+	print_ar_file($ar, $comp, length($comp));
+} {
+	my $tar = Archive::Tar->new();
+	$tar->add_files(tar_filelist($indir));
+	my $comp;
+	my $zFd = compressed_fd(\$comp);
+	$tar->write($zFd);
+	$zFd->close();
+	print_ar_record($ar, compressed_filename($DATAARCHIVENAME), time, 0, 0, 0100644, length($comp));
+	print_ar_file($ar, $comp, length($comp));
+}
+
+close $ar;
+
+sub print_ar_record {
+	my ($fh, $filename, $timestamp, $uid, $gid, $mode, $size) = @_;
+	printf $fh "%-16s%-12lu%-6lu%-6lu%-8lo%-10ld`\n", $filename, $timestamp, $uid, $gid, $mode, $size;
+	$fh->flush();
+}
+
+sub print_ar_file {
+	my ($fh, $data, $size) = @_;
+	syswrite $fh, $data;
+	print $fh "\n" if($size % 2 == 1);
+	$fh->flush();
+}
+
+sub tar_filelist {
+	chdir(shift);
+	my @filelist;
+	my @symlinks;
+
+	find({wanted => sub {
+		return if m#^./DEBIAN#;
+		my $tf = NIC::Archive::Tar::File->new(file=>$_);
+		push @symlinks, $tf if -l;
+		push @filelist, $tf if ! -l;
+	}, no_chdir => 1}, ".");
+	return (@filelist, @symlinks);
+}
+
+sub read_control_file {
+	my $filename = shift;
+	open(my $fh, '<', $filename) or die "ERROR: can't open control file '$filename'\n";
+	my %data;
+	while(<$fh>) {
+		if(m/^(.*?): (.*)/) {
+			$data{lc($1)} = $2;
+		}
+	}
+	close $fh;
+	return %data;
+}
+
+sub compressed_fd {
+	my $sref = shift;
+	return IO::Compress::Gzip->new($sref, -Level => 9) if $::compression eq "gzip";
+	return IO::Compress::Bzip2->new($sref) if $::compression eq "bzip2";
+	open my $fh, ">", $sref;
+	return $fh;
+}
+
+sub compressed_filename {
+	my $fn = shift;
+	my $suffix = "";
+	$suffix = ".gz" if $::compression eq "gzip";
+	$suffix = ".bz2" if $::compression eq "bzip2";
+	return $fn.$suffix;
+}
+
+__END__
+
+=head1 NAME
+
+dm.pl
+
+=head1 SYNOPSIS
+
+dm.pl [options] <directory> <package>
+
+=head1 OPTIONS
+
+=over 8
+
+=item B<-b>
+
+This option exists solely for compatibility with dpkg-deb.
+
+=item B<-ZE<lt>compressionE<gt>>
+
+Specify the package compression type. Valid values are gzip (default), bzip2 and cat (no compression.)
+
+=item B<--help>, B<-?>
+
+Print a brief help message and exit.
+
+=item B<--man>
+
+Print a manual page and exit.
+
+=back
+
+=head1 DESCRIPTION
+
+B<This program> creates Debian software packages (.deb files) and is a drop-in replacement for dpkg-deb.
+
+=cut

+ 1 - 0
CycriptLoader/theos/bin/dm.pl.txt

@@ -0,0 +1 @@
+dm.pl is at revision ac95b88a5c84747b1c40c3456525efeb3a750eed

+ 46 - 0
CycriptLoader/theos/bin/fakeroot.sh

@@ -0,0 +1,46 @@
+#!/bin/bash
+required=0
+persistence=/tmp/dhbxxx
+
+while getopts ":p:rc" flag; do
+	case "$flag" in
+		:)	echo "$0: Option -$OPTARG requires an argument." 1>&2
+			exit 1
+			;;
+		\?)	echo "$0: Option -$OPTARG unrecognized." 1>&2
+			exit 1
+			;;
+		p)	persistence="$OPTARG" ;;
+		r)	required=1 ;;
+		c)	delpersistence=1 ;;
+	esac
+done
+shift $((OPTIND-1))
+cmd=$*
+
+mkdir -p $(dirname $persistence)
+touch $persistence
+
+if [[ $delpersistence -eq 1 ]]; then
+	rm -f $persistence
+	exit 0
+fi
+
+if [[ "$USER" == "root" ]]; then
+	fakeroot=""
+elif type fauxsu &> /dev/null; then
+	fakeroot="fauxsu -p $persistence -- "
+elif type fakeroot-ng &> /dev/null; then
+	fakeroot="fakeroot-ng -p $persistence -- "
+elif type fakeroot &> /dev/null; then
+	fakeroot="fakeroot -i $persistence -s $persistence -- "
+else
+	if [[ $required -eq 1 ]]; then
+		fakeroot=""
+	else
+		fakeroot=": "
+	fi
+fi
+
+#echo $fakeroot $cmd
+$fakeroot $cmd

+ 6 - 0
CycriptLoader/theos/bin/install.copyFile

@@ -0,0 +1,6 @@
+#!/bin/bash
+if [[ TARGET_INSTALL_REMOTE -eq 1 ]]; then
+	scp -P $THEOS_DEVICE_PORT "$1" $THEOS_DEVICE_USER@$THEOS_DEVICE_IP:$2
+else
+	cp "$1" "$2"
+fi

+ 19 - 0
CycriptLoader/theos/bin/install.exec

@@ -0,0 +1,19 @@
+#!/bin/bash
+if [[ TARGET_INSTALL_REMOTE -eq 1 ]]; then
+	args=(ssh)
+
+	if [[ ! -z "$THEOS_DEVICE_PORT" ]]; then
+		args+=(-p "$THEOS_DEVICE_PORT")
+	fi
+
+	if [[ ! -z "$THEOS_DEVICE_USER" ]]; then
+		args+=(-l "$THEOS_DEVICE_USER")
+	fi
+
+	args+=($THEOS_DEVICE_IP)
+	args+=("$@")
+
+	exec ${args[@]}
+else
+	exec su -c "$@"
+fi

+ 4 - 0
CycriptLoader/theos/bin/install.mergeDir

@@ -0,0 +1,4 @@
+#!/bin/bash
+cd "$1"
+# Use fakeroot.sh to ensure that permissions are preserved, and install.exec to ensure that we are running tar -x on the right system.
+fakeroot.sh -r tar -c . | install.exec "tar -x -C \"$2\""

+ 122 - 0
CycriptLoader/theos/bin/lib/Logos/Class.pm

@@ -0,0 +1,122 @@
+package Logos::Class;
+use strict;
+
+sub new {
+	my $proto = shift;
+	my $class = ref($proto) || $proto;
+	my $self = {};
+	$self->{NAME} = undef;
+	$self->{EXPR} = undef;
+	$self->{METAEXPR} = undef;
+	$self->{TYPE} = undef;
+	$self->{META} = 0;
+	$self->{INST} = 0;
+	$self->{OVERRIDDEN} = 0;
+	$self->{REQUIRED} = 0;
+	$self->{METHODS} = [];
+	$self->{NUM_METHODS} = 0;
+	$self->{PROPERTIES} = [];
+	$self->{NUM_PROPERTIES} = 0;
+	$self->{GROUP} = undef;
+	bless($self, $class);
+	return $self;
+}
+
+##################### #
+# Setters and Getters #
+# #####################
+sub name {
+	my $self = shift;
+	if(@_) { $self->{NAME} = shift; }
+	return $self->{NAME};
+}
+
+sub expression {
+	my $self = shift;
+	if(@_) {
+		$self->{EXPR} = shift;
+		$self->type("id");
+		$self->{OVERRIDDEN} = 1;
+	}
+	return $self->{EXPR};
+}
+
+sub metaexpression {
+	my $self = shift;
+	if(@_) {
+		$self->{METAEXPR} = shift;
+		$self->{OVERRIDDEN} = 1;
+	}
+	return $self->{METAEXPR};
+}
+
+sub type {
+	my $self = shift;
+	if(@_) { $self->{TYPE} = shift; }
+	return $self->{TYPE} if $self->{TYPE};
+	return $self->{NAME}."*";
+}
+
+sub hasmetahooks {
+	my $self = shift;
+	if(@_) { $self->{META} = shift; }
+	return $self->{META};
+}
+
+sub hasinstancehooks {
+	my $self = shift;
+	if(@_) { $self->{INST} = shift; }
+	return $self->{INST};
+}
+
+sub group {
+	my $self = shift;
+	if(@_) { $self->{GROUP} = shift; }
+	return $self->{GROUP};
+}
+
+sub required {
+	my $self = shift;
+	if(@_) { $self->{REQUIRED} = shift; }
+	return $self->{REQUIRED};
+}
+
+sub overridden {
+	my $self = shift;
+	return $self->{OVERRIDDEN};
+}
+
+sub methods {
+	my $self = shift;
+	return $self->{METHODS};
+}
+
+sub properties {
+	my $self = shift;
+	return $self->{PROPERTIES};
+}
+
+sub initRequired {
+	my $self = shift;
+	return $self->required || scalar @{$self->{METHODS}} > 0;
+}
+
+##### #
+# END #
+# #####
+
+sub addMethod {
+	my $self = shift;
+	my $hook = shift;
+	push(@{$self->{METHODS}}, $hook);
+	$self->{NUM_METHODS}++;
+}
+
+sub addProperty {
+	my $self = shift;
+	my $property = shift;
+	push(@{$self->{PROPERTIES}}, $property);
+	$self->{NUM_PROPERTIES}++;
+}
+
+1;

+ 64 - 0
CycriptLoader/theos/bin/lib/Logos/Function.pm

@@ -0,0 +1,64 @@
+package Logos::Function;
+use strict;
+
+sub new {
+	my $proto = shift;
+	my $function = ref($proto) || $proto;
+	my $self = {};
+	$self->{NAME} = undef;
+	$self->{RETVAL} = undef;
+	$self->{ARGS} = [];
+	$self->{GROUP} = undef;
+	$self->{REQUIRED} = 0;
+	bless($self, $function);
+	return $self;
+}
+
+##################### #
+# Setters and Getters #
+# #####################
+sub name {
+	my $self = shift;
+	if(@_) { $self->{NAME} = shift; }
+	return $self->{NAME};
+}
+
+sub retval {
+	my $self = shift;
+	if(@_) { $self->{RETVAL} = shift; }
+	return $self->{RETVAL};
+}
+
+sub args {
+	my $self = shift;
+	return $self->{ARGS};
+}
+
+sub group {
+	my $self = shift;
+	if(@_) { $self->{GROUP} = shift; }
+	return $self->{GROUP};
+}
+
+sub required {
+	my $self = shift;
+	if(@_) { $self->{REQUIRED} = shift; }
+	return $self->{REQUIRED};
+}
+
+sub initRequired {
+	my $self = shift;
+	return 1;
+}
+
+##### #
+# END #
+# #####
+
+sub addArg {
+	my $self = shift;
+	my $arg = shift;
+	push(@{$self->{ARGS}}, $arg);
+}
+
+1;

+ 48 - 0
CycriptLoader/theos/bin/lib/Logos/Generator.pm

@@ -0,0 +1,48 @@
+package Logos::Generator;
+use strict;
+use Logos::Generator::Thunk;
+use Scalar::Util qw(blessed);
+use Module::Load::Conditional qw(can_load);
+$Module::Load::Conditional::VERBOSE = 1;
+our $GeneratorPackage = "";
+
+my %cache;
+
+sub for {
+	my $object = shift;
+	my $dequalified = undef;
+	my $cachekey;
+	if(defined $object) {
+		$cachekey = $object;
+		my $class = blessed($object);
+		($dequalified = $class) =~ s/.*::// if defined $class
+	}
+	$cachekey = "-" if !$cachekey;
+	$dequalified .= "Generator" if !defined $dequalified;
+	return $cache{$cachekey} if $cache{$cachekey};
+
+	my $qualified = $GeneratorPackage."::".$dequalified;
+	my $fallback = "Logos::Generator::Base::".$dequalified;
+
+	my $shouldFallBack = 0;
+	can_load(modules=>{$qualified=>undef},verbose=>0) || ($shouldFallBack = 1);
+	can_load(modules=>{$fallback=>undef},verbose=>1) if $shouldFallBack;
+
+	my $thunk = Logos::Generator::Thunk->for(($shouldFallBack ? $fallback : $qualified), $object);
+	$cache{$cachekey} = $thunk;
+	return $thunk;
+}
+
+sub use {
+	my $generatorName = shift;
+	if($generatorName =~ /^(\w+)@(.+)$/) {
+		$generatorName = $1;
+		unshift @INC, $2;
+	}
+	$GeneratorPackage = "Logos::Generator::".$generatorName;
+	::fileError(-1, "I can't find the $generatorName Generator!") if(!can_load(modules => {
+				$GeneratorPackage."::Generator" => undef
+			}));
+}
+
+1;

+ 55 - 0
CycriptLoader/theos/bin/lib/Logos/Generator/Base/Class.pm

@@ -0,0 +1,55 @@
+package Logos::Generator::Base::Class;
+use Logos::Generator;
+use strict;
+
+sub _initExpression {
+	my $self = shift;
+	my $class = shift;
+	return $class->expression if $class->expression;
+	return "objc_getClass(\"".$class->name."\")";
+}
+
+sub _metaInitExpression {
+	my $self = shift;
+	my $class = shift;
+	return $class->metaexpression if $class->metaexpression;
+	return "object_getClass(".$self->variable($class).")";
+}
+
+
+sub variable {
+	my $self = shift;
+	my $class = shift;
+	return Logos::sigil("class").$class->group->name."\$".$class->name;
+}
+
+sub metaVariable {
+	my $self = shift;
+	my $class = shift;
+	return Logos::sigil("metaclass").$class->group->name."\$".$class->name;
+}
+
+sub declarations {
+	my $self = shift;
+	my $class = shift;
+	my $return = "";
+	for(@{$class->methods}) {
+		$return .= Logos::Generator::for($_)->declarations;
+	}
+	return $return;
+}
+
+sub initializers {
+	my $self = shift;
+	my $class = shift;
+	my $return = "";
+	for(@{$class->methods}) {
+		$return .= Logos::Generator::for($_)->initializers;
+	}
+	for(@{$class->properties}) {
+		$return .= Logos::Generator::for($_)->initializers;
+	}
+	return $return;
+}
+
+1;

+ 177 - 0
CycriptLoader/theos/bin/lib/Logos/Generator/Base/Function.pm

@@ -0,0 +1,177 @@
+package Logos::Generator::Base::Function;
+use strict;
+use Logos::Generator;
+use Logos::Util;
+
+sub originalFunctionName {
+	my $self = shift;
+	my $function = shift;
+	return Logos::sigil("orig").$function->group->name."\$".$function->name;
+}
+
+sub newFunctionName {
+	my $self = shift;
+	my $function = shift;
+	return Logos::sigil("function").$function->group->name."\$".$function->name;
+}
+
+sub originalFunctionCall {
+	my $self = shift;
+	my $function = shift;
+	my $args = shift;
+
+	my $return = $self->originalFunctionName($function)."(";
+	if (!$args) {
+		$args = [];
+		for(@{$function->args}) {
+			push(@$args, $self->getArgumentName($_));
+		}
+		$return .= join(", ", @$args);
+	} else {
+		$return .= $args;
+	}
+	$return .= ")";
+
+	return $return;
+}
+
+sub declaration {
+	my $self = shift;
+	my $function = shift;
+	my $return = "";
+	$return .= "_disused static ".$function->retval." (*".$self->originalFunctionName($function).")(".join(", ", @{$function->args})."); ";
+	$return .= "static ".$function->retval." ".$self->newFunctionName($function)."(".join(", ", @{$function->args}).")";
+	return $return;
+}
+
+sub initializers {
+	::fileError(-1, "Base::Function does not implement initializers");
+}
+
+##########
+# extras #
+##########
+
+sub getArgumentName {
+	my $self = shift;
+	my $arg = shift;
+
+	# Split the argument string by spaces
+	my $argArray = $self->notSoSmartSplit($arg, " ");
+	# Try to get the name of the last element of the array if it is a function pointer
+	my $return = $self->escapeFunctionPointer(@$argArray[-1]);
+	# Separate the name from trailing vector size
+	$return =~ s/\[/ \[/g;
+	# Trimm spaces or asterisks from the start
+	while (substr($return, 0, 1) eq " " || substr($return, 0, 1) eq "*") {
+		$return = substr($return, 1, length($return));
+	}
+	# Split the resulting string by spaces
+	$argArray = $self->notSoSmartSplit($return, " ");
+	# Get the first element
+	my $return = @$argArray[0];
+
+	return $return;
+}
+
+sub escapeFunctionPointer {
+	my $self = shift;
+	my $arg = shift;
+	if($arg !~ /\(\s*[*^]/) {
+		return $arg;
+	}
+	my $substring = $arg;
+	my ($opening, $closing) = matchedParenthesisSet($substring, 0);
+	my $offset = 0;
+	while(1) {
+		# We want to put the parameter name right before the closing ) in the deepest nested set if we found a (^ or (*.
+		$substring = substr($substring, $opening, $closing - $opening - 1);
+		$offset += $opening;
+		my ($newopening, $newclosing) = matchedParenthesisSet($substring, 0);
+		last if !defined $newopening;
+		$opening = $newopening;
+		$closing = $newclosing;
+	}
+	return substr($arg, $offset, $closing-$opening-1);
+}
+
+#for a lack of Logos::Util::matchedDelimiterSet()
+sub notSoSmartSplit {
+	my $self = shift;
+	my $argumentString = shift;
+	my $delimiter = shift;
+
+	# Default to commas
+	if (!$delimiter) {
+		$delimiter = ",";
+	}
+	$argumentString .= $delimiter; #uber hax
+
+# curved  brackets or parens ()
+	my $parensLevel = 0;
+# squared brackets or crotchets []
+	my $crotchetsLevel = 0;
+# curly   brackets or braces {}
+	my $bracesLevel = 0;
+# angled  brackets or chevrons <>
+	my $chevronsLevel = 0;
+
+	my $token = "";
+	my $pc = "";
+
+	my $args = [];
+
+	foreach my $c (split //, $argumentString) {
+		if ($c eq $delimiter) {
+			# If at root level, end token, push to array and start again
+			if ($parensLevel == 0 && $crotchetsLevel == 0 && $bracesLevel == 0 && $chevronsLevel == 0) {
+				push(@$args, $token);
+				$pc = $c;
+				$token = "";
+				next;
+			}
+		}
+
+		if ($c eq "(") {
+			$parensLevel++;
+		}
+		if ($c eq ")") {
+			$parensLevel--;
+		}
+
+		if ($c eq "[") {
+			$crotchetsLevel++;
+		}
+		if ($c eq "]") {
+			$crotchetsLevel--;
+		}
+
+		if ($c eq "{") {
+			$bracesLevel++;
+		}
+		if ($c eq "}") {
+			$bracesLevel--;
+		}
+
+		if ($c eq "<") {
+			$chevronsLevel++;
+		}
+		if ($c eq ">") {
+			$chevronsLevel--;
+		}
+
+		#skip redundant empty spaces
+		if (($pc eq $delimiter && $c eq " ") || ($pc eq " " && $c eq " ")) {
+			next;
+		}
+
+		# Concatenate char to token
+		$token .= $c;
+		#save previous char
+		$pc = $c;
+	} # foreach
+
+	return $args;
+}
+
+1;

+ 49 - 0
CycriptLoader/theos/bin/lib/Logos/Generator/Base/Generator.pm

@@ -0,0 +1,49 @@
+package Logos::Generator::Base::Generator;
+use strict;
+
+sub findPreamble {
+	my $self = shift;
+	my $aref = shift;
+	my @matches = grep(/\s*#\s*(import|include)\s*[<"]logos\/logos\.h[">]/, @$aref);
+	return @matches > 0;
+}
+
+sub preamble {
+	return <<END;
+#if defined(__clang__)
+#if __has_feature(objc_arc)
+#define _LOGOS_SELF_TYPE_NORMAL __unsafe_unretained
+#define _LOGOS_SELF_TYPE_INIT __attribute__((ns_consumed))
+#define _LOGOS_SELF_CONST const
+#define _LOGOS_RETURN_RETAINED __attribute__((ns_returns_retained))
+#else
+#define _LOGOS_SELF_TYPE_NORMAL
+#define _LOGOS_SELF_TYPE_INIT
+#define _LOGOS_SELF_CONST
+#define _LOGOS_RETURN_RETAINED
+#endif
+#else
+#define _LOGOS_SELF_TYPE_NORMAL
+#define _LOGOS_SELF_TYPE_INIT
+#define _LOGOS_SELF_CONST
+#define _LOGOS_RETURN_RETAINED
+#endif
+END
+}
+
+sub generateClassList {
+	my $self = shift;
+	my $return = "";
+	map $return .= "\@class $_; ", @_;
+	return $return;
+}
+
+sub classReferenceWithScope {
+	my $self = shift;
+	my $classname = shift;
+	my $scope = shift;
+	my $prefix = Logos::sigil($scope eq "+" ? "static_metaclass_lookup" : "static_class_lookup");
+	return $prefix.$classname."()";
+}
+
+1;

+ 28 - 0
CycriptLoader/theos/bin/lib/Logos/Generator/Base/Group.pm

@@ -0,0 +1,28 @@
+package Logos::Generator::Base::Group;
+use strict;
+
+sub declarations {
+	my $self = shift;
+	my $group = shift;
+	my $return = "";
+	foreach(@{$group->classes}) {
+		$return .= Logos::Generator::for($_)->declarations if $_->initRequired;
+	}
+	return $return;
+}
+
+sub initializers {
+	my $self = shift;
+	my $group = shift;
+	my $return = "{";
+	foreach(@{$group->classes}) {
+		$return .= Logos::Generator::for($_)->initializers if $_->initRequired;
+	}
+	foreach(@{$group->functions}) {
+		$return .= Logos::Generator::for($_)->initializers if $_->initRequired;
+	}
+	$return .= "}";
+	return $return;
+}
+
+1;

+ 119 - 0
CycriptLoader/theos/bin/lib/Logos/Generator/Base/Method.pm

@@ -0,0 +1,119 @@
+package Logos::Generator::Base::Method;
+use strict;
+use Logos::Util;
+
+sub originalFunctionName {
+	my $self = shift;
+	my $method = shift;
+	return Logos::sigil(($method->scope eq "+" ? "meta_" : "")."orig").$method->groupIdentifier."\$".$method->class->name."\$".$method->_new_selector;
+}
+
+sub newFunctionName {
+	my $self = shift;
+	my $method = shift;
+	return Logos::sigil(($method->scope eq "+" ? "meta_" : "")."method").$method->groupIdentifier."\$".$method->class->name."\$".$method->_new_selector;
+}
+
+sub definition {
+	::fileError(-1, "generator does not implement Method::definition");
+}
+
+sub originalCall {
+	::fileError(-1, "generator does not implement Method::originalCall");
+}
+
+sub selectorRef {
+	my $self = shift;
+	my $selector = shift;
+	if ($selector eq "dealloc") {
+		return "sel_registerName(\"".$selector."\")";
+	}
+	return "\@selector(".$selector.")";
+}
+
+sub selfTypeForMethod {
+	my $self = shift;
+	my $method = shift;
+	if($method->scope eq "+") {
+		return "_LOGOS_SELF_TYPE_NORMAL Class _LOGOS_SELF_CONST";
+	}
+	if($method->methodFamily eq "init") {
+		return "_LOGOS_SELF_TYPE_INIT ".$method->class->type;
+	}
+	return "_LOGOS_SELF_TYPE_NORMAL ".$method->class->type." _LOGOS_SELF_CONST";
+}
+
+sub returnTypeForMethod {
+	my $self = shift;
+	my $method = shift;
+ 	if($method->methodFamily ne "") {
+		return $method->class->type;
+	}
+	my $result = $method->return;
+	if ($result eq "instancetype") {
+		return $method->class->type;
+	}
+	return $result;
+}
+
+sub functionAttributesForMethod {
+	my $self = shift;
+	my $method = shift;
+	if($method->methodFamily ne "") {
+		return " _LOGOS_RETURN_RETAINED";
+	}
+	return "";
+}
+
+sub buildLogCall {
+	my $self = shift;
+	my $method = shift;
+	my $args = shift;
+	# Log preamble
+	my $build = "HBLogDebug(\@\"".$method->scope."[<".$method->class->name.": %p>";
+	my $argnamelist = "";
+	if($method->numArgs > 0) {
+		# For each argument, add its keyword and a format char to the log string.
+		map $build .= " ".$method->selectorParts->[$_].":".Logos::Method::formatCharForArgType($method->argtypes->[$_]), (0..$method->numArgs - 1);
+		# This builds a list of args by making sure the format char isn't -- (or, what we're using for non-operational types)
+		# Map (in list context) "format char == -- ? nothing : arg name" over the indices of the arg list.
+		my @newarglist = map(Logos::Method::printArgForArgType($method->argtypes->[$_], $method->argnames->[$_]), (0..$method->numArgs - 1));
+		my @existingargs = grep(defined($_), @newarglist);
+		if(scalar(@existingargs) > 0) {
+			$argnamelist = ", ".join(", ", grep(defined($_), @existingargs));
+		}
+	} else {
+		# Space and then the only keyword in the selector.
+		$build .= " ".$method->selector;
+	}
+
+	my @extraFormatSpecifiers;
+	my @extraArguments;
+	for(Logos::Util::smartSplit(qr/\s*,\s*/, $args)) {
+		my ($popen, $pclose) = matchedParenthesisSet($_);
+		my $type = "id";
+		if(defined $popen) {
+			$type = substr($_, $popen, $pclose-$popen-1);
+		}
+		push(@extraFormatSpecifiers, Logos::Method::formatCharForArgType($type));
+		my $n = Logos::Method::printArgForArgType($type, "($_)");
+		push(@extraArguments, $n) if $n;
+	}
+
+	# Log postamble
+	$build .= "]";
+	$build .= ": ".join(", ", @extraFormatSpecifiers) if @extraFormatSpecifiers > 0;
+	$build .= "\", self".$argnamelist;
+	$build .= ", ".join(", ", @extraArguments) if @extraArguments > 0;
+	$build .= ")";
+}
+
+sub declarations {
+	::fileError(-1, "generator does not implement Method::declarations");
+}
+
+sub initializers {
+	::fileError(-1, "generator does not implement Method::initializers");
+}
+
+1;

+ 271 - 0
CycriptLoader/theos/bin/lib/Logos/Generator/Base/Property.pm

@@ -0,0 +1,271 @@
+package Logos::Generator::Base::Property;
+use strict;
+use Logos::Util;
+
+sub key {
+	my $self = shift;
+	my $property = shift;
+
+	my $build = "_logos_property_key\$" . $property->group . "\$" . $property->class . "\$" . $property->name;
+
+	return $build;
+}
+
+sub getter {
+	my $self = shift;
+	my $property = shift;
+	my $name = shift;
+	my $key = shift;
+	my $type = $property->type;
+
+	$type =~ s/\s+$//;
+
+	if(!$name){
+		# Use property name if no getter specified
+		$name = $property->name;
+	}
+
+	# Build function start
+	my $build = "static " . $type . " _logos_method\$" . $property->group . "\$" . $property->class . "\$" . $name . "\$" . "(" . $property->class . "* self, SEL _cmd){";
+
+	# Build function body
+
+	$build .= " return ";
+
+
+	if ($type =~ /^(BOOL|(unsigned )?char|double|float|CGFloat|(unsigned )?int|NSInteger|unsigned|NSUInteger|(unsigned )?long (long)?|(unsigned )?short|NSRange|CGPoint|CGVector|CGSize|CGRect|CGAffineTransform|UIEdgeInsets|UIOffset|CATransform3D|CMTime(Range|Mapping)?|MKCoordinate(Span)?|SCNVector[34]|SCNMatrix4)$/){
+		$build .= "[";
+	}
+
+	$build .= "objc_getAssociatedObject(self, &" . $key . ")";
+
+	if ($type eq "BOOL"){
+		$build .= " boolValue]";
+	} elsif ($type eq "char"){
+		$build .= " charValue]";
+	} elsif ($type eq "unsigned char"){
+		$build .= " unsignedCharValue]";
+	} elsif ($type eq "double"){
+		$build .= " doubleValue]";
+	} elsif ($type =~ /^(float|CGFloat)$/){
+		$build .= " floatValue]";
+	} elsif ($type eq "int"){
+		$build .= " intValue]";
+	} elsif ($type eq "NSInteger"){
+		$build .= " integerValue]";
+	} elsif ($type =~ /^unsigned( int)?$/){
+		$build .= " unsignedIntValue]";
+	} elsif ($type eq "NSUInteger"){
+		$build .= " unsignedIntegerValue]";
+	} elsif ($type eq "long"){
+		$build .= " longValue]";
+	} elsif ($type eq "unsigned long"){
+		$build .= " unsignedLongValue]";
+	} elsif ($type eq "long long"){
+		$build .= " longLongValue]";
+	} elsif ($type eq "unsigned long long"){
+		$build .= " unsignedLongLongValue]";
+	} elsif ($type eq "short"){
+		$build .= " shortValue]";
+	} elsif ($type eq "unsigned short"){
+		$build .= " unsignedShortValue]";
+	} elsif ($type =~ /^(NSRange|CGPoint|CGVector|CGSize|CGRect|CGAffineTransform|UIEdgeInsets|UIOffset|CATransform3D|CMTime(Range|Mapping)?|MKCoordinate(Span)?|SCNVector[34]|SCNMatrix4)$/){
+		$build .= " " . $type . "Value]";
+	}
+
+	$build .= "; }";
+
+	return $build;
+}
+
+sub setter {
+	my $self = shift;
+	my $property = shift;
+	my $name = shift;
+	my $policy = shift;
+	my $key = shift;
+	my $type = $property->type;
+
+	$type =~ s/\s+$//;
+
+	if(!$name){
+		# Capitalize first letter
+		$_ = $property->name;
+		$_ =~ s/^([a-z])/\u$1/;
+
+		$name = "set" . $_;
+	}
+
+	# Remove semicolon
+	$name =~ s/://;
+
+	my $build = "static void _logos_method\$" . $property->group . "\$" . $property->class . "\$" . $name . "\$" . "(" . $property->class . "* self, SEL _cmd, " . $type . " arg){ ";
+
+
+	$build .= "objc_setAssociatedObject(self, &" . $key . ", ";
+
+	my $hasOpening = 1;
+
+	if ($type eq "BOOL"){
+		$build .= "[NSNumber numberWithBool:";
+	} elsif ($type eq "char"){
+		$build .= "[NSNumber numberWithChar:";
+	} elsif ($type eq "unsigned char"){
+		$build .= "[NSNumber numberWithUnsignedChar:";
+	} elsif ($type eq "double"){
+		$build .= "[NSNumber numberWithDouble:";
+	} elsif ($type =~ /^(float|CGFloat)$/){
+		$build .= "[NSNumber numberWithFloat:";
+	} elsif ($type eq "int"){
+		$build .= "[NSNumber numberWithInt:";
+	} elsif ($type eq "NSInteger"){
+		$build .= "[NSNumber numberWithInteger:";
+	} elsif ($type =~ /^unsigned( int)?$/){
+		$build .= "[NSNumber numberWithUnsignedInt:";
+	} elsif ($type eq "NSUInteger"){
+		$build .= "[NSNumber numberWithUnsignedInteger:";
+	} elsif ($type eq "long"){
+		$build .= "[NSNumber numberWithLong:";
+	} elsif ($type eq "unsigned long"){
+		$build .= "[NSNumber numberWithUnsignedLong:";
+	} elsif ($type eq "long long"){
+		$build .= "[NSNumber numberWithLongLong:";
+	} elsif ($type eq "unsigned long long"){
+		$build .= "[NSNumber numberWithUnsignedLongLong:";
+	} elsif ($type eq "short"){
+		$build .= "[NSNumber numberWithShort:";
+	} elsif ($type eq "unsigned short"){
+		$build .= "[NSNumber numberWithUnsignedShort:";
+	} elsif ($type =~ /^(NSRange|CGPoint|CGVector|CGSize|CGRect|CGAffineTransform|UIEdgeInsets|UIOffset|CATransform3D|CMTime(Range|Mapping)?|MKCoordinate(Span)?|SCNVector[34]|SCNMatrix4)$/){
+		$build .= "[NSValue valueWith " . $type . ":";
+	} else {
+		$hasOpening = 0;
+	}
+
+	$build .= "arg";
+
+	if ($hasOpening){
+		$build .= "]";
+	}
+
+	$build .= ", ".$policy.")";
+
+	$build .= "; }";
+
+	return $build;
+}
+
+sub getters_setters {
+	my $self = shift;
+	my $property = shift;
+
+	my ($assign, $retain, $nonatomic, $copy, $getter, $setter);
+
+
+	for(my $i = 0; $i < $property->numattr; $i++){
+
+		my $attr = $property->attributes->[$i];
+
+		if($attr =~ /assign/){
+			$assign = 1;
+		}elsif($attr =~ /retain/){
+			$retain = 1;
+		}elsif($attr =~ /nonatomic/){
+			$nonatomic = 1;
+		}elsif($attr =~ /copy/){
+			$copy = 1;
+		}elsif($attr =~ /getter=(\w+)/){
+			$getter = $1;
+		}elsif($attr =~ /setter=(\w+:)/){
+			$setter = $1;
+		}
+	}
+
+	my $policy = "OBJC_ASSOCIATION_";
+
+	if($retain){
+		$policy .= "RETAIN";
+	}elsif($copy){
+		$policy .= "COPY";
+	}elsif($assign){
+		$policy .= "ASSIGN";
+	}else{
+		print "error: no 'assign', 'retain', or 'copy' attribu...wait, how did you manage to get here?\n";
+	}
+
+	if($nonatomic){
+		# The 'assign' attribute appears to be nonatomic by default.
+		if(!$assign){
+			$policy .= "_NONATOMIC";
+		}
+	}
+
+	$property->associationPolicy($policy);
+
+	my $build;
+
+	my $key = $self->key($property);
+	my $getter_func = $self->getter($property, $getter, $key);
+	my $setter_func = $self->setter($property, $setter, $policy, $key);
+
+	$build .= $build . "static char " . $key . ";";
+	$build .= $getter_func;
+	$build .= $setter_func;
+
+
+	return $build;
+}
+
+sub initializers {
+	my $self = shift;
+	my $property = shift;
+
+	my ($getter, $setter);
+
+	for(my $i = 0; $i < $property->numattr; $i++){ # This could be more efficient
+		my $attr = $property->attributes->[$i];
+
+		if($attr =~ /getter=(\w+)/){
+			$getter = $1;
+		}elsif($attr =~ /setter=(\w+:)/){
+			$setter = $1;
+			$setter =~ s/://;
+		}
+	}
+
+	if(!$setter){
+		# Capitalize first letter
+		$_ = $property->name;
+		$_ =~ s/^([a-z])/\u$1/;
+
+		$setter = "set" . $_;
+	}
+
+	if(!$getter){
+		# Use property name if no getter specified
+		$getter = $property->name;
+	}
+
+
+	my $build = "";
+
+	$build .= "{ ";
+
+	# Getter
+	$build .= "class_addMethod(";
+
+	$build .= "_logos_class\$" . $property->group . "\$" . $property->class . ", ";
+	$build .= "\@selector(" . $getter . "), " . "(IMP)&" . "_logos_method\$" . $property->group . "\$" . $property->class . "\$" . $getter . "\$, [[NSString stringWithFormat:\@\"%s\@:\", \@encode(".$property->type.")] UTF8String]);";
+
+	# Setter
+	$build .= "class_addMethod(";
+	$build .= "_logos_class\$" . $property->group . "\$" . $property->class . ", ";
+
+	$build .= "\@selector(" . $setter . ":), " . "(IMP)&" . "_logos_method\$" . $property->group . "\$" . $property->class . "\$" . $setter . "\$, [[NSString stringWithFormat:\@\"v\@:%s\", \@encode(".$property->type.")] UTF8String]);";
+
+	$build .= "} ";
+
+	return $build;
+}
+
+1;

+ 34 - 0
CycriptLoader/theos/bin/lib/Logos/Generator/Base/StaticClassGroup.pm

@@ -0,0 +1,34 @@
+package Logos::Generator::Base::StaticClassGroup;
+use strict;
+
+sub _methodForClassWithScope {
+	my $self = shift;
+	my $class = shift;
+	my $scope = shift;
+	my $return = "";
+	my $methodname = Logos::sigil($scope eq "+" ? "static_metaclass_lookup" : "static_class_lookup").$class;
+	my $lookupMethod = $scope eq "+" ? "objc_getMetaClass" : "objc_getClass";
+
+	# This is a dirty assumption - we believe that we will always be using a compiler that defines __GNUC__ and respects GNU C attributes.
+	return "static __inline__ __attribute__((always_inline)) __attribute__((unused)) Class ".$methodname."(void) { static Class _klass; if(!_klass) { _klass = ".$lookupMethod."(\"".$class."\"); } return _klass; }";
+}
+
+sub declarations {
+	my $self = shift;
+	my $group = shift;
+	my $return = "";
+	return "" if scalar(keys %{$group->usedMetaClasses}) + scalar(keys %{$group->usedClasses}) + scalar(keys %{$group->declaredOnlyClasses}) == 0;
+	foreach(keys %{$group->usedMetaClasses}) {
+		$return .= $self->_methodForClassWithScope($_, "+");
+	}
+	foreach(keys %{$group->usedClasses}) {
+		$return .= $self->_methodForClassWithScope($_, "-");
+	}
+	return $return;
+}
+
+sub initializers {
+	return "";
+}
+
+1;

+ 12 - 0
CycriptLoader/theos/bin/lib/Logos/Generator/Base/Subclass.pm

@@ -0,0 +1,12 @@
+package Logos::Generator::Base::Subclass;
+use strict;
+
+sub declarations {
+	::fileError(-1, "generator does not implement Subclass::declarations");
+}
+
+sub initializers {
+	::fileError(-1, "generator does not implement Subclass::initializers");
+}
+
+1;

+ 19 - 0
CycriptLoader/theos/bin/lib/Logos/Generator/MobileSubstrate/Class.pm

@@ -0,0 +1,19 @@
+package Logos::Generator::MobileSubstrate::Class;
+use strict;
+use parent qw(Logos::Generator::Base::Class);
+
+sub initializers {
+	my $self = shift;
+	my $class = shift;
+	my $return = "";
+	if($class->required || $class->overridden || $class->hasinstancehooks || $class->hasmetahooks) {
+		$return .= "Class ".$self->variable($class)." = ".$self->_initExpression($class)."; ";
+	}
+	if($class->hasmetahooks) {
+		$return .= "Class ".$self->metaVariable($class)." = ".$self->_metaInitExpression($class)."; ";
+	}
+	$return .= $self->SUPER::initializers($class);
+	return $return;
+}
+
+1;

+ 18 - 0
CycriptLoader/theos/bin/lib/Logos/Generator/MobileSubstrate/Function.pm

@@ -0,0 +1,18 @@
+package Logos::Generator::MobileSubstrate::Function;
+use strict;
+use parent qw(Logos::Generator::Base::Function);
+
+sub initializers {
+	my $self = shift;
+	my $function = shift;
+
+	my $return = "";
+	$return .= " MSHookFunction((void *)".$function->name;
+	$return .= ", (void *)&".$self->newFunctionName($function);
+	$return .= ", (void **)&".$self->originalFunctionName($function);
+	$return .= ");";
+
+	return $return;
+}
+
+1;

+ 22 - 0
CycriptLoader/theos/bin/lib/Logos/Generator/MobileSubstrate/Generator.pm

@@ -0,0 +1,22 @@
+package Logos::Generator::MobileSubstrate::Generator;
+use strict;
+use parent qw(Logos::Generator::Base::Generator);
+
+sub findPreamble {
+	my $self = shift;
+	my $aref = shift;
+	my @matches = grep(/\s*#\s*(import|include)\s*[<"]substrate\.h[">]/, @$aref);
+	return $self->SUPER::findPreamble($aref) && @matches > 0;
+}
+
+sub preamble {
+	my $self = shift;
+	my $skipIncludes = shift;
+	if ($skipIncludes) {
+		return $self->SUPER::preamble();
+	} else {
+		return join("\n", ($self->SUPER::preamble(), "#include <substrate.h>"));
+	}
+}
+
+1;

+ 122 - 0
CycriptLoader/theos/bin/lib/Logos/Generator/MobileSubstrate/Method.pm

@@ -0,0 +1,122 @@
+package Logos::Generator::MobileSubstrate::Method;
+use strict;
+use parent qw(Logos::Generator::Base::Method);
+
+sub _originalMethodPointerDeclaration {
+	my $self = shift;
+	my $method = shift;
+	if(!$method->isNew) {
+		my $build = "static ";
+		my $classargtype = $self->selfTypeForMethod($method);
+		my $name = "(*".$self->originalFunctionName($method).")(".$classargtype.", SEL";
+		my $argtypelist = join(", ", @{$method->argtypes});
+		$name .= ", ".$argtypelist if $argtypelist;
+
+		$name .= ")";
+		$build .= Logos::Method::declarationForTypeWithName($self->returnTypeForMethod($method), $name);
+		$build .= $self->functionAttributesForMethod($method);
+		return $build;
+	}
+	return undef;
+}
+
+sub _methodPrototype {
+	my $self = shift;
+	my $method = shift;
+	my $includeArgNames = 0 || shift;
+	my $build = "static ";
+	my $classargtype = $self->selfTypeForMethod($method);
+	my $arglist = "";
+	if($includeArgNames == 1) {
+		map $arglist .= ", ".Logos::Method::declarationForTypeWithName($method->argtypes->[$_], $method->argnames->[$_]), (0..$method->numArgs - 1);
+	} else {
+		my $typelist = join(", ", @{$method->argtypes});
+		$arglist = ", ".$typelist if $typelist;
+	}
+
+	my $name = $self->newFunctionName($method)."(".$classargtype.($includeArgNames?" self":"").", SEL".($includeArgNames?" _cmd":"").$arglist.")";
+	$build .= Logos::Method::declarationForTypeWithName($self->returnTypeForMethod($method), $name);
+	$build .= $self->functionAttributesForMethod($method);
+	return $build;
+}
+
+sub definition {
+	my $self = shift;
+	my $method = shift;
+	my $build = "";
+	$build .= $self->_methodPrototype($method, 1);
+	return $build;
+}
+
+sub originalCall {
+	my $self = shift;
+	my $method = shift;
+	my $customargs = shift;
+	return "" if $method->isNew;
+
+	my $build = $self->originalFunctionName($method)."(self, _cmd";
+	if(defined $customargs && $customargs ne "") {
+		$build .= ", ".$customargs;
+	} elsif($method->numArgs > 0) {
+		$build .= ", ".join(", ",@{$method->argnames});
+	}
+	$build .= ")";
+	return $build;
+}
+
+sub declarations {
+	my $self = shift;
+	my $method = shift;
+	my $build = "";
+	my $orig = $self->_originalMethodPointerDeclaration($method);
+	$build .= $orig."; " if $orig;
+	$build .= $self->_methodPrototype($method)."; ";
+	return $build;
+}
+
+sub initializers {
+	my $self = shift;
+	my $method = shift;
+	my $cgen = Logos::Generator::for($method->class);
+	my $classvar = ($method->scope eq "+" ? $cgen->metaVariable : $cgen->variable);
+	if(!$method->isNew) {
+		my $r = "";
+		$r .= "if (".$classvar.") {";
+		$r .=   "if (class_getInstanceMethod(".$classvar.", ".$self->selectorRef($method->selector).")) {";
+		$r .=     "MSHookMessageEx(".$classvar.", ".$self->selectorRef($method->selector).", (IMP)&".$self->newFunctionName($method).", (IMP*)&".$self->originalFunctionName($method).");";
+		$r .=   "} else {";
+		$r .=     "HBLogError(@\"logos: message not found [%s %s]\", \"".$method->class->name."\", \"".$method->selector."\");";
+		$r .=   "}";
+		$r .= "} else {";
+		$r .=   "HBLogError(@\"logos: nil class %s\", \"".$method->class->name."\");";
+		$r .= "}";
+	} else {
+		my $r = "";
+		$r .= "{ ";
+		if(!$method->type) {
+			$r .= "char _typeEncoding[1024]; unsigned int i = 0; ";
+			for ($method->return, "id", "SEL", @{$method->argtypes}) {
+				my $typeEncoding = Logos::Method::typeEncodingForArgType($_);
+				if(defined $typeEncoding) {
+					my @typeEncodingBits = split(//, $typeEncoding);
+					my $i = 0;
+					for my $char (@typeEncodingBits) {
+						$r .= "_typeEncoding[i".($i > 0 ? " + $i" : "")."] = '$char'; ";
+						$i++;
+					}
+					$r .= "i += ".(scalar @typeEncodingBits)."; ";
+				} else {
+					$r .= "memcpy(_typeEncoding + i, \@encode($_), strlen(\@encode($_))); i += strlen(\@encode($_)); ";
+				}
+			}
+			$r .= "_typeEncoding[i] = '\\0'; ";
+		} else {
+			$r .= "const char *_typeEncoding = \"".$method->type."\"; ";
+		}
+		$r .= "class_addMethod(".$classvar.", ".$self->selectorRef($method->selector).", (IMP)&".$self->newFunctionName($method).", _typeEncoding); ";
+		$r .= "}";
+		return $r;
+	}
+}
+
+1;

+ 32 - 0
CycriptLoader/theos/bin/lib/Logos/Generator/MobileSubstrate/Subclass.pm

@@ -0,0 +1,32 @@
+package Logos::Generator::MobileSubstrate::Subclass;
+use strict;
+use parent qw(Logos::Generator::MobileSubstrate::Class);
+
+# declarations is inherited from Class.
+
+sub _initExpression {
+	my $self = shift;
+	my $class = shift;
+	my $cgen = Logos::Generator::for($class->superclass);
+	return "objc_allocateClassPair(".$cgen->variable.", \"".$class->name."\", 0); objc_registerClassPair(".$self->variable($class).")";
+}
+
+sub initializers {
+	my $self = shift;
+	my $class = shift;
+	my $return = "";
+	$return .= "{ ";
+	$return .= $self->SUPER::initializers($class)." ";
+	# <ivars>
+	foreach(@{$class->ivars}) {
+		$return .= Logos::Generator::for($_)->initializers;
+	}
+	# </ivars>
+	foreach(keys %{$class->protocols}) {
+		$return .= "class_addProtocol(".$self->variable($class).", objc_getProtocol(\"$_\")); ";
+	}
+	$return .= "}";
+	return $return;
+}
+
+1;

+ 54 - 0
CycriptLoader/theos/bin/lib/Logos/Generator/Thunk.pm

@@ -0,0 +1,54 @@
+package Logos::Generator::Thunk;
+use strict;
+
+our $AUTOLOAD;
+
+my %subrefCache;
+
+sub AUTOLOAD {
+	my $self = shift;
+	my $method = $AUTOLOAD;
+	return if $method eq "DESTROY";
+
+	$method =~ s/.*:://;
+	my $fullyQualified = $self->{PACKAGE}."::".$method;
+	my $subref = $subrefCache{$fullyQualified};
+
+	$subref = $self->can($method) if !$subref;
+
+	unshift @_, $self->{OBJECT} if $self->{OBJECT};
+	goto &$subref;
+}
+
+sub can {
+	my $self = shift;
+	my $method = shift;
+	my $subref = $self->SUPER::can($method);
+	return $subref if $subref;
+
+	$method =~ s/.*:://;
+	my $fullyQualified = $self->{PACKAGE}."::".$method;
+	return $subrefCache{$fullyQualified} if $subrefCache{$fullyQualified};
+
+	$subref = sub {unshift @_, $self->{PACKAGE}; goto &{$self->{PACKAGE}->can($method)}};
+	$subrefCache{$fullyQualified} = $subref;
+
+	return $subref;
+}
+
+sub DESTROY {
+	my $self = shift;
+	$self->SUPER::destroy();
+}
+
+sub for {
+	my $proto = shift;
+	my $class = ref($proto) || $proto;
+	my $self = {};
+	$self->{PACKAGE} = shift;
+	$self->{OBJECT} = shift;
+	bless($self, $class);
+	return $self;
+}
+
+1;

+ 51 - 0
CycriptLoader/theos/bin/lib/Logos/Generator/internal/Class.pm

@@ -0,0 +1,51 @@
+package Logos::Generator::internal::Class;
+use strict;
+use parent qw(Logos::Generator::Base::Class);
+
+sub superVariable {
+	my $self = shift;
+	my $class = shift;
+	return Logos::sigil("superclass").$class->group->name."\$".$class->name;
+}
+
+sub superMetaVariable {
+	my $self = shift;
+	my $class = shift;
+	return Logos::sigil("supermetaclass").$class->group->name."\$".$class->name;
+}
+
+sub declarations {
+	my $self = shift;
+	my $class = shift;
+	my $return = "";
+	if($class->hasinstancehooks) {
+		$return .= "static Class ".$self->superVariable($class)."; ";
+	}
+	if($class->hasmetahooks) {
+		$return .= "static Class ".$self->superMetaVariable($class)."; ";
+	}
+	$return .= $self->SUPER::declarations($class);
+	return $return;
+}
+
+sub initializers {
+	my $self = shift;
+	my $class = shift;
+	my $return = "";
+	if($class->required || $class->overridden || $class->hasinstancehooks || $class->hasmetahooks) {
+		$return .= "Class ".$self->variable($class)." = ".$self->_initExpression($class)."; ";
+	}
+	if($class->hasmetahooks) {
+		$return .= "Class ".$self->metaVariable($class)." = ".$self->_metaInitExpression($class)."; ";
+	}
+	if ($class->hasinstancehooks) {
+		$return .= $self->superVariable($class)." = class_getSuperclass(".$self->variable($class)."); ";
+	}
+	if ($class->hasmetahooks) {
+		$return .= $self->superMetaVariable($class)." = class_getSuperclass(".$self->metaVariable($class)."); ";
+	}
+	$return .= $self->SUPER::initializers($class);
+	return $return;
+}
+
+1;

+ 14 - 0
CycriptLoader/theos/bin/lib/Logos/Generator/internal/Function.pm

@@ -0,0 +1,14 @@
+package Logos::Generator::internal::Function;
+use strict;
+use parent qw(Logos::Generator::Base::Function);
+
+sub initializers {
+	my $self = shift;
+	my $function = shift;
+
+	my $return = " /* internal::Function does not implement initializers */;";
+
+	return $return;
+}
+
+1;

+ 22 - 0
CycriptLoader/theos/bin/lib/Logos/Generator/internal/Generator.pm

@@ -0,0 +1,22 @@
+package Logos::Generator::internal::Generator;
+use strict;
+use parent qw(Logos::Generator::Base::Generator);
+
+sub findPreamble {
+	my $self = shift;
+	my $aref = shift;
+	my @matches = grep(/\s*#\s*(import|include)\s*[<"]objc\/message\.h[">]/, @$aref);
+	return $self->SUPER::findPreamble($aref) && @matches > 0;
+}
+
+sub preamble {
+	my $self = shift;
+	my $skipIncludes = shift;
+	if ($skipIncludes) {
+		return $self->SUPER::preamble();
+	} else {
+		return join("\n", ($self->SUPER::preamble(), "#include <objc/message.h>"));
+	}
+}
+
+1;

+ 141 - 0
CycriptLoader/theos/bin/lib/Logos/Generator/internal/Method.pm

@@ -0,0 +1,141 @@
+package Logos::Generator::internal::Method;
+use strict;
+use parent qw(Logos::Generator::Base::Method);
+
+sub superFunctionName {
+	my $self = shift;
+	my $method = shift;
+	return Logos::sigil(($method->scope eq "+" ? "meta_" : "")."super").$method->groupIdentifier."\$".$method->class->name."\$".$method->_new_selector;
+}
+
+sub originalCallParams {
+	my $self = shift;
+	my $method = shift;
+	my $customargs = shift;
+	return "" if $method->isNew;
+
+	my $build = "(self, _cmd";
+	if(defined $customargs && $customargs ne "") {
+		$build .= ", ".$customargs;
+	} elsif($method->numArgs > 0) {
+		$build .= ", ".join(", ",@{$method->argnames});
+	}
+	$build .= ")";
+	return $build;
+}
+
+sub definition {
+	my $self = shift;
+	my $method = shift;
+	my $build = "";
+	my $selftype = $self->selfTypeForMethod($method);
+	my $classref = "";
+	my $cgen = Logos::Generator::for($method->class);
+	if($method->scope eq "+") {
+		$classref = $cgen->superMetaVariable;
+	} else {
+		$classref = $cgen->superVariable;
+	}
+	my $arglist = "";
+	map $arglist .= ", ".Logos::Method::declarationForTypeWithName($method->argtypes->[$_], $method->argnames->[$_]), (0..$method->numArgs - 1);
+	my $parameters = "(".$selftype." self, SEL _cmd".$arglist.")";
+	my $return = $self->returnTypeForMethod($method);
+	my $functionAttributes = $self->functionAttributesForMethod($method);
+	if(!$method->isNew) {
+		my $argtypelist = join(", ", @{$method->argtypes});
+
+		$build .= "static ".Logos::Method::declarationForTypeWithName($return, $self->superFunctionName($method).$parameters).$functionAttributes." {";
+		my $pointerType = "(*)(".$selftype.", SEL";
+		$pointerType .=       ", ".$argtypelist if $argtypelist;
+		$pointerType .=   ")";
+		$build .=     "return ((".$functionAttributes." ".Logos::Method::declarationForTypeWithName($return, $pointerType).")class_getMethodImplementation(".$classref.",".$self->selectorRef($method->selector)."))";
+		$build .=         $self->originalCallParams($method).";";
+		$build .= "}";
+
+	}
+	$build .= "static ".Logos::Method::declarationForTypeWithName($return, $self->newFunctionName($method).$parameters).$functionAttributes;
+	return $build;
+}
+
+sub originalCall {
+	my $self = shift;
+	my $method = shift;
+	my $customargs = shift;
+	return $self->originalFunctionName($method).$self->originalCallParams($method, $customargs);
+}
+
+sub declarations {
+	my $self = shift;
+	my $method = shift;
+	my $build = "";
+	if(!$method->isNew) {
+		my $selftype = $self->selfTypeForMethod($method);
+		my $functionAttributes = $self->functionAttributesForMethod($method);
+		$build .= "static ";
+		my $name = "";
+		$name .= $functionAttributes."(*".$self->originalFunctionName($method).")(".$selftype.", SEL";
+		my $argtypelist = join(", ", @{$method->argtypes});
+		$name .= ", ".$argtypelist if $argtypelist;
+		$name .= ")";
+		$build .= Logos::Method::declarationForTypeWithName($self->returnTypeForMethod($method), $name);
+		$build .= ";";
+	}
+	return $build;
+}
+
+sub initializers {
+	my $self = shift;
+	my $method = shift;
+	my $cgen = Logos::Generator::for($method->class);
+	my $classvar = ($method->scope eq "+" ? $cgen->metaVariable : $cgen->variable);
+	my $r = "{ ";
+	if(!$method->isNew) {
+		my $classargtype = "";
+		if($method->scope eq "+") {
+			$classargtype = "Class";
+		} else {
+			$classargtype = $method->class->type;
+		}
+		$r .= "Class _class = ".$classvar.";";
+		$r .= "Method _method = class_getInstanceMethod(_class, ".$self->selectorRef($method->selector)."));";
+		$r .= "if (_class) {";
+		$r .=   "if (_method) {";
+		$r .=     $self->originalFunctionName($method)." = ".$self->superFunctionName($method).";";
+		$r .=     "if (!class_addMethod(_class, ".$self->selectorRef($method->selector)."), (IMP)&".$self->newFunctionName($method).", method_getTypeEncoding(_method))) {";
+		$r .=       $self->originalFunctionName($method)." = (".$pointertype.")method_getImplementation(_method);";
+		$r .=       $self->originalFunctionName($method)." = (".$pointertype.")method_setImplementation(_method, (IMP)&".$self->newFunctionName($method).");";
+		$r .=     "}";
+		$r .=   "} else {";
+		$r .=     "HBLogError(@\"logos: message not found [%s %s]\", \"".$method->class->name."\", \"".$method->selector."\");";
+		$r .=   "}";
+		$r .= "} else {";
+		$r .=   "HBLogError(@\"logos: nil class %s\", \"".$method->class->name."\");";
+		$r .= "}";
+	} else {
+		if(!$method->type) {
+			$r .= "char _typeEncoding[1024]; unsigned int i = 0; ";
+			for ($method->return, "id", "SEL", @{$method->argtypes}) {
+				my $typeEncoding = Logos::Method::typeEncodingForArgType($_);
+				if(defined $typeEncoding) {
+					my @typeEncodingBits = split(//, $typeEncoding);
+					my $i = 0;
+					for my $char (@typeEncodingBits) {
+						$r .= "_typeEncoding[i".($i > 0 ? " + $i" : "")."] = '$char'; ";
+						$i++;
+					}
+					$r .= "i += ".(scalar @typeEncodingBits)."; ";
+				} else {
+					$r .= "memcpy(_typeEncoding + i, \@encode($_), strlen(\@encode($_))); i += strlen(\@encode($_)); ";
+				}
+			}
+			$r .= "_typeEncoding[i] = '\\0'; ";
+		} else {
+			$r .= "const char *_typeEncoding = \"".$method->type."\"; ";
+		}
+		$r .= "class_addMethod(".$classvar.", ".$self->selectorRef($method->selector).", (IMP)&".$self->newFunctionName($method).", _typeEncoding); ";
+	}
+	$r .= "}";
+	return $r;
+}
+
+1;

+ 33 - 0
CycriptLoader/theos/bin/lib/Logos/Generator/internal/Subclass.pm

@@ -0,0 +1,33 @@
+package Logos::Generator::internal::Subclass;
+use strict;
+use parent qw(Logos::Generator::internal::Class);
+
+# declarations is inherited from Class.
+
+sub _initExpression {
+	my $self = shift;
+	my $class = shift;
+	my $cgen = Logos::Generator::for($class->superclass);
+	return "objc_allocateClassPair(".$cgen->variable.", \"".$class->name."\", 0)";
+}
+
+sub initializers {
+	my $self = shift;
+	my $class = shift;
+	my $return = "";
+	$return .= "{ ";
+	$return .= $self->SUPER::initializers($class)." ";
+	# <ivars>
+	foreach(@{$class->ivars}) {
+		$return .= Logos::Generator::for($_)->initializers;
+	}
+	# </ivars>
+	$return .= "objc_registerClassPair(".$self->variable($class)."); ";
+	foreach(keys %{$class->protocols}) {
+		$return .= "class_addProtocol(".$self->variable($class).", objc_getProtocol(\"$_\")); ";
+	}
+	$return .= "}";
+	return $return;
+}
+
+1;

+ 136 - 0
CycriptLoader/theos/bin/lib/Logos/Group.pm

@@ -0,0 +1,136 @@
+package Logos::Group;
+use strict;
+
+sub new {
+	my $proto = shift;
+	my $class = ref($proto) || $proto;
+	my $self = {};
+	$self->{NAME} = undef;
+	$self->{EXPLICIT} = 1;
+	$self->{INITIALIZED} = 0;
+	$self->{INITLINE} = -1;
+	$self->{CLASSES} = [];
+	$self->{FUNCTIONS} = [];
+	bless($self, $class);
+	return $self;
+}
+
+##################### #
+# Setters and Getters #
+# #####################
+sub name {
+	my $self = shift;
+	if(@_) { $self->{NAME} = shift; }
+	return $self->{NAME};
+}
+
+sub explicit {
+	my $self = shift;
+	if(@_) { $self->{EXPLICIT} = shift; }
+	return $self->{EXPLICIT};
+}
+
+sub initialized {
+	my $self = shift;
+	if(@_) { $self->{INITIALIZED} = shift; }
+	return $self->{INITIALIZED};
+}
+
+sub initRequired {
+	my $self = shift;
+	for(@{$self->{CLASSES}}) {
+		return 1 if $_->initRequired;
+	}
+	for(@{$self->{FUNCTIONS}}) {
+		return 1 if $_->initRequired;
+	}
+	return 0;
+}
+
+sub identifier {
+	my $self = shift;
+	return main::sanitize($self->{NAME});
+}
+
+sub initLine {
+	my $self = shift;
+	if(@_) { $self->{INITLINE} = shift; }
+	return $self->{INITLINE};
+}
+
+sub classes {
+	my $self = shift;
+	return $self->{CLASSES};
+}
+
+sub functions {
+	my $self = shift;
+	return $self->{FUNCTIONS};
+}
+##### #
+# END #
+# #####
+
+sub addClass {
+	my $self = shift;
+	my $class = shift;
+	$class->group($self);
+	push(@{$self->{CLASSES}}, $class);
+}
+
+sub addClassNamed {
+	my $self = shift;
+	my $name = shift;
+
+	my $class = $self->getClassNamed($name);
+	return $class if defined($class);
+
+	$class = ::Class()->new();
+	$class->name($name);
+	$self->addClass($class);
+	return $class;
+}
+
+sub getClassNamed {
+	my $self = shift;
+	my $name = shift;
+	foreach(@{$self->{CLASSES}}) {
+		return $_ if $_->name eq $name;
+	}
+	return undef;
+}
+
+sub addFunction {
+	my $self = shift;
+	my $args = shift;
+
+	my $functionRetval = undef;
+	my $functionName = undef;
+	my $functionArgs = [];
+
+	my $argIdx = 0;
+	for (@$args) {
+		if ($argIdx == 0) {
+			$argIdx++;
+			$functionRetval = $_;
+		} elsif ($argIdx == 1) {
+			$argIdx++;
+			$functionName = $_;
+		} else {
+			push(@$functionArgs, $_);
+		}
+	}
+	
+	my $function = ::Function()->new();
+	$function->retval($functionRetval);
+	$function->name($functionName);
+	for(@$functionArgs) {
+		$function->addArg($_);
+	}
+	$function->group($self);
+	push(@{$self->{FUNCTIONS}}, $function);
+
+	return $function;
+}
+
+1;

+ 39 - 0
CycriptLoader/theos/bin/lib/Logos/Ivar.pm

@@ -0,0 +1,39 @@
+package Logos::Ivar;
+use strict;
+
+sub new {
+	my $proto = shift;
+	my $class = ref($proto) || $proto;
+	my $self = {};
+	$self->{NAME} = shift;
+	$self->{TYPE} = shift;
+	$self->{CLASS} = undef;
+	bless($self, $class);
+	return $self;
+}
+
+##################### #
+# Setters and Getters #
+# #####################
+sub name {
+	my $self = shift;
+	if(@_) { $self->{NAME} = shift; }
+	return $self->{NAME};
+}
+
+sub type {
+	my $self = shift;
+	if(@_) { $self->{TYPE} = shift; }
+	return $self->{TYPE};
+}
+
+sub class {
+	my $self = shift;
+	if(@_) { $self->{CLASS} = shift; }
+	return $self->{CLASS};
+}
+##### #
+# END #
+# #####
+
+1;

+ 285 - 0
CycriptLoader/theos/bin/lib/Logos/Method.pm

@@ -0,0 +1,285 @@
+package Logos::Method;
+use strict;
+use Logos::Util qw(matchedParenthesisSet);
+
+sub new {
+	my $proto = shift;
+	my $class = ref($proto) || $proto;
+	my $self = {};
+	$self->{CLASS} = undef;
+	$self->{SCOPE} = undef;
+	$self->{RETURN} = undef;
+	$self->{SELECTOR_PARTS} = [];
+	$self->{ARGNAMES} = [];
+	$self->{ARGTYPES} = [];
+	$self->{NEW} = 0;
+	$self->{TYPE} = "";
+	bless($self, $class);
+	return $self;
+}
+
+##################### #
+# Setters and Getters #
+# #####################
+sub class {
+	my $self = shift;
+	if(@_) { $self->{CLASS} = shift; }
+	return $self->{CLASS};
+}
+
+sub scope {
+	my $self = shift;
+	if(@_) { $self->{SCOPE} = shift; }
+	return $self->{SCOPE};
+}
+
+sub return {
+	my $self = shift;
+	if(@_) { $self->{RETURN} = shift; }
+	return $self->{RETURN};
+}
+
+sub groupIdentifier {
+	my $self = shift;
+	return $self->class->group->identifier;
+}
+
+sub selectorParts {
+	my $self = shift;
+	if(@_) { @{$self->{SELECTOR_PARTS}} = @_; }
+	return $self->{SELECTOR_PARTS};
+}
+
+sub setNew {
+	my $self = shift;
+	if(@_) { $self->{NEW} = shift; }
+	return $self->{NEW};
+}
+
+sub isNew {
+	my $self = shift;
+	return $self->{NEW};
+}
+
+sub type {
+	my $self = shift;
+	if(@_) { $self->{TYPE} = shift; }
+	return $self->{TYPE};
+}
+
+sub argnames {
+	my $self = shift;
+	return $self->{ARGNAMES};
+}
+
+sub argtypes {
+	my $self = shift;
+	return $self->{ARGTYPES};
+}
+##### #
+# END #
+# #####
+
+sub numArgs {
+	my $self = shift;
+	return scalar @{$self->{ARGTYPES}};
+}
+
+sub addArgument {
+	my $self = shift;
+	my ($type, $name) = @_;
+	push(@{$self->{ARGTYPES}}, $type);
+	push(@{$self->{ARGNAMES}}, $name);
+}
+
+sub selector {
+	my $self = shift;
+	if($self->numArgs == 0) {
+		return $self->{SELECTOR_PARTS}[0];
+	} else {
+		return join(":", @{$self->{SELECTOR_PARTS}}).":";
+	}
+}
+
+sub _new_selector {
+	my $self = shift;
+	if($self->numArgs == 0) {
+		return $self->{SELECTOR_PARTS}[0];
+	} else {
+		return join("\$", @{$self->{SELECTOR_PARTS}})."\$";
+	}
+}
+
+sub methodFamily {
+	my $self = shift;
+	my $selector = $self->selector;
+	if ($self->scope eq "+") {
+		if ($selector =~ /^alloc($|[A-Z,:])/) {
+			return "alloc" if $self->return eq "id" || $self->return eq "instancetype";
+		}
+		if ($selector eq "new") {
+			return "new" if $self->return eq "id" || $self->return eq "instancetype";
+		}
+	} else {
+		if ($selector =~ /^init($|[A-Z,:])/) {
+			return "init" if $self->return eq "id" || $self->return eq "instancetype";
+		}
+		if (($selector eq "copy") || ($selector eq "copyWithZone:")) {
+			return "copy";
+		}
+		if (($selector eq "mutableCopy") || ($selector eq "mutableCopyWithZone:")) {
+			return "mutableCopy";
+		}
+	}
+	return "";
+}
+
+sub printArgForArgType {
+	my $argtype = shift;
+	my $argname = shift;
+
+	my ($formatchar, $fallthrough) = formatCharForArgType($argtype);
+	return undef if $formatchar eq "--";
+
+	$argtype =~ s/^\s+//g;
+	$argtype =~ s/\s+$//g;
+
+	return "NSStringFromSelector($argname)" if $argtype =~ /^SEL$/;
+	return "$argname" if $argtype =~ /^Class$/;
+	return "$argname.location, $argname.length" if $argtype =~ /^NSRange$/;
+	return "$argname.origin.x, $argname.origin.y, $argname.size.width, $argname.size.height" if $argtype =~ /^(CG|NS)Rect$/;
+	return "$argname.x, $argname.y" if $argtype =~ /^(CG|NS)Point$/;
+	return "$argname.width, $argname.height" if $argtype =~ /^(CG|NS)Size$/;
+	return "(long)$argname" if $argtype =~ /^NS(Integer|SocketNativeHandle|StringEncoding|SortOptions|ComparisonResult|EnumerationOptions|(Hash|Map)TableOptions|SearchPath(Directory|DomainMask))$/i;
+	return "(unsigned long)$argname" if $argtype =~ /^NSUInteger$/i;
+
+	return ($fallthrough ? "(unsigned int)" : "").$argname;
+}
+
+sub formatCharForArgType {
+	local $_ = shift;
+	s/^\s+//g;
+	s/\s+$//g;
+
+	# Integral Types
+	# Straight characters get %c. Signed/Unsigned characters get %hhu/%hhd.
+	return "'%c'" if /^char$/;
+	if(/^((signed|unsigned)\s+)?(unsigned|signed|int|long|long\s+long|bool|BOOL|_Bool|char|short)$/) {
+		my $conversion = "d";
+		$conversion = "u" if /\bunsigned\b/;
+
+		my $length;
+		$length = "" if /\bint\b/;
+		$length = "l" if /\blong\b/;
+		$length = "ll" if /\blong long\b/;
+		$length = "h" if /\bshort\b/;
+		$length = "hh" if /\bchar\b/;
+
+		return "%".$length.$conversion;
+	}
+	return "%ld" if /^NS(Integer|SocketNativeHandle|StringEncoding|SortOptions|ComparisonResult|EnumerationOptions|(Hash|Map)TableOptions|SearchPath(Directory|DomainMask))$/i;
+	return "%lu" if /^NSUInteger$/i;
+	return "%d" if /^GS(FontTraitMask)$/i;
+
+	# Pointer Types
+	return "%s" if /^char\s*\*$/;
+	return "%p" if /^void\s*\*$/; # void *
+	return "%p" if /^id\s*\*$/; # id *
+	return "%p" if /^((unsigned|signed)\s+)?(unsigned|signed|int|long|long\s+long|bool|BOOL|_Bool|char|short|float|double)\s*\*+$/;
+	return "%p" if /^NS.*?(Pointer|Array)$/;
+	return "%p" if /^NSZone\s*\*$/;
+	return "%p" if /^struct.*\*$/; # struct pointer
+	return "%p" if /\*\*+$/; # anything with more than one pointer indirection
+	return "%p" if /\[.*\]$/; # any array
+
+	# Objects
+	return "%@" if /^id$/; # id is an objc_object.
+	return "%@" if /^\w+\s*\*$/; # try to treat *any* other pointer as an objc_object.
+	return "%@" if /^\w+Ref$/; # *Ref can be printed with %@.
+
+	# Floating-Point Types
+	return "%f" if /^(double|float|CGFloat|CGDouble|NSTimeInterval)$/;
+
+	# Special Types (should also have an entry in printArgForArgType
+	return "%@" if /^SEL$/;
+	return "%@" if /^Class$/;
+
+	# Even-more-special expanded types
+	return "(%d:%d)" if /^NSRange$/;
+	return "{{%g, %g}, {%g, %g}}" if /^(CG|NS)Rect$/;
+	return "{%g, %g}" if /^(CG|NS)Point$/;
+	return "{%g, %g}" if /^(CG|NS)Size$/;
+
+	# Discarded Types
+	return "--" if /^(CG\w*|CF\w*|void)$/;
+	return "--" if /^NS(HashTable(Callbacks)?|Map(Table((Key|Value)Callbacks)?|Enumerator))$/;
+	return "--" if /^struct/; # structs that aren't covered by 'struct ... *'
+
+	# Fallthrough - Treat everything we don't understand as POD.
+	return ("0x%x", 1) if wantarray; # The 1 is the fallthrough flag - used to signal to argName(...) that we should be casting.
+	return "0x%x";
+}
+
+sub typeEncodingForArgType {
+	local $_ = shift;
+	s/^\s+//g;
+	s/\s+$//g;
+
+	return "c" if /^char$/;
+	return "i" if /^int$/;
+	return "s" if /^short$/;
+	return "l" if /^long$/;
+	return "q" if /^long long$/;
+
+	return "C" if /^unsigned\s+char$/;
+	return "I" if /^unsigned\s+int$/;
+	return "S" if /^unsigned\s+short$/;
+	return "L" if /^unsigned\s+long$/;
+	return "Q" if /^unsigned\s+long long$/;
+
+	return "f" if /^float$/;
+	return "d" if /^double$/;
+	return "B" if /^(bool|_Bool)$/;
+
+	return "v" if /^void$/;
+
+	return "*" if /^char\s*\*$/;
+
+	return "@" if /^id$/;
+	return "@" if /^instancetype$/;
+	return "#" if /^Class$/;
+	return ":" if /^SEL$/;
+
+	if(/^([^*\s]+)\s*\*$/) {
+		my $subEncoding = typeEncodingForArgType($1);
+		return undef if(!defined $subEncoding);
+		return "^".$subEncoding;
+	}
+
+	return undef;
+}
+
+sub declarationForTypeWithName {
+	my $argtype = shift;
+	my $argname = shift;
+	if($argtype !~ /\(\s*[*^]/) {
+		return $argtype." ".$argname;
+	}
+	my $substring = $argtype;
+	my ($opening, $closing) = matchedParenthesisSet($substring, 0);
+	my $offset = 0;
+	while(1) {
+		# We want to put the parameter name right before the closing ) in the deepest nested set if we found a (^ or (*.
+		$substring = substr($substring, $opening, $closing - $opening - 1);
+		$offset += $opening;
+		my ($newopening, $newclosing) = matchedParenthesisSet($substring, 0);
+		last if !defined $newopening;
+		$opening = $newopening;
+		$closing = $newclosing;
+	}
+	my $out = $argtype;
+	substr($out, $offset-$opening+$closing-1, 0, $argname);
+	return $out;
+}
+
+1;

+ 98 - 0
CycriptLoader/theos/bin/lib/Logos/Patch.pm

@@ -0,0 +1,98 @@
+package Logos::Patch;
+use strict;
+
+sub new {
+	my $proto = shift;
+	my $class = ref($proto) || $proto;
+	my $self = {};
+	$self->{LINE} = -1;
+	$self->{RANGE} = [];
+	$self->{SOURCE} = undef;
+	$self->{SQUASH} = 0;
+	bless($self, $class);
+	return $self;
+}
+
+##################### #
+# Setters and Getters #
+# #####################
+sub line {
+	my $self = shift;
+	if(@_) { $self->{LINE} = shift; }
+	return $self->{LINE};
+}
+
+sub range {
+	my $self = shift;
+	if(@_) { @{$self->{RANGE}} = @_; }
+	return $self->{RANGE};
+}
+
+sub start {
+	my $self = shift;
+	if(@_) { $self->{RANGE}[0] = shift; }
+	return $self->{RANGE}[0];
+}
+
+sub end {
+	my $self = shift;
+	if(@_) { $self->{RANGE}[1] = shift; }
+	return $self->{RANGE}[1];
+}
+
+sub source {
+	my $self = shift;
+	if(@_) { $self->{SOURCE} = shift; }
+	return $self->{SOURCE};
+}
+
+sub squash {
+	my $self = shift;
+	if(@_) { $self->{SQUASH} = shift; }
+	return $self->{SQUASH};
+}
+
+##### #
+# END #
+# #####
+
+sub evalSource {
+	my $self = shift;
+	my $source = shift;
+	my $sourceref = ref($source);
+	my @lines;
+	if($sourceref) {
+		if($sourceref eq "ARRAY") {
+			for(@$source) {
+				splice(@lines, scalar @lines, 0, $self->evalSource($_));
+			}
+		} else {
+			push(@lines, $source->eval());
+		}
+	} else {
+		push(@lines, $source);
+	}
+	return @lines;
+}
+
+sub apply {
+	my $self = shift;
+	my $lref = shift;
+	my $line = $self->{LINE};
+	my ($start, $end) = @{$self->{RANGE}};
+	my $source = $self->{SOURCE};
+	my @lines = $self->evalSource($source);
+	if(!defined $start) {
+		push(@lines, ::generateLineDirectiveForPhysicalLine($line));
+		if($self->{SQUASH}) {
+			push(@$lref, join('', @lines));
+		} else {
+			splice(@$lref, $line, 0, @lines);
+		}
+	} else {
+		substr($lref->[$line], $start, $end-$start) = join('', @lines);
+	}
+	return;
+}
+
+1;

+ 27 - 0
CycriptLoader/theos/bin/lib/Logos/Patch/Source/Generator.pm

@@ -0,0 +1,27 @@
+package Logos::Patch::Source::Generator;
+use strict;
+
+sub new {
+	my $proto = shift;
+	my $class = ref($proto) || $proto;
+	my $self = {};
+	$self->{OBJECT} = shift;
+	$self->{METHOD} = shift;
+	my @args = @_;
+	$self->{ARGS} = \@args;
+	bless($self, $class);
+	return $self;
+}
+
+sub eval {
+	#no strict 'refs';
+	my $self = shift;
+	my @args = @{$self->{ARGS}};
+	splice(@args, 0, 0, $self->{OBJECT}) if $self->{OBJECT};
+	return Logos::Generator::for($self->{OBJECT})->can($self->{METHOD})->(@args);
+	#my $thunk = Logos::Generator::for($self->{OBJECT})->can($self->{METHOD})-(>${$self->{ARGS}});;
+	#my $mname = $self->{METHOD};
+	#return $thunk->$mname(@{$self->{ARGS}});
+}
+
+1;

+ 69 - 0
CycriptLoader/theos/bin/lib/Logos/Property.pm

@@ -0,0 +1,69 @@
+package Logos::Property;
+use strict;
+
+##################### #
+# Setters and Getters #
+# #####################
+
+sub new{
+	my $proto = shift;
+	my $class = ref($proto) || $proto;
+	my $self = {};
+	$self->{CLASS} = undef;
+	$self->{GROUP} = undef;
+	$self->{NAME} = undef;
+	$self->{TYPE} = undef;
+	$self->{NUMATTR} = undef;
+	$self->{ASSOCIATIONPOLICY} = undef;
+	$self->{ATTRIBUTES} = [];
+	bless($self, $class);
+	return $self;
+}
+
+sub class {
+	my $self = shift;
+	if(@_) { $self->{CLASS} = shift; }
+	return $self->{CLASS};
+}
+
+sub group {
+	my $self = shift;
+	if(@_) { $self->{GROUP} = shift; }
+	return $self->{GROUP};
+}
+
+sub name {
+	my $self = shift;
+	if(@_) { $self->{NAME} = shift; }
+	return $self->{NAME};
+}
+
+sub type {
+	my $self = shift;
+	if(@_) { $self->{TYPE} = shift; }
+	return $self->{TYPE};
+}
+
+sub numattr {
+	my $self = shift;
+	if(@_) { $self->{NUMATTR} = shift; }
+	return $self->{NUMATTR};
+}
+
+sub attributes {
+	my $self = shift;
+	if(@_) { @{$self->{ATTRIBUTES}} = @_; }
+	return $self->{ATTRIBUTES};
+}
+
+sub associationPolicy {
+	my $self = shift;
+	if (@_) { $self->{ASSOCIATIONPOLICY} = shift; }
+	return $self->{ASSOCIATIONPOLICY};
+}
+
+##### #
+# END #
+# #####
+
+1;

+ 51 - 0
CycriptLoader/theos/bin/lib/Logos/StaticClassGroup.pm

@@ -0,0 +1,51 @@
+package Logos::StaticClassGroup;
+use Logos::Group;
+our @ISA = ('Logos::Group');
+
+sub new {
+	my $proto = shift;
+	my $class = ref($proto) || $proto;
+	my $self = Logos::Group->new();
+	$self->name("_staticClass");
+	$self->explicit(0);
+	$self->{DECLAREDONLYCLASSES} = {};
+	$self->{USEDCLASSES} = {};
+	$self->{USEDMETACLASSES} = {};
+	bless($self, $class);
+	return $self;
+}
+
+sub addUsedClass {
+	my $self = shift;
+	my $class = shift;
+	$self->{USEDCLASSES}{$class}++;
+}
+
+sub addUsedMetaClass {
+	my $self = shift;
+	my $class = shift;
+	$self->{USEDMETACLASSES}{$class}++;
+}
+
+sub addDeclaredOnlyClass {
+	my $self = shift;
+	my $class = shift;
+	$self->{DECLAREDONLYCLASSES}{$class}++;
+}
+
+sub declaredOnlyClasses {
+	my $self = shift;
+	return $self->{DECLAREDONLYCLASSES};
+}
+
+sub usedClasses {
+	my $self = shift;
+	return $self->{USEDCLASSES};
+}
+
+sub usedMetaClasses {
+	my $self = shift;
+	return $self->{USEDMETACLASSES};
+}
+
+1;

+ 67 - 0
CycriptLoader/theos/bin/lib/Logos/Subclass.pm

@@ -0,0 +1,67 @@
+package Logos::Subclass;
+use Logos::Class;
+our @ISA = ('Logos::Class');
+
+sub new {
+	my $proto = shift;
+	my $class = ref($proto) || $proto;
+	my $self = $class->SUPER::new();
+	$self->{SUPERCLASS} = undef;
+	$self->{PROTOCOLS} = {};
+	$self->{IVARS} = [];
+	$self->{OVERRIDDEN} = 1;
+	bless($self, $class);
+	return $self;
+}
+
+##################### #
+# Setters and Getters #
+# #####################
+sub superclass {
+	my $self = shift;
+	if(@_) { $self->{SUPERCLASS} = shift; }
+	return $self->{SUPERCLASS};
+}
+
+sub ivars {
+	my $self = shift;
+	return $self->{IVARS};
+}
+
+sub protocols {
+	my $self = shift;
+	return $self->{PROTOCOLS};
+}
+
+sub initRequired {
+	my $self = shift;
+	return 1; # Subclasses must always be initialized.
+}
+
+##### #
+# END #
+# #####
+
+sub addProtocol {
+	my $self = shift;
+	my $protocol = shift;
+	$self->{PROTOCOLS}{$protocol}++;
+}
+
+sub addIvar {
+	my $self = shift;
+	my $ivar = shift;
+	$ivar->class($self);
+	push(@{$self->{IVARS}}, $ivar);
+}
+
+sub getIvarNamed {
+	my $self = shift;
+	my $name = shift;
+	foreach(@{$self->{IVARS}}) {
+		return $_ if $_->name eq $name;
+	}
+	return undef;
+}
+
+1;

+ 113 - 0
CycriptLoader/theos/bin/lib/Logos/Util.pm

@@ -0,0 +1,113 @@
+package Logos::Util;
+use 5.006;
+use strict;
+our @ISA = ('Exporter');
+our @EXPORT = qw(quotes fallsBetween sanitize matchedParenthesisSet nestedParenString smartSplit);
+our $errorhandler = \&_defaultErrorHandler;
+
+sub _defaultErrorHandler {
+	die shift;
+}
+
+sub quotes {
+	my ($line) = @_;
+	my @quotes = ();
+	while($line =~ /(?<!\\)\"/g) {
+		push(@quotes, $-[0]);
+	}
+	return @quotes;
+}
+
+sub fallsBetween {
+	my $idx = shift;
+	while(@_ > 0) {
+		my $start = shift;
+		my $end = shift;
+		return 1 if ($start < $idx && (!defined($end) || $end > $idx))
+	}
+	return 0;
+}
+
+sub sanitize {
+	my $input = shift;
+	my $output = $input;
+	$output =~ s/[^\w]//g;
+	return $output;
+}
+
+sub matchedParenthesisSet {
+	my $in = shift;
+	my $atstart = shift;
+	$atstart = 1 if !defined $atstart;
+	my $untilend = shift;
+	$untilend = 0 if !defined $untilend;
+
+	my @parens;
+	if(!$atstart || $in =~ /^\s*\(/) {
+		# If we encounter a ) that puts us back at zero, we found a (
+		# and have reached its closing ).
+		my $parenmatch = $in;
+		my $pdepth = 0;
+		my @pquotes = quotes($parenmatch);
+		while($parenmatch =~ /[;()]/g) {
+			next if fallsBetween($-[0], @pquotes);
+
+			if($& eq "(") {
+				if($pdepth == 0) { push(@parens, $+[0]); }
+				$pdepth++;
+			} elsif($& eq ")") {
+				$pdepth--;
+				if($pdepth == 0) { push(@parens, $+[0]); last if(!$untilend); }
+			}
+		}
+	}
+
+	return undef if scalar @parens == 0;
+	# Odd number of parens means a closing paren was left off!
+	&$errorhandler("missing closing parenthesis") if scalar @parens % 2 == 1;
+	return @parens;
+}
+
+sub nestedParenString {
+	my $in = shift;
+	my ($opening, $closing) = matchedParenthesisSet($in);
+
+	my @ret;
+	if(defined $opening) {
+		$ret[0] = substr($in, $opening, $closing - $opening - 1);
+		$in = substr($in, $closing);
+	}
+	$ret[1] = $in;
+	return @ret;
+}
+
+sub smartSplit {
+	my $re = shift;
+	my $in = shift;
+	return () if !$in || $in eq "";
+
+	my $limit = shift;
+	$limit = 0 if !defined $limit;
+
+	my @quotes = quotes($in);
+	# We pass 1 for arg 3 to catch all matching parentheses until the end of the string
+	# as smartSplit only operates on a substring.
+	my @parens = matchedParenthesisSet($in, 0, 1);
+
+	my $lstart = 0;
+	my @pieces = ();
+	my $piece = "";
+	while($in =~ /$re/g) {
+		next if (defined $parens[0] && fallsBetween($-[0], @parens)) || fallsBetween($-[0], @quotes);
+		$piece = substr($in, $lstart, $-[0]-$lstart);
+		push(@pieces, $piece);
+		$lstart = $+[0];
+		$limit--;
+		last if($limit == 1); # One item left? Bail out and throw the rest of the string into it!
+	}
+	$piece = substr($in, $lstart);
+	push(@pieces, $piece);
+	return @pieces;
+}
+
+1;

+ 120 - 0
CycriptLoader/theos/bin/lib/NIC/Bridge/Context.pm

@@ -0,0 +1,120 @@
+package NIC::Bridge::Context;
+use strict;
+use warnings;
+use subs qw(warn exit);
+use Module::Load::Conditional qw(can_load);
+use NIC::Tie::PrefixedHandleRedirect;
+use NIC::Bridge::NICBase;
+
+our %handlers = (
+	PROMPT => sub { },
+);
+
+sub import {
+	my $package = shift;
+	my %arg = @_;
+	for(keys %arg) {
+		$handlers{$_} = $arg{$_};
+	}
+}
+
+our $bridge = undef;
+our $global_ret = undef;
+our $errored_out = undef;
+
+sub NIC {
+	return $bridge;
+}
+
+sub warn(@) {
+	print STDERR "[".$bridge->{FOR}->name."/warning] ",@_,$/;
+}
+
+sub error(@) {
+	print STDERR "[".$bridge->{FOR}->name."/error] ",@_,$/;
+	$errored_out = 1;
+	die;
+}
+
+sub exit {
+	$global_ret = shift;
+	die;
+}
+
+sub prompt {
+	__PACKAGE__->_prompt($bridge->{FOR}, undef, @_);
+}
+
+sub _prompt {
+	my $self = shift;
+	my $nic = shift;
+
+	my $n = scalar @_;
+	my $opts = $_[$n-1];
+	if(ref $opts eq "HASH") {
+		$n--;
+	} else {
+		$opts = {};
+	}
+
+	my $variable;
+	$variable = shift unless $n == 1;
+	my $promptstring = shift;
+
+	$handlers{PROMPT}->($nic, $variable, $promptstring, $opts->{default});
+}
+
+sub _wrap {
+	my $self = shift;
+	my @r = map {
+		my $wrap = $_;
+		my $_wrapType = $wrap ? (ref $wrap) : "_Undefined";
+		if(!$_wrapType || (ref($wrap) && $wrap->isa("NIC::Bridge::_BridgedObject"))) {
+			return $wrap;
+		} else {
+			$_wrapType =~ s/.*:://;
+			my $wrappingClass = "NIC::Bridge::$_wrapType";
+			can_load(modules=>{$wrappingClass=>undef}, verbose=>0) or return undef;
+			my $wrapper = $wrappingClass->new($self, $wrap);
+			return $wrapper;
+		}
+	} (@_);
+	return @r if wantarray;
+	return (@r > 0 ? $r[0] : undef);
+}
+
+sub _unwrap {
+	my $self = shift;
+	my @r = map { (ref($_) && $_->isa("NIC::Bridge::_BridgedObject")) ? $_->{FOR} : $_; } (@_);
+	return @r if wantarray;
+	return (@r > 0 ? $r[0] : undef);
+}
+
+sub _execute {
+	my $self = shift;
+	my $nic = shift;
+	my $script = shift;
+	my $ret = 1;
+	{
+		local $global_ret;
+		local $errored_out;
+		local $bridge = NIC::Bridge::NICBase->new($self, $nic);
+		local $SIG{__DIE__} = sub { };
+		tie *OVERRIDE, "NIC::Tie::PrefixedHandleRedirect", *STDERR, $nic->name;
+		my $stdout = select(*OVERRIDE);
+		eval("#line 1 ".$nic->name."/control.pl\n".$script);
+		select($stdout);
+		if(defined $errored_out) {
+			$ret = 0;
+		} elsif(defined $global_ret) {
+			$ret = $global_ret;
+			print STDERR "[".$nic->name."/error] Control script exited with status $ret.",$/;
+		} elsif($@) {
+			$ret = 0;
+			print STDERR "[".$nic->name."/error] Control script exited due to an error: $@";
+		}
+	}
+	return $ret;
+}
+
+1;

+ 6 - 0
CycriptLoader/theos/bin/lib/NIC/Bridge/Directory.pm

@@ -0,0 +1,6 @@
+package NIC::Bridge::Directory;
+use strict;
+use warnings;
+use parent qw(NIC::Bridge::NICType);
+
+1;

+ 13 - 0
CycriptLoader/theos/bin/lib/NIC/Bridge/File.pm

@@ -0,0 +1,13 @@
+package NIC::Bridge::File;
+use strict;
+use warnings;
+use parent qw(NIC::Bridge::NICType);
+use NIC::Tie::Method;
+
+sub data :lvalue {
+	my $self = shift;
+	tie my $tied, 'NIC::Tie::Method', $self->{FOR}, "data";
+	$tied;
+}
+
+1;

+ 76 - 0
CycriptLoader/theos/bin/lib/NIC/Bridge/NICBase.pm

@@ -0,0 +1,76 @@
+package NIC::Bridge::NICBase;
+use strict;
+use warnings;
+use parent qw(NIC::Bridge::_BridgedObject);
+use NIC::NICBase::Directory;
+use NIC::NICBase::File;
+use NIC::NICBase::Symlink;
+
+sub variables {
+	my $self = shift;
+	return keys %{$self->{FOR}->{VARIABLES}};
+}
+
+sub variable :lvalue {
+	my $self = shift;
+	$self->{FOR}->variable(@_);
+}
+
+sub mkdir {
+	my $self = shift;
+	my $dirname = shift;
+	my $mode = shift;
+	my $ref = $self->{FOR}->_getContent($dirname);
+	NIC::NICBase::Directory->take($ref);
+	$ref->mode($mode) if $mode;
+	return $self->{CONTEXT}->_wrap($ref);
+}
+
+sub mkfile {
+	my $self = shift;
+	my $name = shift;
+	my $mode = shift;
+	my $ref = $self->{FOR}->_getContent($name);
+	NIC::NICBase::File->take($ref);
+	$ref->mode($mode) if $mode;
+	return $self->{CONTEXT}->_wrap($ref);
+}
+
+sub symlink {
+	my $self = shift;
+	my $oldfile = shift;
+	my $newfile = shift;
+	my $ref = $self->{FOR}->_getContent($newfile);
+
+	my $realtarget = ref($oldfile) ? $self->{CONTEXT}->_unwrap($oldfile) : $self->{FOR}->_getContentWithoutCreate($oldfile);
+	$realtarget = $oldfile if !$realtarget;
+
+	NIC::NICBase::Symlink->take($ref, $realtarget);
+
+	return $self->{CONTEXT}->_wrap($ref);
+}
+
+sub lookup {
+	my $self = shift;
+	my $name = shift;
+	return $self->{CONTEXT}->_wrap($self->{FOR}->_getContentWithoutCreate($name));
+}
+
+sub setConstraint {
+	my $self = shift;
+	my $constraint = shift;
+	$self->{FOR}->addConstraint($constraint);
+}
+
+sub clearConstraint {
+	my $self = shift;
+	my $constraint = shift;
+	$self->{FOR}->removeConstraint($constraint);
+}
+
+sub prompt {
+	my $self = shift;
+	$self->{CONTEXT}->_prompt($self->{FOR}, @_);
+}
+
+1;

+ 29 - 0
CycriptLoader/theos/bin/lib/NIC/Bridge/NICType.pm

@@ -0,0 +1,29 @@
+package NIC::Bridge::NICType;
+use strict;
+use warnings;
+use parent qw(NIC::Bridge::_BridgedObject);
+use NIC::Tie::Method;
+
+sub name :lvalue {
+	my $self = shift;
+	tie my $tied, 'NIC::Tie::Method', $self->{FOR}, "name";
+	$tied;
+}
+
+sub mode :lvalue {
+	my $self = shift;
+	tie my $tied, 'NIC::Tie::Method', $self->{FOR}, "mode";
+	$tied;
+}
+
+sub constraints {
+	my $self = shift;
+	return $self->{FOR}->constraints;
+}
+
+sub constrain {
+	my $self = shift;
+	$self->{FOR}->addConstraint(shift);
+}
+
+1;

+ 13 - 0
CycriptLoader/theos/bin/lib/NIC/Bridge/Symlink.pm

@@ -0,0 +1,13 @@
+package NIC::Bridge::Symlink;
+use strict;
+use warnings;
+use parent qw(NIC::Bridge::NICType);
+use NIC::Bridge::Tie::WrappedMethod;
+
+sub target :lvalue {
+	my $self = shift;
+	tie my $tied, 'NIC::Bridge::Tie::WrappedMethod', $self->{CONTEXT}, $self->{FOR}, "target";
+	$tied;
+}
+
+1;

+ 28 - 0
CycriptLoader/theos/bin/lib/NIC/Bridge/Tie/WrappedMethod.pm

@@ -0,0 +1,28 @@
+package NIC::Bridge::Tie::WrappedMethod;
+use strict;
+use warnings;
+use parent qw(Tie::Scalar);
+
+sub TIESCALAR {
+	my $class = shift;
+	my $self = { CONTEXT => shift, FOR => shift, METHOD => shift };
+	bless($self, $class);
+	return $self;
+}
+
+sub FETCH {
+	my $self = shift;
+	my $obj = $self->{FOR};
+	my $ret = $self->{FOR}->can($self->{METHOD})->($self->{FOR});
+	return $self->{CONTEXT}->_wrap($ret);
+}
+
+sub STORE {
+	my $self = shift;
+	my $obj = $self->{FOR};
+	my $in = shift;
+	$self->{FOR}->can($self->{METHOD})->($self->{FOR}, $self->{CONTEXT}->_unwrap($in));
+}
+
+1;
+

+ 19 - 0
CycriptLoader/theos/bin/lib/NIC/Bridge/_BridgedObject.pm

@@ -0,0 +1,19 @@
+package NIC::Bridge::_BridgedObject;
+use strict;
+use warnings;
+
+use overload '""' => sub {
+	my $self = shift;
+	return "[".($self->{FOR}//"(undefined)")."]";
+};
+
+sub new {
+	my $proto = shift;
+	my $class = ref($proto) || $proto;
+	my $self = { CONTEXT => shift, FOR => shift };
+	bless($self, $proto);
+	return $self;
+}
+
+
+1;

+ 21 - 0
CycriptLoader/theos/bin/lib/NIC/Bridge/_Undefined.pm

@@ -0,0 +1,21 @@
+package NIC::Bridge::_Undefined;
+use strict;
+use warnings;
+use parent qw(NIC::Bridge::_BridgedObject);
+
+use overload "bool" => sub {
+	return 0;
+};
+
+our $AUTOLOAD;
+sub AUTOLOAD {
+	my $method = $AUTOLOAD;
+	$method =~ s/.*:://;
+	NIC::Bridge::Context::error("Method '$method' called on nonexistent NIC Bridge object.");
+}
+
+sub DESTROY {
+	my $self = shift;
+}
+
+1;

+ 60 - 0
CycriptLoader/theos/bin/lib/NIC/Formats/NIC1.pm

@@ -0,0 +1,60 @@
+package NIC::Formats::NIC1;
+use parent NIC::NICBase;
+use strict;
+
+sub new {
+	my $proto = shift;
+	my $class = ref($proto) || $proto;
+
+	my $fh = shift;
+	my $self = NIC::NICBase->new(@_);
+	bless($self, $class);
+
+	$self->load($fh);
+	return $self;
+}
+
+sub _processLine {
+	my $self = shift;
+	my $fh = shift;
+	local $_ = shift;
+	if(/^name \"(.*)\"$/) {
+		$self->name($1);
+	} elsif(/^dir (.+)$/) {
+		$self->registerDirectory($1);
+	} elsif(/^file (\d+) (.+)$/) {
+		my $lines = $1;
+		my $filename = $2;
+		my $fref = $self->registerFile($filename);
+		my $filedata = "";
+		while($lines > 0) {
+			$filedata .= <$fh>;
+			$lines--;
+		}
+		$fref->data($filedata);
+	} elsif(/^prompt (\w+) \"(.*?)\"( \"(.*?)\")?$/) {
+		my $key = $1;
+		my $prompt = $2;
+		my $default = $4 || undef;
+		$self->registerPrompt($key, $prompt, $default);
+	} elsif(/^symlink \"(.+)\" \"(.+)\"$/) {
+		my $name = $1;
+		my $dest = $2;
+		$self->registerSymlink($name, $dest);
+	} elsif(/^constrain file \"(.+)\" to (.+)$/) {
+		my $constraint = $2;
+		my $filename = $1;
+		$self->registerFileConstraint($filename, $constraint);
+	}
+}
+
+sub load {
+	my $self = shift;
+	my $fh = shift;
+	while(<$fh>) {
+		$self->_processLine($fh, $_);
+	}
+	$self->resolveSymlinks;
+}
+
+1;

+ 146 - 0
CycriptLoader/theos/bin/lib/NIC/Formats/NICTar.pm

@@ -0,0 +1,146 @@
+package NIC::Formats::NICTar;
+use parent NIC::NICBase;
+use strict;
+use NIC::Formats::NICTar::File;
+use NIC::Formats::NICTar::Directory;
+use NIC::Formats::NICTar::Symlink;
+use Archive::Tar;
+use File::Temp;
+use File::Path;
+use File::Spec;
+use NIC::Bridge::Context;
+$Archive::Tar::WARN = 0;
+
+sub new {
+	my $proto = shift;
+	my $fh_or_tar = shift;
+	my $class = ref($proto) || $proto;
+
+	my $tar = ref($fh_or_tar) eq "Archive::Tar" ? $fh_or_tar : Archive::Tar->new($fh_or_tar);
+	return undef if(!$tar);
+
+	my $control = _fileFromTar(undef, $tar, "NIC/control");
+	return undef if(!$control);
+
+	my $self = NIC::NICBase->new(@_);
+	$self->{_TAR} = $tar;
+	bless($self, $class);
+
+	$self->_processData($control->get_content);
+	$self->load();
+
+	return $self;
+}
+
+sub _fileClass { "NIC::Formats::NICTar::File"; }
+sub _directoryClass { "NIC::Formats::NICTar::Directory"; }
+sub _symlinkClass { "NIC::Formats::NICTar::Symlink"; }
+
+sub _fileFromTar {
+	my $self = shift;
+	my $tar = $self ? $self->{_TAR} : shift;
+	my $filename = shift;
+	my @_tarfiles = $tar->get_files("./$filename", $filename);
+	return (scalar @_tarfiles > 0) ? $_tarfiles[0] : undef;
+}
+
+sub _processData {
+	my $self = shift;
+	my $data = shift;
+	for(split /\n\r?/, $data) {
+		$self->_processLine($_);
+	}
+}
+
+sub _processLine {
+	my $self = shift;
+	local $_ = shift;
+	if(/^name\s+\"(.*)\"$/ || /^name\s+(.*)$/) {
+		$self->name($1);
+	} elsif(/^prompt (\w+) \"(.*?)\"( \"(.*?)\")?$/) {
+		my $key = $1;
+		my $prompt = $2;
+		my $default = $4 || undef;
+		$self->registerPrompt($key, $prompt, $default);
+	} elsif(/^constrain (file )?\"(.+)\" to (.+)$/) {
+		my $constraint = $3;
+		my $filename = $2;
+		$self->registerFileConstraint($filename, $constraint);
+	} elsif(/^ignore (\w+)$/) {
+		$self->ignoreVariable($1);
+	}
+}
+
+sub load {
+	my $self = shift;
+	for($self->{_TAR}->get_files()) {
+		next if !$_->full_path || $_->full_path =~ /^(\.\/)?NIC(\/|$)/;
+		my $n = $_->full_path;
+		$n =~ s/^\.\///;
+		next if length $n == 0;
+		if($_->is_dir) {
+			my $ref = $self->registerDirectory($n);
+			$ref->tarfile($_);
+		} elsif($_->is_symlink) {
+			my $target = $_->linkname;
+			$target =~ s/^\.\///;
+
+			my $ref = $self->registerSymlink($n, $target);
+			$ref->tarfile($_);
+		} elsif($_->is_file) {
+			my $ref = $self->registerFile($n);
+			$ref->tarfile($_);
+		}
+	}
+	$self->resolveSymlinks;
+}
+
+sub _execPackageScript {
+	my $self = shift;
+	my $script = shift;
+	my $tarfile = $self->_fileFromTar("NIC/$script");
+	return if !$tarfile || $tarfile->mode & 0500 != 0500;
+	my $filename = File::Spec->catfile($self->{_TEMPDIR}, $script);
+	my $nicfile = NIC::NICType->new($self, $filename);
+	$self->_fileClass->take($nicfile);
+	$nicfile->tarfile($tarfile);
+	$nicfile->create();
+	my $ret = system $filename $script;
+	return ($ret >> 8) == 0
+}
+
+sub prebuild {
+	my $self = shift;
+	return $self->_execPackageScript("prebuild");
+}
+
+sub postbuild {
+	my $self = shift;
+	return $self->_execPackageScript("postbuild");
+}
+
+sub exec {
+	my $self = shift;
+	my $_controlpl = $self->_fileFromTar("NIC/control.pl");
+	if($_controlpl) {
+		return NIC::Bridge::Context->_execute($self, $_controlpl->get_content);
+	}
+	return 1;
+}
+
+sub build {
+	my $self = shift;
+
+	for(keys %{$self->{VARIABLES}}) {
+		$ENV{"NIC_".$_} = $self->variable($_);
+	}
+
+	$self->{_TEMPDIR} = File::Temp::tempdir();
+
+	$self->SUPER::build(@_);
+
+	File::Path::rmtree($self->{_TEMPDIR});
+	$self->{_TEMPDIR} = undef;
+}
+
+1;

+ 11 - 0
CycriptLoader/theos/bin/lib/NIC/Formats/NICTar/Directory.pm

@@ -0,0 +1,11 @@
+package NIC::Formats::NICTar::Directory;
+use parent qw(NIC::Formats::NICTar::_TarMixin NIC::NICBase::Directory);
+use strict;
+
+sub _take_init {
+	my $self = shift;
+	$self->NIC::NICBase::Directory::_take_init(@_);
+	$self->NIC::Formats::NICTar::_TarMixin::_take_init(@_);
+}
+
+1;

+ 16 - 0
CycriptLoader/theos/bin/lib/NIC/Formats/NICTar/File.pm

@@ -0,0 +1,16 @@
+package NIC::Formats::NICTar::File;
+use parent qw(NIC::Formats::NICTar::_TarMixin NIC::NICBase::File);
+use strict;
+
+sub _take_init {
+	my $self = shift;
+	$self->NIC::NICBase::File::_take_init(@_);
+	$self->NIC::Formats::NICTar::_TarMixin::_take_init(@_);
+}
+
+sub data {
+	my $self = shift;
+	return $self->SUPER::data(@_) // $self->tarfile->get_content;
+}
+
+1;

+ 11 - 0
CycriptLoader/theos/bin/lib/NIC/Formats/NICTar/Symlink.pm

@@ -0,0 +1,11 @@
+package NIC::Formats::NICTar::Symlink;
+use parent NIC::NICBase::Symlink;
+use strict;
+
+sub tarfile {
+	my $self = shift;
+	if(@_) { $self->{TARFILE} = shift; }
+	return $self->{TARFILE};
+}
+
+1;

+ 20 - 0
CycriptLoader/theos/bin/lib/NIC/Formats/NICTar/_TarMixin.pm

@@ -0,0 +1,20 @@
+package NIC::Formats::NICTar::_TarMixin;
+use strict;
+
+sub _take_init {
+	my $self = shift;
+	$self->{TARFILE} = undef;
+}
+
+sub tarfile {
+	my $self = shift;
+	if(@_) { $self->{TARFILE} = shift; }
+	return $self->{TARFILE};
+}
+
+sub _mode {
+	my $self = shift;
+	return $self->tarfile->mode;
+}
+
+1;

+ 221 - 0
CycriptLoader/theos/bin/lib/NIC/NICBase.pm

@@ -0,0 +1,221 @@
+package NIC::NICBase;
+use strict;
+use warnings;
+
+use NIC::NICBase::File;
+use NIC::NICBase::Directory;
+use NIC::NICBase::Symlink;
+
+use List::Util qw(first);
+
+sub new {
+	my $proto = shift;
+	my $class = ref($proto) || $proto;
+	my $self = {};
+	$self->{NAME} = shift;
+	$self->{CONTENTS} = [];
+	$self->{VARIABLES} = {};
+	$self->{CONSTRAINTS} = {};
+	$self->{PROMPTS} = [];
+	$self->{IGNORED_VARS} = {};
+	bless($self, $class);
+
+	return $self;
+}
+
+sub _fileClass { "NIC::NICBase::File"; }
+sub _directoryClass { "NIC::NICBase::Directory"; }
+sub _symlinkClass { "NIC::NICBase::Symlink"; }
+
+sub _getContentWithoutCreate {
+	my $self = shift;
+	my $name = shift;
+	return first { $_->name eq $name } @{$self->{CONTENTS}};
+}
+
+sub _getContent {
+	my $self = shift;
+	my $ref = $self->_getContentWithoutCreate(@_);
+	return $ref if $ref;
+	$ref = NIC::NICType->new($self, @_);
+	push(@{$self->{CONTENTS}}, $ref);
+	return $ref;
+}
+
+sub _generate {
+	my $self = shift;
+	my $class = shift;
+	my $name = shift;
+	my $ref = $self->_getContent($name, @_);
+	if($ref->type == NIC::NICType::TYPE_UNKNOWN) {
+		$class->take($ref, @_);
+	}
+	return $ref;
+}
+
+sub registerDirectory {
+	my $self = shift;
+	my $dir = $self->_generate($self->_directoryClass, @_);
+	return $dir;
+}
+
+sub registerFile {
+	my $self = shift;
+	my $file = $self->_generate($self->_fileClass, @_);
+	return $file;
+}
+
+sub registerSymlink {
+	my $self = shift;
+	my $symlink = $self->_generate($self->_symlinkClass, @_);
+	return $symlink;
+}
+
+sub registerPrompt {
+	my($self, $key, $prompt, $default) = @_;
+	push(@{$self->{PROMPTS}}, {
+			name => $key,
+			prompt => $prompt,
+			default => $default
+		});
+}
+
+sub registerFileConstraint {
+	my $self = shift;
+	my $filename = shift;
+	my $constraint = shift;
+	$self->_getContent($filename)->addConstraint($constraint);
+}
+
+sub resolveSymlinks {
+	my $self = shift;
+	for(@{$self->{CONTENTS}}) {
+		next unless $_->type == NIC::NICType::TYPE_SYMLINK;
+		next if $_->target_type != NIC::NICType::TYPE_UNKNOWN;
+		my $ref = $self->_getContentWithoutCreate($_->target);
+		$_->target($ref) if $ref;
+	}
+}
+
+sub variable: lvalue {
+	my $self = shift;
+	my $key = shift;
+	$self->{VARIABLES}->{$key};
+}
+
+sub name {
+	my $self = shift;
+	if(@_) { $self->{NAME} = shift; }
+	return $self->{NAME} // "(unnamed template)";
+}
+
+sub prompts {
+	my $self = shift;
+	return @{$self->{PROMPTS}};
+}
+
+sub addConstraint {
+	my $self = shift;
+	my $constraint = shift;
+	$self->{CONSTRAINTS}->{$constraint} = 1;
+}
+
+sub removeConstraint {
+	my $self = shift;
+	my $constraint = shift;
+	delete $self->{CONSTRAINTS}->{$constraint};
+}
+
+sub _constraintMatch {
+	my $self = shift;
+	my $constraint = shift;
+	my $negated = 0;
+	if(substr($constraint, 0, 1) eq "!") {
+		$negated = 1;
+		substr($constraint, 0, 1, "");
+	}
+	return 0 if(!$negated && (!defined $self->{CONSTRAINTS}->{$constraint} || $self->{CONSTRAINTS}->{$constraint} != 1));
+	return 0 if($negated && (defined $self->{CONSTRAINTS}->{$constraint} || $self->{CONSTRAINTS}->{$constraint} != 0));
+	return 1;
+}
+
+sub _meetsConstraints {
+	my $self = shift;
+	my $content = shift;
+	foreach ($content->constraints) {
+		return 0 if !$self->_constraintMatch($_);
+	}
+	return 1;
+}
+
+sub substituteVariables {
+	my $self = shift;
+	my $line = shift;
+	foreach my $key (keys %{$self->{VARIABLES}}) {
+		my $value = $self->{VARIABLES}->{$key};
+		$line =~ s/\@\@$key\@\@/$value/g;
+	}
+	return $line;
+}
+
+sub ignoreVariable {
+	my $self = shift;
+	my $var = shift;
+	$self->{IGNORED_VARS}->{$var}++;
+}
+
+sub variableIgnored {
+	my $self = shift;
+	my $var = shift;
+	return defined $self->{IGNORED_VARS}->{$var};
+}
+
+sub prebuild {
+
+}
+
+sub postbuild {
+
+}
+
+sub exec {
+	return 1;
+}
+
+sub build {
+	my $self = shift;
+	my $dir = shift;
+	mkdir($dir) or die "Failed to create the directory '$dir': $!\n";
+	chdir($dir) or die $!;
+	$self->prebuild();
+	foreach my $content (sort { $a->type <=> $b->type } (@{$self->{CONTENTS}})) {
+		next if $content->type == NIC::NICType::TYPE_UNKNOWN;
+		next if !$self->_meetsConstraints($content);
+		$content->create();
+	}
+	$self->postbuild();
+}
+
+sub dumpPreamble {
+	my $self = shift;
+	my $preamblefn = shift;
+	open(my $pfh, ">", $preamblefn);
+	print $pfh "name \"".$self->{NAME}."\"",$/;
+	foreach my $prompt (@{$self->{PROMPTS}}) {
+		print $pfh "prompt ".$prompt->{name}." \"".$prompt->{prompt}."\"";
+		print $pfh " \"".$prompt->{default}."\"" if defined $prompt->{default};
+		print $pfh $/;
+	}
+	foreach my $filename (keys %{$self->{FILES}}) {
+		my $file = $self->{FILES}->{$filename};
+		if(!defined $file->{constraints}) {
+			next;
+		}
+		foreach (@{$file->{constraints}}) {
+			print $pfh "constrain file \"".$filename."\" to ".$_,$/
+		}
+	}
+	close($pfh);
+}
+
+1;

+ 24 - 0
CycriptLoader/theos/bin/lib/NIC/NICBase/Directory.pm

@@ -0,0 +1,24 @@
+package NIC::NICBase::Directory;
+use strict;
+use warnings;
+use parent qw(NIC::NICType);
+use File::Path qw(mkpath);
+
+sub type {
+	my $self = shift;
+	return NIC::NICType::TYPE_DIRECTORY;
+}
+
+sub _mode {
+	return 0755;
+}
+
+sub create {
+	my $self = shift;
+	mkpath($self->{OWNER}->substituteVariables($self->{NAME}), { mode => $self->mode }) or return 0;
+	return 1;
+}
+
+
+1;
+

+ 36 - 0
CycriptLoader/theos/bin/lib/NIC/NICBase/File.pm

@@ -0,0 +1,36 @@
+package NIC::NICBase::File;
+use strict;
+use warnings;
+use parent qw(NIC::NICType);
+
+sub _take_init {
+	my $self = shift;
+	$self->{DATA} = undef;
+}
+
+sub type {
+	my $self = shift;
+	return NIC::NICType::TYPE_FILE;
+}
+
+sub _mode {
+	return 0644;
+}
+
+sub data {
+	my $self = shift;
+	$self->{DATA} = shift if @_;
+	$self->{DATA};
+}
+
+sub create {
+	my $self = shift;
+	my $filename = $self->{OWNER}->substituteVariables($self->name);
+	open(my $nicfile, ">", $filename) or return 0;
+	print $nicfile $self->{OWNER}->substituteVariables($self->data);
+	close($nicfile);
+	chmod($self->mode, $filename);
+	return 1;
+}
+
+1;

+ 52 - 0
CycriptLoader/theos/bin/lib/NIC/NICBase/Symlink.pm

@@ -0,0 +1,52 @@
+package NIC::NICBase::Symlink;
+use strict;
+use warnings;
+use parent qw(NIC::NICType);
+use Scalar::Util qw(refaddr);
+
+use overload '""' => sub {
+	my $self = shift;
+	my $ref = ref($self);
+	$ref =~ s/^.*::(\w+)$/$1/g;
+	my $target = (ref($self->target) && refaddr($self) == refaddr($self->target)) ? "itself" : "\"".$self->target."\"";
+	return '"'.$self->name."\" ($ref to $target)";
+};
+
+sub _take_init {
+	my $self = shift;
+	$self->{TARGET} = shift // undef;
+}
+
+sub type {
+	my $self = shift;
+	return NIC::NICType::TYPE_SYMLINK;
+}
+
+sub target {
+	my $self = shift;
+	if(@_) { $self->{TARGET} = shift; }
+	return $self->{TARGET};
+}
+
+sub target_type {
+	my $self = shift;
+	my $t = $self->{TARGET};
+	return ref($t) ? $t->type : NIC::NICType::TYPE_UNKNOWN;
+}
+
+sub target_name {
+	my $self = shift;
+	my $t = $self->{TARGET};
+	return ref($t) ? $t->name : $t;
+}
+
+sub create {
+	my $self = shift;
+	my $name = $self->{OWNER}->substituteVariables($self->{NAME});
+	my $dest = $self->{OWNER}->substituteVariables($self->target_name);
+	symlink($dest, $name) or return 0;
+	return 1;
+}
+
+1;
+

+ 79 - 0
CycriptLoader/theos/bin/lib/NIC/NICType.pm

@@ -0,0 +1,79 @@
+package NIC::NICType;
+use strict;
+use warnings;
+
+use constant {
+	TYPE_UNKNOWN => 0,
+	TYPE_DIRECTORY => 1,
+	TYPE_FILE => 2,
+	TYPE_SYMLINK => 3
+};
+
+use overload '""' => sub {
+	my $self = shift;
+	my $ref = ref($self);
+	$ref =~ s/^.*::(\w+)$/$1/g;
+	return '"'.$self->name."\" ($ref, mode ".sprintf("%4.04o", $self->mode).")";
+};
+
+sub new {
+	my $proto = shift;
+	my $class = ref($proto) || $proto;
+	my $self = {};
+	$self->{OWNER} = shift // undef;
+	$self->{NAME} = shift // undef;
+	$self->{MODE} = undef;
+	$self->{CONSTRAINTS} = [];
+	bless($self, $class);
+
+	return $self;
+}
+
+sub _take_init {
+}
+
+sub take {
+	my $proto = shift;
+	my $class = ref($proto) || $proto;
+	my $obj = shift;
+	bless($obj, $class);
+	$obj->_take_init(@_);
+}
+
+sub name {
+	my $self = shift;
+	if(@_) { $self->{NAME} = shift; }
+	return $self->{NAME};
+}
+
+sub _mode {
+	return 0;
+}
+
+sub mode {
+	my $self = shift;
+	if(@_) { $self->{MODE} = shift; }
+	return $self->{MODE} // $self->_mode;
+}
+
+sub type {
+	my $self = shift;
+	return TYPE_UNKNOWN;
+}
+
+sub constraints {
+	my $self = shift;
+	return @{$self->{CONSTRAINTS}};
+}
+
+sub addConstraint {
+	my $self = shift;
+	my $constraint = shift;
+	push(@{$self->{CONSTRAINTS}}, $constraint);
+}
+
+sub create {
+	return 0;
+}
+
+1;

+ 26 - 0
CycriptLoader/theos/bin/lib/NIC/Tie/Method.pm

@@ -0,0 +1,26 @@
+package NIC::Tie::Method;
+use parent qw(Tie::Scalar);
+
+sub TIESCALAR {
+	my $class = shift;
+	my $for = shift;
+	my $method = shift;
+	my $self = { FOR => $for, METHOD => $method };
+	bless($self, $class);
+	return $self;
+}
+
+sub FETCH {
+	my $self = shift;
+	my $obj = $self->{FOR};
+	{ unshift @_, $obj; goto &{$self->{FOR}->can($self->{METHOD})}; }
+}
+
+sub STORE {
+	my $self = shift;
+	my $obj = $self->{FOR};
+	{ unshift @_, $obj; goto &{$self->{FOR}->can($self->{METHOD})}; }
+}
+
+1;
+

+ 34 - 0
CycriptLoader/theos/bin/lib/NIC/Tie/PrefixedHandleRedirect.pm

@@ -0,0 +1,34 @@
+package NIC::Tie::PrefixedHandleRedirect;
+use strict;
+use parent qw(Tie::Handle);
+sub TIEHANDLE {
+	my $proto = shift;
+	my $fh = shift;
+	my $prefix = shift;
+	return bless [$fh, $prefix], $proto;
+}
+
+sub _token {
+	return "[".$_[0]->[1]."] ";
+}
+
+sub PRINT {
+	my $t = $_[0]->_token;
+	my $fh = $_[0]->[0];
+	shift;
+	my $str = $t.join('', @_);
+	$str =~ s#$/+$##g;
+	$str =~ s#$/#$/$t#g;
+	print $fh $str,$/;
+}
+
+sub PRINTF {
+	my $t = $_[0]->_token;
+	my $fh = $_[0]->[0];
+	shift;
+	my $str = $t.sprintf(shift, @_);
+	$str =~ s#$/+$##g;
+	$str =~ s#$/#$/$t#g;
+	print $fh $str,$/;
+}
+1;

+ 326 - 0
CycriptLoader/theos/bin/lib/aliased.pm

@@ -0,0 +1,326 @@
+package aliased;
+no warnings 'deprecated';
+
+our $VERSION = '0.30_01';
+$VERSION = eval $VERSION;
+
+require Exporter;
+@ISA    = qw(Exporter);
+@EXPORT = qw(alias prefix);
+
+use strict;
+
+sub _croak {
+    require Carp;
+    Carp::croak(@_);
+}
+
+sub import {
+    my ( $class, $package, $alias, @import ) = @_;
+
+    if ( @_ <= 1 ) {
+        $class->export_to_level(1);
+        return;
+    }
+
+    my $callpack = caller(0);
+    _load_alias( $package, $callpack, @import );
+    _make_alias( $package, $callpack, $alias );
+}
+
+sub _get_alias {
+    my $package = shift;
+    $package =~ s/.*(?:::|')//;
+    return $package;
+}
+
+sub _make_alias {
+    my ( $package, $callpack, $alias ) = @_;
+
+    $alias ||= _get_alias($package);
+
+    no strict 'refs';
+    *{ join q{::} => $callpack, $alias } = sub () { $package };
+}
+
+sub _load_alias {
+    my ( $package, $callpack, @import ) = @_;
+
+    # We don't localize $SIG{__DIE__} here because we need to be careful about
+    # restoring its value if there is a failure.  Very, very tricky.
+    my $sigdie = $SIG{__DIE__};
+    {
+        my $code =
+          @import == 0
+          ? "package $callpack; use $package;"
+          : "package $callpack; use $package (\@import)";
+        eval $code;
+        if ( my $error = $@ ) {
+            $SIG{__DIE__} = $sigdie;
+            _croak($error);
+        }
+        $sigdie = $SIG{__DIE__}
+          if defined $SIG{__DIE__};
+    }
+
+    # Make sure a global $SIG{__DIE__} makes it out of the localization.
+    $SIG{__DIE__} = $sigdie if defined $sigdie;
+    return $package;
+}
+
+sub alias {
+    my ( $package, @import ) = @_;
+
+    my $callpack = scalar caller(0);
+    return _load_alias( $package, $callpack, @import );
+}
+
+sub prefix {
+    my ($class) = @_;
+    return sub {
+        my ($name) = @_;
+        my $callpack = caller(0);
+        if ( not @_ ) {
+            return _load_alias( $class, $callpack );
+        }
+        elsif ( @_ == 1 && defined $name ) {
+            return _load_alias( "${class}::$name", $callpack );
+        }
+        else {
+            _croak("Too many arguments to prefix('$class')");
+        }
+    };
+}
+
+1;
+__END__
+
+=head1 NAME
+
+aliased - Use shorter versions of class names.
+
+=head1 VERSION
+
+0.30
+
+=head1 SYNOPSIS
+
+  # Class name interface
+  use aliased 'My::Company::Namespace::Customer';
+  my $cust = Customer->new;
+
+  use aliased 'My::Company::Namespace::Preferred::Customer' => 'Preferred';
+  my $pref = Preferred->new;
+
+
+  # Variable interface
+  use aliased;
+  my $Customer  = alias "My::Other::Namespace::Customer";
+  my $cust      = $Customer->new;
+
+  my $Preferred = alias "My::Other::Namespace::Preferred::Customer";
+  my $pref      = $Preferred->new;  
+
+
+=head1 DESCRIPTION
+
+C<aliased> is simple in concept but is a rather handy module.  It loads the
+class you specify and exports into your namespace a subroutine that returns
+the class name.  You can explicitly alias the class to another name or, if you
+prefer, you can do so implicitly.  In the latter case, the name of the
+subroutine is the last part of the class name.  Thus, it does something
+similar to the following:
+
+  #use aliased 'Some::Annoyingly::Long::Module::Name::Customer';
+
+  use Some::Annoyingly::Long::Module::Name::Customer;
+  sub Customer {
+    return 'Some::Annoyingly::Long::Module::Name::Customer';
+  }
+  my $cust = Customer->new;
+
+This module is useful if you prefer a shorter name for a class.  It's also
+handy if a class has been renamed.
+
+(Some may object to the term "aliasing" because we're not aliasing one
+namespace to another, but it's a handy term.  Just keep in mind that this is
+done with a subroutine and not with typeglobs and weird namespace munging.)
+
+Note that this is B<only> for C<use>ing OO modules.  You cannot use this to
+load procedural modules.  See the L<Why OO Only?|Why OO Only?> section.  Also,
+don't let the version number fool you.  This code is ridiculously simple and
+is just fine for most use.
+
+=head2 Implicit Aliasing
+
+The most common use of this module is:
+
+  use aliased 'Some::Module::name';
+
+C<aliased> will  allow you to reference the class by the last part of the
+class name.  Thus, C<Really::Long::Name> becomes C<Name>.  It does this by
+exporting a subroutine into your namespace with the same name as the aliased
+name.  This subroutine returns the original class name.
+
+For example:
+
+  use aliased "Acme::Company::Customer";
+  my $cust = Customer->find($id);
+
+Note that any class method can be called on the shorter version of the class
+name, not just the constructor.
+
+=head2 Explicit Aliasing
+
+Sometimes two class names can cause a conflict (they both end with C<Customer>
+for example), or you already have a subroutine with the same name as the
+aliased name.  In that case, you can make an explicit alias by stating the
+name you wish to alias to:
+
+  use aliased 'Original::Module::Name' => 'NewName';
+
+Here's how we use C<aliased> to avoid conflicts:
+
+  use aliased "Really::Long::Name";
+  use aliased "Another::Really::Long::Name" => "Aname";
+  my $name  = Name->new;
+  my $aname = Aname->new;
+
+You can even alias to a different package:
+
+  use aliased "Another::Really::Long::Name" => "Another::Name";
+  my $aname = Another::Name->new;
+
+Messing around with different namespaces is a really bad idea and you probably
+don't want to do this.  However, it might prove handy if the module you are
+using has been renamed.  If the interface has not changed, this allows you to
+use the new module by only changing one line of code.
+
+  use aliased "New::Module::Name" => "Old::Module::Name";
+  my $thing = Old::Module::Name->new;
+
+=head2 Import Lists
+
+Sometimes, even with an OO module, you need to specify extra arguments when
+using the module.  When this happens, simply use L<Explicit Aliasing> followed
+by the import list:
+
+Snippet 1:
+
+  use Some::Module::Name qw/foo bar/;
+  my $o = Some::Module::Name->some_class_method; 
+
+Snippet 2 (equivalent to snippet 1):
+
+  use aliased 'Some::Module::Name' => 'Name', qw/foo bar/;
+  my $o = Name->some_class_method;
+
+B<Note>:  remember, you cannot use import lists with L<Implicit Aliasing>.  As
+a result, you may simply prefer to only use L<Explicit Aliasing> as a matter
+of style.
+
+=head2 alias()
+
+This function is only exported if you specify C<use aliased> with no import
+list.
+
+    use aliased;
+    my $alias = alias($class);
+    my $alias = alias($class, @imports);
+
+alias() is an alternative to C<use aliased ...> which uses less magic and
+avoids some of the ambiguities.
+
+Like C<use aliased> it C<use>s the $class (pass in @imports, if given) but
+instead of providing an C<Alias> constant it simply returns a scalar set to
+the $class name.
+
+    my $thing = alias("Some::Thing::With::A::Long::Name");
+
+    # Just like Some::Thing::With::A::Long::Name->method
+    $thing->method;
+
+The use of a scalar instead of a constant avoids any possible ambiguity
+when aliasing two similar names:
+
+    # No ambiguity despite the fact that they both end with "Name"
+    my $thing = alias("Some::Thing::With::A::Long::Name");
+    my $other = alias("Some::Other::Thing::With::A::Long::Name");
+
+and there is no magic constant exported into your namespace.
+
+The only caveat is loading of the $class happens at run time.  If $class
+exports anything you might want to ensure it is loaded at compile time with:
+
+    my $thing;
+    BEGIN { $thing = alias("Some::Thing"); }
+
+However, since OO classes rarely export this should not be necessary.
+
+=head2 prefix() (experimental)
+
+This function is only exported if you specify C<use aliased> with no import
+list.
+
+    use aliased;
+
+Sometimes you find you have a ton of packages in the same top-level namespace
+and you want to alias them, but only use them on demand.  For example:
+
+    # instead of:
+    MailVerwaltung::Client::Exception::REST::Response->throw()
+
+    my $error = prefix('MailVerwaltung::Client::Exception');
+    $error->('REST::Response')->throw();   # same as above
+    $error->()->throw; # same as MailVerwaltung::Client::Exception->throw
+
+=head2 Why OO Only?
+
+Some people have asked why this code only support object-oriented modules
+(OO).  If I were to support normal subroutines, I would have to allow the
+following syntax:
+
+  use aliased 'Some::Really::Long::Module::Name';
+  my $data = Name::data();
+
+That causes a serious problem.  The only (reasonable) way it can be done is to
+handle the aliasing via typeglobs.  Thus, instead of a subroutine that
+provides the class name, we alias one package to another (as the
+L<namespace|namespace> module does.)  However, we really don't want to simply
+alias one package to another and wipe out namespaces willy-nilly.  By merely
+exporting a single subroutine to a namespace, we minimize the issue. 
+
+Fortunately, this doesn't seem to be that much of a problem.  Non-OO modules
+generally support exporting of the functions you need and this eliminates the
+need for a module such as this.
+
+=head1 EXPORT
+
+This modules exports a subroutine with the same name as the "aliased" name.
+
+=head1 BUGS
+
+There are no known bugs in this module, but feel free to email me reports.
+
+=head1 SEE ALSO
+
+The L<namespace> module.
+
+=head1 THANKS
+
+Many thanks to Rentrak, Inc. (http://www.rentrak.com/) for graciously allowing
+me to replicate the functionality of some of their internal code.
+
+=head1 AUTHOR
+
+Curtis Poe, C<< ovid [at] cpan [dot] org >>
+
+=head1 COPYRIGHT AND LICENSE
+
+Copyright (C) 2005 by Curtis "Ovid" Poe
+
+This library is free software; you can redistribute it and/or modify
+it under the same terms as Perl itself, either Perl version 5.8.5 or,
+at your option, any later version of Perl 5 you may have available.
+
+=cut

+ 136 - 0
CycriptLoader/theos/bin/lib/parent.pm

@@ -0,0 +1,136 @@
+package parent;
+use strict;
+use vars qw($VERSION);
+$VERSION = '0.225';
+
+sub import {
+    my $class = shift;
+
+    my $inheritor = caller(0);
+
+    if ( @_ and $_[0] eq '-norequire' ) {
+        shift @_;
+    } else {
+        for ( my @filename = @_ ) {
+            if ( $_ eq $inheritor ) {
+                warn "Class '$inheritor' tried to inherit from itself\n";
+            };
+
+            s{::|'}{/}g;
+            require "$_.pm"; # dies if the file is not found
+        }
+    }
+
+    {
+        no strict 'refs';
+        push @{"$inheritor\::ISA"}, @_;
+    };
+};
+
+"All your base are belong to us"
+
+__END__
+
+=encoding utf8
+
+=head1 NAME
+
+parent - Establish an ISA relationship with base classes at compile time
+
+=head1 SYNOPSIS
+
+    package Baz;
+    use parent qw(Foo Bar);
+
+=head1 DESCRIPTION
+
+Allows you to both load one or more modules, while setting up inheritance from
+those modules at the same time.  Mostly similar in effect to
+
+    package Baz;
+    BEGIN {
+        require Foo;
+        require Bar;
+        push @ISA, qw(Foo Bar);
+    }
+
+By default, every base class needs to live in a file of its own.
+If you want to have a subclass and its parent class in the same file, you
+can tell C<parent> not to load any modules by using the C<-norequire> switch:
+
+  package Foo;
+  sub exclaim { "I CAN HAS PERL" }
+
+  package DoesNotLoadFooBar;
+  use parent -norequire, 'Foo', 'Bar';
+  # will not go looking for Foo.pm or Bar.pm
+
+This is equivalent to the following code:
+
+  package Foo;
+  sub exclaim { "I CAN HAS PERL" }
+
+  package DoesNotLoadFooBar;
+  push @DoesNotLoadFooBar::ISA, 'Foo', 'Bar';
+
+This is also helpful for the case where a package lives within
+a differently named file:
+
+  package MyHash;
+  use Tie::Hash;
+  use parent -norequire, 'Tie::StdHash';
+
+This is equivalent to the following code:
+
+  package MyHash;
+  require Tie::Hash;
+  push @ISA, 'Tie::StdHash';
+
+If you want to load a subclass from a file that C<require> would
+not consider an eligible filename (that is, it does not end in
+either C<.pm> or C<.pmc>), use the following code:
+
+  package MySecondPlugin;
+  require './plugins/custom.plugin'; # contains Plugin::Custom
+  use parent -norequire, 'Plugin::Custom';
+
+=head1 DIAGNOSTICS
+
+=over 4
+
+=item Class 'Foo' tried to inherit from itself
+
+Attempting to inherit from yourself generates a warning.
+
+    package Foo;
+    use parent 'Foo';
+
+=back
+
+=head1 HISTORY
+
+This module was forked from L<base> to remove the cruft
+that had accumulated in it.
+
+=head1 CAVEATS
+
+=head1 SEE ALSO
+
+L<base>
+
+=head1 AUTHORS AND CONTRIBUTORS
+
+Rafaël Garcia-Suarez, Bart Lateur, Max Maischein, Anno Siegel, Michael Schwern
+
+=head1 MAINTAINER
+
+Max Maischein C< corion@cpan.org >
+
+Copyright (c) 2007-10 Max Maischein C<< <corion@cpan.org> >>
+Based on the idea of C<base.pm>, which was introduced with Perl 5.004_04.
+
+=head1 LICENSE
+
+This module is released under the same terms as Perl itself.
+
+=cut

+ 63 - 0
CycriptLoader/theos/bin/logify.pl

@@ -0,0 +1,63 @@
+#!/usr/bin/env perl
+# logify.pl
+############
+# Converts an Objective-C header file (or anything containing a @interface and method definitions)
+#+into a Logos input file which causes all function calls to be logged.
+#
+# Accepts input on stdin or via filename specified on the commandline.
+
+# Lines are only processed if we were in an @interface, so you can run this on a file containing
+# an @implementation, as well.
+use strict;
+
+use FindBin;
+use lib "$FindBin::Bin/lib";
+
+use Logos::Method;
+use Logos::Util;
+$Logos::Util::errorhandler = sub {
+	die "$ARGV:$.: error: missing closing parenthesis$/"
+};
+
+my $interface = 0;
+while(my $line = <>) {
+	if($line =~ m/^[+-]\s*\((.*?)\).*?(?=;)/ && $interface == 1) {
+		print logLineForDeclaration($&);
+	} elsif($line =~ m/^\s*\@property\s*\((.*?)\)\s*(.*?)\b([\$a-zA-Z_][\$_a-zA-Z0-9]*)(?=;)/ && $interface == 1) {
+		my @attributes = smartSplit(qr/\s*,\s*/, $1);
+		my $propertyName = $3;
+		my $type = $2;
+		my $readonly = scalar(grep(/readonly/, @attributes));
+		my %methods = ("setter" => "set".ucfirst($propertyName).":", "getter" => $propertyName);
+		foreach my $attribute (@attributes) {
+			next if($attribute !~ /=/);
+			my @x = smartSplit(qr/\s*=\s*/, $attribute);
+			$methods{$x[0]} = $x[1];
+		}
+		if($readonly == 0) {
+			print logLineForDeclaration("- (void)".$methods{"setter"}."($type)$propertyName");
+		}
+		print logLineForDeclaration("- ($type)".$methods{"getter"});
+	} elsif($line =~ m/^\@interface\s+(.*?)\s*[:(]/ && $interface == 0) {
+		print "%hook $1\n";
+		$interface = 1;
+	} elsif($line =~ m/^\@end/ && $interface == 1) {
+		print "%end\n";
+		$interface = 0;
+	}
+}
+
+sub logLineForDeclaration {
+	my $declaration = shift;
+	$declaration =~ m/^[+-]\s*\((.*?)\).*?/;
+	my $rtype = $1;
+	my $innards = "%log; ";
+	if($rtype ne "void") {
+		$innards .= "$rtype r = %orig; ";
+		$innards .= "HBLogDebug(@\" = ".Logos::Method::formatCharForArgType($rtype)."\", ".Logos::Method::printArgForArgType($rtype, "r")."); " if defined Logos::Method::printArgForArgType($rtype, "r");
+		$innards .= "return r; ";
+	} else {
+		$innards .= "%orig; ";
+	}
+	return "$declaration { $innards}\n";
+}

+ 967 - 0
CycriptLoader/theos/bin/logos.pl

@@ -0,0 +1,967 @@
+#!/usr/bin/perl
+
+use 5.006;
+use warnings;
+use strict;
+use FindBin;
+use lib "$FindBin::Bin/lib";
+use Digest::MD5 'md5_hex';
+use Module::Load;
+use Module::Load::Conditional 'can_load';
+use Getopt::Long;
+
+package Logos;
+sub sigil { my $id = shift; return "_logos_$id\$"; }
+package main;
+
+use Logos::Util;
+$Logos::Util::errorhandler = \&utilErrorHandler;
+
+use aliased 'Logos::Patch';
+use aliased 'Logos::Patch::Source::Generator' => 'Patch::Source::Generator';
+use aliased 'Logos::Patch';
+use aliased 'Logos::Group';
+use aliased 'Logos::Method';
+use aliased 'Logos::Class';
+use aliased 'Logos::Subclass';
+use aliased 'Logos::StaticClassGroup' ;
+use aliased 'Logos::Property';
+use aliased 'Logos::Function';
+
+use Logos::Generator;
+
+%main::CONFIG = ( generator => "MobileSubstrate",
+		  warnings => "default",
+		);
+$main::warnings = 0;
+
+GetOptions("config|c=s" => \%main::CONFIG);
+
+my $filename = $ARGV[0];
+die "Syntax: $FindBin::Script filename\n" if !$filename;
+open(FILE, $filename) or die "Could not open $filename.\n";
+
+my @lines = ();
+my @patches = ();
+my $preprocessed = 0;
+
+my %lineMapping = ();
+
+{ # If the first line matches "# \d \"...\"", this file has been run through the preprocessor already.
+my $firstline = <FILE>;
+seek(FILE, 0, Fcntl::SEEK_SET);
+if($firstline && $firstline =~ /^# \d+ \"(.*?)\"$/) {
+	$preprocessed = 1;
+	$filename = $1;
+}
+$.--; # Reset line number.
+}
+
+{
+my $readignore = 0;
+my $built = "";
+my $building = 0;
+my $iflevel = -1;
+READLOOP: while(my $line = <FILE>) {
+	chomp($line);
+
+	if($preprocessed && $line =~ /^# (\d+) \"(.*?)\"/) {
+		$lineMapping{$.+1} = [$2, $1];
+	}
+
+	if($readignore) {
+		# Handle #if nesting.
+		if($iflevel > -1 && $line =~ /^#\s*if(n?def)?/) {
+			$iflevel++;
+		} elsif($iflevel > 0 && $line =~ /^#\s*endif/) {
+			$line = $';
+			$iflevel--;
+		}
+
+		# End of a multi-line comment or #if block while ignoring input.
+		if($iflevel == 0 || ($iflevel == -1 && $line =~ /^.*?\*\/\s*/)) {
+			$readignore = 0;
+			$iflevel = -1;
+			$line = $';
+		}
+	}
+	if($readignore) { push(@lines, ""); next; }
+
+	my @quotes = quotes($line);
+
+	# Delete all single-line /* xxx */ comments.
+	while($line =~ /\/\*.*?\*\//g) {
+		next if fallsBetween($-[0], @quotes);
+		$line = $`.$';
+		redo READLOOP;
+	}
+
+	# Start of a multi-line /* comment.
+	while($line =~ /\/\*.*$/g) {
+		next if fallsBetween($-[0], @quotes);
+		$line = $`;
+		push(@lines, $line);
+		$readignore = 1;
+		next READLOOP;
+	}
+
+	# Delete all single-line to-EOL // xxx comments.
+	while($line =~ /\/\//g) {
+		next if fallsBetween($-[0], @quotes);
+		$line = $`;
+		redo READLOOP;
+	}
+
+	# #if 0.
+	while($line =~ /^\s*#\s*if\s+0/) {
+		$iflevel = 1;
+		push(@lines, "");
+		$readignore = 1;
+		next READLOOP;
+	}
+
+	if(!$readignore) {
+		# Line starts with - (return), start gluing lines together until we find a { or ;...
+		if(!$building
+				&& (
+					$line =~ /^\s*(%new.*?)?\s*([+-])\s*\(\s*(.*?)\s*\)/
+					|| $line =~ /%orig[^;]*$/
+					|| $line =~ /%init[^;]*$/
+				)
+				&& index($line, "{") < $-[0] && index($line, ";") < $-[0]) {
+			if(fallsBetween($-[0], @quotes)) {
+				push(@lines, $line);
+				next;
+			}
+			$building = 1;
+			$built = $line;
+			push(@lines, "");
+			next;
+		} elsif($building) {
+			$line =~ s/^\s+//g;
+			$built .= " ".$line;
+			if(index($line,"{") != -1 || index($line,";") != -1) {
+				push(@lines, $built);
+				$building = 0;
+				$built = "";
+				next;
+			}
+			push(@lines, "");
+			next;
+		}
+		push(@lines, $line) if !$readignore;
+	}
+}
+if($building == 1) {
+	push(@lines, $built);
+}
+}
+
+close(FILE);
+
+$lineMapping{0} = ["$filename", 0] if scalar keys %lineMapping == 0;
+
+my $lineno = 0;
+
+my $defaultGroup = Group->new();
+$defaultGroup->name("_ungrouped");
+$defaultGroup->explicit(0);
+my $staticClassGroup = StaticClassGroup->new();
+my @groups = ($defaultGroup);
+
+my $currentGroup = $defaultGroup;
+my $currentClass = undef;
+my $currentMethod = undef;
+my $newMethodTypeEncoding = undef;
+my $currentFunction = undef;
+
+my %classes = ();
+
+my @nestingstack = ();
+
+my @firstDirectivePosition;
+my @lastInitPosition;
+
+my %depthMapping = ("0:0" => 0);
+my $depth = 0;
+
+# Mk. I processing loop - directive processing.
+foreach my $line (@lines) {
+	# We don't want to process in-order, so %group %thing %end won't kill itself automatically
+	# because it found a %end with the %group. This allows things to proceed out-of-order:
+	# we re-start the scan loop with the next % every time we find a match so that the commands don't need to
+	# be in the processed order on every line. That would be pointless.
+
+	my @quotes = quotes($line);
+
+	# Brace Depth Mapping
+	pos($line) = 0;
+	my %depthsForCurrentLine;
+	$depthsForCurrentLine{"$lineno:0"} = $depth;
+	while($line =~ /([{}]|(?<=@)(interface|implementation|protocol|end))/g) {
+		next if fallsBetween($-[0], @quotes);
+
+		my $depthtoken = $lineno.":".($-[0]+1);
+
+		$depth++ if($& eq "{");
+		$depth++ if($& eq "implementation");
+		$depth++ if($& eq "interface");
+		# @protocol, but not "@protocol X;" or "@protocol("
+		$depth++ if($& eq "protocol" && substr($line, $-[0]) !~ /^protocol(\s+([_\$A-Za-z0-9]+(,\s*)?)+;|\s*\()/);
+		$depth-- if($& eq "}");
+		$depth-- if($& eq "end");
+		fileError($lineno, "fell off the face of the planet when we found a \'$&\'") if $depth < 0;
+		$depthMapping{$depthtoken} = $depth;
+		$depthsForCurrentLine{$depthtoken} = $depth;
+	}
+
+	# Directive
+	pos($line) = 0;
+	while($line =~ m/\B(?=(\%\w|&\s*\%\w|[+-]\s*\(\s*.*?\s*\)))/gc) {
+		next if fallsBetween($-[0], @quotes);
+
+		my @directiveDepthTokens = locationOpeningDepthAtPositionInMapping(\%depthsForCurrentLine, $lineno, $-[0]);
+		my $directiveDepth;
+		$directiveDepth = 0 if(!@directiveDepthTokens);
+		$directiveDepth = $depthsForCurrentLine{join(':', @directiveDepthTokens)} if @directiveDepthTokens;
+
+		if($line =~ /\G%hook\s+([\$_\w]+)/gc) {
+			# "%hook <identifier>"
+			fileError($lineno, "%hook does not make sense inside a block") if($directiveDepth >= 1);
+			nestingMustNotContain($lineno, "%hook", \@nestingstack, "hook", "subclass");
+
+			@firstDirectivePosition = ($lineno, $-[0]) if !@firstDirectivePosition;
+
+			nestPush("hook", $lineno, \@nestingstack);
+
+			$currentClass = $currentGroup->addClassNamed($1);
+			$classes{$currentClass->name}++;
+			patchHere(undef);
+		} elsif($line =~ /\G%subclass\s+([\$_\w]+)\s*:\s*([\$_\w]+)\s*(\<\s*(.*?)\s*\>)?/gc) {
+			# %subclass <identifier> : <identifier> \<<protocols ...>\>
+			fileError($lineno, "%subclass does not make sense inside a block") if($directiveDepth >= 1);
+			nestingMustNotContain($lineno, "%subclass", \@nestingstack, "hook", "subclass");
+
+			@firstDirectivePosition = ($lineno, $-[0]) if !@firstDirectivePosition;
+
+			nestPush("subclass", $lineno, \@nestingstack);
+
+			my $classname = $1;
+			my $superclassname = $2;
+			my $superclass = $currentGroup->addClassNamed($superclassname);
+			$superclass->required(1);
+			$currentClass = Subclass->new();
+			$currentClass->name($classname);
+			$currentClass->superclass($superclass);
+			if(defined($3) && defined($4)) {
+				my @protocols = split(/\s*,\s*/, $4);
+				foreach(@protocols) {
+					$currentClass->addProtocol($_);
+				}
+			}
+			$currentGroup->addClass($currentClass);
+
+			$staticClassGroup->addDeclaredOnlyClass($classname);
+			$classes{$superclassname}++;
+			$classes{$classname}++;
+
+			patchHere(undef);
+		} elsif($line =~ /\G%group\s+([\$_\w]+)/gc) {
+			# %group <identifier>
+			fileError($lineno, "%group does not make sense inside a block") if($directiveDepth >= 1);
+			nestingMustNotContain($lineno, "%group", \@nestingstack, "group");
+
+			@firstDirectivePosition = ($lineno, $-[0]) if !@firstDirectivePosition;
+
+			nestPush("group", $lineno, \@nestingstack);
+
+			$currentGroup = getGroup($1);
+			my $patchSource = undef;
+			if(!defined($currentGroup)) {
+				$currentGroup = Group->new();
+				$currentGroup->name($1);
+				push(@groups, $currentGroup);
+				my $capturedGroup = $currentGroup;
+				$patchSource = Patch::Source::Generator->new($capturedGroup, 'declarations');
+			}
+			patchHere($patchSource);
+		} elsif($line =~ /\G%class\s+([+-])?([\$_\w]+)/gc) {
+			# %class [+-]<identifier>
+			@firstDirectivePosition = ($lineno, $-[0]) if !@firstDirectivePosition;
+
+			fileWarning($lineno, "%class is deprecated and will be removed in the future; consider switching to inline %c()");
+
+			my $scope = $1;
+			$scope = "-" if !$scope;
+			my $classname = $2;
+			if($scope eq "+") {
+				$staticClassGroup->addUsedMetaClass($classname);
+			} else {
+				$staticClassGroup->addUsedClass($classname);
+			}
+			$classes{$classname}++;
+			patchHere(undef);
+		} elsif($line =~ /\G%c\(\s*([+-])?([\$_\w]+)\s*\)/gc) {
+			# %c([+-]<identifier>)
+			@firstDirectivePosition = ($lineno, $-[0]) if !@firstDirectivePosition;
+
+			my $scope = $1;
+			$scope = "-" if !$scope;
+			my $classname = $2;
+			if($scope eq "+") {
+				$staticClassGroup->addUsedMetaClass($classname);
+			} else {
+				$staticClassGroup->addUsedClass($classname);
+			}
+			$classes{$classname}++;
+			patchHere(Patch::Source::Generator->new($classname, 'classReferenceWithScope', $scope));
+		} elsif($line =~ /\G%new(\((.*?)\))?(?=\W?)/gc) {
+			# %new[(type)]
+			nestingMustContain($lineno, "%new", \@nestingstack, "hook", "subclass");
+			my $xtype = "";
+			$xtype = $2 if $2;
+			$newMethodTypeEncoding = $xtype;
+			patchHere(undef);
+		} elsif($currentClass && $line =~ /\G([+-])\s*\(\s*(.*?)\s*\)(?=\s*[\$\w:])/gc && $directiveDepth < 1) {
+			# [+-] (<return>)<[X:]>, but only when we're in a %hook.
+
+			# Gasp! We've been moved to a different group!
+			if($currentClass->group != $currentGroup) {
+				my $classname = $currentClass->name;
+				$currentClass = $currentGroup->addClassNamed($classname);
+			}
+
+			my $scope = $1;
+			my $return = $2;
+
+			my $method = Method->new();
+
+			$method->class($currentClass);
+			if($scope eq "+") {
+				$currentClass->hasmetahooks(1);
+			} else {
+				$currentClass->hasinstancehooks(1);
+			}
+
+			$method->scope($scope);
+			$method->return($return);
+
+			if(defined $newMethodTypeEncoding) {
+				$method->setNew(1);
+				$method->type($newMethodTypeEncoding);
+				$newMethodTypeEncoding = undef;
+			}
+
+			my @selparts = ();
+
+			my $patchStart = $-[0];
+
+			# word, then an optional: ": (argtype)argname"
+			while($line =~ /\G\s*([\$\w]*)(\s*:\s*(\((.+?)\))?\s*([\$\w]+?)\b)?/gc) {
+				if(!$1 && !$2) { # Exit the loop if both Keywords and Args are missing: e.g. false positive.
+					pos($line) = $-[0];
+					last;
+				}
+
+				my $keyword = $1; # Add any keyword.
+				push(@selparts, $keyword);
+
+				last if !$2;  # Exit the loop if there are no args (single keyword.)
+				$method->addArgument($3 ? $4 : "id", $5);
+			}
+
+			$method->selectorParts(@selparts);
+			$currentClass->addMethod($method);
+			$currentMethod = $method;
+
+			my $patch = Patch->new();
+			$patch->line($lineno);
+			$patch->range($patchStart, pos($line));
+			$patch->source(Patch::Source::Generator->new($method, 'definition'));
+			addPatch($patch);
+		} elsif($line =~ /\G%orig\b/gc) {
+			# %orig, with optional following parens.
+			if (!defined $currentClass) {
+				fileError($lineno, "%orig does not make sense outside a function") if(!defined($currentFunction));
+				my $patchStart = $-[0];
+
+				my $remaining = substr($line, pos($line));
+				my $orig_args = undef;
+
+				my ($popen, $pclose) = matchedParenthesisSet($remaining);
+				if(defined $popen) {
+					$orig_args = substr($remaining, $popen, $pclose-$popen-1);;
+					pos($line) = pos($line) + $pclose;
+				}
+
+				my $patch = Patch->new();
+				$patch->line($lineno);
+				$patch->range($patchStart, pos($line));
+				$patch->source(Patch::Source::Generator->new($currentFunction, 'originalFunctionCall', $orig_args));
+				addPatch($patch);
+			} else {
+				nestingMustContain($lineno, "%orig", \@nestingstack, "hook", "subclass");
+				fileError($lineno, "%orig does not make sense outside a method") if(!defined($currentMethod));
+				fileError($lineno, "%orig does not make sense outside a block") if($directiveDepth < 1);
+				fileWarning($lineno, "%orig in new method ".prettyPrintMethod($currentMethod)." will be non-operative.") if $currentMethod->isNew;
+
+				my $patchStart = $-[0];
+
+				my $remaining = substr($line, pos($line));
+				my $orig_args = undef;
+
+				my ($popen, $pclose) = matchedParenthesisSet($remaining);
+				if(defined $popen) {
+					$orig_args = substr($remaining, $popen, $pclose-$popen-1);;
+					pos($line) = pos($line) + $pclose;
+				}
+
+				my $capturedMethod = $currentMethod;
+				my $patch = Patch->new();
+				$patch->line($lineno);
+				$patch->range($patchStart, pos($line));
+				$patch->source(Patch::Source::Generator->new($capturedMethod, 'originalCall', $orig_args));
+				addPatch($patch);
+			}
+		} elsif($line =~ /\G&\s*%orig\b/gc) {
+			# &%orig, at a word boundary
+			if (!defined $currentClass) {
+				fileError($lineno, "%orig does not make sense outside a function") if(!defined($currentFunction));
+				my $patchStart = $-[0];
+				my $patchEnd = $patchStart + 6;
+				my $patch = Patch->new();
+				$patch->line($lineno);
+				$patch->range($patchStart, $patchEnd);
+				$patch->source(Patch::Source::Generator->new($currentFunction, 'originalFunctionName'));
+				addPatch($patch);
+			} else {
+				nestingMustContain($lineno, "%orig", \@nestingstack, "hook", "subclass");
+				fileError($lineno, "%orig does not make sense outside a method") if(!defined($currentMethod));
+				fileError($lineno, "%orig does not make sense outside a block") if($directiveDepth < 1);
+				fileError($lineno, "no original method pointer for &%orig in new method ".prettyPrintMethod($currentMethod).".") if $currentMethod->isNew;
+
+				my $capturedMethod = $currentMethod;
+				patchHere(Patch::Source::Generator->new($capturedMethod, 'originalFunctionName'));
+			}
+		} elsif($line =~ /\G%log\b/gc) {
+			# %log
+			nestingMustContain($lineno, "%log", \@nestingstack, "hook", "subclass");
+
+			my $patchStart = $-[0];
+
+			my $remaining = substr($line, pos($line));
+			my $log_args = undef;
+
+			my ($popen, $pclose) = matchedParenthesisSet($remaining);
+			if(defined $popen) {
+				$log_args = substr($remaining, $popen, $pclose-$popen-1);
+				pos($line) = pos($line) + $pclose;
+			}
+
+			my $capturedMethod = $currentMethod;
+			my $patch = Patch->new();
+			$patch->line($lineno);
+			$patch->range($patchStart, pos($line));
+			$patch->source(Patch::Source::Generator->new($capturedMethod, 'buildLogCall', $log_args));
+			addPatch($patch);
+		} elsif($line =~ /\G%ctor\b/gc) {
+			# %ctor
+			fileError($lineno, "%ctor does not make sense inside a block") if($directiveDepth >= 1);
+			nestingMustNotContain($lineno, "%ctor", \@nestingstack, "hook", "subclass");
+			my $replacement = "static __attribute__((constructor)) void _logosLocalCtor_".substr(md5_hex($`.$lineno.$'), 0, 8)."(int argc, char **argv, char **envp)";
+			patchHere($replacement);
+		} elsif($line =~ /\G%dtor\b/gc) {
+			# %dtor
+			fileError($lineno, "%dtor does not make sense inside a block") if($directiveDepth >= 1);
+			nestingMustNotContain($lineno, "%dtor", \@nestingstack, "hook", "subclass");
+			my $replacement = "static __attribute__((destructor)) void _logosLocalDtor_".substr(md5_hex($`.$lineno.$'), 0, 8)."(int argc, char **argv, char **envp)";
+			patchHere($replacement);
+		} elsif($line =~ /\G%init\b/gc) {
+			# %init, with optional following parens
+			fileError($lineno, "%init does not make sense outside a block") if($directiveDepth < 1);
+			my $groupname = "_ungrouped";
+
+			my $patchStart = $-[0];
+
+			my $remaining = substr($line, pos($line));
+			my $argstring = undef;
+			my ($popen, $pclose) = matchedParenthesisSet($remaining);
+			if(defined $popen) {
+				$argstring = substr($remaining, $popen, $pclose-$popen-1);;
+				pos($line) = pos($line) + $pclose;
+			}
+
+			my @args;
+			@args = smartSplit(qr/\s*,\s*/, $argstring) if defined($argstring);
+
+			my $tempgroupname = undef;
+			$tempgroupname = $args[0] if $args[0] && $args[0] !~ /=/;
+			if(defined($tempgroupname)) {
+				$groupname = $tempgroupname;
+				shift(@args);
+			}
+
+			my $group = getGroup($groupname);
+
+			fileError($lineno, "%init for an undefined %group $groupname") if !$group;
+			fileError($lineno, "re-%init of %group ".$group->name.", first initialized at ".lineDescriptionForPhysicalLine($group->initLine)) if $group->initialized;
+
+			foreach my $arg (@args) {
+				if($arg !~ /=/) {
+					fileWarning($lineno, "unknown argument to %init: $arg");
+					next;
+				}
+
+				my @parts = smartSplit(qr/\s*=\s*/, $arg, 2);
+				if(!defined($parts[0]) || !defined($parts[1])) {
+					fileWarning($lineno, "invalid class=expr in %init");
+					next;
+				}
+
+				my $classname = $parts[0];
+				my $expr = $parts[1];
+				my $scope = "-";
+				if($classname =~ /^([+-])/) {
+					$scope = $1;
+					$classname = $';
+				}
+
+				my $class = $group->getClassNamed($classname);
+				if(!defined($class)) {
+					fileWarning($lineno, "tried to set expression for unknown class $classname in group $groupname");
+					next;
+				}
+
+				$class->expression($expr) if $scope eq "-";
+				$class->metaexpression($expr) if $scope eq "+";
+			}
+
+			$group->initLine($lineno);
+			$group->initialized(1);
+
+			while($line =~ /\G\s*;/gc) { };
+			my $patchEnd = pos($line);
+
+			my $patch = Patch->new();
+			$patch->line($lineno);
+			$patch->range($patchStart, pos($line));
+			$patch->source(Patch::Source::Generator->new($group, 'initializers'));
+			addPatch($patch);
+
+			@lastInitPosition = ($lineno, pos($line));
+		} elsif($line =~ /\G%end\b/gc) {
+			# %end
+			fileError($lineno, "%end does not make sense inside a block") if($directiveDepth >= 1);
+			my $closing = nestPop(\@nestingstack);
+			fileError($lineno, "dangling %end") if !$closing;
+			if($closing eq "group") {
+				$currentGroup = getGroup("_ungrouped");
+			}
+			if($closing eq "hook" || $closing eq "subclass") {
+				$currentClass = undef;
+			}
+			patchHere(undef);
+		} elsif($line =~ /\G%config\s*\(\s*(\w+)\s*=\s*(.*?)\s*\)/gc) {
+			$main::CONFIG{$1} = $2;
+			patchHere(undef);
+		} elsif($line =~ /\G%property\s*(?:\((\s*\w+\s*(?:,\s*(?:\w|\=|:)+\s*)*)\))?\s*((?:\w+\s+\**)+)(\w+)\s*;/gc){
+			nestingMustContain($lineno, "%property", \@nestingstack, "hook", "subclass");
+
+			# check property attribute validity
+			my @attributes = split/\(?\s*,\s*\)?/, $1;
+			my ($assign, $retain, $copy, $nonatomic, $getter, $setter);
+			my $numattr = 0;
+
+			foreach(@attributes){
+				$numattr++;
+
+				if($_ =~ /assign/){
+					$assign = 1;
+				}elsif($_ =~ /retain/){
+					$retain = 1;
+				}elsif($_ =~ /copy/){
+					$copy = 1;
+				}elsif($_ =~ /nonatomic/){
+					$nonatomic = 1;
+				}elsif($_ =~ /getter=(\w+)/){
+					$getter = $1;
+				}elsif($_ =~ /setter=(\w+:)/){
+					$setter = $1;
+				}elsif($_ =~ /readwrite|readonly/){
+					fileError($lineno, "property attribute '".$_."' not supported.");
+				}else{
+					fileError($lineno, "unknown property attribute '".$_."'.");
+				}
+			}
+
+			if(!$assign && !$retain && !$copy){
+				fileWarning($lineno, "no 'assign', 'retain', or 'copy' attribute is specified - 'assign' is assumed");
+				push(@attributes, "assign");
+				$numattr++;
+			}
+
+			if($assign && $retain){
+				fileError($lineno, "property attributes 'assign' and 'retain' are mutually exclusive.");
+			}
+
+			if($assign && $copy){
+				fileError($lineno, "property attributes 'assign' and 'copy' are mutually exclusive.");
+			}
+
+			if($copy && $retain){
+				fileError($lineno, "property attributes 'copy' and 'retain' are mutually exclusive.");
+			}
+
+			my $property = Property->new();
+
+
+			$property->class($currentClass->name);
+
+			if($currentGroup){
+				$property->group($currentGroup->name);
+			}else{
+				$property->group("_ungrouped");
+			}
+
+			$property->numattr($numattr);
+			$property->attributes(@attributes);
+			$property->type($2);
+			$property->name($3);
+
+			$currentClass->addProperty($property);
+
+			my $patchStart = $-[0];
+			my $patch = Patch->new();
+			$patch->line($lineno);
+			$patch->range($patchStart, pos($line));
+			$patch->source(Patch::Source::Generator->new($property, 'getters_setters'));
+			addPatch($patch);
+		} elsif($line =~ /\G%hookf\b/gc) {
+			#%hookf
+			fileError($lineno, "%hookf does not make sense inside a block") if($directiveDepth >= 1);
+			nestingMustNotContain($lineno, "%hookf", \@nestingstack, "hook", "subclass");
+
+			@firstDirectivePosition = ($lineno, $-[0]) if !@firstDirectivePosition;
+
+			my $patchStart = $-[0];
+
+			my $remaining = substr($line, pos($line));
+			my $argumentString = undef;
+			my $args = [];
+
+			my ($popen, $pclose) = matchedParenthesisSet($remaining);
+			if(defined $popen) {
+				$argumentString = substr($remaining, $popen, $pclose-$popen-1);
+				pos($line) = pos($line) + $pclose;
+				@$args = Logos::Util::smartSplit(qr/\s*,\s*/, $argumentString);
+			}
+
+			$currentFunction = $currentGroup->addFunction($args);
+
+			my $patch = Patch->new();
+			$patch->line($lineno);
+			$patch->range($patchStart, pos($line));
+			$patch->source(Patch::Source::Generator->new($currentFunction, 'declaration'));
+			addPatch($patch);
+		}
+	}
+
+	$lineno++;
+}
+
+while(scalar(@nestingstack) > 0) {
+	my $closing = pop(@nestingstack);
+	my @parts = split(/:/, $closing);
+	fileWarning($lineno, "missing %end (%".$parts[0]." opened at ".lineDescriptionForPhysicalLine($parts[1])." extends to EOF)");
+}
+
+Logos::Generator::use($main::CONFIG{"generator"});
+
+my $hasGeneratorPreamble = $preprocessed; # If we're already preprocessed, we cannot insert #include statements.
+$hasGeneratorPreamble = Logos::Generator::for->findPreamble(\@lines) if !$hasGeneratorPreamble;
+
+if(@firstDirectivePosition) {
+	# Loop until we find a blank line at depth 0 to splice our preamble in.
+	# The top of the file (or, alternatively, the first line of our file post-
+	# preprocessing) will be considered to be a blank line.
+	#
+	# This breaks if one includes a blank line between "int blah()" and its
+	# corresponding "{", however. Nobody codes like that anyway.
+	# This will probably also break if you keep your "{" and "}" inside header files
+	# that you #include into your code. Nobody codes like that, either.
+
+	# Optimization: Only do this once.
+	my @depthKeys = sort {
+		my @ba=split(/:/,$b);
+		my @aa=split(/:/,$a);
+		($ba[0] == $aa[0]
+		? $ba[1] <=> $aa[1]
+			: $ba[0] <=> $aa[0])
+	} keys %depthMapping;
+	my $line = $firstDirectivePosition[0];
+	my $pos = $firstDirectivePosition[1];
+	while(1) {
+		my $depth = lookupDepthMapping($line, $pos, \@depthKeys);
+		my $above;
+		$above = "" if $line eq 0;
+		if($preprocessed) {
+			my @lm = lookupLineMapping($line);
+			$above = "" if($lm[0] eq $filename && $lm[1] == 1);
+		}
+		$above = $lines[$line-1] if !defined $above;
+
+		last if $depth == 0 && $above =~ /^\s*$/;
+
+		$line-- if($pos == 0);
+		$pos = 0;
+	}
+	my $patch = Patch->new();
+	$patch->line($line);
+	my @patchsource = ();
+	push(@patchsource, Patch::Source::Generator->new(undef, 'preamble', $hasGeneratorPreamble));
+	push(@patchsource, Patch::Source::Generator->new(undef, 'generateClassList', keys %classes));
+	push(@patchsource, Patch::Source::Generator->new($groups[0], 'declarations'));
+	push(@patchsource, Patch::Source::Generator->new($staticClassGroup, 'declarations'));
+	$patch->source(\@patchsource);
+	addPatch($patch);
+
+	if(!@lastInitPosition) {
+		# If we haven't seen any %init directives, generate the default constructor.
+		my $patch = Patch->new();
+		$patch->line(scalar @lines);
+		$patch->squash(1);
+		$patch->source(defaultConstructorSource());
+		addPatch($patch);
+	}
+
+}
+
+my @unInitGroups = map {$_->name;} (grep {!$_->initialized && $_->initRequired;} @groups);
+fileError($lineno, "non-initialized hook group".(scalar @unInitGroups == 1 ? "" : "s").": ".join(", ", @unInitGroups)) if scalar @unInitGroups > 0;
+
+my @sortedPatches = sort { ($b->line == $a->line ? ($b->start || -1) <=> ($a->start || -1) : $b->line <=> $a->line) } @patches;
+
+if(exists $main::CONFIG{"dump"}) {
+	my $dumphref = {
+			linemap=>\%lineMapping,
+			depthmap=>\%depthMapping,
+			groups=>\@groups,
+			patches=>\@patches,
+			lines=>\@lines,
+			config=>\%::CONFIG
+		};
+	if($main::CONFIG{"dump"} eq "yaml") {
+		load 'YAML::Syck';
+		print STDERR YAML::Syck::Dump($dumphref);
+	}
+	#print STDERR Data::Dumper->Dump([\@groups, \@patches, \@lines, \%::CONFIG], [qw(groups patches lines config)]);
+}
+
+if($main::warnings > 0 && exists $main::CONFIG{"warnings"} && $main::CONFIG{"warnings"} eq "error") {
+	exit(1);
+}
+
+for(@sortedPatches) {
+	$_->apply(\@lines);
+}
+
+splice(@lines, 0, 0, generateLineDirectiveForPhysicalLine(0)) if !$preprocessed;
+foreach my $oline (@lines) {
+	print $oline."\n" if defined($oline);
+}
+
+sub defaultConstructorSource {
+	my @return;
+	my @initRequiredGroups = grep {$_->initRequired;} @groups;
+	my @explicitGroups = grep {$_->explicit;} @initRequiredGroups;
+	fileError($lineno, "Cannot generate an autoconstructor with multiple %groups. Please explicitly create a constructor.") if scalar @explicitGroups > 0;
+	if(scalar @initRequiredGroups > 0) {
+		push(@return, "static __attribute__((constructor)) void _logosLocalInit() {\n");
+		foreach(@initRequiredGroups) {
+			fileError($lineno, "re-%init of %group ".$_->name.", first initialized at ".lineDescriptionForPhysicalLine($_->initLine)) if $_->initialized;
+			push(@return, Patch::Source::Generator->new($_, 'initializers'));
+			push(@return, " ");
+			$_->initLine($lineno);
+			$_->initialized(1);
+		}
+		push(@return, "}\n");
+	}
+	return @return > 0 ? \@return : undef;
+}
+
+sub fileWarning {
+	my $curline = shift;
+	my $reason = shift;
+	my @lineMap = lookupLineMapping($curline);
+	my $filename = $lineMap[0];
+	my $print = 1;
+	if(exists($main::CONFIG{"warnings"})) {
+		if($main::CONFIG{"warnings"} eq "error") {
+			if($main::warnings == 0) {
+				print STDERR "logos: warnings being treated as errors\n";
+			}
+		} elsif($main::CONFIG{"warnings"} eq "none") {
+			$print = 0;
+		}
+	}
+	print STDERR "$filename:".($curline > -1 ? $lineMap[1].":" : "")." warning: $reason\n" if($print == 1);
+	$main::warnings++;
+}
+
+sub fileError {
+	my $curline = shift;
+	my $reason = shift;
+	my @lineMap = lookupLineMapping($curline);
+	my $filename = $lineMap[0];
+	die "$filename:".($curline > -1 ? $lineMap[1].":" : "")." error: $reason\n";
+}
+
+sub nestingError {
+	my $curline = shift;
+	my $thisblock = shift;
+	my $reason = shift;
+	my @parts = split(/:/, $reason);
+	fileError $curline, "$thisblock inside a %".$parts[0].", opened at ".lineDescriptionForPhysicalLine($parts[1]);
+}
+
+sub nestingMustContain {
+	my $lineno = shift;
+	my $trying = shift;
+	my $stackref = shift;
+	return if nestingContains($stackref, @_);
+	fileError($lineno, "$trying found outside of ".join(" or ", @_));
+}
+
+sub nestingMustNotContain {
+	my $lineno = shift;
+	my $trying = shift;
+	my $stackref = shift;
+	nestingError($lineno, $trying, $_) if nestingContains($stackref, @_);
+}
+
+sub nestingContains {
+	my $stackref = shift;
+	my @stack = @$stackref;
+	my @search = @_;
+	my @parts = ();
+	foreach my $nest (@stack) {
+		@parts = split(/:/, $nest);
+		foreach my $find (@search) {
+			if($find eq $parts[0]) {
+				$_ = $nest;
+				return $_;
+			}
+		}
+	}
+	$_ = undef;
+	return undef;
+}
+
+sub nestPush {
+	my $type = shift;
+	my $line = shift;
+	my $ref_stack = shift;
+	push(@{$ref_stack}, $type.":".$line);
+}
+
+sub nestPop {
+	my $ref_stack = shift;
+	my $outgoing = pop(@{$ref_stack});
+	return undef if !$outgoing;
+	my @parts = split(/:/, $outgoing);
+	return $parts[0];
+}
+
+sub getGroup {
+	my $name = shift;
+	foreach(@groups) {
+		return $_ if $_->name eq $name;
+	}
+	return undef;
+}
+
+sub lookupLineMapping {
+	my $fileline = shift;
+	$fileline++;
+	for (sort {$b <=> $a} keys %lineMapping) {
+		if($fileline >= $_) {
+			my @x = @{$lineMapping{$_}};
+			return ($x[0], $x[1] + ($fileline-$_));
+		}
+	}
+	return undef;
+}
+
+sub generateLineDirectiveForPhysicalLine {
+	my $physline = shift;
+	my @lineMap = lookupLineMapping($physline);
+	my $filename = $lineMap[0];
+	my $lineno = $lineMap[1];
+	return ($preprocessed ? "# " : "#line ").$lineno." \"$filename\"";
+}
+
+sub lineDescriptionForPhysicalLine {
+	my $physline = shift;
+	my @lineMap = lookupLineMapping($physline);
+	my $filename = $lineMap[0];
+	my $lineno = $lineMap[1];
+	return "$filename:$lineno";
+}
+
+sub locationOpeningDepthAtPositionInMapping {
+	my $dref = shift;
+	my $fileline = shift;
+	my $pos = shift;
+	my $kref = shift;
+	my @keys;
+	if($kref) {
+		@keys = @$kref;
+	} else {
+		@keys = sort {
+			my @ba=split(/:/,$b);
+			my @aa=split(/:/,$a);
+			($ba[0] == $aa[0]
+			? $ba[1] <=> $aa[1]
+				: $ba[0] <=> $aa[0])
+		} keys %$dref;
+	}
+	for (@keys) {
+		my @depthTokens = split(/:/, $_);
+		if($fileline > $depthTokens[0] || ($fileline == $depthTokens[0] && $pos >= $depthTokens[1])) {
+			return @depthTokens;
+		}
+	}
+	return undef;
+}
+
+sub lookupDepthMapping {
+	my $fileline = shift;
+	my $pos = shift;
+	my $kref = shift;
+	my @depthTokens = locationOpeningDepthAtPositionInMapping(\%depthMapping, $fileline, $pos, $kref);
+	return 0 if(!@depthTokens);
+	return $depthMapping{join(':', @depthTokens)};
+}
+
+sub patchHere {
+	my $source = shift;
+	my $patch = Patch->new();
+	$patch->line($lineno);
+	$patch->range($-[0], $+[0]);
+	$patch->source($source);
+	push @patches, $patch;
+}
+
+sub addPatch {
+	my $patch = shift;
+	push @patches, $patch;
+}
+
+sub prettyPrintMethod {
+	my $method = shift;
+	return $method->scope."[".$method->class->name." ".$method->selector."]";
+}
+
+sub utilErrorHandler {
+	fileError($lineno, shift);
+}

+ 324 - 0
CycriptLoader/theos/bin/nic.pl

@@ -0,0 +1,324 @@
+#!/usr/bin/perl
+
+my $VER = "2.0";
+
+use strict;
+use warnings;
+use FindBin;
+use lib "$FindBin::Bin/lib";
+
+use Getopt::Long;
+use Cwd qw(abs_path getcwd);
+use File::Spec;
+use File::Find;
+use File::Copy;
+use User::pwent;
+use POSIX qw(getuid);
+use Module::Load::Conditional 'can_load';
+use Tie::File;
+
+use NIC::Bridge::Context (PROMPT => \&nicPrompt);
+use NIC::Formats::NICTar;
+use NIC::NICType;
+
+our $savedStdout = *STDOUT;
+
+my @_dirs = File::Spec->splitdir(abs_path($FindBin::Bin));
+$_dirs[$#_dirs]="templates";
+our $_templatepath = File::Spec->catdir(@_dirs);
+$#_dirs--;
+my $_theospath = File::Spec->catdir(@_dirs);
+
+{
+	my $_abstheospath = abs_path($_theospath);
+	my $_cwd = abs_path(Cwd::getcwd());
+	$_abstheospath .= '/' if $_abstheospath !~ /\/$/;
+	$_cwd .= '/' if $_cwd !~ /\/$/;
+	exitWithError("Cowardly refusing to make a project inside \$THEOS ($_abstheospath)") if($_cwd =~ /^$_abstheospath/);
+}
+
+my %CONFIG = (link_theos => 0);
+loadConfig();
+
+my $clean_project_name = "";
+my $project_name = "";
+my $package_prefix = $CONFIG{'package_prefix'};
+$package_prefix = "com.yourcompany" if !$package_prefix;
+my $package_name = "";
+my $username = $CONFIG{'username'};
+$username = "" if !$username;
+
+my $template = undef;
+my $nicfile = undef;
+
+Getopt::Long::Configure("bundling");
+
+GetOptions(	"packagename|p=s" => \$package_name,
+		"name|n=s" => \$project_name,
+		"user|u=s" => \$username,
+		"nic=s" => \$nicfile,
+		"template|t=s" => \$template);
+
+$project_name = $ARGV[0] if($ARGV[0]);
+
+my $_versionstring = "NIC $VER - New Instance Creator";
+print $_versionstring,$/;
+print "-" x length($_versionstring),$/;
+
+my $NIC;
+if($nicfile) {
+	$NIC = _loadNIC($nicfile) if $nicfile && -f $nicfile;
+} else {
+	my @templates = getTemplates();
+	if(scalar @templates == 0) {
+		exitWithError("No file specified with --nic and no templates found.");
+	}
+
+	if($template) {
+		my @matched = grep { $_->name eq $template } @templates;
+		$NIC = $matched[0] if(scalar @matched > 0);
+	}
+	if(!$NIC) {
+		$NIC = promptList(undef, "Choose a Template (required)", sub { local $_ = shift; return $_->name; }, @templates);
+	}
+}
+
+exitWithError("No NIC file loaded.") if !$NIC;
+
+promptIfMissing(\$project_name, undef, "Project Name (required)");
+exitWithError("I can't live without a project name! Aieeee!") if !$project_name;
+$clean_project_name = cleanProjectName($project_name);
+
+$package_name = $package_prefix.".".packageNameIze($project_name) if $CONFIG{'skip_package_name'};
+promptIfMissing(\$package_name, $package_prefix.".".packageNameIze($project_name), "Package Name") unless $NIC->variableIgnored("PACKAGENAME");
+
+promptIfMissing(\$username, getUserName(), "Author/Maintainer Name") unless $NIC->variableIgnored("USER");
+
+my $directory = lc($clean_project_name);
+if(-d $directory) {
+	my $response;
+	promptIfMissing(\$response, "N", "There's already something in $directory. Continue");
+	exit 1 if(uc($response) eq "N");
+}
+
+$NIC->variable("FULLPROJECTNAME") = $project_name;
+$NIC->variable("PROJECTNAME") = $clean_project_name;
+$NIC->variable("PACKAGENAME") = $package_name;
+$NIC->variable("USER") = $username;
+
+if(! -e "control" && ! -e "layout/DEBIAN/control") {
+	$NIC->addConstraint("package");
+}
+
+foreach my $prompt ($NIC->prompts) {
+	nicPrompt($NIC, $prompt->{name}, $prompt->{prompt}, $prompt->{default});
+}
+
+my $cwd = abs_path(getcwd());
+
+# Add theos symlink to the template, if necessary
+if($CONFIG{'link_theos'} != 0 && !$NIC->variableIgnored("THEOS")) {
+	$NIC->addConstraint("link_theos");
+
+	my $template_theos_reference = $NIC->_getContentWithoutCreate("theos");
+	if(!$template_theos_reference || $template_theos_reference->type == NIC::NICType::TYPE_UNKNOWN) {
+		print STDERR "[warning] Asked to link theos, but template lacks an optional theos link. Creating one! Contact the author of this template about this issue.",$/;
+		$NIC->registerSymlink("theos", '@@THEOS_PATH@@');
+	}
+
+	my $theosLinkPath = $CONFIG{'theos_path'};
+	$theosLinkPath = readlink("$cwd/theos") if !$theosLinkPath && (-l "$cwd/theos") && !$CONFIG{'ignore_parent_theos'};
+	$theosLinkPath = "$cwd/theos" if !$theosLinkPath && (-d "$cwd/theos") && !$CONFIG{'ignore_parent_theos'};
+	$theosLinkPath = $_theospath if !$theosLinkPath;
+
+	# Set @@THEOS@@ to 'theos', so that the project refers to its linked copy of theos.
+	$NIC->variable("THEOS") = "theos";
+	$NIC->variable("THEOS_PATH") = $theosLinkPath;
+} else {
+	# Trust that the user knows what he's doing and set @@THEOS@@ to $(THEOS). (or whatever the user prefers)
+	my $theosLocalName = '$(THEOS)';
+	$theosLocalName = $CONFIG{"theos_local_name"} if $CONFIG{"theos_local_name"};
+	$NIC->variable("THEOS") = $theosLocalName;
+}
+
+# Execute control script.
+$NIC->exec or exitWithError("Failed to build template '".$NIC->name."'.");
+
+print "Instantiating ".$NIC->name." in ".lc($clean_project_name)."/...",$/;
+my $dirname = lc($clean_project_name);
+$NIC->build($dirname);
+chdir($cwd);
+
+my @makefiles = ("GNUmakefile", "makefile", "Makefile");
+my $makefile;
+map { $makefile = $_ if -e $_; } @makefiles;
+if($makefile) {
+	tie(my @lines, 'Tie::File', $makefile);
+	my $hasCommon = 0;
+	map {$hasCommon++ if /common\.mk/;} @lines;
+	if($hasCommon > 0) {
+		my $alreadyHas = 0;
+		map {$alreadyHas++ if /^\s*SUBPROJECTS.*$dirname/;} @lines;
+		if($alreadyHas == 0) {
+			print "Adding '$project_name' as an aggregate subproject in Theos makefile '$makefile'.",$/;
+			my $newline = "SUBPROJECTS += $dirname";
+			my $i = 0;
+			my $aggLine = -1;
+			map {$aggLine = $i if /aggregate\.mk/; $i++;} @lines;
+			if($aggLine == -1) {
+				push(@lines, $newline);
+				push(@lines, "include \$(THEOS_MAKE_PATH)/aggregate.mk");
+			} else {
+				splice(@lines, $aggLine, 0, $newline);
+			}
+		}
+	}
+	untie(@lines);
+}
+print "Done.",$/;
+
+sub promptIfMissing {
+	my $vref = shift;
+	return if(${$vref});
+
+	my $default = shift;
+	my $prompt = shift;
+
+	if($default) {
+		print $::savedStdout $prompt, " [$default]: ";
+	} else {
+		print $::savedStdout $prompt, ": ";
+	}
+
+	$| = 1; $_ = <STDIN>;
+	chomp;
+
+	if($default) {
+		${$vref} = $_ ? $_ : $default;
+	} else {
+		${$vref} = $_;
+	}
+}
+
+sub promptList {
+	my $default = shift;
+	my $prompt = shift;
+	my $formatsub = shift // sub { shift; };
+	my @list = @_;
+
+	$default = -1 if(!defined $default);
+
+	for(0..$#list) { print " ".($_==$default?">":" ")."[".($_+1).".] ",$formatsub->($list[$_]),$/; }
+	print $prompt,": ";
+	$| = 1;
+	my $idx = -1;
+	while(<STDIN>) {
+		chomp;
+		if($default > -1 && $_ eq "") {
+			$idx = $default;
+			last;
+		}
+		if($_ < 1 || $_ > $#list+1) {
+			print "Invalid value.",$/,$prompt,": ";
+			next;	
+		}
+		$idx = $_-1;
+		last;
+	}
+	return $list[$idx];
+}
+
+sub exitWithError {
+	my $error = shift;
+	print STDERR "[error] ", $error, $/;
+	exit 1;
+}
+
+sub _loadNIC {
+	my $nicfile = shift;
+	open(my $nichandle, "<", $nicfile);
+	my $line = <$nichandle>;
+	seek($nichandle, 0, 0);
+
+	(my $prettyname = $nicfile) =~ s/$::_templatepath\/(.*)\.nic(\.tar)?/$1/g;
+	$prettyname .= " (unnamed template)";
+
+	my $nicversion = 1;
+	my $NIC = undef;
+	if($line =~ /^nic (\w+)$/) {
+		$nicversion = $1;
+		my $NICPackage = "NIC$nicversion";
+		return undef if(!can_load(modules => {"NIC::Formats::$NICPackage" => undef}));
+		$NIC = "NIC::Formats::$NICPackage"->new($nichandle, $prettyname);
+	} else {
+		$NIC = NIC::Formats::NICTar->new($nichandle, $prettyname);
+	}
+
+	close($nichandle);
+	return $NIC;
+}
+
+sub getTemplates {
+	our @templates = ();
+	find({wanted => \&templateWanted, no_chdir => 1}, $_templatepath);
+	sub templateWanted {
+		if(-f && (/\.nic$/ || /\.nic\.tar$/)) {
+			my $nic = _loadNIC($_);
+			push(@templates, $nic) if $nic;
+		}
+	}
+	return sort { $a->name cmp $b->name } @templates;
+}
+
+sub packageNameIze {
+	my $name = shift;
+	$name =~ s/ //g;
+	$name =~ s/[^\w\+-.]//g;
+	return lc($name);
+}
+
+sub cleanProjectName {
+	my $name = shift;
+	$name =~ s/ //g;
+	$name =~ s/\W//g;
+	return $name;
+}
+
+sub getUserName {
+	my $pw = getpw(getuid());
+	my ($fullname) = split(/\s*,\s*/, $pw->gecos);
+	return $fullname ? $fullname : $pw->name;
+}
+
+sub getHomeDir {
+	my $pw = getpw(getuid());
+	return $pw->dir;
+}
+
+sub loadConfig {
+	open(my $cfh, "<", getHomeDir()."/.nicrc") or return;
+	while(<$cfh>) {
+		if(/^(.+?)\s*=\s*\"(.*)\"$/) {
+			my $key = $1;
+			my $value = $2;
+			$CONFIG{$key} = $value;
+		}
+	}
+}
+
+sub nicPrompt {
+	# Do we want to import these variables into the NIC automatically? In the format name.VARIABLE?
+	# If so, this could become awesome. We could $NIC->get($prompt->{name})
+	# and have loaded the variables in a loop beforehand.
+	# This would also allow the user to set certain variables (package prefix, username) for different templates.
+	my ($nic, $variable, $prompt, $default) = @_;
+	my $response = undef;
+	$response = $CONFIG{$nic->name().".".$variable} if($variable);
+
+	promptIfMissing(\$response, $default, "[".$nic->name."] ".$prompt);
+
+	$NIC->variable($variable) = $response if $variable;
+
+	# Return the response for anybody who's interested.
+	$response;
+}

+ 147 - 0
CycriptLoader/theos/bin/nicify.pl

@@ -0,0 +1,147 @@
+#!/usr/bin/perl
+
+use strict;
+use warnings;
+use File::Find;
+use File::Spec;
+use Archive::Tar;
+use Cwd qw(abs_path getcwd);
+
+use FindBin;
+use lib "$FindBin::Bin/lib";
+use NIC::Formats::NICTar;
+
+package NIC::Archive::Tar::File;
+use parent "Archive::Tar::File";
+sub new {
+	my $class = shift;
+	my $self = Archive::Tar::File->new(@_);
+	bless($self, $class);
+	return $self;
+}
+
+sub _prefix_and_file {
+	my $self = shift;
+	my $path = shift;
+	my ($prefix, $file) = $self->SUPER::_prefix_and_file($path);
+	$prefix =~ s/^/\.\// if $prefix ne "" && $prefix ne "." && $prefix !~ /^\.\//;
+	return ($prefix, $file);
+}
+1;
+package main;
+
+if(@ARGV == 0) {
+	exitWithError("Syntax: $FindBin::Script <directory>");
+}
+
+my $cwd = abs_path(getcwd());
+my $tar = Archive::Tar->new();
+my $controlfile = undef;
+our @tarfiles = (
+	NIC::Archive::Tar::File->new(data=>"./", "", {type=>Archive::Tar::Constant::DIR, uid=>0, gid=>0, mode=>0755}),
+	NIC::Archive::Tar::File->new(data=>"./NIC/", "", {type=>Archive::Tar::Constant::DIR, uid=>0, gid=>0, mode=>0777})
+);
+
+chdir $ARGV[0];
+
+my $control_in = undef;
+
+if(-f "pre.NIC") {
+	warning("Using legacy pre.NIC as ./NIC/control.");
+	$control_in = "./pre.NIC";
+} elsif(-f "NIC/control") {
+	$control_in = "./NIC/control";
+}
+
+if(!$control_in) {
+	exitWithError("No control file found at NIC/control.");
+	exit 1;
+}
+
+$controlfile = NIC::Archive::Tar::File->new(file=>$control_in);
+$controlfile->prefix("./NIC");
+$controlfile->name("control");
+push(@tarfiles, $controlfile);
+
+find({wanted => \&wanted, preprocess => \&preprocess, follow => 0, no_chdir => 1}, ".");
+
+$tar->add_files(@tarfiles);
+
+chdir($cwd);
+my $newnic = NIC::Formats::NICTar->new($tar);
+if(!defined $newnic->name) {
+	exitWithError("Template has no name. Please insert a `name \"<name>\"` directive into $control_in.");
+}
+
+{ my $_ = scalar @{$newnic->{CONTENTS}}; info("$_ entr".($_==1?"y.":"ies.")); }
+{ my $_ = scalar @{$newnic->{PROMPTS}}; info("$_ prompt".($_==1?".":"s.")); }
+my $constraints = 0;
+{
+	my %constrainthash;
+	for(@{$newnic->{CONTENTS}}) {
+		for my $c ($_->constraints) {
+			$constrainthash{$c}++;
+		}
+	}
+	$constraints = scalar keys %constrainthash;
+}
+{ my $_ = $constraints; info("$_ constraint".($_==1?".":"s.")); }
+
+my $fixedfn = join("_", File::Spec->splitdir($newnic->name));
+my $filename = $fixedfn.".nic.tar";
+$tar->write($filename) and info("Archived template \"".$newnic->name."\" to $filename.");
+
+sub preprocess {
+	my @list = @_;
+	if($File::Find::dir eq "./NIC") {
+		@list = grep !/^control$/, @list;
+	}
+	@list = grep !/^pre.NIC$/ && !/^\.svn$/ && !/^\.git$/ && !/^_MTN$/ && !/\.nic\.tar$/ && !/^\.DS_Store$/ && !/^\._/, @list;
+	return @list;
+}
+
+sub wanted {
+	local $_ = $File::Find::name;
+	my $mode = (stat)[2];
+
+	my $tarfile = undef;
+	if(-d) {
+		s/$/\// if !/\/$/;
+		return if /^\.\/$/;
+		return if /^\.\/NIC\/?$/;
+		$tarfile = NIC::Archive::Tar::File->new(data=>$_, "", {mode=>$mode, uid=>0, gid=>0, type=>Archive::Tar::Constant::DIR});
+	} elsif(-f && ! -l) {
+		$tarfile = NIC::Archive::Tar::File->new(file=>$_);
+		$tarfile->mode($mode);
+		$tarfile->uid(0);
+		$tarfile->gid(0);
+	} elsif(-l) {
+		$tarfile = NIC::Archive::Tar::File->new(data=>$_, "", {linkname=>readlink($_), uid=>0, gid=>0, type=>Archive::Tar::Constant::SYMLINK});
+	}
+	push(@tarfiles, $tarfile) if $tarfile;
+}
+
+sub slurp {
+	my $fn = shift;
+	open(my($fh), "<", $fn);
+	local $/ = undef;
+	my $d = <$fh>;
+	return $d;
+}
+
+sub info {
+	my $text = shift;
+	print STDERR "[info] ", $text, $/;
+}
+
+sub warning {
+	my $text = shift;
+	print STDERR "[warning] ", $text, $/;
+}
+
+sub exitWithError {
+	my $error = shift;
+	print STDERR "[error] ", $error, $/;
+	exit 1;
+}
+

+ 44 - 0
CycriptLoader/theos/bin/package_version.sh

@@ -0,0 +1,44 @@
+#!/bin/bash
+
+function build_num_from_file {
+	version=$(< "$1")
+	version=${version##*-}
+	version=${version%%+*}
+	version=${version%%~*}
+	echo -n "$version"
+}
+
+while getopts ":N:V:" flag; do
+	case "$flag" in
+		:)	echo "$0: Option -$OPTARG requires an argument." 1>&2
+			exit 1
+			;;
+		\?)	echo "$0: What're you talking about?" 1>&2
+			exit 1
+			;;
+		N)	package="$OPTARG" ;;
+		V)	version="$OPTARG" ;;
+	esac
+done
+
+if [[ ! -d "${THEOS_PROJECT_DIR}/.theos/packages" ]]; then
+	if [[ -d "${THEOS_PROJECT_DIR}/.debmake" ]]; then
+		mkdir -p "${THEOS_PROJECT_DIR}/.theos"
+		mv "${THEOS_PROJECT_DIR}/.debmake" "${THEOS_PROJECT_DIR}/.theos/packages"
+	else
+		mkdir -p "${THEOS_PROJECT_DIR}/.theos/packages"
+	fi
+fi
+
+versionfile="${THEOS_PROJECT_DIR}/.theos/packages/$package-$version"
+build_number=0
+
+if [[ ! -e "$versionfile" ]]; then
+	build_number=1
+else
+	build_number=$(build_num_from_file "$versionfile")
+	let build_number++
+fi
+
+echo -n "$build_number" > "$versionfile"
+echo "$build_number"

+ 26 - 0
CycriptLoader/theos/bin/target.pl

@@ -0,0 +1,26 @@
+#!/usr/bin/perl
+use File::Temp;
+
+my @o;
+for(reverse @ARGV) {
+	my $i = 0;
+	for my $a (split /:/) {
+		if(length $a > 0) {
+			@o = () if($i == 0 && $o[$i] && $o[$i] ne $a);
+			$o[$i] = $a;
+		}
+		$i++;
+	}
+}
+#print join(':', map { $_ eq "" ? "-" : $_ } @o);
+my $i = 0;
+my ($fh, $tempfile) = File::Temp::tempfile();
+binmode($fh, ":utf8");
+
+for(@o) {
+	print $fh "export __THEOS_TARGET_ARG_$i := $_\n";
+	++$i;
+}
+
+close($fh);
+print $tempfile,$/;

+ 23 - 0
CycriptLoader/theos/bin/vercmp.pl

@@ -0,0 +1,23 @@
+#!/usr/bin/perl
+use warnings;
+use strict;
+if(@ARGV < 3) {
+	exit 1;
+}
+my @afirst = split(/\./, $ARGV[0]);
+my $op = $ARGV[1];
+my @asecond = split(/\./, $ARGV[2]);
+
+push(@afirst, 0) while(@afirst < @asecond);
+push(@asecond, 0) while(@asecond < @afirst);
+
+my $v1 = 0;
+my $v2 = 0;
+map { ($v1 *= 100) += $_ } (@afirst);
+map { ($v2 *= 100) += $_ } (@asecond);
+
+print "1" if $v1 > $v2 && $op eq "gt";
+print "1" if $v1 < $v2 && $op eq "lt";
+print "1" if $v1 >= $v2 && $op eq "ge";
+print "1" if $v1 <= $v2 && $op eq "le";
+print "1" if $v1 == $v2 && $op eq "eq";

+ 7 - 0
CycriptLoader/theos/documentation/Makefile

@@ -0,0 +1,7 @@
+all: makefiles.html
+
+%.html: %.docbook
+	xsltproc --output $@ /usr/share/sgml/docbook/xsl-stylesheets/xhtml/docbook.xsl $<
+
+clean:
+	rm *.html

+ 405 - 0
CycriptLoader/theos/documentation/makefiles.docbook

@@ -0,0 +1,405 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
+"http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
+<!ENTITY project "<literal>Theos</literal>">
+]>
+<chapter>
+  <title>Makefiles</title>
+
+  <section id="intro">
+    <title>Introduction</title>
+
+    <para>&project; is a set of Makefiles designed to take away the complexity
+    of building and organizing iPhoneOS projects without the use of Xcode (or
+    even Mac OS X.)</para>
+  </section>
+
+  <section id="structure">
+    <title>Structure of a Makefile</title>
+
+    <para>Here is an example makefile for a project using &project;</para>
+
+    <programlisting># System variables such as MODULES and TARGET.
+
+include theos/makefiles/common.mk
+
+# Instance-related variables such as xxx_FILES.
+
+TOOL_NAME = Simple
+Simple_FILES = simple.mm
+
+include $(THEOS_MAKE_PATH)/tool.mk
+
+# Custom rules</programlisting>
+  </section>
+
+  <section id="project-types">
+    <title>Project Types</title>
+
+    <para>Projects are divided into different types, briefly described below.
+    To create a project of a given type, simply include its makefile. For
+    example, to create a command-line tool:</para>
+
+    <programlisting>include theos/makefiles/tool.mk</programlisting>
+
+    <para>From one Makefile, you can build multiple types of project (just
+    include both project type makefiles). An example:</para>
+
+    <programlisting>include theos/makefiles/common.mk
+
+TWEAK_NAME = Simple
+Simple_FILES = Tweak.mm
+
+TOOL_NAME = simpleutility
+simpleutility_FILES = su.c
+
+include $(THEOS_MAKE_PATH)/tweak.mk
+include $(THEOS_MAKE_PATH)/tool.mk</programlisting>
+
+    <para>You can also build multiple instances of a single project type from
+    one Makefile.</para>
+
+    <programlisting>include theos/makefiles/common.mk
+
+TWEAK_NAME = Simple Complex
+Simple_FILES = Tweak.mm
+Complex_FILES = 1.mm 2.mm 3.mm 4.mm
+
+include $(THEOS_MAKE_PATH)/tweak.mk</programlisting>
+
+    <section>
+      <title>Aggregate (<filename>aggregate.mk</filename>)</title>
+
+      <para>An Aggregate project is a project that consists of several
+      subprojects. Each subproject can be any valid type (including another
+      Aggregate).</para>
+
+      <variablelist>
+        <varlistentry>
+          <term><varname>SUBPROJECTS</varname></term>
+
+          <listitem>
+            <para><varname>The SUBPROJECTS</varname> variable defines the
+            directory names that contain the subprojects this Aggregate
+            project should build.</para>
+          </listitem>
+        </varlistentry>
+      </variablelist>
+    </section>
+
+    <section>
+      <title><systemitem class="library">UIKit</systemitem> Applications
+      (<filename>application.mk</filename>)</title>
+
+      <para>An <literal>application</literal> is an Objective-C program that includes a GUI
+      component, and by default links against <systemitem
+      class="library">UIKit</systemitem>.</para>
+    </section>
+
+    <section>
+      <title>Command Line Tools (<filename>tool.mk</filename>)</title>
+
+      <para>A <literal>tool</literal> is a program that does not have a GUI component, and differs from an <literal>application</literal> wherein it does
+      not link against <systemitem class="library">UIKit</systemitem>. This
+      project type is intended for command-line tools, daemons, etc.</para>
+    </section>
+
+    <section>
+      <title>MobileSubstrate Tweaks (<filename>tweak.mk</filename>)</title>
+
+      <para>A <literal>tweak</literal> is a dynamic library that links against <systemitem
+      class="library">MobileSubstrate</systemitem> for the purposes of adding
+      and replacing functions and methods at runtime.</para>
+
+      <para>Tweaks in &project; are often written with the help of the Logos
+      preprocessor.</para>
+
+      <note>
+        <para>A <literal>tweak</literal> does not, by default, link against <systemitem
+        class="library">UIKit</systemitem>. If you want to link against
+        <systemitem class="library">UIKit</systemitem>, add it to
+        <varname>xxx_FRAMEWORKS</varname>.</para>
+      </note>
+    </section>
+
+    <section>
+      <title>Bundles (<filename>bundle.mk</filename>)</title>
+
+      <para>A <literal>bundle</literal> is a dynamic library meant to be loaded into another
+      application at runtime, using the <classname>NSBundle</classname> class.</para>
+    </section>
+
+    <section>
+      <title>Frameworks (<filename>framework.mk</filename>)</title>
+
+      <!--para>A framework is a dynamic library bundle, containing resources, meant to be linked by another
+      application or dynamic library.</para-->
+    </section>
+
+    <section>
+      <title>Dynamic Libraries (<filename>library.mk</filename>)</title>
+    </section>
+  </section>
+
+  <section>
+    <title>Variables</title>
+
+    <section>
+      <title>System Constants</title>
+
+      <para>These constants are listed for use in toplevel Makefiles.</para>
+
+      <variablelist>
+        <varlistentry>
+          <term><varname>THEOS</varname></term>
+          <term><varname>THEOS_MAKE_PATH</varname></term>
+          <term><varname>THEOS_BIN_PATH</varname></term>
+          <term><varname>THEOS_LIBRARY_PATH</varname></term>
+          <term><varname>THEOS_INCLUDE_PATH</varname></term>
+          <term><varname>THEOS_MODULE_PATH</varname></term>
+
+          <listitem>
+            <para>Used for locating other &project; resources, such as binaries, scripts, modules and other makefiles.</para>
+          </listitem>
+        </varlistentry>
+
+        <varlistentry>
+          <term><varname>THEOS_PLATFORM_NAME</varname></term>
+          <term><varname>THEOS_TARGET_NAME</varname></term>
+
+          <listitem>
+            <para>The build platform and the platform being targeted, normalized.</para>
+          </listitem>
+        </varlistentry>
+      </variablelist>
+    </section>
+
+    <section>
+      <title>System Variables</title>
+
+      <para>These variables are listed for use in toplevel Makefiles, but if
+      you really want to change them, you can.</para>
+
+      <variablelist>
+        <varlistentry>
+          <term><varname>THEOS_BUILD_DIR</varname></term>
+
+          <listitem>
+            <para>Build directory (objects are placed in
+            <filename><varname>THEOS_BUILD_DIR</varname>/<varname>THEOS_OBJ_DIR_NAME</varname></filename>).
+            Defaults to the current directory.</para>
+          </listitem>
+        </varlistentry>
+
+        <varlistentry>
+          <term><varname>THEOS_OBJ_DIR_NAME</varname></term>
+
+          <listitem>
+            <para>Output file directory name. Defaults to
+            <filename>.theos/obj</filename>.</para>
+          </listitem>
+        </varlistentry>
+
+        <varlistentry>
+          <term><varname>THEOS_STAGING_DIR</varname></term>
+
+          <listitem>
+            <para>Package staging directory. Defaults to
+            <filename><varname>THEOS_PROJECT_DIR</varname>/_</filename>.</para>
+          </listitem>
+        </varlistentry>
+
+        <varlistentry>
+          <term><varname>Blah</varname></term>
+
+          <listitem>
+            <para>Description</para>
+          </listitem>
+        </varlistentry>
+      </variablelist>
+    </section>
+
+    <section>
+      <title>Local Variables</title>
+
+      <para>These variables are not tied to any particular project instance,
+      and can be set either in the toplevel Makefile or in the
+      environment.</para>
+
+      <variablelist>
+        <varlistentry>
+          <term><varname>ADDITIONAL_CFLAGS</varname></term>
+
+          <term><varname>ADDITIONAL_CCFLAGS</varname></term>
+
+          <term><varname>ADDITIONAL_OBJCFLAGS</varname></term>
+
+          <term><varname>ADDITIONAL_OBJCCFLAGS</varname></term>
+
+          <term><varname>ADDITIONAL_LDFLAGS</varname></term>
+
+          <listitem>
+            <para>The <varname>ADDITIONAL_FLAGS</varname> variables control
+            additional compilation flags for an entire project. These
+            variables are not passed into subdirectories or subprojects, but
+            can be made to do so with <command>export</command>, as in
+            <command>export
+            <varname>ADDITIONAL_CFLAGS</varname></command>.</para>
+          </listitem>
+        </varlistentry>
+
+        <varlistentry>
+          <term><varname>CFLAGS</varname></term>
+
+          <term><varname>CCFLAGS</varname></term>
+
+          <term><varname>OBJCFLAGS</varname></term>
+
+          <term><varname>OBJCCFLAGS</varname></term>
+
+          <term><varname>LDFLAGS</varname></term>
+
+          <listitem>
+            <para>The unqualified <varname>FLAGS</varname> variables can be
+            used for additional compilation flags stored in the environment or
+            given on the commandline, as in <command>make
+            <varname>CFLAGS</varname>=-funroll-loops</command>.</para>
+          </listitem>
+        </varlistentry>
+
+        <varlistentry>
+          <term><varname>OPTFLAG</varname></term>
+
+          <listitem>
+            <para>The <varname>OPTFLAG</varname> variable controls
+            optimization. Its default value is <literal>-O2</literal>.</para>
+          </listitem>
+        </varlistentry>
+
+        <varlistentry>
+          <term><varname>DEBUG</varname></term>
+
+          <listitem>
+            <para>The <varname>DEBUG</varname> variable controls compilation
+            of debug symbols and stripping. When set to <literal>1</literal>,
+            <literal>-ggdb -DDEBUG</literal> is added to the compilation
+            flags, stripping is disabled, and optimization flags are stripped
+            from <varname>OPTFLAG</varname>. Additionally,
+            <literal>+debug</literal> is appended to the package build
+            identifier.</para>
+          </listitem>
+        </varlistentry>
+
+        <varlistentry>
+          <term><varname>Blah</varname></term>
+
+          <listitem>
+            <para>Description</para>
+          </listitem>
+        </varlistentry>
+
+        <varlistentry>
+          <term><varname>Blah</varname></term>
+
+          <listitem>
+            <para>Description</para>
+          </listitem>
+        </varlistentry>
+
+        <varlistentry>
+          <term><varname>Blah</varname></term>
+
+          <listitem>
+            <para>Description</para>
+          </listitem>
+        </varlistentry>
+
+        <varlistentry>
+          <term><varname>Blah</varname></term>
+
+          <listitem>
+            <para>Description</para>
+          </listitem>
+        </varlistentry>
+      </variablelist>
+    </section>
+
+    <section>
+      <title>Project Variables</title>
+
+      <para>The various project type makefiles all support a common set of
+      variables, described below. In this list, <literal>xxx</literal> is
+      assumed to be the project instance name.</para>
+
+      <variablelist>
+        <varlistentry>
+          <term><varname>xxx_FILES</varname></term>
+
+          <listitem>
+            <para>The <varname>FILES</varname> variables contain
+            space-delimited lists of the source files comprising the project.
+	    Including files with the <filename>.m</filename> or <filename>.mm</filename> extensions causes the Objective-C runtime and
+            Foundation framework to be linked with your project.</para>
+            <para>The older type-specific <varname>FILES</varname> variables are deprecated in favour of <varname>xxx_FILES</varname>.</para>
+          </listitem>
+        </varlistentry>
+
+        <varlistentry>
+          <term><varname>xxx_OBJ_FILES</varname></term>
+
+          <listitem>
+            <para>The <varname>OBJ_FILES</varname> variable contains a
+            space-delimited list of precompiled object files
+	    (<filename>.o</filename> or library/framework binaries) to be linked with the project.</para>
+          </listitem>
+        </varlistentry>
+
+        <varlistentry>
+          <term><varname>xxx_FRAMEWORKS</varname></term>
+
+          <term><varname>xxx_PRIVATE_FRAMEWORKS</varname></term>
+
+          <listitem>
+            <para>The <varname>FRAMEWORKS</varname> variables contain
+            space-delimited lists of frameworks to link with the project, if
+            Objective-C source files are used. Including
+            <varname>PRIVATE_FRAMEWORKS</varname> causes the private Framework
+            directory to be included in the Framework search path.</para>
+          </listitem>
+        </varlistentry>
+
+        <varlistentry>
+          <term><varname>xxx_CFLAGS</varname></term>
+
+          <term><varname>xxx_CCFLAGS</varname></term>
+
+          <term><varname>xxx_OBJCFLAGS</varname></term>
+
+          <term><varname>xxx_OBJCCFLAGS</varname></term>
+
+          <listitem>
+            <para>The <varname>FLAGS</varname> variables contain flags passed
+            to the compiler for a given filetype.</para>
+          </listitem>
+        </varlistentry>
+
+        <varlistentry>
+          <term><varname>xxx_LDFLAGS</varname></term>
+
+          <listitem>
+            <para>The <varname>LDFLAGS</varname> variable contains flags
+            passed to the linker for a project.</para>
+          </listitem>
+        </varlistentry>
+
+        <varlistentry>
+          <term><varname>Blah</varname></term>
+
+          <listitem>
+            <para>Description</para>
+          </listitem>
+        </varlistentry>
+      </variablelist>
+    </section>
+  </section>
+</chapter>

+ 3 - 0
CycriptLoader/theos/extras/vim/README

@@ -0,0 +1,3 @@
+Place the following in filetype.vim.
+
+au BufNewFile,BufRead *.xm,*.xmm,*.l.mm setf logos

+ 11 - 0
CycriptLoader/theos/extras/vim/ftplugin/logos.vim

@@ -0,0 +1,11 @@
+" Vim filetype plugin file
+" Language: Logos (Objective-C++)
+" Maintainer: Dustin Howett
+" Latest Revision: December 22, 2009
+
+if exists("b:did_ftplugin")
+	finish
+endif
+
+" Behaves just like Objective-C
+runtime! ftplugin/objc.vim

+ 6 - 0
CycriptLoader/theos/extras/vim/indent/logos.vim

@@ -0,0 +1,6 @@
+" Vim filetype plugin file
+" Language: Logos (Objective-C++)
+" Maintainer: Dustin Howett
+" Latest Revision: December 22, 2009
+
+runtime! indent/objc.vim

+ 69 - 0
CycriptLoader/theos/extras/vim/syntax/logos.vim

@@ -0,0 +1,69 @@
+" Vim syntax file
+" Language: Logos (Objective-C++)
+" Maintainer: Dustin Howett
+" Latest Revision: April 2, 2011
+
+if exists("b:current_syntax")
+	finish
+endif
+
+runtime! syntax/objc.vim
+
+syn match logosDirective '%\(hook\|group\|subclass\|ctor\)' display
+
+syn match logosDirective '%end' display
+
+syn match logosDirective '%class' display skipwhite nextgroup=logosClassName
+
+syn match logosDirective '%log' display contained containedin=logosHook,logosSubclass,logosGroup
+syn match logosDirective '%orig' display contained containedin=logosHook,logosSubclass,logosGroup
+
+syn match logosDirective '%init' display
+syn match logosDirective '%new' display
+syn region logosInit matchgroup=logosDirective start='%init(' end=')' contains=cParen
+
+syn region logosNew oneline matchgroup=logosNew start='%new(' end=')' contains=logosTypeEncoding,logosTypeEncodingUnion
+
+syn match logosTypeEncoding '[*@#:\[\]^?{}A-Za-z0-9$=]' display contained
+syn region logosTypeEncodingUnion oneline matchgroup=logosTypeEncoding start='(' end=')' contained transparent
+
+syn region logosInfixClass oneline matchgroup=logosInfixClass start='%c(' end=')' contains=logosClassName containedin=objcMessage
+syn match logosClassName '[A-Za-z$_][A-Za-z0-9_$]*' display contained
+
+syn region logosHook start="%hook" end="%end" fold transparent keepend extend
+syn region logosGroup start="%group" end="%end" fold transparent keepend extend
+syn region logosSubclass start="%subclass" end="%end" fold transparent keepend extend
+
+syn match logosError '\(@interface\|@implementation\)' contained containedin=logosHook,logosSubclass,logosGroup
+syn match logosError '\(%hook\|%group\|%subclass\)' contained containedin=objcImp,objcHeader
+
+syn match logosDirectiveArgument '\(%\(hook\|subclass\|group\)\)\@<=\s\+\k\+' display contained containedin=logosHook,logosSubclass,logosGroup
+syn match logosSubclassSuperclassName '\(%subclass\s\+\k\+\s*:\)\@<=\s*\k\+' display contained containedin=logosHook,logosSubclass,logosGroup
+
+syn cluster cParenGroup add=logosNew,logosInfixClass,logosInit
+syn cluster cParenGroup add=logosTypeEncoding,logosTypeEncodingUnion
+syn cluster cParenGroup add=logosClassName
+syn cluster cParenGroup add=logosDirectiveArgument,logosSubclassSuperclassName
+syn cluster cParenGroup add=logosError
+syn cluster cParenGroup add=logosHook,logosGroup,logosSubclass
+
+syn cluster cPreProcGroup add=logosClassName,logosDirective,logosTypeEncoding,logosTypeEncodingUnion
+
+syn cluster cMultiGroup add=logosTypeEncoding,logosTypeEncodingUnion,logosClassName
+
+syn sync match logosHookSync grouphere logosHook "%hook"
+syn sync match logosGroupSync grouphere logosGroup "%group"
+syn sync match logosSubclassSync grouphere logosSubclass "%subclass"
+syn sync match logosEndSync grouphere NONE "%end"
+
+let b:current_syntax = "logos"
+hi def link logosDirective PreProc
+hi def link logosDirectiveArgument String
+hi def link logosError Error
+
+hi def link logosTypeEncoding logosDirectiveArgument
+hi def link logosGroupName logosDirectiveArgument
+hi def link logosClassName logosDirectiveArgument
+hi def link logosSubclassSuperclassName logosClassName
+hi def link logosNew logosDirective
+hi def link logosInfixClass logosDirective

+ 11 - 0
CycriptLoader/theos/git-submodule-recur.sh

@@ -0,0 +1,11 @@
+#!/bin/sh
+
+SELF=$(cd ${0%/*} && echo $PWD/${0##*/})
+
+case "$1" in
+        "init") CMD="submodule update --init" ;;
+        *) CMD="$*" ;;
+esac
+
+git $CMD
+git submodule foreach "$SELF" $CMD

+ 0 - 0
CycriptLoader/theos/include/.keep


+ 1 - 0
CycriptLoader/theos/include/APDeviceController.h

@@ -0,0 +1 @@
+../../yourTube/APDeviceController.h

+ 32 - 0
CycriptLoader/theos/include/AppSupport/CPDistributedMessagingCenter.h

@@ -0,0 +1,32 @@
+@interface CPDistributedMessagingCenter : NSObject
+
++ (CPDistributedMessagingCenter*)centerNamed:(NSString*)serverName;
+
+- (BOOL)sendMessageName:(NSString*)name
+			   userInfo:(NSDictionary*)info;
+
+- (NSDictionary*)sendMessageAndReceiveReplyName:(NSString*)name
+									   userInfo:(NSDictionary*)info;
+
+- (NSDictionary*)sendMessageAndReceiveReplyName:(NSString*)name
+									   userInfo:(NSDictionary*)info
+										  error:(NSError**)error;
+
+- (void)sendMessageAndReceiveReplyName:(NSString*)name
+							  userInfo:(NSDictionary*)info
+							  toTarget:(id)target
+							  selector:(SEL)selector
+							   context:(void*)context;
+
+- (void)runServerOnCurrentThread;
+- (void)runServerOnCurrentThreadProtectedByEntitlement:(id)entitlement;
+- (void)stopServer;
+
+- (void)registerForMessageName:(NSString*)messageName
+						target:(id)target
+					  selector:(SEL)selector;
+
+- (void)unregisterForMessageName:(NSString*)messageName;
+
+@end
+

+ 65 - 0
CycriptLoader/theos/include/ContextFilterLogFormatter.h

@@ -0,0 +1,65 @@
+#import <Foundation/Foundation.h>
+#import "DDLog.h"
+
+@class ContextFilterLogFormatter;
+
+/**
+ * Welcome to Cocoa Lumberjack!
+ * 
+ * The project page has a wealth of documentation if you have any questions.
+ * https://github.com/robbiehanson/CocoaLumberjack
+ * 
+ * If you're new to the project you may wish to read the "Getting Started" page.
+ * https://github.com/robbiehanson/CocoaLumberjack/wiki/GettingStarted
+ * 
+ * 
+ * This class provides a log formatter that filters log statements from a logging context not on the whitelist.
+ * 
+ * A log formatter can be added to any logger to format and/or filter its output.
+ * You can learn more about log formatters here:
+ * https://github.com/robbiehanson/CocoaLumberjack/wiki/CustomFormatters
+ * 
+ * You can learn more about logging context's here:
+ * https://github.com/robbiehanson/CocoaLumberjack/wiki/CustomContext
+ *
+ * But here's a quick overview / refresher:
+ * 
+ * Every log statement has a logging context.
+ * These come from the underlying logging macros defined in DDLog.h.
+ * The default logging context is zero.
+ * You can define multiple logging context's for use in your application.
+ * For example, logically separate parts of your app each have a different logging context.
+ * Also 3rd party frameworks that make use of Lumberjack generally use their own dedicated logging context.
+**/
+@interface ContextWhitelistFilterLogFormatter : NSObject <DDLogFormatter>
+
+- (id)init;
+
+- (void)addToWhitelist:(int)loggingContext;
+- (void)removeFromWhitelist:(int)loggingContext;
+
+- (NSArray *)whitelist;
+
+- (BOOL)isOnWhitelist:(int)loggingContext;
+
+@end
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+#pragma mark -
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+/**
+ * This class provides a log formatter that filters log statements from a logging context on the blacklist.
+**/
+@interface ContextBlacklistFilterLogFormatter : NSObject <DDLogFormatter>
+
+- (id)init;
+
+- (void)addToBlacklist:(int)loggingContext;
+- (void)removeFromBlacklist:(int)loggingContext;
+
+- (NSArray *)blacklist;
+
+- (BOOL)isOnBlacklist:(int)loggingContext;
+
+@end

+ 35 - 0
CycriptLoader/theos/include/Cycript.h

@@ -0,0 +1,35 @@
+/* Cycript - The Truly Universal Scripting Language
+ * Copyright (C) 2009-2016  Jay Freeman (saurik)
+*/
+
+/* GNU Affero General Public License, Version 3 {{{ */
+/*
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero 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 Affero General Public License for more details.
+
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+**/
+/* }}} */
+
+#ifndef CYCRIPT_CYCRIPT_H
+#define CYCRIPT_CYCRIPT_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void CYListenServer(short port);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif/*CYCRIPT_CYCRIPT_H*/

+ 41 - 0
CycriptLoader/theos/include/DDASLLogger.h

@@ -0,0 +1,41 @@
+#import <Foundation/Foundation.h>
+#import <asl.h>
+
+#import "DDLog.h"
+
+/**
+ * Welcome to Cocoa Lumberjack!
+ * 
+ * The project page has a wealth of documentation if you have any questions.
+ * https://github.com/robbiehanson/CocoaLumberjack
+ * 
+ * If you're new to the project you may wish to read the "Getting Started" wiki.
+ * https://github.com/robbiehanson/CocoaLumberjack/wiki/GettingStarted
+ * 
+ * 
+ * This class provides a logger for the Apple System Log facility.
+ * 
+ * As described in the "Getting Started" page,
+ * the traditional NSLog() function directs it's output to two places:
+ * 
+ * - Apple System Log
+ * - StdErr (if stderr is a TTY) so log statements show up in Xcode console
+ * 
+ * To duplicate NSLog() functionality you can simply add this logger and a tty logger.
+ * However, if you instead choose to use file logging (for faster performance),
+ * you may choose to use a file logger and a tty logger.
+**/
+
+@interface DDASLLogger : DDAbstractLogger <DDLogger>
+{
+	aslclient client;
+}
+
++ (DDASLLogger *)sharedInstance;
+
+// Inherited from DDAbstractLogger
+
+// - (id <DDLogFormatter>)logFormatter;
+// - (void)setLogFormatter:(id <DDLogFormatter>)formatter;
+
+@end

+ 102 - 0
CycriptLoader/theos/include/DDAbstractDatabaseLogger.h

@@ -0,0 +1,102 @@
+#import <Foundation/Foundation.h>
+
+#import "DDLog.h"
+
+/**
+ * Welcome to Cocoa Lumberjack!
+ * 
+ * The project page has a wealth of documentation if you have any questions.
+ * https://github.com/robbiehanson/CocoaLumberjack
+ * 
+ * If you're new to the project you may wish to read the "Getting Started" wiki.
+ * https://github.com/robbiehanson/CocoaLumberjack/wiki/GettingStarted
+ * 
+ * 
+ * This class provides an abstract implementation of a database logger.
+ * 
+ * That is, it provides the base implementation for a database logger to build atop of.
+ * All that is needed for a concrete database logger is to extend this class
+ * and override the methods in the implementation file that are prefixed with "db_".
+**/
+
+@interface DDAbstractDatabaseLogger : DDAbstractLogger {
+@protected
+	NSUInteger saveThreshold;
+	NSTimeInterval saveInterval;
+	NSTimeInterval maxAge;
+	NSTimeInterval deleteInterval;
+	BOOL deleteOnEverySave;
+	
+	BOOL saveTimerSuspended;
+	NSUInteger unsavedCount;
+	dispatch_time_t unsavedTime;
+	dispatch_source_t saveTimer;
+	dispatch_time_t lastDeleteTime;
+	dispatch_source_t deleteTimer;
+}
+
+/**
+ * Specifies how often to save the data to disk.
+ * Since saving is an expensive operation (disk io) it is not done after every log statement.
+ * These properties allow you to configure how/when the logger saves to disk.
+ * 
+ * A save is done when either (whichever happens first):
+ * 
+ * - The number of unsaved log entries reaches saveThreshold
+ * - The amount of time since the oldest unsaved log entry was created reaches saveInterval
+ * 
+ * You can optionally disable the saveThreshold by setting it to zero.
+ * If you disable the saveThreshold you are entirely dependent on the saveInterval.
+ * 
+ * You can optionally disable the saveInterval by setting it to zero (or a negative value).
+ * If you disable the saveInterval you are entirely dependent on the saveThreshold.
+ * 
+ * It's not wise to disable both saveThreshold and saveInterval.
+ * 
+ * The default saveThreshold is 500.
+ * The default saveInterval is 60 seconds.
+**/
+@property (assign, readwrite) NSUInteger saveThreshold;
+@property (assign, readwrite) NSTimeInterval saveInterval;
+
+/**
+ * It is likely you don't want the log entries to persist forever.
+ * Doing so would allow the database to grow infinitely large over time.
+ * 
+ * The maxAge property provides a way to specify how old a log statement can get
+ * before it should get deleted from the database.
+ * 
+ * The deleteInterval specifies how often to sweep for old log entries.
+ * Since deleting is an expensive operation (disk io) is is done on a fixed interval.
+ * 
+ * An alternative to the deleteInterval is the deleteOnEverySave option.
+ * This specifies that old log entries should be deleted during every save operation.
+ * 
+ * You can optionally disable the maxAge by setting it to zero (or a negative value).
+ * If you disable the maxAge then old log statements are not deleted.
+ * 
+ * You can optionally disable the deleteInterval by setting it to zero (or a negative value).
+ * 
+ * If you disable both deleteInterval and deleteOnEverySave then old log statements are not deleted.
+ * 
+ * It's not wise to enable both deleteInterval and deleteOnEverySave.
+ * 
+ * The default maxAge is 7 days.
+ * The default deleteInterval is 5 minutes.
+ * The default deleteOnEverySave is NO.
+**/
+@property (assign, readwrite) NSTimeInterval maxAge;
+@property (assign, readwrite) NSTimeInterval deleteInterval;
+@property (assign, readwrite) BOOL deleteOnEverySave;
+
+/**
+ * Forces a save of any pending log entries (flushes log entries to disk).
+**/
+- (void)savePendingLogEntries;
+
+/**
+ * Removes any log entries that are older than maxAge.
+**/
+- (void)deleteOldLogEntries;
+
+@end

+ 14 - 0
CycriptLoader/theos/include/DDData.h

@@ -0,0 +1,14 @@
+#import <Foundation/Foundation.h>
+
+@interface NSData (DDData)
+
+- (NSData *)md5Digest;
+
+- (NSData *)sha1Digest;
+
+- (NSString *)hexStringValue;
+
+- (NSString *)base64Encoded;
+- (NSData *)base64Decoded;
+
+@end

+ 334 - 0
CycriptLoader/theos/include/DDFileLogger.h

@@ -0,0 +1,334 @@
+#import <Foundation/Foundation.h>
+#import "DDLog.h"
+
+@class DDLogFileInfo;
+
+/**
+ * Welcome to Cocoa Lumberjack!
+ * 
+ * The project page has a wealth of documentation if you have any questions.
+ * https://github.com/robbiehanson/CocoaLumberjack
+ * 
+ * If you're new to the project you may wish to read the "Getting Started" wiki.
+ * https://github.com/robbiehanson/CocoaLumberjack/wiki/GettingStarted
+ * 
+ * 
+ * This class provides a logger to write log statements to a file.
+**/
+
+
+// Default configuration and safety/sanity values.
+// 
+// maximumFileSize         -> DEFAULT_LOG_MAX_FILE_SIZE
+// rollingFrequency        -> DEFAULT_LOG_ROLLING_FREQUENCY
+// maximumNumberOfLogFiles -> DEFAULT_LOG_MAX_NUM_LOG_FILES
+// 
+// You should carefully consider the proper configuration values for your application.
+
+#define DEFAULT_LOG_MAX_FILE_SIZE     (1024 * 1024)   //  1 MB
+#define DEFAULT_LOG_ROLLING_FREQUENCY (60 * 60 * 24)  // 24 Hours
+#define DEFAULT_LOG_MAX_NUM_LOG_FILES (5)             //  5 Files
+
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+#pragma mark -
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+// The LogFileManager protocol is designed to allow you to control all aspects of your log files.
+// 
+// The primary purpose of this is to allow you to do something with the log files after they have been rolled.
+// Perhaps you want to compress them to save disk space.
+// Perhaps you want to upload them to an FTP server.
+// Perhaps you want to run some analytics on the file.
+// 
+// A default LogFileManager is, of course, provided.
+// The default LogFileManager simply deletes old log files according to the maximumNumberOfLogFiles property.
+// 
+// This protocol provides various methods to fetch the list of log files.
+// 
+// There are two variants: sorted and unsorted.
+// If sorting is not necessary, the unsorted variant is obviously faster.
+// The sorted variant will return an array sorted by when the log files were created,
+// with the most recently created log file at index 0, and the oldest log file at the end of the array.
+// 
+// You can fetch only the log file paths (full path including name), log file names (name only),
+// or an array of DDLogFileInfo objects.
+// The DDLogFileInfo class is documented below, and provides a handy wrapper that
+// gives you easy access to various file attributes such as the creation date or the file size.
+
+@protocol DDLogFileManager <NSObject>
+@required
+
+// Public properties
+
+/**
+ * The maximum number of archived log files to keep on disk.
+ * For example, if this property is set to 3,
+ * then the LogFileManager will only keep 3 archived log files (plus the current active log file) on disk.
+ * Once the active log file is rolled/archived, then the oldest of the existing 3 rolled/archived log files is deleted.
+ * 
+ * You may optionally disable deleting old/rolled/archived log files by setting this property to zero.
+**/
+@property (readwrite, assign) NSUInteger maximumNumberOfLogFiles;
+
+// Public methods
+
+- (NSString *)logsDirectory;
+
+- (NSArray *)unsortedLogFilePaths;
+- (NSArray *)unsortedLogFileNames;
+- (NSArray *)unsortedLogFileInfos;
+
+- (NSArray *)sortedLogFilePaths;
+- (NSArray *)sortedLogFileNames;
+- (NSArray *)sortedLogFileInfos;
+
+// Private methods (only to be used by DDFileLogger)
+
+- (NSString *)createNewLogFile;
+
+@optional
+
+// Notifications from DDFileLogger
+
+- (void)didArchiveLogFile:(NSString *)logFilePath;
+- (void)didRollAndArchiveLogFile:(NSString *)logFilePath;
+
+@end
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+#pragma mark -
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+/**
+ * Default log file manager.
+ * 
+ * All log files are placed inside the logsDirectory.
+ * If a specific logsDirectory isn't specified, the default directory is used.
+ * On Mac, this is in ~/Library/Logs/<Application Name>.
+ * On iPhone, this is in ~/Library/Caches/Logs.
+ * 
+ * Log files are named "log-<uuid>.txt",
+ * where uuid is a 6 character hexadecimal consisting of the set [0123456789ABCDEF].
+ * 
+ * Archived log files are automatically deleted according to the maximumNumberOfLogFiles property.
+**/
+@interface DDLogFileManagerDefault : NSObject <DDLogFileManager>
+{
+	NSUInteger maximumNumberOfLogFiles;
+	NSString *_logsDirectory;
+}
+
+- (id)init;
+- (id)initWithLogsDirectory:(NSString *)logsDirectory;
+
+/* Inherited from DDLogFileManager protocol:
+
+@property (readwrite, assign) NSUInteger maximumNumberOfLogFiles;
+
+- (NSString *)logsDirectory;
+
+- (NSArray *)unsortedLogFilePaths;
+- (NSArray *)unsortedLogFileNames;
+- (NSArray *)unsortedLogFileInfos;
+
+- (NSArray *)sortedLogFilePaths;
+- (NSArray *)sortedLogFileNames;
+- (NSArray *)sortedLogFileInfos;
+
+*/
+
+@end
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+#pragma mark -
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+/**
+ * Most users will want file log messages to be prepended with the date and time.
+ * Rather than forcing the majority of users to write their own formatter,
+ * we will supply a logical default formatter.
+ * Users can easily replace this formatter with their own by invoking the setLogFormatter method.
+ * It can also be removed by calling setLogFormatter, and passing a nil parameter.
+ * 
+ * In addition to the convenience of having a logical default formatter,
+ * it will also provide a template that makes it easy for developers to copy and change.
+**/
+@interface DDLogFileFormatterDefault : NSObject <DDLogFormatter>
+{
+	NSDateFormatter *dateFormatter;
+}
+
+- (id)init;
+- (id)initWithDateFormatter:(NSDateFormatter *)dateFormatter;
+
+@end
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+#pragma mark -
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+@interface DDFileLogger : DDAbstractLogger <DDLogger>
+{
+	__strong id <DDLogFileManager> logFileManager;
+	
+	DDLogFileInfo *currentLogFileInfo;
+	NSFileHandle *currentLogFileHandle;
+	
+	dispatch_source_t rollingTimer;
+	
+	unsigned long long maximumFileSize;
+	NSTimeInterval rollingFrequency;
+}
+
+- (id)init;
+- (id)initWithLogFileManager:(id <DDLogFileManager>)logFileManager;
+
+/**
+ * Log File Rolling:
+ * 
+ * maximumFileSize:
+ *   The approximate maximum size to allow log files to grow.
+ *   If a log file is larger than this value after a log statement is appended,
+ *   then the log file is rolled.
+ * 
+ * rollingFrequency
+ *   How often to roll the log file.
+ *   The frequency is given as an NSTimeInterval, which is a double that specifies the interval in seconds.
+ *   Once the log file gets to be this old, it is rolled.
+ * 
+ * Both the maximumFileSize and the rollingFrequency are used to manage rolling.
+ * Whichever occurs first will cause the log file to be rolled.
+ * 
+ * For example:
+ * The rollingFrequency is 24 hours,
+ * but the log file surpasses the maximumFileSize after only 20 hours.
+ * The log file will be rolled at that 20 hour mark.
+ * A new log file will be created, and the 24 hour timer will be restarted.
+ * 
+ * You may optionally disable rolling due to filesize by setting maximumFileSize to zero.
+ * If you do so, rolling is based solely on rollingFrequency.
+ * 
+ * You may optionally disable rolling due to time by setting rollingFrequency to zero (or any non-positive number).
+ * If you do so, rolling is based solely on maximumFileSize.
+ * 
+ * If you disable both maximumFileSize and rollingFrequency, then the log file won't ever be rolled.
+ * This is strongly discouraged.
+**/
+@property (readwrite, assign) unsigned long long maximumFileSize;
+@property (readwrite, assign) NSTimeInterval rollingFrequency;
+
+/**
+ * The DDLogFileManager instance can be used to retrieve the list of log files,
+ * and configure the maximum number of archived log files to keep.
+ * 
+ * @see DDLogFileManager.maximumNumberOfLogFiles
+**/
+@property (strong, nonatomic, readonly) id <DDLogFileManager> logFileManager;
+
+
+// You can optionally force the current log file to be rolled with this method.
+
+- (void)rollLogFile;
+
+// Inherited from DDAbstractLogger
+
+// - (id <DDLogFormatter>)logFormatter;
+// - (void)setLogFormatter:(id <DDLogFormatter>)formatter;
+
+@end
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+#pragma mark -
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+/**
+ * DDLogFileInfo is a simple class that provides access to various file attributes.
+ * It provides good performance as it only fetches the information if requested,
+ * and it caches the information to prevent duplicate fetches.
+ * 
+ * It was designed to provide quick snapshots of the current state of log files,
+ * and to help sort log files in an array.
+ * 
+ * This class does not monitor the files, or update it's cached attribute values if the file changes on disk.
+ * This is not what the class was designed for.
+ * 
+ * If you absolutely must get updated values,
+ * you can invoke the reset method which will clear the cache.
+**/
+@interface DDLogFileInfo : NSObject
+{
+	__strong NSString *filePath;
+	__strong NSString *fileName;
+	
+	__strong NSDictionary *fileAttributes;
+	
+	__strong NSDate *creationDate;
+	__strong NSDate *modificationDate;
+	
+	unsigned long long fileSize;
+}
+
+@property (strong, nonatomic, readonly) NSString *filePath;
+@property (strong, nonatomic, readonly) NSString *fileName;
+
+@property (strong, nonatomic, readonly) NSDictionary *fileAttributes;
+
+@property (strong, nonatomic, readonly) NSDate *creationDate;
+@property (strong, nonatomic, readonly) NSDate *modificationDate;
+
+@property (nonatomic, readonly) unsigned long long fileSize;
+
+@property (nonatomic, readonly) NSTimeInterval age;
+
+@property (nonatomic, readwrite) BOOL isArchived;
+
++ (id)logFileWithPath:(NSString *)filePath;
+
+- (id)initWithFilePath:(NSString *)filePath;
+
+- (void)reset;
+- (void)renameFile:(NSString *)newFileName;
+
+#if TARGET_IPHONE_SIMULATOR
+
+// So here's the situation.
+// Extended attributes are perfect for what we're trying to do here (marking files as archived).
+// This is exactly what extended attributes were designed for.
+// 
+// But Apple screws us over on the simulator.
+// Everytime you build-and-go, they copy the application into a new folder on the hard drive,
+// and as part of the process they strip extended attributes from our log files.
+// Normally, a copy of a file preserves extended attributes.
+// So obviously Apple has gone to great lengths to piss us off.
+// 
+// Thus we use a slightly different tactic for marking log files as archived in the simulator.
+// That way it "just works" and there's no confusion when testing.
+// 
+// The difference in method names is indicative of the difference in functionality.
+// On the simulator we add an attribute by appending a filename extension.
+// 
+// For example:
+// log-ABC123.txt -> log-ABC123.archived.txt
+
+- (BOOL)hasExtensionAttributeWithName:(NSString *)attrName;
+
+- (void)addExtensionAttributeWithName:(NSString *)attrName;
+- (void)removeExtensionAttributeWithName:(NSString *)attrName;
+
+#else
+
+// Normal use of extended attributes used everywhere else,
+// such as on Macs and on iPhone devices.
+
+- (BOOL)hasExtendedAttributeWithName:(NSString *)attrName;
+
+- (void)addExtendedAttributeWithName:(NSString *)attrName;
+- (void)removeExtendedAttributeWithName:(NSString *)attrName;
+
+#endif
+
+- (NSComparisonResult)reverseCompareByCreationDate:(DDLogFileInfo *)another;
+- (NSComparisonResult)reverseCompareByModificationDate:(DDLogFileInfo *)another;
+
+@end

+ 601 - 0
CycriptLoader/theos/include/DDLog.h

@@ -0,0 +1,601 @@
+#import <Foundation/Foundation.h>
+
+/**
+ * Welcome to Cocoa Lumberjack!
+ * 
+ * The project page has a wealth of documentation if you have any questions.
+ * https://github.com/robbiehanson/CocoaLumberjack
+ * 
+ * If you're new to the project you may wish to read the "Getting Started" wiki.
+ * https://github.com/robbiehanson/CocoaLumberjack/wiki/GettingStarted
+ * 
+ * Otherwise, here is a quick refresher.
+ * There are three steps to using the macros:
+ * 
+ * Step 1:
+ * Import the header in your implementation file:
+ * 
+ * #import "DDLog.h"
+ * 
+ * Step 2:
+ * Define your logging level in your implementation file:
+ * 
+ * // Log levels: off, error, warn, info, verbose
+ * static const int ddLogLevel = LOG_LEVEL_VERBOSE;
+ * 
+ * Step 3:
+ * Replace your NSLog statements with DDLog statements according to the severity of the message.
+ * 
+ * NSLog(@"Fatal error, no dohickey found!"); -> DDLogError(@"Fatal error, no dohickey found!");
+ * 
+ * DDLog works exactly the same as NSLog.
+ * This means you can pass it multiple variables just like NSLog.
+**/
+
+
+@class DDLogMessage;
+
+@protocol DDLogger;
+@protocol DDLogFormatter;
+
+/**
+ * This is the single macro that all other macros below compile into.
+ * This big multiline macro makes all the other macros easier to read.
+**/
+
+#define LOG_MACRO(isAsynchronous, lvl, flg, ctx, atag, fnct, frmt, ...) \
+  [DDLog log:isAsynchronous                                             \
+       level:lvl                                                        \
+        flag:flg                                                        \
+     context:ctx                                                        \
+        file:__FILE__                                                   \
+    function:fnct                                                       \
+        line:__LINE__                                                   \
+         tag:atag                                                       \
+      format:(frmt), ##__VA_ARGS__]
+
+/**
+ * Define the Objective-C and C versions of the macro.
+ * These automatically inject the proper function name for either an objective-c method or c function.
+ * 
+ * We also define shorthand versions for asynchronous and synchronous logging.
+**/
+
+#define LOG_OBJC_MACRO(async, lvl, flg, ctx, frmt, ...) \
+             LOG_MACRO(async, lvl, flg, ctx, nil, sel_getName(_cmd), frmt, ##__VA_ARGS__)
+
+#define LOG_C_MACRO(async, lvl, flg, ctx, frmt, ...) \
+          LOG_MACRO(async, lvl, flg, ctx, nil, __FUNCTION__, frmt, ##__VA_ARGS__)
+
+#define  SYNC_LOG_OBJC_MACRO(lvl, flg, ctx, frmt, ...) \
+              LOG_OBJC_MACRO( NO, lvl, flg, ctx, frmt, ##__VA_ARGS__)
+
+#define ASYNC_LOG_OBJC_MACRO(lvl, flg, ctx, frmt, ...) \
+              LOG_OBJC_MACRO(YES, lvl, flg, ctx, frmt, ##__VA_ARGS__)
+
+#define  SYNC_LOG_C_MACRO(lvl, flg, ctx, frmt, ...) \
+              LOG_C_MACRO( NO, lvl, flg, ctx, frmt, ##__VA_ARGS__)
+
+#define ASYNC_LOG_C_MACRO(lvl, flg, ctx, frmt, ...) \
+              LOG_C_MACRO(YES, lvl, flg, ctx, frmt, ##__VA_ARGS__)
+
+/**
+ * Define version of the macro that only execute if the logLevel is above the threshold.
+ * The compiled versions essentially look like this:
+ * 
+ * if (logFlagForThisLogMsg & ddLogLevel) { execute log message }
+ * 
+ * As shown further below, Lumberjack actually uses a bitmask as opposed to primitive log levels.
+ * This allows for a great amount of flexibility and some pretty advanced fine grained logging techniques.
+ * 
+ * Note that when compiler optimizations are enabled (as they are for your release builds),
+ * the log messages above your logging threshold will automatically be compiled out.
+ * 
+ * (If the compiler sees ddLogLevel declared as a constant, the compiler simply checks to see if the 'if' statement
+ *  would execute, and if not it strips it from the binary.)
+ * 
+ * We also define shorthand versions for asynchronous and synchronous logging.
+**/
+
+#define LOG_MAYBE(async, lvl, flg, ctx, fnct, frmt, ...) \
+  do { if(lvl & flg) LOG_MACRO(async, lvl, flg, ctx, nil, fnct, frmt, ##__VA_ARGS__); } while(0)
+
+#define LOG_OBJC_MAYBE(async, lvl, flg, ctx, frmt, ...) \
+             LOG_MAYBE(async, lvl, flg, ctx, sel_getName(_cmd), frmt, ##__VA_ARGS__)
+
+#define LOG_C_MAYBE(async, lvl, flg, ctx, frmt, ...) \
+          LOG_MAYBE(async, lvl, flg, ctx, __FUNCTION__, frmt, ##__VA_ARGS__)
+
+#define  SYNC_LOG_OBJC_MAYBE(lvl, flg, ctx, frmt, ...) \
+              LOG_OBJC_MAYBE( NO, lvl, flg, ctx, frmt, ##__VA_ARGS__)
+
+#define ASYNC_LOG_OBJC_MAYBE(lvl, flg, ctx, frmt, ...) \
+              LOG_OBJC_MAYBE(YES, lvl, flg, ctx, frmt, ##__VA_ARGS__)
+
+#define  SYNC_LOG_C_MAYBE(lvl, flg, ctx, frmt, ...) \
+              LOG_C_MAYBE( NO, lvl, flg, ctx, frmt, ##__VA_ARGS__)
+
+#define ASYNC_LOG_C_MAYBE(lvl, flg, ctx, frmt, ...) \
+              LOG_C_MAYBE(YES, lvl, flg, ctx, frmt, ##__VA_ARGS__)
+
+/**
+ * Define versions of the macros that also accept tags.
+ * 
+ * The DDLogMessage object includes a 'tag' ivar that may be used for a variety of purposes.
+ * It may be used to pass custom information to loggers or formatters.
+ * Or it may be used by 3rd party extensions to the framework.
+ * 
+ * Thes macros just make it a little easier to extend logging functionality.
+**/
+
+#define LOG_OBJC_TAG_MACRO(async, lvl, flg, ctx, tag, frmt, ...) \
+                 LOG_MACRO(async, lvl, flg, ctx, tag, sel_getName(_cmd), frmt, ##__VA_ARGS__)
+
+#define LOG_C_TAG_MACRO(async, lvl, flg, ctx, tag, frmt, ...) \
+              LOG_MACRO(async, lvl, flg, ctx, tag, __FUNCTION__, frmt, ##__VA_ARGS__)
+
+#define LOG_TAG_MAYBE(async, lvl, flg, ctx, tag, fnct, frmt, ...) \
+  do { if(lvl & flg) LOG_MACRO(async, lvl, flg, ctx, tag, fnct, frmt, ##__VA_ARGS__); } while(0)
+
+#define LOG_OBJC_TAG_MAYBE(async, lvl, flg, ctx, tag, frmt, ...) \
+             LOG_TAG_MAYBE(async, lvl, flg, ctx, tag, sel_getName(_cmd), frmt, ##__VA_ARGS__)
+
+#define LOG_C_TAG_MAYBE(async, lvl, flg, ctx, tag, frmt, ...) \
+          LOG_TAG_MAYBE(async, lvl, flg, ctx, tag, __FUNCTION__, frmt, ##__VA_ARGS__)
+
+/**
+ * Define the standard options.
+ * 
+ * We default to only 4 levels because it makes it easier for beginners
+ * to make the transition to a logging framework.
+ * 
+ * More advanced users may choose to completely customize the levels (and level names) to suite their needs.
+ * For more information on this see the "Custom Log Levels" page:
+ * https://github.com/robbiehanson/CocoaLumberjack/wiki/CustomLogLevels
+ * 
+ * Advanced users may also notice that we're using a bitmask.
+ * This is to allow for custom fine grained logging:
+ * https://github.com/robbiehanson/CocoaLumberjack/wiki/FineGrainedLogging
+ * 
+ * -- Flags --
+ * 
+ * Typically you will use the LOG_LEVELS (see below), but the flags may be used directly in certain situations.
+ * For example, say you have a lot of warning log messages, and you wanted to disable them.
+ * However, you still needed to see your error and info log messages.
+ * You could accomplish that with the following:
+ * 
+ * static const int ddLogLevel = LOG_FLAG_ERROR | LOG_FLAG_INFO;
+ * 
+ * Flags may also be consulted when writing custom log formatters,
+ * as the DDLogMessage class captures the individual flag that caused the log message to fire.
+ * 
+ * -- Levels --
+ * 
+ * Log levels are simply the proper bitmask of the flags.
+ * 
+ * -- Booleans --
+ * 
+ * The booleans may be used when your logging code involves more than one line.
+ * For example:
+ * 
+ * if (LOG_VERBOSE) {
+ *     for (id sprocket in sprockets)
+ *         DDLogVerbose(@"sprocket: %@", [sprocket description])
+ * }
+ * 
+ * -- Async --
+ * 
+ * Defines the default asynchronous options.
+ * The default philosophy for asynchronous logging is very simple:
+ * 
+ * Log messages with errors should be executed synchronously.
+ *     After all, an error just occurred. The application could be unstable.
+ * 
+ * All other log messages, such as debug output, are executed asynchronously.
+ *     After all, if it wasn't an error, then it was just informational output,
+ *     or something the application was easily able to recover from.
+ * 
+ * -- Changes --
+ * 
+ * You are strongly discouraged from modifying this file.
+ * If you do, you make it more difficult on yourself to merge future bug fixes and improvements from the project.
+ * Instead, create your own MyLogging.h or ApplicationNameLogging.h or CompanyLogging.h
+ * 
+ * For an example of customizing your logging experience, see the "Custom Log Levels" page:
+ * https://github.com/robbiehanson/CocoaLumberjack/wiki/CustomLogLevels
+**/
+
+#define LOG_FLAG_ERROR    (1 << 0)  // 0...0001
+#define LOG_FLAG_WARN     (1 << 1)  // 0...0010
+#define LOG_FLAG_INFO     (1 << 2)  // 0...0100
+#define LOG_FLAG_VERBOSE  (1 << 3)  // 0...1000
+
+#define LOG_LEVEL_OFF     0
+#define LOG_LEVEL_ERROR   (LOG_FLAG_ERROR)                                                    // 0...0001
+#define LOG_LEVEL_WARN    (LOG_FLAG_ERROR | LOG_FLAG_WARN)                                    // 0...0011
+#define LOG_LEVEL_INFO    (LOG_FLAG_ERROR | LOG_FLAG_WARN | LOG_FLAG_INFO)                    // 0...0111
+#define LOG_LEVEL_VERBOSE (LOG_FLAG_ERROR | LOG_FLAG_WARN | LOG_FLAG_INFO | LOG_FLAG_VERBOSE) // 0...1111
+
+#define LOG_ERROR   (ddLogLevel & LOG_FLAG_ERROR)
+#define LOG_WARN    (ddLogLevel & LOG_FLAG_WARN)
+#define LOG_INFO    (ddLogLevel & LOG_FLAG_INFO)
+#define LOG_VERBOSE (ddLogLevel & LOG_FLAG_VERBOSE)
+
+#define LOG_ASYNC_ENABLED YES
+
+#define LOG_ASYNC_ERROR   ( NO && LOG_ASYNC_ENABLED)
+#define LOG_ASYNC_WARN    (YES && LOG_ASYNC_ENABLED)
+#define LOG_ASYNC_INFO    (YES && LOG_ASYNC_ENABLED)
+#define LOG_ASYNC_VERBOSE (YES && LOG_ASYNC_ENABLED)
+
+#define DDLogError(frmt, ...)   LOG_OBJC_MAYBE(LOG_ASYNC_ERROR,   ddLogLevel, LOG_FLAG_ERROR,   0, frmt, ##__VA_ARGS__)
+#define DDLogWarn(frmt, ...)    LOG_OBJC_MAYBE(LOG_ASYNC_WARN,    ddLogLevel, LOG_FLAG_WARN,    0, frmt, ##__VA_ARGS__)
+#define DDLogInfo(frmt, ...)    LOG_OBJC_MAYBE(LOG_ASYNC_INFO,    ddLogLevel, LOG_FLAG_INFO,    0, frmt, ##__VA_ARGS__)
+#define DDLogVerbose(frmt, ...) LOG_OBJC_MAYBE(LOG_ASYNC_VERBOSE, ddLogLevel, LOG_FLAG_VERBOSE, 0, frmt, ##__VA_ARGS__)
+
+#define DDLogCError(frmt, ...)   LOG_C_MAYBE(LOG_ASYNC_ERROR,   ddLogLevel, LOG_FLAG_ERROR,   0, frmt, ##__VA_ARGS__)
+#define DDLogCWarn(frmt, ...)    LOG_C_MAYBE(LOG_ASYNC_WARN,    ddLogLevel, LOG_FLAG_WARN,    0, frmt, ##__VA_ARGS__)
+#define DDLogCInfo(frmt, ...)    LOG_C_MAYBE(LOG_ASYNC_INFO,    ddLogLevel, LOG_FLAG_INFO,    0, frmt, ##__VA_ARGS__)
+#define DDLogCVerbose(frmt, ...) LOG_C_MAYBE(LOG_ASYNC_VERBOSE, ddLogLevel, LOG_FLAG_VERBOSE, 0, frmt, ##__VA_ARGS__)
+
+/**
+ * The THIS_FILE macro gives you an NSString of the file name.
+ * For simplicity and clarity, the file name does not include the full path or file extension.
+ * 
+ * For example: DDLogWarn(@"%@: Unable to find thingy", THIS_FILE) -> @"MyViewController: Unable to find thingy"
+**/
+
+NSString *DDExtractFileNameWithoutExtension(const char *filePath, BOOL copy);
+
+#define THIS_FILE (DDExtractFileNameWithoutExtension(__FILE__, NO))
+
+/**
+ * The THIS_METHOD macro gives you the name of the current objective-c method.
+ * 
+ * For example: DDLogWarn(@"%@ - Requires non-nil strings", THIS_METHOD) -> @"setMake:model: requires non-nil strings"
+ * 
+ * Note: This does NOT work in straight C functions (non objective-c).
+ * Instead you should use the predefined __FUNCTION__ macro.
+**/
+
+#define THIS_METHOD NSStringFromSelector(_cmd)
+
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+#pragma mark -
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+@interface DDLog : NSObject
+
+/**
+ * Provides access to the underlying logging queue.
+ * This may be helpful to Logger classes for things like thread synchronization.
+**/
+
++ (dispatch_queue_t)loggingQueue;
+
+/**
+ * Logging Primitive.
+ * 
+ * This method is used by the macros above.
+ * It is suggested you stick with the macros as they're easier to use.
+**/
+
++ (void)log:(BOOL)synchronous
+      level:(int)level
+       flag:(int)flag
+    context:(int)context
+       file:(const char *)file
+   function:(const char *)function
+       line:(int)line
+        tag:(id)tag
+     format:(NSString *)format, ... __attribute__ ((format (__NSString__, 9, 10)));
+
+/**
+ * Logging Primitive.
+ * 
+ * This method can be used if you have a prepared va_list.
+**/
+
++ (void)log:(BOOL)asynchronous
+      level:(int)level
+       flag:(int)flag
+    context:(int)context
+       file:(const char *)file
+   function:(const char *)function
+       line:(int)line
+        tag:(id)tag
+     format:(NSString *)format
+       args:(va_list)argList;
+
+
+/**
+ * Since logging can be asynchronous, there may be times when you want to flush the logs.
+ * The framework invokes this automatically when the application quits.
+**/
+
++ (void)flushLog;
+
+/** 
+ * Loggers
+ * 
+ * If you want your log statements to go somewhere,
+ * you should create and add a logger.
+**/
+
++ (void)addLogger:(id <DDLogger>)logger;
++ (void)removeLogger:(id <DDLogger>)logger;
+
++ (void)removeAllLoggers;
+
+/**
+ * Registered Dynamic Logging
+ * 
+ * These methods allow you to obtain a list of classes that are using registered dynamic logging,
+ * and also provides methods to get and set their log level during run time.
+**/
+
++ (NSArray *)registeredClasses;
++ (NSArray *)registeredClassNames;
+
++ (int)logLevelForClass:(Class)aClass;
++ (int)logLevelForClassWithName:(NSString *)aClassName;
+
++ (void)setLogLevel:(int)logLevel forClass:(Class)aClass;
++ (void)setLogLevel:(int)logLevel forClassWithName:(NSString *)aClassName;
+
+@end
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+#pragma mark -
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+@protocol DDLogger <NSObject>
+@required
+
+- (void)logMessage:(DDLogMessage *)logMessage;
+
+/**
+ * Formatters may optionally be added to any logger.
+ * 
+ * If no formatter is set, the logger simply logs the message as it is given in logMessage,
+ * or it may use its own built in formatting style.
+**/
+- (id <DDLogFormatter>)logFormatter;
+- (void)setLogFormatter:(id <DDLogFormatter>)formatter;
+
+@optional
+
+/**
+ * Since logging is asynchronous, adding and removing loggers is also asynchronous.
+ * In other words, the loggers are added and removed at appropriate times with regards to log messages.
+ * 
+ * - Loggers will not receive log messages that were executed prior to when they were added.
+ * - Loggers will not receive log messages that were executed after they were removed.
+ * 
+ * These methods are executed in the logging thread/queue.
+ * This is the same thread/queue that will execute every logMessage: invocation.
+ * Loggers may use these methods for thread synchronization or other setup/teardown tasks.
+**/
+- (void)didAddLogger;
+- (void)willRemoveLogger;
+
+/**
+ * Some loggers may buffer IO for optimization purposes.
+ * For example, a database logger may only save occasionaly as the disk IO is slow.
+ * In such loggers, this method should be implemented to flush any pending IO.
+ * 
+ * This allows invocations of DDLog's flushLog method to be propogated to loggers that need it.
+ * 
+ * Note that DDLog's flushLog method is invoked automatically when the application quits,
+ * and it may be also invoked manually by the developer prior to application crashes, or other such reasons.
+**/
+- (void)flush;
+
+/**
+ * Each logger is executed concurrently with respect to the other loggers.
+ * Thus, a dedicated dispatch queue is used for each logger.
+ * Logger implementations may optionally choose to provide their own dispatch queue.
+**/
+- (dispatch_queue_t)loggerQueue;
+
+/**
+ * If the logger implementation does not choose to provide its own queue,
+ * one will automatically be created for it.
+ * The created queue will receive its name from this method.
+ * This may be helpful for debugging or profiling reasons.
+**/
+- (NSString *)loggerName;
+
+@end
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+#pragma mark -
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+@protocol DDLogFormatter <NSObject>
+@required
+
+/**
+ * Formatters may optionally be added to any logger.
+ * This allows for increased flexibility in the logging environment.
+ * For example, log messages for log files may be formatted differently than log messages for the console.
+ * 
+ * For more information about formatters, see the "Custom Formatters" page:
+ * https://github.com/robbiehanson/CocoaLumberjack/wiki/CustomFormatters
+ * 
+ * The formatter may also optionally filter the log message by returning nil,
+ * in which case the logger will not log the message.
+**/
+- (NSString *)formatLogMessage:(DDLogMessage *)logMessage;
+
+@optional
+
+/**
+ * A single formatter instance can be added to multiple loggers.
+ * These methods provides hooks to notify the formatter of when it's added/removed.
+ *
+ * This is primarily for thread-safety.
+ * If a formatter is explicitly not thread-safe, it may wish to throw an exception if added to multiple loggers.
+ * Or if a formatter has potentially thread-unsafe code (e.g. NSDateFormatter),
+ * it could possibly use these hooks to switch to thread-safe versions of the code.
+**/
+- (void)didAddToLogger:(id <DDLogger>)logger;
+- (void)willRemoveFromLogger:(id <DDLogger>)logger;
+
+@end
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+#pragma mark -
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+@protocol DDRegisteredDynamicLogging
+
+/**
+ * Implement these methods to allow a file's log level to be managed from a central location.
+ * 
+ * This is useful if you'd like to be able to change log levels for various parts
+ * of your code from within the running application.
+ * 
+ * Imagine pulling up the settings for your application,
+ * and being able to configure the logging level on a per file basis.
+ * 
+ * The implementation can be very straight-forward:
+ * 
+ * + (int)ddLogLevel
+ * {
+ *     return ddLogLevel;
+ * }
+ *  
+ * + (void)ddSetLogLevel:(int)logLevel
+ * {
+ *     ddLogLevel = logLevel;
+ * }
+**/
+
++ (int)ddLogLevel;
++ (void)ddSetLogLevel:(int)logLevel;
+
+@end
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+#pragma mark -
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+/**
+ * The DDLogMessage class encapsulates information about the log message.
+ * If you write custom loggers or formatters, you will be dealing with objects of this class.
+**/
+
+enum {
+	DDLogMessageCopyFile     = 1 << 0,
+	DDLogMessageCopyFunction = 1 << 1
+};
+typedef int DDLogMessageOptions;
+
+@interface DDLogMessage : NSObject
+{
+
+// The public variables below can be accessed directly (for speed).
+// For example: logMessage->logLevel
+	
+@public
+	int logLevel;
+	int logFlag;
+	int logContext;
+	NSString *logMsg;
+	NSDate *timestamp;
+	char *file;
+	char *function;
+	int lineNumber;
+	mach_port_t machThreadID;
+    char *queueLabel;
+	NSString *threadName;
+	
+	// For 3rd party extensions to the framework, where flags and contexts aren't enough.
+	id tag;
+	
+	// For 3rd party extensions that manually create DDLogMessage instances.
+	DDLogMessageOptions options;
+}
+
+/**
+ * Standard init method for a log message object.
+ * Used by the logging primitives. (And the macros use the logging primitives.)
+ * 
+ * If you find need to manually create logMessage objects, there is one thing you should be aware of:
+ * 
+ * If no flags are passed, the method expects the file and function parameters to be string literals.
+ * That is, it expects the given strings to exist for the duration of the object's lifetime,
+ * and it expects the given strings to be immutable.
+ * In other words, it does not copy these strings, it simply points to them.
+ * This is due to the fact that __FILE__ and __FUNCTION__ are usually used to specify these parameters,
+ * so it makes sense to optimize and skip the unnecessary allocations.
+ * However, if you need them to be copied you may use the options parameter to specify this.
+ * Options is a bitmask which supports DDLogMessageCopyFile and DDLogMessageCopyFunction.
+**/
+- (id)initWithLogMsg:(NSString *)logMsg
+               level:(int)logLevel
+                flag:(int)logFlag
+             context:(int)logContext
+                file:(const char *)file
+            function:(const char *)function
+                line:(int)line
+                 tag:(id)tag
+             options:(DDLogMessageOptions)optionsMask;
+
+/**
+ * Returns the threadID as it appears in NSLog.
+ * That is, it is a hexadecimal value which is calculated from the machThreadID.
+**/
+- (NSString *)threadID;
+
+/**
+ * Convenience property to get just the file name, as the file variable is generally the full file path.
+ * This method does not include the file extension, which is generally unwanted for logging purposes.
+**/
+- (NSString *)fileName;
+
+/**
+ * Returns the function variable in NSString form.
+**/
+- (NSString *)methodName;
+
+@end
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+#pragma mark -
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+/**
+ * The DDLogger protocol specifies that an optional formatter can be added to a logger.
+ * Most (but not all) loggers will want to support formatters.
+ * 
+ * However, writting getters and setters in a thread safe manner,
+ * while still maintaining maximum speed for the logging process, is a difficult task.
+ * 
+ * To do it right, the implementation of the getter/setter has strict requiremenets:
+ * - Must NOT require the logMessage method to acquire a lock.
+ * - Must NOT require the logMessage method to access an atomic property (also a lock of sorts).
+ * 
+ * To simplify things, an abstract logger is provided that implements the getter and setter.
+ * 
+ * Logger implementations may simply extend this class,
+ * and they can ACCESS THE FORMATTER VARIABLE DIRECTLY from within their logMessage method!
+**/
+
+@interface DDAbstractLogger : NSObject <DDLogger>
+{
+	id <DDLogFormatter> formatter;
+	
+	dispatch_queue_t loggerQueue;
+}
+
+- (id <DDLogFormatter>)logFormatter;
+- (void)setLogFormatter:(id <DDLogFormatter>)formatter;
+
+// For thread-safety assertions
+- (BOOL)isOnGlobalLoggingQueue;
+- (BOOL)isOnInternalLoggerQueue;
+
+@end

+ 12 - 0
CycriptLoader/theos/include/DDNumber.h

@@ -0,0 +1,12 @@
+#import <Foundation/Foundation.h>
+
+
+@interface NSNumber (DDNumber)
+
++ (BOOL)parseString:(NSString *)str intoSInt64:(SInt64 *)pNum;
++ (BOOL)parseString:(NSString *)str intoUInt64:(UInt64 *)pNum;
+
++ (BOOL)parseString:(NSString *)str intoNSInteger:(NSInteger *)pNum;
++ (BOOL)parseString:(NSString *)str intoNSUInteger:(NSUInteger *)pNum;
+
+@end

+ 56 - 0
CycriptLoader/theos/include/DDRange.h

@@ -0,0 +1,56 @@
+/**
+ * DDRange is the functional equivalent of a 64 bit NSRange.
+ * The HTTP Server is designed to support very large files.
+ * On 32 bit architectures (ppc, i386) NSRange uses unsigned 32 bit integers.
+ * This only supports a range of up to 4 gigabytes.
+ * By defining our own variant, we can support a range up to 16 exabytes.
+ * 
+ * All effort is given such that DDRange functions EXACTLY the same as NSRange.
+**/
+
+#import <Foundation/NSValue.h>
+#import <Foundation/NSObjCRuntime.h>
+
+@class NSString;
+
+typedef struct _DDRange {
+    UInt64 location;
+    UInt64 length;
+} DDRange;
+
+typedef DDRange *DDRangePointer;
+
+NS_INLINE DDRange DDMakeRange(UInt64 loc, UInt64 len) {
+    DDRange r;
+    r.location = loc;
+    r.length = len;
+    return r;
+}
+
+NS_INLINE UInt64 DDMaxRange(DDRange range) {
+    return (range.location + range.length);
+}
+
+NS_INLINE BOOL DDLocationInRange(UInt64 loc, DDRange range) {
+    return (loc - range.location < range.length);
+}
+
+NS_INLINE BOOL DDEqualRanges(DDRange range1, DDRange range2) {
+    return ((range1.location == range2.location) && (range1.length == range2.length));
+}
+
+FOUNDATION_EXPORT DDRange DDUnionRange(DDRange range1, DDRange range2);
+FOUNDATION_EXPORT DDRange DDIntersectionRange(DDRange range1, DDRange range2);
+FOUNDATION_EXPORT NSString *DDStringFromRange(DDRange range);
+FOUNDATION_EXPORT DDRange DDRangeFromString(NSString *aString);
+
+NSInteger DDRangeCompare(DDRangePointer pDDRange1, DDRangePointer pDDRange2);
+
+@interface NSValue (NSValueDDRangeExtensions)
+
++ (NSValue *)valueWithDDRange:(DDRange)range;
+- (DDRange)ddrangeValue;
+
+- (NSInteger)ddrangeCompare:(NSValue *)ddrangeValue;
+
+@end

+ 167 - 0
CycriptLoader/theos/include/DDTTYLogger.h

@@ -0,0 +1,167 @@
+#import <Foundation/Foundation.h>
+#if TARGET_OS_IPHONE
+#import <UIKit/UIColor.h>
+#else
+#import <AppKit/NSColor.h>
+#endif
+
+#import "DDLog.h"
+
+/**
+ * Welcome to Cocoa Lumberjack!
+ * 
+ * The project page has a wealth of documentation if you have any questions.
+ * https://github.com/robbiehanson/CocoaLumberjack
+ * 
+ * If you're new to the project you may wish to read the "Getting Started" wiki.
+ * https://github.com/robbiehanson/CocoaLumberjack/wiki/GettingStarted
+ * 
+ * 
+ * This class provides a logger for Terminal output or Xcode console output,
+ * depending on where you are running your code.
+ * 
+ * As described in the "Getting Started" page,
+ * the traditional NSLog() function directs it's output to two places:
+ * 
+ * - Apple System Log (so it shows up in Console.app)
+ * - StdErr (if stderr is a TTY, so log statements show up in Xcode console)
+ * 
+ * To duplicate NSLog() functionality you can simply add this logger and an asl logger.
+ * However, if you instead choose to use file logging (for faster performance),
+ * you may choose to use only a file logger and a tty logger.
+**/
+
+@interface DDTTYLogger : DDAbstractLogger <DDLogger>
+{
+	NSCalendar *calendar;
+	NSUInteger calendarUnitFlags;
+	
+	NSString *appName;
+	char *app;
+	size_t appLen;
+	
+	NSString *processID;
+	char *pid;
+	size_t pidLen;
+	
+	BOOL colorsEnabled;
+	NSMutableArray *colorProfilesArray;
+	NSMutableDictionary *colorProfilesDict;
+}
+
++ (DDTTYLogger *)sharedInstance;
+
+/* Inherited from the DDLogger protocol:
+ * 
+ * Formatters may optionally be added to any logger.
+ * 
+ * If no formatter is set, the logger simply logs the message as it is given in logMessage,
+ * or it may use its own built in formatting style.
+ * 
+ * More information about formatters can be found here:
+ * https://github.com/robbiehanson/CocoaLumberjack/wiki/CustomFormatters
+ * 
+ * The actual implementation of these methods is inherited from DDAbstractLogger.
+
+- (id <DDLogFormatter>)logFormatter;
+- (void)setLogFormatter:(id <DDLogFormatter>)formatter;
+ 
+*/
+
+/**
+ * Want to use different colors for different log levels?
+ * Enable this property.
+ * 
+ * If you run the application via the Terminal (not Xcode),
+ * the logger will map colors to xterm-256color or xterm-color (if available).
+ * 
+ * Xcode does NOT natively support colors in the Xcode debugging console.
+ * You'll need to install the XcodeColors plugin to see colors in the Xcode console.
+ * https://github.com/robbiehanson/XcodeColors
+ * 
+ * The default value if NO.
+**/
+@property (readwrite, assign) BOOL colorsEnabled;
+
+/**
+ * The default color set (foregroundColor, backgroundColor) is:
+ * 
+ * - LOG_FLAG_ERROR = (red, nil)
+ * - LOG_FLAG_WARN  = (orange, nil)
+ * 
+ * You can customize the colors however you see fit.
+ * Please note that you are passing a flag, NOT a level.
+ * 
+ * GOOD : [ttyLogger setForegroundColor:pink backgroundColor:nil forFlag:LOG_FLAG_INFO];  // <- Good :)
+ *  BAD : [ttyLogger setForegroundColor:pink backgroundColor:nil forFlag:LOG_LEVEL_INFO]; // <- BAD! :(
+ * 
+ * LOG_FLAG_INFO  = 0...00100
+ * LOG_LEVEL_INFO = 0...00111 <- Would match LOG_FLAG_INFO and LOG_FLAG_WARN and LOG_FLAG_ERROR
+ * 
+ * If you run the application within Xcode, then the XcodeColors plugin is required.
+ * 
+ * If you run the application from a shell, then DDTTYLogger will automatically map the given color to
+ * the closest available color. (xterm-256color or xterm-color which have 256 and 16 supported colors respectively.)
+ * 
+ * This method invokes setForegroundColor:backgroundColor:forFlag:context: and passes the default context (0).
+**/
+#if TARGET_OS_IPHONE
+- (void)setForegroundColor:(UIColor *)txtColor backgroundColor:(UIColor *)bgColor forFlag:(int)mask;
+#else
+- (void)setForegroundColor:(NSColor *)txtColor backgroundColor:(NSColor *)bgColor forFlag:(int)mask;
+#endif
+
+/**
+ * Just like setForegroundColor:backgroundColor:flag, but allows you to specify a particular logging context.
+ * 
+ * A logging context is often used to identify log messages coming from a 3rd party framework,
+ * although logging context's can be used for many different functions.
+ * 
+ * Logging context's are explained in further detail here:
+ * https://github.com/robbiehanson/CocoaLumberjack/wiki/CustomContext
+**/
+#if TARGET_OS_IPHONE
+- (void)setForegroundColor:(UIColor *)txtColor backgroundColor:(UIColor *)bgColor forFlag:(int)mask context:(int)ctxt;
+#else
+- (void)setForegroundColor:(NSColor *)txtColor backgroundColor:(NSColor *)bgColor forFlag:(int)mask context:(int)ctxt;
+#endif
+
+/**
+ * Similar to the methods above, but allows you to map DDLogMessage->tag to a particular color profile.
+ * For example, you could do something like this:
+ * 
+ * static NSString *const PurpleTag = @"PurpleTag";
+ * 
+ * #define DDLogPurple(frmt, ...) LOG_OBJC_TAG_MACRO(NO, 0, 0, 0, PurpleTag, frmt, ##__VA_ARGS__)
+ * 
+ * And then in your applicationDidFinishLaunching, or wherever you configure Lumberjack:
+ * 
+ * #if TARGET_OS_IPHONE
+ *   UIColor *purple = [UIColor colorWithRed:(64/255.0) green:(0/255.0) blue:(128/255.0) alpha:1.0];
+ * #else
+ *   NSColor *purple = [NSColor colorWithCalibratedRed:(64/255.0) green:(0/255.0) blue:(128/255.0) alpha:1.0];
+ * 
+ * [[DDTTYLogger sharedInstance] setForegroundColor:purple backgroundColor:nil forTag:PurpleTag];
+ * [DDLog addLogger:[DDTTYLogger sharedInstance]];
+ * 
+ * This would essentially give you a straight NSLog replacement that prints in purple:
+ * 
+ * DDLogPurple(@"I'm a purple log message!");
+**/
+#if TARGET_OS_IPHONE
+- (void)setForegroundColor:(UIColor *)txtColor backgroundColor:(UIColor *)bgColor forTag:(id <NSCopying>)tag;
+#else
+- (void)setForegroundColor:(NSColor *)txtColor backgroundColor:(NSColor *)bgColor forTag:(id <NSCopying>)tag;
+#endif
+
+/**
+ * Clearing color profiles.
+**/
+- (void)clearColorsForFlag:(int)mask;
+- (void)clearColorsForFlag:(int)mask context:(int)context;
+- (void)clearColorsForTag:(id <NSCopying>)tag;
+- (void)clearColorsForAllFlags;
+- (void)clearColorsForAllTags;
+- (void)clearAllColors;
+
+@end

+ 19 - 0
CycriptLoader/theos/include/DHCommon.h

@@ -0,0 +1,19 @@
+#import <Foundation/Foundation.h>
+#import <objc/runtime.h>
+
+/* Common, useful things.
+ * A bit has been lifted from rpetrich's Captain Hook macros. Thanks, Ryan!
+ */
+#define _Constructor __attribute__((constructor))
+#define DHLateClass(name) @class name; static Class $ ## name = objc_getClass(#name)
+#define DHEarlyClass(name) static Class $ ## name = [name class]
+#define DHClass(name) $ ## name
+
+static inline void _DHRelease(id object) __attribute__((always_inline));
+static inline void _DHRelease(id object) {
+	[object release];
+}
+#define DHScopeReleased __attribute__((cleanup(_DHRelease)))
+#define DHScopedAutoreleasePool() NSAutoreleasePool *DHScopedAutoreleasePool __attribute__((cleanup(_DHRelease),unused)) = [[NSAutoreleasePool alloc] init]
+
+// vim:ft=objc

+ 141 - 0
CycriptLoader/theos/include/DHHookCommon.h

@@ -0,0 +1,141 @@
+#import <DHCommon.h>
+#import <substrate.h>
+#import <objc/runtime.h>
+#import <string.h>
+
+/*
+ * Many thanks to ashikase+saurik for the original HOOK/CALL_ORIG macros.
+ */
+
+/*
+ * All hook names are created/specified with $ in place of : for selector names.
+ * init::: -> init$$$
+ * destroyChildren:withMethod: -> destroyChildren$withMethod$
+ * init -> init
+ */
+
+/*
+ * HOOK(class, name, type, args...)
+ *
+ * Example:
+ * 	HOOK(Class, init, id) {
+ * 	  ...
+ * 	}
+ *
+ * 	HOOK(Class, initWithFrame$andOtherThing$, id, CGRect frame, id otherThing) {
+ * 	  ...
+ * 	}
+ *
+ * Creates a static variable (in the form of _class$name) to store the original message address, and a function to replace it,
+ * in the form of $class$name.
+ * type is the return type, and args are all the message arguments, in order; args is optional.
+ */
+#define HOOK(class, name, type, args...) \
+	static type (*_ ## class ## $ ## name)(class *self, SEL sel, ## args); \
+	static type $ ## class ## $ ## name(class *self, SEL sel, ## args)
+
+#define IMPLEMENTATION(class, name, type, args...) \
+	static type $ ## class ## $ ## name(class *self, SEL sel, ## args)
+/*
+ * CALL_ORIG(class, name, args...)
+ *
+ * Example:
+ * 	CALL_ORIG(Class, init);
+ * 	CALL_ORIG(Class, initWithFrame$andOtherThing$, frame, otherThing);
+ *
+ * Calls an original implementation (_class$name).
+ */
+#define CALL_ORIG(class, name, args...) \
+	_ ## class ## $ ## name(self, sel, ## args)
+
+/*
+ * GET_CLASS(class)
+ *
+ * Example:
+ * 	GET_CLASS(UIToolbarButton);
+ *
+ * Simply creates a variable (named $class) to store a class for the HOOK_MESSAGE_* macros.
+ * To avoid having to call objc_getClass over and over, and to provide a uniform naming scheme.
+ */
+#define GET_CLASS(class) \
+	Class $ ## class = objc_getClass(#class)
+
+/*
+ * HOOK_MESSAGE(class, sel)
+ *
+ * Example:
+ * 	HOOK_MESSAGE(Class, init);
+ *
+ * Saves the original implementation of sel to a static variable named after _class$sel (created with HOOK), after
+ * replacing it with $class$sel (created with HOOK).
+ *
+ * This exists because sometimes you just want to hook a message with no args, without having to specify a replacement
+ * or call __getsel
+ */
+#define HOOK_MESSAGE(class, sel) \
+	_ ## class ## $ ## sel = MSHookMessage(DHClass(class), @selector(sel), &$ ## class ## $ ## sel) 
+
+#define ADD_MESSAGE(class, sel) \
+	MSHookMessage(DHClass(class), @selector(sel), &$ ## class ## $ ## sel) 
+
+/*
+ * HOOK_MESSAGE_WITH_SINGLE_ARG(class, sel)
+ *
+ * Example:
+ * 	HOOK_MESSAGE_WITH_SINGLE_ARG(Class, initWithFrame);
+ *
+ * Shorthand for HOOK_MESSAGE_REPLACEMENT(Class, sel:, sel$)
+ */
+#define HOOK_MESSAGE_WITH_SINGLE_ARG(class, sel) \
+	_ ## class ## $ ## sel ## $ = MSHookMessage(DHClass(class), @selector(sel:), &$ ## class ## $ ## sel ## $) 
+
+static inline SEL __getsel(const char *in) __attribute__((always_inline));
+static inline SEL __getsel(const char *in) {
+	int len = strlen(in) + 1;
+	char selector[len];
+	for(int i = 0; i < len; i++)
+		selector[i] = (in[i] == '$' ? ':' : in[i]);
+	return sel_getUid(selector);
+}
+/*
+ * HOOK_MESSAGE_AUTO(class, replace)
+ *
+ * Example:
+ * 	HOOK_MESSAGE_AUTO(Class, initWithFrame$andOtherThing$andAnotherThing$);
+ *
+ * Beware, __getsel (string copy/transform) is called every time this macro is used.
+ * Automatically turns a replacement selector in the $ format into a SEL, as a shorter form of HOOK_MESSAGE_REPLACEMENT.
+ *
+ * Saves the original implementation to a static variable named after _class$replace (created with HOOK), after
+ * replacing it with $class$replace (created with HOOK).
+ */
+#define HOOK_MESSAGE_AUTO(class, replace) \
+	_ ## class ## $ ## replace = MSHookMessage(DHClass(class), __getsel(#replace), &$ ## class ## $ ## replace)
+#define ADD_MESSAGE_AUTO(class, replace) \
+	MSHookMessage(DHClass(class), __getsel(#replace), &$ ## class ## $ ## replace)
+
+/*
+ * HOOK_MESSAGE_REPLACEMENT(class, sel, replace)
+ *
+ * Example:
+ * 	HOOK_MESSAGE_REPLACEMENT(Class, initWithFrame:andOtherThing:andAnotherThing:, initWithFrame$andOtherThing$andAnotherThing$);
+ *
+ * Saves the original implementation to a static variable named after _class$replace (created with HOOK), after
+ * replacing it with $class$replace (created with HOOK).
+ */
+#define HOOK_MESSAGE_REPLACEMENT(class, sel, replace) \
+	_ ## class ## $ ## replace = MSHookMessage(DHClass(class), @selector(sel), &$ ## class ## $ ## replace)
+
+#define ADD_MESSAGE_REPLACEMENT(class, sel, replace) \
+	MSHookMessage(DHClass(class), @selector(sel), &$ ## class ## $ ## replace)
+
+#define HOOK_MESSAGE_ARGS HOOK_MESSAGE_WITH_SINGLE_ARG
+#define HOOK_MESSAGE_EX HOOK_MESSAGE_AUTO
+#define HOOK_MESSAGE_F HOOK_MESSAGE_REPLACEMENT
+#define ADD_MESSAGE_F ADD_MESSAGE_REPLACEMENT
+
+#define DHGetClass GET_CLASS
+#define DHHookMessageWithReplacement HOOK_MESSAGE_REPLACEMENT
+#define DHHookMessageWithAutoRename HOOK_MESSAGE_AUTO
+#define DHHookMessage HOOK_MESSAGE_AUTO
+#define DHAddMessage ADD_MESSAGE_AUTO

+ 0 - 0
CycriptLoader/theos/include/DispatchQueueLogFormatter.h


Some files were not shown because too many files changed in this diff