Y_Less

new y_hooks.inc

Mar 19th, 2014
391
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Pawn 9.23 KB | None | 0 0
  1. enum E_HOOK_NAME_REPLACEMENT_DATA
  2. {
  3.     E_HOOK_NAME_REPLACEMENT_SHORT[4],
  4.     E_HOOK_NAME_REPLACEMENT_LONG[11],
  5.     E_HOOK_NAME_REPLACEMENT_MIN,
  6.     E_HOOK_NAME_REPLACEMENT_LEN
  7. }
  8.  
  9. static stock
  10.     YSI_g_sReplacements[][E_HOOK_NAME_REPLACEMENT_DATA] =
  11.         {
  12.             {"CP",  "Checkpoint", 2, 10},
  13.             {"Dyn", "Dynamic",    3, 7},
  14.             {"TD",  "TextDraw",   2, 8},
  15.             {"Upd", "Update",     3, 6},
  16.             {"Obj", "Object",     3, 6},
  17.             {"Cmd", "Command",    3, 6},
  18.         };
  19.  
  20. stock Hooks_MakeLongName(name[64])
  21. {
  22.     new
  23.         len,
  24.         i = 0,
  25.         pos = -1;
  26.     while (i != sizeof (YSI_g_sReplacements))
  27.     {
  28.         if ((pos = strfind(name, YSI_g_sReplacements[i][E_HOOK_NAME_REPLACEMENT_SHORT], false, pos + 1)) != -1)
  29.         {
  30.             // Try this same string again.  We may have found a different word.
  31.             if ('a' <= name[(len = pos + YSI_g_sReplacements[i][E_HOOK_NAME_REPLACEMENT_MIN])] <= 'z') continue;
  32.             else
  33.             {
  34.                 // Found a complete word according to CamelCase rules.
  35.                 strdel(name, pos, len),
  36.                 strins(name, YSI_g_sReplacements[i][E_HOOK_NAME_REPLACEMENT_LONG], pos),
  37.                 pos = -1;
  38.             }
  39.             else continue;
  40.         }
  41.         ++i;
  42.     }
  43.     // It is possible for the expansions to become TOO big.
  44.     return Hooks_MakeShortName(name);
  45. }
  46.  
  47. Test:Hooks_MakeLongName0()
  48. {
  49.     new
  50.         name[64];
  51.     name = "OnUpd";
  52.     ASSERT(Hooks_MakeLongName(name) == 8);
  53.     ASSERT(!strcmp(name, "OnUpdate"));
  54.     name = "OnUpdD";
  55.     ASSERT(Hooks_MakeLongName(name) == 9);
  56.     ASSERT(!strcmp(name, "OnUpdateD"));
  57.     name = "OnUpda";
  58.     ASSERT(Hooks_MakeLongName(name) == 6);
  59.     ASSERT(!strcmp(name, "OnUpda"));
  60. }
  61.  
  62. Test:Hooks_MakeLongName1()
  63. {
  64.     new
  65.         name[64];
  66.     name = "CP";
  67.     ASSERT(Hooks_MakeLongName(name) == 10);
  68.     ASSERT(!strcmp(name, "Checkpoint"));
  69.     name = "TD";
  70.     ASSERT(Hooks_MakeLongName(name) == 8);
  71.     ASSERT(!strcmp(name, "TextDraw"));
  72.     name = "Upd";
  73.     ASSERT(Hooks_MakeLongName(name) == 6);
  74.     ASSERT(!strcmp(name, "Update"));
  75.     name = "Dyn";
  76.     ASSERT(Hooks_MakeLongName(name) == 7);
  77.     ASSERT(!strcmp(name, "Dynamic"));
  78.     name = "Obj";
  79.     ASSERT(Hooks_MakeLongName(name) == 6);
  80.     ASSERT(!strcmp(name, "Object"));
  81.     name = "Cmd";
  82.     ASSERT(Hooks_MakeLongName(name) == 7);
  83.     ASSERT(!strcmp(name, "Command"));
  84. }
  85.  
  86. Test:Hooks_MakeLongName2()
  87. {
  88.     new
  89.         name[64];
  90.     name = "OnUpdTDCP";
  91.     ASSERT(Hooks_MakeLongName(name) == 26);
  92.     ASSERT(!strcmp(name, "OnUpdateTextDrawCheckpoint"));
  93.     name = "OnUpdTDObjCmd";
  94.     ASSERT(Hooks_MakeLongName(name) == 29);
  95.     ASSERT(!strcmp(name, "OnUpdateTextDrawObjectCommand"));
  96.     name = "OnUpdTDCPObjCmd";
  97.     ASSERT(Hooks_MakeLongName(name) == 31);
  98.     ASSERT(!strcmp(name, "OnUpdateTextDrawCPObjectCommand"));
  99. }
  100.  
  101. stock Hooks_MakeShortName0(name[64])
  102. {
  103.     // Easy one.
  104.     new
  105.         len = strlen(name);
  106.     if (len >= 32)
  107.     {
  108.         new
  109.             pos,
  110.             i = 0;
  111.         do
  112.         {
  113.             if ((pos = strfind(name, YSI_g_sReplacements[i][E_HOOK_NAME_REPLACEMENT_LONG])) != -1)
  114.             {
  115.                 strdel(name, pos, pos + YSI_g_sReplacements[i][E_HOOK_NAME_REPLACEMENT_LEN]),
  116.                 strins(name, YSI_g_sReplacements[i][E_HOOK_NAME_REPLACEMENT_SHORT], pos);
  117.             }
  118.         }
  119.         while ((len = strlen(name)) >= 32 && ++i != sizeof (YSI_g_sReplacements));
  120.     }
  121.     return len;
  122. }
  123.  
  124. Test:Hooks_MakeShortName1()
  125. {
  126.     new
  127.         name[64];
  128.     name = "OnPlayerEnterRaceCP";
  129.     ASSERT(Hooks_MakeShortName(name) == 19);
  130.     ASSERT(!strcmp(name, "OnPlayerEnterRaceCP"));
  131.     name = "OnPlayerEnterRaceCheckpoint";
  132.     ASSERT(Hooks_MakeShortName(name) == 27);
  133.     ASSERT(!strcmp(name, "OnPlayerEnterRaceCheckpoint"));
  134.     name = "OnPlayerEnterDynamicRaceCheckpoint";
  135.     ASSERT(Hooks_MakeShortName(name) == 25);
  136.     ASSERT(!strcmp(name, "OnPlayerEnterDynamicRaceCP"));
  137.     name = "AAAAAAAAAAAAAAAAAAAUpdateTextDraw";
  138.     Hooks_MakeShortName(name);
  139.     ASSERT(!strcmp(name, "AAAAAAAAAAAAAAAAAAAUpdateTD"));
  140.     name = "BBBBBAAAAAAAAAAAAAAAAAAAUpdateTextDraw";
  141.     Hooks_MakeShortName(name);
  142.     ASSERT(!strcmp(name, "BBBBBAAAAAAAAAAAAAAAAAAAUpdTD"));
  143. }
  144.  
  145. Test:Hooks_MakeShortName2()
  146. {
  147.     new
  148.         name[64];
  149.     name = "AAAAAAAAAAAAAABBBBBBBBBBBBBBBBCCCCCCCCCCCCC";
  150.     ASSERT(Hooks_MakeShortName(name) == 43);
  151.     ASSERT(!strcmp(name, "AAAAAAAAAAAAAABBBBBBBBBBBBBBBBCCCCCCCCCCCCC"));
  152.     name = "AAAAAAAAAAAAAABBBBBBBBBBBBBBBBCCCCCCCCCommandCCCC";
  153.     ASSERT(Hooks_MakeShortName(name) == 45);
  154.     ASSERT(!strcmp(name, "AAAAAAAAAAAAAABBBBBBBBBBBBBBBBCCCCCCCCCmdCCCC"));
  155. }
  156.  
  157.  
  158.  
  159.  
  160.  
  161.  
  162.  
  163. // Get rid of the "@yH_" prefix and "@" suffix and change "CP" into "Checkpoint"
  164. // etc.
  165. #define Hooks_MakeBaseName(%0) ( \
  166.     Hooks_IsolateName(name)    , \
  167.     Hooks_MakeLongName(name)   )
  168.  
  169. static stock Hooks_Collate(name[64], &idx)
  170. {
  171.     // For this function, note that:
  172.     //  
  173.     //   hook OnPlayerConnect(playerid)
  174.     //  
  175.     // Compiles as:
  176.     //  
  177.     //   public @yH_OnPlayerConnect@XXX(playerid)
  178.     //  
  179.     // Where "XXX" is some unique number (the exact value is irrelevant, it just
  180.     // means that multiple hooks of the same function have different names).
  181.     static
  182.         sBase[64],
  183.         sHooks[128];
  184.     // Isolate the common prefix part:
  185.     //  
  186.     //   @yH_OnPlayerConnect@042
  187.     //  
  188.     // Becomes:
  189.     //  
  190.     //   @yH_OnPlayerConnect@
  191.     //  
  192.     // The numbers at the end are irrelevant, now we can just search for hooks
  193.     // of this exact callback.
  194.     name[strfind(name, "@", false, 4) + 1] = '\0',
  195.     // The above now becomes:
  196.     //  
  197.     //   OnPlayerConnect
  198.     //  
  199.     // This also handles cases such as:
  200.     //  
  201.     //   @yH_OnPlayerEnterRaceCheckpoint@162
  202.     //  
  203.     // Being invalid (too long), so instead converts the shortened:
  204.     //  
  205.     //   @yH_OnPlayerEnterRaceCP@162
  206.     //  
  207.     // To:
  208.     //  
  209.     //   OnPlayerEnterRaceCheckpoint
  210.     //  
  211.     // Thus expanding common name length reductions.
  212.     sBase = name,
  213.     Hooks_MakeBaseName(sBase);
  214.     new
  215.         // See if the original function exists.
  216.         original = funcidx(sBase),
  217.         // See if a fixes.inc hook exists.
  218.         fixes = Hooks_GetFixesFunc(sBase),
  219.         // Get all the hooks of this type.  They are stored alphabetically.
  220.         hookCount = Hooks_GetAllHooks(name, sHooks, idx);
  221.     // We now have:
  222.     //  
  223.     //  1) All the hooks of this function.
  224.     //  2) The original function if it exists.
  225.     //  3) The FIXES_ ALS chained function if fixes.inc exists.
  226.     //  
  227.     // This took huge chunks of complex code in the old version.  Now not so
  228.     // much!  I don't know if this code is faster (I suspect it is), but it is
  229.     // absolutely simpler!
  230.     // Get the AMX header entry from the public function index.
  231.     original = (original == -1) ? (0) : (AMX_GetEntryFromPublicIndex(original)),
  232.     // Get the AMX header entry from the public function index.
  233.     fixes    = (fixes    == -1) ? (0) : (AMX_GetEntryFromPublicIndex(fixes   ));
  234.     new
  235.         stub = Hooks_GenerateStub(fixes ? Hooks_GetFixesChain(fixes) : AMX_GetEntryPointer(original), sHooks, hookCount);
  236.     return Hooks_MakePublicPointer(original, fixes, stub, name, sBase);
  237. }
  238.  
  239. static stock Hooks_GetFixesChain(stub)
  240. {
  241.     // Get the address of the next function from the FIXES_ ALS state stub.
  242.     new
  243.         ctx[DisasmContext];
  244.     DisasmInit(ctx, stub);
  245.     switch (DisasmNextInsn(ctx))
  246.     {
  247.         case OP_LOAD_PRI:
  248.         {  
  249.             if (DisasmNextInsn(ctx) == OP_SWITCH && DisasmNextInsn(ctx) == OP_CASETBL)
  250.             {
  251.                 // Get the number of items in the casetable.
  252.                 if (DisasmGetNumOperands(ctx) == 3) // 2 means no used hook.
  253.                 {
  254.                     // Got a hook to return.  Find it.
  255.                     new
  256.                         h0 = DisasmGetOperand(ctx, 3),
  257.                         h1 = DisasmGetOperand(ctx, 5),
  258.                         h2 = DisasmGetOperand(ctx, 7);
  259.                     if (h1 == h2)      return h0; // Most likely.
  260.                     else if (h0 == h2) return h1;
  261.                     else if (h0 == h1) return h2;
  262.                 }
  263.             }
  264.         }
  265.         case OP_JUMP:
  266.         {
  267.             // Already replaced once (shouldn't happen, but may if two different
  268.             // hooks use two different short versions of a callback).
  269.             return DisasmGetOperand(ctx, 0);
  270.         }
  271.     }
  272.     return 0;
  273. }
  274.  
  275. static stock Hooks_MakePublicPointer(original, fixes, func, const hname[], const name[])
  276. {
  277.     // We need to create an AMX header entry for "name", e.g. point
  278.     // "OnPlayerConnect" at the correct function.
  279.     if (fixes)
  280.     {
  281.         // Here, "fixes" points to the second item in the ALS chain.  "original"
  282.         // points to the actual callback in "fixes.inc", which if it exists
  283.         // means that we don't need to rewrite anything in the header, just
  284.         // rewrite the states stub.
  285.         // There is a remote chance that the stub has already been rewritten
  286.         // once, in which case just replace that old jump with the new one.
  287.         // Other code will need to account for that case to correct call the
  288.         // remainder of the chain.
  289.         return Hooks_RedirectFixes(fixes, func);
  290.     }
  291.     else if (original)
  292.     {
  293.         // No "fixes.inc", but this callback already exists.  In that case, just
  294.         // replace the pointer address.
  295.         AMX_SetHeaderPOinter(original, func);
  296.     }
  297. }
  298.  
  299. static stock Hooks_GetAllHooks(const name[], hooks[128], &idx)
  300. {
  301.     // Start from the very start - repeats the first item.
  302.     new
  303.         count,
  304.         i = idx - 1;
  305.     while ((i = AMX_GetPublicEntry(i, hooks[count], name)))
  306.     {
  307.         Hooks_InvalidateName(hooks[count]),
  308.         idx = i;
  309.         if (++count == sizeof (hooks))
  310.         {
  311.             P:W("Hooks_GetAllHooks: Potential overflow.");
  312.             break;
  313.         }
  314.     }
  315.     return count;
  316. }
  317.  
  318. static stock Hooks_GetFixesFunc(const name[64])
  319. {
  320.     static
  321.         fn[64];
  322.     return
  323.         fn = "FIXES_",
  324.         strcat(fn, name),
  325.         Hooks_MakeShortName(fn),
  326.         funcidx(fn);
  327. }
  328.  
  329. // Main loop
  330. static
  331.     name[64];
  332. new
  333.     idx;
  334. // Get the next hook type.
  335. while ((idx = AMX_GetPublicNamePrefix(idx, name, _A<@yH_>)))
  336. {
  337.     // Collect all the hooks of this function, and rewrite the call code.
  338.     Hooks_Collate(name, idx);
  339. }
Advertisement
Add Comment
Please, Sign In to add comment