Tool Native Library Generator (C/C++ to B4A)

logo.png

Native Library Generator 4.20 (2018-11-11)
Written in B4J, this program allows you to write or import C/C++ code and have all the functions compiled into a native (.so) library, which in turn is included in a ready-to-use B4A Java lib. When using already existing code, if present, the main() function will be automatically ignored. If you're familiar with C/C++ but not with JNI or NDK, this is the right tool for you! No JAVA required.

Requirements:

Open Source:
This project is open source, under the GNU General Public License. Enjoy! :)
https://gitlab.com/brunowonder/NativeLibraryGenerator-CommunityEdition

Price (pay what you want):
If you wish to buy me a beer (or even dinner!) just follow the link below.
https://www.paypal.me/ninjadynamics
0317.png
0317.png
0317.png

How does it work:
upload_2017-10-27_15-57-1-png.61061


Video Demos:

Updates:
[Version 4.21] [2018-11-12] [CRITICAL]
QuickSource mode fixed
For background music add "nlg.mp3" to the NLG folder ;)

[Version 4.20] [2018-11-11] [NEW FEATURES]
Now supporting multiple source files
Select which files should be exposed to B4A
Requires NDK r18b (please update)
Bug fixes

[Version 4.01] [2017-05-07] [NEW FEATURES]
The 'cpu-features' library can now be used
Custom Makefiles may now be used
Custom Java wrappers may now be used
Bug fixes

[Version 4.00] [2017-05-07] [NEW FEATURES]
Complete visual overhaul
Specifying additional include paths is now possible
Specifying additional prebuilt libraries is now possible
Specifying the target ABI's is now possible
Compatible ABI's are now auto-detected if possible
Handling
multiple projects is now possible

[Version 3.0] [2017-05-07] [NEW FEATURES]
Returning arrays is now possible.
B4A logging with printf() is now possible.


[Version 2.9] [2016-08-12] [NEW FEATURES]
Small UI redesign and bug fixes.
Code clean-up.

Little bit more user-friendly.
Custom makefiles.

[Version 2.8] [2016-07-12] [NEW FEATURES]
Now supporting local #include files.
Now supporting external project locations.
New video demo.
Minor bug fixes.

[Version 2.7] [2016-03-14] [CRITICAL]
Major bug fixes.

[Version 2.6] [2016-01-31] [IMPORTANT]
Important bug fixes.
MazeSolver 1.5 Included as example source code.

[Version 2.5] [2016-01-31] [NEW FEATURES]
Now supporting comment transcription from C++ to B4A.
New splash screen.
Minor bug fixes.

[Version 2.4] [2016-01-27] [CRITICAL]
Critical bug fix regarding string (char*) support.
Cool new intro/exit screens added.


[Version 2.3] [2016-01-25] [NEW FEATURES]
Now supporting Strings (char*), both passing and returning.

[Version 2.2] [2016-01-20] [IMPORTANT]
Now supporting simple C/C++ typedef struct.
Now supporting C/C++ inline functions.

Minor bug fixes.

[Version 2.1] [
2016-01-12] [CRITICAL]
Included example (NinjaCore) source code updated. Several bug fixes.

[Version 2.1] [2016-01-12] [IMPORTANT]
Now supporting C++ headers, such as <vector> or <algorithm>.

[Version 2.0] [2016-01-10] [CRITICAL]
Major issue corrected. Please download Native Library Generator again.

Included Example:

In order to showcase this software's capabilities, I decided to include my MazeSolver project.

A. Download link:

B. Instructions (QuickSource Mode):
In QuickSouce mode all you have to do is write some code and hit the Generate Library button.

1. Before anything else, please make sure you have installed the following required software:
B4A, Simple Library Compiler and Android NDK


2. Download the .jar file into a system-writable folder (NOT Program Files).

3. Run NLG and provide the necessary software paths, as seen below.
upload_2018-11-12_11-56-16.png


4. Compile the example by clicking the big blue button.
upload_2018-11-12_11-56-37.png



5. Test the library you just compiled with this B4A project:
https://www.b4x.com/android/forum/t...orithm-w-path-optimization.61998/#post-391230

6. As you can see, it works!
upload_2018-11-12_12-14-11.png

C. LibFastMath Example code (Copy/Paste to NLG):
B4X:
//LibFastMath 1.00 - Native Library Example

//FastSin() and FastCos() by Allen Chou
//http://allenchou.net/2014/02/game-math-faster-sine-cosine-with-polynomial-curves

//FastSqrt() adapted from Quake 3's Fast Inverse Square Root algorithm
//https://en.wikipedia.org/wiki/Fast_inverse_square_root

#define PI         (3.1415926535f)
#define HALF_PI    (0.5f * PI)
#define TWO_PI     (2.0f * PI)
#define TWO_PI_INV (1.0f / TWO_PI)

float FastSin(float x);
float FastCos(float x);
float FastSqrt(float x);

inline float Hill(float x)
{
  const float a0 = 1.0f;
  const float a2 = 2.0f / PI - 12.0f / (PI * PI);
  const float a3 = 16.0f / (PI * PI * PI) - 4.0f / (PI * PI);
  const float xx = x * x;
  const float xxx = xx * x;

  return a0 + a2 * xx + a3 * xxx;
}

float FastSin(float x)
{
  // wrap x within [0, TWO_PI)
  const float a = x * TWO_PI_INV;
  x -= static_cast<int>(a) * TWO_PI;
  if (x < 0.0f)
    x += TWO_PI;

  // 4 pieces of hills
  if (x < HALF_PI)
    return Hill(HALF_PI - x);
  else if (x < PI)
    return Hill(x - HALF_PI);
  else if (x < 3.0f * HALF_PI)
    return -Hill(3.0f * HALF_PI - x);
  else
    return -Hill(x - 3.0f * HALF_PI);
}

float FastCos(float x)
{
  return FastSin(x + HALF_PI);
}

float FastSqrt(float x)
{
    //This is the method used in Quake3
    const float xhalf = 0.5f*x;

    //Get bits for floating value
    union
    {
        float x;
        int i;
    } u;
    u.x = x;

    //Give initial guess y0
    u.i = 0x5f3759df - (u.i >> 1);

    //Newton step, repeating increases accuracy
    return (x*u.x*(1.5f - xhalf*u.x*u.x));
}

D. How does it work:
Initially, I created this program in order to speed-up the process of writing JNI C/C++ code. Following B4A's RAD philosophy, it allows me to write native code in Visual Studio and compile it into a fully-working B4A lib within a single click.
E. Internal Functions:
If you wish any of your native function not to be exposed in the B4A library, you may do so by either changing their name from foo() into privateFoo() or simply adding a "::ignore" the function's comments.
B4X:
//This function will not be visible in B4A because its name starts with "private".
int privateSum(int a, int b)
{
    return a + b;
}

//This function will not be visible in B4A because this comment contains the keyword "::ignore".
int multiplication(int a, int b)
{
    return a * b;
}

//This function will be exposed in B4A.
int result(int a, int b)
{
    return privateSum(a, b) + multiplication(a, b);
}
F. Current Limitations:
As happy as I am to share this work with the B4x community, let's not forget that this is just my own internal tool, a never ending work-in-progress personal project.
Hence, it does not yet support several features such as passing Arrays into the native layer.
G. Reminder:
Please test your C/C++ code before trying to build a B4A library, as some kinds of syntax errors may crash the application.
 

Attachments

  • upload_2018-11-12_11-53-30.png
    upload_2018-11-12_11-53-30.png
    88.2 KB · Views: 425
Last edited:

wonder

Expert
Licensed User
Longtime User
...and done! NLG 2.3 released. :D

We are now allowed to pass and return strings at will.

Example code:
B4X:
#include <string>

char* test(char* param)
{  
    if (strcmp(param, "12345") == 0) {
        return "ok";
    }
    else {
        return param;
    }
}

Enjoy! ;)
 

wonder

Expert
Licensed User
Longtime User
We are now allowed to pass and return strings at will.
Well, not exactly. At least, not yet. Sorry.

Although the example above works perfectly, I've detected some issues upon using more complex functions.
I was able to fix the code this morning, but I still want to run a few more tests.

========================================================

Alright, 2.4 is out. ;)

Despite my best efforts, string support is limited to char* type.
If you want to use C++ <std::string> functions you'll have convert from/into char* before usage and/or return.
 

JTmartins

Active Member
Licensed User
Longtime User
Hi Wonder,

Windows 10Pro 64bit and your tool Version 2.6 here.

Just tried your tool, as I would like to test some stuff and see how it behaves in Android in c++

I have NDK installed and configured. Running ok from eclipse.

When I try your tool, I get a NDK compilation FAILED (copied & pasted the LibFastMath 1.00 - Native Library Example)

In your tool I have put this values

[LIB] C:\Program Files (x86)\Anywhere Software\Basic4android\Extras-Lib (this is where my extra libs reside)
[NDK] C:\android-ndk-r10e (this where I have the NDK)
[SLC] C:\Program Files (x86)\Anywhere Software\SimpleLibraryCompiler (this is where I've placed SLC)

if I go to the folder where I have your tool installed wich is C:\B4A Tools and then workspace and run the compile.bat it starts compiling the mazesolver !!

Can you help me on this.

Many thanks.

JM

** UPDATE **

I renamed the source.cpp in there (the maze) and run your tool again. Same error.
However when I now run compile manually it does compile teste.cpp (the name I gave to the test).

The output of compile is as follows

C:\B4A Tools>workspace\compile.bat

C:\B4A Tools>path C:\ProgramData\Oracle\Java\javapath;C:\WINDOWS\system32;C:\WINDOWS;C:\WINDOWS\System32\Wbem;C:\WINDOWS\System32\WindowsPowerShell\v1.0\;C:\Program Files\Microsoft SQL Server\110\Tools\Binn\;C:\Program Files\Microsoft SQL Server\120\Tools\Binn\;C:\Users\marti\.dnx\bin;C:\Program Files\Microsoft DNX\Dnvm\;C:\Program Files (x86)\nodejs\;C:\Program Files (x86)\Common Files\Acronis\SnapAPI\;C:\Program Files\Microsoft\Web Platform Installer\;C:\Program Files (x86)\Microsoft SDKs\Azure\CLI\wbin;C:\Program Files (x86)\MySQL\MySQL Fabric 1.5.4 ;C:\android-ndk-r10e;C:\android-ndk-r10e;C:\android-ndk-r10e;C:\android-ndk-r10e;C:\android-ndk-r10e
 
Last edited:

wonder

Expert
Licensed User
Longtime User
Can you help me on this.
Hello!

NLG works in a copy-paste-compile fashion. Once you have your paths properly set (which I believe you do), you just paste the C++ code you want to compile.
To clear the MazeSolver code, hit Ctrl+A and then Delete. This will clear the editor.
Once clear, paste the entire contents of "teste.cpp". If you created this file in Visual Studio, delete (or comment out) the line #include "stdafx.h".
The most recent compiled code will always be saved as "source.cpp" in the workspace folder.
Don't forget to set the Library Name, Author and Package Name as well.

A good way to organize multiple projects is having a separate copy of NLG for each one of your libraries. For example:
B4X:
- C:\My Native Libs\MazeSolver  <-- native_library_compiler_2_x.jar, \workspace, \project
- C:\My Native Libs\NinjaCore   <-- native_library_compiler_2_x.jar, \workspace, \project
- C:\My Native Libs\Foo         <-- native_library_compiler_2_x.jar, \workspace, \project
- C:\My Native Libs\Foo2        <-- native_library_compiler_2_x.jar, \workspace, \project

If necessary, I'll gladly make a tutorial video. :)
 
Last edited:

JTmartins

Active Member
Licensed User
Longtime User
Many thanks for your reply...So, I've tryed your C math example. CTRL+A, delete and pasted it into the code window.

Still getting the same error. However if I run the compile bat, manually, it does compile...

I attatch 2 screenshots, so it's easier for you to point what am I doing wrong

Screen 1 - NDK compilation failed.

ndk1.jpg


screen 2 - Running compile.bat manualy, does compile

ndk2.jpg
 

wonder

Expert
Licensed User
Longtime User
I've tried to replicate your problem.
So far it works fine for me:
B4X:
Name:    FastMath
Author:  Ninja Dynamics
Version: 1.50
Package: com.ninjadynamics.fastmath
[LIB] C:\Android\B4A External Libs
[NDK] C:\ProgramData\Microsoft\AndroidNDK\android-ndk-r10e
[SLC] C:\Program Files (x86)\Anywhere Software\SLC

OUTPUT:
[16:30:41] Ready.
[16:32:23] Working...
[16:32:24] Java file generated.
[16:32:24] JNI header file generated.
[16:32:24] JNI source file generated.
[16:32:24] Preparing to compile.
[16:32:38] Native library compiled.
[16:32:38] Deleting old JAR file.
[16:32:38] Deleting old XML file.
[16:32:42] B4A library compiled.

I'll dig into the code now, stay tunned.
 
Last edited:

wonder

Expert
Licensed User
Longtime User
Alright, let's try two things:

1) Since you can compile manually, the problem might be with the xcopy command. Please repeat the process by issuing "compile.bat" and upon successful compilation, issue:
"C:\B4A Tools\>xcopy workspace\libs project\additional\lib /e /h /y"
Let me know if you get any errors at this point.


2) I get an SLC compile error when I set the External Libs folder to (or somewhere inside) "C:\Program Files".
Could you create a "C:\Teste" folder and set "[LIB] C:\Teste", just to see if it works?
You must set your External Libs folder in B4A to "C:\Teste" as well.
 
Last edited:

JTmartins

Active Member
Licensed User
Longtime User
Step one..No problem. No error. It did copied 7 files.

I will try step 2 in a few minutes, and let you know how it goes.

EDIT

Same problem.

Created c:\teste
Copied all contents from extras-LIB to c:\teste
Went to B4A and changed external libs path to c:\teste
in your tool changed the [LIB] to c:\teste

hit compile...same message as before. NDK compilation failed.

I'm running Java 1.8.0_74 64 bit in this windows 10 machine.
 
Last edited:

wonder

Expert
Licensed User
Longtime User
There's must be something odd happening in here:
B4X:
Sub RunNDK
    Dim fileList As List
    fileList = File.ListFiles(File.DirApp)
    For Each item As String In fileList
        If item.EndsWith(".h") Or item.EndsWith(".c") Or item.EndsWith(".cpp") Then
            File.Copy(File.DirApp, item, File.DirApp & "\workspace", item)
            File.Delete(File.DirApp, item)
        End If
    Next
    Dim compileCommand, copyCommand As String   
    compileCommand = "path %PATH%;" & pathNDK & CRLF & _
                     "cd workspace" & CRLF & _
                     "ndk-build -B"                   
    copyCommand    = "xcopy workspace\libs project\additional\lib /e /h /y"   
    File.WriteString(File.DirApp, "compile.bat", compileCommand)
    File.WriteString(File.DirApp, "copylib.bat", copyCommand)   
    Dim ndk, xcopy As Shell       
    ndk.Initialize("ndk", "compile.bat", Null)
    xcopy.Initialize("xcopy", "copylib.bat", Null)   
    ndk.RunSynchronous(-1)   
    xcopy.RunSynchronous(-1)   
    File.Delete(File.DirApp, "copylib.bat")
    If File.ListFiles(File.DirApp & "\project\additional\lib").Size > 0 Then
        File.Delete(File.DirApp, "compile.bat")
        txtStatsBox.Text = txtStatsBox.Text & "[" & DateTime.Time(DateTime.Now) & "] Native library compiled." & CRLF       
    Else
        File.Copy(File.DirApp, "compile.bat", File.DirApp & "\workspace", "compile.bat")
        File.Delete(File.DirApp, "compile.bat")
        txtStatsBox.Text = txtStatsBox.Text & "[" & DateTime.Time(DateTime.Now) & "] NDK compilation FAILED." & CRLF
        txtStatsBox.Text = txtStatsBox.Text & "[" & DateTime.Time(DateTime.Now) & "] Run 'workspace\compile.bat' to see what went wrong." & CRLF
        ok = False       
    End If
End Sub

I'll review the code once again, I'm really sorry you're not being able to compile your project.

For me, everything works fine, as you can see in this tutorial/demo:
 

wonder

Expert
Licensed User
Longtime User

JTmartins

Active Member
Licensed User
Longtime User
Hi Wonder.

Just a quick question...I do understand the char pointer while passing and returning strings. But can we use std::strings inside the code or do we have to use char in every situation ?

I'm asking this as I have not been able to compile my sample code. It returns a char* however I'm using strings in other functions and NLG is hanging, although the code is running ok in the C compiler.

Many thanks
 

wonder

Expert
Licensed User
Longtime User
can we use std::strings inside the code
tumblr_md3p0xrgqy1r0z99do1_500.jpg


There are virtually no limitations to the code that goes inside a function, as long as you return the correct type.

Here's an example that works for me:
B4X:
char* cMapReadVector(uintptr_t cMapAddress, int x, int y)
{
    ContentMap *cMap = (ContentMap*)(cMapAddress);
    if (x >= cMap->sizeX || y >= cMap->sizeY || x < 0 || y < 0) {
        return "";
    }  
    int vectorIndex = ((y * cMap->sizeX) + x);
    std::string output;
    std::stringstream ss;
    for (unsigned int i = 0; i < cMap->contentClass[vectorIndex].size(); i++)
    {
        if (i != 0) {
            ss << " ";
        }
        //long long a = 1231239812;
        ss << std::to_string(cMap->contentClass[vectorIndex][i]) << ":";
        ss << std::to_string(cMap->contentType[vectorIndex][i]) << ":";
        ss << std::to_string(cMap->contentID[vectorIndex][i]);
        //ss << a;
    }
    output = ss.str();
    char* result = (char*)output.c_str();
    size_t allocSize = sizeof(result) * output.length();
    if (allocSize > 0) {
        cMap->outputString = (char*)realloc(cMap->outputString, allocSize);  
        strcpy(cMap->outputString, result);
        return cMap->outputString;
    }
    else {
        return "";
    }
}

Ok, I know it looks a little bit confusing, but here's the deal, unless you want to do some pointer/address black magic (like me) the easiest way is:
1) Have a Global char* variable
2) Realloc() its memory to hold your std::string content
3) Strcpy() from one to the other
4) Return char*​

Remember, if you don't have a global variable, you local variable will go out of scope and the returned content will be garbage.
 

JTmartins

Active Member
Licensed User
Longtime User
Well I'm getting this, altough the code is working ok with gcc. One file only now.

jni/include\teste.h:11:16: error: 'string' in namespace 'std' does not name a type
JNIEXPORT std::string JNICALL Java_com_teste_teste_teste_cryptDecrypt(JNIEnv *, jobject, std::string);
^
jni/include\teste.h:15:16: error: 'string' in namespace 'std' does not name a type
JNIEXPORT std::string JNICALL Java_com_teste_teste_teste_base64xXxdecode(JNIEnv *, jobject, std::string const&);
^
jni/teste.cpp:124:124: error: expected ',' or '...' before 'toEncrypt'
JNIEXPORT std::string JNICALL Java_com_teste_teste_teste_encriptaDecripta(JNIEnv *env, jobject jobj, std::string toEncrypt toEncrypt)

and other similar errors...So I must be doing something wrong....grrrr

This is the code I'm trying. a little messy, I know, as I've just glued some web examples to see how it works.

B4X:
#include <stdio.h>
#include <string>
#include <iostream>

using namespace std;
static const std::string base64_chars =
             "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
             "abcdefghijklmnopqrstuvwxyz"
             "0123456789+/";

//Test line. Already ciphered and in base 64. This line will return the key after processed by
//decodex.

char Base[]="FTRVExxMZwRSUFUQbC19TxIpEBEPI3E8VVcGbHYMHBdBAytBFTkSNjteQ39FJhoKNFQpEHIZakMnBFVtT0Nl";
/*
*
*/
//::ignore
std::string cryptDecrypt(std::string toEncrypt) {
    char key[8] = {'l', 'c', 'g','!','%','}','$','z'}; // just some xors as per web example
    std::string output = toEncrypt;
   
    for (unsigned int i = 0; i < toEncrypt.size(); i++)
        output[i] = toEncrypt[i] ^ key[i % (sizeof(key) / sizeof(char))];
    return output;
}




static inline bool is_base64(unsigned char c) {
  return (isalnum(c) || (c == '+') || (c == '/'));
}
//::ignore
std::string base64_encode(unsigned char const* bytes_to_encode, unsigned int in_len) {
  std::string ret;
  int i = 0;
  int j = 0;
  unsigned char char_array_3[3];
  unsigned char char_array_4[4];

  while (in_len--) {
    char_array_3[i++] = *(bytes_to_encode++);
    if (i == 3) {
      char_array_4[0] = (char_array_3[0] & 0xfc) >> 2;
      char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4);
      char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6);
      char_array_4[3] = char_array_3[2] & 0x3f;

      for(i = 0; (i <4) ; i++)
        ret += base64_chars[char_array_4[i]];
      i = 0;
    }
  }

  if (i)
  {
    for(j = i; j < 3; j++)
      char_array_3[j] = '\0';

    char_array_4[0] = (char_array_3[0] & 0xfc) >> 2;
    char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4);
    char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6);
    char_array_4[3] = char_array_3[2] & 0x3f;

    for (j = 0; (j < i + 1); j++)
      ret += base64_chars[char_array_4[j]];

    while((i++ < 3))
      ret += '=';

  }

  return ret;

}
//::ignore
std::string base64_decode(std::string const& encoded_string) {
  int in_len = encoded_string.size();
  int i = 0;
  int j = 0;
  int in_ = 0;
  unsigned char char_array_4[4], char_array_3[3];
  std::string ret;

  while (in_len-- && ( encoded_string[in_] != '=') && is_base64(encoded_string[in_])) {
    char_array_4[i++] = encoded_string[in_]; in_++;
    if (i ==4) {
      for (i = 0; i <4; i++)
        char_array_4[i] = base64_chars.find(char_array_4[i]);

      char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4);
      char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2);
      char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3];

      for (i = 0; (i < 3); i++)
        ret += char_array_3[i];
      i = 0;
    }
  }

  if (i) {
    for (j = i; j <4; j++)
      char_array_4[j] = 0;

    for (j = 0; j <4; j++)
      char_array_4[j] = base64_chars.find(char_array_4[j]);

    char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4);
    char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2);
    char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3];

    for (j = 0; (j < i - 1); j++) ret += char_array_3[j];
  }

  return ret;
}

char * decodex() {
    std::string encoded=::Base;
    std::string decoded = base64_decode(encoded);
    string decriptado = cryptDecrypt(decoded);
    char* devolve=&decriptado[0u];
    cout << devolve<<"\n\n";
        return devolve;
}
 
Last edited:

wonder

Expert
Licensed User
Longtime User
Those 3 functions are "internal" and expected be ignored by NLG, right?
I think I know what it is, stay tuned. I'll try to patch it right away.
The ::ignore request wasn't being properly processed.

By the way:
B4X:
char * decodex() {
    std::string encoded=::Base;
    std::string decoded = base64_decode(encoded);
    string decriptado = cryptDecrypt(decoded);
    char* devolve=&decriptado[0u];
    cout << devolve<<"\n\n";
        return devolve;
}

The "devolve" variable must be global, otherwise you'll get nothing more than garbage, as the local variable you're trying to return will go out of scope.
 
Last edited:

wonder

Expert
Licensed User
Longtime User
Alright, the bug should be solved. :)

New version released:
http://85.89.182.79:5555/apps/native/native_library_generator_2_71.jar?

@JTmartins, try this! I did a few corrections and now it compiles without any problems for me.
B4X:
#include <stdio.h>
#include <string>
#include <iostream>

using namespace std;
static const std::string base64_chars =
             "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
             "abcdefghijklmnopqrstuvwxyz"
             "0123456789+/";

//Global variable
char* devolve;

//Test line. Already ciphered and in base 64. This line will return the key after processed by decodex.
char Base[]="FTRVExxMZwRSUFUQbC19TxIpEBEPI3E8VVcGbHYMHBdBAytBFTkSNjteQ39FJhoKNFQpEHIZakMnBFVtT0Nl";

//::ignore
std::string cryptDecrypt(std::string toEncrypt) {
    char key[8] = {'l', 'c', 'g','!','%','}','$','z'}; // just some xors as per web example
    std::string output = toEncrypt;
  
    for (unsigned int i = 0; i < toEncrypt.size(); i++)
        output[i] = toEncrypt[i] ^ key[i % (sizeof(key) / sizeof(char))];
    return output;
}

static inline bool is_base64(unsigned char c) {
  return (isalnum(c) || (c == '+') || (c == '/'));
}

//::ignore
std::string base64_encode(unsigned char const* bytes_to_encode, unsigned int in_len) {
  std::string ret;
  int i = 0;
  int j = 0;
  unsigned char char_array_3[3];
  unsigned char char_array_4[4];

  while (in_len--) {
    char_array_3[i++] = *(bytes_to_encode++);
    if (i == 3) {
      char_array_4[0] = (char_array_3[0] & 0xfc) >> 2;
      char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4);
      char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6);
      char_array_4[3] = char_array_3[2] & 0x3f;

      for(i = 0; (i <4) ; i++)
        ret += base64_chars[char_array_4[i]];
      i = 0;
    }
  }

  if (i)
  {
    for(j = i; j < 3; j++)
      char_array_3[j] = '\0';

    char_array_4[0] = (char_array_3[0] & 0xfc) >> 2;
    char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4);
    char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6);
    char_array_4[3] = char_array_3[2] & 0x3f;

    for (j = 0; (j < i + 1); j++)
      ret += base64_chars[char_array_4[j]];

    while((i++ < 3))
      ret += '=';
  }
  return ret;
}

//::ignore
std::string base64_decode(std::string const& encoded_string) {
  int in_len = encoded_string.size();
  int i = 0;
  int j = 0;
  int in_ = 0;
  unsigned char char_array_4[4], char_array_3[3];
  std::string ret;

  while (in_len-- && ( encoded_string[in_] != '=') && is_base64(encoded_string[in_])) {
    char_array_4[i++] = encoded_string[in_]; in_++;
    if (i ==4) {
      for (i = 0; i <4; i++)
        char_array_4[i] = base64_chars.find(char_array_4[i]);

      char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4);
      char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2);
      char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3];

      for (i = 0; (i < 3); i++)
        ret += char_array_3[i];
      i = 0;
    }
  }

  if (i) {
    for (j = i; j <4; j++)
      char_array_4[j] = 0;

    for (j = 0; j <4; j++)
      char_array_4[j] = base64_chars.find(char_array_4[j]);

    char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4);
    char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2);
    char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3];

    for (j = 0; (j < i - 1); j++) ret += char_array_3[j];
  }

  return ret;
}

char * decodex() {
    std::string encoded=::Base;
    std::string decoded = base64_decode(encoded);
    string decriptado = cryptDecrypt(decoded);

    char* result = (char*)decriptado.c_str();
    size_t allocSize = sizeof(result) * decriptado.length();
    if (allocSize > 0) {
        devolve = (char*)realloc(devolve, allocSize); 
        strcpy(devolve, result);
        return devolve;
    }
    else {
        return "";
    }   
}
 
Last edited:
Top