LCOV - code coverage report
Current view: top level - asar/platform - file-helpers.cpp (source / functions) Coverage Total Hit
Test: asar.info Lines: 86.2 % 58 50
Test Date: 2024-01-15 16:23:49 Functions: 75.0 % 4 3
Branches: 72.6 % 62 45

             Branch data     Line data    Source code
       1                 :             : #include "platform/file-helpers.h"
       2                 :             : 
       3                 :             : 
       4                 :             : // This function is based in part on nall, which is under the following licence.
       5                 :             : // This modified version is licenced under the LGPL version 3 or later. See the LICENSE file
       6                 :             : // for details.
       7                 :             : //
       8                 :             : //   Copyright (c) 2006-2015  byuu
       9                 :             : //
      10                 :             : // Permission to use, copy, modify, and/or distribute this software for
      11                 :             : // any purpose with or without fee is hereby granted, provided that the
      12                 :             : // above copyright notice and this permission notice appear in all
      13                 :             : // copies.
      14                 :             : //
      15                 :             : // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
      16                 :             : // WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
      17                 :             : // WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
      18                 :             : // AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
      19                 :             : // DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
      20                 :             : // PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
      21                 :             : // TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
      22                 :             : // PERFORMANCE OF THIS SOFTWARE.
      23                 :         624 : string dir(char const *name)
      24                 :             : {
      25         [ +  - ]:        6095 :         for (signed i = (int)strlen(name); i >= 0; i--)
      26                 :             :         {
      27   [ +  +  -  + ]:        6095 :                 if (name[i] == '/' || name[i] == '\\')
      28                 :             :                 {
      29                 :         624 :                         return string(name, i+1);
      30                 :             :                 }
      31                 :             :         }
      32                 :           0 :         return "";
      33                 :             : }
      34                 :             : 
      35                 :         438 : string create_combined_path(const char* path1, const char* path2)
      36                 :             : {
      37                 :         438 :         string combined = path1;
      38                 :             : 
      39                 :             :         int length = combined.length();
      40                 :             : 
      41   [ +  -  +  -  :         438 :         if (combined.length() > 0 && path1[length - 1] != '\\' && path1[length - 1] != '/')
                   +  + ]
      42                 :             :         {
      43                 :          23 :                 combined += get_native_path_separator();
      44                 :             :         }
      45                 :             : 
      46                 :         438 :         combined += path2;
      47                 :             : 
      48                 :         876 :         return normalize_path(combined);
      49                 :         438 : }
      50                 :             : 
      51                 :             : 
      52                 :             : // RPG Hacker: This function attempts to normalize a path.
      53                 :             : // This means that it attempts to put it into a format
      54                 :             : // where a simple string compare between two paths
      55                 :             : // referring to the same file will hopefully always
      56                 :             : // succeed.
      57                 :             : // There are a few known problems and limitations:
      58                 :             : // - Relative paths are not recommended, as they can't be
      59                 :             : //   resolved reliably. For example, in this path
      60                 :             : //   ../patch/main.asm
      61                 :             : //   we can't collapse the .. because we don't know the
      62                 :             : //   parent directory. A comparison will also fail when
      63                 :             : //   one piece of code uses a relative path while another
      64                 :             : //   piece of code uses an absolute path. For those
      65                 :             : //   reasons, it's recommended to always use absolute paths
      66                 :             : //   everywhere if possible.
      67                 :             : // - Windows network paths like
      68                 :             : //   \\MY_PC\patch\main.asm
      69                 :             : //   Will likely break with this, since the function converts
      70                 :             : //   all back slashes to forward slashes. I think Windows
      71                 :             : //   actually requires back slashes for network paths.
      72                 :             : // - Currently, the code doesn't look at drive letters
      73                 :             : //   and just treats them as folders, so a path like
      74                 :             : //   C:/../patch/main.asm
      75                 :             : //   would result in
      76                 :             : //   patch/main.asm
      77                 :             : //   (However, a path like that is invalid, anyways, so
      78                 :             : //   this hopefully doesn't matter).
      79                 :        1400 : string normalize_path(const char* path)
      80                 :             : {
      81                 :        1400 :         string normalized = path;
      82                 :             : 
      83                 :             :         
      84                 :             :         // RPG Hacker: Replace all \ in path by /
      85                 :             :         // (Windows should work with / in paths just fine).
      86                 :             :         // Note: will likely break network paths on Windows,
      87                 :             :         // which still expect a prefix of \\, but does anyone
      88                 :             :         // seriously even use them with Asar?
      89         [ +  + ]:       97236 :         for (int i = 0; i < normalized.length(); ++i)
      90                 :             :         {
      91         [ -  + ]:       47218 :                 if (normalized[i] == '\\')
      92                 :             :                 {
      93                 :           0 :                         normalized.temp_raw()[i]= '/';
      94                 :             :                 }
      95                 :             :         }
      96                 :             : 
      97                 :             :         // RPG Hacker: Collapse path by removing all unnecessary
      98                 :             :         // . or .. path components.
      99                 :             :         // As a little hack, just overwrite all the stuff we're
     100                 :             :         // going to remove with 0x01 and remove it later. Probably
     101                 :             :         // easier than to always shorten the path immediately.
     102                 :             :         // Also using \x01 instead of \0 so that the path is still
     103                 :             :         // easily readable in a debugger (since it normally just
     104                 :             :         // assumes a string to end at \0). I don't think \x01 can
     105                 :             :         // be used in valid paths, so this should be okay.
     106                 :             :         char* previous_dir_start_pos = nullptr;
     107                 :             :         char* current_dir_start_pos = normalized.temp_raw();
     108         [ +  + ]:        2408 :         while (*current_dir_start_pos == '/')
     109                 :             :         {
     110                 :        1008 :                 ++current_dir_start_pos;
     111                 :             :         }
     112                 :             :         char* current_dir_end_pos = current_dir_start_pos;
     113                 :             : 
     114                 :             : 
     115         [ +  + ]:        7592 :         while (*current_dir_start_pos != '\0')
     116                 :             :         {
     117   [ +  +  +  + ]:       47619 :                 while (*current_dir_end_pos != '/' && *current_dir_end_pos != '\0')
     118                 :             :                 {
     119                 :       41427 :                         ++current_dir_end_pos;
     120                 :             :                 }
     121                 :             : 
     122                 :        6192 :                 size_t length = (size_t)(current_dir_end_pos - current_dir_start_pos);
     123   [ +  +  +  + ]:        6192 :                 if (length > 0 && strncmp(current_dir_start_pos, ".", length) == 0)
     124                 :             :                 {
     125                 :             :                         // Found a . path component - remove it.
     126         [ +  + ]:          84 :                         while (current_dir_start_pos != current_dir_end_pos)
     127                 :             :                         {
     128                 :          42 :                                 *current_dir_start_pos = '\x01';
     129                 :          42 :                                 ++current_dir_start_pos;
     130                 :             :                         }
     131                 :             : 
     132         [ +  - ]:          42 :                         if (*current_dir_start_pos == '/')
     133                 :             :                         {
     134                 :          42 :                                 *current_dir_start_pos = '\x01';
     135                 :          42 :                                 ++current_dir_end_pos;
     136                 :             :                         }
     137                 :             :                 }
     138         [ +  + ]:        6141 :                 else if (length > 0 && strncmp(current_dir_start_pos, "..", length) == 0)
     139                 :             :                 {
     140                 :             :                         // Found a .. path component - if we have any known
     141                 :             :                         // folder before it, remove them both.
     142         [ +  + ]:          42 :                         if (previous_dir_start_pos != nullptr)
     143                 :             :                         {
     144                 :             :                                 // previous_dir_start_pos and current_dir_start_pos are immediately
     145                 :             :                                 // set to something else shortly after, so it should be
     146                 :             :                                 // okay to move them directly here and not use a
     147                 :             :                                 // temporary variable.
     148   [ +  +  +  - ]:         198 :                                 while (*previous_dir_start_pos != '/' && *previous_dir_start_pos != '\0')
     149                 :             :                                 {
     150                 :         165 :                                         *previous_dir_start_pos = '\x01';
     151                 :         165 :                                         ++previous_dir_start_pos;
     152                 :             :                                 }
     153                 :             : 
     154         [ +  - ]:          33 :                                 if (*previous_dir_start_pos == '/')
     155                 :             :                                 {
     156                 :          33 :                                         *previous_dir_start_pos = '\x01';
     157                 :             :                                 }
     158                 :             : 
     159         [ +  + ]:          99 :                                 while (current_dir_start_pos != current_dir_end_pos)
     160                 :             :                                 {
     161                 :          66 :                                         *current_dir_start_pos = '\x01';
     162                 :          66 :                                         ++current_dir_start_pos;
     163                 :             :                                 }
     164                 :             : 
     165         [ +  - ]:          33 :                                 if (*current_dir_start_pos == '/')
     166                 :             :                                 {
     167                 :          33 :                                         *current_dir_start_pos = '\x01';
     168                 :          33 :                                         ++current_dir_end_pos;
     169                 :             :                                 }
     170                 :             :                         }
     171                 :             : 
     172                 :             :                         previous_dir_start_pos = nullptr;
     173                 :             :                 }
     174                 :             :                 else
     175                 :             :                 {
     176         [ +  + ]:        6108 :                         if (*current_dir_end_pos == '/')
     177                 :             :                         {
     178                 :        4708 :                                 ++current_dir_end_pos;
     179                 :             :                         }
     180                 :             : 
     181         [ +  + ]:        6108 :                         if (length > 0)
     182                 :             :                         {
     183                 :             :                                 previous_dir_start_pos = current_dir_start_pos;
     184                 :             :                         }
     185                 :             :                 }
     186                 :             : 
     187                 :             :                 current_dir_start_pos = current_dir_end_pos;
     188                 :             :         }
     189                 :             : 
     190                 :             : 
     191                 :             :         // Now construct our new string by copying everything but the \x01 into it.
     192                 :        1400 :         string copy;
     193                 :             : 
     194         [ +  + ]:       97236 :         for (int i = 0; i < normalized.length(); ++i)
     195                 :             :         {
     196         [ +  + ]:       47218 :                 if (normalized[i] != '\x01')
     197                 :             :                 {
     198                 :       46837 :                         copy += normalized[i];
     199                 :             :                 }
     200                 :             :         }
     201                 :             : 
     202                 :             :         normalized = copy;
     203                 :             : 
     204                 :             : 
     205                 :             :         // RPG Hacker: On Windows, file paths are case-insensitive.
     206                 :             :         // It isn't really good style to mix different cases, especially
     207                 :             :         // when referring to the same file, but it's theoretically possible
     208                 :             :         // to do so, so we need to handle it and not have Asar fail in this case.
     209                 :             :         // The easiest way to handle it is to convert the entire path to lowercase.
     210                 :             : #if defined(windows)
     211                 :             :         normalized = lower(normalized);
     212                 :             : #endif
     213                 :             : 
     214                 :             : 
     215                 :             :         // TODO: Maybe resolve symbolic links here?
     216                 :             :         // Not sure if it's a good idea and if it's needed in the first place.
     217                 :             :         // In theory, it could lead to some problems with files that exist
     218                 :             :         // only in memory.
     219                 :        1400 :         return normalized;
     220                 :        1400 : }
     221                 :             : 
     222                 :           0 : string get_base_name(char const *name)
     223                 :             : {
     224         [ #  # ]:           0 :         for(int i = (int)strlen(name); i >= 0; --i)
     225                 :             :         {
     226   [ #  #  #  # ]:           0 :                 if(name[i] == '/' || name[i] == '\\')
     227                 :             :                 {
     228                 :             :                         //file has no extension
     229                 :             :                         break;
     230                 :             :                 }
     231         [ #  # ]:           0 :                 if(name[i] == '.')
     232                 :             :                 {
     233                 :           0 :                         return string(name, i);
     234                 :             :                 }
     235                 :             :         }
     236                 :           0 :         return string(name);
     237                 :             : }
        

Generated by: LCOV version 2.0-1