PageRenderTime 50ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 1ms

/external/protobuf/src/google/protobuf/io/zero_copy_stream_impl.cc

https://gitlab.com/brian0218/rk3188_r-box_android4.2.2_sdk
C++ | 470 lines | 306 code | 93 blank | 71 comment | 50 complexity | 3bd715c86c776e88b1f97ec6e1325fb2 MD5 | raw file
  1. // Protocol Buffers - Google's data interchange format
  2. // Copyright 2008 Google Inc. All rights reserved.
  3. // http://code.google.com/p/protobuf/
  4. //
  5. // Redistribution and use in source and binary forms, with or without
  6. // modification, are permitted provided that the following conditions are
  7. // met:
  8. //
  9. // * Redistributions of source code must retain the above copyright
  10. // notice, this list of conditions and the following disclaimer.
  11. // * Redistributions in binary form must reproduce the above
  12. // copyright notice, this list of conditions and the following disclaimer
  13. // in the documentation and/or other materials provided with the
  14. // distribution.
  15. // * Neither the name of Google Inc. nor the names of its
  16. // contributors may be used to endorse or promote products derived from
  17. // this software without specific prior written permission.
  18. //
  19. // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  20. // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  21. // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  22. // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  23. // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  24. // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  25. // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  26. // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  27. // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  28. // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  29. // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  30. // Author: kenton@google.com (Kenton Varda)
  31. // Based on original Protocol Buffers design by
  32. // Sanjay Ghemawat, Jeff Dean, and others.
  33. #ifdef _MSC_VER
  34. #include <io.h>
  35. #else
  36. #include <unistd.h>
  37. #include <sys/types.h>
  38. #include <sys/stat.h>
  39. #include <fcntl.h>
  40. #endif
  41. #include <errno.h>
  42. #include <iostream>
  43. #include <algorithm>
  44. #include <google/protobuf/io/zero_copy_stream_impl.h>
  45. #include <google/protobuf/stubs/common.h>
  46. #include <google/protobuf/stubs/stl_util-inl.h>
  47. namespace google {
  48. namespace protobuf {
  49. namespace io {
  50. #ifdef _WIN32
  51. // Win32 lseek is broken: If invoked on a non-seekable file descriptor, its
  52. // return value is undefined. We re-define it to always produce an error.
  53. #define lseek(fd, offset, origin) ((off_t)-1)
  54. #endif
  55. namespace {
  56. // EINTR sucks.
  57. int close_no_eintr(int fd) {
  58. int result;
  59. do {
  60. result = close(fd);
  61. } while (result < 0 && errno == EINTR);
  62. return result;
  63. }
  64. } // namespace
  65. // ===================================================================
  66. FileInputStream::FileInputStream(int file_descriptor, int block_size)
  67. : copying_input_(file_descriptor),
  68. impl_(&copying_input_, block_size) {
  69. }
  70. FileInputStream::~FileInputStream() {}
  71. bool FileInputStream::Close() {
  72. return copying_input_.Close();
  73. }
  74. bool FileInputStream::Next(const void** data, int* size) {
  75. return impl_.Next(data, size);
  76. }
  77. void FileInputStream::BackUp(int count) {
  78. impl_.BackUp(count);
  79. }
  80. bool FileInputStream::Skip(int count) {
  81. return impl_.Skip(count);
  82. }
  83. int64 FileInputStream::ByteCount() const {
  84. return impl_.ByteCount();
  85. }
  86. FileInputStream::CopyingFileInputStream::CopyingFileInputStream(
  87. int file_descriptor)
  88. : file_(file_descriptor),
  89. close_on_delete_(false),
  90. is_closed_(false),
  91. errno_(0),
  92. previous_seek_failed_(false) {
  93. }
  94. FileInputStream::CopyingFileInputStream::~CopyingFileInputStream() {
  95. if (close_on_delete_) {
  96. if (!Close()) {
  97. GOOGLE_LOG(ERROR) << "close() failed: " << strerror(errno_);
  98. }
  99. }
  100. }
  101. bool FileInputStream::CopyingFileInputStream::Close() {
  102. GOOGLE_CHECK(!is_closed_);
  103. is_closed_ = true;
  104. if (close_no_eintr(file_) != 0) {
  105. // The docs on close() do not specify whether a file descriptor is still
  106. // open after close() fails with EIO. However, the glibc source code
  107. // seems to indicate that it is not.
  108. errno_ = errno;
  109. return false;
  110. }
  111. return true;
  112. }
  113. int FileInputStream::CopyingFileInputStream::Read(void* buffer, int size) {
  114. GOOGLE_CHECK(!is_closed_);
  115. int result;
  116. do {
  117. result = read(file_, buffer, size);
  118. } while (result < 0 && errno == EINTR);
  119. if (result < 0) {
  120. // Read error (not EOF).
  121. errno_ = errno;
  122. }
  123. return result;
  124. }
  125. int FileInputStream::CopyingFileInputStream::Skip(int count) {
  126. GOOGLE_CHECK(!is_closed_);
  127. if (!previous_seek_failed_ &&
  128. lseek(file_, count, SEEK_CUR) != (off_t)-1) {
  129. // Seek succeeded.
  130. return count;
  131. } else {
  132. // Failed to seek.
  133. // Note to self: Don't seek again. This file descriptor doesn't
  134. // support it.
  135. previous_seek_failed_ = true;
  136. // Use the default implementation.
  137. return CopyingInputStream::Skip(count);
  138. }
  139. }
  140. // ===================================================================
  141. FileOutputStream::FileOutputStream(int file_descriptor, int block_size)
  142. : copying_output_(file_descriptor),
  143. impl_(&copying_output_, block_size) {
  144. }
  145. FileOutputStream::~FileOutputStream() {
  146. impl_.Flush();
  147. }
  148. bool FileOutputStream::Close() {
  149. bool flush_succeeded = impl_.Flush();
  150. return copying_output_.Close() && flush_succeeded;
  151. }
  152. bool FileOutputStream::Flush() {
  153. return impl_.Flush();
  154. }
  155. bool FileOutputStream::Next(void** data, int* size) {
  156. return impl_.Next(data, size);
  157. }
  158. void FileOutputStream::BackUp(int count) {
  159. impl_.BackUp(count);
  160. }
  161. int64 FileOutputStream::ByteCount() const {
  162. return impl_.ByteCount();
  163. }
  164. FileOutputStream::CopyingFileOutputStream::CopyingFileOutputStream(
  165. int file_descriptor)
  166. : file_(file_descriptor),
  167. close_on_delete_(false),
  168. is_closed_(false),
  169. errno_(0) {
  170. }
  171. FileOutputStream::CopyingFileOutputStream::~CopyingFileOutputStream() {
  172. if (close_on_delete_) {
  173. if (!Close()) {
  174. GOOGLE_LOG(ERROR) << "close() failed: " << strerror(errno_);
  175. }
  176. }
  177. }
  178. bool FileOutputStream::CopyingFileOutputStream::Close() {
  179. GOOGLE_CHECK(!is_closed_);
  180. is_closed_ = true;
  181. if (close_no_eintr(file_) != 0) {
  182. // The docs on close() do not specify whether a file descriptor is still
  183. // open after close() fails with EIO. However, the glibc source code
  184. // seems to indicate that it is not.
  185. errno_ = errno;
  186. return false;
  187. }
  188. return true;
  189. }
  190. bool FileOutputStream::CopyingFileOutputStream::Write(
  191. const void* buffer, int size) {
  192. GOOGLE_CHECK(!is_closed_);
  193. int total_written = 0;
  194. const uint8* buffer_base = reinterpret_cast<const uint8*>(buffer);
  195. while (total_written < size) {
  196. int bytes;
  197. do {
  198. bytes = write(file_, buffer_base + total_written, size - total_written);
  199. } while (bytes < 0 && errno == EINTR);
  200. if (bytes <= 0) {
  201. // Write error.
  202. // FIXME(kenton): According to the man page, if write() returns zero,
  203. // there was no error; write() simply did not write anything. It's
  204. // unclear under what circumstances this might happen, but presumably
  205. // errno won't be set in this case. I am confused as to how such an
  206. // event should be handled. For now I'm treating it as an error, since
  207. // retrying seems like it could lead to an infinite loop. I suspect
  208. // this never actually happens anyway.
  209. if (bytes < 0) {
  210. errno_ = errno;
  211. }
  212. return false;
  213. }
  214. total_written += bytes;
  215. }
  216. return true;
  217. }
  218. // ===================================================================
  219. IstreamInputStream::IstreamInputStream(istream* input, int block_size)
  220. : copying_input_(input),
  221. impl_(&copying_input_, block_size) {
  222. }
  223. IstreamInputStream::~IstreamInputStream() {}
  224. bool IstreamInputStream::Next(const void** data, int* size) {
  225. return impl_.Next(data, size);
  226. }
  227. void IstreamInputStream::BackUp(int count) {
  228. impl_.BackUp(count);
  229. }
  230. bool IstreamInputStream::Skip(int count) {
  231. return impl_.Skip(count);
  232. }
  233. int64 IstreamInputStream::ByteCount() const {
  234. return impl_.ByteCount();
  235. }
  236. IstreamInputStream::CopyingIstreamInputStream::CopyingIstreamInputStream(
  237. istream* input)
  238. : input_(input) {
  239. }
  240. IstreamInputStream::CopyingIstreamInputStream::~CopyingIstreamInputStream() {}
  241. int IstreamInputStream::CopyingIstreamInputStream::Read(
  242. void* buffer, int size) {
  243. input_->read(reinterpret_cast<char*>(buffer), size);
  244. int result = input_->gcount();
  245. if (result == 0 && input_->fail() && !input_->eof()) {
  246. return -1;
  247. }
  248. return result;
  249. }
  250. // ===================================================================
  251. OstreamOutputStream::OstreamOutputStream(ostream* output, int block_size)
  252. : copying_output_(output),
  253. impl_(&copying_output_, block_size) {
  254. }
  255. OstreamOutputStream::~OstreamOutputStream() {
  256. impl_.Flush();
  257. }
  258. bool OstreamOutputStream::Next(void** data, int* size) {
  259. return impl_.Next(data, size);
  260. }
  261. void OstreamOutputStream::BackUp(int count) {
  262. impl_.BackUp(count);
  263. }
  264. int64 OstreamOutputStream::ByteCount() const {
  265. return impl_.ByteCount();
  266. }
  267. OstreamOutputStream::CopyingOstreamOutputStream::CopyingOstreamOutputStream(
  268. ostream* output)
  269. : output_(output) {
  270. }
  271. OstreamOutputStream::CopyingOstreamOutputStream::~CopyingOstreamOutputStream() {
  272. }
  273. bool OstreamOutputStream::CopyingOstreamOutputStream::Write(
  274. const void* buffer, int size) {
  275. output_->write(reinterpret_cast<const char*>(buffer), size);
  276. return output_->good();
  277. }
  278. // ===================================================================
  279. ConcatenatingInputStream::ConcatenatingInputStream(
  280. ZeroCopyInputStream* const streams[], int count)
  281. : streams_(streams), stream_count_(count), bytes_retired_(0) {
  282. }
  283. ConcatenatingInputStream::~ConcatenatingInputStream() {
  284. }
  285. bool ConcatenatingInputStream::Next(const void** data, int* size) {
  286. while (stream_count_ > 0) {
  287. if (streams_[0]->Next(data, size)) return true;
  288. // That stream is done. Advance to the next one.
  289. bytes_retired_ += streams_[0]->ByteCount();
  290. ++streams_;
  291. --stream_count_;
  292. }
  293. // No more streams.
  294. return false;
  295. }
  296. void ConcatenatingInputStream::BackUp(int count) {
  297. if (stream_count_ > 0) {
  298. streams_[0]->BackUp(count);
  299. } else {
  300. GOOGLE_LOG(DFATAL) << "Can't BackUp() after failed Next().";
  301. }
  302. }
  303. bool ConcatenatingInputStream::Skip(int count) {
  304. while (stream_count_ > 0) {
  305. // Assume that ByteCount() can be used to find out how much we actually
  306. // skipped when Skip() fails.
  307. int64 target_byte_count = streams_[0]->ByteCount() + count;
  308. if (streams_[0]->Skip(count)) return true;
  309. // Hit the end of the stream. Figure out how many more bytes we still have
  310. // to skip.
  311. int64 final_byte_count = streams_[0]->ByteCount();
  312. GOOGLE_DCHECK_LT(final_byte_count, target_byte_count);
  313. count = target_byte_count - final_byte_count;
  314. // That stream is done. Advance to the next one.
  315. bytes_retired_ += final_byte_count;
  316. ++streams_;
  317. --stream_count_;
  318. }
  319. return false;
  320. }
  321. int64 ConcatenatingInputStream::ByteCount() const {
  322. if (stream_count_ == 0) {
  323. return bytes_retired_;
  324. } else {
  325. return bytes_retired_ + streams_[0]->ByteCount();
  326. }
  327. }
  328. // ===================================================================
  329. LimitingInputStream::LimitingInputStream(ZeroCopyInputStream* input,
  330. int64 limit)
  331. : input_(input), limit_(limit) {}
  332. LimitingInputStream::~LimitingInputStream() {
  333. // If we overshot the limit, back up.
  334. if (limit_ < 0) input_->BackUp(-limit_);
  335. }
  336. bool LimitingInputStream::Next(const void** data, int* size) {
  337. if (limit_ <= 0) return false;
  338. if (!input_->Next(data, size)) return false;
  339. limit_ -= *size;
  340. if (limit_ < 0) {
  341. // We overshot the limit. Reduce *size to hide the rest of the buffer.
  342. *size += limit_;
  343. }
  344. return true;
  345. }
  346. void LimitingInputStream::BackUp(int count) {
  347. if (limit_ < 0) {
  348. input_->BackUp(count - limit_);
  349. limit_ = count;
  350. } else {
  351. input_->BackUp(count);
  352. limit_ += count;
  353. }
  354. }
  355. bool LimitingInputStream::Skip(int count) {
  356. if (count > limit_) {
  357. if (limit_ < 0) return false;
  358. input_->Skip(limit_);
  359. limit_ = 0;
  360. return false;
  361. } else {
  362. if (!input_->Skip(count)) return false;
  363. limit_ -= count;
  364. return true;
  365. }
  366. }
  367. int64 LimitingInputStream::ByteCount() const {
  368. if (limit_ < 0) {
  369. return input_->ByteCount() + limit_;
  370. } else {
  371. return input_->ByteCount();
  372. }
  373. }
  374. // ===================================================================
  375. } // namespace io
  376. } // namespace protobuf
  377. } // namespace google