File.cpp 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382
  1. //
  2. // Copyright (c) 2008-2013 the Urho3D project.
  3. //
  4. // Permission is hereby granted, free of charge, to any person obtaining a copy
  5. // of this software and associated documentation files (the "Software"), to deal
  6. // in the Software without restriction, including without limitation the rights
  7. // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  8. // copies of the Software, and to permit persons to whom the Software is
  9. // furnished to do so, subject to the following conditions:
  10. //
  11. // The above copyright notice and this permission notice shall be included in
  12. // all copies or substantial portions of the Software.
  13. //
  14. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  19. // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  20. // THE SOFTWARE.
  21. //
  22. #include "Precompiled.h"
  23. #include "File.h"
  24. #include "FileSystem.h"
  25. #include "Log.h"
  26. #include "PackageFile.h"
  27. #include "Profiler.h"
  28. #include <cstdio>
  29. #include "DebugNew.h"
  30. namespace Urho3D
  31. {
  32. #ifdef WIN32
  33. static const wchar_t* openMode[] =
  34. {
  35. L"rb",
  36. L"wb",
  37. L"w+b"
  38. };
  39. #else
  40. static const char* openMode[] =
  41. {
  42. "rb",
  43. "wb",
  44. "w+b"
  45. };
  46. #endif
  47. #ifdef ANDROID
  48. static const unsigned READ_BUFFER_SIZE = 1024;
  49. #endif
  50. File::File(Context* context) :
  51. Object(context),
  52. mode_(FILE_READ),
  53. handle_(0),
  54. #ifdef ANDROID
  55. assetHandle_(0),
  56. readBufferOffset_(0),
  57. readBufferSize_(0),
  58. #endif
  59. offset_(0),
  60. checksum_(0)
  61. {
  62. }
  63. File::File(Context* context, const String& fileName, FileMode mode) :
  64. Object(context),
  65. mode_(FILE_READ),
  66. handle_(0),
  67. #ifdef ANDROID
  68. assetHandle_(0),
  69. readBufferOffset_(0),
  70. readBufferSize_(0),
  71. #endif
  72. offset_(0),
  73. checksum_(0)
  74. {
  75. Open(fileName, mode);
  76. }
  77. File::File(Context* context, PackageFile* package, const String& fileName) :
  78. Object(context),
  79. mode_(FILE_READ),
  80. handle_(0),
  81. #ifdef ANDROID
  82. assetHandle_(0),
  83. readBufferOffset_(0),
  84. readBufferSize_(0),
  85. #endif
  86. offset_(0),
  87. checksum_(0)
  88. {
  89. Open(package, fileName);
  90. }
  91. File::~File()
  92. {
  93. Close();
  94. }
  95. bool File::Open(const String& fileName, FileMode mode)
  96. {
  97. Close();
  98. FileSystem* fileSystem = GetSubsystem<FileSystem>();
  99. if (fileSystem && !fileSystem->CheckAccess(GetPath(fileName)))
  100. {
  101. LOGERROR("Access denied to " + fileName);
  102. return false;
  103. }
  104. #ifdef ANDROID
  105. if (fileName.StartsWith("/apk/"))
  106. {
  107. if (mode != FILE_READ)
  108. {
  109. LOGERROR("Only read mode is supported for asset files");
  110. return false;
  111. }
  112. assetHandle_ = SDL_RWFromFile(fileName.Substring(5).CString(), "rb");
  113. if (!assetHandle_)
  114. {
  115. LOGERROR("Could not open asset file " + fileName);
  116. return false;
  117. }
  118. else
  119. {
  120. fileName_ = fileName;
  121. mode_ = mode;
  122. position_ = 0;
  123. offset_ = 0;
  124. checksum_ = 0;
  125. size_ = assetHandle_->hidden.androidio.size;
  126. readBuffer_ = new unsigned char[READ_BUFFER_SIZE];
  127. readBufferOffset_ = 0;
  128. readBufferSize_ = 0;
  129. return true;
  130. }
  131. }
  132. #endif
  133. #ifdef WIN32
  134. handle_ = _wfopen(GetWideNativePath(fileName).CString(), openMode[mode]);
  135. #else
  136. handle_ = fopen(GetNativePath(fileName).CString(), openMode[mode]);
  137. #endif
  138. if (!handle_)
  139. {
  140. LOGERROR("Could not open file " + fileName);
  141. return false;
  142. }
  143. fileName_ = fileName;
  144. mode_ = mode;
  145. position_ = 0;
  146. offset_ = 0;
  147. checksum_ = 0;
  148. fseek((FILE*)handle_, 0, SEEK_END);
  149. size_ = ftell((FILE*)handle_);
  150. fseek((FILE*)handle_, 0, SEEK_SET);
  151. return true;
  152. }
  153. bool File::Open(PackageFile* package, const String& fileName)
  154. {
  155. Close();
  156. if (!package)
  157. return false;
  158. const PackageEntry* entry = package->GetEntry(fileName);
  159. if (!entry)
  160. return false;
  161. #ifdef WIN32
  162. handle_ = _wfopen(GetWideNativePath(package->GetName()).CString(), L"rb");
  163. #else
  164. handle_ = fopen(GetNativePath(package->GetName()).CString(), "rb");
  165. #endif
  166. if (!handle_)
  167. {
  168. LOGERROR("Could not open package file " + fileName);
  169. return false;
  170. }
  171. fileName_ = fileName;
  172. mode_ = FILE_READ;
  173. offset_ = entry->offset_;
  174. checksum_ = entry->checksum_;
  175. position_ = 0;
  176. size_ = entry->size_;
  177. fseek((FILE*)handle_, offset_, SEEK_SET);
  178. return true;
  179. }
  180. unsigned File::Read(void* dest, unsigned size)
  181. {
  182. if (mode_ == FILE_WRITE)
  183. {
  184. LOGERROR("File not opened for reading");
  185. return 0;
  186. }
  187. if (size + position_ > size_)
  188. size = size_ - position_;
  189. if (!size)
  190. return 0;
  191. #ifdef ANDROID
  192. if (assetHandle_)
  193. {
  194. unsigned sizeLeft = size;
  195. unsigned char* destPtr = (unsigned char*)dest;
  196. while (sizeLeft)
  197. {
  198. if (readBufferOffset_ >= readBufferSize_)
  199. {
  200. readBufferSize_ = Min((int)size_ - position_, (int)READ_BUFFER_SIZE);
  201. readBufferOffset_ = 0;
  202. SDL_RWread(assetHandle_, readBuffer_.Get(), readBufferSize_, 1);
  203. }
  204. unsigned copySize = Min((int)(readBufferSize_ - readBufferOffset_), (int)sizeLeft);
  205. memcpy(destPtr, readBuffer_.Get() + readBufferOffset_, copySize);
  206. destPtr += copySize;
  207. sizeLeft -= copySize;
  208. readBufferOffset_ += copySize;
  209. position_ += copySize;
  210. }
  211. return size;
  212. }
  213. #endif
  214. if (!handle_)
  215. {
  216. LOGERROR("File not open");
  217. return 0;
  218. }
  219. size_t ret = fread(dest, size, 1, (FILE*)handle_);
  220. if (ret != 1)
  221. {
  222. // Return to the position where the read began
  223. fseek((FILE*)handle_, position_ + offset_, SEEK_SET);
  224. LOGERROR("Error while reading from file " + GetName());
  225. return 0;
  226. }
  227. position_ += size;
  228. return size;
  229. }
  230. unsigned File::Seek(unsigned position)
  231. {
  232. // Allow sparse seeks if writing
  233. if (mode_ == FILE_READ && position > size_)
  234. position = size_;
  235. #ifdef ANDROID
  236. if (assetHandle_)
  237. {
  238. SDL_RWseek(assetHandle_, position, SEEK_SET);
  239. position_ = position;
  240. readBufferOffset_ = 0;
  241. readBufferSize_ = 0;
  242. return position_;
  243. }
  244. #endif
  245. if (!handle_)
  246. {
  247. LOGERROR("File not open");
  248. return 0;
  249. }
  250. fseek((FILE*)handle_, position + offset_, SEEK_SET);
  251. position_ = position;
  252. return position_;
  253. }
  254. unsigned File::Write(const void* data, unsigned size)
  255. {
  256. if (mode_ == FILE_READ)
  257. {
  258. LOGERROR("File not opened for writing");
  259. return 0;
  260. }
  261. if (!handle_)
  262. {
  263. LOGERROR("File not open");
  264. return 0;
  265. }
  266. if (!size)
  267. return 0;
  268. if (fwrite(data, size, 1, (FILE*)handle_) != 1)
  269. {
  270. // Return to the position where the write began
  271. fseek((FILE*)handle_, position_ + offset_, SEEK_SET);
  272. LOGERROR("Error while writing to file " + GetName());
  273. return 0;
  274. }
  275. position_ += size;
  276. if (position_ > size_)
  277. size_ = position_;
  278. return size;
  279. }
  280. unsigned File::GetChecksum()
  281. {
  282. if (offset_ || checksum_)
  283. return checksum_;
  284. if (!handle_ || mode_ == FILE_WRITE)
  285. return 0;
  286. PROFILE(CalculateFileChecksum);
  287. unsigned oldPos = position_;
  288. checksum_ = 0;
  289. Seek(0);
  290. while (!IsEof())
  291. {
  292. unsigned char block[1024];
  293. unsigned readBytes = Read(block, 1024);
  294. for (unsigned i = 0; i < readBytes; ++i)
  295. checksum_ = SDBMHash(checksum_, block[i]);
  296. }
  297. Seek(oldPos);
  298. return checksum_;
  299. }
  300. void File::Close()
  301. {
  302. #ifdef ANDROID
  303. if (assetHandle_)
  304. {
  305. SDL_RWclose(assetHandle_);
  306. assetHandle_ = 0;
  307. readBuffer_.Reset();
  308. }
  309. #endif
  310. if (handle_)
  311. {
  312. fclose((FILE*)handle_);
  313. handle_ = 0;
  314. position_ = 0;
  315. size_ = 0;
  316. offset_ = 0;
  317. checksum_ = 0;
  318. }
  319. }
  320. void File::Flush()
  321. {
  322. if (handle_)
  323. fflush((FILE*)handle_);
  324. }
  325. void File::SetName(const String& name)
  326. {
  327. fileName_ = name;
  328. }
  329. }