Opera 12.15 Source Code
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

BufferedLowLevelFile.cpp 13KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469
  1. /* -*- Mode: c++; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*-
  2. **
  3. ** Copyright (C) 2004-2011 Opera Software ASA. All rights reserved.
  4. **
  5. ** This file is part of the Opera web browser.
  6. ** It may not be distributed under any circumstances.
  7. */
  8. #include "core/pch.h"
  9. #include "modules/search_engine/BufferedLowLevelFile.h"
  10. // Buffer during sequential read:
  11. //
  12. // virtual_file_pos physical_file_pos file_length
  13. // | | |
  14. // 0 V V V
  15. // +--------/ /----------+---+----------------+--------/ /-------+
  16. // | ... |///////buffer///////| ... |
  17. // +--------/ /----------+--------------------+--------/ /-------+
  18. // | |
  19. // buffer_start buffer_end
  20. //
  21. // |<--- n*buffer_size --->|<--- buffer_size -->|
  22. //
  23. //
  24. //
  25. // Buffer at end of file:
  26. // file_length,
  27. // virtual_file_pos physical_file_pos
  28. // | |
  29. // 0 V V
  30. // +--------/ /----------+--+-------------+
  31. // | ... |/////buffer/////|
  32. // +--------/ /----------+----------------+
  33. // | |
  34. // buffer_start buffer_end
  35. //
  36. // |<--- m*buffer_size --->|<--- buffer_size -->|
  37. //
  38. //
  39. //
  40. // Buffer after partially overlapping write (current implementation):
  41. //
  42. // virtual_file_pos,
  43. // physical_file_pos
  44. // |
  45. // 0 V
  46. // +--------/ /----------+--------------------+-------+--------------
  47. // | ... |///////buffer///////| ...
  48. // | |//////////////|###written###|
  49. // +--------/ /----------+--------------+-----+-------+--------------
  50. // | |
  51. // buffer_start buffer_end
  52. //
  53. // |<--- n*buffer_size --->|<--- buffer_size -->|
  54. //
  55. #define BAD_FILE_POS FILE_LENGTH_NONE
  56. #define OPF_IS_NEGATIVE(a) ((((a>>31)>>31)>>2) != 0)
  57. BufferedLowLevelFile*
  58. BufferedLowLevelFile::Create(
  59. OpLowLevelFile* wrapped_file,
  60. OP_STATUS& status,
  61. OpFileLength buffer_size,
  62. BOOL transfer_ownership)
  63. {
  64. if (!wrapped_file || buffer_size == 0)
  65. {
  66. status = OpStatus::ERR;
  67. return NULL;
  68. }
  69. unsigned char* buffer = OP_NEWA(unsigned char, (unsigned int)buffer_size);
  70. if (!buffer)
  71. {
  72. status = OpStatus::ERR_NO_MEMORY;
  73. return NULL;
  74. }
  75. // So now, we are guaranteed that m_f and m_buffer are always valid!
  76. BufferedLowLevelFile* wrapper = OP_NEW(BufferedLowLevelFile, (wrapped_file, buffer_size, buffer, transfer_ownership));
  77. if (!wrapper)
  78. {
  79. OP_DELETEA(buffer);
  80. status = OpStatus::ERR_NO_MEMORY;
  81. return NULL;
  82. }
  83. status = OpStatus::OK;
  84. return wrapper;
  85. }
  86. BufferedLowLevelFile::BufferedLowLevelFile(OpLowLevelFile* wrapped_file, OpFileLength buffer_size, unsigned char* buffer, BOOL transfer_ownership)
  87. : FileWrapper(wrapped_file, transfer_ownership),
  88. m_buffer(buffer),
  89. m_buffer_size(buffer_size),
  90. m_buffer_start(BAD_FILE_POS),
  91. m_buffer_end(BAD_FILE_POS),
  92. m_physical_file_pos(BAD_FILE_POS),
  93. m_virtual_file_pos(BAD_FILE_POS),
  94. m_file_length(BAD_FILE_POS),
  95. m_last_IO_operation(IO_unknown)
  96. {
  97. }
  98. BufferedLowLevelFile::~BufferedLowLevelFile()
  99. {
  100. OP_DELETEA(m_buffer);
  101. }
  102. OP_STATUS BufferedLowLevelFile::Open(int mode)
  103. {
  104. OP_STATUS status = FileWrapper::Open(mode);
  105. if (OpStatus::IsSuccess(status))
  106. m_physical_file_pos = m_virtual_file_pos = 0;
  107. else
  108. m_physical_file_pos = m_virtual_file_pos = BAD_FILE_POS;
  109. m_buffer_start = m_buffer_end = BAD_FILE_POS;
  110. m_file_length = BAD_FILE_POS;
  111. return status;
  112. }
  113. OP_STATUS BufferedLowLevelFile::Close()
  114. {
  115. m_physical_file_pos = m_virtual_file_pos = BAD_FILE_POS;
  116. m_buffer_start = m_buffer_end = BAD_FILE_POS;
  117. m_file_length = BAD_FILE_POS;
  118. return m_f->Close();
  119. }
  120. /** OPPS! Currently not posix compatible. Returns Eof()==TRUE when positioned at end of file,
  121. * not after trying to read past the end. */
  122. BOOL BufferedLowLevelFile::Eof() const
  123. {
  124. RETURN_VALUE_IF_ERROR(EnsureValidFileLength(), TRUE);
  125. RETURN_VALUE_IF_ERROR(EnsureValidVirtualFilePos(), TRUE);
  126. return m_file_length == m_virtual_file_pos;
  127. }
  128. OP_STATUS BufferedLowLevelFile::GetFilePos(OpFileLength* pos) const
  129. {
  130. OP_STATUS status;
  131. if (!pos)
  132. return OpStatus::ERR;
  133. if (OpStatus::IsError(status = EnsureValidVirtualFilePos())) {
  134. *pos = 0;
  135. return status;
  136. }
  137. *pos = m_virtual_file_pos;
  138. return OpStatus::OK;
  139. }
  140. OP_STATUS BufferedLowLevelFile::EnsureValidVirtualFilePos() const
  141. {
  142. OP_STATUS status = OpStatus::OK;
  143. if (m_virtual_file_pos == BAD_FILE_POS && OpStatus::IsSuccess(status = EnsureValidPhysicalFilePos()))
  144. m_virtual_file_pos = m_physical_file_pos;
  145. return status;
  146. }
  147. OP_STATUS BufferedLowLevelFile::EnsureValidPhysicalFilePos() const
  148. {
  149. OP_STATUS status = OpStatus::OK;
  150. OpFileLength actual_pos;
  151. if (m_physical_file_pos == BAD_FILE_POS && OpStatus::IsSuccess(status = m_f->GetFilePos(&actual_pos)))
  152. m_physical_file_pos = actual_pos;
  153. return status;
  154. }
  155. OP_STATUS BufferedLowLevelFile::SetFilePos(OpFileLength pos, OpSeekMode mode /* = SEEK_FROM_START */)
  156. {
  157. // Seeks are lazy, physical file position is not updated until Read/Write
  158. OP_ASSERT(pos != BAD_FILE_POS || mode == SEEK_FROM_CURRENT); // Seek-from-current with offset -1 is allowed
  159. RETURN_IF_ERROR(EnsureValidFileLength());
  160. switch (mode)
  161. {
  162. case SEEK_FROM_START:
  163. break;
  164. case SEEK_FROM_END:
  165. if (pos <= m_file_length)
  166. pos = m_file_length - pos;
  167. else
  168. pos = BAD_FILE_POS;
  169. break;
  170. case SEEK_FROM_CURRENT:
  171. RETURN_IF_ERROR(EnsureValidVirtualFilePos());
  172. pos += m_virtual_file_pos;
  173. break;
  174. }
  175. if (pos == BAD_FILE_POS || pos > m_file_length || OPF_IS_NEGATIVE(pos))
  176. return OpStatus::ERR;
  177. m_virtual_file_pos = pos;
  178. return OpStatus::OK;
  179. }
  180. OP_STATUS BufferedLowLevelFile::EnsurePhysicalFilePos(OpFileLength pos, IOop operation)
  181. {
  182. OP_STATUS status;
  183. OP_ASSERT(pos != BAD_FILE_POS);
  184. if (pos == m_physical_file_pos && (operation & m_last_IO_operation) != 0)
  185. {
  186. m_last_IO_operation = operation;
  187. return OpStatus::OK;
  188. }
  189. m_physical_file_pos = pos;
  190. status = m_f->SetFilePos(pos);
  191. if (OpStatus::IsError(status))
  192. m_physical_file_pos = BAD_FILE_POS;
  193. else
  194. m_last_IO_operation = operation;
  195. return status;
  196. }
  197. OP_STATUS BufferedLowLevelFile::GetFileLength(OpFileLength* len) const
  198. {
  199. OP_STATUS status;
  200. if (!len)
  201. return OpStatus::ERR;
  202. if (OpStatus::IsError(status = EnsureValidFileLength())) {
  203. *len = 0;
  204. return status;
  205. }
  206. *len = m_file_length;
  207. return OpStatus::OK;
  208. }
  209. OP_STATUS BufferedLowLevelFile::EnsureValidFileLength() const
  210. {
  211. OP_STATUS status = OpStatus::OK;
  212. OpFileLength actual_length;
  213. if (m_file_length == BAD_FILE_POS && OpStatus::IsSuccess(status = m_f->GetFileLength(&actual_length)))
  214. m_file_length = actual_length;
  215. return status;
  216. }
  217. OP_STATUS BufferedLowLevelFile::Write(const void* data, OpFileLength len)
  218. {
  219. OP_STATUS status;
  220. RETURN_IF_ERROR(EnsureValidFileLength());
  221. if ((m_mode & OPFILE_APPEND) != 0)
  222. m_virtual_file_pos = m_file_length;
  223. else
  224. RETURN_IF_ERROR(EnsureValidVirtualFilePos());
  225. RETURN_IF_ERROR(EnsurePhysicalFilePos(m_virtual_file_pos, IO_write));
  226. if (m_buffer_start != BAD_FILE_POS && m_virtual_file_pos+len > m_buffer_start && m_virtual_file_pos < m_buffer_end)
  227. {
  228. // Buffered data overlaps -> update buffer with what's written
  229. OpFileLength cpy_len, data_off, buf_off;
  230. cpy_len = len;
  231. buf_off = m_virtual_file_pos - m_buffer_start;
  232. data_off = 0;
  233. if (m_virtual_file_pos < m_buffer_start)
  234. {
  235. buf_off = 0;
  236. data_off = m_buffer_start - m_virtual_file_pos;
  237. cpy_len -= data_off;
  238. }
  239. if (m_virtual_file_pos + len > m_buffer_end) {
  240. if (m_buffer_end - m_buffer_start < m_buffer_size) {
  241. // Expand the buffer
  242. m_buffer_end = m_virtual_file_pos + len;
  243. if (m_buffer_end - m_buffer_start > m_buffer_size)
  244. m_buffer_end = m_buffer_start + m_buffer_size;
  245. }
  246. if (m_virtual_file_pos + len > m_buffer_end)
  247. cpy_len -= m_virtual_file_pos + len - m_buffer_end;
  248. }
  249. op_memcpy(m_buffer + buf_off, (const char*)data + data_off, (size_t)cpy_len);
  250. }
  251. status = m_f->Write(data, len);
  252. if (OpStatus::IsSuccess(status))
  253. {
  254. m_physical_file_pos = m_virtual_file_pos += len;
  255. if (m_physical_file_pos > m_file_length)
  256. m_file_length = m_physical_file_pos;
  257. }
  258. else
  259. {
  260. m_physical_file_pos = m_virtual_file_pos = BAD_FILE_POS;
  261. m_buffer_start = m_buffer_end = BAD_FILE_POS;
  262. m_file_length = BAD_FILE_POS;
  263. }
  264. return status;
  265. }
  266. OP_STATUS BufferedLowLevelFile::Read(void* data, OpFileLength len, OpFileLength* bytes_read)
  267. {
  268. OP_STATUS status;
  269. RETURN_IF_ERROR(EnsureValidFileLength());
  270. RETURN_IF_ERROR(EnsureValidVirtualFilePos());
  271. if (!bytes_read)
  272. return OpStatus::ERR_NULL_POINTER;
  273. status = BufferedRead(data, len, bytes_read);
  274. if (OpStatus::IsError(status))
  275. {
  276. m_physical_file_pos = m_virtual_file_pos = BAD_FILE_POS;
  277. m_buffer_start = m_buffer_end = BAD_FILE_POS;
  278. }
  279. return status;
  280. }
  281. OP_STATUS BufferedLowLevelFile::ReadLine(char** data)
  282. {
  283. // Not implemented, so just invalidate everything and call underlying file
  284. m_physical_file_pos = m_virtual_file_pos = BAD_FILE_POS;
  285. m_buffer_start = m_buffer_end = BAD_FILE_POS;
  286. return m_f->ReadLine(data);
  287. }
  288. OpLowLevelFile* BufferedLowLevelFile::CreateCopy()
  289. {
  290. OpLowLevelFile* copy;
  291. OpLowLevelFile* unbuffered_copy = m_f->CreateCopy();
  292. if (!unbuffered_copy)
  293. return NULL;
  294. OP_STATUS res;
  295. copy = BufferedLowLevelFile::Create(unbuffered_copy, res, m_buffer_size);
  296. if (!OpStatus::IsSuccess(res))
  297. {
  298. OP_DELETE(unbuffered_copy);
  299. return NULL;
  300. }
  301. return copy;
  302. }
  303. OpLowLevelFile* BufferedLowLevelFile::CreateTempFile(const uni_char* prefix)
  304. {
  305. OpLowLevelFile* temp;
  306. OpLowLevelFile* unbuffered_temp = m_f->CreateTempFile(prefix);
  307. if (!unbuffered_temp)
  308. return NULL;
  309. OP_STATUS res;
  310. temp = BufferedLowLevelFile::Create(unbuffered_temp, res, m_buffer_size);
  311. if (!OpStatus::IsSuccess(res))
  312. {
  313. OP_DELETE(unbuffered_temp);
  314. return NULL;
  315. }
  316. return temp;
  317. }
  318. OP_STATUS BufferedLowLevelFile::SafeClose()
  319. {
  320. m_physical_file_pos = m_virtual_file_pos = BAD_FILE_POS;
  321. m_buffer_start = m_buffer_end = BAD_FILE_POS;
  322. m_file_length = BAD_FILE_POS;
  323. return m_f->SafeClose();
  324. }
  325. OP_STATUS BufferedLowLevelFile::Flush()
  326. {
  327. OP_STATUS s;
  328. s = m_f->Flush();
  329. m_physical_file_pos = BAD_FILE_POS;
  330. return s;
  331. }
  332. OP_STATUS BufferedLowLevelFile::SetFileLength(OpFileLength len)
  333. {
  334. OP_STATUS status;
  335. OP_ASSERT(len != BAD_FILE_POS);
  336. if (len == m_file_length)
  337. return OpStatus::OK;
  338. m_file_length = len;
  339. m_physical_file_pos = BAD_FILE_POS;
  340. m_virtual_file_pos = BAD_FILE_POS;
  341. if (m_buffer_start != BAD_FILE_POS && m_buffer_start >= len)
  342. m_buffer_start = m_buffer_end = BAD_FILE_POS;
  343. if (m_buffer_end != BAD_FILE_POS && m_buffer_end > len)
  344. m_buffer_end = len;
  345. status = m_f->SetFileLength(len);
  346. if (OpStatus::IsError(status)) {
  347. m_buffer_start = m_buffer_end = BAD_FILE_POS;
  348. m_file_length = BAD_FILE_POS;
  349. }
  350. return status;
  351. }
  352. OP_STATUS BufferedLowLevelFile::BufferVirtualFilePos()
  353. {
  354. OP_STATUS status;
  355. OpFileLength start, bytes_read;
  356. if (m_buffer_start != BAD_FILE_POS && m_virtual_file_pos >= m_buffer_start && m_virtual_file_pos < m_buffer_end)
  357. return OpStatus::OK;
  358. // Buffers are aligned on m_buffer_size boundaries
  359. start = (m_virtual_file_pos/m_buffer_size)*m_buffer_size;
  360. RETURN_IF_ERROR(EnsurePhysicalFilePos(start, IO_read));
  361. status = m_f->Read(m_buffer, m_buffer_size, &bytes_read);
  362. if (OpStatus::IsSuccess(status))
  363. {
  364. m_buffer_start = start;
  365. m_buffer_end = start+bytes_read;
  366. m_physical_file_pos = m_buffer_end;
  367. if (m_virtual_file_pos >= m_buffer_end) // Unable to buffer the actual m_virtual_file_pos
  368. return OpStatus::ERR;
  369. }
  370. else
  371. {
  372. m_physical_file_pos = m_virtual_file_pos = BAD_FILE_POS;
  373. m_buffer_start = m_buffer_end = BAD_FILE_POS;
  374. }
  375. return status;
  376. }
  377. OP_STATUS BufferedLowLevelFile::BufferedRead(void* data, OpFileLength len, OpFileLength* bytes_read)
  378. {
  379. OP_STATUS status;
  380. OpFileLength size;
  381. *bytes_read = 0;
  382. while (len > 0 && m_virtual_file_pos < m_file_length)
  383. {
  384. status = BufferVirtualFilePos();
  385. if (OpStatus::IsError(status))
  386. return *bytes_read > 0 ? OpStatus::OK : status;
  387. size = len;
  388. if (size > m_buffer_end - m_virtual_file_pos)
  389. size = m_buffer_end - m_virtual_file_pos;
  390. op_memcpy(data, m_buffer + (m_virtual_file_pos - m_buffer_start), (size_t)size);
  391. data = (char*)data + size;
  392. len -= size;
  393. m_virtual_file_pos += size;
  394. *bytes_read += size;
  395. }
  396. return OpStatus::OK;
  397. }
  398. #undef BAD_FILE_POS
  399. #undef OPF_IS_NEGATIVE