File.cpp 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384
  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. OBJECTTYPESTATIC(File);
  51. File::File(Context* context) :
  52. Object(context),
  53. mode_(FILE_READ),
  54. handle_(0),
  55. #ifdef ANDROID
  56. assetHandle_(0),
  57. readBufferOffset_(0),
  58. readBufferSize_(0),
  59. #endif
  60. offset_(0),
  61. checksum_(0)
  62. {
  63. }
  64. File::File(Context* context, const String& fileName, FileMode mode) :
  65. Object(context),
  66. mode_(FILE_READ),
  67. handle_(0),
  68. #ifdef ANDROID
  69. assetHandle_(0),
  70. readBufferOffset_(0),
  71. readBufferSize_(0),
  72. #endif
  73. offset_(0),
  74. checksum_(0)
  75. {
  76. Open(fileName, mode);
  77. }
  78. File::File(Context* context, PackageFile* package, const String& fileName) :
  79. Object(context),
  80. mode_(FILE_READ),
  81. handle_(0),
  82. #ifdef ANDROID
  83. assetHandle_(0),
  84. readBufferOffset_(0),
  85. readBufferSize_(0),
  86. #endif
  87. offset_(0),
  88. checksum_(0)
  89. {
  90. Open(package, fileName);
  91. }
  92. File::~File()
  93. {
  94. Close();
  95. }
  96. bool File::Open(const String& fileName, FileMode mode)
  97. {
  98. Close();
  99. FileSystem* fileSystem = GetSubsystem<FileSystem>();
  100. if (fileSystem && !fileSystem->CheckAccess(GetPath(fileName)))
  101. {
  102. LOGERROR("Access denied to " + fileName);
  103. return false;
  104. }
  105. #ifdef ANDROID
  106. if (fileName.StartsWith("/apk/"))
  107. {
  108. if (mode != FILE_READ)
  109. {
  110. LOGERROR("Only read mode is supported for asset files");
  111. return false;
  112. }
  113. assetHandle_ = SDL_RWFromFile(fileName.Substring(5).CString(), "rb");
  114. if (!assetHandle_)
  115. {
  116. LOGERROR("Could not open asset file " + fileName);
  117. return false;
  118. }
  119. else
  120. {
  121. fileName_ = fileName;
  122. mode_ = mode;
  123. position_ = 0;
  124. offset_ = 0;
  125. checksum_ = 0;
  126. size_ = assetHandle_->hidden.androidio.size;
  127. readBuffer_ = new unsigned char[READ_BUFFER_SIZE];
  128. readBufferOffset_ = 0;
  129. readBufferSize_ = 0;
  130. return true;
  131. }
  132. }
  133. #endif
  134. #ifdef WIN32
  135. handle_ = _wfopen(GetWideNativePath(fileName).CString(), openMode[mode]);
  136. #else
  137. handle_ = fopen(GetNativePath(fileName).CString(), openMode[mode]);
  138. #endif
  139. if (!handle_)
  140. {
  141. LOGERROR("Could not open file " + fileName);
  142. return false;
  143. }
  144. fileName_ = fileName;
  145. mode_ = mode;
  146. position_ = 0;
  147. offset_ = 0;
  148. checksum_ = 0;
  149. fseek((FILE*)handle_, 0, SEEK_END);
  150. size_ = ftell((FILE*)handle_);
  151. fseek((FILE*)handle_, 0, SEEK_SET);
  152. return true;
  153. }
  154. bool File::Open(PackageFile* package, const String& fileName)
  155. {
  156. Close();
  157. if (!package)
  158. return false;
  159. const PackageEntry* entry = package->GetEntry(fileName);
  160. if (!entry)
  161. return false;
  162. #ifdef WIN32
  163. handle_ = _wfopen(GetWideNativePath(package->GetName()).CString(), L"rb");
  164. #else
  165. handle_ = fopen(GetNativePath(package->GetName()).CString(), "rb");
  166. #endif
  167. if (!handle_)
  168. {
  169. LOGERROR("Could not open package file " + fileName);
  170. return false;
  171. }
  172. fileName_ = fileName;
  173. mode_ = FILE_READ;
  174. offset_ = entry->offset_;
  175. checksum_ = entry->checksum_;
  176. position_ = 0;
  177. size_ = entry->size_;
  178. fseek((FILE*)handle_, offset_, SEEK_SET);
  179. return true;
  180. }
  181. unsigned File::Read(void* dest, unsigned size)
  182. {
  183. if (mode_ == FILE_WRITE)
  184. {
  185. LOGERROR("File not opened for reading");
  186. return 0;
  187. }
  188. if (size + position_ > size_)
  189. size = size_ - position_;
  190. if (!size)
  191. return 0;
  192. #ifdef ANDROID
  193. if (assetHandle_)
  194. {
  195. unsigned sizeLeft = size;
  196. unsigned char* destPtr = (unsigned char*)dest;
  197. while (sizeLeft)
  198. {
  199. if (readBufferOffset_ >= readBufferSize_)
  200. {
  201. readBufferSize_ = Min((int)size_ - position_, (int)READ_BUFFER_SIZE);
  202. readBufferOffset_ = 0;
  203. SDL_RWread(assetHandle_, readBuffer_.Get(), readBufferSize_, 1);
  204. }
  205. unsigned copySize = Min((int)(readBufferSize_ - readBufferOffset_), (int)sizeLeft);
  206. memcpy(destPtr, readBuffer_.Get() + readBufferOffset_, copySize);
  207. destPtr += copySize;
  208. sizeLeft -= copySize;
  209. readBufferOffset_ += copySize;
  210. position_ += copySize;
  211. }
  212. return size;
  213. }
  214. #endif
  215. if (!handle_)
  216. {
  217. LOGERROR("File not open");
  218. return 0;
  219. }
  220. size_t ret = fread(dest, size, 1, (FILE*)handle_);
  221. if (ret != 1)
  222. {
  223. // Return to the position where the read began
  224. fseek((FILE*)handle_, position_ + offset_, SEEK_SET);
  225. LOGERROR("Error while reading from file " + GetName());
  226. return 0;
  227. }
  228. position_ += size;
  229. return size;
  230. }
  231. unsigned File::Seek(unsigned position)
  232. {
  233. // Allow sparse seeks if writing
  234. if (mode_ == FILE_READ && position > size_)
  235. position = size_;
  236. #ifdef ANDROID
  237. if (assetHandle_)
  238. {
  239. SDL_RWseek(assetHandle_, position, SEEK_SET);
  240. position_ = position;
  241. readBufferOffset_ = 0;
  242. readBufferSize_ = 0;
  243. return position_;
  244. }
  245. #endif
  246. if (!handle_)
  247. {
  248. LOGERROR("File not open");
  249. return 0;
  250. }
  251. fseek((FILE*)handle_, position + offset_, SEEK_SET);
  252. position_ = position;
  253. return position_;
  254. }
  255. unsigned File::Write(const void* data, unsigned size)
  256. {
  257. if (mode_ == FILE_READ)
  258. {
  259. LOGERROR("File not opened for writing");
  260. return 0;
  261. }
  262. if (!handle_)
  263. {
  264. LOGERROR("File not open");
  265. return 0;
  266. }
  267. if (!size)
  268. return 0;
  269. if (fwrite(data, size, 1, (FILE*)handle_) != 1)
  270. {
  271. // Return to the position where the write began
  272. fseek((FILE*)handle_, position_ + offset_, SEEK_SET);
  273. LOGERROR("Error while writing to file " + GetName());
  274. return 0;
  275. }
  276. position_ += size;
  277. if (position_ > size_)
  278. size_ = position_;
  279. return size;
  280. }
  281. unsigned File::GetChecksum()
  282. {
  283. if (offset_ || checksum_)
  284. return checksum_;
  285. if (!handle_ || mode_ == FILE_WRITE)
  286. return 0;
  287. PROFILE(CalculateFileChecksum);
  288. unsigned oldPos = position_;
  289. checksum_ = 0;
  290. Seek(0);
  291. while (!IsEof())
  292. {
  293. unsigned char block[1024];
  294. unsigned readBytes = Read(block, 1024);
  295. for (unsigned i = 0; i < readBytes; ++i)
  296. checksum_ = SDBMHash(checksum_, block[i]);
  297. }
  298. Seek(oldPos);
  299. return checksum_;
  300. }
  301. void File::Close()
  302. {
  303. #ifdef ANDROID
  304. if (assetHandle_)
  305. {
  306. SDL_RWclose(assetHandle_);
  307. assetHandle_ = 0;
  308. readBuffer_.Reset();
  309. }
  310. #endif
  311. if (handle_)
  312. {
  313. fclose((FILE*)handle_);
  314. handle_ = 0;
  315. position_ = 0;
  316. size_ = 0;
  317. offset_ = 0;
  318. checksum_ = 0;
  319. }
  320. }
  321. void File::Flush()
  322. {
  323. if (handle_)
  324. fflush((FILE*)handle_);
  325. }
  326. void File::SetName(const String& name)
  327. {
  328. fileName_ = name;
  329. }
  330. }