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