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