From 329b4591378e6d02f3ccbeb5427eef102d61ec7e Mon Sep 17 00:00:00 2001 From: XProger Date: Wed, 1 Mar 2023 06:18:26 +0300 Subject: [PATCH] Linux case-insensitive for file names --- src/gameflow.h | 67 +++++++++------------- src/platform/nix/main.cpp | 116 +++++++++++++++++++++++++++++++------- src/utils.h | 79 +++++++++++++++----------- 3 files changed, 169 insertions(+), 93 deletions(-) diff --git a/src/gameflow.h b/src/gameflow.h index 5eab3e9..d324397 100644 --- a/src/gameflow.h +++ b/src/gameflow.h @@ -24,7 +24,7 @@ namespace TR { VER_SDC = 0x8000, VER_TR1 = 0x01, - VER_TR2 = 0x02, + VER_TR2 = 0x02, VER_TR3 = 0x04, VER_TR4 = 0x08, VER_TR5 = 0x10, @@ -1027,14 +1027,14 @@ namespace TR { bool isCutsceneLevel(LevelID id) { return id == LVL_TR1_CUT_1 || id == LVL_TR1_CUT_2 || id == LVL_TR1_CUT_3 || id == LVL_TR1_CUT_4 || - id == LVL_TR2_CUT_1 || id == LVL_TR2_CUT_2 || id == LVL_TR2_CUT_3 || id == LVL_TR2_CUT_4 || + id == LVL_TR2_CUT_1 || id == LVL_TR2_CUT_2 || id == LVL_TR2_CUT_3 || id == LVL_TR2_CUT_4 || id == LVL_TR3_CUT_1 || id == LVL_TR3_CUT_2 || id == LVL_TR3_CUT_3 || id == LVL_TR3_CUT_4 || id == LVL_TR3_CUT_5 || id == LVL_TR3_CUT_6 || id == LVL_TR3_CUT_7 || id == LVL_TR3_CUT_8 || id == LVL_TR3_CUT_9 || id == LVL_TR3_CUT_11 || id == LVL_TR3_CUT_12; } bool isTitleLevel(LevelID id) { - return id == LVL_TR1_TITLE || + return id == LVL_TR1_TITLE || id == LVL_TR2_TITLE || id == LVL_TR3_TITLE || id == LVL_TR4_TITLE; @@ -1081,21 +1081,8 @@ namespace TR { break; case VER_TR1_PSX : sprintf(dst, "PSXDATA/%s.PSX", LEVEL_INFO[id].name); break; case VER_TR1_SAT : sprintf(dst, "DATA/%s.SAT", LEVEL_INFO[id].name); break; - case VER_TR2_PC : { // oh FFFFUUUUUUCKing CaTaComB.Tr2! - if (id == LVL_TR2_VENICE || id == LVL_TR2_CUT_2 || id == LVL_TR2_PLATFORM || id == LVL_TR2_CUT_3 || id == LVL_TR2_UNWATER || - id == LVL_TR2_KEEL || id == LVL_TR2_LIVING || id == LVL_TR2_DECK || id == LVL_TR2_CATACOMB || id == LVL_TR2_ICECAVE || - id == LVL_TR2_CUT_4 || id == LVL_TR2_XIAN || id == LVL_TR2_HOUSE) { - char buf[64]; - strcpy(buf, LEVEL_INFO[id].name); - StrUtils::toLower(buf); - sprintf(dst, "DATA/%s.TR2", buf); - } else if (id == LVL_TR2_TITLE) { - sprintf(dst, "DATA/%s.tr2", LEVEL_INFO[id].name); - } else if (id == LVL_TR2_EMPRTOMB) { - strcpy(dst, "DATA/Emprtomb.tr2"); - } else { - sprintf(dst, "DATA/%s.TR2", LEVEL_INFO[id].name); - } + case VER_TR2_PC : { + sprintf(dst, "DATA/%s.TR2", LEVEL_INFO[id].name); if (Stream::existsContent(dst)) break; strcpy(dst, LEVEL_INFO[id].name); StrUtils::toLower(dst); @@ -1120,13 +1107,13 @@ namespace TR { #else switch (version) { case VER_TR1_PC : strcat(dst, ".PHD"); break; - case VER_TR2_PC : + case VER_TR2_PC : case VER_TR3_PC : strcat(dst, ".TR2"); break; case VER_TR1_PSX : - case VER_TR2_PSX : + case VER_TR2_PSX : case VER_TR3_PSX : strcat(dst, ".PSX"); break; case VER_TR1_SAT : strcat(dst, ".SAT"); break; - case VER_UNKNOWN : + case VER_UNKNOWN : if (Stream::existsContent("level/1/TITLE.PSX")) { strcpy(dst, "level/1/TITLE.PSX"); return; @@ -1186,8 +1173,8 @@ namespace TR { 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 28, 4, 5, 6 }; - static const uint8 TR2_TRACK_MAPPING[] = { - 2, 2, 2, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 18, 18, 19, 20, + static const uint8 TR2_TRACK_MAPPING[] = { + 2, 2, 2, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 18, 18, 19, 20, 21, 22, 23, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61 }; @@ -1425,28 +1412,28 @@ namespace TR { return "level/2/TITLEUS.PNG"; // WEB case LVL_TR2_ASSAULT : case LVL_TR2_HOUSE : - CHECK_FILE("PIX/MANSION.RAW"); + CHECK_FILE("PIX/MANSION.RAW"); return "level/2/MANSION.PNG"; case LVL_TR2_WALL : case LVL_TR2_EMPRTOMB : case LVL_TR2_FLOATING : case LVL_TR2_XIAN : - CHECK_FILE("PIX/CHINA.RAW"); + CHECK_FILE("PIX/CHINA.RAW"); return "level/2/CHINA.PNG"; case LVL_TR2_BOAT : case LVL_TR2_VENICE : case LVL_TR2_OPERA : - CHECK_FILE("PIX/VENICE.RAW"); + CHECK_FILE("PIX/VENICE.RAW"); return "level/2/VENICE.PNG"; case LVL_TR2_RIG : case LVL_TR2_PLATFORM : - CHECK_FILE("PIX/RIG.RAW"); + CHECK_FILE("PIX/RIG.RAW"); return "level/2/RIG.PNG"; case LVL_TR2_UNWATER : case LVL_TR2_KEEL : case LVL_TR2_LIVING : case LVL_TR2_DECK : - CHECK_FILE("PIX/TITAN.RAW"); + CHECK_FILE("PIX/TITAN.RAW"); return "level/2/TITAN.PNG"; case LVL_TR2_SKIDOO : case LVL_TR2_MONASTRY : @@ -1461,43 +1448,43 @@ namespace TR { CHECK_FILE("PIXJAP/TITLEJAP.RAW"); // PSX return "level/3/TITLEUK.PNG"; // WEB case LVL_TR3_HOUSE : - CHECK_FILE("pix/HOUSE.BMP"); - CHECK_FILE("PIX/HOUSE.RAW"); + CHECK_FILE("pix/HOUSE.BMP"); + CHECK_FILE("PIX/HOUSE.RAW"); return "level/3/HOUSE.PNG"; case LVL_TR3_JUNGLE : case LVL_TR3_TEMPLE : case LVL_TR3_QUADCHAS : case LVL_TR3_TONYBOSS : - CHECK_FILE("pix/INDIA.BMP"); - CHECK_FILE("PIX/INDIA.RAW"); + CHECK_FILE("pix/INDIA.BMP"); + CHECK_FILE("PIX/INDIA.RAW"); return "level/3/INDIA.PNG"; case LVL_TR3_SHORE : case LVL_TR3_CRASH : case LVL_TR3_RAPIDS : case LVL_TR3_TRIBOSS : - CHECK_FILE("pix/SOUTHPAC.BMP"); - CHECK_FILE("PIX/SOUTHPAC.RAW"); + CHECK_FILE("pix/SOUTHPAC.BMP"); + CHECK_FILE("PIX/SOUTHPAC.RAW"); return "level/3/SOUTHPAC.PNG"; case LVL_TR3_ROOFS : case LVL_TR3_SEWER : case LVL_TR3_TOWER : case LVL_TR3_OFFICE : case LVL_TR3_STPAUL : - CHECK_FILE("pix/LONDON.BMP"); - CHECK_FILE("PIX/LONDON.RAW"); + CHECK_FILE("pix/LONDON.BMP"); + CHECK_FILE("PIX/LONDON.RAW"); return "level/3/LONDON.PNG"; case LVL_TR3_NEVADA : case LVL_TR3_COMPOUND : case LVL_TR3_AREA51 : - CHECK_FILE("pix/NEVADA.BMP"); - CHECK_FILE("PIX/NEVADA.RAW"); + CHECK_FILE("pix/NEVADA.BMP"); + CHECK_FILE("PIX/NEVADA.RAW"); return "level/3/NEVADA.PNG"; case LVL_TR3_ANTARC : case LVL_TR3_MINES : case LVL_TR3_CITY : case LVL_TR3_CHAMBER : - CHECK_FILE("pix/ANTARC.BMP"); - CHECK_FILE("PIX/ANTARC.RAW"); + CHECK_FILE("pix/ANTARC.BMP"); + CHECK_FILE("PIX/ANTARC.RAW"); return "level/3/ANTARC.PNG"; default : return NULL; diff --git a/src/platform/nix/main.cpp b/src/platform/nix/main.cpp index e36c1a0..35106ee 100644 --- a/src/platform/nix/main.cpp +++ b/src/platform/nix/main.cpp @@ -90,7 +90,7 @@ InputKey keyToInputKey(Display *dpy, XKeyEvent event) { XK_0, XK_1, XK_2, XK_3, XK_4, XK_5, XK_6, XK_7, XK_8, XK_9, XK_a, XK_b, XK_c, XK_d, XK_e, XK_f, XK_g, XK_h, XK_i, XK_j, XK_k, XK_l, XK_m, XK_n, XK_o, XK_p, XK_q, XK_r, XK_s, XK_t, XK_u, XK_v, XK_w, XK_x, XK_y, XK_z, - XK_KP_0, XK_KP_1, XK_KP_2, XK_KP_3, XK_KP_4, XK_KP_5, XK_KP_6, XK_KP_7, XK_KP_8, XK_KP_9, XK_KP_Add, XK_KP_Subtract, XK_KP_Multiply, XK_KP_Divide, XK_KP_Separator, + XK_KP_0, XK_KP_1, XK_KP_2, XK_KP_3, XK_KP_4, XK_KP_5, XK_KP_6, XK_KP_7, XK_KP_8, XK_KP_9, XK_KP_Add, XK_KP_Subtract, XK_KP_Multiply, XK_KP_Divide, XK_KP_Separator, XK_F1, XK_F2, XK_F3, XK_F4, XK_F5, XK_F6, XK_F7, XK_F8, XK_F9, XK_F10, XK_F11, XK_F12, XK_minus, XK_equal, XK_bracketleft, XK_bracketright, XK_slash, XK_backslash, XK_comma, XK_period, XK_grave, XK_semicolon, XK_apostrophe, XK_Page_Up, XK_Page_Down, XK_Home, XK_End, XK_Delete, XK_Insert, XK_BackSpace }; @@ -155,7 +155,7 @@ void joyInit() { ioctl(joy.fd, JSIOCGAXES, &axes); ioctl(joy.fd, JSIOCGBUTTONS, &buttons); ioctl(joy.fd, JSIOCGAXMAP, joy.axismap); - + if (axes < 4 || buttons < 11) { // is it really a gamepad? close(joy.fd); joy.fd = -1; @@ -169,7 +169,7 @@ void joyInit() { LOG(" name : %s\n", name); LOG(" btns : %d\n", int(buttons)); LOG(" axes : %d\n", int(axes)); - + joy.fe = -1; for (int j = 0; j < 99; j++) { sprintf(name, "/sys/class/input/js%d/device/event%d", i, j); @@ -180,13 +180,13 @@ void joyInit() { joy.fe = open(name, O_RDWR); break; } - + uint32 features[4]; if (joy.fe > -1 && (ioctl(joy.fe, EVIOCGBIT(EV_FF, sizeof(features)), features) == -1 || !TEST_BIT(features, FF_RUMBLE))) { close(joy.fe); joy.fe = -1; } - + if (joy.fe > -1) { int n_effects; if (ioctl(joy.fe, EVIOCGEFFECTS, &n_effects) == -1) { @@ -230,13 +230,13 @@ vec2 joyDir(const vec2 &value) { void joyRumble(JoyDevice &joy) { if (joy.fe == -1) return; - + if (joy.oL == 0.0f && joy.vL == 0.0f && joy.oR == 0.0f && joy.vR == 0.0f) return; - + if (Core::getTime() <= joy.time) return; - + input_event event; event.type = EV_FF; @@ -245,28 +245,28 @@ void joyRumble(JoyDevice &joy) { joy.fx.u.rumble.strong_magnitude = int(joy.vL * 65535); joy.fx.u.rumble.weak_magnitude = int(joy.vR * 65535); joy.fx.replay.length = int(max(JOY_MIN_UPDATE_FX_TIME, 1000.0f / Core::stats.fps)); - + if (ioctl(joy.fe, EVIOCSFF, &joy.fx) == -1) { LOG("! joy update fx\n"); } // play effect event.value = 1; - event.code = joy.fx.id; + event.code = joy.fx.id; if (write(joy.fe, &event, sizeof(event)) == -1) LOG("! joy play fx\n"); } else if (joy.oL != 0.0f || joy.oR != 0.0f) { // stop effect event.value = 0; - event.code = joy.fx.id; + event.code = joy.fx.id; if (write(joy.fe, &event, sizeof(event)) == -1) LOG("! joy stop fx\n"); } - + joy.oL = joy.vL; joy.oR = joy.vR; - + joy.time = Core::getTime() + joy.fx.replay.length; } @@ -275,12 +275,12 @@ void joyUpdate() { for (int i = 0; i < INPUT_JOY_COUNT; i++) { JoyDevice &joy = joyDevice[i]; - + if (joy.fd == -1) continue; joyRumble(joy); - + js_event event; while (read(joy.fd, &event, sizeof(event)) != -1) { // buttons @@ -288,7 +288,7 @@ void joyUpdate() { Input::setJoyDown(i, event.number >= COUNT(keys) ? jkNone : keys[event.number], event.value == 1); // axes if (event.type & JS_EVENT_AXIS) { - + switch (joy.axismap[event.number]) { // Left stick case ABS_X : joy.L.x = joyAxisValue(event.value); break; @@ -312,7 +312,7 @@ void joyUpdate() { Input::setJoyDown(i, jkDown, event.value > 0x4000); break; } - + Input::setJoyPos(i, jkL, joyDir(joy.L)); Input::setJoyPos(i, jkR, joyDir(joy.R)); } @@ -320,6 +320,76 @@ void joyUpdate() { } } +// filesystem +#define MAX_FILES 4096 +char* gFiles[MAX_FILES]; +int32 gFilesCount; + +void addDir(char* path) +{ + char* fileName; + struct dirent* e; + DIR* dir = opendir(path); + + int32 pathLen = strlen(path); + path[pathLen] = '/'; + + while ((e = readdir(dir))) + { + if (e->d_type == DT_DIR) + { + if (e->d_name[0] != '.') + { + strcpy(path + 1 + pathLen, e->d_name); + addDir(path); + } + } + else + { + ASSERT(gFilesCount < MAX_FILES); + if (gFilesCount < MAX_FILES) + { + strcpy(path + 1 + pathLen, e->d_name); + fileName = (char*)malloc(strlen(path) + 1 - 2); + gFiles[gFilesCount++] = strcpy(fileName, path + 2); + } + } + } + + path[pathLen] = '\0'; +} + +void fsInit() +{ + char path[1024]; + strcpy(path, "."); + addDir(path); + LOG("scan %d files\n", gFilesCount); +} + +void fsFree() +{ + int32 i; + for (i = 0; i < gFilesCount; i++) + { + free(gFiles[i]); + } +} + +const char* osFixFileName(const char* fileName) +{ + int32 i; + for (i = 0; i < gFilesCount; i++) + { + if (!strcasecmp(fileName, gFiles[i])) + { + return gFiles[i]; + } + } + return NULL; +} + +// system void toggle_fullscreen(Display* dpy, Window win) { const size_t _NET_WM_STATE_TOGGLE=2; @@ -447,6 +517,8 @@ int main(int argc, char **argv) { Core::defLang = checkLanguage(); + fsInit(); + joyInit(); sndInit(); Game::init(argc > 1 ? argv[1] : NULL); @@ -460,12 +532,12 @@ int main(int argc, char **argv) { WndProc(event, dpy, wnd); } else { joyUpdate(); - bool updated = Game::update(); + bool updated = Game::update(); if (updated) { - Game::render(); + Game::render(); Core::waitVBlank(); - glXSwapBuffers(dpy, wnd); - } + glXSwapBuffers(dpy, wnd); + } } }; @@ -473,6 +545,8 @@ int main(int argc, char **argv) { sndFree(); Game::deinit(); + fsFree(); + glXMakeCurrent(dpy, 0, 0); XCloseDisplay(dpy); return 0; diff --git a/src/utils.h b/src/utils.h index 34472db..5b30b8a 100644 --- a/src/utils.h +++ b/src/utils.h @@ -13,7 +13,7 @@ #elif defined(_OS_LINUX) || defined(_OS_RPI) || defined(_OS_CLOVER) #define debugBreak() raise(SIGTRAP); #elif defined(_OS_3DS) - #define debugBreak() svcBreak(USERBREAK_ASSERT); + #define debugBreak() svcBreak(USERBREAK_ASSERT); #else #define debugBreak() _asm { int 3 } #endif @@ -213,7 +213,7 @@ inline float lerp(float a, float b, float t) { float lerpAngle(float a, float b, float t) { if (t <= 0.0f) return a; if (t >= 1.0f) return b; - return a + shortAngle(a, b) * t; + return a + shortAngle(a, b) * t; } int nextPow2(uint32 x) { @@ -322,9 +322,9 @@ namespace Noise { // based on https://github.com/Auburns/FastNoise float fy = quintic(dy0); float fz = quintic(dz0); - return lerp(lerp(lerp(noise(x0, y0, z0, dx0, dy0, dz0), noise(x1, y0, z0, dx1, dy0, dz0), fx), + return lerp(lerp(lerp(noise(x0, y0, z0, dx0, dy0, dz0), noise(x1, y0, z0, dx1, dy0, dz0), fx), lerp(noise(x0, y1, z0, dx0, dy1, dz0), noise(x1, y1, z0, dx1, dy1, dz0), fx), fy), - lerp(lerp(noise(x0, y0, z1, dx0, dy0, dz1), noise(x1, y0, z1, dx1, dy0, dz1), fx), + lerp(lerp(noise(x0, y0, z1, dx0, dy0, dz1), noise(x1, y0, z1, dx1, dy0, dz1), fx), lerp(noise(x0, y1, z1, dx0, dy1, dz1), noise(x1, y1, z1, dx1, dy1, dz1), fx), fy), fz); } @@ -413,7 +413,7 @@ struct vec2 { vec2 lerp(const vec2 &v, const float t) const { if (t <= 0.0f) return *this; if (t >= 1.0f) return v; - return *this + (v - *this) * t; + return *this + (v - *this) * t; } }; @@ -473,7 +473,7 @@ struct vec3 { vec3 lerp(const vec3 &v, const float t) const { if (t <= 0.0f) return *this; if (t >= 1.0f) return v; - return *this + (v - *this) * t; + return *this + (v - *this) * t; } vec3 rotateY(float angle) const { @@ -518,7 +518,7 @@ struct vec4 { vec4 lerp(const vec4 &v, const float t) const { if (t <= 0.0f) return *this; if (t >= 1.0f) return v; - return *this + (v - *this) * t; + return *this + (v - *this) * t; } }; @@ -546,16 +546,16 @@ struct quat { return quat(-x, -y, -z, -w); } - quat operator + (const quat &q) const { - return quat(x + q.x, y + q.y, z + q.z, w + q.w); + quat operator + (const quat &q) const { + return quat(x + q.x, y + q.y, z + q.z, w + q.w); } - quat operator - (const quat &q) const { - return quat(x - q.x, y - q.y, z - q.z, w - q.w); + quat operator - (const quat &q) const { + return quat(x - q.x, y - q.y, z - q.z, w - q.w); } - quat operator * (const float s) const { - return quat(x * s, y * s, z * s, w * s); + quat operator * (const float s) const { + return quat(x * s, y * s, z * s, w * s); } quat operator * (const quat &q) const { @@ -573,11 +573,11 @@ struct quat { return x * q.x + y * q.y + z * q.z + w * q.w; } - float length2() const { - return dot(*this); + float length2() const { + return dot(*this); } - float length() const { + float length() const { return sqrtf(length2()); } @@ -601,7 +601,7 @@ struct quat { if (t <= 0.0f) return *this; if (t >= 1.0f) return q; - return dot(q) < 0 ? (*this - (q + *this) * t) : + return dot(q) < 0 ? (*this - (q + *this) * t) : (*this + (q - *this) * t); } @@ -656,7 +656,7 @@ struct mat4 { mat4(float e00, float e10, float e20, float e30, float e01, float e11, float e21, float e31, float e02, float e12, float e22, float e32, - float e03, float e13, float e23, float e33) : + float e03, float e13, float e23, float e33) : e00(e00), e10(e10), e20(e20), e30(e30), e01(e01), e11(e11), e21(e21), e31(e31), e02(e02), e12(e12), e22(e22), e32(e32), @@ -781,9 +781,9 @@ struct mat4 { } mat4(const vec4 &reflectPlane) { - float a = reflectPlane.x, - b = reflectPlane.y, - c = reflectPlane.z, + float a = reflectPlane.x, + b = reflectPlane.y, + c = reflectPlane.z, d = reflectPlane.w; right() = vec4(1 - 2*a*a, - 2*b*a, - 2*c*a, 0); @@ -825,7 +825,7 @@ struct mat4 { e10 * v.x + e11 * v.y + e12 * v.z + e13, e20 * v.x + e21 * v.y + e22 * v.z + e23); } - + vec4 operator * (const vec4 &v) const { return vec4( e00 * v.x + e01 * v.y + e02 * v.z + e03 * v.w, @@ -1286,7 +1286,7 @@ struct Box { max.x = ::max(max.x, box.max.x); max.y = ::max(max.y, box.max.y); max.z = ::max(max.z, box.max.z); - return *this; + return *this; } Box& operator += (const vec3 &v) { @@ -1296,7 +1296,7 @@ struct Box { max.x = ::max(max.x, v.x); max.y = ::max(max.y, v.y); max.z = ::max(max.z, v.z); - return *this; + return *this; } Box& operator -= (const Box &box) { @@ -1306,13 +1306,13 @@ struct Box { max.x = ::min(max.x, box.max.x); max.y = ::min(max.y, box.max.y); max.z = ::min(max.z, box.max.z); - return *this; + return *this; } Box operator * (const mat4 &m) const { Box res(vec3(+INF), vec3(-INF)); for (int i = 0; i < 8; i++) { - vec4 v = m * vec4((*this)[i], 1.0f); + vec4 v = m * vec4((*this)[i], 1.0f); res += v.xyz() /= v.w; } return res; @@ -1408,7 +1408,7 @@ struct Box { bool intersect(const vec3 &rayPos, const vec3 &rayDir, float &t) const { float tMax = INF, tMin = -tMax; - for (int i = 0; i < 3; i++) + for (int i = 0; i < 3; i++) if (rayDir[i] != 0) { float lo = (min[i] - rayPos[i]) / rayDir[i]; float hi = (max[i] - rayPos[i]) / rayDir[i]; @@ -1598,7 +1598,7 @@ struct Array { Array(int capacity = 32) : capacity(capacity), length(0), items(NULL) {} - ~Array() { + ~Array() { clear(); } @@ -1668,7 +1668,7 @@ struct Array { T& operator[] (int index) { ASSERT(index >= 0 && index < length); - return items[index]; + return items[index]; }; }; @@ -1681,6 +1681,10 @@ extern void osCacheRead (Stream *stream); extern void osReadSlot (Stream *stream); extern void osWriteSlot (Stream *stream); +#ifdef _OS_LINUX +extern const char* osFixFileName(const char* fileName); +#endif; + #ifdef _OS_WEB extern void osDownload (Stream *stream); #endif @@ -1767,7 +1771,7 @@ struct Stream { nameLen = stream->readLE16(); extraLen = stream->readLE16(); - info.offset += 4 + 22 + 2 + 2 + nameLen + extraLen; + info.offset += 4 + 22 + 2 + 2 + nameLen + extraLen; return true; } @@ -1786,7 +1790,7 @@ struct Stream { stream->buffering = false; stream->setPos(stream->size - 22); uint32 magic = stream->readLE32(); - + if (magic != 0x06054B50) { ASSERT(false); @@ -1864,7 +1868,13 @@ private: if (contentDir[0] && (!cacheDir[0] || !strstr(name, cacheDir))) { strcpy(path, contentDir); } + + #ifdef _OS_LINUX + strcat(path, osFixFileName(name)); + #else strcat(path, name); + #endif + fixBackslash(path); f = fopen(path, "rb"); @@ -2077,7 +2087,7 @@ public: char path[255]; strcpy(path, contentDir); readDirectory(path); - } + } #else static void readFileList() {}; #endif @@ -2116,10 +2126,15 @@ public: } static bool exists(const char *name) { + #ifdef _OS_LINUX + name = osFixFileName(name); + return (name != NULL); + #else FILE *f = fopen(name, "rb"); if (!f) return false; fclose(f); return true; + #endif } static bool existsContent(const char *name) {