File.cpp 80 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089
  1. /******************************************************************************/
  2. #include "stdafx.h"
  3. namespace EE{
  4. /******************************************************************************
  5. 'File._cipher_offset' is needed because of:
  6. -'Pak._cipher_per_file' can be either false or true
  7. -'File.limit/unlimit' is used for 'DecompressRaw' and 'ChunkReader' which will break if "Pak._cipher_per_file==true"
  8. -Android can have assets located within the APK with an offset (we can get a stdio file descriptor for APK and a custom file inside it at a certain offset in that file) which will break if "Pak._cipher_per_file==false"
  9. "Pak._cipher_per_file==true" is recommended because it improves Steam patching system:
  10. making updates will require smaller uploads/downloads, because Steam reuses same 1MB chunks:
  11. https://partner.steamgames.com/documentation/steampipe#Building_Efficient_Depots
  12. Because of buffering, the actual position (file descriptor) may be different than File.pos.
  13. Because in FILE_STD_READ more data is read, and placed into the buffer (descriptor being ahead of 'File.pos')
  14. and in FILE_STD_WRITE data is buffered, and written once buffer is full ('File.pos' being ahead of descriptor)
  15. See 'File.posFile'
  16. /******************************************************************************
  17. BUF_SIZE was chosen based on speed tests using following code:
  18. Str file="d:/test.dat";
  19. if(MOBILE)file=SystemPath(SP_APP_DATA).tailSlash(true)+"test.dat";
  20. long size=(1024<<20); int mul=(MOBILE ? 1 : 4);
  21. File f; f.write(file); REP(mul)f.put(null, size); size*=mul;
  22. extern int BUF_SIZE;
  23. LogDel();
  24. ProcPriority(2);
  25. LogN(S+"file size:"+size);
  26. for(BUF_SIZE=4096; BUF_SIZE<=(16<<20); BUF_SIZE*=2)
  27. {
  28. f.del(); f.read(file);
  29. Str s=S+"BUF_SIZE:"+BUF_SIZE;
  30. byte temp[4096];
  31. flt t=Time.curTime(); f.pos(0); for(; !f.end(); )f.getByte(); s+=S+", 1:"+(Time.curTime()-t);
  32. t=Time.curTime(); f.pos(0); for(; !f.end(); )f.getUInt(); s+=S+", 4:"+(Time.curTime()-t);
  33. t=Time.curTime(); f.pos(0); for(; !f.end(); )f>>temp ; s+=S+", 4k:"+(Time.curTime()-t);
  34. LogN(s);
  35. }
  36. Results on Asus Zenbook Prime, 15" 512GB SSD Win Laptop:
  37. file size:4294967296
  38. BUF_SIZE:4096, 1:56.978, 4:16.192, 4k:2.755
  39. BUF_SIZE:8192, 1:55.714, 4:15.340, 4k:2.754
  40. BUF_SIZE:16384, 1:55.269, 4:14.835, 4k:1.635
  41. BUF_SIZE:32768, 1:55.097, 4:14.684, 4k:1.404
  42. BUF_SIZE:65536, 1:54.998, 4:14.600, 4k:1.337 <- BEST
  43. BUF_SIZE:131072, 1:54.920, 4:14.636, 4k:1.416
  44. BUF_SIZE:262144, 1:54.976, 4:14.791, 4k:1.363
  45. BUF_SIZE:524288, 1:54.506, 4:14.718, 4k:1.354
  46. BUF_SIZE:1048576, 1:54.886, 4:14.592, 4k:1.361
  47. BUF_SIZE:2097152, 1:55.293, 4:14.513, 4k:1.364
  48. BUF_SIZE:4194304, 1:55.138, 4:14.704, 4k:1.523
  49. BUF_SIZE:8388608, 1:55.132, 4:14.898, 4k:1.715
  50. Results on MacBook Air 13" Mid 2013 128 GB SSD:
  51. file size:1073741824
  52. BUF_SIZE:4096, 1:22.485, 4:6.513, 4k:0.461
  53. BUF_SIZE:8192, 1:21.548, 4:6.062, 4k:0.461
  54. BUF_SIZE:16384, 1:21.118, 4:6.077, 4k:0.329
  55. BUF_SIZE:32768, 1:21.408, 4:5.797, 4k:0.340
  56. BUF_SIZE:65536, 1:21.656, 4:5.807, 4k:0.275 <- BEST
  57. BUF_SIZE:131072, 1:21.296, 4:5.955, 4k:0.331
  58. BUF_SIZE:262144, 1:21.188, 4:5.991, 4k:0.325
  59. BUF_SIZE:524288, 1:20.682, 4:6.036, 4k:0.321
  60. BUF_SIZE:1048576, 1:21.438, 4:6.011, 4k:0.342
  61. BUF_SIZE:2097152, 1:21.487, 4:5.918, 4k:0.368
  62. BUF_SIZE:4194304, 1:21.127, 4:5.932, 4k:0.414
  63. BUF_SIZE:8388608, 1:20.767, 4:6.236, 4k:0.428
  64. BUF_SIZE:16777216, 1:20.651, 4:5.961, 4k:0.425
  65. Results on iPad Mini 2:
  66. file size:1073741824
  67. BUF_SIZE:4096, 1:34.880, 4:11.120, 4k:6.909
  68. BUF_SIZE:8192, 1:34.407, 4:10.864, 4k:6.891
  69. BUF_SIZE:16384, 1:34.199, 4:10.639, 4k:6.811
  70. BUF_SIZE:32768, 1:34.171, 4:10.387, 4k:6.737
  71. BUF_SIZE:65536, 1:34.142, 4:10.139, 4k:6.747
  72. BUF_SIZE:131072, 1:34.137, 4:9.875, 4k:6.739
  73. BUF_SIZE:262144, 1:34.117, 4:9.860, 4k:6.738
  74. BUF_SIZE:524288, 1:34.292, 4:10.006, 4k:6.507
  75. BUF_SIZE:1048576, 1:34.184, 4:10.021, 4k:5.950
  76. BUF_SIZE:2097152, 1:36.769, 4:12.563, 4k:5.979
  77. BUF_SIZE:4194304, 1:38.040, 4:13.808, 4k:5.956
  78. BUF_SIZE:8388608, 1:38.799, 4:14.405, 4k:5.961
  79. BUF_SIZE:16777216, 1:38.953, 4:14.765, 4k:5.981
  80. /******************************************************************************/
  81. #if DESKTOP
  82. #define BUF_SIZE (1<<16) // 64 KB
  83. #else
  84. #define BUF_SIZE (1<<15) // 32 KB (for Mobile devices use smaller buffers because they usually have less RAM)
  85. #endif
  86. #define TEMP_BUF_SIZE (1<<17) // 128 KB
  87. #define ALLOW_REFLUSH 1 // if allow secondary flush with remaining data when first failed
  88. /******************************************************************************/
  89. #if WINDOWS
  90. static INLINE Long Seek(Int handle, Long offset, Int mode) {return _lseeki64(handle, offset, mode);}
  91. #elif APPLE
  92. static INLINE Long Seek(Int handle, Long offset, Int mode) {return lseek (handle, offset, mode);} // on Apple 'lseek' is already 64-bit
  93. #elif LINUX || ANDROID || WEB
  94. static INLINE Long Seek(Int handle, Long offset, Int mode) {return lseek64 (handle, offset, mode);}
  95. #endif
  96. static INLINE Int Write(Int handle, CPtr data, Int size) {return PLATFORM(_write, write)(handle, data, size);}
  97. static INLINE Int Read (Int handle, Ptr data, Int size) {return PLATFORM(_read , read )(handle, data, size);}
  98. /******************************************************************************/
  99. // !! if adding any members here then adjust 'copyToAndDiscard', 'writeMemFixed' !!
  100. void File::zeroNoBuf()
  101. {
  102. _type=FILE_NONE; _writable=false; _ok=true; _path=FILE_PATH(0);
  103. _buf_pos=_buf_len=_cipher_offset=_handle=0;
  104. _offset=_pos=_size=0;
  105. _pak=null;
  106. _cipher=null;
  107. _mem=null;
  108. #if ANDROID
  109. _aasset=null;
  110. #endif
  111. }
  112. void File::zero()
  113. {
  114. zeroNoBuf();
  115. _buf_size=0;
  116. _buf=null;
  117. }
  118. File::File( ) {zero();}
  119. File::File(C Str &name , Cipher *cipher) : File() {read (name , cipher);}
  120. File::File(C UID &id , Cipher *cipher) : File() {read (id , cipher);}
  121. File::File(C Str &name, C Pak &pak ) : File() {read (name, pak );}
  122. File::File(C PakFile &file, C Pak &pak ) : File() {read (file, pak );}
  123. File::File( CPtr data, Int size, Cipher *cipher) : File() {readMem(data, size, cipher);}
  124. void File::delBuf( ) {Free(_buf); _buf_size=0;}
  125. Bool File::setBuf(Int size) {if(size>_buf_size){delBuf(); if(_buf=Alloc(size))_buf_size=size;} return !size || _buf!=null;}
  126. File& File::del()
  127. {
  128. close(); delBuf(); // !! delete buffer after closing, because it may be used by 'flush' !!
  129. #if !FILE_MEMB_UNION
  130. _memb.del();
  131. #endif
  132. return T;
  133. }
  134. void File::close()
  135. {
  136. switch(_type)
  137. {
  138. case FILE_STD_READ :
  139. case FILE_STD_WRITE:
  140. {
  141. flush(); // remember that this 'flush' may fail, and '_buf_len' may remain >0, however it will be cleared in 'zeroNoBuf'
  142. ::PLATFORM(_close, close)(_handle);
  143. #if WEB
  144. if(_writable)FlushIO(); // check for '_writable' instead of 'FILE_STD_WRITE' because File could have been created as writable but later switched to FILE_STD_READ
  145. #endif
  146. }break;
  147. case FILE_MEM: if(_writable)Free(_mem); break; // write memory was dynamically allocated
  148. case FILE_MEMB: if(FILE_MEMB_UNION)DTOR(_memb);else _memb.clear(); break;
  149. }
  150. #if ANDROID
  151. if(_aasset)AAsset_close((AAsset*)_aasset);
  152. #endif
  153. zeroNoBuf();
  154. }
  155. File& File::reset()
  156. {
  157. if(_type==FILE_MEMB)
  158. {
  159. _memb.reset();
  160. _ok=true;
  161. _cipher_offset=0;
  162. _offset=_pos=_size=0;
  163. }
  164. return T;
  165. }
  166. File& File::append (C Str &name , Cipher *cipher) {if(!appendTry (name , cipher))Exit(MLT(S+"Can't append \""+ name+'"', PL,S+u"Nie można nadpisać \""+ name+'"')); return T;}
  167. File& File::write (C Str &name , Cipher *cipher) {if(! writeTry (name , cipher))Exit(MLT(S+"Can't create \""+ name+'"', PL,S+u"Nie można utworzyć \""+ name+'"')); return T;}
  168. File& File::readStd(C Str &name , Cipher *cipher) {if(! readStdTry(name , cipher))Exit(MLT(S+"Can't open \"" + name+'"', PL,S+u"Nie można otworzyć \""+ name+'"')); return T;}
  169. File& File::read (C PakFile &file, C Pak &pak ) {if(! readTry (file, pak ))Exit(MLT(S+"Can't open \"" + file.name+'"', PL,S+u"Nie można otworzyć \""+ file.name+'"')); return T;}
  170. File& File::read (C Str &name, C Pak &pak ) {if(! readTry (name, pak ))Exit(MLT(S+"Can't open \"" + name+'"', PL,S+u"Nie można otworzyć \""+ name+'"')); return T;}
  171. File& File::read (C UID &id , C Pak &pak ) {if(! readTry (id , pak ))Exit(MLT(S+"Can't open \"" +id.asCString()+'"', PL,S+u"Nie można otworzyć \""+id.asCString()+'"')); return T;}
  172. File& File::read (C Str &name, C PakSet &paks ) {if(! readTry (name, paks ))Exit(MLT(S+"Can't open \"" + name+'"', PL,S+u"Nie można otworzyć \""+ name+'"')); return T;}
  173. File& File::read (C UID &id , C PakSet &paks ) {if(! readTry (id , paks ))Exit(MLT(S+"Can't open \"" +id.asCString()+'"', PL,S+u"Nie można otworzyć \""+id.asCString()+'"')); return T;}
  174. File& File::read (C Str &name , Cipher *cipher) {if(! readTry (name , cipher))Exit(MLT(S+"Can't open \"" + name+'"', PL,S+u"Nie można otworzyć \""+ name+'"')); return T;}
  175. File& File::read (C UID &id , Cipher *cipher) {if(! readTry (id , cipher))Exit(MLT(S+"Can't open \"" +id.asCString()+'"', PL,S+u"Nie można otworzyć \""+id.asCString()+'"')); return T;}
  176. Bool File::copyToAndDiscard(Mems<Byte> &dest)
  177. {
  178. if(T._type==FILE_MEM && T._writable && !_cipher && posAbs()==0) // check if we can just swap memories
  179. { // swap memories, perhaps 'File' may reuse 'Mems' data for future operations
  180. Ptr data=dest.data(); Int elms=dest.elms(); dest.setTemp((Byte*)T._mem, T._size);
  181. T._ok =true;
  182. T._cipher_offset=0;
  183. T._offset =0;
  184. T._pos =0;
  185. T._size =elms;
  186. T._cipher =null;
  187. T._mem =data;
  188. return true;
  189. }else
  190. {
  191. dest.setNum(left());
  192. return getFast(dest.data(), dest.elms());
  193. }
  194. }
  195. File& File::writeMemFixed(Int size, Cipher *cipher)
  196. {
  197. if(T._size==size && T._type==FILE_MEM && T._writable) // check if we can reuse existing memory
  198. {
  199. T._ok =true;
  200. T._cipher_offset=0;
  201. T._offset =0;
  202. T._pos =0;
  203. T._cipher =cipher;
  204. }else
  205. {
  206. close();
  207. if(!size || (_mem=Alloc(size)))
  208. {
  209. T._type =FILE_MEM;
  210. T._writable=true;
  211. T._size =size;
  212. T._cipher =cipher;
  213. }
  214. }
  215. return T;
  216. }
  217. File& File::writeMem(UInt block_elms, Cipher *cipher)
  218. {
  219. if(T._type==FILE_MEMB && _memb.blockElms()==block_elms/* && T._writable - MEMB is always writable*/)
  220. {
  221. reset();
  222. T._cipher=cipher;
  223. }else
  224. {
  225. close();
  226. T._type =FILE_MEMB;
  227. T._writable=true;
  228. T._cipher =cipher;
  229. #if FILE_MEMB_UNION
  230. CTOR(T._memb, block_elms);
  231. #else
  232. if(_memb.blockElms()!=block_elms)
  233. {
  234. DTOR(_memb);
  235. CTOR(_memb, block_elms);
  236. }
  237. #endif
  238. }
  239. return T;
  240. }
  241. File& File::readMem(CPtr data, Int size, Cipher *cipher)
  242. {
  243. close();
  244. if(size>=0)
  245. {
  246. T._type =FILE_MEM;
  247. T._writable=false;
  248. T._mem =(Ptr)data;
  249. T._size =size;
  250. T._cipher =cipher;
  251. }
  252. return T;
  253. }
  254. /******************************************************************************/
  255. #if WINDOWS
  256. Bool File::appendTry (C Str &name, Cipher *cipher) {close(); if(name.is() && !_wsopen_s(&_handle, name, _O_BINARY|_O_RDWR|_O_CREAT , _SH_DENYWR, _S_IREAD|_S_IWRITE)){SetLastError(0); _type=FILE_STD_WRITE; if(setBuf(BUF_SIZE)){_writable=true; _path=FILE_CUR; _pos=_size=Max(0, _filelengthi64(_handle)); Seek(_handle, 0, SEEK_END); _cipher=cipher; return true;} _type=FILE_NONE; _close(_handle); _handle=0;} return false;} // clear error 183 file already exists
  257. Bool File:: writeTry (C Str &name, Cipher *cipher) {close(); if(name.is() && !_wsopen_s(&_handle, name, _O_BINARY|_O_RDWR|_O_CREAT|_O_TRUNC, _SH_DENYWR, _S_IREAD|_S_IWRITE)){SetLastError(0); _type=FILE_STD_WRITE; if(setBuf(BUF_SIZE)){_writable=true; _path=FILE_CUR; _cipher=cipher; return true;} _type=FILE_NONE; _close(_handle); _handle=0;} return false;} // clear error 183 file already exists
  258. Bool File:: readStdTryEx(C Str &name, Cipher *cipher, UInt max_buf_size)
  259. {
  260. close(); if(name.is())
  261. {
  262. if(!_wsopen_s(&_handle, name, _O_BINARY|_O_RDONLY, _SH_DENYNO, _S_IREAD|_S_IWRITE))
  263. {
  264. _type=FILE_STD_READ; _size=Max(0, _filelengthi64(_handle)); if(setBuf(Min(max_buf_size, Min(BUF_SIZE, _size)))){_writable=false; _path=FILE_CUR; _cipher=cipher; return true;}
  265. _type=FILE_NONE ; _close(_handle); _handle=0; _size=0; return false;
  266. }
  267. if(DataPath().is() && !FullPath(name))
  268. {
  269. Char path_name[MAX_LONG_PATH]; MergePath(path_name, DataPath(), name);
  270. if(!_wsopen_s(&_handle, WChar(path_name), _O_BINARY|_O_RDONLY, _SH_DENYNO, _S_IREAD|_S_IWRITE))
  271. {
  272. _type=FILE_STD_READ; _size=Max(0, _filelengthi64(_handle)); if(setBuf(Min(max_buf_size, Min(BUF_SIZE, _size)))){_writable=false; _path=FILE_DATA; _cipher=cipher; return true;}
  273. _type=FILE_NONE ; _close(_handle); _handle=0; _size=0; return false;
  274. }
  275. }
  276. }
  277. return false;
  278. }
  279. #elif APPLE
  280. static void DetectSymLink(File &f, C Str8 &unix_name)
  281. {
  282. struct stat stats; if(!fstat(f._handle, &stats))if(S_ISLNK(stats.st_mode))
  283. {
  284. ASSERT(BUF_SIZE>=MAX_UTF_PATH); // we're reading directly to the File buffer, so make sure that it was set big enough to hold a link path
  285. ssize_t read=readlink(unix_name, (char*)f._buf, Min(f._buf_size, f.size())); if(read>0)f._buf_len=Int(read);
  286. }
  287. }
  288. Bool File::appendTry (C Str &name, Cipher *cipher) {close(); if(name.is()){_handle=open(UnixPathUTF8(name), O_RDWR|O_CREAT| O_EXLOCK|O_NONBLOCK|O_SYMLINK, S_IRWXU|S_IRWXG|S_IRWXO); if(_handle>=0){_type=FILE_STD_WRITE; if(setBuf(BUF_SIZE)){_writable=true; _path=FILE_CUR; _pos=_size=Max(0, Seek(_handle, 0, SEEK_END)); _cipher=cipher; return true;} _type=FILE_NONE; ::close(_handle); _handle=0;}} return false;}
  289. Bool File:: writeTry (C Str &name, Cipher *cipher) {close(); if(name.is()){_handle=open(UnixPathUTF8(name), O_RDWR|O_CREAT|O_TRUNC|O_EXLOCK|O_NONBLOCK|O_SYMLINK, S_IRWXU|S_IRWXG|S_IRWXO); if(_handle>=0){_type=FILE_STD_WRITE; if(setBuf(BUF_SIZE)){_writable=true; _path=FILE_CUR; _cipher=cipher; return true;} _type=FILE_NONE; ::close(_handle); _handle=0;}} return false;}
  290. Bool File:: readStdTryEx(C Str &name, Cipher *cipher, UInt max_buf_size)
  291. {
  292. close(); if(name.is())
  293. {
  294. Str8 unix_name=UnixPathUTF8(name);
  295. _handle=open(unix_name, O_RDONLY|O_NONBLOCK|O_SYMLINK); if(_handle>=0)
  296. {
  297. _type=FILE_STD_READ; _size=Max(0, Seek(_handle, 0, SEEK_END)); if(setBuf(Min(max_buf_size, Min(BUF_SIZE, _size)))){_writable=false; _path=FILE_CUR; Seek(_handle, 0, SEEK_SET); _cipher=cipher; DetectSymLink(T, unix_name); return true;}
  298. _type=FILE_NONE ; ::close(_handle); _handle=0; _size=0; return false;
  299. }
  300. if(DataPath().is() && !FullPath(name))
  301. {
  302. Char path_name[MAX_LONG_PATH]; MergePath(path_name, DataPath(), name);
  303. unix_name=UnixPathUTF8(path_name);
  304. _handle=open(unix_name, O_RDONLY|O_NONBLOCK|O_SYMLINK); if(_handle>=0)
  305. {
  306. _type=FILE_STD_READ; _size=Max(0, Seek(_handle, 0, SEEK_END)); if(setBuf(Min(max_buf_size, Min(BUF_SIZE, _size)))){_writable=false; _path=FILE_DATA; Seek(_handle, 0, SEEK_SET); _cipher=cipher; DetectSymLink(T, unix_name); return true;}
  307. _type=FILE_NONE ; ::close(_handle); _handle=0; _size=0; return false;
  308. }
  309. }
  310. }
  311. return false;
  312. }
  313. #elif LINUX || WEB
  314. Bool File::appendTry (C Str &name, Cipher *cipher) {close(); if(name.is()){_handle=open64(UnixPathUTF8(name), O_RDWR|O_CREAT| O_NONBLOCK, S_IRWXU|S_IRWXG|S_IRWXO); if(_handle>=0){_type=FILE_STD_WRITE; if(setBuf(BUF_SIZE)){_writable=true; _path=FILE_CUR; _pos=_size=Max(0, Seek(_handle, 0, SEEK_END)); _cipher=cipher; return true;} _type=FILE_NONE; ::close(_handle); _handle=0;}} return false;}
  315. Bool File:: writeTry (C Str &name, Cipher *cipher) {close(); if(name.is()){_handle=open64(UnixPathUTF8(name), O_RDWR|O_CREAT|O_TRUNC|O_NONBLOCK, S_IRWXU|S_IRWXG|S_IRWXO); if(_handle>=0){_type=FILE_STD_WRITE; if(setBuf(BUF_SIZE)){_writable=true; _path=FILE_CUR; _cipher=cipher; return true;} _type=FILE_NONE; ::close(_handle); _handle=0;}} return false;}
  316. Bool File:: readStdTryEx(C Str &name, Cipher *cipher, UInt max_buf_size)
  317. {
  318. close(); if(name.is())
  319. {
  320. Str8 unix_name=UnixPathUTF8(name);
  321. _handle=open64(unix_name, O_RDONLY|O_NONBLOCK); if(_handle>=0)
  322. {
  323. _type=FILE_STD_READ; _size=Max(0, Seek(_handle, 0, SEEK_END)); if(setBuf(Min(max_buf_size, Min(BUF_SIZE, _size)))){_writable=false; _path=FILE_CUR; Seek(_handle, 0, SEEK_SET); _cipher=cipher; return true;}
  324. _type=FILE_NONE ; ::close(_handle); _handle=0; _size=0; return false;
  325. }
  326. if(DataPath().is() && !FullPath(name))
  327. {
  328. Char path_name[MAX_LONG_PATH]; MergePath(path_name, DataPath(), name);
  329. unix_name=UnixPathUTF8(path_name);
  330. _handle=open64(unix_name, O_RDONLY|O_NONBLOCK); if(_handle>=0)
  331. {
  332. _type=FILE_STD_READ; _size=Max(0, Seek(_handle, 0, SEEK_END)); if(setBuf(Min(max_buf_size, Min(BUF_SIZE, _size)))){_writable=false; _path=FILE_DATA; Seek(_handle, 0, SEEK_SET); _cipher=cipher; return true;}
  333. _type=FILE_NONE ; ::close(_handle); _handle=0; _size=0; return false;
  334. }
  335. }
  336. }
  337. return false;
  338. }
  339. #elif ANDROID // Android has 'open64' only on API 21 and newer, however it's the same as 'open' with O_LARGEFILE
  340. Bool File::appendTry (C Str &name, Cipher *cipher) {close(); if(name.is()){_handle=open(UnixPathUTF8(name), O_RDWR|O_CREAT| O_NONBLOCK|O_LARGEFILE, S_IRWXU|S_IRWXG|S_IRWXO); if(_handle>=0){_type=FILE_STD_WRITE; if(setBuf(BUF_SIZE)){_writable=true; _path=FILE_CUR; _pos=_size=Max(0, Seek(_handle, 0, SEEK_END)); _cipher=cipher; return true;} _type=FILE_NONE; ::close(_handle); _handle=0;}} return false;}
  341. Bool File:: writeTry (C Str &name, Cipher *cipher) {close(); if(name.is()){_handle=open(UnixPathUTF8(name), O_RDWR|O_CREAT|O_TRUNC|O_NONBLOCK|O_LARGEFILE, S_IRWXU|S_IRWXG|S_IRWXO); if(_handle>=0){_type=FILE_STD_WRITE; if(setBuf(BUF_SIZE)){_writable=true; _path=FILE_CUR; _cipher=cipher; return true;} _type=FILE_NONE; ::close(_handle); _handle=0;}} return false;}
  342. Bool File:: readStdTryEx(C Str &name, Cipher *cipher, UInt max_buf_size, Bool *processed)
  343. {
  344. if(processed)*processed=false;
  345. close(); if(name.is())
  346. {
  347. // assets
  348. if(!FullPath(name) && AssetManager)
  349. if(AAsset *asset=AAssetManager_open(AssetManager, UnixPathUTF8(name), AASSET_MODE_RANDOM))
  350. {
  351. Bool ok=false;
  352. #if __ANDROID_API__>=13
  353. off64_t size=AAsset_getLength64(asset);
  354. #else
  355. off_t size=AAsset_getLength (asset);
  356. #endif
  357. if( size<0)ok=false;else
  358. if(!size ) // no need for opening the file using Android API when it has no size
  359. {
  360. T._type =FILE_MEM;
  361. T._writable=false;
  362. T._size =0;
  363. T._cipher =cipher;
  364. ok=true;
  365. }else // size>0
  366. {
  367. #if __ANDROID_API__>=13
  368. off64_t offset, length; int fd=AAsset_openFileDescriptor64(asset, &offset, &length);
  369. #else
  370. off_t offset, length; int fd=AAsset_openFileDescriptor (asset, &offset, &length);
  371. #endif
  372. if(fd>=0)
  373. {
  374. _size=length;
  375. if(setBuf(Min(max_buf_size, Min(BUF_SIZE, _size))))
  376. {
  377. T._handle =fd;
  378. T._type =FILE_STD_READ;
  379. T._writable=false;
  380. T._path =FILE_ANDROID_ASSET;
  381. T._cipher =cipher;
  382. Seek(_handle, T._offset=offset, SEEK_SET);
  383. ok=true;
  384. }else
  385. {
  386. _size=0;
  387. ::close(fd);
  388. }
  389. }else // file is compressed, needs to be processed using 'AAsset_*' functions
  390. if(_mem=(Ptr)AAsset_getBuffer(asset))
  391. {
  392. if(processed)*processed=true; // file had to be decompressed
  393. T._type =FILE_MEM;
  394. T._writable=false;
  395. T._path =FILE_ANDROID_ASSET;
  396. T._size =size;
  397. T._cipher =cipher;
  398. T._aasset =asset;
  399. return true; // return here and don't close 'asset' because that would make the '_mem' buffer invalid
  400. }
  401. }
  402. AAsset_close(asset);
  403. return ok;
  404. }
  405. // original path
  406. _handle=open(UnixPathUTF8(name), O_RDONLY|O_NONBLOCK|O_LARGEFILE); if(_handle>=0)
  407. {
  408. _type=FILE_STD_READ; _size=Max(0, Seek(_handle, 0, SEEK_END)); if(setBuf(Min(max_buf_size, Min(BUF_SIZE, _size)))){_writable=false; _path=FILE_CUR; Seek(_handle, 0, SEEK_SET); _cipher=cipher; return true;}
  409. _type=FILE_NONE ; ::close(_handle); _handle=0; _size=0; return false;
  410. }
  411. // data path
  412. if(DataPath().is() && !FullPath(name))
  413. {
  414. Char path_name[MAX_LONG_PATH]; MergePath(path_name, DataPath(), name);
  415. _handle=open(UnixPathUTF8(path_name), O_RDONLY|O_NONBLOCK|O_LARGEFILE); if(_handle>=0)
  416. {
  417. _type=FILE_STD_READ; _size=Max(0, Seek(_handle, 0, SEEK_END)); if(setBuf(Min(max_buf_size, Min(BUF_SIZE, _size)))){_writable=false; _path=FILE_DATA; Seek(_handle, 0, SEEK_SET); _cipher=cipher; return true;}
  418. _type=FILE_NONE ; ::close(_handle); _handle=0; _size=0; return false;
  419. }
  420. }
  421. }
  422. return false;
  423. }
  424. #endif
  425. /******************************************************************************/
  426. Bool File::readTryRaw(C PakFile &file, C Pak &pak)
  427. {
  428. if(!(file.flag&PF_REMOVED))switch(pak._file_type)
  429. {
  430. case FILE_MEM:
  431. {
  432. readMem(pak._data, file.data_size_compressed, pak._file_cipher);
  433. T._pak =&pak;
  434. T._offset = pak._data_offset+file.data_offset;
  435. T._cipher_offset=(pak._cipher_per_file ? 0 : pak._file_cipher_offset+file.data_offset);
  436. }return true;
  437. case FILE_STD_READ:
  438. {
  439. if(T._type==FILE_STD_READ && !T._writable && T._pak==&pak) // this 'File' object already points to some 'PakFile' in the same 'Pak' as requested, which means that it's using the same stdio file, and we can re-use it
  440. {
  441. _offset=pak._data_offset+file.data_offset;
  442. if(Seek(_handle, _offset, SEEK_SET)==_offset)
  443. {
  444. T._size=file.data_size_compressed;
  445. if(setBuf(Min(BUF_SIZE, T._size)))
  446. {
  447. clearBuf();
  448. T._ok =true;
  449. T._pos =0;
  450. T._cipher =pak._file_cipher; // re-apply cipher because this could have been changed in 'readTryEx'
  451. T._cipher_offset=(pak._cipher_per_file ? 0 : pak._file_cipher_offset+file.data_offset);
  452. return true;
  453. }
  454. }
  455. }else
  456. if(readStdTryEx(pak.pakFileName(), pak._file_cipher, file.data_size_compressed))
  457. {
  458. _offset=pak._data_offset+file.data_offset;
  459. if(Seek(_handle, _offset, SEEK_SET)==_offset)
  460. {
  461. T._pak =&pak;
  462. T._size =file.data_size_compressed;
  463. T._cipher_offset=(pak._cipher_per_file ? 0 : pak._file_cipher_offset+file.data_offset);
  464. return true;
  465. }
  466. }
  467. }break;
  468. }
  469. close(); return false;
  470. }
  471. Bool File::readTryEx(C PakFile &file, C Pak &pak, Cipher *cipher, Bool *processed)
  472. {
  473. if(readTryRaw(file, pak))
  474. {
  475. Bool p=false;
  476. if(file.compression) // first decompress with original cipher
  477. {
  478. p=true; // we had to perform processing
  479. File temp; if(!DecompressRaw(T, temp, file.compression, file.data_size_compressed, file.data_size, true))goto error;
  480. Swap(T, temp); pos(0);
  481. }
  482. if(cipher) // if we want to use custom cipher on top of what's already available (don't check for 'cipher!=T._cipher' because we want to add new cipher on top of existing)
  483. {
  484. if(T._cipher) // get rid of existing cipher by decrypting it to a memory file
  485. {
  486. p=true; // we had to perform processing
  487. File temp; if(!copy(temp.writeMemFixed(size(), null)))goto error; // we can't apply 'cipher' here and later clear it, because that would encrypt it with 'cipher', however what we want is to decrypt it with 'cipher'
  488. Swap(T, temp); pos(0);
  489. }else _cipher_offset=0; // if there's no cipher yet, but there was '_cipher_offset', then we need to clear it, as it would affect the new cipher
  490. T._cipher=cipher; // here we can just set '_cipher' instead of calling 'cipher' method, because in both cases (decompress+decrypt) we're writing to memory files so these operations are not needed
  491. }
  492. // this method calls 'readTryRaw' which then calls 'readStdTryEx' which on Android can set 'processed' to true, however not in this case, because we're loading a 'PakFile' from 'Pak', and if the File for the 'Pak' had to be processed, then 'Pak' itself decompressed it into a memory based 'File' FILE_MEM inside 'Pak.load'
  493. if(processed)*processed=p; return true;
  494. error:
  495. close();
  496. }//else close(); no need to call 'close' here, because 'readTryRaw' will already call it
  497. if(processed)*processed=false; return false;
  498. }
  499. Bool File::readTryEx(C Str &name, C PakSet &paks, Cipher *cipher, Bool *processed)
  500. {
  501. //if(name.is())) in most cases the 'name' is going to be specified
  502. {
  503. SafeSyncLockerEx locker(paks._lock); // required if we call 'File.read' and 'PakSet.add' in multiple threads simultaneously
  504. if(C PaksFile *file=paks.find(name))
  505. {
  506. Pak &pak=*file->pak ;
  507. C PakFile &pf =*file->file;
  508. locker.off(); // now when references have been copied, we can unlock
  509. return readTryEx(pf, pak, cipher, processed);
  510. }
  511. }
  512. close(); if(processed)*processed=false; return false;
  513. }
  514. Bool File::readTryEx(C UID &id, C PakSet &paks, Cipher *cipher, Bool *processed)
  515. {
  516. //if(id.valid())) in most cases the 'id' is going to be specified
  517. {
  518. SafeSyncLockerEx locker(paks._lock); // required if we call 'File.read' and 'PakSet.add' in multiple threads simultaneously
  519. if(C PaksFile *file=paks.find(id))
  520. {
  521. Pak &pak=*file->pak ;
  522. C PakFile &pf =*file->file;
  523. locker.off(); // now when references have been copied, we can unlock
  524. return readTryEx(pf, pak, cipher, processed);
  525. }
  526. }
  527. close(); if(processed)*processed=false; return false;
  528. }
  529. Bool File::readTryEx(C Str &name, Cipher *cipher, Bool *processed)
  530. {
  531. if(readTryEx (name, Paks, cipher, processed))return true;
  532. #if !ANDROID
  533. if(processed)*processed=false; return readStdTryEx(name, cipher);
  534. #else
  535. return readStdTryEx(name, cipher, UINT_MAX, processed);
  536. #endif
  537. }
  538. Bool File::readTryEx(C UID &id, Cipher *cipher, Bool *processed)
  539. {
  540. if(readTryEx ( id , Paks, cipher, processed))return true;
  541. #if !ANDROID
  542. if(processed)*processed=false; return readStdTryEx(_EncodeFileName(id), cipher);
  543. #else
  544. return readStdTryEx(_EncodeFileName(id), cipher, UINT_MAX, processed);
  545. #endif
  546. }
  547. Bool File::readStdTry(C Str &name, Cipher *cipher) {return readStdTryEx(name, cipher);}
  548. Bool File::readTry (C Str &name, Cipher *cipher) {return readTryEx (name, cipher, null);}
  549. Bool File::readTry (C UID &id , Cipher *cipher) {return readTryEx (id , cipher, null);}
  550. Bool File::readTry (C Str &name, C PakSet &paks ) {return readTryEx (name, paks, null , null);}
  551. Bool File::readTry (C UID &id , C PakSet &paks ) {return readTryEx (id , paks, null , null);}
  552. Bool File::readTry (C PakFile &file, C Pak &pak ) {return readTryEx (file, pak , null , null);}
  553. Bool File::readTry(C Str &name, C Pak &pak)
  554. {
  555. if(C PakFile *file=pak.find(name, false))return readTry(*file, pak);
  556. close(); return false;
  557. }
  558. Bool File::readTry(C UID &id, C Pak &pak)
  559. {
  560. if(C PakFile *file=pak.find(id, false))return readTry(*file, pak);
  561. close(); return false;
  562. }
  563. /******************************************************************************/
  564. Ptr File::mem()
  565. {
  566. switch(_type)
  567. {
  568. case FILE_MEM: return memFast();
  569. }
  570. return null;
  571. }
  572. Long File::posFile()C
  573. {
  574. switch(_type)
  575. {
  576. default : return pos();
  577. case FILE_STD_READ : return pos()+_buf_len; // in read mode, the actual position is ahead
  578. case FILE_STD_WRITE: return pos()-_buf_len; // in write mode, the actual position is behind
  579. }
  580. }
  581. Bool File::pos(Long pos)
  582. {
  583. if(pos==T._pos)return true;
  584. if(pos>=0)switch(_type)
  585. {
  586. case FILE_STD_READ:
  587. {
  588. {
  589. Long delta =pos-T._pos;
  590. if( delta<=_buf_len // we skip forward and we still have data in the buffer
  591. && -delta<=_buf_pos) // we skip backward and we have previous data in the buffer
  592. {
  593. _buf_len-=delta;
  594. _buf_pos+=delta;
  595. T._pos=pos; return true; // don't seek (because file position is already in order with the buffer)
  596. }
  597. }
  598. clearBuf(); // if we're going to seek then we need to clear the buffer if any
  599. seek: Long abs_pos=Seek(_handle, _offset+pos, SEEK_SET); if(abs_pos<0)return false;
  600. T._pos =abs_pos-_offset; // set position to what was actually set, in case it's different than what requested
  601. }return T._pos==pos;
  602. case FILE_STD_WRITE:
  603. {
  604. if(_buf_len && !flushDo())
  605. {
  606. //return false; alternative approach is to just return false, however since 'pos' was called, then we take it with higher priority, and try to do what was requested
  607. #if ALLOW_REFLUSH
  608. _ok=false; // error occurred
  609. clearBuf(); // if we're allowing re-flush then it means some data could be left in the buffer, however because we're seeking, then we need to always discard it, so it's not saved at a different position
  610. #endif
  611. }
  612. }goto seek;
  613. case FILE_MEM :
  614. case FILE_MEMB: T._pos=pos; return true;
  615. }
  616. return false;
  617. }
  618. /******************************************************************************/
  619. // COMPRESS / DECOMPRESS
  620. /******************************************************************************/
  621. File& File::cmpIntV(Int i)
  622. {
  623. Byte data[MaxCmpUIntVSize]; Int pos=0;
  624. Bool negative=(i<0); UInt u=(negative ? -(i+1) : i);
  625. data[pos++]=((u&63)|(negative<<6)|((u>=64)<<7)); // 0
  626. if(u>=64)
  627. {
  628. u>>=6; data[pos++]=((u&127)|((u>=128)<<7)); // 1
  629. if(u>=128)
  630. {
  631. u>>=7; data[pos++]=((u&127)|((u>=128)<<7)); // 2
  632. if(u>=128)
  633. {
  634. u>>=7; data[pos++]=((u&127)|((u>=128)<<7)); // 3
  635. if(u>=128)
  636. {
  637. u>>=7; data[pos++]=(u); // 4
  638. }
  639. }
  640. }
  641. }
  642. put(data, pos);
  643. return T;
  644. }
  645. File& File::decIntV(Int &i)
  646. {
  647. Byte v; T>>v;
  648. Bool negative=((v>>6)&1);
  649. UInt u=(v&63);
  650. if(v&128)
  651. {
  652. T>>v; u|=((v&127)<<6);
  653. if(v&128)
  654. {
  655. T>>v; u|=((v&127)<<(6+7));
  656. if(v&128)
  657. {
  658. T>>v; u|=((v&127)<<(6+7+7));
  659. if(v&128)
  660. {
  661. T>>v; u|=(v<<(6+7+7+7));
  662. }
  663. }
  664. }
  665. }
  666. i=(negative ? -1-Int(u) : Int(u));
  667. return T;
  668. }
  669. File& File::cmpUIntV(UInt u)
  670. {
  671. Byte data[MaxCmpUIntVSize]; Int pos=0;
  672. data[pos++]=((u&127)|((u>=128)<<7));
  673. if(u>=128)
  674. {
  675. u>>=7; data[pos++]=((u&127)|((u>=128)<<7));
  676. if(u>=128)
  677. {
  678. u>>=7; data[pos++]=((u&127)|((u>=128)<<7));
  679. if(u>=128)
  680. {
  681. u>>=7; data[pos++]=((u&127)|((u>=128)<<7));
  682. if(u>=128)
  683. {
  684. u>>=7; data[pos++]=(u);
  685. }
  686. }
  687. }
  688. }
  689. put(data, pos);
  690. return T;
  691. }
  692. File& File::decUIntV(UInt &u)
  693. {
  694. Byte v; T>>v; u=(v&127);
  695. if(v&128)
  696. {
  697. T>>v; u|=((v&127)<<7);
  698. if(v&128)
  699. {
  700. T>>v; u|=((v&127)<<(7+7));
  701. if(v&128)
  702. {
  703. T>>v; u|=((v&127)<<(7+7+7));
  704. if(v&128)
  705. {
  706. T>>v; u|=(v<<(7+7+7+7));
  707. }
  708. }
  709. }
  710. }
  711. return T;
  712. }
  713. File& File::cmpLongV(Long l)
  714. {
  715. Byte data[MaxCmpULongVSize]; Int pos=0;
  716. Bool negative=(l<0); ULong u=(negative ? -(l+1) : l);
  717. data[pos++]=((u&63)|(negative<<6)|((u>=64)<<7)); // 0
  718. if(u>=64)
  719. {
  720. u>>=6; data[pos++]=((u&127)|((u>=128)<<7)); // 1
  721. if(u>=128)
  722. {
  723. u>>=7; data[pos++]=((u&127)|((u>=128)<<7)); // 2
  724. if(u>=128)
  725. {
  726. u>>=7; data[pos++]=((u&127)|((u>=128)<<7)); // 3
  727. if(u>=128)
  728. {
  729. u>>=7; data[pos++]=((u&127)|((u>=128)<<7)); // 4
  730. if(u>=128)
  731. {
  732. u>>=7; data[pos++]=((u&127)|((u>=128)<<7)); // 5
  733. if(u>=128)
  734. {
  735. u>>=7; data[pos++]=((u&127)|((u>=128)<<7)); // 6
  736. if(u>=128)
  737. {
  738. u>>=7; data[pos++]=((u&127)|((u>=128)<<7)); // 7
  739. if(u>=128)
  740. {
  741. u>>=7; data[pos++]=(u); // 8
  742. }
  743. }
  744. }
  745. }
  746. }
  747. }
  748. }
  749. }
  750. put(data, pos);
  751. return T;
  752. }
  753. File& File::decLongV(Long &l)
  754. {
  755. Byte v; T>>v;
  756. Bool negative=((v>>6)&1);
  757. ULong u=(v&63);
  758. if(v&128)
  759. {
  760. T>>v; u|=((v&127)<<6);
  761. if(v&128)
  762. {
  763. T>>v; u|=((v&127)<<(6+7));
  764. if(v&128)
  765. {
  766. T>>v; u|=((v&127)<<(6+7+7));
  767. if(v&128)
  768. {
  769. T>>v; u|=(U64(v&127)<<(6+7+7+7)); // << 27 requires U64
  770. if(v&128)
  771. {
  772. T>>v; u|=(U64(v&127)<<(6+7+7+7+7));
  773. if(v&128)
  774. {
  775. T>>v; u|=(U64(v&127)<<(6+7+7+7+7+7));
  776. if(v&128)
  777. {
  778. T>>v; u|=(U64(v&127)<<(6+7+7+7+7+7+7));
  779. if(v&128)
  780. {
  781. T>>v; u|=(U64(v)<<(6+7+7+7+7+7+7+7));
  782. }
  783. }
  784. }
  785. }
  786. }
  787. }
  788. }
  789. }
  790. l=(negative ? -1-Long(u) : Long(u));
  791. return T;
  792. }
  793. File& File::cmpULongVMax(ULong u)
  794. {
  795. Byte data[MaxCmpULongVSize];
  796. data[0]=((u&127)|(1<<7)); // 0
  797. u>>=7; data[1]=((u&127)|(1<<7)); // 1
  798. u>>=7; data[2]=((u&127)|(1<<7)); // 2
  799. u>>=7; data[3]=((u&127)|(1<<7)); // 3
  800. u>>=7; data[4]=((u&127)|(1<<7)); // 4
  801. u>>=7; data[5]=((u&127)|(1<<7)); // 5
  802. u>>=7; data[6]=((u&127)|(1<<7)); // 6
  803. u>>=7; data[7]=((u&127)|(1<<7)); // 7
  804. u>>=7; data[8]=( u ); // 8
  805. put(data);
  806. return T;
  807. }
  808. File& File::cmpULongV(ULong u)
  809. {
  810. Byte data[MaxCmpULongVSize]; Int pos=0;
  811. data[pos++]=((u&127)|((u>=128)<<7)); // 0
  812. if(u>=128)
  813. {
  814. u>>=7; data[pos++]=((u&127)|((u>=128)<<7)); // 1
  815. if(u>=128)
  816. {
  817. u>>=7; data[pos++]=((u&127)|((u>=128)<<7)); // 2
  818. if(u>=128)
  819. {
  820. u>>=7; data[pos++]=((u&127)|((u>=128)<<7)); // 3
  821. if(u>=128)
  822. {
  823. u>>=7; data[pos++]=((u&127)|((u>=128)<<7)); // 4
  824. if(u>=128)
  825. {
  826. u>>=7; data[pos++]=((u&127)|((u>=128)<<7)); // 5
  827. if(u>=128)
  828. {
  829. u>>=7; data[pos++]=((u&127)|((u>=128)<<7)); // 6
  830. if(u>=128)
  831. {
  832. u>>=7; data[pos++]=((u&127)|((u>=128)<<7)); // 7
  833. if(u>=128)
  834. {
  835. u>>=7; data[pos++]=(u); // 8
  836. }
  837. }
  838. }
  839. }
  840. }
  841. }
  842. }
  843. }
  844. put(data, pos);
  845. return T;
  846. }
  847. File& File::decULongV(ULong &u)
  848. {
  849. Byte v; T>>v; u=(v&127);
  850. if(v&128)
  851. {
  852. T>>v; u|=((v&127)<<7);
  853. if(v&128)
  854. {
  855. T>>v; u|=((v&127)<<(7+7));
  856. if(v&128)
  857. {
  858. T>>v; u|=((v&127)<<(7+7+7));
  859. if(v&128)
  860. {
  861. T>>v; u|=(U64(v&127)<<(7+7+7+7)); // << 28 requires U64
  862. if(v&128)
  863. {
  864. T>>v; u|=(U64(v&127)<<(7+7+7+7+7));
  865. if(v&128)
  866. {
  867. T>>v; u|=(U64(v&127)<<(7+7+7+7+7+7));
  868. if(v&128)
  869. {
  870. T>>v; u|=(U64(v&127)<<(7+7+7+7+7+7+7));
  871. if(v&128)
  872. {
  873. T>>v; u|=(U64(v)<<(7+7+7+7+7+7+7+7));
  874. }
  875. }
  876. }
  877. }
  878. }
  879. }
  880. }
  881. }
  882. return T;
  883. }
  884. File& File::cmpFlt3cm(C Flt &r) {UInt u=Mid(Round(r*100)+8388608, 0, 16777216-1); put(&u, 3); ASSERT(SIZE(u)>=3); return T;}
  885. File& File::decFlt3cm( Flt &r) {Int i=0; get(&i, 3); r=(i-8388608)/100.0f; ASSERT(SIZE(i)>=3); return T;}
  886. File& File::cmpSatFlt1(C Flt &r) { putByte ( FltToByte(r) ); return T;}
  887. File& File::cmpSatFlt2(C Flt &r) { putUShort(RoundU(Sat(r)*65535)); return T;} // it's better to clamp flt for bigger values
  888. File& File::decSatFlt1( Flt &r) {r=getByte ()/ 255.0f; return T;}
  889. File& File::decSatFlt2( Flt &r) {r=getUShort()/65535.0f; return T;}
  890. File& File::cmpAngle1(C Flt &r) { putByte (RoundU(AngleFull(r)*( 256/PI2))); return T;} // use 'AngleFull' to make angle smaller and thus 'RoundPos' work with better precision, there's no need for 'Mid' or "&" because 1) AngleFull already sets 0..PI2 range, 2) putByte takes only Byte as param
  891. File& File::cmpAngle2(C Flt &r) { putUShort(RoundU(AngleFull(r)*(65536/PI2))); return T;} // use 'AngleFull' to make angle smaller and thus 'RoundPos' work with better precision, there's no need for 'Mid' or "&" because 1) AngleFull already sets 0..PI2 range, 2) putUShort takes only UShort as param
  892. File& File::decAngle1( Flt &r) {r=getByte ()*(PI2/ 256); return T;}
  893. File& File::decAngle2( Flt &r) {r=getUShort()*(PI2/65536); return T;}
  894. File& File::cmpDir2(C Vec &v)
  895. {
  896. Byte x=Mid(RoundPos(v.x*127+128), 0, 255), // 8-bits for X
  897. y=Mid(RoundPos(v.y* 63+ 64), 0, 127); // 7-bits for Y
  898. Bool z=(v.z<0); // 1-bit for Z sign
  899. putUShort(x|(y<<8)|(z<<15));
  900. return T;
  901. }
  902. File& File::cmpDir3(C Vec &v)
  903. {
  904. UInt x=Mid(RoundPos(v.x*2047+2048), 0, 4095), // 12-bits for X
  905. y=Mid(RoundPos(v.y*1023+1024), 0, 2047); // 11-bits for Y
  906. Bool z=(v.z<0); // 1-bit for Z sign
  907. UInt c=(x|(y<<12)|(z<<23)); put(&c, 3); ASSERT(SIZE(c)>=3);
  908. return T;
  909. }
  910. File& File::decDir2(Vec &v)
  911. {
  912. UShort c=getUShort();
  913. Int x=((c )&255),
  914. y=((c>> 8)&127);
  915. Bool z=((c>>15)& 1);
  916. v.x=(x-128)/127.0f;
  917. v.y=(y- 64)/ 63.0f;
  918. v.z=CalcZ(v.xy); if(z)CHS(v.z);
  919. v.normalize();
  920. return T;
  921. }
  922. File& File::decDir3(Vec &v)
  923. {
  924. UInt c; get(&c, 3); ASSERT(SIZE(c)>=3); // clearing 'c' to zero first is not needed, since we're reading bits only from first 3 bytes below
  925. Int x=((c )&4095),
  926. y=((c>>12)&2047);
  927. Bool z=((c>>23)& 1);
  928. v.x=(x-2048)/2047.0f;
  929. v.y=(y-1024)/1023.0f;
  930. v.z=CalcZ(v.xy); if(z)CHS(v.z);
  931. v.normalize();
  932. return T;
  933. }
  934. File& File::cmpOrient2(C Matrix3 &m)
  935. {
  936. Vec angles=m.angles();
  937. Byte x=(Round(angles.x*(32/PI2))&31), // 5-bits for X
  938. y=(Round(angles.y*(64/PI2))&63), // 6-bits for Y (because most objects are on ground, and just rotated along Y axis, so give more precision to that axis)
  939. z=(Round(angles.z*(32/PI2))&31); // 5-bits for Z
  940. putUShort(x|(y<<5)|(z<<11));
  941. return T;
  942. }
  943. File& File::cmpOrient3(C Matrix3 &m)
  944. {
  945. Vec angles=m.angles();
  946. Byte b[]={Byte(Round(angles.x*(256/PI2))), Byte(Round(angles.y*(256/PI2))), Byte(Round(angles.z*(256/PI2)))};
  947. T<<b;
  948. return T;
  949. }
  950. File& File::cmpOrient4(C Matrix3 &m)
  951. {
  952. Vec angles=m.angles();
  953. UInt x=(Round(angles.x*(2048/PI2))&2047), // 11-bits for X
  954. y=(Round(angles.y*(2048/PI2))&2047), // 11-bits for Y
  955. z=(Round(angles.z*(1024/PI2))&1023); // 10-bits for Z
  956. putUInt(x|(y<<11)|(z<<22));
  957. return T;
  958. }
  959. File& File::decOrient2(Matrix3 &m)
  960. {
  961. UShort c=getUShort();
  962. Byte x=( c &31),
  963. y=((c>> 5)&63),
  964. z=( c>>11 );
  965. m.setRotateZ(z*(PI2/32)).rotateXY(x*(PI2/32), y*(PI2/64));
  966. return T;
  967. }
  968. File& File::decOrient3(Matrix3 &m)
  969. {
  970. Byte b[3]; T>>b;
  971. m.setRotateZ(b[2]*(PI2/256)).rotateXY(b[0]*(PI2/256), b[1]*(PI2/256));
  972. return T;
  973. }
  974. File& File::decOrient4(Matrix3 &m)
  975. {
  976. UInt c=getUInt(),
  977. x=( c &2047),
  978. y=((c>>11)&2047),
  979. z=( c>>22 );
  980. m.setRotateZ(z*(PI2/1024)).rotateXY(x*(PI2/2048), y*(PI2/2048));
  981. return T;
  982. }
  983. /******************************************************************************/
  984. // MISC
  985. /******************************************************************************/
  986. UInt File::memUsage()C
  987. {
  988. UInt mem=_buf_size;
  989. switch(_type)
  990. {
  991. case FILE_MEM : if(_writable)mem+=_size ; break;
  992. #if FILE_MEMB_UNION
  993. case FILE_MEMB: mem+=_memb.memUsage(); break;
  994. #endif
  995. }
  996. #if !FILE_MEMB_UNION
  997. mem+=_memb.memUsage();
  998. #endif
  999. return mem;
  1000. }
  1001. /******************************************************************************/
  1002. Bool File::flushDo()
  1003. {
  1004. DEBUG_ASSERT(_type==FILE_STD_WRITE && _buf_len, "File.flushDo");
  1005. Int written =Write(_handle, _buf, _buf_len);
  1006. if( written==_buf_len){_buf_len=0; return true;} // check this first because most likely this will happen, so return early
  1007. #if ALLOW_REFLUSH
  1008. if(written>0) // this avoids errors (<0) and when no data was written (==0)
  1009. {
  1010. _buf_len-=written; // decrease what we've written
  1011. MoveFast(_buf, (Byte*)_buf+written, _buf_len); // since writing always uses start of the buffer, we need to copy remaining data at the start
  1012. }
  1013. // here '_pos, _buf_len, _ok' shouldn't be adjusted, because no data is lost, some was written and remaining is still in the buffer
  1014. #else
  1015. if(written>0)_pos+=written; // this avoids errors (<0) and when no data was written (==0)
  1016. _pos-=_buf_len; // normally '_pos' is located already ahead at '_buf_len' position (assumes that everything was written), but if we've written less, then we need to set it back to what was lost
  1017. _buf_len=0; // discard data
  1018. _ok=false; // data was lost
  1019. #endif
  1020. return false;
  1021. }
  1022. Bool File::flushOK() {return flush() && ok();}
  1023. Bool File::flush ()
  1024. {
  1025. if(_buf_len && _type==FILE_STD_WRITE)return flushDo();
  1026. return true;
  1027. }
  1028. Bool File::sync()
  1029. {
  1030. if(_writable && (_type==FILE_STD_WRITE || _type==FILE_STD_READ)) // check 'FILE_STD_READ' too, because we may have written data previously in FILE_STD_WRITE, and later switched to FILE_STD_READ
  1031. {
  1032. #if WINDOWS
  1033. #if 1 // faster
  1034. return FlushFileBuffers((HANDLE)_get_osfhandle(_handle));
  1035. #else // internally calls 'FlushFileBuffers' which means this has bigger overhead
  1036. return _commit(_handle)==0;
  1037. #endif
  1038. #else
  1039. return fsync(_handle)==0;
  1040. #endif
  1041. }
  1042. return true;
  1043. }
  1044. /******************************************************************************/
  1045. void File::cipher(Cipher *cipher)
  1046. {
  1047. if(T._cipher!=cipher)
  1048. {
  1049. if(_type==FILE_STD_READ) // if we're in reading mode (we can skip FILE_STD_WRITE because any data saved in the buffer is saved with correct cipher already, and we don't want to change it)
  1050. if(Int buf_size=_buf_pos+_buf_len) // and we have any data in buffer that we've read ahead
  1051. {
  1052. auto offset=posCipher()-_buf_pos;
  1053. if(T._cipher)T._cipher->encrypt(_buf, _buf, buf_size, offset); // we have to encrypt entire buffer back using old cipher
  1054. if( cipher) cipher->decrypt(_buf, _buf, buf_size, offset); // decrypt using new cipher
  1055. }
  1056. T._cipher=cipher;
  1057. }
  1058. }
  1059. void File::cipherOffset(Int offset)
  1060. {
  1061. if(T._cipher_offset!=offset)
  1062. {
  1063. if(_type==FILE_STD_READ) // if we're in reading mode (we can skip FILE_STD_WRITE because any data saved in the buffer is saved with correct cipher offset already, and we don't want to change it)
  1064. if(_cipher) // we have any cipher
  1065. if(Int buf_size=_buf_pos+_buf_len) // and we have any data in buffer that we've read ahead
  1066. {
  1067. _cipher->encrypt(_buf, _buf, buf_size, posCipher()-_buf_pos); T._cipher_offset=offset; // we have to encrypt entire buffer back using old cipher offset
  1068. _cipher->decrypt(_buf, _buf, buf_size, posCipher()-_buf_pos); // decrypt using new cipher offset
  1069. }
  1070. T._cipher_offset=offset;
  1071. }
  1072. }
  1073. /******************************************************************************/
  1074. Bool File::size(Long size)
  1075. {
  1076. if(size==T.size())return true;
  1077. if(size<0 || _offset)return false;
  1078. if(!flush() && ALLOW_REFLUSH)_ok=false; // if flush failed, then set as ok=false, because the data will be discarded
  1079. switch(_type)
  1080. {
  1081. case FILE_STD_READ :
  1082. case FILE_STD_WRITE: //if(_writable) we can skip this check because the system calls will just fail for non-writable
  1083. {
  1084. #if WINDOWS
  1085. if(!_chsize_s (_handle, size))
  1086. #elif APPLE || (ANDROID && __ANDROID_API__<12) // on Apple 'ftruncate' is already 64-bit, while Android has 'ftruncate64' only on API 12 and above
  1087. if(!ftruncate (_handle, size))
  1088. #else
  1089. if(!ftruncate64(_handle, size))
  1090. #endif
  1091. {
  1092. // no need to call 'setBuf' because we can only change size for files in write mode, an in this mode files always have BUF_SIZE buffer
  1093. // no need to clip current position to size limit, because 'File' allows position being after the end
  1094. _size=size;
  1095. discardBuf(false); // disable flushing because we've already tried it at the start, and doing it again could change the file size
  1096. }
  1097. }break;
  1098. case FILE_MEM:
  1099. {
  1100. if(_writable)_Realloc(_mem, size, _size); // write mode allocated memory manually, so we need to reallocate it
  1101. _size=size;
  1102. }break;
  1103. case FILE_MEMB: _size=_memb.setNum(size).elms(); break; // set '_size' from what 'Memb' will actually have
  1104. }
  1105. return _size==size;
  1106. }
  1107. /******************************************************************************/
  1108. Int File::getReturnSize(Ptr data, Int size)
  1109. {
  1110. Long old_pos=_pos;
  1111. if(!data)skip(size);else
  1112. {
  1113. MIN(size, left());
  1114. if (size>0)switch(_type)
  1115. {
  1116. case FILE_STD_WRITE:
  1117. {
  1118. if(!discardBuf(true))break; // if this fails then we can't read, because we're expecting to read at the current position
  1119. _type=FILE_STD_READ; // set new mode and fall down for reading
  1120. } // !! no break on purpose !!
  1121. case FILE_STD_READ :
  1122. {
  1123. if(_buf_len) // have data in the buffer
  1124. {
  1125. get_from_buffer:
  1126. Int l=Min(_buf_len, size);
  1127. CopyFast(data, (Byte*)_buf+_buf_pos, l);
  1128. _buf_pos+=l;
  1129. _buf_len-=l;
  1130. _pos +=l;
  1131. size-=l; if(size<=0)break;
  1132. data =(Byte*)data+l; // can be placed after break
  1133. }
  1134. // read from file
  1135. if(size>=_buf_size/2) // in this case it will be faster to don't use buffering and just read directly to target memory
  1136. // "size>=_buf_size" was tested as well, but it was slower
  1137. {
  1138. // read to 'data'
  1139. Int l =Read(_handle, data, size);
  1140. if( l<=0)break;
  1141. if(_cipher)_cipher->decrypt(data, data, l, posCipher());
  1142. _pos +=l;
  1143. size-=l; if(size<=0)break;
  1144. data =(Byte*)data+l; // can be placed after break
  1145. }
  1146. // read to buffer
  1147. Int l =Read(_handle, _buf, Min(_buf_size, left())); // read as much as possible
  1148. if( l<=0)break;
  1149. if(_cipher)_cipher->decrypt(_buf, _buf, l, posCipher()); // decrypt entire buffer at the same time (faster)
  1150. _buf_pos=0;
  1151. _buf_len=l;
  1152. goto get_from_buffer;
  1153. }break;
  1154. case FILE_MEM:
  1155. {
  1156. Ptr src=memFast();
  1157. if(_cipher)_cipher->decrypt(data, src, size, posCipher());
  1158. else CopyFast(data, src, size );
  1159. _pos+=size;
  1160. //data=(Byte*)data+size; not needed
  1161. //size= 0; not needed
  1162. }break;
  1163. case FILE_MEMB:
  1164. {
  1165. for(;;)
  1166. {
  1167. Int pos_abs=posAbs(), // Long not needed because later this is used only as Int memb element index
  1168. elm =pos_abs & _memb.mask(), // index of element in a block
  1169. l =Min(size, _memb.blockElms()-elm); // how much elements left in this block
  1170. if(_cipher)_cipher->decrypt(data, &_memb[pos_abs], l, posCipher());
  1171. else CopyFast(data, &_memb[pos_abs], l );
  1172. _pos +=l;
  1173. size-=l; if(size<=0)break;
  1174. data =(Byte*)data+l; // can be placed after break
  1175. }
  1176. }break;
  1177. }
  1178. }
  1179. return _pos-old_pos; // return number of bytes read
  1180. }
  1181. Int File::putReturnSize(CPtr data, Int size)
  1182. {
  1183. Long old_pos=_pos;
  1184. if(size>0)
  1185. {
  1186. switch(_type)
  1187. {
  1188. case FILE_STD_READ:
  1189. {
  1190. if(!_writable || !discardBuf(false))break; // if this fails then we can't write, because we're expecting to write at the current position, no need for flush because FILE_STD_READ doesn't need flush
  1191. _type=FILE_STD_WRITE; // set new mode and fall down for writing
  1192. } // !! no break on purpose !!
  1193. case FILE_STD_WRITE:
  1194. {
  1195. if(!_cipher && data) // buffering optional (check for 'data' because it's allowed to be null and write zeros)
  1196. {
  1197. do{
  1198. if(_buf_len || size<_buf_size) // copy to buffer
  1199. {
  1200. Int l=Min(size, _buf_size-_buf_len);
  1201. CopyFast((Byte*)_buf+_buf_len, data, l);
  1202. _buf_len+=l;
  1203. data =(Byte*)data+l;
  1204. _pos +=l;
  1205. size-=l;
  1206. if(_buf_len>=_buf_size && !flushDo())break; // if buffer is full then flush and check for errors
  1207. }else // direct write
  1208. {
  1209. Int written=Write(_handle, data, size); if(written<=0)break;
  1210. data =(Byte*)data+written;
  1211. _pos +=written;
  1212. size-=written;
  1213. }
  1214. }while(size>0);
  1215. }else // buffering necessary
  1216. {
  1217. do{
  1218. // copy to buffer
  1219. Int l=Min(size, _buf_size-_buf_len);
  1220. if(_cipher)_cipher->encrypt((Byte*)_buf+_buf_len, data, l, posCipher());
  1221. else Copy((Byte*)_buf+_buf_len, data, l );
  1222. _buf_len+=l;
  1223. if(data)data=(Byte*)data+l;
  1224. _pos +=l;
  1225. size-=l;
  1226. if(_buf_len>=_buf_size && !flushDo())break; // if buffer is full then flush and check for errors
  1227. }while(size>0);
  1228. }
  1229. }break;
  1230. case FILE_MEM: if(_writable)
  1231. {
  1232. Int write=Min(size, left()); // don't write more than is allocated
  1233. Ptr dest =memFast();
  1234. if(_cipher)_cipher->encrypt(dest, data, write, posCipher());
  1235. else Copy(dest, data, write );
  1236. _pos +=write;
  1237. size-=write;
  1238. }break;
  1239. case FILE_MEMB:
  1240. {
  1241. Int dest_elms=posAbs()+size; if(dest_elms>_memb.elms())_memb.setNum(dest_elms); // Long not needed because is used for Memb based on 32-bits
  1242. do{
  1243. Int pos_abs=posAbs(), // Long not needed because later is used only as Int memb element index
  1244. elm =pos_abs & _memb.mask(), // index of element in a block
  1245. l =Min(size, _memb.blockElms()-elm); // how much elements left in this block
  1246. if(_cipher)_cipher->encrypt(&_memb[pos_abs], data, l, posCipher());
  1247. else Copy(&_memb[pos_abs], data, l );
  1248. if(data)data=(Byte*)data+l;
  1249. _pos +=l;
  1250. size-=l;
  1251. }while(size>0);
  1252. }break;
  1253. }
  1254. MAX(_size, _pos);
  1255. }
  1256. return _pos-old_pos; // return number of bytes written
  1257. }
  1258. Bool File::getFast(Ptr data, Int size)
  1259. {
  1260. if(getReturnSize(data, size)==size)return true;
  1261. _ok=false; return false; // set error
  1262. }
  1263. Bool File::get(Ptr data, Int size)
  1264. {
  1265. Int read=getReturnSize(data, size);
  1266. if( read==size)return true; // check this first because this is what's most likely going to happen
  1267. if( data)Zero((Byte*)data+read, size-read); // zero unread data, this is important because methods such as f.getInt, f.decUIntV, .. don't check for status, however they're expected to return zeros
  1268. _ok=false; return false; // set error
  1269. }
  1270. Bool File::put(CPtr data, Int size)
  1271. {
  1272. Int written=putReturnSize(data, size);
  1273. if( written==size)return true; // check this first because this is what's most likely going to happen
  1274. _ok=false; return false; // set error
  1275. }
  1276. /******************************************************************************/
  1277. File& File::putStr(CChar8 *t)
  1278. {
  1279. Int length =Length (t);
  1280. Bool unicode=HasUnicode(t);
  1281. cmpIntV(unicode ? -length : length);
  1282. if(length)
  1283. {
  1284. if(unicode)
  1285. {
  1286. Memt<Char> temp; temp.setNum(length+1); Set(temp.data(), t, temp.elms());
  1287. putN(temp.data(), length);
  1288. }else
  1289. {
  1290. putN(t, length);
  1291. }
  1292. }
  1293. return T;
  1294. }
  1295. File& File::putStr(CChar *t)
  1296. {
  1297. Int length =Length (t);
  1298. Bool unicode=HasUnicode(t);
  1299. cmpIntV(unicode ? -length : length);
  1300. if(length)
  1301. {
  1302. if(unicode)
  1303. {
  1304. putN(t, length);
  1305. }else
  1306. {
  1307. Memt<Char8> temp; temp.setNum(length+1); Set(temp.data(), t, temp.elms());
  1308. putN(temp.data(), length);
  1309. }
  1310. }
  1311. return T;
  1312. }
  1313. File& File::putStr(C Str8 &s) // keep this function to allow having '\0' chars in the middle
  1314. {
  1315. Int length =s.length();
  1316. Bool unicode=HasUnicode(s);
  1317. cmpIntV(unicode ? -length : length);
  1318. if(length)
  1319. {
  1320. if(unicode){Memt<Char> temp; temp.setNum(length); FREPAO(temp)=Char8To16Fast(s[i]); putN(temp.data(), length);} // we can assume that Str was already initialized
  1321. else { putN( s(), length);}
  1322. }
  1323. return T;
  1324. }
  1325. File& File::putStr(C Str &s) // keep this function to allow having '\0' chars in the middle
  1326. {
  1327. Int length =s.length();
  1328. Bool unicode=HasUnicode(s);
  1329. cmpIntV(unicode ? -length : length);
  1330. if(length)
  1331. {
  1332. if(unicode){ putN( s(), length);}
  1333. else {Memt<Char8> temp; temp.setNum(length); FREPAO(temp)=Char16To8Fast(s[i]); putN(temp.data(), length);} // we can assume that Str was already initialized
  1334. }
  1335. return T;
  1336. }
  1337. File& File::skipStr()
  1338. {
  1339. Int length; decIntV(length);
  1340. if( length<0){CHS(length); length*=SIZE(Char );} // unicode
  1341. else length*=SIZE(Char8);
  1342. if(left()<length) // length too long
  1343. {
  1344. _ok=false; pos(size()); // if the length was too long then go at the end of file, in case the user will try to read more data after this call, this is important so that the partially available string data is not treated as something else
  1345. }else skip(length);
  1346. return T;
  1347. }
  1348. File& File::getStr(Str8 &s) // warning: this must handle having '\0' chars in the middle
  1349. {
  1350. s.clear(); // always 'clear' even for 'reserve' to avoid copying old data in 'setNum'
  1351. Int length; decIntV(length);
  1352. if( length<0) // unicode
  1353. {
  1354. CHS(length);
  1355. if(left()<length*SIZEI(Char))goto length_too_long;
  1356. s.reserve(length);
  1357. Memt<Char> temp; temp.setNum(length); getN(temp.data(), length);
  1358. FREPA(temp)s._d[i]=Char16To8Fast(temp[i]); s._d[s._length=length]=0; // we can assume that Str was already initialized
  1359. }else
  1360. if(length)
  1361. {
  1362. if(left()<length*SIZEI(Char8))goto length_too_long;
  1363. s.reserve(length);
  1364. getN(s._d.data(), length); s._d[s._length=length]=0;
  1365. }
  1366. if(ok())return T;
  1367. goto error;
  1368. length_too_long:
  1369. _ok=false; pos(size()); // if the length was too long then go at the end of file, in case the user will try to read more data after this call, this is important so that the partially available string data is not treated as something else
  1370. error:
  1371. s.clear(); return T;
  1372. }
  1373. File& File::getStr(Str &s) // warning: this must handle having '\0' chars in the middle
  1374. {
  1375. s.clear(); // always 'clear' even for 'reserve' to avoid copying old data in 'setNum'
  1376. Int length; decIntV(length);
  1377. if( length<0) // unicode
  1378. {
  1379. CHS(length);
  1380. if(left()<length*SIZEI(Char))goto length_too_long;
  1381. s.reserve(length);
  1382. getN(s._d.data(), length); s._d[s._length=length]=0;
  1383. }else
  1384. if(length)
  1385. {
  1386. if(left()<length*SIZEI(Char8))goto length_too_long;
  1387. s.reserve(length);
  1388. Char8 *temp=(Char8*)s._d.data(); getN(temp, length); // we can re-use the string memory because it uses Char which has 2x Char8 capacity
  1389. s._d[s._length=length]=0; // because we're processing from the end, then start with the end too
  1390. REP(length)s._d[i]=Char8To16Fast(temp[i]); // need to process from the end to not overwrite the source, we can assume that Str was already initialized
  1391. }
  1392. if(ok())return T;
  1393. goto error;
  1394. length_too_long:
  1395. _ok=false; pos(size()); // if the length was too long then go at the end of file, in case the user will try to read more data after this call, this is important so that the partially available string data is not treated as something else
  1396. error:
  1397. s.clear(); return T;
  1398. }
  1399. File& File::getStr(Char8 *t, Int t_elms)
  1400. {
  1401. Int length; decIntV(length);
  1402. if( length<0) // unicode
  1403. {
  1404. CHS(length);
  1405. if(left()<length*SIZEI(Char))goto length_too_long;
  1406. if(t && t_elms>0)
  1407. {
  1408. Int read=Min(length, t_elms-1);
  1409. Memt<Char> temp; temp.setNum(read); getN(temp.data(), read);
  1410. FREP(read)t[i]=Char16To8Fast(temp[i]); t[read]=0; // we can assume that Str was already initialized
  1411. length-=read;
  1412. }
  1413. length*=SIZE(Char);
  1414. }else
  1415. {
  1416. if(left()<length*SIZEI(Char8))goto length_too_long;
  1417. if(t && t_elms>0)
  1418. {
  1419. Int read=Min(length, t_elms-1);
  1420. getN(t, read); t[read]=0;
  1421. length-=read;
  1422. }
  1423. }
  1424. skip(length);
  1425. if(ok())return T;
  1426. goto error;
  1427. length_too_long:
  1428. _ok=false; pos(size()); // if the length was too long then go at the end of file, in case the user will try to read more data after this call, this is important so that the partially available string data is not treated as something else
  1429. error:
  1430. if(t && t_elms>0)t[0]='\0'; return T;
  1431. }
  1432. File& File::getStr(Char *t, Int t_elms)
  1433. {
  1434. Int length; decIntV(length);
  1435. if( length<0) // unicode
  1436. {
  1437. CHS(length);
  1438. if(left()<length*SIZEI(Char))goto length_too_long;
  1439. if(t && t_elms>0)
  1440. {
  1441. Int read=Min(length, t_elms-1);
  1442. getN(t, read); t[read]=0;
  1443. length-=read;
  1444. }
  1445. length*=SIZE(Char);
  1446. }else
  1447. {
  1448. if(left()<length*SIZEI(Char8))goto length_too_long;
  1449. if(t && t_elms>0)
  1450. {
  1451. Int read=Min(length, t_elms-1);
  1452. Char8 *temp=(Char8*)t; getN(temp, read); // we can re-use the char array memory because it uses Char which has 2x Char8 capacity
  1453. t[read]=0; // because we're processing from the end, then start with the end too
  1454. REP(read)t[i]=Char8To16Fast(temp[i]); // need to process from the end to not overwrite the source, we can assume that Str was already initialized
  1455. length-=read;
  1456. }
  1457. }
  1458. skip(length);
  1459. if(ok())return T;
  1460. goto error;
  1461. length_too_long:
  1462. _ok=false; pos(size()); // if the length was too long then go at the end of file, in case the user will try to read more data after this call, this is important so that the partially available string data is not treated as something else
  1463. error:
  1464. if(t && t_elms>0)t[0]='\0'; return T;
  1465. }
  1466. Str File::getStr() {Str s; getStr(s); return s;} // warning: this must handle having '\0' chars in the middle
  1467. /******************************************************************************/
  1468. File& File::putAsset(C UID &id)
  1469. {
  1470. Int used; REPAS(used, id.b)if(id.b[used])break; used++;
  1471. putByte(used).put(id.b, used);
  1472. return T;
  1473. }
  1474. File& File::putAsset(CChar *t)
  1475. {
  1476. if(!Is(t))putByte(0);else
  1477. {
  1478. UID id; if(DecodeFileName(t, id))putAsset(id);else putByte(0xFF).putStr(t);
  1479. }
  1480. return T;
  1481. }
  1482. UID File::getAssetID()
  1483. {
  1484. Byte b; T>>b;
  1485. if( b<=SIZE(UID))
  1486. {
  1487. UID id; if(getFast(id.b, b))
  1488. {
  1489. Byte *d=id.b+b; REP(SIZE(id)-b)d[i]=0; return id;
  1490. }
  1491. }else
  1492. if(b==0xFF)skipStr();
  1493. //else error
  1494. return UIDZero;
  1495. }
  1496. File& File::getAsset(Str &s)
  1497. {
  1498. Byte b; T>>b;
  1499. if( b<=SIZE(UID))
  1500. {
  1501. if(!b)s.clear();else
  1502. {
  1503. UID id; if(getFast(id.b, b))
  1504. {
  1505. Byte *d=id.b+b; REP(SIZE(id)-b)d[i]=0; s=_EncodeFileName(id);
  1506. }else s.clear();
  1507. }
  1508. }else
  1509. if(b==0xFF)getStr(s);
  1510. else s.clear(); // error
  1511. return T;
  1512. }
  1513. Str File::getAsset() {Str s; getAsset(s); return s;}
  1514. /******************************************************************************/
  1515. // Deprecated, do not use
  1516. File& File::_decIntV(Int &i)
  1517. {
  1518. Byte v; T>>v;
  1519. Bool positive=((v>>6)&1);
  1520. UInt u=(v&63);
  1521. if(v&128)
  1522. {
  1523. T>>v; u|=((v&127)<<6);
  1524. if(v&128)
  1525. {
  1526. T>>v; u|=((v&127)<<(6+7));
  1527. if(v&128)
  1528. {
  1529. T>>v; u|=((v&127)<<(6+7+7));
  1530. if(v&128)
  1531. {
  1532. T>>v; u|=(v<<(6+7+7+7));
  1533. }
  1534. }
  1535. }
  1536. }
  1537. i=(positive ? u+1 : -Int(u));
  1538. return T;
  1539. }
  1540. Str File::_getStr2( ) {Str s; _getStr2(s); return s;} // warning: this must handle having '\0' chars in the middle
  1541. File& File::_getStr2(Str &s) // warning: this must handle having '\0' chars in the middle
  1542. {
  1543. s.clear(); // always 'clear' even for 'reserve' to avoid copying old data in 'setNum'
  1544. Int length; _decIntV(length);
  1545. if( length<0) // unicode
  1546. {
  1547. CHS(length);
  1548. if(left()<length*SIZEI(Char))goto length_too_long;
  1549. s.reserve(length);
  1550. getN(s._d.data(), length); s._d[s._length=length]=0;
  1551. }else
  1552. if(length)
  1553. {
  1554. if(left()<length*SIZEI(Char8))goto length_too_long;
  1555. s.reserve(length);
  1556. Char8 *temp=(Char8*)s._d.data(); getN(temp, length); // we can re-use the string memory because it uses Char which has 2x Char8 capacity
  1557. s._d[s._length=length]=0; // because we're processing from the end, then start with the end too
  1558. REP(length)s._d[i]=Char8To16Fast(temp[i]); // need to process from the end to not overwrite the source, we can assume that Str was already initialized
  1559. }
  1560. if(ok())return T;
  1561. goto error;
  1562. length_too_long:
  1563. _ok=false; pos(size()); // if the length was too long then go at the end of file, in case the user will try to read more data after this call, this is important so that the partially available string data is not treated as something else
  1564. error:
  1565. s.clear(); return T;
  1566. }
  1567. File& File::_getStr2(Str8 &s) // warning: this must handle having '\0' chars in the middle
  1568. {
  1569. s.clear(); // always 'clear' even for 'reserve' to avoid copying old data in 'setNum'
  1570. Int length; _decIntV(length);
  1571. if( length<0) // unicode
  1572. {
  1573. CHS(length);
  1574. if(left()<length*SIZEI(Char))goto length_too_long;
  1575. s.reserve(length);
  1576. Memt<Char> temp; temp.setNum(length); getN(temp.data(), length);
  1577. FREPA(temp)s._d[i]=Char16To8Fast(temp[i]); s._d[s._length=length]=0; // we can assume that Str was already initialized
  1578. }else
  1579. if(length)
  1580. {
  1581. if(left()<length*SIZEI(Char8))goto length_too_long;
  1582. s.reserve(length);
  1583. getN(s._d.data(), length); s._d[s._length=length]=0;
  1584. }
  1585. if(ok())return T;
  1586. goto error;
  1587. length_too_long:
  1588. _ok=false; pos(size()); // if the length was too long then go at the end of file, in case the user will try to read more data after this call, this is important so that the partially available string data is not treated as something else
  1589. error:
  1590. s.clear(); return T;
  1591. }
  1592. File& File::_getStr2(Char8 *t, Int t_elms)
  1593. {
  1594. Int length; _decIntV(length);
  1595. if( length<0) // unicode
  1596. {
  1597. CHS(length);
  1598. if(left()<length*SIZEI(Char))goto length_too_long;
  1599. if(t && t_elms>0)
  1600. {
  1601. Int read=Min(length, t_elms-1);
  1602. Memt<Char> temp; temp.setNum(read); getN(temp.data(), read);
  1603. FREP(read)t[i]=Char16To8Fast(temp[i]); t[read]=0; // we can assume that Str was already initialized
  1604. length-=read;
  1605. }
  1606. length*=SIZE(Char);
  1607. }else
  1608. {
  1609. if(left()<length*SIZEI(Char8))goto length_too_long;
  1610. if(t && t_elms>0)
  1611. {
  1612. Int read=Min(length, t_elms-1);
  1613. getN(t, read); t[read]=0;
  1614. length-=read;
  1615. }
  1616. }
  1617. skip(length);
  1618. if(ok())return T;
  1619. goto error;
  1620. length_too_long:
  1621. _ok=false; pos(size()); // if the length was too long then go at the end of file, in case the user will try to read more data after this call, this is important so that the partially available string data is not treated as something else
  1622. error:
  1623. if(t && t_elms>0)t[0]='\0'; return T;
  1624. }
  1625. File& File::_getStr2(Char *t, Int t_elms)
  1626. {
  1627. Int length; _decIntV(length);
  1628. if( length<0) // unicode
  1629. {
  1630. CHS(length);
  1631. if(left()<length*SIZEI(Char))goto length_too_long;
  1632. if(t && t_elms>0)
  1633. {
  1634. Int read=Min(length, t_elms-1);
  1635. getN(t, read); t[read]=0;
  1636. length-=read;
  1637. }
  1638. length*=SIZE(Char);
  1639. }else
  1640. {
  1641. if(left()<length*SIZEI(Char8))goto length_too_long;
  1642. if(t && t_elms>0)
  1643. {
  1644. Int read=Min(length, t_elms-1);
  1645. Char8 *temp=(Char8*)t; getN(temp, read); // we can re-use the char array memory because it uses Char which has 2x Char8 capacity
  1646. t[read]=0; // because we're processing from the end, then start with the end too
  1647. REP(read)t[i]=Char8To16Fast(temp[i]); // need to process from the end to not overwrite the source, we can assume that Str was already initialized
  1648. length-=read;
  1649. }
  1650. }
  1651. skip(length);
  1652. if(ok())return T;
  1653. goto error;
  1654. length_too_long:
  1655. _ok=false; pos(size()); // if the length was too long then go at the end of file, in case the user will try to read more data after this call, this is important so that the partially available string data is not treated as something else
  1656. error:
  1657. if(t && t_elms>0)t[0]='\0'; return T;
  1658. }
  1659. File& File::_putStr(C Str8 &s) // warning: this must handle having '\0' chars in the middle
  1660. {
  1661. UInt length =s.length();
  1662. Bool unicode=HasUnicode(s);
  1663. putUInt(unicode ? length^SIGN_BIT : length);
  1664. if(length)
  1665. {
  1666. if(unicode){Memt<Char> temp; temp.setNum(length); FREPAO(temp)=Char8To16Fast(s[i]); putN(temp.data(), length);} // we can assume that Str was already initialized
  1667. else { putN( s(), length);}
  1668. }
  1669. return T;
  1670. }
  1671. File& File::_putStr(C Str &s) // warning: this must handle having '\0' chars in the middle
  1672. {
  1673. UInt length =s.length();
  1674. Bool unicode=HasUnicode(s);
  1675. putUInt(unicode ? length^SIGN_BIT : length);
  1676. if(length)
  1677. {
  1678. if(unicode){ putN( s(), length);}
  1679. else {Memt<Char8> temp; temp.setNum(length); FREPAO(temp)=Char16To8Fast(s[i]); putN(temp.data(), length);} // we can assume that Str was already initialized
  1680. }
  1681. return T;
  1682. }
  1683. File& File::_getStr(Str8 &s) // warning: this must handle having '\0' chars in the middle
  1684. {
  1685. s.clear(); // always 'clear' even for 'reserve' to avoid copying old data in 'setNum'
  1686. UInt length=getUInt();
  1687. if( length&SIGN_BIT) // unicode
  1688. {
  1689. length^=SIGN_BIT; MIN(length, left()/SIZEI(Char));
  1690. if(length)
  1691. {
  1692. s.reserve(length);
  1693. Memt<Char> temp; temp.setNum(length); getN(temp.data(), length);
  1694. FREPA(temp)s._d[i]=Char16To8Fast(temp[i]); // we can assume that Str was already initialized
  1695. s._d[s._length=length]=0;
  1696. }
  1697. }else
  1698. {
  1699. MIN(length, left());
  1700. if (length)
  1701. {
  1702. s.reserve(length);
  1703. getN(s._d.data(), length);
  1704. s._d[s._length=length]=0;
  1705. }
  1706. }
  1707. return T;
  1708. }
  1709. Str File::_getStr( ) {Str s; _getStr(s); return s;} // warning: this must handle having '\0' chars in the middle
  1710. File& File::_getStr(Str &s) // warning: this must handle having '\0' chars in the middle
  1711. {
  1712. s.clear(); // always 'clear' even for 'reserve' to avoid copying old data in 'setNum'
  1713. UInt length=getUInt();
  1714. if( length&SIGN_BIT) // unicode
  1715. {
  1716. length^=SIGN_BIT; MIN(length, left()/SIZEI(Char));
  1717. if(length)
  1718. {
  1719. s.reserve(length);
  1720. getN(s._d.data(), length);
  1721. s._d[s._length=length]=0;
  1722. }
  1723. }else
  1724. {
  1725. MIN(length, left());
  1726. if (length)
  1727. {
  1728. s.reserve(length);
  1729. Memt<Char8> temp; temp.setNum(length); getN(temp.data(), length);
  1730. FREPA(temp)s._d[i]=Char8To16Fast(temp[i]); // we can assume that Str was already initialized
  1731. s._d[s._length=length]=0;
  1732. }
  1733. }
  1734. return T;
  1735. }
  1736. File& File::_getStr(Char *t, Int t_elms)
  1737. {
  1738. UInt length=getUInt();
  1739. if( length&SIGN_BIT) // unicode
  1740. {
  1741. length^=SIGN_BIT;
  1742. if(left()<length*SIZEI(Char))goto length_too_long;
  1743. if(t && t_elms>0)
  1744. {
  1745. Int read=Min(length, t_elms-1);
  1746. getN(t, read); t[read]=0;
  1747. length-=read;
  1748. }
  1749. length*=SIZE(Char);
  1750. }else
  1751. {
  1752. if(left()<length*SIZEI(Char8))goto length_too_long;
  1753. if(t && t_elms>0)
  1754. {
  1755. Int read=Min(length, t_elms-1);
  1756. Char8 *temp=(Char8*)t; getN(temp, read); // we can re-use the char array memory because it uses Char which has 2x Char8 capacity
  1757. t[read]=0; // because we're processing from the end, then start with the end too
  1758. REP(read)t[i]=Char8To16Fast(temp[i]); // need to process from the end to not overwrite the source, we can assume that Str was already initialized
  1759. length-=read;
  1760. }
  1761. }
  1762. skip(length);
  1763. if(ok())return T;
  1764. goto error;
  1765. length_too_long:
  1766. _ok=false; pos(size()); // if the length was too long then go at the end of file, in case the user will try to read more data after this call, this is important so that the partially available string data is not treated as something else
  1767. error:
  1768. if(t && t_elms>0)t[0]='\0'; return T;
  1769. }
  1770. Str8 File::_getStr8()
  1771. {
  1772. Str8 s;
  1773. UInt length=getUInt();
  1774. s._d.setNum( length+1);
  1775. getN(s._d.data(), length+1);
  1776. s._length = length ;
  1777. return s;
  1778. }
  1779. Str File::_getStr16()
  1780. {
  1781. Str s;
  1782. UInt length=getUInt();
  1783. s._d.setNum( length+1);
  1784. getN(s._d.data(), length+1);
  1785. s._length = length ;
  1786. return s;
  1787. }
  1788. File& File::_putAsset(CChar *t)
  1789. {
  1790. if(!Is(t))putByte(0);else {UID id; if(DecodeFileName(t, id))putByte(2)<<id;else putByte(1).putStr(t);}
  1791. return T;
  1792. }
  1793. Str File::_getAsset()
  1794. {
  1795. switch(getByte())
  1796. {
  1797. default: return S;
  1798. case 1: return _getStr2();
  1799. case 2: {UID id; T>>id; return _EncodeFileName(id);}
  1800. }
  1801. }
  1802. /******************************************************************************/
  1803. Short File::getBEShort () { Short i ; T>>i; SwapEndian(i); return i;}
  1804. UShort File::getBEUShort() {UShort i ; T>>i; SwapEndian(i); return i;}
  1805. Int File::getBEInt24 () {Int24 i ; T>>i; Swap(i.b[0], i.b[2]); return i.asInt();}
  1806. UInt File::getBEUInt24() {Byte b[3]; T>>b; return b[2] | (b[1]<<8) | (b[0]<<16);}
  1807. Int File::getBEInt () { Int i ; T>>i; SwapEndian(i); return i;}
  1808. UInt File::getBEUInt () {UInt i ; T>>i; SwapEndian(i); return i;}
  1809. Long File::getBELong () { Long i ; T>>i; SwapEndian(i); return i;}
  1810. ULong File::getBEULong () {ULong i ; T>>i; SwapEndian(i); return i;}
  1811. /******************************************************************************/
  1812. Bool File::equal(File &f, Long max_size)
  1813. {
  1814. if(max_size<0 || left()<max_size || f.left()<max_size){if(left()!=f.left())return false; max_size=left();} // if 'max_size' is not specified or any of the files has less than expected bytes, then continue only if both have same amount of bytes less, and test only those bytes
  1815. if(max_size>0)
  1816. {
  1817. Memt<Byte, TEMP_BUF_SIZE> temp; temp.setNum(TEMP_BUF_SIZE); Int buf_size=temp.elms()/2; Ptr buf=temp.data(), buf2=temp.data()+buf_size;
  1818. for(; max_size>0; )
  1819. {
  1820. Int l=Min(buf_size, max_size); max_size-=l;
  1821. if(!getFast (buf, l) || !f.getFast(buf2, l))return false;
  1822. if(!EqualMem(buf, buf2, l))return false;
  1823. }
  1824. }
  1825. return true;
  1826. }
  1827. Bool File::copy(File &dest, Long max_size)
  1828. {
  1829. if(max_size<0)max_size=left();
  1830. if(max_size>0)
  1831. {
  1832. Memt<Byte, TEMP_BUF_SIZE> temp; temp.setNum(TEMP_BUF_SIZE); Ptr buf=temp.data(); Int buf_size=temp.elms();
  1833. REP( max_size/buf_size )if(!getFast(buf, buf_size) || !dest.put(buf, buf_size))return false;
  1834. buf_size=max_size%buf_size; if(!getFast(buf, buf_size) || !dest.put(buf, buf_size))return false;
  1835. }
  1836. return true;
  1837. }
  1838. Bool File::copy(File &dest, DataCallback &callback, Long max_size)
  1839. {
  1840. if(max_size<0)max_size=left();
  1841. if(max_size>0)
  1842. {
  1843. Memt<Byte, TEMP_BUF_SIZE> temp; temp.setNum(TEMP_BUF_SIZE); Ptr buf=temp.data(); Int buf_size=temp.elms();
  1844. REP( max_size/buf_size ){if(!getFast(buf, buf_size) || !dest.put(buf, buf_size))return false; callback.data(buf, buf_size);}
  1845. buf_size=max_size%buf_size; if(!getFast(buf, buf_size) || !dest.put(buf, buf_size))return false; callback.data(buf, buf_size);
  1846. }
  1847. return true;
  1848. }
  1849. Bool File::copyEncrypt(File &dest, Cipher &cipher, Long max_size)
  1850. {
  1851. if(max_size<0)max_size=left();
  1852. if(max_size>0)
  1853. {
  1854. Memt<Byte, TEMP_BUF_SIZE> temp; temp.setNum(TEMP_BUF_SIZE); Ptr buf=temp.data(); Int buf_size=temp.elms(), offset=0;
  1855. REP( max_size/buf_size ){if(!getFast(buf, buf_size))return false; cipher.encrypt(buf, buf, buf_size, offset); if(!dest.put(buf, buf_size))return false; offset+=buf_size;}
  1856. buf_size=max_size%buf_size; if(!getFast(buf, buf_size))return false; cipher.encrypt(buf, buf, buf_size, offset); if(!dest.put(buf, buf_size))return false;
  1857. }
  1858. return true;
  1859. }
  1860. /******************************************************************************/
  1861. void File:: clearBuf() {_buf_pos=_buf_len=0;} // !! this does not reset the system file handle position, if the buffer read something, then the position is ahead !!
  1862. Bool File::discardBuf(Bool flush)
  1863. {
  1864. if(_buf_pos || _buf_len) // if there's any data in the buffer
  1865. {
  1866. Long pos=T.pos(); // remember current position before doing any operation
  1867. if(flush && !T.flush() && ALLOW_REFLUSH)_ok=false; // !! do this after remembering position because this method may change it !! if we had some data to save which failed, then only disable '_ok', but still proceed because here the priority is to set correct file position
  1868. T._pos=posFile(); // set actual position, so calling "T.pos(pos)" will proceed because current position is different than desired
  1869. clearBuf(); // !! do this after calling 'posFile' !! always clear buffer (in case read mode or in case write mode flush fail)
  1870. return T.pos(pos); // set remembered position
  1871. }
  1872. return true;
  1873. }
  1874. /******************************************************************************/
  1875. void File:: limit(ULong &total_size, ULong &applied_offset, Long new_size) {total_size=size(); applied_offset=pos(); T._size= new_size; T._offset+=applied_offset; T._cipher_offset+=applied_offset; T._pos-=applied_offset;}
  1876. void File::unlimit(ULong &total_size, ULong &applied_offset ) { T._size=total_size; T._offset-=applied_offset; T._cipher_offset-=applied_offset; T._pos+=applied_offset; applied_offset=0;}
  1877. /******************************************************************************/
  1878. UInt File::crc32(Long max_size)
  1879. {
  1880. Byte buf[TEMP_BUF_SIZE];
  1881. CRC32 hash;
  1882. if(max_size<0)max_size=left();
  1883. for(;;)
  1884. {
  1885. Int left=Min(SIZEI(buf), max_size); if(left<=0)break;
  1886. if(!getFast(buf, left))return 0;
  1887. hash.update(buf, left); max_size-=left;
  1888. }
  1889. return hash();
  1890. }
  1891. UInt File::xxHash32(Long max_size)
  1892. {
  1893. Byte buf[TEMP_BUF_SIZE];
  1894. ::xxHash32 hash;
  1895. if(max_size<0)max_size=left();
  1896. for(;;)
  1897. {
  1898. Int left=Min(SIZEI(buf), max_size); if(left<=0)break;
  1899. if(!getFast(buf, left))return 0;
  1900. hash.update(buf, left); max_size-=left;
  1901. }
  1902. return hash();
  1903. }
  1904. #pragma runtime_checks("", off)
  1905. UInt File::xxHash64_32(Long max_size) {return xxHash64(max_size);} // we're interested only in low 32 bits
  1906. #pragma runtime_checks("", restore)
  1907. ULong File::xxHash64 (Long max_size)
  1908. {
  1909. Byte buf[TEMP_BUF_SIZE];
  1910. ::xxHash64 hash;
  1911. if(max_size<0)max_size=left();
  1912. for(;;)
  1913. {
  1914. Int left=Min(SIZEI(buf), max_size); if(left<=0)break;
  1915. if(!getFast(buf, left))return 0;
  1916. hash.update(buf, left); max_size-=left;
  1917. }
  1918. return hash();
  1919. }
  1920. UInt File::spookyHash32 (Long max_size) {return spookyHash128(max_size).i[0];} // can use part of 128-bit because this is how 'SpookyHash' works
  1921. ULong File::spookyHash64 (Long max_size) {return spookyHash128(max_size).l[0];} // can use part of 128-bit because this is how 'SpookyHash' works
  1922. UID File::spookyHash128(Long max_size)
  1923. {
  1924. Byte buf[TEMP_BUF_SIZE];
  1925. SpookyHash hash;
  1926. if(max_size<0)max_size=left();
  1927. for(;;)
  1928. {
  1929. Int left=Min(SIZEI(buf), max_size); if(left<=0)break;
  1930. if(!getFast(buf, left))return UIDZero;
  1931. hash.update(buf, left); max_size-=left;
  1932. }
  1933. return hash.hash128();
  1934. }
  1935. ULong File::metroHash64(Long max_size)
  1936. {
  1937. Byte buf[TEMP_BUF_SIZE];
  1938. MetroHash64 hash;
  1939. if(max_size<0)max_size=left();
  1940. for(;;)
  1941. {
  1942. Int left=Min(SIZEI(buf), max_size); if(left<=0)break;
  1943. if(!getFast(buf, left))return 0;
  1944. hash.update(buf, left); max_size-=left;
  1945. }
  1946. return hash();
  1947. }
  1948. UID File::metroHash128(Long max_size)
  1949. {
  1950. Byte buf[TEMP_BUF_SIZE];
  1951. MetroHash128 hash;
  1952. if(max_size<0)max_size=left();
  1953. for(;;)
  1954. {
  1955. Int left=Min(SIZEI(buf), max_size); if(left<=0)break;
  1956. if(!getFast(buf, left))return UIDZero;
  1957. hash.update(buf, left); max_size-=left;
  1958. }
  1959. return hash();
  1960. }
  1961. UID File::md5(Long max_size)
  1962. {
  1963. Byte buf[TEMP_BUF_SIZE];
  1964. MD5 hash;
  1965. if(max_size<0)max_size=left();
  1966. for(;;)
  1967. {
  1968. Int left=Min(SIZEI(buf), max_size); if(left<=0)break;
  1969. if(!getFast(buf, left))return UIDZero;
  1970. hash.update(buf, left); max_size-=left;
  1971. }
  1972. return hash();
  1973. }
  1974. SHA1::Hash File::sha1(Long max_size)
  1975. {
  1976. Byte buf[TEMP_BUF_SIZE];
  1977. SHA1 hash;
  1978. if(max_size<0)max_size=left();
  1979. for(;;)
  1980. {
  1981. Int left=Min(SIZEI(buf), max_size); if(left<=0)break;
  1982. if(!getFast(buf, left)){hash._hash.zero(); return hash._hash;}
  1983. hash.update(buf, left); max_size-=left;
  1984. }
  1985. return hash();
  1986. }
  1987. SHA2::Hash File::sha2(Long max_size)
  1988. {
  1989. Byte buf[TEMP_BUF_SIZE];
  1990. SHA2 hash;
  1991. if(max_size<0)max_size=left();
  1992. for(;;)
  1993. {
  1994. Int left=Min(SIZEI(buf), max_size); if(left<=0)break;
  1995. if(!getFast(buf, left)){hash._hash.zero(); return hash._hash;}
  1996. hash.update(buf, left); max_size-=left;
  1997. }
  1998. return hash();
  1999. }
  2000. /******************************************************************************/
  2001. }
  2002. /******************************************************************************/