PageRenderTime 29ms CodeModel.GetById 21ms RepoModel.GetById 0ms app.codeStats 0ms

/projects/jruby-1.7.3/src/org/jruby/util/ConvertBytes.java

https://gitlab.com/essere.lab.public/qualitas.class-corpus
Java | 685 lines | 566 code | 88 blank | 31 comment | 164 complexity | 6a354d9d13f86db9761b4b173fb9954f MD5 | raw file
  1. package org.jruby.util;
  2. import java.math.BigInteger;
  3. import java.util.Arrays;
  4. import org.jruby.Ruby;
  5. import org.jruby.RubyBignum;
  6. import org.jruby.RubyInteger;
  7. import org.jruby.RubyString;
  8. import org.jruby.runtime.builtin.IRubyObject;
  9. public class ConvertBytes {
  10. private final Ruby runtime;
  11. private final ByteList _str;
  12. private int str;
  13. private int end;
  14. private byte[] data;
  15. private int base;
  16. private final boolean badcheck;
  17. private final boolean is19;
  18. public ConvertBytes(Ruby runtime, ByteList _str, int base, boolean badcheck) {
  19. this(runtime, _str, base, badcheck, false);
  20. }
  21. public ConvertBytes(Ruby runtime, ByteList _str, int base, boolean badcheck, boolean is19) {
  22. this.runtime = runtime;
  23. this._str = _str;
  24. this.str = _str.getBegin();
  25. this.data = _str.getUnsafeBytes();
  26. this.end = str + _str.getRealSize();
  27. this.badcheck = badcheck;
  28. this.base = base;
  29. this.is19 = is19;
  30. }
  31. public static final byte[] intToBinaryBytes(int i) {
  32. return intToUnsignedByteList(i, 1, LOWER_DIGITS).bytes();
  33. }
  34. public static final byte[] intToOctalBytes(int i) {
  35. return intToUnsignedByteList(i, 3, LOWER_DIGITS).bytes();
  36. }
  37. public static final byte[] intToHexBytes(int i) {
  38. return intToUnsignedByteList(i, 4, LOWER_DIGITS).bytes();
  39. }
  40. public static final byte[] intToHexBytes(int i, boolean upper) {
  41. return intToUnsignedByteList(i, 4, upper ? UPPER_DIGITS : LOWER_DIGITS).bytes();
  42. }
  43. public static final ByteList intToBinaryByteList(int i) {
  44. return new ByteList(intToBinaryBytes(i));
  45. }
  46. public static final ByteList intToOctalByteList(int i) {
  47. return new ByteList(intToOctalBytes(i));
  48. }
  49. public static final ByteList intToHexByteList(int i) {
  50. return new ByteList(intToHexBytes(i));
  51. }
  52. public static final ByteList intToHexByteList(int i, boolean upper) {
  53. return new ByteList(intToHexBytes(i, upper));
  54. }
  55. public static final byte[] intToByteArray(int i, int radix, boolean upper) {
  56. return longToByteArray(i, radix, upper);
  57. }
  58. public static final byte[] intToCharBytes(int i) {
  59. return longToByteList(i, 10, LOWER_DIGITS).bytes();
  60. }
  61. public static final byte[] longToBinaryBytes(long i) {
  62. return longToUnsignedByteList(i, 1, LOWER_DIGITS).bytes();
  63. }
  64. public static final byte[] longToOctalBytes(long i) {
  65. return longToUnsignedByteList(i, 3, LOWER_DIGITS).bytes();
  66. }
  67. public static final byte[] longToHexBytes(long i) {
  68. return longToUnsignedByteList(i, 4, LOWER_DIGITS).bytes();
  69. }
  70. public static final byte[] longToHexBytes(long i, boolean upper) {
  71. return longToUnsignedByteList(i, 4, upper ? UPPER_DIGITS : LOWER_DIGITS).bytes();
  72. }
  73. public static final ByteList longToBinaryByteList(long i) {
  74. return longToByteList(i, 2, LOWER_DIGITS);
  75. }
  76. public static final ByteList longToOctalByteList(long i) {
  77. return longToByteList(i, 8, LOWER_DIGITS);
  78. }
  79. public static final ByteList longToHexByteList(long i) {
  80. return longToByteList(i, 16, LOWER_DIGITS);
  81. }
  82. public static final ByteList longToHexByteList(long i, boolean upper) {
  83. return longToByteList(i, 16, upper ? UPPER_DIGITS : LOWER_DIGITS);
  84. }
  85. public static final byte[] longToByteArray(long i, int radix, boolean upper) {
  86. return longToByteList(i, radix, upper ? UPPER_DIGITS : LOWER_DIGITS).bytes();
  87. }
  88. public static final byte[] longToCharBytes(long i) {
  89. return longToByteList(i, 10, LOWER_DIGITS).bytes();
  90. }
  91. public static final ByteList longToByteList(long i) {
  92. return longToByteList(i, 10, LOWER_DIGITS);
  93. }
  94. public static final ByteList longToByteList(long i, int radix) {
  95. return longToByteList(i, radix, LOWER_DIGITS);
  96. }
  97. public static final ByteList longToByteList(long i, int radix, byte[] digitmap) {
  98. if (i == 0) return new ByteList(ZERO_BYTES);
  99. if (i == Long.MIN_VALUE) return new ByteList(MIN_VALUE_BYTES[radix]);
  100. boolean neg = false;
  101. if (i < 0) {
  102. i = -i;
  103. neg = true;
  104. }
  105. // max 64 chars for 64-bit 2's complement integer
  106. int len = 64;
  107. byte[] buf = new byte[len];
  108. int pos = len;
  109. do {
  110. buf[--pos] = digitmap[(int)(i % radix)];
  111. } while ((i /= radix) > 0);
  112. if (neg) buf[--pos] = (byte)'-';
  113. return new ByteList(buf, pos, len - pos, false);
  114. }
  115. private static final ByteList intToUnsignedByteList(int i, int shift, byte[] digitmap) {
  116. byte[] buf = new byte[32];
  117. int charPos = 32;
  118. int radix = 1 << shift;
  119. long mask = radix - 1;
  120. do {
  121. buf[--charPos] = digitmap[(int)(i & mask)];
  122. i >>>= shift;
  123. } while (i != 0);
  124. return new ByteList(buf, charPos, (32 - charPos), false);
  125. }
  126. private static final ByteList longToUnsignedByteList(long i, int shift, byte[] digitmap) {
  127. byte[] buf = new byte[64];
  128. int charPos = 64;
  129. int radix = 1 << shift;
  130. long mask = radix - 1;
  131. do {
  132. buf[--charPos] = digitmap[(int)(i & mask)];
  133. i >>>= shift;
  134. } while (i != 0);
  135. return new ByteList(buf, charPos, (64 - charPos), false);
  136. }
  137. public static final byte[] twosComplementToBinaryBytes(byte[] in) {
  138. return twosComplementToUnsignedBytes(in, 1, false);
  139. }
  140. public static final byte[] twosComplementToOctalBytes(byte[] in) {
  141. return twosComplementToUnsignedBytes(in, 3, false);
  142. }
  143. public static final byte[] twosComplementToHexBytes(byte[] in, boolean upper) {
  144. return twosComplementToUnsignedBytes(in, 4, upper);
  145. }
  146. private static final byte[] ZERO_BYTES = new byte[] {(byte)'0'};
  147. private static final byte[][] MIN_VALUE_BYTES;
  148. static {
  149. MIN_VALUE_BYTES = new byte[37][];
  150. for (int i = 2; i <= 36; i++) {
  151. MIN_VALUE_BYTES[i] = ByteList.plain(Long.toString(Long.MIN_VALUE, i));
  152. }
  153. }
  154. private static final byte[] LOWER_DIGITS = {
  155. '0' , '1' , '2' , '3' , '4' , '5' ,
  156. '6' , '7' , '8' , '9' , 'a' , 'b' ,
  157. 'c' , 'd' , 'e' , 'f' , 'g' , 'h' ,
  158. 'i' , 'j' , 'k' , 'l' , 'm' , 'n' ,
  159. 'o' , 'p' , 'q' , 'r' , 's' , 't' ,
  160. 'u' , 'v' , 'w' , 'x' , 'y' , 'z'
  161. };
  162. private static final byte[] UPPER_DIGITS = {
  163. '0' , '1' , '2' , '3' , '4' , '5' ,
  164. '6' , '7' , '8' , '9' , 'A' , 'B' ,
  165. 'C' , 'D' , 'E' , 'F' , 'G' , 'H' ,
  166. 'I' , 'J' , 'K' , 'L' , 'M' , 'N' ,
  167. 'O' , 'P' , 'Q' , 'R' , 'S' , 'T' ,
  168. 'U' , 'V' , 'W' , 'X' , 'Y' , 'Z'
  169. };
  170. public static final byte[] twosComplementToUnsignedBytes(byte[] in, int shift, boolean upper) {
  171. if (shift < 1 || shift > 4) {
  172. throw new IllegalArgumentException("shift value must be 1-4");
  173. }
  174. int ilen = in.length;
  175. int olen = (ilen * 8 + shift - 1 ) / shift;
  176. byte[] out = new byte[olen];
  177. int mask = (1 << shift) - 1;
  178. byte[] digits = upper ? UPPER_DIGITS : LOWER_DIGITS;
  179. int bitbuf = 0;
  180. int bitcnt = 0;
  181. for(int i = ilen, o = olen; --o >= 0; ) {
  182. if(bitcnt < shift) {
  183. bitbuf |= ((int)in[--i] & (int)0xff) << bitcnt;
  184. bitcnt += 8;
  185. }
  186. out[o] = digits[bitbuf & mask];
  187. bitbuf >>= shift;
  188. bitcnt -= shift;
  189. }
  190. return out;
  191. }
  192. /** rb_cstr_to_inum
  193. *
  194. */
  195. public static RubyInteger byteListToInum(Ruby runtime, ByteList str, int base, boolean badcheck) {
  196. return new ConvertBytes(runtime, str, base, badcheck).byteListToInum();
  197. }
  198. public static RubyInteger byteListToInum19(Ruby runtime, ByteList str, int base, boolean badcheck) {
  199. return new ConvertBytes(runtime, str, base, badcheck, true).byteListToInum();
  200. }
  201. private final static byte[] conv_digit = new byte[128];
  202. private final static boolean[] digit = new boolean[128];
  203. private final static boolean[] space = new boolean[128];
  204. private final static boolean[] spaceOrUnderscore = new boolean[128];
  205. static {
  206. Arrays.fill(conv_digit, (byte)-1);
  207. Arrays.fill(digit, false);
  208. for(char c = '0'; c <= '9'; c++) {
  209. conv_digit[c] = (byte)(c - '0');
  210. digit[c] = true;
  211. }
  212. for(char c = 'a'; c <= 'z'; c++) {
  213. conv_digit[c] = (byte)(c - 'a' + 10);
  214. }
  215. for(char c = 'A'; c <= 'Z'; c++) {
  216. conv_digit[c] = (byte)(c - 'A' + 10);
  217. }
  218. Arrays.fill(space, false);
  219. space['\t'] = true;
  220. space['\n'] = true;
  221. space[11] = true; // \v
  222. space['\f'] = true;
  223. space['\r'] = true;
  224. space[' '] = true;
  225. Arrays.fill(spaceOrUnderscore, false);
  226. spaceOrUnderscore['\t'] = true;
  227. spaceOrUnderscore['\n'] = true;
  228. spaceOrUnderscore[11] = true; // \v
  229. spaceOrUnderscore['\f'] = true;
  230. spaceOrUnderscore['\r'] = true;
  231. spaceOrUnderscore[' '] = true;
  232. spaceOrUnderscore['_'] = true;
  233. }
  234. /** conv_digit
  235. *
  236. */
  237. private byte convertDigit(byte c) {
  238. if(c < 0) {
  239. return -1;
  240. }
  241. return conv_digit[c];
  242. }
  243. /** ISSPACE
  244. *
  245. */
  246. private boolean isSpace(int str) {
  247. byte c;
  248. if(str == end || (c = data[str]) < 0) {
  249. return false;
  250. }
  251. return space[c];
  252. }
  253. /** ISDIGIT
  254. *
  255. */
  256. private boolean isDigit(byte[] buf, int str) {
  257. byte c;
  258. if(str == buf.length || (c = buf[str]) < 0) {
  259. return false;
  260. }
  261. return digit[c];
  262. }
  263. /** ISSPACE || *str == '_'
  264. *
  265. */
  266. private boolean isSpaceOrUnderscore(int str) {
  267. byte c;
  268. if(str == end || (c = data[str]) < 0) {
  269. return false;
  270. }
  271. return spaceOrUnderscore[c];
  272. }
  273. private boolean getSign() {
  274. //System.err.println("getSign()");
  275. boolean sign = true;
  276. if(str < end) {
  277. if(data[str] == '+') {
  278. str++;
  279. } else if(data[str] == '-') {
  280. str++;
  281. sign = false;
  282. }
  283. }
  284. //System.err.println(" getSign/" + sign);
  285. return sign;
  286. }
  287. private void ignoreLeadingWhitespace() {
  288. if(badcheck || is19) {
  289. while(isSpace(str)) {
  290. str++;
  291. }
  292. } else {
  293. while(isSpaceOrUnderscore(str)) {
  294. str++;
  295. }
  296. }
  297. }
  298. private void figureOutBase() {
  299. //System.err.println("figureOutBase()/base=" + base);
  300. if(base <= 0) {
  301. if(str < end && data[str] == '0') {
  302. if(str + 1 < end) {
  303. switch(data[str+1]) {
  304. case 'x':
  305. case 'X':
  306. base = 16;
  307. break;
  308. case 'b':
  309. case 'B':
  310. base = 2;
  311. break;
  312. case 'o':
  313. case 'O':
  314. base = 8;
  315. break;
  316. case 'd':
  317. case 'D':
  318. base = 10;
  319. break;
  320. default:
  321. base = 8;
  322. }
  323. } else {
  324. base = 8;
  325. }
  326. } else if(base < -1) {
  327. base = -base;
  328. } else {
  329. base = 10;
  330. }
  331. }
  332. //System.err.println(" figureOutBase/base=" + base);
  333. }
  334. private int calculateLength() {
  335. int len = 0;
  336. byte second = ((str+1 < end) && data[str] == '0') ? data[str+1] : (byte)0;
  337. //System.err.println("calculateLength()/str=" + str);
  338. switch(base) {
  339. case 2:
  340. len = 1;
  341. if(second == 'b' || second == 'B') {
  342. str+=2;
  343. }
  344. break;
  345. case 3:
  346. len = 2;
  347. break;
  348. case 8:
  349. if(second == 'o' || second == 'O') {
  350. str+=2;
  351. }
  352. case 4: case 5: case 6: case 7:
  353. len = 3;
  354. break;
  355. case 10:
  356. if(second == 'd' || second == 'D') {
  357. str+=2;
  358. }
  359. case 9: case 11: case 12:
  360. case 13: case 14: case 15:
  361. len = 4;
  362. break;
  363. case 16:
  364. len = 4;
  365. if(second == 'x' || second == 'X') {
  366. str+=2;
  367. }
  368. break;
  369. default:
  370. if(base < 2 || 36 < base) {
  371. throw runtime.newArgumentError("illegal radix " + base);
  372. }
  373. if(base <= 32) {
  374. len = 5;
  375. } else {
  376. len = 6;
  377. }
  378. break;
  379. }
  380. //System.err.println(" calculateLength()/str=" + str);
  381. return len;
  382. }
  383. private void squeezeZeroes() {
  384. byte c;
  385. if(str < end && data[str] == '0') {
  386. str++;
  387. int us = 0;
  388. while((str < end) && ((c = data[str]) == '0' || c == '_')) {
  389. if(c == '_') {
  390. if(++us >= 2) {
  391. break;
  392. }
  393. } else {
  394. us += 0;
  395. }
  396. str++;
  397. }
  398. if(str == end || isSpace(str)) {
  399. str--;
  400. }
  401. }
  402. }
  403. private long stringToLong(int nptr, int[] endptr, int base) {
  404. //System.err.println("stringToLong(" + nptr + ", " + base + ")");
  405. if(base < 0 || base == 1 || base > 36) {
  406. return 0;
  407. }
  408. int save = nptr;
  409. int s = nptr;
  410. boolean overflow = false;
  411. while(isSpace(s)) {
  412. s++;
  413. }
  414. if(s != end) {
  415. boolean negative = false;
  416. if(data[s] == '-') {
  417. negative = true;
  418. s++;
  419. } else if(data[s] == '+') {
  420. negative = false;
  421. s++;
  422. }
  423. save = s;
  424. byte c;
  425. long i = 0;
  426. final long cutoff = Long.MAX_VALUE / (long)base;
  427. final long cutlim = Long.MAX_VALUE % (long)base;
  428. while(s < end) {
  429. //System.err.println(" stringToLong/reading c=" + data[s]);
  430. c = convertDigit(data[s]);
  431. //System.err.println(" stringToLong/converted c=" + c);
  432. if(c == -1 || c >= base) {
  433. break;
  434. }
  435. s++;
  436. if(i > cutoff || (i == cutoff && c > cutlim)) {
  437. overflow = true;
  438. } else {
  439. i *= base;
  440. i += c;
  441. }
  442. }
  443. if(s != save) {
  444. if(endptr != null) {
  445. endptr[0] = s;
  446. }
  447. if(overflow) {
  448. throw new ERange(negative ? ERange.Kind.Underflow : ERange.Kind.Overflow);
  449. }
  450. if(negative) {
  451. return -i;
  452. } else {
  453. return i;
  454. }
  455. }
  456. }
  457. if(endptr != null) {
  458. if(save - nptr >= 2 && (data[save-1] == 'x' || data[save-1] == 'X') && data[save-2] == '0') {
  459. endptr[0] = save-1;
  460. } else {
  461. endptr[0] = nptr;
  462. }
  463. }
  464. return 0;
  465. }
  466. public RubyInteger byteListToInum() {
  467. if(_str == null) {
  468. if(badcheck) {
  469. invalidString("Integer");
  470. }
  471. return runtime.newFixnum(0);
  472. }
  473. ignoreLeadingWhitespace();
  474. boolean sign = getSign();
  475. if(str < end) {
  476. if(data[str] == '+' || data[str] == '-') {
  477. if(badcheck) {
  478. invalidString("Integer");
  479. }
  480. return runtime.newFixnum(0);
  481. }
  482. }
  483. figureOutBase();
  484. int len = calculateLength();
  485. squeezeZeroes();
  486. byte c = 0;
  487. if(str < end) {
  488. c = data[str];
  489. }
  490. c = convertDigit(c);
  491. if(c < 0 || c >= base) {
  492. if(badcheck) {
  493. invalidString("Integer");
  494. }
  495. return runtime.newFixnum(0);
  496. }
  497. len *= (end-str);
  498. //System.err.println(" main/len=" + len);
  499. if(len < Long.SIZE-1) {
  500. int[] endPlace = new int[]{str};
  501. long val = stringToLong(str, endPlace, base);
  502. //System.err.println(" stringToLong=" + val);
  503. if(endPlace[0] < end && data[endPlace[0]] == '_') {
  504. return bigParse(len, sign);
  505. }
  506. if(badcheck) {
  507. if(endPlace[0] == str) {
  508. invalidString("Integer"); // no number
  509. }
  510. while(isSpace(endPlace[0])) {
  511. endPlace[0]++;
  512. }
  513. if(endPlace[0] < end) {
  514. invalidString("Integer"); // trailing garbage
  515. }
  516. }
  517. if(sign) {
  518. return runtime.newFixnum(val);
  519. } else {
  520. return runtime.newFixnum(-val);
  521. }
  522. }
  523. return bigParse(len, sign);
  524. }
  525. private RubyInteger bigParse(int len, boolean sign) {
  526. if(badcheck && str < end && data[str] == '_') {
  527. invalidString("Integer");
  528. }
  529. char[] result = new char[end-str];
  530. int resultIndex = 0;
  531. byte nondigit = -1;
  532. while(str < end) {
  533. byte c = data[str++];
  534. byte cx = c;
  535. if(c == '_') {
  536. if(nondigit != -1) {
  537. if(badcheck) {
  538. invalidString("Integer");
  539. }
  540. break;
  541. }
  542. nondigit = c;
  543. continue;
  544. } else if((c = convertDigit(c)) < 0) {
  545. break;
  546. }
  547. if(c >= base) {
  548. break;
  549. }
  550. nondigit = -1;
  551. //System.err.println("ADDING CHAR: " + (char)cx + " with number: " + cx);
  552. result[resultIndex++] = (char)cx;
  553. }
  554. BigInteger z;
  555. if(resultIndex == 0) {
  556. z = BigInteger.ZERO;
  557. } else {
  558. z = new BigInteger(new String(result, 0, resultIndex), base);
  559. }
  560. if(!sign) {
  561. z = z.negate();
  562. }
  563. if(badcheck) {
  564. if(_str.getBegin() + 1 < str && data[str-1] == '_') {
  565. invalidString("Integer");
  566. }
  567. while(str < end && isSpace(str)) {
  568. str++;
  569. }
  570. if(str < end) {
  571. invalidString("Integer");
  572. }
  573. }
  574. return RubyBignum.bignorm(runtime, z);
  575. }
  576. public static class ERange extends RuntimeException {
  577. public static enum Kind {Overflow, Underflow};
  578. private Kind kind;
  579. public ERange() {
  580. super();
  581. }
  582. public ERange(Kind kind) {
  583. super();
  584. this.kind = kind;
  585. }
  586. public Kind getKind() {
  587. return kind;
  588. }
  589. }
  590. /** rb_invalid_str
  591. *
  592. */
  593. private void invalidString(String type) {
  594. IRubyObject s = RubyString.newString(runtime, _str).inspect();
  595. throw runtime.newArgumentError("invalid value for " + type + ": " + s);
  596. }
  597. }