Advertising (This ad goes away for registered users. You can Login or Register)

Writing a menu for VHBL

VHBL (Vita Half Byte Loader) is an open source tool to load PSP homebrews on the Playstation Vita.
VHBL can be downloaded at http://wololo.net/vhbl
wololo
Site Admin
Posts: 3619
Joined: Wed Oct 15, 2008 12:42 am
Location: Japan

Writing a menu for VHBL

Post by wololo » Wed May 16, 2012 10:46 pm

Writing a menu for HBL in general is not too difficult if you have previous experience in homebrews. a menu for HBL is a typical homebrew that just has to follow a few rules in order to communicate with HBL.
On the Vita, there are additional limitations on the PSP emulator that add a few constraints, which I will describe here.

- a menu for VHBL is a "regular" EBOOT.PBP file. You install it by simply replacing the EBOOT.PBP file included in VHBL

Example
HBL comes with an open source example that you can find here:
http://code.google.com/p/valentine-hbl/ ... der%2Fmenu

This does not have any vita specific enhancements, though.

HBL API
Your Menu must follow an API that has been defined a long time ago in HBL.
HBL passes a pointer to a struct that is described as follow:

Code: Select all

typedef struct
{
        unsigned long        APIVersion;
        char       Credits[32];
        char       VersionName[32];
        char       *BackgroundFilename;   // set to NULL to let menu choose.
    char        * filename;   // The menu will write the selected filename there
}       tMenuApi
The pointer is passed to your EBOOT as the second parameter of argv in your main function. This is how we initialize the structure in our sample:

Code: Select all

void * ebootPath;

int main(int argc, char *argv[])
{
    char dummy_filename[256];
    strcpy(dummy_filename, "ms0:/PSP/GAME");

    int settingsAddr = 0;

    if (argc > 1) {
        char * hex = argv[1];
        *(hex + 8 ) = 0; //bug in HBL ?
        settingsAddr = xstrtoi(hex, 8);
    }
    if (settingsAddr) {
        tMenuApi * settings = (tMenuApi *) settingsAddr;
        ebootPath = (void *) settings->filename;
    } else {
        ebootPath = dummy_filename;
    }
In order to interact with the HBL backend, we simply write back a command at the address of settings->filename, then quit the menu with a typical sceKernelExitGame.
The command we write is usually the path to an eboot (to run a homebrew), but can also be the string "quit" if we want to ask HBL to qui back to the XMB:

To quit:

Code: Select all

strcpy(ebootPath, "quit");
 sceKernelExitGame();
To run a homebrew:

Code: Select all

strcpy(ebootPath, "ms0:/PSP/GAME/TEST/EBOOT.PBP");
 sceKernelExitGame();
(in our sample in the svn, this is done by the function setEboot )

That's it for the basics. Below are some Vita specific rules

Vita specifics

. and .. do not exist
For some reason, retrieving "." and ".." with conventional "dread" calls does not always work with VHBL on the vita (although recent versions attempt to fix this, so it might be worth trying). This can be a problem if you are trying to create a list of files in a folder, and if you want to give the user a possibility to browse folders (something that a VHBL menu might want to do, especially since we also want to be able to access the SAVEDATA folder, see below).
This is how I managed to handle this case in wMenu (C++ code)
(note: this will not compile, it is taken out of context, so don't copy paste blindly)

Code: Select all

void GameApp::loadFiles(const char * folder){
  base = folder;
  if (base[base.size()-1] != '/') {
    base.append("/");
  }

  DIR *mDip = opendir(base.c_str());

  if (!mDip)
      return;

  int count = std::count(base.begin(), base.end(), '/');
  if (count > 1)
      homebrews.push_back("..");

  while ((mDit = readdir(mDip))){


    if (strcmp(mDit->d_name, ".") == 0) continue;
    if (strcmp(mDit->d_name, "..") == 0) continue; //added above
[...]
What I'm doing is that I'm counting the numbers of "/" symbols in the current folder path, to see if I can go up one folder or not. If that's the case, I force add ".." to my list.
In order to stay compatible with regular readdir function (if the menu is running on a regular psp which doesn't have the limitations of the vita, for example), I also force remove "." and ".." from the readdir results, in case I find them

Extracting zips
Because CMA does not allow us to copy folders and subfolders, the best way I found to install homebrews on the Vita is to put them in a zip file, that gets extracted by the VHBL menu. In order to simplify my code I only support uncompressed zip files, but it is up to you to make things "better".
[TODO. My own code is a mess and cannot be used as an example. Anybody knows of a simple zip library and could give an example?]

The code below shows how I "guess" where to extract the zip

Code: Select all

//Load the list of files in the install zip if they're not loaded yet
void GameApp::ensureExtractFilesList()
{
    if (extractError)
        return;

    if (!zipFiles.empty())
        return;

    ZipSupport::PreloadZip(gameToExtract.c_str(), zipFiles);
    currentZipFile.open(gameToExtract.c_str(), ios::binary);

    extractFolder = MEMSTICK_ROOT;
    //Look for eboot and guess output folder from there.
    for (map<std::string, ZipSupport::limited_file_info>::iterator it = zipFiles.begin(); it !=zipFiles.end(); ++it) {
         string name = it->first;
         std::transform(name.begin(), name.end(), name.begin(), ::tolower);
         if ((name.find("eboot.pbp") != string::npos) || (name.find("wmenu.bin") != string::npos)) {
             std::stringstream out;
             out << MEMSTICK_ROOT;

             int count = std::count(name.begin(), name.end(), '/');
             switch (count) {
             case 0:
                 {
                 // eboot.pbp
                 int rnd = rand()%10000;
                 out << "PSP/GAME/WMENU_" << rnd << "/";
                 break;
                 }
             case 1:
                 //mygamegame/eboot.pbp
                 out << "PSP/GAME/";
                 break;
             case 2:
                 //game/mygame/eboot.pbp
                 out << "PSP/";
                 break;
             case 3:
                 //psp/game/mygame/eboot.pbp
                 break;
             default:
                 extractError = 1;
                 currentZipFile.close();
             }

             extractFolder = out.str();
             return;

         }
         
    }
    currentZipFile.close();
    return;

}
EBOOT.PBP files cannot be created
A limitation of the PSP emulator on the vita is that it is not possible to create a file named EBOOT.PBP under the GAME/*/ folder. To bypass this limitation, wMenu renames all files named EBOOT.PBP into wmenu.bin. Technically, any name is fine as long as it is exactly 9 characters long (this is a constraint from HBL).
This is what my code looks like:

Code: Select all

    string outputfile = it->first;
    string lcoutputfile = outputfile;
    std::transform(lcoutputfile.begin(), lcoutputfile.end(), lcoutputfile.begin(), ::tolower);
    size_t found = lcoutputfile.find("eboot.pbp");
    if (found != string::npos)
        outputfile = it->first.substr(0, found) + "wmenu.bin" + it->first.substr(found + 9);

    string outputFile = extractFolder + outputfile;
Again, don't copy/paste this blindly

Remember, this also means that you will have to copy the right filename (ms0:/PSP/GAME/TEST/wmenu.bin for example) in "ebootPath" above when running the homebrews!

That's basically it. for the rest, your imagination is the limit.
Advertising
If you need US PSN Codes, this technique is what I recommend.

Looking for guest bloggers and news hunters here at wololo.net, PM me!

fatboyfry
Posts: 2
Joined: Wed May 09, 2012 1:08 am

Re: Writing a menu for VHBL

Post by fatboyfry » Thu May 17, 2012 1:42 am

wololo wrote: That's basically it.
I laugh every time i read that. Lol I'm not gonna lie i don't know anything about C++ but i love your work and i hope that within the coming months we get a concrete, stable exploit out. Keep it up your efforts along with every other programmer/coder. Good Job.
Advertising

User avatar
m0skit0
Guru
Posts: 3817
Joined: Mon Sep 27, 2010 6:01 pm

Re: Writing a menu for VHBL

Post by m0skit0 » Thu May 17, 2012 8:03 am

@fatboyfry: nice praising, but way too much off-topic. If you have nothing to say on-topic, please just abstain posting or do it on off-topic ;)
I wanna lots of mov al,0xb
Image
"just not into this RA stuffz"

wth
HBL Developer
Posts: 834
Joined: Wed Aug 31, 2011 4:44 pm
Contact:

Re: Writing a menu for VHBL

Post by wth » Thu May 17, 2012 8:46 pm

wololo wrote:[TODO. My own code is a mess and cannot be used as an example. Anybody knows of a simple zip library and could give an example?]
there's always this "load_file_zip" function from gpsp which could certainly be adapted, however it looks like it doesn't load very big files entirely http://sourceforge.jp/projects/gpsp-kai ... /src/zip.c

Also, doesn't JGE++ already support zip compression ? http://jge.khors.com/docs/class_j_file_system.html
Apparently MasterBoy supports zip compression using Oslib too




I also just found this http://forums.ps2dev.org/viewtopic.php? ... eae4389fee : AnonymousTipster's zip/rar unpacker's source code :)
In this one, there are simple unzipToDir / DoExtractRAR functions to use as follows :

Code: Select all

unzipToDir( "ms0:/myfolder/myZipFile.zip", "ms0:/myOutputFolder/", NULL );
DoExtractRAR ( "ms0:/myfolder/myRarFile.rar", "ms0:/myOutputFolder/", NULL );
or
unzipToDir( "ms0:/myfolder/myZipFile.zip", "ms0:/myOutputFolder/", "" );
DoExtractRAR ( "ms0:/myfolder/myRarFile.rar", "ms0:/myOutputFolder/", "" );
prototypes :

Code: Select all

int unzipToDir(const char *zippath, const char *destpath, const char *pass)
void DoExtractRAR(const char *rarfile,const char *extDir,const char *pass)

If the output path folders don't exist, they'll be automatically created
About DoExtractRAR though, it doesn't work for RAR files with higher compression rates than the "Normal" one
Also about unzipToDir, it changes the current working directory to the output folder you mention, so it could be good to change current directory back to normal after it if you're using relative paths
here's a full sample, with only the necessary files for unzipToDir / DoExtractRAR functions : http://www.mediafire.com/?x9x5wqwrb85n0ir

Update : Link updated
Added the define DEBUG_RZ in "unzip.h" line 352 to redirect debug messages to psplink instead of not displaying them at all
Just uncomment it to have debug messages display in psplink



Also btw, apparently the hb_folder value mentionned in the "hbl_config.txt" file is passed to the menu using the tMenuApi's filename member too according to hbl's src
I think it's good to also remember that

User avatar
Acid_Snake
Retired Mod
Posts: 3099
Joined: Tue May 01, 2012 11:32 am
Location: Behind you!

Re: Writing a menu for VHBL

Post by Acid_Snake » Tue May 22, 2012 2:18 pm

I'm making a menu with python and psp2d with better support for zip but I need time to make it communicate with hbl, maybe by and external prx/eboot? I could also take a look at ctypes, I don't know C/C++ but it seems simple.

I have a question: does the eboot.pbp name limitaion is only on ms0:/psp/game/*/ or is it in anywhere, for example ms0:/psp/*/eboot.pbp or ms0:/*/eboot.pbp
Last edited by Acid_Snake on Tue May 22, 2012 2:41 pm, edited 1 time in total.

User avatar
m0skit0
Guru
Posts: 3817
Joined: Mon Sep 27, 2010 6:01 pm

Re: Writing a menu for VHBL

Post by m0skit0 » Tue May 22, 2012 2:22 pm

You can't use external PRXs with HBL. This is one major bug. I don't know Python, but your best call I think is to find some way to load the C structs.
I wanna lots of mov al,0xb
Image
"just not into this RA stuffz"

wth
HBL Developer
Posts: 834
Joined: Wed Aug 31, 2011 4:44 pm
Contact:

Re: Writing a menu for VHBL

Post by wth » Tue May 22, 2012 3:03 pm

Acid_Snake wrote:I'm making a menu with python and psp2d with better support for zip but I need time to make it communicate with hbl, maybe by and external prx/eboot? I could also take a look at ctypes, I don't know C/C++ but it seems simple.

I have a question: does the eboot.pbp name limitaion is only on ms0:/psp/game/*/ or is it in anywhere, for example ms0:/psp/*/eboot.pbp or ms0:/*/eboot.pbp
the eboot.pbp limitation applies anywhere on the psp emu

also I don't know about using C structs on python, but actually I think it's better to use C / C++ for a hbl menu, indeed since hbl usually loads in a kinda unstable environment on 6.60, it's likely a python interpreter won't always even launch

User avatar
Acid_Snake
Retired Mod
Posts: 3099
Joined: Tue May 01, 2012 11:32 am
Location: Behind you!

Re: Writing a menu for VHBL

Post by Acid_Snake » Tue May 22, 2012 4:03 pm

then perhaps I should just make an unzipper for anyone that wants better zip support for their menu, I already have full zip support in my other homebrew and it would be fairly easy:
- the menu creates a text file with the path to the install.zip
- the menu loads the unzipper.
- the unzipper reads the file and extracts the install.zip
- the unzipper finishes, returning to the menu

the only flaw I see would be time, the good thing is the ease of developing the unzipper.
I'll still try to create the menu, just for learning purposes, even if I dont release it.
Another advantage to this would be more than one homebrew per savefile.

wth
HBL Developer
Posts: 834
Joined: Wed Aug 31, 2011 4:44 pm
Contact:

Re: Writing a menu for VHBL

Post by wth » Tue May 22, 2012 4:36 pm

Acid_Snake wrote:then perhaps I should just make an unzipper for anyone that wants better zip support for their menu, I already have full zip support in my other homebrew and it would be fairly easy:
- the menu creates a text file with the path to the install.zip
- the menu loads the unzipper.
- the unzipper reads the file and extracts the install.zip
- the unzipper finishes, returning to the menu

the only flaw I see would be time, the good thing is the ease of developing the unzipper.
well the best way would still be to implement a C / C++ library for unzipping/unraring, and I even just bothered providing a sample with a fairly easy to use one, just two simple functions :
unzipToDir( "ms0:/myfolder/myZipFile.zip", "ms0:/myOutputFolder/", NULL );
DoExtractRAR ( "ms0:/myfolder/myRarFile.rar", "ms0:/myOutputFolder/", NULL );

so I doubt you could make it easier
and with this lib, unzipping already works perfectly. It also even supports unraring up to normal compression.


Also having hbl load another eboot.pbp just for unzipping would be a waste, indeed each time we launch an eboot in hbl and quit, hbl somehow becomes less and less stable with most homebrews, so I don't recommend using a special eboot just for that at all

User avatar
Acid_Snake
Retired Mod
Posts: 3099
Joined: Tue May 01, 2012 11:32 am
Location: Behind you!

Re: Writing a menu for VHBL

Post by Acid_Snake » Tue May 22, 2012 6:54 pm

yes, just like I said, using an eboot wont be the best option
I'll continue to test if I can get a python app to interact with hbl by loading a homebrew, if I manage to do it I'll make a menu just for fun :D it's much simpler in pc since you can use:

Code: Select all

import os
if os.system("any command") == 0:
  do_something
I've also seen the python docs to implement c/c++ code in python and I found a pretty straight way to do it, but I need to install the minimal sdk first. I think I'm gonna hit more than one wall but it should help improve my programming knowledge.

Post Reply

Return to “Vita Half Byte Loader”