Bytes.hx 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707
  1. /*
  2. * Copyright (C)2005-2019 Haxe Foundation
  3. *
  4. * Permission is hereby granted, free of charge, to any person obtaining a
  5. * copy of this software and associated documentation files (the "Software"),
  6. * to deal in the Software without restriction, including without limitation
  7. * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  8. * and/or sell copies of the Software, and to permit persons to whom the
  9. * Software is 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
  19. * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  20. * DEALINGS IN THE SOFTWARE.
  21. */
  22. package haxe.io;
  23. #if cpp
  24. using cpp.NativeArray;
  25. #end
  26. class Bytes {
  27. public var length(default, null):Int;
  28. var b:BytesData;
  29. function new(length, b) {
  30. this.length = length;
  31. this.b = b;
  32. #if flash
  33. b.endian = flash.utils.Endian.LITTLE_ENDIAN;
  34. #end
  35. }
  36. /**
  37. Returns the byte at index `pos`.
  38. **/
  39. public inline function get(pos:Int):Int {
  40. #if neko
  41. return untyped $sget(b, pos);
  42. #elseif flash
  43. return b[pos];
  44. #elseif cpp
  45. return untyped b[pos];
  46. #elseif java
  47. return untyped b[pos] & 0xFF;
  48. #elseif python
  49. return python.Syntax.arrayAccess(b, pos);
  50. #else
  51. return b[pos];
  52. #end
  53. }
  54. /**
  55. Stores the given byte `v` at the given position `pos`.
  56. **/
  57. public inline function set(pos:Int, v:Int):Void {
  58. #if neko
  59. untyped $sset(b, pos, v);
  60. #elseif flash
  61. b[pos] = v;
  62. #elseif cpp
  63. untyped b[pos] = v;
  64. #elseif java
  65. b[pos] = cast v;
  66. #elseif cs
  67. b[pos] = cast v;
  68. #elseif python
  69. python.Syntax.arraySet(b, pos, v & 0xFF);
  70. #else
  71. b[pos] = v & 0xFF;
  72. #end
  73. }
  74. /**
  75. Copies `len` bytes from `src` into this instance.
  76. @param pos Zero-based location in `this` instance at which to start writing
  77. bytes.
  78. @param src Source `Bytes` instance from which to copy bytes.
  79. @param srcpos Zero-based location at `src` from which bytes will be copied.
  80. @param len Number of bytes to be copied.
  81. **/
  82. public function blit(pos:Int, src:Bytes, srcpos:Int, len:Int):Void {
  83. #if !neko
  84. if (pos < 0 || srcpos < 0 || len < 0 || pos + len > length || srcpos + len > src.length)
  85. throw Error.OutsideBounds;
  86. #end
  87. #if neko
  88. try
  89. untyped $sblit(b, pos, src.b, srcpos, len)
  90. catch (e:Dynamic)
  91. throw Error.OutsideBounds;
  92. #elseif flash
  93. b.position = pos;
  94. if (len > 0)
  95. b.writeBytes(src.b, srcpos, len);
  96. #elseif java
  97. java.lang.System.arraycopy(src.b, srcpos, b, pos, len);
  98. #elseif cs
  99. cs.system.Array.Copy(src.b, srcpos, b, pos, len);
  100. #elseif python
  101. python.Syntax.code("self.b[{0}:{0}+{1}] = src.b[srcpos:srcpos+{1}]", pos, len);
  102. #elseif cpp
  103. b.blit(pos, src.b, srcpos, len);
  104. #else
  105. var b1 = b;
  106. var b2 = src.b;
  107. if (b1 == b2 && pos > srcpos) {
  108. var i = len;
  109. while (i > 0) {
  110. i--;
  111. b1[i + pos] = b2[i + srcpos];
  112. }
  113. return;
  114. }
  115. for (i in 0...len)
  116. b1[i + pos] = b2[i + srcpos];
  117. #end
  118. }
  119. /**
  120. Sets `len` consecutive bytes starting from index `pos` of `this` instance
  121. to `value`.
  122. **/
  123. public function fill(pos:Int, len:Int, value:Int) {
  124. #if flash
  125. var v4 = value & 0xFF;
  126. v4 |= v4 << 8;
  127. v4 |= v4 << 16;
  128. b.position = pos;
  129. for (i in 0...len >> 2)
  130. b.writeUnsignedInt(v4);
  131. pos += len & ~3;
  132. for (i in 0...len & 3)
  133. set(pos++, value);
  134. #elseif cpp
  135. untyped __global__.__hxcpp_memory_memset(b, pos, len, value);
  136. #else
  137. for (i in 0...len)
  138. set(pos++, value);
  139. #end
  140. }
  141. /**
  142. Returns a new `Bytes` instance that contains a copy of `len` bytes of
  143. `this` instance, starting at index `pos`.
  144. **/
  145. public function sub(pos:Int, len:Int):Bytes {
  146. #if !neko
  147. if (pos < 0 || len < 0 || pos + len > length)
  148. throw Error.OutsideBounds;
  149. #end
  150. #if neko
  151. return try new Bytes(len, untyped __dollar__ssub(b, pos, len)) catch (e:Dynamic) throw Error.OutsideBounds;
  152. #elseif flash
  153. b.position = pos;
  154. var b2 = new flash.utils.ByteArray();
  155. b.readBytes(b2, 0, len);
  156. return new Bytes(len, b2);
  157. #elseif java
  158. var newarr = new java.NativeArray(len);
  159. java.lang.System.arraycopy(b, pos, newarr, 0, len);
  160. return new Bytes(len, newarr);
  161. #elseif cs
  162. var newarr = new cs.NativeArray(len);
  163. cs.system.Array.Copy(b, pos, newarr, 0, len);
  164. return new Bytes(len, newarr);
  165. #elseif python
  166. return new Bytes(len, python.Syntax.arrayAccess(b, pos, pos + len));
  167. #else
  168. return new Bytes(len, b.slice(pos, pos + len));
  169. #end
  170. }
  171. /**
  172. Returns `0` if the bytes of `this` instance and the bytes of `other` are
  173. identical.
  174. Returns a negative value if the `length` of `this` instance is less than
  175. the `length` of `other`, or a positive value if the `length` of `this`
  176. instance is greater than the `length` of `other`.
  177. In case of equal `length`s, returns a negative value if the first different
  178. value in `other` is greater than the corresponding value in `this`
  179. instance; otherwise returns a positive value.
  180. **/
  181. public function compare(other:Bytes):Int {
  182. #if neko
  183. return untyped __dollar__compare(b, other.b);
  184. #elseif flash
  185. var len = (length < other.length) ? length : other.length;
  186. var b1 = b;
  187. var b2 = other.b;
  188. b1.position = 0;
  189. b2.position = 0;
  190. b1.endian = flash.utils.Endian.BIG_ENDIAN;
  191. b2.endian = flash.utils.Endian.BIG_ENDIAN;
  192. for (i in 0...len >> 2)
  193. if (b1.readUnsignedInt() != b2.readUnsignedInt()) {
  194. b1.position -= 4;
  195. b2.position -= 4;
  196. var d = b1.readUnsignedInt() - b2.readUnsignedInt();
  197. b1.endian = flash.utils.Endian.LITTLE_ENDIAN;
  198. b2.endian = flash.utils.Endian.LITTLE_ENDIAN;
  199. return d;
  200. }
  201. for (i in 0...len & 3)
  202. if (b1.readUnsignedByte() != b2.readUnsignedByte()) {
  203. b1.endian = flash.utils.Endian.LITTLE_ENDIAN;
  204. b2.endian = flash.utils.Endian.LITTLE_ENDIAN;
  205. return b1[b1.position - 1] - b2[b2.position - 1];
  206. }
  207. b1.endian = flash.utils.Endian.LITTLE_ENDIAN;
  208. b2.endian = flash.utils.Endian.LITTLE_ENDIAN;
  209. return length - other.length;
  210. // #elseif cs
  211. // TODO: memcmp if unsafe flag is on
  212. #elseif cpp
  213. return b.memcmp(other.b);
  214. #else
  215. var b1 = b;
  216. var b2 = other.b;
  217. var len = (length < other.length) ? length : other.length;
  218. for (i in 0...len)
  219. if (b1[i] != b2[i])
  220. return untyped b1[i] - b2[i];
  221. return length - other.length;
  222. #end
  223. }
  224. /**
  225. Returns the IEEE double-precision value at the given position `pos` (in
  226. little-endian encoding). Result is unspecified if `pos` is outside the
  227. bounds.
  228. **/
  229. #if (neko_v21 || (cpp && !cppia) || flash)
  230. inline
  231. #end
  232. public function getDouble(pos:Int):Float {
  233. #if neko_v21
  234. return untyped $sgetd(b, pos, false);
  235. #elseif flash
  236. b.position = pos;
  237. return b.readDouble();
  238. #elseif cpp
  239. if (pos < 0 || pos + 8 > length)
  240. throw Error.OutsideBounds;
  241. return untyped __global__.__hxcpp_memory_get_double(b, pos);
  242. #else
  243. return FPHelper.i64ToDouble(getInt32(pos), getInt32(pos + 4));
  244. #end
  245. }
  246. /**
  247. Returns the IEEE single-precision value at the given position `pos` (in
  248. little-endian encoding). Result is unspecified if `pos` is outside the
  249. bounds.
  250. **/
  251. #if (neko_v21 || (cpp && !cppia) || flash)
  252. inline
  253. #end
  254. public function getFloat(pos:Int):Float {
  255. #if neko_v21
  256. return untyped $sgetf(b, pos, false);
  257. #elseif flash
  258. b.position = pos;
  259. return b.readFloat();
  260. #elseif cpp
  261. if (pos < 0 || pos + 4 > length)
  262. throw Error.OutsideBounds;
  263. return untyped __global__.__hxcpp_memory_get_float(b, pos);
  264. #else
  265. return FPHelper.i32ToFloat(getInt32(pos));
  266. #end
  267. }
  268. /**
  269. Stores the given IEEE double-precision value `v` at the given position
  270. `pos` in little-endian encoding. Result is unspecified if writing outside
  271. of bounds.
  272. **/
  273. #if (neko_v21 || flash)
  274. inline
  275. #end
  276. public function setDouble(pos:Int, v:Float):Void {
  277. #if neko_v21
  278. untyped $ssetd(b, pos, v, false);
  279. #elseif neko
  280. untyped $sblit(b, pos, FPHelper._double_bytes(v, false), 0, 8);
  281. #elseif flash
  282. b.position = pos;
  283. b.writeDouble(v);
  284. #elseif cpp
  285. if (pos < 0 || pos + 8 > length)
  286. throw Error.OutsideBounds;
  287. untyped __global__.__hxcpp_memory_set_double(b, pos, v);
  288. #else
  289. var i = FPHelper.doubleToI64(v);
  290. setInt32(pos, i.low);
  291. setInt32(pos + 4, i.high);
  292. #end
  293. }
  294. /**
  295. Stores the given IEEE single-precision value `v` at the given position
  296. `pos` in little-endian encoding. Result is unspecified if writing outside
  297. of bounds.
  298. **/
  299. #if (neko_v21 || flash)
  300. inline
  301. #end
  302. public function setFloat(pos:Int, v:Float):Void {
  303. #if neko_v21
  304. untyped $ssetf(b, pos, v, false);
  305. #elseif neko
  306. untyped $sblit(b, pos, FPHelper._float_bytes(v, false), 0, 4);
  307. #elseif flash
  308. b.position = pos;
  309. b.writeFloat(v);
  310. #elseif cpp
  311. if (pos < 0 || pos + 4 > length)
  312. throw Error.OutsideBounds;
  313. untyped __global__.__hxcpp_memory_set_float(b, pos, v);
  314. #else
  315. setInt32(pos, FPHelper.floatToI32(v));
  316. #end
  317. }
  318. /**
  319. Returns the 16-bit unsigned integer at the given position `pos` (in
  320. little-endian encoding).
  321. **/
  322. public inline function getUInt16(pos:Int):Int {
  323. #if neko_v21
  324. return untyped $sget16(b, pos, false);
  325. #else
  326. return get(pos) | (get(pos + 1) << 8);
  327. #end
  328. }
  329. /**
  330. Stores the given 16-bit unsigned integer `v` at the given position `pos`
  331. (in little-endian encoding).
  332. **/
  333. public inline function setUInt16(pos:Int, v:Int):Void {
  334. #if neko_v21
  335. untyped $sset16(b, pos, v, false);
  336. #else
  337. set(pos, v);
  338. set(pos + 1, v >> 8);
  339. #end
  340. }
  341. /**
  342. Returns the 32-bit integer at the given position `pos` (in little-endian
  343. encoding).
  344. **/
  345. public inline function getInt32(pos:Int):Int {
  346. #if neko_v21
  347. return untyped $sget32(b, pos, false);
  348. #elseif python
  349. var v = get(pos) | (get(pos + 1) << 8) | (get(pos + 2) << 16) | (get(pos + 3) << 24);
  350. return if (v & 0x80000000 != 0) v | 0x80000000 else v;
  351. #elseif lua
  352. var v = get(pos) | (get(pos + 1) << 8) | (get(pos + 2) << 16) | (get(pos + 3) << 24);
  353. return lua.Boot.clampInt32(if (v & 0x80000000 != 0) v | 0x80000000 else v);
  354. #else
  355. return get(pos) | (get(pos + 1) << 8) | (get(pos + 2) << 16) | (get(pos + 3) << 24);
  356. #end
  357. }
  358. /**
  359. Returns the 64-bit integer at the given position `pos` (in little-endian
  360. encoding).
  361. **/
  362. public inline function getInt64(pos:Int):haxe.Int64 {
  363. return haxe.Int64.make(getInt32(pos + 4), getInt32(pos));
  364. }
  365. /**
  366. Stores the given 32-bit integer `v` at the given position `pos` (in
  367. little-endian encoding).
  368. **/
  369. public inline function setInt32(pos:Int, v:Int):Void {
  370. #if neko_v21
  371. untyped $sset32(b, pos, v, false);
  372. #else
  373. set(pos, v);
  374. set(pos + 1, v >> 8);
  375. set(pos + 2, v >> 16);
  376. set(pos + 3, v >>> 24);
  377. #end
  378. }
  379. /**
  380. Stores the given 64-bit integer `v` at the given position `pos` (in
  381. little-endian encoding).
  382. **/
  383. public inline function setInt64(pos:Int, v:haxe.Int64):Void {
  384. setInt32(pos, v.low);
  385. setInt32(pos + 4, v.high);
  386. }
  387. /**
  388. Returns the `len`-bytes long string stored at the given position `pos`,
  389. interpreted with the given `encoding` (UTF-8 by default).
  390. **/
  391. public function getString(pos:Int, len:Int, ?encoding:Encoding):String {
  392. if (encoding == null)
  393. encoding == UTF8;
  394. #if !neko
  395. if (pos < 0 || len < 0 || pos + len > length)
  396. throw Error.OutsideBounds;
  397. #end
  398. #if neko
  399. return try new String(untyped __dollar__ssub(b, pos, len)) catch (e:Dynamic) throw Error.OutsideBounds;
  400. #elseif flash
  401. b.position = pos;
  402. return encoding == RawNative ? b.readMultiByte(len, "unicode") : b.readUTFBytes(len);
  403. #elseif cpp
  404. var result:String = "";
  405. untyped __global__.__hxcpp_string_of_bytes(b, result, pos, len);
  406. return result;
  407. #elseif cs
  408. switch (encoding) {
  409. case UTF8 | null:
  410. return cs.system.text.Encoding.UTF8.GetString(b, pos, len);
  411. case RawNative:
  412. return cs.system.text.Encoding.Unicode.GetString(b, pos, len);
  413. }
  414. #elseif java
  415. try {
  416. switch (encoding) {
  417. case UTF8 | null:
  418. return new String(b, pos, len, "UTF-8");
  419. case RawNative:
  420. return new String(b, pos, len, "UTF-16LE");
  421. }
  422. } catch (e:Dynamic) {
  423. throw e;
  424. }
  425. #elseif python
  426. return python.Syntax.code("self.b[{0}:{0}+{1}].decode('UTF-8','replace')", pos, len);
  427. #elseif lua
  428. if (b.length - pos <= lua.Boot.MAXSTACKSIZE) {
  429. var end:Int = cast Math.min(b.length, pos + len) - 1;
  430. return lua.NativeStringTools.char(lua.TableTools.unpack(untyped b, pos, end));
  431. } else {
  432. var tbl:lua.Table<Int, String> = lua.Table.create();
  433. for (idx in pos...pos + len) {
  434. lua.Table.insert(tbl, lua.NativeStringTools.char(b[idx]));
  435. }
  436. return lua.Table.concat(tbl, '');
  437. }
  438. #else
  439. var s = "";
  440. var b = b;
  441. var fcc = String.fromCharCode;
  442. var i = pos;
  443. var max = pos + len;
  444. // utf8-decode and utf16-encode
  445. while (i < max) {
  446. var c = b[i++];
  447. if (c < 0x80) {
  448. if (c == 0)
  449. break;
  450. s += fcc(c);
  451. } else if (c < 0xE0)
  452. s += fcc(((c & 0x3F) << 6) | (b[i++] & 0x7F));
  453. else if (c < 0xF0) {
  454. var c2 = b[i++];
  455. s += fcc(((c & 0x1F) << 12) | ((c2 & 0x7F) << 6) | (b[i++] & 0x7F));
  456. } else {
  457. var c2 = b[i++];
  458. var c3 = b[i++];
  459. var u = ((c & 0x0F) << 18) | ((c2 & 0x7F) << 12) | ((c3 & 0x7F) << 6) | (b[i++] & 0x7F);
  460. // surrogate pair
  461. s += fcc((u >> 10) + 0xD7C0);
  462. s += fcc((u & 0x3FF) | 0xDC00);
  463. }
  464. }
  465. return s;
  466. #end
  467. }
  468. @:deprecated("readString is deprecated, use getString instead")
  469. @:noCompletion
  470. public inline function readString(pos:Int, len:Int):String {
  471. return getString(pos, len);
  472. }
  473. /**
  474. Returns a `String` representation of the bytes interpreted as UTF-8.
  475. **/
  476. public function toString():String {
  477. #if neko
  478. return new String(untyped __dollar__ssub(b, 0, length));
  479. #elseif flash
  480. b.position = 0;
  481. return b.toString();
  482. #elseif cs
  483. return cs.system.text.Encoding.UTF8.GetString(b, 0, length);
  484. #elseif java
  485. try {
  486. return new String(b, 0, length, "UTF-8");
  487. } catch (e:Dynamic)
  488. throw e;
  489. #else
  490. return getString(0, length);
  491. #end
  492. }
  493. /**
  494. Returns a hexadecimal `String` representation of the bytes of `this`
  495. instance.
  496. **/
  497. public function toHex():String {
  498. var s = new StringBuf();
  499. var chars = [];
  500. var str = "0123456789abcdef";
  501. for (i in 0...str.length)
  502. chars.push(str.charCodeAt(i));
  503. for (i in 0...length) {
  504. var c = get(i);
  505. s.addChar(chars[c >> 4]);
  506. s.addChar(chars[c & 15]);
  507. }
  508. return s.toString();
  509. }
  510. /**
  511. Returns the bytes of `this` instance as `BytesData`.
  512. **/
  513. public inline function getData():BytesData {
  514. return b;
  515. }
  516. /**
  517. Returns a new `Bytes` instance with the given `length`. The values of the
  518. bytes are not initialized and may not be zero.
  519. **/
  520. public static function alloc(length:Int):Bytes {
  521. #if neko
  522. return new Bytes(length, untyped __dollar__smake(length));
  523. #elseif flash
  524. var b = new flash.utils.ByteArray();
  525. b.length = length;
  526. return new Bytes(length, b);
  527. #elseif cpp
  528. var a = new BytesData();
  529. if (length > 0)
  530. cpp.NativeArray.setSize(a, length);
  531. return new Bytes(length, a);
  532. #elseif cs
  533. return new Bytes(length, new cs.NativeArray(length));
  534. #elseif java
  535. return new Bytes(length, new java.NativeArray(length));
  536. #elseif python
  537. return new Bytes(length, new python.Bytearray(length));
  538. #else
  539. var a = new Array();
  540. for (i in 0...length)
  541. a.push(0);
  542. return new Bytes(length, a);
  543. #end
  544. }
  545. /**
  546. Returns the `Bytes` representation of the given `String`, using the
  547. specified encoding (UTF-8 by default).
  548. **/
  549. @:pure
  550. public static function ofString(s:String, ?encoding:Encoding):Bytes {
  551. #if neko
  552. return new Bytes(s.length, untyped __dollar__ssub(s.__s, 0, s.length));
  553. #elseif flash
  554. var b = new flash.utils.ByteArray();
  555. if (encoding == RawNative)
  556. b.writeMultiByte(s, "unicode")
  557. else
  558. b.writeUTFBytes(s);
  559. return new Bytes(b.length, b);
  560. #elseif cpp
  561. var a = new BytesData();
  562. untyped __global__.__hxcpp_bytes_of_string(a, s);
  563. return new Bytes(a.length, a);
  564. #elseif cs
  565. var b = switch (encoding) {
  566. case UTF8 | null:
  567. cs.system.text.Encoding.UTF8.GetBytes(s);
  568. case RawNative:
  569. cs.system.text.Encoding.Unicode.GetBytes(s);
  570. };
  571. return new Bytes(b.Length, b);
  572. #elseif java
  573. try {
  574. var b:BytesData = switch (encoding) {
  575. case UTF8 | null:
  576. @:privateAccess s.getBytes("UTF-8");
  577. case RawNative:
  578. @:privateAccess s.getBytes("UTF-16LE");
  579. };
  580. return new Bytes(b.length, b);
  581. } catch (e:Dynamic) {
  582. throw e;
  583. }
  584. #elseif python
  585. var b:BytesData = new python.Bytearray(s, "UTF-8");
  586. return new Bytes(b.length, b);
  587. #elseif lua
  588. var bytes = [
  589. for (i in 0...lua.NativeStringTools.len(s)) {
  590. lua.NativeStringTools.byte(s, i + 1);
  591. }
  592. ];
  593. return new Bytes(bytes.length, bytes);
  594. #else
  595. var a = new Array();
  596. // utf16-decode and utf8-encode
  597. var i = 0;
  598. while (i < s.length) {
  599. var c:Int = StringTools.fastCodeAt(s, i++);
  600. // surrogate pair
  601. if (0xD800 <= c && c <= 0xDBFF)
  602. c = (c - 0xD7C0 << 10) | (StringTools.fastCodeAt(s, i++) & 0x3FF);
  603. if (c <= 0x7F)
  604. a.push(c);
  605. else if (c <= 0x7FF) {
  606. a.push(0xC0 | (c >> 6));
  607. a.push(0x80 | (c & 63));
  608. } else if (c <= 0xFFFF) {
  609. a.push(0xE0 | (c >> 12));
  610. a.push(0x80 | ((c >> 6) & 63));
  611. a.push(0x80 | (c & 63));
  612. } else {
  613. a.push(0xF0 | (c >> 18));
  614. a.push(0x80 | ((c >> 12) & 63));
  615. a.push(0x80 | ((c >> 6) & 63));
  616. a.push(0x80 | (c & 63));
  617. }
  618. }
  619. return new Bytes(a.length, a);
  620. #end
  621. }
  622. /**
  623. Returns the `Bytes` representation of the given `BytesData`.
  624. **/
  625. public static function ofData(b:BytesData) {
  626. #if flash
  627. return new Bytes(b.length, b);
  628. #elseif neko
  629. return new Bytes(untyped __dollar__ssize(b), b);
  630. #elseif cs
  631. return new Bytes(b.Length, b);
  632. #else
  633. return new Bytes(b.length, b);
  634. #end
  635. }
  636. /**
  637. Converts the given hexadecimal `String` to `Bytes`. `s` must be a string of
  638. even length consisting only of hexadecimal digits. For example:
  639. `"0FDA14058916052309"`.
  640. **/
  641. public static function ofHex(s:String):Bytes {
  642. var len:Int = s.length;
  643. if ((len & 1) != 0)
  644. throw "Not a hex string (odd number of digits)";
  645. var ret:Bytes = Bytes.alloc(len >> 1);
  646. for (i in 0...ret.length) {
  647. var high = StringTools.fastCodeAt(s, i * 2);
  648. var low = StringTools.fastCodeAt(s, i * 2 + 1);
  649. high = (high & 0xF) + ((high & 0x40) >> 6) * 9;
  650. low = (low & 0xF) + ((low & 0x40) >> 6) * 9;
  651. ret.set(i, ((high << 4) | low) & 0xFF);
  652. }
  653. return ret;
  654. }
  655. /**
  656. Reads the `pos`-th byte of the given `b` bytes, in the most efficient way
  657. possible. Behavior when reading outside of the available data is
  658. unspecified.
  659. **/
  660. public inline static function fastGet(b:BytesData, pos:Int):Int {
  661. #if neko
  662. return untyped __dollar__sget(b, pos);
  663. #elseif flash
  664. return b[pos];
  665. #elseif cpp
  666. return untyped b.unsafeGet(pos);
  667. #elseif java
  668. return untyped b[pos] & 0xFF;
  669. #else
  670. return b[pos];
  671. #end
  672. }
  673. }