1/* Copyright 2017 The TensorFlow Authors. All Rights Reserved.
2
3Licensed under the Apache License, Version 2.0 (the "License");
4you may not use this file except in compliance with the License.
5You may obtain a copy of the License at
6
7 http://www.apache.org/licenses/LICENSE-2.0
8
9Unless required by applicable law or agreed to in writing, software
10distributed under the License is distributed on an "AS IS" BASIS,
11WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12See the License for the specific language governing permissions and
13limitations 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__)
27namespace std {
28double round(double x) { return ::round(x); }
29} // namespace std
30#endif
31
32namespace toco {
33namespace port {
34void CopyToBuffer(const std::string& src, char* dest) {
35 memcpy(dest, src.data(), src.size());
36}
37
38#ifdef PLATFORM_GOOGLE
39void 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
56namespace toco {
57namespace port {
58
59void InitGoogle(const char* usage, int* argc, char*** argv, bool remove_flags) {
60 ::InitGoogle(usage, argc, argv, remove_flags);
61}
62
63void InitGoogleWasDoneElsewhere() {
64 // Nothing need be done since ::CheckInitGoogleIsDone() is aware of other
65 // possible initialization entry points.
66}
67
68void CheckInitGoogleIsDone(const char* message) {
69 ::CheckInitGoogleIsDone(message);
70}
71
72namespace file {
73
74// Conversion to our wrapper Status.
75tensorflow::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.
85toco::port::file::Options ToOptions(const ::file::Options& options) {
86 CHECK_EQ(&options, &::file::Defaults());
87 return Options();
88}
89
90tensorflow::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
99tensorflow::Status Readable(const std::string& filename,
100 const file::Options& options) {
101 return ToStatus(::file::Readable(filename, ::file::Defaults()));
102}
103
104tensorflow::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
110tensorflow::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
116tensorflow::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
122std::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
145namespace toco {
146namespace 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.
154constexpr int kFileCreateMode = _S_IREAD | _S_IWRITE;
155constexpr int kFileReadFlags = _O_RDONLY | _O_BINARY;
156constexpr int kFileWriteFlags = _O_WRONLY | _O_BINARY | _O_CREAT;
157#else
158constexpr int kFileCreateMode = 0664;
159constexpr int kFileReadFlags = O_RDONLY;
160constexpr int kFileWriteFlags = O_CREAT | O_WRONLY;
161#endif // _WIN32
162
163static bool port_initialized = false;
164
165void InitGoogleWasDoneElsewhere() { port_initialized = true; }
166
167void 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
176void CheckInitGoogleIsDone(const char* message) {
177 CHECK(port_initialized) << message;
178}
179
180namespace file {
181
182tensorflow::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
191tensorflow::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
201tensorflow::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
211tensorflow::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
242tensorflow::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
264string 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