Home | History | Annotate | Download | only in ports
      1 /*
      2  * Copyright 2006 The Android Open Source Project
      3  *
      4  * Use of this source code is governed by a BSD-style license that can be
      5  * found in the LICENSE file.
      6  */
      7 
      8 #include "SkOSFile.h"
      9 #include "SkTypes.h"
     10 
     11 #include <errno.h>
     12 #include <stdio.h>
     13 #include <sys/stat.h>
     14 
     15 #ifdef SK_BUILD_FOR_UNIX
     16 #include <unistd.h>
     17 #endif
     18 
     19 #ifdef _WIN32
     20 #include <direct.h>
     21 #include <io.h>
     22 #include <vector>
     23 #include "SkUtils.h"
     24 #endif
     25 
     26 #ifdef SK_BUILD_FOR_IOS
     27 #include "SkOSFile_ios.h"
     28 #endif
     29 
     30 #ifdef _WIN32
     31 static bool is_ascii(const char* s) {
     32     while (char v = *s++) {
     33         if ((v & 0x80) != 0) {
     34             return false;
     35         }
     36     }
     37     return true;
     38 }
     39 
     40 static FILE* fopen_win(const char* utf8path, const char* perm) {
     41     if (is_ascii(utf8path)) {
     42         return fopen(utf8path, perm);
     43     }
     44 
     45     const char* ptr = utf8path;
     46     const char* end = utf8path + strlen(utf8path);
     47     size_t n = 0;
     48     while (ptr < end) {
     49         SkUnichar u = SkUTF8_NextUnicharWithError(&ptr, end);
     50         if (u < 0) {
     51             return nullptr;  // malformed UTF-8
     52         }
     53         n += SkUTF16_FromUnichar(u);
     54     }
     55     std::vector<uint16_t> wchars(n + 1);
     56     uint16_t* out = wchars.data();
     57     for (const char* ptr = utf8path; ptr < end;) {
     58         out += SkUTF16_FromUnichar(SkUTF8_NextUnicharWithError(&ptr, end), out);
     59     }
     60     SkASSERT(out == &wchars[n]);
     61     *out = 0; // final null
     62     wchar_t wperms[4] = {(wchar_t)perm[0], (wchar_t)perm[1], (wchar_t)perm[2], (wchar_t)perm[3]};
     63     return _wfopen((wchar_t*)wchars.data(), wperms);
     64 }
     65 #endif
     66 
     67 FILE* sk_fopen(const char path[], SkFILE_Flags flags) {
     68     char    perm[4] = {0, 0, 0, 0};
     69     char*   p = perm;
     70 
     71     if (flags & kRead_SkFILE_Flag) {
     72         *p++ = 'r';
     73     }
     74     if (flags & kWrite_SkFILE_Flag) {
     75         *p++ = 'w';
     76     }
     77     *p = 'b';
     78 
     79     FILE* file = nullptr;
     80 #ifdef _WIN32
     81     file = fopen_win(path, perm);
     82 #else
     83     file = fopen(path, perm);
     84 #endif
     85 #ifdef SK_BUILD_FOR_IOS
     86     // if not found in default path and read-only, try to open from bundle
     87     if (!file && kRead_SkFILE_Flag == flags) {
     88         SkString bundlePath;
     89         if (ios_get_path_in_bundle(path, &bundlePath)) {
     90             file = fopen(bundlePath.c_str(), perm);
     91         }
     92     }
     93 #endif
     94 
     95     if (nullptr == file && (flags & kWrite_SkFILE_Flag)) {
     96         SkDEBUGF(("sk_fopen: fopen(\"%s\", \"%s\") returned nullptr (errno:%d): %s\n",
     97                   path, perm, errno, strerror(errno)));
     98     }
     99     return file;
    100 }
    101 
    102 size_t sk_fgetsize(FILE* f) {
    103     SkASSERT(f);
    104 
    105     long curr = ftell(f); // remember where we are
    106     if (curr < 0) {
    107         return 0;
    108     }
    109 
    110     fseek(f, 0, SEEK_END); // go to the end
    111     long size = ftell(f); // record the size
    112     if (size < 0) {
    113         size = 0;
    114     }
    115 
    116     fseek(f, curr, SEEK_SET); // go back to our prev location
    117     return size;
    118 }
    119 
    120 size_t sk_fwrite(const void* buffer, size_t byteCount, FILE* f) {
    121     SkASSERT(f);
    122     return fwrite(buffer, 1, byteCount, f);
    123 }
    124 
    125 void sk_fflush(FILE* f) {
    126     SkASSERT(f);
    127     fflush(f);
    128 }
    129 
    130 void sk_fsync(FILE* f) {
    131 #if !defined(_WIN32) && !defined(SK_BUILD_FOR_ANDROID) && !defined(__UCLIBC__) \
    132         && !defined(_NEWLIB_VERSION)
    133     int fd = fileno(f);
    134     fsync(fd);
    135 #endif
    136 }
    137 
    138 size_t sk_ftell(FILE* f) {
    139     long curr = ftell(f);
    140     if (curr < 0) {
    141         return 0;
    142     }
    143     return curr;
    144 }
    145 
    146 void sk_fclose(FILE* f) {
    147     if (f) {
    148         fclose(f);
    149     }
    150 }
    151 
    152 bool sk_isdir(const char *path) {
    153     struct stat status;
    154     if (0 != stat(path, &status)) {
    155 #ifdef SK_BUILD_FOR_IOS
    156         // check the bundle directory if not in default path
    157         SkString bundlePath;
    158         if (ios_get_path_in_bundle(path, &bundlePath)) {
    159             if (0 != stat(bundlePath.c_str(), &status)) {
    160                 return false;
    161             }
    162         }
    163 #else
    164         return false;
    165 #endif
    166     }
    167     return SkToBool(status.st_mode & S_IFDIR);
    168 }
    169 
    170 bool sk_mkdir(const char* path) {
    171     if (sk_isdir(path)) {
    172         return true;
    173     }
    174     if (sk_exists(path)) {
    175         fprintf(stderr,
    176                 "sk_mkdir: path '%s' already exists but is not a directory\n",
    177                 path);
    178         return false;
    179     }
    180 
    181     int retval;
    182 #ifdef _WIN32
    183     retval = _mkdir(path);
    184 #else
    185     retval = mkdir(path, 0777);
    186 #endif
    187     return 0 == retval;
    188 }
    189