1 | /* Copyright 2017 The TensorFlow Authors. All Rights Reserved. |
2 | |
3 | Licensed under the Apache License, Version 2.0 (the "License"); |
4 | you may not use this file except in compliance with the License. |
5 | You may obtain a copy of the License at |
6 | |
7 | http://www.apache.org/licenses/LICENSE-2.0 |
8 | |
9 | Unless required by applicable law or agreed to in writing, software |
10 | distributed under the License is distributed on an "AS IS" BASIS, |
11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
12 | See the License for the specific language governing permissions and |
13 | limitations under the License. |
14 | ==============================================================================*/ |
15 | #include "tensorflow/lite/toco/toco_port.h" |
16 | |
17 | #include <cstring> |
18 | #include <string> |
19 | |
20 | #include "absl/status/status.h" |
21 | #include "tensorflow/core/lib/core/errors.h" |
22 | #include "tensorflow/core/lib/core/status.h" |
23 | #include "tensorflow/core/platform/logging.h" |
24 | #include "tensorflow/lite/toco/toco_types.h" |
25 | |
26 | #if defined(__ANDROID__) && defined(__ARM_ARCH_7A__) |
27 | namespace std { |
28 | double round(double x) { return ::round(x); } |
29 | } // namespace std |
30 | #endif |
31 | |
32 | namespace toco { |
33 | namespace port { |
34 | void CopyToBuffer(const std::string& src, char* dest) { |
35 | memcpy(dest, src.data(), src.size()); |
36 | } |
37 | |
38 | #ifdef PLATFORM_GOOGLE |
39 | void CopyToBuffer(const absl::Cord& src, char* dest) { src.CopyToArray(dest); } |
40 | #endif |
41 | } // namespace port |
42 | } // namespace toco |
43 | |
44 | #if defined(PLATFORM_GOOGLE) && !defined(__APPLE__) && \ |
45 | !defined(__ANDROID__) && !defined(_WIN32) |
46 | |
47 | // Wrap Google file operations. |
48 | |
49 | #include "base/init_google.h" |
50 | #include "file/base/file.h" |
51 | #include "file/base/filesystem.h" |
52 | #include "file/base/helpers.h" |
53 | #include "file/base/options.h" |
54 | #include "file/base/path.h" |
55 | |
56 | namespace toco { |
57 | namespace port { |
58 | |
59 | void InitGoogle(const char* usage, int* argc, char*** argv, bool remove_flags) { |
60 | ::InitGoogle(usage, argc, argv, remove_flags); |
61 | } |
62 | |
63 | void InitGoogleWasDoneElsewhere() { |
64 | // Nothing need be done since ::CheckInitGoogleIsDone() is aware of other |
65 | // possible initialization entry points. |
66 | } |
67 | |
68 | void CheckInitGoogleIsDone(const char* message) { |
69 | ::CheckInitGoogleIsDone(message); |
70 | } |
71 | |
72 | namespace file { |
73 | |
74 | // Conversion to our wrapper Status. |
75 | tensorflow::Status ToStatus(const absl::Status& uts) { |
76 | if (!uts.ok()) { |
77 | return tensorflow::Status( |
78 | tensorflow::errors::Code(::util::RetrieveErrorCode(uts)), |
79 | uts.error_message()); |
80 | } |
81 | return ::tensorflow::OkStatus(); |
82 | } |
83 | |
84 | // Conversion to our wrapper Options. |
85 | toco::port::file::Options ToOptions(const ::file::Options& options) { |
86 | CHECK_EQ(&options, &::file::Defaults()); |
87 | return Options(); |
88 | } |
89 | |
90 | tensorflow::Status Writable(const std::string& filename) { |
91 | File* f = nullptr; |
92 | const auto status = ::file::Open(filename, "w" , &f, ::file::Defaults()); |
93 | if (f) { |
94 | QCHECK_OK(f->Close(::file::Defaults())); |
95 | } |
96 | return ToStatus(status); |
97 | } |
98 | |
99 | tensorflow::Status Readable(const std::string& filename, |
100 | const file::Options& options) { |
101 | return ToStatus(::file::Readable(filename, ::file::Defaults())); |
102 | } |
103 | |
104 | tensorflow::Status Exists(const std::string& filename, |
105 | const file::Options& options) { |
106 | auto status = ::file::Exists(filename, ::file::Defaults()); |
107 | return ToStatus(status); |
108 | } |
109 | |
110 | tensorflow::Status GetContents(const std::string& filename, |
111 | std::string* contents, |
112 | const file::Options& options) { |
113 | return ToStatus(::file::GetContents(filename, contents, ::file::Defaults())); |
114 | } |
115 | |
116 | tensorflow::Status SetContents(const std::string& filename, |
117 | const std::string& contents, |
118 | const file::Options& options) { |
119 | return ToStatus(::file::SetContents(filename, contents, ::file::Defaults())); |
120 | } |
121 | |
122 | std::string JoinPath(const std::string& a, const std::string& b) { |
123 | return ::file::JoinPath(a, b); |
124 | } |
125 | |
126 | } // namespace file |
127 | } // namespace port |
128 | } // namespace toco |
129 | |
130 | #else // !PLATFORM_GOOGLE || __APPLE__ || __ANDROID__ || _WIN32 |
131 | |
132 | #include <fcntl.h> |
133 | #if defined(_WIN32) |
134 | #include <io.h> // for _close, _open, _read |
135 | #endif |
136 | #include <sys/stat.h> |
137 | #include <sys/types.h> |
138 | #include <unistd.h> |
139 | #include <cstdio> |
140 | |
141 | #if defined(PLATFORM_GOOGLE) |
142 | #include "base/commandlineflags.h" |
143 | #endif |
144 | |
145 | namespace toco { |
146 | namespace port { |
147 | |
148 | #if defined(_WIN32) |
149 | #define close _close |
150 | #define open _open |
151 | #define read _read |
152 | // Windows does not support the same set of file permissions as other platforms, |
153 | // and also requires an explicit flag for binary file read/write support. |
154 | constexpr int kFileCreateMode = _S_IREAD | _S_IWRITE; |
155 | constexpr int kFileReadFlags = _O_RDONLY | _O_BINARY; |
156 | constexpr int kFileWriteFlags = _O_WRONLY | _O_BINARY | _O_CREAT; |
157 | #else |
158 | constexpr int kFileCreateMode = 0664; |
159 | constexpr int kFileReadFlags = O_RDONLY; |
160 | constexpr int kFileWriteFlags = O_CREAT | O_WRONLY; |
161 | #endif // _WIN32 |
162 | |
163 | static bool port_initialized = false; |
164 | |
165 | void InitGoogleWasDoneElsewhere() { port_initialized = true; } |
166 | |
167 | void InitGoogle(const char* usage, int* argc, char*** argv, bool remove_flags) { |
168 | if (!port_initialized) { |
169 | #if defined(PLATFORM_GOOGLE) |
170 | ParseCommandLineFlags(argc, argv, remove_flags); |
171 | #endif |
172 | port_initialized = true; |
173 | } |
174 | } |
175 | |
176 | void CheckInitGoogleIsDone(const char* message) { |
177 | CHECK(port_initialized) << message; |
178 | } |
179 | |
180 | namespace file { |
181 | |
182 | tensorflow::Status Writable(const string& filename) { |
183 | FILE* f = fopen(filename.c_str(), "w" ); |
184 | if (f) { |
185 | fclose(f); |
186 | return tensorflow::OkStatus(); |
187 | } |
188 | return tensorflow::errors::NotFound("not writable" ); |
189 | } |
190 | |
191 | tensorflow::Status Readable(const string& filename, |
192 | const file::Options& options) { |
193 | FILE* f = fopen(filename.c_str(), "r" ); |
194 | if (f) { |
195 | fclose(f); |
196 | return tensorflow::OkStatus(); |
197 | } |
198 | return tensorflow::errors::NotFound("not readable" ); |
199 | } |
200 | |
201 | tensorflow::Status Exists(const string& filename, |
202 | const file::Options& options) { |
203 | struct stat statbuf; |
204 | int ret = stat(filename.c_str(), &statbuf); |
205 | if (ret == -1) { |
206 | return tensorflow::errors::NotFound("file doesn't exist" ); |
207 | } |
208 | return tensorflow::OkStatus(); |
209 | } |
210 | |
211 | tensorflow::Status GetContents(const string& path, string* output, |
212 | const file::Options& options) { |
213 | output->clear(); |
214 | |
215 | int fd = open(path.c_str(), kFileReadFlags); |
216 | if (fd == -1) { |
217 | return tensorflow::errors::NotFound("can't open() for read" ); |
218 | } |
219 | |
220 | // Direct read, for speed. |
221 | const int kBufSize = 1 << 16; |
222 | char buffer[kBufSize]; |
223 | while (true) { |
224 | int size = read(fd, buffer, kBufSize); |
225 | if (size == 0) { |
226 | // Done. |
227 | close(fd); |
228 | return tensorflow::OkStatus(); |
229 | } else if (size == -1) { |
230 | // Error. |
231 | close(fd); |
232 | return tensorflow::errors::Internal("error during read()" ); |
233 | } else { |
234 | output->append(buffer, size); |
235 | } |
236 | } |
237 | |
238 | CHECK(0); |
239 | return tensorflow::errors::Internal("internal error" ); |
240 | } |
241 | |
242 | tensorflow::Status SetContents(const string& filename, const string& contents, |
243 | const file::Options& options) { |
244 | int fd = open(filename.c_str(), kFileWriteFlags, kFileCreateMode); |
245 | if (fd == -1) { |
246 | return tensorflow::errors::Internal("can't open() for write" ); |
247 | } |
248 | |
249 | size_t i = 0; |
250 | while (i < contents.size()) { |
251 | size_t to_write = contents.size() - i; |
252 | ssize_t written = write(fd, &contents[i], to_write); |
253 | if (written == -1) { |
254 | close(fd); |
255 | return tensorflow::errors::Internal("write() error" ); |
256 | } |
257 | i += written; |
258 | } |
259 | close(fd); |
260 | |
261 | return tensorflow::OkStatus(); |
262 | } |
263 | |
264 | string JoinPath(const string& base, const string& filename) { |
265 | if (base.empty()) return filename; |
266 | string base_fixed = base; |
267 | if (!base_fixed.empty() && base_fixed.back() == '/') base_fixed.pop_back(); |
268 | string filename_fixed = filename; |
269 | if (!filename_fixed.empty() && filename_fixed.front() == '/') |
270 | filename_fixed.erase(0, 1); |
271 | return base_fixed + "/" + filename_fixed; |
272 | } |
273 | |
274 | } // namespace file |
275 | } // namespace port |
276 | } // namespace toco |
277 | |
278 | #endif // !PLATFORM_GOOGLE || __APPLE || __ANDROID__ || _WIN32 |
279 | |