Skip to content
Permalink
Browse files

android: read files from assets without extracting to sdcard

  • Loading branch information
JaCzekanski committed Aug 17, 2019
1 parent 998812f commit d53715c9e376dec8a9b49a7a0bd12ec8fe991467
@@ -6,82 +6,57 @@
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.os.Environment;
import android.util.Log;
import android.widget.Toast;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.core.app.ActivityCompat;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.file.Path;
import java.util.Arrays;
import java.util.List;

public class StartingActivity extends Activity {
private static final String TAG = StartingActivity.class.getSimpleName();
private List<String> dataDirs = Arrays.asList("bios", "memory", "iso", "exe");

static final int REQUEST_PERMISSION = 1;

@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, REQUEST_PERMISSION);
} else {
prepareEnviroment();
return;
}
}

private void copyFileOrDir(String path) {
String[] assets = new String[]{};
try {
assets = getAssets().list(path);
if (assets.length == 0) {
copyFile(path);
} else {
String fullPath = Environment.getExternalStorageDirectory().getAbsolutePath() + "/avocado/" + path;
File dir = new File(fullPath);
if (!dir.exists()) {
dir.mkdir();
}
for (int i = 0; i < assets.length; ++i) {
copyFileOrDir(path + "/" + assets[i]);
}
}
} catch (IOException ex) {
Log.e(TAG, "I/O Exception", ex);
}
prepareEnviroment();
}

private void copyFile(String filename) {
String newFileName = Environment.getExternalStorageDirectory().getAbsolutePath() + "/avocado/" + filename;
try (InputStream in = getAssets().open(filename);
OutputStream out = new FileOutputStream(newFileName)) {
byte[] buffer = new byte[16 * 1024];
int read;
while ((read = in.read(buffer)) != -1) {
out.write(buffer, 0, read);
}
out.flush();
} catch (Exception e) {
Log.e(TAG, e.getMessage());
private void prepareEnviroment() {
Path sdcard = Environment.getExternalStorageDirectory().toPath();
Path avocadoData = sdcard.resolve("avocado").resolve("data");

for (String dir : dataDirs) {
avocadoData.resolve(dir).toFile().mkdirs();
}

runAvocado();
}

private void prepareEnviroment() {
copyFileOrDir("");
private void runAvocado() {
startActivity(new Intent(this, MainActivity.class));
finish();
}

@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
if (requestCode == REQUEST_PERMISSION && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
prepareEnviroment();
} else {
Toast.makeText(this, "Storage permission is required", Toast.LENGTH_SHORT).show();
finish();
if (requestCode == REQUEST_PERMISSION) {
if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
prepareEnviroment();
} else {
Toast.makeText(this, "Storage permission is required", Toast.LENGTH_SHORT).show();
runAvocado();
}
}
}
}
@@ -0,0 +1,79 @@
#include "utils/file.h"
#include <cstdio>

bool fileExists(std::string name) {
FILE *f = fopen(name.c_str(), "r");
bool exists = false;
if (f) {
exists = true;
fclose(f);
}
return exists;
}

std::vector<uint8_t> getFileContents(std::string name) {
std::vector<uint8_t> contents;

FILE *f = fopen(name.c_str(), "rb");
if (!f) return contents;

fseek(f, 0, SEEK_END);
int filesize = ftell(f);
fseek(f, 0, SEEK_SET);

contents.resize(filesize);
fread(&contents[0], 1, filesize, f);

fclose(f);
return contents;
}

bool putFileContents(std::string name, std::vector<unsigned char> &contents) {
FILE *f = fopen(name.c_str(), "wb");
if (!f) return false;

fwrite(&contents[0], 1, contents.size(), f);

fclose(f);

return true;
}

bool putFileContents(std::string name, std::string contents) {
FILE *f = fopen(name.c_str(), "wb");
if (!f) return false;

fwrite(&contents[0], 1, contents.size(), f);

fclose(f);

return true;
}

std::string getFileContentsAsString(std::string name) {
std::string contents;

FILE *f = fopen(name.c_str(), "rb");
if (!f) return contents;

fseek(f, 0, SEEK_END);
int filesize = ftell(f);
fseek(f, 0, SEEK_SET);

contents.resize(filesize);
fread(&contents[0], 1, filesize, f);

fclose(f);
return contents;
}

size_t getFileSize(std::string name) {
FILE *f = fopen(name.c_str(), "rb");
if (!f) return 0;

fseek(f, 0, SEEK_END);
int size = ftell(f);
fclose(f);

return size;
}
@@ -0,0 +1,79 @@
#include "utils/file.h"
#include <SDL.h>

bool fileExists(std::string name) {
SDL_RWops *f = SDL_RWFromFile(name.c_str(), "r");
bool exists = false;
if (f) {
exists = true;
SDL_RWclose(f);
}
return exists;
}

std::vector<uint8_t> getFileContents(std::string name) {
std::vector<uint8_t> contents;

SDL_RWops *f = SDL_RWFromFile(name.c_str(), "rb");
if (!f) return contents;

SDL_RWseek(f, 0, SEEK_END);
int filesize = SDL_RWtell(f);
SDL_RWseek(f, 0, SEEK_SET);

contents.resize(filesize);
SDL_RWread(f, &contents[0], 1, filesize);

SDL_RWclose(f);
return contents;
}

bool putFileContents(std::string name, std::vector<unsigned char> &contents) {
SDL_RWops *f = SDL_RWFromFile(name.c_str(), "wb");
if (!f) return false;

SDL_RWwrite(f, &contents[0], 1, contents.size());

SDL_RWclose(f);

return true;
}

bool putFileContents(std::string name, std::string contents) {
SDL_RWops *f = SDL_RWFromFile(name.c_str(), "wb");
if (!f) return false;

SDL_RWwrite(f, &contents[0], 1, contents.size());

SDL_RWclose(f);

return true;
}

std::string getFileContentsAsString(std::string name) {
std::string contents;

SDL_RWops *f = SDL_RWFromFile(name.c_str(), "rb");
if (!f) return contents;

SDL_RWseek(f, 0, SEEK_END);
int filesize = SDL_RWtell(f);
SDL_RWseek(f, 0, SEEK_SET);

contents.resize(filesize);
SDL_RWread(f, &contents[0], 1, filesize);

SDL_RWclose(f);
return contents;
}

size_t getFileSize(std::string name) {
SDL_RWops *f = SDL_RWFromFile(name.c_str(), "rb");
if (!f) return 0;

SDL_RWseek(f, 0, SEEK_END);
int size = SDL_RWtell(f);
SDL_RWclose(f);

return size;
}
@@ -12,7 +12,14 @@ std::unordered_map<std::string, std::optional<Image>> images;

std::optional<Image> loadImage(const std::string& file) {
int w, h, bit;
auto data = stbi_load(file.c_str(), &w, &h, &bit, 4);

auto rawdata = getFileContents(file);
if (rawdata.empty()) {
printf("[Error] Cannot load %s\n", getFilenameExt(file).c_str());
return {};
}

auto data = stbi_load_from_memory(rawdata.data(), rawdata.size(), &w, &h, &bit, 4);
if (data == nullptr) {
printf("[Error] Cannot load %s\n", getFilenameExt(file).c_str());
return {};
@@ -141,29 +141,33 @@ void biosSelectionWindow() {
static std::vector<std::string> bioses;
static int selectedBios = 0;

if (!biosesFound) {
bioses.clear();
auto dir = fs::directory_iterator("data/bios");
for (auto& e : dir) {
if (!fs::is_regular_file(e)) continue;

auto path = e.path().string();
auto ext = getExtension(path);
std::transform(ext.begin(), ext.end(), ext.begin(), tolower);

if (ext == "bin" || ext == "rom") {
bioses.push_back(path);
try {
if (!biosesFound) {
bioses.clear();
auto dir = fs::directory_iterator("data/bios");
for (auto& e : dir) {
if (!fs::is_regular_file(e)) continue;

auto path = e.path().string();
auto ext = getExtension(path);
std::transform(ext.begin(), ext.end(), ext.begin(), tolower);

if (ext == "bin" || ext == "rom") {
bioses.push_back(path);
}
}
}
biosesFound = true;

int i = 0;
for (auto it = bioses.begin(); it != bioses.end(); ++it, ++i) {
if (*it == config["bios"]) {
selectedBios = i;
break;
biosesFound = true;

int i = 0;
for (auto it = bioses.begin(); it != bioses.end(); ++it, ++i) {
if (*it == config["bios"]) {
selectedBios = i;
break;
}
}
}
} catch (fs::filesystem_error& err) {
printf("%s", err.what());
}

ImGui::Begin("BIOS", &showBiosWindow, ImGuiWindowFlags_AlwaysAutoResize);
@@ -183,7 +187,13 @@ void biosSelectionWindow() {
(void*)&bioses, (int)bioses.size());

if (ImGui::Button("Select", ImVec2(-1, 0)) && selectedBios < (int)bioses.size()) {
config["bios"] = bioses[selectedBios];
std::string biosPath = bioses[selectedBios];
// SDL treats relative paths (not starting with /) as relative to app internal storage path
// Storing path as absolute is needed for file to be found
#ifdef ANDROID
biosPath = fs::absolute(biosPath).string();
#endif
config["bios"] = biosPath;

biosesFound = false;
showBiosWindow = false;
@@ -227,12 +227,12 @@ void limitFramerate(std::unique_ptr<System>& sys, SDL_Window* window, bool frame
void fatalError(const std::string& error) {
fprintf(stderr, "[FATAL] %s", error.c_str());
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Avocado", error.c_str(), nullptr);
SDL_Quit();
}

void changeWorkingDirectory() {
std::string workingDirectory = ".";
#ifdef ANDROID
// TODO: Use Envoiroment.getExternalStorageDirectory();
workingDirectory = "/sdcard/avocado";
#else
char* basePath = SDL_GetBasePath();
@@ -320,6 +320,7 @@ int main(int argc, char** argv) {
ImFontConfig config;
config.OversampleH = 4;
config.OversampleV = 4;
config.FontDataOwnedByAtlas = false;
int fontSize = 16.f;

#ifdef ANDROID
@@ -332,15 +333,16 @@ int main(int argc, char** argv) {
style.GrabRounding = 6.f;
style.FrameRounding = 6.f;

io.Fonts->AddFontFromFileTTF("data/assets/roboto-mono.ttf", fontSize, &config);
auto font = getFileContents("data/assets/roboto-mono.ttf");
io.Fonts->AddFontFromMemoryTTF(font.data(), font.size(), fontSize, &config);
io.Fonts->AddFontDefault();
}

initGui();

Sound::play();

if (!isEmulatorConfigured())
if (!sys->isSystemReady())
sys->state = System::State::stop;
else
sys->state = System::State::run;

0 comments on commit d53715c

Please sign in to comment.
You can’t perform that action at this time.